@stacknet/stacks 0.1.2 → 0.2.2

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 (67) hide show
  1. package/README.md +136 -0
  2. package/dist/{billing-BqscteyZ.d.cts → billing-cj0eSVrp.d.cts} +61 -1
  3. package/dist/{billing-BqscteyZ.d.ts → billing-cj0eSVrp.d.ts} +61 -1
  4. package/dist/clients/index.cjs +4 -4
  5. package/dist/clients/index.d.cts +27 -1
  6. package/dist/clients/index.d.ts +27 -1
  7. package/dist/clients/index.js +4 -4
  8. package/dist/{index-DVzKiF_0.d.cts → index-B_dUFmAg.d.cts} +31 -6
  9. package/dist/{index-DVzKiF_0.d.ts → index-B_dUFmAg.d.ts} +31 -6
  10. package/dist/index.cjs +12 -16
  11. package/dist/index.d.cts +4 -4
  12. package/dist/index.d.ts +4 -4
  13. package/dist/index.js +12 -16
  14. package/dist/proxy/index.cjs +2 -2
  15. package/dist/proxy/index.d.cts +1 -1
  16. package/dist/proxy/index.d.ts +1 -1
  17. package/dist/proxy/index.js +2 -2
  18. package/dist/streaming/index.cjs +8 -12
  19. package/dist/streaming/index.js +8 -12
  20. package/dist/types/index.d.cts +1 -1
  21. package/dist/types/index.d.ts +1 -1
  22. package/package.json +15 -13
  23. package/src/clients/agents.ts +0 -233
  24. package/src/clients/billing.ts +0 -197
  25. package/src/clients/coder.ts +0 -655
  26. package/src/clients/files.ts +0 -86
  27. package/src/clients/index.ts +0 -93
  28. package/src/clients/magma.ts +0 -299
  29. package/src/clients/mcp.ts +0 -208
  30. package/src/clients/network.ts +0 -118
  31. package/src/clients/points.ts +0 -403
  32. package/src/clients/skills.ts +0 -236
  33. package/src/clients/social.ts +0 -286
  34. package/src/clients/stack-management.ts +0 -279
  35. package/src/clients/task-network.ts +0 -303
  36. package/src/clients/user.ts +0 -84
  37. package/src/clients/widgets.ts +0 -171
  38. package/src/index.ts +0 -387
  39. package/src/managers/index.ts +0 -10
  40. package/src/managers/task-manager.ts +0 -310
  41. package/src/proxy/forwarder.ts +0 -146
  42. package/src/proxy/index.ts +0 -32
  43. package/src/proxy/route-handlers.ts +0 -950
  44. package/src/streaming/component-stream.ts +0 -319
  45. package/src/streaming/index.ts +0 -21
  46. package/src/streaming/sse.ts +0 -241
  47. package/src/types/agent.ts +0 -106
  48. package/src/types/billing.ts +0 -121
  49. package/src/types/chat.ts +0 -58
  50. package/src/types/coder.ts +0 -345
  51. package/src/types/credential.ts +0 -111
  52. package/src/types/file.ts +0 -15
  53. package/src/types/imagination.ts +0 -50
  54. package/src/types/index.ts +0 -20
  55. package/src/types/mcp.ts +0 -35
  56. package/src/types/network.ts +0 -97
  57. package/src/types/points.ts +0 -250
  58. package/src/types/skill.ts +0 -107
  59. package/src/types/social.ts +0 -109
  60. package/src/types/stack.ts +0 -269
  61. package/src/types/task.ts +0 -41
  62. package/src/types/user.ts +0 -29
  63. package/src/types/widget.ts +0 -57
  64. package/src/utils/constants.ts +0 -26
  65. package/src/utils/errors.ts +0 -169
  66. package/src/utils/helpers.ts +0 -85
  67. package/src/utils/index.ts +0 -7
