From 9296acb5ef2bac1962a958080c6b01f7fd77c7da Mon Sep 17 00:00:00 2001 From: "Usman S." Date: Thu, 21 Aug 2025 15:08:53 +0000 Subject: [PATCH 1/5] =?UTF-8?q?=E2=9C=A8=20Add=20arktype=20dependency=20an?= =?UTF-8?q?d=20implement=20ID=20validation=20schema=20with=20comprehensive?= =?UTF-8?q?=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bun.lock | 9 +++ package.json | 5 ++ src/validators/arktype.ts | 12 ++++ tests/validators/arktype.test.ts | 106 +++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+) create mode 100644 src/validators/arktype.ts create mode 100644 tests/validators/arktype.test.ts diff --git a/bun.lock b/bun.lock index ba4a5cc..84cd44d 100644 --- a/bun.lock +++ b/bun.lock @@ -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/schema@0.46.0", "", { "dependencies": { "@ark/util": "0.46.0" } }, "sha512-c2UQdKgP2eqqDArfBqQIJppxJHvNNXuQPeuSPlDML4rjw+f1cu0qAlzOG4b8ujgm9ctIDWwhpyw6gjG5ledIVQ=="], + + "@ark/util": ["@ark/util@0.46.0", "", {}, "sha512-JPy/NGWn/lvf1WmGCPw2VGpBg5utZraE84I7wli18EDF3p3zc/e9WolT35tINeZO3l7C77SjqRJeAUoT0CvMRg=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.9", "", { "os": "aix", "cpu": "ppc64" }, "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA=="], "@esbuild/android-arm": ["@esbuild/android-arm@0.25.9", "", { "os": "android", "cpu": "arm" }, "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ=="], @@ -169,6 +176,8 @@ "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], + "arktype": ["arktype@2.1.20", "", { "dependencies": { "@ark/schema": "0.46.0", "@ark/util": "0.46.0" } }, "sha512-IZCEEXaJ8g+Ijd59WtSYwtjnqXiwM8sWQ5EjGamcto7+HVN9eK0C4p0zDlCuAwWhpqr6fIBkxPuYDl4/Mcj/+Q=="], + "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="], "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], diff --git a/package.json b/package.json index 9c67f9a..d04f839 100644 --- a/package.json +++ b/package.json @@ -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" @@ -79,6 +81,9 @@ "nanoid": "^5.1.5" }, "peerDependenciesMeta": { + "arktype": { + "optional": true + }, "valibot": { "optional": true }, diff --git a/src/validators/arktype.ts b/src/validators/arktype.ts new file mode 100644 index 0000000..8f3ac68 --- /dev/null +++ b/src/validators/arktype.ts @@ -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) { + const { regex } = idHelper; + + return type>>>(regex); +} diff --git a/tests/validators/arktype.test.ts b/tests/validators/arktype.test.ts new file mode 100644 index 0000000..afc1db2 --- /dev/null +++ b/tests/validators/arktype.test.ts @@ -0,0 +1,106 @@ +import { describe, it, expect } from "vitest"; +import { IdHelper } from "../../src"; +import { createArktypeIdSchema } from "../../src/validators/arktype"; +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); + }); +}); From b5bf177be15d9f838fb4489f54973a19d370fd79 Mon Sep 17 00:00:00 2001 From: "Usman S." Date: Thu, 21 Aug 2025 15:10:27 +0000 Subject: [PATCH 2/5] =?UTF-8?q?=E2=9C=A8=20Update=20index.ts=20to=20export?= =?UTF-8?q?=20arktype=20module,=20and=20adjust=20test=20imports=20accordin?= =?UTF-8?q?gly?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/validators/index.ts | 1 + tests/validators/arktype.test.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/validators/index.ts b/src/validators/index.ts index e930ef6..5ce70a5 100644 --- a/src/validators/index.ts +++ b/src/validators/index.ts @@ -1,2 +1,3 @@ +export * from "./arktype"; export * from "./validbot"; export * from "./zod"; diff --git a/tests/validators/arktype.test.ts b/tests/validators/arktype.test.ts index afc1db2..d1b2d06 100644 --- a/tests/validators/arktype.test.ts +++ b/tests/validators/arktype.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect } from "vitest"; import { IdHelper } from "../../src"; -import { createArktypeIdSchema } from "../../src/validators/arktype"; +import { createArktypeIdSchema } from "../../src/validators"; import { ArkErrors } from "arktype"; describe("Arktype ID Validator", () => { From e61114bb779cf489d2fb650e7230539be60c3718 Mon Sep 17 00:00:00 2001 From: "Usman S." Date: Thu, 21 Aug 2025 15:18:22 +0000 Subject: [PATCH 3/5] =?UTF-8?q?=E2=9C=A8=20Enhance=20README.md=20to=20incl?= =?UTF-8?q?ude=20ArkType=20integration=20and=20update=20validation=20secti?= =?UTF-8?q?ons=20for=20clarity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 117 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 101 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 0a82352..d9565b2 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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 @@ -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: @@ -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: @@ -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: "john@example.com", +}); + +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 | @@ -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: From 331a485ad6afbca8f1876f8e269ca95f52358848 Mon Sep 17 00:00:00 2001 From: "Usman S." Date: Thu, 21 Aug 2025 15:20:26 +0000 Subject: [PATCH 4/5] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Rename=20Arktype=20to?= =?UTF-8?q?=20ArkType?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +++++----- src/validators/arktype.ts | 2 +- tests/validators/arktype.test.ts | 14 +++++++------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index d9565b2..291ec12 100644 --- a/README.md +++ b/README.md @@ -185,11 +185,11 @@ If you're using ArkType for validation, typed-id provides built-in schema creato ```typescript import { IdHelper } from "typed-id"; -import { createArktypeIdSchema } from "typed-id/validators/arktype"; +import { createArkTypeIdSchema } from "typed-id/validators/arktype"; import { ArkErrors } from "arktype"; const userIdHelper = new IdHelper("user"); -const userIdSchema = createArktypeIdSchema(userIdHelper); +const userIdSchema = createArkTypeIdSchema(userIdHelper); // Validate IDs const validId = userIdHelper.generate(); @@ -226,7 +226,7 @@ if (result instanceof ArkErrors) { ```typescript import { IdHelper } from "typed-id"; -import { createArktypeIdSchema } from "typed-id/validators/arktype"; +import { createArkTypeIdSchema } from "typed-id/validators/arktype"; // Different ID helpers with custom configurations const orderIdHelper = new IdHelper("order", { @@ -242,8 +242,8 @@ const sessionIdHelper = new IdHelper("session", { }); // Create corresponding schemas -const orderIdSchema = createArktypeIdSchema(orderIdHelper); -const sessionIdSchema = createArktypeIdSchema(sessionIdHelper); +const orderIdSchema = createArkTypeIdSchema(orderIdHelper); +const sessionIdSchema = createArkTypeIdSchema(sessionIdHelper); // Validate different ID formats const orderId = orderIdHelper.generate(); // "order::ABC123DEF456" diff --git a/src/validators/arktype.ts b/src/validators/arktype.ts index 8f3ac68..79483bd 100644 --- a/src/validators/arktype.ts +++ b/src/validators/arktype.ts @@ -2,7 +2,7 @@ import { IdHelper } from "../id-helper"; import { Type, type } from "arktype"; import type { GeneratedId, SeparatorOrDefault } from "../types"; -export function createArktypeIdSchema< +export function createArkTypeIdSchema< P extends string, S extends string | undefined = undefined >(idHelper: IdHelper) { diff --git a/tests/validators/arktype.test.ts b/tests/validators/arktype.test.ts index d1b2d06..7895a36 100644 --- a/tests/validators/arktype.test.ts +++ b/tests/validators/arktype.test.ts @@ -1,15 +1,15 @@ import { describe, it, expect } from "vitest"; import { IdHelper } from "../../src"; -import { createArktypeIdSchema } from "../../src/validators"; +import { createArkTypeIdSchema } from "../../src/validators"; import { ArkErrors } from "arktype"; -describe("Arktype ID Validator", () => { +describe("ArkType ID Validator", () => { it("should validate ID with default options", () => { const userIdHelper = new IdHelper("user"); const id = userIdHelper.generate(); - const IdSchema = createArktypeIdSchema(userIdHelper); + const IdSchema = createArkTypeIdSchema(userIdHelper); // Test that the schema validates the generated ID expect(IdSchema(id)).toBe(id); @@ -33,7 +33,7 @@ describe("Arktype ID Validator", () => { const id = userIdHelper.generate(); - const IdSchema = createArktypeIdSchema(userIdHelper); + const IdSchema = createArkTypeIdSchema(userIdHelper); // Test that the schema validates the generated ID expect(IdSchema(id)).toBe(id); @@ -56,7 +56,7 @@ describe("Arktype ID Validator", () => { const id = userIdHelper.generate(); - const IdSchema = createArktypeIdSchema(userIdHelper); + const IdSchema = createArkTypeIdSchema(userIdHelper); // Test that the schema validates the generated ID expect(IdSchema(id)).toBe(id); @@ -73,7 +73,7 @@ describe("Arktype ID Validator", () => { const id = userIdHelper.generate(); - const IdSchema = createArktypeIdSchema(userIdHelper); + const IdSchema = createArkTypeIdSchema(userIdHelper); // Test that the schema validates the generated ID expect(IdSchema(id)).toBe(id); @@ -92,7 +92,7 @@ describe("Arktype ID Validator", () => { const id = userIdHelper.generate(); - const IdSchema = createArktypeIdSchema(userIdHelper); + const IdSchema = createArkTypeIdSchema(userIdHelper); // Test that the schema validates the generated ID expect(IdSchema(id)).toBe(id); From fb8544fe621d3452ab3d8a734d862c63de5e0cf8 Mon Sep 17 00:00:00 2001 From: "Usman S." Date: Thu, 21 Aug 2025 17:29:08 +0000 Subject: [PATCH 5/5] import type separately --- src/validators/arktype.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/validators/arktype.ts b/src/validators/arktype.ts index 79483bd..23931fa 100644 --- a/src/validators/arktype.ts +++ b/src/validators/arktype.ts @@ -1,6 +1,7 @@ import { IdHelper } from "../id-helper"; -import { Type, type } from "arktype"; +import { type } from "arktype"; import type { GeneratedId, SeparatorOrDefault } from "../types"; +import type { Type } from "arktype"; export function createArkTypeIdSchema< P extends string,