deepspace 0.3.10 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +331 -115
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +199 -16
- package/dist/index.js +354 -166
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +242 -73
- package/dist/server.js +985 -374
- package/dist/server.js.map +1 -1
- package/dist/worker.d.ts +322 -73
- package/dist/worker.js +961 -343
- package/dist/worker.js.map +1 -1
- package/features/admin-page/feature.json +29 -0
- package/features/admin-page/src/AdminPage.tsx +292 -0
- package/features/admin-page/src/admin-schema.ts +20 -0
- package/features/ai-chat/feature.json +41 -0
- package/features/ai-chat/src/AiChatPage.tsx +692 -0
- package/features/ai-chat/src/ChatPanel.tsx +1098 -0
- package/features/ai-chat/src/ai-chat-schema.ts +11 -0
- package/features/canvas/feature.json +45 -0
- package/features/canvas/src/CanvasEditorPage.tsx +87 -0
- package/features/canvas/src/CanvasListPage.tsx +202 -0
- package/features/canvas/src/canvas-schema.ts +33 -0
- package/features/canvas/src/components/CanvasToolbar.tsx +170 -0
- package/features/canvas/src/components/CanvasView.tsx +369 -0
- package/features/canvas/src/components/ShapeRenderer.tsx +114 -0
- package/features/cron/feature.json +33 -0
- package/features/cron/src/CronLogPage.tsx +100 -0
- package/features/cron/src/cron.ts +25 -0
- package/features/docs/feature.json +96 -0
- package/features/docs/src/DocsEditorPage.tsx +1012 -0
- package/features/docs/src/DocsListPage.tsx +951 -0
- package/features/docs/src/DocsOutlinePanel.tsx +68 -0
- package/features/docs/src/DocsPresence.tsx +138 -0
- package/features/docs/src/InviteDialog.tsx +336 -0
- package/features/docs/src/LibrarySidebar.tsx +464 -0
- package/features/docs/src/docs-favorites.ts +18 -0
- package/features/docs/src/docs-library-types.ts +15 -0
- package/features/docs/src/docs-schema.ts +80 -0
- package/features/docs/src/docs-ui.css +309 -0
- package/features/docs/src/editor/DocEditorSurface.tsx +257 -0
- package/features/docs/src/editor/DocsTiptapToolbar.tsx +560 -0
- package/features/docs/src/editor/useDocEditor.ts +206 -0
- package/features/docs/src/use-yjs-room-with-awareness.ts +285 -0
- package/features/file-attachments/feature.json +42 -0
- package/features/file-attachments/src/AttachmentsPage.tsx +864 -0
- package/features/file-attachments/src/attachments-constants.ts +9 -0
- package/features/file-attachments/src/attachments-schema.ts +45 -0
- package/features/file-attachments/src/useFilePreview.ts +471 -0
- package/features/file-attachments/src/useMimeTypeDetection.ts +138 -0
- package/features/file-manager/feature.json +24 -0
- package/features/file-manager/src/FileManagerPage.tsx +330 -0
- package/features/integration-test/feature.json +18 -0
- package/features/integration-test/src/IntegrationTestPage.tsx +423 -0
- package/features/integration-test/src/integration.spec.ts +42 -0
- package/features/items/feature.json +33 -0
- package/features/items/src/ItemsPage.tsx +325 -0
- package/features/items/src/items-constants.ts +10 -0
- package/features/items/src/items-schema.ts +27 -0
- package/features/kanban/feature.json +18 -0
- package/features/kanban/src/Kanban.tsx +283 -0
- package/features/landing/feature.json +62 -0
- package/features/landing/src/LandingPage.tsx +627 -0
- package/features/landing/src/primitives.tsx +389 -0
- package/features/landing/src/sections/FAQSection.tsx +110 -0
- package/features/landing/src/sections/FeaturesGridSection.tsx +311 -0
- package/features/landing/src/sections/HowItWorksSection.tsx +62 -0
- package/features/landing/src/sections/LogoCloudSection.tsx +58 -0
- package/features/landing/src/sections/ShowcaseSection.tsx +63 -0
- package/features/landing/src/sections/StatsSection.tsx +31 -0
- package/features/landing/src/sections/TeamSection.tsx +86 -0
- package/features/landing/src/sections/TestimonialsSection.tsx +68 -0
- package/features/landing/src/sections/VideoSection.tsx +71 -0
- package/features/leaderboard/feature.json +33 -0
- package/features/leaderboard/src/LeaderboardPage.tsx +372 -0
- package/features/leaderboard/src/leaderboard-constants.ts +21 -0
- package/features/leaderboard/src/leaderboard-schema.ts +36 -0
- package/features/messaging/feature.json +111 -0
- package/features/messaging/src/ChatMultiPage.tsx +300 -0
- package/features/messaging/src/ChatPage.tsx +75 -0
- package/features/messaging/src/components/chat/ChatHeader.tsx +76 -0
- package/features/messaging/src/components/chat/MessageActionSheet.tsx +168 -0
- package/features/messaging/src/components/chat/MessageInput.tsx +65 -0
- package/features/messaging/src/components/chat/MessageItem.tsx +352 -0
- package/features/messaging/src/components/chat/MessageList.tsx +248 -0
- package/features/messaging/src/components/chat/ReactionPicker.tsx +2 -0
- package/features/messaging/src/components/chat/ThreadPanel.tsx +107 -0
- package/features/messaging/src/components/chat/UserProfilePopover.tsx +158 -0
- package/features/messaging/src/components/chat-multi/AddMemberModal.tsx +188 -0
- package/features/messaging/src/components/chat-multi/BrowseGroupsModal.tsx +163 -0
- package/features/messaging/src/components/chat-multi/ChannelListItem.tsx +147 -0
- package/features/messaging/src/components/chat-multi/ChannelSettingsPanel.tsx +344 -0
- package/features/messaging/src/components/chat-multi/ChannelSidebar.tsx +460 -0
- package/features/messaging/src/components/chat-multi/CreateGroupModal.tsx +190 -0
- package/features/messaging/src/components/chat-multi/InvitationList.tsx +149 -0
- package/features/messaging/src/components/chat-multi/NewMessageModal.tsx +159 -0
- package/features/messaging/src/hooks/useChatChannel.ts +64 -0
- package/features/messaging/src/hooks/useLongPress.ts +74 -0
- package/features/messaging/src/hooks/useMultiChannel.ts +142 -0
- package/features/messaging/src/messaging-schema.ts +25 -0
- package/features/presence-test/feature.json +21 -0
- package/features/presence-test/src/PresenceTestPage.tsx +120 -0
- package/features/sidebar/feature.json +19 -0
- package/features/sidebar/src/AppSidebar.tsx +558 -0
- package/features/tasks/feature.json +33 -0
- package/features/tasks/src/TasksPage.tsx +598 -0
- package/features/tasks/src/tasks-constants.ts +43 -0
- package/features/tasks/src/tasks-schema.ts +56 -0
- package/features/testing/feature.json +49 -0
- package/features/testing/src/TestPage.tsx +145 -0
- package/features/testing/src/cpu-burn-action.ts +51 -0
- package/features/testing/src/subrequest-burn-action.ts +53 -0
- package/features/testing/src/test-schema.ts +23 -0
- package/features/topbar/feature.json +18 -0
- package/features/topbar/src/Topbar.tsx +353 -0
- package/features/tree/feature.json +26 -0
- package/features/tree/src/TreeSidebar.tsx +607 -0
- package/features/tree/src/tree-constants.ts +68 -0
- package/features/tree/src/tree-hooks.ts +258 -0
- package/package.json +4 -2
- package/scripts/add-feature.cjs +654 -0
package/dist/index.js
CHANGED
|
@@ -407,6 +407,13 @@ var MSG = {
|
|
|
407
407
|
USER_LIST: "user.list",
|
|
408
408
|
SET_ROLE: "user.set_role",
|
|
409
409
|
USER_UPDATE: "user.update",
|
|
410
|
+
// ---- Auth signal -----------------------------------------------------
|
|
411
|
+
// Server → client one-shot on connect from rooms that enforce role-based
|
|
412
|
+
// writes (Canvas, Game, Cron). Tells the client whether this connection
|
|
413
|
+
// can write so its hook can disable local write APIs and the UI can
|
|
414
|
+
// render controls accordingly. Without this, a viewer's click would
|
|
415
|
+
// round-trip to the server and silently come back as ERROR.
|
|
416
|
+
AUTH: "auth",
|
|
410
417
|
// ---- Yjs JSON control frames (binary sync lives in ./yjs.ts) ---------
|
|
411
418
|
YJS_JOIN: "yjs.join",
|
|
412
419
|
YJS_LEAVE: "yjs.leave",
|
|
@@ -440,6 +447,14 @@ var MSG = {
|
|
|
440
447
|
CRON_PAUSE: "cron.pause",
|
|
441
448
|
CRON_RESUME: "cron.resume",
|
|
442
449
|
CRON_STATUS: "cron.status",
|
|
450
|
+
// ---- JobRoom ---------------------------------------------------------
|
|
451
|
+
// Background-job queue with durable, alarm-driven execution. See
|
|
452
|
+
// server/rooms/job-room.ts. Clients enqueue and subscribe to updates;
|
|
453
|
+
// the room broadcasts JOB_UPDATE for every status transition.
|
|
454
|
+
JOB_ENQUEUE: "job.enqueue",
|
|
455
|
+
JOB_CANCEL: "job.cancel",
|
|
456
|
+
JOB_RETRY: "job.retry",
|
|
457
|
+
JOB_UPDATE: "job.update",
|
|
443
458
|
// ---- PresenceRoom ----------------------------------------------------
|
|
444
459
|
PRESENCE_SYNC: "presence.sync",
|
|
445
460
|
PRESENCE_JOIN: "presence.join",
|
|
@@ -496,6 +511,13 @@ var clientBuild = {
|
|
|
496
511
|
cronTrigger: (taskName) => ({ type: MSG.CRON_TRIGGER, payload: { taskName } }),
|
|
497
512
|
cronPause: (taskName) => ({ type: MSG.CRON_PAUSE, payload: { taskName } }),
|
|
498
513
|
cronResume: (taskName) => ({ type: MSG.CRON_RESUME, payload: { taskName } }),
|
|
514
|
+
// Jobs
|
|
515
|
+
jobEnqueue: (requestId, type, payload, maxAttempts) => ({
|
|
516
|
+
type: MSG.JOB_ENQUEUE,
|
|
517
|
+
payload: { requestId, type, payload, maxAttempts }
|
|
518
|
+
}),
|
|
519
|
+
jobCancel: (jobId) => ({ type: MSG.JOB_CANCEL, payload: { jobId } }),
|
|
520
|
+
jobRetry: (jobId) => ({ type: MSG.JOB_RETRY, payload: { jobId } }),
|
|
499
521
|
// Presence
|
|
500
522
|
presenceUpdate: (state) => ({ type: MSG.PRESENCE_UPDATE, payload: state }),
|
|
501
523
|
// Gateway
|
|
@@ -550,6 +572,17 @@ var serverBuild = {
|
|
|
550
572
|
cronTasks: (tasks) => ({ type: MSG.CRON_TASKS, payload: { tasks } }),
|
|
551
573
|
cronHistory: (history) => ({ type: MSG.CRON_HISTORY, payload: { history } }),
|
|
552
574
|
cronStatus: (tasks, recentHistory) => ({ type: MSG.CRON_STATUS, payload: { tasks, recentHistory } }),
|
|
575
|
+
// Jobs
|
|
576
|
+
jobSnapshot: (jobs) => ({ type: MSG.JOB_UPDATE, payload: { kind: "snapshot", jobs } }),
|
|
577
|
+
jobEnqueued: (job, requestId) => ({
|
|
578
|
+
type: MSG.JOB_UPDATE,
|
|
579
|
+
payload: { kind: "enqueued", job, requestId }
|
|
580
|
+
}),
|
|
581
|
+
jobProgress: (job) => ({ type: MSG.JOB_UPDATE, payload: { kind: "progress", job } }),
|
|
582
|
+
jobSucceeded: (job) => ({ type: MSG.JOB_UPDATE, payload: { kind: "succeeded", job } }),
|
|
583
|
+
jobFailed: (job) => ({ type: MSG.JOB_UPDATE, payload: { kind: "failed", job } }),
|
|
584
|
+
jobCanceled: (job) => ({ type: MSG.JOB_UPDATE, payload: { kind: "canceled", job } }),
|
|
585
|
+
jobRetried: (job) => ({ type: MSG.JOB_UPDATE, payload: { kind: "retried", job } }),
|
|
553
586
|
// Presence
|
|
554
587
|
presenceSync: (peers) => ({ type: MSG.PRESENCE_SYNC, payload: { peers } }),
|
|
555
588
|
presenceJoin: (peer) => ({ type: MSG.PRESENCE_JOIN, payload: { peer } }),
|
|
@@ -691,12 +724,17 @@ function DeepSpaceAuthProvider({ children }) {
|
|
|
691
724
|
}
|
|
692
725
|
|
|
693
726
|
// src/client/auth/hooks.ts
|
|
727
|
+
var sessionHasResolved = false;
|
|
728
|
+
function stickyIsLoaded(isPending) {
|
|
729
|
+
if (!isPending) sessionHasResolved = true;
|
|
730
|
+
return sessionHasResolved;
|
|
731
|
+
}
|
|
694
732
|
function useAuth() {
|
|
695
733
|
const session = useSession();
|
|
696
734
|
const isSignedIn = !!session.data?.user;
|
|
697
735
|
const userId = session.data?.user?.id ?? null;
|
|
698
736
|
return {
|
|
699
|
-
isLoaded:
|
|
737
|
+
isLoaded: stickyIsLoaded(session.isPending),
|
|
700
738
|
isSignedIn,
|
|
701
739
|
userId,
|
|
702
740
|
sessionId: session.data?.session?.id ?? null
|
|
@@ -706,7 +744,7 @@ function useAuthUser() {
|
|
|
706
744
|
const session = useSession();
|
|
707
745
|
const user = session.data?.user ?? null;
|
|
708
746
|
return {
|
|
709
|
-
isLoaded:
|
|
747
|
+
isLoaded: stickyIsLoaded(session.isPending),
|
|
710
748
|
isSignedIn: !!user,
|
|
711
749
|
user: user ? {
|
|
712
750
|
id: user.id,
|
|
@@ -2822,6 +2860,7 @@ function useGameRoom(roomId) {
|
|
|
2822
2860
|
const [players, setPlayers] = useState8([]);
|
|
2823
2861
|
const [running, setRunning] = useState8(false);
|
|
2824
2862
|
const [connected, setConnected] = useState8(false);
|
|
2863
|
+
const [canWrite, setCanWrite] = useState8(false);
|
|
2825
2864
|
const wsRef = useRef9(null);
|
|
2826
2865
|
useEffect11(() => {
|
|
2827
2866
|
let ws = null;
|
|
@@ -2843,6 +2882,9 @@ function useGameRoom(roomId) {
|
|
|
2843
2882
|
};
|
|
2844
2883
|
ws.onmessage = (event) => {
|
|
2845
2884
|
dispatch(event.data, {
|
|
2885
|
+
[MSG.AUTH]: (p) => {
|
|
2886
|
+
setCanWrite(p.canWrite);
|
|
2887
|
+
},
|
|
2846
2888
|
[MSG.GAME_STATE]: (p) => {
|
|
2847
2889
|
setGameState(p.state);
|
|
2848
2890
|
setTick(p.tick);
|
|
@@ -2880,6 +2922,7 @@ function useGameRoom(roomId) {
|
|
|
2880
2922
|
wsLog("disconnected", `game:${roomId}`);
|
|
2881
2923
|
wsRef.current = null;
|
|
2882
2924
|
setConnected(false);
|
|
2925
|
+
setCanWrite(false);
|
|
2883
2926
|
if (alive) reconnectTimer = setTimeout(connect, 1e3);
|
|
2884
2927
|
};
|
|
2885
2928
|
ws.onerror = () => ws?.close();
|
|
@@ -2898,27 +2941,23 @@ function useGameRoom(roomId) {
|
|
|
2898
2941
|
wsRef.current = null;
|
|
2899
2942
|
};
|
|
2900
2943
|
}, [roomId]);
|
|
2901
|
-
const
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
const endGame = useCallback10(() =>
|
|
2917
|
-
|
|
2918
|
-
if (!ws || ws.readyState !== WebSocket.OPEN) return;
|
|
2919
|
-
ws.send(encode(clientBuild.gameEnd()));
|
|
2920
|
-
}, []);
|
|
2921
|
-
return { state: gameState, tick, players, running, connected, sendInput, setReady, startGame, endGame };
|
|
2944
|
+
const send = useCallback10(
|
|
2945
|
+
(message) => {
|
|
2946
|
+
if (!canWrite) return;
|
|
2947
|
+
const ws = wsRef.current;
|
|
2948
|
+
if (!ws || ws.readyState !== WebSocket.OPEN) return;
|
|
2949
|
+
ws.send(encode(message));
|
|
2950
|
+
},
|
|
2951
|
+
[canWrite]
|
|
2952
|
+
);
|
|
2953
|
+
const sendInput = useCallback10(
|
|
2954
|
+
(action, data = {}) => send(clientBuild.gameInput(action, data)),
|
|
2955
|
+
[send]
|
|
2956
|
+
);
|
|
2957
|
+
const setReady = useCallback10(() => send(clientBuild.gamePlayerReady()), [send]);
|
|
2958
|
+
const startGame = useCallback10(() => send(clientBuild.gameStart()), [send]);
|
|
2959
|
+
const endGame = useCallback10(() => send(clientBuild.gameEnd()), [send]);
|
|
2960
|
+
return { state: gameState, tick, players, running, connected, canWrite, sendInput, setReady, startGame, endGame };
|
|
2922
2961
|
}
|
|
2923
2962
|
|
|
2924
2963
|
// src/client/storage/hooks/useCanvas.ts
|
|
@@ -2927,6 +2966,7 @@ function useCanvas(roomId) {
|
|
|
2927
2966
|
const [shapes, setShapes] = useState9([]);
|
|
2928
2967
|
const [viewports, setViewports] = useState9([]);
|
|
2929
2968
|
const [connected, setConnected] = useState9(false);
|
|
2969
|
+
const [canWrite, setCanWrite] = useState9(false);
|
|
2930
2970
|
const wsRef = useRef10(null);
|
|
2931
2971
|
useEffect12(() => {
|
|
2932
2972
|
let ws = null;
|
|
@@ -2948,6 +2988,9 @@ function useCanvas(roomId) {
|
|
|
2948
2988
|
};
|
|
2949
2989
|
ws.onmessage = (event) => {
|
|
2950
2990
|
dispatch(event.data, {
|
|
2991
|
+
[MSG.AUTH]: (p) => {
|
|
2992
|
+
setCanWrite(p.canWrite);
|
|
2993
|
+
},
|
|
2951
2994
|
[MSG.CANVAS_SHAPES]: (p) => {
|
|
2952
2995
|
setShapes(p.shapes);
|
|
2953
2996
|
setViewports(p.viewports);
|
|
@@ -3000,6 +3043,7 @@ function useCanvas(roomId) {
|
|
|
3000
3043
|
wsLog("disconnected", `canvas:${roomId}`);
|
|
3001
3044
|
wsRef.current = null;
|
|
3002
3045
|
setConnected(false);
|
|
3046
|
+
setCanWrite(false);
|
|
3003
3047
|
if (alive) reconnectTimer = setTimeout(connect, 1e3);
|
|
3004
3048
|
};
|
|
3005
3049
|
ws.onerror = () => ws?.close();
|
|
@@ -3026,33 +3070,40 @@ function useCanvas(roomId) {
|
|
|
3026
3070
|
},
|
|
3027
3071
|
[]
|
|
3028
3072
|
);
|
|
3073
|
+
const sendWrite = useCallback11(
|
|
3074
|
+
(message) => {
|
|
3075
|
+
if (!canWrite) return;
|
|
3076
|
+
sendBuilt(message);
|
|
3077
|
+
},
|
|
3078
|
+
[sendBuilt, canWrite]
|
|
3079
|
+
);
|
|
3029
3080
|
const addShape = useCallback11(
|
|
3030
|
-
(shape) =>
|
|
3031
|
-
[
|
|
3081
|
+
(shape) => sendWrite(clientBuild.canvasAdd(shape)),
|
|
3082
|
+
[sendWrite]
|
|
3032
3083
|
);
|
|
3033
3084
|
const moveShape = useCallback11(
|
|
3034
|
-
(shapeId, x, y) =>
|
|
3035
|
-
[
|
|
3085
|
+
(shapeId, x, y) => sendWrite(clientBuild.canvasMove(shapeId, x, y)),
|
|
3086
|
+
[sendWrite]
|
|
3036
3087
|
);
|
|
3037
3088
|
const resizeShape = useCallback11(
|
|
3038
|
-
(shapeId, width, height, x, y) =>
|
|
3039
|
-
[
|
|
3089
|
+
(shapeId, width, height, x, y) => sendWrite(clientBuild.canvasResize(shapeId, width, height, x, y)),
|
|
3090
|
+
[sendWrite]
|
|
3040
3091
|
);
|
|
3041
3092
|
const deleteShape = useCallback11(
|
|
3042
|
-
(shapeId) =>
|
|
3043
|
-
[
|
|
3093
|
+
(shapeId) => sendWrite(clientBuild.canvasDelete(shapeId)),
|
|
3094
|
+
[sendWrite]
|
|
3044
3095
|
);
|
|
3045
3096
|
const updateShape = useCallback11(
|
|
3046
|
-
(shapeId, props) =>
|
|
3047
|
-
[
|
|
3097
|
+
(shapeId, props) => sendWrite(clientBuild.canvasUpdate(shapeId, props)),
|
|
3098
|
+
[sendWrite]
|
|
3048
3099
|
);
|
|
3049
3100
|
const setViewport = useCallback11(
|
|
3050
3101
|
(viewport) => sendBuilt(clientBuild.canvasViewport(viewport)),
|
|
3051
3102
|
[sendBuilt]
|
|
3052
3103
|
);
|
|
3053
|
-
const undo = useCallback11(() =>
|
|
3054
|
-
const redo = useCallback11(() =>
|
|
3055
|
-
return { shapes, viewports, connected, addShape, moveShape, resizeShape, deleteShape, updateShape, setViewport, undo, redo };
|
|
3104
|
+
const undo = useCallback11(() => sendWrite(clientBuild.canvasUndo()), [sendWrite]);
|
|
3105
|
+
const redo = useCallback11(() => sendWrite(clientBuild.canvasRedo()), [sendWrite]);
|
|
3106
|
+
return { shapes, viewports, connected, canWrite, addShape, moveShape, resizeShape, deleteShape, updateShape, setViewport, undo, redo };
|
|
3056
3107
|
}
|
|
3057
3108
|
|
|
3058
3109
|
// src/client/storage/hooks/useCronMonitor.ts
|
|
@@ -3061,6 +3112,7 @@ function useCronMonitor(roomId) {
|
|
|
3061
3112
|
const [tasks, setTasks] = useState10([]);
|
|
3062
3113
|
const [history, setHistory] = useState10([]);
|
|
3063
3114
|
const [connected, setConnected] = useState10(false);
|
|
3115
|
+
const [canWrite, setCanWrite] = useState10(false);
|
|
3064
3116
|
const wsRef = useRef11(null);
|
|
3065
3117
|
useEffect13(() => {
|
|
3066
3118
|
let ws = null;
|
|
@@ -3078,6 +3130,9 @@ function useCronMonitor(roomId) {
|
|
|
3078
3130
|
ws.onopen = () => setConnected(true);
|
|
3079
3131
|
ws.onmessage = (event) => {
|
|
3080
3132
|
dispatch(event.data, {
|
|
3133
|
+
[MSG.AUTH]: (p) => {
|
|
3134
|
+
setCanWrite(p.canWrite);
|
|
3135
|
+
},
|
|
3081
3136
|
[MSG.CRON_TASKS]: (p) => {
|
|
3082
3137
|
setTasks(p.tasks);
|
|
3083
3138
|
},
|
|
@@ -3093,6 +3148,7 @@ function useCronMonitor(roomId) {
|
|
|
3093
3148
|
ws.onclose = () => {
|
|
3094
3149
|
wsRef.current = null;
|
|
3095
3150
|
setConnected(false);
|
|
3151
|
+
setCanWrite(false);
|
|
3096
3152
|
if (alive) reconnectTimer = setTimeout(connect, 1e3);
|
|
3097
3153
|
};
|
|
3098
3154
|
ws.onerror = () => ws?.close();
|
|
@@ -3105,36 +3161,167 @@ function useCronMonitor(roomId) {
|
|
|
3105
3161
|
wsRef.current = null;
|
|
3106
3162
|
};
|
|
3107
3163
|
}, [roomId]);
|
|
3108
|
-
const
|
|
3164
|
+
const sendWrite = useCallback12(
|
|
3109
3165
|
(message) => {
|
|
3166
|
+
if (!canWrite) return;
|
|
3110
3167
|
const ws = wsRef.current;
|
|
3111
3168
|
if (!ws || ws.readyState !== WebSocket.OPEN) return;
|
|
3112
3169
|
ws.send(encode(message));
|
|
3113
3170
|
},
|
|
3114
|
-
[]
|
|
3171
|
+
[canWrite]
|
|
3115
3172
|
);
|
|
3116
3173
|
const trigger = useCallback12(
|
|
3117
|
-
(taskName) =>
|
|
3118
|
-
[
|
|
3174
|
+
(taskName) => sendWrite(clientBuild.cronTrigger(taskName)),
|
|
3175
|
+
[sendWrite]
|
|
3119
3176
|
);
|
|
3120
3177
|
const pause = useCallback12(
|
|
3121
|
-
(taskName) =>
|
|
3122
|
-
[
|
|
3178
|
+
(taskName) => sendWrite(clientBuild.cronPause(taskName)),
|
|
3179
|
+
[sendWrite]
|
|
3123
3180
|
);
|
|
3124
3181
|
const resume = useCallback12(
|
|
3125
|
-
(taskName) =>
|
|
3126
|
-
[
|
|
3182
|
+
(taskName) => sendWrite(clientBuild.cronResume(taskName)),
|
|
3183
|
+
[sendWrite]
|
|
3127
3184
|
);
|
|
3128
|
-
return { tasks, history, connected, trigger, pause, resume };
|
|
3185
|
+
return { tasks, history, connected, canWrite, trigger, pause, resume };
|
|
3129
3186
|
}
|
|
3130
3187
|
|
|
3131
|
-
// src/client/storage/hooks/
|
|
3188
|
+
// src/client/storage/hooks/useJobs.ts
|
|
3132
3189
|
import { useState as useState11, useEffect as useEffect14, useCallback as useCallback13, useRef as useRef12 } from "react";
|
|
3133
|
-
|
|
3134
|
-
|
|
3190
|
+
var ENQUEUE_TIMEOUT_MS = 1e4;
|
|
3191
|
+
function useJobs(roomId) {
|
|
3192
|
+
const [jobs, setJobs] = useState11([]);
|
|
3135
3193
|
const [connected, setConnected] = useState11(false);
|
|
3136
3194
|
const wsRef = useRef12(null);
|
|
3195
|
+
const pendingEnqueueRef = useRef12(/* @__PURE__ */ new Map());
|
|
3137
3196
|
useEffect14(() => {
|
|
3197
|
+
let ws = null;
|
|
3198
|
+
let reconnectTimer = null;
|
|
3199
|
+
let alive = true;
|
|
3200
|
+
const upsert = (next) => {
|
|
3201
|
+
setJobs((prev) => {
|
|
3202
|
+
const idx = prev.findIndex((j) => j.id === next.id);
|
|
3203
|
+
if (idx === -1) return [next, ...prev];
|
|
3204
|
+
const copy = prev.slice();
|
|
3205
|
+
copy[idx] = next;
|
|
3206
|
+
return copy;
|
|
3207
|
+
});
|
|
3208
|
+
};
|
|
3209
|
+
const rejectAllPending = (err) => {
|
|
3210
|
+
for (const [id, pending] of pendingEnqueueRef.current.entries()) {
|
|
3211
|
+
clearTimeout(pending.timer);
|
|
3212
|
+
pending.reject(err);
|
|
3213
|
+
pendingEnqueueRef.current.delete(id);
|
|
3214
|
+
}
|
|
3215
|
+
};
|
|
3216
|
+
const connect = async () => {
|
|
3217
|
+
if (!alive) return;
|
|
3218
|
+
const token = await getAuthToken();
|
|
3219
|
+
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
|
3220
|
+
const baseUrl = `${protocol}//${window.location.host}`;
|
|
3221
|
+
const url = new URL(`/ws/jobs/${encodeURIComponent(roomId)}`, baseUrl);
|
|
3222
|
+
if (token) url.searchParams.set("token", token);
|
|
3223
|
+
ws = new WebSocket(url.toString());
|
|
3224
|
+
wsRef.current = ws;
|
|
3225
|
+
ws.onopen = () => setConnected(true);
|
|
3226
|
+
ws.onmessage = (event) => {
|
|
3227
|
+
dispatch(event.data, {
|
|
3228
|
+
[MSG.JOB_UPDATE]: (p) => {
|
|
3229
|
+
if (p.kind === "snapshot" && Array.isArray(p.jobs)) {
|
|
3230
|
+
setJobs(p.jobs);
|
|
3231
|
+
return;
|
|
3232
|
+
}
|
|
3233
|
+
const job = p.job;
|
|
3234
|
+
if (!job) return;
|
|
3235
|
+
upsert(job);
|
|
3236
|
+
if (p.kind === "enqueued" && typeof p.requestId === "string") {
|
|
3237
|
+
const pending = pendingEnqueueRef.current.get(p.requestId);
|
|
3238
|
+
if (pending) {
|
|
3239
|
+
clearTimeout(pending.timer);
|
|
3240
|
+
pendingEnqueueRef.current.delete(p.requestId);
|
|
3241
|
+
pending.resolve(job.id);
|
|
3242
|
+
}
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
});
|
|
3246
|
+
};
|
|
3247
|
+
ws.onclose = () => {
|
|
3248
|
+
wsRef.current = null;
|
|
3249
|
+
setConnected(false);
|
|
3250
|
+
rejectAllPending(new Error("JobRoom WebSocket closed"));
|
|
3251
|
+
if (alive) reconnectTimer = setTimeout(connect, 1e3);
|
|
3252
|
+
};
|
|
3253
|
+
ws.onerror = () => ws?.close();
|
|
3254
|
+
};
|
|
3255
|
+
connect();
|
|
3256
|
+
return () => {
|
|
3257
|
+
alive = false;
|
|
3258
|
+
if (reconnectTimer) clearTimeout(reconnectTimer);
|
|
3259
|
+
rejectAllPending(new Error("useJobs unmounted"));
|
|
3260
|
+
ws?.close();
|
|
3261
|
+
wsRef.current = null;
|
|
3262
|
+
};
|
|
3263
|
+
}, [roomId]);
|
|
3264
|
+
const enqueue = useCallback13(
|
|
3265
|
+
(type, payload, options) => {
|
|
3266
|
+
return new Promise((resolve, reject) => {
|
|
3267
|
+
const ws = wsRef.current;
|
|
3268
|
+
if (!ws || ws.readyState !== WebSocket.OPEN) {
|
|
3269
|
+
reject(new Error("JobRoom WebSocket not connected"));
|
|
3270
|
+
return;
|
|
3271
|
+
}
|
|
3272
|
+
const requestId = crypto.randomUUID();
|
|
3273
|
+
const timer = setTimeout(() => {
|
|
3274
|
+
pendingEnqueueRef.current.delete(requestId);
|
|
3275
|
+
reject(
|
|
3276
|
+
new Error(
|
|
3277
|
+
`JobRoom enqueue timed out (no server ack within ${ENQUEUE_TIMEOUT_MS}ms)`
|
|
3278
|
+
)
|
|
3279
|
+
);
|
|
3280
|
+
}, ENQUEUE_TIMEOUT_MS);
|
|
3281
|
+
pendingEnqueueRef.current.set(requestId, { resolve, reject, timer });
|
|
3282
|
+
try {
|
|
3283
|
+
ws.send(
|
|
3284
|
+
encode(clientBuild.jobEnqueue(requestId, type, payload, options?.maxAttempts))
|
|
3285
|
+
);
|
|
3286
|
+
} catch (e) {
|
|
3287
|
+
clearTimeout(timer);
|
|
3288
|
+
pendingEnqueueRef.current.delete(requestId);
|
|
3289
|
+
reject(e instanceof Error ? e : new Error(String(e)));
|
|
3290
|
+
}
|
|
3291
|
+
});
|
|
3292
|
+
},
|
|
3293
|
+
[]
|
|
3294
|
+
);
|
|
3295
|
+
const sendBuilt = useCallback13(
|
|
3296
|
+
(message) => {
|
|
3297
|
+
const ws = wsRef.current;
|
|
3298
|
+
if (!ws || ws.readyState !== WebSocket.OPEN) return;
|
|
3299
|
+
ws.send(encode(message));
|
|
3300
|
+
},
|
|
3301
|
+
[]
|
|
3302
|
+
);
|
|
3303
|
+
const getJob = useCallback13(
|
|
3304
|
+
(jobId) => jobs.find((j) => j.id === jobId),
|
|
3305
|
+
[jobs]
|
|
3306
|
+
);
|
|
3307
|
+
const cancel = useCallback13(
|
|
3308
|
+
(jobId) => sendBuilt(clientBuild.jobCancel(jobId)),
|
|
3309
|
+
[sendBuilt]
|
|
3310
|
+
);
|
|
3311
|
+
const retry = useCallback13(
|
|
3312
|
+
(jobId) => sendBuilt(clientBuild.jobRetry(jobId)),
|
|
3313
|
+
[sendBuilt]
|
|
3314
|
+
);
|
|
3315
|
+
return { jobs, connected, enqueue, getJob, cancel, retry };
|
|
3316
|
+
}
|
|
3317
|
+
|
|
3318
|
+
// src/client/storage/hooks/usePresenceRoom.ts
|
|
3319
|
+
import { useState as useState12, useEffect as useEffect15, useCallback as useCallback14, useRef as useRef13 } from "react";
|
|
3320
|
+
function usePresenceRoom(scopeId) {
|
|
3321
|
+
const [peers, setPeers] = useState12([]);
|
|
3322
|
+
const [connected, setConnected] = useState12(false);
|
|
3323
|
+
const wsRef = useRef13(null);
|
|
3324
|
+
useEffect15(() => {
|
|
3138
3325
|
let ws = null;
|
|
3139
3326
|
let reconnectTimer = null;
|
|
3140
3327
|
let alive = true;
|
|
@@ -3195,7 +3382,7 @@ function usePresenceRoom(scopeId) {
|
|
|
3195
3382
|
wsRef.current = null;
|
|
3196
3383
|
};
|
|
3197
3384
|
}, [scopeId]);
|
|
3198
|
-
const updateState =
|
|
3385
|
+
const updateState = useCallback14((state) => {
|
|
3199
3386
|
const ws = wsRef.current;
|
|
3200
3387
|
if (!ws || ws.readyState !== WebSocket.OPEN) return;
|
|
3201
3388
|
ws.send(encode(clientBuild.presenceUpdate(state)));
|
|
@@ -3211,7 +3398,7 @@ function toConnectionStatus(queryStatus) {
|
|
|
3211
3398
|
}
|
|
3212
3399
|
|
|
3213
3400
|
// src/client/storage/useR2Files.ts
|
|
3214
|
-
import { useCallback as
|
|
3401
|
+
import { useCallback as useCallback15, useState as useState13, useMemo as useMemo10 } from "react";
|
|
3215
3402
|
function resolveFile(fileOrKey) {
|
|
3216
3403
|
if (typeof fileOrKey === "string") {
|
|
3217
3404
|
return { key: fileOrKey, name: void 0 };
|
|
@@ -3219,20 +3406,20 @@ function resolveFile(fileOrKey) {
|
|
|
3219
3406
|
return { key: fileOrKey.key, name: fileOrKey.originalName };
|
|
3220
3407
|
}
|
|
3221
3408
|
function useR2Files(options) {
|
|
3222
|
-
const [isUploading, setIsUploading] =
|
|
3409
|
+
const [isUploading, setIsUploading] = useState13(false);
|
|
3223
3410
|
const scopeParams = useMemo10(() => {
|
|
3224
3411
|
const params = new URLSearchParams();
|
|
3225
3412
|
params.set("scope", "self");
|
|
3226
3413
|
return params.toString();
|
|
3227
3414
|
}, []);
|
|
3228
|
-
const authHeaders =
|
|
3415
|
+
const authHeaders = useCallback15(async () => {
|
|
3229
3416
|
const token = await getAuthToken();
|
|
3230
3417
|
if (token) {
|
|
3231
3418
|
return { Authorization: `Bearer ${token}` };
|
|
3232
3419
|
}
|
|
3233
3420
|
return {};
|
|
3234
3421
|
}, []);
|
|
3235
|
-
const upload =
|
|
3422
|
+
const upload = useCallback15(async (file, name) => {
|
|
3236
3423
|
setIsUploading(true);
|
|
3237
3424
|
try {
|
|
3238
3425
|
const headers = await authHeaders();
|
|
@@ -3251,7 +3438,7 @@ function useR2Files(options) {
|
|
|
3251
3438
|
setIsUploading(false);
|
|
3252
3439
|
}
|
|
3253
3440
|
}, [scopeParams, authHeaders]);
|
|
3254
|
-
const uploadBase64 =
|
|
3441
|
+
const uploadBase64 = useCallback15(async (base64Data, name, mimeType) => {
|
|
3255
3442
|
setIsUploading(true);
|
|
3256
3443
|
try {
|
|
3257
3444
|
const headers = await authHeaders();
|
|
@@ -3267,7 +3454,7 @@ function useR2Files(options) {
|
|
|
3267
3454
|
setIsUploading(false);
|
|
3268
3455
|
}
|
|
3269
3456
|
}, [scopeParams, authHeaders]);
|
|
3270
|
-
const deleteFile =
|
|
3457
|
+
const deleteFile = useCallback15(async (fileOrKey) => {
|
|
3271
3458
|
const { key } = resolveFile(fileOrKey);
|
|
3272
3459
|
try {
|
|
3273
3460
|
const headers = await authHeaders();
|
|
@@ -3277,7 +3464,7 @@ function useR2Files(options) {
|
|
|
3277
3464
|
return { success: false, error: err instanceof Error ? err.message : "Delete failed" };
|
|
3278
3465
|
}
|
|
3279
3466
|
}, [scopeParams, authHeaders]);
|
|
3280
|
-
const list =
|
|
3467
|
+
const list = useCallback15(async (prefix) => {
|
|
3281
3468
|
try {
|
|
3282
3469
|
const headers = await authHeaders();
|
|
3283
3470
|
const params = new URLSearchParams(scopeParams);
|
|
@@ -3289,7 +3476,7 @@ function useR2Files(options) {
|
|
|
3289
3476
|
return [];
|
|
3290
3477
|
}
|
|
3291
3478
|
}, [scopeParams, authHeaders]);
|
|
3292
|
-
const downloadFile =
|
|
3479
|
+
const downloadFile = useCallback15(async (fileOrKey, fileName) => {
|
|
3293
3480
|
const { key, name: infoName } = resolveFile(fileOrKey);
|
|
3294
3481
|
try {
|
|
3295
3482
|
const headers = await authHeaders();
|
|
@@ -3316,7 +3503,7 @@ function useR2Files(options) {
|
|
|
3316
3503
|
return { success: false, error: err instanceof Error ? err.message : "Download failed" };
|
|
3317
3504
|
}
|
|
3318
3505
|
}, [scopeParams, authHeaders]);
|
|
3319
|
-
const readFile =
|
|
3506
|
+
const readFile = useCallback15(async (fileOrKey) => {
|
|
3320
3507
|
const { key } = resolveFile(fileOrKey);
|
|
3321
3508
|
const headers = await authHeaders();
|
|
3322
3509
|
const response = await fetch(`/api/files/${key}?${scopeParams}`, { headers });
|
|
@@ -3326,7 +3513,7 @@ function useR2Files(options) {
|
|
|
3326
3513
|
}
|
|
3327
3514
|
return response;
|
|
3328
3515
|
}, [scopeParams, authHeaders]);
|
|
3329
|
-
const getUrl =
|
|
3516
|
+
const getUrl = useCallback15((fileOrKey) => {
|
|
3330
3517
|
const { key } = resolveFile(fileOrKey);
|
|
3331
3518
|
return `/api/files/${key}?${scopeParams}`;
|
|
3332
3519
|
}, [scopeParams]);
|
|
@@ -3369,7 +3556,7 @@ function getUserColor(userId, palette = DEFAULT_USER_COLORS) {
|
|
|
3369
3556
|
}
|
|
3370
3557
|
|
|
3371
3558
|
// src/client/messaging/useMessages.ts
|
|
3372
|
-
import { useCallback as
|
|
3559
|
+
import { useCallback as useCallback16, useMemo as useMemo11 } from "react";
|
|
3373
3560
|
function useMessages(channelId, options) {
|
|
3374
3561
|
const where = useMemo11(() => {
|
|
3375
3562
|
if (!channelId) return { channelId: "__none__" };
|
|
@@ -3386,7 +3573,7 @@ function useMessages(channelId, options) {
|
|
|
3386
3573
|
orderDir: "asc"
|
|
3387
3574
|
});
|
|
3388
3575
|
const { create, put, remove: removeMutation } = useMutations("messages");
|
|
3389
|
-
const send =
|
|
3576
|
+
const send = useCallback16(
|
|
3390
3577
|
(content, parentMessageId) => {
|
|
3391
3578
|
if (!channelId || !user) return;
|
|
3392
3579
|
const data = { channelId, content, authorId: user.id, edited: false };
|
|
@@ -3395,19 +3582,19 @@ function useMessages(channelId, options) {
|
|
|
3395
3582
|
},
|
|
3396
3583
|
[channelId, create]
|
|
3397
3584
|
);
|
|
3398
|
-
const edit =
|
|
3585
|
+
const edit = useCallback16(
|
|
3399
3586
|
(messageId, newContent) => {
|
|
3400
3587
|
put(messageId, { content: newContent, edited: true });
|
|
3401
3588
|
},
|
|
3402
3589
|
[put]
|
|
3403
3590
|
);
|
|
3404
|
-
const remove =
|
|
3591
|
+
const remove = useCallback16(
|
|
3405
3592
|
(messageId) => {
|
|
3406
3593
|
removeMutation(messageId);
|
|
3407
3594
|
},
|
|
3408
3595
|
[removeMutation]
|
|
3409
3596
|
);
|
|
3410
|
-
const softDelete =
|
|
3597
|
+
const softDelete = useCallback16(
|
|
3411
3598
|
(messageId) => {
|
|
3412
3599
|
put(messageId, { deleted: true });
|
|
3413
3600
|
},
|
|
@@ -3417,7 +3604,7 @@ function useMessages(channelId, options) {
|
|
|
3417
3604
|
}
|
|
3418
3605
|
|
|
3419
3606
|
// src/client/messaging/useChannels.ts
|
|
3420
|
-
import { useCallback as
|
|
3607
|
+
import { useCallback as useCallback17 } from "react";
|
|
3421
3608
|
function useChannels() {
|
|
3422
3609
|
const { user } = useUser();
|
|
3423
3610
|
const { records, status, error } = useQuery("channels", {
|
|
@@ -3425,7 +3612,7 @@ function useChannels() {
|
|
|
3425
3612
|
orderDir: "asc"
|
|
3426
3613
|
});
|
|
3427
3614
|
const { create: createMutation, put, remove } = useMutations("channels");
|
|
3428
|
-
const create =
|
|
3615
|
+
const create = useCallback17(
|
|
3429
3616
|
(data) => {
|
|
3430
3617
|
return createMutation({
|
|
3431
3618
|
name: data.name,
|
|
@@ -3437,13 +3624,13 @@ function useChannels() {
|
|
|
3437
3624
|
},
|
|
3438
3625
|
[createMutation]
|
|
3439
3626
|
);
|
|
3440
|
-
const archive =
|
|
3627
|
+
const archive = useCallback17(
|
|
3441
3628
|
(channelId) => {
|
|
3442
3629
|
put(channelId, { archived: true });
|
|
3443
3630
|
},
|
|
3444
3631
|
[put]
|
|
3445
3632
|
);
|
|
3446
|
-
const update =
|
|
3633
|
+
const update = useCallback17(
|
|
3447
3634
|
(channelId, data) => {
|
|
3448
3635
|
put(channelId, data);
|
|
3449
3636
|
},
|
|
@@ -3453,14 +3640,14 @@ function useChannels() {
|
|
|
3453
3640
|
}
|
|
3454
3641
|
|
|
3455
3642
|
// src/client/messaging/useReactions.ts
|
|
3456
|
-
import { useCallback as
|
|
3643
|
+
import { useCallback as useCallback18 } from "react";
|
|
3457
3644
|
function useReactions(channelId) {
|
|
3458
3645
|
const { user } = useUser();
|
|
3459
3646
|
const { records, status, error } = useQuery("reactions", {
|
|
3460
3647
|
where: channelId ? { channelId } : { channelId: "__none__" }
|
|
3461
3648
|
});
|
|
3462
3649
|
const { create, remove: removeMutation } = useMutations("reactions");
|
|
3463
|
-
const getReactionsForMessage =
|
|
3650
|
+
const getReactionsForMessage = useCallback18(
|
|
3464
3651
|
(messageId) => {
|
|
3465
3652
|
const messageReactions = records.filter((r) => r.data.messageId === messageId);
|
|
3466
3653
|
const grouped = /* @__PURE__ */ new Map();
|
|
@@ -3477,7 +3664,7 @@ function useReactions(channelId) {
|
|
|
3477
3664
|
},
|
|
3478
3665
|
[records, user]
|
|
3479
3666
|
);
|
|
3480
|
-
const toggle =
|
|
3667
|
+
const toggle = useCallback18(
|
|
3481
3668
|
(messageId, emoji) => {
|
|
3482
3669
|
if (!channelId || !user) return;
|
|
3483
3670
|
const existing = records.find(
|
|
@@ -3495,20 +3682,20 @@ function useReactions(channelId) {
|
|
|
3495
3682
|
}
|
|
3496
3683
|
|
|
3497
3684
|
// src/client/messaging/useChannelMembers.ts
|
|
3498
|
-
import { useCallback as
|
|
3685
|
+
import { useCallback as useCallback19 } from "react";
|
|
3499
3686
|
function useChannelMembers(channelId) {
|
|
3500
3687
|
const { user } = useUser();
|
|
3501
3688
|
const { records, status, error } = useQuery("channel-members", {
|
|
3502
3689
|
where: channelId ? { channelId } : { channelId: "__none__" }
|
|
3503
3690
|
});
|
|
3504
3691
|
const { create, remove: removeMutation } = useMutations("channel-members");
|
|
3505
|
-
const join =
|
|
3692
|
+
const join = useCallback19(() => {
|
|
3506
3693
|
if (!channelId || !user) return;
|
|
3507
3694
|
const existing = records.find((r) => r.data.userId === user.id);
|
|
3508
3695
|
if (existing) return;
|
|
3509
3696
|
create({ channelId, userId: user.id, joinedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
3510
3697
|
}, [channelId, user, records, create]);
|
|
3511
|
-
const leave =
|
|
3698
|
+
const leave = useCallback19(() => {
|
|
3512
3699
|
if (!channelId || !user) return;
|
|
3513
3700
|
const membership = records.find((r) => r.data.userId === user.id);
|
|
3514
3701
|
if (membership) removeMutation(membership.recordId);
|
|
@@ -3518,14 +3705,14 @@ function useChannelMembers(channelId) {
|
|
|
3518
3705
|
}
|
|
3519
3706
|
|
|
3520
3707
|
// src/client/messaging/useReadReceipts.ts
|
|
3521
|
-
import { useCallback as
|
|
3708
|
+
import { useCallback as useCallback20 } from "react";
|
|
3522
3709
|
function useReadReceipts() {
|
|
3523
3710
|
const { user } = useUser();
|
|
3524
3711
|
const { records, status, error } = useQuery("read-receipts", {
|
|
3525
3712
|
where: user ? { userId: user.id } : { userId: "__none__" }
|
|
3526
3713
|
});
|
|
3527
3714
|
const { create, put } = useMutations("read-receipts");
|
|
3528
|
-
const markAsRead =
|
|
3715
|
+
const markAsRead = useCallback20(
|
|
3529
3716
|
(channelId) => {
|
|
3530
3717
|
if (!user) return;
|
|
3531
3718
|
const existing = records.find((r) => r.data.channelId === channelId);
|
|
@@ -3538,7 +3725,7 @@ function useReadReceipts() {
|
|
|
3538
3725
|
},
|
|
3539
3726
|
[user, records, create, put]
|
|
3540
3727
|
);
|
|
3541
|
-
const getUnreadCount =
|
|
3728
|
+
const getUnreadCount = useCallback20(
|
|
3542
3729
|
(channelId, messages) => {
|
|
3543
3730
|
const receipt = records.find((r) => r.data.channelId === channelId);
|
|
3544
3731
|
if (!receipt) return messages.length;
|
|
@@ -3551,7 +3738,7 @@ function useReadReceipts() {
|
|
|
3551
3738
|
}
|
|
3552
3739
|
|
|
3553
3740
|
// src/client/messaging/useConversation.ts
|
|
3554
|
-
import { useCallback as
|
|
3741
|
+
import { useCallback as useCallback21, useMemo as useMemo12 } from "react";
|
|
3555
3742
|
function useConversation(opts) {
|
|
3556
3743
|
const { user } = useUser();
|
|
3557
3744
|
const { ready } = useRecordContext();
|
|
@@ -3560,7 +3747,7 @@ function useConversation(opts) {
|
|
|
3560
3747
|
const { records: members } = useQuery("conv_members");
|
|
3561
3748
|
const messageMut = useMutations("conv_messages");
|
|
3562
3749
|
const reactionMut = useMutations("conv_reactions");
|
|
3563
|
-
const send =
|
|
3750
|
+
const send = useCallback21(
|
|
3564
3751
|
(content, parentMessageId, messageType, metadata) => {
|
|
3565
3752
|
messageMut.create({
|
|
3566
3753
|
Content: content,
|
|
@@ -3574,7 +3761,7 @@ function useConversation(opts) {
|
|
|
3574
3761
|
},
|
|
3575
3762
|
[messageMut, user?.id, opts?.onMessageSent]
|
|
3576
3763
|
);
|
|
3577
|
-
const edit =
|
|
3764
|
+
const edit = useCallback21(
|
|
3578
3765
|
(recordId, content) => {
|
|
3579
3766
|
const existing = allMessages.find((m) => m.recordId === recordId);
|
|
3580
3767
|
if (!existing) return;
|
|
@@ -3582,7 +3769,7 @@ function useConversation(opts) {
|
|
|
3582
3769
|
},
|
|
3583
3770
|
[messageMut, allMessages]
|
|
3584
3771
|
);
|
|
3585
|
-
const remove =
|
|
3772
|
+
const remove = useCallback21(
|
|
3586
3773
|
(recordId) => {
|
|
3587
3774
|
const existing = allMessages.find((m) => m.recordId === recordId);
|
|
3588
3775
|
if (!existing) return;
|
|
@@ -3595,7 +3782,7 @@ function useConversation(opts) {
|
|
|
3595
3782
|
},
|
|
3596
3783
|
[messageMut, allMessages]
|
|
3597
3784
|
);
|
|
3598
|
-
const toggleReaction =
|
|
3785
|
+
const toggleReaction = useCallback21(
|
|
3599
3786
|
(messageId, emoji) => {
|
|
3600
3787
|
const existing = allReactions.find(
|
|
3601
3788
|
(r) => r.data.MessageId === messageId && r.data.Emoji === emoji && r.data.UserId === user?.id
|
|
@@ -3728,7 +3915,7 @@ function parseMessageMetadata(raw) {
|
|
|
3728
3915
|
}
|
|
3729
3916
|
|
|
3730
3917
|
// src/client/directory/useConversations.ts
|
|
3731
|
-
import { useCallback as
|
|
3918
|
+
import { useCallback as useCallback22, useMemo as useMemo13, useRef as useRef14 } from "react";
|
|
3732
3919
|
function useConversations() {
|
|
3733
3920
|
const { records: conversations, status } = useQuery("conversations");
|
|
3734
3921
|
const { create, put } = useMutations("conversations");
|
|
@@ -3736,7 +3923,7 @@ function useConversations() {
|
|
|
3736
3923
|
const stateMut = useMutations("conversation_state");
|
|
3737
3924
|
const { user } = useUser();
|
|
3738
3925
|
const ready = status === "ready";
|
|
3739
|
-
const recentCreationsRef =
|
|
3926
|
+
const recentCreationsRef = useRef14(/* @__PURE__ */ new Map());
|
|
3740
3927
|
for (const [id] of recentCreationsRef.current) {
|
|
3741
3928
|
if (conversations.find((c) => c.recordId === id)) {
|
|
3742
3929
|
recentCreationsRef.current.delete(id);
|
|
@@ -3758,7 +3945,7 @@ function useConversations() {
|
|
|
3758
3945
|
() => new Set(stateRecords.filter((r) => r.data.Archived).map((r) => r.data.ConversationId)),
|
|
3759
3946
|
[stateRecords]
|
|
3760
3947
|
);
|
|
3761
|
-
const getConversationState =
|
|
3948
|
+
const getConversationState = useCallback22(
|
|
3762
3949
|
(conversationId) => {
|
|
3763
3950
|
return stateRecords.find((r) => r.data.ConversationId === conversationId)?.data;
|
|
3764
3951
|
},
|
|
@@ -3771,7 +3958,7 @@ function useConversations() {
|
|
|
3771
3958
|
LinkedRef: "",
|
|
3772
3959
|
MessageCount: 0
|
|
3773
3960
|
};
|
|
3774
|
-
const createChannel =
|
|
3961
|
+
const createChannel = useCallback22(
|
|
3775
3962
|
async (name, description) => {
|
|
3776
3963
|
const existing = conversations.find((r) => r.data.Name === name && r.data.Type !== "dm");
|
|
3777
3964
|
if (existing) return existing.recordId;
|
|
@@ -3791,7 +3978,7 @@ function useConversations() {
|
|
|
3791
3978
|
},
|
|
3792
3979
|
[create, user?.id, conversations]
|
|
3793
3980
|
);
|
|
3794
|
-
const createDM =
|
|
3981
|
+
const createDM = useCallback22(
|
|
3795
3982
|
async (otherUserId) => {
|
|
3796
3983
|
if (!user?.id) return null;
|
|
3797
3984
|
const hash = [user.id, otherUserId].sort().join(":");
|
|
@@ -3819,7 +4006,7 @@ function useConversations() {
|
|
|
3819
4006
|
},
|
|
3820
4007
|
[create, user?.id, conversations]
|
|
3821
4008
|
);
|
|
3822
|
-
const createGroupDM =
|
|
4009
|
+
const createGroupDM = useCallback22(
|
|
3823
4010
|
async (participantIds) => {
|
|
3824
4011
|
if (!user?.id) return null;
|
|
3825
4012
|
const allIds = [.../* @__PURE__ */ new Set([user.id, ...participantIds])];
|
|
@@ -3849,14 +4036,14 @@ function useConversations() {
|
|
|
3849
4036
|
},
|
|
3850
4037
|
[create, user?.id, conversations]
|
|
3851
4038
|
);
|
|
3852
|
-
const lookupByName =
|
|
4039
|
+
const lookupByName = useCallback22(
|
|
3853
4040
|
(name) => {
|
|
3854
4041
|
const found = conversations.find((r) => r.data.Name === name);
|
|
3855
4042
|
return found?.recordId ?? null;
|
|
3856
4043
|
},
|
|
3857
4044
|
[conversations]
|
|
3858
4045
|
);
|
|
3859
|
-
const updateLastMessage =
|
|
4046
|
+
const updateLastMessage = useCallback22(
|
|
3860
4047
|
(conversationId, preview, authorId) => {
|
|
3861
4048
|
const conv = conversations.find((c) => c.recordId === conversationId);
|
|
3862
4049
|
const baseData = conv?.data ?? recentCreationsRef.current.get(conversationId);
|
|
@@ -3875,7 +4062,7 @@ function useConversations() {
|
|
|
3875
4062
|
},
|
|
3876
4063
|
[put, conversations]
|
|
3877
4064
|
);
|
|
3878
|
-
const upsertState =
|
|
4065
|
+
const upsertState = useCallback22(
|
|
3879
4066
|
(conversationId, partial) => {
|
|
3880
4067
|
if (!user?.id) return;
|
|
3881
4068
|
const existing = stateRecords.find(
|
|
@@ -3897,7 +4084,7 @@ function useConversations() {
|
|
|
3897
4084
|
},
|
|
3898
4085
|
[stateMut, stateRecords, user?.id]
|
|
3899
4086
|
);
|
|
3900
|
-
const markRead =
|
|
4087
|
+
const markRead = useCallback22(
|
|
3901
4088
|
(conversationId) => {
|
|
3902
4089
|
const conv = conversations.find((c) => c.recordId === conversationId);
|
|
3903
4090
|
const msgCount = conv?.data.MessageCount ?? recentCreationsRef.current.get(conversationId)?.MessageCount ?? 0;
|
|
@@ -3908,32 +4095,32 @@ function useConversations() {
|
|
|
3908
4095
|
},
|
|
3909
4096
|
[upsertState, conversations]
|
|
3910
4097
|
);
|
|
3911
|
-
const toggleStar =
|
|
4098
|
+
const toggleStar = useCallback22(
|
|
3912
4099
|
(conversationId) => {
|
|
3913
4100
|
const isStarred = starredSet.has(conversationId);
|
|
3914
4101
|
upsertState(conversationId, { Starred: isStarred ? 0 : 1 });
|
|
3915
4102
|
},
|
|
3916
4103
|
[upsertState, starredSet]
|
|
3917
4104
|
);
|
|
3918
|
-
const setArchived =
|
|
4105
|
+
const setArchived = useCallback22(
|
|
3919
4106
|
(conversationId, archived) => {
|
|
3920
4107
|
upsertState(conversationId, { Archived: archived ? 1 : 0 });
|
|
3921
4108
|
},
|
|
3922
4109
|
[upsertState]
|
|
3923
4110
|
);
|
|
3924
|
-
const setTrashed =
|
|
4111
|
+
const setTrashed = useCallback22(
|
|
3925
4112
|
(conversationId, trashed) => {
|
|
3926
4113
|
upsertState(conversationId, { Trashed: trashed ? 1 : 0 });
|
|
3927
4114
|
},
|
|
3928
4115
|
[upsertState]
|
|
3929
4116
|
);
|
|
3930
|
-
const setLabels =
|
|
4117
|
+
const setLabels = useCallback22(
|
|
3931
4118
|
(conversationId, labels) => {
|
|
3932
4119
|
upsertState(conversationId, { Labels: JSON.stringify(labels) });
|
|
3933
4120
|
},
|
|
3934
4121
|
[upsertState]
|
|
3935
4122
|
);
|
|
3936
|
-
const setFolder =
|
|
4123
|
+
const setFolder = useCallback22(
|
|
3937
4124
|
(conversationId, folder) => {
|
|
3938
4125
|
upsertState(conversationId, { Folder: folder });
|
|
3939
4126
|
},
|
|
@@ -3963,7 +4150,7 @@ function useConversations() {
|
|
|
3963
4150
|
}
|
|
3964
4151
|
|
|
3965
4152
|
// src/client/directory/useCommunities.ts
|
|
3966
|
-
import { useCallback as
|
|
4153
|
+
import { useCallback as useCallback23, useMemo as useMemo14 } from "react";
|
|
3967
4154
|
function useCommunities() {
|
|
3968
4155
|
const { records: communities, status } = useQuery("communities");
|
|
3969
4156
|
const communityMut = useMutations("communities");
|
|
@@ -3986,7 +4173,7 @@ function useCommunities() {
|
|
|
3986
4173
|
),
|
|
3987
4174
|
[memberships, user?.id]
|
|
3988
4175
|
);
|
|
3989
|
-
const createCommunity =
|
|
4176
|
+
const createCommunity = useCallback23(
|
|
3990
4177
|
async (name, opts) => {
|
|
3991
4178
|
const existing = communities.find((c) => c.data.Name === name);
|
|
3992
4179
|
if (existing) return existing.recordId;
|
|
@@ -4005,7 +4192,7 @@ function useCommunities() {
|
|
|
4005
4192
|
},
|
|
4006
4193
|
[communityMut, user?.id, communities]
|
|
4007
4194
|
);
|
|
4008
|
-
const updateCommunity =
|
|
4195
|
+
const updateCommunity = useCallback23(
|
|
4009
4196
|
(communityId, updates) => {
|
|
4010
4197
|
const existing = communities.find((c) => c.recordId === communityId);
|
|
4011
4198
|
if (!existing) return;
|
|
@@ -4013,7 +4200,7 @@ function useCommunities() {
|
|
|
4013
4200
|
},
|
|
4014
4201
|
[communityMut, communities]
|
|
4015
4202
|
);
|
|
4016
|
-
const joinCommunity =
|
|
4203
|
+
const joinCommunity = useCallback23(
|
|
4017
4204
|
async (communityId, userName) => {
|
|
4018
4205
|
if (!user?.id) return null;
|
|
4019
4206
|
const existing = memberships.find(
|
|
@@ -4031,7 +4218,7 @@ function useCommunities() {
|
|
|
4031
4218
|
},
|
|
4032
4219
|
[membershipMut, memberships, user?.id]
|
|
4033
4220
|
);
|
|
4034
|
-
const leaveCommunity =
|
|
4221
|
+
const leaveCommunity = useCallback23(
|
|
4035
4222
|
(communityId) => {
|
|
4036
4223
|
if (!user?.id) return;
|
|
4037
4224
|
const membership = memberships.find(
|
|
@@ -4043,13 +4230,13 @@ function useCommunities() {
|
|
|
4043
4230
|
},
|
|
4044
4231
|
[membershipMut, memberships, user?.id]
|
|
4045
4232
|
);
|
|
4046
|
-
const getMembersOf =
|
|
4233
|
+
const getMembersOf = useCallback23(
|
|
4047
4234
|
(communityId) => {
|
|
4048
4235
|
return membershipMap.get(communityId) ?? [];
|
|
4049
4236
|
},
|
|
4050
4237
|
[membershipMap]
|
|
4051
4238
|
);
|
|
4052
|
-
const lookupByName =
|
|
4239
|
+
const lookupByName = useCallback23(
|
|
4053
4240
|
(name) => {
|
|
4054
4241
|
const found = communities.find((c) => c.data.Name === name);
|
|
4055
4242
|
return found?.recordId ?? null;
|
|
@@ -4071,14 +4258,14 @@ function useCommunities() {
|
|
|
4071
4258
|
}
|
|
4072
4259
|
|
|
4073
4260
|
// src/client/directory/usePosts.ts
|
|
4074
|
-
import { useCallback as
|
|
4261
|
+
import { useCallback as useCallback24 } from "react";
|
|
4075
4262
|
function usePosts(opts) {
|
|
4076
4263
|
const { records: allPosts, status } = useQuery("posts");
|
|
4077
4264
|
const postMut = useMutations("posts");
|
|
4078
4265
|
const { user } = useUser();
|
|
4079
4266
|
const ready = status === "ready";
|
|
4080
4267
|
const posts = opts?.communityId ? allPosts.filter((p) => p.data.CommunityId === opts.communityId) : allPosts;
|
|
4081
|
-
const createPost =
|
|
4268
|
+
const createPost = useCallback24(
|
|
4082
4269
|
async (data) => {
|
|
4083
4270
|
const recordId = await postMut.create({
|
|
4084
4271
|
Title: data.title,
|
|
@@ -4096,7 +4283,7 @@ function usePosts(opts) {
|
|
|
4096
4283
|
},
|
|
4097
4284
|
[postMut, user?.id]
|
|
4098
4285
|
);
|
|
4099
|
-
const updatePost =
|
|
4286
|
+
const updatePost = useCallback24(
|
|
4100
4287
|
(postId, updates) => {
|
|
4101
4288
|
const existing = allPosts.find((p) => p.recordId === postId);
|
|
4102
4289
|
if (!existing) return;
|
|
@@ -4104,13 +4291,13 @@ function usePosts(opts) {
|
|
|
4104
4291
|
},
|
|
4105
4292
|
[postMut, allPosts]
|
|
4106
4293
|
);
|
|
4107
|
-
const deletePost =
|
|
4294
|
+
const deletePost = useCallback24(
|
|
4108
4295
|
(postId) => {
|
|
4109
4296
|
postMut.remove(postId);
|
|
4110
4297
|
},
|
|
4111
4298
|
[postMut]
|
|
4112
4299
|
);
|
|
4113
|
-
const setConversationId =
|
|
4300
|
+
const setConversationId = useCallback24(
|
|
4114
4301
|
(postId, conversationId) => {
|
|
4115
4302
|
updatePost(postId, { ConversationId: conversationId });
|
|
4116
4303
|
},
|
|
@@ -4127,7 +4314,7 @@ function usePosts(opts) {
|
|
|
4127
4314
|
}
|
|
4128
4315
|
|
|
4129
4316
|
// src/client/theme/DeepSpaceThemeProvider.tsx
|
|
4130
|
-
import { useEffect as
|
|
4317
|
+
import { useEffect as useEffect16 } from "react";
|
|
4131
4318
|
|
|
4132
4319
|
// src/client/theme/applyTheme.ts
|
|
4133
4320
|
function mix(color, pct, base = "transparent") {
|
|
@@ -4440,7 +4627,7 @@ function DeepSpaceThemeProvider({
|
|
|
4440
4627
|
children,
|
|
4441
4628
|
theme
|
|
4442
4629
|
}) {
|
|
4443
|
-
|
|
4630
|
+
useEffect16(() => {
|
|
4444
4631
|
const root = document.documentElement;
|
|
4445
4632
|
const config = theme ?? readThemeFromDOM(root);
|
|
4446
4633
|
applyDeepSpaceTheme(config, root);
|
|
@@ -4449,12 +4636,12 @@ function DeepSpaceThemeProvider({
|
|
|
4449
4636
|
}
|
|
4450
4637
|
|
|
4451
4638
|
// src/client/theme/useIsDarkTheme.ts
|
|
4452
|
-
import { useState as
|
|
4639
|
+
import { useState as useState14, useEffect as useEffect17 } from "react";
|
|
4453
4640
|
function useIsDarkTheme() {
|
|
4454
|
-
const [isDark, setIsDark] =
|
|
4641
|
+
const [isDark, setIsDark] = useState14(
|
|
4455
4642
|
() => typeof document === "undefined" || document.documentElement.dataset.uiTheme !== "light"
|
|
4456
4643
|
);
|
|
4457
|
-
|
|
4644
|
+
useEffect17(() => {
|
|
4458
4645
|
const update = () => {
|
|
4459
4646
|
setIsDark(document.documentElement.dataset.uiTheme !== "light");
|
|
4460
4647
|
};
|
|
@@ -4466,7 +4653,7 @@ function useIsDarkTheme() {
|
|
|
4466
4653
|
}
|
|
4467
4654
|
|
|
4468
4655
|
// src/client/platform/PlatformProvider.tsx
|
|
4469
|
-
import { createContext as createContext3, useContext as useContext5, useState as
|
|
4656
|
+
import { createContext as createContext3, useContext as useContext5, useState as useState15, useEffect as useEffect18, useRef as useRef15, useCallback as useCallback25 } from "react";
|
|
4470
4657
|
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
4471
4658
|
var PlatformContext = createContext3(null);
|
|
4472
4659
|
function usePlatform() {
|
|
@@ -4476,14 +4663,14 @@ function usePlatform() {
|
|
|
4476
4663
|
}
|
|
4477
4664
|
function useInbox() {
|
|
4478
4665
|
const { inbox, subscribeInbox } = usePlatform();
|
|
4479
|
-
|
|
4666
|
+
useEffect18(() => subscribeInbox(), [subscribeInbox]);
|
|
4480
4667
|
return inbox;
|
|
4481
4668
|
}
|
|
4482
4669
|
function PlatformProvider({ children }) {
|
|
4483
|
-
const [inbox, setInbox] =
|
|
4484
|
-
const inboxSubscribers =
|
|
4485
|
-
const [inboxActive, setInboxActive] =
|
|
4486
|
-
const subscribeInbox =
|
|
4670
|
+
const [inbox, setInbox] = useState15([]);
|
|
4671
|
+
const inboxSubscribers = useRef15(0);
|
|
4672
|
+
const [inboxActive, setInboxActive] = useState15(false);
|
|
4673
|
+
const subscribeInbox = useCallback25(() => {
|
|
4487
4674
|
inboxSubscribers.current++;
|
|
4488
4675
|
if (inboxSubscribers.current === 1) setInboxActive(true);
|
|
4489
4676
|
return () => {
|
|
@@ -4491,7 +4678,7 @@ function PlatformProvider({ children }) {
|
|
|
4491
4678
|
if (inboxSubscribers.current === 0) setInboxActive(false);
|
|
4492
4679
|
};
|
|
4493
4680
|
}, []);
|
|
4494
|
-
|
|
4681
|
+
useEffect18(() => {
|
|
4495
4682
|
if (!inboxActive) return;
|
|
4496
4683
|
let mounted = true;
|
|
4497
4684
|
let ws = null;
|
|
@@ -4549,7 +4736,7 @@ function PlatformProvider({ children }) {
|
|
|
4549
4736
|
setInbox([]);
|
|
4550
4737
|
};
|
|
4551
4738
|
}, [inboxActive]);
|
|
4552
|
-
const platformFetch =
|
|
4739
|
+
const platformFetch = useCallback25(async (path, init) => {
|
|
4553
4740
|
const token = await getAuthToken();
|
|
4554
4741
|
const headers = new Headers(init?.headers);
|
|
4555
4742
|
if (token) headers.set("Authorization", `Bearer ${token}`);
|
|
@@ -4560,28 +4747,28 @@ function PlatformProvider({ children }) {
|
|
|
4560
4747
|
}
|
|
4561
4748
|
|
|
4562
4749
|
// src/client/platform/usePlatformWS.ts
|
|
4563
|
-
import { useState as
|
|
4750
|
+
import { useState as useState16, useEffect as useEffect19, useRef as useRef16 } from "react";
|
|
4564
4751
|
var MAX_RECONNECT_DELAY = 1e4;
|
|
4565
4752
|
var BASE_RECONNECT_DELAY = 500;
|
|
4566
4753
|
function usePlatformWS(options) {
|
|
4567
4754
|
const { path, scopeId, initialState, onMessage } = options;
|
|
4568
|
-
const wsRef =
|
|
4569
|
-
const pingIntervalRef =
|
|
4570
|
-
const [state, setState] =
|
|
4571
|
-
const reconnectAttemptRef =
|
|
4572
|
-
const reconnectTimerRef =
|
|
4573
|
-
const mountedRef =
|
|
4574
|
-
const onMessageRef =
|
|
4755
|
+
const wsRef = useRef16(null);
|
|
4756
|
+
const pingIntervalRef = useRef16(null);
|
|
4757
|
+
const [state, setState] = useState16(initialState);
|
|
4758
|
+
const reconnectAttemptRef = useRef16(0);
|
|
4759
|
+
const reconnectTimerRef = useRef16(null);
|
|
4760
|
+
const mountedRef = useRef16(true);
|
|
4761
|
+
const onMessageRef = useRef16(onMessage);
|
|
4575
4762
|
onMessageRef.current = onMessage;
|
|
4576
|
-
const initialStateRef =
|
|
4763
|
+
const initialStateRef = useRef16(initialState);
|
|
4577
4764
|
initialStateRef.current = initialState;
|
|
4578
|
-
|
|
4765
|
+
useEffect19(() => {
|
|
4579
4766
|
mountedRef.current = true;
|
|
4580
4767
|
return () => {
|
|
4581
4768
|
mountedRef.current = false;
|
|
4582
4769
|
};
|
|
4583
4770
|
}, []);
|
|
4584
|
-
|
|
4771
|
+
useEffect19(() => {
|
|
4585
4772
|
if (!scopeId) return;
|
|
4586
4773
|
setState(initialStateRef.current);
|
|
4587
4774
|
reconnectAttemptRef.current = 0;
|
|
@@ -4640,7 +4827,7 @@ function usePlatformWS(options) {
|
|
|
4640
4827
|
wsRef.current = null;
|
|
4641
4828
|
};
|
|
4642
4829
|
}, [scopeId, path]);
|
|
4643
|
-
const send =
|
|
4830
|
+
const send = useRef16((msg) => {
|
|
4644
4831
|
wsRef.current?.send(JSON.stringify(msg));
|
|
4645
4832
|
}).current;
|
|
4646
4833
|
return { state, send };
|
|
@@ -4802,7 +4989,7 @@ function decodeAiStreamChunk(chunk) {
|
|
|
4802
4989
|
}
|
|
4803
4990
|
|
|
4804
4991
|
// src/client/subscriptions/useSubscription.ts
|
|
4805
|
-
import { useCallback as
|
|
4992
|
+
import { useCallback as useCallback26, useEffect as useEffect20, useState as useState17 } from "react";
|
|
4806
4993
|
|
|
4807
4994
|
// src/shared/subscription.ts
|
|
4808
4995
|
var ENTITLED_STATUSES = /* @__PURE__ */ new Set([
|
|
@@ -4833,7 +5020,7 @@ async function authedJson(path, init) {
|
|
|
4833
5020
|
return data;
|
|
4834
5021
|
}
|
|
4835
5022
|
function useSubscription() {
|
|
4836
|
-
const [state, setState] =
|
|
5023
|
+
const [state, setState] = useState17({
|
|
4837
5024
|
tier: "free",
|
|
4838
5025
|
status: "none",
|
|
4839
5026
|
interval: null,
|
|
@@ -4842,9 +5029,9 @@ function useSubscription() {
|
|
|
4842
5029
|
trialEndsAt: null,
|
|
4843
5030
|
plans: []
|
|
4844
5031
|
});
|
|
4845
|
-
const [isLoading, setLoading] =
|
|
4846
|
-
const [error, setError] =
|
|
4847
|
-
const refresh =
|
|
5032
|
+
const [isLoading, setLoading] = useState17(true);
|
|
5033
|
+
const [error, setError] = useState17(null);
|
|
5034
|
+
const refresh = useCallback26(async () => {
|
|
4848
5035
|
setLoading(true);
|
|
4849
5036
|
try {
|
|
4850
5037
|
const r = await authedJson("/_deepspace/subscriptions/me");
|
|
@@ -4864,15 +5051,15 @@ function useSubscription() {
|
|
|
4864
5051
|
setLoading(false);
|
|
4865
5052
|
}
|
|
4866
5053
|
}, []);
|
|
4867
|
-
|
|
5054
|
+
useEffect20(() => {
|
|
4868
5055
|
refresh();
|
|
4869
5056
|
}, [refresh]);
|
|
4870
5057
|
const entitled = isEntitled(state.tier, state.status);
|
|
4871
|
-
const hasTier =
|
|
5058
|
+
const hasTier = useCallback26(
|
|
4872
5059
|
(slug) => state.tier === slug && isEntitled(state.tier, state.status),
|
|
4873
5060
|
[state.tier, state.status]
|
|
4874
5061
|
);
|
|
4875
|
-
const isAtLeast =
|
|
5062
|
+
const isAtLeast = useCallback26(
|
|
4876
5063
|
(slug) => {
|
|
4877
5064
|
if (!isEntitled(state.tier, state.status)) return false;
|
|
4878
5065
|
const targetRank = state.plans.find((p) => p.slug === slug)?.rank;
|
|
@@ -4882,7 +5069,7 @@ function useSubscription() {
|
|
|
4882
5069
|
},
|
|
4883
5070
|
[state.plans, state.tier, state.status]
|
|
4884
5071
|
);
|
|
4885
|
-
const subscribe =
|
|
5072
|
+
const subscribe = useCallback26(
|
|
4886
5073
|
async (planSlug, opts) => {
|
|
4887
5074
|
const result = await authedJson("/_deepspace/subscriptions/checkout", {
|
|
4888
5075
|
method: "POST",
|
|
@@ -4902,7 +5089,7 @@ function useSubscription() {
|
|
|
4902
5089
|
},
|
|
4903
5090
|
[refresh]
|
|
4904
5091
|
);
|
|
4905
|
-
const openPortal =
|
|
5092
|
+
const openPortal = useCallback26(
|
|
4906
5093
|
async (returnUrl) => {
|
|
4907
5094
|
return authedJson("/_deepspace/subscriptions/portal", {
|
|
4908
5095
|
method: "POST",
|
|
@@ -4971,7 +5158,7 @@ function PricingTable(props) {
|
|
|
4971
5158
|
}
|
|
4972
5159
|
|
|
4973
5160
|
// src/client/charges/useCheckout.ts
|
|
4974
|
-
import { useCallback as
|
|
5161
|
+
import { useCallback as useCallback27, useEffect as useEffect21, useMemo as useMemo15, useState as useState18 } from "react";
|
|
4975
5162
|
async function authedJson2(path, init) {
|
|
4976
5163
|
const token = await getAuthToken();
|
|
4977
5164
|
const res = await fetch(path, {
|
|
@@ -4990,10 +5177,10 @@ async function authedJson2(path, init) {
|
|
|
4990
5177
|
return data;
|
|
4991
5178
|
}
|
|
4992
5179
|
function useCheckout(opts) {
|
|
4993
|
-
const [purchases, setPurchases] =
|
|
4994
|
-
const [isLoading, setLoading] =
|
|
4995
|
-
const [error, setError] =
|
|
4996
|
-
const refresh =
|
|
5180
|
+
const [purchases, setPurchases] = useState18([]);
|
|
5181
|
+
const [isLoading, setLoading] = useState18(true);
|
|
5182
|
+
const [error, setError] = useState18(null);
|
|
5183
|
+
const refresh = useCallback27(async () => {
|
|
4997
5184
|
setLoading(true);
|
|
4998
5185
|
try {
|
|
4999
5186
|
const r = await authedJson2(
|
|
@@ -5007,10 +5194,10 @@ function useCheckout(opts) {
|
|
|
5007
5194
|
setLoading(false);
|
|
5008
5195
|
}
|
|
5009
5196
|
}, []);
|
|
5010
|
-
|
|
5197
|
+
useEffect21(() => {
|
|
5011
5198
|
refresh();
|
|
5012
5199
|
}, [refresh]);
|
|
5013
|
-
const chargeOnce =
|
|
5200
|
+
const chargeOnce = useCallback27(
|
|
5014
5201
|
async (chargeOpts) => {
|
|
5015
5202
|
setError(null);
|
|
5016
5203
|
const common = {
|
|
@@ -5044,7 +5231,7 @@ function useCheckout(opts) {
|
|
|
5044
5231
|
},
|
|
5045
5232
|
[]
|
|
5046
5233
|
);
|
|
5047
|
-
const ownsProduct =
|
|
5234
|
+
const ownsProduct = useCallback27(
|
|
5048
5235
|
(productId) => purchases.some((p) => p.productId === productId),
|
|
5049
5236
|
[purchases]
|
|
5050
5237
|
);
|
|
@@ -5895,9 +6082,9 @@ AlertDescription.displayName = "AlertDescription";
|
|
|
5895
6082
|
import {
|
|
5896
6083
|
createContext as createContext4,
|
|
5897
6084
|
useContext as useContext6,
|
|
5898
|
-
useState as
|
|
5899
|
-
useCallback as
|
|
5900
|
-
useEffect as
|
|
6085
|
+
useState as useState19,
|
|
6086
|
+
useCallback as useCallback28,
|
|
6087
|
+
useEffect as useEffect22
|
|
5901
6088
|
} from "react";
|
|
5902
6089
|
import { jsx as jsx28, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
5903
6090
|
function CheckCircleIcon({ className }) {
|
|
@@ -5944,14 +6131,14 @@ function ToastProvider({
|
|
|
5944
6131
|
position = "bottom-right",
|
|
5945
6132
|
maxToasts = 5
|
|
5946
6133
|
}) {
|
|
5947
|
-
const [toasts, setToasts] =
|
|
5948
|
-
const dismiss =
|
|
6134
|
+
const [toasts, setToasts] = useState19([]);
|
|
6135
|
+
const dismiss = useCallback28((id) => {
|
|
5949
6136
|
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
5950
6137
|
}, []);
|
|
5951
|
-
const dismissAll =
|
|
6138
|
+
const dismissAll = useCallback28(() => {
|
|
5952
6139
|
setToasts([]);
|
|
5953
6140
|
}, []);
|
|
5954
|
-
const addToast =
|
|
6141
|
+
const addToast = useCallback28(
|
|
5955
6142
|
(options) => {
|
|
5956
6143
|
const id = Math.random().toString(36).slice(2);
|
|
5957
6144
|
const duration = options.duration ?? 5e3;
|
|
@@ -5965,23 +6152,23 @@ function ToastProvider({
|
|
|
5965
6152
|
},
|
|
5966
6153
|
[dismiss, maxToasts]
|
|
5967
6154
|
);
|
|
5968
|
-
const toast =
|
|
6155
|
+
const toast = useCallback28(
|
|
5969
6156
|
(options) => addToast(options),
|
|
5970
6157
|
[addToast]
|
|
5971
6158
|
);
|
|
5972
|
-
const success =
|
|
6159
|
+
const success = useCallback28(
|
|
5973
6160
|
(title, description) => addToast({ type: "success", title, description }),
|
|
5974
6161
|
[addToast]
|
|
5975
6162
|
);
|
|
5976
|
-
const error =
|
|
6163
|
+
const error = useCallback28(
|
|
5977
6164
|
(title, description) => addToast({ type: "error", title, description }),
|
|
5978
6165
|
[addToast]
|
|
5979
6166
|
);
|
|
5980
|
-
const warning =
|
|
6167
|
+
const warning = useCallback28(
|
|
5981
6168
|
(title, description) => addToast({ type: "warning", title, description }),
|
|
5982
6169
|
[addToast]
|
|
5983
6170
|
);
|
|
5984
|
-
const info =
|
|
6171
|
+
const info = useCallback28(
|
|
5985
6172
|
(title, description) => addToast({ type: "info", title, description }),
|
|
5986
6173
|
[addToast]
|
|
5987
6174
|
);
|
|
@@ -6018,8 +6205,8 @@ var TOAST_CONFIG = {
|
|
|
6018
6205
|
};
|
|
6019
6206
|
function ToastItem({ toast, onDismiss }) {
|
|
6020
6207
|
const { Icon: Icon2, accent, icon } = TOAST_CONFIG[toast.type];
|
|
6021
|
-
const [exiting, setExiting] =
|
|
6022
|
-
|
|
6208
|
+
const [exiting, setExiting] = useState19(false);
|
|
6209
|
+
useEffect22(() => {
|
|
6023
6210
|
if (exiting) {
|
|
6024
6211
|
const timer = setTimeout(onDismiss, 150);
|
|
6025
6212
|
return () => clearTimeout(timer);
|
|
@@ -6701,6 +6888,7 @@ export {
|
|
|
6701
6888
|
useGameRoom,
|
|
6702
6889
|
useInbox,
|
|
6703
6890
|
useIsDarkTheme,
|
|
6891
|
+
useJobs,
|
|
6704
6892
|
useMessages,
|
|
6705
6893
|
useMutations,
|
|
6706
6894
|
usePlatform,
|