@arke-institute/sdk 0.1.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/README.md ADDED
@@ -0,0 +1,258 @@
1
+ # Arke SDK
2
+
3
+ TypeScript SDK for building applications on the Arke platform.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @arke/sdk
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { createClient } from '@arke/sdk';
15
+
16
+ const arke = createClient({
17
+ authToken: 'your-jwt-token',
18
+ });
19
+
20
+ // Create a collection
21
+ const collection = await arke.collections.create({
22
+ title: 'My Archive',
23
+ slug: 'my-archive',
24
+ });
25
+
26
+ // Upload files to create a new collection
27
+ const result = await arke.upload.createCollection({
28
+ files: './photos',
29
+ collectionMetadata: {
30
+ title: 'Photo Archive',
31
+ slug: 'photos',
32
+ },
33
+ });
34
+
35
+ // Query the knowledge graph
36
+ const results = await arke.query.natural(
37
+ 'Who are the people in photographs from Hawaii?'
38
+ );
39
+ ```
40
+
41
+ ## Packages
42
+
43
+ The SDK contains five packages:
44
+
45
+ | Package | Purpose | Auth Required |
46
+ |---------|---------|---------------|
47
+ | **collections** | Create/manage collections, members, invitations | Yes |
48
+ | **upload** | Upload files, create/add to collections | Yes |
49
+ | **edit** | Edit entities, trigger AI regeneration | Yes |
50
+ | **query** | Search and traverse the knowledge graph | No (public) |
51
+ | **content** | Read entities, download content | No (public) |
52
+
53
+ ### Package Dependency Graph
54
+
55
+ ```
56
+ collections (foundational)
57
+
58
+
59
+ ┌────┴────┐
60
+ │ │
61
+ upload edit
62
+
63
+ query (independent)
64
+ content (independent)
65
+ ```
66
+
67
+ ## Package Details
68
+
69
+ ### collections
70
+
71
+ ```typescript
72
+ // Create collection
73
+ await arke.collections.create({ title, slug, description, visibility });
74
+
75
+ // List collections
76
+ const collections = await arke.collections.list({ page: 1 });
77
+
78
+ // Manage members
79
+ await arke.members.updateRole(collectionId, userId, 'editor');
80
+
81
+ // Invitations
82
+ await arke.invitations.create(collectionId, { email, role: 'editor' });
83
+ await arke.invitations.accept(invitationId);
84
+ ```
85
+
86
+ ### upload
87
+
88
+ ```typescript
89
+ // Create new collection from files (anyone authenticated)
90
+ await arke.upload.createCollection({
91
+ files: './photos',
92
+ collectionMetadata: { title: 'My Archive', slug: 'my-archive' },
93
+ });
94
+
95
+ // Add to existing collection (requires membership)
96
+ await arke.upload.addToCollection({
97
+ files: './more-photos',
98
+ parentPi: 'pi:existing-root',
99
+ });
100
+ ```
101
+
102
+ ### edit
103
+
104
+ ```typescript
105
+ // Edit entity
106
+ const session = await arke.edit.createSession('pi:abc123');
107
+ session.setPrompt('Update the description');
108
+ const result = await session.submit();
109
+
110
+ // Trigger AI regeneration
111
+ await arke.edit.regenerate('pi:abc123');
112
+ ```
113
+
114
+ ### query
115
+
116
+ ```typescript
117
+ // Direct path query (requires knowing syntax)
118
+ await arke.query.path('"Hawaii" -[depicts]-> type:person');
119
+
120
+ // Natural language (LLM translates to path query)
121
+ await arke.query.natural('Who photographed Pearl Harbor?');
122
+
123
+ // Collection search
124
+ await arke.query.searchCollection(collectionId, 'family portraits');
125
+ ```
126
+
127
+ ### content
128
+
129
+ ```typescript
130
+ // Get entity
131
+ const entity = await arke.content.get('pi:abc123');
132
+
133
+ // Download content
134
+ const blob = await arke.content.download('pi:abc123');
135
+
136
+ // Get version history
137
+ const versions = await arke.content.versions('pi:abc123');
138
+ ```
139
+
140
+ ## Documentation
141
+
142
+ - [Architecture Overview](./ARCHITECTURE.md)
143
+ - [collections package](./packages/collections/PLAN.md)
144
+ - [upload package](./packages/upload/PLAN.md)
145
+ - [edit package](./packages/edit/PLAN.md)
146
+ - [query package](./packages/query/PLAN.md)
147
+ - [content package](./packages/content/PLAN.md)
148
+
149
+ ## Project Structure
150
+
151
+ ```
152
+ arke-sdk/
153
+ ├── src/
154
+ │ ├── index.ts # Main entry, createClient()
155
+ │ ├── client.ts # Base HTTP client
156
+ │ └── types.ts # Shared types
157
+ ├── packages/
158
+ │ ├── collections/
159
+ │ │ ├── index.ts # Package entry
160
+ │ │ ├── collections.ts # Collection CRUD
161
+ │ │ ├── members.ts # Membership operations
162
+ │ │ ├── invitations.ts # Invitation operations
163
+ │ │ └── types.ts
164
+ │ ├── upload/
165
+ │ │ ├── index.ts
166
+ │ │ ├── uploader.ts # Main uploader class
167
+ │ │ ├── create-collection.ts
168
+ │ │ ├── add-to-collection.ts
169
+ │ │ └── types.ts
170
+ │ ├── edit/
171
+ │ │ ├── index.ts
172
+ │ │ ├── session.ts # Edit session
173
+ │ │ ├── diff.ts # Diff engine
174
+ │ │ └── types.ts
175
+ │ ├── query/
176
+ │ │ ├── index.ts
177
+ │ │ ├── path-query.ts # Direct path queries
178
+ │ │ ├── natural-query.ts # NL queries
179
+ │ │ ├── collection-search.ts
180
+ │ │ └── types.ts
181
+ │ └── content/
182
+ │ ├── index.ts
183
+ │ ├── entities.ts # Entity operations
184
+ │ ├── download.ts # Content download
185
+ │ └── types.ts
186
+ ├── package.json
187
+ ├── tsconfig.json
188
+ └── README.md
189
+ ```
190
+
191
+ ## Distribution
192
+
193
+ The SDK is published to npm as `@arke/sdk`.
194
+
195
+ ### Building
196
+
197
+ ```bash
198
+ npm run build
199
+ ```
200
+
201
+ ### Publishing
202
+
203
+ ```bash
204
+ npm version patch|minor|major
205
+ npm publish
206
+ ```
207
+
208
+ ### Imports
209
+
210
+ Users can import the full SDK or specific packages:
211
+
212
+ ```typescript
213
+ // Full SDK
214
+ import { createClient } from '@arke/sdk';
215
+ const arke = createClient({ authToken });
216
+ arke.collections.create(...);
217
+
218
+ // Specific packages (tree-shakeable)
219
+ import { CollectionsClient } from '@arke/sdk/collections';
220
+ import { UploadClient } from '@arke/sdk/upload';
221
+ ```
222
+
223
+ ## Implementation Order
224
+
225
+ ### Backend (Workers)
226
+ 1. GraphDB Gateway - Add `is_collection_root` field + update endpoint
227
+ 2. Query Links - Add filter support for `is_collection_root`
228
+ 3. **Collections Worker** (new) - Manages collections in Supabase
229
+
230
+ ### SDK (This Repo)
231
+ 4. collections package
232
+ 5. content package
233
+ 6. upload package (refactor existing)
234
+ 7. edit package (refactor existing)
235
+ 8. query package
236
+
237
+ ### Consumers
238
+ 9. CLI (`arke-cli/`)
239
+ 10. Web Frontend
240
+
241
+ ## Backend Architecture
242
+
243
+ The SDK calls the Arke Gateway (`api.arke.institute`), which routes to workers:
244
+
245
+ | Route | Worker |
246
+ |-------|--------|
247
+ | `/collections/*`, `/me/*`, `/invitations/*` | Collections Worker |
248
+ | `/ingest/*` | Ingest Worker |
249
+ | `/api/*` | IPFS Wrapper |
250
+ | `/reprocess/*` | Reprocess API |
251
+ | `/query/*` | Query Links |
252
+ | `/translate/*` | Query Translator |
253
+
254
+ ## Related Repositories
255
+
256
+ - **Collections Worker** - Backend for collection management (new)
257
+ - **Arke CLI** (`arke-cli/`) - Command-line interface using this SDK
258
+ - **Arke Gateway** (`arke-gateway/`) - API gateway routing
@@ -0,0 +1 @@
1
+ export { ChangeRootPayload, ChangeRootResponse, Collection, CollectionDetails, CollectionRole, CollectionVisibility, CollectionsClient, CollectionsClientConfig, CollectionsError, CreateCollectionPayload, Invitation, InvitationsResponse, Member, MembersResponse, MyAccessResponse, MyCollectionsResponse, PaginatedCollections, PiPermissions, RegisterRootPayload, RootResponse, SuccessResponse, UpdateCollectionPayload } from '../index.mjs';
@@ -0,0 +1 @@
1
+ export { ChangeRootPayload, ChangeRootResponse, Collection, CollectionDetails, CollectionRole, CollectionVisibility, CollectionsClient, CollectionsClientConfig, CollectionsError, CreateCollectionPayload, Invitation, InvitationsResponse, Member, MembersResponse, MyAccessResponse, MyCollectionsResponse, PaginatedCollections, PiPermissions, RegisterRootPayload, RootResponse, SuccessResponse, UpdateCollectionPayload } from '../index.js';
@@ -0,0 +1,232 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/collections/index.ts
21
+ var collections_exports = {};
22
+ __export(collections_exports, {
23
+ CollectionsClient: () => CollectionsClient,
24
+ CollectionsError: () => CollectionsError
25
+ });
26
+ module.exports = __toCommonJS(collections_exports);
27
+
28
+ // src/collections/errors.ts
29
+ var CollectionsError = class extends Error {
30
+ constructor(message, code = "UNKNOWN_ERROR", details) {
31
+ super(message);
32
+ this.code = code;
33
+ this.details = details;
34
+ this.name = "CollectionsError";
35
+ }
36
+ };
37
+
38
+ // src/collections/client.ts
39
+ var CollectionsClient = class {
40
+ constructor(config) {
41
+ this.baseUrl = config.gatewayUrl.replace(/\/$/, "");
42
+ this.authToken = config.authToken;
43
+ this.fetchImpl = config.fetchImpl ?? fetch;
44
+ }
45
+ setAuthToken(token) {
46
+ this.authToken = token;
47
+ }
48
+ // ---------------------------------------------------------------------------
49
+ // Request helpers
50
+ // ---------------------------------------------------------------------------
51
+ buildUrl(path, query) {
52
+ const url = new URL(`${this.baseUrl}${path}`);
53
+ if (query) {
54
+ Object.entries(query).forEach(([key, value]) => {
55
+ if (value !== void 0 && value !== null) {
56
+ url.searchParams.set(key, String(value));
57
+ }
58
+ });
59
+ }
60
+ return url.toString();
61
+ }
62
+ getHeaders(authRequired) {
63
+ const headers = { "Content-Type": "application/json" };
64
+ if (authRequired || this.authToken) {
65
+ if (!this.authToken && authRequired) {
66
+ throw new CollectionsError("Authentication required for this operation", "AUTH_REQUIRED");
67
+ }
68
+ if (this.authToken) {
69
+ headers["Authorization"] = `Bearer ${this.authToken}`;
70
+ }
71
+ }
72
+ return headers;
73
+ }
74
+ async request(path, options = {}) {
75
+ const authRequired = options.authRequired ?? false;
76
+ const url = this.buildUrl(path, options.query);
77
+ const headers = new Headers(this.getHeaders(authRequired));
78
+ if (options.headers) {
79
+ Object.entries(options.headers).forEach(([k, v]) => {
80
+ if (v !== void 0) headers.set(k, v);
81
+ });
82
+ }
83
+ const response = await this.fetchImpl(url, { ...options, headers });
84
+ if (response.ok) {
85
+ if (response.status === 204) {
86
+ return void 0;
87
+ }
88
+ const contentType = response.headers.get("content-type") || "";
89
+ if (contentType.includes("application/json")) {
90
+ return await response.json();
91
+ }
92
+ return await response.text();
93
+ }
94
+ let body;
95
+ try {
96
+ body = await response.json();
97
+ } catch {
98
+ body = await response.text();
99
+ }
100
+ const message = body?.error && typeof body.error === "string" ? body.error : `Request failed with status ${response.status}`;
101
+ throw new CollectionsError(message, "HTTP_ERROR", {
102
+ status: response.status,
103
+ body
104
+ });
105
+ }
106
+ // ---------------------------------------------------------------------------
107
+ // Collections
108
+ // ---------------------------------------------------------------------------
109
+ async listCollections(params) {
110
+ return this.request("/collections", {
111
+ method: "GET",
112
+ query: { limit: params?.limit, offset: params?.offset }
113
+ });
114
+ }
115
+ async getCollection(id) {
116
+ return this.request(`/collections/${id}`, { method: "GET" });
117
+ }
118
+ async getCollectionRoot(id) {
119
+ return this.request(`/collections/${id}/root`, { method: "GET" });
120
+ }
121
+ async getMyAccess(id) {
122
+ return this.request(`/collections/${id}/my-access`, { method: "GET", authRequired: true });
123
+ }
124
+ async createCollection(payload) {
125
+ return this.request("/collections", {
126
+ method: "POST",
127
+ authRequired: true,
128
+ body: JSON.stringify(payload)
129
+ });
130
+ }
131
+ async registerRoot(payload) {
132
+ return this.request("/collections/register-root", {
133
+ method: "POST",
134
+ authRequired: true,
135
+ body: JSON.stringify(payload)
136
+ });
137
+ }
138
+ async updateCollection(id, payload) {
139
+ return this.request(`/collections/${id}`, {
140
+ method: "PATCH",
141
+ authRequired: true,
142
+ body: JSON.stringify(payload)
143
+ });
144
+ }
145
+ async changeRoot(id, payload) {
146
+ return this.request(`/collections/${id}/change-root`, {
147
+ method: "PATCH",
148
+ authRequired: true,
149
+ body: JSON.stringify(payload)
150
+ });
151
+ }
152
+ async deleteCollection(id) {
153
+ return this.request(`/collections/${id}`, {
154
+ method: "DELETE",
155
+ authRequired: true
156
+ });
157
+ }
158
+ // ---------------------------------------------------------------------------
159
+ // Members
160
+ // ---------------------------------------------------------------------------
161
+ async listMembers(collectionId) {
162
+ return this.request(`/collections/${collectionId}/members`, { method: "GET" });
163
+ }
164
+ async updateMemberRole(collectionId, userId, role) {
165
+ return this.request(`/collections/${collectionId}/members/${userId}`, {
166
+ method: "PATCH",
167
+ authRequired: true,
168
+ body: JSON.stringify({ role })
169
+ });
170
+ }
171
+ async removeMember(collectionId, userId) {
172
+ return this.request(`/collections/${collectionId}/members/${userId}`, {
173
+ method: "DELETE",
174
+ authRequired: true
175
+ });
176
+ }
177
+ // ---------------------------------------------------------------------------
178
+ // Invitations
179
+ // ---------------------------------------------------------------------------
180
+ async createInvitation(collectionId, email, role) {
181
+ return this.request(`/collections/${collectionId}/invitations`, {
182
+ method: "POST",
183
+ authRequired: true,
184
+ body: JSON.stringify({ email, role })
185
+ });
186
+ }
187
+ async listInvitations(collectionId) {
188
+ return this.request(`/collections/${collectionId}/invitations`, {
189
+ method: "GET",
190
+ authRequired: true
191
+ });
192
+ }
193
+ async acceptInvitation(invitationId) {
194
+ return this.request(`/invitations/${invitationId}/accept`, {
195
+ method: "POST",
196
+ authRequired: true
197
+ });
198
+ }
199
+ async declineInvitation(invitationId) {
200
+ return this.request(`/invitations/${invitationId}/decline`, {
201
+ method: "POST",
202
+ authRequired: true
203
+ });
204
+ }
205
+ async revokeInvitation(invitationId) {
206
+ return this.request(`/invitations/${invitationId}`, {
207
+ method: "DELETE",
208
+ authRequired: true
209
+ });
210
+ }
211
+ // ---------------------------------------------------------------------------
212
+ // Current user
213
+ // ---------------------------------------------------------------------------
214
+ async getMyCollections() {
215
+ return this.request("/me/collections", { method: "GET", authRequired: true });
216
+ }
217
+ async getMyInvitations() {
218
+ return this.request("/me/invitations", { method: "GET", authRequired: true });
219
+ }
220
+ // ---------------------------------------------------------------------------
221
+ // PI permissions
222
+ // ---------------------------------------------------------------------------
223
+ async getPiPermissions(pi) {
224
+ return this.request(`/pi/${pi}/permissions`, { method: "GET" });
225
+ }
226
+ };
227
+ // Annotate the CommonJS export names for ESM import in node:
228
+ 0 && (module.exports = {
229
+ CollectionsClient,
230
+ CollectionsError
231
+ });
232
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/collections/index.ts","../../src/collections/errors.ts","../../src/collections/client.ts"],"sourcesContent":["export { CollectionsClient, type CollectionsClientConfig } from './client';\nexport { CollectionsError } from './errors';\nexport type {\n ChangeRootPayload,\n ChangeRootResponse,\n Collection,\n CollectionDetails,\n CollectionRole,\n CollectionVisibility,\n CreateCollectionPayload,\n Invitation,\n InvitationsResponse,\n Member,\n MembersResponse,\n MyAccessResponse,\n MyCollectionsResponse,\n PaginatedCollections,\n PiPermissions,\n RegisterRootPayload,\n RootResponse,\n SuccessResponse,\n UpdateCollectionPayload,\n} from './types';\n","export class CollectionsError extends Error {\n constructor(\n message: string,\n public code: string = 'UNKNOWN_ERROR',\n public details?: unknown\n ) {\n super(message);\n this.name = 'CollectionsError';\n }\n}\n","import { CollectionsError } from './errors';\nimport type {\n ChangeRootPayload,\n ChangeRootResponse,\n Collection,\n CollectionDetails,\n CollectionRole,\n CreateCollectionPayload,\n Invitation,\n InvitationsResponse,\n Member,\n MembersResponse,\n MyAccessResponse,\n MyCollectionsResponse,\n PaginatedCollections,\n PiPermissions,\n RegisterRootPayload,\n RootResponse,\n SuccessResponse,\n UpdateCollectionPayload,\n} from './types';\n\nexport interface CollectionsClientConfig {\n /**\n * Gateway base URL (e.g., https://api.arke.institute).\n * Must already point at the Arke gateway that proxies /collections/*.\n */\n gatewayUrl: string;\n /**\n * Optional bearer token for authenticated routes.\n * Public routes will still include it if provided.\n */\n authToken?: string;\n /**\n * Optional custom fetch (useful for testing).\n */\n fetchImpl?: typeof fetch;\n}\n\ntype JsonBody = Record<string, unknown>;\n\nexport class CollectionsClient {\n private baseUrl: string;\n private authToken?: string;\n private fetchImpl: typeof fetch;\n\n constructor(config: CollectionsClientConfig) {\n this.baseUrl = config.gatewayUrl.replace(/\\/$/, '');\n this.authToken = config.authToken;\n this.fetchImpl = config.fetchImpl ?? fetch;\n }\n\n setAuthToken(token?: string) {\n this.authToken = token;\n }\n\n // ---------------------------------------------------------------------------\n // Request helpers\n // ---------------------------------------------------------------------------\n\n private buildUrl(path: string, query?: Record<string, string | number | undefined>) {\n const url = new URL(`${this.baseUrl}${path}`);\n if (query) {\n Object.entries(query).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n });\n }\n return url.toString();\n }\n\n private getHeaders(authRequired: boolean): HeadersInit {\n const headers: HeadersInit = { 'Content-Type': 'application/json' };\n if (authRequired || this.authToken) {\n if (!this.authToken && authRequired) {\n throw new CollectionsError('Authentication required for this operation', 'AUTH_REQUIRED');\n }\n if (this.authToken) {\n headers['Authorization'] = `Bearer ${this.authToken}`;\n }\n }\n return headers;\n }\n\n private async request<T>(\n path: string,\n options: RequestInit & {\n authRequired?: boolean;\n query?: Record<string, string | number | undefined>;\n } = {}\n ): Promise<T> {\n const authRequired = options.authRequired ?? false;\n const url = this.buildUrl(path, options.query);\n const headers = new Headers(this.getHeaders(authRequired));\n if (options.headers) {\n Object.entries(options.headers).forEach(([k, v]) => {\n if (v !== undefined) headers.set(k, v as string);\n });\n }\n\n const response = await this.fetchImpl(url, { ...options, headers });\n\n if (response.ok) {\n if (response.status === 204) {\n return undefined as T;\n }\n const contentType = response.headers.get('content-type') || '';\n if (contentType.includes('application/json')) {\n return (await response.json()) as T;\n }\n return (await response.text()) as unknown as T;\n }\n\n let body: unknown;\n try {\n body = await response.json();\n } catch {\n body = await response.text();\n }\n\n const message =\n (body as JsonBody)?.error && typeof (body as JsonBody).error === 'string'\n ? ((body as JsonBody).error as string)\n : `Request failed with status ${response.status}`;\n\n throw new CollectionsError(message, 'HTTP_ERROR', {\n status: response.status,\n body,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Collections\n // ---------------------------------------------------------------------------\n\n async listCollections(params?: { limit?: number; offset?: number }): Promise<PaginatedCollections> {\n return this.request('/collections', {\n method: 'GET',\n query: { limit: params?.limit, offset: params?.offset },\n });\n }\n\n async getCollection(id: string): Promise<CollectionDetails> {\n return this.request(`/collections/${id}`, { method: 'GET' });\n }\n\n async getCollectionRoot(id: string): Promise<RootResponse> {\n return this.request(`/collections/${id}/root`, { method: 'GET' });\n }\n\n async getMyAccess(id: string): Promise<MyAccessResponse> {\n return this.request(`/collections/${id}/my-access`, { method: 'GET', authRequired: true });\n }\n\n async createCollection(payload: CreateCollectionPayload): Promise<Collection> {\n return this.request('/collections', {\n method: 'POST',\n authRequired: true,\n body: JSON.stringify(payload),\n });\n }\n\n async registerRoot(payload: RegisterRootPayload): Promise<Collection & { rootPi: string }> {\n return this.request('/collections/register-root', {\n method: 'POST',\n authRequired: true,\n body: JSON.stringify(payload),\n });\n }\n\n async updateCollection(id: string, payload: UpdateCollectionPayload): Promise<Collection> {\n return this.request(`/collections/${id}`, {\n method: 'PATCH',\n authRequired: true,\n body: JSON.stringify(payload),\n });\n }\n\n async changeRoot(id: string, payload: ChangeRootPayload): Promise<ChangeRootResponse> {\n return this.request(`/collections/${id}/change-root`, {\n method: 'PATCH',\n authRequired: true,\n body: JSON.stringify(payload),\n });\n }\n\n async deleteCollection(id: string): Promise<SuccessResponse> {\n return this.request(`/collections/${id}`, {\n method: 'DELETE',\n authRequired: true,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Members\n // ---------------------------------------------------------------------------\n\n async listMembers(collectionId: string): Promise<MembersResponse> {\n return this.request(`/collections/${collectionId}/members`, { method: 'GET' });\n }\n\n async updateMemberRole(\n collectionId: string,\n userId: string,\n role: CollectionRole\n ): Promise<{ success: true; role: CollectionRole }> {\n return this.request(`/collections/${collectionId}/members/${userId}`, {\n method: 'PATCH',\n authRequired: true,\n body: JSON.stringify({ role }),\n });\n }\n\n async removeMember(collectionId: string, userId: string): Promise<SuccessResponse> {\n return this.request(`/collections/${collectionId}/members/${userId}`, {\n method: 'DELETE',\n authRequired: true,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Invitations\n // ---------------------------------------------------------------------------\n\n async createInvitation(collectionId: string, email: string, role: CollectionRole): Promise<Invitation> {\n return this.request(`/collections/${collectionId}/invitations`, {\n method: 'POST',\n authRequired: true,\n body: JSON.stringify({ email, role }),\n });\n }\n\n async listInvitations(collectionId: string): Promise<InvitationsResponse> {\n return this.request(`/collections/${collectionId}/invitations`, {\n method: 'GET',\n authRequired: true,\n });\n }\n\n async acceptInvitation(invitationId: string): Promise<{ success: true; role: CollectionRole }> {\n return this.request(`/invitations/${invitationId}/accept`, {\n method: 'POST',\n authRequired: true,\n });\n }\n\n async declineInvitation(invitationId: string): Promise<SuccessResponse> {\n return this.request(`/invitations/${invitationId}/decline`, {\n method: 'POST',\n authRequired: true,\n });\n }\n\n async revokeInvitation(invitationId: string): Promise<SuccessResponse> {\n return this.request(`/invitations/${invitationId}`, {\n method: 'DELETE',\n authRequired: true,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Current user\n // ---------------------------------------------------------------------------\n\n async getMyCollections(): Promise<MyCollectionsResponse> {\n return this.request('/me/collections', { method: 'GET', authRequired: true });\n }\n\n async getMyInvitations(): Promise<InvitationsResponse> {\n return this.request('/me/invitations', { method: 'GET', authRequired: true });\n }\n\n // ---------------------------------------------------------------------------\n // PI permissions\n // ---------------------------------------------------------------------------\n\n async getPiPermissions(pi: string): Promise<PiPermissions> {\n return this.request(`/pi/${pi}/permissions`, { method: 'GET' });\n }\n}\n"],"mappings":"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","names":[]}