@astrale-os/kernel-server 0.5.0-beta.55 → 0.5.0-beta.57

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.
@@ -17,7 +17,7 @@ export interface RouteReservation {
17
17
  readonly path: string;
18
18
  readonly methods: readonly string[];
19
19
  }
20
- export declare function mountRoutes(app: ServerRouter, source: PublicationSource, deliveryProvider: DeliveryProvider | undefined, handler: Handler, active: ActiveOperations, nextInvocation: NextInvocationId, limits: RouteLimits, cors: CorsPolicy, hostFor: (request: Request) => ApplicationHost | undefined, reservations: readonly RouteReservation[], externalIssuer?: string): void;
20
+ export declare function mountRoutes(app: ServerRouter, source: PublicationSource, deliveryProvider: DeliveryProvider | undefined, handler: Handler, active: ActiveOperations, nextInvocation: NextInvocationId, limits: RouteLimits, cors: CorsPolicy, hostFor: (request: Request) => ApplicationHost | undefined, reservations: readonly RouteReservation[], externalIssuer?: string, publicOrigin?: string): void;
21
21
  export declare function currentPublicationSnapshot(source: PublicationSource, limits: Pick<RouteLimits, 'maximumPublicationBytes' | 'maximumBundleBytes'>, serving?: {
22
22
  readonly origin: string;
23
23
  readonly issuer?: string;
@@ -12,11 +12,11 @@ import { readPreparedPublicationSnapshot, } from '../publication/index.js';
12
12
  import { readBoundedBody } from '../transport/body.js';
13
13
  import {} from '../transport/router.js';
14
14
  import { interruptedStreamError } from '../transport/stream-error.js';
15
- export function mountRoutes(app, source, deliveryProvider, handler, active, nextInvocation, limits, cors, hostFor, reservations, externalIssuer) {
15
+ export function mountRoutes(app, source, deliveryProvider, handler, active, nextInvocation, limits, cors, hostFor, reservations, externalIssuer, publicOrigin) {
16
16
  const publicationPath = externalIssuer === undefined
17
17
  ? PUBLICATION_PATH
18
18
  : new URL(publicationUrl(externalIssuer)).pathname;
19
- const externalOrigin = externalIssuer === undefined ? undefined : new URL(externalIssuer).origin;
19
+ const externalOrigin = publicOrigin ?? (externalIssuer === undefined ? undefined : new URL(externalIssuer).origin);
20
20
  if (cors.enabled) {
21
21
  app.options(publicationPath, (context) => cors.preflight(context.req.raw, {
22
22
  methods: ['GET'],
@@ -27,7 +27,7 @@ export function mountRoutes(app, source, deliveryProvider, handler, active, next
27
27
  const responseCors = cors.response(context.req.raw, ['etag']);
28
28
  if (!active.isAccepting)
29
29
  return response({ error: 'Publication is unavailable while draining.' }, 503, responseCors);
30
- const snapshot = servingSnapshot(source, limits, context.req.raw, reservations, externalIssuer);
30
+ const snapshot = servingSnapshot(source, limits, context.req.raw, reservations, externalIssuer, externalOrigin);
31
31
  if (snapshot === undefined)
32
32
  return response({ error: 'Publication is not ready.' }, 503, responseCors);
33
33
  const body = snapshot.publicationBytes;
@@ -52,7 +52,7 @@ export function mountRoutes(app, source, deliveryProvider, handler, active, next
52
52
  });
53
53
  });
54
54
  app.all('*', async (context) => {
55
- const snapshot = servingSnapshot(source, limits, context.req.raw, reservations, externalIssuer);
55
+ const snapshot = servingSnapshot(source, limits, context.req.raw, reservations, externalIssuer, externalOrigin);
56
56
  if (snapshot === undefined)
57
57
  return context.notFound();
58
58
  const request = context.req.raw;
@@ -352,9 +352,10 @@ export function currentPublicationSnapshot(source, limits, serving) {
352
352
  }
353
353
  return prepared;
354
354
  }
355
- function servingSnapshot(source, limits, request, reservations, externalIssuer) {
355
+ function servingSnapshot(source, limits, request, reservations, externalIssuer, publicOrigin) {
356
356
  return currentPublicationSnapshot(source, limits, {
357
- origin: externalIssuer === undefined ? new URL(request.url).origin : new URL(externalIssuer).origin,
357
+ origin: publicOrigin ??
358
+ (externalIssuer === undefined ? new URL(request.url).origin : new URL(externalIssuer).origin),
358
359
  ...(externalIssuer === undefined ? {} : { issuer: externalIssuer }),
359
360
  reservations,
360
361
  });
package/dist/server.js CHANGED
@@ -26,7 +26,8 @@ function createPreparedServer(input, config) {
26
26
  const app = createServerRouter();
27
27
  const hosts = new WeakMap();
28
28
  const externalIssuer = config.issuer?.issuer;
29
- const externalOrigin = externalIssuer === undefined ? undefined : new URL(externalIssuer).origin;
29
+ const externalOrigin = config.publicOrigin ??
30
+ (externalIssuer === undefined ? undefined : new URL(externalIssuer).origin);
30
31
  const handleHttp = createHttpHandler({
31
32
  handler,
32
33
  active,
@@ -82,7 +83,7 @@ function createPreparedServer(input, config) {
82
83
  mountIssuer(app, config.issuer, config.cors, active, config.limits.invocationTimeoutMs, config.tokenExchange);
83
84
  }
84
85
  if (config.publication !== undefined) {
85
- mountRoutes(app, config.publication, config.delivery, handler, active, config.invocation, config.limits, config.cors, (request) => hosts.get(request), config.routeReservations, externalIssuer);
86
+ mountRoutes(app, config.publication, config.delivery, handler, active, config.invocation, config.limits, config.cors, (request) => hosts.get(request), config.routeReservations, externalIssuer, externalOrigin);
86
87
  }
87
88
  app.onError((_error, context) => new Response('{"error":"Internal server error."}', {
88
89
  status: 500,
@@ -131,6 +132,7 @@ function captureHandler(input) {
131
132
  return Object.freeze({ dispatch });
132
133
  }
133
134
  function admitOptions(config) {
135
+ const publicOrigin = config.publicOrigin === undefined ? undefined : admitPublicOrigin(config.publicOrigin);
134
136
  const invocation = captureInvocationSource(config.invocation);
135
137
  const limits = admitLimits(config.limits);
136
138
  const path = admitRoute(config.path ?? '/', 'invocation path');
@@ -180,6 +182,7 @@ function admitOptions(config) {
180
182
  }
181
183
  return Object.freeze({
182
184
  invocation,
185
+ ...(publicOrigin === undefined ? {} : { publicOrigin }),
183
186
  limits,
184
187
  path,
185
188
  cors: prepareCors(config.cors),
@@ -264,3 +267,15 @@ function admitRoute(path, label) {
264
267
  }
265
268
  return path;
266
269
  }
270
+ function admitPublicOrigin(input) {
271
+ const url = new URL(input);
272
+ if (!['http:', 'https:'].includes(url.protocol) ||
273
+ url.username !== '' ||
274
+ url.password !== '' ||
275
+ url.pathname !== '/' ||
276
+ url.search !== '' ||
277
+ url.hash !== '') {
278
+ throw new TypeError('Server publicOrigin must be an HTTP(S) origin.');
279
+ }
280
+ return url.origin;
281
+ }
package/dist/types.d.ts CHANGED
@@ -37,6 +37,8 @@ export interface ServerOptions {
37
37
  readonly probe: HealthProbe;
38
38
  } | false;
39
39
  readonly issuer?: Issuer;
40
+ /** Public HTTP origin for transport placement, independent of the stable issuer. */
41
+ readonly publicOrigin?: string;
40
42
  /** Present only for the configured self issuer; owns verification and signing. */
41
43
  readonly tokenExchange?: exchange.Provider;
42
44
  readonly publication?: PublicationSource;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/kernel-server",
3
- "version": "0.5.0-beta.55",
3
+ "version": "0.5.0-beta.57",
4
4
  "description": "Portable HTTP and WebSocket boundary for Astrale invocation, publication, installation, and issuer protocols",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -33,9 +33,9 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@astrale-os/kernel-core": "0.9.0-beta.47",
37
- "@astrale-os/kernel-dsl": "0.2.0-beta.33",
38
- "@astrale-os/kernel-protocol": "0.5.0-beta.53",
36
+ "@astrale-os/kernel-core": "0.9.0-beta.49",
37
+ "@astrale-os/kernel-dsl": "0.2.0-beta.34",
38
+ "@astrale-os/kernel-protocol": "0.5.0-beta.55",
39
39
  "hono": "^4.6.20",
40
40
  "msgpackr": "^2.0.5"
41
41
  },