Skip to content

feat: withArkEnv should support split schema#1116

Merged
yamcodes merged 8 commits into
mainfrom
1114-witharkenv-should-support-split-schema
May 31, 2026
Merged

feat: withArkEnv should support split schema#1116
yamcodes merged 8 commits into
mainfrom
1114-witharkenv-should-support-split-schema

Conversation

@yamcodes
Copy link
Copy Markdown
Owner

Fixes #1114

This PR implements split schema layout (strict mode) support in the Next.js config wrapper withArkEnv and updates the CLI scaffold templates and next steps.

@yamcodes yamcodes added the enhancement New feature or request label May 31, 2026
@yamcodes yamcodes linked an issue May 31, 2026 that may be closed by this pull request
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 31, 2026

🦋 Changeset detected

Latest commit: bf20517

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@arkenv/cli Patch
@arkenv/nextjs Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added docs Improvements or additions to documentation tests This issue or PR is about adding, removing or changing tests @arkenv/cli Issues or Pull Requests involving the ArkEnv CLI @arkenv/nextjs Issues or Pull Requests involving the Next.js integration for ArkEnv labels May 31, 2026
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 31, 2026

Open in StackBlitz

arkenv

npm i https://pkg.pr.new/arkenv@1116

@arkenv/bun-plugin

npm i https://pkg.pr.new/@arkenv/bun-plugin@1116

@arkenv/cli

npm i https://pkg.pr.new/@arkenv/cli@1116

@arkenv/fumadocs-ui

npm i https://pkg.pr.new/@arkenv/fumadocs-ui@1116

@arkenv/nextjs

npm i https://pkg.pr.new/@arkenv/nextjs@1116

@arkenv/vite-plugin

npm i https://pkg.pr.new/@arkenv/vite-plugin@1116

commit: bf20517

@arkenv-bot
Copy link
Copy Markdown
Contributor

arkenv-bot Bot commented May 31, 2026

📦 Bundle Size Report

Package Size Limit Diff Status
@arkenv/nextjs 1003 B 2.93 kB 0.0%
@arkenv/nextjs/shared 1022 B 1.46 kB 0.0%
@arkenv/nextjs/server 1.06 kB 1.95 kB 0.0%
@arkenv/nextjs/client 1.05 kB 1.95 kB 0.0%
@arkenv/nextjs/config 2.36 kB 2.93 kB +47.5%

All size limits passed!

Copy link
Copy Markdown
Contributor

@pullfrog pullfrog Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

One correctness issue when layout: "strict" is explicitly set but the required split files are missing — the codegen silently produces an empty runtimeEnv instead of throwing. Details inline.

Reviewed changes — Added split-schema ("strict layout") support to the Next.js withArkEnv config wrapper, including auto-detection, static key extraction from split files, and updated CLI scaffolding/next-steps.

  • Add layout option and auto-detection to withArkEnvpackages/nextjs/src/config.ts now resolves "simple" vs "strict" by inspecting the filesystem, and generates a minimal runtimeEnv export for strict mode.
  • Introduce extractClientKeys and extractSharedKeys — New static parsers that extract env var names from client.ts and internal/shared.ts respectively.
  • Update CLI strict templates and next-stepsgetStrictEnvTemplates branches on disableCodegen, and getNextStepsNote includes withArkEnv wrapping instructions for strict-layout projects.
  • Add tests — Coverage for strict layout auto-detection, key extraction, template generation, and next-steps messaging.

⚠️ Layout resolution logic is duplicated between withArkEnv and runCodegen

The strict-layout auto-detection and baseDir resolution logic appears almost verbatim in both withArkEnv (lines 101–177) and runCodegen (lines 301–367). Keeping two copies in sync is error-prone — a future fix to one is likely to miss the other. Consider extracting a shared resolveLayoutAndBaseDir(schemaPath, layoutOption) helper.

Technical details
# Layout resolution logic is duplicated between `withArkEnv` and `runCodegen`

## Affected sites
- `packages/nextjs/src/config.ts:101-177``withArkEnv` layout resolution
- `packages/nextjs/src/config.ts:301-367``runCodegen` layout resolution

## Required outcome
- A single source of truth for mapping a `schemaPath` + optional `layout` to a resolved layout and `baseDir`.
- Both `withArkEnv` and `runCodegen` (and the watcher callback) must use it.

## Suggested approach
Extract a pure function:

