@kyro-cms/core 0.12.71 → 0.13.1

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 (252) hide show
  1. package/README.md +150 -76
  2. package/dist/{WebhookService-DQyM9fVo.d.ts → WebhookService-BLi5Rz2m.d.ts} +1 -1
  3. package/dist/{WebhookService-bo1NrgBW.d.cts → WebhookService-BOJMgjBm.d.cts} +1 -1
  4. package/dist/WebhookService-BcuD8tnn.d.cts +143 -0
  5. package/dist/WebhookService-CFe6Zd0_.d.cts +143 -0
  6. package/dist/WebhookService-CGxHtw7E.d.cts +143 -0
  7. package/dist/WebhookService-CNC1lYz7.d.ts +143 -0
  8. package/dist/WebhookService-CVXmjbtQ.d.cts +143 -0
  9. package/dist/WebhookService-D5PSI5t6.d.cts +143 -0
  10. package/dist/WebhookService-DPCCn_12.d.ts +143 -0
  11. package/dist/WebhookService-Dk1lzSrG.d.cts +143 -0
  12. package/dist/WebhookService-Dncnbgm9.d.cts +143 -0
  13. package/dist/WebhookService-I6hdue2Y.d.ts +143 -0
  14. package/dist/WebhookService-KnQ2UDlW.d.ts +143 -0
  15. package/dist/WebhookService-UY5p89Bj.d.ts +143 -0
  16. package/dist/WebhookService-YZXBCRXA.d.ts +143 -0
  17. package/dist/WebhookService-fk0FGRlk.d.ts +143 -0
  18. package/dist/WebhookService-vsFnWrOh.d.ts +143 -0
  19. package/dist/WebhookService-zrDmAx7L.d.cts +143 -0
  20. package/dist/api-handler-graphql.cjs +1 -1
  21. package/dist/api-handler-graphql.js +1 -1
  22. package/dist/api-handler-trpc.cjs +1 -1
  23. package/dist/api-handler-trpc.js +1 -1
  24. package/dist/api-handler.cjs +1 -1
  25. package/dist/api-handler.js +1 -1
  26. package/dist/{base-urWvrsX8.d.cts → base-B--L0lCn.d.cts} +1 -1
  27. package/dist/base-B-i-tjm1.d.ts +218 -0
  28. package/dist/base-B-siit_y.d.cts +218 -0
  29. package/dist/base-B8SyZI4D.d.ts +218 -0
  30. package/dist/base-BCgFt3Yx.d.ts +218 -0
  31. package/dist/base-BHRGJ40F.d.cts +218 -0
  32. package/dist/base-BVoDPNjJ.d.cts +218 -0
  33. package/dist/base-BaOJ5uWd.d.cts +218 -0
  34. package/dist/base-BfPaVEAE.d.cts +218 -0
  35. package/dist/base-BxrX5EPU.d.cts +218 -0
  36. package/dist/base-CAb9EYQs.d.ts +218 -0
  37. package/dist/base-CcZIEll-.d.ts +218 -0
  38. package/dist/base-CyG7aF1e.d.cts +218 -0
  39. package/dist/{base-BcfNgOqZ.d.ts → base-DOImeJ-F.d.ts} +1 -1
  40. package/dist/base-DbnwE42-.d.cts +218 -0
  41. package/dist/base-NyiSsD-n.d.ts +218 -0
  42. package/dist/base-OYfoYPYP.d.ts +218 -0
  43. package/dist/base-xflndGDO.d.ts +218 -0
  44. package/dist/bootstrap-QQ6D3OYG.js +1 -0
  45. package/dist/bootstrap-QVKSKXJF.cjs +1 -0
  46. package/dist/bootstrap-RILR44UM.cjs +1 -0
  47. package/dist/bootstrap-ZRRUPRUR.js +1 -0
  48. package/dist/chunk-262YP5XA.cjs +1 -0
  49. package/dist/chunk-2FSOHXOU.cjs +56 -0
  50. package/dist/chunk-2OS5Y4LE.cjs +1 -0
  51. package/dist/chunk-2PXXQKN3.cjs +3 -0
  52. package/dist/{chunk-K6ZW5M6S.cjs → chunk-355R4LS5.cjs} +3 -3
  53. package/dist/chunk-35IVNLMA.js +122 -0
  54. package/dist/{chunk-FSWDDVLA.js → chunk-3GXLOYM3.js} +1 -1
  55. package/dist/chunk-3KZXF4US.js +2 -0
  56. package/dist/{chunk-H7PC2ENZ.cjs → chunk-3LAWUINR.cjs} +1 -1
  57. package/dist/chunk-3O3AVMWM.cjs +1 -0
  58. package/dist/chunk-3U6MKWET.cjs +120 -0
  59. package/dist/chunk-4BMWWGJN.js +384 -0
  60. package/dist/chunk-5A7E7N4B.cjs +431 -0
  61. package/dist/chunk-6DD4J7LI.js +2 -0
  62. package/dist/chunk-6GGPY7U2.js +4 -0
  63. package/dist/chunk-6MNLRAKM.cjs +121 -0
  64. package/dist/chunk-6NBZDW53.js +133 -0
  65. package/dist/{chunk-2HATK4C5.js → chunk-73Y63IPP.js} +4 -4
  66. package/dist/chunk-7K6ZUNJM.js +4 -0
  67. package/dist/chunk-7NKNSRCB.cjs +448 -0
  68. package/dist/chunk-A3IOQOV6.js +2 -0
  69. package/dist/chunk-A3XVL6ED.cjs +3 -0
  70. package/dist/{chunk-LKQHIOPW.cjs → chunk-APDQ6ZTG.cjs} +1 -1
  71. package/dist/chunk-ATI2UZ7U.js +2 -0
  72. package/dist/chunk-B4AC23SG.js +122 -0
  73. package/dist/chunk-BD6XHMMM.cjs +2 -0
  74. package/dist/chunk-CH4TZZI5.js +449 -0
  75. package/dist/{chunk-26KFM3P6.js → chunk-CNHUCCQJ.js} +1 -1
  76. package/dist/chunk-CRP6PSCE.js +2 -0
  77. package/dist/chunk-DI6TCZSE.js +122 -0
  78. package/dist/chunk-DORUYZQV.cjs +1 -0
  79. package/dist/chunk-E4H3ZZ7U.js +4 -0
  80. package/dist/chunk-EFKEVWAD.js +4 -0
  81. package/dist/chunk-EI7FRSNY.js +57 -0
  82. package/dist/chunk-EON4XLKQ.cjs +1 -0
  83. package/dist/chunk-EUQAOYEO.cjs +121 -0
  84. package/dist/chunk-EVAUBT7H.js +57 -0
  85. package/dist/chunk-EYHD7HZE.cjs +1 -0
  86. package/dist/chunk-EYYIPA5N.js +432 -0
  87. package/dist/chunk-F2O4QO5N.cjs +383 -0
  88. package/dist/chunk-FBWLSWZ4.js +122 -0
  89. package/dist/chunk-FDKU7HJX.js +2 -0
  90. package/dist/chunk-FGN6IMPY.cjs +3 -0
  91. package/dist/chunk-FK2BG4HU.js +3 -0
  92. package/dist/chunk-GV2IB4WQ.cjs +56 -0
  93. package/dist/chunk-GWIZT2P5.js +57 -0
  94. package/dist/chunk-H3FJ54KB.cjs +121 -0
  95. package/dist/chunk-HY3EAWB2.js +4 -0
  96. package/dist/chunk-I6UJVO2P.js +57 -0
  97. package/dist/chunk-IQSF6XRV.js +57 -0
  98. package/dist/chunk-IXGDTAES.js +4 -0
  99. package/dist/chunk-JA44K75G.js +2 -0
  100. package/dist/chunk-JZ7Z6WC2.cjs +3 -0
  101. package/dist/chunk-K5XGP57D.cjs +19 -0
  102. package/dist/chunk-KEITOXIP.js +2 -0
  103. package/dist/chunk-LPFRMQFQ.js +121 -0
  104. package/dist/chunk-LYU44UNN.cjs +56 -0
  105. package/dist/chunk-MDLJTZLV.cjs +1 -0
  106. package/dist/chunk-MFNN5DYG.cjs +1 -0
  107. package/dist/chunk-MJAODEFC.cjs +121 -0
  108. package/dist/chunk-MYHNTJLR.cjs +56 -0
  109. package/dist/chunk-N2YHO2WI.cjs +3 -0
  110. package/dist/chunk-N4FXLQE3.cjs +132 -0
  111. package/dist/chunk-NPBXLPOP.js +3 -0
  112. package/dist/chunk-ON5XJEPO.cjs +3 -0
  113. package/dist/chunk-OT2Z4XBD.cjs +1 -0
  114. package/dist/chunk-PFTBTWSC.cjs +1 -0
  115. package/dist/chunk-PTPVFLET.js +20 -0
  116. package/dist/chunk-PZDLPRJF.js +4 -0
  117. package/dist/chunk-Q5TFO66G.cjs +1 -0
  118. package/dist/chunk-QUTYCUST.js +4 -0
  119. package/dist/chunk-REKKBAQX.cjs +56 -0
  120. package/dist/chunk-REQ622YC.js +3 -0
  121. package/dist/chunk-RTNQP6BV.js +2 -0
  122. package/dist/chunk-RUJW47ZJ.js +2 -0
  123. package/dist/chunk-RXYCFZJC.cjs +121 -0
  124. package/dist/chunk-RYHOWZLK.js +2 -0
  125. package/dist/chunk-S2MZNEBQ.cjs +1 -0
  126. package/dist/chunk-S73YERS2.js +57 -0
  127. package/dist/chunk-SBNMXQNO.cjs +2 -0
  128. package/dist/chunk-SMQ6736Y.js +57 -0
  129. package/dist/chunk-T3DJ3UTP.cjs +121 -0
  130. package/dist/chunk-TJZO7ZSX.cjs +3 -0
  131. package/dist/chunk-TKUNRCRH.js +4 -0
  132. package/dist/chunk-TQLCOMKC.js +4 -0
  133. package/dist/chunk-TRXYDWGE.cjs +1 -0
  134. package/dist/chunk-TS55CUNJ.js +57 -0
  135. package/dist/chunk-UFBJ3WOZ.js +2 -0
  136. package/dist/chunk-UQRVQUVR.js +2 -0
  137. package/dist/chunk-UW5W35NP.js +122 -0
  138. package/dist/chunk-VI7WCO2J.cjs +3 -0
  139. package/dist/chunk-W2GPP6RB.js +122 -0
  140. package/dist/chunk-WHOA7YJU.cjs +1 -0
  141. package/dist/chunk-WNRUPL26.js +2 -0
  142. package/dist/chunk-WXT2XW7T.js +13 -0
  143. package/dist/chunk-XFYSADHV.cjs +2 -0
  144. package/dist/chunk-XIAJQLGS.js +2 -0
  145. package/dist/chunk-XK6UB77Q.js +4 -0
  146. package/dist/chunk-Y2VHO66Q.cjs +3 -0
  147. package/dist/chunk-Y5O2OD7J.cjs +3 -0
  148. package/dist/chunk-YARB43JG.cjs +56 -0
  149. package/dist/chunk-YLCEMVYY.cjs +56 -0
  150. package/dist/chunk-YSOM57GK.cjs +3 -0
  151. package/dist/chunk-Z3UVDGYS.cjs +56 -0
  152. package/dist/chunk-ZTLGK6R4.cjs +12 -0
  153. package/dist/chunk-ZUBJ6RLQ.cjs +1 -0
  154. package/dist/cli/index.cjs +1 -1
  155. package/dist/cli/index.js +1 -1
  156. package/dist/client.cjs +10 -10
  157. package/dist/client.d.cts +1265 -0
  158. package/dist/client.d.ts +1265 -0
  159. package/dist/client.js +10 -10
  160. package/dist/drizzle/index.cjs +1 -1
  161. package/dist/drizzle/index.d.cts +3 -3
  162. package/dist/drizzle/index.d.ts +3 -3
  163. package/dist/drizzle/index.js +1 -1
  164. package/dist/fields/index.cjs +1 -1
  165. package/dist/fields/index.d.cts +2 -2
  166. package/dist/fields/index.d.ts +2 -2
  167. package/dist/fields/index.js +1 -1
  168. package/dist/graphql/index.d.cts +3 -3
  169. package/dist/graphql/index.d.ts +3 -3
  170. package/dist/index-8Ino7vKq.d.ts +105 -0
  171. package/dist/{index-d1m_oup7.d.cts → index-B9BFNOHd.d.cts} +1 -1
  172. package/dist/index-BMcYFpTv.d.cts +105 -0
  173. package/dist/index-BttsFZDa.d.ts +105 -0
  174. package/dist/index-ByOM1Y5x.d.ts +105 -0
  175. package/dist/index-C6xmtRio.d.cts +105 -0
  176. package/dist/index-CTI3K_uq.d.cts +105 -0
  177. package/dist/index-CTL4zv_u.d.ts +105 -0
  178. package/dist/index-CaDbioSg.d.ts +105 -0
  179. package/dist/index-CxA9uOv0.d.ts +105 -0
  180. package/dist/{index-4cH-BjtP.d.ts → index-D6AXbuPI.d.ts} +1 -1
  181. package/dist/index-DF0KDBaM.d.cts +105 -0
  182. package/dist/index-DG4Xu7gA.d.cts +105 -0
  183. package/dist/index-DS3DpJli.d.cts +105 -0
  184. package/dist/index-NGnJpSgf.d.ts +105 -0
  185. package/dist/index-Zrg3sZ6R.d.cts +105 -0
  186. package/dist/index-eHex8Iwj.d.ts +105 -0
  187. package/dist/index-rm7uyOK1.d.cts +105 -0
  188. package/dist/index.cjs +32 -32
  189. package/dist/index.d.cts +73 -11
  190. package/dist/index.d.ts +73 -11
  191. package/dist/index.js +32 -32
  192. package/dist/lib-A2D63VXD.cjs +1 -0
  193. package/dist/lib-JQD2JAOO.js +2 -0
  194. package/dist/local-KR3AIGVA.cjs +1 -0
  195. package/dist/local-T7GISZBL.js +1 -0
  196. package/dist/mongo-auth-adapter-GR2CFFEA.js +1 -0
  197. package/dist/mongo-auth-adapter-UOO2LZUJ.cjs +1 -0
  198. package/dist/mongodb/index.cjs +1 -1
  199. package/dist/mongodb/index.d.cts +4 -3
  200. package/dist/mongodb/index.d.ts +4 -3
  201. package/dist/mongodb/index.js +1 -1
  202. package/dist/nodemailer-transport-3VWVUBM5.cjs +1 -0
  203. package/dist/nodemailer-transport-7RHATUKL.js +1 -0
  204. package/dist/nodemailer-transport-CHO2WKIY.js +1 -0
  205. package/dist/nodemailer-transport-ED2IXNGW.cjs +1 -0
  206. package/dist/rest/index.cjs +1 -1
  207. package/dist/rest/index.d.cts +4 -4
  208. package/dist/rest/index.d.ts +4 -4
  209. package/dist/rest/index.js +1 -1
  210. package/dist/templates/index.cjs +1 -1
  211. package/dist/templates/index.d.cts +2 -2
  212. package/dist/templates/index.d.ts +2 -2
  213. package/dist/templates/index.js +1 -1
  214. package/dist/trpc/index.cjs +1 -1
  215. package/dist/trpc/index.d.cts +3 -3
  216. package/dist/trpc/index.d.ts +3 -3
  217. package/dist/trpc/index.js +1 -1
  218. package/dist/types-6ShQp2EM.d.cts +839 -0
  219. package/dist/types-B5Qz1svz.d.cts +822 -0
  220. package/dist/types-B9oXBEKI.d.cts +330 -0
  221. package/dist/types-B9oXBEKI.d.ts +330 -0
  222. package/dist/types-BCOhfwHC.d.ts +839 -0
  223. package/dist/types-BRDBNacn.d.ts +839 -0
  224. package/dist/types-Bii0bhUV.d.cts +329 -0
  225. package/dist/types-Bii0bhUV.d.ts +329 -0
  226. package/dist/{types-BADIMVGF.d.ts → types-Bt2_ycUO.d.ts} +36 -1
  227. package/dist/types-C4wXHImf.d.ts +822 -0
  228. package/dist/types-C8yIAV6K.d.cts +839 -0
  229. package/dist/types-CORUQhY-.d.ts +839 -0
  230. package/dist/types-Cdssrcbz.d.cts +839 -0
  231. package/dist/types-CjGqxBd3.d.cts +330 -0
  232. package/dist/types-CjGqxBd3.d.ts +330 -0
  233. package/dist/types-DBGR-eQl.d.cts +839 -0
  234. package/dist/types-DCWgPFmi.d.cts +822 -0
  235. package/dist/types-DROqAsr0.d.cts +330 -0
  236. package/dist/types-DROqAsr0.d.ts +330 -0
  237. package/dist/{types-YAVR0H9Z.d.cts → types-DsF64Wrc.d.cts} +36 -1
  238. package/dist/types-DxaK39ix.d.cts +330 -0
  239. package/dist/types-DxaK39ix.d.ts +330 -0
  240. package/dist/types-IeKFn7Ky.d.ts +839 -0
  241. package/dist/types-QglJ7PwT.d.cts +839 -0
  242. package/dist/types-ZrjEVWfi.d.ts +811 -0
  243. package/dist/types-dEy5JxvN.d.ts +822 -0
  244. package/dist/types-tVJc9YbX.d.cts +811 -0
  245. package/dist/types-zt5qIvje.d.ts +839 -0
  246. package/dist/ws/index.cjs +1 -1
  247. package/dist/ws/index.d.cts +121 -1
  248. package/dist/ws/index.d.ts +121 -1
  249. package/dist/ws/index.js +1 -1
  250. package/package.json +2 -2
  251. package/dist/chunk-5M3FKE2V.js +0 -2
  252. package/dist/chunk-WCFHS7EZ.cjs +0 -1
