release: WRNexusJS 0.8.0
This commit is contained in:
+178
-12
@@ -30,6 +30,7 @@ coverage/
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.*.example
|
||||
|
||||
# Logs and runtime files
|
||||
*.log
|
||||
@@ -43,6 +44,7 @@ logs/
|
||||
*.db-wal
|
||||
*.sqlite
|
||||
*.sqlite3
|
||||
uploads/
|
||||
|
||||
# Generated native projects
|
||||
mobile/android/
|
||||
@@ -77,20 +79,41 @@ Thumbs.db
|
||||
"build": "wrnexus build .",
|
||||
"start": "bun dist/server.js",
|
||||
"production": "bun run build && bun run start",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "wrnexus test .",
|
||||
"test:watch": "wrnexus test . --watch",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix",
|
||||
"format": "prettier . --write",
|
||||
"format:check": "prettier . --check",
|
||||
"check": "bun run lint && bun run format:check"
|
||||
"doctor": "wrnexus doctor .",
|
||||
"analyze": "wrnexus analyze .",
|
||||
"inspect": "wrnexus inspect packages .",
|
||||
"check": "bun run typecheck && bun run lint && bun run test && bun run format:check"
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/ai": "${frameworkVersion}",
|
||||
"@wrnexus/auth": "${frameworkVersion}",
|
||||
"@wrnexus/captcha": "${frameworkVersion}",
|
||||
"@wrnexus/core": "${frameworkVersion}",
|
||||
"@wrnexus/csr": "${frameworkVersion}",
|
||||
"@wrnexus/db": "${frameworkVersion}",
|
||||
"@wrnexus/dev-server": "${frameworkVersion}",
|
||||
"@wrnexus/encryption": "${frameworkVersion}",
|
||||
"@wrnexus/helpers": "${frameworkVersion}",
|
||||
"@wrnexus/i18n": "${frameworkVersion}",
|
||||
"@wrnexus/image": "${frameworkVersion}",
|
||||
"@wrnexus/jwt": "${frameworkVersion}",
|
||||
"@wrnexus/observability": "${frameworkVersion}",
|
||||
"@wrnexus/realtime": "${frameworkVersion}",
|
||||
"@wrnexus/security": "${frameworkVersion}",
|
||||
"@wrnexus/store": "${frameworkVersion}",
|
||||
"@wrnexus/styles": "${frameworkVersion}",
|
||||
"@wrnexus/tracking": "${frameworkVersion}",
|
||||
"@wrnexus/ui": "${frameworkVersion}",
|
||||
"@wrnexus/uploader": "${frameworkVersion}",
|
||||
"@wrnexus/validation": "${frameworkVersion}",
|
||||
"@wrnexus/db": "${frameworkVersion}"
|
||||
"@wrnexus/authz": "${frameworkVersion}"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@wrnexus/cli": "${frameworkVersion}",
|
||||
@@ -124,9 +147,22 @@ Thumbs.db
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "@wrnexus/core"
|
||||
},
|
||||
"include": ["app", "wrnexus.config.ts"],
|
||||
"include": ["app", "test", "wrnexus.config.ts"],
|
||||
"exclude": ["node_modules", "dist", "**/dist", "**/.wrnexus"]
|
||||
}
|
||||
`,
|
||||
".env.example": `# Copy to .env for local development. Never commit real secrets.
|
||||
WRNEXUS_PUBLIC_ORIGIN=http://localhost:3000
|
||||
DATABASE_URL=file:./dev.db
|
||||
REDIS_URL=redis://localhost:6379
|
||||
AUTH_SECRET=replace-with-at-least-32-random-characters
|
||||
ENCRYPTION_KEY=replace-with-a-base64-encoded-32-byte-key
|
||||
ANTHROPIC_API_KEY=
|
||||
OTEL_EXPORTER_OTLP_ENDPOINT=
|
||||
`,
|
||||
".env.test.example": `WRNEXUS_PUBLIC_ORIGIN=http://localhost:3000
|
||||
DATABASE_URL=file:./test.db
|
||||
AUTH_SECRET=test-only-secret-replace-outside-tests
|
||||
`,
|
||||
"eslint.config.js": `import { dirname } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
@@ -220,6 +256,56 @@ trim_trailing_whitespace = true
|
||||
"wrnexus.config.ts": `import type { AppConfig } from "@wrnexus/styles";
|
||||
|
||||
const config: AppConfig = {
|
||||
compatibilityDate: "2026-08-02",
|
||||
frameworkBehaviour: 1,
|
||||
// v0.8 defaults: explicit imports, strict template types, safe stores, and
|
||||
// automatic progressive navigation. Package plugins are discovered from the
|
||||
// installed packages above; add custom plugins to this array when needed.
|
||||
plugins: [],
|
||||
imports: { mode: "explicit", autoImport: true, aliases: { "@": "./app" } },
|
||||
types: {
|
||||
strict: true,
|
||||
noImplicitAny: true,
|
||||
strictNullChecks: true,
|
||||
checkTemplates: true,
|
||||
checkComponentProps: true,
|
||||
generateDeclarations: true,
|
||||
},
|
||||
functions: { legacyDefaultRuntime: "current" },
|
||||
stores: { strictMutations: true, persistence: true },
|
||||
compatibility: {
|
||||
legacyEmit: false,
|
||||
legacyEventProps: false,
|
||||
legacyComponentDiscovery: false,
|
||||
stringLayouts: false,
|
||||
},
|
||||
experimental: {},
|
||||
|
||||
performance: {
|
||||
enforcement: "warn",
|
||||
analyze: true,
|
||||
budgets: {
|
||||
routeJsBytes: 50 * 1024,
|
||||
routeCssBytes: 25 * 1024,
|
||||
lcpMs: 2_500,
|
||||
inpMs: 200,
|
||||
cls: 0.1,
|
||||
},
|
||||
},
|
||||
observability: {
|
||||
enabled: true,
|
||||
serviceName: "APP_SLUG",
|
||||
serverTiming: true,
|
||||
sampleRate: 1,
|
||||
exporter: process.env.OTEL_EXPORTER_OTLP_ENDPOINT ? "otlp" : "none",
|
||||
endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
|
||||
webVitals: true,
|
||||
},
|
||||
tenancy: { mode: "domain", required: false, rootDomains: ["localhost"] },
|
||||
build: { cache: true, sourceMaps: true, report: true, adapter: "bun" },
|
||||
navigation: { mode: "auto" },
|
||||
devToolbar: { enabled: true, position: "bottom-center", openEditor: true },
|
||||
|
||||
mobile: {
|
||||
enabled: true,
|
||||
appId: "com.example.APP_SLUG",
|
||||
@@ -272,18 +358,77 @@ const config: AppConfig = {
|
||||
// // Or self-host (fastest, no third party) — drop files in public/fonts/:
|
||||
// // local: [{ family: "Inter", src: "/fonts/inter.woff2", weight: "100 900", preload: true }],
|
||||
|
||||
// security: {
|
||||
// cors: {
|
||||
// enabled: true,
|
||||
// origin: ["http://localhost:5173"],
|
||||
// },
|
||||
// },
|
||||
theme: { palette: "violet", default: "light" },
|
||||
i18n: { default: "en", locales: ["en"] },
|
||||
db: { driver: "sqlite", url: process.env.DATABASE_URL ?? "file:./dev.db" },
|
||||
databases: {},
|
||||
storage: {
|
||||
default: "public",
|
||||
stores: {
|
||||
public: {
|
||||
driver: "local",
|
||||
access: "public",
|
||||
dir: "uploads/public",
|
||||
maxBytes: 10_000_000,
|
||||
accept: ["image/*", "application/pdf"],
|
||||
},
|
||||
private: {
|
||||
driver: "local",
|
||||
access: "private",
|
||||
dir: "uploads/private",
|
||||
maxBytes: 10_000_000,
|
||||
},
|
||||
},
|
||||
},
|
||||
realtime: { scale: Boolean(process.env.REDIS_URL), redisUrl: process.env.REDIS_URL },
|
||||
port: Number(process.env.PORT ?? 3000),
|
||||
security: {
|
||||
cors: { enabled: false },
|
||||
},
|
||||
profiles: {
|
||||
development: {},
|
||||
test: {
|
||||
db: { driver: "sqlite", url: "file:./test.db" },
|
||||
observability: { exporter: "none", sampleRate: 0 },
|
||||
},
|
||||
staging: {
|
||||
seo: { robots: "noindex,nofollow" },
|
||||
performance: { enforcement: "error" },
|
||||
build: { sourceMaps: true, report: true },
|
||||
},
|
||||
production: {
|
||||
seo: { canonicalBase: process.env.WRNEXUS_PUBLIC_ORIGIN },
|
||||
performance: { enforcement: "error" },
|
||||
build: { sourceMaps: false, report: true },
|
||||
devToolbar: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
`,
|
||||
"public/robots.txt": `User-agent: *
|
||||
Allow: /
|
||||
`,
|
||||
"app/locales/en.json": `{
|
||||
"common": {
|
||||
"appName": "APP_NAME",
|
||||
"welcome": "Welcome to APP_NAME"
|
||||
}
|
||||
}
|
||||
`,
|
||||
"app/db/migrations/0001_init.sql": `-- Create application tables here.
|
||||
-- Run with: bunx wrnexus db migrate
|
||||
`,
|
||||
"app/db/seed.ts": `// Add deterministic development seed data here.
|
||||
export async function seed(): Promise<void> {}
|
||||
`,
|
||||
"app/schemas/contact.ts": `import { v } from "@wrnexus/validation";
|
||||
|
||||
export const contactSchema = v.object({
|
||||
email: v.string().email(),
|
||||
message: v.string().min(10).max(2_000),
|
||||
});
|
||||
`,
|
||||
"app/styles/global.css": `/*
|
||||
* Global stylesheet. Tailwind v4 is compiled by the styles.process hook in
|
||||
@@ -441,10 +586,11 @@ component Counter {
|
||||
"app/api/ai.ts": `// POST /api/ai { "prompt": "..." } → Claude's reply.
|
||||
// Set ANTHROPIC_API_KEY in your environment (e.g. a .env file) to enable this.
|
||||
import { createAI } from "@wrnexus/ai";
|
||||
import type { Context } from "@wrnexus/core";
|
||||
|
||||
const ai = createAI(); // reads ANTHROPIC_API_KEY; defaults to claude-opus-4-8
|
||||
|
||||
export const POST = async (ctx) => {
|
||||
export const POST = async (ctx: Context) => {
|
||||
if (!process.env.ANTHROPIC_API_KEY) {
|
||||
return Response.json({ error: "Set ANTHROPIC_API_KEY to use AI." }, { status: 501 });
|
||||
}
|
||||
@@ -455,10 +601,14 @@ export const POST = async (ctx) => {
|
||||
return ai.streamResponse(prompt);
|
||||
};
|
||||
`,
|
||||
"app/middleware/logger.ts": `export default async function logger(ctx, next) {
|
||||
"app/middleware/logger.ts": `import type { Middleware } from "@wrnexus/core";
|
||||
|
||||
const logger: Middleware = async (ctx, next) => {
|
||||
console.log(ctx.req.method, ctx.url.pathname);
|
||||
return next();
|
||||
}
|
||||
};
|
||||
|
||||
export default logger;
|
||||
`,
|
||||
"app/realtime/chat.ts": `// ws://<host>/realtime/chat — a simple broadcast room.
|
||||
//
|
||||
@@ -480,6 +630,22 @@ export default defineRoom({
|
||||
client.room.broadcast({ type: "message", data: msg });
|
||||
},
|
||||
});
|
||||
`,
|
||||
"test/smoke.test.ts": `import { expect, test } from "bun:test";
|
||||
import { parseOrThrow } from "@wrnexus/validation";
|
||||
import { contactSchema } from "../app/schemas/contact.ts";
|
||||
|
||||
test("starter validation schema accepts a contact request", () => {
|
||||
expect(
|
||||
parseOrThrow(contactSchema, {
|
||||
email: "hello@example.com",
|
||||
message: "Hello from the generated application.",
|
||||
}),
|
||||
).toEqual({
|
||||
email: "hello@example.com",
|
||||
message: "Hello from the generated application.",
|
||||
});
|
||||
});
|
||||
`,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user