@astrale-os/sdk 0.5.0-beta.142 → 0.5.0-beta.143

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/README.md CHANGED
@@ -224,3 +224,26 @@ coherent Publication, bundle, and View catalog observation.
224
224
  ## License
225
225
 
226
226
  Apache License 2.0 — see [LICENSE](LICENSE) for details.
227
+
228
+ ## View host requirements
229
+
230
+ A frontend route can declare the exact external origins its View needs to open:
231
+
232
+ ```ts
233
+ routes: {
234
+ application: {
235
+ path: '/',
236
+ host: {
237
+ navigation: {
238
+ external: { origins: ['https://provider.example'] },
239
+ },
240
+ },
241
+ },
242
+ }
243
+ ```
244
+
245
+ These requirements are publication metadata, so changing them updates the publication ETag without
246
+ changing the Application's business Schema. They require the `shell` handshake. Origins must use
247
+ HTTPS without credentials, paths, queries, fragments, or wildcards; authoring normalizes and sorts
248
+ them. Supporting hosts admit them per mount and execute the existing `browser.openExternal`
249
+ intent. Nested Views cannot expand their parent's grant.
@@ -5,5 +5,5 @@ export type { AuthorityRequirements, AuthorityRequirementsInput, ClassOperation,
5
5
  export { route, routes } from './routes/index.js';
6
6
  export type { Route, RouteInput, RouteTarget, Routes } from './routes/index.js';
7
7
  export { defineFrontend, external, vite } from './view/index.js';
8
- export type { Frontend, FrontendInput, FrontendSource, IframeRequirements } from './view/index.js';
8
+ export type { Frontend, FrontendInput, FrontendSource, IframeRequirements, ViewHostRequirements, } from './view/index.js';
9
9
  export type { Application, ApplicationIdentity, RuntimeOfApplication, SchemaOfApplication, SchemaOfRuntime, } from './application.js';
@@ -1,6 +1,6 @@
1
1
  export { isFrontend } from './admission.js';
2
2
  export { defineFrontend } from './define.js';
3
3
  export type { Frontend, FrontendInput, FrontendRouteInputs, FrontendRoutes, ViewName, } from './frontend.js';
4
- export type { FrontendHandshake, FrontendRoute, FrontendRouteInput, IframeRequirements, } from './route.js';
4
+ export type { FrontendHandshake, FrontendRoute, FrontendRouteInput, IframeRequirements, ViewHostRequirements, } from './route.js';
5
5
  export { external, isFrontendSource, vite } from './source.js';
6
6
  export type { ExternalSource, FrontendSource, ViteSource } from './source.js';
@@ -1,3 +1,5 @@
1
+ import { type ViewHostRequirements } from '@astrale-os/kernel-core/schema/kernel/syscalls/view-resolution';
2
+ export type { ViewHostRequirements } from '@astrale-os/kernel-core/schema/kernel/syscalls/view-resolution';
1
3
  export type FrontendHandshake = 'shell' | 'none';
2
4
  export interface IframeRequirements {
3
5
  readonly sandbox?: readonly string[];
@@ -8,12 +10,14 @@ export type FrontendRouteInput = string | {
8
10
  readonly document?: string;
9
11
  readonly handshake?: FrontendHandshake;
10
12
  readonly iframe?: IframeRequirements;
13
+ readonly host?: ViewHostRequirements;
11
14
  };
12
15
  export interface FrontendRoute {
13
16
  readonly path: string;
14
17
  readonly document: string;
15
18
  readonly handshake: FrontendHandshake;
16
19
  readonly iframe?: IframeRequirements;
20
+ readonly host?: ViewHostRequirements;
17
21
  }
18
22
  export declare function normalizeRoute(input: FrontendRouteInput | undefined, fallback: string): FrontendRoute;
19
23
  export declare function defaultRoute(name: string): string;
@@ -1,3 +1,4 @@
1
+ import { acceptViewHostRequirements, } from '@astrale-os/kernel-core/schema/kernel/syscalls/view-resolution';
1
2
  const TOKEN = /^[a-z][a-z0-9-]*$/u;
2
3
  const BASELINES = Object.freeze({
3
4
  none: iframeRequirements(['allow-scripts'], []),
@@ -8,7 +9,8 @@ export function normalizeRoute(input, fallback) {
8
9
  return Object.freeze({ path: routePath(input), document: 'index.html', handshake: 'shell' });
9
10
  }
10
11
  const value = plainRecord(input ?? {});
11
- if (Reflect.ownKeys(value).some((key) => typeof key !== 'string' || !['path', 'document', 'handshake', 'iframe'].includes(key))) {
12
+ if (Reflect.ownKeys(value).some((key) => typeof key !== 'string' ||
13
+ !['path', 'document', 'handshake', 'iframe', 'host'].includes(key))) {
12
14
  invalid();
13
15
  }
14
16
  const authoredHandshake = dataValue(value, 'handshake');
@@ -19,11 +21,13 @@ export function normalizeRoute(input, fallback) {
19
21
  }
20
22
  const handshake = authoredHandshake ?? 'shell';
21
23
  const iframe = normalizeIframeRequirements(dataValue(value, 'iframe'), handshake);
24
+ const host = acceptViewHostRequirements(dataValue(value, 'host'), handshake, true);
22
25
  return Object.freeze({
23
26
  path: routePath(dataValue(value, 'path') ?? fallback),
24
27
  document: filePath(dataValue(value, 'document') ?? 'index.html'),
25
28
  handshake,
26
29
  ...(iframe === undefined ? {} : { iframe }),
30
+ ...(host === undefined ? {} : { host }),
27
31
  });
28
32
  }
29
33
  function normalizeIframeRequirements(input, handshake) {
@@ -1,5 +1,5 @@
1
1
  import type { Frontend, FrontendSource } from '../../../application/view/index.js';
2
- import type { FrontendHandshake, IframeRequirements } from '../../../application/view/index.js';
2
+ import type { FrontendHandshake, IframeRequirements, ViewHostRequirements } from '../../../application/view/index.js';
3
3
  import type { Key, ViewRef } from '../../../platform/schema/index.js';
4
4
  import type { Domain } from '../../../platform/schema/index.js';
5
5
  export interface CompiledFrontendRoute {
@@ -8,6 +8,7 @@ export interface CompiledFrontendRoute {
8
8
  readonly document: string;
9
9
  readonly handshake: FrontendHandshake;
10
10
  readonly iframe?: IframeRequirements;
11
+ readonly host?: ViewHostRequirements;
11
12
  }
12
13
  export interface FrontendCompilation {
13
14
  readonly source: FrontendSource;
@@ -16,6 +16,7 @@ export function compileFrontend(frontend, domain) {
16
16
  document: route.document,
17
17
  handshake: route.handshake,
18
18
  ...(route.iframe === undefined ? {} : { iframe: route.iframe }),
19
+ ...(route.host === undefined ? {} : { host: route.host }),
19
20
  });
20
21
  });
21
22
  const entrypoint = domain.views[frontend.entrypoint];
@@ -9,5 +9,6 @@ export function views(build, addressing) {
9
9
  href: new URL(route.path.replace(/^\//u, ''), base).href,
10
10
  handshake: route.handshake,
11
11
  ...(route.iframe === undefined ? {} : { iframe: route.iframe }),
12
+ ...(route.host === undefined ? {} : { host: route.host }),
12
13
  })));
13
14
  }
@@ -21,7 +21,7 @@ async function json(fetcher, url, signal) {
21
21
  throw new Error(`GET ${url} exceeded ${MAXIMUM_IDENTITY_BYTES} bytes.`);
22
22
  }
23
23
  try {
24
- return JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes));
24
+ return JSON.parse(new TextDecoder('utf-8', { fatal: true, ignoreBOM: false }).decode(bytes));
25
25
  }
