nolo-cli 0.157.0-alpha.1 → 0.157.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 (164) hide show
  1. package/{_executeModel-5WS2PA62.js → _executeModel-ZIQHOREX.js} +55 -55
  2. package/{accountResolver-7RYB4D2P.js → accountResolver-55EDKEIK.js} +1 -1
  3. package/{action-ZJYUBXFC.js → action-GPPJC5TI.js} +5 -5
  4. package/{addContentAction-TVHB4526.js → addContentAction-XJQEJ4XW.js} +8 -8
  5. package/{addDialogAgentAction-FDPBU6K6.js → addDialogAgentAction-5WZX5CAY.js} +7 -7
  6. package/{agentDeleteCommand-Q6M4F3U6.js → agentDeleteCommand-LQSOJEXY.js} +75 -76
  7. package/{agentEmailCommands-FNH6FEHS.js → agentEmailCommands-HTPKXONW.js} +78 -79
  8. package/{agentListCommands-JUNMFS6E.js → agentListCommands-GOCGOQUB.js} +36 -36
  9. package/{agentMachineCommands-VNLDEKNT.js → agentMachineCommands-T7DAZG77.js} +35 -32
  10. package/{agentProviderCommands-X2HQE6HY.js → agentProviderCommands-CXBHNONN.js} +5 -5
  11. package/{agentPullCommand-FA43RBRU.js → agentPullCommand-GXXEDOSA.js} +4 -4
  12. package/{agentRecordCommands-47XXRVPI.js → agentRecordCommands-HSW3RJ4H.js} +72 -73
  13. package/{agentRunCommand-QEXFJUXQ.js → agentRunCommand-TIRJ57DK.js} +75 -75
  14. package/{agentRunControl-2C5GM3BW.js → agentRunControl-QWFFIAQY.js} +9 -7
  15. package/{agentRuntimeLocal-O5GDAFTN.js → agentRuntimeLocal-J6I63NZC.js} +21 -19
  16. package/{agentSlice-E3XS5FTQ.js → agentSlice-JNM3HF3V.js} +8 -8
  17. package/{appDeleteCommands-C2J5RQ3I.js → appDeleteCommands-KKLAK2UR.js} +31 -29
  18. package/{appDeployCommands-3YRK7PSU.js → appDeployCommands-PXWK4FAX.js} +31 -29
  19. package/{appDeployStatusCommands-FPAX7MOK.js → appDeployStatusCommands-3NGWDZTX.js} +31 -29
  20. package/{appGetCommands-XAC2V766.js → appGetCommands-APWYPEO3.js} +31 -29
  21. package/{appListCommands-ZJL2W5O7.js → appListCommands-OP7IRALO.js} +31 -29
  22. package/{authCommand-J3XILHWW.js → authCommand-3Z52KJID.js} +22 -302
  23. package/{authCommands-77CHYBGF.js → authCommands-QOCKVPX3.js} +5 -5
  24. package/{builtinSkillRegistry-A6VSPJEJ.js → builtinSkillRegistry-LJV7FHNI.js} +4 -4
  25. package/{chromeCommands-OBBNJCLS.js → chromeCommands-IY4NVSXZ.js} +17 -10
  26. package/{chunk-SW4S4XYB.js → chunk-2AB2HA4M.js} +84 -34
  27. package/{chunk-C5VPAHIU.js → chunk-32ZKZET7.js} +1 -1
  28. package/{chunk-XPWGOTBQ.js → chunk-3L2WKC3W.js} +1 -8
  29. package/{chunk-3XZKV7QQ.js → chunk-3L5MSPWX.js} +1 -1
  30. package/{chunk-QLQ573SU.js → chunk-3M52COK5.js} +120 -0
  31. package/{chunk-VSOWPETY.js → chunk-4226O6F7.js} +10 -10
  32. package/{chunk-Z6KQDSZW.js → chunk-43OFVLWJ.js} +6 -6
  33. package/{chunk-TJ2VPCBE.js → chunk-4JCAW7TO.js} +2 -2
  34. package/{chunk-6TF64IF2.js → chunk-4L4K6YR7.js} +16 -2
  35. package/{chunk-PEO24UB5.js → chunk-5E5VB7PS.js} +324 -57
  36. package/{chunk-ZD2BLOY6.js → chunk-5EDQTOUR.js} +7 -7
  37. package/{chunk-HKT6QXP3.js → chunk-5IKRTRRR.js} +5 -5
  38. package/{chunk-P5QACQDK.js → chunk-62TBKWTV.js} +1 -1
  39. package/{chunk-TRW43TSC.js → chunk-6EQD4AQL.js} +41 -1
  40. package/{chunk-YLMMECCH.js → chunk-6XIE5ZGI.js} +1 -1
  41. package/{chunk-OH2M7WEU.js → chunk-6Y3ETA2Y.js} +3 -3
  42. package/{chunk-7A4LJCDR.js → chunk-B3ZIFOFI.js} +5 -5
  43. package/{chunk-WZ6OU4NX.js → chunk-BAWAKW7X.js} +2 -2
  44. package/{chunk-UUPR3TD7.js → chunk-BL4HFN6L.js} +2 -4
  45. package/{chunk-2GGXHQIW.js → chunk-BLVSFYQ3.js} +4 -2
  46. package/{chunk-HP6O6LTV.js → chunk-CDLP56BS.js} +9 -9
  47. package/{chunk-UTIMX333.js → chunk-DJ2BOPJY.js} +1 -1
  48. package/{chunk-36OMEXXR.js → chunk-DLV3H464.js} +8 -8
  49. package/{chunk-CE7PIHQD.js → chunk-ESMZW5PE.js} +3 -3
  50. package/{chunk-PSJWPSKS.js → chunk-EWO77ZGF.js} +9 -43
  51. package/{chunk-ZWG3C7VI.js → chunk-F3SOW2EU.js} +81 -1
  52. package/{chunk-FY4SDK2E.js → chunk-FDLDMJTM.js} +1 -1
  53. package/{chunk-KOB75UNU.js → chunk-FHG46N5C.js} +53 -4
  54. package/{chunk-7KYVUFDG.js → chunk-G3VYRPTV.js} +5 -267
  55. package/{chunk-DW7MGLMG.js → chunk-GGUTTH6C.js} +35 -207
  56. package/{chunk-6MJNEXUU.js → chunk-HGDKT2D6.js} +4 -0
  57. package/{chunk-B2EGWZJG.js → chunk-I7S63QUU.js} +1 -1
  58. package/{chunk-ROPSATAB.js → chunk-IF7V3CBU.js} +1 -1
  59. package/chunk-IKOKYBYJ.js +2685 -0
  60. package/{chunk-T6CBQ6BN.js → chunk-INFHX73M.js} +1 -1
  61. package/{chunk-YBNHPX4S.js → chunk-IW64YHXL.js} +155 -31
  62. package/{chunk-K43ZF2C3.js → chunk-JPPQ3GUO.js} +1 -1
  63. package/{chunk-TZTWMGE3.js → chunk-JWEXJ573.js} +3 -3
  64. package/{chunk-RUNKPFM5.js → chunk-K6Y5T4GE.js} +12 -8
  65. package/{chunk-MVJVF4ED.js → chunk-KESKU5BG.js} +18 -17
  66. package/{chunk-I2ZMGXXF.js → chunk-KFHREHUQ.js} +1 -1
  67. package/{chunk-3C2QLERX.js → chunk-KMDDG73K.js} +1 -1
  68. package/{chunk-5MM7NNO6.js → chunk-KSTEXKL6.js} +78 -39
  69. package/{chunk-EM3YOZJ4.js → chunk-L2JMH4I5.js} +3 -3
  70. package/{chunk-MM3662RS.js → chunk-LPO6AMQU.js} +780 -64
  71. package/{chunk-D4OWHT5Y.js → chunk-MAYW6V3E.js} +2 -2
  72. package/{chunk-IPAW7XLD.js → chunk-MFVOJ6KF.js} +2 -2
  73. package/{chunk-FDT27L7S.js → chunk-MLEANT7D.js} +19 -17
  74. package/{chunk-7GC3EKUG.js → chunk-MMSQTZCJ.js} +3 -3
  75. package/{chunk-XFKZ3MCV.js → chunk-MR3ITQEV.js} +344 -88
  76. package/{chunk-CBHGZRCE.js → chunk-MYOH447Z.js} +1 -1
  77. package/{chunk-6MPAEODB.js → chunk-NHEWV5FD.js} +17 -3
  78. package/{chunk-ZEHTARJA.js → chunk-NLFTBC6S.js} +321 -150
  79. package/{chunk-SKPPKHD3.js → chunk-OLUKIUX6.js} +2 -2
  80. package/{chunk-SUKSWFLP.js → chunk-PIG2IUVZ.js} +1 -1
  81. package/{chunk-SEJ5OS6F.js → chunk-PXYBUFDB.js} +4 -0
  82. package/{chunk-2MTE2PEH.js → chunk-QA2C5NKI.js} +5 -739
  83. package/{chunk-L6EQV5OC.js → chunk-QXZH5UDF.js} +3 -3
  84. package/{chunk-TNIX77YM.js → chunk-R5GO3YZP.js} +34 -1
  85. package/{chunk-X5SUT4CN.js → chunk-R7GCGOGZ.js} +6 -6
  86. package/{chunk-4Z245KOA.js → chunk-SH3XD4E2.js} +8 -4
  87. package/{chunk-JGRPBIZZ.js → chunk-SQX235S2.js} +1 -1
  88. package/chunk-TT644UJD.js +188 -0
  89. package/{chunk-IYBIRCQV.js → chunk-U34KT53V.js} +29 -11
  90. package/{chunk-ANJTRG52.js → chunk-ULQAD7ZY.js} +18 -43
  91. package/{chunk-QDA4Y5O6.js → chunk-UVYSBQ2M.js} +21 -17
  92. package/{chunk-I2RMFLLH.js → chunk-V7PCFWX3.js} +1 -1
  93. package/{chunk-HXHSTRGH.js → chunk-VYNMQ6HW.js} +0 -27
  94. package/{chunk-G47IPDOK.js → chunk-W7FGZRLK.js} +1 -1
  95. package/{chunk-7BSQK2UC.js → chunk-WRCZXJ4N.js} +2 -2
  96. package/{chunk-KX6LPG7W.js → chunk-WYJTNSVL.js} +9 -9
  97. package/{chunk-H4KACZMG.js → chunk-XZIW3Q5B.js} +271 -138
  98. package/chunk-Y5GCAMGP.js +9 -0
  99. package/{chunk-JZX2XLKC.js → chunk-YCRROBDY.js} +1 -1
  100. package/{chunk-FPWT3RH2.js → chunk-YN5DT4JS.js} +22 -22
  101. package/{chunk-SCJD2PNK.js → chunk-YPG7TUQD.js} +3 -3
  102. package/{chunk-EJU23ST5.js → chunk-ZKVS36H3.js} +5069 -3730
  103. package/{chunk-YANF2RR4.js → chunk-ZPKUJROL.js} +1 -1
  104. package/{chunk-TYND6RDQ.js → chunk-ZZDVBZOP.js} +74 -3
  105. package/{commandRegistry-OUBQIF62.js → commandRegistry-DR2RPWK6.js} +88 -96
  106. package/{contentThunks-B3FRQGP7.js → contentThunks-CSJDJDEJ.js} +21 -21
  107. package/{createAgentAutomationAction-T2YFJ6MY.js → createAgentAutomationAction-ISEUEQSY.js} +21 -21
  108. package/{createDialogAction-2NFGFBXW.js → createDialogAction-HUCFOZY3.js} +25 -25
  109. package/{createPageAction-LDAVZDN7.js → createPageAction-DT5CYXCL.js} +24 -25
  110. package/{dbSlice-5QGKMQLO.js → dbSlice-6PVPY44C.js} +7 -7
  111. package/{deleteFile-EW6QNRRT.js → deleteFile-YM6NDPAR.js} +5 -5
  112. package/{dialogCommands-ZLBEAQHE.js → dialogCommands-3W6AIUXT.js} +35 -32
  113. package/{dialogSlice-64S3J6CP.js → dialogSlice-WJEEPG4W.js} +20 -20
  114. package/{dist-NJC2W7I4.js → dist-Q2JSMAKA.js} +7 -361
  115. package/{docCreateCommands-XOG5BBFQ.js → docCreateCommands-KQHQNLRX.js} +32 -30
  116. package/{docDeleteCommands-NCW3BBRX.js → docDeleteCommands-O3DWFX2W.js} +33 -31
  117. package/{docReadCommands-OT7X44Y3.js → docReadCommands-2U2BUONC.js} +32 -30
  118. package/{docStore-NIP7OO4I.js → docStore-7JPYT25V.js} +8 -8
  119. package/{docUpdateCommands-JW7OWW2J.js → docUpdateCommands-MF3C52XI.js} +32 -30
  120. package/{getPricing-TX35D7PI.js → getPricing-XQ3N3RBP.js} +2 -2
  121. package/{handleSendMessageAction-TOKA7ED7.js → handleSendMessageAction-BV5FMID4.js} +43 -39
  122. package/index.js +8 -8
  123. package/{localRuntimeAdapter-EQM6LFYC.js → localRuntimeAdapter-6FBEJJ4D.js} +70 -69
  124. package/{localRuntimeAuthority-JDAD7CB6.js → localRuntimeAuthority-BPN5OAQG.js} +2 -2
  125. package/{localRuntimeDb-CVC62PM5.js → localRuntimeDb-QIVAXMUL.js} +1 -1
  126. package/{machineCommands-WJ7FZ67T.js → machineCommands-WCAFDI5N.js} +80 -79
  127. package/{machineWsRunDispatch-BQT4DEA2.js → machineWsRunDispatch-ZF6BBQ3X.js} +70 -71
  128. package/{memberThunks-KRV5YXOB.js → memberThunks-AZINUM4S.js} +10 -10
  129. package/package.json +6 -2
  130. package/{profileConfig-ZGOFORWV.js → profileConfig-KN3N2BLF.js} +7 -1
  131. package/{providerPresetApply-CRZFMQD5.js → providerPresetApply-PKUOHQJT.js} +5 -5
  132. package/{providerRegistry-7IS43D3X.js → providerRegistry-HNQLIFN2.js} +5 -5
  133. package/{read-5KAZHHDM.js → read-7JPIWRBQ.js} +5 -5
  134. package/{readDocTool-5QO34OSX.js → readDocTool-AAQTB2Y3.js} +1 -1
  135. package/{readlineWorkspace-JHJSU5DS.js → readlineWorkspace-I5MHMEUE.js} +375 -200
  136. package/{removeDialogAgentAction-6X63HMI3.js → removeDialogAgentAction-RMVRILLK.js} +9 -9
  137. package/{runAgentClientLoop-5QIGEALK.js → runAgentClientLoop-TSNSRQEP.js} +59 -54
  138. package/{runtimeDoctorCommands-56NWKNON.js → runtimeDoctorCommands-MMCP4B4U.js} +12 -12
  139. package/{secretCommands-ZXZRLR3R.js → secretCommands-DNY56NSU.js} +11 -1
  140. package/{setDialogExtraReferencesAction-4MAYKKYW.js → setDialogExtraReferencesAction-L3V7JTMG.js} +8 -8
  141. package/{setPrimaryDialogAgentAction-EGBAMREH.js → setPrimaryDialogAgentAction-X52JQGTJ.js} +9 -9
  142. package/settingThunks-N6XFWPOU.js +923 -0
  143. package/{spaceCommands-ZWDPTURU.js → spaceCommands-NDPGHDMD.js} +29 -27
  144. package/{streamAgentChatTurn-456DWXNY.js → streamAgentChatTurn-RJLDV4WZ.js} +154 -95
  145. package/{switchDialogAgentAction-YBKTD6DO.js → switchDialogAgentAction-ZJ5CGU7J.js} +7 -7
  146. package/{tableCommands-U3QDY4L6.js → tableCommands-IVC5S7Y3.js} +11 -11
  147. package/{toolApiClient-7WSJJJBV.js → toolApiClient-HGNO53TC.js} +2 -2
  148. package/{tools-IWNXKK4Y.js → tools-X6QNIYFJ.js} +43 -44
  149. package/{tuiSummaryLlmCaller-KLK6K3Q3.js → tuiSummaryLlmCaller-FESHBDTT.js} +7 -7
  150. package/{updateCommands-NQXAGFM7.js → updateCommands-FJHGWD3Q.js} +5 -3
  151. package/{updateDialogTitleAction-SX53FZWO.js → updateDialogTitleAction-6LURCTMG.js} +21 -21
  152. package/{workloadLifecycle-36DXRZKU.js → workloadLifecycle-6O6PMISX.js} +2 -2
  153. package/chunk-IA7TRNNR.js +0 -11
  154. package/chunk-UKZX3NHN.js +0 -48
  155. package/chunk-VAZHH6FO.js +0 -7012
  156. package/chunk-W4S6OTSC.js +0 -35
  157. package/clipboardy-GCO3GT3I.js +0 -11793
  158. package/settingThunks-FTDRZNSJ.js +0 -1371
  159. package/{agentGrantCommands-HOJ3JBBQ.js → agentGrantCommands-5DPHYEKP.js} +3 -3
  160. package/{chromeOpsCommands-3Z34RKSE.js → chromeOpsCommands-GZVVK7HU.js} +4 -4
  161. package/{chunk-XETG4RIX.js → chunk-AETZ7AD6.js} +4 -4
  162. package/{chunk-2IXDJNZI.js → chunk-GAGGEA7D.js} +3 -3
  163. package/{memoryCommands-CUNBFRVS.js → memoryCommands-ZS3VQJAL.js} +3 -3
  164. package/{offlineMarxistsAgentCommand-2QTHJCHV.js → offlineMarxistsAgentCommand-3GLX4QQY.js} +3 -3
