Repository: colinhacks/zod
Pull request #4298 (2025-05-01 00:48:13)

docs: in v4, `strict()` is not deprecated
The following commit removed the deprecated mark from strict():

https://github.com/colinhacks/zod/commit/4d269a2f379914ab5b8be7f7a33e959cf2e2d53d

And this was an omission from the guide, so I fixed it.

https://github.com/colinhacks/zod/pull/4289#issuecomment-2842957366


coderabbitai[bot]: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->

> [!NOTE]
> Currently processing new changes in this PR. This may take a few minutes, please wait...
> 
> <details>
> <summary>📥 Commits</summary>
> 
> Reviewing files that changed from the base of the PR and between f210613edf99c322b015ff535f6b1388d17b59bd and 0845a1ace6c7974774e80b8a33917f20c5822c2b.
> 
> </details>
> 
> <details>
> <summary>⛔ Files ignored due to path filters (33)</summary>
> 
> * `logo/Logo Black.jpg` is excluded by `!**/*.jpg`
> * `logo/Logo Black.pdf` is excluded by `!**/*.pdf`
> * `logo/Logo Black.png` is excluded by `!**/*.png`
> * `logo/Logo Outer Glow.jpg` is excluded by `!**/*.jpg`
> * `logo/Logo Outer Glow.pdf` is excluded by `!**/*.pdf`
> * `logo/Logo Outer Glow.png` is excluded by `!**/*.png`
> * `logo/Logo White.jpg` is excluded by `!**/*.jpg`
> * `logo/Logo White.pdf` is excluded by `!**/*.pdf`
> * `logo/Logo White.png` is excluded by `!**/*.png`
> * `logo/Logo.jpg` is excluded by `!**/*.jpg`
> * `logo/Logo.pdf` is excluded by `!**/*.pdf`
> * `logo/Logo.png` is excluded by `!**/*.png`
> * `packages/docs/app/apple-icon.png` is excluded by `!**/*.png`
> * `packages/docs/app/icon.png` is excluded by `!**/*.png`
> * `packages/docs/app/logo.ico` is excluded by `!**/*.ico`
> * `packages/docs/pnpm-lock.yaml` is excluded by `!**/pnpm-lock.yaml`
> * `packages/docs/public/github-white.png` is excluded by `!**/*.png`
> * `packages/docs/public/logo/logo-black.jpg` is excluded by `!**/*.jpg`
> * `packages/docs/public/logo/logo-black.pdf` is excluded by `!**/*.pdf`
> * `packages/docs/public/logo/logo-black.png` is excluded by `!**/*.png`
> * `packages/docs/public/logo/logo-glow.jpg` is excluded by `!**/*.jpg`
> * `packages/docs/public/logo/logo-glow.pdf` is excluded by `!**/*.pdf`
> * `packages/docs/public/logo/logo-glow.png` is excluded by `!**/*.png`
> * `packages/docs/public/logo/logo-white.jpg` is excluded by `!**/*.jpg`
> * `packages/docs/public/logo/logo-white.pdf` is excluded by `!**/*.pdf`
> * `packages/docs/public/logo/logo-white.png` is excluded by `!**/*.png`
> * `packages/docs/public/logo/logo.jpg` is excluded by `!**/*.jpg`
> * `packages/docs/public/logo/logo.pdf` is excluded by `!**/*.pdf`
> * `packages/docs/public/logo/logo.png` is excluded by `!**/*.png`
> * `packages/docs/public/logo/logo.svg` is excluded by `!**/*.svg`
> * `packages/docs/public/logo/logo_square.png` is excluded by `!**/*.png`
> * `packages/docs/public/logo/profile_circle.png` is excluded by `!**/*.png`
> * `packages/docs/public/logo/profile_square.png` is excluded by `!**/*.png`
> 
> </details>
> 
> <details>
> <summary>📒 Files selected for processing (107)</summary>
> 
> * `.changeset/README.md` (1 hunks)
> * `.changeset/config.json` (1 hunks)
> * `.configs/rollup.config.js` (1 hunks)
> * `.configs/tsconfig.base.json` (1 hunks)
> * `.dependency-cruiser.js` (0 hunks)
> * `.devcontainer/devcontainer.json` (1 hunks)
> * `.eslintrc.js` (0 hunks)
> * `.github/pull_request_template.md` (1 hunks)
> * `.github/workflows/release-beta.yaml` (1 hunks)
> * `.github/workflows/release-canary.yml` (2 hunks)
> * `.github/workflows/release.yml` (2 hunks)
> * `.github/workflows/test.yml` (2 hunks)
> * `.gitignore` (1 hunks)
> * `.husky/pre-commit` (1 hunks)
> * `.husky/pre-push` (1 hunks)
> * `.npmrc` (1 hunks)
> * `.nvmrc` (1 hunks)
> * `.prettierrc.yaml` (1 hunks)
> * `.vscode/launch.json` (1 hunks)
> * `.vscode/settings.json` (1 hunks)
> * `CHANGELOG.md` (0 hunks)
> * `CONTRIBUTING.md` (2 hunks)
> * `ERROR_HANDLING.md` (2 hunks)
> * `LICENSE` (1 hunks)
> * `MIGRATION.md` (1 hunks)
> * `README.md` (18 hunks)
> * `README_ZH.md` (4 hunks)
> * `biome.jsonc` (1 hunks)
> * `configs/babel-jest.config.json` (0 hunks)
> * `configs/babel.config.js` (0 hunks)
> * `configs/jest.config.json` (0 hunks)
> * `configs/rollup.config.js` (0 hunks)
> * `configs/swc-jest.config.json` (0 hunks)
> * `configs/ts-jest.config.json` (0 hunks)
> * `configs/tsconfig.base.json` (0 hunks)
> * `configs/tsconfig.cjs.json` (0 hunks)
> * `configs/tsconfig.esm.json` (0 hunks)
> * `configs/tsconfig.test.json` (0 hunks)
> * `configs/tsconfig.types.json` (0 hunks)
> * `configs/vitest.config.ts` (0 hunks)
> * `deno-build.mjs` (0 hunks)
> * `deno/lib/README.md` (0 hunks)
> * `deno/lib/ZodError.ts` (0 hunks)
> * `deno/lib/__tests__/Mocker.ts` (0 hunks)
> * `deno/lib/__tests__/all-errors.test.ts` (0 hunks)
> * `deno/lib/__tests__/anyunknown.test.ts` (0 hunks)
> * `deno/lib/__tests__/array.test.ts` (0 hunks)
> * `deno/lib/__tests__/async-parsing.test.ts` (0 hunks)
> * `deno/lib/__tests__/async-refinements.test.ts` (0 hunks)
> * `deno/lib/__tests__/base.test.ts` (0 hunks)
> * `deno/lib/__tests__/bigint.test.ts` (0 hunks)
> * `deno/lib/__tests__/branded.test.ts` (0 hunks)
> * `deno/lib/__tests__/complex.test.ts` (0 hunks)
> * `deno/lib/__tests__/crazySchema.ts` (0 hunks)
> * `deno/lib/__tests__/custom.test.ts` (0 hunks)
> * `deno/lib/__tests__/date.test.ts` (0 hunks)
> * `deno/lib/__tests__/deepmasking.test.ts` (0 hunks)
> * `deno/lib/__tests__/default.test.ts` (0 hunks)
> * `deno/lib/__tests__/description.test.ts` (0 hunks)
> * `deno/lib/__tests__/discriminated-unions.test.ts` (0 hunks)
> * `deno/lib/__tests__/enum.test.ts` (0 hunks)
> * `deno/lib/__tests__/error.test.ts` (0 hunks)
> * `deno/lib/__tests__/firstparty.test.ts` (0 hunks)
> * `deno/lib/__tests__/firstpartyschematypes.test.ts` (0 hunks)
> * `deno/lib/__tests__/function.test.ts` (0 hunks)
> * `deno/lib/__tests__/generics.test.ts` (0 hunks)
> * `deno/lib/__tests__/instanceof.test.ts` (0 hunks)
> * `deno/lib/__tests__/intersection.test.ts` (0 hunks)
> * `deno/lib/__tests__/literal.test.ts` (0 hunks)
> * `deno/lib/__tests__/map.test.ts` (0 hunks)
> * `deno/lib/__tests__/masking.test.ts` (0 hunks)
> * `deno/lib/__tests__/mocker.test.ts` (0 hunks)
> * `deno/lib/__tests__/nan.test.ts` (0 hunks)
> * `deno/lib/__tests__/nativeEnum.test.ts` (0 hunks)
> * `deno/lib/__tests__/nullable.test.ts` (0 hunks)
> * `deno/lib/__tests__/number.test.ts` (0 hunks)
> * `deno/lib/__tests__/object-augmentation.test.ts` (0 hunks)
> * `deno/lib/__tests__/object.test.ts` (0 hunks)
> * `deno/lib/__tests__/optional.test.ts` (0 hunks)
> * `deno/lib/__tests__/parseUtil.test.ts` (0 hunks)
> * `deno/lib/__tests__/parser.test.ts` (0 hunks)
> * `deno/lib/__tests__/partials.test.ts` (0 hunks)
> * `deno/lib/__tests__/pipeline.test.ts` (0 hunks)
> * `deno/lib/__tests__/preprocess.test.ts` (0 hunks)
> * `deno/lib/__tests__/primitive.test.ts` (0 hunks)
> * `deno/lib/__tests__/promise.test.ts` (0 hunks)
> * `deno/lib/__tests__/readonly.test.ts` (0 hunks)
> * `deno/lib/__tests__/record.test.ts` (0 hunks)
> * `deno/lib/__tests__/recursive.test.ts` (0 hunks)
> * `deno/lib/__tests__/refine.test.ts` (0 hunks)
> * `deno/lib/__tests__/safeparse.test.ts` (0 hunks)
> * `deno/lib/__tests__/set.test.ts` (0 hunks)
> * `deno/lib/__tests__/tuple.test.ts` (0 hunks)
> * `deno/lib/__tests__/unions.test.ts` (0 hunks)
> * `deno/lib/__tests__/validations.test.ts` (0 hunks)
> * `deno/lib/__tests__/void.test.ts` (0 hunks)
> * `deno/lib/benchmarks/datetime.ts` (0 hunks)
> * `deno/lib/benchmarks/discriminatedUnion.ts` (0 hunks)
> * `deno/lib/benchmarks/index.ts` (0 hunks)
> * `deno/lib/benchmarks/ipv4.ts` (0 hunks)
> * `deno/lib/benchmarks/object.ts` (0 hunks)
> * `deno/lib/benchmarks/primitives.ts` (0 hunks)
> * `deno/lib/benchmarks/realworld.ts` (0 hunks)
> * `deno/lib/benchmarks/string.ts` (0 hunks)
> * `deno/lib/benchmarks/union.ts` (0 hunks)
> * `deno/lib/errors.ts` (0 hunks)
> * `deno/lib/external.ts` (0 hunks)
> 
> </details>
> 
> ```ascii
>  ______________________________________________________________
> < How would you like your code review? Scrambled or over-easy? >
>  --------------------------------------------------------------
>   \
>    \   \
>         \ /\
>         ( )
>       .( o ).
> ```

