Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 101 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ A lightweight, type-safe TypeScript library for generating prefixed IDs with cus
- 📦 **Lightweight** - Minimal dependencies (only `nanoid`)
- 🔍 **Zod Integration** - Built-in Zod validation schemas (optional)
- ✅ **Valibot Integration** - Built-in Valibot validation schemas (optional)
- 🏛️ **ArkType Integration** - Built-in ArkType validation schemas (optional)
- 🧪 **Well Tested** - Comprehensive test coverage
- 📚 **Modern ESM** - ES modules with CommonJS support

Expand All @@ -27,20 +28,6 @@ pnpm add typed-id
bun add typed-id
```

### Optional Dependencies

For Zod validation support:

```bash
npm install zod
```

For Valibot validation support:

```bash
npm install valibot
```

## 📖 Usage

### Basic Usage
Expand Down Expand Up @@ -117,7 +104,17 @@ const orderId = orderIdHelper.generate();
// processUser(orderId); // ❌ Type error: Argument of type 'OrderId' is not assignable to parameter of type 'UserId'
```

## 🔍 Zod Integration
## 🔧 Integrations

Typed-id provides seamless integration with popular TypeScript validation libraries. Choose the one that fits your project's needs.

### 🔍 Zod Integration

First, install Zod if you haven't already:

```bash
npm install zod
```

If you're using Zod for validation, typed-id provides built-in schema creators:

Expand All @@ -143,7 +140,13 @@ const userSchema = z.object({
});
```

## ✅ Valibot Integration
### ✅ Valibot Integration

First, install Valibot if you haven't already:

```bash
npm install valibot
```

If you're using Valibot for validation, typed-id provides built-in schema creators:

Expand All @@ -170,6 +173,87 @@ const userSchema = object({
});
```

### 🏛️ ArkType Integration

First, install ArkType if you haven't already:

```bash
npm install arktype
```

If you're using ArkType for validation, typed-id provides built-in schema creators:

```typescript
import { IdHelper } from "typed-id";
import { createArkTypeIdSchema } from "typed-id/validators/arktype";
import { ArkErrors } from "arktype";

const userIdHelper = new IdHelper("user");
const userIdSchema = createArkTypeIdSchema(userIdHelper);

// Validate IDs
const validId = userIdHelper.generate();
const validResult = userIdSchema(validId);
console.log(validResult); // Returns the actual ID string if valid

const invalidResult = userIdSchema("invalid_id");
console.log(invalidResult instanceof ArkErrors); // true if invalid

// Use in your ArkType schemas
import { type } from "arktype";

const userSchema = type({
id: userIdSchema,
name: "string",
email: "string.email",
});

// Type-safe validation
const result = userSchema({
id: userIdHelper.generate(),
name: "John Doe",
email: "[email protected]",
});

if (result instanceof ArkErrors) {
console.log("Validation failed:", result.summary);
} else {
console.log("Valid user:", result); // Fully typed user object
}
```

#### Custom Validation Examples

```typescript
import { IdHelper } from "typed-id";
import { createArkTypeIdSchema } from "typed-id/validators/arktype";

// Different ID helpers with custom configurations
const orderIdHelper = new IdHelper("order", {
separator: "::",
length: 12,
customAlphabets: "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
});

const sessionIdHelper = new IdHelper("session", {
separator: "_",
length: 16,
customAlphabets: "0123456789abcdef", // Hex only
});

// Create corresponding schemas
const orderIdSchema = createArkTypeIdSchema(orderIdHelper);
const sessionIdSchema = createArkTypeIdSchema(sessionIdHelper);

// Validate different ID formats
const orderId = orderIdHelper.generate(); // "order::ABC123DEF456"
const sessionId = sessionIdHelper.generate(); // "session_a1b2c3d4e5f6789a"

console.log(orderIdSchema(orderId)); // Valid: returns the ID
console.log(sessionIdSchema(sessionId)); // Valid: returns the ID
console.log(orderIdSchema(sessionId) instanceof ArkErrors); // true - wrong format
```

## ⚙️ Configuration Options

| Option | Type | Default | Description |
Expand Down Expand Up @@ -300,6 +384,7 @@ This library has comprehensive test coverage including:
- ID generation with custom options
- Zod validation schemas
- Valibot validation schemas
- ArkType validation schemas
- Type safety verification

