@mandujs/core 0.53.2 → 0.54.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.
- package/README.md +654 -654
- package/package.json +2 -2
- package/src/a11y/__tests__/run-audit.test.ts +333 -333
- package/src/a11y/fix-hints.ts +76 -76
- package/src/a11y/index.ts +18 -18
- package/src/a11y/run-audit.ts +394 -394
- package/src/a11y/types.ts +125 -125
- package/src/auth/__tests__/login.test.ts +1 -1
- package/src/auth/__tests__/password.test.ts +122 -122
- package/src/auth/__tests__/tokens.test.ts +274 -274
- package/src/auth/__tests__/verification.test.ts +274 -274
- package/src/auth/index.ts +76 -76
- package/src/auth/login.ts +225 -225
- package/src/auth/password.ts +120 -120
- package/src/auth/reset.ts +243 -243
- package/src/auth/tokens.ts +612 -612
- package/src/auth/verification.ts +253 -253
- package/src/brain/__tests__/redactor.test.ts +94 -94
- package/src/brain/adapters/__tests__/_helpers.ts +83 -83
- package/src/brain/adapters/__tests__/anthropic-oauth.test.ts +196 -196
- package/src/brain/adapters/__tests__/chatgpt-auth.test.ts +193 -193
- package/src/brain/adapters/__tests__/openai-oauth.test.ts +209 -209
- package/src/brain/adapters/__tests__/resolver.test.ts +143 -143
- package/src/brain/adapters/anthropic-oauth.ts +1 -1
- package/src/brain/adapters/chatgpt-auth.ts +300 -300
- package/src/brain/adapters/index.ts +319 -319
- package/src/brain/adapters/oauth-flow.ts +439 -439
- package/src/brain/consent.ts +240 -240
- package/src/brain/credentials.ts +396 -396
- package/src/bundler/__tests__/build-runner.ts +113 -113
- package/src/bundler/__tests__/dev-reliability.test.ts +619 -619
- package/src/bundler/__tests__/extended-watch.test.ts +711 -711
- package/src/bundler/__tests__/fast-refresh.test.ts +10 -10
- package/src/bundler/__tests__/hdr.test.ts +353 -353
- package/src/bundler/__tests__/hmr-client.test.ts +532 -532
- package/src/bundler/__tests__/manifest-schema.test.ts +266 -266
- package/src/bundler/__tests__/prod-smoke.test.ts +138 -138
- package/src/bundler/__tests__/reverse-import-graph.test.ts +519 -519
- package/src/bundler/__tests__/slot-dispatch.test.ts +573 -573
- package/src/bundler/__tests__/url-cap-and-slot-regex.test.ts +286 -286
- package/src/bundler/__tests__/vendor-cache.test.ts +455 -455
- package/src/bundler/budget.ts +404 -404
- package/src/bundler/build.test.ts +179 -179
- package/src/bundler/build.ts +55 -55
- package/src/bundler/dev.ts +42 -42
- package/src/bundler/manifest-schema.ts +301 -301
- package/src/bundler/plugins/__tests__/block-generated-imports.test.ts +263 -263
- package/src/bundler/plugins/__tests__/react-compiler-config.test.ts +83 -83
- package/src/bundler/plugins/__tests__/react-compiler-lint.test.ts +110 -110
- package/src/bundler/plugins/block-generated-imports.ts +155 -155
- package/src/bundler/plugins/index.ts +83 -83
- package/src/bundler/plugins/react-compiler-config.ts +108 -108
- package/src/bundler/plugins/react-compiler-lint.ts +253 -253
- package/src/bundler/plugins/react-compiler.ts +162 -162
- package/src/bundler/reverse-import-graph.ts +339 -339
- package/src/bundler/safe-build.test.ts +201 -201
- package/src/bundler/safe-build.ts +103 -103
- package/src/bundler/scenario-matrix.ts +229 -229
- package/src/bundler/types.ts +10 -10
- package/src/bundler/vendor-cache-types.ts +130 -130
- package/src/bundler/vendor-cache.ts +526 -526
- package/src/change/snapshot.ts +18 -18
- package/src/client/Form.tsx +105 -105
- package/src/client/Link.tsx +9 -9
- package/src/client/__tests__/use-sse.test.ts +153 -153
- package/src/client/globals.ts +1 -1
- package/src/client/hooks.ts +362 -362
- package/src/client/hydrate.ts +340 -340
- package/src/client/prefetch-helper.ts +55 -55
- package/src/client/router.ts +11 -11
- package/src/client/runtime.ts +47 -47
- package/src/client/serialize.ts +404 -404
- package/src/client/use-fetch.ts +6 -6
- package/src/client/use-head.ts +197 -197
- package/src/client/use-sse.ts +378 -378
- package/src/client/window-state.ts +101 -101
- package/src/components/Image.tsx +162 -162
- package/src/config/validate.ts +3 -3
- package/src/config/watcher.ts +311 -311
- package/src/constants.ts +40 -40
- package/src/content/collection.ts +8 -8
- package/src/content/content-layer.ts +7 -7
- package/src/content/data-store.ts +245 -245
- package/src/content/frontmatter.ts +189 -189
- package/src/content/loader-context.ts +171 -171
- package/src/content/loaders/api.ts +216 -216
- package/src/content/loaders/file.ts +172 -172
- package/src/content/loaders/glob.ts +253 -253
- package/src/content/loaders/index.ts +34 -34
- package/src/content/loaders/types.ts +137 -137
- package/src/content/meta-store.ts +209 -209
- package/src/content/prebuild.test.ts +571 -571
- package/src/content/prebuild.ts +636 -636
- package/src/content/schema.ts +20 -20
- package/src/content/sidebar.ts +630 -630
- package/src/content/slug.ts +110 -110
- package/src/content/types.ts +282 -282
- package/src/content/watcher.ts +135 -135
- package/src/contract/client-safe.test.ts +42 -42
- package/src/contract/client-safe.ts +114 -114
- package/src/contract/define.ts +11 -11
- package/src/contract/index.ts +1 -1
- package/src/contract/normalize.test.ts +276 -276
- package/src/contract/normalize.ts +410 -410
- package/src/contract/registry.test.ts +206 -206
- package/src/contract/route-helpers.ts +1 -1
- package/src/contract/rpc.ts +443 -443
- package/src/contract/schema.ts +48 -48
- package/src/contract/types.ts +58 -58
- package/src/db/__tests__/db.test.ts +482 -482
- package/src/db/index.ts +138 -138
- package/src/db/migrations/history-table.ts +345 -345
- package/src/db/migrations/index.ts +3 -3
- package/src/db/migrations/lock.ts +324 -324
- package/src/db/migrations/runner.ts +650 -650
- package/src/deploy/cache.ts +140 -140
- package/src/deploy/compile/vercel.ts +344 -344
- package/src/deploy/index.ts +87 -87
- package/src/deploy/inference/brain.ts +268 -268
- package/src/deploy/inference/context.ts +182 -182
- package/src/deploy/inference/filling-extract.ts +245 -245
- package/src/deploy/inference/heuristic.ts +182 -182
- package/src/deploy/intent.ts +173 -173
- package/src/deploy/plan.ts +178 -178
- package/src/design/__tests__/agents-link.test.ts +109 -109
- package/src/design/__tests__/extract-patch-diff.test.ts +265 -265
- package/src/design/__tests__/lint.test.ts +110 -110
- package/src/design/__tests__/parser.test.ts +195 -195
- package/src/design/__tests__/tailwind-theme.test.ts +229 -229
- package/src/design/agents-link.ts +165 -165
- package/src/design/diff.ts +138 -138
- package/src/design/extract.ts +285 -285
- package/src/design/index.ts +102 -102
- package/src/design/lint.ts +209 -209
- package/src/design/parser.ts +555 -555
- package/src/design/patch.ts +241 -241
- package/src/design/scaffold.ts +147 -147
- package/src/design/tailwind-theme.ts +441 -441
- package/src/design/types.ts +210 -210
- package/src/desktop/__tests__/webview-fallback.test.ts +254 -254
- package/src/desktop/__tests__/window.test.ts +248 -248
- package/src/desktop/__tests__/worker.test.ts +266 -266
- package/src/desktop/index.ts +43 -43
- package/src/desktop/types.ts +158 -158
- package/src/desktop/worker.ts +180 -180
- package/src/dev-error-overlay/__tests__/overlay-injector.test.ts +241 -241
- package/src/dev-error-overlay/index.ts +30 -30
- package/src/dev-error-overlay/overlay-injector.ts +243 -243
- package/src/dev-error-overlay/overlay-styles.ts +52 -52
- package/src/dev-error-overlay/types.ts +66 -66
- package/src/devtools/ai/context-builder.ts +375 -375
- package/src/devtools/ai/index.ts +25 -25
- package/src/devtools/ai/mcp-connector.ts +25 -25
- package/src/devtools/client/catchers/error-catcher.ts +344 -344
- package/src/devtools/client/catchers/index.ts +18 -18
- package/src/devtools/client/components/index.ts +39 -39
- package/src/devtools/client/components/mandu-character.tsx +331 -331
- package/src/devtools/client/components/overlay.tsx +368 -368
- package/src/devtools/client/components/panel/errors-panel.tsx +259 -259
- package/src/devtools/client/components/panel/guard-panel.tsx +30 -30
- package/src/devtools/client/components/panel/islands-panel.tsx +320 -320
- package/src/devtools/client/components/panel/network-panel.tsx +291 -291
- package/src/devtools/client/components/panel/panel-container.tsx +500 -500
- package/src/devtools/client/components/panel/preview-panel.tsx +46 -46
- package/src/devtools/client/filters/context-filters.ts +282 -282
- package/src/devtools/client/filters/index.ts +16 -16
- package/src/devtools/client/index.ts +63 -63
- package/src/devtools/client/persistence.ts +335 -335
- package/src/devtools/hook/create-hook.ts +207 -207
- package/src/devtools/hook/index.ts +13 -13
- package/src/devtools/index.ts +439 -439
- package/src/devtools/init.ts +265 -265
- package/src/devtools/protocol.ts +237 -237
- package/src/devtools/server/index.ts +17 -17
- package/src/devtools/server/source-context.ts +450 -450
- package/src/devtools/types.ts +35 -35
- package/src/devtools/worker/index.ts +25 -25
- package/src/devtools/worker/redaction-worker.ts +233 -233
- package/src/devtools/worker/worker-manager.ts +410 -410
- package/src/diagnose/__tests__/checks.test.ts +451 -380
- package/src/diagnose/checks.ts +832 -720
- package/src/diagnose/index.ts +17 -16
- package/src/diagnose/run.ts +93 -91
- package/src/diagnose/types.ts +53 -53
- package/src/email/__tests__/email.test.ts +355 -355
- package/src/email/index.ts +282 -282
- package/src/email/smtp.ts +64 -64
- package/src/error/domains.ts +265 -265
- package/src/error/result.ts +60 -60
- package/src/error/types.ts +6 -6
- package/src/errors/extractor.ts +409 -409
- package/src/errors/index.ts +19 -19
- package/src/filling/__tests__/session-sqlite.test.ts +454 -454
- package/src/filling/auth.ts +308 -308
- package/src/filling/cookie-codec.ts +299 -299
- package/src/filling/deps.ts +265 -265
- package/src/filling/session-sqlite.ts +617 -617
- package/src/filling/sse.ts +5 -5
- package/src/filling/ws.ts +78 -78
- package/src/generator/index.ts +3 -3
- package/src/guard/__tests__/design-inline-class.test.ts +219 -219
- package/src/guard/__tests__/tsgolint-bridge.test.ts +347 -347
- package/src/guard/analyzer.ts +360 -360
- package/src/guard/auto-correct.ts +1 -1
- package/src/guard/contract-guard.ts +9 -9
- package/src/guard/define-rule.ts +243 -243
- package/src/guard/design-inline-class.ts +393 -393
- package/src/guard/file-type.test.ts +24 -24
- package/src/guard/graph.ts +1 -1
- package/src/guard/healing.ts +36 -36
- package/src/guard/presets/atomic.ts +70 -70
- package/src/guard/presets/clean.ts +77 -77
- package/src/guard/presets/fsd.ts +79 -79
- package/src/guard/presets/hexagonal.ts +68 -68
- package/src/guard/reporter.ts +442 -442
- package/src/guard/rule-presets.ts +379 -379
- package/src/guard/semantic-slots.ts +1 -1
- package/src/guard/suggestions.ts +358 -358
- package/src/guard/tsgolint-bridge.ts +512 -512
- package/src/guard/types.ts +348 -348
- package/src/guard/watcher.ts +405 -405
- package/src/i18n/define.ts +126 -126
- package/src/i18n/index.ts +52 -52
- package/src/i18n/message-registry.ts +173 -173
- package/src/i18n/types.ts +112 -112
- package/src/id/index.ts +105 -105
- package/src/index.ts +2 -2
- package/src/kitchen/api/agent-devtools-api.ts +779 -544
- package/src/kitchen/api/errors-grouping.ts +126 -0
- package/src/kitchen/kitchen-handler.ts +192 -63
- package/src/kitchen/kitchen-ui.ts +842 -464
- package/src/logging/index.ts +22 -22
- package/src/logging/transports.ts +365 -365
- package/src/middleware/bridge.ts +147 -147
- package/src/middleware/compose.ts +134 -134
- package/src/middleware/compress.ts +62 -62
- package/src/middleware/cors.ts +47 -47
- package/src/middleware/csrf.ts +328 -328
- package/src/middleware/define.ts +132 -132
- package/src/middleware/jwt.ts +134 -134
- package/src/middleware/logger.ts +58 -58
- package/src/middleware/oauth/__tests__/oauth.test.ts +1 -1
- package/src/middleware/oauth/index.ts +505 -505
- package/src/middleware/oauth/providers.ts +115 -115
- package/src/middleware/rate-limit/index.ts +522 -522
- package/src/middleware/rate-limit/sqlite-store.ts +382 -382
- package/src/middleware/scheduler-cron.ts +96 -96
- package/src/middleware/secure/__tests__/secure.test.ts +360 -360
- package/src/middleware/secure/csp.ts +193 -193
- package/src/middleware/session.ts +174 -174
- package/src/middleware/timeout.ts +55 -55
- package/src/observability/logger-adapter.ts +36 -36
- package/src/observability/sqlite-store.ts +254 -254
- package/src/openapi/generator.ts +1 -1
- package/src/openapi/openapi.test.ts +43 -43
- package/src/perf/__tests__/user-marks.test.ts +354 -354
- package/src/perf/index.ts +133 -133
- package/src/plugins/__tests__/lifecycle-integration.test.ts +272 -272
- package/src/plugins/__tests__/runner.test.ts +409 -409
- package/src/plugins/define.ts +124 -124
- package/src/plugins/examples/dep-check-plugin.ts +80 -80
- package/src/plugins/examples/prerender-cache-plugin.ts +111 -111
- package/src/plugins/examples/sitemap-plugin.ts +65 -65
- package/src/plugins/runner.ts +361 -361
- package/src/plugins/types.ts +368 -368
- package/src/report/index.ts +1 -1
- package/src/resource/__tests__/generator.test.ts +32 -32
- package/src/resource/ddl/__tests__/diff.test.ts +639 -639
- package/src/resource/ddl/__tests__/emit.test.ts +823 -823
- package/src/resource/ddl/__tests__/snapshot.test.ts +499 -499
- package/src/resource/ddl/emit.ts +559 -559
- package/src/resource/ddl/persistence-types.ts +218 -218
- package/src/resource/ddl/type-map.ts +223 -223
- package/src/resource/ddl/types.ts +232 -232
- package/src/resource/generator-repo.ts +630 -630
- package/src/resource/schema.ts +1 -1
- package/src/router/fs-patterns.test.ts +96 -96
- package/src/router/fs-routes.ts +6 -6
- package/src/routes/index.ts +74 -74
- package/src/routes/metadata-routes.ts +427 -427
- package/src/routes/types.ts +341 -341
- package/src/runtime/__tests__/error-boundary-redaction.test.ts +141 -141
- package/src/runtime/__tests__/hdr-client.test.ts +223 -223
- package/src/runtime/__tests__/http-errors.test.ts +117 -117
- package/src/runtime/__tests__/not-found.test.ts +152 -152
- package/src/runtime/adapter.ts +47 -47
- package/src/runtime/boundary.tsx +252 -252
- package/src/runtime/cache.ts +494 -494
- package/src/runtime/compose.ts +222 -222
- package/src/runtime/fast-refresh-runtime.ts +322 -322
- package/src/runtime/handler.ts +65 -65
- package/src/runtime/handlers.ts +300 -300
- package/src/runtime/http-errors.ts +113 -113
- package/src/runtime/image-handler.ts +1 -1
- package/src/runtime/lifecycle.ts +381 -381
- package/src/runtime/logger.test.ts +345 -345
- package/src/runtime/middleware.ts +264 -264
- package/src/runtime/not-found.ts +93 -93
- package/src/runtime/openapi-endpoint.ts +236 -236
- package/src/runtime/ppr.ts +74 -74
- package/src/runtime/registry.ts +171 -171
- package/src/runtime/router.ts +105 -105
- package/src/runtime/server.ts +67 -67
- package/src/runtime/shims.ts +48 -48
- package/src/runtime/ssr.ts +24 -31
- package/src/runtime/streaming-ssr.ts +32 -37
- package/src/runtime/trace.ts +144 -144
- package/src/scheduler/validate.ts +169 -169
- package/src/seo/index.ts +219 -219
- package/src/seo/integration/ssr.ts +306 -306
- package/src/seo/render/basic.ts +435 -435
- package/src/seo/render/index.ts +143 -143
- package/src/seo/render/jsonld.ts +539 -539
- package/src/seo/render/opengraph.ts +197 -197
- package/src/seo/render/robots.ts +116 -116
- package/src/seo/render/sitemap.ts +137 -137
- package/src/seo/render/twitter.ts +127 -127
- package/src/seo/resolve/opengraph.ts +143 -143
- package/src/seo/resolve/robots.ts +73 -73
- package/src/seo/resolve/title.ts +94 -94
- package/src/seo/resolve/twitter.ts +73 -73
- package/src/seo/resolve/url.ts +104 -104
- package/src/seo/routes/index.ts +290 -290
- package/src/seo/types.ts +588 -588
- package/src/slot/validator.ts +39 -39
- package/src/storage/s3/__tests__/s3.test.ts +479 -479
- package/src/storage/s3/index.ts +412 -412
- package/src/testing/__tests__/assertions.test.ts +632 -632
- package/src/testing/__tests__/reporter.test.ts +454 -454
- package/src/testing/assertions.ts +986 -986
- package/src/testing/db.ts +157 -157
- package/src/testing/mocks.ts +203 -203
- package/src/testing/session.ts +190 -190
- package/src/types/branded.ts +56 -56
- package/src/types/index.ts +1 -1
- package/src/utils/safe-io.ts +188 -188
- package/src/utils/string-safe.ts +298 -298
- package/src/watcher/watcher.ts +18 -18
|
@@ -1,223 +1,223 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phase 4c — Dialect-specific type mapping.
|
|
3
|
-
*
|
|
4
|
-
* Pure, stateless translation from Mandu's abstract `DdlFieldType` to the
|
|
5
|
-
* concrete SQL column type declaration for each supported provider.
|
|
6
|
-
*
|
|
7
|
-
* This module is intentionally tiny and has no dependency on `emit.ts`; it
|
|
8
|
-
* is imported by `emit.ts` and may be consumed independently by Agents
|
|
9
|
-
* D (generator) and F (QA) for table introspection / parity checks.
|
|
10
|
-
*
|
|
11
|
-
* ## Type map (v1 definitive)
|
|
12
|
-
*
|
|
13
|
-
* | Mandu `type` | Postgres | MySQL | SQLite |
|
|
14
|
-
* |---------------------------|-------------------|---------------|---------|
|
|
15
|
-
* | `string` (no maxLength) | `TEXT` | `VARCHAR(255)`| `TEXT` |
|
|
16
|
-
* | `string` (maxLength = N) | `VARCHAR(N)` | `VARCHAR(N)` | `TEXT` |
|
|
17
|
-
* | `number` | `DOUBLE PRECISION`| `DOUBLE` | `REAL` |
|
|
18
|
-
* | `boolean` | `BOOLEAN` | `TINYINT(1)` | `INTEGER`|
|
|
19
|
-
* | `date` | `TIMESTAMPTZ` | `DATETIME(6)` | `TEXT` |
|
|
20
|
-
* | `uuid` | `UUID` | `CHAR(36)` | `TEXT` |
|
|
21
|
-
* | `email` | `VARCHAR(320)` | `VARCHAR(320)`| `TEXT` |
|
|
22
|
-
* | `url` | `VARCHAR(2048)` | `VARCHAR(2048)`| `TEXT` |
|
|
23
|
-
* | `json` / `array` / `object`| `JSONB` | `JSON` | `TEXT` |
|
|
24
|
-
*
|
|
25
|
-
* Rationale for fixed lengths:
|
|
26
|
-
* - `email` 320 chars — RFC 5321 cap (64 local + 1 @ + 255 domain).
|
|
27
|
-
* - `url` 2048 chars — de facto HTTP URL upper bound used by most
|
|
28
|
-
* browsers and CDNs; shorter than many drivers' TEXT truncation.
|
|
29
|
-
* - `string` default on MySQL is `VARCHAR(255)` because MySQL without a
|
|
30
|
-
* length on `VARCHAR` fails to parse; `TEXT` on MySQL disallows indexes
|
|
31
|
-
* without a prefix spec which breaks `indexed: true`.
|
|
32
|
-
*
|
|
33
|
-
* SQLite notes:
|
|
34
|
-
* - SQLite uses dynamic type affinity; our mapping chooses the canonical
|
|
35
|
-
* affinity names (`TEXT`, `REAL`, `INTEGER`) over the richer PG types so
|
|
36
|
-
* `SELECT typeof(col)` returns the expected affinity in tests.
|
|
37
|
-
* - Booleans are `INTEGER` — SQLite has no native boolean; the driver
|
|
38
|
-
* stores `1`/`0`.
|
|
39
|
-
*/
|
|
40
|
-
import type { DdlDefault, DdlFieldDef, DdlFieldType, SqlProvider } from "./types";
|
|
41
|
-
|
|
42
|
-
// =====================================================================
|
|
43
|
-
// Constants — exposed for testability and to document magic numbers.
|
|
44
|
-
// =====================================================================
|
|
45
|
-
|
|
46
|
-
/** Default VARCHAR length for MySQL when the `string` field omits `maxLength`. */
|
|
47
|
-
export const MYSQL_DEFAULT_STRING_LENGTH = 255;
|
|
48
|
-
|
|
49
|
-
/** RFC 5321 email upper bound. Enforced on MySQL/PG as a VARCHAR cap. */
|
|
50
|
-
export const EMAIL_MAX_LENGTH = 320;
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Pragmatic HTTP URL cap — shorter than most TEXT truncation points
|
|
54
|
-
* (e.g. IE's historical 2083 limit) and long enough for OAuth redirects.
|
|
55
|
-
*/
|
|
56
|
-
export const URL_MAX_LENGTH = 2048;
|
|
57
|
-
|
|
58
|
-
/** Fixed CHAR length for UUIDs on MySQL (36 = canonical hex-with-dashes). */
|
|
59
|
-
export const UUID_CHAR_LENGTH = 36;
|
|
60
|
-
|
|
61
|
-
// =====================================================================
|
|
62
|
-
// Static per-provider map for non-parameterized types.
|
|
63
|
-
// `string` is resolved dynamically because it depends on `maxLength`.
|
|
64
|
-
// =====================================================================
|
|
65
|
-
|
|
66
|
-
type StaticType = Exclude<DdlFieldType, "string">;
|
|
67
|
-
|
|
68
|
-
const TYPE_MAP: Record<SqlProvider, Record<StaticType, string>> = {
|
|
69
|
-
postgres: {
|
|
70
|
-
number: "DOUBLE PRECISION",
|
|
71
|
-
boolean: "BOOLEAN",
|
|
72
|
-
date: "TIMESTAMPTZ",
|
|
73
|
-
uuid: "UUID",
|
|
74
|
-
email: `VARCHAR(${EMAIL_MAX_LENGTH})`,
|
|
75
|
-
url: `VARCHAR(${URL_MAX_LENGTH})`,
|
|
76
|
-
json: "JSONB",
|
|
77
|
-
array: "JSONB",
|
|
78
|
-
object: "JSONB",
|
|
79
|
-
},
|
|
80
|
-
mysql: {
|
|
81
|
-
number: "DOUBLE",
|
|
82
|
-
boolean: "TINYINT(1)",
|
|
83
|
-
date: "DATETIME(6)",
|
|
84
|
-
uuid: `CHAR(${UUID_CHAR_LENGTH})`,
|
|
85
|
-
email: `VARCHAR(${EMAIL_MAX_LENGTH})`,
|
|
86
|
-
url: `VARCHAR(${URL_MAX_LENGTH})`,
|
|
87
|
-
json: "JSON",
|
|
88
|
-
array: "JSON",
|
|
89
|
-
object: "JSON",
|
|
90
|
-
},
|
|
91
|
-
sqlite: {
|
|
92
|
-
number: "REAL",
|
|
93
|
-
boolean: "INTEGER",
|
|
94
|
-
date: "TEXT",
|
|
95
|
-
uuid: "TEXT",
|
|
96
|
-
email: "TEXT",
|
|
97
|
-
url: "TEXT",
|
|
98
|
-
json: "TEXT",
|
|
99
|
-
array: "TEXT",
|
|
100
|
-
object: "TEXT",
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
// =====================================================================
|
|
105
|
-
// Public API
|
|
106
|
-
// =====================================================================
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Dialect-specific NOW() expression. Used by `DdlDefault.kind === "now"`
|
|
110
|
-
* and by emit.ts when a field's default should map to "current timestamp".
|
|
111
|
-
*
|
|
112
|
-
* - Postgres & MySQL — `NOW()` (ANSI-ish, identical semantics).
|
|
113
|
-
* - SQLite — `CURRENT_TIMESTAMP` (SQLite has no `NOW()`).
|
|
114
|
-
*/
|
|
115
|
-
export function nowExpr(provider: SqlProvider): string {
|
|
116
|
-
switch (provider) {
|
|
117
|
-
case "postgres":
|
|
118
|
-
case "mysql":
|
|
119
|
-
return "NOW()";
|
|
120
|
-
case "sqlite":
|
|
121
|
-
return "CURRENT_TIMESTAMP";
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Resolve a Mandu field to its dialect-specific SQL column type declaration.
|
|
127
|
-
*
|
|
128
|
-
* `maxLength` applies ONLY to `string` — other types have fixed widths
|
|
129
|
-
* documented in the module header.
|
|
130
|
-
*
|
|
131
|
-
* @example
|
|
132
|
-
* resolveColumnType({ type: "string", maxLength: 100, ... }, "postgres")
|
|
133
|
-
* → "VARCHAR(100)"
|
|
134
|
-
* resolveColumnType({ type: "string", ... }, "postgres")
|
|
135
|
-
* → "TEXT"
|
|
136
|
-
* resolveColumnType({ type: "string", ... }, "mysql")
|
|
137
|
-
* → "VARCHAR(255)"
|
|
138
|
-
*/
|
|
139
|
-
export function resolveColumnType(field: DdlFieldDef, provider: SqlProvider): string {
|
|
140
|
-
if (field.type === "string") {
|
|
141
|
-
return resolveStringType(field.maxLength, provider);
|
|
142
|
-
}
|
|
143
|
-
// Narrowed above — the remaining types are StaticType.
|
|
144
|
-
return TYPE_MAP[provider][field.type];
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Resolve a `DdlDefault` to the SQL literal that goes after `DEFAULT`.
|
|
149
|
-
*
|
|
150
|
-
* Returns JUST the expression — the caller prepends `DEFAULT ` when
|
|
151
|
-
* composing the column definition.
|
|
152
|
-
*
|
|
153
|
-
* Escaping rules:
|
|
154
|
-
* - `literal: string` — ANSI single-quote escape (`'` → `''`).
|
|
155
|
-
* - `literal: number` — emitted verbatim (already numeric).
|
|
156
|
-
* - `literal: boolean` — Postgres/MySQL `TRUE`/`FALSE`; SQLite `1`/`0`
|
|
157
|
-
* (no native boolean).
|
|
158
|
-
* - `sql: expr` — passed through unchanged. Caller is responsible
|
|
159
|
-
* for cross-dialect portability; this is the escape hatch for things
|
|
160
|
-
* like sequence defaults or Postgres-specific `gen_random_uuid()`.
|
|
161
|
-
*/
|
|
162
|
-
export function resolveDefault(def: NonNullable<DdlFieldDef["default"]>, provider: SqlProvider): string {
|
|
163
|
-
switch (def.kind) {
|
|
164
|
-
case "now":
|
|
165
|
-
return nowExpr(provider);
|
|
166
|
-
case "null":
|
|
167
|
-
return "NULL";
|
|
168
|
-
case "sql":
|
|
169
|
-
return def.expr;
|
|
170
|
-
case "literal":
|
|
171
|
-
return formatLiteral(def.value, provider);
|
|
172
|
-
}
|
|
173
|
-
// Exhaustiveness check — if DdlDefault gains a variant, TS will force this
|
|
174
|
-
// function to be updated before the project type-checks.
|
|
175
|
-
const _exhaustive: never = def;
|
|
176
|
-
return _exhaustive;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// =====================================================================
|
|
180
|
-
// Internals
|
|
181
|
-
// =====================================================================
|
|
182
|
-
|
|
183
|
-
function resolveStringType(maxLength: number | undefined, provider: SqlProvider): string {
|
|
184
|
-
if (provider === "sqlite") return "TEXT"; // SQLite ignores length spec.
|
|
185
|
-
if (typeof maxLength === "number" && maxLength > 0) return `VARCHAR(${maxLength})`;
|
|
186
|
-
if (provider === "postgres") return "TEXT";
|
|
187
|
-
// MySQL default: we MUST pick a length because `VARCHAR` with no length is
|
|
188
|
-
// a parse error. 255 is the convention most ORMs settle on.
|
|
189
|
-
return `VARCHAR(${MYSQL_DEFAULT_STRING_LENGTH})`;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function formatLiteral(value: string | number | boolean, provider: SqlProvider): string {
|
|
193
|
-
if (typeof value === "string") {
|
|
194
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
195
|
-
}
|
|
196
|
-
if (typeof value === "number") {
|
|
197
|
-
if (!Number.isFinite(value)) {
|
|
198
|
-
throw new Error(`DDL default literal must be a finite number, got ${String(value)}`);
|
|
199
|
-
}
|
|
200
|
-
return String(value);
|
|
201
|
-
}
|
|
202
|
-
// boolean
|
|
203
|
-
if (provider === "sqlite") return value ? "1" : "0";
|
|
204
|
-
return value ? "TRUE" : "FALSE";
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Runtime sanity — exported for test use only.
|
|
208
|
-
export function _internal_allStaticTypes(): StaticType[] {
|
|
209
|
-
return [
|
|
210
|
-
"number",
|
|
211
|
-
"boolean",
|
|
212
|
-
"date",
|
|
213
|
-
"uuid",
|
|
214
|
-
"email",
|
|
215
|
-
"url",
|
|
216
|
-
"json",
|
|
217
|
-
"array",
|
|
218
|
-
"object",
|
|
219
|
-
];
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/** Re-export DdlDefault for ergonomic consumer imports. */
|
|
223
|
-
export type { DdlDefault };
|
|
1
|
+
/**
|
|
2
|
+
* Phase 4c — Dialect-specific type mapping.
|
|
3
|
+
*
|
|
4
|
+
* Pure, stateless translation from Mandu's abstract `DdlFieldType` to the
|
|
5
|
+
* concrete SQL column type declaration for each supported provider.
|
|
6
|
+
*
|
|
7
|
+
* This module is intentionally tiny and has no dependency on `emit.ts`; it
|
|
8
|
+
* is imported by `emit.ts` and may be consumed independently by Agents
|
|
9
|
+
* D (generator) and F (QA) for table introspection / parity checks.
|
|
10
|
+
*
|
|
11
|
+
* ## Type map (v1 definitive)
|
|
12
|
+
*
|
|
13
|
+
* | Mandu `type` | Postgres | MySQL | SQLite |
|
|
14
|
+
* |---------------------------|-------------------|---------------|---------|
|
|
15
|
+
* | `string` (no maxLength) | `TEXT` | `VARCHAR(255)`| `TEXT` |
|
|
16
|
+
* | `string` (maxLength = N) | `VARCHAR(N)` | `VARCHAR(N)` | `TEXT` |
|
|
17
|
+
* | `number` | `DOUBLE PRECISION`| `DOUBLE` | `REAL` |
|
|
18
|
+
* | `boolean` | `BOOLEAN` | `TINYINT(1)` | `INTEGER`|
|
|
19
|
+
* | `date` | `TIMESTAMPTZ` | `DATETIME(6)` | `TEXT` |
|
|
20
|
+
* | `uuid` | `UUID` | `CHAR(36)` | `TEXT` |
|
|
21
|
+
* | `email` | `VARCHAR(320)` | `VARCHAR(320)`| `TEXT` |
|
|
22
|
+
* | `url` | `VARCHAR(2048)` | `VARCHAR(2048)`| `TEXT` |
|
|
23
|
+
* | `json` / `array` / `object`| `JSONB` | `JSON` | `TEXT` |
|
|
24
|
+
*
|
|
25
|
+
* Rationale for fixed lengths:
|
|
26
|
+
* - `email` 320 chars — RFC 5321 cap (64 local + 1 @ + 255 domain).
|
|
27
|
+
* - `url` 2048 chars — de facto HTTP URL upper bound used by most
|
|
28
|
+
* browsers and CDNs; shorter than many drivers' TEXT truncation.
|
|
29
|
+
* - `string` default on MySQL is `VARCHAR(255)` because MySQL without a
|
|
30
|
+
* length on `VARCHAR` fails to parse; `TEXT` on MySQL disallows indexes
|
|
31
|
+
* without a prefix spec which breaks `indexed: true`.
|
|
32
|
+
*
|
|
33
|
+
* SQLite notes:
|
|
34
|
+
* - SQLite uses dynamic type affinity; our mapping chooses the canonical
|
|
35
|
+
* affinity names (`TEXT`, `REAL`, `INTEGER`) over the richer PG types so
|
|
36
|
+
* `SELECT typeof(col)` returns the expected affinity in tests.
|
|
37
|
+
* - Booleans are `INTEGER` — SQLite has no native boolean; the driver
|
|
38
|
+
* stores `1`/`0`.
|
|
39
|
+
*/
|
|
40
|
+
import type { DdlDefault, DdlFieldDef, DdlFieldType, SqlProvider } from "./types";
|
|
41
|
+
|
|
42
|
+
// =====================================================================
|
|
43
|
+
// Constants — exposed for testability and to document magic numbers.
|
|
44
|
+
// =====================================================================
|
|
45
|
+
|
|
46
|
+
/** Default VARCHAR length for MySQL when the `string` field omits `maxLength`. */
|
|
47
|
+
export const MYSQL_DEFAULT_STRING_LENGTH = 255;
|
|
48
|
+
|
|
49
|
+
/** RFC 5321 email upper bound. Enforced on MySQL/PG as a VARCHAR cap. */
|
|
50
|
+
export const EMAIL_MAX_LENGTH = 320;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Pragmatic HTTP URL cap — shorter than most TEXT truncation points
|
|
54
|
+
* (e.g. IE's historical 2083 limit) and long enough for OAuth redirects.
|
|
55
|
+
*/
|
|
56
|
+
export const URL_MAX_LENGTH = 2048;
|
|
57
|
+
|
|
58
|
+
/** Fixed CHAR length for UUIDs on MySQL (36 = canonical hex-with-dashes). */
|
|
59
|
+
export const UUID_CHAR_LENGTH = 36;
|
|
60
|
+
|
|
61
|
+
// =====================================================================
|
|
62
|
+
// Static per-provider map for non-parameterized types.
|
|
63
|
+
// `string` is resolved dynamically because it depends on `maxLength`.
|
|
64
|
+
// =====================================================================
|
|
65
|
+
|
|
66
|
+
type StaticType = Exclude<DdlFieldType, "string">;
|
|
67
|
+
|
|
68
|
+
const TYPE_MAP: Record<SqlProvider, Record<StaticType, string>> = {
|
|
69
|
+
postgres: {
|
|
70
|
+
number: "DOUBLE PRECISION",
|
|
71
|
+
boolean: "BOOLEAN",
|
|
72
|
+
date: "TIMESTAMPTZ",
|
|
73
|
+
uuid: "UUID",
|
|
74
|
+
email: `VARCHAR(${EMAIL_MAX_LENGTH})`,
|
|
75
|
+
url: `VARCHAR(${URL_MAX_LENGTH})`,
|
|
76
|
+
json: "JSONB",
|
|
77
|
+
array: "JSONB",
|
|
78
|
+
object: "JSONB",
|
|
79
|
+
},
|
|
80
|
+
mysql: {
|
|
81
|
+
number: "DOUBLE",
|
|
82
|
+
boolean: "TINYINT(1)",
|
|
83
|
+
date: "DATETIME(6)",
|
|
84
|
+
uuid: `CHAR(${UUID_CHAR_LENGTH})`,
|
|
85
|
+
email: `VARCHAR(${EMAIL_MAX_LENGTH})`,
|
|
86
|
+
url: `VARCHAR(${URL_MAX_LENGTH})`,
|
|
87
|
+
json: "JSON",
|
|
88
|
+
array: "JSON",
|
|
89
|
+
object: "JSON",
|
|
90
|
+
},
|
|
91
|
+
sqlite: {
|
|
92
|
+
number: "REAL",
|
|
93
|
+
boolean: "INTEGER",
|
|
94
|
+
date: "TEXT",
|
|
95
|
+
uuid: "TEXT",
|
|
96
|
+
email: "TEXT",
|
|
97
|
+
url: "TEXT",
|
|
98
|
+
json: "TEXT",
|
|
99
|
+
array: "TEXT",
|
|
100
|
+
object: "TEXT",
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// =====================================================================
|
|
105
|
+
// Public API
|
|
106
|
+
// =====================================================================
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Dialect-specific NOW() expression. Used by `DdlDefault.kind === "now"`
|
|
110
|
+
* and by emit.ts when a field's default should map to "current timestamp".
|
|
111
|
+
*
|
|
112
|
+
* - Postgres & MySQL — `NOW()` (ANSI-ish, identical semantics).
|
|
113
|
+
* - SQLite — `CURRENT_TIMESTAMP` (SQLite has no `NOW()`).
|
|
114
|
+
*/
|
|
115
|
+
export function nowExpr(provider: SqlProvider): string {
|
|
116
|
+
switch (provider) {
|
|
117
|
+
case "postgres":
|
|
118
|
+
case "mysql":
|
|
119
|
+
return "NOW()";
|
|
120
|
+
case "sqlite":
|
|
121
|
+
return "CURRENT_TIMESTAMP";
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Resolve a Mandu field to its dialect-specific SQL column type declaration.
|
|
127
|
+
*
|
|
128
|
+
* `maxLength` applies ONLY to `string` — other types have fixed widths
|
|
129
|
+
* documented in the module header.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* resolveColumnType({ type: "string", maxLength: 100, ... }, "postgres")
|
|
133
|
+
* → "VARCHAR(100)"
|
|
134
|
+
* resolveColumnType({ type: "string", ... }, "postgres")
|
|
135
|
+
* → "TEXT"
|
|
136
|
+
* resolveColumnType({ type: "string", ... }, "mysql")
|
|
137
|
+
* → "VARCHAR(255)"
|
|
138
|
+
*/
|
|
139
|
+
export function resolveColumnType(field: DdlFieldDef, provider: SqlProvider): string {
|
|
140
|
+
if (field.type === "string") {
|
|
141
|
+
return resolveStringType(field.maxLength, provider);
|
|
142
|
+
}
|
|
143
|
+
// Narrowed above — the remaining types are StaticType.
|
|
144
|
+
return TYPE_MAP[provider][field.type];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Resolve a `DdlDefault` to the SQL literal that goes after `DEFAULT`.
|
|
149
|
+
*
|
|
150
|
+
* Returns JUST the expression — the caller prepends `DEFAULT ` when
|
|
151
|
+
* composing the column definition.
|
|
152
|
+
*
|
|
153
|
+
* Escaping rules:
|
|
154
|
+
* - `literal: string` — ANSI single-quote escape (`'` → `''`).
|
|
155
|
+
* - `literal: number` — emitted verbatim (already numeric).
|
|
156
|
+
* - `literal: boolean` — Postgres/MySQL `TRUE`/`FALSE`; SQLite `1`/`0`
|
|
157
|
+
* (no native boolean).
|
|
158
|
+
* - `sql: expr` — passed through unchanged. Caller is responsible
|
|
159
|
+
* for cross-dialect portability; this is the escape hatch for things
|
|
160
|
+
* like sequence defaults or Postgres-specific `gen_random_uuid()`.
|
|
161
|
+
*/
|
|
162
|
+
export function resolveDefault(def: NonNullable<DdlFieldDef["default"]>, provider: SqlProvider): string {
|
|
163
|
+
switch (def.kind) {
|
|
164
|
+
case "now":
|
|
165
|
+
return nowExpr(provider);
|
|
166
|
+
case "null":
|
|
167
|
+
return "NULL";
|
|
168
|
+
case "sql":
|
|
169
|
+
return def.expr;
|
|
170
|
+
case "literal":
|
|
171
|
+
return formatLiteral(def.value, provider);
|
|
172
|
+
}
|
|
173
|
+
// Exhaustiveness check — if DdlDefault gains a variant, TS will force this
|
|
174
|
+
// function to be updated before the project type-checks.
|
|
175
|
+
const _exhaustive: never = def;
|
|
176
|
+
return _exhaustive;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// =====================================================================
|
|
180
|
+
// Internals
|
|
181
|
+
// =====================================================================
|
|
182
|
+
|
|
183
|
+
function resolveStringType(maxLength: number | undefined, provider: SqlProvider): string {
|
|
184
|
+
if (provider === "sqlite") return "TEXT"; // SQLite ignores length spec.
|
|
185
|
+
if (typeof maxLength === "number" && maxLength > 0) return `VARCHAR(${maxLength})`;
|
|
186
|
+
if (provider === "postgres") return "TEXT";
|
|
187
|
+
// MySQL default: we MUST pick a length because `VARCHAR` with no length is
|
|
188
|
+
// a parse error. 255 is the convention most ORMs settle on.
|
|
189
|
+
return `VARCHAR(${MYSQL_DEFAULT_STRING_LENGTH})`;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function formatLiteral(value: string | number | boolean, provider: SqlProvider): string {
|
|
193
|
+
if (typeof value === "string") {
|
|
194
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
195
|
+
}
|
|
196
|
+
if (typeof value === "number") {
|
|
197
|
+
if (!Number.isFinite(value)) {
|
|
198
|
+
throw new Error(`DDL default literal must be a finite number, got ${String(value)}`);
|
|
199
|
+
}
|
|
200
|
+
return String(value);
|
|
201
|
+
}
|
|
202
|
+
// boolean
|
|
203
|
+
if (provider === "sqlite") return value ? "1" : "0";
|
|
204
|
+
return value ? "TRUE" : "FALSE";
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Runtime sanity — exported for test use only.
|
|
208
|
+
export function _internal_allStaticTypes(): StaticType[] {
|
|
209
|
+
return [
|
|
210
|
+
"number",
|
|
211
|
+
"boolean",
|
|
212
|
+
"date",
|
|
213
|
+
"uuid",
|
|
214
|
+
"email",
|
|
215
|
+
"url",
|
|
216
|
+
"json",
|
|
217
|
+
"array",
|
|
218
|
+
"object",
|
|
219
|
+
];
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** Re-export DdlDefault for ergonomic consumer imports. */
|
|
223
|
+
export type { DdlDefault };
|