fastscript 0.1.0 → 0.1.1
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.
- package/CHANGELOG.md +3 -0
- package/package.json +10 -3
- package/.github/workflows/ci.yml +0 -17
- package/Dockerfile +0 -9
- package/app/api/auth.js +0 -10
- package/app/api/hello.js +0 -3
- package/app/api/upload.js +0 -9
- package/app/api/webhook.js +0 -10
- package/app/db/migrations/001_init.js +0 -6
- package/app/db/seed.js +0 -5
- package/app/env.schema.js +0 -6
- package/app/middleware.fs +0 -7
- package/app/pages/404.fs +0 -3
- package/app/pages/_layout.fs +0 -17
- package/app/pages/benchmarks.fs +0 -15
- package/app/pages/docs/index.fs +0 -16
- package/app/pages/index.fs +0 -22
- package/app/pages/private.fs +0 -12
- package/app/pages/showcase.fs +0 -14
- package/app/styles.css +0 -14
- package/docs/AI_CONTEXT_PACK_V1.md +0 -25
- package/docs/DEPLOY_GUIDE.md +0 -14
- package/docs/INCIDENT_PLAYBOOK.md +0 -18
- package/docs/INTEROP_RULES.md +0 -7
- package/docs/PLUGIN_API_CONTRACT.md +0 -22
- package/ecosystem.config.cjs +0 -1
- package/examples/fullstack/README.md +0 -10
- package/examples/fullstack/app/api/orders.js +0 -8
- package/examples/fullstack/app/db/migrations/001_init.js +0 -3
- package/examples/fullstack/app/db/seed.js +0 -3
- package/examples/fullstack/app/jobs/send-order-email.js +0 -4
- package/examples/fullstack/app/pages/_layout.fs +0 -1
- package/examples/fullstack/app/pages/index.fs +0 -3
- package/examples/startup-mvp/README.md +0 -8
- package/examples/startup-mvp/app/api/cart.js +0 -9
- package/examples/startup-mvp/app/api/checkout.js +0 -8
- package/examples/startup-mvp/app/db/migrations/001_products.js +0 -6
- package/examples/startup-mvp/app/jobs/send-receipt.js +0 -4
- package/examples/startup-mvp/app/pages/_layout.fs +0 -3
- package/examples/startup-mvp/app/pages/dashboard/index.fs +0 -9
- package/examples/startup-mvp/app/pages/index.fs +0 -18
- package/scripts/bench-report.mjs +0 -36
- package/scripts/release.mjs +0 -21
- package/scripts/smoke-dev.mjs +0 -78
- package/scripts/smoke-start.mjs +0 -41
- package/scripts/test-auth.mjs +0 -26
- package/scripts/test-db.mjs +0 -31
- package/scripts/test-jobs.mjs +0 -15
- package/scripts/test-middleware.mjs +0 -37
- package/scripts/test-roundtrip.mjs +0 -44
- package/scripts/test-validation.mjs +0 -17
- package/scripts/test-webhook-storage.mjs +0 -22
- package/spec/FASTSCRIPT_1000_BUILD_LIST.md +0 -1090
- package/vercel.json +0 -15
- package/vscode/fastscript-language/README.md +0 -12
- package/vscode/fastscript-language/extension.js +0 -24
- package/vscode/fastscript-language/language-configuration.json +0 -6
- package/vscode/fastscript-language/lsp/server.cjs +0 -27
- package/vscode/fastscript-language/lsp/smoke-test.cjs +0 -1
- package/vscode/fastscript-language/package.json +0 -36
- package/vscode/fastscript-language/snippets/fastscript.code-snippets +0 -24
- package/vscode/fastscript-language/syntaxes/fastscript.tmLanguage.json +0 -21
- package/wrangler.toml +0 -5
package/scripts/smoke-start.mjs
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
|
-
import { setTimeout as sleep } from "node:timers/promises";
|
|
3
|
-
|
|
4
|
-
async function waitFor(url, ms = 20000) {
|
|
5
|
-
const start = Date.now();
|
|
6
|
-
while (Date.now() - start < ms) {
|
|
7
|
-
try {
|
|
8
|
-
const r = await fetch(url);
|
|
9
|
-
if (r.status >= 200) return;
|
|
10
|
-
} catch {}
|
|
11
|
-
await sleep(300);
|
|
12
|
-
}
|
|
13
|
-
throw new Error(`Timeout waiting for ${url}`);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const build = spawn(process.execPath, ["./src/cli.mjs", "build"], { cwd: process.cwd(), stdio: "inherit" });
|
|
17
|
-
await new Promise((resolve, reject) => {
|
|
18
|
-
build.on("exit", (code) => (code === 0 ? resolve() : reject(new Error(`build failed: ${code}`))));
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
const proc = spawn(process.execPath, ["./src/cli.mjs", "start"], {
|
|
22
|
-
cwd: process.cwd(),
|
|
23
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
24
|
-
env: { ...process.env, PORT: "4173", NODE_ENV: "production" },
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
try {
|
|
28
|
-
await waitFor("http://localhost:4173/");
|
|
29
|
-
const home = await fetch("http://localhost:4173/");
|
|
30
|
-
if (home.status !== 200) throw new Error(`start home status ${home.status}`);
|
|
31
|
-
const reqId = home.headers.get("x-request-id");
|
|
32
|
-
if (!reqId) throw new Error("missing x-request-id header");
|
|
33
|
-
|
|
34
|
-
const api = await fetch("http://localhost:4173/api/hello", { headers: { accept: "application/json" } });
|
|
35
|
-
if (api.status !== 200) throw new Error(`start api status ${api.status}`);
|
|
36
|
-
|
|
37
|
-
console.log("smoke-start pass: production adapter serving SSR/API with request IDs");
|
|
38
|
-
} finally {
|
|
39
|
-
proc.kill("SIGTERM");
|
|
40
|
-
await sleep(300);
|
|
41
|
-
}
|
package/scripts/test-auth.mjs
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { rmSync } from "node:fs";
|
|
3
|
-
import { resolve } from "node:path";
|
|
4
|
-
import { createSessionManager, parseCookies, serializeCookie } from "../src/auth.mjs";
|
|
5
|
-
|
|
6
|
-
const dir = resolve('.tmp-auth-tests');
|
|
7
|
-
rmSync(dir, { recursive: true, force: true });
|
|
8
|
-
|
|
9
|
-
const sm = createSessionManager({ dir, cookieName: 't' });
|
|
10
|
-
const token = sm.create({ id: 'u1' }, 60);
|
|
11
|
-
assert.ok(token.split('.').length === 3);
|
|
12
|
-
assert.equal(sm.read(token).user.id, 'u1');
|
|
13
|
-
|
|
14
|
-
const rotated = sm.rotate(token, 60);
|
|
15
|
-
assert.ok(rotated);
|
|
16
|
-
assert.equal(sm.read(token), null);
|
|
17
|
-
assert.equal(sm.read(rotated).user.id, 'u1');
|
|
18
|
-
|
|
19
|
-
sm.delete(rotated);
|
|
20
|
-
assert.equal(sm.read(rotated), null);
|
|
21
|
-
|
|
22
|
-
const c = serializeCookie('a', 'b', { path: '/', maxAge: 10, httpOnly: true });
|
|
23
|
-
assert.ok(c.includes('a=b'));
|
|
24
|
-
assert.equal(parseCookies('a=b; x=y').x, 'y');
|
|
25
|
-
|
|
26
|
-
console.log('test-auth pass');
|
package/scripts/test-db.mjs
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { rmSync } from "node:fs";
|
|
3
|
-
import { resolve } from "node:path";
|
|
4
|
-
import { createFileDatabase } from "../src/db.mjs";
|
|
5
|
-
|
|
6
|
-
const dir = resolve('.tmp-db-tests');
|
|
7
|
-
rmSync(dir, { recursive: true, force: true });
|
|
8
|
-
|
|
9
|
-
const db = createFileDatabase({ dir, name: 'test' });
|
|
10
|
-
const users = db.collection('users');
|
|
11
|
-
users.set('u1', { id: 'u1', role: 'admin', active: true });
|
|
12
|
-
users.upsert('u2', () => ({ id: 'u2', role: 'user', active: false }));
|
|
13
|
-
|
|
14
|
-
assert.equal(users.get('u1').role, 'admin');
|
|
15
|
-
assert.equal(users.first((u) => u.id === 'u2').id, 'u2');
|
|
16
|
-
assert.equal(users.where({ role: 'admin' }).length, 1);
|
|
17
|
-
assert.equal(db.where('users', { active: false }).length, 1);
|
|
18
|
-
|
|
19
|
-
let rolledBack = false;
|
|
20
|
-
try {
|
|
21
|
-
db.transaction((tx) => {
|
|
22
|
-
tx.collection('users').set('u3', { id: 'u3' });
|
|
23
|
-
throw new Error('boom');
|
|
24
|
-
});
|
|
25
|
-
} catch {
|
|
26
|
-
rolledBack = true;
|
|
27
|
-
}
|
|
28
|
-
assert.equal(rolledBack, true);
|
|
29
|
-
assert.equal(users.get('u3'), null);
|
|
30
|
-
|
|
31
|
-
console.log('test-db pass');
|
package/scripts/test-jobs.mjs
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { rmSync } from "node:fs";
|
|
3
|
-
import { resolve } from "node:path";
|
|
4
|
-
import { createJobQueue } from "../src/jobs.mjs";
|
|
5
|
-
|
|
6
|
-
const dir = resolve('.tmp-jobs-tests');
|
|
7
|
-
rmSync(dir, { recursive: true, force: true });
|
|
8
|
-
const q = createJobQueue({ dir });
|
|
9
|
-
const job = q.enqueue('a', { n: 1 }, { delayMs: 0, maxAttempts: 2, backoffMs: 1 });
|
|
10
|
-
assert.equal(q.peekReady(10).length >= 1, true);
|
|
11
|
-
q.fail(job);
|
|
12
|
-
assert.equal(q.list().length, 1);
|
|
13
|
-
q.fail(job);
|
|
14
|
-
assert.equal(q.list().length, 0);
|
|
15
|
-
console.log('test-jobs pass');
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { composeMiddleware } from "../src/middleware.mjs";
|
|
3
|
-
|
|
4
|
-
const calls = [];
|
|
5
|
-
const run = composeMiddleware([
|
|
6
|
-
async (ctx, next) => {
|
|
7
|
-
calls.push("m1:before");
|
|
8
|
-
ctx.x = 1;
|
|
9
|
-
const r = await next();
|
|
10
|
-
calls.push("m1:after");
|
|
11
|
-
return r;
|
|
12
|
-
},
|
|
13
|
-
async (ctx, next) => {
|
|
14
|
-
calls.push("m2:before");
|
|
15
|
-
ctx.y = ctx.x + 1;
|
|
16
|
-
const r = await next();
|
|
17
|
-
calls.push("m2:after");
|
|
18
|
-
return r;
|
|
19
|
-
},
|
|
20
|
-
]);
|
|
21
|
-
|
|
22
|
-
const result = await run({}, async () => {
|
|
23
|
-
calls.push("handler");
|
|
24
|
-
return { ok: true };
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
assert.equal(result.ok, true);
|
|
28
|
-
assert.deepEqual(calls, ["m1:before", "m2:before", "handler", "m2:after", "m1:after"]);
|
|
29
|
-
|
|
30
|
-
const short = composeMiddleware([
|
|
31
|
-
async () => ({ status: 401 }),
|
|
32
|
-
async () => ({ status: 200 }),
|
|
33
|
-
]);
|
|
34
|
-
const shortRes = await short({}, async () => ({ status: 204 }));
|
|
35
|
-
assert.equal(shortRes.status, 401);
|
|
36
|
-
|
|
37
|
-
console.log("test-middleware pass");
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { cpSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, existsSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { join, resolve } from "node:path";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import { runMigrate } from "../src/migrate.mjs";
|
|
6
|
-
import { runExport } from "../src/export.mjs";
|
|
7
|
-
|
|
8
|
-
const root = resolve('.tmp-roundtrip');
|
|
9
|
-
const pages = join(root, 'pages');
|
|
10
|
-
rmSync(root, { recursive: true, force: true });
|
|
11
|
-
mkdirSync(pages, { recursive: true });
|
|
12
|
-
|
|
13
|
-
writeFileSync(join(pages, 'index.ts'), `
|
|
14
|
-
import type { X } from './types'
|
|
15
|
-
state n = 1
|
|
16
|
-
function add(a: number, b: number): number { return a + b }
|
|
17
|
-
export default function Home(){ return '<h1>' + String(add(n,2)) + '</h1>' }
|
|
18
|
-
`, 'utf8');
|
|
19
|
-
|
|
20
|
-
await runMigrate(root);
|
|
21
|
-
assert.equal(existsSync(join(pages, 'index.fs')), true);
|
|
22
|
-
assert.equal(existsSync(join(pages, 'index.ts')), false);
|
|
23
|
-
|
|
24
|
-
const appDir = resolve('app');
|
|
25
|
-
const restoreDir = mkdtempSync(join(tmpdir(), 'fs-app-backup-'));
|
|
26
|
-
const backupApp = join(restoreDir, 'app');
|
|
27
|
-
|
|
28
|
-
if (existsSync(appDir)) renameSync(appDir, backupApp);
|
|
29
|
-
|
|
30
|
-
try {
|
|
31
|
-
mkdirSync(join(appDir, 'pages'), { recursive: true });
|
|
32
|
-
writeFileSync(join(appDir, 'pages', 'index.fs'), readFileSync(join(pages, 'index.fs'), 'utf8'), 'utf8');
|
|
33
|
-
|
|
34
|
-
await runExport(['--to', 'js', '--out', '.tmp-export-js']);
|
|
35
|
-
await runExport(['--to', 'ts', '--out', '.tmp-export-ts']);
|
|
36
|
-
assert.equal(existsSync(resolve('.tmp-export-js/pages/index.js')), true);
|
|
37
|
-
assert.equal(existsSync(resolve('.tmp-export-ts/pages/index.ts')), true);
|
|
38
|
-
} finally {
|
|
39
|
-
rmSync(appDir, { recursive: true, force: true });
|
|
40
|
-
if (existsSync(backupApp)) renameSync(backupApp, appDir);
|
|
41
|
-
rmSync(restoreDir, { recursive: true, force: true });
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
console.log('test-roundtrip pass');
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { validateShape } from "../src/validation.mjs";
|
|
3
|
-
|
|
4
|
-
const q = validateShape({ page: "int", search: "string?" }, { page: "2" }, "query");
|
|
5
|
-
assert.equal(q.value.page, 2);
|
|
6
|
-
assert.equal(q.value.search, undefined);
|
|
7
|
-
|
|
8
|
-
let failed = false;
|
|
9
|
-
try {
|
|
10
|
-
validateShape({ page: "int" }, { page: "x" }, "query");
|
|
11
|
-
} catch (e) {
|
|
12
|
-
failed = true;
|
|
13
|
-
assert.equal(e.status, 400);
|
|
14
|
-
}
|
|
15
|
-
assert.equal(failed, true);
|
|
16
|
-
|
|
17
|
-
console.log("test-validation pass");
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { rmSync } from "node:fs";
|
|
3
|
-
import { resolve } from "node:path";
|
|
4
|
-
import { signPayload, verifySignature, isReplay } from "../src/webhook.mjs";
|
|
5
|
-
import { createLocalStorage } from "../src/storage.mjs";
|
|
6
|
-
|
|
7
|
-
const payload = Buffer.from('{"ok":true}');
|
|
8
|
-
const secret = 'topsecret';
|
|
9
|
-
const sig = signPayload(payload, secret);
|
|
10
|
-
assert.equal(verifySignature(payload, sig, secret), true);
|
|
11
|
-
assert.equal(verifySignature(payload, sig, 'bad'), false);
|
|
12
|
-
assert.equal(isReplay(Math.floor(Date.now() / 1000), 300), false);
|
|
13
|
-
|
|
14
|
-
const dir = resolve('.tmp-storage-tests');
|
|
15
|
-
rmSync(dir, { recursive: true, force: true });
|
|
16
|
-
const store = createLocalStorage({ dir });
|
|
17
|
-
store.put('a/b.txt', Buffer.from('hello'));
|
|
18
|
-
assert.equal(String(store.get('a/b.txt')), 'hello');
|
|
19
|
-
store.delete('a/b.txt');
|
|
20
|
-
assert.equal(store.get('a/b.txt'), null);
|
|
21
|
-
|
|
22
|
-
console.log('test-webhook-storage pass');
|