deepspace 0.3.9 → 0.3.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/dist/cli.js +96 -18
  2. package/dist/cli.js.map +1 -1
  3. package/dist/index.d.ts +160 -1
  4. package/dist/index.js +283 -126
  5. package/dist/index.js.map +1 -1
  6. package/dist/server.d.ts +172 -2
  7. package/dist/server.js +581 -1
  8. package/dist/server.js.map +1 -1
  9. package/dist/worker.d.ts +252 -2
  10. package/dist/worker.js +588 -1
  11. package/dist/worker.js.map +1 -1
  12. package/features/admin-page/feature.json +29 -0
  13. package/features/admin-page/src/AdminPage.tsx +292 -0
  14. package/features/admin-page/src/admin-schema.ts +20 -0
  15. package/features/ai-chat/feature.json +41 -0
  16. package/features/ai-chat/src/AiChatPage.tsx +692 -0
  17. package/features/ai-chat/src/ChatPanel.tsx +1098 -0
  18. package/features/ai-chat/src/ai-chat-schema.ts +11 -0
  19. package/features/canvas/feature.json +45 -0
  20. package/features/canvas/src/CanvasEditorPage.tsx +87 -0
  21. package/features/canvas/src/CanvasListPage.tsx +202 -0
  22. package/features/canvas/src/canvas-schema.ts +33 -0
  23. package/features/canvas/src/components/CanvasToolbar.tsx +170 -0
  24. package/features/canvas/src/components/CanvasView.tsx +369 -0
  25. package/features/canvas/src/components/ShapeRenderer.tsx +114 -0
  26. package/features/cron/feature.json +33 -0
  27. package/features/cron/src/CronLogPage.tsx +100 -0
  28. package/features/cron/src/cron.ts +25 -0
  29. package/features/docs/feature.json +96 -0
  30. package/features/docs/src/DocsEditorPage.tsx +1012 -0
  31. package/features/docs/src/DocsListPage.tsx +951 -0
  32. package/features/docs/src/DocsOutlinePanel.tsx +68 -0
  33. package/features/docs/src/DocsPresence.tsx +138 -0
  34. package/features/docs/src/InviteDialog.tsx +336 -0
  35. package/features/docs/src/LibrarySidebar.tsx +464 -0
  36. package/features/docs/src/docs-favorites.ts +18 -0
  37. package/features/docs/src/docs-library-types.ts +15 -0
  38. package/features/docs/src/docs-schema.ts +80 -0
  39. package/features/docs/src/docs-ui.css +309 -0
  40. package/features/docs/src/editor/DocEditorSurface.tsx +257 -0
  41. package/features/docs/src/editor/DocsTiptapToolbar.tsx +560 -0
  42. package/features/docs/src/editor/useDocEditor.ts +206 -0
  43. package/features/docs/src/use-yjs-room-with-awareness.ts +285 -0
  44. package/features/file-attachments/feature.json +42 -0
  45. package/features/file-attachments/src/AttachmentsPage.tsx +864 -0
  46. package/features/file-attachments/src/attachments-constants.ts +9 -0
  47. package/features/file-attachments/src/attachments-schema.ts +45 -0
  48. package/features/file-attachments/src/useFilePreview.ts +471 -0
  49. package/features/file-attachments/src/useMimeTypeDetection.ts +138 -0
  50. package/features/file-manager/feature.json +24 -0
  51. package/features/file-manager/src/FileManagerPage.tsx +330 -0
  52. package/features/integration-test/feature.json +18 -0
  53. package/features/integration-test/src/IntegrationTestPage.tsx +423 -0
  54. package/features/integration-test/src/integration.spec.ts +42 -0
  55. package/features/items/feature.json +33 -0
  56. package/features/items/src/ItemsPage.tsx +325 -0
  57. package/features/items/src/items-constants.ts +10 -0
  58. package/features/items/src/items-schema.ts +27 -0
  59. package/features/kanban/feature.json +18 -0
  60. package/features/kanban/src/Kanban.tsx +283 -0
  61. package/features/landing/feature.json +62 -0
  62. package/features/landing/src/LandingPage.tsx +627 -0
  63. package/features/landing/src/primitives.tsx +389 -0
  64. package/features/landing/src/sections/FAQSection.tsx +110 -0
  65. package/features/landing/src/sections/FeaturesGridSection.tsx +311 -0
  66. package/features/landing/src/sections/HowItWorksSection.tsx +62 -0
  67. package/features/landing/src/sections/LogoCloudSection.tsx +58 -0
  68. package/features/landing/src/sections/ShowcaseSection.tsx +63 -0
  69. package/features/landing/src/sections/StatsSection.tsx +31 -0
  70. package/features/landing/src/sections/TeamSection.tsx +86 -0
  71. package/features/landing/src/sections/TestimonialsSection.tsx +68 -0
  72. package/features/landing/src/sections/VideoSection.tsx +71 -0
  73. package/features/leaderboard/feature.json +33 -0
  74. package/features/leaderboard/src/LeaderboardPage.tsx +372 -0
  75. package/features/leaderboard/src/leaderboard-constants.ts +21 -0
  76. package/features/leaderboard/src/leaderboard-schema.ts +36 -0
  77. package/features/messaging/feature.json +111 -0
  78. package/features/messaging/src/ChatMultiPage.tsx +300 -0
  79. package/features/messaging/src/ChatPage.tsx +75 -0
  80. package/features/messaging/src/components/chat/ChatHeader.tsx +76 -0
  81. package/features/messaging/src/components/chat/MessageActionSheet.tsx +168 -0
  82. package/features/messaging/src/components/chat/MessageInput.tsx +65 -0
  83. package/features/messaging/src/components/chat/MessageItem.tsx +352 -0
  84. package/features/messaging/src/components/chat/MessageList.tsx +248 -0
  85. package/features/messaging/src/components/chat/ReactionPicker.tsx +2 -0
  86. package/features/messaging/src/components/chat/ThreadPanel.tsx +107 -0
  87. package/features/messaging/src/components/chat/UserProfilePopover.tsx +158 -0
  88. package/features/messaging/src/components/chat-multi/AddMemberModal.tsx +188 -0
  89. package/features/messaging/src/components/chat-multi/BrowseGroupsModal.tsx +163 -0
  90. package/features/messaging/src/components/chat-multi/ChannelListItem.tsx +147 -0
  91. package/features/messaging/src/components/chat-multi/ChannelSettingsPanel.tsx +344 -0
  92. package/features/messaging/src/components/chat-multi/ChannelSidebar.tsx +460 -0
  93. package/features/messaging/src/components/chat-multi/CreateGroupModal.tsx +190 -0
  94. package/features/messaging/src/components/chat-multi/InvitationList.tsx +149 -0
  95. package/features/messaging/src/components/chat-multi/NewMessageModal.tsx +159 -0
  96. package/features/messaging/src/hooks/useChatChannel.ts +64 -0
  97. package/features/messaging/src/hooks/useLongPress.ts +74 -0
  98. package/features/messaging/src/hooks/useMultiChannel.ts +142 -0
  99. package/features/messaging/src/messaging-schema.ts +25 -0
  100. package/features/presence-test/feature.json +21 -0
  101. package/features/presence-test/src/PresenceTestPage.tsx +120 -0
  102. package/features/sidebar/feature.json +19 -0
  103. package/features/sidebar/src/AppSidebar.tsx +558 -0
  104. package/features/tasks/feature.json +33 -0
  105. package/features/tasks/src/TasksPage.tsx +598 -0
  106. package/features/tasks/src/tasks-constants.ts +43 -0
  107. package/features/tasks/src/tasks-schema.ts +56 -0
  108. package/features/testing/feature.json +49 -0
  109. package/features/testing/src/TestPage.tsx +145 -0
  110. package/features/testing/src/cpu-burn-action.ts +51 -0
  111. package/features/testing/src/subrequest-burn-action.ts +53 -0
  112. package/features/testing/src/test-schema.ts +23 -0
  113. package/features/topbar/feature.json +18 -0
  114. package/features/topbar/src/Topbar.tsx +353 -0
  115. package/features/tree/feature.json +26 -0
  116. package/features/tree/src/TreeSidebar.tsx +607 -0
  117. package/features/tree/src/tree-constants.ts +68 -0
  118. package/features/tree/src/tree-hooks.ts +258 -0
  119. package/package.json +4 -2
  120. package/scripts/add-feature.cjs +654 -0
