altair-koa-middleware 8.2.7 → 8.3.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.
@@ -1,8 +1,8 @@
1
1
 
2
- > altair-koa-middleware@8.2.7 bootstrap /home/runner/work/altair/altair/packages/altair-koa-middleware
2
+ > altair-koa-middleware@8.3.0 bootstrap /home/runner/work/altair/altair/packages/altair-koa-middleware
3
3
  > pnpm declarations
4
4
 
5
5
 
6
- > altair-koa-middleware@8.2.7 declarations /home/runner/work/altair/altair/packages/altair-koa-middleware
6
+ > altair-koa-middleware@8.3.0 declarations /home/runner/work/altair/altair/packages/altair-koa-middleware
7
7
  > tsc --declaration
8
8
 
@@ -1,8 +1,16 @@
1
+ import { ParameterizedContext } from 'koa';
1
2
  import * as KoaRouter from '@koa/router';
2
3
  import { RenderOptions } from 'altair-static';
3
- export declare const createRouteExplorer: ({ router, url, opts, }: {
4
+ export interface AltairKoaMiddlewareOptions {
4
5
  router: KoaRouter;
5
6
  url: string;
6
7
  opts: RenderOptions;
7
- }) => void;
8
+ /**
9
+ * Generates a Content Security Policy (CSP) nonce for the request.
10
+ * @param ctx The Koa context.
11
+ * @returns The generated CSP nonce.
12
+ */
13
+ cspNonceGenerator?: (ctx: ParameterizedContext) => string;
14
+ }
15
+ export declare const createRouteExplorer: ({ router, url, opts, cspNonceGenerator, }: AltairKoaMiddlewareOptions) => void;
8
16
  //# sourceMappingURL=index.d.ts.map
@@ -3,18 +3,27 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createRouteExplorer = void 0;
4
4
  const send_1 = require("@koa/send");
5
5
  const altair_static_1 = require("altair-static");
