@fitzzero/quickdraw-core 3.6.0 → 3.8.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.
Files changed (37) hide show
  1. package/README.md +218 -64
  2. package/dist/client/index.d.ts +34 -4
  3. package/dist/client/index.js +57 -65
  4. package/dist/client/index.js.map +1 -1
  5. package/dist/client/testing.d.ts +1 -1
  6. package/dist/client/testing.js.map +1 -1
  7. package/dist/server/express/index.d.ts +37 -0
  8. package/dist/server/express/index.js +60 -0
  9. package/dist/server/express/index.js.map +1 -0
  10. package/dist/server/index.d.ts +330 -5
  11. package/dist/server/index.js +593 -144
  12. package/dist/server/index.js.map +1 -1
  13. package/dist/server/testing-prisma.d.ts +101 -0
  14. package/dist/server/testing-prisma.js +172 -0
  15. package/dist/server/testing-prisma.js.map +1 -0
  16. package/dist/server/testing.d.ts +1 -1
  17. package/dist/server/testing.js +87 -22
  18. package/dist/server/testing.js.map +1 -1
  19. package/dist/shared/index.d.ts +77 -1
  20. package/dist/shared/index.js +5 -1
  21. package/dist/shared/index.js.map +1 -1
  22. package/dist/{types-DniMxkQs.d.ts → types-ClgSr90l.d.ts} +5 -1
  23. package/dist/{types-B1z5aXdR.d.ts → types-DUHPIy_5.d.ts} +20 -1
  24. package/eslint-config/index.mjs +1 -2
  25. package/eslint-plugin-quickdraw/index.mjs +15 -7
  26. package/eslint-plugin-quickdraw/rules/no-cross-service-mutations.mjs +31 -32
  27. package/eslint-plugin-quickdraw/rules/no-direct-prisma-mutations.mjs +17 -18
  28. package/eslint-plugin-quickdraw/rules/no-raw-button-strings.mjs +52 -0
  29. package/eslint-plugin-quickdraw/rules/no-raw-service-room-string.mjs +140 -0
  30. package/eslint-plugin-quickdraw/rules/no-raw-socket-emit.mjs +20 -22
  31. package/eslint-plugin-quickdraw/rules/no-raw-socket-on.mjs +17 -17
  32. package/eslint-plugin-quickdraw/rules/no-raw-tooltip-strings.mjs +59 -0
  33. package/eslint-plugin-quickdraw/rules/no-raw-typography-strings.mjs +52 -0
  34. package/eslint-plugin-quickdraw/rules/no-service-method-record.mjs +3 -3
  35. package/eslint-plugin-quickdraw/rules/no-unsafe-payload-cast.mjs +8 -8
  36. package/eslint-plugin-quickdraw/rules/require-zod-schema.mjs +15 -20
  37. package/package.json +74 -50
@@ -115,9 +115,7 @@ var QuickdrawSocketContext = React.createContext(null);
115
115
  function useQuickdrawSocket() {
116
116
  const context = React.useContext(QuickdrawSocketContext);
117
117
  if (!context) {
118
- throw new Error(
119
- "useQuickdrawSocket must be used within a QuickdrawProvider"
120
- );
118
+ throw new Error("useQuickdrawSocket must be used within a QuickdrawProvider");
121
119
  }
122
120
  return context;
123
121
  }
