@bananacool467/authtics-host 0.2.6 → 0.2.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.
@@ -0,0 +1 @@
1
+ - [Node child-process test cleanup](node-child-process-tests.md) — a signaled child can have `exitCode === null`; check `signalCode` too.
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: Node child-process test cleanup
3
+ description: Avoid hanging integration-test cleanup when a fixture server exits from a signal.
4
+ ---
5
+
6
+ When a Node child process is terminated by a signal, `exitCode` remains `null` and `signalCode` identifies how it exited. Treat either a non-null exit code or signal code as completion.
7
+
8
+ **Why:** Fixture-server tests can otherwise wait for an `exit` event that already fired and be cancelled when the event loop empties.
9
+
10
+ **How to apply:** In child-process test helpers, check both `exitCode` and `signalCode`, and register the exit listener before sending a termination signal.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Authtics Host
2
2
 
3
- Version 0.2.6, License: MIT
3
+ Version 0.2.8, License: MIT
4
4
 
5
5
  Authtics Host is a web framework inspired by Next.js. Authtics Host supports SSR (Server-Side Rendering), SSG (Static Site Generation), CSR (Client-Side Rendering) and SRTWS (Site Rendering Through WebSockets) and uses **Esbuild**. This is not to be confused with auth platforms.
6
6
 
@@ -17,6 +17,11 @@ or
17
17
  npm install @bananacool467/authtics-host@latest
18
18
  ```
19
19
 
20
+ You may have to get **React** and **React DOM**:
21
+ ```bash
22
+ npm i @types/react @types/react-dom
23
+ ```
24
+
20
25
  You can have auto paging enabled, auto paging checks your given directory for HTML and TSX files and then adds them to route. If auto filing is enabled, auto filing will check your given directory for files and add them accessible to route.
21
26
 
22
27
  To make your app, with auto paging and auto filing, your file tree should look like:
@@ -125,6 +130,36 @@ export default function Index () {
125
130
  }
126
131
  ```
127
132
 
133
+ ## Build Output Styles
134
+
135
+ HostJS supports two output layouts through `buildStyle` in `authtics_host.config.ts`.
136
+
137
+ - `default` (the default) keeps the existing `.authtics_host/` cache layout.
138
+ - `super` enables the Next.js-inspired `.hostjs/` layout with separated client/server bundler caches, route-cache files, route and middleware manifests, generated route type files, diagnostics metadata, and trace directories.
139
+
140
+ To opt in, add this to your existing `defineConfig({ ... })` object:
141
+
142
+ ```ts
143
+ buildStyle: "super"
144
+ ```
145
+
146
+ The setting is opt-in, so projects that do not specify it continue using `default`.
147
+
148
+ ## Build Triggers
149
+
150
+ HostJS supports two ways to trigger page bundle compilation using `buildTrigger` in `authtics_host.config.ts`.
151
+
152
+ - `default` (the default) compiles a TSX page on demand when a request needs it.
153
+ - `prebuilt` compiles discoverable TSX pages during Authtics Host startup, before the HTTP server begins listening. SSR pages are compiled without eagerly invoking their page components; SSG pages are rendered during startup so their static HTML is ready. Startup reports a prebuild error instead of opening the server if compilation (or SSG generation) fails.
154
+
155
+ Prebuilt mode scans the configured auto-page directory for TSX pages and also prebuilds a registered `app.registerApp(...)` entry when it points to an existing TSX file. API handlers and static files are not TSX renderer bundles, so they are not prebuilt by this option. The renderer reuses generated caches in both `default` and `super` build styles.
156
+
157
+ To opt in, add this to your existing `defineConfig({ ... })` object:
158
+
159
+ ```ts
160
+ buildTrigger: "prebuilt"
161
+ ```
162
+
128
163
  ## To Run The Project
129
164
 
130
165
  Make sure **Node 22** is installed:
@@ -142,12 +177,21 @@ To run the project use:
142
177
  node --experimental-strip-types index.ts
