@dream-api/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.js ADDED
@@ -0,0 +1,599 @@
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/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ DreamAPI: () => DreamAPI,
24
+ DreamAPIException: () => DreamAPIException,
25
+ default: () => index_default
26
+ });
27
+ module.exports = __toCommonJS(index_exports);
28
+
29
+ // src/types.ts
30
+ var DreamAPIException = class extends Error {
31
+ constructor(error, status = 500) {
32
+ super(error.message);
33
+ this.name = "DreamAPIException";
34
+ this.status = status;
35
+ this.code = error.error;
36
+ }
37
+ };
38
+
39
+ // src/client.ts
40
+ var DEFAULT_BASE_URL = "https://api-multi.k-c-sheffield012376.workers.dev";
41
+ var DEFAULT_SIGNUP_URL = "https://sign-up.k-c-sheffield012376.workers.dev";
42
+ var DEFAULT_CLERK_URL = "https://composed-blowfish-76.accounts.dev";
43
+ var DreamClient = class {
44
+ constructor(config) {
45
+ this.userToken = null;
46
+ this.tokenRefresher = null;
47
+ if (!config.secretKey) {
48
+ throw new Error("DreamAPI: secretKey is required");
49
+ }
50
+ this.secretKey = config.secretKey;
51
+ this.publishableKey = config.publishableKey;
52
+ this.baseUrl = config.baseUrl || DEFAULT_BASE_URL;
53
+ this.signupUrl = config.signupUrl || DEFAULT_SIGNUP_URL;
54
+ this.clerkUrl = config.clerkBaseUrl || DEFAULT_CLERK_URL;
55
+ }
56
+ /**
57
+ * Set the end-user JWT token for user-specific operations.
58
+ * Call this after the user signs in via Clerk.
59
+ */
60
+ setUserToken(token) {
61
+ this.userToken = token;
62
+ }
63
+ /**
64
+ * Clear the current user token (on sign out)
65
+ */
66
+ clearUserToken() {
67
+ this.userToken = null;
68
+ }
69
+ /**
70
+ * Set a function to refresh the token before API calls
71
+ */
72
+ setTokenRefresher(refresher) {
73
+ this.tokenRefresher = refresher;
74
+ }
75
+ /**
76
+ * Refresh token if we have a refresher set
77
+ */
78
+ async ensureFreshToken() {
79
+ if (this.tokenRefresher) {
80
+ const newToken = await this.tokenRefresher();
81
+ if (newToken) {
82
+ this.userToken = newToken;
83
+ }
84
+ }
85
+ }
86
+ /**
87
+ * Get the publishable key
88
+ */
89
+ getPublishableKey() {
90
+ return this.publishableKey;
91
+ }
92
+ /**
93
+ * Get the sign-up URL base
94
+ */
95
+ getSignupBaseUrl() {
96
+ return this.signupUrl;
97
+ }
98
+ /**
99
+ * Get the Clerk base URL for hosted auth pages
100
+ */
101
+ getClerkBaseUrl() {
102
+ return this.clerkUrl;
103
+ }
104
+ /**
105
+ * Make an authenticated request to the API
106
+ */
107
+ async request(method, endpoint, options = {}) {
108
+ const { body, requiresUserToken = false } = options;
109
+ const headers = {
110
+ "Authorization": `Bearer ${this.secretKey}`,
111
+ "Content-Type": "application/json"
112
+ };
113
+ if (this.publishableKey) {
114
+ headers["X-Publishable-Key"] = this.publishableKey;
115
+ }
116
+ if (requiresUserToken) {
117
+ if (!this.userToken) {
118
+ throw new DreamAPIException(
119
+ { error: "auth_required", message: "User token required. Call setUserToken() first." },
120
+ 401
121
+ );
122
+ }
123
+ headers["X-Clerk-Token"] = this.userToken;
124
+ } else if (this.userToken) {
125
+ headers["X-Clerk-Token"] = this.userToken;
126
+ }
127
+ const url = `${this.baseUrl}${endpoint}`;
128
+ const response = await fetch(url, {
129
+ method,
130
+ headers,
131
+ body: body ? JSON.stringify(body) : void 0
132
+ });
133
+ const data = await response.json();
134
+ if (!response.ok) {
135
+ const error = data;
136
+ throw new DreamAPIException(error, response.status);
137
+ }
138
+ return data;
139
+ }
140
+ /**
141
+ * GET request
142
+ */
143
+ async get(endpoint, requiresUserToken = false) {
144
+ return this.request("GET", endpoint, { requiresUserToken });
145
+ }
146
+ /**
147
+ * POST request
148
+ */
149
+ async post(endpoint, body, requiresUserToken = false) {
150
+ return this.request("POST", endpoint, { body, requiresUserToken });
151
+ }
152
+ /**
153
+ * PATCH request
154
+ */
155
+ async patch(endpoint, body, requiresUserToken = false) {
156
+ return this.request("PATCH", endpoint, { body, requiresUserToken });
157
+ }
158
+ /**
159
+ * DELETE request
160
+ */
161
+ async delete(endpoint, requiresUserToken = false) {
162
+ return this.request("DELETE", endpoint, { requiresUserToken });
163
+ }
164
+ };
165
+
166
+ // src/clerk.ts
167
+ var CLERK_PUBLISHABLE_KEY = "pk_test_Y29tcG9zZWQtYmxvd2Zpc2gtNzYuY2xlcmsuYWNjb3VudHMuZGV2JA";
168
+ var CLERK_CDN_URL = "https://cdn.jsdelivr.net/npm/@clerk/clerk-js@5/dist/clerk.browser.js";
169
+ var JWT_TEMPLATE = "end-user-api";
170
+ function getClerk() {
171
+ return window.Clerk;
172
+ }
173
+ var ClerkManager = class {
174
+ constructor(onTokenChange) {
175
+ this.loaded = false;
176
+ this.token = null;
177
+ this.onTokenChange = onTokenChange;
178
+ }
179
+ /**
180
+ * Load Clerk SDK (call once on page load)
181
+ */
182
+ async load() {
183
+ if (this.loaded || typeof window === "undefined") return;
184
+ const existingClerk = getClerk();
185
+ if (existingClerk) {
186
+ this.loaded = true;
187
+ await this.checkSession();
188
+ return;
189
+ }
190
+ await new Promise((resolve, reject) => {
191
+ const script = document.createElement("script");
192
+ script.src = CLERK_CDN_URL;
193
+ script.async = true;
194
+ script.crossOrigin = "anonymous";
195
+ script.setAttribute("data-clerk-publishable-key", CLERK_PUBLISHABLE_KEY);
196
+ script.onload = () => resolve();
197
+ script.onerror = () => reject(new Error("Failed to load Clerk SDK"));
198
+ document.head.appendChild(script);
199
+ });
200
+ const clerk = getClerk();
201
+ if (clerk) {
202
+ await clerk.load();
203
+ }
204
+ this.loaded = true;
205
+ await this.checkSession();
206
+ }
207
+ /**
208
+ * Check if returning from auth and grab token
209
+ */
210
+ async checkSession() {
211
+ const clerk = getClerk();
212
+ if (!clerk?.session || !clerk?.user) {
213
+ return;
214
+ }
215
+ try {
216
+ this.token = await clerk.session.getToken({ template: JWT_TEMPLATE });
217
+ this.onTokenChange?.(this.token);
218
+ } catch (err) {
219
+ console.error("Failed to get Clerk token:", err);
220
+ }
221
+ }
222
+ /**
223
+ * Check if user is signed in
224
+ */
225
+ isSignedIn() {
226
+ const clerk = getClerk();
227
+ return !!clerk?.user && !!clerk?.session;
228
+ }
229
+ /**
230
+ * Get current user info
231
+ */
232
+ getUser() {
233
+ const clerk = getClerk();
234
+ if (!clerk?.user) return null;
235
+ const user = clerk.user;
236
+ const metadata = user.publicMetadata || {};
237
+ return {
238
+ id: user.id,
239
+ email: user.primaryEmailAddress?.emailAddress || "",
240
+ plan: metadata.plan || "free",
241
+ publishableKey: metadata.publishableKey || ""
242
+ };
243
+ }
244
+ /**
245
+ * Get current token
246
+ */
247
+ getToken() {
248
+ return this.token;
249
+ }
250
+ /**
251
+ * Refresh token (call before API requests)
252
+ */
253
+ async refreshToken() {
254
+ const clerk = getClerk();
255
+ if (!clerk?.session) return null;
256
+ try {
257
+ this.token = await clerk.session.getToken({ template: JWT_TEMPLATE });
258
+ this.onTokenChange?.(this.token);
259
+ return this.token;
260
+ } catch (err) {
261
+ console.error("Failed to refresh token:", err);
262
+ return null;
263
+ }
264
+ }
265
+ /**
266
+ * Sign out
267
+ */
268
+ async signOut() {
269
+ const clerk = getClerk();
270
+ if (!clerk) return;
271
+ await clerk.signOut();
272
+ this.token = null;
273
+ this.onTokenChange?.(null);
274
+ }
275
+ /**
276
+ * Check if we're returning from auth (has clerk params/cookies)
277
+ */
278
+ static hasAuthParams() {
279
+ if (typeof window === "undefined") return false;
280
+ return window.location.search.includes("__clerk") || document.cookie.includes("__clerk") || document.cookie.includes("__session");
281
+ }
282
+ };
283
+
284
+ // src/auth.ts
285
+ var AuthHelpers = class {
286
+ constructor(client) {
287
+ this.initialized = false;
288
+ this.client = client;
289
+ this.clerk = new ClerkManager((token) => {
290
+ if (token) {
291
+ this.client.setUserToken(token);
292
+ } else {
293
+ this.client.clearUserToken();
294
+ }
295
+ });
296
+ }
297
+ /**
298
+ * Initialize auth (loads Clerk internally).
299
+ * Call this on page load to detect existing sessions.
300
+ *
301
+ * @example
302
+ * ```typescript
303
+ * await api.auth.init();
304
+ * if (api.auth.isSignedIn()) {
305
+ * // User is signed in, token already set
306
+ * await api.usage.track();
307
+ * }
308
+ * ```
309
+ */
310
+ async init() {
311
+ if (this.initialized) return;
312
+ await this.clerk.load();
313
+ this.initialized = true;
314
+ }
315
+ /**
316
+ * Check if user is signed in
317
+ */
318
+ isSignedIn() {
319
+ return this.clerk.isSignedIn();
320
+ }
321
+ /**
322
+ * Get current user info
323
+ */
324
+ getUser() {
325
+ return this.clerk.getUser();
326
+ }
327
+ /**
328
+ * Sign out the current user
329
+ */
330
+ async signOut() {
331
+ await this.clerk.signOut();
332
+ }
333
+ /**
334
+ * Refresh the auth token (call before long sessions)
335
+ */
336
+ async refreshToken() {
337
+ await this.clerk.refreshToken();
338
+ }
339
+ /**
340
+ * Check if returning from auth redirect
341
+ */
342
+ static hasAuthParams() {
343
+ return ClerkManager.hasAuthParams();
344
+ }
345
+ /**
346
+ * Get the sign-up URL for new users.
347
+ *
348
+ * Redirects to the sign-up worker which handles user creation
349
+ * and sets the required metadata (publishableKey, plan).
350
+ *
351
+ * @example
352
+ * ```typescript
353
+ * const signupUrl = api.auth.getSignUpUrl({ redirect: '/dashboard' });
354
+ * // Returns: https://sign-up.../signup?pk=pk_xxx&redirect=...
355
+ * window.location.href = signupUrl;
356
+ * ```
357
+ */
358
+ getSignUpUrl(options) {
359
+ const pk = this.client.getPublishableKey();
360
+ if (!pk) {
361
+ throw new Error("DreamAPI: publishableKey required for auth URLs");
362
+ }
363
+ const baseUrl = this.client.getSignupBaseUrl();
364
+ const params = new URLSearchParams({
365
+ pk,
366
+ redirect: options.redirect
367
+ });
368
+ return `${baseUrl}/signup?${params.toString()}`;
369
+ }
370
+ /**
371
+ * Get the sign-in URL for returning users.
372
+ *
373
+ * Redirects to Clerk's hosted sign-in page. After sign-in,
374
+ * users are redirected to your specified URL.
375
+ *
376
+ * @example
377
+ * ```typescript
378
+ * const signinUrl = api.auth.getSignInUrl({ redirect: '/dashboard' });
379
+ * window.location.href = signinUrl;
380
+ * ```
381
+ */
382
+ getSignInUrl(options) {
383
+ const clerkBaseUrl = this.client.getClerkBaseUrl();
384
+ return `${clerkBaseUrl}/sign-in?redirect_url=${encodeURIComponent(options.redirect)}`;
385
+ }
386
+ /**
387
+ * Get the customer portal URL for account management.
388
+ *
389
+ * Redirects to Clerk's hosted account page where users can
390
+ * manage their profile, password, and security settings.
391
+ *
392
+ * Note: This is separate from billing management.
393
+ * For billing, use api.billing.openPortal().
394
+ *
395
+ * @example
396
+ * ```typescript
397
+ * const portalUrl = api.auth.getCustomerPortalUrl();
398
+ * window.location.href = portalUrl;
399
+ * ```
400
+ */
401
+ getCustomerPortalUrl() {
402
+ const clerkBaseUrl = this.client.getClerkBaseUrl();
403
+ return `${clerkBaseUrl}/user`;
404
+ }
405
+ };
406
+
407
+ // src/index.ts
408
+ var DreamAPI = class {
409
+ constructor(config) {
410
+ this.client = new DreamClient(config);
411
+ this.auth = new AuthHelpers(this.client);
412
+ this.customers = new CustomerAPI(this.client);
413
+ this.usage = new UsageAPI(this.client);
414
+ this.billing = new BillingAPI(this.client);
415
+ this.products = new ProductAPI(this.client);
416
+ this.dashboard = new DashboardAPI(this.client);
417
+ }
418
+ /**
419
+ * Set the end-user JWT token.
420
+ * Required for user-specific operations (usage, billing).
421
+ *
422
+ * @example
423
+ * ```typescript
424
+ * // After user signs in via Clerk
425
+ * const token = await clerk.session.getToken();
426
+ * api.setUserToken(token);
427
+ * ```
428
+ */
429
+ setUserToken(token) {
430
+ this.client.setUserToken(token);
431
+ }
432
+ /**
433
+ * Clear the user token (on sign out)
434
+ */
435
+ clearUserToken() {
436
+ this.client.clearUserToken();
437
+ }
438
+ };
439
+ var CustomerAPI = class {
440
+ constructor(client) {
441
+ this.client = client;
442
+ }
443
+ /**
444
+ * Create a new customer
445
+ *
446
+ * @example
447
+ * ```typescript
448
+ * const { customer } = await api.customers.create({
449
+ * email: 'user@example.com',
450
+ * firstName: 'John',
451
+ * plan: 'free',
452
+ * });
453
+ * ```
454
+ */
455
+ async create(params) {
456
+ return this.client.post("/api/customers", params);
457
+ }
458
+ /**
459
+ * Get a customer by ID
460
+ */
461
+ async get(customerId) {
462
+ return this.client.get(`/api/customers/${customerId}`);
463
+ }
464
+ /**
465
+ * Update a customer's plan
466
+ */
467
+ async update(customerId, params) {
468
+ return this.client.patch(`/api/customers/${customerId}`, params);
469
+ }
470
+ /**
471
+ * Delete a customer
472
+ */
473
+ async delete(customerId) {
474
+ return this.client.delete(`/api/customers/${customerId}`);
475
+ }
476
+ };
477
+ var UsageAPI = class {
478
+ constructor(client) {
479
+ this.client = client;
480
+ }
481
+ /**
482
+ * Track a usage event.
483
+ * Increments the user's usage counter for the current period.
484
+ *
485
+ * @example
486
+ * ```typescript
487
+ * const { usage } = await api.usage.track();
488
+ * console.log(`Used ${usage.usageCount} of ${usage.limit}`);
489
+ * ```
490
+ */
491
+ async track() {
492
+ const response = await this.client.post("/api/data", null, true);
493
+ if ("success" in response) {
494
+ return response;
495
+ }
496
+ return { success: true, usage: response };
497
+ }
498
+ /**
499
+ * Check current usage without incrementing.
500
+ *
501
+ * @example
502
+ * ```typescript
503
+ * const usage = await api.usage.check();
504
+ * if (usage.remaining <= 0) {
505
+ * // Show upgrade prompt
506
+ * }
507
+ * ```
508
+ */
509
+ async check() {
510
+ const response = await this.client.get("/api/usage", true);
511
+ return response.usage || response;
512
+ }
513
+ };
514
+ var BillingAPI = class {
515
+ constructor(client) {
516
+ this.client = client;
517
+ }
518
+ /**
519
+ * Create a checkout session for subscription upgrade.
520
+ *
521
+ * @example
522
+ * ```typescript
523
+ * const { url } = await api.billing.createCheckout({
524
+ * tier: 'pro',
525
+ * successUrl: '/success',
526
+ * cancelUrl: '/pricing',
527
+ * });
528
+ * window.location.href = url;
529
+ * ```
530
+ */
531
+ async createCheckout(params) {
532
+ return this.client.post("/api/create-checkout", params, true);
533
+ }
534
+ /**
535
+ * Open the Stripe customer portal for billing management.
536
+ *
537
+ * @example
538
+ * ```typescript
539
+ * const { url } = await api.billing.openPortal({ returnUrl: '/dashboard' });
540
+ * window.location.href = url;
541
+ * ```
542
+ */
543
+ async openPortal(params) {
544
+ return this.client.post("/api/customer-portal", params, true);
545
+ }
546
+ };
547
+ var ProductAPI = class {
548
+ constructor(client) {
549
+ this.client = client;
550
+ }
551
+ /**
552
+ * List subscription tiers
553
+ */
554
+ async listTiers() {
555
+ return this.client.get("/api/tiers");
556
+ }
557
+ /**
558
+ * List products (for store projects)
559
+ */
560
+ async list() {
561
+ return this.client.get("/api/products");
562
+ }
563
+ /**
564
+ * Create a cart checkout (guest checkout for store)
565
+ */
566
+ async cartCheckout(params) {
567
+ return this.client.post("/api/cart/checkout", params);
568
+ }
569
+ };
570
+ var DashboardAPI = class {
571
+ constructor(client) {
572
+ this.client = client;
573
+ }
574
+ /**
575
+ * Get dashboard metrics
576
+ *
577
+ * @example
578
+ * ```typescript
579
+ * const dashboard = await api.dashboard.get();
580
+ * console.log(`MRR: $${dashboard.mrr}`);
581
+ * console.log(`Active subs: ${dashboard.activeSubscriptions}`);
582
+ * ```
583
+ */
584
+ async get() {
585
+ return this.client.get("/api/dashboard");
586
+ }
587
+ /**
588
+ * Get aggregate totals across all projects
589
+ */
590
+ async getTotals() {
591
+ return this.client.get("/api/dashboard/totals");
592
+ }
593
+ };
594
+ var index_default = DreamAPI;
595
+ // Annotate the CommonJS export names for ESM import in node:
596
+ 0 && (module.exports = {
597
+ DreamAPI,
598
+ DreamAPIException
599
+ });