6
- const createRouteExplorer = ({ router, url, opts, }) => {
6
+ const createRouteExplorer = ({ router, url, opts, cspNonceGenerator, }) => {
7
7
  router.get(url, async (ctx, next) => {
8
- ctx.body = (0, altair_static_1.renderAltair)({ baseURL: ctx.url.replace(/\/?$/, '/'), ...opts });
8
+ const cspNonce = opts.cspNonce ?? cspNonceGenerator?.(ctx);
9
+ ctx.body = (0, altair_static_1.renderAltair)({
10
+ baseURL: ctx.url.replace(/\/?$/, '/'),
11
+ ...opts,
12
+ cspNonce,
13
+ });
9
14
  await next();
10
15
  });
11
16
  // Use the main favicon for my API subdomain.
12
- router.get(`${url}/favicon.ico`, ctx => {
17
+ router.get(`${url}/favicon.ico`, (ctx) => {
13
18
  ctx.status = 301;
14
19
  ctx.redirect(`/favicon.ico`);
15
20
  });
16
- router.get(`${url}/:path+`, async (ctx) => {
21
+ router.get(`${url}/*path`, async (ctx) => {
17
22
  const path = ctx.params.path;
23
+ // Disable CSP for the sandbox iframe
24
+ if (path && (0, altair_static_1.isSandboxFrame)(path)) {
25
+ ctx.set('Content-Security-Policy', '');
26
+ }
18
27
  await (0, send_1.send)(ctx, path || '', { root: (0, altair_static_1.getDistDirectory)() });
19
28
  });
20
29
  };
package/package.json CHANGED
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "name": "altair-koa-middleware",
3
3
  "description": "Koa middleware for altair graphql client",
4
- "version": "8.2.7",
4
+ "version": "8.3.0",
5
5
  "author": "Samuel Imolorhe <altair@sirmuel.design> (https://sirmuel.design)",
6
6
  "bugs": "https://github.com/altair-graphql/altair/issues",
7
7
  "dependencies": {
8
8
  "@koa/send": "^6.0.0",
9
- "altair-static": "8.2.7"
9
+ "altair-static": "8.3.0"
10
10
  },
11
11
  "devDependencies": {
12
12
  "@types/jest": "^27.0.1",
13
- "@types/koa": "^2.15.0",
13
+ "@types/koa": "^3.0.0",
14
14
  "@types/koa__router": "^12.0.4",
15
15
  "@types/node": "^22.7.4",
16
16
  "@types/supertest": "^6.0.2",
17
17
  "jest": "29.4.1",
18
- "koa": "^2.16.1",
18
+ "koa": "^3.0.1",
19
19
  "nodemon": "^2.0.12",
20
20
  "supertest": "^7.0.0",
21
21
  "ts-jest": "29.0.5",
package/src/index.ts CHANGED
@@ -1,32 +1,55 @@
1
1
  'use strict';
2
2
 
3
+ import { ParameterizedContext } from 'koa';
3
4
  import { send } from '@koa/send';
4
5
  import * as KoaRouter from '@koa/router';
5
- import { getDistDirectory, renderAltair, RenderOptions } from 'altair-static';
6
+ import {
7
+ getDistDirectory,
8
+ renderAltair,
9
+ RenderOptions,
10
+ isSandboxFrame,
11
+ } from 'altair-static';
6
12
 
13
+ export interface AltairKoaMiddlewareOptions {
14
+ router: KoaRouter;
15
+ url: string;
16
+ opts: RenderOptions;
17
+ /**
18
+ * Generates a Content Security Policy (CSP) nonce for the request.
19
+ * @param ctx The Koa context.
20
+ * @returns The generated CSP nonce.
21
+ */
22
+ cspNonceGenerator?: (ctx: ParameterizedContext) => string;
23
+ }
7
24
  export const createRouteExplorer = ({
8
25
  router,
9
26
  url,
10
27
  opts,
11
- }: {
12
- router: KoaRouter;
13
- url: string;
14
- opts: RenderOptions;
15
- }) => {
28
+ cspNonceGenerator,
29
+ }: AltairKoaMiddlewareOptions) => {
16
30
  router.get(url, async (ctx, next) => {
17
- ctx.body = renderAltair({ baseURL: ctx.url.replace(/\/?$/, '/'), ...opts });
31
+ const cspNonce = opts.cspNonce ?? cspNonceGenerator?.(ctx);
32
+ ctx.body = renderAltair({
33
+ baseURL: ctx.url.replace(/\/?$/, '/'),
34
+ ...opts,
35
+ cspNonce,
36
+ });
18
37
 
19
38
  await next();
20
39
  });
21
40
 
22
41
  // Use the main favicon for my API subdomain.
23
- router.get(`${url}/favicon.ico`, ctx => {
42
+ router.get(`${url}/favicon.ico`, (ctx) => {
24
43
  ctx.status = 301;
25
44
  ctx.redirect(`/favicon.ico`);
26
45
  });
27
46
 
28
- router.get(`${url}/:path+`, async ctx => {
47
+ router.get(`${url}/*path`, async (ctx) => {
29
48
  const path = ctx.params.path;
49
+ // Disable CSP for the sandbox iframe
50
+ if (path && isSandboxFrame(path)) {
51
+ ctx.set('Content-Security-Policy', '');
52
+ }
30
53
  await send(ctx, path || '', { root: getDistDirectory() });
31
54
  });
32
55
  };
package/example/index.ts DELETED
@@ -1,25 +0,0 @@
1
- import * as Koa from 'koa';
2
- import * as KoaRouter from '@koa/router';
3
- import { createRouteExplorer } from '../src/index';
4
-
5
- const app = new Koa();
6
- const router = new KoaRouter();
7
- const port = 3130;
8
-
9
- // app.use(async ctx => {
10
- // ctx.body = 'Hello world';
11
- // });
12
- createRouteExplorer({
13
- url: '/altair',
14
- router,
15
- opts: {
16
- endpointURL: '/graphql',
17
- subscriptionsEndpoint: `ws://localhost:4000/subscriptions`,
18
- initialQuery: `{ getData { id name surname } }`,
19
- initialPreRequestScript: `console.log('Hello from pre request!')`,
20
- },
21
- });
22
-
23
- app.use(router.routes()).use(router.allowedMethods());
24
-
25
- app.listen(port, () => console.log(`Listening on port ${port}`));