@chidchanun/bcp 0.1.9 → 0.1.11

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.
@@ -7,32 +7,76 @@ import {
7
7
 
8
8
  const LOADER_DATA_PARAM =
9
9
  "__bcp_loader_data";
10
+ const GUARD_DATA_PARAM =
11
+ "__bcp_guard_data";
12
+ const SERVER_DATA_MARKER =
13
+ "__bcp_server_data";
10
14
  const MISSING_LOADER_DATA =
11
15
  Symbol(
12
16
  "bcp-loader-data"
13
17
  );
18
+ const MISSING_GUARD_DATA =
19
+ Symbol(
20
+ "bcp-guard-data"
21
+ );
14
22
 
15
23
  const LoaderDataContext =
16
24
  createContext<unknown>(
17
25
  MISSING_LOADER_DATA
18
26
  );
27
+ const GuardDataContext =
28
+ createContext<unknown>(
29
+ MISSING_GUARD_DATA
30
+ );
19
31
 
20
32
  export interface BcpLoaderDataProviderProps {
21
33
  data: unknown;
22
34
  children?: ReactNode;
23
35
  }
24
36
 
37
+ interface ServerDataEnvelope {
38
+ __bcp_server_data: true;
39
+ hasPageLoader: boolean;
40
+ hasGuard: boolean;
41
+ loaderData: unknown;
42
+ guardData: unknown;
43
+ }
44
+
25
45
  export function BcpLoaderDataProvider({
26
46
  data,
27
47
  children,
28
48
  }: BcpLoaderDataProviderProps) {
49
+ const envelope =
50
+ isServerDataEnvelope(
51
+ data
52
+ )
53
+ ? data
54
+ : null;
55
+ const loaderValue =
56
+ envelope
57
+ ? envelope.hasPageLoader
58
+ ? envelope.loaderData
59
+ : MISSING_LOADER_DATA
60
+ : data;
61
+ const guardValue =
62
+ envelope?.hasGuard
63
+ ? envelope.guardData
64
+ : MISSING_GUARD_DATA;
65
+
29
66
  return createElement(
30
- LoaderDataContext.Provider,
67
+ GuardDataContext.Provider,
31
68
  {
32
69
  value:
33
- data,
70
+ guardValue,
34
71
  },
35
- children
72
+ createElement(
73
+ LoaderDataContext.Provider,
74
+ {
75
+ value:
76
+ loaderValue,
77
+ },
78
+ children
79
+ )
36
80
  );
37
81
  }
38
82
 
@@ -51,49 +95,135 @@ export function useLoaderData<
51
95
  return contextValue as T;
52
96
  }
53
97
 
98
+ const browserValue =
99
+ readFrameworkParam(
100
+ LOADER_DATA_PARAM
101
+ );
102
+
103
+ if (browserValue.found) {
104
+ return browserValue.value as T;
105
+ }
106
+
107
+ throw new Error(
108
+ "BCP Framework: useLoaderData() was used on a route without loader data. Add loader.ts next to page.tsx."
109
+ );
110
+ }
111
+
112
+ export function useGuardData<
113
+ T = unknown
114
+ >(): T {
115
+ const contextValue =
116
+ useContext(
117
+ GuardDataContext
118
+ );
119
+
54
120
  if (
55
- typeof document !==
121
+ contextValue !==
122
+ MISSING_GUARD_DATA
123
+ ) {
124
+ return contextValue as T;
125
+ }
126
+
127
+ const browserValue =
128
+ readFrameworkParam(
129
+ GUARD_DATA_PARAM
130
+ );
131
+
132
+ if (browserValue.found) {
133
+ return browserValue.value as T;
134
+ }
135
+
136
+ throw new Error(
137
+ "BCP Framework: useGuardData() was used on a route without guard data. Add guard.ts to the route or an ancestor route directory."
138
+ );
139
+ }
140
+
141
+ function readFrameworkParam(
142
+ key: string
143
+ ): {
144
+ found: boolean;
145
+ value: unknown;
146
+ } {
147
+ if (
148
+ typeof document ===
56
149
  "undefined"
57
150
  ) {
58
- const element =
59
- document.getElementById(
60
- "__BCP_DATA__"
61
- );
62
-
63
- if (element) {
64
- try {
65
- const frameworkData =
66
- JSON.parse(
67
- element.textContent ||
68
- "{}"
69
- ) as {
70
- params?: Record<
71
- string,
72
- unknown
73
- >;
74
- };
75
- const params =
76
- frameworkData.params;
77
-
78
- if (
79
- params &&
80
- Object.prototype
81
- .hasOwnProperty.call(
82
- params,
83
- LOADER_DATA_PARAM
84
- )
85
- ) {
86
- return params[
87
- LOADER_DATA_PARAM
88
- ] as T;
89
- }
90
- } catch {
91
- // Fall through to the framework error below.
92
- }
151
+ return {
152
+ found:
153
+ false,
154
+ value:
155
+ undefined,
156
+ };
157
+ }
158
+
159
+ const element =
160
+ document.getElementById(
161
+ "__BCP_DATA__"
162
+ );
163
+
164
+ if (!element) {
165
+ return {
166
+ found:
167
+ false,
168
+ value:
169
+ undefined,
170
+ };
171
+ }
172
+
173
+ try {
174
+ const frameworkData =
175
+ JSON.parse(
176
+ element.textContent ||
177
+ "{}"
178
+ ) as {
179
+ params?: Record<
180
+ string,
181
+ unknown
182
+ >;
183
+ };
184
+ const params =
185
+ frameworkData.params;
186
+
187
+ if (
188
+ params &&
189
+ Object.prototype
190
+ .hasOwnProperty.call(
191
+ params,
192
+ key
193
+ )
194
+ ) {
195
+ return {
196
+ found:
197
+ true,
198
+ value:
199
+ params[
200
+ key
201
+ ],
202
+ };
93
203
  }
204
+ } catch {
205
+ // Fall through to the missing-data result.
94
206
  }
95
207
 
96
- throw new Error(
97
- "BCP Framework: useLoaderData() was used on a route without loader data. Add loader.ts next to page.tsx."
208
+ return {
209
+ found:
210
+ false,
211
+ value:
212
+ undefined,
213
+ };
214
+ }
215
+
216
+ function isServerDataEnvelope(
217
+ value: unknown
218
+ ): value is ServerDataEnvelope {
219
+ return (
220
+ value !== null &&
221
+ typeof value ===
222
+ "object" &&
223
+ (
224
+ value as
225
+ Record<string, unknown>
226
+ )[SERVER_DATA_MARKER] ===
227
+ true
98
228
  );
99
229
  }
@@ -34,3 +34,9 @@ export {
34
34
  type SessionPayload,
35
35
  type SessionTokenOptions,
36
36
  } from "../../server/src/session.js";
37
+
38
+ export type {
39
+ PageAction,
40
+ PageActionContext,
41
+ PageActionMethod,
42
+ } from "../../server/src/form-action.js";