@@ -0,0 +1,2685 @@
1
+ import {
2
+ deleteDialog,
3
+ runtime_default,
4
+ toast
5
+ } from "./chunk-XZIW3Q5B.js";
6
+ import {
7
+ getCurrentSpaceId,
8
+ getCurrentSpaceIdRaw,
9
+ updateCurrentSpaceIfMatch
10
+ } from "./chunk-ZJ7UHBJS.js";
11
+ import {
12
+ formatISO
13
+ } from "./chunk-ZRAU6T47.js";
14
+ import {
15
+ require_react
16
+ } from "./chunk-YDH3FDFQ.js";
17
+ import {
18
+ UNCATEGORIZED_ID,
19
+ addContentAction,
20
+ checkSpaceMembership,
21
+ localSpaceAuthorityPatchStamp
22
+ } from "./chunk-JWEXJ573.js";
23
+ import {
24
+ createSpaceKey,
25
+ normalizeSpaceId
26
+ } from "./chunk-UAD2WT54.js";
27
+ import {
28
+ patch,
29
+ read,
30
+ readAndWait,
31
+ remove,
32
+ uploadFileAction,
33
+ upsertSSREntity,
34
+ write
35
+ } from "./chunk-CDLP56BS.js";
36
+ import {
37
+ resolveFileCategory
38
+ } from "./chunk-3PVYUPXK.js";
39
+ import {
40
+ DEVICE_LOCAL_OWNER_ID,
41
+ getRuntimeServerContext,
42
+ isDeviceLocalSpaceBody,
43
+ resolveReplicationServers,
44
+ scheduleDeleteReplication,
45
+ scheduleWriteReplication
46
+ } from "./chunk-43OFVLWJ.js";
47
+ import {
48
+ createAsyncThunk
49
+ } from "./chunk-WRCZXJ4N.js";
50
+ import {
51
+ getIsDesktopApp
52
+ } from "./chunk-6Q7UTJKR.js";
53
+ import {
54
+ createClientLogger
55
+ } from "./chunk-QQ56R7KS.js";
56
+ import {
57
+ selectIdentityUserId
58
+ } from "./chunk-PXYBUFDB.js";
59
+ import {
60
+ buildTombstoneRecord
61
+ } from "./chunk-D2MDMY2M.js";
62
+ import {
63
+ isSystemAdmin
64
+ } from "./chunk-Y6ORVLSS.js";
65
+ import {
66
+ asRecordOrEmpty
67
+ } from "./chunk-KX6YBIHG.js";
68
+ import {
69
+ isAbortError
70
+ } from "./chunk-7DPNBQSV.js";
71
+ import {
72
+ extractUserId
73
+ } from "./chunk-M2EJHDJP.js";
74
+ import {
75
+ SEPARATOR,
76
+ createKey,
77
+ fileKey,
78
+ isAgentKey,
79
+ isPageKey,
80
+ metaKey,
81
+ rowKey,
82
+ splitKey,
83
+ ulid
84
+ } from "./chunk-5EMSBTQ6.js";
85
+ import {
86
+ asTrimmedNonEmptyStringArray
87
+ } from "./chunk-I42VC5KR.js";
88
+ import {
89
+ asOptionalPositiveFiniteNumber
90
+ } from "./chunk-U6VC4MU4.js";
91
+ import {
92
+ asOptionalFiniteNumber
93
+ } from "./chunk-WWC7I6TA.js";
94
+ import {
95
+ isRecord
96
+ } from "./chunk-KUG52IAP.js";
97
+ import {
98
+ asTrimmedString
99
+ } from "./chunk-3EUW3WEO.js";
100
+ import {
101
+ asOptionalTrimmedString
102
+ } from "./chunk-G3SUCT4W.js";
103
+ import {
104
+ __toESM
105
+ } from "./chunk-4VNS5WPM.js";
106
+
107
+ // packages/render/table/tableStore.ts
108
+ var import_react = __toESM(require_react(), 1);
109
+ import { ulid as ulid3 } from "ulid";
110
+
111
+ // packages/core/logger.ts
112
+ import pino from "pino";
113
+ var logger = pino({
114
+ level: process.env.NODE_ENV === "production" ? "info" : "debug"
115
+ });
116
+
117
+ // packages/render/table/fetchAndCacheTableRows.ts
118
+ var TABLE_ROWS_FETCH_TIMEOUT_MS = 5e3;
119
+ var getRowTimestamp = (row) => {
120
+ if (!row || typeof row !== "object") return 0;
121
+ return asOptionalPositiveFiniteNumber(Date.parse(row.updatedAt ?? "")) ?? asOptionalPositiveFiniteNumber(Date.parse(row.createdAt ?? "")) ?? 0;
122
+ };
123
+ var shouldReplaceMergedRow = (nextRow, currentRow) => {
124
+ const nextTs = getRowTimestamp(nextRow);
125
+ const currentTs = getRowTimestamp(currentRow);
126
+ if (nextTs !== currentTs) return nextTs > currentTs;
127
+ return Boolean(nextRow?.deletedAt) && !currentRow?.deletedAt;
128
+ };
129
+ var mergeTableRows = (...rowLists) => {
130
+ const merged = /* @__PURE__ */ new Map();
131
+ for (const rowList of rowLists) {
132
+ for (const row of rowList) {
133
+ const dbKey = row?.dbKey;
134
+ if (!dbKey) continue;
135
+ const existing = merged.get(dbKey);
136
+ if (!existing || shouldReplaceMergedRow(row, existing)) {
137
+ merged.set(dbKey, row);
138
+ }
139
+ }
140
+ }
141
+ return Array.from(merged.values());
142
+ };
143
+ var TABLE_SYNC_ENVELOPE = "table-sync-v1";
144
+ var getLatestTableMeta = (snapshots) => {
145
+ let latestMeta = null;
146
+ for (const snapshot of snapshots) {
147
+ const tableMeta = snapshot.tableMeta;
148
+ if (!tableMeta || typeof tableMeta !== "object") continue;
149
+ if (!latestMeta || shouldReplaceMergedRow(tableMeta, latestMeta)) {
150
+ latestMeta = tableMeta;
151
+ }
152
+ }
153
+ return latestMeta;
154
+ };
155
+ var loadLocalTableRows = async (db, tenantId, tableId) => {
156
+ if (!db || typeof db.iterator !== "function") {
157
+ return [];
158
+ }
159
+ const rows = [];
160
+ const { gte, lte } = rowKey.range(tenantId, tableId);
161
+ try {
162
+ for await (const [, value] of db.iterator({ gte, lte })) {
163
+ if (value?.type === "table_row" /* TABLE_ROW */) {
164
+ rows.push(value);
165
+ }
166
+ }
167
+ } catch {
168
+ return [];
169
+ }
170
+ return rows;
171
+ };
172
+ var fetchTableRowsFromServer = async (server, tenantId, tableId, headers, fetchImpl = fetch) => {
173
+ const controller = new AbortController();
174
+ const timeoutId = setTimeout(
175
+ () => controller.abort(),
176
+ TABLE_ROWS_FETCH_TIMEOUT_MS
177
+ );
178
+ try {
179
+ const res = await fetchImpl(`${server}/rpc/listTableRows`, {
180
+ method: "POST",
181
+ headers,
182
+ credentials: "include",
183
+ body: JSON.stringify({
184
+ tenantId,
185
+ tableId,
186
+ includeDeleted: true,
187
+ envelope: TABLE_SYNC_ENVELOPE
188
+ }),
189
+ signal: controller.signal
190
+ });
191
+ if (!res.ok) {
192
+ let msg = `\u52A0\u8F7D\u8868 ${tableId} \u884C\u5931\u8D25\uFF08${res.status}\uFF09`;
193
+ try {
194
+ const err2 = await res.json();
195
+ if (err2 && typeof err2.message === "string") {
196
+ msg = err2.message;
197
+ }
198
+ } catch {
199
+ }
200
+ throw new Error(msg);
201
+ }
202
+ const data = await res.json();
203
+ if (Array.isArray(data)) {
204
+ return {
205
+ rows: data,
206
+ deletedRows: [],
207
+ tableMeta: null,
208
+ complete: false
209
+ };
210
+ }
211
+ if (!data || typeof data !== "object" || !Array.isArray(data.rows)) {
212
+ throw new Error("\u670D\u52A1\u5668\u8FD4\u56DE\u683C\u5F0F\u9519\u8BEF\uFF1A\u9884\u671F\u4E3A\u6570\u7EC4");
213
+ }
214
+ return {
215
+ rows: data.rows,
216
+ deletedRows: Array.isArray(data.deletedRows) ? data.deletedRows : [],
217
+ tableMeta: data.tableMeta ?? null,
218
+ complete: data.complete === true
219
+ };
220
+ } catch (err2) {
221
+ if (isAbortError(err2)) {
222
+ throw new Error(
223
+ `\u52A0\u8F7D\u8868 ${tableId} \u884C\u8D85\u65F6\uFF1A${server} \u5728 ${TABLE_ROWS_FETCH_TIMEOUT_MS / 1e3}s \u5185\u65E0\u54CD\u5E94`
224
+ );
225
+ }
226
+ throw err2;
227
+ } finally {
228
+ clearTimeout(timeoutId);
229
+ }
230
+ };
231
+ var cacheMergedTableRows = async (db, mergedRows) => {
232
+ if (!db) return;
233
+ await Promise.all(
234
+ mergedRows.map(async (mergedRow) => {
235
+ if (!mergedRow?.dbKey) return;
236
+ try {
237
+ const localRow = await db.get(mergedRow.dbKey).catch(() => null);
238
+ if (!localRow) {
239
+ await db.put(mergedRow.dbKey, mergedRow);
240
+ return;
241
+ }
242
+ const serverTs = new Date(
243
+ mergedRow.updatedAt ?? mergedRow.createdAt ?? 0
244
+ ).getTime();
245
+ const localTs = new Date(
246
+ localRow.updatedAt ?? localRow.createdAt ?? 0
247
+ ).getTime();
248
+ const shouldOverwrite = serverTs > localTs || serverTs === localTs && Boolean(mergedRow.deletedAt) && !Boolean(localRow.deletedAt);
249
+ if (shouldOverwrite) {
250
+ await db.put(mergedRow.dbKey, mergedRow);
251
+ }
252
+ } catch {
253
+ }
254
+ })
255
+ );
256
+ };
257
+ var clearStaleLocalRows = async (db, localRows, authoritativeRows) => {
258
+ if (!db || typeof db.del !== "function") return;
259
+ const authoritativeKeys = new Set(
260
+ authoritativeRows.map((row) => row?.dbKey).filter((dbKey) => typeof dbKey === "string" && dbKey.length > 0)
261
+ );
262
+ await Promise.all(
263
+ localRows.map(async (row) => {
264
+ const dbKey = row?.dbKey;
265
+ if (typeof dbKey !== "string" || authoritativeKeys.has(dbKey)) return;
266
+ try {
267
+ await db.del(dbKey);
268
+ } catch {
269
+ }
270
+ })
271
+ );
272
+ };
273
+ var keepRemoteRowForPartialMerge = (row, localRowsByKey) => {
274
+ const dbKey = row?.dbKey;
275
+ if (typeof dbKey !== "string" || !dbKey) return false;
276
+ const localRow = localRowsByKey.get(dbKey);
277
+ if (!localRow) return true;
278
+ const remoteDeleted = Boolean(row?.deletedAt);
279
+ const localDeleted = Boolean(localRow?.deletedAt);
280
+ return remoteDeleted === localDeleted;
281
+ };
282
+ var fetchAndCacheTableRows = async ({
283
+ db,
284
+ tenantId,
285
+ tableId,
286
+ token,
287
+ remoteServers = [],
288
+ fetchImpl = fetch
289
+ }) => {
290
+ const headers = {
291
+ "Content-Type": "application/json"
292
+ };
293
+ if (typeof token === "string" && token.trim()) {
294
+ headers.Authorization = `Bearer ${token.trim()}`;
295
+ }
296
+ const isWebBrowser = typeof window !== "undefined" && !getIsDesktopApp();
297
+ const serversToQuery = isWebBrowser && remoteServers.length > 0 ? [remoteServers[0]] : remoteServers;
298
+ const localRows = await loadLocalTableRows(db, tenantId, tableId);
299
+ const remoteResults = await Promise.allSettled(
300
+ serversToQuery.map(
301
+ (server) => fetchTableRowsFromServer(server, tenantId, tableId, headers, fetchImpl)
302
+ )
303
+ );
304
+ const fulfilledRemoteSnapshots = remoteResults.filter(
305
+ (result) => result.status === "fulfilled"
306
+ ).map((result) => result.value);
307
+ if (fulfilledRemoteSnapshots.length === 0 && localRows.length === 0) {
308
+ const firstFailure = remoteResults.find(
309
+ (result) => result.status === "rejected"
310
+ );
311
+ throw new Error(firstFailure?.reason?.message || "\u52A0\u8F7D\u8868\u884C\u5931\u8D25");
312
+ }
313
+ const allRemoteSnapshotsComplete = serversToQuery.length > 0 && remoteResults.length === serversToQuery.length && fulfilledRemoteSnapshots.length === serversToQuery.length && fulfilledRemoteSnapshots.every((snapshot) => snapshot.complete);
314
+ const localRowsByKey = new Map(
315
+ localRows.filter((row) => typeof row?.dbKey === "string" && row.dbKey.length > 0).map((row) => [row.dbKey, row])
316
+ );
317
+ const remoteRowLists = fulfilledRemoteSnapshots.map((snapshot) => {
318
+ const snapshotRows = [...snapshot.rows, ...snapshot.deletedRows];
319
+ return allRemoteSnapshotsComplete ? snapshotRows : snapshotRows.filter((row) => keepRemoteRowForPartialMerge(row, localRowsByKey));
320
+ });
321
+ const authoritativeRemoteRows = remoteRowLists.flat();
322
+ const tableDeleted = allRemoteSnapshotsComplete && Boolean(getLatestTableMeta(fulfilledRemoteSnapshots)?.deletedAt);
323
+ if (allRemoteSnapshotsComplete) {
324
+ await clearStaleLocalRows(db, localRows, authoritativeRemoteRows);
325
+ }
326
+ const localRowsForMerge = allRemoteSnapshotsComplete ? localRows.filter(
327
+ (row) => authoritativeRemoteRows.some((remoteRow) => remoteRow?.dbKey === row?.dbKey)
328
+ ) : localRows;
329
+ const mergedRows = mergeTableRows(localRowsForMerge, ...remoteRowLists);
330
+ await cacheMergedTableRows(db, mergedRows);
331
+ return tableDeleted ? [] : mergedRows.filter((row) => !row?.deletedAt);
332
+ };
333
+
334
+ // packages/render/table/tableColumnCore.ts
335
+ var ok = (value) => ({ ok: true, value });
336
+ var err = (error) => ({ ok: false, error });
337
+ var hasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key);
338
+ var buildMeta = (meta, columns, updatedAt) => ({
339
+ meta: { ...meta, columns, updatedAt },
340
+ metaChanges: { columns, updatedAt },
341
+ noop: false
342
+ });
343
+ var reorderList = (list, from, to) => {
344
+ const next = [...list];
345
+ const [moved] = next.splice(from, 1);
346
+ next.splice(to, 0, moved);
347
+ return next;
348
+ };
349
+ function addColumnToMeta(meta, input, deps) {
350
+ const { columnName } = input;
351
+ if (!columnName.trim()) {
352
+ return err("\u5B57\u6BB5\u540D\u4E0D\u80FD\u4E3A\u7A7A");
353
+ }
354
+ if (meta.columns.some((c) => c.name === columnName)) {
355
+ return err(`\u5B57\u6BB5 ${columnName} \u5DF2\u5B58\u5728`);
356
+ }
357
+ const newColumn = {
358
+ id: deps.id,
359
+ name: columnName,
360
+ label: columnName
361
+ };
362
+ return ok(buildMeta(meta, [...meta.columns, newColumn], deps.nowIso));
363
+ }
364
+ function deleteColumnFromMeta(meta, rows, input, deps) {
365
+ const { columnName } = input;
366
+ const { nowIso } = deps;
367
+ if (!meta.columns.some((c) => c.name === columnName)) {
368
+ return err(`\u5B57\u6BB5 ${columnName} \u4E0D\u5B58\u5728`);
369
+ }
370
+ const newColumns = meta.columns.filter((c) => c.name !== columnName);
371
+ const rowPatches = rows.filter((row) => hasOwn(row, columnName)).map((row) => ({
372
+ dbKey: row.dbKey,
373
+ changes: { [columnName]: null, updatedAt: nowIso }
374
+ }));
375
+ const newRows = rows.map((row) => {
376
+ if (!hasOwn(row, columnName)) {
377
+ return row;
378
+ }
379
+ const { [columnName]: _removed, ...rest } = row;
380
+ return { ...rest, updatedAt: nowIso };
381
+ });
382
+ return ok({
383
+ ...buildMeta(meta, newColumns, nowIso),
384
+ rows: newRows,
385
+ rowPatches
386
+ });
387
+ }
388
+ function reorderColumnInMeta(meta, input, deps) {
389
+ const { fromIndex, toIndex } = input;
390
+ const columnCount = meta.columns.length;
391
+ if (fromIndex < 0 || fromIndex >= columnCount || toIndex < 0 || toIndex >= columnCount) {
392
+ return err("\u5217\u7D22\u5F15\u8D85\u51FA\u8303\u56F4");
393
+ }
394
+ if (fromIndex === toIndex) {
395
+ return ok({
396
+ meta,
397
+ metaChanges: { columns: meta.columns, updatedAt: meta.updatedAt },
398
+ noop: true
399
+ });
400
+ }
401
+ return ok(
402
+ buildMeta(meta, reorderList(meta.columns, fromIndex, toIndex), deps.nowIso)
403
+ );
404
+ }
405
+ function renameColumnLabelInMeta(meta, input, deps) {
406
+ const { columnId } = input;
407
+ const label = input.label.trim();
408
+ if (!label) {
409
+ return err("\u5B57\u6BB5\u663E\u793A\u540D\u4E0D\u80FD\u4E3A\u7A7A");
410
+ }
411
+ if (!meta.columns.some((c) => c.id === columnId)) {
412
+ return err("\u8981\u91CD\u547D\u540D\u7684\u5B57\u6BB5\u4E0D\u5B58\u5728");
413
+ }
414
+ const newColumns = meta.columns.map(
415
+ (c) => c.id === columnId ? { ...c, label } : c
416
+ );
417
+ return ok(buildMeta(meta, newColumns, deps.nowIso));
418
+ }
419
+ function updateColumnWidthInMeta(meta, input, deps) {
420
+ const { columnId, width } = input;
421
+ if (!meta.columns.some((c) => c.id === columnId)) {
422
+ return err("\u8981\u8C03\u6574\u5BBD\u5EA6\u7684\u5B57\u6BB5\u4E0D\u5B58\u5728");
423
+ }
424
+ const normalizedWidth = typeof width === "number" && width > 0 ? Math.round(width) : void 0;
425
+ const newColumns = meta.columns.map(
426
+ (c) => c.id === columnId ? { ...c, width: normalizedWidth } : c
427
+ );
428
+ return ok(buildMeta(meta, newColumns, deps.nowIso));
429
+ }
430
+ function addColumnOptionInMeta(meta, input, deps) {
431
+ const { columnId } = input;
432
+ const option = input.option.trim();
433
+ if (!option) {
434
+ return err("\u9009\u9879\u540D\u4E0D\u80FD\u4E3A\u7A7A");
435
+ }
436
+ const column = meta.columns.find((c) => c.id === columnId);
437
+ if (!column) {
438
+ return err("\u8981\u65B0\u589E\u9009\u9879\u7684\u5B57\u6BB5\u4E0D\u5B58\u5728");
439
+ }
440
+ if ((column.options ?? []).some((o) => o.trim() === option)) {
441
+ return ok({
442
+ meta,
443
+ metaChanges: { columns: meta.columns, updatedAt: meta.updatedAt },
444
+ noop: true
445
+ });
446
+ }
447
+ const newColumns = meta.columns.map(
448
+ (c) => c.id === columnId ? { ...c, options: [...c.options ?? [], option] } : c
449
+ );
450
+ return ok(buildMeta(meta, newColumns, deps.nowIso));
451
+ }
452
+
453
+ // packages/render/table/createTableAction.ts
454
+ import { ulid as ulid2 } from "ulid";
455
+ var DEFAULT_COLUMNS = [
456
+ {
457
+ name: "title",
458
+ label: "\u6807\u9898",
459
+ type: "text",
460
+ description: "\u8FD9\u4E00\u884C\u8BB0\u5F55\u7684\u4E3B\u9898\u6216\u540D\u79F0\u3002",
461
+ isPrimary: true,
462
+ required: true
463
+ },
464
+ {
465
+ name: "note",
466
+ label: "\u5907\u6CE8",
467
+ type: "text",
468
+ description: "\u5BF9\u8BE5\u6761\u76EE\u7684\u8865\u5145\u8BF4\u660E\u3002",
469
+ required: false
470
+ }
471
+ ];
472
+ var normalizeColumns = (inputColumns) => {
473
+ const base = Array.isArray(inputColumns) ? inputColumns : [];
474
+ const normalized = base.map((c) => {
475
+ if (!c || typeof c.name !== "string") return null;
476
+ const name = c.name.trim();
477
+ if (!name) return null;
478
+ const col = {
479
+ id: asOptionalTrimmedString(c.id) ?? ulid2(),
480
+ name
481
+ };
482
+ const label = asOptionalTrimmedString(c.label);
483
+ if (label) col.label = label;
484
+ if (typeof c.type === "string") {
485
+ col.type = c.type;
486
+ }
487
+ const description = asOptionalTrimmedString(c.description);
488
+ if (description) col.description = description;
489
+ if (typeof c.isPrimary === "boolean") {
490
+ col.isPrimary = c.isPrimary;
491
+ }
492
+ if (typeof c.required === "boolean") {
493
+ col.required = c.required;
494
+ }
495
+ if (Array.isArray(c.options)) {
496
+ const opts = asTrimmedNonEmptyStringArray(c.options);
497
+ if (opts.length) {
498
+ col.options = opts;
499
+ }
500
+ }
501
+ return col;
502
+ }).filter(Boolean);
503
+ if (normalized.length > 0) {
504
+ if (!normalized.some((c) => c.isPrimary)) {
505
+ normalized[0].isPrimary = true;
506
+ }
507
+ return normalized;
508
+ }
509
+ return DEFAULT_COLUMNS.map((c) => ({
510
+ ...c,
511
+ id: ulid2()
512
+ }));
513
+ };
514
+ var normalizeStringArray = (value) => {
515
+ if (!Array.isArray(value)) return void 0;
516
+ const items = [...new Set(asTrimmedNonEmptyStringArray(value))];
517
+ return items.length ? items : void 0;
518
+ };
519
+ var normalizePublicIntake = (input) => {
520
+ if (!isRecord(input)) return void 0;
521
+ const allowedFields = normalizeStringArray(input.allowedFields) ?? [];
522
+ if (input.enabled !== true) {
523
+ return { enabled: false, allowedFields };
524
+ }
525
+ if (allowedFields.length === 0) {
526
+ throw new Error("publicIntake.allowedFields \u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5B57\u6BB5\u3002");
527
+ }
528
+ const slug = asOptionalTrimmedString(input.slug);
529
+ const honeypotField = asOptionalTrimmedString(input.honeypotField);
530
+ return {
531
+ enabled: true,
532
+ ...slug ? { slug } : {},
533
+ ...normalizeStringArray(input.appIds) ? { appIds: normalizeStringArray(input.appIds) } : {},
534
+ allowedFields,
535
+ ...normalizeStringArray(input.requiredFields) ? { requiredFields: normalizeStringArray(input.requiredFields) } : {},
536
+ ...honeypotField ? { honeypotField } : {}
537
+ };
538
+ };
539
+ var createTableAction = async ({
540
+ spaceId: customSpaceId,
541
+ title: customTitle,
542
+ purpose: customPurpose,
543
+ description: customDescription,
544
+ tags: customTags,
545
+ publicIntake,
546
+ categoryId,
547
+ columns,
548
+ withDefaultRows = true
549
+ } = {}, { dispatch, getState }) => {
550
+ const state3 = getState();
551
+ const userId = selectIdentityUserId(state3);
552
+ if (!userId) throw new Error("User ID not found.");
553
+ const spaceId = customSpaceId ?? getCurrentSpaceId();
554
+ const tableId = ulid2();
555
+ const now = /* @__PURE__ */ new Date();
556
+ const nowIso = formatISO(now);
557
+ const dbKey = metaKey(userId, tableId);
558
+ const defaultTitle = runtime_default.t("space:newTable", {
559
+ defaultValue: "\u65B0\u5EFA\u8868\u683C"
560
+ });
561
+ const title = asOptionalTrimmedString(customTitle) ?? defaultTitle;
562
+ const purpose = asOptionalTrimmedString(customPurpose);
563
+ const description = asOptionalTrimmedString(customDescription);
564
+ const tags = Array.isArray(customTags) && customTags.length ? asTrimmedNonEmptyStringArray(customTags) : void 0;
565
+ const finalPublicIntake = normalizePublicIntake(publicIntake);
566
+ const finalColumns = normalizeColumns(columns);
567
+ const tableMeta = {
568
+ dbKey,
569
+ tenantId: userId,
570
+ tableId,
571
+ spaceId: spaceId ?? null,
572
+ displayName: title,
573
+ purpose,
574
+ description,
575
+ tags,
576
+ schemaVersion: 1,
577
+ columns: finalColumns,
578
+ views: [],
579
+ // 后续可以在 UI 中新增视图
580
+ triggers: [],
581
+ // 后续可以在 UI/配置中新增触发器
582
+ aiConfig: void 0,
583
+ ...finalPublicIntake ? { publicIntake: finalPublicIntake } : {},
584
+ createdAt: nowIso,
585
+ updatedAt: nowIso,
586
+ type: "table" /* TABLE */
587
+ };
588
+ await dispatch(
589
+ write({
590
+ data: tableMeta,
591
+ customKey: dbKey
592
+ })
593
+ ).unwrap();
594
+ if (withDefaultRows) {
595
+ const defaultRows = [
596
+ {
597
+ title: "\u793A\u4F8B\u4E00",
598
+ note: "\u4F60\u53EF\u4EE5\u5728\u8FD9\u91CC\u8BB0\u5F55\u4EFB\u4F55\u5185\u5BB9\uFF0C\u4F8B\u5982\u4EFB\u52A1\u3001\u60F3\u6CD5\u6216\u914D\u7F6E\u9879\u3002"
599
+ },
600
+ {
601
+ title: "\u793A\u4F8B\u4E8C",
602
+ note: "\u53CC\u51FB\u5355\u5143\u683C\u5F00\u59CB\u7F16\u8F91\uFF0C\u53F3\u4E0A\u89D2\u53EF\u4EE5\u6DFB\u52A0\u5B57\u6BB5\u548C\u884C\u3002"
603
+ }
604
+ ];
605
+ await Promise.all(
606
+ defaultRows.map(async (values) => {
607
+ const { dbKey: rowKeyStr, rowId } = rowKey.create(userId, tableId);
608
+ const row = {
609
+ dbKey: rowKeyStr,
610
+ tenantId: userId,
611
+ tableId,
612
+ rowId,
613
+ createdAt: nowIso,
614
+ updatedAt: nowIso,
615
+ type: "table_row" /* TABLE_ROW */,
616
+ ...values
617
+ };
618
+ await dispatch(
619
+ write({
620
+ data: row,
621
+ customKey: rowKeyStr
622
+ })
623
+ ).unwrap();
624
+ })
625
+ );
626
+ }
627
+ if (spaceId) {
628
+ await dispatch(
629
+ addContentToSpace({
630
+ spaceId,
631
+ contentKey: dbKey,
632
+ type: "table" /* TABLE */,
633
+ title,
634
+ categoryId
635
+ })
636
+ ).unwrap();
637
+ }
638
+ if (typeof window !== "undefined") {
639
+ window.dispatchEvent(new Event("nolo-user-data-updated"));
640
+ }
641
+ return dbKey;
642
+ };
643
+
644
+ // packages/render/table/deleteTableAction.ts
645
+ var parseMetaKey = (dbKey) => {
646
+ const parts = dbKey.split(SEPARATOR);
647
+ if (parts[0] !== "meta" || parts.length < 3) {
648
+ throw new Error(`\u975E\u6CD5\u8868 key\uFF1A${dbKey}`);
649
+ }
650
+ const tenantId = parts[1];
651
+ const tableId = parts.slice(2).join(SEPARATOR);
652
+ return { tenantId, tableId };
653
+ };
654
+ var collectEntriesByPrefix = async (db, prefix) => {
655
+ const entries = [];
656
+ for await (const [key, value] of db.iterator({
657
+ gte: prefix,
658
+ lte: prefix + "\uFFFF"
659
+ })) {
660
+ entries.push([key, value]);
661
+ }
662
+ return entries;
663
+ };
664
+ var belongsToTable = (value, tenantId, tableId) => Boolean(
665
+ value && typeof value === "object" && value.tenantId === tenantId && value.tableId === tableId
666
+ );
667
+ var indexValueReferencesRows = (value, rowDbKeys, rowIds) => {
668
+ if (typeof value === "string") {
669
+ return rowDbKeys.has(value) || rowIds.has(value);
670
+ }
671
+ if (!value || typeof value !== "object") return false;
672
+ const candidate = value;
673
+ return typeof candidate.dbKey === "string" && rowDbKeys.has(candidate.dbKey) || typeof candidate.rowDbKey === "string" && rowDbKeys.has(candidate.rowDbKey) || typeof candidate.rowId === "string" && rowIds.has(candidate.rowId);
674
+ };
675
+ var deleteTableAction = async ({ dbKey }, {
676
+ dispatch,
677
+ getState,
678
+ extra
679
+ }) => {
680
+ const { db } = extra;
681
+ const state3 = getState();
682
+ const { currentServer, syncServers } = getRuntimeServerContext(state3);
683
+ const { tenantId, tableId } = parseMetaKey(dbKey);
684
+ const nowIso = (/* @__PURE__ */ new Date()).toISOString();
685
+ const rowPrefix = createKey("row", tenantId, tableId, "");
686
+ const rowEntries = (await collectEntriesByPrefix(db, rowPrefix)).filter(
687
+ ([, value]) => belongsToTable(value, tenantId, tableId)
688
+ );
689
+ const rowDbKeys = new Set(rowEntries.map(([key]) => key));
690
+ const rowIds = new Set(
691
+ rowEntries.map(([, value]) => value.rowId).filter((rowId) => typeof rowId === "string")
692
+ );
693
+ const idxPrefix = createKey("idx", tenantId, tableId, "");
694
+ const idxEntries = await collectEntriesByPrefix(db, idxPrefix);
695
+ const idxKeys = idxEntries.filter(
696
+ ([, value]) => belongsToTable(value, tenantId, tableId) || indexValueReferencesRows(value, rowDbKeys, rowIds)
697
+ ).map(([key]) => key);
698
+ const viewPrefix = createKey("view", tenantId, tableId, "");
699
+ const viewEntries = await collectEntriesByPrefix(db, viewPrefix);
700
+ const viewKeys = viewEntries.filter(([, value]) => belongsToTable(value, tenantId, tableId)).map(([key]) => key);
701
+ const metaRecord = typeof db.get === "function" ? await db.get(dbKey).catch(() => null) : null;
702
+ const keysToDelete = Array.from(
703
+ /* @__PURE__ */ new Set([
704
+ ...idxKeys,
705
+ ...viewKeys
706
+ ])
707
+ );
708
+ const putOps = [
709
+ ...metaRecord && typeof metaRecord === "object" ? [
710
+ {
711
+ type: "put",
712
+ key: dbKey,
713
+ value: buildTombstoneRecord(metaRecord, nowIso)
714
+ }
715
+ ] : [],
716
+ ...rowEntries.map(([key, value]) => ({
717
+ type: "put",
718
+ key,
719
+ value: buildTombstoneRecord(value, nowIso)
720
+ }))
721
+ ];
722
+ if (keysToDelete.length > 0 || putOps.length > 0) {
723
+ const ops = [
724
+ ...putOps,
725
+ ...keysToDelete.map((key) => ({
726
+ type: "del",
727
+ key
728
+ }))
729
+ ];
730
+ await db.batch(ops);
731
+ }
732
+ scheduleDeleteReplication({
733
+ currentServer,
734
+ syncServers,
735
+ dbKey,
736
+ deleteOptions: { type: "table" },
737
+ state: state3
738
+ });
739
+ return dbKey;
740
+ };
741
+
742
+ // packages/render/table/tableStore.ts
743
+ async function safeDispatch(dispatch, action) {
744
+ if (!dispatch) return void 0;
745
+ const res = await dispatch(action);
746
+ if (res && typeof res.unwrap === "function") {
747
+ return await res.unwrap();
748
+ }
749
+ return res?.payload ?? res;
750
+ }
751
+ var createInitialState = () => ({
752
+ currentTable: null,
753
+ expectedTableKey: null,
754
+ isLoading: false,
755
+ isInitialized: false,
756
+ error: null,
757
+ rows: [],
758
+ focusContext: null
759
+ });
760
+ var listeners = /* @__PURE__ */ new Set();
761
+ var version = 0;
762
+ var state = createInitialState();
763
+ var notify = () => {
764
+ for (const listener of listeners) {
765
+ try {
766
+ listener();
767
+ } catch {
768
+ }
769
+ }
770
+ };
771
+ var bump = () => {
772
+ version += 1;
773
+ notify();
774
+ };
775
+ var setState = (updater) => {
776
+ state = typeof updater === "function" ? updater(state) : updater;
777
+ bump();
778
+ };
779
+ function getTableState() {
780
+ return state;
781
+ }
782
+ function createTableCommand(name, fn) {
783
+ const command = (args) => {
784
+ return async (dispatch, getState, extra) => {
785
+ try {
786
+ const payload = await fn(args, { dispatch, getState, extra });
787
+ return {
788
+ type: `${name}/fulfilled`,
789
+ payload,
790
+ meta: { arg: args },
791
+ unwrap: async () => payload
792
+ };
793
+ } catch (err2) {
794
+ const message = err2?.message || String(err2);
795
+ return {
796
+ type: `${name}/rejected`,
797
+ payload: message,
798
+ error: { message },
799
+ unwrap: async () => {
800
+ throw err2 instanceof Error ? err2 : new Error(message);
801
+ }
802
+ };
803
+ }
804
+ };
805
+ };
806
+ command.fulfilled = {
807
+ type: `${name}/fulfilled`,
808
+ match: (action) => action?.type === `${name}/fulfilled`
809
+ };
810
+ command.rejected = {
811
+ type: `${name}/rejected`,
812
+ match: (action) => action?.type === `${name}/rejected`
813
+ };
814
+ command.pending = {
815
+ type: `${name}/pending`,
816
+ match: (action) => action?.type === `${name}/pending`
817
+ };
818
+ command.run = (args, context = {}) => fn(args, context);
819
+ return command;
820
+ }
821
+ var initTable = createTableCommand(
822
+ "table/initTable",
823
+ async (args, { dispatch } = {}) => {
824
+ const { tenantId, tableId } = args;
825
+ const dbKey = metaKey(tenantId, tableId);
826
+ setState((s) => ({
827
+ ...s,
828
+ isLoading: true,
829
+ error: null,
830
+ isInitialized: false,
831
+ currentTable: null,
832
+ // 从第一行起就声明「预期表」:读取期间 currentTable 为 null,
833
+ // 但只有本表的 loadTableRows 结果有权写入(见 isCurrentTableTarget)。
834
+ expectedTableKey: { tenantId, tableId },
835
+ rows: []
836
+ }));
837
+ try {
838
+ if (!dispatch) {
839
+ throw new Error("dispatch is required to initialize table");
840
+ }
841
+ const readAction = await dispatch(readAndWait(dbKey));
842
+ const isMatch = typeof readAndWait?.fulfilled?.match === "function" && readAndWait.fulfilled.match(readAction);
843
+ const meta = isMatch && readAction.payload ? readAction.payload : readAction?.payload || readAction;
844
+ if (meta && typeof meta === "object" && ("columns" in meta || "displayName" in meta || "tableId" in meta)) {
845
+ setState((s) => {
846
+ if (!isCurrentTableTarget(s, tenantId, tableId)) return s;
847
+ return {
848
+ ...s,
849
+ isLoading: false,
850
+ isInitialized: true,
851
+ currentTable: meta,
852
+ error: null
853
+ };
854
+ });
855
+ return meta;
856
+ }
857
+ const msg = readAction.payload?.message || `\u65E0\u6CD5\u52A0\u8F7D\u8868 ${tableId}`;
858
+ setState((s) => {
859
+ if (!isCurrentTableTarget(s, tenantId, tableId)) return s;
860
+ return {
861
+ ...s,
862
+ isLoading: false,
863
+ isInitialized: true,
864
+ currentTable: null,
865
+ error: msg,
866
+ rows: []
867
+ };
868
+ });
869
+ throw new Error(msg);
870
+ } catch (e) {
871
+ const msg = e?.message || `\u521D\u59CB\u5316\u8868 ${tableId} \u65F6\u51FA\u9519`;
872
+ setState((s) => {
873
+ if (!isCurrentTableTarget(s, tenantId, tableId)) return s;
874
+ return {
875
+ ...s,
876
+ isLoading: false,
877
+ isInitialized: true,
878
+ currentTable: null,
879
+ error: msg,
880
+ rows: []
881
+ };
882
+ });
883
+ throw e;
884
+ }
885
+ }
886
+ );
887
+ var sameTableTarget = (target, tenantId, tableId) => !!target && target.tenantId === tenantId && target.tableId === tableId;
888
+ var isCurrentTableTarget = (s, tenantId, tableId) => {
889
+ if (s.expectedTableKey) {
890
+ return sameTableTarget(s.expectedTableKey, tenantId, tableId);
891
+ }
892
+ if (s.currentTable) {
893
+ return sameTableTarget(s.currentTable, tenantId, tableId);
894
+ }
895
+ return true;
896
+ };
897
+ var loadTableRows = createTableCommand(
898
+ "table/loadTableRows",
899
+ async (args, { getState, extra } = {}) => {
900
+ const { tenantId, tableId } = args;
901
+ const db = extra?.db;
902
+ setState((s) => {
903
+ if (isCurrentTableTarget(s, tenantId, tableId)) {
904
+ return { ...s, error: null };
905
+ }
906
+ return s;
907
+ });
908
+ try {
909
+ const stateObj = getState ? getState() : {};
910
+ const { currentToken: token, remoteServers } = getRuntimeServerContext(stateObj);
911
+ const rows = await fetchAndCacheTableRows({
912
+ db,
913
+ tenantId,
914
+ tableId,
915
+ token,
916
+ remoteServers
917
+ });
918
+ setState((s) => {
919
+ if (isCurrentTableTarget(s, tenantId, tableId)) {
920
+ return { ...s, rows };
921
+ }
922
+ return s;
923
+ });
924
+ return rows;
925
+ } catch (e) {
926
+ const msg = e?.message || "\u52A0\u8F7D\u8868\u884C\u5931\u8D25";
927
+ try {
928
+ const stateObj = getState ? getState() : {};
929
+ const { remoteServers } = getRuntimeServerContext(stateObj);
930
+ logger.warn(
931
+ {
932
+ tenantId,
933
+ tableId,
934
+ remoteServers: remoteServers?.length ?? 0,
935
+ err: msg
936
+ },
937
+ "loadTableRows failed"
938
+ );
939
+ } catch {
940
+ }
941
+ setState((s) => {
942
+ if (isCurrentTableTarget(s, tenantId, tableId)) {
943
+ return { ...s, error: msg, rows: [] };
944
+ }
945
+ return s;
946
+ });
947
+ throw e;
948
+ }
949
+ }
950
+ );
951
+ var addRow = createTableCommand(
952
+ "table/addRow",
953
+ async (args, { dispatch } = {}) => {
954
+ const { tenantId, tableId, values } = args;
955
+ setState((s) => {
956
+ if (s.currentTable && s.currentTable.tenantId === tenantId && s.currentTable.tableId === tableId) {
957
+ return { ...s, error: null };
958
+ }
959
+ return s;
960
+ });
961
+ try {
962
+ const { dbKey, rowId } = rowKey.create(tenantId, tableId);
963
+ const nowIso = formatISO(/* @__PURE__ */ new Date());
964
+ const row = {
965
+ dbKey,
966
+ tenantId,
967
+ tableId,
968
+ rowId,
969
+ createdAt: nowIso,
970
+ updatedAt: nowIso,
971
+ type: "table_row" /* TABLE_ROW */,
972
+ ...values
973
+ };
974
+ if (dispatch) {
975
+ await safeDispatch(
976
+ dispatch,
977
+ write({
978
+ data: row,
979
+ customKey: dbKey
980
+ })
981
+ );
982
+ }
983
+ setState((s) => {
984
+ const meta = s.currentTable;
985
+ if (meta && row?.tenantId === meta.tenantId && row?.tableId === meta.tableId) {
986
+ return { ...s, rows: [...s.rows, row] };
987
+ }
988
+ return s;
989
+ });
990
+ return row;
991
+ } catch (e) {
992
+ const msg = e?.message || "\u65B0\u589E\u8868\u884C\u5931\u8D25";
993
+ setState((s) => {
994
+ if (s.currentTable && s.currentTable.tenantId === tenantId && s.currentTable.tableId === tableId) {
995
+ return { ...s, error: msg };
996
+ }
997
+ return s;
998
+ });
999
+ throw e;
1000
+ }
1001
+ }
1002
+ );
1003
+ var deleteRow = createTableCommand(
1004
+ "table/deleteRow",
1005
+ async (dbKey, { dispatch, getState, extra } = {}) => {
1006
+ try {
1007
+ let row = state.rows.find((item) => item?.dbKey === dbKey);
1008
+ if (!row && extra?.db && typeof extra.db.get === "function") {
1009
+ try {
1010
+ row = await extra.db.get(dbKey);
1011
+ } catch {
1012
+ }
1013
+ }
1014
+ if (!row && dispatch) {
1015
+ try {
1016
+ const readAction = await safeDispatch(dispatch, readAndWait(dbKey));
1017
+ row = readAction?.payload || readAction;
1018
+ } catch {
1019
+ }
1020
+ }
1021
+ if (!row) {
1022
+ throw new Error(`\u5F53\u524D\u8868\u4E2D\u627E\u4E0D\u5230\u8981\u5220\u9664\u7684\u884C\uFF1A${dbKey}`);
1023
+ }
1024
+ const nowIso = formatISO(/* @__PURE__ */ new Date());
1025
+ const tombstoneRow = {
1026
+ ...row,
1027
+ deletedAt: nowIso,
1028
+ updatedAt: nowIso,
1029
+ type: "table_row" /* TABLE_ROW */
1030
+ };
1031
+ if (extra?.db && typeof extra.db.put === "function") {
1032
+ await extra.db.put(dbKey, tombstoneRow);
1033
+ }
1034
+ if (dispatch) {
1035
+ dispatch(upsertSSREntity(tombstoneRow));
1036
+ }
1037
+ const stateObj = getState ? getState() : {};
1038
+ const { currentServer, syncServers } = getRuntimeServerContext(stateObj);
1039
+ const servers = resolveReplicationServers(currentServer, syncServers);
1040
+ scheduleWriteReplication(
1041
+ servers,
1042
+ {
1043
+ data: tombstoneRow,
1044
+ customKey: dbKey
1045
+ },
1046
+ stateObj
1047
+ );
1048
+ setState((s) => ({
1049
+ ...s,
1050
+ rows: s.rows.filter((r) => r.dbKey !== dbKey)
1051
+ }));
1052
+ return dbKey;
1053
+ } catch (e) {
1054
+ const msg = e?.message || "\u5220\u9664\u8868\u884C\u5931\u8D25";
1055
+ setState((s) => ({ ...s, error: msg }));
1056
+ throw e;
1057
+ }
1058
+ }
1059
+ );
1060
+ var createTable = createTableCommand(
1061
+ "table/createTable",
1062
+ async (args, context = {}) => {
1063
+ return await createTableAction(args, context);
1064
+ }
1065
+ );
1066
+ var deleteTable = createTableCommand(
1067
+ "table/deleteTable",
1068
+ async (args, context = {}) => {
1069
+ setState((s) => ({ ...s, error: null }));
1070
+ try {
1071
+ const deletedKey = await deleteTableAction(args, context);
1072
+ setState((s) => {
1073
+ if (s.currentTable?.dbKey === deletedKey) {
1074
+ return {
1075
+ ...s,
1076
+ currentTable: null,
1077
+ rows: [],
1078
+ isInitialized: false
1079
+ };
1080
+ }
1081
+ return s;
1082
+ });
1083
+ return deletedKey;
1084
+ } catch (e) {
1085
+ const msg = e?.message || "\u5220\u9664\u8868\u65F6\u53D1\u751F\u672A\u77E5\u9519\u8BEF";
1086
+ setState((s) => ({ ...s, error: msg }));
1087
+ throw e;
1088
+ }
1089
+ }
1090
+ );
1091
+ var addColumn = createTableCommand(
1092
+ "table/addColumn",
1093
+ async (args, { dispatch } = {}) => {
1094
+ const { tenantId, tableId, columnName } = args;
1095
+ const meta = state.currentTable;
1096
+ if (!meta || meta.tenantId !== tenantId || meta.tableId !== tableId) {
1097
+ throw new Error("\u5F53\u524D\u6CA1\u6709\u52A0\u8F7D\u5BF9\u5E94\u7684\u8868\u5B9A\u4E49");
1098
+ }
1099
+ const result = addColumnToMeta(
1100
+ meta,
1101
+ { columnName },
1102
+ { id: ulid3(), nowIso: formatISO(/* @__PURE__ */ new Date()) }
1103
+ );
1104
+ if (!result.ok) {
1105
+ throw new Error(result.error);
1106
+ }
1107
+ setState((s) => ({ ...s, error: null }));
1108
+ try {
1109
+ if (dispatch) {
1110
+ await safeDispatch(
1111
+ dispatch,
1112
+ patch({
1113
+ dbKey: meta.dbKey,
1114
+ changes: result.value.metaChanges
1115
+ })
1116
+ );
1117
+ }
1118
+ setState((s) => ({
1119
+ ...s,
1120
+ currentTable: result.value.meta,
1121
+ isInitialized: true
1122
+ }));
1123
+ return result.value.meta;
1124
+ } catch (e) {
1125
+ const msg = e?.message || "\u6DFB\u52A0\u5B57\u6BB5\u5931\u8D25";
1126
+ setState((s) => ({ ...s, error: msg }));
1127
+ throw e;
1128
+ }
1129
+ }
1130
+ );
1131
+ var deleteColumn = createTableCommand(
1132
+ "table/deleteColumn",
1133
+ async (args, { dispatch } = {}) => {
1134
+ const { tenantId, tableId, columnName } = args;
1135
+ const meta = state.currentTable;
1136
+ if (!meta || meta.tenantId !== tenantId || meta.tableId !== tableId) {
1137
+ throw new Error("\u5F53\u524D\u6CA1\u6709\u52A0\u8F7D\u5BF9\u5E94\u7684\u8868\u5B9A\u4E49");
1138
+ }
1139
+ const result = deleteColumnFromMeta(
1140
+ meta,
1141
+ state.rows,
1142
+ { columnName },
1143
+ { nowIso: formatISO(/* @__PURE__ */ new Date()) }
1144
+ );
1145
+ if (!result.ok) {
1146
+ throw new Error(result.error);
1147
+ }
1148
+ const { meta: nextMeta, metaChanges, rows: newRows, rowPatches } = result.value;
1149
+ setState((s) => ({ ...s, error: null }));
1150
+ try {
1151
+ if (dispatch) {
1152
+ await Promise.all(
1153
+ rowPatches.map((p) => safeDispatch(dispatch, patch(p)))
1154
+ );
1155
+ await safeDispatch(
1156
+ dispatch,
1157
+ patch({ dbKey: meta.dbKey, changes: metaChanges })
1158
+ );
1159
+ }
1160
+ setState((s) => ({
1161
+ ...s,
1162
+ currentTable: nextMeta,
1163
+ rows: newRows,
1164
+ isInitialized: true
1165
+ }));
1166
+ return { meta: nextMeta, rows: newRows };
1167
+ } catch (e) {
1168
+ const msg = e?.message || "\u5220\u9664\u5B57\u6BB5\u5931\u8D25";
1169
+ setState((s) => ({ ...s, error: msg }));
1170
+ throw e;
1171
+ }
1172
+ }
1173
+ );
1174
+ var reorderColumn = createTableCommand(
1175
+ "table/reorderColumn",
1176
+ async (args, { dispatch } = {}) => {
1177
+ const { tenantId, tableId, fromIndex, toIndex } = args;
1178
+ const meta = state.currentTable;
1179
+ if (!meta || meta.tenantId !== tenantId || meta.tableId !== tableId) {
1180
+ throw new Error("\u5F53\u524D\u6CA1\u6709\u52A0\u8F7D\u5BF9\u5E94\u7684\u8868\u5B9A\u4E49");
1181
+ }
1182
+ const result = reorderColumnInMeta(
1183
+ meta,
1184
+ { fromIndex, toIndex },
1185
+ { nowIso: formatISO(/* @__PURE__ */ new Date()) }
1186
+ );
1187
+ if (!result.ok) {
1188
+ throw new Error(result.error);
1189
+ }
1190
+ if (result.value.noop) {
1191
+ return meta;
1192
+ }
1193
+ const { meta: nextMeta, metaChanges } = result.value;
1194
+ setState((s) => ({ ...s, error: null }));
1195
+ try {
1196
+ if (dispatch) {
1197
+ await safeDispatch(
1198
+ dispatch,
1199
+ patch({ dbKey: meta.dbKey, changes: metaChanges })
1200
+ );
1201
+ }
1202
+ setState((s) => ({
1203
+ ...s,
1204
+ currentTable: nextMeta,
1205
+ isInitialized: true
1206
+ }));
1207
+ return nextMeta;
1208
+ } catch (e) {
1209
+ const msg = e?.message || "\u8C03\u6574\u5217\u987A\u5E8F\u5931\u8D25";
1210
+ setState((s) => ({ ...s, error: msg }));
1211
+ throw e;
1212
+ }
1213
+ }
1214
+ );
1215
+ var renameColumnLabel = createTableCommand(
1216
+ "table/renameColumnLabel",
1217
+ async (args, { dispatch } = {}) => {
1218
+ const { tenantId, tableId, columnId, newLabel } = args;
1219
+ const meta = state.currentTable;
1220
+ if (!meta || meta.tenantId !== tenantId || meta.tableId !== tableId) {
1221
+ throw new Error("\u5F53\u524D\u6CA1\u6709\u52A0\u8F7D\u5BF9\u5E94\u7684\u8868\u5B9A\u4E49");
1222
+ }
1223
+ const result = renameColumnLabelInMeta(
1224
+ meta,
1225
+ { columnId, label: newLabel },
1226
+ { nowIso: formatISO(/* @__PURE__ */ new Date()) }
1227
+ );
1228
+ if (!result.ok) {
1229
+ throw new Error(result.error);
1230
+ }
1231
+ const { meta: nextMeta, metaChanges } = result.value;
1232
+ setState((s) => ({ ...s, error: null }));
1233
+ try {
1234
+ if (dispatch) {
1235
+ await safeDispatch(
1236
+ dispatch,
1237
+ patch({ dbKey: meta.dbKey, changes: metaChanges })
1238
+ );
1239
+ }
1240
+ setState((s) => ({
1241
+ ...s,
1242
+ currentTable: nextMeta,
1243
+ isInitialized: true
1244
+ }));
1245
+ return nextMeta;
1246
+ } catch (e) {
1247
+ const msg = e?.message || "\u91CD\u547D\u540D\u5B57\u6BB5\u663E\u793A\u540D\u5931\u8D25";
1248
+ setState((s) => ({ ...s, error: msg }));
1249
+ throw e;
1250
+ }
1251
+ }
1252
+ );
1253
+ var updateColumnWidth = createTableCommand(
1254
+ "table/updateColumnWidth",
1255
+ async (args, { dispatch } = {}) => {
1256
+ const { tenantId, tableId, columnId, width } = args;
1257
+ const meta = state.currentTable;
1258
+ if (!meta || meta.tenantId !== tenantId || meta.tableId !== tableId) {
1259
+ throw new Error("\u5F53\u524D\u6CA1\u6709\u52A0\u8F7D\u5BF9\u5E94\u7684\u8868\u5B9A\u4E49");
1260
+ }
1261
+ const result = updateColumnWidthInMeta(
1262
+ meta,
1263
+ { columnId, width },
1264
+ { nowIso: formatISO(/* @__PURE__ */ new Date()) }
1265
+ );
1266
+ if (!result.ok) {
1267
+ throw new Error(result.error);
1268
+ }
1269
+ const { meta: nextMeta, metaChanges } = result.value;
1270
+ setState((s) => ({ ...s, error: null }));
1271
+ try {
1272
+ if (dispatch) {
1273
+ await safeDispatch(
1274
+ dispatch,
1275
+ patch({ dbKey: meta.dbKey, changes: metaChanges })
1276
+ );
1277
+ }
1278
+ setState((s) => ({
1279
+ ...s,
1280
+ currentTable: nextMeta,
1281
+ isInitialized: true
1282
+ }));
1283
+ return nextMeta;
1284
+ } catch (e) {
1285
+ const msg = e?.message || "\u66F4\u65B0\u5B57\u6BB5\u5BBD\u5EA6\u5931\u8D25";
1286
+ setState((s) => ({ ...s, error: msg }));
1287
+ throw e;
1288
+ }
1289
+ }
1290
+ );
1291
+ var addColumnOption = createTableCommand(
1292
+ "table/addColumnOption",
1293
+ async (args, { dispatch } = {}) => {
1294
+ const { tenantId, tableId, columnId, option } = args;
1295
+ const meta = state.currentTable;
1296
+ if (!meta || meta.tenantId !== tenantId || meta.tableId !== tableId) {
1297
+ throw new Error("\u5F53\u524D\u6CA1\u6709\u52A0\u8F7D\u5BF9\u5E94\u7684\u8868\u5B9A\u4E49");
1298
+ }
1299
+ const result = addColumnOptionInMeta(
1300
+ meta,
1301
+ { columnId, option },
1302
+ { nowIso: formatISO(/* @__PURE__ */ new Date()) }
1303
+ );
1304
+ if (!result.ok) {
1305
+ throw new Error(result.error);
1306
+ }
1307
+ if (result.value.noop) {
1308
+ return meta;
1309
+ }
1310
+ const { meta: nextMeta, metaChanges } = result.value;
1311
+ setState((s) => ({ ...s, error: null }));
1312
+ try {
1313
+ if (dispatch) {
1314
+ await safeDispatch(
1315
+ dispatch,
1316
+ patch({ dbKey: meta.dbKey, changes: metaChanges })
1317
+ );
1318
+ }
1319
+ setState((s) => ({
1320
+ ...s,
1321
+ currentTable: nextMeta,
1322
+ isInitialized: true
1323
+ }));
1324
+ return nextMeta;
1325
+ } catch (e) {
1326
+ const msg = e?.message || "\u65B0\u589E\u9009\u9879\u5931\u8D25";
1327
+ setState((s) => ({ ...s, error: msg }));
1328
+ throw e;
1329
+ }
1330
+ }
1331
+ );
1332
+ var renameTable = createTableCommand(
1333
+ "table/renameTable",
1334
+ async (args, { dispatch } = {}) => {
1335
+ const { tenantId, tableId, newName } = args;
1336
+ const trimmedName = newName.trim();
1337
+ if (!trimmedName) {
1338
+ throw new Error("\u8868\u540D\u4E0D\u80FD\u4E3A\u7A7A");
1339
+ }
1340
+ const meta = state.currentTable;
1341
+ if (!meta || meta.tenantId !== tenantId || meta.tableId !== tableId) {
1342
+ throw new Error("\u5F53\u524D\u6CA1\u6709\u52A0\u8F7D\u5BF9\u5E94\u7684\u8868\u5B9A\u4E49");
1343
+ }
1344
+ const nowIso = formatISO(/* @__PURE__ */ new Date());
1345
+ setState((s) => ({ ...s, error: null }));
1346
+ try {
1347
+ if (dispatch) {
1348
+ await safeDispatch(
1349
+ dispatch,
1350
+ patch({
1351
+ dbKey: meta.dbKey,
1352
+ changes: {
1353
+ displayName: trimmedName,
1354
+ updatedAt: nowIso
1355
+ }
1356
+ })
1357
+ );
1358
+ }
1359
+ const nextMeta = {
1360
+ ...meta,
1361
+ displayName: trimmedName,
1362
+ updatedAt: nowIso
1363
+ };
1364
+ setState((s) => {
1365
+ if (!isCurrentTableTarget(s, tenantId, tableId) || !sameTableTarget(s.currentTable, tenantId, tableId)) return s;
1366
+ return {
1367
+ ...s,
1368
+ currentTable: { ...s.currentTable, displayName: trimmedName, updatedAt: nowIso },
1369
+ isInitialized: true
1370
+ };
1371
+ });
1372
+ return nextMeta;
1373
+ } catch (e) {
1374
+ const msg = e?.message || "\u91CD\u547D\u540D\u8868\u5931\u8D25";
1375
+ setState((s) => sameTableTarget(s.expectedTableKey ?? s.currentTable, tenantId, tableId) ? { ...s, error: msg } : s);
1376
+ throw e;
1377
+ }
1378
+ }
1379
+ );
1380
+ var updateTableIcon = createTableCommand(
1381
+ "table/updateTableIcon",
1382
+ async (args, { dispatch } = {}) => {
1383
+ const { tenantId, tableId, icon } = args;
1384
+ const meta = state.currentTable;
1385
+ if (!meta || meta.tenantId !== tenantId || meta.tableId !== tableId) {
1386
+ throw new Error("\u5F53\u524D\u6CA1\u6709\u52A0\u8F7D\u5BF9\u5E94\u7684\u8868\u5B9A\u4E49");
1387
+ }
1388
+ const nowIso = formatISO(/* @__PURE__ */ new Date());
1389
+ setState((s) => ({ ...s, error: null }));
1390
+ try {
1391
+ if (dispatch) {
1392
+ await safeDispatch(
1393
+ dispatch,
1394
+ patch({
1395
+ dbKey: meta.dbKey,
1396
+ changes: {
1397
+ icon: icon ?? null,
1398
+ updatedAt: nowIso
1399
+ }
1400
+ })
1401
+ );
1402
+ }
1403
+ const nextMeta = {
1404
+ ...meta,
1405
+ icon: icon ?? null,
1406
+ updatedAt: nowIso
1407
+ };
1408
+ setState((s) => {
1409
+ if (!isCurrentTableTarget(s, tenantId, tableId) || !sameTableTarget(s.currentTable, tenantId, tableId)) return s;
1410
+ return {
1411
+ ...s,
1412
+ currentTable: { ...s.currentTable, icon: icon ?? null, updatedAt: nowIso }
1413
+ };
1414
+ });
1415
+ return nextMeta;
1416
+ } catch (e) {
1417
+ const msg = e?.message || "\u66F4\u65B0\u8868\u683C\u56FE\u6807\u5931\u8D25";
1418
+ setState((s) => sameTableTarget(s.expectedTableKey ?? s.currentTable, tenantId, tableId) ? { ...s, error: msg } : s);
1419
+ throw e;
1420
+ }
1421
+ }
1422
+ );
1423
+ var updateCell = createTableCommand(
1424
+ "table/updateCell",
1425
+ async (args, { dispatch } = {}) => {
1426
+ const { dbKey, columnName, value } = args;
1427
+ setState((s) => ({ ...s, error: null }));
1428
+ try {
1429
+ const nowIso = formatISO(/* @__PURE__ */ new Date());
1430
+ if (dispatch) {
1431
+ await safeDispatch(
1432
+ dispatch,
1433
+ patch({
1434
+ dbKey,
1435
+ changes: {
1436
+ [columnName]: value,
1437
+ updatedAt: nowIso
1438
+ }
1439
+ })
1440
+ );
1441
+ }
1442
+ setState((s) => ({
1443
+ ...s,
1444
+ rows: s.rows.map((r) => {
1445
+ if (r.dbKey === dbKey) {
1446
+ return {
1447
+ ...r,
1448
+ [columnName]: value,
1449
+ updatedAt: nowIso
1450
+ };
1451
+ }
1452
+ return r;
1453
+ })
1454
+ }));
1455
+ return { dbKey, columnName, value, updatedAt: nowIso };
1456
+ } catch (e) {
1457
+ const msg = e?.message || "\u66F4\u65B0\u5355\u5143\u683C\u5931\u8D25";
1458
+ setState((s) => ({ ...s, error: msg }));
1459
+ throw e;
1460
+ }
1461
+ }
1462
+ );
1463
+
1464
+ // packages/create/space/content/deleteContentFromSpaceAction.ts
1465
+ var nextSpaceUpdatedAt = (value) => {
1466
+ const previousTimestamp = typeof value === "number" ? value : typeof value === "string" ? Date.parse(value) || 0 : 0;
1467
+ const nextTimestamp = Math.max(Date.now(), previousTimestamp + 1);
1468
+ return typeof value === "string" ? new Date(nextTimestamp).toISOString() : nextTimestamp;
1469
+ };
1470
+ var findContentReference = (spaceData, requestedContentKey) => {
1471
+ const contents = spaceData.contents ?? {};
1472
+ const directMatch = contents[requestedContentKey];
1473
+ if (directMatch) {
1474
+ return { entryKey: requestedContentKey, contentInfo: directMatch };
1475
+ }
1476
+ for (const [entryKey, item] of Object.entries(contents)) {
1477
+ if (!item) continue;
1478
+ if (item.contentKey === requestedContentKey) {
1479
+ return { entryKey, contentInfo: item };
1480
+ }
1481
+ }
1482
+ return null;
1483
+ };
1484
+ var ENTITY_DELETE_STRATEGIES = {
1485
+ dialog: async (key, { dispatch }) => {
1486
+ await dispatch(deleteDialog(key)).unwrap();
1487
+ },
1488
+ page: async (key, { dispatch, userId, sourceServerOrigin }) => {
1489
+ const isOwnerByKey = extractUserId(key) === userId;
1490
+ if (isOwnerByKey || isSystemAdmin(userId)) {
1491
+ await dispatch(remove({ dbKey: key, preferredServerOrigin: sourceServerOrigin }));
1492
+ }
1493
+ },
1494
+ table: async (key, { dispatch }) => {
1495
+ await dispatch(deleteTable({ dbKey: key })).unwrap();
1496
+ },
1497
+ file: async (key, { thunkAPI }) => {
1498
+ const { deleteFileAction } = await import("./deleteFile-YM6NDPAR.js");
1499
+ await deleteFileAction(key, thunkAPI);
1500
+ },
1501
+ image: async (key, { thunkAPI }) => {
1502
+ const { deleteFileAction } = await import("./deleteFile-YM6NDPAR.js");
1503
+ await deleteFileAction(key, thunkAPI);
1504
+ },
1505
+ agent: async (key, { dispatch, userId, sourceServerOrigin }) => {
1506
+ const parts = splitKey(key);
1507
+ const isPublic = parts[1] === "pub";
1508
+ const isOwnerByKey = parts[1] === userId;
1509
+ if (!isPublic) {
1510
+ if (isOwnerByKey || isSystemAdmin(userId)) {
1511
+ await dispatch(remove({ dbKey: key, preferredServerOrigin: sourceServerOrigin }));
1512
+ }
1513
+ } else {
1514
+ const agentData = await dispatch(read({
1515
+ dbKey: key,
1516
+ preferredServerOrigin: sourceServerOrigin
1517
+ })).unwrap();
1518
+ if (agentData) {
1519
+ const isCreator = agentData.userId === userId;
1520
+ const isAdmin = isSystemAdmin(userId);
1521
+ if (isCreator || isAdmin) {
1522
+ await dispatch(remove({ dbKey: key, preferredServerOrigin: sourceServerOrigin }));
1523
+ }
1524
+ }
1525
+ }
1526
+ }
1527
+ };
1528
+ var deleteContentFromSpaceAction = async (input, thunkAPI) => {
1529
+ const { contentKey, sourceServerOrigin } = input;
1530
+ const spaceId = normalizeSpaceId(input.spaceId);
1531
+ const { dispatch, getState } = thunkAPI;
1532
+ const accountUserId = selectIdentityUserId(getState());
1533
+ const spaceKey = createSpaceKey.space(spaceId);
1534
+ const spaceData = await dispatch(read({
1535
+ dbKey: spaceKey,
1536
+ preferredServerOrigin: sourceServerOrigin
1537
+ })).unwrap();
1538
+ if (!spaceData) throw new Error("\u7A7A\u95F4\u4E0D\u5B58\u5728");
1539
+ checkSpaceMembership(spaceData, accountUserId);
1540
+ const contentReference = findContentReference(spaceData, contentKey);
1541
+ if (!contentReference) {
1542
+ return { contentKey, spaceId, updatedSpaceData: spaceData };
1543
+ }
1544
+ const { entryKey, contentInfo } = contentReference;
1545
+ const entityKey = String(contentInfo.contentKey || contentKey || entryKey);
1546
+ const contentDeletes = {
1547
+ [entryKey]: null
1548
+ };
1549
+ if (entityKey !== entryKey) {
1550
+ contentDeletes[entityKey] = null;
1551
+ }
1552
+ const updatedSpaceData = await dispatch(
1553
+ patch({
1554
+ dbKey: spaceKey,
1555
+ preferredServerOrigin: sourceServerOrigin,
1556
+ changes: {
1557
+ contents: contentDeletes,
1558
+ updatedAt: nextSpaceUpdatedAt(spaceData.updatedAt),
1559
+ ...localSpaceAuthorityPatchStamp(spaceData)
1560
+ }
1561
+ })
1562
+ ).unwrap();
1563
+ const userId = isDeviceLocalSpaceBody(spaceData) ? DEVICE_LOCAL_OWNER_ID : String(accountUserId ?? "");
1564
+ let entityRemoveError = null;
1565
+ const contentType = String(contentInfo.type || "").toLowerCase();
1566
+ try {
1567
+ const strategy = ENTITY_DELETE_STRATEGIES[contentType];
1568
+ if (strategy) {
1569
+ await strategy(entityKey, { dispatch, userId, thunkAPI, sourceServerOrigin });
1570
+ } else if (isPageKey(entityKey)) {
1571
+ await ENTITY_DELETE_STRATEGIES.page(entityKey, {
1572
+ dispatch,
1573
+ userId,
1574
+ thunkAPI,
1575
+ sourceServerOrigin
1576
+ });
1577
+ } else if (isAgentKey(entityKey)) {
1578
+ await ENTITY_DELETE_STRATEGIES.agent(entityKey, {
1579
+ dispatch,
1580
+ userId,
1581
+ thunkAPI,
1582
+ sourceServerOrigin
1583
+ });
1584
+ }
1585
+ } catch (err2) {
1586
+ console.error(`[deleteContent] Failed to delete entity ${entityKey}:`, err2);
1587
+ entityRemoveError = err2.message || "Unknown error";
1588
+ }
1589
+ return {
1590
+ contentKey,
1591
+ spaceId,
1592
+ updatedSpaceData,
1593
+ entityRemoveError
1594
+ };
1595
+ };
1596
+
1597
+ // packages/create/space/content/moveContentAction.ts
1598
+ var logger2 = createClientLogger("move-content");
1599
+ var moveContentAction = async (input, thunkAPI) => {
1600
+ const {
1601
+ contentKey,
1602
+ sourceSpaceId,
1603
+ targetSpaceId,
1604
+ targetCategoryId: rawTargetCategoryId
1605
+ } = input;
1606
+ const { dispatch, getState } = thunkAPI;
1607
+ const state3 = getState();
1608
+ const userId = selectIdentityUserId(state3);
1609
+ const now = Date.now();
1610
+ logger2.info({ ...input, userId }, "Initiating moveContentAction");
1611
+ if (sourceSpaceId === targetSpaceId) {
1612
+ logger2.error("Source and target space IDs are the same.");
1613
+ throw new Error(
1614
+ "\u6E90\u7A7A\u95F4\u548C\u76EE\u6807\u7A7A\u95F4\u4E0D\u80FD\u76F8\u540C\u3002\u5982\u9700\u4FEE\u6539\u5206\u7C7B\uFF0C\u8BF7\u4F7F\u7528\u66F4\u65B0\u5206\u7C7B\u64CD\u4F5C\u3002"
1615
+ );
1616
+ }
1617
+ if (!contentKey || typeof contentKey !== "string" || contentKey.trim() === "") {
1618
+ logger2.error("Invalid contentKey provided.");
1619
+ throw new Error("\u65E0\u6548\u7684\u5185\u5BB9 Key\u3002");
1620
+ }
1621
+ let sourceSpaceData = null;
1622
+ let targetSpaceData = null;
1623
+ let contentDataFromSource = null;
1624
+ let finalSourceData = null;
1625
+ let finalTargetData = null;
1626
+ let overallError = void 0;
1627
+ try {
1628
+ const sourceSpaceKey = createSpaceKey.space(sourceSpaceId);
1629
+ const targetSpaceKey = createSpaceKey.space(targetSpaceId);
1630
+ logger2.info(
1631
+ { sourceSpaceKey, targetSpaceKey },
1632
+ "Reading source and target space data."
1633
+ );
1634
+ const [sourceResult, targetResult] = await Promise.allSettled([
1635
+ dispatch(read({
1636
+ dbKey: sourceSpaceKey
1637
+ })).unwrap(),
1638
+ dispatch(read({
1639
+ dbKey: targetSpaceKey
1640
+ })).unwrap()
1641
+ ]);
1642
+ if (sourceResult.status === "rejected" || !sourceResult.value) {
1643
+ const reason = sourceResult.status === "rejected" ? sourceResult.reason : "Data is null";
1644
+ throw new Error(
1645
+ `\u65E0\u6CD5\u52A0\u8F7D\u6E90\u7A7A\u95F4 (${sourceSpaceId}): ${reason?.message || reason}`
1646
+ );
1647
+ }
1648
+ sourceSpaceData = sourceResult.value;
1649
+ if (targetResult.status === "rejected" || !targetResult.value) {
1650
+ const reason = targetResult.status === "rejected" ? targetResult.reason : "Data is null";
1651
+ throw new Error(
1652
+ `\u65E0\u6CD5\u52A0\u8F7D\u76EE\u6807\u7A7A\u95F4 (${targetSpaceId}): ${reason?.message || reason}`
1653
+ );
1654
+ }
1655
+ targetSpaceData = targetResult.value;
1656
+ logger2.info("Checking permissions for source and target spaces.");
1657
+ checkSpaceMembership(sourceSpaceData, userId);
1658
+ checkSpaceMembership(targetSpaceData, userId);
1659
+ if (!sourceSpaceData.contents || !sourceSpaceData.contents[contentKey]) {
1660
+ logger2.error(
1661
+ { contentKey, sourceSpaceId },
1662
+ "Content key not found in source space contents."
1663
+ );
1664
+ throw new Error(
1665
+ `\u5185\u5BB9 (${contentKey}) \u4E0D\u5728\u6E90\u7A7A\u95F4 (${sourceSpaceId}) \u4E2D\u3002`
1666
+ );
1667
+ }
1668
+ contentDataFromSource = sourceSpaceData.contents[contentKey];
1669
+ if (targetSpaceData.contents && targetSpaceData.contents[contentKey]) {
1670
+ logger2.warn(
1671
+ { contentKey, targetSpaceId },
1672
+ "Content key already exists in target space. Overwriting."
1673
+ );
1674
+ }
1675
+ let categoryIdForTargetStorage;
1676
+ if (rawTargetCategoryId && rawTargetCategoryId !== "" && rawTargetCategoryId !== UNCATEGORIZED_ID) {
1677
+ if (targetSpaceData.categories?.[rawTargetCategoryId]) {
1678
+ categoryIdForTargetStorage = rawTargetCategoryId;
1679
+ } else {
1680
+ logger2.warn(
1681
+ `Target category ${rawTargetCategoryId} not found in target space ${targetSpaceId}. Content will be uncategorized.`
1682
+ );
1683
+ categoryIdForTargetStorage = void 0;
1684
+ }
1685
+ } else {
1686
+ categoryIdForTargetStorage = void 0;
1687
+ }
1688
+ const contentReferenceForTarget = {
1689
+ ...contentDataFromSource,
1690
+ updatedAt: now
1691
+ };
1692
+ delete contentReferenceForTarget.categoryId;
1693
+ if (categoryIdForTargetStorage !== void 0) {
1694
+ contentReferenceForTarget.categoryId = categoryIdForTargetStorage;
1695
+ }
1696
+ const sourcePatchChanges = {
1697
+ contents: {
1698
+ [contentKey]: null
1699
+ // 从源移除引用 (null value in patch typically means delete key)
1700
+ },
1701
+ updatedAt: now,
1702
+ ...localSpaceAuthorityPatchStamp(sourceSpaceData)
1703
+ };
1704
+ const targetPatchChanges = {
1705
+ contents: {
1706
+ [contentKey]: contentReferenceForTarget
1707
+ // 向目标添加(或覆盖)引用
1708
+ },
1709
+ updatedAt: now,
1710
+ ...localSpaceAuthorityPatchStamp(targetSpaceData)
1711
+ };
1712
+ logger2.info("Patching source and target space data.");
1713
+ await Promise.all([
1714
+ dispatch(
1715
+ patch({ dbKey: sourceSpaceKey, changes: sourcePatchChanges })
1716
+ ).unwrap(),
1717
+ dispatch(
1718
+ patch({ dbKey: targetSpaceKey, changes: targetPatchChanges })
1719
+ ).unwrap()
1720
+ ]);
1721
+ logger2.info("Successfully patched both source and target spaces.");
1722
+ } catch (error) {
1723
+ logger2.error(
1724
+ { error: error.message, stack: error.stack },
1725
+ "Error during move content action execution."
1726
+ );
1727
+ overallError = error.message || "\u79FB\u52A8\u5185\u5BB9\u65F6\u53D1\u751F\u672A\u77E5\u9519\u8BEF";
1728
+ } finally {
1729
+ logger2.info("Attempting to re-read final space data.");
1730
+ const sourceSpaceKey = createSpaceKey.space(sourceSpaceId);
1731
+ const targetSpaceKey = createSpaceKey.space(targetSpaceId);
1732
+ const [finalSourceResult, finalTargetResult] = await Promise.allSettled([
1733
+ dispatch(read({
1734
+ dbKey: sourceSpaceKey
1735
+ })).unwrap(),
1736
+ dispatch(read({
1737
+ dbKey: targetSpaceKey
1738
+ })).unwrap()
1739
+ ]);
1740
+ if (finalSourceResult.status === "fulfilled") {
1741
+ finalSourceData = finalSourceResult.value;
1742
+ } else {
1743
+ logger2.error(
1744
+ { sourceSpaceId, reason: finalSourceResult.reason },
1745
+ "Failed to re-read final source space data."
1746
+ );
1747
+ }
1748
+ if (finalTargetResult.status === "fulfilled") {
1749
+ finalTargetData = finalTargetResult.value;
1750
+ } else {
1751
+ logger2.error(
1752
+ { targetSpaceId, reason: finalTargetResult.reason },
1753
+ "Failed to re-read final target space data."
1754
+ );
1755
+ }
1756
+ logger2.info(
1757
+ {
1758
+ hasError: !!overallError,
1759
+ sourceReadSuccess: !!finalSourceData,
1760
+ targetReadSuccess: !!finalTargetData
1761
+ },
1762
+ "Move content action finished."
1763
+ );
1764
+ const result = {
1765
+ sourceSpaceId,
1766
+ updatedSourceSpaceData: finalSourceData,
1767
+ targetSpaceId,
1768
+ updatedTargetSpaceData: finalTargetData,
1769
+ error: overallError
1770
+ // 如果过程中有错误,则传递错误信息
1771
+ };
1772
+ return result;
1773
+ }
1774
+ };
1775
+
1776
+ // packages/create/space/content/spaceContentPatch.ts
1777
+ var notifyUserDataUpdated = () => {
1778
+ if (typeof window !== "undefined" && typeof window.dispatchEvent === "function" && typeof window.Event === "function") {
1779
+ window.dispatchEvent(new window.Event("nolo-user-data-updated"));
1780
+ }
1781
+ };
1782
+ var loadSpaceContentOrThrow = async (dispatch, spaceId, contentKey, sourceServerOrigin) => {
1783
+ if (!contentKey || typeof contentKey !== "string" || contentKey.trim() === "") {
1784
+ throw new Error("Invalid contentKey provided.");
1785
+ }
1786
+ const spaceKey = createSpaceKey.space(spaceId);
1787
+ let spaceData = null;
1788
+ try {
1789
+ spaceData = await dispatch(
1790
+ read({ dbKey: spaceKey, preferredServerOrigin: sourceServerOrigin })
1791
+ ).unwrap();
1792
+ } catch (readError) {
1793
+ throw new Error(`\u65E0\u6CD5\u52A0\u8F7D\u7A7A\u95F4\u6570\u636E: ${spaceId}`);
1794
+ }
1795
+ if (!spaceData) {
1796
+ throw new Error("Space not found");
1797
+ }
1798
+ const content = spaceData.contents?.[contentKey];
1799
+ if (!content) {
1800
+ throw new Error("Content not found in space");
1801
+ }
1802
+ return { spaceKey, spaceData, content };
1803
+ };
1804
+ var patchIndividualContentRecord = async (dispatch, contentKey, changes, sourceServerOrigin, failMessagePrefix) => {
1805
+ let hasIndividualRecord = false;
1806
+ try {
1807
+ const existing = await dispatch(
1808
+ read({ dbKey: contentKey, preferredServerOrigin: sourceServerOrigin })
1809
+ ).unwrap();
1810
+ hasIndividualRecord = Boolean(existing);
1811
+ } catch {
1812
+ hasIndividualRecord = false;
1813
+ }
1814
+ if (hasIndividualRecord) {
1815
+ try {
1816
+ await dispatch(
1817
+ patch({
1818
+ dbKey: contentKey,
1819
+ changes,
1820
+ preferredServerOrigin: sourceServerOrigin
1821
+ })
1822
+ ).unwrap();
1823
+ notifyUserDataUpdated();
1824
+ } catch (contentPatchError) {
1825
+ throw new Error(
1826
+ `${failMessagePrefix}: ${contentPatchError?.message || "\u672A\u77E5\u9519\u8BEF"}`
1827
+ );
1828
+ }
1829
+ }
1830
+ };
1831
+
1832
+ // packages/create/space/content/updateContentTitleAction.ts
1833
+ var buildContentRecordTitleChanges = (content, title, updatedAt) => {
1834
+ const changes = { title, updatedAt };
1835
+ if (content.type === "app") {
1836
+ changes.name = title;
1837
+ }
1838
+ return changes;
1839
+ };
1840
+ var updateContentTitleAction = async (input, thunkAPI) => {
1841
+ const { spaceId, contentKey, title, skillSummary, sourceServerOrigin } = input;
1842
+ const { dispatch } = thunkAPI;
1843
+ if (title === void 0 || title === null || typeof title !== "string") {
1844
+ throw new Error("Invalid title provided.");
1845
+ }
1846
+ if (title.trim() === "") {
1847
+ throw new Error("Title cannot be empty.");
1848
+ }
1849
+ const { spaceKey, spaceData, content } = await loadSpaceContentOrThrow(
1850
+ dispatch,
1851
+ spaceId,
1852
+ contentKey,
1853
+ sourceServerOrigin
1854
+ );
1855
+ const trimmedTitle = title.trim();
1856
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1857
+ const changes = {
1858
+ contents: {
1859
+ [contentKey]: {
1860
+ ...spaceData.contents[contentKey],
1861
+ title: trimmedTitle,
1862
+ updatedAt: now,
1863
+ ...skillSummary !== void 0 ? { skillSummary } : {}
1864
+ }
1865
+ },
1866
+ updatedAt: now
1867
+ };
1868
+ let updatedSpaceData;
1869
+ try {
1870
+ updatedSpaceData = await dispatch(
1871
+ patch({
1872
+ dbKey: spaceKey,
1873
+ changes,
1874
+ preferredServerOrigin: sourceServerOrigin
1875
+ })
1876
+ ).unwrap();
1877
+ } catch (patchError) {
1878
+ throw new Error(`\u66F4\u65B0\u5185\u5BB9\u6807\u9898\u5931\u8D25: ${patchError.message || "\u672A\u77E5\u9519\u8BEF"}`);
1879
+ }
1880
+ await patchIndividualContentRecord(
1881
+ dispatch,
1882
+ contentKey,
1883
+ buildContentRecordTitleChanges(content, trimmedTitle, now),
1884
+ sourceServerOrigin,
1885
+ "\u6807\u9898\u5DF2\u5199\u5165\u7A7A\u95F4\uFF0C\u4F46\u540C\u6B65\u72EC\u7ACB\u8BB0\u5F55\u5931\u8D25"
1886
+ );
1887
+ if (contentKey.startsWith("meta-")) {
1888
+ const parts = contentKey.split(SEPARATOR);
1889
+ if (parts.length >= 3) {
1890
+ const tableId = parts.slice(2).join(SEPARATOR);
1891
+ const tenantId = parts[1];
1892
+ try {
1893
+ await dispatch(
1894
+ renameTable({
1895
+ tenantId,
1896
+ tableId,
1897
+ newName: trimmedTitle
1898
+ })
1899
+ ).unwrap();
1900
+ } catch (tableError) {
1901
+ console.error("Failed to sync title to TableMeta:", tableError);
1902
+ }
1903
+ }
1904
+ }
1905
+ return { spaceId, updatedSpaceData };
1906
+ };
1907
+
1908
+ // packages/create/space/content/updateContentPinnedAction.ts
1909
+ var updateContentPinnedAction = async (input, thunkAPI) => {
1910
+ const { spaceId, contentKey, pinned, sourceServerOrigin } = input;
1911
+ const { dispatch } = thunkAPI;
1912
+ if (typeof pinned !== "boolean") {
1913
+ throw new Error("Invalid pinned value provided.");
1914
+ }
1915
+ if (!spaceId) {
1916
+ if (!contentKey || typeof contentKey !== "string" || contentKey.trim() === "") {
1917
+ throw new Error("Invalid contentKey provided.");
1918
+ }
1919
+ await patchIndividualContentRecord(
1920
+ dispatch,
1921
+ contentKey,
1922
+ { pinned },
1923
+ sourceServerOrigin,
1924
+ "\u66F4\u65B0\u7F6E\u9876\u72B6\u6001\u5931\u8D25"
1925
+ );
1926
+ return { spaceId: null, updatedSpaceData: null };
1927
+ }
1928
+ const { spaceKey, spaceData } = await loadSpaceContentOrThrow(
1929
+ dispatch,
1930
+ spaceId,
1931
+ contentKey,
1932
+ sourceServerOrigin
1933
+ );
1934
+ const changes = {
1935
+ contents: {
1936
+ [contentKey]: { ...spaceData.contents[contentKey], pinned }
1937
+ },
1938
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1939
+ };
1940
+ let updatedSpaceData;
1941
+ try {
1942
+ updatedSpaceData = await dispatch(
1943
+ patch({ dbKey: spaceKey, changes, preferredServerOrigin: sourceServerOrigin })
1944
+ ).unwrap();
1945
+ } catch (patchError) {
1946
+ throw new Error(`\u66F4\u65B0\u5185\u5BB9\u7F6E\u9876\u72B6\u6001\u5931\u8D25: ${patchError.message || "\u672A\u77E5\u9519\u8BEF"}`);
1947
+ }
1948
+ await patchIndividualContentRecord(
1949
+ dispatch,
1950
+ contentKey,
1951
+ { pinned },
1952
+ sourceServerOrigin,
1953
+ "\u7F6E\u9876\u72B6\u6001\u5DF2\u5199\u5165\u7A7A\u95F4\uFF0C\u4F46\u540C\u6B65\u72EC\u7ACB\u8BB0\u5F55\u5931\u8D25"
1954
+ );
1955
+ return { spaceId, updatedSpaceData };
1956
+ };
1957
+
1958
+ // packages/create/space/content/updateContentCategoryAction.ts
1959
+ var updateContentCategoryAction = async (input, thunkAPI) => {
1960
+ const { spaceId, contentKey, categoryId: targetContainerId } = input;
1961
+ const { dispatch, getState } = thunkAPI;
1962
+ const state3 = getState();
1963
+ const userId = selectIdentityUserId(state3);
1964
+ if (!userId) {
1965
+ throw new Error("User is not logged in.");
1966
+ }
1967
+ if (!contentKey || typeof contentKey !== "string" || contentKey.trim() === "") {
1968
+ throw new Error("Invalid contentKey provided.");
1969
+ }
1970
+ if (typeof targetContainerId !== "string") {
1971
+ throw new Error("Invalid target container ID provided (must be a string).");
1972
+ }
1973
+ const spaceKey = createSpaceKey.space(spaceId);
1974
+ let spaceData = null;
1975
+ try {
1976
+ spaceData = await dispatch(read({
1977
+ dbKey: spaceKey
1978
+ })).unwrap();
1979
+ } catch (readError) {
1980
+ console.error(
1981
+ `[updateContentCategoryAction] Failed to read space data for key ${spaceKey}:`,
1982
+ readError
1983
+ );
1984
+ throw new Error(
1985
+ `\u65E0\u6CD5\u52A0\u8F7D\u7A7A\u95F4\u6570\u636E: ${spaceId}, \u539F\u56E0: ${readError.message || "\u672A\u77E5\u9519\u8BEF"}`
1986
+ );
1987
+ }
1988
+ if (!spaceData) {
1989
+ throw new Error(`\u7A7A\u95F4\u4E0D\u5B58\u5728: ${spaceId}`);
1990
+ }
1991
+ try {
1992
+ checkSpaceMembership(spaceData, userId);
1993
+ } catch (permissionError) {
1994
+ throw new Error(`\u6743\u9650\u4E0D\u8DB3\uFF0C\u65E0\u6CD5\u4FEE\u6539\u5185\u5BB9\u5206\u7C7B: ${permissionError.message}`);
1995
+ }
1996
+ const currentContent = spaceData.contents?.[contentKey];
1997
+ if (!currentContent) {
1998
+ console.warn(
1999
+ `[updateContentCategoryAction] Content ${contentKey} not found in space ${spaceId}.`
2000
+ );
2001
+ throw new Error("Content not found");
2002
+ }
2003
+ if (targetContainerId !== UNCATEGORIZED_ID) {
2004
+ if (!spaceData.categories[targetContainerId]) {
2005
+ console.warn(
2006
+ `[updateContentCategoryAction] Target category ${targetContainerId} not found or invalid in space ${spaceId}. Cannot move content.`
2007
+ );
2008
+ throw new Error("Target category not found or is invalid");
2009
+ }
2010
+ }
2011
+ const now = Date.now();
2012
+ const categoryIdValueForPatch = targetContainerId === UNCATEGORIZED_ID ? null : targetContainerId;
2013
+ const currentCategoryId = currentContent.categoryId;
2014
+ let needsUpdate = true;
2015
+ if (categoryIdValueForPatch === null && currentCategoryId === void 0) {
2016
+ needsUpdate = false;
2017
+ } else if (categoryIdValueForPatch === currentCategoryId) {
2018
+ needsUpdate = false;
2019
+ }
2020
+ let changes = null;
2021
+ if (needsUpdate) {
2022
+ changes = {
2023
+ contents: {
2024
+ // 使用动态键更新指定的 contentKey
2025
+ [contentKey]: {
2026
+ // --- 修改: 使用计算出的 categoryIdValueForPatch ---
2027
+ categoryId: categoryIdValueForPatch,
2028
+ // null 或 目标分类 ID
2029
+ updatedAt: now
2030
+ // 更新内容的 updatedAt
2031
+ }
2032
+ },
2033
+ updatedAt: now
2034
+ // 更新顶层的 updatedAt
2035
+ };
2036
+ } else {
2037
+ console.log(
2038
+ `[updateContentCategoryAction] No category change needed for ${contentKey}. Skipping patch.`
2039
+ );
2040
+ return { spaceId, updatedSpaceData: spaceData };
2041
+ }
2042
+ let updatedSpaceData;
2043
+ try {
2044
+ updatedSpaceData = await dispatch(
2045
+ patch({ dbKey: spaceKey, changes })
2046
+ // 使用非空断言,因为已检查
2047
+ ).unwrap();
2048
+ } catch (patchError) {
2049
+ console.error(
2050
+ `[updateContentCategoryAction] Failed to patch space data for key ${spaceKey}:`,
2051
+ patchError
2052
+ );
2053
+ throw new Error(`\u66F4\u65B0\u5185\u5BB9\u5206\u7C7B\u5931\u8D25: ${patchError.message || "\u672A\u77E5\u9519\u8BEF"}`);
2054
+ }
2055
+ return { spaceId, updatedSpaceData };
2056
+ };
2057
+
2058
+ // packages/create/space/content/deleteMultipleContentAction.ts
2059
+ var logger3 = createClientLogger("delete-multiple-content");
2060
+ var deleteMultipleContentAction = async (input, thunkAPI) => {
2061
+ const { contentKeys, spaceId } = input;
2062
+ if (!contentKeys || contentKeys.length === 0) {
2063
+ logger3.warn("deleteMultipleContentAction called with no contentKeys.");
2064
+ return { spaceId, updatedSpaceData: null };
2065
+ }
2066
+ const { dispatch, getState } = thunkAPI;
2067
+ const state3 = getState();
2068
+ const userId = selectIdentityUserId(state3);
2069
+ logger3.info(
2070
+ { count: contentKeys.length, spaceId, userId },
2071
+ "Initiating deleteMultipleContentAction"
2072
+ );
2073
+ const spaceKey = createSpaceKey.space(spaceId);
2074
+ const spaceData = await dispatch(
2075
+ read({
2076
+ dbKey: spaceKey
2077
+ })
2078
+ ).unwrap();
2079
+ if (!spaceData) {
2080
+ logger3.error({ spaceKey }, "Space data not found for batch delete");
2081
+ throw new Error("\u7A7A\u95F4\u4E0D\u5B58\u5728");
2082
+ }
2083
+ if (!userId || !spaceData.members.includes(userId)) {
2084
+ logger3.warn({ userId, spaceId }, "Unauthorized attempt for batch delete");
2085
+ throw new Error("\u65E0\u6743\u4FEE\u6539\u6B64\u7A7A\u95F4");
2086
+ }
2087
+ const changes = {
2088
+ contents: contentKeys.reduce(
2089
+ (acc, key) => {
2090
+ acc[key] = null;
2091
+ return acc;
2092
+ },
2093
+ {}
2094
+ )
2095
+ };
2096
+ try {
2097
+ await dispatch(patch({ dbKey: spaceKey, changes })).unwrap();
2098
+ logger3.info(
2099
+ { spaceKey, count: contentKeys.length },
2100
+ "Successfully batched patch to remove content references"
2101
+ );
2102
+ } catch (patchError) {
2103
+ logger3.error(
2104
+ { error: patchError, spaceKey },
2105
+ "Failed to batch patch space data. Aborting."
2106
+ );
2107
+ throw new Error(`\u66F4\u65B0\u7A7A\u95F4\u5F15\u7528\u5931\u8D25: ${patchError.message}`);
2108
+ }
2109
+ const removePromises = contentKeys.map(
2110
+ (key) => dispatch(remove(key)).unwrap()
2111
+ );
2112
+ const results = await Promise.allSettled(removePromises);
2113
+ results.forEach((result, index) => {
2114
+ if (result.status === "fulfilled") {
2115
+ logger3.info({ contentKey: contentKeys[index] }, "Entity removed");
2116
+ } else {
2117
+ logger3.error(
2118
+ { contentKey: contentKeys[index], error: result.reason },
2119
+ "Failed to remove an entity"
2120
+ );
2121
+ }
2122
+ });
2123
+ const finalSpaceData = await dispatch(
2124
+ read({
2125
+ dbKey: spaceKey
2126
+ })
2127
+ ).unwrap();
2128
+ logger3.info({ spaceId }, "Finished batch delete and refetched space data.");
2129
+ return {
2130
+ spaceId,
2131
+ updatedSpaceData: finalSpaceData
2132
+ };
2133
+ };
2134
+
2135
+ // packages/create/space/content/spaceFileVersions.ts
2136
+ var normalizeFileName = (name) => typeof name === "string" ? name.trim().normalize("NFC") : "";
2137
+ var versionsOf = (entryKey, entry) => {
2138
+ if (Array.isArray(entry.versions) && entry.versions.length > 0) {
2139
+ return entry.versions.filter((v) => v && typeof v.fileKey === "string");
2140
+ }
2141
+ return [
2142
+ {
2143
+ fileKey: entry.contentKey || entryKey,
2144
+ sha256: entry.sha256 || "",
2145
+ size: typeof entry.fileSize === "number" ? entry.fileSize : 0,
2146
+ uploadedAt: typeof entry.createdAt === "number" ? entry.createdAt : 0
2147
+ }
2148
+ ];
2149
+ };
2150
+ var findSameNameFileEntries = (contents, originalName) => {
2151
+ const target = normalizeFileName(originalName);
2152
+ if (!target || !contents) return [];
2153
+ return Object.entries(contents).filter(([, value]) => Boolean(value)).map(([entryKey, value]) => ({ entryKey, entry: value })).filter(
2154
+ ({ entry }) => entry.type === "file" && normalizeFileName(entry.originalName ?? entry.title) === target
2155
+ );
2156
+ };
2157
+ var sortVersions = (versions) => [...versions].sort(
2158
+ (a, b) => a.uploadedAt - b.uploadedAt || a.fileKey.localeCompare(b.fileKey)
2159
+ );
2160
+ var mergeVersions = (groups) => {
2161
+ const byKey = /* @__PURE__ */ new Map();
2162
+ for (const { entryKey, entry } of groups) {
2163
+ for (const v of versionsOf(entryKey, entry)) {
2164
+ const prev = byKey.get(v.fileKey);
2165
+ if (!prev || !prev.sha256 && v.sha256) byKey.set(v.fileKey, v);
2166
+ }
2167
+ }
2168
+ return sortVersions([...byKey.values()]);
2169
+ };
2170
+ var planSpaceFileUpload = (contents, originalName, sha256) => {
2171
+ const same = findSameNameFileEntries(contents, originalName);
2172
+ if (same.length === 0) return { kind: "new_file" };
2173
+ const primary = pickPrimary(same);
2174
+ const current = primary.entry.contentKey || primary.entryKey;
2175
+ const versions = mergeVersions(same);
2176
+ const currentVersion = versions.find((v) => v.fileKey === current);
2177
+ if (currentVersion?.sha256 && currentVersion.sha256 === sha256) {
2178
+ return { kind: "unchanged", entryKey: primary.entryKey, currentKey: current };
2179
+ }
2180
+ const older = versions.find((v) => v.sha256 && v.sha256 === sha256);
2181
+ if (older) {
2182
+ return { kind: "restore_existing", entryKey: primary.entryKey, versionKey: older.fileKey };
2183
+ }
2184
+ return { kind: "new_version", entryKey: primary.entryKey };
2185
+ };
2186
+ var pickPrimary = (same) => [...same].sort((a, b) => {
2187
+ const at = Math.max(...versionsOf(a.entryKey, a.entry).map((v) => v.uploadedAt));
2188
+ const bt = Math.max(...versionsOf(b.entryKey, b.entry).map((v) => v.uploadedAt));
2189
+ return bt - at || b.entryKey.localeCompare(a.entryKey);
2190
+ })[0];
2191
+ var buildVersionedEntryPatch = (input) => {
2192
+ const { same, extraVersion, now } = input;
2193
+ const versions = mergeVersions(
2194
+ extraVersion ? [...same, { entryKey: extraVersion.fileKey, entry: { versions: [extraVersion] } }] : same
2195
+ );
2196
+ const currentKey = input.currentKey ?? versions[versions.length - 1].fileKey;
2197
+ const current = versions.find((v) => v.fileKey === currentKey);
2198
+ if (!current) throw new Error(`Version ${currentKey} not found for this file.`);
2199
+ const template = same.length > 0 ? pickPrimary(same).entry : {};
2200
+ const patch2 = {};
2201
+ for (const { entryKey } of same) {
2202
+ if (entryKey !== currentKey) patch2[entryKey] = null;
2203
+ }
2204
+ patch2[currentKey] = {
2205
+ ...template,
2206
+ contentKey: currentKey,
2207
+ currentVersionKey: currentKey,
2208
+ fileSize: current.size,
2209
+ versions,
2210
+ updatedAt: now,
2211
+ ...input.restoredFrom ? { restoredFromVersionKey: input.restoredFrom } : {}
2212
+ };
2213
+ return patch2;
2214
+ };
2215
+ var sha256Hex = async (file) => {
2216
+ const digest = await crypto.subtle.digest("SHA-256", await file.arrayBuffer());
2217
+ return Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, "0")).join("");
2218
+ };
2219
+
2220
+ // packages/create/space/content/uploadAndAddFileToSpaceAction.ts
2221
+ var uploadQueues = /* @__PURE__ */ new Map();
2222
+ var serialize = (key, task) => {
2223
+ const prev = uploadQueues.get(key) ?? Promise.resolve();
2224
+ const next = prev.catch(() => void 0).then(task);
2225
+ uploadQueues.set(key, next);
2226
+ void next.finally(() => {
2227
+ if (uploadQueues.get(key) === next) uploadQueues.delete(key);
2228
+ }).catch(() => void 0);
2229
+ return next;
2230
+ };
2231
+ var readSpaceOrNull = async (dispatch, spaceId) => {
2232
+ try {
2233
+ return await dispatch(read({ dbKey: createSpaceKey.space(spaceId) })).unwrap() ?? null;
2234
+ } catch {
2235
+ return null;
2236
+ }
2237
+ };
2238
+ var reconcileSameNameEntries = async (thunkAPI, spaceId, originalName, options = {}) => {
2239
+ let updated = await reconcileOnce(thunkAPI, spaceId, originalName, options);
2240
+ for (let attempt = 0; attempt < 2 && updated; attempt += 1) {
2241
+ const same = findSameNameFileEntries(updated.contents, originalName);
2242
+ const keys = new Set(mergeVersions(same).map((v) => v.fileKey));
2243
+ const missingOwn = options.extraVersion && !keys.has(options.extraVersion.fileKey);
2244
+ if (same.length <= 1 && !missingOwn) break;
2245
+ const fresh = await readSpaceOrNull(thunkAPI.dispatch, spaceId);
2246
+ const freshSame = findSameNameFileEntries(fresh?.contents, originalName);
2247
+ const freshKeys = new Set(mergeVersions(freshSame).map((v) => v.fileKey));
2248
+ const stillMissing = options.extraVersion && !freshKeys.has(options.extraVersion.fileKey);
2249
+ if (freshSame.length <= 1 && !stillMissing) {
2250
+ updated = fresh;
2251
+ break;
2252
+ }
2253
+ updated = await reconcileOnce(thunkAPI, spaceId, originalName, {
2254
+ ...stillMissing ? { extraVersion: options.extraVersion } : {}
2255
+ });
2256
+ }
2257
+ return updated;
2258
+ };
2259
+ var reconcileOnce = async (thunkAPI, spaceId, originalName, options = {}) => {
2260
+ const { dispatch, getState } = thunkAPI;
2261
+ const spaceData = await readSpaceOrNull(dispatch, spaceId);
2262
+ if (!spaceData) return null;
2263
+ checkSpaceMembership(spaceData, selectIdentityUserId(getState()));
2264
+ const same = findSameNameFileEntries(spaceData.contents, originalName);
2265
+ if (same.length === 0 && !options.extraVersion) return spaceData;
2266
+ const contentsPatch = buildVersionedEntryPatch({ same, now: Date.now(), ...options });
2267
+ return await dispatch(
2268
+ patch({
2269
+ dbKey: createSpaceKey.space(spaceId),
2270
+ changes: {
2271
+ contents: contentsPatch,
2272
+ updatedAt: Date.now(),
2273
+ ...localSpaceAuthorityPatchStamp(spaceData)
2274
+ }
2275
+ })
2276
+ ).unwrap();
2277
+ };
2278
+ var uploadAndAddFileToSpaceAction = async (payload, thunkAPI) => {
2279
+ const { spaceId, file } = payload;
2280
+ const userId = selectIdentityUserId(thunkAPI.getState());
2281
+ if (!userId) {
2282
+ throw new Error("Cannot upload a file to a space without an authenticated user.");
2283
+ }
2284
+ return serialize(
2285
+ `${spaceId}\0${file.name}`,
2286
+ () => uploadOnce(payload, thunkAPI, userId)
2287
+ );
2288
+ };
2289
+ var uploadOnce = async (payload, thunkAPI, userId) => {
2290
+ const { spaceId, file, categoryId } = payload;
2291
+ const { dispatch } = thunkAPI;
2292
+ try {
2293
+ const sha256 = await sha256Hex(file);
2294
+ const existingSpace = await readSpaceOrNull(dispatch, spaceId);
2295
+ const plan = existingSpace ? planSpaceFileUpload(existingSpace.contents, file.name, sha256) : { kind: "new_file" };
2296
+ if (plan.kind === "unchanged") {
2297
+ return {
2298
+ spaceId,
2299
+ updatedSpaceData: existingSpace,
2300
+ contentKey: plan.currentKey,
2301
+ fileId: plan.currentKey.split("-").slice(2).join("-"),
2302
+ outcome: "unchanged"
2303
+ };
2304
+ }
2305
+ if (plan.kind === "restore_existing") {
2306
+ const updated = await reconcileSameNameEntries(thunkAPI, spaceId, file.name, {
2307
+ currentKey: plan.versionKey,
2308
+ restoredFrom: plan.entryKey
2309
+ });
2310
+ return {
2311
+ spaceId,
2312
+ updatedSpaceData: updated ?? existingSpace,
2313
+ contentKey: plan.versionKey,
2314
+ fileId: plan.versionKey.split("-").slice(2).join("-"),
2315
+ outcome: "restored_existing"
2316
+ };
2317
+ }
2318
+ const id = ulid();
2319
+ const dbKey = fileKey.single(userId, id);
2320
+ const contentType = "file" /* FILE */;
2321
+ const fileCategory = resolveFileCategory({
2322
+ mimeType: file.type,
2323
+ fileName: file.name
2324
+ });
2325
+ const fileMetadata = await uploadFileAction(
2326
+ { file, customKey: dbKey, userId },
2327
+ thunkAPI
2328
+ );
2329
+ if (!fileMetadata) {
2330
+ throw new Error("Upload failed, no metadata returned");
2331
+ }
2332
+ const contentKey = fileMetadata.dbKey || dbKey;
2333
+ const title = file.name;
2334
+ const fileSize = asOptionalFiniteNumber(file.size);
2335
+ const version3 = {
2336
+ fileKey: contentKey,
2337
+ sha256,
2338
+ size: fileSize ?? 0,
2339
+ uploadedAt: Date.now()
2340
+ };
2341
+ const addAsNewFile = async () => {
2342
+ const result2 = await addContentAction({
2343
+ spaceId,
2344
+ contentKey,
2345
+ title,
2346
+ type: contentType,
2347
+ fileCategory,
2348
+ mimeType: file.type || void 0,
2349
+ fileSize,
2350
+ originalName: file.name,
2351
+ categoryId
2352
+ }, thunkAPI);
2353
+ return result2;
2354
+ };
2355
+ const result = plan.kind === "new_file" ? await addAsNewFile() : { spaceId, updatedSpaceData: existingSpace };
2356
+ await dispatch(
2357
+ patch({
2358
+ dbKey: contentKey,
2359
+ changes: {
2360
+ title,
2361
+ spaceId,
2362
+ fileCategory,
2363
+ mimeType: file.type || void 0,
2364
+ fileSize,
2365
+ originalName: file.name
2366
+ }
2367
+ })
2368
+ ).unwrap();
2369
+ const reconciled = await reconcileSameNameEntries(thunkAPI, spaceId, file.name, {
2370
+ extraVersion: version3,
2371
+ currentKey: contentKey
2372
+ }).catch((error) => {
2373
+ if (plan.kind === "new_version") throw error;
2374
+ console.warn("[uploadAndAddFileToSpace] version reconcile failed", error);
2375
+ return null;
2376
+ });
2377
+ if (typeof window !== "undefined") {
2378
+ window.dispatchEvent(new Event("nolo-user-data-updated"));
2379
+ }
2380
+ return {
2381
+ ...result,
2382
+ ...reconciled ? { updatedSpaceData: reconciled } : {},
2383
+ contentKey,
2384
+ fileId: fileMetadata.id,
2385
+ outcome: plan.kind === "new_file" ? "new_file" : "new_version"
2386
+ };
2387
+ } catch (error) {
2388
+ console.error("Upload and add file error:", error);
2389
+ throw error;
2390
+ }
2391
+ };
2392
+ var restoreSpaceFileVersionAction = async (input, thunkAPI) => {
2393
+ const { spaceId, contentKey, versionKey } = input;
2394
+ const spaceData = await readSpaceOrNull(thunkAPI.dispatch, spaceId);
2395
+ if (!spaceData) throw new Error(`\u65E0\u6CD5\u52A0\u8F7D\u7A7A\u95F4\u6570\u636E: ${spaceId}`);
2396
+ const entry = spaceData.contents?.[contentKey];
2397
+ if (!entry || entry.type !== "file" /* FILE */) throw new Error("File not found in space");
2398
+ const versions = Array.isArray(entry.versions) ? entry.versions : [];
2399
+ if (!versions.some((v) => v.fileKey === versionKey)) {
2400
+ throw new Error("Version not found for this file");
2401
+ }
2402
+ const name = entry.originalName ?? entry.title;
2403
+ const updated = await serialize(
2404
+ `${spaceId}\0${name}`,
2405
+ () => reconcileSameNameEntries(thunkAPI, spaceId, name, {
2406
+ currentKey: versionKey,
2407
+ restoredFrom: contentKey
2408
+ })
2409
+ );
2410
+ return { spaceId, updatedSpaceData: updated ?? spaceData, contentKey: versionKey };
2411
+ };
2412
+
2413
+ // packages/create/space/spaceCollapsedState.ts
2414
+ var SPACE_COLLAPSE_STORAGE_PREFIX = "space-collapsed-categories:";
2415
+ var normalizeCollapsedCategories = (value) => {
2416
+ const entries = Object.entries(asRecordOrEmpty(value)).filter(
2417
+ ([key, collapsed]) => typeof key === "string" && typeof collapsed === "boolean"
2418
+ );
2419
+ return Object.fromEntries(entries);
2420
+ };
2421
+ var storageKeyForSpace = (spaceId) => `${SPACE_COLLAPSE_STORAGE_PREFIX}${spaceId}`;
2422
+ var readStoredCollapsedCategories = (spaceId, storage) => {
2423
+ if (!spaceId || !storage) return {};
2424
+ try {
2425
+ const raw = storage.getItem(storageKeyForSpace(spaceId));
2426
+ if (!raw) return { [UNCATEGORIZED_ID]: false };
2427
+ return normalizeCollapsedCategories(JSON.parse(raw));
2428
+ } catch (error) {
2429
+ console.warn("[Space] \u8BFB\u53D6\u5206\u7C7B\u6298\u53E0\u72B6\u6001\u5931\u8D25:", error);
2430
+ return {};
2431
+ }
2432
+ };
2433
+ var writeStoredCollapsedCategories = (spaceId, collapsedCategories, storage) => {
2434
+ if (!spaceId || !storage) return;
2435
+ try {
2436
+ storage.setItem(
2437
+ storageKeyForSpace(spaceId),
2438
+ JSON.stringify(normalizeCollapsedCategories(collapsedCategories))
2439
+ );
2440
+ } catch (error) {
2441
+ console.warn("[Space] \u4FDD\u5B58\u5206\u7C7B\u6298\u53E0\u72B6\u6001\u5931\u8D25:", error);
2442
+ }
2443
+ };
2444
+
2445
+ // packages/create/space/spaceUiStore.ts
2446
+ var import_react2 = __toESM(require_react(), 1);
2447
+ var DEFAULT_COLLAPSED_CATEGORIES = {
2448
+ [UNCATEGORIZED_ID]: false
2449
+ };
2450
+ var FAVORITES_COLLAPSED_STORAGE_KEY = "nolo-sidebar-favorites-collapsed";
2451
+ var readStoredFavoritesCollapsed = () => {
2452
+ try {
2453
+ if (typeof window === "undefined") return false;
2454
+ return window.localStorage.getItem(FAVORITES_COLLAPSED_STORAGE_KEY) === "1";
2455
+ } catch {
2456
+ return false;
2457
+ }
2458
+ };
2459
+ var createInitialState2 = () => ({
2460
+ favoritesCollapsed: readStoredFavoritesCollapsed(),
2461
+ collapsedCategories: {},
2462
+ collapsedCategoriesSpaceId: null
2463
+ });
2464
+ var state2 = createInitialState2();
2465
+ var listeners2 = /* @__PURE__ */ new Set();
2466
+ var version2 = 0;
2467
+ var notify2 = () => {
2468
+ version2 += 1;
2469
+ for (const listener of listeners2) {
2470
+ try {
2471
+ listener();
2472
+ } catch {
2473
+ }
2474
+ }
2475
+ };
2476
+ function getCollapsedCategories() {
2477
+ return state2.collapsedCategories;
2478
+ }
2479
+ function setCollapsedCategories(categories, spaceId) {
2480
+ state2 = {
2481
+ ...state2,
2482
+ collapsedCategories: categories,
2483
+ collapsedCategoriesSpaceId: spaceId
2484
+ };
2485
+ notify2();
2486
+ }
2487
+ function toggleCategoryCollapse(categoryId) {
2488
+ const current = state2.collapsedCategories[categoryId] ?? (DEFAULT_COLLAPSED_CATEGORIES[categoryId] ?? true);
2489
+ state2 = {
2490
+ ...state2,
2491
+ collapsedCategories: {
2492
+ ...state2.collapsedCategories,
2493
+ [categoryId]: !current
2494
+ }
2495
+ };
2496
+ notify2();
2497
+ }
2498
+ function expandCategoryInCollapsed(categoryId, spaceId) {
2499
+ if (!categoryId || categoryId === UNCATEGORIZED_ID) return;
2500
+ state2 = {
2501
+ ...state2,
2502
+ collapsedCategories: {
2503
+ ...state2.collapsedCategories,
2504
+ [categoryId]: false
2505
+ }
2506
+ };
2507
+ if (typeof window !== "undefined") {
2508
+ writeStoredCollapsedCategories(
2509
+ spaceId,
2510
+ state2.collapsedCategories,
2511
+ window.localStorage
2512
+ );
2513
+ }
2514
+ notify2();
2515
+ }
2516
+
2517
+ // packages/create/space/content/contentThunks.ts
2518
+ var syncCurrentSpaceIfNormalizedMatch = (spaceId, updatedSpaceData) => {
2519
+ const normalizedSpaceId = normalizeSpaceId(spaceId);
2520
+ const rawSpaceId = getCurrentSpaceIdRaw();
2521
+ const normalizedCurrentSpaceId = rawSpaceId ? normalizeSpaceId(rawSpaceId) : null;
2522
+ if (normalizedCurrentSpaceId === normalizedSpaceId && updatedSpaceData) {
2523
+ updateCurrentSpaceIfMatch(spaceId, updatedSpaceData);
2524
+ }
2525
+ };
2526
+ var addContentToSpace = createAsyncThunk(
2527
+ "space/addContentToSpace",
2528
+ async (input, thunkAPI) => {
2529
+ const result = await addContentAction(input, thunkAPI);
2530
+ const rawCategoryId = asTrimmedString(input.categoryId);
2531
+ const expandCategoryId = rawCategoryId && rawCategoryId !== UNCATEGORIZED_ID ? rawCategoryId : null;
2532
+ if (expandCategoryId) {
2533
+ const collapsedCategories = {
2534
+ ...getCollapsedCategories(),
2535
+ [expandCategoryId]: false
2536
+ };
2537
+ if (typeof window !== "undefined") {
2538
+ writeStoredCollapsedCategories(
2539
+ result.spaceId,
2540
+ collapsedCategories,
2541
+ window.localStorage
2542
+ );
2543
+ }
2544
+ expandCategoryInCollapsed(expandCategoryId, result.spaceId);
2545
+ syncCurrentSpaceIfNormalizedMatch(
2546
+ result.spaceId,
2547
+ result.updatedSpaceData
2548
+ );
2549
+ return { ...result, expandCategoryId, collapsedCategories };
2550
+ }
2551
+ syncCurrentSpaceIfNormalizedMatch(result.spaceId, result.updatedSpaceData);
2552
+ return { ...result, expandCategoryId: null };
2553
+ }
2554
+ );
2555
+ var moveContentToSpace = createAsyncThunk(
2556
+ "space/moveContentToSpace",
2557
+ async (arg, thunkAPI) => {
2558
+ const payload = await moveContentAction(arg, thunkAPI);
2559
+ const {
2560
+ sourceSpaceId,
2561
+ updatedSourceSpaceData,
2562
+ targetSpaceId,
2563
+ updatedTargetSpaceData
2564
+ } = payload;
2565
+ if (getCurrentSpaceIdRaw() === sourceSpaceId && updatedSourceSpaceData) {
2566
+ updateCurrentSpaceIfMatch(sourceSpaceId, updatedSourceSpaceData);
2567
+ }
2568
+ if (getCurrentSpaceIdRaw() === targetSpaceId && updatedTargetSpaceData) {
2569
+ updateCurrentSpaceIfMatch(targetSpaceId, updatedTargetSpaceData);
2570
+ }
2571
+ return payload;
2572
+ }
2573
+ );
2574
+ var deleteContentFromSpace = createAsyncThunk(
2575
+ "space/deleteContentFromSpace",
2576
+ async (arg, thunkAPI) => {
2577
+ const payload = await deleteContentFromSpaceAction(arg, thunkAPI);
2578
+ syncCurrentSpaceIfNormalizedMatch(
2579
+ payload.spaceId,
2580
+ payload.updatedSpaceData
2581
+ );
2582
+ return payload;
2583
+ }
2584
+ );
2585
+ var deleteMultipleContent = createAsyncThunk(
2586
+ "space/deleteMultipleContent",
2587
+ async (arg, thunkAPI) => {
2588
+ const payload = await deleteMultipleContentAction(arg, thunkAPI);
2589
+ syncCurrentSpaceIfNormalizedMatch(
2590
+ payload.spaceId,
2591
+ payload.updatedSpaceData
2592
+ );
2593
+ return payload;
2594
+ }
2595
+ );
2596
+ var uploadAndAddFileToSpace = createAsyncThunk(
2597
+ "space/uploadAndAddFileToSpace",
2598
+ async (arg, thunkAPI) => {
2599
+ const payload = await uploadAndAddFileToSpaceAction(arg, thunkAPI);
2600
+ if (getCurrentSpaceIdRaw() === payload.spaceId) {
2601
+ updateCurrentSpaceIfMatch(payload.spaceId, payload.updatedSpaceData);
2602
+ }
2603
+ return payload;
2604
+ }
2605
+ );
2606
+ var restoreSpaceFileVersion = createAsyncThunk(
2607
+ "space/restoreSpaceFileVersion",
2608
+ async (arg, thunkAPI) => {
2609
+ const payload = await restoreSpaceFileVersionAction(arg, thunkAPI);
2610
+ if (getCurrentSpaceIdRaw() === payload.spaceId) {
2611
+ updateCurrentSpaceIfMatch(payload.spaceId, payload.updatedSpaceData);
2612
+ }
2613
+ return payload;
2614
+ }
2615
+ );
2616
+ var updateContentTitle = createAsyncThunk(
2617
+ "space/updateContentTitle",
2618
+ async (arg, thunkAPI) => {
2619
+ try {
2620
+ const payload = await updateContentTitleAction(arg, thunkAPI);
2621
+ if (getCurrentSpaceIdRaw() === payload.spaceId) {
2622
+ updateCurrentSpaceIfMatch(payload.spaceId, payload.updatedSpaceData);
2623
+ }
2624
+ return payload;
2625
+ } catch (error) {
2626
+ const message = error?.message || "\u6807\u9898\u4FDD\u5B58\u5931\u8D25";
2627
+ if (!message.includes("\u65E0\u6CD5\u52A0\u8F7D\u7A7A\u95F4\u6570\u636E")) {
2628
+ toast.error(message);
2629
+ }
2630
+ throw error;
2631
+ }
2632
+ }
2633
+ );
2634
+ var updateContentPinned = createAsyncThunk(
2635
+ "space/updateContentPinned",
2636
+ async (arg, thunkAPI) => {
2637
+ try {
2638
+ const payload = await updateContentPinnedAction(arg, thunkAPI);
2639
+ if (payload.updatedSpaceData && payload.spaceId && getCurrentSpaceIdRaw() === payload.spaceId) {
2640
+ updateCurrentSpaceIfMatch(payload.spaceId, payload.updatedSpaceData);
2641
+ }
2642
+ return payload;
2643
+ } catch (error) {
2644
+ toast.error(
2645
+ error?.message || "\u7F6E\u9876\u72B6\u6001\u66F4\u65B0\u5931\u8D25"
2646
+ );
2647
+ throw error;
2648
+ }
2649
+ }
2650
+ );
2651
+ var updateContentCategory = createAsyncThunk(
2652
+ "space/updateContentCategory",
2653
+ async (arg, thunkAPI) => {
2654
+ const payload = await updateContentCategoryAction(arg, thunkAPI);
2655
+ if (getCurrentSpaceIdRaw() === payload.spaceId) {
2656
+ updateCurrentSpaceIfMatch(payload.spaceId, payload.updatedSpaceData);
2657
+ }
2658
+ return payload;
2659
+ }
2660
+ );
2661
+
2662
+ export {
2663
+ fetchAndCacheTableRows,
2664
+ getTableState,
2665
+ loadTableRows,
2666
+ addRow,
2667
+ createTable,
2668
+ deleteTable,
2669
+ readStoredCollapsedCategories,
2670
+ writeStoredCollapsedCategories,
2671
+ DEFAULT_COLLAPSED_CATEGORIES,
2672
+ getCollapsedCategories,
2673
+ setCollapsedCategories,
2674
+ toggleCategoryCollapse,
2675
+ expandCategoryInCollapsed,
2676
+ addContentToSpace,
2677
+ moveContentToSpace,
2678
+ deleteContentFromSpace,
2679
+ deleteMultipleContent,
2680
+ uploadAndAddFileToSpace,
2681
+ restoreSpaceFileVersion,
2682
+ updateContentTitle,
2683
+ updateContentPinned,
2684
+ updateContentCategory
2685
+ };