doover-js 0.6.5 → 0.6.6

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.
@@ -2,25 +2,30 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.resolveChannelArgs = resolveChannelArgs;
4
4
  exports.resolveAgentArgs = resolveAgentArgs;
5
+ const request_options_1 = require("../client/request-options");
5
6
  function resolveChannelArgs(args) {
6
7
  if (typeof args[0] === "string") {
8
+ const options = (0, request_options_1.isDooverRequestOptions)(args[2]) ? undefined : args[2];
7
9
  return {
8
10
  agentId: args[0],
9
11
  channelName: args[1],
10
- options: args[2],
12
+ options: options,
11
13
  };
12
14
  }
13
15
  const id = args[0];
16
+ const options = (0, request_options_1.isDooverRequestOptions)(args[1]) ? undefined : args[1];
14
17
  return {
15
18
  agentId: id.agentId,
16
19
  channelName: id.channelName,
17
- options: args[1],
20
+ options: options,
18
21
  };
19
22
  }
20
23
  function resolveAgentArgs(args) {
21
24
  if (typeof args[0] === "string") {
22
- return { agentId: args[0], options: args[1] };
25
+ const options = (0, request_options_1.isDooverRequestOptions)(args[1]) ? undefined : args[1];
26
+ return { agentId: args[0], options: options };
23
27
  }
24
28
  const id = args[0];
25
- return { agentId: id.agentId, options: args[1] };
29
+ const options = (0, request_options_1.isDooverRequestOptions)(args[1]) ? undefined : args[1];
30
+ return { agentId: id.agentId, options: options };
26
31
  }
@@ -1,6 +1,7 @@
1
1
  import type { AgentAggregate, BatchMessagesResponse } from "../types/openapi";
2
2
  import type { AgentsResponse, GetAgentsOptions } from "../types/viewer";
3
3
  import type { RestClient } from "../http/rest-client";
