@hyperspan/framework 0.1.0 → 0.1.2

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/package.json CHANGED
@@ -1,13 +1,22 @@
1
1
  {
2
2
  "name": "@hyperspan/framework",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Hyperspan Web Framework",
5
- "type": "module",
6
- "module": "src/server.ts",
5
+ "main": "dist/index.js",
7
6
  "public": true,
8
7
  "publishConfig": {
9
8
  "access": "public"
10
9
  },
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "./assets": {
16
+ "types": "./dist/assets.d.ts",
17
+ "default": "./dist/assets.js"
18
+ }
19
+ },
11
20
  "author": "Vance Lucas <vance@vancelucas.com>",
12
21
  "license": "BSD-3-Clause",
13
22
  "keywords": [
@@ -23,18 +32,22 @@
23
32
  "homepage": "https://www.hyperspan.dev",
24
33
  "repository": {
25
34
  "type": "git",
26
- "url": "https://github.com/vlucas/hyperspan-framework"
35
+ "url": "git+https://github.com/vlucas/hyperspan.git"
27
36
  },
28
37
  "bugs": {
29
- "url": "https://github.com/vlucas/hyperspan-framework/issues"
38
+ "url": "https://github.com/vlucas/hyperspan/issues"
30
39
  },
31
40
  "scripts": {
32
- "test": "bun test"
41
+ "build": "bun ./build.ts",
42
+ "clean": "rm -rf dist",
43
+ "test": "bun test",
44
+ "prepack": "npm run clean && npm run build"
33
45
  },
34
46
  "devDependencies": {
35
47
  "@types/bun": "^1.1.9",
36
48
  "@types/node": "^22.5.5",
37
49
  "@types/react": "^19.1.0",
50
+ "bun-plugin-dts": "^0.3.0",
38
51
  "bun-types": "latest",
39
52
  "prettier": "^3.2.5"
40
53
  },
@@ -42,10 +55,10 @@
42
55
  "typescript": "^5.0.0"
43
56
  },
44
57
  "dependencies": {
45
- "@hyperspan/html": "^0.1.0",
58
+ "@hyperspan/html": "^0.1.1",
46
59
  "@preact/compat": "^18.3.1",
47
60
  "hono": "^4.7.4",
48
61
  "isbot": "^5.1.25",
49
- "valibot": "^1.0.0-rc.3"
62
+ "zod": "^4.0.0-beta.20250415T232143"
50
63
  }
51
64
  }
package/src/assets.ts CHANGED
@@ -1,17 +1,17 @@
1
- import { html } from '@hyperspan/html';
2
- import { md5 } from './clientjs/md5';
3
- import { readdir } from 'node:fs/promises';
4
- import { resolve } from 'node:path';
1
+ import {html} from '@hyperspan/html';
2
+ import {md5} from './clientjs/md5';
3
+ import {readdir} from 'node:fs/promises';
4
+ import {resolve} from 'node:path';
5
5
 
6
- export const IS_PROD = process.env.NODE_ENV === 'production';
6
+ const IS_PROD = process.env.NODE_ENV === 'production';
7
7
  const PWD = import.meta.dir;
8
8
 
9
9
  /**
10
10
  * Build client JS for end users (minimal JS for Hyperspan to work)
11
11
  */
