@crossworks/client-types 0.239.30 → 0.239.32

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.239.30",
3
+ "version": "0.239.32",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Inbound API keys on the wire (migration 0232, plan page 1e62e204): the
3
+ * Settings > API access screen, and the public API v1 answers about keys.
4
+ *
5
+ * A key acts as the ONE login that made it (admin, member or client) and
6
+ * can only narrow it: `access` (read or read_write) and `areas` (null = every area). It is
7
+ * a Bearer on /api/v1/* and /api/mcp, nowhere else. The secret is in the
8
+ * create answer once; no other answer carries it or its hash.
9
+ *
10
+ * The runtime list of areas is this subpath's `ACCESS_KEY_AREAS`
11
+ * (`@crossworks/client-types/dto/access-keys`); the brain pins it to its
12
+ * own list in a test.
13
+ */
14
+
15
+ /** The parts of the brain a key can be limited to. */
16
+ export const ACCESS_KEY_AREAS = [
17
+ 'search',
18
+ 'pages',
19
+ 'notes',
20
+ 'tasks',
21
+ 'tables',
22
+ 'files',
23
+ 'calendar',
24
+ 'contacts',
25
+ 'journal',
26
+ 'apps',
27
+ ] as const;
28
+ export type AccessKeyArea = (typeof ACCESS_KEY_AREAS)[number];
29
+
30
+ export type AccessKeyAccess = 'read' | 'read_write';
31
+
32
+ export type AccessKeyRole = 'admin' | 'member' | 'client';
33
+
34
+ export type AccessKeyStatus = 'active' | 'expired' | 'revoked';
35
+
36
+ /** One key in GET /api/access-keys. Never the secret, never its hash. */
37
+ export type AccessKeyView = {
38
+ id: string;
39
+ name: string;
40
+ /** `mtlk_<prefix>`: tells keys apart, useless without the rest. */
41
+ prefix: string;
42
+ /** The login the key acts as. */
43
+ login: { id: string; email: string | null; displayName: string | null; role: AccessKeyRole };
44
+ access: AccessKeyAccess;
45
+ /** null = every area. */
46
+ areas: AccessKeyArea[] | null;
47
+ /** An admin key on /api/mcp: risky tools allowed by name. */
48
+ riskyTools: string[];
49
+ status: AccessKeyStatus;
50
+ /** ISO time; null = never expires. */
51
+ expiresAt: string | null;
52
+ createdAt: string;
53
+ createdBy: { id: string; email: string | null } | null;
54
+ lastUsedAt: string | null;
55
+ lastUsedIp: string | null;
56
+ revokedAt: string | null;
57
+ };
58
+
59
+ /** GET /api/access-keys. A member or client gets their own keys; an
60
+ * admin gets every key on the brain. */
61
+ export type AccessKeyList = {
62
+ keys: AccessKeyView[];
63
+ /** The caller's role: an admin may name risky tools, and sees every key. */
64
+ role: AccessKeyRole;
65
+ areas: AccessKeyArea[];
66
+ /** The expiry a key gets when the create names none. */
67
+ defaultExpiryDays: number;
68
+ /** The longest expiry the caller may pick, in days; null = any, "never"
69
+ * included (an admin). A member's keys last at most 90 days, a client's
70
+ * 30. */
71
+ maxExpiryDays: number | null;
72
+ /** Whether the create needs the caller's password (an admin or member;
73
+ * a client has none). */
74
+ needsPassword: boolean;
75
+ };
76
+
77
+ /** POST /api/access-keys body. The key acts as the caller's own login:
78
+ * nobody can make a key that acts as another login. */
79
+ export type AccessKeyCreateInput = {
80
+ name: string;
81
+ access: AccessKeyAccess;
82
+ /** null = every area; else at least one. */
83
+ areas: AccessKeyArea[] | null;
84
+ /** Omitted = the default (90); null = never; else 1 to 3650 days. */
85
+ expiresInDays?: number | null;
86
+ /** Only for an admin's own key. */
87
+ riskyTools?: string[];
88
+ /** The caller's password, when `needsPassword` (never stored, never
89
+ * logged). */
90
+ password?: string;
91
+ };
92
+
93
+ /** POST /api/access-keys answer (201). `secret` is shown ONCE. */
94
+ export type AccessKeyCreated = {
95
+ id: string;
96
+ prefix: string;
97
+ secret: string;
98
+ expiresAt: string | null;
99
+ };
100
+
101
+ /** The `reason` of a 403 a key gets outside its scope on /api/v1. */
102
+ export type AccessKeyScopeRefusal = 'key-area' | 'key-read-only';
103
+
104
+ /** GET /api/v1/whoami. `key` is set when the caller is an API key. */
105
+ export type ApiV1Whoami = {
106
+ role: AccessKeyRole;
107
+ loginId: string;
108
+ email: string;
109
+ displayName: string | null;
110
+ key: {
111
+ id: string;
112
+ prefix: string;
113
+ name: string;
114
+ access: AccessKeyAccess;
115
+ areas: AccessKeyArea[] | null;
116
+ } | null;
117
+ };
package/src/index.ts CHANGED
@@ -127,6 +127,20 @@ export type {
127
127
  LoginRefusedReason,
128
128
  PasswordResetRefused,
129
129
  } from './dto/logins';
130
+ // Inbound API keys (0232). Types at the root; the runtime ACCESS_KEY_AREAS
131
+ // is the `@mantle/client-types/dto/access-keys` subpath.
132
+ export type {
133
+ AccessKeyAccess,
134
+ AccessKeyArea,
135
+ AccessKeyCreateInput,
136
+ AccessKeyCreated,
137
+ AccessKeyList,
138
+ AccessKeyRole,
139
+ AccessKeyScopeRefusal,
140
+ AccessKeyStatus,
141
+ AccessKeyView,
142
+ ApiV1Whoami,
143
+ } from './dto/access-keys';
130
144
  export type {
131
145
  ClientAdminRefusedReason,
132
146
  ClientChatMessage,