@pingroom/sdk 0.8.0 → 0.9.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.
Files changed (179) hide show
  1. package/README.md +153 -41
  2. package/dist/client.d.ts +14 -348
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +15 -1300
  5. package/dist/client.js.map +1 -1
  6. package/dist/errors.d.ts +32 -3
  7. package/dist/errors.d.ts.map +1 -1
  8. package/dist/errors.js +47 -1
  9. package/dist/errors.js.map +1 -1
  10. package/dist/http.d.ts.map +1 -1
  11. package/dist/http.js +7 -1
  12. package/dist/http.js.map +1 -1
  13. package/dist/index.d.ts +3 -5
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +1 -2
  16. package/dist/index.js.map +1 -1
  17. package/dist/internal/guards.d.ts +7 -0
  18. package/dist/internal/guards.d.ts.map +1 -1
  19. package/dist/internal/guards.js +1 -1
  20. package/dist/internal/guards.js.map +1 -1
  21. package/dist/internal/request.d.ts +41 -0
  22. package/dist/internal/request.d.ts.map +1 -0
  23. package/dist/internal/request.js +78 -0
  24. package/dist/internal/request.js.map +1 -0
  25. package/dist/internal/retry.d.ts +9 -2
  26. package/dist/internal/retry.d.ts.map +1 -1
  27. package/dist/internal/retry.js +24 -6
  28. package/dist/internal/retry.js.map +1 -1
  29. package/dist/internal/validate.d.ts +13 -0
  30. package/dist/internal/validate.d.ts.map +1 -0
  31. package/dist/internal/validate.js +36 -0
  32. package/dist/internal/validate.js.map +1 -0
  33. package/dist/liveStatus.d.ts +106 -11
  34. package/dist/liveStatus.d.ts.map +1 -1
  35. package/dist/liveStatus.js +20 -3
  36. package/dist/liveStatus.js.map +1 -1
  37. package/dist/mcp.d.ts.map +1 -1
  38. package/dist/mcp.js +30 -8
  39. package/dist/mcp.js.map +1 -1
  40. package/dist/namespaces/actions.d.ts +50 -0
  41. package/dist/namespaces/actions.d.ts.map +1 -0
  42. package/dist/namespaces/actions.js +219 -0
  43. package/dist/namespaces/actions.js.map +1 -0
  44. package/dist/namespaces/approvals.d.ts +23 -0
  45. package/dist/namespaces/approvals.d.ts.map +1 -0
  46. package/dist/namespaces/approvals.js +78 -0
  47. package/dist/namespaces/approvals.js.map +1 -0
  48. package/dist/namespaces/attachments.d.ts +37 -0
  49. package/dist/namespaces/attachments.d.ts.map +1 -0
  50. package/dist/namespaces/attachments.js +91 -0
  51. package/dist/namespaces/attachments.js.map +1 -0
  52. package/dist/namespaces/auth.d.ts +58 -0
  53. package/dist/namespaces/auth.d.ts.map +1 -0
  54. package/dist/namespaces/auth.js +242 -0
  55. package/dist/namespaces/auth.js.map +1 -0
  56. package/dist/namespaces/directory.d.ts +10 -0
  57. package/dist/namespaces/directory.d.ts.map +1 -0
  58. package/dist/namespaces/directory.js +19 -0
  59. package/dist/namespaces/directory.js.map +1 -0
  60. package/dist/namespaces/handoffs.d.ts +47 -0
  61. package/dist/namespaces/handoffs.d.ts.map +1 -0
  62. package/dist/namespaces/handoffs.js +126 -0
  63. package/dist/namespaces/handoffs.js.map +1 -0
  64. package/dist/namespaces/inbox.d.ts +17 -0
  65. package/dist/namespaces/inbox.d.ts.map +1 -0
  66. package/dist/namespaces/inbox.js +192 -0
  67. package/dist/namespaces/inbox.js.map +1 -0
  68. package/dist/namespaces/live.d.ts +57 -0
  69. package/dist/namespaces/live.d.ts.map +1 -0
  70. package/dist/namespaces/live.js +116 -0
  71. package/dist/namespaces/live.js.map +1 -0
  72. package/dist/namespaces/notifications.d.ts +25 -0
  73. package/dist/namespaces/notifications.d.ts.map +1 -0
  74. package/dist/namespaces/notifications.js +128 -0
  75. package/dist/namespaces/notifications.js.map +1 -0
  76. package/dist/namespaces/profile.d.ts +19 -0
  77. package/dist/namespaces/profile.d.ts.map +1 -0
  78. package/dist/namespaces/profile.js +22 -0
  79. package/dist/namespaces/profile.js.map +1 -0
  80. package/dist/namespaces/questions.d.ts +41 -0
  81. package/dist/namespaces/questions.d.ts.map +1 -0
  82. package/dist/namespaces/questions.js +107 -0
  83. package/dist/namespaces/questions.js.map +1 -0
  84. package/dist/namespaces/rooms.d.ts +13 -0
  85. package/dist/namespaces/rooms.d.ts.map +1 -0
  86. package/dist/namespaces/rooms.js +41 -0
  87. package/dist/namespaces/rooms.js.map +1 -0
  88. package/dist/namespaces/webhooks.d.ts +11 -0
  89. package/dist/namespaces/webhooks.d.ts.map +1 -0
  90. package/dist/namespaces/webhooks.js +32 -0
  91. package/dist/namespaces/webhooks.js.map +1 -0
  92. package/dist/types/approvals.d.ts +62 -0
  93. package/dist/types/approvals.d.ts.map +1 -0
  94. package/dist/types/approvals.js +2 -0
  95. package/dist/types/approvals.js.map +1 -0
  96. package/dist/types/auth.d.ts +185 -0
  97. package/dist/types/auth.d.ts.map +1 -0
  98. package/dist/types/auth.js +2 -0
  99. package/dist/types/auth.js.map +1 -0
  100. package/dist/types/common.d.ts +43 -0
  101. package/dist/types/common.d.ts.map +1 -0
  102. package/dist/types/common.js +2 -0
  103. package/dist/types/common.js.map +1 -0
  104. package/dist/types/handoffs.d.ts +121 -0
  105. package/dist/types/handoffs.d.ts.map +1 -0
  106. package/dist/types/handoffs.js +2 -0
  107. package/dist/types/handoffs.js.map +1 -0
  108. package/dist/types/inbox.d.ts +51 -0
  109. package/dist/types/inbox.d.ts.map +1 -0
  110. package/dist/types/inbox.js +2 -0
  111. package/dist/types/inbox.js.map +1 -0
  112. package/dist/types/notifications.d.ts +376 -0
  113. package/dist/types/notifications.d.ts.map +1 -0
  114. package/dist/types/notifications.js +2 -0
  115. package/dist/types/notifications.js.map +1 -0
  116. package/dist/types/profile.d.ts +30 -0
  117. package/dist/types/profile.d.ts.map +1 -0
  118. package/dist/types/profile.js +3 -0
  119. package/dist/types/profile.js.map +1 -0
  120. package/dist/types/questions.d.ts +210 -0
  121. package/dist/types/questions.d.ts.map +1 -0
  122. package/dist/types/questions.js +2 -0
  123. package/dist/types/questions.js.map +1 -0
  124. package/dist/types/rooms.d.ts +163 -0
  125. package/dist/types/rooms.d.ts.map +1 -0
  126. package/dist/types/rooms.js +3 -0
  127. package/dist/types/rooms.js.map +1 -0
  128. package/dist/types.d.ts +9 -1199
  129. package/dist/types.d.ts.map +1 -1
  130. package/dist/version.d.ts +1 -1
  131. package/dist/version.js +1 -1
  132. package/dist/webhooks.d.ts +14 -4
  133. package/dist/webhooks.d.ts.map +1 -1
  134. package/dist/webhooks.js +30 -5
  135. package/dist/webhooks.js.map +1 -1
  136. package/package.json +4 -2
  137. package/src/client.ts +115 -0
  138. package/src/errors.ts +291 -0
  139. package/src/http.ts +225 -0
  140. package/src/index.ts +97 -0
  141. package/src/internal/async.ts +54 -0
  142. package/src/internal/guards.ts +129 -0
  143. package/src/internal/request.ts +97 -0
  144. package/src/internal/retry.ts +157 -0
  145. package/src/internal/url.ts +78 -0
  146. package/src/internal/validate.ts +42 -0
  147. package/src/linkPing.ts +56 -0
  148. package/src/liveStatus.ts +337 -0
  149. package/src/locationPing.ts +101 -0
  150. package/src/mcp.ts +161 -0
  151. package/src/namespaces/actions.ts +234 -0
  152. package/src/namespaces/approvals.ts +104 -0
  153. package/src/namespaces/attachments.ts +106 -0
  154. package/src/namespaces/auth.ts +284 -0
  155. package/src/namespaces/directory.ts +21 -0
  156. package/src/namespaces/handoffs.ts +160 -0
  157. package/src/namespaces/inbox.ts +253 -0
  158. package/src/namespaces/live.ts +134 -0
  159. package/src/namespaces/notifications.ts +152 -0
  160. package/src/namespaces/profile.ts +24 -0
  161. package/src/namespaces/questions.ts +133 -0
  162. package/src/namespaces/rooms.ts +53 -0
  163. package/src/namespaces/webhooks.ts +38 -0
  164. package/src/types/approvals.ts +67 -0
  165. package/src/types/auth.ts +202 -0
  166. package/src/types/common.ts +74 -0
  167. package/src/types/handoffs.ts +148 -0
  168. package/src/types/inbox.ts +64 -0
  169. package/src/types/notifications.ts +393 -0
  170. package/src/types/profile.ts +37 -0
  171. package/src/types/questions.ts +226 -0
  172. package/src/types/rooms.ts +169 -0
  173. package/src/types.ts +17 -0
  174. package/src/version.ts +2 -0
  175. package/src/webhooks.ts +373 -0
  176. package/dist/liveActivity.d.ts +0 -101
  177. package/dist/liveActivity.d.ts.map +0 -1
  178. package/dist/liveActivity.js +0 -83
  179. package/dist/liveActivity.js.map +0 -1
