{"id":14156545,"url":"https://github.com/skarab42/zoxy","last_synced_at":"2025-03-24T04:30:54.943Z","repository":{"id":64568569,"uuid":"576634517","full_name":"skarab42/zoxy","owner":"skarab42","description":"A small type-safe object proxy around Zod to help you stay safe after your data is loaded while continuing to edit them.","archived":false,"fork":false,"pushed_at":"2023-10-07T10:16:39.000Z","size":2459,"stargazers_count":117,"open_issues_count":4,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-05-21T11:29:20.821Z","etag":null,"topics":["object","proxy","type-safe","typescript","validation","zod"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/zoxy","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/skarab42.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-12-10T13:33:36.000Z","updated_at":"2024-01-28T02:29:56.000Z","dependencies_parsed_at":"2024-01-14T05:07:34.144Z","dependency_job_id":"21bdb4bf-d948-4ce6-97c6-a6f0588309af","html_url":"https://github.com/skarab42/zoxy","commit_stats":{"total_commits":15,"total_committers":1,"mean_commits":15.0,"dds":0.0,"last_synced_commit":"34d608c4855f484ebcfa8bcf330a1fdc026659e3"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skarab42%2Fzoxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skarab42%2Fzoxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skarab42%2Fzoxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skarab42%2Fzoxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/skarab42","download_url":"https://codeload.github.com/skarab42/zoxy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245210845,"owners_count":20578299,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["object","proxy","type-safe","typescript","validation","zod"],"created_at":"2024-08-17T08:06:12.604Z","updated_at":"2025-03-24T04:30:54.652Z","avatar_url":"https://github.com/skarab42.png","language":"TypeScript","funding_links":[],"categories":["typescript"],"sub_categories":[],"readme":"\u003ccenter\u003e\n  \u003ch1\u003eA small type-safe object proxy around \u003ca href=\"https://github.com/colinhacks/zod\"\u003eZod\u003c/a\u003e to help you stay safe after your data is loaded.\u003c/h1\u003e\n  \u003ch2\u003eBecause it can be a bit verbose to modify and validate complex structures deeply after loading them.\u003c/h2\u003e\n  \u003cimg src=\"example.png\" title=\"Zod over Zoxy sample code\" /\u003e\n  \u003cblockquote\u003eIf you don't need to modify your data after loading, you probably don't need zoxy!\u003c/blockquote\u003e\n\u003c/center\u003e\n\n\u003chr /\u003e\n\n## Installation\n\n```bash\npnpm add zod zoxy\n```\n\n## Basic usage ([live demo])\n\n```ts\nimport { z } from 'zod';\nimport { zoxy } from 'zoxy';\n\nconst User = z.object({\n  username: z.string().min(4),\n  email: z.string().email().optional(),\n  phone: z.object({\n    home: z.string().min(10).max(42).optional(),\n    work: z.string().min(10).max(42).optional(),\n  }),\n  foo: z.object({ bar: z.object({ baz: z.string().max(3).optional() }).optional() }).optional(),\n});\n\nconst user = zoxy(User, { username: 'anonymous', phone: {} });\n\n// Pass\nuser.username = 'nyan';\nuser.email = undefined;\nuser.phone.home = '555 042 42 42';\nuser.phone = { home: '555 042 42 42', work: '555 024 24 24' };\n\n// Fail\nuser.email = 'xxx'; // throw 'Invalid email'\nuser.phone = { home: 'xxx' }; // throw 'String must contain at least 10 character(s)'\n```\n\n## Ensure default value\n\nIn the example below the schema has three levels which are all optional and if you want to define the last level it can be quite verbose. Zoxy offers a solution to this with a little helper that makes sure that a default value is set. Simply [prefix](#options) the desired value with a '$' sign and you get a method that allows you to set a default value.\n\n```ts\nconst Data = z.object({\n  foo: z\n    .object({\n      bar: z\n        .object({\n          baz: z.string().max(3).optional(),\n        })\n        .optional(),\n    })\n    .optional(),\n});\n\nconst data = zoxy(Data, {});\n\n// Get `data.foo.bar.baz` if defined or set default value where needed.\nconst baz = data.$foo({}).$bar({}).$baz('baz'); // 'baz'\n```\n\nThe above line will perform the following actions:\n\n- if `data.foo` is undefined set it to {}\n- if `data.foo.bar` is undefined set it to {}\n- if `data.foo.bar.baz` is undefined set it to 'baz'\n- return `data.foo.bar.baz`\n\n\u003e Note that the returned value can be something different from the default value if it has already been initialized previously.\n\n## Set deep optional property\n\nIf you want to assign a new value deeply you must use the following syntax.\n\n```ts\n// Set default value on `foo.bar` where needed and set `foo.bar.baz` to 'buzz'.\ndata.$foo({}).$bar({}).baz = 'buzz';\n\nconsole.log(data.foo?.bar?.baz); // 'buzz'\n```\n\n## Signature\n\n```ts\nfunction zoxy(schema: ZodObject, data: Data, options?: ZoxyOptions): Zoxy;\n```\n\n### Options\n\n```ts\ntype ZoxyOptions = {\n  prefix: string; // default '$'\n};\n```\n\n---\n\nScaffolded with [@skarab/skaffold](https://www.npmjs.com/package/@skarab/skaffold)\n\n[live demo]: https://www.typescriptlang.org/play?#code/FASwtgDg9gTgLgAgN4IF4IL4IGYymBAclSgBNCBuUSWRFEgDwE9Mc8DipnLhgBjKADsAzogCqwgKYwEAXjQA6KACMAVpL5wAFEmAIEAVykxBAQzCSAXItEwQggOZaAlArD2tAFmcAaPQkkwUxAAG2tUBVt7J1dA4JCXJQg4ECFTBN9-CAALIStFFXVNHX99XItwyLg7R0T3QS0ARgAGVyCGLwAmVyhk1LMMv319AHdYAGtKqNq2jxa20w7PbqSUtMH-DEz9bCgoSsKNbRRlUxgDtSOdBFPUKerousWtAGYevvWXTHe1ga+t1b9dIuPxbKj8ISiQzGORoLhMLQSaQ+ZDQ6RmCpEUyCIRMMBQIyEFE5PLWJBYMG8AD0VIQAAVTMJhMAjNIFKyTOZJLDCIImNieByFHFQrCDIJSJJsPZJKQqEKSYJJApytz5IQAKxahDNZYIPXLQXGBSKtWo1XWTXa3WdfW2w0osYwSZELUanWdTwIT3ezyETDgmkIABi8RZxpFIR5DBjlAQQbg2TwIyIAElBAA3dIgUgBIKhQjhtmm2EoC1EGMMf0YCjx2mJ5NEADKD0cCDARkQAkEcGCggQpkQIUkjMQLQQfGyZ1MmmkWmEzkIQA\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskarab42%2Fzoxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskarab42%2Fzoxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskarab42%2Fzoxy/lists"}