@blocklet/pages-kit-inner-components 0.7.4 → 0.7.6

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.
@@ -0,0 +1,2013 @@
1
+ import { d as Je, l as p, m as lt, b as pt, I as ut, c as dt } from "./components-D4ywfyMi.js";
2
+ import { getYjsValue as J, syncedStore as ft } from "@syncedstore/core";
3
+ import * as F from "yjs";
4
+ import { setPageDataSource as mt } from "@blocklet/pages-kit/utils/data-source";
5
+ import { getRouteMetaDataByOptionIds as gt, generateParamCombinations as be } from "@blocklet/pages-kit/utils/route";
6
+ import Ae from "lodash/cloneDeep";
7
+ import { DataTypes as P, Sequelize as ht, Model as Ee, Op as Z } from "sequelize";
8
+ import "sqlite3";
9
+ import E from "@blocklet/sdk/lib/config";
10
+ import { withoutTrailingSlash as Oe, withLeadingSlash as He, joinURL as x } from "ufo";
11
+ import { union as yt, debounce as St } from "lodash";
12
+ import Le from "crypto";
13
+ import z, { mkdtempSync as wt, existsSync as It, readFileSync as Pt, createWriteStream as bt } from "fs";
14
+ import Re from "p-limit";
15
+ import $e, { join as A, basename as $, dirname as M } from "path";
16
+ import { Worker as At } from "worker_threads";
17
+ import { nextId as Ue } from "@blocklet/pages-kit/utils/common";
18
+ import { unzipSection as Et } from "@blocklet/pages-kit/utils/page-model";
19
+ import { getComponentDependencies as Ot } from "@blocklet/pages-kit/utils/property";
20
+ import { getComponentWebEndpoint as Rt, getResources as Ct, call as jt } from "@blocklet/sdk/lib/component";
21
+ import { reactive as kt } from "@reactivedata/reactive";
22
+ import { rename as Ne, mkdir as B, rm as We, writeFile as re, lstat as oe, readFile as te, copyFile as Dt, readdir as vt } from "fs/promises";
23
+ import { globSync as Tt, glob as ye } from "glob";
24
+ import * as fe from "lib0/decoding";
25
+ import * as v from "lib0/encoding";
26
+ import Ce from "lodash/debounce";
27
+ import je from "lodash/get";
28
+ import ke from "lodash/isEmpty";
29
+ import Me from "lodash/set";
30
+ import Lt from "lodash/union";
31
+ import { LRUCache as Ke } from "lru-cache";
32
+ import { pipeline as $t } from "stream/promises";
33
+ import { x as Ut } from "tar";
34
+ import Nt from "wait-on";
35
+ import { Awareness as Mt, encodeAwarenessUpdate as _e, removeAwarenessStates as _t, applyAwarenessUpdate as Ft } from "y-protocols/awareness";
36
+ import { writeUpdate as xt, writeSyncStep1 as Bt, readSyncMessage as Gt } from "y-protocols/sync";
37
+ import * as q from "yaml";
38
+ import { m as Fe } from "./html-CNFwwbdj.js";
39
+ import "@blocklet/pages-kit/types/state";
40
+ const Vt = P.sqlite.DATE.parse;
41
+ P.sqlite.DATE.parse = (t, e) => typeof t == "number" ? new Date(t) : Vt(t, e);
42
+ const _ = new ht({
43
+ dialect: "sqlite",
44
+ storage: Je,
45
+ benchmark: process.env.ENABLE_SEQUELIZE_BENCHMARK === "true",
46
+ retry: {
47
+ match: [/SQLITE_BUSY/],
48
+ name: "query",
49
+ max: 10
50
+ },
51
+ // eslint-disable-next-line no-console
52
+ logging: process.env.ENABLE_SEQUELIZE_LOGGING === "true" ? console.log : !1
53
+ // logQueryParameters: true,
54
+ });
55
+ _.query("PRAGMA journal_mode = WAL;");
56
+ _.query("PRAGMA synchronous = normal;");
57
+ _.query("PRAGMA journal_size_limit = 67108864;");
58
+ _.query("PRAGMA cache_size = 10000;");
59
+ process.on("SIGINT", async () => {
60
+ await _.close(), process.exit(0);
61
+ });
62
+ process.on("SIGTERM", async () => {
63
+ await _.close(), process.exit(0);
64
+ });
65
+ async function zt(t, e) {
66
+ try {
67
+ if (t.getDialect() !== "sqlite")
68
+ return;
69
+ const [s] = await t.query("SELECT 1");
70
+ if (!s || s.length === 0)
71
+ return;
72
+ await t.query("PRAGMA shrink_memory;");
73
+ } catch (s) {
74
+ if (s.name === "SequelizeConnectionError" || s?.message && /closed!/.test(s.message))
75
+ return;
76
+ console.error("Failed to cleanup SQLite memory", e, s);
77
+ }
78
+ }
79
+ let Se = null;
80
+ Se && clearInterval(Se);
81
+ Se = setInterval(
82
+ async () => {
83
+ p.info("Start cleanupSqliteMemory"), await zt(_, Je), p.info("End cleanupSqliteMemory");
84
+ },
85
+ 60 * 1e3 * 10
86
+ // 10 minutes
87
+ );
88
+ const qt = "z8iZiDFg3vkkrPwsiba1TLXy3H9XHzFERsP8o", xe = "page", we = "trigger-reload-project-resource", Ye = qt, Jt = "z2qa7BQdkEb3TwYyEYC1psK6uvmGnHSUHt5RM", Ht = "z8iZiDFg3vkkrPwsiba1TLXy3H9XHzFERsP8o";
89
+ class De extends Ee {
90
+ // Foreign key to Component
91
+ }
92
+ De.init(
93
+ {
94
+ id: {
95
+ type: P.UUID,
96
+ allowNull: !1,
97
+ primaryKey: !0,
98
+ defaultValue: P.UUIDV4
99
+ },
100
+ projectId: {
101
+ type: P.UUID,
102
+ allowNull: !1
103
+ },
104
+ componentId: {
105
+ type: P.STRING,
106
+ allowNull: !1
107
+ }
108
+ },
109
+ { sequelize: _, tableName: "ProjectComponents", timestamps: !1 }
110
+ );
111
+ const Wt = "SLUG_INVALID", W = (t) => ({
112
+ error: "slugInvalid",
113
+ code: Wt,
114
+ field: "slug",
115
+ message: t
116
+ }), Kt = {
117
+ error: "slugRequired",
118
+ code: "SLUG_REQUIRED",
119
+ field: "slug",
120
+ message: () => "Project slug is required"
121
+ }, Yt = {
122
+ error: "slugAlreadyExists",
123
+ code: "SLUG_EXISTS",
124
+ field: "slug",
125
+ message: (t) => `Project slug "${t}" already exists`
126
+ }, Xt = [
127
+ /\.\./,
128
+ // Directory traversal
129
+ /<[^>]*>/,
130
+ // HTML/XML tags
131
+ /%[0-9a-f]{2}/i,
132
+ // Percent encoding
133
+ /[<>'"%;{}()\\]/,
134
+ // Special characters
135
+ // eslint-disable-next-line no-control-regex
136
+ /\x00/,
137
+ // Null byte
138
+ /\n|\r|\t|\v|\f/,
139
+ // Control characters
140
+ /[^a-zA-Z0-9-_@/\\:]/
141
+ // Only allow specific characters
142
+ ], Be = (t) => {
143
+ if (!t) return "";
144
+ if (t === "/") return "/";
145
+ const e = Oe(t);
146
+ return He(e) || "/";
147
+ }, Qt = (t) => t.did === Ht;
148
+ class U extends Ee {
149
+ static async getProjectByIdOrSlug(e, s) {
150
+ return e ? U.findOne({
151
+ where: {
152
+ [Z.or]: [{ id: e }, { slug: e }],
153
+ ...s?.createdBy ? { createdBy: s.createdBy } : {}
154
+ }
155
+ }) : null;
156
+ }
157
+ static async validateProjectSlug({
158
+ slug: e,
159
+ projectId: s
160
+ }) {
161
+ if (e == null)
162
+ return null;
163
+ if (e === "")
164
+ return Kt;
165
+ const a = e === "/" ? "/" : Oe(He(e)), o = Be(a);
166
+ if (a !== "/" && a.endsWith("/"))
167
+ return W((n) => `Project slug "${n}" cannot end with /`);
168
+ if (/\/{2,}/.test(a))
169
+ return W((n) => `Project slug "${n}" cannot contain consecutive /`);
170
+ if (/\s/.test(a))
171
+ return W((n) => `Project slug "${n}" cannot contain whitespace`);
172
+ if (Xt.some((n) => n.test(a)))
173
+ return W((n) => `Project slug "${n}" contains invalid characters`);
174
+ if (E.components?.filter((n) => n.mountPoint && !Qt(n)).some((n) => Be(n.mountPoint) === o))
175
+ return W((n) => `Project slug "${n}" conflicts with existing blocklet`);
176
+ const l = await U.findOne({
177
+ where: { slug: a }
178
+ });
179
+ return l && l?.id !== s ? Yt : null;
180
+ }
181
+ }
182
+ U.init(
183
+ {
184
+ id: {
185
+ type: P.UUID,
186
+ defaultValue: P.UUIDV4,
187
+ primaryKey: !0
188
+ },
189
+ name: {
190
+ type: P.STRING,
191
+ allowNull: !1
192
+ },
193
+ description: P.TEXT,
194
+ createdAt: P.DATE,
195
+ updatedAt: P.DATE,
196
+ createdBy: {
197
+ type: P.STRING,
198
+ allowNull: !1
199
+ },
200
+ updatedBy: {
201
+ type: P.STRING,
202
+ allowNull: !1
203
+ },
204
+ slug: P.STRING,
205
+ icon: P.STRING,
206
+ pinnedAt: P.DATE,
207
+ useAllResources: P.BOOLEAN,
208
+ npmSecret: P.STRING,
209
+ relatedBlocklets: {
210
+ type: P.JSON,
211
+ allowNull: !1,
212
+ defaultValue: {},
213
+ get() {
214
+ const t = this.getDataValue("relatedBlocklets");
215
+ if (typeof t == "object")
216
+ return t ?? {};
217
+ try {
218
+ return t ? JSON.parse(t) : {};
219
+ } catch (e) {
220
+ return p.error("Failed to parse relatedBlocklets", { error: e, rawValue: t }), {};
221
+ }
222
+ },
223
+ set(t) {
224
+ try {
225
+ this.setDataValue("relatedBlocklets", t ? JSON.stringify(t) : "{}");
226
+ } catch (e) {
227
+ p.error("Failed to set relatedBlocklets", { error: e, value: t }), this.setDataValue("relatedBlocklets", "{}");
228
+ }
229
+ }
230
+ },
231
+ productionState: {
232
+ type: P.JSON,
233
+ allowNull: !1,
234
+ defaultValue: {},
235
+ get() {
236
+ const t = this.getDataValue("productionState");
237
+ if (typeof t == "object")
238
+ return t ?? {};
239
+ try {
240
+ return t ? JSON.parse(t) : {};
241
+ } catch (e) {
242
+ return p.error("Failed to parse productionState", { error: e, rawValue: t }), {};
243
+ }
244
+ },
245
+ set(t) {
246
+ try {
247
+ this.setDataValue("productionState", t ? JSON.stringify(t) : "{}");
248
+ } catch (e) {
249
+ p.error("Failed to set productionState", { error: e, value: t }), this.setDataValue("productionState", "{}");
250
+ }
251
+ }
252
+ },
253
+ meta: {
254
+ type: P.JSON,
255
+ allowNull: !0
256
+ }
257
+ },
258
+ {
259
+ sequelize: _,
260
+ paranoid: !0,
261
+ indexes: [
262
+ {
263
+ name: "projects_slug_unique",
264
+ unique: !0,
265
+ fields: ["slug"]
266
+ },
267
+ {
268
+ name: "projects_created_by",
269
+ fields: ["createdBy"]
270
+ },
271
+ {
272
+ name: "projects_pinned_updated_meta_not_null",
273
+ fields: [
274
+ { name: "pinnedAt", order: "DESC" },
275
+ { name: "updatedAt", order: "DESC" }
276
+ ],
277
+ where: {
278
+ meta: {
279
+ [Z.ne]: null
280
+ }
281
+ }
282
+ }
283
+ ]
284
+ }
285
+ );
286
+ U.hasMany(De, {
287
+ foreignKey: "projectId",
288
+ as: "components"
289
+ });
290
+ async function G(t) {
291
+ try {
292
+ return await z.promises.access(t, z.constants.F_OK), !0;
293
+ } catch {
294
+ return !1;
295
+ }
296
+ }
297
+ function Xe(t, e) {
298
+ return new Promise((s, a) => {
299
+ const o = z.createReadStream(t), r = z.createWriteStream(e);
300
+ o.on("error", a), r.on("error", a), r.on("finish", s), o.pipe(r);
301
+ });
302
+ }
303
+ async function Qe(t, e) {
304
+ await z.promises.mkdir(e, { recursive: !0 });
305
+ const s = await z.promises.readdir(t, { withFileTypes: !0 });
306
+ for (const a of s) {
307
+ const o = $e.join(t, a.name), r = $e.join(e, a.name);
308
+ a.isDirectory() ? await Qe(o, r) : await Xe(o, r);
309
+ }
310
+ }
311
+ async function oa(t, e) {
312
+ (await z.promises.stat(t)).isDirectory() ? await Qe(t, e) : await Xe(t, e);
313
+ }
314
+ class ee extends Ee {
315
+ }
316
+ ee.init(
317
+ {
318
+ id: {
319
+ type: P.UUID,
320
+ primaryKey: !0,
321
+ defaultValue: P.UUIDV4
322
+ },
323
+ projectId: {
324
+ type: P.UUID,
325
+ allowNull: !1,
326
+ comment: "Project ID"
327
+ },
328
+ urlPath: {
329
+ type: P.STRING(512),
330
+ allowNull: !1,
331
+ unique: !0,
332
+ comment: "URL path, e.g. /project-slug/page-slug or /en/project-slug/page-slug"
333
+ },
334
+ projectSlug: {
335
+ type: P.STRING,
336
+ allowNull: !0,
337
+ comment: "Project slug"
338
+ },
339
+ pageSlug: {
340
+ type: P.STRING,
341
+ allowNull: !1,
342
+ comment: "Page slug"
343
+ },
344
+ pageId: {
345
+ type: P.UUID,
346
+ allowNull: !1,
347
+ comment: "Page ID"
348
+ },
349
+ routeId: {
350
+ type: P.UUID,
351
+ allowNull: !0,
352
+ comment: "Route ID (for draft mode)"
353
+ },
354
+ locale: {
355
+ type: P.STRING(10),
356
+ allowNull: !0,
357
+ comment: "Locale code, e.g. en, zh"
358
+ },
359
+ defaultLocale: {
360
+ type: P.STRING(10),
361
+ allowNull: !0,
362
+ comment: "Default locale"
363
+ },
364
+ shouldRedirect: {
365
+ type: P.BOOLEAN,
366
+ defaultValue: !1,
367
+ comment: "Whether this URL should redirect"
368
+ },
369
+ mainPage: {
370
+ type: P.BOOLEAN,
371
+ defaultValue: !1,
372
+ comment: "Whether this is the main page"
373
+ },
374
+ isPublic: {
375
+ type: P.BOOLEAN,
376
+ allowNull: !1,
377
+ defaultValue: !0,
378
+ comment: "Whether the page is public"
379
+ },
380
+ publishedAt: {
381
+ type: P.BIGINT,
382
+ allowNull: !0,
383
+ comment: "Published timestamp"
384
+ },
385
+ locales: {
386
+ type: P.JSON,
387
+ allowNull: !0,
388
+ comment: "Supported locales array"
389
+ },
390
+ createdAt: P.DATE,
391
+ updatedAt: P.DATE
392
+ },
393
+ {
394
+ sequelize: _,
395
+ tableName: "PageUrlMappings",
396
+ timestamps: !0,
397
+ indexes: [
398
+ {
399
+ name: "idx_project_id",
400
+ fields: ["projectId"]
401
+ },
402
+ {
403
+ name: "idx_url_path",
404
+ unique: !0,
405
+ fields: ["urlPath"]
406
+ },
407
+ {
408
+ name: "idx_page_id",
409
+ fields: ["pageId"]
410
+ }
411
+ ]
412
+ }
413
+ );
414
+ function Zt(t) {
415
+ const { projectId: e, projectSlug: s, state: a } = t, o = s || e, r = yt(
416
+ E.env.languages?.map((c) => c.code) || [],
417
+ a.supportedLocales?.map((c) => c.locale) || []
418
+ ), l = {}, n = (c, f) => {
419
+ o && (l[x("/", o, c)] = {
420
+ ...f,
421
+ shouldRedirect: !0,
422
+ mainPage: !0
423
+ }), l[x("/", e, c)] = {
424
+ ...f,
425
+ shouldRedirect: !0,
426
+ mainPage: !0
427
+ };
428
+ for (const b of r) {
429
+ const R = { ...f, locale: b };
430
+ l[x("/", b, e, c)] = R, o && (l[x("/", b, o, c)] = R);
431
+ }
432
+ };
433
+ for (const c of a.pageIds || []) {
434
+ const f = a.pages?.[c];
435
+ if (!f || !f.isPublic)
436
+ continue;
437
+ const b = {
438
+ projectId: e,
439
+ projectSlug: o,
440
+ pageSlug: f.slug,
441
+ pageId: c,
442
+ defaultLocale: r?.[0],
443
+ locales: r,
444
+ publishedAt: a.config?.publishedAt,
445
+ isPublic: f.isPublic
446
+ };
447
+ n(f.slug, b);
448
+ }
449
+ return l;
450
+ }
451
+ async function es(t, e, s) {
452
+ const a = t.map((r) => r.urlPath), o = await ee.findAll({
453
+ where: {
454
+ urlPath: {
455
+ [Z.in]: a
456
+ },
457
+ projectId: {
458
+ [Z.ne]: e
459
+ }
460
+ },
461
+ attributes: ["urlPath", "projectId", "projectSlug", "pageSlug"],
462
+ transaction: s,
463
+ raw: !0
464
+ });
465
+ if (o.length > 0) {
466
+ p.warn(
467
+ `[URL Duplicate Warning] Found ${o.length} URL conflicts for project ${e}:`
468
+ );
469
+ for (const r of o) {
470
+ const l = t.find((n) => n.urlPath === r.urlPath);
471
+ if (l) {
472
+ const n = r.projectSlug ? x(r.projectSlug, r.pageSlug) : r.pageSlug;
473
+ p.warn(
474
+ ` - URL "${r.urlPath}" conflicts with project ${r.projectId} (${n}). Current project trying to use same URL for page: ${l.pageSlug}`
475
+ );
476
+ }
477
+ }
478
+ p.warn(
479
+ "[URL Duplicate Warning] These duplicate URLs will be ignored during save. Consider using different project slugs or page slugs to avoid conflicts."
480
+ );
481
+ }
482
+ }
483
+ async function ts(t) {
484
+ const { projectId: e, transaction: s } = t;
485
+ try {
486
+ await ee.destroy({
487
+ where: { projectId: e },
488
+ transaction: s
489
+ });
490
+ const a = Zt(t), o = Object.entries(a).map(([r, l]) => ({
491
+ projectId: e,
492
+ urlPath: r,
493
+ projectSlug: l.projectSlug,
494
+ pageSlug: l.pageSlug,
495
+ pageId: l.pageId,
496
+ routeId: l.routeId,
497
+ locale: l.locale,
498
+ defaultLocale: l.defaultLocale,
499
+ shouldRedirect: l.shouldRedirect,
500
+ mainPage: l.mainPage,
501
+ isPublic: l.isPublic,
502
+ publishedAt: typeof l.publishedAt == "number" ? l.publishedAt : void 0,
503
+ locales: l.locales
504
+ }));
505
+ if (o.length > 0) {
506
+ await es(o, e, s);
507
+ const r = 100, l = [];
508
+ for (let n = 0; n < o.length; n += r) {
509
+ const c = o.slice(n, n + r);
510
+ l.push(
511
+ ee.bulkCreate(c, {
512
+ transaction: s,
513
+ ignoreDuplicates: !0
514
+ // 忽略重复数据,避免因脏数据导致整批插入失败
515
+ })
516
+ );
517
+ }
518
+ await Promise.all(l), p.info(`Regenerated ${o.length} URL mappings for project ${e}`);
519
+ }
520
+ return o.length;
521
+ } catch (a) {
522
+ throw p.error(`Failed to regenerate URL mappings for project ${e}:`, a), a;
523
+ }
524
+ }
525
+ function ne(t) {
526
+ t.observeDeep((e) => {
527
+ e.some((s) => s.changes.keys.has("updatedAt") || s.changes.keys.has("publishedAt")) || t.set("updatedAt", (/* @__PURE__ */ new Date()).toISOString());
528
+ });
529
+ }
530
+ function Ze() {
531
+ return wt(A(E.env.dataDir, "tmp-"));
532
+ }
533
+ function ie(t, e, s = []) {
534
+ return Array.isArray(t) ? t.flatMap((a, o) => ie(a, e, [...s, o])) : typeof t == "object" ? t === null ? [] : Object.entries(t).flatMap(([a, o]) => ie(o, e, [...s, a])) : e(t) ? [s] : [];
535
+ }
536
+ function L(t) {
537
+ return t.filter((e) => e != null);
538
+ }
539
+ function ss(t) {
540
+ return new Promise((e, s) => {
541
+ let a;
542
+ process.env.NODE_ENV === "development" ? a = A(__dirname, "yaml-worker.js") : a = A(__dirname, "api/dist/utils/yaml-worker.js");
543
+ const o = new At(a);
544
+ o.postMessage({ payload: t }), o.on("message", (r) => {
545
+ r.status === "success" ? e(r.result) : s(new Error(`YAML stringify failed in worker: ${r.message}`)), o.terminate();
546
+ }), o.on("error", (r) => {
547
+ s(r);
548
+ }), o.on("exit", (r) => {
549
+ r !== 0 && s(new Error(`Worker stopped with exit code ${r}`));
550
+ });
551
+ });
552
+ }
553
+ function Ge(t, e) {
554
+ if (t === e) return !0;
555
+ if (!t || !e) return t === e;
556
+ const s = Object.keys(t), a = Object.keys(e);
557
+ if (s.length !== a.length) return !1;
558
+ if (s.length < 10) {
559
+ for (const l of s) {
560
+ if (!(l in e)) return !1;
561
+ const n = t[l], c = e[l];
562
+ if (n?.blockletId !== c?.blockletId || n?.page?.id !== c?.page?.id || n?.page?.updatedAt !== c?.page?.updatedAt || n?.component?.id !== c?.component?.id || n?.component?.updatedAt !== c?.component?.updatedAt)
563
+ return !1;
564
+ }
565
+ return !0;
566
+ }
567
+ const o = Le.createHash("md5").update(JSON.stringify(t, Object.keys(t).sort())).digest("hex"), r = Le.createHash("md5").update(JSON.stringify(e, Object.keys(e).sort())).digest("hex");
568
+ return o === r;
569
+ }
570
+ function as(t) {
571
+ t.pages && Object.keys(t.pages).forEach((s) => {
572
+ const a = J(t.pages[s]);
573
+ a && a instanceof F.Map && ne(a);
574
+ });
575
+ const e = J(t.pages);
576
+ e && e instanceof F.Map && e.observe((s) => {
577
+ s.changes.keys.forEach((a, o) => {
578
+ if (a.action === "add") {
579
+ const r = J(t.pages[o]);
580
+ r && r instanceof F.Map && ne(r);
581
+ }
582
+ });
583
+ });
584
+ }
585
+ function os(t) {
586
+ t.routes && Object.keys(t.routes).forEach((s) => {
587
+ const a = J(t.routes?.[s]);
588
+ a && a instanceof F.Map && ne(a);
589
+ });
590
+ const e = J(t.routes);
591
+ e && e instanceof F.Map && e.observe((s) => {
592
+ s.changes.keys.forEach((a, o) => {
593
+ if (a.action === "add") {
594
+ const r = J(t.routes?.[o]);
595
+ r && r instanceof F.Map && ne(r);
596
+ }
597
+ });
598
+ });
599
+ }
600
+ function rs(t, e) {
601
+ for (const s of e || Object.keys(t.routes || {})) {
602
+ let a = s, o = [];
603
+ if (s.includes("-")) {
604
+ const [r, ...l] = s.split("-");
605
+ a = r, o = l || [];
606
+ }
607
+ if (t.routes?.[a] !== void 0) {
608
+ t.routes[a].publishedAt = (/* @__PURE__ */ new Date()).toISOString();
609
+ const r = t.routes[a];
610
+ if (!r || !r.params || r.params.length === 0)
611
+ continue;
612
+ if (s.includes("-") && o.length > 0) {
613
+ const l = gt(o, r);
614
+ l && (l.publishedAt = (/* @__PURE__ */ new Date()).toISOString());
615
+ }
616
+ if (!e) {
617
+ const l = be({
618
+ basePath: r.path,
619
+ params: r.params,
620
+ routeId: r.id,
621
+ paramsOptions: r.paramsOptions,
622
+ currentIndex: 0,
623
+ currentParams: [],
624
+ currentOptionIds: [],
625
+ result: []
626
+ });
627
+ for (const n of l)
628
+ n.routeMetaData ??= {}, n.routeMetaData.publishedAt = (/* @__PURE__ */ new Date()).toISOString();
629
+ }
630
+ }
631
+ }
632
+ }
633
+ function me({
634
+ page: t,
635
+ route: e,
636
+ state: s,
637
+ routeId: a,
638
+ routePathInfo: o
639
+ }) {
640
+ p.info(
641
+ `Executing datasource data assembly, routeId: ${a}, routePathInfo: ${JSON.stringify(o)}`
642
+ );
643
+ const r = {
644
+ ...Ae(t),
645
+ id: a,
646
+ slug: o?.path ?? e.path,
647
+ createdAt: e.createdAt,
648
+ updatedAt: o?.routeMetaData?.updatedAt ?? e.updatedAt,
649
+ publishedAt: o?.routeMetaData?.publishedAt ?? e.publishedAt,
650
+ isPublic: (o?.routeMetaData?.isPublic ?? e.isPublic) && e.isPublic
651
+ };
652
+ for (const l of s.supportedLocales) {
653
+ if (e.dataSource) {
654
+ let n = e.id;
655
+ o && (n = o.paramOptionIds.join("-"));
656
+ const c = e.dataSource.pathDataMappings?.[n]?.dataCache?.[l.locale] ?? e.dataSource.pathDataMappings?.[n]?.dataCache?.[s.config.defaultLocale || "en"];
657
+ if (!c)
658
+ continue;
659
+ mt(r, s, l.locale, c);
660
+ }
661
+ o && o.routeMetaData && (o.routeMetaData.publishedAt = (/* @__PURE__ */ new Date()).toISOString());
662
+ }
663
+ return r;
664
+ }
665
+ ["true", "1", "yes", "y"].includes(process.env.USE_FS_CACHE_HTML ?? "");
666
+ const ns = 60 * 60 * 1e3, Y = new Ke({
667
+ max: 300,
668
+ ttl: ns,
669
+ ttlResolution: 10 * 1e3,
670
+ // 10 seconds
671
+ allowStale: !0
672
+ });
673
+ function is(t, e = []) {
674
+ let s = 0;
675
+ const a = Array.from(Y.keys()), o = t.map((r) => Oe(r));
676
+ for (const r of a)
677
+ for (const l of o) {
678
+ if (Fe(r, { currentPath: l })) {
679
+ Y.delete(r), s++, p.info(`[Cache CLEAR] key: ${r}`);
680
+ break;
681
+ }
682
+ for (const n of e)
683
+ if (Fe(r, { currentPath: `/${n}${l}` })) {
684
+ Y.delete(r), s++, p.info(`[Cache CLEAR] key: ${r}`);
685
+ break;
686
+ }
687
+ }
688
+ return p.info(`[Cache CLEAR] cleared ${s} entries for paths:`, o), s;
689
+ }
690
+ function cs() {
691
+ const t = Y.size;
692
+ return Y.clear(), p.info(`[Cache CLEAR ALL] cleared ${t} entries`), t;
693
+ }
694
+ const ls = St(cs, 300);
695
+ E.events.on(E.Events.envUpdate, ls);
696
+ const { uploadToMediaKit: ps } = require("@blocklet/uploader-server"), ve = /^\w+(\w|-|\.)+\w+\.(jpe?g|png|gif|svg|bmp|webp|mp4|m4v|webm)$/, X = /mediakit:\/\/([a-f0-9]{32}\.(jpe?g|png|gif|svg|bmp|webp|mp4|m4v|webm))/i, Ve = /mediakit:\/\/([a-f0-9]{32}\.(jpe?g|png|gif|svg|bmp|webp|mp4|m4v|webm))/gi, us = 1e4, ds = 3e4, se = 0, ge = 1, fs = 0, ms = 1, Ie = E, K = A(process.env.BLOCKLET_DATA_DIR, "site-state"), ra = ["production", "draft"], na = ["production"];
697
+ function ce(t) {
698
+ return t?.replace(/\//g, "|") || "";
699
+ }
700
+ function gs() {
701
+ const t = Ie.env.languages?.map((s) => ({ locale: s.code, name: s.name })) || [], e = t[0]?.locale || "en";
702
+ return {
703
+ pageIds: [],
704
+ pages: {},
705
+ routeIds: [],
706
+ routes: {},
707
+ dataSourceIds: [],
708
+ dataSources: {},
709
+ components: {},
710
+ supportedLocales: t,
711
+ config: { defaultLocale: e },
712
+ resources: {}
713
+ };
714
+ }
715
+ class k extends F.Doc {
716
+ constructor(e) {
717
+ super(), this.options = e, It(this.draftYjsFilePath) && F.applyUpdate(this, Pt(this.draftYjsFilePath)), this.syncedStore = kt(
718
+ ft(
719
+ {
720
+ pages: {},
721
+ pageIds: [],
722
+ components: {},
723
+ supportedLocales: [],
724
+ config: {},
725
+ resources: {},
726
+ routeIds: [],
727
+ routes: {},
728
+ dataSourceIds: [],
729
+ dataSources: {}
730
+ },
731
+ this
732
+ )
733
+ ), this.initObserver(), this.on("update", this.updateHandler), this.awareness = new Mt(this), this.awareness.on("update", this.awarenessChangeHandler), this.ensureDataStructure();
734
+ }
735
+ // 延迟释放时间:5 分钟
736
+ static RELEASE_DELAY = 5 * 60 * 1e3;
737
+ // 定期检查间隔:2 小时
738
+ static PERIODIC_CHECK_INTERVAL = 2 * 60 * 60 * 1e3;
739
+ // 2 hours
740
+ static sharedInstances = {};
741
+ // 定期检查定时器
742
+ static periodicCheckTimer;
743
+ // safe delete project state dir
744
+ static async safeDeleteProjectStateDir(e) {
745
+ if (!e)
746
+ throw new Error("Should provide project context");
747
+ try {
748
+ const s = A(K, e), a = A(K, `@del-${e}`);
749
+ await Ne(s, a);
750
+ } catch (s) {
751
+ p.error("Failed to safe delete project state dir:", s);
752
+ }
753
+ }
754
+ static async getProjectIds() {
755
+ return (await U.findAll({ attributes: ["id"], raw: !0 }))?.map((e) => e.id);
756
+ }
757
+ /** @deprecated 不再使用这个 getter 了,仅作为兼容性处理,请使用 getProjectIds 代替 */
758
+ static get projectIds() {
759
+ return Tt("*/", {
760
+ cwd: K,
761
+ ignore: ["@del-*", "@tmp-*", ".*", "staging", "production", "@backup-*", "undefined"]
762
+ // Ignore temp directories and hidden files
763
+ });
764
+ }
765
+ /** @deprecated 不再使用这个 getter 了,仅作为兼容性处理 */
766
+ static get allShared() {
767
+ return this.projectIds.map((e) => k.shared(e));
768
+ }
769
+ static shared(e) {
770
+ if (!e)
771
+ throw new Error("Should provide project context");
772
+ let s = k.sharedInstances[e];
773
+ return s || (s = new k({
774
+ path: A(K, e)
775
+ }), k.sharedInstances[e] = s, s);
776
+ }
777
+ // 轻量级 production 状态获取,不加载 draft 数据
778
+ static async getProductionState(e) {
779
+ const s = await U.findByPk(e, {
780
+ attributes: ["productionState"]
781
+ });
782
+ if (ke(s?.productionState)) {
783
+ const a = A(K, e, "production"), o = await tt(a, { includeResources: !0 }) ?? gs();
784
+ if (!o?.config?.defaultLocale) {
785
+ o.config ??= {};
786
+ const r = Ie.env.languages?.map((l) => ({ locale: l.code, name: l.name })) || [];
787
+ o.config.defaultLocale = r[0]?.locale;
788
+ }
789
+ return o;
790
+ }
791
+ return s?.productionState;
792
+ }
793
+ destroy() {
794
+ this.cancelRelease(), this.save({ flush: !0 }), this.conns.forEach((s, a) => this.closeConn(a)), this.awareness.destroy();
795
+ const e = $(this.options.path);
796
+ delete k.sharedInstances[e], super.destroy();
797
+ }
798
+ initObserver() {
799
+ as(this.syncedStore), os(this.syncedStore);
800
+ }
801
+ get draftYjsFilePath() {
802
+ return A(this.options.path, "draft.yjs");
803
+ }
804
+ static async getStateByProjectId({
805
+ projectId: e,
806
+ mode: s,
807
+ clone: a = !0
808
+ }) {
809
+ if (s === "draft") {
810
+ const o = k.shared(e);
811
+ return a ? JSON.parse(JSON.stringify(o.syncedStore)) : o.syncedStore;
812
+ }
813
+ return k.getProductionState(e);
814
+ }
815
+ async getState(e) {
816
+ if (e === "draft")
817
+ return JSON.parse(JSON.stringify(this.syncedStore));
818
+ const s = $(this.options.path);
819
+ return k.getProductionState(s);
820
+ }
821
+ async setState(e, s) {
822
+ if (e === "production") {
823
+ const r = $(this.options.path), l = Ae(s);
824
+ await _.transaction(async (n) => {
825
+ await U.update({ productionState: l }, { where: { id: r }, transaction: n });
826
+ const c = await U.findByPk(r, {
827
+ attributes: ["slug"],
828
+ transaction: n
829
+ }), f = await ts({
830
+ projectId: r,
831
+ projectSlug: c?.slug,
832
+ state: s,
833
+ transaction: n
834
+ });
835
+ p.info(`[SiteState] saved ${f} URL mappings for project ${r}`);
836
+ }), await this.clearPageCacheForRoutes(void 0, s);
837
+ }
838
+ const a = await ws(s, { exportAssets: !1, includeResources: !0 }), o = this.getPublishDir(e);
839
+ await B(M(o), { recursive: !0 }), await We(o, { force: !0, recursive: !0 }), await Ne(a, o);
840
+ }
841
+ getPublishDir(e) {
842
+ return A(this.options.path, e);
843
+ }
844
+ syncedStore;
845
+ conns = /* @__PURE__ */ new Map();
846
+ awareness;
847
+ // 延迟释放定时器
848
+ releaseTimer;
849
+ awarenessChangeHandler = ({ added: e, updated: s, removed: a }, o) => {
850
+ const r = e.concat(s, a);
851
+ if (o !== null) {
852
+ const c = this.conns.get(o);
853
+ c && (e.forEach((f) => {
854
+ c.add(f);
855
+ }), a.forEach((f) => {
856
+ c.delete(f);
857
+ }));
858
+ }
859
+ const l = v.createEncoder();
860
+ v.writeVarUint(l, ge), v.writeVarUint8Array(l, _e(this.awareness, r));
861
+ const n = v.toUint8Array(l);
862
+ this.conns.forEach((c, f) => this.send(f, n));
863
+ };
864
+ updateHandler = (e) => {
865
+ const s = v.createEncoder();
866
+ v.writeVarUint(s, se), xt(s, e);
867
+ const a = v.toUint8Array(s);
868
+ this.conns.forEach((o, r) => this.send(r, a));
869
+ };
870
+ ensureDataStructure = () => {
871
+ this.transact(() => {
872
+ const { supportedLocales: e, pages: s, pageIds: a, config: o, routes: r, routeIds: l } = this.syncedStore;
873
+ {
874
+ const n = new Set(Object.keys(s));
875
+ let c = 0;
876
+ for (; c < a.length; ) {
877
+ const f = a[c];
878
+ n.has(f) ? (n.delete(f), c++) : a.splice(c, 1);
879
+ }
880
+ }
881
+ {
882
+ const n = new Set(Object.keys(r));
883
+ let c = 0;
884
+ for (; c < l.length; ) {
885
+ const f = l[c];
886
+ n.has(f) ? (n.delete(f), c++) : l.splice(c, 1);
887
+ }
888
+ }
889
+ e.splice(0, e.length), e.push(...Ie.env.languages.map((n) => ({ locale: n.code, name: n.name }))), o.defaultLocale = e[0]?.locale;
890
+ {
891
+ let n = 0;
892
+ const c = /* @__PURE__ */ new Set();
893
+ for (; n < e.length; ) {
894
+ const { locale: f } = e[n];
895
+ c.has(f) ? e.splice(n, 1) : (n++, c.add(f));
896
+ }
897
+ }
898
+ });
899
+ };
900
+ send = (e, s) => {
901
+ e.readyState !== fs && e.readyState !== ms && this.closeConn(e);
902
+ try {
903
+ e.send(s, (a) => {
904
+ a && this.closeConn(e);
905
+ });
906
+ } catch {
907
+ this.closeConn(e);
908
+ }
909
+ };
910
+ closeConn = (e) => {
911
+ if (e.removeAllListeners(), this.conns.has(e)) {
912
+ const s = this.conns.get(e);
913
+ this.conns.delete(e), s && _t(this.awareness, Array.from(s), null);
914
+ }
915
+ e.close(), this.checkAndScheduleRelease();
916
+ };
917
+ // 检查并调度延迟释放
918
+ checkAndScheduleRelease() {
919
+ this.conns.size === 0 && this.scheduleRelease();
920
+ }
921
+ // 调度延迟释放
922
+ scheduleRelease() {
923
+ this.cancelRelease();
924
+ const e = $(this.options.path);
925
+ this.releaseTimer = setTimeout(() => {
926
+ p.info(`[SiteState] releasing instance due to no active connections: ${e}`), this.conns.size === 0 && (this.releaseTimer = void 0, this.destroy());
927
+ }, k.RELEASE_DELAY), p.info(`[SiteState] scheduled release for project ${e} in ${k.RELEASE_DELAY / 1e3}s`);
928
+ }
929
+ // 取消延迟释放
930
+ cancelRelease() {
931
+ if (this.releaseTimer) {
932
+ clearTimeout(this.releaseTimer), this.releaseTimer = void 0;
933
+ const e = $(this.options.path);
934
+ p.info(`[SiteState] cancelled scheduled release for project ${e}`);
935
+ }
936
+ }
937
+ autoSave = Ce(async () => {
938
+ await B(M(this.draftYjsFilePath), { recursive: !0 }), await re(this.draftYjsFilePath, F.encodeStateAsUpdate(this));
939
+ }, us);
940
+ save = ({ flush: e = !1 } = {}) => {
941
+ this.autoSave(), e && this.autoSave.flush();
942
+ };
943
+ publish = async ({ mode: e, routes: s }) => {
944
+ const a = $(this.options.path);
945
+ await bs(a);
946
+ const o = await this.getState("draft"), r = await this.getState("production");
947
+ await qe(o, r, { routes: s, mergeMode: "replace", deleteRoutes: !0, publishMode: e }), r.config.publishedAt = (/* @__PURE__ */ new Date()).getTime(), setImmediate(() => {
948
+ this.transact(() => {
949
+ rs(this.syncedStore, s);
950
+ });
951
+ }), await this.setState(e, r);
952
+ };
953
+ mergeState = async (e, s) => {
954
+ const a = JSON.parse(JSON.stringify(s));
955
+ e.config.fontFamily ??= {};
956
+ const o = a.config?.fontFamily, r = e.config?.fontFamily;
957
+ e.config.fontFamily.title = o?.title || r?.title, e.config.fontFamily.description = o?.description || r?.description, await new Promise((l, n) => {
958
+ this.transact(async () => {
959
+ try {
960
+ const c = await qe(e, s);
961
+ l(c);
962
+ } catch (c) {
963
+ n(c);
964
+ }
965
+ });
966
+ });
967
+ };
968
+ clearPageCacheForRoutes = async (e, s) => {
969
+ const a = $(this.options.path), r = (await U.findByPk(a))?.slug || a;
970
+ let l = e;
971
+ (!l || l.length === 0) && (l = s.pageIds ?? []), p.info(`[SiteState] clearing page cache for project ${a}, routes:`, l || []);
972
+ const n = s.supportedLocales.map((b) => b.locale), c = [], f = l.filter((b) => s.pageIds?.includes(b));
973
+ for (const b of f) {
974
+ const y = s.pages[b].slug;
975
+ r && r !== a && (r === "/" ? c.push(y) : c.push(`${r.startsWith("/") ? "" : "/"}${r}${y}`)), c.push(`/${a}${y}`);
976
+ }
977
+ if (c.length > 0)
978
+ try {
979
+ const b = is(c, n);
980
+ p.info(`[SiteState] cleared ${b} page cache entries for project ${a}, routes:`, l);
981
+ } catch {
982
+ }
983
+ };
984
+ addConnection = (e) => {
985
+ if (this.conns.has(e))
986
+ return;
987
+ this.cancelRelease(), e.binaryType = "arraybuffer", this.conns.set(e, /* @__PURE__ */ new Set()), e.on("message", (o) => this.messageListener(e, new Uint8Array(o)));
988
+ let s = !0;
989
+ const a = setInterval(() => {
990
+ if (!s)
991
+ this.conns.has(e) && this.closeConn(e), clearInterval(a);
992
+ else if (this.conns.has(e)) {
993
+ s = !1;
994
+ try {
995
+ e.ping();
996
+ } catch {
997
+ this.closeConn(e), clearInterval(a);
998
+ }
999
+ }
1000
+ }, ds);
1001
+ e.on("close", () => {
1002
+ this.closeConn(e), clearInterval(a);
1003
+ }), e.on("pong", () => {
1004
+ s = !0;
1005
+ });
1006
+ {
1007
+ const o = v.createEncoder();
1008
+ v.writeVarUint(o, se), Bt(o, this), this.send(e, v.toUint8Array(o));
1009
+ const r = this.awareness.getStates();
1010
+ if (r.size > 0) {
1011
+ const l = v.createEncoder();
1012
+ v.writeVarUint(l, ge), v.writeVarUint8Array(l, _e(this.awareness, Array.from(r.keys()))), this.send(e, v.toUint8Array(l));
1013
+ }
1014
+ }
1015
+ };
1016
+ messageListener = (e, s) => {
1017
+ try {
1018
+ const a = v.createEncoder(), o = fe.createDecoder(s), r = fe.readVarUint(o);
1019
+ switch (p.info(`[SiteState] messageListener, messageType: ${r}`), r) {
1020
+ case se:
1021
+ v.writeVarUint(a, se), Gt(o, a, this, null), p.info(`[SiteState] messageListener, encoder length: ${v.length(a)}`), v.length(a) > 1 && (this.ensureDataStructure(), this.send(e, v.toUint8Array(a)));
1022
+ break;
1023
+ case ge: {
1024
+ Ft(this.awareness, fe.readVarUint8Array(o), e);
1025
+ break;
1026
+ }
1027
+ default:
1028
+ p.warn(`Unsupported messageType ${r}`);
1029
+ }
1030
+ } catch (a) {
1031
+ p.error(a);
1032
+ }
1033
+ this.save();
1034
+ };
1035
+ // 这个方法还是需要动态的,因为可能会动态修改 projectSlug、语言之类的
1036
+ static async pageUrlMap(e, s) {
1037
+ if (p.info(`[SiteState] get pageUrlMap, mode: ${e}, projectId: ${s}`), e === "production") {
1038
+ const r = s ? { projectId: s } : {}, l = await ee.findAll({
1039
+ where: r,
1040
+ raw: !0
1041
+ }), n = {};
1042
+ for (const c of l)
1043
+ n[c.urlPath] = {
1044
+ projectId: c.projectId,
1045
+ projectSlug: c.projectSlug,
1046
+ pageSlug: c.pageSlug,
1047
+ pageId: c.pageId,
1048
+ routeId: c.routeId,
1049
+ locale: c.locale,
1050
+ defaultLocale: c.defaultLocale,
1051
+ shouldRedirect: c.shouldRedirect,
1052
+ mainPage: c.mainPage,
1053
+ isPublic: c.isPublic,
1054
+ publishedAt: c.publishedAt,
1055
+ locales: c.locales
1056
+ };
1057
+ return p.info(`[SiteState] loaded ${l.length} URL mappings from database`), n;
1058
+ }
1059
+ let a = [];
1060
+ s ? a = [s] : a = await this.getProjectIds();
1061
+ let o = {};
1062
+ if (a?.length) {
1063
+ p.info("[SiteState] find project infos from database, projectIds: ", a);
1064
+ const r = 30, l = Re(5);
1065
+ for (let n = 0; n < a.length; n += r) {
1066
+ const c = a.slice(n, n + r);
1067
+ p.info(`[SiteState] processing project batch ${n / r + 1}, ids: `, c);
1068
+ const f = await U.findAll({
1069
+ where: {
1070
+ id: {
1071
+ [Z.in]: c
1072
+ }
1073
+ },
1074
+ attributes: {
1075
+ exclude: ["relatedBlocklets"]
1076
+ }
1077
+ });
1078
+ await Promise.all(
1079
+ f?.map(
1080
+ (b) => l(async () => {
1081
+ const R = b.id, y = b.slug || R, g = {}, u = await k.getStateByProjectId({ projectId: b.id, mode: e, clone: !1 }), I = Lt(
1082
+ E.env.languages?.map((O) => O.code) || [],
1083
+ u.supportedLocales?.map((O) => O.locale) || []
1084
+ ), C = (O, w) => {
1085
+ y && (g[x("/", y, O)] = {
1086
+ ...w,
1087
+ shouldRedirect: !0,
1088
+ mainPage: !0
1089
+ }), g[x("/", R, O)] = {
1090
+ ...w,
1091
+ shouldRedirect: !0,
1092
+ mainPage: !0
1093
+ };
1094
+ for (const D of I) {
1095
+ const h = { ...w, locale: D };
1096
+ g[x("/", D, R, O)] = h, y && (g[x("/", D, y, O)] = h);
1097
+ }
1098
+ };
1099
+ if (e === "draft")
1100
+ for (const O of u.routeIds || []) {
1101
+ const w = u?.routes?.[O];
1102
+ if (!w) continue;
1103
+ if (w.params && w.params.length > 0) {
1104
+ const S = be({
1105
+ basePath: w.path,
1106
+ params: w.params,
1107
+ routeId: w.id,
1108
+ paramsOptions: w.paramsOptions,
1109
+ currentIndex: 0,
1110
+ currentParams: [],
1111
+ currentOptionIds: [],
1112
+ result: []
1113
+ });
1114
+ for (const i of S) {
1115
+ const d = i.path, m = {
1116
+ projectId: R,
1117
+ projectSlug: y,
1118
+ pageSlug: d,
1119
+ pageId: w.displayTemplateId || "",
1120
+ routeId: O,
1121
+ // default locale
1122
+ defaultLocale: I?.[0],
1123
+ locales: I,
1124
+ publishedAt: u.config.publishedAt,
1125
+ isPublic: w.isPublic && i?.routeMetaData?.isPublic
1126
+ };
1127
+ C(d, m);
1128
+ }
1129
+ }
1130
+ const D = w.path, h = {
1131
+ projectId: R,
1132
+ projectSlug: y,
1133
+ pageSlug: D,
1134
+ pageId: w.displayTemplateId || "",
1135
+ routeId: O,
1136
+ // default locale
1137
+ defaultLocale: I?.[0],
1138
+ locales: I,
1139
+ publishedAt: u.config.publishedAt,
1140
+ isPublic: w.isPublic
1141
+ };
1142
+ C(D, h);
1143
+ }
1144
+ for (const O of u.pageIds || []) {
1145
+ const w = u.pages[O];
1146
+ if (!w) continue;
1147
+ const D = w.slug, h = b.slug || R, S = {
1148
+ projectId: R,
1149
+ projectSlug: h,
1150
+ pageSlug: D,
1151
+ pageId: O,
1152
+ // default locale
1153
+ defaultLocale: I?.[0],
1154
+ locales: I,
1155
+ publishedAt: u.config.publishedAt,
1156
+ isPublic: w.isPublic,
1157
+ templateConfig: w.templateConfig
1158
+ };
1159
+ C(D, S);
1160
+ }
1161
+ o = { ...o, ...g };
1162
+ })
1163
+ )
1164
+ );
1165
+ }
1166
+ }
1167
+ return p.info("[SiteState] success get pageUrlMap"), o;
1168
+ }
1169
+ getDocumentSize() {
1170
+ return F.encodeStateAsUpdate(this).byteLength;
1171
+ }
1172
+ static getInstancesSizeInfo() {
1173
+ const e = [];
1174
+ for (const [s, a] of Object.entries(k.sharedInstances)) {
1175
+ const o = a.getDocumentSize();
1176
+ e.push({
1177
+ projectId: s,
1178
+ sizeInBytes: o,
1179
+ sizeInMB: `${(o / (1024 * 1024)).toFixed(2)} MB`,
1180
+ activeConnections: a.conns.size
1181
+ });
1182
+ }
1183
+ return e;
1184
+ }
1185
+ // 启动定期检查
1186
+ static startPeriodicCheck() {
1187
+ this.periodicCheckTimer || (this.periodicCheckTimer = setInterval(() => {
1188
+ this.performPeriodicCheck();
1189
+ }, this.PERIODIC_CHECK_INTERVAL), p.info(
1190
+ `[SiteState] periodic check started, interval: ${this.PERIODIC_CHECK_INTERVAL / (60 * 60 * 1e3)} hours`
1191
+ ));
1192
+ }
1193
+ // 停止定期检查
1194
+ static stopPeriodicCheck() {
1195
+ this.periodicCheckTimer && (clearInterval(this.periodicCheckTimer), this.periodicCheckTimer = void 0, p.info("[SiteState] periodic check stopped"));
1196
+ }
1197
+ // 执行定期检查
1198
+ static performPeriodicCheck() {
1199
+ const e = Object.keys(k.sharedInstances).length, s = [], a = [];
1200
+ for (const [o, r] of Object.entries(k.sharedInstances))
1201
+ r.conns.size === 0 ? s.push({ projectId: o, instance: r }) : a.push({ projectId: o, connections: r.conns.size });
1202
+ if (p.info(
1203
+ `[SiteState] periodic check summary: total instances: ${e}, with connections: ${a.length}, without connections: ${s.length}`
1204
+ ), s.length > 0) {
1205
+ p.info(
1206
+ `[SiteState] releasing ${s.length} instances without connections:`,
1207
+ s.map((r) => r.projectId)
1208
+ );
1209
+ let o = 0;
1210
+ for (const { projectId: r, instance: l } of s)
1211
+ try {
1212
+ p.info(`[SiteState] releasing instance due to periodic check: ${r}`), l.destroy(), o++;
1213
+ } catch (n) {
1214
+ p.error(`[SiteState] failed to release instance ${r} during periodic check:`, n);
1215
+ }
1216
+ p.info(
1217
+ `[SiteState] periodic check completed: ${o}/${s.length} instances released successfully`
1218
+ );
1219
+ } else e > 0 ? p.debug("[SiteState] periodic check: all instances have active connections") : p.debug("[SiteState] periodic check: no instances exist");
1220
+ }
1221
+ }
1222
+ async function hs(t, e, s) {
1223
+ if (!t || !await G(t) || !(await oe(t)).isFile())
1224
+ return null;
1225
+ let o = s[t];
1226
+ return o || (o = (async () => {
1227
+ try {
1228
+ return (await ps({
1229
+ filePath: t,
1230
+ fileName: e
1231
+ }))?.data?.filename;
1232
+ } catch (r) {
1233
+ return p.error(`Failed to upload asset ${t}:`, r), null;
1234
+ }
1235
+ })(), s[t] = o), o;
1236
+ }
1237
+ const ys = async (t, e) => {
1238
+ const s = $(t), a = await jt({
1239
+ name: Ye,
1240
+ path: x("/uploads", s),
1241
+ responseType: "stream",
1242
+ method: "GET"
1243
+ });
1244
+ if (a.status >= 200 && a.status < 400) {
1245
+ const o = bt(e);
1246
+ await $t(a.data, o);
1247
+ } else
1248
+ throw new Error(`download asset failed ${a.status}`);
1249
+ }, Ss = async (t, e) => {
1250
+ await Promise.all(
1251
+ t.map(async (s) => {
1252
+ try {
1253
+ await ys(s, A(e, $(s)));
1254
+ } catch (a) {
1255
+ p.error(`Failed to export assets: ${s}, ${a}`);
1256
+ }
1257
+ })
1258
+ );
1259
+ };
1260
+ function et(t) {
1261
+ return ve.test(t) ? [t] : X.test(t) ? (Ve.lastIndex = 0, Array.from(t.matchAll(Ve)).map((s) => s[1]).filter((s) => !!s)) : [];
1262
+ }
1263
+ async function ae(t, e, s) {
1264
+ const { getFilename: a, exportAssets: o, useWorker: r } = s, l = A(e, a(t));
1265
+ await B(M(l), { recursive: !0 });
1266
+ const n = r ? await ss(t) : q.stringify(t);
1267
+ if (await re(l, n), o) {
1268
+ const f = ie(
1269
+ t,
1270
+ (b) => typeof b == "string" && (ve.test(b) || X.test(b))
1271
+ ).map((b) => {
1272
+ const R = je(t, b);
1273
+ return et(R);
1274
+ }).flat().filter(Boolean);
1275
+ await Ss(f, M(l));
1276
+ }
1277
+ }
1278
+ const Pe = new Ke({
1279
+ max: 100,
1280
+ ttl: 1 * 60 * 1e3
1281
+ // 1 minute
1282
+ });
1283
+ async function ze(t, e, s) {
1284
+ const a = ie(
1285
+ t,
1286
+ (n) => typeof n == "string" && (ve.test(n) || X.test(n))
1287
+ ), o = Re(2), r = a.map(
1288
+ (n) => o(async () => {
1289
+ try {
1290
+ const c = je(t, n), f = et(c);
1291
+ for (const b of f) {
1292
+ const R = $(b), y = s.getFilePath(b, n), g = y ? `${y}:${R}` : R, u = Pe.get(g);
1293
+ if (u) {
1294
+ X.test(c) || Me(t, n, u);
1295
+ return;
1296
+ }
1297
+ const I = await hs(y, R, e);
1298
+ I && (X.test(c) || Me(t, n, I), Pe.set(g, I));
1299
+ }
1300
+ } catch (c) {
1301
+ p.error(`Failed to process upload for path ${n.join(".")}:`, c.message || c.reason);
1302
+ }
1303
+ })
1304
+ ), l = await Promise.allSettled(r);
1305
+ s.onFinish?.(l);
1306
+ }
1307
+ async function ws(t, {
1308
+ exportAssets: e,
1309
+ pageIds: s = "all",
1310
+ componentIds: a = "all",
1311
+ rawConfig: o,
1312
+ includeResources: r = !1,
1313
+ routeIds: l = "all"
1314
+ } = {}) {
1315
+ const n = s === "all" ? t.pageIds : s, c = Ot({
1316
+ state: t,
1317
+ pageIds: n,
1318
+ componentIds: a === "all" ? Object.keys(t.components) : a
1319
+ });
1320
+ Object.entries(t.components).forEach(([i, d]) => {
1321
+ d.data?.renderer?.type === "component-template" && c.push(i);
1322
+ });
1323
+ const f = l === "all" ? t.routeIds : l, b = (i) => ({
1324
+ id: i.id,
1325
+ name: i.name,
1326
+ isTemplateSection: i.isTemplateSection ?? !1,
1327
+ templateDescription: i.templateDescription,
1328
+ /** @deprecated 已经废弃,llmConfig 从 component / resources.component 中获取 */
1329
+ // llmConfig: section.llmConfig,
1330
+ component: i.component,
1331
+ config: i.config,
1332
+ visibility: i.visibility,
1333
+ sections: i?.sectionIds ? L(
1334
+ i?.sectionIds?.map((d) => {
1335
+ const m = i.sections?.[d];
1336
+ return m && b(m);
1337
+ })
1338
+ ) : void 0
1339
+ /** @deprecated 已经废弃,数据在 page.dataSource 中管理 */
1340
+ // properties: section.locales?.[locale] ?? {},
1341
+ }), R = (i, d) => ({
1342
+ id: i.id,
1343
+ createdAt: i.createdAt,
1344
+ updatedAt: i.updatedAt,
1345
+ publishedAt: i.publishedAt,
1346
+ isPublic: i.isPublic ?? !0,
1347
+ templateConfig: i.templateConfig,
1348
+ meta: i.locales?.[d] ?? {},
1349
+ sections: L(
1350
+ i.sectionIds.map((m) => {
1351
+ const j = i.sections[m];
1352
+ return j && b(j);
1353
+ })
1354
+ ),
1355
+ // 将 dataSource.sectionId.locale 转换为 dataSource.sectionId
1356
+ dataSource: Object.fromEntries(
1357
+ Object.entries(i.dataSource || {}).map(([m, j]) => [m, j?.[d] ?? {}])
1358
+ )
1359
+ }), y = (i) => ({
1360
+ id: i.id,
1361
+ createdAt: i.createdAt,
1362
+ updatedAt: i.updatedAt,
1363
+ publishedAt: i.publishedAt,
1364
+ path: i.path,
1365
+ handler: i.handler,
1366
+ isPublic: i.isPublic ?? !0,
1367
+ params: i.params ?? [],
1368
+ enabledGenerate: i.enabledGenerate ?? !1,
1369
+ displayTemplateId: i.displayTemplateId,
1370
+ dataSource: i.dataSource
1371
+ }), g = L(
1372
+ f.map((i) => {
1373
+ const d = t.routes[i];
1374
+ return d && y(d);
1375
+ })
1376
+ ), u = L(
1377
+ t.supportedLocales.map((i) => i.locale).flatMap(
1378
+ (i) => n.map((d) => {
1379
+ const m = t.pages[d];
1380
+ return m && {
1381
+ locale: i,
1382
+ slug: m.slug,
1383
+ page: R(m, i)
1384
+ };
1385
+ })
1386
+ )
1387
+ ), I = Ze(), C = A(I, "pages");
1388
+ await B(C, { recursive: !0 });
1389
+ const O = A(I, "components");
1390
+ await B(O, { recursive: !0 });
1391
+ const w = A(I, "routes");
1392
+ await B(w, { recursive: !0 });
1393
+ for (const { locale: i, slug: d, page: m } of u)
1394
+ await ae(m, C, {
1395
+ getFilename: () => `${ce(d) || "index"}.${i}.yml`,
1396
+ exportAssets: e,
1397
+ useWorker: !0
1398
+ });
1399
+ for (const i of g)
1400
+ await ae(i, w, {
1401
+ // getFilename: () => `${sanitizeSlug(route.path)}.yml`,
1402
+ getFilename: () => `${ce(i.path) || "index"}.yml`,
1403
+ exportAssets: e
1404
+ });
1405
+ for (const i of c) {
1406
+ const d = t.components[i]?.data;
1407
+ d && await ae(d, O, {
1408
+ getFilename: (m) => `${m.name || "unnamed"}.${m.id}.yml`,
1409
+ exportAssets: e
1410
+ });
1411
+ }
1412
+ const D = A(I, ".blocklet/pages/pages.config.yml");
1413
+ await B(M(D), { recursive: !0 });
1414
+ const h = {
1415
+ pages: L(
1416
+ n.map((i) => {
1417
+ const d = t.pages[i];
1418
+ return d && { id: i, slug: d.slug };
1419
+ })
1420
+ ),
1421
+ routes: L(
1422
+ f.map((i) => {
1423
+ const d = t.routes[i];
1424
+ return d && { id: i, path: d.path };
1425
+ })
1426
+ ),
1427
+ components: L(
1428
+ c.map((i) => {
1429
+ const d = t.components[i]?.data;
1430
+ return d && {
1431
+ id: i,
1432
+ name: d.name
1433
+ };
1434
+ })
1435
+ ),
1436
+ ...r ? {
1437
+ resources: {
1438
+ components: L(
1439
+ Object.keys(t.resources?.components || {}).filter((i) => c.includes(i)).map((i) => ({
1440
+ id: i,
1441
+ name: t.resources?.components?.[i]?.component?.name
1442
+ }))
1443
+ )
1444
+ }
1445
+ } : {},
1446
+ supportedLocales: t.supportedLocales,
1447
+ config: t.config
1448
+ };
1449
+ await re(D, q.stringify(h));
1450
+ const S = A(I, "config.source.json");
1451
+ if (o && await re(S, JSON.stringify(o)), r) {
1452
+ const i = A(I, "resources"), d = A(i, "components");
1453
+ await B(d, { recursive: !0 });
1454
+ for (const N of Object.keys(t?.resources?.components ?? {}).filter(
1455
+ (T) => c.includes(T)
1456
+ )) {
1457
+ const T = t.resources?.components?.[N]?.component;
1458
+ T && await ae(T, d, {
1459
+ getFilename: (V) => `${V.name || "unnamed"}.${V.id}.yml`,
1460
+ exportAssets: e
1461
+ });
1462
+ }
1463
+ const m = A(I, "chunks");
1464
+ await B(m, { recursive: !0 });
1465
+ const j = await Is();
1466
+ for (const N of Object.keys(t?.resources?.components ?? {}).filter(
1467
+ (T) => c.includes(T)
1468
+ )) {
1469
+ const T = t.resources?.components?.[N]?.component;
1470
+ if (T && T.renderer?.type === "react-component") {
1471
+ const V = T.renderer?.chunks ?? [];
1472
+ if (V?.length > 0)
1473
+ for (const H of V) {
1474
+ const Te = A(m, H), de = j?.[H];
1475
+ try {
1476
+ de && await G(de) && !await G(Te) && await Dt(de, Te);
1477
+ } catch (ct) {
1478
+ p.error(`copy chunk ${H} error`, ct.message);
1479
+ }
1480
+ }
1481
+ }
1482
+ }
1483
+ }
1484
+ return I;
1485
+ }
1486
+ async function tt(t, { importAssets: e, includeResources: s } = {}) {
1487
+ if (!await G(t))
1488
+ return null;
1489
+ let a, o = !1;
1490
+ try {
1491
+ (await oe(t)).isDirectory() ? a = t : /\.(tgz|gz|tar)$/.test(t) && (o = !0, a = Ze(), await Ut({ file: t, C: a }));
1492
+ const n = (await ye("**/.blocklet/pages/pages.config.yml", { cwd: a, absolute: !0 }))[0], c = n && A(M(n), "../../pages"), f = n && A(M(n), "../../components"), b = n && A(M(n), "../../routes");
1493
+ if (!n)
1494
+ return null;
1495
+ const R = await te(n, "utf-8"), y = q.parse(R), g = async (h, S, i) => {
1496
+ let d = A(h, `${S}${i ? `.${i}` : ""}.yml`);
1497
+ if (!await G(d) && (d = A(h, S, `index${i ? `.${i}` : ""}.yml`), !await G(d)) || !(await oe(d)).isFile())
1498
+ return null;
1499
+ const j = await te(d, "utf-8");
1500
+ return q.parse(j);
1501
+ }, u = async (h, S) => {
1502
+ try {
1503
+ const d = (await ye(`*.${S}.yml`, { cwd: h, absolute: !0 }))[0];
1504
+ if (!d) return null;
1505
+ const m = await te(d, "utf-8");
1506
+ return q.parse(m);
1507
+ } catch (i) {
1508
+ p.error("parse component error", i);
1509
+ }
1510
+ return null;
1511
+ }, I = async (h, S) => {
1512
+ let i = A(h, `${S}.yml`);
1513
+ if (!await G(i) && (i = A(h, S, "index.yml"), !await G(i)) || !(await oe(i)).isFile())
1514
+ return null;
1515
+ const m = await te(i, "utf-8");
1516
+ return q.parse(m);
1517
+ }, C = L(
1518
+ await Promise.all(
1519
+ y.pages.map(async ({ slug: h }) => {
1520
+ const S = L(
1521
+ await Promise.all(
1522
+ y.supportedLocales.map(async ({ locale: m }) => {
1523
+ const j = c ? await g(c, ce(h), m) : void 0;
1524
+ if (j)
1525
+ return { locale: m, page: j };
1526
+ const N = c ? await g(c, h, m) : void 0;
1527
+ return N && { locale: m, page: N };
1528
+ })
1529
+ )
1530
+ ), i = S[0]?.page;
1531
+ if (!i)
1532
+ return null;
1533
+ const d = i.sections.map(Et);
1534
+ return {
1535
+ id: i.id || Ue(),
1536
+ createdAt: i.createdAt,
1537
+ updatedAt: i.updatedAt,
1538
+ publishedAt: i.publishedAt,
1539
+ isPublic: i.isPublic ?? !0,
1540
+ templateConfig: i.templateConfig,
1541
+ slug: h,
1542
+ sections: Object.fromEntries(d.map((m) => [m.id, m])),
1543
+ sectionIds: d.map((m) => m.id),
1544
+ locales: Object.fromEntries(S.map(({ locale: m, page: j }) => [m, j.meta])),
1545
+ dataSource: i.dataSource ? Object.fromEntries(
1546
+ // 获取 dataSource 中所有 section ID
1547
+ [...new Set(S.flatMap(({ page: m }) => Object.keys(m.dataSource ?? {})))].map((m) => [
1548
+ m,
1549
+ Object.fromEntries(
1550
+ S.map(({ locale: j, page: N }) => {
1551
+ const T = N.dataSource?.[m];
1552
+ return [j, T || {}];
1553
+ })
1554
+ )
1555
+ ])
1556
+ ) : Object.fromEntries(
1557
+ // 获取所有 section ID
1558
+ [...new Set(S.flatMap(({ page: m }) => m.sections.map((j) => j.id)))].map((m) => [
1559
+ m,
1560
+ Object.fromEntries(
1561
+ S.map(({ locale: j, page: N }) => {
1562
+ const T = N.dataSource?.[m];
1563
+ if (T)
1564
+ return [j, T];
1565
+ const V = N.sections.find((H) => H.id === m);
1566
+ return [j, V?.properties || {}];
1567
+ })
1568
+ )
1569
+ ])
1570
+ )
1571
+ };
1572
+ })
1573
+ )
1574
+ ), O = L(
1575
+ await Promise.all(
1576
+ (y?.routes || []).map(async ({ path: h }) => {
1577
+ const S = b ? await I(b, ce(h)) : void 0;
1578
+ return {
1579
+ ...S,
1580
+ id: S?.id || Ue(),
1581
+ createdAt: S?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
1582
+ updatedAt: S?.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
1583
+ publishedAt: (/* @__PURE__ */ new Date(0)).toISOString(),
1584
+ path: S?.path ?? `/${S?.id}`,
1585
+ params: S?.params,
1586
+ handler: S?.handler ?? "Pages Kit",
1587
+ isPublic: S?.isPublic ?? !0,
1588
+ enabledGenerate: S?.enabledGenerate ?? !1,
1589
+ displayTemplateId: S?.displayTemplateId ?? void 0,
1590
+ dataSource: S?.dataSource ?? {}
1591
+ };
1592
+ })
1593
+ )
1594
+ ), w = f ? L(
1595
+ await Promise.all((y.components || []).map(async ({ id: h }) => u(f, h)))
1596
+ ) : [];
1597
+ if (e) {
1598
+ const h = (...S) => {
1599
+ p.info(`[${o ? $(t) : $(A(t, "../../../../"))}] importAssets:`, ...S);
1600
+ };
1601
+ try {
1602
+ h("wait image-bin api ready"), await Nt({
1603
+ resources: [`${Rt(ut)}/api/sdk/uploads`],
1604
+ validateStatus: (d) => d >= 200 && d <= 500
1605
+ }), h("image-bin api is ready");
1606
+ const S = {}, i = {};
1607
+ h("start to upload assets"), await Promise.allSettled([
1608
+ ze(w, S, {
1609
+ getFilePath: (d) => f && A(f, d),
1610
+ onFinish: (d) => {
1611
+ h(`upload ${d.length} component assets`);
1612
+ }
1613
+ }),
1614
+ ze(C, i, {
1615
+ getFilePath: (d, m) => {
1616
+ const j = je(C, m.slice(0, 1));
1617
+ return c && A(c, M(j.slug), d);
1618
+ },
1619
+ onFinish: (d) => {
1620
+ h(`upload ${d.length} page assets`);
1621
+ }
1622
+ })
1623
+ ]), h("upload assets done"), Pe.clear(), global.gc && global.gc();
1624
+ } catch (S) {
1625
+ h("Error during asset import:", S);
1626
+ }
1627
+ }
1628
+ const D = {};
1629
+ if (s) {
1630
+ const h = n && A(M(n), "../../resources/components"), S = L(
1631
+ await Promise.all(
1632
+ (y.resources?.components || []).map(async ({ id: i }) => u(h, i))
1633
+ )
1634
+ );
1635
+ S.length > 0 && (D.components = Object.fromEntries(
1636
+ S.map((i, d) => [i.id, { index: d, component: i }])
1637
+ ));
1638
+ }
1639
+ return {
1640
+ supportedLocales: y.supportedLocales,
1641
+ pageIds: C.map((h) => h.id),
1642
+ components: Object.fromEntries(w.map((h, S) => [h.id, { index: S, data: h }])),
1643
+ pages: Object.fromEntries(C.map((h) => [h.id, h])),
1644
+ config: y.config || {},
1645
+ resources: D,
1646
+ routeIds: O.map((h) => h.id),
1647
+ routes: Object.fromEntries(O.map((h) => [h.id, h])),
1648
+ dataSourceIds: [],
1649
+ dataSources: {}
1650
+ };
1651
+ } finally {
1652
+ o && a && await We(a, { force: !0, recursive: !0 });
1653
+ }
1654
+ }
1655
+ async function qe(t, e, {
1656
+ routes: s,
1657
+ mergeMode: a = "byUpdateTime",
1658
+ deleteRoutes: o = !1,
1659
+ publishMode: r = void 0
1660
+ } = {}) {
1661
+ try {
1662
+ r && dt(r);
1663
+ } catch (y) {
1664
+ p.error("clear preload page cache error", { error: y });
1665
+ }
1666
+ const { pages: l, pageIds: n, routeIds: c, routes: f, supportedLocales: b } = t;
1667
+ if (r === "production") {
1668
+ let y = s ?? [], g = null;
1669
+ for (const u of c ?? []) {
1670
+ const I = f?.[u];
1671
+ if (I?.params && I?.params.length > 0 && I?.paramsOptions && I?.paramsOptions.length > 0) {
1672
+ const C = be({
1673
+ basePath: I.path,
1674
+ params: I.params,
1675
+ routeId: I.id,
1676
+ paramsOptions: I.paramsOptions,
1677
+ currentIndex: 0,
1678
+ currentParams: [],
1679
+ currentOptionIds: [],
1680
+ result: []
1681
+ }), O = Object.fromEntries(C.map((w) => [`${u}-${w.paramOptionIds.join("-")}`, w]));
1682
+ g = { ...g || {}, ...O }, s || (y = [...y, ...C.map((w) => `${u}-${w.paramOptionIds.join("-")}`)]);
1683
+ } else s || y.push(u);
1684
+ }
1685
+ p.info("routeIds to be published: ", y);
1686
+ for (const u of y) {
1687
+ let I = u;
1688
+ if (I.includes("-")) {
1689
+ const [w] = I.split("-");
1690
+ I = w;
1691
+ }
1692
+ const C = f?.[I];
1693
+ if (!C) {
1694
+ const w = e.pageIds.indexOf(I);
1695
+ w !== -1 && o && (e.pageIds.splice(w, 1), delete e.pages[I]);
1696
+ for (const D of e.pageIds)
1697
+ D.includes(`${I}-`) && (e.pageIds.splice(e.pageIds.indexOf(D), 1), delete e.pages[D]);
1698
+ p.info("delete main route page", I);
1699
+ continue;
1700
+ }
1701
+ if (u.includes("-") && !g?.[u]) {
1702
+ const w = e.pageIds.indexOf(u);
1703
+ w !== -1 && o && (e.pageIds.splice(w, 1), delete e.pages[u]), p.info("delete page", u);
1704
+ continue;
1705
+ }
1706
+ if (!C.displayTemplateId) {
1707
+ p.info("no display template", u);
1708
+ continue;
1709
+ }
1710
+ const O = l[C.displayTemplateId];
1711
+ if (!O) {
1712
+ p.info("no template page", u);
1713
+ continue;
1714
+ }
1715
+ if (e.pageIds.includes(u)) {
1716
+ if (p.info("has need update page", u), a === "replace")
1717
+ e.pages[u] = me({
1718
+ page: O,
1719
+ route: C,
1720
+ state: t,
1721
+ routeId: u,
1722
+ routePathInfo: g?.[u]
1723
+ }), p.info("replace page", u);
1724
+ else if (a === "byUpdateTime") {
1725
+ const w = e.pages[C.id];
1726
+ (!w || C.updatedAt && C.updatedAt > w.updatedAt) && (e.pages[u] = me({
1727
+ page: O,
1728
+ route: C,
1729
+ state: t,
1730
+ routeId: u,
1731
+ routePathInfo: g?.[u]
1732
+ }), p.info("replace page by update time", u));
1733
+ }
1734
+ } else
1735
+ e.pageIds.push(u), e.pages[u] = me({
1736
+ page: O,
1737
+ route: C,
1738
+ state: t,
1739
+ routeId: u,
1740
+ routePathInfo: g?.[u]
1741
+ }), p.info("add page", u);
1742
+ }
1743
+ if (o && !s)
1744
+ for (const u of e.pageIds)
1745
+ y?.includes(u) || (delete e.pages[u], p.info("delete page", u)), e.pageIds = [...e.pageIds].filter((I) => y?.includes(I));
1746
+ } else {
1747
+ for (const y of n) {
1748
+ const g = l[y];
1749
+ if (g)
1750
+ if (e.pageIds.includes(g.id)) {
1751
+ if (a === "replace")
1752
+ e.pages[g.id] = g;
1753
+ else if (a === "byUpdateTime") {
1754
+ const u = e.pages[g.id];
1755
+ (!u || g.updatedAt && g.updatedAt > u.updatedAt) && (e.pages[g.id] = g);
1756
+ }
1757
+ } else
1758
+ e.pageIds.push(g.id), e.pages[g.id] = g;
1759
+ }
1760
+ for (const y of c) {
1761
+ const g = f[y];
1762
+ if (g)
1763
+ if (e.routeIds.includes(g.id)) {
1764
+ if (a === "replace")
1765
+ e.routes[g.id] = g;
1766
+ else if (a === "byUpdateTime") {
1767
+ const u = e.routes[g.id];
1768
+ (!u || g.updatedAt && g.updatedAt > u.updatedAt) && (e.routes[g.id] = g);
1769
+ }
1770
+ } else
1771
+ e.routeIds.push(g.id), e.routes[g.id] = g;
1772
+ }
1773
+ }
1774
+ if (e.supportedLocales.splice(0, e.supportedLocales.length), e.supportedLocales.push(...Ae(b)), o)
1775
+ for (const y of Object.keys(e.components))
1776
+ delete e.components[y];
1777
+ let R = JSON.parse(JSON.stringify(t.components));
1778
+ R = Object.fromEntries(
1779
+ await Promise.all(
1780
+ Object.entries(R).map(async ([y, g]) => {
1781
+ const u = await st(g?.data);
1782
+ return [
1783
+ y,
1784
+ {
1785
+ ...g,
1786
+ data: u
1787
+ }
1788
+ ];
1789
+ })
1790
+ )
1791
+ ), Object.assign(e.components, R), Object.assign(e.config, JSON.parse(JSON.stringify(t.config))), ke(t.resources.components) || (e.resources.components = JSON.parse(JSON.stringify(t.resources.components || {})));
1792
+ }
1793
+ const st = lt(
1794
+ async (t) => {
1795
+ if (!ke(t?.properties))
1796
+ return t;
1797
+ if (t?.renderer?.type === "react-component") {
1798
+ const { script: e, PROPERTIES_SCHEMA: s } = t?.renderer || {};
1799
+ if (s || e && e.includes("PROPERTIES_SCHEMA"))
1800
+ try {
1801
+ const a = await pt(
1802
+ e ?? "",
1803
+ "PROPERTIES_SCHEMA",
1804
+ t.id,
1805
+ s
1806
+ );
1807
+ a && a.length > 0 && t && (t.properties = {}, a.forEach((o, r) => {
1808
+ t?.properties && (t.properties[o.id] = {
1809
+ index: r,
1810
+ data: o
1811
+ });
1812
+ }));
1813
+ } catch (a) {
1814
+ p.error("getPropertiesFromCode error", { componentId: t.id, name: t.name }, { error: a });
1815
+ }
1816
+ }
1817
+ return t;
1818
+ },
1819
+ {
1820
+ subdir: "getPropertiesFromCode"
1821
+ }
1822
+ );
1823
+ let le, Q, pe, ue;
1824
+ const at = () => Ct({
1825
+ types: [
1826
+ { did: Ye, type: xe },
1827
+ { did: Jt, type: xe }
1828
+ ]
1829
+ }), Is = async () => {
1830
+ const t = at(), e = {};
1831
+ for (const s of t) {
1832
+ const o = (await ye("**/.blocklet/pages/pages.config.yml", {
1833
+ cwd: s.path,
1834
+ absolute: !0
1835
+ }))[0], r = o && A(M(o), "../../chunks");
1836
+ if (r && await G(r)) {
1837
+ const l = await vt(r);
1838
+ for (const n of l)
1839
+ e[n] = A(r, n);
1840
+ }
1841
+ }
1842
+ return e;
1843
+ };
1844
+ function ot() {
1845
+ return le = (async () => {
1846
+ const t = at();
1847
+ Q = (await Promise.all(
1848
+ t.map(async (s) => {
1849
+ const a = s.path ? await tt(s.path, { importAssets: !1 }) : void 0;
1850
+ return a ? { blockletId: s.did, state: a, blockletTitle: s.title } : void 0;
1851
+ })
1852
+ )).filter((s) => !!s), pe = Q.reduce(
1853
+ (s, a) => Object.assign(
1854
+ s,
1855
+ Object.fromEntries(
1856
+ Object.values(a.state.pages).map((o) => o ? [o?.id, { page: o, blockletId: a.blockletId }] : [])
1857
+ )
1858
+ ),
1859
+ {}
1860
+ );
1861
+ const e = Q.reduce(
1862
+ (s, a) => Object.assign(
1863
+ s,
1864
+ Object.fromEntries(
1865
+ Object.values(a.state.components).map((o) => [o.data.id, { blockletId: a.blockletId, component: o.data }])
1866
+ )
1867
+ ),
1868
+ {}
1869
+ );
1870
+ ue = Object.fromEntries(
1871
+ await Promise.all(
1872
+ Object.entries(e).map(async ([s, a]) => {
1873
+ const o = await st(a.component);
1874
+ return [
1875
+ s,
1876
+ {
1877
+ ...a,
1878
+ component: o
1879
+ }
1880
+ ];
1881
+ })
1882
+ )
1883
+ );
1884
+ })(), le;
1885
+ }
1886
+ function Ps(t) {
1887
+ const e = Ce(
1888
+ async () => {
1889
+ await ot().catch((s) => {
1890
+ p.error("load resource states error", { error: s });
1891
+ }), await t?.({
1892
+ states: Q,
1893
+ pages: pe,
1894
+ components: ue
1895
+ });
1896
+ },
1897
+ 3e3,
1898
+ // 3s
1899
+ { leading: !1, trailing: !0 }
1900
+ );
1901
+ return e(), E.events.on(E.Events.componentAdded, e), E.events.on(E.Events.componentRemoved, e), E.events.on(E.Events.componentStarted, e), E.events.on(E.Events.componentStopped, e), E.events.on(E.Events.componentUpdated, e), E.events.on(we, e), () => {
1902
+ E.events.off(E.Events.componentAdded, e), E.events.off(E.Events.componentRemoved, e), E.events.off(E.Events.componentStarted, e), E.events.off(E.Events.componentStopped, e), E.events.off(E.Events.componentUpdated, e), E.events.off(we, e);
1903
+ };
1904
+ }
1905
+ const rt = Symbol.for("GLOBAL_RESOURCE_STATES_LISTENER_KEY"), nt = globalThis;
1906
+ nt[rt]?.();
1907
+ nt[rt] = Ps(async ({ pages: t, components: e }) => {
1908
+ const s = await k.getProjectIds();
1909
+ p.info(`start update resource states projects(${s.length})`, s);
1910
+ const a = Re(10);
1911
+ await Promise.race([
1912
+ new Promise((o) => {
1913
+ setTimeout(() => {
1914
+ o({});
1915
+ }, 30 * 1e3);
1916
+ }),
1917
+ Promise.all(
1918
+ s.map(
1919
+ (o) => a(async () => {
1920
+ it({
1921
+ projectId: o,
1922
+ pages: t,
1923
+ components: e
1924
+ });
1925
+ })
1926
+ )
1927
+ )
1928
+ ]).catch((o) => {
1929
+ p.error("update resource states failed:", o);
1930
+ });
1931
+ });
1932
+ k.startPeriodicCheck();
1933
+ process.on("beforeExit", () => {
1934
+ k.stopPeriodicCheck();
1935
+ });
1936
+ process.on("SIGINT", () => {
1937
+ k.stopPeriodicCheck(), process.exit(0);
1938
+ });
1939
+ process.on("SIGTERM", () => {
1940
+ k.stopPeriodicCheck(), process.exit(0);
1941
+ });
1942
+ async function it({
1943
+ projectId: t,
1944
+ pages: e,
1945
+ components: s
1946
+ }) {
1947
+ const a = k.sharedInstances[t];
1948
+ if (!a) {
1949
+ p.info(`projectId: ${t} not found in sharedInstances`);
1950
+ return;
1951
+ }
1952
+ const o = a.syncedStore.resources.pages, r = a.syncedStore.resources.components, l = await U.findByPk(t, {
1953
+ attributes: { exclude: ["productionState", "relatedBlocklets"] }
1954
+ });
1955
+ let n;
1956
+ if (l?.useAllResources)
1957
+ n = s;
1958
+ else {
1959
+ const R = (await De.findAll({ where: { projectId: t } })).map((y) => y.componentId);
1960
+ n = Object.fromEntries(Object.entries(s || {}).filter(([y]) => R.includes(y)));
1961
+ }
1962
+ const c = !Ge(o, e), f = !Ge(r, n);
1963
+ c || f ? a.transact(() => {
1964
+ c && (a.syncedStore.resources.pages = e, p.info(`[${t}] pages resources updated: ${Object.keys(e || {}).length} pages`)), f && (a.syncedStore.resources.components = n, p.info(
1965
+ `[${t}] components resources updated: ${Object.keys(n || {}).length} components`
1966
+ ));
1967
+ }) : p.info(`[${t}] resource states unchanged, skipping update`), p.info(`update [${t}] resource states summary:`, {
1968
+ pages: Object.keys(a.syncedStore.resources.pages || {}).length,
1969
+ components: Object.keys(a.syncedStore.resources.components || {}).length,
1970
+ pagesChanged: c,
1971
+ componentsChanged: f
1972
+ });
1973
+ }
1974
+ const he = /* @__PURE__ */ new Map();
1975
+ async function bs(t) {
1976
+ if (!he.has(t)) {
1977
+ const e = Ce(async (s) => it({
1978
+ projectId: s,
1979
+ pages: pe,
1980
+ components: ue
1981
+ }), 3e3);
1982
+ he.set(t, e);
1983
+ }
1984
+ return he.get(t)(t);
1985
+ }
1986
+ async function ia() {
1987
+ p.info("trigger reload all project resource"), E.events.emit(we);
1988
+ }
1989
+ async function ca({
1990
+ ensureLoaded: t = !0
1991
+ } = {}) {
1992
+ return t && (le ??= ot(), await le), { states: Q, pages: pe, components: ue };
1993
+ }
1994
+ export {
1995
+ Ye as C,
1996
+ U as P,
1997
+ xe as R,
1998
+ k as S,
1999
+ K as a,
2000
+ ra as b,
2001
+ oa as c,
2002
+ na as d,
2003
+ gs as e,
2004
+ ys as f,
2005
+ ca as g,
2006
+ Ss as h,
2007
+ tt as i,
2008
+ Ps as j,
2009
+ ia as k,
2010
+ qe as m,
2011
+ ws as t,
2012
+ bs as u
2013
+ };