Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 13 additions & 0 deletions .changeset/tanstack-addon-rc-ranges.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@arkenv/tanstack-addon": patch
---

#### Point TanStack add-on dependencies at the current release

Scaffolded TanStack Start apps now install `@arkenv/core`, `@arkenv/standard`, and `@arkenv/vite-plugin` at `^1.0.0-rc.2`, which matches the versions on npm `latest` and still accepts `1.0.0` when it publishes.

Usage:

```bash
npx @tanstack/cli create my-app --add-ons https://arkenv.js.org/tanstack/info.json
```
5 changes: 5 additions & 0 deletions apps/www/content/docs/frameworks/tanstack-start.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ Generate a TanStack Start app with ArkEnv wired in:
npx @tanstack/cli create my-app --add-ons https://arkenv.js.org/tanstack/info.json
```

<Callout type="info" title="No catalog id yet">
`@tanstack/cli` does not include an `arkenv` add-on, so
`--add-ons arkenv` fails. Use the URL above.
</Callout>

When the CLI runs, it asks a few setup questions — including which
validator engine to use (ArkType, Zod, or Valibot) and whether to
include the `/demo/arkenv` route. You can accept the defaults or pick
Expand Down
4 changes: 2 additions & 2 deletions apps/www/public/tanstack/add-on.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "arkenv",
"name": "ArkEnv",
"version": "1.0.0-alpha.1",
"version": "1.0.0-rc.2",
"description": "Typesafe environment variable validation with build-time validation and runtime leak protection.",
"type": "add-on",
"phase": "add-on",
Expand Down Expand Up @@ -61,7 +61,7 @@
"code": "arkenv()"
}
],
"packageTemplate": "<%\n const arkenvOption = (typeof addOnOption !== 'undefined' && (\n addOnOption['arkenv'] ||\n Object.entries(addOnOption).find(([k]) => k.includes('arkenv') || k.includes('info.json'))?.[1]\n )) || {};\n const validator = arkenvOption.validator || 'arktype';\n-%>\n{\n \"dependencies\": {\n<% if (validator === 'zod') { -%>\n \"@arkenv/standard\": \"^1.0.0-alpha.1\",\n \"zod\": \"^3.24.2\"\n<% } else if (validator === 'valibot') { -%>\n \"@arkenv/standard\": \"^1.0.0-alpha.1\",\n \"valibot\": \"^1.0.0\"\n<% } else { -%>\n \"@arkenv/core\": \"^1.0.0-alpha.1\",\n \"arktype\": \"^2.2.0\"\n<% } -%>\n },\n \"devDependencies\": {\n \"@arkenv/vite-plugin\": \"^1.0.0-alpha.1\"\n }\n}\n",
"packageTemplate": "<%\n const arkenvOption = (typeof addOnOption !== 'undefined' && (\n addOnOption['arkenv'] ||\n Object.entries(addOnOption).find(([k]) => k.includes('arkenv') || k.includes('info.json'))?.[1]\n )) || {};\n const validator = arkenvOption.validator || 'arktype';\n-%>\n{\n \"dependencies\": {\n<% if (validator === 'zod') { -%>\n \"@arkenv/standard\": \"^1.0.0-rc.2\",\n \"zod\": \"^3.24.2\"\n<% } else if (validator === 'valibot') { -%>\n \"@arkenv/standard\": \"^1.0.0-rc.2\",\n \"valibot\": \"^1.0.0\"\n<% } else { -%>\n \"@arkenv/core\": \"^1.0.0-rc.2\",\n \"arktype\": \"^2.2.0\"\n<% } -%>\n },\n \"devDependencies\": {\n \"@arkenv/vite-plugin\": \"^1.0.0-rc.2\"\n }\n}\n",
"files": {
"_dot_env.example": "# Port for the dev/preview server\nPORT=3000\n\n# Public API URL (inlined into client bundle)\nVITE_API_URL=https://api.example.com\n\n# Server-only database connection URL (protected from client access)\nDATABASE_URL=postgresql://postgres:postgres@localhost:5432/db\n\n# Environment mode\nNODE_ENV=development\n",
"src/env.ts.ejs": "<%\n const arkenvOption = (typeof addOnOption !== 'undefined' && (\n addOnOption['arkenv'] ||\n Object.entries(addOnOption).find(([k]) => k.includes('arkenv') || k.includes('info.json'))?.[1]\n )) || {};\n const validator = arkenvOption.validator || 'arktype';\n-%>\n<% if (validator === 'zod') { -%>\nimport arkenv from \"@arkenv/standard\";\nimport { z } from \"zod\";\n\nexport const env = arkenv({\n PORT: z.coerce.number().int().min(1).max(65535).default(3000),\n VITE_API_URL: z.string().url().default(\"https://api.example.com\"),\n DATABASE_URL: z.string().url().default(\"postgresql://postgres:postgres@localhost:5432/db\"),\n NODE_ENV: z.enum([\"development\", \"production\", \"test\"]).default(\"development\"),\n});\n<% } else if (validator === 'valibot') { -%>\nimport arkenv from \"@arkenv/standard\";\nimport * as v from \"valibot\";\n\nexport const env = arkenv({\n PORT: v.optional(v.pipe(v.unknown(), v.transform(Number), v.integer()), 3000),\n VITE_API_URL: v.optional(v.pipe(v.string(), v.url()), \"https://api.example.com\"),\n DATABASE_URL: v.optional(v.pipe(v.string(), v.url()), \"postgresql://postgres:postgres@localhost:5432/db\"),\n NODE_ENV: v.optional(v.picklist([\"development\", \"production\", \"test\"]), \"development\"),\n});\n<% } else { -%>\nimport arkenv from \"@arkenv/core\";\n\nexport const env = arkenv({\n PORT: \"number.port = 3000\",\n VITE_API_URL: \"string = 'https://api.example.com'\",\n DATABASE_URL: \"string = 'postgresql://postgres:postgres@localhost:5432/db'\",\n NODE_ENV: \"'development' | 'production' | 'test' = 'development'\",\n});\n<% } -%>\n",
Expand Down
4 changes: 2 additions & 2 deletions apps/www/public/tanstack/info.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "arkenv",
"name": "ArkEnv",
"version": "1.0.0-alpha.1",
"version": "1.0.0-rc.2",
"description": "Typesafe environment variable validation with build-time validation and runtime leak protection.",
"type": "add-on",
"phase": "add-on",
Expand Down Expand Up @@ -61,7 +61,7 @@
"code": "arkenv()"
}
],
"packageTemplate": "<%\n const arkenvOption = (typeof addOnOption !== 'undefined' && (\n addOnOption['arkenv'] ||\n Object.entries(addOnOption).find(([k]) => k.includes('arkenv') || k.includes('info.json'))?.[1]\n )) || {};\n const validator = arkenvOption.validator || 'arktype';\n-%>\n{\n \"dependencies\": {\n<% if (validator === 'zod') { -%>\n \"@arkenv/standard\": \"^1.0.0-alpha.1\",\n \"zod\": \"^3.24.2\"\n<% } else if (validator === 'valibot') { -%>\n \"@arkenv/standard\": \"^1.0.0-alpha.1\",\n \"valibot\": \"^1.0.0\"\n<% } else { -%>\n \"@arkenv/core\": \"^1.0.0-alpha.1\",\n \"arktype\": \"^2.2.0\"\n<% } -%>\n },\n \"devDependencies\": {\n \"@arkenv/vite-plugin\": \"^1.0.0-alpha.1\"\n }\n}\n",
"packageTemplate": "<%\n const arkenvOption = (typeof addOnOption !== 'undefined' && (\n addOnOption['arkenv'] ||\n Object.entries(addOnOption).find(([k]) => k.includes('arkenv') || k.includes('info.json'))?.[1]\n )) || {};\n const validator = arkenvOption.validator || 'arktype';\n-%>\n{\n \"dependencies\": {\n<% if (validator === 'zod') { -%>\n \"@arkenv/standard\": \"^1.0.0-rc.2\",\n \"zod\": \"^3.24.2\"\n<% } else if (validator === 'valibot') { -%>\n \"@arkenv/standard\": \"^1.0.0-rc.2\",\n \"valibot\": \"^1.0.0\"\n<% } else { -%>\n \"@arkenv/core\": \"^1.0.0-rc.2\",\n \"arktype\": \"^2.2.0\"\n<% } -%>\n },\n \"devDependencies\": {\n \"@arkenv/vite-plugin\": \"^1.0.0-rc.2\"\n }\n}\n",
"files": {
"_dot_env.example": "# Port for the dev/preview server\nPORT=3000\n\n# Public API URL (inlined into client bundle)\nVITE_API_URL=https://api.example.com\n\n# Server-only database connection URL (protected from client access)\nDATABASE_URL=postgresql://postgres:postgres@localhost:5432/db\n\n# Environment mode\nNODE_ENV=development\n",
"src/env.ts.ejs": "<%\n const arkenvOption = (typeof addOnOption !== 'undefined' && (\n addOnOption['arkenv'] ||\n Object.entries(addOnOption).find(([k]) => k.includes('arkenv') || k.includes('info.json'))?.[1]\n )) || {};\n const validator = arkenvOption.validator || 'arktype';\n-%>\n<% if (validator === 'zod') { -%>\nimport arkenv from \"@arkenv/standard\";\nimport { z } from \"zod\";\n\nexport const env = arkenv({\n PORT: z.coerce.number().int().min(1).max(65535).default(3000),\n VITE_API_URL: z.string().url().default(\"https://api.example.com\"),\n DATABASE_URL: z.string().url().default(\"postgresql://postgres:postgres@localhost:5432/db\"),\n NODE_ENV: z.enum([\"development\", \"production\", \"test\"]).default(\"development\"),\n});\n<% } else if (validator === 'valibot') { -%>\nimport arkenv from \"@arkenv/standard\";\nimport * as v from \"valibot\";\n\nexport const env = arkenv({\n PORT: v.optional(v.pipe(v.unknown(), v.transform(Number), v.integer()), 3000),\n VITE_API_URL: v.optional(v.pipe(v.string(), v.url()), \"https://api.example.com\"),\n DATABASE_URL: v.optional(v.pipe(v.string(), v.url()), \"postgresql://postgres:postgres@localhost:5432/db\"),\n NODE_ENV: v.optional(v.picklist([\"development\", \"production\", \"test\"]), \"development\"),\n});\n<% } else { -%>\nimport arkenv from \"@arkenv/core\";\n\nexport const env = arkenv({\n PORT: \"number.port = 3000\",\n VITE_API_URL: \"string = 'https://api.example.com'\",\n DATABASE_URL: \"string = 'postgresql://postgres:postgres@localhost:5432/db'\",\n NODE_ENV: \"'development' | 'production' | 'test' = 'development'\",\n});\n<% } -%>\n",
Expand Down
8 changes: 4 additions & 4 deletions apps/www/public/tanstack/package.json.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@
{
"dependencies": {
<% if (validator === 'zod') { -%>
"@arkenv/standard": "^1.0.0-alpha.1",
"@arkenv/standard": "^1.0.0-rc.2",
"zod": "^3.24.2"
<% } else if (validator === 'valibot') { -%>
"@arkenv/standard": "^1.0.0-alpha.1",
"@arkenv/standard": "^1.0.0-rc.2",
"valibot": "^1.0.0"
<% } else { -%>
"@arkenv/core": "^1.0.0-alpha.1",
"@arkenv/core": "^1.0.0-rc.2",
"arktype": "^2.2.0"
<% } -%>
},
"devDependencies": {
"@arkenv/vite-plugin": "^1.0.0-alpha.1"
"@arkenv/vite-plugin": "^1.0.0-rc.2"
}
}
18 changes: 18 additions & 0 deletions packages/tanstack-addon/.add-on/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
## ArkEnv

Typesafe environment variables for TanStack Start. The add-on installs
`@arkenv/vite-plugin`, writes `src/env.ts`, and can add a `/demo/arkenv`
route that shows server-only keys staying on the server.

Pick a validator when you scaffold: ArkType (`@arkenv/core`), Zod, or
Valibot (`@arkenv/standard`).

### Usage

```ts
import { env } from "#/env";

