@timbrix/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/dist/index.mjs ADDED
@@ -0,0 +1,527 @@
1
+ // src/client.ts
2
+ import ky from "ky";
3
+
4
+ // src/auth/base.ts
5
+ var BearerAuth = class {
6
+ constructor(token) {
7
+ this.token = token;
8
+ }
9
+ getHeaders() {
10
+ return {
11
+ Authorization: `Bearer ${this.token}`
12
+ };
13
+ }
14
+ applyAuth(options) {
15
+ return {
16
+ ...options,
17
+ headers: {
18
+ ...options.headers,
19
+ ...this.getHeaders()
20
+ }
21
+ };
22
+ }
23
+ };
24
+ var ApiKeyAuth = class {
25
+ constructor(apiKey) {
26
+ this.apiKey = apiKey;
27
+ }
28
+ getHeaders() {
29
+ return {
30
+ "X-API-Key": this.apiKey
31
+ };
32
+ }
33
+ applyAuth(options) {
34
+ return {
35
+ ...options,
36
+ headers: {
37
+ ...options.headers,
38
+ ...this.getHeaders()
39
+ }
40
+ };
41
+ }
42
+ };
43
+
44
+ // src/resources/api-keys.ts
45
+ var ApiKeysResource = class {
46
+ constructor(http) {
47
+ this.http = http;
48
+ }
49
+ /**
50
+ * List all API keys for an organization
51
+ */
52
+ async list(organizationId) {
53
+ return this.http.get(`organizations/${organizationId}/api-keys`).json();
54
+ }
55
+ /**
56
+ * Get API key by ID
57
+ */
58
+ async get(organizationId, apiKeyId) {
59
+ return this.http.get(`organizations/${organizationId}/api-keys/${apiKeyId}`).json();
60
+ }
61
+ /**
62
+ * Create a new API key. The plain key is returned only once in the response.
63
+ */
64
+ async create(organizationId, data) {
65
+ return this.http.post(`organizations/${organizationId}/api-keys`, { json: data }).json();
66
+ }
67
+ /**
68
+ * Update API key
69
+ */
70
+ async update(organizationId, apiKeyId, data) {
71
+ return this.http.put(`organizations/${organizationId}/api-keys/${apiKeyId}`, {
72
+ json: data
73
+ }).json();
74
+ }
75
+ /**
76
+ * Delete (revoke) API key
77
+ */
78
+ async delete(organizationId, apiKeyId) {
79
+ await this.http.delete(
80
+ `organizations/${organizationId}/api-keys/${apiKeyId}`
81
+ );
82
+ }
83
+ /**
84
+ * Get API key usage statistics for an organization
85
+ */
86
+ async stats(organizationId) {
87
+ return this.http.get(`organizations/${organizationId}/api-keys/stats`).json();
88
+ }
89
+ /**
90
+ * Validate the currently authenticated API key (uses X-API-Key header)
91
+ */
92
+ async validate() {
93
+ return this.http.post("api-keys/validate").json();
94
+ }
95
+ };
96
+
97
+ // src/resources/auth.ts
98
+ var AuthResource = class {
99
+ constructor(http) {
100
+ this.http = http;
101
+ }
102
+ /**
103
+ * Login with email and password. Returns an access token.
104
+ */
105
+ async login(data) {
106
+ return this.http.post("auth/login", { json: data }).json();
107
+ }
108
+ /**
109
+ * Logout and revoke the current access token.
110
+ */
111
+ async logout() {
112
+ await this.http.post("auth/logout");
113
+ }
114
+ };
115
+
116
+ // src/resources/customers.ts
117
+ var CustomersResource = class {
118
+ constructor(http) {
119
+ this.http = http;
120
+ }
121
+ /**
122
+ * List all customers for an organization
123
+ */
124
+ async list(organizationId) {
125
+ return this.http.get(`organizations/${organizationId}/customers`).json();
126
+ }
127
+ /**
128
+ * Get a customer by ID
129
+ */
130
+ async get(organizationId, customerId) {
131
+ return this.http.get(`organizations/${organizationId}/customers/${customerId}`).json();
132
+ }
133
+ /**
134
+ * Create a new customer
135
+ */
136
+ async create(organizationId, data) {
137
+ return this.http.post(`organizations/${organizationId}/customers`, { json: data }).json();
138
+ }
139
+ /**
140
+ * Update a customer
141
+ */
142
+ async update(organizationId, customerId, data) {
143
+ return this.http.put(`organizations/${organizationId}/customers/${customerId}`, {
144
+ json: data
145
+ }).json();
146
+ }
147
+ /**
148
+ * Delete a customer
149
+ */
150
+ async delete(organizationId, customerId) {
151
+ await this.http.delete(
152
+ `organizations/${organizationId}/customers/${customerId}`
153
+ );
154
+ }
155
+ };
156
+
157
+ // src/resources/oauth.ts
158
+ var OAuthResource = class {
159
+ constructor(http) {
160
+ this.http = http;
161
+ }
162
+ // ─── App Management ─────────────────────────────────────────────────────────
163
+ /**
164
+ * Create a new OAuth application. Client secret is returned only once.
165
+ */
166
+ async createApp(data) {
167
+ return this.http.post("oauth/apps", { json: data }).json();
168
+ }
169
+ /**
170
+ * Get OAuth application by client ID
171
+ */
172
+ async getApp(clientId) {
173
+ return this.http.get(`oauth/apps/${clientId}`).json();
174
+ }
175
+ /**
176
+ * List OAuth applications for an organization
177
+ */
178
+ async listApps(organizationId) {
179
+ return this.http.get(`oauth/apps/organization/${organizationId}`).json();
180
+ }
181
+ /**
182
+ * Update OAuth application
183
+ */
184
+ async updateApp(clientId, data) {
185
+ return this.http.put(`oauth/apps/${clientId}`, { json: data }).json();
186
+ }
187
+ /**
188
+ * Delete OAuth application. All associated tokens will be revoked.
189
+ */
190
+ async deleteApp(clientId) {
191
+ await this.http.delete(`oauth/apps/${clientId}`);
192
+ }
193
+ /**
194
+ * List active tokens for an OAuth application
195
+ */
196
+ async listTokens(clientId) {
197
+ return this.http.get(`oauth/apps/${clientId}/tokens`).json();
198
+ }
199
+ /**
200
+ * Revoke an OAuth token (requires write:oauth-apps scope)
201
+ */
202
+ async revokeToken(tokenId) {
203
+ await this.http.delete(`oauth/token/${tokenId}`);
204
+ }
205
+ // ─── Token Operations ────────────────────────────────────────────────────────
206
+ /**
207
+ * Generate an access token using client credentials flow
208
+ */
209
+ async generateToken(data) {
210
+ return this.http.post("oauth/token", {
211
+ json: {
212
+ grant_type: "client_credentials",
213
+ client_id: data.clientId,
214
+ client_secret: data.clientSecret,
215
+ scope: data.scopes.join(" "),
216
+ user_id: data.userId
217
+ }
218
+ }).json();
219
+ }
220
+ /**
221
+ * Exchange an authorization code for access and refresh tokens
222
+ */
223
+ async exchangeCode(data) {
224
+ return this.http.post("oauth/token/exchange", {
225
+ json: {
226
+ code: data.code,
227
+ clientId: data.clientId,
228
+ clientSecret: data.clientSecret,
229
+ redirectUri: data.redirectUri,
230
+ grantType: "authorization_code",
231
+ codeVerifier: data.codeVerifier
232
+ }
233
+ }).json();
234
+ }
235
+ /**
236
+ * Refresh an access token using a refresh token
237
+ */
238
+ async refreshToken(data) {
239
+ return this.http.post("oauth/token/refresh", {
240
+ json: { refreshToken: data.refreshToken }
241
+ }).json();
242
+ }
243
+ };
244
+
245
+ // src/resources/organizations.ts
246
+ var OrganizationsResource = class {
247
+ constructor(http) {
248
+ this.http = http;
249
+ }
250
+ /**
251
+ * Create a new organization
252
+ */
253
+ async create(data) {
254
+ return this.http.post("organizations", { json: data }).json();
255
+ }
256
+ /**
257
+ * Get organization by ID
258
+ */
259
+ async get(id) {
260
+ return this.http.get(`organizations/${id}`).json();
261
+ }
262
+ /**
263
+ * Update organization (owner only)
264
+ */
265
+ async update(id, data) {
266
+ return this.http.put(`organizations/${id}`, { json: data }).json();
267
+ }
268
+ /**
269
+ * Update organization legal/fiscal data (owner only)
270
+ */
271
+ async updateLegalData(id, data) {
272
+ return this.http.put(`organizations/${id}/legal`, { json: data }).json();
273
+ }
274
+ /**
275
+ * Delete organization (owner only)
276
+ */
277
+ async delete(id) {
278
+ await this.http.delete(`organizations/${id}`);
279
+ }
280
+ /**
281
+ * Get organization members
282
+ */
283
+ async members(id) {
284
+ return this.http.get(`organizations/${id}/members`).json();
285
+ }
286
+ /**
287
+ * Invite a member (owner/admin only)
288
+ */
289
+ async invite(id, data) {
290
+ return this.http.post(`organizations/${id}/members/invite`, { json: data }).json();
291
+ }
292
+ /**
293
+ * Remove a member (owner/admin only)
294
+ */
295
+ async removeMember(id, memberId) {
296
+ await this.http.delete(`organizations/${id}/members/${memberId}`);
297
+ }
298
+ /**
299
+ * Update member role (owner/admin only)
300
+ */
301
+ async updateMemberRole(id, memberId, data) {
302
+ return this.http.put(`organizations/${id}/members/${memberId}/role`, { json: data }).json();
303
+ }
304
+ /**
305
+ * Get pending invitations
306
+ */
307
+ async invites(id) {
308
+ return this.http.get(`organizations/${id}/invites`).json();
309
+ }
310
+ /**
311
+ * Cancel a pending invitation (owner/admin only)
312
+ */
313
+ async cancelInvite(id, inviteId) {
314
+ await this.http.delete(`organizations/${id}/invites/${inviteId}`);
315
+ }
316
+ };
317
+
318
+ // src/resources/products.ts
319
+ var ProductsResource = class {
320
+ constructor(http) {
321
+ this.http = http;
322
+ }
323
+ /**
324
+ * List products for an organization, with optional filters
325
+ */
326
+ async list(organizationId, filters) {
327
+ const searchParams = {};
328
+ if (filters?.description) searchParams.description = filters.description;
329
+ if (filters?.sku) searchParams.sku = filters.sku;
330
+ if (filters?.productKey !== void 0)
331
+ searchParams.productKey = String(filters.productKey);
332
+ return this.http.get(`organizations/${organizationId}/products`, {
333
+ searchParams: Object.keys(searchParams).length > 0 ? searchParams : void 0
334
+ }).json();
335
+ }
336
+ /**
337
+ * Get a product by ID
338
+ */
339
+ async get(organizationId, productId) {
340
+ return this.http.get(`organizations/${organizationId}/products/${productId}`).json();
341
+ }
342
+ /**
343
+ * Create a new product or service
344
+ */
345
+ async create(organizationId, data) {
346
+ return this.http.post(`organizations/${organizationId}/products`, { json: data }).json();
347
+ }
348
+ /**
349
+ * Update a product
350
+ */
351
+ async update(organizationId, productId, data) {
352
+ return this.http.put(`organizations/${organizationId}/products/${productId}`, {
353
+ json: data
354
+ }).json();
355
+ }
356
+ /**
357
+ * Delete a product
358
+ */
359
+ async delete(organizationId, productId) {
360
+ await this.http.delete(
361
+ `organizations/${organizationId}/products/${productId}`
362
+ );
363
+ }
364
+ };
365
+
366
+ // src/resources/users.ts
367
+ var UsersResource = class {
368
+ constructor(http) {
369
+ this.http = http;
370
+ }
371
+ /**
372
+ * Get the currently authenticated user
373
+ */
374
+ async me() {
375
+ return this.http.get("users/me").json();
376
+ }
377
+ /**
378
+ * Get user by ID (requires read:user scope)
379
+ */
380
+ async getById(id) {
381
+ return this.http.get(`users/${id}`).json();
382
+ }
383
+ /**
384
+ * Get organizations for a user (requires read:organization scope)
385
+ */
386
+ async getOrganizations(id) {
387
+ return this.http.get(`users/${id}/organizations`).json();
388
+ }
389
+ /**
390
+ * Get user by email (requires read:user scope)
391
+ */
392
+ async getByEmail(email) {
393
+ return this.http.get(`users/email/${encodeURIComponent(email)}`).json();
394
+ }
395
+ };
396
+
397
+ // src/resources/webhooks.ts
398
+ var WebhooksResource = class {
399
+ constructor(http) {
400
+ this.http = http;
401
+ }
402
+ /**
403
+ * List all webhooks for an organization
404
+ */
405
+ async list(organizationId) {
406
+ return this.http.get(`organizations/${organizationId}/webhooks`).json();
407
+ }
408
+ /**
409
+ * Get webhook by ID
410
+ */
411
+ async get(organizationId, webhookId) {
412
+ return this.http.get(`organizations/${organizationId}/webhooks/${webhookId}`).json();
413
+ }
414
+ /**
415
+ * Create a new webhook
416
+ */
417
+ async create(organizationId, data) {
418
+ return this.http.post(`organizations/${organizationId}/webhooks`, { json: data }).json();
419
+ }
420
+ /**
421
+ * Update webhook
422
+ */
423
+ async update(organizationId, webhookId, data) {
424
+ return this.http.put(`organizations/${organizationId}/webhooks/${webhookId}`, {
425
+ json: data
426
+ }).json();
427
+ }
428
+ /**
429
+ * Delete webhook
430
+ */
431
+ async delete(organizationId, webhookId) {
432
+ await this.http.delete(
433
+ `organizations/${organizationId}/webhooks/${webhookId}`
434
+ );
435
+ }
436
+ /**
437
+ * Get webhook delivery history
438
+ */
439
+ async deliveries(organizationId, webhookId) {
440
+ return this.http.get(`organizations/${organizationId}/webhooks/${webhookId}/deliveries`).json();
441
+ }
442
+ /**
443
+ * Send test webhook
444
+ */
445
+ async test(organizationId, webhookId) {
446
+ return this.http.post(`organizations/${organizationId}/webhooks/${webhookId}/test`).json();
447
+ }
448
+ };
449
+
450
+ // src/client.ts
451
+ var Timbrix = class {
452
+ http;
453
+ authStrategy;
454
+ auth;
455
+ organizations;
456
+ webhooks;
457
+ apiKeys;
458
+ users;
459
+ customers;
460
+ oauth;
461
+ products;
462
+ constructor(config = {}) {
463
+ const baseUrl = config.baseUrl || "http://localhost:3001/api";
464
+ if (config.bearerToken) {
465
+ this.authStrategy = new BearerAuth(config.bearerToken);
466
+ } else if (config.apiKey) {
467
+ this.authStrategy = new ApiKeyAuth(config.apiKey);
468
+ }
469
+ this.http = ky.create({
470
+ prefixUrl: baseUrl,
471
+ headers: {
472
+ "Content-Type": "application/json"
473
+ },
474
+ hooks: {
475
+ beforeRequest: [
476
+ (request) => {
477
+ if (this.authStrategy) {
478
+ const authHeaders = this.authStrategy.getHeaders();
479
+ Object.entries(authHeaders).forEach(([key, value]) => {
480
+ request.headers.set(key, value);
481
+ });
482
+ }
483
+ }
484
+ ]
485
+ }
486
+ });
487
+ this.auth = new AuthResource(this.http);
488
+ this.organizations = new OrganizationsResource(this.http);
489
+ this.webhooks = new WebhooksResource(this.http);
490
+ this.apiKeys = new ApiKeysResource(this.http);
491
+ this.users = new UsersResource(this.http);
492
+ this.customers = new CustomersResource(this.http);
493
+ this.oauth = new OAuthResource(this.http);
494
+ this.products = new ProductsResource(this.http);
495
+ }
496
+ /**
497
+ * Update authentication strategy (useful for CLI when token changes)
498
+ */
499
+ setAuth(bearerToken, apiKey) {
500
+ if (bearerToken) {
501
+ this.authStrategy = new BearerAuth(bearerToken);
502
+ } else if (apiKey) {
503
+ this.authStrategy = new ApiKeyAuth(apiKey);
504
+ } else {
505
+ this.authStrategy = void 0;
506
+ }
507
+ }
508
+ /**
509
+ * Make a custom request
510
+ */
511
+ async request(url, options) {
512
+ return this.http(url, options).json();
513
+ }
514
+ };
515
+ export {
516
+ ApiKeyAuth,
517
+ ApiKeysResource,
518
+ AuthResource,
519
+ BearerAuth,
520
+ CustomersResource,
521
+ OAuthResource,
522
+ OrganizationsResource,
523
+ ProductsResource,
524
+ Timbrix,
525
+ UsersResource,
526
+ WebhooksResource
527
+ };
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@timbrix/sdk",
3
+ "version": "0.1.0",
4
+ "description": "TypeScript SDK for Timbrix API",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "keywords": [
19
+ "timbrix",
20
+ "api",
21
+ "client",
22
+ "sdk"
23
+ ],
24
+ "license": "MIT",
25
+ "dependencies": {
26
+ "ky": "^1.14.3"
27
+ },
28
+ "devDependencies": {
29
+ "tsup": "^8.5.1",
30
+ "typescript": "^5.9.3",
31
+ "@repo/eslint-config": "0.1.0",
32
+ "@repo/typescript-config": "0.1.0"
33
+ },
34
+ "scripts": {
35
+ "build": "tsup src/index.ts --format cjs,esm --dts",
36
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
37
+ "lint": "eslint \"src/**/*.ts\" --fix",
38
+ "check-types": "tsc --noEmit"
39
+ }
40
+ }