@ubean/pages 0.2.1 → 0.3.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/dist/index.d.ts CHANGED
@@ -27,6 +27,15 @@ interface PageRenderContext {
27
27
  locale?: string;
28
28
  localeDir?: 'ltr' | 'rtl';
29
29
  messages?: Record<string, unknown>;
30
+ fallbackLocale?: string;
31
+ fallbackMessages?: Record<string, unknown>;
32
+ routing?: {
33
+ defaultLocale: string;
34
+ locales: string[];
35
+ strategy: 'prefix' | 'prefix_except_default' | 'prefix_and_default' | 'no_prefix';
36
+ };
37
+ cookieName?: string;
38
+ baseUrl?: string;
30
39
  /** All registered locales (metadata only, no messages) — sent to the
31
40
  * client so it can register every available locale during hydration,
32
41
  * preventing `availableLocales` hydration mismatches. */
@@ -50,7 +59,7 @@ type PageRenderFn = (pageObj: PageObject, shellHtml: string, assetTags: PageAsse
50
59
  * 流式渲染函数:返回一个 `ReadableStream<Uint8Array>`,将完整 HTML 文档
51
60
  * 分块流式输出(头部先发送,app HTML 边渲染边输出,state 在尾部注入)。
52
61
  *
53
- * 由 `@ubean/ssr` 的 `createVueRenderer` 实现。当 renderer 提供此方法且
62
+ * 由 `@ubean/client/ssr` 的 `createVueRenderer` 实现。当 renderer 提供此方法且
54
63
  * 应用配置启用了 `streaming` 时,页面处理器会优先使用流式渲染,显著改善
55
64
  * TTFB/LCP(浏览器可在 app 渲染期间提前加载 CSS/JS)。
56
65
  */
@@ -252,6 +261,30 @@ interface StreamHelper {
252
261
  declare function createStreamResponse(init?: ResponseInit, onStart?: (stream: StreamHelper) => void | Promise<void>): Response;
253
262
  declare function createSseStream(onStart?: (stream: StreamHelper) => void | Promise<void>): Response;
254
263
  //#endregion
264
+ //#region src/fetch.d.ts
265
+ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
266
+ interface FetchClient {
267
+ get?: <T>(url: string, options?: {
268
+ query?: Record<string, unknown>;
269
+ }) => Promise<T>;
270
+ request?: <T>(options: {
271
+ url: string;
272
+ method?: string;
273
+ data?: unknown;
274
+ query?: Record<string, unknown>;
275
+ }) => Promise<T>;
276
+ }
277
+ interface UseFetchOptions<T> extends UseAsyncDataOptions {
278
+ method?: HttpMethod;
279
+ query?: Record<string, unknown>;
280
+ body?: unknown;
281
+ request?: FetchClient;
282
+ transform?: (data: T) => T;
283
+ }
284
+ declare function setDefaultFetch(request: FetchClient | undefined): void;
285
+ declare function getDefaultFetch(): FetchClient | undefined;
286
+ declare function useFetch<T>(key: string, url: string, options?: UseFetchOptions<T>, context?: object): Promise<DataResult<T>>;
287
+ //#endregion
255
288
  //#region src/defer.d.ts
256
289
  /**
257
290
  * `__UBEAN_DEFERRED__` script 标签 ID — SSR 流式渲染完成后,延迟数据
@@ -350,4 +383,4 @@ interface UseDeferredDataResult<T> {
350
383
  */
351
384
  declare function useDeferredData<T>(key: string, deferred: DeferredValue<T>): UseDeferredDataResult<T>;
352
385
  //#endregion
353
- export { DATA_PAYLOAD_ID, DEFERRED_DATA_ID, type DataCacheEntry, type DataKey, type DataPayloadEntry, type DataResult, type DataStatus, type DeferredValue, type DependencyDeclaration, type InternalFetchOptions, LOCALE_DATA_ID, type LocaleMetaInfo, PAGE_DATA_ID, PAGE_REQUEST_HEADER, type PageAssetTags, type PageHead, type PageHeadMeta, type PageObject, type PageRenderContext, type PageRenderFn, type PageRenderResult, type PageRenderer, type PageStreamRenderFn, SSR_CONTENT_MARKER, STATE_DATA_ID, STATE_MARKER, type StreamHelper, type UseAsyncDataOptions, type UseDataOptions, type UseDeferredDataResult, __clearDataPayload, __clearDeferred, __registerDataPayload, __registerDeferred, __resetDataPayloadCache, __resetDeferredCache, __resolveDataPayload, __resolveDeferred, __serializeDataPayload, __serializeDeferred, buildClientOnlyShell, buildPageShell, clearPageData, createInternalFetch, createSseStream, createStreamResponse, declareDependencies, defer, defineDataKey, getInvalidatedKeysForAction, hasData, insertSsrContent, insertStateContent, invalidateAll, invalidateData, isDeferredValue, isPagesRequest, pageJsonResponse, renderFaviconLink, renderPage, renderPageToStream, safeJsonStringify, serializePageData, useAsyncData, useData, useDeferredData, withDependencies };
386
+ export { DATA_PAYLOAD_ID, DEFERRED_DATA_ID, type DataCacheEntry, type DataKey, type DataPayloadEntry, type DataResult, type DataStatus, type DeferredValue, type DependencyDeclaration, type FetchClient, type InternalFetchOptions, LOCALE_DATA_ID, type LocaleMetaInfo, PAGE_DATA_ID, PAGE_REQUEST_HEADER, type PageAssetTags, type PageHead, type PageHeadMeta, type PageObject, type PageRenderContext, type PageRenderFn, type PageRenderResult, type PageRenderer, type PageStreamRenderFn, SSR_CONTENT_MARKER, STATE_DATA_ID, STATE_MARKER, type StreamHelper, type UseAsyncDataOptions, type UseDataOptions, type UseDeferredDataResult, type UseFetchOptions, __clearDataPayload, __clearDeferred, __registerDataPayload, __registerDeferred, __resetDataPayloadCache, __resetDeferredCache, __resolveDataPayload, __resolveDeferred, __serializeDataPayload, __serializeDeferred, buildClientOnlyShell, buildPageShell, clearPageData, createInternalFetch, createSseStream, createStreamResponse, declareDependencies, defer, defineDataKey, getDefaultFetch, getInvalidatedKeysForAction, hasData, insertSsrContent, insertStateContent, invalidateAll, invalidateData, isDeferredValue, isPagesRequest, pageJsonResponse, renderFaviconLink, renderPage, renderPageToStream, safeJsonStringify, serializePageData, setDefaultFetch, useAsyncData, useData, useDeferredData, useFetch, withDependencies };
package/dist/index.js CHANGED
@@ -97,6 +97,11 @@ function buildPageShell(pageObj, assetTags, preambleScript = "", appId = "app",
97
97
  locale,
98
98
  dir: localeDir,
99
99
  ...messages ? { messages } : {},
100
+ ...renderContext?.fallbackLocale ? { fallbackLocale: renderContext.fallbackLocale } : {},
101
+ ...renderContext?.fallbackMessages ? { fallbackMessages: renderContext.fallbackMessages } : {},
102
+ ...renderContext?.routing ? { routing: renderContext.routing } : {},
103
+ ...renderContext?.cookieName ? { cookieName: renderContext.cookieName } : {},
104
+ ...renderContext?.baseUrl ? { baseUrl: renderContext.baseUrl } : {},
100
105
  ...availableLocales?.length ? { availableLocales } : {}
101
106
  })}<\/script>` : "";
102
107
  const { headTags, htmlAttrsStr, bodyAttrsStr } = renderHeadTags(pageObj.head);
@@ -151,6 +156,11 @@ function buildClientOnlyShell(pageObj, assetTags, preambleScript = "", appId = "
151
156
  locale,
152
157
  dir: localeDir,
153
158
  ...messages ? { messages } : {},
159
+ ...renderContext?.fallbackLocale ? { fallbackLocale: renderContext.fallbackLocale } : {},
160
+ ...renderContext?.fallbackMessages ? { fallbackMessages: renderContext.fallbackMessages } : {},
161
+ ...renderContext?.routing ? { routing: renderContext.routing } : {},
162
+ ...renderContext?.cookieName ? { cookieName: renderContext.cookieName } : {},
163
+ ...renderContext?.baseUrl ? { baseUrl: renderContext.baseUrl } : {},
154
164
  ...availableLocales?.length ? { availableLocales } : {}
155
165
  })}<\/script>` : "";
156
166
  const { headTags, htmlAttrsStr: pageHtmlAttrsStr, bodyAttrsStr } = renderHeadTags(pageObj.head);
@@ -675,6 +685,62 @@ function createSseStream(onStart) {
675
685
  } });
