@crossworks/client-types 0.232.329 → 0.232.334
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/package.json +1 -1
- package/src/dto/access.ts +9 -2
- package/src/dto/client.ts +66 -5
- package/src/dto/member-apps.ts +6 -1
- package/src/dto/member-invites.ts +2 -1
- package/src/dto/member.ts +69 -0
- package/src/index.ts +10 -0
- package/src/member-kinds.ts +34 -0
package/package.json
CHANGED
package/src/dto/access.ts
CHANGED
|
@@ -33,8 +33,15 @@ export type AccessLinkView = {
|
|
|
33
33
|
/** GET /api/access/nodes/:id */
|
|
34
34
|
/** Who wrote a brain item, when a member wrote it and an admin accepted it
|
|
35
35
|
* (member logins Phase 4): the member-authored badge. `name` is the login's
|
|
36
|
-
* display name ("A member" without one, "
|
|
37
|
-
|
|
36
|
+
* display name ("A member" without one, "A client" for a client without
|
|
37
|
+
* one, "Removed member" once deleted). `role` (0.232.333 on) names the
|
|
38
|
+
* author's role: show "Client", never "A member", for a client (client
|
|
39
|
+
* logins audit B26); null once the login is deleted. */
|
|
40
|
+
export type MemberItemAuthor = {
|
|
41
|
+
name: string;
|
|
42
|
+
acceptedAt: string | null;
|
|
43
|
+
role?: 'member' | 'client' | null;
|
|
44
|
+
};
|
|
38
45
|
|
|
39
46
|
export type AccessNodeView = {
|
|
40
47
|
item: AccessItemView;
|
package/src/dto/client.ts
CHANGED
|
@@ -35,7 +35,9 @@ export type ClientSharedRow = {
|
|
|
35
35
|
type: MemberItemKind;
|
|
36
36
|
title: string;
|
|
37
37
|
icon: string | null;
|
|
38
|
-
|
|
38
|
+
/** Never sent since 0.232.333 (it was built from the unredacted text); do
|
|
39
|
+
* not show it. Optional only so older clients still compile. */
|
|
40
|
+
summary?: string | null;
|
|
39
41
|
updatedAt: string;
|
|
40
42
|
};
|
|
41
43
|
|
|
@@ -54,7 +56,7 @@ export type ClientSharedPage = {
|
|
|
54
56
|
export type ClientSharedItem =
|
|
55
57
|
| (ClientSharedRow & { type: 'page'; doc: unknown })
|
|
56
58
|
| (ClientSharedRow & { type: 'note'; content: string })
|
|
57
|
-
| (ClientSharedRow & { type: 'table'; table:
|
|
59
|
+
| (ClientSharedRow & { type: 'table'; table: ClientSharedTable })
|
|
58
60
|
| (ClientSharedRow & { type: 'draw' })
|
|
59
61
|
| (ClientSharedRow & {
|
|
60
62
|
type: 'file';
|
|
@@ -63,6 +65,39 @@ export type ClientSharedItem =
|
|
|
63
65
|
sizeBytes: number | null;
|
|
64
66
|
});
|
|
65
67
|
|
|
68
|
+
/** One column of a client table: what the grid draws a header and a cell
|
|
69
|
+
* with. No formula, no reference source, no options. */
|
|
70
|
+
export type ClientSharedTableColumn = { id: string; name: string; type: string };
|
|
71
|
+
|
|
72
|
+
/** One committed row of a client table. A cell that names an item the
|
|
73
|
+
* client may not read (`/n/<id>`, `page:`, `media:`, `draw:`, `mention:`)
|
|
74
|
+
* arrives as "Private item". */
|
|
75
|
+
export type ClientSharedTableRow = {
|
|
76
|
+
id: string;
|
|
77
|
+
cells: Record<string, string | number | boolean | string[] | null>;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/** A client table (GET /api/client/shared/:id, type table): the committed
|
|
81
|
+
* grid of one tab and nothing else about the table (no description, tags,
|
|
82
|
+
* summary, visibility, level, app link or draft). The shape the member
|
|
83
|
+
* reader draws (`data`, `docClipped`, `tabs`, `tabId`), so one viewer reads
|
|
84
|
+
* both. `data` is a leading window when `docClipped`; `rowCount` is the
|
|
85
|
+
* tab's true total. */
|
|
86
|
+
export type ClientSharedTable = {
|
|
87
|
+
data: {
|
|
88
|
+
columns: ClientSharedTableColumn[];
|
|
89
|
+
rows: ClientSharedTableRow[];
|
|
90
|
+
/** Footer totals the owner set, by column id. */
|
|
91
|
+
aggregates?: Record<string, string>;
|
|
92
|
+
};
|
|
93
|
+
docClipped?: boolean;
|
|
94
|
+
/** The workbook's tabs in order (absent for a one-grid table). */
|
|
95
|
+
tabs?: { id: string; name: string; rows: number; columns: number }[];
|
|
96
|
+
/** Which tab `data` holds. */
|
|
97
|
+
tabId?: string | null;
|
|
98
|
+
rowCount?: number;
|
|
99
|
+
};
|
|
100
|
+
|
|
66
101
|
/** The label a client sees instead of a reference it may not read. */
|
|
67
102
|
export const CLIENT_PRIVATE_LABEL = 'Private item';
|
|
68
103
|
|
|
@@ -104,7 +139,9 @@ export type ClientLoginCreated = { client: ClientLoginRow };
|
|
|
104
139
|
|
|
105
140
|
/** POST /api/team-admin/clients/:id/signin-link -> the link, ONCE. `path` is
|
|
106
141
|
* the client-app path to hand the client (the code is its only secret);
|
|
107
|
-
* 72 hours, one use. Any older open link of the login is revoked.
|
|
142
|
+
* 72 hours, one use. Any older open link of the login is revoked. Since
|
|
143
|
+
* 0.232.333 the code rides in the fragment (`/client-signin#code=...`), so
|
|
144
|
+
* it never reaches a server log; links issued before carry `?code=`. */
|
|
108
145
|
export type ClientSigninLinkCreated = {
|
|
109
146
|
link: ClientSigninLinkRow;
|
|
110
147
|
code: string;
|
|
@@ -118,7 +155,10 @@ export type ClientAdminRefusedReason =
|
|
|
118
155
|
| 'contact-not-found'
|
|
119
156
|
| 'contact-has-login'
|
|
120
157
|
| 'no-email'
|
|
121
|
-
| 'not-a-client'
|
|
158
|
+
| 'not-a-client'
|
|
159
|
+
/** A contact-linked client's email must be one of the contact's addresses
|
|
160
|
+
* (the mail gates know the client by its contact; audit B26). */
|
|
161
|
+
| 'email-not-on-contact';
|
|
122
162
|
|
|
123
163
|
/** POST /api/auth/client-link { code, email } -> 200 { ok: true } and the
|
|
124
164
|
* session cookie (30 days), or one uniform 401 for every failure. */
|
|
@@ -159,7 +199,28 @@ export type ClientSigninSender = {
|
|
|
159
199
|
dailyCap: number;
|
|
160
200
|
sentLast24h: number;
|
|
161
201
|
capReached: boolean;
|
|
202
|
+
/** Codes actually handed to the mail server in the last 24 h (sentLast24h counted failed ones too; it now equals this). */
|
|
203
|
+
deliveredLast24h?: number;
|
|
204
|
+
/** Sends that failed in the last 24 h, and the newest failure. */
|
|
205
|
+
failedLast24h?: number;
|
|
206
|
+
lastFailure?: { at: string; reason: string } | null;
|
|
207
|
+
/** False when no email worker serves the code queue on this box: codes are then OFF whatever the sender. */
|
|
208
|
+
emailWorker?: boolean;
|
|
209
|
+
/** Requests that were skipped because a cap was hit in the last 24 h (per email, per address or brain-wide). */
|
|
210
|
+
capSkipsLast24h?: number;
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
/** GET /api/team-admin/clients/signin-sender/preview?accountId=<id>: what
|
|
214
|
+
* choosing that account as the sender would do, before the admin confirms.
|
|
215
|
+
* Choosing None (or another sender) later RESTORES the folders the choice
|
|
216
|
+
* left out (the server remembers exactly which it added). */
|
|
217
|
+
export type ClientSigninSenderPreview = {
|
|
218
|
+
/** The folders that choosing this sender will leave out of mail sync. Empty + canUse false = refused. */
|
|
219
|
+
sentFolders: string[];
|
|
220
|
+
canUse: boolean;
|
|
221
|
+
reason?: 'no-sent-folder' | 'folders-unreadable' | 'account-cannot-send';
|
|
162
222
|
};
|
|
163
223
|
|
|
164
224
|
/** Why an admin's sender choice was refused (the 4xx `reason`). */
|
|
165
|
-
export type ClientSenderRefusedReason =
|
|
225
|
+
export type ClientSenderRefusedReason =
|
|
226
|
+
'account-not-found' | 'account-cannot-send' | 'no-sent-folder' | 'folders-unreadable';
|
package/src/dto/member-apps.ts
CHANGED
|
@@ -56,8 +56,13 @@ export type MemberChatRow = {
|
|
|
56
56
|
name: string;
|
|
57
57
|
email: string;
|
|
58
58
|
/** False when the login is disabled or no longer a member (its old
|
|
59
|
-
* thread still shows).
|
|
59
|
+
* thread still shows). Always false for a client: a client is never a
|
|
60
|
+
* team member (client logins audit B26). */
|
|
60
61
|
active: boolean;
|
|
62
|
+
/** The login's role, named (0.232.333 on): 'member' for the team; 'client'
|
|
63
|
+
* for a client login with a chat thread, which is NOT a team member; absent
|
|
64
|
+
* for a former member who is an admin now (its old thread still shows). */
|
|
65
|
+
role?: 'member' | 'client';
|
|
61
66
|
lastMessageAt: string | null;
|
|
62
67
|
lastMessageText: string | null;
|
|
63
68
|
lastMessageDirection: 'inbound' | 'outbound' | null;
|
|
@@ -37,7 +37,8 @@ export type MemberInviteList = { invites: MemberInviteRow[] };
|
|
|
37
37
|
/**
|
|
38
38
|
* POST /api/team-admin/invites (201). `code` and `linkPath` are shown ONCE:
|
|
39
39
|
* only the code's hash is stored. `linkPath` is a client-app path
|
|
40
|
-
* (`/invite
|
|
40
|
+
* (`/invite#code=...` since 0.232.333: the fragment never reaches a server
|
|
41
|
+
* log; `/invite?code=…` before); prefix the client's origin to share it.
|
|
41
42
|
*/
|
|
42
43
|
export type MemberInviteCreated = {
|
|
43
44
|
invite: MemberInviteRow;
|
package/src/dto/member.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { AccessLevel, MemberItemAuthor } from './access';
|
|
8
8
|
import type { MemberItemKind } from '../member-kinds';
|
|
9
|
+
export type { MemberItemFilter } from '../member-kinds';
|
|
9
10
|
|
|
10
11
|
/** GET /api/member/shell */
|
|
11
12
|
export type MemberShell = {
|
|
@@ -109,6 +110,8 @@ export type MemberSpaceItemRow = {
|
|
|
109
110
|
returnedNote: string | null;
|
|
110
111
|
/** The login that wrote it (team drafts show whose it is). */
|
|
111
112
|
authorLoginId: string | null;
|
|
113
|
+
/** Brains from the item-list alignment release on. */
|
|
114
|
+
createdAt?: string;
|
|
112
115
|
updatedAt: string;
|
|
113
116
|
};
|
|
114
117
|
|
|
@@ -247,3 +250,69 @@ export type MemberAcceptedItem =
|
|
|
247
250
|
sizeBytes: number | null;
|
|
248
251
|
changedByAdmin?: boolean;
|
|
249
252
|
});
|
|
253
|
+
|
|
254
|
+
// ── One list of everything a member can see (item-list alignment) ───────
|
|
255
|
+
|
|
256
|
+
/** Where a row of the one list comes from; it picks the item view that
|
|
257
|
+
* opens it: `own` the member's editor, `team` a teammate's saved draft,
|
|
258
|
+
* `library` the brain item, `accepted` the version this member wrote and an
|
|
259
|
+
* admin accepted at a level above the Library's (admin or public). */
|
|
260
|
+
export type MemberItemSource = 'own' | 'team' | 'library' | 'accepted';
|
|
261
|
+
|
|
262
|
+
/** The small state pill a row wears beside its actions. Brain items (the
|
|
263
|
+
* Library and accepted rows) wear none. */
|
|
264
|
+
export type MemberItemPill = 'private' | 'draft' | 'submitted' | 'returned' | 'with-admin';
|
|
265
|
+
|
|
266
|
+
/** One row of GET /api/member/items. */
|
|
267
|
+
export type MemberItemRow = {
|
|
268
|
+
id: string;
|
|
269
|
+
type: MemberItemKind;
|
|
270
|
+
title: string;
|
|
271
|
+
icon: string | null;
|
|
272
|
+
summary: string | null;
|
|
273
|
+
updatedAt: string;
|
|
274
|
+
source: MemberItemSource;
|
|
275
|
+
pill: MemberItemPill | null;
|
|
276
|
+
/** The brain item's level (library and accepted rows); null on a draft. */
|
|
277
|
+
audience: AccessLevel | null;
|
|
278
|
+
/** A brain item a member wrote and an admin accepted: whose it is. */
|
|
279
|
+
author: MemberItemAuthor | null;
|
|
280
|
+
/** This member wrote it and an admin accepted it. */
|
|
281
|
+
byMe: boolean;
|
|
282
|
+
/** The personal-space row (own and team rows): sharing, review state, the
|
|
283
|
+
* returned note, for the item view and the detail header. */
|
|
284
|
+
space: MemberSpaceItemRow | null;
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* GET /api/member/items?kind=&q=&state=&page= (brains from the item-list
|
|
289
|
+
* alignment release): the member's own items, teammates' shared drafts, the
|
|
290
|
+
* Library and their accepted items above it, in ONE list, newest first.
|
|
291
|
+
* `state` is a MemberItemFilter (default `all`). Absent on older brains: the
|
|
292
|
+
* client then falls back to the four source lists.
|
|
293
|
+
*/
|
|
294
|
+
export type MemberItemsPage = {
|
|
295
|
+
items: MemberItemRow[];
|
|
296
|
+
total: number;
|
|
297
|
+
page: number;
|
|
298
|
+
pageSize: number;
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* The calling admin's own private item as a row of a BRAIN list (item-list
|
|
303
|
+
* alignment): /api/pages, /api/notes, /api/tables, /api/draws and the files
|
|
304
|
+
* root and Recent lists, with `?state=all` or `?state=private`. The
|
|
305
|
+
* `private` key marks it (brain rows never carry it) and holds the space
|
|
306
|
+
* row the item view opens; the item itself is read and written through
|
|
307
|
+
* /api/admin/space. Private items have no tags and no parent: a tag filter
|
|
308
|
+
* or a sub-page level lists none.
|
|
309
|
+
*/
|
|
310
|
+
export type AdminPrivateListRow = {
|
|
311
|
+
id: string;
|
|
312
|
+
type: MemberItemKind;
|
|
313
|
+
title: string;
|
|
314
|
+
icon: string | null;
|
|
315
|
+
createdAt: string;
|
|
316
|
+
updatedAt: string;
|
|
317
|
+
private: AdminSpaceItemRow;
|
|
318
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -58,6 +58,7 @@ export type {
|
|
|
58
58
|
ReviewAuthorView,
|
|
59
59
|
} from './dto/review';
|
|
60
60
|
export type {
|
|
61
|
+
AdminPrivateListRow,
|
|
61
62
|
AdminSpaceItem,
|
|
62
63
|
AdminSpaceItemRow,
|
|
63
64
|
AdminSpaceList,
|
|
@@ -70,6 +71,11 @@ export type {
|
|
|
70
71
|
MemberAcceptedRow,
|
|
71
72
|
MemberChatMessage,
|
|
72
73
|
MemberChatThread,
|
|
74
|
+
MemberItemFilter,
|
|
75
|
+
MemberItemPill,
|
|
76
|
+
MemberItemRow,
|
|
77
|
+
MemberItemSource,
|
|
78
|
+
MemberItemsPage,
|
|
73
79
|
MemberLibraryItem,
|
|
74
80
|
MemberLibraryKind,
|
|
75
81
|
MemberLibraryPage,
|
|
@@ -118,6 +124,7 @@ export type {
|
|
|
118
124
|
ClientCodeSignIn,
|
|
119
125
|
ClientSigninSenderCandidate,
|
|
120
126
|
ClientSigninSender,
|
|
127
|
+
ClientSigninSenderPreview,
|
|
121
128
|
ClientSenderRefusedReason,
|
|
122
129
|
ClientLoginCreated,
|
|
123
130
|
ClientLoginList,
|
|
@@ -125,6 +132,9 @@ export type {
|
|
|
125
132
|
ClientSharedItem,
|
|
126
133
|
ClientSharedPage,
|
|
127
134
|
ClientSharedRow,
|
|
135
|
+
ClientSharedTable,
|
|
136
|
+
ClientSharedTableColumn,
|
|
137
|
+
ClientSharedTableRow,
|
|
128
138
|
ClientShell,
|
|
129
139
|
ClientSigninLinkCreated,
|
|
130
140
|
ClientSigninLinkRow,
|
package/src/member-kinds.ts
CHANGED
|
@@ -10,3 +10,37 @@ export type MemberItemKind = (typeof MEMBER_ITEM_KINDS)[number];
|
|
|
10
10
|
export function isMemberItemKind(v: unknown): v is MemberItemKind {
|
|
11
11
|
return typeof v === 'string' && (MEMBER_ITEM_KINDS as readonly string[]).includes(v);
|
|
12
12
|
}
|
|
13
|
+
|
|
14
|
+
/** The State filter of a member's one list (GET /api/member/items?state=):
|
|
15
|
+
* `all`, one row pill, `brain` (the rows without a pill), or `by-me` (what
|
|
16
|
+
* this member wrote and an admin accepted, at any level). A runtime constant
|
|
17
|
+
* for the same reason as the kinds: the brain parses it, the client offers
|
|
18
|
+
* it. */
|
|
19
|
+
export const MEMBER_ITEM_FILTERS = [
|
|
20
|
+
'all',
|
|
21
|
+
'private',
|
|
22
|
+
'draft',
|
|
23
|
+
'submitted',
|
|
24
|
+
'returned',
|
|
25
|
+
'with-admin',
|
|
26
|
+
'brain',
|
|
27
|
+
'by-me',
|
|
28
|
+
] as const;
|
|
29
|
+
export type MemberItemFilter = (typeof MEMBER_ITEM_FILTERS)[number];
|
|
30
|
+
|
|
31
|
+
export function isMemberItemFilter(v: unknown): v is MemberItemFilter {
|
|
32
|
+
return typeof v === 'string' && (MEMBER_ITEM_FILTERS as readonly string[]).includes(v);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Which items an ADMIN's brain list holds (`?state=` on /api/pages, /notes,
|
|
36
|
+
* /tables, /draws and the files lists): `brain` (the default, as before),
|
|
37
|
+
* `private` (the admin's own private items only) or `all` (both, merged in
|
|
38
|
+
* the list's own order). */
|
|
39
|
+
export const ADMIN_LIST_STATES = ['brain', 'private', 'all'] as const;
|
|
40
|
+
export type AdminListState = (typeof ADMIN_LIST_STATES)[number];
|
|
41
|
+
|
|
42
|
+
export function adminListStateOf(v: unknown): AdminListState {
|
|
43
|
+
return typeof v === 'string' && (ADMIN_LIST_STATES as readonly string[]).includes(v)
|
|
44
|
+
? (v as AdminListState)
|
|
45
|
+
: 'brain';
|
|
46
|
+
}
|