Run tests:
Expand Down
9 changes: 9 additions & 0 deletions bun.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,30 @@
"@types/bun": "latest",
"@types/node": "^24.3.0",
"@vitest/ui": "^3.2.4",
"arktype": "^2.1.20",
"tsup": "^8.5.0",
"valibot": "^1.1.0",
"vitest": "^3.2.4",
"zod": "^4.0.17",
},
"peerDependencies": {
"arktype": "^2.1.20",
"typescript": "^5",
"valibot": "^1.1.0",
"zod": "^4.0.17",
},
"optionalPeers": [
"arktype",
"valibot",
"zod",
],
},
},
"packages": {
"@ark/schema": ["@ark/[email protected]", "", { "dependencies": { "@ark/util": "0.46.0" } }, "sha512-c2UQdKgP2eqqDArfBqQIJppxJHvNNXuQPeuSPlDML4rjw+f1cu0qAlzOG4b8ujgm9ctIDWwhpyw6gjG5ledIVQ=="],

"@ark/util": ["@ark/[email protected]", "", {}, "sha512-JPy/NGWn/lvf1WmGCPw2VGpBg5utZraE84I7wli18EDF3p3zc/e9WolT35tINeZO3l7C77SjqRJeAUoT0CvMRg=="],

"@esbuild/aix-ppc64": ["@esbuild/[email protected]", "", { "os": "aix", "cpu": "ppc64" }, "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA=="],

"@esbuild/android-arm": ["@esbuild/[email protected]", "", { "os": "android", "cpu": "arm" }, "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ=="],
Expand Down Expand Up @@ -169,6 +176,8 @@

"any-promise": ["[email protected]", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="],

"arktype": ["[email protected]", "", { "dependencies": { "@ark/schema": "0.46.0", "@ark/util": "0.46.0" } }, "sha512-IZCEEXaJ8g+Ijd59WtSYwtjnqXiwM8sWQ5EjGamcto7+HVN9eK0C4p0zDlCuAwWhpqr6fIBkxPuYDl4/Mcj/+Q=="],

"assertion-error": ["[email protected]", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="],

"balanced-match": ["[email protected]", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,14 @@
"@types/bun": "latest",
"@types/node": "^24.3.0",
"@vitest/ui": "^3.2.4",
"arktype": "^2.1.20",
"tsup": "^8.5.0",
"valibot": "^1.1.0",
"vitest": "^3.2.4",
"zod": "^4.0.17"
},
"peerDependencies": {
"arktype": "^2.1.20",
"typescript": "^5",
"valibot": "^1.1.0",
"zod": "^4.0.17"
Expand All @@ -79,6 +81,9 @@
"nanoid": "^5.1.5"
},
"peerDependenciesMeta": {
"arktype": {
"optional": true
},
"valibot": {
"optional": true
},
Expand Down
12 changes: 12 additions & 0 deletions src/validators/arktype.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { IdHelper } from "../id-helper";
import { Type, type } from "arktype";
import type { GeneratedId, SeparatorOrDefault } from "../types";

export function createArkTypeIdSchema<
P extends string,
S extends string | undefined = undefined
>(idHelper: IdHelper<P, S>) {
const { regex } = idHelper;

return type<RegExp, Type<GeneratedId<P, SeparatorOrDefault<S>>>>(regex);
}
1 change: 1 addition & 0 deletions src/validators/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./arktype";
export * from "./validbot";
export * from "./zod";
106 changes: 106 additions & 0 deletions tests/validators/arktype.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { describe, it, expect } from "vitest";
import { IdHelper } from "../../src";
import { createArkTypeIdSchema } from "../../src/validators";
import { ArkErrors } from "arktype";

describe("ArkType ID Validator", () => {
it("should validate ID with default options", () => {
const userIdHelper = new IdHelper("user");

const id = userIdHelper.generate();

const IdSchema = createArkTypeIdSchema(userIdHelper);

// Test that the schema validates the generated ID
expect(IdSchema(id)).toBe(id);

// Test that the schema rejects IDs with different prefix
expect(IdSchema("person_0123456789")).toBeInstanceOf(ArkErrors);

// Test that the schema rejects IDs with different separator
expect(IdSchema("user::0123456789")).toBeInstanceOf(ArkErrors);

// Test that the schema rejects IDs with different length
expect(IdSchema("user_1234")).toBeInstanceOf(ArkErrors);
});

it("should validate ID with custom options", () => {
const userIdHelper = new IdHelper("user", {
separator: "::",
length: 12,
customAlphabets: "abcdefghijklmnopqrstuvwxyz",
});

const id = userIdHelper.generate();

const IdSchema = createArkTypeIdSchema(userIdHelper);

// Test that the schema validates the generated ID
expect(IdSchema(id)).toBe(id);

// Test that the schema rejects IDs with different prefix
expect(IdSchema("person::abcdefghijkl")).toBeInstanceOf(ArkErrors);

// Test that the schema rejects IDs with different separator
expect(IdSchema("user_abcdefghijkl")).toBeInstanceOf(ArkErrors);

// Test that the schema rejects IDs with different length
expect(IdSchema("user::abcdefghijk")).toBeInstanceOf(ArkErrors);

// Test that the schema rejects IDs with different alphabets
expect(IdSchema("user::0123456789123")).toBeInstanceOf(ArkErrors);
});

it("should validate ID with custom separator", () => {
const userIdHelper = new IdHelper("user", { separator: "::" });

const id = userIdHelper.generate();

const IdSchema = createArkTypeIdSchema(userIdHelper);

// Test that the schema validates the generated ID
expect(IdSchema(id)).toBe(id);

// Test that the schema rejects IDs with different prefix
expect(IdSchema("person::0123456789")).toBeInstanceOf(ArkErrors);

// Test that the schema rejects IDs with different separator
expect(IdSchema("user_0123456789")).toBeInstanceOf(ArkErrors);
});

it("should validate ID with custom length", () => {
const userIdHelper = new IdHelper("user", { length: 12 });

const id = userIdHelper.generate();

const IdSchema = createArkTypeIdSchema(userIdHelper);

// Test that the schema validates the generated ID
expect(IdSchema(id)).toBe(id);

// Test that the schema rejects IDs with different prefix
expect(IdSchema("person_0123456789")).toBeInstanceOf(ArkErrors);

// Test that the schema rejects IDs with different length
expect(IdSchema("user_0123456789")).toBeInstanceOf(ArkErrors);
});

it("should validate ID with custom alphabets", () => {
const userIdHelper = new IdHelper("user", {
customAlphabets: "abcdefghijklmnopqrstuvwxyz",
});

const id = userIdHelper.generate();

const IdSchema = createArkTypeIdSchema(userIdHelper);

// Test that the schema validates the generated ID
expect(IdSchema(id)).toBe(id);

// Test that the schema rejects IDs with different prefix
expect(IdSchema("person_0123456789")).toBeInstanceOf(ArkErrors);

// Test that the schema rejects IDs with different alphabets
expect(IdSchema("user_0123456789123")).toBeInstanceOf(ArkErrors);
});
});