@tinyfx/runtime 0.1.6 → 0.1.8

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,16 +1,15 @@
1
1
  # @tinyfx/runtime
2
2
 
3
- > The minimal, browser-side runtime for tinyfx.
4
-
5
- A lightweight collection of helpers for reactivity, DOM manipulation, and typed HTTP communication. Designed to be used standalone or as part of the `tinyfx` build pipeline.
3
+ The TinyFX browser runtime: signals, DOM helpers, typed HTTP, and router lifecycle utilities.
6
4
 
7
5
  ## Features
8
6
 
9
- - **Signals** Explicit reactivity without Proxies.
10
- - **DOM Helpers** One-way bindings for text, attributes, and classes.
11
- - **Typed HTTP** Minimal wrapper over `fetch` with response typing.
12
- - **DI Container** — Simple `provide()`/`inject()` registry for app services.
13
- - **Tiny** No dependencies, tree-shakeable, and extremely fast.
7
+ - Signals (`signal`, `effect`)
8
+ - DOM binding helpers (`bindText`, `bindAttr`, `bindClass`)
9
+ - Typed HTTP client (`createHttp`)
10
+ - Router helpers (`initRouter`, `navigate`, `goBack`, `getParam`)
11
+ - Lifecycle hooks (`onMount`, `onDestroy`)
12
+ - Lightweight `TinyFxContext` (`params`, `navigate`)
14
13
 
15
14
  ## Installation
16
15
 
@@ -20,27 +19,21 @@ npm install @tinyfx/runtime
20
19
 
21
20
  ## Usage
22
21
 
23
- ### Signals (Reactivity)
24
-
25
- Signals provide a simple way to manage state that triggers effects when changed.
22
+ ### Signals
26
23
 
27
24
  ```ts
28
25
  import { signal, effect } from "@tinyfx/runtime";
29
26
 
30
27
  const count = signal(0);
31
28
 
32
- // Runs immediately, and re-runs whenever count() changes
33
29
  effect(() => {
34
- console.log("The count is:", count());
30
+ console.log("count:", count());
35
31
  });
36
32
 
37
- count.set(1); // logs: "The count is: 1"
38
- count.set(count() + 1); // logs: "The count is: 2"
33
+ count.set(count() + 1);
39
34
  ```
40
35
 
41
- ### DOM Bindings
42
-
43
- Keep your JS decoupled from the DOM while maintaining reactive updates.
36
+ ### DOM bindings
44
37
 
45
38
  ```ts
46
39
  import { signal, bindText, bindClass, bindAttr } from "@tinyfx/runtime";
@@ -51,132 +44,66 @@ const isActive = signal(false);
51
44
  const el = document.getElementById("counter");
52
45
  const btn = document.querySelector("button");
53
46
 
54
- bindText(el, () => `Count: ${count()}`);
55
- bindClass(btn, "active", isActive);
56
- bindAttr(btn, "disabled", () => count() > 10);
57
- ```
58
-
59
- ### Typed HTTP Client
60
-
61
- A thin wrapper over `fetch` that returns typed responses.
62
-
63
- ```ts
64
- import { createHttp } from "@tinyfx/runtime";
65
-
66
- interface User {
67
- id: number;
68
- name: string;
47
+ if (el && btn) {
48
+ bindText(el, () => `Count: ${count()}`);
49
+ bindClass(btn, "active", isActive);
50
+ bindAttr(btn, "disabled", () => count() > 10);
69
51
  }
70
-
71
- const api = createHttp({ baseUrl: "/api" });
72
-
73
- // Fully typed response
74
- const users = await api.get<User[]>("/users");
75
-
76
- // POST with data
77
- await api.post("/users", { name: "Alice" });
78
52
  ```
79
53
 
80
- ### DI Container (provide / inject)
81
-
82
- TinyFX includes a small dependency injection container to avoid importing singleton instances everywhere.
83
-
84
- Import it from `@tinyfx/runtime/di`:
54
+ ### HTTP client
85
55
 
86
56
  ```ts
87
- import { Container } from "@tinyfx/runtime/di";
88
-
89
- class Config {
90
- constructor(public baseUrl: string) {}
91
- }
92
-
93
- const container = new Container();
94
- container.provide(Config, new Config("/api"));
95
-
96
- const cfg = container.inject(Config);
97
- console.log(cfg.baseUrl);
98
- ```
99
-
100
- #### Using DI with tinyfx components
101
-
102
- When you use the tinyfx compiler, the generated glue calls your component behavior as:
57
+ import { createHttp } from "@tinyfx/runtime";
103
58
 
104
- ```ts
105
- init(el, { container })
59
+ const http = createHttp({ baseUrl: "/api" });
60
+ const users = await http.get<{ id: number; name: string }[]>("/users");
106
61
  ```
107
62
 
108
- So your component can inject services without importing global singletons:
63
+ ### TinyFxContext
109
64
 
