@chidchanun/bcp 0.1.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.
Files changed (66) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/LICENSE +21 -0
  3. package/README.md +241 -0
  4. package/docs/caching.md +76 -0
  5. package/docs/configuration.md +97 -0
  6. package/docs/deployment.md +74 -0
  7. package/docs/getting-started.md +82 -0
  8. package/docs/middleware.md +58 -0
  9. package/docs/releasing.md +299 -0
  10. package/docs/routing.md +103 -0
  11. package/docs/security.md +57 -0
  12. package/package.json +68 -0
  13. package/packages/bundler/src/client-islands.ts +1457 -0
  14. package/packages/bundler/src/incremental-context.ts +206 -0
  15. package/packages/bundler/src/index.ts +1991 -0
  16. package/packages/bundler/src/module-graph.ts +317 -0
  17. package/packages/bundler/src/partial-hydration.ts +414 -0
  18. package/packages/bundler/src/production.ts +974 -0
  19. package/packages/bundler/src/server-production-middleware.ts +447 -0
  20. package/packages/bundler/src/server-production.ts +1193 -0
  21. package/packages/bundler/src/special-files.ts +131 -0
  22. package/packages/cache/src/index.ts +761 -0
  23. package/packages/cli/bin/bcp.mjs +93 -0
  24. package/packages/cli/src/args.ts +305 -0
  25. package/packages/cli/src/bootstrap.ts +514 -0
  26. package/packages/cli/src/index.ts +504 -0
  27. package/packages/cli/src/version.ts +45 -0
  28. package/packages/client/src/cache.ts +11 -0
  29. package/packages/client/src/config.ts +18 -0
  30. package/packages/client/src/error-boundary.tsx +149 -0
  31. package/packages/client/src/hydration.ts +3 -0
  32. package/packages/client/src/index.tsx +57 -0
  33. package/packages/client/src/islands.tsx +315 -0
  34. package/packages/client/src/metadata.ts +281 -0
  35. package/packages/client/src/navigation-loading.ts +52 -0
  36. package/packages/client/src/navigation-state.ts +80 -0
  37. package/packages/client/src/not-found.ts +34 -0
  38. package/packages/client/src/persistent-layout-runtime.ts +273 -0
  39. package/packages/client/src/router-v2.tsx +969 -0
  40. package/packages/client/src/router.tsx +1 -0
  41. package/packages/config/src/index.ts +1038 -0
  42. package/packages/env/src/index.ts +593 -0
  43. package/packages/router/src/advanced-router.ts +1032 -0
  44. package/packages/router/src/index.ts +1 -0
  45. package/packages/server/src/compression.ts +249 -0
  46. package/packages/server/src/dev-document-metadata.ts +154 -0
  47. package/packages/server/src/dev-hmr.ts +225 -0
  48. package/packages/server/src/index.ts +2265 -0
  49. package/packages/server/src/metadata.ts +478 -0
  50. package/packages/server/src/middleware-dev-server.ts +260 -0
  51. package/packages/server/src/middleware-loader.ts +140 -0
  52. package/packages/server/src/middleware-proxy.ts +516 -0
  53. package/packages/server/src/middleware.ts +704 -0
  54. package/packages/server/src/navigation-payload.ts +471 -0
  55. package/packages/server/src/production-server.ts +1746 -0
  56. package/packages/server/src/response-cache-proxy.ts +828 -0
  57. package/packages/server/src/security-proxy.ts +406 -0
  58. package/packages/server/src/security.ts +451 -0
  59. package/packages/server/src/standalone-production-runtime-v2.ts +2047 -0
  60. package/packages/server/src/standalone-production-runtime-v3.ts +250 -0
  61. package/packages/server/src/standalone-production-runtime-v4.ts +289 -0
  62. package/packages/server/src/standalone-production-runtime-v5.ts +289 -0
  63. package/packages/server/src/standalone-production-runtime.ts +1951 -0
  64. package/packages/server/src/standalone-production-server.ts +6 -0
  65. package/packages/server/src/static-assets.ts +262 -0
  66. package/packages/server/src/static-dev-server.ts +854 -0
