@omnibase/core-js 0.5.0 → 0.5.1

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.cjs CHANGED
@@ -3,6 +3,10 @@ var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
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
+ };
6
10
  var __copyProps = (to, from, except, desc) => {
7
11
  if (from && typeof from === "object" || typeof from === "function") {
8
12
  for (let key of __getOwnPropNames(from))
@@ -15,4 +19,1259 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
15
19
 
16
20
  // src/index.ts
17
21
  var index_exports = {};
22
+ __export(index_exports, {
23
+ OmnibaseClient: () => OmnibaseClient
24
+ });
18
25
  module.exports = __toCommonJS(index_exports);
26
+
27
+ // src/payments/checkout.ts
28
+ var CheckoutManager = class {
29
+ /**
30
+ * Initialize the checkout manager
31
+ *
32
+ * @param paymentHandler - Payment handler instance for API communication
33
+ *
34
+ * @group Checkout
35
+ */
36
+ constructor(omnibaseClient) {
37
+ this.omnibaseClient = omnibaseClient;
38
+ }
39
+ /**
40
+ * Create a new Stripe checkout session
41
+ *
42
+ * Creates a checkout session with the specified options and returns
43
+ * the session URL for redirecting the user to complete payment.
44
+ * The session will be configured for either one-time payment or
45
+ * subscription based on the mode parameter.
46
+ *
47
+ * @param options - Configuration options for the checkout session
48
+ * @param options.price_id - Stripe price ID for the product/service
49
+ * @param options.mode - Payment mode ('payment' for one-time, 'subscription' for recurring)
50
+ * @param options.success_url - URL to redirect after successful payment
51
+ * @param options.cancel_url - URL to redirect if user cancels
52
+ * @param options.customer_id - Optional existing Stripe customer ID
53
+ *
54
+ * @returns Promise resolving to checkout session response with URL and session ID
55
+ *
56
+ * @throws {Error} When the API request fails due to network issues
57
+ * @throws {Error} When the server returns an error response (invalid price_id, etc.)
58
+ * @throws {ValidationError} When required parameters are missing or invalid
59
+ *
60
+ * @example
61
+ * One-time payment checkout:
62
+ * ```typescript
63
+ * const session = await checkoutManager.createSession({
64
+ * price_id: 'price_one_time_product',
65
+ * mode: 'payment',
66
+ * success_url: 'https://app.com/success',
67
+ * cancel_url: 'https://app.com/cancel'
68
+ * });
69
+ *
70
+ * // Redirect to Stripe checkout
71
+ * window.location.href = session.data.url;
72
+ * ```
73
+ *
74
+ * @example
75
+ * Subscription checkout with existing customer:
76
+ * ```typescript
77
+ * const session = await checkoutManager.createSession({
78
+ * price_id: 'price_monthly_plan',
79
+ * mode: 'subscription',
80
+ * success_url: 'https://app.com/dashboard?welcome=true',
81
+ * cancel_url: 'https://app.com/pricing',
82
+ * customer_id: 'cus_12345'
83
+ * });
84
+ *
85
+ * console.log(`Session created: ${session.data.sessionId}`);
86
+ * ```
87
+ *
88
+ * @since 1.0.0
89
+ * @group Checkout
90
+ */
91
+ async createSession(options) {
92
+ const response = await this.omnibaseClient.fetch(
93
+ "/api/v1/payments/checkout",
94
+ {
95
+ method: "POST",
96
+ headers: {
97
+ "Content-Type": "application/json"
98
+ },
99
+ body: JSON.stringify(options)
100
+ }
101
+ );
102
+ if (!response.ok) {
103
+ const errorData = await response.text();
104
+ throw new Error(
105
+ `Failed to create checkout session: ${response.status} - ${errorData}`
106
+ );
107
+ }
108
+ const result = await response.json();
109
+ return result;
110
+ }
111
+ };
112
+
113
+ // src/payments/config.ts
114
+ var ConfigManager = class {
115
+ constructor(omnibaseClient) {
116
+ this.omnibaseClient = omnibaseClient;
117
+ }
118
+ /**
119
+ * Get the current Stripe configuration from the database
120
+ *
121
+ * Retrieves the latest Stripe configuration including products, prices,
122
+ * and UI customization data. This configuration represents the current
123
+ * active pricing structure with all UI elements for pricing table rendering.
124
+ *
125
+ * @returns Promise resolving to the current Stripe configuration
126
+ *
127
+ * @throws {Error} When the API request fails due to network issues
128
+ * @throws {Error} When the server returns an error response (4xx, 5xx status codes)
129
+ *
130
+ * @example
131
+ * Basic usage:
132
+ * ```typescript
133
+ * const config = await getStripeConfig();
134
+ * console.log(`Found ${config.data.config.products.length} products`);
135
+ *
136
+ * // Access product UI configuration
137
+ * config.data.config.products.forEach(product => {
138
+ * console.log(`${product.name}: ${product.ui?.tagline || 'No tagline'}`);
139
+ * });
140
+ * ```
141
+ */
142
+ async getStripeConfig() {
143
+ try {
144
+ const response = await this.omnibaseClient.fetch(
145
+ `/api/v1/stripe/config`,
146
+ {
147
+ method: "GET",
148
+ headers: {
149
+ "Content-Type": "application/json"
150
+ },
151
+ credentials: "include"
152
+ }
153
+ );
154
+ if (!response.ok) {
155
+ const errorData = await response.text();
156
+ throw new Error(
157
+ `Failed to get Stripe config: ${response.status} - ${errorData}`
158
+ );
159
+ }
160
+ const data = await response.json();
161
+ return data;
162
+ } catch (error) {
163
+ console.error("Error getting Stripe config:", error);
164
+ throw error;
165
+ }
166
+ }
167
+ /**
168
+ * Get available products with UI-ready pricing data
169
+ *
170
+ * Transforms the raw Stripe configuration into UI-ready format for pricing
171
+ * table rendering. Includes formatted pricing, features, limits, and all
172
+ * display customizations needed for marketing pages.
173
+ *
174
+ * @returns Promise resolving to products ready for UI consumption
175
+ *
176
+ * @throws {Error} When the API request fails or configuration is invalid
177
+ *
178
+ * @example
179
+ * Pricing table rendering:
180
+ * ```typescript
181
+ * const products = await getAvailableProducts();
182
+ *
183
+ * products.forEach(product => {
184
+ * const display = product.pricing_display;
185
+ * console.log(`${display.name} - ${display.tagline}`);
186
+ *
187
+ * display.prices.forEach(price => {
188
+ * console.log(` ${price.display_name}: ${price.formatted_price}`);
189
+ * });
190
+ * });
191
+ * ```
192
+ */
193
+ async getAvailableProducts() {
194
+ const configResponse = await this.getStripeConfig();
195
+ if (!configResponse.data?.config) {
196
+ throw new Error("No Stripe configuration found");
197
+ }
198
+ const products = configResponse.data.config.products;
199
+ return products.map(transformProductToUIReady).sort(
200
+ (a, b) => a.pricing_display.sort_order - b.pricing_display.sort_order
201
+ );
202
+ }
203
+ /**
204
+ * Get a specific product by ID
205
+ *
206
+ * Retrieves a single product configuration by its ID from the current
207
+ * Stripe configuration. Useful for product-specific operations.
208
+ *
209
+ * @param productId - The configuration product ID to retrieve
210
+ * @returns Promise resolving to the product or null if not found
211
+ *
212
+ * @example
213
+ * ```typescript
214
+ * const product = await getProduct('starter_plan');
215
+ * if (product) {
216
+ * console.log(`Found product: ${product.name}`);
217
+ * }
218
+ * ```
219
+ */
220
+ async getProduct(productId) {
221
+ const configResponse = await this.getStripeConfig();
222
+ if (!configResponse.data?.config) {
223
+ return null;
224
+ }
225
+ const product = configResponse.data.config.products.find(
226
+ (p) => p.id === productId
227
+ );
228
+ return product || null;
229
+ }
230
+ };
231
+ function transformProductToUIReady(product) {
232
+ const ui = product.ui || {};
233
+ return {
234
+ ...product,
235
+ pricing_display: {
236
+ name: ui.display_name || product.name,
237
+ tagline: ui.tagline,
238
+ features: ui.features || [],
239
+ badge: ui.badge,
240
+ cta_text: ui.cta_text || "Choose Plan",
241
+ highlighted: ui.highlighted || false,
242
+ sort_order: ui.sort_order || 0,
243
+ prices: product.prices.map((price) => {
244
+ const priceUI = price.ui || {};
245
+ return {
246
+ id: price.id,
247
+ display_name: priceUI.display_name || formatDefaultPriceName(price),
248
+ formatted_price: formatPrice(price, priceUI),
249
+ billing_period: priceUI.billing_period || formatDefaultBillingPeriod(price),
250
+ features: priceUI.features || [],
251
+ limits: priceUI.limits || []
252
+ };
253
+ })
254
+ }
255
+ };
256
+ }
257
+ function formatPrice(price, priceUI) {
258
+ if (priceUI.price_display?.custom_text) {
259
+ return priceUI.price_display.custom_text;
260
+ }
261
+ if (!price.amount || price.amount === 0) {
262
+ return "Free";
263
+ }
264
+ const amount = price.amount / 100;
265
+ const currency = price.currency.toUpperCase();
266
+ let formattedPrice = "";
267
+ if (priceUI.price_display?.show_currency !== false) {
268
+ const currencySymbol = getCurrencySymbol(currency);
269
+ formattedPrice = `${currencySymbol}${amount.toFixed(2)}`;
270
+ } else {
271
+ formattedPrice = amount.toFixed(2);
272
+ }
273
+ if (priceUI.price_display?.suffix) {
274
+ formattedPrice += ` ${priceUI.price_display.suffix}`;
275
+ }
276
+ return formattedPrice;
277
+ }
278
+ function getCurrencySymbol(currency) {
279
+ const symbols = {
280
+ USD: "$",
281
+ EUR: "\u20AC",
282
+ GBP: "\xA3",
283
+ JPY: "\xA5",
284
+ CAD: "C$",
285
+ AUD: "A$"
286
+ };
287
+ return symbols[currency] || currency;
288
+ }
289
+ function formatDefaultPriceName(price) {
290
+ if (price.interval) {
291
+ return price.interval.charAt(0).toUpperCase() + price.interval.slice(1);
292
+ }
293
+ return "One-time";
294
+ }
295
+ function formatDefaultBillingPeriod(price) {
296
+ if (price.interval) {
297
+ const count = price.interval_count || 1;
298
+ const period = count === 1 ? price.interval : `${count} ${price.interval}s`;
299
+ return `per ${period}`;
300
+ }
301
+ return "one-time";
302
+ }
303
+
304
+ // src/payments/portal.ts
305
+ var PortalManager = class {
306
+ /**
307
+ * Initialize the portal manager
308
+ *
309
+ * @param paymentHandler - Payment handler instance for API communication
310
+ *
311
+ * @group Portal
312
+ */
313
+ constructor(omnibaseClient) {
314
+ this.omnibaseClient = omnibaseClient;
315
+ }
316
+ /**
317
+ * Create a new customer portal session
318
+ *
319
+ * Creates a portal session that allows the specified customer to
320
+ * manage their billing information, subscriptions, and payment methods.
321
+ * Returns a URL that the customer should be redirected to.
322
+ *
323
+ * The portal session is temporary and expires after a short period
324
+ * for security. Each access requires creating a new session.
325
+ *
326
+ * @param options - Configuration options for the portal session
327
+ * @param options.customer_id - Stripe customer ID for the user
328
+ * @param options.return_url - URL to redirect to when exiting the portal
329
+ *
330
+ * @returns Promise resolving to portal session response with access URL
331
+ *
332
+ * @throws {Error} When the API request fails due to network issues
333
+ * @throws {Error} When the server returns an error response (invalid customer_id, etc.)
334
+ * @throws {ValidationError} When required parameters are missing or invalid
335
+ *
336
+ * @example
337
+ * Basic portal creation:
338
+ * ```typescript
339
+ * const portal = await portalManager.create({
340
+ * customer_id: 'cus_abc123',
341
+ * return_url: 'https://myapp.com/account/billing'
342
+ * });
343
+ *
344
+ * // Redirect user to portal
345
+ * window.location.href = portal.data.url;
346
+ * ```
347
+ *
348
+ * @example
349
+ * With error handling:
350
+ * ```typescript
351
+ * try {
352
+ * const portal = await portalManager.create({
353
+ * customer_id: currentUser.stripeCustomerId,
354
+ * return_url: window.location.origin + '/billing'
355
+ * });
356
+ *
357
+ * window.location.href = portal.data.url;
358
+ * } catch (error) {
359
+ * console.error('Failed to create portal session:', error);
360
+ * showErrorMessage('Unable to access billing portal. Please try again.');
361
+ * }
362
+ * ```
363
+ *
364
+ * @since 1.0.0
365
+ * @group Portal
366
+ */
367
+ async create(options) {
368
+ const response = await this.omnibaseClient.fetch(
369
+ "/api/v1/payments/portal",
370
+ {
371
+ method: "POST",
372
+ headers: {
373
+ "Content-Type": "application/json"
374
+ },
375
+ body: JSON.stringify(options)
376
+ }
377
+ );
378
+ if (!response.ok) {
379
+ const errorData = await response.text();
380
+ throw new Error(
381
+ `Failed to create customer portal: ${response.status} - ${errorData}`
382
+ );
383
+ }
384
+ const result = await response.json();
385
+ return result;
386
+ }
387
+ };
388
+
389
+ // src/payments/usage.ts
390
+ var UsageManager = class {
391
+ /**
392
+ * Initialize the usage manager
393
+ *
394
+ * @param paymentHandler - Payment handler instance for API communication
395
+ *
396
+ * @group Usage
397
+ */
398
+ constructor(omnibaseClient) {
399
+ this.omnibaseClient = omnibaseClient;
400
+ }
401
+ /**
402
+ * Record a usage event for metered billing
403
+ *
404
+ * Records a usage event against a specific meter for billing calculation.
405
+ * The event will be aggregated with other usage events for the billing period
406
+ * to determine the customer's charges for metered products.
407
+ *
408
+ * Usage events should be recorded in real-time or as close to real-time as
409
+ * possible to ensure accurate billing and provide up-to-date usage visibility
410
+ * to customers.
411
+ *
412
+ * @param options - Usage recording options
413
+ * @param options.meter_event_name - Name of the meter to record against
414
+ * @param options.customer_id - Stripe customer ID
415
+ * @param options.value - Usage quantity as string
416
+ *
417
+ * @returns Promise resolving to API response confirmation
418
+ *
419
+ * @throws {Error} When the API request fails due to network issues
420
+ * @throws {Error} When the server returns an error response (invalid meter name, customer, etc.)
421
+ * @throws {ValidationError} When required parameters are missing or invalid
422
+ *
423
+ * @example
424
+ * API call tracking:
425
+ * ```typescript
426
+ * // Record each API call
427
+ * await usageManager.recordUsage({
428
+ * meter_event_name: 'api_requests',
429
+ * customer_id: user.stripeCustomerId,
430
+ * value: '1'
431
+ * });
432
+ * ```
433
+ *
434
+ * @example
435
+ * Batch usage recording:
436
+ * ```typescript
437
+ * // Record multiple operations at once
438
+ * const usageEvents = [
439
+ * { meter_event_name: 'compute_hours', customer_id: 'cus_123', value: '0.5' },
440
+ * { meter_event_name: 'storage_gb', customer_id: 'cus_123', value: '10' },
441
+ * { meter_event_name: 'api_calls', customer_id: 'cus_123', value: '50' }
442
+ * ];
443
+ *
444
+ * for (const event of usageEvents) {
445
+ * await usageManager.recordUsage(event);
446
+ * }
447
+ * ```
448
+ *
449
+ * @example
450
+ * With error handling:
451
+ * ```typescript
452
+ * try {
453
+ * await usageManager.recordUsage({
454
+ * meter_event_name: 'file_uploads',
455
+ * customer_id: currentUser.stripeCustomerId,
456
+ * value: String(uploadedFiles.length)
457
+ * });
458
+ * } catch (error) {
459
+ * console.error('Failed to record usage:', error);
460
+ * // Usage recording failure shouldn't block user operations
461
+ * // but should be logged for billing accuracy
462
+ * }
463
+ * ```
464
+ *
465
+ * @since 1.0.0
466
+ * @group Usage
467
+ */
468
+ async recordUsage(options) {
469
+ const response = await this.omnibaseClient.fetch("/api/v1/payments/usage", {
470
+ method: "POST",
471
+ headers: {
472
+ "Content-Type": "application/json"
473
+ },
474
+ body: JSON.stringify(options)
475
+ });
476
+ if (!response.ok) {
477
+ const errorData = await response.text();
478
+ throw new Error(
479
+ `Failed to record usage: ${response.status} - ${errorData}`
480
+ );
481
+ }
482
+ const result = await response.json();
483
+ return result;
484
+ }
485
+ };
486
+
487
+ // src/payments/handler.ts
488
+ var PaymentHandler = class {
489
+ /**
490
+ * Initialize the payment handler with API configuration
491
+ *
492
+ * Creates a new payment handler instance that will communicate with
493
+ * the specified API endpoint. The handler automatically handles
494
+ * request formatting and authentication headers.
495
+ *
496
+ * @param apiUrl - Base URL for the payment API endpoint
497
+ *
498
+ * @example
499
+ * ```typescript
500
+ * const paymentHandler = new PaymentHandler('https://api.myapp.com');
501
+ * ```
502
+ *
503
+ * @since 1.0.0
504
+ * @group Client
505
+ */
506
+ constructor(omnibaseClient) {
507
+ this.omnibaseClient = omnibaseClient;
508
+ this.checkout = new CheckoutManager(this.omnibaseClient);
509
+ this.config = new ConfigManager(this.omnibaseClient);
510
+ this.portal = new PortalManager(this.omnibaseClient);
511
+ this.usage = new UsageManager(this.omnibaseClient);
512
+ }
513
+ /**
514
+ * Checkout session management
515
+ *
516
+ * Provides functionality for creating and managing Stripe checkout sessions
517
+ * for both one-time payments and subscription billing.
518
+ *
519
+ * @example
520
+ * ```typescript
521
+ * const session = await paymentHandler.checkout.createSession({
522
+ * price_id: 'price_monthly',
523
+ * mode: 'subscription',
524
+ * success_url: window.location.origin + '/success',
525
+ * cancel_url: window.location.origin + '/pricing'
526
+ * });
527
+ * ```
528
+ */
529
+ checkout;
530
+ /**
531
+ * Stripe configuration management
532
+ *
533
+ * Handles retrieval and processing of database-backed Stripe configurations,
534
+ * providing UI-ready product and pricing data for rendering pricing tables.
535
+ *
536
+ * @example
537
+ * ```typescript
538
+ * const products = await paymentHandler.config.getAvailableProducts();
539
+ * const config = await paymentHandler.config.getStripeConfig();
540
+ * ```
541
+ */
542
+ config;
543
+ /**
544
+ * Customer portal management
545
+ *
546
+ * Creates customer portal sessions for subscription management,
547
+ * billing history, and payment method updates.
548
+ *
549
+ * @example
550
+ * ```typescript
551
+ * const portal = await paymentHandler.portal.create({
552
+ * customer_id: 'cus_123',
553
+ * return_url: 'https://app.com/billing'
554
+ * });
555
+ * ```
556
+ */
557
+ portal;
558
+ /**
559
+ * Usage tracking and metered billing
560
+ *
561
+ * Records usage events for metered billing products and manages
562
+ * usage-based pricing calculations.
563
+ *
564
+ * @example
565
+ * ```typescript
566
+ * await paymentHandler.usage.recordUsage({
567
+ * meter_event_name: 'api_calls',
568
+ * customer_id: 'cus_123',
569
+ * value: '1'
570
+ * });
571
+ * ```
572
+ */
573
+ usage;
574
+ };
575
+
576
+ // src/permissions/handler.ts
577
+ var import_client = require("@ory/client");
578
+ var PermissionsClient = class {
579
+ /**
580
+ * Ory Keto RelationshipApi for managing subject-object relationships
581
+ *
582
+ * Provides methods for creating, updating, and deleting relationships between
583
+ * subjects (users, groups) and objects (tenants, resources). This API handles
584
+ * write operations and is used to establish permission structures.
585
+ *
586
+ * Key methods:
587
+ * - `createRelationship()` - Creates a new relationship tuple
588
+ * - `deleteRelationships()` - Removes existing relationship tuples
589
+ * - `getRelationships()` - Queries existing relationships
590
+ * - `patchRelationships()` - Updates multiple relationships atomically
591
+ *
592
+ * @example
593
+ * ```typescript
594
+ * // Create a relationship
595
+ * await client.relationships.createRelationship(
596
+ * undefined,
597
+ * {
598
+ * namespace: 'Tenant',
599
+ * object: 'tenant_123',
600
+ * relation: 'members',
601
+ * subjectId: 'user_456'
602
+ * }
603
+ * );
604
+ * ```
605
+ *
606
+ * @since 1.0.0
607
+ * @group Relationships
608
+ */
609
+ relationships;
610
+ /**
611
+ * Ory Keto PermissionApi for checking permissions
612
+ *
613
+ * Provides methods for querying whether a subject has a specific permission
614
+ * on an object. This API handles read operations and is optimized for fast
615
+ * permission checks in your application logic.
616
+ *
617
+ * Key methods:
618
+ * - `checkPermission()` - Checks if a subject has permission on an object
619
+ * - `checkPermissionOrError()` - Same as above but throws error if denied
620
+ * - `expandPermissions()` - Expands relationships to show all granted permissions
621
+ *
622
+ * @example
623
+ * ```typescript
624
+ * // Check permission
625
+ * const result = await client.permissions.checkPermission(
626
+ * undefined,
627
+ * {
628
+ * namespace: 'Tenant',
629
+ * object: 'tenant_123',
630
+ * relation: 'view',
631
+ * subjectId: 'user_456'
632
+ * }
633
+ * );
634
+ *
635
+ * console.log('Has permission:', result.data.allowed);
636
+ * ```
637
+ *
638
+ * @since 1.0.0
639
+ * @group Permissions
640
+ */
641
+ permissions;
642
+ /**
643
+ * Creates a new PermissionsClient instance
644
+ *
645
+ * Initializes the client with separate endpoints for read and write operations.
646
+ * The client automatically appends the appropriate Keto API paths to the base URL
647
+ * for optimal performance and security separation.
648
+ *
649
+ * @param apiBaseUrl - The base URL for your Omnibase API instance
650
+ *
651
+ * @throws {Error} When the base URL is invalid or cannot be reached
652
+ *
653
+ * @example
654
+ * ```typescript
655
+ * const client = new PermissionsClient('https://api.example.com');
656
+ * ```
657
+ *
658
+ * @example
659
+ * Local development:
660
+ * ```typescript
661
+ * const client = new PermissionsClient('http://localhost:8080');
662
+ * ```
663
+ *
664
+ * @since 1.0.0
665
+ * @group Client
666
+ */
667
+ constructor(apiBaseUrl) {
668
+ this.relationships = new import_client.RelationshipApi(
669
+ void 0,
670
+ `${apiBaseUrl}/api/v1/permissions/write`
671
+ );
672
+ this.permissions = new import_client.PermissionApi(
673
+ void 0,
674
+ `${apiBaseUrl}/api/v1/permissions/read`
675
+ );
676
+ }
677
+ };
678
+
679
+ // src/tenants/invites.ts
680
+ var TenantInviteManager = class {
681
+ /**
682
+ * Creates a new TenantInviteManager instance
683
+ *
684
+ * Initializes the manager with the provided Omnibase client for making
685
+ * authenticated API requests to tenant invitation endpoints.
686
+ *
687
+ * @param omnibaseClient - Configured Omnibase client instance
688
+ *
689
+ * @group Tenant Invitations
690
+ */
691
+ constructor(omnibaseClient) {
692
+ this.omnibaseClient = omnibaseClient;
693
+ }
694
+ /**
695
+ * Accepts a tenant invitation using a secure token
696
+ *
697
+ * Processes a tenant invitation by validating the provided token and
698
+ * adding the authenticated user to the specified tenant. The invitation
699
+ * token is consumed during this process and cannot be used again.
700
+ *
701
+ * The function performs several validations:
702
+ * - Verifies the token exists and is valid
703
+ * - Checks that the invitation hasn't expired
704
+ * - Ensures the invitation hasn't already been used
705
+ * - Confirms the user is authenticated via session cookies
706
+ *
707
+ * Upon successful acceptance, the user is granted access to the tenant
708
+ * with the role specified in the original invitation. The invitation
709
+ * record is marked as used and cannot be accepted again.
710
+ *
711
+ * @param token - The secure invitation token from the email invitation
712
+ *
713
+ * @returns Promise resolving to the tenant ID and success confirmation
714
+ *
715
+ * @throws {Error} When the token parameter is missing or empty
716
+ * @throws {Error} When the invitation token is invalid or expired
717
+ * @throws {Error} When the invitation has already been accepted
718
+ * @throws {Error} When the user is not authenticated
719
+ * @throws {Error} When the API request fails due to network issues
720
+ * @throws {Error} When the server returns an error response (4xx, 5xx status codes)
721
+ *
722
+ * @example
723
+ * Basic invitation acceptance:
724
+ * ```typescript
725
+ * const result = await acceptTenantInvite('inv_secure_token_abc123');
726
+ *
727
+ * console.log(`Successfully joined tenant: ${result.data.tenant_id}`);
728
+ * // User can now access tenant resources
729
+ * await switchActiveTenant(result.data.tenant_id);
730
+ * ```
731
+ *
732
+ * @example
733
+ * Handling the invitation flow:
734
+ * ```typescript
735
+ * // Typically called from an invitation link like:
736
+ * // https://app.com/accept-invite?token=inv_secure_token_abc123
737
+ *
738
+ * const urlParams = new URLSearchParams(window.location.search);
739
+ * const inviteToken = urlParams.get('token');
740
+ *
741
+ * if (inviteToken) {
742
+ * try {
743
+ * const result = await acceptTenantInvite(inviteToken);
744
+ *
745
+ * // Success - redirect to tenant dashboard
746
+ * window.location.href = `/dashboard?tenant=${result.data.tenant_id}`;
747
+ * } catch (error) {
748
+ * console.error('Failed to accept invitation:', error.message);
749
+ * // Show error to user
750
+ * }
751
+ * }
752
+ * ```
753
+ *
754
+ *
755
+ * @since 1.0.0
756
+ * @public
757
+ * @group User Management
758
+ */
759
+ async accept(token) {
760
+ if (!token) {
761
+ throw new Error("Invite token is required");
762
+ }
763
+ const requestBody = {
764
+ token
765
+ };
766
+ try {
767
+ const response = await this.omnibaseClient.fetch(
768
+ `/api/v1/tenants/invites/accept`,
769
+ {
770
+ method: "PUT",
771
+ headers: {
772
+ "Content-Type": "application/json"
773
+ },
774
+ body: JSON.stringify(requestBody),
775
+ credentials: "include"
776
+ }
777
+ );
778
+ if (!response.ok) {
779
+ const errorData = await response.text();
780
+ throw new Error(
781
+ `Failed to accept invite: ${response.status} - ${errorData}`
782
+ );
783
+ }
784
+ const data = await response.json();
785
+ return data;
786
+ } catch (error) {
787
+ console.error("Error accepting tenant invite:", error);
788
+ throw error;
789
+ }
790
+ }
791
+ /**
792
+ * Creates a new user invitation for a specific tenant
793
+ *
794
+ * Generates a secure invitation that allows a user to join the specified
795
+ * tenant with the defined role. The invitation is sent to the provided
796
+ * email address and includes a time-limited token for security.
797
+ *
798
+ * The function creates the invitation record in the database and can
799
+ * trigger email notifications (depending on server configuration).
800
+ * The invitation expires after a predefined time period and can only
801
+ * be used once.
802
+ *
803
+ * Only existing tenant members with appropriate permissions can create
804
+ * invitations. The inviter's authentication is validated via HTTP-only
805
+ * cookies sent with the request.
806
+ *
807
+ * @param tenantId - Unique identifier of the tenant to invite the user to
808
+ * @param inviteData - Configuration object for the invitation
809
+ * @param inviteData.email - Email address of the user to invite
810
+ * @param inviteData.role - Role the user will have after joining (e.g., 'member', 'admin')
811
+ *
812
+ * @returns Promise resolving to the created invitation with secure token
813
+ *
814
+ * @throws {Error} When tenantId parameter is missing or empty
815
+ * @throws {Error} When required fields (email, role) are missing or empty
816
+ * @throws {Error} When the API request fails due to network issues
817
+ * @throws {Error} When the server returns an error response (4xx, 5xx status codes)
818
+ *
819
+ * @example
820
+ * Basic invitation creation:
821
+ * ```typescript
822
+ * const invite = await createTenantUserInvite('tenant_123', {
823
+ * email: 'colleague@company.com',
824
+ * role: 'member'
825
+ * });
826
+ *
827
+ * console.log(`Invite sent to: ${invite.data.invite.email}`);
828
+ * // The invite token can be used to generate invitation links
829
+ * const inviteLink = `https://app.com/accept-invite?token=${invite.data.invite.token}`;
830
+ * ```
831
+ *
832
+ * @example
833
+ * Creating admin invitation:
834
+ * ```typescript
835
+ * const adminInvite = await createTenantUserInvite('tenant_456', {
836
+ * email: 'admin@company.com',
837
+ * role: 'admin'
838
+ * });
839
+ *
840
+ * // Admin users get elevated permissions
841
+ * console.log(`Admin invite created with ID: ${adminInvite.data.invite.id}`);
842
+ * ```
843
+ *
844
+ *
845
+ * @since 1.0.0
846
+ * @public
847
+ * @group User Management
848
+ */
849
+ async create(tenantId, inviteData) {
850
+ if (!tenantId) {
851
+ throw new Error("Tenant ID is required");
852
+ }
853
+ if (!inviteData.email || !inviteData.role) {
854
+ throw new Error("Email and role are required");
855
+ }
856
+ try {
857
+ const response = await this.omnibaseClient.fetch(
858
+ `/api/v1/tenants/${tenantId}/invites`,
859
+ {
860
+ method: "POST",
861
+ headers: {
862
+ "Content-Type": "application/json"
863
+ },
864
+ body: JSON.stringify(inviteData),
865
+ credentials: "include"
866
+ }
867
+ );
868
+ if (!response.ok) {
869
+ const errorData = await response.text();
870
+ throw new Error(
871
+ `Failed to create invite: ${response.status} - ${errorData}`
872
+ );
873
+ }
874
+ const data = await response.json();
875
+ return data;
876
+ } catch (error) {
877
+ console.error("Error creating tenant user invite:", error);
878
+ throw error;
879
+ }
880
+ }
881
+ };
882
+
883
+ // src/tenants/tenants.ts
884
+ var TenantManger = class {
885
+ /**
886
+ * Creates a new TenantManger instance
887
+ *
888
+ * Initializes the manager with the provided Omnibase client for making
889
+ * authenticated API requests to tenant management endpoints.
890
+ *
891
+ * @param omnibaseClient - Configured Omnibase client instance
892
+ *
893
+ * @group Tenant Management
894
+ */
895
+ constructor(omnibaseClient) {
896
+ this.omnibaseClient = omnibaseClient;
897
+ }
898
+ /**
899
+ * Creates a new tenant in the multi-tenant system
900
+ *
901
+ * Establishes a new tenant with integrated Stripe billing setup and assigns
902
+ * the specified user as the tenant owner. The operation creates the necessary
903
+ * database records and returns a JWT token that enables Row-Level Security
904
+ * access to the tenant's isolated data.
905
+ *
906
+ * The function automatically handles Stripe customer creation for billing
907
+ * integration and sets up the initial tenant configuration. The returned
908
+ * token should be stored securely for subsequent API calls.
909
+ *
910
+ * @param tenantData - Configuration object for the new tenant
911
+ * @param tenantData.name - Display name for the tenant organization
912
+ * @param tenantData.billing_email - Email address for Stripe billing notifications
913
+ * @param tenantData.user_id - Unique identifier of the user who will own this tenant
914
+ *
915
+ * @returns Promise resolving to the created tenant with authentication token
916
+ *
917
+ * @throws {Error} When required fields (name, user_id) are missing or empty
918
+ * @throws {Error} When the API request fails due to network issues
919
+ * @throws {Error} When the server returns an error response (4xx, 5xx status codes)
920
+ *
921
+ * @example
922
+ * Basic tenant creation:
923
+ * ```typescript
924
+ * const newTenant = await createTenant({
925
+ * name: 'Acme Corporation',
926
+ * billing_email: 'billing@acme.com',
927
+ * user_id: 'user_123'
928
+ * });
929
+ *
930
+ * console.log(`Created tenant: ${newTenant.data.tenant.name}`);
931
+ * // Store the token for authenticated requests
932
+ * localStorage.setItem('tenant_token', newTenant.data.token);
933
+ * ```
934
+ *
935
+ *
936
+ * @since 1.0.0
937
+ * @public
938
+ * @group Tenant Management
939
+ */
940
+ async createTenant(tenantData) {
941
+ if (!tenantData.name || !tenantData.user_id) {
942
+ throw new Error("Name and user_id are required");
943
+ }
944
+ try {
945
+ const response = await this.omnibaseClient.fetch(`/api/v1/tenants`, {
946
+ method: "POST",
947
+ headers: {
948
+ "Content-Type": "application/json"
949
+ },
950
+ body: JSON.stringify(tenantData),
951
+ credentials: "include"
952
+ });
953
+ if (!response.ok) {
954
+ const errorData = await response.text();
955
+ throw new Error(
956
+ `Failed to create tenant: ${response.status} - ${errorData}`
957
+ );
958
+ }
959
+ const data = await response.json();
960
+ return data;
961
+ } catch (error) {
962
+ console.error("Error creating tenant:", error);
963
+ throw error;
964
+ }
965
+ }
966
+ /**
967
+ * Permanently deletes a tenant and all associated data
968
+ *
969
+ * ⚠️ **WARNING: This operation is irreversible and will permanently delete:**
970
+ * - The tenant record and all metadata
971
+ * - All user memberships and invitations for this tenant
972
+ * - All tenant-specific data protected by row-level security
973
+ * - Any tenant-related billing information
974
+ * - All tenant configuration and settings
975
+ *
976
+ * **Access Control:**
977
+ * Only tenant owners can delete a tenant. This operation requires:
978
+ * - User must be authenticated
979
+ * - User must have 'owner' role for the specified tenant
980
+ * - Tenant must exist and be accessible to the user
981
+ *
982
+ * **Security Considerations:**
983
+ * - All tenant data is immediately and permanently removed
984
+ * - Other tenant members lose access immediately
985
+ * - Any active sessions for this tenant are invalidated
986
+ * - Billing subscriptions are cancelled (if applicable)
987
+ * - Audit logs for deletion are maintained for compliance
988
+ *
989
+ * @param tenantId - The unique identifier of the tenant to delete
990
+ *
991
+ * @returns Promise resolving to a confirmation message
992
+ *
993
+ * @throws {Error} When the tenantId parameter is missing or empty
994
+ * @throws {Error} When the user is not authenticated
995
+ * @throws {Error} When the user is not an owner of the specified tenant
996
+ * @throws {Error} When the tenant doesn't exist or is not accessible
997
+ * @throws {Error} When the API request fails due to network issues
998
+ * @throws {Error} When the server returns an error response (4xx, 5xx status codes)
999
+ *
1000
+ * @example
1001
+ * Basic tenant deletion with confirmation:
1002
+ * ```typescript
1003
+ * const tenantToDelete = 'tenant_abc123';
1004
+ *
1005
+ * // Always confirm before deleting
1006
+ * const userConfirmed = confirm(
1007
+ * 'Are you sure you want to delete this tenant? This action cannot be undone.'
1008
+ * );
1009
+ *
1010
+ * if (userConfirmed) {
1011
+ * try {
1012
+ * const result = await deleteTenant(tenantToDelete);
1013
+ * console.log(result.data.message); // "Tenant deleted successfully"
1014
+ *
1015
+ * // Redirect user away from deleted tenant
1016
+ * window.location.href = '/dashboard';
1017
+ * } catch (error) {
1018
+ * console.error('Failed to delete tenant:', error);
1019
+ * }
1020
+ * }
1021
+ * ```
1022
+ *
1023
+ * @since 1.0.0
1024
+ * @public
1025
+ * @group Tenant Management
1026
+ */
1027
+ async deleteTenant(tenantId) {
1028
+ if (!tenantId) {
1029
+ throw new Error("Tenant ID is required");
1030
+ }
1031
+ try {
1032
+ const response = await this.omnibaseClient.fetch(
1033
+ `/api/v1/tenants/${tenantId}`,
1034
+ {
1035
+ method: "DELETE",
1036
+ headers: {
1037
+ "Content-Type": "application/json"
1038
+ },
1039
+ credentials: "include"
1040
+ }
1041
+ );
1042
+ if (!response.ok) {
1043
+ const errorData = await response.text();
1044
+ throw new Error(
1045
+ `Failed to delete tenant: ${response.status} - ${errorData}`
1046
+ );
1047
+ }
1048
+ const data = await response.json();
1049
+ return data;
1050
+ } catch (error) {
1051
+ console.error("Error deleting tenant:", error);
1052
+ throw error;
1053
+ }
1054
+ }
1055
+ /**
1056
+ * Switches the user's active tenant context
1057
+ *
1058
+ * Changes the user's active tenant to the specified tenant ID, updating
1059
+ * their authentication context and permissions. This function is essential
1060
+ * for multi-tenant applications where users belong to multiple tenants
1061
+ * and need to switch between them.
1062
+ *
1063
+ * The function performs several operations:
1064
+ * - Validates that the user has access to the specified tenant
1065
+ * - Updates the user's active tenant in their session
1066
+ * - Generates a new JWT token with updated tenant claims
1067
+ * - Updates any cached tenant-specific data
1068
+ *
1069
+ * After switching tenants, all subsequent API calls will be made within
1070
+ * the context of the new active tenant, with row-level security policies
1071
+ * applied accordingly. The new JWT token should be used for all future
1072
+ * authenticated requests.
1073
+ *
1074
+ * @param tenantId - The ID of the tenant to switch to (must be a tenant the user belongs to)
1075
+ *
1076
+ * @returns Promise resolving to a new JWT token and success confirmation
1077
+ *
1078
+ * @throws {Error} When the tenantId parameter is missing or empty
1079
+ * @throws {Error} When the user doesn't have access to the specified tenant
1080
+ * @throws {Error} When the user is not authenticated
1081
+ * @throws {Error} When the specified tenant doesn't exist
1082
+ * @throws {Error} When the API request fails due to network issues
1083
+ * @throws {Error} When the server returns an error response (4xx, 5xx status codes)
1084
+ *
1085
+ * @example
1086
+ * Basic tenant switching:
1087
+ * ```typescript
1088
+ * const result = await switchActiveTenant('tenant_xyz789');
1089
+ *
1090
+ * // Now all API calls will be in the context of tenant_xyz789
1091
+ * const tenantData = await getCurrentTenantData();
1092
+ * ```
1093
+ *
1094
+ * @example
1095
+ * Using with tenant-aware data fetching:
1096
+ * ```typescript
1097
+ * // Switch tenant and immediately fetch tenant-specific data
1098
+ * const switchAndLoadTenant = async (tenantId: string) => {
1099
+ * try {
1100
+ * // Switch to new tenant context
1101
+ * const switchResult = await switchActiveTenant(tenantId);
1102
+ *
1103
+ * // Update authentication token
1104
+ * setAuthToken(switchResult.data.token);
1105
+ *
1106
+ * // Fetch data in new tenant context
1107
+ * const [tenantInfo, userPermissions, tenantSettings] = await Promise.all([
1108
+ * getTenantInfo(),
1109
+ * getUserPermissions(),
1110
+ * getTenantSettings()
1111
+ * ]);
1112
+ *
1113
+ * return {
1114
+ * tenant: tenantInfo,
1115
+ * permissions: userPermissions,
1116
+ * settings: tenantSettings
1117
+ * };
1118
+ * } catch (error) {
1119
+ * console.error('Failed to switch tenant and load data:', error);
1120
+ * throw error;
1121
+ * }
1122
+ * };
1123
+ * ```
1124
+ *
1125
+ * @since 1.0.0
1126
+ * @public
1127
+ * @group Tenant Management
1128
+ */
1129
+ async switchActiveTenant(tenantId) {
1130
+ if (!tenantId) {
1131
+ throw new Error("Tenant ID is required");
1132
+ }
1133
+ const requestBody = {
1134
+ tenant_id: tenantId
1135
+ };
1136
+ try {
1137
+ const response = await this.omnibaseClient.fetch(
1138
+ `/api/v1/tenants/switch-active`,
1139
+ {
1140
+ method: "PUT",
1141
+ headers: {
1142
+ "Content-Type": "application/json"
1143
+ },
1144
+ body: JSON.stringify(requestBody),
1145
+ credentials: "include"
1146
+ }
1147
+ );
1148
+ if (!response.ok) {
1149
+ const errorData = await response.text();
1150
+ throw new Error(
1151
+ `Failed to switch tenant: ${response.status} - ${errorData}`
1152
+ );
1153
+ }
1154
+ const data = await response.json();
1155
+ return data;
1156
+ } catch (error) {
1157
+ console.error("Error switching active tenant:", error);
1158
+ throw error;
1159
+ }
1160
+ }
1161
+ };
1162
+
1163
+ // src/tenants/handler.ts
1164
+ var TenantHandler = class {
1165
+ /**
1166
+ * Creates a new TenantHandler instance
1167
+ *
1168
+ * Initializes the handler with the provided Omnibase client and sets up
1169
+ * the specialized manager instances for tenant and invitation operations.
1170
+ * The client is used for all underlying HTTP requests and authentication.
1171
+ *
1172
+ * @param omnibaseClient - Configured Omnibase client instance
1173
+ *
1174
+ * @example
1175
+ * ```typescript
1176
+ * const client = new OmnibaseClient({
1177
+ * apiKey: 'your-api-key',
1178
+ * baseURL: 'https://api.yourapp.com'
1179
+ * });
1180
+ * const tenantHandler = new TenantHandler(client);
1181
+ * ```
1182
+ *
1183
+ * @group Tenant Management
1184
+ */
1185
+ constructor(omnibaseClient) {
1186
+ this.omnibaseClient = omnibaseClient;
1187
+ this.invites = new TenantInviteManager(this.omnibaseClient);
1188
+ this.tenants = new TenantManger(this.omnibaseClient);
1189
+ }
1190
+ /**
1191
+ * Core tenant management operations
1192
+ *
1193
+ * Provides access to tenant lifecycle operations including creation,
1194
+ * deletion, and active tenant switching. All operations respect user
1195
+ * permissions and tenant ownership rules.
1196
+ *
1197
+ * @example
1198
+ * ```typescript
1199
+ * // Create a new tenant
1200
+ * const tenant = await tenantHandler.tenants.createTenant({
1201
+ * name: 'New Company',
1202
+ * billing_email: 'billing@newcompany.com',
1203
+ * user_id: 'user_456'
1204
+ * });
1205
+ *
1206
+ * // Switch to the tenant
1207
+ * await tenantHandler.tenants.switchActiveTenant(tenant.data.tenant.id);
1208
+ *
1209
+ * // Delete the tenant (owner only)
1210
+ * await tenantHandler.tenants.deleteTenant(tenant.data.tenant.id);
1211
+ * ```
1212
+ */
1213
+ tenants;
1214
+ /**
1215
+ * Tenant invitation management operations
1216
+ *
1217
+ * Provides access to user invitation functionality including creating
1218
+ * invitations for new users and accepting existing invitations.
1219
+ * Supports role-based access control and secure token-based workflows.
1220
+ *
1221
+ * @example
1222
+ * ```typescript
1223
+ * // Create an invitation
1224
+ * const invite = await tenantHandler.invites.create('tenant_123', {
1225
+ * email: 'newuser@company.com',
1226
+ * role: 'admin'
1227
+ * });
1228
+ *
1229
+ * // Accept an invitation (from the invited user's session)
1230
+ * const result = await tenantHandler.invites.accept('invite_token_xyz');
1231
+ * ```
1232
+ */
1233
+ invites;
1234
+ };
1235
+
1236
+ // src/client.ts
1237
+ var OmnibaseClient = class {
1238
+ constructor(config) {
1239
+ this.config = config;
1240
+ this.permissions = new PermissionsClient(this.config.api_url);
1241
+ }
1242
+ /**
1243
+ * Main payment handler for all payment-related operations
1244
+ *
1245
+ * This class serves as the central coordinator for all payment functionality,
1246
+ * providing access to checkout sessions, billing configuration, customer portals,
1247
+ * and usage tracking. It handles the low-level HTTP communication with the
1248
+ * payment API and delegates specific operations to specialized managers.
1249
+ *
1250
+ * The handler automatically manages authentication, request formatting, and
1251
+ * provides a consistent interface across all payment operations.
1252
+ *
1253
+ * @example
1254
+ * ```typescript
1255
+ * // Create a checkout session
1256
+ * const checkout = await omnibase.payments.checkout.createSession({
1257
+ * price_id: 'price_123',
1258
+ * mode: 'subscription',
1259
+ * success_url: 'https://app.com/success',
1260
+ * cancel_url: 'https://app.com/cancel'
1261
+ * });
1262
+ *
1263
+ * // Get available products
1264
+ * const products = await omnibase.payments.config.getAvailableProducts();
1265
+ * ```
1266
+ */
1267
+ payments = new PaymentHandler(this);
1268
+ tenants = new TenantHandler(this);
1269
+ permissions;
1270
+ async fetch(endpoint, options = {}) {
1271
+ return await fetch(this.config.api_url + endpoint, options);
1272
+ }
1273
+ };
1274
+ // Annotate the CommonJS export names for ESM import in node:
1275
+ 0 && (module.exports = {
1276
+ OmnibaseClient
1277
+ });