143
178
  ```
144
179
 
180
+ Or:
181
+ ```
182
+ hostjs start
183
+ ```
184
+
145
185
  ## Result
146
186
 
147
187
  Then when you run your project, you will get a page just saying **"Hello, World!"** and you should see a clickable Developer Panel at the bottom-right.
148
188
 
189
+ ![Result](assets/result.jpg)
190
+
149
191
  ## About The Developer Panel
150
192
 
193
+ ![Developer Panel](assets/dev_panel.jpg)
194
+
151
195
  The Developer Panel is what you could use to help you debug your code. The Developer Panel has **8 tabs**:
152
196
 
153
197
  * **Console** — Shows current logs.
@@ -187,11 +231,42 @@ Pages may fail to render in SSR if it uses `window` instead of assigning it to a
187
231
 
188
232
  You can fix this by adding this to your config file:
189
233
  ```json
190
- "patchForSsr": true
234
+ "patchForServer": true
191
235
  ```
192
236
 
193
237
  It makes a fake `window`, `document`, etc for SSR when building for Node. Which fixes the issue.
194
238
 
239
+ ## Browser API
240
+
241
+ You can set, delete and get cookies using Authtics Host's BrowserAPI (BAPI) feature. Example:
242
+
243
+ ```typescript
244
+ import {
245
+ Cookies
246
+ } from "@bananacool467/authtics-host";
247
+
248
+ const cookies = new Cookies();
249
+ // set
250
+ cookies.set("name", "value");
251
+ // get
252
+ const data = cookies.get("name");
253
+ // delete
254
+ cookies.del("name");
255
+ ```
256
+
257
+ You can also enable stuff on cookies, like:
258
+ * **Secure**
259
+ * **Max Age / Expires**
260
+ * **Same Site**
261
+
262
+ Example:
263
+ ```typescript
264
+ cookies.set("name", "value", true, "Lax", 2 * 24 * 60 * 60);
265
+ ```
266
+ * **Secure** is `true`
267
+ * **Same Site** is `Lax`
268
+ * **Max Age** is `2 * 24 * 60 * 60` (2 days)
269
+
195
270
  ## App APIs
196
271
 
197
272
  You can add APIs like `get`, `post`, `del` and `put`.
@@ -207,13 +282,73 @@ Then when you go to `/hi` you see:
207
282
  Hello!
208
283
  ```
209
284
 