console.log(env.VITE_API_URL);
```

Docs: [https://arkenv.js.org/docs/frameworks/tanstack-start](https://arkenv.js.org/docs/frameworks/tanstack-start)
2 changes: 1 addition & 1 deletion packages/tanstack-addon/.add-on/info.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "arkenv",
"name": "ArkEnv",
"version": "1.0.0-alpha.1",
"version": "1.0.0-rc.2",
"description": "Typesafe environment variable validation with build-time validation and runtime leak protection.",
"type": "add-on",
"phase": "add-on",
Expand Down
8 changes: 4 additions & 4 deletions packages/tanstack-addon/.add-on/package.json.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@
{
"dependencies": {
<% if (validator === 'zod') { -%>
"@arkenv/standard": "^1.0.0-alpha.1",
"@arkenv/standard": "^1.0.0-rc.2",
"zod": "^3.24.2"
<% } else if (validator === 'valibot') { -%>
"@arkenv/standard": "^1.0.0-alpha.1",
"@arkenv/standard": "^1.0.0-rc.2",
"valibot": "^1.0.0"
<% } else { -%>
"@arkenv/core": "^1.0.0-alpha.1",
"@arkenv/core": "^1.0.0-rc.2",
"arktype": "^2.2.0"
<% } -%>
},
"devDependencies": {
"@arkenv/vite-plugin": "^1.0.0-alpha.1"
"@arkenv/vite-plugin": "^1.0.0-rc.2"
}
}
2 changes: 2 additions & 0 deletions packages/tanstack-addon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Create a new TanStack Start app with ArkEnv pre-configured:
tanstack create my-app --add-ons https://arkenv.js.org/tanstack/info.json
```

