@hypercerts-org/sdk-core 0.2.0-beta.0 → 0.5.0-beta.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.
package/dist/index.d.ts CHANGED
@@ -766,9 +766,10 @@ declare const OrganizationSchema: z.ZodObject<{
766
766
  /**
767
767
  * How the current user relates to this organization.
768
768
  * - `"owner"`: User created or owns the organization
769
- * - `"collaborator"`: User was invited to collaborate
769
+ * - `"shared"`: User was invited to collaborate (has permissions)
770
+ * - `"none"`: User has no access to this organization
770
771
  */
771
- accessType: z.ZodEnum<["owner", "collaborator"]>;
772
+ accessType: z.ZodEnum<["owner", "shared", "none"]>;
772
773
  }, "strip", z.ZodTypeAny, {
773
774
  did: string;
774
775
  handle: string;
@@ -782,7 +783,7 @@ declare const OrganizationSchema: z.ZodObject<{
782
783
  admin: boolean;
783
784
  owner: boolean;
784
785
  };
785
- accessType: "owner" | "collaborator";
786
+ accessType: "owner" | "shared" | "none";
786
787
  description?: string | undefined;
787
788
  }, {
788
789
  did: string;
@@ -797,7 +798,7 @@ declare const OrganizationSchema: z.ZodObject<{
797
798
  admin: boolean;
798
799
  owner: boolean;
799
800
  };
800
- accessType: "owner" | "collaborator";
801
+ accessType: "owner" | "shared" | "none";
801
802
  description?: string | undefined;
802
803
  }>;
803
804
  /**
@@ -1022,7 +1023,7 @@ interface OrganizationInfo {
1022
1023
  name: string;
1023
1024
  description?: string;
1024
1025
  createdAt: string;
1025
- accessType: "owner" | "collaborator";
1026
+ accessType: "owner" | "shared" | "none";
1026
1027
  permissions: CollaboratorPermissions;
1027
1028
  collaboratorCount?: number;
1028
1029
  profile?: {
@@ -1089,16 +1090,6 @@ interface HypercertWithMetadata {
1089
1090
  record: HypercertClaim;
1090
1091
  }
1091
1092
 
1092
- /**
1093
- * Repository interfaces - Operation contracts for repository functionality.
1094
- *
1095
- * This module defines the interfaces for all repository operations,
1096
- * providing clear contracts for record management, blob handling,
1097
- * profile management, and domain-specific operations.
1098
- *
1099
- * @packageDocumentation
1100
- */
1101
-
1102
1093
  /**
1103
1094
  * Parameters for creating a new hypercert.
1104
1095
  *
@@ -1845,6 +1836,17 @@ interface HypercertOperations extends EventEmitter<HypercertEvents> {
1845
1836
  * const hasAccess = await repo.collaborators.hasAccess("did:plc:someone");
1846
1837
  * const role = await repo.collaborators.getRole("did:plc:someone");
1847
1838
  *
1839
+ * // Get current user permissions
1840
+ * const permissions = await repo.collaborators.getPermissions();
1841
+ * if (permissions.admin) {
1842
+ * // Can manage collaborators
1843
+ * }
1844
+ *
1845
+ * // Transfer ownership
1846
+ * await repo.collaborators.transferOwnership({
1847
+ * newOwnerDid: "did:plc:new-owner",
1848
+ * });
1849
+ *
1848
1850
  * // Revoke access
1849
1851
  * await repo.collaborators.revoke({ userDid: "did:plc:former-user" });
1850
1852
  * ```
@@ -1873,9 +1875,18 @@ interface CollaboratorOperations {
1873
1875
  /**
1874
1876
  * Lists all collaborators on the repository.
1875
1877
  *
1876
- * @returns Promise resolving to array of access grants
1878
+ * @param params - Optional pagination parameters
1879
+ * @param params.limit - Maximum number of results (1-100, default 50)
1880
+ * @param params.cursor - Pagination cursor from previous response
1881
+ * @returns Promise resolving to collaborators and optional cursor
1877
1882
  */