285
+ You can add an `on` event onto the Node.js server by using `on(event, handler)`, example:
286
+ ```typescript
287
+ app.on("upgrade", (req, socket, head) => {
288
+ if (req.headers['upgrade'] && req.headers['upgrade'].toLowerCase() === 'websocket') {
289
+ // any code here
290
+ }
291
+ });
292
+ ```
293
+
294
+ You can also add an `use` event onto the HostJS App, when a user visits the page, the first `use` event runs on it before reaching any other route, any other `use` event doesn't run until you call `next()`. Example:
295
+ ```typescript
296
+ app.use((req, res, id, next) => {
297
+ console.log("Request cookies: " + req.cookies);
298
+ return next();
299
+ });
300
+
301
+ app.use((req, res, id, next) => {
302
+ console.log("2nd USE event ran.");
303
+ });
304
+
305
+ app.use((req, res, id, next) => {
306
+ console.log("3rd...");
307
+ })
308
+ ```
309
+
310
+ The 3rd USE event will never run because the 2nd USE event didnt use `next()`.
311
+
312
+ ## SRTWS
313
+
314
+ SRTWS is **Site Rendering Through WebSockets**, its currently in BETA.
315
+
316
+ When a client visits your site if renderer is set to SRTWS, a **SRTWS server** starts and the client connects to it. Then, the **SRTWS server** sends the entire compiled TSX to the client.
317
+
318
+ ## REQuest APIs
319
+
320
+ The `req` variable (like used in `app.get`) is an extension of the ***Node.js HTTP IncomingMessage*** class, the added items in `req` are:
321
+
322
+ * **dat** (`req.dat`) — The user's DAT cookie for the current App.
323
+ * **cookies** (`req.cookies`) — All the extracted user's cookies for the current App.
324
+ * **body** (`req.body` for POST) — The parsed `body` that was sent from client.
325
+ * **ip** (`req.ip`) — The request's IP.
326
+ * **ipType** (`req.ipType`) — The IP's type as a number, 6 is IPv6, 4 is IPv4, 0 is unknown.
327
+ * **ua** (`req.ua`) — The request's UserAgent.
328
+ * **os** (`req.os`) — The request's OS from the UserAgent.
329
+ * **browser** (`req.browser`) — The request's browser from the UserAgent.
330
+ * **sentTime** (`req.sentTim.e`) — When the request was sent
331
+ * **bodySize** (`req.bodySize` for POST) — The size of the body. (`req.body`)
332
+ * **bodyType** (`req.bodyType`) — The Content-Type of the body. (`req.body`)
333
+
334
+ ## RESponse APIs
335
+
336
+ The `res` variable (like used in `app.get`) is an extension of the ***Node.js HTTP ServerResponse*** class, the added items in `res` are:
337
+
338
+ * **redirect** (`res.redirect(url)`) — Send the client to another URL.
339
+ * **html** (`res.html(content)`) — Return HTML to the client.
340
+ * **json** (`res.json(content)`) — Return JSON to the client.
341
+ * **text** (`res.text(content)`) — Return plain text to the client.
342
+ * **file** (`res.file(path)`) — Let HostJS read the provided file path and return the file content to the client.
343
+ * **status** (`res.status(code)`) — Change the server's status code, returns new **ServerResponse** object.
344
+ * **reload** (`res.reload()`) — Send a reload request to the client.
345
+ * **setCookie** (`res.setCookie(name, value)`) — Set a cookie on the client.
346
+ * **rmvCookie** (`res.rmvCookie(name)`) — Remove a cookie from the client.
347
+
210
348
  ## Notes about Authtics Host
211
349
 
