@opencxh/domain 1.211.0 → 1.216.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/dist/entities/activity/types.d.ts +2 -0
- package/dist/entities/assignment/types.d.ts +9 -0
- package/dist/entities/work/types.d.ts +4 -35
- package/dist/index.cjs +15 -15
- package/dist/index.js +734 -701
- package/dist/platform/notification.d.ts +11 -0
- package/dist/platform/resource-source.d.ts +105 -0
- package/dist/platform/resource-source.test.d.ts +1 -0
- package/dist/text/triage.d.ts +20 -0
- package/dist/text/triage.test.d.ts +1 -0
- package/package.json +1 -1
|
@@ -83,6 +83,15 @@ export interface Notification {
|
|
|
83
83
|
context?: NotificationText;
|
|
84
84
|
actor?: NotificationActor;
|
|
85
85
|
link?: NotificationLink;
|
|
86
|
+
/**
|
|
87
|
+
* Identity of what this is about, in `refKey()` form: `"interaction:i_1"`, `"work_item:w1"`.
|
|
88
|
+
*
|
|
89
|
+
* Next to {@link link} and not instead of it: the path is how you *navigate* there and cannot be
|
|
90
|
+
* derived from the id (work's route wants `itemKey`), while the key is how a surface is
|
|
91
|
+
* *recognised* — the shell already resolves the open page to a scopeKey, so this is what lets
|
|
92
|
+
* opening the item mark its notifications read.
|
|
93
|
+
*/
|
|
94
|
+
subjectKey?: string;
|
|
86
95
|
/** Free-form; travels untouched into the push payload. */
|
|
87
96
|
data?: Record<string, unknown>;
|
|
88
97
|
createdAt: number;
|
|
@@ -102,6 +111,8 @@ export interface NotifyRequest {
|
|
|
102
111
|
context?: NotificationText;
|
|
103
112
|
actor?: NotificationActor;
|
|
104
113
|
link?: NotificationLink;
|
|
114
|
+
/** `refKey(ref)` of the subject — see {@link Notification.subjectKey}. */
|
|
115
|
+
subjectKey?: string;
|
|
105
116
|
data?: Record<string, unknown>;
|
|
106
117
|
/**
|
|
107
118
|
* Wake the devices without leaving a row behind. For a signal that is meaningless once it is
|
|
@@ -36,6 +36,10 @@ export declare const RESOURCE_RESOLVE_SERVICE = "resources.resolve";
|
|
|
36
36
|
* items carry the conversation's key, the conversation knows nothing about work. Answering it
|
|
37
37
|
* here rather than per consumer is what keeps the shell from growing an
|
|
38
38
|
* `if (kind === "interaction")` per app that could be linked.
|
|
39
|
+
*
|
|
40
|
+
* The rows may be {@link RelatedResource}s, i.e. carry an `origin`. Answering with the plain
|
|
41
|
+
* summary stays valid; a consumer that wants to separate a link from a lead reads that field and
|
|
42
|
+
* treats its absence as "unknown, so not a stated link".
|
|
39
43
|
*/
|
|
40
44
|
export declare const RESOURCE_ATTACHED_SERVICE = "resources.attached";
|
|
41
45
|
/** One pointable resource, as the app that owns it shows it. */
|
|
@@ -106,3 +110,104 @@ export interface ResourceAttachedParams {
|
|
|
106
110
|
* and this contract is read mostly on the client.
|
|
107
111
|
*/
|
|
108
112
|
export declare function resourceKindOf(scopeKey: string): string;
|
|
113
|
+
/**
|
|
114
|
+
* The same question, server-side: **what hangs on this key, and is that a fact or a guess.**
|
|
115
|
+
*
|
|
116
|
+
* The service-bus keys above are asked by a user with the app open. An AI tool, a playbook and a
|
|
117
|
+
* job have no client and no store, so they need the question over HTTP, and in one place: the hub
|
|
118
|
+
* in apps/context (`POST /resource/related`). It answers from two sources:
|
|
119
|
+
*
|
|
120
|
+
* - **linked** — a {@link Relation} row: somebody (or a tool) linked the two. One local indexed
|
|
121
|
+
* read on the relation store, both directions, no protocol between apps.
|
|
122
|
+
* - **derived** — a row that merely shares a dossier key with the anchor (`domain:`, `mailto:`).
|
|
123
|
+
* The hub fans `/provider/scope/related` out over the **existing `scope` provider role**: the
|
|
124
|
+
* apps that own kinds already authorize there and already return {@link ScopeAuth.keys}.
|
|
125
|
+
*
|
|
126
|
+
* | Route | Body | Answer |
|
|
127
|
+
* |---|---|---|
|
|
128
|
+
* | `/provider/scope/related` | {@link RelatedResourceRequest} | {@link RelatedResourceResponse} |
|
|
129
|
+
* | `/provider/scope/read` | {@link ResourceReadRequest} | {@link ResourceReadResponse} |
|
|
130
|
+
*
|
|
131
|
+
* Both are app-to-app and optional: an app that does not implement them loses its own rows, never
|
|
132
|
+
* the answer. The hub resolves the anchor's dossier keys **once** (`authorizeIdentity`) and passes
|
|
133
|
+
* them along, so a fan-out over five apps still costs one authorization.
|
|
134
|
+
*/
|
|
135
|
+
export declare const SCOPE_RELATED_ROUTE = "/provider/scope/related";
|
|
136
|
+
export declare const SCOPE_READ_ROUTE = "/provider/scope/read";
|
|
137
|
+
/**
|
|
138
|
+
* One explicit link between two resources, stored by apps/context.
|
|
139
|
+
*
|
|
140
|
+
* **Two rows per link**, out and back, so "what hangs on this key" is one indexed query on
|
|
141
|
+
* `fromKey` in either direction instead of an `$or` no index serves. **One hop, never traversed:**
|
|
142
|
+
* this store cannot join or recurse, so a relation is read, not followed. Party matches (a shared
|
|
143
|
+
* domain, a shared address) are not relations; they stay dossier keys on the row.
|
|
144
|
+
*/
|
|
145
|
+
export interface Relation {
|
|
146
|
+
id: string;
|
|
147
|
+
organizationId: string;
|
|
148
|
+
fromKey: string;
|
|
149
|
+
toKey: string;
|
|
150
|
+
/**
|
|
151
|
+
* The relation and the party role in one vocabulary: `client` · `opposing` · `context` ·
|
|
152
|
+
* `blocks` · `blocked_by` · `relates` · `duplicates` · `attachment` · `party`. One field, no
|
|
153
|
+
* separate role column: "this company is the client" and "this item blocks that" are both a
|
|
154
|
+
* named arrow.
|
|
155
|
+
*/
|
|
156
|
+
type: string;
|
|
157
|
+
/** Shared by the outbound and the inbound row; keeps unlinking one action. */
|
|
158
|
+
pairId: string;
|
|
159
|
+
/** How the inbound row identifies itself, so a UI can show "is blocked by". */
|
|
160
|
+
inverse?: boolean;
|
|
161
|
+
createdBy: string;
|
|
162
|
+
createdAt?: number;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* What the hub asks one app. `scopeKey` is already authorized — the answering app must not
|
|
166
|
+
* re-gate it, but it must filter its own rows for the stamped acting identity.
|
|
167
|
+
*/
|
|
168
|
+
export interface RelatedResourceRequest {
|
|
169
|
+
/** The anchor: the thing the user (or the model) is standing on. */
|
|
170
|
+
scopeKey: string;
|
|
171
|
+
/**
|
|
172
|
+
* The anchor's dossier keys and the keys it is linked to, `scopeKey` included. An app matches
|
|
173
|
+
* its own indexed key column against this in one `$in`, and resolves the keys that name its
|
|
174
|
+
* own rows (`interaction:<id>`).
|
|
175
|
+
*/
|
|
176
|
+
keys: string[];
|
|
177
|
+
/** Maximum rows this app may return. Absent = its own sensible cap. */
|
|
178
|
+
limit?: number;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* One related row, and **why** it is related.
|
|
182
|
+
*
|
|
183
|
+
* `origin` is decided by the hub: a row the anchor has a {@link Relation} to is `linked`, any
|
|
184
|
+
* other match is `derived`. An app sets it only for a **structural** relation it owns and that
|
|
185
|
+
* no relation row expresses (a contact's employer via `companyId`). A consumer keeps the two
|
|
186
|
+
* apart: a model told "these are the linked conversations" reads a domain match as a fact.
|
|
187
|
+
*/
|
|
188
|
+
export interface RelatedResource extends ResourceSummary {
|
|
189
|
+
origin?: "linked" | "derived";
|
|
190
|
+
/** Why this row is here: the relation type (`client`), or the dossier key that matched. */
|
|
191
|
+
via?: string;
|
|
192
|
+
}
|
|
193
|
+
export interface RelatedResourceResponse {
|
|
194
|
+
/**
|
|
195
|
+
* Rows relevant to the asked key set, in both directions an app can answer:
|
|
196
|
+
* rows **identified by** one of the keys (resolution), and rows **carrying** one of them
|
|
197
|
+
* (the key match). One route for both, because to the answering app they are the same
|
|
198
|
+
* `$in` over the same indexed column.
|
|
199
|
+
*/
|
|
200
|
+
rows: RelatedResource[];
|
|
201
|
+
}
|
|
202
|
+
/** Params for `/provider/scope/read`: one key, answered by the app that owns the kind. */
|
|
203
|
+
export interface ResourceReadRequest {
|
|
204
|
+
scopeKey: string;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* One resource as readable text — the generic counterpart of `read_work_item` /
|
|
208
|
+
* `list_activities`, so a caller with a bare key does not have to know which app's tool reads it.
|
|
209
|
+
*/
|
|
210
|
+
export interface ResourceReadResponse {
|
|
211
|
+
text: string;
|
|
212
|
+
title?: string;
|
|
213
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/text/triage.d.ts
CHANGED
|
@@ -11,3 +11,23 @@ export declare const SUMMARY_MIN_MESSAGES = 3;
|
|
|
11
11
|
export declare const SUMMARY_MIN_LAST_CHARS = 600;
|
|
12
12
|
/** True when the thread is long enough that a summary saves the reader scrolling. */
|
|
13
13
|
export declare function isThreadLongEnough(messageCount: number, lastMessageChars: number): boolean;
|
|
14
|
+
/** Headers that say something about bulk/automated origin. Nothing else is stored. */
|
|
15
|
+
export declare const MAIL_HINT_HEADERS: string[];
|
|
16
|
+
/** Graph and Gmail both hand us `{name,value}[]`; keep only the whitelist, lowercased. */
|
|
17
|
+
export declare function pickMailHeaders(entries: {
|
|
18
|
+
name?: string;
|
|
19
|
+
value?: string;
|
|
20
|
+
}[]): Record<string, string>;
|
|
21
|
+
export type MailClass = "marketing" | "automated";
|
|
22
|
+
/**
|
|
23
|
+
* Which bulk label an inbound mail deserves, if any. Headers first, sender/body
|
|
24
|
+
* regex as fallback. `automated` is checked first on purpose: an order
|
|
25
|
+
* confirmation carrying an unsubscribe footer is still automated, not marketing.
|
|
26
|
+
*/
|
|
27
|
+
export declare function classifyMail(p: {
|
|
28
|
+
from?: {
|
|
29
|
+
email: string;
|
|
30
|
+
};
|
|
31
|
+
body?: string;
|
|
32
|
+
headers?: Record<string, string>;
|
|
33
|
+
}): MailClass | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|