Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
c679758
Update layout.tsx to enhance user experience
yamcodes Nov 25, 2025
89d227d
Update pnpm-lock.yaml to add Bun plugin dependencies
yamcodes Nov 25, 2025
797bc22
Add Bun plugin entry to workspace configuration
yamcodes Nov 25, 2025
71f2605
[autofix.ci] apply automated fixes
autofix-ci[bot] Nov 25, 2025
08a7e73
Implement @arkenv/bun-plugin with environment variable validation
yamcodes Nov 25, 2025
c78343e
Add @arkenv/bun-plugin and vitest dependencies
yamcodes Nov 25, 2025
99e52a3
[autofix.ci] apply automated fixes
autofix-ci[bot] Nov 25, 2025
9c58942
Reorganize bun dependency in pnpm-lock.yaml
yamcodes Nov 25, 2025
92e11d4
Update bun dependencies and environment variable handling
yamcodes Nov 25, 2025
c432425
Remove unnecessary blank line in bun-plugin-config.ts for cleaner code.
yamcodes Nov 25, 2025
17c6456
Add Bun Plugin for ArkEnv with Configuration Patterns
yamcodes Nov 26, 2025
25d9fb4
chore: add `@types/bun` to bun-plugin dev dependencies
yamcodes Nov 27, 2025
6cd230b
refactor: Use `await Bun.file().text()` for asynchronous file content…
yamcodes Nov 27, 2025
351ce5b
feat: Centralize Bun React playground environment variable definition…
yamcodes Nov 27, 2025
63ef1e5
[autofix.ci] apply automated fixes
autofix-ci[bot] Nov 27, 2025
43ae600
feat: display environment variables in a styled table and add plugin …
yamcodes Nov 27, 2025
ddbc008
feat: Add specific public Bun environment variables and refactor SVG/…
yamcodes Nov 27, 2025
408248a
feat: add type column for environment variables display in the UI
yamcodes Nov 27, 2025
0651540
feat: enable sourcemap generation in tsdown configuration
yamcodes Nov 27, 2025
46fe73b
feat: Add `preview` script, display `NODE_ENV` in the app, and remove…
yamcodes Nov 27, 2025
f53d087
feat: Update Bun plugin to use named export and support direct regist…
yamcodes Nov 27, 2025
f3432a7
feat: Add default static ArkEnv plugin with automatic schema discover…
yamcodes Nov 27, 2025
d0beeba
chore: Delete ArkEnv Bun plugin configuration file.
yamcodes Nov 27, 2025
7b75358
[autofix.ci] apply automated fixes
autofix-ci[bot] Nov 27, 2025
08fcca6
feat: Refactor `arkenv` Bun plugin to support hybrid zero-config and …
yamcodes Nov 27, 2025
bfe0a9e
feat: configure Bun build to define process.env.NODE_ENV as production
yamcodes Nov 27, 2025
f7abcbe
refactor: Initialize Bun plugin environment schema using `build.onSta…
yamcodes Nov 27, 2025
3a59005
feat: introduce a hybrid export for the Bun plugin, clarify usage pat…
yamcodes Nov 27, 2025
e3c82b3
feat: Add Bun plugin documentation and update the install button to s…
yamcodes Nov 27, 2025
9b81288
refactor: Remove Vite logger support proposal files and add arkenv al…
yamcodes Nov 27, 2025
c811ade
Merge branch 'main' into bun-plugin
yamcodes Nov 27, 2025
761e3ba
Merge branch 'main' into bun-plugin
yamcodes Nov 28, 2025
d3bdcbc
chore: add bun to devDependencies
yamcodes Nov 28, 2025
328e867
Update apps/playgrounds/bun-react/bin/build.ts
yamcodes Nov 28, 2025
b498d52
docs: clarify how to customize the public environment variable prefix…
yamcodes Nov 28, 2025
754a62c
refactor: update Bun plugin usage to import `arkenv` directly and def…
yamcodes Nov 28, 2025
b13f5a3
docs: Update Bun plugin package name from `bun-plugin-arkenv` to `@ar…
yamcodes Nov 28, 2025
5a88d9a
feat: Update Bun plugin package name to `@arkenv/bun-plugin`, switch …
yamcodes Nov 28, 2025
f1ba897
feat: update Bun plugin package name and schema definition method fro…
yamcodes Nov 28, 2025
0b345b7
Update packages/bun-plugin/src/index.ts
yamcodes Nov 28, 2025
cd702be
[autofix.ci] apply automated fixes
autofix-ci[bot] Nov 28, 2025
bad196e
docs: simplify Bun plugin creation function name in examples and desc…
yamcodes Nov 28, 2025
a70bde8
docs: Update `ProcessEnvAugmented` example to use default export from…
yamcodes Nov 28, 2025
c4047f4
test: improve test isolation by saving and restoring process.env in t…
yamcodes Nov 28, 2025
05e81ca
feat: export `processEnvSchema` function and update tests to directly…
yamcodes Nov 28, 2025
df8c39e
docs: add impact section to Bun plugin proposal detailing its opt-in,…
yamcodes Nov 28, 2025
84c6c1f
Replace detailed Bun plugin specification and design with an implemen…
yamcodes Nov 28, 2025
517ce75
docs: update markdown heading levels and formatting in design and pro…
yamcodes Nov 28, 2025
3981063
feat: introduce OpenSpec agent workflows for proposal, apply, and arc…
yamcodes Nov 28, 2025
db3ff26
feat: Add arkenv and arktype dependencies, configure production envir…
yamcodes Nov 28, 2025
6cd680c
Merge branch 'main' into bun-plugin
yamcodes Nov 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .agent/workflows/openspec-apply.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
description: Implement an approved OpenSpec change and keep tasks in sync.
---
<!-- OPENSPEC:START -->
**Guardrails**
- Favor straightforward, minimal implementations first and add complexity only when it is requested or clearly required.
- Keep changes tightly scoped to the requested outcome.
- Refer to `openspec/AGENTS.md` (located inside the `openspec/` directory—run `ls openspec` or `openspec update` if you don't see it) if you need additional OpenSpec conventions or clarifications.

**Steps**
Track these steps as TODOs and complete them one by one.
1. Read `changes/<id>/proposal.md`, `design.md` (if present), and `tasks.md` to confirm scope and acceptance criteria.
2. Work through tasks sequentially, keeping edits minimal and focused on the requested change.
3. Confirm completion before updating statuses—make sure every item in `tasks.md` is finished.
4. Update the checklist after all work is done so each task is marked `- [x]` and reflects reality.
5. Reference `openspec list` or `openspec show <item>` when additional context is required.

**Reference**
- Use `openspec show <id> --json --deltas-only` if you need additional context from the proposal while implementing.
<!-- OPENSPEC:END -->
24 changes: 24 additions & 0 deletions .agent/workflows/openspec-archive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
description: Archive a deployed OpenSpec change and update specs.
---
<!-- OPENSPEC:START -->
**Guardrails**
- Favor straightforward, minimal implementations first and add complexity only when it is requested or clearly required.
- Keep changes tightly scoped to the requested outcome.
- Refer to `openspec/AGENTS.md` (located inside the `openspec/` directory—run `ls openspec` or `openspec update` if you don't see it) if you need additional OpenSpec conventions or clarifications.

**Steps**
1. Determine the change ID to archive:
- If this prompt already includes a specific change ID (for example inside a `<ChangeId>` block populated by slash-command arguments), use that value after trimming whitespace.
- If the conversation references a change loosely (for example by title or summary), run `openspec list` to surface likely IDs, share the relevant candidates, and confirm which one the user intends.
- Otherwise, review the conversation, run `openspec list`, and ask the user which change to archive; wait for a confirmed change ID before proceeding.
- If you still cannot identify a single change ID, stop and tell the user you cannot archive anything yet.
2. Validate the change ID by running `openspec list` (or `openspec show <id>`) and stop if the change is missing, already archived, or otherwise not ready to archive.
3. Run `openspec archive <id> --yes` so the CLI moves the change and applies spec updates without prompts (use `--skip-specs` only for tooling-only work).
4. Review the command output to confirm the target specs were updated and the change landed in `changes/archive/`.
5. Validate with `openspec validate --strict` and inspect with `openspec show <id>` if anything looks off.

**Reference**
- Use `openspec list` to confirm change IDs before archiving.
- Inspect refreshed specs with `openspec list --specs` and address any validation issues before handing off.
<!-- OPENSPEC:END -->
25 changes: 25 additions & 0 deletions .agent/workflows/openspec-proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
description: Scaffold a new OpenSpec change and validate strictly.
---
<!-- OPENSPEC:START -->
**Guardrails**
- Favor straightforward, minimal implementations first and add complexity only when it is requested or clearly required.
- Keep changes tightly scoped to the requested outcome.
- Refer to `openspec/AGENTS.md` (located inside the `openspec/` directory—run `ls openspec` or `openspec update` if you don't see it) if you need additional OpenSpec conventions or clarifications.
- Identify any vague or ambiguous details and ask the necessary follow-up questions before editing files.
- Do not write any code during the proposal stage. Only create design documents (proposal.md, tasks.md, design.md, and spec deltas). Implementation happens in the apply stage after approval.

**Steps**
1. Review `openspec/project.md`, run `openspec list` and `openspec list --specs`, and inspect related code or docs (e.g., via `rg`/`ls`) to ground the proposal in current behaviour; note any gaps that require clarification.
2. Choose a unique verb-led `change-id` and scaffold `proposal.md`, `tasks.md`, and `design.md` (when needed) under `openspec/changes/<id>/`.
3. Map the change into concrete capabilities or requirements, breaking multi-scope efforts into distinct spec deltas with clear relationships and sequencing.
4. Capture architectural reasoning in `design.md` when the solution spans multiple systems, introduces new patterns, or demands trade-off discussion before committing to specs.
5. Draft spec deltas in `changes/<id>/specs/<capability>/spec.md` (one folder per capability) using `## ADDED|MODIFIED|REMOVED Requirements` with at least one `#### Scenario:` per requirement and cross-reference related capabilities when relevant.
6. Draft `tasks.md` as an ordered list of small, verifiable work items that deliver user-visible progress, include validation (tests, tooling), and highlight dependencies or parallelizable work.
7. Validate with `openspec validate <id> --strict` and resolve every issue before sharing the proposal.

**Reference**
- Use `openspec show <id> --json --deltas-only` or `openspec show <spec> --type spec` to inspect details when validation fails.
- Search existing requirements with `rg -n "Requirement:|Scenario:" openspec/specs` before writing new ones.
- Explore the codebase with `rg <keyword>`, `ls`, or direct file reads so proposals align with current implementation realities.
<!-- OPENSPEC:END -->
6 changes: 6 additions & 0 deletions .changeset/bun-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@arkenv/bun-plugin": minor
---

Add Bun plugin for build-time environment variable validation and type-safe access, similar to the Vite plugin.

1 change: 1 addition & 0 deletions .cursor/commands/openspec-proposal.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ description: Scaffold a new OpenSpec change and validate strictly.
- Keep changes tightly scoped to the requested outcome.
- Refer to `openspec/AGENTS.md` (located inside the `openspec/` directory—run `ls openspec` or `openspec update` if you don't see it) if you need additional OpenSpec conventions or clarifications.
- Identify any vague or ambiguous details and ask the necessary follow-up questions before editing files.
- Do not write any code during the proposal stage. Only create design documents (proposal.md, tasks.md, design.md, and spec deltas). Implementation happens in the apply stage after approval.

**Steps**
1. Review `openspec/project.md`, run `openspec list` and `openspec list --specs`, and inspect related code or docs (e.g., via `rg`/`ls`) to ground the proposal in current behaviour; note any gaps that require clarification.
Expand Down
2 changes: 2 additions & 0 deletions apps/playgrounds/bun-react/.env.production
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
BUN_PUBLIC_API_URL=https://api.example.com
BUN_PUBLIC_DEBUG=true
20 changes: 20 additions & 0 deletions apps/playgrounds/bun-react/bin/build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import arkenv from "@arkenv/bun-plugin";

const result = await Bun.build({
entrypoints: ["./src/index.html"],
outdir: "./dist",
sourcemap: true,
target: "browser",
minify: true,
plugins: [arkenv],
});

if (!result.success) {
console.error("Build failed:");
for (const log of result.logs) {
console.error(log);
}
process.exit(1);
}

console.log(`✓ Build succeeded: ${result.outputs.length} files generated`);
26 changes: 16 additions & 10 deletions apps/playgrounds/bun-react/bun-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
// Generated by `bun init`
/// <reference types="bun-types" />

// Import the Env schema type from env.ts
type ProcessEnvAugmented = import("@arkenv/bun-plugin").ProcessEnvAugmented<
typeof import("./src/env").default
>;

declare namespace NodeJS {
interface ProcessEnv extends ProcessEnvAugmented {
BUN_PUBLIC_API_URL: string;
BUN_PUBLIC_DEBUG: boolean;
}
}

declare module "*.svg" {
/**
* A path to the SVG file
*/
const path: `${string}.svg`;
export = path;
const content: string;
export default content;
}

declare module "*.module.css" {
/**
* A record of class names to their corresponding CSS module classes
*/
const classes: { readonly [key: string]: string };
export = classes;
export default classes;
}
3 changes: 2 additions & 1 deletion apps/playgrounds/bun-react/bunfig.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
[serve.static]
env = "BUN_PUBLIC_*"
env = "BUN_PUBLIC_*"
plugins = ["@arkenv/bun-plugin"]
6 changes: 5 additions & 1 deletion apps/playgrounds/bun-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
"type": "module",
"scripts": {
"dev": "bun --hot src/index.tsx",
"build": "bun build ./src/index.html --outdir=dist --sourcemap --target=browser --minify --define:process.env.NODE_ENV='\"production\"' --env='BUN_PUBLIC_*'",
"build": "NODE_ENV=production bun bin/build.ts",
"preview": "bun dist/index.html",
"start": "NODE_ENV=production bun src/index.tsx",
"clean": "rimraf dist node_modules"
},
"dependencies": {
"@arkenv/bun-plugin": "workspace:*",
"arkenv": "workspace:*",
"arktype": "catalog:",
"react": "catalog:",
"react-dom": "catalog:"
},
Expand Down
23 changes: 23 additions & 0 deletions apps/playgrounds/bun-react/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,29 @@ export function App() {
Edit <code>src/App.tsx</code> and save to test HMR
</p>
<APITester />
<table className="env-table">
<thead>
<tr>
<th>Variable</th>
<th>Value</th>
<th>Type</th>
</tr>
</thead>
<tbody>
<tr>
<td>BUN_PUBLIC_API_URL</td>
<td>{process.env.BUN_PUBLIC_API_URL}</td>
<td>{typeof process.env.BUN_PUBLIC_API_URL}</td>
</tr>
<tr>
<td>BUN_PUBLIC_DEBUG</td>
<td>{String(process.env.BUN_PUBLIC_DEBUG)}</td>
<td>{typeof process.env.BUN_PUBLIC_DEBUG}</td>
</tr>
</tbody>
</table>
{/* Print whether we are in "build" or in the dev server */}
<p>Mode: {process.env.NODE_ENV}</p>
</div>
);
}
Expand Down
6 changes: 6 additions & 0 deletions apps/playgrounds/bun-react/src/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { type } from "arkenv";

export default type({
BUN_PUBLIC_API_URL: "string",
BUN_PUBLIC_DEBUG: "boolean",
});
34 changes: 34 additions & 0 deletions apps/playgrounds/bun-react/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,37 @@ code {
animation: none !important;
}
}

.env-table {
width: 100%;
max-width: 600px;
margin: 2rem auto;
border-collapse: separate;
border-spacing: 0;
background: #1a1a1a;
border-radius: 12px;
overflow: hidden;
border: 2px solid #fbf0df;
}

.env-table th,
.env-table td {
padding: 1rem;
text-align: left;
border-bottom: 1px solid rgba(251, 240, 223, 0.1);
}

.env-table th {
background: rgba(251, 240, 223, 0.1);
color: #fbf0df;
font-weight: 600;
}

.env-table td {
color: #e0e0e0;
font-family: monospace;
}

.env-table tr:last-child td {
border-bottom: none;
}
4 changes: 2 additions & 2 deletions apps/playgrounds/bun-react/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ const server = serve({
"/*": index,

"/api/hello": {
async GET(req) {
async GET() {
return Response.json({
message: "Hello, world!",
method: "GET",
});
},
async PUT(req) {
async PUT() {
return Response.json({
message: "Hello, world!",
method: "PUT",
Expand Down
15 changes: 2 additions & 13 deletions apps/www/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Banner } from "fumadocs-ui/components/banner";
import { Banner } from "~/components/banner";
import "./globals.css";
import { Analytics } from "@vercel/analytics/next";
import { SpeedInsights } from "@vercel/speed-insights/next";
Expand Down Expand Up @@ -48,18 +48,7 @@ export default function Layout({ children }: { children: ReactNode }) {
enableSystem: true,
}}
>
<Banner variant="rainbow" id="vite-support-banner">
🎉 Announcing Vite support: check out the&nbsp;
<a
href="https://arkenv.js.org/docs/vite-plugin"
target="_blank"
rel="noopener noreferrer"
className="underline underline-offset-2 hover:text-blue-500"
>
new docs
</a>
!
</Banner>
<Banner />
{children}
<SpeedInsights />
<Analytics />
Expand Down
19 changes: 19 additions & 0 deletions apps/www/components/banner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"use client";

import { Banner as FumadocsBanner } from "fumadocs-ui/components/banner";
import { useRouter } from "next/navigation";

export function Banner() {
const router = useRouter();
return (
<FumadocsBanner
variant="rainbow"
id="bun-support-banner"
onClick={() => router.push("/docs/bun-plugin")}
className="cursor-pointer"
>
🎉 Official Bun support is here: ArkEnv at build time, fullstack dev
server
</FumadocsBanner>
);
}
22 changes: 14 additions & 8 deletions apps/www/components/docs/install-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,24 @@ import { Button } from "~/components/ui/button";
export function InstallButton() {
const pathname = usePathname();
const isVitePluginPage = pathname?.includes("/docs/vite-plugin");
const isBunPluginPage = pathname?.includes("/docs/bun-plugin");

let href = "/docs/arkenv/quickstart#install";
let label = "Install ArkEnv";

if (isVitePluginPage) {
href = "/docs/vite-plugin#installation";
label = "Install ArkEnv Vite plugin";
} else if (isBunPluginPage) {
href = "/docs/bun-plugin#installation";
label = "Install ArkEnv Bun plugin";
}

return (
<Button asChild className="w-full cursor-pointer">
<Link
href={
isVitePluginPage
? "/docs/vite-plugin#installation"
: "/docs/arkenv/quickstart#install"
}
>
<Link href={href}>
<Download aria-hidden="true" />
{isVitePluginPage ? "Install ArkEnv Vite plugin" : "Install ArkEnv"}
{label}
</Link>
</Button>
);
Expand Down
Loading
Loading