@buildspacestudio/sdk 0.2.2 → 0.4.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.
Files changed (106) hide show
  1. package/README.md +126 -0
  2. package/dist/auth/index.cjs +259 -0
  3. package/dist/auth/index.cjs.map +1 -0
  4. package/dist/auth/index.d.cts +3 -0
  5. package/dist/auth/index.d.ts +3 -5
  6. package/dist/auth/index.js +255 -2
  7. package/dist/auth/index.js.map +1 -1
  8. package/dist/billing/index.cjs +226 -0
  9. package/dist/billing/index.cjs.map +1 -0
  10. package/dist/billing/index.d.cts +60 -0
  11. package/dist/billing/index.d.ts +60 -0
  12. package/dist/billing/index.js +222 -0
  13. package/dist/billing/index.js.map +1 -0
  14. package/dist/client/index.cjs +558 -0
  15. package/dist/client/index.cjs.map +1 -0
  16. package/dist/client/index.d.cts +89 -0
  17. package/dist/client/index.d.ts +12 -7
  18. package/dist/client/index.js +546 -105
  19. package/dist/client/index.js.map +1 -1
  20. package/dist/client-BYUWUiGZ.d.cts +143 -0
  21. package/dist/{auth/client.d.ts → client-ByNR5EZz.d.ts} +7 -5
  22. package/dist/client-D0vypxWb.d.cts +58 -0
  23. package/dist/{auth/client.js → client-D7bqvGJv.d.cts} +27 -30
  24. package/dist/{events/client.d.ts → client-DbGRRMt7.d.ts} +5 -3
  25. package/dist/client-d7kX5WfR.d.ts +143 -0
  26. package/dist/events/index.cjs +131 -0
  27. package/dist/events/index.cjs.map +1 -0
  28. package/dist/events/{server.d.ts → index.d.cts} +7 -4
  29. package/dist/events/index.d.ts +59 -4
  30. package/dist/events/index.js +127 -2
  31. package/dist/events/index.js.map +1 -1
  32. package/dist/http-D2gXpNpr.d.cts +100 -0
  33. package/dist/http-D2gXpNpr.d.ts +100 -0
  34. package/dist/index.cjs +1029 -0
  35. package/dist/index.cjs.map +1 -0
  36. package/dist/index.d.cts +92 -0
  37. package/dist/index.d.ts +21 -15
  38. package/dist/index.js +1010 -106
  39. package/dist/index.js.map +1 -1
  40. package/dist/next/index.cjs +183 -0
  41. package/dist/next/index.cjs.map +1 -0
  42. package/dist/next/index.d.cts +164 -0
  43. package/dist/next/index.d.ts +164 -0
  44. package/dist/next/index.js +172 -0
  45. package/dist/next/index.js.map +1 -0
  46. package/dist/notifications/index.cjs +56 -0
  47. package/dist/notifications/index.cjs.map +1 -0
  48. package/dist/notifications/{server.d.ts → index.d.cts} +8 -6
  49. package/dist/notifications/index.d.ts +79 -3
  50. package/dist/notifications/index.js +53 -1
  51. package/dist/notifications/index.js.map +1 -1
  52. package/dist/react/index.cjs +120 -0
  53. package/dist/react/index.cjs.map +1 -0
  54. package/dist/react/index.d.cts +567 -0
  55. package/dist/react/index.d.ts +567 -0
  56. package/dist/react/index.js +92 -0
  57. package/dist/react/index.js.map +1 -0
  58. package/dist/server-CoPDzSUP.d.cts +117 -0
  59. package/dist/{auth/server.d.ts → server-Suq3tZZC.d.ts} +8 -6
  60. package/dist/storage/index.cjs +213 -0
  61. package/dist/storage/index.cjs.map +1 -0
  62. package/dist/storage/index.d.cts +195 -0
  63. package/dist/storage/index.d.ts +195 -5
  64. package/dist/storage/index.js +209 -2
  65. package/dist/storage/index.js.map +1 -1
  66. package/package.json +124 -16
  67. package/dist/auth/client.d.ts.map +0 -1
  68. package/dist/auth/client.js.map +0 -1
  69. package/dist/auth/index.d.ts.map +0 -1
  70. package/dist/auth/server.d.ts.map +0 -1
  71. package/dist/auth/server.js +0 -148
  72. package/dist/auth/server.js.map +0 -1
  73. package/dist/client/index.d.ts.map +0 -1
  74. package/dist/config.d.ts +0 -40
  75. package/dist/config.d.ts.map +0 -1
  76. package/dist/config.js +0 -27
  77. package/dist/config.js.map +0 -1
  78. package/dist/errors.d.ts +0 -31
  79. package/dist/errors.d.ts.map +0 -1
  80. package/dist/errors.js +0 -30
  81. package/dist/errors.js.map +0 -1
  82. package/dist/events/client.d.ts.map +0 -1
  83. package/dist/events/client.js +0 -97
  84. package/dist/events/client.js.map +0 -1
  85. package/dist/events/index.d.ts.map +0 -1
  86. package/dist/events/server.d.ts.map +0 -1
  87. package/dist/events/server.js +0 -65
  88. package/dist/events/server.js.map +0 -1
  89. package/dist/http.d.ts +0 -39
  90. package/dist/http.d.ts.map +0 -1
  91. package/dist/http.js +0 -74
  92. package/dist/http.js.map +0 -1
  93. package/dist/index.d.ts.map +0 -1
  94. package/dist/notifications/index.d.ts.map +0 -1
  95. package/dist/notifications/server.d.ts.map +0 -1
  96. package/dist/notifications/server.js +0 -73
  97. package/dist/notifications/server.js.map +0 -1
  98. package/dist/storage/client.d.ts +0 -91
  99. package/dist/storage/client.d.ts.map +0 -1
  100. package/dist/storage/client.js +0 -117
  101. package/dist/storage/client.js.map +0 -1
  102. package/dist/storage/index.d.ts.map +0 -1
  103. package/dist/storage/server.d.ts +0 -104
  104. package/dist/storage/server.d.ts.map +0 -1
  105. package/dist/storage/server.js +0 -104
  106. package/dist/storage/server.js.map +0 -1