<!-- end of auto-generated comment: review in progress by coderabbit.ai -->
<!-- usage_tips_start -->

> [!TIP]
> <details>
> <summary>You can disable poems in the walkthrough.</summary>
> 
> Disable the `reviews.poem` setting in your project's settings in CodeRabbit to disable the poems in the walkthrough.
> 
> </details>

<!-- usage_tips_end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=colinhacks/zod&utm_content=4298):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
netlify[bot]: ### <span aria-hidden="true">👷</span> Deploy Preview for *guileless-rolypoly-866f8a* processing.


|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | 0845a1ace6c7974774e80b8a33917f20c5822c2b |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/guileless-rolypoly-866f8a/deploys/6812c4cf43bdea0008dabe10 |

Patch:
diff --git a/packages/core/src/checks.ts b/packages/core/src/checks.ts
index 34378c23..83e5559d 100644
--- a/packages/core/src/checks.ts
+++ b/packages/core/src/checks.ts
@@ -266,7 +266,7 @@ export const $ZodCheckNumberFormat: core.$constructor<$ZodCheckNumberFormat> = /
 
     const isInt = def.format?.includes("int");
     const origin = isInt ? "int" : "number";
-    const [minimum, maximum] = util.NUMBER_FORMAT_RANGES[def.format!];
+    const [minimum, maximum] = util.NUMBER_FORMAT_RANGES[def.format];
 
     inst._zod.onattach.push((inst) => {
       inst._zod.computed.format = def.format;
diff --git a/packages/core/src/regexes.ts b/packages/core/src/regexes.ts
index e9cbd00d..f1638225 100644
--- a/packages/core/src/regexes.ts
+++ b/packages/core/src/regexes.ts
@@ -1,6 +1,6 @@
 export const cuid: RegExp = /^[cC][^\s-]{8,}$/;
 export const cuid2: RegExp = /^[0-9a-z]+$/;
-export const ulid: RegExp = /^[0-9A-HJKMNP-TV-Z]{26}$/;
+export const ulid: RegExp = /^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/;
 export const xid: RegExp = /^[0-9a-vA-V]{20}$/;
 export const ksuid: RegExp = /^[A-Za-z0-9]{27}$/;
 export const nanoid: RegExp = /^[a-zA-Z0-9_-]{21}$/;
diff --git a/packages/core/src/versions.ts b/packages/core/src/versions.ts
index 61ecbf32..7b33c9bb 100644
--- a/packages/core/src/versions.ts
+++ b/packages/core/src/versions.ts
@@ -1,5 +1,5 @@
 export const version = {
   major: 0,
   minor: 10,
-  patch: 0 as number,
+  patch: 1 as number,
 } as const;
diff --git a/packages/docs/content/error-formatting.mdx b/packages/docs/content/error-formatting.mdx
index 6a48d1cd..d760163d 100644
--- a/packages/docs/content/error-formatting.mdx
+++ b/packages/docs/content/error-formatting.mdx
@@ -10,7 +10,7 @@ Zod emphasizes _completeness_ and _correctness_ in its error reporting. In many
 Consider this simple object schema.
 
 ```ts
-const schema = z.object({
+const schema = z.strictObject({
   username: z.string(),
   favoriteNumbers: z.array(z.number()),
 });
@@ -22,6 +22,7 @@ Attempting to parse this invalid data results in an error containing two issues.
 const result = schema.safeParse({
   username: 1234,
   favoriteNumbers: [1234, "4567"],
+  extraKey: 1234,
 });
 
 result.error!.issues;
diff --git a/packages/docs/content/packages/mini.mdx b/packages/docs/content/packages/mini.mdx
index 1127c3bb..adb469b0 100644
--- a/packages/docs/content/packages/mini.mdx
+++ b/packages/docs/content/packages/mini.mdx
@@ -22,7 +22,7 @@ const mySchema = z.nullable(z.optional(z.string()));
 </Tab>
 <Tab value="zod">
 ```ts
-import * as z from "@zod/mini";
+import { z } from "zod";
 
 const mySchema = z.string().optional().nullable();
 ```
diff --git a/packages/docs/content/v4/changelog.mdx b/packages/docs/content/v4/changelog.mdx
index de2b14c1..1adfb1bc 100644
--- a/packages/docs/content/v4/changelog.mdx
+++ b/packages/docs/content/v4/changelog.mdx
@@ -309,8 +309,10 @@ type schemaInput = z.input<typeof schema>;
 
 These modifier methods on the `ZodObject` class determine how the schema handles unknown keys. In Zod 4, this functionality now exists in top-level functions. This aligns better with Zod's declarative-first philosophy, and puts all object variants on equal footing. 
 
-### deprecates `.strict()`
 
+### discourages `.strict()`
+
+> The `.strict()` method is discouraged but not deprecat4ed. It won't be removed. 
 ```ts
 // Zod 3
 z.object({ name: z.string() }).strict();
diff --git a/packages/zod/src/schemas.ts b/packages/zod/src/schemas.ts
index 4255cb4e..d7ec6630 100644
--- a/packages/zod/src/schemas.ts
+++ b/packages/zod/src/schemas.ts
@@ -665,7 +665,7 @@ export interface _ZodNumber<Input = unknown> extends ZodType {
   max(value: number, params?: string | core.$ZodCheckLessThanParams): this;
   /** Consider `z.int()` instead. This API is considered *legacy*; it will never be removed but a better alternative exists. */
   int(params?: string | core.$ZodCheckNumberFormatParams): this;
-  /** @deprecated This is now identical to `.int()` instead. Only numbers in the safe integer range are accepted. */
+  /** @deprecated This is now identical to `.int()`. Only numbers in the safe integer range are accepted. */
   safe(params?: string | core.$ZodCheckNumberFormatParams): this;
   positive(params?: string | core.$ZodCheckGreaterThanParams): this;
   nonnegative(params?: string | core.$ZodCheckGreaterThanParams): this;
@@ -1089,6 +1089,7 @@ export interface ZodInterface<
       extra: Record<string, T["_zod"]["output"]>;
     }
   >;
+  /** Consider `z.strictObject({ ...A.shape })` instead. */
   strict(): ZodInterface<
     Shape,
     {
@@ -1097,6 +1098,7 @@ export interface ZodInterface<
       extra: {};
     }
   >;
+
   loose(): ZodInterface<
     Shape,
     {
@@ -1105,6 +1107,8 @@ export interface ZodInterface<
       extra: Record<string, unknown>;
     }
   >;
+
+  /**  Use `z.looseObject({ ...A.shape })` instead. */
   strip(): ZodInterface<
     Shape,
     {
@@ -1257,17 +1261,18 @@ export interface ZodObject<
   shape: Shape;
 
   keyof(): ZodEnum<util.ToEnum<keyof Shape & string>>;
+  /** Define a schema to validate all unrecognized keys. This overrides the existing strict/loose behavior. */
   catchall<T extends core.$ZodType>(schema: T): ZodObject<Shape, Record<string, T["_zod"]["output"]>>;
 
   /** @deprecated Use `z.looseObject()` or `.loose()` instead. */
   passthrough(): ZodObject<Shape, Record<string, unknown>>;
-
+  /** Consider `z.looseObject(A.shape)` instead */
   loose(): ZodObject<Shape, Record<string, unknown>>;
 
-  /** The `z.strictObject()` API is preferred. */
+  /** Consider `z.strictObject(A.shape)` instead */
   strict(): ZodObject<Shape, {}>;
 
-  /** @deprecated This is the default behavior. This method call is likely unnecessary. */
+  /** This is the default behavior. This method call is likely unnecessary. */
   strip(): ZodObject<Shape, {}>;
 
   extend<const U extends ZodObject>(schema: U): ZodObject<util.Extend<Shape, U["_zod"]["def"]["shape"]>, Extra>;
@@ -1279,7 +1284,7 @@ export interface ZodObject<
   >;
 
   // merge
-  /** @deprecated Use `A.extend(B)` */
+  /** @deprecated Use `A.extend(B.shape)` */
   merge<U extends ZodObject<any, any>>(
     other: U
   ): ZodObject<util.Flatten<util.Extend<Shape, U["_zod"]["def"]["shape"]>>, Extra>;
diff --git a/play.ts b/play.ts
index 4253b9f5..55bbac99 100644
--- a/play.ts
+++ b/play.ts
@@ -1,11 +1,12 @@
-import * as z from "@zod/mini";
+import * as z from "zod";
 
-// console.log(z.int().min(0).parse(234));
+z;
 
-console.log(z.number().safe().parse(123.0));
+const frozenLetters = Object.freeze(["a", "b"]);
+const lettersAsConst = ["a", "b"] as const;
 
-z.number().safe();
+const frozenLettersParser = z.enum(frozenLetters);
+const lettersAsConstParser = z.enum(lettersAsConst);
 
-z.core.$ZodCustom;
-
-z._default;
+console.log(frozenLettersParser.safeParse("a"));
+console.log(lettersAsConstParser.safeParse("a"));


Test patch:
diff --git a/packages/zod/tests/json-schema.test.ts b/packages/zod/tests/json-schema.test.ts
index a4210b9c..b050897f 100644
--- a/packages/zod/tests/json-schema.test.ts
+++ b/packages/zod/tests/json-schema.test.ts
@@ -145,7 +145,7 @@ describe("toJSONSchema", () => {
     expect(toJSONSchema(z.ulid())).toMatchInlineSnapshot(`
       {
         "format": "ulid",
-        "pattern": "^[0-9A-HJKMNP-TV-Z]{26}$",
+        "pattern": "^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$",
         "type": "string",
       }
     `);
diff --git a/packages/zod/tests/string.test.ts b/packages/zod/tests/string.test.ts
index b7388f42..a1313fd9 100644
--- a/packages/zod/tests/string.test.ts
+++ b/packages/zod/tests/string.test.ts
@@ -492,6 +492,9 @@ test("ulid", () => {
   const tooLong = "01ARZ3NDEKTSV4RRFFQ69G5FAVA";
   expect(ulid.safeParse(tooLong)).toMatchObject({ success: false });
 
+  const caseInsensitive = ulid.safeParse("01arZ3nDeKTsV4RRffQ69G5FAV");
+  expect(caseInsensitive.success).toEqual(true);
+
   expect(result.error!.issues[0].message).toEqual("Invalid ULID");
   expect(result.error).toMatchInlineSnapshot(`
     ZodError {
@@ -502,7 +505,7 @@ test("ulid", () => {
           "message": "Invalid ULID",
           "origin": "string",
           "path": [],
-          "pattern": "/^[0-9A-HJKMNP-TV-Z]{26}$/",
+          "pattern": "/^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/",
         },
       ],
     }
diff --git a/packages/zod/tests/template-literal.test.ts b/packages/zod/tests/template-literal.test.ts
index a011d7e3..ad17d6f7 100644
--- a/packages/zod/tests/template-literal.test.ts
+++ b/packages/zod/tests/template-literal.test.ts
@@ -565,7 +565,7 @@ test("regexes", () => {
   expect(ipv6._zod.pattern.source).toMatchInlineSnapshot(
     `"^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})$"`
   );
-  expect(ulid._zod.pattern.source).toMatchInlineSnapshot(`"^[0-9A-HJKMNP-TV-Z]{26}$"`);
+  expect(ulid._zod.pattern.source).toMatchInlineSnapshot(`"^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$"`);
   expect(uuid._zod.pattern.source).toMatchInlineSnapshot(
     `"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000)$"`
   );