chatwoot-router 0.1.0 → 0.3.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.
- package/CHANGELOG.md +74 -1
- package/README.md +178 -208
- package/lib/packages/chatwoot-router/scripts/store-config.js +18 -17
- package/lib/packages/chatwoot-router/scripts/stored-config.js +18 -17
- package/lib/packages/chatwoot-router/src/config.d.ts +4 -9
- package/lib/packages/chatwoot-router/src/coordinator.d.ts +10 -0
- package/lib/packages/chatwoot-router/src/env.d.ts +4 -2
- package/lib/packages/chatwoot-router/src/index.d.ts +1 -0
- package/lib/packages/chatwoot-router/src/index.js +746 -397
- package/lib/packages/chatwoot-router/src/reply.d.ts +5 -0
- package/lib/packages/chatwoot-router/src/router.d.ts +3 -6
- package/lib/packages/chatwoot-router/src/routing.d.ts +0 -4
- package/lib/packages/chatwoot-router/src/turn.d.ts +118 -0
- package/lib/packages/chatwoot-router/src/webhook.d.ts +5 -0
- package/lib/shared/alarm.d.ts +2 -0
- package/lib/shared/budget.d.ts +15 -2
- package/lib/shared/chatwoot/api.d.ts +60 -7
- package/lib/shared/concurrent.d.ts +4 -0
- package/lib/shared/deadline.d.ts +6 -0
- package/lib/shared/rate-limit.d.ts +5 -0
- package/lib/shared/store.d.ts +11 -4
- package/lib/shared/types.d.ts +4 -0
- package/package.json +1 -1
- package/lib/packages/chatwoot-router/src/effects.d.ts +0 -14
- package/lib/shared/attributes.d.ts +0 -6
- package/lib/shared/sweep.d.ts +0 -11
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type ChatwootClient, type ChatwootMessage } from "../../../shared/chatwoot/api.ts";
|
|
2
|
+
/** A Chatwoot creation receipt, not a channel delivery receipt. */
|
|
3
|
+
export declare function confirmedReply(message: ChatwootMessage | undefined, botId: number | undefined): boolean;
|
|
4
|
+
/** Read past turn boundaries, including replies made by the former relay's brand bot. */
|
|
5
|
+
export declare function replyHistory(chatwoot: ChatwootClient, accountId: number, conversationId: number, botId: number | undefined, freshPages?: readonly ChatwootMessage[][]): Promise<"found" | "complete-none" | "unknown">;
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { DurableObject } from "cloudflare:workers";
|
|
2
2
|
import type { Env } from "./env.ts";
|
|
3
|
-
|
|
4
|
-
export declare
|
|
3
|
+
import type { Transition } from "./webhook.ts";
|
|
4
|
+
export declare function conversationName(accountId: number, conversationId: number): string;
|
|
5
5
|
export declare class Router extends DurableObject<Env> {
|
|
6
6
|
private readonly store;
|
|
7
7
|
constructor(context: DurableObjectState, env: Env);
|
|
8
|
-
enqueueConversation(accountId: number, conversationId: number): Promise<void>;
|
|
9
|
-
requestSweep(): Promise<void>;
|
|
8
|
+
enqueueConversation(accountId: number, conversationId: number, transition?: Transition): Promise<void>;
|
|
10
9
|
alarm(): Promise<void>;
|
|
11
|
-
private sweep;
|
|
12
10
|
private enqueue;
|
|
13
|
-
private schedule;
|
|
14
11
|
}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { type ChatwootClient, type Fetch } from "../../../shared/chatwoot/api.ts";
|
|
2
2
|
import type { Settings } from "./config.ts";
|
|
3
|
-
/** Jev's answer when no owner fits; also the reserved route name. */
|
|
4
|
-
export declare const UNCLEAR = "unclear";
|
|
5
3
|
export interface RoutingStore {
|
|
6
4
|
get(key: string): string | undefined;
|
|
7
|
-
list(start: string, end: string): string[];
|
|
8
5
|
set(key: string, value: string): void;
|
|
9
6
|
}
|
|
10
7
|
export interface RoutingContext {
|
|
@@ -16,4 +13,3 @@ export interface RoutingContext {
|
|
|
16
13
|
}
|
|
17
14
|
export declare function routesAccount(settings: Settings, accountId: number): boolean;
|
|
18
15
|
export declare function routeConversation(ctx: RoutingContext, accountId: number, conversationId: number): Promise<"defer" | undefined>;
|
|
19
|
-
export declare function sanitize(text: string, identities: Array<string | null | undefined>): string;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { type ChatwootClient } from "../../../shared/chatwoot/api.ts";
|
|
2
|
+
import type { RoutingStore } from "./routing.ts";
|
|
3
|
+
import type { Transition } from "./webhook.ts";
|
|
4
|
+
export declare function expectActivity(store: RoutingStore, accountId: number, conversationId: number, transition: Transition): void;
|
|
5
|
+
/** Preserve an observed pending departure across retries, without using metadata timestamps. */
|
|
6
|
+
export declare function observeStatus(store: RoutingStore, accountId: number, conversationId: number, status: string): void;
|
|
7
|
+
export declare function requestHandoff(store: RoutingStore, accountId: number, conversationId: number): void;
|
|
8
|
+
/** Counts processing failures for this turn, independently of an old queued job's backoff. */
|
|
9
|
+
export declare function recordFailure(store: RoutingStore, accountId: number, conversationId: number): number;
|
|
10
|
+
export declare function clearFailures(store: RoutingStore, accountId: number, conversationId: number): void;
|
|
11
|
+
export declare function readTurn(chatwoot: ChatwootClient, store: RoutingStore, accountId: number, conversationId: number): Promise<{
|
|
12
|
+
pages: {
|
|
13
|
+
id: number;
|
|
14
|
+
conversation_id?: number | undefined;
|
|
15
|
+
content?: string | null | undefined;
|
|
16
|
+
message_type: number;
|
|
17
|
+
content_type?: string | null | undefined;
|
|
18
|
+
status?: string | null | undefined;
|
|
19
|
+
created_at?: number | null | undefined;
|
|
20
|
+
private?: boolean | null | undefined;
|
|
21
|
+
content_attributes?: {
|
|
22
|
+
email?: {
|
|
23
|
+
subject?: string | null | undefined;
|
|
24
|
+
auto_reply?: boolean | null | undefined;
|
|
25
|
+
text_content?: {
|
|
26
|
+
quoted?: string | null | undefined;
|
|
27
|
+
} | null | undefined;
|
|
28
|
+
html_content?: {
|
|
29
|
+
quoted?: string | null | undefined;
|
|
30
|
+
} | null | undefined;
|
|
31
|
+
} | null | undefined;
|
|
32
|
+
deleted?: boolean | null | undefined;
|
|
33
|
+
external_error?: string | null | undefined;
|
|
34
|
+
activity?: {
|
|
35
|
+
type?: string | null | undefined;
|
|
36
|
+
status?: string | null | undefined;
|
|
37
|
+
} | null | undefined;
|
|
38
|
+
submitted_values?: unknown;
|
|
39
|
+
submitted_email?: unknown;
|
|
40
|
+
items?: unknown;
|
|
41
|
+
} | null | undefined;
|
|
42
|
+
sender?: {
|
|
43
|
+
id?: number | null | undefined;
|
|
44
|
+
name?: string | null | undefined;
|
|
45
|
+
email?: string | null | undefined;
|
|
46
|
+
type?: string | null | undefined;
|
|
47
|
+
thumbnail?: string | null | undefined;
|
|
48
|
+
avatar_url?: string | null | undefined;
|
|
49
|
+
} | null | undefined;
|
|
50
|
+
attachments?: {
|
|
51
|
+
file_type?: string | null | undefined;
|
|
52
|
+
data_url?: string | null | undefined;
|
|
53
|
+
fallback_title?: string | null | undefined;
|
|
54
|
+
coordinates_lat?: number | null | undefined;
|
|
55
|
+
coordinates_long?: number | null | undefined;
|
|
56
|
+
meta?: {
|
|
57
|
+
firstName?: string | null | undefined;
|
|
58
|
+
lastName?: string | null | undefined;
|
|
59
|
+
first_name?: string | null | undefined;
|
|
60
|
+
last_name?: string | null | undefined;
|
|
61
|
+
} | null | undefined;
|
|
62
|
+
}[] | null | undefined;
|
|
63
|
+
}[][];
|
|
64
|
+
messages: {
|
|
65
|
+
id: number;
|
|
66
|
+
conversation_id?: number | undefined;
|
|
67
|
+
content?: string | null | undefined;
|
|
68
|
+
message_type: number;
|
|
69
|
+
content_type?: string | null | undefined;
|
|
70
|
+
status?: string | null | undefined;
|
|
71
|
+
created_at?: number | null | undefined;
|
|
72
|
+
private?: boolean | null | undefined;
|
|
73
|
+
content_attributes?: {
|
|
74
|
+
email?: {
|
|
75
|
+
subject?: string | null | undefined;
|
|
76
|
+
auto_reply?: boolean | null | undefined;
|
|
77
|
+
text_content?: {
|
|
78
|
+
quoted?: string | null | undefined;
|
|
79
|
+
} | null | undefined;
|
|
80
|
+
html_content?: {
|
|
81
|
+
quoted?: string | null | undefined;
|
|
82
|
+
} | null | undefined;
|
|
83
|
+
} | null | undefined;
|
|
84
|
+
deleted?: boolean | null | undefined;
|
|
85
|
+
external_error?: string | null | undefined;
|
|
86
|
+
activity?: {
|
|
87
|
+
type?: string | null | undefined;
|
|
88
|
+
status?: string | null | undefined;
|
|
89
|
+
} | null | undefined;
|
|
90
|
+
submitted_values?: unknown;
|
|
91
|
+
submitted_email?: unknown;
|
|
92
|
+
items?: unknown;
|
|
93
|
+
} | null | undefined;
|
|
94
|
+
sender?: {
|
|
95
|
+
id?: number | null | undefined;
|
|
96
|
+
name?: string | null | undefined;
|
|
97
|
+
email?: string | null | undefined;
|
|
98
|
+
type?: string | null | undefined;
|
|
99
|
+
thumbnail?: string | null | undefined;
|
|
100
|
+
avatar_url?: string | null | undefined;
|
|
101
|
+
} | null | undefined;
|
|
102
|
+
attachments?: {
|
|
103
|
+
file_type?: string | null | undefined;
|
|
104
|
+
data_url?: string | null | undefined;
|
|
105
|
+
fallback_title?: string | null | undefined;
|
|
106
|
+
coordinates_lat?: number | null | undefined;
|
|
107
|
+
coordinates_long?: number | null | undefined;
|
|
108
|
+
meta?: {
|
|
109
|
+
firstName?: string | null | undefined;
|
|
110
|
+
lastName?: string | null | undefined;
|
|
111
|
+
first_name?: string | null | undefined;
|
|
112
|
+
last_name?: string | null | undefined;
|
|
113
|
+
} | null | undefined;
|
|
114
|
+
}[] | null | undefined;
|
|
115
|
+
}[];
|
|
116
|
+
boundary: number;
|
|
117
|
+
handoff: boolean;
|
|
118
|
+
}>;
|
package/lib/shared/budget.d.ts
CHANGED
|
@@ -2,12 +2,25 @@ import type { Fetch } from "./chatwoot/api.ts";
|
|
|
2
2
|
export declare class BudgetExhaustedError extends Error {
|
|
3
3
|
constructor();
|
|
4
4
|
}
|
|
5
|
+
export { JobDeadlineError } from "./deadline.ts";
|
|
6
|
+
export declare const METADATA_TIMEOUT_MS = 1500;
|
|
7
|
+
export declare const TRANSFER_TIMEOUT_MS = 8000;
|
|
8
|
+
export declare const JOB_SLICE_MS = 10000;
|
|
5
9
|
export declare class Budget {
|
|
6
10
|
readonly limit: number;
|
|
7
11
|
private readonly fetchImpl;
|
|
8
|
-
private readonly timeoutMs;
|
|
9
12
|
private used;
|
|
10
|
-
|
|
13
|
+
private slice;
|
|
14
|
+
private sliceEnds;
|
|
15
|
+
constructor(limit: number, fetchImpl?: Fetch);
|
|
11
16
|
get remaining(): number;
|
|
17
|
+
startSlice(ms?: number): void;
|
|
18
|
+
requireTime(ms: number): void;
|
|
19
|
+
checkpoint(): void;
|
|
20
|
+
consume(): void;
|
|
21
|
+
require(requests: number): void;
|
|
22
|
+
controlSignal(ms: number): AbortSignal;
|
|
23
|
+
fetchWith(timeoutMs: number): Fetch;
|
|
12
24
|
readonly fetch: Fetch;
|
|
25
|
+
private request;
|
|
13
26
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import type { RateLimitStore } from "../rate-limit.ts";
|
|
2
3
|
import type { RelayConversation, RelayMessage } from "../types.ts";
|
|
3
4
|
import type { components, operations } from "./schema.ts";
|
|
4
5
|
export type Fetch = (input: Request) => Promise<Response>;
|
|
@@ -6,15 +7,21 @@ export type Fetch = (input: Request) => Promise<Response>;
|
|
|
6
7
|
export declare class ChatwootError extends Error {
|
|
7
8
|
readonly status: number;
|
|
8
9
|
readonly conversationMissing: boolean;
|
|
9
|
-
|
|
10
|
+
readonly retryAfterMs: number | undefined;
|
|
11
|
+
constructor(status: number, operation: string, conversationMissing?: boolean, retryAfterMs?: number);
|
|
10
12
|
}
|
|
11
13
|
/**
|
|
12
14
|
* A conversation as returned by GET conversations/{id} and in the conversation list. The spec's
|
|
13
15
|
* `status` enum omits `snoozed`, which the API does return, so the relay treats it as a string.
|
|
14
16
|
*/
|
|
15
|
-
export type ChatwootConversation = components["schemas"]["conversation_show"]
|
|
17
|
+
export type ChatwootConversation = components["schemas"]["conversation_show"] & {
|
|
18
|
+
meta?: {
|
|
19
|
+
assignee_type?: string | null;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
16
22
|
declare const messageSchema: z.ZodObject<{
|
|
17
23
|
id: z.ZodNumber;
|
|
24
|
+
conversation_id: z.ZodOptional<z.ZodNumber>;
|
|
18
25
|
content: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
19
26
|
message_type: z.ZodNumber;
|
|
20
27
|
content_type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
@@ -34,6 +41,10 @@ declare const messageSchema: z.ZodObject<{
|
|
|
34
41
|
}, z.core.$strip>>>;
|
|
35
42
|
deleted: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
36
43
|
external_error: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
44
|
+
activity: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
45
|
+
type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
46
|
+
status: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
47
|
+
}, z.core.$strip>>>;
|
|
37
48
|
submitted_values: z.ZodOptional<z.ZodUnknown>;
|
|
38
49
|
submitted_email: z.ZodOptional<z.ZodUnknown>;
|
|
39
50
|
items: z.ZodOptional<z.ZodUnknown>;
|
|
@@ -65,6 +76,8 @@ export type ChatwootMessage = z.infer<typeof messageSchema>;
|
|
|
65
76
|
export declare const CONVERSATIONS_PER_PAGE = 25;
|
|
66
77
|
/** Chatwoot returns up to 100 messages per `after` page. */
|
|
67
78
|
export declare const MESSAGE_PAGE_SIZE = 100;
|
|
79
|
+
/** MessageFinder returns 20 for the latest page and for `before`. */
|
|
80
|
+
export declare const MESSAGE_HISTORY_PAGE_SIZE = 20;
|
|
68
81
|
/** The body of POST conversations/{id}/toggle_status. */
|
|
69
82
|
export type StatusChange = operations["toggle-status-of-a-conversation"]["requestBody"]["content"]["application/json"];
|
|
70
83
|
/** A priority for POST conversations/{id}/toggle_priority; null clears it. */
|
|
@@ -86,7 +99,7 @@ export type ChatwootClient = ReturnType<typeof chatwootClient>;
|
|
|
86
99
|
type MessageQuery = NonNullable<operations["list-all-messages"]["parameters"]["query"]> & {
|
|
87
100
|
filter_internal_messages?: true;
|
|
88
101
|
};
|
|
89
|
-
export declare function chatwootClient(baseUrl: string, token: string, fetch: Fetch): {
|
|
102
|
+
export declare function chatwootClient(baseUrl: string, token: string, fetch: Fetch, limits?: RateLimitStore): {
|
|
90
103
|
/** The conversation, or undefined when it does not exist (it was deleted). */
|
|
91
104
|
getConversation(accountId: number, conversationId: number): Promise<ChatwootConversation | undefined>;
|
|
92
105
|
/** Messages with an id above `after`, oldest first; without `after`, the latest page. */
|
|
@@ -97,13 +110,16 @@ export declare function chatwootClient(baseUrl: string, token: string, fetch: Fe
|
|
|
97
110
|
* (MessageFinder#messages_between at v4.18.0) or exclusively (as the spec describes it).
|
|
98
111
|
*/
|
|
99
112
|
getMessage(accountId: number, conversationId: number, messageId: number): Promise<ChatwootMessage | undefined>;
|
|
113
|
+
inboxBot(accountId: number, inboxId: number): Promise<{
|
|
114
|
+
id: number;
|
|
115
|
+
} | undefined>;
|
|
100
116
|
inboxName(accountId: number, inboxId: number): Promise<string | undefined>;
|
|
101
117
|
/**
|
|
102
118
|
* One page (CONVERSATIONS_PER_PAGE) of conversations of any assignee and the given status
|
|
103
119
|
* (default: any), most recent activity first (Conversations::SortService's default,
|
|
104
120
|
* `last_activity_at_desc`, at v4.18.0).
|
|
105
121
|
*/
|
|
106
|
-
listConversations(accountId: number, page: number, status?: "all" | "open" | "snoozed"): Promise<ChatwootConversation[]>;
|
|
122
|
+
listConversations(accountId: number, page: number, status?: "all" | "open" | "snoozed" | "pending"): Promise<ChatwootConversation[]>;
|
|
107
123
|
/** The content of the account's canned response with this short code, if it exists. */
|
|
108
124
|
cannedResponse(accountId: number, shortCode: string): Promise<string | undefined>;
|
|
109
125
|
getProfile(): Promise<{
|
|
@@ -160,7 +176,7 @@ export declare function chatwootClient(baseUrl: string, token: string, fetch: Fe
|
|
|
160
176
|
setStatus(accountId: number, conversationId: number, change: StatusChange): Promise<void>;
|
|
161
177
|
setPriority(accountId: number, conversationId: number, priority: ConversationPriority | null): Promise<void>;
|
|
162
178
|
setContactBlocked(accountId: number, contactId: number, blocked: boolean): Promise<void>;
|
|
163
|
-
assign(accountId: number, conversationId: number, assigneeId: number): Promise<void>;
|
|
179
|
+
assign(accountId: number, conversationId: number, assigneeId: number, assigneeType?: "User" | "AgentBot"): Promise<void>;
|
|
164
180
|
/**
|
|
165
181
|
* Removes the conversation's assignee the way Chatwoot's dashboard does (ConversationAction.vue
|
|
166
182
|
* posts `assignee_id: null`, which AssignmentsController#create applies, at v4.18.0). The
|
|
@@ -172,14 +188,51 @@ export declare function chatwootClient(baseUrl: string, token: string, fetch: Fe
|
|
|
172
188
|
conversationLabels(accountId: number, conversationId: number): Promise<string[]>;
|
|
173
189
|
/** Replaces the conversation's labels (the spec's "Add Labels" overwrites the list). */
|
|
174
190
|
setLabels(accountId: number, conversationId: number, labels: string[]): Promise<void>;
|
|
175
|
-
setCustomAttributes
|
|
191
|
+
setCustomAttributes(accountId: number, conversationId: number, attributes: Record<string, unknown>): Promise<void>;
|
|
176
192
|
/**
|
|
177
193
|
* Sends an outgoing message (or private note). With files it is sent as the spec's
|
|
178
194
|
* multipart/form-data body; the generated type renders its `attachments[]` binaries as
|
|
179
195
|
* strings, so the serializer appends the files itself.
|
|
180
196
|
*/
|
|
181
|
-
createMessage(accountId: number, conversationId: number, message: NewMessage): Promise<
|
|
197
|
+
createMessage(accountId: number, conversationId: number, message: NewMessage): Promise<ChatwootMessage | undefined>;
|
|
182
198
|
};
|
|
199
|
+
/** A bot (or another explicit non-user assignee) must never be matched to a numeric user id. */
|
|
200
|
+
export declare function personAssignee(conversation: ChatwootConversation): {
|
|
201
|
+
id?: number;
|
|
202
|
+
access_token?: string;
|
|
203
|
+
account_id?: number;
|
|
204
|
+
available_name?: string;
|
|
205
|
+
avatar_url?: string;
|
|
206
|
+
confirmed?: boolean;
|
|
207
|
+
display_name?: string | null;
|
|
208
|
+
message_signature?: string | null;
|
|
209
|
+
email?: string;
|
|
210
|
+
hmac_identifier?: string;
|
|
211
|
+
inviter_id?: number | null;
|
|
212
|
+
name?: string;
|
|
213
|
+
provider?: string;
|
|
214
|
+
pubsub_token?: string;
|
|
215
|
+
role?: "agent" | "administrator";
|
|
216
|
+
ui_settings?: Record<string, unknown>;
|
|
217
|
+
uid?: string;
|
|
218
|
+
type?: string | null;
|
|
219
|
+
custom_attributes?: Record<string, unknown>;
|
|
220
|
+
accounts?: {
|
|
221
|
+
id?: number;
|
|
222
|
+
name?: string;
|
|
223
|
+
status?: string;
|
|
224
|
+
active_at?: string | null;
|
|
225
|
+
role?: "administrator" | "agent";
|
|
226
|
+
permissions?: string[];
|
|
227
|
+
availability?: string;
|
|
228
|
+
availability_status?: string;
|
|
229
|
+
auto_offline?: boolean;
|
|
230
|
+
custom_role_id?: number | null;
|
|
231
|
+
custom_role?: Record<string, unknown> | null;
|
|
232
|
+
}[];
|
|
233
|
+
} | undefined;
|
|
234
|
+
/** An actual public answer; Chatwoot templates include greetings and out-of-office notices. */
|
|
235
|
+
export declare function isAnsweringReply(message: ChatwootMessage): boolean;
|
|
183
236
|
export declare function toRelayConversation(conversationId: number, conversation: ChatwootConversation): RelayConversation;
|
|
184
237
|
export declare function toRelayMessage(message: ChatwootMessage, context: {
|
|
185
238
|
account: {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Bounds non-fetch dependencies too, including an RPC whose enqueue outcome can be unknown. */
|
|
2
|
+
export declare function within<T>(pending: Promise<T>, signal: AbortSignal): Promise<T>;
|
|
3
|
+
export declare class JobDeadlineError extends Error {
|
|
4
|
+
readonly requestStarted: boolean;
|
|
5
|
+
constructor(requestStarted?: boolean);
|
|
6
|
+
}
|
package/lib/shared/store.d.ts
CHANGED
|
@@ -1,27 +1,30 @@
|
|
|
1
1
|
export declare function retryDelay(attempts: number): number;
|
|
2
|
-
export
|
|
2
|
+
export type Job = {
|
|
3
3
|
key: string;
|
|
4
4
|
payload: string;
|
|
5
5
|
version: number;
|
|
6
6
|
attempts: number;
|
|
7
7
|
/** When the job was first queued (ms since the epoch). */
|
|
8
8
|
createdAt: number;
|
|
9
|
-
}
|
|
9
|
+
};
|
|
10
10
|
export declare class QueueStore {
|
|
11
11
|
protected readonly sql: SqlStorage;
|
|
12
12
|
protected readonly now: () => number;
|
|
13
|
-
|
|
13
|
+
private readonly atomic;
|
|
14
|
+
constructor(sql: SqlStorage, now?: () => number, atomic?: <T>(write: () => T) => T);
|
|
15
|
+
transaction<T>(write: () => T): T;
|
|
14
16
|
migrate(): void;
|
|
15
17
|
get(key: string): string | undefined;
|
|
16
18
|
set(key: string, value: string, ttlMs?: number): void;
|
|
17
19
|
delete(key: string): void;
|
|
18
|
-
list(start: string, end: string): string[];
|
|
19
20
|
/**
|
|
20
21
|
* Adds a job, or marks an existing one as needing another run (its version changes). A job
|
|
21
22
|
* that is backing off after failures keeps its schedule.
|
|
22
23
|
*/
|
|
23
24
|
enqueue(key: string, priority: number, payload: string, notBefore?: number): void;
|
|
24
25
|
nextDueJob(): Job | undefined;
|
|
26
|
+
/** A bounded due batch; independent scan and delivery work can select their own keys. */
|
|
27
|
+
nextDueJobs(limit: number, prefix?: string): Job[];
|
|
25
28
|
/** Earliest due time. */
|
|
26
29
|
nextWakeup(): number | undefined;
|
|
27
30
|
/** Removes a finished job unless it was enqueued again while running. */
|
|
@@ -33,5 +36,9 @@ export declare class QueueStore {
|
|
|
33
36
|
* budget, or Discord rate limits it.
|
|
34
37
|
*/
|
|
35
38
|
deferJob(job: Job, delayMs?: number): void;
|
|
39
|
+
/** One short re-read for a racing status webhook, then wait for an event or a sweep. */
|
|
40
|
+
holdJob(job: Job): void;
|
|
41
|
+
/** Suspended conversation jobs need reconciliation even outside the ordinary activity window. */
|
|
42
|
+
wakeHeldJobs(): void;
|
|
36
43
|
prune(): void;
|
|
37
44
|
}
|
package/lib/shared/types.d.ts
CHANGED
|
@@ -49,7 +49,9 @@ export interface RelayConversation {
|
|
|
49
49
|
blocked?: boolean;
|
|
50
50
|
avatarUrl?: string | null;
|
|
51
51
|
};
|
|
52
|
+
/** Person only; agent bots are represented as unassigned. */
|
|
52
53
|
assignee?: RelayAssignee | null;
|
|
54
|
+
assigneeType?: string | null;
|
|
53
55
|
customAttributes: Record<string, unknown>;
|
|
54
56
|
}
|
|
55
57
|
export interface RelayMessage {
|
|
@@ -64,6 +66,8 @@ export interface RelayMessage {
|
|
|
64
66
|
emailSubject?: string | null;
|
|
65
67
|
/** An automatic email reply (out of office, for example): relayed without notifications. */
|
|
66
68
|
autoReply?: boolean;
|
|
69
|
+
/** A qualifying public reply follows this message in Chatwoot. */
|
|
70
|
+
answered?: boolean;
|
|
67
71
|
attachments: RelayAttachment[];
|
|
68
72
|
/** A bot's options to pick, cards, or articles, with a link each when they have one. */
|
|
69
73
|
items?: RelayItem[];
|
package/package.json
CHANGED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import type { RoutingContext, RoutingStore } from "./routing.ts";
|
|
3
|
-
declare const effectSchema: z.ZodObject<{
|
|
4
|
-
inputId: z.ZodNumber;
|
|
5
|
-
kind: z.ZodNullable<z.ZodString>;
|
|
6
|
-
handled: z.ZodNumber;
|
|
7
|
-
}, z.core.$strip>;
|
|
8
|
-
export declare function actOnce(ctx: RoutingContext, key: string, effect: z.infer<typeof effectSchema>, record: "before" | "after", act: () => Promise<unknown>): Promise<void>;
|
|
9
|
-
export declare function readEffects(store: RoutingStore, accountId: number, conversationId: number): {
|
|
10
|
-
inputId: number;
|
|
11
|
-
kind: string | null;
|
|
12
|
-
handled: number;
|
|
13
|
-
}[];
|
|
14
|
-
export {};
|
package/lib/shared/sweep.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import type { reconcileSchema } from "./config.ts";
|
|
3
|
-
import type { QueueStore } from "./store.ts";
|
|
4
|
-
declare const passSchema: z.ZodObject<{
|
|
5
|
-
cutoff: z.ZodNumber;
|
|
6
|
-
page: z.ZodNumber;
|
|
7
|
-
startedAt: z.ZodNumber;
|
|
8
|
-
}, z.core.$strip>;
|
|
9
|
-
export declare function readSweepPass(store: QueueStore, accountId: number, reconcile: z.infer<typeof reconcileSchema>): z.infer<typeof passSchema>;
|
|
10
|
-
export declare function saveSweepPass(store: QueueStore, accountId: number, pass: z.infer<typeof passSchema>, nextPage?: number): void;
|
|
11
|
-
export {};
|