@bleedingdev/modern-js-renderer-core 0.0.0-bootstrap → 3.9.3-ultramodern.1

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.
Files changed (147) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/abort.js +65 -0
  3. package/dist/cjs/adapter.js +62 -0
  4. package/dist/cjs/data/body.js +78 -0
  5. package/dist/cjs/data/client.js +409 -0
  6. package/dist/cjs/data/codec.js +168 -0
  7. package/dist/cjs/data/index.js +125 -0
  8. package/dist/cjs/data/private.js +77 -0
  9. package/dist/cjs/data/routes.js +149 -0
  10. package/dist/cjs/data/server.js +791 -0
  11. package/dist/cjs/data/static.js +110 -0
  12. package/dist/cjs/data/tree.js +231 -0
  13. package/dist/cjs/data/types.js +56 -0
  14. package/dist/cjs/document.js +184 -0
  15. package/dist/cjs/entry-client.js +142 -0
  16. package/dist/cjs/entry-server.js +253 -0
  17. package/dist/cjs/federation.js +80 -0
  18. package/dist/cjs/identity.js +120 -0
  19. package/dist/cjs/index.js +46 -0
  20. package/dist/cjs/localization.js +48 -0
  21. package/dist/cjs/router.js +293 -0
  22. package/dist/cjs/server/assets.js +56 -0
  23. package/dist/cjs/server/dispatch.js +351 -0
  24. package/dist/cjs/server/index.js +57 -0
  25. package/dist/cjs/server/types.js +18 -0
  26. package/dist/cjs/server/worker.js +73 -0
  27. package/dist/cjs/session/cache.js +172 -0
  28. package/dist/cjs/session/index.js +63 -0
  29. package/dist/cjs/session/request.js +269 -0
  30. package/dist/cjs/session/types.js +18 -0
  31. package/dist/esm/abort.mjs +27 -0
  32. package/dist/esm/adapter.mjs +21 -0
  33. package/dist/esm/data/body.mjs +40 -0
  34. package/dist/esm/data/client.mjs +368 -0
  35. package/dist/esm/data/codec.mjs +112 -0
  36. package/dist/esm/data/index.mjs +7 -0
  37. package/dist/esm/data/private.mjs +39 -0
  38. package/dist/esm/data/routes.mjs +108 -0
  39. package/dist/esm/data/server.mjs +723 -0
  40. package/dist/esm/data/static.mjs +51 -0
  41. package/dist/esm/data/tree.mjs +193 -0
  42. package/dist/esm/data/types.mjs +6 -0
  43. package/dist/esm/document.mjs +131 -0
  44. package/dist/esm/entry-client.mjs +104 -0
  45. package/dist/esm/entry-server.mjs +215 -0
  46. package/dist/esm/federation.mjs +36 -0
  47. package/dist/esm/identity.mjs +63 -0
  48. package/dist/esm/index.mjs +1 -0
  49. package/dist/esm/localization.mjs +10 -0
  50. package/dist/esm/router.mjs +225 -0
  51. package/dist/esm/server/assets.mjs +15 -0
  52. package/dist/esm/server/dispatch.mjs +307 -0
  53. package/dist/esm/server/index.mjs +3 -0
  54. package/dist/esm/server/types.mjs +0 -0
  55. package/dist/esm/server/worker.mjs +35 -0
  56. package/dist/esm/session/cache.mjs +116 -0
  57. package/dist/esm/session/index.mjs +3 -0
  58. package/dist/esm/session/request.mjs +231 -0
  59. package/dist/esm/session/types.mjs +0 -0
  60. package/dist/esm-node/abort.mjs +28 -0
  61. package/dist/esm-node/adapter.mjs +22 -0
  62. package/dist/esm-node/data/body.mjs +41 -0
  63. package/dist/esm-node/data/client.mjs +369 -0
  64. package/dist/esm-node/data/codec.mjs +113 -0
  65. package/dist/esm-node/data/index.mjs +8 -0
  66. package/dist/esm-node/data/private.mjs +40 -0
  67. package/dist/esm-node/data/routes.mjs +109 -0
  68. package/dist/esm-node/data/server.mjs +724 -0
  69. package/dist/esm-node/data/static.mjs +52 -0
  70. package/dist/esm-node/data/tree.mjs +194 -0
  71. package/dist/esm-node/data/types.mjs +7 -0
  72. package/dist/esm-node/document.mjs +132 -0
  73. package/dist/esm-node/entry-client.mjs +105 -0
  74. package/dist/esm-node/entry-server.mjs +216 -0
  75. package/dist/esm-node/federation.mjs +37 -0
  76. package/dist/esm-node/identity.mjs +64 -0
  77. package/dist/esm-node/index.mjs +2 -0
  78. package/dist/esm-node/localization.mjs +11 -0
  79. package/dist/esm-node/router.mjs +226 -0
  80. package/dist/esm-node/server/assets.mjs +16 -0
  81. package/dist/esm-node/server/dispatch.mjs +308 -0
  82. package/dist/esm-node/server/index.mjs +4 -0
  83. package/dist/esm-node/server/types.mjs +1 -0
  84. package/dist/esm-node/server/worker.mjs +36 -0
  85. package/dist/esm-node/session/cache.mjs +117 -0
  86. package/dist/esm-node/session/index.mjs +4 -0
  87. package/dist/esm-node/session/request.mjs +232 -0
  88. package/dist/esm-node/session/types.mjs +1 -0
  89. package/dist/types/abort.d.ts +6 -0
  90. package/dist/types/adapter.d.ts +195 -0
  91. package/dist/types/data/body.d.ts +2 -0
  92. package/dist/types/data/client.d.ts +17 -0
  93. package/dist/types/data/codec.d.ts +14 -0
  94. package/dist/types/data/index.d.ts +8 -0
  95. package/dist/types/data/private.d.ts +6 -0
  96. package/dist/types/data/routes.d.ts +28 -0
  97. package/dist/types/data/server.d.ts +59 -0
  98. package/dist/types/data/static.d.ts +31 -0
  99. package/dist/types/data/tree.d.ts +3 -0
  100. package/dist/types/data/types.d.ts +104 -0
  101. package/dist/types/document.d.ts +76 -0
  102. package/dist/types/entry-client.d.ts +53 -0
  103. package/dist/types/entry-server.d.ts +63 -0
  104. package/dist/types/federation.d.ts +56 -0
  105. package/dist/types/identity.d.ts +27 -0
  106. package/dist/types/index.d.ts +1 -0
  107. package/dist/types/localization.d.ts +58 -0
  108. package/dist/types/router.d.ts +201 -0
  109. package/dist/types/server/assets.d.ts +14 -0
  110. package/dist/types/server/dispatch.d.ts +11 -0
  111. package/dist/types/server/index.d.ts +4 -0
  112. package/dist/types/server/types.d.ts +64 -0
  113. package/dist/types/server/worker.d.ts +25 -0
  114. package/dist/types/session/cache.d.ts +25 -0
  115. package/dist/types/session/index.d.ts +4 -0
  116. package/dist/types/session/request.d.ts +8 -0
  117. package/dist/types/session/types.d.ts +48 -0
  118. package/package.json +159 -4
  119. package/src/abort.ts +40 -0
  120. package/src/adapter.ts +255 -0
  121. package/src/data/body.ts +43 -0
  122. package/src/data/client.ts +501 -0
  123. package/src/data/codec.ts +247 -0
  124. package/src/data/index.ts +8 -0
  125. package/src/data/private.ts +68 -0
  126. package/src/data/routes.ts +201 -0
  127. package/src/data/server.ts +977 -0
  128. package/src/data/static.ts +105 -0
  129. package/src/data/tree.ts +244 -0
  130. package/src/data/types.ts +98 -0
  131. package/src/document.ts +338 -0
  132. package/src/entry-client.ts +236 -0
  133. package/src/entry-server.ts +393 -0
  134. package/src/federation.ts +111 -0
  135. package/src/identity.ts +128 -0
  136. package/src/index.ts +7 -0
  137. package/src/localization.ts +77 -0
  138. package/src/router.ts +475 -0
  139. package/src/server/assets.ts +60 -0
  140. package/src/server/dispatch.ts +523 -0
  141. package/src/server/index.ts +16 -0
  142. package/src/server/types.ts +94 -0
  143. package/src/server/worker.ts +94 -0
  144. package/src/session/cache.ts +177 -0
  145. package/src/session/index.ts +11 -0
  146. package/src/session/request.ts +324 -0
  147. package/src/session/types.ts +60 -0
