@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
@@ -0,0 +1,242 @@
1
+ // `pr.auth`: registration, claim, app pairing and the credential lifecycle.
2
+ import { PingRoomError } from '../errors.js';
3
+ import { sleep, throwIfAborted } from '../internal/async.js';
4
+ import { requireNonEmpty } from '../internal/guards.js';
5
+ import { dropUndefined } from '../internal/request.js';
6
+ import { isRecord } from '../internal/validate.js';
7
+ /** Drop a malformed or unsafe server-provided URL without rejecting its response. */
8
+ function normalizePublicHttpUrl(candidate) {
9
+ if (typeof candidate !== 'string' || candidate.trim() === '')
10
+ return undefined;
11
+ const trimmed = candidate.trim();
12
+ // eslint-disable-next-line no-control-regex
13
+ if (/[\u0000-\u001F\u007F-\u009F]/.test(trimmed))
14
+ return undefined;
15
+ try {
16
+ const url = new URL(trimmed);
17
+ if (url.protocol !== 'https:' && url.protocol !== 'http:')
18
+ return undefined;
19
+ if (url.username !== '' || url.password !== '')
20
+ return undefined;
21
+ }
22
+ catch {
23
+ return undefined;
24
+ }
25
+ return trimmed;
26
+ }
27
+ /** Drop malformed or unsafe server-provided links without rejecting a valid credential. */
28
+ function normalizePairingLinks(value) {
29
+ if (!isRecord(value))
30
+ return undefined;
31
+ const latestPings = normalizePublicHttpUrl(value['latest_pings']);
32
+ if (!latestPings)
33
+ return undefined;
34
+ const installApp = normalizePublicHttpUrl(value['install_app']);
35
+ return {
36
+ latest_pings: latestPings,
37
+ ...(installApp ? { install_app: installApp } : {}),
38
+ };
39
+ }
40
+ /** Agent credential lifecycle (auth.md flow). */
41
+ export class AuthApi {
42
+ http;
43
+ pairing = null;
44
+ constructor(http) {
45
+ this.http = http;
46
+ }
47
+ /** Register an agent. Anonymous or via an identity assertion (ID-JAG / verified email). Public. */
48
+ register(params) {
49
+ requireNonEmpty(params.type, 'type');
50
+ return this.http.request('POST', '/api/agent/auth', { auth: false, body: dropUndefined({ ...params }) });
51
+ }
52
+ /** Begin claiming a pre-claim credential onto a human account; emails an OTP. */
53
+ claimStart(params) {
54
+ requireNonEmpty(params.email, 'email');
55
+ return this.http.request('POST', '/api/agent/auth/claim/start', { body: { email: params.email } });
56
+ }
57
+ /** Complete the claim with the emailed OTP; returns an active credential + handle. */
58
+ claimComplete(params) {
59
+ requireNonEmpty(params.email, 'email');
60
+ requireNonEmpty(params.otp, 'otp');
61
+ return this.http.request('POST', '/api/agent/auth/claim/complete', { body: dropUndefined({ ...params }) });
62
+ }
63
+ /**
64
+ * Register a pending agent and create a short-lived link that opens the
65
+ * PingRoom app. The server owns the full grant shown to the approver; this
66
+ * client sends no scope list. The pending credential stays private inside the
67
+ * client and is replaced automatically once waitForPairing() succeeds. If the
68
+ * client already held a credential, it is put back when the pairing expires
69
+ * or the wait is aborted, so a re-pairing that never completes leaves the
70
+ * client on the working credential rather than the dead pending one.
71
+ */
72
+ async startPairing(params = {}) {
73
+ const previousToken = this.http.getToken();
74
+ const pending = await this.register({
75
+ type: 'anonymous',
76
+ ...(params.agent_label ? { agent_label: params.agent_label } : {}),
77
+ });
78
+ this.http.setToken(pending.credential);
79
+ try {
80
+ const started = await this.http.request('POST', '/api/agent/auth/pair/start', {
81
+ body: {},
82
+ });
83
+ // A second pairing started while the first is still pending falls back
84
+ // to the credential beneath it, not to the first pairing's pending one.
85
+ this.pairing = {
86
+ pairToken: started.pair_token,
87
+ pending: pending.credential,
88
+ previous: this.pairing !== null && this.pairing.pending === previousToken
89
+ ? this.pairing.previous
90
+ : previousToken,
91
+ };
92
+ return started;
93
+ }
94
+ catch (error) {
95
+ if (this.http.getToken() === pending.credential) {
96
+ this.http.setToken(previousToken);
97
+ }
98
+ throw error;
99
+ }
100
+ }
101
+ /** Read the current state of an app pairing using the pending credential. */
102
+ pairingStatus(options = {}) {
103
+ return this.http.request('GET', '/api/agent/auth/pair/status', { signal: options.signal });
104
+ }
105
+ /**
106
+ * Wait until the person approves in PingRoom, or the short-lived link
107
+ * expires. Transient network, 429, and 5xx failures are retried inside the
108
+ * server-provided lifetime. On success the client immediately starts using
109
+ * the active credential returned by the server. When the link expires or the
110
+ * wait is aborted, the credential the client held before startPairing() is
111
+ * restored; calling waitForPairing() again after an abort resumes the same
112
+ * pairing.
113
+ */
114
+ async waitForPairing(pairing, options = {}) {
115
+ const tracked = this.pairing !== null && this.pairing.pairToken === pairing.pair_token
116
+ ? this.pairing
117
+ : null;
118
+ if (tracked !== null && this.http.getToken() === tracked.previous) {
119
+ // Resuming after an abort put the earlier credential back.
120
+ this.http.setToken(tracked.pending);
121
+ }
122
+ try {
123
+ const paired = await this.pollPairing(pairing, options);
124
+ if (tracked !== null && this.pairing === tracked)
125
+ this.pairing = null;
126
+ return paired;
127
+ }
128
+ catch (error) {
129
+ if (tracked !== null && this.pairing === tracked) {
130
+ const expired = error instanceof PingRoomError && error.code === 'pairing_expired';
131
+ if (expired || options.signal?.aborted === true) {
132
+ if (this.http.getToken() === tracked.pending)
133
+ this.http.setToken(tracked.previous);
134
+ }
135
+ // An expired pairing cannot be resumed; an aborted one can.
136
+ if (expired)
137
+ this.pairing = null;
138
+ }
139
+ throw error;
140
+ }
141
+ }
142
+ async pollPairing(pairing, options) {
143
+ const lifetimeMs = Math.max(1, Number(pairing.expires_in) || 900) * 1000;
144
+ const requestedInterval = options.pollIntervalMs ?? pairing.poll_interval_ms;
145
+ const intervalMs = Math.min(Math.max(Number(requestedInterval) || 1500, 1000), 10_000);
146
+ const startedAt = Date.now();
147
+ const deadline = startedAt + lifetimeMs;
148
+ let transientFailures = 0;
149
+ while (Date.now() < deadline) {
150
+ throwIfAborted(options.signal);
151
+ try {
152
+ const status = await this.pairingStatus({ signal: options.signal });
153
+ throwIfAborted(options.signal);
154
+ transientFailures = 0;
155
+ if (status.status === 'active') {
156
+ if (typeof status.credential !== 'string'
157
+ || status.credential.trim() === ''
158
+ || status.credential_type !== 'active'
159
+ || (status.expires_in !== null
160
+ && (typeof status.expires_in !== 'number'
161
+ || !Number.isFinite(status.expires_in)
162
+ || status.expires_in < 0))
163
+ // A null/absent `room` is valid when the account has no eligible
164
+ // private delivery room (and on older servers). Only a room that is
165
+ // present but malformed is a broken response.
166
+ || (status.room != null
167
+ && (typeof status.room.invite_code !== 'string'
168
+ || status.room.invite_code.trim() === ''))) {
169
+ throw new PingRoomError('PingRoom returned an incomplete approved pairing.', {
170
+ code: 'pairing_invalid_response',
171
+ body: { status: status.status },
172
+ });
173
+ }
174
+ this.http.setToken(status.credential);
175
+ // Pairing is server-authoritative. Some servers still include their
176
+ // internal grant marker for protocol compatibility; it is neither a
177
+ // client input nor part of the paired credential surface.
178
+ const { status: _status, scopes: _serverScopes, links: rawLinks, ...credential } = status;
179
+ const links = normalizePairingLinks(rawLinks);
180
+ return links ? { ...credential, links } : credential;
181
+ }
182
+ if (status.status === 'expired') {
183
+ throw new PingRoomError('The PingRoom pairing link expired before it was approved.', {
184
+ code: 'pairing_expired',
185
+ });
186
+ }
187
+ }
188
+ catch (error) {
189
+ if (error instanceof PingRoomError
190
+ && [401, 403, 404].includes(error.status)
191
+ && Date.now() - startedAt >= lifetimeMs / 2) {
192
+ // The pending bearer can expire before the server returns an
193
+ // explicit expired pairing state. Keep early auth failures intact.
194
+ throw new PingRoomError('The PingRoom pairing link expired before it was approved.', {
195
+ code: 'pairing_expired',
196
+ });
197
+ }
198
+ if (error instanceof PingRoomError
199
+ && (error.code === 'network_error'
200
+ || error.code === 'timeout'
201
+ || error.status === 429
202
+ || error.status >= 500)) {
203
+ transientFailures += 1;
204
+ const backoffMs = Math.min(intervalMs * 2 ** Math.max(0, transientFailures - 3), 30_000);
205
+ await sleep(Math.max(0, Math.min(backoffMs, deadline - Date.now())), options.signal);
206
+ continue;
207
+ }
208
+ throw error;
209
+ }
210
+ await sleep(Math.max(0, Math.min(intervalMs, deadline - Date.now())), options.signal);
211
+ }
212
+ throw new PingRoomError('The PingRoom pairing link expired before it was approved.', {
213
+ code: 'pairing_expired',
214
+ });
215
+ }
216
+ /** Rotate to a fresh credential (same scopes/handle). */
217
+ refresh() {
218
+ return this.http.request('POST', '/api/agent/auth/refresh', { body: {} });
219
+ }
220
+ /** Revoke the current credential. */
221
+ revoke() {
222
+ return this.http.request('POST', '/api/agent/auth/revoke', { body: {} });
223
+ }
224
+ /**
225
+ * What this credential is connected to: the robot, the owner's public id and
226
+ * name, the home room and room memberships, and the room grant. Check
227
+ * `owner.id` and `handle` against the account and robot you approved before
228
+ * sending anything.
229
+ */
230
+ connection() {
231
+ return this.http.request('GET', '/api/agent/connection');
232
+ }
233
+ /**
234
+ * Disconnect this agent: revokes the calling credential and its refresh
235
+ * credentials. The client keeps the now-revoked token; clear it with
236
+ * `setToken(null)` or pair again.
237
+ */
238
+ disconnect() {
239
+ return this.http.request('POST', '/api/agent/disconnect', { body: {} });
240
+ }
241
+ }
242
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/namespaces/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { HttpClient } from '../http.js';
2
+ import type { DirectoryEntry, DirectoryListInput, DirectoryProfile, Paginated } from '../types.js';
3
+ /** Public, unauthenticated agent directory. */
4
+ export declare class DirectoryApi {
5
+ private readonly http;
6
+ constructor(http: HttpClient);
7
+ list(input?: DirectoryListInput): Promise<Paginated<DirectoryEntry>>;
8
+ get(handle: string): Promise<DirectoryProfile>;
9
+ }
10
+ //# sourceMappingURL=directory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directory.d.ts","sourceRoot":"","sources":["../../src/namespaces/directory.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGnG,+CAA+C;AAC/C,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C,IAAI,CAAC,KAAK,GAAE,kBAAuB,GAAG,OAAO,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAOxE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAG/C"}
@@ -0,0 +1,19 @@
1
+ // `pr.directory`: the public agent directory.
2
+ import { enc, dropUndefined } from '../internal/request.js';
3
+ /** Public, unauthenticated agent directory. */
4
+ export class DirectoryApi {
5
+ http;
6
+ constructor(http) {
7
+ this.http = http;
8
+ }
9
+ list(input = {}) {
10
+ return this.http.request('GET', '/api/agents/directory', {
11
+ auth: false,
12
+ query: dropUndefined({ ...input }),
13
+ });
14
+ }
15
+ get(handle) {
16
+ return this.http.request('GET', `/api/agents/directory/${enc(handle)}`, { auth: false });
17
+ }
18
+ }
19
+ //# sourceMappingURL=directory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directory.js","sourceRoot":"","sources":["../../src/namespaces/directory.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAI9C,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE5D,+CAA+C;AAC/C,MAAM,OAAO,YAAY;IACM;IAA7B,YAA6B,IAAgB;QAAhB,SAAI,GAAJ,IAAI,CAAY;IAAG,CAAC;IAEjD,IAAI,CAAC,QAA4B,EAAE;QACjC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,uBAAuB,EAAE;YACvD,IAAI,EAAE,KAAK;YACX,KAAK,EAAE,aAAa,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;SACnC,CAAC,CAAC;IACL,CAAC;IAED,GAAG,CAAC,MAAc;QAChB,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,yBAAyB,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3F,CAAC;CACF"}
@@ -0,0 +1,47 @@
1
+ import type { HttpClient } from '../http.js';
2
+ import type { AskInput, Handoff, ListHandoffsInput, RequestAckInput, WaitHandoffInput, WaitForOutcomeOptions } from '../types.js';
3
+ /**
4
+ * The Handoff façade: the Agent → one-human loop. Always DIRECT (exactly one
5
+ * human) and PRIVATE (no other room member can read it). Backed by the ack and
6
+ * question primitives, so its {@link Handoff.state | state} space is their union
7
+ * — kept DISTINCT per {@link Handoff.kind | kind}. A negative answer to a
8
+ * question handoff (e.g. `hold`) is a SUCCESSFUL `answered` result, not an error.
9
+ *
10
+ * const task = await pr.handoffs.requestAck({ prompt, idempotencyKey });
11
+ * const result = await pr.handoffs.waitForResult(task.id);
12
+ *
13
+ * const q = await pr.handoffs.ask({ prompt, options: ['deploy', 'hold'], idempotencyKey });
14
+ */
15
+ export declare class HandoffsApi {
16
+ private readonly http;
17
+ constructor(http: HttpClient);
18
+ /** Ask a human to acknowledge (an `ack` handoff). Resolves on the first acknowledgement. */
19
+ requestAck(input: RequestAckInput): Promise<Handoff>;
20
+ /**
21
+ * Ask a human a multi-option question (a `question` handoff). Resolves on the
22
+ * first tapped answer. Bare-string options normalize to `{ value, label }`.
23
+ */
24
+ ask(input: AskInput): Promise<Handoff>;
25
+ /** Fetch a handoff's current state. */
26
+ get(id: string): Promise<Handoff>;
27
+ /**
28
+ * Block until the handoff resolves (or expires/cancels), looping the bounded
29
+ * long-poll under the hood. `expired`/`cancelled` and a negative answer (e.g.
30
+ * `hold`) all surface as normal terminal results — nothing is thrown for them.
31
+ *
32
+ * Polls start at least 2.1 s apart, so a short `timeout` stays under the
33
+ * route's 30-per-minute limit. A response that is not this handoff in a
34
+ * known state rejects with `invalid_response`. Network failures, 429 and 5xx
35
+ * are retried with backoff (honouring `retryAfter`), and reported to
36
+ * `onRetry`, until `signal` aborts or the outage outlasts the handoff's
37
+ * `expires_at` by 5 minutes (15 minutes of failures while no `expires_at` has
38
+ * been read); that rejects with `unavailable`. See {@link WaitForOutcomeOptions}.
39
+ */
40
+ waitForResult(id: string, input?: WaitHandoffInput & WaitForOutcomeOptions): Promise<Handoff>;
41
+ /** List the agent's open handoffs or bounded recent history. */
42
+ list(input?: ListHandoffsInput): Promise<Handoff[]>;
43
+ /** One bounded long-poll; returns the (possibly still-open) handoff. */
44
+ private wait;
45
+ private create;
46
+ }
47
+ //# sourceMappingURL=handoffs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handoffs.d.ts","sourceRoot":"","sources":["../../src/namespaces/handoffs.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAO7C,OAAO,KAAK,EACV,QAAQ,EACR,OAAO,EAGP,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,aAAa,CAAC;AA+BrB;;;;;;;;;;;GAWG;AACH,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C,4FAA4F;IAC5F,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IAMpD;;;OAGG;IACH,GAAG,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAWtC,uCAAuC;IACvC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKjC;;;;;;;;;;;;OAYG;IACG,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,GAAE,gBAAgB,GAAG,qBAA0B,GAAG,OAAO,CAAC,OAAO,CAAC;IAevG,gEAAgE;IAC1D,IAAI,CAAC,KAAK,GAAE,iBAAsB,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAO7D,wEAAwE;IACxE,OAAO,CAAC,IAAI;IAQZ,OAAO,CAAC,MAAM;CAqBf"}
@@ -0,0 +1,126 @@
1
+ // `pr.handoffs`: the direct, private agent-to-human loop.
2
+ import { PingRoomError } from '../errors.js';
3
+ import { assertStructuredData, normalizeIdempotencyKey, requireNonEmpty, } from '../internal/guards.js';
4
+ import { pollUntilSettled } from '../internal/retry.js';
5
+ import { MIN_HANDOFF_POLL_INTERVAL_MS, enc, assertOnRetry, dropUndefined, waitTimeoutMs, } from '../internal/request.js';
6
+ import { isRecord, sameId, invalidWaitResponse } from '../internal/validate.js';
7
+ const HANDOFF_STATES = new Set(['open', 'acked', 'pending', 'answered', 'expired', 'cancelled']);
8
+ function validateHandoffWait(value, handoffId) {
9
+ const state = isRecord(value) ? value['state'] : undefined;
10
+ if (!isRecord(value) || !sameId(value['id'], handoffId) || typeof state !== 'string' || !HANDOFF_STATES.has(state)) {
11
+ return invalidWaitResponse('handoff', handoffId, value, 'state');
12
+ }
13
+ return value;
14
+ }
15
+ /** A bare string option is shorthand for `{ value, label: value }`. */
16
+ function normalizeHandoffOptions(options) {
17
+ return options.map((o) => (typeof o === 'string' ? { value: o, label: o } : o));
18
+ }
19
+ /** Terminal states never change again — the wait loop can stop as soon as one lands. */
20
+ function isHandoffTerminal(handoff) {
21
+ const s = handoff.state;
22
+ return s === 'acked' || s === 'answered' || s === 'expired' || s === 'cancelled';
23
+ }
24
+ /**
25
+ * The Handoff façade: the Agent → one-human loop. Always DIRECT (exactly one
26
+ * human) and PRIVATE (no other room member can read it). Backed by the ack and
27
+ * question primitives, so its {@link Handoff.state | state} space is their union
28
+ * — kept DISTINCT per {@link Handoff.kind | kind}. A negative answer to a
29
+ * question handoff (e.g. `hold`) is a SUCCESSFUL `answered` result, not an error.
30
+ *
31
+ * const task = await pr.handoffs.requestAck({ prompt, idempotencyKey });
32
+ * const result = await pr.handoffs.waitForResult(task.id);
33
+ *
34
+ * const q = await pr.handoffs.ask({ prompt, options: ['deploy', 'hold'], idempotencyKey });
35
+ */
36
+ export class HandoffsApi {
37
+ http;
38
+ constructor(http) {
39
+ this.http = http;
40
+ }
41
+ /** Ask a human to acknowledge (an `ack` handoff). Resolves on the first acknowledgement. */
42
+ requestAck(input) {
43
+ requireNonEmpty(input.prompt, 'prompt');
44
+ assertStructuredData(input.data);
45
+ return this.create('ack', input);
46
+ }
47
+ /**
48
+ * Ask a human a multi-option question (a `question` handoff). Resolves on the
49
+ * first tapped answer. Bare-string options normalize to `{ value, label }`.
50
+ */
51
+ ask(input) {
52
+ requireNonEmpty(input.prompt, 'prompt');
53
+ assertStructuredData(input.data);
54
+ if (!Array.isArray(input.options) || input.options.length < 2 || input.options.length > 4) {
55
+ throw new PingRoomError('`options` must contain between 2 and 4 entries for a question handoff.', {
56
+ code: 'invalid_request',
57
+ });
58
+ }
59
+ return this.create('question', input, normalizeHandoffOptions(input.options));
60
+ }
61
+ /** Fetch a handoff's current state. */
62
+ get(id) {
63
+ requireNonEmpty(id, 'id');
64
+ return this.http.request('GET', `/api/agent/handoffs/${enc(id)}`);
65
+ }
66
+ /**
67
+ * Block until the handoff resolves (or expires/cancels), looping the bounded
68
+ * long-poll under the hood. `expired`/`cancelled` and a negative answer (e.g.
69
+ * `hold`) all surface as normal terminal results — nothing is thrown for them.
70
+ *
71
+ * Polls start at least 2.1 s apart, so a short `timeout` stays under the
72
+ * route's 30-per-minute limit. A response that is not this handoff in a
73
+ * known state rejects with `invalid_response`. Network failures, 429 and 5xx
74
+ * are retried with backoff (honouring `retryAfter`), and reported to
75
+ * `onRetry`, until `signal` aborts or the outage outlasts the handoff's
76
+ * `expires_at` by 5 minutes (15 minutes of failures while no `expires_at` has
77
+ * been read); that rejects with `unavailable`. See {@link WaitForOutcomeOptions}.
78
+ */
79
+ async waitForResult(id, input = {}) {
80
+ requireNonEmpty(id, 'id');
81
+ assertOnRetry(input.onRetry);
82
+ return pollUntilSettled({
83
+ poll: () => this.wait(id, input),
84
+ validate: (value) => validateHandoffWait(value, id),
85
+ settled: isHandoffTerminal,
86
+ expiresAt: (handoff) => handoff.expires_at,
87
+ what: `handoff ${id}`,
88
+ minIntervalMs: MIN_HANDOFF_POLL_INTERVAL_MS,
89
+ ...(input.signal ? { signal: input.signal } : {}),
90
+ ...(input.onRetry ? { onRetry: input.onRetry } : {}),
91
+ });
92
+ }
93
+ /** List the agent's open handoffs or bounded recent history. */
94
+ async list(input = {}) {
95
+ const res = await this.http.request('GET', '/api/agent/handoffs', {
96
+ query: dropUndefined({ state: input.state }),
97
+ });
98
+ return res.handoffs ?? [];
99
+ }
100
+ /** One bounded long-poll; returns the (possibly still-open) handoff. */
101
+ wait(id, input) {
102
+ return this.http.request('GET', `/api/agent/handoffs/${enc(id)}/wait`, {
103
+ query: dropUndefined({ timeout: input.timeout }),
104
+ timeoutMs: waitTimeoutMs(input.timeout),
105
+ ...(input.signal ? { signal: input.signal } : {}),
106
+ });
107
+ }
108
+ create(kind, input, options) {
109
+ const body = dropUndefined({
110
+ kind,
111
+ prompt: input.prompt,
112
+ audience: { type: 'direct', user_id: input.target ?? 'me' },
113
+ expires_in: input.expiresIn,
114
+ urgency: input.urgency,
115
+ options,
116
+ correlation_id: input.correlationId,
117
+ reply_to: input.replyTo,
118
+ data: input.data,
119
+ });
120
+ return this.http.request('POST', '/api/agent/handoffs', {
121
+ body,
122
+ ...(input.idempotencyKey ? { headers: { 'Idempotency-Key': normalizeIdempotencyKey(input.idempotencyKey) } } : {}),
123
+ });
124
+ }
125
+ }
126
+ //# sourceMappingURL=handoffs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handoffs.js","sourceRoot":"","sources":["../../src/namespaces/handoffs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { HttpClient } from '../http.js';
2
+ import type { AgentInboxEnsureResult, AgentInboxActivateInput, AgentInboxActivationResult, AgentInboxEnsureInput } from '../types.js';
3
+ /** Setup and activation of the bound human's Agent Inbox delivery room. */
4
+ export declare class InboxApi {
5
+ private readonly http;
6
+ constructor(http: HttpClient);
7
+ /** Replay the viable activation attempt or create its next numbered retry. */
8
+ ensure(input?: AgentInboxEnsureInput): Promise<AgentInboxEnsureResult>;
9
+ /**
10
+ * Ensure the bound human's Agent Inbox, then block on its onboarding
11
+ * Question until the server confirms activation, it expires/cancels, or the
12
+ * overall deadline elapses. Pairing remains a separate operation so adopting
13
+ * a credential never silently waits for a phone response.
14
+ */
15
+ activate(input?: AgentInboxActivateInput): Promise<AgentInboxActivationResult>;
16
+ }
17
+ //# sourceMappingURL=inbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox.d.ts","sourceRoot":"","sources":["../../src/namespaces/inbox.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C,OAAO,KAAK,EACV,sBAAsB,EACtB,uBAAuB,EAEvB,0BAA0B,EAC1B,qBAAqB,EAEtB,MAAM,aAAa,CAAC;AA8GrB,2EAA2E;AAC3E,qBAAa,QAAQ;IACP,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C,8EAA8E;IAC9E,MAAM,CAAC,KAAK,GAAE,qBAA0B,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAO1E;;;;;OAKG;IACG,QAAQ,CAAC,KAAK,GAAE,uBAA4B,GAAG,OAAO,CAAC,0BAA0B,CAAC;CA+GzF"}