@daouy/loader-fetcher 1.0.58

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Chung Wu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # @daouy/loader-fetcher
2
+
3
+ Library for fetching component data from Daouy.
@@ -0,0 +1,225 @@
1
+ export declare class Api {
2
+ private opts;
3
+ private host;
4
+ private fetch;
5
+ private lastResponse;
6
+ constructor(opts: {
7
+ projects: {
8
+ id: string;
9
+ token: string;
10
+ }[];
11
+ host?: string;
12
+ nativeFetch?: boolean;
13
+ manualRedirect?: boolean;
14
+ });
15
+ fetchLoaderData(projectIds: string[], opts: {
16
+ platform?: "react" | "nextjs" | "gatsby";
17
+ platformOptions?: {
18
+ nextjs?: {
19
+ appDir: boolean;
20
+ };
21
+ };
22
+ preview?: boolean;
23
+ browserOnly?: boolean;
24
+ i18nKeyScheme?: "content" | "hash" | "path";
25
+ i18nTagPrefix?: string;
26
+ skipHead?: boolean;
27
+ }): Promise<LoaderBundleOutput>;
28
+ private verifyAndParseJsonResponse;
29
+ private parseJsonResponse;
30
+ fetchHtmlData(opts: {
31
+ projectId: string;
32
+ component: string;
33
+ hydrate?: boolean;
34
+ embedHydrate?: boolean;
35
+ }): Promise<LoaderHtmlOutput>;
36
+ private makeGetHeaders;
37
+ private makeAuthHeaders;
38
+ getChunksUrl(bundle: LoaderBundleOutput, modules: CodeModule[]): string;
39
+ }
40
+
41
+ declare interface ApiLoaderBundleOutput {
42
+ modules: {
43
+ browser: (CodeModule | AssetModule)[];
44
+ server: (CodeModule | AssetModule)[];
45
+ };
46
+ components: ComponentMeta[];
47
+ globalGroups: GlobalGroupMeta[];
48
+ projects: ProjectMeta[];
49
+ activeSplits: Split[];
50
+ bundleKey: string | null;
51
+ deferChunksByDefault: boolean;
52
+ disableRootLoadingBoundaryByDefault: boolean;
53
+ redirectUrl?: string;
54
+ }
55
+
56
+ export declare interface AssetModule {
57
+ fileName: string;
58
+ source: string;
59
+ type: "asset";
60
+ }
61
+
62
+ declare interface BareSplit {
63
+ id: string;
64
+ projectId: string;
65
+ name: string;
66
+ externalId?: string;
67
+ description?: string;
68
+ pagesPaths: string[];
69
+ }
70
+
71
+ export declare interface CodeModule {
72
+ fileName: string;
73
+ code: string;
74
+ imports: string[];
75
+ type: "code";
76
+ }
77
+
78
+ export declare interface ComponentMeta {
79
+ id: string;
80
+ usedComponents: string[];
81
+ projectId: string;
82
+ name: string;
83
+ displayName: string;
84
+ cssFile: string;
85
+ path: string | undefined;
86
+ isPage: boolean;
87
+ plumeType?: string;
88
+ entry: string;
89
+ isCode: boolean;
90
+ isGlobalContextProvider: boolean;
91
+ pageMetadata?: PageMetadata;
92
+ metadata?: Record<string, string>;
93
+ serverQueriesExecFuncFileName?: string;
94
+ generateMetadataFuncFileName?: string;
95
+ }
96
+
97
+ export declare class DaouyModulesFetcher {
98
+ private opts;
99
+ private api;
100
+ private curFetch;
101
+ constructor(opts: FetcherOptions);
102
+ getChunksUrl(bundle: LoaderBundleOutput, modules: CodeModule[]): string;
103
+ fetchAllData(): Promise<LoaderBundleOutput>;
104
+ private getCachedOrFetch;
105
+ private doFetch;
106
+ private cacheBundleInNodeServer;
107
+ }
108
+
109
+ export declare interface ExperimentSlice extends Slice {
110
+ prob: number;
111
+ }
112
+
113
+ declare interface ExperimentSplit extends BareSplit {
114
+ type: "experiment";
115
+ slices: ExperimentSlice[];
116
+ }
117
+
118
+ export declare interface FetcherOptions {
119
+ projects: {
120
+ id: string;
121
+ version?: string;
122
+ token: string;
123
+ }[];
124
+ cache?: LoaderBundleCache;
125
+ platform?: "react" | "nextjs" | "gatsby";
126
+ platformOptions?: {
127
+ nextjs?: {
128
+ appDir: boolean;
129
+ };
130
+ };
131
+ preview?: boolean;
132
+ host?: string;
133
+ /**
134
+ * @deprecated use i18n.keyScheme instead
135
+ */
136
+ i18nKeyScheme?: "content" | "hash" | "path";
137
+ i18n?: {
138
+ keyScheme: "content" | "hash" | "path";
139
+ tagPrefix?: string;
140
+ };
141
+ skipHead?: boolean;
142
+ nativeFetch?: boolean;
143
+ manualRedirect?: boolean;
144
+ }
145
+
146
+ export declare interface FontMeta {
147
+ url: string;
148
+ }
149
+
150
+ export declare interface GlobalGroupMeta {
151
+ id: string;
152
+ projectId: string;
153
+ name: string;
154
+ type: string;
155
+ contextFile: string;
156
+ useName: string;
157
+ }
158
+
159
+ declare interface GlobalVariantSplitContent {
160
+ type: "global-variant";
161
+ projectId: string;
162
+ group: string;
163
+ variant: string;
164
+ }
165
+
166
+ export declare function internal_getCachedBundleInNodeServer(opts: FetcherOptions): LoaderBundleOutput | undefined;
167
+
168
+ export declare interface LoaderBundleCache {
169
+ set: (data: LoaderBundleOutput) => Promise<void>;
170
+ get: () => Promise<LoaderBundleOutput>;
171
+ }
172
+
173
+ export declare interface LoaderBundleOutput extends ApiLoaderBundleOutput {
174
+ filteredIds: Record<string, string[]>;
175
+ }
176
+
177
+ export declare interface LoaderHtmlOutput {
178
+ html: string;
179
+ }
180
+
181
+ export declare interface PageMeta extends ComponentMeta {
182
+ isPage: true;
183
+ path: string;
184
+ plumeType: never;
185
+ pageMetadata: PageMetadata;
186
+ }
187
+
188
+ export declare interface PageMetadata {
189
+ path: string;
190
+ title?: string | null;
191
+ description?: string | null;
192
+ openGraphImageUrl?: string | null;
193
+ canonical?: string | null;
194
+ }
195
+
196
+ export declare interface ProjectMeta {
197
+ id: string;
198
+ teamId?: string;
199
+ indirect: boolean;
200
+ name: string;
201
+ version: string;
202
+ remoteFonts: FontMeta[];
203
+ hasStyleTokenOverrides: boolean;
204
+ styleTokensProviderFileName: string;
205
+ globalContextsProviderFileName: string;
206
+ }
207
+
208
+ export declare interface SegmentSlice extends Slice {
209
+ cond: any;
210
+ }
211
+
212
+ declare interface SegmentSplit extends BareSplit {
213
+ type: "segment";
214
+ slices: SegmentSlice[];
215
+ }
216
+
217
+ declare interface Slice {
218
+ id: string;
219
+ contents: GlobalVariantSplitContent[];
220
+ externalId?: string;
221
+ }
222
+
223
+ export declare type Split = ExperimentSplit | SegmentSplit;
224
+
225
+ export { }
@@ -0,0 +1,306 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ var __async = (__this, __arguments, generator) => {
21
+ return new Promise((resolve, reject) => {
22
+ var fulfilled = (value) => {
23
+ try {
24
+ step(generator.next(value));
25
+ } catch (e) {
26
+ reject(e);
27
+ }
28
+ };
29
+ var rejected = (value) => {
30
+ try {
31
+ step(generator.throw(value));
32
+ } catch (e) {
33
+ reject(e);
34
+ }
35
+ };
36
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
37
+ step((generator = generator.apply(__this, __arguments)).next());
38
+ });
39
+ };
40
+
41
+ // src/api.ts
42
+ import unfetch from "@daouy/isomorphic-unfetch";
43
+ var VERSION = "10";
44
+ var isBrowser = typeof window !== "undefined" && window != null && typeof window.document !== "undefined";
45
+ function transformApiLoaderBundleOutput(bundle) {
46
+ return __spreadProps(__spreadValues({}, bundle), {
47
+ filteredIds: Object.fromEntries(bundle.projects.map((p) => [p.id, []]))
48
+ });
49
+ }
50
+ var Api = class {
51
+ constructor(opts) {
52
+ this.opts = opts;
53
+ this.lastResponse = void 0;
54
+ var _a;
55
+ this.host = (_a = opts.host) != null ? _a : "https://codegen.quocuy.cloud";
56
+ this.fetch = (opts.nativeFetch && globalThis.fetch ? globalThis.fetch : unfetch).bind(globalThis);
57
+ }
58
+ fetchLoaderData(projectIds, opts) {
59
+ return __async(this, null, function* () {
60
+ var _a, _b, _c, _d, _e;
61
+ const { platform, preview } = opts;
62
+ const query = new URLSearchParams([
63
+ ["platform", platform != null ? platform : "react"],
64
+ ...((_b = (_a = opts.platformOptions) == null ? void 0 : _a.nextjs) == null ? void 0 : _b.appDir) ? [["nextjsAppDir", "true"]] : [],
65
+ ...projectIds.map((projectId) => ["projectId", projectId]),
66
+ ...opts.browserOnly ? [["browserOnly", "true"]] : [],
67
+ ...opts.i18nKeyScheme ? [["i18nKeyScheme", opts.i18nKeyScheme]] : [],
68
+ ...opts.i18nTagPrefix ? [["i18nTagPrefix", opts.i18nTagPrefix]] : [],
69
+ ...opts.skipHead ? [["skipHead", "true"]] : []
70
+ ]).toString();
71
+ const url = `${this.host}/api/v1/loader/code/${preview ? "preview" : "published"}?${query}`;
72
+ const useLastReponse = (
73
+ // We consider that manualRedirect is true by default, only by setting it to false
74
+ // we disable it.
75
+ !(this.opts.manualRedirect === false) && !preview && !isBrowser
76
+ );
77
+ if (useLastReponse) {
78
+ const redirectResp = yield this.fetch(url, {
79
+ method: "GET",
80
+ headers: this.makeGetHeaders(),
81
+ redirect: "manual"
82
+ });
83
+ if (redirectResp.status !== 301 && redirectResp.status !== 302) {
84
+ const error = yield this.parseJsonResponse(redirectResp);
85
+ throw new Error(
86
+ `Error fetching loader data, a redirect was expected: ${(_d = (_c = error == null ? void 0 : error.error) == null ? void 0 : _c.message) != null ? _d : redirectResp.statusText}`
87
+ );
88
+ }
89
+ const nextLocation = redirectResp.headers.get("location");
90
+ if (!nextLocation) {
91
+ throw new Error(
92
+ `Error fetching loader data, a redirect was expected but no location header was found`
93
+ );
94
+ }
95
+ if (((_e = this.lastResponse) == null ? void 0 : _e.key) === nextLocation) {
96
+ return this.lastResponse.bundle;
97
+ }
98
+ const resp2 = yield this.fetch(`${this.host}${nextLocation}`, {
99
+ method: "GET",
100
+ headers: this.makeGetHeaders()
101
+ });
102
+ const json2 = transformApiLoaderBundleOutput(
103
+ yield this.verifyAndParseJsonResponse(resp2)
104
+ );
105
+ this.lastResponse = {
106
+ bundle: json2,
107
+ key: nextLocation
108
+ };
109
+ return json2;
110
+ }
111
+ const resp = yield this.fetch(url, {
112
+ method: "GET",
113
+ headers: this.makeGetHeaders()
114
+ });
115
+ let json = yield this.verifyAndParseJsonResponse(resp);
116
+ if (json.redirectUrl) {
117
+ const redirectResp = yield this.fetch(`${this.host}${json.redirectUrl}`, {
118
+ method: "GET",
119
+ headers: this.makeGetHeaders()
120
+ });
121
+ json = yield this.verifyAndParseJsonResponse(redirectResp);
122
+ }
123
+ return transformApiLoaderBundleOutput(json);
124
+ });
125
+ }
126
+ verifyAndParseJsonResponse(resp, errorText = "Error fetching loader data") {
127
+ return __async(this, null, function* () {
128
+ var _a, _b;
129
+ if (resp.status >= 400) {
130
+ const error = yield this.parseJsonResponse(resp);
131
+ throw new Error(
132
+ `${errorText}: ${(_b = (_a = error == null ? void 0 : error.error) == null ? void 0 : _a.message) != null ? _b : resp.statusText}`
133
+ );
134
+ }
135
+ return yield this.parseJsonResponse(resp);
136
+ });
137
+ }
138
+ parseJsonResponse(resp) {
139
+ return __async(this, null, function* () {
140
+ const text = yield resp.text();
141
+ try {
142
+ return JSON.parse(text);
143
+ } catch (err) {
144
+ throw new Error(
145
+ `Error parsing JSON response: ${err}; status: ${resp.status}; response: ${text}`
146
+ );
147
+ }
148
+ });
149
+ }
150
+ fetchHtmlData(opts) {
151
+ return __async(this, null, function* () {
152
+ const { projectId, component, embedHydrate, hydrate } = opts;
153
+ const query = new URLSearchParams([
154
+ ["projectId", projectId],
155
+ ["component", component],
156
+ ["embedHydrate", embedHydrate ? "1" : "0"],
157
+ ["hydrate", hydrate ? "1" : "0"]
158
+ ]).toString();
159
+ const resp = yield this.fetch(`${this.host}/api/v1/loader/html?${query}`, {
160
+ method: "GET",
161
+ headers: this.makeGetHeaders()
162
+ });
163
+ const json = yield resp.json();
164
+ return json;
165
+ });
166
+ }
167
+ makeGetHeaders() {
168
+ return __spreadValues({
169
+ "x-daouy-loader-version": VERSION
170
+ }, this.makeAuthHeaders());
171
+ }
172
+ makeAuthHeaders() {
173
+ const tokens = this.opts.projects.map((p) => `${p.id}:${p.token}`).join(",");
174
+ return {
175
+ "x-daouy-api-project-tokens": tokens
176
+ };
177
+ }
178
+ getChunksUrl(bundle, modules) {
179
+ var _a;
180
+ return `${this.host}/api/v1/loader/chunks?bundleKey=${encodeURIComponent(
181
+ (_a = bundle.bundleKey) != null ? _a : "null"
182
+ )}&fileName=${encodeURIComponent(
183
+ modules.map((m) => m.fileName).sort().join(",")
184
+ )}`;
185
+ }
186
+ };
187
+
188
+ // src/fetcher.ts
189
+ var DaouyModulesFetcher = class {
190
+ constructor(opts) {
191
+ this.opts = opts;
192
+ this.curFetch = void 0;
193
+ this.api = new Api({
194
+ projects: opts.projects,
195
+ host: opts.host,
196
+ nativeFetch: opts.nativeFetch,
197
+ manualRedirect: opts.manualRedirect
198
+ });
199
+ }
200
+ getChunksUrl(bundle, modules) {
201
+ return this.api.getChunksUrl(bundle, modules);
202
+ }
203
+ fetchAllData() {
204
+ return __async(this, null, function* () {
205
+ const bundle = yield this.getCachedOrFetch();
206
+ this.cacheBundleInNodeServer(bundle);
207
+ return bundle;
208
+ });
209
+ }
210
+ getCachedOrFetch() {
211
+ return __async(this, null, function* () {
212
+ var _a;
213
+ if (this.opts.cache) {
214
+ const cachedData = yield this.opts.cache.get();
215
+ if (cachedData) {
216
+ return cachedData;
217
+ }
218
+ }
219
+ if (this.curFetch) {
220
+ return yield this.curFetch;
221
+ }
222
+ if (typeof process === "undefined" || !((_a = process.env) == null ? void 0 : _a.DAOUY_QUIET)) {
223
+ console.debug("Daouy: doing a fresh fetch...");
224
+ }
225
+ const fetchPromise = this.doFetch();
226
+ this.curFetch = fetchPromise;
227
+ try {
228
+ const data = yield fetchPromise;
229
+ return data;
230
+ } finally {
231
+ if (this.curFetch === fetchPromise) {
232
+ this.curFetch = void 0;
233
+ }
234
+ }
235
+ });
236
+ }
237
+ doFetch() {
238
+ return __async(this, null, function* () {
239
+ var _a, _b, _c, _d;
240
+ const data = yield this.api.fetchLoaderData(
241
+ this.opts.projects.map(
242
+ (p) => p.version ? `${p.id}@${p.version}` : p.id
243
+ ),
244
+ {
245
+ platform: this.opts.platform,
246
+ platformOptions: this.opts.platformOptions,
247
+ preview: this.opts.preview,
248
+ i18nKeyScheme: (_b = (_a = this.opts.i18n) == null ? void 0 : _a.keyScheme) != null ? _b : this.opts.i18nKeyScheme,
249
+ i18nTagPrefix: (_c = this.opts.i18n) == null ? void 0 : _c.tagPrefix,
250
+ browserOnly: isBrowser,
251
+ skipHead: this.opts.skipHead
252
+ }
253
+ );
254
+ if (this.opts.cache) {
255
+ yield this.opts.cache.set(data);
256
+ }
257
+ if (typeof process === "undefined" || !((_d = process.env) == null ? void 0 : _d.DAOUY_QUIET)) {
258
+ console.debug(
259
+ `Daouy: fetched designs for ${data.projects.map((p) => `"${p.name}" (${p.id}@${p.version})`).join(", ")}`
260
+ );
261
+ }
262
+ return data;
263
+ });
264
+ }
265
+ cacheBundleInNodeServer(bundle) {
266
+ if (isBrowser) {
267
+ return;
268
+ }
269
+ const global = globalThis;
270
+ if (global.__DAOUY_BUNDLES === void 0) {
271
+ global.__DAOUY_BUNDLES = {};
272
+ }
273
+ global.__DAOUY_BUNDLES[getBundleKey(this.opts)] = bundle;
274
+ }
275
+ };
276
+ function internal_getCachedBundleInNodeServer(opts) {
277
+ var _a;
278
+ if (isBrowser) {
279
+ throw new Error(`Should not be consulting Node server cache in browser`);
280
+ }
281
+ const global = globalThis;
282
+ return (_a = global.__DAOUY_BUNDLES) == null ? void 0 : _a[getBundleKey(opts)];
283
+ }
284
+ function getBundleKey({
285
+ host,
286
+ platform,
287
+ i18nKeyScheme,
288
+ preview,
289
+ projects,
290
+ skipHead
291
+ }) {
292
+ return JSON.stringify({
293
+ host,
294
+ platform,
295
+ i18nKeyScheme,
296
+ preview,
297
+ projects,
298
+ skipHead
299
+ });
300
+ }
301
+ export {
302
+ Api,
303
+ DaouyModulesFetcher,
304
+ internal_getCachedBundleInNodeServer
305
+ };
306
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/api.ts", "../src/fetcher.ts"],
4
+ "sourcesContent": ["import unfetch from \"@daouy/isomorphic-unfetch\";\n\nexport interface ComponentMeta {\n id: string;\n usedComponents: string[];\n projectId: string;\n name: string;\n displayName: string;\n cssFile: string;\n path: string | undefined;\n isPage: boolean;\n plumeType?: string;\n entry: string;\n isCode: boolean;\n isGlobalContextProvider: boolean;\n pageMetadata?: PageMetadata;\n metadata?: Record<string, string>;\n serverQueriesExecFuncFileName?: string;\n generateMetadataFuncFileName?: string;\n}\n\nexport interface PageMeta extends ComponentMeta {\n isPage: true;\n path: string;\n plumeType: never;\n pageMetadata: PageMetadata;\n}\n\nexport interface PageMetadata {\n path: string;\n title?: string | null;\n description?: string | null;\n openGraphImageUrl?: string | null;\n canonical?: string | null;\n}\n\nexport interface GlobalGroupMeta {\n id: string;\n projectId: string;\n name: string;\n type: string;\n contextFile: string;\n useName: string;\n}\n\n// Keep in sync with platform/wab ProjectMeta\nexport interface ProjectMeta {\n id: string;\n teamId?: string;\n indirect: boolean;\n name: string;\n version: string;\n remoteFonts: FontMeta[];\n hasStyleTokenOverrides: boolean;\n styleTokensProviderFileName: string;\n globalContextsProviderFileName: string;\n}\n\nexport interface FontMeta {\n url: string;\n}\n\ninterface GlobalVariantSplitContent {\n type: \"global-variant\";\n projectId: string;\n group: string;\n variant: string;\n}\n\ninterface Slice {\n id: string;\n contents: GlobalVariantSplitContent[];\n externalId?: string;\n}\n\nexport interface ExperimentSlice extends Slice {\n prob: number;\n}\n\nexport interface SegmentSlice extends Slice {\n cond: any;\n}\n\ninterface BareSplit {\n id: string;\n projectId: string;\n name: string;\n externalId?: string;\n description?: string;\n pagesPaths: string[];\n}\n\nexport interface ExperimentSplit extends BareSplit {\n type: \"experiment\";\n slices: ExperimentSlice[];\n}\n\nexport interface SegmentSplit extends BareSplit {\n type: \"segment\";\n slices: SegmentSlice[];\n}\n\nexport type Split = ExperimentSplit | SegmentSplit;\n\ninterface ApiLoaderBundleOutput {\n modules: {\n browser: (CodeModule | AssetModule)[];\n server: (CodeModule | AssetModule)[];\n };\n components: ComponentMeta[];\n globalGroups: GlobalGroupMeta[];\n projects: ProjectMeta[];\n activeSplits: Split[];\n bundleKey: string | null;\n deferChunksByDefault: boolean;\n disableRootLoadingBoundaryByDefault: boolean;\n redirectUrl?: string;\n}\n\nexport interface LoaderBundleOutput extends ApiLoaderBundleOutput {\n // A map from project ID to the list of component IDs that are not included in the bundle\n // this is used to know which components exist in the project, which allow us to properly\n // handle bundle merging being aware of the deleted components.\n filteredIds: Record<string, string[]>;\n}\n\nexport interface LoaderHtmlOutput {\n html: string;\n}\n\nexport interface CodeModule {\n fileName: string;\n code: string;\n imports: string[];\n type: \"code\";\n}\n\nexport interface AssetModule {\n fileName: string;\n source: string;\n type: \"asset\";\n}\n\nconst VERSION = \"10\";\n\nexport const isBrowser =\n typeof window !== \"undefined\" &&\n window != null &&\n typeof window.document !== \"undefined\";\n\nexport function transformApiLoaderBundleOutput(\n bundle: ApiLoaderBundleOutput\n): LoaderBundleOutput {\n return {\n ...bundle,\n filteredIds: Object.fromEntries(bundle.projects.map((p) => [p.id, []])),\n };\n}\n\nexport class Api {\n private host: string;\n private fetch: typeof globalThis.fetch;\n\n private lastResponse:\n | {\n bundle: LoaderBundleOutput;\n key: string;\n }\n | undefined = undefined;\n\n constructor(\n private opts: {\n projects: { id: string; token: string }[];\n host?: string;\n nativeFetch?: boolean;\n manualRedirect?: boolean;\n }\n ) {\n this.host = opts.host ?? \"https://codegen.quocuy.cloud\";\n this.fetch = (\n opts.nativeFetch && globalThis.fetch ? globalThis.fetch : unfetch\n ).bind(globalThis);\n }\n\n async fetchLoaderData(\n projectIds: string[],\n opts: {\n platform?: \"react\" | \"nextjs\" | \"gatsby\";\n platformOptions?: {\n nextjs?: {\n appDir: boolean;\n };\n };\n preview?: boolean;\n browserOnly?: boolean;\n i18nKeyScheme?: \"content\" | \"hash\" | \"path\";\n i18nTagPrefix?: string;\n skipHead?: boolean;\n }\n ): Promise<LoaderBundleOutput> {\n const { platform, preview } = opts;\n const query = new URLSearchParams([\n [\"platform\", platform ?? \"react\"],\n ...(opts.platformOptions?.nextjs?.appDir\n ? [[\"nextjsAppDir\", \"true\"]]\n : []),\n ...projectIds.map((projectId) => [\"projectId\", projectId]),\n ...(opts.browserOnly ? [[\"browserOnly\", \"true\"]] : []),\n ...(opts.i18nKeyScheme ? [[\"i18nKeyScheme\", opts.i18nKeyScheme]] : []),\n ...(opts.i18nTagPrefix ? [[\"i18nTagPrefix\", opts.i18nTagPrefix]] : []),\n ...(opts.skipHead ? [[\"skipHead\", \"true\"]] : []),\n ]).toString();\n\n const url = `${this.host}/api/v1/loader/code/${\n preview ? \"preview\" : \"published\"\n }?${query}`;\n\n // We only expect a redirect when we're dealing with published mode, as there should be\n // a stable set of versions to be used. As in browser, we could receive a opaque response\n // with a redirect, we don't try to use last response in browser.\n const useLastReponse =\n // We consider that manualRedirect is true by default, only by setting it to false\n // we disable it.\n !(this.opts.manualRedirect === false) && !preview && !isBrowser;\n\n if (useLastReponse) {\n const redirectResp = await this.fetch(url, {\n method: \"GET\",\n headers: this.makeGetHeaders(),\n redirect: \"manual\",\n });\n\n if (redirectResp.status !== 301 && redirectResp.status !== 302) {\n const error = await this.parseJsonResponse(redirectResp);\n throw new Error(\n `Error fetching loader data, a redirect was expected: ${\n error?.error?.message ?? redirectResp.statusText\n }`\n );\n }\n\n const nextLocation = redirectResp.headers.get(\"location\");\n if (!nextLocation) {\n throw new Error(\n `Error fetching loader data, a redirect was expected but no location header was found`\n );\n }\n\n if (this.lastResponse?.key === nextLocation) {\n return this.lastResponse.bundle;\n }\n\n const resp = await this.fetch(`${this.host}${nextLocation}`, {\n method: \"GET\",\n headers: this.makeGetHeaders(),\n });\n\n const json = transformApiLoaderBundleOutput(\n await this.verifyAndParseJsonResponse(resp)\n );\n this.lastResponse = {\n bundle: json,\n key: nextLocation,\n };\n\n return json;\n }\n\n const resp = await this.fetch(url, {\n method: \"GET\",\n headers: this.makeGetHeaders(),\n });\n\n let json = await this.verifyAndParseJsonResponse(resp);\n\n // An Angular polyfill can cause 302 redirects to fail in Safari, due to missing headers.\n // This 200 response with `redirectUrl` is a workaround for specific projects that need it.\n if (json.redirectUrl) {\n const redirectResp = await this.fetch(`${this.host}${json.redirectUrl}`, {\n method: \"GET\",\n headers: this.makeGetHeaders(),\n });\n json = await this.verifyAndParseJsonResponse(redirectResp);\n }\n\n return transformApiLoaderBundleOutput(json);\n }\n\n private async verifyAndParseJsonResponse(\n resp: Response,\n errorText = \"Error fetching loader data\"\n ) {\n if (resp.status >= 400) {\n const error = await this.parseJsonResponse(resp);\n throw new Error(\n `${errorText}: ${error?.error?.message ?? resp.statusText}`\n );\n }\n return (await this.parseJsonResponse(resp)) as ApiLoaderBundleOutput;\n }\n\n private async parseJsonResponse(resp: Response) {\n const text = await resp.text();\n try {\n return JSON.parse(text);\n } catch (err) {\n throw new Error(\n `Error parsing JSON response: ${err}; status: ${resp.status}; response: ${text}`\n );\n }\n }\n\n async fetchHtmlData(opts: {\n projectId: string;\n component: string;\n hydrate?: boolean;\n embedHydrate?: boolean;\n }) {\n const { projectId, component, embedHydrate, hydrate } = opts;\n const query = new URLSearchParams([\n [\"projectId\", projectId],\n [\"component\", component],\n [\"embedHydrate\", embedHydrate ? \"1\" : \"0\"],\n [\"hydrate\", hydrate ? \"1\" : \"0\"],\n ]).toString();\n const resp = await this.fetch(`${this.host}/api/v1/loader/html?${query}`, {\n method: \"GET\",\n headers: this.makeGetHeaders(),\n });\n const json = await resp.json();\n return json as LoaderHtmlOutput;\n }\n\n private makeGetHeaders() {\n return {\n \"x-daouy-loader-version\": VERSION,\n ...this.makeAuthHeaders(),\n };\n }\n\n private makeAuthHeaders() {\n const tokens = this.opts.projects\n .map((p) => `${p.id}:${p.token}`)\n .join(\",\");\n return {\n \"x-daouy-api-project-tokens\": tokens,\n };\n }\n\n getChunksUrl(bundle: LoaderBundleOutput, modules: CodeModule[]) {\n return `${this.host}/api/v1/loader/chunks?bundleKey=${encodeURIComponent(\n bundle.bundleKey ?? \"null\"\n )}&fileName=${encodeURIComponent(\n modules\n .map((m) => m.fileName)\n .sort()\n .join(\",\")\n )}`;\n }\n}\n", "import { Api, CodeModule, isBrowser, LoaderBundleOutput } from \"./api\";\n\nexport interface FetcherOptions {\n projects: {\n id: string;\n version?: string;\n token: string;\n }[];\n cache?: LoaderBundleCache;\n platform?: \"react\" | \"nextjs\" | \"gatsby\";\n platformOptions?: {\n nextjs?: {\n appDir: boolean;\n };\n };\n preview?: boolean;\n host?: string;\n /**\n * @deprecated use i18n.keyScheme instead\n */\n i18nKeyScheme?: \"content\" | \"hash\" | \"path\";\n i18n?: {\n keyScheme: \"content\" | \"hash\" | \"path\";\n tagPrefix?: string;\n };\n skipHead?: boolean;\n nativeFetch?: boolean;\n manualRedirect?: boolean;\n}\n\nexport interface LoaderBundleCache {\n set: (data: LoaderBundleOutput) => Promise<void>;\n get: () => Promise<LoaderBundleOutput>;\n}\n\nexport class DaouyModulesFetcher {\n private api: Api;\n private curFetch: Promise<LoaderBundleOutput> | undefined = undefined;\n constructor(private opts: FetcherOptions) {\n this.api = new Api({\n projects: opts.projects,\n host: opts.host,\n nativeFetch: opts.nativeFetch,\n manualRedirect: opts.manualRedirect,\n });\n }\n\n getChunksUrl(bundle: LoaderBundleOutput, modules: CodeModule[]) {\n return this.api.getChunksUrl(bundle, modules);\n }\n\n async fetchAllData() {\n // getCachedOrFetched uses a cache defined by the user.\n const bundle = await this.getCachedOrFetch();\n\n // For React Server Components (Next.js 13+),\n // we need to pass server modules in LoaderBundleOutput from Server Components to Client Components.\n // We don't want to pass them via normal page props because that will be serialized to the browser.\n // Instead, we pass the bundle (including the server modules) via the Node `global` variable.\n //\n // cacheBundleInNodeServer caches a bundle in the Node server process.\n this.cacheBundleInNodeServer(bundle);\n\n return bundle;\n }\n\n private async getCachedOrFetch() {\n if (this.opts.cache) {\n const cachedData = await this.opts.cache.get();\n if (cachedData) {\n return cachedData;\n }\n }\n if (this.curFetch) {\n return await this.curFetch;\n }\n if (typeof process === \"undefined\" || !process.env?.DAOUY_QUIET) {\n console.debug(\"Daouy: doing a fresh fetch...\");\n }\n const fetchPromise = this.doFetch();\n this.curFetch = fetchPromise;\n try {\n const data = await fetchPromise;\n return data;\n } finally {\n // Reset this.curFetch only if it still holds the original fetch promise\n if (this.curFetch === fetchPromise) {\n this.curFetch = undefined;\n }\n }\n }\n\n private async doFetch() {\n const data = await this.api.fetchLoaderData(\n this.opts.projects.map((p) =>\n p.version ? `${p.id}@${p.version}` : p.id\n ),\n {\n platform: this.opts.platform,\n platformOptions: this.opts.platformOptions,\n preview: this.opts.preview,\n i18nKeyScheme: this.opts.i18n?.keyScheme ?? this.opts.i18nKeyScheme,\n i18nTagPrefix: this.opts.i18n?.tagPrefix,\n browserOnly: isBrowser,\n skipHead: this.opts.skipHead,\n }\n );\n if (this.opts.cache) {\n await this.opts.cache.set(data);\n }\n if (typeof process === \"undefined\" || !process.env?.DAOUY_QUIET) {\n console.debug(\n `Daouy: fetched designs for ${data.projects\n .map((p) => `\"${p.name}\" (${p.id}@${p.version})`)\n .join(\", \")}`\n );\n }\n return data;\n }\n\n private cacheBundleInNodeServer(bundle: LoaderBundleOutput) {\n if (isBrowser) {\n return;\n }\n\n const global = globalThis as GlobalWithBundles;\n if (global.__DAOUY_BUNDLES === undefined) {\n global.__DAOUY_BUNDLES = {};\n }\n global.__DAOUY_BUNDLES[getBundleKey(this.opts)] = bundle;\n }\n}\n\nexport function internal_getCachedBundleInNodeServer(\n opts: FetcherOptions\n): LoaderBundleOutput | undefined {\n if (isBrowser) {\n throw new Error(`Should not be consulting Node server cache in browser`);\n }\n\n const global = globalThis as GlobalWithBundles;\n return global.__DAOUY_BUNDLES?.[getBundleKey(opts)];\n}\n\nfunction getBundleKey({\n host,\n platform,\n i18nKeyScheme,\n preview,\n projects,\n skipHead,\n}: FetcherOptions) {\n return JSON.stringify({\n host,\n platform,\n i18nKeyScheme,\n preview,\n projects,\n skipHead,\n });\n}\n\ninterface GlobalWithBundles {\n __DAOUY_BUNDLES?: { [bundleKey: string]: LoaderBundleOutput };\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,aAAa;AA+IpB,IAAM,UAAU;AAET,IAAM,YACX,OAAO,WAAW,eAClB,UAAU,QACV,OAAO,OAAO,aAAa;AAEtB,SAAS,+BACd,QACoB;AACpB,SAAO,iCACF,SADE;AAAA,IAEL,aAAa,OAAO,YAAY,OAAO,SAAS,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AAAA,EACxE;AACF;AAEO,IAAM,MAAN,MAAU;AAAA,EAWf,YACU,MAMR;AANQ;AARV,SAAQ,eAKQ;AAxKlB;AAkLI,SAAK,QAAO,UAAK,SAAL,YAAa;AACzB,SAAK,SACH,KAAK,eAAe,WAAW,QAAQ,WAAW,QAAQ,SAC1D,KAAK,UAAU;AAAA,EACnB;AAAA,EAEM,gBACJ,YACA,MAa6B;AAAA;AAvMjC;AAwMI,YAAM,EAAE,UAAU,QAAQ,IAAI;AAC9B,YAAM,QAAQ,IAAI,gBAAgB;AAAA,QAChC,CAAC,YAAY,8BAAY,OAAO;AAAA,QAChC,KAAI,gBAAK,oBAAL,mBAAsB,WAAtB,mBAA8B,UAC9B,CAAC,CAAC,gBAAgB,MAAM,CAAC,IACzB,CAAC;AAAA,QACL,GAAG,WAAW,IAAI,CAAC,cAAc,CAAC,aAAa,SAAS,CAAC;AAAA,QACzD,GAAI,KAAK,cAAc,CAAC,CAAC,eAAe,MAAM,CAAC,IAAI,CAAC;AAAA,QACpD,GAAI,KAAK,gBAAgB,CAAC,CAAC,iBAAiB,KAAK,aAAa,CAAC,IAAI,CAAC;AAAA,QACpE,GAAI,KAAK,gBAAgB,CAAC,CAAC,iBAAiB,KAAK,aAAa,CAAC,IAAI,CAAC;AAAA,QACpE,GAAI,KAAK,WAAW,CAAC,CAAC,YAAY,MAAM,CAAC,IAAI,CAAC;AAAA,MAChD,CAAC,EAAE,SAAS;AAEZ,YAAM,MAAM,GAAG,KAAK,2BAClB,UAAU,YAAY,eACpB;AAKJ,YAAM;AAAA;AAAA;AAAA,QAGJ,EAAE,KAAK,KAAK,mBAAmB,UAAU,CAAC,WAAW,CAAC;AAAA;AAExD,UAAI,gBAAgB;AAClB,cAAM,eAAe,MAAM,KAAK,MAAM,KAAK;AAAA,UACzC,QAAQ;AAAA,UACR,SAAS,KAAK,eAAe;AAAA,UAC7B,UAAU;AAAA,QACZ,CAAC;AAED,YAAI,aAAa,WAAW,OAAO,aAAa,WAAW,KAAK;AAC9D,gBAAM,QAAQ,MAAM,KAAK,kBAAkB,YAAY;AACvD,gBAAM,IAAI;AAAA,YACR,yDACE,0CAAO,UAAP,mBAAc,YAAd,YAAyB,aAAa;AAAA,UAE1C;AAAA,QACF;AAEA,cAAM,eAAe,aAAa,QAAQ,IAAI,UAAU;AACxD,YAAI,CAAC,cAAc;AACjB,gBAAM,IAAI;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAEA,cAAI,UAAK,iBAAL,mBAAmB,SAAQ,cAAc;AAC3C,iBAAO,KAAK,aAAa;AAAA,QAC3B;AAEA,cAAMA,QAAO,MAAM,KAAK,MAAM,GAAG,KAAK,OAAO,gBAAgB;AAAA,UAC3D,QAAQ;AAAA,UACR,SAAS,KAAK,eAAe;AAAA,QAC/B,CAAC;AAED,cAAMC,QAAO;AAAA,UACX,MAAM,KAAK,2BAA2BD,KAAI;AAAA,QAC5C;AACA,aAAK,eAAe;AAAA,UAClB,QAAQC;AAAA,UACR,KAAK;AAAA,QACP;AAEA,eAAOA;AAAA,MACT;AAEA,YAAM,OAAO,MAAM,KAAK,MAAM,KAAK;AAAA,QACjC,QAAQ;AAAA,QACR,SAAS,KAAK,eAAe;AAAA,MAC/B,CAAC;AAED,UAAI,OAAO,MAAM,KAAK,2BAA2B,IAAI;AAIrD,UAAI,KAAK,aAAa;AACpB,cAAM,eAAe,MAAM,KAAK,MAAM,GAAG,KAAK,OAAO,KAAK,eAAe;AAAA,UACvE,QAAQ;AAAA,UACR,SAAS,KAAK,eAAe;AAAA,QAC/B,CAAC;AACD,eAAO,MAAM,KAAK,2BAA2B,YAAY;AAAA,MAC3D;AAEA,aAAO,+BAA+B,IAAI;AAAA,IAC5C;AAAA;AAAA,EAEc,2BACZ,MACA,YAAY,8BACZ;AAAA;AAnSJ;AAoSI,UAAI,KAAK,UAAU,KAAK;AACtB,cAAM,QAAQ,MAAM,KAAK,kBAAkB,IAAI;AAC/C,cAAM,IAAI;AAAA,UACR,GAAG,eAAc,0CAAO,UAAP,mBAAc,YAAd,YAAyB,KAAK;AAAA,QACjD;AAAA,MACF;AACA,aAAQ,MAAM,KAAK,kBAAkB,IAAI;AAAA,IAC3C;AAAA;AAAA,EAEc,kBAAkB,MAAgB;AAAA;AAC9C,YAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,UAAI;AACF,eAAO,KAAK,MAAM,IAAI;AAAA,MACxB,SAAS,KAAP;AACA,cAAM,IAAI;AAAA,UACR,gCAAgC,gBAAgB,KAAK,qBAAqB;AAAA,QAC5E;AAAA,MACF;AAAA,IACF;AAAA;AAAA,EAEM,cAAc,MAKjB;AAAA;AACD,YAAM,EAAE,WAAW,WAAW,cAAc,QAAQ,IAAI;AACxD,YAAM,QAAQ,IAAI,gBAAgB;AAAA,QAChC,CAAC,aAAa,SAAS;AAAA,QACvB,CAAC,aAAa,SAAS;AAAA,QACvB,CAAC,gBAAgB,eAAe,MAAM,GAAG;AAAA,QACzC,CAAC,WAAW,UAAU,MAAM,GAAG;AAAA,MACjC,CAAC,EAAE,SAAS;AACZ,YAAM,OAAO,MAAM,KAAK,MAAM,GAAG,KAAK,2BAA2B,SAAS;AAAA,QACxE,QAAQ;AAAA,QACR,SAAS,KAAK,eAAe;AAAA,MAC/B,CAAC;AACD,YAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,aAAO;AAAA,IACT;AAAA;AAAA,EAEQ,iBAAiB;AACvB,WAAO;AAAA,MACL,0BAA0B;AAAA,OACvB,KAAK,gBAAgB;AAAA,EAE5B;AAAA,EAEQ,kBAAkB;AACxB,UAAM,SAAS,KAAK,KAAK,SACtB,IAAI,CAAC,MAAM,GAAG,EAAE,MAAM,EAAE,OAAO,EAC/B,KAAK,GAAG;AACX,WAAO;AAAA,MACL,8BAA8B;AAAA,IAChC;AAAA,EACF;AAAA,EAEA,aAAa,QAA4B,SAAuB;AA7VlE;AA8VI,WAAO,GAAG,KAAK,uCAAuC;AAAA,OACpD,YAAO,cAAP,YAAoB;AAAA,IACtB,cAAc;AAAA,MACZ,QACG,IAAI,CAAC,MAAM,EAAE,QAAQ,EACrB,KAAK,EACL,KAAK,GAAG;AAAA,IACb;AAAA,EACF;AACF;;;ACpUO,IAAM,sBAAN,MAA0B;AAAA,EAG/B,YAAoB,MAAsB;AAAtB;AADpB,SAAQ,WAAoD;AAE1D,SAAK,MAAM,IAAI,IAAI;AAAA,MACjB,UAAU,KAAK;AAAA,MACf,MAAM,KAAK;AAAA,MACX,aAAa,KAAK;AAAA,MAClB,gBAAgB,KAAK;AAAA,IACvB,CAAC;AAAA,EACH;AAAA,EAEA,aAAa,QAA4B,SAAuB;AAC9D,WAAO,KAAK,IAAI,aAAa,QAAQ,OAAO;AAAA,EAC9C;AAAA,EAEM,eAAe;AAAA;AAEnB,YAAM,SAAS,MAAM,KAAK,iBAAiB;AAQ3C,WAAK,wBAAwB,MAAM;AAEnC,aAAO;AAAA,IACT;AAAA;AAAA,EAEc,mBAAmB;AAAA;AAlEnC;AAmEI,UAAI,KAAK,KAAK,OAAO;AACnB,cAAM,aAAa,MAAM,KAAK,KAAK,MAAM,IAAI;AAC7C,YAAI,YAAY;AACd,iBAAO;AAAA,QACT;AAAA,MACF;AACA,UAAI,KAAK,UAAU;AACjB,eAAO,MAAM,KAAK;AAAA,MACpB;AACA,UAAI,OAAO,YAAY,eAAe,GAAC,aAAQ,QAAR,mBAAa,cAAa;AAC/D,gBAAQ,MAAM,+BAA+B;AAAA,MAC/C;AACA,YAAM,eAAe,KAAK,QAAQ;AAClC,WAAK,WAAW;AAChB,UAAI;AACF,cAAM,OAAO,MAAM;AACnB,eAAO;AAAA,MACT,UAAE;AAEA,YAAI,KAAK,aAAa,cAAc;AAClC,eAAK,WAAW;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAAA;AAAA,EAEc,UAAU;AAAA;AA5F1B;AA6FI,YAAM,OAAO,MAAM,KAAK,IAAI;AAAA,QAC1B,KAAK,KAAK,SAAS;AAAA,UAAI,CAAC,MACtB,EAAE,UAAU,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE;AAAA,QACzC;AAAA,QACA;AAAA,UACE,UAAU,KAAK,KAAK;AAAA,UACpB,iBAAiB,KAAK,KAAK;AAAA,UAC3B,SAAS,KAAK,KAAK;AAAA,UACnB,gBAAe,gBAAK,KAAK,SAAV,mBAAgB,cAAhB,YAA6B,KAAK,KAAK;AAAA,UACtD,gBAAe,UAAK,KAAK,SAAV,mBAAgB;AAAA,UAC/B,aAAa;AAAA,UACb,UAAU,KAAK,KAAK;AAAA,QACtB;AAAA,MACF;AACA,UAAI,KAAK,KAAK,OAAO;AACnB,cAAM,KAAK,KAAK,MAAM,IAAI,IAAI;AAAA,MAChC;AACA,UAAI,OAAO,YAAY,eAAe,GAAC,aAAQ,QAAR,mBAAa,cAAa;AAC/D,gBAAQ;AAAA,UACN,8BAA8B,KAAK,SAChC,IAAI,CAAC,MAAM,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAC/C,KAAK,IAAI;AAAA,QACd;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA;AAAA,EAEQ,wBAAwB,QAA4B;AAC1D,QAAI,WAAW;AACb;AAAA,IACF;AAEA,UAAM,SAAS;AACf,QAAI,OAAO,oBAAoB,QAAW;AACxC,aAAO,kBAAkB,CAAC;AAAA,IAC5B;AACA,WAAO,gBAAgB,aAAa,KAAK,IAAI,CAAC,IAAI;AAAA,EACpD;AACF;AAEO,SAAS,qCACd,MACgC;AAvIlC;AAwIE,MAAI,WAAW;AACb,UAAM,IAAI,MAAM,uDAAuD;AAAA,EACzE;AAEA,QAAM,SAAS;AACf,UAAO,YAAO,oBAAP,mBAAyB,aAAa,IAAI;AACnD;AAEA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAmB;AACjB,SAAO,KAAK,UAAU;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACH;",
6
+ "names": ["resp", "json"]
7
+ }
package/dist/index.js ADDED
@@ -0,0 +1,336 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __defProps = Object.defineProperties;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
9
+ var __getProtoOf = Object.getPrototypeOf;
10
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
11
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
12
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
13
+ var __spreadValues = (a, b) => {
14
+ for (var prop in b || (b = {}))
15
+ if (__hasOwnProp.call(b, prop))
16
+ __defNormalProp(a, prop, b[prop]);
17
+ if (__getOwnPropSymbols)
18
+ for (var prop of __getOwnPropSymbols(b)) {
19
+ if (__propIsEnum.call(b, prop))
20
+ __defNormalProp(a, prop, b[prop]);
21
+ }
22
+ return a;
23
+ };
24
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
25
+ var __export = (target, all) => {
26
+ for (var name in all)
27
+ __defProp(target, name, { get: all[name], enumerable: true });
28
+ };
29
+ var __copyProps = (to, from, except, desc) => {
30
+ if (from && typeof from === "object" || typeof from === "function") {
31
+ for (let key of __getOwnPropNames(from))
32
+ if (!__hasOwnProp.call(to, key) && key !== except)
33
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
34
+ }
35
+ return to;
36
+ };
37
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
38
+ // If the importer is in node compatibility mode or this is not an ESM
39
+ // file that has been converted to a CommonJS file using a Babel-
40
+ // compatible transform (i.e. "__esModule" has not been set), then set
41
+ // "default" to the CommonJS "module.exports" for node compatibility.
42
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
43
+ mod
44
+ ));
45
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
46
+ var __async = (__this, __arguments, generator) => {
47
+ return new Promise((resolve, reject) => {
48
+ var fulfilled = (value) => {
49
+ try {
50
+ step(generator.next(value));
51
+ } catch (e) {
52
+ reject(e);
53
+ }
54
+ };
55
+ var rejected = (value) => {
56
+ try {
57
+ step(generator.throw(value));
58
+ } catch (e) {
59
+ reject(e);
60
+ }
61
+ };
62
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
63
+ step((generator = generator.apply(__this, __arguments)).next());
64
+ });
65
+ };
66
+
67
+ // src/index.ts
68
+ var src_exports = {};
69
+ __export(src_exports, {
70
+ Api: () => Api,
71
+ DaouyModulesFetcher: () => DaouyModulesFetcher,
72
+ internal_getCachedBundleInNodeServer: () => internal_getCachedBundleInNodeServer
73
+ });
74
+ module.exports = __toCommonJS(src_exports);
75
+
76
+ // src/api.ts
77
+ var import_isomorphic_unfetch = __toESM(require("@daouy/isomorphic-unfetch"));
78
+ var VERSION = "10";
79
+ var isBrowser = typeof window !== "undefined" && window != null && typeof window.document !== "undefined";
80
+ function transformApiLoaderBundleOutput(bundle) {
81
+ return __spreadProps(__spreadValues({}, bundle), {
82
+ filteredIds: Object.fromEntries(bundle.projects.map((p) => [p.id, []]))
83
+ });
84
+ }
85
+ var Api = class {
86
+ constructor(opts) {
87
+ this.opts = opts;
88
+ this.lastResponse = void 0;
89
+ var _a;
90
+ this.host = (_a = opts.host) != null ? _a : "https://codegen.quocuy.cloud";
91
+ this.fetch = (opts.nativeFetch && globalThis.fetch ? globalThis.fetch : import_isomorphic_unfetch.default).bind(globalThis);
92
+ }
93
+ fetchLoaderData(projectIds, opts) {
94
+ return __async(this, null, function* () {
95
+ var _a, _b, _c, _d, _e;
96
+ const { platform, preview } = opts;
97
+ const query = new URLSearchParams([
98
+ ["platform", platform != null ? platform : "react"],
99
+ ...((_b = (_a = opts.platformOptions) == null ? void 0 : _a.nextjs) == null ? void 0 : _b.appDir) ? [["nextjsAppDir", "true"]] : [],
100
+ ...projectIds.map((projectId) => ["projectId", projectId]),
101
+ ...opts.browserOnly ? [["browserOnly", "true"]] : [],
102
+ ...opts.i18nKeyScheme ? [["i18nKeyScheme", opts.i18nKeyScheme]] : [],
103
+ ...opts.i18nTagPrefix ? [["i18nTagPrefix", opts.i18nTagPrefix]] : [],
104
+ ...opts.skipHead ? [["skipHead", "true"]] : []
105
+ ]).toString();
106
+ const url = `${this.host}/api/v1/loader/code/${preview ? "preview" : "published"}?${query}`;
107
+ const useLastReponse = (
108
+ // We consider that manualRedirect is true by default, only by setting it to false
109
+ // we disable it.
110
+ !(this.opts.manualRedirect === false) && !preview && !isBrowser
111
+ );
112
+ if (useLastReponse) {
113
+ const redirectResp = yield this.fetch(url, {
114
+ method: "GET",
115
+ headers: this.makeGetHeaders(),
116
+ redirect: "manual"
117
+ });
118
+ if (redirectResp.status !== 301 && redirectResp.status !== 302) {
119
+ const error = yield this.parseJsonResponse(redirectResp);
120
+ throw new Error(
121
+ `Error fetching loader data, a redirect was expected: ${(_d = (_c = error == null ? void 0 : error.error) == null ? void 0 : _c.message) != null ? _d : redirectResp.statusText}`
122
+ );
123
+ }
124
+ const nextLocation = redirectResp.headers.get("location");
125
+ if (!nextLocation) {
126
+ throw new Error(
127
+ `Error fetching loader data, a redirect was expected but no location header was found`
128
+ );
129
+ }
130
+ if (((_e = this.lastResponse) == null ? void 0 : _e.key) === nextLocation) {
131
+ return this.lastResponse.bundle;
132
+ }
133
+ const resp2 = yield this.fetch(`${this.host}${nextLocation}`, {
134
+ method: "GET",
135
+ headers: this.makeGetHeaders()
136
+ });
137
+ const json2 = transformApiLoaderBundleOutput(
138
+ yield this.verifyAndParseJsonResponse(resp2)
139
+ );
140
+ this.lastResponse = {
141
+ bundle: json2,
142
+ key: nextLocation
143
+ };
144
+ return json2;
145
+ }
146
+ const resp = yield this.fetch(url, {
147
+ method: "GET",
148
+ headers: this.makeGetHeaders()
149
+ });
150
+ let json = yield this.verifyAndParseJsonResponse(resp);
151
+ if (json.redirectUrl) {
152
+ const redirectResp = yield this.fetch(`${this.host}${json.redirectUrl}`, {
153
+ method: "GET",
154
+ headers: this.makeGetHeaders()
155
+ });
156
+ json = yield this.verifyAndParseJsonResponse(redirectResp);
157
+ }
158
+ return transformApiLoaderBundleOutput(json);
159
+ });
160
+ }
161
+ verifyAndParseJsonResponse(resp, errorText = "Error fetching loader data") {
162
+ return __async(this, null, function* () {
163
+ var _a, _b;
164
+ if (resp.status >= 400) {
165
+ const error = yield this.parseJsonResponse(resp);
166
+ throw new Error(
167
+ `${errorText}: ${(_b = (_a = error == null ? void 0 : error.error) == null ? void 0 : _a.message) != null ? _b : resp.statusText}`
168
+ );
169
+ }
170
+ return yield this.parseJsonResponse(resp);
171
+ });
172
+ }
173
+ parseJsonResponse(resp) {
174
+ return __async(this, null, function* () {
175
+ const text = yield resp.text();
176
+ try {
177
+ return JSON.parse(text);
178
+ } catch (err) {
179
+ throw new Error(
180
+ `Error parsing JSON response: ${err}; status: ${resp.status}; response: ${text}`
181
+ );
182
+ }
183
+ });
184
+ }
185
+ fetchHtmlData(opts) {
186
+ return __async(this, null, function* () {
187
+ const { projectId, component, embedHydrate, hydrate } = opts;
188
+ const query = new URLSearchParams([
189
+ ["projectId", projectId],
190
+ ["component", component],
191
+ ["embedHydrate", embedHydrate ? "1" : "0"],
192
+ ["hydrate", hydrate ? "1" : "0"]
193
+ ]).toString();
194
+ const resp = yield this.fetch(`${this.host}/api/v1/loader/html?${query}`, {
195
+ method: "GET",
196
+ headers: this.makeGetHeaders()
197
+ });
198
+ const json = yield resp.json();
199
+ return json;
200
+ });
201
+ }
202
+ makeGetHeaders() {
203
+ return __spreadValues({
204
+ "x-daouy-loader-version": VERSION
205
+ }, this.makeAuthHeaders());
206
+ }
207
+ makeAuthHeaders() {
208
+ const tokens = this.opts.projects.map((p) => `${p.id}:${p.token}`).join(",");
209
+ return {
210
+ "x-daouy-api-project-tokens": tokens
211
+ };
212
+ }
213
+ getChunksUrl(bundle, modules) {
214
+ var _a;
215
+ return `${this.host}/api/v1/loader/chunks?bundleKey=${encodeURIComponent(
216
+ (_a = bundle.bundleKey) != null ? _a : "null"
217
+ )}&fileName=${encodeURIComponent(
218
+ modules.map((m) => m.fileName).sort().join(",")
219
+ )}`;
220
+ }
221
+ };
222
+
223
+ // src/fetcher.ts
224
+ var DaouyModulesFetcher = class {
225
+ constructor(opts) {
226
+ this.opts = opts;
227
+ this.curFetch = void 0;
228
+ this.api = new Api({
229
+ projects: opts.projects,
230
+ host: opts.host,
231
+ nativeFetch: opts.nativeFetch,
232
+ manualRedirect: opts.manualRedirect
233
+ });
234
+ }
235
+ getChunksUrl(bundle, modules) {
236
+ return this.api.getChunksUrl(bundle, modules);
237
+ }
238
+ fetchAllData() {
239
+ return __async(this, null, function* () {
240
+ const bundle = yield this.getCachedOrFetch();
241
+ this.cacheBundleInNodeServer(bundle);
242
+ return bundle;
243
+ });
244
+ }
245
+ getCachedOrFetch() {
246
+ return __async(this, null, function* () {
247
+ var _a;
248
+ if (this.opts.cache) {
249
+ const cachedData = yield this.opts.cache.get();
250
+ if (cachedData) {
251
+ return cachedData;
252
+ }
253
+ }
254
+ if (this.curFetch) {
255
+ return yield this.curFetch;
256
+ }
257
+ if (typeof process === "undefined" || !((_a = process.env) == null ? void 0 : _a.DAOUY_QUIET)) {
258
+ console.debug("Daouy: doing a fresh fetch...");
259
+ }
260
+ const fetchPromise = this.doFetch();
261
+ this.curFetch = fetchPromise;
262
+ try {
263
+ const data = yield fetchPromise;
264
+ return data;
265
+ } finally {
266
+ if (this.curFetch === fetchPromise) {
267
+ this.curFetch = void 0;
268
+ }
269
+ }
270
+ });
271
+ }
272
+ doFetch() {
273
+ return __async(this, null, function* () {
274
+ var _a, _b, _c, _d;
275
+ const data = yield this.api.fetchLoaderData(
276
+ this.opts.projects.map(
277
+ (p) => p.version ? `${p.id}@${p.version}` : p.id
278
+ ),
279
+ {
280
+ platform: this.opts.platform,
281
+ platformOptions: this.opts.platformOptions,
282
+ preview: this.opts.preview,
283
+ i18nKeyScheme: (_b = (_a = this.opts.i18n) == null ? void 0 : _a.keyScheme) != null ? _b : this.opts.i18nKeyScheme,
284
+ i18nTagPrefix: (_c = this.opts.i18n) == null ? void 0 : _c.tagPrefix,
285
+ browserOnly: isBrowser,
286
+ skipHead: this.opts.skipHead
287
+ }
288
+ );
289
+ if (this.opts.cache) {
290
+ yield this.opts.cache.set(data);
291
+ }
292
+ if (typeof process === "undefined" || !((_d = process.env) == null ? void 0 : _d.DAOUY_QUIET)) {
293
+ console.debug(
294
+ `Daouy: fetched designs for ${data.projects.map((p) => `"${p.name}" (${p.id}@${p.version})`).join(", ")}`
295
+ );
296
+ }
297
+ return data;
298
+ });
299
+ }
300
+ cacheBundleInNodeServer(bundle) {
301
+ if (isBrowser) {
302
+ return;
303
+ }
304
+ const global = globalThis;
305
+ if (global.__DAOUY_BUNDLES === void 0) {
306
+ global.__DAOUY_BUNDLES = {};
307
+ }
308
+ global.__DAOUY_BUNDLES[getBundleKey(this.opts)] = bundle;
309
+ }
310
+ };
311
+ function internal_getCachedBundleInNodeServer(opts) {
312
+ var _a;
313
+ if (isBrowser) {
314
+ throw new Error(`Should not be consulting Node server cache in browser`);
315
+ }
316
+ const global = globalThis;
317
+ return (_a = global.__DAOUY_BUNDLES) == null ? void 0 : _a[getBundleKey(opts)];
318
+ }
319
+ function getBundleKey({
320
+ host,
321
+ platform,
322
+ i18nKeyScheme,
323
+ preview,
324
+ projects,
325
+ skipHead
326
+ }) {
327
+ return JSON.stringify({
328
+ host,
329
+ platform,
330
+ i18nKeyScheme,
331
+ preview,
332
+ projects,
333
+ skipHead
334
+ });
335
+ }
336
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts", "../src/api.ts", "../src/fetcher.ts"],
4
+ "sourcesContent": ["export type {\n AssetModule,\n CodeModule,\n ComponentMeta,\n ExperimentSlice,\n FontMeta,\n GlobalGroupMeta,\n LoaderBundleOutput,\n LoaderHtmlOutput,\n PageMeta,\n PageMetadata,\n ProjectMeta,\n SegmentSlice,\n Split,\n} from \"./api\";\nexport { Api } from \"./api\";\nexport type { FetcherOptions, LoaderBundleCache } from \"./fetcher\";\nexport {\n internal_getCachedBundleInNodeServer,\n DaouyModulesFetcher,\n} from \"./fetcher\";\n", "import unfetch from \"@daouy/isomorphic-unfetch\";\n\nexport interface ComponentMeta {\n id: string;\n usedComponents: string[];\n projectId: string;\n name: string;\n displayName: string;\n cssFile: string;\n path: string | undefined;\n isPage: boolean;\n plumeType?: string;\n entry: string;\n isCode: boolean;\n isGlobalContextProvider: boolean;\n pageMetadata?: PageMetadata;\n metadata?: Record<string, string>;\n serverQueriesExecFuncFileName?: string;\n generateMetadataFuncFileName?: string;\n}\n\nexport interface PageMeta extends ComponentMeta {\n isPage: true;\n path: string;\n plumeType: never;\n pageMetadata: PageMetadata;\n}\n\nexport interface PageMetadata {\n path: string;\n title?: string | null;\n description?: string | null;\n openGraphImageUrl?: string | null;\n canonical?: string | null;\n}\n\nexport interface GlobalGroupMeta {\n id: string;\n projectId: string;\n name: string;\n type: string;\n contextFile: string;\n useName: string;\n}\n\n// Keep in sync with platform/wab ProjectMeta\nexport interface ProjectMeta {\n id: string;\n teamId?: string;\n indirect: boolean;\n name: string;\n version: string;\n remoteFonts: FontMeta[];\n hasStyleTokenOverrides: boolean;\n styleTokensProviderFileName: string;\n globalContextsProviderFileName: string;\n}\n\nexport interface FontMeta {\n url: string;\n}\n\ninterface GlobalVariantSplitContent {\n type: \"global-variant\";\n projectId: string;\n group: string;\n variant: string;\n}\n\ninterface Slice {\n id: string;\n contents: GlobalVariantSplitContent[];\n externalId?: string;\n}\n\nexport interface ExperimentSlice extends Slice {\n prob: number;\n}\n\nexport interface SegmentSlice extends Slice {\n cond: any;\n}\n\ninterface BareSplit {\n id: string;\n projectId: string;\n name: string;\n externalId?: string;\n description?: string;\n pagesPaths: string[];\n}\n\nexport interface ExperimentSplit extends BareSplit {\n type: \"experiment\";\n slices: ExperimentSlice[];\n}\n\nexport interface SegmentSplit extends BareSplit {\n type: \"segment\";\n slices: SegmentSlice[];\n}\n\nexport type Split = ExperimentSplit | SegmentSplit;\n\ninterface ApiLoaderBundleOutput {\n modules: {\n browser: (CodeModule | AssetModule)[];\n server: (CodeModule | AssetModule)[];\n };\n components: ComponentMeta[];\n globalGroups: GlobalGroupMeta[];\n projects: ProjectMeta[];\n activeSplits: Split[];\n bundleKey: string | null;\n deferChunksByDefault: boolean;\n disableRootLoadingBoundaryByDefault: boolean;\n redirectUrl?: string;\n}\n\nexport interface LoaderBundleOutput extends ApiLoaderBundleOutput {\n // A map from project ID to the list of component IDs that are not included in the bundle\n // this is used to know which components exist in the project, which allow us to properly\n // handle bundle merging being aware of the deleted components.\n filteredIds: Record<string, string[]>;\n}\n\nexport interface LoaderHtmlOutput {\n html: string;\n}\n\nexport interface CodeModule {\n fileName: string;\n code: string;\n imports: string[];\n type: \"code\";\n}\n\nexport interface AssetModule {\n fileName: string;\n source: string;\n type: \"asset\";\n}\n\nconst VERSION = \"10\";\n\nexport const isBrowser =\n typeof window !== \"undefined\" &&\n window != null &&\n typeof window.document !== \"undefined\";\n\nexport function transformApiLoaderBundleOutput(\n bundle: ApiLoaderBundleOutput\n): LoaderBundleOutput {\n return {\n ...bundle,\n filteredIds: Object.fromEntries(bundle.projects.map((p) => [p.id, []])),\n };\n}\n\nexport class Api {\n private host: string;\n private fetch: typeof globalThis.fetch;\n\n private lastResponse:\n | {\n bundle: LoaderBundleOutput;\n key: string;\n }\n | undefined = undefined;\n\n constructor(\n private opts: {\n projects: { id: string; token: string }[];\n host?: string;\n nativeFetch?: boolean;\n manualRedirect?: boolean;\n }\n ) {\n this.host = opts.host ?? \"https://codegen.quocuy.cloud\";\n this.fetch = (\n opts.nativeFetch && globalThis.fetch ? globalThis.fetch : unfetch\n ).bind(globalThis);\n }\n\n async fetchLoaderData(\n projectIds: string[],\n opts: {\n platform?: \"react\" | \"nextjs\" | \"gatsby\";\n platformOptions?: {\n nextjs?: {\n appDir: boolean;\n };\n };\n preview?: boolean;\n browserOnly?: boolean;\n i18nKeyScheme?: \"content\" | \"hash\" | \"path\";\n i18nTagPrefix?: string;\n skipHead?: boolean;\n }\n ): Promise<LoaderBundleOutput> {\n const { platform, preview } = opts;\n const query = new URLSearchParams([\n [\"platform\", platform ?? \"react\"],\n ...(opts.platformOptions?.nextjs?.appDir\n ? [[\"nextjsAppDir\", \"true\"]]\n : []),\n ...projectIds.map((projectId) => [\"projectId\", projectId]),\n ...(opts.browserOnly ? [[\"browserOnly\", \"true\"]] : []),\n ...(opts.i18nKeyScheme ? [[\"i18nKeyScheme\", opts.i18nKeyScheme]] : []),\n ...(opts.i18nTagPrefix ? [[\"i18nTagPrefix\", opts.i18nTagPrefix]] : []),\n ...(opts.skipHead ? [[\"skipHead\", \"true\"]] : []),\n ]).toString();\n\n const url = `${this.host}/api/v1/loader/code/${\n preview ? \"preview\" : \"published\"\n }?${query}`;\n\n // We only expect a redirect when we're dealing with published mode, as there should be\n // a stable set of versions to be used. As in browser, we could receive a opaque response\n // with a redirect, we don't try to use last response in browser.\n const useLastReponse =\n // We consider that manualRedirect is true by default, only by setting it to false\n // we disable it.\n !(this.opts.manualRedirect === false) && !preview && !isBrowser;\n\n if (useLastReponse) {\n const redirectResp = await this.fetch(url, {\n method: \"GET\",\n headers: this.makeGetHeaders(),\n redirect: \"manual\",\n });\n\n if (redirectResp.status !== 301 && redirectResp.status !== 302) {\n const error = await this.parseJsonResponse(redirectResp);\n throw new Error(\n `Error fetching loader data, a redirect was expected: ${\n error?.error?.message ?? redirectResp.statusText\n }`\n );\n }\n\n const nextLocation = redirectResp.headers.get(\"location\");\n if (!nextLocation) {\n throw new Error(\n `Error fetching loader data, a redirect was expected but no location header was found`\n );\n }\n\n if (this.lastResponse?.key === nextLocation) {\n return this.lastResponse.bundle;\n }\n\n const resp = await this.fetch(`${this.host}${nextLocation}`, {\n method: \"GET\",\n headers: this.makeGetHeaders(),\n });\n\n const json = transformApiLoaderBundleOutput(\n await this.verifyAndParseJsonResponse(resp)\n );\n this.lastResponse = {\n bundle: json,\n key: nextLocation,\n };\n\n return json;\n }\n\n const resp = await this.fetch(url, {\n method: \"GET\",\n headers: this.makeGetHeaders(),\n });\n\n let json = await this.verifyAndParseJsonResponse(resp);\n\n // An Angular polyfill can cause 302 redirects to fail in Safari, due to missing headers.\n // This 200 response with `redirectUrl` is a workaround for specific projects that need it.\n if (json.redirectUrl) {\n const redirectResp = await this.fetch(`${this.host}${json.redirectUrl}`, {\n method: \"GET\",\n headers: this.makeGetHeaders(),\n });\n json = await this.verifyAndParseJsonResponse(redirectResp);\n }\n\n return transformApiLoaderBundleOutput(json);\n }\n\n private async verifyAndParseJsonResponse(\n resp: Response,\n errorText = \"Error fetching loader data\"\n ) {\n if (resp.status >= 400) {\n const error = await this.parseJsonResponse(resp);\n throw new Error(\n `${errorText}: ${error?.error?.message ?? resp.statusText}`\n );\n }\n return (await this.parseJsonResponse(resp)) as ApiLoaderBundleOutput;\n }\n\n private async parseJsonResponse(resp: Response) {\n const text = await resp.text();\n try {\n return JSON.parse(text);\n } catch (err) {\n throw new Error(\n `Error parsing JSON response: ${err}; status: ${resp.status}; response: ${text}`\n );\n }\n }\n\n async fetchHtmlData(opts: {\n projectId: string;\n component: string;\n hydrate?: boolean;\n embedHydrate?: boolean;\n }) {\n const { projectId, component, embedHydrate, hydrate } = opts;\n const query = new URLSearchParams([\n [\"projectId\", projectId],\n [\"component\", component],\n [\"embedHydrate\", embedHydrate ? \"1\" : \"0\"],\n [\"hydrate\", hydrate ? \"1\" : \"0\"],\n ]).toString();\n const resp = await this.fetch(`${this.host}/api/v1/loader/html?${query}`, {\n method: \"GET\",\n headers: this.makeGetHeaders(),\n });\n const json = await resp.json();\n return json as LoaderHtmlOutput;\n }\n\n private makeGetHeaders() {\n return {\n \"x-daouy-loader-version\": VERSION,\n ...this.makeAuthHeaders(),\n };\n }\n\n private makeAuthHeaders() {\n const tokens = this.opts.projects\n .map((p) => `${p.id}:${p.token}`)\n .join(\",\");\n return {\n \"x-daouy-api-project-tokens\": tokens,\n };\n }\n\n getChunksUrl(bundle: LoaderBundleOutput, modules: CodeModule[]) {\n return `${this.host}/api/v1/loader/chunks?bundleKey=${encodeURIComponent(\n bundle.bundleKey ?? \"null\"\n )}&fileName=${encodeURIComponent(\n modules\n .map((m) => m.fileName)\n .sort()\n .join(\",\")\n )}`;\n }\n}\n", "import { Api, CodeModule, isBrowser, LoaderBundleOutput } from \"./api\";\n\nexport interface FetcherOptions {\n projects: {\n id: string;\n version?: string;\n token: string;\n }[];\n cache?: LoaderBundleCache;\n platform?: \"react\" | \"nextjs\" | \"gatsby\";\n platformOptions?: {\n nextjs?: {\n appDir: boolean;\n };\n };\n preview?: boolean;\n host?: string;\n /**\n * @deprecated use i18n.keyScheme instead\n */\n i18nKeyScheme?: \"content\" | \"hash\" | \"path\";\n i18n?: {\n keyScheme: \"content\" | \"hash\" | \"path\";\n tagPrefix?: string;\n };\n skipHead?: boolean;\n nativeFetch?: boolean;\n manualRedirect?: boolean;\n}\n\nexport interface LoaderBundleCache {\n set: (data: LoaderBundleOutput) => Promise<void>;\n get: () => Promise<LoaderBundleOutput>;\n}\n\nexport class DaouyModulesFetcher {\n private api: Api;\n private curFetch: Promise<LoaderBundleOutput> | undefined = undefined;\n constructor(private opts: FetcherOptions) {\n this.api = new Api({\n projects: opts.projects,\n host: opts.host,\n nativeFetch: opts.nativeFetch,\n manualRedirect: opts.manualRedirect,\n });\n }\n\n getChunksUrl(bundle: LoaderBundleOutput, modules: CodeModule[]) {\n return this.api.getChunksUrl(bundle, modules);\n }\n\n async fetchAllData() {\n // getCachedOrFetched uses a cache defined by the user.\n const bundle = await this.getCachedOrFetch();\n\n // For React Server Components (Next.js 13+),\n // we need to pass server modules in LoaderBundleOutput from Server Components to Client Components.\n // We don't want to pass them via normal page props because that will be serialized to the browser.\n // Instead, we pass the bundle (including the server modules) via the Node `global` variable.\n //\n // cacheBundleInNodeServer caches a bundle in the Node server process.\n this.cacheBundleInNodeServer(bundle);\n\n return bundle;\n }\n\n private async getCachedOrFetch() {\n if (this.opts.cache) {\n const cachedData = await this.opts.cache.get();\n if (cachedData) {\n return cachedData;\n }\n }\n if (this.curFetch) {\n return await this.curFetch;\n }\n if (typeof process === \"undefined\" || !process.env?.DAOUY_QUIET) {\n console.debug(\"Daouy: doing a fresh fetch...\");\n }\n const fetchPromise = this.doFetch();\n this.curFetch = fetchPromise;\n try {\n const data = await fetchPromise;\n return data;\n } finally {\n // Reset this.curFetch only if it still holds the original fetch promise\n if (this.curFetch === fetchPromise) {\n this.curFetch = undefined;\n }\n }\n }\n\n private async doFetch() {\n const data = await this.api.fetchLoaderData(\n this.opts.projects.map((p) =>\n p.version ? `${p.id}@${p.version}` : p.id\n ),\n {\n platform: this.opts.platform,\n platformOptions: this.opts.platformOptions,\n preview: this.opts.preview,\n i18nKeyScheme: this.opts.i18n?.keyScheme ?? this.opts.i18nKeyScheme,\n i18nTagPrefix: this.opts.i18n?.tagPrefix,\n browserOnly: isBrowser,\n skipHead: this.opts.skipHead,\n }\n );\n if (this.opts.cache) {\n await this.opts.cache.set(data);\n }\n if (typeof process === \"undefined\" || !process.env?.DAOUY_QUIET) {\n console.debug(\n `Daouy: fetched designs for ${data.projects\n .map((p) => `\"${p.name}\" (${p.id}@${p.version})`)\n .join(\", \")}`\n );\n }\n return data;\n }\n\n private cacheBundleInNodeServer(bundle: LoaderBundleOutput) {\n if (isBrowser) {\n return;\n }\n\n const global = globalThis as GlobalWithBundles;\n if (global.__DAOUY_BUNDLES === undefined) {\n global.__DAOUY_BUNDLES = {};\n }\n global.__DAOUY_BUNDLES[getBundleKey(this.opts)] = bundle;\n }\n}\n\nexport function internal_getCachedBundleInNodeServer(\n opts: FetcherOptions\n): LoaderBundleOutput | undefined {\n if (isBrowser) {\n throw new Error(`Should not be consulting Node server cache in browser`);\n }\n\n const global = globalThis as GlobalWithBundles;\n return global.__DAOUY_BUNDLES?.[getBundleKey(opts)];\n}\n\nfunction getBundleKey({\n host,\n platform,\n i18nKeyScheme,\n preview,\n projects,\n skipHead,\n}: FetcherOptions) {\n return JSON.stringify({\n host,\n platform,\n i18nKeyScheme,\n preview,\n projects,\n skipHead,\n });\n}\n\ninterface GlobalWithBundles {\n __DAOUY_BUNDLES?: { [bundleKey: string]: LoaderBundleOutput };\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["unfetch", "resp", "json"]
7
+ }
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "version": "1.0.58",
3
+ "license": "MIT",
4
+ "types": "./dist/index.d.ts",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.esm.js",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.esm.js",
11
+ "require": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "engines": {
18
+ "node": ">=10"
19
+ },
20
+ "scripts": {
21
+ "build": "yarn build:types && yarn build:index",
22
+ "build:types": "yarn tsc",
23
+ "build:index": "node ../../build.mjs ./src/index.ts",
24
+ "yalcp": "yalc publish --push",
25
+ "test": "TEST_CWD=`pwd` yarn --cwd=../.. test",
26
+ "lint": "eslint",
27
+ "prepublishOnly": "npm run build",
28
+ "postpublish": "bash ../../scripts/publish-api-doc-model.sh",
29
+ "size": "size-limit",
30
+ "analyze": "size-limit --why"
31
+ },
32
+ "name": "@daouy/loader-fetcher",
33
+ "author": "Chung Wu",
34
+ "size-limit": [
35
+ {
36
+ "path": "dist/index.js",
37
+ "limit": "10 KB"
38
+ }
39
+ ],
40
+ "dependencies": {
41
+ "@daouy/isomorphic-unfetch": "^1.0.3"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^20.8.9",
45
+ "typescript": "^5.2.2"
46
+ },
47
+ "publishConfig": {
48
+ "access": "public"
49
+ },
50
+ "gitHead": "fa53f7d79f0e26d8b061102fda0c06788da6f8a7"
51
+ }