Repository: colinhacks/zod
Pull request #4267 (2025-04-23 11:45:09)

V4(fix): generate json-schema with min/max(0)
This pull request solves the problem of generating a json schema when the minimum/maximum is zero and does not fall into the schema.

```ts
import { z } from 'zod';

const User = z.strictObject({
  gt: z.number().gt(0),
  gte: z.number().gte(0),

  lt: z.number().lt(0),
  lte: z.number().lte(0),

  positive: z.number().positive(),
  negative: z.number().negative(),

  str: z.string().min(0),
  arr: z.array(z.number()).min(0),
});

console.dir(z.toJSONSchema(User), {depth: null});
```

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

> [!IMPORTANT]
> ## Review skipped
> 
> Auto reviews are disabled on base/target branches other than the default branch.
> 
> 
> 
> Please check the settings in the CodeRabbit UI or the `.coderabbit.yaml` file in this repository. To trigger a single review, invoke the `@coderabbitai review` command.
> 
> You can disable this status message by setting the `reviews.review_status` to `false` in the CodeRabbit configuration file.

<!-- end of auto-generated comment: skip review by coderabbit.ai -->
<!-- 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=4267):

- 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.`

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 -->
RobinTail: @PandaWorker , consider reverting code style changes that are not related to the actual fix.
Thus, you'd also fix the linting issue that is currently blocking this PR.

Very important fix, @colinhacks 

Patch:
diff --git a/packages/core/src/api.ts b/packages/core/src/api.ts
index 8ce68fcb..1b911ec4 100644
--- a/packages/core/src/api.ts
+++ b/packages/core/src/api.ts
@@ -1005,130 +1005,7 @@ export function _array<T extends schemas.$ZodType>(
   }) as schemas.$ZodArray<T>;
 }
 
-// ZodObjectLike
-export type $ZodObjectLikeParams = util.TypeParams<schemas.$ZodObjectLike, "shape" | "catchall">;
-
-export type $ZodInterfaceParams = util.TypeParams<schemas.$ZodInterface, "shape">;
-export function _interface<T extends schemas.$ZodLooseShape>(
-  Class: util.SchemaClass<schemas.$ZodInterface>,
-  shape: T,
-  params?: $ZodInterfaceParams
-): schemas.$ZodInterface<util.CleanInterfaceShape<T>, util.InitInterfaceParams<T, {}>> {
-  const cleaned = util.cached(() => util.cleanInterfaceShape(shape));
-  const def: schemas.$ZodInterfaceDef = {
-    type: "interface",
-    get shape() {
-      const _shape = cleaned.value.shape;
-      util.assignProp(this, "shape", _shape);
-      return _shape;
-      // return cleaned.value.shape;
-    },
-    get optional() {
-      return cleaned.value.optional;
-    },
-    ...util.normalizeParams(params),
-  };
-  return new Class(def) as any;
-}
-
-// strictInterface
-export function _strictInterface<T extends schemas.$ZodLooseShape>(
-  Class: util.SchemaClass<schemas.$ZodInterface>,
-  shape: T,
-  params?: $ZodInterfaceParams
-): schemas.$ZodInterface<util.CleanInterfaceShape<T>, util.InitInterfaceParams<T, {}>> {
-  const cleaned = util.cached(() => util.cleanInterfaceShape(shape));
-  const def: schemas.$ZodInterfaceDef = {
-    type: "interface",
-    get shape() {
-      const _shape = cleaned.value.shape;
-      util.assignProp(this, "shape", _shape);
-      return _shape;
-      // return cleaned.value.shape;
-    },
-    get optional() {
-      return cleaned.value.optional;
-    },
-    catchall: _never(schemas.$ZodNever),
-    ...util.normalizeParams(params),
-  };
-  return new Class(def) as any;
-}
-
-// looseInterface
-export function _looseInterface<T extends schemas.$ZodLooseShape>(
-  Class: util.SchemaClass<schemas.$ZodInterface>,
-  shape: T,
-  params?: $ZodInterfaceParams
-): schemas.$ZodInterface<util.CleanInterfaceShape<T>, util.InitInterfaceParams<T, Record<string, unknown>>> {
-  const cleaned = util.cached(() => util.cleanInterfaceShape(shape));
-  const def: schemas.$ZodInterfaceDef = {
-    type: "interface",
-    get optional() {
-      return cleaned.value.optional;
-    },
-    get shape() {
-      const _shape = cleaned.value.shape;
-      util.assignProp(this, "shape", _shape);
-      return _shape;
-      // return cleaned.value.shape;
-    },
-    catchall: _unknown(schemas.$ZodUnknown),
-    ...util.normalizeParams(params),
-  };
-  return new Class(def) as any;
-}
-
 export type $ZodObjectParams = util.TypeParams<schemas.$ZodObject, "shape" | "catchall">;
-export function _object<T extends schemas.$ZodShape = Record<never, schemas.$ZodObject>>(
-  Class: util.SchemaClass<schemas.$ZodObject>,
-  shape?: T,
-  params?: $ZodObjectLikeParams
-): schemas.$ZodObject<T, {}> {
-  const def: schemas.$ZodObjectDef = {
-    type: "object",
-    shape: shape ?? {},
-    get optional() {
-      return util.optionalObjectKeys(shape ?? {});
-    },
-    ...util.normalizeParams(params),
-  };
-  return new Class(def) as any;
-}
-
-// strictObject
-export function _strictObject<T extends schemas.$ZodShape>(
-  Class: util.SchemaClass<schemas.$ZodObject>,
-  shape: T,
-  params?: $ZodObjectParams
-): schemas.$ZodObject<T, {}> {
-  return new Class({
-    type: "object",
-    shape: shape as schemas.$ZodShape,
-    get optional() {
-      return util.optionalObjectKeys(shape);
-    },
-    catchall: _never(schemas.$ZodNever),
-    ...util.normalizeParams(params),
-  }) as any;
-}
-
-// looseObject
-export function _looseObject<T extends schemas.$ZodShape>(
-  Class: util.SchemaClass<schemas.$ZodObject>,
-  shape: T,
-  params?: $ZodObjectParams
-): schemas.$ZodObject<T, { [k: string]: unknown }> {
-  return new Class({
-    type: "object",
-    shape: shape as schemas.$ZodShape,
-    get optional() {
-      return util.optionalObjectKeys(shape);
-    },
-    catchall: _unknown(schemas.$ZodUnknown),
-    ...util.normalizeParams(params),
-  }) as any;
-}
 
 // ZodUnion
 export type $ZodUnionParams = util.TypeParams<schemas.$ZodUnion, "options">;
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/core.ts b/packages/core/src/core.ts
index 512cd2fe..ea17c872 100644
--- a/packages/core/src/core.ts
+++ b/packages/core/src/core.ts
@@ -1,6 +1,5 @@
 import type * as errors from "./errors.js";
 import type * as schemas from "./schemas.js";
-
 //////////////////////////////   CONSTRUCTORS   ///////////////////////////////////////
 
 type ZodTrait = { _zod: { def: any; [k: string]: any } };
@@ -59,8 +58,12 @@ export class $ZodAsyncError extends Error {
 
 ////////////////////////////  TYPE HELPERS  ///////////////////////////////////
 
-export type input<T extends schemas.$ZodType> = T["_zod"]["input"];
-export type output<T extends schemas.$ZodType> = T["_zod"]["output"];
+export type input<T extends schemas.$ZodType> = T["_zod"] extends { "~input": any }
+  ? T["_zod"]["~input"]
+  : T["_zod"]["input"];
+export type output<T extends schemas.$ZodType> = T["_zod"] extends { "~output": any }
+  ? T["_zod"]["~output"]
+  : T["_zod"]["output"];
 export type { output as infer };
 
 //////////////////////////////   CONFIG   ///////////////////////////////////////
diff --git a/packages/core/src/json-schema.ts b/packages/core/src/json-schema.ts
index 486a3ac7..6ca2d6e1 100644
--- a/packages/core/src/json-schema.ts
+++ b/packages/core/src/json-schema.ts
@@ -11,7 +11,6 @@ export type Schema =
 export interface BaseSchema {
   /** A special key used as an intermediate representation of extends-style relationships. Removed in the omit stage. */
   _ref?: BaseSchema;
-
   type?: string | undefined;
   $id?: string | undefined;
   id?: string | undefined;
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/schemas.ts b/packages/core/src/schemas.ts
index 5d642ed3..9f0f8c6c 100644
--- a/packages/core/src/schemas.ts
+++ b/packages/core/src/schemas.ts
@@ -79,21 +79,31 @@ export interface $ZodTypeDef {
   checks?: checks.$ZodCheck<never>[];
 }
 
-export interface $ZodTypeInternals<out O = unknown, out I = unknown> extends $ZodType<O, I> {
+export const $out: unique symbol = Symbol("out");
+export type $out = typeof $out;
+export const $in: unique symbol = Symbol("in");
+export type $in = typeof $in;
+
+// @ts-ignore
+export interface $ZodTypeInternals<out O = unknown, out I = unknown> {
   /** The `@zod/core` version of this schema */
   version: typeof version;
 
   /** Schema internals. */
   def: $ZodTypeDef;
+  // types: Types;
 
   /** Randomly generated ID for this schema. */
   id: string;
 
-  /** The inferred output typre */
-  output: O;
-
+  /** The inferred output type */
+  // "
+  // "?: any;
+  // "~input"?: any;
+  // "~types"?: any;
+  output: O; //extends { $out: infer O } ? O : Out;
   /** The inferred input type */
-  input: I;
+  input: I; //extends { $in: infer I } ? I : In;
 
   /** List of deferred initializers. */
   deferred: util.AnyFunc[] | undefined;
@@ -107,11 +117,10 @@ export interface $ZodTypeInternals<out O = unknown, out I = unknown> extends $Zo
   /** Stores identifiers for the set of traits implemented by this schema. */
   traits: Set<string>;
 
-  /** Indicates that a schema output type should be considered optional inside objects.  */
-  qout: "true" | undefined;
-
-  /** Indicates that a schema input type should be considered optional inside objects. */
-  qin: "true" | undefined;
+  /** Indicates that a schema output type should be considered optional inside objects.
+   * @default Required
+   */
+  optionality?: "optional" | "defaulted" | undefined;
 
   /** A set of literal discriminators used for the fast path in discriminated unions. */
   disc: util.DiscriminatorMap | undefined;
@@ -145,9 +154,20 @@ export interface $ZodTypeInternals<out O = unknown, out I = unknown> extends $Zo
   parent?: $ZodType | undefined;
 }
 
-export interface $ZodType<out O = unknown, out I = unknown> {
+// export interface $ZodTypeInternals<out O = unknown, out I = unknown> extends $ZodTypeInternals {
+//   // "~types": { output: O; input: I };
+//   output: O;
+//   input: I;
+// }
+
+// export interface _$ZodType {
+//   _zod: $ZodTypeInternals;
+//   "~standard": StandardSchemaV1.Props<core.input<this>, core.output<this>>;
+// }
+
+export interface $ZodType<O = unknown, I = unknown> {
   _zod: $ZodTypeInternals<O, I>;
-  "~standard": StandardSchemaV1.Props<this["_zod"]["input"], this["_zod"]["output"]>;
+  "~standard": StandardSchemaV1.Props<core.input<this>, core.output<this>>;
 }
 
 export const $ZodType: core.$constructor<$ZodType> = /*@__PURE__*/ core.$constructor("$ZodType", (inst, def) => {
@@ -156,9 +176,9 @@ export const $ZodType: core.$constructor<$ZodType> = /*@__PURE__*/ core.$constru
   inst._zod.def = def; // set _def property
   inst._zod.computed = inst._zod.computed || {}; // initialize _computed object
   inst._zod.version = version;
+  // inst._zod.optionality ??= "required"; // default
 
   const checks = [...(inst._zod.def.checks ?? [])];
-  def.type;
 
   // if inst is itself a checks.$ZodCheck, run it as a check
   if (inst._zod.traits.has("$ZodCheck")) {
@@ -243,11 +263,15 @@ export const $ZodType: core.$constructor<$ZodType> = /*@__PURE__*/ core.$constru
       if (result instanceof Promise) {
         return result.then(({ issues, value }) => {
           if (issues.length === 0) return { value } as any;
-          return { issues: issues.map((iss) => util.finalizeIssue(iss, {}, core.config())) };
+          return {
+            issues: issues.map((iss) => util.finalizeIssue(iss, {}, core.config())),
+          };
         });
       }
       if (result.issues.length === 0) return { value: result.value } as any;
-      return { issues: result.issues.map((iss) => util.finalizeIssue(iss, {}, core.config())) };
+      return {
+        issues: result.issues.map((iss) => util.finalizeIssue(iss, {}, core.config())),
+      };
     },
     vendor: "zod",
     version: 1 as const,
@@ -1387,7 +1411,7 @@ export interface $ZodArrayDef<T extends $ZodType = $ZodType> extends $ZodTypeDef
 }
 
 export interface $ZodArrayInternals<T extends $ZodType = $ZodType>
-  extends $ZodTypeInternals<T["_zod"]["output"][], T["_zod"]["input"][]> {
+  extends $ZodTypeInternals<core.output<T>[], core.input<T>[]> {
   def: $ZodArrayDef<T>;
   isst: errors.$ZodIssueInvalidType;
 }
@@ -1423,7 +1447,6 @@ export const $ZodArray: core.$constructor<$ZodArray> = /*@__PURE__*/ core.$const
     const proms: Promise<any>[] = [];
     for (let i = 0; i < input.length; i++) {
       const item = input[i];
-
       const result = def.element._zod.run(
         {
           value: item,
@@ -1450,29 +1473,70 @@ export const $ZodArray: core.$constructor<$ZodArray> = /*@__PURE__*/ core.$const
 //////////////////////////////////////////
 //////////////////////////////////////////
 //////////                      //////////
-//////////      $ZodObjectLike      //////////
+//////////      $ZodObject      //////////
 //////////                      //////////
 //////////////////////////////////////////
 //////////////////////////////////////////
 
 export type $ZodShape = Readonly<{ [k: string]: $ZodType }>;
+// export type $ZodShapeMetaValue<T extends $ZodType = $ZodType> = {
+//   type: T;
+//   optionality?: "optional" | "defaulted" | undefined;
+// };
+// export type $ZodShapeMeta<T extends $ZodShape = $ZodShape> = Readonly<{ [k in keyof T]: $ZodShapeMetaValue<T[k]> }>;
 
-export interface $ZodObjectLikeDef<out Shape extends $ZodShape = $ZodShape> extends $ZodTypeDef {
-  type: "object" | "interface";
+export interface $ZodObjectDef<Shape extends $ZodShape = $ZodShape> extends $ZodTypeDef {
+  type: "object";
   shape: Shape;
-  optional: string[];
   catchall?: $ZodType | undefined;
 }
 
-export interface $ZodObjectLikeInternals<out O = object, out I = object> extends $ZodTypeInternals<O, I> {
-  def: $ZodObjectLikeDef;
-  // shape: $ZodShape;
-  extra: Record<string, unknown>;
-  optional: string;
-  defaulted: string;
+export interface $ZodObjectInternals<
+  Shape extends Readonly<$ZodShape> = Readonly<$ZodShape>,
+  out OutExtra extends Record<string, unknown> = Record<string, unknown>,
+  out InExtra extends Record<string, unknown> = Record<string, unknown>,
+> extends $ZodTypeInternals<any, any> {
+  def: $ZodObjectDef<Shape>;
+  outextra: OutExtra;
+  inextra: InExtra;
   isst: errors.$ZodIssueInvalidType | errors.$ZodIssueUnrecognizedKeys;
   disc: util.DiscriminatorMap;
+
+  // special keys only used for objects
+  // not defined on $ZodTypeInternals (base interface) because it breaks cyclical inference
+  // the z.infer<> util checks for these first when extracting inferred type
+  "~output": $InferObjectOutput<Shape, OutExtra>;
+  "~input": $InferObjectInput<Shape, InExtra>;
 }
+export type $ZodLooseShape = Record<string, any>;
+
+type OptionalOutSchema = { _zod: { optionality: "optional" } };
+type OptionalInSchema = { _zod: { optionality: "defaulted" | "optional" } };
+
+export type $InferObjectOutput<T extends $ZodLooseShape, Extra extends Record<string, unknown>> = string extends keyof T
+  ? object
+  : keyof T extends never
+    ? object
+    : util.Prettify<
+        {
+          -readonly [k in keyof T as T[k] extends OptionalOutSchema ? never : k]: core.output<T[k]>;
+        } & {
+          -readonly [k in keyof T as T[k] extends OptionalOutSchema ? k : never]?: core.output<T[k]>;
+        }
+      > &
+        Extra;
+
+export type $InferObjectInput<T extends $ZodLooseShape, Extra extends Record<string, unknown>> = string extends keyof T
+  ? object
+  : keyof T extends never
+    ? object
+    : util.Prettify<
+        {
+          [k in keyof T as T[k] extends OptionalInSchema ? never : k]: core.input<T[k]>;
+        } & {
+          [k in keyof T as T[k] extends OptionalInSchema ? k : never]?: core.input<T[k]>;
+        } & Extra
+      >;
 
 function handleObjectResult(result: ParsePayload, final: ParsePayload, key: PropertyKey) {
   // if(isOptional)
@@ -1503,145 +1567,96 @@ function handleOptionalObjectResult(result: ParsePayload, final: ParsePayload, k
   }
 }
 
-export interface $ZodObjectLike<O = object, I = object> extends $ZodType {
-  _zod: $ZodObjectLikeInternals<O, I>;
+export interface $ZodObject<
+  Shape extends Readonly<$ZodShape> = Readonly<$ZodShape>,
+  OutExtra extends Record<string, unknown> = Record<string, unknown>,
+  InExtra extends Record<string, unknown> = Record<string, unknown>,
+> extends $ZodType {
+  _zod: $ZodObjectInternals<Shape, OutExtra, InExtra>;
 }
 
-export const $ZodObjectLike: core.$constructor<$ZodObjectLike> = /*@__PURE__*/ core.$constructor(
-  "$ZodObjectLike",
-  (inst, def) => {
-    $ZodType.init(inst, def);
-    // util.defineLazy(inst._zod, "shape", () => def.shape);
-
-    const _normalized = util.cached(() => {
-      const keys = Object.keys(def.shape);
-      return {
-        shape: def.shape,
-        keys,
-        keySet: new Set(keys),
-        numKeys: keys.length,
-        optionalKeys: new Set(def.optional),
-      };
-    });
+export const $ZodObject: core.$constructor<$ZodObject> = /*@__PURE__*/ core.$constructor("$ZodObject", (inst, def) => {
+  $ZodType.init(inst, def);
+  // util.defineLazy(inst._zod, "shape", () => def.shape);
+
+  const _normalized = util.cached(() => {
+    const keys = Object.keys(def.shape);
+    const okeys = util.optionalObjectKeys(def.shape);
+    return {
+      shape: def.shape,
+      keys,
+      keySet: new Set(keys),
+      numKeys: keys.length,
+      optionalKeys: new Set(okeys),
+    };
+  });
 
-    util.defineLazy(inst._zod, "disc", () => {
-      const shape = def.shape;
-      const discMap: util.DiscriminatorMap = new Map();
-      let hasDisc = false;
-      for (const key in shape) {
-        const field = shape[key]._zod;
-        if (field.values || field.disc) {
-          hasDisc = true;
-          const o: util.DiscriminatorMapElement = {
-            values: new Set(field.values ?? []),
-            maps: field.disc ? [field.disc] : [],
-          };
-          discMap.set(key, o);
-        }
-      }
-      if (!hasDisc) {
-        return undefined as any;
+  util.defineLazy(inst._zod, "disc", () => {
+    const shape = def.shape;
+    const discMap: util.DiscriminatorMap = new Map();
+    let hasDisc = false;
+    for (const key in shape) {
+      const field = shape[key]._zod;
+      if (field.values || field.disc) {
+        hasDisc = true;
+        const o: util.DiscriminatorMapElement = {
+          values: new Set(field.values ?? []),
+          maps: field.disc ? [field.disc] : [],
+        };
+        discMap.set(key, o);
       }
-      return discMap;
-    });
+    }
+    if (!hasDisc) {
+      return undefined as any;
+    }
+    return discMap;
+  });
 
-    const generateFastpass = (shape: any) => {
-      const doc = new Doc(["shape", "payload", "ctx"]);
-      const { keys, optionalKeys } = _normalized.value;
-      const parseStr = (key: string) => {
-        const k = util.esc(key);
-        return `shape[${k}]._zod.run({ value: input[${k}], issues: [] }, ctx)`;
-      };
+  const generateFastpass = (shape: any) => {
+    const doc = new Doc(["shape", "payload", "ctx"]);
+    const { keys, optionalKeys } = _normalized.value;
+
+    const parseStr = (key: string) => {
+      const k = util.esc(key);
+      return `shape[${k}]._zod.run({ value: input[${k}], issues: [] }, ctx)`;
+    };
 
-      // doc.write(`const shape = inst._zod.def.shape;`);
-      doc.write(`const input = payload.value;`);
+    // doc.write(`const shape = inst._zod.def.shape;`);
+    doc.write(`const input = payload.value;`);
 
-      const ids: any = {};
-      for (const key of keys) {
-        ids[key] = util.randomString(15);
-      }
-      for (const key of keys) {
-        if (optionalKeys.has(key)) continue;
-        const id = ids[key];
-        doc.write(`const ${id} = ${parseStr(key)};`);
-        doc.write(`
+    const ids: any = {};
+    for (const key of keys) {
+      ids[key] = util.randomString(15);
+    }
+    for (const key of keys) {
+      if (optionalKeys.has(key)) continue;
+      const id = ids[key];
+      doc.write(`const ${id} = ${parseStr(key)};`);
+      doc.write(`
           if (${id}.issues.length) payload.issues = payload.issues.concat(${id}.issues.map(iss => ({
             ...iss,
             path: iss.path ? [${util.esc(key)}, ...iss.path] : [${util.esc(key)}]
           })));`);
-      }
+    }
 
