truss-shopify-mcp 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/LICENSE +21 -0
- package/README.md +89 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +106 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/ai-content.d.ts +7 -0
- package/dist/lib/ai-content.d.ts.map +1 -0
- package/dist/lib/ai-content.js +111 -0
- package/dist/lib/ai-content.js.map +1 -0
- package/dist/lib/analytics.d.ts +8 -0
- package/dist/lib/analytics.d.ts.map +1 -0
- package/dist/lib/analytics.js +190 -0
- package/dist/lib/analytics.js.map +1 -0
- package/dist/lib/config.d.ts +5 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +29 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/license.d.ts +4 -0
- package/dist/lib/license.d.ts.map +1 -0
- package/dist/lib/license.js +94 -0
- package/dist/lib/license.js.map +1 -0
- package/dist/lib/shopify-client.d.ts +30 -0
- package/dist/lib/shopify-client.d.ts.map +1 -0
- package/dist/lib/shopify-client.js +156 -0
- package/dist/lib/shopify-client.js.map +1 -0
- package/dist/lib/usage.d.ts +10 -0
- package/dist/lib/usage.d.ts.map +1 -0
- package/dist/lib/usage.js +55 -0
- package/dist/lib/usage.js.map +1 -0
- package/dist/tools/create-product.d.ts +3 -0
- package/dist/tools/create-product.d.ts.map +1 -0
- package/dist/tools/create-product.js +106 -0
- package/dist/tools/create-product.js.map +1 -0
- package/dist/tools/fulfill-order.d.ts +3 -0
- package/dist/tools/fulfill-order.d.ts.map +1 -0
- package/dist/tools/fulfill-order.js +89 -0
- package/dist/tools/fulfill-order.js.map +1 -0
- package/dist/tools/generate-description.d.ts +3 -0
- package/dist/tools/generate-description.d.ts.map +1 -0
- package/dist/tools/generate-description.js +47 -0
- package/dist/tools/generate-description.js.map +1 -0
- package/dist/tools/get-order.d.ts +3 -0
- package/dist/tools/get-order.d.ts.map +1 -0
- package/dist/tools/get-order.js +94 -0
- package/dist/tools/get-order.js.map +1 -0
- package/dist/tools/get-product.d.ts +3 -0
- package/dist/tools/get-product.d.ts.map +1 -0
- package/dist/tools/get-product.js +92 -0
- package/dist/tools/get-product.js.map +1 -0
- package/dist/tools/list-orders.d.ts +3 -0
- package/dist/tools/list-orders.d.ts.map +1 -0
- package/dist/tools/list-orders.js +83 -0
- package/dist/tools/list-orders.js.map +1 -0
- package/dist/tools/list-products.d.ts +3 -0
- package/dist/tools/list-products.d.ts.map +1 -0
- package/dist/tools/list-products.js +76 -0
- package/dist/tools/list-products.js.map +1 -0
- package/dist/tools/sales-report.d.ts +3 -0
- package/dist/tools/sales-report.d.ts.map +1 -0
- package/dist/tools/sales-report.js +66 -0
- package/dist/tools/sales-report.js.map +1 -0
- package/dist/tools/store-analytics.d.ts +3 -0
- package/dist/tools/store-analytics.d.ts.map +1 -0
- package/dist/tools/store-analytics.js +73 -0
- package/dist/tools/store-analytics.js.map +1 -0
- package/dist/tools/update-inventory.d.ts +3 -0
- package/dist/tools/update-inventory.d.ts.map +1 -0
- package/dist/tools/update-inventory.js +103 -0
- package/dist/tools/update-inventory.js.map +1 -0
- package/dist/types.d.ts +268 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/evals/eval-analytics.ts +188 -0
- package/evals/eval-products.ts +281 -0
- package/evals/eval-rate-limit.ts +139 -0
- package/evals/run-evals.ts +66 -0
- package/glama.json +4 -0
- package/package.json +38 -0
- package/smithery.yaml +17 -0
- package/src/index.ts +132 -0
- package/src/lib/ai-content.ts +143 -0
- package/src/lib/analytics.ts +231 -0
- package/src/lib/config.ts +33 -0
- package/src/lib/license.ts +118 -0
- package/src/lib/shopify-client.ts +189 -0
- package/src/lib/usage.ts +69 -0
- package/src/tools/create-product.ts +128 -0
- package/src/tools/fulfill-order.ts +115 -0
- package/src/tools/generate-description.ts +61 -0
- package/src/tools/get-order.ts +109 -0
- package/src/tools/get-product.ts +109 -0
- package/src/tools/list-orders.ts +101 -0
- package/src/tools/list-products.ts +93 -0
- package/src/tools/sales-report.ts +81 -0
- package/src/tools/store-analytics.ts +91 -0
- package/src/tools/update-inventory.ts +139 -0
- package/src/types.ts +302 -0
- package/tsconfig.json +19 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 TRUSS
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# TRUSS Shopify Operations Hub
|
|
2
|
+
|
|
3
|
+
MCP server for managing Shopify stores from Claude Code. List products, track orders, update inventory, fulfill shipments, generate AI descriptions, and analyze sales — all from your AI coding assistant.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
### 1. Create a Shopify Custom App
|
|
8
|
+
|
|
9
|
+
1. Go to **Shopify Admin > Settings > Apps and sales channels > Develop apps**
|
|
10
|
+
2. Click **Create an app**
|
|
11
|
+
3. Under **Configuration > Admin API integration**, enable these scopes:
|
|
12
|
+
- `read_products`, `write_products`
|
|
13
|
+
- `read_orders`, `write_orders`
|
|
14
|
+
- `read_inventory`, `write_inventory`
|
|
15
|
+
- `read_locations`
|
|
16
|
+
- `read_fulfillments`, `write_fulfillments`
|
|
17
|
+
4. Click **Install app** and copy the **Admin API access token**
|
|
18
|
+
|
|
19
|
+
### 2. Configure Claude Code
|
|
20
|
+
|
|
21
|
+
Add to your Claude Code MCP settings (`~/.claude/settings.json` or project-level):
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"mcpServers": {
|
|
26
|
+
"shopify": {
|
|
27
|
+
"command": "node",
|
|
28
|
+
"args": ["/path/to/shopify-mcp/dist/index.js"],
|
|
29
|
+
"env": {
|
|
30
|
+
"SHOPIFY_STORE": "your-store-subdomain",
|
|
31
|
+
"SHOPIFY_ACCESS_TOKEN": "shpat_..."
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 3. Build
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install
|
|
42
|
+
npm run build
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Tools
|
|
46
|
+
|
|
47
|
+
### Free Tier (10 operations/day)
|
|
48
|
+
|
|
49
|
+
| Tool | Description |
|
|
50
|
+
|------|-------------|
|
|
51
|
+
| `shopify_status` | Check connection status and license tier |
|
|
52
|
+
| `list_products` | List products with status/collection/vendor filters |
|
|
53
|
+
| `get_product` | Full product details with variants, images, metafields |
|
|
54
|
+
| `list_orders` | Recent orders with status and date filters |
|
|
55
|
+
| `get_order` | Full order details with line items, customer, fulfillment |
|
|
56
|
+
| `store_analytics` | Revenue, order count, top products, AOV |
|
|
57
|
+
|
|
58
|
+
### Pro Tier ($25/mo)
|
|
59
|
+
|
|
60
|
+
| Tool | Description |
|
|
61
|
+
|------|-------------|
|
|
62
|
+
| `create_product` | Create products with variants and images |
|
|
63
|
+
| `update_inventory` | Bulk update inventory levels |
|
|
64
|
+
| `fulfill_order` | Create fulfillments with tracking |
|
|
65
|
+
| `generate_description` | AI-powered product descriptions |
|
|
66
|
+
| `sales_report` | Detailed analytics with period comparisons |
|
|
67
|
+
|
|
68
|
+
## Environment Variables
|
|
69
|
+
|
|
70
|
+
| Variable | Required | Description |
|
|
71
|
+
|----------|----------|-------------|
|
|
72
|
+
| `SHOPIFY_STORE` | Yes | Store subdomain (e.g., `my-store` from `my-store.myshopify.com`) |
|
|
73
|
+
| `SHOPIFY_ACCESS_TOKEN` | Yes | Admin API access token from your custom app |
|
|
74
|
+
| `TRUSS_LICENSE_KEY` | No | Pro license key for write operations |
|
|
75
|
+
| `ANTHROPIC_API_KEY` | No | For AI description generation (preferred) |
|
|
76
|
+
| `OPENAI_API_KEY` | No | For AI description generation (fallback) |
|
|
77
|
+
|
|
78
|
+
## Rate Limiting
|
|
79
|
+
|
|
80
|
+
The Shopify Admin API uses a leaky bucket algorithm (40 requests/minute). This server handles rate limiting automatically:
|
|
81
|
+
|
|
82
|
+
- Tracks bucket state from `X-Shopify-Shop-Api-Call-Limit` headers
|
|
83
|
+
- Pre-flight checks to avoid hitting limits
|
|
84
|
+
- Automatic retry on 429 responses with `Retry-After` header respect
|
|
85
|
+
- Maximum 3 retries before failing
|
|
86
|
+
|
|
87
|
+
## License
|
|
88
|
+
|
|
89
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
// Tool registrations — Free Tier
|
|
5
|
+
import { registerListProducts } from './tools/list-products.js';
|
|
6
|
+
import { registerGetProduct } from './tools/get-product.js';
|
|
7
|
+
import { registerListOrders } from './tools/list-orders.js';
|
|
8
|
+
import { registerGetOrder } from './tools/get-order.js';
|
|
9
|
+
import { registerStoreAnalytics } from './tools/store-analytics.js';
|
|
10
|
+
// Tool registrations — Pro Tier
|
|
11
|
+
import { registerCreateProduct } from './tools/create-product.js';
|
|
12
|
+
import { registerUpdateInventory } from './tools/update-inventory.js';
|
|
13
|
+
import { registerFulfillOrder } from './tools/fulfill-order.js';
|
|
14
|
+
import { registerGenerateDescription } from './tools/generate-description.js';
|
|
15
|
+
import { registerSalesReport } from './tools/sales-report.js';
|
|
16
|
+
// Lib
|
|
17
|
+
import { getLicenseStatus } from './lib/license.js';
|
|
18
|
+
import { validateShopifyConfig } from './lib/shopify-client.js';
|
|
19
|
+
import { closeDb } from './lib/usage.js';
|
|
20
|
+
const server = new McpServer({
|
|
21
|
+
name: '@truss-dev/shopify-mcp',
|
|
22
|
+
version: '1.0.0',
|
|
23
|
+
});
|
|
24
|
+
// ── Status Tool ─────────────────────────────────────────────────────
|
|
25
|
+
server.tool('shopify_status', 'Check Shopify connection status, store config, and license tier.', {}, async () => {
|
|
26
|
+
const configCheck = validateShopifyConfig();
|
|
27
|
+
const license = await getLicenseStatus();
|
|
28
|
+
return {
|
|
29
|
+
content: [
|
|
30
|
+
{
|
|
31
|
+
type: 'text',
|
|
32
|
+
text: JSON.stringify({
|
|
33
|
+
shopify: {
|
|
34
|
+
configured: configCheck.valid,
|
|
35
|
+
...(configCheck.valid
|
|
36
|
+
? { store: process.env.SHOPIFY_STORE }
|
|
37
|
+
: { error: configCheck.error }),
|
|
38
|
+
setup_instructions: !configCheck.valid
|
|
39
|
+
? {
|
|
40
|
+
step_1: 'Go to your Shopify admin > Settings > Apps and sales channels > Develop apps',
|
|
41
|
+
step_2: 'Create a custom app with Admin API access',
|
|
42
|
+
step_3: 'Grant scopes: read_products, write_products, read_orders, write_orders, read_inventory, write_inventory, read_locations, read_fulfillments, write_fulfillments',
|
|
43
|
+
step_4: 'Install the app and copy the Admin API access token',
|
|
44
|
+
step_5: 'Set env vars: SHOPIFY_STORE=your-store-subdomain SHOPIFY_ACCESS_TOKEN=shpat_...',
|
|
45
|
+
}
|
|
46
|
+
: undefined,
|
|
47
|
+
},
|
|
48
|
+
license: {
|
|
49
|
+
tier: license.tier,
|
|
50
|
+
valid: license.valid,
|
|
51
|
+
expires_at: license.expiresAt,
|
|
52
|
+
},
|
|
53
|
+
...(license.tier === 'free'
|
|
54
|
+
? {
|
|
55
|
+
upgrade_info: {
|
|
56
|
+
url: 'https://buy.stripe.com/truss-shopify-pro',
|
|
57
|
+
price: '$25/mo',
|
|
58
|
+
free_tier: '10 read-only operations/day',
|
|
59
|
+
pro_features: [
|
|
60
|
+
'Unlimited operations',
|
|
61
|
+
'Create products',
|
|
62
|
+
'Update inventory',
|
|
63
|
+
'Fulfill orders',
|
|
64
|
+
'AI product descriptions',
|
|
65
|
+
'Detailed sales reports with comparisons',
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
: {}),
|
|
70
|
+
}, null, 2),
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
// ── Register Free Tier Tools ────────────────────────────────────────
|
|
76
|
+
registerListProducts(server);
|
|
77
|
+
registerGetProduct(server);
|
|
78
|
+
registerListOrders(server);
|
|
79
|
+
registerGetOrder(server);
|
|
80
|
+
registerStoreAnalytics(server);
|
|
81
|
+
// ── Register Pro Tier Tools ─────────────────────────────────────────
|
|
82
|
+
registerCreateProduct(server);
|
|
83
|
+
registerUpdateInventory(server);
|
|
84
|
+
registerFulfillOrder(server);
|
|
85
|
+
registerGenerateDescription(server);
|
|
86
|
+
registerSalesReport(server);
|
|
87
|
+
// ── Start Server ────────────────────────────────────────────────────
|
|
88
|
+
async function main() {
|
|
89
|
+
const transport = new StdioServerTransport();
|
|
90
|
+
// Clean shutdown
|
|
91
|
+
process.on('SIGINT', () => {
|
|
92
|
+
closeDb();
|
|
93
|
+
process.exit(0);
|
|
94
|
+
});
|
|
95
|
+
process.on('SIGTERM', () => {
|
|
96
|
+
closeDb();
|
|
97
|
+
process.exit(0);
|
|
98
|
+
});
|
|
99
|
+
await server.connect(transport);
|
|
100
|
+
}
|
|
101
|
+
main().catch((err) => {
|
|
102
|
+
console.error('Fatal error starting MCP server:', err);
|
|
103
|
+
closeDb();
|
|
104
|
+
process.exit(1);
|
|
105
|
+
});
|
|
106
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI-powered product description generation.
|
|
3
|
+
* Uses customer's Anthropic or OpenAI API key.
|
|
4
|
+
*/
|
|
5
|
+
import type { DescriptionInput, GeneratedDescription } from '../types.js';
|
|
6
|
+
export declare function generateProductDescription(input: DescriptionInput): Promise<GeneratedDescription>;
|
|
7
|
+
//# sourceMappingURL=ai-content.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-content.d.ts","sourceRoot":"","sources":["../../src/lib/ai-content.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAkH1E,wBAAsB,0BAA0B,CAC9C,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,oBAAoB,CAAC,CAoB/B"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI-powered product description generation.
|
|
3
|
+
* Uses customer's Anthropic or OpenAI API key.
|
|
4
|
+
*/
|
|
5
|
+
import { getConfig } from './config.js';
|
|
6
|
+
const DEFAULT_TONE = 'professional';
|
|
7
|
+
function buildPrompt(input) {
|
|
8
|
+
const tone = input.tone || DEFAULT_TONE;
|
|
9
|
+
const features = input.features.map((f) => `- ${f}`).join('\n');
|
|
10
|
+
const keywords = input.keywords?.length ? `\nTarget keywords: ${input.keywords.join(', ')}` : '';
|
|
11
|
+
return `Write a compelling product description for an e-commerce product.
|
|
12
|
+
|
|
13
|
+
Product title: ${input.product_title}
|
|
14
|
+
|
|
15
|
+
Key features:
|
|
16
|
+
${features}
|
|
17
|
+
${keywords}
|
|
18
|
+
|
|
19
|
+
Tone: ${tone}
|
|
20
|
+
|
|
21
|
+
Return a JSON object with these fields:
|
|
22
|
+
- "title": An optimized product title (may differ slightly from input)
|
|
23
|
+
- "description": HTML-formatted product description (2-4 paragraphs, use <p>, <ul>, <li> tags)
|
|
24
|
+
- "meta_description": SEO meta description (under 160 characters)
|
|
25
|
+
|
|
26
|
+
Return ONLY the JSON object, no other text.`;
|
|
27
|
+
}
|
|
28
|
+
async function generateWithAnthropic(prompt, apiKey) {
|
|
29
|
+
const response = await fetch('https://api.anthropic.com/v1/messages', {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: {
|
|
32
|
+
'x-api-key': apiKey,
|
|
33
|
+
'anthropic-version': '2023-06-01',
|
|
34
|
+
'Content-Type': 'application/json',
|
|
35
|
+
},
|
|
36
|
+
body: JSON.stringify({
|
|
37
|
+
model: 'claude-sonnet-4-20250514',
|
|
38
|
+
max_tokens: 1024,
|
|
39
|
+
messages: [{ role: 'user', content: prompt }],
|
|
40
|
+
}),
|
|
41
|
+
signal: AbortSignal.timeout(30000),
|
|
42
|
+
});
|
|
43
|
+
if (!response.ok) {
|
|
44
|
+
const err = await response.text().catch(() => 'Unknown error');
|
|
45
|
+
throw new Error(`Anthropic API error ${response.status}: ${err}`);
|
|
46
|
+
}
|
|
47
|
+
const body = (await response.json());
|
|
48
|
+
const text = body.content.find((c) => c.type === 'text')?.text;
|
|
49
|
+
if (!text)
|
|
50
|
+
throw new Error('Empty response from Anthropic API');
|
|
51
|
+
return parseGeneratedDescription(text);
|
|
52
|
+
}
|
|
53
|
+
async function generateWithOpenAI(prompt, apiKey) {
|
|
54
|
+
const response = await fetch('https://api.openai.com/v1/chat/completions', {
|
|
55
|
+
method: 'POST',
|
|
56
|
+
headers: {
|
|
57
|
+
Authorization: `Bearer ${apiKey}`,
|
|
58
|
+
'Content-Type': 'application/json',
|
|
59
|
+
},
|
|
60
|
+
body: JSON.stringify({
|
|
61
|
+
model: 'gpt-4o-mini',
|
|
62
|
+
messages: [{ role: 'user', content: prompt }],
|
|
63
|
+
max_tokens: 1024,
|
|
64
|
+
temperature: 0.7,
|
|
65
|
+
}),
|
|
66
|
+
signal: AbortSignal.timeout(30000),
|
|
67
|
+
});
|
|
68
|
+
if (!response.ok) {
|
|
69
|
+
const err = await response.text().catch(() => 'Unknown error');
|
|
70
|
+
throw new Error(`OpenAI API error ${response.status}: ${err}`);
|
|
71
|
+
}
|
|
72
|
+
const body = (await response.json());
|
|
73
|
+
const text = body.choices[0]?.message?.content;
|
|
74
|
+
if (!text)
|
|
75
|
+
throw new Error('Empty response from OpenAI API');
|
|
76
|
+
return parseGeneratedDescription(text);
|
|
77
|
+
}
|
|
78
|
+
function parseGeneratedDescription(text) {
|
|
79
|
+
// Try to extract JSON from the response
|
|
80
|
+
const jsonMatch = text.match(/\{[\s\S]*\}/);
|
|
81
|
+
if (!jsonMatch) {
|
|
82
|
+
throw new Error('AI response did not contain valid JSON');
|
|
83
|
+
}
|
|
84
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
85
|
+
if (!parsed.description) {
|
|
86
|
+
throw new Error('AI response missing required "description" field');
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
title: parsed.title || '',
|
|
90
|
+
description: parsed.description,
|
|
91
|
+
meta_description: parsed.meta_description || '',
|
|
92
|
+
tone: DEFAULT_TONE,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export async function generateProductDescription(input) {
|
|
96
|
+
const config = getConfig();
|
|
97
|
+
const prompt = buildPrompt(input);
|
|
98
|
+
// Prefer Anthropic, fall back to OpenAI
|
|
99
|
+
if (config.anthropicApiKey) {
|
|
100
|
+
const result = await generateWithAnthropic(prompt, config.anthropicApiKey);
|
|
101
|
+
result.tone = input.tone || DEFAULT_TONE;
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
if (config.openaiApiKey) {
|
|
105
|
+
const result = await generateWithOpenAI(prompt, config.openaiApiKey);
|
|
106
|
+
result.tone = input.tone || DEFAULT_TONE;
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
109
|
+
throw new Error('No AI API key configured. Set ANTHROPIC_API_KEY or OPENAI_API_KEY to use AI-powered description generation.');
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=ai-content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-content.js","sourceRoot":"","sources":["../../src/lib/ai-content.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analytics aggregation for Shopify store data.
|
|
3
|
+
* Computes metrics from orders and products fetched via the API.
|
|
4
|
+
*/
|
|
5
|
+
import type { ShopifyOrder, StoreMetrics, SalesReportData, AnalyticsPeriod, GroupBy, CompareTo } from '../types.js';
|
|
6
|
+
export declare function computeStoreMetrics(orders: ShopifyOrder[], period: AnalyticsPeriod): StoreMetrics;
|
|
7
|
+
export declare function computeSalesReport(orders: ShopifyOrder[], period: AnalyticsPeriod, groupBy?: GroupBy, compareTo?: CompareTo): SalesReportData;
|
|
8
|
+
//# sourceMappingURL=analytics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../src/lib/analytics.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,eAAe,EACf,OAAO,EACP,SAAS,EACV,MAAM,aAAa,CAAC;AAyDrB,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,YAAY,EAAE,EACtB,MAAM,EAAE,eAAe,GACtB,YAAY,CA2Cd;AAaD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,YAAY,EAAE,EACtB,MAAM,EAAE,eAAe,EACvB,OAAO,GAAE,OAAe,EACxB,SAAS,CAAC,EAAE,SAAS,GACpB,eAAe,CAiGjB"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analytics aggregation for Shopify store data.
|
|
3
|
+
* Computes metrics from orders and products fetched via the API.
|
|
4
|
+
*/
|
|
5
|
+
function getPeriodDates(period) {
|
|
6
|
+
const now = new Date();
|
|
7
|
+
const end = new Date(now);
|
|
8
|
+
switch (period) {
|
|
9
|
+
case 'today': {
|
|
10
|
+
const start = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
11
|
+
return { start, end, label: 'Today' };
|
|
12
|
+
}
|
|
13
|
+
case 'week': {
|
|
14
|
+
const start = new Date(now);
|
|
15
|
+
start.setDate(now.getDate() - 7);
|
|
16
|
+
return { start, end, label: 'Last 7 days' };
|
|
17
|
+
}
|
|
18
|
+
case 'month': {
|
|
19
|
+
const start = new Date(now);
|
|
20
|
+
start.setDate(now.getDate() - 30);
|
|
21
|
+
return { start, end, label: 'Last 30 days' };
|
|
22
|
+
}
|
|
23
|
+
case 'quarter': {
|
|
24
|
+
const start = new Date(now);
|
|
25
|
+
start.setDate(now.getDate() - 90);
|
|
26
|
+
return { start, end, label: 'Last 90 days' };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function getComparisonDates(period, compareTo) {
|
|
31
|
+
const current = getPeriodDates(period);
|
|
32
|
+
const durationMs = current.end.getTime() - current.start.getTime();
|
|
33
|
+
if (compareTo === 'previous_period') {
|
|
34
|
+
const end = new Date(current.start);
|
|
35
|
+
const start = new Date(end.getTime() - durationMs);
|
|
36
|
+
return { start, end, label: 'Previous period' };
|
|
37
|
+
}
|
|
38
|
+
// last_year
|
|
39
|
+
const start = new Date(current.start);
|
|
40
|
+
start.setFullYear(start.getFullYear() - 1);
|
|
41
|
+
const end = new Date(current.end);
|
|
42
|
+
end.setFullYear(end.getFullYear() - 1);
|
|
43
|
+
return { start, end, label: 'Same period last year' };
|
|
44
|
+
}
|
|
45
|
+
function filterOrdersByDateRange(orders, start, end) {
|
|
46
|
+
return orders.filter((o) => {
|
|
47
|
+
const d = new Date(o.created_at);
|
|
48
|
+
return d >= start && d <= end;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
export function computeStoreMetrics(orders, period) {
|
|
52
|
+
const dates = getPeriodDates(period);
|
|
53
|
+
const filtered = filterOrdersByDateRange(orders, dates.start, dates.end);
|
|
54
|
+
const totalRevenue = filtered.reduce((sum, o) => sum + parseFloat(o.total_price), 0);
|
|
55
|
+
const averageOrderValue = filtered.length > 0 ? totalRevenue / filtered.length : 0;
|
|
56
|
+
// Top products by quantity sold
|
|
57
|
+
const productMap = new Map();
|
|
58
|
+
for (const order of filtered) {
|
|
59
|
+
for (const item of order.line_items) {
|
|
60
|
+
const key = item.title;
|
|
61
|
+
const existing = productMap.get(key) || { quantity: 0, revenue: 0 };
|
|
62
|
+
existing.quantity += item.quantity;
|
|
63
|
+
existing.revenue += parseFloat(item.price) * item.quantity;
|
|
64
|
+
productMap.set(key, existing);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const topProducts = Array.from(productMap.entries())
|
|
68
|
+
.map(([title, data]) => ({
|
|
69
|
+
title,
|
|
70
|
+
quantity_sold: data.quantity,
|
|
71
|
+
revenue: Math.round(data.revenue * 100) / 100,
|
|
72
|
+
}))
|
|
73
|
+
.sort((a, b) => b.revenue - a.revenue)
|
|
74
|
+
.slice(0, 10);
|
|
75
|
+
// Orders by status
|
|
76
|
+
const ordersByStatus = {};
|
|
77
|
+
for (const order of filtered) {
|
|
78
|
+
const status = order.financial_status || 'unknown';
|
|
79
|
+
ordersByStatus[status] = (ordersByStatus[status] || 0) + 1;
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
period: dates.label,
|
|
83
|
+
total_orders: filtered.length,
|
|
84
|
+
total_revenue: Math.round(totalRevenue * 100) / 100,
|
|
85
|
+
average_order_value: Math.round(averageOrderValue * 100) / 100,
|
|
86
|
+
top_products: topProducts,
|
|
87
|
+
orders_by_status: ordersByStatus,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function getGroupKey(date, groupBy, productTitle) {
|
|
91
|
+
if (groupBy === 'product')
|
|
92
|
+
return productTitle || 'Unknown';
|
|
93
|
+
if (groupBy === 'day')
|
|
94
|
+
return date.toISOString().split('T')[0];
|
|
95
|
+
// week: use ISO week start (Monday)
|
|
96
|
+
const d = new Date(date);
|
|
97
|
+
const day = d.getDay();
|
|
98
|
+
const diff = d.getDate() - day + (day === 0 ? -6 : 1);
|
|
99
|
+
d.setDate(diff);
|
|
100
|
+
return `week_of_${d.toISOString().split('T')[0]}`;
|
|
101
|
+
}
|
|
102
|
+
export function computeSalesReport(orders, period, groupBy = 'day', compareTo) {
|
|
103
|
+
const dates = getPeriodDates(period);
|
|
104
|
+
const filtered = filterOrdersByDateRange(orders, dates.start, dates.end);
|
|
105
|
+
const totalRevenue = filtered.reduce((sum, o) => sum + parseFloat(o.total_price), 0);
|
|
106
|
+
const avgOrderValue = filtered.length > 0 ? totalRevenue / filtered.length : 0;
|
|
107
|
+
// Grouped data
|
|
108
|
+
const groupMap = new Map();
|
|
109
|
+
for (const order of filtered) {
|
|
110
|
+
const orderDate = new Date(order.created_at);
|
|
111
|
+
if (groupBy === 'product') {
|
|
112
|
+
// Group by product
|
|
113
|
+
for (const item of order.line_items) {
|
|
114
|
+
const key = getGroupKey(orderDate, groupBy, item.title);
|
|
115
|
+
const existing = groupMap.get(key) || { revenue: 0, orders: 0 };
|
|
116
|
+
existing.revenue += parseFloat(item.price) * item.quantity;
|
|
117
|
+
existing.orders += 1;
|
|
118
|
+
groupMap.set(key, existing);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
// Group by time period
|
|
123
|
+
const key = getGroupKey(orderDate, groupBy);
|
|
124
|
+
const existing = groupMap.get(key) || { revenue: 0, orders: 0 };
|
|
125
|
+
existing.revenue += parseFloat(order.total_price);
|
|
126
|
+
existing.orders += 1;
|
|
127
|
+
groupMap.set(key, existing);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const groupedData = Array.from(groupMap.entries())
|
|
131
|
+
.map(([group_key, data]) => ({
|
|
132
|
+
group_key,
|
|
133
|
+
revenue: Math.round(data.revenue * 100) / 100,
|
|
134
|
+
orders: data.orders,
|
|
135
|
+
average_order_value: data.orders > 0 ? Math.round((data.revenue / data.orders) * 100) / 100 : 0,
|
|
136
|
+
}))
|
|
137
|
+
.sort((a, b) => (groupBy === 'product' ? b.revenue - a.revenue : a.group_key.localeCompare(b.group_key)));
|
|
138
|
+
// Top products
|
|
139
|
+
const productMap = new Map();
|
|
140
|
+
for (const order of filtered) {
|
|
141
|
+
for (const item of order.line_items) {
|
|
142
|
+
const existing = productMap.get(item.title) || { quantity: 0, revenue: 0 };
|
|
143
|
+
existing.quantity += item.quantity;
|
|
144
|
+
existing.revenue += parseFloat(item.price) * item.quantity;
|
|
145
|
+
productMap.set(item.title, existing);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const topProducts = Array.from(productMap.entries())
|
|
149
|
+
.map(([title, data]) => ({
|
|
150
|
+
title,
|
|
151
|
+
quantity_sold: data.quantity,
|
|
152
|
+
revenue: Math.round(data.revenue * 100) / 100,
|
|
153
|
+
}))
|
|
154
|
+
.sort((a, b) => b.revenue - a.revenue)
|
|
155
|
+
.slice(0, 10);
|
|
156
|
+
// Comparison data
|
|
157
|
+
let comparison;
|
|
158
|
+
if (compareTo) {
|
|
159
|
+
const compDates = getComparisonDates(period, compareTo);
|
|
160
|
+
const compOrders = filterOrdersByDateRange(orders, compDates.start, compDates.end);
|
|
161
|
+
const compRevenue = compOrders.reduce((sum, o) => sum + parseFloat(o.total_price), 0);
|
|
162
|
+
comparison = {
|
|
163
|
+
period: compDates.label,
|
|
164
|
+
total_revenue: Math.round(compRevenue * 100) / 100,
|
|
165
|
+
total_orders: compOrders.length,
|
|
166
|
+
revenue_change_pct: compRevenue > 0
|
|
167
|
+
? Math.round(((totalRevenue - compRevenue) / compRevenue) * 10000) / 100
|
|
168
|
+
: totalRevenue > 0
|
|
169
|
+
? 100
|
|
170
|
+
: 0,
|
|
171
|
+
orders_change_pct: compOrders.length > 0
|
|
172
|
+
? Math.round(((filtered.length - compOrders.length) / compOrders.length) * 10000) / 100
|
|
173
|
+
: filtered.length > 0
|
|
174
|
+
? 100
|
|
175
|
+
: 0,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
period: dates.label,
|
|
180
|
+
compare_to: compareTo,
|
|
181
|
+
group_by: groupBy,
|
|
182
|
+
total_revenue: Math.round(totalRevenue * 100) / 100,
|
|
183
|
+
total_orders: filtered.length,
|
|
184
|
+
average_order_value: Math.round(avgOrderValue * 100) / 100,
|
|
185
|
+
grouped_data: groupedData,
|
|
186
|
+
comparison,
|
|
187
|
+
top_products: topProducts,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=analytics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analytics.js","sourceRoot":"","sources":["../../src/lib/analytics.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,SAAS,cAAc,CAAC,MAAuB;IAC7C,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;IAE1B,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,GAAG,CAAC,QAAQ,EAAE,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YACzE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;QACxC,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;YAC5B,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;YACjC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;QAC9C,CAAC;QACD,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;YAC5B,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;YAClC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC;QAC/C,CAAC;QACD,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;YAC5B,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;YAClC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC;QAC/C,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,kBAAkB,CACzB,MAAuB,EACvB,SAAoB;IAEpB,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;IAEnE,IAAI,SAAS,KAAK,iBAAiB,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACpC,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,UAAU,CAAC,CAAC;QACnD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAClD,CAAC;IAED,YAAY;IACZ,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC;IAC3C,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAClC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC;IACvC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC;AACxD,CAAC;AAED,SAAS,uBAAuB,CAAC,MAAsB,EAAE,KAAW,EAAE,GAAS;IAC7E,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QACzB,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QACjC,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,GAAG,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,MAAsB,EACtB,MAAuB;IAEvB,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAG,uBAAuB,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAEzE,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;IACrF,MAAM,iBAAiB,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAEnF,gCAAgC;IAChC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAiD,CAAC;IAC5E,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;YACpC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC;YACvB,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;YACpE,QAAQ,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC;YACnC,QAAQ,CAAC,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;YAC3D,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;SACjD,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QACvB,KAAK;QACL,aAAa,EAAE,IAAI,CAAC,QAAQ;QAC5B,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,GAAG;KAC9C,CAAC,CAAC;SACF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC;SACrC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEhB,mBAAmB;IACnB,MAAM,cAAc,GAA2B,EAAE,CAAC;IAClD,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,KAAK,CAAC,gBAAgB,IAAI,SAAS,CAAC;QACnD,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO;QACL,MAAM,EAAE,KAAK,CAAC,KAAK;QACnB,YAAY,EAAE,QAAQ,CAAC,MAAM;QAC7B,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,GAAG,CAAC,GAAG,GAAG;QACnD,mBAAmB,EAAE,IAAI,CAAC,KAAK,CAAC,iBAAiB,GAAG,GAAG,CAAC,GAAG,GAAG;QAC9D,YAAY,EAAE,WAAW;QACzB,gBAAgB,EAAE,cAAc;KACjC,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,IAAU,EAAE,OAAgB,EAAE,YAAqB;IACtE,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,YAAY,IAAI,SAAS,CAAC;IAC5D,IAAI,OAAO,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,oCAAoC;IACpC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,MAAM,GAAG,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC;IACvB,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,GAAG,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAChB,OAAO,WAAW,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,MAAsB,EACtB,MAAuB,EACvB,UAAmB,KAAK,EACxB,SAAqB;IAErB,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAG,uBAAuB,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAEzE,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;IACrF,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAE/E,eAAe;IACf,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA+C,CAAC;IACxE,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC7B,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAE7C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,mBAAmB;YACnB,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;gBACpC,MAAM,GAAG,GAAG,WAAW,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;gBACxD,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;gBAChE,QAAQ,CAAC,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;gBAC3D,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAC;gBACrB,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;aAAM,CAAC;YACN,uBAAuB;YACvB,MAAM,GAAG,GAAG,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAC5C,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;YAChE,QAAQ,CAAC,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;YAClD,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAC;YACrB,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;SAC/C,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QAC3B,SAAS;QACT,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,GAAG;QAC7C,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,mBAAmB,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;KAChG,CAAC,CAAC;SACF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAE5G,eAAe;IACf,MAAM,UAAU,GAAG,IAAI,GAAG,EAAiD,CAAC;IAC5E,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;YACpC,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;YAC3E,QAAQ,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC;YACnC,QAAQ,CAAC,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;YAC3D,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;SACjD,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QACvB,KAAK;QACL,aAAa,EAAE,IAAI,CAAC,QAAQ;QAC5B,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,GAAG;KAC9C,CAAC,CAAC;SACF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC;SACrC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEhB,kBAAkB;IAClB,IAAI,UAAyC,CAAC;IAC9C,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,SAAS,GAAG,kBAAkB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACxD,MAAM,UAAU,GAAG,uBAAuB,CAAC,MAAM,EAAE,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC;QACnF,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;QAEtF,UAAU,GAAG;YACX,MAAM,EAAE,SAAS,CAAC,KAAK;YACvB,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,GAAG,CAAC,GAAG,GAAG;YAClD,YAAY,EAAE,UAAU,CAAC,MAAM;YAC/B,kBAAkB,EAChB,WAAW,GAAG,CAAC;gBACb,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,GAAG,WAAW,CAAC,GAAG,WAAW,CAAC,GAAG,KAAK,CAAC,GAAG,GAAG;gBACxE,CAAC,CAAC,YAAY,GAAG,CAAC;oBAChB,CAAC,CAAC,GAAG;oBACL,CAAC,CAAC,CAAC;YACT,iBAAiB,EACf,UAAU,CAAC,MAAM,GAAG,CAAC;gBACnB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,GAAG;gBACvF,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;oBACnB,CAAC,CAAC,GAAG;oBACL,CAAC,CAAC,CAAC;SACV,CAAC;IACJ,CAAC;IAED,OAAO;QACL,MAAM,EAAE,KAAK,CAAC,KAAK;QACnB,UAAU,EAAE,SAAS;QACrB,QAAQ,EAAE,OAAO;QACjB,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,GAAG,CAAC,GAAG,GAAG;QACnD,YAAY,EAAE,QAAQ,CAAC,MAAM;QAC7B,mBAAmB,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,GAAG,CAAC,GAAG,GAAG;QAC1D,YAAY,EAAE,WAAW;QACzB,UAAU;QACV,YAAY,EAAE,WAAW;KAC1B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAWjD,wBAAgB,SAAS,IAAI,aAAa,CAUzC;AAED,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,SAAS,IAAI,MAAM,CAElC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { mkdirSync } from 'node:fs';
|
|
4
|
+
const DATA_DIR = join(homedir(), '.truss', 'shopify');
|
|
5
|
+
// Ensure data directory exists on import
|
|
6
|
+
try {
|
|
7
|
+
mkdirSync(DATA_DIR, { recursive: true });
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
// ignore -- directory already exists
|
|
11
|
+
}
|
|
12
|
+
export function getConfig() {
|
|
13
|
+
return {
|
|
14
|
+
shopifyStore: process.env.SHOPIFY_STORE || '',
|
|
15
|
+
shopifyAccessToken: process.env.SHOPIFY_ACCESS_TOKEN || '',
|
|
16
|
+
licenseKey: process.env.TRUSS_LICENSE_KEY,
|
|
17
|
+
anthropicApiKey: process.env.ANTHROPIC_API_KEY,
|
|
18
|
+
openaiApiKey: process.env.OPENAI_API_KEY,
|
|
19
|
+
trussApiBaseUrl: process.env.TRUSS_API_BASE_URL || 'https://api.truss.dev',
|
|
20
|
+
dataDir: DATA_DIR,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function getDataDir() {
|
|
24
|
+
return DATA_DIR;
|
|
25
|
+
}
|
|
26
|
+
export function getDbPath() {
|
|
27
|
+
return join(DATA_DIR, 'usage.db');
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGpC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;AAEtD,yCAAyC;AACzC,IAAI,CAAC;IACH,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC3C,CAAC;AAAC,MAAM,CAAC;IACP,qCAAqC;AACvC,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO;QACL,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,EAAE;QAC7C,kBAAkB,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,EAAE;QAC1D,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB;QACzC,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAC9C,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc;QACxC,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,uBAAuB;QAC1E,OAAO,EAAE,QAAQ;KAClB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"license.d.ts","sourceRoot":"","sources":["../../src/lib/license.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,aAAa,CAAC;AAuE9D,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,aAAa,CAAC,CAiC/D;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAQhD"}
|