4
+ import type { DooverRequestOptions } from "../client/request-options";
4
5
  export interface MultiAgentMessagesParams {
5
6
  agent_id: string[];
6
7
  /**
@@ -32,6 +33,8 @@ export declare class AgentsApi {
32
33
  private readonly controlApiUrl?;
33
34
  constructor(rest: RestClient, controlApiUrl?: string | undefined);
34
35
  listAgents(options?: GetAgentsOptions): Promise<AgentsResponse>;
36
+ listAgents(requestOptions?: DooverRequestOptions): Promise<AgentsResponse>;
37
+ listAgents(options?: GetAgentsOptions, requestOptions?: DooverRequestOptions): Promise<AgentsResponse>;
35
38
  /**
36
39
  * Batch-fetch recent messages for many agents. Auto-chunks `agent_id`
37
40
  * (and the parallel `agent_before` cursors, if given) at MULTI_AGENT_CHUNK_SIZE
@@ -110,13 +110,14 @@ class AgentsApi {
110
110
  this.rest = rest;
111
111
  this.controlApiUrl = controlApiUrl;
112
112
  }
113
- async listAgents(options) {
113
+ async listAgents(options, _requestOptions) {
114
+ const agentOptions = options;
114
115
  const query = {};
115
- if (options?.includeArchived)
116
+ if (agentOptions?.includeArchived)
116
117
  query["include-archived"] = true;
117
- if (options?.includeOrganisations)
118
+ if (agentOptions?.includeOrganisations)
118
119
  query["include-organisations"] = true;
119
- if (options?.includeUsers)
120
+ if (agentOptions?.includeUsers)
120
121
  query["include-users"] = true;
121
122
  const raw = await this.rest.request({
122
123
  path: "/agents/",
@@ -126,18 +127,18 @@ class AgentsApi {
126
127
  });
127
128
  const rawAgents = Array.isArray(raw.agents) ? raw.agents : [];
128
129
  const normalizedAgents = rawAgents.map(normalizeAgentEntry);
129
- if (!options?.mergeIncludedAsAgents) {
130
+ if (!agentOptions?.mergeIncludedAsAgents) {
130
131
  return { ...raw, agents: normalizedAgents };
131
132
  }
132
133
  const merged = [...normalizedAgents];
133
- if (options.includeOrganisations) {
134
+ if (agentOptions.includeOrganisations) {
134
135
  const rawOrgs = Array.isArray(raw.organisations)
135
136
  ? raw.organisations
136
137
  : [];
137
138
  for (const org of rawOrgs)
138
139
  merged.push(normalizeOrganisationEntry(org));
139
140
  }
140
- if (options.includeUsers) {
141
+ if (agentOptions.includeUsers) {
141
142
  const rawUsers = Array.isArray(raw.users) ? raw.users : [];
142
143
  for (const user of rawUsers)
143
144
  merged.push(normalizeUserEntry(user));
@@ -1,5 +1,6 @@
1
1
  import type { RestClient } from "../http/rest-client";
2
2
  import type { Aggregate } from "../types/openapi";
3
+ import type { DooverRequestOptions } from "../client/request-options";
3
4
  export interface AggregateMutationParams {
4
5
  suppress_response?: boolean;
5
6
  clear_attachments?: boolean;
@@ -9,10 +10,15 @@ export declare class AggregatesApi {
9
10
  private readonly rest;
10
11
  constructor(rest: RestClient);
11
12
  getAggregate(agentId: string, channelName: string): Promise<Aggregate>;
13
+ getAggregate(agentId: string, channelName: string, requestOptions: DooverRequestOptions): Promise<Aggregate>;
12
14
  getAggregate(identifier: {
13
15
  agentId: string;
14
16
  channelName: string;
15
17
  }): Promise<Aggregate>;
18
+ getAggregate(identifier: {
19
+ agentId: string;
20
+ channelName: string;
21
+ }, requestOptions: DooverRequestOptions): Promise<Aggregate>;
16
22
  private _getAggregate;
17
23
  putAggregate(agentId: string, channelName: string, body: Record<string, unknown> | FormData, params?: AggregateMutationParams): Promise<Aggregate>;
18
24
  putAggregate(identifier: {
@@ -27,9 +33,14 @@ export declare class AggregatesApi {
27
33
  }, body: Record<string, unknown> | FormData, params?: AggregateMutationParams): Promise<Aggregate>;
28
34
  private _patchAggregate;
29
35
  getAggregateAttachment(agentId: string, channelName: string, attachmentId: string): Promise<Blob>;
36
+ getAggregateAttachment(agentId: string, channelName: string, attachmentId: string, requestOptions: DooverRequestOptions): Promise<Blob>;
30
37
  getAggregateAttachment(identifier: {
31
38
  agentId: string;
32
39
  channelName: string;
33
40
  }, attachmentId: string): Promise<Blob>;
41
+ getAggregateAttachment(identifier: {
42
+ agentId: string;
43
+ channelName: string;
44
+ }, attachmentId: string, requestOptions: DooverRequestOptions): Promise<Blob>;
34
45
  private _getAggregateAttachment;
35
46
  }
@@ -1,5 +1,6 @@
1
1
  import type { RestClient } from "../http/rest-client";
2
2
  import type { Channel, CreateChannelRequest, DataSeries, PutChannelRequest } from "../types/openapi";
3
+ import type { DooverRequestOptions } from "../client/request-options";
3
4
  export interface ListChannelsOptions {
4
5
  include_aggregate?: boolean;
5
6
  include_daily_summaries?: boolean;
@@ -18,15 +19,33 @@ export declare class ChannelsApi {
18
19
  private readonly rest;
19
20
  constructor(rest: RestClient);
20
21
  listChannels(agentId: string, options?: ListChannelsOptions): Promise<Channel[]>;
22
+ listChannels(agentId: string, requestOptions: DooverRequestOptions): Promise<Channel[]>;
23
+ listChannels(agentId: string, options: ListChannelsOptions, requestOptions: DooverRequestOptions): Promise<Channel[]>;
21
24
  listChannels(identifier: {
22
25
  agentId: string;
23
26
  }, options?: ListChannelsOptions): Promise<Channel[]>;
27
+ listChannels(identifier: {
28
+ agentId: string;
29
+ }, requestOptions: DooverRequestOptions): Promise<Channel[]>;
30
+ listChannels(identifier: {
31
+ agentId: string;
32
+ }, options: ListChannelsOptions, requestOptions: DooverRequestOptions): Promise<Channel[]>;
24
33
  private _listChannels;
25
34
  getChannel(agentId: string, channelName: string, options?: GetChannelOptions): Promise<Channel>;
35
+ getChannel(agentId: string, channelName: string, requestOptions: DooverRequestOptions): Promise<Channel>;
36
+ getChannel(agentId: string, channelName: string, options: GetChannelOptions, requestOptions: DooverRequestOptions): Promise<Channel>;
26
37
  getChannel(identifier: {
27
38
  agentId: string;
28
39
  channelName: string;
29
40
  }, options?: GetChannelOptions): Promise<Channel>;
41
+ getChannel(identifier: {
42
+ agentId: string;
43
+ channelName: string;
44
+ }, requestOptions: DooverRequestOptions): Promise<Channel>;
45
+ getChannel(identifier: {
46
+ agentId: string;
47
+ channelName: string;
48
+ }, options: GetChannelOptions, requestOptions: DooverRequestOptions): Promise<Channel>;
30
49
  private _getChannel;
31
50
  createChannel(agentId: string, channelName: string, body: CreateChannelRequest): Promise<{
32
51
  id: string;
@@ -1,5 +1,6 @@
1
1
  import type { RestClient } from "../http/rest-client";
2
2
  import type { CreateMessageRequest, DataSeries, MessageStructure, UpdateMessageRequest } from "../types/openapi";
3
+ import type { DooverRequestOptions } from "../client/request-options";
3
4
  export interface ListMessagesParams {
4
5
  before?: string;
5
6
  after?: string;
@@ -27,10 +28,15 @@ export declare class MessagesApi {
27
28
  private readonly rest;
28
29
  constructor(rest: RestClient);
29
30
  listMessages(agentId: string, channelName: string, params?: ListMessagesParams): Promise<MessageStructure[]>;
31
+ listMessages(agentId: string, channelName: string, params: ListMessagesParams, requestOptions: DooverRequestOptions): Promise<MessageStructure[]>;
30
32
  listMessages(identifier: {
31
33
  agentId: string;
32
34
  channelName: string;
33
35
  }, params?: ListMessagesParams): Promise<MessageStructure[]>;
36
+ listMessages(identifier: {
37
+ agentId: string;
38
+ channelName: string;
39
+ }, params: ListMessagesParams, requestOptions: DooverRequestOptions): Promise<MessageStructure[]>;
34
40
  private _listMessages;
35
41
  postMessage(agentId: string, channelName: string, body: MessageBody): Promise<MessageStructure>;
36
42
  postMessage(identifier: {
@@ -21,3 +21,12 @@ export declare class AmbiguousWriteError extends DooverApiError {
21
21
  readonly candidateSourceIds: string[];
22
22
  constructor(capability: Capability, candidateSourceIds: string[]);
23
23
  }
24
+ /**
25
+ * Thrown by offline-aware clients when a network-only operation is attempted
26
+ * while offline, or when an offline read has no usable cached value.
27
+ */
28
+ export declare class DooverOfflineError extends DooverApiError {
29
+ readonly operation: string;
30
+ readonly cacheKey?: string;
31
+ constructor(operation: string, message?: string, cacheKey?: string);
32
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AmbiguousWriteError = exports.UnsupportedCapabilityError = void 0;
3
+ exports.DooverOfflineError = exports.AmbiguousWriteError = exports.UnsupportedCapabilityError = void 0;
4
4
  const errors_1 = require("../http/errors");
5
5
  /**
6
6
  * Thrown when a `DataClient` method is called whose backing capability the
@@ -48,3 +48,23 @@ class AmbiguousWriteError extends errors_1.DooverApiError {
48
48
  }
49
49
  }
50
50
  exports.AmbiguousWriteError = AmbiguousWriteError;
51
+ /**
52
+ * Thrown by offline-aware clients when a network-only operation is attempted
53
+ * while offline, or when an offline read has no usable cached value.
54
+ */
55
+ class DooverOfflineError extends errors_1.DooverApiError {
56
+ constructor(operation, message, cacheKey) {
57
+ super({
58
+ status: 0,
59
+ body: { operation, cacheKey },
60
+ url: "",
61
+ method: "",
62
+ message: message ?? `Operation "${operation}" is unavailable while offline.`,
63
+ });
64
+ this.name = "DooverOfflineError";
65
+ this.operation = operation;
66
+ this.cacheKey = cacheKey;
67
+ Object.setPrototypeOf(this, DooverOfflineError.prototype);
68
+ }
69
+ }
70
+ exports.DooverOfflineError = DooverOfflineError;
@@ -0,0 +1,162 @@
1
+ import type { AgentScope, AgentsApiLike, AggregatesApiLike, AlarmsApiLike, ChannelsApiLike, ConnectionsApiLike, DataClient, DataClientStatus, GatewayClientLike, MessagesApiLike, NotificationsApiLike, PermissionsApiLike, ProcessorsApiLike, RpcDispatcherLike, TurnApiLike, UsersApiLike } from "./data-client";
2
+ import type { Capability } from "./capabilities";
3
+ export declare const DEFAULT_OFFLINE_RETENTION_MS: number;
4
+ export type OfflineCacheMode = "read-through" | "network-first" | "cache-first" | "cache-only";
5
+ export interface OfflineReadCacheOptions {
6
+ enabled?: boolean;
7
+ mode?: OfflineCacheMode;
8
+ policy?: string;
9
+ retentionMs?: number;
10
+ allowExpired?: boolean;
11
+ }
12
+ export interface OfflineChannelPolicy {
13
+ id?: string;
14
+ channel: {
15
+ agentId?: string;
16
+ channelName: string;
17
+ };
18
+ cache?: boolean;
19
+ retentionMs?: number;
20
+ messages?: {
21
+ mode?: "latest";
22
+ count?: number;
23
+ };
24
+ messageAttachments?: {
25
+ include?: "none" | "metadata-only" | "metadata-and-selected-blobs";
26
+ };
27
+ aggregateAttachments?: {
28
+ include?: "none" | "metadata-only" | "metadata-and-selected-blobs";
29
+ };
30
+ }
31
+ export interface OfflineCacheScope {
32
+ userId: string;
33
+ organisationId?: string | null;
34
+ sourceId?: string;
35
+ sharing?: string;
36
+ assumeUserId?: string | null;
37
+ }
38
+ export interface OfflineCacheRecord<T = unknown> {
39
+ key: string;
40
+ scope: OfflineCacheScope;
41
+ kind: string;
42
+ value: T;
43
+ cachedAt: number;
44
+ lastAccessedAt: number;
45
+ expiresAt: number | null;
46
+ serverUpdatedAt?: number | null;
47
+ schemaVersion: number;
48
+ policyId?: string;
49
+ }
50
+ export type OfflineReadState = "online" | "cache-fallback" | "cache-hit" | "cache-miss" | "expired";
51
+ export interface OfflineStatusSnapshot {
52
+ online: boolean;
53
+ state: OfflineReadState;
54
+ operation?: string;
55
+ cacheKey?: string;
56
+ cachedAt?: number;
57
+ expiresAt?: number | null;
58
+ serverUpdatedAt?: number | null;
59
+ isOfflineFallback: boolean;
60
+ isExpired: boolean;
61
+ at: number;
62
+ }
63
+ export interface OfflineStorageAdapter {
64
+ getJson<T>(key: string): Promise<OfflineCacheRecord<T> | undefined>;
65
+ setJson<T>(key: string, record: OfflineCacheRecord<T>): Promise<void>;
66
+ deleteJson?(key: string): Promise<void>;
67
+ listJsonKeys?(prefix?: string): Promise<string[]>;
68
+ clearScope?(scope: OfflineCacheScope): Promise<void>;
69
+ getBlob?(key: string): Promise<Blob | undefined>;
70
+ setBlob?(key: string, blob: Blob, metadata: OfflineCacheRecord): Promise<void>;
71
+ deleteBlob?(key: string): Promise<void>;
72
+ }
73
+ export declare class MemoryOfflineStorageAdapter implements OfflineStorageAdapter {
74
+ private readonly json;
75
+ private readonly blobs;
76
+ getJson<T>(key: string): Promise<OfflineCacheRecord<T> | undefined>;
77
+ setJson<T>(key: string, record: OfflineCacheRecord<T>): Promise<void>;
78
+ deleteJson(key: string): Promise<void>;
79
+ listJsonKeys(prefix?: string): Promise<string[]>;
80
+ clearScope(scope: OfflineCacheScope): Promise<void>;
81
+ getBlob(key: string): Promise<Blob | undefined>;
82
+ setBlob(key: string, blob: Blob, metadata: OfflineCacheRecord): Promise<void>;
83
+ deleteBlob(key: string): Promise<void>;
84
+ }
85
+ export interface OfflineDataClientOptions {
86
+ client: DataClient;
87
+ storage: OfflineStorageAdapter;
88
+ scope: OfflineCacheScope;
89
+ policies?: OfflineChannelPolicy[];
90
+ defaultRetentionMs?: number;
91
+ /**
92
+ * Apps may provide their own reachability signal. When omitted, the wrapper
93
+ * uses `navigator.onLine` when present and otherwise assumes online.
94
+ */
95
+ isOnline?: () => boolean;
96
+ }
97
+ export declare class OfflineDataClient implements DataClient {
98
+ readonly agents: AgentsApiLike;
99
+ readonly channels: ChannelsApiLike;
100
+ readonly messages: MessagesApiLike;
101
+ readonly aggregates: AggregatesApiLike;
102
+ readonly alarms: AlarmsApiLike;
103
+ readonly connections: ConnectionsApiLike;
104
+ readonly notifications: NotificationsApiLike;
105
+ readonly permissions: PermissionsApiLike;
106
+ readonly processors: ProcessorsApiLike;
107
+ readonly turn: TurnApiLike;
108
+ readonly users: UsersApiLike;
109
+ readonly gateway: GatewayClientLike;
110
+ readonly rpc: RpcDispatcherLike;
111
+ private readonly client;
112
+ private readonly storage;
113
+ private readonly scope;
114
+ private readonly defaultRetentionMs;
115
+ private readonly isOnlineFn?;
116
+ private readonly offlineStatusListeners;
117
+ private policies;
118
+ private offlineStatus;
119
+ private persistQueue;
120
+ constructor(options: OfflineDataClientOptions);
121
+ setChannelPolicy(policy: OfflineChannelPolicy): void;
122
+ setChannelPolicies(policies: OfflineChannelPolicy[]): void;
123
+ getChannelPolicies(): readonly OfflineChannelPolicy[];
124
+ getOfflineStatus(): OfflineStatusSnapshot;
125
+ onOfflineStatusChange(listener: (status: OfflineStatusSnapshot) => void): () => void;
126
+ clearScope(scope?: OfflineCacheScope): Promise<void>;
127
+ getCapabilities(): ReadonlySet<Capability>;
128
+ supports(cap: Capability): boolean;
129
+ isConnected(): boolean;
130
+ getStatus(): DataClientStatus;
131
+ onStatusChange(listener: (status: DataClientStatus) => void): () => void;
132
+ getAgentScope(): Promise<AgentScope>;
133
+ getKnownAgentScope(): AgentScope | "unknown";
134
+ private makeAgentsFacade;
135
+ private makeChannelsFacade;
136
+ private makeAggregatesFacade;
137
+ private makeMessagesFacade;
138
+ private makeGatewayFacade;
139
+ private makeRpcFacade;
140
+ private passThroughSubclient;
141
+ private offlineGuard;
142
+ private readCached;
143
+ private readBlobCached;
144
+ private readRecord;
145
+ private tryReadRecord;
146
+ private writeRecord;
147
+ private writePolicyDerivedRecords;
148
+ private writeLatestMessagesRecord;
149
+ private mergeLatestMessage;
150
+ private persistGatewayMessage;
151
+ private persistGatewayAggregate;
152
+ private effectivePolicy;
153
+ private matchPolicy;
154
+ private shouldCacheAttachmentBlob;
155
+ private withDelegateOptions;
156
+ private cacheKey;
157
+ private latestMessagesKeyParts;
158
+ private scopePrefix;
159
+ private isOnline;
160
+ private setOfflineStatus;
161
+ private enqueuePersist;
162
+ }