@c9up/aurora 0.1.17 → 0.1.19

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.
@@ -22,6 +22,13 @@ export interface AuroraManagerConfig {
22
22
  * Override only if you want to serve a custom build.
23
23
  */
24
24
  auroraDistRoot?: string;
25
+ /**
26
+ * Filesystem path to `@c9up/comet`'s `dist/`. Defaults to the dist of the
27
+ * installed (optional-peer) `@c9up/comet` — resolved automatically so the
28
+ * RPC client's `import '@c9up/comet'` works in the no-bundler browser with
29
+ * zero app wiring. Left unserved when comet isn't installed (no RPC).
30
+ */
31
+ cometDistRoot?: string;
25
32
  /**
26
33
  * URL prefix the asset routes mount under. The aurora runtime is served
27
34
  * from `<assetsPrefix>/aurora/*` and the app's pages from
@@ -41,6 +48,10 @@ export declare class AuroraManager {
41
48
  readonly auroraAssetPath: string;
42
49
  /** Mount path for the app's pages — `<assetsPrefix>/pages`. */
43
50
  readonly pageAssetPath: string;
51
+ /** Mount path for the RPC client's `@c9up/comet` runtime — `<assetsPrefix>/comet`. */
52
+ readonly cometAssetPath: string;
53
+ /** Resolved `@c9up/comet` dist dir, or `null` when comet isn't installed. */
54
+ readonly cometDistRoot: string | null;
44
55
  constructor(config: AuroraManagerConfig);
45
56
  /**
46
57
  * SSR + hydrate + ship the document. The importmap default points
@@ -59,4 +70,10 @@ export declare class AuroraManager {
59
70
  * `GET /_assets/pages/*`.
60
71
  */
61
72
  pageAssetsHandler(): (ctx: AssetsHttpContext) => Promise<void>;
73
+ /**
74
+ * Handler for `@c9up/comet`'s runtime (the RPC client). Mount on
75
+ * `GET <cometAssetPath>/*`. Returns `null` when comet isn't installed —
76
+ * the provider then skips the route (no RPC, nothing to serve).
77
+ */
78
+ cometAssetsHandler(): ((ctx: AssetsHttpContext) => Promise<void>) | null;
62
79
  }
@@ -15,8 +15,21 @@ import { dirname, resolve as resolvePath } from "node:path";
15
15
  import { fileURLToPath } from "node:url";
16
16
  import { Pages } from "./Pages.js";
17
17
  import { renderPage, } from "./server/renderPage.js";
18
- import { serveAssets } from "./server/serveAssets.js";
18
+ import { packageAssetDir, serveAssets, } from "./server/serveAssets.js";
19
19
  const DEFAULT_AURORA_DIST = resolvePath(dirname(fileURLToPath(import.meta.url)), "../dist");
