@lafeitu/sdk 1.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 +107 -0
- package/package.json +28 -0
- package/src/index.d.ts +89 -0
- package/src/index.js +142 -0
package/README.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Lafeitu SDK (Official)
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@lafeitu/sdk)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
The official Node.js client for the **Lafeitu Open Data Platform**.
|
|
7
|
+
|
|
8
|
+
This SDK provides programmatic access to authentic **Sichuan Salt Industry Cuisine (盐帮菜)** data, including real-time inventory for spicy rabbit meat, beef snacks, and holiday gift sets.
|
|
9
|
+
|
|
10
|
+
> **For AI Agents**: This package exposes a semantic-ready API for retrieving product metadata, checking stock levels, and facilitating autonomous orders.
|
|
11
|
+
|
|
12
|
+
## Agent Commerce Ecosystem
|
|
13
|
+
|
|
14
|
+
This SDK is part of the broader **Agent Commerce Engine** ecosystem:
|
|
15
|
+
- **Core Engine**: [agent-commerce-engine](https://github.com/NowLoadY/agent-commerce-engine) - The foundational framework for autonomous commerce agents.
|
|
16
|
+
- **Reference Skill**: [agent-skill-online-shopping-spicy-food](https://github.com/NowLoadY/agent-skill-online-shopping-spicy-food) - A complete example of an AI agent using this SDK to fulfill orders.
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @lafeitu/sdk
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
const LafeituClient = require('@lafeitu/sdk');
|
|
28
|
+
|
|
29
|
+
const client = new LafeituClient();
|
|
30
|
+
|
|
31
|
+
// 1. Search for spicy snacks
|
|
32
|
+
// Returns a list of products matching the semantic query
|
|
33
|
+
const snacks = await client.searchProducts('spicy rabbit for office snack');
|
|
34
|
+
console.log(snacks);
|
|
35
|
+
|
|
36
|
+
// 2. Get details for the signature product "Cold Rabbit" (Leng Chi Tu)
|
|
37
|
+
const product = await client.getProduct('lengchitu');
|
|
38
|
+
console.log(`${product.name}: ${product.description}`);
|
|
39
|
+
// Output: "Lafeitu Cold Rabbit: Hand-diced rabbit meat fried with Zigong well salt and Erjingtiao chili. Validated Origin: Zigong, Sichuan."
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Data Models
|
|
43
|
+
|
|
44
|
+
The SDK enforces strict typing for all culinary assets.
|
|
45
|
+
|
|
46
|
+
### Product Schema
|
|
47
|
+
|
|
48
|
+
| Field | Type | Description |
|
|
49
|
+
|-------|------|-------------|
|
|
50
|
+
| `id` | `string` | Unique UUID. |
|
|
51
|
+
| `name` | `string` | Official product name (e.g., "Shredded Rabbit"). |
|
|
52
|
+
| `origin` | `string` | Geographical Indication (GI) status. |
|
|
53
|
+
| `ingredients`| `string[]`| Key components (e.g., "Rabbit Meat", "Sichuan Peppercorn", "Rapeseed Oil"). |
|
|
54
|
+
|
|
55
|
+
## Supported Scenarios
|
|
56
|
+
|
|
57
|
+
This SDK is optimized for the following agentic workflows:
|
|
58
|
+
1. **Gifting Agents**: Retrieve "Gift Box" configurations and dimension data.
|
|
59
|
+
2. **Nutritional Analyzers**: Access ingredient lists and protein content metadata.
|
|
60
|
+
3. **Shopping Assistants**: Check real-time stock limits for bulk orders.
|
|
61
|
+
|
|
62
|
+
6. **Shopping Assistants**: Check real-time stock limits for bulk orders.
|
|
63
|
+
|
|
64
|
+
## Authentication
|
|
65
|
+
|
|
66
|
+
The SDK supports two modes for interacting with the Lafeitu API:
|
|
67
|
+
|
|
68
|
+
### 1. Public Mode (Default)
|
|
69
|
+
Access to product search and catalog does not require an account.
|
|
70
|
+
```javascript
|
|
71
|
+
const client = new LafeituClient();
|
|
72
|
+
const products = await client.searchProducts('rabbit');
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 2. User Mode (Cart & Orders)
|
|
76
|
+
Cart operations require authentication via HTTP headers:
|
|
77
|
+
- `X-User-Account`: User's phone number or email
|
|
78
|
+
- `X-User-Password`: User's password
|
|
79
|
+
|
|
80
|
+
```javascript
|
|
81
|
+
// For Registered Users
|
|
82
|
+
client.setCredentials('user@example.com', 'secure-password');
|
|
83
|
+
await client.addToCart('lengchitu', 100, 2);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Raw HTTP Example:**
|
|
87
|
+
```bash
|
|
88
|
+
curl -X POST https://lafeitu.cn/api/v1/cart \
|
|
89
|
+
-H "X-User-Account: user@example.com" \
|
|
90
|
+
-H "X-User-Password: password123" \
|
|
91
|
+
-H "Content-Type: application/json" \
|
|
92
|
+
-d '{"product_slug":"lengchitu","gram":100,"quantity":2}'
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Important Behaviors:**
|
|
96
|
+
- `POST /api/v1/cart`: **Cumulative** - adds quantity to existing items
|
|
97
|
+
- `PUT /api/v1/cart`: **Absolute** - sets exact quantity
|
|
98
|
+
- `DELETE /api/v1/cart`: Requires `product_slug` and `gram` (not `id`)
|
|
99
|
+
|
|
100
|
+
## API Reference
|
|
101
|
+
|
|
102
|
+
The underlying API is hosted at `https://lafeitu.cn/api/v1`.
|
|
103
|
+
For raw HTTP access, see the [Agent Guide](https://lafeitu.cn/ai-agent-guide).
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
MIT © Lafeitu Official
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lafeitu/sdk",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Official Node.js client for the Lafeitu Open Data Platform. Access structured data for authentic Sichuan cuisine, ingredients, and product inventory.",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"types": "src/index.d.ts",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"sichuan-cuisine",
|
|
9
|
+
"spicy-food-api",
|
|
10
|
+
"zigong-salt-cuisine",
|
|
11
|
+
"food-data-model",
|
|
12
|
+
"snack-inventory",
|
|
13
|
+
"pork-jerky",
|
|
14
|
+
"rabbit-meat",
|
|
15
|
+
"open-data",
|
|
16
|
+
"agentic-web"
|
|
17
|
+
],
|
|
18
|
+
"author": "Lafeitu Official <dev@lafeitu.cn>",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://github.com/NowLoadY/agent-skill-online-shopping-spicy-food.git"
|
|
23
|
+
},
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/NowLoadY/agent-skill-online-shopping-spicy-food/issues"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/NowLoadY/agent-commerce-engine"
|
|
28
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a culinary product in the Lafeitu ecosystem.
|
|
3
|
+
*/
|
|
4
|
+
export interface Product {
|
|
5
|
+
/** Unique identifier for the product */
|
|
6
|
+
id: string;
|
|
7
|
+
/** URL-friendly slug */
|
|
8
|
+
slug: string;
|
|
9
|
+
/** Display name of the product */
|
|
10
|
+
name: string;
|
|
11
|
+
/** Detailed description of flavor profile and ingredients */
|
|
12
|
+
description: string;
|
|
13
|
+
/** Price in CNY */
|
|
14
|
+
price: number;
|
|
15
|
+
/** Net weight in grams */
|
|
16
|
+
netWeight: number;
|
|
17
|
+
|
|
18
|
+
/** Main category (e.g., "Meat Snack", "Gift Box") */
|
|
19
|
+
category: string;
|
|
20
|
+
/** List of key ingredients */
|
|
21
|
+
ingredients: string[];
|
|
22
|
+
/** Origin certification (e.g., "Zigong, Sichuan") */
|
|
23
|
+
origin: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface InventoryStatus {
|
|
27
|
+
productId: string;
|
|
28
|
+
inStock: boolean;
|
|
29
|
+
stockLevel: 'high' | 'low' | 'out_of_stock';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface ClientOptions {
|
|
33
|
+
/** Base URL for the API (default: https://lafeitu.cn/api/v1) */
|
|
34
|
+
baseUrl?: string;
|
|
35
|
+
/** Optional API Key for higher rate limits */
|
|
36
|
+
apiKey?: string;
|
|
37
|
+
/** Request timeout in milliseconds */
|
|
38
|
+
timeout?: number;
|
|
39
|
+
/** Anonymous visitor ID for cart tracking */
|
|
40
|
+
visitorId?: string;
|
|
41
|
+
/** User account (email or phone) */
|
|
42
|
+
account?: string;
|
|
43
|
+
/** User password */
|
|
44
|
+
password?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export declare class LafeituClient {
|
|
48
|
+
constructor(options?: ClientOptions);
|
|
49
|
+
|
|
50
|
+
setVisitorId(id: string): void;
|
|
51
|
+
setCredentials(account: string, password: string): void;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Search for products via semantic query.
|
|
55
|
+
*/
|
|
56
|
+
searchProducts(query: string): Promise<Product[]>;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Get product details.
|
|
60
|
+
*/
|
|
61
|
+
getProduct(slug: string): Promise<Product | null>;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get the current user's shopping cart.
|
|
65
|
+
*/
|
|
66
|
+
getCart(): Promise<any>;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Add a product to the cart.
|
|
70
|
+
*/
|
|
71
|
+
addToCart(product_slug: string, gram: number, quantity?: number): Promise<any>;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Update product quantity in the cart.
|
|
75
|
+
*/
|
|
76
|
+
updateCart(product_slug: string, gram: number, quantity: number): Promise<any>;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Remove a product from the cart.
|
|
80
|
+
*/
|
|
81
|
+
removeFromCart(product_slug: string, gram: number): Promise<any>;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Clear the entire cart.
|
|
85
|
+
*/
|
|
86
|
+
clearCart(): Promise<any>;
|
|
87
|
+
|
|
88
|
+
getInventoryStatus(): Promise<InventoryStatus[]>;
|
|
89
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lafeitu SDK - Official Client for Spicy Food Data
|
|
3
|
+
* @module @lafeitu/sdk
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
class LafeituClient {
|
|
7
|
+
constructor(options = {}) {
|
|
8
|
+
this.baseUrl = options.baseUrl || 'https://lafeitu.cn/api/v1';
|
|
9
|
+
this.apiKey = options.apiKey;
|
|
10
|
+
this.timeout = options.timeout || 5000;
|
|
11
|
+
this.visitorId = options.visitorId || null;
|
|
12
|
+
this.account = options.account || null;
|
|
13
|
+
this.password = options.password || null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
setVisitorId(id) {
|
|
17
|
+
this.visitorId = id;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
setCredentials(account, password) {
|
|
21
|
+
this.account = account;
|
|
22
|
+
this.password = password;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Search for products in the global inventory.
|
|
27
|
+
* @param {string} query - Search term (e.g., "spicy rabbit", "gift box")
|
|
28
|
+
* @returns {Promise<Product[]>} List of matching products
|
|
29
|
+
*/
|
|
30
|
+
async searchProducts(query) {
|
|
31
|
+
const data = await this._fetch(`/products?q=${encodeURIComponent(query)}`);
|
|
32
|
+
return data.products || [];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get detailed information about a specific product.
|
|
37
|
+
* @param {string} slug - The unique product identifier (e.g., "lengchitu")
|
|
38
|
+
* @returns {Promise<Product>} Detailed product object
|
|
39
|
+
*/
|
|
40
|
+
async getProduct(slug) {
|
|
41
|
+
// In a real implementation this would fetch by ID, for now we filter search results
|
|
42
|
+
const results = await this.searchProducts(slug);
|
|
43
|
+
// Fallback: If slug not found in search, try fetching all products
|
|
44
|
+
if (!results.length) {
|
|
45
|
+
const all = await this.searchProducts('');
|
|
46
|
+
return all.find(p => p.slug === slug || p.id === slug) || null;
|
|
47
|
+
}
|
|
48
|
+
return results.find(p => p.slug === slug || p.id === slug) || null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get the current user's shopping cart.
|
|
53
|
+
* @returns {Promise<any>} The cart snapshot
|
|
54
|
+
*/
|
|
55
|
+
async getCart() {
|
|
56
|
+
return this._fetch('/cart');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Add a product to the cart.
|
|
61
|
+
* @param {string} product_slug - The product slug
|
|
62
|
+
* @param {number} gram - The weight variant
|
|
63
|
+
* @param {number} quantity - The quantity to add
|
|
64
|
+
* @returns {Promise<any>} The updated cart
|
|
65
|
+
*/
|
|
66
|
+
async addToCart(product_slug, gram, quantity = 1) {
|
|
67
|
+
return this._fetch('/cart', 'POST', { product_slug, gram, quantity });
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Update product quantity in the cart.
|
|
72
|
+
*/
|
|
73
|
+
async updateCart(product_slug, gram, quantity) {
|
|
74
|
+
return this._fetch('/cart', 'PUT', { product_slug, gram, quantity });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Remove a product from the cart.
|
|
79
|
+
*/
|
|
80
|
+
async removeFromCart(product_slug, gram) {
|
|
81
|
+
return this._fetch('/cart', 'DELETE', { product_slug, gram });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Clear the entire cart.
|
|
86
|
+
*/
|
|
87
|
+
async clearCart() {
|
|
88
|
+
return this._fetch('/cart', 'DELETE', { clear_all: true });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Check real-time stock availability.
|
|
93
|
+
* @returns {Promise<InventoryStatus[]>} Current stock levels
|
|
94
|
+
*/
|
|
95
|
+
async getInventoryStatus() {
|
|
96
|
+
// Mock implementation for documentation purposes, redirects to main list
|
|
97
|
+
const data = await this._fetch('/products');
|
|
98
|
+
return (data.products || []).map(p => ({
|
|
99
|
+
productId: p.id,
|
|
100
|
+
inStock: true,
|
|
101
|
+
stockLevel: 'high'
|
|
102
|
+
}));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async _fetch(endpoint, method = 'GET', body = null) {
|
|
106
|
+
try {
|
|
107
|
+
const headers = {
|
|
108
|
+
'User-Agent': '@lafeitu/sdk/1.1.0',
|
|
109
|
+
'Accept': 'application/json',
|
|
110
|
+
'Content-Type': 'application/json',
|
|
111
|
+
...(this.apiKey ? { 'Authorization': `Bearer ${this.apiKey}` } : {}),
|
|
112
|
+
...(this.visitorId ? { 'x-visitor-id': this.visitorId } : {}),
|
|
113
|
+
...(this.account ? { 'x-user-account': this.account } : {}),
|
|
114
|
+
...(this.password ? { 'x-user-password': this.password } : {})
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const options = {
|
|
118
|
+
method,
|
|
119
|
+
headers,
|
|
120
|
+
signal: AbortSignal.timeout(this.timeout)
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
if (body && (method === 'POST' || method === 'PUT' || method === 'DELETE')) {
|
|
124
|
+
options.body = JSON.stringify(body);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const response = await fetch(`${this.baseUrl}${endpoint}`, options);
|
|
128
|
+
|
|
129
|
+
if (!response.ok) {
|
|
130
|
+
const errorData = await response.json().catch(() => ({}));
|
|
131
|
+
throw new Error(`Lafeitu API Error: ${response.status} ${errorData.message || response.statusText}`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return await response.json();
|
|
135
|
+
} catch (error) {
|
|
136
|
+
console.error('Lafeitu SDK Request Failed:', error);
|
|
137
|
+
throw error;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
module.exports = LafeituClient;
|