12
- export const clientJSFiles = new Map<string, { src: string; type?: string }>();
12
+ export const clientJSFiles = new Map<string, {src: string; type?: string}>();
13
13
  export async function buildClientJS() {
14
- const sourceFile = resolve(PWD, '../', './hyperspan/clientjs/hyperspan-client.ts');
14
+ const sourceFile = resolve(PWD, '../', './src/clientjs/hyperspan-client.ts');
15
15
  const output = await Bun.build({
16
16
  entrypoints: [sourceFile],
17
17
  outdir: `./public/_hs/js`,
@@ -20,7 +20,7 @@ export async function buildClientJS() {
20
20
  });
21
21
 
22
22
  const jsFile = output.outputs[0].path.split('/').reverse()[0];
23
- clientJSFiles.set('_hs', { src: '/_hs/js/' + jsFile });
23
+ clientJSFiles.set('_hs', {src: '/_hs/js/' + jsFile});
24
24
  return jsFile;
25
25
  }
26
26
 
@@ -61,7 +61,7 @@ export async function buildClientCSS() {
61
61
  export function hyperspanStyleTags() {
62
62
  const cssFiles = Array.from(clientCSSFiles.entries());
63
63
  return html`${cssFiles.map(
64
- ([key, file]) => html`<link rel="stylesheet" href="/_hs/css/${file}" />`
64
+ ([_, file]) => html`<link rel="stylesheet" href="/_hs/css/${file}" />`
65
65
  )}`;
66
66
  }
67
67
 
@@ -84,13 +84,13 @@ export function hyperspanScriptTags() {
84
84
  }
85
85
  </script>
86
86
  ${jsFiles.map(
87
- ([key, file]) =>
88
- html`<script
87
+ ([key, file]) =>
88
+ html`<script
89
89
  id="js-${key}"
90
90
  type="${file.type || 'text/javascript'}"
91
91
  src="${file.src}"
92
92
  ></script>`
93
- )}
93
+ )}
94
94
  `;
95
95
  }
96
96
 
@@ -1,5 +1,5 @@
1
- import { html } from '../html';
2
- import { Idiomorph } from './idiomorph.esm';
1
+ import {html} from '@hyperspan/html';
2
+ import {Idiomorph} from './idiomorph.esm';
3
3
 
4
4
  /**
5
5
  * Used for streaming content from the server to the client.
@@ -20,7 +20,7 @@ function htmlAsyncContentObserver() {
20
20
  asyncContent.forEach((el: any) => {
21
21
  try {
22
22
  // Also observe child nodes for nested async content
23
- asyncContentObserver.observe(el.content, { childList: true, subtree: true });
23
+ asyncContentObserver.observe(el.content, {childList: true, subtree: true});
24
24
 
25
25
  const slotId = el.id.replace('_content', '');
26
26
  const slotEl = document.getElementById(slotId);
@@ -41,7 +41,7 @@ function htmlAsyncContentObserver() {
41
41
  }
42
42
  });
43
43
  });
44
- asyncContentObserver.observe(document.body, { childList: true, subtree: true });
44
+ asyncContentObserver.observe(document.body, {childList: true, subtree: true});
45
45
  }
46
46
  }
47
47
  htmlAsyncContentObserver();
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './server';
package/src/server.ts CHANGED
@@ -5,82 +5,12 @@ import { isbot } from 'isbot';
5
5
  import { buildClientJS, buildClientCSS } from './assets';
6
6
  import { Hono } from 'hono';
7
7
  import { serveStatic } from 'hono/bun';
8
+ import * as z from 'zod';
8
9
  import type { Context, Handler } from 'hono';
9
10
 
10
- import * as v from 'valibot';
11
- import type {
12
- AnySchema,
13
- ArraySchema,
14
- BigintSchema,
15
- BooleanSchema,
16
- DateSchema,
17
- EnumSchema,
18
- GenericIssue,
19
- IntersectSchema,
20
- LazySchema,
21
- LiteralSchema,
22
- NullSchema,
23
- NullableSchema,
24
- NullishSchema,
25
- NumberSchema,
26
- ObjectSchema,
27
- ObjectWithRestSchema,
28
- OptionalSchema,
29
- PicklistSchema,
30
- PipeItem,
31
- RecordSchema,
32
- SchemaWithPipe,
33
- StrictObjectSchema,
34
- StrictTupleSchema,
35
- StringSchema,
36
- TupleSchema,
37
- TupleWithRestSchema,
38
- UndefinedSchema,
39
- UnionSchema,
40
- VariantSchema,
41
- } from 'valibot';
42
-
43
11
  export const IS_PROD = process.env.NODE_ENV === 'production';
44
- const PWD = import.meta.dir;
45
12
  const CWD = process.cwd();
46
13
 
47
- type NonPipeSchemas =
48
- | AnySchema
49
- | LiteralSchema<any, any>
50
- | NullSchema<any>
51
- | NumberSchema<any>
52
- | BigintSchema<any>
53
- | StringSchema<any>
54
- | BooleanSchema<any>
55
- | NullableSchema<any, any>
56
- | StrictObjectSchema<any, any>
57
- | ObjectSchema<any, any>
58
- | ObjectWithRestSchema<any, any, any>
59
- | RecordSchema<any, any, any>
60
- | ArraySchema<any, any>
61
- | TupleSchema<any, any>
62
- | StrictTupleSchema<any, any>
63
- | TupleWithRestSchema<readonly any[], any, any>
64
- | IntersectSchema<any, any>
65
- | UnionSchema<any, any>
66
- | VariantSchema<any, any, any>
67
- | PicklistSchema<any, any>
68
- | EnumSchema<any, any>
69
- | LazySchema<any>
70
- | DateSchema<any>
71
- | NullishSchema<any, any>
72
- | OptionalSchema<any, any>
73
- | UndefinedSchema<any>;
74
-
75
- type PipeSchema = SchemaWithPipe<[NonPipeSchemas, ...PipeItem<any, any, GenericIssue<any>>[]]>;
76
- // Type inference for valibot taken from:
77
- // @link https://github.com/gcornut/valibot-json-schema/blob/main/src/toJSONSchema/schemas.ts
78
- export type TSupportedSchema = NonPipeSchemas | PipeSchema;
79
-
80
- /**
81
- * ===========================================================================
82
- */
83
-
84
14
  /**
85
15
  * Route
86
16
  * Define a route that can handle a direct HTTP request
@@ -114,7 +44,7 @@ export function createComponent(render: () => THSComponentReturn | Promise<THSCo
114
44
  */
115
45
  export function createForm(
116
46
  renderForm: (data?: any) => THSResponseTypes,
117
- schema?: TSupportedSchema | null
47
+ schema?: z.ZodSchema | null
118
48
  ): HSFormRoute {
119
49
  return new HSFormRoute(renderForm, schema);
120
50
  }
@@ -165,12 +95,12 @@ export class HSFormRoute {
165
95
  _handlers: Record<string, Handler> = {};
166
96
  _form: THSFormRenderer;
167
97
  _methods: null | string[] = null;
168
- _schema: null | TSupportedSchema = null;
98
+ _schema: null | z.ZodSchema = null;
169
99
 
170
- constructor(renderForm: THSFormRenderer, schema: TSupportedSchema | null = null) {
100
+ constructor(renderForm: THSFormRenderer, schema: z.ZodSchema | null = null) {
171
101
  // Haz schema?
172
102
  if (schema) {
173
- type TSchema = v.InferInput<typeof schema>;
103
+ type TSchema = z.infer<typeof schema>;
174
104
  this._form = renderForm as (data: TSchema) => THSResponseTypes;
175
105
  this._schema = schema;
176
106
  } else {
@@ -178,7 +108,7 @@ export class HSFormRoute {
178
108
  }
179
109
 
180
110
  // GET request is render form by default
181
- this._handlers.GET = (ctx: Context) => renderForm(this.getDefaultData());
111
+ this._handlers.GET = () => renderForm(this.getDefaultData());
182
112
  }
183
113
 
184
114
  // Form data
@@ -187,8 +117,8 @@ export class HSFormRoute {
187
117
  return {};
188
118
  }
189
119
 
190
- type TSchema = v.InferInput<typeof this._schema>;
191
- const data = v.parse(this._schema, {});
120
+ type TSchema = z.infer<typeof this._schema>;
121
+ const data = z.parse(this._schema, {});
192
122
  return data as TSchema;
193
123
  }
194
124
 
@@ -276,8 +206,15 @@ export async function runFileRoute(RouteModule: any, context: Context): Promise<
276
206
  return routeContent;
277
207
  }
278
208
 
209
+ let routeKind = typeof routeContent;
210
+
279
211
  // Render TmplHtml if returned from route handler
280
- if (routeContent instanceof TmplHtml) {
212
+ if (
213
+ routeKind === 'object' &&
214
+ (routeContent instanceof TmplHtml ||
215
+ routeContent.constructor.name === 'TmplHtml' ||
216
+ routeContent?._kind === 'TmplHtml')
217
+ ) {
281
218
  if (streamingEnabled) {
282
219
  return new StreamResponse(renderStream(routeContent)) as Response;
283
220
  } else {
@@ -286,6 +223,8 @@ export async function runFileRoute(RouteModule: any, context: Context): Promise<
286
223
  }
287
224
  }
288
225
 
226
+ console.log('Returning unknown type... ', routeContent);
227
+
289
228
  return routeContent;
290
229
  } catch (e) {
291
230
  console.error(e);
@@ -379,7 +318,7 @@ export async function buildRoutes(config: THSServerConfig): Promise<THSRouteMap[
379
318
 
380
319
  if (dynamicPaths) {
381
320
  params = [];
382
- route = route.replace(ROUTE_SEGMENT, (match: string, p1: string, offset: number) => {
321
+ route = route.replace(ROUTE_SEGMENT, (match: string) => {
383
322
  const paramName = match.replace(/[^a-zA-Z_\.]+/g, '');
384
323
 
385
324
  if (match.includes('...')) {