@mandujs/core 0.53.3 → 0.54.1
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 +1 -1
- 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 -451
- package/src/diagnose/checks.ts +832 -832
- package/src/diagnose/index.ts +17 -17
- package/src/diagnose/run.ts +93 -93
- 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/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
package/src/auth/password.ts
CHANGED
|
@@ -1,120 +1,120 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @mandujs/core/auth/password
|
|
3
|
-
*
|
|
4
|
-
* Password hashing and verification backed by `Bun.password`.
|
|
5
|
-
*
|
|
6
|
-
* Defaults to **argon2id** — the OWASP-recommended memory-hard KDF. `bcrypt`
|
|
7
|
-
* is exposed for legacy database interop only. PBKDF2/scrypt are intentionally
|
|
8
|
-
* not supported (see non-goals in the module design doc).
|
|
9
|
-
*
|
|
10
|
-
* This module is **Bun-native**. It will throw at first call if executed in a
|
|
11
|
-
* runtime without `Bun.password`. Use the Web Crypto polyfills in `@mandujs/core/id`
|
|
12
|
-
* as a reference for how we handle runtime-specific APIs.
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* ```ts
|
|
16
|
-
* import { hashPassword, verifyPassword } from "@mandujs/core/auth/password";
|
|
17
|
-
*
|
|
18
|
-
* const hash = await hashPassword("s3cret!");
|
|
19
|
-
* const ok = await verifyPassword("s3cret!", hash); // true
|
|
20
|
-
* ```
|
|
21
|
-
*
|
|
22
|
-
* @module auth/password
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* bcrypt hard-limits passwords to 72 bytes. We reject at the boundary instead
|
|
27
|
-
* of letting Bun silently truncate, so callers get a clear error at hash time.
|
|
28
|
-
* See https://en.wikipedia.org/wiki/Bcrypt#User_input
|
|
29
|
-
*/
|
|
30
|
-
const BCRYPT_MAX_BYTES = 72;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Password hashing options. Mirrors the `Bun.password` option shape.
|
|
34
|
-
*/
|
|
35
|
-
export interface PasswordOptions {
|
|
36
|
-
/** Default: "argon2id". bcrypt available for legacy interop. */
|
|
37
|
-
algorithm?: "argon2id" | "argon2d" | "argon2i" | "bcrypt";
|
|
38
|
-
/** Argon2 only. Memory cost in KiB. Default: Bun default. */
|
|
39
|
-
memoryCost?: number;
|
|
40
|
-
/** Argon2 only. Time cost (iterations). Default: Bun default. */
|
|
41
|
-
timeCost?: number;
|
|
42
|
-
/** bcrypt only. Cost factor. Default: Bun default. */
|
|
43
|
-
cost?: number;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** Minimal structural type for the Bun.password surface we consume. */
|
|
47
|
-
interface BunPasswordApi {
|
|
48
|
-
hash: (plain: string, options?: PasswordOptions) => Promise<string>;
|
|
49
|
-
verify: (plain: string, hash: string) => Promise<boolean>;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function getBunPassword(): BunPasswordApi {
|
|
53
|
-
const g = globalThis as unknown as { Bun?: { password?: BunPasswordApi } };
|
|
54
|
-
if (!g.Bun || !g.Bun.password) {
|
|
55
|
-
throw new Error(
|
|
56
|
-
"[@mandujs/core/auth/password] Bun.password is unavailable — this module requires the Bun runtime (>= 1.3).",
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
return g.Bun.password;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Hashes a plaintext password. Uses argon2id by default.
|
|
64
|
-
*
|
|
65
|
-
* Throws if `plain` is empty, or if `algorithm: "bcrypt"` is selected and the
|
|
66
|
-
* UTF-8 byte length exceeds 72 (bcrypt's hard limit — we surface the error
|
|
67
|
-
* early instead of silently truncating).
|
|
68
|
-
*/
|
|
69
|
-
export async function hashPassword(
|
|
70
|
-
plain: string,
|
|
71
|
-
options?: PasswordOptions,
|
|
72
|
-
): Promise<string> {
|
|
73
|
-
if (typeof plain !== "string" || plain.length === 0) {
|
|
74
|
-
throw new Error(
|
|
75
|
-
"[@mandujs/core/auth/password] hashPassword: plaintext must be a non-empty string.",
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (options?.algorithm === "bcrypt") {
|
|
80
|
-
const bytes = Buffer.byteLength(plain, "utf8");
|
|
81
|
-
if (bytes > BCRYPT_MAX_BYTES) {
|
|
82
|
-
throw new Error(
|
|
83
|
-
`[@mandujs/core/auth/password] hashPassword: bcrypt input exceeds 72-byte limit (got ${bytes} bytes). Use argon2id for longer passwords.`,
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return await getBunPassword().hash(plain, options);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Verifies a plaintext password against a stored hash. Algorithm is
|
|
93
|
-
* auto-detected from the hash prefix by Bun.
|
|
94
|
-
*
|
|
95
|
-
* Returns `false` on mismatch, malformed hash, or empty input. Never throws
|
|
96
|
-
* for user-supplied values — a throwing verify path would leak hash-format
|
|
97
|
-
* signal via timing/exception type to callers on the login path, so we
|
|
98
|
-
* collapse every failure mode to the same boolean result.
|
|
99
|
-
*/
|
|
100
|
-
export async function verifyPassword(
|
|
101
|
-
plain: string,
|
|
102
|
-
hash: string,
|
|
103
|
-
): Promise<boolean> {
|
|
104
|
-
if (
|
|
105
|
-
typeof plain !== "string" ||
|
|
106
|
-
plain.length === 0 ||
|
|
107
|
-
typeof hash !== "string" ||
|
|
108
|
-
hash.length === 0
|
|
109
|
-
) {
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
try {
|
|
114
|
-
return await getBunPassword().verify(plain, hash);
|
|
115
|
-
} catch {
|
|
116
|
-
// Malformed hash, unsupported algorithm, or any other internal error —
|
|
117
|
-
// treat as verification failure. See function-level comment for rationale.
|
|
118
|
-
return false;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* @mandujs/core/auth/password
|
|
3
|
+
*
|
|
4
|
+
* Password hashing and verification backed by `Bun.password`.
|
|
5
|
+
*
|
|
6
|
+
* Defaults to **argon2id** — the OWASP-recommended memory-hard KDF. `bcrypt`
|
|
7
|
+
* is exposed for legacy database interop only. PBKDF2/scrypt are intentionally
|
|
8
|
+
* not supported (see non-goals in the module design doc).
|
|
9
|
+
*
|
|
10
|
+
* This module is **Bun-native**. It will throw at first call if executed in a
|
|
11
|
+
* runtime without `Bun.password`. Use the Web Crypto polyfills in `@mandujs/core/id`
|
|
12
|
+
* as a reference for how we handle runtime-specific APIs.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { hashPassword, verifyPassword } from "@mandujs/core/auth/password";
|
|
17
|
+
*
|
|
18
|
+
* const hash = await hashPassword("s3cret!");
|
|
19
|
+
* const ok = await verifyPassword("s3cret!", hash); // true
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @module auth/password
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* bcrypt hard-limits passwords to 72 bytes. We reject at the boundary instead
|
|
27
|
+
* of letting Bun silently truncate, so callers get a clear error at hash time.
|
|
28
|
+
* See https://en.wikipedia.org/wiki/Bcrypt#User_input
|
|
29
|
+
*/
|
|
30
|
+
const BCRYPT_MAX_BYTES = 72;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Password hashing options. Mirrors the `Bun.password` option shape.
|
|
34
|
+
*/
|
|
35
|
+
export interface PasswordOptions {
|
|
36
|
+
/** Default: "argon2id". bcrypt available for legacy interop. */
|
|
37
|
+
algorithm?: "argon2id" | "argon2d" | "argon2i" | "bcrypt";
|
|
38
|
+
/** Argon2 only. Memory cost in KiB. Default: Bun default. */
|
|
39
|
+
memoryCost?: number;
|
|
40
|
+
/** Argon2 only. Time cost (iterations). Default: Bun default. */
|
|
41
|
+
timeCost?: number;
|
|
42
|
+
/** bcrypt only. Cost factor. Default: Bun default. */
|
|
43
|
+
cost?: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Minimal structural type for the Bun.password surface we consume. */
|
|
47
|
+
interface BunPasswordApi {
|
|
48
|
+
hash: (plain: string, options?: PasswordOptions) => Promise<string>;
|
|
49
|
+
verify: (plain: string, hash: string) => Promise<boolean>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function getBunPassword(): BunPasswordApi {
|
|
53
|
+
const g = globalThis as unknown as { Bun?: { password?: BunPasswordApi } };
|
|
54
|
+
if (!g.Bun || !g.Bun.password) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
"[@mandujs/core/auth/password] Bun.password is unavailable — this module requires the Bun runtime (>= 1.3).",
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return g.Bun.password;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Hashes a plaintext password. Uses argon2id by default.
|
|
64
|
+
*
|
|
65
|
+
* Throws if `plain` is empty, or if `algorithm: "bcrypt"` is selected and the
|
|
66
|
+
* UTF-8 byte length exceeds 72 (bcrypt's hard limit — we surface the error
|
|
67
|
+
* early instead of silently truncating).
|
|
68
|
+
*/
|
|
69
|
+
export async function hashPassword(
|
|
70
|
+
plain: string,
|
|
71
|
+
options?: PasswordOptions,
|
|
72
|
+
): Promise<string> {
|
|
73
|
+
if (typeof plain !== "string" || plain.length === 0) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
"[@mandujs/core/auth/password] hashPassword: plaintext must be a non-empty string.",
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (options?.algorithm === "bcrypt") {
|
|
80
|
+
const bytes = Buffer.byteLength(plain, "utf8");
|
|
81
|
+
if (bytes > BCRYPT_MAX_BYTES) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`[@mandujs/core/auth/password] hashPassword: bcrypt input exceeds 72-byte limit (got ${bytes} bytes). Use argon2id for longer passwords.`,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return await getBunPassword().hash(plain, options);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Verifies a plaintext password against a stored hash. Algorithm is
|
|
93
|
+
* auto-detected from the hash prefix by Bun.
|
|
94
|
+
*
|
|
95
|
+
* Returns `false` on mismatch, malformed hash, or empty input. Never throws
|
|
96
|
+
* for user-supplied values — a throwing verify path would leak hash-format
|
|
97
|
+
* signal via timing/exception type to callers on the login path, so we
|
|
98
|
+
* collapse every failure mode to the same boolean result.
|
|
99
|
+
*/
|
|
100
|
+
export async function verifyPassword(
|
|
101
|
+
plain: string,
|
|
102
|
+
hash: string,
|
|
103
|
+
): Promise<boolean> {
|
|
104
|
+
if (
|
|
105
|
+
typeof plain !== "string" ||
|
|
106
|
+
plain.length === 0 ||
|
|
107
|
+
typeof hash !== "string" ||
|
|
108
|
+
hash.length === 0
|
|
109
|
+
) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
return await getBunPassword().verify(plain, hash);
|
|
115
|
+
} catch {
|
|
116
|
+
// Malformed hash, unsupported algorithm, or any other internal error —
|
|
117
|
+
// treat as verification failure. See function-level comment for rationale.
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
}
|