authtara-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,372 @@
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
+ ApiError: () => ApiError,
24
+ Authtara: () => Authtara,
25
+ AuthtaraError: () => AuthtaraError,
26
+ ConfigurationError: () => ConfigurationError,
27
+ EntitlementDeniedError: () => EntitlementDeniedError,
28
+ InvalidTokenError: () => InvalidTokenError,
29
+ default: () => index_default
30
+ });
31
+ module.exports = __toCommonJS(index_exports);
32
+
33
+ // src/common/errors.ts
34
+ var AuthtaraError = class _AuthtaraError extends Error {
35
+ constructor(message, code, statusCode) {
36
+ super(message);
37
+ this.name = "AuthtaraError";
38
+ this.code = code;
39
+ this.statusCode = statusCode;
40
+ Object.setPrototypeOf(this, _AuthtaraError.prototype);
41
+ }
42
+ };
43
+ var InvalidTokenError = class _InvalidTokenError extends AuthtaraError {
44
+ constructor(message = "Invalid or expired token") {
45
+ super(message, "INVALID_TOKEN", 401);
46
+ this.name = "InvalidTokenError";
47
+ Object.setPrototypeOf(this, _InvalidTokenError.prototype);
48
+ }
49
+ };
50
+ var EntitlementDeniedError = class _EntitlementDeniedError extends AuthtaraError {
51
+ constructor(message = "Access denied", reason) {
52
+ super(message, "ENTITLEMENT_DENIED", 403);
53
+ this.name = "EntitlementDeniedError";
54
+ this.reason = reason;
55
+ Object.setPrototypeOf(this, _EntitlementDeniedError.prototype);
56
+ }
57
+ };
58
+ var ApiError = class _ApiError extends AuthtaraError {
59
+ constructor(message, statusCode, response) {
60
+ super(message, "API_ERROR", statusCode);
61
+ this.name = "ApiError";
62
+ this.response = response;
63
+ Object.setPrototypeOf(this, _ApiError.prototype);
64
+ }
65
+ };
66
+ var ConfigurationError = class _ConfigurationError extends AuthtaraError {
67
+ constructor(message) {
68
+ super(message, "CONFIG_ERROR");
69
+ this.name = "ConfigurationError";
70
+ Object.setPrototypeOf(this, _ConfigurationError.prototype);
71
+ }
72
+ };
73
+
74
+ // src/common/http-client.ts
75
+ function extractErrorMessage(error, fallback) {
76
+ if (!error) return fallback;
77
+ if (typeof error === "string") return error;
78
+ if (typeof error === "object" && error.message) return error.message;
79
+ return fallback;
80
+ }
81
+ var HttpClient = class {
82
+ constructor(config) {
83
+ if (!config.baseUrl) {
84
+ throw new ConfigurationError("baseUrl is required");
85
+ }
86
+ if (!config.apiKey) {
87
+ throw new ConfigurationError("apiKey is required");
88
+ }
89
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
90
+ this.apiKey = config.apiKey;
91
+ this.timeout = config.timeout ?? 3e4;
92
+ }
93
+ /**
94
+ * Make HTTP request to Platform API
95
+ */
96
+ async request(options) {
97
+ const url = `${this.baseUrl}${options.path}`;
98
+ const headers = {
99
+ "Content-Type": "application/json",
100
+ Authorization: `Bearer ${this.apiKey}`,
101
+ ...options.headers
102
+ };
103
+ const controller = new AbortController();
104
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
105
+ try {
106
+ const response = await fetch(url, {
107
+ method: options.method,
108
+ headers,
109
+ body: options.body ? JSON.stringify(options.body) : void 0,
110
+ signal: controller.signal
111
+ });
112
+ clearTimeout(timeoutId);
113
+ const data = await response.json();
114
+ if (!response.ok) {
115
+ throw new ApiError(
116
+ extractErrorMessage(data.error, `HTTP ${response.status}: ${response.statusText}`),
117
+ response.status,
118
+ data
119
+ );
120
+ }
121
+ if (!data.success) {
122
+ throw new ApiError(extractErrorMessage(data.error, "API request failed"), 400, data);
123
+ }
124
+ return data.data;
125
+ } catch (error) {
126
+ clearTimeout(timeoutId);
127
+ if (error instanceof ApiError) {
128
+ throw error;
129
+ }
130
+ if (error instanceof Error) {
131
+ if (error.name === "AbortError") {
132
+ throw new ApiError(`Request timeout after ${this.timeout}ms`, 408);
133
+ }
134
+ throw new ApiError(error.message, 500);
135
+ }
136
+ throw new ApiError("Unknown error occurred", 500);
137
+ }
138
+ }
139
+ /**
140
+ * POST request shorthand
141
+ */
142
+ async post(path, body) {
143
+ return this.request({ method: "POST", path, body });
144
+ }
145
+ /**
146
+ * GET request shorthand
147
+ */
148
+ async get(path) {
149
+ return this.request({ method: "GET", path });
150
+ }
151
+ };
152
+
153
+ // src/auth/index.ts
154
+ var import_jose = require("jose");
155
+ var AuthModule = class {
156
+ constructor(apiKey, httpClient, issuer = "platform.digitalsolution.com") {
157
+ if (!apiKey) {
158
+ throw new ConfigurationError("apiKey is required for AuthModule");
159
+ }
160
+ this.apiKey = apiKey;
161
+ this.httpClient = httpClient;
162
+ this.issuer = issuer;
163
+ }
164
+ /**
165
+ * Verifikasi SSO JWT token secara offline
166
+ *
167
+ * Token diverifikasi menggunakan App Secret (HS256).
168
+ * Ini lebih cepat daripada memanggil API karena tidak memerlukan network request.
169
+ *
170
+ * @param token - JWT token dari SSO callback
171
+ * @returns SessionVerifyResult dengan data user, tenant, dan subscription
172
+ * @throws InvalidTokenError jika token tidak valid atau expired
173
+ *
174
+ * @example
175
+ * ```typescript
176
+ * const session = await ds.auth.verifySession(token);
177
+ * if (session.isValid) {
178
+ * console.log('User:', session.user);
179
+ * console.log('Tenant:', session.tenant);
180
+ * }
181
+ * ```
182
+ */
183
+ async verifySession(token) {
184
+ if (!token) {
185
+ throw new InvalidTokenError("Token is required");
186
+ }
187
+ try {
188
+ const secretKey = new TextEncoder().encode(this.apiKey);
189
+ const { payload } = await (0, import_jose.jwtVerify)(token, secretKey, {
190
+ algorithms: ["HS256"],
191
+ issuer: this.issuer
192
+ });
193
+ const ssoPayload = payload;
194
+ return {
195
+ isValid: true,
196
+ user: {
197
+ id: ssoPayload.sub ?? "",
198
+ email: ssoPayload.email ?? "",
199
+ name: ssoPayload.name ?? null
200
+ },
201
+ tenant: ssoPayload.tenant,
202
+ subscription: ssoPayload.subscription
203
+ };
204
+ } catch (error) {
205
+ const message = error instanceof Error ? error.message : "Token verification failed";
206
+ throw new InvalidTokenError(message);
207
+ }
208
+ }
209
+ /**
210
+ * Exchange authorization code untuk JWT token (server-to-server)
211
+ *
212
+ * Gunakan ini di callback endpoint untuk menukar authorization code
213
+ * menjadi JWT token yang bisa diverifikasi.
214
+ *
215
+ * @param code - Authorization code dari callback URL
216
+ * @returns ExchangeResult dengan token dan data context
217
+ *
218
+ * @example
219
+ * ```typescript
220
+ * // Di endpoint /api/sso/callback
221
+ * const code = searchParams.get('code');
222
+ * const result = await ds.auth.exchangeCode(code);
223
+ * // Simpan result.token ke session
224
+ * ```
225
+ */
226
+ async exchangeCode(code) {
227
+ if (!code) {
228
+ throw new ConfigurationError("Authorization code is required");
229
+ }
230
+ return this.httpClient.post("/api/sso/exchange", {
231
+ code,
232
+ appSecret: this.apiKey
233
+ });
234
+ }
235
+ };
236
+
237
+ // src/billing/index.ts
238
+ var BillingModule = class {
239
+ constructor(httpClient) {
240
+ if (!httpClient) {
241
+ throw new ConfigurationError("httpClient is required for BillingModule");
242
+ }
243
+ this.httpClient = httpClient;
244
+ }
245
+ /**
246
+ * Cek apakah tenant memiliki akses ke aplikasi Anda
247
+ *
248
+ * @param params - Parameter pengecekan (tenantId wajib, featureKey opsional)
249
+ * @returns EntitlementResult dengan status akses
250
+ *
251
+ * @example
252
+ * ```typescript
253
+ * // Cek akses dasar
254
+ * const hasAccess = await ds.billing.checkEntitlement({
255
+ * tenantId: tenant.id
256
+ * });
257
+ *
258
+ * // Cek fitur spesifik
259
+ * const canUseAI = await ds.billing.checkEntitlement({
260
+ * tenantId: tenant.id,
261
+ * featureKey: 'ai_generator'
262
+ * });
263
+ *
264
+ * if (!canUseAI.granted) {
265
+ * throw new Error(canUseAI.reason);
266
+ * }
267
+ * ```
268
+ */
269
+ async checkEntitlement(params) {
270
+ if (!params.tenantId) {
271
+ throw new ConfigurationError("tenantId is required");
272
+ }
273
+ return this.httpClient.post(
274
+ "/api/v1/dev/entitlements/check",
275
+ {
276
+ tenantId: params.tenantId,
277
+ featureKey: params.featureKey
278
+ }
279
+ );
280
+ }
281
+ };
282
+
283
+ // src/metering/index.ts
284
+ var MeteringModule = class {
285
+ constructor(httpClient) {
286
+ if (!httpClient) {
287
+ throw new ConfigurationError(
288
+ "httpClient is required for MeteringModule"
289
+ );
290
+ }
291
+ this.httpClient = httpClient;
292
+ }
293
+ /**
294
+ * Catat penggunaan untuk usage-based billing
295
+ *
296
+ * @param params - Parameter pencatatan
297
+ * @returns RecordUsageResult
298
+ *
299
+ * @example
300
+ * ```typescript
301
+ * // Setelah user mengirim pesan
302
+ * await ds.metering.recordUsage({
303
+ * tenantId: currentTenant.id,
304
+ * metricSlug: 'message_sent',
305
+ * amount: 1
306
+ * });
307
+ *
308
+ * // Batch recording untuk efisiensi
309
+ * await ds.metering.recordUsage({
310
+ * tenantId: currentTenant.id,
311
+ * metricSlug: 'api_call',
312
+ * amount: 100 // Batch 100 API calls
313
+ * });
314
+ * ```
315
+ */
316
+ async recordUsage(params) {
317
+ if (!params.tenantId) {
318
+ throw new ConfigurationError("tenantId is required");
319
+ }
320
+ if (!params.metricSlug) {
321
+ throw new ConfigurationError("metricSlug is required");
322
+ }
323
+ if (!params.amount || params.amount < 1) {
324
+ throw new ConfigurationError("amount must be a positive number");
325
+ }
326
+ return this.httpClient.post(
327
+ "/api/v1/dev/metering/record",
328
+ {
329
+ tenantId: params.tenantId,
330
+ metricSlug: params.metricSlug,
331
+ amount: params.amount,
332
+ timestamp: params.timestamp
333
+ }
334
+ );
335
+ }
336
+ };
337
+
338
+ // src/index.ts
339
+ var Authtara = class {
340
+ /**
341
+ * Create new Authtara SDK instance
342
+ *
343
+ * @param config - Konfigurasi SDK
344
+ * @throws ConfigurationError jika apiKey tidak disediakan
345
+ */
346
+ constructor(config) {
347
+ if (!config.apiKey) {
348
+ throw new ConfigurationError(
349
+ "apiKey is required. Get it from your Developer Dashboard."
350
+ );
351
+ }
352
+ const endpoint = config.endpoint ?? "https://api.digitalsolution.com";
353
+ const httpClient = new HttpClient({
354
+ baseUrl: endpoint,
355
+ apiKey: config.apiKey,
356
+ timeout: config.timeout
357
+ });
358
+ this.auth = new AuthModule(config.apiKey, httpClient);
359
+ this.billing = new BillingModule(httpClient);
360
+ this.metering = new MeteringModule(httpClient);
361
+ }
362
+ };
363
+ var index_default = Authtara;
364
+ // Annotate the CommonJS export names for ESM import in node:
365
+ 0 && (module.exports = {
366
+ ApiError,
367
+ Authtara,
368
+ AuthtaraError,
369
+ ConfigurationError,
370
+ EntitlementDeniedError,
371
+ InvalidTokenError
372
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,340 @@
1
+ // src/common/errors.ts
2
+ var AuthtaraError = class _AuthtaraError extends Error {
3
+ constructor(message, code, statusCode) {
4
+ super(message);
5
+ this.name = "AuthtaraError";
6
+ this.code = code;
7
+ this.statusCode = statusCode;
8
+ Object.setPrototypeOf(this, _AuthtaraError.prototype);
9
+ }
10
+ };
11
+ var InvalidTokenError = class _InvalidTokenError extends AuthtaraError {
12
+ constructor(message = "Invalid or expired token") {
13
+ super(message, "INVALID_TOKEN", 401);
14
+ this.name = "InvalidTokenError";
15
+ Object.setPrototypeOf(this, _InvalidTokenError.prototype);
16
+ }
17
+ };
18
+ var EntitlementDeniedError = class _EntitlementDeniedError extends AuthtaraError {
19
+ constructor(message = "Access denied", reason) {
20
+ super(message, "ENTITLEMENT_DENIED", 403);
21
+ this.name = "EntitlementDeniedError";
22
+ this.reason = reason;
23
+ Object.setPrototypeOf(this, _EntitlementDeniedError.prototype);
24
+ }
25
+ };
26
+ var ApiError = class _ApiError extends AuthtaraError {
27
+ constructor(message, statusCode, response) {
28
+ super(message, "API_ERROR", statusCode);
29
+ this.name = "ApiError";
30
+ this.response = response;
31
+ Object.setPrototypeOf(this, _ApiError.prototype);
32
+ }
33
+ };
34
+ var ConfigurationError = class _ConfigurationError extends AuthtaraError {
35
+ constructor(message) {
36
+ super(message, "CONFIG_ERROR");
37
+ this.name = "ConfigurationError";
38
+ Object.setPrototypeOf(this, _ConfigurationError.prototype);
39
+ }
40
+ };
41
+
42
+ // src/common/http-client.ts
43
+ function extractErrorMessage(error, fallback) {
44
+ if (!error) return fallback;
45
+ if (typeof error === "string") return error;
46
+ if (typeof error === "object" && error.message) return error.message;
47
+ return fallback;
48
+ }
49
+ var HttpClient = class {
50
+ constructor(config) {
51
+ if (!config.baseUrl) {
52
+ throw new ConfigurationError("baseUrl is required");
53
+ }
54
+ if (!config.apiKey) {
55
+ throw new ConfigurationError("apiKey is required");
56
+ }
57
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
58
+ this.apiKey = config.apiKey;
59
+ this.timeout = config.timeout ?? 3e4;
60
+ }
61
+ /**
62
+ * Make HTTP request to Platform API
63
+ */
64
+ async request(options) {
65
+ const url = `${this.baseUrl}${options.path}`;
66
+ const headers = {
67
+ "Content-Type": "application/json",
68
+ Authorization: `Bearer ${this.apiKey}`,
69
+ ...options.headers
70
+ };
71
+ const controller = new AbortController();
72
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
73
+ try {
74
+ const response = await fetch(url, {
75
+ method: options.method,
76
+ headers,
77
+ body: options.body ? JSON.stringify(options.body) : void 0,
78
+ signal: controller.signal
79
+ });
80
+ clearTimeout(timeoutId);
81
+ const data = await response.json();
82
+ if (!response.ok) {
83
+ throw new ApiError(
84
+ extractErrorMessage(data.error, `HTTP ${response.status}: ${response.statusText}`),
85
+ response.status,
86
+ data
87
+ );
88
+ }
89
+ if (!data.success) {
90
+ throw new ApiError(extractErrorMessage(data.error, "API request failed"), 400, data);
91
+ }
92
+ return data.data;
93
+ } catch (error) {
94
+ clearTimeout(timeoutId);
95
+ if (error instanceof ApiError) {
96
+ throw error;
97
+ }
98
+ if (error instanceof Error) {
99
+ if (error.name === "AbortError") {
100
+ throw new ApiError(`Request timeout after ${this.timeout}ms`, 408);
101
+ }
102
+ throw new ApiError(error.message, 500);
103
+ }
104
+ throw new ApiError("Unknown error occurred", 500);
105
+ }
106
+ }
107
+ /**
108
+ * POST request shorthand
109
+ */
110
+ async post(path, body) {
111
+ return this.request({ method: "POST", path, body });
112
+ }
113
+ /**
114
+ * GET request shorthand
115
+ */
116
+ async get(path) {
117
+ return this.request({ method: "GET", path });
118
+ }
119
+ };
120
+
121
+ // src/auth/index.ts
122
+ import { jwtVerify } from "jose";
123
+ var AuthModule = class {
124
+ constructor(apiKey, httpClient, issuer = "platform.digitalsolution.com") {
125
+ if (!apiKey) {
126
+ throw new ConfigurationError("apiKey is required for AuthModule");
127
+ }
128
+ this.apiKey = apiKey;
129
+ this.httpClient = httpClient;
130
+ this.issuer = issuer;
131
+ }
132
+ /**
133
+ * Verifikasi SSO JWT token secara offline
134
+ *
135
+ * Token diverifikasi menggunakan App Secret (HS256).
136
+ * Ini lebih cepat daripada memanggil API karena tidak memerlukan network request.
137
+ *
138
+ * @param token - JWT token dari SSO callback
139
+ * @returns SessionVerifyResult dengan data user, tenant, dan subscription
140
+ * @throws InvalidTokenError jika token tidak valid atau expired
141
+ *
142
+ * @example
143
+ * ```typescript
144
+ * const session = await ds.auth.verifySession(token);
145
+ * if (session.isValid) {
146
+ * console.log('User:', session.user);
147
+ * console.log('Tenant:', session.tenant);
148
+ * }
149
+ * ```
150
+ */
151
+ async verifySession(token) {
152
+ if (!token) {
153
+ throw new InvalidTokenError("Token is required");
154
+ }
155
+ try {
156
+ const secretKey = new TextEncoder().encode(this.apiKey);
157
+ const { payload } = await jwtVerify(token, secretKey, {
158
+ algorithms: ["HS256"],
159
+ issuer: this.issuer
160
+ });
161
+ const ssoPayload = payload;
162
+ return {
163
+ isValid: true,
164
+ user: {
165
+ id: ssoPayload.sub ?? "",
166
+ email: ssoPayload.email ?? "",
167
+ name: ssoPayload.name ?? null
168
+ },
169
+ tenant: ssoPayload.tenant,
170
+ subscription: ssoPayload.subscription
171
+ };
172
+ } catch (error) {
173
+ const message = error instanceof Error ? error.message : "Token verification failed";
174
+ throw new InvalidTokenError(message);
175
+ }
176
+ }
177
+ /**
178
+ * Exchange authorization code untuk JWT token (server-to-server)
179
+ *
180
+ * Gunakan ini di callback endpoint untuk menukar authorization code
181
+ * menjadi JWT token yang bisa diverifikasi.
182
+ *
183
+ * @param code - Authorization code dari callback URL
184
+ * @returns ExchangeResult dengan token dan data context
185
+ *
186
+ * @example
187
+ * ```typescript
188
+ * // Di endpoint /api/sso/callback
189
+ * const code = searchParams.get('code');
190
+ * const result = await ds.auth.exchangeCode(code);
191
+ * // Simpan result.token ke session
192
+ * ```
193
+ */
194
+ async exchangeCode(code) {
195
+ if (!code) {
196
+ throw new ConfigurationError("Authorization code is required");
197
+ }
198
+ return this.httpClient.post("/api/sso/exchange", {
199
+ code,
200
+ appSecret: this.apiKey
201
+ });
202
+ }
203
+ };
204
+
205
+ // src/billing/index.ts
206
+ var BillingModule = class {
207
+ constructor(httpClient) {
208
+ if (!httpClient) {
209
+ throw new ConfigurationError("httpClient is required for BillingModule");
210
+ }
211
+ this.httpClient = httpClient;
212
+ }
213
+ /**
214
+ * Cek apakah tenant memiliki akses ke aplikasi Anda
215
+ *
216
+ * @param params - Parameter pengecekan (tenantId wajib, featureKey opsional)
217
+ * @returns EntitlementResult dengan status akses
218
+ *
219
+ * @example
220
+ * ```typescript
221
+ * // Cek akses dasar
222
+ * const hasAccess = await ds.billing.checkEntitlement({
223
+ * tenantId: tenant.id
224
+ * });
225
+ *
226
+ * // Cek fitur spesifik
227
+ * const canUseAI = await ds.billing.checkEntitlement({
228
+ * tenantId: tenant.id,
229
+ * featureKey: 'ai_generator'
230
+ * });
231
+ *
232
+ * if (!canUseAI.granted) {
233
+ * throw new Error(canUseAI.reason);
234
+ * }
235
+ * ```
236
+ */
237
+ async checkEntitlement(params) {
238
+ if (!params.tenantId) {
239
+ throw new ConfigurationError("tenantId is required");
240
+ }
241
+ return this.httpClient.post(
242
+ "/api/v1/dev/entitlements/check",
243
+ {
244
+ tenantId: params.tenantId,
245
+ featureKey: params.featureKey
246
+ }
247
+ );
248
+ }
249
+ };
250
+
251
+ // src/metering/index.ts
252
+ var MeteringModule = class {
253
+ constructor(httpClient) {
254
+ if (!httpClient) {
255
+ throw new ConfigurationError(
256
+ "httpClient is required for MeteringModule"
257
+ );
258
+ }
259
+ this.httpClient = httpClient;
260
+ }
261
+ /**
262
+ * Catat penggunaan untuk usage-based billing
263
+ *
264
+ * @param params - Parameter pencatatan
265
+ * @returns RecordUsageResult
266
+ *
267
+ * @example
268
+ * ```typescript
269
+ * // Setelah user mengirim pesan
270
+ * await ds.metering.recordUsage({
271
+ * tenantId: currentTenant.id,
272
+ * metricSlug: 'message_sent',
273
+ * amount: 1
274
+ * });
275
+ *
276
+ * // Batch recording untuk efisiensi
277
+ * await ds.metering.recordUsage({
278
+ * tenantId: currentTenant.id,
279
+ * metricSlug: 'api_call',
280
+ * amount: 100 // Batch 100 API calls
281
+ * });
282
+ * ```
283
+ */
284
+ async recordUsage(params) {
285
+ if (!params.tenantId) {
286
+ throw new ConfigurationError("tenantId is required");
287
+ }
288
+ if (!params.metricSlug) {
289
+ throw new ConfigurationError("metricSlug is required");
290
+ }
291
+ if (!params.amount || params.amount < 1) {
292
+ throw new ConfigurationError("amount must be a positive number");
293
+ }
294
+ return this.httpClient.post(
295
+ "/api/v1/dev/metering/record",
296
+ {
297
+ tenantId: params.tenantId,
298
+ metricSlug: params.metricSlug,
299
+ amount: params.amount,
300
+ timestamp: params.timestamp
301
+ }
302
+ );
303
+ }
304
+ };
305
+
306
+ // src/index.ts
307
+ var Authtara = class {
308
+ /**
309
+ * Create new Authtara SDK instance
310
+ *
311
+ * @param config - Konfigurasi SDK
312
+ * @throws ConfigurationError jika apiKey tidak disediakan
313
+ */
314
+ constructor(config) {
315
+ if (!config.apiKey) {
316
+ throw new ConfigurationError(
317
+ "apiKey is required. Get it from your Developer Dashboard."
318
+ );
319
+ }
320
+ const endpoint = config.endpoint ?? "https://api.digitalsolution.com";
321
+ const httpClient = new HttpClient({
322
+ baseUrl: endpoint,
323
+ apiKey: config.apiKey,
324
+ timeout: config.timeout
325
+ });
326
+ this.auth = new AuthModule(config.apiKey, httpClient);
327
+ this.billing = new BillingModule(httpClient);
328
+ this.metering = new MeteringModule(httpClient);
329
+ }
330
+ };
331
+ var index_default = Authtara;
332
+ export {
333
+ ApiError,
334
+ Authtara,
335
+ AuthtaraError,
336
+ ConfigurationError,
337
+ EntitlementDeniedError,
338
+ InvalidTokenError,
339
+ index_default as default
340
+ };