@montra/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/README.md ADDED
@@ -0,0 +1,96 @@
1
+ # @montra/sdk
2
+
3
+ The official Montra SDK for Node.js, React, Next.js, and Express.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @montra/sdk
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Server-side (Node.js / Next.js Server Actions)
14
+
15
+ The `Montra` class is designed for server-side environments.
16
+
17
+ ```typescript
18
+ import { Montra } from '@montra/sdk';
19
+
20
+ const montra = new Montra({
21
+ apiKey: process.env.MONTRA_API_KEY
22
+ });
23
+
24
+ // Use in Server Actions or API routes
25
+ export async function getInvoices() {
26
+ return await montra.listInvoices();
27
+ }
28
+ ```
29
+
30
+ ### Express Middleware
31
+
32
+ ```typescript
33
+ import express from 'express';
34
+ import { montraMiddleware } from '@montra/sdk';
35
+
36
+ const app = express();
37
+
38
+ app.use(montraMiddleware({
39
+ apiKey: 'your_api_key'
40
+ }));
41
+
42
+ app.get('/billing', async (req, res) => {
43
+ // Access the client via req.montra
44
+ const invoices = await req.montra.listInvoices();
45
+ res.json(invoices);
46
+ });
47
+ ```
48
+
49
+ ### React / Next.js Client Side
50
+
51
+ #### Setup Provider
52
+
53
+ ```tsx
54
+ // For Next.js App Router, add 'use client' if this is in a layout
55
+ import { MontraProvider } from '@montra/sdk';
56
+
57
+ function App({ children }) {
58
+ return (
59
+ <MontraProvider publishableKey="your_pk">
60
+ {children}
61
+ </MontraProvider>
62
+ );
63
+ }
64
+ ```
65
+
66
+ #### Use Hook or Component
67
+
68
+ ```tsx
69
+ import { useMontra, PaymentElement } from '@montra/sdk';
70
+
71
+ function Checkout() {
72
+ const montra = useMontra();
73
+
74
+ const handleLegacyMount = async () => {
75
+ const checkout = await montra.initializeCheckout('session_123');
76
+ checkout.mount('#container');
77
+ };
78
+
79
+ return (
80
+ <div>
81
+ <PaymentElement sessionId="session_123" />
82
+ </div>
83
+ );
84
+ }
85
+ ```
86
+
87
+ ## Features
88
+
89
+ - **Next.js Support**: Includes `'use client'` directives for App Router compatibility.
90
+ - **Express Integration**: Built-in middleware for easy access to the SDK in your routes.
91
+ - **React Hooks**: First-class support for React with `MontraProvider` and `useMontra`.
92
+ - **Unified Package**: One SDK for both client-side checkout and server-side billing logic.
93
+
94
+ ## License
95
+
96
+ MIT
@@ -0,0 +1,26 @@
1
+ import { MontraOptions, Customer, UsagePayload, EntitlementCheck, Invoice, Feature } from './types';
2
+ export declare class Montra {
3
+ private apiKey;
4
+ private baseUrl;
5
+ constructor(options: MontraOptions);
6
+ private request;
7
+ createCustomer(data: {
8
+ name: string;
9
+ email: string;
10
+ }): Promise<Customer>;
11
+ listCustomers(): Promise<Customer[]>;
12
+ reportUsage(payload: UsagePayload): Promise<boolean>;
13
+ checkEntitlement(customerId: string, meterSlug: string): Promise<EntitlementCheck>;
14
+ listInvoices(): Promise<Invoice[]>;
15
+ getInvoice(id: string): Promise<Invoice>;
16
+ listFeatures(): Promise<Feature[]>;
17
+ createFeature(data: {
18
+ name: string;
19
+ slug: string;
20
+ description?: string;
21
+ pricing_model_id: string;
22
+ type?: string;
23
+ status?: string;
24
+ }): Promise<Feature>;
25
+ }
26
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAEb,QAAQ,EACR,YAAY,EACZ,gBAAgB,EAChB,OAAO,EACP,OAAO,EACR,MAAM,SAAS,CAAC;AAGjB,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,EAAE,aAAa;YAKpB,OAAO;IAuBf,cAAc,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,QAAQ,CAAC;IAQxE,aAAa,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAMpC,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC;IASpD,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAQlF,YAAY,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAKlC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMxC,YAAY,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAKlC,aAAa,CAAC,IAAI,EAAE;QACxB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,gBAAgB,EAAE,MAAM,CAAC;QACzB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC,OAAO,CAAC;CAOrB"}
package/dist/client.js ADDED
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Montra = void 0;
4
+ const constants_1 = require("./constants");
5
+ class Montra {
6
+ constructor(options) {
7
+ this.apiKey = options.apiKey;
8
+ this.baseUrl = options.baseUrl || constants_1.DEFAULT_BASE_URL;
9
+ }
10
+ async request(path, options = {}) {
11
+ const url = `${this.baseUrl}${path}`;
12
+ const headers = {
13
+ 'Authorization': `Bearer ${this.apiKey}`,
14
+ 'Content-Type': 'application/json',
15
+ ...options.headers,
16
+ };
17
+ const response = await fetch(url, {
18
+ ...options,
19
+ headers,
20
+ });
21
+ const body = await response.json();
22
+ if (!response.ok) {
23
+ throw new Error(body.error?.message || `Request failed with status ${response.status}`);
24
+ }
25
+ return body;
26
+ }
27
+ // Customers
28
+ async createCustomer(data) {
29
+ const res = await this.request('/customers', {
30
+ method: 'POST',
31
+ body: JSON.stringify(data),
32
+ });
33
+ return res.data;
34
+ }
35
+ async listCustomers() {
36
+ const res = await this.request('/customers');
37
+ return res.data;
38
+ }
39
+ // Usage
40
+ async reportUsage(payload) {
41
+ const res = await this.request('/usage', {
42
+ method: 'POST',
43
+ body: JSON.stringify(payload),
44
+ });
45
+ return res.success;
46
+ }
47
+ // Entitlements
48
+ async checkEntitlement(customerId, meterSlug) {
49
+ const res = await this.request(`/entitlements?customer_id=${customerId}&meter=${meterSlug}`);
50
+ return res.data;
51
+ }
52
+ // Invoices
53
+ async listInvoices() {
54
+ const res = await this.request('/invoices');
55
+ return res.data;
56
+ }
57
+ async getInvoice(id) {
58
+ const res = await this.request(`/invoices/${id}`);
59
+ return res.data;
60
+ }
61
+ // Features
62
+ async listFeatures() {
63
+ const res = await this.request('/features');
64
+ return res.data;
65
+ }
66
+ async createFeature(data) {
67
+ const res = await this.request('/features', {
68
+ method: 'POST',
69
+ body: JSON.stringify(data),
70
+ });
71
+ return res.data;
72
+ }
73
+ }
74
+ exports.Montra = Montra;
75
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.d.ts","sourceRoot":"","sources":["../src/client.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const client_1 = require("./client");
5
+ (0, vitest_1.describe)('Montra SDK', () => {
6
+ const apiKey = 'sk_test_123';
7
+ const client = new client_1.Montra({ apiKey });
8
+ (0, vitest_1.beforeEach)(() => {
9
+ vitest_1.vi.stubGlobal('fetch', vitest_1.vi.fn());
10
+ });
11
+ (0, vitest_1.it)('should instantiate correctly', () => {
12
+ (0, vitest_1.expect)(client).toBeDefined();
13
+ });
14
+ (0, vitest_1.describe)('Customers', () => {
15
+ (0, vitest_1.it)('should create a customer', async () => {
16
+ const mockCustomer = { id: 'cust_1', name: 'Test', email: 'test@test.com' };
17
+ vitest_1.vi.mocked(fetch).mockResolvedValue({
18
+ ok: true,
19
+ json: async () => ({ success: true, data: mockCustomer }),
20
+ });
21
+ const result = await client.createCustomer({ name: 'Test', email: 'test@test.com' });
22
+ (0, vitest_1.expect)(result).toEqual(mockCustomer);
23
+ (0, vitest_1.expect)(fetch).toHaveBeenCalledWith(vitest_1.expect.stringContaining('/customers'), vitest_1.expect.objectContaining({
24
+ method: 'POST',
25
+ headers: vitest_1.expect.objectContaining({
26
+ 'Authorization': `Bearer ${apiKey}`,
27
+ }),
28
+ }));
29
+ });
30
+ (0, vitest_1.it)('should list customers', async () => {
31
+ const mockCustomers = [{ id: 'cust_1', name: 'Test', email: 'test@test.com' }];
32
+ vitest_1.vi.mocked(fetch).mockResolvedValue({
33
+ ok: true,
34
+ json: async () => ({ success: true, data: mockCustomers }),
35
+ });
36
+ const result = await client.listCustomers();
37
+ (0, vitest_1.expect)(result).toEqual(mockCustomers);
38
+ (0, vitest_1.expect)(fetch).toHaveBeenCalledWith(vitest_1.expect.stringContaining('/customers'), vitest_1.expect.any(Object));
39
+ });
40
+ });
41
+ (0, vitest_1.describe)('Usage', () => {
42
+ (0, vitest_1.it)('should report usage', async () => {
43
+ vitest_1.vi.mocked(fetch).mockResolvedValue({
44
+ ok: true,
45
+ json: async () => ({ success: true }),
46
+ });
47
+ const result = await client.reportUsage({
48
+ customer_id: 'cust_1',
49
+ meter_slug: 'tokens',
50
+ amount: 100
51
+ });
52
+ (0, vitest_1.expect)(result).toBe(true);
53
+ });
54
+ });
55
+ (0, vitest_1.describe)('Entitlements', () => {
56
+ (0, vitest_1.it)('should check entitlement', async () => {
57
+ const mockCheck = { has_access: true, usage: 10, limit: 100 };
58
+ vitest_1.vi.mocked(fetch).mockResolvedValue({
59
+ ok: true,
60
+ json: async () => ({ success: true, data: mockCheck }),
61
+ });
62
+ const result = await client.checkEntitlement('cust_1', 'tokens');
63
+ (0, vitest_1.expect)(result).toEqual(mockCheck);
64
+ });
65
+ });
66
+ (0, vitest_1.describe)('Invoices', () => {
67
+ (0, vitest_1.it)('should list invoices', async () => {
68
+ const mockInvoices = [{ id: 'inv_1', amount: 1000 }];
69
+ vitest_1.vi.mocked(fetch).mockResolvedValue({
70
+ ok: true,
71
+ json: async () => ({ success: true, data: mockInvoices }),
72
+ });
73
+ const result = await client.listInvoices();
74
+ (0, vitest_1.expect)(result).toEqual(mockInvoices);
75
+ (0, vitest_1.expect)(fetch).toHaveBeenCalledWith(vitest_1.expect.stringContaining('/invoices'), vitest_1.expect.any(Object));
76
+ });
77
+ (0, vitest_1.it)('should get an invoice', async () => {
78
+ const mockInvoice = { id: 'inv_1', amount: 1000 };
79
+ vitest_1.vi.mocked(fetch).mockResolvedValue({
80
+ ok: true,
81
+ json: async () => ({ success: true, data: mockInvoice }),
82
+ });
83
+ const result = await client.getInvoice('inv_1');
84
+ (0, vitest_1.expect)(result).toEqual(mockInvoice);
85
+ (0, vitest_1.expect)(fetch).toHaveBeenCalledWith(vitest_1.expect.stringContaining('/invoices/inv_1'), vitest_1.expect.any(Object));
86
+ });
87
+ });
88
+ });
89
+ //# sourceMappingURL=client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.js","sourceRoot":"","sources":["../src/client.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare const DEFAULT_BASE_URL = "https://api.montra.fi/v1";
2
+ export declare const DEFAULT_CHECKOUT_URL = "https://checkout.montra.fi";
3
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,6BAA6B,CAAC;AAC3D,eAAO,MAAM,oBAAoB,+BAA+B,CAAC"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_CHECKOUT_URL = exports.DEFAULT_BASE_URL = void 0;
4
+ exports.DEFAULT_BASE_URL = 'https://api.montra.fi/v1';
5
+ exports.DEFAULT_CHECKOUT_URL = 'https://checkout.montra.fi';
6
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,gBAAgB,GAAG,0BAA0B,CAAC;AAC9C,QAAA,oBAAoB,GAAG,4BAA4B,CAAC"}
@@ -0,0 +1,128 @@
1
+ import React from 'react';
2
+ import { Request, Response, NextFunction } from 'express';
3
+
4
+ interface MontraOptions {
5
+ apiKey: string;
6
+ baseUrl?: string;
7
+ }
8
+ interface ApiResponse<T = any> {
9
+ success: boolean;
10
+ data?: T;
11
+ error?: {
12
+ code: string;
13
+ message: string;
14
+ details?: any;
15
+ };
16
+ }
17
+ interface Customer {
18
+ id: string;
19
+ name: string;
20
+ email: string;
21
+ status: string;
22
+ created_at: string;
23
+ }
24
+ interface UsagePayload {
25
+ customer_id: string;
26
+ meter_slug: string;
27
+ amount: number;
28
+ metadata?: Record<string, any>;
29
+ }
30
+ interface EntitlementCheck {
31
+ has_access: boolean;
32
+ usage: number;
33
+ limit: number | null;
34
+ type?: 'meter' | 'feature';
35
+ reason?: string;
36
+ }
37
+ interface Invoice {
38
+ id: string;
39
+ title: string;
40
+ amount_due: number;
41
+ currency: string;
42
+ status: string;
43
+ created_at: string;
44
+ }
45
+ interface Feature {
46
+ id: string;
47
+ name: string;
48
+ slug: string;
49
+ description: string | null;
50
+ type: string;
51
+ status: string;
52
+ pricing_model_id: string;
53
+ created_at: string;
54
+ }
55
+ interface MontraCheckoutOptions {
56
+ publishableKey: string;
57
+ checkoutUrl?: string;
58
+ }
59
+ type CheckoutSessionResponse = {
60
+ id: string;
61
+ url: string;
62
+ status: 'open' | 'complete' | 'expired';
63
+ };
64
+ interface IMontraCheckout {
65
+ mount(elementOrId: string | HTMLElement): void;
66
+ unmount(): void;
67
+ }
68
+
69
+ declare class Montra {
70
+ private apiKey;
71
+ private baseUrl;
72
+ constructor(options: MontraOptions);
73
+ private request;
74
+ createCustomer(data: {
75
+ name: string;
76
+ email: string;
77
+ }): Promise<Customer>;
78
+ listCustomers(): Promise<Customer[]>;
79
+ reportUsage(payload: UsagePayload): Promise<boolean>;
80
+ checkEntitlement(customerId: string, meterSlug: string): Promise<EntitlementCheck>;
81
+ listInvoices(): Promise<Invoice[]>;
82
+ getInvoice(id: string): Promise<Invoice>;
83
+ listFeatures(): Promise<Feature[]>;
84
+ createFeature(data: {
85
+ name: string;
86
+ slug: string;
87
+ description?: string;
88
+ pricing_model_id: string;
89
+ type?: string;
90
+ status?: string;
91
+ }): Promise<Feature>;
92
+ }
93
+
94
+ declare class MontraCheckout {
95
+ private publishableKey;
96
+ private checkoutUrl;
97
+ constructor(options: MontraCheckoutOptions);
98
+ initializeCheckout(sessionId: string): Promise<IMontraCheckout>;
99
+ }
100
+ declare const loadMontra: (publishableKey: string) => MontraCheckout;
101
+
102
+ type PaymentElementProps = {
103
+ sessionId: string;
104
+ checkoutUrl?: string;
105
+ onSuccess?: (data: any) => void;
106
+ onError?: (error: Error) => void;
107
+ };
108
+ /**
109
+ * PaymentElement component that renders the Montra payment form.
110
+ * In a production SDK, this would likely be an iframe-based component
111
+ * to ensure PCI compliance and security.
112
+ */
113
+ declare const PaymentElement: React.FC<PaymentElementProps>;
114
+
115
+ interface MontraProviderProps {
116
+ publishableKey: string;
117
+ checkoutUrl?: string;
118
+ children: React.ReactNode;
119
+ }
120
+ declare const MontraProvider: React.FC<MontraProviderProps>;
121
+ declare const useMontra: () => MontraCheckout;
122
+
123
+ interface MontraRequest extends Request {
124
+ montra?: Montra;
125
+ }
126
+ declare const montraMiddleware: (options: MontraOptions) => (req: MontraRequest, _res: Response, next: NextFunction) => void;
127
+
128
+ export { type ApiResponse, type CheckoutSessionResponse, type Customer, type EntitlementCheck, type Feature, type IMontraCheckout, type Invoice, Montra, MontraCheckout, type MontraCheckoutOptions, type MontraOptions, MontraProvider, type MontraProviderProps, type MontraRequest, PaymentElement, type PaymentElementProps, type UsagePayload, loadMontra, montraMiddleware, useMontra };
@@ -0,0 +1,128 @@
1
+ import React from 'react';
2
+ import { Request, Response, NextFunction } from 'express';
3
+
4
+ interface MontraOptions {
5
+ apiKey: string;
6
+ baseUrl?: string;
7
+ }
8
+ interface ApiResponse<T = any> {
9
+ success: boolean;
10
+ data?: T;
11
+ error?: {
12
+ code: string;
13
+ message: string;
14
+ details?: any;
15
+ };
16
+ }
17
+ interface Customer {
18
+ id: string;
19
+ name: string;
20
+ email: string;
21
+ status: string;
22
+ created_at: string;
23
+ }
24
+ interface UsagePayload {
25
+ customer_id: string;
26
+ meter_slug: string;
27
+ amount: number;
28
+ metadata?: Record<string, any>;
29
+ }
30
+ interface EntitlementCheck {
31
+ has_access: boolean;
32
+ usage: number;
33
+ limit: number | null;
34
+ type?: 'meter' | 'feature';
35
+ reason?: string;
36
+ }
37
+ interface Invoice {
38
+ id: string;
39
+ title: string;
40
+ amount_due: number;
41
+ currency: string;
42
+ status: string;
43
+ created_at: string;
44
+ }
45
+ interface Feature {
46
+ id: string;
47
+ name: string;
48
+ slug: string;
49
+ description: string | null;
50
+ type: string;
51
+ status: string;
52
+ pricing_model_id: string;
53
+ created_at: string;
54
+ }
55
+ interface MontraCheckoutOptions {
56
+ publishableKey: string;
57
+ checkoutUrl?: string;
58
+ }
59
+ type CheckoutSessionResponse = {
60
+ id: string;
61
+ url: string;
62
+ status: 'open' | 'complete' | 'expired';
63
+ };
64
+ interface IMontraCheckout {
65
+ mount(elementOrId: string | HTMLElement): void;
66
+ unmount(): void;
67
+ }
68
+
69
+ declare class Montra {
70
+ private apiKey;
71
+ private baseUrl;
72
+ constructor(options: MontraOptions);
73
+ private request;
74
+ createCustomer(data: {
75
+ name: string;
76
+ email: string;
77
+ }): Promise<Customer>;
78
+ listCustomers(): Promise<Customer[]>;
79
+ reportUsage(payload: UsagePayload): Promise<boolean>;
80
+ checkEntitlement(customerId: string, meterSlug: string): Promise<EntitlementCheck>;
81
+ listInvoices(): Promise<Invoice[]>;
82
+ getInvoice(id: string): Promise<Invoice>;
83
+ listFeatures(): Promise<Feature[]>;
84
+ createFeature(data: {
85
+ name: string;
86
+ slug: string;
87
+ description?: string;
88
+ pricing_model_id: string;
89
+ type?: string;
90
+ status?: string;
91
+ }): Promise<Feature>;
92
+ }
93
+
94
+ declare class MontraCheckout {
95
+ private publishableKey;
96
+ private checkoutUrl;
97
+ constructor(options: MontraCheckoutOptions);
98
+ initializeCheckout(sessionId: string): Promise<IMontraCheckout>;
99
+ }
100
+ declare const loadMontra: (publishableKey: string) => MontraCheckout;
101
+
102
+ type PaymentElementProps = {
103
+ sessionId: string;
104
+ checkoutUrl?: string;
105
+ onSuccess?: (data: any) => void;
106
+ onError?: (error: Error) => void;
107
+ };
108
+ /**
109
+ * PaymentElement component that renders the Montra payment form.
110
+ * In a production SDK, this would likely be an iframe-based component
111
+ * to ensure PCI compliance and security.
112
+ */
113
+ declare const PaymentElement: React.FC<PaymentElementProps>;
114
+
115
+ interface MontraProviderProps {
116
+ publishableKey: string;
117
+ checkoutUrl?: string;
118
+ children: React.ReactNode;
119
+ }
120
+ declare const MontraProvider: React.FC<MontraProviderProps>;
121
+ declare const useMontra: () => MontraCheckout;
122
+
123
+ interface MontraRequest extends Request {
124
+ montra?: Montra;
125
+ }
126
+ declare const montraMiddleware: (options: MontraOptions) => (req: MontraRequest, _res: Response, next: NextFunction) => void;
127
+
128
+ export { type ApiResponse, type CheckoutSessionResponse, type Customer, type EntitlementCheck, type Feature, type IMontraCheckout, type Invoice, Montra, MontraCheckout, type MontraCheckoutOptions, type MontraOptions, MontraProvider, type MontraProviderProps, type MontraRequest, PaymentElement, type PaymentElementProps, type UsagePayload, loadMontra, montraMiddleware, useMontra };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,241 @@
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
+ Montra: () => Montra,
24
+ MontraCheckout: () => MontraCheckout,
25
+ MontraProvider: () => MontraProvider,
26
+ PaymentElement: () => PaymentElement,
27
+ loadMontra: () => loadMontra,
28
+ montraMiddleware: () => montraMiddleware,
29
+ useMontra: () => useMontra
30
+ });
31
+ module.exports = __toCommonJS(index_exports);
32
+
33
+ // src/constants.ts
34
+ var DEFAULT_BASE_URL = "https://api.montra.fi/v1";
35
+ var DEFAULT_CHECKOUT_URL = "https://checkout.montra.fi";
36
+
37
+ // src/client.ts
38
+ var Montra = class {
39
+ constructor(options) {
40
+ this.apiKey = options.apiKey;
41
+ this.baseUrl = options.baseUrl || DEFAULT_BASE_URL;
42
+ }
43
+ async request(path, options = {}) {
44
+ const url = `${this.baseUrl}${path}`;
45
+ const headers = {
46
+ "Authorization": `Bearer ${this.apiKey}`,
47
+ "Content-Type": "application/json",
48
+ ...options.headers
49
+ };
50
+ const response = await fetch(url, {
51
+ ...options,
52
+ headers
53
+ });
54
+ const body = await response.json();
55
+ if (!response.ok) {
56
+ throw new Error(body.error?.message || `Request failed with status ${response.status}`);
57
+ }
58
+ return body;
59
+ }
60
+ // Customers
61
+ async createCustomer(data) {
62
+ const res = await this.request("/customers", {
63
+ method: "POST",
64
+ body: JSON.stringify(data)
65
+ });
66
+ return res.data;
67
+ }
68
+ async listCustomers() {
69
+ const res = await this.request("/customers");
70
+ return res.data;
71
+ }
72
+ // Usage
73
+ async reportUsage(payload) {
74
+ const res = await this.request("/usage", {
75
+ method: "POST",
76
+ body: JSON.stringify(payload)
77
+ });
78
+ return res.success;
79
+ }
80
+ // Entitlements
81
+ async checkEntitlement(customerId, meterSlug) {
82
+ const res = await this.request(
83
+ `/entitlements?customer_id=${customerId}&meter=${meterSlug}`
84
+ );
85
+ return res.data;
86
+ }
87
+ // Invoices
88
+ async listInvoices() {
89
+ const res = await this.request("/invoices");
90
+ return res.data;
91
+ }
92
+ async getInvoice(id) {
93
+ const res = await this.request(`/invoices/${id}`);
94
+ return res.data;
95
+ }
96
+ // Features
97
+ async listFeatures() {
98
+ const res = await this.request("/features");
99
+ return res.data;
100
+ }
101
+ async createFeature(data) {
102
+ const res = await this.request("/features", {
103
+ method: "POST",
104
+ body: JSON.stringify(data)
105
+ });
106
+ return res.data;
107
+ }
108
+ };
109
+
110
+ // src/checkout.ts
111
+ var MontraCheckout = class {
112
+ constructor(options) {
113
+ this.publishableKey = options.publishableKey;
114
+ this.checkoutUrl = options.checkoutUrl || DEFAULT_CHECKOUT_URL;
115
+ }
116
+ async initializeCheckout(sessionId) {
117
+ if (!sessionId) {
118
+ throw new Error("sessionId is required to initialize checkout");
119
+ }
120
+ let container = null;
121
+ let iframe = null;
122
+ return {
123
+ mount: (elementOrId) => {
124
+ if (typeof elementOrId === "string") {
125
+ container = document.getElementById(elementOrId);
126
+ } else {
127
+ container = elementOrId;
128
+ }
129
+ if (!container) {
130
+ throw new Error("Mount element not found");
131
+ }
132
+ iframe = document.createElement("iframe");
133
+ iframe.src = `${this.checkoutUrl}/pay/${sessionId}?pk=${this.publishableKey}`;
134
+ iframe.style.width = "100%";
135
+ iframe.style.height = "600px";
136
+ iframe.style.border = "none";
137
+ container.appendChild(iframe);
138
+ },
139
+ unmount: () => {
140
+ if (container && iframe) {
141
+ container.removeChild(iframe);
142
+ iframe = null;
143
+ }
144
+ }
145
+ };
146
+ }
147
+ };
148
+ var loadMontra = (publishableKey) => {
149
+ return new MontraCheckout({ publishableKey });
150
+ };
151
+
152
+ // src/components/PaymentElement.tsx
153
+ var import_react = require("react");
154
+ var import_jsx_runtime = require("react/jsx-runtime");
155
+ var PaymentElement = ({
156
+ sessionId,
157
+ checkoutUrl = DEFAULT_CHECKOUT_URL,
158
+ onSuccess,
159
+ onError
160
+ }) => {
161
+ const [loading, setLoading] = (0, import_react.useState)(true);
162
+ const finalCheckoutUrl = `${checkoutUrl}/pay/${sessionId}`;
163
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
164
+ "div",
165
+ {
166
+ className: "montra-payment-container",
167
+ style: {
168
+ width: "100%",
169
+ minHeight: "600px",
170
+ position: "relative",
171
+ overflow: "hidden"
172
+ },
173
+ children: [
174
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
175
+ "iframe",
176
+ {
177
+ src: finalCheckoutUrl,
178
+ title: "Montra Checkout",
179
+ style: {
180
+ width: "100%",
181
+ height: "100%",
182
+ minHeight: "600px",
183
+ border: "none"
184
+ },
185
+ onLoad: () => setLoading(false)
186
+ }
187
+ ),
188
+ loading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
189
+ position: "absolute",
190
+ top: 0,
191
+ left: 0,
192
+ right: 0,
193
+ bottom: 0,
194
+ display: "flex",
195
+ alignItems: "center",
196
+ justifyContent: "center",
197
+ backgroundColor: "#fff"
198
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { "data-testid": "loading-message", children: "Loading payment form..." }) })
199
+ ]
200
+ }
201
+ );
202
+ };
203
+
204
+ // src/react.tsx
205
+ var import_react2 = require("react");
206
+ var import_jsx_runtime2 = require("react/jsx-runtime");
207
+ var MontraContext = (0, import_react2.createContext)(null);
208
+ var MontraProvider = ({
209
+ publishableKey,
210
+ checkoutUrl,
211
+ children
212
+ }) => {
213
+ const montra = (0, import_react2.useMemo)(() => loadMontra(publishableKey), [publishableKey, checkoutUrl]);
214
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MontraContext.Provider, { value: montra, children });
215
+ };
216
+ var useMontra = () => {
217
+ const context = (0, import_react2.useContext)(MontraContext);
218
+ if (!context) {
219
+ throw new Error("useMontra must be used within a MontraProvider");
220
+ }
221
+ return context;
222
+ };
223
+
224
+ // src/express.ts
225
+ var montraMiddleware = (options) => {
226
+ const montra = new Montra(options);
227
+ return (req, _res, next) => {
228
+ req.montra = montra;
229
+ next();
230
+ };
231
+ };
232
+ // Annotate the CommonJS export names for ESM import in node:
233
+ 0 && (module.exports = {
234
+ Montra,
235
+ MontraCheckout,
236
+ MontraProvider,
237
+ PaymentElement,
238
+ loadMontra,
239
+ montraMiddleware,
240
+ useMontra
241
+ });
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,0CAAwB"}
package/dist/index.mjs ADDED
@@ -0,0 +1,208 @@
1
+ // src/constants.ts
2
+ var DEFAULT_BASE_URL = "https://api.montra.fi/v1";
3
+ var DEFAULT_CHECKOUT_URL = "https://checkout.montra.fi";
4
+
5
+ // src/client.ts
6
+ var Montra = class {
7
+ constructor(options) {
8
+ this.apiKey = options.apiKey;
9
+ this.baseUrl = options.baseUrl || DEFAULT_BASE_URL;
10
+ }
11
+ async request(path, options = {}) {
12
+ const url = `${this.baseUrl}${path}`;
13
+ const headers = {
14
+ "Authorization": `Bearer ${this.apiKey}`,
15
+ "Content-Type": "application/json",
16
+ ...options.headers
17
+ };
18
+ const response = await fetch(url, {
19
+ ...options,
20
+ headers
21
+ });
22
+ const body = await response.json();
23
+ if (!response.ok) {
24
+ throw new Error(body.error?.message || `Request failed with status ${response.status}`);
25
+ }
26
+ return body;
27
+ }
28
+ // Customers
29
+ async createCustomer(data) {
30
+ const res = await this.request("/customers", {
31
+ method: "POST",
32
+ body: JSON.stringify(data)
33
+ });
34
+ return res.data;
35
+ }
36
+ async listCustomers() {
37
+ const res = await this.request("/customers");
38
+ return res.data;
39
+ }
40
+ // Usage
41
+ async reportUsage(payload) {
42
+ const res = await this.request("/usage", {
43
+ method: "POST",
44
+ body: JSON.stringify(payload)
45
+ });
46
+ return res.success;
47
+ }
48
+ // Entitlements
49
+ async checkEntitlement(customerId, meterSlug) {
50
+ const res = await this.request(
51
+ `/entitlements?customer_id=${customerId}&meter=${meterSlug}`
52
+ );
53
+ return res.data;
54
+ }
55
+ // Invoices
56
+ async listInvoices() {
57
+ const res = await this.request("/invoices");
58
+ return res.data;
59
+ }
60
+ async getInvoice(id) {
61
+ const res = await this.request(`/invoices/${id}`);
62
+ return res.data;
63
+ }
64
+ // Features
65
+ async listFeatures() {
66
+ const res = await this.request("/features");
67
+ return res.data;
68
+ }
69
+ async createFeature(data) {
70
+ const res = await this.request("/features", {
71
+ method: "POST",
72
+ body: JSON.stringify(data)
73
+ });
74
+ return res.data;
75
+ }
76
+ };
77
+
78
+ // src/checkout.ts
79
+ var MontraCheckout = class {
80
+ constructor(options) {
81
+ this.publishableKey = options.publishableKey;
82
+ this.checkoutUrl = options.checkoutUrl || DEFAULT_CHECKOUT_URL;
83
+ }
84
+ async initializeCheckout(sessionId) {
85
+ if (!sessionId) {
86
+ throw new Error("sessionId is required to initialize checkout");
87
+ }
88
+ let container = null;
89
+ let iframe = null;
90
+ return {
91
+ mount: (elementOrId) => {
92
+ if (typeof elementOrId === "string") {
93
+ container = document.getElementById(elementOrId);
94
+ } else {
95
+ container = elementOrId;
96
+ }
97
+ if (!container) {
98
+ throw new Error("Mount element not found");
99
+ }
100
+ iframe = document.createElement("iframe");
101
+ iframe.src = `${this.checkoutUrl}/pay/${sessionId}?pk=${this.publishableKey}`;
102
+ iframe.style.width = "100%";
103
+ iframe.style.height = "600px";
104
+ iframe.style.border = "none";
105
+ container.appendChild(iframe);
106
+ },
107
+ unmount: () => {
108
+ if (container && iframe) {
109
+ container.removeChild(iframe);
110
+ iframe = null;
111
+ }
112
+ }
113
+ };
114
+ }
115
+ };
116
+ var loadMontra = (publishableKey) => {
117
+ return new MontraCheckout({ publishableKey });
118
+ };
119
+
120
+ // src/components/PaymentElement.tsx
121
+ import { useState } from "react";
122
+ import { jsx, jsxs } from "react/jsx-runtime";
123
+ var PaymentElement = ({
124
+ sessionId,
125
+ checkoutUrl = DEFAULT_CHECKOUT_URL,
126
+ onSuccess,
127
+ onError
128
+ }) => {
129
+ const [loading, setLoading] = useState(true);
130
+ const finalCheckoutUrl = `${checkoutUrl}/pay/${sessionId}`;
131
+ return /* @__PURE__ */ jsxs(
132
+ "div",
133
+ {
134
+ className: "montra-payment-container",
135
+ style: {
136
+ width: "100%",
137
+ minHeight: "600px",
138
+ position: "relative",
139
+ overflow: "hidden"
140
+ },
141
+ children: [
142
+ /* @__PURE__ */ jsx(
143
+ "iframe",
144
+ {
145
+ src: finalCheckoutUrl,
146
+ title: "Montra Checkout",
147
+ style: {
148
+ width: "100%",
149
+ height: "100%",
150
+ minHeight: "600px",
151
+ border: "none"
152
+ },
153
+ onLoad: () => setLoading(false)
154
+ }
155
+ ),
156
+ loading && /* @__PURE__ */ jsx("div", { style: {
157
+ position: "absolute",
158
+ top: 0,
159
+ left: 0,
160
+ right: 0,
161
+ bottom: 0,
162
+ display: "flex",
163
+ alignItems: "center",
164
+ justifyContent: "center",
165
+ backgroundColor: "#fff"
166
+ }, children: /* @__PURE__ */ jsx("p", { "data-testid": "loading-message", children: "Loading payment form..." }) })
167
+ ]
168
+ }
169
+ );
170
+ };
171
+
172
+ // src/react.tsx
173
+ import { createContext, useContext, useMemo } from "react";
174
+ import { jsx as jsx2 } from "react/jsx-runtime";
175
+ var MontraContext = createContext(null);
176
+ var MontraProvider = ({
177
+ publishableKey,
178
+ checkoutUrl,
179
+ children
180
+ }) => {
181
+ const montra = useMemo(() => loadMontra(publishableKey), [publishableKey, checkoutUrl]);
182
+ return /* @__PURE__ */ jsx2(MontraContext.Provider, { value: montra, children });
183
+ };
184
+ var useMontra = () => {
185
+ const context = useContext(MontraContext);
186
+ if (!context) {
187
+ throw new Error("useMontra must be used within a MontraProvider");
188
+ }
189
+ return context;
190
+ };
191
+
192
+ // src/express.ts
193
+ var montraMiddleware = (options) => {
194
+ const montra = new Montra(options);
195
+ return (req, _res, next) => {
196
+ req.montra = montra;
197
+ next();
198
+ };
199
+ };
200
+ export {
201
+ Montra,
202
+ MontraCheckout,
203
+ MontraProvider,
204
+ PaymentElement,
205
+ loadMontra,
206
+ montraMiddleware,
207
+ useMontra
208
+ };
@@ -0,0 +1,52 @@
1
+ export interface MontraOptions {
2
+ apiKey: string;
3
+ baseUrl?: string;
4
+ }
5
+ export interface ApiResponse<T = any> {
6
+ success: boolean;
7
+ data?: T;
8
+ error?: {
9
+ code: string;
10
+ message: string;
11
+ details?: any;
12
+ };
13
+ }
14
+ export interface Customer {
15
+ id: string;
16
+ name: string;
17
+ email: string;
18
+ status: string;
19
+ created_at: string;
20
+ }
21
+ export interface UsagePayload {
22
+ customer_id: string;
23
+ meter_slug: string;
24
+ amount: number;
25
+ metadata?: Record<string, any>;
26
+ }
27
+ export interface EntitlementCheck {
28
+ has_access: boolean;
29
+ usage: number;
30
+ limit: number | null;
31
+ type?: 'meter' | 'feature';
32
+ reason?: string;
33
+ }
34
+ export interface Invoice {
35
+ id: string;
36
+ title: string;
37
+ amount_due: number;
38
+ currency: string;
39
+ status: string;
40
+ created_at: string;
41
+ }
42
+ export interface Feature {
43
+ id: string;
44
+ name: string;
45
+ slug: string;
46
+ description: string | null;
47
+ type: string;
48
+ status: string;
49
+ pricing_model_id: string;
50
+ created_at: string;
51
+ }
52
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,GAAG;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,GAAG,CAAC;KACf,CAAC;CACH;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;CACpB"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@montra/sdk",
3
+ "version": "0.1.0",
4
+ "description": "The official Montra SDK for Node.js and Browser",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "scripts": {
12
+ "build": "tsup src/index.ts --format cjs,esm --dts",
13
+ "dev": "tsup src/index.ts --format cjs,esm --watch --dts",
14
+ "lint": "eslint src/",
15
+ "test": "vitest run"
16
+ },
17
+ "keywords": [
18
+ "montra",
19
+ "payfac",
20
+ "billing",
21
+ "metering",
22
+ "sdk",
23
+ "checkout",
24
+ "payments"
25
+ ],
26
+ "author": "Montra",
27
+ "license": "MIT",
28
+ "peerDependencies": {
29
+ "react": "^18.0.0 || ^19.0.0",
30
+ "react-dom": "^18.0.0 || ^19.0.0"
31
+ },
32
+ "peerDependenciesMeta": {
33
+ "react": {
34
+ "optional": true
35
+ },
36
+ "react-dom": {
37
+ "optional": true
38
+ }
39
+ },
40
+ "devDependencies": {
41
+ "@types/express": "^5.0.6",
42
+ "@types/react": "^19.0.0",
43
+ "@types/react-dom": "^19.0.0",
44
+ "react": "^19.0.0",
45
+ "react-dom": "^19.0.0",
46
+ "tsup": "^8.0.2",
47
+ "typescript": "^5.3.3",
48
+ "vitest": "^3.2.4"
49
+ }
50
+ }