package/dist/index.js CHANGED
@@ -11,11 +11,11 @@ var DEV_CONFIG = {
11
11
  };
12
12
  var PROD_CONFIG = {
13
13
  name: "prod",
14
- apiUrl: "https://deepspace-api.eudaimonicincorporated.workers.dev",
15
- platformWorkerUrl: "https://deepspace-platform-worker.eudaimonicincorporated.workers.dev",
16
- authUrl: "https://deepspace-auth.eudaimonicincorporated.workers.dev",
17
- authSignInUrl: "https://deep.space/sign-in",
18
- authSignUpUrl: "https://deep.space/sign-up",
14
+ apiUrl: "https://api-worker.deep.space",
15
+ platformWorkerUrl: "https://platform-worker.deep.space",
16
+ authUrl: "https://auth.deep.space",
17
+ authSignInUrl: "https://auth.deep.space/login/social",
18
+ authSignUpUrl: "https://auth.deep.space/login/social",
19
19
  mainAppUrl: "https://deep.space",
20
20
  dashboardUrl: "https://dashboard.deep.space"
21
21
  };
@@ -440,6 +440,14 @@ var MSG = {
440
440
  CRON_PAUSE: "cron.pause",
441
441
  CRON_RESUME: "cron.resume",
442
442
  CRON_STATUS: "cron.status",
443
+ // ---- JobRoom ---------------------------------------------------------
444
+ // Background-job queue with durable, alarm-driven execution. See
445
+ // server/rooms/job-room.ts. Clients enqueue and subscribe to updates;
446
+ // the room broadcasts JOB_UPDATE for every status transition.
447
+ JOB_ENQUEUE: "job.enqueue",
448
+ JOB_CANCEL: "job.cancel",
449
+ JOB_RETRY: "job.retry",
450
+ JOB_UPDATE: "job.update",
443
451
  // ---- PresenceRoom ----------------------------------------------------
444
452
  PRESENCE_SYNC: "presence.sync",
445
453
  PRESENCE_JOIN: "presence.join",
@@ -496,6 +504,13 @@ var clientBuild = {
496
504
  cronTrigger: (taskName) => ({ type: MSG.CRON_TRIGGER, payload: { taskName } }),
497
505
  cronPause: (taskName) => ({ type: MSG.CRON_PAUSE, payload: { taskName } }),
498
506
  cronResume: (taskName) => ({ type: MSG.CRON_RESUME, payload: { taskName } }),
507
+ // Jobs
508
+ jobEnqueue: (requestId, type, payload, maxAttempts) => ({
509
+ type: MSG.JOB_ENQUEUE,
510
+ payload: { requestId, type, payload, maxAttempts }
511
+ }),
512
+ jobCancel: (jobId) => ({ type: MSG.JOB_CANCEL, payload: { jobId } }),
513
+ jobRetry: (jobId) => ({ type: MSG.JOB_RETRY, payload: { jobId } }),
499
514
  // Presence
500
515
  presenceUpdate: (state) => ({ type: MSG.PRESENCE_UPDATE, payload: state }),
501
516
  // Gateway
@@ -550,6 +565,17 @@ var serverBuild = {
550
565
  cronTasks: (tasks) => ({ type: MSG.CRON_TASKS, payload: { tasks } }),
551
566
  cronHistory: (history) => ({ type: MSG.CRON_HISTORY, payload: { history } }),
552
567
  cronStatus: (tasks, recentHistory) => ({ type: MSG.CRON_STATUS, payload: { tasks, recentHistory } }),
568
+ // Jobs
569
+ jobSnapshot: (jobs) => ({ type: MSG.JOB_UPDATE, payload: { kind: "snapshot", jobs } }),
570
+ jobEnqueued: (job, requestId) => ({
571
+ type: MSG.JOB_UPDATE,
572
+ payload: { kind: "enqueued", job, requestId }
573
+ }),
574
+ jobProgress: (job) => ({ type: MSG.JOB_UPDATE, payload: { kind: "progress", job } }),
575
+ jobSucceeded: (job) => ({ type: MSG.JOB_UPDATE, payload: { kind: "succeeded", job } }),
576
+ jobFailed: (job) => ({ type: MSG.JOB_UPDATE, payload: { kind: "failed", job } }),
577
+ jobCanceled: (job) => ({ type: MSG.JOB_UPDATE, payload: { kind: "canceled", job } }),
578
+ jobRetried: (job) => ({ type: MSG.JOB_UPDATE, payload: { kind: "retried", job } }),
553
579
  // Presence
554
580
  presenceSync: (peers) => ({ type: MSG.PRESENCE_SYNC, payload: { peers } }),
555
581
  presenceJoin: (peer) => ({ type: MSG.PRESENCE_JOIN, payload: { peer } }),
@@ -3128,13 +3154,143 @@ function useCronMonitor(roomId) {
3128
3154
  return { tasks, history, connected, trigger, pause, resume };
3129
3155
  }
3130
3156
 
3131
- // src/client/storage/hooks/usePresenceRoom.ts
3157
+ // src/client/storage/hooks/useJobs.ts
3132
3158
  import { useState as useState11, useEffect as useEffect14, useCallback as useCallback13, useRef as useRef12 } from "react";
3133
- function usePresenceRoom(scopeId) {
3134
- const [peers, setPeers] = useState11([]);
3159
+ var ENQUEUE_TIMEOUT_MS = 1e4;
3160
+ function useJobs(roomId) {
3161
+ const [jobs, setJobs] = useState11([]);
3135
3162
  const [connected, setConnected] = useState11(false);
3136
3163
  const wsRef = useRef12(null);
3164
+ const pendingEnqueueRef = useRef12(/* @__PURE__ */ new Map());
3137
3165
  useEffect14(() => {
3166
+ let ws = null;
3167
+ let reconnectTimer = null;
3168
+ let alive = true;
3169
+ const upsert = (next) => {
3170
+ setJobs((prev) => {
3171
+ const idx = prev.findIndex((j) => j.id === next.id);
3172
+ if (idx === -1) return [next, ...prev];
3173
+ const copy = prev.slice();
3174
+ copy[idx] = next;
3175
+ return copy;
3176
+ });
3177
+ };
3178
+ const rejectAllPending = (err) => {
3179
+ for (const [id, pending] of pendingEnqueueRef.current.entries()) {
3180
+ clearTimeout(pending.timer);
3181
+ pending.reject(err);
3182
+ pendingEnqueueRef.current.delete(id);
3183
+ }
3184
+ };
3185
+ const connect = async () => {
3186
+ if (!alive) return;
3187
+ const token = await getAuthToken();
3188
+ const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
3189
+ const baseUrl = `${protocol}//${window.location.host}`;
3190
+ const url = new URL(`/ws/jobs/${encodeURIComponent(roomId)}`, baseUrl);
3191
+ if (token) url.searchParams.set("token", token);
3192
+ ws = new WebSocket(url.toString());
3193
+ wsRef.current = ws;
3194
+ ws.onopen = () => setConnected(true);
3195
+ ws.onmessage = (event) => {
3196
+ dispatch(event.data, {
3197
+ [MSG.JOB_UPDATE]: (p) => {
3198
+ if (p.kind === "snapshot" && Array.isArray(p.jobs)) {
3199
+ setJobs(p.jobs);
3200
+ return;
3201
+ }
3202
+ const job = p.job;
3203
+ if (!job) return;
3204
+ upsert(job);
3205
+ if (p.kind === "enqueued" && typeof p.requestId === "string") {
3206
+ const pending = pendingEnqueueRef.current.get(p.requestId);
3207
+ if (pending) {
3208
+ clearTimeout(pending.timer);
3209
+ pendingEnqueueRef.current.delete(p.requestId);
3210
+ pending.resolve(job.id);
3211
+ }
3212
+ }
3213
+ }
3214
+ });
3215
+ };
3216
+ ws.onclose = () => {
3217
+ wsRef.current = null;
3218
+ setConnected(false);
3219
+ rejectAllPending(new Error("JobRoom WebSocket closed"));
3220
+ if (alive) reconnectTimer = setTimeout(connect, 1e3);
3221
+ };
3222
+ ws.onerror = () => ws?.close();
3223
+ };
3224
+ connect();
3225
+ return () => {
3226
+ alive = false;
3227
+ if (reconnectTimer) clearTimeout(reconnectTimer);
3228
+ rejectAllPending(new Error("useJobs unmounted"));
3229
+ ws?.close();
3230
+ wsRef.current = null;
3231
+ };
3232
+ }, [roomId]);
3233
+ const enqueue = useCallback13(
3234
+ (type, payload, options) => {
3235
+ return new Promise((resolve, reject) => {
3236
+ const ws = wsRef.current;
3237
+ if (!ws || ws.readyState !== WebSocket.OPEN) {
3238
+ reject(new Error("JobRoom WebSocket not connected"));
3239
+ return;
3240
+ }
3241
+ const requestId = crypto.randomUUID();
3242
+ const timer = setTimeout(() => {
3243
+ pendingEnqueueRef.current.delete(requestId);
3244
+ reject(
3245
+ new Error(
3246
+ `JobRoom enqueue timed out (no server ack within ${ENQUEUE_TIMEOUT_MS}ms)`
3247
+ )
3248
+ );
3249
+ }, ENQUEUE_TIMEOUT_MS);
3250
+ pendingEnqueueRef.current.set(requestId, { resolve, reject, timer });
3251
+ try {
3252
+ ws.send(
3253
+ encode(clientBuild.jobEnqueue(requestId, type, payload, options?.maxAttempts))
3254
+ );
3255
+ } catch (e) {
3256
+ clearTimeout(timer);
3257
+ pendingEnqueueRef.current.delete(requestId);
3258
+ reject(e instanceof Error ? e : new Error(String(e)));
3259
+ }
3260
+ });
3261
+ },
3262
+ []
3263
+ );
3264
+ const sendBuilt = useCallback13(
3265
+ (message) => {
3266
+ const ws = wsRef.current;
3267
+ if (!ws || ws.readyState !== WebSocket.OPEN) return;
3268
+ ws.send(encode(message));
3269
+ },
3270
+ []
3271
+ );
3272
+ const getJob = useCallback13(
3273
+ (jobId) => jobs.find((j) => j.id === jobId),
3274
+ [jobs]
3275
+ );
3276
+ const cancel = useCallback13(
3277
+ (jobId) => sendBuilt(clientBuild.jobCancel(jobId)),
3278
+ [sendBuilt]
3279
+ );
3280
+ const retry = useCallback13(
3281
+ (jobId) => sendBuilt(clientBuild.jobRetry(jobId)),
3282
+ [sendBuilt]
3283
+ );
3284
+ return { jobs, connected, enqueue, getJob, cancel, retry };
3285
+ }
3286
+
3287
+ // src/client/storage/hooks/usePresenceRoom.ts
3288
+ import { useState as useState12, useEffect as useEffect15, useCallback as useCallback14, useRef as useRef13 } from "react";
3289
+ function usePresenceRoom(scopeId) {
3290
+ const [peers, setPeers] = useState12([]);
3291
+ const [connected, setConnected] = useState12(false);
3292
+ const wsRef = useRef13(null);
3293
+ useEffect15(() => {
3138
3294
  let ws = null;
3139
3295
  let reconnectTimer = null;
3140
3296
  let alive = true;
@@ -3195,7 +3351,7 @@ function usePresenceRoom(scopeId) {
3195
3351
  wsRef.current = null;
3196
3352
  };
3197
3353
  }, [scopeId]);
3198
- const updateState = useCallback13((state) => {
3354
+ const updateState = useCallback14((state) => {
3199
3355
  const ws = wsRef.current;
3200
3356
  if (!ws || ws.readyState !== WebSocket.OPEN) return;
3201
3357
  ws.send(encode(clientBuild.presenceUpdate(state)));
@@ -3211,7 +3367,7 @@ function toConnectionStatus(queryStatus) {
3211
3367
  }
3212
3368
 
3213
3369
  // src/client/storage/useR2Files.ts
3214
- import { useCallback as useCallback14, useState as useState12, useMemo as useMemo10 } from "react";
3370
+ import { useCallback as useCallback15, useState as useState13, useMemo as useMemo10 } from "react";
3215
3371
  function resolveFile(fileOrKey) {
3216
3372
  if (typeof fileOrKey === "string") {
3217
3373
  return { key: fileOrKey, name: void 0 };
@@ -3219,20 +3375,20 @@ function resolveFile(fileOrKey) {
3219
3375
  return { key: fileOrKey.key, name: fileOrKey.originalName };
3220
3376
  }
3221
3377
  function useR2Files(options) {
3222
- const [isUploading, setIsUploading] = useState12(false);
3378
+ const [isUploading, setIsUploading] = useState13(false);
3223
3379
  const scopeParams = useMemo10(() => {
3224
3380
  const params = new URLSearchParams();
3225
3381
  params.set("scope", "self");
3226
3382
  return params.toString();
3227
3383
  }, []);
3228
- const authHeaders = useCallback14(async () => {
3384
+ const authHeaders = useCallback15(async () => {
3229
3385
  const token = await getAuthToken();
3230
3386
  if (token) {
3231
3387
  return { Authorization: `Bearer ${token}` };
3232
3388
  }
3233
3389
  return {};
3234
3390
  }, []);
3235
- const upload = useCallback14(async (file, name) => {
3391
+ const upload = useCallback15(async (file, name) => {
3236
3392
  setIsUploading(true);
3237
3393
  try {
3238
3394
  const headers = await authHeaders();
@@ -3251,7 +3407,7 @@ function useR2Files(options) {
3251
3407
  setIsUploading(false);
3252
3408
  }
3253
3409
  }, [scopeParams, authHeaders]);
3254
- const uploadBase64 = useCallback14(async (base64Data, name, mimeType) => {
3410
+ const uploadBase64 = useCallback15(async (base64Data, name, mimeType) => {
3255
3411
  setIsUploading(true);
3256
3412
  try {
3257
3413
  const headers = await authHeaders();
@@ -3267,7 +3423,7 @@ function useR2Files(options) {
3267
3423
  setIsUploading(false);
3268
3424
  }
3269
3425
  }, [scopeParams, authHeaders]);
3270
- const deleteFile = useCallback14(async (fileOrKey) => {
3426
+ const deleteFile = useCallback15(async (fileOrKey) => {
3271
3427
  const { key } = resolveFile(fileOrKey);
3272
3428
  try {
3273
3429
  const headers = await authHeaders();
@@ -3277,7 +3433,7 @@ function useR2Files(options) {
3277
3433
  return { success: false, error: err instanceof Error ? err.message : "Delete failed" };
3278
3434
  }
3279
3435
  }, [scopeParams, authHeaders]);
3280
- const list = useCallback14(async (prefix) => {
3436
+ const list = useCallback15(async (prefix) => {
3281
3437
  try {
3282
3438
  const headers = await authHeaders();
3283
3439
  const params = new URLSearchParams(scopeParams);
@@ -3289,7 +3445,7 @@ function useR2Files(options) {
3289
3445
  return [];
3290
3446
  }
3291
3447
  }, [scopeParams, authHeaders]);
3292
- const downloadFile = useCallback14(async (fileOrKey, fileName) => {
3448
+ const downloadFile = useCallback15(async (fileOrKey, fileName) => {
3293
3449
  const { key, name: infoName } = resolveFile(fileOrKey);
3294
3450
  try {
3295
3451
  const headers = await authHeaders();
@@ -3316,7 +3472,7 @@ function useR2Files(options) {
3316
3472
  return { success: false, error: err instanceof Error ? err.message : "Download failed" };
3317
3473
  }
3318
3474
  }, [scopeParams, authHeaders]);
3319
- const readFile = useCallback14(async (fileOrKey) => {
3475
+ const readFile = useCallback15(async (fileOrKey) => {
3320
3476
  const { key } = resolveFile(fileOrKey);
3321
3477
  const headers = await authHeaders();
3322
3478
  const response = await fetch(`/api/files/${key}?${scopeParams}`, { headers });
@@ -3326,7 +3482,7 @@ function useR2Files(options) {
3326
3482
  }
3327
3483
  return response;
3328
3484
  }, [scopeParams, authHeaders]);
3329
- const getUrl = useCallback14((fileOrKey) => {
3485
+ const getUrl = useCallback15((fileOrKey) => {
3330
3486
  const { key } = resolveFile(fileOrKey);
3331
3487
  return `/api/files/${key}?${scopeParams}`;
3332
3488
  }, [scopeParams]);
@@ -3369,7 +3525,7 @@ function getUserColor(userId, palette = DEFAULT_USER_COLORS) {
3369
3525
  }
3370
3526
 
3371
3527
  // src/client/messaging/useMessages.ts
3372
- import { useCallback as useCallback15, useMemo as useMemo11 } from "react";
3528
+ import { useCallback as useCallback16, useMemo as useMemo11 } from "react";
3373
3529
  function useMessages(channelId, options) {
3374
3530
  const where = useMemo11(() => {
3375
3531
  if (!channelId) return { channelId: "__none__" };
@@ -3386,7 +3542,7 @@ function useMessages(channelId, options) {
3386
3542
  orderDir: "asc"
3387
3543
  });
3388
3544
  const { create, put, remove: removeMutation } = useMutations("messages");
3389
- const send = useCallback15(
3545
+ const send = useCallback16(
3390
3546
  (content, parentMessageId) => {
3391
3547
  if (!channelId || !user) return;
3392
3548
  const data = { channelId, content, authorId: user.id, edited: false };
@@ -3395,19 +3551,19 @@ function useMessages(channelId, options) {
3395
3551
  },
3396
3552
  [channelId, create]
3397
3553
  );
3398
- const edit = useCallback15(
3554
+ const edit = useCallback16(
3399
3555
  (messageId, newContent) => {
3400
3556
  put(messageId, { content: newContent, edited: true });
3401
3557
  },
3402
3558
  [put]
3403
3559
  );
3404
- const remove = useCallback15(
3560
+ const remove = useCallback16(
3405
3561
  (messageId) => {
3406
3562
  removeMutation(messageId);
3407
3563
  },
3408
3564
  [removeMutation]
3409
3565
  );
3410
- const softDelete = useCallback15(
3566
+ const softDelete = useCallback16(
3411
3567
  (messageId) => {
3412
3568
  put(messageId, { deleted: true });
3413
3569
  },
@@ -3417,7 +3573,7 @@ function useMessages(channelId, options) {
3417
3573
  }
3418
3574
 
3419
3575
  // src/client/messaging/useChannels.ts
3420
- import { useCallback as useCallback16 } from "react";
3576
+ import { useCallback as useCallback17 } from "react";
3421
3577
  function useChannels() {
3422
3578
  const { user } = useUser();
3423
3579
  const { records, status, error } = useQuery("channels", {
@@ -3425,7 +3581,7 @@ function useChannels() {
3425
3581
  orderDir: "asc"
3426
3582
  });
3427
3583
  const { create: createMutation, put, remove } = useMutations("channels");
3428
- const create = useCallback16(
3584
+ const create = useCallback17(
3429
3585
  (data) => {
3430
3586
  return createMutation({
3431
3587
  name: data.name,
@@ -3437,13 +3593,13 @@ function useChannels() {
3437
3593
  },
3438
3594
  [createMutation]
3439
3595
  );
3440
- const archive = useCallback16(
3596
+ const archive = useCallback17(
3441
3597
  (channelId) => {
3442
3598
  put(channelId, { archived: true });
3443
3599
  },
3444
3600
  [put]
3445
3601
  );
3446
- const update = useCallback16(
3602
+ const update = useCallback17(
3447
3603
  (channelId, data) => {
3448
3604
  put(channelId, data);
3449
3605
  },
@@ -3453,14 +3609,14 @@ function useChannels() {
3453
3609
  }
3454
3610
 
3455
3611
  // src/client/messaging/useReactions.ts
3456
- import { useCallback as useCallback17 } from "react";
3612
+ import { useCallback as useCallback18 } from "react";
3457
3613
  function useReactions(channelId) {
3458
3614
  const { user } = useUser();
3459
3615
  const { records, status, error } = useQuery("reactions", {
3460
3616
  where: channelId ? { channelId } : { channelId: "__none__" }
3461
3617
  });
3462
3618
  const { create, remove: removeMutation } = useMutations("reactions");
3463
- const getReactionsForMessage = useCallback17(
3619
+ const getReactionsForMessage = useCallback18(
3464
3620
  (messageId) => {
3465
3621
  const messageReactions = records.filter((r) => r.data.messageId === messageId);
3466
3622
  const grouped = /* @__PURE__ */ new Map();
@@ -3477,7 +3633,7 @@ function useReactions(channelId) {
3477
3633
  },
3478
3634
  [records, user]
3479
3635
  );
3480
- const toggle = useCallback17(
3636
+ const toggle = useCallback18(
3481
3637
  (messageId, emoji) => {
3482
3638
  if (!channelId || !user) return;
3483
3639
  const existing = records.find(
@@ -3495,20 +3651,20 @@ function useReactions(channelId) {
3495
3651
  }
3496
3652
 
3497
3653
  // src/client/messaging/useChannelMembers.ts
3498
- import { useCallback as useCallback18 } from "react";
3654
+ import { useCallback as useCallback19 } from "react";
3499
3655
  function useChannelMembers(channelId) {
3500
3656
  const { user } = useUser();
3501
3657
  const { records, status, error } = useQuery("channel-members", {
3502
3658
  where: channelId ? { channelId } : { channelId: "__none__" }
3503
3659
  });
3504
3660
  const { create, remove: removeMutation } = useMutations("channel-members");
3505
- const join = useCallback18(() => {
3661
+ const join = useCallback19(() => {
3506
3662
  if (!channelId || !user) return;
3507
3663
  const existing = records.find((r) => r.data.userId === user.id);
3508
3664
  if (existing) return;
3509
3665
  create({ channelId, userId: user.id, joinedAt: (/* @__PURE__ */ new Date()).toISOString() });
3510
3666
  }, [channelId, user, records, create]);
3511
- const leave = useCallback18(() => {
3667
+ const leave = useCallback19(() => {
3512
3668
  if (!channelId || !user) return;
3513
3669
  const membership = records.find((r) => r.data.userId === user.id);
3514
3670
  if (membership) removeMutation(membership.recordId);
@@ -3518,14 +3674,14 @@ function useChannelMembers(channelId) {
3518
3674
  }
3519
3675
 
3520
3676
  // src/client/messaging/useReadReceipts.ts
3521
- import { useCallback as useCallback19 } from "react";
3677
+ import { useCallback as useCallback20 } from "react";
3522
3678
  function useReadReceipts() {
3523
3679
  const { user } = useUser();
3524
3680
  const { records, status, error } = useQuery("read-receipts", {
3525
3681
  where: user ? { userId: user.id } : { userId: "__none__" }
3526
3682
  });
3527
3683
  const { create, put } = useMutations("read-receipts");
3528
- const markAsRead = useCallback19(
3684
+ const markAsRead = useCallback20(
3529
3685
  (channelId) => {
3530
3686
  if (!user) return;
3531
3687
  const existing = records.find((r) => r.data.channelId === channelId);
@@ -3538,7 +3694,7 @@ function useReadReceipts() {
3538
3694
  },
3539
3695
  [user, records, create, put]
3540
3696
  );
3541
- const getUnreadCount = useCallback19(
3697
+ const getUnreadCount = useCallback20(
3542
3698
  (channelId, messages) => {
3543
3699
  const receipt = records.find((r) => r.data.channelId === channelId);
3544
3700
  if (!receipt) return messages.length;
@@ -3551,7 +3707,7 @@ function useReadReceipts() {
3551
3707
  }
3552
3708
 
3553
3709
  // src/client/messaging/useConversation.ts
3554
- import { useCallback as useCallback20, useMemo as useMemo12 } from "react";
3710
+ import { useCallback as useCallback21, useMemo as useMemo12 } from "react";
3555
3711
  function useConversation(opts) {
3556
3712
  const { user } = useUser();
3557
3713
  const { ready } = useRecordContext();
@@ -3560,7 +3716,7 @@ function useConversation(opts) {
3560
3716
  const { records: members } = useQuery("conv_members");
3561
3717
  const messageMut = useMutations("conv_messages");
3562
3718
  const reactionMut = useMutations("conv_reactions");
3563
- const send = useCallback20(
3719
+ const send = useCallback21(
3564
3720
  (content, parentMessageId, messageType, metadata) => {
3565
3721
  messageMut.create({
3566
3722
  Content: content,
@@ -3574,7 +3730,7 @@ function useConversation(opts) {
3574
3730
  },
3575
3731
  [messageMut, user?.id, opts?.onMessageSent]
3576
3732
  );
3577
- const edit = useCallback20(
3733
+ const edit = useCallback21(
3578
3734
  (recordId, content) => {
3579
3735
  const existing = allMessages.find((m) => m.recordId === recordId);
3580
3736
  if (!existing) return;
@@ -3582,7 +3738,7 @@ function useConversation(opts) {
3582
3738
  },
3583
3739
  [messageMut, allMessages]
3584
3740
  );
3585
- const remove = useCallback20(
3741
+ const remove = useCallback21(
3586
3742
  (recordId) => {
3587
3743
  const existing = allMessages.find((m) => m.recordId === recordId);
3588
3744
  if (!existing) return;
@@ -3595,7 +3751,7 @@ function useConversation(opts) {
3595
3751
  },
3596
3752
  [messageMut, allMessages]
3597
3753
  );
3598
- const toggleReaction = useCallback20(
3754
+ const toggleReaction = useCallback21(
3599
3755
  (messageId, emoji) => {
3600
3756
  const existing = allReactions.find(
3601
3757
  (r) => r.data.MessageId === messageId && r.data.Emoji === emoji && r.data.UserId === user?.id
@@ -3728,7 +3884,7 @@ function parseMessageMetadata(raw) {
3728
3884
  }
3729
3885
 
3730
3886
  // src/client/directory/useConversations.ts
3731
- import { useCallback as useCallback21, useMemo as useMemo13, useRef as useRef13 } from "react";
3887
+ import { useCallback as useCallback22, useMemo as useMemo13, useRef as useRef14 } from "react";
3732
3888
  function useConversations() {
3733
3889
  const { records: conversations, status } = useQuery("conversations");
3734
3890
  const { create, put } = useMutations("conversations");
@@ -3736,7 +3892,7 @@ function useConversations() {
3736
3892
  const stateMut = useMutations("conversation_state");
3737
3893
  const { user } = useUser();
3738
3894
  const ready = status === "ready";
3739
- const recentCreationsRef = useRef13(/* @__PURE__ */ new Map());
3895
+ const recentCreationsRef = useRef14(/* @__PURE__ */ new Map());
3740
3896
  for (const [id] of recentCreationsRef.current) {
3741
3897
  if (conversations.find((c) => c.recordId === id)) {
3742
3898
  recentCreationsRef.current.delete(id);
@@ -3758,7 +3914,7 @@ function useConversations() {
3758
3914
  () => new Set(stateRecords.filter((r) => r.data.Archived).map((r) => r.data.ConversationId)),
3759
3915
  [stateRecords]
3760
3916
  );
3761
- const getConversationState = useCallback21(
3917
+ const getConversationState = useCallback22(
3762
3918
  (conversationId) => {
3763
3919
  return stateRecords.find((r) => r.data.ConversationId === conversationId)?.data;
3764
3920
  },
@@ -3771,7 +3927,7 @@ function useConversations() {
3771
3927
  LinkedRef: "",
3772
3928
  MessageCount: 0
3773
3929
  };
3774
- const createChannel = useCallback21(
3930
+ const createChannel = useCallback22(
3775
3931
  async (name, description) => {
3776
3932
  const existing = conversations.find((r) => r.data.Name === name && r.data.Type !== "dm");
3777
3933
  if (existing) return existing.recordId;
@@ -3791,7 +3947,7 @@ function useConversations() {
3791
3947
  },
3792
3948
  [create, user?.id, conversations]
3793
3949
  );
3794
- const createDM = useCallback21(
3950
+ const createDM = useCallback22(
3795
3951
  async (otherUserId) => {
3796
3952
  if (!user?.id) return null;
3797
3953
  const hash = [user.id, otherUserId].sort().join(":");
@@ -3819,7 +3975,7 @@ function useConversations() {
3819
3975
  },
3820
3976
  [create, user?.id, conversations]
3821
3977
  );
3822
- const createGroupDM = useCallback21(
3978
+ const createGroupDM = useCallback22(
3823
3979
  async (participantIds) => {
3824
3980
  if (!user?.id) return null;
3825
3981
  const allIds = [.../* @__PURE__ */ new Set([user.id, ...participantIds])];
@@ -3849,14 +4005,14 @@ function useConversations() {
3849
4005
  },
3850
4006
  [create, user?.id, conversations]
3851
4007
  );
3852
- const lookupByName = useCallback21(
4008
+ const lookupByName = useCallback22(
3853
4009
  (name) => {
3854
4010
  const found = conversations.find((r) => r.data.Name === name);
3855
4011
  return found?.recordId ?? null;
3856
4012
  },
3857
4013
  [conversations]
3858
4014
  );
3859
- const updateLastMessage = useCallback21(
4015
+ const updateLastMessage = useCallback22(
3860
4016
  (conversationId, preview, authorId) => {
3861
4017
  const conv = conversations.find((c) => c.recordId === conversationId);
3862
4018
  const baseData = conv?.data ?? recentCreationsRef.current.get(conversationId);
@@ -3875,7 +4031,7 @@ function useConversations() {
3875
4031
  },
3876
4032
  [put, conversations]
3877
4033
  );
3878
- const upsertState = useCallback21(
4034
+ const upsertState = useCallback22(
3879
4035
  (conversationId, partial) => {
3880
4036
  if (!user?.id) return;
3881
4037
  const existing = stateRecords.find(
@@ -3897,7 +4053,7 @@ function useConversations() {
3897
4053
  },
3898
4054
  [stateMut, stateRecords, user?.id]
3899
4055
  );
3900
- const markRead = useCallback21(
4056
+ const markRead = useCallback22(
3901
4057
  (conversationId) => {
3902
4058
  const conv = conversations.find((c) => c.recordId === conversationId);
3903
4059
  const msgCount = conv?.data.MessageCount ?? recentCreationsRef.current.get(conversationId)?.MessageCount ?? 0;
@@ -3908,32 +4064,32 @@ function useConversations() {
3908
4064
  },
3909
4065
  [upsertState, conversations]
3910
4066
  );
3911
- const toggleStar = useCallback21(
4067
+ const toggleStar = useCallback22(
3912
4068
  (conversationId) => {
3913
4069
  const isStarred = starredSet.has(conversationId);
3914
4070
  upsertState(conversationId, { Starred: isStarred ? 0 : 1 });
3915
4071
  },
3916
4072
  [upsertState, starredSet]
3917
4073
  );
3918
- const setArchived = useCallback21(
4074
+ const setArchived = useCallback22(
3919
4075
  (conversationId, archived) => {
3920
4076
  upsertState(conversationId, { Archived: archived ? 1 : 0 });
3921
4077
  },
3922
4078
  [upsertState]
3923
4079
  );
3924
- const setTrashed = useCallback21(
4080
+ const setTrashed = useCallback22(
3925
4081
  (conversationId, trashed) => {
3926
4082
  upsertState(conversationId, { Trashed: trashed ? 1 : 0 });
3927
4083
  },
3928
4084
  [upsertState]
3929
4085
  );
3930
- const setLabels = useCallback21(
4086
+ const setLabels = useCallback22(
3931
4087
  (conversationId, labels) => {
3932
4088
  upsertState(conversationId, { Labels: JSON.stringify(labels) });
3933
4089
  },
3934
4090
  [upsertState]
3935
4091
  );
3936
- const setFolder = useCallback21(
4092
+ const setFolder = useCallback22(
3937
4093
  (conversationId, folder) => {
3938
4094
  upsertState(conversationId, { Folder: folder });
3939
4095
  },
@@ -3963,7 +4119,7 @@ function useConversations() {
3963
4119
  }
3964
4120
 
3965
4121
  // src/client/directory/useCommunities.ts
3966
- import { useCallback as useCallback22, useMemo as useMemo14 } from "react";
4122
+ import { useCallback as useCallback23, useMemo as useMemo14 } from "react";
3967
4123
  function useCommunities() {
3968
4124
  const { records: communities, status } = useQuery("communities");
3969
4125
  const communityMut = useMutations("communities");
@@ -3986,7 +4142,7 @@ function useCommunities() {
3986
4142
  ),
3987
4143
  [memberships, user?.id]
3988
4144
  );
3989
- const createCommunity = useCallback22(
4145
+ const createCommunity = useCallback23(
3990
4146
  async (name, opts) => {
3991
4147
  const existing = communities.find((c) => c.data.Name === name);
3992
4148
  if (existing) return existing.recordId;
@@ -4005,7 +4161,7 @@ function useCommunities() {
4005
4161
  },
4006
4162
  [communityMut, user?.id, communities]
4007
4163
  );
4008
- const updateCommunity = useCallback22(
4164
+ const updateCommunity = useCallback23(
4009
4165
  (communityId, updates) => {
4010
4166
  const existing = communities.find((c) => c.recordId === communityId);
4011
4167
  if (!existing) return;
@@ -4013,7 +4169,7 @@ function useCommunities() {
4013
4169
  },
4014
4170
  [communityMut, communities]
4015
4171
  );
4016
- const joinCommunity = useCallback22(
4172
+ const joinCommunity = useCallback23(
4017
4173
  async (communityId, userName) => {
4018
4174
  if (!user?.id) return null;
4019
4175
  const existing = memberships.find(
@@ -4031,7 +4187,7 @@ function useCommunities() {
4031
4187
  },
4032
4188
  [membershipMut, memberships, user?.id]
4033
4189
  );
4034
- const leaveCommunity = useCallback22(
4190
+ const leaveCommunity = useCallback23(
4035
4191
  (communityId) => {
4036
4192
  if (!user?.id) return;
4037
4193
  const membership = memberships.find(
@@ -4043,13 +4199,13 @@ function useCommunities() {
4043
4199
  },
4044
4200
  [membershipMut, memberships, user?.id]
4045
4201
  );
4046
- const getMembersOf = useCallback22(
4202
+ const getMembersOf = useCallback23(
4047
4203
  (communityId) => {
4048
4204
  return membershipMap.get(communityId) ?? [];
4049
4205
  },
4050
4206
  [membershipMap]
4051
4207
  );
4052
- const lookupByName = useCallback22(
4208
+ const lookupByName = useCallback23(
4053
4209
  (name) => {
4054
4210
  const found = communities.find((c) => c.data.Name === name);
4055
4211
  return found?.recordId ?? null;
@@ -4071,14 +4227,14 @@ function useCommunities() {
4071
4227
  }
4072
4228
 
4073
4229
  // src/client/directory/usePosts.ts
4074
- import { useCallback as useCallback23 } from "react";
4230
+ import { useCallback as useCallback24 } from "react";
4075
4231
  function usePosts(opts) {
4076
4232
  const { records: allPosts, status } = useQuery("posts");
4077
4233
  const postMut = useMutations("posts");
4078
4234
  const { user } = useUser();
4079
4235
  const ready = status === "ready";
4080
4236
  const posts = opts?.communityId ? allPosts.filter((p) => p.data.CommunityId === opts.communityId) : allPosts;
4081
- const createPost = useCallback23(
4237
+ const createPost = useCallback24(
4082
4238
  async (data) => {
4083
4239
  const recordId = await postMut.create({
4084
4240
  Title: data.title,
@@ -4096,7 +4252,7 @@ function usePosts(opts) {
4096
4252
  },
4097
4253
  [postMut, user?.id]
4098
4254
  );
4099
- const updatePost = useCallback23(
4255
+ const updatePost = useCallback24(
4100
4256
  (postId, updates) => {
4101
4257
  const existing = allPosts.find((p) => p.recordId === postId);
4102
4258
  if (!existing) return;
@@ -4104,13 +4260,13 @@ function usePosts(opts) {
4104
4260
  },
4105
4261
  [postMut, allPosts]
4106
4262
  );
4107
- const deletePost = useCallback23(
4263
+ const deletePost = useCallback24(
4108
4264
  (postId) => {
4109
4265
  postMut.remove(postId);
4110
4266
  },
4111
4267
  [postMut]
4112
4268
  );
4113
- const setConversationId = useCallback23(
4269
+ const setConversationId = useCallback24(
4114
4270
  (postId, conversationId) => {
4115
4271
  updatePost(postId, { ConversationId: conversationId });
4116
4272
  },
@@ -4127,7 +4283,7 @@ function usePosts(opts) {
4127
4283
  }
4128
4284
 
4129
4285
  // src/client/theme/DeepSpaceThemeProvider.tsx
4130
- import { useEffect as useEffect15 } from "react";
4286
+ import { useEffect as useEffect16 } from "react";
4131
4287
 
4132
4288
  // src/client/theme/applyTheme.ts
4133
4289
  function mix(color, pct, base = "transparent") {
@@ -4440,7 +4596,7 @@ function DeepSpaceThemeProvider({
4440
4596
  children,
4441
4597
  theme
4442
4598
  }) {
4443
- useEffect15(() => {
4599
+ useEffect16(() => {
4444
4600
  const root = document.documentElement;
4445
4601
  const config = theme ?? readThemeFromDOM(root);
4446
4602
  applyDeepSpaceTheme(config, root);
@@ -4449,12 +4605,12 @@ function DeepSpaceThemeProvider({
4449
4605
  }
4450
4606
 
4451
4607
  // src/client/theme/useIsDarkTheme.ts
4452
- import { useState as useState13, useEffect as useEffect16 } from "react";
4608
+ import { useState as useState14, useEffect as useEffect17 } from "react";
4453
4609
  function useIsDarkTheme() {
4454
- const [isDark, setIsDark] = useState13(
4610
+ const [isDark, setIsDark] = useState14(
4455
4611
  () => typeof document === "undefined" || document.documentElement.dataset.uiTheme !== "light"
4456
4612
  );
4457
- useEffect16(() => {
4613
+ useEffect17(() => {
4458
4614
  const update = () => {
4459
4615
  setIsDark(document.documentElement.dataset.uiTheme !== "light");
4460
4616
  };
@@ -4466,7 +4622,7 @@ function useIsDarkTheme() {
4466
4622
  }
4467
4623
 
4468
4624
  // src/client/platform/PlatformProvider.tsx
4469
- import { createContext as createContext3, useContext as useContext5, useState as useState14, useEffect as useEffect17, useRef as useRef14, useCallback as useCallback24 } from "react";
4625
+ import { createContext as createContext3, useContext as useContext5, useState as useState15, useEffect as useEffect18, useRef as useRef15, useCallback as useCallback25 } from "react";
4470
4626
  import { jsx as jsx9 } from "react/jsx-runtime";
4471
4627
  var PlatformContext = createContext3(null);
4472
4628
  function usePlatform() {
@@ -4476,14 +4632,14 @@ function usePlatform() {
4476
4632
  }
4477
4633
  function useInbox() {
4478
4634
  const { inbox, subscribeInbox } = usePlatform();
4479
- useEffect17(() => subscribeInbox(), [subscribeInbox]);
4635
+ useEffect18(() => subscribeInbox(), [subscribeInbox]);
4480
4636
  return inbox;
4481
4637
  }
4482
4638
  function PlatformProvider({ children }) {
4483
- const [inbox, setInbox] = useState14([]);
4484
- const inboxSubscribers = useRef14(0);
4485
- const [inboxActive, setInboxActive] = useState14(false);
4486
- const subscribeInbox = useCallback24(() => {
4639
+ const [inbox, setInbox] = useState15([]);
4640
+ const inboxSubscribers = useRef15(0);
4641
+ const [inboxActive, setInboxActive] = useState15(false);
4642
+ const subscribeInbox = useCallback25(() => {
4487
4643
  inboxSubscribers.current++;
4488
4644
  if (inboxSubscribers.current === 1) setInboxActive(true);
4489
4645
  return () => {
@@ -4491,7 +4647,7 @@ function PlatformProvider({ children }) {
4491
4647
  if (inboxSubscribers.current === 0) setInboxActive(false);
4492
4648
  };
4493
4649
  }, []);
4494
- useEffect17(() => {
4650
+ useEffect18(() => {
4495
4651
  if (!inboxActive) return;
4496
4652
  let mounted = true;
4497
4653
  let ws = null;
@@ -4549,7 +4705,7 @@ function PlatformProvider({ children }) {
4549
4705
  setInbox([]);
4550
4706
  };
4551
4707
  }, [inboxActive]);
4552
- const platformFetch = useCallback24(async (path, init) => {
4708
+ const platformFetch = useCallback25(async (path, init) => {
4553
4709
  const token = await getAuthToken();
4554
4710
  const headers = new Headers(init?.headers);
4555
4711
  if (token) headers.set("Authorization", `Bearer ${token}`);
@@ -4560,28 +4716,28 @@ function PlatformProvider({ children }) {
4560
4716
  }
4561
4717
 
4562
4718
  // src/client/platform/usePlatformWS.ts
4563
- import { useState as useState15, useEffect as useEffect18, useRef as useRef15 } from "react";
4719
+ import { useState as useState16, useEffect as useEffect19, useRef as useRef16 } from "react";
4564
4720
  var MAX_RECONNECT_DELAY = 1e4;
4565
4721
  var BASE_RECONNECT_DELAY = 500;
4566
4722
  function usePlatformWS(options) {
4567
4723
  const { path, scopeId, initialState, onMessage } = options;
4568
- const wsRef = useRef15(null);
4569
- const pingIntervalRef = useRef15(null);
4570
- const [state, setState] = useState15(initialState);
4571
- const reconnectAttemptRef = useRef15(0);
4572
- const reconnectTimerRef = useRef15(null);
4573
- const mountedRef = useRef15(true);
4574
- const onMessageRef = useRef15(onMessage);
4724
+ const wsRef = useRef16(null);
4725
+ const pingIntervalRef = useRef16(null);
4726
+ const [state, setState] = useState16(initialState);
4727
+ const reconnectAttemptRef = useRef16(0);
4728
+ const reconnectTimerRef = useRef16(null);
4729
+ const mountedRef = useRef16(true);
4730
+ const onMessageRef = useRef16(onMessage);
4575
4731
  onMessageRef.current = onMessage;
4576
- const initialStateRef = useRef15(initialState);
4732
+ const initialStateRef = useRef16(initialState);
4577
4733
  initialStateRef.current = initialState;
4578
- useEffect18(() => {
4734
+ useEffect19(() => {
4579
4735
  mountedRef.current = true;
4580
4736
  return () => {
4581
4737
  mountedRef.current = false;
4582
4738
  };
4583
4739
  }, []);
4584
- useEffect18(() => {
4740
+ useEffect19(() => {
4585
4741
  if (!scopeId) return;
4586
4742
  setState(initialStateRef.current);
4587
4743
  reconnectAttemptRef.current = 0;
@@ -4640,7 +4796,7 @@ function usePlatformWS(options) {
4640
4796
  wsRef.current = null;
4641
4797
  };
4642
4798
  }, [scopeId, path]);
4643
- const send = useRef15((msg) => {
4799
+ const send = useRef16((msg) => {
4644
4800
  wsRef.current?.send(JSON.stringify(msg));
4645
4801
  }).current;
4646
4802
  return { state, send };
@@ -4802,7 +4958,7 @@ function decodeAiStreamChunk(chunk) {
4802
4958
  }
4803
4959
 
4804
4960
  // src/client/subscriptions/useSubscription.ts
4805
- import { useCallback as useCallback25, useEffect as useEffect19, useState as useState16 } from "react";
4961
+ import { useCallback as useCallback26, useEffect as useEffect20, useState as useState17 } from "react";
4806
4962
 
4807
4963
  // src/shared/subscription.ts
4808
4964
  var ENTITLED_STATUSES = /* @__PURE__ */ new Set([
@@ -4833,7 +4989,7 @@ async function authedJson(path, init) {
4833
4989
  return data;
4834
4990
  }
4835
4991
  function useSubscription() {
4836
- const [state, setState] = useState16({
4992
+ const [state, setState] = useState17({
4837
4993
  tier: "free",
4838
4994
  status: "none",
4839
4995
  interval: null,
@@ -4842,9 +4998,9 @@ function useSubscription() {
4842
4998
  trialEndsAt: null,
4843
4999
  plans: []
4844
5000
  });
4845
- const [isLoading, setLoading] = useState16(true);
4846
- const [error, setError] = useState16(null);
4847
- const refresh = useCallback25(async () => {
5001
+ const [isLoading, setLoading] = useState17(true);
5002
+ const [error, setError] = useState17(null);
5003
+ const refresh = useCallback26(async () => {
4848
5004
  setLoading(true);
4849
5005
  try {
4850
5006
  const r = await authedJson("/_deepspace/subscriptions/me");
@@ -4864,15 +5020,15 @@ function useSubscription() {
4864
5020
  setLoading(false);
4865
5021
  }
4866
5022
  }, []);
4867
- useEffect19(() => {
5023
+ useEffect20(() => {
4868
5024
  refresh();
4869
5025
  }, [refresh]);
4870
5026
  const entitled = isEntitled(state.tier, state.status);
4871
- const hasTier = useCallback25(
5027
+ const hasTier = useCallback26(
4872
5028
  (slug) => state.tier === slug && isEntitled(state.tier, state.status),
4873
5029
  [state.tier, state.status]
4874
5030
  );
4875
- const isAtLeast = useCallback25(
5031
+ const isAtLeast = useCallback26(
4876
5032
  (slug) => {
4877
5033
  if (!isEntitled(state.tier, state.status)) return false;
4878
5034
  const targetRank = state.plans.find((p) => p.slug === slug)?.rank;
@@ -4882,7 +5038,7 @@ function useSubscription() {
4882
5038
  },
4883
5039
  [state.plans, state.tier, state.status]
4884
5040
  );
4885
- const subscribe = useCallback25(
5041
+ const subscribe = useCallback26(
4886
5042
  async (planSlug, opts) => {
4887
5043
  const result = await authedJson("/_deepspace/subscriptions/checkout", {
4888
5044
  method: "POST",
@@ -4902,7 +5058,7 @@ function useSubscription() {
4902
5058
  },
4903
5059
  [refresh]
4904
5060
  );
4905
- const openPortal = useCallback25(
5061
+ const openPortal = useCallback26(
4906
5062
  async (returnUrl) => {
4907
5063
  return authedJson("/_deepspace/subscriptions/portal", {
4908
5064
  method: "POST",
@@ -4971,7 +5127,7 @@ function PricingTable(props) {
4971
5127
  }
4972
5128
 
4973
5129
  // src/client/charges/useCheckout.ts
4974
- import { useCallback as useCallback26, useEffect as useEffect20, useMemo as useMemo15, useState as useState17 } from "react";
5130
+ import { useCallback as useCallback27, useEffect as useEffect21, useMemo as useMemo15, useState as useState18 } from "react";
4975
5131
  async function authedJson2(path, init) {
4976
5132
  const token = await getAuthToken();
4977
5133
  const res = await fetch(path, {
@@ -4990,10 +5146,10 @@ async function authedJson2(path, init) {
4990
5146
  return data;
4991
5147
  }
4992
5148
  function useCheckout(opts) {
4993
- const [purchases, setPurchases] = useState17([]);
4994
- const [isLoading, setLoading] = useState17(true);
4995
- const [error, setError] = useState17(null);
4996
- const refresh = useCallback26(async () => {
5149
+ const [purchases, setPurchases] = useState18([]);
5150
+ const [isLoading, setLoading] = useState18(true);
5151
+ const [error, setError] = useState18(null);
5152
+ const refresh = useCallback27(async () => {
4997
5153
  setLoading(true);
4998
5154
  try {
4999
5155
  const r = await authedJson2(
@@ -5007,10 +5163,10 @@ function useCheckout(opts) {
5007
5163
  setLoading(false);
5008
5164
  }
5009
5165
  }, []);
5010
- useEffect20(() => {
5166
+ useEffect21(() => {
5011
5167
  refresh();
5012
5168
  }, [refresh]);
5013
- const chargeOnce = useCallback26(
5169
+ const chargeOnce = useCallback27(
5014
5170
  async (chargeOpts) => {
5015
5171
  setError(null);
5016
5172
  const common = {
@@ -5044,7 +5200,7 @@ function useCheckout(opts) {
5044
5200
  },
5045
5201
  []
5046
5202
  );
5047
- const ownsProduct = useCallback26(
5203
+ const ownsProduct = useCallback27(
5048
5204
  (productId) => purchases.some((p) => p.productId === productId),
5049
5205
  [purchases]
5050
5206
  );
@@ -5895,9 +6051,9 @@ AlertDescription.displayName = "AlertDescription";
5895
6051
  import {
5896
6052
  createContext as createContext4,
5897
6053
  useContext as useContext6,
5898
- useState as useState18,
5899
- useCallback as useCallback27,
5900
- useEffect as useEffect21
6054
+ useState as useState19,
6055
+ useCallback as useCallback28,
6056
+ useEffect as useEffect22
5901
6057
  } from "react";
5902
6058
  import { jsx as jsx28, jsxs as jsxs10 } from "react/jsx-runtime";
5903
6059
  function CheckCircleIcon({ className }) {
@@ -5944,14 +6100,14 @@ function ToastProvider({
5944
6100
  position = "bottom-right",
5945
6101
  maxToasts = 5
5946
6102
  }) {
5947
- const [toasts, setToasts] = useState18([]);
5948
- const dismiss = useCallback27((id) => {
6103
+ const [toasts, setToasts] = useState19([]);
6104
+ const dismiss = useCallback28((id) => {
5949
6105
  setToasts((prev) => prev.filter((t) => t.id !== id));
5950
6106
  }, []);
5951
- const dismissAll = useCallback27(() => {
6107
+ const dismissAll = useCallback28(() => {
5952
6108
  setToasts([]);
5953
6109
  }, []);
5954
- const addToast = useCallback27(
6110
+ const addToast = useCallback28(
5955
6111
  (options) => {
5956
6112
  const id = Math.random().toString(36).slice(2);
5957
6113
  const duration = options.duration ?? 5e3;
@@ -5965,23 +6121,23 @@ function ToastProvider({
5965
6121
  },
5966
6122
  [dismiss, maxToasts]
5967
6123
  );
5968
- const toast = useCallback27(
6124
+ const toast = useCallback28(
5969
6125
  (options) => addToast(options),
5970
6126
  [addToast]
5971
6127
  );
5972
- const success = useCallback27(
6128
+ const success = useCallback28(
5973
6129
  (title, description) => addToast({ type: "success", title, description }),
5974
6130
  [addToast]
5975
6131
  );
5976
- const error = useCallback27(
6132
+ const error = useCallback28(
5977
6133
  (title, description) => addToast({ type: "error", title, description }),
5978
6134
  [addToast]
5979
6135
  );
5980
- const warning = useCallback27(
6136
+ const warning = useCallback28(
5981
6137
  (title, description) => addToast({ type: "warning", title, description }),
5982
6138
  [addToast]
5983
6139
  );
5984
- const info = useCallback27(
6140
+ const info = useCallback28(
5985
6141
  (title, description) => addToast({ type: "info", title, description }),
5986
6142
  [addToast]
5987
6143
  );
@@ -6018,8 +6174,8 @@ var TOAST_CONFIG = {
6018
6174
  };
6019
6175
  function ToastItem({ toast, onDismiss }) {
6020
6176
  const { Icon: Icon2, accent, icon } = TOAST_CONFIG[toast.type];
6021
- const [exiting, setExiting] = useState18(false);
6022
- useEffect21(() => {
6177
+ const [exiting, setExiting] = useState19(false);
6178
+ useEffect22(() => {
6023
6179
  if (exiting) {
6024
6180
  const timer = setTimeout(onDismiss, 150);
6025
6181
  return () => clearTimeout(timer);
@@ -6701,6 +6857,7 @@ export {
6701
6857
  useGameRoom,
6702
6858
  useInbox,
6703
6859
  useIsDarkTheme,
6860
+ useJobs,
6704
6861
  useMessages,
6705
6862
  useMutations,
6706
6863
  usePlatform,