@rdlabo/workers-hono-kit 0.10.6 → 0.11.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,48 @@
1
+ # Storage-agnostic role policies
2
+
3
+ `createRolePolicy` builds pure RBAC checks without coupling the policy to a database schema. The application can resolve roles from a membership table, a `users.role` column, token claims, or any other source.
4
+
5
+ ```ts
6
+ import { createRolePolicy } from '@rdlabo/workers-hono-kit';
7
+
8
+ type Role = 'owner' | 'admin' | 'member' | 'read';
9
+ type Permission = 'organization.manage' | 'resource.write' | 'resource.read';
10
+
11
+ const policy = createRolePolicy<Role, Permission>({
12
+ permissions: {
13
+ owner: ['organization.manage', 'resource.write', 'resource.read'],
14
+ admin: ['resource.write', 'resource.read'],
15
+ member: ['resource.write', 'resource.read'],
16
+ read: ['resource.read'],
17
+ },
18
+ assignableRoles: {
19
+ owner: ['admin', 'member', 'read'],
20
+ admin: ['member', 'read'],
21
+ member: [],
22
+ read: [],
23
+ },
24
+ manageableRoles: {
25
+ owner: ['admin', 'member', 'read'],
26
+ admin: ['member', 'read'],
27
+ member: [],
28
+ read: [],
29
+ },
30
+ });
31
+ ```
32
+
33
+ ## Policy fields
34
+
35
+ - `permissions` maps a role to the set of permissions it grants.
36
+ - `assignableRoles` defines which roles an actor may grant to another subject.
37
+ - `manageableRoles` defines which existing subject roles an actor may manage.
38
+
39
+ The resulting `RolePolicy` has four pure checks:
40
+
41
+ ```ts
42
+ policy.hasPermission('member', 'resource.write'); // true
43
+ policy.canAssignRole('admin', 'member'); // true
44
+ policy.canManageRole('owner', 'admin'); // true
45
+ policy.canChangeRole('owner', 'admin', 'member'); // true
46
+ ```
47
+
48
+ `canChangeRole(actor, current, next)` is a combination: the actor must be able to manage the subject's current role and also be allowed to assign the next role. Keeping role lookup and policy checks separate means the same policy can be reused no matter where roles are stored.
@@ -0,0 +1,25 @@
1
+ ## Testing entry point
2
+
3
+ `@rdlabo/workers-hono-kit/testing` requires the database peers and is never loaded by production code.
4
+
5
+ | Helper | Use |
6
+ | --------------------------------------------------------------- | --------------------------------------------------------------------- |
7
+ | `createTestDb()` | Build a Drizzle-migration-backed test database. |
8
+ | `FakeFirebaseVerifier` | Verify registered in-memory Firebase tokens. |
9
+ | `createPoolDatabase()` / `createNoopDatabase()` | Provide database implementations for tests. |
10
+ | `authHeaders()` / `registerFirebaseToken()` / `provisionUser()` | Prepare authenticated route tests. |
11
+ | `configurableFake()` | Create a partial fake that fails explicitly for unconfigured members. |
12
+ | `fakeKv()` / `fakeQueue()` | Use in-memory Workers binding fakes. |
13
+ | Stripe fixture factories | Create typed events, sessions, subscriptions, prices, and intents. |
14
+
15
+ ## Queues
16
+
17
+ `sendInChunks()` bounds queue sends under Workers subrequest limits. `processBatch()` handles a message batch sequentially, bounding concurrent subrequests to one; errors explicitly marked with `queueDisposition: 'discard'` are acknowledged, while other failures retry. `createQueueErrorHandler()` adds logging and optional final-attempt reporting.
18
+
19
+ ## Operational CLI
20
+
21
+ The package publishes commands for synchronizing development AWS credentials, checking subrequest fanout, creating database baselines, checking realtime bundles, and querying Durable Object metrics. Run the exact CLI shipped with the installed package version and review its `--help` before changing infrastructure.
22
+
23
+ ## Trust boundaries
24
+
25
+ AWS, Firebase, AI Gateway, Stripe, and database clients are configured by the consuming application. Do not place domain-specific credentials, schemas, or authorization policy inside the shared kit. Use `createRolePolicy()` only for storage-agnostic role and relation mapping; the application still owns its roles and permissions.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rdlabo/workers-hono-kit",
3
- "version": "0.10.6",
3
+ "version": "0.11.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -11,12 +11,12 @@
11
11
  "license": "MIT",
12
12
  "repository": {
13
13
  "type": "git",
14
- "url": "git+https://github.com/rdlabo-team/workers-hono-kit.git"
14
+ "url": "git+https://github.com/rdlabo-dev/workers-hono-kit.git"
15
15
  },
16
16
  "bugs": {
17
- "url": "https://github.com/rdlabo-team/workers-hono-kit/issues"
17
+ "url": "https://github.com/rdlabo-dev/workers-hono-kit/issues"
18
18
  },
