Version 1.0.0 (see README.md for details)
This commit is contained in:
parent
7c46e53d08
commit
7a7fbfa42f
4 changed files with 95 additions and 34 deletions
119
README.md
119
README.md
|
@ -1,37 +1,96 @@
|
||||||
# framerock
|
# framerock
|
||||||
|
|
||||||
*JS framework for rad web apps*
|
*minimalist framework for realtime, AI-Ready web apps*
|
||||||
|
|
||||||
a minimal example:
|
## about
|
||||||
|
|
||||||
```javascript
|
framerock is a lightweight framework that enables developers to build client-server JavaScript applications with minimal boilerplate. It abstracts away web server infrastructure and WebSocket management, focusing purely on the core logic of your app.
|
||||||
|
|
||||||
|
## features
|
||||||
|
|
||||||
|
framerock provides a simple, secure foundation for real-time web applications. It handles the full lifecycle of a web server, including serving static resources and managing bidirectional communication via WebSocket. The framework is designed for speed, clarity, and ease of integration.
|
||||||
|
|
||||||
|
| Feature | Description |
|
||||||
|
|--------|-------------|
|
||||||
|
| Zero-dependency | Runs entirely on the Bun runtime with no external packages required |
|
||||||
|
| Real-time bidirectional communication | Uses raw bytes for transport, enabling full control over message format and encoding |
|
||||||
|
| Automatic PING/PONG | Maintains active connections with configurable timeouts and intervals |
|
||||||
|
| Error resilience | Wraps provided functions in try/catch blocks to prevent crashes during runtime |
|
||||||
|
|
||||||
|
## AI-Ready
|
||||||
|
|
||||||
|
framerock is specifically engineered to work seamlessly with AI tools and agent-based workflows. By minimizing surface area and eliminating boilerplate, it reduces context overhead and allows models to focus on application logic. This makes it ideal for iterative development, prompt engineering, and generating or reviewing agent behaviors.
|
||||||
|
|
||||||
|
| Benefit | Description |
|
||||||
|
|--------|-------------|
|
||||||
|
| Reduced context noise | LLMs receive only the relevant code and logic, not server setup or routing details |
|
||||||
|
| Faster iteration | Small, focused codebases enable rapid prototyping and feedback loops |
|
||||||
|
| Direct compatibility | Can be used as both input and output for LLMs without intermediate parsing or transformation |
|
||||||
|
| Safe for evaluation | Raw bytes are passed directly to backend functions, avoiding unsafe string parsing or injection risks |
|
||||||
|
|
||||||
|
## when to use
|
||||||
|
|
||||||
|
- when building a real-time single-page application with low-latency client-server interaction
|
||||||
|
- when you want to leverage AI tools to generate or review frontend or backend code without entangling it in web server logic
|
||||||
|
- when you need a lightweight, portable, and zero-dependency foundation for experimentation or deployment
|
||||||
|
|
||||||
|
## getting started
|
||||||
|
|
||||||
|
Install framerock via Bun:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun add 'git+https://git.daemons.my/dab/framerock.git'
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a file named `your-app-entrypoint.js` with the following content:
|
||||||
|
|
||||||
|
```js
|
||||||
import { async_run } from 'framerock'
|
import { async_run } from 'framerock'
|
||||||
|
|
||||||
const jsbuild_app_frontend = async function () {
|
await async_run({
|
||||||
return `
|
jsbuild_app_frontend: async function () {return `
|
||||||
const on_open = function () {
|
FRAMEROCK_UTILS.setup_transport({
|
||||||
FRAMEROCK_UTILS.transport_send_bytes(new TextEncoder().encode('Hello from client!'))
|
on_open: () => FRAMEROCK_UTILS.transport_send_bytes(new TextEncoder().encode('Hello from client!')),
|
||||||
return
|
on_message: (event) => document.body.appendChild(document.createTextNode('Client received message: ' + new TextDecoder().decode(event.data)))
|
||||||
}
|
})
|
||||||
const on_message = function (event) {
|
`},
|
||||||
console.log(['Client received message:', new TextDecoder().decode(event.data)])
|
handle_transport_bytes: function (message, { client_id, transport_send_bytes }) {
|
||||||
return
|
console.log(['Server received message:', client_id, new TextDecoder().decode(message)])
|
||||||
}
|
transport_send_bytes(new TextEncoder().encode('Hello from server!'))
|
||||||
FRAMEROCK_UTILS.setup_transport({ on_open, on_message })
|
}
|
||||||
`.trim()
|
})
|
||||||
}
|
|
||||||
|
|
||||||
const handle_transport_bytes = function (utils, message) {
|
|
||||||
console.log(['Server received message:', new TextDecoder().decode(message)])
|
|
||||||
utils.transport_send_bytes(new TextEncoder().encode('Hello from server!'))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
hostname: '0.0.0.0',
|
|
||||||
port: 8800,
|
|
||||||
page_title: 'framerock demo',
|
|
||||||
}
|
|
||||||
|
|
||||||
async_run({ config, jsbuild_app_frontend, handle_transport_bytes }).then(()=>{}).catch(console.error)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Run the app:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run ./your-app-entrypoint.js
|
||||||
|
```
|
||||||
|
|
||||||
|
The app will start at `http://127.0.0.1:8800`. Open the page in a browser to see the real-time interaction between client and server.
|
||||||
|
|
||||||
|
## codebase overview
|
||||||
|
|
||||||
|
| file | purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `backend/index.js` | Implements the server-side logic including web server setup, route handling, WebSocket lifecycle management, and dynamic script generation |
|
||||||
|
| `frontend/index.js` | Provides client-side utility functions for managing WebSocket connections and safely executing frontend code via a custom eval wrapper |
|
||||||
|
|
||||||
|
## why framerock
|
||||||
|
|
||||||
|
- eliminates the need to write or maintain repetitive web server or routing code
|
||||||
|
- enables developers to focus on application logic rather than infrastructure
|
||||||
|
- supports rapid iteration and experimentation, especially when paired with AI tools
|
||||||
|
- provides a clean, transparent, and portable foundation that works across environments
|
||||||
|
|
||||||
|
## changelog
|
||||||
|
|
||||||
|
- **Version 1.0.0**
|
||||||
|
- `page_title` now defaults to "framerock app"
|
||||||
|
- `client_id` now available inside `handle_transport_bytes` (added property to `utils` object)
|
||||||
|
- ⚠️ **BACKWARD-INCOMPATIBLE CHANGES** ⚠️
|
||||||
|
- `handle_transport_bytes` moved `utils` to be the final argument in function call (can be optionally consumed now)
|
||||||
|
|
||||||
|
## built with framerock
|
||||||
|
|
||||||
|
- [theatrics](https://git.daemons.my/dab/theatrics), *JS Actor System with first-class support for AI Agents and Assistants*
|
||||||
|
|
|
@ -18,7 +18,7 @@ const get_siteroot_html = function ({ page_title }) {return `
|
||||||
<meta charset=utf-8>
|
<meta charset=utf-8>
|
||||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'/>">
|
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'/>">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>${page_title || 'Page Title'}</title>
|
<title>${page_title}</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script type="text/javascript" src="/index.js">
|
<script type="text/javascript" src="/index.js">
|
||||||
|
@ -173,7 +173,8 @@ const start_server = function ({ context_meta, config, jsbuild_app_frontend, han
|
||||||
if (handle_transport_bytes !== undefined) {
|
if (handle_transport_bytes !== undefined) {
|
||||||
const transport_send_bytes = wrap_transport_sendbytes.bind(null, ws)
|
const transport_send_bytes = wrap_transport_sendbytes.bind(null, ws)
|
||||||
try {
|
try {
|
||||||
handle_transport_bytes({ transport_send_bytes }, message)
|
const utils = { client_id: ws.data.uid, transport_send_bytes }
|
||||||
|
handle_transport_bytes(message, utils)
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
console.error(['error during handle_transport_bytes', err])
|
console.error(['error during handle_transport_bytes', err])
|
||||||
|
@ -229,6 +230,7 @@ const async_run = async function ({
|
||||||
// defaults
|
// defaults
|
||||||
hostname: '127.0.0.1',
|
hostname: '127.0.0.1',
|
||||||
port: 8800,
|
port: 8800,
|
||||||
|
page_title: 'framerock app',
|
||||||
ping_interval: 1000 * 15,
|
ping_interval: 1000 * 15,
|
||||||
pong_timeout : 1000 * 5,
|
pong_timeout : 1000 * 5,
|
||||||
// overrides
|
// overrides
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// provided by outer context: APP_CONSTANTS, JS_APP_FRONTEND
|
// provided by outer context: JS_APP_FRONTEND
|
||||||
|
|
||||||
const setup_safer_eval = function (lst_idents) {
|
const setup_safer_eval = function (lst_idents) {
|
||||||
const runCodeWithCustomFunction = (obj) => {
|
const runCodeWithCustomFunction = (obj) => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "framerock",
|
"name": "framerock",
|
||||||
"version": "0.1.0",
|
"version": "1.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "backend/index.js"
|
"main": "backend/index.js"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue