@withvlibe/base-sdk 1.0.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,702 @@
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
+ VlibeBaseAuth: () => VlibeBaseAuth,
24
+ VlibeBaseDatabase: () => VlibeBaseDatabase,
25
+ VlibeBasePayments: () => VlibeBasePayments
26
+ });
27
+ module.exports = __toCommonJS(index_exports);
28
+
29
+ // src/VlibeBaseDatabase.ts
30
+ var import_supabase_js = require("@supabase/supabase-js");
31
+ var DEFAULT_BASE_URL = "https://vlibe.app";
32
+ var DEFAULT_SUPABASE_URL = "https://qoblysxhxtifxhgdlzgl.supabase.co";
33
+ function resolveBaseUrl(configBaseUrl) {
34
+ if (configBaseUrl) return configBaseUrl;
35
+ if (typeof process !== "undefined" && process.env) {
36
+ if (process.env.VLIBE_BASE_URL) return process.env.VLIBE_BASE_URL;
37
+ if (process.env.NEXT_PUBLIC_VLIBE_BASE_URL) return process.env.NEXT_PUBLIC_VLIBE_BASE_URL;
38
+ }
39
+ return DEFAULT_BASE_URL;
40
+ }
41
+ var VlibeBaseDatabase = class {
42
+ /**
43
+ * Create a new VlibeBaseDatabase instance
44
+ *
45
+ * @param config - Database configuration
46
+ * @throws Error if projectId or databaseToken is missing
47
+ */
48
+ constructor(config) {
49
+ this.supabase = null;
50
+ this.subscriptions = /* @__PURE__ */ new Map();
51
+ if (!config.projectId) {
52
+ throw new Error("VlibeBaseDatabase: projectId is required");
53
+ }
54
+ if (!config.databaseToken) {
55
+ throw new Error("VlibeBaseDatabase: databaseToken is required");
56
+ }
57
+ this.projectId = config.projectId;
58
+ this.databaseToken = config.databaseToken;
59
+ this.baseUrl = resolveBaseUrl(config.baseUrl);
60
+ this.supabaseUrl = config.supabaseUrl || DEFAULT_SUPABASE_URL;
61
+ }
62
+ /**
63
+ * Initialize Supabase client for real-time subscriptions
64
+ */
65
+ initSupabase() {
66
+ if (this.supabase) return;
67
+ this.supabase = (0, import_supabase_js.createClient)(this.supabaseUrl, this.databaseToken, {
68
+ realtime: {
69
+ params: {
70
+ eventsPerSecond: 10
71
+ }
72
+ }
73
+ });
74
+ }
75
+ /**
76
+ * Make an authenticated API request
77
+ */
78
+ async apiRequest(endpoint, options = {}) {
79
+ const url = `${this.baseUrl}/api/database/${this.projectId}${endpoint}`;
80
+ const response = await fetch(url, {
81
+ ...options,
82
+ headers: {
83
+ "Content-Type": "application/json",
84
+ Authorization: `Bearer ${this.databaseToken}`,
85
+ ...options.headers
86
+ }
87
+ });
88
+ const data = await response.json();
89
+ if (!response.ok) {
90
+ throw new Error(data.error || data.message || "API request failed");
91
+ }
92
+ return data;
93
+ }
94
+ // ============================================================================
95
+ // Table Operations
96
+ // ============================================================================
97
+ /**
98
+ * Create a new table
99
+ */
100
+ async createTable(name, schema) {
101
+ const response = await this.apiRequest(
102
+ "/tables",
103
+ {
104
+ method: "POST",
105
+ body: JSON.stringify({ name, schema })
106
+ }
107
+ );
108
+ return response.data;
109
+ }
110
+ /**
111
+ * Get table information
112
+ */
113
+ async getTable(name) {
114
+ try {
115
+ const response = await this.apiRequest(
116
+ `/tables/${name}`
117
+ );
118
+ return response.data;
119
+ } catch {
120
+ return null;
121
+ }
122
+ }
123
+ /**
124
+ * List all tables
125
+ */
126
+ async listTables() {
127
+ const response = await this.apiRequest(
128
+ "/tables"
129
+ );
130
+ return response.data;
131
+ }
132
+ /**
133
+ * Delete a table
134
+ */
135
+ async deleteTable(name) {
136
+ await this.apiRequest(`/tables/${name}`, { method: "DELETE" });
137
+ return true;
138
+ }
139
+ // ============================================================================
140
+ // CRUD Operations
141
+ // ============================================================================
142
+ /**
143
+ * Insert a document into a collection
144
+ */
145
+ async insert(collection, data) {
146
+ const response = await this.apiRequest(
147
+ `/collections/${collection}`,
148
+ {
149
+ method: "POST",
150
+ body: JSON.stringify(data)
151
+ }
152
+ );
153
+ return response.data;
154
+ }
155
+ /**
156
+ * Query documents from a collection
157
+ */
158
+ async query(collection, options = {}) {
159
+ const params = new URLSearchParams();
160
+ if (options.limit) params.set("limit", String(options.limit));
161
+ if (options.offset) params.set("offset", String(options.offset));
162
+ if (options.orderBy) params.set("orderBy", options.orderBy);
163
+ if (options.orderDirection) params.set("orderDirection", options.orderDirection);
164
+ if (options.where) params.set("where", JSON.stringify(options.where));
165
+ const queryString = params.toString();
166
+ const endpoint = `/collections/${collection}${queryString ? `?${queryString}` : ""}`;
167
+ const response = await this.apiRequest(endpoint);
168
+ return response.data;
169
+ }
170
+ /**
171
+ * Get a single document by ID
172
+ */
173
+ async get(collection, id) {
174
+ try {
175
+ const response = await this.apiRequest(
176
+ `/collections/${collection}/${id}`
177
+ );
178
+ return response.data;
179
+ } catch {
180
+ return null;
181
+ }
182
+ }
183
+ /**
184
+ * Update a document
185
+ */
186
+ async update(collection, id, data) {
187
+ const response = await this.apiRequest(
188
+ `/collections/${collection}/${id}`,
189
+ {
190
+ method: "PATCH",
191
+ body: JSON.stringify(data)
192
+ }
193
+ );
194
+ return response.data;
195
+ }
196
+ /**
197
+ * Delete a document
198
+ */
199
+ async delete(collection, id) {
200
+ await this.apiRequest(`/collections/${collection}/${id}`, {
201
+ method: "DELETE"
202
+ });
203
+ return true;
204
+ }
205
+ /**
206
+ * Count documents in a collection
207
+ */
208
+ async count(collection, where) {
209
+ const params = new URLSearchParams();
210
+ if (where) params.set("where", JSON.stringify(where));
211
+ const queryString = params.toString();
212
+ const endpoint = `/collections/${collection}/count${queryString ? `?${queryString}` : ""}`;
213
+ const response = await this.apiRequest(
214
+ endpoint
215
+ );
216
+ return response.data.count;
217
+ }
218
+ // ============================================================================
219
+ // Key-Value Store
220
+ // ============================================================================
221
+ /**
222
+ * Set a key-value pair
223
+ */
224
+ async setKV(key, value) {
225
+ await this.apiRequest("/kv", {
226
+ method: "POST",
227
+ body: JSON.stringify({ key, value })
228
+ });
229
+ }
230
+ /**
231
+ * Get a value by key
232
+ */
233
+ async getKV(key) {
234
+ try {
235
+ const response = await this.apiRequest(
236
+ `/kv/${key}`
237
+ );
238
+ return response.data.value;
239
+ } catch {
240
+ return null;
241
+ }
242
+ }
243
+ /**
244
+ * Delete a key-value pair
245
+ */
246
+ async deleteKV(key) {
247
+ await this.apiRequest(`/kv/${key}`, { method: "DELETE" });
248
+ return true;
249
+ }
250
+ // ============================================================================
251
+ // Real-time Subscriptions
252
+ // ============================================================================
253
+ /**
254
+ * Subscribe to real-time changes on a collection
255
+ */
256
+ subscribe(collection, callback) {
257
+ this.initSupabase();
258
+ const channelName = `base:${this.projectId}:${collection}`;
259
+ const tableName = `project_${this.projectId.replace(/-/g, "_")}_${collection}`;
260
+ const channel = this.supabase.channel(channelName).on(
261
+ "postgres_changes",
262
+ {
263
+ event: "*",
264
+ schema: "public",
265
+ table: tableName
266
+ },
267
+ (payload) => {
268
+ callback({
269
+ eventType: payload.eventType,
270
+ new: payload.new,
271
+ old: payload.old,
272
+ table: collection
273
+ });
274
+ }
275
+ ).subscribe();
276
+ this.subscriptions.set(channelName, channel);
277
+ return {
278
+ unsubscribe: () => {
279
+ channel.unsubscribe();
280
+ this.subscriptions.delete(channelName);
281
+ }
282
+ };
283
+ }
284
+ /**
285
+ * Unsubscribe from all subscriptions
286
+ */
287
+ unsubscribeAll() {
288
+ for (const channel of this.subscriptions.values()) {
289
+ channel.unsubscribe();
290
+ }
291
+ this.subscriptions.clear();
292
+ }
293
+ // ============================================================================
294
+ // Utilities
295
+ // ============================================================================
296
+ /**
297
+ * Get the project ID
298
+ */
299
+ getProjectId() {
300
+ return this.projectId;
301
+ }
302
+ /**
303
+ * Get the base URL
304
+ */
305
+ getBaseUrl() {
306
+ return this.baseUrl;
307
+ }
308
+ };
309
+
310
+ // src/VlibeBaseAuth.ts
311
+ var DEFAULT_BASE_URL2 = "https://vlibe.app";
312
+ function resolveBaseUrl2(configBaseUrl) {
313
+ if (configBaseUrl) return configBaseUrl;
314
+ if (typeof process !== "undefined" && process.env) {
315
+ if (process.env.VLIBE_BASE_URL) return process.env.VLIBE_BASE_URL;
316
+ if (process.env.NEXT_PUBLIC_VLIBE_BASE_URL) return process.env.NEXT_PUBLIC_VLIBE_BASE_URL;
317
+ }
318
+ return DEFAULT_BASE_URL2;
319
+ }
320
+ var VlibeBaseAuth = class {
321
+ /**
322
+ * Create a new VlibeBaseAuth instance
323
+ *
324
+ * @param config - Authentication configuration
325
+ * @throws Error if appId or appSecret is missing
326
+ */
327
+ constructor(config) {
328
+ if (!config.appId) {
329
+ throw new Error("VlibeBaseAuth: appId is required");
330
+ }
331
+ if (!config.appSecret) {
332
+ throw new Error("VlibeBaseAuth: appSecret is required");
333
+ }
334
+ this.appId = config.appId;
335
+ this.appSecret = config.appSecret;
336
+ this.baseUrl = resolveBaseUrl2(config.baseUrl);
337
+ }
338
+ /**
339
+ * Verify a session token and get user information
340
+ *
341
+ * @param token - The session token from the SSO callback
342
+ * @returns The user object if valid, null otherwise
343
+ */
344
+ async verifySession(token) {
345
+ if (!token) {
346
+ return null;
347
+ }
348
+ try {
349
+ const response = await fetch(`${this.baseUrl}/api/auth/sso/verify`, {
350
+ method: "POST",
351
+ headers: {
352
+ "Content-Type": "application/json"
353
+ },
354
+ body: JSON.stringify({
355
+ token,
356
+ appId: this.appId,
357
+ appSecret: this.appSecret,
358
+ appType: "base"
359
+ // Indicate this is a Base app
360
+ })
361
+ });
362
+ if (!response.ok) {
363
+ return null;
364
+ }
365
+ const data = await response.json();
366
+ if (data.valid && data.user) {
367
+ return data.user;
368
+ }
369
+ return null;
370
+ } catch (error) {
371
+ console.error("VlibeBaseAuth: Failed to verify session:", error);
372
+ return null;
373
+ }
374
+ }
375
+ /**
376
+ * Generate the SSO login URL to redirect unauthenticated users
377
+ *
378
+ * @param redirectPath - The path to redirect to after login
379
+ * @returns The full Vlibe SSO URL
380
+ */
381
+ getLoginUrl(redirectPath = "/") {
382
+ const params = new URLSearchParams({
383
+ app_id: this.appId,
384
+ app_type: "base",
385
+ redirect: redirectPath
386
+ });
387
+ return `${this.baseUrl}/api/auth/sso?${params.toString()}`;
388
+ }
389
+ /**
390
+ * Generate the logout URL
391
+ *
392
+ * @param redirectPath - The path to redirect to after logout
393
+ * @returns The logout URL
394
+ */
395
+ getLogoutUrl(redirectPath = "/") {
396
+ const params = new URLSearchParams({
397
+ app_id: this.appId,
398
+ redirect: redirectPath
399
+ });
400
+ return `${this.baseUrl}/api/auth/sso/logout?${params.toString()}`;
401
+ }
402
+ /**
403
+ * Check if user has access to a specific feature
404
+ *
405
+ * @param user - The Vlibe user object
406
+ * @param feature - The feature name to check
407
+ * @returns True if user has access to the feature
408
+ */
409
+ hasFeature(user, feature) {
410
+ if (!user) return false;
411
+ if (user.subscriptionType === "platform") {
412
+ return true;
413
+ }
414
+ if (user.appAccess?.features) {
415
+ return user.appAccess.features.includes("*") || user.appAccess.features.includes(feature);
416
+ }
417
+ return false;
418
+ }
419
+ /**
420
+ * Check if user has an active subscription
421
+ *
422
+ * @param user - The Vlibe user object
423
+ * @returns True if user has any active subscription
424
+ */
425
+ hasSubscription(user) {
426
+ return user?.subscriptionType !== null;
427
+ }
428
+ /**
429
+ * Get the subscription tier for a user
430
+ *
431
+ * @param user - The Vlibe user object
432
+ * @returns The tier name or null
433
+ */
434
+ getTier(user) {
435
+ if (!user) return null;
436
+ if (user.subscriptionType === "platform") return "platform";
437
+ return user.appAccess?.tier || null;
438
+ }
439
+ /**
440
+ * Get the app ID
441
+ */
442
+ getAppId() {
443
+ return this.appId;
444
+ }
445
+ /**
446
+ * Get the base URL
447
+ */
448
+ getBaseUrl() {
449
+ return this.baseUrl;
450
+ }
451
+ };
452
+
453
+ // src/VlibeBasePayments.ts
454
+ var DEFAULT_BASE_URL3 = "https://vlibe.app";
455
+ function resolveBaseUrl3(configBaseUrl) {
456
+ if (configBaseUrl) return configBaseUrl;
457
+ if (typeof process !== "undefined" && process.env) {
458
+ if (process.env.VLIBE_BASE_URL) return process.env.VLIBE_BASE_URL;
459
+ if (process.env.NEXT_PUBLIC_VLIBE_BASE_URL) return process.env.NEXT_PUBLIC_VLIBE_BASE_URL;
460
+ }
461
+ return DEFAULT_BASE_URL3;
462
+ }
463
+ var VlibeBasePayments = class {
464
+ /**
465
+ * Create a new VlibeBasePayments instance
466
+ *
467
+ * @param config - Payments configuration
468
+ * @throws Error if appId or appSecret is missing
469
+ *
470
+ * @remarks
471
+ * This class should only be used server-side. Never expose your
472
+ * appSecret to the client.
473
+ */
474
+ constructor(config) {
475
+ if (!config.appId) {
476
+ throw new Error("VlibeBasePayments: appId is required");
477
+ }
478
+ if (!config.appSecret) {
479
+ throw new Error("VlibeBasePayments: appSecret is required");
480
+ }
481
+ if (typeof window !== "undefined") {
482
+ console.warn(
483
+ "VlibeBasePayments: This class should only be used server-side. Never expose your appSecret to the client."
484
+ );
485
+ }
486
+ this.appId = config.appId;
487
+ this.appSecret = config.appSecret;
488
+ this.baseUrl = resolveBaseUrl3(config.baseUrl);
489
+ }
490
+ /**
491
+ * Make an authenticated API request
492
+ */
493
+ async apiRequest(endpoint, options = {}) {
494
+ const url = `${this.baseUrl}/api/base/payments${endpoint}`;
495
+ const response = await fetch(url, {
496
+ ...options,
497
+ headers: {
498
+ "Content-Type": "application/json",
499
+ "X-App-Id": this.appId,
500
+ "X-App-Secret": this.appSecret,
501
+ ...options.headers
502
+ }
503
+ });
504
+ const data = await response.json();
505
+ if (!response.ok) {
506
+ throw new Error(data.error || data.message || "Payment API request failed");
507
+ }
508
+ return data;
509
+ }
510
+ // ============================================================================
511
+ // Stripe Connect
512
+ // ============================================================================
513
+ /**
514
+ * Get Stripe Connect onboarding URL
515
+ *
516
+ * Redirect users to this URL to connect their Stripe account.
517
+ *
518
+ * @param returnUrl - URL to return to after onboarding
519
+ * @returns The Stripe Connect onboarding URL
520
+ */
521
+ async getConnectOnboardingUrl(returnUrl) {
522
+ const response = await this.apiRequest(
523
+ "/connect/onboard",
524
+ {
525
+ method: "POST",
526
+ body: JSON.stringify({ returnUrl })
527
+ }
528
+ );
529
+ return response.data.url;
530
+ }
531
+ /**
532
+ * Check Stripe Connect status
533
+ *
534
+ * @returns The current Stripe Connect status
535
+ */
536
+ async getConnectStatus() {
537
+ const response = await this.apiRequest(
538
+ "/connect/status"
539
+ );
540
+ return response.data;
541
+ }
542
+ // ============================================================================
543
+ // Checkout
544
+ // ============================================================================
545
+ /**
546
+ * Create a checkout session for one-time payments
547
+ *
548
+ * @param options - Checkout options
549
+ * @returns The checkout session with URL to redirect user
550
+ *
551
+ * @remarks
552
+ * Transaction fees are automatically calculated based on your plan:
553
+ * - Free plan: 2% of transaction
554
+ * - Premium plan: 0.5% of transaction
555
+ */
556
+ async createCheckout(options) {
557
+ const response = await this.apiRequest(
558
+ "/checkout",
559
+ {
560
+ method: "POST",
561
+ body: JSON.stringify({
562
+ amount: options.amount,
563
+ currency: options.currency || "usd",
564
+ userId: options.userId,
565
+ userEmail: options.userEmail,
566
+ description: options.description,
567
+ metadata: options.metadata,
568
+ successUrl: options.successUrl,
569
+ cancelUrl: options.cancelUrl
570
+ })
571
+ }
572
+ );
573
+ return response.data;
574
+ }
575
+ /**
576
+ * Get checkout session by ID
577
+ *
578
+ * @param sessionId - The checkout session ID
579
+ * @returns The checkout session details
580
+ */
581
+ async getCheckoutSession(sessionId) {
582
+ try {
583
+ const response = await this.apiRequest(
584
+ `/checkout/${sessionId}`
585
+ );
586
+ return response.data;
587
+ } catch {
588
+ return null;
589
+ }
590
+ }
591
+ // ============================================================================
592
+ // Transactions
593
+ // ============================================================================
594
+ /**
595
+ * Get all transactions
596
+ *
597
+ * @param options - Query options
598
+ * @returns List of transactions
599
+ */
600
+ async getTransactions(options = {}) {
601
+ const params = new URLSearchParams();
602
+ if (options.limit) params.set("limit", String(options.limit));
603
+ if (options.offset) params.set("offset", String(options.offset));
604
+ if (options.status) params.set("status", options.status);
605
+ const queryString = params.toString();
606
+ const endpoint = `/transactions${queryString ? `?${queryString}` : ""}`;
607
+ const response = await this.apiRequest(
608
+ endpoint
609
+ );
610
+ return response.data;
611
+ }
612
+ /**
613
+ * Get a single transaction
614
+ *
615
+ * @param transactionId - The transaction ID
616
+ * @returns The transaction details
617
+ */
618
+ async getTransaction(transactionId) {
619
+ try {
620
+ const response = await this.apiRequest(
621
+ `/transactions/${transactionId}`
622
+ );
623
+ return response.data;
624
+ } catch {
625
+ return null;
626
+ }
627
+ }
628
+ /**
629
+ * Get transaction summary/stats
630
+ *
631
+ * @returns Transaction statistics
632
+ */
633
+ async getTransactionStats() {
634
+ const response = await this.apiRequest("/transactions/stats");
635
+ return response.data;
636
+ }
637
+ // ============================================================================
638
+ // Refunds
639
+ // ============================================================================
640
+ /**
641
+ * Create a refund
642
+ *
643
+ * @param options - Refund options
644
+ * @returns The updated transaction
645
+ *
646
+ * @remarks
647
+ * Note: Transaction fees are not refunded when you issue a refund.
648
+ */
649
+ async createRefund(options) {
650
+ const response = await this.apiRequest(
651
+ "/refunds",
652
+ {
653
+ method: "POST",
654
+ body: JSON.stringify(options)
655
+ }
656
+ );
657
+ return response.data;
658
+ }
659
+ // ============================================================================
660
+ // Utilities
661
+ // ============================================================================
662
+ /**
663
+ * Calculate the Vlibe fee for an amount
664
+ *
665
+ * @param amount - Amount in cents
666
+ * @param plan - The Base plan ('free' or 'premium')
667
+ * @returns The fee amount in cents
668
+ */
669
+ calculateFee(amount, plan = "free") {
670
+ const feeRate = plan === "premium" ? 5e-3 : 0.02;
671
+ return Math.round(amount * feeRate);
672
+ }
673
+ /**
674
+ * Calculate net amount after fees
675
+ *
676
+ * @param amount - Gross amount in cents
677
+ * @param plan - The Base plan ('free' or 'premium')
678
+ * @returns The net amount in cents
679
+ */
680
+ calculateNetAmount(amount, plan = "free") {
681
+ const fee = this.calculateFee(amount, plan);
682
+ return amount - fee;
683
+ }
684
+ /**
685
+ * Get the app ID
686
+ */
687
+ getAppId() {
688
+ return this.appId;
689
+ }
690
+ /**
691
+ * Get the base URL
692
+ */
693
+ getBaseUrl() {
694
+ return this.baseUrl;
695
+ }
696
+ };
697
+ // Annotate the CommonJS export names for ESM import in node:
698
+ 0 && (module.exports = {
699
+ VlibeBaseAuth,
700
+ VlibeBaseDatabase,
701
+ VlibeBasePayments
702
+ });