deepspace 0.3.11 → 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 +258 -120
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +39 -15
- package/dist/index.js +76 -45
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +72 -73
- package/dist/server.js +368 -337
- package/dist/server.js.map +1 -1
- package/dist/worker.d.ts +72 -73
- package/dist/worker.js +422 -391
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -396,6 +396,7 @@ declare const MSG: {
|
|
|
396
396
|
readonly USER_LIST: "user.list";
|
|
397
397
|
readonly SET_ROLE: "user.set_role";
|
|
398
398
|
readonly USER_UPDATE: "user.update";
|
|
399
|
+
readonly AUTH: "auth";
|
|
399
400
|
readonly YJS_JOIN: "yjs.join";
|
|
400
401
|
readonly YJS_LEAVE: "yjs.leave";
|
|
401
402
|
readonly ACK: "records.ack";
|
|
@@ -639,6 +640,8 @@ type ServerMessage = BaseMessage<typeof MSG.QUERY_RESULT, {
|
|
|
639
640
|
error: string;
|
|
640
641
|
}> | BaseMessage<typeof MSG.RESUBSCRIBE, EmptyPayload> | BaseMessage<typeof MSG.LIST_SCHEMAS, {
|
|
641
642
|
schemas: unknown;
|
|
643
|
+
}> | BaseMessage<typeof MSG.AUTH, {
|
|
644
|
+
canWrite: boolean;
|
|
642
645
|
}> | BaseMessage<typeof MSG.USER_INFO, unknown> | BaseMessage<typeof MSG.USER_LIST, {
|
|
643
646
|
users: unknown[];
|
|
644
647
|
}> | BaseMessage<typeof MSG.YJS_JOIN, {
|
|
@@ -5972,13 +5975,20 @@ interface UseGameRoomResult {
|
|
|
5972
5975
|
running: boolean;
|
|
5973
5976
|
/** Whether WebSocket is connected */
|
|
5974
5977
|
connected: boolean;
|
|
5975
|
-
/**
|
|
5978
|
+
/**
|
|
5979
|
+
* Whether this connection has write access. False for viewers /
|
|
5980
|
+
* unauthenticated spectators — they receive state broadcasts but the
|
|
5981
|
+
* send callbacks below no-op. UIs should disable input controls when
|
|
5982
|
+
* false so spectators see why their actions don't take effect.
|
|
5983
|
+
*/
|
|
5984
|
+
canWrite: boolean;
|
|
5985
|
+
/** Send a game input (no-op for spectators) */
|
|
5976
5986
|
sendInput: (action: string, data?: Record<string, unknown>) => void;
|
|
5977
|
-
/** Mark self as ready */
|
|
5987
|
+
/** Mark self as ready (no-op for spectators) */
|
|
5978
5988
|
setReady: () => void;
|
|
5979
|
-
/** Request game start */
|
|
5989
|
+
/** Request game start (no-op for spectators) */
|
|
5980
5990
|
startGame: () => void;
|
|
5981
|
-
/** Request game end */
|
|
5991
|
+
/** Request game end (no-op for spectators) */
|
|
5982
5992
|
endGame: () => void;
|
|
5983
5993
|
}
|
|
5984
5994
|
declare function useGameRoom(roomId: string): UseGameRoomResult;
|
|
@@ -6019,21 +6029,28 @@ interface UseCanvasResult {
|
|
|
6019
6029
|
viewports: ViewportClient[];
|
|
6020
6030
|
/** Whether WebSocket is connected */
|
|
6021
6031
|
connected: boolean;
|
|
6022
|
-
/**
|
|
6032
|
+
/**
|
|
6033
|
+
* Whether this connection has write access (member/admin role). The
|
|
6034
|
+
* write callbacks below no-op when this is false; UIs should also use
|
|
6035
|
+
* it to disable controls so viewers see why their clicks do nothing.
|
|
6036
|
+
* Viewport reporting stays available regardless — it's presence info.
|
|
6037
|
+
*/
|
|
6038
|
+
canWrite: boolean;
|
|
6039
|
+
/** Add a shape (no-op when canWrite is false) */
|
|
6023
6040
|
addShape: (shape: Partial<CanvasShapeClient>) => void;
|
|
6024
|
-
/** Move a shape */
|
|
6041
|
+
/** Move a shape (no-op when canWrite is false) */
|
|
6025
6042
|
moveShape: (shapeId: string, x: number, y: number) => void;
|
|
6026
|
-
/** Resize a shape */
|
|
6043
|
+
/** Resize a shape (no-op when canWrite is false) */
|
|
6027
6044
|
resizeShape: (shapeId: string, width: number, height: number, x?: number, y?: number) => void;
|
|
6028
|
-
/** Delete a shape */
|
|
6045
|
+
/** Delete a shape (no-op when canWrite is false) */
|
|
6029
6046
|
deleteShape: (shapeId: string) => void;
|
|
6030
|
-
/** Update shape properties */
|
|
6047
|
+
/** Update shape properties (no-op when canWrite is false) */
|
|
6031
6048
|
updateShape: (shapeId: string, props: Record<string, unknown>) => void;
|
|
6032
|
-
/** Report local viewport */
|
|
6049
|
+
/** Report local viewport (allowed for viewers — presence-like) */
|
|
6033
6050
|
setViewport: (viewport: Omit<ViewportClient, 'userId'>) => void;
|
|
6034
|
-
/** Undo last action */
|
|
6051
|
+
/** Undo last action (no-op when canWrite is false) */
|
|
6035
6052
|
undo: () => void;
|
|
6036
|
-
/** Redo last undone action */
|
|
6053
|
+
/** Redo last undone action (no-op when canWrite is false) */
|
|
6037
6054
|
redo: () => void;
|
|
6038
6055
|
}
|
|
6039
6056
|
declare function useCanvas(roomId: string): UseCanvasResult;
|
|
@@ -6070,11 +6087,18 @@ interface UseCronMonitorResult {
|
|
|
6070
6087
|
history: CronHistoryEntry[];
|
|
6071
6088
|
/** Whether WebSocket is connected */
|
|
6072
6089
|
connected: boolean;
|
|
6073
|
-
/**
|
|
6090
|
+
/**
|
|
6091
|
+
* Whether this connection can mutate cron state (trigger / pause /
|
|
6092
|
+
* resume). False for viewers and unauthenticated connections — the
|
|
6093
|
+
* mutation callbacks below no-op and UIs should disable those
|
|
6094
|
+
* controls. Reading tasks/history stays available either way.
|
|
6095
|
+
*/
|
|
6096
|
+
canWrite: boolean;
|
|
6097
|
+
/** Manually trigger a task (no-op when canWrite is false) */
|
|
6074
6098
|
trigger: (taskName: string) => void;
|
|
6075
|
-
/** Pause a task */
|
|
6099
|
+
/** Pause a task (no-op when canWrite is false) */
|
|
6076
6100
|
pause: (taskName: string) => void;
|
|
6077
|
-
/** Resume a paused task */
|
|
6101
|
+
/** Resume a paused task (no-op when canWrite is false) */
|
|
6078
6102
|
resume: (taskName: string) => void;
|
|
6079
6103
|
}
|
|
6080
6104
|
declare function useCronMonitor(roomId: string): UseCronMonitorResult;
|
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",
|
|
@@ -717,12 +724,17 @@ function DeepSpaceAuthProvider({ children }) {
|
|
|
717
724
|
}
|
|
718
725
|
|
|
719
726
|
// src/client/auth/hooks.ts
|
|
727
|
+
var sessionHasResolved = false;
|
|
728
|
+
function stickyIsLoaded(isPending) {
|
|
729
|
+
if (!isPending) sessionHasResolved = true;
|
|
730
|
+
return sessionHasResolved;
|
|
731
|
+
}
|
|
720
732
|
function useAuth() {
|
|
721
733
|
const session = useSession();
|
|
722
734
|
const isSignedIn = !!session.data?.user;
|
|
723
735
|
const userId = session.data?.user?.id ?? null;
|
|
724
736
|
return {
|
|
725
|
-
isLoaded:
|
|
737
|
+
isLoaded: stickyIsLoaded(session.isPending),
|
|
726
738
|
isSignedIn,
|
|
727
739
|
userId,
|
|
728
740
|
sessionId: session.data?.session?.id ?? null
|
|
@@ -732,7 +744,7 @@ function useAuthUser() {
|
|
|
732
744
|
const session = useSession();
|
|
733
745
|
const user = session.data?.user ?? null;
|
|
734
746
|
return {
|
|
735
|
-
isLoaded:
|
|
747
|
+
isLoaded: stickyIsLoaded(session.isPending),
|
|
736
748
|
isSignedIn: !!user,
|
|
737
749
|
user: user ? {
|
|
738
750
|
id: user.id,
|
|
@@ -2848,6 +2860,7 @@ function useGameRoom(roomId) {
|
|
|
2848
2860
|
const [players, setPlayers] = useState8([]);
|
|
2849
2861
|
const [running, setRunning] = useState8(false);
|
|
2850
2862
|
const [connected, setConnected] = useState8(false);
|
|
2863
|
+
const [canWrite, setCanWrite] = useState8(false);
|
|
2851
2864
|
const wsRef = useRef9(null);
|
|
2852
2865
|
useEffect11(() => {
|
|
2853
2866
|
let ws = null;
|
|
@@ -2869,6 +2882,9 @@ function useGameRoom(roomId) {
|
|
|
2869
2882
|
};
|
|
2870
2883
|
ws.onmessage = (event) => {
|
|
2871
2884
|
dispatch(event.data, {
|
|
2885
|
+
[MSG.AUTH]: (p) => {
|
|
2886
|
+
setCanWrite(p.canWrite);
|
|
2887
|
+
},
|
|
2872
2888
|
[MSG.GAME_STATE]: (p) => {
|
|
2873
2889
|
setGameState(p.state);
|
|
2874
2890
|
setTick(p.tick);
|
|
@@ -2906,6 +2922,7 @@ function useGameRoom(roomId) {
|
|
|
2906
2922
|
wsLog("disconnected", `game:${roomId}`);
|
|
2907
2923
|
wsRef.current = null;
|
|
2908
2924
|
setConnected(false);
|
|
2925
|
+
setCanWrite(false);
|
|
2909
2926
|
if (alive) reconnectTimer = setTimeout(connect, 1e3);
|
|
2910
2927
|
};
|
|
2911
2928
|
ws.onerror = () => ws?.close();
|
|
@@ -2924,27 +2941,23 @@ function useGameRoom(roomId) {
|
|
|
2924
2941
|
wsRef.current = null;
|
|
2925
2942
|
};
|
|
2926
2943
|
}, [roomId]);
|
|
2927
|
-
const
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
const endGame = useCallback10(() =>
|
|
2943
|
-
|
|
2944
|
-
if (!ws || ws.readyState !== WebSocket.OPEN) return;
|
|
2945
|
-
ws.send(encode(clientBuild.gameEnd()));
|
|
2946
|
-
}, []);
|
|
2947
|
-
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 };
|
|
2948
2961
|
}
|
|
2949
2962
|
|
|
2950
2963
|
// src/client/storage/hooks/useCanvas.ts
|
|
@@ -2953,6 +2966,7 @@ function useCanvas(roomId) {
|
|
|
2953
2966
|
const [shapes, setShapes] = useState9([]);
|
|
2954
2967
|
const [viewports, setViewports] = useState9([]);
|
|
2955
2968
|
const [connected, setConnected] = useState9(false);
|
|
2969
|
+
const [canWrite, setCanWrite] = useState9(false);
|
|
2956
2970
|
const wsRef = useRef10(null);
|
|
2957
2971
|
useEffect12(() => {
|
|
2958
2972
|
let ws = null;
|
|
@@ -2974,6 +2988,9 @@ function useCanvas(roomId) {
|
|
|
2974
2988
|
};
|
|
2975
2989
|
ws.onmessage = (event) => {
|
|
2976
2990
|
dispatch(event.data, {
|
|
2991
|
+
[MSG.AUTH]: (p) => {
|
|
2992
|
+
setCanWrite(p.canWrite);
|
|
2993
|
+
},
|
|
2977
2994
|
[MSG.CANVAS_SHAPES]: (p) => {
|
|
2978
2995
|
setShapes(p.shapes);
|
|
2979
2996
|
setViewports(p.viewports);
|
|
@@ -3026,6 +3043,7 @@ function useCanvas(roomId) {
|
|
|
3026
3043
|
wsLog("disconnected", `canvas:${roomId}`);
|
|
3027
3044
|
wsRef.current = null;
|
|
3028
3045
|
setConnected(false);
|
|
3046
|
+
setCanWrite(false);
|
|
3029
3047
|
if (alive) reconnectTimer = setTimeout(connect, 1e3);
|
|
3030
3048
|
};
|
|
3031
3049
|
ws.onerror = () => ws?.close();
|
|
@@ -3052,33 +3070,40 @@ function useCanvas(roomId) {
|
|
|
3052
3070
|
},
|
|
3053
3071
|
[]
|
|
3054
3072
|
);
|
|
3073
|
+
const sendWrite = useCallback11(
|
|
3074
|
+
(message) => {
|
|
3075
|
+
if (!canWrite) return;
|
|
3076
|
+
sendBuilt(message);
|
|
3077
|
+
},
|
|
3078
|
+
[sendBuilt, canWrite]
|
|
3079
|
+
);
|
|
3055
3080
|
const addShape = useCallback11(
|
|
3056
|
-
(shape) =>
|
|
3057
|
-
[
|
|
3081
|
+
(shape) => sendWrite(clientBuild.canvasAdd(shape)),
|
|
3082
|
+
[sendWrite]
|
|
3058
3083
|
);
|
|
3059
3084
|
const moveShape = useCallback11(
|
|
3060
|
-
(shapeId, x, y) =>
|
|
3061
|
-
[
|
|
3085
|
+
(shapeId, x, y) => sendWrite(clientBuild.canvasMove(shapeId, x, y)),
|
|
3086
|
+
[sendWrite]
|
|
3062
3087
|
);
|
|
3063
3088
|
const resizeShape = useCallback11(
|
|
3064
|
-
(shapeId, width, height, x, y) =>
|
|
3065
|
-
[
|
|
3089
|
+
(shapeId, width, height, x, y) => sendWrite(clientBuild.canvasResize(shapeId, width, height, x, y)),
|
|
3090
|
+
[sendWrite]
|
|
3066
3091
|
);
|
|
3067
3092
|
const deleteShape = useCallback11(
|
|
3068
|
-
(shapeId) =>
|
|
3069
|
-
[
|
|
3093
|
+
(shapeId) => sendWrite(clientBuild.canvasDelete(shapeId)),
|
|
3094
|
+
[sendWrite]
|
|
3070
3095
|
);
|
|
3071
3096
|
const updateShape = useCallback11(
|
|
3072
|
-
(shapeId, props) =>
|
|
3073
|
-
[
|
|
3097
|
+
(shapeId, props) => sendWrite(clientBuild.canvasUpdate(shapeId, props)),
|
|
3098
|
+
[sendWrite]
|
|
3074
3099
|
);
|
|
3075
3100
|
const setViewport = useCallback11(
|
|
3076
3101
|
(viewport) => sendBuilt(clientBuild.canvasViewport(viewport)),
|
|
3077
3102
|
[sendBuilt]
|
|
3078
3103
|
);
|
|
3079
|
-
const undo = useCallback11(() =>
|
|
3080
|
-
const redo = useCallback11(() =>
|
|
3081
|
-
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 };
|
|
3082
3107
|
}
|
|
3083
3108
|
|
|
3084
3109
|
// src/client/storage/hooks/useCronMonitor.ts
|
|
@@ -3087,6 +3112,7 @@ function useCronMonitor(roomId) {
|
|
|
3087
3112
|
const [tasks, setTasks] = useState10([]);
|
|
3088
3113
|
const [history, setHistory] = useState10([]);
|
|
3089
3114
|
const [connected, setConnected] = useState10(false);
|
|
3115
|
+
const [canWrite, setCanWrite] = useState10(false);
|
|
3090
3116
|
const wsRef = useRef11(null);
|
|
3091
3117
|
useEffect13(() => {
|
|
3092
3118
|
let ws = null;
|
|
@@ -3104,6 +3130,9 @@ function useCronMonitor(roomId) {
|
|
|
3104
3130
|
ws.onopen = () => setConnected(true);
|
|
3105
3131
|
ws.onmessage = (event) => {
|
|
3106
3132
|
dispatch(event.data, {
|
|
3133
|
+
[MSG.AUTH]: (p) => {
|
|
3134
|
+
setCanWrite(p.canWrite);
|
|
3135
|
+
},
|
|
3107
3136
|
[MSG.CRON_TASKS]: (p) => {
|
|
3108
3137
|
setTasks(p.tasks);
|
|
3109
3138
|
},
|
|
@@ -3119,6 +3148,7 @@ function useCronMonitor(roomId) {
|
|
|
3119
3148
|
ws.onclose = () => {
|
|
3120
3149
|
wsRef.current = null;
|
|
3121
3150
|
setConnected(false);
|
|
3151
|
+
setCanWrite(false);
|
|
3122
3152
|
if (alive) reconnectTimer = setTimeout(connect, 1e3);
|
|
3123
3153
|
};
|
|
3124
3154
|
ws.onerror = () => ws?.close();
|
|
@@ -3131,27 +3161,28 @@ function useCronMonitor(roomId) {
|
|
|
3131
3161
|
wsRef.current = null;
|
|
3132
3162
|
};
|
|
3133
3163
|
}, [roomId]);
|
|
3134
|
-
const
|
|
3164
|
+
const sendWrite = useCallback12(
|
|
3135
3165
|
(message) => {
|
|
3166
|
+
if (!canWrite) return;
|
|
3136
3167
|
const ws = wsRef.current;
|
|
3137
3168
|
if (!ws || ws.readyState !== WebSocket.OPEN) return;
|
|
3138
3169
|
ws.send(encode(message));
|
|
3139
3170
|
},
|
|
3140
|
-
[]
|
|
3171
|
+
[canWrite]
|
|
3141
3172
|
);
|
|
3142
3173
|
const trigger = useCallback12(
|
|
3143
|
-
(taskName) =>
|
|
3144
|
-
[
|
|
3174
|
+
(taskName) => sendWrite(clientBuild.cronTrigger(taskName)),
|
|
3175
|
+
[sendWrite]
|
|
3145
3176
|
);
|
|
3146
3177
|
const pause = useCallback12(
|
|
3147
|
-
(taskName) =>
|
|
3148
|
-
[
|
|
3178
|
+
(taskName) => sendWrite(clientBuild.cronPause(taskName)),
|
|
3179
|
+
[sendWrite]
|
|
3149
3180
|
);
|
|
3150
3181
|
const resume = useCallback12(
|
|
3151
|
-
(taskName) =>
|
|
3152
|
-
[
|
|
3182
|
+
(taskName) => sendWrite(clientBuild.cronResume(taskName)),
|
|
3183
|
+
[sendWrite]
|
|
3153
3184
|
);
|
|
3154
|
-
return { tasks, history, connected, trigger, pause, resume };
|
|
3185
|
+
return { tasks, history, connected, canWrite, trigger, pause, resume };
|
|
3155
3186
|
}
|
|
3156
3187
|
|
|
3157
3188
|
// src/client/storage/hooks/useJobs.ts
|