@absolutejs/mcp 0.15.1 → 0.17.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.
@@ -0,0 +1 @@
1
+ export {};
package/dist/commerce.js CHANGED
@@ -145,6 +145,227 @@ var createPurchaseStatusTool = (options) => ({
145
145
  };
146
146
  }
147
147
  });
148
+ // node_modules/@absolutejs/billing/dist/reports.js
149
+ var DAY_MS = 86400000;
150
+ var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
151
+ var record2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
152
+ var only = (input, keys) => {
153
+ if (!record2(input) || Object.keys(input).some((key) => !keys.includes(key)))
154
+ throw new Error("Invalid report input");
155
+ return input;
156
+ };
157
+ var integer = (value) => {
158
+ if (!Number.isSafeInteger(value) || value < 0)
159
+ throw new Error("Invalid report amount");
160
+ return value;
161
+ };
162
+ var iso = (value) => {
163
+ if (!Number.isFinite(Date.parse(value)) || new Date(value).toISOString() !== value)
164
+ throw new Error("Invalid report timestamp");
165
+ return value;
166
+ };
167
+ var day = (value) => {
168
+ if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(value) || new Date(value + "T00:00:00.000Z").toISOString().slice(0, 10) !== value)
169
+ throw new Error("Expected a UTC calendar date");
170
+ return value;
171
+ };
172
+ var parseUsageRange = (input, now = new Date) => {
173
+ const args = only(input, ["from", "to"]);
174
+ const tomorrow = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()) + DAY_MS);
175
+ const to = day(args.to ?? tomorrow.toISOString().slice(0, 10));
176
+ const from = day(args.from ?? new Date(Date.parse(to) - 30 * DAY_MS).toISOString().slice(0, 10));
177
+ const duration = Date.parse(to) - Date.parse(from);
178
+ if (duration <= 0 || duration > 90 * DAY_MS || Date.parse(to) > tomorrow.getTime())
179
+ throw new Error("Choose a range of 1\u201390 UTC days, ending no later than tomorrow");
180
+ return { from, to };
181
+ };
182
+ var parseReceiptPage = (input) => {
183
+ const args = only(input, ["limit", "cursor"]);
184
+ const limit = args.limit ?? 20;
185
+ if (typeof limit !== "number" || !Number.isInteger(limit) || limit < 1 || limit > 50)
186
+ throw new Error("Receipt limit must be 1\u201350");
187
+ if (args.cursor === undefined || args.cursor === null)
188
+ return { limit, cursor: null };
189
+ if (typeof args.cursor !== "string" || args.cursor.length > 256 || !/^[A-Za-z0-9_-]+$/.test(args.cursor))
190
+ throw new Error("Invalid receipt cursor");
191
+ const decoded = JSON.parse(Buffer.from(args.cursor, "base64url").toString("utf8"));
192
+ if (!record2(decoded) || typeof decoded.at !== "string" || typeof decoded.id !== "string" || !UUID.test(decoded.id))
193
+ throw new Error("Invalid receipt cursor");
194
+ return { limit, cursor: { at: iso(decoded.at), id: decoded.id } };
195
+ };
196
+ var projectBillingStatus = (value) => ({
197
+ portalAccess: value.portalAccess === true,
198
+ subscription: value.subscription ? {
199
+ status: String(value.subscription.status).slice(0, 64),
200
+ renewsAt: value.subscription.renewsAt === null ? null : iso(value.subscription.renewsAt),
201
+ cancelAtPeriodEnd: value.subscription.cancelAtPeriodEnd === true
202
+ } : null,
203
+ credits: {
204
+ remaining: integer(value.credits.remaining),
205
+ reserved: integer(value.credits.reserved),
206
+ purchased: integer(value.credits.purchased),
207
+ promotional: integer(value.credits.promotional),
208
+ debt: integer(value.credits.debt)
209
+ },
210
+ automaticRefill: false
211
+ });
212
+ var projectReceiptPage = (value, limit) => {
213
+ if (value.receipts.length > limit)
214
+ throw new Error("Receipt page exceeds its limit");
215
+ if (value.nextCursor !== null)
216
+ parseReceiptPage({ cursor: value.nextCursor });
217
+ return {
218
+ receipts: value.receipts.map((row) => {
219
+ if (!UUID.test(row.id) || !/^[A-Z]{3}$/.test(row.currency) || !["credit_purchase", "initial", "plan_change", "renewal"].includes(row.source) || !["paid", "partially_refunded", "refunded"].includes(row.status) || row.refundedAmountCents > row.amountCents)
220
+ throw new Error("Invalid receipt");
221
+ return {
222
+ id: row.id,
223
+ issuedAt: iso(row.issuedAt),
224
+ currency: row.currency,
225
+ amountCents: integer(row.amountCents),
226
+ refundedAmountCents: integer(row.refundedAmountCents),
227
+ source: row.source,
228
+ status: row.status
229
+ };
230
+ }),
231
+ nextCursor: value.nextCursor
232
+ };
233
+ };
234
+ var projectUsageReport = (value, range) => {
235
+ if (value.from !== range.from || value.to !== range.to || value.byDay.length > 90 || value.byFeature.length > 21)
236
+ throw new Error("Invalid usage report bounds");
237
+ const byDay = value.byDay.map((row) => ({
238
+ day: day(row.day),
239
+ credits: integer(row.credits),
240
+ events: integer(row.events)
241
+ }));
242
+ const byFeature = value.byFeature.map((row) => ({
243
+ feature: row.feature.slice(0, 128),
244
+ credits: integer(row.credits),
245
+ events: integer(row.events)
246
+ }));
247
+ const credits = integer(value.creditsConsumed), events = integer(value.events);
248
+ for (const rows of [byDay, byFeature])
249
+ if (rows.reduce((sum, row) => sum + row.credits, 0) !== credits || rows.reduce((sum, row) => sum + row.events, 0) !== events)
250
+ throw new Error("Usage breakdown does not reconcile");
251
+ if (new Set(byDay.map((row) => row.day)).size !== byDay.length || byDay.some((row) => row.day < range.from || row.day >= range.to))
252
+ throw new Error("Invalid usage days");
253
+ return {
254
+ from: range.from,
255
+ to: range.to,
256
+ creditsConsumed: credits,
257
+ events,
258
+ byDay,
259
+ byFeature
260
+ };
261
+ };
262
+
263
+ // src/billingTools.ts
264
+ var result = (text, data) => ({
265
+ content: [{ type: "text", text }],
266
+ structuredContent: { ...data }
267
+ });
268
+ var empty = (input) => {
269
+ if (!input || typeof input !== "object" || Array.isArray(input) || Object.keys(input).length)
270
+ throw new Error("This tool takes no arguments");
271
+ };
272
+ var createBillingReportTools = (readers) => ({
273
+ get_billing_status: {
274
+ annotations: {
275
+ readOnlyHint: true,
276
+ destructiveHint: false,
277
+ openWorldHint: false
278
+ },
279
+ commerce: {
280
+ action: "entitlement_status",
281
+ categories: ["usage_credits", "subscription"]
282
+ },
283
+ description: "Read subscription and service-credit status for this account, including reserved credits and debt. Does not charge, renew or cancel anything. Available at zero balance.",
284
+ inputSchema: {
285
+ type: "object",
286
+ properties: {},
287
+ additionalProperties: false
288
+ },
289
+ handler: async (input) => {
290
+ empty(input);
291
+ const status = projectBillingStatus(await readers.status());
292
+ return result(`${status.credits.remaining} service credits available, ${status.credits.reserved} reserved. Portal access: ${status.portalAccess ? "enabled" : "not enabled"}. Automatic refill is off.`, status);
293
+ }
294
+ },
295
+ list_receipts: {
296
+ annotations: {
297
+ readOnlyHint: true,
298
+ destructiveHint: false,
299
+ openWorldHint: false
300
+ },
301
+ commerce: {
302
+ action: "entitlement_status",
303
+ categories: ["usage_credits", "subscription"]
304
+ },
305
+ description: "List this account's payment receipts, newest first, with original amounts and refunds recorded to date. Amounts are currency minor units, not consumed credits. Follow nextCursor for more. No payment credentials or provider references are exposed.",
306
+ inputSchema: {
307
+ type: "object",
308
+ properties: {
309
+ limit: { type: "integer", minimum: 1, maximum: 50, default: 20 },
310
+ cursor: { type: ["string", "null"], maxLength: 256 }
311
+ },
312
+ additionalProperties: false
313
+ },
314
+ handler: async (input) => {
315
+ const request = parseReceiptPage(input);
316
+ const page = projectReceiptPage(await readers.receipts(request), request.limit);
317
+ return result(`${page.receipts.length} receipts.${page.nextCursor ? " More receipts are available using nextCursor." : ""}`, page);
318
+ }
319
+ },
320
+ get_usage_report: {
321
+ annotations: {
322
+ readOnlyHint: true,
323
+ destructiveHint: false,
324
+ openWorldHint: false
325
+ },
326
+ commerce: { action: "entitlement_status", categories: ["usage_credits"] },
327
+ description: "Read recorded service-credit consumption by UTC day and feature. from is inclusive and to is exclusive; at most 90 days, default last 30 days including today. Credits consumed are not dollars paid or the assistant's own tokens. Does not estimate ROI or expose internal provider costs.",
328
+ inputSchema: {
329
+ type: "object",
330
+ properties: {
331
+ from: { type: "string", format: "date" },
332
+ to: { type: "string", format: "date" }
333
+ },
334
+ additionalProperties: false
335
+ },
336
+ handler: async (input) => {
337
+ const range = parseUsageRange(input, readers.now?.());
338
+ const usage = projectUsageReport(await readers.usage(range), range);
339
+ return result(`${usage.creditsConsumed} service credits across ${usage.events} recorded events, ${range.from} inclusive to ${range.to} exclusive (UTC).`, usage);
340
+ }
341
+ }
342
+ });
343
+ var createBillingManagementTool = (destination) => {
344
+ const url = new URL(destination);
345
+ if (url.protocol !== "https:" || url.username || url.password || url.search || url.hash)
346
+ throw new Error("Billing management requires a fixed HTTPS page URL");
347
+ return {
348
+ annotations: {
349
+ readOnlyHint: true,
350
+ destructiveHint: false,
351
+ openWorldHint: true
352
+ },
353
+ commerce: {
354
+ action: "external_checkout",
355
+ categories: ["usage_credits", "subscription"]
356
+ },
357
+ description: "Open the service's authenticated billing page to buy credits, review receipts, or manage an existing subscription. Uses a matching browser login; may require sign-in. This link does not grant a login session or authorize any payment.",
358
+ inputSchema: {
359
+ type: "object",
360
+ properties: {},
361
+ additionalProperties: false
362
+ },
363
+ handler: async (input) => {
364
+ empty(input);
365
+ return result(`Manage billing on ${url.hostname}: ${url.href}. Sign in if needed; changes require your confirmation.`, { url: url.href, requiresBrowserAuthentication: true });
366
+ }
367
+ };
368
+ };
148
369
 
149
370
  // src/commerce.ts
150
371
  var COMMERCE_POLICY_VERSION = "2026-09-10.1";
@@ -254,6 +475,8 @@ var evaluateCommerce = (req, context, now = new Date) => {
254
475
  export {
255
476
  COMMERCE_POLICY_SOURCES,
256
477
  COMMERCE_POLICY_VERSION,
478
+ createBillingManagementTool,
479
+ createBillingReportTools,
257
480
  createCheckoutHandoffTool,
258
481
  createCreditBalanceTool,
259
482
  createPurchaseStatusTool,