@ozsarman/clarityjs 0.6.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.
- package/README.md +178 -0
- package/package.json +168 -0
- package/src/analyze.js +534 -0
- package/src/async-state.js +555 -0
- package/src/bundle-runtime.js +35 -0
- package/src/clarity-bundle.js +332 -0
- package/src/clarity-test.js +622 -0
- package/src/cli.js +453 -0
- package/src/codegen.js +1934 -0
- package/src/dev-server.js +362 -0
- package/src/devtools.js +765 -0
- package/src/edge.js +606 -0
- package/src/error-overlay.js +535 -0
- package/src/file-conventions.js +472 -0
- package/src/font.js +513 -0
- package/src/game-loop.js +106 -0
- package/src/head.js +393 -0
- package/src/hydrate.js +292 -0
- package/src/i18n.js +403 -0
- package/src/image.js +352 -0
- package/src/index.js +193 -0
- package/src/islands.js +284 -0
- package/src/isr.js +306 -0
- package/src/layout.js +342 -0
- package/src/lexer.js +572 -0
- package/src/linter.js +547 -0
- package/src/pages-router.js +229 -0
- package/src/parser.js +1108 -0
- package/src/router.js +732 -0
- package/src/runtime.js +1465 -0
- package/src/scoped-css.js +641 -0
- package/src/server-actions.js +439 -0
- package/src/server-data.js +225 -0
- package/src/sourcemap.js +130 -0
- package/src/ssg.js +310 -0
- package/src/ssr.js +621 -0
- package/src/store.js +276 -0
- package/src/transitions.js +438 -0
- package/src/ts-plugin.js +613 -0
- package/src/typegen.js +240 -0
- package/src/vite-plugin.js +447 -0
- package/types/index.d.ts +366 -0
package/README.md
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Clarity.js
|
|
2
|
+
|
|
3
|
+
[](https://gitlab.com/ozsarman/clarity.js/-/pipelines)
|
|
4
|
+
|
|
5
|
+
**An AI-native, permission-aware frontend framework and DSL.**
|
|
6
|
+
Components declare what AI agents may read, act on, and must never touch — directly in the markup.
|
|
7
|
+
|
|
8
|
+
> **Disclaimer:** Clarity.js is an AI-native frontend framework and DSL. It is **not** affiliated with, and is unrelated to, Microsoft Clarity (the web analytics product).
|
|
9
|
+
|
|
10
|
+
- Site & docs: **https://clarity-js.com**
|
|
11
|
+
- Source: **https://gitlab.com/ozsarman/clarity.js**
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## The idea
|
|
16
|
+
|
|
17
|
+
Everyone is building AI agents. Almost nobody defines what those agents are allowed
|
|
18
|
+
to **see** or **change** inside a user interface. We have authentication,
|
|
19
|
+
authorization and RBAC for *people* — but almost no AI-specific access control for
|
|
20
|
+
*interfaces*.
|
|
21
|
+
|
|
22
|
+
Clarity.js makes that a first-class language feature. A component states its AI
|
|
23
|
+
permissions right where the UI is declared:
|
|
24
|
+
|
|
25
|
+
```clarity
|
|
26
|
+
component Checkout() {
|
|
27
|
+
state email = ""
|
|
28
|
+
state total = 0
|
|
29
|
+
state paymentToken = ""
|
|
30
|
+
|
|
31
|
+
ai:readable [email, total] // agents may read these
|
|
32
|
+
ai:actionable [applyCoupon] // agents may call this
|
|
33
|
+
ai:forbidden [paymentToken] // agents must never touch this
|
|
34
|
+
|
|
35
|
+
action applyCoupon(code) { /* ... */ }
|
|
36
|
+
|
|
37
|
+
render {
|
|
38
|
+
<form>
|
|
39
|
+
<input bind:value={ email } />
|
|
40
|
+
<button on:click={ applyCoupon('SAVE10') }>Apply</button>
|
|
41
|
+
</form>
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The UI itself becomes the source of truth for what an agent may do — instead of
|
|
47
|
+
teaching every agent, per integration, what it can and cannot touch. Every agent
|
|
48
|
+
interaction flows through an **audited contract** (`readable` · `snapshot` · `act` ·
|
|
49
|
+
`forbidden`) with a timestamped log.
|
|
50
|
+
|
|
51
|
+
This is the part of Clarity.js worth caring about. The signals, router and SSR are
|
|
52
|
+
solid table stakes; the **AI permission model is the differentiator**. There are
|
|
53
|
+
hundreds of frontend frameworks — but almost none that govern AI agents' access at
|
|
54
|
+
the component level.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Status — building in public
|
|
59
|
+
|
|
60
|
+
Clarity.js is an **early, experimental framework**: a strong, well-tested foundation,
|
|
61
|
+
**not yet production-hardened**. What exists today:
|
|
62
|
+
|
|
63
|
+
- A real compiler pipeline — `.clarity` DSL → lexer → parser → codegen → lean JS
|
|
64
|
+
- Signal-based, fine-grained reactivity — **no virtual DOM**, ~11.5 KB runtime
|
|
65
|
+
- AI directives with **enforced `ai:forbidden`** — reads/writes blocked in agent
|
|
66
|
+
context, typed errors and an audit trail (not just a declaration)
|
|
67
|
+
- A full-stack toolkit (routing, SSR/SSG, forms, i18n, testing, devtools…)
|
|
68
|
+
- 234 passing tests, and a docs site built with the framework itself
|
|
69
|
+
|
|
70
|
+
What is still ahead (tracked in [PRODUCTION_ROADMAP.md](PRODUCTION_ROADMAP.md)):
|
|
71
|
+
broader security hardening (XSS/CSP/CSRF), benchmarks, npm publishing, release
|
|
72
|
+
automation and wider coverage. Honest framing: this is research-grade and evolving fast.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Quick start
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
npm create clarity@latest my-app
|
|
80
|
+
cd my-app
|
|
81
|
+
npm install
|
|
82
|
+
npm run dev
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Your first component:
|
|
86
|
+
|
|
87
|
+
```clarity
|
|
88
|
+
component Counter() {
|
|
89
|
+
state count = 0
|
|
90
|
+
|
|
91
|
+
render {
|
|
92
|
+
<button on:click={ count++ }>Clicked { count } times</button>
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`count++` writes to a signal; only the text node that reads `count` updates — there
|
|
98
|
+
is no component re-render and no virtual DOM.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## The AI contract
|
|
103
|
+
|
|
104
|
+
The `ai:` directives compile into an audited contract attached to each component, so
|
|
105
|
+
an agent interacts through one guarded surface:
|
|
106
|
+
|
|
107
|
+
```js
|
|
108
|
+
const contract = el.__clarity_ai__
|
|
109
|
+
|
|
110
|
+
contract.snapshot() // audited read of all `ai:readable` state
|
|
111
|
+
contract.read('email') // audited single read — throws for non-readable fields
|
|
112
|
+
contract.act('applyCoupon', '…') // guarded, logged action call
|
|
113
|
+
contract.forbidden // ['paymentToken'] — off-limits
|
|
114
|
+
|
|
115
|
+
import { getAIAuditLog } from '@ozsarman/clarityjs'
|
|
116
|
+
getAIAuditLog() // full timestamped trail of every interaction
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`ai:forbidden` is **enforced, not just declared**. Forbidden fields are excluded from
|
|
120
|
+
`readable` / `snapshot` / `read`, and the underlying signal blocks **both reads and
|
|
121
|
+
writes** from inside any agent `act()` call — throwing a typed `ClarityAIForbiddenError`
|
|
122
|
+
and recording an audit entry. An agent cannot read, alias, or return a forbidden field
|
|
123
|
+
through the contract:
|
|
124
|
+
|
|
125
|
+
```js
|
|
126
|
+
import { ClarityAIForbiddenError } from '@ozsarman/clarityjs'
|
|
127
|
+
try { contract.read('paymentToken') } // ✗ throws ClarityAIForbiddenError (audited)
|
|
128
|
+
catch (e) { e instanceof ClarityAIForbiddenError } // true
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Normal user/app code is completely unaffected — the guard fires only inside AI-action
|
|
132
|
+
context. This is the boundary that turns the idea into a working AI security layer.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## What is in the box
|
|
137
|
+
|
|
138
|
+
Beyond the reactive core and the AI layer, Clarity ships a full-stack toolkit — use
|
|
139
|
+
only what you need:
|
|
140
|
+
|
|
141
|
+
- **File-based routing** — `pages/` with dynamic `[slug]` routes, code-split (`scanPages`)
|
|
142
|
+
- **Server rendering** — SSR, SSG, ISR, islands; `useServerData()` for component-level data
|
|
143
|
+
- **Server actions** — `<form action={serverAction}>`, Express + edge adapters
|
|
144
|
+
- **Async state** — `createQuery` / `useFetch` / `createMutation` (SWR/TanStack-style)
|
|
145
|
+
- **Styling** — scoped CSS and CSS Modules (compile-time, no runtime CSS-in-JS)
|
|
146
|
+
- **Tooling** — `create-clarity`, `eslint-plugin-clarity` (9 rules), test utilities,
|
|
147
|
+
in-browser devtools, a VS Code extension and language server
|
|
148
|
+
|
|
149
|
+
A small `createGameLoop()` helper also powers the DOM games on the
|
|
150
|
+
[showcase](https://clarity-js.com) — Clarity is a UI framework, not a game engine,
|
|
151
|
+
but its reactivity drives more than forms.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Documentation
|
|
156
|
+
|
|
157
|
+
Full guides and an API reference live at **https://clarity-js.com** (itself built
|
|
158
|
+
with Clarity.js). See also [CHANGES.md](CHANGES.md), [ROADMAP.md](ROADMAP.md) and
|
|
159
|
+
[GAP_ANALYSIS.md](GAP_ANALYSIS.md).
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Contributing
|
|
164
|
+
|
|
165
|
+
This is an open-source project, built in public. Issues, ideas and pull requests are
|
|
166
|
+
welcome at https://gitlab.com/ozsarman/clarity.js. Run `npm test` before submitting —
|
|
167
|
+
all 228 tests should stay green.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## License
|
|
172
|
+
|
|
173
|
+
MIT
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
*Created by Özdemir Şarman. Built in public, with heavy use of AI tooling — fittingly,
|
|
178
|
+
for a framework about humans and AI agents sharing the same UI.*
|
package/package.json
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ozsarman/clarityjs",
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "An AI-native, permission-aware frontend framework and DSL — components declare what AI agents may read, act on, and never touch.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/index.js",
|
|
7
|
+
"module": "./src/index.js",
|
|
8
|
+
"types": "./types/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./src/index.js",
|
|
12
|
+
"default": "./src/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./runtime": {
|
|
15
|
+
"import": "./src/runtime.js",
|
|
16
|
+
"default": "./src/runtime.js"
|
|
17
|
+
},
|
|
18
|
+
"./hydrate": {
|
|
19
|
+
"import": "./src/hydrate.js",
|
|
20
|
+
"default": "./src/hydrate.js"
|
|
21
|
+
},
|
|
22
|
+
"./ssr": {
|
|
23
|
+
"import": "./src/ssr.js",
|
|
24
|
+
"default": "./src/ssr.js"
|
|
25
|
+
},
|
|
26
|
+
"./vite": {
|
|
27
|
+
"import": "./src/vite-plugin.js",
|
|
28
|
+
"default": "./src/vite-plugin.js"
|
|
29
|
+
},
|
|
30
|
+
"./router": {
|
|
31
|
+
"import": "./src/router.js",
|
|
32
|
+
"default": "./src/router.js"
|
|
33
|
+
},
|
|
34
|
+
"./test": {
|
|
35
|
+
"import": "./src/clarity-test.js",
|
|
36
|
+
"default": "./src/clarity-test.js"
|
|
37
|
+
},
|
|
38
|
+
"./bundle": {
|
|
39
|
+
"import": "./src/clarity-bundle.js",
|
|
40
|
+
"default": "./src/clarity-bundle.js"
|
|
41
|
+
},
|
|
42
|
+
"./async-state": {
|
|
43
|
+
"import": "./src/async-state.js",
|
|
44
|
+
"default": "./src/async-state.js"
|
|
45
|
+
},
|
|
46
|
+
"./devtools": {
|
|
47
|
+
"import": "./src/devtools.js",
|
|
48
|
+
"default": "./src/devtools.js"
|
|
49
|
+
},
|
|
50
|
+
"./head": {
|
|
51
|
+
"import": "./src/head.js",
|
|
52
|
+
"default": "./src/head.js"
|
|
53
|
+
},
|
|
54
|
+
"./image": {
|
|
55
|
+
"import": "./src/image.js",
|
|
56
|
+
"default": "./src/image.js"
|
|
57
|
+
},
|
|
58
|
+
"./font": {
|
|
59
|
+
"import": "./src/font.js",
|
|
60
|
+
"default": "./src/font.js"
|
|
61
|
+
},
|
|
62
|
+
"./layout": {
|
|
63
|
+
"import": "./src/layout.js",
|
|
64
|
+
"default": "./src/layout.js"
|
|
65
|
+
},
|
|
66
|
+
"./linter": {
|
|
67
|
+
"import": "./src/linter.js",
|
|
68
|
+
"default": "./src/linter.js"
|
|
69
|
+
},
|
|
70
|
+
"./ssg": {
|
|
71
|
+
"import": "./src/ssg.js",
|
|
72
|
+
"default": "./src/ssg.js"
|
|
73
|
+
},
|
|
74
|
+
"./isr": {
|
|
75
|
+
"import": "./src/isr.js",
|
|
76
|
+
"default": "./src/isr.js"
|
|
77
|
+
},
|
|
78
|
+
"./islands": {
|
|
79
|
+
"import": "./src/islands.js",
|
|
80
|
+
"default": "./src/islands.js"
|
|
81
|
+
},
|
|
82
|
+
"./server-actions": {
|
|
83
|
+
"import": "./src/server-actions.js",
|
|
84
|
+
"default": "./src/server-actions.js"
|
|
85
|
+
},
|
|
86
|
+
"./edge": {
|
|
87
|
+
"import": "./src/edge.js",
|
|
88
|
+
"default": "./src/edge.js"
|
|
89
|
+
},
|
|
90
|
+
"./ts-plugin": {
|
|
91
|
+
"import": "./src/ts-plugin.js",
|
|
92
|
+
"default": "./src/ts-plugin.js"
|
|
93
|
+
},
|
|
94
|
+
"./file-conventions": {
|
|
95
|
+
"import": "./src/file-conventions.js",
|
|
96
|
+
"default": "./src/file-conventions.js"
|
|
97
|
+
},
|
|
98
|
+
"./pages-router": {
|
|
99
|
+
"import": "./src/pages-router.js",
|
|
100
|
+
"default": "./src/pages-router.js"
|
|
101
|
+
},
|
|
102
|
+
"./server-data": {
|
|
103
|
+
"import": "./src/server-data.js",
|
|
104
|
+
"default": "./src/server-data.js"
|
|
105
|
+
},
|
|
106
|
+
"./game-loop": {
|
|
107
|
+
"import": "./src/game-loop.js",
|
|
108
|
+
"default": "./src/game-loop.js"
|
|
109
|
+
},
|
|
110
|
+
"./error-overlay": {
|
|
111
|
+
"import": "./src/error-overlay.js",
|
|
112
|
+
"default": "./src/error-overlay.js"
|
|
113
|
+
},
|
|
114
|
+
"./analyze": {
|
|
115
|
+
"import": "./src/analyze.js",
|
|
116
|
+
"default": "./src/analyze.js"
|
|
117
|
+
},
|
|
118
|
+
"./i18n": {
|
|
119
|
+
"import": "./src/i18n.js",
|
|
120
|
+
"default": "./src/i18n.js"
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
"bin": {
|
|
124
|
+
"clarity": "src/cli.js"
|
|
125
|
+
},
|
|
126
|
+
"files": [
|
|
127
|
+
"src/",
|
|
128
|
+
"types/",
|
|
129
|
+
"README.md",
|
|
130
|
+
"LICENSE"
|
|
131
|
+
],
|
|
132
|
+
"scripts": {
|
|
133
|
+
"test": "node --experimental-vm-modules tests/run.js",
|
|
134
|
+
"build:examples": "node src/cli.js build examples/",
|
|
135
|
+
"demo": "node src/cli.js demo",
|
|
136
|
+
"size": "npx esbuild src/runtime.js --bundle --format=esm --minify | wc -c | xargs -I{} sh -c 'echo \"Runtime minified: {} bytes ({KB} KB)\" | sed s/{KB}/$(echo \"scale=1; {} / 1024\" | bc)/'",
|
|
137
|
+
"size:full": "npx esbuild src/index.js --bundle --format=esm --minify --outfile=/tmp/clarity-full.min.js && echo \"Full bundle:\" && wc -c /tmp/clarity-full.min.js",
|
|
138
|
+
"prepublishOnly": "npm test",
|
|
139
|
+
"release:patch": "node scripts/release.js patch",
|
|
140
|
+
"release:minor": "node scripts/release.js minor",
|
|
141
|
+
"release:major": "node scripts/release.js major"
|
|
142
|
+
},
|
|
143
|
+
"keywords": [
|
|
144
|
+
"ai-native",
|
|
145
|
+
"ai-permissions",
|
|
146
|
+
"ai-agents",
|
|
147
|
+
"permission-aware",
|
|
148
|
+
"framework",
|
|
149
|
+
"frontend",
|
|
150
|
+
"signals",
|
|
151
|
+
"reactivity",
|
|
152
|
+
"compiler",
|
|
153
|
+
"dsl"
|
|
154
|
+
],
|
|
155
|
+
"author": "Özdemir Şarman",
|
|
156
|
+
"license": "MIT",
|
|
157
|
+
"engines": {
|
|
158
|
+
"node": ">=18.0.0"
|
|
159
|
+
},
|
|
160
|
+
"repository": {
|
|
161
|
+
"type": "git",
|
|
162
|
+
"url": "https://gitlab.com/ozsarman/clarity.js.git"
|
|
163
|
+
},
|
|
164
|
+
"bugs": {
|
|
165
|
+
"url": "https://gitlab.com/ozsarman/clarity.js/-/issues"
|
|
166
|
+
},
|
|
167
|
+
"homepage": "https://clarity-js.com"
|
|
168
|
+
}
|