package/dist/types.d.ts CHANGED
@@ -5,1203 +5,13 @@
5
5
  * SDK is a faithful, reviewable wrapper — what you pass is what the API sees.
6
6
  * SDK-only knobs (timeouts, signals, callbacks) use camelCase.
7
7
  */
8
- import type { PingRoomError } from './errors.js';
9
- /** A plain JSON object — the shape the API accepts for structured `data`. */
10
- export type JsonObject = Record<string, unknown>;
11
- /** Minimal fetch signature the SDK depends on (Node >= 18, browsers, workers, Deno, Bun). */
12
- export type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
13
- /** The scopes an agent credential can hold. */
14
- export type AgentScope = 'pingroom:full' | 'pingroom:rooms:read' | 'pingroom:rooms:write' | 'pingroom:rooms:publish' | 'pingroom:rooms:join' | 'pingroom:actions:write' | 'pingroom:actions:trigger' | 'pingroom:broadcast:send' | 'pingroom:attachments:write' | 'pingroom:notifications:read' | 'pingroom:webhooks:read' | 'pingroom:webhooks:write' | 'pingroom:webhooks:delete' | 'pingroom:agents:ping' | 'pingroom:approvals:request' | 'pingroom:questions:ask' | 'pingroom:handoffs:create' | 'pingroom:live:write' | 'pingroom:profile:write' | 'pingroom:codes:redeem';
15
- /** A known scope, or any forward-compatible string (keeps autocomplete on the knowns). */
16
- export type ScopeInput = AgentScope | (string & {});
17
- export interface PingRoomOptions {
18
- /** Agent credential (Bearer JWT). Optional — public reads (directory) work without it. */
19
- token?: string | null;
20
- /** API base URL. Defaults to env PINGROOM_API_URL/PINGROOM_BASE_URL, else https://api.pingroom.io. */
21
- baseUrl?: string;
22
- /** Default per-request timeout in ms (long-poll calls extend this automatically). Default 30000. */
23
- timeoutMs?: number;
24
- /** Custom fetch implementation (for tests or non-global-fetch runtimes). */
25
- fetch?: FetchLike;
26
- /** Override the User-Agent header. */
27
- userAgent?: string;
28
- /** Allow plain-http base URLs to non-loopback hosts. Off by default — credentials require https. */
29
- allowInsecure?: boolean;
30
- }
31
- /** Pro entitlement applied to the human who authorized this agent. */
32
- export interface RedeemCodeResult {
33
- message: string;
34
- kind: 'gift' | 'redeem';
35
- reward_days: number | null;
36
- package: string | null;
37
- lifetime: boolean;
38
- plan: 'pro';
39
- plan_expires_at: string | null;
40
- }
41
- export type AgentRegisterType = 'identity_assertion' | 'anonymous';
42
- export type AgentAssertionType = 'urn:ietf:params:oauth:token-type:id-jag' | 'verified_email';
43
- export interface RegisterParams {
44
- type: AgentRegisterType;
45
- assertion_type?: AgentAssertionType;
46
- assertion?: string;
47
- scopes?: ScopeInput[];
48
- agent_label?: string;
49
- }
50
- /**
51
- * How wide the human made this agent's room grant.
52
- *
53
- * `'all'` — every room the account is in; the grant lists none, while `room`
54
- * may identify one eligible private delivery destination. `'selected'` —
55
- * exactly the rooms in `rooms`.
56
- */
57
- export type AgentRoomAccess = 'all' | 'selected';
58
- /** One room inside an agent's grant. */
59
- export interface AgentAccessRoom {
60
- id: string;
61
- invite_code: string;
62
- name: string;
63
- }
64
- /** The delivery room: where handoffs and questions land. */
65
- export interface AgentDeliveryRoom {
66
- invite_code: string;
67
- name?: string | null;
68
- }
69
- /** Stable, non-credential URLs returned with an approved agent connection. */
70
- export interface AgentCredentialLinks {
71
- /** REST endpoint for the agent's latest visible pings. Authenticate normally. */
72
- latest_pings: string;
73
- /** Token-free smart link for installing PingRoom on iOS or Android. */
74
- install_app?: string;
75
- }
76
- /** Public robot identity provisioned before a person approves pairing. */
77
- export interface AgentProfile {
78
- display_name: string | null;
79
- handle: string | null;
80
- avatar_id: string | null;
81
- avatar_url: string | null;
82
- }
83
- /** Agent wrapper used by pairing v2. Older servers omit it entirely. */
84
- export interface PairingAgent {
85
- id?: string;
86
- label?: string | null;
87
- handle?: string | null;
88
- profile?: AgentProfile;
89
- }
90
- /** Human who claimed the robot. Present only after approval. */
91
- export interface PairingOwner {
92
- name: string | null;
93
- }
94
- /** Visible home-room membership, distinct from the wider room-access grant. */
95
- export interface AgentRoomMembership {
96
- status: 'active' | 'removed';
97
- joined_at: string | null;
98
- removed_at: string | null;
99
- /** True for the robot's home room. Sent by `auth.connection()`. */
100
- is_home?: boolean;
101
- room: AgentDeliveryRoom | null;
102
- }
103
- /** Additive pairing-v2 identity metadata; every field is optional for old servers. */
104
- export interface PairingIdentityMetadata {
105
- flow_version?: 2;
106
- claim_mode?: 'agent_identity';
107
- agent?: PairingAgent;
108
- owner?: PairingOwner;
109
- /** Alias of legacy `room`: the robot's Question/Handoff delivery room. */
110
- home_room?: AgentDeliveryRoom | null;
111
- room_membership?: AgentRoomMembership | null;
112
- }
113
- export interface Credential extends PairingIdentityMetadata {
114
- credential: string;
115
- credential_type: 'pre_claim' | 'active';
116
- expires_in: number | null;
117
- scopes: string[];
118
- handle?: string;
119
- claim?: {
120
- start_uri: string;
121
- complete_uri: string;
122
- };
123
- account?: {
124
- name?: string | null;
125
- } | null;
126
- /** The delivery room, or null when the human pinned none. */
127
- room?: AgentDeliveryRoom | null;
128
- room_access?: AgentRoomAccess | null;
129
- /** The full grant. Empty under `room_access: 'all'`. */
130
- rooms?: AgentAccessRoom[];
131
- /** Server-authoritative endpoints associated with this connection. */
132
- links?: AgentCredentialLinks;
133
- }
134
- /** The human a connection belongs to, as `auth.connection()` and `auth.disconnect()` report it. */
135
- export interface AgentConnectionOwner {
136
- /** Public user id. Match it to the account you approved before sending. */
137
- id: string;
138
- name: string;
139
- }
140
- /** `auth.connection()`: what this credential is connected to. */
141
- export interface AgentConnectionInfo {
142
- flow_version: 2;
143
- claim_mode: 'agent_identity';
144
- status: 'active';
145
- handle: string | null;
146
- agent: PairingAgent;
147
- owner: AgentConnectionOwner;
148
- /** The robot's Question/Handoff delivery room, or null when none is designated. */
149
- home_room: AgentAccessRoom | null;
150
- /** The robot's membership of its home room. */
151
- room_membership: AgentRoomMembership | null;
152
- /** Every active room membership, home room first. */
153
- room_memberships: AgentRoomMembership[];
154
- room_access: AgentRoomAccess | null;
155
- links: AgentCredentialLinks;
156
- [key: string]: unknown;
157
- }
158
- /** `auth.disconnect()`: the calling credential and its refresh credentials are revoked. */
159
- export interface AgentDisconnectResult {
160
- status: 'revoked';
161
- handle: string | null;
162
- owner: AgentConnectionOwner;
163
- /** Reconnect guidance for the human. */
164
- message: string;
165
- [key: string]: unknown;
166
- }
167
- export interface ClaimStartParams {
168
- email: string;
169
- }
170
- export interface ClaimCompleteParams {
171
- email: string;
172
- otp: string;
173
- scopes?: ScopeInput[];
174
- }
175
- /** Start an app-approved pairing without copying an API token or room code. */
176
- export interface StartPairingParams {
177
- /**
178
- * @deprecated Pairing grants are server-authoritative. This value is ignored
179
- * and retained only so existing TypeScript callers continue to compile.
180
- */
181
- scopes?: ScopeInput[];
182
- agent_label?: string;
183
- }
184
- /** Short-lived browser and native-app links returned when pairing starts. */
185
- export interface PairingStart extends PairingIdentityMetadata {
186
- pair_token: string;
187
- /** Legacy approval link, kept QR-compatible for existing clients. */
188
- pair_url: string;
189
- /** Browser approval page. Fall back to `pair_url` on older servers. */
190
- pair_browser_url?: string;
191
- /** Native app universal link for QR renderers. Falls back to `pair_url` on older servers. */
192
- pair_qr_url?: string;
193
- /** Token-free smart install link. Never append `pair_token` to it. */
194
- app_install_url?: string;
195
- expires_in: number;
196
- poll_interval_ms: number;
197
- }
198
- export type PairedCredential = Omit<Credential, 'credential_type' | 'scopes'> & {
199
- credential_type: 'active';
200
- /**
201
- * The selected/deterministic private delivery room. Null remains valid when
202
- * the account has no eligible private room (and for older servers).
203
- */
204
- room: AgentDeliveryRoom | null;
205
- room_access: AgentRoomAccess;
206
- /** The full grant. Empty under `room_access: 'all'`. */
207
- rooms: AgentAccessRoom[];
208
- };
209
- export type PairingStatus = (PairingIdentityMetadata & {
210
- status: 'pending';
211
- }) | (PairingIdentityMetadata & {
212
- status: 'expired';
213
- }) | (PairedCredential & {
214
- status: 'active';
215
- /** Legacy server metadata accepted on input and omitted from the result. */
216
- scopes?: string[];
217
- });
218
- export interface WaitForPairingOptions {
219
- /** Stop waiting without consuming the pairing session. */
220
- signal?: AbortSignal;
221
- /** Override the server-suggested polling interval (clamped to 1–10 seconds). */
222
- pollIntervalMs?: number;
223
- }
224
- /**
225
- * The detail every press of a quick action must carry. `location` needs
226
- * `data.location`, `link` needs `data.url`, `file`/`photo`/`pdf` need
227
- * `attachment_ids` (photo: jpg/png only, pdf: pdf only). A press without it is
228
- * refused with `422 quick_action_input_required` and nothing is sent.
229
- */
230
- export type QuickActionInputType = 'none' | 'location' | 'link' | 'file' | 'photo' | 'pdf';
231
- export interface QuickActionInput {
232
- action_number: number;
233
- label: string;
234
- /**
235
- * Emoji or icon id. Sending `label` and `icon` both empty reserves the slot
236
- * as disabled: it stays in the layout and a press answers `404
237
- * action_not_configured`.
238
- */
239
- icon: string;
240
- sound?: string | null;
241
- haptic_style?: string | null;
242
- /** Every fire of this reusable action opens the acknowledgement lifecycle. */
243
- requires_ack?: boolean;
244
- /** Omit to keep the stored value; new slots default to `none`. */
245
- input_type?: QuickActionInputType;
246
- }
247
- /**
248
- * Body of `actions.updateLayout()`. `page_order` lists the new page positions:
249
- * each entry is the ORIGINAL page number (1–4) to keep at that index, or
250
- * `null` for a fresh blank page; original pages absent from the list are
251
- * deleted. `actions` is the full renumbered 4–16 set. `base_action_ids` is
252
- * every stored action id in `action_number` order as last read — a stale
253
- * snapshot is refused with `409 quick_action_layout_changed`.
254
- */
255
- export interface UpdateQuickActionLayoutInput {
256
- base_action_ids: string[];
257
- page_order: Array<number | null>;
258
- actions: QuickActionInput[];
259
- }
260
- export interface CreateRoomInput {
261
- name: string;
262
- icon: string;
263
- color: string;
264
- }
265
- export interface CreatePublicRoomInput extends CreateRoomInput {
266
- handle: string;
267
- description?: string;
268
- everyone_can_trigger?: boolean;
269
- is_password_protected?: boolean;
270
- password?: string;
271
- actions?: QuickActionInput[];
272
- category?: string;
273
- show_owner?: boolean;
274
- /**
275
- * Public-room location for nearby discovery. Send all three or none —
276
- * `createPublic()` rejects a partial trio locally, the server with a 422.
277
- */
278
- location_name?: string;
279
- location_latitude?: number;
280
- location_longitude?: number;
281
- }
282
- export interface JoinRoomInput {
283
- invite_code: string;
284
- password?: string;
285
- }
286
- export interface UpdateQuickActionInput {
287
- /**
288
- * The Ping's title. Must be sent, but may be `''` — a Ping can be named by
289
- * its emoji alone, and the app renders an untitled one as just the emoji.
290
- */
291
- label: string;
292
- icon: string;
293
- sound?: string | null;
294
- haptic_style?: string | null;
295
- /** Every fire of this reusable action opens the acknowledgement lifecycle. */
296
- requires_ack?: boolean;
297
- /** Omit to keep the stored value. */
298
- input_type?: QuickActionInputType;
299
- }
300
- export interface QuickAction {
301
- id?: string;
302
- action_number: number;
303
- label: string;
304
- icon: string;
305
- sound?: string | null;
306
- haptic_style?: string | null;
307
- /** Every fire of this reusable action opens the acknowledgement lifecycle. */
308
- requires_ack?: boolean;
309
- /** Missing on pre-2026-09-16 rows; treat absent as `none`. */
310
- input_type?: QuickActionInputType;
311
- [key: string]: unknown;
312
- }
313
- export interface Room {
314
- id: string;
315
- name: string;
316
- icon: string | null;
317
- color: string | null;
318
- invite_code: string;
319
- is_public?: boolean;
320
- handle?: string | null;
321
- quick_actions?: QuickAction[];
322
- /** 4, or 16 while the room owner is Pro. */
323
- quick_action_limit?: 4 | 16;
324
- /** Every stored slot, including pages hidden by a lapsed Pro. */
325
- quick_action_count?: number;
326
- location_name?: string | null;
327
- location_latitude?: number | null;
328
- location_longitude?: number | null;
329
- [key: string]: unknown;
330
- }
331
- /** Catalog ids accepted by room and webhook creation. */
332
- export interface RoomIconCatalog {
333
- version: number;
334
- base_url: string;
335
- categories: Array<{
336
- id: string;
337
- label: string;
338
- icons: string[];
339
- }>;
340
- icons: Record<string, {
341
- file: string;
342
- tags: string[];
343
- }>;
344
- }
345
- export interface CreateWebhookInput {
346
- name: string;
347
- title?: string | null;
348
- message?: string | null;
349
- emoji?: string | null;
350
- icon?: string | null;
351
- color?: string | null;
352
- sound?: string | null;
353
- haptic?: string | null;
354
- /** Optional Quick Ping preset. Omit or use null for an independent webhook. */
355
- action_number?: number | null;
356
- enabled?: boolean;
357
- cooldown_seconds?: number;
358
- }
359
- export interface UpdateWebhookInput extends Partial<CreateWebhookInput> {
360
- /** Rotate the trigger URL; the previous URL stops working. */
361
- regenerate_secret?: boolean;
362
- }
363
- /** Incoming webhook configuration. The trigger URL contains its credential. */
364
- export interface Webhook {
365
- id: string;
366
- room_id: string;
367
- name: string;
368
- title: string | null;
369
- message: string | null;
370
- emoji: string | null;
371
- icon: string | null;
372
- color: string | null;
373
- sound: string | null;
374
- haptic: string | null;
375
- /** Null when the webhook uses its own content without a Quick Ping preset. */
376
- action_number: number | null;
377
- enabled: boolean;
378
- cooldown_seconds: number;
379
- trigger_count: number;
380
- last_triggered_at?: string | null;
381
- webhook_url: string;
382
- created_at: string;
383
- updated_at: string;
384
- [key: string]: unknown;
385
- }
386
- /** A visible Ping — used for broadcasts and the retired direct-ping compatibility method. */
387
- export interface PingInput {
388
- /** Visible body (≤ 120 characters in private rooms; ≤ 160 in public rooms). */
389
- message: string;
390
- /** Optional visible title (≤ 40 characters). */
391
- title?: string;
392
- action_number?: number;
393
- action_icon?: string;
394
- /**
395
- * Structured data echoed on every read surface (<= 25 keys / 8KB).
396
- * Reserved keys `url` + `button_label` make the ping a tappable link —
397
- * see the `linkPing()` helper. Reserved `location` carries finite numeric
398
- * latitude/longitude plus an optional label/address — see `locationPing()`.
399
- */
400
- data?: JsonObject;
401
- correlation_id?: string;
402
- reply_to?: string;
403
- /**
404
- * Ordered ids from `attachments.upload()` (max 4). Ids are single-use: the
405
- * send claims them, and an already-claimed or expired id fails the whole
406
- * ping. File bytes never ride this JSON body.
407
- */
408
- attachment_ids?: string[];
409
- /**
410
- * Open the acknowledgement lifecycle for this ping. The ack_mode rule
411
- * determines when it resolves, and recipients see a lock-screen card with an Acknowledge button.
412
- *
413
- * Does NOT raise the delivery priority — that is {@link PingInput.is_urgent},
414
- * and the two are independent. They were one flag, which meant asking for a
415
- * ping that cuts through Focus also demanded that somebody acknowledge it.
416
- */
417
- requires_ack?: boolean;
418
- /** Confirmation rule; defaults to any. all waits for every original eligible recipient. */
419
- ack_mode?: AckMode;
420
- /**
421
- * Deliver time-sensitive so the ping breaks through Focus / Do Not Disturb
422
- * and reaches members who muted the room or you (a block still wins).
423
- * Delivery priority only: no acknowledgement, no Live Activity, nothing asked
424
- * of the recipient. Set alongside `requires_ack` for an acknowledgement that
425
- * also cuts through Focus.
426
- */
427
- is_urgent?: boolean;
428
- /**
429
- * Optional acknowledgement deadline in seconds (60–86400). Omit/null for no
430
- * deadline. Validated on every send, so an out-of-range value is a 422 even
431
- * without `requires_ack`; it takes effect only when the ping requires
432
- * acknowledgement.
433
- */
434
- ack_timeout_seconds?: number | null;
435
- /**
436
- * Sent as the `Idempotency-Key` header (1–255 printable ASCII characters,
437
- * spaces allowed), never in the body.
438
- * Reuse the same key when retrying after a timeout or network error: the
439
- * server replays the first result instead of sending the ping again.
440
- */
441
- idempotencyKey?: string;
442
- }
443
- /**
444
- * Safe attachment metadata. Storage keys, checksums, owner ids, and permanent
445
- * URLs are deliberately not part of this contract — read the bytes through
446
- * `attachments.content()` with the credential that can see the ping.
447
- */
448
- export interface Attachment {
449
- id: string;
450
- filename: string;
451
- mime_type: string;
452
- size_bytes: number;
453
- created_at: string;
454
- }
455
- /** The file types the attachment endpoint accepts. */
456
- /** One row of a `.zip` attachment's listing. */
457
- export interface ZipManifestEntry {
458
- name: string;
459
- /** Null when the archive declared no size, or declared a ZIP64 sentinel. */
460
- size_bytes: number | null;
461
- is_directory: boolean;
462
- }
463
- /**
464
- * A `.zip` attachment's contents as recorded at upload. Bounded server-side, so
465
- * `entries` may be shorter than `total_entries`.
466
- */
467
- export interface ZipManifest {
468
- entries: ZipManifestEntry[];
469
- total_entries: number;
470
- truncated: boolean;
471
- /** Sum of the sizes the archive DECLARES. Nothing verifies or expands them. */
472
- total_uncompressed_bytes: number;
473
- }
474
- export type AttachmentExtension = 'md' | 'pdf' | 'html' | 'txt' | 'jpg' | 'jpeg' | 'png' | 'zip';
475
- export interface UploadAttachmentInput {
476
- /** File bytes (1 byte–5 MiB). A Blob/File, a Uint8Array, or a UTF-8 string. */
477
- content: Blob | Uint8Array | string;
478
- /** Display filename. Its extension must be one of AttachmentExtension. */
479
- filename: string;
480
- /** Overrides the type sent in the multipart part. Usually inferred is fine. */
481
- contentType?: string;
482
- signal?: AbortSignal;
483
- }
484
- export interface TriggerInput {
485
- /**
486
- * Only the sources a device legitimately originates. `webhook`/`system` are
487
- * stamped server-side and are rejected here.
488
- */
489
- trigger_source?: 'manual' | 'location';
490
- /**
491
- * Deliver this one press time-sensitive so it breaks through Focus / Do Not
492
- * Disturb and reaches members who muted the room or you (a block still
493
- * wins). Send-time only — the action's saved configuration is untouched,
494
- * and quick actions have no stored urgency policy to override. Never implies
495
- * `requires_ack`, which is the action's own saved acknowledgement policy.
496
- */
497
- is_urgent?: boolean;
498
- /**
499
- * One-shot acknowledgement modifier for this press only. It is OR-ed with the
500
- * action's stored policy, so it can only ADD an ack requirement — passing
501
- * `false` never removes one from an action already configured to require it.
502
- * The action's saved configuration is untouched either way.
503
- */
504
- requires_ack?: boolean;
505
- /** Applies to this press only, when its effective acknowledgement policy is enabled. */
506
- ack_mode?: AckMode;
507
- /**
508
- * The detail this press carries when the action has an `input_type`. Only
509
- * `location` and `url` are accepted on a trigger — no `button_label`; build
510
- * the fragments with `locationPing()` / `linkPing()` or pass them directly.
511
- */
512
- data?: TriggerData;
513
- /**
514
- * Ids from `attachments.upload()`, at most 4. Required when `input_type` is
515
- * `file`, `photo` (jpg/png only) or `pdf` (pdf only); a mismatched type is
516
- * `422 quick_action_input_type`.
517
- */
518
- attachment_ids?: string[];
519
- /**
520
- * The action's `id` as read from `actions.list()`. When that slot has since
521
- * moved pages the press is refused with `409 quick_action_layout_changed`
522
- * rather than firing the wrong Ping.
523
- */
524
- quick_action_id?: string;
525
- /**
526
- * Sent as the `Idempotency-Key` header (1–255 printable ASCII characters,
527
- * spaces allowed), never in the body.
528
- * Reuse the same key when retrying after a timeout or network error: the
529
- * server replays the first result instead of firing the press again.
530
- */
531
- idempotencyKey?: string;
532
- }
533
- /** The closed `data` object a quick-action press may carry. */
534
- export interface TriggerData {
535
- location?: TriggerLocation;
536
- /** Absolute http(s) URL, at most 2048 characters. */
537
- url?: string;
538
- }
539
- /** Same shape as `LocationPingLocation`; declared here to keep types.ts import-free. */
540
- export interface TriggerLocation {
541
- latitude: number;
542
- longitude: number;
543
- label?: string;
544
- address?: string;
545
- }
546
- export type AckMode = 'any' | 'all';
547
- /** The server-authoritative acknowledgement lifecycle attached to a ping. */
548
- export interface ActionState {
549
- /** Omitted by older servers and by the default any mode. */
550
- mode?: AckMode;
551
- confirmed_count?: number;
552
- required_count?: number;
553
- /** REST only; public rooms redact identities and MCP omits them. */
554
- confirmed_user_ids?: string[];
555
- status: 'open' | 'acked' | 'expired' | null;
556
- requires_ack: boolean;
557
- acked_by: {
558
- id: string | null;
559
- name: string | null;
560
- profile_image: string | null;
561
- } | null;
562
- acked_at: string | null;
563
- expires_at: string | null;
564
- /** Set when the confirmation window was closed early. */
565
- ended_at?: string | null;
566
- /** Viewer-specific human mutation eligibility; agent read paths return false. */
567
- can_ack?: boolean;
568
- /** Recipients who dismissed the card without confirming. Never counts as a confirmation. */
569
- dismissed_count?: number;
570
- /** REST only; public rooms redact identities and MCP omits them. */
571
- dismissed_user_ids?: string[];
572
- /** Viewer-scoped: when the reading viewer dismissed it. */
573
- dismissed_at?: string | null;
574
- }
575
- export interface PingResult {
576
- id: string;
577
- message: string;
578
- action_number: number | null;
579
- action_icon: string | null;
580
- trigger_source: string | null;
581
- data?: JsonObject | null;
582
- correlation_id?: string | null;
583
- reply_to?: string | null;
584
- attachments?: Attachment[];
585
- action_state?: ActionState | null;
586
- created_at: string;
587
- recipient_count?: number;
588
- muted_count?: number;
589
- [key: string]: unknown;
590
- }
591
- export interface DirectPingResult {
592
- id: string;
593
- target_handle: string;
594
- room_code: string;
595
- message: string;
596
- correlation_id: string | null;
597
- reply_to: string | null;
598
- action_state?: ActionState | null;
599
- created_at: string;
600
- [key: string]: unknown;
601
- }
602
- /**
603
- * The named fields of a listened/listed notification, without the index
604
- * signature. `Omit` collapses a type carrying a string index signature down to
605
- * that signature alone, so `NotificationDetail` derives from this rather than
606
- * from `AgentNotification` — otherwise every named field would widen to
607
- * `unknown`.
608
- */
609
- interface AgentNotificationFields {
610
- id: string;
611
- message: string;
612
- action_number: number | null;
613
- action_icon: string | null;
614
- trigger_source: string | null;
615
- /**
616
- * True when this ping is an agent handoff (a request to take over a
617
- * conversation) rather than an ordinary ping.
618
- */
619
- is_handoff?: boolean;
620
- data?: JsonObject | null;
621
- correlation_id?: string | null;
622
- reply_to?: string | null;
623
- attachments?: Attachment[];
624
- action_state?: ActionState | null;
625
- /** Confirmation rule the ping was sent with; absent on older rows. */
626
- ack_mode?: AckMode;
627
- /**
628
- * Delivered without sound/haptics (the sender's silent mode at send time).
629
- * `null` on rows written before 2026-09-16; not surfaced through MCP.
630
- */
631
- is_silent?: boolean | null;
632
- /**
633
- * The embedded Question when this ping carries one, else null. Same wire
634
- * shape as the dedicated Question read paths.
635
- */
636
- question?: Question | null;
637
- created_at: string;
638
- room?: {
639
- code: string;
640
- name: string;
641
- icon: string | null;
642
- color: string | null;
643
- };
644
- sender?: {
645
- id: string;
646
- name: string | null;
647
- };
648
- /**
649
- * Present when a connected agent (MCP / CLI credential) originated the
650
- * ping: the agent registration's display identity. Null/absent on human,
651
- * webhook, and trigger rows.
652
- */
653
- origin_agent?: {
654
- id?: string;
655
- handle: string | null;
656
- display_name: string | null;
657
- avatar_url?: string | null;
658
- } | null;
659
- }
660
- export interface AgentNotification extends AgentNotificationFields {
661
- [key: string]: unknown;
662
- }
663
- /** Full notification record returned by the single-notification read path. */
664
- export type NotificationDetail = Omit<AgentNotificationFields, 'room'> & {
665
- room_id?: string;
666
- sender_id?: string;
667
- type?: string;
668
- requires_ack?: boolean;
669
- /** Whether this ping was delivered time-sensitive. Independent of `requires_ack`. */
670
- is_urgent?: boolean;
671
- action_state: ActionState | null;
672
- room?: Room;
673
- [key: string]: unknown;
674
- };
675
- /** History keeps the full room and adds the listener-compatible `room.code`. */
676
- export interface NotificationHistoryEntry extends AgentNotification {
677
- room?: Room & {
678
- code: string;
679
- };
680
- }
681
- export interface ListNotificationsInput {
682
- /** `received` or `sent`; the server refuses any other value. */
683
- type?: 'received' | 'sent';
684
- room_id?: string;
685
- date?: string;
686
- /** Page size (1–25). Omit to retain the server's legacy default. */
687
- limit?: number;
688
- /** Page number, starting at 1. */
689
- page?: number;
690
- /** @deprecated Use limit. Sent as limit when limit is absent. */
691
- notifications_per_page?: number;
692
- }
693
- export interface WaitInput {
694
- /** Cursor (a notification id). Omit to start from the current head. */
695
- after?: string;
696
- /** Seconds to hold the connection (0–30, default 20). */
697
- timeout?: number;
698
- /** Max notifications to return (1–100, default 50). */
699
- limit?: number;
700
- signal?: AbortSignal;
701
- }
702
- export interface WaitResult {
703
- notifications: AgentNotification[];
704
- cursor: string;
705
- }
706
- export interface WaitForAcknowledgementInput {
707
- /** Seconds to hold the connection (0–30, default 20). */
708
- timeout?: number;
709
- signal?: AbortSignal;
710
- }
711
- export interface AcknowledgementWaitResult {
712
- id: string;
713
- action_state: ActionState;
714
- }
715
- export interface ListenInput {
716
- after?: string;
717
- timeout?: number;
718
- limit?: number;
719
- signal?: AbortSignal;
720
- /**
721
- * Called with each transient error (network failure, request timeout, 429,
722
- * 5xx) before the loop backs off and retries; transient errors are retried
723
- * whether or not this is set. Any other error (401, 403, 422, …) ends the
724
- * iterator by throwing, so a revoked credential never retries forever.
725
- */
726
- onError?: (err: unknown) => void;
727
- /**
728
- * First backoff after a transient error, in ms (default 1000). It doubles on
729
- * each consecutive failure up to 30 s; a server `retryAfter` replaces it.
730
- */
731
- backoffMs?: number;
732
- }
733
- export interface ApprovalInput {
734
- question: string;
735
- title?: string;
736
- options?: string[];
737
- correlation_id?: string;
738
- data?: JsonObject;
739
- ttl?: number;
740
- /**
741
- * Sent as the `Idempotency-Key` header (1–255 printable ASCII characters,
742
- * spaces allowed), never in the body.
743
- * Reuse the same key when retrying after a timeout or network error: the
744
- * server replays the first result instead of asking the human a second time.
745
- */
746
- idempotencyKey?: string;
747
- }
748
- export interface Approval {
749
- id: string;
750
- /**
751
- * A human answer has status `decided`; inspect `decision` for the chosen
752
- * option. `approved`/`denied` are never sent.
753
- */
754
- status: 'pending' | 'decided' | 'expired' | 'cancelled' | (string & {});
755
- question: string;
756
- title: string | null;
757
- options: string[];
758
- decision: string | null;
759
- decided_at: string | null;
760
- expires_at: string | null;
761
- correlation_id: string | null;
762
- data: JsonObject | null;
763
- /** Null when the approval's room no longer exists. */
764
- room_code: string | null;
765
- [key: string]: unknown;
766
- }
767
- export interface WaitApprovalInput {
768
- /** Seconds the server holds the connection (0–30, default 20). */
769
- timeout?: number;
770
- signal?: AbortSignal;
771
- }
772
- /**
773
- * Options for the blocking waits: `approvals.waitForDecision()`,
774
- * `questions.waitForAnswer()` and `handoffs.waitForResult()`.
775
- *
776
- * Network errors, request timeouts, 429 and 5xx are retried with backoff. The
777
- * retries stop with `PingRoomError` code `unavailable` (the last failure as
778
- * its `cause`) once only failures have come back since the last valid
779
- * response and the last-seen `expires_at` is more than 5 minutes past, or,
780
- * before any `expires_at` was seen, after 15 minutes of unbroken failures.
781
- */
782
- export interface WaitForOutcomeOptions {
783
- /** Abort to stop waiting; the wait rejects with the signal's reason. */
784
- signal?: AbortSignal;
785
- /**
786
- * Called before each retry of a transient failure, with that failure and
787
- * the number of consecutive failures so far (1 on the first). Throwing from
788
- * it ends the wait with the thrown error.
789
- */
790
- onRetry?: (error: PingRoomError, attempt: number) => void;
791
- }
792
- /**
793
- * The authenticated human who answered a Question or handoff (never
794
- * caller-supplied).
795
- *
796
- * Every field is redacted to `null` together when the caller is not entitled to
797
- * see who answered, which is why `id` is nullable even on a decided question.
798
- * The server sends all five fields from both `QuestionPresenter::responder` and
799
- * the handoff presenter; the type previously declared only `id` and
800
- * `display_name`, and being a closed object type that made the avatar fields
801
- * unreachable without a cast.
802
- */
803
- export interface QuestionResponder {
804
- id: string | null;
805
- display_name: string | null;
806
- profile_image_url: string | null;
807
- emoji: string | null;
808
- color: string | null;
809
- }
810
- /** The lifecycle states of a Question. Terminal states are immutable. */
811
- export type QuestionState = 'pending' | 'answered' | 'expired' | 'cancelled';
812
- /** Who may answer: `direct` (one named person) or `room` (any eligible member). */
813
- export type ResponderScope = 'direct' | 'room';
814
- /**
815
- * How a room Question resolves: `first` (the default — the first valid answer
816
- * wins) or `all` (a poll — everyone asked votes once; it closes when they all
817
- * have, or at its deadline).
818
- */
819
- export type QuestionResolutionPolicy = 'first' | 'all';
820
- /** One option offered on a Question. A bare string is shorthand for `{ value, label: value }`. */
821
- export interface QuestionOptionInput {
822
- /** Stable machine token returned as the answer (1–40 chars, unique per question). */
823
- value: string;
824
- /** Human text on the button (defaults to `value`; 1–40 chars). */
825
- label?: string;
826
- /** Presentation hint: `primary` = brand-strike affirmative, `danger` = cancel. */
827
- style?: 'primary' | 'danger' | 'default';
828
- /** Legacy boolean form of `style: 'primary'`. */
829
- primary?: boolean;
830
- /** Legacy boolean form of `style: 'danger'`. */
831
- destructive?: boolean;
832
- }
833
- export type QuestionOptionSpec = string | QuestionOptionInput;
834
- /** Invite a short typed answer, on its own (text-only) or alongside options. */
835
- export interface QuestionTextInput {
836
- placeholder?: string;
837
- /** 1–60 (default 60). A value outside that range is refused with a 422. */
838
- max_length?: number;
839
- }
840
- export interface QuestionInput {
841
- /** The question the human reads (required, ≤ 500 chars). */
842
- prompt: string;
843
- /** Optional secondary line, e.g. a build number (≤ 40 chars). */
844
- context?: string;
845
- /** 2–4 options. Omit for the binary Approve/Deny default (the lock-screen fast path). */
846
- options?: QuestionOptionSpec[];
847
- /** Offer a typed answer instead of / alongside options. */
848
- text_input?: QuestionTextInput;
849
- /** `direct` (defaults to your bound user) or `room` (any eligible member). Default `direct`. */
850
- responder_scope?: ResponderScope;
851
- /**
852
- * `first` (default) or `all` to poll the room: every member except your bound
853
- * human gets one final vote. A poll implies `room` scope when
854
- * `responder_scope` is omitted, and cannot be combined with
855
- * `responder_scope: 'direct'`, `target_user_id`, or `text_input`. If your
856
- * bound human is the room's only member the server falls back to a `direct`
857
- * `first` Question — check `resolution_policy` on the returned Question.
858
- */
859
- resolution_policy?: QuestionResolutionPolicy;
860
- /** For `direct` scope: a specific room member (UUID). Defaults to the bound user. */
861
- target_user_id?: string;
862
- /** Seconds until expiry. Omit for the server default (1h); clamped to 30–86400. A poll with at least one vote closes `answered` at this deadline. */
863
- ttl?: number;
864
- data?: JsonObject;
865
- correlation_id?: string;
866
- reply_to?: string;
867
- /** Ordered ids from `attachments.upload()` (max 4). Same single-use rules as PingInput. */
868
- attachment_ids?: string[];
869
- /**
870
- * Sent as the `Idempotency-Key` header (1–255 printable ASCII characters,
871
- * spaces allowed). Reuse this key when retrying the same question creation.
872
- */
873
- idempotencyKey?: string;
874
- }
875
- /** A resolved option on the Question wire shape. */
876
- export interface QuestionOption {
877
- value: string;
878
- label: string;
879
- primary?: boolean;
880
- destructive?: boolean;
881
- [key: string]: unknown;
882
- }
883
- /**
884
- * The resolution, present once `state === 'answered'` — except on a tied poll,
885
- * which is `answered` with a null `answer` (read `results` instead).
886
- */
887
- export interface QuestionAnswer {
888
- /** The chosen option's `value` (a poll's leading option), or null for a text-only answer. */
889
- value: string | null;
890
- /** The chosen option's `label`. */
891
- label: string | null;
892
- /** The typed answer, when the question invited one. Always null on a poll. */
893
- text: string | null;
894
- /**
895
- * The authenticated human who answered (never caller-supplied). Present once
896
- * the question is decided — but every field is redacted to `null` when the
897
- * caller is not entitled to see who answered, so `id` is nullable even here.
898
- * Null on a poll: the room chose the answer, and the voters are in
899
- * `results.responses`. Matches `HandoffAnswer.responder`.
900
- */
901
- responder: QuestionResponder | null;
902
- answered_at: string | null;
903
- }
904
- /** One option's tally in a poll's {@link QuestionPollResults}. */
905
- export interface QuestionPollOptionResult {
906
- value: string;
907
- label: string;
908
- /** Votes cast for this option (0 when nobody chose it). */
909
- count: number;
910
- }
911
- /** One cast vote in a poll's {@link QuestionPollResults.responses}. */
912
- export interface QuestionPollResponse {
913
- value: string;
914
- label: string;
915
- /** Who voted. Every field is `null` when the caller may not see who answered. */
916
- responder: QuestionResponder;
917
- answered_at: string | null;
918
- }
919
- /** The reading person's own seat in a poll. */
920
- export interface QuestionPollViewer {
921
- /** Whether the poll asked this person. */
922
- asked: boolean;
923
- /** The value they voted, or null until they vote. */
924
- response: string | null;
925
- }
926
- /**
927
- * A poll's tally (`resolution_policy: 'all'`). Present on every read of a poll
928
- * — including while it is still `pending` — and `null` on a `first` Question.
929
- */
930
- export interface QuestionPollResults {
931
- /** People the poll asked, fixed when it was created. */
932
- audience_count: number;
933
- /** Votes cast so far (exact). */
934
- response_count: number;
935
- /** Every option, in display order, with its count. */
936
- options: QuestionPollOptionResult[];
937
- /** Up to the 100 most recent votes, oldest first. */
938
- responses: QuestionPollResponse[];
939
- /** Only on a signed-in person's own surfaces; always `null` on agent reads and webhook events. */
940
- viewer: QuestionPollViewer | null;
941
- }
942
- /** The public Question wire shape — identical across ask / get / wait / list. */
943
- export interface Question {
944
- id: string;
945
- /** Canonical delivery notification when supplied by the server. */
946
- notification_id?: string | null;
947
- kind: 'question';
948
- prompt: string;
949
- context: string | null;
950
- options: QuestionOption[];
951
- text_input: {
952
- placeholder: string | null;
953
- max_length: number;
954
- } | null;
955
- responder_scope: ResponderScope;
956
- target_user_id: string | null;
957
- /** `first` or `all` (a poll). Open-ended so a future policy does not break callers. */
958
- resolution_policy: QuestionResolutionPolicy | (string & {});
959
- state: QuestionState;
960
- /** Null until answered, and on a tied poll even once `answered`. */
961
- answer: QuestionAnswer | null;
962
- /** A poll's tally; `null` on a `first` Question (absent on servers before Question Protocol 1.3). */
963
- results?: QuestionPollResults | null;
964
- expires_at: string | null;
965
- resolved_at: string | null;
966
- correlation_id: string | null;
967
- reply_to: string | null;
968
- data: JsonObject | null;
969
- created_at: string | null;
970
- room?: {
971
- code: string;
972
- name: string;
973
- icon: string | null;
974
- color: string | null;
975
- };
976
- room_code?: string;
977
- asker?: {
978
- /**
979
- * `'user'` for a human-asked Question (composer "Add Options"), `'agent'`
980
- * when an agent asked it. Both reach an agent's listen/list feed, so this
981
- * cannot be narrowed to `'agent'`.
982
- */
983
- type: 'agent' | 'user';
984
- id: string | null;
985
- handle: string | null;
986
- display_name: string | null;
987
- avatar_url: string | null;
988
- };
989
- [key: string]: unknown;
990
- }
991
- export interface WaitQuestionInput {
992
- /** Seconds the server holds the connection (0–30, default 20). */
993
- timeout?: number;
994
- signal?: AbortSignal;
995
- }
996
- export interface ListQuestionsInput {
997
- /** Filter by state; `all` returns every state. Omit for the recent window across states. */
998
- state?: QuestionState | 'all';
999
- }
1000
- /** Which primitive backs a handoff: an acknowledgement or a multi-option question. */
1001
- export type HandoffKind = 'ack' | 'question';
1002
- /** The lifecycle states of an `ack` handoff. Terminal: `acked`, `expired`. */
1003
- export type HandoffAckState = 'open' | 'acked' | 'expired';
1004
- /** The lifecycle states of a `question` handoff. Terminal: `answered`, `expired`, `cancelled`. */
1005
- export type HandoffQuestionState = 'answered' | 'expired' | 'cancelled' | 'pending';
1006
- /** The full handoff state space (union of ack + question states). */
1007
- export type HandoffState = HandoffAckState | HandoffQuestionState;
1008
- /**
1009
- * Whether the ping was enqueued, remains pending dispatch, or exhausted its
1010
- * retry budget (`failed`). Only populated on create; null on reads.
1011
- */
1012
- export type HandoffDeliveryState = 'enqueued' | 'pending' | 'failed';
1013
- /** One option offered on a `question` handoff. A bare string is shorthand for `{ value, label: value }`. */
1014
- export interface HandoffOptionInput {
1015
- /** Stable machine token returned as the answer. */
1016
- value: string;
1017
- /** Human text on the button (defaults to `value`). */
1018
- label?: string;
1019
- /** Presentation hint: `primary` = affirmative, `danger` = cancel/negative. */
1020
- style?: 'primary' | 'danger' | 'default';
1021
- }
1022
- export type HandoffOptionSpec = string | HandoffOptionInput;
1023
- /** A resolved option on the handoff wire shape. */
1024
- export interface HandoffOption {
1025
- value: string;
1026
- label: string;
1027
- [key: string]: unknown;
1028
- }
1029
- /** The human who acknowledged an `ack` handoff (present once `state === 'acked'`). */
1030
- export interface HandoffAcker {
1031
- /** Null when the actor is redacted (reader-privacy). */
1032
- id: string | null;
1033
- display_name: string | null;
1034
- }
1035
- /** The resolution of a `question` handoff (present once `state === 'answered'`). */
1036
- export interface HandoffAnswer {
1037
- /** The chosen option's `value`, or null for a text-only answer. */
1038
- value: string | null;
1039
- /** The chosen option's `label`. */
1040
- label: string | null;
1041
- /** The typed answer, when the question invited one. */
1042
- text: string | null;
1043
- /** The authenticated human who answered. */
1044
- responder: QuestionResponder | null;
1045
- answered_at: string | null;
1046
- }
1047
- /**
1048
- * The public handoff wire shape — identical across create / get / wait / list.
1049
- * `options`/`answer` appear on question handoffs; `acked_by`/`acked_at` on ack
1050
- * handoffs.
1051
- */
1052
- export interface Handoff {
1053
- id: string;
1054
- kind: HandoffKind;
1055
- prompt: string;
1056
- state: HandoffState;
1057
- /** Delivery status, populated only on create; null on reads. */
1058
- delivery_state: HandoffDeliveryState | null;
1059
- correlation_id: string | null;
1060
- reply_to: string | null;
1061
- data: JsonObject | null;
1062
- expires_at: string | null;
1063
- created_at: string | null;
1064
- /** ack handoff: the human who acknowledged (once `state === 'acked'`). */
1065
- acked_by?: HandoffAcker | null;
1066
- /** ack handoff: when it was acknowledged. */
1067
- acked_at?: string | null;
1068
- /** question handoff: the offered options. */
1069
- options?: HandoffOption[];
1070
- /** question handoff: the resolution (once `state === 'answered'`). */
1071
- answer?: HandoffAnswer | null;
1072
- /**
1073
- * Question handoffs used for Agent Inbox onboarding expose whether the
1074
- * server recorded the exact delivery + answer + agent-observation event.
1075
- */
1076
- activation_completed?: boolean;
1077
- [key: string]: unknown;
1078
- }
1079
- /** Ask a human to acknowledge (the ack handoff). Resolves on the first acknowledgement. */
1080
- export interface RequestAckInput {
1081
- /** What the human reads (required, ≤ 500 chars). */
1082
- prompt: string;
1083
- /**
1084
- * Who to reach: `me`, the bound human (the default). The bound human's own
1085
- * user id is accepted as an alias; any other id is refused with 403
1086
- * `target_not_permitted`.
1087
- */
1088
- target?: string;
1089
- /** Seconds until expiry. Clamped server-side to 120–86400; default 900. */
1090
- expiresIn?: number;
1091
- /** Interruption level — `active` (default) or `passive`. */
1092
- urgency?: 'active' | 'passive';
1093
- correlationId?: string;
1094
- replyTo?: string;
1095
- data?: JsonObject;
1096
- /**
1097
- * Idempotency key — same key + same body replays the original resource; a
1098
- * different body for the same key returns a 409 `idempotency_conflict`.
1099
- * Reuse it verbatim on network retries. 1–255 printable ASCII characters
1100
- * (spaces allowed); an empty string sends no key.
1101
- */
1102
- idempotencyKey?: string;
1103
- }
1104
- /** Ask a human a multi-option question (the question handoff). Resolves on the first tapped answer. */
1105
- export interface AskInput extends RequestAckInput {
1106
- /** 2–4 options. A bare string is shorthand for `{ value, label: value }`. */
1107
- options: HandoffOptionSpec[];
1108
- }
1109
- export interface WaitHandoffInput {
1110
- /** Seconds the server holds the connection (server caps at 25s; default 20). */
1111
- timeout?: number;
1112
- signal?: AbortSignal;
1113
- }
1114
- export interface ListHandoffsInput {
1115
- /** `open` for unresolved work, or `all` for recent history (up to 200 per kind). */
1116
- state?: 'open' | 'all';
1117
- }
1118
- /** Idempotent first-connect result from POST /api/agent/inbox/ensure. */
1119
- export interface AgentInboxEnsureResult {
1120
- onboarded: true;
1121
- replayed: boolean;
1122
- room: {
1123
- id: string;
1124
- name: string;
1125
- invite_code: string;
1126
- is_agent_inbox: boolean;
1127
- };
1128
- question: {
1129
- id: string;
1130
- kind: 'question';
1131
- prompt: string;
1132
- options: HandoffOption[];
1133
- state: HandoffQuestionState;
1134
- expires_at: string | null;
1135
- created_at: string | null;
1136
- };
1137
- }
1138
- /** Cancellation for the idempotent Agent Inbox ensure request. */
1139
- export interface AgentInboxEnsureInput {
1140
- signal?: AbortSignal;
1141
- }
1142
- /**
1143
- * Controls the activation handoff wait. `timeout` is the duration of each
1144
- * bounded server hold; a still-pending response is polled again until the
1145
- * server confirms activation, the Question expires/cancels, the overall
1146
- * deadline elapses, or `signal` is aborted.
1147
- */
1148
- export interface AgentInboxActivateInput extends WaitHandoffInput {
1149
- /**
1150
- * Wall-clock limit for ensure + every pending long-poll combined. Defaults
1151
- * to 120000 (two minutes). Distinct from `timeout`, which controls one hold.
1152
- */
1153
- overallTimeoutMs?: number;
1154
- }
1155
- /** The terminal question returned by a completed Agent Inbox activation. */
1156
- export type AgentInboxActivationQuestion = Handoff & {
1157
- kind: 'question';
1158
- state: 'answered';
1159
- answer: HandoffAnswer;
1160
- activation_completed: true;
1161
- };
1162
- /** `ensure` metadata plus the terminal, fully resolved onboarding handoff. */
1163
- export type AgentInboxActivationResult = Omit<AgentInboxEnsureResult, 'question'> & {
1164
- activation_completed: true;
1165
- question: AgentInboxActivationQuestion;
1166
- };
1167
- export interface RotateHandleResult {
1168
- handle: string;
1169
- [key: string]: unknown;
1170
- }
1171
- export type PingPolicy = 'open' | 'members' | 'closed' | (string & {});
1172
- export type ActivityBucket = 'active_now' | 'today' | 'this_week' | 'quiet' | (string & {});
1173
- export interface DirectoryEntry {
1174
- handle: string;
1175
- display_name: string;
1176
- tagline: string;
1177
- tags: string[];
1178
- icon: string | null;
1179
- color: string | null;
1180
- ping_policy: PingPolicy;
1181
- is_featured: boolean;
1182
- operated_by: string | null;
1183
- last_active: ActivityBucket;
1184
- }
1185
- export interface DirectoryProfile extends DirectoryEntry {
1186
- description: string | null;
1187
- listed_at: string | null;
1188
- card_url: string | null;
1189
- }
1190
- export interface DirectoryListInput {
1191
- search?: string;
1192
- tag?: string;
1193
- per_page?: number;
1194
- page?: number;
1195
- }
1196
- export interface Paginated<T> {
1197
- current_page: number;
1198
- data: T[];
1199
- per_page: number;
1200
- total: number;
1201
- last_page: number;
1202
- next_page_url: string | null;
1203
- prev_page_url: string | null;
1204
- [key: string]: unknown;
1205
- }
1206
- export {};
8
+ export type * from './types/common.js';
9
+ export type * from './types/auth.js';
10
+ export type * from './types/rooms.js';
11
+ export type * from './types/notifications.js';
12
+ export type * from './types/approvals.js';
13
+ export type * from './types/questions.js';
14
+ export type * from './types/handoffs.js';
15
+ export type * from './types/inbox.js';
16
+ export type * from './types/profile.js';
1207
17
  //# sourceMappingURL=types.d.ts.map