doover-js 0.13.2 → 0.14.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.
@@ -20,10 +20,32 @@ export interface ListMessagesParams {
20
20
  * index 0.
21
21
  */
22
22
  order?: "asc" | "desc";
23
+ }
24
+ /**
25
+ * `getTimeseries` options. The endpoint always returns `{ results, count,
26
+ * next }`: while `next` is set there's more, and passing it back as `before`
27
+ * continues newest → oldest.
28
+ */
29
+ export interface TimeseriesParams {
30
+ /** Exclusive upper bound, and the paging cursor (a response's `next`). */
31
+ before?: string;
32
+ /**
33
+ * Lower bound. A missing bound is filled a week from the other, so unlike
34
+ * `listMessages`, `after` on its own doesn't page forward: it reads the
35
+ * newest `limit` points in the week after it.
36
+ */
37
+ after?: string;
38
+ /** Points per page; the server sends 50 without it and allows 1500. */
39
+ limit?: number;
40
+ field_name?: string[];
41
+ /**
42
+ * `"desc"` (default) keeps the server's newest-first order; `"asc"`
43
+ * reverses each page client-side so the oldest point is at index 0.
44
+ */
45
+ order?: "asc" | "desc";
23
46
  /**
24
- * Opt into paginated timeseries responses (`getTimeseries` only). When true
25
- * the server returns a `next` cursor alongside `{ results, count }`; pass it
26
- * back as `before` to page through results.
47
+ * @deprecated No effect, and no longer sent: the endpoint has no such
48
+ * parameter and always returns `next`.
27
49
  */
28
50
  paginate?: boolean;
29
51
  }
@@ -52,11 +74,11 @@ export declare class MessagesApi {
52
74
  channelName: string;
53
75
  }, body: MessageBody): Promise<MessageStructure>;
54
76
  private _postMessage;
55
- getTimeseries(agentId: string, channelName: string, params: ListMessagesParams): Promise<DataSeries>;
77
+ getTimeseries(agentId: string, channelName: string, params: TimeseriesParams): Promise<DataSeries>;
56
78
  getTimeseries(identifier: {
57
79
  agentId: string;
58
80
  channelName: string;
59
- }, params: ListMessagesParams): Promise<DataSeries>;
81
+ }, params: TimeseriesParams): Promise<DataSeries>;
60
82
  private _getTimeseries;
61
83
  getMessage(agentId: string, channelName: string, messageId: string): Promise<MessageStructure>;