`@tanstack/cli` does not include an `arkenv` add-on yet, so `--add-ons arkenv` fails.

Or add to an existing project:

```bash
Expand Down
17 changes: 11 additions & 6 deletions packages/tanstack-addon/tests/templates.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ const demoRouteTemplate = readFileSync(
"utf-8",
);

/** Range emitted for `@arkenv/core`, `@arkenv/standard`, and `@arkenv/vite-plugin`. */
const ARKENV_RANGE = "^1.0.0-rc.2";

describe("Template Rendering", () => {
describe("src/env.ts.ejs", () => {
it("renders ArkType syntax by default when no options provided", () => {
Expand Down Expand Up @@ -96,7 +99,8 @@ describe("Template Rendering", () => {
expect(parsed.dependencies["@arkenv/core"]).toBeDefined();
expect(parsed.dependencies.arktype).toBeDefined();
expect(parsed.dependencies["@arkenv/standard"]).toBeUndefined();
expect(parsed.devDependencies["@arkenv/vite-plugin"]).toBeDefined();
expect(parsed.devDependencies["@arkenv/vite-plugin"]).toBe(ARKENV_RANGE);
expect(parsed.dependencies["@arkenv/core"]).toBe(ARKENV_RANGE);
});

it("renders valid JSON with Zod dependencies", () => {
Expand All @@ -105,10 +109,10 @@ describe("Template Rendering", () => {
});
const parsed = JSON.parse(rendered);

expect(parsed.dependencies["@arkenv/standard"]).toBeDefined();
expect(parsed.dependencies["@arkenv/standard"]).toBe(ARKENV_RANGE);
expect(parsed.dependencies.zod).toBeDefined();
expect(parsed.dependencies["@arkenv/core"]).toBeUndefined();
expect(parsed.devDependencies["@arkenv/vite-plugin"]).toBeDefined();
expect(parsed.devDependencies["@arkenv/vite-plugin"]).toBe(ARKENV_RANGE);
});

it("renders valid JSON with Valibot dependencies", () => {
Expand All @@ -117,10 +121,10 @@ describe("Template Rendering", () => {
});
const parsed = JSON.parse(rendered);

expect(parsed.dependencies["@arkenv/standard"]).toBeDefined();
expect(parsed.dependencies["@arkenv/standard"]).toBe(ARKENV_RANGE);
expect(parsed.dependencies.valibot).toBeDefined();
expect(parsed.dependencies["@arkenv/core"]).toBeUndefined();
expect(parsed.devDependencies["@arkenv/vite-plugin"]).toBeDefined();
expect(parsed.devDependencies["@arkenv/vite-plugin"]).toBe(ARKENV_RANGE);
});

it("renders valid JSON when keyed by remote URL ID", () => {
Expand All @@ -131,8 +135,9 @@ describe("Template Rendering", () => {
});
const parsed = JSON.parse(rendered);

expect(parsed.dependencies["@arkenv/standard"]).toBeDefined();
expect(parsed.dependencies["@arkenv/standard"]).toBe(ARKENV_RANGE);
expect(parsed.dependencies.zod).toBeDefined();
expect(parsed.devDependencies["@arkenv/vite-plugin"]).toBe(ARKENV_RANGE);
});
});

Expand Down
Loading