@@ -1,114 +1,555 @@
1
- import { AuthClientNamespace } from "../auth";
2
- import { resolveConfig } from "../config";
3
- import { BuildspaceError } from "../errors";
4
- import { EventsClientNamespace } from "../events";
5
- import { HttpTransport } from "../http";
6
- import { StorageClientNamespace } from "../storage";
7
- /**
8
- * Buildspace client SDK use with a publishable key (`bs_pub_*`).
9
- *
10
- * Provides client-safe access to auth URL generation, event tracking
11
- * (with automatic batching), and file uploads. For server-side usage
12
- * with full API access, use `new Buildspace()` from `@buildspacestudio/sdk`.
13
- *
14
- * @example
15
- * ```ts
16
- * import { createClient } from "@buildspacestudio/sdk/client";
17
- *
18
- * const buildspace = createClient(process.env.NEXT_PUBLIC_BUILDSPACE_KEY!);
19
- *
20
- * // Generate a sign-in URL
21
- * const url = buildspace.auth.getSignInUrl({
22
- * redirectUri: "https://yourapp.com/auth/callback",
23
- * });
24
- *
25
- * // Track an event (fire and forget)
26
- * buildspace.events.track("button.clicked", { label: "upgrade" });
27
- *
28
- * // Upload a file
29
- * const { key, url } = await buildspace.storage.upload(file, {
30
- * path: "avatars/user-123.png",
31
- * });
32
- * ```
33
- */
34
- class BuildspaceClient {
35
- transport;
36
- config;
37
- _auth = null;
38
- _events = null;
39
- _storage = null;
40
- /**
41
- * Create a new client SDK instance.
42
- *
43
- * @param publishableKey - Your Buildspace publishable key (starts with `bs_pub_`).
44
- * @param config - Optional configuration overrides.
45
- */
46
- constructor(publishableKey, config = {}) {
47
- this.config = config;
48
- this.transport = new HttpTransport({
49
- key: publishableKey,
50
- resolvedConfig: resolveConfig("client", config),
51
- });
1
+ // src/auth/client.ts
2
+ var AuthClientNamespace = class {
3
+ transport;
4
+ constructor(transport) {
5
+ this.transport = transport;
6
+ }
7
+ /**
8
+ * Build a URL that redirects the user to the Buildspace sign-in page.
9
+ *
10
+ * After the user authenticates, they are redirected back to `redirectUri`
11
+ * with a `?code=` parameter that can be exchanged for tokens via
12
+ * `buildspace.auth.handleCallback()` on the server.
13
+ *
14
+ * @param opts - Sign-in URL options.
15
+ * @returns The full sign-in URL as a string.
16
+ */
17
+ getSignInUrl(opts) {
18
+ const url = new URL("/sign-in", this.transport.loginUrl);
19
+ if (opts.appSlug) {
20
+ url.searchParams.set("app", opts.appSlug);
52
21
  }
53
- /** Client-side auth: sign-in and sign-up URL generation. */
54
- get auth() {
55
- this._auth ??= new AuthClientNamespace(this.transport);
56
- return this._auth;
22
+ url.searchParams.set("redirect_uri", opts.redirectUri);
23
+ url.searchParams.set("client_id", this.transport.key);
24
+ if (opts.env) {
25
+ url.searchParams.set("env", opts.env);
57
26
  }
58
- /** Client-side event tracking with automatic batching. */
59
- get events() {
60
- this._events ??= new EventsClientNamespace(this.transport, this.config.events);
61
- return this._events;
27
+ return url.toString();
28
+ }
29
+ /**
30
+ * Build a URL that redirects the user to the Buildspace sign-up page.
31
+ *
32
+ * Works identically to {@link getSignInUrl} but directs the user to the
33
+ * registration flow instead.
34
+ *
35
+ * @param opts - Sign-up URL options.
36
+ * @returns The full sign-up URL as a string.
37
+ */
38
+ getSignUpUrl(opts) {
39
+ const url = new URL("/sign-up", this.transport.loginUrl);
40
+ if (opts.appSlug) {
41
+ url.searchParams.set("app", opts.appSlug);
62
42
  }
63
- /** Client-side file storage: uploads, downloads, listing, deletion. */
64
- get storage() {
65
- this._storage ??= new StorageClientNamespace(this.transport);
66
- return this._storage;
43
+ url.searchParams.set("redirect_uri", opts.redirectUri);
44
+ url.searchParams.set("client_id", this.transport.key);
45
+ if (opts.env) {
46
+ url.searchParams.set("env", opts.env);
67
47
  }
68
- /**
69
- * Notifications are server-only and not available on the client SDK.
70
- *
71
- * @throws {BuildspaceError} Always throws — use the server SDK for notifications.
72
- */
73
- get notifications() {
74
- throw new BuildspaceError({
75
- service: "notifications",
76
- status: 400,
77
- code: "notifications/server-only",
78
- message: "Notifications require a secret key. Use the server SDK via new Buildspace() from '@buildspacestudio/sdk'.",
79
- });
48
+ return url.toString();
49
+ }
50
+ };
51
+
52
+ // src/errors.ts
53
+ var BuildspaceError = class extends Error {
54
+ /** Machine-readable error code, e.g. `"auth/invalid-token"`. */
55
+ code;
56
+ /** Which service produced the error. */
57
+ service;
58
+ /** HTTP status code from the API. */
59
+ status;
60
+ constructor({
61
+ code,
62
+ message,
63
+ service,
64
+ status
65
+ }) {
66
+ super(message);
67
+ this.name = "BuildspaceError";
68
+ this.code = code;
69
+ this.service = service;
70
+ this.status = status;
71
+ }
72
+ };
73
+
74
+ // src/billing/shared.ts
75
+ function checkoutRequestBody(opts) {
76
+ return {
77
+ app_user_id: "appUserId" in opts ? opts.appUserId : void 0,
78
+ cancel_url: opts.cancelUrl,
79
+ checkout_request_id: opts.checkoutRequestId,
80
+ lookup_key: opts.lookupKey,
81
+ metadata: opts.metadata,
82
+ price_id: opts.priceId,
83
+ quantity: opts.quantity,
84
+ success_url: opts.successUrl,
85
+ user_id: "userId" in opts ? opts.userId : void 0
86
+ };
87
+ }
88
+ function portalRequestBody(opts) {
89
+ return {
90
+ app_user_id: "appUserId" in opts ? opts.appUserId : void 0,
91
+ return_url: opts.returnUrl,
92
+ user_id: "userId" in opts ? opts.userId : void 0
93
+ };
94
+ }
95
+
96
+ // src/billing/client.ts
97
+ function redirectTo(url) {
98
+ const browser = globalThis;
99
+ if (!browser.window?.location) {
100
+ throw new Error("redirectToCheckout can only be used in a browser environment");
101
+ }
102
+ browser.window.location.href = url;
103
+ }
104
+ var BillingClientNamespace = class {
105
+ transport;
106
+ constructor(transport) {
107
+ this.transport = transport;
108
+ }
109
+ /**
110
+ * Read whether billing is enabled for the app environment tied to this
111
+ * publishable key, and whether the connected Stripe account is in test or
112
+ * live mode.
113
+ *
114
+ * Render a "Test mode" banner in your app whenever `testMode` is true.
115
+ */
116
+ getStatus() {
117
+ return this.transport.request({
118
+ service: "billing",
119
+ path: "/v1/billing/status"
120
+ });
121
+ }
122
+ /**
123
+ * List the active billing products for the app environment tied to this
124
+ * publishable key.
125
+ */
126
+ listProducts() {
127
+ return this.transport.request({
128
+ service: "billing",
129
+ path: "/v1/billing/products"
130
+ });
131
+ }
132
+ /**
133
+ * List the active billing prices for the app environment tied to this
134
+ * publishable key.
135
+ */
136
+ listPrices() {
137
+ return this.transport.request({
138
+ service: "billing",
139
+ path: "/v1/billing/prices"
140
+ });
141
+ }
142
+ /**
143
+ * Create a Checkout Session for the signed-in browser user and redirect to
144
+ * the Stripe-hosted Checkout page.
145
+ *
146
+ * This method depends on a Buildspace session being available through
147
+ * `setSession()` or your app's authenticated request context.
148
+ */
149
+ async redirectToCheckout(opts) {
150
+ const checkout = await this.transport.request({
151
+ service: "billing",
152
+ path: "/v1/billing/checkout",
153
+ method: "POST",
154
+ body: checkoutRequestBody(opts)
155
+ });
156
+ redirectTo(checkout.url);
157
+ }
158
+ /**
159
+ * Open the Stripe-hosted customer portal for the signed-in browser user.
160
+ */
161
+ async redirectToPortal(opts) {
162
+ const portal = await this.transport.request({
163
+ service: "billing",
164
+ path: "/v1/billing/portal",
165
+ method: "POST",
166
+ body: portalRequestBody(opts)
167
+ });
168
+ redirectTo(portal.url);
169
+ }
170
+ /**
171
+ * Discoverable alias for redirectToPortal — opens the Stripe-hosted customer
172
+ * portal so the signed-in user can manage their subscription, payment method,
173
+ * and invoices.
174
+ */
175
+ manageSubscription(opts) {
176
+ return this.redirectToPortal(opts);
177
+ }
178
+ /**
179
+ * Read the current subscription state for the signed-in browser user.
180
+ */
181
+ getSubscription() {
182
+ return this.transport.request({
183
+ service: "billing",
184
+ path: "/v1/billing/subscription"
185
+ });
186
+ }
187
+ /**
188
+ * Read the current paid entitlement state for the signed-in browser user.
189
+ */
190
+ getEntitlements() {
191
+ return this.transport.request({
192
+ service: "billing",
193
+ path: "/v1/billing/entitlements"
194
+ });
195
+ }
196
+ };
197
+
198
+ // src/config.ts
199
+ var DEFAULT_BASE_URL = "https://api.buildspace.studio";
200
+ var DEFAULT_LOGIN_URL = "https://login.buildspace.studio";
201
+ var DEFAULT_API_VERSION = "2025-06-01";
202
+ function resolveConfig(mode, config = {}) {
203
+ return {
204
+ mode,
205
+ baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,
206
+ loginUrl: config.loginUrl ?? DEFAULT_LOGIN_URL,
207
+ version: config.version ?? DEFAULT_API_VERSION,
208
+ fetch: config.fetch ?? fetch
209
+ };
210
+ }
211
+ function formatMode(mode) {
212
+ return mode === "server" ? "server SDK" : "client SDK";
213
+ }
214
+ function validateApiKey({ mode, key }) {
215
+ if (!key) {
216
+ throw new Error(`Missing API key. The ${formatMode(mode)} requires a valid Buildspace key.`);
217
+ }
218
+ if (mode === "server" && !key.startsWith("bs_sec_")) {
219
+ throw new Error(
220
+ "The server SDK requires a secret key (bs_sec_*). Use createClient() from '@buildspacestudio/sdk/client' for browser usage with publishable keys."
221
+ );
222
+ }
223
+ if (mode === "client" && !key.startsWith("bs_pub_")) {
224
+ throw new Error(
225
+ "The client SDK requires a publishable key (bs_pub_*). Use new Buildspace() from '@buildspacestudio/sdk' for server usage with secret keys."
226
+ );
227
+ }
228
+ }
229
+
230
+ // src/events/client.ts
231
+ var EventsClientNamespace = class {
232
+ queue = [];
233
+ transport;
234
+ timer = null;
235
+ constructor(transport, config = {}) {
236
+ this.transport = transport;
237
+ const flushInterval = config.flushInterval ?? 5e3;
238
+ this.maxBatchSize = config.maxBatchSize ?? 20;
239
+ this.timer = setInterval(() => {
240
+ this.flush().catch(() => {
241
+ });
242
+ }, flushInterval);
243
+ }
244
+ maxBatchSize;
245
+ /**
246
+ * Queue an event for batched delivery.
247
+ *
248
+ * This method is synchronous and returns immediately. Events are
249
+ * automatically flushed when the batch size is reached or on the
250
+ * configured interval.
251
+ *
252
+ * @param event - Event name, e.g. `"button.clicked"`.
253
+ * @param properties - Arbitrary key-value data to attach.
254
+ * @param actorId - Identifier of the user or entity that triggered the event.
255
+ */
256
+ track(event, properties, actorId) {
257
+ this.queue.push({
258
+ event,
259
+ properties,
260
+ actor_id: actorId,
261
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
262
+ });
263
+ if (this.queue.length >= this.maxBatchSize) {
264
+ this.flush().catch(() => {
265
+ });
80
266
  }
81
- /** Clear the stored session token. */
82
- clearSession() {
83
- this.transport.clearSession();
267
+ }
268
+ /**
269
+ * Send all queued events to the API immediately.
270
+ *
271
+ * If the flush fails, events are re-queued for the next attempt.
272
+ */
273
+ async flush() {
274
+ if (this.queue.length === 0) {
275
+ return;
84
276
  }
85
- /**
86
- * Set a session token that will be sent as `X-Session-Token` on all
87
- * subsequent API requests.
88
- *
89
- * @param sessionToken - The session token to attach to requests.
90
- */
91
- setSession(sessionToken) {
92
- this.transport.setSession(sessionToken);
277
+ const batch = this.queue.splice(0, this.queue.length);
278
+ try {
279
+ await this.transport.request({
280
+ service: "events",
281
+ path: "/v1/events/batch",
282
+ method: "POST",
283
+ keepalive: true,
284
+ body: { events: batch }
285
+ });
286
+ } catch {
287
+ this.queue.unshift(...batch);
288
+ throw new Error("Failed to flush events batch.");
93
289
  }
290
+ }
291
+ /**
292
+ * Stop the automatic flush timer and send any remaining events.
293
+ *
294
+ * Call this during app shutdown or cleanup to ensure no events are lost.
295
+ */
296
+ async shutdown() {
297
+ if (this.timer) {
298
+ clearInterval(this.timer);
299
+ this.timer = null;
300
+ }
301
+ await this.flush();
302
+ }
303
+ };
304
+
305
+ // src/http.ts
306
+ var HttpTransport = class {
307
+ baseUrl;
308
+ fetcher;
309
+ key;
310
+ loginUrl;
311
+ mode;
312
+ version;
313
+ sessionToken = null;
314
+ constructor({ key, resolvedConfig }) {
315
+ validateApiKey({ mode: resolvedConfig.mode, key });
316
+ this.key = key;
317
+ this.mode = resolvedConfig.mode;
318
+ this.baseUrl = resolvedConfig.baseUrl;
319
+ this.loginUrl = resolvedConfig.loginUrl;
320
+ this.version = resolvedConfig.version;
321
+ this.fetcher = resolvedConfig.fetch;
322
+ }
323
+ /** Remove the stored session token. */
324
+ clearSession() {
325
+ this.sessionToken = null;
326
+ }
327
+ /** Return the current session token, or `null` if none is set. */
328
+ getSessionToken() {
329
+ return this.sessionToken;
330
+ }
331
+ /** Store a session token that will be sent as `X-Session-Token` on subsequent requests. */
332
+ setSession(sessionToken) {
333
+ this.sessionToken = sessionToken;
334
+ }
335
+ async request({
336
+ service,
337
+ path,
338
+ method = "GET",
339
+ query,
340
+ body,
341
+ headers,
342
+ keepalive
343
+ }) {
344
+ const url = new URL(path, this.baseUrl);
345
+ if (query) {
346
+ for (const [key, value] of Object.entries(query)) {
347
+ if (value !== void 0) {
348
+ url.searchParams.set(key, String(value));
349
+ }
350
+ }
351
+ }
352
+ const response = await this.fetcher(url.toString(), {
353
+ method,
354
+ keepalive,
355
+ headers: {
356
+ Authorization: `Bearer ${this.key}`,
357
+ "Content-Type": "application/json",
358
+ "X-Buildspace-Version": this.version,
359
+ ...this.sessionToken ? { "X-Session-Token": this.sessionToken } : {},
360
+ ...headers
361
+ },
362
+ body: body === void 0 ? void 0 : JSON.stringify(body)
363
+ });
364
+ if (!response.ok) {
365
+ const payload = await response.json().catch(() => null);
366
+ throw new BuildspaceError({
367
+ service,
368
+ status: response.status,
369
+ code: payload?.code ?? `${service}/http-${response.status}`,
370
+ message: payload?.error ?? payload?.message ?? response.statusText
371
+ });
372
+ }
373
+ if (response.status === 204) {
374
+ return void 0;
375
+ }
376
+ return response.json();
377
+ }
378
+ };
379
+
380
+ // src/storage/client.ts
381
+ var StorageClientNamespace = class {
382
+ transport;
383
+ constructor(transport) {
384
+ this.transport = transport;
385
+ }
386
+ /**
387
+ * Upload a `File` or `Blob` to Buildspace storage.
388
+ *
389
+ * This method handles the full upload flow:
390
+ * 1. Requests a pre-signed upload URL from the API
391
+ * 2. Uploads the file directly to the storage provider
392
+ * 3. Returns a signed download URL for the uploaded file
393
+ *
394
+ * @param file - The file or blob to upload.
395
+ * @param opts - Upload options including the storage path.
396
+ * @returns The storage key, file size, and a signed download URL.
397
+ *
398
+ * @throws {BuildspaceError} If the upload URL request or the direct upload fails.
399
+ */
400
+ async upload(file, opts) {
401
+ const contentType = opts.contentType ?? (file instanceof File ? file.type : "application/octet-stream");
402
+ const signed = await this.transport.request({
403
+ service: "storage",
404
+ path: "/v1/storage/upload",
405
+ method: "POST",
406
+ body: {
407
+ path: opts.path,
408
+ content_type: contentType,
409
+ size: file.size
410
+ }
411
+ });
412
+ const response = await this.transport.fetcher(signed.upload_url, {
413
+ method: "PUT",
414
+ headers: { "Content-Type": contentType },
415
+ body: file
416
+ });
417
+ if (!response.ok) {
418
+ throw new BuildspaceError({
419
+ service: "storage",
420
+ status: response.status,
421
+ code: "storage/upload-failed",
422
+ message: `Direct upload failed: ${response.statusText}`
423
+ });
424
+ }
425
+ const { url } = await this.getUrl(signed.key);
426
+ return {
427
+ key: signed.key,
428
+ size: file.size,
429
+ url
430
+ };
431
+ }
432
+ /**
433
+ * Get a time-limited signed URL for downloading a stored file.
434
+ *
435
+ * @param key - The storage key of the object.
436
+ * @param opts - Optional settings.
437
+ * @param opts.expiresIn - URL lifetime in seconds.
438
+ */
439
+ getUrl(key, opts) {
440
+ return this.transport.request({
441
+ service: "storage",
442
+ path: "/v1/storage/url",
443
+ query: {
444
+ key,
445
+ expires_in: opts?.expiresIn
446
+ }
447
+ });
448
+ }
449
+ /**
450
+ * List stored objects, optionally filtered by key prefix.
451
+ *
452
+ * @param prefix - Only return objects whose key starts with this prefix.
453
+ * @param opts - Pagination options.
454
+ */
455
+ list(prefix, opts) {
456
+ return this.transport.request({
457
+ service: "storage",
458
+ path: "/v1/storage/objects",
459
+ query: {
460
+ prefix,
461
+ limit: opts?.limit,
462
+ offset: opts?.offset
463
+ }
464
+ });
465
+ }
466
+ /**
467
+ * Delete a stored object by key.
468
+ *
469
+ * @param key - The storage key of the object to delete.
470
+ */
471
+ async delete(key) {
472
+ await this.transport.request({
473
+ service: "storage",
474
+ path: "/v1/storage/object",
475
+ method: "DELETE",
476
+ body: { key }
477
+ });
478
+ }
479
+ };
480
+
481
+ // src/client/index.ts
482
+ var BuildspaceClient = class {
483
+ transport;
484
+ config;
485
+ _auth = null;
486
+ _billing = null;
487
+ _events = null;
488
+ _storage = null;
489
+ /**
490
+ * Create a new client SDK instance.
491
+ *
492
+ * @param publishableKey - Your Buildspace publishable key (starts with `bs_pub_`).
493
+ * @param config - Optional configuration overrides.
494
+ */
495
+ constructor(publishableKey, config = {}) {
496
+ this.config = config;
497
+ this.transport = new HttpTransport({
498
+ key: publishableKey,
499
+ resolvedConfig: resolveConfig("client", config)
500
+ });
501
+ }
502
+ /** Client-side auth: sign-in and sign-up URL generation. */
503
+ get auth() {
504
+ this._auth ??= new AuthClientNamespace(this.transport);
505
+ return this._auth;
506
+ }
507
+ /** Client-side event tracking with automatic batching. */
508
+ get events() {
509
+ this._events ??= new EventsClientNamespace(this.transport, this.config.events);
510
+ return this._events;
511
+ }
512
+ /** Client-side billing: list prices and redirect to Checkout or Portal. */
513
+ get billing() {
514
+ this._billing ??= new BillingClientNamespace(this.transport);
515
+ return this._billing;
516
+ }
517
+ /** Client-side file storage: uploads, downloads, listing, deletion. */
518
+ get storage() {
519
+ this._storage ??= new StorageClientNamespace(this.transport);
520
+ return this._storage;
521
+ }
522
+ /**
523
+ * Notifications are server-only and not available on the client SDK.
524
+ *
525
+ * @throws {BuildspaceError} Always throws — use the server SDK for notifications.
526
+ */
527
+ get notifications() {
528
+ throw new BuildspaceError({
529
+ service: "notifications",
530
+ status: 400,
531
+ code: "notifications/server-only",
532
+ message: "Notifications require a secret key. Use the server SDK via new Buildspace() from '@buildspacestudio/sdk'."
533
+ });
534
+ }
535
+ /** Clear the stored session token. */
536
+ clearSession() {
537
+ this.transport.clearSession();
538
+ }
539
+ /**
540
+ * Set a session token that will be sent as `X-Session-Token` on all
541
+ * subsequent API requests.
542
+ *
543
+ * @param sessionToken - The session token to attach to requests.
544
+ */
545
+ setSession(sessionToken) {
546
+ this.transport.setSession(sessionToken);
547
+ }
548
+ };
549
+ function createClient(publishableKey, config = {}) {
550
+ return new BuildspaceClient(publishableKey, config);
94
551
  }
95
- /**
96
- * Create a Buildspace client SDK instance.
97
- *
98
- * Preferred over `new BuildspaceClient()` for a more concise API.
99
- *
100
- * @param publishableKey - Your Buildspace publishable key (starts with `bs_pub_`).
101
- * @param config - Optional configuration overrides.
102
- *
103
- * @example
104
- * ```ts
105
- * import { createClient } from "@buildspacestudio/sdk/client";
106
- *
107
- * const buildspace = createClient(process.env.NEXT_PUBLIC_BUILDSPACE_KEY!);
108
- * ```
109
- */
110
- export function createClient(publishableKey, config = {}) {
111
- return new BuildspaceClient(publishableKey, config);
112
- }
113
- export { BuildspaceClient };
552
+
553
+ export { BuildspaceClient, createClient };
554
+ //# sourceMappingURL=index.js.map
114
555
  //# sourceMappingURL=index.js.map