@@ -0,0 +1,11 @@
1
+ import type { NativeDispatchOptions } from './types.js';
2
+ /** Runs before bundle loading, cache lookup, or any renderer dispatch. */
3
+ export declare function rejectNativeRscRequest(request: Request): Response | undefined;
4
+ /** Production Fetch dispatch. React rendering and matching are never imported. */
5
+ export declare function dispatchNativeRequest<Bindings extends object>(request: Request, options: NativeDispatchOptions<Bindings>): Promise<Response>;
6
+ /**
7
+ * Node host dispatch; the request platform binding is always `node`.
8
+ * The Node adapter hands over a Proxy for requests with a body, which
9
+ * `new Request(request)` rejects, so the body request is rebuilt first.
10
+ */
11
+ export declare function dispatchNativeNodeRequest<Bindings extends object>(request: Request, options: NativeDispatchOptions<Bindings>): Promise<Response>;
@@ -0,0 +1,4 @@
1
+ export { type NativeClientAssetManifest, RENDERER_ASSET_MANIFEST_FILE, validateNativeClientAssetManifest, } from './assets.js';
2
+ export { dispatchNativeNodeRequest, dispatchNativeRequest, rejectNativeRscRequest, } from './dispatch.js';
3
+ export type * from './types.js';
4
+ export { dispatchNativeWorkerRequest, type NativeWorkerDispatchOptions, type NativeWorkerEntryResources, } from './worker.js';
@@ -0,0 +1,64 @@
1
+ import type { DocumentAsset } from '../document.js';
2
+ import type { RendererIdentity } from '../identity.js';
3
+ import type { RequestPlatform, RequestSession } from '../session/index.js';
4
+ /** Native route matching remains with the selected router adapter. */
5
+ export interface NativeServerConfig {
6
+ readonly ssr?: boolean | 'stream';
7
+ readonly forceCSR?: boolean;
8
+ readonly ssrByRouteIds?: readonly string[];
9
+ }
10
+ export interface NativeRequestContext<Bindings extends object = object> {
11
+ readonly session: RequestSession<Bindings>;
12
+ readonly assets?: readonly DocumentAsset[];
13
+ readonly nonce?: string;
14
+ /** Opaque compiler-owned JSON. The native adapter validates its own ABI. */
15
+ readonly nativeManifest?: unknown;
16
+ readonly serverConfig?: NativeServerConfig;
17
+ readonly entry: Readonly<RendererIdentity>;
18
+ }
19
+ export type NativeRequestHandler<Bindings extends object = object> = (request: Request, context: NativeRequestContext<Bindings>) => Response | Promise<Response>;
20
+ /** Identity is generated with the bundle, never inferred from its filename. */
21
+ export interface NativeServerManifest<Bindings extends object = object> {
22
+ readonly rendererIdentity: RendererIdentity;
23
+ readonly nativeRequestHandler: NativeRequestHandler<Bindings>;
24
+ readonly nativeCSRRequestHandler?: NativeRequestHandler<Bindings>;
25
+ readonly nativeMatchRouteIds?: (request: Request, context: NativeRequestContext<Bindings>) => readonly string[] | Promise<readonly string[]>;
26
+ }
27
+ export interface CachedNativeDocument {
28
+ readonly identityKey: string;
29
+ /** Epoch milliseconds when the document was stored; replays derive Age from it. */
30
+ readonly storedAt: number;
31
+ readonly expiresAt: number;
32
+ readonly status: 200;
33
+ readonly statusText: string;
34
+ readonly headers: ReadonlyArray<readonly [string, string]>;
35
+ readonly bytes: Uint8Array;
36
+ }
37
+ /** All calls receive an identity-namespaced key, including custom stores. */
38
+ export interface NativeDocumentCache {
39
+ get(key: string): CachedNativeDocument | undefined | Promise<CachedNativeDocument | undefined>;
40
+ set(key: string, value: CachedNativeDocument): void | Promise<void>;
41
+ }
42
+ /** The subset of a worker execution context the native dispatcher uses. */
43
+ export interface NativeExecutionContext {
44
+ waitUntil(promise: Promise<unknown>): void;
45
+ }
46
+ export interface NativeDispatchOptions<Bindings extends object = object> {
47
+ readonly identity: RendererIdentity;
48
+ readonly loadManifest: () => NativeServerManifest<Bindings> | Promise<NativeServerManifest<Bindings>>;
49
+ readonly context: Omit<NativeRequestContext<Bindings>, 'session' | 'entry'> & {
50
+ readonly bindings: Bindings;
51
+ };
52
+ /** The request host binding kind. Defaults to `node`. */
53
+ readonly platform?: RequestPlatform['kind'];
54
+ /** Worker hosts retain each owned session until its cleanup completes. */
55
+ readonly executionContext?: NativeExecutionContext;
56
+ readonly cache?: NativeDocumentCache;
57
+ readonly maxCacheBytes?: number;
58
+ /** Native hydration ABI build, distinct from the source/profile identity. */
59
+ readonly hydrationBuildId?: string;
60
+ /** Node hosts confirm complete delivery and return the final wire headers. */
61
+ readonly confirmDelivery?: (response: Response) => Promise<Headers | undefined>;
62
+ readonly onCacheError?: (error: unknown) => void;
63
+ readonly onError?: (error: unknown, request: Request, context: NativeRequestContext<Bindings>) => Response | Promise<Response>;
64
+ }
@@ -0,0 +1,25 @@
1
+ import { type DocumentAsset } from '../document.js';
2
+ import { type RendererIdentity } from '../identity.js';
3
+ import type { NativeExecutionContext, NativeServerConfig } from './types.js';
4
+ /** Build-validated per-entry inputs a worker bundle cannot read from disk. */
5
+ export interface NativeWorkerEntryResources {
6
+ readonly assets: readonly DocumentAsset[];
7
+ /** Opaque compiler-owned JSON, revalidated by the native request handler. */
8
+ readonly nativeManifest?: unknown;
9
+ readonly hydrationBuildId?: string;
10
+ readonly serverConfig: NativeServerConfig;
11
+ /** Present only when the entry admits a CSR fallback request. */
12
+ readonly csrFallbackHeader?: string;
13
+ readonly nonce?: string;
14
+ }
15
+ export interface NativeWorkerDispatchOptions<Bindings extends object> {
16
+ readonly identity: RendererIdentity;
17
+ /** The imported worker bundle: its namespace or default-exported manifest. */
18
+ readonly bundle: unknown;
19
+ readonly resources: NativeWorkerEntryResources;
20
+ /** The module worker `env`, forwarded unchanged as the platform binding. */
21
+ readonly bindings: Bindings | undefined;
22
+ readonly executionContext?: NativeExecutionContext;
23
+ }
24
+ /** Worker Fetch dispatch over the same native handler the Node host loads. */
25
+ export declare function dispatchNativeWorkerRequest<Bindings extends object>(request: Request, options: NativeWorkerDispatchOptions<Bindings>): Promise<Response>;
@@ -0,0 +1,25 @@
1
+ import { type RendererIdentity } from '../identity.js';
2
+ import type { DocumentCachePolicy, ResponseHeaders, ResponsePolicy } from './types.js';
3
+ /** Compute this before looking up any application-provided request key. */
4
+ export declare function documentCacheKey(identity: RendererIdentity, requestKey: string): string;
5
+ /** Header fields with each Set-Cookie kept as its own entry. */
6
+ export declare function responseHeaders(headers: Headers): [string, string][];
7
+ export declare function policyHeaders(headers: ResponseHeaders): Headers;
8
+ /**
9
+ * Every Cache-Control directive in order, names lowercased, or `undefined`
10
+ * when any part is malformed (an unterminated quote, trailing syntax). Quoted
11
+ * values are consumed whole, so their text is never read as a directive.
12
+ */
13
+ export declare function parseCacheControl(value: string): {
14
+ name: string;
15
+ value: string | undefined;
16
+ }[] | undefined;
17
+ /** The `max-age` and `s-maxage` lifetimes these headers declare. */
18
+ export declare function headerMaxAgeSeconds(headers: Headers): number[];
19
+ export declare function permitsDocumentCache(policy: ResponsePolicy): boolean;
20
+ /**
21
+ * Narrow a policy's cache to what every header source allows, then write the
22
+ * matching Cache-Control to `outgoing`. Only a 200 HTML document can be public;
23
+ * its lifetime is the shortest one any source declares.
24
+ */
25
+ export declare function restrictDocumentCache(policy: ResponsePolicy, sources: readonly Headers[], outgoing: Headers): DocumentCachePolicy;
@@ -0,0 +1,4 @@
1
+ export { untilAborted } from '../abort.js';
2
+ export { documentCacheKey, headerMaxAgeSeconds, permitsDocumentCache, policyHeaders, responseHeaders, restrictDocumentCache, } from './cache.js';
3
+ export { createRequestSession } from './request.js';
4
+ export type * from './types.js';
@@ -0,0 +1,8 @@
1
+ import type { RendererIdentity } from '../identity.js';
2
+ import type { RequestPlatform, RequestSession } from './types.js';
3
+ /** Owns one request and the lifetime of its response body, not a server instance. */
4
+ export declare function createRequestSession<Bindings extends object>(input: {
5
+ request: Request;
6
+ identity: RendererIdentity;
7
+ platform: RequestPlatform<Bindings>;
8
+ }): RequestSession<Bindings>;
@@ -0,0 +1,48 @@
1
+ import type { RendererIdentity } from '../identity.js';
2
+ export type ResponseHeaders = ReadonlyArray<readonly [string, string]>;
3
+ export type DocumentCachePolicy = {
4
+ readonly mode: 'no-store' | 'private';
5
+ } | {
6
+ readonly mode: 'public';
7
+ readonly maxAgeSeconds: number;
8
+ };
9
+ export interface ResponsePolicy {
10
+ readonly kind: 'document' | 'terminal';
11
+ readonly status: number;
12
+ readonly statusText?: string;
13
+ readonly headers: ResponseHeaders;
14
+ readonly cache: DocumentCachePolicy;
15
+ }
16
+ export interface RequestPlatform<Bindings extends object = object> {
17
+ readonly kind: 'node' | 'worker';
18
+ readonly bindings: Bindings;
19
+ }
20
+ export type RequestState = 'matching' | 'ready' | 'rendering' | 'committed' | 'completed' | 'failed' | 'aborted';
21
+ export interface RequestCompletion {
22
+ readonly state: 'completed' | 'failed' | 'aborted';
23
+ readonly fallback: boolean;
24
+ readonly error?: unknown;
25
+ readonly cleanupErrors: readonly unknown[];
26
+ readonly cacheEligible: boolean;
27
+ }
28
+ export type RequestCleanup = () => void | Promise<void>;
29
+ export interface RequestSession<Bindings extends object = object> {
30
+ readonly request: Request;
31
+ readonly identity: Readonly<RendererIdentity>;
32
+ readonly platform: RequestPlatform<Bindings>;
33
+ readonly signal: AbortSignal;
34
+ readonly state: RequestState;
35
+ readonly responsePolicy: ResponsePolicy | undefined;
36
+ readonly committedPolicy: ResponsePolicy | undefined;
37
+ readonly completion: Promise<RequestCompletion>;
38
+ resolveResponse(policy: ResponsePolicy): void;
39
+ startRendering(): void;
40
+ registerCleanup(cleanup: RequestCleanup): () => void;
41
+ markFallback(): void;
42
+ respond(body: ReadableStream<Uint8Array> | null): Response;
43
+ /** The returned response must deliver this session's final owned stream. */
44
+ ownsResponseBody(response: Response): boolean;
45
+ /** Notify termination. Await completion separately outside owned cleanup. */
46
+ fail(error: unknown): void;
47
+ abort(reason?: unknown): void;
48
+ }
package/package.json CHANGED
@@ -1,11 +1,166 @@
1
1
  {
2
2
  "name": "@bleedingdev/modern-js-renderer-core",
3
- "version": "0.0.0-bootstrap",
4
- "description": "Package-name reservation. Release versions publish through GitHub Trusted Publishing.",
3
+ "version": "3.9.3-ultramodern.1",
4
+ "description": "UltraModern native renderer request, data and document contracts.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "git+https://github.com/ultramodernjs/ultramodern.js.git"
8
+ "url": "git+https://github.com/ultramodernjs/ultramodern.js.git",
9
+ "directory": "packages/runtime/renderer-core"
9
10
  },
