@jk2908/solas 0.8.1 → 0.8.3

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.8.3
4
+
5
+ ### Changed
6
+
7
+ - `url` and `trustedOrigins` now accept plain strings, so `process.env` values can be passed directly without a cast. The resolved `url` is validated (it must be an `http(s)` origin) and normalised to its origin.
8
+
9
+ ## 0.8.2
10
+
11
+ ### Fixes
12
+
13
+ - The Cloudflare adapter copies `dist/sitemap.xml` to the asset root, so `/sitemap.xml` is served. It was generated at the output root but never copied into the deployed assets.
14
+
3
15
  ## 0.8.1
4
16
 
5
17
  ### Fixes
@@ -48,17 +48,18 @@ async function findAssetDirs(root, found = []) {
48
48
  * renders RSC otherwise
49
49
  * - `dist/.solas/**` (runtime manifest + ppr artifacts) at `<prefix>`, read back
50
50
  * through the `ASSETS` binding
51
+ * - `dist/sitemap.xml` at the asset root, so `/sitemap.xml` is served
51
52
  */
52
53
  async function copyOutput(cwd) {
53
54
  const outDir = path.join(cwd, Config.OUT_DIR);
54
55
  const artifactSource = path.join(outDir, Config.GENERATED_DIR);
55
56
  const staticSource = path.join(outDir, 'static');
57
+ const sitemapSource = path.join(outDir, 'sitemap.xml');
56
58
  const assetDirs = await findAssetDirs(path.join(cwd, '.cloudflare', 'output'));
57
59
  // Cloudflare compresses at the edge, so the Worker must serve uncompressed
58
- // bytes. If a `.br`/`.gz` sibling is present the assets binding hands the
59
- // Worker the precompressed body, which the edge then compresses *again*,
60
- // producing a double-encoded body (or one that does not match its
61
- // `content-encoding`). Skip the siblings so the Worker serves the original.
60
+ // bytes. Keeping a `.br`/`.gz` sibling makes the assets binding hand the
61
+ // Worker the compressed body, which the edge compresses again, producing a
62
+ // double-encoded response (or one that does not match its `content-encoding`)
62
63
  const skipPrecompressed = (source) => !/\.(br|gz)$/.test(source);
63
64
  for (const assetDir of assetDirs) {
64
65
  if (await pathExists(artifactSource)) {
@@ -75,6 +76,10 @@ async function copyOutput(cwd) {
75
76
  filter: skipPrecompressed,
76
77
  });
77
78
  }
79
+ // the sitemap is generated at the output root; serve it at the asset root
80
+ if (await pathExists(sitemapSource)) {
81
+ await fs.copyFile(sitemapSource, path.join(assetDir, 'sitemap.xml'));
82
+ }
78
83
  }
79
84
  }
80
85
  function withAdapterConfig(config) {
package/dist/index.js CHANGED
@@ -22,6 +22,25 @@ const DEFAULT_CONFIG = {
22
22
  trustedOrigins: [],
23
23
  trailingSlash: 'never',
24
24
  };
25
+ /**
26
+ * Validate a configured url and return its canonical origin (scheme and host,
27
+ * without a trailing slash or path). Throws when it is not a http(s) origin.
28
+ */
29
+ function resolveOrigin(value) {
30
+ if (!value)
31
+ return undefined;
32
+ let url;
33
+ try {
34
+ url = new URL(value);
35
+ }
36
+ catch {
37
+ throw new Error(`[solas] Invalid url: "${value}"`);
38
+ }
39
+ if (url.protocol !== 'http:' && url.protocol !== 'https:') {
40
+ throw new Error(`[solas] url must use http:// or https://: "${value}"`);
41
+ }
42
+ return url.origin;
43
+ }
25
44
  function solas(c) {
26
45
  const validatedConfig = Config.validate(c);
27
46
  const config = {
@@ -29,7 +48,7 @@ function solas(c) {
29
48
  ...validatedConfig,
30
49
  };
31
50
  const envUrl = process.env.VITE_APP_URL?.toString();
32
- let resolvedUrl = c?.url ?? (envUrl && envUrl.length > 0 ? envUrl : undefined);
51
+ let resolvedUrl = resolveOrigin(c?.url) ?? resolveOrigin(envUrl);
33
52
  if (config.logger?.level)
34
53
  Logger.defaultLevel = config.logger.level;
35
54
  const logger = new Logger();
package/dist/types.d.ts CHANGED
@@ -25,14 +25,14 @@ type PluginConfigBase = {
25
25
  prerender?: Route.Prerender;
26
26
  metadata?: Metadata.Item;
27
27
  trailingSlash?: (typeof Config.TRAILING_SLASH_MODES)[number];
28
- trustedOrigins?: readonly Origin[];
28
+ trustedOrigins?: readonly string[];
29
29
  adapter?: Adapter;
30
30
  readonly logger?: {
31
31
  level?: LogLevel;
32
32
  };
33
33
  };
34
34
  export type PluginConfig = PluginConfigBase & {
35
- url?: Origin;
35
+ url?: string;
36
36
  sitemap?: boolean | {
37
37
  routes: (existing: string[]) => string[] | Promise<string[]>;
38
38
  };
@@ -116,7 +116,7 @@ export type BuildManifest = {
116
116
  sitemapRoutes: string[];
117
117
  precompress: boolean;
118
118
  trailingSlash: (typeof Config.TRAILING_SLASH_MODES)[number];
119
- url?: Origin;
119
+ url?: string;
120
120
  };
121
121
  export declare namespace Route {
122
122
  type ParamsOf<TRoute> = TRoute extends {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jk2908/solas",
3
- "version": "0.8.1",
3
+ "version": "0.8.3",
4
4
  "description": "A Vite + React meta-framework exploring streaming, Server Components, and partial prerendering. Designed for simplicity and lightness",
5
5
  "keywords": [
6
6
  "framework",