@@ -1,279 +0,0 @@
1
- /**
2
- * Stack Management Client
3
- * CRUD operations for stacks, providers, keys, allowlists, capabilities, members, and model layers
4
- */
5
-
6
- import { DEFAULT_GLAYER_NETWORK_URL, JSON_HEADERS } from '../utils/constants';
7
- import { StacksSDKError } from '../utils/errors';
8
- import type {
9
- StackConfig,
10
- CreateStackRequest,
11
- StackResponse,
12
- StackListResponse,
13
- StackOAuthProvider,
14
- StackWeb3Provider,
15
- StackStripeProvider,
16
- ConfigureOAuthInput,
17
- ConfigureWeb3Input,
18
- ConfigureStripeInput,
19
- StackKeyInfo,
20
- CreateKeyResponse,
21
- StackKeysListResponse,
22
- AllowlistConfig,
23
- AllowlistUpdateInput,
24
- ModelLayersResponse,
25
- StackMember,
26
- StackMemberStats,
27
- StackManagementClientConfig,
28
- } from '../types/stack';
29
-
30
- export type { StackManagementClientConfig } from '../types/stack';
31
-
32
- const API_PATH = '/api/v2';
33
-
34
- export class StackManagementClient {
35
- private baseUrl: string;
36
- private authToken: string | null;
37
-
38
- constructor(config: StackManagementClientConfig = {}) {
39
- this.baseUrl = config.baseUrl || DEFAULT_GLAYER_NETWORK_URL;
40
- this.authToken = config.authToken || null;
41
- }
42
-
43
- /** Update the auth token (e.g. after login via userutils) */
44
- setAuthToken(token: string | null) {
45
- this.authToken = token;
46
- }
47
-
48
- private get headers(): Record<string, string> {
49
- const h: Record<string, string> = { ...JSON_HEADERS };
50
- if (this.authToken) {
51
- h['Authorization'] = `Bearer ${this.authToken}`;
52
- }
53
- return h;
54
- }
55
-
56
- private url(path: string): string {
57
- return `${this.baseUrl}${API_PATH}${path}`;
58
- }
59
-
60
- private async request<T>(method: string, path: string, body?: unknown): Promise<T> {
61
- const opts: RequestInit = { method, headers: this.headers };
62
- if (body && method !== 'GET') {
63
- opts.body = JSON.stringify(body);
64
- }
65
-
66
- const response = await fetch(this.url(path), opts);
67
-
68
- if (!response.ok) {
69
- const data = await response.json().catch(() => ({}));
70
- const code = response.status === 404 ? 'not_found' : response.status === 401 ? 'unauthorized' : 'bad_request';
71
- throw new StacksSDKError(
72
- `${code}:api`,
73
- data.error?.message || data.error || `Request failed: ${response.statusText}`
74
- );
75
- }
76
-
77
- const data = await response.json();
78
- // Unwrap server envelope { success, data }
79
- return (data && typeof data === 'object' && 'data' in data) ? data.data : data;
80
- }
81
-
82
- // =========================================================================
83
- // Stack CRUD
84
- // =========================================================================
85
-
86
- async createStack(input: CreateStackRequest): Promise<StackResponse> {
87
- return this.request<StackResponse>('POST', '/stacks', input);
88
- }
89
-
90
- async listStacks(): Promise<StackListResponse> {
91
- return this.request<StackListResponse>('GET', '/stacks');
92
- }
93
-
94
- async getStack(stackId: string): Promise<StackResponse> {
95
- return this.request<StackResponse>('GET', `/stacks/${stackId}`);
96
- }
97
-
98
- async updateStack(stackId: string, updates: Partial<StackConfig>): Promise<StackResponse> {
99
- return this.request<StackResponse>('PATCH', `/stacks/${stackId}`, updates);
100
- }
101
-
102
- async deleteStack(stackId: string): Promise<{ deleted: boolean }> {
103
- return this.request<{ deleted: boolean }>('DELETE', `/stacks/${stackId}`);
104
- }
105
-
106
- // =========================================================================
107
- // OAuth Providers
108
- // =========================================================================
109
-
110
- /** @server-only — Sends OAuth clientSecret. Only call from server-side code. */
111
- async configureOAuthProvider(stackId: string, provider: string, config: ConfigureOAuthInput): Promise<StackOAuthProvider> {
112
- return this.request<StackOAuthProvider>('POST', `/stacks/${stackId}/oauth/${provider}`, config);
113
- }
114
-
115
- async removeOAuthProvider(stackId: string, provider: string): Promise<{ removed: boolean }> {
116
- return this.request<{ removed: boolean }>('DELETE', `/stacks/${stackId}/oauth/${provider}`);
117
- }
118
-
119
- // =========================================================================
120
- // Web3 Providers
121
- // =========================================================================
122
-
123
- async configureWeb3Provider(stackId: string, provider: string, config: ConfigureWeb3Input): Promise<StackWeb3Provider> {
124
- return this.request<StackWeb3Provider>('POST', `/stacks/${stackId}/web3/${provider}`, config);
125
- }
126
-
127
- async removeWeb3Provider(stackId: string, provider: string): Promise<{ removed: boolean }> {
128
- return this.request<{ removed: boolean }>('DELETE', `/stacks/${stackId}/web3/${provider}`);
129
- }
130
-
131
- // =========================================================================
132
- // Stripe Provider
133
- // =========================================================================
134
-
135
- /** @server-only — Sends Stripe secretKey. Only call from server-side code. */
136
- async configureStripeProvider(stackId: string, config: ConfigureStripeInput): Promise<StackStripeProvider> {
137
- return this.request<StackStripeProvider>('POST', `/stacks/${stackId}/stripe`, config);
138
- }
139
-
140
- async getStripeProvider(stackId: string): Promise<StackStripeProvider> {
141
- return this.request<StackStripeProvider>('GET', `/stacks/${stackId}/stripe`);
142
- }
143
-
144
- async removeStripeProvider(stackId: string): Promise<{ removed: boolean }> {
145
- return this.request<{ removed: boolean }>('DELETE', `/stacks/${stackId}/stripe`);
146
- }
147
-
148
- async createPaymentIntent(stackId: string, amountCents: number, metadata?: Record<string, string>): Promise<{ clientSecret: string; paymentIntentId: string }> {
149
- return this.request('POST', `/stacks/${stackId}/stripe/payment-intent`, { amountCents, metadata });
150
- }
151
-
152
- // =========================================================================
153
- // Stack Keys
154
- // =========================================================================
155
-
156
- async createKey(stackId: string, name: string, permission: 'read' | 'write'): Promise<CreateKeyResponse> {
157
- return this.request<CreateKeyResponse>('POST', `/stacks/${stackId}/keys`, { name, permission });
158
- }
159
-
160
- async listKeys(stackId: string): Promise<StackKeysListResponse> {
161
- return this.request<StackKeysListResponse>('GET', `/stacks/${stackId}/keys`);
162
- }
163
-
164
- async revokeKey(stackId: string, keyId: string): Promise<{ success: boolean }> {
165
- return this.request<{ success: boolean }>('DELETE', `/stacks/${stackId}/keys/${keyId}`);
166
- }
167
-
168
- // =========================================================================
169
- // Allowlist
170
- // =========================================================================
171
-
172
- async getAllowlist(stackId: string): Promise<AllowlistConfig> {
173
- return this.request<AllowlistConfig>('GET', `/stacks/${stackId}/auth/allowlist`);
174
- }
175
-
176
- async updateAllowlist(stackId: string, config: AllowlistUpdateInput): Promise<AllowlistConfig> {
177
- return this.request<AllowlistConfig>('PUT', `/stacks/${stackId}/auth/allowlist`, config);
178
- }
179
-
180
- // =========================================================================
181
- // Capabilities
182
- // =========================================================================
183
-
184
- async updateCapabilities(stackId: string, capabilityBitmask: number): Promise<StackResponse> {
185
- return this.request<StackResponse>('PATCH', `/stacks/${stackId}`, { capabilityBitmask });
186
- }
187
-
188
- // =========================================================================
189
- // Model Layers
190
- // =========================================================================
191
-
192
- async getModelLayers(stackId: string): Promise<ModelLayersResponse> {
193
- return this.request<ModelLayersResponse>('GET', `/stacks/${stackId}/model-layers`);
194
- }
195
-
196
- async updateModelAlias(stackId: string, layer: string, capability: string, alias: string): Promise<{ updated: boolean }> {
197
- return this.request('PATCH', `/stacks/${stackId}/model-layers`, { layer, capability, alias });
198
- }
199
-
200
- async resetModelAlias(stackId: string, layer: string, capability: string): Promise<{ updated: boolean }> {
201
- return this.request('DELETE', `/stacks/${stackId}/model-layers/${layer}/${capability}`);
202
- }
203
-
204
- // =========================================================================
205
- // Logo
206
- // =========================================================================
207
-
208
- async uploadLogo(stackId: string, file: File): Promise<StackResponse> {
209
- const url = `${this.baseUrl}${API_PATH}/stacks/${stackId}/logo`;
210
- const formData = new FormData();
211
- formData.append('logo', file);
212
-
213
- const headers: Record<string, string> = {};
214
- if (this.authToken) {
215
- headers['Authorization'] = `Bearer ${this.authToken}`;
216
- }
217
-
218
- const response = await fetch(url, { method: 'POST', headers, body: formData });
219
-
220
- if (!response.ok) {
221
- const data = await response.json().catch(() => ({}));
222
- throw new StacksSDKError('bad_request:api', data.error?.message || `Failed to upload logo: ${response.statusText}`);
223
- }
224
-
225
- const data = await response.json();
226
- return (data && typeof data === 'object' && 'data' in data) ? data.data : data;
227
- }
228
-
229
- async deleteLogo(stackId: string): Promise<StackResponse> {
230
- return this.request<StackResponse>('DELETE', `/stacks/${stackId}/logo`);
231
- }
232
-
233
- // =========================================================================
234
- // Members
235
- // =========================================================================
236
-
237
- async getMemberStats(stackId: string): Promise<StackMemberStats> {
238
- return this.request<StackMemberStats>('GET', `/stacks/${stackId}/members/stats`);
239
- }
240
-
241
- async getMembers(stackId: string, opts?: { limit?: number; offset?: number; role?: string }): Promise<StackMember[]> {
242
- const params = new URLSearchParams();
243
- if (opts?.limit) params.set('limit', String(opts.limit));
244
- if (opts?.offset) params.set('offset', String(opts.offset));
245
- if (opts?.role) params.set('role', opts.role);
246
- const qs = params.toString() ? `?${params}` : '';
247
- return this.request<StackMember[]>('GET', `/stacks/${stackId}/members${qs}`);
248
- }
249
-
250
- async updateMemberRole(stackId: string, userId: string, role: 'admin' | 'user'): Promise<{ success: boolean }> {
251
- return this.request<{ success: boolean }>('PATCH', `/stacks/${stackId}/members/${encodeURIComponent(userId)}/role`, { role });
252
- }
253
-
254
- // =========================================================================
255
- // Usage Records
256
- // =========================================================================
257
-
258
- async getUsageRecords(stackId: string, opts?: { page?: number; limit?: number; days?: number; model?: string }): Promise<{ data: any[]; pagination: any }> {
259
- const params = new URLSearchParams();
260
- if (opts?.page) params.set('page', String(opts.page));
261
- if (opts?.limit) params.set('limit', String(opts.limit));
262
- if (opts?.days) params.set('days', String(opts.days));
263
- if (opts?.model) params.set('model', opts.model);
264
- const qs = params.toString() ? `?${params}` : '';
265
- return this.request('GET', `/stacks/${stackId}/usage/records${qs}`);
266
- }
267
- }
268
-
269
- /**
270
- * Create a StackManagementClient instance
271
- */
272
- export function createStackManagementClient(config: StackManagementClientConfig = {}): StackManagementClient {
273
- return new StackManagementClient(config);
274
- }
275
-
276
- /**
277
- * Default stack management client instance
278
- */
279
- export const stackManagementClient = createStackManagementClient();
@@ -1,303 +0,0 @@
1
- /**
2
- * TaskNetworkClient - OpenAI-compatible SDK for StackNet
3
- *
4
- * Provides streaming chat completions via the local StackNet
5
- */
6
-
7
- import type {
8
- Message,
9
- ChatCompletionRequest,
10
- ChatCompletionChunk,
11
- TaskPayload,
12
- } from '../types';
13
- import { DEFAULT_TASK_NETWORK_URL } from '../utils/constants';
14
-
15
- export interface TaskNetworkConfig {
16
- baseUrl?: string;
17
- apiKey?: string;
18
- timeout?: number;
19
- }
20
-
21
- export class TaskNetworkClient {
22
- private baseUrl: string;
23
- private apiKey?: string;
24
- private timeout: number;
25
-
26
- constructor(config: TaskNetworkConfig = {}) {
27
- this.baseUrl = (config.baseUrl || DEFAULT_TASK_NETWORK_URL).replace(/\/$/, '');
28
- this.apiKey = config.apiKey;
29
- this.timeout = config.timeout || 60000;
30
- }
31
-
32
- /**
33
- * OpenAI-compatible streaming chat completions
34
- */
35
- async *chatCompletions(
36
- request: ChatCompletionRequest
37
- ): AsyncIterable<ChatCompletionChunk> {
38
- const userMessages = request.messages.filter((m) => m.role === 'user');
39
- const prompt = userMessages[userMessages.length - 1]?.content || '';
40
-
41
- const taskId = await this.submitTask({
42
- type: 'ai-prompt',
43
- model: request.model,
44
- prompt: prompt,
45
- sessionId: request.sessionId,
46
- temperature: request.temperature,
47
- maxTokens: request.max_tokens,
48
- stream: true,
49
- });
50
-
51
- yield* this.streamTaskResults(taskId, request.model);
52
- }
53
-
54
- /**
55
- * Submit a task to the network
56
- * Returns taskId. If result is immediately available, also includes output.
57
- */
58
- async submitTask(payload: TaskPayload): Promise<string> {
59
- const response = await fetch(`${this.baseUrl}/tasks`, {
60
- method: 'POST',
61
- headers: {
62
- 'Content-Type': 'application/json',
63
- ...(this.apiKey && { Authorization: `Bearer ${this.apiKey}` }),
64
- },
65
- body: JSON.stringify(payload),
66
- });
67
-
68
- if (!response.ok) {
69
- const error = await response.text();
70
- throw new Error(`Task submission failed: ${error}`);
71
- }
72
-
73
- const data = await response.json();
74
- // Handle both taskId and id (StackNet uses different field names)
75
- const taskId = data.taskId || data.id;
76
- if (!taskId) {
77
- throw new Error('Task submission did not return a taskId');
78
- }
79
- return taskId;
80
- }
81
-
82
- /**
83
- * Submit a task and get full response (for immediate results)
84
- */
85
- async submitTaskFull(payload: TaskPayload): Promise<{ taskId: string; output?: unknown; status?: string }> {
86
- const response = await fetch(`${this.baseUrl}/tasks`, {
87
- method: 'POST',
88
- headers: {
89
- 'Content-Type': 'application/json',
90
- ...(this.apiKey && { Authorization: `Bearer ${this.apiKey}` }),
91
- },
92
- body: JSON.stringify(payload),
93
- });
94
-
95
- if (!response.ok) {
96
- const error = await response.text();
97
- throw new Error(`Task submission failed: ${error}`);
98
- }
99
-
100
- const data = await response.json();
101
- return {
102
- taskId: data.taskId || data.id,
103
- output: data.output,
104
- status: data.status,
105
- };
106
- }
107
-
108
- /**
109
- * Get task status
110
- */
111
- async getTask(taskId: string): Promise<{ status: string; result?: unknown }> {
112
- const response = await fetch(`${this.baseUrl}/tasks/${taskId}`, {
113
- headers: {
114
- ...(this.apiKey && { Authorization: `Bearer ${this.apiKey}` }),
115
- },
116
- });
117
-
118
- if (!response.ok) {
119
- throw new Error(`Failed to get task: ${response.statusText}`);
120
- }
121
-
122
- return response.json();
123
- }
124
-
125
- /**
126
- * Stream task results as OpenAI-compatible chunks
127
- */
128
- async *streamTaskResults(
129
- taskId: string,
130
- model: string
131
- ): AsyncIterable<ChatCompletionChunk> {
132
- const response = await fetch(`${this.baseUrl}/tasks/${taskId}/stream`, {
133
- headers: {
134
- ...(this.apiKey && { Authorization: `Bearer ${this.apiKey}` }),
135
- },
136
- });
137
-
138
- if (!response.ok) {
139
- throw new Error(`Stream failed: ${response.statusText}`);
140
- }
141
-
142
- if (!response.body) {
143
- throw new Error('Response body is null');
144
- }
145
-
146
- const reader = response.body.getReader();
147
- const decoder = new TextDecoder();
148
- let buffer = '';
149
- let lastContent = '';
150
- const created = Math.floor(Date.now() / 1000);
151
-
152
- try {
153
- while (true) {
154
- const { done, value } = await reader.read();
155
-
156
- if (done) {
157
- yield {
158
- id: taskId,
159
- object: 'chat.completion.chunk',
160
- created,
161
- model,
162
- choices: [
163
- {
164
- index: 0,
165
- delta: {},
166
- finish_reason: 'stop',
167
- },
168
- ],
169
- };
170
- break;
171
- }
172
-
173
- buffer += decoder.decode(value, { stream: true });
174
- const lines = buffer.split('\n');
175
- buffer = lines.pop() || '';
176
-
177
- for (const line of lines) {
178
- if (line.startsWith('data: ')) {
179
- try {
180
- const data = JSON.parse(line.slice(6));
181
-
182
- if (Array.isArray(data) && data.length > 0) {
183
- const latestCommit = data[0];
184
- const newContent = latestCommit.result || '';
185
-
186
- if (newContent && newContent !== lastContent) {
187
- const delta = newContent.substring(lastContent.length);
188
- lastContent = newContent;
189
-
190
- if (delta) {
191
- yield {
192
- id: taskId,
193
- object: 'chat.completion.chunk',
194
- created,
195
- model,
196
- choices: [
197
- {
198
- index: 0,
199
- delta: {
200
- role: 'assistant',
201
- content: delta,
202
- },
203
- finish_reason: null,
204
- },
205
- ],
206
- };
207
- }
208
- }
209
- }
210
- } catch {
211
- // Skip invalid JSON
212
- }
213
- }
214
- }
215
- }
216
- } finally {
217
- reader.releaseLock();
218
- }
219
- }
220
-
221
- /**
222
- * Stream raw task results (not OpenAI format)
223
- */
224
- async *streamTaskRaw(taskId: string): AsyncIterable<unknown> {
225
- const response = await fetch(`${this.baseUrl}/tasks/${taskId}/stream`, {
226
- headers: {
227
- ...(this.apiKey && { Authorization: `Bearer ${this.apiKey}` }),
228
- },
229
- });
230
-
231
- if (!response.ok) {
232
- throw new Error(`Stream failed: ${response.statusText}`);
233
- }
234
-
235
- if (!response.body) {
236
- throw new Error('Response body is null');
237
- }
238
-
239
- const reader = response.body.getReader();
240
- const decoder = new TextDecoder();
241
- let buffer = '';
242
-
243
- try {
244
- while (true) {
245
- const { done, value } = await reader.read();
246
- if (done) break;
247
-
248
- buffer += decoder.decode(value, { stream: true });
249
- const lines = buffer.split('\n');
250
- buffer = lines.pop() || '';
251
-
252
- for (const line of lines) {
253
- if (line.startsWith('data: ')) {
254
- try {
255
- yield JSON.parse(line.slice(6));
256
- } catch {
257
- // Skip invalid JSON
258
- }
259
- }
260
- }
261
- }
262
- } finally {
263
- reader.releaseLock();
264
- }
265
- }
266
-
267
- /**
268
- * Health check
269
- */
270
- async healthCheck(): Promise<boolean> {
271
- try {
272
- const response = await fetch(`${this.baseUrl}/health`);
273
- return response.ok;
274
- } catch {
275
- return false;
276
- }
277
- }
278
-
279
- /**
280
- * Get node information
281
- */
282
- async getNode(): Promise<unknown> {
283
- const response = await fetch(`${this.baseUrl}/node`);
284
- if (!response.ok) {
285
- throw new Error(`Failed to get node info: ${response.statusText}`);
286
- }
287
- return response.json();
288
- }
289
- }
290
-
291
- /**
292
- * Factory function to create a client
293
- */
294
- export function createTaskNetworkClient(
295
- config?: TaskNetworkConfig
296
- ): TaskNetworkClient {
297
- return new TaskNetworkClient(config);
298
- }
299
-
300
- /**
301
- * Default singleton instance
302
- */
303
- export const taskNetworkClient = createTaskNetworkClient();
@@ -1,84 +0,0 @@
1
- /**
2
- * User Client
3
- * Client for interacting with user profile API
4
- */
5
-
6
- import { DEFAULT_TASK_NETWORK_URL, JSON_HEADERS } from '../utils/constants';
7
- import { StacksSDKError } from '../utils/errors';
8
- import type {
9
- UserProfile,
10
- UserProfileUpdateInput,
11
- UserProfileResponse,
12
- UserClientConfig,
13
- } from '../types/user';
14
-
15
- export type { UserClientConfig } from '../types/user';
16
-
17
- export class UserClient {
18
- private baseUrl: string;
19
-
20
- constructor(config: UserClientConfig = {}) {
21
- this.baseUrl = config.baseUrl || DEFAULT_TASK_NETWORK_URL;
22
- }
23
-
24
- private get userUrl(): string {
25
- return `${this.baseUrl}/user`;
26
- }
27
-
28
- /**
29
- * Get user profile by MID
30
- */
31
- async getProfile(mid: string): Promise<UserProfile | null> {
32
- try {
33
- const response = await fetch(`${this.userUrl}/profile/${mid}`);
34
-
35
- if (!response.ok) {
36
- if (response.status === 404) {
37
- return null;
38
- }
39
- throw new StacksSDKError(
40
- 'bad_request:api',
41
- `Failed to get user profile: ${response.statusText}`
42
- );
43
- }
44
-
45
- return response.json();
46
- } catch (error) {
47
- if (error instanceof StacksSDKError) throw error;
48
- return null;
49
- }
50
- }
51
-
52
- /**
53
- * Update user profile
54
- */
55
- async updateProfile(mid: string, input: UserProfileUpdateInput): Promise<UserProfileResponse> {
56
- const response = await fetch(`${this.userUrl}/profile/${mid}`, {
57
- method: 'PUT',
58
- headers: JSON_HEADERS,
59
- body: JSON.stringify(input),
60
- });
61
-
62
- if (!response.ok) {
63
- const data = await response.json().catch(() => ({}));
64
- throw new StacksSDKError(
65
- 'bad_request:api',
66
- data.error || `Failed to update user profile: ${response.statusText}`
67
- );
68
- }
69
-
70
- return response.json();
71
- }
72
- }
73
-
74
- /**
75
- * Create a UserClient instance
76
- */
77
- export function createUserClient(config: UserClientConfig = {}): UserClient {
78
- return new UserClient(config);
79
- }
80
-
81
- /**
82
- * Default user client instance
83
- */
84
- export const userClient = createUserClient();