Secure storage and distribution of cryptographic keys in ATProto applications

add missing methods to client

Changed files
+166
packages
client
src
+166
packages/client/src/client.ts
··· 298 298 this.keyCache.clear() 299 299 this.authManager.clearCache() 300 300 } 301 + 302 + /** 303 + * Add a member to a group 304 + * Requires authorization: Must be group owner OR have delegation with 'add_member' permission 305 + */ 306 + async addMember(params: { 307 + group_id: string 308 + member_did: string 309 + }): Promise<{ groupId: string; memberDid: string; status: string }> { 310 + const url = new URL( 311 + '/xrpc/dev.atpkeyserver.alpha.group.addMember', 312 + this.keyserverUrl, 313 + ) 314 + 315 + const lxm = 'dev.atpkeyserver.alpha.group.addMember' 316 + const token = await this.authManager.getToken(this.keyserverDid, lxm) 317 + 318 + const response = await this.fetchWithRetry(url.toString(), { 319 + method: 'POST', 320 + headers: { 321 + 'Authorization': `Bearer ${token}`, 322 + 'Content-Type': 'application/json', 323 + }, 324 + body: JSON.stringify(params), 325 + }) 326 + 327 + if (!response.ok) { 328 + await this.handleErrorResponse(response) 329 + } 330 + 331 + return await response.json() 332 + } 333 + 334 + /** 335 + * Remove a member from a group 336 + * Requires authorization: Must be group owner OR have delegation with 'remove_member' permission 337 + */ 338 + async removeMember(params: { 339 + group_id: string 340 + member_did: string 341 + }): Promise<{ groupId: string; memberDid: string; status: string }> { 342 + const url = new URL( 343 + '/xrpc/dev.atpkeyserver.alpha.group.removeMember', 344 + this.keyserverUrl, 345 + ) 346 + 347 + const lxm = 'dev.atpkeyserver.alpha.group.removeMember' 348 + const token = await this.authManager.getToken(this.keyserverDid, lxm) 349 + 350 + const response = await this.fetchWithRetry(url.toString(), { 351 + method: 'POST', 352 + headers: { 353 + 'Authorization': `Bearer ${token}`, 354 + 'Content-Type': 'application/json', 355 + }, 356 + body: JSON.stringify(params), 357 + }) 358 + 359 + if (!response.ok) { 360 + await this.handleErrorResponse(response) 361 + } 362 + 363 + return await response.json() 364 + } 365 + 366 + /** 367 + * Authorize a delegate to manage group membership 368 + * Requires authorization: Must be group owner 369 + */ 370 + async authorizeDelegate(params: { 371 + group_id: string 372 + delegate_did: string 373 + permissions: string[] 374 + expires_at?: string 375 + }): Promise<{ groupId: string; delegateDid: string; status: string }> { 376 + const url = new URL( 377 + '/xrpc/dev.atpkeyserver.alpha.group.authorizeDelegate', 378 + this.keyserverUrl, 379 + ) 380 + 381 + const lxm = 'dev.atpkeyserver.alpha.group.authorizeDelegate' 382 + const token = await this.authManager.getToken(this.keyserverDid, lxm) 383 + 384 + const response = await this.fetchWithRetry(url.toString(), { 385 + method: 'POST', 386 + headers: { 387 + 'Authorization': `Bearer ${token}`, 388 + 'Content-Type': 'application/json', 389 + }, 390 + body: JSON.stringify(params), 391 + }) 392 + 393 + if (!response.ok) { 394 + await this.handleErrorResponse(response) 395 + } 396 + 397 + return await response.json() 398 + } 399 + 400 + /** 401 + * Revoke a delegate's authorization 402 + * Requires authorization: Must be group owner 403 + */ 404 + async revokeDelegate(params: { 405 + group_id: string 406 + delegate_did: string 407 + }): Promise<{ groupId: string; delegateDid: string; status: string }> { 408 + const url = new URL( 409 + '/xrpc/dev.atpkeyserver.alpha.group.revokeDelegate', 410 + this.keyserverUrl, 411 + ) 412 + 413 + const lxm = 'dev.atpkeyserver.alpha.group.revokeDelegate' 414 + const token = await this.authManager.getToken(this.keyserverDid, lxm) 415 + 416 + const response = await this.fetchWithRetry(url.toString(), { 417 + method: 'POST', 418 + headers: { 419 + 'Authorization': `Bearer ${token}`, 420 + 'Content-Type': 'application/json', 421 + }, 422 + body: JSON.stringify(params), 423 + }) 424 + 425 + if (!response.ok) { 426 + await this.handleErrorResponse(response) 427 + } 428 + 429 + return await response.json() 430 + } 431 + 432 + /** 433 + * List all delegates for a group 434 + * Requires authorization: Must be group owner 435 + */ 436 + async listDelegates(params: { group_id: string }): Promise<{ 437 + groupId: string 438 + delegates: Array<{ 439 + delegateDid: string 440 + permissions: string[] 441 + grantedAt: string 442 + expiresAt?: string 443 + }> 444 + }> { 445 + const url = new URL( 446 + '/xrpc/dev.atpkeyserver.alpha.group.listDelegates', 447 + this.keyserverUrl, 448 + ) 449 + url.searchParams.set('group_id', params.group_id) 450 + 451 + const lxm = 'dev.atpkeyserver.alpha.group.listDelegates' 452 + const token = await this.authManager.getToken(this.keyserverDid, lxm) 453 + 454 + const response = await this.fetchWithRetry(url.toString(), { 455 + method: 'GET', 456 + headers: { 457 + Authorization: `Bearer ${token}`, 458 + }, 459 + }) 460 + 461 + if (!response.ok) { 462 + await this.handleErrorResponse(response) 463 + } 464 + 465 + return await response.json() 466 + } 301 467 }