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.
- package/CHANGELOG.md +35 -0
- package/dist/{chunk-LPXWXF6R.js → chunk-YBXIUDZJ.js} +2 -2
- package/dist/{chunk-LPXWXF6R.js.map → chunk-YBXIUDZJ.js.map} +1 -1
- package/dist/cli.js +80 -45
- package/dist/cli.js.map +1 -1
- package/dist/documentation-client-core.js +1 -1
- package/dist/documentation-default-renderer.cjs +1 -1
- package/dist/documentation-react.js +1 -1
- package/dist/documentation-runtime.js +1 -1
- package/dist/documentation-server-core.js +1 -1
- package/dist/documentation.js +1 -1
- package/dist/documentation.js.map +1 -1
- package/dist/index.d.ts +26 -434
- package/dist/index.js +99 -864
- package/dist/index.js.map +1 -1
- package/dist/schema.d.ts +4 -41
- package/dist/schema.js +2 -242
- package/dist/schema.js.map +1 -1
- package/dist/server.d.ts +6 -162
- package/dist/server.js +13 -281
- package/dist/server.js.map +1 -1
- package/dist/worker.d.ts +4 -160
- package/dist/worker.js +15 -281
- package/dist/worker.js.map +1 -1
- package/features/messaging/feature.json +3 -43
- package/features/messaging/src/ChatPage.tsx +12 -16
- package/features/messaging/src/components/chat/ChatHeader.tsx +5 -13
- package/features/messaging/src/components/chat/MessageItem.tsx +7 -9
- package/features/messaging/src/components/chat/MessageList.tsx +57 -40
- package/features/messaging/src/components/chat/ThreadPanel.tsx +25 -11
- package/features/messaging/src/components/chat/UserProfilePopover.tsx +10 -29
- package/features/messaging/src/hooks/useChatChannel.ts +18 -23
- package/features/messaging/src/messaging-schema.ts +0 -2
- package/features/search-bar/feature.json +9 -20
- package/features/search-bar/src/InlineSearch.tsx +101 -0
- package/features/search-bar/src/__tests__/search-model.test.tsx +38 -0
- package/features/search-bar/src/search-model.ts +2 -149
- package/package.json +1 -1
- package/features/messaging/src/ChatMultiPage.tsx +0 -298
- package/features/messaging/src/components/chat-multi/AddMemberModal.tsx +0 -188
- package/features/messaging/src/components/chat-multi/BrowseGroupsModal.tsx +0 -163
- package/features/messaging/src/components/chat-multi/ChannelListItem.tsx +0 -147
- package/features/messaging/src/components/chat-multi/ChannelSettingsPanel.tsx +0 -344
- package/features/messaging/src/components/chat-multi/ChannelSidebar.tsx +0 -460
- package/features/messaging/src/components/chat-multi/CreateGroupModal.tsx +0 -190
- package/features/messaging/src/components/chat-multi/InvitationList.tsx +0 -149
- package/features/messaging/src/components/chat-multi/NewMessageModal.tsx +0 -159
- package/features/messaging/src/hooks/useMultiChannel.ts +0 -142
- package/features/search-bar/src/SearchOverlay.tsx +0 -566
- package/features/search-bar/src/__tests__/search-model.test.ts +0 -40
- package/features/sidebar/feature.json +0 -19
- 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:
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
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)
|
|
4123
|
-
}, [channelId, user, records,
|
|
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
|
|
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] =
|
|
5431
|
-
const [isMuted, setIsMuted] =
|
|
5432
|
-
const [isAgentSpeaking, setIsAgentSpeaking] =
|
|
5433
|
-
const [transcript, setTranscript] =
|
|
5434
|
-
const [error, setError] =
|
|
5435
|
-
const pcRef =
|
|
5436
|
-
const dcRef =
|
|
5437
|
-
const streamRef =
|
|
5438
|
-
const audioRef =
|
|
5439
|
-
const timerRef =
|
|
5440
|
-
const sessionIdRef =
|
|
5441
|
-
const liveStartRef =
|
|
5442
|
-
const settledRef =
|
|
5443
|
-
const usageRef =
|
|
5444
|
-
const optsRef =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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] =
|
|
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 =
|
|
5816
|
-
const [reloadTick, setReloadTick] =
|
|
5817
|
-
const reload =
|
|
5067
|
+
const requestIdRef = useRef14(0);
|
|
5068
|
+
const [reloadTick, setReloadTick] = useState15(0);
|
|
5069
|
+
const reload = useCallback21(() => {
|
|
5818
5070
|
setReloadTick((tick) => tick + 1);
|
|
5819
5071
|
}, []);
|
|
5820
|
-
|
|
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
|
|
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] =
|
|
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 =
|
|
5920
|
-
const controllerRef =
|
|
5921
|
-
const loadingRef =
|
|
5922
|
-
const nextPageRef =
|
|
5923
|
-
const failedPageRef =
|
|
5924
|
-
const failureCountRef =
|
|
5925
|
-
const cooldownUntilRef =
|
|
5926
|
-
const autoRetryTimerRef =
|
|
5927
|
-
const clearAutoRetryTimer =
|
|
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 =
|
|
5185
|
+
const resetCooldown = useCallback21(() => {
|
|
5934
5186
|
failureCountRef.current = 0;
|
|
5935
5187
|
cooldownUntilRef.current = 0;
|
|
5936
5188
|
}, []);
|
|
5937
|
-
const setFailureCooldown =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
5283
|
+
const retry = useCallback21(() => {
|
|
6032
5284
|
const page = failedPageRef.current ?? nextPageRef.current;
|
|
6033
5285
|
void startLoad(page, "manual");
|
|
6034
5286
|
}, [startLoad]);
|
|
6035
|
-
const refresh =
|
|
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
|
-
|
|
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
|
|
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
|
|
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] =
|
|
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] =
|
|
6121
|
-
const [error, setError] =
|
|
6122
|
-
const [errorCode, setErrorCode] =
|
|
6123
|
-
const refresh =
|
|
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
|
-
|
|
5397
|
+
useEffect19(() => {
|
|
6146
5398
|
refresh();
|
|
6147
5399
|
}, [refresh]);
|
|
6148
5400
|
const entitled = isEntitled(state.tier, state.status);
|
|
6149
|
-
const hasTier =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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] =
|
|
6256
|
-
const [isLoading, setLoading] =
|
|
6257
|
-
const [error, setError] =
|
|
6258
|
-
const [errorCode, setErrorCode] =
|
|
6259
|
-
const refresh =
|
|
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
|
-
|
|
5527
|
+
useEffect20(() => {
|
|
6276
5528
|
refresh();
|
|
6277
5529
|
}, [refresh]);
|
|
6278
|
-
const chargeOnce =
|
|
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 =
|
|
5566
|
+
const ownsProduct = useCallback23(
|
|
6315
5567
|
(productId) => purchases.some((p) => p.productId === productId),
|
|
6316
5568
|
[purchases]
|
|
6317
5569
|
);
|
|
6318
|
-
const owned =
|
|
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,
|