@luckystack/sync 0.9.2 → 0.10.1

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.js CHANGED
@@ -1,3 +1,7 @@
1
+ import {
2
+ SYNC_ERROR_CODES
3
+ } from "./chunk-AJ36D2PQ.js";
4
+
1
5
  // src/handleSyncRequest.ts
2
6
  import { randomUUID } from "crypto";
3
7
  import {
@@ -73,7 +77,7 @@ var waitUntilSocketDrained = async (socket, packetThreshold, isAborted) => {
73
77
  }
74
78
  };
75
79
  var collectRoomSocketsForPressure = (receiver) => {
76
- const io = getIoInstance();
80
+ const io = getIoInstance({ raw: true });
77
81
  if (!io) return [];
78
82
  if (!receiver) return [];
79
83
  if (receiver === "all") {
@@ -893,22 +897,16 @@ async function runSyncServerExecution({
893
897
  }
894
898
  return { ok: true, serverOutput: serverSyncResult };
895
899
  }
896
- async function runSyncFanout({
900
+ async function resolveSyncRecipients({
897
901
  ioInstance,
898
902
  receiver,
899
903
  resolvedName,
900
- normalizedData,
901
- serverOutput,
902
904
  user,
903
905
  socket,
904
906
  responseIndex,
905
907
  buildSyncError,
906
908
  preferredLocale,
907
- cleanupRequest,
908
- ignoreSelf,
909
- token,
910
- syncObject,
911
- functionsObject
909
+ cleanupRequest
912
910
  }) {
913
911
  const physicalReceiver = receiver === "all" ? "all" : formatRoomName2(receiver, { purpose: "broadcast", userId: user?.id ?? null });
914
912
  const sockets = physicalReceiver === "all" ? await ioInstance.fetchSockets() : await ioInstance.in(physicalReceiver).fetchSockets();
@@ -918,8 +916,27 @@ async function runSyncFanout({
918
916
  }
919
917
  cleanupRequest();
920
918
  rejectSync({ socket, responseIndex, buildSyncError, response: { status: "error", errorCode: "sync.noReceiversFound" }, preferred: preferredLocale, userLanguage: user?.language });
921
- return false;
919
+ return null;
922
920
  }
921
+ return sockets;
922
+ }
923
+ async function runSyncFanout({
924
+ sockets,
925
+ receiver,
926
+ resolvedName,
927
+ normalizedData,
928
+ serverOutput,
929
+ user,
930
+ socket,
931
+ responseIndex,
932
+ buildSyncError,
933
+ preferredLocale,
934
+ cleanupRequest,
935
+ ignoreSelf,
936
+ token,
937
+ syncObject,
938
+ functionsObject
939
+ }) {
923
940
  const fanoutPayload = {
924
941
  routeName: resolvedName,
925
942
  data: normalizedData,
@@ -972,6 +989,7 @@ async function runSyncFanout({
972
989
  routeName: resolvedName,
973
990
  receiver,
974
991
  recipientSocketId: tempSocket.id,
992
+ recipientToken: tempToken,
975
993
  recipientUserId: null,
976
994
  serverOutput
977
995
  });
@@ -1123,6 +1141,18 @@ async function handleSyncRequestInner({ msg, socket, token }) {
1123
1141
  return;
1124
1142
  }
1125
1143
  if (!await runPreAuthorizeHook({ resolvedName, normalizedData, user, receiver, socket, responseIndex, buildSyncError, preferredLocale, cleanupRequest })) return;
1144
+ const sockets = await resolveSyncRecipients({
1145
+ ioInstance,
1146
+ receiver,
1147
+ resolvedName,
1148
+ user,
1149
+ socket,
1150
+ responseIndex,
1151
+ buildSyncError,
1152
+ preferredLocale,
1153
+ cleanupRequest
1154
+ });
1155
+ if (sockets === null) return;
1126
1156
  const executionResult = await runSyncServerExecution({
1127
1157
  serverSyncEntry,
1128
1158
  resolvedName,
@@ -1144,7 +1174,7 @@ async function handleSyncRequestInner({ msg, socket, token }) {
1144
1174
  if (!executionResult.ok) return;
1145
1175
  const { serverOutput } = executionResult;
1146
1176
  const fanoutAcked = await runSyncFanout({
1147
- ioInstance,
1177
+ sockets,
1148
1178
  receiver,
1149
1179
  resolvedName,
1150
1180
  normalizedData,
@@ -1608,9 +1638,33 @@ async function stageExecuteServer(resolvedName, serverSyncEntry, functionsObject
1608
1638
  }
1609
1639
  return { serverOutput: serverSyncResult };
1610
1640
  }
1611
- async function stageFanout(resolvedName, callbackName, serverOutput, syncObject, functionsObject, ctx) {
1612
- const { data, normalizedReceiver, token, ignoreSelf, user, buildSyncError, preferredLocale } = ctx;
1641
+ async function stageResolveRecipients(resolvedName, ctx) {
1642
+ const { normalizedReceiver, user, buildSyncError, preferredLocale } = ctx;
1613
1643
  const ioInstance = getIoInstance3();
1644
+ const physicalReceiver = normalizedReceiver === "all" ? "all" : formatRoomName3(normalizedReceiver, { purpose: "broadcast", userId: user?.id ?? null });
1645
+ const sockets = physicalReceiver === "all" ? await ioInstance.fetchSockets() : await ioInstance.in(physicalReceiver).fetchSockets();
1646
+ if (sockets.length === 0) {
1647
+ if (shouldLogDev()) {
1648
+ getLogger4().warn("http sync: no sockets found for receiver", { receiver: normalizedReceiver, sync: resolvedName, transport: "http" });
1649
+ }
1650
+ return {
1651
+ error: buildSyncError({
1652
+ response: { status: "error", errorCode: "sync.noReceiversFound", httpStatus: 404 },
1653
+ preferred: preferredLocale,
1654
+ userLanguage: user?.language
1655
+ })
1656
+ };
1657
+ }
1658
+ return { sockets };
1659
+ }
1660
+ async function stageFanout(resolvedName, callbackName, serverOutput, sockets, syncObject, functionsObject, ctx) {
1661
+ const { data, normalizedReceiver, token, ignoreSelf, user, buildSyncError, preferredLocale } = ctx;
1662
+ if (shouldLogDev() && token && getProjectConfig4().sync.requireRoomMembership && normalizedReceiver !== "all" && normalizedReceiver !== token && !sockets.some((recipient) => extractTokenFromSocket2(recipient) === token)) {
1663
+ getLogger4().warn(
1664
+ `http sync: ${resolvedName} was authorized on the session's roomCodes, but the caller has no socket in "${normalizedReceiver}" \u2014 it will not receive this fan-out`,
1665
+ { sync: resolvedName, receiver: normalizedReceiver, transport: "http" }
1666
+ );
1667
+ }
1614
1668
  const fanoutPayload = {
1615
1669
  routeName: resolvedName,
1616
1670
  data,
@@ -1632,8 +1686,6 @@ async function stageFanout(resolvedName, callbackName, serverOutput, syncObject,
1632
1686
  userLanguage: user?.language
1633
1687
  });
1634
1688
  }
1635
- const physicalReceiver = normalizedReceiver === "all" ? "all" : formatRoomName3(normalizedReceiver, { purpose: "broadcast", userId: user?.id ?? null });
1636
- const sockets = physicalReceiver === "all" ? await ioInstance.fetchSockets() : await ioInstance.in(physicalReceiver).fetchSockets();
1637
1689
  let recipientCount = 0;
1638
1690
  const { fanoutYieldEvery, fanoutYieldMs } = getProjectConfig4().sync;
1639
1691
  const yieldEvery = Math.max(1, fanoutYieldEvery);
@@ -1651,6 +1703,7 @@ async function stageFanout(resolvedName, callbackName, serverOutput, syncObject,
1651
1703
  routeName: resolvedName,
1652
1704
  receiver: normalizedReceiver,
1653
1705
  recipientSocketId: tempSocket.id,
1706
+ recipientToken: tempToken,
1654
1707
  recipientUserId: null,
1655
1708
  serverOutput
1656
1709
  });
@@ -1785,6 +1838,9 @@ async function handleHttpSyncRequestScoped({
1785
1838
  if (rateLimitResult) return rateLimitResult;
1786
1839
  const authorizeHookError = await stageRunAuthorizeHooks(resolvedName, ctx);
1787
1840
  if (authorizeHookError) return authorizeHookError;
1841
+ const recipientsResult = await stageResolveRecipients(resolvedName, ctx);
1842
+ if (recipientsResult.error) return recipientsResult.error;
1843
+ const { sockets } = recipientsResult;
1788
1844
  let serverOutput = {};
1789
1845
  if (serverSyncEntry) {
1790
1846
  const validationError = await stageValidateInput(resolvedName, serverSyncEntry, ctx);
@@ -1793,7 +1849,7 @@ async function handleHttpSyncRequestScoped({
1793
1849
  if (executeResult.error) return executeResult.error;
1794
1850
  serverOutput = executeResult.serverOutput;
1795
1851
  }
1796
- const fanoutError = await stageFanout(resolvedName, callbackName, serverOutput, syncObject, functionsObject, ctx);
1852
+ const fanoutError = await stageFanout(resolvedName, callbackName, serverOutput, sockets, syncObject, functionsObject, ctx);
1797
1853
  if (fanoutError) return fanoutError;
1798
1854
  if (shouldLogDev()) {
1799
1855
  getLogger4().debug(`http sync: ${resolvedName} completed`);
@@ -1872,6 +1928,7 @@ var createStreamThrottle = (options = {}) => {
1872
1928
  };
1873
1929
  };
1874
1930
  export {
1931
+ SYNC_ERROR_CODES,
1875
1932
  createStreamThrottle,
1876
1933
  handleHttpSyncRequest,
1877
1934
  handleSyncRequest