doover-js 0.6.4 → 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.
Files changed (44) hide show
  1. package/dist/apis/_args.js +9 -4
  2. package/dist/apis/agents-api.d.ts +3 -0
  3. package/dist/apis/agents-api.js +8 -7
  4. package/dist/apis/aggregates-api.d.ts +11 -0
  5. package/dist/apis/channels-api.d.ts +19 -0
  6. package/dist/apis/messages-api.d.ts +6 -0
  7. package/dist/apis/organisations-api.d.ts +26 -0
  8. package/dist/apis/organisations-api.js +45 -0
  9. package/dist/auth/cookie-auth.d.ts +1 -0
  10. package/dist/auth/cookie-auth.js +3 -0
  11. package/dist/auth/doover-auth.d.ts +5 -0
  12. package/dist/auth/doover-token-auth.d.ts +1 -0
  13. package/dist/auth/doover-token-auth.js +5 -0
  14. package/dist/client/doover-client.d.ts +2 -0
  15. package/dist/client/doover-client.js +2 -0
  16. package/dist/client/errors.d.ts +9 -0
  17. package/dist/client/errors.js +21 -1
  18. package/dist/client/offline-cache.d.ts +162 -0
  19. package/dist/client/offline-cache.js +757 -0
  20. package/dist/client/request-options.d.ts +23 -0
  21. package/dist/client/request-options.js +30 -0
  22. package/dist/http/rest-client.js +5 -2
  23. package/dist/index.d.ts +7 -1
  24. package/dist/index.js +12 -1
  25. package/dist/react/index.d.ts +2 -0
  26. package/dist/react/index.js +4 -1
  27. package/dist/react/useChannelAggregate.d.ts +3 -0
  28. package/dist/react/useChannelAggregate.js +3 -0
  29. package/dist/react/useChannelMessages.d.ts +3 -0
  30. package/dist/react/useChannelMessages.js +3 -1
  31. package/dist/react/useOfflineStatus.d.ts +8 -0
  32. package/dist/react/useOfflineStatus.js +27 -0
  33. package/dist/refine/index.d.ts +72 -0
  34. package/dist/refine/index.js +219 -0
  35. package/dist/test/api-overloads.test.js +45 -0
  36. package/dist/test/auth.test.js +19 -0
  37. package/dist/test/exports.test.js +5 -1
  38. package/dist/test/offline-cache.test.d.ts +1 -0
  39. package/dist/test/offline-cache.test.js +289 -0
  40. package/dist/test/react-exports.test.js +1 -0
  41. package/dist/test/refine.test.d.ts +1 -0
  42. package/dist/test/refine.test.js +71 -0
  43. package/dist/types/viewer.d.ts +37 -0
  44. package/package.json +9 -1
@@ -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: {
@@ -0,0 +1,26 @@
1
+ import type { RestClient } from "../http/rest-client";
2
+ import type { CustomerSite, Organisation, PaginatedResponse } from "../types/viewer";
3
+ export interface ListOrganisationsOptions {
4
+ page?: number;
5
+ perPage?: number;
6
+ search?: string;
7
+ archived?: boolean | "";
8
+ ordering?: string;
9
+ name?: string;
10
+ name__contains?: string;
11
+ name__icontains?: string;
12
+ id?: string | number;
13
+ [key: string]: string | number | boolean | "" | undefined;
14
+ }
15
+ export declare class OrganisationsApi {
16
+ private readonly rest;
17
+ private readonly controlApiUrl?;
18
+ constructor(rest: RestClient, controlApiUrl?: string | undefined);
19
+ listOrganisations(options?: ListOrganisationsOptions): Promise<PaginatedResponse<Organisation>>;
20
+ getOrganisation(id: string): Promise<Organisation>;
21
+ /**
22
+ * Convert an organisation record from `/organisations/` into the smaller
23
+ * customer-site bootstrap shape returned by `/site/`.
24
+ */
25
+ toCustomerSite(organisation: Organisation): CustomerSite;
26
+ }
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OrganisationsApi = void 0;
4
+ class OrganisationsApi {
5
+ constructor(rest, controlApiUrl) {
6
+ this.rest = rest;
7
+ this.controlApiUrl = controlApiUrl;
8
+ }
9
+ listOrganisations(options) {
10
+ return this.rest.get("/organisations/", buildListQuery(options), this.controlApiUrl);
11
+ }
12
+ getOrganisation(id) {
13
+ return this.rest.get(`/organisations/${id}/`, undefined, this.controlApiUrl);
14
+ }
15
+ /**
16
+ * Convert an organisation record from `/organisations/` into the smaller
17
+ * customer-site bootstrap shape returned by `/site/`.
18
+ */
19
+ toCustomerSite(organisation) {
20
+ return {
21
+ id: organisation.id,
22
+ name: organisation.name,
23
+ application_id: organisation.application_id,
24
+ archived: organisation.archived,
25
+ theme: organisation.theme ?? {},
26
+ };
27
+ }
28
+ }
29
+ exports.OrganisationsApi = OrganisationsApi;
30
+ function buildListQuery(options) {
31
+ if (!options)
32
+ return undefined;
33
+ const { page, perPage, ...rest } = options;
34
+ const query = {};
35
+ if (page !== undefined)
36
+ query.page = page;
37
+ if (perPage !== undefined)
38
+ query.per_page = perPage;
39
+ for (const [key, value] of Object.entries(rest)) {
40
+ if (value === undefined)
41
+ continue;
42
+ query[key] = value;
43
+ }
44
+ return query;
45
+ }
@@ -13,5 +13,6 @@ export declare class CookieAuth extends DooverAuth {
13
13
  headers?: Record<string, string>;
14
14
  }>;
15
15
  setToken(_token: string | null, _tokenExpires?: Date | number | null): void;
16
+ setRefreshToken(_refreshToken: string | null): void;
16
17
  ensureReady(): Promise<void>;
17
18
  }