package/dist/ws/index.cjs CHANGED
@@ -1 +1 @@
1
- 'use strict';var chunkWCFHS7EZ_cjs=require('../chunk-WCFHS7EZ.cjs');require('../chunk-73D2PNHD.cjs'),require('../chunk-BUNLC3II.cjs');Object.defineProperty(exports,"KyroPubSub",{enumerable:true,get:function(){return chunkWCFHS7EZ_cjs.b}});Object.defineProperty(exports,"KyroWSServer",{enumerable:true,get:function(){return chunkWCFHS7EZ_cjs.c}});Object.defineProperty(exports,"PubSub",{enumerable:true,get:function(){return chunkWCFHS7EZ_cjs.a}});Object.defineProperty(exports,"createWSServer",{enumerable:true,get:function(){return chunkWCFHS7EZ_cjs.d}});
1
+ 'use strict';var chunkMDLJTZLV_cjs=require('../chunk-MDLJTZLV.cjs');require('../chunk-73D2PNHD.cjs'),require('../chunk-BUNLC3II.cjs');Object.defineProperty(exports,"KyroPubSub",{enumerable:true,get:function(){return chunkMDLJTZLV_cjs.b}});Object.defineProperty(exports,"KyroWSServer",{enumerable:true,get:function(){return chunkMDLJTZLV_cjs.d}});Object.defineProperty(exports,"PresenceManager",{enumerable:true,get:function(){return chunkMDLJTZLV_cjs.c}});Object.defineProperty(exports,"PubSub",{enumerable:true,get:function(){return chunkMDLJTZLV_cjs.a}});Object.defineProperty(exports,"createWSServer",{enumerable:true,get:function(){return chunkMDLJTZLV_cjs.e}});
@@ -36,6 +36,117 @@ declare class KyroPubSub extends PubSub {
36
36
  autoRegisterHooks(): void;
37
37
  }