676
686
  }
677
687
  //#endregion
688
+ //#region src/fetch.ts
689
+ /**
690
+ * `useFetch` — Nuxt-style wrapper around `useAsyncData`.
691
+ *
692
+ * Does not invent an HTTP client. Pass a `@soybeanjs/fetch` `createRequest()`
693
+ * instance (or any duck-typed client) via `setDefaultFetch` / `options.request`.
694
+ * Without a client, falls back to global `fetch` + JSON.
695
+ */
696
+ const FETCH_KEY = "__UBEAN_DEFAULT_FETCH__";
697
+ function setDefaultFetch(request) {
698
+ globalThis[FETCH_KEY] = request;
699
+ }
700
+ function getDefaultFetch() {
701
+ return globalThis[FETCH_KEY];
702
+ }
703
+ async function nativeJson(url, options) {
704
+ const method = options.method ?? "GET";
705
+ const target = new URL(url, "http://ubean.local");
706
+ if (options.query) {
707
+ for (const [key, value] of Object.entries(options.query)) if (value !== void 0 && value !== null) target.searchParams.set(key, String(value));
708
+ }
709
+ const init = { method };
710
+ if (method !== "GET" && method !== "DELETE" && options.body !== void 0) {
711
+ init.headers = { "Content-Type": "application/json" };
712
+ init.body = JSON.stringify(options.body);
713
+ }
714
+ const href = url.startsWith("http") ? target.toString() : `${target.pathname}${target.search}`;
715
+ const res = await fetch(href, init);
716
+ if (!res.ok) throw new Error(`useFetch ${method} ${href} failed: ${res.status}`);
717
+ return await res.json();
718
+ }
719
+ async function runFetch(url, options) {
720
+ const client = options.request ?? getDefaultFetch();
721
+ const method = options.method ?? "GET";
722
+ let data;
723
+ if (client?.get && method === "GET") data = await client.get(url, { query: options.query });
724
+ else if (client?.request) data = await client.request({
725
+ url,
726
+ method,
727
+ data: options.body,
728
+ query: options.query
729
+ });
730
+ else data = await nativeJson(url, options);
731
+ return options.transform ? options.transform(data) : data;
732
+ }
733
+ async function useFetch(key, url, options = {}, context) {
734
+ const { method, query, body, request, transform, ...asyncOpts } = options;
735
+ return useAsyncData(key, () => runFetch(url, {
736
+ method,
737
+ query,
738
+ body,
739
+ request,
740
+ transform
741
+ }), asyncOpts, context);
742
+ }
743
+ //#endregion
678
744
  //#region src/defer.ts