1878
- list(): Promise<RepositoryAccessGrant[]>;
1883
+ list(params?: {
1884
+ limit?: number;
1885
+ cursor?: string;
1886
+ }): Promise<{
1887
+ collaborators: RepositoryAccessGrant[];
1888
+ cursor?: string;
1889
+ }>;
1879
1890
  /**
1880
1891
  * Checks if a user has any access to the repository.
1881
1892
  *
@@ -1890,6 +1901,24 @@ interface CollaboratorOperations {
1890
1901
  * @returns Promise resolving to role, or `null` if no access
1891
1902
  */
1892
1903
  getRole(userDid: string): Promise<RepositoryRole | null>;
1904
+ /**
1905
+ * Gets the current user's permissions for this repository.
1906
+ *
1907
+ * @returns Promise resolving to permission flags
1908
+ */
1909
+ getPermissions(): Promise<CollaboratorPermissions>;
1910
+ /**
1911
+ * Transfers repository ownership to another user.
1912
+ *
1913
+ * **WARNING**: This action is irreversible. The new owner will have
1914
+ * full control of the repository.
1915
+ *
1916
+ * @param params - Transfer parameters
1917
+ * @param params.newOwnerDid - DID of the user to transfer ownership to
1918
+ */
1919
+ transferOwnership(params: {
1920
+ newOwnerDid: string;
1921
+ }): Promise<void>;
1893
1922
  }
1894
1923
  /**
1895
1924
  * Organization operations for SDS organization management.
@@ -1936,9 +1965,18 @@ interface OrganizationOperations {
1936
1965
  /**
1937
1966
  * Lists organizations the current user has access to.
1938
1967
  *
1939
- * @returns Promise resolving to array of organization info
1968
+ * @param params - Optional pagination parameters
1969
+ * @param params.limit - Maximum number of results (1-100, default 50)
1970
+ * @param params.cursor - Pagination cursor from previous response
1971
+ * @returns Promise resolving to organizations and optional cursor
1940
1972
  */
1941
- list(): Promise<OrganizationInfo[]>;
1973
+ list(params?: {
1974
+ limit?: number;
1975
+ cursor?: string;
1976
+ }): Promise<{
1977
+ organizations: OrganizationInfo[];
1978
+ cursor?: string;
1979
+ }>;
1942
1980
  }
1943
1981
 
