Gathering detailed insights and metrics for @httpx/dsn-parser
Gathering detailed insights and metrics for @httpx/dsn-parser
Gathering detailed insights and metrics for @httpx/dsn-parser
Gathering detailed insights and metrics for @httpx/dsn-parser
npm install @httpx/dsn-parser
Typescript
Module System
Min. Node Version
Node Version
NPM Version
@httpx/exception@3.1.1
Updated on Jul 09, 2025
@httpx/stable-hash@0.3.0
Updated on Jun 25, 2025
@httpx/memo-intl@1.4.0
Updated on Jun 25, 2025
@httpx/assert@0.16.0
Updated on Jun 25, 2025
@httpx/treeu@0.5.0
Updated on Jun 25, 2025
@httpx/lru@0.11.0
Updated on Jun 25, 2025
TypeScript (90.52%)
JavaScript (9.48%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
MIT License
18 Stars
2,861 Commits
1 Forks
2 Watchers
15 Branches
1 Contributors
Updated on Jul 12, 2025
Latest Version
1.9.0
Package Id
@httpx/dsn-parser@1.9.0
Unpacked Size
52.59 kB
Size
12.94 kB
File Count
9
NPM Version
10.9.2
Node Version
22.16.0
Published on
Jun 25, 2025
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
DSN & JDBC string parser with query params support in a light (~750B) and modern package.
1$ npm install @httpx/dsn-parser 2$ yarn add @httpx/dsn-parser 3$ pnpm add @httpx/dsn-parser
driver
, user
, password
, host
...)/
, :
... in the password (some libs won't).👉 Official website or Github Readme
Usage with exceptions
1import { parseDsnOrThrow } from "@httpx/dsn-parser"; 2 3const dsn = "redis://user:p@/ssword@localhost:6379/0?ssl=true"; 4 5try { 6 const parsedDsn = parseDsnOrThrow(dsn); 7 assert.deepEqual(parsedDsn, { 8 driver: "redis", 9 pass: "p@/ssword", 10 host: "localhost", 11 user: "user", 12 port: 6379, 13 db: "0", 14 params: { 15 ssl: true, 16 }, 17 }); 18} catch (e) { 19 // example: 20 // e -> Error("Can't parse dsn: Invalid port: 12345678 (INVALID_PORT)") 21}
Usage with discriminated union.
1import { parseDsn } from "@httpx/dsn-parser"; 2 3const dsn = "redis://user:p@/ssword@localhost:6379/0?ssl=true"; 4 5const parsed = parseDsn(dsn); 6 7if (parsed.success) { 8 assert.deepEqual(parsed.value, { 9 driver: "redis", 10 pass: "p@/ssword", 11 host: "localhost", 12 user: "user", 13 port: 6379, 14 db: "0", 15 params: { 16 ssl: true, 17 }, 18 }); 19} else { 20 assert.deepEqual(parsed, { 21 success: false, 22 // Reasons might vary 23 reason: "INVALID_PORT", 24 message: "Invalid http port: 12345678", 25 }); 26}
1import { parseDsn, type ParseDsnOptions } from "@httpx/dsn-parser"; 2 3const dsn = "mySql://localhost:6379/db"; 4const parsed = parseDsn(dsn, { 5 lowercaseDriver: true, 6 // Overrides, allows to force some values (ParseDsnOptions) 7 overrides: { 8 db: "db3", 9 port: undefined, 10 }, 11}); 12 13assert.deepEqual(parsed.value, { 14 driver: "mysql", 15 host: "localhost", 16 db: "db3", 17});
Params | Type | Description |
---|---|---|
lowercaseDriver | boolean | Driver name in lowercase, default false |
overrides | ParseDsnOptions | Overrides allows to force specific values |
1import { isParsableDsn, type ParsableDsn } from "@httpx/dsn-parser"; 2 3const dsn = "postgresql://localhost:6379/db"; 4 5if (isParsableDsn(dsn)) { 6 // known to be ParsableDsn 7}
1import { assertParsableDsn, ParsableDsn } from "@httpx/dsn-parser"; 2 3try { 4 assertParsableDsn("redis:/"); 5 // Type is narrowed to string (ParsableDsn) if it 6 // didn't throw. 7} catch (e) { 8 assert.equal(e.message, "Cannot parse DSN (PARSE_ERROR)"); 9}
ParsableDsn is a weak opaque type.
1declare const tag: unique symbol; 2export type WeakOpaqueContainer<Token> = { 3 readonly [tag]: Token; 4}; 5export type ParsableDsn = string & WeakOpaqueContainer<'ParsableDsn'>;
It can be used to enforce that the isParsableDsn
or assertParsableDsn
have been
used before usage.
1import type { ParsableDsn } from "./dsn-parser.type"; 2import { assertParsableDsn } from "./assert-parsable-dsn"; 3 4// to opt-in, just change the dsn param type to `ParsableDsn` instead of `string` 5const fnWithWeakOpaqueType = (dsn: ParsableDsn) => { 6 // by explictly requiring a ParsableDsn, we can rely on typescript 7 // to be sure that a validation has occured before (isParsableDsn or assertParsableDsn) 8} 9 10fnWithWeakOpaqueType('redis://localhost'); // ❌ typescript will complain 11 12const dsn = 'redis://localhost'; 13assertParsableDsn(dsn); 14fnWithWeakOpaqueType(dsn); // ✅ working cause it was checked before 15
PS: WeakOpaque usage is totally optional, a nice to have if applicable
Utility to convert jdbc dsn. Useful for prisma using sqlserver.
1import { convertJdbcToDsn } from "@httpx/dsn-parser"; 2 3const jdbcDsn = 4 "sqlserver://localhost:1433;database=my-db;authentication=default;user=sa;password=pass03$;encrypt=true;trustServerCertificate=true"; 5 6const dsn = convertJdbcToDsn(jdbc); 7 8// -> 'sqlserver://localhost:1433?database=my-db&authentication=default&user=sa&password=pass03$&encrypt=true&trustServerCertificate=true'
The minimum requirement for dsn parsing is to have a host and
a driver (/[a-z0-9]+/i)
defined. All other options are optional.
1export type ParsedDsn = { 2 driver: string; 3 host: string; 4 user?: string; 5 pass?: string; 6 port?: number; 7 db?: string; 8 /** Query params */ 9 params?: Record<string, number | string | boolean>; 10};
Things like:
1const validExamples = [ 2 "postgresql://postgres:@localhost:5432/prisma-db", 3 "redis://us_er-name:P@ass-_:?/ssw/rd@www.example.com:6379/0?cache=true", 4 //... 5];
should work.
Simple query parameters are supported (no arrays, no nested). For convenience
it will cast 'true'
and 'false'
to booleans,
parse numeric string to numbers if possible. When a query
parameter does not contain a value, it will be returned as true
.
1const dsn = "redis://host?index=1&compress=false&ssl"; 2const parsed = parseDsn(dsn); 3assert.deepEqual(parsed.value.params, { 4 index: 1, 5 compress: false, 6 ssl: true, 7});
parseDsn
won't make any assumptions on default values (i.e: default port for mysql...).
parseDsn
wraps its result in a discriminated union
to allow the retrieval of validation errors. No try... catch
needed and full typescript support.
Reason codes are guaranteed in semantic versions and messages does not leak credentials
1const parsed = parseDsn("redis://localhost:65636"); 2assert.deepEqual(parsed, { 3 success: false, 4 reason: "INVALID_PORT", 5 message: "Invalid port: 65636", 6}); 7if (!parsed.success) { 8 // `success: false` narrows the type to 9 // { 10 // reason: 'PARSE_ERROR'|'INVALID_ARGUMENT'|... 11 // message: string 12 // } 13 log(parsed.reason); 14}
Reason | Message | Comment |
---|---|---|
'PARSE_ERROR' | Cannot parse DSN | Regexp failed |
'INVALID_ARGUMENT' | DSN must be a string | |
'EMPTY_DSN' | DSN cannot be empty | |
'INVALID_PORT' | Invalid port: ${port} | [1-65535] |
The isParsableDsn
can be easily plugged into zod custom validation. Example:
1import { z } from "zod"; 2import { isParsableDsn, type ParsableDsn } from "@httpx/dsn-parser"; 3 4export const serverEnvSchema = z.object({ 5 PRISMA_DATABASE_URL: z.custom<ParsableDsn>( 6 (dsn) => isParsableDsn(dsn), 7 "Invalid DSN format." 8 ), 9}); 10 11serverEnvSchema.parse(process.env);
Some libs (ioredis...) still might fail parsing a password containing '/', unfortunately they're pretty convenient, i.e:
1openssl rand 60 | openssl base64 -A 2 3# YFUXIG9INIK7dFyE9aXtxLmjmnYL0zv6YluBJJbC6alKIBema/MwEGy3VUpx0oLAvWHUFGFMagAdLxrB
Bundle size is tracked by a size-limit configuration
Scenario (esm) | Size (compressed) |
---|---|
import { parseDsn } from '@httpx/dsn-parser | ~ 750B |
Level | CI | Description |
---|---|---|
Node | ✅ | CI for 20.x, 22.x & 24.x. |
Browser | ✅ | Tested with latest chrome (vitest/playwright) |
Browserslist | ✅ | > 95% on 01/2025. defaults, chrome >= 96, firefox >= 105, edge >= 113, safari >= 15, ios >= 15, opera >= 103, not dead |
Edge | ✅ | Ensured on CI with @vercel/edge-runtime. |
Cloudflare | ✅ | Ensured with @cloudflare/vitest-pool-workers (see wrangler.toml |
Typescript | ✅ | TS 5.0 + / are-the-type-wrong checks on CI. |
ES2022 | ✅ | Dist files checked with es-check |
For older browsers: most frontend frameworks can transpile the library (ie: nextjs...)
Contributions are warmly appreciated. Have a look to the CONTRIBUTING document.
If my OSS work brightens your day, let's take it to new heights together! Sponsor, coffee, or star – any gesture of support fuels my passion to improve. Thanks for being awesome! 🙏❤️
![]() |
|
JetBrains | Embie.be |
MIT © belgattitude and contributors.
No vulnerabilities found.
No security vulnerabilities found.