@crossworks/client-types 0.232.338 → 0.232.343

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crossworks/client-types",
3
- "version": "0.232.338",
3
+ "version": "0.232.343",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
package/src/dto/client.ts CHANGED
@@ -5,7 +5,9 @@
5
5
  * client level only (the brain enforces it with row security). Client DTOs
6
6
  * never carry a staff name or an author: clients see the brand name.
7
7
  */
8
- import type { MemberItemKind } from '../member-kinds';
8
+ import type { ClientItemKind, MemberItemKind } from '../member-kinds';
9
+ import type { MemberItemPill, MemberSpaceItemRow } from './member';
10
+ import type { NodeComment } from './rows';
9
11
 
10
12
  /** GET /api/client/shell: who is signed in and the brain's brand. */
11
13
  export type ClientShell = {
@@ -265,3 +267,182 @@ export type ClientChatUsage = {
265
267
  limits: { dailyTurns: number; dailyTokens: number };
266
268
  rows: { loginId: string; turnsToday: number; tokensToday: number }[];
267
269
  };
270
+
271
+ // ── The client's own items, My requests (client logins C5) ─────────────────
272
+
273
+ /**
274
+ * Where a row of My requests comes from: `own` an item in the client's own
275
+ * space (GET /api/client/space/:id; a draft, submitted, returned, or with a
276
+ * reviewer who took it over), `accepted` the version the client wrote and an
277
+ * admin accepted (GET /api/client/accepted/:id).
278
+ */
279
+ export type ClientItemSource = 'own' | 'accepted';
280
+
281
+ /** One row of GET /api/client/items. No level, no staff name. */
282
+ export type ClientItemRow = {
283
+ id: string;
284
+ type: ClientItemKind;
285
+ title: string;
286
+ icon: string | null;
287
+ updatedAt: string;
288
+ source: ClientItemSource;
289
+ /** `private` a draft, `submitted`, `returned`, `with-admin`; null on an
290
+ * accepted row. Never `draft` (a client never shares with the team). */
291
+ pill: MemberItemPill | null;
292
+ /** The space row of an own item (review state, the returned note). */
293
+ space: MemberSpaceItemRow | null;
294
+ acceptedAt: string | null;
295
+ };
296
+
297
+ /** GET /api/client/items?kind=&q=&state=&page=: the client's own items and
298
+ * their accepted items in ONE list, newest first. `state` is a
299
+ * ClientItemFilter (default `all`). */
300
+ export type ClientItemsPage = {
301
+ items: ClientItemRow[];
302
+ total: number;
303
+ page: number;
304
+ pageSize: number;
305
+ };
306
+
307
+ /**
308
+ * The client's own space (/api/client/space*, /api/client/space-files): the
309
+ * member space routes' shapes (MemberSpaceItem, MemberSpaceItemRow,
310
+ * MemberSpaceList) for kinds page, note and file only. No share route: a
311
+ * client's item is private until submitted, and a submitted item goes to the
312
+ * reviewers (and members read it as a client request). Refusals (the 409
313
+ * `reason`): the member ones, plus `quota` for the client caps: 20 MB a file,
314
+ * 200 MB a client, 50 MB uploaded a day, 500 items, 10 submissions a day, 50
315
+ * waiting for review, and one total for all client spaces of the brain. The
316
+ * 200 MB and the total count page and note text too (C5 audit). A page
317
+ * document over 500 KB serialized (draft or Save version), or a note over
318
+ * 50,000 characters, is a 400 `too-large`. The comment caps:
319
+ * ClientCommentRefusedReason. Any JSON body over the route's ceiling (8 MB)
320
+ * is a 413 `body-too-large`.
321
+ */
322
+ export type ClientSpaceRefusedReason =
323
+ | 'not-found'
324
+ | 'frozen'
325
+ | 'not-draft'
326
+ | 'not-submitted'
327
+ | 'unsaved-draft'
328
+ | 'quota'
329
+ | 'embed'
330
+ | 'not-shared'
331
+ | 'too-large'
332
+ | 'invalid'
333
+ | 'with-admin';
334
+
335
+ /** GET /api/client/accepted/:id -> { item }: the version the client wrote
336
+ * and an admin accepted (the snapshot taken at Accept, never the brain's
337
+ * current version). A file's bytes: /api/client/files/:id while the brain
338
+ * file still holds the bytes accepted (`changedByAdmin` otherwise). */
339
+ export type ClientAcceptedItem =
340
+ | (ClientAcceptedBase & { type: 'page'; doc: unknown })
341
+ | (ClientAcceptedBase & { type: 'note'; content: string })
342
+ | (ClientAcceptedBase & {
343
+ type: 'file';
344
+ filename: string;
345
+ mimeType: string | null;
346
+ sizeBytes: number | null;
347
+ changedByAdmin?: boolean;
348
+ });
349
+
350
+ export type ClientAcceptedBase = {
351
+ id: string;
352
+ title: string;
353
+ icon: string | null;
354
+ acceptedAt: string | null;
355
+ updatedAt: string;
356
+ };
357
+
358
+ // ── Comments (client logins C5, decision 8) ─────────────────────────────────
359
+
360
+ /**
361
+ * GET /api/client/shared/:id/comments (POST { body } -> 201 { comment },
362
+ * DELETE /comments/:commentId for the client's own): the thread on an item
363
+ * shared with clients. The team, admins and every client login read and
364
+ * write it; each comment shows its author's display name (clients are
365
+ * approved users). Only on an item at client level: any other id is a 404.
366
+ *
367
+ * GET /api/client/space/:id/comments (POST, DELETE own) on the client's own
368
+ * item: the review talk with the reviewers, open while it is submitted. A
369
+ * reviewer's comment shows the brand name, never a staff name.
370
+ */
371
+ export type ClientCommentThread = {
372
+ comments: NodeComment[];
373
+ /**
374
+ * Older comments exist (client logins C5 audit): a thread answers its
375
+ * NEWEST 100 comments, oldest first; `?before=<createdAt of the oldest
376
+ * shown>` answers the 100 before them. The same paging and `hasMore` on
377
+ * GET /api/member/library/:id/comments, /api/member/space/:id/comments,
378
+ * /api/team-admin/submissions/:id/comments and /api/nodes/:id/comments.
379
+ * Absent on an older brain (the whole thread).
380
+ */
381
+ hasMore?: boolean;
382
+ };
383
+
384
+ /**
385
+ * Why a comment was refused (the 4xx `reason`, client logins C5 audit): 429
386
+ * `comment-cap` (a client login writes at most 100 comments a day across
387
+ * every thread, the review talk and client threads; deleting one does not
388
+ * give it back), 409 `thread-full` (one thread holds at most 1000
389
+ * comments).
390
+ */
391
+ export type ClientCommentRefusedReason = 'comment-cap' | 'thread-full';
392
+
393
+ // ── Team admin > Clients: storage and client threads (C5 audit) ────────────
394
+
395
+ /**
396
+ * GET /api/team-admin/clients/storage (admin only): what the client spaces
397
+ * hold against the client limits. A client space counts files, page
398
+ * documents (saved, draft and plain text) and note text, as stored.
399
+ * `limits.totalBytes` is the brain-wide total for ALL client spaces (5 GB
400
+ * unless the box sets MANTLE_CLIENT_SPACES_TOTAL_BYTES). A `former` row is a
401
+ * deleted client's space: it still counts until its 30-day purge, and its
402
+ * `loginId` is the space's id (the login row is gone).
403
+ */
404
+ export type ClientStorageUsage = {
405
+ limits: {
406
+ fileMaxBytes: number;
407
+ perClientBytes: number;
408
+ dailyUploadBytes: number;
409
+ itemLimit: number;
410
+ totalBytes: number;
411
+ submitsPerDay: number;
412
+ openSubmissions: number;
413
+ };
414
+ totalUsedBytes: number;
415
+ rows: {
416
+ loginId: string;
417
+ name: string;
418
+ usedBytes: number;
419
+ uploadedTodayBytes: number;
420
+ items: number;
421
+ openSubmissions: number;
422
+ former: boolean;
423
+ }[];
424
+ /** Quota refusals in the last 7 days, newest first, at most 50. */
425
+ refusals: { at: string; loginId: string | null; reason: string }[];
426
+ };
427
+
428
+ /**
429
+ * GET /api/team-admin/clients/comments?days=7 (admin only, 1 to 90 days):
430
+ * the client-level items whose client thread had a comment by a CLIENT in
431
+ * the window, newest first, at most 100. `clientComments` counts the
432
+ * clients' comments in the window; `lastClientName` is the newest one's
433
+ * author. Open the thread on /api/nodes/:id/comments.
434
+ */
435
+ export type ClientThreadActivity = {
436
+ rows: {
437
+ nodeId: string;
438
+ title: string;
439
+ type: string;
440
+ lastCommentAt: string;
441
+ clientComments: number;
442
+ lastClientName: string;
443
+ }[];
444
+ };
445
+
446
+ /** DELETE /api/team-admin/clients/:id/comments (admin only): every comment
447
+ * that client login wrote (client threads and review talk) is removed. */
448
+ export type ClientCommentsDeleted = { deleted: number };
package/src/dto/member.ts CHANGED
@@ -256,8 +256,11 @@ export type MemberAcceptedItem =
256
256
  /** Where a row of the one list comes from; it picks the item view that
257
257
  * opens it: `own` the member's editor, `team` a teammate's saved draft,
258
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';
259
+ * admin accepted at a level above the Library's (admin or public),
260
+ * `client-request` a client's SUBMITTED item (client logins C5, decision
261
+ * 5 B), read only from /api/member/client-requests/:id; its `space` row
262
+ * carries the review state, its `author` the client (role `client`). */
263
+ export type MemberItemSource = 'own' | 'team' | 'library' | 'accepted' | 'client-request';
261
264
 
262
265
  /** The small state pill a row wears beside its actions. Brain items (the
263
266
  * Library and accepted rows) wear none. */
@@ -284,6 +287,14 @@ export type MemberItemRow = {
284
287
  space: MemberSpaceItemRow | null;
285
288
  };
286
289
 
290
+ /** GET /api/member/client-requests/:id (client logins C5, decision 5 B): a
291
+ * client's SUBMITTED item, read only, with its author (the client). File
292
+ * bytes: /api/member/client-requests/:id/bytes. */
293
+ export type MemberClientRequestItem<TDoc = unknown, TTable = unknown> = MemberSpaceItem<
294
+ TDoc,
295
+ TTable
296
+ > & { author: MemberItemAuthor };
297
+
287
298
  /**
288
299
  * GET /api/member/items?kind=&q=&state=&page= (brains from the item-list
289
300
  * alignment release): the member's own items, teammates' shared drafts, the
package/src/dto/rows.ts CHANGED
@@ -50,7 +50,7 @@ export type TaskTodo = {
50
50
  };
51
51
 
52
52
  /** Mirrors @mantle/db `NodeCommentAuthorKind`. */
53
- export type NodeCommentAuthorKind = 'owner' | 'member' | 'agent';
53
+ export type NodeCommentAuthorKind = 'owner' | 'member' | 'agent' | 'client';
54
54
 
55
55
  /**
56
56
  * A comment on a node (tasks first; the table is node-generic). `authorName`
package/src/index.ts CHANGED
@@ -86,6 +86,7 @@ export type {
86
86
  MemberSpaceItem,
87
87
  MemberSpaceItemBody,
88
88
  MemberSpaceItemRow,
89
+ MemberClientRequestItem,
89
90
  MemberSpaceItemState,
90
91
  MemberSpaceList,
91
92
  MemberSpaceSharing,
@@ -109,7 +110,7 @@ export type {
109
110
  MemberInviteRow,
110
111
  MemberInviteState,
111
112
  } from './dto/member-invites';
112
- export type { MemberItemKind } from './member-kinds';
113
+ export type { MemberItemKind, ClientItemKind, ClientItemFilter } from './member-kinds';
113
114
  export type {
114
115
  LoginKind,
115
116
  LoginRefused,
@@ -143,6 +144,17 @@ export type {
143
144
  ClientShell,
144
145
  ClientSigninLinkCreated,
145
146
  ClientSigninLinkRow,
147
+ ClientItemSource,
148
+ ClientItemRow,
149
+ ClientItemsPage,
150
+ ClientSpaceRefusedReason,
151
+ ClientAcceptedItem,
152
+ ClientAcceptedBase,
153
+ ClientCommentThread,
154
+ ClientCommentRefusedReason,
155
+ ClientStorageUsage,
156
+ ClientThreadActivity,
157
+ ClientCommentsDeleted,
146
158
  } from './dto/client';
147
159
 
148
160
  // Types only at the root; the runtime constants (APP_TINTS, limits) are the
@@ -25,6 +25,8 @@ export const MEMBER_ITEM_FILTERS = [
25
25
  'with-admin',
26
26
  'brain',
27
27
  'by-me',
28
+ // A client's submitted items (client logins C5, decision 5 B): read only.
29
+ 'client-requests',
28
30
  ] as const;
29
31
  export type MemberItemFilter = (typeof MEMBER_ITEM_FILTERS)[number];
30
32
 
@@ -44,3 +46,30 @@ export function adminListStateOf(v: unknown): AdminListState {
44
46
  ? (v as AdminListState)
45
47
  : 'brain';
46
48
  }
49
+
50
+ /** The kinds a CLIENT works with in their own space (client logins C5, plan
51
+ * section 6): pages and notes they write, files they upload. */
52
+ export const CLIENT_ITEM_KINDS = ['page', 'note', 'file'] as const;
53
+ export type ClientItemKind = (typeof CLIENT_ITEM_KINDS)[number];
54
+
55
+ export function isClientItemKind(v: unknown): v is ClientItemKind {
56
+ return typeof v === 'string' && (CLIENT_ITEM_KINDS as readonly string[]).includes(v);
57
+ }
58
+
59
+ /** The State filter of a client's one list, My requests (GET
60
+ * /api/client/items?state=): `all`, one row pill (`private` a draft,
61
+ * `submitted`, `returned`, `with-admin` an item a reviewer took over to
62
+ * work on), or `accepted`. */
63
+ export const CLIENT_ITEM_FILTERS = [
64
+ 'all',
65
+ 'private',
66
+ 'submitted',
67
+ 'returned',
68
+ 'with-admin',
69
+ 'accepted',
70
+ ] as const;
71
+ export type ClientItemFilter = (typeof CLIENT_ITEM_FILTERS)[number];
72
+
73
+ export function isClientItemFilter(v: unknown): v is ClientItemFilter {
74
+ return typeof v === 'string' && (CLIENT_ITEM_FILTERS as readonly string[]).includes(v);
75
+ }