deepspace 0.26.0 → 0.26.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 (52) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/{chunk-LPXWXF6R.js → chunk-YBXIUDZJ.js} +2 -2
  3. package/dist/{chunk-LPXWXF6R.js.map → chunk-YBXIUDZJ.js.map} +1 -1
  4. package/dist/cli.js +80 -45
  5. package/dist/cli.js.map +1 -1
  6. package/dist/documentation-client-core.js +1 -1
  7. package/dist/documentation-default-renderer.cjs +1 -1
  8. package/dist/documentation-react.js +1 -1
  9. package/dist/documentation-runtime.js +1 -1
  10. package/dist/documentation-server-core.js +1 -1
  11. package/dist/documentation.js +1 -1
  12. package/dist/documentation.js.map +1 -1
  13. package/dist/index.d.ts +26 -434
  14. package/dist/index.js +99 -864
  15. package/dist/index.js.map +1 -1
  16. package/dist/schema.d.ts +4 -41
  17. package/dist/schema.js +2 -242
  18. package/dist/schema.js.map +1 -1
  19. package/dist/server.d.ts +6 -162
  20. package/dist/server.js +13 -281
  21. package/dist/server.js.map +1 -1
  22. package/dist/worker.d.ts +4 -160
  23. package/dist/worker.js +15 -281
  24. package/dist/worker.js.map +1 -1
  25. package/features/messaging/feature.json +3 -43
  26. package/features/messaging/src/ChatPage.tsx +12 -16
  27. package/features/messaging/src/components/chat/ChatHeader.tsx +5 -13
  28. package/features/messaging/src/components/chat/MessageItem.tsx +7 -9
  29. package/features/messaging/src/components/chat/MessageList.tsx +57 -40
  30. package/features/messaging/src/components/chat/ThreadPanel.tsx +25 -11
  31. package/features/messaging/src/components/chat/UserProfilePopover.tsx +10 -29
  32. package/features/messaging/src/hooks/useChatChannel.ts +18 -23
  33. package/features/messaging/src/messaging-schema.ts +0 -2
  34. package/features/search-bar/feature.json +9 -20
  35. package/features/search-bar/src/InlineSearch.tsx +101 -0
  36. package/features/search-bar/src/__tests__/search-model.test.tsx +38 -0
  37. package/features/search-bar/src/search-model.ts +2 -149
  38. package/package.json +1 -1
  39. package/features/messaging/src/ChatMultiPage.tsx +0 -298
  40. package/features/messaging/src/components/chat-multi/AddMemberModal.tsx +0 -188
  41. package/features/messaging/src/components/chat-multi/BrowseGroupsModal.tsx +0 -163
  42. package/features/messaging/src/components/chat-multi/ChannelListItem.tsx +0 -147
  43. package/features/messaging/src/components/chat-multi/ChannelSettingsPanel.tsx +0 -344
  44. package/features/messaging/src/components/chat-multi/ChannelSidebar.tsx +0 -460
  45. package/features/messaging/src/components/chat-multi/CreateGroupModal.tsx +0 -190
  46. package/features/messaging/src/components/chat-multi/InvitationList.tsx +0 -149
  47. package/features/messaging/src/components/chat-multi/NewMessageModal.tsx +0 -159
  48. package/features/messaging/src/hooks/useMultiChannel.ts +0 -142
  49. package/features/search-bar/src/SearchOverlay.tsx +0 -566
  50. package/features/search-bar/src/__tests__/search-model.test.ts +0 -40
  51. package/features/sidebar/feature.json +0 -19
  52. package/features/sidebar/src/AppSidebar.tsx +0 -558
package/dist/index.js CHANGED
@@ -139,6 +139,9 @@ var ROLES = {
139
139
  MEMBER: "member",
140
140
  ADMIN: "admin"
141
141
  };
