@jk2908/solas 0.8.0-canary.1791495022678 → 0.8.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.
- package/CHANGELOG.md +1 -1
- package/dist/adapters/cloudflare/runtime.d.ts +11 -8
- package/dist/adapters/cloudflare/runtime.js +31 -35
- package/dist/adapters/cloudflare/vite.js +3 -3
- package/dist/adapters/cloudflare/worker.js +2 -6
- package/dist/internal/codegen/environments.js +2 -4
- package/dist/internal/env/rsc.d.ts +11 -0
- package/dist/internal/env/rsc.js +13 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Assets } from '../../internal/runtimes/assets.js';
|
|
1
|
+
import type { AssetNamespace, Assets } from '../../internal/runtimes/assets.js';
|
|
2
2
|
/**
|
|
3
3
|
* The subset of the Cloudflare `assets` Fetcher binding that Solas needs.
|
|
4
4
|
*/
|
|
@@ -13,17 +13,20 @@ export type CloudflareEnv = {
|
|
|
13
13
|
[key: string]: unknown;
|
|
14
14
|
};
|
|
15
15
|
/**
|
|
16
|
-
* Path prefix the adapter copies `dist/.solas`
|
|
17
|
-
*
|
|
16
|
+
* Path prefix the adapter copies `dist/.solas` artifacts under in the asset
|
|
17
|
+
* output.
|
|
18
18
|
*/
|
|
19
19
|
export declare const ARTIFACT_PREFIX = "_solas-artifacts";
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
21
|
+
* Where each namespace lives in the asset output, keyed by the shared
|
|
22
|
+
* `AssetNamespace`. `client` files sit at the asset root; `static` (prerenders)
|
|
23
|
+
* and `artifact` (manifest, ppr) live under the artifact prefix.
|
|
24
|
+
*
|
|
25
|
+
* Prerenders must not sit at their route paths: the asset layer ignores
|
|
26
|
+
* `Accept`, so it would answer an RSC navigation (`Accept: text/x-component`)
|
|
27
|
+
* with HTML instead of letting the Worker render it.
|
|
25
28
|
*/
|
|
26
|
-
export declare const
|
|
29
|
+
export declare const NAMESPACE_PREFIX: Record<AssetNamespace, string>;
|
|
27
30
|
/**
|
|
28
31
|
* Create a Solas asset store backed by the Cloudflare assets binding.
|
|
29
32
|
*
|
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
import { getMimeTypeFromPath } from '../../internal/runtimes/mime.js';
|
|
2
2
|
/**
|
|
3
|
-
* Path prefix the adapter copies `dist/.solas`
|
|
4
|
-
*
|
|
3
|
+
* Path prefix the adapter copies `dist/.solas` artifacts under in the asset
|
|
4
|
+
* output.
|
|
5
5
|
*/
|
|
6
6
|
export const ARTIFACT_PREFIX = '_solas-artifacts';
|
|
7
|
-
/**
|
|
8
|
-
* Prerendered documents live under the artifact prefix rather than the asset
|
|
9
|
-
* root. If they sat at their route paths the asset layer would serve them for
|
|
10
|
-
* every request to that path, so an RSC navigation (`Accept:
|
|
11
|
-
* text/x-component`) would receive HTML instead of reaching the Worker.
|
|
12
|
-
*/
|
|
13
|
-
export const PRERENDER_PREFIX = `${ARTIFACT_PREFIX}/static`;
|
|
14
7
|
// The assets binding matches on pathname only, so this is only used to satisfy
|
|
15
8
|
// the URL constructor
|
|
16
9
|
const ASSET_ORIGIN = 'https://solas-assets.invalid';
|
|
10
|
+
/**
|
|
11
|
+
* Where each namespace lives in the asset output, keyed by the shared
|
|
12
|
+
* `AssetNamespace`. `client` files sit at the asset root; `static` (prerenders)
|
|
13
|
+
* and `artifact` (manifest, ppr) live under the artifact prefix.
|
|
14
|
+
*
|
|
15
|
+
* Prerenders must not sit at their route paths: the asset layer ignores
|
|
16
|
+
* `Accept`, so it would answer an RSC navigation (`Accept: text/x-component`)
|
|
17
|
+
* with HTML instead of letting the Worker render it.
|
|
18
|
+
*/
|
|
19
|
+
export const NAMESPACE_PREFIX = {
|
|
20
|
+
client: '',
|
|
21
|
+
static: `${ARTIFACT_PREFIX}/static`,
|
|
22
|
+
artifact: ARTIFACT_PREFIX,
|
|
23
|
+
};
|
|
17
24
|
/**
|
|
18
25
|
* Create a Solas asset store backed by the Cloudflare assets binding.
|
|
19
26
|
*
|
|
@@ -26,47 +33,36 @@ export function createCloudflareAssets(env) {
|
|
|
26
33
|
if (!assets || typeof assets.fetch !== 'function') {
|
|
27
34
|
throw new Error('[solas] createCloudflareAssets requires an `ASSETS` binding. Add an assets binding to your Worker.');
|
|
28
35
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
* asset root, prerenders and artifacts under the artifact prefix.
|
|
32
|
-
*/
|
|
33
|
-
function toAssetPath(asset) {
|
|
34
|
-
switch (asset.namespace) {
|
|
35
|
-
case 'artifact':
|
|
36
|
-
return `${ARTIFACT_PREFIX}/${asset.path}`;
|
|
37
|
-
case 'static':
|
|
38
|
-
return `${PRERENDER_PREFIX}/${asset.path}`;
|
|
39
|
-
default:
|
|
40
|
-
return asset.path;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
36
|
+
// narrowed here, and `const` keeps that type inside the closures below
|
|
37
|
+
const binding = assets;
|
|
43
38
|
function toUrl(asset) {
|
|
44
|
-
|
|
39
|
+
const prefix = NAMESPACE_PREFIX[asset.namespace];
|
|
40
|
+
const path = prefix ? `${prefix}/${asset.path}` : asset.path;
|
|
41
|
+
return new URL(`/${path}`, ASSET_ORIGIN).toString();
|
|
45
42
|
}
|
|
46
43
|
async function read(asset) {
|
|
47
|
-
const res = await
|
|
44
|
+
const res = await binding.fetch(toUrl(asset), {
|
|
48
45
|
// asset responses should be passed through verbatim
|
|
49
46
|
headers: { 'accept-encoding': 'identity' },
|
|
50
47
|
});
|
|
51
48
|
return res.ok ? res : null;
|
|
52
49
|
}
|
|
50
|
+
async function readOrThrow(asset) {
|
|
51
|
+
const res = await read(asset);
|
|
52
|
+
if (!res) {
|
|
53
|
+
throw new Error(`[solas] asset not found: ${asset.namespace}/${asset.path}`);
|
|
54
|
+
}
|
|
55
|
+
return res;
|
|
56
|
+
}
|
|
53
57
|
return {
|
|
54
58
|
async exists(asset) {
|
|
55
59
|
return (await read(asset)) !== null;
|
|
56
60
|
},
|
|
57
61
|
async readText(asset) {
|
|
58
|
-
|
|
59
|
-
if (!res) {
|
|
60
|
-
throw new Error(`[solas] asset not found: ${asset.namespace}/${asset.path}`);
|
|
61
|
-
}
|
|
62
|
-
return res.text();
|
|
62
|
+
return (await readOrThrow(asset)).text();
|
|
63
63
|
},
|
|
64
64
|
async readBuffer(asset) {
|
|
65
|
-
|
|
66
|
-
if (!res) {
|
|
67
|
-
throw new Error(`[solas] asset not found: ${asset.namespace}/${asset.path}`);
|
|
68
|
-
}
|
|
69
|
-
return res.arrayBuffer();
|
|
65
|
+
return (await readOrThrow(asset)).arrayBuffer();
|
|
70
66
|
},
|
|
71
67
|
mimeType(filePath) {
|
|
72
68
|
return getMimeTypeFromPath(filePath);
|
|
@@ -4,7 +4,7 @@ import { cloudflare as cloudflareVitePlugin } from '@cloudflare/vite-plugin';
|
|
|
4
4
|
import * as Config from '../../config.js';
|
|
5
5
|
import { writeCloudflareEntry } from '../../internal/codegen/environments.js';
|
|
6
6
|
import { setRscEntry } from '../../internal/postbuild.js';
|
|
7
|
-
import {
|
|
7
|
+
import { NAMESPACE_PREFIX } from './runtime.js';
|
|
8
8
|
const VIRTUAL_ENTRY = 'virtual:solas-cloudflare-entry';
|
|
9
9
|
/**
|
|
10
10
|
* Solas dependencies that are imported at request time from the Worker
|
|
@@ -56,13 +56,13 @@ async function copyOutput(cwd) {
|
|
|
56
56
|
const assetDirs = await findAssetDirs(path.join(cwd, '.cloudflare', 'output'));
|
|
57
57
|
for (const assetDir of assetDirs) {
|
|
58
58
|
if (await pathExists(artifactSource)) {
|
|
59
|
-
await fs.cp(artifactSource, path.join(assetDir,
|
|
59
|
+
await fs.cp(artifactSource, path.join(assetDir, NAMESPACE_PREFIX.artifact), {
|
|
60
60
|
recursive: true,
|
|
61
61
|
force: true,
|
|
62
62
|
});
|
|
63
63
|
}
|
|
64
64
|
if (await pathExists(staticSource)) {
|
|
65
|
-
await fs.cp(staticSource, path.join(assetDir,
|
|
65
|
+
await fs.cp(staticSource, path.join(assetDir, NAMESPACE_PREFIX.static), {
|
|
66
66
|
recursive: true,
|
|
67
67
|
force: true,
|
|
68
68
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createRuntimeHandler } from '../../internal/env/rsc.js';
|
|
2
2
|
import { nodeAssets } from '../../internal/runtimes/assets.js';
|
|
3
3
|
import { createCloudflareAssets } from './runtime.js';
|
|
4
4
|
/**
|
|
@@ -13,11 +13,7 @@ export function createWorker(options) {
|
|
|
13
13
|
const handlers = new WeakMap();
|
|
14
14
|
let nodeHandler;
|
|
15
15
|
async function build(assets) {
|
|
16
|
-
|
|
17
|
-
return createHandler(options.config, options.manifest, options.importMap, {
|
|
18
|
-
assets,
|
|
19
|
-
runtimeManifest,
|
|
20
|
-
});
|
|
16
|
+
return createRuntimeHandler(options.config, options.manifest, options.importMap, assets);
|
|
21
17
|
}
|
|
22
18
|
function getHandler(env) {
|
|
23
19
|
if (!env) {
|
|
@@ -7,15 +7,13 @@ export function writeRSCEntry(_config) {
|
|
|
7
7
|
return source `
|
|
8
8
|
${AUTOGEN_MSG}
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { createRuntimeHandler } from '${Config.PKG_NAME}/env/rsc'
|
|
11
11
|
|
|
12
12
|
import { manifest } from './manifest.js'
|
|
13
13
|
import { importMap } from './maps.js'
|
|
14
14
|
import { config } from './config.js'
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
export default createHandler(config, manifest, importMap, { runtimeManifest })
|
|
16
|
+
export default await createRuntimeHandler(config, manifest, importMap)
|
|
19
17
|
|
|
20
18
|
if (import.meta.hot) {
|
|
21
19
|
import.meta.hot.accept()
|
|
@@ -38,3 +38,14 @@ export type RscPayload = {
|
|
|
38
38
|
export declare function createHandler(config: RuntimeConfig, manifest: Manifest, importMap: ImportMap, options?: HandlerOptions): {
|
|
39
39
|
fetch(req: Request): Promise<Response>;
|
|
40
40
|
};
|
|
41
|
+
/**
|
|
42
|
+
* Build a Solas request handler over an {@link Assets} store.
|
|
43
|
+
*
|
|
44
|
+
* Loads the runtime manifest and constructs the RSC handler, defaulting to the
|
|
45
|
+
* Node standard library for assets. Platform adapters pass their own store (for
|
|
46
|
+
* example the Cloudflare `ASSETS` binding), so the same generated entry runs
|
|
47
|
+
* unchanged across runtimes.
|
|
48
|
+
*/
|
|
49
|
+
export declare function createRuntimeHandler(config: RuntimeConfig, manifest: Manifest, importMap: ImportMap, assets?: Assets): Promise<{
|
|
50
|
+
fetch(req: Request): Promise<Response>;
|
|
51
|
+
}>;
|
package/dist/internal/env/rsc.js
CHANGED
|
@@ -3,6 +3,7 @@ import { renderToReadableStream } from '@vitejs/plugin-rsc/rsc';
|
|
|
3
3
|
import { applyBasePath, normaliseBasePath, stripBasePath } from '../../utils/base-path.js';
|
|
4
4
|
import { Logger } from '../../utils/logger.js';
|
|
5
5
|
import * as Config from '../../config.js';
|
|
6
|
+
import * as RuntimeManifest from '../../manifest.js';
|
|
6
7
|
import { createHttpRouter } from '../http-router/create-http-router.js';
|
|
7
8
|
import { HttpRouter } from '../http-router/router.js';
|
|
8
9
|
import { normalisePathname } from '../http-router/utils.js';
|
|
@@ -412,6 +413,18 @@ export function createHandler(config, manifest, importMap, options = {}) {
|
|
|
412
413
|
},
|
|
413
414
|
};
|
|
414
415
|
}
|
|
416
|
+
/**
|
|
417
|
+
* Build a Solas request handler over an {@link Assets} store.
|
|
418
|
+
*
|
|
419
|
+
* Loads the runtime manifest and constructs the RSC handler, defaulting to the
|
|
420
|
+
* Node standard library for assets. Platform adapters pass their own store (for
|
|
421
|
+
* example the Cloudflare `ASSETS` binding), so the same generated entry runs
|
|
422
|
+
* unchanged across runtimes.
|
|
423
|
+
*/
|
|
424
|
+
export async function createRuntimeHandler(config, manifest, importMap, assets = nodeAssets) {
|
|
425
|
+
const runtimeManifest = await RuntimeManifest.loadManifest(assets);
|
|
426
|
+
return createHandler(config, manifest, importMap, { assets, runtimeManifest });
|
|
427
|
+
}
|
|
415
428
|
function onError(err) {
|
|
416
429
|
if (err == null)
|
|
417
430
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jk2908/solas",
|
|
3
|
-
"version": "0.8.0
|
|
3
|
+
"version": "0.8.0",
|
|
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",
|