212
350
  The developer might redesign the UI for the DevPanel using [UI Tools](https://npmjs.com/package/@bananakitssu/ui-tools).
213
351
 
214
- > **Warning**:
215
- > SRTWS may not work properly. It may render pages, but not run scripts.
216
-
217
352
  > **Warning**:
218
353
  > Asking AI about HostJS is not recommended, it will give an Auth platform and call HostJS/Authtics Host a typo, say it doesn't exist, say it was renamed, it is private, or the account doesn't exist. Or if it knows, it may swap your server script with regular **Node.js**/**ExpressJS**/**Next.js** or use **Next.js-like** code because this framework is **Next.js-inspired**
219
354
 
@@ -241,10 +376,37 @@ There isn't any limit of DATs you can add.
241
376
 
242
377
  **(Note: Adding your DAT will give you access to Restart and Shutdown and Pause/Resume Users and other features in the Developer Panel)**
243
378
 
379
+ ## HostJS commands
380
+
381
+ There are 3 different HostJS commands:
382
+
383
+ ```bash
384
+ hostjs -v
385
+ # or:
386
+ hostjs --version
387
+ # or:
388
+ hostjs version
389
+ ```
390
+ Returns the current HostJS *version*.
391
+
392
+ ```bash
393
+ hostjs help
394
+ ```
395
+ Returns all the avaliable HostJS commands.
396
+
397
+ ```bash
398
+ hostjs start
399
+ ```
400
+ Runs `node --experimental-strip-types index.ts` but you can use:
401
+ ```bash
402
+ hostjs start path/to/script.ts
403
+ ```
404
+ Which runs the same command but uses the path to the script instead of `index.ts`
405
+
244
406
  ## Reasons for the name, Authtics Host
245
407
 
246
408
  I named this web framework Authtics Host because it uses DAT (For the **Auth**tics part) for developer authentication for dev panel, and for "Host" is because it let's the developer **Restart**/**Shutdown** the server.
247
409
 
248
410
  ## Contacting The Developer Of Authtics Host
249
411
 
250
- If you have any questions, or encountered a bug while using HostJS, contact: authtics@proton.me
412
+ If you have any questions, or encountered a bug while using HostJS, contact: authtics@proton.me
Binary file
Binary file
package/bin/hostjs.js ADDED
@@ -0,0 +1,62 @@
1
+ import { parseArgs } from 'node:util';
2
+ import { logger } from './logger.js';
3
+ import { spawnSync } from 'node:child_process';
4
+ import path from "node:path";
5
+ import fs from "node:fs/promises";
6
+ import url from "node:url";
7
+
8
+ const { positionals } = parseArgs({
9
+ allowPositionals: true
10
+ });
11
+
12
+ const [arg, arg2] = positionals;
13
+ if ( !arg ) {
14
+ process.exit(0);
15
+ }
16
+
17
+ if ( arg != "help" && arg != "version" && arg != "--version" && arg != "start" && arg != "-v" ) {
18
+ logger.error(`Unknown command: \x1b[33m${arg}`);
19
+ logger.skip();
20
+ logger.notice("You can get commands by typing \"hostjs help\".");
21
+ process.exit(1);
22
+ } else if ( arg == "help" ) {
23
+ logger.log("Avaliable HostJS commands:");
24
+ logger.skip();
25
+ logger.log(" help => Get help with HostJS commands.");
26
+ logger.log(" version => See the current downloaded version.");
27
+ logger.log(" [-v|--version] => Other ways to get version.");
28
+ logger.log(" start => Start your website.");
29
+ } else if ( arg == "start" ) {
30
+ logger.notice("Starting...");
31
+ let file = "index.ts";
32
+ const command = "node";
33
+ const commandArg = "--experimental-strip-types";
34
+ if ( arg2 != null ) file = arg2;
35
+
36
+ const result = spawnSync(command, [commandArg, file], { stdio: 'inherit' });
37
+
38
+ if ( result.status !== 0 ) {
39
+ logger.error(`Process exited with code ${result.status}`);
40
+ process.exit(result.status || 1);
41
+ }
42
+ } else if ( arg == "-v" || arg == "version" || arg == "--version" ) {
43
+ const __filename = url.fileURLToPath(import.meta.url);
44
+ const __dirname = path.dirname(__filename);
45
+ const packageJsonPath = path.join(__dirname, '..', 'package.json');
46
+ async function loadPackageConfig() {
47
+ try {
48
+ const rawData = await fs.readFile(packageJsonPath, 'utf-8');
49
+
50
+ const packageJson = JSON.parse(rawData);
51
+
52
+ return packageJson
53
+ } catch (error) {
54
+ logger.error('Failed to read package.json:', error);
55
+ process.exit(1);
56
+ }
57
+ }
58
+
59
+ const package_ = await loadPackageConfig();
60
+ logger.notice(`Authtics Host version: ${package_.version}`);
61
+ }
62
+ process.exit(0);
package/bin/logger.js ADDED
@@ -0,0 +1,29 @@
1
+ function skip () {
2
+ return console.log('');
3
+ }
4
+
5
+ function error (msg) {
6
+ return console.error(`[HostJS \x1b[31mError\x1b[0m]: \x1b[31m${msg}\x1b[0m`);
7
+ }
8
+
9
+ function notice (msg) {
10
+ return console.log(`[HostJS \x1b[32mNotice\x1b[0m]: \x1b[32m${msg}\x1b[0m`)
11
+ }
12
+
13
+ function log (msg) {
14
+ return console.log(msg);
15
+ }
16
+
17
+ function warn (msg) {
18
+ return console.log(`[HostJS \x1b[33mWarn\x1b[0m]: \x1b[33m${msg}\x1b[0m`)
19
+ }
20
+
21
+ const logger = {
22
+ skip,
23
+ error,
24
+ notice,
25
+ log,
26
+ warn
27
+ }
28
+
29
+ export { logger };
@@ -0,0 +1,10 @@
1
+ type bAPI = 'navigator' | 'window' | 'document' | 'location' | 'localStorage' | 'sessionStorage' | 'fetch' | 'XMLHttpRequest';
2
+ export declare function load(browserAPI: bAPI): Promise<any>;
3
+ export declare class Cookies {
4
+ private Document;
5
+ constructor();
6
+ set(name: string, value: string, sameSite?: string, Secure?: boolean, MaxAge?: number | null): Promise<void>;
7
+ get(name: string): Promise<string | undefined>;
8
+ del(name: string): Promise<void>;
9
+ }
10
+ export {};
@@ -0,0 +1,53 @@
1
+ 'use strict';
2
+ export async function load(browserAPI) {
3
+ while (typeof window === "undefined") {
4
+ return null;
5
+ }
6
+ const apiMap = {
7
+ navigator: window.navigator,
8
+ window: window,
9
+ document: window.document,
10
+ location: window.location,
11
+ localStorage: window.localStorage,
12
+ sessionStorage: window.sessionStorage,
13
+ fetch: window.fetch.bind(window),
14
+ XMLHttpRequest: window.XMLHttpRequest
15
+ };
16
+ return apiMap[browserAPI];
17
+ }
18
+ export class Cookies {
19
+ Document;
20
+ constructor() {
21
+ this.Document = load('document');
22
+ }
23
+ async set(name, value, sameSite = "Lax", Secure = true, MaxAge = null) {
24
+ const Document = this.Document;
25
+ const cookieParts = [`${encodeURIComponent(name)}=${encodeURIComponent(value)}`, "Path=/"];
26
+ if (MaxAge !== null) {
27
+ cookieParts.push(`max-age=${MaxAge}`);
28
+ const d = new Date();
29
+ d.setTime(d.getTime() + (MaxAge * 1000));
30
+ cookieParts.push(`expires=${d.toUTCString()}`);
31
+ }
32
+ if (Secure)
33
+ cookieParts.push("secure");
34
+ if (sameSite)
35
+ cookieParts.push(`samesite=${sameSite}`);
36
+ Document.cookie = cookieParts.join("; ");
37
+ }
38
+ async get(name) {
39
+ const Document = this.Document;
40
+ const cookies = Document.cookie.split(";").filter(Boolean);
41
+ for (const c of cookies) {
42
+ const [key, ...valParts] = c.trim().split("=");
43
+ if (decodeURIComponent(key) === name) {
44
+ return decodeURIComponent(valParts.join("="));
45
+ }
46
+ }
47
+ return undefined;
48
+ }
49
+ async del(name) {
50
+ const Document = await load('document');
51
+ Document.cookie = `${encodeURIComponent(name)}=; path=/; max-age=0; samesite=Lax; secure`;
52
+ }
53
+ }
package/dist/cli.d.ts CHANGED
@@ -1,13 +1,15 @@
1
1
  #!/usr/bin/env node
2
- import { IncomingMessage, ServerResponse } from "node:http";
2
+ import { IncomingMessage, ServerResponse, Server } from "node:http";
3
3
  export default class App {
4
- server: any;
4
+ server: Server | null | undefined;
5
5
  constructor();
6
6
  startServer(): Promise<void>;
7
- get(routePath: string, handler: (req: IncomingMessage, res: ServerResponse) => void): void;
8
7
  registerApp(route: string): void;
8
+ get(routePath: string, handler: (req: IncomingMessage, res: ServerResponse) => void): void;
9
9
  post(routePath: string, handler: (req: IncomingMessage, res: ServerResponse) => void): void;
10
10
  put(routePath: string, handler: (req: IncomingMessage, res: ServerResponse) => void): void;
11
11
  delete(routePath: string, handler: (req: IncomingMessage, res: ServerResponse) => void): void;
12
+ use(handler: (req: IncomingMessage, res: ServerResponse, id: bigint | null, next: Function) => void): void;
13
+ on(method: string, handler: (...args: any[]) => void): void;
12
14
  remove(method: string, routePath: string): void;
13
15
  }