@@ -22,6 +22,9 @@ class CookieAuth extends doover_auth_1.DooverAuth {
22
22
  setToken(_token, _tokenExpires) {
23
23
  // No-op for cookie auth.
24
24
  }
25
+ setRefreshToken(_refreshToken) {
26
+ // No-op for cookie auth.
27
+ }
25
28
  async ensureReady() {
26
29
  // Nothing to prepare for cookie auth.
27
30
  }
@@ -31,6 +31,11 @@ export declare abstract class DooverAuth {
31
31
  * Subclasses that do not use tokens may no-op.
32
32
  */
33
33
  abstract setToken(token: string | null, tokenExpires?: Date | number | null): void;
34
+ /**
35
+ * Imperatively set or clear the refresh token. Subclasses that do not use
36
+ * refresh tokens may no-op.
37
+ */
38
+ abstract setRefreshToken(refreshToken: string | null): void;
34
39
  /**
35
40
  * Ensure the auth layer is ready (e.g. token refreshed if needed).
36
41
  * Called before every HTTP request and before opening a websocket.
@@ -26,6 +26,7 @@ export declare class DooverTokenAuth extends DooverAuth {
26
26
  headers?: Record<string, string>;
27
27
  }>;
28
28
  setToken(token: string | null, tokenExpires?: Date | number | null): void;
29
+ setRefreshToken(refreshToken: string | null): void;
29
30
  ensureReady(): Promise<void>;
30
31
  attachProfile(profile: AuthProfile, configManager?: AuthProfileStore): void;
31
32
  private needsRefresh;
@@ -48,6 +48,11 @@ class DooverTokenAuth extends doover_auth_1.DooverAuth {
48
48
  setToken(token, tokenExpires) {
49
49
  this.token = token;
50
50
  this.tokenExpires = this.resolveExpiry(tokenExpires, token);
51
+ this.persistToProfile();
52
+ }
53
+ setRefreshToken(refreshToken) {
54
+ this.refreshToken = refreshToken;
55
+ this.persistToProfile();
51
56
  }
52
57
  async ensureReady() {
53
58
  if (!this.needsRefresh()) {
@@ -1,3 +1,4 @@
1
+ import { OrganisationsApi } from "../apis/organisations-api";
1
2
  import type { DooverAuth } from "../auth/doover-auth";
2
3
  import { RestClient, type DooverClientConfig } from "../http/rest-client";
3
4
  import { DooverDataProvider } from "../viewer/doover-data-provider";
@@ -15,6 +16,7 @@ export declare class DooverClient implements DataClient {
15
16
  readonly alarms: AlarmsApiLike;
16
17
  readonly connections: ConnectionsApiLike;
17
18
  readonly notifications: NotificationsApiLike;
19
+ readonly organisations: OrganisationsApi;
18
20
  readonly permissions: PermissionsApiLike;
19
21
  readonly processors: ProcessorsApiLike;
20
22
  readonly turn: TurnApiLike;
@@ -8,6 +8,7 @@ const channels_api_1 = require("../apis/channels-api");
8
8
  const connections_api_1 = require("../apis/connections-api");
9
9
  const messages_api_1 = require("../apis/messages-api");
10
10
  const notifications_api_1 = require("../apis/notifications-api");
11
+ const organisations_api_1 = require("../apis/organisations-api");
11
12
  const permissions_api_1 = require("../apis/permissions-api");
12
13
  const processors_api_1 = require("../apis/processors-api");
13
14
  const turn_api_1 = require("../apis/turn-api");
@@ -63,6 +64,7 @@ class DooverClient {
63
64
  this.alarms = (0, provenance_1.wrapSubclient)(new alarms_api_1.AlarmsApi(this.rest), "alarms", stamper);
64
65
  this.connections = (0, provenance_1.wrapSubclient)(new connections_api_1.ConnectionsApi(this.rest), "connections", stamper);
65
66
  this.notifications = (0, provenance_1.wrapSubclient)(new notifications_api_1.NotificationsApi(this.rest), "notifications", stamper);
67
+ this.organisations = (0, provenance_1.wrapSubclient)(new organisations_api_1.OrganisationsApi(this.rest, config.controlApiUrl), "organisations", stamper);
66
68
  this.permissions = (0, provenance_1.wrapSubclient)(new permissions_api_1.PermissionsApi(this.rest), "permissions", stamper);
67
69
  this.processors = (0, provenance_1.wrapSubclient)(new processors_api_1.ProcessorsApi(this.rest), "processors", stamper);
68
70
  this.turn = (0, provenance_1.wrapSubclient)(new turn_api_1.TurnApi(this.rest), "turn", stamper);
@@ -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
+ }