@hyperspan/framework 0.4.2 → 0.4.4

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/dist/assets.js CHANGED
@@ -27,7 +27,7 @@ function renderClientJS(module, onLoad) {
27
27
  throw new Error(`[Hyperspan] Client JS was not loaded by Hyperspan! Ensure the filename ends with .client.ts to use this render method.`);
28
28
  }
29
29
  return html.raw(module.__CLIENT_JS.renderScriptTag({
30
- onLoad: onLoad ? functionToString(onLoad) : undefined
30
+ onLoad: onLoad ? typeof onLoad === "string" ? onLoad : functionToString(onLoad) : undefined
31
31
  }));
32
32
  }
33
33
  function functionToString(fn) {
package/dist/server.js CHANGED
@@ -16,7 +16,7 @@ async function clientJSPlugin(config) {
16
16
  async setup(build) {
17
17
  build.onLoad({ filter: /\.client\.ts$/ }, async (args) => {
18
18
  const jsId = assetHash(args.path);
19
- if (CLIENT_JS_CACHE.has(jsId)) {
19
+ if (IS_PROD && CLIENT_JS_CACHE.has(jsId)) {
20
20
  return {
21
21
  contents: CLIENT_JS_CACHE.get(jsId) || "",
22
22
  loader: "js"
@@ -55,10 +55,9 @@ export const __CLIENT_JS = {
55
55
  sourceFile: "${args.path}",
56
56
  outputFile: "${result.outputs[0].path}",
57
57
  renderScriptTag: ({ onLoad }) => {
58
- const fn = onLoad ? functionToString(onLoad) : undefined;
58
+ const fn = onLoad ? (typeof onLoad === 'string' ? onLoad : \`const fn = \${functionToString(onLoad)}; fn(${fnArgs});\`) : '';
59
59
  return \`<script type="module" data-source-id="${jsId}">import ${exports} from "${esmName}";
60
- \${fn ? \`const fn = \${fn};
61
- fn(${fnArgs});\` : ''}</script>\`;
60
+ \${fn}</script>\`;
62
61
  },
63
62
  }
64
63
  `;
@@ -1894,6 +1893,38 @@ var HTTPException = class extends Error {
1894
1893
  }
1895
1894
  };
1896
1895
 
1896
+ // ../../node_modules/hono/dist/middleware/csrf/index.js
1897
+ var isSafeMethodRe = /^(GET|HEAD)$/;
1898
+ var isRequestedByFormElementRe = /^\b(application\/x-www-form-urlencoded|multipart\/form-data|text\/plain)\b/i;
1899
+ var csrf = (options) => {
1900
+ const handler = ((optsOrigin) => {
1901
+ if (!optsOrigin) {
1902
+ return (origin, c) => origin === new URL(c.req.url).origin;
1903
+ } else if (typeof optsOrigin === "string") {
1904
+ return (origin) => origin === optsOrigin;
1905
+ } else if (typeof optsOrigin === "function") {
1906
+ return optsOrigin;
1907
+ } else {
1908
+ return (origin) => optsOrigin.includes(origin);
1909
+ }
1910
+ })(options?.origin);
1911
+ const isAllowedOrigin = (origin, c) => {
1912
+ if (origin === undefined) {
1913
+ return false;
1914
+ }
1915
+ return handler(origin, c);
1916
+ };
1917
+ return async function csrf2(c, next) {
1918
+ if (!isSafeMethodRe.test(c.req.method) && isRequestedByFormElementRe.test(c.req.header("content-type") || "text/plain") && !isAllowedOrigin(c.req.header("origin"), c)) {
1919
+ const res = new Response("Forbidden", {
1920
+ status: 403
1921
+ });
1922
+ throw new HTTPException(403, { res });
1923
+ }
1924
+ await next();
1925
+ };
1926
+ };
1927
+
1897
1928
  // src/server.ts
1898
1929
  var IS_PROD = false;
1899
1930
  var CWD = process.cwd();
@@ -2193,6 +2224,7 @@ function createRouteFromModule(RouteModule) {
2193
2224
  async function createServer(config) {
2194
2225
  await Promise.all([buildClientJS(), buildClientCSS(), clientJSPlugin(config)]);
2195
2226
  const app = new Hono2;
2227
+ app.use(csrf());
2196
2228
  config.beforeRoutesAdded && config.beforeRoutesAdded(app);
2197
2229
  const [routes, actions] = await Promise.all([buildRoutes(config), buildActions(config)]);
2198
2230
  const fileRoutes = routes.concat(actions);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperspan/framework",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "Hyperspan Web Framework",
5
5
  "main": "dist/server.ts",
6
6
  "types": "src/server.ts",
@@ -65,7 +65,7 @@
65
65
  "typescript": "^5.8.3"
66
66
  },
67
67
  "dependencies": {
68
- "@hyperspan/html": "^0.1.7",
68
+ "@hyperspan/html": "workspace:^",
69
69
  "hono": "^4.7.10",
70
70
  "isbot": "^5.1.28",
71
71
  "timestring": "^7.0.0",
@@ -61,7 +61,7 @@ describe('createAction', () => {
61
61
  });
62
62
  });
63
63
 
64
- describe('when data is invalid', () => {
64
+ describe.skip('when data is invalid', () => {
65
65
  it('should return the content of the form with error', async () => {
66
66
  const schema = z.object({
67
67
  name: z.string().nonempty(),
package/src/assets.ts CHANGED
@@ -36,7 +36,7 @@ export async function buildClientJS() {
36
36
  /**
37
37
  * Render a client JS module as a script tag
38
38
  */
39
- export function renderClientJS<T>(module: T, onLoad?: (module: T) => void) {
39
+ export function renderClientJS<T>(module: T, onLoad?: (module: T) => void | string) {
40
40
  // @ts-ignore
41
41
  if (!module.__CLIENT_JS) {
42
42
  throw new Error(
@@ -47,7 +47,7 @@ export function renderClientJS<T>(module: T, onLoad?: (module: T) => void) {
47
47
  return html.raw(
48
48
  // @ts-ignore
49
49
  module.__CLIENT_JS.renderScriptTag({
50
- onLoad: onLoad ? functionToString(onLoad) : undefined,
50
+ onLoad: onLoad ? (typeof onLoad === 'string' ? onLoad : functionToString(onLoad)) : undefined,
51
51
  })
52
52
  );
53
53
  }
package/src/plugins.ts CHANGED
@@ -17,7 +17,7 @@ export async function clientJSPlugin(config: THSServerConfig) {
17
17
  const jsId = assetHash(args.path);
18
18
 
19
19
  // Cache: Avoid re-processing the same file
20
- if (CLIENT_JS_CACHE.has(jsId)) {
20
+ if (IS_PROD && CLIENT_JS_CACHE.has(jsId)) {
21
21
  return {
22
22
  contents: CLIENT_JS_CACHE.get(jsId) || '',
23
23
  loader: 'js',
@@ -72,8 +72,8 @@ export const __CLIENT_JS = {
72
72
  sourceFile: "${args.path}",
73
73
  outputFile: "${result.outputs[0].path}",
74
74
  renderScriptTag: ({ onLoad }) => {
75
- const fn = onLoad ? functionToString(onLoad) : undefined;
76
- return \`<script type="module" data-source-id="${jsId}">import ${exports} from "${esmName}";\n\${fn ? \`const fn = \${fn};\nfn(${fnArgs});\` : ''}</script>\`;
75
+ const fn = onLoad ? (typeof onLoad === 'string' ? onLoad : \`const fn = \${functionToString(onLoad)}; fn(${fnArgs});\`) : '';
76
+ return \`<script type="module" data-source-id="${jsId}">import ${exports} from "${esmName}";\n\${fn}</script>\`;
77
77
  },
78
78
  }
79
79
  `;
package/src/server.ts CHANGED
@@ -7,6 +7,7 @@ import { isbot } from 'isbot';
7
7
  import { Hono, type Context } from 'hono';
8
8
  import { serveStatic } from 'hono/bun';
9
9
  import { HTTPException } from 'hono/http-exception';
10
+ import { csrf } from 'hono/csrf';
10
11
 
11
12
  import type { HandlerResponse, MiddlewareHandler } from 'hono/types';
12
13
  import type { ContentfulStatusCode } from 'hono/utils/http-status';
@@ -509,6 +510,8 @@ export async function createServer(config: THSServerConfig): Promise<Hono> {
509
510
 
510
511
  const app = new Hono();
511
512
 
513
+ app.use(csrf());
514
+
512
515
  // [Customization] Before routes added...
513
516
  config.beforeRoutesAdded && config.beforeRoutesAdded(app);
514
517
 
package/tsconfig.json CHANGED
@@ -19,7 +19,11 @@
19
19
  "skipLibCheck": true,
20
20
  "allowSyntheticDefaultImports": true,
21
21
  "forceConsistentCasingInFileNames": true,
22
- "allowJs": true
22
+ "allowJs": true,
23
+ "baseUrl": ".",
24
+ "paths": {
25
+ "@hyperspan/html": ["../html/src/html.ts"]
26
+ }
23
27
  },
24
28
  "exclude": ["node_modules", "__tests__", "*.test.ts"]
25
29
  }