10
- "deprecated": "Package-name reservation only. Install a release version published through GitHub Trusted Publishing."
11
+ "files": [
12
+ "dist",
13
+ "src"
14
+ ],
15
+ "main": "./dist/cjs/index.js",
16
+ "types": "./dist/types/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "import": {
20
+ "types": "./dist/types/index.d.ts",
21
+ "default": "./dist/esm/index.mjs"
22
+ },
23
+ "require": {
24
+ "types": "./dist/types/index.d.ts",
25
+ "default": "./dist/cjs/index.js"
26
+ }
27
+ },
28
+ "./identity": {
29
+ "import": {
30
+ "types": "./dist/types/identity.d.ts",
31
+ "default": "./dist/esm/identity.mjs"
32
+ },
33
+ "require": {
34
+ "types": "./dist/types/identity.d.ts",
35
+ "default": "./dist/cjs/identity.js"
36
+ }
37
+ },
38
+ "./adapter": {
39
+ "import": {
40
+ "types": "./dist/types/adapter.d.ts",
41
+ "default": "./dist/esm/adapter.mjs"
42
+ },
43
+ "require": {
44
+ "types": "./dist/types/adapter.d.ts",
45
+ "default": "./dist/cjs/adapter.js"
46
+ }
47
+ },
48
+ "./package.json": "./package.json",
49
+ "./federation": {
50
+ "import": {
51
+ "types": "./dist/types/federation.d.ts",
52
+ "default": "./dist/esm/federation.mjs"
53
+ },
54
+ "require": {
55
+ "types": "./dist/types/federation.d.ts",
56
+ "default": "./dist/cjs/federation.js"
57
+ }
58
+ },
59
+ "./data": {
60
+ "import": {
61
+ "types": "./dist/types/data/index.d.ts",
62
+ "default": "./dist/esm/data/index.mjs"
63
+ },
64
+ "require": {
65
+ "types": "./dist/types/data/index.d.ts",
66
+ "default": "./dist/cjs/data/index.js"
67
+ }
68
+ },
69
+ "./session": {
70
+ "import": {
71
+ "types": "./dist/types/session/index.d.ts",
72
+ "default": "./dist/esm/session/index.mjs"
73
+ },
74
+ "require": {
75
+ "types": "./dist/types/session/index.d.ts",
76
+ "default": "./dist/cjs/session/index.js"
77
+ }
78
+ },
79
+ "./document": {
80
+ "import": {
81
+ "types": "./dist/types/document.d.ts",
82
+ "default": "./dist/esm/document.mjs"
83
+ },
84
+ "require": {
85
+ "types": "./dist/types/document.d.ts",
86
+ "default": "./dist/cjs/document.js"
87
+ }
88
+ },
89
+ "./router": {
90
+ "import": {
91
+ "types": "./dist/types/router.d.ts",
92
+ "default": "./dist/esm/router.mjs"
93
+ },
94
+ "require": {
95
+ "types": "./dist/types/router.d.ts",
96
+ "default": "./dist/cjs/router.js"
97
+ }
98
+ },
99
+ "./server": {
100
+ "import": {
101
+ "types": "./dist/types/server/index.d.ts",
102
+ "default": "./dist/esm/server/index.mjs"
103
+ },
104
+ "require": {
105
+ "types": "./dist/types/server/index.d.ts",
106
+ "default": "./dist/cjs/server/index.js"
107
+ }
108
+ },
109
+ "./entry-client": {
110
+ "import": {
111
+ "types": "./dist/types/entry-client.d.ts",
112
+ "default": "./dist/esm/entry-client.mjs"
113
+ },
114
+ "require": {
115
+ "types": "./dist/types/entry-client.d.ts",
116
+ "default": "./dist/cjs/entry-client.js"
117
+ }
118
+ },
119
+ "./entry-server": {
120
+ "import": {
121
+ "types": "./dist/types/entry-server.d.ts",
122
+ "default": "./dist/esm/entry-server.mjs"
123
+ },
124
+ "require": {
125
+ "types": "./dist/types/entry-server.d.ts",
126
+ "default": "./dist/cjs/entry-server.js"
127
+ }
128
+ }
129
+ },
130
+ "engines": {
131
+ "node": ">=26.10.0"
132
+ },
133
+ "dependencies": {
134
+ "seroval": "1.6.8"
135
+ },
136
+ "peerDependencies": {
137
+ "@rsbuild/core": "2.2.11"
138
+ },
139
+ "peerDependenciesMeta": {
140
+ "@rsbuild/core": {
141
+ "optional": true
142
+ }
143
+ },
144
+ "devDependencies": {
145
+ "@modern-js/tsconfig": "npm:@bleedingdev/modern-js-tsconfig@3.9.3-ultramodern.1",
146
+ "@rsbuild/core": "2.2.11",
147
+ "@rslib/core": "1.0.3",
148
+ "@scripts/rstest-config": "2.66.0",
149
+ "@types/node": "^26.6.3"
150
+ },
151
+ "sideEffects": false,
152
+ "publishConfig": {
153
+ "access": "public"
154
+ },
155
+ "scripts": {
156
+ "build": "rslib build",
157
+ "test": "rstest"
158
+ },
159
+ "homepage": "https://github.com/ultramodernjs/ultramodern.js#readme",
160
+ "bugs": {
161
+ "url": "https://github.com/ultramodernjs/ultramodern.js/issues"
162
+ },
163
+ "ultramodern": {
164
+ "sourceName": "@modern-js/renderer-core"
165
+ }
11
166
  }