110
65
  ```ts
111
- import type { TinyFxContext } from "@tinyfx/runtime/di";
112
- import { HttpService } from "../lib/http.service";
66
+ import type { TinyFxContext } from "@tinyfx/runtime";
113
67
 
114
68
  export function init(el: HTMLElement, ctx: TinyFxContext) {
115
- const http = ctx.container.inject(HttpService);
116
- http.getWeather().then((text) => {
117
- el.textContent = text;
118
- });
69
+ console.log(ctx.params);
70
+ ctx.navigate("/about");
119
71
  }
120
72
  ```
121
73
 
122
- #### Example: service that uses the HTTP helper
74
+ ### Router + lifecycle hooks
123
75
 
124
76
  ```ts
125
- // src/lib/http.service.ts
126
- import { createHttp } from "@tinyfx/runtime";
127
-
128
- export class HttpService {
129
- private readonly http;
77
+ import { initRouter, onMount, onDestroy } from "@tinyfx/runtime";
130
78
 
131
- constructor(baseUrl: string) {
132
- this.http = createHttp({ baseUrl });
133
- }
134
-
135
- getWeather() {
136
- // wttr.in can return plain text; your wrapper returns text when not JSON.
137
- return this.http.get<string>("");
138
- }
139
- }
140
- ```
141
-
142
- ```ts
143
- // src/main.ts
144
- import { Container } from "@tinyfx/runtime/di";
145
- import { setupComponents } from "./tinyfx.gen";
146
- import { HttpService } from "./lib/http.service";
79
+ initRouter({
80
+ "/": { page: "index", path: "/" },
81
+ });
147
82
 
148
- const container = new Container();
149
- container.provide(HttpService, new HttpService("https://wttr.in/tunisa"));
83
+ onMount(() => {
84
+ console.log("mounted");
85
+ });
150
86
 
151
- document.addEventListener("DOMContentLoaded", () => {
152
- setupComponents(container);
87
+ onDestroy(() => {
88
+ console.log("destroyed");
153
89
  });
154
90
  ```
155
91
 
156
- ## API Overview
157
-
158
- ### Signals
159
- - `signal<T>(value: T): Signal<T>`
160
- - `effect(fn: () => void): void`
161
-
162
- ### DOM
163
- - `bindText(el: HTMLElement, source: Signal<any> | (() => any)): void`
164
- - `bindAttr(el: HTMLElement, attr: string, source: Signal<any> | (() => any)): void`
165
- - `bindClass(el: HTMLElement, className: string, source: Signal<boolean> | (() => boolean)): void`
166
-
167
- ### HTTP
168
- - `createHttp(config: HttpConfig): HttpClient`
169
- - `client.get<T>(url: string): Promise<T>`
170
- - `client.post<T>(url: string, data?: any): Promise<T>`
171
- - `client.put<T>(url: string, data?: any): Promise<T>`
172
- - `client.del<T>(url: string): Promise<T>`
173
-
174
- ### DI
175
- - `new Container()`
176
- - `container.provide(token, instance)`
177
- - `container.inject(token)`
178
- - `createToken<T>(description: string): symbol`
179
- - `TinyFxContext` (passed to component init via tinyfx glue)
92
+ ## API overview
93
+
94
+ - `signal<T>(value: T)`
95
+ - `effect(fn)`
96
+ - `bindText(el, source)`
97
+ - `bindAttr(el, attr, source)`
98
+ - `bindClass(el, className, source)`
99
+ - `createHttp(config?)`
100
+ - `initRouter(routes)`
101
+ - `getParam(name)`
102
+ - `navigate(path)`
103
+ - `goBack()`
104
+ - `onMount(fn)`
105
+ - `onDestroy(fn)`
106
+ - `TinyFxContext`
180
107
 
181
108
  ## License
182
109
 
@@ -0,0 +1,4 @@
1
+ export interface TinyFxContext {
2
+ params: Record<string, string>;
3
+ navigate: (path: string) => void;
4
+ }
@@ -0,0 +1,3 @@
1
+ // Lightweight page context passed to components by the runtime.
2
+ // Not a DI container — services are created explicitly via factory functions.
3
+ export {};
package/dist/http.d.ts CHANGED
@@ -1,10 +1,2 @@
1
- export interface HttpConfig {
2
- baseUrl?: string;
3
- headers?: Record<string, string>;
4
- }
5
- export declare function createHttp(config?: HttpConfig): {
6
- get: <T>(url: string) => Promise<T>;
7
- post: <T>(url: string, body?: unknown) => Promise<T>;
8
- put: <T>(url: string, body?: unknown) => Promise<T>;
9
- del: <T>(url: string) => Promise<T>;
10
- };
1
+ export { createHttp } from "./http/http";
2
+ export type { HttpConfig } from "./http/data";
package/dist/http.js CHANGED
@@ -1,38 +1 @@
1
- // @tinyfx/runtime HTTP client
2
- // Thin, typed wrapper over fetch.
3
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
4
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5
- return new (P || (P = Promise))(function (resolve, reject) {
6
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
7
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
8
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
9
- step((generator = generator.apply(thisArg, _arguments || [])).next());
10
- });
11
- };
12
- export function createHttp(config = {}) {
13
- var _a, _b;
14
- const base = (_a = config.baseUrl) !== null && _a !== void 0 ? _a : "";
15
- const defaultHeaders = (_b = config.headers) !== null && _b !== void 0 ? _b : {};
16
- function request(method, url, body) {
17
- return __awaiter(this, void 0, void 0, function* () {
18
- const headers = Object.assign({}, defaultHeaders);
19
- if (body !== undefined) {
20
- headers["Content-Type"] = "application/json";
21
- }
22
- const res = yield fetch(base + url, {
23
- method,
24
- headers,
25
- body: body !== undefined ? JSON.stringify(body) : undefined,
26
- });
27
- if (!res.ok)
28
- throw new Error(`${method} ${url}: ${res.status} ${res.statusText}`);
29
- return res.json();
30
- });
31
- }
32
- return {
33
- get: (url) => request("GET", url),
34
- post: (url, body) => request("POST", url, body),
35
- put: (url, body) => request("PUT", url, body),
36
- del: (url) => request("DELETE", url),
37
- };
38
- }
1
+ export { createHttp } from "./http/http";
package/dist/index.d.ts CHANGED
@@ -1,11 +1,7 @@
1
- export { signal, effect, Signal } from "./signals";
1
+ export { signal, effect } from "./signals";
2
2
  export { bindText, bindAttr, bindClass } from "./dom";
