fastscript 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/.github/workflows/ci.yml +17 -0
  2. package/CHANGELOG.md +5 -0
  3. package/Dockerfile +9 -0
  4. package/LICENSE +21 -0
  5. package/README.md +102 -0
  6. package/app/api/auth.js +10 -0
  7. package/app/api/hello.js +3 -0
  8. package/app/api/upload.js +9 -0
  9. package/app/api/webhook.js +10 -0
  10. package/app/db/migrations/001_init.js +6 -0
  11. package/app/db/seed.js +5 -0
  12. package/app/env.schema.js +6 -0
  13. package/app/middleware.fs +7 -0
  14. package/app/pages/404.fs +3 -0
  15. package/app/pages/_layout.fs +17 -0
  16. package/app/pages/benchmarks.fs +15 -0
  17. package/app/pages/docs/index.fs +16 -0
  18. package/app/pages/index.fs +22 -0
  19. package/app/pages/private.fs +12 -0
  20. package/app/pages/showcase.fs +14 -0
  21. package/app/styles.css +14 -0
  22. package/docs/AI_CONTEXT_PACK_V1.md +25 -0
  23. package/docs/DEPLOY_GUIDE.md +14 -0
  24. package/docs/INCIDENT_PLAYBOOK.md +18 -0
  25. package/docs/INTEROP_RULES.md +7 -0
  26. package/docs/PLUGIN_API_CONTRACT.md +22 -0
  27. package/ecosystem.config.cjs +1 -0
  28. package/examples/fullstack/README.md +10 -0
  29. package/examples/fullstack/app/api/orders.js +8 -0
  30. package/examples/fullstack/app/db/migrations/001_init.js +3 -0
  31. package/examples/fullstack/app/db/seed.js +3 -0
  32. package/examples/fullstack/app/jobs/send-order-email.js +4 -0
  33. package/examples/fullstack/app/pages/_layout.fs +1 -0
  34. package/examples/fullstack/app/pages/index.fs +3 -0
  35. package/examples/startup-mvp/README.md +8 -0
  36. package/examples/startup-mvp/app/api/cart.js +9 -0
  37. package/examples/startup-mvp/app/api/checkout.js +8 -0
  38. package/examples/startup-mvp/app/db/migrations/001_products.js +6 -0
  39. package/examples/startup-mvp/app/jobs/send-receipt.js +4 -0
  40. package/examples/startup-mvp/app/pages/_layout.fs +3 -0
  41. package/examples/startup-mvp/app/pages/dashboard/index.fs +9 -0
  42. package/examples/startup-mvp/app/pages/index.fs +18 -0
  43. package/package.json +50 -0
  44. package/scripts/bench-report.mjs +36 -0
  45. package/scripts/release.mjs +21 -0
  46. package/scripts/smoke-dev.mjs +78 -0
  47. package/scripts/smoke-start.mjs +41 -0
  48. package/scripts/test-auth.mjs +26 -0
  49. package/scripts/test-db.mjs +31 -0
  50. package/scripts/test-jobs.mjs +15 -0
  51. package/scripts/test-middleware.mjs +37 -0
  52. package/scripts/test-roundtrip.mjs +44 -0
  53. package/scripts/test-validation.mjs +17 -0
  54. package/scripts/test-webhook-storage.mjs +22 -0
  55. package/spec/FASTSCRIPT_1000_BUILD_LIST.md +1090 -0
  56. package/src/auth-flows.mjs +29 -0
  57. package/src/auth.mjs +115 -0
  58. package/src/bench.mjs +46 -0
  59. package/src/build.mjs +222 -0
  60. package/src/cache.mjs +58 -0
  61. package/src/check.mjs +22 -0
  62. package/src/cli.mjs +71 -0
  63. package/src/compat.mjs +122 -0
  64. package/src/create.mjs +190 -0
  65. package/src/db-cli.mjs +45 -0
  66. package/src/db-postgres.mjs +40 -0
  67. package/src/db.mjs +103 -0
  68. package/src/deploy.mjs +65 -0
  69. package/src/dev.mjs +5 -0
  70. package/src/env.mjs +89 -0
  71. package/src/export.mjs +83 -0
  72. package/src/fs-normalize.mjs +100 -0
  73. package/src/interop.mjs +16 -0
  74. package/src/jobs.mjs +127 -0
  75. package/src/logger.mjs +27 -0
  76. package/src/middleware.mjs +14 -0
  77. package/src/migrate.mjs +81 -0
  78. package/src/observability.mjs +21 -0
  79. package/src/security.mjs +55 -0
  80. package/src/server-runtime.mjs +339 -0
  81. package/src/start.mjs +10 -0
  82. package/src/storage.mjs +56 -0
  83. package/src/validate.mjs +18 -0
  84. package/src/validation.mjs +79 -0
  85. package/src/webhook.mjs +71 -0
  86. package/src/worker.mjs +5 -0
  87. package/vercel.json +15 -0
  88. package/vscode/fastscript-language/README.md +12 -0
  89. package/vscode/fastscript-language/extension.js +24 -0
  90. package/vscode/fastscript-language/language-configuration.json +6 -0
  91. package/vscode/fastscript-language/lsp/server.cjs +27 -0
  92. package/vscode/fastscript-language/lsp/smoke-test.cjs +1 -0
  93. package/vscode/fastscript-language/package.json +36 -0
  94. package/vscode/fastscript-language/snippets/fastscript.code-snippets +24 -0
  95. package/vscode/fastscript-language/syntaxes/fastscript.tmLanguage.json +21 -0
  96. package/wrangler.toml +5 -0