package/src/abort.ts ADDED
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Settle with the work, or reject once the signal aborts: work that ignores
3
+ * cancellation must not keep its caller alive. A late Response body is
4
+ * cancelled and a late failure observed.
5
+ */
6
+ export function untilAborted<T>(
7
+ handled: T | Promise<T>,
8
+ signal: AbortSignal,
9
+ ): Promise<T> {
10
+ const settled = Promise.resolve(handled);
11
+ const discard = () =>
12
+ void settled.then(
13
+ value => {
14
+ if (value instanceof Response)
15
+ void value.body?.cancel().catch(() => {});
16
+ },
17
+ () => {},
18
+ );
19
+ if (signal.aborted) {
20
+ discard();
21
+ return Promise.reject(signal.reason);
22
+ }
23
+ return new Promise<T>((resolve, reject) => {
24
+ const onAbort = () => {
25
+ discard();
26
+ reject(signal.reason);
27
+ };
28
+ signal.addEventListener('abort', onAbort, { once: true });
29
+ settled.then(
30
+ value => {
31
+ signal.removeEventListener('abort', onAbort);
32
+ resolve(value);
33
+ },
34
+ error => {
35
+ signal.removeEventListener('abort', onAbort);
36
+ reject(error);
37
+ },
38
+ );
39
+ });
40
+ }
package/src/adapter.ts ADDED
@@ -0,0 +1,255 @@
1
+ import type { RsbuildPlugin } from '@rsbuild/core';
2
+ import type { Renderer, RendererIdentity } from './identity';
3
+
4
+ /**
5
+ * Renderer adapters are build-side descriptors. A renderer package exports one
6
+ * from its `./plugin` entry; UltraModern loads only the selected adapter and
7
+ * drives native entries, compilation, artifacts, deployment and scaffolding
8
+ * from its data. Nothing here is imported by application runtime code.
9
+ */
10
+
11
+ export interface RendererBuildProfile<TRenderer extends Renderer = Renderer> {
12
+ renderer: TRenderer;
13
+ status: 'stable' | 'preview';
14
+ protocolVersion: 1;
15
+ minimumNode: '26.10.0';
16
+ hmr: {
17
+ editedBoundary: 'may-reset';
18
+ unaffectedComponents: 'preserved';
19
+ document: 'preserved';
20
+ roots: 'single';
21
+ cleanup: 'exactly-once';
22
+ };
23
+ compiler: { name: string; version: string };
24
+ hydration: { name: string; version: string };
25
+ router: {
26
+ name: string;
27
+ version: string;
28
+ coreName: string;
29
+ coreVersion: string;
30
+ };
31
+ sourceExtensions: readonly string[];
32
+ jsxImportSource: string;
33
+ dependencies: Readonly<Record<string, string>>;
34
+ capabilities: {
35
+ worker: boolean;
36
+ /**
37
+ * `true`: Module Federation with SSR. React federates through the React
38
+ * MF plugin; native renderers server-render same-renderer federated
39
+ * components from a native module-federation.config.
40
+ * `'client'`: native same-renderer federated components rendered on the
41
+ * client only.
42
+ */
43
+ moduleFederation: boolean | 'client';
44
+ rsc: boolean;
45
+ ssg: boolean;
46
+ i18n: boolean;
47
+ svgComponent: boolean;
48
+ };
49
+ }
50
+
51
+ export interface NativeRendererCompilerOptions {
52
+ /** The selected native infrastructure owns these source-build identities. */
53
+ rendererIdentities(): Readonly<Record<string, RendererIdentity>>;
54
+ /** Rsbuild environment that renders server documents inside a web worker. */
55
+ readonly workerEnvironmentName: string;
56
+ }
57
+
58
+ export interface NativeCompilerArtifactContext {
59
+ /** Hash from the completed client compiler, when validating emitted output. */
60
+ readonly compilationHash?: string;
61
+ /** Hydration identity retained with a development snapshot. */
62
+ readonly hydrationBuildId?: string;
63
+ readonly development?: boolean;
64
+ }
65
+
66
+ export interface ValidatedNativeCompilerArtifact {
67
+ readonly nativeManifest: unknown;
68
+ /** Optional compiler-owned hydration and document cache identity. */
69
+ readonly hydrationBuildId?: string;
70
+ }
71
+
72
+ /** The selected compiler owns its artifact ABI; lifecycle consumers keep it opaque. */
73
+ export interface NativeCompilerArtifacts {
74
+ clientManifestFile(entryName: string): string;
75
+ validateClientManifest(
76
+ value: unknown,
77
+ identity: RendererIdentity,
78
+ context: NativeCompilerArtifactContext,
79
+ ): Promise<ValidatedNativeCompilerArtifact>;
80
+ isMutableDevelopmentAsset(
81
+ filename: string,
82
+ entryNames: readonly string[],
83
+ ): boolean;
84
+ }
85
+
86
+ /** Public modules the generated native entries and the host import. */
87
+ export interface NativeRendererRuntime {
88
+ /** The renderer's own reactive runtime package, e.g. `solid-js`. */
89
+ readonly package: string;
90
+ /** The renderer package that owns this adapter and its runtime modules. */
91
+ readonly bootstrap: string;
92
+ readonly entryClient: string;
93
+ readonly entryServer: string;
94
+ readonly router: string;
95
+ readonly i18n?: string;
96
+ /**
97
+ * Exports the renderer's `compilerArtifacts`, which the production server
98
+ * loads to validate compiler module manifests; also proves the installed
99
+ * owner.
100
+ */
101
+ readonly manifest: string;
102
+ }
103
+
104
+ export interface NativeRendererFederation {
105
+ /** Runtime singletons a host and every remote share (`pkg/` for subpaths). */
106
+ readonly shared: readonly string[];
107
+ /** Required providers, with the native import each compilation owns. */
108
+ readonly sharedByEnvironment?: Readonly<
109
+ Record<'client' | 'server', Readonly<Record<string, string>>>
110
+ >;
111
+ /** Browser container format, matching the renderer's client chunks. */
112
+ readonly library: 'module';
113
+ /** Whether federated components also render on the server. */
114
+ readonly ssr: boolean;
115
+ }
116
+
117
+ export interface RendererWorkerSupport {
118
+ /** Worker documents come from the renderer's native server handler. */
119
+ readonly nativeDocuments: boolean;
120
+ readonly rsc: boolean;
121
+ }
122
+
123
+ export interface NativeEntryClientStub {
124
+ /** Ambient declarations the generated client entry needs. */
125
+ readonly declarations: string;
126
+ /** Extra `startNativeClient` fields, as source expressions. */
127
+ readonly fields: Readonly<Record<string, string>>;
128
+ }
129
+
130
+ export interface RendererAppSourceOptions {
131
+ appId: string;
132
+ title: string;
133
+ entryName: string;
134
+ sourceExtension: '.tsx' | '.tsrx';
135
+ jsxImportSource: string;
136
+ capabilities: { ssr: boolean; federation: boolean };
137
+ }
138
+
139
+ export interface RendererAppSources {
140
+ sourceExtension: '.tsx' | '.tsrx';
141
+ jsxImportSource: string;
142
+ artifacts: { path: string; content: string }[];
143
+ }
144
+
145
+ export interface RendererCreatePackages {
146
+ /** Framework packages the generated application depends on directly. */
147
+ frameworkDependencies: readonly string[];
148
+ dependencies: Record<string, string>;
149
+ devDependencies: Record<string, string>;
150
+ typecheckCommand?: string;
151
+ tsconfig?: Record<string, unknown>;
152
+ }
153
+
154
+ export interface RendererCreateSupport {
155
+ /** Deployment templates the adapter admits in generated workspaces. */
156
+ readonly templates?: {
157
+ readonly federation: boolean;
158
+ readonly workers: boolean;
159
+ };
160
+ dependencies(
161
+ profile: RendererBuildProfile,
162
+ context: { readonly typescriptVersion: string },
163
+ ): RendererCreatePackages;
164
+ generateAppSources(options: RendererAppSourceOptions): RendererAppSources;
165
+ }
166
+
167
+ interface RendererAdapterDescriptor<TRenderer extends Renderer> {
168
+ readonly name: TRenderer;
169
+ readonly profile: RendererBuildProfile<TRenderer>;
170
+ readonly routerFrameworks: readonly string[];
171
+ readonly worker: RendererWorkerSupport;
172
+ readonly create?: RendererCreateSupport;
173
+ }
174
+
175
+ export interface NativeRendererAdapter<TRenderer extends Renderer = Renderer>
176
+ extends RendererAdapterDescriptor<TRenderer> {
177
+ readonly kind: 'native';
178
+ readonly runtime: NativeRendererRuntime;
179
+ readonly federation?: NativeRendererFederation;
180
+ readonly entryClient?: NativeEntryClientStub;
181
+ /**
182
+ * Who links the stylesheets of lazy components in a server document.
183
+ * `'renderer'`: the server render links each one beside the markup it
184
+ * renders. `'document'`: the render cannot report which lazy modules it
185
+ * rendered, so the document links every lazy stylesheet up front.
186
+ */
187
+ readonly lazyStyles: 'renderer' | 'document';
188
+ /** Path of a CommonJS module exporting `(parts) => source` for `?component` SVGs. */
189
+ svgComponentTemplate?(): string;
190
+ /** The renderer compiler; UltraModern applies SVG and ownership policy. */
191
+ compiler(options: NativeRendererCompilerOptions): RsbuildPlugin;
192
+ readonly artifacts: NativeCompilerArtifacts;
193
+ assertSupportedSource?(source: string | false | undefined): Promise<void>;
194
+ }
195
+
196
+ /** A renderer composed from an existing plugin stack (React only). */
197
+ export interface ComposedRendererAdapter<
198
+ TRenderer extends Renderer = Renderer,
199
+ TPlugin = unknown,
200
+ TPolicy = unknown,
201
+ > extends RendererAdapterDescriptor<TRenderer> {
202
+ readonly kind: 'composed';
203
+ /** Public modules whose installed owners pin the profile versions. */
204
+ readonly frameworkModules: readonly {
205
+ readonly specifier: string;
206
+ readonly request: string;
207
+ }[];
208
+ compose(consumerPlugins: readonly TPlugin[], policy?: TPolicy): TPlugin;
209
+ }
210
+
211
+ export type RendererAdapter<TRenderer extends Renderer = Renderer> =
212
+ | NativeRendererAdapter<TRenderer>
213
+ | ComposedRendererAdapter<TRenderer>;
214
+
215
+ const adapterError = (name: unknown, detail: string) =>
216
+ new Error(`Invalid renderer adapter ${String(name)}: ${detail}`);
217
+
218
+ /** Validate an adapter's internal consistency and freeze its descriptor data. */
219
+ export function defineRendererAdapter<T extends RendererAdapter>(
220
+ adapter: T,
221
+ ): T {
222
+ const { name, profile } = adapter;
223
+ if (profile.renderer !== name)
224
+ throw adapterError(name, `profile names ${profile.renderer}`);
225
+ if (!adapter.routerFrameworks.length)
226
+ throw adapterError(name, 'it declares no router framework');
227
+ if (adapter.worker.rsc !== profile.capabilities.rsc)
228
+ throw adapterError(name, 'worker RSC support contradicts its profile');
229
+ if (adapter.kind === 'native') {
230
+ if (adapter.worker.nativeDocuments !== true)
231
+ throw adapterError(name, 'native documents come from its server handler');
232
+ const federation = adapter.federation;
233
+ const capability = profile.capabilities.moduleFederation;
234
+ if (
235
+ (federation === undefined) !== (capability === false) ||
236
+ (federation !== undefined && federation.ssr !== (capability === true))
237
+ )
238
+ throw adapterError(name, 'federation support contradicts its profile');
239
+ }
240
+ return Object.freeze(adapter);
241
+ }
242
+
243
+ /** Third-party runtime packages a generated native application installs. */
244
+ export function nativeRendererDependencies(
245
+ profile: RendererBuildProfile,
246
+ ): Record<string, string> {
247
+ return {
248
+ ...Object.fromEntries(
249
+ Object.entries(profile.dependencies).filter(
250
+ ([name]) => !name.startsWith('@modern-js/'),
251
+ ),
252
+ ),
253
+ [profile.router.coreName]: profile.router.coreVersion,
254
+ };
255
+ }