@smartspace/chat-ui 1.13.1-pr.252.acadb9f → 1.13.1-pr.256.1f430b8

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/index.d.ts CHANGED
@@ -238,6 +238,14 @@ type MessageThread = {
238
238
  totalMessages: number;
239
239
  pinned: boolean;
240
240
  workSpaceId: string;
241
+ /**
242
+ * Monotonic version of when this summary was emitted (epoch ms). Used by
243
+ * `applyThreadToCache` to reject stale writes — e.g. a SignalR summary
244
+ * landing after a fresher SSE thread frame because the server's DB write
245
+ * lagged Redis. Mappers derive this from `lastUpdatedAt`; client-side
246
+ * writers like `ensureDraftThread` use `Date.now()`.
247
+ */
248
+ summaryEmittedAt: number;
241
249
  };
242
250
  type ThreadsResponse = {
243
251
  data: MessageThread[];
@@ -969,20 +977,6 @@ declare function mapMentionUserDtoToModel(dto: MentionUserDto): MentionUser;
969
977
  declare function mapWorkspaceDtoToModel(dto: WorkspaceDto): Workspace;
970
978
  declare const mapWorkspacesDtoToModels: (arr: WorkspacesListItemDto[]) => Workspace[];
971
979
 
972
- /**
973
- * Write a freshly-observed thread (from SignalR or an SSE thread frame)
974
- * directly into the relevant query caches so subscribers paint without a
975
- * refetch roundtrip.
976
- *
977
- * - Merges into `threadsKeys.detail(workspaceId, thread.id)`.
978
- * - Splices into every threads-list cache for the workspace, handling both
979
- * finite `ThreadsResponse` and infinite `{ pages, pageParams }` shapes.
980
- *
981
- * Returns `true` when the thread was found in at least one list cache.
982
- * Callers that need to surface brand-new threads (e.g. another user just
983
- * created one) can fall back to invalidating the list queries when this
984
- * returns `false`.
985
- */
986
980
  declare function applyThreadToCache(qc: QueryClient, thread: MessageThread): boolean;
987
981
  /**
988
982
  * Invalidate every threads-list cache for a workspace. Use as a fallback when
@@ -1019,6 +1013,23 @@ declare function unmarkDraftThreadId(threadId: string): void;
1019
1013
  declare function isDraftThreadId(threadId?: string | null): boolean;
1020
1014
  declare function createDraftThreadId(): string;
1021
1015
 
1016
+ /**
1017
+ * Treat an API date string as UTC even when it lacks a trailing "Z".
1018
+ * If already a Date, returns it as-is (Date stores UTC internally).
1019
+ */
1020
+ declare function utcDate(value: string | Date): Date;
1021
+ /**
1022
+ * Zod schema that coerces a Date, ISO string, or numeric timestamp
1023
+ * from the API into a Date object, ensuring timezone-less strings
1024
+ * are treated as UTC.
1025
+ */
1026
+ declare const DateFromApi: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodCoercedDate<unknown>>;
1027
+
1028
+ declare function parseDateTime(date: Date | string, customFormat?: string): string;
1029
+ declare function parseDateTimeHuman(date: Date | string): string;
1030
+
1031
+ declare function getUserPhotoUrl(userId: string | null | undefined): string | undefined;
1032
+
1022
1033
  declare const messagesKeys: {
1023
1034
  all: readonly ["messages"];
1024
1035
  lists: () => readonly ["messages", "list"];
@@ -1301,4 +1312,4 @@ declare function useModels({ search, take, skip, }?: {
1301
1312
  total: number;
1302
1313
  }, Error>;
1303
1314
 
1304
- export { type ChatContextIds, type ChatIdentity, ChatProvider, type ChatProviderProps, type ChatService, ChatVariablesForm, DRAFT_THREAD_PREFIX, type FileInfo$1 as FileInfo, type FileScope, type FlowRunVariables, MarkdownEditor, type MarkdownEditorHandle, type MentionUser, type Message, MessageComposer, type MessageComposerProps, type MessageContentItem, type MessageError, MessageList, type MessageListProps, MessageListSkeleton, MessageMarkdown, type MessageThread, type MessageValue, MessageValueType, type Model, type ModelProperty, NEW_THREAD_ID, THREAD_LIST_PAGE_SIZE, type ThreadsResponse, type Variables, type Workspace, applyDeltaToMessage, applyThreadToCache, createDraftThreadId, createThreadId, downloadFileBlobOptions, filesKeys, flowRunsKeys, getModelIcon, getThreadPlaceholderFromListCache, invalidateWorkspaceThreadLists, isDraftThreadId, mapFileInfoDtoToModel, mapMentionUserDtoToModel, mapMessageDtoToModel, mapMessageErrorDtoToModel, mapMessageValueDtoToModel, mapMessagesDtoToModels, mapSignalRThreadSummaryToModel, mapThreadDtoToModel, mapThreadsResponseDtoToModel, mapWorkspaceDtoToModel, mapWorkspacesDtoToModels, markDraftThreadId, messagesKeys, messagesListOptions, messagesMutationsKeys, modelsKeys, setThreadOptimisticRunning, setThreadRunningInLists, taggableUsersOptions, threadDetailOptions, threadsKeys, unmarkDraftThreadId, useAddInputToMessage, useChatContext, useChatIdentity, useChatService, useDownloadFileBlobQuery, useFileMutations, useFlowRunVariables, useMessages, useModels, useSendMessage, useTaggableWorkspaceUsers, useThread, useThreadIsRunning, useUpdateFlowRunVariable, useWorkspace, workspaceDetailOptions, workspaceKeys };
1315
+ export { type ChatContextIds, type ChatIdentity, ChatProvider, type ChatProviderProps, type ChatService, ChatVariablesForm, DRAFT_THREAD_PREFIX, DateFromApi, type FileInfo$1 as FileInfo, type FileScope, type FlowRunVariables, MarkdownEditor, type MarkdownEditorHandle, type MentionUser, type Message, MessageComposer, type MessageComposerProps, type MessageContentItem, type MessageError, MessageList, type MessageListProps, MessageListSkeleton, MessageMarkdown, type MessageThread, type MessageValue, MessageValueType, type Model, type ModelProperty, NEW_THREAD_ID, THREAD_LIST_PAGE_SIZE, type ThreadsResponse, type Variables, type Workspace, applyDeltaToMessage, applyThreadToCache, createDraftThreadId, createThreadId, downloadFileBlobOptions, filesKeys, flowRunsKeys, getModelIcon, getThreadPlaceholderFromListCache, getUserPhotoUrl, invalidateWorkspaceThreadLists, isDraftThreadId, mapFileInfoDtoToModel, mapMentionUserDtoToModel, mapMessageDtoToModel, mapMessageErrorDtoToModel, mapMessageValueDtoToModel, mapMessagesDtoToModels, mapSignalRThreadSummaryToModel, mapThreadDtoToModel, mapThreadsResponseDtoToModel, mapWorkspaceDtoToModel, mapWorkspacesDtoToModels, markDraftThreadId, messagesKeys, messagesListOptions, messagesMutationsKeys, modelsKeys, parseDateTime, parseDateTimeHuman, setThreadOptimisticRunning, setThreadRunningInLists, taggableUsersOptions, threadDetailOptions, threadsKeys, unmarkDraftThreadId, useAddInputToMessage, useChatContext, useChatIdentity, useChatService, useDownloadFileBlobQuery, useFileMutations, useFlowRunVariables, useMessages, useModels, useSendMessage, useTaggableWorkspaceUsers, useThread, useThreadIsRunning, useUpdateFlowRunVariable, useWorkspace, utcDate, workspaceDetailOptions, workspaceKeys };
package/dist/index.js CHANGED
@@ -3221,7 +3221,19 @@ var threadsKeys = {
3221
3221
  };
3222
3222
 
3223
3223
  // src/domains/threads/cache.ts
3224
+ function isStaleSummary(incoming, existing) {
3225
+ if (!existing) return false;
3226
+ if (typeof existing.summaryEmittedAt !== "number") return false;
3227
+ if (typeof incoming.summaryEmittedAt !== "number") return false;
3228
+ return incoming.summaryEmittedAt < existing.summaryEmittedAt;
3229
+ }
3224
3230
  function applyThreadToCache(qc, thread) {
3231
+ const existingDetail = qc.getQueryData(
3232
+ threadsKeys.detail(thread.workSpaceId, thread.id)
3233
+ );
3234
+ if (isStaleSummary(thread, existingDetail)) {
3235
+ return false;
3236
+ }
3225
3237
  qc.setQueryData(
3226
3238
  threadsKeys.detail(thread.workSpaceId, thread.id),
3227
3239
  (old) => ({ ...old ?? thread, ...thread })
@@ -3242,6 +3254,7 @@ function applyThreadToCache(qc, thread) {
3242
3254
  if (!page?.data) return page;
3243
3255
  const idx2 = page.data.findIndex((t) => t.id === thread.id);
3244
3256
  if (idx2 === -1) return page;
3257
+ if (isStaleSummary(thread, page.data[idx2])) return page;
3245
3258
  changed = true;
3246
3259
  foundInList = true;
3247
3260
  const nextData2 = page.data.slice();
@@ -3254,6 +3267,7 @@ function applyThreadToCache(qc, thread) {
3254
3267
  if (!list2.data) return old;
3255
3268
  const idx = list2.data.findIndex((t) => t.id === thread.id);
3256
3269
  if (idx === -1) return old;
3270
+ if (isStaleSummary(thread, list2.data[idx])) return old;
3257
3271
  foundInList = true;
3258
3272
  const nextData = list2.data.slice();
3259
3273
  nextData[idx] = { ...nextData[idx], ...thread };
@@ -3310,7 +3324,7 @@ function utcDate(value) {
3310
3324
  }
3311
3325
  return new Date(value);
3312
3326
  }
3313
- z.preprocess((val) => {
3327
+ var DateFromApi = z.preprocess((val) => {
3314
3328
  if (typeof val === "string" && !hasTimezone(val)) {
3315
3329
  return val + "Z";
3316
3330
  }
@@ -3323,36 +3337,40 @@ var {
3323
3337
  messageThreadsGetMessageThreadWorkspacesWorkspaceIdMessagethreadsIdResponse: threadResponseSchema
3324
3338
  } = ChatZod;
3325
3339
  function mapThreadDtoToModel(dto) {
3340
+ const lastUpdatedAt = utcDate(dto.lastUpdatedAt);
3326
3341
  return {
3327
3342
  id: dto.id,
3328
3343
  createdAt: utcDate(dto.createdAt),
3329
3344
  createdBy: dto.createdBy ?? "",
3330
3345
  createdByUserId: dto.createdByUserId,
3331
3346
  isFlowRunning: dto.isFlowRunning,
3332
- lastUpdatedAt: utcDate(dto.lastUpdatedAt),
3347
+ lastUpdatedAt,
3333
3348
  lastUpdatedByUserId: dto.lastUpdatedByUserId,
3334
3349
  name: dto.name ?? "",
3335
3350
  totalMessages: dto.totalMessages,
3336
3351
  pinned: dto.favorited,
3337
- workSpaceId: dto.workSpaceId
3352
+ workSpaceId: dto.workSpaceId,
3353
+ summaryEmittedAt: lastUpdatedAt.getTime()
3338
3354
  };
3339
3355
  }
3340
3356
  function mapThreadsResponseDtoToModel(dto) {
3341
3357
  return { data: dto.data.map(mapThreadDtoToModel), total: dto.total };
3342
3358
  }
3343
3359
  function mapSignalRThreadSummaryToModel(summary) {
3360
+ const lastUpdatedAt = utcDate(summary.lastUpdatedAt);
3344
3361
  return {
3345
3362
  id: summary.id,
3346
3363
  createdAt: utcDate(summary.createdAt),
3347
3364
  createdBy: summary.createdBy ?? "",
3348
3365
  createdByUserId: summary.createdByUserId,
3349
3366
  isFlowRunning: summary.isFlowRunning,
3350
- lastUpdatedAt: utcDate(summary.lastUpdatedAt),
3367
+ lastUpdatedAt,
3351
3368
  lastUpdatedByUserId: summary.lastUpdatedByUserId,
3352
3369
  name: summary.name ?? "",
3353
3370
  totalMessages: summary.totalMessages,
3354
3371
  pinned: summary.favorited,
3355
- workSpaceId: summary.workSpaceId
3372
+ workSpaceId: summary.workSpaceId,
3373
+ summaryEmittedAt: lastUpdatedAt.getTime()
3356
3374
  };
3357
3375
  }
3358
3376
  var threadDetailOptions = ({
@@ -3459,10 +3477,10 @@ function useSendMessage() {
3459
3477
  if (!threadId) throw new Error("Thread ID is required");
3460
3478
  if (!workspaceId) throw new Error("Workspace ID is required");
3461
3479
  const optimistic = {
3462
- id: `temp-${Date.now()}`,
3480
+ id: `temp-${crypto.randomUUID()}`,
3463
3481
  values: [
3464
3482
  {
3465
- id: `temp-${Date.now()}-prompt`,
3483
+ id: `temp-${crypto.randomUUID()}-prompt`,
3466
3484
  type: "Input" /* INPUT */,
3467
3485
  name: "prompt",
3468
3486
  value: contentList,
@@ -3473,7 +3491,7 @@ function useSendMessage() {
3473
3491
  },
3474
3492
  ...files?.length ? [
3475
3493
  {
3476
- id: `temp-${Date.now()}-files`,
3494
+ id: `temp-${crypto.randomUUID()}-files`,
3477
3495
  type: "Input" /* INPUT */,
3478
3496
  name: "files",
3479
3497
  value: files,
@@ -3485,7 +3503,7 @@ function useSendMessage() {
3485
3503
  ] : [],
3486
3504
  ...variables && Object.keys(variables).length ? [
3487
3505
  {
3488
- id: `temp-${Date.now()}-vars`,
3506
+ id: `temp-${crypto.randomUUID()}-vars`,
3489
3507
  type: "Input" /* INPUT */,
3490
3508
  name: "variables",
3491
3509
  value: variables,
@@ -3627,7 +3645,10 @@ var workspaceDetailOptions = ({
3627
3645
  });
3628
3646
  function useWorkspace(workspaceId) {
3629
3647
  const service = useChatService();
3630
- return useQuery(workspaceDetailOptions({ service, workspaceId }));
3648
+ return useQuery({
3649
+ ...workspaceDetailOptions({ service, workspaceId }),
3650
+ enabled: !!workspaceId
3651
+ });
3631
3652
  }
3632
3653
  var taggableUsersOptions = ({
3633
3654
  service,
@@ -3815,11 +3836,13 @@ function MessageComposer({
3815
3836
  workspaceId,
3816
3837
  threadId: isDraftThread ? void 0 : threadId
3817
3838
  });
3818
- if (typeof window !== "undefined") {
3819
- window.__ssDownloadFile = async (id) => {
3820
- return await getFileBlobUrl(id);
3839
+ useEffect(() => {
3840
+ if (typeof window === "undefined") return;
3841
+ window.__ssDownloadFile = (id) => getFileBlobUrl(id);
3842
+ return () => {
3843
+ if (window.__ssDownloadFile) delete window.__ssDownloadFile;
3821
3844
  };
3822
- }
3845
+ }, [getFileBlobUrl]);
3823
3846
  const onUploadFiles = async (files) => {
3824
3847
  const res = await uploadFilesMutation.mutateAsync(files);
3825
3848
  return res.map(({ id, name }) => ({ id, name }));
@@ -19081,14 +19104,20 @@ dayjs.extend(relativeTime);
19081
19104
  dayjs.extend(advancedFormat);
19082
19105
  function parseDateTime(date, customFormat) {
19083
19106
  const d = dayjs.utc(date).local();
19084
- return d.format(customFormat);
19107
+ if (customFormat === "X") return Math.floor(d.valueOf() / 1e3).toString();
19108
+ if (customFormat === "x") return d.valueOf().toString();
19109
+ return d.format(customFormat ?? "YYYY-MM-DD HH:mm:ss");
19110
+ }
19111
+ function parseDateTimeHuman(date) {
19112
+ return dayjs.utc(date).local().fromNow();
19085
19113
  }
19086
19114
 
19087
19115
  // src/shared/utils/userPhoto.ts
19088
19116
  function getChatApiBaseUrl() {
19089
19117
  try {
19090
19118
  const w = window;
19091
- const cfg = w?.ssconfig?.Chat_Api_Uri ?? import.meta.env.VITE_CHAT_API_URI;
19119
+ const env2 = import.meta.env;
19120
+ const cfg = w?.ssconfig?.Chat_Api_Uri ?? env2?.VITE_CHAT_API_URI;
19092
19121
  return typeof cfg === "string" && cfg.trim() ? cfg.trim() : "";
19093
19122
  } catch {
19094
19123
  return "";
@@ -20141,6 +20170,6 @@ function mapWorkspaceDtoToModel(dto) {
20141
20170
  }
20142
20171
  var mapWorkspacesDtoToModels = (arr) => arr.map(mapWorkspaceDtoToModel);
20143
20172
 
20144
- export { ChatProvider, ChatVariablesForm, DRAFT_THREAD_PREFIX, MarkdownEditor, MessageComposer, MessageList, MessageListSkeleton, MessageMarkdown, MessageValueType, NEW_THREAD_ID, THREAD_LIST_PAGE_SIZE, applyDeltaToMessage, applyThreadToCache, createDraftThreadId, createThreadId, downloadFileBlobOptions, filesKeys, flowRunsKeys, getModelIcon, getThreadPlaceholderFromListCache, invalidateWorkspaceThreadLists, isDraftThreadId, mapFileInfoDtoToModel, mapMentionUserDtoToModel, mapMessageDtoToModel, mapMessageErrorDtoToModel, mapMessageValueDtoToModel, mapMessagesDtoToModels, mapSignalRThreadSummaryToModel, mapThreadDtoToModel, mapThreadsResponseDtoToModel, mapWorkspaceDtoToModel, mapWorkspacesDtoToModels, markDraftThreadId, messagesKeys, messagesListOptions, messagesMutationsKeys, modelsKeys, setThreadOptimisticRunning, setThreadRunningInLists, taggableUsersOptions, threadDetailOptions, threadsKeys, unmarkDraftThreadId, useAddInputToMessage, useChatContext, useChatIdentity, useChatService, useDownloadFileBlobQuery, useFileMutations, useFlowRunVariables, useMessages, useModels, useSendMessage, useTaggableWorkspaceUsers, useThread, useThreadIsRunning, useUpdateFlowRunVariable, useWorkspace, workspaceDetailOptions, workspaceKeys };
20173
+ export { ChatProvider, ChatVariablesForm, DRAFT_THREAD_PREFIX, DateFromApi, MarkdownEditor, MessageComposer, MessageList, MessageListSkeleton, MessageMarkdown, MessageValueType, NEW_THREAD_ID, THREAD_LIST_PAGE_SIZE, applyDeltaToMessage, applyThreadToCache, createDraftThreadId, createThreadId, downloadFileBlobOptions, filesKeys, flowRunsKeys, getModelIcon, getThreadPlaceholderFromListCache, getUserPhotoUrl, invalidateWorkspaceThreadLists, isDraftThreadId, mapFileInfoDtoToModel, mapMentionUserDtoToModel, mapMessageDtoToModel, mapMessageErrorDtoToModel, mapMessageValueDtoToModel, mapMessagesDtoToModels, mapSignalRThreadSummaryToModel, mapThreadDtoToModel, mapThreadsResponseDtoToModel, mapWorkspaceDtoToModel, mapWorkspacesDtoToModels, markDraftThreadId, messagesKeys, messagesListOptions, messagesMutationsKeys, modelsKeys, parseDateTime, parseDateTimeHuman, setThreadOptimisticRunning, setThreadRunningInLists, taggableUsersOptions, threadDetailOptions, threadsKeys, unmarkDraftThreadId, useAddInputToMessage, useChatContext, useChatIdentity, useChatService, useDownloadFileBlobQuery, useFileMutations, useFlowRunVariables, useMessages, useModels, useSendMessage, useTaggableWorkspaceUsers, useThread, useThreadIsRunning, useUpdateFlowRunVariable, useWorkspace, utcDate, workspaceDetailOptions, workspaceKeys };
20145
20174
  //# sourceMappingURL=index.js.map
20146
20175
  //# sourceMappingURL=index.js.map