38
38
 
39
+ interface PresenceUser {
40
+ id: string;
41
+ name: string;
42
+ email?: string;
43
+ avatar?: string;
44
+ color?: string;
45
+ lastSeen: number;
46
+ }
47
+ interface CursorState {
48
+ userId: string;
49
+ field?: string;
50
+ position?: number;
51
+ selection?: {
52
+ start: number;
53
+ end: number;
54
+ };
55
+ updatedAt: number;
56
+ }
57
+ interface FieldLock {
58
+ fieldName: string;
59
+ userId: string;
60
+ userName: string;
61
+ lockedAt: number;
62
+ expiresAt: number;
63
+ }
64
+ interface DocComment {
65
+ id: string;
66
+ authorId: string;
67
+ authorName: string;
68
+ field?: string;
69
+ text: string;
70
+ createdAt: string;
71
+ resolved?: boolean;
72
+ }
73
+ interface DocPresenceState {
74
+ docKey: string;
75
+ users: Map<string, PresenceUser>;
76
+ cursors: Map<string, CursorState>;
77
+ locks: Map<string, FieldLock>;
78
+ comments: DocComment[];
79
+ }
80
+ declare class PresenceManager {
81
+ private documents;
82
+ private defaultLockTtlMs;
83
+ private getOrCreateDoc;
84
+ /**
85
+ * User joins a document room
86
+ */
87
+ join(docKey: string, user: Omit<PresenceUser, 'lastSeen'>): PresenceUser[];
88
+ /**
89
+ * User leaves a document room
90
+ */
91
+ leave(docKey: string, userId: string): {
92
+ remainingUsers: PresenceUser[];
93
+ releasedLocks: string[];
94
+ };
95
+ /**
96
+ * Updates user cursor / focused field in real time
97
+ */
98
+ updateCursor(docKey: string, userId: string, cursor: {
99
+ field?: string;
100
+ position?: number;
101
+ selection?: {
102
+ start: number;
103
+ end: number;
104
+ };
105
+ }): CursorState;
106
+ /**
107
+ * Attempts to acquire an exclusive lock on a field
108
+ */
109
+ acquireLock(docKey: string, fieldName: string, user: {
110
+ id: string;
111
+ name: string;
112
+ }, ttlMs?: number): {
113
+ success: boolean;
114
+ lock?: FieldLock;
115
+ currentLock?: FieldLock;
116
+ };
117
+ /**
118
+ * Releases an exclusive lock on a field
119
+ */
120
+ releaseLock(docKey: string, fieldName: string, userId: string): boolean;
121
+ /**
122
+ * Adds an editorial review comment
123
+ */
124
+ addComment(docKey: string, comment: {
125
+ id: string;
126
+ authorId: string;
127
+ authorName: string;
128
+ field?: string;
129
+ text: string;
130
+ }): DocComment;
131
+ /**
132
+ * Resolves an editorial comment
133
+ */
134
+ resolveComment(docKey: string, commentId: string): boolean;
135
+ /**
136
+ * Returns snapshot of entire presence state for a document
137
+ */
138
+ getSnapshot(docKey: string): {
139
+ users: PresenceUser[];
140
+ cursors: CursorState[];
141
+ locks: FieldLock[];
142
+ comments: DocComment[];
143
+ };
144
+ /**
145
+ * Deterministic avatar color generator for users
146
+ */
147
+ private generateUserColor;
148
+ }
149
+
39
150
  interface WSServerOptions {
40
151
  port?: number;
41
152
  pubsub: KyroPubSub;
@@ -57,6 +168,7 @@ interface WSClient {
57
168
  tenantId?: string;
58
169
  connectedAt: Date;
59
170
  lastActivity: Date;
171
+ activeDocKey?: string;
60
172
  }
61
173
  declare class KyroWSServer {
62
174
  private wss;
@@ -64,6 +176,7 @@ declare class KyroWSServer {
64
176
  private pubsub;
65
177
  private options;
66
178
  private pingTimer?;
179
+ readonly presence: PresenceManager;
67
180
  constructor(options: WSServerOptions);
68
181
  private setupServer;
69
182
  private handleMessage;
@@ -72,6 +185,13 @@ declare class KyroWSServer {
72
185
  private handleUnsubscribe;
73
186
  private handleUnsubscribeAll;
74
187
  private handleList;
188
+ private handlePresenceJoin;
189
+ private handlePresenceLeave;
190
+ private handlePresenceCursor;
191
+ private handlePresenceLock;
192
+ private handlePresenceUnlock;
193
+ private handlePresenceComment;
194
+ private handlePresenceSnapshot;
75
195
  private handleDisconnect;
76
196
  private sendToClient;
77
197
  private generateClientId;
@@ -85,4 +205,4 @@ declare class KyroWSServer {
85
205
  }
86
206
  declare function createWSServer(options: WSServerOptions): KyroWSServer;
87
207
 
88
- export { type EventHandler, type KyroEvent, KyroPubSub, KyroWSServer, PubSub, type WSClient, type WSServerOptions, createWSServer };
208
+ export { type CursorState, type DocComment, type DocPresenceState, type EventHandler, type FieldLock, type KyroEvent, KyroPubSub, KyroWSServer, PresenceManager, type PresenceUser, PubSub, type WSClient, type WSServerOptions, createWSServer };
@@ -36,6 +36,117 @@ declare class KyroPubSub extends PubSub {
36
36
  autoRegisterHooks(): void;
37
37
  }
38
38
 
39
+ interface PresenceUser {
40
+ id: string;
41
+ name: string;
42
+ email?: string;
43
+ avatar?: string;
44
+ color?: string;
45
+ lastSeen: number;
46
+ }
47
+ interface CursorState {
48
+ userId: string;
49
+ field?: string;
50
+ position?: number;
51
+ selection?: {
52
+ start: number;
53
+ end: number;
54
+ };
55
+ updatedAt: number;
56
+ }
57
+ interface FieldLock {
58
+ fieldName: string;
59
+ userId: string;
60
+ userName: string;
61
+ lockedAt: number;
62
+ expiresAt: number;
63
+ }
64
+ interface DocComment {
65
+ id: string;
66
+ authorId: string;
67
+ authorName: string;
68
+ field?: string;
69
+ text: string;
70
+ createdAt: string;
71
+ resolved?: boolean;
72
+ }
73
+ interface DocPresenceState {
74
+ docKey: string;
75
+ users: Map<string, PresenceUser>;
76
+ cursors: Map<string, CursorState>;
77
+ locks: Map<string, FieldLock>;
78
+ comments: DocComment[];
79
+ }
80
+ declare class PresenceManager {
81
+ private documents;
82
+ private defaultLockTtlMs;
83
+ private getOrCreateDoc;
84
+ /**
85
+ * User joins a document room
86
+ */
87
+ join(docKey: string, user: Omit<PresenceUser, 'lastSeen'>): PresenceUser[];
88
+ /**
89
+ * User leaves a document room
90
+ */
91
+ leave(docKey: string, userId: string): {
92
+ remainingUsers: PresenceUser[];
93
+ releasedLocks: string[];
94
+ };
95
+ /**
96
+ * Updates user cursor / focused field in real time
97
+ */
98
+ updateCursor(docKey: string, userId: string, cursor: {
99
+ field?: string;
100
+ position?: number;
101
+ selection?: {
102
+ start: number;
103
+ end: number;
104
+ };
105
+ }): CursorState;
106
+ /**
107
+ * Attempts to acquire an exclusive lock on a field
108
+ */
109
+ acquireLock(docKey: string, fieldName: string, user: {
110
+ id: string;
111
+ name: string;
112
+ }, ttlMs?: number): {
113
+ success: boolean;
114
+ lock?: FieldLock;
115
+ currentLock?: FieldLock;
116
+ };
117
+ /**
118
+ * Releases an exclusive lock on a field
119
+ */
120
+ releaseLock(docKey: string, fieldName: string, userId: string): boolean;
121
+ /**
122
+ * Adds an editorial review comment
123
+ */
124
+ addComment(docKey: string, comment: {
125
+ id: string;
126
+ authorId: string;
127
+ authorName: string;
128
+ field?: string;
129
+ text: string;
130
+ }): DocComment;
131
+ /**
132
+ * Resolves an editorial comment
133
+ */
134
+ resolveComment(docKey: string, commentId: string): boolean;
135
+ /**
136
+ * Returns snapshot of entire presence state for a document
137
+ */
138
+ getSnapshot(docKey: string): {
139
+ users: PresenceUser[];
140
+ cursors: CursorState[];
141
+ locks: FieldLock[];
142
+ comments: DocComment[];
143
+ };
144
+ /**
145
+ * Deterministic avatar color generator for users
146
+ */
147
+ private generateUserColor;
148
+ }
149
+
39
150
  interface WSServerOptions {
40
151
  port?: number;
41
152
  pubsub: KyroPubSub;
@@ -57,6 +168,7 @@ interface WSClient {
57
168
  tenantId?: string;
58
169
  connectedAt: Date;
59
170
  lastActivity: Date;
171
+ activeDocKey?: string;
60
172
  }
61
173
  declare class KyroWSServer {
62
174
  private wss;
@@ -64,6 +176,7 @@ declare class KyroWSServer {
64
176
  private pubsub;
65
177
  private options;
66
178
  private pingTimer?;
179
+ readonly presence: PresenceManager;
67
180
  constructor(options: WSServerOptions);
68
181
  private setupServer;
69
182
  private handleMessage;
@@ -72,6 +185,13 @@ declare class KyroWSServer {
72
185
  private handleUnsubscribe;
73
186
  private handleUnsubscribeAll;
74
187
  private handleList;
188
+ private handlePresenceJoin;
189
+ private handlePresenceLeave;
190
+ private handlePresenceCursor;
191
+ private handlePresenceLock;
192
+ private handlePresenceUnlock;
193
+ private handlePresenceComment;
194
+ private handlePresenceSnapshot;
75
195
  private handleDisconnect;
76
196
  private sendToClient;
77
197
  private generateClientId;
@@ -85,4 +205,4 @@ declare class KyroWSServer {
85
205
  }
86
206
  declare function createWSServer(options: WSServerOptions): KyroWSServer;
87
207
 
88
- export { type EventHandler, type KyroEvent, KyroPubSub, KyroWSServer, PubSub, type WSClient, type WSServerOptions, createWSServer };
208
+ export { type CursorState, type DocComment, type DocPresenceState, type EventHandler, type FieldLock, type KyroEvent, KyroPubSub, KyroWSServer, PresenceManager, type PresenceUser, PubSub, type WSClient, type WSServerOptions, createWSServer };
package/dist/ws/index.js CHANGED
@@ -1 +1 @@
1
- export{b as KyroPubSub,c as KyroWSServer,a as PubSub,d as createWSServer}from'../chunk-5M3FKE2V.js';import'../chunk-7MNDQU6K.js';import'../chunk-Y2YAKDEQ.js';if (typeof window === "undefined") { const { createRequire } = await import(/* @vite-ignore */ 'module'); createRequire(import.meta.url); }
1
+ export{b as KyroPubSub,d as KyroWSServer,c as PresenceManager,a as PubSub,e as createWSServer}from'../chunk-KEITOXIP.js';import'../chunk-7MNDQU6K.js';import'../chunk-Y2YAKDEQ.js';if (typeof window === "undefined") { const { createRequire } = await import(/* @vite-ignore */ 'module'); createRequire(import.meta.url); }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kyro-cms/core",
3
- "version": "0.12.71",
3
+ "version": "0.13.1",
4
4
  "description": "Astro-native headless CMS with multi-database adapters, multi-protocol APIs, and multi-vendor support",
5
5
  "engines": {
6
6
  "node": ">=22"
@@ -191,7 +191,7 @@
191
191
  "ws": "^8.18.0",
192
192
  "zod": "^3.24.0",
193
193
  "zod-to-json-schema": "^3.25.2",
194
- "@kyro-cms/ai": "0.12.71"
194
+ "@kyro-cms/ai": "0.13.0"
195
195
  },
196
196
  "devDependencies": {
197
197
  "@tailwindcss/vite": "^4.0.0",
@@ -1,2 +0,0 @@
1
- import {b,a as a$1}from'./chunk-7MNDQU6K.js';import {g}from'./chunk-Y2YAKDEQ.js';if (typeof window === "undefined") { const { createRequire } = await import(/* @vite-ignore */ 'module'); createRequire(import.meta.url); }
2
- g();g();var a=class{channels=new Map;maxListeners;constructor(e=100){this.maxListeners=e;}subscribe(e,t){this.channels.has(e)||this.channels.set(e,new Set);let s=this.channels.get(e);if(s.size>=this.maxListeners)throw new Error(`Max listeners (${this.maxListeners}) reached for channel "${e}"`);return s.add(t),()=>{s.delete(t),s.size===0&&this.channels.delete(e);}}publish(e,t){let s=this.channels.get(e);if(s)for(let n of s)try{let i=n(t);i instanceof Promise&&i.catch(b=>{console.error(`[PubSub] Error in handler for channel "${e}":`,b);});}catch(i){console.error(`[PubSub] Error in handler for channel "${e}":`,i);}}hasSubscribers(e){return this.channels.has(e)&&this.channels.get(e).size>0}getSubscriberCount(e){return this.channels.get(e)?.size||0}getChannels(){return Array.from(this.channels.keys())}clear(){this.channels.clear();}},l=class extends a{registry;constructor(e,t=100){super(t),this.registry=e;}publishCollectionEvent(e,t){this.publish(`collection:${e}`,t),this.publish("events:collection",t),t.tenantId&&(this.publish(`tenant:${t.tenantId}:collection:${e}`,t),this.publish(`tenant:${t.tenantId}:events`,t)),this.publish(`collection:${e}:${t.type}`,t);}subscribeToCollection(e,t){return this.subscribe(`collection:${e}`,t)}subscribeToCollectionEvent(e,t,s){return this.subscribe(`collection:${e}:${t}`,s)}subscribeToTenant(e,t){return this.subscribe(`tenant:${e}:events`,t)}subscribeToTenantCollection(e,t,s){return this.subscribe(`tenant:${e}:collection:${t}`,s)}subscribeToAllCollections(e){return this.subscribe("events:collection",e)}createAfterChangeHook(e){return async t=>{this.publishCollectionEvent(e,{type:t.operation==="create"?"create":"update",collection:e,doc:t.doc,originalDoc:t.originalDoc,id:t.id||t.doc?.id,tenantId:t.tenantId,timestamp:new Date().toISOString(),user:t.user});}}createAfterDeleteHook(e){return async t=>{this.publishCollectionEvent(e,{type:"delete",collection:e,doc:t.doc,originalDoc:t.originalDoc,id:t.id||t.doc?.id,tenantId:t.tenantId,timestamp:new Date().toISOString(),user:t.user});}}autoRegisterHooks(){let e=this.registry.getCollections();for(let t of e){let s=this.registry.getCollection(t.slug);s&&(s.hooks||(s.hooks={}),s.hooks.afterChange||(s.hooks.afterChange=[]),s.hooks.afterDelete||(s.hooks.afterDelete=[]),s.hooks.afterChange.push(this.createAfterChangeHook(t.slug)),s.hooks.afterDelete.push(this.createAfterDeleteHook(t.slug)));}}};g();var c=class{wss;clients=new Map;pubsub;options;pingTimer;constructor(e){this.options=e,this.pubsub=e.pubsub,this.wss=new b.default({port:e.port||8080}),this.setupServer(),this.startPingInterval();}setupServer(){this.wss.on("connection",(e,t)=>{let s=this.generateClientId();if(this.options.maxConnections&&this.clients.size>=this.options.maxConnections){e.close(1013,"Server at capacity");return}let n={id:s,ws:e,subscriptions:new Map,authenticated:false,connectedAt:new Date,lastActivity:new Date};this.clients.set(s,n),this.sendToClient(n,{type:"connected",clientId:s,timestamp:new Date().toISOString()}),e.on("message",i=>{this.handleMessage(n,i);}),e.on("error",i=>{console.error(`[WS] Client error ${s}:`,i);}),e.on("close",()=>{this.handleDisconnect(n);}),e.on("pong",()=>{n.lastActivity=new Date;});}),this.wss.on("error",e=>{console.error("[WS] Server error:",e);});}handleMessage(e,t){e.lastActivity=new Date;let s;try{s=JSON.parse(t.toString());}catch{this.sendToClient(e,{type:"error",error:"Invalid JSON"});return}switch(s.type){case "authenticate":this.handleAuthenticate(e,s);break;case "subscribe":this.handleSubscribe(e,s);break;case "unsubscribe":this.handleUnsubscribe(e,s);break;case "unsubscribeAll":this.handleUnsubscribeAll(e);break;case "list":this.handleList(e);break;case "ping":this.sendToClient(e,{type:"pong",timestamp:new Date().toISOString()});break;default:this.sendToClient(e,{type:"error",error:`Unknown message type: ${s.type}`});}}async handleAuthenticate(e,t){if(!this.options.requireAuth){e.authenticated=true,this.sendToClient(e,{type:"authenticated",success:true});return}if(!this.options.verifyToken){e.authenticated=true,this.sendToClient(e,{type:"authenticated",success:true});return}try{let s=await this.options.verifyToken(t.token);e.authenticated=!0,e.user=s,e.tenantId=s.tenantId,this.sendToClient(e,{type:"authenticated",success:!0,user:{id:s.id,email:s.email}});}catch(s){this.sendToClient(e,{type:"authenticated",success:false,error:s.message});}}handleSubscribe(e,t){if(this.options.requireAuth&&!e.authenticated){this.sendToClient(e,{type:"error",error:"Not authenticated"});return}let s=t.channel;if(!s){this.sendToClient(e,{type:"error",error:"Channel is required"});return}if(e.subscriptions.has(s)){this.sendToClient(e,{type:"subscribed",channel:s,success:true,message:"Already subscribed"});return}let n=this.pubsub.subscribe(s,i=>{this.sendToClient(e,{type:"event",channel:s,data:i,timestamp:new Date().toISOString()});});e.subscriptions.set(s,{channel:s,unsubscribe:n}),this.sendToClient(e,{type:"subscribed",channel:s,success:true});}handleUnsubscribe(e,t){let s=t.channel;if(!s){this.sendToClient(e,{type:"error",error:"Channel is required"});return}let n=e.subscriptions.get(s);n?(n.unsubscribe(),e.subscriptions.delete(s),this.sendToClient(e,{type:"unsubscribed",channel:s,success:true})):this.sendToClient(e,{type:"unsubscribed",channel:s,success:false,message:"Not subscribed"});}handleUnsubscribeAll(e){for(let[,t]of e.subscriptions)t.unsubscribe();e.subscriptions.clear(),this.sendToClient(e,{type:"unsubscribedAll",success:true});}handleList(e){let t=this.pubsub.getChannels();this.sendToClient(e,{type:"channels",channels:t,count:t.length});}handleDisconnect(e){for(let[,t]of e.subscriptions)t.unsubscribe();this.clients.delete(e.id);}sendToClient(e,t){e.ws.readyState===a$1.default.OPEN&&e.ws.send(JSON.stringify(t));}generateClientId(){return `ws_${Date.now()}_${Math.random().toString(36).slice(2,9)}`}startPingInterval(){this.options.pingInterval&&(this.pingTimer=setInterval(()=>{for(let[e,t]of this.clients)if(t.ws.readyState===a$1.default.OPEN){if(Date.now()-t.lastActivity.getTime()>this.options.pingInterval*3){t.ws.terminate(),this.handleDisconnect(t);continue}t.ws.ping();}},this.options.pingInterval));}broadcast(e,t){this.pubsub.publish(e,t);}getConnectedClients(){return Array.from(this.clients.values())}getClientCount(){return this.clients.size}getSubscriptionCount(){let e=0;for(let t of this.clients.values())e+=t.subscriptions.size;return e}async close(){this.pingTimer&&clearInterval(this.pingTimer);for(let e of this.clients.values())e.ws.close(1001,"Server shutting down");return new Promise(e=>{this.wss.close(()=>{e();});})}getServer(){return this.wss}};function v(o){return new c(o)}export{a,l as b,c,v as d};
@@ -1 +0,0 @@
1
- 'use strict';var chunk73D2PNHD_cjs=require('./chunk-73D2PNHD.cjs'),chunkBUNLC3II_cjs=require('./chunk-BUNLC3II.cjs');chunkBUNLC3II_cjs.h();chunkBUNLC3II_cjs.h();var a=class{channels=new Map;maxListeners;constructor(e=100){this.maxListeners=e;}subscribe(e,t){this.channels.has(e)||this.channels.set(e,new Set);let s=this.channels.get(e);if(s.size>=this.maxListeners)throw new Error(`Max listeners (${this.maxListeners}) reached for channel "${e}"`);return s.add(t),()=>{s.delete(t),s.size===0&&this.channels.delete(e);}}publish(e,t){let s=this.channels.get(e);if(s)for(let n of s)try{let i=n(t);i instanceof Promise&&i.catch(p=>{console.error(`[PubSub] Error in handler for channel "${e}":`,p);});}catch(i){console.error(`[PubSub] Error in handler for channel "${e}":`,i);}}hasSubscribers(e){return this.channels.has(e)&&this.channels.get(e).size>0}getSubscriberCount(e){return this.channels.get(e)?.size||0}getChannels(){return Array.from(this.channels.keys())}clear(){this.channels.clear();}},l=class extends a{registry;constructor(e,t=100){super(t),this.registry=e;}publishCollectionEvent(e,t){this.publish(`collection:${e}`,t),this.publish("events:collection",t),t.tenantId&&(this.publish(`tenant:${t.tenantId}:collection:${e}`,t),this.publish(`tenant:${t.tenantId}:events`,t)),this.publish(`collection:${e}:${t.type}`,t);}subscribeToCollection(e,t){return this.subscribe(`collection:${e}`,t)}subscribeToCollectionEvent(e,t,s){return this.subscribe(`collection:${e}:${t}`,s)}subscribeToTenant(e,t){return this.subscribe(`tenant:${e}:events`,t)}subscribeToTenantCollection(e,t,s){return this.subscribe(`tenant:${e}:collection:${t}`,s)}subscribeToAllCollections(e){return this.subscribe("events:collection",e)}createAfterChangeHook(e){return async t=>{this.publishCollectionEvent(e,{type:t.operation==="create"?"create":"update",collection:e,doc:t.doc,originalDoc:t.originalDoc,id:t.id||t.doc?.id,tenantId:t.tenantId,timestamp:new Date().toISOString(),user:t.user});}}createAfterDeleteHook(e){return async t=>{this.publishCollectionEvent(e,{type:"delete",collection:e,doc:t.doc,originalDoc:t.originalDoc,id:t.id||t.doc?.id,tenantId:t.tenantId,timestamp:new Date().toISOString(),user:t.user});}}autoRegisterHooks(){let e=this.registry.getCollections();for(let t of e){let s=this.registry.getCollection(t.slug);s&&(s.hooks||(s.hooks={}),s.hooks.afterChange||(s.hooks.afterChange=[]),s.hooks.afterDelete||(s.hooks.afterDelete=[]),s.hooks.afterChange.push(this.createAfterChangeHook(t.slug)),s.hooks.afterDelete.push(this.createAfterDeleteHook(t.slug)));}}};chunkBUNLC3II_cjs.h();var c=class{wss;clients=new Map;pubsub;options;pingTimer;constructor(e){this.options=e,this.pubsub=e.pubsub,this.wss=new chunk73D2PNHD_cjs.b.default({port:e.port||8080}),this.setupServer(),this.startPingInterval();}setupServer(){this.wss.on("connection",(e,t)=>{let s=this.generateClientId();if(this.options.maxConnections&&this.clients.size>=this.options.maxConnections){e.close(1013,"Server at capacity");return}let n={id:s,ws:e,subscriptions:new Map,authenticated:false,connectedAt:new Date,lastActivity:new Date};this.clients.set(s,n),this.sendToClient(n,{type:"connected",clientId:s,timestamp:new Date().toISOString()}),e.on("message",i=>{this.handleMessage(n,i);}),e.on("error",i=>{console.error(`[WS] Client error ${s}:`,i);}),e.on("close",()=>{this.handleDisconnect(n);}),e.on("pong",()=>{n.lastActivity=new Date;});}),this.wss.on("error",e=>{console.error("[WS] Server error:",e);});}handleMessage(e,t){e.lastActivity=new Date;let s;try{s=JSON.parse(t.toString());}catch{this.sendToClient(e,{type:"error",error:"Invalid JSON"});return}switch(s.type){case "authenticate":this.handleAuthenticate(e,s);break;case "subscribe":this.handleSubscribe(e,s);break;case "unsubscribe":this.handleUnsubscribe(e,s);break;case "unsubscribeAll":this.handleUnsubscribeAll(e);break;case "list":this.handleList(e);break;case "ping":this.sendToClient(e,{type:"pong",timestamp:new Date().toISOString()});break;default:this.sendToClient(e,{type:"error",error:`Unknown message type: ${s.type}`});}}async handleAuthenticate(e,t){if(!this.options.requireAuth){e.authenticated=true,this.sendToClient(e,{type:"authenticated",success:true});return}if(!this.options.verifyToken){e.authenticated=true,this.sendToClient(e,{type:"authenticated",success:true});return}try{let s=await this.options.verifyToken(t.token);e.authenticated=!0,e.user=s,e.tenantId=s.tenantId,this.sendToClient(e,{type:"authenticated",success:!0,user:{id:s.id,email:s.email}});}catch(s){this.sendToClient(e,{type:"authenticated",success:false,error:s.message});}}handleSubscribe(e,t){if(this.options.requireAuth&&!e.authenticated){this.sendToClient(e,{type:"error",error:"Not authenticated"});return}let s=t.channel;if(!s){this.sendToClient(e,{type:"error",error:"Channel is required"});return}if(e.subscriptions.has(s)){this.sendToClient(e,{type:"subscribed",channel:s,success:true,message:"Already subscribed"});return}let n=this.pubsub.subscribe(s,i=>{this.sendToClient(e,{type:"event",channel:s,data:i,timestamp:new Date().toISOString()});});e.subscriptions.set(s,{channel:s,unsubscribe:n}),this.sendToClient(e,{type:"subscribed",channel:s,success:true});}handleUnsubscribe(e,t){let s=t.channel;if(!s){this.sendToClient(e,{type:"error",error:"Channel is required"});return}let n=e.subscriptions.get(s);n?(n.unsubscribe(),e.subscriptions.delete(s),this.sendToClient(e,{type:"unsubscribed",channel:s,success:true})):this.sendToClient(e,{type:"unsubscribed",channel:s,success:false,message:"Not subscribed"});}handleUnsubscribeAll(e){for(let[,t]of e.subscriptions)t.unsubscribe();e.subscriptions.clear(),this.sendToClient(e,{type:"unsubscribedAll",success:true});}handleList(e){let t=this.pubsub.getChannels();this.sendToClient(e,{type:"channels",channels:t,count:t.length});}handleDisconnect(e){for(let[,t]of e.subscriptions)t.unsubscribe();this.clients.delete(e.id);}sendToClient(e,t){e.ws.readyState===chunk73D2PNHD_cjs.a.default.OPEN&&e.ws.send(JSON.stringify(t));}generateClientId(){return `ws_${Date.now()}_${Math.random().toString(36).slice(2,9)}`}startPingInterval(){this.options.pingInterval&&(this.pingTimer=setInterval(()=>{for(let[e,t]of this.clients)if(t.ws.readyState===chunk73D2PNHD_cjs.a.default.OPEN){if(Date.now()-t.lastActivity.getTime()>this.options.pingInterval*3){t.ws.terminate(),this.handleDisconnect(t);continue}t.ws.ping();}},this.options.pingInterval));}broadcast(e,t){this.pubsub.publish(e,t);}getConnectedClients(){return Array.from(this.clients.values())}getClientCount(){return this.clients.size}getSubscriptionCount(){let e=0;for(let t of this.clients.values())e+=t.subscriptions.size;return e}async close(){this.pingTimer&&clearInterval(this.pingTimer);for(let e of this.clients.values())e.ws.close(1001,"Server shutting down");return new Promise(e=>{this.wss.close(()=>{e();});})}getServer(){return this.wss}};function b(o){return new c(o)}exports.a=a;exports.b=l;exports.c=c;exports.d=b;