hadars 0.3.1 → 0.4.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/README.md +50 -17
- package/dist/{chunk-2KJRDPCN.js → chunk-2J2L2H3H.js} +9 -9
- package/dist/{chunk-LY5MTHFV.js → chunk-TV37IMRB.js} +50 -51
- package/dist/cli.js +74 -67
- package/dist/cloudflare.cjs +58 -57
- package/dist/cloudflare.d.cts +1 -1
- package/dist/cloudflare.d.ts +1 -1
- package/dist/cloudflare.js +4 -2
- package/dist/{hadars-CSWWhlQC.d.cts → hadars-CPplIz_z.d.cts} +17 -0
- package/dist/{hadars-CSWWhlQC.d.ts → hadars-CPplIz_z.d.ts} +17 -0
- package/dist/index.cjs +32 -59
- package/dist/index.d.cts +12 -8
- package/dist/index.d.ts +12 -8
- package/dist/index.js +32 -59
- package/dist/lambda.cjs +60 -65
- package/dist/lambda.d.cts +1 -1
- package/dist/lambda.d.ts +1 -1
- package/dist/lambda.js +6 -10
- package/dist/loader.cjs +2 -7
- package/dist/slim-react/index.cjs +50 -51
- package/dist/slim-react/index.js +1 -1
- package/dist/ssr-render-worker.js +46 -47
- package/dist/ssr-watch.js +9 -6
- package/dist/utils/Head.tsx +68 -116
- package/package.json +2 -2
- package/src/build.ts +11 -5
- package/src/cloudflare.ts +1 -0
- package/src/lambda.ts +8 -14
- package/src/slim-react/render.ts +39 -25
- package/src/slim-react/renderContext.ts +34 -11
- package/src/types/hadars.ts +17 -0
- package/src/utils/Head.tsx +68 -116
- package/src/utils/loader.ts +5 -13
- package/src/utils/rspack.ts +9 -6
- package/src/utils/ssrHandler.ts +13 -8
package/dist/index.cjs
CHANGED
|
@@ -182,42 +182,46 @@ function getCtx() {
|
|
|
182
182
|
var clientServerDataCache = /* @__PURE__ */ new Map();
|
|
183
183
|
var pendingDataFetch = /* @__PURE__ */ new Map();
|
|
184
184
|
var fetchedPaths = /* @__PURE__ */ new Set();
|
|
185
|
-
var
|
|
186
|
-
var
|
|
187
|
-
function scheduleUnclaimedKeyCheck() {
|
|
188
|
-
if (unclaimedKeyCheckScheduled) return;
|
|
189
|
-
unclaimedKeyCheckScheduled = true;
|
|
190
|
-
setTimeout(() => {
|
|
191
|
-
unclaimedKeyCheckScheduled = false;
|
|
192
|
-
if (ssrInitialKeys && ssrInitialKeys.size > 0) {
|
|
193
|
-
console.warn(
|
|
194
|
-
`[hadars] useServerData: ${ssrInitialKeys.size} server-resolved key(s) were never claimed during client hydration: ${[...ssrInitialKeys].map((k) => JSON.stringify(k)).join(", ")}. This usually means the key passed to useServerData was different on the server than on the client (e.g. it contains Date.now(), Math.random(), or another value that changes between renders). Keys must be stable and deterministic.`
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
ssrInitialKeys = null;
|
|
198
|
-
}, 0);
|
|
199
|
-
}
|
|
185
|
+
var _navValues = [];
|
|
186
|
+
var _navIdx = 0;
|
|
200
187
|
function initServerDataCache(data) {
|
|
201
188
|
clientServerDataCache.clear();
|
|
202
|
-
|
|
189
|
+
_navValues = [];
|
|
190
|
+
_navIdx = 0;
|
|
203
191
|
for (const [k, v] of Object.entries(data)) {
|
|
204
192
|
clientServerDataCache.set(k, v);
|
|
205
|
-
ssrInitialKeys.add(k);
|
|
206
193
|
}
|
|
207
194
|
}
|
|
208
|
-
function useServerData(
|
|
209
|
-
const cacheKey =
|
|
195
|
+
function useServerData(fn, options) {
|
|
196
|
+
const cacheKey = import_react.default.useId();
|
|
197
|
+
const evictTimerRef = import_react.default.useRef(null);
|
|
198
|
+
import_react.default.useEffect(() => {
|
|
199
|
+
if (options?.cache !== false) return;
|
|
200
|
+
if (evictTimerRef.current !== null) {
|
|
201
|
+
clearTimeout(evictTimerRef.current);
|
|
202
|
+
evictTimerRef.current = null;
|
|
203
|
+
}
|
|
204
|
+
return () => {
|
|
205
|
+
evictTimerRef.current = setTimeout(() => {
|
|
206
|
+
clientServerDataCache.delete(cacheKey);
|
|
207
|
+
evictTimerRef.current = null;
|
|
208
|
+
}, 0);
|
|
209
|
+
};
|
|
210
|
+
}, []);
|
|
210
211
|
if (typeof window !== "undefined") {
|
|
211
212
|
if (clientServerDataCache.has(cacheKey)) {
|
|
212
|
-
ssrInitialKeys?.delete(cacheKey);
|
|
213
213
|
return clientServerDataCache.get(cacheKey);
|
|
214
214
|
}
|
|
215
|
-
if (ssrInitialKeys !== null && ssrInitialKeys.size > 0) {
|
|
216
|
-
scheduleUnclaimedKeyCheck();
|
|
217
|
-
}
|
|
218
215
|
const pathKey = window.location.pathname + window.location.search;
|
|
219
216
|
if (fetchedPaths.has(pathKey)) {
|
|
220
|
-
|
|
217
|
+
if (_navIdx < _navValues.length) {
|
|
218
|
+
const value = _navValues[_navIdx++];
|
|
219
|
+
clientServerDataCache.set(cacheKey, value);
|
|
220
|
+
return value;
|
|
221
|
+
}
|
|
222
|
+
fetchedPaths.delete(pathKey);
|
|
223
|
+
_navValues = [];
|
|
224
|
+
_navIdx = 0;
|
|
221
225
|
}
|
|
222
226
|
if (!pendingDataFetch.has(pathKey)) {
|
|
223
227
|
let resolve;
|
|
@@ -236,9 +240,9 @@ function useServerData(key, fn) {
|
|
|
236
240
|
const res = await fetch(pathKey, { headers: { "Accept": "application/json" } });
|
|
237
241
|
if (res.ok) json = await res.json();
|
|
238
242
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
243
|
+
_navValues = Object.values(json?.serverData ?? {});
|
|
244
|
+
_navIdx = 0;
|
|
245
|
+
fetchedPaths.clear();
|
|
242
246
|
} finally {
|
|
243
247
|
fetchedPaths.add(pathKey);
|
|
244
248
|
pendingDataFetch.delete(pathKey);
|
|
@@ -250,12 +254,7 @@ function useServerData(key, fn) {
|
|
|
250
254
|
}
|
|
251
255
|
const unsuspend = globalThis.__hadarsUnsuspend;
|
|
252
256
|
if (!unsuspend) return void 0;
|
|
253
|
-
const _u = unsuspend;
|
|
254
|
-
if (!_u.pendingCreated) _u.pendingCreated = 0;
|
|
255
257
|
const existing = unsuspend.cache.get(cacheKey);
|
|
256
|
-
if (existing?.status === "fulfilled" && _u.lastPendingKey === cacheKey) {
|
|
257
|
-
_u.lastPendingKeyAccessed = true;
|
|
258
|
-
}
|
|
259
258
|
if (!existing) {
|
|
260
259
|
const result = fn();
|
|
261
260
|
const isThenable = result !== null && typeof result === "object" && typeof result.then === "function";
|
|
@@ -264,22 +263,6 @@ function useServerData(key, fn) {
|
|
|
264
263
|
unsuspend.cache.set(cacheKey, { status: "fulfilled", value });
|
|
265
264
|
return value;
|
|
266
265
|
}
|
|
267
|
-
if (_u.lastPendingKey != null && !_u.lastPendingKeyAccessed) {
|
|
268
|
-
const prev = unsuspend.cache.get(_u.lastPendingKey);
|
|
269
|
-
if (prev?.status === "fulfilled") {
|
|
270
|
-
throw new Error(
|
|
271
|
-
`[hadars] useServerData: key ${JSON.stringify(cacheKey)} is not stable between render passes. The previous pass resolved ${JSON.stringify(_u.lastPendingKey)} but it was not requested in this pass \u2014 the key is changing between renders. Avoid dynamic values in keys (e.g. Date.now() or Math.random()); use stable, deterministic identifiers instead.`
|
|
272
|
-
);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
_u.pendingCreated++;
|
|
276
|
-
if (_u.pendingCreated > 100) {
|
|
277
|
-
throw new Error(
|
|
278
|
-
`[hadars] useServerData: more than 100 async keys created in a single render. This usually means a key is not stable between renders (e.g. it contains Date.now() or Math.random()). Currently offending key: ${JSON.stringify(cacheKey)}.`
|
|
279
|
-
);
|
|
280
|
-
}
|
|
281
|
-
_u.lastPendingKey = cacheKey;
|
|
282
|
-
_u.lastPendingKeyAccessed = false;
|
|
283
266
|
const promise = result.then(
|
|
284
267
|
(value) => {
|
|
285
268
|
unsuspend.cache.set(cacheKey, { status: "fulfilled", value });
|
|
@@ -297,18 +280,8 @@ function useServerData(key, fn) {
|
|
|
297
280
|
if (existing.status === "rejected") throw existing.reason;
|
|
298
281
|
return existing.value;
|
|
299
282
|
}
|
|
300
|
-
function toCacheKey(doc) {
|
|
301
|
-
if (typeof doc === "string") return doc.trim();
|
|
302
|
-
for (const def of doc?.definitions ?? []) {
|
|
303
|
-
if (def.kind === "OperationDefinition" && def.name?.value) {
|
|
304
|
-
return `op:${def.name.value}`;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
return JSON.stringify(doc?.definitions ?? doc);
|
|
308
|
-
}
|
|
309
283
|
function useGraphQL(query, variables) {
|
|
310
|
-
|
|
311
|
-
return useServerData(key, async () => {
|
|
284
|
+
return useServerData(async () => {
|
|
312
285
|
const executor = globalThis.__hadarsGraphQL;
|
|
313
286
|
if (!executor) {
|
|
314
287
|
throw new Error(
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { b as HadarsDocumentNode } from './hadars-
|
|
2
|
-
export { G as GraphQLExecutor, c as HadarsApp, H as HadarsEntryModule, d as HadarsGetClientProps, e as HadarsGetFinalProps, f as HadarsGetInitialProps, a as HadarsOptions, g as HadarsProps, h as HadarsRequest, i as HadarsSourceEntry, j as HadarsStaticContext } from './hadars-
|
|
1
|
+
import { b as HadarsDocumentNode } from './hadars-CPplIz_z.cjs';
|
|
2
|
+
export { G as GraphQLExecutor, c as HadarsApp, H as HadarsEntryModule, d as HadarsGetClientProps, e as HadarsGetFinalProps, f as HadarsGetInitialProps, a as HadarsOptions, g as HadarsProps, h as HadarsRequest, i as HadarsSourceEntry, j as HadarsStaticContext } from './hadars-CPplIz_z.cjs';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
|
|
5
5
|
/** Call this before hydrating to seed the client cache from the server's data.
|
|
@@ -14,9 +14,8 @@ declare function initServerDataCache(data: Record<string, unknown>): void;
|
|
|
14
14
|
* On the client the pre-resolved value is read from the hydration cache
|
|
15
15
|
* serialised into the page by the server, so no fetch is issued in the browser.
|
|
16
16
|
*
|
|
17
|
-
* The
|
|
18
|
-
*
|
|
19
|
-
* unique within the page.
|
|
17
|
+
* The cache key is derived automatically from the call-site's position in the
|
|
18
|
+
* component tree via `useId()` — no manual key is required.
|
|
20
19
|
*
|
|
21
20
|
* `fn` may return a `Promise<T>` (async usage) or return `T` synchronously.
|
|
22
21
|
* The resolved value is serialised into `__serverData` and returned from cache
|
|
@@ -28,11 +27,16 @@ declare function initServerDataCache(data: Record<string, unknown>): void;
|
|
|
28
27
|
* React Suspense until the server returns the JSON map of resolved values.
|
|
29
28
|
*
|
|
30
29
|
* @example
|
|
31
|
-
* const user = useServerData(
|
|
32
|
-
* const post = useServerData(
|
|
30
|
+
* const user = useServerData(() => db.getUser(id));
|
|
31
|
+
* const post = useServerData(() => db.getPost(postId));
|
|
33
32
|
* if (!user) return null; // undefined while pending on the first SSR pass
|
|
33
|
+
*
|
|
34
|
+
* // cache: false — evicts the entry on unmount so the next mount fetches fresh data
|
|
35
|
+
* const stats = useServerData(() => getServerStats(), { cache: false });
|
|
34
36
|
*/
|
|
35
|
-
declare function useServerData<T>(
|
|
37
|
+
declare function useServerData<T>(fn: () => Promise<T> | T, options?: {
|
|
38
|
+
cache?: boolean;
|
|
39
|
+
}): T | undefined;
|
|
36
40
|
/**
|
|
37
41
|
* Execute a GraphQL query server-side and return the result.
|
|
38
42
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { b as HadarsDocumentNode } from './hadars-
|
|
2
|
-
export { G as GraphQLExecutor, c as HadarsApp, H as HadarsEntryModule, d as HadarsGetClientProps, e as HadarsGetFinalProps, f as HadarsGetInitialProps, a as HadarsOptions, g as HadarsProps, h as HadarsRequest, i as HadarsSourceEntry, j as HadarsStaticContext } from './hadars-
|
|
1
|
+
import { b as HadarsDocumentNode } from './hadars-CPplIz_z.js';
|
|
2
|
+
export { G as GraphQLExecutor, c as HadarsApp, H as HadarsEntryModule, d as HadarsGetClientProps, e as HadarsGetFinalProps, f as HadarsGetInitialProps, a as HadarsOptions, g as HadarsProps, h as HadarsRequest, i as HadarsSourceEntry, j as HadarsStaticContext } from './hadars-CPplIz_z.js';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
|
|
5
5
|
/** Call this before hydrating to seed the client cache from the server's data.
|
|
@@ -14,9 +14,8 @@ declare function initServerDataCache(data: Record<string, unknown>): void;
|
|
|
14
14
|
* On the client the pre-resolved value is read from the hydration cache
|
|
15
15
|
* serialised into the page by the server, so no fetch is issued in the browser.
|
|
16
16
|
*
|
|
17
|
-
* The
|
|
18
|
-
*
|
|
19
|
-
* unique within the page.
|
|
17
|
+
* The cache key is derived automatically from the call-site's position in the
|
|
18
|
+
* component tree via `useId()` — no manual key is required.
|
|
20
19
|
*
|
|
21
20
|
* `fn` may return a `Promise<T>` (async usage) or return `T` synchronously.
|
|
22
21
|
* The resolved value is serialised into `__serverData` and returned from cache
|
|
@@ -28,11 +27,16 @@ declare function initServerDataCache(data: Record<string, unknown>): void;
|
|
|
28
27
|
* React Suspense until the server returns the JSON map of resolved values.
|
|
29
28
|
*
|
|
30
29
|
* @example
|
|
31
|
-
* const user = useServerData(
|
|
32
|
-
* const post = useServerData(
|
|
30
|
+
* const user = useServerData(() => db.getUser(id));
|
|
31
|
+
* const post = useServerData(() => db.getPost(postId));
|
|
33
32
|
* if (!user) return null; // undefined while pending on the first SSR pass
|
|
33
|
+
*
|
|
34
|
+
* // cache: false — evicts the entry on unmount so the next mount fetches fresh data
|
|
35
|
+
* const stats = useServerData(() => getServerStats(), { cache: false });
|
|
34
36
|
*/
|
|
35
|
-
declare function useServerData<T>(
|
|
37
|
+
declare function useServerData<T>(fn: () => Promise<T> | T, options?: {
|
|
38
|
+
cache?: boolean;
|
|
39
|
+
}): T | undefined;
|
|
36
40
|
/**
|
|
37
41
|
* Execute a GraphQL query server-side and return the result.
|
|
38
42
|
*
|
package/dist/index.js
CHANGED
|
@@ -142,42 +142,46 @@ function getCtx() {
|
|
|
142
142
|
var clientServerDataCache = /* @__PURE__ */ new Map();
|
|
143
143
|
var pendingDataFetch = /* @__PURE__ */ new Map();
|
|
144
144
|
var fetchedPaths = /* @__PURE__ */ new Set();
|
|
145
|
-
var
|
|
146
|
-
var
|
|
147
|
-
function scheduleUnclaimedKeyCheck() {
|
|
148
|
-
if (unclaimedKeyCheckScheduled) return;
|
|
149
|
-
unclaimedKeyCheckScheduled = true;
|
|
150
|
-
setTimeout(() => {
|
|
151
|
-
unclaimedKeyCheckScheduled = false;
|
|
152
|
-
if (ssrInitialKeys && ssrInitialKeys.size > 0) {
|
|
153
|
-
console.warn(
|
|
154
|
-
`[hadars] useServerData: ${ssrInitialKeys.size} server-resolved key(s) were never claimed during client hydration: ${[...ssrInitialKeys].map((k) => JSON.stringify(k)).join(", ")}. This usually means the key passed to useServerData was different on the server than on the client (e.g. it contains Date.now(), Math.random(), or another value that changes between renders). Keys must be stable and deterministic.`
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
ssrInitialKeys = null;
|
|
158
|
-
}, 0);
|
|
159
|
-
}
|
|
145
|
+
var _navValues = [];
|
|
146
|
+
var _navIdx = 0;
|
|
160
147
|
function initServerDataCache(data) {
|
|
161
148
|
clientServerDataCache.clear();
|
|
162
|
-
|
|
149
|
+
_navValues = [];
|
|
150
|
+
_navIdx = 0;
|
|
163
151
|
for (const [k, v] of Object.entries(data)) {
|
|
164
152
|
clientServerDataCache.set(k, v);
|
|
165
|
-
ssrInitialKeys.add(k);
|
|
166
153
|
}
|
|
167
154
|
}
|
|
168
|
-
function useServerData(
|
|
169
|
-
const cacheKey =
|
|
155
|
+
function useServerData(fn, options) {
|
|
156
|
+
const cacheKey = React.useId();
|
|
157
|
+
const evictTimerRef = React.useRef(null);
|
|
158
|
+
React.useEffect(() => {
|
|
159
|
+
if (options?.cache !== false) return;
|
|
160
|
+
if (evictTimerRef.current !== null) {
|
|
161
|
+
clearTimeout(evictTimerRef.current);
|
|
162
|
+
evictTimerRef.current = null;
|
|
163
|
+
}
|
|
164
|
+
return () => {
|
|
165
|
+
evictTimerRef.current = setTimeout(() => {
|
|
166
|
+
clientServerDataCache.delete(cacheKey);
|
|
167
|
+
evictTimerRef.current = null;
|
|
168
|
+
}, 0);
|
|
169
|
+
};
|
|
170
|
+
}, []);
|
|
170
171
|
if (typeof window !== "undefined") {
|
|
171
172
|
if (clientServerDataCache.has(cacheKey)) {
|
|
172
|
-
ssrInitialKeys?.delete(cacheKey);
|
|
173
173
|
return clientServerDataCache.get(cacheKey);
|
|
174
174
|
}
|
|
175
|
-
if (ssrInitialKeys !== null && ssrInitialKeys.size > 0) {
|
|
176
|
-
scheduleUnclaimedKeyCheck();
|
|
177
|
-
}
|
|
178
175
|
const pathKey = window.location.pathname + window.location.search;
|
|
179
176
|
if (fetchedPaths.has(pathKey)) {
|
|
180
|
-
|
|
177
|
+
if (_navIdx < _navValues.length) {
|
|
178
|
+
const value = _navValues[_navIdx++];
|
|
179
|
+
clientServerDataCache.set(cacheKey, value);
|
|
180
|
+
return value;
|
|
181
|
+
}
|
|
182
|
+
fetchedPaths.delete(pathKey);
|
|
183
|
+
_navValues = [];
|
|
184
|
+
_navIdx = 0;
|
|
181
185
|
}
|
|
182
186
|
if (!pendingDataFetch.has(pathKey)) {
|
|
183
187
|
let resolve;
|
|
@@ -196,9 +200,9 @@ function useServerData(key, fn) {
|
|
|
196
200
|
const res = await fetch(pathKey, { headers: { "Accept": "application/json" } });
|
|
197
201
|
if (res.ok) json = await res.json();
|
|
198
202
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
203
|
+
_navValues = Object.values(json?.serverData ?? {});
|
|
204
|
+
_navIdx = 0;
|
|
205
|
+
fetchedPaths.clear();
|
|
202
206
|
} finally {
|
|
203
207
|
fetchedPaths.add(pathKey);
|
|
204
208
|
pendingDataFetch.delete(pathKey);
|
|
@@ -210,12 +214,7 @@ function useServerData(key, fn) {
|
|
|
210
214
|
}
|
|
211
215
|
const unsuspend = globalThis.__hadarsUnsuspend;
|
|
212
216
|
if (!unsuspend) return void 0;
|
|
213
|
-
const _u = unsuspend;
|
|
214
|
-
if (!_u.pendingCreated) _u.pendingCreated = 0;
|
|
215
217
|
const existing = unsuspend.cache.get(cacheKey);
|
|
216
|
-
if (existing?.status === "fulfilled" && _u.lastPendingKey === cacheKey) {
|
|
217
|
-
_u.lastPendingKeyAccessed = true;
|
|
218
|
-
}
|
|
219
218
|
if (!existing) {
|
|
220
219
|
const result = fn();
|
|
221
220
|
const isThenable = result !== null && typeof result === "object" && typeof result.then === "function";
|
|
@@ -224,22 +223,6 @@ function useServerData(key, fn) {
|
|
|
224
223
|
unsuspend.cache.set(cacheKey, { status: "fulfilled", value });
|
|
225
224
|
return value;
|
|
226
225
|
}
|
|
227
|
-
if (_u.lastPendingKey != null && !_u.lastPendingKeyAccessed) {
|
|
228
|
-
const prev = unsuspend.cache.get(_u.lastPendingKey);
|
|
229
|
-
if (prev?.status === "fulfilled") {
|
|
230
|
-
throw new Error(
|
|
231
|
-
`[hadars] useServerData: key ${JSON.stringify(cacheKey)} is not stable between render passes. The previous pass resolved ${JSON.stringify(_u.lastPendingKey)} but it was not requested in this pass \u2014 the key is changing between renders. Avoid dynamic values in keys (e.g. Date.now() or Math.random()); use stable, deterministic identifiers instead.`
|
|
232
|
-
);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
_u.pendingCreated++;
|
|
236
|
-
if (_u.pendingCreated > 100) {
|
|
237
|
-
throw new Error(
|
|
238
|
-
`[hadars] useServerData: more than 100 async keys created in a single render. This usually means a key is not stable between renders (e.g. it contains Date.now() or Math.random()). Currently offending key: ${JSON.stringify(cacheKey)}.`
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
_u.lastPendingKey = cacheKey;
|
|
242
|
-
_u.lastPendingKeyAccessed = false;
|
|
243
226
|
const promise = result.then(
|
|
244
227
|
(value) => {
|
|
245
228
|
unsuspend.cache.set(cacheKey, { status: "fulfilled", value });
|
|
@@ -257,18 +240,8 @@ function useServerData(key, fn) {
|
|
|
257
240
|
if (existing.status === "rejected") throw existing.reason;
|
|
258
241
|
return existing.value;
|
|
259
242
|
}
|
|
260
|
-
function toCacheKey(doc) {
|
|
261
|
-
if (typeof doc === "string") return doc.trim();
|
|
262
|
-
for (const def of doc?.definitions ?? []) {
|
|
263
|
-
if (def.kind === "OperationDefinition" && def.name?.value) {
|
|
264
|
-
return `op:${def.name.value}`;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
return JSON.stringify(doc?.definitions ?? doc);
|
|
268
|
-
}
|
|
269
243
|
function useGraphQL(query, variables) {
|
|
270
|
-
|
|
271
|
-
return useServerData(key, async () => {
|
|
244
|
+
return useServerData(async () => {
|
|
272
245
|
const executor = globalThis.__hadarsGraphQL;
|
|
273
246
|
if (!executor) {
|
|
274
247
|
throw new Error(
|
package/dist/lambda.cjs
CHANGED
|
@@ -323,7 +323,16 @@ function componentCalledUseId() {
|
|
|
323
323
|
function snapshotContext() {
|
|
324
324
|
const st = s();
|
|
325
325
|
const ctx = st.currentTreeContext;
|
|
326
|
-
|
|
326
|
+
const depth = _treeDepth;
|
|
327
|
+
return {
|
|
328
|
+
tree: { id: ctx.id, overflow: ctx.overflow },
|
|
329
|
+
localId: st.localIdCounter,
|
|
330
|
+
treeDepth: depth,
|
|
331
|
+
// Snapshot the live stack so that popTreeContext reads correct saved values
|
|
332
|
+
// even if another concurrent render's resetRenderState stomped the arrays.
|
|
333
|
+
idStack: _treeIdStack.slice(0, depth),
|
|
334
|
+
ovStack: _treeOvStack.slice(0, depth)
|
|
335
|
+
};
|
|
327
336
|
}
|
|
328
337
|
function restoreContext(snap) {
|
|
329
338
|
const st = s();
|
|
@@ -332,6 +341,10 @@ function restoreContext(snap) {
|
|
|
332
341
|
ctx.overflow = snap.tree.overflow;
|
|
333
342
|
st.localIdCounter = snap.localId;
|
|
334
343
|
_treeDepth = snap.treeDepth;
|
|
344
|
+
for (let i = 0; i < snap.treeDepth; i++) {
|
|
345
|
+
_treeIdStack[i] = snap.idStack[i];
|
|
346
|
+
_treeOvStack[i] = snap.ovStack[i];
|
|
347
|
+
}
|
|
335
348
|
}
|
|
336
349
|
function getTreeId() {
|
|
337
350
|
const { id, overflow } = s().currentTreeContext;
|
|
@@ -445,6 +458,14 @@ function restoreDispatcher(prev) {
|
|
|
445
458
|
}
|
|
446
459
|
|
|
447
460
|
// src/slim-react/render.ts
|
|
461
|
+
function captureRenderCtx() {
|
|
462
|
+
return { m: captureMap(), u: captureUnsuspend(), t: snapshotContext() };
|
|
463
|
+
}
|
|
464
|
+
function restoreRenderCtx(ctx) {
|
|
465
|
+
swapContextMap(ctx.m);
|
|
466
|
+
restoreUnsuspend(ctx.u);
|
|
467
|
+
restoreContext(ctx.t);
|
|
468
|
+
}
|
|
448
469
|
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
449
470
|
"area",
|
|
450
471
|
"base",
|
|
@@ -888,11 +909,9 @@ function renderComponent(type, props, writer, isSvg, _suspenseRetries = 0) {
|
|
|
888
909
|
if (e && typeof e.then === "function") {
|
|
889
910
|
if (_suspenseRetries + 1 >= MAX_COMPONENT_SUSPENSE_RETRIES) throw SUSPENSE_RETRY_LIMIT;
|
|
890
911
|
patchPromiseStatus(e);
|
|
891
|
-
const
|
|
892
|
-
const u = captureUnsuspend();
|
|
912
|
+
const rctx = captureRenderCtx();
|
|
893
913
|
return e.then(() => {
|
|
894
|
-
|
|
895
|
-
restoreUnsuspend(u);
|
|
914
|
+
restoreRenderCtx(rctx);
|
|
896
915
|
return renderComponent(type, props, writer, isSvg, _suspenseRetries + 1);
|
|
897
916
|
});
|
|
898
917
|
}
|
|
@@ -929,17 +948,14 @@ function renderComponent(type, props, writer, isSvg, _suspenseRetries = 0) {
|
|
|
929
948
|
};
|
|
930
949
|
const r2 = renderChildren(props.children, writer, isSvg);
|
|
931
950
|
if (r2 && typeof r2.then === "function") {
|
|
932
|
-
const
|
|
933
|
-
const u = captureUnsuspend();
|
|
951
|
+
const rctx = captureRenderCtx();
|
|
934
952
|
return r2.then(
|
|
935
953
|
() => {
|
|
936
|
-
|
|
937
|
-
restoreUnsuspend(u);
|
|
954
|
+
restoreRenderCtx(rctx);
|
|
938
955
|
finish();
|
|
939
956
|
},
|
|
940
957
|
(e) => {
|
|
941
|
-
|
|
942
|
-
restoreUnsuspend(u);
|
|
958
|
+
restoreRenderCtx(rctx);
|
|
943
959
|
finish();
|
|
944
960
|
throw e;
|
|
945
961
|
}
|
|
@@ -968,11 +984,9 @@ function renderComponent(type, props, writer, isSvg, _suspenseRetries = 0) {
|
|
|
968
984
|
if (e && typeof e.then === "function") {
|
|
969
985
|
if (_suspenseRetries + 1 >= MAX_COMPONENT_SUSPENSE_RETRIES) throw SUSPENSE_RETRY_LIMIT;
|
|
970
986
|
patchPromiseStatus(e);
|
|
971
|
-
const
|
|
972
|
-
const u = captureUnsuspend();
|
|
987
|
+
const rctx = captureRenderCtx();
|
|
973
988
|
return e.then(() => {
|
|
974
|
-
|
|
975
|
-
restoreUnsuspend(u);
|
|
989
|
+
restoreRenderCtx(rctx);
|
|
976
990
|
return renderComponent(type, props, writer, isSvg, _suspenseRetries + 1);
|
|
977
991
|
});
|
|
978
992
|
}
|
|
@@ -984,30 +998,25 @@ function renderComponent(type, props, writer, isSvg, _suspenseRetries = 0) {
|
|
|
984
998
|
savedIdTree = pushTreeContext(1, 0);
|
|
985
999
|
}
|
|
986
1000
|
if (result instanceof Promise) {
|
|
987
|
-
const
|
|
988
|
-
const u = captureUnsuspend();
|
|
1001
|
+
const rctx = captureRenderCtx();
|
|
989
1002
|
return result.then((resolved) => {
|
|
990
|
-
|
|
991
|
-
restoreUnsuspend(u);
|
|
1003
|
+
restoreRenderCtx(rctx);
|
|
992
1004
|
let asyncSavedIdTree;
|
|
993
1005
|
if (componentCalledUseId()) {
|
|
994
1006
|
asyncSavedIdTree = pushTreeContext(1, 0);
|
|
995
1007
|
}
|
|
996
1008
|
const r2 = renderNode(resolved, writer, isSvg);
|
|
997
1009
|
if (r2 && typeof r2.then === "function") {
|
|
998
|
-
const
|
|
999
|
-
const u2 = captureUnsuspend();
|
|
1010
|
+
const rctx2 = captureRenderCtx();
|
|
1000
1011
|
return r2.then(
|
|
1001
1012
|
() => {
|
|
1002
|
-
|
|
1003
|
-
restoreUnsuspend(u2);
|
|
1013
|
+
restoreRenderCtx(rctx2);
|
|
1004
1014
|
if (asyncSavedIdTree !== void 0) popTreeContext(asyncSavedIdTree);
|
|
1005
1015
|
popComponentScope(savedScope);
|
|
1006
1016
|
if (isProvider) popContextValue(ctx, prevCtxValue);
|
|
1007
1017
|
},
|
|
1008
1018
|
(e) => {
|
|
1009
|
-
|
|
1010
|
-
restoreUnsuspend(u2);
|
|
1019
|
+
restoreRenderCtx(rctx2);
|
|
1011
1020
|
if (asyncSavedIdTree !== void 0) popTreeContext(asyncSavedIdTree);
|
|
1012
1021
|
popComponentScope(savedScope);
|
|
1013
1022
|
if (isProvider) popContextValue(ctx, prevCtxValue);
|
|
@@ -1019,8 +1028,7 @@ function renderComponent(type, props, writer, isSvg, _suspenseRetries = 0) {
|
|
|
1019
1028
|
popComponentScope(savedScope);
|
|
1020
1029
|
if (isProvider) popContextValue(ctx, prevCtxValue);
|
|
1021
1030
|
}, (e) => {
|
|
1022
|
-
|
|
1023
|
-
restoreUnsuspend(u);
|
|
1031
|
+
restoreRenderCtx(rctx);
|
|
1024
1032
|
popComponentScope(savedScope);
|
|
1025
1033
|
if (isProvider) popContextValue(ctx, prevCtxValue);
|
|
1026
1034
|
throw e;
|
|
@@ -1028,19 +1036,16 @@ function renderComponent(type, props, writer, isSvg, _suspenseRetries = 0) {
|
|
|
1028
1036
|
}
|
|
1029
1037
|
const r = renderNode(result, writer, isSvg);
|
|
1030
1038
|
if (r && typeof r.then === "function") {
|
|
1031
|
-
const
|
|
1032
|
-
const u = captureUnsuspend();
|
|
1039
|
+
const rctx = captureRenderCtx();
|
|
1033
1040
|
return r.then(
|
|
1034
1041
|
() => {
|
|
1035
|
-
|
|
1036
|
-
restoreUnsuspend(u);
|
|
1042
|
+
restoreRenderCtx(rctx);
|
|
1037
1043
|
if (savedIdTree !== void 0) popTreeContext(savedIdTree);
|
|
1038
1044
|
popComponentScope(savedScope);
|
|
1039
1045
|
if (isProvider) popContextValue(ctx, prevCtxValue);
|
|
1040
1046
|
},
|
|
1041
1047
|
(e) => {
|
|
1042
|
-
|
|
1043
|
-
restoreUnsuspend(u);
|
|
1048
|
+
restoreRenderCtx(rctx);
|
|
1044
1049
|
if (savedIdTree !== void 0) popTreeContext(savedIdTree);
|
|
1045
1050
|
popComponentScope(savedScope);
|
|
1046
1051
|
if (isProvider) popContextValue(ctx, prevCtxValue);
|
|
@@ -1065,11 +1070,9 @@ function renderChildArrayFrom(children, startIndex, writer, isSvg) {
|
|
|
1065
1070
|
const savedTree = pushTreeContext(totalChildren, i);
|
|
1066
1071
|
const r = renderNode(child, writer, isSvg);
|
|
1067
1072
|
if (r && typeof r.then === "function") {
|
|
1068
|
-
const
|
|
1069
|
-
const u = captureUnsuspend();
|
|
1073
|
+
const rctx = captureRenderCtx();
|
|
1070
1074
|
return r.then(() => {
|
|
1071
|
-
|
|
1072
|
-
restoreUnsuspend(u);
|
|
1075
|
+
restoreRenderCtx(rctx);
|
|
1073
1076
|
popTreeContext(savedTree);
|
|
1074
1077
|
return renderChildArrayFrom(children, i + 1, writer, isSvg);
|
|
1075
1078
|
});
|
|
@@ -1093,11 +1096,9 @@ async function renderSuspense(props, writer, isSvg = false) {
|
|
|
1093
1096
|
try {
|
|
1094
1097
|
const r = renderNode(children, buffer, isSvg);
|
|
1095
1098
|
if (r && typeof r.then === "function") {
|
|
1096
|
-
const
|
|
1097
|
-
const u = captureUnsuspend();
|
|
1099
|
+
const rctx = captureRenderCtx();
|
|
1098
1100
|
await r;
|
|
1099
|
-
|
|
1100
|
-
restoreUnsuspend(u);
|
|
1101
|
+
restoreRenderCtx(rctx);
|
|
1101
1102
|
}
|
|
1102
1103
|
writer.write("<!--$-->");
|
|
1103
1104
|
buffer.flushTo(writer);
|
|
@@ -1111,11 +1112,9 @@ async function renderSuspense(props, writer, isSvg = false) {
|
|
|
1111
1112
|
if (fallback) {
|
|
1112
1113
|
const r = renderNode(fallback, writer, isSvg);
|
|
1113
1114
|
if (r && typeof r.then === "function") {
|
|
1114
|
-
const
|
|
1115
|
-
const u = captureUnsuspend();
|
|
1115
|
+
const rctx = captureRenderCtx();
|
|
1116
1116
|
await r;
|
|
1117
|
-
|
|
1118
|
-
restoreUnsuspend(u);
|
|
1117
|
+
restoreRenderCtx(rctx);
|
|
1119
1118
|
}
|
|
1120
1119
|
}
|
|
1121
1120
|
writer.write("<!--/$-->");
|
|
@@ -1140,9 +1139,9 @@ async function renderPreflight(element, options) {
|
|
|
1140
1139
|
NULL_WRITER.lastWasText = false;
|
|
1141
1140
|
const r = renderNode(element, NULL_WRITER);
|
|
1142
1141
|
if (r && typeof r.then === "function") {
|
|
1143
|
-
const
|
|
1142
|
+
const rctx = captureRenderCtx();
|
|
1144
1143
|
await r;
|
|
1145
|
-
|
|
1144
|
+
restoreRenderCtx(rctx);
|
|
1146
1145
|
}
|
|
1147
1146
|
} finally {
|
|
1148
1147
|
swapContextMap(prev);
|
|
@@ -1167,9 +1166,9 @@ async function renderToString(element, options) {
|
|
|
1167
1166
|
resetRenderState(idPrefix);
|
|
1168
1167
|
const r = renderNode(element, writer);
|
|
1169
1168
|
if (r && typeof r.then === "function") {
|
|
1170
|
-
const
|
|
1169
|
+
const rctx = captureRenderCtx();
|
|
1171
1170
|
await r;
|
|
1172
|
-
|
|
1171
|
+
restoreRenderCtx(rctx);
|
|
1173
1172
|
}
|
|
1174
1173
|
return output;
|
|
1175
1174
|
} finally {
|
|
@@ -1285,18 +1284,18 @@ var makePrecontentHtmlGetter = (htmlFilePromise) => {
|
|
|
1285
1284
|
let preHead = null;
|
|
1286
1285
|
let postHead = null;
|
|
1287
1286
|
let postContent = null;
|
|
1287
|
+
const primed = htmlFilePromise.then((html) => {
|
|
1288
|
+
const headEnd = html.indexOf(HEAD_MARKER);
|
|
1289
|
+
const contentStart = html.indexOf(BODY_MARKER);
|
|
1290
|
+
preHead = html.slice(0, headEnd);
|
|
1291
|
+
postHead = html.slice(headEnd + HEAD_MARKER.length, contentStart);
|
|
1292
|
+
postContent = html.slice(contentStart + BODY_MARKER.length);
|
|
1293
|
+
});
|
|
1288
1294
|
return (headHtml) => {
|
|
1289
1295
|
if (preHead !== null) {
|
|
1290
1296
|
return [preHead + headHtml + postHead, postContent];
|
|
1291
1297
|
}
|
|
1292
|
-
return
|
|
1293
|
-
const headEnd = html.indexOf(HEAD_MARKER);
|
|
1294
|
-
const contentStart = html.indexOf(BODY_MARKER);
|
|
1295
|
-
preHead = html.slice(0, headEnd);
|
|
1296
|
-
postHead = html.slice(headEnd + HEAD_MARKER.length, contentStart);
|
|
1297
|
-
postContent = html.slice(contentStart + BODY_MARKER.length);
|
|
1298
|
-
return [preHead + headHtml + postHead, postContent];
|
|
1299
|
-
});
|
|
1298
|
+
return primed.then(() => [preHead + headHtml + postHead, postContent]);
|
|
1300
1299
|
};
|
|
1301
1300
|
};
|
|
1302
1301
|
async function transformStream(data, stream) {
|
|
@@ -1456,14 +1455,8 @@ function createLambdaHandler(options, bundled) {
|
|
|
1456
1455
|
const fetchHandler = options.fetch;
|
|
1457
1456
|
const handleProxy = createProxyHandler(options);
|
|
1458
1457
|
const getPrecontentHtml = bundled ? makePrecontentHtmlGetter(Promise.resolve(bundled.outHtml)) : makePrecontentHtmlGetter(import_promises2.default.readFile(import_node_path.default.join(cwd, StaticPath, "out.html"), "utf-8"));
|
|
1459
|
-
|
|
1460
|
-
const getSsrModule = () =>
|
|
1461
|
-
if (bundled) return Promise.resolve(bundled.ssrModule);
|
|
1462
|
-
if (!ssrModulePromise) {
|
|
1463
|
-
ssrModulePromise = import((0, import_node_url.pathToFileURL)(import_node_path.default.resolve(cwd, HadarsFolder, SSR_FILENAME)).href);
|
|
1464
|
-
}
|
|
1465
|
-
return ssrModulePromise;
|
|
1466
|
-
};
|
|
1458
|
+
const ssrModulePromise = bundled ? Promise.resolve(bundled.ssrModule) : import((0, import_node_url.pathToFileURL)(import_node_path.default.resolve(cwd, HadarsFolder, SSR_FILENAME)).href);
|
|
1459
|
+
const getSsrModule = () => ssrModulePromise;
|
|
1467
1460
|
const runHandler = async (req) => {
|
|
1468
1461
|
const request = parseRequest(req);
|
|
1469
1462
|
if (fetchHandler) {
|
|
@@ -1517,6 +1510,8 @@ function createLambdaHandler(options, bundled) {
|
|
|
1517
1510
|
});
|
|
1518
1511
|
} catch (err) {
|
|
1519
1512
|
console.error("[hadars] SSR render error:", err);
|
|
1513
|
+
options.onError?.(err, request)?.catch?.(() => {
|
|
1514
|
+
});
|
|
1520
1515
|
return new Response("Internal Server Error", { status: 500 });
|
|
1521
1516
|
}
|
|
1522
1517
|
};
|
package/dist/lambda.d.cts
CHANGED
package/dist/lambda.d.ts
CHANGED