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: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
In one sentence: **Fun is a scripting language that goes all the way from JSON to machine code.**

- One runtime spans the whole spectrum, from high-level data work (JSON/FD) down to low-level system programming (FFI, C at runtime, JIT, machine code);
- 65 standard-library modules written in Fun itself ship together as one embeddable `fun.dll`;
- 66 standard-library modules written in Fun itself ship together as one embeddable `fun.dll`;
- in AI-agent and domestic-IT scenarios, it is the lightweight glue connecting OSes, databases, chips, and business logic.

Fun is designed around a simple premise: **data and code should be equally first-class, and a script should be able to reach down to the machine without leaving the language.**
Expand Down Expand Up @@ -70,7 +70,7 @@ Fun is written in Pascal (Delphi / Free Pascal). The core is a small tree-walkin
- **Keyword aliasing** — a canonical English keyword set with pluggable alias packs (Chinese, French, custom) selected at runtime (see [below](#keyword-aliasing)).
- **Cross-platform** — Windows (32/64-bit), Linux, ARM, and Windows CE.
- **Dual distribution** — command-line `fun.exe` and embeddable runtime `fun.dll` exporting a simple `Run` interface.
- **Self-hosted standard library** — 65 modules written in Fun itself, from JSON/YAML/XML to ORM, async, UI, and native bindings.
- **Self-hosted standard library** — 66 modules written in Fun itself, from JSON/YAML/XML to ORM, async, UI, and native bindings.

---

Expand Down Expand Up @@ -372,7 +372,7 @@ fun/
│ ├── utils/ # Utility functions
│ └── prj/fun/ # Projects & build scripts (funcmd.dpr, Delphi/FPC)
├── fun/
│ ├── lib/ # Standard library (pure Fun, 65 modules)
│ ├── lib/ # Standard library (pure Fun, 66 modules)
│ ├── demo/ # Language syntax demos
│ ├── demos/ # Full applications & benchmarks
│ └── key_*.ini # Keyword alias packs (CN / FR / PUA)
Expand Down Expand Up @@ -497,16 +497,16 @@ win64/aarch64 target, so there is nothing to build with.

## Standard library

The standard library in [`fun/lib`](fun/lib) is written in pure Fun (65 modules):
The standard library in [`fun/lib`](fun/lib) is written in pure Fun (66 modules):

> In total roughly 6,000 lines of logical code (excluding comments), about 100 lines per module — all 65 modules written in Fun itself.
> In total roughly 6,000 lines of logical code (excluding comments), about 100 lines per module — all 66 modules written in Fun itself.

- **Data**: `lib-json`, `lib-yaml`, `lib-xml`, `lib-base64`, `lib-cstruct`, `lib-md5`, `lib-crypt`
- **Utility**: `uuid`
- **Collections / algorithms**: `lib-set`, `lib-tree`, `lib-stack`, `lib-dyns`, `lib-math`
- **Text**: `lib-string`, `lib-regex`, `lib-match`, `lib-unicode`
- **System / IO**: `lib-file`, `lib-os`, `lib-host`, `lib-time`, `lib-cmdline`, `lib-proc`
- **Network**: `lib-winsock`, `lib-ajax`, `lib-jsonrpc`, `http-server`, `http-client`, `http-auth`, `http-cors`
- **Network**: `lib-winsock`, `lib-ajax`, `lib-jsonrpc`, `http-server`, `http-client`, `http-auth`, `http-bearer`, `http-cors`
- **Databases**: `lib-orm`, `lib-orm-pro`, `lib-orm-gen`, `lib-orm-rpc`, `lib-orm-cte`, `lib-ado`, `lib-ado-schema`
- **Native / low-level**: `lib-winapi`, `lib-winole`, `lib-tcc` (C compile), `lib-jit`, `lib-asm`, `lib-asm-pro`
- **UI**: `lib-ui`, `lib-ui-base`, `lib-dialog`, `lib-trayicon`
Expand All @@ -532,6 +532,7 @@ The standard library in [`fun/lib`](fun/lib) is written in pure Fun (65 modules)
- [`fun/demos/package-demo`](fun/demos/package-demo) — a small package with a path dependency: `tidy`, `run` (project and flat mode), and `pack`.
- [`fun/demos/test-demo`](fun/demos/test-demo) — a lib-only package with tests, a shared helper, and a failing-assertion example.
- [`fun/demos/http-cors-demo`](fun/demos/http-cors-demo) — CORS preflight, credentials, exposed headers, and a browser page.
- [`fun/demos/http-bearer-demo`](fun/demos/http-bearer-demo) — Bearer token auth, 401 challenges, and a same-origin page.

---

Expand Down
13 changes: 7 additions & 6 deletions README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
一句话定位:**Fun 是一门从 JSON 一路写到机器码的脚本语言。**

- 用同一个运行时,覆盖从高层数据处理(JSON/FD)到底层系统编程(FFI、运行时 C、JIT、机器码)的全谱系;
- 自带 65 个用 Fun 自身编写的标准库模块,全栈能力打包进单个可嵌入的 `fun.dll`;
- 自带 66 个用 Fun 自身编写的标准库模块,全栈能力打包进单个可嵌入的 `fun.dll`;
- 在信创与 AI Agent 场景中,作为连接国产 OS、数据库、芯片与业务逻辑的轻量级胶水。

Fun 的设计出发点很简单:**数据与代码都应该是头等公民,而且一段脚本应该能在不离开语言的情况下一路触达机器底层。**
Expand Down Expand Up @@ -70,7 +70,7 @@ Fun 使用 Pascal(Delphi / Free Pascal)编写。核心是一个小巧的树
- **关键字别名** —— 规范英文关键字 + 可插拔的别名包(中文、法文、自定义),运行时选择(见[下文](#关键字别名))。
- **跨平台** —— Windows(32/64 位)、Linux、ARM 与 Windows CE。
- **双形态分发** —— 命令行 `fun.exe` 与嵌入运行时 `fun.dll`(导出简单的 `Run` 接口)。
- **自托管的标准库** —— 65 个用 Fun 自身编写的模块,覆盖 JSON/YAML/XML 到 ORM、异步、UI 与原生绑定。
- **自托管的标准库** —— 66 个用 Fun 自身编写的模块,覆盖 JSON/YAML/XML 到 ORM、异步、UI 与原生绑定。

---

Expand Down Expand Up @@ -365,7 +365,7 @@ fun/
│ ├── utils/ # 工具函数
│ └── prj/fun/ # 工程与构建脚本(funcmd.dpr,Delphi/FPC)
├── fun/
│ ├── lib/ # 标准库(纯 Fun 编写,65 个模块)
│ ├── lib/ # 标准库(纯 Fun 编写,66 个模块)
│ ├── demo/ # 语言语法演示
│ ├── demos/ # 完整应用与基准测试
│ └── key_*.ini # 关键字别名包(CN / FR / PUA)
Expand Down Expand Up @@ -477,16 +477,16 @@ float/混合参数与 `@toCallback` 闭包在 win64 上也有覆盖;`ffi-scala

## 标准库

标准库位于 [`fun/lib`](fun/lib),以纯 Fun 编写(65 个模块):
标准库位于 [`fun/lib`](fun/lib),以纯 Fun 编写(66 个模块):

> 总代码量约 6,000 行逻辑代码(不含注释),平均每个模块约 100 行——65 个模块全部用 Fun 自身写成。
> 总代码量约 6,000 行逻辑代码(不含注释),平均每个模块约 100 行——66 个模块全部用 Fun 自身写成。

- **数据**:`lib-json`、`lib-yaml`、`lib-xml`、`lib-base64`、`lib-cstruct`、`lib-md5`、`lib-crypt`
- **工具**:`uuid`
- **集合 / 算法**:`lib-set`、`lib-tree`、`lib-stack`、`lib-dyns`、`lib-math`
- **文本**:`lib-string`、`lib-regex`、`lib-match`、`lib-unicode`
- **系统 / IO**:`lib-file`、`lib-os`、`lib-host`、`lib-time`、`lib-cmdline`、`lib-proc`
- **网络**:`lib-winsock`、`lib-ajax`、`lib-jsonrpc`、`http-server`、`http-client`、`http-auth`、`http-cors`
- **网络**:`lib-winsock`、`lib-ajax`、`lib-jsonrpc`、`http-server`、`http-client`、`http-auth`、`http-bearer`、`http-cors`
- **数据库**:`lib-orm`、`lib-orm-pro`、`lib-orm-gen`、`lib-orm-rpc`、`lib-orm-cte`、`lib-ado`、`lib-ado-schema`
- **原生 / 底层**:`lib-winapi`、`lib-winole`、`lib-tcc`(C 编译)、`lib-jit`、`lib-asm`、`lib-asm-pro`
- **UI**:`lib-ui`、`lib-ui-base`、`lib-dialog`、`lib-trayicon`
Expand All @@ -509,6 +509,7 @@ float/混合参数与 `@toCallback` 闭包在 win64 上也有覆盖;`ffi-scala
- [`fun/demos/package-demo`](fun/demos/package-demo) —— 带路径依赖的小项目:`tidy`、`run`(项目/平铺)与 `pack`。
- [`fun/demos/test-demo`](fun/demos/test-demo) —— 只有库的包及测试:共享 helper、通过用例与失败断言示例。
- [`fun/demos/http-cors-demo`](fun/demos/http-cors-demo) —— CORS 预检、credentials、暴露响应头与浏览器页面示例。
- [`fun/demos/http-bearer-demo`](fun/demos/http-bearer-demo) —— Bearer token 认证、401 挑战与同源页面示例。

---

Expand Down
77 changes: 77 additions & 0 deletions fun/demos/http-bearer-demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# http-bearer-demo

A small API and page showing Bearer token authentication:

- `GET /api/public` is open;
- `GET /api/me` requires `Authorization: Bearer demo-token`;
- missing credentials get a `Bearer realm="demo"` challenge;
- an invalid token adds `error="invalid_token"`;
- the token is never stored in `req.auth`.

```text
package.fun # manifest
src/main.fun # API + static page on :8080
web/index.html # same-origin page
```

## Run

`fun` below is the command-line binary (`fun.exe` on Windows). From the
repository root, after building, the in-tree binary is
`src/prj/fun/funcmd`; from this directory that is
`../../../src/prj/fun/funcmd`.

```text
cd fun/demos/http-bearer-demo
fun run
# or: ../../../src/prj/fun/funcmd run
```

Open <http://127.0.0.1:8080/>. The page calls the API with the token in the
input (default `demo-token`).

## Curl

Missing credentials:

```text
curl -i http://127.0.0.1:8080/api/me
```

Expected: `401` with `WWW-Authenticate: Bearer realm="demo"`.

Invalid token:

```text
curl -i http://127.0.0.1:8080/api/me \
-H 'Authorization: Bearer wrong-token'
```

Expected: `401` with `Bearer realm="demo", error="invalid_token"`.

Malformed header:

```text
curl -i http://127.0.0.1:8080/api/me \
-H 'Authorization: Bearer'
```

Expected: `401` with `Bearer realm="demo", error="invalid_request"`.

Valid token:

```text
curl -i http://127.0.0.1:8080/api/me \
-H 'Authorization: Bearer demo-token'
```

Expected: `200` and `{"sub":"demo-user","scheme":"bearer"}`.

## Notes

- Only the `Authorization` header is read; query/form tokens are not accepted.
- The verifier is application code. Real applications should validate an
opaque token against a store, or verify a JWT signature and claims.
- Bearer tokens are secrets: use HTTPS and do not log `req.credentials`.
- `demo-token` is fixed for demonstration only; never use it in production.
- Basic and Bearer are separate scheme middlewares; pick one per route/group.
15 changes: 15 additions & 0 deletions fun/demos/http-bearer-demo/package.fun
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
fun package()
result = [
name: 'http-bearer-demo',
version: '0.1.0',
bin: 'src/main.fun',
lib: '',
'fun': '9.4',

dependencies: [],

// >>> generated - do not edit; run 'fun package tidy' to refresh
resolved: []
// <<< generated
];
end fun;
31 changes: 31 additions & 0 deletions fun/demos/http-bearer-demo/src/main.fun
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use '../../../lib/http-server.fun';
use '../../../lib/http-bearer.fun';

fun verifyDemo(req, c)
if c['token'] = 'demo-token' then
var p = new [];
p['sub'] = 'demo-user';
p['roles'] = new [];
p['roles']['reader'] = true;
result = p;
else
result = false;
end if;
end fun;

fun meH(req, res)
res.json([sub: req.auth['sub'], scheme: req.auth['scheme']]);
end fun;

fun publicH(req, res)
res.json([ok: true, from: 'public']);
end fun;

var s = HttpServer(8080);
s.Use(HttpLogger());
s.get('/api/public', publicH);
var api = s.group('/api');
api.Use(HttpBearerAuth(verifyDemo, [realm: 'demo']));
api.get('/me', meH);
s.static('/', 'web');
s.run();
57 changes: 57 additions & 0 deletions fun/demos/http-bearer-demo/web/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Fun Bearer demo</title>
<style>
body { font: 15px/1.5 system-ui, sans-serif; margin: 2rem auto; max-width: 760px; padding: 0 1rem; }
input { padding: .4rem; width: 16rem; }
button { margin: 0 .5rem .5rem 0; padding: .4rem .8rem; }
pre { background: #f4f4f4; padding: 1rem; overflow: auto; white-space: pre-wrap; }
code { background: #eee; padding: .1rem .3rem; }
</style>
</head>
<body>
<h1>Fun Bearer demo</h1>
<p>API and page share <code>http://127.0.0.1:8080</code>; no CORS is involved.</p>
<p>
Token: <input id="token" value="demo-token">
</p>
<button id="public">GET /api/public</button>
<button id="me">GET /api/me</button>
<button id="bad">GET /api/me (bad token)</button>
<pre id="out">Click a button.</pre>

<script>
const out = document.getElementById('out');
const token = document.getElementById('token');

async function show(label, path, auth) {
out.textContent = label + ' ...';
const headers = {};
if (auth) headers['Authorization'] = 'Bearer ' + auth;
try {
const r = await fetch(path, { headers });
const body = await r.text();
out.textContent =
label + '\n' +
'status: ' + r.status + '\n' +
'WWW-Authenticate: ' + (r.headers.get('WWW-Authenticate') || '(none)') + '\n\n' +
body;
} catch (e) {
out.textContent = label + '\nfetch error: ' + e;
}
}

document.getElementById('public').onclick = () =>
show('GET /api/public', '/api/public', null);

document.getElementById('me').onclick = () =>
show('GET /api/me (token)', '/api/me', token.value);

document.getElementById('bad').onclick = () =>
show('GET /api/me (bad)', '/api/me', 'wrong-token');
</script>
</body>
</html>
Loading
Loading