20
+ /**
21
+ * Resolve `@c9up/comet`'s dist dir, or `null` when it isn't installed. comet is
22
+ * aurora's OPTIONAL peer (only present when the app uses RPC), so a missing one
23
+ * is expected — aurora then simply doesn't serve it or add it to the importmap.
24
+ */
25
+ function resolveCometDist() {
26
+ try {
27
+ return packageAssetDir("@c9up/comet");
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ }
20
33
  /** Normalize an asset prefix: ensure a leading slash, drop trailing slashes. */
21
34
  function normalizePrefix(prefix) {
22
35
  const withLead = prefix.startsWith("/") ? prefix : `/${prefix}`;
@@ -31,10 +44,16 @@ export class AuroraManager {
31
44
  auroraAssetPath;
32
45
  /** Mount path for the app's pages — `<assetsPrefix>/pages`. */
33
46
  pageAssetPath;
47
+ /** Mount path for the RPC client's `@c9up/comet` runtime — `<assetsPrefix>/comet`. */
48
+ cometAssetPath;
49
+ /** Resolved `@c9up/comet` dist dir, or `null` when comet isn't installed. */
50
+ cometDistRoot;
34
51
  constructor(config) {
35
52
  this.assetsPrefix = normalizePrefix(config.assetsPrefix ?? "/_assets");
36
53
  this.auroraAssetPath = `${this.assetsPrefix}/aurora`;
37
54
  this.pageAssetPath = `${this.assetsPrefix}/pages`;
55
+ this.cometAssetPath = `${this.assetsPrefix}/comet`;
56
+ this.cometDistRoot = config.cometDistRoot ?? resolveCometDist();
38
57
  // Pages serve their compiled JS from the same prefix unless the app
39
58
  // pins an explicit urlPrefix.
40
59
  this.pages = new Pages({
@@ -54,6 +73,17 @@ export class AuroraManager {
54
73
  ...options,
55
74
  importmap: {
56
75
  "@c9up/aurora": `${this.auroraAssetPath}/index.js`,
76
+ // The browser-facing subpath (RPC client) needs an explicit entry —
77
+ // importmaps don't read package `exports`, and an extensionless bare
78
+ // specifier won't hit a trailing-slash prefix map. Served from the
79
+ // same aurora dist; harmless when a page never imports it.
80
+ "@c9up/aurora/rpc": `${this.auroraAssetPath}/rpc.js`,
81
+ // Auto-map @c9up/comet when installed so the rpc client's bare
82
+ // `import '@c9up/comet'` resolves in the no-bundler browser — no
83
+ // app-side importmap wiring. Omitted when comet isn't present.
84
+ ...(this.cometDistRoot
85
+ ? { "@c9up/comet": `${this.cometAssetPath}/index.js` }
86
+ : {}),
57
87
  ...options?.importmap,
58
88
  },
59
89
  });
@@ -72,4 +102,14 @@ export class AuroraManager {
72
102
  pageAssetsHandler() {
73
103
  return serveAssets({ root: this.pages.root });
74
104
  }
105
+ /**
106
+ * Handler for `@c9up/comet`'s runtime (the RPC client). Mount on
107
+ * `GET <cometAssetPath>/*`. Returns `null` when comet isn't installed —
108
+ * the provider then skips the route (no RPC, nothing to serve).
109
+ */
110
+ cometAssetsHandler() {
111
+ return this.cometDistRoot
112
+ ? serveAssets({ root: this.cometDistRoot })
113
+ : null;
114
+ }
75
115
  }
@@ -67,6 +67,13 @@ export default class AuroraProvider {
67
67
  // `/_assets`) — set `config.aurora.assetsPrefix` to change the scheme.
68
68
  router.get(`${manager.auroraAssetPath}/*`, adaptHandler(manager.auroraAssetsHandler()));
69
69
  router.get(`${manager.pageAssetPath}/*`, adaptHandler(manager.pageAssetsHandler()));
70
+ // Serve @c9up/comet's runtime so the RPC client's bare `import
71
+ // '@c9up/comet'` resolves in the browser. Skipped when comet isn't
72
+ // installed (optional peer — the app doesn't use RPC).
73
+ const cometHandler = manager.cometAssetsHandler();
74
+ if (cometHandler) {
75
+ router.get(`${manager.cometAssetPath}/*`, adaptHandler(cometHandler));
76
+ }
70
77
  }
71
78
  async ready() { }
72
79
  async shutdown() { }
@@ -9,6 +9,17 @@
9
9
  * and writes to `ctx.response`. Any context that satisfies
10
10
  * `AssetsHttpContext` (Ream, AdonisJS, anything duck-typed) works.
11
11
  */
12
+ /**
13
+ * Absolute dist directory of an installed package — for mounting its pre-built
14
+ * ESM as browser assets (`serveAssets({ root: packageAssetDir('@c9up/x') })`).
15
+ *
16
+ * Uses `import.meta.resolve`, which honours the package's `exports` `import`
17
+ * condition — so it works for `@c9up/*` import-only packages where
18
+ * `createRequire().resolve()` throws `ERR_PACKAGE_PATH_NOT_EXPORTED` (their
19
+ * `exports` carry no `require` condition, and `main` is ignored once `exports`
20
+ * exists). Throws if the package isn't installed/resolvable.
21
+ */
22
+ export declare function packageAssetDir(specifier: string): string;
12
23
  export interface AssetsRequest {
13
24
  /**
14
25
  * Read the wildcard `*` segment of the matched route. Most routers
@@ -10,7 +10,21 @@
10
10
  * `AssetsHttpContext` (Ream, AdonisJS, anything duck-typed) works.
11
11
  */
12
12
  import { readFile, realpath } from "node:fs/promises";
13
- import { extname, join, resolve as resolvePath, sep } from "node:path";
13
+ import { dirname, extname, join, resolve as resolvePath, sep } from "node:path";
14
+ import { fileURLToPath } from "node:url";
15
+ /**
16
+ * Absolute dist directory of an installed package — for mounting its pre-built
17
+ * ESM as browser assets (`serveAssets({ root: packageAssetDir('@c9up/x') })`).
18
+ *
19
+ * Uses `import.meta.resolve`, which honours the package's `exports` `import`
20
+ * condition — so it works for `@c9up/*` import-only packages where
21
+ * `createRequire().resolve()` throws `ERR_PACKAGE_PATH_NOT_EXPORTED` (their
22
+ * `exports` carry no `require` condition, and `main` is ignored once `exports`
23
+ * exists). Throws if the package isn't installed/resolvable.
24
+ */
25
+ export function packageAssetDir(specifier) {
26
+ return dirname(fileURLToPath(import.meta.resolve(specifier)));
27
+ }
14
28
  const CONTENT_TYPES = {
15
29
  ".js": "text/javascript; charset=utf-8",
16
30
  ".mjs": "text/javascript; charset=utf-8",
package/dist/server.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { AuroraManager, type AuroraManagerConfig } from "./AuroraManager.js";
2
2
  export { type PageFactory, Pages, type PagesConfig } from "./Pages.js";
3
3
  export { type RenderHttpContext, type RenderPageOptions, type RenderResponse, renderPage, } from "./server/renderPage.js";
4
- export { type AssetsHttpContext, type AssetsRequest, type AssetsResponse, type ServeAssetsOptions, serveAssets, } from "./server/serveAssets.js";
4
+ export { type AssetsHttpContext, type AssetsRequest, type AssetsResponse, packageAssetDir, type ServeAssetsOptions, serveAssets, } from "./server/serveAssets.js";
package/dist/server.js CHANGED
@@ -7,4 +7,4 @@
7
7
  export { AuroraManager } from "./AuroraManager.js";
8
8
  export { Pages } from "./Pages.js";
9
9
  export { renderPage, } from "./server/renderPage.js";
10
- export { serveAssets, } from "./server/serveAssets.js";
10
+ export { packageAssetDir, serveAssets, } from "./server/serveAssets.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c9up/aurora",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "description": "Aurora — reactive UI runtime for the Ream framework. Tagged-template DOM, signal-based state, isomorphic SSR + hydration, zero build step.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -20,7 +20,11 @@ import {
20
20
  type RenderPageOptions,
21
21
  renderPage,
22
22
  } from "./server/renderPage.js";
23
- import { type AssetsHttpContext, serveAssets } from "./server/serveAssets.js";
23
+ import {
24
+ type AssetsHttpContext,
25
+ packageAssetDir,
26
+ serveAssets,
27
+ } from "./server/serveAssets.js";
24
28
 
25
29
  export interface AuroraManagerConfig {
26
30
  pages: PagesConfig;
@@ -30,6 +34,13 @@ export interface AuroraManagerConfig {
30
34
  * Override only if you want to serve a custom build.
31
35
  */
32
36
  auroraDistRoot?: string;
37
+ /**
38
+ * Filesystem path to `@c9up/comet`'s `dist/`. Defaults to the dist of the
39
+ * installed (optional-peer) `@c9up/comet` — resolved automatically so the
40
+ * RPC client's `import '@c9up/comet'` works in the no-bundler browser with
41
+ * zero app wiring. Left unserved when comet isn't installed (no RPC).
42
+ */
43
+ cometDistRoot?: string;
33
44
  /**
34
45
  * URL prefix the asset routes mount under. The aurora runtime is served
35
46
  * from `<assetsPrefix>/aurora/*` and the app's pages from
@@ -46,6 +57,19 @@ const DEFAULT_AURORA_DIST = resolvePath(
46
57
  "../dist",
47
58
  );
48
59
 
60
+ /**
61
+ * Resolve `@c9up/comet`'s dist dir, or `null` when it isn't installed. comet is
62
+ * aurora's OPTIONAL peer (only present when the app uses RPC), so a missing one
63
+ * is expected — aurora then simply doesn't serve it or add it to the importmap.
64
+ */
65
+ function resolveCometDist(): string | null {
66
+ try {
67
+ return packageAssetDir("@c9up/comet");
68
+ } catch {
69
+ return null;
70
+ }
71
+ }
72
+
49
73
  /** Normalize an asset prefix: ensure a leading slash, drop trailing slashes. */
50
74
  function normalizePrefix(prefix: string): string {
51
75
  const withLead = prefix.startsWith("/") ? prefix : `/${prefix}`;
@@ -61,11 +85,17 @@ export class AuroraManager {
61
85
  readonly auroraAssetPath: string;
62
86
  /** Mount path for the app's pages — `<assetsPrefix>/pages`. */
63
87
  readonly pageAssetPath: string;
88
+ /** Mount path for the RPC client's `@c9up/comet` runtime — `<assetsPrefix>/comet`. */
89
+ readonly cometAssetPath: string;
90
+ /** Resolved `@c9up/comet` dist dir, or `null` when comet isn't installed. */
91
+ readonly cometDistRoot: string | null;
64
92
 
65
93
  constructor(config: AuroraManagerConfig) {
66
94
  this.assetsPrefix = normalizePrefix(config.assetsPrefix ?? "/_assets");
67
95
  this.auroraAssetPath = `${this.assetsPrefix}/aurora`;
68
96
  this.pageAssetPath = `${this.assetsPrefix}/pages`;
97
+ this.cometAssetPath = `${this.assetsPrefix}/comet`;
98
+ this.cometDistRoot = config.cometDistRoot ?? resolveCometDist();
69
99
  // Pages serve their compiled JS from the same prefix unless the app
70
100
  // pins an explicit urlPrefix.
71
101
  this.pages = new Pages({
@@ -91,6 +121,17 @@ export class AuroraManager {
91
121
  ...options,
92
122
  importmap: {
93
123
  "@c9up/aurora": `${this.auroraAssetPath}/index.js`,
124
+ // The browser-facing subpath (RPC client) needs an explicit entry —
125
+ // importmaps don't read package `exports`, and an extensionless bare
126
+ // specifier won't hit a trailing-slash prefix map. Served from the
127
+ // same aurora dist; harmless when a page never imports it.
128
+ "@c9up/aurora/rpc": `${this.auroraAssetPath}/rpc.js`,
129
+ // Auto-map @c9up/comet when installed so the rpc client's bare
130
+ // `import '@c9up/comet'` resolves in the no-bundler browser — no
131
+ // app-side importmap wiring. Omitted when comet isn't present.
132
+ ...(this.cometDistRoot
133
+ ? { "@c9up/comet": `${this.cometAssetPath}/index.js` }
134
+ : {}),
94
135
  ...options?.importmap,
95
136
  },
96
137
  });
@@ -111,4 +152,15 @@ export class AuroraManager {
111
152
  pageAssetsHandler(): (ctx: AssetsHttpContext) => Promise<void> {
112
153
  return serveAssets({ root: this.pages.root });
113
154
  }
155
+
156
+ /**
157
+ * Handler for `@c9up/comet`'s runtime (the RPC client). Mount on
158
+ * `GET <cometAssetPath>/*`. Returns `null` when comet isn't installed —
159
+ * the provider then skips the route (no RPC, nothing to serve).
160
+ */
161
+ cometAssetsHandler(): ((ctx: AssetsHttpContext) => Promise<void>) | null {
162
+ return this.cometDistRoot
163
+ ? serveAssets({ root: this.cometDistRoot })
164
+ : null;
165
+ }
114
166
  }
@@ -101,6 +101,13 @@ export default class AuroraProvider {
101
101
  `${manager.pageAssetPath}/*`,
102
102
  adaptHandler(manager.pageAssetsHandler()),
103
103
  );
104
+ // Serve @c9up/comet's runtime so the RPC client's bare `import
105
+ // '@c9up/comet'` resolves in the browser. Skipped when comet isn't
106
+ // installed (optional peer — the app doesn't use RPC).
107
+ const cometHandler = manager.cometAssetsHandler();
108
+ if (cometHandler) {
109
+ router.get(`${manager.cometAssetPath}/*`, adaptHandler(cometHandler));
110
+ }
104
111
  }
105
112
 
106
113
  async ready(): Promise<void> {}
@@ -11,7 +11,22 @@
11
11
  */
12
12
 
13
13
  import { readFile, realpath } from "node:fs/promises";
14
- import { extname, join, resolve as resolvePath, sep } from "node:path";
14
+ import { dirname, extname, join, resolve as resolvePath, sep } from "node:path";
15
+ import { fileURLToPath } from "node:url";
16
+
17
+ /**
18
+ * Absolute dist directory of an installed package — for mounting its pre-built
19
+ * ESM as browser assets (`serveAssets({ root: packageAssetDir('@c9up/x') })`).
20
+ *
21
+ * Uses `import.meta.resolve`, which honours the package's `exports` `import`
22
+ * condition — so it works for `@c9up/*` import-only packages where
23
+ * `createRequire().resolve()` throws `ERR_PACKAGE_PATH_NOT_EXPORTED` (their
24
+ * `exports` carry no `require` condition, and `main` is ignored once `exports`
25
+ * exists). Throws if the package isn't installed/resolvable.
26
+ */
27
+ export function packageAssetDir(specifier: string): string {
28
+ return dirname(fileURLToPath(import.meta.resolve(specifier)));
29
+ }
15
30
 
16
31
  const CONTENT_TYPES: Record<string, string> = {
17
32
  ".js": "text/javascript; charset=utf-8",
package/src/server.ts CHANGED
@@ -17,6 +17,7 @@ export {
17
17
  type AssetsHttpContext,
18
18
  type AssetsRequest,
19
19
  type AssetsResponse,
20
+ packageAssetDir,
20
21
  type ServeAssetsOptions,
21
22
  serveAssets,
22
23
  } from "./server/serveAssets.js";