@webqit/webflo 0.20.11 → 0.20.12-next.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
CHANGED
|
@@ -1,26 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
# Webflo
|
|
4
|
-
|
|
5
|
-
_A web-native framework for the next generation of apps_
|
|
1
|
+
# Webflo – _A next-gen, web-native framework_
|
|
6
2
|
|
|
7
3
|
[![npm version][npm-version-src]][npm-version-href]<!--[![npm downloads][npm-downloads-src]][npm-downloads-href]-->
|
|
8
4
|
[![License][license-src]][license-href]
|
|
9
5
|
|
|
10
|
-
</div>
|
|
11
|
-
|
|
12
|
-
<div align="center">
|
|
13
|
-
|
|
14
6
|
_Build the full spectrum of modern applications — backends, frontends, offline-first, and realtime apps — on raw platform power._ 🛸<br>
|
|
15
7
|
[Webflo ↗](https://webflo.netlify.app/overview) is a web-native framework that lets you build absurdlly fast — with the whole sophistication and scale of modern apps solved from the foundation up.
|
|
16
8
|
|
|
17
|
-
</div>
|
|
18
|
-
|
|
19
9
|
---
|
|
20
10
|
|
|
21
11
|
> [!IMPORTANT]
|
|
22
12
|
> 🚀 **Webflo is in active development and evolving daily.** Current status = **alpha**.<br>
|
|
23
|
-
> You’re welcome to experiment, but it’s not yet suited for production
|
|
13
|
+
> You’re welcome to experiment, but it’s not yet suited for production apps.
|
|
24
14
|
|
|
25
15
|
---
|
|
26
16
|
|
|
@@ -38,12 +28,12 @@ For a quick intro, see the docs:
|
|
|
38
28
|
|
|
39
29
|
| Category | Examples & Notes |
|
|
40
30
|
| :------------------------- | :--------------------------------------------------------------------------------------------------------------- |
|
|
41
|
-
| **Web apps** |
|
|
42
|
-
| **API backends** | REST endpoints
|
|
43
|
-
| **Static sites** | Static-first or fully pre-rendered sites
|
|
44
|
-
| **Mobile experiences** | Installable, offline-capable PWAs with background sync,
|
|
45
|
-
| **Realtime & multiplayer** | Chats, presence, dashboards, live docs, notifications
|
|
46
|
-
| **AI & agents** | Multi-step AI workflows, background agents, and automation powered by Webflo’s
|
|
31
|
+
| **Web apps** | Anything from classic MPAs to rich SPAs – with SSR/CSR/hybrid rendering patterns. |
|
|
32
|
+
| **API backends** | REST endpoints and webhooks – with streaming, partial responses, and live messaging. |
|
|
33
|
+
| **Static sites** | Static-first or fully pre-rendered sites – with the same client-side richness of a Webflo app. |
|
|
34
|
+
| **Mobile experiences** | Installable, offline-capable PWAs – with background sync, push notifications, and more. |
|
|
35
|
+
| **Realtime & multiplayer** | Chats, presence, dashboards, live docs, notifications – realtime channels and dialogs available out of the box. |
|
|
36
|
+
| **AI & agents** | Multi-step AI workflows, background agents, and automation – powered by Webflo’s realtime capabilities. |
|
|
47
37
|
|
|
48
38
|
---
|
|
49
39
|
|
|
@@ -51,14 +41,12 @@ For a quick intro, see the docs:
|
|
|
51
41
|
|
|
52
42
|
| Feature | Description |
|
|
53
43
|
| :------------------------------------ | :-------------------------------------------------------------------------------------------------- |
|
|
54
|
-
| 📁 **Folder-based routing** | Filesystem routing across client, worker, and server layers
|
|
55
|
-
| 🌍 **
|
|
56
|
-
| 🔗 **Internal API composition** | Reuse your own routes as local function calls via `next(path)` — no extra networking required. |
|
|
44
|
+
| 📁 **Folder-based routing** | Filesystem routing across client, service worker, and server layers. |
|
|
45
|
+
| 🌍 **Service Worker routing** | Support for route handlers in the service worker. |
|
|
57
46
|
| 🔐 **Sessions & auth** | Built-in cookie handling, session utilities, and helpers for gated routes and user-aware flows. |
|
|
58
|
-
| ⚡ **Realtime capabilities** | Live responses,
|
|
47
|
+
| ⚡ **Realtime capabilities** | Live responses, mutable/differential responses, two-way background messaging — all built in. |
|
|
59
48
|
| 🧠 **Mutation-based reactivity** | State is plain objects and arrays; mutations drive reactivity via the Observer API. |
|
|
60
49
|
| 🧱 **OOHTML integration** | HTML-native templates, imports, and composition without a component DSL or build-heavy toolchain. |
|
|
61
|
-
| 📦 **Offline & worker features** | Worker-side routing, caching, background sync, and offline-first behaviors built in. |
|
|
62
50
|
| 🧩 **Dev mode & HMR** | Fast development server with fine-grained rebuilds and hot updates for HTML, JS, and CSS. |
|
|
63
51
|
|
|
64
52
|
---
|
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"vanila-javascript"
|
|
13
13
|
],
|
|
14
14
|
"homepage": "https://webqit.io/tooling/webflo",
|
|
15
|
-
"version": "0.20.
|
|
15
|
+
"version": "0.20.12-next.0",
|
|
16
16
|
"license": "MIT",
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
@@ -45,15 +45,15 @@
|
|
|
45
45
|
"@octokit/webhooks": "^7.15.1",
|
|
46
46
|
"@webqit/backpack": "^0.1.12",
|
|
47
47
|
"@webqit/oohtml-ssr": "^2.2.1",
|
|
48
|
-
"@webqit/use-live": "^0.5.
|
|
48
|
+
"@webqit/use-live": "^0.5.44",
|
|
49
49
|
"@webqit/util": "^0.8.11",
|
|
50
|
+
"chokidar": "^4.0.3",
|
|
50
51
|
"dotenv": "^16.4.7",
|
|
51
52
|
"esbuild": "^0.14.38",
|
|
53
|
+
"fast-glob": "^3.3.3",
|
|
52
54
|
"mime-types": "^2.1.33",
|
|
53
55
|
"simple-git": "^2.20.1",
|
|
54
|
-
"urlpattern-polyfill": "^4.0.3"
|
|
55
|
-
"chokidar": "^4.0.3",
|
|
56
|
-
"fast-glob": "^3.3.3"
|
|
56
|
+
"urlpattern-polyfill": "^4.0.3"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"chai": "^4.3.6",
|
package/site/overview.md
CHANGED
|
@@ -68,25 +68,23 @@ The service worker as a new routing site exposes this underutilized layer of the
|
|
|
68
68
|
|
|
69
69
|
| Category | Examples & Notes |
|
|
70
70
|
| :------------------------- | :--------------------------------------------------------------------------------------------------------------- |
|
|
71
|
-
| **Web apps** |
|
|
72
|
-
| **API backends** | REST endpoints
|
|
73
|
-
| **Static sites** | Static-first or fully pre-rendered sites
|
|
74
|
-
| **Mobile experiences** | Installable, offline-capable PWAs with background sync,
|
|
75
|
-
| **Realtime & multiplayer** | Chats, presence, dashboards, live docs, notifications
|
|
76
|
-
| **AI & agents** | Multi-step AI workflows, background agents, and automation powered by Webflo’s
|
|
71
|
+
| **Web apps** | Anything from classic MPAs to rich SPAs – with SSR/CSR/hybrid rendering patterns. |
|
|
72
|
+
| **API backends** | REST endpoints and webhooks – with streaming, partial responses, and live messaging. |
|
|
73
|
+
| **Static sites** | Static-first or fully pre-rendered sites – with the same client-side richness of a Webflo app. |
|
|
74
|
+
| **Mobile experiences** | Installable, offline-capable PWAs – with background sync, push notifications, and more. |
|
|
75
|
+
| **Realtime & multiplayer** | Chats, presence, dashboards, live docs, notifications – realtime channels and dialogs available out of the box. |
|
|
76
|
+
| **AI & agents** | Multi-step AI workflows, background agents, and automation – powered by Webflo’s realtime capabilities. |
|
|
77
77
|
|
|
78
78
|
## Features
|
|
79
79
|
|
|
80
80
|
| Feature | Description |
|
|
81
81
|
| :------------------------------------ | :-------------------------------------------------------------------------------------------------- |
|
|
82
|
-
| 📁 **Folder-based routing** | Filesystem routing across client, worker, and server layers
|
|
83
|
-
| 🌍 **
|
|
84
|
-
| 🔗 **Internal API composition** | Reuse your own routes as local function calls via `next(path)` — no extra networking required. |
|
|
82
|
+
| 📁 **Folder-based routing** | Filesystem routing across client, service worker, and server layers. |
|
|
83
|
+
| 🌍 **Service Worker routing** | Support for route handlers in the service worker. |
|
|
85
84
|
| 🔐 **Sessions & auth** | Built-in cookie handling, session utilities, and helpers for gated routes and user-aware flows. |
|
|
86
|
-
| ⚡ **Realtime capabilities** | Live responses,
|
|
85
|
+
| ⚡ **Realtime capabilities** | Live responses, mutable/differential responses, two-way background messaging — all built in. |
|
|
87
86
|
| 🧠 **Mutation-based reactivity** | State is plain objects and arrays; mutations drive reactivity via the Observer API. |
|
|
88
87
|
| 🧱 **OOHTML integration** | HTML-native templates, imports, and composition without a component DSL or build-heavy toolchain. |
|
|
89
|
-
| 📦 **Offline & worker features** | Worker-side routing, caching, background sync, and offline-first behaviors built in. |
|
|
90
88
|
| 🧩 **Dev mode & HMR** | Fast development server with fine-grained rebuilds and hot updates for HTML, JS, and CSS. |
|
|
91
89
|
|
|
92
90
|
## Get Started
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Observer,
|
|
1
|
+
import { Observer, LiveProgramHandle } from '@webqit/use-live';
|
|
2
2
|
import { _isObject, _isTypeObject } from '@webqit/util/js/index.js';
|
|
3
3
|
import { publishMutations, applyMutations } from '../webflo-messaging/wq-message-port.js';
|
|
4
4
|
import { WQBroadcastChannel } from '../webflo-messaging/WQBroadcastChannel.js';
|
|
@@ -22,9 +22,9 @@ export class LiveResponse extends EventTarget {
|
|
|
22
22
|
if (isGenerator(data)) {
|
|
23
23
|
return 'Generator';
|
|
24
24
|
}
|
|
25
|
-
if (data instanceof
|
|
26
|
-
|| data?.[Symbol.toStringTag] === '
|
|
27
|
-
return '
|
|
25
|
+
if (data instanceof LiveProgramHandle
|
|
26
|
+
|| data?.[Symbol.toStringTag] === 'LiveProgramHandle') {
|
|
27
|
+
return 'LiveProgramHandle';
|
|
28
28
|
}
|
|
29
29
|
return 'Default';
|
|
30
30
|
}
|
|
@@ -39,8 +39,8 @@ export class LiveResponse extends EventTarget {
|
|
|
39
39
|
if (this.test(data) === 'Generator') {
|
|
40
40
|
return await this.fromGenerator(data, ...args);
|
|
41
41
|
}
|
|
42
|
-
if (this.test(data) === '
|
|
43
|
-
return this.
|
|
42
|
+
if (this.test(data) === 'LiveProgramHandle') {
|
|
43
|
+
return this.fromLiveProgramHandle(data, ...args);
|
|
44
44
|
}
|
|
45
45
|
return new this(data, ...args);
|
|
46
46
|
}
|
|
@@ -137,18 +137,18 @@ export class LiveResponse extends EventTarget {
|
|
|
137
137
|
return instance;
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
static async
|
|
141
|
-
if (!this.test(
|
|
142
|
-
throw new Error('Argument must be a UseLive
|
|
140
|
+
static async fromLiveProgramHandle(liveProgramHandle, options = {}) {
|
|
141
|
+
if (!this.test(liveProgramHandle) === 'LiveProgramHandle') {
|
|
142
|
+
throw new Error('Argument must be a UseLive LiveProgramHandle instance.');
|
|
143
143
|
}
|
|
144
144
|
const instance = new this;
|
|
145
|
-
await instance.replaceWith(
|
|
145
|
+
await instance.replaceWith(liveProgramHandle.value, { done: false, ...options });
|
|
146
146
|
if (instance.#generatorType === 'Default') {
|
|
147
|
-
instance.#generator =
|
|
148
|
-
instance.#generatorType = '
|
|
147
|
+
instance.#generator = liveProgramHandle;
|
|
148
|
+
instance.#generatorType = 'LiveProgramHandle';
|
|
149
149
|
}
|
|
150
150
|
Observer.observe(
|
|
151
|
-
|
|
151
|
+
liveProgramHandle,
|
|
152
152
|
'value',
|
|
153
153
|
(e) => instance.#replaceWith(e.value),
|
|
154
154
|
{ signal: instance.#abortController.signal }
|
|
@@ -446,8 +446,8 @@ export class LiveResponse extends EventTarget {
|
|
|
446
446
|
}));
|
|
447
447
|
}
|
|
448
448
|
|
|
449
|
-
|
|
450
|
-
const state = new
|
|
449
|
+
toLiveProgramHandle({ signal: abortSignal } = {}) {
|
|
450
|
+
const state = new LiveProgramHandleX;
|
|
451
451
|
const replaceHandler = () => Observer.defineProperty(state, 'value', { value: this.body, enumerable: true, configurable: true });
|
|
452
452
|
this.addEventListener('replace', replaceHandler, { signal: abortSignal });
|
|
453
453
|
replaceHandler();
|
|
@@ -469,7 +469,7 @@ export const isGenerator = (obj) => {
|
|
|
469
469
|
typeof obj?.return === 'function';
|
|
470
470
|
};
|
|
471
471
|
|
|
472
|
-
class
|
|
472
|
+
class LiveProgramHandleX extends LiveProgramHandle {
|
|
473
473
|
constructor() { }
|
|
474
474
|
abort() { }
|
|
475
475
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { _isFunction, _isArray, _isObject } from '@webqit/util/js/index.js';
|
|
2
2
|
import { _from as _arrFrom } from '@webqit/util/arr/index.js';
|
|
3
3
|
import { LiveResponse } from '../webflo-fetch/LiveResponse.js';
|
|
4
|
+
import { request as requestShim } from '../webflo-fetch/index.js';
|
|
4
5
|
import { path as Path } from '../webflo-url/util.js';
|
|
5
6
|
|
|
6
7
|
export class WebfloRouter {
|
|
@@ -102,7 +103,7 @@ export class WebfloRouter {
|
|
|
102
103
|
// Build request inheritance chain
|
|
103
104
|
const requestInheritanceChain = [url];
|
|
104
105
|
if (!isFetch && thisTick.event.request instanceof Request) {
|
|
105
|
-
const { url: _, ...init } = await
|
|
106
|
+
const { url: _, ...init } = await requestShim.copy.value(thisTick.event.request);
|
|
106
107
|
requestInheritanceChain.push(init);
|
|
107
108
|
}
|
|
108
109
|
const noArg2 = () => {
|
|
@@ -110,7 +111,7 @@ export class WebfloRouter {
|
|
|
110
111
|
};
|
|
111
112
|
if (args[0] instanceof Request) {
|
|
112
113
|
if (args[1]) noArg2();
|
|
113
|
-
const { url: _, ...init } = await
|
|
114
|
+
const { url: _, ...init } = await requestShim.copy.value(args[0]);
|
|
114
115
|
requestInheritanceChain.push(init);
|
|
115
116
|
} else if (!isFetch && _isObject(args[0])) {
|
|
116
117
|
if (args[1]) noArg2();
|
|
@@ -173,7 +174,7 @@ export class WebfloRouter {
|
|
|
173
174
|
const returnValue = await handler.call(thisContext, thisTick.event, $next/*next*/, $fetch/*fetch*/);
|
|
174
175
|
|
|
175
176
|
// Handle cleanup on abort
|
|
176
|
-
if (LiveResponse.test(returnValue) === '
|
|
177
|
+
if (LiveResponse.test(returnValue) === 'LiveProgramHandle') {
|
|
177
178
|
thisTick.event.signal.addEventListener('abort', () => {
|
|
178
179
|
returnValue.abort();
|
|
179
180
|
});
|