@allbluecn/shared 0.3.13 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/dist/config-CcbSbJoC.js +6344 -0
  2. package/dist/constants/perf.d.ts +6 -0
  3. package/dist/constants/perf.js +6 -0
  4. package/dist/constants-C3hGP_ru.d.ts +33 -0
  5. package/dist/i18n/client.d.ts +5 -0
  6. package/dist/i18n/client.js +34 -0
  7. package/dist/i18n/config.d.ts +6270 -0
  8. package/dist/i18n/config.js +2 -0
  9. package/dist/i18n/detect.d.ts +5 -0
  10. package/dist/i18n/detect.js +35 -0
  11. package/dist/i18n/server.d.ts +6 -0
  12. package/dist/i18n/server.js +19 -0
  13. package/dist/i18n/types.d.ts +3 -0
  14. package/dist/i18n/types.js +0 -0
  15. package/dist/index.d.ts +18 -0
  16. package/dist/index.js +14 -0
  17. package/dist/infrastructure/ai/adapter.d.ts +8 -0
  18. package/dist/infrastructure/ai/adapter.js +32 -0
  19. package/dist/infrastructure/ai/cli-detector.d.ts +6 -0
  20. package/dist/infrastructure/ai/cli-detector.js +121 -0
  21. package/dist/infrastructure/ip-location.d.ts +9 -0
  22. package/dist/infrastructure/ip-location.js +48 -0
  23. package/dist/infrastructure/references/engine.d.ts +7 -0
  24. package/dist/infrastructure/references/engine.js +64 -0
  25. package/dist/infrastructure/ua-parser.d.ts +20 -0
  26. package/dist/infrastructure/ua-parser.js +69 -0
  27. package/dist/interfaces/ai.d.ts +27 -0
  28. package/dist/interfaces/ai.js +0 -0
  29. package/dist/interfaces/avatar.d.ts +6 -0
  30. package/dist/interfaces/avatar.js +0 -0
  31. package/dist/interfaces/module.d.ts +45 -0
  32. package/dist/interfaces/module.js +0 -0
  33. package/dist/interfaces/references.d.ts +27 -0
  34. package/dist/interfaces/references.js +0 -0
  35. package/dist/interfaces/transport.d.ts +11 -0
  36. package/dist/interfaces/transport.js +0 -0
  37. package/dist/lib/annotation-template.d.ts +9 -0
  38. package/dist/lib/annotation-template.js +14 -0
  39. package/dist/lib/comment-utils.d.ts +7 -0
  40. package/dist/lib/comment-utils.js +27 -0
  41. package/dist/lib/datetime.d.ts +25 -0
  42. package/dist/lib/datetime.js +73 -0
  43. package/dist/lib/desktop-detect.d.ts +13 -0
  44. package/dist/lib/desktop-detect.js +23 -0
  45. package/dist/lib/outline-utils.d.ts +6 -0
  46. package/dist/lib/outline-utils.js +46 -0
  47. package/dist/lib/pacer.d.ts +45 -0
  48. package/dist/lib/pacer.js +70 -0
  49. package/dist/lib/prd/stack-layout.d.ts +18 -0
  50. package/dist/lib/prd/stack-layout.js +24 -0
  51. package/dist/lib/prd-tree-utils.d.ts +21 -0
  52. package/dist/lib/prd-tree-utils.js +62 -0
  53. package/dist/lib/prototype-registry.d.ts +2 -0
  54. package/dist/lib/prototype-registry.js +2 -0
  55. package/dist/lib/query-client-seam.d.ts +6 -0
  56. package/dist/lib/query-client-seam.js +11 -0
  57. package/dist/lib/share-events.d.ts +7 -0
  58. package/dist/lib/share-events.js +47 -0
  59. package/dist/lib/sidebar-utils.d.ts +4 -0
  60. package/dist/lib/sidebar-utils.js +7 -0
  61. package/dist/lib/stores/prd-canvas-store.d.ts +16 -0
  62. package/dist/lib/stores/prd-canvas-store.js +42 -0
  63. package/dist/lib/tag-colors.d.ts +12 -0
  64. package/dist/lib/tag-colors.js +74 -0
  65. package/dist/lib/time-format.d.ts +4 -0
  66. package/dist/lib/time-format.js +20 -0
  67. package/dist/modules/ai-providers/constants.d.ts +2 -0
  68. package/dist/modules/ai-providers/constants.js +125 -0
  69. package/dist/modules/ai-providers/index.d.ts +4 -0
  70. package/dist/modules/ai-providers/index.js +4 -0
  71. package/dist/modules/ai-providers/seed-data.d.ts +2 -0
  72. package/dist/modules/ai-providers/seed-data.js +408 -0
  73. package/dist/modules/ai-providers/types.d.ts +2 -0
  74. package/dist/modules/ai-providers/types.js +10 -0
  75. package/dist/modules/billing/feature-registry.d.ts +72 -0
  76. package/dist/modules/billing/feature-registry.js +67 -0
  77. package/dist/modules/billing/plan-features-schema.d.ts +6 -0
  78. package/dist/modules/billing/plan-features-schema.js +6 -0
  79. package/dist/modules/billing/resource-registry.d.ts +59 -0
  80. package/dist/modules/billing/resource-registry.js +47 -0
  81. package/dist/modules/definitions/plugin.module.d.ts +5 -0
  82. package/dist/modules/definitions/plugin.module.js +24 -0
  83. package/dist/modules/definitions/prd.module.d.ts +5 -0
  84. package/dist/modules/definitions/prd.module.js +26 -0
  85. package/dist/modules/definitions/prototype.module.d.ts +5 -0
  86. package/dist/modules/definitions/prototype.module.js +20 -0
  87. package/dist/modules/dependencies/index.d.ts +92 -0
  88. package/dist/modules/dependencies/index.js +334 -0
  89. package/dist/modules/register-defaults.d.ts +4 -0
  90. package/dist/modules/register-defaults.js +12 -0
  91. package/dist/modules/registry.d.ts +17 -0
  92. package/dist/modules/registry.js +27 -0
  93. package/dist/seed-data-BK0cl93n.d.ts +6 -0
  94. package/dist/server-seam.d.ts +19 -0
  95. package/dist/server-seam.js +11 -0
  96. package/dist/types/outline.d.ts +10 -0
  97. package/dist/types/outline.js +0 -0
  98. package/dist/types/prd.d.ts +48 -0
  99. package/dist/types/prd.js +37 -0
  100. package/dist/types/prototype.d.ts +2 -0
  101. package/dist/types/prototype.js +2 -0
  102. package/dist/types-dopOMFRC.d.ts +61 -0
  103. package/dist/virtual.d.ts +1 -0
  104. package/package.json +133 -37
  105. package/src/constants/perf.ts +0 -21
  106. package/src/i18n/client.ts +0 -32
  107. package/src/i18n/config.ts +0 -104
  108. package/src/i18n/detect.ts +0 -43
  109. package/src/i18n/locales/en/agents.json +0 -134
  110. package/src/i18n/locales/en/apps.json +0 -6
  111. package/src/i18n/locales/en/auth.json +0 -88
  112. package/src/i18n/locales/en/billing.json +0 -78
  113. package/src/i18n/locales/en/chat.json +0 -194
  114. package/src/i18n/locales/en/common.json +0 -203
  115. package/src/i18n/locales/en/dashboard.json +0 -38
  116. package/src/i18n/locales/en/design.json +0 -70
  117. package/src/i18n/locales/en/desktop.json +0 -35
  118. package/src/i18n/locales/en/display.json +0 -37
  119. package/src/i18n/locales/en/editor.json +0 -304
  120. package/src/i18n/locales/en/enterprise.json +0 -1
  121. package/src/i18n/locales/en/invite.json +0 -11
  122. package/src/i18n/locales/en/knowledge.json +0 -451
  123. package/src/i18n/locales/en/mindmap.json +0 -28
  124. package/src/i18n/locales/en/prd.json +0 -43
  125. package/src/i18n/locales/en/projects.json +0 -133
  126. package/src/i18n/locales/en/settings.json +0 -375
  127. package/src/i18n/locales/en/share.json +0 -20
  128. package/src/i18n/locales/en/story.json +0 -785
  129. package/src/i18n/locales/en/tags.json +0 -42
  130. package/src/i18n/locales/en/workspace.json +0 -90
  131. package/src/i18n/locales/zh/agents.json +0 -134
  132. package/src/i18n/locales/zh/apps.json +0 -6
  133. package/src/i18n/locales/zh/auth.json +0 -88
  134. package/src/i18n/locales/zh/billing.json +0 -78
  135. package/src/i18n/locales/zh/chat.json +0 -194
  136. package/src/i18n/locales/zh/common.json +0 -203
  137. package/src/i18n/locales/zh/dashboard.json +0 -38
  138. package/src/i18n/locales/zh/design.json +0 -70
  139. package/src/i18n/locales/zh/desktop.json +0 -35
  140. package/src/i18n/locales/zh/display.json +0 -37
  141. package/src/i18n/locales/zh/editor.json +0 -304
  142. package/src/i18n/locales/zh/enterprise.json +0 -1
  143. package/src/i18n/locales/zh/invite.json +0 -11
  144. package/src/i18n/locales/zh/knowledge.json +0 -451
  145. package/src/i18n/locales/zh/mindmap.json +0 -28
  146. package/src/i18n/locales/zh/prd.json +0 -43
  147. package/src/i18n/locales/zh/projects.json +0 -133
  148. package/src/i18n/locales/zh/settings.json +0 -375
  149. package/src/i18n/locales/zh/share.json +0 -20
  150. package/src/i18n/locales/zh/story.json +0 -785
  151. package/src/i18n/locales/zh/tags.json +0 -42
  152. package/src/i18n/locales/zh/workspace.json +0 -90
  153. package/src/i18n/server.ts +0 -18
  154. package/src/i18n/types.ts +0 -5
  155. package/src/index.ts +0 -90
  156. package/src/infrastructure/ai/adapter.ts +0 -59
  157. package/src/infrastructure/ai/cli-detector.ts +0 -64
  158. package/src/infrastructure/ip-location.ts +0 -76
  159. package/src/infrastructure/references/engine.ts +0 -104
  160. package/src/infrastructure/ua-parser.ts +0 -107
  161. package/src/interfaces/ai.ts +0 -38
  162. package/src/interfaces/avatar.ts +0 -22
  163. package/src/interfaces/module.ts +0 -60
  164. package/src/interfaces/references.ts +0 -44
  165. package/src/interfaces/transport.ts +0 -26
  166. package/src/lib/annotation-template.ts +0 -33
  167. package/src/lib/comment-utils.ts +0 -47
  168. package/src/lib/datetime.ts +0 -115
  169. package/src/lib/desktop-detect.ts +0 -27
  170. package/src/lib/outline-utils.ts +0 -57
  171. package/src/lib/pacer.ts +0 -96
  172. package/src/lib/prd/stack-layout.ts +0 -53
  173. package/src/lib/prd-tree-utils.ts +0 -94
  174. package/src/lib/prototype-registry.ts +0 -24
  175. package/src/lib/query-client-seam.ts +0 -14
  176. package/src/lib/share-events.ts +0 -78
  177. package/src/lib/sidebar-utils.ts +0 -21
  178. package/src/lib/stores/prd-canvas-store.ts +0 -69
  179. package/src/lib/tag-colors.ts +0 -35
  180. package/src/lib/time-format.ts +0 -50
  181. package/src/modules/ai-providers/constants.ts +0 -79
  182. package/src/modules/ai-providers/index.ts +0 -21
  183. package/src/modules/ai-providers/seed-data.ts +0 -222
  184. package/src/modules/ai-providers/types.ts +0 -95
  185. package/src/modules/billing/feature-registry.ts +0 -63
  186. package/src/modules/billing/plan-features-schema.ts +0 -11
  187. package/src/modules/billing/resource-registry.ts +0 -80
  188. package/src/modules/definitions/plugin.module.ts +0 -38
  189. package/src/modules/definitions/prd.module.ts +0 -45
  190. package/src/modules/definitions/prototype.module.ts +0 -38
  191. package/src/modules/dependencies/index.ts +0 -186
  192. package/src/modules/register-defaults.ts +0 -27
  193. package/src/modules/registry.ts +0 -53
  194. package/src/server-seam.ts +0 -51
  195. package/src/types/outline.ts +0 -26
  196. package/src/types/prd.ts +0 -90
  197. package/src/types/prototype.ts +0 -12
  198. package/src/virtual.d.ts +0 -4