@@ -141,7 +139,8 @@ function QuickdrawProvider({
141
139
  queryClient,
142
140
  authToken,
143
141
  autoConnect = !!authToken,
144
- withCredentials = true
142
+ withCredentials = true,
143
+ socketPath
145
144
  }) {
146
145
  const [defaultQueryClient] = React.useState(() => createQueryClient());
147
146
  const actualQueryClient = queryClient ?? defaultQueryClient;
@@ -149,9 +148,7 @@ function QuickdrawProvider({
149
148
  const [isConnected, setIsConnected] = React.useState(false);
150
149
  const [userId, setUserId] = React.useState(null);
151
150
  const [serviceAccess, setServiceAccess] = React.useState({});
152
- const subscriptionRegistryRef = React.useRef(
153
- createSubscriptionRegistry()
154
- );
151
+ const subscriptionRegistryRef = React.useRef(createSubscriptionRegistry());
155
152
  const prevAuthTokenRef = React.useRef(authToken);
156
153
  const socketRef = React.useRef(null);
157
154
  const subscriptionBatcherRef = React.useRef(
@@ -167,7 +164,8 @@ function QuickdrawProvider({
167
164
  auth: authToUse ? { token: authToUse } : void 0,
168
165
  withCredentials,
169
166
  transports: ["websocket", "polling"],
170
- autoConnect: true
167
+ autoConnect: true,
168
+ ...socketPath ? { path: socketPath } : {}
171
169
  });
172
170
  newSocket.on("connect", () => {
173
171
  setIsConnected(true);
@@ -189,7 +187,7 @@ function QuickdrawProvider({
189
187
  socketRef.current = newSocket;
190
188
  setSocket(newSocket);
191
189
  },
192
- [serverUrl, withCredentials]
190
+ [serverUrl, withCredentials, socketPath]
193
191
  );
194
192
  const disconnect = React.useCallback(() => {
195
193
  if (socketRef.current) {
@@ -259,18 +257,14 @@ function useService(serviceName, methodName, options) {
259
257
  const timeout = setTimeout(() => {
260
258
  reject(new Error("Request timeout"));
261
259
  }, options?.timeout ?? 1e4);
262
- socket.emit(
263
- eventName,
264
- payload,
265
- (response) => {
266
- clearTimeout(timeout);
267
- if (response.success) {
268
- resolve(response.data);
269
- } else {
270
- reject(new Error(response.error));
271
- }
260
+ socket.emit(eventName, payload, (response) => {
261
+ clearTimeout(timeout);
262
+ if (response.success) {
263
+ resolve(response.data);
264
+ } else {
265
+ reject(new Error(response.error));
272
266
  }
273
- );
267
+ });
274
268
  });
275
269
  },
276
270
  onSuccess: (data) => {
@@ -334,24 +328,20 @@ function useServiceMethod(serviceName, methodName, options) {
334
328
  optionsRef.current?.onError?.(errorMsg);
335
329
  resolve(null);
336
330
  }, options?.timeout ?? 1e4);
337
- socket.emit(
338
- eventName,
339
- payload,
340
- (response) => {
341
- clearTimeout(timeout);
342
- setLoading(false);
343
- if (response.success) {
344
- setError(null);
345
- setData(response.data);
346
- optionsRef.current?.onSuccess?.(response.data);
347
- resolve(response.data);
348
- } else {
349
- setError(response.error);
350
- optionsRef.current?.onError?.(response.error);
351
- resolve(null);
352
- }
331
+ socket.emit(eventName, payload, (response) => {
332
+ clearTimeout(timeout);
333
+ setLoading(false);
334
+ if (response.success) {
335
+ setError(null);
336
+ setData(response.data);
337
+ optionsRef.current?.onSuccess?.(response.data);
338
+ resolve(response.data);
339
+ } else {
340
+ setError(response.error);
341
+ optionsRef.current?.onError?.(response.error);
342
+ resolve(null);
353
343
  }
354
- );
344
+ });
355
345
  });
356
346
  },
357
347
  [socket, isConnected, serviceName, methodName, options?.timeout]
@@ -402,18 +392,14 @@ function useServiceQuery(serviceName, methodName, payload, options) {
402
392
  const timeoutId = setTimeout(() => {
403
393
  reject(new Error("Request timeout"));
404
394
  }, timeout);
405
- socket.emit(
406
- eventName,
407
- payload,
408
- (response) => {
409
- clearTimeout(timeoutId);
410
- if (response.success) {
411
- resolve(response.data);
412
- } else {
413
- reject(new Error(response.error));
414
- }
395
+ socket.emit(eventName, payload, (response) => {
396
+ clearTimeout(timeoutId);
397
+ if (response.success) {
398
+ resolve(response.data);
399
+ } else {
400
+ reject(new Error(response.error));
415
401
  }
416
- );
402
+ });
417
403
  });
418
404
  }, [socket, isConnected, serviceName, methodName, payload, timeout]);
419
405
  React.useEffect(() => {
@@ -564,10 +550,7 @@ function useSubscription(serviceName, entryId, options = {}) {
564
550
  socket.on(updateEvent, handleUpdate);
565
551
  const handleBatchResponse = (response) => {
566
552
  if (response.success && response.data) {
567
- queryClient.setQueryData(
568
- queryKey,
569
- response.data
570
- );
553
+ queryClient.setQueryData(queryKey, response.data);
571
554
  setIsSubscribed(true);
572
555
  setError(null);
573
556
  onDataRef.current?.(response.data);
@@ -577,24 +560,14 @@ function useSubscription(serviceName, entryId, options = {}) {
577
560
  onErrorRef.current?.(response.error ?? "Subscription failed");
578
561
  }
579
562
  };
580
- subscriptionBatcher.enqueue(
581
- serviceName,
582
- entryId,
583
- requiredLevel,
584
- handleBatchResponse
585
- );
563
+ subscriptionBatcher.enqueue(serviceName, entryId, requiredLevel, handleBatchResponse);
586
564
  let visibilityDebounceTimer = null;
587
565
  const handleVisibilityChange = () => {
588
566
  if (document.visibilityState !== "visible") return;
589
567
  if (visibilityDebounceTimer) clearTimeout(visibilityDebounceTimer);
590
568
  visibilityDebounceTimer = setTimeout(() => {
591
569
  visibilityDebounceTimer = null;
592
- subscriptionBatcher.enqueue(
593
- serviceName,
594
- entryId,
595
- requiredLevel,
596
- handleBatchResponse
597
- );
570
+ subscriptionBatcher.enqueue(serviceName, entryId, requiredLevel, handleBatchResponse);
598
571
  }, 200);
599
572
  };
600
573
  if (refetchOnWindowFocus) {
@@ -693,6 +666,25 @@ function useRoomEvents(handlers, options) {
693
666
  };
694
667
  }, [socket, isConnected, enabled, stableEventNames]);
695
668
  }
669
+
670
+ // src/shared/types.ts
671
+ function channelEventName(serviceName, channelName) {
672
+ return `channel:${serviceName}:${channelName}`;
673
+ }
674
+
675
+ // src/client/useChannelSend.ts
676
+ function useChannelSend(serviceName, channelName) {
677
+ const { socket, isConnected } = useQuickdrawSocket();
678
+ const eventName = channelEventName(serviceName, channelName);
679
+ const send = React.useCallback(
680
+ (payload) => {
681
+ if (!socket?.connected) return;
682
+ socket.volatile.emit(eventName, payload);
683
+ },
684
+ [socket, eventName]
685
+ );
686
+ return { send, isReady: isConnected && !!socket };
687
+ }
696
688
  function useSocketInput(options) {
697
689
  const {
698
690
  state,
@@ -1223,6 +1215,6 @@ function routeRequiresAuth(pathname, navigation, userMenuItems) {
1223
1215
  return false;
1224
1216
  }
1225
1217
 
1226
- export { QuickdrawProvider, SocketCheckbox, SocketSelect, SocketSlider, SocketSwitch, SocketTextField, buildBreadcrumbs, clearAuthToken, findNavItemByHref, findParentNavItem, formatCurrency, formatDate, formatDateTime, formatNumber, formatPercent, getAuthToken, getOAuthUrl, logout, logoutAllDevices, parseJWTPayload, routeRequiresAuth, setAuthToken, truncate, useQuickdrawSocket, useRoomEvents, useService, useServiceMethod, useServiceQuery, useSocketInput, useSubscription };
1218
+ export { QuickdrawProvider, SocketCheckbox, SocketSelect, SocketSlider, SocketSwitch, SocketTextField, buildBreadcrumbs, clearAuthToken, findNavItemByHref, findParentNavItem, formatCurrency, formatDate, formatDateTime, formatNumber, formatPercent, getAuthToken, getOAuthUrl, logout, logoutAllDevices, parseJWTPayload, routeRequiresAuth, setAuthToken, truncate, useChannelSend, useQuickdrawSocket, useRoomEvents, useService, useServiceMethod, useServiceQuery, useSocketInput, useSubscription };
1227
1219
  //# sourceMappingURL=index.js.map
1228
1220
  //# sourceMappingURL=index.js.map