142
+ function isWriterRole(role) {
143
+ return role === ROLES.ADMIN || role === ROLES.MEMBER;
144
+ }
142
145
  var ROLE_CONFIG = {
143
146
  viewer: { title: "Viewer", badgeVariant: "secondary", description: "Read-only access" },
144
147
  member: { title: "Member", badgeVariant: "default", description: "Can create and edit own content" },
@@ -4029,7 +4032,7 @@ function useChannels() {
4029
4032
  (data) => {
4030
4033
  return createMutation({
4031
4034
  name: data.name,
4032
- type: data.type,
4035
+ type: "public",
4033
4036
  description: data.description ?? "",
4034
4037
  createdBy: user?.id ?? "",
4035
4038
  archived: false
@@ -4099,7 +4102,13 @@ function useReactions(channelId) {
4099
4102
  },
4100
4103
  [channelId, user, records, create, removeMutation]
4101
4104
  );
4102
- return { reactions: records, status, error, getReactionsForMessage, toggle };
4105
+ return {
4106
+ reactions: records,
4107
+ status,
4108
+ error,
4109
+ getReactionsForMessage,
4110
+ toggle
4111
+ };
4103
4112
  }
4104
4113
 
4105
4114
  // src/client/messaging/useChannelMembers.ts
@@ -4109,18 +4118,22 @@ function useChannelMembers(channelId) {
4109
4118
  const { records, status, error } = useQuery("channel-members", {
4110
4119
  where: channelId ? { channelId } : { channelId: "__none__" }
4111
4120
  });
4112
- const { create, remove: removeMutation } = useMutations("channel-members");
4113
- const join = useCallback18(() => {
4121
+ const { createConfirmed, removeConfirmed } = useMutations("channel-members");
4122
+ const join = useCallback18(async () => {
4114
4123
  if (!channelId || !user) return;
4115
4124
  const existing = records.find((r) => r.data.userId === user.id);
4116
4125
  if (existing) return;
4117
- create({ channelId, userId: user.id, joinedAt: (/* @__PURE__ */ new Date()).toISOString() });
4118
- }, [channelId, user, records, create]);
4119
- const leave = useCallback18(() => {
4126
+ await createConfirmed({
4127
+ channelId,
4128
+ userId: user.id,
4129
+ joinedAt: (/* @__PURE__ */ new Date()).toISOString()
4130
+ });
4131
+ }, [channelId, user, records, createConfirmed]);
4132
+ const leave = useCallback18(async () => {
4120
4133
  if (!channelId || !user) return;
4121
4134
  const membership = records.find((r) => r.data.userId === user.id);
4122
- if (membership) removeMutation(membership.recordId);
4123
- }, [channelId, user, records, removeMutation]);
4135
+ if (membership) await removeConfirmed(membership.recordId);
4136
+ }, [channelId, user, records, removeConfirmed]);
4124
4137
  const isMember = user ? records.some((r) => r.data.userId === user.id) : false;
4125
4138
  return { members: records, status, error, join, leave, isMember };
4126
4139
  }
@@ -4158,583 +4171,6 @@ function useReadReceipts() {
4158
4171
  return { receipts: records, status, error, markAsRead, getUnreadCount };
4159
4172
  }
4160
4173
 
4161
- // src/client/messaging/useConversation.ts
4162
- import { useCallback as useCallback20, useMemo as useMemo13 } from "react";
4163
- function useConversation(opts) {
4164
- const { user } = useUser();
4165
- const { ready } = useRecordContext();
4166
- const { records: allMessages } = useQuery("conv_messages", { orderBy: "_created_at" });
4167
- const { records: allReactions } = useQuery("conv_reactions");
4168
- const { records: members } = useQuery("conv_members");
4169
- const messageMut = useMutations("conv_messages");
4170
- const reactionMut = useMutations("conv_reactions");
4171
- const send = useCallback20(
4172
- (content, parentMessageId, messageType, metadata) => {
4173
- messageMut.create({
4174
- Content: content,
4175
- AuthorId: user?.id ?? "",
4176
- ParentId: parentMessageId ?? "",
4177
- Edited: 0,
4178
- MessageType: messageType ?? "message",
4179
- Metadata: metadata ? JSON.stringify(metadata) : ""
4180
- });
4181
- opts?.onMessageSent?.(content, parentMessageId);
4182
- },
4183
- // eslint-disable-next-line react-hooks/exhaustive-deps -- depend on the precise opts?.onMessageSent callback, not the whole opts object, to avoid recreating send when unrelated opts fields change
4184
- [messageMut, user?.id, opts?.onMessageSent]
4185
- );
4186
- const edit = useCallback20(
4187
- (recordId, content) => {
4188
- const existing = allMessages.find((m) => m.recordId === recordId);
4189
- if (!existing) return;
4190
- messageMut.put(recordId, { ...existing.data, Content: content, Edited: 1 });
4191
- },
4192
- [messageMut, allMessages]
4193
- );
4194
- const remove = useCallback20(
4195
- (recordId) => {
4196
- const existing = allMessages.find((m) => m.recordId === recordId);
4197
- if (!existing) return;
4198
- messageMut.put(recordId, {
4199
- ...existing.data,
4200
- Content: "",
4201
- MessageType: "deleted",
4202
- Metadata: ""
4203
- });
4204
- },
4205
- [messageMut, allMessages]
4206
- );
4207
- const toggleReaction = useCallback20(
4208
- (messageId, emoji) => {
4209
- const existing = allReactions.find(
4210
- (r) => r.data.MessageId === messageId && r.data.Emoji === emoji && r.data.UserId === user?.id
4211
- );
4212
- if (existing) {
4213
- reactionMut.remove(existing.recordId);
4214
- } else {
4215
- reactionMut.create({ MessageId: messageId, Emoji: emoji, UserId: user?.id ?? "" });
4216
- }
4217
- },
4218
- [reactionMut, allReactions, user?.id]
4219
- );
4220
- return useMemo13(
4221
- () => ({
4222
- messages: allMessages,
4223
- reactions: allReactions,
4224
- members,
4225
- status: ready ? "connected" : "connecting",
4226
- send,
4227
- edit,
4228
- remove,
4229
- toggleReaction
4230
- }),
4231
- [allMessages, allReactions, members, ready, send, edit, remove, toggleReaction]
4232
- );
4233
- }
4234
-
4235
- // src/client/messaging/utils.ts
4236
- function groupReactionsForMessage(reactions, messageId, currentUserId) {
4237
- const forMessage = reactions.filter((r) => r.data.MessageId === messageId);
4238
- const groups = /* @__PURE__ */ new Map();
4239
- for (const r of forMessage) {
4240
- const existing = groups.get(r.data.Emoji) ?? { count: 0, currentUserReacted: false, userIds: [] };
4241
- existing.count++;
4242
- existing.userIds.push(r.data.UserId);
4243
- if (r.data.UserId === currentUserId) existing.currentUserReacted = true;
4244
- groups.set(r.data.Emoji, existing);
4245
- }
4246
- return Array.from(groups.entries()).map(([emoji, data]) => ({
4247
- emoji,
4248
- count: data.count,
4249
- currentUserReacted: data.currentUserReacted,
4250
- userIds: data.userIds
4251
- }));
4252
- }
4253
- var GROUPING_THRESHOLD_MS = 5 * 60 * 1e3;
4254
- function shouldGroupMessages(current, previous, options) {
4255
- if (!previous) return false;
4256
- if (options?.dateChanged) return false;
4257
- if (previous.data.AuthorId !== current.data.AuthorId) return false;
4258
- const timeDiff = new Date(current.createdAt).getTime() - new Date(previous.createdAt).getTime();
4259
- return timeDiff < (options?.thresholdMs ?? GROUPING_THRESHOLD_MS);
4260
- }
4261
- function getThreadCounts(messages) {
4262
- const counts = /* @__PURE__ */ new Map();
4263
- for (const m of messages) {
4264
- if (m.data.ParentId) {
4265
- counts.set(m.data.ParentId, (counts.get(m.data.ParentId) ?? 0) + 1);
4266
- }
4267
- }
4268
- return counts;
4269
- }
4270
- function formatMessageTime(dateStr) {
4271
- return new Date(dateStr).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
4272
- }
4273
- function formatFullTimestamp(dateStr) {
4274
- const date = new Date(dateStr);
4275
- const datePart = date.toLocaleDateString([], { month: "short", day: "numeric", year: "numeric" });
4276
- const timePart = date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
4277
- return `${datePart} at ${timePart}`;
4278
- }
4279
-
4280
- // src/client/messaging/conversation-utils.ts
4281
- function getConversationDisplayName(conversation, currentUserId, getUser) {
4282
- const { Type, Name } = conversation.data;
4283
- if (Type !== "dm" && Type !== "group") {
4284
- return Name || "Untitled";
4285
- }
4286
- const ids = getConversationParticipantIds(conversation, currentUserId);
4287
- if (ids.length === 0) return "Unknown";
4288
- if (Type === "dm") {
4289
- const other = getUser(ids[0]);
4290
- return other?.name ?? "Unknown";
4291
- }
4292
- const MAX_NAMES = 3;
4293
- const names = [];
4294
- for (let i = 0; i < Math.min(ids.length, MAX_NAMES); i++) {
4295
- const u = getUser(ids[i]);
4296
- names.push(u?.name?.split(" ")[0] ?? "Unknown");
4297
- }
4298
- const remaining = ids.length - MAX_NAMES;
4299
- if (remaining > 0) {
4300
- return `${names.join(", ")}, +${remaining}`;
4301
- }
4302
- return names.join(", ");
4303
- }
4304
- function isDMConversation(type) {
4305
- return type === "dm" || type === "group";
4306
- }
4307
- function getConversationParticipantIds(conversation, excludeUserId) {
4308
- let ids = [];
4309
- try {
4310
- const parsed = JSON.parse(conversation.data.ParticipantIds);
4311
- if (Array.isArray(parsed) && parsed.length > 0) {
4312
- ids = parsed;
4313
- }
4314
- } catch {
4315
- }
4316
- if (ids.length === 0 && conversation.data.ParticipantHash) {
4317
- ids = conversation.data.ParticipantHash.split(":");
4318
- }
4319
- if (excludeUserId) {
4320
- return ids.filter((id) => id !== excludeUserId);
4321
- }
4322
- return ids;
4323
- }
4324
-
4325
- // src/client/messaging/message-utils.ts
4326
- function parseMessageMetadata(raw) {
4327
- if (!raw) return null;
4328
- if (typeof raw === "object") return raw;
4329
- if (typeof raw === "string") {
4330
- try {
4331
- return JSON.parse(raw);
4332
- } catch {
4333
- return null;
4334
- }
4335
- }
4336
- return null;
4337
- }
4338
-
4339
- // src/client/directory/useConversations.ts
4340
- import { useCallback as useCallback21, useMemo as useMemo14, useRef as useRef13 } from "react";
4341
- var defaultConvFields = {
4342
- Visibility: "public",
4343
- Status: "active",
4344
- AssigneeId: "",
4345
- LinkedRef: "",
4346
- MessageCount: 0
4347
- };
4348
- function useConversations() {
4349
- const { records: conversations, status } = useQuery("conversations");
4350
- const { create, put } = useMutations("conversations");
4351
- const { records: stateRecords } = useQuery("conversation_state");
4352
- const stateMut = useMutations("conversation_state");
4353
- const { user } = useUser();
4354
- const ready = status === "ready";
4355
- const recentCreationsRef = useRef13(/* @__PURE__ */ new Map());
4356
- for (const [id] of recentCreationsRef.current) {
4357
- if (conversations.find((c) => c.recordId === id)) {
4358
- recentCreationsRef.current.delete(id);
4359
- }
4360
- }
4361
- const readStateMap = useMemo14(
4362
- () => new Map(stateRecords.map((r) => [r.data.ConversationId, r.data.LastReadAt])),
4363
- [stateRecords]
4364
- );
4365
- const readMessageCountMap = useMemo14(
4366
- () => new Map(stateRecords.map((r) => [r.data.ConversationId, r.data.LastReadMessageCount ?? 0])),
4367
- [stateRecords]
4368
- );
4369
- const starredSet = useMemo14(
4370
- () => new Set(stateRecords.filter((r) => r.data.Starred).map((r) => r.data.ConversationId)),
4371
- [stateRecords]
4372
- );
4373
- const archivedSet = useMemo14(
4374
- () => new Set(stateRecords.filter((r) => r.data.Archived).map((r) => r.data.ConversationId)),
4375
- [stateRecords]
4376
- );
4377
- const getConversationState = useCallback21(
4378
- (conversationId) => {
4379
- return stateRecords.find((r) => r.data.ConversationId === conversationId)?.data;
4380
- },
4381
- [stateRecords]
4382
- );
4383
- const createChannel = useCallback21(
4384
- async (name, description) => {
4385
- const existing = conversations.find((r) => r.data.Name === name && r.data.Type !== "dm");
4386
- if (existing) return existing.recordId;
4387
- const recordId = await create({
4388
- Name: name,
4389
- Description: description ?? "",
4390
- Type: "public",
4391
- CreatedBy: user?.id ?? "",
4392
- ParticipantHash: "",
4393
- ParticipantIds: "",
4394
- LastMessageAt: "",
4395
- LastMessagePreview: "",
4396
- LastMessageAuthor: "",
4397
- ...defaultConvFields
4398
- });
4399
- return recordId;
4400
- },
4401
- [create, user?.id, conversations]
4402
- );
4403
- const createDM = useCallback21(
4404
- async (otherUserId) => {
4405
- if (!user?.id) return null;
4406
- const hash = [user.id, otherUserId].sort().join(":");
4407
- const existing = conversations.find((r) => r.data.ParticipantHash === hash);
4408
- if (existing) return existing.recordId;
4409
- const data = {
4410
- Name: "",
4411
- Description: "",
4412
- Type: "dm",
4413
- Visibility: "private",
4414
- CreatedBy: user.id,
4415
- ParticipantHash: hash,
4416
- ParticipantIds: JSON.stringify([user.id, otherUserId]),
4417
- Status: "active",
4418
- AssigneeId: "",
4419
- LinkedRef: "",
4420
- LastMessageAt: "",
4421
- LastMessagePreview: "",
4422
- LastMessageAuthor: "",
4423
- MessageCount: 0
4424
- };
4425
- const recordId = await create(data);
4426
- recentCreationsRef.current.set(recordId, data);
4427
- return recordId;
4428
- },
4429
- [create, user?.id, conversations]
4430
- );
4431
- const createGroupDM = useCallback21(
4432
- async (participantIds) => {
4433
- if (!user?.id) return null;
4434
- const allIds = [.../* @__PURE__ */ new Set([user.id, ...participantIds])];
4435
- if (allIds.length < 3) return null;
4436
- const hash = allIds.sort().join(":");
4437
- const existing = conversations.find((r) => r.data.ParticipantHash === hash);
4438
- if (existing) return existing.recordId;
4439
- const data = {
4440
- Name: "",
4441
- Description: "",
4442
- Type: "group",
4443
- Visibility: "private",
4444
- CreatedBy: user.id,
4445
- ParticipantHash: hash,
4446
- ParticipantIds: JSON.stringify(allIds),
4447
- Status: "active",
4448
- AssigneeId: "",
4449
- LinkedRef: "",
4450
- LastMessageAt: "",
4451
- LastMessagePreview: "",
4452
- LastMessageAuthor: "",
4453
- MessageCount: 0
4454
- };
4455
- const recordId = await create(data);
4456
- recentCreationsRef.current.set(recordId, data);
4457
- return recordId;
4458
- },
4459
- [create, user?.id, conversations]
4460
- );
4461
- const lookupByName = useCallback21(
4462
- (name) => {
4463
- const found = conversations.find((r) => r.data.Name === name);
4464
- return found?.recordId ?? null;
4465
- },
4466
- [conversations]
4467
- );
4468
- const updateLastMessage = useCallback21(
4469
- (conversationId, preview, authorId) => {
4470
- const conv = conversations.find((c) => c.recordId === conversationId);
4471
- const baseData = conv?.data ?? recentCreationsRef.current.get(conversationId);
4472
- if (!baseData) return;
4473
- const updatedData = {
4474
- ...baseData,
4475
- LastMessageAt: (/* @__PURE__ */ new Date()).toISOString(),
4476
- LastMessagePreview: preview.slice(0, 100),
4477
- LastMessageAuthor: authorId ?? baseData.LastMessageAuthor,
4478
- MessageCount: (baseData.MessageCount ?? 0) + 1
4479
- };
4480
- put(conversationId, updatedData);
4481
- if (recentCreationsRef.current.has(conversationId)) {
4482
- recentCreationsRef.current.set(conversationId, updatedData);
4483
- }
4484
- },
4485
- [put, conversations]
4486
- );
4487
- const upsertState = useCallback21(
4488
- (conversationId, partial) => {
4489
- if (!user?.id) return;
4490
- const existing = stateRecords.find(
4491
- (r) => r.data.ConversationId === conversationId && r.data.UserId === user.id
4492
- );
4493
- const base = existing?.data ?? {
4494
- ConversationId: conversationId,
4495
- UserId: user.id,
4496
- LastReadAt: "",
4497
- LastReadMessageCount: 0,
4498
- Starred: 0,
4499
- Archived: 0,
4500
- Trashed: 0,
4501
- Labels: "",
4502
- Folder: ""
4503
- };
4504
- const recordId = existing?.recordId ?? `state-${user.id}-${conversationId}`;
4505
- stateMut.put(recordId, { ...base, ...partial });
4506
- },
4507
- [stateMut, stateRecords, user?.id]
4508
- );
4509
- const markRead = useCallback21(
4510
- (conversationId) => {
4511
- const conv = conversations.find((c) => c.recordId === conversationId);
4512
- const msgCount = conv?.data.MessageCount ?? recentCreationsRef.current.get(conversationId)?.MessageCount ?? 0;
4513
- upsertState(conversationId, {
4514
- LastReadAt: (/* @__PURE__ */ new Date()).toISOString(),
4515
- LastReadMessageCount: msgCount
4516
- });
4517
- },
4518
- [upsertState, conversations]
4519
- );
4520
- const toggleStar = useCallback21(
4521
- (conversationId) => {
4522
- const isStarred = starredSet.has(conversationId);
4523
- upsertState(conversationId, { Starred: isStarred ? 0 : 1 });
4524
- },
4525
- [upsertState, starredSet]
4526
- );
4527
- const setArchived = useCallback21(
4528
- (conversationId, archived) => {
4529
- upsertState(conversationId, { Archived: archived ? 1 : 0 });
4530
- },
4531
- [upsertState]
4532
- );
4533
- const setTrashed = useCallback21(
4534
- (conversationId, trashed) => {
4535
- upsertState(conversationId, { Trashed: trashed ? 1 : 0 });
4536
- },
4537
- [upsertState]
4538
- );
4539
- const setLabels = useCallback21(
4540
- (conversationId, labels) => {
4541
- upsertState(conversationId, { Labels: JSON.stringify(labels) });
4542
- },
4543
- [upsertState]
4544
- );
4545
- const setFolder = useCallback21(
4546
- (conversationId, folder) => {
4547
- upsertState(conversationId, { Folder: folder });
4548
- },
4549
- [upsertState]
4550
- );
4551
- return {
4552
- conversations,
4553
- ready,
4554
- createChannel,
4555
- createDM,
4556
- createGroupDM,
4557
- lookupByName,
4558
- updateLastMessage,
4559
- readStateMap,
4560
- readMessageCountMap,
4561
- starredSet,
4562
- archivedSet,
4563
- getConversationState,
4564
- upsertState,
4565
- markRead,
4566
- toggleStar,
4567
- setArchived,
4568
- setTrashed,
4569
- setLabels,
4570
- setFolder
4571
- };
4572
- }
4573
-
4574
- // src/client/directory/useCommunities.ts
4575
- import { useCallback as useCallback22, useMemo as useMemo15 } from "react";
4576
- function useCommunities() {
4577
- const { records: communities, status } = useQuery("communities");
4578
- const communityMut = useMutations("communities");
4579
- const { records: memberships } = useQuery("memberships");
4580
- const membershipMut = useMutations("memberships");
4581
- const { user } = useUser();
4582
- const ready = status === "ready";
4583
- const membershipMap = useMemo15(() => {
4584
- const map = /* @__PURE__ */ new Map();
4585
- for (const m of memberships) {
4586
- const list = map.get(m.data.CommunityId) ?? [];
4587
- list.push(m.data);
4588
- map.set(m.data.CommunityId, list);
4589
- }
4590
- return map;
4591
- }, [memberships]);
4592
- const myMemberships = useMemo15(
4593
- () => new Set(
4594
- memberships.filter((m) => m.data.UserId === user?.id).map((m) => m.data.CommunityId)
4595
- ),
4596
- [memberships, user?.id]
4597
- );
4598
- const createCommunity = useCallback22(
4599
- async (name, opts) => {
4600
- const existing = communities.find((c) => c.data.Name === name);
4601
- if (existing) return existing.recordId;
4602
- const recordId = await communityMut.create({
4603
- Name: name,
4604
- Description: opts?.description ?? "",
4605
- CreatedBy: user?.id ?? "",
4606
- Type: opts?.type ?? "community",
4607
- Visibility: opts?.visibility ?? "public",
4608
- MemberCount: 0,
4609
- Rules: opts?.rules ?? "",
4610
- IconUrl: "",
4611
- CoverUrl: ""
4612
- });
4613
- return recordId;
4614
- },
4615
- [communityMut, user?.id, communities]
4616
- );
4617
- const updateCommunity = useCallback22(
4618
- (communityId, updates) => {
4619
- const existing = communities.find((c) => c.recordId === communityId);
4620
- if (!existing) return;
4621
- communityMut.put(communityId, { ...existing.data, ...updates });
4622
- },
4623
- [communityMut, communities]
4624
- );
4625
- const joinCommunity = useCallback22(
4626
- async (communityId, userName) => {
4627
- if (!user?.id) return null;
4628
- const existing = memberships.find(
4629
- (m) => m.data.CommunityId === communityId && m.data.UserId === user.id
4630
- );
4631
- if (existing) return existing.recordId;
4632
- const recordId = await membershipMut.create({
4633
- CommunityId: communityId,
4634
- UserId: user.id,
4635
- UserName: userName,
4636
- Role: "member",
4637
- JoinedAt: (/* @__PURE__ */ new Date()).toISOString()
4638
- });
4639
- return recordId;
4640
- },
4641
- [membershipMut, memberships, user?.id]
4642
- );
4643
- const leaveCommunity = useCallback22(
4644
- (communityId) => {
4645
- if (!user?.id) return;
4646
- const membership = memberships.find(
4647
- (m) => m.data.CommunityId === communityId && m.data.UserId === user.id
4648
- );
4649
- if (membership) {
4650
- membershipMut.remove(membership.recordId);
4651
- }
4652
- },
4653
- [membershipMut, memberships, user?.id]
4654
- );
4655
- const getMembersOf = useCallback22(
4656
- (communityId) => {
4657
- return membershipMap.get(communityId) ?? [];
4658
- },
4659
- [membershipMap]
4660
- );
4661
- const lookupByName = useCallback22(
4662
- (name) => {
4663
- const found = communities.find((c) => c.data.Name === name);
4664
- return found?.recordId ?? null;
4665
- },
4666
- [communities]
4667
- );
4668
- return {
4669
- communities,
4670
- memberships,
4671
- ready,
4672
- myMemberships,
4673
- createCommunity,
4674
- updateCommunity,
4675
- joinCommunity,
4676
- leaveCommunity,
4677
- getMembersOf,
4678
- lookupByName
4679
- };
4680
- }
4681
-
4682
- // src/client/directory/usePosts.ts
4683
- import { useCallback as useCallback23 } from "react";
4684
- function usePosts(opts) {
4685
- const { records: allPosts, status } = useQuery("posts");
4686
- const postMut = useMutations("posts");
4687
- const { user } = useUser();
4688
- const ready = status === "ready";
4689
- const posts = opts?.communityId ? allPosts.filter((p) => p.data.CommunityId === opts.communityId) : allPosts;
4690
- const createPost = useCallback23(
4691
- async (data) => {
4692
- const recordId = await postMut.create({
4693
- Title: data.title,
4694
- Content: data.content,
4695
- AuthorId: user?.id ?? "",
4696
- Type: data.type ?? "post",
4697
- CommunityId: data.communityId ?? "",
4698
- ParentId: data.parentId ?? "",
4699
- ConversationId: "",
4700
- Status: "published",
4701
- Tags: data.tags ? JSON.stringify(data.tags) : "",
4702
- LinkUrl: data.linkUrl ?? ""
4703
- });
4704
- return recordId;
4705
- },
4706
- [postMut, user?.id]
4707
- );
4708
- const updatePost = useCallback23(
4709
- (postId, updates) => {
4710
- const existing = allPosts.find((p) => p.recordId === postId);
4711
- if (!existing) return;
4712
- postMut.put(postId, { ...existing.data, ...updates });
4713
- },
4714
- [postMut, allPosts]
4715
- );
4716
- const deletePost = useCallback23(
4717
- (postId) => {
4718
- postMut.remove(postId);
4719
- },
4720
- [postMut]
4721
- );
4722
- const setConversationId = useCallback23(
4723
- (postId, conversationId) => {
4724
- updatePost(postId, { ConversationId: conversationId });
4725
- },
4726
- [updatePost]
4727
- );
4728
- return {
4729
- posts,
4730
- ready,
4731
- createPost,
4732
- updatePost,
4733
- deletePost,
4734
- setConversationId
4735
- };
4736
- }
4737
-
4738
4174
  // src/client/theme/DeepSpaceThemeProvider.tsx
4739
4175
  import { useEffect as useEffect15 } from "react";
4740
4176
 
@@ -5074,190 +4510,6 @@ function useIsDarkTheme() {
5074
4510
  return isDark;
5075
4511
  }
5076
4512
 
5077
- // src/client/platform/PlatformProvider.tsx
5078
- import { createContext as createContext3, useContext as useContext5, useState as useState14, useEffect as useEffect17, useRef as useRef14, useCallback as useCallback24 } from "react";
5079
- import { jsx as jsx9 } from "react/jsx-runtime";
5080
- var PlatformContext = createContext3(null);
5081
- function usePlatform() {
5082
- const ctx = useContext5(PlatformContext);
5083
- if (!ctx) throw new Error("usePlatform must be used within a PlatformProvider");
5084
- return ctx;
5085
- }
5086
- function useInbox() {
5087
- const { inbox, subscribeInbox } = usePlatform();
5088
- useEffect17(() => subscribeInbox(), [subscribeInbox]);
5089
- return inbox;
5090
- }
5091
- function PlatformProvider({ children }) {
5092
- const [inbox, setInbox] = useState14([]);
5093
- const inboxSubscribers = useRef14(0);
5094
- const [inboxActive, setInboxActive] = useState14(false);
5095
- const subscribeInbox = useCallback24(() => {
5096
- inboxSubscribers.current++;
5097
- if (inboxSubscribers.current === 1) setInboxActive(true);
5098
- return () => {
5099
- inboxSubscribers.current--;
5100
- if (inboxSubscribers.current === 0) setInboxActive(false);
5101
- };
5102
- }, []);
5103
- useEffect17(() => {
5104
- if (!inboxActive) return;
5105
- let mounted = true;
5106
- let ws = null;
5107
- let pingInterval;
5108
- let retryTimer;
5109
- async function connect() {
5110
- const token = await getAuthToken();
5111
- if (!mounted) return;
5112
- if (!token) {
5113
- retryTimer = setTimeout(connect, 2e3);
5114
- return;
5115
- }
5116
- const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
5117
- ws = new WebSocket(
5118
- `${protocol}//${window.location.host}/platform/ws/inbox?token=${encodeURIComponent(token)}`
5119
- );
5120
- ws.onmessage = (e) => {
5121
- if (e.data === "pong") return;
5122
- try {
5123
- const msg = JSON.parse(e.data);
5124
- switch (msg.type) {
5125
- case "inbox_init":
5126
- setInbox(msg.entries);
5127
- break;
5128
- case "inbox_added":
5129
- setInbox((prev) => [...prev, msg.entry]);
5130
- break;
5131
- case "inbox_removed":
5132
- setInbox((prev) => prev.filter((x) => x.conversationId !== msg.conversationId));
5133
- break;
5134
- case "inbox_updated":
5135
- setInbox(
5136
- (prev) => prev.map((x) => x.conversationId === msg.entry.conversationId ? msg.entry : x)
5137
- );
5138
- break;
5139
- }
5140
- } catch {
5141
- }
5142
- };
5143
- ws.onclose = () => {
5144
- clearInterval(pingInterval);
5145
- pingInterval = void 0;
5146
- if (mounted) {
5147
- retryTimer = setTimeout(connect, 3e3);
5148
- }
5149
- };
5150
- clearInterval(pingInterval);
5151
- pingInterval = setInterval(() => {
5152
- if (ws?.readyState === WebSocket.OPEN) ws.send("ping");
5153
- }, 3e4);
5154
- }
5155
- connect();
5156
- return () => {
5157
- mounted = false;
5158
- clearTimeout(retryTimer);
5159
- clearInterval(pingInterval);
5160
- ws?.close();
5161
- setInbox([]);
5162
- };
5163
- }, [inboxActive]);
5164
- const platformFetch = useCallback24(async (path, init) => {
5165
- const token = await getAuthToken();
5166
- const headers = new Headers(init?.headers);
5167
- if (token) headers.set("Authorization", `Bearer ${token}`);
5168
- if (!headers.has("Content-Type") && init?.body) headers.set("Content-Type", "application/json");
5169
- return fetch(`/platform${path}`, { ...init, headers });
5170
- }, []);
5171
- return /* @__PURE__ */ jsx9(PlatformContext.Provider, { value: { platformFetch, subscribeInbox, inbox }, children });
5172
- }
5173
-
5174
- // src/client/platform/usePlatformWS.ts
5175
- import { useState as useState15, useEffect as useEffect18, useRef as useRef15 } from "react";
5176
- var MAX_RECONNECT_DELAY = 1e4;
5177
- var BASE_RECONNECT_DELAY = 500;
5178
- function usePlatformWS(options) {
5179
- const { path, scopeId, initialState, onMessage } = options;
5180
- const wsRef = useRef15(null);
5181
- const pingIntervalRef = useRef15(null);
5182
- const [state, setState] = useState15(initialState);
5183
- const reconnectAttemptRef = useRef15(0);
5184
- const reconnectTimerRef = useRef15(null);
5185
- const mountedRef = useRef15(true);
5186
- const onMessageRef = useRef15(onMessage);
5187
- onMessageRef.current = onMessage;
5188
- const initialStateRef = useRef15(initialState);
5189
- initialStateRef.current = initialState;
5190
- useEffect18(() => {
5191
- mountedRef.current = true;
5192
- return () => {
5193
- mountedRef.current = false;
5194
- };
5195
- }, []);
5196
- useEffect18(() => {
5197
- if (!scopeId) return;
5198
- setState(initialStateRef.current);
5199
- reconnectAttemptRef.current = 0;
5200
- async function connect() {
5201
- if (!mountedRef.current || !scopeId) return;
5202
- const token = await getAuthToken();
5203
- if (!token || !mountedRef.current) {
5204
- reconnectTimerRef.current = setTimeout(connect, 2e3);
5205
- return;
5206
- }
5207
- const params = new URLSearchParams();
5208
- params.set("token", token);
5209
- const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
5210
- const ws = new WebSocket(
5211
- `${protocol}//${window.location.host}/platform/ws/${path}/${scopeId}?${params}`
5212
- );
5213
- wsRef.current = ws;
5214
- ws.onmessage = (e) => {
5215
- if (e.data === "pong") return;
5216
- try {
5217
- const msg = JSON.parse(e.data);
5218
- if (msg.type === "init") {
5219
- reconnectAttemptRef.current = 0;
5220
- }
5221
- setState((prev) => onMessageRef.current(msg, prev));
5222
- } catch (err) {
5223
- console.error(`[usePlatformWS:${path}] message parse error:`, err);
5224
- }
5225
- };
5226
- ws.onclose = () => {
5227
- if (!mountedRef.current) return;
5228
- const attempt = reconnectAttemptRef.current++;
5229
- const delay = Math.min(BASE_RECONNECT_DELAY * Math.pow(2, attempt), MAX_RECONNECT_DELAY);
5230
- setState((prev) => ({
5231
- ...prev,
5232
- status: attempt === 0 ? "connecting" : "reconnecting"
5233
- }));
5234
- reconnectTimerRef.current = setTimeout(connect, delay);
5235
- };
5236
- if (pingIntervalRef.current) clearInterval(pingIntervalRef.current);
5237
- pingIntervalRef.current = setInterval(() => {
5238
- if (ws.readyState === WebSocket.OPEN) ws.send("ping");
5239
- }, 3e4);
5240
- }
5241
- connect();
5242
- return () => {
5243
- if (reconnectTimerRef.current) {
5244
- clearTimeout(reconnectTimerRef.current);
5245
- reconnectTimerRef.current = null;
5246
- }
5247
- if (pingIntervalRef.current) {
5248
- clearInterval(pingIntervalRef.current);
5249
- pingIntervalRef.current = null;
5250
- }
5251
- wsRef.current?.close();
5252
- wsRef.current = null;
5253
- };
5254
- }, [scopeId, path]);
5255
- const send = useRef15((msg) => {
5256
- wsRef.current?.send(JSON.stringify(msg));
5257
- }).current;
5258
- return { state, send };
5259
- }
5260
-
5261
4513
  // src/shared/api-error.ts
5262
4514
  var SLUG_RE = /^[a-z0-9]+(?:[_.-][a-z0-9]+)*$/;
5263
4515
  var HUMAN_MESSAGES = {
@@ -5423,27 +4675,27 @@ var integration = {
5423
4675
  };
5424
4676
 
5425
4677
  // src/client/voice/useVoiceAgent.ts
5426
- import { useCallback as useCallback25, useEffect as useEffect19, useRef as useRef16, useState as useState16 } from "react";
4678
+ import { useCallback as useCallback20, useEffect as useEffect17, useRef as useRef13, useState as useState14 } from "react";
5427
4679
  var OPENAI_REALTIME_BASE = "https://api.openai.com/v1";
5428
4680
  var ZERO_USAGE = { inputAudioTokens: 0, outputAudioTokens: 0, inputTextTokens: 0, outputTextTokens: 0 };
5429
4681
  function useVoiceAgent(options = {}) {
5430
- const [status, setStatus] = useState16("idle");
5431
- const [isMuted, setIsMuted] = useState16(false);
5432
- const [isAgentSpeaking, setIsAgentSpeaking] = useState16(false);
5433
- const [transcript, setTranscript] = useState16([]);
5434
- const [error, setError] = useState16(null);
5435
- const pcRef = useRef16(null);
5436
- const dcRef = useRef16(null);
5437
- const streamRef = useRef16(null);
5438
- const audioRef = useRef16(null);
5439
- const timerRef = useRef16(null);
5440
- const sessionIdRef = useRef16(null);
5441
- const liveStartRef = useRef16(null);
5442
- const settledRef = useRef16(false);
5443
- const usageRef = useRef16({ ...ZERO_USAGE });
5444
- const optsRef = useRef16(options);
4682
+ const [status, setStatus] = useState14("idle");
4683
+ const [isMuted, setIsMuted] = useState14(false);
4684
+ const [isAgentSpeaking, setIsAgentSpeaking] = useState14(false);
4685
+ const [transcript, setTranscript] = useState14([]);
4686
+ const [error, setError] = useState14(null);
4687
+ const pcRef = useRef13(null);
4688
+ const dcRef = useRef13(null);
4689
+ const streamRef = useRef13(null);
4690
+ const audioRef = useRef13(null);
4691
+ const timerRef = useRef13(null);
4692
+ const sessionIdRef = useRef13(null);
4693
+ const liveStartRef = useRef13(null);
4694
+ const settledRef = useRef13(false);
4695
+ const usageRef = useRef13({ ...ZERO_USAGE });
4696
+ const optsRef = useRef13(options);
5445
4697
  optsRef.current = options;
5446
- const settle = useCallback25(async () => {
4698
+ const settle = useCallback20(async () => {
5447
4699
  const sessionId = sessionIdRef.current;
5448
4700
  if (!sessionId || settledRef.current) return;
5449
4701
  settledRef.current = true;
@@ -5457,7 +4709,7 @@ function useVoiceAgent(options = {}) {
5457
4709
  } catch {
5458
4710
  }
5459
4711
  }, []);
5460
- const cleanup = useCallback25(() => {
4712
+ const cleanup = useCallback20(() => {
5461
4713
  if (timerRef.current) {
5462
4714
  clearTimeout(timerRef.current);
5463
4715
  timerRef.current = null;
@@ -5481,13 +4733,13 @@ function useVoiceAgent(options = {}) {
5481
4733
  streamRef.current = null;
5482
4734
  audioRef.current = null;
5483
4735
  }, []);
5484
- const stop = useCallback25(async () => {
4736
+ const stop = useCallback20(async () => {
5485
4737
  cleanup();
5486
4738
  await settle();
5487
4739
  setIsAgentSpeaking(false);
5488
4740
  setStatus((s) => s === "error" ? s : "ended");
5489
4741
  }, [cleanup, settle]);
5490
- const appendTranscript = useCallback25((role, delta) => {
4742
+ const appendTranscript = useCallback20((role, delta) => {
5491
4743
  if (!delta) return;
5492
4744
  setTranscript((prev) => {
5493
4745
  const last = prev[prev.length - 1];
@@ -5495,7 +4747,7 @@ function useVoiceAgent(options = {}) {
5495
4747
  return [...prev, { role, content: delta }];
5496
4748
  });
5497
4749
  }, []);
5498
- const handleToolCall = useCallback25(async (item) => {
4750
+ const handleToolCall = useCallback20(async (item) => {
5499
4751
  const onToolCall = optsRef.current.onToolCall;
5500
4752
  let output = null;
5501
4753
  if (onToolCall && item.name) {
@@ -5521,7 +4773,7 @@ function useVoiceAgent(options = {}) {
5521
4773
  );
5522
4774
  dc.send(JSON.stringify({ type: "response.create" }));
5523
4775
  }, []);
5524
- const handleEvent = useCallback25(
4776
+ const handleEvent = useCallback20(
5525
4777
  (raw) => {
5526
4778
  if (typeof raw !== "string") return;
5527
4779
  let ev;
@@ -5561,7 +4813,7 @@ function useVoiceAgent(options = {}) {
5561
4813
  },
5562
4814
  [appendTranscript, handleToolCall]
5563
4815
  );
5564
- const start = useCallback25(
4816
+ const start = useCallback20(
5565
4817
  async (overrides = {}) => {
5566
4818
  if (sessionIdRef.current) {
5567
4819
  cleanup();
@@ -5623,7 +4875,7 @@ function useVoiceAgent(options = {}) {
5623
4875
  },
5624
4876
  [cleanup, settle, stop, handleEvent]
5625
4877
  );
5626
- const toggleMute = useCallback25(() => {
4878
+ const toggleMute = useCallback20(() => {
5627
4879
  const stream = streamRef.current;
5628
4880
  if (!stream) return;
5629
4881
  setIsMuted((muted) => {
@@ -5632,7 +4884,7 @@ function useVoiceAgent(options = {}) {
5632
4884
  return next;
5633
4885
  });
5634
4886
  }, []);
5635
- useEffect19(() => {
4887
+ useEffect17(() => {
5636
4888
  return () => {
5637
4889
  cleanup();
5638
4890
  void settle();
@@ -5720,7 +4972,7 @@ function decodeAiStreamChunk(chunk) {
5720
4972
  }
5721
4973
 
5722
4974
  // src/client/status.ts
5723
- import { useCallback as useCallback26, useEffect as useEffect20, useMemo as useMemo16, useRef as useRef17, useState as useState17 } from "react";
4975
+ import { useCallback as useCallback21, useEffect as useEffect18, useMemo as useMemo13, useRef as useRef14, useState as useState15 } from "react";
5724
4976
 
5725
4977
  // src/client/status-core.ts
5726
4978
  var ASYNC_RESOURCE_DEFAULTS = {
@@ -5804,7 +5056,7 @@ function useAsyncResource(fetcher, deps, options = {}) {
5804
5056
  const retry = options.retry ?? ASYNC_RESOURCE_DEFAULTS.retry;
5805
5057
  const retryDelayMs = options.retryDelayMs ?? ASYNC_RESOURCE_DEFAULTS.retryDelayMs;
5806
5058
  const slowAfterMs = options.slowAfterMs ?? ASYNC_RESOURCE_DEFAULTS.slowAfterMs;
5807
- const [state, setState] = useState17(() => ({
5059
+ const [state, setState] = useState15(() => ({
5808
5060
  status: enabled ? "loading" : "idle",
5809
5061
  data: options.initialData ?? null,
5810
5062
  error: null,
@@ -5812,12 +5064,12 @@ function useAsyncResource(fetcher, deps, options = {}) {
5812
5064
  isSlow: false,
5813
5065
  retryCount: 0
5814
5066
  }));
5815
- const requestIdRef = useRef17(0);
5816
- const [reloadTick, setReloadTick] = useState17(0);
5817
- const reload = useCallback26(() => {
5067
+ const requestIdRef = useRef14(0);
5068
+ const [reloadTick, setReloadTick] = useState15(0);
5069
+ const reload = useCallback21(() => {
5818
5070
  setReloadTick((tick) => tick + 1);
5819
5071
  }, []);
5820
- useEffect20(() => {
5072
+ useEffect18(() => {
5821
5073
  if (!enabled) {
5822
5074
  setState((prev) => ({ ...prev, status: "idle", isRefreshing: false, isSlow: false, retryCount: 0 }));
5823
5075
  return;
@@ -5894,7 +5146,7 @@ function useAsyncResource(fetcher, deps, options = {}) {
5894
5146
  controller.abort();
5895
5147
  };
5896
5148
  }, [enabled, keepPreviousData, retry, retryDelayMs, slowAfterMs, reloadTick, ...deps]);
5897
- return useMemo16(() => ({ ...state, reload }), [state, reload]);
5149
+ return useMemo13(() => ({ ...state, reload }), [state, reload]);
5898
5150
  }
5899
5151
  function usePagedResource(fetchPage, deps, options = {}) {
5900
5152
  const enabled = options.enabled ?? true;
@@ -5906,7 +5158,7 @@ function usePagedResource(fetchPage, deps, options = {}) {
5906
5158
  const retryDelayMs = options.retryDelayMs ?? ASYNC_RESOURCE_DEFAULTS.retryDelayMs;
5907
5159
  const maxRetryDelayMs = options.maxRetryDelayMs ?? 3e4;
5908
5160
  const hasInitialItems = initialItems.length > 0;
5909
- const [state, setState] = useState17(() => ({
5161
+ const [state, setState] = useState15(() => ({
5910
5162
  status: enabled ? hasInitialItems ? "ready" : "loading" : "idle",
5911
5163
  items: initialItems,
5912
5164
  error: null,
@@ -5916,25 +5168,25 @@ function usePagedResource(fetchPage, deps, options = {}) {
5916
5168
  isLoadingMore: false,
5917
5169
  isRefreshing: false
5918
5170
  }));
5919
- const requestIdRef = useRef17(0);
5920
- const controllerRef = useRef17(null);
5921
- const loadingRef = useRef17(false);
5922
- const nextPageRef = useRef17(hasInitialItems ? 2 : 1);
5923
- const failedPageRef = useRef17(null);
5924
- const failureCountRef = useRef17(0);
5925
- const cooldownUntilRef = useRef17(0);
5926
- const autoRetryTimerRef = useRef17(null);
5927
- const clearAutoRetryTimer = useCallback26(() => {
5171
+ const requestIdRef = useRef14(0);
5172
+ const controllerRef = useRef14(null);
5173
+ const loadingRef = useRef14(false);
5174
+ const nextPageRef = useRef14(hasInitialItems ? 2 : 1);
5175
+ const failedPageRef = useRef14(null);
5176
+ const failureCountRef = useRef14(0);
5177
+ const cooldownUntilRef = useRef14(0);
5178
+ const autoRetryTimerRef = useRef14(null);
5179
+ const clearAutoRetryTimer = useCallback21(() => {
5928
5180
  if (autoRetryTimerRef.current) {
5929
5181
  clearTimeout(autoRetryTimerRef.current);
5930
5182
  autoRetryTimerRef.current = null;
5931
5183
  }
5932
5184
  }, []);
5933
- const resetCooldown = useCallback26(() => {
5185
+ const resetCooldown = useCallback21(() => {
5934
5186
  failureCountRef.current = 0;
5935
5187
  cooldownUntilRef.current = 0;
5936
5188
  }, []);
5937
- const setFailureCooldown = useCallback26(() => {
5189
+ const setFailureCooldown = useCallback21(() => {
5938
5190
  failureCountRef.current += 1;
5939
5191
  const delay = getPagedResourceCooldownMs({
5940
5192
  failureCount: failureCountRef.current,
@@ -5944,7 +5196,7 @@ function usePagedResource(fetchPage, deps, options = {}) {
5944
5196
  cooldownUntilRef.current = Date.now() + delay;
5945
5197
  return delay;
5946
5198
  }, [maxRetryDelayMs, retryDelayMs]);
5947
- const startLoad = useCallback26(async (page, mode) => {
5199
+ const startLoad = useCallback21(async (page, mode) => {
5948
5200
  if (!enabled || loadingRef.current) return;
5949
5201
  if (mode === "auto" && !canAutoLoadPagedResource({
5950
5202
  hasMore: true,
@@ -6024,21 +5276,21 @@ function usePagedResource(fetchPage, deps, options = {}) {
6024
5276
  }
6025
5277
  }
6026
5278
  }, [autoRetryOnError, clearAutoRetryTimer, enabled, fetchPage, keepPreviousData, maxItemsPerPage, pageSize, resetCooldown, setFailureCooldown]);
6027
- const loadMore = useCallback26(() => {
5279
+ const loadMore = useCallback21(() => {
6028
5280
  if (!state.hasMore || state.isLoadingInitial || state.isLoadingMore || state.isRefreshing) return;
6029
5281
  void startLoad(nextPageRef.current, "auto");
6030
5282
  }, [startLoad, state.hasMore, state.isLoadingInitial, state.isLoadingMore, state.isRefreshing]);
6031
- const retry = useCallback26(() => {
5283
+ const retry = useCallback21(() => {
6032
5284
  const page = failedPageRef.current ?? nextPageRef.current;
6033
5285
  void startLoad(page, "manual");
6034
5286
  }, [startLoad]);
6035
- const refresh = useCallback26(() => {
5287
+ const refresh = useCallback21(() => {
6036
5288
  failedPageRef.current = null;
6037
5289
  resetCooldown();
6038
5290
  nextPageRef.current = 1;
6039
5291
  void startLoad(1, "refresh");
6040
5292
  }, [resetCooldown, startLoad]);
6041
- useEffect20(() => {
5293
+ useEffect18(() => {
6042
5294
  requestIdRef.current += 1;
6043
5295
  controllerRef.current?.abort();
6044
5296
  clearAutoRetryTimer();
@@ -6066,7 +5318,7 @@ function usePagedResource(fetchPage, deps, options = {}) {
6066
5318
  loadingRef.current = false;
6067
5319
  };
6068
5320
  }, [enabled, pageSize, maxItemsPerPage, keepPreviousData, autoRetryOnError, retryDelayMs, maxRetryDelayMs, ...deps]);
6069
- return useMemo16(() => ({
5321
+ return useMemo13(() => ({
6070
5322
  ...state,
6071
5323
  loadMore,
6072
5324
  retry,
@@ -6075,7 +5327,7 @@ function usePagedResource(fetchPage, deps, options = {}) {
6075
5327
  }
6076
5328
 
6077
5329
  // src/client/subscriptions/useSubscription.ts
6078
- import { useCallback as useCallback27, useEffect as useEffect21, useState as useState18 } from "react";
5330
+ import { useCallback as useCallback22, useEffect as useEffect19, useState as useState16 } from "react";
6079
5331
 
6080
5332
  // src/client/authed-json.ts
6081
5333
  async function authedJson(path, init) {
@@ -6108,7 +5360,7 @@ function isEntitled(tier, status) {
6108
5360
 
6109
5361
  // src/client/subscriptions/useSubscription.ts
6110
5362
  function useSubscription() {
6111
- const [state, setState] = useState18({
5363
+ const [state, setState] = useState16({
6112
5364
  tier: "free",
6113
5365
  status: "none",
6114
5366
  interval: null,
@@ -6117,10 +5369,10 @@ function useSubscription() {
6117
5369
  trialEndsAt: null,
6118
5370
  plans: []
6119
5371
  });
6120
- const [isLoading, setLoading] = useState18(true);
6121
- const [error, setError] = useState18(null);
6122
- const [errorCode, setErrorCode] = useState18(null);
6123
- const refresh = useCallback27(async () => {
5372
+ const [isLoading, setLoading] = useState16(true);
5373
+ const [error, setError] = useState16(null);
5374
+ const [errorCode, setErrorCode] = useState16(null);
5375
+ const refresh = useCallback22(async () => {
6124
5376
  setLoading(true);
6125
5377
  try {
6126
5378
  const r = await authedJson("/_deepspace/subscriptions/me");
@@ -6142,15 +5394,15 @@ function useSubscription() {
6142
5394
  setLoading(false);
6143
5395
  }
6144
5396
  }, []);
6145
- useEffect21(() => {
5397
+ useEffect19(() => {
6146
5398
  refresh();
6147
5399
  }, [refresh]);
6148
5400
  const entitled = isEntitled(state.tier, state.status);
6149
- const hasTier = useCallback27(
5401
+ const hasTier = useCallback22(
6150
5402
  (slug) => state.tier === slug && isEntitled(state.tier, state.status),
6151
5403
  [state.tier, state.status]
6152
5404
  );
6153
- const isAtLeast = useCallback27(
5405
+ const isAtLeast = useCallback22(
6154
5406
  (slug) => {
6155
5407
  if (!isEntitled(state.tier, state.status)) return false;
6156
5408
  const targetRank = state.plans.find((p) => p.slug === slug)?.rank;
@@ -6160,7 +5412,7 @@ function useSubscription() {
6160
5412
  },
6161
5413
  [state.plans, state.tier, state.status]
6162
5414
  );
6163
- const subscribe = useCallback27(
5415
+ const subscribe = useCallback22(
6164
5416
  async (planSlug, opts) => {
6165
5417
  const result = await authedJson("/_deepspace/subscriptions/checkout", {
6166
5418
  method: "POST",
@@ -6180,7 +5432,7 @@ function useSubscription() {
6180
5432
  },
6181
5433
  [refresh]
6182
5434
  );
6183
- const openPortal = useCallback27(
5435
+ const openPortal = useCallback22(
6184
5436
  async (returnUrl) => {
6185
5437
  return authedJson("/_deepspace/subscriptions/portal", {
6186
5438
  method: "POST",
@@ -6210,10 +5462,10 @@ function useSubscription() {
6210
5462
  }
6211
5463
 
6212
5464
  // src/client/subscriptions/PricingTable.tsx
6213
- import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
5465
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
6214
5466
  function PricingTable(props) {
6215
5467
  const interval = props.interval ?? "month";
6216
- return /* @__PURE__ */ jsx10("div", { className: "grid gap-4 md:grid-cols-3", children: props.plans.map((plan) => {
5468
+ return /* @__PURE__ */ jsx9("div", { className: "grid gap-4 md:grid-cols-3", children: props.plans.map((plan) => {
6217
5469
  const price = plan.prices.find((p) => p.interval === interval);
6218
5470
  const selected = props.currentTier === plan.slug;
6219
5471
  const isTrueFree = plan.prices.length === 0;
@@ -6225,17 +5477,17 @@ function PricingTable(props) {
6225
5477
  const disabled = selected || intervalUnavailable;
6226
5478
  return /* @__PURE__ */ jsxs6("section", { className: "rounded-lg border border-border p-5", children: [
6227
5479
  /* @__PURE__ */ jsxs6("div", { className: "space-y-1", children: [
6228
- /* @__PURE__ */ jsx10("h3", { className: "text-lg font-semibold", children: plan.name }),
5480
+ /* @__PURE__ */ jsx9("h3", { className: "text-lg font-semibold", children: plan.name }),
6229
5481
  /* @__PURE__ */ jsxs6("p", { className: "text-3xl font-semibold", children: [
6230
5482
  priceLabel,
6231
- /* @__PURE__ */ jsx10("span", { className: "text-sm font-normal text-muted-foreground", children: price ? `/${interval}` : "" })
5483
+ /* @__PURE__ */ jsx9("span", { className: "text-sm font-normal text-muted-foreground", children: price ? `/${interval}` : "" })
6232
5484
  ] }),
6233
5485
  plan.trialDays ? /* @__PURE__ */ jsxs6("p", { className: "text-xs text-muted-foreground", children: [
6234
5486
  plan.trialDays,
6235
5487
  "-day free trial"
6236
5488
  ] }) : null
6237
5489
  ] }),
6238
- /* @__PURE__ */ jsx10(
5490
+ /* @__PURE__ */ jsx9(
6239
5491
  "button",
6240
5492
  {
6241
5493
  type: "button",
@@ -6250,13 +5502,13 @@ function PricingTable(props) {
6250
5502
  }
6251
5503
 
6252
5504
  // src/client/charges/useCheckout.ts
6253
- import { useCallback as useCallback28, useEffect as useEffect22, useMemo as useMemo17, useState as useState19 } from "react";
5505
+ import { useCallback as useCallback23, useEffect as useEffect20, useMemo as useMemo14, useState as useState17 } from "react";
6254
5506
  function useCheckout(opts) {
6255
- const [purchases, setPurchases] = useState19([]);
6256
- const [isLoading, setLoading] = useState19(true);
6257
- const [error, setError] = useState19(null);
6258
- const [errorCode, setErrorCode] = useState19(null);
6259
- const refresh = useCallback28(async () => {
5507
+ const [purchases, setPurchases] = useState17([]);
5508
+ const [isLoading, setLoading] = useState17(true);
5509
+ const [error, setError] = useState17(null);
5510
+ const [errorCode, setErrorCode] = useState17(null);
5511
+ const refresh = useCallback23(async () => {
6260
5512
  setLoading(true);
6261
5513
  try {
6262
5514
  const r = await authedJson(
@@ -6272,10 +5524,10 @@ function useCheckout(opts) {
6272
5524
  setLoading(false);
6273
5525
  }
6274
5526
  }, []);
6275
- useEffect22(() => {
5527
+ useEffect20(() => {
6276
5528
  refresh();
6277
5529
  }, [refresh]);
6278
- const chargeOnce = useCallback28(
5530
+ const chargeOnce = useCallback23(
6279
5531
  async (chargeOpts) => {
6280
5532
  setError(null);
6281
5533
  setErrorCode(null);
@@ -6311,11 +5563,11 @@ function useCheckout(opts) {
6311
5563
  },
6312
5564
  []
6313
5565
  );
6314
- const ownsProduct = useCallback28(
5566
+ const ownsProduct = useCallback23(
6315
5567
  (productId) => purchases.some((p) => p.productId === productId),
6316
5568
  [purchases]
6317
5569
  );
6318
- const owned = useMemo17(
5570
+ const owned = useMemo14(
6319
5571
  () => !!opts?.productId && purchases.some((p) => p.productId === opts.productId),
6320
5572
  [opts?.productId, purchases]
6321
5573
  );
@@ -6505,8 +5757,6 @@ export {
6505
5757
  MSG_YJS_AWARENESS,
6506
5758
  MSG_YJS_SYNC,
6507
5759
  PlatformApiError,
6508
- PlatformContext,
6509
- PlatformProvider,
6510
5760
  PricingTable,
6511
5761
  RECORD_NOT_FOUND,
6512
5762
  ROLES,
@@ -6543,21 +5793,15 @@ export {
6543
5793
  encodeUpdate,
6544
5794
  formatBytes,
6545
5795
  formatFileSize,
6546
- formatFullTimestamp,
6547
- formatMessageTime,
6548
5796
  getApiUrl,
6549
5797
  getAuthToken,
6550
5798
  getAuthUrl,
6551
- getConversationDisplayName,
6552
- getConversationParticipantIds,
6553
5799
  getDeepSpaceAIModel,
6554
5800
  getEnvironmentConfig,
6555
5801
  getMessageType,
6556
5802
  getPagedResourceCooldownMs,
6557
5803
  getPlatformWorkerUrl,
6558
- getThreadCounts,
6559
5804
  getUserColor,
6560
- groupReactionsForMessage,
6561
5805
  handleAwarenessMessage,
6562
5806
  handleSyncMessage,
6563
5807
  hasContent,
@@ -6565,13 +5809,12 @@ export {
6565
5809
  integration,
6566
5810
  isAnonymousUserId,
6567
5811
  isAsyncResourceSlow,
6568
- isDMConversation,
6569
5812
  isDarkColor,
6570
5813
  isImageFile,
6571
5814
  isLocalDev,
6572
5815
  isProduction,
5816
+ isWriterRole,
6573
5817
  listDeepSpaceAgentModels,
6574
- parseMessageMetadata,
6575
5818
  parseSseLine,
6576
5819
  readThemeFromDOM,
6577
5820
  readVarUint,
@@ -6580,7 +5823,6 @@ export {
6580
5823
  resetEnvironmentCache,
6581
5824
  resolveDeepSpaceAgentModel,
6582
5825
  serverBuild,
6583
- shouldGroupMessages,
6584
5826
  signIn,
6585
5827
  signOut,
6586
5828
  storageLimitForTier,
@@ -6595,20 +5837,13 @@ export {
6595
5837
  useChannelMembers,
6596
5838
  useChannels,
6597
5839
  useCheckout,
6598
- useCommunities,
6599
- useConversation,
6600
- useConversations,
6601
5840
  useCronMonitor,
6602
5841
  useDisplayName,
6603
- useInbox,
6604
5842
  useIsDarkTheme,
6605
5843
  useJobs,
6606
5844
  useMessages,
6607
5845
  useMutations,
6608
5846
  usePagedResource,
6609
- usePlatform,
6610
- usePlatformWS,
6611
- usePosts,
6612
5847
  usePresence,
6613
5848
  usePresenceRoom,
6614
5849
  useQuery,