```ts
function resolveLayout(
  schemaPath: string,
  layoutOption?: "simple" | "strict",
): { layout: "simple" | "strict"; baseDir: string };
```

Move the `checkStrict` helper and all `fs.existsSync` / `fs.statSync` branching into it. `withArkEnv` calls it once up front and passes the resolved values to `runCodegen`, which can then skip its own re-resolution when they are provided.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using Kimi K2𝕏

Comment thread packages/nextjs/src/config.ts Outdated
} else {
resolvedLayout = "simple";
}
} else if (resolvedLayout === "strict") {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ When layout: "strict" is explicitly set but the required split files (client.ts, internal/shared.ts) don't exist, runCodegen silently produces an empty runtimeEnv instead of throwing a helpful error.

The else if (resolvedLayout === "strict") branch (lines 349–367) resolves baseDir but never validates that client.ts and internal/shared.ts actually exist under it. If they don't, fs.readFileSync isn't called (guarded by fs.existsSync), so clientContent and sharedContent are empty strings, and the generated file exports an empty object.

Technical details
# Explicit strict layout without split files silently produces empty runtimeEnv

## Affected sites
- `packages/nextjs/src/config.ts:369-401` — strict codegen path

## Required outcome
- If `resolvedLayout === "strict"`, the codegen must verify that `client.ts` and `internal/shared.ts` exist under `baseDir`.
- If either is missing, throw a clear error telling the user which files are expected.

## Suggested approach
After resolving `baseDir` in the strict branch, add:

```ts
const clientPath = path.join(baseDir, "client.ts");
const sharedPath = path.join(baseDir, "internal", "shared.ts");
if (!fs.existsSync(clientPath) || !fs.existsSync(sharedPath)) {
  throw new Error(
    `[ArkEnv] Strict layout requires "${path.join(baseDir, "client.ts")}" and "${path.join(baseDir, "internal", "shared.ts")}".`,
  );
}
```

This mirrors the validation already done during auto-detection.

});
});