1944
1982
  /**
package/dist/index.mjs CHANGED
@@ -1669,7 +1669,7 @@ class BlobOperationsImpl {
1669
1669
  throw new NetworkError("Failed to upload blob");
1670
1670
  }
1671
1671
  return {
1672
- ref: result.data.blob.ref,
1672
+ ref: { $link: result.data.blob.ref.toString() },
1673
1673
  mimeType: result.data.blob.mimeType,
1674
1674
  size: result.data.blob.size,
1675
1675
  };
@@ -2176,7 +2176,7 @@ class HypercertOperationsImpl extends EventEmitter {
2176
2176
  if (uploadResult.success) {
2177
2177
  imageBlobRef = {
2178
2178
  $type: "blob",
2179
- ref: uploadResult.data.blob.ref,
2179
+ ref: { $link: uploadResult.data.blob.ref.toString() },
2180
2180
  mimeType: uploadResult.data.blob.mimeType,
2181
2181
  size: uploadResult.data.blob.size,
2182
2182
  };
@@ -2601,7 +2601,7 @@ class HypercertOperationsImpl extends EventEmitter {
2601
2601
  if (uploadResult.success) {
2602
2602
  locationValue = {
2603
2603
  $type: "blob",
2604
- ref: uploadResult.data.blob.ref,
2604
+ ref: { $link: uploadResult.data.blob.ref.toString() },
2605
2605
  mimeType: uploadResult.data.blob.mimeType,
2606
2606
  size: uploadResult.data.blob.size,
2607
2607
  };
@@ -2886,7 +2886,7 @@ class HypercertOperationsImpl extends EventEmitter {
2886
2886
  if (uploadResult.success) {
2887
2887
  coverPhotoRef = {
2888
2888
  $type: "blob",
2889
- ref: uploadResult.data.blob.ref,
2889
+ ref: { $link: uploadResult.data.blob.ref.toString() },
2890
2890
  mimeType: uploadResult.data.blob.mimeType,
2891
2891
  size: uploadResult.data.blob.size,
2892
2892
  };
@@ -3040,9 +3040,11 @@ class HypercertOperationsImpl extends EventEmitter {
3040
3040
  * - `owner`: Full control including ownership management
3041
3041
  *
3042
3042
  * **SDS API Endpoints Used**:
3043
- * - `com.atproto.sds.grantAccess`: Grant access to a user
3044
- * - `com.atproto.sds.revokeAccess`: Revoke access from a user
3045
- * - `com.atproto.sds.listCollaborators`: List all collaborators
3043
+ * - `com.sds.repo.grantAccess`: Grant access to a user
3044
+ * - `com.sds.repo.revokeAccess`: Revoke access from a user
3045
+ * - `com.sds.repo.listCollaborators`: List all collaborators
3046
+ * - `com.sds.repo.getPermissions`: Get current user's permissions
3047
+ * - `com.sds.repo.transferOwnership`: Transfer repository ownership
3046
3048
  *
3047
3049
  * @example
3048
3050
  * ```typescript
@@ -3115,6 +3117,26 @@ class CollaboratorOperationsImpl {
3115
3117
  return "editor";
3116
3118
  return "viewer";
3117
3119
  }
3120
+ /**
3121
+ * Converts a permission string array to a permissions object.
3122
+ *
3123
+ * The SDS API returns permissions as an array of strings (e.g., ["read", "create"]).
3124
+ * This method converts them to the boolean flag format used by the SDK.
3125
+ *
3126
+ * @param permissionArray - Array of permission strings from SDS API
3127
+ * @returns Permission flags object
3128
+ * @internal
3129
+ */
3130
+ parsePermissions(permissionArray) {
3131
+ return {
3132
+ read: permissionArray.includes("read"),
3133
+ create: permissionArray.includes("create"),
3134
+ update: permissionArray.includes("update"),
3135
+ delete: permissionArray.includes("delete"),
3136
+ admin: permissionArray.includes("admin"),
3137
+ owner: permissionArray.includes("owner"),
3138
+ };
3139
+ }
3118
3140
  /**
3119
3141
  * Grants repository access to a user.
3120
3142
  *
@@ -3144,7 +3166,7 @@ class CollaboratorOperationsImpl {
3144
3166
  */