@@ -0,0 +1,80 @@
1
+ import {
2
+ useSyncExternalStore,
3
+ } from "react";
4
+
5
+ export interface NavigationState {
6
+ isNavigating: boolean;
7
+
8
+ targetHref: string | null;
9
+
10
+ targetRoute: string | null;
11
+ }
12
+
13
+ const serverSnapshot: NavigationState = {
14
+ isNavigating: false,
15
+ targetHref: null,
16
+ targetRoute: null,
17
+ };
18
+
19
+ let currentState: NavigationState =
20
+ serverSnapshot;
21
+
22
+ const listeners =
23
+ new Set<() => void>();
24
+
25
+ export function getNavigationState(): NavigationState {
26
+ return currentState;
27
+ }
28
+
29
+ export function setNavigationState(
30
+ nextState: Partial<NavigationState>
31
+ ): void {
32
+ currentState = {
33
+ ...currentState,
34
+ ...nextState,
35
+ };
36
+
37
+ for (
38
+ const listener
39
+ of listeners
40
+ ) {
41
+ listener();
42
+ }
43
+ }
44
+
45
+ export function resetNavigationState(): void {
46
+ currentState = {
47
+ isNavigating: false,
48
+ targetHref: null,
49
+ targetRoute: null,
50
+ };
51
+
52
+ for (
53
+ const listener
54
+ of listeners
55
+ ) {
56
+ listener();
57
+ }
58
+ }
59
+
60
+ export function useNavigation(): NavigationState {
61
+ return useSyncExternalStore(
62
+ subscribe,
63
+ getNavigationState,
64
+ () => serverSnapshot
65
+ );
66
+ }
67
+
68
+ function subscribe(
69
+ listener: () => void
70
+ ): () => void {
71
+ listeners.add(
72
+ listener
73
+ );
74
+
75
+ return () => {
76
+ listeners.delete(
77
+ listener
78
+ );
79
+ };
80
+ }
@@ -0,0 +1,34 @@
1
+ const NOT_FOUND_CODE =
2
+ "BCP_NOT_FOUND";
3
+
4
+ export interface BcpNotFoundError
5
+ extends Error {
6
+ code:
7
+ typeof NOT_FOUND_CODE;
8
+ }
9
+
10
+ export function notFound(): never {
11
+ const error =
12
+ new Error(
13
+ "BCP Framework: notFound() was called."
14
+ ) as BcpNotFoundError;
15
+
16
+ error.name =
17
+ "BcpNotFoundError";
18
+ error.code =
19
+ NOT_FOUND_CODE;
20
+
21
+ throw error;
22
+ }
23
+
24
+ export function isNotFoundError(
25
+ error: unknown
26
+ ): error is BcpNotFoundError {
27
+ return (
28
+ typeof error === "object" &&
29
+ error !== null &&
30
+ "code" in error &&
31
+ error.code ===
32
+ NOT_FOUND_CODE
33
+ );
34
+ }
@@ -0,0 +1,273 @@
1
+ import {
2
+ createElement,
3
+ isValidElement,
4
+ type ReactElement,
5
+ type ReactNode,
6
+ } from "react";
7
+
8
+ declare global {
9
+ var __BCP_LAYOUT_RUNTIME_INSTALLED__:
10
+ | boolean
11
+ | undefined;
12
+ }
13
+
14
+ const layoutTypes =
15
+ new Map<string, ReactElement["type"]>();
16
+
17
+ function installPersistentLayoutRuntime(): void {
18
+ if (
19
+ typeof window === "undefined"
20
+ ) {
21
+ return;
22
+ }
23
+
24
+ if (
25
+ globalThis.__BCP_LAYOUT_RUNTIME_INSTALLED__
26
+ ) {
27
+ return;
28
+ }
29
+
30
+ const root =
31
+ globalThis.__BCP_REACT_ROOT__;
32
+
33
+ if (!root) {
34
+ queueMicrotask(
35
+ installPersistentLayoutRuntime
36
+ );
37
+
38
+ return;
39
+ }
40
+
41
+ const originalRender =
42
+ root.render.bind(root);
43
+
44
+ root.render = (
45
+ tree: ReactNode
46
+ ) => {
47
+ originalRender(
48
+ normalizeLayoutTree(
49
+ tree
50
+ )
51
+ );
52
+ };
53
+
54
+ globalThis.__BCP_LAYOUT_RUNTIME_INSTALLED__ =
55
+ true;
56
+ }
57
+
58
+ queueMicrotask(
59
+ installPersistentLayoutRuntime
60
+ );
61
+
62
+ function normalizeLayoutTree(
63
+ tree: ReactNode
64
+ ): ReactNode {
65
+ const route =
66
+ getCurrentRoutePattern();
67
+
68
+ const layoutKeys =
69
+ getLayoutSegmentKeys(
70
+ route
71
+ );
72
+
73
+ const chain:
74
+ ReactElement[] = [];
75
+
76
+ let current =
77
+ tree;
78
+
79
+ let depth = 0;
80
+
81
+ while (
82
+ isValidElement(
83
+ current
84
+ )
85
+ ) {
86
+ const props =
87
+ current.props as {
88
+ children?: ReactNode;
89
+ };
90
+
91
+ if (
92
+ !isValidElement(
93
+ props.children
94
+ )
95
+ ) {
96
+ break;
97
+ }
98
+
99
+ if (
100
+ typeof current.type !==
101
+ "function"
102
+ ) {
103
+ break;
104
+ }
105
+
106
+ const layoutKey =
107
+ layoutKeys[depth] ??
108
+ `depth:${depth}`;
109
+
110
+ const existingType =
111
+ layoutTypes.get(
112
+ layoutKey
113
+ );
114
+
115
+ if (
116
+ existingType
117
+ ) {
118
+ chain.push(
119
+ createElement(
120
+ existingType,
121
+ createElementProps(
122
+ current
123
+ ),
124
+ props.children
125
+ )
126
+ );
127
+ } else {
128
+ layoutTypes.set(
129
+ layoutKey,
130
+ current.type
131
+ );
132
+
133
+ chain.push(
134
+ current
135
+ );
136
+ }
137
+
138
+ current =
139
+ props.children;
140
+
141
+ depth++;
142
+ }
143
+
144
+ if (
145
+ chain.length === 0
146
+ ) {
147
+ return tree;
148
+ }
149
+
150
+ let result =
151
+ current;
152
+
153
+ for (
154
+ let index =
155
+ chain.length - 1;
156
+ index >= 0;
157
+ index--
158
+ ) {
159
+ const layout =
160
+ chain[index];
161
+
162
+ const props =
163
+ layout.props as
164
+ Record<string, unknown>;
165
+
166
+ result =
167
+ createElement(
168
+ layout.type,
169
+ {
170
+ ...props,
171
+ ...(layout.key !==
172
+ null
173
+ ? {
174
+ key:
175
+ layout.key,
176
+ }
177
+ : {}),
178
+ },
179
+ result
180
+ );
181
+ }
182
+
183
+ return result;
184
+ }
185
+
186
+ function getCurrentRoutePattern(): string {
187
+ if (
188
+ typeof document !==
189
+ "undefined"
190
+ ) {
191
+ const dataElement =
192
+ document.getElementById(
193
+ "__BCP_DATA__"
194
+ );
195
+
196
+ if (
197
+ dataElement?.textContent
198
+ ) {
199
+ try {
200
+ const data =
201
+ JSON.parse(
202
+ dataElement.textContent
203
+ ) as {
204
+ route?: unknown;
205
+ };
206
+
207
+ if (
208
+ typeof data.route ===
209
+ "string"
210
+ ) {
211
+ return data.route;
212
+ }
213
+ } catch {
214
+ // Fall through to the runtime URL.
215
+ }
216
+ }
217
+ }
218
+
219
+ return (
220
+ globalThis.__BCP_DEV_CONFIG__
221
+ ?.route ??
222
+ window.location.pathname
223
+ );
224
+ }
225
+
226
+ function createElementProps(
227
+ element: ReactElement
228
+ ): Record<string, unknown> {
229
+ return {
230
+ ...(element.props as
231
+ Record<string, unknown>),
232
+
233
+ ...(element.key !== null
234
+ ? {
235
+ key:
236
+ element.key,
237
+ }
238
+ : {}),
239
+ };
240
+ }
241
+
242
+ function getLayoutSegmentKeys(
243
+ route: string
244
+ ): string[] {
245
+ const pathname =
246
+ route.split("?")[0] ||
247
+ "/";
248
+
249
+ const segments =
250
+ pathname
251
+ .split("/")
252
+ .filter(Boolean);
253
+
254
+ const keys = [
255
+ "/",
256
+ ];
257
+
258
+ let prefix = "";
259
+
260
+ for (
261
+ const segment
262
+ of segments
263
+ ) {
264
+ prefix +=
265
+ `/${segment}`;
266
+
267
+ keys.push(
268
+ prefix
269
+ );
270
+ }
271
+
272
+ return keys;
273
+ }