describe("strict config key extraction", () => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ The new extractClientKeys and extractSharedKeys tests only cover happy paths. Consider adding coverage for edge cases the underlying parsers handle — comments inside blocks, string literals containing braces or colons, and nested object literals — to prevent regressions if the regex/brace-counting logic is ever tightened.

@pullfrog
Copy link
Copy Markdown
Contributor

pullfrog Bot commented May 31, 2026

Pullfrog stalled

The agent stopped emitting events for 304s and was killed by the activity-timeout watchdog. 41 events were processed before the failure.

Recent agent stderr
INFO  2026-05-31T10:09:57 +53ms service=bus type=message.part.delta publishing
INFO  2026-05-31T10:09:57 +52ms service=bus type=message.part.delta publishing
INFO  2026-05-31T10:09:57 +57ms service=bus type=message.part.delta publishing
INFO  2026-05-31T10:09:58 +67ms service=bus type=message.part.delta publishing
INFO  2026-05-31T10:09:58 +59ms service=bus type=message.part.delta publishing
INFO  2026-05-31T10:09:58 +62ms service=bus type=message.part.delta publishing
INFO  2026-05-31T10:09:58 +65ms service=bus type=message.part.delta publishing
INFO  2026-05-31T10:09:58 +60ms service=bus type=message.part.delta publishing
INFO  2026-05-31T10:09:58 +60ms service=bus type=message.part.delta publishing
INFO  2026-05-31T10:09:58 +63ms service=bus type=message.part.delta publishing
INFO  2026-05-31T10:09:58 +67ms service=bus type=message.part.delta publishing
INFO  2026-05-31T10:09:58 +63ms service=bus type=message.part.delta publishing
INFO  2026-05-31T10:09:58 +103ms service=bus type=message.part.delta publishing
INFO  2026-05-31T10:09:58 +13ms service=bus type=message.part.delta publishing
INFO  2026-05-31T10:09:58 +67ms service=bus type=message.part.delta publishing
INFO  2026-05-31T10:09:58 +84ms service=bus type=message.part.delta publishing
INFO  2026-05-31T10:09:58 +48ms service=bus type=message.part.delta publishing
INFO  2026-05-31T10:09:58 +57ms service=bus type=message.part.delta publishing
INFO  2026-05-31T10:09:58 +59ms service=bus type=message.part.delta publishing
INFO  2026-05-31T10:09:58 +58ms service=bus type=message.part.delta publishing

Pullfrog  | Rerun failed job ➔View workflow run | via Pullfrog | Using Kimi K2𝕏

@yamcodes yamcodes merged commit b62ebbd into main May 31, 2026
21 checks passed
@yamcodes yamcodes deleted the 1114-witharkenv-should-support-split-schema branch May 31, 2026 10:21
@arkenv-bot arkenv-bot Bot mentioned this pull request May 31, 2026
yamcodes pushed a commit that referenced this pull request May 31, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @arkenv/cli@0.2.7

### Patch Changes

- #### Format empty schema objects cleanly in scaffolding
_[`#1116`](#1116)
[`b62ebbd`](b62ebbd)
[@yamcodes](https://github.com/yamcodes)_

Format empty schema objects cleanly as `{}` on a single line (instead of
multi-line empty blocks with trailing whitespace) during project
scaffolding.

- #### Generate tailored `createEnv` factory in Next.js strict layout
_[`#1116`](#1116)
[`b62ebbd`](b62ebbd)
[@yamcodes](https://github.com/yamcodes)_

Generate a tailored `createEnv` factory helper in `env.gen.ts` when
using the strict split-schema layout (instead of exporting a raw
`runtimeEnv` object).

This eliminates the need to manually declare or reference the
`runtimeEnv` object inside the client schema `client.ts` file, aligning
it closer to the core `arkenv` experience of simply calling
`createEnv(schema, options)`.

    Example usage in `client.ts`:

    ```ts
    import { createEnv } from "./generated/env.gen";
    import { SharedSchema } from "./internal/shared";

    export const env = createEnv(
      {
        NEXT_PUBLIC_API_URL: "string",
      },
      {
        extends: [SharedSchema],
      }
    );
    ```

- #### Support split schema layout in Next.js config wrapper
_[`#1116`](#1116)
[`b62ebbd`](b62ebbd)
[@yamcodes](https://github.com/yamcodes)_

Add support for the strict split schema layout in the Next.js
`withArkEnv` configuration wrapper and update CLI scaffolding
instructions:

- Add a `layout` option (`"simple" | "strict"`) to `withArkEnv`
configuration, which defaults to auto-detecting the strict layout if
split files (`env/internal/shared.ts`, `env/client.ts`, `env/server.ts`)
exist.
- Implement key extraction from strict client and shared schema files.
- Update CLI next-steps messages to include `withArkEnv` wrapping
instructions for strict layout nextjs projects.

## @arkenv/nextjs@0.0.5

### Patch Changes

- #### Generate tailored `createEnv` factory in Next.js strict layout
_[`#1116`](#1116)
[`b62ebbd`](b62ebbd)
[@yamcodes](https://github.com/yamcodes)_

Generate a tailored `createEnv` factory helper in `env.gen.ts` when
using the strict split-schema layout (instead of exporting a raw
`runtimeEnv` object).

This eliminates the need to manually declare or reference the
`runtimeEnv` object inside the client schema `client.ts` file, aligning
it closer to the core `arkenv` experience of simply calling
`createEnv(schema, options)`.

    Example usage in `client.ts`:

    ```ts
    import { createEnv } from "./generated/env.gen";
    import { SharedSchema } from "./internal/shared";

    export const env = createEnv(
      {
        NEXT_PUBLIC_API_URL: "string",
      },
      {
        extends: [SharedSchema],
      }
    );
    ```

- #### Support split schema layout in Next.js config wrapper
_[`#1116`](#1116)
[`b62ebbd`](b62ebbd)
[@yamcodes](https://github.com/yamcodes)_

Add support for the strict split schema layout in the Next.js
`withArkEnv` configuration wrapper and update CLI scaffolding
instructions:

- Add a `layout` option (`"simple" | "strict"`) to `withArkEnv`
configuration, which defaults to auto-detecting the strict layout if
split files (`env/internal/shared.ts`, `env/client.ts`, `env/server.ts`)
exist.
- Implement key extraction from strict client and shared schema files.
- Update CLI next-steps messages to include `withArkEnv` wrapping
instructions for strict layout nextjs projects.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

@arkenv/cli Issues or Pull Requests involving the ArkEnv CLI @arkenv/nextjs Issues or Pull Requests involving the Next.js integration for ArkEnv docs Improvements or additions to documentation enhancement New feature or request tests This issue or PR is about adding, removing or changing tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

withArkEnv should support split schema

1 participant