3145
3167
  async grant(params) {
3146
3168
  const permissions = this.roleToPermissions(params.role);
3147
- const response = await this.session.fetchHandler(`${this.serverUrl}/xrpc/com.atproto.sds.grantAccess`, {
3169
+ const response = await this.session.fetchHandler(`${this.serverUrl}/xrpc/com.sds.repo.grantAccess`, {
3148
3170
  method: "POST",
3149
3171
  headers: { "Content-Type": "application/json" },
3150
3172
  body: JSON.stringify({
@@ -3176,7 +3198,7 @@ class CollaboratorOperationsImpl {
3176
3198
  * ```
3177
3199
  */
3178
3200
  async revoke(params) {
3179
- const response = await this.session.fetchHandler(`${this.serverUrl}/xrpc/com.atproto.sds.revokeAccess`, {
3201
+ const response = await this.session.fetchHandler(`${this.serverUrl}/xrpc/com.sds.repo.revokeAccess`, {
3180
3202
  method: "POST",
3181
3203
  headers: { "Content-Type": "application/json" },
3182
3204
  body: JSON.stringify({
@@ -3191,7 +3213,10 @@ class CollaboratorOperationsImpl {
3191
3213
  /**
3192
3214
  * Lists all collaborators on the repository.
3193
3215
  *
3194
- * @returns Promise resolving to array of access grants
3216
+ * @param params - Optional pagination parameters
3217
+ * @param params.limit - Maximum number of results (1-100, default 50)
3218
+ * @param params.cursor - Pagination cursor from previous response
3219
+ * @returns Promise resolving to collaborators and optional cursor
3195
3220
  * @throws {@link NetworkError} if the list operation fails
3196
3221
  *
3197
3222
  * @remarks
@@ -3200,34 +3225,49 @@ class CollaboratorOperationsImpl {
3200
3225
  *
3201
3226
  * @example
3202
3227
  * ```typescript
3203
- * const collaborators = await repo.collaborators.list();
3228
+ * // Get first page
3229
+ * const page1 = await repo.collaborators.list({ limit: 10 });
3230
+ * console.log(`Found ${page1.collaborators.length} collaborators`);
3231
+ *
3232
+ * // Get next page if available
3233
+ * if (page1.cursor) {
3234
+ * const page2 = await repo.collaborators.list({ limit: 10, cursor: page1.cursor });
3235
+ * }
3204
3236
  *
3205
3237
  * // Filter active collaborators
3206
- * const active = collaborators.filter(c => !c.revokedAt);
3207
- *
3208
- * // Group by role
3209
- * const byRole = {
3210
- * owners: active.filter(c => c.role === "owner"),
3211
- * admins: active.filter(c => c.role === "admin"),
3212
- * editors: active.filter(c => c.role === "editor"),
3213
- * viewers: active.filter(c => c.role === "viewer"),
3214
- * };
3238
+ * const active = page1.collaborators.filter(c => !c.revokedAt);
3215
3239
  * ```
3216
3240
  */
3217
- async list() {
3218
- const response = await this.session.fetchHandler(`${this.serverUrl}/xrpc/com.atproto.sds.listCollaborators?repo=${encodeURIComponent(this.repoDid)}`, { method: "GET" });
3241
+ async list(params) {
3242
+ const queryParams = new URLSearchParams({
3243
+ repo: this.repoDid,
3244
+ });
3245
+ if (params?.limit !== undefined) {
3246
+ queryParams.set("limit", params.limit.toString());
3247
+ }
3248
+ if (params?.cursor) {
3249
+ queryParams.set("cursor", params.cursor);
3250
+ }
3251
+ const response = await this.session.fetchHandler(`${this.serverUrl}/xrpc/com.sds.repo.listCollaborators?${queryParams.toString()}`, { method: "GET" });
3219
3252
  if (!response.ok) {
3220
3253
  throw new NetworkError(`Failed to list collaborators: ${response.statusText}`);
3221
3254
  }
3222
3255
  const data = await response.json();
3223
- return (data.collaborators || []).map((c) => ({
3224
- userDid: c.userDid,
3225
- role: this.permissionsToRole(c.permissions),
3226
- permissions: c.permissions,
3227
- grantedBy: c.grantedBy,
3228
- grantedAt: c.grantedAt,
3229
- revokedAt: c.revokedAt,
3230
- }));
3256
+ const collaborators = (data.collaborators || []).map((c) => {
3257
+ const permissions = this.parsePermissions(c.permissions);
3258
+ return {
3259
+ userDid: c.userDid,
3260
+ role: this.permissionsToRole(permissions),
3261
+ permissions: permissions,
3262
+ grantedBy: c.grantedBy,
3263
+ grantedAt: c.grantedAt,
3264
+ revokedAt: c.revokedAt,
3265
+ };
3266
+ });
3267
+ return {
3268
+ collaborators,
3269
+ cursor: data.cursor,
3270
+ };
3231
3271
  }
3232
3272
  /**
3233
3273
  * Checks if a user has any access to the repository.
@@ -3250,7 +3290,7 @@ class CollaboratorOperationsImpl {
3250
3290
  */
3251
3291
  async hasAccess(userDid) {
3252
3292
  try {
3253
- const collaborators = await this.list();
3293
+ const { collaborators } = await this.list();
3254
3294
  return collaborators.some((c) => c.userDid === userDid && !c.revokedAt);
3255
3295
  }
3256
3296
  catch {
@@ -3272,10 +3312,108 @@ class CollaboratorOperationsImpl {
3272
3312
  * ```
3273
3313
  */
3274
3314
  async getRole(userDid) {
3275
- const collaborators = await this.list();
3315
+ const { collaborators } = await this.list();
3276
3316
  const collab = collaborators.find((c) => c.userDid === userDid && !c.revokedAt);
3277
3317
  return collab?.role ?? null;
3278
3318
  }
3319
+ /**
3320
+ * Gets the current user's permissions for this repository.
3321
+ *
3322
+ * @returns Promise resolving to the permission flags
3323
+ * @throws {@link NetworkError} if the request fails
3324
+ *
3325
+ * @remarks
3326
+ * This is useful for checking what actions the current user can perform
3327
+ * before attempting operations that might fail due to insufficient permissions.
3328
+ *
3329
+ * @example
3330
+ * ```typescript
3331
+ * const permissions = await repo.collaborators.getPermissions();
3332
+ *
3333
+ * if (permissions.admin) {
3334
+ * // Show admin UI
3335
+ * console.log("You can manage collaborators");
3336
+ * }
3337
+ *
3338
+ * if (permissions.create) {
3339
+ * console.log("You can create records");
3340
+ * }
3341
+ * ```
3342
+ *
3343
+ * @example Conditional UI rendering
3344
+ * ```typescript
3345
+ * const permissions = await repo.collaborators.getPermissions();
3346
+ *
3347
+ * // Show/hide UI elements based on permissions
3348
+ * const canEdit = permissions.update;
3349
+ * const canDelete = permissions.delete;
3350
+ * const isAdmin = permissions.admin;
3351
+ * const isOwner = permissions.owner;
3352
+ * ```
3353
+ */
3354
+ async getPermissions() {
3355
+ const response = await this.session.fetchHandler(`${this.serverUrl}/xrpc/com.sds.repo.getPermissions?repo=${encodeURIComponent(this.repoDid)}`, { method: "GET" });
3356
+ if (!response.ok) {
3357
+ throw new NetworkError(`Failed to get permissions: ${response.statusText}`);
3358
+ }
3359
+ const data = await response.json();
3360
+ return data.permissions;
3361
+ }
3362
+ /**
3363
+ * Transfers repository ownership to another user.
3364
+ *
3365
+ * @param params - Transfer parameters
3366
+ * @param params.newOwnerDid - DID of the user to transfer ownership to
3367
+ * @throws {@link NetworkError} if the transfer fails
3368
+ *
3369
+ * @remarks
3370
+ * **IMPORTANT**: This action is irreversible. Once ownership is transferred:
3371
+ * - The new owner gains full control of the repository
3372
+ * - Your role will be changed to admin (or specified role)
3373
+ * - You cannot transfer ownership back without the new owner's approval
3374
+ *
3375
+ * **Requirements**:
3376
+ * - You must be the current owner
3377
+ * - The new owner must have an existing account
3378
+ * - The new owner will be notified of the ownership transfer
3379
+ *
3380
+ * @example
3381
+ * ```typescript
3382
+ * // Transfer ownership to another user
3383
+ * await repo.collaborators.transferOwnership({
3384
+ * newOwnerDid: "did:plc:new-owner",
3385
+ * });
3386
+ *
3387
+ * console.log("Ownership transferred successfully");
3388
+ * // You are now an admin, not the owner
3389
+ * ```
3390
+ *
3391
+ * @example With confirmation
3392
+ * ```typescript
3393
+ * const confirmTransfer = await askUser(
3394
+ * "Are you sure you want to transfer ownership? This cannot be undone."
3395
+ * );
3396
+ *
3397
+ * if (confirmTransfer) {
3398
+ * await repo.collaborators.transferOwnership({
3399
+ * newOwnerDid: "did:plc:new-owner",
3400
+ * });
3401
+ * }
3402
+ * ```
3403
+ */
3404
+ async transferOwnership(params) {
3405
+ const response = await this.session.fetchHandler(`${this.serverUrl}/xrpc/com.sds.repo.transferOwnership`, {
3406
+ method: "POST",
3407
+ headers: { "Content-Type": "application/json" },
3408
+ body: JSON.stringify({
3409
+ repo: this.repoDid,
3410
+ newOwner: params.newOwnerDid,
3411
+ }),
3412
+ });
3413
+ if (!response.ok) {
3414
+ throw new NetworkError(`Failed to transfer ownership: ${response.statusText}`);
3415
+ }
3416
+ }
3279
3417
  }
3280
3418
 
3281
3419
  /**
@@ -3302,8 +3440,8 @@ class CollaboratorOperationsImpl {
3302
3440
  * {@link Repository.organizations} on an SDS-connected repository.
3303
3441
  *
3304
3442
  * **SDS API Endpoints Used**:
3305
- * - `com.atproto.sds.createRepository`: Create a new organization
3306
- * - `com.atproto.sds.listRepositories`: List accessible organizations
3443
+ * - `com.sds.organization.create`: Create a new organization
3444
+ * - `com.sds.organization.list`: List accessible organizations
3307
3445
  *
3308
3446
  * **Access Types**:
3309
3447
  * - `"owner"`: User created or owns the organization
@@ -3381,10 +3519,17 @@ class OrganizationOperationsImpl {
3381
3519
  * ```
3382
3520
  */
3383
3521
  async create(params) {
3384
- const response = await this.session.fetchHandler(`${this.serverUrl}/xrpc/com.atproto.sds.createRepository`, {
3522
+ const userDid = this.session.did || this.session.sub;
3523
+ if (!userDid) {
3524
+ throw new NetworkError("No authenticated user found");
3525
+ }
3526
+ const response = await this.session.fetchHandler(`${this.serverUrl}/xrpc/com.sds.organization.create`, {
3385
3527
  method: "POST",
3386
3528
  headers: { "Content-Type": "application/json" },
3387
- body: JSON.stringify(params),
3529
+ body: JSON.stringify({
3530
+ ...params,
3531
+ creatorDid: userDid,
3532
+ }),
3388
3533
  });
3389
3534
  if (!response.ok) {
3390
3535
  throw new NetworkError(`Failed to create organization: ${response.statusText}`);
@@ -3396,8 +3541,15 @@ class OrganizationOperationsImpl {
3396
3541
  name: data.name,
3397
3542
  description: data.description,
3398
3543
  createdAt: data.createdAt || new Date().toISOString(),
3399
- accessType: "owner",
3400
- permissions: { read: true, create: true, update: true, delete: true, admin: true, owner: true },
3544
+ accessType: data.accessType || "owner",
3545
+ permissions: data.permissions || {
3546
+ read: true,
3547
+ create: true,
3548
+ update: true,
3549
+ delete: true,
3550
+ admin: true,
3551
+ owner: true,
3552
+ },
3401
3553
  };
3402
3554
  }
3403
3555
  /**
@@ -3424,8 +3576,8 @@ class OrganizationOperationsImpl {
3424
3576
  */
3425
3577
  async get(did) {
3426
3578
  try {
3427
- const orgs = await this.list();
3428
- return orgs.find((o) => o.did === did) ?? null;
3579
+ const { organizations } = await this.list();
3580
+ return organizations.find((o) => o.did === did) ?? null;
3429
3581
  }
3430
3582
  catch {
3431
3583
  return null;
@@ -3434,7 +3586,10 @@ class OrganizationOperationsImpl {
3434
3586
  /**
3435
3587
  * Lists organizations the current user has access to.
3436
3588
  *
3437
- * @returns Promise resolving to array of organization info
3589
+ * @param params - Optional pagination parameters
3590
+ * @param params.limit - Maximum number of results (1-100, default 50)
3591
+ * @param params.cursor - Pagination cursor from previous response
3592
+ * @returns Promise resolving to organizations and optional cursor
3438
3593
  * @throws {@link NetworkError} if the list operation fails
3439
3594
  *
3440
3595
  * @remarks
@@ -3446,21 +3601,25 @@ class OrganizationOperationsImpl {
3446
3601
  *
3447
3602
  * @example
3448
3603
  * ```typescript
3449
- * const orgs = await repo.organizations.list();
3604
+ * // Get first page
3605
+ * const page1 = await repo.organizations.list({ limit: 20 });
3606
+ * console.log(`Found ${page1.organizations.length} organizations`);
3450
3607
  *
3451
- * // Filter by access type
3452
- * const owned = orgs.filter(o => o.accessType === "owner");
3453
- * const collaborated = orgs.filter(o => o.accessType === "collaborator");
3608
+ * // Get next page if available
3609
+ * if (page1.cursor) {
3610
+ * const page2 = await repo.organizations.list({ limit: 20, cursor: page1.cursor });
3611
+ * }
3454
3612
  *
3455
- * console.log(`You own ${owned.length} organizations`);
3456
- * console.log(`You collaborate on ${collaborated.length} organizations`);
3613
+ * // Filter by access type
3614
+ * const owned = page1.organizations.filter(o => o.accessType === "owner");
3615
+ * const shared = page1.organizations.filter(o => o.accessType === "shared");
3457
3616
  * ```
3458
3617
  *
3459
3618
  * @example Display organization details
3460
3619
  * ```typescript
3461
- * const orgs = await repo.organizations.list();
3620
+ * const { organizations } = await repo.organizations.list();
3462
3621
  *
3463
- * for (const org of orgs) {
3622
+ * for (const org of organizations) {
3464
3623
  * console.log(`${org.name} (@${org.handle})`);
3465
3624
  * console.log(` DID: ${org.did}`);
3466
3625
  * console.log(` Access: ${org.accessType}`);
@@ -3470,21 +3629,38 @@ class OrganizationOperationsImpl {
3470
3629
  * }
3471
3630
  * ```
3472
3631
  */
3473
- async list() {
3474
- const response = await this.session.fetchHandler(`${this.serverUrl}/xrpc/com.atproto.sds.listRepositories?userDid=${encodeURIComponent(this.session.did || this.session.sub)}`, { method: "GET" });
3632
+ async list(params) {
3633
+ const userDid = this.session.did || this.session.sub;
3634
+ if (!userDid) {
3635
+ throw new NetworkError("No authenticated user found");
3636
+ }
3637
+ const queryParams = new URLSearchParams({
3638
+ userDid,
3639
+ });
3640
+ if (params?.limit !== undefined) {
3641
+ queryParams.set("limit", params.limit.toString());
3642
+ }
3643
+ if (params?.cursor) {
3644
+ queryParams.set("cursor", params.cursor);
3645
+ }
3646
+ const response = await this.session.fetchHandler(`${this.serverUrl}/xrpc/com.sds.organization.list?${queryParams.toString()}`, { method: "GET" });
3475
3647
  if (!response.ok) {
3476
3648
  throw new NetworkError(`Failed to list organizations: ${response.statusText}`);
3477
3649
  }
3478
3650
  const data = await response.json();
3479
- return (data.repositories || []).map((r) => ({
3651
+ const organizations = (data.organizations || []).map((r) => ({
3480
3652
  did: r.did,
3481
3653
  handle: r.handle,
3482
3654
  name: r.name,
3483
3655
  description: r.description,
3484
- createdAt: new Date().toISOString(), // SDS may not return this
3656
+ createdAt: r.createdAt || new Date().toISOString(),
3485
3657
  accessType: r.accessType,
3486
3658
  permissions: r.permissions,
3487
3659
  }));
3660
+ return {
3661
+ organizations,
3662
+ cursor: data.cursor,
3663
+ };
3488
3664
  }
3489
3665
  }
3490
3666
 
@@ -4407,9 +4583,10 @@ const OrganizationSchema = z.object({
4407
4583
  /**
4408
4584
  * How the current user relates to this organization.
4409
4585
  * - `"owner"`: User created or owns the organization
4410
- * - `"collaborator"`: User was invited to collaborate
4586
+ * - `"shared"`: User was invited to collaborate (has permissions)
4587
+ * - `"none"`: User has no access to this organization
4411
4588
  */
4412
- accessType: z.enum(["owner", "collaborator"]),
4589
+ accessType: z.enum(["owner", "shared", "none"]),
4413
4590
  });
4414
4591
  /**
4415
4592
  * Zod schema for collaborator data.