diff --git a/.gitignore b/.gitignore
index 610f8a0..66ae94f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
dist
node_modules
coverage
+.next
# Logs
logs
diff --git a/docs/content/docs/api.mdx b/docs/content/docs/api.mdx
new file mode 100644
index 0000000..b016324
--- /dev/null
+++ b/docs/content/docs/api.mdx
@@ -0,0 +1,322 @@
+---
+title: Defining schemas
+description: Learn how to create and use schemas with dynz
+---
+
+import { Tabs, Tab } from 'fumadocs-ui/components/tabs';
+import { Callout } from 'fumadocs-ui/components/callout';
+
+# Defining Schemas
+
+To validate data, you must first define a schema. Schemas represent types, from simple primitive values to complex nested objects and arrays.
+
+# Primitives
+```typescript
+
+import { string, number, object, validate, equals, lt, min, max } from 'dynz'
+
+// Primitive types
+string()
+number()
+boolean()
+dateString()
+
+```
+
+{/* STRING: "string",
+ DATE: "date",
+ DATE_STRING: "date_string",
+ NUMBER: "number",
+ OBJECT: "object",
+ ARRAY: "array",
+ OPTIONS: "options",
+ BOOLEAN: "boolean",
+ FILE: "file", */}
+
+
+```typescript
+import { string, number, object, validate, equals, lt, min, max } from 'dynz'
+
+// Define a schema
+const schema = object({
+ fields: {
+ name: string({
+ rules: [min(2)]
+ }),
+ age: number({
+ rules: [min(0), max(120)]
+ }),
+ parentalApproval: boolean({
+ rules: [equals(true)],
+ // `parentalApproval` field is only included when age is under 18
+ included: lt('age', 18)
+ })
+ }
+})
+
+// Validate data
+const result = validate(userSchema, {
+ name: "John Doe",
+ age: 16,
+ parentalApproval: false
+})
+
+if (result.success) {
+ console.log("Valid data:", result.data)
+} else {
+ console.log("Validation errors:", result.errors)
+}
+```
+
+## Installation
+
+
+
+ ```bash
+ pnpm add dynz
+ ```
+
+
+ ```bash
+ npm install dynz
+ ```
+
+
+ ```bash
+ yarn add dynz
+ ```
+
+
+
+## Basic Usage
+
+### Creating Your First Schema
+
+Start by importing the schema builders and validation function:
+
+```typescript
+import { string, number, object, validate } from 'dynz'
+
+// Define a schema
+const userSchema = object({
+ fields: {
+ name: string(),
+ age: number({
+ rules: [min(0), max(120)]
+ }),
+ parentalApproval: boolean({
+ rules: [equals(true)],
+ // field is only included when age is under 18
+ included: lt('age', 18)
+ })
+ }
+})
+
+// Some data
+const data = { .... }
+
+// Validate data
+const result = validate(userSchema, undefined, data)
+
+if (result.success) {
+ console.log("Valid data:", result.data)
+} else {
+ console.log("Validation errors:", result.errors)
+}
+```
+
+### Schema Types
+
+dynz supports several built-in schema types:
+
+#### String Schema
+
+```typescript
+import { string } from 'dynz'
+
+const nameSchema = string()
+ .min(2, "Name must be at least 2 characters")
+ .max(50, "Name must not exceed 50 characters")
+ .regex(/^[a-zA-Z\s]+$/, "Name can only contain letters and spaces")
+
+const emailSchema = string()
+ .email("Please enter a valid email address")
+```
+
+#### Number Schema
+
+```typescript
+import { number } from 'dynz'
+
+const ageSchema = number()
+ .min(0, "Age must be positive")
+ .max(120, "Age must be realistic")
+
+const priceSchema = number()
+ .positive("Price must be positive")
+```
+
+#### Object Schema
+
+```typescript
+import { object, string, number } from 'dynz'
+
+const productSchema = object({
+ name: string().min(1),
+ price: number().positive(),
+ description: string().optional()
+})
+```
+
+#### Array Schema
+
+```typescript
+import { array, string } from 'dynz'
+
+const tagsSchema = array(string().min(1))
+ .min(1, "At least one tag is required")
+ .max(5, "Maximum 5 tags allowed")
+```
+
+### Conditional Validation
+
+dynz excels at dynamic, conditional validation based on other field values:
+
+```typescript
+import { object, string, conditions } from 'dynz'
+
+const userSchema = object({
+ accountType: string().oneOf(['personal', 'business']),
+
+ // Only required if accountType is 'business'
+ companyName: string()
+ .requiredIf(conditions.equals('accountType', 'business'))
+ .min(2),
+
+ // Different validation rules based on account type
+ email: string()
+ .email()
+ .ruleIf(
+ conditions.equals('accountType', 'business'),
+ string().regex(/@company\.com$/, "Business accounts must use company email")
+ )
+})
+```
+
+### Framework Integration
+
+#### Vue.js with VeeValidate
+
+
+ Install the VeeValidate integration: `pnpm add @dynz/veevalidate`
+
+
+```typescript
+import { useForm } from 'vee-validate'
+import { toDynzValidator } from '@dynz/veevalidate'
+import { object, string } from 'dynz'
+
+const schema = object({
+ username: string().min(3),
+ password: string().min(8)
+})
+
+const { defineField, handleSubmit, errors } = useForm({
+ validationSchema: toDynzValidator(schema)
+})
+
+const [username, usernameAttrs] = defineField('username')
+const [password, passwordAttrs] = defineField('password')
+```
+
+#### React (with custom hook)
+
+```typescript
+import { useState } from 'react'
+import { validate } from 'dynz'
+
+function useFormValidation(schema) {
+ const [errors, setErrors] = useState({})
+
+ const validateField = (name, value, allValues) => {
+ const result = validate(schema, { ...allValues, [name]: value })
+ if (!result.success) {
+ setErrors(prev => ({
+ ...prev,
+ [name]: result.errors[name]?.[0]
+ }))
+ } else {
+ setErrors(prev => {
+ const newErrors = { ...prev }
+ delete newErrors[name]
+ return newErrors
+ })
+ }
+ }
+
+ return { errors, validateField }
+}
+```
+
+## Advanced Features
+
+### Private Field Masking
+
+Mark sensitive fields as private to automatically mask them in validation results:
+
+```typescript
+import { object, string } from 'dynz'
+
+const userSchema = object({
+ username: string(),
+ password: string().private(), // Will be masked in results
+ confirmPassword: string().private()
+})
+```
+
+### Cross-Field Validation
+
+Reference other fields in your validation rules:
+
+```typescript
+import { object, string, conditions } from 'dynz'
+
+const signupSchema = object({
+ password: string().min(8),
+ confirmPassword: string()
+ .equals(conditions.ref('password'), "Passwords must match")
+})
+```
+
+### Custom Rules
+
+Create your own validation rules:
+
+```typescript
+import { string, customRule } from 'dynz'
+
+const strongPasswordRule = customRule((value) => {
+ const hasUppercase = /[A-Z]/.test(value)
+ const hasLowercase = /[a-z]/.test(value)
+ const hasNumbers = /\d/.test(value)
+ const hasSpecialChar = /[!@#$%^&*]/.test(value)
+
+ return hasUppercase && hasLowercase && hasNumbers && hasSpecialChar
+}, "Password must contain uppercase, lowercase, numbers, and special characters")
+
+const passwordSchema = string()
+ .min(8)
+ .custom(strongPasswordRule)
+```
+
+## Next Steps
+
+Now that you understand the basics, explore more advanced topics:
+
+- **[API Reference](/docs/api)** - Complete API documentation
+- **[Examples](/docs/examples)** - Real-world usage examples
+- **[Framework Integrations](/docs/integrations)** - Vue, React, and other framework guides
+
+
+ Check out the [examples directory](https://github.com/your-username/dynz/tree/main/examples) in the repository for complete working examples with Vue.js and Next.js.
+
\ No newline at end of file
diff --git a/docs/content/docs/dynamic.mdx b/docs/content/docs/dynamic.mdx
new file mode 100644
index 0000000..1ca0782
--- /dev/null
+++ b/docs/content/docs/dynamic.mdx
@@ -0,0 +1,328 @@
+---
+title: Dynamic Schemas
+description: Learn how to create and use schemas with dynz
+---
+
+import { Tabs, Tab } from 'fumadocs-ui/components/tabs';
+import { Callout } from 'fumadocs-ui/components/callout';
+
+# Dynamic Schemas
+
+Dynamic schema explanation here
+
+# Primitives
+```typescript
+
+import { string, number, object, validate, equals, lt, min, max } from 'dynz'
+
+// Dynamically include fields based on other field values
+const schema = object({
+ fields: {
+ age: number({
+ rules: [min(0), max(120)]
+ }),
+ parentalApproval: boolean({
+ rules: [equals(true)],
+ // `parentalApproval` field is only included when age is under 18
+ included: lt('age', 18)
+ })
+}
+```
+
+{/* STRING: "string",
+ DATE: "date",
+ DATE_STRING: "date_string",
+ NUMBER: "number",
+ OBJECT: "object",
+ ARRAY: "array",
+ OPTIONS: "options",
+ BOOLEAN: "boolean",
+ FILE: "file", */}
+
+
+```typescript
+import { string, number, object, validate, equals, lt, min, max } from 'dynz'
+
+// Define a schema
+const schema = object({
+ fields: {
+ name: string({
+ rules: [min(2)]
+ }),
+ age: number({
+ rules: [min(0), max(120)]
+ }),
+ parentalApproval: boolean({
+ rules: [equals(true)],
+ // `parentalApproval` field is only included when age is under 18
+ included: lt('age', 18)
+ })
+ }
+})
+
+// Validate data
+const result = validate(userSchema, {
+ name: "John Doe",
+ age: 16,
+ parentalApproval: false
+})
+
+if (result.success) {
+ console.log("Valid data:", result.data)
+} else {
+ console.log("Validation errors:", result.errors)
+}
+```
+
+## Installation
+
+
+
+ ```bash
+ pnpm add dynz
+ ```
+
+
+ ```bash
+ npm install dynz
+ ```
+
+
+ ```bash
+ yarn add dynz
+ ```
+
+
+
+## Basic Usage
+
+### Creating Your First Schema
+
+Start by importing the schema builders and validation function:
+
+```typescript
+import { string, number, object, validate } from 'dynz'
+
+// Define a schema
+const userSchema = object({
+ fields: {
+ name: string(),
+ age: number({
+ rules: [min(0), max(120)]
+ }),
+ parentalApproval: boolean({
+ rules: [equals(true)],
+ // field is only included when age is under 18
+ included: lt('age', 18)
+ })
+ }
+})
+
+// Some data
+const data = { .... }
+
+// Validate data
+const result = validate(userSchema, undefined, data)
+
+if (result.success) {
+ console.log("Valid data:", result.data)
+} else {
+ console.log("Validation errors:", result.errors)
+}
+```
+
+### Schema Types
+
+dynz supports several built-in schema types:
+
+#### String Schema
+
+```typescript
+import { string } from 'dynz'
+
+const nameSchema = string()
+ .min(2, "Name must be at least 2 characters")
+ .max(50, "Name must not exceed 50 characters")
+ .regex(/^[a-zA-Z\s]+$/, "Name can only contain letters and spaces")
+
+const emailSchema = string()
+ .email("Please enter a valid email address")
+```
+
+#### Number Schema
+
+```typescript
+import { number } from 'dynz'
+
+const ageSchema = number()
+ .min(0, "Age must be positive")
+ .max(120, "Age must be realistic")
+
+const priceSchema = number()
+ .positive("Price must be positive")
+```
+
+#### Object Schema
+
+```typescript
+import { object, string, number } from 'dynz'
+
+const productSchema = object({
+ name: string().min(1),
+ price: number().positive(),
+ description: string().optional()
+})
+```
+
+#### Array Schema
+
+```typescript
+import { array, string } from 'dynz'
+
+const tagsSchema = array(string().min(1))
+ .min(1, "At least one tag is required")
+ .max(5, "Maximum 5 tags allowed")
+```
+
+### Conditional Validation
+
+dynz excels at dynamic, conditional validation based on other field values:
+
+```typescript
+import { object, string, conditions } from 'dynz'
+
+const userSchema = object({
+ accountType: string().oneOf(['personal', 'business']),
+
+ // Only required if accountType is 'business'
+ companyName: string()
+ .requiredIf(conditions.equals('accountType', 'business'))
+ .min(2),
+
+ // Different validation rules based on account type
+ email: string()
+ .email()
+ .ruleIf(
+ conditions.equals('accountType', 'business'),
+ string().regex(/@company\.com$/, "Business accounts must use company email")
+ )
+})
+```
+
+### Framework Integration
+
+#### Vue.js with VeeValidate
+
+
+ Install the VeeValidate integration: `pnpm add @dynz/veevalidate`
+
+
+```typescript
+import { useForm } from 'vee-validate'
+import { toDynzValidator } from '@dynz/veevalidate'
+import { object, string } from 'dynz'
+
+const schema = object({
+ username: string().min(3),
+ password: string().min(8)
+})
+
+const { defineField, handleSubmit, errors } = useForm({
+ validationSchema: toDynzValidator(schema)
+})
+
+const [username, usernameAttrs] = defineField('username')
+const [password, passwordAttrs] = defineField('password')
+```
+
+#### React (with custom hook)
+
+```typescript
+import { useState } from 'react'
+import { validate } from 'dynz'
+
+function useFormValidation(schema) {
+ const [errors, setErrors] = useState({})
+
+ const validateField = (name, value, allValues) => {
+ const result = validate(schema, { ...allValues, [name]: value })
+ if (!result.success) {
+ setErrors(prev => ({
+ ...prev,
+ [name]: result.errors[name]?.[0]
+ }))
+ } else {
+ setErrors(prev => {
+ const newErrors = { ...prev }
+ delete newErrors[name]
+ return newErrors
+ })
+ }
+ }
+
+ return { errors, validateField }
+}
+```
+
+## Advanced Features
+
+### Private Field Masking
+
+Mark sensitive fields as private to automatically mask them in validation results:
+
+```typescript
+import { object, string } from 'dynz'
+
+const userSchema = object({
+ username: string(),
+ password: string().private(), // Will be masked in results
+ confirmPassword: string().private()
+})
+```
+
+### Cross-Field Validation
+
+Reference other fields in your validation rules:
+
+```typescript
+import { object, string, conditions } from 'dynz'
+
+const signupSchema = object({
+ password: string().min(8),
+ confirmPassword: string()
+ .equals(conditions.ref('password'), "Passwords must match")
+})
+```
+
+### Custom Rules
+
+Create your own validation rules:
+
+```typescript
+import { string, customRule } from 'dynz'
+
+const strongPasswordRule = customRule((value) => {
+ const hasUppercase = /[A-Z]/.test(value)
+ const hasLowercase = /[a-z]/.test(value)
+ const hasNumbers = /\d/.test(value)
+ const hasSpecialChar = /[!@#$%^&*]/.test(value)
+
+ return hasUppercase && hasLowercase && hasNumbers && hasSpecialChar
+}, "Password must contain uppercase, lowercase, numbers, and special characters")
+
+const passwordSchema = string()
+ .min(8)
+ .custom(strongPasswordRule)
+```
+
+## Next Steps
+
+Now that you understand the basics, explore more advanced topics:
+
+- **[API Reference](/docs/api)** - Complete API documentation
+- **[Examples](/docs/examples)** - Real-world usage examples
+- **[Framework Integrations](/docs/integrations)** - Vue, React, and other framework guides
+
+
+ Check out the [examples directory](https://github.com/your-username/dynz/tree/main/examples) in the repository for complete working examples with Vue.js and Next.js.
+
\ No newline at end of file
diff --git a/docs/content/docs/introduction.mdx b/docs/content/docs/introduction.mdx
index 03a73ef..38e8aa1 100644
--- a/docs/content/docs/introduction.mdx
+++ b/docs/content/docs/introduction.mdx
@@ -8,7 +8,7 @@ import { Callout } from 'fumadocs-ui/components/callout';
# Introduction
-dynz is a TypeScript schema validation that provides serializable type-safe validation with dynamic schemas. It is perfect for creating complex
+`dynz` is a TypeScript schema validator that provides serializable type-safe validation with dynamic schemas. It is perfect for creating complex
schemas that power your form logic.
```typescript
@@ -25,7 +25,7 @@ const schema = object({
}),
parentalApproval: boolean({
rules: [equals(true)],
- // field is only included when age is under 18
+ // `parentalApproval` field is only included when age is under 18
included: lt('age', 18)
})
}
diff --git a/docs/src/app/layout.tsx b/docs/src/app/layout.tsx
index 4e98c37..325d08e 100644
--- a/docs/src/app/layout.tsx
+++ b/docs/src/app/layout.tsx
@@ -1,14 +1,18 @@
import "@/app/global.css";
import { RootProvider } from "fumadocs-ui/provider";
-import { Inter } from "next/font/google";
+// import { Inter } from "next/font/google";
-const inter = Inter({
- subsets: ["latin"],
-});
+// const inter = Inter({
+// subsets: ["latin"],
+// });
export default function Layout({ children }: LayoutProps<"/">) {
return (
-
+
{children}
diff --git a/examples/example/src/index.ts b/examples/example/src/index.ts
index 1f5ef50..ac3269c 100644
--- a/examples/example/src/index.ts
+++ b/examples/example/src/index.ts
@@ -1,13 +1,20 @@
-import { conditional, email, eq, matches, min, object, options, regex, string } from "dynz";
+import { boolean, number, SchemaValues, string, tuple, validate } from "dynz";
+
+const foo = tuple({
+ schema: [
+ string(),
+ boolean(),
+ tuple({
+ schema: [string(), boolean()],
+ }),
+ ],
+});
-// const foo = object({
-// fields: {
-// password: string(),
-// confirmPassword: string({
-// rules: [equals(ref('password'))]
-// })
-// }
-// })
+const f = validate(foo, undefined, ["foo", true, 123]);
+
+if (f.success) {
+ const a = f.values[2][1];
+}
// const schema = object({
// fields: {
@@ -29,33 +36,33 @@ import { conditional, email, eq, matches, min, object, options, regex, string }
// console.log(result.values); // ✅ Type-safe access
// }
-const schema = object({
- fields: {
- accountType: options({
- options: ["personal", "business"],
- }),
+// const schema = object({
+// fields: {
+// accountType: options({
+// options: ["personal", "business"],
+// }),
- // Only included if accountType is 'business'
- companyName: string({
- rules: [min(2)],
- required: matches("email", "@gmail.com$"),
- included: eq("accountType", "business"),
- }),
+// // Only included if accountType is 'business'
+// companyName: string({
+// rules: [min(2)],
+// required: matches("email", "@gmail.com$"),
+// included: eq("accountType", "business"),
+// }),
- email: string({
- rules: [
- email(),
- conditional({
- // Different validation rules based on account type
- when: eq("accountType", "business"),
- then: regex("@company.com$", "Business accounts must use company email"),
- }),
- ],
- }),
- },
-});
+// email: string({
+// rules: [
+// email(),
+// conditional({
+// // Different validation rules based on account type
+// when: eq("accountType", "business"),
+// then: regex("@company.com$", "Business accounts must use company email"),
+// }),
+// ],
+// }),
+// },
+// });
-console.log(JSON.stringify(schema, undefined, 2));
+// console.log(JSON.stringify(schema, undefined, 2));
// // Validate data
// const result = validate(schema, undefined, {
diff --git a/examples/next-example/.next/trace b/examples/next-example/.next/trace
index 7867007..380f937 100644
--- a/examples/next-example/.next/trace
+++ b/examples/next-example/.next/trace
@@ -1 +1,2 @@
-[{"name":"generate-buildid","duration":95,"timestamp":2950126648760,"id":4,"parentId":1,"tags":{},"startTime":1757343220433,"traceId":"4b8621af667f44c3"},{"name":"load-custom-routes","duration":148,"timestamp":2950126648894,"id":5,"parentId":1,"tags":{},"startTime":1757343220433,"traceId":"4b8621af667f44c3"},{"name":"create-dist-dir","duration":111,"timestamp":2950126673772,"id":6,"parentId":1,"tags":{},"startTime":1757343220458,"traceId":"4b8621af667f44c3"},{"name":"create-pages-mapping","duration":90,"timestamp":2950126679210,"id":7,"parentId":1,"tags":{},"startTime":1757343220464,"traceId":"4b8621af667f44c3"},{"name":"collect-app-paths","duration":1103,"timestamp":2950126679315,"id":8,"parentId":1,"tags":{},"startTime":1757343220464,"traceId":"4b8621af667f44c3"},{"name":"create-app-mapping","duration":1239,"timestamp":2950126680435,"id":9,"parentId":1,"tags":{},"startTime":1757343220465,"traceId":"4b8621af667f44c3"},{"name":"public-dir-conflict-check","duration":185,"timestamp":2950126681859,"id":10,"parentId":1,"tags":{},"startTime":1757343220466,"traceId":"4b8621af667f44c3"},{"name":"generate-routes-manifest","duration":1005,"timestamp":2950126682140,"id":11,"parentId":1,"tags":{},"startTime":1757343220467,"traceId":"4b8621af667f44c3"},{"name":"create-entrypoints","duration":6932,"timestamp":2950126710668,"id":14,"parentId":1,"tags":{},"startTime":1757343220495,"traceId":"4b8621af667f44c3"},{"name":"generate-webpack-config","duration":147387,"timestamp":2950126717629,"id":15,"parentId":13,"tags":{},"startTime":1757343220502,"traceId":"4b8621af667f44c3"},{"name":"next-trace-entrypoint-plugin","duration":1082,"timestamp":2950126909255,"id":17,"parentId":16,"tags":{},"startTime":1757343220694,"traceId":"4b8621af667f44c3"},{"name":"add-entry","duration":119447,"timestamp":2950126913001,"id":21,"parentId":18,"tags":{"request":"next/dist/pages/_app"},"startTime":1757343220697,"traceId":"4b8621af667f44c3"},{"name":"add-entry","duration":151854,"timestamp":2950126913025,"id":25,"parentId":18,"tags":{"request":"next/dist/pages/_document"},"startTime":1757343220697,"traceId":"4b8621af667f44c3"},{"name":"add-entry","duration":171488,"timestamp":2950126913008,"id":22,"parentId":18,"tags":{"request":"next-route-loader?kind=PAGES&page=%2F_error&preferredRegion=&absolutePagePath=next%2Fdist%2Fpages%2F_error&absoluteAppPath=next%2Fdist%2Fpages%2F_app&absoluteDocumentPath=next%2Fdist%2Fpages%2F_document&middlewareConfigBase64=e30%3D!"},"startTime":1757343220697,"traceId":"4b8621af667f44c3"},{"name":"build-module-tsx","duration":10230,"timestamp":2950127093577,"id":26,"parentId":16,"tags":{"name":"/Users/ruben.van.rooij/git/dynz/examples/next-example/src/app/[locale]/page.tsx","layer":"rsc"},"startTime":1757343220878,"traceId":"4b8621af667f44c3"},{"name":"add-entry","duration":230457,"timestamp":2950126912989,"id":20,"parentId":18,"tags":{"request":"next-app-loader?page=%2Ffavicon.ico%2Froute&name=app%2Ffavicon.ico%2Froute&pagePath=private-next-app-dir%2Ffavicon.ico&appDir=%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fexamples%2Fnext-example%2Fsrc%2Fapp&appPaths=%2Ffavicon.ico&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&nextConfigExperimentalUseEarlyImport=&preferredRegion=&middlewareConfig=e30%3D!"},"startTime":1757343220697,"traceId":"4b8621af667f44c3"},{"name":"add-entry","duration":243637,"timestamp":2950126912764,"id":19,"parentId":18,"tags":{"request":"next-app-loader?page=%2F_not-found%2Fpage&name=app%2F_not-found%2Fpage&pagePath=next%2Fdist%2Fclient%2Fcomponents%2Fnot-found-error&appDir=%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fexamples%2Fnext-example%2Fsrc%2Fapp&appPaths=next%2Fdist%2Fclient%2Fcomponents%2Fnot-found-error&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&nextConfigExperimentalUseEarlyImport=&preferredRegion=&middlewareConfig=e30%3D!"},"startTime":1757343220697,"traceId":"4b8621af667f44c3"},{"name":"add-entry","duration":243399,"timestamp":2950126913013,"id":23,"parentId":18,"tags":{"request":"next-app-loader?page=%2F%5Blocale%5D%2Fpage&name=app%2F%5Blocale%5D%2Fpage&pagePath=private-next-app-dir%2F%5Blocale%5D%2Fpage.tsx&appDir=%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fexamples%2Fnext-example%2Fsrc%2Fapp&appPaths=%2F%5Blocale%5D%2Fpage&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&nextConfigExperimentalUseEarlyImport=&preferredRegion=&middlewareConfig=e30%3D!"},"startTime":1757343220697,"traceId":"4b8621af667f44c3"},{"name":"add-entry","duration":243396,"timestamp":2950126913019,"id":24,"parentId":18,"tags":{"request":"next-app-loader?page=%2Fpage&name=app%2Fpage&pagePath=private-next-app-dir%2Fpage.tsx&appDir=%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fexamples%2Fnext-example%2Fsrc%2Fapp&appPaths=%2Fpage&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&nextConfigExperimentalUseEarlyImport=&preferredRegion=&middlewareConfig=e30%3D!"},"startTime":1757343220697,"traceId":"4b8621af667f44c3"},{"name":"build-module-tsx","duration":8491,"timestamp":2950127188643,"id":43,"parentId":16,"tags":{"name":"/Users/ruben.van.rooij/git/dynz/examples/next-example/src/app/[locale]/page.tsx","layer":"ssr"},"startTime":1757343220973,"traceId":"4b8621af667f44c3"},{"name":"make","duration":424140,"timestamp":2950126912648,"id":18,"parentId":16,"tags":{},"startTime":1757343220697,"traceId":"4b8621af667f44c3"},{"name":"get-entries","duration":276,"timestamp":2950127337427,"id":45,"parentId":44,"tags":{},"startTime":1757343221122,"traceId":"4b8621af667f44c3"},{"name":"node-file-trace-plugin","duration":38072,"timestamp":2950127339264,"id":46,"parentId":44,"tags":{"traceEntryCount":"10"},"startTime":1757343221124,"traceId":"4b8621af667f44c3"},{"name":"collect-traced-files","duration":213,"timestamp":2950127377348,"id":47,"parentId":44,"tags":{},"startTime":1757343221162,"traceId":"4b8621af667f44c3"},{"name":"finish-modules","duration":40224,"timestamp":2950127337340,"id":44,"parentId":17,"tags":{},"startTime":1757343221122,"traceId":"4b8621af667f44c3"},{"name":"chunk-graph","duration":6551,"timestamp":2950127395734,"id":49,"parentId":48,"tags":{},"startTime":1757343221180,"traceId":"4b8621af667f44c3"},{"name":"optimize-modules","duration":11,"timestamp":2950127402351,"id":51,"parentId":48,"tags":{},"startTime":1757343221187,"traceId":"4b8621af667f44c3"},{"name":"optimize-chunks","duration":6890,"timestamp":2950127402400,"id":52,"parentId":48,"tags":{},"startTime":1757343221187,"traceId":"4b8621af667f44c3"},{"name":"optimize-tree","duration":72,"timestamp":2950127409344,"id":53,"parentId":48,"tags":{},"startTime":1757343221194,"traceId":"4b8621af667f44c3"},{"name":"optimize-chunk-modules","duration":8709,"timestamp":2950127409459,"id":54,"parentId":48,"tags":{},"startTime":1757343221194,"traceId":"4b8621af667f44c3"},{"name":"optimize","duration":15893,"timestamp":2950127402327,"id":50,"parentId":48,"tags":{},"startTime":1757343221187,"traceId":"4b8621af667f44c3"},{"name":"module-hash","duration":10695,"timestamp":2950127426530,"id":55,"parentId":48,"tags":{},"startTime":1757343221211,"traceId":"4b8621af667f44c3"},{"name":"code-generation","duration":132295,"timestamp":2950127437268,"id":56,"parentId":48,"tags":{},"startTime":1757343221222,"traceId":"4b8621af667f44c3"},{"name":"hash","duration":3628,"timestamp":2950127571858,"id":57,"parentId":48,"tags":{},"startTime":1757343221356,"traceId":"4b8621af667f44c3"},{"name":"code-generation-jobs","duration":120,"timestamp":2950127575485,"id":58,"parentId":48,"tags":{},"startTime":1757343221360,"traceId":"4b8621af667f44c3"},{"name":"module-assets","duration":210,"timestamp":2950127575587,"id":59,"parentId":48,"tags":{},"startTime":1757343221360,"traceId":"4b8621af667f44c3"},{"name":"create-chunk-assets","duration":2574,"timestamp":2950127575802,"id":60,"parentId":48,"tags":{},"startTime":1757343221360,"traceId":"4b8621af667f44c3"},{"name":"minify-js","duration":14004,"timestamp":2950127588370,"id":63,"parentId":61,"tags":{"name":"../app/favicon.ico/route.js","cache":"HIT"},"startTime":1757343221373,"traceId":"4b8621af667f44c3"},{"name":"minify-js","duration":13973,"timestamp":2950127588413,"id":64,"parentId":61,"tags":{"name":"../pages/_app.js","cache":"HIT"},"startTime":1757343221373,"traceId":"4b8621af667f44c3"},{"name":"minify-js","duration":13969,"timestamp":2950127588419,"id":65,"parentId":61,"tags":{"name":"../pages/_error.js","cache":"HIT"},"startTime":1757343221373,"traceId":"4b8621af667f44c3"},{"name":"minify-js","duration":2919,"timestamp":2950127599470,"id":68,"parentId":61,"tags":{"name":"../pages/_document.js","cache":"HIT"},"startTime":1757343221384,"traceId":"4b8621af667f44c3"},{"name":"minify-js","duration":2906,"timestamp":2950127599484,"id":69,"parentId":61,"tags":{"name":"../webpack-runtime.js","cache":"HIT"},"startTime":1757343221384,"traceId":"4b8621af667f44c3"},{"name":"minify-js","duration":2902,"timestamp":2950127599488,"id":70,"parentId":61,"tags":{"name":"368.js","cache":"HIT"},"startTime":1757343221384,"traceId":"4b8621af667f44c3"},{"name":"minify-js","duration":2900,"timestamp":2950127599492,"id":71,"parentId":61,"tags":{"name":"857.js","cache":"HIT"},"startTime":1757343221384,"traceId":"4b8621af667f44c3"},{"name":"minify-js","duration":246,"timestamp":2950127602146,"id":74,"parentId":61,"tags":{"name":"256.js","cache":"HIT"},"startTime":1757343221387,"traceId":"4b8621af667f44c3"},{"name":"minify-js","duration":28250,"timestamp":2950127586771,"id":62,"parentId":61,"tags":{"name":"../app/_not-found/page.js","cache":"MISS"},"startTime":1757343221371,"traceId":"4b8621af667f44c3"},{"name":"minify-js","duration":15825,"timestamp":2950127599222,"id":67,"parentId":61,"tags":{"name":"../app/page.js","cache":"MISS"},"startTime":1757343221384,"traceId":"4b8621af667f44c3"},{"name":"minify-js","duration":26343,"timestamp":2950127602152,"id":75,"parentId":61,"tags":{"name":"360.js","cache":"MISS"},"startTime":1757343221387,"traceId":"4b8621af667f44c3"},{"name":"minify-js","duration":37121,"timestamp":2950127599497,"id":72,"parentId":61,"tags":{"name":"979.js","cache":"MISS"},"startTime":1757343221384,"traceId":"4b8621af667f44c3"},{"name":"minify-js","duration":94140,"timestamp":2950127588422,"id":66,"parentId":61,"tags":{"name":"../app/[locale]/page.js","cache":"MISS"},"startTime":1757343221373,"traceId":"4b8621af667f44c3"},{"name":"minify-js","duration":94507,"timestamp":2950127600211,"id":73,"parentId":61,"tags":{"name":"498.js","cache":"MISS"},"startTime":1757343221385,"traceId":"4b8621af667f44c3"},{"name":"minify-webpack-plugin-optimize","duration":113084,"timestamp":2950127581649,"id":61,"parentId":16,"tags":{"compilationName":"server","mangle":"true"},"startTime":1757343221366,"traceId":"4b8621af667f44c3"},{"name":"css-minimizer-plugin","duration":98,"timestamp":2950127694836,"id":76,"parentId":16,"tags":{},"startTime":1757343221479,"traceId":"4b8621af667f44c3"},{"name":"create-trace-assets","duration":770,"timestamp":2950127695048,"id":77,"parentId":17,"tags":{},"startTime":1757343221480,"traceId":"4b8621af667f44c3"},{"name":"seal","duration":311893,"timestamp":2950127387393,"id":48,"parentId":16,"tags":{},"startTime":1757343221172,"traceId":"4b8621af667f44c3"},{"name":"webpack-compilation","duration":795134,"timestamp":2950126908414,"id":16,"parentId":13,"tags":{"name":"server"},"startTime":1757343220693,"traceId":"4b8621af667f44c3"},{"name":"emit","duration":3755,"timestamp":2950127703717,"id":78,"parentId":13,"tags":{},"startTime":1757343221488,"traceId":"4b8621af667f44c3"},{"name":"webpack-close","duration":137954,"timestamp":2950127708156,"id":79,"parentId":13,"tags":{"name":"server"},"startTime":1757343221493,"traceId":"4b8621af667f44c3"},{"name":"webpack-generate-error-stats","duration":1185,"timestamp":2950127846150,"id":80,"parentId":79,"tags":{},"startTime":1757343221631,"traceId":"4b8621af667f44c3"},{"name":"make","duration":135,"timestamp":2950127853458,"id":82,"parentId":81,"tags":{},"startTime":1757343221638,"traceId":"4b8621af667f44c3"},{"name":"chunk-graph","duration":24,"timestamp":2950127853988,"id":84,"parentId":83,"tags":{},"startTime":1757343221638,"traceId":"4b8621af667f44c3"},{"name":"optimize-modules","duration":3,"timestamp":2950127854041,"id":86,"parentId":83,"tags":{},"startTime":1757343221638,"traceId":"4b8621af667f44c3"},{"name":"optimize-chunks","duration":34,"timestamp":2950127854073,"id":87,"parentId":83,"tags":{},"startTime":1757343221639,"traceId":"4b8621af667f44c3"},{"name":"optimize-tree","duration":3,"timestamp":2950127854126,"id":88,"parentId":83,"tags":{},"startTime":1757343221639,"traceId":"4b8621af667f44c3"},{"name":"optimize-chunk-modules","duration":27,"timestamp":2950127854160,"id":89,"parentId":83,"tags":{},"startTime":1757343221639,"traceId":"4b8621af667f44c3"},{"name":"optimize","duration":178,"timestamp":2950127854026,"id":85,"parentId":83,"tags":{},"startTime":1757343221638,"traceId":"4b8621af667f44c3"},{"name":"module-hash","duration":8,"timestamp":2950127854292,"id":90,"parentId":83,"tags":{},"startTime":1757343221639,"traceId":"4b8621af667f44c3"},{"name":"code-generation","duration":6,"timestamp":2950127854305,"id":91,"parentId":83,"tags":{},"startTime":1757343221639,"traceId":"4b8621af667f44c3"},{"name":"hash","duration":27,"timestamp":2950127854340,"id":92,"parentId":83,"tags":{},"startTime":1757343221639,"traceId":"4b8621af667f44c3"},{"name":"code-generation-jobs","duration":15,"timestamp":2950127854368,"id":93,"parentId":83,"tags":{},"startTime":1757343221639,"traceId":"4b8621af667f44c3"},{"name":"module-assets","duration":7,"timestamp":2950127854380,"id":94,"parentId":83,"tags":{},"startTime":1757343221639,"traceId":"4b8621af667f44c3"},{"name":"create-chunk-assets","duration":7,"timestamp":2950127854391,"id":95,"parentId":83,"tags":{},"startTime":1757343221639,"traceId":"4b8621af667f44c3"},{"name":"minify-js","duration":20,"timestamp":2950127857152,"id":97,"parentId":96,"tags":{"name":"interception-route-rewrite-manifest.js","cache":"HIT"},"startTime":1757343221642,"traceId":"4b8621af667f44c3"},{"name":"minify-webpack-plugin-optimize","duration":342,"timestamp":2950127856838,"id":96,"parentId":81,"tags":{"compilationName":"edge-server","mangle":"true"},"startTime":1757343221641,"traceId":"4b8621af667f44c3"},{"name":"css-minimizer-plugin","duration":3,"timestamp":2950127857213,"id":98,"parentId":81,"tags":{},"startTime":1757343221642,"traceId":"4b8621af667f44c3"},{"name":"seal","duration":4234,"timestamp":2950127853914,"id":83,"parentId":81,"tags":{},"startTime":1757343221638,"traceId":"4b8621af667f44c3"},{"name":"webpack-compilation","duration":5561,"timestamp":2950127852635,"id":81,"parentId":13,"tags":{"name":"edge-server"},"startTime":1757343221637,"traceId":"4b8621af667f44c3"},{"name":"emit","duration":383,"timestamp":2950127858221,"id":99,"parentId":13,"tags":{},"startTime":1757343221643,"traceId":"4b8621af667f44c3"},{"name":"webpack-close","duration":78,"timestamp":2950127858775,"id":100,"parentId":13,"tags":{"name":"edge-server"},"startTime":1757343221643,"traceId":"4b8621af667f44c3"},{"name":"webpack-generate-error-stats","duration":404,"timestamp":2950127858856,"id":101,"parentId":100,"tags":{},"startTime":1757343221643,"traceId":"4b8621af667f44c3"},{"name":"add-entry","duration":86148,"timestamp":2950127863890,"id":113,"parentId":103,"tags":{"request":"next-flight-client-entry-loader?server=false!"},"startTime":1757343221648,"traceId":"4b8621af667f44c3"},{"name":"build-module-tsx","duration":3997,"timestamp":2950127963352,"id":114,"parentId":102,"tags":{"name":"/Users/ruben.van.rooij/git/dynz/examples/next-example/src/app/[locale]/page.tsx","layer":"app-pages-browser"},"startTime":1757343221748,"traceId":"4b8621af667f44c3"},{"name":"add-entry","duration":128947,"timestamp":2950127863813,"id":107,"parentId":103,"tags":{"request":"next-client-pages-loader?absolutePagePath=next%2Fdist%2Fclient%2Fcomponents%2Fnot-found-error&page=%2F_not-found%2Fpage!"},"startTime":1757343221648,"traceId":"4b8621af667f44c3"},{"name":"add-entry","duration":135779,"timestamp":2950127863872,"id":108,"parentId":103,"tags":{"request":"next-client-pages-loader?absolutePagePath=next%2Fdist%2Fpages%2F_app&page=%2F_app!"},"startTime":1757343221648,"traceId":"4b8621af667f44c3"},{"name":"postcss-process","duration":58160,"timestamp":2950128125822,"id":118,"parentId":117,"tags":{},"startTime":1757343221910,"traceId":"4b8621af667f44c3"},{"name":"postcss-loader","duration":189403,"timestamp":2950127994637,"id":117,"parentId":116,"tags":{},"startTime":1757343221779,"traceId":"4b8621af667f44c3"},{"name":"css-loader","duration":28556,"timestamp":2950128184158,"id":119,"parentId":116,"tags":{"astUsed":"true"},"startTime":1757343221969,"traceId":"4b8621af667f44c3"},{"name":"add-entry","duration":354195,"timestamp":2950127863879,"id":110,"parentId":103,"tags":{"request":"next-client-pages-loader?absolutePagePath=next%2Fdist%2Fpages%2F_error&page=%2F_error!"},"startTime":1757343221648,"traceId":"4b8621af667f44c3"},{"name":"build-module-css","duration":240909,"timestamp":2950127986175,"id":116,"parentId":115,"tags":{"name":"/Users/ruben.van.rooij/git/dynz/examples/next-example/src/app/globals.css.webpack[javascript/auto]!=!/Users/ruben.van.rooij/git/dynz/node_modules/.pnpm/next@15.3.5_react-dom@19.1.1_react@19.1.1__react@19.1.1/node_modules/next/dist/build/webpack/loaders/css-loader/src/index.js??ruleSet[1].rules[13].oneOf[10].use[2]!/Users/ruben.van.rooij/git/dynz/node_modules/.pnpm/next@15.3.5_react-dom@19.1.1_react@19.1.1__react@19.1.1/node_modules/next/dist/build/webpack/loaders/postcss-loader/src/index.js??ruleSet[1].rules[13].oneOf[10].use[3]!/Users/ruben.van.rooij/git/dynz/examples/next-example/src/app/globals.css","layer":null},"startTime":1757343221771,"traceId":"4b8621af667f44c3"},{"name":"add-entry","duration":363996,"timestamp":2950127863876,"id":109,"parentId":103,"tags":{"request":"/Users/ruben.van.rooij/git/dynz/node_modules/.pnpm/next@15.3.5_react-dom@19.1.1_react@19.1.1__react@19.1.1/node_modules/next/dist/client/router.js"},"startTime":1757343221648,"traceId":"4b8621af667f44c3"},{"name":"add-entry","duration":364108,"timestamp":2950127863770,"id":104,"parentId":103,"tags":{"request":"./../../node_modules/.pnpm/next@15.3.5_react-dom@19.1.1_react@19.1.1__react@19.1.1/node_modules/next/dist/client/next.js"},"startTime":1757343221648,"traceId":"4b8621af667f44c3"},{"name":"add-entry","duration":374895,"timestamp":2950127863808,"id":106,"parentId":103,"tags":{"request":"next-flight-client-entry-loader?modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fnode_modules%2F.pnpm%2Fnext%4015.3.5_react-dom%4019.1.1_react%4019.1.1__react%4019.1.1%2Fnode_modules%2Fnext%2Fdist%2Fclient%2Fcomponents%2Fclient-page.js%22%2C%22ids%22%3A%5B%5D%7D&modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fnode_modules%2F.pnpm%2Fnext%4015.3.5_react-dom%4019.1.1_react%4019.1.1__react%4019.1.1%2Fnode_modules%2Fnext%2Fdist%2Fclient%2Fcomponents%2Fclient-segment.js%22%2C%22ids%22%3A%5B%5D%7D&modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fnode_modules%2F.pnpm%2Fnext%4015.3.5_react-dom%4019.1.1_react%4019.1.1__react%4019.1.1%2Fnode_modules%2Fnext%2Fdist%2Fclient%2Fcomponents%2Ferror-boundary.js%22%2C%22ids%22%3A%5B%5D%7D&modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fnode_modules%2F.pnpm%2Fnext%4015.3.5_react-dom%4019.1.1_react%4019.1.1__react%4019.1.1%2Fnode_modules%2Fnext%2Fdist%2Fclient%2Fcomponents%2Fhttp-access-fallback%2Ferror-boundary.js%22%2C%22ids%22%3A%5B%5D%7D&modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fnode_modules%2F.pnpm%2Fnext%4015.3.5_react-dom%4019.1.1_react%4019.1.1__react%4019.1.1%2Fnode_modules%2Fnext%2Fdist%2Fclient%2Fcomponents%2Flayout-router.js%22%2C%22ids%22%3A%5B%5D%7D&modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fnode_modules%2F.pnpm%2Fnext%4015.3.5_react-dom%4019.1.1_react%4019.1.1__react%4019.1.1%2Fnode_modules%2Fnext%2Fdist%2Fclient%2Fcomponents%2Fmetadata%2Fasync-metadata.js%22%2C%22ids%22%3A%5B%5D%7D&modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fnode_modules%2F.pnpm%2Fnext%4015.3.5_react-dom%4019.1.1_react%4019.1.1__react%4019.1.1%2Fnode_modules%2Fnext%2Fdist%2Fclient%2Fcomponents%2Fmetadata%2Fmetadata-boundary.js%22%2C%22ids%22%3A%5B%5D%7D&modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fnode_modules%2F.pnpm%2Fnext%4015.3.5_react-dom%4019.1.1_react%4019.1.1__react%4019.1.1%2Fnode_modules%2Fnext%2Fdist%2Fclient%2Fcomponents%2Frender-from-template-context.js%22%2C%22ids%22%3A%5B%5D%7D&server=false!"},"startTime":1757343221648,"traceId":"4b8621af667f44c3"},{"name":"build-module-css","duration":274132,"timestamp":2950127972786,"id":115,"parentId":102,"tags":{"name":"/Users/ruben.van.rooij/git/dynz/examples/next-example/src/app/globals.css","layer":"app-pages-browser"},"startTime":1757343221757,"traceId":"4b8621af667f44c3"},{"name":"add-entry","duration":384266,"timestamp":2950127863800,"id":105,"parentId":103,"tags":{"request":"./../../node_modules/.pnpm/next@15.3.5_react-dom@19.1.1_react@19.1.1__react@19.1.1/node_modules/next/dist/client/app-next.js"},"startTime":1757343221648,"traceId":"4b8621af667f44c3"},{"name":"build-module","duration":61,"timestamp":2950128251490,"id":120,"parentId":115,"tags":{},"startTime":1757343222036,"traceId":"4b8621af667f44c3"},{"name":"add-entry","duration":398568,"timestamp":2950127863882,"id":111,"parentId":103,"tags":{"request":"next-flight-client-entry-loader?modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fexamples%2Fnext-example%2Fsrc%2Fapp%2Fglobals.css%22%2C%22ids%22%3A%5B%5D%7D&modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fnode_modules%2F.pnpm%2Fnext-intl%404.3.4_next%4015.3.5_react-dom%4019.1.1_react%4019.1.1__react%4019.1.1__react%4019.1.1_typescript%405.8.3%2Fnode_modules%2Fnext-intl%2Fdist%2Fesm%2Fproduction%2Fshared%2FNextIntlClientProvider.js%22%2C%22ids%22%3A%5B%22default%22%5D%7D&server=false!"},"startTime":1757343221648,"traceId":"4b8621af667f44c3"},{"name":"add-entry","duration":400421,"timestamp":2950127863885,"id":112,"parentId":103,"tags":{"request":"next-flight-client-entry-loader?modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fexamples%2Fnext-example%2Fsrc%2Fapp%2F%5Blocale%5D%2Fpage.tsx%22%2C%22ids%22%3A%5B%5D%7D&server=false!"},"startTime":1757343221648,"traceId":"4b8621af667f44c3"},{"name":"make","duration":400777,"timestamp":2950127863642,"id":103,"parentId":102,"tags":{},"startTime":1757343221648,"traceId":"4b8621af667f44c3"},{"name":"chunk-graph","duration":2988,"timestamp":2950128275922,"id":122,"parentId":121,"tags":{},"startTime":1757343222060,"traceId":"4b8621af667f44c3"},{"name":"optimize-modules","duration":3,"timestamp":2950128278940,"id":124,"parentId":121,"tags":{},"startTime":1757343222063,"traceId":"4b8621af667f44c3"},{"name":"optimize-chunks","duration":3457,"timestamp":2950128279425,"id":126,"parentId":121,"tags":{},"startTime":1757343222064,"traceId":"4b8621af667f44c3"}]
+[{"name":"generate-buildid","duration":97,"timestamp":2961011321272,"id":4,"parentId":1,"tags":{},"startTime":1757354105122,"traceId":"c31c4c1ec2fda4fe"},{"name":"load-custom-routes","duration":149,"timestamp":2961011321411,"id":5,"parentId":1,"tags":{},"startTime":1757354105122,"traceId":"c31c4c1ec2fda4fe"},{"name":"create-dist-dir","duration":109,"timestamp":2961011347244,"id":6,"parentId":1,"tags":{},"startTime":1757354105148,"traceId":"c31c4c1ec2fda4fe"},{"name":"create-pages-mapping","duration":85,"timestamp":2961011354935,"id":7,"parentId":1,"tags":{},"startTime":1757354105156,"traceId":"c31c4c1ec2fda4fe"},{"name":"collect-app-paths","duration":929,"timestamp":2961011355036,"id":8,"parentId":1,"tags":{},"startTime":1757354105156,"traceId":"c31c4c1ec2fda4fe"},{"name":"create-app-mapping","duration":931,"timestamp":2961011355975,"id":9,"parentId":1,"tags":{},"startTime":1757354105157,"traceId":"c31c4c1ec2fda4fe"},{"name":"public-dir-conflict-check","duration":153,"timestamp":2961011357059,"id":10,"parentId":1,"tags":{},"startTime":1757354105158,"traceId":"c31c4c1ec2fda4fe"},{"name":"generate-routes-manifest","duration":972,"timestamp":2961011357292,"id":11,"parentId":1,"tags":{},"startTime":1757354105158,"traceId":"c31c4c1ec2fda4fe"},{"name":"create-entrypoints","duration":8766,"timestamp":2961011398910,"id":14,"parentId":1,"tags":{},"startTime":1757354105200,"traceId":"c31c4c1ec2fda4fe"},{"name":"generate-webpack-config","duration":154510,"timestamp":2961011407706,"id":15,"parentId":13,"tags":{},"startTime":1757354105209,"traceId":"c31c4c1ec2fda4fe"},{"name":"next-trace-entrypoint-plugin","duration":1057,"timestamp":2961011606484,"id":17,"parentId":16,"tags":{},"startTime":1757354105407,"traceId":"c31c4c1ec2fda4fe"},{"name":"add-entry","duration":116584,"timestamp":2961011610200,"id":21,"parentId":18,"tags":{"request":"next/dist/pages/_app"},"startTime":1757354105411,"traceId":"c31c4c1ec2fda4fe"},{"name":"add-entry","duration":158688,"timestamp":2961011610223,"id":25,"parentId":18,"tags":{"request":"next/dist/pages/_document"},"startTime":1757354105411,"traceId":"c31c4c1ec2fda4fe"},{"name":"add-entry","duration":170434,"timestamp":2961011610206,"id":22,"parentId":18,"tags":{"request":"next-route-loader?kind=PAGES&page=%2F_error&preferredRegion=&absolutePagePath=next%2Fdist%2Fpages%2F_error&absoluteAppPath=next%2Fdist%2Fpages%2F_app&absoluteDocumentPath=next%2Fdist%2Fpages%2F_document&middlewareConfigBase64=e30%3D!"},"startTime":1757354105411,"traceId":"c31c4c1ec2fda4fe"},{"name":"add-entry","duration":222752,"timestamp":2961011609962,"id":19,"parentId":18,"tags":{"request":"next-app-loader?page=%2Ffavicon.ico%2Froute&name=app%2Ffavicon.ico%2Froute&pagePath=private-next-app-dir%2Ffavicon.ico&appDir=%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fexamples%2Fnext-example%2Fsrc%2Fapp&appPaths=%2Ffavicon.ico&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&nextConfigExperimentalUseEarlyImport=&preferredRegion=&middlewareConfig=e30%3D!"},"startTime":1757354105411,"traceId":"c31c4c1ec2fda4fe"},{"name":"add-entry","duration":233766,"timestamp":2961011610188,"id":20,"parentId":18,"tags":{"request":"next-app-loader?page=%2F_not-found%2Fpage&name=app%2F_not-found%2Fpage&pagePath=next%2Fdist%2Fclient%2Fcomponents%2Fnot-found-error&appDir=%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fexamples%2Fnext-example%2Fsrc%2Fapp&appPaths=next%2Fdist%2Fclient%2Fcomponents%2Fnot-found-error&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&nextConfigExperimentalUseEarlyImport=&preferredRegion=&middlewareConfig=e30%3D!"},"startTime":1757354105411,"traceId":"c31c4c1ec2fda4fe"},{"name":"add-entry","duration":233752,"timestamp":2961011610212,"id":23,"parentId":18,"tags":{"request":"next-app-loader?page=%2F%5Blocale%5D%2Fpage&name=app%2F%5Blocale%5D%2Fpage&pagePath=private-next-app-dir%2F%5Blocale%5D%2Fpage.tsx&appDir=%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fexamples%2Fnext-example%2Fsrc%2Fapp&appPaths=%2F%5Blocale%5D%2Fpage&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&nextConfigExperimentalUseEarlyImport=&preferredRegion=&middlewareConfig=e30%3D!"},"startTime":1757354105411,"traceId":"c31c4c1ec2fda4fe"},{"name":"add-entry","duration":233749,"timestamp":2961011610218,"id":24,"parentId":18,"tags":{"request":"next-app-loader?page=%2Fpage&name=app%2Fpage&pagePath=private-next-app-dir%2Fpage.tsx&appDir=%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fexamples%2Fnext-example%2Fsrc%2Fapp&appPaths=%2Fpage&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&nextConfigExperimentalUseEarlyImport=&preferredRegion=&middlewareConfig=e30%3D!"},"startTime":1757354105411,"traceId":"c31c4c1ec2fda4fe"},{"name":"make","duration":414337,"timestamp":2961011609848,"id":18,"parentId":16,"tags":{},"startTime":1757354105411,"traceId":"c31c4c1ec2fda4fe"},{"name":"get-entries","duration":221,"timestamp":2961012024834,"id":43,"parentId":42,"tags":{},"startTime":1757354105826,"traceId":"c31c4c1ec2fda4fe"},{"name":"node-file-trace-plugin","duration":40148,"timestamp":2961012026669,"id":44,"parentId":42,"tags":{"traceEntryCount":"10"},"startTime":1757354105828,"traceId":"c31c4c1ec2fda4fe"},{"name":"collect-traced-files","duration":202,"timestamp":2961012066828,"id":45,"parentId":42,"tags":{},"startTime":1757354105868,"traceId":"c31c4c1ec2fda4fe"},{"name":"finish-modules","duration":42287,"timestamp":2961012024745,"id":42,"parentId":17,"tags":{},"startTime":1757354105826,"traceId":"c31c4c1ec2fda4fe"},{"name":"chunk-graph","duration":6552,"timestamp":2961012087020,"id":47,"parentId":46,"tags":{},"startTime":1757354105888,"traceId":"c31c4c1ec2fda4fe"},{"name":"optimize-modules","duration":11,"timestamp":2961012093645,"id":49,"parentId":46,"tags":{},"startTime":1757354105895,"traceId":"c31c4c1ec2fda4fe"},{"name":"optimize-chunks","duration":5730,"timestamp":2961012093772,"id":50,"parentId":46,"tags":{},"startTime":1757354105895,"traceId":"c31c4c1ec2fda4fe"},{"name":"optimize-tree","duration":65,"timestamp":2961012099552,"id":51,"parentId":46,"tags":{},"startTime":1757354105900,"traceId":"c31c4c1ec2fda4fe"},{"name":"optimize-chunk-modules","duration":9671,"timestamp":2961012099658,"id":52,"parentId":46,"tags":{},"startTime":1757354105901,"traceId":"c31c4c1ec2fda4fe"},{"name":"optimize","duration":15763,"timestamp":2961012093620,"id":48,"parentId":46,"tags":{},"startTime":1757354105894,"traceId":"c31c4c1ec2fda4fe"},{"name":"module-hash","duration":10752,"timestamp":2961012118298,"id":53,"parentId":46,"tags":{},"startTime":1757354105919,"traceId":"c31c4c1ec2fda4fe"},{"name":"code-generation","duration":3052,"timestamp":2961012129097,"id":54,"parentId":46,"tags":{},"startTime":1757354105930,"traceId":"c31c4c1ec2fda4fe"},{"name":"hash","duration":3853,"timestamp":2961012134243,"id":55,"parentId":46,"tags":{},"startTime":1757354105935,"traceId":"c31c4c1ec2fda4fe"},{"name":"code-generation-jobs","duration":136,"timestamp":2961012138095,"id":56,"parentId":46,"tags":{},"startTime":1757354105939,"traceId":"c31c4c1ec2fda4fe"},{"name":"module-assets","duration":237,"timestamp":2961012138214,"id":57,"parentId":46,"tags":{},"startTime":1757354105939,"traceId":"c31c4c1ec2fda4fe"},{"name":"create-chunk-assets","duration":2807,"timestamp":2961012138456,"id":58,"parentId":46,"tags":{},"startTime":1757354105939,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":7325,"timestamp":2961012147069,"id":60,"parentId":59,"tags":{"name":"../app/favicon.ico/route.js","cache":"HIT"},"startTime":1757354105948,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":5849,"timestamp":2961012148554,"id":62,"parentId":59,"tags":{"name":"../pages/_app.js","cache":"HIT"},"startTime":1757354105949,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":5841,"timestamp":2961012148563,"id":63,"parentId":59,"tags":{"name":"../pages/_error.js","cache":"HIT"},"startTime":1757354105949,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":3773,"timestamp":2961012150633,"id":66,"parentId":59,"tags":{"name":"../pages/_document.js","cache":"HIT"},"startTime":1757354105952,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":3768,"timestamp":2961012150639,"id":67,"parentId":59,"tags":{"name":"../webpack-runtime.js","cache":"HIT"},"startTime":1757354105952,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":3765,"timestamp":2961012150642,"id":68,"parentId":59,"tags":{"name":"368.js","cache":"HIT"},"startTime":1757354105952,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":3763,"timestamp":2961012150646,"id":69,"parentId":59,"tags":{"name":"857.js","cache":"HIT"},"startTime":1757354105952,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":260,"timestamp":2961012154150,"id":72,"parentId":59,"tags":{"name":"256.js","cache":"HIT"},"startTime":1757354105955,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":18411,"timestamp":2961012147152,"id":61,"parentId":59,"tags":{"name":"../app/_not-found/page.js","cache":"MISS"},"startTime":1757354105948,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":15153,"timestamp":2961012150441,"id":65,"parentId":59,"tags":{"name":"../app/page.js","cache":"MISS"},"startTime":1757354105951,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":24827,"timestamp":2961012154168,"id":73,"parentId":59,"tags":{"name":"360.js","cache":"MISS"},"startTime":1757354105955,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":39724,"timestamp":2961012150650,"id":70,"parentId":59,"tags":{"name":"979.js","cache":"MISS"},"startTime":1757354105952,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":90480,"timestamp":2961012148567,"id":64,"parentId":59,"tags":{"name":"../app/[locale]/page.js","cache":"MISS"},"startTime":1757354105949,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":98944,"timestamp":2961012152061,"id":71,"parentId":59,"tags":{"name":"498.js","cache":"MISS"},"startTime":1757354105953,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-webpack-plugin-optimize","duration":108405,"timestamp":2961012142617,"id":59,"parentId":16,"tags":{"compilationName":"server","mangle":"true"},"startTime":1757354105943,"traceId":"c31c4c1ec2fda4fe"},{"name":"css-minimizer-plugin","duration":100,"timestamp":2961012251125,"id":74,"parentId":16,"tags":{},"startTime":1757354106052,"traceId":"c31c4c1ec2fda4fe"},{"name":"create-trace-assets","duration":806,"timestamp":2961012251330,"id":75,"parentId":17,"tags":{},"startTime":1757354106052,"traceId":"c31c4c1ec2fda4fe"},{"name":"seal","duration":177323,"timestamp":2961012078478,"id":46,"parentId":16,"tags":{},"startTime":1757354105879,"traceId":"c31c4c1ec2fda4fe"},{"name":"webpack-compilation","duration":654473,"timestamp":2961011605629,"id":16,"parentId":13,"tags":{"name":"server"},"startTime":1757354105406,"traceId":"c31c4c1ec2fda4fe"},{"name":"emit","duration":3745,"timestamp":2961012260301,"id":76,"parentId":13,"tags":{},"startTime":1757354106061,"traceId":"c31c4c1ec2fda4fe"},{"name":"webpack-close","duration":43546,"timestamp":2961012264788,"id":77,"parentId":13,"tags":{"name":"server"},"startTime":1757354106066,"traceId":"c31c4c1ec2fda4fe"},{"name":"webpack-generate-error-stats","duration":1347,"timestamp":2961012308373,"id":78,"parentId":77,"tags":{},"startTime":1757354106109,"traceId":"c31c4c1ec2fda4fe"},{"name":"make","duration":88,"timestamp":2961012315618,"id":80,"parentId":79,"tags":{},"startTime":1757354106116,"traceId":"c31c4c1ec2fda4fe"},{"name":"chunk-graph","duration":24,"timestamp":2961012316019,"id":82,"parentId":81,"tags":{},"startTime":1757354106117,"traceId":"c31c4c1ec2fda4fe"},{"name":"optimize-modules","duration":3,"timestamp":2961012316064,"id":84,"parentId":81,"tags":{},"startTime":1757354106117,"traceId":"c31c4c1ec2fda4fe"},{"name":"optimize-chunks","duration":29,"timestamp":2961012316095,"id":85,"parentId":81,"tags":{},"startTime":1757354106117,"traceId":"c31c4c1ec2fda4fe"},{"name":"optimize-tree","duration":10,"timestamp":2961012316141,"id":86,"parentId":81,"tags":{},"startTime":1757354106117,"traceId":"c31c4c1ec2fda4fe"},{"name":"optimize-chunk-modules","duration":24,"timestamp":2961012316182,"id":87,"parentId":81,"tags":{},"startTime":1757354106117,"traceId":"c31c4c1ec2fda4fe"},{"name":"optimize","duration":167,"timestamp":2961012316053,"id":83,"parentId":81,"tags":{},"startTime":1757354106117,"traceId":"c31c4c1ec2fda4fe"},{"name":"module-hash","duration":8,"timestamp":2961012316307,"id":88,"parentId":81,"tags":{},"startTime":1757354106117,"traceId":"c31c4c1ec2fda4fe"},{"name":"code-generation","duration":6,"timestamp":2961012316320,"id":89,"parentId":81,"tags":{},"startTime":1757354106117,"traceId":"c31c4c1ec2fda4fe"},{"name":"hash","duration":24,"timestamp":2961012316350,"id":90,"parentId":81,"tags":{},"startTime":1757354106117,"traceId":"c31c4c1ec2fda4fe"},{"name":"code-generation-jobs","duration":30,"timestamp":2961012316375,"id":91,"parentId":81,"tags":{},"startTime":1757354106117,"traceId":"c31c4c1ec2fda4fe"},{"name":"module-assets","duration":9,"timestamp":2961012316401,"id":92,"parentId":81,"tags":{},"startTime":1757354106117,"traceId":"c31c4c1ec2fda4fe"},{"name":"create-chunk-assets","duration":7,"timestamp":2961012316413,"id":93,"parentId":81,"tags":{},"startTime":1757354106117,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":17,"timestamp":2961012318152,"id":95,"parentId":94,"tags":{"name":"interception-route-rewrite-manifest.js","cache":"HIT"},"startTime":1757354106119,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-webpack-plugin-optimize","duration":414,"timestamp":2961012317761,"id":94,"parentId":79,"tags":{"compilationName":"edge-server","mangle":"true"},"startTime":1757354106119,"traceId":"c31c4c1ec2fda4fe"},{"name":"css-minimizer-plugin","duration":3,"timestamp":2961012318215,"id":96,"parentId":79,"tags":{},"startTime":1757354106119,"traceId":"c31c4c1ec2fda4fe"},{"name":"seal","duration":3238,"timestamp":2961012315948,"id":81,"parentId":79,"tags":{},"startTime":1757354106117,"traceId":"c31c4c1ec2fda4fe"},{"name":"webpack-compilation","duration":4431,"timestamp":2961012314801,"id":79,"parentId":13,"tags":{"name":"edge-server"},"startTime":1757354106116,"traceId":"c31c4c1ec2fda4fe"},{"name":"emit","duration":339,"timestamp":2961012319256,"id":97,"parentId":13,"tags":{},"startTime":1757354106120,"traceId":"c31c4c1ec2fda4fe"},{"name":"webpack-close","duration":83,"timestamp":2961012319777,"id":98,"parentId":13,"tags":{"name":"edge-server"},"startTime":1757354106121,"traceId":"c31c4c1ec2fda4fe"},{"name":"webpack-generate-error-stats","duration":269,"timestamp":2961012319864,"id":99,"parentId":98,"tags":{},"startTime":1757354106121,"traceId":"c31c4c1ec2fda4fe"},{"name":"add-entry","duration":72754,"timestamp":2961012324337,"id":111,"parentId":101,"tags":{"request":"next-flight-client-entry-loader?server=false!"},"startTime":1757354106125,"traceId":"c31c4c1ec2fda4fe"},{"name":"add-entry","duration":115537,"timestamp":2961012324265,"id":105,"parentId":101,"tags":{"request":"next-client-pages-loader?absolutePagePath=next%2Fdist%2Fclient%2Fcomponents%2Fnot-found-error&page=%2F_not-found%2Fpage!"},"startTime":1757354106125,"traceId":"c31c4c1ec2fda4fe"},{"name":"add-entry","duration":130958,"timestamp":2961012324320,"id":106,"parentId":101,"tags":{"request":"next-client-pages-loader?absolutePagePath=next%2Fdist%2Fpages%2F_app&page=%2F_app!"},"startTime":1757354106125,"traceId":"c31c4c1ec2fda4fe"},{"name":"add-entry","duration":133180,"timestamp":2961012324327,"id":108,"parentId":101,"tags":{"request":"next-client-pages-loader?absolutePagePath=next%2Fdist%2Fpages%2F_error&page=%2F_error!"},"startTime":1757354106125,"traceId":"c31c4c1ec2fda4fe"},{"name":"add-entry","duration":139801,"timestamp":2961012324324,"id":107,"parentId":101,"tags":{"request":"/Users/ruben.van.rooij/git/dynz/node_modules/.pnpm/next@15.3.5_react-dom@19.1.1_react@19.1.1__react@19.1.1/node_modules/next/dist/client/router.js"},"startTime":1757354106125,"traceId":"c31c4c1ec2fda4fe"},{"name":"add-entry","duration":144970,"timestamp":2961012324231,"id":102,"parentId":101,"tags":{"request":"./../../node_modules/.pnpm/next@15.3.5_react-dom@19.1.1_react@19.1.1__react@19.1.1/node_modules/next/dist/client/next.js"},"startTime":1757354106125,"traceId":"c31c4c1ec2fda4fe"},{"name":"add-entry","duration":148582,"timestamp":2961012324261,"id":104,"parentId":101,"tags":{"request":"next-flight-client-entry-loader?modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fnode_modules%2F.pnpm%2Fnext%4015.3.5_react-dom%4019.1.1_react%4019.1.1__react%4019.1.1%2Fnode_modules%2Fnext%2Fdist%2Fclient%2Fcomponents%2Fclient-page.js%22%2C%22ids%22%3A%5B%5D%7D&modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fnode_modules%2F.pnpm%2Fnext%4015.3.5_react-dom%4019.1.1_react%4019.1.1__react%4019.1.1%2Fnode_modules%2Fnext%2Fdist%2Fclient%2Fcomponents%2Fclient-segment.js%22%2C%22ids%22%3A%5B%5D%7D&modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fnode_modules%2F.pnpm%2Fnext%4015.3.5_react-dom%4019.1.1_react%4019.1.1__react%4019.1.1%2Fnode_modules%2Fnext%2Fdist%2Fclient%2Fcomponents%2Ferror-boundary.js%22%2C%22ids%22%3A%5B%5D%7D&modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fnode_modules%2F.pnpm%2Fnext%4015.3.5_react-dom%4019.1.1_react%4019.1.1__react%4019.1.1%2Fnode_modules%2Fnext%2Fdist%2Fclient%2Fcomponents%2Fhttp-access-fallback%2Ferror-boundary.js%22%2C%22ids%22%3A%5B%5D%7D&modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fnode_modules%2F.pnpm%2Fnext%4015.3.5_react-dom%4019.1.1_react%4019.1.1__react%4019.1.1%2Fnode_modules%2Fnext%2Fdist%2Fclient%2Fcomponents%2Flayout-router.js%22%2C%22ids%22%3A%5B%5D%7D&modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fnode_modules%2F.pnpm%2Fnext%4015.3.5_react-dom%4019.1.1_react%4019.1.1__react%4019.1.1%2Fnode_modules%2Fnext%2Fdist%2Fclient%2Fcomponents%2Fmetadata%2Fasync-metadata.js%22%2C%22ids%22%3A%5B%5D%7D&modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fnode_modules%2F.pnpm%2Fnext%4015.3.5_react-dom%4019.1.1_react%4019.1.1__react%4019.1.1%2Fnode_modules%2Fnext%2Fdist%2Fclient%2Fcomponents%2Fmetadata%2Fmetadata-boundary.js%22%2C%22ids%22%3A%5B%5D%7D&modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fnode_modules%2F.pnpm%2Fnext%4015.3.5_react-dom%4019.1.1_react%4019.1.1__react%4019.1.1%2Fnode_modules%2Fnext%2Fdist%2Fclient%2Fcomponents%2Frender-from-template-context.js%22%2C%22ids%22%3A%5B%5D%7D&server=false!"},"startTime":1757354106125,"traceId":"c31c4c1ec2fda4fe"},{"name":"add-entry","duration":160360,"timestamp":2961012324253,"id":103,"parentId":101,"tags":{"request":"./../../node_modules/.pnpm/next@15.3.5_react-dom@19.1.1_react@19.1.1__react@19.1.1/node_modules/next/dist/client/app-next.js"},"startTime":1757354106125,"traceId":"c31c4c1ec2fda4fe"},{"name":"add-entry","duration":190753,"timestamp":2961012324330,"id":109,"parentId":101,"tags":{"request":"next-flight-client-entry-loader?modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fexamples%2Fnext-example%2Fsrc%2Fapp%2Fglobals.css%22%2C%22ids%22%3A%5B%5D%7D&modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fnode_modules%2F.pnpm%2Fnext-intl%404.3.4_next%4015.3.5_react-dom%4019.1.1_react%4019.1.1__react%4019.1.1__react%4019.1.1_typescript%405.8.3%2Fnode_modules%2Fnext-intl%2Fdist%2Fesm%2Fproduction%2Fshared%2FNextIntlClientProvider.js%22%2C%22ids%22%3A%5B%22default%22%5D%7D&server=false!"},"startTime":1757354106125,"traceId":"c31c4c1ec2fda4fe"},{"name":"add-entry","duration":191861,"timestamp":2961012324333,"id":110,"parentId":101,"tags":{"request":"next-flight-client-entry-loader?modules=%7B%22request%22%3A%22%2FUsers%2Fruben.van.rooij%2Fgit%2Fdynz%2Fexamples%2Fnext-example%2Fsrc%2Fapp%2F%5Blocale%5D%2Fpage.tsx%22%2C%22ids%22%3A%5B%5D%7D&server=false!"},"startTime":1757354106125,"traceId":"c31c4c1ec2fda4fe"},{"name":"make","duration":192142,"timestamp":2961012324122,"id":101,"parentId":100,"tags":{},"startTime":1757354106125,"traceId":"c31c4c1ec2fda4fe"},{"name":"chunk-graph","duration":3410,"timestamp":2961012529629,"id":113,"parentId":112,"tags":{},"startTime":1757354106330,"traceId":"c31c4c1ec2fda4fe"},{"name":"optimize-modules","duration":4,"timestamp":2961012533070,"id":115,"parentId":112,"tags":{},"startTime":1757354106334,"traceId":"c31c4c1ec2fda4fe"},{"name":"optimize-chunks","duration":4652,"timestamp":2961012533855,"id":117,"parentId":112,"tags":{},"startTime":1757354106335,"traceId":"c31c4c1ec2fda4fe"},{"name":"optimize-tree","duration":5,"timestamp":2961012538535,"id":118,"parentId":112,"tags":{},"startTime":1757354106339,"traceId":"c31c4c1ec2fda4fe"},{"name":"optimize-chunk-modules","duration":5108,"timestamp":2961012538553,"id":119,"parentId":112,"tags":{},"startTime":1757354106339,"traceId":"c31c4c1ec2fda4fe"},{"name":"optimize","duration":10623,"timestamp":2961012533060,"id":114,"parentId":112,"tags":{},"startTime":1757354106334,"traceId":"c31c4c1ec2fda4fe"},{"name":"module-hash","duration":4816,"timestamp":2961012549718,"id":120,"parentId":112,"tags":{},"startTime":1757354106351,"traceId":"c31c4c1ec2fda4fe"},{"name":"code-generation","duration":944,"timestamp":2961012554562,"id":121,"parentId":112,"tags":{},"startTime":1757354106355,"traceId":"c31c4c1ec2fda4fe"},{"name":"hash","duration":2559,"timestamp":2961012556869,"id":122,"parentId":112,"tags":{},"startTime":1757354106358,"traceId":"c31c4c1ec2fda4fe"},{"name":"code-generation-jobs","duration":147,"timestamp":2961012559427,"id":123,"parentId":112,"tags":{},"startTime":1757354106360,"traceId":"c31c4c1ec2fda4fe"},{"name":"module-assets","duration":90,"timestamp":2961012559561,"id":124,"parentId":112,"tags":{},"startTime":1757354106360,"traceId":"c31c4c1ec2fda4fe"},{"name":"create-chunk-assets","duration":965,"timestamp":2961012559655,"id":125,"parentId":112,"tags":{},"startTime":1757354106361,"traceId":"c31c4c1ec2fda4fe"}]
+[{"name":"NextJsBuildManifest-generateClientManifest","duration":733,"timestamp":2961012561529,"id":127,"parentId":100,"tags":{},"startTime":1757354106362,"traceId":"c31c4c1ec2fda4fe"},{"name":"NextJsBuildManifest-createassets","duration":1078,"timestamp":2961012561189,"id":126,"parentId":100,"tags":{},"startTime":1757354106362,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":198,"timestamp":2961012564050,"id":129,"parentId":128,"tags":{"name":"static/chunks/main-ad41ac689df7cb05.js","cache":"HIT"},"startTime":1757354106365,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":181,"timestamp":2961012564069,"id":130,"parentId":128,"tags":{"name":"static/chunks/main-app-b008306136c9aa8a.js","cache":"HIT"},"startTime":1757354106365,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":176,"timestamp":2961012564075,"id":131,"parentId":128,"tags":{"name":"static/chunks/app/_not-found/page-3c4b55b490798e8e.js","cache":"HIT"},"startTime":1757354106365,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":172,"timestamp":2961012564080,"id":132,"parentId":128,"tags":{"name":"static/chunks/pages/_app-4a74985419195a15.js","cache":"HIT"},"startTime":1757354106365,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":169,"timestamp":2961012564084,"id":133,"parentId":128,"tags":{"name":"static/chunks/pages/_error-36dbe6b4df21c7b4.js","cache":"HIT"},"startTime":1757354106365,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":167,"timestamp":2961012564087,"id":134,"parentId":128,"tags":{"name":"static/chunks/app/layout-a4afaea6b12462d8.js","cache":"HIT"},"startTime":1757354106365,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":164,"timestamp":2961012564091,"id":135,"parentId":128,"tags":{"name":"static/chunks/app/[locale]/page-5a6ec397883cba6c.js","cache":"HIT"},"startTime":1757354106365,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":161,"timestamp":2961012564094,"id":136,"parentId":128,"tags":{"name":"static/chunks/app/page-9f8d50a03e074da9.js","cache":"HIT"},"startTime":1757354106365,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":159,"timestamp":2961012564097,"id":137,"parentId":128,"tags":{"name":"static/chunks/webpack-f571b29ee03141fd.js","cache":"HIT"},"startTime":1757354106365,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":157,"timestamp":2961012564100,"id":138,"parentId":128,"tags":{"name":"static/chunks/framework-d6f52249270a7456.js","cache":"HIT"},"startTime":1757354106365,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":154,"timestamp":2961012564103,"id":139,"parentId":128,"tags":{"name":"static/chunks/fc0ab130-cdbbc2c44752a813.js","cache":"HIT"},"startTime":1757354106365,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":152,"timestamp":2961012564106,"id":140,"parentId":128,"tags":{"name":"static/chunks/281-00741685ba81fe9b.js","cache":"HIT"},"startTime":1757354106365,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":149,"timestamp":2961012564110,"id":141,"parentId":128,"tags":{"name":"static/chunks/294-5b1d257cf0a8a5a6.js","cache":"HIT"},"startTime":1757354106365,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":147,"timestamp":2961012564113,"id":142,"parentId":128,"tags":{"name":"static/chunks/105-ac4508b78336a076.js","cache":"HIT"},"startTime":1757354106365,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":145,"timestamp":2961012564116,"id":143,"parentId":128,"tags":{"name":"server/middleware-react-loadable-manifest.js","cache":"HIT"},"startTime":1757354106365,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":40,"timestamp":2961012564221,"id":145,"parentId":128,"tags":{"name":"server/middleware-build-manifest.js","cache":"HIT"},"startTime":1757354106365,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":16,"timestamp":2961012564246,"id":147,"parentId":128,"tags":{"name":"server/next-font-manifest.js","cache":"HIT"},"startTime":1757354106365,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":535,"timestamp":2961012564163,"id":144,"parentId":128,"tags":{"name":"static/L26cplQZbJaAG-AcYOt2e/_ssgManifest.js","cache":"MISS"},"startTime":1757354106365,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-js","duration":614,"timestamp":2961012564226,"id":146,"parentId":128,"tags":{"name":"static/L26cplQZbJaAG-AcYOt2e/_buildManifest.js","cache":"MISS"},"startTime":1757354106365,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-webpack-plugin-optimize","duration":2204,"timestamp":2961012562641,"id":128,"parentId":100,"tags":{"compilationName":"client","mangle":"true"},"startTime":1757354106364,"traceId":"c31c4c1ec2fda4fe"},{"name":"minify-css","duration":37,"timestamp":2961012564896,"id":149,"parentId":148,"tags":{"file":"static/css/39dc86cea916b2f3.css","cache":"HIT"},"startTime":1757354106366,"traceId":"c31c4c1ec2fda4fe"},{"name":"css-minimizer-plugin","duration":63,"timestamp":2961012564872,"id":148,"parentId":100,"tags":{},"startTime":1757354106366,"traceId":"c31c4c1ec2fda4fe"},{"name":"seal","duration":46497,"timestamp":2961012522005,"id":112,"parentId":100,"tags":{},"startTime":1757354106323,"traceId":"c31c4c1ec2fda4fe"},{"name":"webpack-compilation","duration":244983,"timestamp":2961012323557,"id":100,"parentId":13,"tags":{"name":"client"},"startTime":1757354106124,"traceId":"c31c4c1ec2fda4fe"},{"name":"emit","duration":3383,"timestamp":2961012568560,"id":150,"parentId":13,"tags":{},"startTime":1757354106369,"traceId":"c31c4c1ec2fda4fe"},{"name":"webpack-close","duration":12499,"timestamp":2961012572197,"id":151,"parentId":13,"tags":{"name":"client"},"startTime":1757354106373,"traceId":"c31c4c1ec2fda4fe"},{"name":"webpack-generate-error-stats","duration":527,"timestamp":2961012584708,"id":152,"parentId":151,"tags":{},"startTime":1757354106386,"traceId":"c31c4c1ec2fda4fe"},{"name":"run-webpack-compiler","duration":1186506,"timestamp":2961011398908,"id":13,"parentId":1,"tags":{},"startTime":1757354105200,"traceId":"c31c4c1ec2fda4fe"},{"name":"format-webpack-messages","duration":59,"timestamp":2961012585418,"id":153,"parentId":1,"tags":{},"startTime":1757354106386,"traceId":"c31c4c1ec2fda4fe"},{"name":"verify-and-lint","duration":1281139,"timestamp":2961012590005,"id":156,"parentId":1,"tags":{},"startTime":1757354106391,"traceId":"c31c4c1ec2fda4fe"},{"name":"verify-typescript-setup","duration":2162205,"timestamp":2961012587463,"id":155,"parentId":1,"tags":{},"startTime":1757354106388,"traceId":"c31c4c1ec2fda4fe"},{"name":"check-static-error-page","duration":1812,"timestamp":2961014767443,"id":159,"parentId":158,"tags":{},"startTime":1757354108568,"traceId":"c31c4c1ec2fda4fe"},{"name":"check-page","duration":821,"timestamp":2961014802974,"id":160,"parentId":158,"tags":{"page":"/_app"},"startTime":1757354108604,"traceId":"c31c4c1ec2fda4fe"},{"name":"check-page","duration":374,"timestamp":2961014803435,"id":162,"parentId":158,"tags":{"page":"/_document"},"startTime":1757354108604,"traceId":"c31c4c1ec2fda4fe"},{"name":"check-page","duration":478,"timestamp":2961014803402,"id":161,"parentId":158,"tags":{"page":"/_error"},"startTime":1757354108604,"traceId":"c31c4c1ec2fda4fe"},{"name":"is-page-static","duration":215348,"timestamp":2961014814929,"id":168,"parentId":163,"tags":{},"startTime":1757354108616,"traceId":"c31c4c1ec2fda4fe"},{"name":"check-page","duration":226840,"timestamp":2961014803510,"id":163,"parentId":158,"tags":{"page":"/_not-found"},"startTime":1757354108604,"traceId":"c31c4c1ec2fda4fe"},{"name":"is-page-static","duration":224796,"timestamp":2961014814554,"id":167,"parentId":166,"tags":{},"startTime":1757354108615,"traceId":"c31c4c1ec2fda4fe"},{"name":"check-page","duration":235789,"timestamp":2961014803614,"id":166,"parentId":158,"tags":{"page":"/favicon.ico"},"startTime":1757354108604,"traceId":"c31c4c1ec2fda4fe"},{"name":"is-page-static","duration":221176,"timestamp":2961014819821,"id":169,"parentId":164,"tags":{},"startTime":1757354108621,"traceId":"c31c4c1ec2fda4fe"},{"name":"check-page","duration":237440,"timestamp":2961014803579,"id":164,"parentId":158,"tags":{"page":"/[locale]"},"startTime":1757354108604,"traceId":"c31c4c1ec2fda4fe"},{"name":"is-page-static","duration":232403,"timestamp":2961014819922,"id":170,"parentId":165,"tags":{},"startTime":1757354108621,"traceId":"c31c4c1ec2fda4fe"},{"name":"check-page","duration":248768,"timestamp":2961014803598,"id":165,"parentId":158,"tags":{"page":"/"},"startTime":1757354108604,"traceId":"c31c4c1ec2fda4fe"},{"name":"static-check","duration":291744,"timestamp":2961014760653,"id":158,"parentId":1,"tags":{},"startTime":1757354108562,"traceId":"c31c4c1ec2fda4fe"},{"name":"generate-required-server-files","duration":199,"timestamp":2961015052443,"id":172,"parentId":1,"tags":{},"startTime":1757354108853,"traceId":"c31c4c1ec2fda4fe"},{"name":"write-routes-manifest","duration":541,"timestamp":2961015058148,"id":174,"parentId":1,"tags":{},"startTime":1757354108859,"traceId":"c31c4c1ec2fda4fe"},{"name":"load-dotenv","duration":17,"timestamp":2961015126503,"id":177,"parentId":176,"tags":{},"startTime":1757354108927,"traceId":"c31c4c1ec2fda4fe"},{"name":"run-export-path-map","duration":214,"timestamp":2961015439964,"id":178,"parentId":176,"tags":{},"startTime":1757354109241,"traceId":"c31c4c1ec2fda4fe"},{"name":"next-export","duration":747656,"timestamp":2961015126037,"id":176,"parentId":1,"tags":{},"startTime":1757354108927,"traceId":"c31c4c1ec2fda4fe"},{"name":"move-exported-app-not-found-","duration":37,"timestamp":2961015874256,"id":179,"parentId":175,"tags":{},"startTime":1757354109675,"traceId":"c31c4c1ec2fda4fe"},{"name":"move-exported-page","duration":6933,"timestamp":2961015874340,"id":180,"parentId":175,"tags":{},"startTime":1757354109675,"traceId":"c31c4c1ec2fda4fe"},{"name":"static-generation","duration":793871,"timestamp":2961015121899,"id":175,"parentId":1,"tags":{},"startTime":1757354108923,"traceId":"c31c4c1ec2fda4fe"},{"name":"write-routes-manifest","duration":4470,"timestamp":2961015915787,"id":181,"parentId":1,"tags":{},"startTime":1757354109717,"traceId":"c31c4c1ec2fda4fe"},{"name":"node-file-trace-build","duration":3802328,"timestamp":2961015054257,"id":173,"parentId":1,"tags":{"isTurbotrace":"false"},"startTime":1757354108855,"traceId":"c31c4c1ec2fda4fe"},{"name":"apply-include-excludes","duration":275,"timestamp":2961018856601,"id":182,"parentId":1,"tags":{},"startTime":1757354112657,"traceId":"c31c4c1ec2fda4fe"},{"name":"print-tree-view","duration":1343,"timestamp":2961018856946,"id":183,"parentId":1,"tags":{},"startTime":1757354112658,"traceId":"c31c4c1ec2fda4fe"},{"name":"telemetry-flush","duration":14,"timestamp":2961018858294,"id":184,"parentId":1,"tags":{},"startTime":1757354112659,"traceId":"c31c4c1ec2fda4fe"},{"name":"next-build","duration":7645140,"timestamp":2961011213172,"id":1,"tags":{"buildMode":"default","isTurboBuild":"false","version":"15.3.5","has-custom-webpack-config":"true","use-build-worker":"false"},"startTime":1757354105014,"traceId":"c31c4c1ec2fda4fe"}]
diff --git a/examples/next-example/src/components/dynz/dynz-form.tsx b/examples/next-example/src/components/dynz/dynz-form.tsx
index e122a93..902b630 100644
--- a/examples/next-example/src/components/dynz/dynz-form.tsx
+++ b/examples/next-example/src/components/dynz/dynz-form.tsx
@@ -49,22 +49,6 @@ export function DynzForm, A extends SchemaValues) {
const t = useTranslations();
- // const resolver = dynzResolver(
- // schema,
- // undefined,
- // {
- // stripNotIncludedValues: true,
- // },
- // {
- // messageTransformer: (error: ErrorMessage) => {
- // const customErrorMessagePath = `${name}.${error.path.slice(2)}.errors.${error.customCode}`;
- // return t.has(customErrorMessagePath)
- // ? t(customErrorMessagePath, error as unknown as Record)
- // : t(`errors.${error.customCode}`, error as unknown as Record);
- // },
- // }
- // );
-
const methods = useForm({
resolver: dynzResolver(
schema,
@@ -139,7 +123,12 @@ export function DynzTextInput({ name, description }: BaseInputProps) {
-
+
{description && {description}}
diff --git a/packages/dynz/src/resolve.test.ts b/packages/dynz/src/resolve.test.ts
index 87b76c3..4f5898b 100644
--- a/packages/dynz/src/resolve.test.ts
+++ b/packages/dynz/src/resolve.test.ts
@@ -523,7 +523,7 @@ describe("resolve", () => {
fields: {
user: object({
fields: {
- name: string({ default: "Unknown" }),
+ name: string(),
age: number(),
contacts: array({
schema: string(),
@@ -543,16 +543,6 @@ describe("resolve", () => {
});
});
- it("should return default value when value is undefined", () => {
- const values = { user: { age: 30 } };
- const result = getNested("$.user.name", schema, values);
-
- expect(result).toEqual({
- schema: expect.objectContaining({ type: SchemaType.STRING }),
- value: "Unknown",
- });
- });
-
it("should get nested value in array", () => {
const values = { user: { contacts: ["email@test.com", "phone"] } };
const result = getNested("$.user.contacts[0]", schema, values);
diff --git a/packages/dynz/src/resolve.ts b/packages/dynz/src/resolve.ts
index e655c6f..1dc4a79 100644
--- a/packages/dynz/src/resolve.ts
+++ b/packages/dynz/src/resolve.ts
@@ -352,7 +352,7 @@ export function getNested(path: string, schema: T, value: unkn
}
return {
- value: val === undefined ? acc.schema.default : val,
+ value: val,
schema: acc.schema.schema,
};
}
@@ -374,7 +374,7 @@ export function getNested(path: string, schema: T, value: unkn
}
return {
- value: val === undefined ? acc.schema.fields[cur]?.default : val,
+ value: val,
schema: childSchema,
};
}
diff --git a/packages/dynz/src/schema.test.ts b/packages/dynz/src/schema.test.ts
index 8562dae..8286dfb 100644
--- a/packages/dynz/src/schema.test.ts
+++ b/packages/dynz/src/schema.test.ts
@@ -3,9 +3,9 @@ import { equals, max, min } from "./rules";
import {
array,
boolean,
- date,
// rules,
DEFAULT_DATE_STRING_FORMAT,
+ date,
dateString,
file,
number,
@@ -14,6 +14,7 @@ import {
options,
required,
string,
+ tuple,
} from "./schema";
import { SchemaType } from "./types";
@@ -30,14 +31,12 @@ describe("schema", () => {
it("should create string schema with options", () => {
const schema = string({
required: true,
- default: "hello",
rules: [min(3), max(10)],
});
expect(schema).toEqual({
type: SchemaType.STRING,
required: true,
- default: "hello",
rules: [
{ type: "min", min: 3 },
{ type: "max", max: 10 },
@@ -51,7 +50,6 @@ describe("schema", () => {
mutable: true,
included: false,
private: true,
- default: "test",
});
expect(schema).toEqual({
@@ -60,7 +58,6 @@ describe("schema", () => {
mutable: true,
included: false,
private: true,
- default: "test",
});
});
});
@@ -77,14 +74,12 @@ describe("schema", () => {
it("should create number schema with options", () => {
const schema = number({
required: true,
- default: 42,
rules: [min(0), max(100)],
});
expect(schema).toEqual({
type: SchemaType.NUMBER,
required: true,
- default: 42,
rules: [
{ type: "min", min: 0 },
{ type: "max", max: 100 },
@@ -215,7 +210,6 @@ describe("schema", () => {
mutable: true,
included: true,
private: false,
- default: "medium",
});
expect(schema).toEqual({
@@ -225,7 +219,6 @@ describe("schema", () => {
mutable: true,
included: true,
private: false,
- default: "medium",
});
});
});
@@ -357,6 +350,116 @@ describe("schema", () => {
});
});
+ describe("tuple", () => {
+ it("should create basic tuple schema with mixed types", () => {
+ const schema = tuple({
+ schema: [string(), number(), boolean()],
+ });
+
+ expect(schema).toEqual({
+ type: SchemaType.TUPLE,
+ schema: [{ type: SchemaType.STRING }, { type: SchemaType.NUMBER }, { type: SchemaType.BOOLEAN }],
+ });
+ });
+
+ it("should create tuple schema with single element", () => {
+ const schema = tuple({
+ schema: [string()],
+ });
+
+ expect(schema).toEqual({
+ type: SchemaType.TUPLE,
+ schema: [{ type: SchemaType.STRING }],
+ });
+ });
+
+ it("should create tuple schema with empty array", () => {
+ const schema = tuple({
+ schema: [],
+ });
+
+ expect(schema).toEqual({
+ type: SchemaType.TUPLE,
+ schema: [],
+ });
+ });
+
+ it("should create tuple schema with complex types", () => {
+ const schema = tuple({
+ schema: [
+ string({ required: true }),
+ number({ rules: [min(0), max(100)] }),
+ object({
+ fields: {
+ name: string(),
+ age: number(),
+ },
+ }),
+ array({ schema: string() }),
+ ],
+ });
+
+ expect(schema.type).toBe(SchemaType.TUPLE);
+ expect(schema.schema).toHaveLength(4);
+ expect(schema.schema[0]).toEqual({ type: SchemaType.STRING, required: true });
+ expect(schema.schema[1]).toEqual({
+ type: SchemaType.NUMBER,
+ rules: [
+ { type: "min", min: 0 },
+ { type: "max", max: 100 },
+ ],
+ });
+ expect(schema.schema[2].type).toBe(SchemaType.OBJECT);
+ expect(schema.schema[3].type).toBe(SchemaType.ARRAY);
+ });
+
+ it("should create tuple schema with nested tuples", () => {
+ const schema = tuple({
+ schema: [
+ string(),
+ tuple({
+ schema: [number(), boolean()],
+ }),
+ ],
+ });
+
+ expect(schema.type).toBe(SchemaType.TUPLE);
+ expect(schema.schema).toHaveLength(2);
+ expect(schema.schema[0].type).toBe(SchemaType.STRING);
+ expect(schema.schema[1].type).toBe(SchemaType.TUPLE);
+ expect(schema.schema[1].schema).toEqual([{ type: SchemaType.NUMBER }, { type: SchemaType.BOOLEAN }]);
+ });
+
+ it("should create tuple schema with all base properties", () => {
+ const schema = tuple({
+ schema: [string(), number()],
+ required: false,
+ mutable: true,
+ included: true,
+ private: false,
+ });
+
+ expect(schema.type).toBe(SchemaType.TUPLE);
+ expect(schema.schema).toEqual([{ type: SchemaType.STRING }, { type: SchemaType.NUMBER }]);
+ expect(schema.required).toBe(false);
+ expect(schema.mutable).toBe(true);
+ expect(schema.included).toBe(true);
+ expect(schema.private).toBe(false);
+ });
+
+ it("should create tuple schema with date and date string", () => {
+ const schema = tuple({
+ schema: [date(), dateString({ format: "MM/dd/yyyy" })],
+ });
+
+ expect(schema.type).toBe(SchemaType.TUPLE);
+ expect(schema.schema).toEqual([
+ { type: SchemaType.DATE },
+ { type: SchemaType.DATE_STRING, format: "MM/dd/yyyy" },
+ ]);
+ });
+ });
+
describe("date", () => {
it("should create basic date schema", () => {
const schema = date();
@@ -369,13 +472,11 @@ describe("schema", () => {
it("should create date schema with options", () => {
const schema = date({
required: true,
- default: new Date("2024-01-01"),
});
expect(schema).toEqual({
type: SchemaType.DATE,
required: true,
- default: new Date("2024-01-01"),
});
});
@@ -397,7 +498,6 @@ describe("schema", () => {
included: true,
private: false,
coerce: true,
- default: new Date("2023-12-25"),
});
expect(schema).toEqual({
@@ -407,7 +507,6 @@ describe("schema", () => {
included: true,
private: false,
coerce: true,
- default: new Date("2023-12-25"),
});
});
@@ -453,14 +552,12 @@ describe("schema", () => {
const schema = dateString({
format: "dd-MM-yyyy",
required: true,
- default: "01-01-2024",
});
expect(schema).toEqual({
type: SchemaType.DATE_STRING,
format: "dd-MM-yyyy",
required: true,
- default: "01-01-2024",
});
});
@@ -490,13 +587,12 @@ describe("schema", () => {
});
it("should override required property", () => {
- const baseSchema = number({ required: true, default: 0 });
+ const baseSchema = number({ required: true });
const optionalSchema = optional(baseSchema);
expect(optionalSchema).toEqual({
type: SchemaType.NUMBER,
required: false,
- default: 0,
});
});
});
@@ -537,7 +633,7 @@ describe("schema", () => {
fields: {
street: string({ required: true }),
city: string({ required: true }),
- country: string({ default: "US" }),
+ country: string({}),
},
}),
rules: [max(3)],
diff --git a/packages/dynz/src/schema.ts b/packages/dynz/src/schema.ts
index 5b586d7..ae88d17 100644
--- a/packages/dynz/src/schema.ts
+++ b/packages/dynz/src/schema.ts
@@ -12,6 +12,7 @@ import {
type Schema,
SchemaType,
type StringSchema,
+ type TupleSchema,
} from "./types";
export function string(): StringSchema;
@@ -106,6 +107,15 @@ export const array = , "type">>(
+ value: A
+): Prettify, "type">> => {
+ return {
+ ...value,
+ type: SchemaType.TUPLE,
+ };
+};
+
export function optional(schema: T): T & { required: false } {
return {
...schema,
diff --git a/packages/dynz/src/types.ts b/packages/dynz/src/types.ts
index 26eb76a..c83ff89 100644
--- a/packages/dynz/src/types.ts
+++ b/packages/dynz/src/types.ts
@@ -5,6 +5,8 @@ export type Prettify = {
[K in keyof T]: T[K];
} & {};
+type Flatten = T extends (infer U)[] ? U : T;
+
export type Filter = T extends []
? []
: T extends [infer H, ...infer R]
@@ -278,6 +280,7 @@ export const SchemaType = {
NUMBER: "number",
OBJECT: "object",
ARRAY: "array",
+ TUPLE: "tuple",
OPTIONS: "options",
BOOLEAN: "boolean",
FILE: "file",
@@ -285,10 +288,9 @@ export const SchemaType = {
export type SchemaType = EnumValues;
-export type BaseSchema = {
+export type BaseSchema = {
type: TType;
rules?: Array>;
- default?: TValue;
required?: boolean | Condition;
mutable?: boolean | Condition;
included?: boolean | Condition;
@@ -312,11 +314,7 @@ export type StringRules =
| EmailRule
| CustomRule
| OneOfRule>;
-export type StringSchema = BaseSchema<
- string,
- typeof SchemaType.STRING,
- TRule
-> &
+export type StringSchema = BaseSchema &
PrivateSchema & { coerce?: boolean };
/**
@@ -335,7 +333,7 @@ export type DateStringRules =
export type DateStringSchema<
TFormat extends string = string,
TRule extends DateStringRules = DateStringRules,
-> = BaseSchema &
+> = BaseSchema &
PrivateSchema & {
/*
* Unicode Tokens
@@ -352,7 +350,6 @@ export type DateStringSchema<
*/
export type OptionsRules = EqualsRule | CustomRule;
export type OptionsSchema = BaseSchema<
- TValue,
typeof SchemaType.OPTIONS,
OptionsRules
> & {
@@ -364,21 +361,13 @@ export type OptionsSchema = Ba
*/
// TODO: Add mime type rule
export type FileRules = MinRule | MaxRule | MimeTypeRule;
-export type FileSchema = BaseSchema<
- TValue,
- typeof SchemaType.FILE,
- FileRules
->;
+export type FileSchema = BaseSchema;
/**
* OBJECT SCHEMA
*/
export type ObjectRules = CustomRule | MinRule | MaxRule;
-export type ObjectSchema> = BaseSchema<
- [T] extends [never] ? Record : { [A in keyof T]: SchemaValuesInternal },
- typeof SchemaType.OBJECT,
- ObjectRules
-> & {
+export type ObjectSchema> = BaseSchema & {
fields: [T] extends [never] ? Record : T;
};
@@ -386,15 +375,19 @@ export type ObjectSchema> = BaseSchema<
* ARRAY SCHEMA
*/
export type ArrayRules = MinRule | MaxRule | CustomRule;
-export type ArraySchema = BaseSchema<
- [T] extends [never] ? unknown[] : SchemaValuesInternal[],
- typeof SchemaType.ARRAY,
- ArrayRules
-> & {
+export type ArraySchema = BaseSchema & {
schema: [T] extends [never] ? Schema : T;
coerce?: boolean;
};
+/**
+ * TUPLE SCHEMA
+ */
+export type TupleRules = CustomRule;
+export type TupleSchema = BaseSchema & {
+ schema: [T] extends [never] ? unknown[] : T;
+};
+
/**
* DATE SCHEMA
*/
@@ -405,7 +398,7 @@ export type DateRules =
| BeforeRule
| EqualsRule
| CustomRule;
-export type DateSchema = BaseSchema & {
+export type DateSchema = BaseSchema & {
coerce?: boolean;
};
@@ -419,7 +412,7 @@ export type NumberRules =
| EqualsRule
| CustomRule
| OneOfRule>;
-export type NumberSchema = BaseSchema & {
+export type NumberSchema = BaseSchema & {
coerce?: boolean;
};
@@ -427,7 +420,7 @@ export type NumberSchema = BaseSchema | CustomRule;
-export type BooleanSchema = BaseSchema & {
+export type BooleanSchema = BaseSchema & {
coerce?: boolean;
};
@@ -437,6 +430,7 @@ export type Schema =
| NumberSchema
| BooleanSchema
| ArraySchema
+ | TupleSchema
| DateStringSchema
| OptionsSchema
| FileSchema
@@ -497,7 +491,9 @@ export type ValueType = T extends typeof Sche
? string | number
: T extends typeof SchemaType.FILE
? File
- : never;
+ : T extends typeof SchemaType.TUPLE
+ ? unknown[]
+ : never;
// === Object Field Categorization ===
type OptionalFields> = {
@@ -514,11 +510,19 @@ type RequiredFields> = {
export type ObjectValue> = OptionalFields & RequiredFields;
+export type TupleValue = {
+ [K in keyof T]: T[K] extends Schema ? SchemaValuesInternal : unknown;
+};
+
export type SchemaValuesInternal = T extends ObjectSchema
? Prettify>
: T extends ArraySchema
? MakeOptional>>
- : MakeOptional>;
+ : T extends OptionsSchema
+ ? MakeOptional>
+ : T extends TupleSchema
+ ? MakeOptional>
+ : MakeOptional>;
export type SchemaValues = Prettify>>;
/***
diff --git a/packages/dynz/src/validate.test.ts b/packages/dynz/src/validate.test.ts
index 2963e8a..622e6ed 100644
--- a/packages/dynz/src/validate.test.ts
+++ b/packages/dynz/src/validate.test.ts
@@ -14,7 +14,7 @@ import {
oneOf,
regex,
} from "./rules";
-import { array, boolean, date, dateString, file, number, object, options, string } from "./schema";
+import { array, boolean, date, dateString, file, number, object, options, string, tuple } from "./schema";
import { type CustomRuleMap, ErrorCode, SchemaType } from "./types";
import {
isArray,
@@ -522,6 +522,257 @@ describe("validate", () => {
});
});
+ describe("tuple validation", () => {
+ it("should validate basic tuple with correct types", () => {
+ const schema = tuple({
+ schema: [string(), number(), boolean()],
+ });
+ const result = validate(schema, undefined, ["hello", 42, true]);
+
+ expect(result).toEqual({
+ success: true,
+ values: ["hello", 42, true],
+ });
+ });
+
+ it("should fail when tuple value is not an array", () => {
+ const schema = tuple({
+ schema: [string(), number()],
+ });
+ const result = validate(schema, undefined, "not an array");
+
+ expect(result).toEqual({
+ success: false,
+ errors: [
+ expect.objectContaining({
+ code: ErrorCode.TYPE,
+ expectedType: SchemaType.TUPLE,
+ }),
+ ],
+ });
+ });
+
+ it("should fail when tuple has wrong type at specific position", () => {
+ const schema = tuple({
+ schema: [string(), number(), boolean()],
+ });
+ const result = validate(schema, undefined, ["hello", "not a number", true]);
+
+ expect(result).toEqual({
+ success: false,
+ errors: [
+ expect.objectContaining({
+ code: ErrorCode.TYPE,
+ path: "$.[1]",
+ expectedType: SchemaType.NUMBER,
+ }),
+ ],
+ });
+ });
+
+ it("should fail when tuple has too many elements", () => {
+ const schema = tuple({
+ schema: [string(), number()],
+ });
+ const result = validate(schema, undefined, ["hello", 42, "extra"]);
+
+ expect(result).toEqual({
+ success: false,
+ errors: [
+ expect.objectContaining({
+ code: ErrorCode.TYPE,
+ path: "$.[2]",
+ expectedType: SchemaType.TUPLE,
+ }),
+ ],
+ });
+ });
+
+ it("should validate tuple with fewer elements than schema length", () => {
+ const schema = tuple({
+ schema: [string(), number({ required: false }), boolean({ required: false })],
+ });
+ const result = validate(schema, undefined, ["hello"]);
+
+ expect(result.success).toBe(true);
+ });
+
+ it("should validate empty tuple", () => {
+ const schema = tuple({
+ schema: [],
+ });
+ const result = validate(schema, undefined, []);
+
+ expect(result).toEqual({
+ success: true,
+ values: [],
+ });
+ });
+
+ it("should fail when empty tuple schema receives non-empty array", () => {
+ const schema = tuple({
+ schema: [],
+ });
+ const result = validate(schema, undefined, ["unexpected"]);
+
+ expect(result).toEqual({
+ success: false,
+ errors: [
+ expect.objectContaining({
+ code: ErrorCode.TYPE,
+ path: "$.[0]",
+ expectedType: SchemaType.TUPLE,
+ }),
+ ],
+ });
+ });
+
+ it("should validate nested tuple", () => {
+ const schema = tuple({
+ schema: [
+ string(),
+ tuple({
+ schema: [number(), boolean()],
+ }),
+ ],
+ });
+ const result = validate(schema, undefined, ["hello", [42, true]]);
+
+ expect(result).toEqual({
+ success: true,
+ values: ["hello", [42, true]],
+ });
+ });
+
+ it("should fail validation for nested tuple with wrong inner type", () => {
+ const schema = tuple({
+ schema: [
+ string(),
+ tuple({
+ schema: [number(), boolean()],
+ }),
+ ],
+ });
+ const result = validate(schema, undefined, ["hello", [42, "not boolean"]]);
+
+ expect(result).toEqual({
+ success: false,
+ errors: [
+ expect.objectContaining({
+ code: ErrorCode.TYPE,
+ path: "$.[1].[1]",
+ expectedType: SchemaType.BOOLEAN,
+ }),
+ ],
+ });
+ });
+
+ it("should validate tuple with complex nested schemas", () => {
+ const schema = tuple({
+ schema: [
+ string(),
+ object({
+ fields: {
+ id: number(),
+ name: string(),
+ },
+ }),
+ array({ schema: string() }),
+ ],
+ });
+
+ const result = validate(schema, undefined, ["hello", { id: 1, name: "John" }, ["tag1", "tag2"]]);
+
+ expect(result.success).toBe(true);
+ if (result.success) {
+ expect(result.values[0]).toBe("hello");
+ expect(result.values[1]).toEqual({ id: 1, name: "John" });
+ expect(result.values[2]).toEqual(["tag1", "tag2"]);
+ }
+ });
+
+ it("should validate tuple with rules on individual elements", () => {
+ const schema = tuple({
+ schema: [string({ rules: [min(3), max(10)] }), number({ rules: [min(0), max(100)] }), boolean()],
+ });
+
+ const validResult = validate(schema, undefined, ["hello", 50, true]);
+ expect(validResult.success).toBe(true);
+
+ const invalidStringResult = validate(schema, undefined, ["hi", 50, true]);
+ expect(invalidStringResult.success).toBe(false);
+
+ const invalidNumberResult = validate(schema, undefined, ["hello", 150, true]);
+ expect(invalidNumberResult.success).toBe(false);
+ });
+
+ it("should validate tuple with required and optional elements", () => {
+ const schema = tuple({
+ schema: [string({ required: true }), number({ required: false }), boolean({ required: false })],
+ });
+
+ const fullResult = validate(schema, undefined, ["hello", 42, true]);
+ expect(fullResult.success).toBe(true);
+
+ const partialResult = validate(schema, undefined, ["hello"]);
+ expect(partialResult.success).toBe(true);
+
+ // For tuples, if we provide an empty array, there's no element at position 0
+ // so it should actually pass because undefined is processed for the required field
+ // Let me test with undefined at the first position instead
+ const undefinedRequiredResult = validate(schema, undefined, [undefined, 42]);
+ expect(undefinedRequiredResult.success).toBe(false);
+ });
+
+ it("should validate tuple with date elements", () => {
+ const schema = tuple({
+ schema: [date(), dateString({ format: "MM/dd/yyyy" })],
+ });
+
+ const testDate = new Date("2023-12-25");
+ const result = validate(schema, undefined, [testDate, "12/25/2023"]);
+
+ expect(result.success).toBe(true);
+ if (result.success) {
+ expect(result.values[0]).toBe(testDate);
+ expect(result.values[1]).toBe("12/25/2023");
+ }
+ });
+
+ it("should validate tuple with coercion enabled on elements", () => {
+ const schema = tuple({
+ schema: [string({ coerce: true }), number({ coerce: true }), boolean({ coerce: true })],
+ });
+
+ const result = validate(schema, undefined, [123, "456", "true"]);
+ expect(result.success).toBe(true);
+ if (result.success) {
+ expect(result.values[0]).toBe("123");
+ expect(result.values[1]).toBe(456);
+ expect(result.values[2]).toBe(true);
+ }
+ });
+
+ it("should handle mutability validation for tuples", () => {
+ const originalTuple = ["original", 42];
+ const changedTuple = ["changed", 42];
+
+ // Test that the tuple itself can be immutable
+ const tupleSchema = tuple({
+ schema: [string(), number()],
+ mutable: false,
+ });
+
+ // biome-ignore lint/suspicious/noExplicitAny: unit test
+ const tupleChangedResult = validate(tupleSchema, originalTuple as any, changedTuple);
+ expect(tupleChangedResult.success).toBe(false);
+
+ // biome-ignore lint/suspicious/noExplicitAny: unit test
+ const tupleSameResult = validate(tupleSchema, originalTuple as any, originalTuple);
+ expect(tupleSameResult.success).toBe(true);
+ });
+ });
+
describe("validation rules", () => {
describe("min rule", () => {
it("should pass when string length meets minimum", () => {
@@ -1340,6 +1591,15 @@ describe("validate", () => {
expect(validateType(SchemaType.DATE, new Date("invalid"))).toBe(false);
});
+ it("should validate tuple type", () => {
+ expect(validateType(SchemaType.TUPLE, [])).toBe(true);
+ expect(validateType(SchemaType.TUPLE, [1, 2, 3])).toBe(true);
+ expect(validateType(SchemaType.TUPLE, ["hello", "world"])).toBe(true);
+ expect(validateType(SchemaType.TUPLE, "not an array")).toBe(false);
+ expect(validateType(SchemaType.TUPLE, {})).toBe(false);
+ expect(validateType(SchemaType.TUPLE, null)).toBe(false);
+ });
+
it("should validate date string type with format", () => {
expect(validateType(SchemaType.DATE_STRING, "2023-12-25", "yyyy-MM-dd")).toBe(true);
expect(validateType(SchemaType.DATE_STRING, "invalid-date", "yyyy-MM-dd")).toBe(false);
diff --git a/packages/dynz/src/validate.ts b/packages/dynz/src/validate.ts
index 4ac50bb..f14c0b7 100644
--- a/packages/dynz/src/validate.ts
+++ b/packages/dynz/src/validate.ts
@@ -254,7 +254,7 @@ export function _validate(
/**
* Validate array
*/
- if (schema.type === SchemaType.ARRAY) {
+ if (schema.type === SchemaType.ARRAY || schema.type === SchemaType.TUPLE) {
if (!isArray(newValue)) {
throw new Error(`new value is not an array: ${newValue}`);
}
@@ -271,8 +271,29 @@ export function _validate(
return newValue.reduce>(
(acc, cur, index) => {
+ const validationSchema =
+ schema.type === SchemaType.ARRAY ? schema.schema : (schema.schema[index] as Schema | undefined);
+
+ if (validationSchema === undefined) {
+ return {
+ success: false,
+ errors: [
+ {
+ path: `${path}.[${index}]`,
+ schema,
+ value: cur,
+ current: currentValue?.[index],
+ customCode: ErrorCode.TYPE,
+ code: ErrorCode.TYPE,
+ expectedType: schema.type,
+ message: `The value for schema ${path} is not of type ${schema.type}`,
+ },
+ ],
+ };
+ }
+
const result = _validate(
- schema.schema,
+ validationSchema,
{
current: currentValue?.[index],
new: cur,
@@ -858,6 +879,8 @@ export function validateType(
return isDateString(value, dateFormat);
}
+ case SchemaType.TUPLE:
+ return isArray(value);
case SchemaType.OPTIONS:
return isNumber(value) || isString(value) || isBoolean(value);
}