62
84
  getMessage(identifier: {
@@ -66,9 +66,19 @@ class MessagesApi {
66
66
  const { agentId, channelName, options } = (0, _args_js_1.resolveChannelArgs)(args);
67
67
  return this._getTimeseries(agentId, channelName, options);
68
68
  }
69
- _getTimeseries(agentId, channelName, params) {
70
- const { order: _order, ...rest } = params;
71
- return this.rest.get(`/agents/${agentId}/channels/${channelName}/messages/timeseries`, rest);
69
+ async _getTimeseries(agentId, channelName, params) {
70
+ const { order, paginate: _paginate, ...query } = params;
71
+ const series = await this.rest.get(`/agents/${agentId}/channels/${channelName}/messages/timeseries`, query);
72
+ // Older servers sent `next` as a JSON number; keep the declared string
73
+ // type (the digits past 2^53 were already rounded in parsing).
74
+ const next = series.next;
75
+ return {
76
+ ...series,
77
+ ...(typeof next === "number" ? { next: String(next) } : {}),
78
+ results: order === "asc" && series.results
79
+ ? [...series.results].reverse()
80
+ : series.results,
81
+ };
72
82
  }
73
83
  async getMessage(...args) {
74
84
  if (typeof args[0] === "string") {
@@ -20,10 +20,32 @@ export interface ListMessagesParams {
20
20
  * index 0.
21
21
  */
22
22
  order?: "asc" | "desc";
23
+ }
24
+ /**
25
+ * `getTimeseries` options. The endpoint always returns `{ results, count,
26
+ * next }`: while `next` is set there's more, and passing it back as `before`
27
+ * continues newest → oldest.
28
+ */
29
+ export interface TimeseriesParams {
30
+ /** Exclusive upper bound, and the paging cursor (a response's `next`). */
31
+ before?: string;
32
+ /**
33
+ * Lower bound. A missing bound is filled a week from the other, so unlike
34
+ * `listMessages`, `after` on its own doesn't page forward: it reads the
35
+ * newest `limit` points in the week after it.
36
+ */
37
+ after?: string;
38
+ /** Points per page; the server sends 50 without it and allows 1500. */
39
+ limit?: number;
40
+ field_name?: string[];
41
+ /**
42
+ * `"desc"` (default) keeps the server's newest-first order; `"asc"`
43
+ * reverses each page client-side so the oldest point is at index 0.
44
+ */
45
+ order?: "asc" | "desc";
23
46
  /**
24
- * Opt into paginated timeseries responses (`getTimeseries` only). When true
25
- * the server returns a `next` cursor alongside `{ results, count }`; pass it
26
- * back as `before` to page through results.
47
+ * @deprecated No effect, and no longer sent: the endpoint has no such
48
+ * parameter and always returns `next`.
27
49
  */
28
50
  paginate?: boolean;
29
51
  }
@@ -52,11 +74,11 @@ export declare class MessagesApi {
52
74
  channelName: string;
53
75
  }, body: MessageBody): Promise<MessageStructure>;
54
76
  private _postMessage;
55
- getTimeseries(agentId: string, channelName: string, params: ListMessagesParams): Promise<DataSeries>;
77
+ getTimeseries(agentId: string, channelName: string, params: TimeseriesParams): Promise<DataSeries>;
56
78
  getTimeseries(identifier: {
57
79
  agentId: string;
58
80
  channelName: string;
59
- }, params: ListMessagesParams): Promise<DataSeries>;
81
+ }, params: TimeseriesParams): Promise<DataSeries>;
60
82
  private _getTimeseries;
61
83
  getMessage(agentId: string, channelName: string, messageId: string): Promise<MessageStructure>;
62
84
  getMessage(identifier: {
@@ -63,9 +63,19 @@ export class MessagesApi {
63
63
  const { agentId, channelName, options } = resolveChannelArgs(args);
64
64
  return this._getTimeseries(agentId, channelName, options);
65
65
  }
66
- _getTimeseries(agentId, channelName, params) {
67
- const { order: _order, ...rest } = params;
68
- return this.rest.get(`/agents/${agentId}/channels/${channelName}/messages/timeseries`, rest);
66
+ async _getTimeseries(agentId, channelName, params) {
67
+ const { order, paginate: _paginate, ...query } = params;
68
+ const series = await this.rest.get(`/agents/${agentId}/channels/${channelName}/messages/timeseries`, query);
69
+ // Older servers sent `next` as a JSON number; keep the declared string
70
+ // type (the digits past 2^53 were already rounded in parsing).
71
+ const next = series.next;
72
+ return {
73
+ ...series,
74
+ ...(typeof next === "number" ? { next: String(next) } : {}),
75
+ results: order === "asc" && series.results
76
+ ? [...series.results].reverse()
77
+ : series.results,
78
+ };
69
79
  }
70
80
  async getMessage(...args) {
71
81
  if (typeof args[0] === "string") {
@@ -1 +1 @@
1
- {"name":"doover-js","version":"0.13.2","type":"module","sideEffects":false}
1
+ {"name":"doover-js","version":"0.14.0","type":"module","sideEffects":false}
@@ -28,7 +28,7 @@ export { useSendRpc } from "./useSendRpc.js";
28
28
  export type { RpcCommandId, RpcStatusEvent, SendRpcVariables, UseSendRpcOptions, UseSendRpcResult, } from "./useSendRpc.js";
29
29
  export { useMultiAgentAggregates, multiAgentAggregatesQueryKey, } from "./useMultiAgentAggregates.js";
30
30
  export type { UseMultiAgentAggregatesOptions, UseMultiAgentAggregatesResult, } from "./useMultiAgentAggregates.js";
31
- export { useMultiAgentChannelMessages, multiAgentChannelMessagesQueryKey, } from "./useMultiAgentChannelMessages.js";
31
+ export { useMultiAgentChannelMessages, multiAgentChannelMessagesQueryKey, MULTI_AGENT_MAX_WINDOW_MS, } from "./useMultiAgentChannelMessages.js";
32
32
  export type { UseMultiAgentChannelMessagesOptions, UseMultiAgentChannelMessagesResult, } from "./useMultiAgentChannelMessages.js";
33
33
  export { useDeviceMap } from "./useDeviceMap.js";
34
34
  export type { DeviceMapEntry, UseDeviceMapOptions, UseDeviceMapResult, } from "./useDeviceMap.js";
@@ -14,7 +14,7 @@ export { useChannelMessage, channelMessageQueryKey, } from "./useChannelMessage.
14
14
  export { useInvocationLogs, invocationLogsQueryKey, } from "./useInvocationLogs.js";
15
15
  export { useSendRpc } from "./useSendRpc.js";
16
16
  export { useMultiAgentAggregates, multiAgentAggregatesQueryKey, } from "./useMultiAgentAggregates.js";
17
- export { useMultiAgentChannelMessages, multiAgentChannelMessagesQueryKey, } from "./useMultiAgentChannelMessages.js";
17
+ export { useMultiAgentChannelMessages, multiAgentChannelMessagesQueryKey, MULTI_AGENT_MAX_WINDOW_MS, } from "./useMultiAgentChannelMessages.js";
18
18
  export { useDeviceMap } from "./useDeviceMap.js";
19
19
  export { useTurnCredentials } from "./useTurnCredentials.js";
20
20
  export { useAgentTokenState, useSetAgentTokenPolicy, useSetAgentAuthLock, useRevokeAgentTokens, useSetRevocationFloor, useCreateAdhocToken, useCreateDeviceToken, agentTokenStateQueryKey, } from "./useAgentTokenState.js";
@@ -1,5 +1,12 @@
1
1
  import { type InfiniteData, type UseInfiniteQueryResult } from "@tanstack/react-query";
2
2
  import type { MessageStructure } from "../types/common.js";
3
+ /**
4
+ * Widest `before - after` span one multi-agent request may cover. The server
5
+ * caps it at 7 days (it walks each agent's history a day at a time); the
6
+ * minute's margin keeps each request clear of the cap. Longer ranges are
7
+ * read as a series of these, newest first.
8
+ */
9
+ export declare const MULTI_AGENT_MAX_WINDOW_MS: number;
3
10
  export declare function multiAgentChannelMessagesQueryKey(channelName: string, agentIds: string[], sources?: string[], scope?: {
4
11
  after?: string;
5
12
  fields?: readonly string[];
@@ -25,7 +32,12 @@ export interface UseMultiAgentChannelMessagesOptions {
25
32
  * of these top-level field names. Forwarded as `field_name`.
26
33
  */
27
34
  fields?: string[];
28
- /** Optional first-page `before` cursor (snowflake id). */
35
+ /**
36
+ * Optional first-page `before` cursor (snowflake id). With `after`, it
37
+ * bounds a time range, which may be wider than the server's 7-day cap:
38
+ * the range is then read a window at a time, each further window arriving
39
+ * as more pages (see `after`).
40
+ */
29
41
  initialBefore?: string;
30
42
  /**
31
43
  * Keep paging older automatically until `hasNextPage` is false. Each page
@@ -48,6 +60,14 @@ export interface UseMultiAgentChannelMessagesOptions {
48
60
  * mirrors `useChannelMessages`'s `after`. Use this to fetch a bounded
49
61
  * time window (e.g. last 24h) across many agents without filtering
50
62
  * on the client.
63
+ *
64
+ * With `initialBefore` more than `MULTI_AGENT_MAX_WINDOW_MS` before it, the
65
+ * range is split into windows the server accepts, read newest first:
66
+ * `fetchNextPage` finishes one window's per-agent cursors, then moves on
67
+ * to the next window, and `hasNextPage` stays true until the whole range
68
+ * is read. A quiet window can come back empty, so fetch on until you have
69
+ * what you need (or set `autoPaginate`, raising `maxPages` for a long
70
+ * range: a year is 53 windows).
51
71
  */
52
72
  after?: string;
53
73
  /**
@@ -1,6 +1,15 @@
1
1
  import { useCallback, useEffect, useMemo } from "react";
2
2
  import { useInfiniteQuery, useQueryClient, } from "@tanstack/react-query";
3
3
  import { useDooverClient } from "./context.js";
4
+ /**
5
+ * Widest `before - after` span one multi-agent request may cover. The server
6
+ * caps it at 7 days (it walks each agent's history a day at a time); the
7
+ * minute's margin keeps each request clear of the cap. Longer ranges are
8
+ * read as a series of these, newest first.
9
+ */
10
+ export const MULTI_AGENT_MAX_WINDOW_MS = 7 * 24 * 60 * 60 * 1000 - 60000;
11
+ /** The window above as a snowflake-id delta (ids carry ms in bits 22+). */
12
+ const MAX_WINDOW_ID_SPAN = BigInt(MULTI_AGENT_MAX_WINDOW_MS) << 22n;
4
13
  export function multiAgentChannelMessagesQueryKey(channelName, agentIds, sources, scope) {
5
14
  const sourceDim = sources && sources.length ? [...sources].sort().join(",") : "*";
6
15
  const base = [
@@ -26,6 +35,31 @@ export function multiAgentChannelMessagesQueryKey(channelName, agentIds, sources
26
35
  ? [...base, scopeKey]
27
36
  : base;
28
37
  }
38
+ /** The window ending at `before`, reaching back no further than `after`. */
39
+ function windowEndingAt(before, after) {
40
+ const start = BigInt(before) - MAX_WINDOW_ID_SPAN;
41
+ const floor = BigInt(after);
42
+ return {
43
+ windowBefore: before,
44
+ windowAfter: (start > floor ? start : floor).toString(),
45
+ };
46
+ }
47
+ /**
48
+ * Within a windowed range: carry on inside the current window, or once it's
49
+ * drained, step back to the window before it until the range's `after`.
50
+ */
51
+ function nextWindowedPageParam(lastPage, lastParam, after) {
52
+ const { windowBefore, windowAfter } = lastParam;
53
+ if (windowBefore === undefined || windowAfter === undefined) {
54
+ return nextPageParam(lastPage);
55
+ }
56
+ const within = nextPageParam(lastPage);
57
+ if (within)
58
+ return { ...within, windowBefore, windowAfter };
59
+ if (BigInt(windowAfter) <= BigInt(after))
60
+ return undefined;
61
+ return windowEndingAt(windowAfter, after);
62
+ }
29
63
  function nextPageParam(lastPage) {
30
64
  if (!lastPage)
31
65
  return undefined;
@@ -107,23 +141,36 @@ export function useMultiAgentChannelMessages(channelName, agentIds, options) {
107
141
  };
108
142
  // eslint-disable-next-line react-hooks/exhaustive-deps
109
143
  }, [client, channelName, liveUpdates, agentIds.join(",")]);
144
+ // A range wider than the server accepts in one request is read a window
145
+ // at a time; narrower ones (and open-ended reads) are one window as ever.
146
+ const windowed = after !== undefined &&
147
+ initialBefore !== undefined &&
148
+ BigInt(initialBefore) - BigInt(after) > MAX_WINDOW_ID_SPAN;
110
149
  const query = useInfiniteQuery({
111
150
  queryKey: key,
112
151
  enabled: agentIds.length > 0,
113
152
  staleTime: Infinity,
114
- initialPageParam: (initialBefore ? { before: initialBefore } : {}),
115
- getNextPageParam: nextPageParam,
153
+ initialPageParam: (windowed
154
+ ? windowEndingAt(initialBefore, after)
155
+ : initialBefore
156
+ ? { before: initialBefore }
157
+ : {}),
158
+ getNextPageParam: (lastPage, _allPages, lastParam) => windowed
159
+ ? nextWindowedPageParam(lastPage, lastParam, after)
160
+ : nextPageParam(lastPage),
116
161
  queryFn: async ({ pageParam }) => {
162
+ const before = pageParam.before ?? pageParam.windowBefore;
163
+ const lowerBound = pageParam.windowAfter ?? after;
117
164
  const params = {
118
165
  agent_id: pageParam.agentIds ?? agentIds,
119
- ...(pageParam.before ? { before: pageParam.before } : {}),
166
+ ...(before ? { before } : {}),
120
167
  ...(pageParam.agentBefore ? { agent_before: pageParam.agentBefore } : {}),
121
168
  ...(limit !== undefined ? { limit } : {}),
122
169
  ...(agentMessageLimit !== undefined
123
170
  ? { agent_message_limit: agentMessageLimit }
124
171
  : {}),
125
172
  ...(fields && fields.length > 0 ? { field_name: fields } : {}),
126
- ...(after !== undefined ? { after } : {}),
173
+ ...(lowerBound !== undefined ? { after: lowerBound } : {}),
127
174
  };
128
175
  // Pass `{ sources }` as a trailing bag only when set — cast through
129
176
  // `never` since the TypeScript overloads don't declare it.
@@ -28,7 +28,7 @@ export { useSendRpc } from "./useSendRpc.js";
28
28
  export type { RpcCommandId, RpcStatusEvent, SendRpcVariables, UseSendRpcOptions, UseSendRpcResult, } from "./useSendRpc.js";
29
29
  export { useMultiAgentAggregates, multiAgentAggregatesQueryKey, } from "./useMultiAgentAggregates.js";
30
30
  export type { UseMultiAgentAggregatesOptions, UseMultiAgentAggregatesResult, } from "./useMultiAgentAggregates.js";
31
- export { useMultiAgentChannelMessages, multiAgentChannelMessagesQueryKey, } from "./useMultiAgentChannelMessages.js";
31
+ export { useMultiAgentChannelMessages, multiAgentChannelMessagesQueryKey, MULTI_AGENT_MAX_WINDOW_MS, } from "./useMultiAgentChannelMessages.js";
32
32
  export type { UseMultiAgentChannelMessagesOptions, UseMultiAgentChannelMessagesResult, } from "./useMultiAgentChannelMessages.js";
33
33
  export { useDeviceMap } from "./useDeviceMap.js";
34
34
  export type { DeviceMapEntry, UseDeviceMapOptions, UseDeviceMapResult, } from "./useDeviceMap.js";
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useServiceReachability = exports.resetSharedQueryClient = exports.getSharedQueryClient = exports.agentTokenStateQueryKey = exports.useCreateDeviceToken = exports.useCreateAdhocToken = exports.useSetRevocationFloor = exports.useRevokeAgentTokens = exports.useSetAgentAuthLock = exports.useSetAgentTokenPolicy = exports.useAgentTokenState = exports.useTurnCredentials = exports.useDeviceMap = exports.multiAgentChannelMessagesQueryKey = exports.useMultiAgentChannelMessages = exports.multiAgentAggregatesQueryKey = exports.useMultiAgentAggregates = exports.useSendRpc = exports.invocationLogsQueryKey = exports.useInvocationLogs = exports.channelMessageQueryKey = exports.useChannelMessage = exports.channelMessagesQueryKey = exports.useChannelMessages = exports.useUpdateMessage = exports.useUpdateAggregate = exports.useSendMessage = exports.useAgentChannel = exports.channelAggregateQueryKey = exports.useChannelAggregate = exports.useChannelSubscription = exports.agentConnectionsQueryKey = exports.useAgentConnections = exports.useConnectionState = exports.hasOfflineStatus = exports.useOfflineStatus = exports.useClientStatus = exports.useDooverClient = exports.DooverProvider = void 0;
3
+ exports.useServiceReachability = exports.resetSharedQueryClient = exports.getSharedQueryClient = exports.agentTokenStateQueryKey = exports.useCreateDeviceToken = exports.useCreateAdhocToken = exports.useSetRevocationFloor = exports.useRevokeAgentTokens = exports.useSetAgentAuthLock = exports.useSetAgentTokenPolicy = exports.useAgentTokenState = exports.useTurnCredentials = exports.useDeviceMap = exports.MULTI_AGENT_MAX_WINDOW_MS = exports.multiAgentChannelMessagesQueryKey = exports.useMultiAgentChannelMessages = exports.multiAgentAggregatesQueryKey = exports.useMultiAgentAggregates = exports.useSendRpc = exports.invocationLogsQueryKey = exports.useInvocationLogs = exports.channelMessageQueryKey = exports.useChannelMessage = exports.channelMessagesQueryKey = exports.useChannelMessages = exports.useUpdateMessage = exports.useUpdateAggregate = exports.useSendMessage = exports.useAgentChannel = exports.channelAggregateQueryKey = exports.useChannelAggregate = exports.useChannelSubscription = exports.agentConnectionsQueryKey = exports.useAgentConnections = exports.useConnectionState = exports.hasOfflineStatus = exports.useOfflineStatus = exports.useClientStatus = exports.useDooverClient = exports.DooverProvider = void 0;
4
4
  var context_js_1 = require("./context.js");
5
5
  Object.defineProperty(exports, "DooverProvider", { enumerable: true, get: function () { return context_js_1.DooverProvider; } });
6
6
  Object.defineProperty(exports, "useDooverClient", { enumerable: true, get: function () { return context_js_1.useDooverClient; } });
@@ -44,6 +44,7 @@ Object.defineProperty(exports, "multiAgentAggregatesQueryKey", { enumerable: tru
44
44
  var useMultiAgentChannelMessages_js_1 = require("./useMultiAgentChannelMessages.js");
45
45
  Object.defineProperty(exports, "useMultiAgentChannelMessages", { enumerable: true, get: function () { return useMultiAgentChannelMessages_js_1.useMultiAgentChannelMessages; } });
46
46
  Object.defineProperty(exports, "multiAgentChannelMessagesQueryKey", { enumerable: true, get: function () { return useMultiAgentChannelMessages_js_1.multiAgentChannelMessagesQueryKey; } });
47
+ Object.defineProperty(exports, "MULTI_AGENT_MAX_WINDOW_MS", { enumerable: true, get: function () { return useMultiAgentChannelMessages_js_1.MULTI_AGENT_MAX_WINDOW_MS; } });
47
48
  var useDeviceMap_js_1 = require("./useDeviceMap.js");
48
49
  Object.defineProperty(exports, "useDeviceMap", { enumerable: true, get: function () { return useDeviceMap_js_1.useDeviceMap; } });
49
50
  var useTurnCredentials_js_1 = require("./useTurnCredentials.js");
@@ -1,5 +1,12 @@
1
1
  import { type InfiniteData, type UseInfiniteQueryResult } from "@tanstack/react-query";
2
2
  import type { MessageStructure } from "../types/common.js";
3
+ /**
4
+ * Widest `before - after` span one multi-agent request may cover. The server
5
+ * caps it at 7 days (it walks each agent's history a day at a time); the
6
+ * minute's margin keeps each request clear of the cap. Longer ranges are
7
+ * read as a series of these, newest first.
8
+ */
9
+ export declare const MULTI_AGENT_MAX_WINDOW_MS: number;
3
10
  export declare function multiAgentChannelMessagesQueryKey(channelName: string, agentIds: string[], sources?: string[], scope?: {
4
11
  after?: string;
5
12
  fields?: readonly string[];
@@ -25,7 +32,12 @@ export interface UseMultiAgentChannelMessagesOptions {
25
32
  * of these top-level field names. Forwarded as `field_name`.
26
33
  */
27
34
  fields?: string[];
28
- /** Optional first-page `before` cursor (snowflake id). */
35
+ /**
36
+ * Optional first-page `before` cursor (snowflake id). With `after`, it
37
+ * bounds a time range, which may be wider than the server's 7-day cap:
38
+ * the range is then read a window at a time, each further window arriving
39
+ * as more pages (see `after`).
40
+ */
29
41
  initialBefore?: string;
30
42
  /**
31
43
  * Keep paging older automatically until `hasNextPage` is false. Each page
@@ -48,6 +60,14 @@ export interface UseMultiAgentChannelMessagesOptions {
48
60
  * mirrors `useChannelMessages`'s `after`. Use this to fetch a bounded
49
61
  * time window (e.g. last 24h) across many agents without filtering
50
62
  * on the client.
63
+ *
64
+ * With `initialBefore` more than `MULTI_AGENT_MAX_WINDOW_MS` before it, the
65
+ * range is split into windows the server accepts, read newest first:
66
+ * `fetchNextPage` finishes one window's per-agent cursors, then moves on
67
+ * to the next window, and `hasNextPage` stays true until the whole range
68
+ * is read. A quiet window can come back empty, so fetch on until you have
69
+ * what you need (or set `autoPaginate`, raising `maxPages` for a long
70
+ * range: a year is 53 windows).
51
71
  */
52
72
  after?: string;
53
73
  /**
@@ -1,10 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MULTI_AGENT_MAX_WINDOW_MS = void 0;
3
4
  exports.multiAgentChannelMessagesQueryKey = multiAgentChannelMessagesQueryKey;
4
5
  exports.useMultiAgentChannelMessages = useMultiAgentChannelMessages;
5
6
  const react_1 = require("react");
6
7
  const react_query_1 = require("@tanstack/react-query");
7
8
  const context_js_1 = require("./context.js");
9
+ /**
10
+ * Widest `before - after` span one multi-agent request may cover. The server
11
+ * caps it at 7 days (it walks each agent's history a day at a time); the
12
+ * minute's margin keeps each request clear of the cap. Longer ranges are
13
+ * read as a series of these, newest first.
14
+ */
15
+ exports.MULTI_AGENT_MAX_WINDOW_MS = 7 * 24 * 60 * 60 * 1000 - 60000;
16
+ /** The window above as a snowflake-id delta (ids carry ms in bits 22+). */
17
+ const MAX_WINDOW_ID_SPAN = BigInt(exports.MULTI_AGENT_MAX_WINDOW_MS) << 22n;
8
18
  function multiAgentChannelMessagesQueryKey(channelName, agentIds, sources, scope) {
9
19
  const sourceDim = sources && sources.length ? [...sources].sort().join(",") : "*";
10
20
  const base = [
@@ -30,6 +40,31 @@ function multiAgentChannelMessagesQueryKey(channelName, agentIds, sources, scope
30
40
  ? [...base, scopeKey]
31
41
  : base;
32
42
  }
43
+ /** The window ending at `before`, reaching back no further than `after`. */
44
+ function windowEndingAt(before, after) {
45
+ const start = BigInt(before) - MAX_WINDOW_ID_SPAN;
46
+ const floor = BigInt(after);
47
+ return {
48
+ windowBefore: before,
49
+ windowAfter: (start > floor ? start : floor).toString(),
50
+ };
51
+ }
52
+ /**
53
+ * Within a windowed range: carry on inside the current window, or once it's
54
+ * drained, step back to the window before it until the range's `after`.
55
+ */
56
+ function nextWindowedPageParam(lastPage, lastParam, after) {
57
+ const { windowBefore, windowAfter } = lastParam;
58
+ if (windowBefore === undefined || windowAfter === undefined) {
59
+ return nextPageParam(lastPage);
60
+ }
61
+ const within = nextPageParam(lastPage);
62
+ if (within)
63
+ return { ...within, windowBefore, windowAfter };
64
+ if (BigInt(windowAfter) <= BigInt(after))
65
+ return undefined;
66
+ return windowEndingAt(windowAfter, after);
67
+ }
33
68
  function nextPageParam(lastPage) {
34
69
  if (!lastPage)
35
70
  return undefined;
@@ -111,23 +146,36 @@ function useMultiAgentChannelMessages(channelName, agentIds, options) {
111
146
  };
112
147
  // eslint-disable-next-line react-hooks/exhaustive-deps
113
148
  }, [client, channelName, liveUpdates, agentIds.join(",")]);
149
+ // A range wider than the server accepts in one request is read a window
150
+ // at a time; narrower ones (and open-ended reads) are one window as ever.
151
+ const windowed = after !== undefined &&
152
+ initialBefore !== undefined &&
153
+ BigInt(initialBefore) - BigInt(after) > MAX_WINDOW_ID_SPAN;
114
154
  const query = (0, react_query_1.useInfiniteQuery)({
115
155
  queryKey: key,
116
156
  enabled: agentIds.length > 0,
117
157
  staleTime: Infinity,
118
- initialPageParam: (initialBefore ? { before: initialBefore } : {}),
119
- getNextPageParam: nextPageParam,
158
+ initialPageParam: (windowed
159
+ ? windowEndingAt(initialBefore, after)
160
+ : initialBefore
161
+ ? { before: initialBefore }
162
+ : {}),
163
+ getNextPageParam: (lastPage, _allPages, lastParam) => windowed
164
+ ? nextWindowedPageParam(lastPage, lastParam, after)
165
+ : nextPageParam(lastPage),
120
166
  queryFn: async ({ pageParam }) => {
167
+ const before = pageParam.before ?? pageParam.windowBefore;
168
+ const lowerBound = pageParam.windowAfter ?? after;
121
169
  const params = {
122
170
  agent_id: pageParam.agentIds ?? agentIds,
123
- ...(pageParam.before ? { before: pageParam.before } : {}),
171
+ ...(before ? { before } : {}),
124
172
  ...(pageParam.agentBefore ? { agent_before: pageParam.agentBefore } : {}),
125
173
  ...(limit !== undefined ? { limit } : {}),
126
174
  ...(agentMessageLimit !== undefined
127
175
  ? { agent_message_limit: agentMessageLimit }
128
176
  : {}),
129
177
  ...(fields && fields.length > 0 ? { field_name: fields } : {}),
130
- ...(after !== undefined ? { after } : {}),
178
+ ...(lowerBound !== undefined ? { after: lowerBound } : {}),
131
179
  };
132
180
  // Pass `{ sources }` as a trailing bag only when set — cast through
133
181
  // `never` since the TypeScript overloads don't declare it.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doover-js",
3
- "version": "0.13.2",
3
+ "version": "0.14.0",
4
4
  "description": "TypeScript client for Doover.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",