@rdlabo/workers-hono-kit 0.4.0 → 0.4.3
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 +115 -24
- package/dist/business-time/index.d.ts +98 -21
- package/dist/business-time/index.js +99 -22
- package/dist/business-time/types.d.ts +3 -3
- package/dist/business-time/types.js +1 -1
- package/dist/db/columns.d.ts +8 -6
- package/dist/db/columns.js +25 -19
- package/dist/db/decimal.d.ts +17 -9
- package/dist/db/decimal.js +17 -9
- package/dist/db/jst.d.ts +11 -6
- package/dist/db/jst.js +11 -6
- package/dist/db/migrate.d.ts +21 -21
- package/dist/db/migrate.js +34 -29
- package/dist/db/orm-config.d.ts +10 -6
- package/dist/db/orm-config.js +15 -11
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/middleware/perf-log.d.ts +77 -0
- package/dist/middleware/perf-log.js +97 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +2 -0
- package/dist/testing/workers-bindings.d.ts +49 -0
- package/dist/testing/workers-bindings.js +62 -0
- package/package.json +1 -1
- package/scripts/db-baseline.mjs +10 -9
package/README.md
CHANGED
|
@@ -35,13 +35,13 @@ npm install ai ai-gateway-provider # createAiGatewayProvider
|
|
|
35
35
|
> **Compiled ESM, with types.** The package is published as compiled ES modules (`./dist/*.js`) plus
|
|
36
36
|
> declaration files (`./dist/*.d.ts`) via the `exports` field. It depends only on Web-standard APIs
|
|
37
37
|
> (`fetch`, `crypto.subtle`, `Response`) available on Cloudflare Workers (`workerd`) and other edge
|
|
38
|
-
> runtimes, and requires Node.js ≥ 20 for tooling.
|
|
38
|
+
> runtimes, and requires Node.js ≥ 20 for tooling. Four entry points are exposed:
|
|
39
39
|
>
|
|
40
40
|
> | Subpath | Import | Use |
|
|
41
41
|
> | --- | --- | --- |
|
|
42
42
|
> | `.` | `@rdlabo/workers-hono-kit` | Web-standard helpers (middleware, HTTP, Firebase, AWS, AI, Stripe, KV). |
|
|
43
43
|
> | `./db` | `@rdlabo/workers-hono-kit/db` | MySQL data layer (mysql2 + Drizzle). |
|
|
44
|
-
> | `./business-time` | `@rdlabo/workers-hono-kit/business-time` | JST
|
|
44
|
+
> | `./business-time` | `@rdlabo/workers-hono-kit/business-time` | JST business-time API (`toBusinessDateTime` / `normalizeBusinessDate` / `formatBusinessDateTime`, etc.). |
|
|
45
45
|
> | `./testing` | `@rdlabo/workers-hono-kit/testing` | Test helpers (mysql2 + Drizzle + fakes/fixtures). |
|
|
46
46
|
|
|
47
47
|
## API
|
|
@@ -70,11 +70,12 @@ npm install ai ai-gateway-provider # createAiGatewayProvider
|
|
|
70
70
|
| `normalizeTrailingSlash(request)` | Strip trailing slash(es) from the request URL before routing (Express/Nest parity). Does **not** 301-redirect — preserves POST/PUT/DELETE bodies. |
|
|
71
71
|
| `NEST_REASON_PHRASES` | `{ 400, 401, 403, 404 }` → NestJS reason phrases. |
|
|
72
72
|
| `createAuthMiddleware(options)` / `AuthMiddlewareOptions` | Factory for a Firebase-token auth middleware: reads the token header, verifies, resolves the DB user id, and stashes the result on the context. Omit `resolveUserId` for a token-only (login) guard. |
|
|
73
|
+
| `perfLog(options?)` / `PerfLogOptions` / `AnalyticsEngineDatasetLike` | Middleware that records one per-request latency data point (`t_app`, colo, cold/warm, route, status) and emits it to **Workers Logs** (`console.log`) and/or **Workers Analytics Engine** (`writeDataPoint`). Lets you measure low-traffic Workers without a live `wrangler tail`. |
|
|
73
74
|
| `ErrorReporter` / `ErrorReportContext` | Types for a `reportError`-style unhandled-error reporter (e.g. wired to Sentry), paired with `createNestErrorHandler`'s `onUnhandledError`. |
|
|
74
75
|
| `createAiGatewayProvider(config)` / `AiGatewayConfig` / `AiGatewayProvider` | Route `@ai-sdk` models through the Cloudflare AI Gateway, via either a Workers `AI` binding or REST credentials (`accountId` / `gateway` / `token`). |
|
|
75
76
|
| `KVCache` / `KVNamespace` / `KVCacheOptions` | Workers-KV cache-aside helper (key `appName+version+table_type_column`, sha256 for string ids, TTL clamped ≥60s). Set `appName` / `version` per application. |
|
|
76
77
|
| `createStripeClient(secret, opts?)` / `verifyStripeWebhook(...)` / `CreateStripeClientOptions` | Workers-native Stripe client (fetch transport) + async webhook verification (SubtleCrypto). `apiVersion` optional (pin to a fixed Stripe API version). |
|
|
77
|
-
| `sendInChunks(queue, messages,
|
|
78
|
+
| `sendInChunks(queue, messages, options?)` / `QueueLike` / `QueueSendMessage` | Send queue messages in bounded chunks to stay under the Workers subrequest cap per invocation. `options.chunkSize` sets the per-batch size (defaults to and is capped at 100). |
|
|
78
79
|
| `processBatch(batch, handler, options?)` / `MessageBatchLike` / `QueueMessageLike` / `ProcessBatchOptions` / `ProcessBatchResult` | Process a queue batch with bounded concurrency (consumer-side counterpart to `sendInChunks`). |
|
|
79
80
|
| `ExecutionContextLike` | Minimal `waitUntil`-only Workers execution context shape (for `withMysqlConnections` in worker entry modules without importing `./db`). |
|
|
80
81
|
|
|
@@ -88,45 +89,83 @@ Requires the `drizzle-orm` and `mysql2` peers. Reads run against a replica via r
|
|
|
88
89
|
| `createMysqlDatabase(options)` | Assemble a `Database` from an already-connected Drizzle ORM + replica `QueryRunner`. |
|
|
89
90
|
| `databaseFrom(orm, replica)` | Build a `Database` from an existing Drizzle instance + replica handle. |
|
|
90
91
|
| `Database` / `DisposableDatabase` / `QueryRunner` / `TxOf` | The `read` / `write` / `transaction` API and its supporting types. |
|
|
91
|
-
| `hyperdriveConnectionOptions(hyperdrive, overrides?)` / `HyperdriveLike` / `ExecutionContextLike` | Build mysql2 `createConnection` options from a Hyperdrive binding (`disableEval`, `decimalNumbers`, `timezone '+09:00'` by default). |
|
|
92
|
+
| `hyperdriveConnectionOptions(hyperdrive, overrides?)` / `HyperdriveLike` / `ExecutionContextLike` | Build mysql2 `createConnection` options from a Hyperdrive binding (`disableEval`, `decimalNumbers`, `timezone '+09:00'` by default). `ExecutionContextLike` is the same type as the root export, re-exported here so `withMysqlConnections` callers don't need the root import. |
|
|
92
93
|
| `withMysqlConnections(...)` | Open primary/replica connections, run a function, close them in `finally` (via `ctx.waitUntil`). |
|
|
93
94
|
| `retryWhenDeadlock(fn, retries?, delay?)` | Same deadlock-retry helper as the root export. |
|
|
94
95
|
| `insertIdOf` / `affectedRowsOf` / `insertedIdsOf` / `DzWriteResult` | Extract `insertId` / `affectedRows` (and derive contiguous bulk-insert ids) from a mysql2 write result. |
|
|
95
|
-
| `toJstDate` / `jstTimestampParams` / `jstDatetimeParams` / `jstDateParams` | JST date/time normalization params
|
|
96
|
-
| `
|
|
97
|
-
| `
|
|
98
|
-
| `
|
|
96
|
+
| `toJstDate` / `jstTimestampParams` / `jstDatetimeParams` / `jstDateParams` | JST date/time normalization params (advanced use). |
|
|
97
|
+
| `MYSQL_TIMEZONE` | Default mysql2 connection `timezone` (`'+09:00'`) for the JST DB deployment. |
|
|
98
|
+
| `jstTimestamp` / `jstDatetime` / `jstDate` / `decimalNumber` | Drizzle column helpers (no repo-side wrapper needed). |
|
|
99
|
+
| `jstOnUpdateNow` | SQL expression for `ON UPDATE CURRENT_TIMESTAMP`. The `jstTimestamp` customType (and friends) do not support `.onUpdateNow()`, so pair it with `.$onUpdateFn(() => jstOnUpdateNow(fsp))`. |
|
|
100
|
+
| `coerceDecimalNumber` / `decimalNumberParams` | DECIMAL normalization params (the `decimalNumber` column helper is usually enough). |
|
|
99
101
|
| `DRIZZLE_ORM_OPTIONS` / `honoDrizzleConfig(options)` / `HonoDrizzleConfigOptions` | Shared Drizzle casing (`snake_case`) for both the runtime `drizzle()` call and `drizzle.config.ts`, keeping config ↔ runtime in sync. |
|
|
100
|
-
| `resolveDbSecret(
|
|
102
|
+
| `resolveDbSecret()` / `ResolvedDbSecret` | Resolve DB connection info from the `DB_SECRET` env var (an AWS RDS managed-secret JSON string) for CI migrate / local tooling. Returns `undefined` when `DB_SECRET` is unset; throws on invalid JSON or a missing required key. |
|
|
101
103
|
| `baselineMigrations(options)` / `readBaselineEntry(migrationsFolder)` / `BaselineMigrationsOptions` / `BaselineResult` / `BaselineEntry` | Brownfield first-deploy helper: mark an existing `0000_*` migration as applied without re-running DDL. |
|
|
102
104
|
|
|
103
|
-
#### Drizzle
|
|
105
|
+
#### Drizzle column helpers (`jstTimestamp` / `decimalNumber`, etc.)
|
|
104
106
|
|
|
105
|
-
- `drizzle-orm`
|
|
106
|
-
- consumer
|
|
107
|
-
- npm
|
|
108
|
-
-
|
|
109
|
-
-
|
|
107
|
+
- `drizzle-orm` is a **peer** only. The kit does not include `drizzle-orm` as a dependency (even after publishing, it uses the consumer's single copy).
|
|
108
|
+
- The consumer just keeps `drizzle-orm` in its `dependencies` as usual. **No `overrides` in `package.json` are needed.**
|
|
109
|
+
- The npm-published artifact contains no `devDependencies`, so installing it does not add a kit-specific `drizzle-orm` (there is only the one peer copy).
|
|
110
|
+
- The column helpers `import` the consumer's `drizzle-orm` at runtime, and the types are the `customType` inference as-is (`MySqlCustomColumnBuilder<…>`). No `any` is used, so the column's semantic type propagates to the consumer table's `$inferSelect`.
|
|
111
|
+
- **Precondition: resolve drizzle to a single copy.** Drizzle's `SQL` is a **nominal** type carrying a private field `shouldInlineParams`, so if the kit and the consumer resolve different copies, `jstTimestamp(…).default(sql\`…\`)` fails the whole schema with `TS2345 separate declarations of a private property 'shouldInlineParams'`. Under `file:`-link development, `drizzle-orm` nests under the kit and becomes a second copy, so **pin `drizzle-orm` to the consumer's own single copy in `tsconfig.json`**:
|
|
110
112
|
|
|
111
113
|
```jsonc
|
|
112
|
-
// tsconfig.json compilerOptions
|
|
114
|
+
// tsconfig.json compilerOptions (merge with existing paths if any)
|
|
113
115
|
"paths": {
|
|
114
116
|
"drizzle-orm": ["./node_modules/drizzle-orm"],
|
|
115
117
|
"drizzle-orm/*": ["./node_modules/drizzle-orm/*"]
|
|
116
118
|
}
|
|
117
119
|
```
|
|
118
120
|
|
|
119
|
-
`moduleResolution: "Bundler"
|
|
120
|
-
-
|
|
121
|
+
With `moduleResolution: "Bundler"`, `baseUrl` is not required (if `baseUrl` is already set, drop the leading `./`). On the published package (a single copy) these `paths` are harmless. **No `overrides` needed.**
|
|
122
|
+
- When developing against the kit via a direct `file:` link, run `npm install` in the kit repo itself to satisfy its peers (do not add `overrides` on the consumer side).
|
|
121
123
|
|
|
122
|
-
**`CURRENT_TIMESTAMP`
|
|
124
|
+
**`CURRENT_TIMESTAMP` vs the connection `timezone:'+09:00'`**
|
|
123
125
|
|
|
124
|
-
|
|
|
126
|
+
| Path | Who decides the time | Relationship to JST |
|
|
125
127
|
| --- | --- | --- |
|
|
126
|
-
|
|
|
127
|
-
| `DEFAULT CURRENT_TIMESTAMP` / `ON UPDATE CURRENT_TIMESTAMP` | MySQL
|
|
128
|
+
| The app binds a `Date` (INSERT/UPDATE) | mysql2 + connection `timezone:'+09:00'` | Treated as JST on the wire (`datetime-wire` test) |
|
|
129
|
+
| `DEFAULT CURRENT_TIMESTAMP` / `ON UPDATE CURRENT_TIMESTAMP` | The MySQL server (session `time_zone`) | A **separate path** from the connection option. JST if the RDS `time_zone` is `+09:00`, UTC if UTC |
|
|
128
130
|
|
|
129
|
-
`jstTimestamp` / `jstDatetime`
|
|
131
|
+
`jstTimestamp` / `jstDatetime` only handle read/write pass-through and DATE normalization; they do not change the timezone of server-side defaults. For columns that need `ON UPDATE`, keep the DDL intent with `.$onUpdateFn(() => jstOnUpdateNow(6))`.
|
|
132
|
+
|
|
133
|
+
### Business time — `@rdlabo/workers-hono-kit/business-time`
|
|
134
|
+
|
|
135
|
+
String-level JST business-time conversions (Workers UTC instant ↔ business calendar date / date-time),
|
|
136
|
+
with **no `mysql2` / `drizzle-orm` dependency**. This is a different layer from the `./db` column helpers
|
|
137
|
+
(which handle the MySQL wire format): the DB stays on JST, and the app handles JST explicitly through
|
|
138
|
+
this module instead of relying implicitly on the connection `timezone`.
|
|
139
|
+
|
|
140
|
+
| Export | Description |
|
|
141
|
+
| --- | --- |
|
|
142
|
+
| `today(ref?)` | The JST business calendar date (`YYYY-MM-DD`) of `ref` (defaults to now). |
|
|
143
|
+
| `toBusinessDate(instant)` | UTC instant → JST business calendar date (`YYYY-MM-DD`). |
|
|
144
|
+
| `normalizeBusinessDate(value)` | Normalize a `string` / `Date` / nullish to `YYYY-MM-DD`; a `YYYY-MM-DD` string passes through unchanged, nullish/empty/invalid → `null`. |
|
|
145
|
+
| `toBusinessDateTime(instant)` | UTC instant → JST business date-time (`YYYY-MM-DD HH:mm:ss`). |
|
|
146
|
+
| `parseBusinessDateTime(value)` | JST business date-time string → UTC instant (accepts a space or `T` separator). |
|
|
147
|
+
| `formatBusinessDateTime(instant, pattern?)` | Format an instant in the business TZ (Nest `helper.formatDate`-compatible tokens). |
|
|
148
|
+
| `startOfBusinessDay(date)` / `endOfBusinessDay(date)` | UTC instant of `00:00:00` / `23:59:59` on a JST business date. |
|
|
149
|
+
| `businessDateTimeInstant(date, time)` | JST business date + wall-clock time → UTC instant. |
|
|
150
|
+
| `addBusinessDays(date, days)` | Add calendar days to a JST business date. |
|
|
151
|
+
| `ageOnBusinessDate(birthDate, asOfDate?)` | Full years of age on a business date (`asOfDate` defaults to `today()`). |
|
|
152
|
+
| `DEFAULT_BUSINESS_DATETIME_PATTERN` | Default `formatBusinessDateTime` pattern (`YYYY-MM-DDThh:mm:ss`). |
|
|
153
|
+
| `BUSINESS_TIMEZONE` / `BusinessDate` / `BusinessDateTime` | JST timezone constant and the business-date / date-time string types. |
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
import {
|
|
157
|
+
toBusinessDate,
|
|
158
|
+
toBusinessDateTime,
|
|
159
|
+
formatBusinessDateTime,
|
|
160
|
+
addBusinessDays,
|
|
161
|
+
} from '@rdlabo/workers-hono-kit/business-time';
|
|
162
|
+
|
|
163
|
+
const now = new Date('2026-07-05T21:00:00Z');
|
|
164
|
+
toBusinessDate(now); // '2026-07-06' (JST)
|
|
165
|
+
toBusinessDateTime(now); // '2026-07-06 06:00:00'
|
|
166
|
+
formatBusinessDateTime(now); // '2026-07-06T06:00:00'
|
|
167
|
+
addBusinessDays('2026-07-06', 3); // '2026-07-09'
|
|
168
|
+
```
|
|
130
169
|
|
|
131
170
|
### Testing — `@rdlabo/workers-hono-kit/testing`
|
|
132
171
|
|
|
@@ -143,6 +182,7 @@ Requires the `drizzle-orm` and `mysql2` peers. Consolidates duplicated test boil
|
|
|
143
182
|
| `provisionUser(pool, firebase, opts)` | Register a token and provision a conventional `users(id, firebase_uid, agree)` row; returns the user id (idempotent). |
|
|
144
183
|
| `configurableFake(impl, name?)` | Build a test double from a partial implementation; un-stubbed members throw `"${name}.${method} not configured"`. |
|
|
145
184
|
| `fakeApiList` / `fakePaymentIntent` / `fakeStripeEvent` / `fakeCheckoutSession` / `fakeCustomer` / `fakePrice` / `fakeSubscription` | Stripe object fixtures with sensible defaults, overridable per test. |
|
|
185
|
+
| `fakeKv()` / `fakeQueue()` / `FakeQueue` | In-memory Workers KV / Queues producer doubles (`sent` + `batchCount` on queues for subrequest-bound assertions). |
|
|
146
186
|
|
|
147
187
|
## Usage
|
|
148
188
|
|
|
@@ -290,6 +330,47 @@ const tokenAuth = createAuthMiddleware<AppEnv, UserRecord>({
|
|
|
290
330
|
});
|
|
291
331
|
```
|
|
292
332
|
|
|
333
|
+
### Latency instrumentation (`perfLog`)
|
|
334
|
+
|
|
335
|
+
Records one data point per request — `t_app` (time inside the app), `colo`, `cold`/`warm`, matched
|
|
336
|
+
route, `status` — and ships it to **Workers Logs** and/or **Workers Analytics Engine**. This lets you
|
|
337
|
+
measure a low-traffic Worker after the fact (retained + queryable) instead of watching a live
|
|
338
|
+
`wrangler tail`. Register it first so it wraps everything.
|
|
339
|
+
|
|
340
|
+
```ts
|
|
341
|
+
import { perfLog } from '@rdlabo/workers-hono-kit';
|
|
342
|
+
|
|
343
|
+
// A) app served with env (`app.fetch(req, env, ctx)`): bare — reads `PERF` (Analytics Engine
|
|
344
|
+
// dataset binding) and `PERF_LOG === '1'` (Workers Logs) off `c.env`.
|
|
345
|
+
app.use('*', perfLog());
|
|
346
|
+
|
|
347
|
+
// B) app built without Hono env (`createApp(container).fetch(req)`): pass bindings explicitly.
|
|
348
|
+
app.use('*', perfLog({ console: env.PERF_LOG === '1', dataset: env.PERF }));
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
```toml
|
|
352
|
+
# wrangler.toml — dataset is created on first write (no provisioning); needs [observability] for Logs.
|
|
353
|
+
[[analytics_engine_datasets]]
|
|
354
|
+
binding = "PERF"
|
|
355
|
+
dataset = "myapp_perf"
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
Query percentiles by route/colo with the Analytics Engine SQL API:
|
|
359
|
+
|
|
360
|
+
```sql
|
|
361
|
+
SELECT blob1 AS path, blob2 AS colo,
|
|
362
|
+
quantileWeighted(0.5)(double1, _sample_interval) AS p50,
|
|
363
|
+
quantileWeighted(0.9)(double1, _sample_interval) AS p90
|
|
364
|
+
FROM myapp_perf WHERE timestamp > now() - INTERVAL '7' DAY
|
|
365
|
+
GROUP BY path, colo ORDER BY p90 DESC
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
> **Scope of `t_app`**: it covers everything *inside* the app; work done in `fetch` *before* the app
|
|
369
|
+
> (e.g. secrets fetch / DB connect in `createApp(container)` vs. building the container in `fetch`) is
|
|
370
|
+
> not comparable across differently-wired apps. Instrument the `fetch` seam if you need a secrets/connect
|
|
371
|
+
> cold breakdown. On production Workers `Date.now()` only advances at I/O boundaries, so `t_app` ≈ I/O
|
|
372
|
+
> wait, not CPU time.
|
|
373
|
+
|
|
293
374
|
### AI Gateway
|
|
294
375
|
|
|
295
376
|
Route `@ai-sdk` models through the Cloudflare AI Gateway — either with a Workers `AI` binding
|
|
@@ -362,7 +443,7 @@ await testDb.resetSchema();
|
|
|
362
443
|
const pool = testDb.createTestPool();
|
|
363
444
|
|
|
364
445
|
const firebase = new FakeFirebaseVerifier();
|
|
365
|
-
firebase.register('
|
|
446
|
+
firebase.register('token-1', { uid: 'uid-1', email: 'a@example.com' });
|
|
366
447
|
|
|
367
448
|
const gateway = configurableFake<PaymentGateway>({ charge: async () => ({ ok: true }) }, 'PaymentGateway');
|
|
368
449
|
```
|
|
@@ -386,6 +467,16 @@ If you consume this package via a local path (e.g. `"@rdlabo/workers-hono-kit":
|
|
|
386
467
|
|
|
387
468
|
When installed from npm normally, package managers dedupe `zod` to a single copy and this is not needed.
|
|
388
469
|
|
|
470
|
+
## CLI
|
|
471
|
+
|
|
472
|
+
The package ships three `bin` commands (run via `npx` or an npm script in the consuming app):
|
|
473
|
+
|
|
474
|
+
| Command | Use |
|
|
475
|
+
| --- | --- |
|
|
476
|
+
| `workers-hono-kit-sync-dev-aws <wrangler-args…>` | Launch `wrangler` with AWS credentials injected as `--var`, resolved from the active AWS profile (honors `AWS_PROFILE`, supports short-lived SSO/temporary creds). Nothing is written to disk — replaces `.dev.vars`. Wire it as the `dev` script, e.g. `AWS_PROFILE=<p> workers-hono-kit-sync-dev-aws dev --var APP_ENV:development`. |
|
|
477
|
+
| `workers-hono-kit-check-subrequest-fanout [dir…]` | CI gate that greps for per-item external-call fan-outs (`runWithConcurrency(` / `PromisePool` / `.withConcurrency(`) that would eventually exceed the Workers subrequest cap. Annotate a genuinely-safe site with `subrequest-ok`. Scans `src` by default; exits 1 on an un-annotated marker. |
|
|
478
|
+
| `workers-hono-kit-db-baseline [--migrations ./drizzle]` | Brownfield first-deploy helper: record the baseline `0000` migration as *already applied* on an existing MySQL DB without running its DDL (the CLI wrapper around `baselineMigrations` / `readBaselineEntry`). Reads DB credentials from `DB_SECRET` (AWS RDS managed secret) or the individual `DB_*` env vars. |
|
|
479
|
+
|
|
389
480
|
## Development
|
|
390
481
|
|
|
391
482
|
```bash
|
|
@@ -1,49 +1,126 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* JST
|
|
2
|
+
* Explicit JST business-time API (Workers UTC instant ↔ business calendar date / date-time).
|
|
3
3
|
*
|
|
4
4
|
* @remarks
|
|
5
|
-
* - DB
|
|
6
|
-
*
|
|
7
|
-
* -
|
|
5
|
+
* - The DB stays on JST. The app does not implicitly rely on the mysql2 `timezone` option; it goes
|
|
6
|
+
* through this module to handle JST.
|
|
7
|
+
* - Converting to the MySQL wire format is the responsibility of {@link ../db/jst.js | db/jst}.
|
|
8
|
+
* - Do not use a `Date`'s local getters (`getHours`, etc.) for business-time decisions.
|
|
8
9
|
*
|
|
9
10
|
* @packageDocumentation
|
|
10
11
|
*/
|
|
11
12
|
import { BUSINESS_TIMEZONE } from './types.js';
|
|
12
13
|
import type { BusinessDate, BusinessDateTime } from './types.js';
|
|
13
14
|
export { BUSINESS_TIMEZONE, type BusinessDate, type BusinessDateTime };
|
|
14
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* The JST business calendar date of a reference instant.
|
|
17
|
+
*
|
|
18
|
+
* @param ref - the instant to read; defaults to now.
|
|
19
|
+
* @returns the business date as `YYYY-MM-DD`.
|
|
20
|
+
* @example
|
|
21
|
+
* today(new Date('2026-07-05T20:00:00Z')); // → '2026-07-06' (JST)
|
|
22
|
+
*/
|
|
15
23
|
export declare function today(ref?: Date): BusinessDate;
|
|
16
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* Convert a UTC instant to a JST business calendar date.
|
|
26
|
+
*
|
|
27
|
+
* @param instant - the UTC instant to convert.
|
|
28
|
+
* @returns the business date as `YYYY-MM-DD`.
|
|
29
|
+
*/
|
|
17
30
|
export declare function toBusinessDate(instant: Date): BusinessDate;
|
|
18
31
|
/**
|
|
19
|
-
*
|
|
32
|
+
* Normalize a client / DB input to a JST business calendar date `YYYY-MM-DD`.
|
|
33
|
+
*
|
|
34
|
+
* - A string already in `YYYY-MM-DD` form is returned as-is, **without** constructing a `Date`
|
|
35
|
+
* (a birthday is a calendar day, not an instant).
|
|
36
|
+
* - ISO 8601 and similar values are converted to a JST calendar date via their instant.
|
|
37
|
+
* - Nullish / empty / invalid inputs yield `null`.
|
|
20
38
|
*
|
|
21
|
-
*
|
|
22
|
-
* -
|
|
23
|
-
*
|
|
39
|
+
* @param value - the string, `Date`, or nullish value to normalize.
|
|
40
|
+
* @returns the business date as `YYYY-MM-DD`, or `null` when the input cannot be resolved.
|
|
41
|
+
* @example
|
|
42
|
+
* normalizeBusinessDate('1990-01-15'); // → '1990-01-15' (unchanged)
|
|
43
|
+
* normalizeBusinessDate('2026-07-05T20:00:00Z'); // → '2026-07-06' (JST)
|
|
44
|
+
* normalizeBusinessDate(''); // → null
|
|
24
45
|
*/
|
|
25
46
|
export declare function normalizeBusinessDate(value: string | Date | null | undefined): BusinessDate | null;
|
|
26
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* Convert a UTC instant to a JST business date-time (`YYYY-MM-DD HH:mm:ss`).
|
|
49
|
+
*
|
|
50
|
+
* @param instant - the UTC instant to convert.
|
|
51
|
+
* @returns the business date-time string.
|
|
52
|
+
* @example
|
|
53
|
+
* toBusinessDateTime(new Date('2026-07-05T21:00:00Z')); // → '2026-07-06 06:00:00' (JST)
|
|
54
|
+
*/
|
|
27
55
|
export declare function toBusinessDateTime(instant: Date): BusinessDateTime;
|
|
28
|
-
/** Nest / foodlabel / winecode `helper.formatDate
|
|
56
|
+
/** Default pattern for the Nest / foodlabel / winecode `helper.formatDate`. */
|
|
29
57
|
export declare const DEFAULT_BUSINESS_DATETIME_PATTERN: "YYYY-MM-DDThh:mm:ss";
|
|
30
58
|
/**
|
|
31
|
-
* Nest `helper.formatDate
|
|
32
|
-
*
|
|
59
|
+
* Format an instant in the business TZ, compatible with the Nest `helper.formatDate`.
|
|
60
|
+
*
|
|
61
|
+
* Supported tokens: `YYYY` / `MM` / `DD` / `hh` / `mm` / `ss`, plus `S` for the source instant's
|
|
62
|
+
* milliseconds (matching the Nest reference implementation).
|
|
63
|
+
*
|
|
64
|
+
* @param instant - the UTC instant to format.
|
|
65
|
+
* @param pattern - the format pattern; defaults to {@link DEFAULT_BUSINESS_DATETIME_PATTERN}.
|
|
66
|
+
* @returns the formatted string.
|
|
67
|
+
* @example
|
|
68
|
+
* formatBusinessDateTime(new Date('2026-07-05T21:00:00Z')); // → '2026-07-06T06:00:00' (JST)
|
|
33
69
|
*/
|
|
34
70
|
export declare function formatBusinessDateTime(instant: Date, pattern?: string): string;
|
|
35
|
-
/**
|
|
71
|
+
/**
|
|
72
|
+
* Parse a JST business date-time string into a UTC instant. Accepts a space or `T` separator
|
|
73
|
+
* (`YYYY-MM-DD HH:mm:ss` or `YYYY-MM-DDTHH:mm:ss`).
|
|
74
|
+
*
|
|
75
|
+
* @param value - the business date-time string to parse.
|
|
76
|
+
* @returns the corresponding UTC instant.
|
|
77
|
+
* @throws RangeError when `value` is not a valid business date-time.
|
|
78
|
+
* @example
|
|
79
|
+
* parseBusinessDateTime('2026-07-06 06:00:00'); // → 2026-07-05T21:00:00Z
|
|
80
|
+
*/
|
|
36
81
|
export declare function parseBusinessDateTime(value: BusinessDateTime): Date;
|
|
37
|
-
/**
|
|
82
|
+
/**
|
|
83
|
+
* The UTC instant of `00:00:00` on a JST business calendar date.
|
|
84
|
+
*
|
|
85
|
+
* @param date - the business date as `YYYY-MM-DD`.
|
|
86
|
+
* @returns the UTC instant at the start of that business day.
|
|
87
|
+
*/
|
|
38
88
|
export declare function startOfBusinessDay(date: BusinessDate): Date;
|
|
39
|
-
/**
|
|
89
|
+
/**
|
|
90
|
+
* The UTC instant of `23:59:59` on a JST business calendar date.
|
|
91
|
+
*
|
|
92
|
+
* @param date - the business date as `YYYY-MM-DD`.
|
|
93
|
+
* @returns the UTC instant at the end of that business day.
|
|
94
|
+
*/
|
|
40
95
|
export declare function endOfBusinessDay(date: BusinessDate): Date;
|
|
41
96
|
/**
|
|
42
|
-
* JST
|
|
43
|
-
*
|
|
97
|
+
* Convert a JST business calendar date + wall-clock time to a UTC instant.
|
|
98
|
+
*
|
|
99
|
+
* @param date - the business date as `YYYY-MM-DD`.
|
|
100
|
+
* @param time - the wall-clock time as `HH:mm:ss` (or `HH:mm`).
|
|
101
|
+
* @returns the corresponding UTC instant.
|
|
102
|
+
* @throws RangeError when `date` or `time` is malformed.
|
|
103
|
+
* @example
|
|
104
|
+
* businessDateTimeInstant('2026-07-06', '06:00:00'); // → 2026-07-05T21:00:00Z
|
|
44
105
|
*/
|
|
45
106
|
export declare function businessDateTimeInstant(date: BusinessDate, time: string): Date;
|
|
46
|
-
/**
|
|
107
|
+
/**
|
|
108
|
+
* Add a number of calendar days to a JST business calendar date.
|
|
109
|
+
*
|
|
110
|
+
* @param date - the starting business date as `YYYY-MM-DD`.
|
|
111
|
+
* @param days - the number of calendar days to add (may be negative).
|
|
112
|
+
* @returns the resulting business date as `YYYY-MM-DD`.
|
|
113
|
+
* @example
|
|
114
|
+
* addBusinessDays('2026-07-06', 3); // → '2026-07-09'
|
|
115
|
+
*/
|
|
47
116
|
export declare function addBusinessDays(date: BusinessDate, days: number): BusinessDate;
|
|
48
|
-
/**
|
|
117
|
+
/**
|
|
118
|
+
* The full years of age on a business calendar date (a birthday is a `BusinessDate`, not an instant).
|
|
119
|
+
*
|
|
120
|
+
* @param birthDate - the birth date as `YYYY-MM-DD`.
|
|
121
|
+
* @param asOfDate - the reference business date; defaults to {@link today}.
|
|
122
|
+
* @returns the age in completed years.
|
|
123
|
+
* @example
|
|
124
|
+
* ageOnBusinessDate('1990-07-10', '2026-07-06'); // → 35
|
|
125
|
+
*/
|
|
49
126
|
export declare function ageOnBusinessDate(birthDate: BusinessDate, asOfDate?: BusinessDate): number;
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* JST
|
|
2
|
+
* Explicit JST business-time API (Workers UTC instant ↔ business calendar date / date-time).
|
|
3
3
|
*
|
|
4
4
|
* @remarks
|
|
5
|
-
* - DB
|
|
6
|
-
*
|
|
7
|
-
* -
|
|
5
|
+
* - The DB stays on JST. The app does not implicitly rely on the mysql2 `timezone` option; it goes
|
|
6
|
+
* through this module to handle JST.
|
|
7
|
+
* - Converting to the MySQL wire format is the responsibility of {@link ../db/jst.js | db/jst}.
|
|
8
|
+
* - Do not use a `Date`'s local getters (`getHours`, etc.) for business-time decisions.
|
|
8
9
|
*
|
|
9
10
|
* @packageDocumentation
|
|
10
11
|
*/
|
|
11
12
|
import { BUSINESS_TIMEZONE } from './types.js';
|
|
12
13
|
export { BUSINESS_TIMEZONE };
|
|
13
14
|
const pad2 = (n) => String(n).padStart(2, '0');
|
|
14
|
-
/** instant
|
|
15
|
+
/** Shift an instant so it can be read as a business-TZ wall clock (extract fields with `getUTC*`). */
|
|
15
16
|
function toWallClock(instant) {
|
|
16
17
|
return new Date(instant.getTime() + BUSINESS_TIMEZONE.offsetMinutes * 60_000);
|
|
17
18
|
}
|
|
@@ -29,21 +30,41 @@ function parseHms(time) {
|
|
|
29
30
|
}
|
|
30
31
|
return [Number(m[1]), Number(m[2]), Number(m[3] || 0)];
|
|
31
32
|
}
|
|
32
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* The JST business calendar date of a reference instant.
|
|
35
|
+
*
|
|
36
|
+
* @param ref - the instant to read; defaults to now.
|
|
37
|
+
* @returns the business date as `YYYY-MM-DD`.
|
|
38
|
+
* @example
|
|
39
|
+
* today(new Date('2026-07-05T20:00:00Z')); // → '2026-07-06' (JST)
|
|
40
|
+
*/
|
|
33
41
|
export function today(ref = new Date()) {
|
|
34
42
|
return toBusinessDate(ref);
|
|
35
43
|
}
|
|
36
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* Convert a UTC instant to a JST business calendar date.
|
|
46
|
+
*
|
|
47
|
+
* @param instant - the UTC instant to convert.
|
|
48
|
+
* @returns the business date as `YYYY-MM-DD`.
|
|
49
|
+
*/
|
|
37
50
|
export function toBusinessDate(instant) {
|
|
38
51
|
const wall = toWallClock(instant);
|
|
39
52
|
return `${wall.getUTCFullYear()}-${pad2(wall.getUTCMonth() + 1)}-${pad2(wall.getUTCDate())}`;
|
|
40
53
|
}
|
|
41
54
|
/**
|
|
42
|
-
*
|
|
55
|
+
* Normalize a client / DB input to a JST business calendar date `YYYY-MM-DD`.
|
|
56
|
+
*
|
|
57
|
+
* - A string already in `YYYY-MM-DD` form is returned as-is, **without** constructing a `Date`
|
|
58
|
+
* (a birthday is a calendar day, not an instant).
|
|
59
|
+
* - ISO 8601 and similar values are converted to a JST calendar date via their instant.
|
|
60
|
+
* - Nullish / empty / invalid inputs yield `null`.
|
|
43
61
|
*
|
|
44
|
-
*
|
|
45
|
-
* -
|
|
46
|
-
*
|
|
62
|
+
* @param value - the string, `Date`, or nullish value to normalize.
|
|
63
|
+
* @returns the business date as `YYYY-MM-DD`, or `null` when the input cannot be resolved.
|
|
64
|
+
* @example
|
|
65
|
+
* normalizeBusinessDate('1990-01-15'); // → '1990-01-15' (unchanged)
|
|
66
|
+
* normalizeBusinessDate('2026-07-05T20:00:00Z'); // → '2026-07-06' (JST)
|
|
67
|
+
* normalizeBusinessDate(''); // → null
|
|
47
68
|
*/
|
|
48
69
|
export function normalizeBusinessDate(value) {
|
|
49
70
|
if (value == null) {
|
|
@@ -72,16 +93,31 @@ export function normalizeBusinessDate(value) {
|
|
|
72
93
|
}
|
|
73
94
|
return toBusinessDate(new Date(ms));
|
|
74
95
|
}
|
|
75
|
-
/**
|
|
96
|
+
/**
|
|
97
|
+
* Convert a UTC instant to a JST business date-time (`YYYY-MM-DD HH:mm:ss`).
|
|
98
|
+
*
|
|
99
|
+
* @param instant - the UTC instant to convert.
|
|
100
|
+
* @returns the business date-time string.
|
|
101
|
+
* @example
|
|
102
|
+
* toBusinessDateTime(new Date('2026-07-05T21:00:00Z')); // → '2026-07-06 06:00:00' (JST)
|
|
103
|
+
*/
|
|
76
104
|
export function toBusinessDateTime(instant) {
|
|
77
105
|
const wall = toWallClock(instant);
|
|
78
106
|
return `${wall.getUTCFullYear()}-${pad2(wall.getUTCMonth() + 1)}-${pad2(wall.getUTCDate())} ${pad2(wall.getUTCHours())}:${pad2(wall.getUTCMinutes())}:${pad2(wall.getUTCSeconds())}`;
|
|
79
107
|
}
|
|
80
|
-
/** Nest / foodlabel / winecode `helper.formatDate
|
|
108
|
+
/** Default pattern for the Nest / foodlabel / winecode `helper.formatDate`. */
|
|
81
109
|
export const DEFAULT_BUSINESS_DATETIME_PATTERN = 'YYYY-MM-DDThh:mm:ss';
|
|
82
110
|
/**
|
|
83
|
-
* Nest `helper.formatDate
|
|
84
|
-
*
|
|
111
|
+
* Format an instant in the business TZ, compatible with the Nest `helper.formatDate`.
|
|
112
|
+
*
|
|
113
|
+
* Supported tokens: `YYYY` / `MM` / `DD` / `hh` / `mm` / `ss`, plus `S` for the source instant's
|
|
114
|
+
* milliseconds (matching the Nest reference implementation).
|
|
115
|
+
*
|
|
116
|
+
* @param instant - the UTC instant to format.
|
|
117
|
+
* @param pattern - the format pattern; defaults to {@link DEFAULT_BUSINESS_DATETIME_PATTERN}.
|
|
118
|
+
* @returns the formatted string.
|
|
119
|
+
* @example
|
|
120
|
+
* formatBusinessDateTime(new Date('2026-07-05T21:00:00Z')); // → '2026-07-06T06:00:00' (JST)
|
|
85
121
|
*/
|
|
86
122
|
export function formatBusinessDateTime(instant, pattern = DEFAULT_BUSINESS_DATETIME_PATTERN) {
|
|
87
123
|
const wall = toWallClock(instant);
|
|
@@ -102,7 +138,16 @@ export function formatBusinessDateTime(instant, pattern = DEFAULT_BUSINESS_DATET
|
|
|
102
138
|
}
|
|
103
139
|
return out;
|
|
104
140
|
}
|
|
105
|
-
/**
|
|
141
|
+
/**
|
|
142
|
+
* Parse a JST business date-time string into a UTC instant. Accepts a space or `T` separator
|
|
143
|
+
* (`YYYY-MM-DD HH:mm:ss` or `YYYY-MM-DDTHH:mm:ss`).
|
|
144
|
+
*
|
|
145
|
+
* @param value - the business date-time string to parse.
|
|
146
|
+
* @returns the corresponding UTC instant.
|
|
147
|
+
* @throws RangeError when `value` is not a valid business date-time.
|
|
148
|
+
* @example
|
|
149
|
+
* parseBusinessDateTime('2026-07-06 06:00:00'); // → 2026-07-05T21:00:00Z
|
|
150
|
+
*/
|
|
106
151
|
export function parseBusinessDateTime(value) {
|
|
107
152
|
const normalized = value.includes('T') ? value.replace('T', ' ') : value;
|
|
108
153
|
const m = /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/.exec(normalized);
|
|
@@ -113,17 +158,33 @@ export function parseBusinessDateTime(value) {
|
|
|
113
158
|
const offsetHours = BUSINESS_TIMEZONE.offsetMinutes / 60;
|
|
114
159
|
return new Date(Date.UTC(Number(y), Number(mo) - 1, Number(d), Number(h) - offsetHours, Number(mi), Number(s), 0));
|
|
115
160
|
}
|
|
116
|
-
/**
|
|
161
|
+
/**
|
|
162
|
+
* The UTC instant of `00:00:00` on a JST business calendar date.
|
|
163
|
+
*
|
|
164
|
+
* @param date - the business date as `YYYY-MM-DD`.
|
|
165
|
+
* @returns the UTC instant at the start of that business day.
|
|
166
|
+
*/
|
|
117
167
|
export function startOfBusinessDay(date) {
|
|
118
168
|
return businessDateTimeInstant(date, '00:00:00');
|
|
119
169
|
}
|
|
120
|
-
/**
|
|
170
|
+
/**
|
|
171
|
+
* The UTC instant of `23:59:59` on a JST business calendar date.
|
|
172
|
+
*
|
|
173
|
+
* @param date - the business date as `YYYY-MM-DD`.
|
|
174
|
+
* @returns the UTC instant at the end of that business day.
|
|
175
|
+
*/
|
|
121
176
|
export function endOfBusinessDay(date) {
|
|
122
177
|
return businessDateTimeInstant(date, '23:59:59');
|
|
123
178
|
}
|
|
124
179
|
/**
|
|
125
|
-
* JST
|
|
126
|
-
*
|
|
180
|
+
* Convert a JST business calendar date + wall-clock time to a UTC instant.
|
|
181
|
+
*
|
|
182
|
+
* @param date - the business date as `YYYY-MM-DD`.
|
|
183
|
+
* @param time - the wall-clock time as `HH:mm:ss` (or `HH:mm`).
|
|
184
|
+
* @returns the corresponding UTC instant.
|
|
185
|
+
* @throws RangeError when `date` or `time` is malformed.
|
|
186
|
+
* @example
|
|
187
|
+
* businessDateTimeInstant('2026-07-06', '06:00:00'); // → 2026-07-05T21:00:00Z
|
|
127
188
|
*/
|
|
128
189
|
export function businessDateTimeInstant(date, time) {
|
|
129
190
|
const [y, mo, d] = parseYmd(date);
|
|
@@ -131,12 +192,28 @@ export function businessDateTimeInstant(date, time) {
|
|
|
131
192
|
const offsetHours = BUSINESS_TIMEZONE.offsetMinutes / 60;
|
|
132
193
|
return new Date(Date.UTC(y, mo - 1, d, h - offsetHours, mi, s, 0));
|
|
133
194
|
}
|
|
134
|
-
/**
|
|
195
|
+
/**
|
|
196
|
+
* Add a number of calendar days to a JST business calendar date.
|
|
197
|
+
*
|
|
198
|
+
* @param date - the starting business date as `YYYY-MM-DD`.
|
|
199
|
+
* @param days - the number of calendar days to add (may be negative).
|
|
200
|
+
* @returns the resulting business date as `YYYY-MM-DD`.
|
|
201
|
+
* @example
|
|
202
|
+
* addBusinessDays('2026-07-06', 3); // → '2026-07-09'
|
|
203
|
+
*/
|
|
135
204
|
export function addBusinessDays(date, days) {
|
|
136
205
|
const anchor = businessDateTimeInstant(date, '12:00:00');
|
|
137
206
|
return toBusinessDate(new Date(anchor.getTime() + days * 24 * 60 * 60 * 1000));
|
|
138
207
|
}
|
|
139
|
-
/**
|
|
208
|
+
/**
|
|
209
|
+
* The full years of age on a business calendar date (a birthday is a `BusinessDate`, not an instant).
|
|
210
|
+
*
|
|
211
|
+
* @param birthDate - the birth date as `YYYY-MM-DD`.
|
|
212
|
+
* @param asOfDate - the reference business date; defaults to {@link today}.
|
|
213
|
+
* @returns the age in completed years.
|
|
214
|
+
* @example
|
|
215
|
+
* ageOnBusinessDate('1990-07-10', '2026-07-06'); // → 35
|
|
216
|
+
*/
|
|
140
217
|
export function ageOnBusinessDate(birthDate, asOfDate) {
|
|
141
218
|
const asOf = asOfDate ?? today();
|
|
142
219
|
const [by, bm, bd] = parseYmd(birthDate);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
/** JST
|
|
1
|
+
/** A JST business calendar date `YYYY-MM-DD` (a calendar day, not an instant). */
|
|
2
2
|
export type BusinessDate = string;
|
|
3
|
-
/** JST
|
|
3
|
+
/** A JST business date-time `YYYY-MM-DD HH:mm:ss` (a wall-clock value, MySQL `DATETIME`-compatible). */
|
|
4
4
|
export type BusinessDateTime = string;
|
|
5
|
-
/** JST
|
|
5
|
+
/** JST business timezone constant. Workers run in UTC instants; business time is made explicit here. */
|
|
6
6
|
export declare const BUSINESS_TIMEZONE: {
|
|
7
7
|
readonly iana: "Asia/Tokyo";
|
|
8
8
|
readonly offsetMinutes: 540;
|
package/dist/db/columns.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { DecimalNumberConfig } from './decimal.js';
|
|
2
2
|
/**
|
|
3
|
-
* `ON UPDATE CURRENT_TIMESTAMP`
|
|
4
|
-
* customType
|
|
3
|
+
* SQL expression for `ON UPDATE CURRENT_TIMESTAMP` (the MySQL session clock).
|
|
4
|
+
* customType columns have no `.onUpdateNow()`, so pair this with `.$onUpdateFn(() => jstOnUpdateNow(fsp))`.
|
|
5
|
+
*
|
|
6
|
+
* @param fsp - optional fractional-seconds precision; when provided, emits `CURRENT_TIMESTAMP(fsp)`.
|
|
5
7
|
*/
|
|
6
8
|
export declare const jstOnUpdateNow: (fsp?: number) => import("drizzle-orm").SQL<unknown>;
|
|
7
|
-
/** MySQL `timestamp` — pass-through
|
|
9
|
+
/** MySQL `timestamp` — pass-through. A `Date` is formatted as JST by mysql2 via the connection `timezone:'+09:00'`. */
|
|
8
10
|
export declare const jstTimestamp: (name: string, opts?: {
|
|
9
11
|
fsp?: number;
|
|
10
12
|
}) => import("drizzle-orm/mysql-core").MySqlCustomColumnBuilder<{
|
|
@@ -15,7 +17,7 @@ export declare const jstTimestamp: (name: string, opts?: {
|
|
|
15
17
|
driverParam: string | Date;
|
|
16
18
|
enumValues: undefined;
|
|
17
19
|
}>;
|
|
18
|
-
/** MySQL `datetime` — {@link jstTimestamp}
|
|
20
|
+
/** MySQL `datetime` — same pass-through policy as {@link jstTimestamp}. */
|
|
19
21
|
export declare const jstDatetime: (name: string, opts?: {
|
|
20
22
|
fsp?: number;
|
|
21
23
|
}) => import("drizzle-orm/mysql-core").MySqlCustomColumnBuilder<{
|
|
@@ -26,7 +28,7 @@ export declare const jstDatetime: (name: string, opts?: {
|
|
|
26
28
|
driverParam: string | Date;
|
|
27
29
|
enumValues: undefined;
|
|
28
30
|
}>;
|
|
29
|
-
/** MySQL `date` — INSERT/UPDATE
|
|
31
|
+
/** MySQL `date` — on INSERT/UPDATE, normalizes ISO / empty strings to `YYYY-MM-DD` (via `toDriver`). */
|
|
30
32
|
export declare const jstDate: (name: string) => import("drizzle-orm/mysql-core").MySqlCustomColumnBuilder<{
|
|
31
33
|
name: string;
|
|
32
34
|
dataType: "custom";
|
|
@@ -35,7 +37,7 @@ export declare const jstDate: (name: string) => import("drizzle-orm/mysql-core")
|
|
|
35
37
|
driverParam: string | null;
|
|
36
38
|
enumValues: undefined;
|
|
37
39
|
}>;
|
|
38
|
-
/** MySQL `decimal` — SELECT
|
|
40
|
+
/** MySQL `decimal` — SELECT coerces string→number via `fromDriver`; writes bind the number as-is. */
|
|
39
41
|
export declare const decimalNumber: (name: string, config: DecimalNumberConfig) => import("drizzle-orm/mysql-core").MySqlCustomColumnBuilder<{
|
|
40
42
|
name: string;
|
|
41
43
|
dataType: "custom";
|