@@ -0,0 +1,14 @@
1
+ import { DOMParser } from "@tiptap/pm/model";
2
+ //#region src/lib/annotation-template.ts
3
+ /**
4
+ * 将 HTML 字符串转为 ProseMirror content 节点数组(用于 insertContent 的 content 字段)。
5
+ * 客户端调用(onAnnotate 事件触发),document 可用。
6
+ */
7
+ function htmlToPmContent(editor, html) {
8
+ if (typeof document === "undefined" || !html) return [{ type: "paragraph" }];
9
+ const wrapper = document.createElement("div");
10
+ wrapper.innerHTML = html;
11
+ return DOMParser.fromSchema(editor.schema).parse(wrapper).toJSON().content ?? [{ type: "paragraph" }];
12
+ }
13
+ //#endregion
14
+ export { htmlToPmContent };
@@ -0,0 +1,7 @@
1
+ //#region src/lib/comment-utils.d.ts
2
+ declare function maskEmail(email?: string | null): string;
3
+ declare function formatTime(date: Date | string): string;
4
+ declare function formatEditedTime(date: Date | string): string;
5
+ declare function getUserInitial(username: string): string;
6
+ //#endregion
7
+ export { formatEditedTime, formatTime, getUserInitial, maskEmail };
@@ -0,0 +1,27 @@
1
+ //#region src/lib/comment-utils.ts
2
+ function maskEmail(email) {
3
+ if (!email) return "未知用户";
4
+ const [local, domain] = email.split("@");
5
+ if (!domain) return email;
6
+ return `${local.length > 3 ? local.slice(0, 3) : local}***@${domain}`;
7
+ }
8
+ function formatTime(date) {
9
+ const d = new Date(date);
10
+ const diff = (/* @__PURE__ */ new Date()).getTime() - d.getTime();
11
+ const minutes = Math.floor(diff / 6e4);
12
+ if (minutes < 1) return "刚刚";
13
+ if (minutes < 60) return `${minutes}分钟前`;
14
+ const hours = Math.floor(minutes / 60);
15
+ if (hours < 24) return `${hours}小时前`;
16
+ const days = Math.floor(hours / 24);
17
+ if (days < 7) return `${days}天前`;
18
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")} ${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`;
19
+ }
20
+ function formatEditedTime(date) {
21
+ return `修改于${formatTime(date)}`;
22
+ }
23
+ function getUserInitial(username) {
24
+ return (username || "?").charAt(0).toUpperCase();
25
+ }
26
+ //#endregion
27
+ export { formatEditedTime, formatTime, getUserInitial, maskEmail };
@@ -0,0 +1,25 @@
1
+ //#region src/lib/datetime.d.ts
2
+ /**
3
+ * 解析生效时区:项目时区 > 用户时区 > 浏览器时区 > Asia/Shanghai
4
+ */
5
+ declare function resolveTimezone(projectTz?: string | null, userTz?: string | null): string;
6
+ /**
7
+ * 时区感知的时间格式化。
8
+ * @param date UTC Date 对象(来自 DB)
9
+ * @param timezone IANA 时区,如 "Asia/Shanghai"
10
+ * @param fmt date-fns 格式,默认 "yyyy-MM-dd HH:mm"
11
+ */
12
+ declare function formatDate(date: Date, timezone: string, fmt?: string): string;
13
+ /**
14
+ * 相对时间(今天/昨天/具体日期),基于时区计算「今天的 0 点」。
15
+ * @param now 当前时间(测试注入;生产用默认 new Date())
16
+ */
17
+ declare function formatRelative(date: Date, timezone: string, now?: Date): string;
18
+ /**
19
+ * 对话历史日期分组标签(今天/昨天/本周/具体日期)。
20
+ * @param date UTC Date 对象
21
+ * @param timezone IANA 时区
22
+ */
23
+ declare function formatChatDate(date: Date, timezone: string): string;
24
+ //#endregion
25
+ export { formatChatDate, formatDate, formatRelative, resolveTimezone };
@@ -0,0 +1,73 @@
1
+ import { formatInTimeZone, fromZonedTime, toZonedTime } from "date-fns-tz";
2
+ import { startOfDay, subDays } from "date-fns";
3
+ //#region src/lib/datetime.ts
4
+ const FALLBACK_TIMEZONE = "Asia/Shanghai";
5
+ /**
6
+ * 解析生效时区:项目时区 > 用户时区 > 浏览器时区 > Asia/Shanghai
7
+ */
8
+ function resolveTimezone(projectTz, userTz) {
9
+ const browserTz = typeof Intl !== "undefined" ? Intl.DateTimeFormat().resolvedOptions().timeZone : FALLBACK_TIMEZONE;
10
+ return projectTz || userTz || browserTz || FALLBACK_TIMEZONE;
11
+ }
12
+ /**
13
+ * 时区感知的时间格式化。
14
+ * @param date UTC Date 对象(来自 DB)
15
+ * @param timezone IANA 时区,如 "Asia/Shanghai"
16
+ * @param fmt date-fns 格式,默认 "yyyy-MM-dd HH:mm"
17
+ */
18
+ function formatDate(date, timezone, fmt = "yyyy-MM-dd HH:mm") {
19
+ try {
20
+ return formatInTimeZone(date, timezone, fmt);
21
+ } catch {
22
+ return formatInTimeZone(date, FALLBACK_TIMEZONE, fmt);
23
+ }
24
+ }
25
+ /**
26
+ * 相对时间(今天/昨天/具体日期),基于时区计算「今天的 0 点」。
27
+ * @param now 当前时间(测试注入;生产用默认 new Date())
28
+ */
29
+ function formatRelative(date, timezone, now = /* @__PURE__ */ new Date()) {
30
+ try {
31
+ const todayStart = startOfDayInTimeZone(now, timezone);
32
+ const yesterdayStart = new Date(todayStart);
33
+ yesterdayStart.setDate(yesterdayStart.getDate() - 1);
34
+ const dateStart = startOfDayInTimeZone(date, timezone);
35
+ if (dateStart.getTime() === todayStart.getTime()) return "今天";
36
+ if (dateStart.getTime() === yesterdayStart.getTime()) return "昨天";
37
+ return formatInTimeZone(date, timezone, "yyyy-MM-dd");
38
+ } catch {
39
+ return formatInTimeZone(date, FALLBACK_TIMEZONE, "yyyy-MM-dd");
40
+ }
41
+ }
42
+ /**
43
+ * 获取指定时区下某天的 0 点(UTC Date 对象)。
44
+ */
45
+ function startOfDayInTimeZone(date, timezone) {
46
+ const zoned = toZonedTime(date, timezone);
47
+ const dayStart = startOfDay(zoned);
48
+ return fromZonedTime(dayStart, timezone);
49
+ }
50
+ /**
51
+ * 对话历史日期分组标签(今天/昨天/本周/具体日期)。
52
+ * @param date UTC Date 对象
53
+ * @param timezone IANA 时区
54
+ */
55
+ function formatChatDate(date, timezone) {
56
+ try {
57
+ const now = /* @__PURE__ */ new Date();
58
+ const todayStart = startOfDayInTimeZone(now, timezone);
59
+ const yesterdayStart = subDays(todayStart, 1);
60
+ const weekStart = subDays(todayStart, 7);
61
+ const dateStart = startOfDayInTimeZone(date, timezone);
62
+ if (dateStart.getTime() === todayStart.getTime()) return "今天";
63
+ if (dateStart.getTime() === yesterdayStart.getTime()) return "昨天";
64
+ if (dateStart.getTime() >= weekStart.getTime()) return "本周";
65
+ const currentYear = Number(formatInTimeZone(now, timezone, "yyyy"));
66
+ if (Number(formatInTimeZone(date, timezone, "yyyy")) === currentYear) return formatInTimeZone(date, timezone, "M月d日");
67
+ return formatInTimeZone(date, timezone, "yyyy年M月d日");
68
+ } catch {
69
+ return formatInTimeZone(date, FALLBACK_TIMEZONE, "yyyy-MM-dd");
70
+ }
71
+ }
72
+ //#endregion
73
+ export { formatChatDate, formatDate, formatRelative, resolveTimezone };
@@ -0,0 +1,13 @@
1
+ //#region src/lib/desktop-detect.d.ts
2
+ /**
3
+ * Detect if code is running inside Tauri desktop environment.
4
+ * Uses `window.__TAURI_INTERNALS__` (Tauri 2) with fallback to `window.__TAURI__` (Tauri 1 compat).
5
+ */
6
+ declare function isDesktop(): boolean;
7
+ /**
8
+ * Dynamically import Tauri core API. Returns null if not in desktop env.
9
+ * Use this to avoid bundling @tauri-apps/api in web production.
10
+ */
11
+ declare function getTauriInvoke(): Promise<((cmd: string, args?: Record<string, unknown>) => Promise<unknown>) | null>;
12
+ //#endregion
13
+ export { getTauriInvoke, isDesktop };
@@ -0,0 +1,23 @@
1
+ //#region src/lib/desktop-detect.ts
2
+ /**
3
+ * Detect if code is running inside Tauri desktop environment.
4
+ * Uses `window.__TAURI_INTERNALS__` (Tauri 2) with fallback to `window.__TAURI__` (Tauri 1 compat).
5
+ */
6
+ function isDesktop() {
7
+ if (typeof window === "undefined") return false;
8
+ return Boolean(window.__TAURI_INTERNALS__ || window.__TAURI__);
9
+ }
10
+ /**
11
+ * Dynamically import Tauri core API. Returns null if not in desktop env.
12
+ * Use this to avoid bundling @tauri-apps/api in web production.
13
+ */
14
+ async function getTauriInvoke() {
15
+ if (!isDesktop()) return null;
16
+ try {
17
+ return (await import("@tauri-apps/api/core")).invoke;
18
+ } catch {
19
+ return null;
20
+ }
21
+ }
22
+ //#endregion
23
+ export { getTauriInvoke, isDesktop };
@@ -0,0 +1,6 @@
1
+ import { CanvasElement } from "../types/prototype.js";
2
+ import { OutlineNode } from "../types/outline.js";
3
+ //#region src/lib/outline-utils.d.ts
4
+ declare function buildOutline(elements: CanvasElement[]): OutlineNode[];
5
+ //#endregion
6
+ export { buildOutline };
@@ -0,0 +1,46 @@
1
+ //#region src/lib/outline-utils.ts
2
+ function buildOutline(elements) {
3
+ const containers = elements.filter((e) => isContainer(e));
4
+ const atoms = elements.filter((e) => !isContainer(e));
5
+ const roots = [];
6
+ const usedAtoms = /* @__PURE__ */ new Set();
7
+ for (const c of containers) {
8
+ const rect = {
9
+ x: c.x,
10
+ y: c.y,
11
+ w: c.width,
12
+ h: c.height
13
+ };
14
+ const children = atoms.filter((a) => !usedAtoms.has(a.id) && isInside(a, rect)).map((a) => {
15
+ usedAtoms.add(a.id);
16
+ return toAtomNode(a);
17
+ });
18
+ roots.push({
19
+ id: `container-${c.id}`,
20
+ label: (c.overrides ?? c.props)?.name || c.type,
21
+ type: "container",
22
+ elementId: c.id,
23
+ children
24
+ });
25
+ }
26
+ for (const a of atoms) if (!usedAtoms.has(a.id)) roots.push(toAtomNode(a));
27
+ return roots;
28
+ }
29
+ function isContainer(el) {
30
+ return el.width >= 160 && el.height >= 100 || (el.overrides ?? el.props)?.isContainer === true;
31
+ }
32
+ function isInside(atom, rect) {
33
+ return atom.x >= rect.x && atom.y >= rect.y && atom.x + atom.width <= rect.x + rect.w && atom.y + atom.height <= rect.y + rect.h;
34
+ }
35
+ function toAtomNode(el) {
36
+ const p = el.overrides ?? el.props;
37
+ return {
38
+ id: `atom-${el.id}`,
39
+ label: p?.text || p?.label || el.type,
40
+ type: "atom",
41
+ elementId: el.id,
42
+ children: []
43
+ };
44
+ }
45
+ //#endregion
46
+ export { buildOutline };
@@ -0,0 +1,45 @@
1
+ import { RateLimiter } from "@tanstack/pacer";
2
+ import { useDebouncedCallback, useThrottledCallback } from "@tanstack/react-pacer";
3
+ //#region src/lib/pacer.d.ts
4
+ declare const EDITOR_AUTO_SAVE_MS = 2000;
5
+ declare const EDITOR_CHANGE_DEBOUNCE_MS = 500;
6
+ declare const SEARCH_DEBOUNCE_MS = 300;
7
+ declare const SCROLL_THROTTLE_MS = 150;
8
+ declare const AI_RATE_LIMIT: {
9
+ readonly chat: {
10
+ readonly max: 10;
11
+ readonly windowMs: 60000;
12
+ };
13
+ readonly execute: {
14
+ readonly max: 5;
15
+ readonly windowMs: 60000;
16
+ };
17
+ readonly generatePrototype: {
18
+ readonly max: 5;
19
+ readonly windowMs: 60000;
20
+ };
21
+ readonly testProvider: {
22
+ readonly max: 10;
23
+ readonly windowMs: 60000;
24
+ };
25
+ readonly detect: {
26
+ readonly max: 10;
27
+ readonly windowMs: 60000;
28
+ };
29
+ readonly webSearch: {
30
+ readonly max: 20;
31
+ readonly windowMs: 60000;
32
+ };
33
+ };
34
+ interface RateLimitConfig {
35
+ max: number;
36
+ windowMs: number;
37
+ }
38
+ interface ServerFnRateLimitResult {
39
+ allowed: boolean;
40
+ retryAfterMs: number;
41
+ }
42
+ declare function getRateLimiter(key: string, config: RateLimitConfig): RateLimiter<(...args: unknown[]) => boolean>;
43
+ declare function checkRateLimit(key: string, config: RateLimitConfig): ServerFnRateLimitResult;
44
+ //#endregion
45
+ export { AI_RATE_LIMIT, EDITOR_AUTO_SAVE_MS, EDITOR_CHANGE_DEBOUNCE_MS, RateLimitConfig, SCROLL_THROTTLE_MS, SEARCH_DEBOUNCE_MS, checkRateLimit, getRateLimiter, useDebouncedCallback, useThrottledCallback };
@@ -0,0 +1,70 @@
1
+ import { RateLimiter } from "@tanstack/pacer";
2
+ import { useDebouncedCallback, useThrottledCallback } from "@tanstack/react-pacer";
3
+ //#region src/lib/pacer.ts
4
+ const EDITOR_AUTO_SAVE_MS = 2e3;
5
+ const EDITOR_CHANGE_DEBOUNCE_MS = 500;
6
+ const SEARCH_DEBOUNCE_MS = 300;
7
+ const SCROLL_THROTTLE_MS = 150;
8
+ const AI_RATE_LIMIT = {
9
+ chat: {
10
+ max: 10,
11
+ windowMs: 6e4
12
+ },
13
+ execute: {
14
+ max: 5,
15
+ windowMs: 6e4
16
+ },
17
+ generatePrototype: {
18
+ max: 5,
19
+ windowMs: 6e4
20
+ },
21
+ testProvider: {
22
+ max: 10,
23
+ windowMs: 6e4
24
+ },
25
+ detect: {
26
+ max: 10,
27
+ windowMs: 6e4
28
+ },
29
+ webSearch: {
30
+ max: 20,
31
+ windowMs: 6e4
32
+ }
33
+ };
34
+ const limiterCache = /* @__PURE__ */ new Map();
35
+ const CACHE_TTL_MS = 3e5;
36
+ function purgeStaleEntries() {
37
+ const now = Date.now();
38
+ for (const [key, entry] of limiterCache) if (now - entry.lastAccess > CACHE_TTL_MS) {
39
+ entry.limiter.reset();
40
+ limiterCache.delete(key);
41
+ }
42
+ }
43
+ setInterval(purgeStaleEntries, 6e4);
44
+ function getRateLimiter(key, config) {
45
+ const existing = limiterCache.get(key);
46
+ if (existing) {
47
+ existing.lastAccess = Date.now();
48
+ return existing.limiter;
49
+ }
50
+ const limiter = new RateLimiter(() => true, {
51
+ limit: config.max,
52
+ window: config.windowMs,
53
+ windowType: "sliding"
54
+ });
55
+ limiterCache.set(key, {
56
+ limiter,
57
+ lastAccess: Date.now()
58
+ });
59
+ return limiter;
60
+ }
61
+ function checkRateLimit(key, config) {
62
+ const limiter = getRateLimiter(key, config);
63
+ const allowed = limiter.maybeExecute();
64
+ return {
65
+ allowed,
66
+ retryAfterMs: allowed ? 0 : limiter.getMsUntilNextWindow()
67
+ };
68
+ }
69
+ //#endregion
70
+ export { AI_RATE_LIMIT, EDITOR_AUTO_SAVE_MS, EDITOR_CHANGE_DEBOUNCE_MS, SCROLL_THROTTLE_MS, SEARCH_DEBOUNCE_MS, checkRateLimit, getRateLimiter, useDebouncedCallback, useThrottledCallback };
@@ -0,0 +1,18 @@
1
+ import { CanvasElement } from "../../types/prototype.js";
2
+ //#region src/lib/prd/stack-layout.d.ts
3
+ interface StackLayoutOptions {
4
+ startX: number;
5
+ startY: number;
6
+ gap: number;
7
+ }
8
+ /**
9
+ * 计算新组件在画板上的纵向堆叠位置。
10
+ * 起始 y = 现有元素的最大 (y + height) + gap,若无现有元素则用 startY。
11
+ * items 的 height 用于决定每个新组件的纵向偏移,确保大小不一的组件不会重叠。
12
+ */
13
+ declare function computeStackPositions(existing: Pick<CanvasElement, "x" | "y" | "height">[], items: Array<Pick<CanvasElement, "height">>, options: StackLayoutOptions): Array<{
14
+ x: number;
15
+ y: number;
16
+ }>;
17
+ //#endregion
18
+ export { StackLayoutOptions, computeStackPositions };
@@ -0,0 +1,24 @@
1
+ //#region src/lib/prd/stack-layout.ts
2
+ /**
3
+ * 计算新组件在画板上的纵向堆叠位置。
4
+ * 起始 y = 现有元素的最大 (y + height) + gap,若无现有元素则用 startY。
5
+ * items 的 height 用于决定每个新组件的纵向偏移,确保大小不一的组件不会重叠。
6
+ */
7
+ function computeStackPositions(existing, items, options) {
8
+ if (items.length === 0) return [];
9
+ const { startX, startY, gap } = options;
10
+ const maxBottom = existing.reduce((max, el) => Math.max(max, el.y + el.height), 0);
11
+ const baseY = existing.length > 0 ? maxBottom + gap : startY;
12
+ const positions = [];
13
+ let cursorY = baseY;
14
+ for (const item of items) {
15
+ positions.push({
16
+ x: startX,
17
+ y: cursorY
18
+ });
19
+ cursorY += item.height + gap;
20
+ }
21
+ return positions;
22
+ }
23
+ //#endregion
24
+ export { computeStackPositions };
@@ -0,0 +1,21 @@
1
+ //#region src/lib/prd-tree-utils.d.ts
2
+ interface PRDPage {
3
+ id: string;
4
+ name: string;
5
+ type: "folder" | "page";
6
+ parentId: string | null;
7
+ order: number;
8
+ version: number;
9
+ }
10
+ interface TreeNode extends PRDPage {
11
+ children: TreeNode[];
12
+ }
13
+ declare function buildTree(pages: PRDPage[]): TreeNode[];
14
+ declare function flattenTree(nodes: TreeNode[]): PRDPage[];
15
+ declare function findNode(nodes: TreeNode[], id: string): TreeNode | null;
16
+ declare function canMove(node: TreeNode, targetParentId: string | null, allPages: PRDPage[]): boolean;
17
+ declare function sortSnapshotsByTree<T extends {
18
+ pageId: string;
19
+ }>(snapshots: T[], prdPages: PRDPage[]): T[];
20
+ //#endregion
21
+ export { PRDPage, TreeNode, buildTree, canMove, findNode, flattenTree, sortSnapshotsByTree };
@@ -0,0 +1,62 @@
1
+ //#region src/lib/prd-tree-utils.ts
2
+ function buildTree(pages) {
3
+ const map = /* @__PURE__ */ new Map();
4
+ const roots = [];
5
+ for (const p of pages) map.set(p.id, {
6
+ ...p,
7
+ children: []
8
+ });
9
+ for (const p of pages) {
10
+ const node = map.get(p.id);
11
+ if (p.parentId && map.has(p.parentId)) map.get(p.parentId).children.push(node);
12
+ else roots.push(node);
13
+ }
14
+ const sortNodes = (nodes) => nodes.sort((a, b) => a.order - b.order);
15
+ sortNodes(roots);
16
+ for (const node of map.values()) sortNodes(node.children);
17
+ return roots;
18
+ }
19
+ function flattenTree(nodes) {
20
+ const result = [];
21
+ for (const n of nodes) {
22
+ result.push({
23
+ id: n.id,
24
+ name: n.name,
25
+ type: n.type,
26
+ parentId: n.parentId,
27
+ order: n.order,
28
+ version: n.version
29
+ });
30
+ result.push(...flattenTree(n.children));
31
+ }
32
+ return result;
33
+ }
34
+ function findNode(nodes, id) {
35
+ for (const n of nodes) {
36
+ if (n.id === id) return n;
37
+ const found = findNode(n.children, id);
38
+ if (found) return found;
39
+ }
40
+ return null;
41
+ }
42
+ function canMove(node, targetParentId, allPages) {
43
+ if (node.type === "folder" && targetParentId !== null) return false;
44
+ if (targetParentId === node.id) return false;
45
+ if (allPages.find((p) => p.id === targetParentId)?.type === "folder") return false;
46
+ return true;
47
+ }
48
+ function sortSnapshotsByTree(snapshots, prdPages) {
49
+ if (snapshots.length <= 1) return snapshots;
50
+ const ordered = flattenTree(buildTree(prdPages));
51
+ const indexMap = new Map(ordered.map((p, i) => [p.id, i]));
52
+ return [...snapshots].sort((a, b) => {
53
+ const ia = indexMap.get(a.pageId);
54
+ const ib = indexMap.get(b.pageId);
55
+ if (ia === void 0 && ib === void 0) return 0;
56
+ if (ia === void 0) return 1;
57
+ if (ib === void 0) return -1;
58
+ return ia - ib;
59
+ });
60
+ }
61
+ //#endregion
62
+ export { buildTree, canMove, findNode, flattenTree, sortSnapshotsByTree };
@@ -0,0 +1,2 @@
1
+ import { getAllComponents, getComponent, registerComponent, registerComponents, unregisterComponent } from "@allbluecn/prototype";
2
+ export { getAllComponents, getComponent, registerComponent, registerComponents, unregisterComponent };
@@ -0,0 +1,2 @@
1
+ import { getAllComponents, getComponent, registerComponent, registerComponents, unregisterComponent } from "@allbluecn/prototype";
2
+ export { getAllComponents, getComponent, registerComponent, registerComponents, unregisterComponent };
@@ -0,0 +1,6 @@
1
+ import { QueryClient } from "@tanstack/react-query";
2
+ //#region src/lib/query-client-seam.d.ts
3
+ declare function setQueryClient(client: QueryClient): void;
4
+ declare function getQueryClient(): QueryClient;
5
+ //#endregion
6
+ export { getQueryClient, setQueryClient };
@@ -0,0 +1,11 @@
1
+ //#region src/lib/query-client-seam.ts
2
+ let instance = null;
3
+ function setQueryClient(client) {
4
+ instance = client;
5
+ }
6
+ function getQueryClient() {
7
+ if (!instance) throw new Error("QueryClient 未注入:宿主需在 router 初始化时调用 setQueryClient()");
8
+ return instance;
9
+ }
10
+ //#endregion
11
+ export { getQueryClient, setQueryClient };
@@ -0,0 +1,7 @@
1
+ //#region src/lib/share-events.d.ts
2
+ declare function addClient(prdId: string, controller: ReadableStreamDefaultController): void;
3
+ declare function removeClient(prdId: string, controller: ReadableStreamDefaultController): void;
4
+ declare function notifyClients(prdId: string, event: string, data: unknown): void;
5
+ declare function getClientCount(): number;
6
+ //#endregion
7
+ export { addClient, getClientCount, notifyClients, removeClient };
@@ -0,0 +1,47 @@
1
+ //#region src/lib/share-events.ts
2
+ const clients = /* @__PURE__ */ new Map();
3
+ const MAX_CLIENTS_PER_PRD = 20;
4
+ setInterval(() => {
5
+ for (const [prdId, set] of clients) {
6
+ for (const controller of set) try {
7
+ controller.enqueue(new TextEncoder().encode(":cleanup-ping\n\n"));
8
+ } catch {
9
+ set.delete(controller);
10
+ }
11
+ if (set.size === 0) clients.delete(prdId);
12
+ }
13
+ }, 6e4);
14
+ const controllerMeta = /* @__PURE__ */ new WeakMap();
15
+ function addClient(prdId, controller) {
16
+ const set = clients.get(prdId);
17
+ if (set && set.size >= MAX_CLIENTS_PER_PRD) throw new Error("连接数已达上限");
18
+ if (!set) clients.set(prdId, /* @__PURE__ */ new Set());
19
+ clients.get(prdId).add(controller);
20
+ controllerMeta.set(controller, Date.now());
21
+ }
22
+ function removeClient(prdId, controller) {
23
+ const set = clients.get(prdId);
24
+ if (!set) return;
25
+ set.delete(controller);
26
+ controllerMeta.delete(controller);
27
+ if (set.size === 0) clients.delete(prdId);
28
+ }
29
+ function notifyClients(prdId, event, data) {
30
+ const set = clients.get(prdId);
31
+ if (!set) return;
32
+ const message = new TextEncoder().encode(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
33
+ for (const controller of set) try {
34
+ controller.enqueue(message);
35
+ controllerMeta.set(controller, Date.now());
36
+ } catch {
37
+ set.delete(controller);
38
+ controllerMeta.delete(controller);
39
+ }
40
+ }
41
+ function getClientCount() {
42
+ let total = 0;
43
+ for (const set of clients.values()) total += set.size;
44
+ return total;
45
+ }
46
+ //#endregion
47
+ export { addClient, getClientCount, notifyClients, removeClient };
@@ -0,0 +1,4 @@
1
+ //#region src/lib/sidebar-utils.d.ts
2
+ declare function isParentActive(pathname: string, parentLink: string): boolean;
3
+ //#endregion
4
+ export { isParentActive };
@@ -0,0 +1,7 @@
1
+ //#region src/lib/sidebar-utils.ts
2
+ function isParentActive(pathname, parentLink) {
3
+ if (!parentLink || parentLink === "#") return false;
4
+ return pathname === parentLink;
5
+ }
6
+ //#endregion
7
+ export { isParentActive };
@@ -0,0 +1,16 @@
1
+ import { CanvasElement } from "../../types/prototype.js";
2
+ import { SetStateAction } from "react";
3
+ //#region src/lib/stores/prd-canvas-store.d.ts
4
+ interface PrdCanvasState {
5
+ elements: CanvasElement[];
6
+ selectedElementId: string | null;
7
+ viewMode: 'edit' | 'preview' | 'prototype';
8
+ }
9
+ declare const prdCanvasStore: import("@tanstack/store").Store<PrdCanvasState, never>;
10
+ declare function setCanvasElements(value: SetStateAction<CanvasElement[]>): void;
11
+ declare function setCanvasSelectedElementId(id: string | null): void;
12
+ declare function setCanvasViewMode(mode: PrdCanvasState['viewMode']): void;
13
+ declare function updateCanvasElement(id: string, patch: Partial<CanvasElement>): void;
14
+ declare function deleteCanvasElement(id: string): void;
15
+ //#endregion
16
+ export { type CanvasElement, type PrdCanvasState, deleteCanvasElement, prdCanvasStore, setCanvasElements, setCanvasSelectedElementId, setCanvasViewMode, updateCanvasElement };
@@ -0,0 +1,42 @@
1
+ import { createStore } from "@tanstack/store";
2
+ //#region src/lib/stores/prd-canvas-store.ts
3
+ const prdCanvasStore = createStore({
4
+ elements: [],
5
+ selectedElementId: null,
6
+ viewMode: "edit"
7
+ });
8
+ function setCanvasElements(value) {
9
+ prdCanvasStore.setState((s) => ({
10
+ ...s,
11
+ elements: typeof value === "function" ? value(s.elements) : value
12
+ }));
13
+ }
14
+ function setCanvasSelectedElementId(id) {
15
+ prdCanvasStore.setState((s) => ({
16
+ ...s,
17
+ selectedElementId: id
18
+ }));
19
+ }
20
+ function setCanvasViewMode(mode) {
21
+ prdCanvasStore.setState((s) => ({
22
+ ...s,
23
+ viewMode: mode
24
+ }));
25
+ }
26
+ function updateCanvasElement(id, patch) {
27
+ prdCanvasStore.setState((s) => ({
28
+ ...s,
29
+ elements: s.elements.map((e) => e.id === id ? {
30
+ ...e,
31
+ ...patch
32
+ } : e)
33
+ }));
34
+ }
35
+ function deleteCanvasElement(id) {
36
+ prdCanvasStore.setState((s) => ({
37
+ ...s,
38
+ elements: s.elements.filter((e) => e.id !== id)
39
+ }));
40
+ }
41
+ //#endregion
42
+ export { deleteCanvasElement, prdCanvasStore, setCanvasElements, setCanvasSelectedElementId, setCanvasViewMode, updateCanvasElement };
@@ -0,0 +1,12 @@
1
+ //#region src/lib/tag-colors.d.ts
2
+ declare const TAG_COLORS: {
3
+ bg: string;
4
+ text: string;
5
+ border: string;
6
+ selected: string;
7
+ check: string;
8
+ label: string;
9
+ }[];
10
+ declare function hashColorIndex(name: string): number;
11
+ //#endregion
12
+ export { TAG_COLORS, hashColorIndex };