26
26
  catch (cause) {
27
27
  throw new Error(`GET ${url} returned invalid JSON.`, { cause });
@@ -33,7 +33,7 @@ async function bounded(response, url, maximum) {
33
33
  async function text(response, url, maximum) {
34
34
  const bytes = await bounded(response, url, maximum);
35
35
  try {
36
- return new TextDecoder('utf-8', { fatal: true }).decode(bytes);
36
+ return new TextDecoder('utf-8', { fatal: true, ignoreBOM: false }).decode(bytes);
37
37
  }
38
38
  catch (cause) {
39
39
  throw new Error(`GET ${url} returned invalid UTF-8.`, { cause });
@@ -244,7 +244,7 @@ async function json(response, signal) {
244
244
  throw new CredentialRejected('Issuer discovery document exceeds its byte limit.');
245
245
  }
246
246
  try {
247
- return JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes));
247
+ return JSON.parse(new TextDecoder('utf-8', { fatal: true, ignoreBOM: false }).decode(bytes));
248
248
  }
249
249
  catch (cause) {
250
250
  throw new CredentialRejected('Issuer discovery document is invalid.', cause);
@@ -35,7 +35,7 @@ export function createService(input) {
35
35
  path: invocationPath(),
36
36
  invocation: {
37
37
  source: selectedIdentity.issuer,
38
- next: () => globalThis.crypto.randomUUID(),
38
+ next: () => crypto.randomUUID(),
39
39
  },
40
40
  issuer: selectedIdentity,
41
41
  ...(selectedIdentity.tokenExchange === undefined
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/sdk",
3
- "version": "0.5.0-beta.142",
3
+ "version": "0.5.0-beta.143",
4
4
  "description": "Schema-first SDK for defining, composing, and deploying Astrale domains",
5
5
  "keywords": [
6
6
  "astrale",
@@ -237,11 +237,11 @@
237
237
  "registry": "https://registry.npmjs.org/"
238
238
  },
239
239
  "dependencies": {
240
- "@astrale-os/kernel-client": "0.6.0-beta.61",
241
- "@astrale-os/kernel-core": "0.9.0-beta.46",
240
+ "@astrale-os/kernel-client": "0.6.0-beta.62",
241
+ "@astrale-os/kernel-core": "0.9.0-beta.47",
242
242
  "@astrale-os/kernel-dsl": "0.2.0-beta.33",
243
- "@astrale-os/kernel-protocol": "0.5.0-beta.52",
244
- "@astrale-os/kernel-server": "0.5.0-beta.54",
243
+ "@astrale-os/kernel-protocol": "0.5.0-beta.53",
244
+ "@astrale-os/kernel-server": "0.5.0-beta.55",
245
245
  "@lucide/icons": "1.34.0",
246
246
  "@typescript/native-preview": "7.0.0-dev.20260707.2",
247
247
  "cross-spawn": "7.0.6",
@@ -253,6 +253,7 @@
253
253
  "@astrale-os/ox": "0.1.3",
254
254
  "@astrale/commitlint-config": "npm:@jsr/astrale__commitlint-config@~2.0.5",
255
255
  "@astrale/typescript-config": "npm:@jsr/astrale__typescript-config@~1.1.3",
256
+ "@cloudflare/workers-types": "^5.20260820.1",
256
257
  "@commitlint/cli": "~21.2.2",
257
258
  "@commitlint/config-conventional": "~21.2.2",
258
259
  "@hono/node-server": "^2.1.1",
@@ -310,7 +311,8 @@
310
311
  "scripts": {
311
312
  "build": "node scripts/clean-dist.mjs && tsgo && node scripts/verify-no-source-maps.mjs dist && pnpm run verify:package",
312
313
  "e2e": "node __e2e__/flagship/runner.mjs",
313
- "typecheck": "tsgo --noEmit && pnpm run typecheck:specs && pnpm run typecheck:types && pnpm run typecheck:tests && pnpm run typecheck:e2e && pnpm run typecheck:knowledge",
314
+ "typecheck": "tsgo --noEmit && pnpm run typecheck:workers && pnpm run typecheck:specs && pnpm run typecheck:types && pnpm run typecheck:tests && pnpm run typecheck:e2e && pnpm run typecheck:knowledge",
315
+ "typecheck:workers": "tsgo --noEmit -p tsconfig.workers.json",
314
316
  "typecheck:specs": "tsgo --noEmit -p src/application/query/.spec/tsconfig.json && tsgo --noEmit -p src/platform/schema/.spec/tsconfig.json && tsgo --noEmit -p src/application/mutation/.spec/tsconfig.json && tsgo --noEmit -p src/tooling/cli/.spec/tsconfig.json",
315
317
  "typecheck:types": "tsgo --noEmit -p __tests__/tsconfig.types.json",
316
318
  "typecheck:tests": "tsgo --noEmit -p tsconfig.test.json",