Skip to content

Commit 99bd9e4

Browse files
committed
fix(sds): align organization and collaborator operations with SDS API contracts
- Add creatorDid parameter to organization.create endpoint - Change organization.list response parsing from repositories to organizations field - Update accessType values from owner|collaborator to owner|shared|none - Add permission string array parser for collaborator.list endpoint - Update type definitions to match actual SDS API response formats
1 parent 8c0b6e6 commit 99bd9e4

File tree

7 files changed

+68
-22
lines changed

7 files changed

+68
-22
lines changed

packages/lexicon/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@hypercerts-org/lexicon",
3-
"version": "0.3.0",
3+
"version": "0.4.0",
44
"description": "ATProto lexicon definitions and TypeScript types for the Hypercerts protocol",
55
"type": "module",
66
"main": "dist/index.cjs",

packages/sdk-core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@hypercerts-org/sdk-core",
3-
"version": "0.3.0",
3+
"version": "0.4.0",
44
"description": "Framework-agnostic ATProto SDK core for authentication, repository operations, and lexicon management",
55
"main": "dist/index.cjs",
66
"repository": {

packages/sdk-core/src/core/types.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,10 @@ export const OrganizationSchema = z.object({
185185
/**
186186
* How the current user relates to this organization.
187187
* - `"owner"`: User created or owns the organization
188-
* - `"collaborator"`: User was invited to collaborate
188+
* - `"shared"`: User was invited to collaborate (has permissions)
189+
* - `"none"`: User has no access to this organization
189190
*/
190-
accessType: z.enum(["owner", "collaborator"]),
191+
accessType: z.enum(["owner", "shared", "none"]),
191192
});
192193

193194
/**

packages/sdk-core/src/repository/CollaboratorOperationsImpl.ts

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,27 @@ export class CollaboratorOperationsImpl implements CollaboratorOperations {
107107
return "viewer";
108108
}
109109

110+
/**
111+
* Converts a permission string array to a permissions object.
112+
*
113+
* The SDS API returns permissions as an array of strings (e.g., ["read", "create"]).
114+
* This method converts them to the boolean flag format used by the SDK.
115+
*
116+
* @param permissionArray - Array of permission strings from SDS API
117+
* @returns Permission flags object
118+
* @internal
119+
*/
120+
private parsePermissions(permissionArray: string[]): CollaboratorPermissions {
121+
return {
122+
read: permissionArray.includes("read"),
123+
create: permissionArray.includes("create"),
124+
update: permissionArray.includes("update"),
125+
delete: permissionArray.includes("delete"),
126+
admin: permissionArray.includes("admin"),
127+
owner: permissionArray.includes("owner"),
128+
};
129+
}
130+
110131
/**
111132
* Grants repository access to a user.
112133
*
@@ -225,18 +246,21 @@ export class CollaboratorOperationsImpl implements CollaboratorOperations {
225246
return (data.collaborators || []).map(
226247
(c: {
227248
userDid: string;
228-
permissions: CollaboratorPermissions;
249+
permissions: string[]; // SDS API returns string array
229250
grantedBy: string;
230251
grantedAt: string;
231252
revokedAt?: string;
232-
}) => ({
233-
userDid: c.userDid,
234-
role: this.permissionsToRole(c.permissions),
235-
permissions: c.permissions,
236-
grantedBy: c.grantedBy,
237-
grantedAt: c.grantedAt,
238-
revokedAt: c.revokedAt,
239-
}),
253+
}) => {
254+
const permissions = this.parsePermissions(c.permissions);
255+
return {
256+
userDid: c.userDid,
257+
role: this.permissionsToRole(permissions),
258+
permissions: permissions,
259+
grantedBy: c.grantedBy,
260+
grantedAt: c.grantedAt,
261+
revokedAt: c.revokedAt,
262+
};
263+
},
240264
);
241265
}
242266

packages/sdk-core/src/repository/OrganizationOperationsImpl.ts

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,18 @@ export class OrganizationOperationsImpl implements OrganizationOperations {
109109
* ```
110110
*/
111111
async create(params: { name: string; description?: string; handle?: string }): Promise<OrganizationInfo> {
112+
const userDid = this.session.did || this.session.sub;
113+
if (!userDid) {
114+
throw new NetworkError("No authenticated user found");
115+
}
116+
112117
const response = await this.session.fetchHandler(`${this.serverUrl}/xrpc/com.sds.organization.create`, {
113118
method: "POST",
114119
headers: { "Content-Type": "application/json" },
115-
body: JSON.stringify(params),
120+
body: JSON.stringify({
121+
...params,
122+
creatorDid: userDid,
123+
}),
116124
});
117125

118126
if (!response.ok) {
@@ -126,8 +134,15 @@ export class OrganizationOperationsImpl implements OrganizationOperations {
126134
name: data.name,
127135
description: data.description,
128136
createdAt: data.createdAt || new Date().toISOString(),
129-
accessType: "owner",
130-
permissions: { read: true, create: true, update: true, delete: true, admin: true, owner: true },
137+
accessType: data.accessType || "owner",
138+
permissions: data.permissions || {
139+
read: true,
140+
create: true,
141+
update: true,
142+
delete: true,
143+
admin: true,
144+
owner: true,
145+
},
131146
};
132147
}
133148

@@ -202,8 +217,13 @@ export class OrganizationOperationsImpl implements OrganizationOperations {
202217
* ```
203218
*/
204219
async list(): Promise<OrganizationInfo[]> {
220+
const userDid = this.session.did || this.session.sub;
221+
if (!userDid) {
222+
throw new NetworkError("No authenticated user found");
223+
}
224+
205225
const response = await this.session.fetchHandler(
206-
`${this.serverUrl}/xrpc/com.sds.organization.list?userDid=${encodeURIComponent(this.session.did || this.session.sub)}`,
226+
`${this.serverUrl}/xrpc/com.sds.organization.list?userDid=${encodeURIComponent(userDid)}`,
207227
{ method: "GET" },
208228
);
209229

@@ -212,20 +232,21 @@ export class OrganizationOperationsImpl implements OrganizationOperations {
212232
}
213233

214234
const data = await response.json();
215-
return (data.repositories || []).map(
235+
return (data.organizations || []).map(
216236
(r: {
217237
did: string;
218238
handle: string;
219239
name: string;
220240
description?: string;
221-
accessType: "owner" | "collaborator";
241+
createdAt?: string;
242+
accessType: "owner" | "shared" | "none";
222243
permissions: CollaboratorPermissions;
223244
}) => ({
224245
did: r.did,
225246
handle: r.handle,
226247
name: r.name,
227248
description: r.description,
228-
createdAt: new Date().toISOString(), // SDS may not return this
249+
createdAt: r.createdAt || new Date().toISOString(),
229250
accessType: r.accessType,
230251
permissions: r.permissions,
231252
}),

packages/sdk-core/src/repository/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export interface OrganizationInfo {
8585
name: string;
8686
description?: string;
8787
createdAt: string;
88-
accessType: "owner" | "collaborator";
88+
accessType: "owner" | "shared" | "none";
8989
permissions: CollaboratorPermissions;
9090
collaboratorCount?: number;
9191
profile?: {

packages/sdk-react/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@hypercerts-org/sdk-react",
3-
"version": "0.3.0",
3+
"version": "0.4.0",
44
"description": "React hooks and components for the Hypercerts ATProto SDK",
55
"type": "module",
66
"main": "dist/index.cjs",

0 commit comments

Comments
 (0)