19
- "homepage": "https://github.com/rdlabo-team/workers-hono-kit#readme",
19
+ "homepage": "https://docs.rdlabo.dev/projects/workers-hono-kit",
20
20
  "keywords": [
21
21
  "hono",
22
22
  "cloudflare-workers",
@@ -43,6 +43,7 @@
43
43
  "files": [
44
44
  "dist",
45
45
  "scripts",
46
+ "docs",
46
47
  "!src/**/*.spec.ts"
47
48
  ],
48
49
  "bin": {
File without changes
File without changes
@@ -1,35 +0,0 @@
1
- /**
2
- * Drizzle `customType` params for a MySQL `DECIMAL` column.
3
- *
4
- * @remarks
5
- * - **Reads (SELECT)**: `fromDriver` unifies the driver value (`number` / `string` / `null`) to a JS
6
- * `number | null`. Combined with the connection's `decimalNumbers: true`
7
- * ({@link hyperdriveConnectionOptions} default), it aligns values to numbers even on the Drizzle
8
- * builder path when strings like `"0"` / `"100.00"` slip in, without dropping `0`.
9
- * - **Writes (INSERT/UPDATE)**: `toDriver` binds the number to mysql2 as-is (no `String()` conversion).
10
- * - Raw-SQL `db.read` relies on the connection's `decimalNumbers: true`; the column's `fromDriver` is
11
- * for the Drizzle `select` path.
12
- */
13
- export interface DecimalNumberConfig {
14
- precision: number;
15
- scale: number;
16
- }
17
- /**
18
- * Normalize a DECIMAL value coming from mysql2 / Drizzle to a JS `number | null`.
19
- * `0` is preserved as-is so it is not dropped as falsy.
20
- *
21
- * @param value - the raw driver value (`number` / `string` / `bigint` / nullish).
22
- * @returns the coerced finite number, or `null` when it cannot be resolved.
23
- */
24
- export declare function coerceDecimalNumber(value: unknown): number | null;
25
- /**
26
- * Params for a `customType`. For advanced use; the {@link decimalNumber} column helper is usually enough.
27
- *
28
- * @param config - the DECIMAL `precision` / `scale`.
29
- * @returns the `customType` params (`dataType` / `fromDriver` / `toDriver`).
30
- */
31
- export declare const decimalNumberParams: (config: DecimalNumberConfig) => {
32
- dataType: () => string;
33
- fromDriver: (value: unknown) => number | null;
34
- toDriver: (value: number | string | null) => number | string | null;
35
- };
@@ -1,58 +0,0 @@
1
- /**
2
- * Drizzle `customType` params for a MySQL `DECIMAL` column.
3
- *
4
- * @remarks
5
- * - **Reads (SELECT)**: `fromDriver` unifies the driver value (`number` / `string` / `null`) to a JS
6
- * `number | null`. Combined with the connection's `decimalNumbers: true`
7
- * ({@link hyperdriveConnectionOptions} default), it aligns values to numbers even on the Drizzle
8
- * builder path when strings like `"0"` / `"100.00"` slip in, without dropping `0`.
9
- * - **Writes (INSERT/UPDATE)**: `toDriver` binds the number to mysql2 as-is (no `String()` conversion).
10
- * - Raw-SQL `db.read` relies on the connection's `decimalNumbers: true`; the column's `fromDriver` is
11
- * for the Drizzle `select` path.
12
- */
13
- /**
14
- * Normalize a DECIMAL value coming from mysql2 / Drizzle to a JS `number | null`.
15
- * `0` is preserved as-is so it is not dropped as falsy.
16
- *
17
- * @param value - the raw driver value (`number` / `string` / `bigint` / nullish).
18
- * @returns the coerced finite number, or `null` when it cannot be resolved.
19
- */
20
- export function coerceDecimalNumber(value) {
21
- if (value === null || value === undefined) {
22
- return null;
23
- }
24
- if (typeof value === 'number') {
25
- return Number.isFinite(value) ? value : null;
26
- }
27
- if (typeof value === 'string') {
28
- const trimmed = value.trim();
29
- if (trimmed === '') {
30
- return null;
31
- }
32
- const n = Number(trimmed);
33
- return Number.isFinite(n) ? n : null;
34
- }
35
- if (typeof value === 'bigint') {
36
- return Number(value);
37
- }
38
- return null;
39
- }
40
- /**
41
- * Params for a `customType`. For advanced use; the {@link decimalNumber} column helper is usually enough.
42
- *
43
- * @param config - the DECIMAL `precision` / `scale`.
44
- * @returns the `customType` params (`dataType` / `fromDriver` / `toDriver`).
45
- */
46
- export const decimalNumberParams = (config) => ({
47
- dataType: () => `decimal(${config.precision},${config.scale})`,
48
- fromDriver: (value) => coerceDecimalNumber(value),
49
- toDriver: (value) => {
50
- if (value === null) {
51
- return null;
52
- }
53
- if (typeof value === 'number') {
54
- return value;
55
- }
56
- return coerceDecimalNumber(value);
57
- },
58
- });