@@ -0,0 +1,17 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ test:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+ - uses: actions/setup-node@v4
13
+ with:
14
+ node-version: 20
15
+ cache: npm
16
+ - run: npm ci
17
+ - run: npm run qa:all
package/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # Changelog
2
+
3
+ ## v0.1.0 - 2026-04-13
4
+ - FastScript JS-first full-stack core
5
+
package/Dockerfile ADDED
@@ -0,0 +1,9 @@
1
+ FROM node:20-alpine
2
+ WORKDIR /app
3
+ COPY package*.json ./
4
+ RUN npm ci --omit=dev
5
+ COPY . .
6
+ RUN npm run build
7
+ ENV NODE_ENV=production
8
+ EXPOSE 4173
9
+ CMD ["node","./src/cli.mjs","start"]
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 FastScript
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # FastScript
2
+
3
+ FastScript is a JavaScript-first full-stack framework focused on three things:
4
+
5
+ - Simpler than heavy framework stacks
6
+ - Faster build and runtime pipeline
7
+ - Compatible with existing JavaScript ecosystem
8
+ - `.fs` first, `.js` always supported
9
+
10
+ ## Commands
11
+
12
+ ```bash
13
+ npm install
14
+ npm run create
15
+ npm run dev
16
+ npm run start
17
+ npm run build
18
+ npm run check
19
+ npm run migrate
20
+ npm run bench
21
+ npm run export:js
22
+ npm run export:ts
23
+ npm run compat
24
+ npm run validate
25
+ npm run db:migrate
26
+ npm run db:seed
27
+ npm run smoke:dev
28
+ npm run smoke:start
29
+ npm run test:core
30
+ npm run bench:report
31
+ npm run qa:all
32
+ npm run worker
33
+ npm run deploy:node
34
+ npm run deploy:vercel
35
+ npm run deploy:cloudflare
36
+ npm run release:patch
37
+ npm run pack:check
38
+ ```
39
+
40
+ - `npm run migrate`: convert `app/pages` files (`.js/.jsx/.ts/.tsx`) to `.fs`
41
+ - `npm run bench`: enforce 3G-oriented gzip budgets on built output
42
+ - `npm run export:js`: export `.fs` app source to plain `.js` project
43
+ - `npm run export:ts`: export `.fs` app source to `.ts` project
44
+ - `npm run compat`: run ESM/CJS/FS interop smoke checks
45
+ - `npm run db:migrate`: run database migrations from `app/db/migrations`
46
+ - `npm run db:seed`: seed database from `app/db/seed.js`
47
+ - `npm run validate`: run full quality gate (check/build/bench/compat/db/export)
48
+ - `npm run smoke:dev`: automated SSR/API/auth/middleware smoke test
49
+ - `npm run smoke:start`: production `fastscript start` smoke test
50
+ - `npm run test:core`: middleware/auth/db/migration round-trip tests
51
+ - `npm run bench:report`: writes benchmark report to `benchmarks/latest-report.md`
52
+ - `npm run qa:all`: full quality sweep in one command
53
+ - `npm run worker`: run queue worker runtime
54
+ - `npm run deploy:*`: generate deploy adapters for node/vercel/cloudflare
55
+ - `npm run release:*`: semver bump + changelog append
56
+ - `npm run pack:check`: npm publish dry-run
57
+
58
+ ## Additional Docs
59
+
60
+ - `docs/AI_CONTEXT_PACK_V1.md`
61
+ - `docs/PLUGIN_API_CONTRACT.md`
62
+ - `docs/INCIDENT_PLAYBOOK.md`
63
+ - `docs/DEPLOY_GUIDE.md`
64
+
65
+ ## Project layout
66
+
67
+ ```txt
68
+ app/
69
+ pages/
70
+ _layout.fs
71
+ index.fs
72
+ 404.fs
73
+ api/
74
+ hello.js
75
+ auth.js
76
+ db/
77
+ migrations/
78
+ 001_init.js
79
+ seed.js
80
+ middleware.fs
81
+ styles.css
82
+ ```
83
+
84
+ ## Page contract
85
+
86
+ - `export default function Page(ctx) { return htmlString }`
87
+ - Optional `export async function load(ctx) { return data }`
88
+ - Optional method actions in page files: `POST/PUT/PATCH/DELETE`
89
+ - `.fs` supports lenient FastScript syntax such as `~state = value`
90
+ - Optional `export function hydrate({ root, ...ctx })` for client hydration
91
+
92
+ ## Routing
93
+
94
+ - `app/pages/index.fs` or `index.js` -> `/`
95
+ - `app/pages/blog/index.fs` or `index.js` -> `/blog`
96
+ - `app/pages/blog/[slug].fs` or `[slug].js` -> `/blog/:slug`
97
+ - `app/pages/404.fs` or `404.js` -> not found view
98
+ - `app/pages/_layout.fs` or `_layout.js` -> global layout wrapper
99
+
100
+ ## Why this reset
101
+
102
+ This repo was reset intentionally to rebuild from ground up around a JavaScript-first model with minimal syntax friction.
@@ -0,0 +1,10 @@
1
+ export async function POST(ctx) {
2
+ const user = { id: "u_1", name: "Dev" };
3
+ ctx.auth.login(user);
4
+ return ctx.helpers.json({ ok: true, user });
5
+ }
6
+
7
+ export async function DELETE(ctx) {
8
+ ctx.auth.logout();
9
+ return ctx.helpers.json({ ok: true });
10
+ }
@@ -0,0 +1,3 @@
1
+ export async function GET() {
2
+ return { status: 200, json: { ok: true, message: "Hello from FastScript API" } };
3
+ }
@@ -0,0 +1,9 @@
1
+ export const schemas = {
2
+ POST: { key: "string", content: "string" }
3
+ };
4
+
5
+ export async function POST(ctx) {
6
+ const body = await ctx.input.validateBody(schemas.POST);
7
+ const put = ctx.storage.put(body.key, Buffer.from(body.content, "utf8"));
8
+ return ctx.helpers.json({ ok: true, ...put, url: ctx.storage.url(body.key) });
9
+ }
@@ -0,0 +1,10 @@
1
+ import { verifyWebhookRequest } from "../../src/webhook.mjs";
2
+
3
+ export async function POST(ctx) {
4
+ const result = await verifyWebhookRequest(ctx.req, {
5
+ secret: process.env.WEBHOOK_SECRET || "dev-secret",
6
+ replayDir: ".fastscript"
7
+ });
8
+ if (!result.ok) return ctx.helpers.json({ ok: false, reason: result.reason }, 401);
9
+ return ctx.helpers.json({ ok: true });
10
+ }
@@ -0,0 +1,6 @@
1
+ export async function up(db) {
2
+ const users = db.collection("users");
3
+ if (!users.get("u_1")) {
4
+ users.set("u_1", { id: "u_1", name: "Dev" });
5
+ }
6
+ }
package/app/db/seed.js ADDED
@@ -0,0 +1,5 @@
1
+ export async function seed(db) {
2
+ db.transaction((tx) => {
3
+ tx.collection("posts").set("hello", { id: "hello", title: "First Post", published: true });
4
+ });
5
+ }
@@ -0,0 +1,6 @@
1
+ export const schema = {
2
+ SESSION_SECRET: "string?",
3
+ DATABASE_URL: "string?",
4
+ REDIS_URL: "string?",
5
+ NODE_ENV: "string?",
6
+ };
@@ -0,0 +1,7 @@
1
+ export async function middleware(ctx, next) {
2
+ const protectedRoute = ctx.pathname.startsWith("/private");
3
+ if (protectedRoute && !ctx.user) {
4
+ return ctx.helpers.redirect("/");
5
+ }
6
+ return next();
7
+ }
@@ -0,0 +1,3 @@
1
+ export default function NotFound() {
2
+ return `<section><h1>404</h1><p>Page not found.</p></section>`;
3
+ }
@@ -0,0 +1,17 @@
1
+ export default function Layout({ content, pathname, user }) {
2
+ return `
3
+ <header class="nav">
4
+ <a href="/">FastScript</a>
5
+ <nav>
6
+ <a href="/">Home</a>
7
+ <a href="/docs">Docs</a>
8
+ <a href="/benchmarks">Benchmarks</a>
9
+ <a href="/showcase">Showcase</a>
10
+ <a href="/private">Private</a>
11
+ </nav>
12
+ <small>${user ? "Signed in" : "Guest"}</small>
13
+ </header>
14
+ <main class="page">${content}</main>
15
+ <footer class="footer">Built with FastScript • JS-first • .fs-native</footer>
16
+ `;
17
+ }
@@ -0,0 +1,15 @@
1
+ export default function Benchmarks() {
2
+ return `
3
+ <section>
4
+ <p class="eyebrow">Benchmarks</p>
5
+ <h1>Real budgets for 3G-first apps</h1>
6
+ <div class="grid">
7
+ <article><h3>JS first load</h3><p><strong>1.43KB</strong> gzip (budget 30KB)</p></article>
8
+ <article><h3>CSS first load</h3><p><strong>0.38KB</strong> gzip (budget 10KB)</p></article>
9
+ <article><h3>Build speed</h3><p>Sub-second warm build target</p></article>
10
+ <article><h3>Quality</h3><p>validate + smoke + tests</p></article>
11
+ </div>
12
+ <p>Report generated by <code>npm run bench:report</code>.</p>
13
+ </section>
14
+ `;
15
+ }
@@ -0,0 +1,16 @@
1
+ export default function DocsIndex() {
2
+ return `
3
+ <section>
4
+ <p class="eyebrow">Docs</p>
5
+ <h1>FastScript Documentation</h1>
6
+ <ul>
7
+ <li><code>pages/</code> for file-based routing</li>
8
+ <li><code>api/</code> for server endpoints</li>
9
+ <li><code>middleware.fs</code> for guards/security</li>
10
+ <li><code>db/</code> for migrations and seeds</li>
11
+ <li><code>jobs/</code> for worker handlers</li>
12
+ </ul>
13
+ <p>Quality gate: <code>npm run qa:all</code></p>
14
+ </section>
15
+ `;
16
+ }
@@ -0,0 +1,22 @@
1
+ export default function Home() {
2
+ return `
3
+ <section class="hero">
4
+ <p class="eyebrow">FastScript v0.1</p>
5
+ <h1>Full-stack speed with readable .fs syntax.</h1>
6
+ <p>SSR, API routes, auth, DB, jobs, storage, and deploy adapters in one stack.</p>
7
+ <div class="hero-links">
8
+ <a href="/docs">Read docs</a>
9
+ <a href="/benchmarks">See benchmarks</a>
10
+ <a href="/showcase">View showcase</a>
11
+ </div>
12
+ </section>
13
+ `;
14
+ }
15
+
16
+ export function hydrate({ root }) {
17
+ for (const a of root.querySelectorAll('.hero-links a')) {
18
+ a.style.transition = 'opacity .2s ease';
19
+ a.addEventListener('mouseenter', () => (a.style.opacity = '0.8'));
20
+ a.addEventListener('mouseleave', () => (a.style.opacity = '1'));
21
+ }
22
+ }
@@ -0,0 +1,12 @@
1
+ export default function PrivatePage({ user }) {
2
+ return `<section><h1>Private</h1><p>Hello ${user?.name ?? "anonymous"}</p></section>`;
3
+ }
4
+
5
+ export async function GET(ctx) {
6
+ try {
7
+ const user = ctx.auth.requireUser();
8
+ return ctx.helpers.json({ ok: true, user });
9
+ } catch {
10
+ return ctx.helpers.redirect("/");
11
+ }
12
+ }
@@ -0,0 +1,14 @@
1
+ export default function Showcase() {
2
+ return `
3
+ <section>
4
+ <p class="eyebrow">Showcase</p>
5
+ <h1>What you can build with FastScript</h1>
6
+ <div class="grid">
7
+ <article><h3>Starter app</h3><p>SSR + hydration + actions.</p></article>
8
+ <article><h3>Commerce API</h3><p>Orders endpoint + queue job email.</p></article>
9
+ <article><h3>Secure webhook</h3><p>Signature verify + replay protection.</p></article>
10
+ <article><h3>Portable exports</h3><p>.fs -> .js/.ts with one command.</p></article>
11
+ </div>
12
+ </section>
13
+ `;
14
+ }
package/app/styles.css ADDED
@@ -0,0 +1,14 @@
1
+ :root { color-scheme: dark; }
2
+ * { box-sizing: border-box; }
3
+ body { margin: 0; font: 16px/1.7 ui-sans-serif, system-ui; background: #050505; color: #fff; }
4
+ .nav { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 14px 24px; border-bottom: 1px solid #1f1f1f; position: sticky; top: 0; background: rgba(5,5,5,.9); backdrop-filter: blur(6px); }
5
+ .nav nav a { color: #d3d3ff; text-decoration: none; margin-right: 12px; }
6
+ .page { max-width: 1080px; margin: 0 auto; padding: 44px 24px; }
7
+ .hero h1, h1 { font-size: clamp(2rem, 5vw, 3.6rem); line-height: 1.07; margin: 0 0 12px; }
8
+ .eyebrow { color: #9f92ff; font-size: 12px; text-transform: uppercase; letter-spacing: .12em; }
9
+ .hero-links { display: flex; gap: 12px; margin-top: 16px; }
10
+ .hero-links a { color: #fff; border: 1px solid #353535; padding: 8px 12px; border-radius: 10px; text-decoration: none; }
11
+ .grid { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 14px; }
12
+ .grid article { border: 1px solid #202020; border-radius: 12px; padding: 14px; background: #090909; }
13
+ .footer { border-top: 1px solid #1f1f1f; padding: 24px; color: #8a8a8a; }
14
+ @media (max-width: 800px) { .grid { grid-template-columns: 1fr; } .nav { flex-wrap: wrap; } }
@@ -0,0 +1,25 @@
1
+ # FastScript AI Context Pack v1
2
+
3
+ ## Core Contracts
4
+ - `.fs` primary, `.js` compatible.
5
+ - Route pages live in `app/pages`.
6
+ - API routes live in `app/api`.
7
+ - Optional `app/middleware.fs` for global middleware.
8
+ - Optional `load(ctx)` and HTTP methods (`GET/POST/PUT/PATCH/DELETE`).
9
+
10
+ ## Validation
11
+ - Use `ctx.input.validateBody(schema)` and `ctx.input.validateQuery(schema)`.
12
+ - Use `schemas` export in route modules to auto-enforce request shape.
13
+
14
+ ## Runtime
15
+ - SSR + hydration (`export function hydrate({ root })`).
16
+ - Queue available via `ctx.queue`.
17
+ - DB available via `ctx.db`.
18
+ - Auth available via `ctx.auth`.
19
+
20
+ ## Quality Gates
21
+ - `npm run validate`
22
+ - `npm run test:core`
23
+ - `npm run smoke:dev`
24
+ - `npm run smoke:start`
25
+ - `npm run qa:all`
@@ -0,0 +1,14 @@
1
+ # FastScript Deploy Guide
2
+
3
+ ## Node/PM2
4
+ - `npm run build`
5
+ - `npm run deploy:node`
6
+ - `pm2 start ecosystem.config.cjs`
7
+
8
+ ## Vercel
9
+ - `npm run deploy:vercel`
10
+ - import project in Vercel
11
+
12
+ ## Cloudflare
13
+ - `npm run deploy:cloudflare`
14
+ - `wrangler deploy`
@@ -0,0 +1,18 @@
1
+ # FastScript Incident Playbook
2
+
3
+ ## Rollback
4
+ 1. Keep previous `dist/` artifact.
5
+ 2. Stop current process.
6
+ 3. Start previous artifact with `fastscript start`.
7
+
8
+ ## Session Key Rotation
9
+ 1. Set new `SESSION_SECRET`.
10
+ 2. Restart app.
11
+ 3. Existing sessions are invalidated.
12
+
13
+ ## Backup
14
+ - Back up `.fastscript/` database and job files every hour.
15
+
16
+ ## Verification
17
+ - Run `npm run smoke:start`.
18
+ - Check logs for `request_error` and high 5xx rate.
@@ -0,0 +1,7 @@
1
+ # FastScript Interop Rules
2
+
3
+ 1. Prefer ESM imports.
4
+ 2. CJS is supported via esbuild bundling.
5
+ 3. `.fs` can import `.js/.mjs/.cjs/.json`.
6
+ 4. `importAny()` handles default-only modules.
7
+ 5. Use `resolveExport(mod, ["named", "default"])` for unknown module shapes.
@@ -0,0 +1,22 @@
1
+ # FastScript Plugin API Contract
2
+
3
+ ## Hook Surface
4
+ - `middleware(ctx, next)`
5
+ - `onBuildStart(ctx)`
6
+ - `onBuildEnd(ctx)`
7
+ - `onRequestStart(ctx)`
8
+ - `onRequestEnd(ctx)`
9
+
10
+ ## Plugin Shape
11
+ ```js
12
+ export default {
13
+ name: "my-plugin",
14
+ setup(api) {
15
+ api.hooks.middleware(async (ctx, next) => next());
16
+ }
17
+ }
18
+ ```
19
+
20
+ ## Stability
21
+ - Contract version: `1`.
22
+ - Breaking changes require major version bump.
@@ -0,0 +1 @@
1
+ module.exports = { apps: [{ name: "fastscript-app", script: "node", args: "./src/cli.mjs start", env: { NODE_ENV: "production", PORT: 4173 } }] };
@@ -0,0 +1,10 @@
1
+ # FastScript Fullstack Example
2
+
3
+ Features:
4
+ - SSR pages + hydrate
5
+ - API actions with schema validation
6
+ - Middleware route guards
7
+ - Session auth
8
+ - DB migration + seed
9
+ - Queue + worker
10
+ - Webhook signature verification helper
@@ -0,0 +1,8 @@
1
+ export const schemas = { POST: { sku: "string", qty: "int" } };
2
+ export async function POST(ctx) {
3
+ const body = await ctx.input.validateBody(schemas.POST);
4
+ const order = { id: Date.now().toString(36), ...body };
5
+ ctx.db.collection("orders").set(order.id, order);
6
+ ctx.queue.enqueue("send-order-email", { orderId: order.id });
7
+ return ctx.helpers.json({ ok: true, order });
8
+ }
@@ -0,0 +1,3 @@
1
+ export async function up(db) {
2
+ db.collection("orders");
3
+ }
@@ -0,0 +1,3 @@
1
+ export async function seed(db) {
2
+ db.collection("orders").set("demo", { id: "demo", sku: "starter", qty: 1 });
3
+ }
@@ -0,0 +1,4 @@
1
+ export const name = "send-order-email";
2
+ export async function handle(payload) {
3
+ console.log("email job", payload.orderId);
4
+ }
@@ -0,0 +1 @@
1
+ export default function Layout({ content }) { return `<main>${content}</main>`; }
@@ -0,0 +1,3 @@
1
+ export default function Home() {
2
+ return `<section><h1>FastScript Fullstack</h1><p>Production-style starter.</p></section>`;
3
+ }
@@ -0,0 +1,8 @@
1
+ # Startup MVP (FastScript)
2
+
3
+ - Product catalog page
4
+ - Cart + checkout APIs
5
+ - Queue-backed receipt job
6
+ - Dashboard orders page
7
+
8
+ Use this folder as your startup baseline.
@@ -0,0 +1,9 @@
1
+ export const schemas = { POST: { productId: "string", qty: "int" } };
2
+
3
+ export async function POST(ctx) {
4
+ const body = await ctx.input.validateBody(schemas.POST);
5
+ const cart = ctx.db.collection("carts");
6
+ const id = `c_${Date.now()}`;
7
+ cart.set(id, { id, ...body });
8
+ return ctx.helpers.json({ ok: true, id });
9
+ }
@@ -0,0 +1,8 @@
1
+ export async function POST(ctx) {
2
+ const items = ctx.db.collection("carts").all();
3
+ const total = items.reduce((s, i) => s + i.qty * 10, 0);
4
+ const id = `o_${Date.now()}`;
5
+ ctx.db.collection("orders").set(id, { id, total, status: "paid" });
6
+ ctx.queue.enqueue("send-receipt", { orderId: id });
7
+ return ctx.helpers.json({ ok: true, orderId: id, total });
8
+ }
@@ -0,0 +1,6 @@
1
+ export async function up(db) {
2
+ const products = db.collection("products");
3
+ if (!products.get("p1")) products.set("p1", { id: "p1", name: "Starter Plan", price: 19 });
4
+ if (!products.get("p2")) products.set("p2", { id: "p2", name: "Growth Plan", price: 49 });
5
+ if (!products.get("p3")) products.set("p3", { id: "p3", name: "Scale Plan", price: 99 });
6
+ }
@@ -0,0 +1,4 @@
1
+ export const name = "send-receipt";
2
+ export async function handle(payload) {
3
+ console.log("send receipt", payload.orderId);
4
+ }
@@ -0,0 +1,3 @@
1
+ export default function Layout({ content }) {
2
+ return `<main style="max-width:1100px;margin:0 auto;padding:24px;font-family:ui-sans-serif,system-ui">${content}</main>`;
3
+ }
@@ -0,0 +1,9 @@
1
+ export async function load(ctx) {
2
+ const orders = ctx.db.collection("orders").all();
3
+ return { orders };
4
+ }
5
+
6
+ export default function Dashboard({ orders }) {
7
+ const rows = (orders || []).map((o) => `<li>${o.id} • ${o.total} • ${o.status}</li>`).join("");
8
+ return `<section><h1>Dashboard</h1><ul>${rows}</ul></section>`;
9
+ }
@@ -0,0 +1,18 @@
1
+ export async function load(ctx) {
2
+ const products = ctx.db.collection("products").all();
3
+ return { products };
4
+ }
5
+
6
+ export default function Home({ products }) {
7
+ const cards = (products || []).map((p) => `<article style="border:1px solid #ddd;padding:12px;border-radius:10px"><h3>${p.name}</h3><p>$${p.price}</p><button data-add="${p.id}">Add to cart</button></article>`).join("");
8
+ return `<section><h1>Startup MVP Store</h1><div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px">${cards}</div><p><a href="/dashboard">Dashboard</a></p></section>`;
9
+ }
10
+
11
+ export function hydrate({ root }) {
12
+ for (const b of root.querySelectorAll('[data-add]')) {
13
+ b.addEventListener('click', async () => {
14
+ await fetch('/api/cart', { method:'POST', headers:{'content-type':'application/json'}, body: JSON.stringify({ productId: b.getAttribute('data-add'), qty: 1 })});
15
+ alert('Added to cart');
16
+ });
17
+ }
18
+ }
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "fastscript",
3
+ "version": "0.1.0",
4
+ "description": "JavaScript-first full-stack framework that is simpler and faster.",
5
+ "type": "module",
6
+ "bin": {
7
+ "fastscript": "./src/cli.mjs"
8
+ },
9
+ "scripts": {
10
+ "dev": "node ./src/cli.mjs dev",
11
+ "start": "node ./src/cli.mjs start",
12
+ "build": "node ./src/cli.mjs build",
13
+ "create": "node ./src/cli.mjs create",
14
+ "check": "node ./src/cli.mjs check",
15
+ "migrate": "node ./src/cli.mjs migrate",
16
+ "bench": "node ./src/cli.mjs bench",
17
+ "export:js": "node ./src/cli.mjs export --to js --out exported-js-app",
18
+ "export:ts": "node ./src/cli.mjs export --to ts --out exported-ts-app",
19
+ "compat": "node ./src/cli.mjs compat",
20
+ "validate": "node ./src/cli.mjs validate",
21
+ "db:migrate": "node ./src/cli.mjs db:migrate",
22
+ "db:seed": "node ./src/cli.mjs db:seed",
23
+ "deploy:node": "node ./src/cli.mjs deploy --target node",
24
+ "deploy:vercel": "node ./src/cli.mjs deploy --target vercel",
25
+ "deploy:cloudflare": "node ./src/cli.mjs deploy --target cloudflare",
26
+ "worker": "node ./src/cli.mjs worker",
27
+ "smoke:dev": "node ./scripts/smoke-dev.mjs",
28
+ "smoke:start": "node ./scripts/smoke-start.mjs",
29
+ "test:middleware": "node ./scripts/test-middleware.mjs",
30
+ "test:auth": "node ./scripts/test-auth.mjs",
31
+ "test:db": "node ./scripts/test-db.mjs",
32
+ "test:roundtrip": "node ./scripts/test-roundtrip.mjs",
33
+ "test:validation": "node ./scripts/test-validation.mjs",
34
+ "test:webhook-storage": "node ./scripts/test-webhook-storage.mjs",
35
+ "test:jobs": "node ./scripts/test-jobs.mjs",
36
+ "bench:report": "node ./scripts/bench-report.mjs",
37
+ "test:core": "npm run test:middleware && npm run test:auth && npm run test:db && npm run test:validation && npm run test:webhook-storage && npm run test:jobs && npm run test:roundtrip",
38
+ "qa:all": "npm run validate && npm run test:core && npm run smoke:dev && npm run smoke:start && npm run bench:report",
39
+ "release:patch": "node ./scripts/release.mjs patch",
40
+ "release:minor": "node ./scripts/release.mjs minor",
41
+ "release:major": "node ./scripts/release.mjs major",
42
+ "pack:check": "npm pack --dry-run"
43
+ },
44
+ "engines": {
45
+ "node": ">=20.0.0"
46
+ },
47
+ "dependencies": {
48
+ "esbuild": "^0.25.11"
49
+ }
50
+ }