autocart-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.
Files changed (4) hide show
  1. package/README.md +61 -0
  2. package/index.d.ts +14 -0
  3. package/index.js +136 -0
  4. package/package.json +1 -0
package/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # @autocart/sdk
2
+
3
+ The official Node.js SDK for the AutoCart Agentic Commerce Platform.
4
+
5
+ This SDK allows you to instantly expose your existing e-commerce inventory to autonomous AI Buyers, while enforcing strict, cryptographic spending policies and risk-tier firewalls to protect your revenue.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @autocart/sdk
11
+ ```
12
+
13
+ ## Quick Start Integration
14
+
15
+ You do not need to change your database structure to use AutoCart. You simply provide a `fetchCatalog` adapter function that maps your existing database fields to the standard AutoCart format (`sku`, `name`, `price`, `stock`).
16
+
17
+ ```javascript
18
+ import express from 'express';
19
+ import { AutoCartGateway } from '@autocart/sdk';
20
+
21
+ const app = express();
22
+
23
+ // Initialize the Gateway
24
+ const autocart = new AutoCartGateway({
25
+ merchantKey: 'YOUR_MERCHANT_KEY', // Generated in the AutoCart Portal
26
+ merchantSecret: 'YOUR_MERCHANT_SECRET', // Keep this safe!
27
+
28
+ // The Adapter Function: Translate your DB format to the AutoCart format
29
+ fetchCatalog: async () => {
30
+ // 1. Fetch data from your specific database (SQL, MongoDB, Shopify, etc.)
31
+ const myRawInventory = await myCustomDatabase.getProducts();
32
+
33
+ // 2. Map your custom fields to the strict AutoCart schema
34
+ return myRawInventory.map(product => ({
35
+ sku: product.item_id, // Must be a unique string
36
+ name: product.product_title, // String
37
+ price: product.price_in_inr, // Number (e.g., 4500)
38
+ stock: product.inventory_qty, // Number (e.g., 10)
39
+
40
+ // Optional: Add a short description to help the AI make decisions
41
+ description: product.short_desc
42
+ }));
43
+ }
44
+ });
45
+
46
+ // Mount the SDK on your Express server
47
+ app.use('/api/ai-store', autocart.createRouter());
48
+
49
+ app.listen(3000, () => {
50
+ console.log('AI-Ready Storefront running on port 3000');
51
+ });
52
+ ```
53
+
54
+ ## How It Works
55
+
56
+ By mounting `autocart.createRouter()`, the SDK automatically generates two endpoints on your server:
57
+
58
+ 1. **`GET /api/ai-store/catalog`**: A highly optimized, token-lean JSON endpoint that AI Scout Agents query to compare prices and check stock.
59
+ 2. **`POST /api/ai-store/checkout`**: The Policy Firewall interceptor. When an AI attempts a purchase, this endpoint verifies the price against your live DB, cryptographically signs the payload, and pings the AutoCart Trust Engine to ensure the human buyer has approved the budget.
60
+
61
+ For support, visit [merchants.autocart.com](https://autocart.com).
package/index.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import { Router } from 'express';
2
+
3
+ export interface AutoCartConfig {
4
+ merchantKey: string;
5
+ merchantSecret: string;
6
+ nexusUrl?: string;
7
+ fetchCatalog?: () => Promise<Array<{ sku: string; name: string; price: number; stock: number }>>;
8
+ fetchProduct: (sku: string) => Promise<{ sku: string; price: number; stock: number } | null>;
9
+ }
10
+
11
+ export class AutoCartGateway {
12
+ constructor(config: AutoCartConfig);
13
+ createRouter(): Router;
14
+ }
package/index.js ADDED
@@ -0,0 +1,136 @@
1
+ import express from 'express';
2
+ import crypto from 'crypto';
3
+
4
+
5
+ export class AutoCartGateway {
6
+ constructor(config) {
7
+ if (!config.merchantKey || !config.merchantSecret || !config.fetchProduct) {
8
+ throw new Error('AutoCartGateway requires merchantKey, merchantSecret, and fetchProduct');
9
+ }
10
+ this.merchantKey = config.merchantKey;
11
+ this.merchantSecret = config.merchantSecret;
12
+ this.fetchCatalog = config.fetchCatalog; // Optional for legacy/indexing
13
+ this.fetchProduct = config.fetchProduct;
14
+ this.nexusUrl = config.nexusUrl || 'http://localhost:5000';
15
+ }
16
+
17
+ _signPayload(payload) {
18
+ return crypto
19
+ .createHmac('sha256', this.merchantSecret)
20
+ .update(JSON.stringify(payload))
21
+ .digest('hex');
22
+ }
23
+
24
+ createRouter() {
25
+ const router = express.Router();
26
+ router.use(express.json());
27
+
28
+ router.get('/catalog', async (req, res) => {
29
+ try {
30
+ if (!this.fetchCatalog) {
31
+ return res.status(501).json({ error: 'Merchant does not support full catalog fetching' });
32
+ }
33
+ const fullCatalog = await this.fetchCatalog();
34
+ const leanCatalog = fullCatalog.map(item => ({
35
+ sku: item.sku,
36
+ n: item.name,
37
+ p: item.price,
38
+ s: item.stock
39
+ }));
40
+ res.json({ catalog: leanCatalog });
41
+ } catch (err) {
42
+ res.status(500).json({ error: 'Failed to fetch catalog' });
43
+ }
44
+ });
45
+
46
+ router.post('/checkout', async (req, res) => {
47
+ try {
48
+ const { sku, qty, idempotencyKey, maxAuthorizedAmount } = req.body;
49
+ const buyerKey = req.headers['x-buyer-key'];
50
+
51
+ if (!buyerKey || !sku || !qty || !idempotencyKey) {
52
+ return res.status(400).json({ error: 'Missing required checkout fields or x-buyer-key header' });
53
+ }
54
+
55
+ const product = await this.fetchProduct(sku);
56
+
57
+ if (!product) {
58
+ return res.status(404).json({ error: 'Product SKU not found in merchant catalog' });
59
+ }
60
+ if (product.stock < qty) {
61
+ return res.status(409).json({ error: 'Insufficient stock' });
62
+ }
63
+
64
+ const lineTotal = product.price * qty;
65
+
66
+ const enginePayload = {
67
+ merchantKey: this.merchantKey,
68
+ buyerKey,
69
+ sku,
70
+ qty,
71
+ lineTotal,
72
+ idempotencyKey,
73
+ maxAuthorizedAmount
74
+ };
75
+
76
+ const signature = this._signPayload(enginePayload);
77
+
78
+ const response = await fetch(`${this.nexusUrl}/api/engine/verify-intent`, {
79
+ method: 'POST',
80
+ headers: {
81
+ 'Content-Type': 'application/json',
82
+ 'x-autocart-signature': signature
83
+ },
84
+ body: JSON.stringify(enginePayload)
85
+ });
86
+
87
+ const engineResult = await response.json();
88
+
89
+ if (!response.ok) {
90
+ return res.status(response.status).json(engineResult);
91
+ }
92
+
93
+ if (engineResult.status !== 'AUTO_APPROVED') {
94
+ return res.status(200).json({
95
+ status: engineResult.status,
96
+ message: 'Transaction requires human approval or is blocked.',
97
+ auditId: engineResult.auditId
98
+ });
99
+ }
100
+
101
+ // Simulating the Webhook since headless payments aren't tokenized in this demo
102
+ await fetch(`${this.nexusUrl}/api/webhook/razorpay`, {
103
+ method: 'POST',
104
+ headers: {
105
+ 'Content-Type': 'application/json',
106
+ 'x-razorpay-signature': 'test-webhook-bypass'
107
+ },
108
+ body: JSON.stringify({
109
+ event: 'payment.captured',
110
+ payload: {
111
+ payment: {
112
+ entity: {
113
+ id: 'pay_sdk_auto',
114
+ order_id: engineResult.razorpayOrderId
115
+ }
116
+ }
117
+ }
118
+ })
119
+ });
120
+
121
+ return res.status(200).json({
122
+ status: 'PAYMENT_CAPTURED',
123
+ razorpayOrderId: engineResult.razorpayOrderId,
124
+ auditId: engineResult.auditId,
125
+ receipt: `Paid ${lineTotal} INR`
126
+ });
127
+
128
+ } catch (err) {
129
+ console.error('[AutoCart SDK] Checkout Error:', err.message);
130
+ res.status(500).json({ error: 'SDK Checkout processing failed' });
131
+ }
132
+ });
133
+
134
+ return router;
135
+ }
136
+ }
package/package.json ADDED
@@ -0,0 +1 @@
1
+ {"name":"autocart-sdk","version":"1.0.0","type":"module","main":"index.js","dependencies":{"axios":"^1.19.0","express":"^5.2.1"}}