679
745
  /**
680
746
  * `__UBEAN_DEFERRED__` script 标签 ID — SSR 流式渲染完成后,延迟数据
@@ -840,4 +906,4 @@ function useDeferredData(key, deferred) {
840
906
  };
841
907
  }
842
908
  //#endregion
843
- export { DATA_PAYLOAD_ID, DEFERRED_DATA_ID, LOCALE_DATA_ID, PAGE_DATA_ID, PAGE_REQUEST_HEADER, SSR_CONTENT_MARKER, STATE_DATA_ID, STATE_MARKER, __clearDataPayload, __clearDeferred, __registerDataPayload, __registerDeferred, __resetDataPayloadCache, __resetDeferredCache, __resolveDataPayload, __resolveDeferred, __serializeDataPayload, __serializeDeferred, buildClientOnlyShell, buildPageShell, clearPageData, createInternalFetch, createSseStream, createStreamResponse, declareDependencies, defer, defineDataKey, getInvalidatedKeysForAction, hasData, insertSsrContent, insertStateContent, invalidateAll, invalidateData, isDeferredValue, isPagesRequest, pageJsonResponse, renderFaviconLink, renderPage, renderPageToStream, safeJsonStringify, serializePageData, useAsyncData, useData, useDeferredData, withDependencies };
909
+ export { DATA_PAYLOAD_ID, DEFERRED_DATA_ID, LOCALE_DATA_ID, PAGE_DATA_ID, PAGE_REQUEST_HEADER, SSR_CONTENT_MARKER, STATE_DATA_ID, STATE_MARKER, __clearDataPayload, __clearDeferred, __registerDataPayload, __registerDeferred, __resetDataPayloadCache, __resetDeferredCache, __resolveDataPayload, __resolveDeferred, __serializeDataPayload, __serializeDeferred, buildClientOnlyShell, buildPageShell, clearPageData, createInternalFetch, createSseStream, createStreamResponse, declareDependencies, defer, defineDataKey, getDefaultFetch, getInvalidatedKeysForAction, hasData, insertSsrContent, insertStateContent, invalidateAll, invalidateData, isDeferredValue, isPagesRequest, pageJsonResponse, renderFaviconLink, renderPage, renderPageToStream, safeJsonStringify, serializePageData, setDefaultFetch, useAsyncData, useData, useDeferredData, useFetch, withDependencies };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ubean/pages",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Page data protocol and isomorphic data layer for ubean (PageObject, useData, invalidateData)",
5
5
  "files": [
6
6
  "dist"
@@ -16,7 +16,7 @@
16
16
  }
17
17
  },
18
18
  "dependencies": {
19
- "@ubean/shared": "0.2.1"
19
+ "@ubean/shared": "0.3.0"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@types/node": "^26.2.0",