@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/docs/data-layer.md
CHANGED
|
@@ -1,17 +1,62 @@
|
|
|
1
|
-
|
|
1
|
+
# Data Layer
|
|
2
|
+
|
|
3
|
+
Standalone MySQL / Hyperdrive access for Workers, plus the thin Hono container adapter. Fixed
|
|
4
|
+
`+09:00` storage helpers are independent of IANA display timezones.
|
|
5
|
+
|
|
6
|
+
- [HTTP and Authentication](./http-auth.md)
|
|
7
|
+
- [Realtime and Offline](./realtime-offline.md)
|
|
8
|
+
- [Testing and Operations](./testing-operations.md)
|
|
9
|
+
- [API reference](./api.md)
|
|
10
|
+
|
|
11
|
+
Import database helpers from `@rdlabo/workers-mysql`. The package installs `mysql2` directly. Add
|
|
12
|
+
`drizzle-orm` only when using the `/drizzle` or `/testing` entry point. The old
|
|
13
|
+
`@rdlabo/workers-hono-kit/db` path is a deprecated compatibility re-export.
|
|
14
|
+
|
|
15
|
+
Workers using `mysql2` must enable its required Node.js networking APIs:
|
|
16
|
+
|
|
17
|
+
```toml
|
|
18
|
+
# wrangler.toml
|
|
19
|
+
compatibility_flags = ["nodejs_compat"]
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
npm install @rdlabo/workers-mysql drizzle-orm
|
|
24
|
+
npm install -D @types/node@20
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
For candidate tarball installation, see [Development](./development.md).
|
|
28
|
+
|
|
29
|
+
## Migrating from workers-hono-kit
|
|
30
|
+
|
|
31
|
+
The package boundary is a breaking change in `0.12.0`. Update these imports before
|
|
32
|
+
upgrading:
|
|
33
|
+
|
|
34
|
+
| Current import | Replacement |
|
|
35
|
+
| ------------------------------------------------------- | ----------------------------------------------------- |
|
|
36
|
+
| `createContainerRuntime` from the kit root | `@rdlabo/workers-hono-kit/mysql` |
|
|
37
|
+
| `retryWhenDeadlock` from the kit root | `@rdlabo/workers-mysql` |
|
|
38
|
+
| DB helpers from `@rdlabo/workers-hono-kit/db` | `@rdlabo/workers-mysql`, `/drizzle`, or `/migrations` |
|
|
39
|
+
| DB test helpers from `@rdlabo/workers-hono-kit/testing` | `@rdlabo/workers-mysql/testing` |
|
|
40
|
+
|
|
41
|
+
The old `/db` and DB-related `/testing` exports remain available for backward compatibility.
|
|
42
|
+
Their individual functions and types carry `@deprecated` notices pointing to the standalone
|
|
43
|
+
package. No removal release is scheduled. The kit-owned `/mysql` adapter is not deprecated.
|
|
44
|
+
Because `/testing` statically re-exports DB helpers, all kit `/testing` consumers must install the
|
|
45
|
+
MySQL package and `drizzle-orm`, including consumers of non-DB helpers such as Firebase or KV fakes.
|
|
2
46
|
|
|
3
47
|
## Hyperdrive database
|
|
4
48
|
|
|
5
49
|
`createHyperdriveDatabase()` lazily opens primary and replica connections from Hyperdrive bindings. `read()` uses the replica query runner; `query()` provides an explicit raw primary SELECT for read-after-write consistency; writes and transactions use the primary Drizzle instance. `readTransaction()` runs Drizzle and raw reads against one primary repeatable-read snapshot. Read transactions are serialized on one separately cached connection so their boundaries cannot mix with each other or with ordinary primary operations. After a fatal mysql2 connection error, a single read or the complete read-only transaction opens a fresh connection and repeats at most once. Writes and write transactions are not repeated because their commit state may be ambiguous. Workers owns connection cleanup at invocation end.
|
|
6
50
|
|
|
7
51
|
```ts
|
|
8
|
-
import { createHyperdriveDatabase } from '@rdlabo/workers-
|
|
52
|
+
import { createHyperdriveDatabase } from '@rdlabo/workers-mysql';
|
|
53
|
+
import { DRIZZLE_ORM_OPTIONS } from '@rdlabo/workers-mysql/drizzle';
|
|
9
54
|
import { drizzle } from 'drizzle-orm/mysql2';
|
|
10
55
|
|
|
11
56
|
const db = createHyperdriveDatabase({
|
|
12
57
|
primaryHyperdrive: env.DB_PRIMARY,
|
|
13
58
|
replicaHyperdrive: env.DB_REPLICA,
|
|
14
|
-
createOrm: (primary) => drizzle(primary, { schema }),
|
|
59
|
+
createOrm: (primary) => drizzle(primary, { schema, ...DRIZZLE_ORM_OPTIONS }),
|
|
15
60
|
});
|
|
16
61
|
|
|
17
62
|
const rows = await db.read<Item>('SELECT * FROM items WHERE id = ?', [id]);
|
|
@@ -31,6 +76,12 @@ Do not call `readTransaction()` recursively from inside its callback. Calls shar
|
|
|
31
76
|
|
|
32
77
|
Use `hyperdriveConnectionOptions()` when constructing lower-level mysql2 connections. The default JavaScript date conversion timezone is `+09:00`; it does not change the MySQL session timezone.
|
|
33
78
|
|
|
79
|
+
Hono applications that want the standard request container use the thin adapter separately:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
import { createContainerRuntime } from '@rdlabo/workers-hono-kit/mysql';
|
|
83
|
+
```
|
|
84
|
+
|
|
34
85
|
## Writes and retries
|
|
35
86
|
|
|
36
87
|
- `retryWhenDeadlock()` retries `ER_LOCK_DEADLOCK` with exponential backoff.
|
|
@@ -41,10 +92,16 @@ Use `hyperdriveConnectionOptions()` when constructing lower-level mysql2 connect
|
|
|
41
92
|
|
|
42
93
|
Use `jstTimestamp`, `jstDatetime`, and `jstDate` for shared date behavior. Pair update timestamps with `jstOnUpdateNow()` because custom timestamp types do not expose Drizzle's `.onUpdateNow()`. For decimal columns, use Drizzle's `decimal(name, { precision, scale, mode: 'number' })` directly.
|
|
43
94
|
|
|
44
|
-
|
|
95
|
+
Generic business-time conversion is separate from the DB's fixed `+09:00` wire contract.
|
|
96
|
+
Install `@rdlabo/workers-timezone` directly and migrate from the kit's deprecated `/business-time`
|
|
97
|
+
compatibility path to its canonical entry point.
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
npm install @rdlabo/workers-timezone
|
|
101
|
+
```
|
|
45
102
|
|
|
46
103
|
```ts
|
|
47
|
-
import { addBusinessDays, toBusinessDateTime } from '@rdlabo/workers-
|
|
104
|
+
import { addBusinessDays, toBusinessDateTime } from '@rdlabo/workers-timezone';
|
|
48
105
|
|
|
49
106
|
toBusinessDateTime(new Date('2026-07-05T21:00:00Z'));
|
|
50
107
|
// '2026-07-06 06:00:00'
|
|
@@ -52,3 +109,9 @@ toBusinessDateTime(new Date('2026-07-05T21:00:00Z'));
|
|
|
52
109
|
addBusinessDays('2026-07-06', 3);
|
|
53
110
|
// '2026-07-09'
|
|
54
111
|
```
|
|
112
|
+
|
|
113
|
+
## Next step
|
|
114
|
+
|
|
115
|
+
Continue to [Realtime and Offline](./realtime-offline.md), or see
|
|
116
|
+
[`@rdlabo/workers-mysql`](https://docs.rdlabo.dev/projects/workers-mysql/docs/readme) for the
|
|
117
|
+
standalone package guides.
|
package/docs/development.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Development
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Maintainer commands and release procedures for this monorepo. Application install guides live in
|
|
4
|
+
each package README.
|
|
4
5
|
|
|
5
6
|
```bash
|
|
6
7
|
npm install
|
|
@@ -10,9 +11,128 @@ npm test # vitest
|
|
|
10
11
|
npm run build # tsc -p tsconfig.build.json → dist/
|
|
11
12
|
```
|
|
12
13
|
|
|
14
|
+
## Candidate artifacts and publication
|
|
15
|
+
|
|
16
|
+
Pull requests and merges build immutable candidate tarballs for all three packages:
|
|
17
|
+
|
|
18
|
+
- `rdlabo-workers-hono-kit-*.tgz`
|
|
19
|
+
- `rdlabo-workers-timezone-*.tgz`
|
|
20
|
+
- `rdlabo-workers-mysql-*.tgz`
|
|
21
|
+
|
|
22
|
+
Install all three when testing the complete package boundary:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
npm install drizzle-orm ai-gateway-provider ./rdlabo-workers-mysql-*.tgz ./rdlabo-workers-timezone-*.tgz ./rdlabo-workers-hono-kit-*.tgz
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
No publication opt-in variable is required. Release tags trigger publication; candidate publication
|
|
29
|
+
requires the authorization and successful source-run checks described below.
|
|
30
|
+
The publisher validates all three archives before any write, then publishes timezone, MySQL, and
|
|
31
|
+
the kit in that order. A retry skips a version only when the registry's SHA-512 integrity matches
|
|
32
|
+
the local tarball; different content under an existing version fails and requires a version bump.
|
|
33
|
+
|
|
34
|
+
## Release bundle verification
|
|
35
|
+
|
|
36
|
+
Use Node.js 24 with a current npm CLI. From a clean checkout at the reviewed commit, verify the
|
|
37
|
+
release bundle without publishing:
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
npm ci
|
|
41
|
+
npm run typecheck
|
|
42
|
+
npm run lint
|
|
43
|
+
npm test
|
|
44
|
+
npm run test:release
|
|
45
|
+
npm run test:package
|
|
46
|
+
RELEASE_DIR=$(mktemp -d)
|
|
47
|
+
npm pack --ignore-scripts --workspaces --pack-destination "$RELEASE_DIR"
|
|
48
|
+
node tooling/release/publish-packages.mjs --directory "$RELEASE_DIR" --manifests . --tag latest
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The last command only validates and prints the plan: it does not publish or contact npm.
|
|
52
|
+
Confirm registry visibility for the packages you intend to publish or skip:
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
npm view @rdlabo/workers-timezone version --registry https://registry.npmjs.org/
|
|
56
|
+
npm view @rdlabo/workers-mysql version --registry https://registry.npmjs.org/
|
|
57
|
+
npm view @rdlabo/workers-hono-kit version --registry https://registry.npmjs.org/
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
If a lookup fails for a version that should already exist, resolve registry visibility before
|
|
61
|
+
releasing. The tag workflow compares archive integrity and skips identical versions when retrying a
|
|
62
|
+
release. Changes to packaged contents require a new synchronized release version.
|
|
63
|
+
|
|
64
|
+
## Trusted Publishing and repository protection
|
|
65
|
+
|
|
66
|
+
Verify each public package's Trusted Publisher connection against these values before releasing:
|
|
67
|
+
|
|
68
|
+
| Field | Value |
|
|
69
|
+
| ------------------------ | ------------------------------------------------------------ |
|
|
70
|
+
| Organization / user | `rdlabo-dev` |
|
|
71
|
+
| Repository | `workers-hono-kit` |
|
|
72
|
+
| Workflow filename | `release.yml` |
|
|
73
|
+
| Environment | Leave empty (the workflow does not use a GitHub environment) |
|
|
74
|
+
| Allowed action, if shown | Direct `npm publish` |
|
|
75
|
+
|
|
76
|
+
Do not create duplicate Trusted Publisher connections. Connections are npm account settings, not
|
|
77
|
+
repository files. See [npm's Trusted Publishing guide](https://docs.npmjs.com/trusted-publishers/).
|
|
78
|
+
|
|
79
|
+
Before releasing, install the packed candidates in a fresh consumer directory (using `RELEASE_DIR`
|
|
80
|
+
from above):
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
npm install "$RELEASE_DIR"/rdlabo-workers-timezone-*.tgz "$RELEASE_DIR"/rdlabo-workers-mysql-*.tgz "$RELEASE_DIR"/rdlabo-workers-hono-kit-*.tgz drizzle-orm
|
|
84
|
+
npm install -D @types/node@20
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Before releasing, create an **active tag ruleset** for `v*` in GitHub repository Settings → Rules:
|
|
88
|
+
restrict tag creation, updates, and deletion; grant bypass only to the designated release maintainer.
|
|
89
|
+
That maintainer must tag only reviewed commits on `main`. The tag workflow runs code from the tag,
|
|
90
|
+
so unrestricted tag creation would bypass the PR review boundary. Keep the default branch protected
|
|
91
|
+
and require review for workflow/publisher changes as well. Configure these repository settings in
|
|
92
|
+
GitHub; they are not applied by merging documentation.
|
|
93
|
+
|
|
94
|
+
CI uses OIDC and generates provenance; no npm token secret or publication opt-in variable is needed.
|
|
95
|
+
After merging the reviewed changes, `npm run release` creates the next release tag.
|
|
96
|
+
Eligible merge/PR candidate events can also publish betas after their authorization checks pass.
|
|
97
|
+
|
|
98
|
+
## Subsequent releases
|
|
99
|
+
|
|
100
|
+
From a clean, up-to-date `main` checkout with dependencies installed, run:
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
npm run release
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Choose the next version in `np`. Its npm `version` hook synchronizes the kit, timezone, and MySQL
|
|
107
|
+
versions, internal dependency ranges, and lockfile **before** npm creates the release commit/tag.
|
|
108
|
+
For example, choosing `0.12.1` advances all three packages to `0.12.1`. No separate workspace bump
|
|
109
|
+
is required. The same applies to RCs. The tag workflow verifies synchronization, tests the packages,
|
|
110
|
+
and publishes all three in dependency order. Unlike the Stripe repository's CI-side version update,
|
|
111
|
+
no additional version commit is needed after tagging: the release tag already contains the complete
|
|
112
|
+
version set.
|
|
113
|
+
|
|
114
|
+
CI publishing requires the Trusted Publishing configuration above. Do not use `--ignore-scripts`
|
|
115
|
+
when creating release versions: it bypasses synchronization and the tag workflow will reject the set.
|
|
116
|
+
|
|
117
|
+
- A root `v<version>` tag must match the synchronized versions on the private workspace root and all
|
|
118
|
+
three public packages under `packages/`. Stable versions publish all three packages with `latest`;
|
|
119
|
+
prerelease versions publish all three with `next`.
|
|
120
|
+
- All three versions must match for tag releases. Retries skip already-published archives only on
|
|
121
|
+
an exact integrity match; do not change an archive under an existing version.
|
|
122
|
+
- `/beta` on a ready PR requires an owner/maintainer and successful Validation + Package Candidate
|
|
123
|
+
runs. A PR changing release workflows or publisher/versioning scripts cannot publish a beta until
|
|
124
|
+
those changes are reviewed and merged. Automatic merge beta has the same restriction.
|
|
125
|
+
- PR betas use the trusted `main` package versions: all three version fields must match `main`.
|
|
126
|
+
Test version-bump PRs with the downloaded artifacts; their new versions can publish as merge
|
|
127
|
+
betas after reaching `main`. A mismatched PR version is rejected before any registry write.
|
|
128
|
+
- Candidates publish all three immutable versions with one commit suffix and exact kit peer ranges.
|
|
129
|
+
The success message includes all three versions in the install command.
|
|
130
|
+
- Candidate publication executes the publisher from the trusted default-branch commit. It reads
|
|
131
|
+
archive metadata without extracting or running candidate code, and uses `--ignore-scripts`.
|
|
132
|
+
|
|
13
133
|
## Local development / linking
|
|
14
134
|
|
|
15
|
-
If you consume this package via a local path (e.g. `"@rdlabo/workers-hono-kit": "../../hono-kit"`) rather than from npm, TypeScript and esbuild resolve the package's bare imports from
|
|
135
|
+
If you consume this package via a local path (e.g. `"@rdlabo/workers-hono-kit": "../../workers-hono-kit/packages/hono-kit"`) rather than from npm, TypeScript and esbuild resolve the package's bare imports from _its own_ `node_modules`, which can create a second `zod` instance. That breaks types where your zod-inferred values flow into other libraries (e.g. Drizzle inserts). Dedupe with tsconfig `paths`:
|
|
16
136
|
|
|
17
137
|
```jsonc
|
|
18
138
|
{
|
|
@@ -21,9 +141,9 @@ If you consume this package via a local path (e.g. `"@rdlabo/workers-hono-kit":
|
|
|
21
141
|
"paths": {
|
|
22
142
|
"zod": ["node_modules/zod"],
|
|
23
143
|
"zod/*": ["node_modules/zod/*"],
|
|
24
|
-
"@hono/zod-validator": ["node_modules/@hono/zod-validator"]
|
|
25
|
-
}
|
|
26
|
-
}
|
|
144
|
+
"@hono/zod-validator": ["node_modules/@hono/zod-validator"],
|
|
145
|
+
},
|
|
146
|
+
},
|
|
27
147
|
}
|
|
28
148
|
```
|
|
29
149
|
|
package/docs/http-auth.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
# HTTP and Authentication
|
|
2
|
+
|
|
3
|
+
Validation, Firebase authentication, shared NestJS-shaped error bodies, and response finalization
|
|
4
|
+
for Hono Workers APIs.
|
|
5
|
+
|
|
6
|
+
- [Data Layer](./data-layer.md)
|
|
7
|
+
- [Realtime and Offline](./realtime-offline.md)
|
|
8
|
+
- [Testing and Operations](./testing-operations.md)
|
|
9
|
+
- [API reference](./api.md)
|
|
10
|
+
|
|
1
11
|
## Validation
|
|
2
12
|
|
|
3
13
|
`validate(target, schema, options?)` adapts a Zod schema to Hono and returns a NestJS `ValidationPipe`-shaped `400` response. Use `createValidate({ sentry })` to bind optional reporting once.
|
|
@@ -34,3 +44,8 @@ Mount `createMaintenanceMiddleware()` after CORS and before container or databas
|
|
|
34
44
|
## Deferred work and observability
|
|
35
45
|
|
|
36
46
|
`createWaitUntilDefer(ctx)` registers background work through `waitUntil` and logs rejected work. `perfLog()` emits per-request application latency, colo, cold/warm state, route, and status to Workers Logs and optionally Analytics Engine.
|
|
47
|
+
|
|
48
|
+
## Next step
|
|
49
|
+
|
|
50
|
+
Continue to [Data Layer](./data-layer.md) for MySQL and Hyperdrive, or [API](./api.md) for the full
|
|
51
|
+
export list.
|
package/docs/realtime-offline.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
# Realtime and Offline
|
|
2
|
+
|
|
3
|
+
Durable Object WebSocket helpers and table-agnostic offline replica contracts. Product schemas,
|
|
4
|
+
Zod shapes, and domain policy stay in the application.
|
|
5
|
+
|
|
6
|
+
- [HTTP and Authentication](./http-auth.md)
|
|
7
|
+
- [Data Layer](./data-layer.md)
|
|
8
|
+
- [Testing and Operations](./testing-operations.md)
|
|
9
|
+
- [API reference](./api.md)
|
|
10
|
+
|
|
1
11
|
## Durable Object realtime
|
|
2
12
|
|
|
3
13
|
The root and `/realtime` entry points expose the same focused realtime primitives:
|
|
@@ -25,3 +35,8 @@ Wire helpers canonicalize values:
|
|
|
25
35
|
- `replicaNowIso(clock?)` → injectable current time
|
|
26
36
|
|
|
27
37
|
Journal helpers enforce cursor coverage, retention, mutation transactions, and rebaseline behavior. Wire compatibility helpers let an application accept explicit previous fingerprints while maintaining a canonical current fingerprint.
|
|
38
|
+
|
|
39
|
+
## Next step
|
|
40
|
+
|
|
41
|
+
Continue to [Testing and Operations](./testing-operations.md), or [Offline API](./api-offline.md) for
|
|
42
|
+
converter and wire export details.
|
package/docs/role-policies.md
CHANGED
|
@@ -39,10 +39,10 @@ const policy = createRolePolicy<Role, Permission>({
|
|
|
39
39
|
The resulting `RolePolicy` has four pure checks:
|
|
40
40
|
|
|
41
41
|
```ts
|
|
42
|
-
policy.hasPermission('member', 'resource.write');
|
|
43
|
-
policy.canAssignRole('admin', 'member');
|
|
44
|
-
policy.canManageRole('owner', 'admin');
|
|
45
|
-
policy.canChangeRole('owner', 'admin', 'member');
|
|
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
46
|
```
|
|
47
47
|
|
|
48
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.
|
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
# Testing and Operations
|
|
2
|
+
|
|
3
|
+
Test helpers, queue batching, operational CLIs, and trust boundaries for Hono Workers applications.
|
|
4
|
+
|
|
5
|
+
- [HTTP and Authentication](./http-auth.md)
|
|
6
|
+
- [Data Layer](./data-layer.md)
|
|
7
|
+
- [Realtime and Offline](./realtime-offline.md)
|
|
8
|
+
- [API reference](./api.md)
|
|
9
|
+
|
|
1
10
|
## Testing entry point
|
|
2
11
|
|
|
3
|
-
`@rdlabo/workers-hono-kit/testing`
|
|
12
|
+
`@rdlabo/workers-hono-kit/testing` is never loaded by production code. Its DB helpers are deprecated
|
|
13
|
+
compatibility exports from `@rdlabo/workers-mysql/testing`, while Firebase, HTTP, Stripe, KV, and
|
|
14
|
+
Queue fakes remain in the Hono kit.
|
|
4
15
|
|
|
5
16
|
| Helper | Use |
|
|
6
17
|
| --------------------------------------------------------------- | --------------------------------------------------------------------- |
|
|
@@ -12,14 +23,26 @@
|
|
|
12
23
|
| `fakeKv()` / `fakeQueue()` | Use in-memory Workers binding fakes. |
|
|
13
24
|
| Stripe fixture factories | Create typed events, sessions, subscriptions, prices, and intents. |
|
|
14
25
|
|
|
26
|
+
Because `/testing` statically re-exports DB helpers, every kit `/testing` consumer must install
|
|
27
|
+
`@rdlabo/workers-mysql` and `drizzle-orm`, including consumers of non-DB helpers.
|
|
28
|
+
|
|
15
29
|
## Queues
|
|
16
30
|
|
|
17
31
|
`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
32
|
|
|
19
33
|
## Operational CLI
|
|
20
34
|
|
|
21
|
-
The
|
|
35
|
+
The Hono kit publishes commands for synchronizing development AWS credentials, checking subrequest
|
|
36
|
+
fanout, checking realtime bundles, and querying Durable Object metrics. Database baselining is owned
|
|
37
|
+
by `workers-mysql-db-baseline`; the old `workers-hono-kit-db-baseline` command delegates to it during
|
|
38
|
+
the compatibility period. Run the exact CLI shipped with the installed version before changing
|
|
39
|
+
infrastructure.
|
|
22
40
|
|
|
23
41
|
## Trust boundaries
|
|
24
42
|
|
|
25
43
|
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.
|
|
44
|
+
|
|
45
|
+
## Next step
|
|
46
|
+
|
|
47
|
+
See [Testing APIs](./api-testing.md) for export tables, [CLI](./cli.md) for command details, or
|
|
48
|
+
[API](./api.md) for the full package map.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rdlabo/workers-hono-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0-beta.pr48.sha371f5792ce8a",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"repository": {
|
|
13
13
|
"type": "git",
|
|
14
|
-
"url": "git+https://github.com/rdlabo-dev/workers-hono-kit.git"
|
|
14
|
+
"url": "git+https://github.com/rdlabo-dev/workers-hono-kit.git",
|
|
15
|
+
"directory": "packages/hono-kit"
|
|
15
16
|
},
|
|
16
17
|
"bugs": {
|
|
17
18
|
"url": "https://github.com/rdlabo-dev/workers-hono-kit/issues"
|
|
@@ -47,11 +48,11 @@
|
|
|
47
48
|
"!src/**/*.spec.ts"
|
|
48
49
|
],
|
|
49
50
|
"bin": {
|
|
50
|
-
"workers-hono-kit-sync-dev-aws": "
|
|
51
|
-
"workers-hono-kit-check-subrequest-fanout": "
|
|
52
|
-
"workers-hono-kit-db-baseline": "
|
|
53
|
-
"workers-hono-kit-check-realtime-bundle": "
|
|
54
|
-
"workers-hono-kit-query-realtime-do-metrics": "
|
|
51
|
+
"workers-hono-kit-sync-dev-aws": "scripts/sync-dev-aws.mjs",
|
|
52
|
+
"workers-hono-kit-check-subrequest-fanout": "scripts/check-subrequest-fanout.mjs",
|
|
53
|
+
"workers-hono-kit-db-baseline": "scripts/db-baseline.mjs",
|
|
54
|
+
"workers-hono-kit-check-realtime-bundle": "scripts/check-realtime-bundle.mjs",
|
|
55
|
+
"workers-hono-kit-query-realtime-do-metrics": "scripts/query-realtime-do-metrics.mjs"
|
|
55
56
|
},
|
|
56
57
|
"exports": {
|
|
57
58
|
".": {
|
|
@@ -64,6 +65,11 @@
|
|
|
64
65
|
"import": "./dist/db/index.js",
|
|
65
66
|
"default": "./dist/db/index.js"
|
|
66
67
|
},
|
|
68
|
+
"./mysql": {
|
|
69
|
+
"types": "./dist/mysql/index.d.ts",
|
|
70
|
+
"import": "./dist/mysql/index.js",
|
|
71
|
+
"default": "./dist/mysql/index.js"
|
|
72
|
+
},
|
|
67
73
|
"./business-time": {
|
|
68
74
|
"types": "./dist/business-time/index.d.ts",
|
|
69
75
|
"import": "./dist/business-time/index.js",
|
|
@@ -87,41 +93,42 @@
|
|
|
87
93
|
},
|
|
88
94
|
"scripts": {
|
|
89
95
|
"build": "node scripts/clean-dist.mjs && tsc -p tsconfig.build.json",
|
|
90
|
-
"prepare": "npm run build",
|
|
91
96
|
"typecheck": "tsc --noEmit",
|
|
92
97
|
"test": "vitest run",
|
|
93
98
|
"test:watch": "vitest",
|
|
94
99
|
"lint": "eslint \"src/**/*.ts\"",
|
|
95
100
|
"lint:fix": "eslint \"src/**/*.ts\" --fix",
|
|
96
|
-
"
|
|
97
|
-
"format
|
|
98
|
-
"
|
|
101
|
+
"test:package": "node scripts/workspace-package-smoke.mjs",
|
|
102
|
+
"format": "prettier --write .",
|
|
103
|
+
"format:check": "prettier --check .",
|
|
104
|
+
"prepack": "npm run build"
|
|
99
105
|
},
|
|
100
106
|
"dependencies": {
|
|
101
107
|
"stripe": "^20.4.1"
|
|
102
108
|
},
|
|
103
109
|
"peerDependencies": {
|
|
104
110
|
"@hono/zod-validator": "^0.8.0",
|
|
111
|
+
"@rdlabo/workers-mysql": "0.1.0-beta.pr48.sha371f5792ce8a",
|
|
112
|
+
"@rdlabo/workers-timezone": "0.1.0-beta.pr48.sha371f5792ce8a",
|
|
105
113
|
"ai": "^6.0.0",
|
|
106
114
|
"ai-gateway-provider": "^3.1.0",
|
|
107
115
|
"aws4fetch": "^1.0.20",
|
|
108
116
|
"drizzle-orm": "^0.45.2",
|
|
109
117
|
"hono": "^4.6.0",
|
|
110
118
|
"jose": "^6.2.0",
|
|
111
|
-
"mysql2": "^3.14.0",
|
|
112
119
|
"zod": "^4.4.0"
|
|
113
120
|
},
|
|
114
121
|
"peerDependenciesMeta": {
|
|
115
|
-
"
|
|
122
|
+
"@rdlabo/workers-mysql": {
|
|
116
123
|
"optional": true
|
|
117
124
|
},
|
|
118
|
-
"
|
|
125
|
+
"@rdlabo/workers-timezone": {
|
|
119
126
|
"optional": true
|
|
120
127
|
},
|
|
121
|
-
"
|
|
128
|
+
"ai": {
|
|
122
129
|
"optional": true
|
|
123
130
|
},
|
|
124
|
-
"
|
|
131
|
+
"drizzle-orm": {
|
|
125
132
|
"optional": true
|
|
126
133
|
}
|
|
127
134
|
},
|
|
@@ -143,8 +150,7 @@
|
|
|
143
150
|
"eslint": "^9.39.4",
|
|
144
151
|
"hono": "^4.6.0",
|
|
145
152
|
"jose": "^6.2.3",
|
|
146
|
-
"mysql2": "3.
|
|
147
|
-
"np": "^8.0.4",
|
|
153
|
+
"mysql2": "3.24.3",
|
|
148
154
|
"prettier": "^3.8.4",
|
|
149
155
|
"typescript": "~5.6.2",
|
|
150
156
|
"typescript-eslint": "^8.61.1",
|
package/scripts/db-baseline.mjs
CHANGED
|
@@ -1,70 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
//
|
|
5
|
-
// Why: an in-production DB already has its schema, so running the introspect-derived baseline 0000 via
|
|
6
|
-
// `db:migrate` collides. Instead we insert a single marker row into `__drizzle_migrations` so that
|
|
7
|
-
// subsequent `db:migrate` runs apply only the later 0001+ (larger `when`). A fresh / test DB has no
|
|
8
|
-
// marker, so the full chain runs (behavior unchanged).
|
|
9
|
-
//
|
|
10
|
-
// Where it runs: direct TCP from inside a VPC (e.g. AWS CodeBuild) to RDS. Hyperdrive is Workers-only
|
|
11
|
-
// and cannot be used here. Credentials come from env (on CodeBuild, Secrets Manager → injected into env):
|
|
12
|
-
// DB_HOST / DB_PORT / DB_USER / DB_PASSWORD / DB_NAME
|
|
13
|
-
// Migrations folder: defaults to ./drizzle (override with --migrations <dir> or MIGRATIONS_DIR).
|
|
14
|
-
//
|
|
15
|
-
// usage:
|
|
16
|
-
// npx workers-hono-kit-db-baseline [--migrations ./drizzle]
|
|
17
|
-
import { createConnection } from 'mysql2/promise';
|
|
18
|
-
import { baselineMigrations } from '../dist/db/migrate.js';
|
|
19
|
-
import { resolveDbSecret } from '../dist/db/index.js';
|
|
2
|
+
// Deprecated compatibility command. The implementation is owned by @rdlabo/workers-mysql.
|
|
3
|
+
import { runBaselineCli } from '@rdlabo/workers-mysql/baseline-cli';
|
|
20
4
|
|
|
21
|
-
|
|
22
|
-
const i = process.argv.indexOf(`--${name}`);
|
|
23
|
-
return i >= 0 ? process.argv[i + 1] : undefined;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const migrationsFolder = arg('migrations') ?? process.env.MIGRATIONS_DIR ?? './drizzle';
|
|
27
|
-
// Shares the same DB_SECRET handling as db:migrate (honoDrizzleConfig). CI/production passes an AWS
|
|
28
|
-
// Secrets Manager RDS managed secret via DB_SECRET (invalid/missing → resolveDbSecret throws). When
|
|
29
|
-
// unset, it falls back to the individual DB_* env vars.
|
|
30
|
-
const secret = resolveDbSecret();
|
|
31
|
-
const conn = secret
|
|
32
|
-
? {
|
|
33
|
-
host: secret.host,
|
|
34
|
-
port: secret.port,
|
|
35
|
-
user: secret.username,
|
|
36
|
-
password: secret.password,
|
|
37
|
-
database: secret.dbname,
|
|
38
|
-
}
|
|
39
|
-
: {
|
|
40
|
-
host: process.env.DB_HOST ?? '127.0.0.1',
|
|
41
|
-
port: Number(process.env.DB_PORT ?? '3306'),
|
|
42
|
-
user: process.env.DB_USER ?? 'root',
|
|
43
|
-
password: process.env.DB_PASSWORD ?? 'root',
|
|
44
|
-
database: process.env.DB_NAME,
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
if (!conn.database) {
|
|
48
|
-
console.error('[db:baseline] DB_NAME (or DB_SECRET) is required.');
|
|
49
|
-
process.exit(1);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
console.log(`[db:baseline] target = ${conn.user}@${conn.host}:${conn.port}/${conn.database} (migrations: ${migrationsFolder})`);
|
|
53
|
-
|
|
54
|
-
const db = await createConnection(conn);
|
|
55
|
-
try {
|
|
56
|
-
const res = await baselineMigrations({ db, migrationsFolder });
|
|
57
|
-
if (res.status === 'already-baselined') {
|
|
58
|
-
console.log(`[db:baseline] already baselined (${res.tag}, created_at=${res.when}). no-op.`);
|
|
59
|
-
} else {
|
|
60
|
-
console.log(
|
|
61
|
-
`[db:baseline] inserted baseline marker for ${res.tag} (created_at=${res.when}). ` +
|
|
62
|
-
`0000 is now recorded as applied; future migrations will run.`,
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
} catch (err) {
|
|
66
|
-
console.error('[db:baseline] failed:', err instanceof Error ? err.message : err);
|
|
67
|
-
process.exitCode = 1;
|
|
68
|
-
} finally {
|
|
69
|
-
await db.end();
|
|
70
|
-
}
|
|
5
|
+
await runBaselineCli();
|