3
- export { createHttp } from "./http/http";
4
- export type { HttpConfig } from "./http/data";
5
- export { Container, createToken } from "./di";
6
- export type { Token, TinyFxContext } from "./di";
7
- export { initRouter } from "./router/index";
8
- export { getParam } from "./router/params";
3
+ export { createHttp } from "./http";
4
+ export { initRouter, getParam, navigate, goBack } from "./router/index";
9
5
  export { onMount, onDestroy } from "./router/lifecycle";
10
- export { navigate, goBack } from "./router/navigate";
6
+ export type { TinyFxContext } from "./context";
11
7
  export type { RouteMap, RouteMeta } from "./router/types";
package/dist/index.js CHANGED
@@ -1,10 +1,6 @@
1
1
  // @tinyfx/runtime — barrel export
2
- export { signal, effect, Signal } from "./signals";
2
+ export { signal, effect } from "./signals";
3
3
  export { bindText, bindAttr, bindClass } from "./dom";
4
- export { createHttp } from "./http/http";
5
- export { Container, createToken } from "./di";
6
- // Router — hard file-based router
7
- export { initRouter } from "./router/index";
8
- export { getParam } from "./router/params";
4
+ export { createHttp } from "./http";
5
+ export { initRouter, getParam, navigate, goBack } from "./router/index";
9
6
  export { onMount, onDestroy } from "./router/lifecycle";
10
- export { navigate, goBack } from "./router/navigate";
@@ -1,5 +1,8 @@
1
1
  import type { RouteMap } from "./types";
2
+ import { navigate, goBack } from "./navigate";
3
+ import { getParam } from "./params";
2
4
  export type { RouteMap };
5
+ export { navigate, goBack, getParam };
3
6
  /**
4
7
  * Initialise the TinyFX router for the current page.
5
8
  *
@@ -1,7 +1,9 @@
1
1
  // @tinyfx/runtime — router entry point
2
- import { resolveParams } from "./params";
2
+ import { navigate, goBack } from "./navigate";
3
+ import { getParam, resolveParams } from "./params";
3
4
  import { initLifecycle } from "./lifecycle";
4
5
  import { highlightActiveLinks } from "./active-links";
6
+ export { navigate, goBack, getParam };
5
7
  /**
6
8
  * Initialise the TinyFX router for the current page.
7
9
  *
@@ -8,7 +8,11 @@ const destroyCallbacks = [];
8
8
  * - If the document is already loaded, the callback runs immediately.
9
9
  */
10
10
  export function onMount(fn) {
11
- mountCallbacks.push(fn);
11
+ if (document.readyState === "loading") {
12
+ mountCallbacks.push(fn);
13
+ return;
14
+ }
15
+ fn();
12
16
  }
13
17
  /**
14
18
  * Register a callback to run when the user navigates away from this page.
@@ -16,3 +16,4 @@ export declare function resolveParams(pattern: string, pathname: string): boolea
16
16
  * getParam("slug"); // → "hello-world"
17
17
  */
18
18
  export declare function getParam(key: string): string | undefined;
19
+ export declare function getParams(): Record<string, string>;
@@ -40,3 +40,6 @@ export function resolveParams(pattern, pathname) {
40
40
  export function getParam(key) {
41
41
  return currentParams[key];
42
42
  }
43
+ export function getParams() {
44
+ return Object.assign({}, currentParams);
45
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tinyfx/runtime",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "Minimal frontend runtime — signals, DOM helpers, typed HTTP, DTO mapping",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -10,7 +10,6 @@
10
10
  "./signals": "./dist/signals.js",
11
11
  "./dom": "./dist/dom.js",
12
12
  "./http": "./dist/http.js",
13
- "./di": "./dist/di.js",
14
13
  "./router": "./dist/router/index.js"
15
14
  },
16
15
  "files": [