-      // check for missing keys
-      // for (const key of keys) {
-      //   if (optionalKeys.has(key)) continue;
-      //   doc.write(`if(!(${util.esc(key)} in input)) {`);
-      //   doc.indented(() => {
-      //     doc.write(`payload.issues.push({`);
-      //     doc.indented(() => {
-      //       doc.write(`code: "invalid_type",`);
-      //       doc.write(`path: [${util.esc(key)}],`);
-      //       doc.write(`expected: "nonoptional",`);
-      //       doc.write(`note: 'Missing required key: "${key}"',`);
-      //       doc.write(`input,`);
-      //       doc.write(`inst,`);
-      //     });
-      //     doc.write(`});`);
-      //   });
-      //   doc.write(`}`);
-      // }
-
-      // add required keys to result
-      // doc.write(`return payload;`);
-      // doc.write(`if(Object.keys(input).length === ${keys.length}) {
-      //   payload.value = {...input};
-      //   return payload;
-      // }`);
-      doc.write(`payload.value = {`);
-      doc.indented(() => {
-        for (const key of keys) {
-          if (optionalKeys.has(key)) continue;
-          const id = ids[key];
-          doc.write(`  ${util.esc(key)}: ${id}.value,`);
-          // doc.write(`payload.value[${util.esc(key)}] = ${id}.value;`);
-        }
-      });
-      doc.write(`}`);
-
-      // add in optionalKeys if defined
-
-      // OLD: only run validation if they are define in input
-      // for (const key of keys) {
-      //   if (!optionalKeys.has(key)) continue;
-      //   const id = ids[key];
-      //   doc.write(`if (${util.esc(key)} in input) {`);
-      //   doc.indented(() => {
-      //     doc.write(`if(input[${util.esc(key)}] === undefined) {`);
-      //     doc.indented(() => {
-      //       doc.write(`payload.value[${util.esc(key)}] = undefined;`);
-      //     });
-      //     doc.write(`} else {`);
-      //     doc.indented(() => {
-      //       doc.write(`const ${id} = ${parseStr(key)};`);
-      //       doc.write(`payload.value[${util.esc(key)}] = ${id}.value;`);
-      //       doc.write(`
-      //         if (${id}.issues.length) payload.issues = payload.issues.concat(${id}.issues.map(iss => ({
-      //           ...iss,
-      //           path: iss.path ? [${util.esc(key)}, ...iss.path] : [${util.esc(key)}]
-      //         })));`);
-      //     });
-      //     doc.write(`}`);
-      //   });
-      //   doc.write(`}`);
-      // }
-
-      // NEW: always run validation
-      // this lets default values get applied to optionals
+    doc.write(`payload.value = {`);
+    doc.indented(() => {
       for (const key of keys) {
-        if (!optionalKeys.has(key)) continue;
+        if (optionalKeys.has(key)) continue;
         const id = ids[key];
-        doc.write(`const ${id} = ${parseStr(key)};`);
-        const k = util.esc(key);
-        doc.write(`
+        doc.write(`  ${util.esc(key)}: ${id}.value,`);
+      }
+    });
+    doc.write(`}`);
+
+    // NEW: always run validation
+    // this lets default values get applied to optionals
+    for (const key of keys) {
+      if (!optionalKeys.has(key)) continue;
+      const id = ids[key];
+      doc.write(`const ${id} = ${parseStr(key)};`);
+      const k = util.esc(key);
+      doc.write(`
         if (${id}.issues.length) {
           if (input[${k}] === undefined) {
             if (${k} in input) {
@@ -1661,268 +1676,116 @@ export const $ZodObjectLike: core.$constructor<$ZodObjectLike> = /*@__PURE__*/ c
           payload.value[${k}] = ${id}.value;
         }  
         `);
-      }
+    }
 
-      // doc.write(`payload.value = final;`);
-      doc.write(`return payload;`);
-      // return doc.compile().bind(null, shape);
-      const fn = doc.compile();
-      return (payload: any, ctx: any) => fn(shape, payload, ctx);
-      // return fn.bind(null, _inst._zod.def.shape);
-    };
+    doc.write(`return payload;`);
+    const fn = doc.compile();
+    return (payload: any, ctx: any) => fn(shape, payload, ctx);
+  };
 
-    let fastpass!: ReturnType<typeof generateFastpass>;
-    const fastEnabled = util.allowsEval.value; // && !def.catchall;
-    const isObject = util.isObject;
-    const { catchall } = def;
+  let fastpass!: ReturnType<typeof generateFastpass>;
+  const fastEnabled = util.allowsEval.value; // && !def.catchall;
+  const isObject = util.isObject;
+  const { catchall } = def;
 
-    let value!: typeof _normalized.value;
+  let value!: typeof _normalized.value;
 
-    // const noCatchall = !def.catchall;
+  inst._zod.parse = (payload, ctx) => {
+    value ??= _normalized.value;
+    const input = payload.value;
+    if (!isObject(input)) {
+      payload.issues.push({
+        expected: "object",
+        code: "invalid_type",
+        input,
+        inst,
+      });
+      return payload;
+    }
 
-    inst._zod.parse = (payload, ctx) => {
-      value ??= _normalized.value;
-      const input = payload.value;
-      if (!isObject(input)) {
-        payload.issues.push({
-          expected: "object",
-          code: "invalid_type",
-          input,
-          inst,
-        });
-        return payload;
-      }
+    const proms: Promise<any>[] = [];
+
+    if (fastEnabled && ctx?.async === false && ctx.noPrecompilation !== true) {
+      // always synchronous
+      if (!fastpass) fastpass = generateFastpass(def.shape);
+      payload = fastpass(payload, ctx);
+    } else {
+      payload.value = {};
 
-      const proms: Promise<any>[] = [];
+      const shape = value.shape;
+      for (const key of value.keys) {
+        const el = shape[key];
+
+        // do not add omitted optional keys
+        // if (!(key in input)) {
+        //   if (optionalKeys.has(key)) continue;
+        //   payload.issues.push({
+        //     code: "invalid_type",
+        //     path: [key],
+        //     expected: "nonoptional",
+        //     note: `Missing required key: "${key}"`,
+        //     input,
+        //     inst,
+        //   });
+        // }
+
+        const r = el._zod.run({ value: input[key], issues: [] }, ctx);
+        const isOptional = el._zod.optionality === "optional";
 
-      if (fastEnabled && ctx?.async === false && ctx.noPrecompilation !== true) {
-        // always synchronous
-        if (!fastpass) fastpass = generateFastpass(def.shape);
-        payload = fastpass(payload, ctx);
-      } else {
-        payload.value = {};
-        // const normalized = _normalized.value;
-        const { keys, shape, optionalKeys } = value;
-        for (const key of keys) {
-          const valueSchema = shape[key];
-
-          // do not add omitted optional keys
-          // if (!(key in input)) {
-          //   if (optionalKeys.has(key)) continue;
-          //   payload.issues.push({
-          //     code: "invalid_type",
-          //     path: [key],
-          //     expected: "nonoptional",
-          //     note: `Missing required key: "${key}"`,
-          //     input,
-          //     inst,
-          //   });
-          // }
-
-          const r = valueSchema._zod.run({ value: input[key], issues: [] }, ctx);
-          const isOptional = optionalKeys.has(key);
-          // if (isOptional) {
-          //   if (!(key in input)) {
-          //     continue;
-          //   }
-          //   if (input[key] === undefined) {
-          //     input[key] = undefined;
-          //     continue;
-          //   }
-          // }
-
-          // const r = valueSchema._zod.run({ value: input[key], issues: [] }, ctx);
-          if (r instanceof Promise) {
-            proms.push(
-              r.then((r) =>
-                isOptional ? handleOptionalObjectResult(r, payload, key, input) : handleObjectResult(r, payload, key)
-              )
-            );
+        if (r instanceof Promise) {
+          proms.push(
+            r.then((r) =>
+              isOptional ? handleOptionalObjectResult(r, payload, key, input) : handleObjectResult(r, payload, key)
+            )
+          );
+        } else {
+          if (isOptional) {
+            handleOptionalObjectResult(r, payload, key, input);
           } else {
-            if (isOptional) {
-              handleOptionalObjectResult(r, payload, key, input);
-            } else {
-              handleObjectResult(r, payload, key);
-            }
+            handleObjectResult(r, payload, key);
           }
         }
       }
+    }
 
-      if (!catchall) {
-        // return payload;
-        return proms.length ? Promise.all(proms).then(() => payload) : payload;
-      }
-      const unrecognized: string[] = [];
-      // iterate over input keys
-      const keySet = value.keySet;
-      const _catchall = catchall._zod;
-      const t = _catchall.def.type;
-      for (const key of Object.keys(input)) {
-        if (keySet.has(key)) continue;
-        if (t === "never") {
-          unrecognized.push(key);
-          continue;
-        }
-        const r = _catchall.run({ value: input[key], issues: [] }, ctx);
-
-        if (r instanceof Promise) {
-          proms.push(r.then((r) => handleObjectResult(r, payload, key)));
-        } else {
-          handleObjectResult(r, payload, key);
-        }
+    if (!catchall) {
+      // return payload;
+      return proms.length ? Promise.all(proms).then(() => payload) : payload;
+    }
+    const unrecognized: string[] = [];
+    // iterate over input keys
+    const keySet = value.keySet;
+    const _catchall = catchall._zod;
+    const t = _catchall.def.type;
+    for (const key of Object.keys(input)) {
+      if (keySet.has(key)) continue;
+      if (t === "never") {
+        unrecognized.push(key);
+        continue;
       }
+      const r = _catchall.run({ value: input[key], issues: [] }, ctx);
 
-      if (unrecognized.length) {
-        payload.issues.push({
-          code: "unrecognized_keys",
-          keys: unrecognized,
-          input,
-          inst,
-        });
+      if (r instanceof Promise) {
+        proms.push(r.then((r) => handleObjectResult(r, payload, key)));
+      } else {
+        handleObjectResult(r, payload, key);
       }
+    }
 
-      if (!proms.length) return payload;
-      return Promise.all(proms).then(() => {
-        return payload;
+    if (unrecognized.length) {
+      payload.issues.push({
+        code: "unrecognized_keys",
+        keys: unrecognized,
+        input,
+        inst,
       });
-    };
-  }
-);
-
-///////////////////////////////////////////////////
-/////////////      $ZodInterface      /////////////
-///////////////////////////////////////////////////
-// looser type is required for recursive inference
-export type $ZodLooseShape = Record<string, any>;
-
-export type $InferInterfaceOutput<
-  T extends $ZodLooseShape,
-  Params extends $ZodInterfaceNamedParams,
-> = string extends keyof T
-  ? object
-  : {} extends T
-    ? object
-    : util.Flatten<
-        {
-          -readonly [k in Params["optional"]]?: T[k]["_zod"]["output"];
-        } & {
-          -readonly [k in Exclude<keyof T, Params["optional"]>]: T[k]["_zod"]["output"];
-        } & Params["extra"]
-      >;
-
-export type $InferInterfaceInput<
-  T extends $ZodLooseShape,
-  Params extends $ZodInterfaceNamedParams,
-> = string extends keyof T
-  ? Record<string, unknown>
-  : $ZodInterfaceNamedParams extends Params
-    ? Record<string, unknown>
-    : util.Flatten<
-        {
-          -readonly [k in Params["optional"] | Params["defaulted"]]?: T[k]["_zod"]["input"];
-        } & {
-          -readonly [k in Exclude<keyof T, Params["optional"] | Params["defaulted"]>]: T[k]["_zod"]["input"];
-        } & Params["extra"]
-      >;
-
-export interface $ZodInterfaceDef<out Shape extends $ZodLooseShape = $ZodLooseShape> extends $ZodObjectLikeDef<Shape> {
-  type: "interface";
-}
-
-export interface $ZodInterfaceNamedParams {
-  optional: string;
-  defaulted: string;
-  extra: Record<string, unknown>;
-}
-
-export interface $ZodInterfaceInternals<
-  Shape extends Readonly<$ZodLooseShape> = Readonly<$ZodLooseShape>,
-  Params extends $ZodInterfaceNamedParams = $ZodInterfaceNamedParams,
-> extends $ZodObjectLikeInternals<$InferInterfaceOutput<Shape, Params>, $InferInterfaceInput<Shape, Params>> {
-  subtype: "interface";
-  def: $ZodInterfaceDef<Shape>;
-  // shape: Shape;
-  optional: Params["optional"];
-  defaulted: Params["defaulted"];
-  extra: Params["extra"];
-}
-
-export interface $ZodInterface<
-  Shape extends Readonly<$ZodLooseShape> = Readonly<$ZodLooseShape>,
-  Params extends $ZodInterfaceNamedParams = {
-    optional: string;
-    defaulted: string;
-    extra: Record<string, unknown>;
-  },
-> extends $ZodType {
-  _zod: $ZodInterfaceInternals<Shape, Params>;
-}
-
-export const $ZodInterface: core.$constructor<$ZodInterface> = /*@__PURE__*/ core.$constructor(
-  "$ZodInterface",
-  (inst, def) => {
-    $ZodObjectLike.init(inst, def);
-  }
-);
-
-///////////////////////////////////////////////////////
-/////////////      $ZodObject      /////////////
-///////////////////////////////////////////////////////
-
-// compute output type
-type OptionalOutKeys<T extends $ZodShape> = {
-  [k in keyof T]: T[k] extends { _zod: { qout: "true" } } ? k : never;
-}[keyof T];
-type OptionalOutProps<T extends $ZodShape> = {
-  [k in OptionalOutKeys<T>]?: T[k]["_zod"]["output"];
-};
-type RequiredOutProps<T extends $ZodShape> = {
-  [k in keyof T as T[k]["_zod"]["qout"] extends "true" ? never : k]-?: T[k]["_zod"]["output"];
-};
-export type $InferObjectOutput<T extends $ZodShape, Extra extends Record<string, unknown>> = {} extends T
-  ? object
-  : util.Flatten<OptionalOutProps<T> & RequiredOutProps<T>> & Extra;
-
-// compute input type
-type OptionalInKeys<T extends $ZodShape> = {
-  [k in keyof T]: T[k] extends { _zod: { qin: "true" } } ? k : never;
-}[keyof T];
-type OptionalInProps<T extends $ZodShape> = {
-  [k in OptionalInKeys<T>]?: T[k]["_zod"]["input"];
-};
-type RequiredInKeys<T extends $ZodShape> = {
-  [k in keyof T]: T[k] extends { _zod: { qin: "true" } } ? never : k;
-}[keyof T];
-type RequiredInProps<T extends $ZodShape> = {
-  [k in RequiredInKeys<T>]: T[k]["_zod"]["input"];
-};
-export type $InferObjectInput<T extends $ZodShape, Extra extends Record<string, unknown>> = util.Flatten<
-  ({} extends T ? object : OptionalInProps<T> & RequiredInProps<T>) & Extra
->;
-
-export interface $ZodObjectDef<Shape extends $ZodShape = $ZodShape> extends $ZodObjectLikeDef<Shape> {
-  type: "object";
-  shape: Shape;
-}
-
-export interface $ZodObjectInternals<
-  Shape extends $ZodShape = $ZodShape,
-  Extra extends Record<string, unknown> = Record<string, unknown>,
-> extends $ZodObjectLikeInternals<$InferObjectOutput<Shape, Extra>, $InferObjectInput<Shape, Extra>> {
-  subtype: "object";
-  def: $ZodObjectDef<Shape>;
-  extra: Extra;
-}
-
-export interface $ZodObject<
-  Shape extends $ZodShape = $ZodShape,
-  Extra extends Record<string, unknown> = Record<string, unknown>,
-> extends $ZodType {
-  _zod: $ZodObjectInternals<Shape, Extra>;
-}
+    }
 
-export const $ZodObject: core.$constructor<$ZodObject> = /*@__PURE__*/ core.$constructor("$ZodObject", (inst, def) => {
-  $ZodObjectLike.init(inst, def);
+    if (!proms.length) return payload;
+    return Promise.all(proms).then(() => {
+      return payload;
+    });
+  };
 });
 
 /////////////////////////////////////////
@@ -1938,7 +1801,7 @@ export interface $ZodUnionDef<Options extends readonly $ZodType[] = readonly $Zo
 }
 
 export interface $ZodUnionInternals<T extends readonly $ZodType[] = readonly $ZodType[]>
-  extends $ZodTypeInternals<T[number]["_zod"]["output"], T[number]["_zod"]["input"]> {
+  extends $ZodTypeInternals<core.output<T[number]>, core.input<T[number]>> {
   def: $ZodUnionDef<T>;
   isst: errors.$ZodIssueInvalidUnion;
   pattern: T[number]["_zod"]["pattern"];
@@ -2145,7 +2008,7 @@ export interface $ZodIntersectionDef extends $ZodTypeDef {
 }
 
 export interface $ZodIntersectionInternals<A extends $ZodType = $ZodType, B extends $ZodType = $ZodType>
-  extends $ZodTypeInternals<A["_zod"]["output"] & B["_zod"]["output"], A["_zod"]["input"] & B["_zod"]["input"]> {
+  extends $ZodTypeInternals<core.output<A> & core.output<B>, core.input<A> & core.input<B>> {
   def: $ZodIntersectionDef;
   isst: never;
 }
@@ -2272,33 +2135,33 @@ export interface $ZodTupleDef<
 
 export type $InferTupleInputType<T extends util.TupleItems, Rest extends $ZodType | null> = [
   ...TupleInputTypeWithOptionals<T>,
-  ...(Rest extends $ZodType ? Rest["_zod"]["input"][] : []),
+  ...(Rest extends $ZodType ? core.input<Rest>[] : []),
 ];
 type TupleInputTypeNoOptionals<T extends util.TupleItems> = {
-  [k in keyof T]: T[k]["_zod"]["input"];
+  [k in keyof T]: core.input<T[k]>;
 };
 type TupleInputTypeWithOptionals<T extends util.TupleItems> = T extends readonly [
   ...infer Prefix extends $ZodType[],
   infer Tail extends $ZodType,
 ]
-  ? Tail["_zod"]["qin"] extends "true"
+  ? Tail["_zod"]["optionality"] extends "optional" | "defaulted"
     ? [...TupleInputTypeWithOptionals<Prefix>, Tail["_zod"]["input"]?]
     : TupleInputTypeNoOptionals<T>
   : [];
 
 export type $InferTupleOutputType<T extends util.TupleItems, Rest extends $ZodType | null> = [
   ...TupleOutputTypeWithOptionals<T>,
-  ...(Rest extends $ZodType ? Rest["_zod"]["output"][] : []),
+  ...(Rest extends $ZodType ? core.output<Rest>[] : []),
 ];
 type TupleOutputTypeNoOptionals<T extends util.TupleItems> = {
-  [k in keyof T]: T[k]["_zod"]["output"];
+  [k in keyof T]: core.output<T[k]>;
 };
 type TupleOutputTypeWithOptionals<T extends util.TupleItems> = T extends readonly [
   ...infer Prefix extends $ZodType[],
   infer Tail extends $ZodType,
 ]
-  ? Tail["_zod"]["qout"] extends "true"
-    ? [...TupleOutputTypeWithOptionals<Prefix>, Tail["_zod"]["output"]?]
+  ? Tail["_zod"]["optionality"] extends "optional"
+    ? [...TupleOutputTypeWithOptionals<Prefix>, core.output<Tail>?]
     : TupleOutputTypeNoOptionals<T>
   : [];
 
@@ -2318,7 +2181,7 @@ export interface $ZodTuple<T extends util.TupleItems = util.TupleItems, Rest ext
 export const $ZodTuple: core.$constructor<$ZodTuple> = /*@__PURE__*/ core.$constructor("$ZodTuple", (inst, def) => {
   $ZodType.init(inst, def);
   const items = def.items;
-  const optStart = items.length - [...items].reverse().findIndex((item) => item._zod.qout !== "true");
+  const optStart = items.length - [...items].reverse().findIndex((item) => item._zod.optionality !== "optional");
 
   inst._zod.parse = (payload, ctx) => {
     const input = payload.value;
@@ -2421,13 +2284,13 @@ type $InferZodRecordOutput<
   Value extends $ZodType = $ZodType,
 > = undefined extends Key["_zod"]["values"]
   ? string extends Key["_zod"]["output"]
-    ? Record<Key["_zod"]["output"], Value["_zod"]["output"]>
+    ? Record<Key["_zod"]["output"], core.output<Value>>
     : number extends Key["_zod"]["output"]
-      ? Record<Key["_zod"]["output"], Value["_zod"]["output"]>
+      ? Record<Key["_zod"]["output"], core.output<Value>>
       : symbol extends Key["_zod"]["output"]
-        ? Record<Key["_zod"]["output"], Value["_zod"]["output"]>
-        : Partial<Record<Key["_zod"]["output"], Value["_zod"]["output"]>>
-  : Record<Key["_zod"]["output"], Value["_zod"]["output"]>;
+        ? Record<Key["_zod"]["output"], core.output<Value>>
+        : Partial<Record<Key["_zod"]["output"], core.output<Value>>>
+  : Record<Key["_zod"]["output"], core.output<Value>>;
 
 type $InferZodRecordInput<
   Key extends $ZodRecordKey = $ZodRecordKey,
@@ -2576,10 +2439,7 @@ export interface $ZodMapDef extends $ZodTypeDef {
 }
 
 export interface $ZodMapInternals<Key extends $ZodType = $ZodType, Value extends $ZodType = $ZodType>
-  extends $ZodTypeInternals<
-    Map<Key["_zod"]["output"], Value["_zod"]["output"]>,
-    Map<Key["_zod"]["input"], Value["_zod"]["input"]>
-  > {
+  extends $ZodTypeInternals<Map<core.output<Key>, core.output<Value>>, Map<core.input<Key>, core.input<Value>>> {
   def: $ZodMapDef;
   isst: errors.$ZodIssueInvalidType | errors.$ZodIssueInvalidKey | errors.$ZodIssueInvalidElement<unknown>;
 }
@@ -2679,7 +2539,7 @@ export interface $ZodSetDef extends $ZodTypeDef {
 }
 
 export interface $ZodSetInternals<T extends $ZodType = $ZodType>
-  extends $ZodTypeInternals<Set<T["_zod"]["output"]>, Set<T["_zod"]["input"]>> {
+  extends $ZodTypeInternals<Set<core.output<T>>, Set<core.input<T>>> {
   def: $ZodSetDef;
   isst: errors.$ZodIssueInvalidType;
 }
@@ -2979,10 +2839,9 @@ export interface $ZodOptionalDef<T extends $ZodType = $ZodType> extends $ZodType
 }
 
 export interface $ZodOptionalInternals<T extends $ZodType = $ZodType>
-  extends $ZodTypeInternals<T["_zod"]["output"] | undefined, T["_zod"]["input"] | undefined> {
+  extends $ZodTypeInternals<core.output<T> | undefined, core.input<T> | undefined> {
   def: $ZodOptionalDef<T>;
-  qin: "true";
-  qout: "true";
+  optionality: "optional";
   isst: never;
   values: T["_zod"]["values"];
   pattern: RegExp;
@@ -2996,8 +2855,9 @@ export const $ZodOptional: core.$constructor<$ZodOptional> = /*@__PURE__*/ core.
   "$ZodOptional",
   (inst, def) => {
     $ZodType.init(inst, def);
+    inst._zod.optionality = "optional";
     // inst._zod.qin = "true";
-    inst._zod.qout = "true";
+    // inst._zod.qout = "true";
     if (def.innerType._zod.values) inst._zod.values = new Set([...def.innerType._zod.values, undefined]);
     const pattern = (def.innerType as any)._zod.pattern;
     if (pattern) inst._zod.pattern = new RegExp(`^(${util.cleanRegex(pattern.source)})?$`);
@@ -3024,10 +2884,9 @@ export interface $ZodNullableDef<T extends $ZodType = $ZodType> extends $ZodType
 }
 
 export interface $ZodNullableInternals<T extends $ZodType = $ZodType>
-  extends $ZodTypeInternals<T["_zod"]["output"] | null, T["_zod"]["input"] | null> {
+  extends $ZodTypeInternals<core.output<T> | null, core.input<T> | null> {
   def: $ZodNullableDef<T>;
-  qin: T["_zod"]["qin"];
-  qout: T["_zod"]["qout"];
+  optionality: T["_zod"]["optionality"];
   isst: never;
   values: T["_zod"]["values"];
   pattern: RegExp;
@@ -3041,8 +2900,9 @@ export const $ZodNullable: core.$constructor<$ZodNullable> = /*@__PURE__*/ core.
   "$ZodNullable",
   (inst, def) => {
     $ZodType.init(inst, def);
-    inst._zod.qin = def.innerType._zod.qin;
-    inst._zod.qout = def.innerType._zod.qout;
+    inst._zod.optionality = def.innerType._zod.optionality;
+    // inst._zod.qin = def.innerType._zod.qin;
+    // inst._zod.qout = def.innerType._zod.qout;
 
     const pattern = (def.innerType as any)._zod.pattern;
     if (pattern) inst._zod.pattern = new RegExp(`^(${util.cleanRegex(pattern.source)}|null)$`);
@@ -3067,17 +2927,18 @@ export const $ZodNullable: core.$constructor<$ZodNullable> = /*@__PURE__*/ core.
 export interface $ZodDefaultDef<T extends $ZodType = $ZodType> extends $ZodTypeDef {
   type: "default";
   innerType: T;
-  defaultValue: () => util.NoUndefined<T["_zod"]["output"]>;
+  defaultValue: () => util.NoUndefined<core.output<T>>;
 }
 
 export interface $ZodDefaultInternals<T extends $ZodType = $ZodType>
   extends $ZodTypeInternals<
     // this is pragmatic but not strictly correct
-    util.NoUndefined<T["_zod"]["output"]>,
-    T["_zod"]["input"] | undefined
+    util.NoUndefined<core.output<T>>,
+    core.input<T> | undefined
   > {
   def: $ZodDefaultDef<T>;
-  qin: "true";
+  // qin: "true";
+  optionality: "defaulted";
   isst: never;
   values: T["_zod"]["values"];
 }
@@ -3091,6 +2952,8 @@ export const $ZodDefault: core.$constructor<$ZodDefault> = /*@__PURE__*/ core.$c
   (inst, def) => {
     $ZodType.init(inst, def);
 
+    // inst._zod.qin = "true";
+    inst._zod.optionality = "defaulted";
     inst._zod.values = def.innerType._zod.values;
 
     inst._zod.parse = (payload, ctx) => {
@@ -3129,7 +2992,7 @@ export interface $ZodNonOptionalDef<T extends $ZodType = $ZodType> extends $ZodT
 }
 
 export interface $ZodNonOptionalInternals<T extends $ZodType = $ZodType>
-  extends $ZodTypeInternals<util.NoUndefined<T["_zod"]["output"]>, util.NoUndefined<T["_zod"]["input"]>> {
+  extends $ZodTypeInternals<util.NoUndefined<core.output<T>>, util.NoUndefined<core.input<T>>> {
   def: $ZodNonOptionalDef<T>;
   isst: errors.$ZodIssueInvalidType;
   values: T["_zod"]["values"];
@@ -3219,8 +3082,7 @@ export interface $ZodSuccessDef extends $ZodTypeDef {
   innerType: $ZodType;
 }
 
-export interface $ZodSuccessInternals<T extends $ZodType = $ZodType>
-  extends $ZodTypeInternals<boolean, T["_zod"]["input"]> {
+export interface $ZodSuccessInternals<T extends $ZodType = $ZodType> extends $ZodTypeInternals<boolean, core.input<T>> {
   def: $ZodSuccessDef;
   isst: never;
 }
@@ -3268,10 +3130,12 @@ export interface $ZodCatchDef extends $ZodTypeDef {
 }
 
 export interface $ZodCatchInternals<T extends $ZodType = $ZodType>
-  extends $ZodTypeInternals<T["_zod"]["output"], util.Loose<T["_zod"]["input"]>> {
+  extends $ZodTypeInternals<core.output<T>, util.Loose<core.input<T>>> {
   def: $ZodCatchDef;
-  qin: T["_zod"]["qin"];
-  qout: T["_zod"]["qout"];
+  // qin: T["_zod"]["qin"];
+  // qout: T["_zod"]["qout"];
+
+  optionality: T["_zod"]["optionality"];
   isst: never;
   values: T["_zod"]["values"];
 }
@@ -3283,7 +3147,8 @@ export interface $ZodCatch<T extends $ZodType = $ZodType> extends $ZodType {
 export const $ZodCatch: core.$constructor<$ZodCatch> = /*@__PURE__*/ core.$constructor("$ZodCatch", (inst, def) => {
   $ZodType.init(inst, def);
   // inst._zod.qin = def.innerType._zod.qin;
-  inst._zod.qout = def.innerType._zod.qout;
+  // inst._zod.qout = def.innerType._zod.qout;
+  inst._zod.optionality = def.innerType._zod.optionality;
   inst._zod.values = def.innerType._zod.values;
 
   inst._zod.parse = (payload, ctx) => {
@@ -3293,7 +3158,9 @@ export const $ZodCatch: core.$constructor<$ZodCatch> = /*@__PURE__*/ core.$const
         if (result.issues.length) {
           payload.value = def.catchValue({
             ...payload,
-            error: { issues: result.issues.map((iss) => util.finalizeIssue(iss, ctx, core.config())) },
+            error: {
+              issues: result.issues.map((iss) => util.finalizeIssue(iss, ctx, core.config())),
+            },
             input: payload.value,
           });
           payload.issues = [];
@@ -3307,7 +3174,9 @@ export const $ZodCatch: core.$constructor<$ZodCatch> = /*@__PURE__*/ core.$const
     if (result.issues.length) {
       payload.value = def.catchValue({
         ...payload,
-        error: { issues: result.issues.map((iss) => util.finalizeIssue(iss, ctx, core.config())) },
+        error: {
+          issues: result.issues.map((iss) => util.finalizeIssue(iss, ctx, core.config())),
+        },
         input: payload.value,
       });
       payload.issues = [];
@@ -3369,7 +3238,7 @@ export interface $ZodPipeDef<A extends $ZodType = $ZodType, B extends $ZodType =
 }
 
 export interface $ZodPipeInternals<A extends $ZodType = $ZodType, B extends $ZodType = $ZodType>
-  extends $ZodTypeInternals<B["_zod"]["output"], A["_zod"]["input"]> {
+  extends $ZodTypeInternals<core.output<B>, core.input<A>> {
   def: $ZodPipeDef<A, B>;
   isst: never;
   values: A["_zod"]["values"];
@@ -3416,10 +3285,11 @@ export interface $ZodReadonlyDef extends $ZodTypeDef {
 }
 
 export interface $ZodReadonlyInternals<T extends $ZodType = $ZodType>
-  extends $ZodTypeInternals<util.MakeReadonly<T["_zod"]["output"]>, util.MakeReadonly<T["_zod"]["input"]>> {
+  extends $ZodTypeInternals<util.MakeReadonly<core.output<T>>, util.MakeReadonly<core.input<T>>> {
   def: $ZodReadonlyDef;
-  qin: T["_zod"]["qin"];
-  qout: T["_zod"]["qout"];
+  // qin: T["_zod"]["qin"];
+  // qout: T["_zod"]["qout"];
+  optionality: T["_zod"]["optionality"];
   isst: never;
   disc: T["_zod"]["disc"];
 }
@@ -3434,7 +3304,8 @@ export const $ZodReadonly: core.$constructor<$ZodReadonly> = /*@__PURE__*/ core.
     $ZodType.init(inst, def);
     util.defineLazy(inst._zod, "disc", () => def.innerType._zod.disc);
     // inst._zod.qin = def.innerType._zod.qin;
-    inst._zod.qout = def.innerType._zod.qout;
+    // inst._zod.qout = def.innerType._zod.qout;
+    inst._zod.optionality = def.innerType._zod.optionality;
 
     inst._zod.parse = (payload, ctx) => {
       const result = def.innerType._zod.run(payload, ctx);
@@ -3489,9 +3360,7 @@ type AppendToTemplateLiteral<
   Suffix extends $LiteralPart | $ZodType,
 > = Suffix extends $LiteralPart
   ? `${Template}${UndefinedToEmptyString<Suffix>}`
-  : Suffix extends $ZodType
-    ? `${Template}${UndefinedToEmptyString<$LiteralPart & Suffix["_zod"]["output"]>}`
-    : never;
+  : `${Template}${UndefinedToEmptyString<$LiteralPart & core.output<Suffix & $ZodType>>}`;
 
 export type $PartsToTemplateLiteral<Parts extends $TemplateLiteralPart[]> = [] extends Parts
   ? ``
@@ -3568,7 +3437,7 @@ export interface $ZodPromiseDef extends $ZodTypeDef {
 }
 
 export interface $ZodPromiseInternals<T extends $ZodType = $ZodType>
-  extends $ZodTypeInternals<T["_zod"]["output"], util.MaybeAsync<T["_zod"]["input"]>> {
+  extends $ZodTypeInternals<core.output<T>, util.MaybeAsync<core.input<T>>> {
   def: $ZodPromiseDef;
   isst: never;
 }
@@ -3602,14 +3471,15 @@ export interface $ZodLazyDef extends $ZodTypeDef {
 }
 
 export interface $ZodLazyInternals<T extends $ZodType = $ZodType>
-  extends $ZodTypeInternals<T["_zod"]["output"], T["_zod"]["input"]> {
+  extends $ZodTypeInternals<core.output<T>, core.input<T>> {
   def: $ZodLazyDef;
   isst: never;
   _getter: T;
   pattern: T["_zod"]["pattern"];
   disc: T["_zod"]["disc"];
-  qin: T["_zod"]["qin"];
-  qout: T["_zod"]["qout"];
+  // qin: T["_zod"]["qin"];
+  // qout: T["_zod"]["qout"];
+  optionality: T["_zod"]["optionality"];
 }
 
 export interface $ZodLazy<T extends $ZodType = $ZodType> extends $ZodType {
@@ -3622,12 +3492,10 @@ export const $ZodLazy: core.$constructor<$ZodLazy> = /*@__PURE__*/ core.$constru
   util.defineLazy(inst._zod, "_getter", def.getter);
   util.defineLazy(inst._zod, "pattern", () => inst._zod._getter._zod.pattern);
   util.defineLazy(inst._zod, "disc", () => inst._zod._getter._zod.disc);
+  util.defineLazy(inst._zod, "optionality", () => inst._zod._getter._zod.optionality);
   inst._zod.parse = (payload, ctx) => {
     return inst._zod._getter._zod.run(payload, ctx);
   };
-  // qin and qout
-  util.defineLazy(inst._zod, "qin", () => inst._zod._getter._zod.qin);
-  util.defineLazy(inst._zod, "qout", () => inst._zod._getter._zod.qout);
 });
 
 ////////////////////////////////////////
@@ -3708,7 +3576,6 @@ export type $ZodTypes =
   | $ZodVoid
   | $ZodArray
   | $ZodObject
-  | $ZodInterface
   | $ZodUnion
   | $ZodIntersection
   | $ZodTuple
diff --git a/packages/core/src/to-json-schema.ts b/packages/core/src/to-json-schema.ts
index 1dc89662..b0ce825f 100644
--- a/packages/core/src/to-json-schema.ts
+++ b/packages/core/src/to-json-schema.ts
@@ -173,8 +173,8 @@ export class JSONSchemaGenerator {
             pattern?: RegExp;
             contentEncoding?: string;
           };
-          if (minimum) json.minLength = minimum;
-          if (maximum) json.maxLength = maximum;
+          if (typeof minimum === "number") json.minLength = minimum;
+          if (typeof maximum === "number") json.maxLength = maximum;
           // custom pattern overrides format
           if (format) {
             json.format = formatMap[format] ?? format;
@@ -198,15 +198,15 @@ export class JSONSchemaGenerator {
           if (format?.includes("int")) json.type = "integer";
           else json.type = "number";
 
-          if (minimum) {
+          if (typeof minimum === "number") {
             if (inclusive) json.minimum = minimum;
             else json.exclusiveMinimum = minimum;
           }
-          if (maximum) {
+          if (typeof maximum === "number") {
             if (inclusive) json.maximum = maximum;
             else json.exclusiveMaximum = maximum;
           }
-          if (multipleOf) json.multipleOf = multipleOf;
+          if (typeof multipleOf === "number") json.multipleOf = multipleOf;
 
           break;
         }
@@ -265,14 +265,13 @@ export class JSONSchemaGenerator {
             minimum?: number;
             maximum?: number;
           };
-          if (minimum) json.minItems = minimum;
-          if (maximum) json.maxItems = maximum;
+          if (typeof minimum === "number") json.minItems = minimum;
+          if (typeof maximum === "number") json.maxItems = maximum;
           json.type = "array";
           json.items = this.process(def.element, { ...params, path: [...params.path, "items"] });
           break;
         }
-        case "object":
-        case "interface": {
+        case "object": {
           const json: JSONSchema.ObjectSchema = _json as any;
           json.type = "object";
           json.properties = {};
@@ -290,8 +289,17 @@ export class JSONSchemaGenerator {
 
           // required keys
           const allKeys = new Set(Object.keys(shape));
-          const optionalKeys = new Set(def.optional);
-          const requiredKeys = new Set([...allKeys].filter((key) => !optionalKeys.has(key)));
+          // const optionalKeys = new Set(def.optional);
+          const requiredKeys = new Set(
+            [...allKeys].filter((key) => {
+              const opt = def.shape[key]._zod.optionality;
+              if (this.io === "input") {
+                return opt === undefined;
+              } else {
+                return opt === undefined || opt === "defaulted";
+              }
+            })
+          );
           json.required = Array.from(requiredKeys);
 
           // catchall
@@ -365,8 +373,8 @@ export class JSONSchemaGenerator {
             minimum?: number;
             maximum?: number;
           };
-          if (minimum) json.minItems = minimum;
-          if (maximum) json.maxItems = maximum;
+          if (typeof minimum === "number") json.minItems = minimum;
+          if (typeof maximum === "number") json.maxItems = maximum;
           break;
         }
         case "record": {
@@ -482,7 +490,6 @@ export class JSONSchemaGenerator {
         case "pipe": {
           const innerType = this.io === "input" ? def.in : def.out;
           const inner = this.process(innerType, params);
-          // result.schema = inner;
           _json._ref = inner;
 
           break;
@@ -673,8 +680,8 @@ export class JSONSchemaGenerator {
 
     for (const entry of this.seen.entries()) {
       const seen = entry[1];
-      flattenRef(seen.schema);
-      if (seen.def) flattenRef(seen.def);
+      flattenRef(seen.schema, { target: this.target });
+      if (seen.def) flattenRef(seen.def, { target: this.target });
     }
 
     const result = { ...root.def };
@@ -707,12 +714,19 @@ export class JSONSchemaGenerator {
 }
 
 // flatten _refs
-const flattenRef = (schema: JSONSchema.BaseSchema) => {
+const flattenRef = (schema: JSONSchema.BaseSchema, params: Pick<ToJSONSchemaParams, "target">) => {
   const _schema = { ...schema };
-  if (schema._ref) flattenRef(schema._ref);
+  if (schema._ref) flattenRef(schema._ref, params);
   const ref = schema._ref;
-  Object.assign(schema, ref);
-  Object.assign(schema, _schema); // this is to prevent mutation of the original schema
+  if (ref) {
+    if (ref.$ref && params.target === "draft-7") {
+      schema.allOf = schema.allOf ?? [];
+      schema.allOf.push(ref);
+    } else {
+      Object.assign(schema, ref);
+      Object.assign(schema, _schema); // this is to prevent overwriting any fields in the original schema
+    }
+  }
   delete schema._ref;
 };
 
diff --git a/packages/core/src/util.ts b/packages/core/src/util.ts
index d40dd9af..208182de 100644
--- a/packages/core/src/util.ts
+++ b/packages/core/src/util.ts
@@ -89,7 +89,7 @@ export type Exactly<T, X> = T & Record<Exclude<keyof X, keyof T>, never>;
 export type NoUndefined<T> = T extends undefined ? never : T;
 export type Loose<T> = T | {} | undefined | null;
 export type Mask<Keys extends PropertyKey> = { [K in string & Keys]?: true };
-export type Writeable<T> = { -readonly [P in keyof T]: T[P] };
+export type Writeable<T> = { -readonly [P in keyof T]: T[P] } & {};
 export type InexactPartial<T> = {
   [P in keyof T]?: T[P] | undefined;
 };
@@ -117,7 +117,9 @@ export type SomeObject = Record<PropertyKey, any>;
 export type Identity<T> = T;
 export type Flatten<T> = Identity<{ [k in keyof T]: T[k] }>;
 export type Mapped<T> = { [k in keyof T]: T[k] };
-
+export type Prettify<T> = {
+  [K in keyof T]: T[K];
+} & {};
 export type NoNeverKeys<T> = {
   [k in keyof T]: [T[k]] extends [never] ? never : k;
 }[keyof T];
@@ -149,7 +151,9 @@ export type ExtractIndexSignature<T> = {
 };
 export type Keys<T extends object> = keyof OmitIndexSignature<T>;
 
-export type SchemaClass<T extends schemas.$ZodType> = { new (def: T["_zod"]["def"]): T };
+export type SchemaClass<T extends schemas.$ZodType> = {
+  new (def: T["_zod"]["def"]): T;
+};
 export type EnumValue = string | number; // | bigint | boolean | symbol;
 export type EnumLike = Readonly<Record<string, EnumValue>>;
 export type ToEnum<T extends EnumValue> = Flatten<{ [k in T]: k }>;
@@ -164,7 +168,11 @@ export type HasLength = { length: number }; // string | Array<unknown> | Set<unk
 export type Numeric = number | bigint | Date;
 export type SafeParseResult<T> = SafeParseSuccess<T> | SafeParseError<T>;
 export type SafeParseSuccess<T> = { success: true; data: T; error?: never };
-export type SafeParseError<T> = { success: false; data?: never; error: errors.$ZodError<T> };
+export type SafeParseError<T> = {
+  success: false;
+  data?: never;
+  error: errors.$ZodError<T>;
+};
 
 export type DiscriminatorMapElement = {
   values: Set<Primitive>;
@@ -541,92 +549,60 @@ export function stringifyPrimitive(value: any): string {
   return `${value}`;
 }
 
+// export function objectShapeMeta(rawShape: schemas.$ZodShape): schemas.$ZodShape {
+//   const shape: Writeable<schemas.$ZodShape> = {};
+//   for (const key in rawShape) {
+//     shape[key] = {
+//       type: rawShape[key],
+//       optionality: rawShape[key]._zod.optionality,
+//     };
+//     // if (rawShape[key]._zod.qin) {
+//     //   shape[key].optionality = "defaulted";
+//     // } else if (rawShape[key]._zod.qout) {
+//     //   shape[key].optionality = "optional";
+//     // } else {
+//     //   shape[key].optionality = "required";
+//     // }
+//   }
+//   return shape;
+// }
+// export function interfaceShapeMeta(shape: schemas.$ZodShape): schemas.$ZodShape {
+//   const shapeMeta: Writeable<schemas.$ZodShape> = {};
+//   for (const key in shape) {
+//     if(key[0] === "?") {
+//     shapeMeta[key] ??= { optionality: "required" }; // default
+//     if (shape[key]._zod.qin) {
+//       shapeMeta[key].optionality = "defaulted";
+//     } else if (shape[key]._zod.qout) {
+//       shapeMeta[key].optionality = "optional";
+//     }
+//   }
+//   return shapeMeta;
+// }
 export function optionalObjectKeys(shape: schemas.$ZodShape): string[] {
   return Object.keys(shape).filter((k) => {
-    return shape[k]._zod.qout === "true";
+    return shape[k]._zod.optionality === "optional";
   });
 }
 
-export function optionalInterfaceKeys(shape: schemas.$ZodLooseShape): string[] {
-  return Object.keys(shape)
-    .filter((k) => {
-      return k.endsWith("?");
-    })
-    .map((k) => k.replace(/\?$/, ""));
-}
-
-export type CleanInterfaceShape<T extends object> = Identity<{
-  [k in keyof T as k extends `${infer K}?` ? K : k extends `?${infer K}` ? K : k]: T[k];
-}>;
-export type CleanKeys<T extends PropertyKey> = T extends `${infer K}?` ? K : T extends `?${infer K}` ? K : T;
-export type OptionalInterfaceKeys<T extends PropertyKey> = T extends `${infer K}?` ? K : never;
-export type DefaultedInterfaceKeys<T extends PropertyKey> = T extends `?${infer K}` ? K : never;
-
-export type InitInterfaceParams<T extends schemas.$ZodLooseShape, Extra extends Record<string, unknown>> = Identity<{
-  optional: OptionalInterfaceKeys<keyof T>;
-  defaulted: DefaultedInterfaceKeys<keyof T>;
-  extra: Extra;
-}>;
-
-export type MergeOptional<A extends schemas.$ZodInterface, B extends schemas.$ZodInterface> =
-  | Exclude<A["_zod"]["optional"], keyof B["_zod"]["def"]["shape"]>
-  | B["_zod"]["optional"];
-export type MergeDefaulted<A extends schemas.$ZodInterface, B extends schemas.$ZodInterface> =
-  | Exclude<A["_zod"]["defaulted"], keyof B["_zod"]["def"]["shape"]>
-  | B["_zod"]["defaulted"];
-
-export type MergeInterfaceParams<
-  A extends schemas.$ZodInterface,
-  B extends schemas.$ZodInterface,
-  // BKeys extends PropertyKey,
-> = Identity<{
-  optional: Exclude<A["_zod"]["optional"], keyof B["_zod"]["def"]["shape"]> | B["_zod"]["optional"];
-  defaulted: Exclude<A["_zod"]["defaulted"], keyof B["_zod"]["def"]["shape"]> | B["_zod"]["defaulted"];
-  extra: A["_zod"]["extra"];
-}>;
-
-export type ExtendInterfaceParams<A extends schemas.$ZodInterface, Shape extends schemas.$ZodLooseShape> = Identity<{
-  optional: Exclude<A["_zod"]["optional"], CleanKeys<keyof Shape>> | OptionalInterfaceKeys<keyof Shape>;
-  defaulted: Exclude<A["_zod"]["defaulted"], CleanKeys<keyof Shape>> | DefaultedInterfaceKeys<keyof Shape>;
-  extra: A["_zod"]["extra"];
-}>;
-export type ExtendInterfaceShape<A extends schemas.$ZodLooseShape, B extends schemas.$ZodLooseShape> = Extend<
-  A,
-  CleanInterfaceShape<B>
->;
-export type InterfaceParams<T extends schemas.$ZodInterface> = {
-  optional: T["_zod"]["optional"];
-  defaulted: T["_zod"]["defaulted"];
-  extra: T["_zod"]["extra"];
+// export function optionalInterfaceKeys(shape: schemas.$ZodLooseShape): string[] {
+//   return Object.keys(shape)
+//     .filter((k) => {
+//       return k.endsWith("?");
+//     })
+//     .map((k) => k.replace(/\?$/, ""));
+// }
+
+// type CleanInterfaceShape<T extends object> = Identity<{
+//   [k in keyof T as k extends `${infer K}?` ? K : k extends `?${infer K}` ? K : k]: T[k];
+// }>;
+export type CleanKey<T extends PropertyKey> = T extends `?${infer K}` ? K : T extends `${infer K}?` ? K : T;
+export type ToCleanMap<T extends schemas.$ZodLooseShape> = {
+  [k in keyof T]: k extends `?${infer K}` ? K : k extends `${infer K}?` ? K : k;
+};
+export type FromCleanMap<T extends schemas.$ZodLooseShape> = {
+  [k in keyof T as k extends `?${infer K}` ? K : k extends `${infer K}?` ? K : k]: k;
 };
-
-export function cleanInterfaceKey(key: string): string {
-  return key.replace(/^\?/, "").replace(/\?$/, "");
-}
-
-export function cleanInterfaceShape<T extends schemas.$ZodLooseShape>(
-  _shape: T
-): {
-  shape: CleanInterfaceShape<T>;
-  keyMap: Record<string, string>;
-  optional: string[];
-  defaulted: string[];
-} {
-  const keyMap: Record<string, string> = {};
-  const shape = {} as CleanInterfaceShape<T>;
-  const optional: string[] = [];
-  const defaulted: string[] = [];
-
-  for (const [key, value] of Object.entries(_shape)) {
-    if (key.endsWith("?")) optional.push(key.slice(0, -1));
-    if (key.startsWith("?")) defaulted.push(key.slice(1));
-    const cleanKey = cleanInterfaceKey(key);
-    (shape as any)[cleanKey] = value;
-    keyMap[cleanKey] = key;
-  }
-
-  return { shape, keyMap, optional, defaulted };
-}
 
 export const NUMBER_FORMAT_RANGES: Record<checks.$ZodNumberFormats, [number, number]> = {
   safeint: [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER],
@@ -641,146 +617,117 @@ export const BIGINT_FORMAT_RANGES: Record<checks.$ZodBigIntFormats, [bigint, big
   uint64: [/* @__PURE__*/ BigInt(0), /* @__PURE__*/ BigInt("18446744073709551615")],
 };
 
-export function pick(schema: schemas.$ZodObjectLike, mask: object): any {
+export function pick(schema: schemas.$ZodObject, mask: Record<string, unknown>): any {
   const newShape: Writeable<schemas.$ZodShape> = {};
-  const newOptional: string[] = [];
-  const currShape = schema._zod.def.shape;
-  const currOptional = new Set(schema._zod.def.optional);
-  // const currDefaulted = new Set(schema._zod.def.defaulted);
+  const currDef = schema._zod.def; //.shape;
 
   for (const key in mask) {
-    if (!(key in currShape)) {
+    if (!(key in currDef.shape)) {
       throw new Error(`Unrecognized key: "${key}"`);
     }
-    if (!(mask as any)[key]) continue;
+    if (!mask[key]) continue;
 
     // pick key
-    newShape[key] = currShape[key];
-    if (currOptional.has(key)) {
-      newOptional.push(key);
-    }
+    newShape[key] = currDef.shape[key];
   }
 
   return clone(schema, {
     ...schema._zod.def,
     shape: newShape,
-    optional: newOptional,
     checks: [],
   }) as any;
 }
 
-export function omit(schema: schemas.$ZodObjectLike, mask: object): any {
+export function omit(schema: schemas.$ZodObject, mask: object): any {
   const newShape: Writeable<schemas.$ZodShape> = { ...schema._zod.def.shape };
-  const newOptional = new Set(schema._zod.def.optional);
+  const currDef = schema._zod.def; //.shape;
   for (const key in mask) {
-    if (!(key in schema._zod.def.shape)) {
+    if (!(key in currDef.shape)) {
       throw new Error(`Unrecognized key: "${key}"`);
     }
     if (!(mask as any)[key]) continue;
 
     delete newShape[key];
-    newOptional.delete(key);
   }
   return clone(schema, {
     ...schema._zod.def,
     shape: newShape,
-    optional: [...newOptional],
     checks: [],
   });
 }
 
-export function extend(schema: schemas.$ZodObjectLike, shape: schemas.$ZodShape): any {
+export function extend(schema: schemas.$ZodObject, shape: schemas.$ZodShape): any {
   const def = {
     ...schema._zod.def,
     get shape() {
       const _shape = { ...schema._zod.def.shape, ...shape };
-      assignProp(this, "shape", _shape);
+      assignProp(this, "shape", _shape); // self-caching
       return _shape;
     },
     checks: [], // delete existing checks
   } as any;
-  defineLazy(def, "shape", () => ({ ...schema._zod.def.shape, ...shape }));
   return clone(schema, def) as any;
 }
 
-export function mergeObjectLike(a: schemas.$ZodObjectLike, b: schemas.$ZodObjectLike): any {
-  const bKeys = new Set(Object.keys(b._zod.def.shape));
-  const optional = [...a._zod.def.optional.filter((k) => !bKeys.has(k)), ...b._zod.def.optional];
-
+export function merge(a: schemas.$ZodObject, b: schemas.$ZodObject): any {
   return clone(a, {
     ...a._zod.def,
     get shape() {
       const _shape = { ...a._zod.def.shape, ...b._zod.def.shape };
-      assignProp(this, "shape", _shape);
+      assignProp(this, "shape", _shape); // self-caching
       return _shape;
-      // return { ...a._zod.def.shape, ...b._zod.def.shape };
     },
-    optional,
     catchall: b._zod.def.catchall,
     checks: [], // delete existing checks
   }) as any;
 }
 
-export function extendObjectLike(a: schemas.$ZodObjectLike, b: schemas.$ZodObjectLike): any {
-  const bKeys = new Set(Object.keys(b._zod.def.shape));
-  const optional = [...a._zod.def.optional.filter((k) => !bKeys.has(k)), ...b._zod.def.optional];
-  return clone(a, {
-    ...a._zod.def,
-    get shape() {
-      const _shape = { ...a._zod.def.shape, ...b._zod.def.shape };
-      assignProp(this, "shape", _shape);
-      return _shape;
-      // return { ...a._zod.def.shape, ...b._zod.def.shape };
-    },
-    optional,
-    checks: [], // delete existent checks
-  }) as any;
-}
-
-export function partialObjectLike(
-  Class: SchemaClass<schemas.$ZodOptional>,
-  schema: schemas.$ZodObjectLike,
+export function partial(
+  Class: SchemaClass<schemas.$ZodOptional> | null,
+  schema: schemas.$ZodObject,
   mask: object | undefined
 ): any {
-  const shape: Writeable<schemas.$ZodShape> = { ...schema._zod.def.shape };
-  const optional: Set<string> = new Set(schema._zod.def.optional);
+  const oldShape = schema._zod.def.shape;
+  const shape: Writeable<schemas.$ZodShape> = { ...oldShape };
 
   if (mask) {
     for (const key in mask) {
-      if (!(key in shape)) {
+      if (!(key in oldShape)) {
         throw new Error(`Unrecognized key: "${key}"`);
       }
       if (!(mask as any)[key]) continue;
-      shape[key] = new Class({
-        type: "optional",
-        innerType: schema._zod.def.shape[key],
-      });
-      optional.add(key);
+      shape[key] = Class
+        ? new Class({
+            type: "optional",
+            innerType: oldShape[key],
+          })
+        : oldShape[key];
     }
   } else {
-    for (const key in schema._zod.def.shape) {
-      shape[key] = new Class({
-        type: "optional",
-        innerType: schema._zod.def.shape[key],
-      });
-      optional.add(key);
+    for (const key in oldShape) {
+      shape[key] = Class
+        ? new Class({
+            type: "optional",
+            innerType: oldShape[key],
+          })
+        : oldShape[key];
     }
   }
 
   return clone(schema, {
     ...schema._zod.def,
     shape,
-    optional: [...optional],
     checks: [],
   }) as any;
 }
 
-export function requiredObjectLike(
+export function required(
   Class: SchemaClass<schemas.$ZodNonOptional>,
-  schema: schemas.$ZodObjectLike,
+  schema: schemas.$ZodObject,
   mask: object | undefined
 ): any {
-  const shape: Writeable<schemas.$ZodShape> = { ...schema._zod.def.shape };
+  const oldShape = schema._zod.def.shape;
+  const shape: Writeable<schemas.$ZodShape> = { ...oldShape };
 
   if (mask) {
     for (const key in mask) {
@@ -791,15 +738,15 @@ export function requiredObjectLike(
       // overwrite with non-optional
       shape[key] = new Class({
         type: "nonoptional",
-        innerType: schema._zod.def.shape[key],
+        innerType: oldShape[key],
       });
     }
   } else {
-    for (const key in schema._zod.def.shape) {
+    for (const key in oldShape) {
       // overwrite with non-optional
       shape[key] = new Class({
         type: "nonoptional",
-        innerType: schema._zod.def.shape[key],
+        innerType: oldShape[key],
       });
     }
   }
@@ -807,63 +754,13 @@ export function requiredObjectLike(
   return clone(schema, {
     ...schema._zod.def,
     shape,
-    optional: [],
+    // optional: [],
     checks: [],
   }) as any;
 }
 
-// add question mark to all non-optional keys
-export type PartialInterfaceShape<T extends schemas.$ZodShape, Keys extends string> = Flatten<
-  Omit<T, Keys> & {
-    [k in Keys as k extends `${string}?` ? k : `${string & k}?`]: T[k];
-  }
->;
-
-export type InterfaceKeys<Keys extends string> = string extends Keys
-  ? string
-  : Keys extends `${infer K}?`
-    ? K
-    : Keys extends `?${infer K}`
-      ? K
-      : Keys;
-
 export type Constructor<T, Def extends any[] = any[]> = new (...args: Def) => T;
 
-export function normalizeObjectLikeDef(def: schemas.$ZodObjectLikeDef): {
-  shape: Readonly<Record<string, schemas.$ZodType<unknown, unknown>>>;
-  // keyMap: Record<string, string>;
-  keys: string[];
-  keySet: Set<string>;
-  numKeys: number;
-  optionalKeys: Set<string>;
-} {
-  if (def.type === "interface") {
-    const keys = Object.keys(def.shape);
-    const keySet = new Set(Object.keys(def.shape));
-
-    return {
-      shape: { ...def.shape }, // resolve getters
-      keys,
-      keySet,
-      numKeys: keys.length,
-      optionalKeys: new Set(def.optional),
-    };
-  }
-  if (def.type === "object") {
-    const keys = Object.keys(def.shape);
-    const keySet: Set<string> = new Set(Object.keys(def.shape));
-
-    return {
-      shape: { ...def.shape }, // resolve getters
-      keys,
-      keySet,
-      numKeys: keys.length,
-      optionalKeys: new Set(def.optional),
-    };
-  }
-  throw new Error("Invalid object-like type");
-}
-
 export function aborted(x: schemas.ParsePayload, startIndex = 0): boolean {
   for (let i = startIndex; i < x.issues.length; i++) {
     if (x.issues[i].continue !== true) return true;
diff --git a/packages/core/src/versions.ts b/packages/core/src/versions.ts
index 13b84741..a3b480f6 100644
--- a/packages/core/src/versions.ts
+++ b/packages/core/src/versions.ts
@@ -1,5 +1,5 @@
 export const version = {
   major: 0,
-  minor: 9,
+  minor: 11,
   patch: 0 as number,
 } as const;
diff --git a/packages/docs/components/ecosystem.tsx b/packages/docs/components/ecosystem.tsx
index a6389888..6f67febe 100644
--- a/packages/docs/components/ecosystem.tsx
+++ b/packages/docs/components/ecosystem.tsx
@@ -29,7 +29,20 @@ const formIntegrations: ZodResource[] = [];
 
 const zodToXConverters: ZodResource[] = [];
 
-const xToZodConverters: ZodResource[] = [];
+const xToZodConverters: ZodResource[] = [
+  {
+    name: "orval",
+    url: "https://github.com/orval-labs/orval",
+    description: "Generate Zod schemas from OpenAPI schemas",
+    slug: "orval-labs/orval",
+  },
+  {
+    name: "kubb",
+    url: "https://github.com/kubb-labs/kubb",
+    description: "The ultimate toolkit for working with APIs.",
+    slug: "kubb-labs/kubb",
+  },
+];
 
 const mockingLibraries: ZodResource[] = [
   {
@@ -40,7 +53,20 @@ const mockingLibraries: ZodResource[] = [
   },
 ];
 
-const poweredByZodProjects: ZodResource[] = [];
+const poweredByZodProjects: ZodResource[] = [
+  {
+    name: "zod-config",
+    url: "https://github.com/alexmarqs/zod-config",
+    description: "Load configurations across multiple sources with flexible adapters, ensuring type safety with Zod.",
+    slug: "alexmarqs/zod-config",
+  },
+  {
+    name: "Composable Functions",
+    url: "https://github.com/seasonedcc/composable-functions",
+    description: "Types and functions to make composition easy and safe.",
+    slug: "seasonedcc/composable-functions",
+  },
+];
 
 const zodUtilities: ZodResource[] = [];
 
diff --git a/packages/docs/components/featured.tsx b/packages/docs/components/featured.tsx
index 2083aedb..07db14ac 100644
--- a/packages/docs/components/featured.tsx
+++ b/packages/docs/components/featured.tsx
@@ -1,18 +1,26 @@
-export function Featured() {
+type FeatureData = {
+  name: string;
+  link: string;
+  lightImage: string;
+  darkImage: string;
+};
+
+export function Featured(props: { data: FeatureData }) {
+  const { data: feature } = props;
   return (
     <div className="w-full flex flex-col items-center">
       <span
         style={{ borderBottom: "1px solid hsla(0, 0%, 100%, 0.1)" }}
         className="font-semibold w-full text-center pb-2 border-b border-gray-900 border-solid text-xl"
       >
-        Featured sponsor: Fern
+        Featured sponsor: {feature.name}
       </span>
 
-      <a href="https://link.buildwithfern.com/zod-partnership" className="mt-0 mb-0 border-none">
+      <a href={feature.link} className="mt-0 mb-0 border-none">
         <div className="h-[320px] flex justify-center items-center m-3">
           <picture className="h-[300px] flex items-center">
-            <source media="(prefers-color-scheme: dark)" srcSet="https://i.imgur.com/ntvK08h.png" />
-            <img alt="fern logo" src="https://i.imgur.com/pqyEkg5.png" className="max-h-[300px] w-auto" />
+            <source media="(prefers-color-scheme: dark)" srcSet={feature.darkImage} />
+            <img alt={`${feature.name} logo`} src={feature.lightImage} className="max-h-[300px] w-auto" />
           </picture>
         </div>
       </a>
diff --git a/packages/docs/content/api.mdx b/packages/docs/content/api.mdx
index 85e755a3..fb663c08 100644
--- a/packages/docs/content/api.mdx
+++ b/packages/docs/content/api.mdx
@@ -387,7 +387,7 @@ v6.parse("2001:db8:85a3::8a2e:370:7334"); // ✅
 
 ### IP blocks (CIDR)
 
-Validate IP address ranges specified with [CIDR notation](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing). By default, `.cidr()` allows both IPv4 and IPv6.
+Validate IP address ranges specified with [CIDR notation](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing).
 
 ```ts
 const cidrv4 = z.string().cidrv4();
@@ -820,104 +820,9 @@ const email = z.templateLiteral([
 
 ## Objects
 
-There are two APIs for defining object schemas: `z.object()` and `z.interface()`. The two APIs are largely identical, with a small (but important!) difference in how *optional properties* are defined.
-{/* 
-<Callout>
-The `z.interface()` API was introduced in Zod 4 as a more flexible and powerful way to represent objects. Optional properties are specified with a `?` suffix in the key. This gives you more control over representing *optionality*:
-
-```ts
-z.interface({
-  email: z.string(),
-  name: z.string().optional(),
-  "bio?": z.string(),
-});
-// { email: string; name: string | undefined; bio?: string; }
-```
-
-With this new syntax, it's now possible to define recursive types directly using getters—no `z.lazy()` required.
-
-```ts
-const Node = z.interface({
-  value: z.string(),
-  get children(){
-    return z.array(Node).optional()
-  }
-});
-``` 
-
-For these reasons, `z.interface` is the recommended approach. However, `z.object()` is still fully supported. 
-</Callout> */}
-
-{/* For a detailed discussion of the differences, refer to the [introductory blog post](#) for `z.interface()`. */}
-
-<Accordions>
-<Accordion title="z.interface() vs. z.object()">
-
-{/* The `z.interface()` API fixes some shortcomings with `z.object()`. Let's run through them. */}
-
-There are a couple ways in which a key can be "optional" in TypeScript. Consider these two interfaces.
-
-```ts
-interface A {
-  name?: string | undefined;
-}
-
-interface B {
-  name: string | undefined;
-}
-```
-
-In `A`, the `name` property can be set `undefined` or it can be omitted from the object entirely. By contrast, `B` requires that a `name` propertly is set.
-
-```ts
-const obj: A = { name: undefined }; // ✅
-const obj: A = {} ; // ✅ pass
-
-const obj: B = { name: undefined }; // ✅ 
-const obj: B = {} ; // ❌ compile error: missing required property `name`
-```
-
-
-The `z.object()` API can only represent `A`. When an an optional schema (e.g. `z.string().optional()`) is passed into `z.object()`, Zod automatically adds the question mark to the inferred type. 
-
-```ts
-z.object({ name: z.string().optional() });
-// { name?: string | undefined; }
-```
-
-By contrast, `z.interface()` can represent both varieties. To make a property "key optional" (e.g. to add the question mark), suffix that key with `?`. 
-
-
-```ts
-z.interface({ "name?": z.string() });
-// { name?: string | undefined; }
-
-z.interface({ name: z.string().optional() });
-// { name: string | undefined; }
-```
-
-As a happy side-effect of this new `z.interface()` API, it's possible to define recursive types directly—no type-casting or `z.lazy()` required! See the documentation on [`Recursive objects`](#recursive-objects) for more information.
-</Accordion>
-</Accordions>
-
 To define an object type:
 
-<Tabs groupId="object-api" items={["z.interface", "z.object"]}>
-  <Tab value="z.interface">
-  ```ts z.interface
-  // all properties are required by default
-  const Person = z.interface({
-    name: z.string(),
-    age: z.number(),
-  });
-
-  type Person = z.infer<typeof Person>;
-  // => { name: string; age: number; }
-  ```
-  </Tab>
-
-  <Tab value="z.object">
-  ```ts z.object
+```ts z.object
   // all properties are required by default
   const Person = z.object({
     name: z.string(),
@@ -927,24 +832,8 @@ To define an object type:
   type Person = z.infer<typeof Person>;
   // => { name: string; age: number; }
   ```
-  </Tab>
-</Tabs>
-
 By default, all properties are required. To make certain properties optional:
 
-<Tabs groupId="object-api" items={["z.interface", "z.object"]}>
-<Tab value="z.interface">
-```ts z.interface
-const Dog = z.interface({
-  name: z.string(),
-  "age?": z.number(), // optional field
-});
-
-Dog.parse({ name: "Yeller" }); // ✅
-```
-</Tab>
-
-<Tab value="z.object">
 ```ts z.object
 const Dog = z.object({
   name: z.string(),
@@ -953,40 +842,15 @@ const Dog = z.object({
 
 Dog.parse({ name: "Yeller" }); // ✅
 ```
-</Tab>
-</Tabs>
 
 By default, unrecognized keys are *stripped* from the parsed result:
 
-<Tabs groupId="object-api" items={["z.interface", "z.object"]}>
-<Tab value="z.interface">
-```ts z.interface
-Dog.parse({ name: "Yeller", extraKey: true });
-// => { name: "Yeller" }
-```
-</Tab>
-<Tab value="z.object">
 ```ts z.object
 Dog.parse({ name: "Yeller", extraKey: true });
 // => { name: "Yeller" }
 ```
-</Tab>
-</Tabs>
-
 To define a *strict* schema that throws an error when unknown keys are found:
 
-<Tabs groupId="object-api" items={["z.interface", "z.object"]}>
-<Tab value="z.interface">
-```ts z.interface
-const StrictDog = z.strictInterface({
-  name: z.string(),
-});
-
-StrictDog.parse({ name: "Yeller", extraKey: true });
-// ❌ throws
-```
-</Tab>
-<Tab value="z.object">
 ```ts z.object
 const StrictDog = z.strictObject({
   name: z.string(),
@@ -995,23 +859,9 @@ const StrictDog = z.strictObject({
 StrictDog.parse({ name: "Yeller", extraKey: true });
 // ❌ throws
 ```
-</Tab>
-</Tabs>
 
 To define a *loose* schema that allows unknown keys to pass through:
 
-<Tabs groupId="object-api" items={["z.interface", "z.object"]}>
-<Tab value="z.interface">
-```ts z.interface
-const LooseDog = z.looseInterface({
-  name: z.string(),
-});
-
-Dog.parse({ name: "Yeller", extraKey: true });
-// => { name: "Yeller", extraKey: true }
-```
-</Tab>
-<Tab value="z.object">
 ```ts z.object
 const LooseDog = z.looseObject({
   name: z.string(),
@@ -1020,30 +870,6 @@ const LooseDog = z.looseObject({
 Dog.parse({ name: "Yeller", extraKey: true });
 // => { name: "Yeller", extraKey: true }
 ```
-</Tab>
-</Tabs>
-
-{/* 
-To validate unknown keys against a schema:
-
-<CodeGroup>
-```ts z.interface
-const Dog = z.interface({
-  name: z.string(),
-}).catchall;
-
-Dog.parse({ name: "Yeller", extraKey: true });
-// => { name: "Yeller" }
-```
-```ts z.object
-const Dog = z.strictObject({
-  name: z.string(),
-});
-
-Dog.parse({ name: "Yeller", extraKey: true });
-// => { name: "Yeller" }
-```
-</Tab></Tabs> */}
 
 ### `.shape`
 
@@ -1105,42 +931,12 @@ const DogWithBreed = z.extend(Dog, {
 </Tabs>
 
 <Callout>
-  This API can be used to overwrite existing fields! Be careful with this power!
-</Callout>
-
-You can also pass another object schema into `.extend()`:
-
-<Tabs groupId="lib" items={["zod", "@zod/mini"]}>
-<Tab value="zod">
-```ts
-const HasBreed = z.interface({ breed: z.string() });
-const DogWithBreed = Dog.extend(HasBreed);
-```
-</Tab>
-<Tab value="@zod/mini">
-```ts @zod/mini
-const HasBreed = z.interface({ breed: z.string() });
-const DogWithBreed = z.extend(Dog, HasBreed);
-```
-</Tab>
-</Tabs>
-
-<Callout>
-If the two schemas share keys, B will override A. The returned schema also inherits the strictness level (strip, strict, loose) from B.
+  This API can be used to overwrite existing fields! Be careful with this power! 
+  
+  
+  If the two schemas share keys, B will override A.
 </Callout>
 
-{/* 
-### `.merge()`
-
-```ts
-const BaseTeacher = z.object({ students: z.array(z.string()) });
-const HasID = z.object({ id: z.string() });
-
-const Teacher = BaseTeacher.merge(HasID);
-type Teacher = z.infer<typeof Teacher>; // => { students: string[], id: string }
-```
-
-> If the two schemas share keys, the properties of B overrides the property of A. The returned schema also inherits the "unknownKeys" policy (strip/strict/passthrough) and the catchall schema of B. */}
 
 ### `.pick`
 
@@ -1148,18 +944,6 @@ Inspired by TypeScript's built-in `Pick` and `Omit` utility types, Zod provides
 
 Starting from this initial schema:
 
-<Tabs groupId="lib" items={["zod", "@zod/mini"]}>
-<Tab value="zod">
-```ts z.interface
-const Recipe = z.interface({
-  title: z.string(),
-  "description?": z.string(),
-  ingredients: z.array(z.string()),
-});
-// { name: string; description?: string; ingredients: string[] }
-```
-</Tab>
-<Tab value="@zod/mini">
 ```ts z.object
 const Recipe = z.object({
   name: z.string(),
@@ -1168,9 +952,6 @@ const Recipe = z.object({
 });
 // { id: string; name: string; ingredients: string[] }
 ```
-</Tab>
-</Tabs>
-
 To pick certain keys:
 
 
@@ -1209,28 +990,7 @@ const RecipeNoId = z.omit(Recipe, { id: true });
 ### `.partial()`
 
 For convenience, Zod provides a dedicated API for making some or all properties optional, inspired by the built-in TypeScript utility type [`Partial`](https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype).
-{/* 
 
-<Tabs groupId="object-api" items={["z.interface", "z.object"]}>
-<Tab value="z.interface">
-```ts z.interface
-const User = z.object({
-  email: z.string(),
-  username: z.string(),
-});
-// { email: string; username: string }
-```
-</Tab>
-<Tab value="z.object">
-```ts z.object
-const User = z.object({
-  email: z.string(),
-  username: z.string(),
-});
-// { email: string; username: string }
-```
-</Tab>
-</Tabs> */}
 
 To make all fields optional:
 
@@ -1274,30 +1034,6 @@ const RecipeOptionalIngredients = z.partial(Recipe, {
 
 Zod provides an API for making some or all properties *required*, inspired by TypeScript's [`Required`](https://www.typescriptlang.org/docs/handbook/utility-types.html#requiredtype) utility type.
 
-{/* 
-Starting from this schema:
-
-<Tabs groupId="object-api" items={["z.interface", "z.object"]}>
-<Tab value="z.interface">
-```ts z.interface
-const User = z.object({
-  "email?": z.string(),
-  "username?": z.string(),
-});
-// { email?: string | undefined; username?: string | undefined }
-```
-</Tab>
-<Tab value="z.object">
-```ts z.object
-const User = z.object({
-  email: z.string().optional(),
-  username: z.string().optional(),
-});
-// { email?: string | undefined; username?: string | undefined }
-```
-</Tab>
-</Tabs> */}
-
 To make all properties required:
 
 <Tabs groupId="lib" items={["zod", "@zod/mini"]}>
@@ -1332,88 +1068,12 @@ const RecipeRequiredDescription = z.required(Recipe, {description: true});
 </Tab>
 </Tabs>
 
-{/* ### `.passthrough`
-
-By default Zod object schemas strip out unrecognized keys during parsing.
-
-```ts
-const person = z.object({
-  name: z.string(),
-});
-
-person.parse({
-  name: "bob dylan",
-  extraKey: 61,
-});
-// => { name: "bob dylan" }
-// extraKey has been stripped
-```
-
-Instead, if you want to pass through unknown keys, use `.passthrough()` .
-
-```ts
-person.passthrough().parse({
-  name: "bob dylan",
-  extraKey: 61,
-});
-// => { name: "bob dylan", extraKey: 61 }
-```
-
-### `.strict`
-
-By default Zod object schemas strip out unrecognized keys during parsing. You can _disallow_ unknown keys with `.strict()` . If there are any unknown keys in the input, Zod will throw an error.
-
-```ts
-const person = z
-  .object({
-    name: z.string(),
-  })
-  .strict();
-
-person.parse({
-  name: "bob dylan",
-  extraKey: 61,
-});
-// => throws ZodError
-```
-
-### `.strip`
-
-You can use the `.strip` method to reset an object schema to the default behavior (stripping unrecognized keys).
-
-### `.catchall`
-
-You can pass a "catchall" schema into an object schema. All unknown keys will be validated against it.
-
-```ts
-const person = z
-  .object({
-    name: z.string(),
-  })
-  .catchall(z.number());
-
-person.parse({
-  name: "bob dylan",
-  validExtraKey: 61, // works fine
-});
-
-person.parse({
-  name: "bob dylan",
-  validExtraKey: false, // fails
-});
-// => throws ZodError
-```
-
-Using `.catchall()` obviates `.passthrough()` , `.strip()` , or `.strict()`. All keys are now considered "known".
-
-<br/> */}
-
 ## Recursive objects
 
-The `z.interface()` API is capable of representing recursive types using [getters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get).
+To define a self-referential type, use a [getter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) on the key. This lets JavaScript resolve the cyclical schema at runtime.
 
 ```ts
-const Category = z.interface({
+const Category = z.object({
   name: z.string(),
   get subcategories(){
     return z.array(Category)
@@ -1427,14 +1087,14 @@ type Category = z.infer<typeof Category>;
 You can also represent *mutually recursive types*:
 
 ```ts
-const User = z.interface({
+const User = z.object({
   email: z.email(),
   get posts(){
     return z.array(Post)
   }
 });
 
-const Post = z.interface({
+const Post = z.object({
   title: z.string(),
   get author(){
     return User
@@ -1444,36 +1104,10 @@ const Post = z.interface({
 
 All object APIs (pick, omit, required, partial, etc) work as you'd expect.
 
-<Accordions>
-<Accordion title="What about z.object()?">
-Due to a limitation in TypeScript, `z.object()` isn't capable of defining recursive types without a manual type definition. This means you need to redundantly define a TypeScript type in addition to your Zod schema.
-
-```ts
-interface Category {
-  name: string;
-  subcategories: Category[];
-};
-
-const categorySchema: z.ZodType<Category> = z.object({
-  name: z.string(),
-  subcategories: z.lazy(() => categorySchema.array()),
-});
-```
-
-This is verbose, error prone, and counter to the goals of Zod. The `z.interface()` API was introduced in large part so recursive types could be more readily represented in Zod.
-</Accordion>
-</Accordions>
-
-{/* ### Cyclical objects */}
-
 <Callout type="warn"> 
   Though recursive schemas are supported, passing cyclical data into Zod will cause an infinite loop.
 </Callout>
 
-
-
-> To detect cyclical objects before they cause problems, consider [this approach](https://gist.github.com/colinhacks/d35825e505e635df27cc950776c5500b).
-
 ## Arrays
 
 To define an array schema:
@@ -1506,27 +1140,6 @@ stringArray.def.element; // => string schema
 </Tab>
 </Tabs>
 
-{/* ### `.nonempty`
-
-If you want to ensure that an array contains at least one element, use `.nonempty()`.
-
-```ts
-const nonEmptyStrings = z.string().array().nonempty();
-// the inferred type is now
-// [string, ...string[]]
-
-nonEmptyStrings.parse([]); // throws: "Array cannot be empty"
-nonEmptyStrings.parse(["Ariana Grande"]); // passes
-```
-
-You can optionally specify a custom error message:
-
-```ts
-// optional custom error message
-const nonEmptyStrings = z.string().array().nonempty({
-  message: "Can't be empty!",
-});
-``` */}
 
 ### `.min/.max/.length`
 
@@ -1647,8 +1260,8 @@ So Zod provides a `z.discriminatedUnion()` API that uses a *discriminator key* t
 
 ```ts
 const MyResult = z.discriminatedUnion([
-  z.interface({ status: z.literal("success"), data: z.string() }),
-  z.interface({ status: z.literal("failed"), error: z.string() }),
+  z.object({ status: z.literal("success"), data: z.string() }),
+  z.object({ status: z.literal("failed"), error: z.string() }),
 ]);
 ```
 
@@ -1658,8 +1271,8 @@ const MyResult = z.discriminatedUnion([
 
   ```ts
   const MyResult = z.discriminatedUnion("status", [
-    z.interface({ status: z.literal("success"), data: z.string() }),
-    z.interface({ status: z.literal("failed"), error: z.string() }),
+    z.object({ status: z.literal("success"), data: z.string() }),
+    z.object({ status: z.literal("failed"), error: z.string() }),
   ]);
   ```
 
@@ -1674,13 +1287,13 @@ const MyResult = z.discriminatedUnion([
   ```ts
   const BaseError = { status: z.literal("failed"), message: z.string() };
   const MyErrors = z.discriminatedUnion([
-    z.interface({ ...BaseError, code: z.literal(400) }),
-    z.interface({ ...BaseError, code: z.literal(401) }),
-    z.interface({ ...BaseError, code: z.literal(500) }),
+    z.object({ ...BaseError, code: z.literal(400) }),
+    z.object({ ...BaseError, code: z.literal(401) }),
+    z.object({ ...BaseError, code: z.literal(500) }),
   ]);
 
   const MyResult = z.discriminatedUnion([
-    z.interface({ status: z.literal("success"), data: z.string() }),
+    z.object({ status: z.literal("success"), data: z.string() }),
     MyErrors
   ]);
   ```
@@ -2386,37 +1999,13 @@ defaultTuna.parse(undefined); // => "tuna"
 </Tab>
 <Tab value="@zod/mini">
 ```ts
-const defaultTuna = z.default(z.string(), "tuna");
+const defaultTuna = z._default(z.string(), "tuna");
 
 defaultTuna.parse(undefined); // => "tuna"
 ```
 </Tab>
 </Tabs>
 
-
-{/* This value will be returned if the `input` is undefined. This is also true inside object schemas:
-
-<Tabs groupId="lib" items={["zod", "@zod/mini"]}>
-<Tab value="zod">
-```ts
-const Fish = z.interface({
-  name: z.string().default("tuna"),
-});
-
-Fish.parse({}); // => { name: "tuna" }
-```
-</Tab>
-<Tab value="@zod/mini">
-```ts
-const Fish = z.interface({
-  name: z.string().default("tuna"),
-});
-
-z.parse(Fish, {}); // => { name: "tuna" }
-```
-</Tab>
-</Tabs> */}
-
 Alternatively, you can pass a function which will be re-executed whenever a default value needs to be generated:
 
 <Tabs groupId="lib" items={["zod", "@zod/mini"]}>
@@ -2431,7 +2020,7 @@ randomDefault.parse(undefined);    // => 0.7223408162401552
 </Tab>
 <Tab value="@zod/mini">
 ```ts
-const randomDefault = z.default(z.number(), Math.random);
+const randomDefault = z._default(z.number(), Math.random);
 
 z.parse(randomDefault, undefined); // => 0.4413456736055323
 z.parse(randomDefault, undefined); // => 0.1871840107401901
diff --git a/packages/docs/content/basics.mdx b/packages/docs/content/basics.mdx
index 35f036a1..2ef529d2 100644
--- a/packages/docs/content/basics.mdx
+++ b/packages/docs/content/basics.mdx
@@ -16,7 +16,7 @@ Before you can do anything else, you need to define a schema. For the purposes o
 ```ts
 import * as z from "zod"; 
 
-const Player = z.interface({ 
+const Player = z.object({ 
   username: z.string(),
   xp: z.number()
 });
@@ -26,7 +26,7 @@ const Player = z.interface({
 ```ts
 import * as z from "@zod/mini";
 
-const Player = z.interface({ 
+const Player = z.object({ 
   username: z.string(),
   xp: z.number()
 });
@@ -158,7 +158,7 @@ await schema.safeParseAsync("hello");
 Zod infers a static type from your schema definitions. You can extract this type with the `z.infer<>` utility and use it however you like.
 
 ```ts
-const Player = z.interface({ 
+const Player = z.object({ 
   username: z.string(),
   xp: z.number()
 });
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/index.mdx b/packages/docs/content/index.mdx
index 99f1ef6b..68ad6a29 100644
--- a/packages/docs/content/index.mdx
+++ b/packages/docs/content/index.mdx
@@ -71,7 +71,12 @@ import { Bronze } from '../components/bronze';
 
 <br /><br /><br />
 
-<Featured />
+<Featured data={{
+  name: "Stainless",
+  link: "https://www.stainless.com/?utm_source=zod",
+  lightImage: "https://i.imgur.com/bjyoaHY.jpeg",
+  darkImage: "https://i.imgur.com/bjyoaHY.jpeg",
+}} />
 
 ## Introduction
 
@@ -80,7 +85,7 @@ Zod is a TypeScript-first validation library. Using Zod, you can define *schemas
 ```ts
 import * as z from "zod";
 
-const User = z.interface({
+const User = z.object({
   name: z.string(),
 });
 
diff --git a/packages/docs/content/json-schema.mdx b/packages/docs/content/json-schema.mdx
index 41bc3297..09ba4547 100644
--- a/packages/docs/content/json-schema.mdx
+++ b/packages/docs/content/json-schema.mdx
@@ -16,7 +16,7 @@ To convert a Zod schema to JSON Schema, use the `z.toJSONSchema()` function.
 ```ts
 import * as z from "zod";
 
-const schema = z.interface({
+const schema = z.object({
   name: z.string(),
   age: z.number(),
 });
@@ -80,7 +80,8 @@ z.emoji();
 z.nanoid();
 z.cuid2();
 z.ulid();
-z.cidr();
+z.cidrv4();
+z.cidrv6();
 ```
 
 ## Numeric types
@@ -335,7 +336,7 @@ z.toJSONSchema(z.bigint(), { unrepresentable: "any" });
 How to handle cycles. If a cycle is encountered as `z.toJSONSchema()` traverses the schema, it will be represented using `$ref`. 
 
 ```ts
-const User = z.interface({
+const User = z.object({
   name: z.string(),
   get friend() {
     return User;
@@ -364,7 +365,7 @@ How to handle schemas that occur multiple times in the same schema. By default,
 
 ```ts
 const name = z.string();
-const User = z.interface({
+const User = z.object({
   firstName: name,
   lastName: name,
 });
@@ -642,7 +643,7 @@ z.tuple([z.string()]).rest(z.boolean());
 Full support for objects:
 
 ```ts
-z.interface({ name: z.string() });
+z.object({ name: z.string() });
 // => { type: "object", properties: { name: { type: "string" }}, required: ["name"] }
 
 z.strictInterface({ name: z.string() })
@@ -651,7 +652,7 @@ z.strictInterface({ name: z.string() })
 z.looseInterface({ name: z.string() })
 // => { ..., additionalProperties: {} }
 
-z.interface({ "name?": z.string() });
+z.object({ "name?": z.string() });
 // => { type: "object", properties: { name: { type: "string" }}, required: [] }
 
 z.record(z.string(), z.string());
@@ -809,14 +810,14 @@ In other cases, you may have a set of Zod schemas you'd like to represent using
 ```ts
 import * as z from "zod";
 
-const User = z.interface({
+const User = z.object({
   name: z.string(),
   get posts(){
     return z.array(Post);
   }
 });
 
-const Post = z.interface({
+const Post = z.object({
   title: z.string(),
   content: z.string(),
   get author(){
diff --git a/packages/docs/content/packages/core.mdx b/packages/docs/content/packages/core.mdx
index 8ac5e05e..9cff6cb9 100644
--- a/packages/docs/content/packages/core.mdx
+++ b/packages/docs/content/packages/core.mdx
@@ -79,7 +79,6 @@ export type $ZodTypes =
   | $ZodVoid
   | $ZodArray
   | $ZodObject
-  | $ZodInterface
   | $ZodUnion
   | $ZodIntersection
   | $ZodTuple
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/packages/zod.mdx b/packages/docs/content/packages/zod.mdx
index 00a1e187..8538ad5c 100644
--- a/packages/docs/content/packages/zod.mdx
+++ b/packages/docs/content/packages/zod.mdx
@@ -11,7 +11,7 @@ Zod aims to provide a schema API that maps one-to-one to TypeScript's type syste
 ```ts
 import * as z from "zod";
 
-const schema = z.interface({
+const schema = z.object({
   name: z.string(),
   age: z.number().int().positive(),
   email: z.string().email(),
diff --git a/packages/docs/content/v4/changelog.mdx b/packages/docs/content/v4/changelog.mdx
index 013cd724..36ab6bd4 100644
--- a/packages/docs/content/v4/changelog.mdx
+++ b/packages/docs/content/v4/changelog.mdx
@@ -254,7 +254,8 @@ z.cuid2();
 z.ulid();
 z.ipv4();
 z.ipv6();
-z.cidr();          // ip range
+z.cidrv4();          // ip range
+z.cidrv6();          // ip range
 z.iso.date();
 z.iso.time();
 z.iso.datetime();
@@ -274,8 +275,8 @@ This has been replaced with separate `.ipv4()` and `.ipv6()` methods. Use `z.uni
 
 ```ts
 z.string().ip() // ❌
-z.string().ipv4() // ✅
-z.string().ipv6() // ✅
+z.ipv4() // ✅
+z.ipv6() // ✅
 ```
 
 ### updates `z.string().ipv6()`
@@ -288,8 +289,8 @@ Similarly, this has been replaced with separate `.cidrv4()` and `.cidrv6()` meth
 
 ```ts
 z.string().cidr() // ❌
-z.string().cidrv4() // ✅
-z.string().cidrv6() // ✅
+z.cidrv4() // ✅
+z.cidrv6() // ✅
 ```
 
 ## `z.coerce` updates
@@ -308,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();
@@ -332,15 +335,6 @@ z.looseObject({ name: z.string() });
 
 This was never particularly useful, as it was the default behavior of `z.object()`. 
 
-<Callout>
-The equivalents for `z.interface()` also exist. Read more about `z.interface()` [here](/api#objects).
-
-```ts
-z.interface({ name: z.string() });
-z.looseInterface({ name: z.string() });
-z.strictInterface({ name: z.string() });
-```
-</Callout>
 
 ### drops `.nonstrict()`
 
@@ -395,7 +389,7 @@ This now behaves identically to `z.array().min(1)`. The inferred type does not c
 const NonEmpty = z.array(z.string()).nonempty();
 
 type NonEmpty = z.infer<typeof NonEmpty>; 
-// Zod 3: [string, string[]]
+// Zod 3: [string, ...string[]]
 // Zod 4: string[]
 ```
 
@@ -403,7 +397,7 @@ The old behavior is now better represented with `z.tuple()` and a "rest" argumen
 
 ```ts
 z.tuple([z.string()], z.string());
-// => [string, string[]]
+// => [string, ...string[]]
 ```
 
 ## `z.promise()` deprecated
@@ -495,7 +489,7 @@ z.ZodString.create(); // ❌
 You no longer need to specify a discriminator key (though you still can if you wish; it is ignored).
 
 ```ts
-in Zod 4:
+// in Zod 4:
 const myUnion = z.discriminatedUnion([
   z.object({ type: z.literal("a"), a: z.string() }),
   z.object({ type: z.literal("b"), b: z.number() }),
diff --git a/packages/docs/content/v4/index.mdx b/packages/docs/content/v4/index.mdx
index 245a362d..8336a75a 100644
--- a/packages/docs/content/v4/index.mdx
+++ b/packages/docs/content/v4/index.mdx
@@ -520,105 +520,6 @@ z.toJSONSchema(mySchema);
 Refer to the [JSON Schema docs](/json-schema) for information on customizing the generated JSON Schema.
 
 
-## `z.interface()`
-
-Zod 4 introduces a new API for defining object types: `z.interface()`. This may seem surprising or confusing, so I'll briefly explain the reasoning here. (A full blog post on this topic is coming soon.)
-
-### Exact(er) optional properties
-
-In TypeScript a property can be "optional" in two distinct ways:
-
-```ts
-type KeyOptional = { prop?: string };
-type ValueOptional = { prop: string | undefined };
-```
-
-In `KeyOptional`, the `prop` key can be omitted from the object ("key optional"). In `ValueOptional`, the `prop` key *must be set* however it can be set to `undefined` ("value optional").
-
-Zod 3 cannot represent `ValueOptional`. Instead, `z.object()` automatically adds question marks to any key that accepts a value of `undefined`:
-
-```ts
-z.object({ name: z.string().optional() }); 
-// { name?: string | undefined }
-
-z.object({ name: z.union([z.string(), z.undefined()]) }); 
-// { name?: string | undefined }
-```
-
-This includes special schema types like `z.unknown()`:
-
-```ts
-z.object({ name: z.unknown() }); // { name?: unknown } 
-z.object({ name: z.any() }); // { name?: any } 
-```
-
-To properly represent "key optionality", Zod needed an *object-level* API for marking keys as optional, instead of trying to guess based on the value schema.
-
-This is why Zod 4 introduces a new API for defining object types: `z.interface()`.
-
-```ts
-const ValueOptional = z.interface({ name: z.string().optional()}); 
-// { name: string | undefined }
-
-const KeyOptional = z.interface({ "name?": z.string() }); 
-// { name?: string }
-```
-
-Key optionality is now defined with a `?` suffix in the key itself. This way, you have the power to differentiate between key- and value-optionality.
-
-> Besides this change to optionality, `z.object()` and `z.interface()` are functionality identical. They even use the same parser internally. 
-
-The `z.object()` API is *not deprecated*; feel free to continue using it if you prefer it! For the sake of backwards compatibility, `z.interface()` was added as an opt-in API.
-
-### True recursive types
-
-But wait there's more! After implementing `z.interface()`, I had a huge realization. The `?`-suffix API in `z.interface()` lets Zod sidestep a TypeScript limitation that has long prevented Zod from cleanly representing recursive (cyclical) types. Take this example from the old Zod 3 docs: 
-
-```ts
-import * as z from "zod"; // zod@3
-
-interface Category  {
-  name: string;
-  subcategories: Category[];
-};
-
-const Category: z.ZodType<Category> = z.object({
-  name: z.string(),
-  subcategories: z.lazy(() => Category.array()),
-});
-```
-
-This has been a thorn in my side for years. To define a cyclical object type, you must 
-
-- define a redundant interface
-- use `z.lazy()` to avoid reference errors
-- cast your schema to `z.ZodType`
-
-That's terrible.
-
-Here's the same example in Zod 4:
-
-```ts
-import * as z from "zod"; // zod@4
-
-const Category = z.interface({
-  name: z.string(),
-  get subcategories() {
-    return z.array(Category)
-  }
-});
-```
-
-No casting, no `z.lazy()`, no redundant type signatures. Just use [getters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) to define any cyclical properties. The resulting instance has all the object methods you expect:
-
-```ts
-Category.pick({ subcategories: true });
-```
-
-This means Zod can finally represent commonly cyclical data structure like ORM schemas, GraphQL types, etc. 
-
-> Given its ability to represent both cyclical types and more exact optionality, I recommend always using `z.interface()` over `z.object()` without reservation. That said, `z.object()` will never be deprecated or removed, so feel free to keep using it if you prefer.
-
 
 ## File schemas
 
@@ -899,7 +800,7 @@ const MyErrors = z.discriminatedUnion([
 ]);
 
 const MyResult = z.discriminatedUnion([
-  z.interface({ status: z.literal("success"), data: z.string() }),
+  z.object({ status: z.literal("success"), data: z.string() }),
   MyErrors
 ]);
 ```
@@ -972,7 +873,7 @@ If you're building a schema library, refer to the implementations of `zod` and `
 
 ## Wrapping up
 
-I'm planning to write up a series of additional posts explaining the design process and rationale behind some major features like `@zod/mini` and `z.interface()`. I'll update this section as those get posted. 
+I'm planning to write up a series of additional posts explaining the design process and rationale behind some major features like `@zod/mini`. I'll update this section as those get posted. 
 
 Zod 4 will remain in beta for roughly 6 weeks as I work with library authors and major adopters to ensure a smooth day-one transition from Zod 3 to Zod 4. I encourage all users of Zod to upgrade their installation and provide feedback during the beta window.
 
diff --git a/packages/mini/src/schemas.ts b/packages/mini/src/schemas.ts
index ad829375..a0655471 100644
--- a/packages/mini/src/schemas.ts
+++ b/packages/mini/src/schemas.ts
@@ -7,7 +7,7 @@ export * as iso from "./iso.js";
 
 type SomeType = core.$ZodType;
 
-export interface ZodMiniType<out O = unknown, out I = unknown> extends core.$ZodType<O, I> {
+export interface ZodMiniType<out Output = unknown, out Input = unknown> extends core.$ZodType<Output, Input> {
   check(...checks: (core.CheckFn<this["_zod"]["output"]> | core.$ZodCheck<this["_zod"]["output"]>)[]): this;
   clone(def?: this["_zod"]["def"]): this;
   register<R extends core.$ZodRegistry>(
@@ -20,7 +20,7 @@ export interface ZodMiniType<out O = unknown, out I = unknown> extends core.$Zod
   ): this;
   brand<T extends PropertyKey = PropertyKey>(
     value?: T
-  ): this & Record<"_zod", Record<"output", this["_zod"]["output"] & core.$brand<T>>>;
+  ): PropertyKey extends T ? this : this & Record<"_zod", Record<"~output", core.output<this> & core.$brand<T>>>;
 
   def: this["_zod"]["def"];
 
@@ -439,7 +439,7 @@ export const ZodMiniNumberFormat: core.$constructor<ZodMiniNumberFormat> = /*@__
   "ZodMiniNumberFormat",
   (inst, def) => {
     core.$ZodNumberFormat.init(inst, def);
-    ZodMiniType.init(inst, def);
+    ZodMiniNumber.init(inst, def);
   }
 );
 
@@ -683,126 +683,21 @@ export function array<T extends SomeType>(element: SomeType, params?: any): ZodM
   }) as ZodMiniArray<T>;
 }
 
-// ZodMiniObjectLike
-export interface ZodMiniObjectLike<out O = object, out I = object> extends ZodMiniType {
-  _zod: core.$ZodObjectLikeInternals<O, I>;
-}
-export const ZodMiniObjectLike: core.$constructor<ZodMiniObjectLike> = /*@__PURE__*/ core.$constructor(
-  "ZodMiniObjectLike",
-  (inst, def) => {
-    core.$ZodObjectLike.init(inst, def);
-    ZodMiniType.init(inst, def);
-  }
-);
-
 // .keyof
-export function keyof<T extends ZodMiniObject>(schema: T): ZodMiniLiteral<keyof T["_zod"]["def"]["shape"]>;
-export function keyof<T extends ZodMiniInterface>(schema: T): ZodMiniLiteral<keyof T["_zod"]["output"]>;
-export function keyof(schema: ZodMiniObjectLike) {
-  const shape =
-    schema._zod.def.type === "interface"
-      ? util.cleanInterfaceShape(schema._zod.def.shape).shape
-      : schema._zod.def.shape;
-
+export function keyof<T extends ZodMiniObject>(schema: T): ZodMiniLiteral<keyof T["shape"]> {
+  const shape = schema._zod.def.shape;
   return literal(Object.keys(shape)) as any;
 }
 
-// ZodMiniInterface
-export interface ZodMiniInterface<
-  Shape extends core.$ZodLooseShape = core.$ZodLooseShape,
-  Params extends core.$ZodInterfaceNamedParams = {
-    optional: string & keyof Shape;
-    defaulted: string & keyof Shape;
-    extra: {};
-  },
-> extends ZodMiniType {
-  _zod: core.$ZodInterfaceInternals<Shape, Params>;
-}
-export const ZodMiniInterface: core.$constructor<ZodMiniInterface> = /*@__PURE__*/ core.$constructor(
-  "ZodMiniInterface",
-  (inst, def) => {
-    core.$ZodInterface.init(inst, def);
-    ZodMiniType.init(inst, def);
-  }
-);
-
-function _interface<T extends core.$ZodLooseShape>(
-  shape: T,
-  params?: string | core.$ZodInterfaceParams,
-  Class: util.Constructor<ZodMiniInterface> = ZodMiniInterface
-): ZodMiniInterface<util.CleanInterfaceShape<T>, util.InitInterfaceParams<T, {}>> {
-  const cleaned = util.cached(() => util.cleanInterfaceShape(shape));
-  const def: core.$ZodInterfaceDef = {
-    type: "interface",
-    get shape() {
-      const _shape = cleaned.value.shape;
-      util.assignProp(this, "shape", _shape);
-      return _shape;
-      // return cleaned.value.shape;
-    },
-    get optional() {
-      return cleaned.value.optional;
-    },
-    ...util.normalizeParams(params),
-  };
-  return new Class(def) as any;
-}
-export { _interface as interface };
-
-// strictInterface
-
-export function strictInterface<T extends core.$ZodLooseShape>(
-  shape: T,
-  params?: string | core.$ZodInterfaceParams
-): ZodMiniInterface<util.CleanInterfaceShape<T>, util.InitInterfaceParams<T, {}>> {
-  const cleaned = util.cached(() => util.cleanInterfaceShape(shape));
-  const def: core.$ZodInterfaceDef = {
-    type: "interface",
-    get shape() {
-      const _shape = cleaned.value.shape;
-      util.assignProp(this, "shape", _shape);
-      return _shape;
-      // return cleaned.value.shape;
-    },
-    get optional() {
-      return cleaned.value.optional;
-    },
-    catchall: never(),
-    ...util.normalizeParams(params),
-  };
-  return new ZodMiniInterface(def) as any;
-}
-
-// looseInterface
-
-export function looseInterface<T extends core.$ZodLooseShape>(
-  shape: T,
-  params?: string | core.$ZodInterfaceParams
-): ZodMiniInterface<util.CleanInterfaceShape<T>, util.InitInterfaceParams<T, Record<string, unknown>>> {
-  const cleaned = util.cached(() => util.cleanInterfaceShape(shape));
-  const def: core.$ZodInterfaceDef = {
-    type: "interface",
-    get optional() {
-      return cleaned.value.optional;
-    },
-    get shape() {
-      // return cleaned.value.shape;
-      const _shape = cleaned.value.shape;
-      util.assignProp(this, "shape", _shape);
-      return _shape;
-    },
-    catchall: unknown(),
-    ...util.normalizeParams(params),
-  };
-  return new ZodMiniInterface(def) as any;
-}
-
 // ZodMiniObject
 export interface ZodMiniObject<
-  Shape extends core.$ZodShape = core.$ZodShape,
-  Extra extends Record<string, unknown> = Record<string, unknown>,
+  // @ts-ignore Cast variance
+  out Shape extends core.$ZodShape = core.$ZodShape,
+  OutExtra extends Record<string, unknown> = Record<string, unknown>,
+  InExtra extends Record<string, unknown> = Record<string, unknown>,
 > extends ZodMiniType {
-  _zod: core.$ZodObjectInternals<Shape, Extra>;
+  _zod: core.$ZodObjectInternals<Shape, OutExtra, InExtra>;
+  shape: Shape;
 }
 export const ZodMiniObject: core.$constructor<ZodMiniObject> = /*@__PURE__*/ core.$constructor(
   "ZodMiniObject",
@@ -813,13 +708,13 @@ export const ZodMiniObject: core.$constructor<ZodMiniObject> = /*@__PURE__*/ cor
 );
 export function object<T extends core.$ZodShape = Record<never, SomeType>>(
   shape?: T,
-  params?: string | core.$ZodObjectLikeParams
-): ZodMiniObject<T, {}> {
+  params?: string | core.$ZodObjectParams
+): ZodMiniObject<T, {}, {}> {
   const def: core.$ZodObjectDef = {
     type: "object",
-    shape: shape ?? {},
-    get optional() {
-      return util.optionalObjectKeys(shape ?? {});
+    get shape() {
+      util.assignProp(this, "shape", { ...shape });
+      return this.shape;
     },
     ...util.normalizeParams(params),
   };
@@ -831,13 +726,17 @@ export function object<T extends core.$ZodShape = Record<never, SomeType>>(
 export function strictObject<T extends core.$ZodShape>(
   shape: T,
   params?: string | core.$ZodObjectParams
-): ZodMiniObject<T, {}> {
+): ZodMiniObject<T, {}, {}> {
   return new ZodMiniObject({
     type: "object",
-    shape: shape as core.$ZodShape,
-    get optional() {
-      return util.optionalObjectKeys(shape);
+    // shape: shape as core.$ZodShape,
+    get shape() {
+      util.assignProp(this, "shape", { ...shape });
+      return this.shape;
     },
+    // get optional() {
+    //   return util.optionalObjectKeys(shape);
+    // },
     catchall: never(),
     ...util.normalizeParams(params),
   }) as any;
@@ -848,218 +747,117 @@ export function strictObject<T extends core.$ZodShape>(
 export function looseObject<T extends core.$ZodShape>(
   shape: T,
   params?: string | core.$ZodObjectParams
-): ZodMiniObject<T, { [k: string]: unknown }> {
+): ZodMiniObject<T, { [k: string]: unknown }, { [k: string]: unknown }> {
   return new ZodMiniObject({
     type: "object",
-    shape: shape as core.$ZodShape,
-    get optional() {
-      return util.optionalObjectKeys(shape);
+    // shape: shape as core.$ZodShape,
+    get shape() {
+      util.assignProp(this, "shape", { ...shape });
+      return this.shape;
     },
+    // get optional() {
+    //   return util.optionalObjectKeys(shape);
+    // },
     catchall: unknown(),
     ...util.normalizeParams(params),
   }) as any;
 }
 
 // object methods
-export function extend<T extends ZodMiniInterface, U extends ZodMiniInterface>(
-  a: T,
-  b: U
-): ZodMiniInterface<util.Extend<T["_zod"]["def"]["shape"], U["_zod"]["def"]["shape"]>, util.MergeInterfaceParams<T, U>>;
-export function extend<T extends ZodMiniObject, U extends ZodMiniObject>(
-  a: T,
-  b: U
-): ZodMiniObject<
-  util.Extend<T["_zod"]["def"]["shape"], U["_zod"]["def"]["shape"]>,
-  U["_zod"]["extra"] & T["_zod"]["extra"]
->;
-
-export function extend<T extends ZodMiniInterface, U extends core.$ZodLooseShape>(
-  a: T,
-  b: U
-): ZodMiniInterface<util.ExtendInterfaceShape<T["_zod"]["def"]["shape"], U>, util.ExtendInterfaceParams<T, U>>;
 export function extend<T extends ZodMiniObject, U extends core.$ZodLooseShape>(
+  schema: T,
+  shape: U
+): ZodMiniObject<util.Extend<T["shape"], U>, T["_zod"]["outextra"], T["_zod"]["inextra"]> {
+  return util.extend(schema, shape);
+}
+
+/** @deprecated Identical to `z.extend(A, B)` */
+export function merge<T extends ZodMiniObject, U extends ZodMiniObject>(
   a: T,
   b: U
-): ZodMiniObject<util.Extend<T["_zod"]["def"]["shape"], U>, T["_zod"]["extra"]>;
-export function extend(schema: ZodMiniObjectLike, shape: any): ZodMiniObjectLike {
-  // console.log({ schema, shape });
-  if (shape instanceof core.$ZodType) return util.mergeObjectLike(schema, shape as any);
-  if (schema instanceof ZodMiniInterface) {
-    return util.mergeObjectLike(schema, _interface(shape));
-  }
-  if (schema instanceof ZodMiniObject) return util.mergeObjectLike(schema, object(shape));
+): ZodMiniObject<util.Extend<T["shape"], U["shape"]>, T["_zod"]["outextra"], T["_zod"]["inextra"]>;
+export function merge(schema: ZodMiniObject, shape: any): ZodMiniObject {
   return util.extend(schema, shape);
 }
 
-export function merge<T extends ZodMiniObjectLike, U extends core.$ZodLooseShape>(
-  schema: T,
-  shape: U
-): T["_zod"]["def"]["type"] extends "interface"
-  ? ZodMiniInterface<
-      util.Extend<T["_zod"]["def"]["shape"], U["_zod"]["def"]["shape"]>,
-      {
-        extra: T["_zod"]["extra"] & U["_zod"]["extra"];
-        optional: Exclude<T["_zod"]["optional"], keyof U["_zod"]["def"]["shape"]> | U["_zod"]["optional"];
-        defaulted: Exclude<T["_zod"]["defaulted"], keyof U["_zod"]["def"]["shape"]> | U["_zod"]["defaulted"];
-      }
-    >
-  : ZodMiniObject<util.Extend<T["_zod"]["def"]["shape"], U>, T["_zod"]["extra"]>;
-export function merge(a: ZodMiniObjectLike, b: ZodMiniObjectLike): ZodMiniObjectLike {
-  return util.mergeObjectLike(a, b);
-}
-
-// .pick
-export function pick<
-  T extends ZodMiniObjectLike,
-  M extends util.Exactly<util.Mask<keyof T["_zod"]["def"]["shape"]>, M>,
->(
+export function pick<T extends ZodMiniObject, M extends util.Exactly<util.Mask<keyof T["shape"]>, M>>(
   schema: T,
   mask: M
-): T["_zod"]["def"]["type"] extends "interface"
-  ? ZodMiniInterface<
-      util.Flatten<Pick<T["_zod"]["def"]["shape"], keyof T["_zod"]["def"]["shape"] & keyof M>>,
-      {
-        optional: Extract<T["_zod"]["optional"], keyof M>;
-        defaulted: Extract<T["_zod"]["defaulted"], keyof M>;
-        extra: T["_zod"]["extra"];
-      }
-    >
-  : ZodMiniObject<
-      util.Flatten<Pick<T["_zod"]["def"]["shape"], keyof T["_zod"]["def"]["shape"] & keyof M>>,
-      T["_zod"]["extra"]
-    >;
-export function pick(schema: ZodMiniObjectLike, mask: object) {
-  return util.pick(schema, mask);
+): ZodMiniObject<
+  util.Flatten<Pick<T["shape"], keyof T["shape"] & keyof M>>,
+  T["_zod"]["outextra"],
+  T["_zod"]["inextra"]
+> {
+  return util.pick(schema, mask as any);
 }
 
 // .omit
-export function omit<
-  T extends ZodMiniObjectLike,
-  const M extends util.Exactly<util.Mask<keyof T["_zod"]["def"]["shape"]>, M>,
->(
+
+export function omit<T extends ZodMiniObject, const M extends util.Exactly<util.Mask<keyof T["shape"]>, M>>(
   schema: T,
   mask: M
-): T["_zod"]["def"]["type"] extends "interface"
-  ? ZodMiniInterface<
-      util.Flatten<Omit<T["_zod"]["def"]["shape"], keyof M>>,
-      {
-        optional: Exclude<T["_zod"]["optional"], keyof M>;
-        defaulted: Exclude<T["_zod"]["defaulted"], keyof M>;
-        extra: T["_zod"]["extra"];
-      }
-    >
-  : ZodMiniObject<util.Flatten<Omit<T["_zod"]["def"]["shape"], keyof M>>, T["_zod"]["extra"]>;
-
-export function omit(schema: ZodMiniObjectLike, mask: object) {
+): ZodMiniObject<util.Flatten<Omit<T["shape"], keyof M>>, T["_zod"]["outextra"], T["_zod"]["inextra"]> {
   return util.omit(schema, mask);
 }
 
-export function partial<T extends ZodMiniObjectLike>(
+export function partial<T extends ZodMiniObject>(
   schema: T
-): T["_zod"]["def"]["type"] extends "interface"
-  ? ZodMiniInterface<
-      // T['_zod']["shape"],
-      {
-        [k in keyof T["_zod"]["def"]["shape"]]: ZodMiniOptional<T["_zod"]["def"]["shape"][k]>;
-      },
-      {
-        optional: string & keyof T["_zod"]["def"]["shape"];
-        defaulted: never;
-        extra: T["_zod"]["extra"];
-      }
-    >
-  : ZodMiniObject<
-      {
-        [k in keyof T["_zod"]["def"]["shape"]]: ZodMiniOptional<T["_zod"]["def"]["shape"][k]>;
-      },
-      T["_zod"]["extra"]
-    >;
-export function partial<
-  T extends ZodMiniObjectLike,
-  M extends util.Exactly<util.Mask<keyof T["_zod"]["def"]["shape"]>, M>,
->(
-  schema: T,
-  mask: M
-): T["_zod"]["def"]["type"] extends "interface"
-  ? ZodMiniInterface<
-      util.Extend<
-        T["_zod"]["def"]["shape"],
-        {
-          [k in keyof M & keyof T["_zod"]["def"]["shape"]]: ZodMiniOptional<T["_zod"]["def"]["shape"][k]>;
-        }
-      >,
-      {
-        optional: string & (T["_zod"]["optional"] | keyof M);
-        defaulted: T["_zod"]["defaulted"];
-        extra: T["_zod"]["extra"];
-      }
-    >
-  : ZodMiniObject<
-      {
-        [k in keyof T["_zod"]["def"]["shape"]]: k extends keyof M
-          ? ZodMiniOptional<T["_zod"]["def"]["shape"][k]>
-          : T["_zod"]["def"]["shape"][k];
-      },
-      T["_zod"]["extra"]
-    >;
-
-export function partial(schema: ZodMiniObjectLike, mask?: object): ZodMiniObjectLike {
-  return util.partialObjectLike(ZodMiniOptional, schema, mask);
-}
-
-// .required
-export function required<T extends { _zod: { subtype: "object" } } & ZodMiniObject>(
-  schema: T
-): ZodMiniObject<{
-  [k in keyof T["_zod"]["def"]["shape"]]: ZodMiniNonOptional<T["_zod"]["def"]["shape"][k]>;
-}>;
-export function required<
-  T extends { _zod: { subtype: "object" } } & ZodMiniObject,
-  M extends util.Exactly<util.Mask<keyof T["_zod"]["def"]["shape"]>, M>,
->(
+): ZodMiniObject<
+  {
+    [k in keyof T["shape"]]: ZodMiniOptional<T["shape"][k]>;
+  },
+  T["_zod"]["outextra"],
+  T["_zod"]["inextra"]
+>;
+export function partial<T extends ZodMiniObject, M extends util.Exactly<util.Mask<keyof T["shape"]>, M>>(
   schema: T,
   mask: M
 ): ZodMiniObject<
-  util.Extend<
-    T["_zod"]["def"]["shape"],
-    {
-      [k in keyof M & keyof T["_zod"]["def"]["shape"]]: ZodMiniNonOptional<T["_zod"]["def"]["shape"][k]>;
-    }
-  >
->;
-export function required<T extends { _zod: { subtype: "interface" } } & ZodMiniInterface>(
-  schema: T
-): ZodMiniInterface<
   {
-    [k in keyof T["_zod"]["def"]["shape"]]: ZodMiniNonOptional<T["_zod"]["def"]["shape"][k]>;
+    [k in keyof T["shape"]]: k extends keyof M ? ZodMiniOptional<T["shape"][k]> : T["shape"][k];
   },
+  T["_zod"]["outextra"],
+  T["_zod"]["inextra"]
+>;
+export function partial(schema: ZodMiniObject, mask?: object) {
+  return util.partial(ZodMiniOptional, schema, mask);
+}
+
+export type RequiredInterfaceShape<
+  Shape extends core.$ZodLooseShape,
+  Keys extends PropertyKey = keyof Shape,
+> = util.Identity<
   {
-    optional: never;
-    defaulted: T["_zod"]["defaulted"];
-    extra: T["_zod"]["extra"];
+    [k in keyof Shape as k extends Keys ? k : never]: ZodMiniNonOptional<Shape[k]>;
+  } & {
+    [k in keyof Shape as k extends Keys ? never : k]: Shape[k];
   }
 >;
-export function required<
-  T extends { _zod: { subtype: "interface" } } & ZodMiniInterface,
-  M extends util.Mask<keyof T["_zod"]["output"]>,
->(
+
+export function required<T extends ZodMiniObject>(
+  schema: T
+): ZodMiniObject<
+  {
+    [k in keyof T["shape"]]: ZodMiniNonOptional<T["shape"][k]>;
+  },
+  T["_zod"]["outextra"],
+  T["_zod"]["inextra"]
+>;
+export function required<T extends ZodMiniObject, M extends util.Exactly<util.Mask<keyof T["shape"]>, M>>(
   schema: T,
   mask: M
-): ZodMiniInterface<
+): ZodMiniObject<
   util.Extend<
-    T["_zod"]["def"]["shape"],
+    T["shape"],
     {
-      [k in keyof M & keyof T["_zod"]["def"]["shape"]]: ZodMiniNonOptional<T["_zod"]["def"]["shape"][k]>;
+      [k in keyof M & keyof T["shape"]]: ZodMiniNonOptional<T["shape"][k]>;
     }
   >,
-  {
-    optional: Exclude<T["_zod"]["optional"], keyof M>;
-    defaulted: T["_zod"]["defaulted"];
-    extra: T["_zod"]["extra"];
-  }
+  T["_zod"]["outextra"],
+  T["_zod"]["inextra"]
 >;
-export function required(schema: ZodMiniObjectLike, mask?: object): ZodMiniObjectLike {
-  return util.requiredObjectLike(ZodMiniNonOptional, schema, mask);
+export function required(schema: ZodMiniObject, mask?: object) {
+  return util.required(ZodMiniNonOptional, schema, mask);
 }
 
 // ZodMiniUnion
diff --git a/packages/treeshake/out.js b/packages/treeshake/out.js
index b608b0c0..d2ff0fbc 100644
--- a/packages/treeshake/out.js
+++ b/packages/treeshake/out.js
@@ -46,14 +46,6 @@ function jsonStringifyReplacer(_, value) {
         return value.toString();
     return value;
 }
-function nullish(input) {
-    return input === null || input === undefined;
-}
-function cleanRegex(source) {
-    const start = source.startsWith("^") ? 1 : 0;
-    const end = source.endsWith("$") ? source.length - 1 : source.length;
-    return source.slice(start, end);
-}
 function randomString(length = 10) {
     const chars = "abcdefghijklmnopqrstuvwxyz";
     let str = "";
@@ -64,23 +56,13 @@ function randomString(length = 10) {
 }
 // zod-specific utils
 function clone(inst, def) {
-    return new inst._zod.constr(def);
+    const cl = new inst._zod.constr(def ?? inst._zod.def);
+    if (!def)
+        cl._zod.parent = inst;
+    return cl;
 }
 function normalizeParams(_params) {
-    const params = _params;
-    if (!params)
-        return {};
-    if (typeof params === "string")
-        return { error: () => params };
-    if (params?.message !== undefined) {
-        if (params?.error !== undefined)
-            throw new Error("Cannot specify both `message` and `error` params");
-        params.error = params.message;
-    }
-    delete params.message;
-    if (typeof params.error === "string")
-        return { ...params, error: () => params.error };
-    return params;
+    return {};
 }
 function aborted(x, startIndex = 0) {
     for (let i = startIndex; i < x.issues.length; i++) {
@@ -89,14 +71,6 @@ function aborted(x, startIndex = 0) {
     }
     return false;
 }
-function prefixIssues(path, issues) {
-    return issues.map((iss) => {
-        var _a;
-        (_a = iss).path ?? (_a.path = []);
-        iss.path.unshift(path);
-        return iss;
-    });
-}
 function unwrapMessage(message) {
     return typeof message === "string" ? message : message?.message;
 }
@@ -120,25 +94,6 @@ function finalizeIssue(iss, ctx, config) {
     }
     return full;
 }
-function getLengthableOrigin(input) {
-    if (Array.isArray(input))
-        return "array";
-    if (typeof input === "string")
-        return "string";
-    return "unknown";
-}
-function issue(...args) {
-    const [iss, input, inst] = args;
-    if (typeof iss === "string") {
-        return {
-            message: iss,
-            code: "custom",
-            input,
-            inst,
-        };
-    }
-    return { ...iss };
-}
 
 ////////////////////////    ERROR CLASS   ////////////////////////
 const ZOD_ERROR = Symbol.for("{{zod.error}}");
@@ -156,62 +111,6 @@ class $ZodError {
         return inst?._tag === ZOD_ERROR;
     }
 }
-function flattenError(error, mapper = (issue) => issue.message) {
-    const fieldErrors = {};
-    const formErrors = [];
-    for (const sub of error.issues) {
-        if (sub.path.length > 0) {
-            fieldErrors[sub.path[0]] = fieldErrors[sub.path[0]] || [];
-            fieldErrors[sub.path[0]].push(mapper(sub));
-        }
-        else {
-            formErrors.push(mapper(sub));
-        }
-    }
-    return { formErrors, fieldErrors };
-}
-function formatError(error, _mapper) {
-    const mapper = _mapper ||
-        function (issue) {
-            return issue.message;
-        };
-    const fieldErrors = { _errors: [] };
-    const processError = (error) => {
-        for (const issue of error.issues) {
-            if (issue.code === "invalid_union") {
-                issue.errors.map((issues) => processError({ issues }));
-            }
-            else if (issue.code === "invalid_key") {
-                processError({ issues: issue.issues });
-            }
-            else if (issue.code === "invalid_element") {
-                processError({ issues: issue.issues });
-            }
-            else if (issue.path.length === 0) {
-                fieldErrors._errors.push(mapper(issue));
-            }
-            else {
-                let curr = fieldErrors;
-                let i = 0;
-                while (i < issue.path.length) {
-                    const el = issue.path[i];
-                    const terminal = i === issue.path.length - 1;
-                    if (!terminal) {
-                        curr[el] = curr[el] || { _errors: [] };
-                    }
-                    else {
-                        curr[el] = curr[el] || { _errors: [] };
-                        curr[el]._errors.push(mapper(issue));
-                    }
-                    curr = curr[el];
-                    i++;
-                }
-            }
-        }
-    };
-    processError(error);
-    return fieldErrors;
-}
 
 function _parse(schema, value, _ctx) {
     const ctx = _ctx ? { ..._ctx, async: false } : { async: false };
@@ -263,98 +162,11 @@ async function _safeParseAsync(schema, value, _ctx) {
 
 const boolean$1 = /true|false/i;
 
-// import { $ZodType } from "./schemas.js";
-const $ZodCheck = /*@__PURE__*/ $constructor("$ZodCheck", (inst, def) => {
-    inst._zod ?? (inst._zod = {});
-    inst._zod.def = def;
-});
-const $ZodCheckMaxLength = /*@__PURE__*/ $constructor("$ZodCheckMaxLength", (inst, def) => {
-    $ZodCheck.init(inst, def);
-    inst._zod.when = (payload) => {
-        const val = payload.value;
-        return !nullish(val) && val.length !== undefined;
-    };
-    inst._zod.onattach = (inst) => {
-        const curr = (inst._zod.computed.maximum ?? Number.POSITIVE_INFINITY);
-        if (def.maximum < curr)
-            inst._zod.computed.maximum = def.maximum;
-    };
-    inst._zod.check = (payload) => {
-        const input = payload.value;
-        const length = input.length;
-        if (length <= def.maximum)
-            return;
-        const origin = getLengthableOrigin(input);
-        payload.issues.push({
-            origin,
-            code: "too_big",
-            maximum: def.maximum,
-            input,
-            inst,
-            continue: !def.abort,
-        });
-    };
-});
-const $ZodCheckMinLength = /*@__PURE__*/ $constructor("$ZodCheckMinLength", (inst, def) => {
-    $ZodCheck.init(inst, def);
-    inst._zod.when = (payload) => {
-        const val = payload.value;
-        return !nullish(val) && val.length !== undefined;
-    };
-    inst._zod.onattach = (inst) => {
-        const curr = (inst._zod.computed.minimum ?? Number.NEGATIVE_INFINITY);
-        if (def.minimum > curr)
-            inst._zod.computed.minimum = def.minimum;
-    };
-    inst._zod.check = (payload) => {
-        const input = payload.value;
-        const length = input.length;
-        if (length >= def.minimum)
-            return;
-        const origin = getLengthableOrigin(input);
-        payload.issues.push({
-            origin,
-            code: "too_small",
-            minimum: def.minimum,
-            input,
-            inst,
-            continue: !def.abort,
-        });
-    };
-});
-const $ZodCheckLengthEquals = /*@__PURE__*/ $constructor("$ZodCheckLengthEquals", (inst, def) => {
-    $ZodCheck.init(inst, def);
-    inst._zod.when = (payload) => {
-        const val = payload.value;
-        return !nullish(val) && val.length !== undefined;
-    };
-    inst._zod.onattach = (inst) => {
-        inst._zod.computed.minimum = def.length;
-        inst._zod.computed.maximum = def.length;
-        inst._zod.computed.length = def.length;
-    };
-    inst._zod.check = (payload) => {
-        const input = payload.value;
-        const length = input.length;
-        if (length === def.length)
-            return;
-        const origin = getLengthableOrigin(input);
-        const tooBig = length > def.length;
-        payload.issues.push({
-            origin,
-            ...(tooBig ? { code: "too_big", maximum: def.length } : { code: "too_small", minimum: def.length }),
-            input: payload.value,
-            inst,
-            continue: !def.abort,
-        });
-    };
-});
-const $ZodCheckOverwrite = /*@__PURE__*/ $constructor("$ZodCheckOverwrite", (inst, def) => {
-    $ZodCheck.init(inst, def);
-    inst._zod.check = (payload) => {
-        payload.value = def.tx(payload.value);
-    };
-});
+const version = {
+    major: 0,
+    minor: 8,
+    patch: 1,
+};
 
 const $ZodType = /*@__PURE__*/ $constructor("$ZodType", (inst, def) => {
     var _a;
@@ -362,6 +174,8 @@ const $ZodType = /*@__PURE__*/ $constructor("$ZodType", (inst, def) => {
     inst._zod.id = def.type + "_" + randomString(10);
     inst._zod.def = def; // set _def property
     inst._zod.computed = inst._zod.computed || {}; // initialize _computed object
+    inst._zod.version = version;
+    // inst._zod.optionality ??= "required"; // default
     const checks = [...(inst._zod.def.checks ?? [])];
     // if inst is itself a checks.$ZodCheck, run it as a check
     if (inst._zod.traits.has("$ZodCheck")) {
@@ -369,7 +183,9 @@ const $ZodType = /*@__PURE__*/ $constructor("$ZodType", (inst, def) => {
     }
     //
     for (const ch of checks) {
-        ch._zod.onattach?.(inst);
+        for (const fn of ch._zod.onattach) {
+            fn(inst);
+        }
     }
     if (checks.length === 0) {
         // deferred initializer
@@ -400,8 +216,7 @@ const $ZodType = /*@__PURE__*/ $constructor("$ZodType", (inst, def) => {
                     throw new $ZodAsyncError();
                 }
                 if (asyncResult || _ instanceof Promise) {
-                    asyncResult = asyncResult ?? Promise.resolve();
-                    asyncResult.then(async () => {
+                    asyncResult = (asyncResult ?? Promise.resolve()).then(async () => {
                         await _;
                         const nextLen = payload.issues.length;
                         if (nextLen === currLen)
@@ -442,12 +257,12 @@ const $ZodType = /*@__PURE__*/ $constructor("$ZodType", (inst, def) => {
                 return result.then(({ issues, value }) => {
                     if (issues.length === 0)
                         return { value };
-                    return { issues };
+                    return { issues: issues.map((iss) => finalizeIssue(iss, {}, config())) };
                 });
             }
             if (result.issues.length === 0)
                 return { value: result.value };
-            return { issues: result.issues };
+            return { issues: result.issues.map((iss) => finalizeIssue(iss, {}, config())) };
         },
         vendor: "zod",
         version: 1,
@@ -474,682 +289,52 @@ const $ZodBoolean = /*@__PURE__*/ $constructor("$ZodBoolean", (inst, def) => {
         return payload;
     };
 });
-function handleArrayResult(result, final, index) {
-    if (result.issues.length) {
-        final.issues.push(...prefixIssues(index, result.issues));
-    }
-    final.value[index] = result.value;
-}
-const $ZodArray = /*@__PURE__*/ $constructor("$ZodArray", (inst, def) => {
-    $ZodType.init(inst, def);
-    inst._zod.parse = (payload, ctx) => {
-        const input = payload.value;
-        if (!Array.isArray(input)) {
-            payload.issues.push({
-                expected: "array",
-                code: "invalid_type",
-                input,
-                inst,
-            });
-            return payload;
-        }
-        payload.value = Array(input.length);
-        const proms = [];
-        for (let i = 0; i < input.length; i++) {
-            const item = input[i];
-            const result = def.element._zod.run({
-                value: item,
-                issues: [],
-            }, ctx);
-            if (result instanceof Promise) {
-                proms.push(result.then((result) => handleArrayResult(result, payload, i)));
-            }
-            else {
-                handleArrayResult(result, payload, i);
-            }
-        }
-        if (proms.length) {
-            return Promise.all(proms).then(() => payload);
-        }
-        return payload; //handleArrayResultsAsync(parseResults, final);
-    };
-});
-function handleUnionResults(results, final, inst, ctx) {
-    for (const result of results) {
-        if (result.issues.length === 0) {
-            final.value = result.value;
-            return final;
-        }
-    }
-    final.issues.push({
-        code: "invalid_union",
-        input: final.value,
-        inst,
-        errors: results.map((result) => result.issues.map((iss) => finalizeIssue(iss, ctx, config()))),
-    });
-    return final;
-}
-const $ZodUnion = /*@__PURE__*/ $constructor("$ZodUnion", (inst, def) => {
-    $ZodType.init(inst, def);
-    const values = new Set();
-    if (def.options.every((o) => o._zod.values)) {
-        for (const option of def.options) {
-            for (const v of option._zod.values) {
-                values.add(v);
-            }
-        }
-        inst._zod.values = values;
-    }
-    // computed union regex for pattern if all options have pattern
-    if (def.options.every((o) => o._zod.pattern)) {
-        const patterns = def.options.map((o) => o._zod.pattern);
-        inst._zod.pattern = new RegExp(`^(${patterns.map((p) => cleanRegex(p.source)).join("|")})$`);
-    }
-    inst._zod.parse = (payload, ctx) => {
-        const results = [];
-        for (const option of def.options) {
-            const result = option._zod.run({
-                value: payload.value,
-                issues: [],
-            }, ctx);
-            if (result instanceof Promise) {
-                results.push(result);
-            }
-            else {
-                if (result.issues.length === 0)
-                    return result;
-                results.push(result);
-            }
-        }
-        return handleUnionResults(results, payload, inst, ctx);
-    };
-});
-const $ZodTransform = /*@__PURE__*/ $constructor("$ZodTransform", (inst, def) => {
-    $ZodType.init(inst, def);
-    inst._zod.parse = (payload, _ctx) => {
-        const _out = def.transform(payload.value, payload);
-        if (_ctx.async) {
-            const output = _out instanceof Promise ? _out : Promise.resolve(_out);
-            return output.then((output) => {
-                payload.value = output;
-                return payload;
-            });
-        }
-        if (_out instanceof Promise) {
-            throw new $ZodAsyncError();
-        }
-        payload.value = _out;
-        return payload;
-    };
-});
-const $ZodOptional = /*@__PURE__*/ $constructor("$ZodOptional", (inst, def) => {
-    $ZodType.init(inst, def);
-    // inst._zod.qin = "true";
-    inst._zod.qout = "true";
-    if (def.innerType._zod.values)
-        inst._zod.values = new Set([...def.innerType._zod.values, undefined]);
-    const pattern = def.innerType._zod.pattern;
-    if (pattern)
-        inst._zod.pattern = new RegExp(`^(${cleanRegex(pattern.source)})?$`);
-    inst._zod.parse = (payload, ctx) => {
-        if (payload.value === undefined) {
-            return payload;
-        }
-        return def.innerType._zod.run(payload, ctx);
-    };
-});
-const $ZodNullable = /*@__PURE__*/ $constructor("$ZodNullable", (inst, def) => {
-    $ZodType.init(inst, def);
-    inst._zod.qin = def.innerType._zod.qin;
-    inst._zod.qout = def.innerType._zod.qout;
-    const pattern = def.innerType._zod.pattern;
-    if (pattern)
-        inst._zod.pattern = new RegExp(`^(${cleanRegex(pattern.source)}|null)$`);
-    if (def.innerType._zod.values)
-        inst._zod.values = new Set([...def.innerType._zod.values, null]);
-    inst._zod.parse = (payload, ctx) => {
-        if (payload.value === null)
-            return payload;
-        return def.innerType._zod.run(payload, ctx);
-    };
-});
-const $ZodDefault = /*@__PURE__*/ $constructor("$ZodDefault", (inst, def) => {
-    $ZodType.init(inst, def);
-    inst._zod.values = def.innerType._zod.values;
-    inst._zod.parse = (payload, ctx) => {
-        if (payload.value === undefined) {
-            payload.value = def.defaultValue();
-            /**
-             * $ZodDefault always returns the default value immediately.
-             * It doesn't pass the default value into the validator ("prefault"). There's no reason to pass the default value through validation. The validity of the default is enforced by TypeScript statically. Otherwise, it's the responsibility of the user to ensure the default is valid. In the case of pipes with divergent in/out types, you can specify the default on the `in` schema of your ZodPipe to set a "prefault" for the pipe.   */
-            return payload;
-        }
-        const result = def.innerType._zod.run(payload, ctx);
-        if (result instanceof Promise) {
-            return result.then((result) => handleDefaultResult(result, def));
-        }
-        return handleDefaultResult(result, def);
-    };
-});
-function handleDefaultResult(payload, def) {
-    if (payload.value === undefined) {
-        payload.value = def.defaultValue();
-    }
-    return payload;
-}
-const $ZodNonOptional = /*@__PURE__*/ $constructor("$ZodNonOptional", (inst, def) => {
-    $ZodType.init(inst, def);
-    if (def.innerType._zod.values)
-        inst._zod.values = new Set([...def.innerType._zod.values].filter((x) => x !== undefined));
-    inst._zod.parse = (payload, ctx) => {
-        const result = def.innerType._zod.run(payload, ctx);
-        if (result instanceof Promise) {
-            return result.then((result) => handleNonOptionalResult(result, inst));
-        }
-        return handleNonOptionalResult(result, inst);
-    };
-});
-function handleNonOptionalResult(payload, inst) {
-    if (!payload.issues.length && payload.value === undefined) {
-        payload.issues.push({
-            code: "invalid_type",
-            expected: "nonoptional",
-            input: payload.value,
-            inst,
-        });
-    }
-    return payload;
-}
-const $ZodCatch = /*@__PURE__*/ $constructor("$ZodCatch", (inst, def) => {
-    $ZodType.init(inst, def);
-    // inst._zod.qin = def.innerType._zod.qin;
-    inst._zod.qout = def.innerType._zod.qout;
-    inst._zod.values = def.innerType._zod.values;
-    inst._zod.parse = (payload, ctx) => {
-        const result = def.innerType._zod.run(payload, ctx);
-        if (result instanceof Promise) {
-            return result.then((result) => {
-                if (result.issues.length) {
-                    payload.value = def.catchValue({
-                        ...payload,
-                        error: { issues: result.issues.map((iss) => finalizeIssue(iss, ctx, config())) },
-                        input: payload.value,
-                    });
-                    payload.issues = [];
-                }
-                else {
-                    payload.value = result.value;
-                }
-                return payload;
-            });
-        }
-        if (result.issues.length) {
-            payload.value = def.catchValue({
-                ...payload,
-                error: { issues: result.issues.map((iss) => finalizeIssue(iss, ctx, config())) },
-                input: payload.value,
-            });
-            payload.issues = [];
-        }
-        else {
-            payload.value = result.value;
-        }
-        return payload;
-    };
-});
-const $ZodPipe = /*@__PURE__*/ $constructor("$ZodPipe", (inst, def) => {
-    $ZodType.init(inst, def);
-    // inst._zod.qin = def.in._zod.qin;
-    // inst._zod.qout = def.in._zod.qout;
-    inst._zod.values = def.in._zod.values;
-    inst._zod.parse = (payload, ctx) => {
-        const left = def.in._zod.run(payload, ctx);
-        if (left instanceof Promise) {
-            return left.then((left) => handlePipeResult(left, def, ctx));
-        }
-        return handlePipeResult(left, def, ctx);
-    };
-});
-function handlePipeResult(left, def, ctx) {
-    if (aborted(left)) {
-        return left;
-    }
-    return def.out._zod.run({ value: left.value, issues: left.issues }, ctx);
-}
-const $ZodReadonly = /*@__PURE__*/ $constructor("$ZodReadonly", (inst, def) => {
-    $ZodType.init(inst, def);
-    // inst._zod.qin = def.innerType._zod.qin;
-    inst._zod.qout = def.innerType._zod.qout;
-    inst._zod.parse = (payload, ctx) => {
-        const result = def.innerType._zod.run(payload, ctx);
-        if (result instanceof Promise) {
-            return result.then(handleReadonlyResult);
-        }
-        return handleReadonlyResult(result);
-    };
-});
-function handleReadonlyResult(payload) {
-    payload.value = Object.freeze(payload.value);
-    return payload;
-}
-const $ZodCustom = /*@__PURE__*/ $constructor("$ZodCustom", (inst, def) => {
-    // if (def.checks?.length) console.warn("Can't add custom checks to z.custom()");
-    $ZodCheck.init(inst, def);
-    $ZodType.init(inst, def);
-    inst._zod.parse = (payload, _) => {
-        return payload;
-    };
-    inst._zod.check = (payload) => {
-        const input = payload.value;
-        const r = def.fn(input);
-        if (r instanceof Promise) {
-            return r.then((r) => handleRefineResult(r, payload, input, inst));
-        }
-        handleRefineResult(r, payload, input, inst);
-        return;
-    };
-});
-function handleRefineResult(result, payload, input, inst) {
-    if (!result) {
-        const _iss = {
-            code: "custom",
-            input,
-            inst, // incorporates params.error into issue reporting
-            path: inst._zod.def.path, // incorporates params.error into issue reporting
-            continue: !inst._zod.def.abort,
-            // params: inst._zod.def.params,
-        };
-        if (inst._zod.def.params)
-            _iss.params = inst._zod.def.params;
-        payload.issues.push(issue(_iss));
-    }
-}
-
-class $ZodRegistry {
-    constructor() {
-        this._map = new WeakMap();
-        this._idmap = new Map();
-    }
-    add(schema, ..._meta) {
-        const meta = _meta[0];
-        this._map.set(schema, meta);
-        if (meta && typeof meta === "object" && "id" in meta) {
-            if (this._idmap.has(meta.id)) {
-                throw new Error(`ID ${meta.id} already exists in the registry`);
-            }
-            this._idmap.set(meta.id, schema);
-        }
-        return this;
-    }
-    remove(schema) {
-        this._map.delete(schema);
-        return this;
-    }
-    get(schema) {
-        return this._map.get(schema);
-    }
-    has(schema) {
-        return this._map.has(schema);
-    }
-}
-class $ZodJSONSchemaRegistry extends $ZodRegistry {
-    toJSONSchema(_schema) {
-        return {};
-    }
-}
-const globalRegistry = 
-/*@__PURE__*/ new $ZodJSONSchemaRegistry();
 
 function _boolean(Class, params) {
     return new Class({
         type: "boolean",
-        ...normalizeParams(params),
-    });
-}
-function _maxLength(maximum, params) {
-    const ch = new $ZodCheckMaxLength({
-        check: "max_length",
-        ...normalizeParams(params),
-        maximum,
-    });
-    return ch;
-}
-function _minLength(minimum, params) {
-    return new $ZodCheckMinLength({
-        check: "min_length",
-        ...normalizeParams(params),
-        minimum,
-    });
-}
-function _length(length, params) {
-    return new $ZodCheckLengthEquals({
-        check: "length_equals",
-        ...normalizeParams(params),
-        length,
-    });
-}
-function _overwrite(tx) {
-    return new $ZodCheckOverwrite({
-        check: "overwrite",
-        tx,
+        ...normalizeParams(),
     });
 }
-function _array(Class, element, params) {
-    return new Class({
-        type: "array",
-        element,
-        // get element() {
-        //   return element;
-        // },
-        ...normalizeParams(params),
-    });
-}
-function _custom(Class, fn, _params) {
-    const schema = new Class({
-        type: "custom",
-        check: "custom",
-        fn: fn,
-        ...normalizeParams(_params),
-    });
-    return schema;
-}
 
-class ZodError extends $ZodError {
-    format(mapper) {
-        return formatError(this, mapper);
-    }
-    flatten(mapper) {
-        return flattenError(this, mapper);
-    }
-    /** @deprecated Push directly to `.issues` instead. */
-    addIssue(issue) {
-        this.issues.push(issue);
-    }
-    /** @deprecated Push directly to `.issues` instead. */
-    addIssues(issues) {
-        this.issues.push(...issues);
-    }
-    /** @deprecated Check `err.issues.length === 0` instead. */
-    get isEmpty() {
-        return this.issues.length === 0;
-    }
-}
-// /** @deprecated Use `z.core.$ZodErrorMapCtx` instead. */
-// export type ErrorMapCtx = core.$ZodErrorMapCtx;
-
-const parse = /* @__PURE__ */ _parse.bind({ Error: ZodError });
-const safeParse = /* @__PURE__ */ _safeParse.bind({ Error: ZodError });
-const parseAsync = /* @__PURE__ */ _parseAsync.bind({ Error: ZodError });
+const parse = /* @__PURE__ */ _parse.bind({ Error: $ZodError });
+const safeParse = /* @__PURE__ */ _safeParse.bind({ Error: $ZodError });
+const parseAsync = /* @__PURE__ */ _parseAsync.bind({ Error: $ZodError });
 const safeParseAsync = /* @__PURE__ */ _safeParseAsync.bind({
-    Error: ZodError,
+    Error: $ZodError,
 });
 
-const ZodType = /*@__PURE__*/ $constructor("ZodType", (inst, def) => {
+const ZodMiniType = /*@__PURE__*/ $constructor("ZodMiniType", (inst, def) => {
+    if (!inst._zod)
+        throw new Error("Uninitialized schema in mixin ZodMiniType.");
     $ZodType.init(inst, def);
     inst.def = def;
-    inst._def = def;
-    // base methods
+    inst.parse = (data, params) => parse(inst, data, params);
+    inst.safeParse = (data, params) => safeParse(inst, data, params);
+    inst.parseAsync = async (data, params) => parseAsync(inst, data, params);
+    inst.safeParseAsync = async (data, params) => safeParseAsync(inst, data, params);
     inst.check = (...checks) => {
         return inst.clone({
             ...def,
             checks: [
                 ...(def.checks ?? []),
-                ...checks.map((ch) => (typeof ch === "function" ? { _zod: { check: ch, def: { check: "custom" } } } : ch)),
+                ...checks.map((ch) => typeof ch === "function" ? { _zod: { check: ch, def: { check: "custom" }, onattach: [] } } : ch),
             ],
         });
     };
-    inst.clone = (_def) => clone(inst, _def ?? def);
+    inst.clone = (_def) => clone(inst, _def);
     inst.brand = () => inst;
     inst.register = ((reg, meta) => {
         reg.add(inst, meta);
         return inst;
     });
-    // parsing
-    inst.parse = (data, params) => parse(inst, data, params);
-    inst.safeParse = (data, params) => safeParse(inst, data, params);
-    inst.parseAsync = async (data, params) => parseAsync(inst, data, params);
-    inst.safeParseAsync = async (data, params) => safeParseAsync(inst, data, params);
-    inst.spa = inst.safeParseAsync;
-    // refinements
-    inst.refine = (check, params) => inst.check(refine(check, params));
-    inst.superRefine = (refinement) => inst.check(superRefine(refinement));
-    inst.overwrite = (fn) => inst.check(_overwrite(fn));
-    // wrappers
-    inst.optional = (params) => optional(inst, params);
-    inst.nullable = (params) => nullable(inst, params);
-    inst.nullish = () => optional(nullable(inst));
-    inst.nonoptional = (params) => nonoptional(inst, params);
-    inst.array = () => array(inst);
-    inst.or = (arg) => union([inst, arg]);
-    // inst.and = (arg) => intersection(inst, arg);
-    inst.transform = (tx) => pipe(inst, transform(tx));
-    inst.default = (def, params) => _default(inst, def, params);
-    // inst.coalesce = (def, params) => coalesce(inst, def, params);
-    inst.catch = (params) => _catch(inst, params);
-    inst.pipe = (target) => pipe(inst, target);
-    inst.readonly = () => readonly(inst);
-    // meta
-    inst.describe = (description) => {
-        const cl = inst.clone();
-        const meta = globalRegistry.get(inst) ?? {};
-        meta.description = description;
-        globalRegistry.add(cl, meta);
-        return cl;
-    };
-    Object.defineProperty(inst, "description", {
-        get() {
-            return globalRegistry.get(inst)?.description;
-        },
-        configurable: true,
-    });
-    inst.meta = (...args) => {
-        if (args.length === 0)
-            return globalRegistry.get(inst);
-        const cl = inst.clone();
-        globalRegistry.add(cl, args[0]);
-        return cl;
-    };
-    // helpers
-    inst.isOptional = () => inst.safeParse(undefined).success;
-    inst.isNullable = () => inst.safeParse(null).success;
-    return inst;
 });
-const ZodBoolean = /*@__PURE__*/ $constructor("ZodBoolean", (inst, def) => {
+const ZodMiniBoolean = /*@__PURE__*/ $constructor("ZodMiniBoolean", (inst, def) => {
     $ZodBoolean.init(inst, def);
-    ZodType.init(inst, def);
+    ZodMiniType.init(inst, def);
 });
 function boolean(params) {
-    return _boolean(ZodBoolean, params);
-}
-const ZodArray = /*@__PURE__*/ $constructor("ZodArray", (inst, def) => {
-    $ZodArray.init(inst, def);
-    ZodType.init(inst, def);
-    inst.element = def.element;
-    inst.min = (minLength, params) => inst.check(_minLength(minLength, params));
-    inst.nonempty = (params) => inst.check(_minLength(1, params));
-    inst.max = (maxLength, params) => inst.check(_maxLength(maxLength, params));
-    inst.length = (len, params) => inst.check(_length(len, params));
-});
-function array(element, params) {
-    return _array(ZodArray, element, params);
-}
-const ZodUnion = /*@__PURE__*/ $constructor("ZodUnion", (inst, def) => {
-    $ZodUnion.init(inst, def);
-    ZodType.init(inst, def);
-    inst.options = def.options;
-});
-function union(options, params) {
-    return new ZodUnion({
-        type: "union",
-        options,
-        ...normalizeParams(params),
-    });
-}
-const ZodTransform = /*@__PURE__*/ $constructor("ZodTransform", (inst, def) => {
-    $ZodTransform.init(inst, def);
-    ZodType.init(inst, def);
-    inst._zod.parse = (payload, _ctx) => {
-        payload.addIssue = (issue$1) => {
-            if (typeof issue$1 === "string") {
-                payload.issues.push(issue(issue$1, payload.value, def));
-            }
-            else {
-                // for Zod 3 backwards compatibility
-                const _issue = issue$1;
-                if (_issue.fatal)
-                    _issue.continue = false;
-                _issue.code ?? (_issue.code = "custom");
-                _issue.input ?? (_issue.input = payload.value);
-                _issue.inst ?? (_issue.inst = inst);
-                _issue.continue ?? (_issue.continue = !def.abort);
-                payload.issues.push(issue(_issue));
-            }
-        };
-        const output = def.transform(payload.value, payload);
-        if (output instanceof Promise) {
-            return output.then((output) => {
-                payload.value = output;
-                return payload;
-            });
-        }
-        payload.value = output;
-        return payload;
-    };
-});
-function transform(fn, params) {
-    return new ZodTransform({
-        type: "transform",
-        transform: fn,
-        ...normalizeParams(params),
-    });
-}
-const ZodOptional = /*@__PURE__*/ $constructor("ZodOptional", (inst, def) => {
-    $ZodOptional.init(inst, def);
-    ZodType.init(inst, def);
-    inst.unwrap = () => inst._zod.def.innerType;
-});
-function optional(innerType, params) {
-    return new ZodOptional({
-        type: "optional",
-        innerType,
-        ...normalizeParams(params),
-    });
-}
-const ZodNullable = /*@__PURE__*/ $constructor("ZodNullable", (inst, def) => {
-    $ZodNullable.init(inst, def);
-    ZodType.init(inst, def);
-    inst.unwrap = () => inst._zod.def.innerType;
-});
-function nullable(innerType, params) {
-    return new ZodNullable({
-        type: "nullable",
-        innerType,
-        ...normalizeParams(params),
-    });
-}
-const ZodDefault = /*@__PURE__*/ $constructor("ZodDefault", (inst, def) => {
-    $ZodDefault.init(inst, def);
-    ZodType.init(inst, def);
-    inst.unwrap = () => inst._zod.def.innerType;
-    inst.removeDefault = inst.unwrap;
-});
-function _default(innerType, defaultValue, params) {
-    return new ZodDefault({
-        type: "default",
-        defaultValue: (typeof defaultValue === "function" ? defaultValue : () => defaultValue),
-        innerType,
-        ...normalizeParams(params),
-    });
-}
-const ZodNonOptional = /*@__PURE__*/ $constructor("ZodNonOptional", (inst, def) => {
-    $ZodNonOptional.init(inst, def);
-    ZodType.init(inst, def);
-    inst.unwrap = () => inst._zod.def.innerType;
-});
-function nonoptional(innerType, params) {
-    return new ZodNonOptional({
-        type: "nonoptional",
-        innerType,
-        ...normalizeParams(params),
-    });
-}
-const ZodCatch = /*@__PURE__*/ $constructor("ZodCatch", (inst, def) => {
-    $ZodCatch.init(inst, def);
-    ZodType.init(inst, def);
-    inst.unwrap = () => inst._zod.def.innerType;
-    inst.removeCatch = inst.unwrap;
-});
-function _catch(innerType, catchValue, params) {
-    return new ZodCatch({
-        type: "catch",
-        innerType,
-        catchValue: (typeof catchValue === "function" ? catchValue : () => catchValue),
-        ...normalizeParams(params),
-    });
-}
-const ZodPipe = /*@__PURE__*/ $constructor("ZodPipe", (inst, def) => {
-    $ZodPipe.init(inst, def);
-    ZodType.init(inst, def);
-    inst.in = def.in;
-    inst.out = def.out;
-});
-function pipe(in_, out, params) {
-    return new ZodPipe({
-        type: "pipe",
-        in: in_,
-        out,
-        ...normalizeParams(params),
-    });
-}
-const ZodReadonly = /*@__PURE__*/ $constructor("ZodReadonly", (inst, def) => {
-    $ZodReadonly.init(inst, def);
-    ZodType.init(inst, def);
-});
-function readonly(innerType, params) {
-    return new ZodReadonly({
-        type: "readonly",
-        innerType,
-        ...normalizeParams(params),
-    });
-}
-const ZodCustom = /*@__PURE__*/ $constructor("ZodCustom", (inst, def) => {
-    $ZodCustom.init(inst, def);
-    ZodType.init(inst, def);
-});
-// custom checks
-function check(fn, params) {
-    const ch = new $ZodCheck({
-        check: "custom",
-        ...normalizeParams(params),
-    });
-    ch._zod.check = fn;
-    return ch;
-}
-function refine(fn, _params = {}) {
-    return _custom(ZodCustom, fn, _params);
-}
-// superRefine
-function superRefine(fn, params) {
-    const ch = check((payload) => {
-        payload.addIssue = (issue$1) => {
-            if (typeof issue$1 === "string") {
-                payload.issues.push(issue(issue$1, payload.value, ch._zod.def));
-            }
-            else {
-                // for Zod 3 backwards compatibility
-                const _issue = issue$1;
-                if (_issue.fatal)
-                    _issue.continue = false;
-                _issue.code ?? (_issue.code = "custom");
-                _issue.input ?? (_issue.input = payload.value);
-                _issue.inst ?? (_issue.inst = ch);
-                _issue.continue ?? (_issue.continue = !ch._zod.def.abort);
-                payload.issues.push(issue(_issue));
-            }
-        };
-        return fn(payload.value, payload);
-    }, params);
-    return ch;
+    return _boolean(ZodMiniBoolean);
 }
 
 var schema = boolean();
diff --git a/packages/tsc/bench/strongly-connected.ts b/packages/tsc/bench/strongly-connected.ts
index ed996bb4..919813a4 100644
--- a/packages/tsc/bench/strongly-connected.ts
+++ b/packages/tsc/bench/strongly-connected.ts
@@ -8,7 +8,7 @@ console.log("║     Zod v4     ║");
 console.log("╚════════════════╝");
 await gen.generate({
   ...gen.ZOD,
-  schemaType: "z.interface",
+  schemaType: "z.object",
   numSchemas: 500,
   numKeys: 3,
   numRefs: 1,
diff --git a/packages/tsc/bisect.ts b/packages/tsc/bisect.ts
index 07e87728..00aaa0d3 100644
--- a/packages/tsc/bisect.ts
+++ b/packages/tsc/bisect.ts
@@ -40,15 +40,8 @@ let CURR = MIN;
 // shape interface: 43472
 
 while (!MAX || MAX - MIN > 2) {
-  // generate({
-  //   ...ZOD,
-  //   schemaType: "z.interface",
-  //   numSchemas: CURR,
-  //   numKeys: 3,
-  //   numRefs: 1,
-  // });
   gen.generateExtendChain({
-    ...gen.ZOD,
+    ...gen.ARKTYPE,
     numSchemas: CURR,
     numKeys: 6,
   });
diff --git a/packages/tsc/generate.ts b/packages/tsc/generate.ts
index 4a160e61..f9c7f8be 100644
--- a/packages/tsc/generate.ts
+++ b/packages/tsc/generate.ts
@@ -25,33 +25,15 @@ export const ARKTYPE = {
 };
 
 generateExtendChain({
-  ...ZOD,
-  numSchemas: 40,
+  ...ARKTYPE,
+  numSchemas: 25,
   numKeys: 6,
 });
-// generate({
-//   // ...ZOD3,
-//   ...ZOD,
-//   schemaType: "z.interface",
-//   // ...ARKTYPE,
-//   // ...ZOD3,
-//   numSchemas: 1000,
-//   numKeys: 10,
-//   numRefs: 3,
-
-//   // numSchemas: 1000,
-//   // methods: [""],
-//   // numKeys: 5,
-//   // numRefs: 0,
-//   // numOmits: 10,
-//   // numPicks: 10,
-//   // numExtends: 10,
-// });
 
 interface GenerateObjectsParams {
   // path?: string;
   imports: string[];
-  schemaType: "z.object" | "z.interface" | "arktype" | "valibot";
+  schemaType: "z.object" | "arktype" | "valibot";
   valueTypes: string[];
   methods?: string[];
   numSchemas: number;
@@ -109,9 +91,7 @@ export function generate(params: GenerateObjectsParams) {
       for (let i = 0; i < numRefs; i++) {
         const randomIndex = Math.floor(Math.random() * generated.length);
         const linked = generated[randomIndex];
-        if (schemaType === "z.interface") {
-          file.push(`  get ${randomStr(7)}(){\n    return ${linked} as typeof ${linked}\n  },`);
-        } else if (schemaType === "arktype") {
+        if (schemaType === "arktype") {
           throw new Error("References not supported in arktype.");
         } else {
           file.push(`  get ${randomStr(7)}(){ return ${linked} as typeof ${linked}},`);
@@ -172,7 +152,7 @@ export function generate(params: GenerateObjectsParams) {
       //   .fill(0)
       //   .map(() => randomStr(7));
 
-      if (schemaType === "z.interface" || schemaType === "z.object") {
+      if (schemaType === "z.object") {
         file.push(`export const ${varname} = ${variableName}.extend({`);
         for (const field of fields) {
           file.push(`  "${field.key}": ${field.schema},`);
@@ -201,7 +181,7 @@ export function generate(params: GenerateObjectsParams) {
 interface GenerateExtendChainParams {
   // path?: string;
   imports: string[];
-  schemaType: "z.object" | "z.interface" | "arktype" | "valibot";
+  schemaType: "z.object" | "arktype" | "valibot";
   valueTypes: string[];
   methods?: string[];
   numSchemas: number;
@@ -344,7 +324,7 @@ function generateFields(
 ): { key: string; schema: string }[] {
   //Math.floor(Math.random() * 30) + 1; // 1-30 keys
   const { methods = [""] } = params;
-  // let schema = `z.interface({`;
+
   // const keys = [];
   const fields: { key: string; schema: string }[] = [];
   for (let i = 0; i < params.numKeys; i++) {
diff --git a/packages/tsc/package.json b/packages/tsc/package.json
index d217d851..140de49b 100644
--- a/packages/tsc/package.json
+++ b/packages/tsc/package.json
@@ -8,13 +8,13 @@
   "devDependencies": {
     "@types/node": "^22.10.5",
     "@typescript/analyze-trace": "^0.10.1",
-    "arktype": "2.0.0-rc.33",
+    "arktype": "^2.0.0",
     "valibot": "^1.0.0",
     "zod": "workspace:*",
     "@zod/core": "workspace:*",
     "zod3-24-2": "npm:zod@3.24.2",
     "zod3-24-3": "npm:zod@3.24.3",
-    "zod4": "npm:zod@4.0.0-beta.20250415T232143",
+    "zod4": "npm:zod@4.0.0-beta.20250420T053007",
     "zod3": "npm:zod@^3.0.0",
     "@zod/mini": "workspace:*",
     "execa": "^9.5.2"
diff --git a/packages/zod/src/schemas.ts b/packages/zod/src/schemas.ts
index 1811bfc9..7ee43a3a 100644
--- a/packages/zod/src/schemas.ts
+++ b/packages/zod/src/schemas.ts
@@ -1,5 +1,6 @@
 import * as core from "@zod/core";
 import { util } from "@zod/core";
+
 import * as checks from "./checks.js";
 import * as iso from "./iso.js";
 import * as parse from "./parse.js";
@@ -23,12 +24,12 @@ export interface ZodType<out Output = unknown, out Input = unknown> extends core
   def: this["_zod"]["def"];
   /** @deprecated Use `.def` instead. */
   _def: this["_zod"]["def"];
-  /** @deprecated Use `z.output<typeof schema>` instead. */
-  _output: this["_zod"]["output"];
-  /** @deprecated Use `z.input<typeof schema>` instead. */
-  _input: this["_zod"]["input"];
+  // /** @deprecated Use `z.output<typeof schema>` instead. */
+  _output: core.output<this>;
+  // /** @deprecated Use `z.input<typeof schema>` instead. */
+  _input: core.input<this>;
   // base methods
-  check(...checks: (core.CheckFn<this["_zod"]["output"]> | core.$ZodCheck<this["_zod"]["output"]>)[]): this;
+  check(...checks: (core.CheckFn<core.output<this>> | core.$ZodCheck<core.output<this>>)[]): this;
   clone(def?: this["_zod"]["def"]): this;
   register<R extends core.$ZodRegistry>(
     registry: R,
@@ -38,9 +39,10 @@ export interface ZodType<out Output = unknown, out Input = unknown> extends core
         : [core.$ZodRegistry<R["_meta"], this>["_meta"]]
       : ["Incompatible schema"]
   ): this;
+
   brand<T extends PropertyKey = PropertyKey>(
     value?: T
-  ): this & Record<"_zod", Record<"output", this["_zod"]["output"] & core.$brand<T>>>;
+  ): PropertyKey extends T ? this : this & Record<"_zod", Record<"~output", core.output<this> & core.$brand<T>>>;
 
   // parsing
   parse(data: unknown, params?: core.ParseContext<core.$ZodIssue>): core.output<this>;
@@ -182,6 +184,56 @@ export interface _ZodString<Input = unknown> extends ZodType {
   minLength: number | null;
   maxLength: number | null;
 
+  // /** @deprecated Use `z.jsonString()` instead. */
+  // json(params?: string | core.$ZodCheckJSONStringParams): this;
+
+  // miscellaneous checks
+  regex(regex: RegExp, params?: string | core.$ZodCheckRegexParams): this;
+  includes(value: string, params?: { message?: string; position?: number }): this;
+  startsWith(value: string, params?: string | core.$ZodCheckStartsWithParams): this;
+  endsWith(value: string, params?: string | core.$ZodCheckEndsWithParams): this;
+  min(minLength: number, params?: string | core.$ZodCheckMinLengthParams): this;
+  max(maxLength: number, params?: string | core.$ZodCheckMaxLengthParams): this;
+  length(len: number, params?: string | core.$ZodCheckLengthEqualsParams): this;
+  nonempty(params?: string | core.$ZodCheckMinLengthParams): this;
+  lowercase(params?: string | core.$ZodCheckLowerCaseParams): this;
+  uppercase(params?: string | core.$ZodCheckUpperCaseParams): this;
+
+  // transforms
+  trim(): this;
+  normalize(form?: "NFC" | "NFD" | "NFKC" | "NFKD" | (string & {})): this;
+  toLowerCase(): this;
+  toUpperCase(): this;
+}
+
+export const _ZodString: core.$constructor<_ZodString> = /*@__PURE__*/ core.$constructor("_ZodString", (inst, def) => {
+  core.$ZodString.init(inst, def);
+  ZodType.init(inst, def);
+
+  inst.format = inst._zod.computed.format ?? null;
+  inst.minLength = inst._zod.computed.minimum ?? null;
+  inst.maxLength = inst._zod.computed.maximum ?? null;
+
+  // validations
+  inst.regex = (...args) => inst.check(checks.regex(...args));
+  inst.includes = (...args) => inst.check(checks.includes(...args));
+  inst.startsWith = (params) => inst.check(checks.startsWith(params));
+  inst.endsWith = (params) => inst.check(checks.endsWith(params));
+  inst.min = (...args) => inst.check(checks.minLength(...args));
+  inst.max = (...args) => inst.check(checks.maxLength(...args));
+  inst.length = (...args) => inst.check(checks.length(...args));
+  inst.nonempty = (...args) => inst.check(checks.minLength(1, ...args));
+  inst.lowercase = (params) => inst.check(checks.lowercase(params));
+  inst.uppercase = (params) => inst.check(checks.uppercase(params));
+
+  // transforms
+  inst.trim = () => inst.check(checks.trim());
+  inst.normalize = (...args) => inst.check(checks.normalize(...args));
+  inst.toLowerCase = () => inst.check(checks.toLowerCase());
+  inst.toUpperCase = () => inst.check(checks.toUpperCase());
+});
+
+export interface ZodString extends _ZodString<string> {
   // string format checks
   // email(): ZodString;
   // email(params?: string): ZodString;
@@ -254,37 +306,11 @@ export interface _ZodString<Input = unknown> extends ZodType {
   ): this;
   /** @deprecated Use `z.iso.duration()` instead. */
   duration(params?: string | core.$ZodCheckISODurationParams): this;
-
-  // /** @deprecated Use `z.jsonString()` instead. */
-  // json(params?: string | core.$ZodCheckJSONStringParams): this;
-
-  // miscellaneous checks
-  regex(regex: RegExp, params?: string | core.$ZodCheckRegexParams): this;
-  includes(value: string, params?: { message?: string; position?: number }): this;
-  startsWith(value: string, params?: string | core.$ZodCheckStartsWithParams): this;
-  endsWith(value: string, params?: string | core.$ZodCheckEndsWithParams): this;
-  min(minLength: number, params?: string | core.$ZodCheckMinLengthParams): this;
-  max(maxLength: number, params?: string | core.$ZodCheckMaxLengthParams): this;
-  length(len: number, params?: string | core.$ZodCheckLengthEqualsParams): this;
-  nonempty(params?: string | core.$ZodCheckMinLengthParams): this;
-  lowercase(params?: string | core.$ZodCheckLowerCaseParams): this;
-  uppercase(params?: string | core.$ZodCheckUpperCaseParams): this;
-
-  // transforms
-  trim(): this;
-  normalize(form?: "NFC" | "NFD" | "NFKC" | "NFKD" | (string & {})): this;
-  toLowerCase(): this;
-  toUpperCase(): this;
 }
 
-export interface ZodString extends _ZodString<string> {}
 export const ZodString: core.$constructor<ZodString> = /*@__PURE__*/ core.$constructor("ZodString", (inst, def) => {
   core.$ZodString.init(inst, def);
-  ZodType.init(inst, def);
-
-  inst.format = inst._zod.computed.format ?? null;
-  inst.minLength = inst._zod.computed.minimum ?? null;
-  inst.maxLength = inst._zod.computed.maximum ?? null;
+  _ZodString.init(inst, def);
 
   inst.email = (params) => inst.check(core._email(ZodEmail, params));
   inst.url = (params) => inst.check(core._url(ZodURL, params));
@@ -302,16 +328,8 @@ export const ZodString: core.$constructor<ZodString> = /*@__PURE__*/ core.$const
   inst.ulid = (params) => inst.check(core._ulid(ZodULID, params));
   inst.base64 = (params) => inst.check(core._base64(ZodBase64, params));
   inst.base64url = (params) => inst.check(core._base64url(ZodBase64URL, params));
-  // inst.jsonString = (params) => inst.check(core._jsonString(Zodinst,params));
-  // inst.json = (params) => inst.check(core._jsonString(Zodinst,params));
   inst.xid = (params) => inst.check(core._xid(ZodXID, params));
   inst.ksuid = (params) => inst.check(core._ksuid(ZodKSUID, params));
-  // inst.ip = (params) => {
-  //   const version = (params ?? {} as any)?.version;
-  //   if (version === "v4") return inst.check(core._ipv4(ZodIPv4, params));
-  //   if (version === "v6") return inst.check(core._ipv6(ZodIPv6, params as any));
-  //   return union([inst.ipv4(params), inst.ipv6(params as any)]);
-  // };
   inst.ipv4 = (params) => inst.check(core._ipv4(ZodIPv4, params));
   inst.ipv6 = (params) => inst.check(core._ipv6(ZodIPv6, params));
   inst.cidrv4 = (params) => inst.check(core._cidrv4(ZodCIDRv4, params));
@@ -323,24 +341,6 @@ export const ZodString: core.$constructor<ZodString> = /*@__PURE__*/ core.$const
   inst.date = (params) => inst.check(iso.date(params as any));
   inst.time = (params) => inst.check(iso.time(params as any));
   inst.duration = (params) => inst.check(iso.duration(params as any));
-
-  // validations
-  inst.regex = (...args) => inst.check(checks.regex(...args));
-  inst.includes = (...args) => inst.check(checks.includes(...args));
-  inst.startsWith = (params) => inst.check(checks.startsWith(params));
-  inst.endsWith = (params) => inst.check(checks.endsWith(params));
-  inst.min = (...args) => inst.check(checks.minLength(...args));
-  inst.max = (...args) => inst.check(checks.maxLength(...args));
-  inst.length = (...args) => inst.check(checks.length(...args));
-  inst.nonempty = (...args) => inst.check(checks.minLength(1, ...args));
-  inst.lowercase = (params) => inst.check(checks.lowercase(params));
-  inst.uppercase = (params) => inst.check(checks.uppercase(params));
-
-  // transforms
-  inst.trim = () => inst.check(checks.trim());
-  inst.normalize = (...args) => inst.check(checks.normalize(...args));
-  inst.toLowerCase = () => inst.check(checks.toLowerCase());
-  inst.toUpperCase = () => inst.check(checks.toUpperCase());
 });
 
 export function string(params?: string | core.$ZodStringParams): ZodString {
@@ -348,14 +348,14 @@ export function string(params?: string | core.$ZodStringParams): ZodString {
 }
 
 // ZodStringFormat
-export interface ZodStringFormat<Format extends core.$ZodStringFormats = core.$ZodStringFormats> extends ZodString {
+export interface ZodStringFormat<Format extends core.$ZodStringFormats = core.$ZodStringFormats> extends _ZodString {
   _zod: core.$ZodStringFormatInternals<Format>;
 }
 export const ZodStringFormat: core.$constructor<ZodStringFormat> = /*@__PURE__*/ core.$constructor(
   "ZodStringFormat",
   (inst, def) => {
     core.$ZodStringFormat.init(inst, def);
-    ZodString.init(inst, def);
+    _ZodString.init(inst, def);
   }
 );
 
@@ -667,7 +667,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;
@@ -733,7 +733,7 @@ export const ZodNumberFormat: core.$constructor<ZodNumberFormat> = /*@__PURE__*/
   "ZodNumberFormat",
   (inst, def) => {
     core.$ZodNumberFormat.init(inst, def);
-    ZodType.init(inst, def);
+    ZodNumber.init(inst, def);
   }
 );
 
@@ -1008,297 +1008,83 @@ export function array<T extends core.$ZodType>(element: core.$ZodType, params?:
   return core._array(ZodArray, element, params) as any;
 }
 
-// ZodObjectLike
-export interface ZodObjectLike<out O = object, out I = object> extends ZodType {
-  _zod: core.$ZodObjectLikeInternals<O, I>;
-}
-export const ZodObjectLike: core.$constructor<ZodObjectLike> = /*@__PURE__*/ core.$constructor(
-  "ZodObjectLike",
-  (inst, def) => {
-    core.$ZodObjectLike.init(inst, def);
-    ZodType.init(inst, def);
-  }
-);
-
 // .keyof
-export function keyof<T extends ZodObject>(schema: T): ZodLiteral<keyof T["_zod"]["def"]["shape"]>;
-export function keyof<T extends ZodInterface>(schema: T): ZodLiteral<keyof T["_zod"]["output"]>;
-export function keyof(schema: ZodObjectLike) {
-  const shape =
-    schema._zod.def.type === "interface"
-      ? util.cleanInterfaceShape(schema._zod.def.shape).shape
-      : schema._zod.def.shape;
-
+export function keyof<T extends ZodObject>(schema: T): ZodLiteral<keyof T["_zod"]["output"]> {
+  const shape = schema._zod.def.shape;
   return literal(Object.keys(shape)) as any;
 }
 
-// ZodInterface
-type ZodInterfacePartial<
-  T extends ZodInterface,
-  Keys extends keyof T["_zod"]["def"]["shape"] = keyof T["_zod"]["def"]["shape"],
-> = ZodInterface<
-  util.Extend<
-    T["_zod"]["def"]["shape"],
-    {
-      [k in Keys]: ZodOptional<T["_zod"]["def"]["shape"][k]>;
-    }
-  >,
-  {
-    optional: T["_zod"]["optional"] | (string & Keys);
-    defaulted: T["_zod"]["defaulted"];
-    extra: T["_zod"]["extra"];
-  }
->;
-
-type ZodInterfaceRequired<
-  T extends ZodInterface,
-  Keys extends keyof T["_zod"]["def"]["shape"] = keyof T["_zod"]["def"]["shape"],
-> = ZodInterface<
-  util.Extend<
-    T["_zod"]["def"]["shape"],
-    {
-      [k in Keys]: ZodNonOptional<T["_zod"]["def"]["shape"][k]>;
-    }
-  >,
-  {
-    optional: never;
-    defaulted: T["_zod"]["defaulted"];
-    extra: T["_zod"]["extra"];
-  }
->;
-
-export type MergeInterfaces<A extends ZodInterface, B extends ZodInterface> = ZodInterface<
-  util.Extend<A["_zod"]["def"]["shape"], B["_zod"]["def"]["shape"]>,
-  util.MergeInterfaceParams<A, B>
->;
-
-export interface ZodInterface<
-  // @ts-ignore cast variance
-  out Shape extends core.$ZodLooseShape = core.$ZodLooseShape,
-  // @ts-ignore cast variance
-  out Params extends core.$ZodInterfaceNamedParams = core.$ZodInterfaceNamedParams,
-> extends ZodType {
-  _zod: core.$ZodInterfaceInternals<Shape, Params>;
-
-  keyof(): ZodEnum<util.ToEnum<util.InterfaceKeys<string & keyof Shape>>>;
-  catchall<T extends core.$ZodType>(
-    schema: T
-  ): ZodInterface<
-    Shape,
-    {
-      optional: Params["optional"];
-      defaulted: Params["defaulted"];
-      extra: Record<string, T["_zod"]["output"]>;
-    }
-  >;
-  strict(): ZodInterface<
-    Shape,
-    {
-      optional: Params["optional"];
-      defaulted: Params["defaulted"];
-      extra: {};
-    }
-  >;
-  loose(): ZodInterface<
-    Shape,
-    {
-      optional: Params["optional"];
-      defaulted: Params["defaulted"];
-      extra: Record<string, unknown>;
-    }
-  >;
-  strip(): ZodInterface<
-    Shape,
-    {
-      optional: Params["optional"];
-      defaulted: Params["defaulted"];
-      extra: {};
-    }
-  >;
-
-  extend<U extends ZodInterface>(int: U): MergeInterfaces<this, U>;
-  extend<U extends core.$ZodLooseShape>(
-    shape: U
-  ): MergeInterfaces<this, ZodInterface<U, util.InitInterfaceParams<U, {}>>>;
-
-  /** @deprecated Use `A.extend(B)` */
-  merge<U extends ZodInterface>(incoming: U): MergeInterfaces<this, U>;
-
-  pick<const M extends util.Exactly<util.Mask<string & keyof Shape>, M>>(
-    mask: M
-  ): ZodInterface<
-    util.Flatten<Pick<Shape, keyof Shape & keyof M>>,
-    {
-      optional: Extract<Params["optional"], keyof M>;
-      defaulted: Extract<Params["defaulted"], keyof M>;
-      extra: Params["extra"];
-    }
-  >;
-
-  omit<const M extends util.Exactly<util.Mask<string & keyof Shape>, M>>(
-    mask: M
-  ): ZodInterface<
-    util.Flatten<Omit<Shape, keyof M>>,
-    {
-      optional: Exclude<Params["optional"], keyof M>;
-      defaulted: Exclude<Params["defaulted"], keyof M>;
-      extra: Params["extra"];
-    }
-  >;
-
-  partial(): ZodInterfacePartial<this>;
-  partial<M extends util.Mask<string & keyof Shape>>(mask: M): ZodInterfacePartial<this, string & keyof M>;
-
-  required(): ZodInterfaceRequired<this, string & keyof Shape>;
-  required<M extends util.Mask<string & keyof Shape>>(mask: M): ZodInterfaceRequired<this, string & keyof M>;
-}
-export const ZodInterface: core.$constructor<ZodInterface> = /*@__PURE__*/ core.$constructor(
-  "ZodInterface",
-  (inst, def) => {
-    core.$ZodInterface.init(inst, def);
-    ZodType.init(inst, def);
-    // util.defineLazy(inst._zod, "shape", () => def.shape);
-
-    inst.keyof = () => _enum(Object.keys(inst._zod.def.shape));
-    inst.catchall = (catchall) => inst.clone({ ...inst._zod.def, catchall });
-    inst.loose = () => inst.clone({ ...inst._zod.def, catchall: unknown() });
-    inst.strict = () => inst.clone({ ...inst._zod.def, catchall: never() });
-    inst.strip = () => inst.clone({ ...inst._zod.def, catchall: undefined });
-    inst.extend = (incoming: any) => {
-      if (incoming instanceof core.$ZodInterface) return util.extendObjectLike(inst, incoming);
-      return util.extendObjectLike(inst, _interface(incoming));
-    };
-    inst.merge = (other) => util.mergeObjectLike(inst, other);
-    inst.pick = (mask) => util.pick(inst, mask) as any;
-    inst.omit = (mask) => util.omit(inst, mask);
-    inst.partial = (...args: any[]) => util.partialObjectLike(ZodOptional, inst, args[0]);
-    inst.required = (...args: any[]) => util.requiredObjectLike(ZodNonOptional, inst, args[0]);
-  }
-);
-
-function _interface<T extends core.$ZodLooseShape>(
-  shape: T,
-  params?: string | core.$ZodInterfaceParams,
-  Class: util.Constructor<ZodInterface> = ZodInterface
-): ZodInterface<util.CleanInterfaceShape<T>, util.InitInterfaceParams<T, {}>> {
-  const cleaned = util.cached(() => util.cleanInterfaceShape(shape));
-  const def: core.$ZodInterfaceDef = {
-    type: "interface",
-    get shape() {
-      // return cleaned.value.shape;
-      const _shape = cleaned.value.shape;
-      util.assignProp(this, "shape", _shape);
-      return _shape;
-    },
-    get optional() {
-      return cleaned.value.optional;
-    },
-    ...util.normalizeParams(params),
-  };
-  return new Class(def) as any;
-}
-export { _interface as interface };
-
-// strictInterface
-
-export function strictInterface<T extends core.$ZodLooseShape>(
-  shape: T,
-  params?: string | core.$ZodInterfaceParams
-): ZodInterface<util.CleanInterfaceShape<T>, util.InitInterfaceParams<T, {}>> {
-  const cleaned = util.cached(() => util.cleanInterfaceShape(shape));
-  const def: core.$ZodInterfaceDef = {
-    type: "interface",
-    get shape() {
-      // return cleaned.value.shape;
-      const _shape = cleaned.value.shape;
-      util.assignProp(this, "shape", _shape);
-      return _shape;
-    },
-    get optional() {
-      return cleaned.value.optional;
-    },
-    catchall: never(),
-    ...util.normalizeParams(params),
-  };
-  return new ZodInterface(def) as any;
-}
-
-// looseInterface
-
-export function looseInterface<T extends core.$ZodLooseShape>(
-  shape: T,
-  params?: string | core.$ZodInterfaceParams
-): ZodInterface<util.CleanInterfaceShape<T>, util.InitInterfaceParams<T, Record<string, unknown>>> {
-  const cleaned = util.cached(() => util.cleanInterfaceShape(shape));
-  const def: core.$ZodInterfaceDef = {
-    type: "interface",
-    get optional() {
-      return cleaned.value.optional;
-    },
-    get shape() {
-      // return cleaned.value.shape;
-      const _shape = cleaned.value.shape;
-      util.assignProp(this, "shape", _shape);
-      return _shape;
-    },
-    catchall: unknown(),
-    ...util.normalizeParams(params),
-  };
-  return new ZodInterface(def) as any;
-}
-
 // ZodObject
 export interface ZodObject<
   // @ts-ignore cast variance
-  out Shape extends core.$ZodShape = core.$ZodShape,
-  // @ts-ignore cast variance
-  Extra extends Record<string, unknown> = Record<string, unknown>,
+  out Shape extends core.$ZodShape = core.$ZodLooseShape,
+  OutExtra extends Record<string, unknown> = Record<string, unknown>,
+  InExtra extends Record<string, unknown> = Record<string, unknown>,
 > extends ZodType {
-  _zod: core.$ZodObjectInternals<Shape, Extra>;
-
+  _zod: core.$ZodObjectInternals<Shape, OutExtra, InExtra>;
   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>;
-  extend<U extends core.$ZodShape>(
+  extend<U extends core.$ZodLooseShape>(
     shape: U
   ): ZodObject<
     util.Extend<Shape, U>,
-    Extra // & B['_zod']["extra"]
+    OutExtra,
+    InExtra // & B['_zod']["extra"]
   >;
 
-  // merge
-  /** @deprecated Use `A.extend(B)` */
-  merge<U extends ZodObject<any, any>>(
+  /**
+   * @deprecated Use destructuring to merge the shapes:
+   *
+   * ```ts
+   * z.object({
+   *    ...A.shape,
+   *    ...B.shape
+   * });
+   * ```
+   */
+  merge<U extends ZodObject>(
     other: U
-  ): ZodObject<util.Flatten<util.Extend<Shape, U["_zod"]["def"]["shape"]>>, Extra>;
+  ): ZodObject<util.Extend<Shape, U["shape"]>, U["_zod"]["outextra"], U["_zod"]["inextra"]>;
+  /**
+   * @deprecated Use destructuring to merge the shapes:
+   *
+   * ```ts
+   * z.object({
+   *    ...A.shape,
+   *    ...B.shape
+   * });
+   * ```
+   */
 
   pick<M extends util.Exactly<util.Mask<string & keyof Shape>, M>>(
     mask: M
-  ): ZodObject<util.Flatten<Pick<Shape, Extract<keyof Shape, keyof M>>>, Extra>;
+  ): ZodObject<util.Flatten<Pick<Shape, Extract<keyof Shape, keyof M>>>, OutExtra, InExtra>;
 
   omit<M extends util.Exactly<util.Mask<string & keyof Shape>, M>>(
     mask: M
-  ): ZodObject<util.Flatten<Omit<Shape, Extract<keyof Shape, keyof M>>>, Extra>;
+  ): ZodObject<util.Flatten<Omit<Shape, Extract<keyof Shape, keyof M>>>, OutExtra, InExtra>;
 
   partial(): ZodObject<
     {
       [k in keyof Shape]: ZodOptional<Shape[k]>;
     },
-    Extra
+    OutExtra,
+    InExtra
   >;
   partial<M extends util.Exactly<util.Mask<string & keyof Shape>, M>>(
     mask: M
@@ -1306,7 +1092,8 @@ export interface ZodObject<
     {
       [k in keyof Shape]: k extends keyof M ? ZodOptional<Shape[k]> : Shape[k];
     },
-    Extra
+    OutExtra,
+    InExtra
   >;
 
   // required
@@ -1314,7 +1101,8 @@ export interface ZodObject<
     {
       [k in keyof Shape]: ZodNonOptional<Shape[k]>;
     },
-    Extra
+    OutExtra,
+    InExtra
   >;
   required<M extends util.Exactly<util.Mask<string & keyof Shape>, M>>(
     mask: M
@@ -1322,14 +1110,18 @@ export interface ZodObject<
     {
       [k in keyof Shape]: k extends keyof M ? ZodNonOptional<Shape[k]> : Shape[k];
     },
-    Extra
+    OutExtra,
+    InExtra
   >;
 }
+
 export const ZodObject: core.$constructor<ZodObject> = /*@__PURE__*/ core.$constructor("ZodObject", (inst, def) => {
   core.$ZodObject.init(inst, def);
   ZodType.init(inst, def);
 
-  inst.shape = def.shape;
+  util.defineLazy(inst, "shape", () => {
+    return Object.fromEntries(Object.entries(inst._zod.def.shape));
+  });
   inst.keyof = () => _enum(Object.keys(inst._zod.def.shape)) as any;
   inst.catchall = (catchall) => inst.clone({ ...inst._zod.def, catchall });
   inst.passthrough = () => inst.clone({ ...inst._zod.def, catchall: unknown() });
@@ -1339,25 +1131,27 @@ export const ZodObject: core.$constructor<ZodObject> = /*@__PURE__*/ core.$const
   inst.strip = () => inst.clone({ ...inst._zod.def, catchall: undefined });
 
   inst.extend = (incoming: any) => {
-    if (incoming instanceof ZodObject) return util.extendObjectLike(inst, incoming);
-    return util.extendObjectLike(inst, object(incoming));
+    return util.extend(inst, incoming);
   };
-  inst.merge = (other) => util.mergeObjectLike(inst, other);
+  inst.merge = (other) => util.merge(inst, other);
   inst.pick = (mask) => util.pick(inst, mask);
   inst.omit = (mask) => util.omit(inst, mask);
-  inst.partial = (...args: any[]) => util.partialObjectLike(ZodOptional, inst, args[0] as object);
-  inst.required = (...args: any[]) => util.requiredObjectLike(ZodNonOptional, inst, args[0] as object);
+  inst.partial = (...args: any[]) => util.partial(ZodOptional, inst, args[0] as object);
+  inst.required = (...args: any[]) => util.required(ZodNonOptional, inst, args[0] as object);
 });
-export function object<T extends core.$ZodShape = Record<never, core.$ZodType>>(
+
+export function object<T extends core.$ZodLooseShape = Record<never, core.$ZodType>>(
   shape?: T,
-  params?: string | core.$ZodObjectLikeParams
-): ZodObject<T, {}> {
+  params?: string | core.$ZodObjectParams
+): ZodObject<util.Writeable<T> & {}, {}, {}> {
   const def: core.$ZodObjectDef = {
     type: "object",
-    shape: shape ?? {},
-    get optional() {
-      return util.optionalObjectKeys(shape ?? {});
+
+    get shape() {
+      util.assignProp(this, "shape", { ...shape });
+      return this.shape;
     },
+
     ...util.normalizeParams(params),
   };
   return new ZodObject(def) as any;
@@ -1365,230 +1159,43 @@ export function object<T extends core.$ZodShape = Record<never, core.$ZodType>>(
 
 // strictObject
 
-export function strictObject<T extends core.$ZodShape>(
+export function strictObject<T extends core.$ZodLooseShape>(
   shape: T,
   params?: string | core.$ZodObjectParams
-): ZodObject<T, {}> {
+): ZodObject<T, {}, {}> {
   return new ZodObject({
     type: "object",
-    shape: shape as core.$ZodShape,
-    get optional() {
-      return util.optionalObjectKeys(shape);
+
+    get shape() {
+      util.assignProp(this, "shape", { ...shape });
+      return this.shape;
     },
+
     catchall: never(),
     ...util.normalizeParams(params),
   }) as any;
 }
 
 // looseObject
-
-export function looseObject<T extends core.$ZodShape>(
+export function looseObject<T extends core.$ZodLooseShape>(
   shape: T,
   params?: string | core.$ZodObjectParams
-): ZodObject<T, { [k: string]: unknown }> {
+): ZodObject<T, { [k: string]: unknown }, { [k: string]: unknown }> {
   return new ZodObject({
     type: "object",
-    shape: shape as core.$ZodShape,
-    get optional() {
-      return util.optionalObjectKeys(shape);
+
+    get shape() {
+      util.assignProp(this, "shape", { ...shape });
+      return this.shape;
     },
+
     catchall: unknown(),
     ...util.normalizeParams(params),
   }) as any;
 }
 
-// object methods
-export function extend<T extends ZodInterface, U extends ZodInterface>(
-  a: T,
-  b: U
-): ZodInterface<util.Extend<T["_zod"]["def"]["shape"], U["_zod"]["def"]["shape"]>, util.MergeInterfaceParams<T, U>>;
-export function extend<T extends ZodObject, U extends ZodObject>(
-  a: T,
-  b: U
-): ZodObject<
-  util.Extend<T["_zod"]["def"]["shape"], U["_zod"]["def"]["shape"]>,
-  U["_zod"]["extra"] & T["_zod"]["extra"]
->;
-export function extend<T extends ZodObjectLike, U extends core.$ZodLooseShape>(
-  schema: T,
-  shape: U
-): T extends ZodInterface<infer TShape, infer TParams>
-  ? ZodInterface<util.ExtendInterfaceShape<TShape, U>, util.ExtendInterfaceParams<ZodInterface<TShape, TParams>, U>>
-  : ZodObject<util.Extend<T["_zod"]["def"]["shape"], U>, T["_zod"]["extra"]>;
-export function extend(schema: ZodObjectLike, shape: core.$ZodShape): ZodObjectLike {
-  if (shape instanceof core.$ZodType) return util.mergeObjectLike(schema, shape as any);
-  if (schema instanceof ZodInterface) {
-    return util.mergeObjectLike(schema, _interface(shape));
-  }
-  if (schema instanceof ZodObject) return util.mergeObjectLike(schema, object(shape));
-  return util.extend(schema, shape);
-}
-
-export function merge<T extends ZodObjectLike, U extends core.$ZodLooseShape>(
-  schema: T,
-  shape: U
-): T["_zod"]["def"]["type"] extends "interface"
-  ? // T extends ZodInterface
-    ZodInterface<
-      util.Extend<T["_zod"]["def"]["shape"], U["_zod"]["def"]["shape"]>,
-      {
-        extra: T["_zod"]["extra"] & U["_zod"]["extra"];
-        optional: Exclude<T["_zod"]["optional"], keyof U["_zod"]["def"]["shape"]> | U["_zod"]["optional"];
-        defaulted: Exclude<T["_zod"]["defaulted"], keyof U["_zod"]["def"]["shape"]> | U["_zod"]["defaulted"];
-      }
-    >
-  : ZodObject<util.Extend<T["_zod"]["def"]["shape"], U>, T["_zod"]["extra"]>;
-export function merge(a: ZodObjectLike, b: ZodObjectLike): ZodObjectLike {
-  return util.mergeObjectLike(a, b);
-}
-
-// .pick
-export function pick<T extends ZodObjectLike, M extends util.Exactly<util.Mask<keyof T["_zod"]["def"]["shape"]>, M>>(
-  schema: T,
-  mask: M
-): T["_zod"]["def"]["type"] extends "interface"
-  ? ZodInterface<
-      util.Flatten<Pick<T["_zod"]["def"]["shape"], keyof T["_zod"]["def"]["shape"] & keyof M>>,
-      {
-        optional: Extract<T["_zod"]["optional"], keyof M>;
-        defaulted: Extract<T["_zod"]["defaulted"], keyof M>;
-        extra: T["_zod"]["extra"];
-      }
-    >
-  : ZodObject<
-      util.Flatten<Pick<T["_zod"]["def"]["shape"], keyof T["_zod"]["def"]["shape"] & keyof M>>,
-      T["_zod"]["extra"]
-    >;
-export function pick(schema: ZodObjectLike, mask: object) {
-  // const picked = util.pick(schema, mask);
-  return util.pick(schema, mask);
-}
-
-// .omit
-export function omit<
-  T extends ZodObjectLike,
-  const M extends util.Exactly<util.Mask<keyof T["_zod"]["def"]["shape"]>, M>,
->(
-  schema: T,
-  mask: M
-): T["_zod"]["def"]["type"] extends "interface"
-  ? ZodInterface<
-      util.Flatten<Omit<T["_zod"]["def"]["shape"], keyof M>>,
-      {
-        optional: Exclude<T["_zod"]["optional"], keyof M>;
-        defaulted: Exclude<T["_zod"]["defaulted"], keyof M>;
-        extra: T["_zod"]["extra"];
-      }
-    >
-  : ZodObject<util.Flatten<Omit<T["_zod"]["def"]["shape"], keyof M>>, T["_zod"]["extra"]>;
-
-export function omit(schema: ZodObjectLike, mask: object) {
-  return util.omit(schema, mask);
-}
-
-export function partial<T extends ZodObjectLike>(
-  schema: T
-): T["_zod"]["def"]["type"] extends "interface"
-  ? ZodInterface<
-      // T['_zod']["shape"],
-      {
-        [k in keyof T["_zod"]["def"]["shape"]]: ZodOptional<T["_zod"]["def"]["shape"][k]>;
-      },
-      {
-        optional: string & keyof T["_zod"]["def"]["shape"];
-        defaulted: never;
-        extra: T["_zod"]["extra"];
-      }
-    >
-  : ZodObject<
-      {
-        [k in keyof T["_zod"]["def"]["shape"]]: ZodOptional<T["_zod"]["def"]["shape"][k]>;
-      },
-      T["_zod"]["extra"]
-    >;
-export function partial<T extends ZodObjectLike, M extends util.Exactly<util.Mask<keyof T["_zod"]["def"]["shape"]>, M>>(
-  schema: T,
-  mask: M
-): T["_zod"]["def"]["type"] extends "interface"
-  ? ZodInterface<
-      util.Extend<
-        T["_zod"]["def"]["shape"],
-        {
-          [k in keyof M & keyof T["_zod"]["def"]["shape"]]: ZodOptional<T["_zod"]["def"]["shape"][k]>;
-        }
-      >,
-      {
-        optional: string & (T["_zod"]["optional"] | keyof M);
-        defaulted: T["_zod"]["defaulted"];
-        extra: T["_zod"]["extra"];
-      }
-    >
-  : ZodObject<
-      {
-        [k in keyof T["_zod"]["def"]["shape"]]: k extends keyof M
-          ? ZodOptional<T["_zod"]["def"]["shape"][k]>
-          : T["_zod"]["def"]["shape"][k];
-      },
-      T["_zod"]["extra"]
-    >;
-
-export function partial(schema: ZodObjectLike, mask?: object): ZodObjectLike {
-  return util.partialObjectLike(ZodOptional, schema, mask);
-}
-
-// .required
-export function required<T extends { _subtype: "object" } & ZodObject>(
-  schema: T
-): ZodObject<{
-  [k in keyof T["_zod"]["def"]["shape"]]: ZodNonOptional<T["_zod"]["def"]["shape"][k]>;
-}>;
-export function required<
-  T extends { _subtype: "object" } & ZodObject,
-  M extends util.Exactly<util.Mask<keyof T["_zod"]["def"]["shape"]>, M>,
->(
-  schema: T,
-  mask: M
-): ZodObject<
-  util.Extend<
-    T["_zod"]["def"]["shape"],
-    {
-      [k in keyof M & keyof T["_zod"]["def"]["shape"]]: ZodNonOptional<T["_zod"]["def"]["shape"][k]>;
-    }
-  >
->;
-export function required<T extends { _subtype: "interface" } & ZodInterface>(
-  schema: T
-): ZodInterface<
-  {
-    [k in keyof T["_zod"]["def"]["shape"]]: ZodNonOptional<T["_zod"]["def"]["shape"][k]>;
-  },
-  {
-    optional: never;
-    defaulted: T["_zod"]["defaulted"];
-    extra: T["_zod"]["extra"];
-  }
->;
-export function required<
-  T extends { _subtype: "interface" } & ZodInterface,
-  M extends util.Mask<keyof T["_zod"]["output"]>,
->(
-  schema: T,
-  mask: M
-): ZodInterface<
-  util.Extend<
-    T["_zod"]["def"]["shape"],
-    {
-      [k in keyof M & keyof T["_zod"]["def"]["shape"]]: ZodNonOptional<T["_zod"]["def"]["shape"][k]>;
-    }
-  >,
-  {
-    optional: Exclude<T["_zod"]["optional"], keyof M>;
-    defaulted: T["_zod"]["defaulted"];
-    extra: T["_zod"]["extra"];
-  }
->;
-export function required(schema: ZodObjectLike, mask?: object): ZodObjectLike {
-  return util.requiredObjectLike(ZodNonOptional, schema, mask);
+export function partial<T>(shape: T): Partial<T> {
+  return shape;
 }
 
 // ZodUnion
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c43b2205..99fc1aa5 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -237,8 +237,8 @@ importers:
         specifier: workspace:*
         version: link:../mini
       arktype:
-        specifier: 2.0.0-rc.33
-        version: 2.0.0-rc.33
+        specifier: ^2.0.0
+        version: 2.1.19
       execa:
         specifier: ^9.5.2
         version: 9.5.2
@@ -258,8 +258,8 @@ importers:
         specifier: npm:zod@3.24.3
         version: zod@3.24.3
       zod4:
-        specifier: npm:zod@4.0.0-beta.20250415T232143
-        version: zod@4.0.0-beta.20250415T232143
+        specifier: npm:zod@4.0.0-beta.20250420T053007
+        version: zod@4.0.0-beta.20250420T053007
 
   packages/zod:
     dependencies:
@@ -285,15 +285,9 @@ packages:
     resolution: {integrity: sha512-Izvir8iIoU+X4SKtDAa5kpb+9cpifclzsbA8x/AZY0k0gIfXYQ1fa1B6Epfe6vNA2YfDX8VtrZFgvnXB6aPEoQ==}
     engines: {node: '>=18'}
 
-  '@ark/schema@0.33.0':
-    resolution: {integrity: sha512-GPjzbiydOL5gd9UFZMUQr5JBqT9YTX2dPT+u18aNswlGOgQE01y9B6kiwK/JyoaSwEJSDyxAPABsVRL7gG9KSQ==}
-
   '@ark/schema@0.45.9':
     resolution: {integrity: sha512-rG0v/JI0sibn/0wERAHTYVLCtEqoMP2IIlxnb+S5DrEjCI5wpubbZSWMDW50tZ8tV6FANu6zzHDeeKbp6lsZdg==}
 
-  '@ark/util@0.33.0':
-    resolution: {integrity: sha512-zzYQiRHLPwK15T5CM6SgQXTycKNpAvA2qwdlMbK5vFbLzy3P87VNKA8NiezBIXm+jsov3lEtMKE6kLtbZQDUbg==}
-
   '@ark/util@0.45.9':
     resolution: {integrity: sha512-0WYNAb8aRGp7dNt6xIvIrRzL7V1XL3u3PK2vcklhtTrdaP235DjC9qJhzidrxtWr68mA5ySSjUrgrXk622bKkw==}
 
@@ -2447,8 +2441,8 @@ packages:
   '@zag-js/types@1.8.2':
     resolution: {integrity: sha512-J+94HhFAPOBchNdGcmvqjB8nbQFgKHcqGoPl5vNTKlcoibN0yFjn4XFZoQU6uCf8sPhNg6NUNTkluR5YjybyJA==}
 
-  '@zod/core@0.5.1':
-    resolution: {integrity: sha512-Iqa3r1weIYaG1pjR+vNhfmaQ+5YtdQEp839R7bil0CC30cwiExXuBI5AAEjZMMS2CzGcBlAWca+0+vxzUmdJ6Q==}
+  '@zod/core@0.8.1':
+    resolution: {integrity: sha512-djj8hPhxIHcG8ptxITaw/Bout5HJZ9NyRbKr95Eilqwt9R0kvITwUQGDU+n+MVdsBIka5KwztmZSLti22F+P0A==}
 
   '@zxing/text-encoding@0.9.0':
     resolution: {integrity: sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==}
@@ -2551,9 +2545,6 @@ packages:
     resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==}
     engines: {node: '>=10'}
 
-  arktype@2.0.0-rc.33:
-    resolution: {integrity: sha512-ndtDXtunbff0o1urOOXq/eHGuUqIlp5MZ99lWON3MS0LZzF7/WFf+SwOCSomoPj9BptMLMyLS9cIYVNndD5QVQ==}
-
   arktype@2.1.19:
     resolution: {integrity: sha512-notORSuTSpfLV7rq0kYC4mTgIVlVR0xQuvtFxOaE9aKiXyON/kgoIBwZZcKeSSb4BebNcfJoGlxJicAUl/HMdw==}
 
@@ -2897,6 +2888,10 @@ packages:
     resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
     engines: {node: '>=8'}
 
+  detect-libc@2.0.4:
+    resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
+    engines: {node: '>=8'}
+
   detect-node-es@1.1.0:
     resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
 
@@ -5265,8 +5260,8 @@ packages:
   zod@3.24.3:
     resolution: {integrity: sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==}
 
-  zod@4.0.0-beta.20250415T232143:
-    resolution: {integrity: sha512-qy5jcyX/4Vt003S9II2NxTeAU31CQ71wJxk54stbrU+dhF+RcZL6xMwj8vGBbRVJi26pjCbTe2BldpK75nzlDw==}
+  zod@4.0.0-beta.20250420T053007:
+    resolution: {integrity: sha512-5pp8Q0PNDaNcUptGiBE9akyioJh3RJpagIxrLtAVMR9IxwcSZiOsJD/1/98CyhItdTlI2H91MfhhLzRlU+fifA==}
 
   zwitch@2.0.4:
     resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
@@ -5298,16 +5293,10 @@ snapshots:
       typescript: 5.6.1-rc
       validate-npm-package-name: 5.0.1
 
-  '@ark/schema@0.33.0':
-    dependencies:
-      '@ark/util': 0.33.0
-
   '@ark/schema@0.45.9':
     dependencies:
       '@ark/util': 0.45.9
 
-  '@ark/util@0.33.0': {}
-
   '@ark/util@0.45.9': {}
 
   '@babel/runtime@7.27.0':
@@ -7250,7 +7239,7 @@ snapshots:
     dependencies:
       csstype: 3.1.3
 
-  '@zod/core@0.5.1': {}
+  '@zod/core@0.8.1': {}
 
   '@zxing/text-encoding@0.9.0':
     optional: true
@@ -7337,11 +7326,6 @@ snapshots:
     dependencies:
       tslib: 2.8.1
 
-  arktype@2.0.0-rc.33:
-    dependencies:
-      '@ark/schema': 0.33.0
-      '@ark/util': 0.33.0
-
   arktype@2.1.19:
     dependencies:
       '@ark/schema': 0.45.9
@@ -7690,6 +7674,9 @@ snapshots:
 
   detect-libc@2.0.3: {}
 
+  detect-libc@2.0.4:
+    optional: true
+
   detect-node-es@1.1.0: {}
 
   devlop@1.1.0:
@@ -8612,7 +8599,7 @@ snapshots:
 
   lightningcss@1.29.3:
     dependencies:
-      detect-libc: 2.0.3
+      detect-libc: 2.0.4
     optionalDependencies:
       lightningcss-darwin-arm64: 1.29.3
       lightningcss-darwin-x64: 1.29.3
@@ -10691,8 +10678,8 @@ snapshots:
 
   zod@3.24.3: {}
 
-  zod@4.0.0-beta.20250415T232143:
+  zod@4.0.0-beta.20250420T053007:
     dependencies:
-      '@zod/core': 0.5.1
+      '@zod/core': 0.8.1
 
   zwitch@2.0.4: {}
diff --git a/v4.md b/v4.md
index 090551e5..2eb9e79e 100644
--- a/v4.md
+++ b/v4.md
@@ -45,14 +45,7 @@ libraries:
 - Add new bigint formats
   - `z.int64`
   - `z.uint64`
-- Add `z.interface()`
-  - Fixes `exactOptionalPropertyTypes`
-  - Supports recursive objects
-  - Lightweight types: easier on the compiler
-  - Less characters than `.optional()`
-  - No methods: `.passthrough()`, `.strict()`, `.nonstrict()`
-  - No `.merge()`: use `.extend()`
-  - Drops `.shape`
+
 - Simplifies error customization
   - Unifies `message` and `errorMap` into `error`
   - Access `issue.input` directly


Test patch:
diff --git a/packages/mini/tests/interface.test.ts b/packages/mini/tests/interface.test.ts
deleted file mode 100644
index fa00afc0..00000000
--- a/packages/mini/tests/interface.test.ts
+++ /dev/null
@@ -1,341 +0,0 @@
-import * as z from "@zod/mini";
-
-import { expect, expectTypeOf, test } from "vitest";
-
-test("z.interface", () => {
-  const a = z.interface({
-    name: z.string(),
-    age: z.number(),
-  });
-  expect(z.parse(a, { name: "john", age: 30 })).toEqual({
-    name: "john",
-    age: 30,
-  });
-  expect(() => z.parse(a, { name: "john", age: "30" })).toThrow();
-  expect(() => z.parse(a, "hello")).toThrow();
-});
-
-test("optionals", () => {
-  const a = z.interface({
-    a: z.string(),
-    "b?": z.string(),
-    "?c": z._default(z.string(), "c"),
-    d: z._default(z.string(), "d"),
-    e: z.optional(z.string()),
-    "?f": z.optional(z.string()),
-  });
-
-  interface a_in {
-    a: string;
-    b?: string;
-    c?: string;
-    d: string | undefined;
-    e: string | undefined;
-    f?: string | undefined;
-  }
-  interface a_out {
-    a: string;
-    b?: string;
-    c: string;
-    d: string;
-    e: string | undefined;
-    f: string | undefined;
-  }
-
-  expectTypeOf<typeof a._zod.output>().toEqualTypeOf<a_out>();
-  expectTypeOf<typeof a._zod.input>().toEqualTypeOf<a_in>();
-
-  // check parsing behavior
-  // b is optional in input and output
-  // c is optional in input but will always show up in output
-  // d is required in input & output but will be overwritten if `undefined`
-  // e is required in input & output but can be `undefined`
-  // f is optional in input but will always show up in output
-  expect(z.parse(a, { a: "a", b: "b", c: "c", d: "d", e: "e", f: "f" })).toEqual({
-    a: "a",
-    b: "b",
-    c: "c",
-    d: "d",
-    e: "e",
-    f: "f",
-  });
-
-  // omit b, c, and f to test optionality
-  expect(z.parse(a, { a: "a", d: "d", e: "e" })).toEqual({
-    a: "a",
-    c: "c", // default
-    d: "d",
-    e: "e",
-    f: undefined,
-  });
-
-  // test default values for d and f
-  expect(z.parse(a, { a: "a", d: undefined, e: "e", f: undefined })).toEqual({
-    a: "a",
-    c: "c",
-    d: "d",
-    e: "e",
-    f: undefined,
-  });
-});
-
-test("one to one", () => {
-  const A = z.interface({
-    name: z.string(),
-    get b() {
-      return z._default(z.optional(B), {} as any);
-    },
-  });
-
-  const B = z.interface({
-    name: z.string(),
-    get a() {
-      return A;
-    },
-  });
-
-  interface A {
-    name: string;
-    b: B | undefined;
-  }
-  interface B {
-    name: string;
-    a: A;
-  }
-  expectTypeOf<(typeof A._zod.output)["b"]["a"]["b"]["name"]>().toEqualTypeOf<string>();
-  expectTypeOf<(typeof A._zod.input)["b"]>().toEqualTypeOf<B | undefined>();
-});
-
-test("one to many", () => {
-  const C = z.interface({
-    name: z.string(),
-    get d() {
-      return z.array(D);
-    },
-  });
-
-  const D = z.interface({
-    age: z.number(),
-    get c() {
-      return C;
-    },
-  });
-
-  interface _C {
-    name: string;
-    d: _D[];
-  }
-  interface _D {
-    age: number;
-    c: _C;
-  }
-
-  // ._zod.outputC.d.c.d.c.d;
-  // expectTypeOf<(typeof C)["_def"]["shape"]>().toEqualTypeOf<z.ZodMiniShape>();
-  expectTypeOf<typeof C._zod.output>().toEqualTypeOf<_C>();
-  expectTypeOf<(typeof D._zod.output)["c"]["d"][number]>().toEqualTypeOf<_D>();
-});
-
-test("many to many", () => {
-  const E = z.interface({
-    name: z.string(),
-    get f() {
-      return z.array(F);
-    },
-  });
-
-  const F = z.interface({
-    age: z.number(),
-    get e() {
-      return z.array(E);
-    },
-  });
-
-  interface _E {
-    name: string;
-    f: _F[];
-  }
-  interface _F {
-    age: number;
-    e: _E[];
-  }
-
-  expectTypeOf<typeof E._zod.output>().toEqualTypeOf<_E>();
-  expectTypeOf<(typeof F._zod.output)["e"][number]>().toEqualTypeOf<_E>();
-});
-
-test("self recursive", () => {
-  const E = z.interface({
-    name: z.string(),
-    get e() {
-      return E;
-    },
-  });
-
-  interface _E {
-    name: string;
-    e: _E;
-  }
-  expectTypeOf<(typeof E._zod.output)["e"]["e"]["e"]>().toEqualTypeOf<_E>();
-  E;
-});
-
-test("self recursive optional", () => {
-  const F = z.interface({
-    name: z.string(),
-    get "f?"() {
-      return z.nullable(F);
-    },
-  });
-
-  interface _F {
-    name: string;
-    f?: _F | null;
-  }
-
-  expectTypeOf<typeof F._zod.output>().toEqualTypeOf<_F>();
-
-  expect(z.parse(F, { name: "a", f: null })).toEqual({ name: "a", f: null });
-});
-
-const userSchema = z.interface({
-  name: z.string(),
-  age: z.number(),
-  "email?": z.string(),
-});
-
-test("z.keyof", () => {
-  const userKeysSchema = z.keyof(userSchema);
-  type UserKeys = z.infer<typeof userKeysSchema>;
-  expectTypeOf<UserKeys>().toEqualTypeOf<"name" | "age" | "email">();
-  expect(userKeysSchema).toBeDefined();
-  expect(z.safeParse(userKeysSchema, "name").success).toBe(true);
-  expect(z.safeParse(userKeysSchema, "age").success).toBe(true);
-  expect(z.safeParse(userKeysSchema, "email").success).toBe(true);
-  expect(z.safeParse(userKeysSchema, "isAdmin").success).toBe(false);
-});
-
-// test("z.extend", () => {
-//   const extendedSchema = z.extend(userSchema, {
-//     isAdmin: z.boolean(),
-//   });
-//   type ExtendedUser = z.infer<typeof extendedSchema>;
-//   expectTypeOf<ExtendedUser>().toEqualTypeOf<{
-//     name: string;
-//     age: number;
-//     email?: string;
-//     isAdmin: boolean;
-//   }>();
-//   expect(extendedSchema).toBeDefined();
-//   expect(z.safeParse(extendedSchema, { name: "John", age: 30, isAdmin: true }).success).toBe(true);
-// });
-
-test("z.extend", () => {
-  const a = z.interface({ a: z.string() });
-
-  const b = z.extend(a, z.interface({ b: z.string() }));
-  expectTypeOf(b).toEqualTypeOf<
-    z.ZodMiniInterface<
-      { a: z.ZodMiniString<string>; b: z.ZodMiniString<string> },
-      {
-        optional: never;
-        defaulted: never;
-        extra: {};
-      }
-    >
-  >();
-  z.parse(b, { a: "a", b: "b" });
-  expect(() => z.parse(b, { a: "a" })).toThrow();
-});
-
-test("z.extend with optionals", () => {
-  const a = z.interface({ a: z.string(), "b?": z.string() });
-  const _ = z.interface({ "a?": z.string(), b: z.string() });
-  const b = z.extend(a, _);
-  expectTypeOf(b).toEqualTypeOf<
-    z.ZodMiniInterface<
-      { a: z.ZodMiniString<string>; b: z.ZodMiniString<string> },
-      {
-        optional: "a";
-        defaulted: never;
-        extra: {};
-      }
-    >
-  >();
-  z.parse(b, { a: "a", b: "b" });
-  expect(b._zod.def.optional).toEqual(["a"]);
-  z.parse(b, { b: "b" });
-  expect(() => z.parse(b, { a: "a" })).toThrow();
-});
-
-test("z.extend with optional properties", () => {
-  const a = z.interface({ "a?": z.string(), b: z.string() });
-  const b = z.extend(a, { "?a": z.string(), "b?": z.string() });
-  type b = z.infer<typeof b>;
-  expectTypeOf(b._zod.def.shape).toEqualTypeOf<{
-    a: z.ZodMiniString<string>;
-    b: z.ZodMiniString<string>;
-  }>();
-  expectTypeOf<typeof a._zod.defaulted>().toEqualTypeOf<never>();
-  expectTypeOf<typeof a._zod.optional>().toEqualTypeOf<"a">();
-  expectTypeOf<typeof b._zod.defaulted>().toEqualTypeOf<"a">();
-  expectTypeOf<typeof b._zod.optional>().toEqualTypeOf<"b">();
-  expectTypeOf<b>().toEqualTypeOf<{ a: string; b?: string }>();
-});
-
-test("z.pick", () => {
-  const pickedSchema = z.pick(userSchema, { name: true, email: true });
-  type PickedUser = z.infer<typeof pickedSchema>;
-  expectTypeOf<PickedUser>().toEqualTypeOf<{ name: string; email?: string }>();
-  expect(pickedSchema).toBeDefined();
-  expect(z.safeParse(pickedSchema, { name: "John", email: "john@example.com" }).success).toBe(true);
-});
-
-test("z.omit", () => {
-  const omittedSchema = z.omit(userSchema, { age: true });
-
-  type OmittedUser = z.infer<typeof omittedSchema>;
-  expectTypeOf<OmittedUser>().toEqualTypeOf<{ name: string; email?: string }>();
-  expect(omittedSchema).toBeDefined();
-  expect(z.safeParse(omittedSchema, { name: "John", email: "john@example.com" }).success).toBe(true);
-});
-
-test("z.partial", () => {
-  const partialSchema = z.partial(userSchema);
-  partialSchema._zod.def.type;
-
-  type PartialUser = z.infer<typeof partialSchema>;
-  expectTypeOf<PartialUser>().toEqualTypeOf<{
-    name?: string;
-    age?: number;
-    email?: string;
-  }>();
-  expect(z.safeParse(partialSchema, {}).success).toBe(true);
-  expect(z.safeParse(partialSchema, { name: "foo" }).success).toBe(true);
-  expect(z.safeParse(partialSchema, { age: 123 }).success).toBe(true);
-  expect(z.safeParse(partialSchema, { email: "foo" }).success).toBe(true);
-
-  const partialSchemaWithMask = z.partial(userSchema, { name: true });
-  type PartialUserWithMask = z.infer<typeof partialSchemaWithMask>;
-  expectTypeOf<PartialUserWithMask>().toEqualTypeOf<{
-    name?: string;
-    age: number;
-    email?: string;
-  }>();
-  expect(z.safeParse(partialSchemaWithMask, { age: 30 }).success).toBe(true);
-  expect(z.safeParse(partialSchemaWithMask, { name: "John" }).success).toBe(false);
-});
-
-test("z.required()", () => {
-  const reqSchema = z.required(userSchema);
-  expect(z.parse(reqSchema, { name: "John", age: 30, email: "foo" })).toEqual({
-    name: "John",
-    age: 30,
-    email: "foo",
-  });
-
-  expect(() => z.parse(reqSchema, { age: 30 })).toThrow();
-  expect(() => z.parse(reqSchema, { name: "John" })).toThrow();
-  expect(() => z.parse(reqSchema, { email: "John" })).toThrow();
-  expect(() => z.parse(reqSchema, {})).toThrow();
-});
diff --git a/packages/mini/tests/object.test.ts b/packages/mini/tests/object.test.ts
index d40735da..15a7bc1b 100644
--- a/packages/mini/tests/object.test.ts
+++ b/packages/mini/tests/object.test.ts
@@ -10,7 +10,7 @@ test("z.object", () => {
   });
 
   a._zod.def.shape["test?"];
-  a._zod.def.shape.points._zod.qout;
+  a._zod.def.shape.points._zod.optionality;
 
   type a = z.output<typeof a>;
 
@@ -124,7 +124,9 @@ test("z.partial", () => {
     email?: string;
   }>();
   expect(z.safeParse(partialSchema, { name: "John" }).success).toBe(true);
+});
 
+test("z.partial with mask", () => {
   const partialSchemaWithMask = z.partial(userSchema, { name: true });
   type PartialUserWithMask = z.infer<typeof partialSchemaWithMask>;
   expectTypeOf<PartialUserWithMask>().toEqualTypeOf<{
diff --git a/packages/zod/tests/brand.test.ts b/packages/zod/tests/brand.test.ts
index d861f50b..957a6a70 100644
--- a/packages/zod/tests/brand.test.ts
+++ b/packages/zod/tests/brand.test.ts
@@ -11,7 +11,7 @@ test("branded types", () => {
   // simple branding
   type MySchema = z.infer<typeof mySchema>;
 
-  expectTypeOf<MySchema>().toEqualTypeOf<{ name: string } & z.BRAND<"superschema">>();
+  expectTypeOf<MySchema>().toEqualTypeOf<{ name: string } & z.$brand<"superschema">>();
 
   const doStuff = (arg: MySchema) => arg;
   doStuff(mySchema.parse({ name: "hello there" }));
diff --git a/packages/zod/tests/default.test.ts b/packages/zod/tests/default.test.ts
index 1a950f9e..fd0d1f75 100644
--- a/packages/zod/tests/default.test.ts
+++ b/packages/zod/tests/default.test.ts
@@ -112,17 +112,3 @@ test("object optionality", () => {
     hi: "hi",
   });
 });
-
-test("interface optionality", () => {
-  const schema = z.interface({
-    "?hi": z.string().default("hi"),
-  });
-
-  expect(
-    schema.parse({
-      hi: "hi",
-    })
-  ).toEqual({
-    hi: "hi",
-  });
-});
diff --git a/packages/zod/tests/discriminated-unions.test.ts b/packages/zod/tests/discriminated-unions.test.ts
index 7c786bc1..da219f5e 100644
--- a/packages/zod/tests/discriminated-unions.test.ts
+++ b/packages/zod/tests/discriminated-unions.test.ts
@@ -37,17 +37,6 @@ test("valid parse - object", () => {
   ).toEqual({ type: "a", a: "abc" });
 });
 
-test("valid parse - interface", () => {
-  expect(
-    z
-      .discriminatedUnion([
-        z.interface({ type: z.literal("a"), a: z.string() }),
-        z.interface({ type: z.literal("b"), b: z.string() }),
-      ])
-      .parse({ type: "a", a: "abc" })
-  ).toEqual({ type: "a", a: "abc" });
-});
-
 test("valid - include discriminator key (deprecated)", () => {
   expect(
     z
@@ -68,16 +57,6 @@ test("valid - optional discriminator (object)", () => {
   expect(schema.parse({ a: "abc" })).toEqual({ a: "abc" });
 });
 
-test("valid - optional discriminator (interface)", () => {
-  const schema = z.discriminatedUnion([
-    z.interface({ type: z.literal("a").optional(), a: z.string() }),
-    z.interface({ type: z.literal("b"), b: z.string() }),
-  ]);
-  expect(schema.parse({ type: "a", a: "abc" })).toEqual({ type: "a", a: "abc" });
-  expect(schema.parse({ type: undefined, a: "abc" })).toEqual({ type: undefined, a: "abc" });
-  expect(schema.parse({ type: "b", b: "abc" })).toEqual({ type: "b", b: "abc" });
-});
-
 test("valid - discriminator value of various primitive types", () => {
   const schema = z.discriminatedUnion([
     z.object({ type: z.literal("1"), val: z.string() }),
diff --git a/packages/zod/tests/firstparty.test.ts b/packages/zod/tests/firstparty.test.ts
index 9251ae48..63ac26b2 100644
--- a/packages/zod/tests/firstparty.test.ts
+++ b/packages/zod/tests/firstparty.test.ts
@@ -34,8 +34,6 @@ test("first party switch", () => {
       break;
     case "object":
       break;
-    case "interface":
-      break;
     case "union":
       break;
     case "intersection":
diff --git a/packages/zod/tests/interface.test.ts b/packages/zod/tests/interface.test.ts
deleted file mode 100644
index 1f5a75de..00000000
--- a/packages/zod/tests/interface.test.ts
+++ /dev/null
@@ -1,419 +0,0 @@
-import { expect, expectTypeOf, test } from "vitest";
-
-import * as z from "zod";
-
-test("object type inference", () => {
-  const Test = z.interface({
-    f1: z.number(),
-    "f2?": z.string(),
-    f3: z.string().nullable(),
-    f4: z.array(z.interface({ t: z.union([z.string(), z.boolean()]) })),
-  });
-
-  type Test = z.output<typeof Test>;
-  type TestType = {
-    f1: number;
-    f2?: string | undefined;
-    f3: string | null;
-    f4: { t: string | boolean }[];
-  };
-
-  expectTypeOf<Test>().toEqualTypeOf<TestType>();
-
-  const data = {
-    f1: 12,
-    f2: "string",
-    f3: "string",
-    f4: [
-      {
-        t: "string",
-      },
-    ],
-  };
-  expect(Test.parse(data)).toEqual(data);
-  expect(Test.safeParse("foo")).toMatchObject({ success: false });
-});
-
-// test("shape() should return schema of particular key", () => {
-//   const schema = z.interface({
-//     name: z.string(),
-//   });
-
-//   expect(schema.shape.name).toBeInstanceOf(z.ZodString);
-// });
-
-test("optional with .optional()", () => {
-  const schema = z.interface({
-    a: z.string().optional(),
-  });
-
-  expect(schema.parse({})).toEqual({ a: undefined });
-  expect(schema.parse({ a: undefined })).toEqual({ a: undefined });
-});
-
-test("question mark optional", () => {
-  const schema = z.interface({
-    "a?": z.string().optional(),
-  });
-  expect(schema.parse({})).toEqual({});
-  expect("a" in schema.parse({})).toEqual(false);
-  expect(schema.parse({ a: undefined })).toEqual({ a: undefined });
-  expect("a" in schema.parse({ a: undefined })).toEqual(true);
-  expect(schema.parse({ a: "foo" })).toEqual({ a: "foo" });
-});
-
-test("default in optional key", () => {
-  const schema = z.interface({
-    "name?": z.string().default("tuna"),
-  });
-  expect(schema.parse({}).name).toEqual("tuna");
-  expect(schema.parse({ name: undefined }).name).toEqual("tuna");
-});
-
-test("defaulted key", () => {
-  const schema = z.interface({
-    "?a": z.string().default("asdf"),
-  });
-
-  expectTypeOf<typeof schema._zod.input>().toEqualTypeOf<{ a?: string }>();
-  expectTypeOf<typeof schema._zod.output>().toEqualTypeOf<{ a: string }>();
-  expect(schema.parse({})).toEqual({ a: "asdf" });
-  expect(schema.parse({ a: undefined })).toEqual({ a: "asdf" });
-});
-
-test("z.interface - strip by default", () => {
-  const schema = z.interface({ points: z.number() });
-  const data = { points: 2314, unknown: "asdf" };
-  const result = schema.safeParse(data);
-  expect(result.data).toEqual({ points: 2314 });
-});
-
-test("z.looseInterface", () => {
-  const schema = z.looseInterface({ points: z.number() });
-  const data = { points: 2314, unknown: "asdf" };
-  const val = schema.parse(data);
-  expect(val).toEqual(data);
-});
-
-test("strict", () => {
-  const schema = z.strictInterface({ points: z.number() });
-  const data = { points: 2314, unknown: "asdf" };
-  const val = schema.safeParse(data);
-  expect(val.success).toEqual(false);
-});
-
-test("catchall", () => {
-  const schema = z
-    .interface({
-      first: z.string(),
-    })
-    .catchall(z.number());
-
-  const d1 = schema.safeParse({ first: "asdf", num: 1243 });
-  expect(d1.data).toEqual({ first: "asdf", num: 1243 });
-
-  const d2 = schema.safeParse({ first: "asdf", num: "asdf" });
-  expect(d2.success).toEqual(false);
-});
-
-test("catchall overrides strict", () => {
-  const schema = z.strictInterface({ first: z.string().optional() }).catchall(z.number());
-
-  // setting a catchall overrides the unknownKeys behavior
-  schema.parse({ asdf: 1234 });
-});
-
-test("only run catchall on unknown keys", () => {
-  const schema = z.strictInterface({ first: z.string().optional() }).catchall(z.number());
-  schema.parse({
-    first: "asdf",
-    asdf: 1234,
-  });
-});
-
-test("extend overrides existing", async () => {
-  const a = z.interface({ a: z.string() });
-  const b = z.interface({ a: z.number() });
-  const c = a.extend(b);
-  type c = z.infer<typeof c>;
-  expectTypeOf<c>().toEqualTypeOf<{ a: number }>();
-});
-
-test("extend overrides optionality", async () => {
-  const a = z.interface({ "?a": z.string(), "b?": z.string() });
-  const b = z.interface({ a: z.string(), b: z.string() });
-  const c = a.extend(b);
-
-  type c = z.infer<typeof c>;
-  expectTypeOf<c>().toEqualTypeOf<{ a: string; b: string }>();
-
-  const aData = { a: "asdf" };
-  expect(a.parse(aData)).toEqual(aData);
-
-  expect(c.safeParse(aData).success).toEqual(false);
-
-  const cData = { a: "asdf", b: "asdf" };
-  expect(c.parse(cData)).toEqual(cData);
-});
-
-test("inferred merged object type with optional properties", async () => {
-  const a = z.interface({ "a?": z.string(), b: z.string().optional() });
-  const b = z.interface({ a: z.string().optional(), "b?": z.string() });
-  const c = a.merge(b);
-  // c.shape;
-  type c = z.infer<typeof c>;
-  expectTypeOf<c>().toEqualTypeOf<{ a: string | undefined; b?: string }>();
-  expectTypeOf<typeof a>().toMatchTypeOf<z.ZodInterface>();
-});
-
-// declare let xx: z.ZodInterface<{a: z.ZodString}>;
-// xx._output;
-test("inferred unioned object type with optional properties", async () => {
-  const Unioned = z.union([
-    z.interface({ a: z.string(), "b?": z.string().optional() }),
-    z.interface({ "a?": z.string().optional(), b: z.string() }),
-  ]);
-  type Unioned = z.infer<typeof Unioned>;
-  expectTypeOf<Unioned>().toEqualTypeOf<{ a: string; b?: string } | { a?: string; b: string }>();
-});
-
-test("inferred enum type", async () => {
-  const Enum = z.interface({ a: z.string(), b: z.string().optional() }).keyof();
-
-  expect(Enum.enum).toEqual({
-    a: "a",
-    b: "b",
-  });
-
-  expect(Enum._zod.def.entries).toEqual({
-    a: "a",
-    b: "b",
-  });
-  type Enum = z.infer<typeof Enum>;
-  expectTypeOf<Enum>().toEqualTypeOf<"a" | "b">();
-});
-
-test(".partial", async () => {
-  const Partial = z.interface({ a: z.string(), b: z.string().optional() }).partial();
-  type Partial = z.infer<typeof Partial>;
-  expectTypeOf<Partial>().toEqualTypeOf<{ a?: string; b?: string }>();
-  expect(Partial._zod.def.shape.a).toBeInstanceOf(z.ZodOptional);
-  expect(Partial._zod.def.shape.b).toBeInstanceOf(z.ZodOptional);
-  expect(Partial._zod.def.optional).toEqual(["a", "b"]);
-});
-
-test(".required", async () => {
-  const Required = z
-    .interface({ a: z.string(), b: z.string().optional(), "c?": z.string(), "?d": z.string() })
-    .required();
-  type Required = z.infer<typeof Required>;
-  expectTypeOf<Required>().toEqualTypeOf<{ a: string; b: string; c: string; d: string }>();
-  expectTypeOf<typeof Required._zod.optional>().toEqualTypeOf<never>();
-  expectTypeOf<typeof Required._zod.defaulted>().toEqualTypeOf<"d">();
-  expect(Required._zod.def.shape.a).toBeInstanceOf(z.ZodNonOptional);
-  expect(Required._zod.def.shape.b).toBeInstanceOf(z.ZodNonOptional);
-  expect(Required._zod.def.shape.c).toBeInstanceOf(z.ZodNonOptional);
-  expect(Required._zod.def.shape.d).toBeInstanceOf(z.ZodNonOptional);
-  expect(Required._zod.def.optional).toEqual([]);
-  // expect(Required._zod.def.defaulted).toEqual(["d"]);
-});
-
-test("inferred picked object type with optional properties", async () => {
-  const Picked = z.interface({ a: z.string(), "b?": z.string() }).pick({ b: true });
-  type Picked = z.infer<typeof Picked>;
-  expectTypeOf<Picked>().toEqualTypeOf<{ b?: string }>();
-});
-
-test("inferred type for unknown/any keys", () => {
-  const myType = z.interface({
-    anyOptional: z.any().optional(),
-    anyRequired: z.any(),
-    unknownOptional: z.unknown().optional(),
-    unknownRequired: z.unknown(),
-  });
-  type myType = z.infer<typeof myType>;
-  expectTypeOf<myType>().toEqualTypeOf<{
-    anyOptional: any;
-    anyRequired: any;
-    unknownOptional: unknown;
-    unknownRequired: unknown;
-  }>();
-
-  const myType2 = z.interface({
-    "anyOptional?": z.any().optional(),
-    "anyRequired?": z.any(),
-    "unknownOptional?": z.unknown().optional(),
-    "unknownRequired?": z.unknown(),
-  });
-  type myType2 = z.infer<typeof myType2>;
-  expectTypeOf<myType2>().toEqualTypeOf<{
-    anyOptional?: any;
-    anyRequired?: any;
-    unknownOptional?: unknown;
-    unknownRequired?: unknown;
-  }>();
-});
-
-// test("setKey", () => {
-//   const base = z.interface({ name: z.string() });
-//   const withNewKey = base.setKey("age", z.number());
-
-//   type withNewKey = z.infer<typeof withNewKey>;
-//   expectTypeOf<withNewKey>().toEqualTypeOf<{ name: string; age: number }>();
-//   withNewKey.parse({ name: "asdf", age: 1234 });
-// });
-
-test("strictObject", async () => {
-  const strictObj = z.strictObject({
-    name: z.string(),
-  });
-
-  const syncResult = strictObj.safeParse({ name: "asdf", unexpected: 13 });
-  expect(syncResult.success).toEqual(false);
-
-  const asyncResult = await strictObj.spa({ name: "asdf", unexpected: 13 });
-  expect(asyncResult.success).toEqual(false);
-});
-
-test("object with refine", async () => {
-  const schema = z
-    .interface({
-      a: z.string().default("foo"),
-      b: z.number(),
-    })
-    .refine(() => true);
-  expect(schema.parse({ b: 5 })).toEqual({ b: 5, a: "foo" });
-  const result = await schema.parseAsync({ b: 5 });
-  expect(result).toEqual({ b: 5, a: "foo" });
-});
-
-test("intersection of object with date", async () => {
-  const schema = z.interface({
-    a: z.date(),
-  });
-  expect(z.intersection(schema, schema).parse({ a: new Date(1637353595983) })).toEqual({
-    a: new Date(1637353595983),
-  });
-  const result = await schema.parseAsync({ a: new Date(1637353595983) });
-  expect(result).toEqual({ a: new Date(1637353595983) });
-});
-
-test("intersection of object with refine with date", async () => {
-  const schema = z
-    .interface({
-      a: z.date(),
-    })
-    .refine(() => true);
-  expect(z.intersection(schema, schema).parse({ a: new Date(1637353595983) })).toEqual({
-    a: new Date(1637353595983),
-  });
-  const result = await schema.parseAsync({ a: new Date(1637353595983) });
-  expect(result).toEqual({ a: new Date(1637353595983) });
-});
-
-test("strictInterface", () => {
-  const person = z.strictInterface({
-    name: z.string(),
-  });
-
-  expect(() =>
-    person.parse({
-      name: "bob dylan",
-      constructor: 61,
-    })
-  ).toThrow();
-});
-
-test("catchall", () => {
-  const a = z.interface({});
-  expect(a._zod.def.catchall).toBeUndefined();
-
-  const b = z.strictObject({});
-  expect(b._zod.def.catchall).toBeInstanceOf(z.ZodNever);
-
-  const c = z.looseObject({});
-  expect(c._zod.def.catchall).toBeInstanceOf(z.ZodUnknown);
-
-  const d = z.interface({}).catchall(z.number());
-  expect(d._zod.def.catchall).toBeInstanceOf(z.ZodNumber);
-});
-
-test("unknownkeys merging", () => {
-  // This one is "strict"
-  const a = z.looseObject({
-    a: z.string(),
-  });
-
-  const b = z.strictObject({ b: z.string() });
-
-  // incoming object overrides
-  const c = a.merge(b);
-  expect(c._zod.def.catchall).toBeInstanceOf(z.ZodNever);
-
-  // // This one is "strip"
-  // const schemaB = z
-  //   .interface({
-  //     b: z.string(),
-  //   })
-  //   .catchall(z.string());
-
-  // const mergedSchema = schemaA.merge(schemaB);
-  // type mergedSchema = typeof mergedSchema;
-  // // expectTypeOf<mergedSchema["_def"].catchall>().toEqualTypeOf<"strip">(true);
-  // expect(mergedSchema._zod.def.catchall).toBeInstanceOf(z.ZodUnknown);
-
-  // expectTypeOf<mergedSchema["_def"]["catchall"]>().toEqualTypeOf<z.ZodString>(true);
-  // expect(mergedSchema._zod.def.catchall instanceof z.ZodString).toEqual(true);
-});
-
-const personToExtend = z.interface({
-  firstName: z.string(),
-  lastName: z.string(),
-});
-
-test("extend() should return schema with new key", () => {
-  const PersonWithNickname = personToExtend.extend({ nickName: z.string() });
-  type PersonWithNickname = z.infer<typeof PersonWithNickname>;
-
-  const expected = { firstName: "f", nickName: "n", lastName: "l" };
-  const actual = PersonWithNickname.parse(expected);
-
-  expect(actual).toEqual(expected);
-  expectTypeOf<keyof PersonWithNickname>().toEqualTypeOf<"firstName" | "lastName" | "nickName">();
-  expectTypeOf<PersonWithNickname>().toEqualTypeOf<{ firstName: string; lastName: string; nickName: string }>();
-});
-
-test("extend() should have power to override existing key", () => {
-  const PersonWithNumberAsLastName = personToExtend.extend({
-    lastName: z.number(),
-  });
-  type PersonWithNumberAsLastName = z.infer<typeof PersonWithNumberAsLastName>;
-
-  const expected = { firstName: "f", lastName: 42 };
-  const actual = PersonWithNumberAsLastName.parse(expected);
-
-  expect(actual).toEqual(expected);
-  expectTypeOf<PersonWithNumberAsLastName>().toEqualTypeOf<{ firstName: string; lastName: number }>();
-});
-
-// test("passthrough index signature", () => {
-//   const a = z.interface({ a: z.string() });
-//   type a = z.infer<typeof a>;
-//   expectTypeOf<{ a: string }>().toEqualTypeOf<a>(true);
-//   const b = a.passthrough();
-//   type b = z.infer<typeof b>;
-//   expectTypeOf<{ a: string } & { [k: string]: unknown }>().toEqualTypeOf<b>(true);
-// });
-
-test("xor", () => {
-  type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
-  type XOR<T, U> = T extends object ? (U extends object ? (Without<T, U> & U) | (Without<U, T> & T) : U) : T;
-
-  type A = { name: string; a: number };
-  type B = { name: string; b: number };
-  type C = XOR<A, B>;
-  type Outer = { data: C };
-  const _Outer: z.ZodType<Outer> = z.interface({
-    data: z.union([z.interface({ name: z.string(), a: z.number() }), z.interface({ name: z.string(), b: z.number() })]),
-  });
-});
diff --git a/packages/zod/tests/json-schema.test.ts b/packages/zod/tests/json-schema.test.ts
index a4210b9c..17d1ef76 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",
       }
     `);
@@ -658,10 +658,9 @@ describe("toJSONSchema", () => {
   });
 
   test("simple interface", () => {
-    const userSchema = z.interface({
+    const userSchema = z.object({
       name: z.string(),
-      "age?": z.number(),
-      "?email": z.string(),
+      age: z.number().optional(),
     });
 
     const result = toJSONSchema(userSchema);
@@ -671,16 +670,12 @@ describe("toJSONSchema", () => {
           "age": {
             "type": "number",
           },
-          "email": {
-            "type": "string",
-          },
           "name": {
             "type": "string",
           },
         },
         "required": [
           "name",
-          "email",
         ],
         "type": "object",
       }
@@ -688,7 +683,7 @@ describe("toJSONSchema", () => {
   });
 
   test("catchall interface", () => {
-    const a = z.strictInterface({
+    const a = z.strictObject({
       name: z.string(),
       age: z.number(),
     });
@@ -715,7 +710,7 @@ describe("toJSONSchema", () => {
     `);
 
     const b = z
-      .interface({
+      .object({
         name: z.string(),
       })
       .catchall(z.string());
@@ -737,7 +732,7 @@ describe("toJSONSchema", () => {
       }
     `);
 
-    const c = z.looseInterface({
+    const c = z.looseObject({
       name: z.string(),
     });
 
@@ -758,7 +753,7 @@ describe("toJSONSchema", () => {
   });
 
   test("recursive interface schemas", () => {
-    const TreeNodeSchema = z.interface({
+    const TreeNodeSchema = z.object({
       id: z.string(),
       get children() {
         return TreeNodeSchema;
@@ -790,14 +785,14 @@ describe("toJSONSchema", () => {
   });
 
   test("mutually recursive interface schemas", () => {
-    const FolderSchema = z.interface({
+    const FolderSchema = z.object({
       name: z.string(),
       get files() {
         return z.array(FileSchema);
       },
     });
 
-    const FileSchema = z.interface({
+    const FileSchema = z.object({
       name: z.string(),
       get parent() {
         return FolderSchema;
@@ -1179,16 +1174,22 @@ test("overwrite descriptions", () => {
       reused: "ref",
     }
   );
-  expect(a).toMatchInlineSnapshot(`
+  expect(b).toMatchInlineSnapshot(`
     {
+      "$defs": {
+        "__schema0": {
+          "description": "c",
+          "type": "string",
+        },
+      },
       "properties": {
         "d": {
+          "$ref": "#/$defs/__schema0",
           "description": "d",
-          "type": "string",
         },
         "e": {
+          "$ref": "#/$defs/__schema0",
           "description": "e",
-          "type": "string",
         },
       },
       "required": [
@@ -1202,7 +1203,7 @@ test("overwrite descriptions", () => {
 
 test("top-level readonly", () => {
   const A = z
-    .interface({
+    .object({
       name: z.string(),
       get b() {
         return B;
@@ -1212,7 +1213,7 @@ test("top-level readonly", () => {
     .meta({ id: "A" });
 
   const B = z
-    .interface({
+    .object({
       name: z.string(),
       get a() {
         return A;
@@ -1264,14 +1265,14 @@ test("top-level readonly", () => {
 
 test("basic registry", () => {
   const myRegistry = z.registry<{ id: string }>();
-  const User = z.interface({
+  const User = z.object({
     name: z.string(),
     get posts() {
       return z.array(Post);
     },
   });
 
-  const Post = z.interface({
+  const Post = z.object({
     title: z.string(),
     content: z.string(),
     get author() {
@@ -1327,3 +1328,102 @@ test("basic registry", () => {
     }
   `);
 });
+
+test("_ref", () => {
+  // const a = z.promise(z.string().describe("a"));
+  const a = z.toJSONSchema(z.promise(z.string().describe("a")));
+  expect(a).toMatchInlineSnapshot(`
+    {
+      "description": "a",
+      "type": "string",
+    }
+  `);
+
+  const b = z.toJSONSchema(z.lazy(() => z.string().describe("a")));
+  expect(b).toMatchInlineSnapshot(`
+    {
+      "description": "a",
+      "type": "string",
+    }
+  `);
+
+  const c = z.toJSONSchema(z.optional(z.string().describe("a")));
+  expect(c).toMatchInlineSnapshot(`
+    {
+      "description": "a",
+      "type": "string",
+    }
+  `);
+});
+
+test("input type", () => {
+  const schema = z.object({
+    a: z.string(),
+    b: z.string().optional(),
+    c: z.string().default("hello"),
+    d: z.string().nullable(),
+  });
+  expect(toJSONSchema(schema, { io: "input" })).toMatchInlineSnapshot(`
+    {
+      "properties": {
+        "a": {
+          "type": "string",
+        },
+        "b": {
+          "type": "string",
+        },
+        "c": {
+          "default": "hello",
+          "type": "string",
+        },
+        "d": {
+          "anyOf": [
+            {
+              "type": "string",
+            },
+            {
+              "type": "null",
+            },
+          ],
+        },
+      },
+      "required": [
+        "a",
+        "d",
+      ],
+      "type": "object",
+    }
+  `);
+  expect(toJSONSchema(schema, { io: "output" })).toMatchInlineSnapshot(`
+    {
+      "properties": {
+        "a": {
+          "type": "string",
+        },
+        "b": {
+          "type": "string",
+        },
+        "c": {
+          "default": "hello",
+          "type": "string",
+        },
+        "d": {
+          "anyOf": [
+            {
+              "type": "string",
+            },
+            {
+              "type": "null",
+            },
+          ],
+        },
+      },
+      "required": [
+        "a",
+        "c",
+        "d",
+      ],
+      "type": "object",
+    }
+  `);
+});
diff --git a/packages/zod/tests/lazy.test.ts b/packages/zod/tests/lazy.test.ts
index 457a53a4..466d4622 100644
--- a/packages/zod/tests/lazy.test.ts
+++ b/packages/zod/tests/lazy.test.ts
@@ -2,7 +2,7 @@ import { expect, expectTypeOf, test } from "vitest";
 
 import * as z from "zod";
 
-test("qin qout passthrough", () => {
+test("opt passthrough", () => {
   const object = z.object({
     a: z.lazy(() => z.string()),
     b: z.lazy(() => z.string().optional()),
@@ -36,11 +36,167 @@ test("qin qout passthrough", () => {
     c: "default",
   });
 
-  const lazyString = z.lazy(() => z.string().optional());
-  expect(lazyString._zod.qout).toEqual("true");
-  expect(object._zod.def.optional).toMatchInlineSnapshot(`
-    [
-      "b",
-    ]
-  `);
+  expect(z.lazy(() => z.string())._zod.optionality).toEqual(undefined);
+  expect(z.lazy(() => z.string().optional())._zod.optionality).toEqual("optional");
+  expect(z.lazy(() => z.string().default("asdf"))._zod.optionality).toEqual("defaulted");
+});
+
+//////////////   LAZY   //////////////
+
+test("schema getter", () => {
+  z.lazy(() => z.string()).parse("asdf");
+});
+
+test("lazy proxy", () => {
+  const schema = z.lazy(() => z.string())._zod._getter.min(6);
+  schema.parse("123456");
+  expect(schema.safeParse("12345").success).toBe(false);
+});
+
+interface Category {
+  name: string;
+  subcategories: Category[];
+}
+
+const testCategory: Category = {
+  name: "I",
+  subcategories: [
+    {
+      name: "A",
+      subcategories: [
+        {
+          name: "1",
+          subcategories: [
+            {
+              name: "a",
+              subcategories: [],
+            },
+          ],
+        },
+      ],
+    },
+  ],
+};
+
+test("recursion with z.lazy", () => {
+  const Category: z.ZodType<Category> = z.lazy(() =>
+    z.object({
+      name: z.string(),
+      subcategories: z.array(Category),
+    })
+  );
+  Category.parse(testCategory);
+});
+
+type LinkedList = null | { value: number; next: LinkedList };
+
+const linkedListExample = {
+  value: 1,
+  next: {
+    value: 2,
+    next: {
+      value: 3,
+      next: {
+        value: 4,
+        next: null,
+      },
+    },
+  },
+};
+
+test("recursive union wit z.lazy", () => {
+  const LinkedListSchema: z.ZodType<LinkedList> = z.lazy(() =>
+    z.union([
+      z.null(),
+      z.object({
+        value: z.number(),
+        next: LinkedListSchema,
+      }),
+    ])
+  );
+  LinkedListSchema.parse(linkedListExample);
+});
+
+interface A {
+  val: number;
+  b: B;
+}
+
+interface B {
+  val: number;
+  a?: A | undefined;
+}
+
+test("mutual recursion with lazy", () => {
+  const Alazy: z.ZodType<A> = z.lazy(() =>
+    z.object({
+      val: z.number(),
+      b: Blazy,
+    })
+  );
+
+  const Blazy: z.ZodType<B> = z.lazy(() =>
+    z.object({
+      val: z.number(),
+      a: Alazy.optional(),
+    })
+  );
+
+  const testData = {
+    val: 1,
+    b: {
+      val: 5,
+      a: {
+        val: 3,
+        b: {
+          val: 4,
+          a: {
+            val: 2,
+            b: {
+              val: 1,
+            },
+          },
+        },
+      },
+    },
+  };
+
+  Alazy.parse(testData);
+  Blazy.parse(testData.b);
+
+  expect(() => Alazy.parse({ val: "asdf" })).toThrow();
+});
+
+// TODO
+test("mutual recursion with cyclical data", () => {
+  const a: any = { val: 1 };
+  const b: any = { val: 2 };
+  a.b = b;
+  b.a = a;
+});
+
+test("complicated self-recursion", () => {
+  const Category = z.object({
+    name: z.string(),
+    age: z.optional(z.number()),
+    get nullself() {
+      return Category.nullable();
+    },
+    get optself() {
+      return Category.optional();
+    },
+    get self() {
+      return Category;
+    },
+    get subcategories() {
+      return z.array(Category);
+    },
+    nested: z.object({
+      get sub() {
+        return Category;
+      },
+    }),
+  });
+
+  type _Category = z.output<typeof Category>;
 });
diff --git a/packages/zod/tests/number.test.ts b/packages/zod/tests/number.test.ts
index d8383c02..27ef999b 100644
--- a/packages/zod/tests/number.test.ts
+++ b/packages/zod/tests/number.test.ts
@@ -242,3 +242,9 @@ test("int getter", () => {
 test("finite getter", () => {
   expect(z.number().isFinite).toEqual(true);
 });
+
+test("string format methods", () => {
+  const a = z.int32().min(5);
+  expect(a.parse(6)).toEqual(6);
+  expect(() => a.parse(1)).toThrow();
+});
diff --git a/packages/zod/tests/object.test.ts b/packages/zod/tests/object.test.ts
index 46283b7a..d07a2466 100644
--- a/packages/zod/tests/object.test.ts
+++ b/packages/zod/tests/object.test.ts
@@ -80,7 +80,7 @@ test("empty object", () => {
   expect(schema.parse({ name: "asdf" })).toEqual({});
   expect(schema.safeParse(null).success).toEqual(false);
   expect(schema.safeParse("asdf").success).toEqual(false);
-  expectTypeOf<typeof schema._zod.output>().toEqualTypeOf<object>();
+  expectTypeOf<z.output<typeof schema>>().toEqualTypeOf<object>();
 });
 
 const data = {
@@ -213,6 +213,7 @@ test("test async union", async () => {
 test("test inferred merged type", async () => {
   const asdf = z.object({ a: z.string() }).merge(z.object({ a: z.number() }));
   type asdf = z.infer<typeof asdf>;
+
   expectTypeOf<asdf>().toEqualTypeOf<{ a: number }>();
 });
 
@@ -433,12 +434,12 @@ test("passthrough index signature", () => {
 // });
 
 test("assignability", () => {
-  z.interface({ a: z.string() }) satisfies z.ZodInterface;
-  z.interface({ a: z.string() }).catchall(z.number()) satisfies z.ZodInterface;
-  z.interface({ a: z.string() }).strict() satisfies z.ZodInterface;
-  z.interface({}) satisfies z.ZodInterface;
-  z.interface({ "a?": z.string() }) satisfies z.ZodInterface;
-  z.interface({ "?a": z.string() }) satisfies z.ZodInterface;
+  z.object({ a: z.string() }) satisfies z.ZodObject;
+  z.object({ a: z.string() }).catchall(z.number()) satisfies z.ZodObject;
+  z.object({ a: z.string() }).strict() satisfies z.ZodObject;
+  z.object({}) satisfies z.ZodObject;
+  z.object({ "a?": z.string() }) satisfies z.ZodObject;
+  z.object({ "?a": z.string() }) satisfies z.ZodObject;
 });
 
 test("null prototype", () => {
diff --git a/packages/zod/tests/partial-interface.test.ts b/packages/zod/tests/partial-interface.test.ts
deleted file mode 100644
index 907ba4c7..00000000
--- a/packages/zod/tests/partial-interface.test.ts
+++ /dev/null
@@ -1,147 +0,0 @@
-import { expect, expectTypeOf, test } from "vitest";
-import * as z from "zod";
-
-const nested = z.interface({
-  name: z.string(),
-  age: z.number(),
-  outer: z.interface({
-    inner: z.string(),
-  }),
-  array: z.array(z.interface({ asdf: z.string() })),
-});
-
-test("shallow inference", () => {
-  const shallow = nested.partial();
-  type shallow = z.infer<typeof shallow>;
-
-  expectTypeOf<shallow>().toEqualTypeOf<{
-    name?: string | undefined;
-    age?: number | undefined;
-    outer?: { inner: string } | undefined;
-    array?: { asdf: string }[] | undefined;
-  }>();
-});
-
-test("shallow partial parse", () => {
-  const shallow = nested.partial();
-  shallow.parse({});
-  shallow.parse({
-    name: "asdf",
-    age: 23143,
-  });
-});
-
-test("required", () => {
-  const object = z.interface({
-    name: z.string(),
-    age: z.number().optional(),
-    field: z.string().optional().default("asdf"),
-    nullableField: z.number().nullable(),
-    nullishField: z.string().nullish(),
-  });
-
-  const requiredObject = object.required();
-  expect(requiredObject._zod.def.shape.name).toBeInstanceOf(z.ZodNonOptional);
-  expect(requiredObject._zod.def.shape.name.unwrap()).toBeInstanceOf(z.ZodString);
-  expect(requiredObject._zod.def.shape.age).toBeInstanceOf(z.ZodNonOptional);
-  expect(requiredObject._zod.def.shape.age.unwrap()).toBeInstanceOf(z.ZodOptional);
-  expect(requiredObject._zod.def.shape.field).toBeInstanceOf(z.ZodNonOptional);
-  expect(requiredObject._zod.def.shape.field.unwrap()).toBeInstanceOf(z.ZodDefault);
-  expect(requiredObject._zod.def.shape.nullableField).toBeInstanceOf(z.ZodNonOptional);
-  expect(requiredObject._zod.def.shape.nullableField.unwrap()).toBeInstanceOf(z.ZodNullable);
-  expect(requiredObject._zod.def.shape.nullishField).toBeInstanceOf(z.ZodNonOptional);
-  expect(requiredObject._zod.def.shape.nullishField.unwrap()).toBeInstanceOf(z.ZodOptional);
-  expect(requiredObject._zod.def.shape.nullishField.unwrap().unwrap()).toBeInstanceOf(z.ZodNullable);
-});
-
-test("required inference", () => {
-  const object = z.interface({
-    name: z.string(),
-    age: z.number().optional(),
-    field: z.string().optional().default("asdf"),
-    nullableField: z.number().nullable(),
-    nullishField: z.string().nullish(),
-  });
-
-  const requiredObject = object.required();
-
-  type required = z.infer<typeof requiredObject>;
-  type expected = {
-    name: string;
-    age: number;
-    field: string;
-    nullableField: number | null;
-    nullishField: string | null;
-  };
-  expectTypeOf<expected>().toEqualTypeOf<required>();
-});
-
-test("required with mask", () => {
-  const object = z.interface({
-    name: z.string(),
-    age: z.number().optional(),
-    field: z.string().optional().default("asdf"),
-    country: z.string().optional(),
-  });
-
-  const requiredObject = object.required({ age: true });
-  expect(requiredObject._zod.def.shape.name).toBeInstanceOf(z.ZodString);
-  expect(requiredObject._zod.def.shape.age).toBeInstanceOf(z.ZodNonOptional);
-  expect(requiredObject._zod.def.shape.field).toBeInstanceOf(z.ZodDefault);
-  expect(requiredObject._zod.def.shape.country).toBeInstanceOf(z.ZodOptional);
-});
-
-test("required with mask -- ignore falsy values", () => {
-  const object = z.interface({
-    name: z.string(),
-    age: z.number().optional(),
-    field: z.string().optional().default("asdf"),
-    country: z.string().optional(),
-  });
-
-  // @ts-expect-error
-  const requiredObject = object.required({ age: true, country: false });
-  expect(requiredObject._zod.def.shape.name).toBeInstanceOf(z.ZodString);
-  expect(requiredObject._zod.def.shape.age).toBeInstanceOf(z.ZodNonOptional);
-  expect(requiredObject._zod.def.shape.field).toBeInstanceOf(z.ZodDefault);
-  expect(requiredObject._zod.def.shape.country).toBeInstanceOf(z.ZodOptional);
-});
-
-test("partial with mask", async () => {
-  const object = z.interface({
-    name: z.string(),
-    age: z.number().optional(),
-    field: z.string().optional().default("asdf"),
-    country: z.string(),
-  });
-
-  const masked = object.partial({ age: true, field: true, name: true }).strict();
-
-  expect(masked._zod.def.shape.name).toBeInstanceOf(z.ZodOptional);
-  expect(masked._zod.def.shape.age).toBeInstanceOf(z.ZodOptional);
-  expect(masked._zod.def.shape.field).toBeInstanceOf(z.ZodOptional);
-  expect(masked._zod.def.shape.country).toBeInstanceOf(z.ZodString);
-
-  masked.parse({ country: "US" });
-  await masked.parseAsync({ country: "US" });
-});
-
-test("partial with mask -- ignore falsy values", async () => {
-  const object = z.interface({
-    name: z.string(),
-    age: z.number().optional(),
-    field: z.string().optional().default("asdf"),
-    country: z.string(),
-  });
-
-  // @ts-expect-error
-  const masked = object.partial({ name: true, country: false }).strict();
-
-  expect(masked._zod.def.shape.name).toBeInstanceOf(z.ZodOptional);
-  expect(masked._zod.def.shape.age).toBeInstanceOf(z.ZodOptional);
-  expect(masked._zod.def.shape.field).toBeInstanceOf(z.ZodDefault);
-  expect(masked._zod.def.shape.country).toBeInstanceOf(z.ZodString);
-
-  masked.parse({ country: "US" });
-  await masked.parseAsync({ country: "US" });
-});
diff --git a/packages/zod/tests/pickomit-interface.test.ts b/packages/zod/tests/pickomit-interface.test.ts
deleted file mode 100644
index 0d7d3f85..00000000
--- a/packages/zod/tests/pickomit-interface.test.ts
+++ /dev/null
@@ -1,125 +0,0 @@
-import { expect, expectTypeOf, test } from "vitest";
-import * as z from "zod";
-
-const fish = z.interface({
-  name: z.string(),
-  age: z.number(),
-  nested: z.interface({}),
-});
-
-test("pick type inference", () => {
-  const nameonlyFish = fish.pick({ name: true });
-  type nameonlyFish = z.infer<typeof nameonlyFish>;
-  expectTypeOf<nameonlyFish>().toEqualTypeOf<{ name: string }>();
-});
-
-test("pick", () => {
-  fish.pick({ name: true }).parse({ name: "bob" });
-  fish.pick({ name: true }).parse({ name: "12" });
-  fish.pick({ name: true }).parse({ name: "bob", age: 12 });
-  fish.pick({ age: true }).parse({ age: 12 });
-
-  // @ts-expect-error checking runtime picks `name` only.
-  const b = fish.pick({ name: true, age: false });
-  b.parse({ name: "bob" });
-  b.parse({ name: "bob", age: 12 });
-  expect(() => b.parse({ age: 12 })).toThrow();
-});
-
-test("pick parse - fail", () => {
-  fish.pick({ name: true }).parse({ name: "12" } as any);
-  fish.pick({ name: true }).parse({ name: "bob", age: 12 } as any);
-  fish.pick({ age: true }).parse({ age: 12 } as any);
-
-  const nameonlyFish = fish.pick({ name: true }).strict();
-  const bad1 = () => nameonlyFish.parse({ name: 12 } as any);
-  const bad2 = () => nameonlyFish.parse({ name: "bob", age: 12 } as any);
-  const bad3 = () => nameonlyFish.parse({ age: 12 } as any);
-
-  // @ts-expect-error checking runtime picks `name` only.
-  const anotherNameonlyFish = fish.pick({ name: true, age: false }).strict();
-  const bad4 = () => anotherNameonlyFish.parse({ name: "bob", age: 12 } as any);
-
-  expect(bad1).toThrow();
-  expect(bad2).toThrow();
-  expect(bad3).toThrow();
-  expect(bad4).toThrow();
-});
-
-test("pick - remove optional", () => {
-  const schema = z.interface({ a: z.string, "b?": z.string() });
-  expect(schema.pick({ a: true })._zod.def.optional).toEqual([]);
-  expect(schema.pick({ b: true })._zod.def.optional).toEqual(["b"]);
-});
-
-test("omit type inference", () => {
-  const nonameFish = fish.omit({ name: true });
-  type nonameFish = z.infer<typeof nonameFish>;
-
-  expectTypeOf<nonameFish>().toEqualTypeOf<{ age: number; nested: object }>();
-});
-
-test("omit parse - success", () => {
-  const nonameFish = fish.omit({ name: true });
-  nonameFish.parse({ age: 12, nested: {} });
-
-  // @ts-expect-error checking runtime omits `name` only.
-  const anotherNonameFish = fish.omit({ name: true, age: false });
-  anotherNonameFish.parse({ age: 12, nested: {} });
-});
-
-test("omit parse - fail", () => {
-  const nonameFish = fish.omit({ name: true });
-  const bad1 = () => nonameFish.parse({ name: 12 } as any);
-  const bad2 = () => nonameFish.parse({ age: 12 } as any);
-  const bad3 = () => nonameFish.parse({} as any);
-
-  // @ts-expect-error checking runtime omits `name` only.
-  const anotherNonameFish = fish.omit({ name: true, age: false });
-  const bad4 = () => anotherNonameFish.parse({ nested: {} } as any);
-
-  expect(bad1).toThrow();
-  expect(bad2).toThrow();
-  expect(bad3).toThrow();
-  expect(bad4).toThrow();
-});
-
-test("omit - remove optional", () => {
-  const schema = z.interface({ a: z.string(), "b?": z.string() });
-  expect(schema.omit({ a: true })._zod.def.optional).toEqual(["b"]);
-  expect(schema.omit({ b: true })._zod.def.optional).toEqual([]);
-});
-
-test("nonstrict inference", () => {
-  const laxfish = fish.pick({ name: true }).catchall(z.any());
-  type laxfish = z.infer<typeof laxfish>;
-  expectTypeOf<laxfish>().toEqualTypeOf<{ name: string; [k: string]: any }>();
-});
-
-test("nonstrict parsing - pass", () => {
-  const laxfish = fish.loose().pick({ name: true });
-  laxfish.parse({ name: "asdf", whatever: "asdf" });
-  laxfish.parse({ name: "asdf", age: 12, nested: {} });
-});
-
-test("nonstrict parsing - fail", () => {
-  const laxfish = fish.loose().pick({ name: true });
-  const bad = () => laxfish.parse({ whatever: "asdf" } as any);
-  expect(bad).toThrow();
-});
-
-test("pick/omit/required/partial - do not allow unknown keys", () => {
-  const schema = z.interface({
-    name: z.string(),
-    age: z.number(),
-  });
-
-  // @ts-expect-error
-  expect(() => schema.pick({ $unknown: true })).toThrow();
-  // @ts-expect-error
-  expect(() => schema.omit({ $unknown: true })).toThrow();
-  // @ts-expect-error
-  expect(() => schema.required({ $unknown: true })).toThrow();
-  // @ts-expect-error
-  expect(() => schema.partial({ $unknown: true })).toThrow();
-});
diff --git a/packages/zod/tests/pickomit-object.test.ts b/packages/zod/tests/pickomit-object.test.ts
index 1b20f284..7d0cbfe1 100644
--- a/packages/zod/tests/pickomit-object.test.ts
+++ b/packages/zod/tests/pickomit-object.test.ts
@@ -43,9 +43,12 @@ test("pick parse - fail", () => {
 });
 
 test("pick - remove optional", () => {
-  const schema = z.interface({ a: z.string, "b?": z.string() });
-  expect(schema.pick({ a: true })._zod.def.optional).toEqual([]);
-  expect(schema.pick({ b: true })._zod.def.optional).toEqual(["b"]);
+  const schema = z.object({ a: z.string(), b: z.string().optional() });
+  expect(schema._zod.def.shape.a._zod.optionality).toEqual(undefined);
+  expect(schema._zod.def.shape.b!._zod.optionality).toEqual("optional");
+  const picked = schema.pick({ a: true });
+  expect(picked._zod.def.shape.a._zod.optionality).toEqual(undefined);
+  expect("b" in picked._zod.def.shape!).toEqual(false);
 });
 
 test("omit type inference", () => {
@@ -81,9 +84,10 @@ test("omit parse - fail", () => {
 });
 
 test("omit - remove optional", () => {
-  const schema = z.interface({ a: z.string, "b?": z.string() });
-  expect(schema.omit({ a: true })._zod.def.optional).toEqual(["b"]);
-  expect(schema.omit({ b: true })._zod.def.optional).toEqual([]);
+  const schema = z.object({ a: z.string(), b: z.string().optional() });
+  const omitted = schema.omit({ a: true });
+  expect("a" in omitted._zod.def.shape).toEqual(false);
+  expect(omitted._zod.def.shape.b!._zod.optionality).toEqual("optional");
 });
 
 test("nonstrict inference", () => {
diff --git a/packages/zod/tests/recursive-object.test.ts b/packages/zod/tests/recursive-object.test.ts
deleted file mode 100644
index 22def211..00000000
--- a/packages/zod/tests/recursive-object.test.ts
+++ /dev/null
@@ -1,134 +0,0 @@
-import { expect, test } from "vitest";
-
-import { z } from "zod";
-
-test("schema getter", () => {
-  z.lazy(() => z.string()).parse("asdf");
-});
-
-test("lazy proxy", () => {
-  const schema = z.lazy(() => z.string())._zod._getter.min(6);
-  schema.parse("123456");
-  expect(schema.safeParse("12345").success).toBe(false);
-});
-
-interface Category {
-  name: string;
-  subcategories: Category[];
-}
-
-const testCategory: Category = {
-  name: "I",
-  subcategories: [
-    {
-      name: "A",
-      subcategories: [
-        {
-          name: "1",
-          subcategories: [
-            {
-              name: "a",
-              subcategories: [],
-            },
-          ],
-        },
-      ],
-    },
-  ],
-};
-
-test("recursion with z.lazy", () => {
-  const Category: z.ZodType<Category> = z.lazy(() =>
-    z.object({
-      name: z.string(),
-      subcategories: z.array(Category),
-    })
-  );
-  Category.parse(testCategory);
-});
-
-type LinkedList = null | { value: number; next: LinkedList };
-
-const linkedListExample = {
-  value: 1,
-  next: {
-    value: 2,
-    next: {
-      value: 3,
-      next: {
-        value: 4,
-        next: null,
-      },
-    },
-  },
-};
-
-test("recursion involving union type", () => {
-  const LinkedListSchema: z.ZodType<LinkedList> = z.lazy(() =>
-    z.union([
-      z.null(),
-      z.object({
-        value: z.number(),
-        next: LinkedListSchema,
-      }),
-    ])
-  );
-  LinkedListSchema.parse(linkedListExample);
-});
-
-interface A {
-  val: number;
-  b: B;
-}
-
-interface B {
-  val: number;
-  a?: A | undefined;
-}
-
-const Alazy: z.ZodType<A> = z.lazy(() =>
-  z.object({
-    val: z.number(),
-    b: Blazy,
-  })
-);
-
-const Blazy: z.ZodType<B> = z.lazy(() =>
-  z.object({
-    val: z.number(),
-    a: Alazy.optional(),
-  })
-);
-
-test("mutual recursion", () => {
-  const testData = {
-    val: 1,
-    b: {
-      val: 5,
-      a: {
-        val: 3,
-        b: {
-          val: 4,
-          a: {
-            val: 2,
-            b: {
-              val: 1,
-            },
-          },
-        },
-      },
-    },
-  };
-
-  Alazy.parse(testData);
-  Blazy.parse(testData.b);
-
-  expect(() => Alazy.parse({ val: "asdf" })).toThrow();
-});
-
-test("mutual recursion with cyclical data", () => {
-  const a: any = { val: 1 };
-  const b: any = { val: 2 };
-  a.b = b;
-  b.a = a;
-});
diff --git a/packages/zod/tests/recursive-interface.test.ts b/packages/zod/tests/recursive-types.test.ts
similarity index 73%
rename from packages/zod/tests/recursive-interface.test.ts
rename to packages/zod/tests/recursive-types.test.ts
index 290c2fb8..5079e46f 100644
--- a/packages/zod/tests/recursive-interface.test.ts
+++ b/packages/zod/tests/recursive-types.test.ts
@@ -1,5 +1,4 @@
 import { expect, expectTypeOf, test } from "vitest";
-
 import { z } from "zod";
 
 test("recursion with z.lazy", () => {
@@ -23,7 +22,7 @@ test("recursion with z.lazy", () => {
     ],
   };
 
-  const Category = z.interface({
+  const Category = z.object({
     name: z.string(),
     get subcategories() {
       return z.array(Category);
@@ -47,34 +46,32 @@ test("recursion involving union type", () => {
     },
   };
 
-  const LinkedListSchema = z.union([
-    z.null(),
-    z.interface({
+  const LL = z
+    .object({
       value: z.number(),
       get next() {
-        return LinkedListSchema;
+        return LL.nullable();
       },
-    }),
-  ]);
-
-  LinkedListSchema.parse(data);
-});
+    })
+    .or(z.null());
 
-const Alazy = z.interface({
-  val: z.number(),
-  get b() {
-    return Blazy;
-  },
+  LL.parse(data);
 });
 
-const Blazy = z.interface({
-  val: z.number(),
-  get a() {
-    return Alazy.optional();
-  },
-});
+test("mutual recursion - native", () => {
+  const Alazy = z.object({
+    val: z.number(),
+    get b() {
+      return Blazy;
+    },
+  });
 
-test("mutual recursion", () => {
+  const Blazy = z.object({
+    val: z.number(),
+    get a() {
+      return Alazy.optional();
+    },
+  });
   const testData = {
     val: 1,
     b: {
@@ -100,18 +97,8 @@ test("mutual recursion", () => {
   expect(() => Alazy.parse({ val: "asdf" })).toThrow();
 });
 
-// test("mutual recursion with cyclical data", () => {
-//   const a: any = { val: 1 };
-//   const b: any = { val: 2 };
-//   a.b = b;
-//   b.a = a;
-
-//   Alazy.parse(a);
-//   Blazy.parse(b);
-// });
-
-test("pick and omit with recursive interface", () => {
-  const Category = z.strictInterface({
+test("pick and omit with getter", () => {
+  const Category = z.strictObject({
     name: z.string(),
     get subcategories() {
       return z.array(Category);
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)$"`
   );