@rdlabo/workers-hono-kit 0.11.2 → 0.12.0-beta.pr48.sha371f5792ce8a
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/README.md +73 -37
- package/dist/aws/sts.d.ts +2 -2
- package/dist/aws/sts.js +4 -4
- package/dist/business-time/index.d.ts +68 -122
- package/dist/business-time/index.js +55 -222
- package/dist/container/middleware.d.ts +1 -2
- package/dist/container/middleware.js +1 -1
- package/dist/db/index.d.ts +95 -20
- package/dist/db/index.js +56 -15
- package/dist/db/payment-failed.d.ts +1 -1
- package/dist/db/payment-failed.js +1 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -3
- package/dist/mysql/index.d.ts +9 -0
- package/dist/mysql/index.js +8 -0
- package/dist/testing/auth.d.ts +1 -1
- package/dist/testing/db.d.ts +19 -106
- package/dist/testing/db.js +3 -95
- package/dist/testing/fakes.d.ts +15 -97
- package/dist/testing/fakes.js +12 -104
- package/dist/testing/index.d.ts +8 -3
- package/dist/testing/index.js +8 -2
- package/docs/api-business-time.md +47 -30
- package/docs/api-db.md +48 -29
- package/docs/api-offline.md +11 -15
- package/docs/api-root.md +64 -58
- package/docs/api-testing.md +41 -13
- package/docs/api.md +35 -12
- package/docs/cli.md +11 -7
- package/docs/data-layer.md +68 -5
- package/docs/development.md +125 -5
- package/docs/http-auth.md +15 -0
- package/docs/realtime-offline.md +15 -0
- package/docs/role-policies.md +4 -4
- package/docs/testing-operations.md +25 -2
- package/package.json +24 -18
- package/scripts/db-baseline.mjs +3 -68
- package/scripts/workspace-package-smoke.mjs +206 -0
- package/dist/business-time/types.d.ts +0 -9
- package/dist/business-time/types.js +0 -5
- package/dist/db/columns.d.ts +0 -38
- package/dist/db/columns.js +0 -38
- package/dist/db/connection.d.ts +0 -74
- package/dist/db/connection.js +0 -67
- package/dist/db/database.d.ts +0 -249
- package/dist/db/database.js +0 -196
- package/dist/db/jst.d.ts +0 -45
- package/dist/db/jst.js +0 -47
- package/dist/db/migrate.d.ts +0 -51
- package/dist/db/migrate.js +0 -109
- package/dist/db/orm-config.d.ts +0 -127
- package/dist/db/orm-config.js +0 -122
- package/dist/db/retry.d.ts +0 -28
- package/dist/db/retry.js +0 -56
- package/dist/db/write-result.d.ts +0 -39
- package/dist/db/write-result.js +0 -34
package/dist/testing/db.d.ts
CHANGED
|
@@ -1,106 +1,19 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*/
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
export interface CreateTestDbOptions {
|
|
21
|
-
/**
|
|
22
|
-
* Test database name (e.g. `'app_test'`). To isolate parallel runs per feature, resolve a per-run
|
|
23
|
-
* name on the caller side and pass it here.
|
|
24
|
-
*/
|
|
25
|
-
dbName: string;
|
|
26
|
-
/**
|
|
27
|
-
* Absolute path to the Drizzle migrations folder. Resolve it on the caller side, e.g.
|
|
28
|
-
* `join(here, '..', 'drizzle')`.
|
|
29
|
-
*/
|
|
30
|
-
migrationsFolder: string;
|
|
31
|
-
/**
|
|
32
|
-
* Connection overrides. Unspecified fields fall back to environment variables
|
|
33
|
-
* (`DB_HOST`/`DB_PORT`/`DB_USER`/`DB_PASSWORD`), then to `127.0.0.1`/`3306`/`root`/`root`.
|
|
34
|
-
*/
|
|
35
|
-
connection?: Partial<TestDbConnection>;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Test database handle returned by {@link createTestDb}, bundling schema setup, pooling, and
|
|
39
|
-
* fixture helpers for a single test database.
|
|
40
|
-
*/
|
|
41
|
-
export interface TestDb {
|
|
42
|
-
/** The resolved test database name. */
|
|
43
|
-
readonly dbName: string;
|
|
44
|
-
/** The resolved connection parameters. */
|
|
45
|
-
readonly connection: TestDbConnection;
|
|
46
|
-
/**
|
|
47
|
-
* Drop and recreate the database, then apply the committed Drizzle migrations to build the schema.
|
|
48
|
-
*
|
|
49
|
-
* @returns A promise that resolves once migrations have been applied.
|
|
50
|
-
*/
|
|
51
|
-
resetSchema(): Promise<void>;
|
|
52
|
-
/**
|
|
53
|
-
* Create a mysql2 pool connected to the test database.
|
|
54
|
-
*
|
|
55
|
-
* @remarks Call `pool.end()` (e.g. in `afterAll`) to release connections.
|
|
56
|
-
* @returns A connection pool for the test database.
|
|
57
|
-
*/
|
|
58
|
-
createTestPool(): Pool;
|
|
59
|
-
/**
|
|
60
|
-
* Truncate every base table in the database.
|
|
61
|
-
*
|
|
62
|
-
* @remarks Table names are discovered dynamically from `information_schema`; the
|
|
63
|
-
* `__drizzle_migrations` bookkeeping table is excluded. Foreign-key checks are disabled for the
|
|
64
|
-
* duration so truncation order does not matter.
|
|
65
|
-
* @param pool - Pool connected to the test database.
|
|
66
|
-
*/
|
|
67
|
-
truncateAll(pool: Pool): Promise<void>;
|
|
68
|
-
/**
|
|
69
|
-
* Insert a single row, mapping column names to values — a generic fixture helper for specs.
|
|
70
|
-
*
|
|
71
|
-
* @param pool - Pool connected to the test database.
|
|
72
|
-
* @param table - Target table name.
|
|
73
|
-
* @param row - Column-name to value map. A no-op if empty.
|
|
74
|
-
*/
|
|
75
|
-
seed(pool: Pool, table: string, row: Record<string, unknown>): Promise<void>;
|
|
76
|
-
/**
|
|
77
|
-
* Report whether the local MySQL server is reachable.
|
|
78
|
-
*
|
|
79
|
-
* @remarks Useful as a guard, e.g. `describe.skipIf(!(await mysqlReachable()))`.
|
|
80
|
-
* @returns `true` if a connection could be opened, otherwise `false`.
|
|
81
|
-
*/
|
|
82
|
-
mysqlReachable(): Promise<boolean>;
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Create a {@link TestDb} handle for a single test database.
|
|
86
|
-
*
|
|
87
|
-
* @remarks
|
|
88
|
-
* The test schema is built from the committed Drizzle migrations as the single source of truth
|
|
89
|
-
* (the `db:generate` output under `./drizzle`), rather than a hand-written `schema.sql`. This helper
|
|
90
|
-
* is Node-only test infrastructure (run under Vitest) and is unrelated to runtime behavior.
|
|
91
|
-
*
|
|
92
|
-
* @param options - Database name, migrations folder, and optional connection overrides. See
|
|
93
|
-
* {@link CreateTestDbOptions}.
|
|
94
|
-
* @returns A handle exposing schema setup, pooling, truncation, seeding, and a reachability probe.
|
|
95
|
-
* @example
|
|
96
|
-
* ```ts
|
|
97
|
-
* const testDb = createTestDb({ dbName: 'app_test', migrationsFolder: join(here, '..', 'drizzle') });
|
|
98
|
-
* beforeAll(async () => {
|
|
99
|
-
* await testDb.resetSchema();
|
|
100
|
-
* });
|
|
101
|
-
* const pool = testDb.createTestPool();
|
|
102
|
-
* beforeEach(() => testDb.truncateAll(pool));
|
|
103
|
-
* afterAll(() => pool.end());
|
|
104
|
-
* ```
|
|
105
|
-
*/
|
|
106
|
-
export declare function createTestDb(options: CreateTestDbOptions): TestDb;
|
|
1
|
+
import type { Database as DatabaseCanonical, DisposableDatabase as DisposableDatabaseCanonical, QueryRunner as QueryRunnerCanonical, TxOf as TxOfCanonical } from '@rdlabo/workers-mysql';
|
|
2
|
+
import { createTestDb as createTestDbCanonical } from '@rdlabo/workers-mysql/testing';
|
|
3
|
+
import type { CreateTestDbOptions as CreateTestDbOptionsCanonical, TestDb as TestDbCanonical, TestDbConnection as TestDbConnectionCanonical } from '@rdlabo/workers-mysql/testing';
|
|
4
|
+
/** @deprecated Import from `@rdlabo/workers-mysql/testing` instead. */
|
|
5
|
+
export declare const createTestDb: typeof createTestDbCanonical;
|
|
6
|
+
/** @deprecated Import from `@rdlabo/workers-mysql/testing` instead. */
|
|
7
|
+
export type TestDb = TestDbCanonical;
|
|
8
|
+
/** @deprecated Import from `@rdlabo/workers-mysql/testing` instead. */
|
|
9
|
+
export type CreateTestDbOptions = CreateTestDbOptionsCanonical;
|
|
10
|
+
/** @deprecated Import from `@rdlabo/workers-mysql/testing` instead. */
|
|
11
|
+
export type TestDbConnection = TestDbConnectionCanonical;
|
|
12
|
+
/** @deprecated Import from `@rdlabo/workers-mysql` or `@rdlabo/workers-mysql/testing` instead. */
|
|
13
|
+
export type TxOf<TDrizzle> = TxOfCanonical<TDrizzle>;
|
|
14
|
+
/** @deprecated Import from `@rdlabo/workers-mysql` or `@rdlabo/workers-mysql/testing` instead. */
|
|
15
|
+
export type Database<TDrizzle, TTx = TxOfCanonical<TDrizzle>> = DatabaseCanonical<TDrizzle, TTx>;
|
|
16
|
+
/** @deprecated Import from `@rdlabo/workers-mysql` or `@rdlabo/workers-mysql/testing` instead. */
|
|
17
|
+
export type DisposableDatabase<TDrizzle, TTx = TxOfCanonical<TDrizzle>> = DisposableDatabaseCanonical<TDrizzle, TTx>;
|
|
18
|
+
/** @deprecated Import from `@rdlabo/workers-mysql` or `@rdlabo/workers-mysql/testing` instead. */
|
|
19
|
+
export type QueryRunner = QueryRunnerCanonical;
|
package/dist/testing/db.js
CHANGED
|
@@ -1,95 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
function resolveConnection(override) {
|
|
5
|
-
const env = globalThis.process?.env ?? {};
|
|
6
|
-
return {
|
|
7
|
-
host: override?.host ?? env.DB_HOST ?? '127.0.0.1',
|
|
8
|
-
port: override?.port ?? Number(env.DB_PORT ?? '3306'),
|
|
9
|
-
user: override?.user ?? env.DB_USER ?? 'root',
|
|
10
|
-
password: override?.password ?? env.DB_PASSWORD ?? 'root',
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Create a {@link TestDb} handle for a single test database.
|
|
15
|
-
*
|
|
16
|
-
* @remarks
|
|
17
|
-
* The test schema is built from the committed Drizzle migrations as the single source of truth
|
|
18
|
-
* (the `db:generate` output under `./drizzle`), rather than a hand-written `schema.sql`. This helper
|
|
19
|
-
* is Node-only test infrastructure (run under Vitest) and is unrelated to runtime behavior.
|
|
20
|
-
*
|
|
21
|
-
* @param options - Database name, migrations folder, and optional connection overrides. See
|
|
22
|
-
* {@link CreateTestDbOptions}.
|
|
23
|
-
* @returns A handle exposing schema setup, pooling, truncation, seeding, and a reachability probe.
|
|
24
|
-
* @example
|
|
25
|
-
* ```ts
|
|
26
|
-
* const testDb = createTestDb({ dbName: 'app_test', migrationsFolder: join(here, '..', 'drizzle') });
|
|
27
|
-
* beforeAll(async () => {
|
|
28
|
-
* await testDb.resetSchema();
|
|
29
|
-
* });
|
|
30
|
-
* const pool = testDb.createTestPool();
|
|
31
|
-
* beforeEach(() => testDb.truncateAll(pool));
|
|
32
|
-
* afterAll(() => pool.end());
|
|
33
|
-
* ```
|
|
34
|
-
*/
|
|
35
|
-
export function createTestDb(options) {
|
|
36
|
-
const { dbName, migrationsFolder } = options;
|
|
37
|
-
const connection = resolveConnection(options.connection);
|
|
38
|
-
return {
|
|
39
|
-
dbName,
|
|
40
|
-
connection,
|
|
41
|
-
async resetSchema() {
|
|
42
|
-
const admin = await createConnection({ ...connection, multipleStatements: true });
|
|
43
|
-
await admin.query(`DROP DATABASE IF EXISTS \`${dbName}\`; CREATE DATABASE \`${dbName}\` DEFAULT CHARACTER SET utf8mb4;`);
|
|
44
|
-
await admin.changeUser({ database: dbName });
|
|
45
|
-
await migrate(drizzle(admin), { migrationsFolder });
|
|
46
|
-
await admin.end();
|
|
47
|
-
},
|
|
48
|
-
createTestPool() {
|
|
49
|
-
// decimalNumbers / timezone mirror the runtime hyperdriveConnectionOptions so specs read
|
|
50
|
-
// DECIMAL columns as numbers and handle datetime in +09:00 (JST), matching production.
|
|
51
|
-
const pool = createPool({
|
|
52
|
-
...connection,
|
|
53
|
-
database: dbName,
|
|
54
|
-
connectionLimit: 5,
|
|
55
|
-
decimalNumbers: true,
|
|
56
|
-
timezone: '+09:00',
|
|
57
|
-
});
|
|
58
|
-
// Pin ONLY_FULL_GROUP_BY on every pooled connection so GROUP BY violations surface in specs
|
|
59
|
-
// regardless of the server's my.cnf (the policy is centralized here, not left to each server). CONCAT keeps
|
|
60
|
-
// the server's other sql_mode flags and is harmless if ONLY_FULL_GROUP_BY is already present.
|
|
61
|
-
// mysql2 queues this SET ahead of the consumer's first query on each new physical connection.
|
|
62
|
-
pool.on('connection', (conn) => {
|
|
63
|
-
void conn.query("SET SESSION sql_mode = CONCAT(@@SESSION.sql_mode, ',ONLY_FULL_GROUP_BY')");
|
|
64
|
-
});
|
|
65
|
-
return pool;
|
|
66
|
-
},
|
|
67
|
-
async truncateAll(pool) {
|
|
68
|
-
const [rows] = await pool.query("SELECT table_name AS t FROM information_schema.tables WHERE table_schema = ? AND table_type='BASE TABLE' AND table_name <> '__drizzle_migrations'", [dbName]);
|
|
69
|
-
const tables = rows.map((r) => r.t);
|
|
70
|
-
await pool.query('SET FOREIGN_KEY_CHECKS=0');
|
|
71
|
-
for (const t of tables) {
|
|
72
|
-
await pool.query(`TRUNCATE TABLE \`${t}\``);
|
|
73
|
-
}
|
|
74
|
-
await pool.query('SET FOREIGN_KEY_CHECKS=1');
|
|
75
|
-
},
|
|
76
|
-
async seed(pool, table, row) {
|
|
77
|
-
const cols = Object.keys(row);
|
|
78
|
-
if (cols.length === 0) {
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
const placeholders = cols.map(() => '?').join(', ');
|
|
82
|
-
const columnList = cols.map((c) => `\`${c}\``).join(', ');
|
|
83
|
-
await pool.query(`INSERT INTO \`${table}\` (${columnList}) VALUES (${placeholders})`, Object.values(row));
|
|
84
|
-
},
|
|
85
|
-
async mysqlReachable() {
|
|
86
|
-
const connect = async () => createConnection({ ...connection });
|
|
87
|
-
const c = await connect().catch(() => undefined);
|
|
88
|
-
if (!c) {
|
|
89
|
-
return false;
|
|
90
|
-
}
|
|
91
|
-
const close = async () => c.end();
|
|
92
|
-
return close().then(() => true, () => false);
|
|
93
|
-
},
|
|
94
|
-
};
|
|
95
|
-
}
|
|
1
|
+
import { createTestDb as createTestDbCanonical } from '@rdlabo/workers-mysql/testing';
|
|
2
|
+
/** @deprecated Import from `@rdlabo/workers-mysql/testing` instead. */
|
|
3
|
+
export const createTestDb = createTestDbCanonical;
|
package/dist/testing/fakes.d.ts
CHANGED
|
@@ -1,113 +1,31 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type {
|
|
1
|
+
import { createNoopDatabase as createNoopDatabaseCanonical, createPoolDatabase as createPoolDatabaseCanonical } from '@rdlabo/workers-mysql/testing';
|
|
2
|
+
import type { CreatePoolDatabaseOptions as CreatePoolDatabaseOptionsCanonical } from '@rdlabo/workers-mysql/testing';
|
|
3
3
|
import type { DecodedIdToken, FirebaseVerifier } from '../firebase/firebase-verifier.js';
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
* ```ts
|
|
12
|
-
* const firebase = new FakeFirebaseVerifier();
|
|
13
|
-
* firebase.register('tok-1', { uid: 'uid-1' });
|
|
14
|
-
* const decoded = await firebase.verifyIdToken('tok-1'); // { uid: 'uid-1' }
|
|
15
|
-
* ```
|
|
16
|
-
*/
|
|
4
|
+
/** @deprecated Import from `@rdlabo/workers-mysql/testing` instead. */
|
|
5
|
+
export declare const createPoolDatabase: typeof createPoolDatabaseCanonical;
|
|
6
|
+
/** @deprecated Import from `@rdlabo/workers-mysql/testing` instead. */
|
|
7
|
+
export declare const createNoopDatabase: typeof createNoopDatabaseCanonical;
|
|
8
|
+
/** @deprecated Import from `@rdlabo/workers-mysql/testing` instead. */
|
|
9
|
+
export type CreatePoolDatabaseOptions<TDrizzle> = CreatePoolDatabaseOptionsCanonical<TDrizzle>;
|
|
10
|
+
/** In-memory Firebase verifier for route tests. */
|
|
17
11
|
export declare class FakeFirebaseVerifier implements FirebaseVerifier {
|
|
18
12
|
private readonly tokens;
|
|
19
|
-
/** UIDs passed to {@link
|
|
13
|
+
/** UIDs passed to {@link deleteUser}, in call order. */
|
|
20
14
|
readonly deleted: string[];
|
|
21
|
-
/**
|
|
22
|
-
* Register a fake decoded token so that {@link FakeFirebaseVerifier.verifyIdToken} resolves it.
|
|
23
|
-
*
|
|
24
|
-
* @param token - Token string clients will present.
|
|
25
|
-
* @param record - Decoded token returned on verification (must include `uid`).
|
|
26
|
-
*/
|
|
15
|
+
/** Register a decoded token for later verification. */
|
|
27
16
|
register(token: string, record: DecodedIdToken): void;
|
|
28
|
-
/**
|
|
29
|
-
* Resolve the decoded token previously registered for `idToken`.
|
|
30
|
-
*
|
|
31
|
-
* @param idToken - Token string to verify.
|
|
32
|
-
* @returns The registered decoded token.
|
|
33
|
-
* @throws Error if the token was never registered.
|
|
34
|
-
*/
|
|
17
|
+
/** Resolve a registered token. */
|
|
35
18
|
verifyIdToken(idToken: string): Promise<DecodedIdToken>;
|
|
36
|
-
/**
|
|
37
|
-
* Return a minimal user record echoing the requested UID.
|
|
38
|
-
*
|
|
39
|
-
* @param uid - UID to look up.
|
|
40
|
-
* @returns An object containing the `uid` (never `null` in this fake).
|
|
41
|
-
*/
|
|
19
|
+
/** Return a minimal fake user. */
|
|
42
20
|
getUser(uid: string): Promise<{
|
|
43
21
|
uid: string;
|
|
44
22
|
email?: string;
|
|
45
23
|
} | null>;
|
|
46
|
-
/**
|
|
47
|
-
* Return minimal user records echoing each requested UID.
|
|
48
|
-
*
|
|
49
|
-
* @param uids - UIDs to look up.
|
|
50
|
-
* @returns One `{ uid }` entry per requested uid (never omits any, in this fake).
|
|
51
|
-
*/
|
|
24
|
+
/** Return one minimal fake user per UID. */
|
|
52
25
|
getUsers(uids: string[]): Promise<{
|
|
53
26
|
uid: string;
|
|
54
27
|
email?: string;
|
|
55
28
|
}[]>;
|
|
56
|
-
/**
|
|
57
|
-
* Record a user deletion by appending the UID to {@link FakeFirebaseVerifier.deleted}.
|
|
58
|
-
*
|
|
59
|
-
* @param uid - UID being deleted.
|
|
60
|
-
*/
|
|
29
|
+
/** Record a fake user deletion. */
|
|
61
30
|
deleteUser(uid: string): Promise<void>;
|
|
62
31
|
}
|
|
63
|
-
/**
|
|
64
|
-
* Options for {@link createPoolDatabase}.
|
|
65
|
-
*
|
|
66
|
-
* @typeParam TDrizzle - The Drizzle instance type, supplied by the consumer so that type identity is
|
|
67
|
-
* not coupled to this package's copy of `drizzle-orm`.
|
|
68
|
-
*/
|
|
69
|
-
export interface CreatePoolDatabaseOptions<TDrizzle> {
|
|
70
|
-
/** Test pool used as both primary and replica. */
|
|
71
|
-
pool: Pool;
|
|
72
|
-
/** Drizzle instance built by the consumer with its own `drizzle-orm`, e.g. `drizzle(pool, { schema, ... })`. */
|
|
73
|
-
orm: TDrizzle;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Create a `Database` backed by a single pool used as both primary and replica, suitable for tests.
|
|
77
|
-
*
|
|
78
|
-
* @remarks
|
|
79
|
-
* `dispose()` ends the pool. The `orm` is provided by the caller (rather than constructed here) so
|
|
80
|
-
* the returned database uses the consumer's own `drizzle-orm` types, avoiding type-identity clashes
|
|
81
|
-
* across duplicated `drizzle-orm` installs.
|
|
82
|
-
*
|
|
83
|
-
* @typeParam TDrizzle - The Drizzle instance type provided by the consumer.
|
|
84
|
-
* @param options - Pool and Drizzle instance. See {@link CreatePoolDatabaseOptions}.
|
|
85
|
-
* @returns A {@link DisposableDatabase} whose `dispose()` closes the pool.
|
|
86
|
-
* @example
|
|
87
|
-
* ```ts
|
|
88
|
-
* const pool = testDb.createTestPool();
|
|
89
|
-
* const db = createPoolDatabase({ pool, orm: drizzle(pool, { schema }) });
|
|
90
|
-
* // ... run tests ...
|
|
91
|
-
* await db.dispose();
|
|
92
|
-
* ```
|
|
93
|
-
*/
|
|
94
|
-
export declare function createPoolDatabase<TDrizzle>(options: CreatePoolDatabaseOptions<TDrizzle>): DisposableDatabase<TDrizzle>;
|
|
95
|
-
/**
|
|
96
|
-
* Create a no-op `Database` stub for routes that never touch the database (e.g. plain GET handlers).
|
|
97
|
-
*
|
|
98
|
-
* @remarks
|
|
99
|
-
* `read` resolves to an empty array, while `write` and `transaction` throw so that any unexpected
|
|
100
|
-
* database access is caught as a misuse. `dispose` is a no-op, so this can stand in for a
|
|
101
|
-
* {@link DisposableDatabase} backing (e.g. a Hyperdrive- or pool-based one) without changes.
|
|
102
|
-
*
|
|
103
|
-
* @typeParam TDrizzle - The Drizzle instance type the consumer expects (defaults to `unknown`).
|
|
104
|
-
* @returns A {@link DisposableDatabase} that reads empty and throws on writes/transactions.
|
|
105
|
-
* @throws Error from `write`/`transaction` if they are accessed.
|
|
106
|
-
* @example
|
|
107
|
-
* ```ts
|
|
108
|
-
* const db = createNoopDatabase();
|
|
109
|
-
* await db.read('SELECT 1'); // []
|
|
110
|
-
* await db.write(async (dz) => dz); // throws: noopDatabase.write accessed unexpectedly
|
|
111
|
-
* ```
|
|
112
|
-
*/
|
|
113
|
-
export declare function createNoopDatabase<TDrizzle = unknown>(): DisposableDatabase<TDrizzle>;
|
package/dist/testing/fakes.js
CHANGED
|
@@ -1,37 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```ts
|
|
10
|
-
* const firebase = new FakeFirebaseVerifier();
|
|
11
|
-
* firebase.register('tok-1', { uid: 'uid-1' });
|
|
12
|
-
* const decoded = await firebase.verifyIdToken('tok-1'); // { uid: 'uid-1' }
|
|
13
|
-
* ```
|
|
14
|
-
*/
|
|
1
|
+
import { createNoopDatabase as createNoopDatabaseCanonical, createPoolDatabase as createPoolDatabaseCanonical, } from '@rdlabo/workers-mysql/testing';
|
|
2
|
+
/** @deprecated Import from `@rdlabo/workers-mysql/testing` instead. */
|
|
3
|
+
export const createPoolDatabase = createPoolDatabaseCanonical;
|
|
4
|
+
/** @deprecated Import from `@rdlabo/workers-mysql/testing` instead. */
|
|
5
|
+
export const createNoopDatabase = createNoopDatabaseCanonical;
|
|
6
|
+
/** In-memory Firebase verifier for route tests. */
|
|
15
7
|
export class FakeFirebaseVerifier {
|
|
16
8
|
tokens = new Map();
|
|
17
|
-
/** UIDs passed to {@link
|
|
9
|
+
/** UIDs passed to {@link deleteUser}, in call order. */
|
|
18
10
|
deleted = [];
|
|
19
|
-
/**
|
|
20
|
-
* Register a fake decoded token so that {@link FakeFirebaseVerifier.verifyIdToken} resolves it.
|
|
21
|
-
*
|
|
22
|
-
* @param token - Token string clients will present.
|
|
23
|
-
* @param record - Decoded token returned on verification (must include `uid`).
|
|
24
|
-
*/
|
|
11
|
+
/** Register a decoded token for later verification. */
|
|
25
12
|
register(token, record) {
|
|
26
13
|
this.tokens.set(token, record);
|
|
27
14
|
}
|
|
28
|
-
/**
|
|
29
|
-
* Resolve the decoded token previously registered for `idToken`.
|
|
30
|
-
*
|
|
31
|
-
* @param idToken - Token string to verify.
|
|
32
|
-
* @returns The registered decoded token.
|
|
33
|
-
* @throws Error if the token was never registered.
|
|
34
|
-
*/
|
|
15
|
+
/** Resolve a registered token. */
|
|
35
16
|
async verifyIdToken(idToken) {
|
|
36
17
|
const record = this.tokens.get(idToken);
|
|
37
18
|
if (!record) {
|
|
@@ -39,89 +20,16 @@ export class FakeFirebaseVerifier {
|
|
|
39
20
|
}
|
|
40
21
|
return record;
|
|
41
22
|
}
|
|
42
|
-
/**
|
|
43
|
-
* Return a minimal user record echoing the requested UID.
|
|
44
|
-
*
|
|
45
|
-
* @param uid - UID to look up.
|
|
46
|
-
* @returns An object containing the `uid` (never `null` in this fake).
|
|
47
|
-
*/
|
|
23
|
+
/** Return a minimal fake user. */
|
|
48
24
|
async getUser(uid) {
|
|
49
25
|
return { uid };
|
|
50
26
|
}
|
|
51
|
-
/**
|
|
52
|
-
* Return minimal user records echoing each requested UID.
|
|
53
|
-
*
|
|
54
|
-
* @param uids - UIDs to look up.
|
|
55
|
-
* @returns One `{ uid }` entry per requested uid (never omits any, in this fake).
|
|
56
|
-
*/
|
|
27
|
+
/** Return one minimal fake user per UID. */
|
|
57
28
|
async getUsers(uids) {
|
|
58
29
|
return uids.map((uid) => ({ uid }));
|
|
59
30
|
}
|
|
60
|
-
/**
|
|
61
|
-
* Record a user deletion by appending the UID to {@link FakeFirebaseVerifier.deleted}.
|
|
62
|
-
*
|
|
63
|
-
* @param uid - UID being deleted.
|
|
64
|
-
*/
|
|
31
|
+
/** Record a fake user deletion. */
|
|
65
32
|
async deleteUser(uid) {
|
|
66
33
|
this.deleted.push(uid);
|
|
67
34
|
}
|
|
68
35
|
}
|
|
69
|
-
/**
|
|
70
|
-
* Create a `Database` backed by a single pool used as both primary and replica, suitable for tests.
|
|
71
|
-
*
|
|
72
|
-
* @remarks
|
|
73
|
-
* `dispose()` ends the pool. The `orm` is provided by the caller (rather than constructed here) so
|
|
74
|
-
* the returned database uses the consumer's own `drizzle-orm` types, avoiding type-identity clashes
|
|
75
|
-
* across duplicated `drizzle-orm` installs.
|
|
76
|
-
*
|
|
77
|
-
* @typeParam TDrizzle - The Drizzle instance type provided by the consumer.
|
|
78
|
-
* @param options - Pool and Drizzle instance. See {@link CreatePoolDatabaseOptions}.
|
|
79
|
-
* @returns A {@link DisposableDatabase} whose `dispose()` closes the pool.
|
|
80
|
-
* @example
|
|
81
|
-
* ```ts
|
|
82
|
-
* const pool = testDb.createTestPool();
|
|
83
|
-
* const db = createPoolDatabase({ pool, orm: drizzle(pool, { schema }) });
|
|
84
|
-
* // ... run tests ...
|
|
85
|
-
* await db.dispose();
|
|
86
|
-
* ```
|
|
87
|
-
*/
|
|
88
|
-
export function createPoolDatabase(options) {
|
|
89
|
-
const { pool, orm } = options;
|
|
90
|
-
const base = databaseFrom(orm, pool);
|
|
91
|
-
return {
|
|
92
|
-
...base,
|
|
93
|
-
async dispose() {
|
|
94
|
-
await pool.end();
|
|
95
|
-
},
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Create a no-op `Database` stub for routes that never touch the database (e.g. plain GET handlers).
|
|
100
|
-
*
|
|
101
|
-
* @remarks
|
|
102
|
-
* `read` resolves to an empty array, while `write` and `transaction` throw so that any unexpected
|
|
103
|
-
* database access is caught as a misuse. `dispose` is a no-op, so this can stand in for a
|
|
104
|
-
* {@link DisposableDatabase} backing (e.g. a Hyperdrive- or pool-based one) without changes.
|
|
105
|
-
*
|
|
106
|
-
* @typeParam TDrizzle - The Drizzle instance type the consumer expects (defaults to `unknown`).
|
|
107
|
-
* @returns A {@link DisposableDatabase} that reads empty and throws on writes/transactions.
|
|
108
|
-
* @throws Error from `write`/`transaction` if they are accessed.
|
|
109
|
-
* @example
|
|
110
|
-
* ```ts
|
|
111
|
-
* const db = createNoopDatabase();
|
|
112
|
-
* await db.read('SELECT 1'); // []
|
|
113
|
-
* await db.write(async (dz) => dz); // throws: noopDatabase.write accessed unexpectedly
|
|
114
|
-
* ```
|
|
115
|
-
*/
|
|
116
|
-
export function createNoopDatabase() {
|
|
117
|
-
return {
|
|
118
|
-
read: async () => [],
|
|
119
|
-
write: () => {
|
|
120
|
-
throw new Error('noopDatabase.write accessed unexpectedly');
|
|
121
|
-
},
|
|
122
|
-
transaction: () => {
|
|
123
|
-
throw new Error('noopDatabase.transaction accessed unexpectedly');
|
|
124
|
-
},
|
|
125
|
-
dispose: async () => { },
|
|
126
|
-
};
|
|
127
|
-
}
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared test infrastructure for Hono on Cloudflare Workers projects
|
|
2
|
+
* Shared test infrastructure for Hono on Cloudflare Workers projects.
|
|
3
|
+
* Every import requires `@rdlabo/workers-mysql` and `drizzle-orm` because DB compatibility exports
|
|
4
|
+
* are loaded statically, including when only non-DB helpers are used. Prefer
|
|
5
|
+
* `@rdlabo/workers-mysql/testing` for database helpers; kit-owned Firebase/auth/KV/Stripe fakes remain
|
|
6
|
+
* the supported testing surface here.
|
|
3
7
|
*
|
|
4
8
|
* Test-only helpers that are never loaded at runtime. This subpath consolidates the duplicated
|
|
5
9
|
* test boilerplate (test DB setup, in-memory fakes, auth header builders, Stripe fixtures) that
|
|
@@ -7,9 +11,10 @@
|
|
|
7
11
|
*/
|
|
8
12
|
export { createTestDb } from './db.js';
|
|
9
13
|
export type { TestDb, CreateTestDbOptions, TestDbConnection } from './db.js';
|
|
10
|
-
export {
|
|
14
|
+
export type { Database, DisposableDatabase, QueryRunner, TxOf } from './db.js';
|
|
15
|
+
export { FakeFirebaseVerifier } from './fakes.js';
|
|
16
|
+
export { createPoolDatabase, createNoopDatabase } from './fakes.js';
|
|
11
17
|
export type { CreatePoolDatabaseOptions } from './fakes.js';
|
|
12
|
-
export type { Database, DisposableDatabase, QueryRunner, TxOf } from '../db/database.js';
|
|
13
18
|
export { authHeaders, registerFirebaseToken, provisionUser } from './auth.js';
|
|
14
19
|
export { configurableFake } from './configurable-fake.js';
|
|
15
20
|
export { fakeApiList, fakePaymentIntent, fakeStripeEvent, fakeCheckoutSession, fakeCustomer, fakePrice, fakeSubscription, } from './stripe-fixtures.js';
|
package/dist/testing/index.js
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared test infrastructure for Hono on Cloudflare Workers projects
|
|
2
|
+
* Shared test infrastructure for Hono on Cloudflare Workers projects.
|
|
3
|
+
* Every import requires `@rdlabo/workers-mysql` and `drizzle-orm` because DB compatibility exports
|
|
4
|
+
* are loaded statically, including when only non-DB helpers are used. Prefer
|
|
5
|
+
* `@rdlabo/workers-mysql/testing` for database helpers; kit-owned Firebase/auth/KV/Stripe fakes remain
|
|
6
|
+
* the supported testing surface here.
|
|
3
7
|
*
|
|
4
8
|
* Test-only helpers that are never loaded at runtime. This subpath consolidates the duplicated
|
|
5
9
|
* test boilerplate (test DB setup, in-memory fakes, auth header builders, Stripe fixtures) that
|
|
6
10
|
* tends to be copy-pasted across projects into a single, importable surface.
|
|
7
11
|
*/
|
|
12
|
+
/* eslint-disable @typescript-eslint/no-deprecated -- compatibility barrel re-exports DB helpers */
|
|
8
13
|
export { createTestDb } from './db.js';
|
|
9
|
-
export { FakeFirebaseVerifier
|
|
14
|
+
export { FakeFirebaseVerifier } from './fakes.js';
|
|
15
|
+
export { createPoolDatabase, createNoopDatabase } from './fakes.js';
|
|
10
16
|
// Authentication test helpers (route-spec header builders and user provisioning).
|
|
11
17
|
export { authHeaders, registerFirebaseToken, provisionUser } from './auth.js';
|
|
12
18
|
// Test double helper (partial-implementation fake that throws explicitly on unconfigured members).
|
|
@@ -1,33 +1,50 @@
|
|
|
1
|
-
# API: `@rdlabo/workers-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
# API: `@rdlabo/workers-timezone`
|
|
2
|
+
|
|
3
|
+
Install with `npm install @rdlabo/workers-timezone`. The kit's `/business-time` entry point is a
|
|
4
|
+
deprecated compatibility re-export from `0.12.0`.
|
|
5
|
+
|
|
6
|
+
Timezone-aware calendar and wall-clock conversion for Cloudflare Workers, with no database or Node
|
|
7
|
+
runtime dependency. The uninitialized default remains `Asia/Tokyo` for compatibility.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { TIME_ZONES, initializeTimezone, toLocalDateTime } from '@rdlabo/workers-timezone';
|
|
11
|
+
|
|
12
|
+
initializeTimezone({ timeZone: TIME_ZONES.NEW_YORK });
|
|
13
|
+
toLocalDateTime(new Date('2026-07-01T13:00:00Z')); // '2026-07-01 09:00:00'
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Initialize once during module evaluation using deployment-wide static configuration. Do not mutate
|
|
17
|
+
the default per request, user, or tenant. Every conversion function accepts an explicit IANA
|
|
18
|
+
timezone override without changing the module-instance default.
|
|
19
|
+
|
|
20
|
+
| Export | Description |
|
|
21
|
+
| ----------------------------------------------- | -------------------------------------------------------------------------------- |
|
|
22
|
+
| `initializeTimezone(config)` | Set the module-instance default once; repeated identical initialization is safe. |
|
|
23
|
+
| `getTimezoneConfig()` | Return the active configuration. |
|
|
24
|
+
| `toLocalDate(instant, timeZone?)` | Instant to local `YYYY-MM-DD`. |
|
|
25
|
+
| `toLocalDateTime(instant, timeZone?)` | Instant to local `YYYY-MM-DD HH:mm:ss`. |
|
|
26
|
+
| `localDateTimeToInstant(date, time, timeZone?)` | Local calendar date and wall clock to an instant. |
|
|
27
|
+
| `startOfDay` / `endOfDay` | First or final representable whole second of a local calendar day. |
|
|
28
|
+
| `addDays(date, days)` | Add calendar days without assuming a 24-hour day. |
|
|
29
|
+
| `TIME_ZONES` / `TimeZone` | Common typed constants and the open IANA timezone type. |
|
|
30
|
+
|
|
31
|
+
IANA rules determine daylight-saving and historical offsets. A skipped local clock throws
|
|
32
|
+
`RangeError`; when a clock occurs twice during a DST overlap, the earlier instant is selected.
|
|
33
|
+
|
|
34
|
+
## Legacy compatibility
|
|
35
|
+
|
|
36
|
+
`@rdlabo/workers-hono-kit/business-time` is deprecated and re-exports the same module instance from
|
|
37
|
+
`@rdlabo/workers-timezone`. Existing names such as `today`, `normalizeBusinessDate`,
|
|
38
|
+
`toBusinessDateTime`, `businessDateTimeInstant`, `formatBusinessDateTime`, and
|
|
39
|
+
`ageOnBusinessDate` remain available during migration.
|
|
40
|
+
|
|
41
|
+
This is source compatibility for API names, not full output compatibility. Results now follow IANA
|
|
42
|
+
historical offsets instead of the legacy fixed `+09:00`, so historical dates can change when
|
|
43
|
+
Tokyo's offset was not `+09:00`. Impossible `YYYY-MM-DD` values now normalize to `null`; invalid
|
|
44
|
+
date-time construction and parsing throw `RangeError` instead of using JavaScript `Date` rollover.
|
|
45
|
+
Treat both behavior changes as breaking when planning the migration.
|
|
19
46
|
|
|
20
47
|
```ts
|
|
21
|
-
import
|
|
22
|
-
|
|
23
|
-
toBusinessDateTime,
|
|
24
|
-
formatBusinessDateTime,
|
|
25
|
-
addBusinessDays,
|
|
26
|
-
} from '@rdlabo/workers-hono-kit/business-time';
|
|
27
|
-
|
|
28
|
-
const now = new Date('2026-07-05T21:00:00Z');
|
|
29
|
-
toBusinessDate(now); // '2026-07-06' (JST)
|
|
30
|
-
toBusinessDateTime(now); // '2026-07-06 06:00:00'
|
|
31
|
-
formatBusinessDateTime(now); // '2026-07-06T06:00:00'
|
|
32
|
-
addBusinessDays('2026-07-06', 3); // '2026-07-09'
|
|
48
|
+
// Deprecated; migrate the import path when practical.
|
|
49
|
+
import { toBusinessDateTime } from '@rdlabo/workers-hono-kit/business-time';
|
|
33
50
|
```
|