ecomcoder-cli 1.3.10 → 1.3.12
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 +16 -0
- package/dist/commands/asset/delete.d.ts.map +1 -1
- package/dist/commands/asset/delete.js +14 -0
- package/dist/commands/asset/delete.js.map +1 -1
- package/dist/commands/asset/external-apis.d.ts +13 -0
- package/dist/commands/asset/external-apis.d.ts.map +1 -0
- package/dist/commands/asset/external-apis.js +99 -0
- package/dist/commands/asset/external-apis.js.map +1 -0
- package/dist/commands/asset/import.d.ts.map +1 -1
- package/dist/commands/asset/import.js +14 -0
- package/dist/commands/asset/import.js.map +1 -1
- package/dist/commands/asset/index.d.ts.map +1 -1
- package/dist/commands/asset/index.js +17 -0
- package/dist/commands/asset/index.js.map +1 -1
- package/dist/commands/asset/search-icons.d.ts +6 -0
- package/dist/commands/asset/search-icons.d.ts.map +1 -0
- package/dist/commands/asset/search-icons.js +84 -0
- package/dist/commands/asset/search-icons.js.map +1 -0
- package/dist/commands/asset/search-stock.d.ts +6 -0
- package/dist/commands/asset/search-stock.d.ts.map +1 -0
- package/dist/commands/asset/search-stock.js +79 -0
- package/dist/commands/asset/search-stock.js.map +1 -0
- package/dist/commands/asset/service.d.ts +13 -1
- package/dist/commands/asset/service.d.ts.map +1 -1
- package/dist/commands/asset/service.js +75 -6
- package/dist/commands/asset/service.js.map +1 -1
- package/dist/commands/asset/types.d.ts +30 -1
- package/dist/commands/asset/types.d.ts.map +1 -1
- package/dist/commands/asset/upload.d.ts.map +1 -1
- package/dist/commands/asset/upload.js +35 -3
- package/dist/commands/asset/upload.js.map +1 -1
- package/dist/commands/asset/utils.d.ts +13 -0
- package/dist/commands/asset/utils.d.ts.map +1 -0
- package/dist/commands/asset/utils.js +68 -0
- package/dist/commands/asset/utils.js.map +1 -0
- package/dist/commands/create-dummy-products.d.ts.map +1 -1
- package/dist/commands/create-dummy-products.js +14 -0
- package/dist/commands/create-dummy-products.js.map +1 -1
- package/dist/commands/create-metafield.d.ts.map +1 -1
- package/dist/commands/create-metafield.js +14 -0
- package/dist/commands/create-metafield.js.map +1 -1
- package/dist/commands/discount/create-basic.d.ts.map +1 -1
- package/dist/commands/discount/create-basic.js +14 -0
- package/dist/commands/discount/create-basic.js.map +1 -1
- package/dist/commands/discount/create-bxgy.d.ts.map +1 -1
- package/dist/commands/discount/create-bxgy.js +14 -0
- package/dist/commands/discount/create-bxgy.js.map +1 -1
- package/dist/commands/discount/create-shipping.d.ts.map +1 -1
- package/dist/commands/discount/create-shipping.js +14 -0
- package/dist/commands/discount/create-shipping.js.map +1 -1
- package/dist/commands/discount/delete.d.ts.map +1 -1
- package/dist/commands/discount/delete.js +14 -0
- package/dist/commands/discount/delete.js.map +1 -1
- package/dist/commands/product/add-options.d.ts.map +1 -1
- package/dist/commands/product/add-options.js +14 -0
- package/dist/commands/product/add-options.js.map +1 -1
- package/dist/commands/product/create-variants.d.ts.map +1 -1
- package/dist/commands/product/create-variants.js +14 -0
- package/dist/commands/product/create-variants.js.map +1 -1
- package/dist/commands/product/create.d.ts.map +1 -1
- package/dist/commands/product/create.js +14 -0
- package/dist/commands/product/create.js.map +1 -1
- package/dist/commands/product/delete-variants.d.ts.map +1 -1
- package/dist/commands/product/delete-variants.js +14 -0
- package/dist/commands/product/delete-variants.js.map +1 -1
- package/dist/commands/product/set-metafield.d.ts.map +1 -1
- package/dist/commands/product/set-metafield.js +14 -0
- package/dist/commands/product/set-metafield.js.map +1 -1
- package/dist/commands/product/update-description.d.ts.map +1 -1
- package/dist/commands/product/update-description.js +14 -0
- package/dist/commands/product/update-description.js.map +1 -1
- package/dist/commands/product/update-options.d.ts.map +1 -1
- package/dist/commands/product/update-options.js +14 -0
- package/dist/commands/product/update-options.js.map +1 -1
- package/dist/commands/product/update-price.d.ts.map +1 -1
- package/dist/commands/product/update-price.js +14 -0
- package/dist/commands/product/update-price.js.map +1 -1
- package/dist/commands/product/update-status.d.ts.map +1 -1
- package/dist/commands/product/update-status.js +14 -0
- package/dist/commands/product/update-status.js.map +1 -1
- package/dist/commands/product/update-template.d.ts.map +1 -1
- package/dist/commands/product/update-template.js +14 -0
- package/dist/commands/product/update-template.js.map +1 -1
- package/dist/commands/product/update-title.d.ts.map +1 -1
- package/dist/commands/product/update-title.js +14 -0
- package/dist/commands/product/update-title.js.map +1 -1
- package/dist/commands/set-product-rating.d.ts.map +1 -1
- package/dist/commands/set-product-rating.js +14 -0
- package/dist/commands/set-product-rating.js.map +1 -1
- package/dist/commands/shop/set-metafield.d.ts.map +1 -1
- package/dist/commands/shop/set-metafield.js +14 -0
- package/dist/commands/shop/set-metafield.js.map +1 -1
- package/dist/lib/approval.d.ts +28 -0
- package/dist/lib/approval.d.ts.map +1 -0
- package/dist/lib/approval.js +38 -0
- package/dist/lib/approval.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -128,6 +128,22 @@ You can also manually provide the session ID:
|
|
|
128
128
|
ecomcoder products list --session-id=your-session-id
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
+
## Safety Features
|
|
132
|
+
|
|
133
|
+
### User Approval for Destructive Operations
|
|
134
|
+
|
|
135
|
+
All commands that modify your live Shopify store (create, update, delete operations) require user confirmation before execution. This prevents accidental changes to your production store.
|
|
136
|
+
|
|
137
|
+
**Commands requiring approval:**
|
|
138
|
+
- Product updates (price, title, description, status, etc.)
|
|
139
|
+
- Product/variant creation and deletion
|
|
140
|
+
- Discount creation and deletion
|
|
141
|
+
- Metafield modifications
|
|
142
|
+
|
|
143
|
+
**Read-only commands** (like `products list`, `product get`) execute immediately without approval prompts.
|
|
144
|
+
|
|
145
|
+
When used with the EcomCoder app, you'll see a confirmation dialog before any destructive operation is executed. The CLI will wait for your approval before proceeding.
|
|
146
|
+
|
|
131
147
|
## Development
|
|
132
148
|
|
|
133
149
|
### Setup
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../src/commands/asset/delete.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../src/commands/asset/delete.ts"],"names":[],"mappings":"AAAA;;GAEG;AAwBH,wBAAsB,GAAG,CAAC,IAAI,GAAE,MAAM,EAA0B,iBAkD/D"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { getCredentials, getSessionId } from '../../lib/api-client.js';
|
|
5
5
|
import { parseArgs, hasHelpFlag } from '../../lib/args-parser.js';
|
|
6
6
|
import { AssetService } from './service.js';
|
|
7
|
+
import { requestApproval } from '../../lib/approval.js';
|
|
7
8
|
function showHelp() {
|
|
8
9
|
console.log(`
|
|
9
10
|
Delete Asset
|
|
@@ -35,6 +36,19 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
35
36
|
try {
|
|
36
37
|
const sessionId = getSessionId(args.sessionId);
|
|
37
38
|
const credentials = await getCredentials(sessionId, args.backendUrl, args.jwt);
|
|
39
|
+
// Request approval before executing
|
|
40
|
+
const approved = await requestApproval({
|
|
41
|
+
command: `ecomcoder asset delete --id=${args.id}`,
|
|
42
|
+
message: `This will permanently delete the asset from your live Shopify store. This action cannot be undone.`,
|
|
43
|
+
riskLevel: 'high'
|
|
44
|
+
});
|
|
45
|
+
if (!approved) {
|
|
46
|
+
console.log(JSON.stringify({
|
|
47
|
+
success: false,
|
|
48
|
+
error: 'Operation cancelled by user'
|
|
49
|
+
}));
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
38
52
|
const result = await AssetService.delete(credentials, {
|
|
39
53
|
id: args.id
|
|
40
54
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delete.js","sourceRoot":"","sources":["../../../src/commands/asset/delete.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"delete.js","sourceRoot":"","sources":["../../../src/commands/asset/delete.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,SAAS,QAAQ;IACf,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;CAYb,CAAC,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,OAAiB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9D,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,QAAQ,EAAE,CAAC;IACb,CAAC;IAED,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAE7B,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;YAC3B,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,iCAAiC;SACzC,CAAC,CAAC,CAAC;QACJ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/C,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QAE/E,oCAAoC;QACpC,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC;YACrC,OAAO,EAAE,+BAA+B,IAAI,CAAC,EAAE,EAAE;YACjD,OAAO,EAAE,oGAAoG;YAC7G,SAAS,EAAE,MAAM;SAClB,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC;gBACzB,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,6BAA6B;aACrC,CAAC,CAAC,CAAC;YACJ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,WAAW,EAAE;YACpD,EAAE,EAAE,IAAI,CAAC,EAAE;SACZ,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAE7C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;YAC3B,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,KAAK,CAAC,OAAO,IAAI,wBAAwB;SACjD,CAAC,CAAC,CAAC;QACJ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External API Integrations
|
|
3
|
+
* Handles stock images (Pexels) and icons (Lucide)
|
|
4
|
+
*/
|
|
5
|
+
import { StockImage, SearchStockInput, Icon, SearchIconsInput } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Pexels API Client
|
|
8
|
+
* Free stock photos API
|
|
9
|
+
* Rate limit: 200/hour, 20,000/month (free tier)
|
|
10
|
+
*/
|
|
11
|
+
export declare function searchPexelsImages(input: SearchStockInput): Promise<StockImage[]>;
|
|
12
|
+
export declare function searchLucideIcons(input: SearchIconsInput): Promise<Icon[]>;
|
|
13
|
+
//# sourceMappingURL=external-apis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-apis.d.ts","sourceRoot":"","sources":["../../../src/commands/asset/external-apis.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAElF;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAkDvF;AAkCD,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAkBhF"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External API Integrations
|
|
3
|
+
* Handles stock images (Pexels) and icons (Lucide)
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Pexels API Client
|
|
7
|
+
* Free stock photos API
|
|
8
|
+
* Rate limit: 200/hour, 20,000/month (free tier)
|
|
9
|
+
*/
|
|
10
|
+
export async function searchPexelsImages(input) {
|
|
11
|
+
const apiKey = process.env.PEXELS_API_KEY;
|
|
12
|
+
if (!apiKey) {
|
|
13
|
+
throw new Error('PEXELS_API_KEY environment variable not set. Get your free API key at https://www.pexels.com/api/');
|
|
14
|
+
}
|
|
15
|
+
const limit = Math.min(input.limit || 10, 80); // Max 80 per request
|
|
16
|
+
const params = new URLSearchParams({
|
|
17
|
+
query: input.query,
|
|
18
|
+
per_page: limit.toString(),
|
|
19
|
+
});
|
|
20
|
+
if (input.orientation) {
|
|
21
|
+
params.append('orientation', input.orientation);
|
|
22
|
+
}
|
|
23
|
+
if (input.size) {
|
|
24
|
+
params.append('size', input.size);
|
|
25
|
+
}
|
|
26
|
+
if (input.color) {
|
|
27
|
+
params.append('color', input.color);
|
|
28
|
+
}
|
|
29
|
+
const response = await fetch(`https://api.pexels.com/v1/search?${params}`, {
|
|
30
|
+
headers: {
|
|
31
|
+
'Authorization': apiKey
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
if (response.status === 429) {
|
|
36
|
+
throw new Error('Pexels rate limit exceeded. Free tier: 200/hour, 20,000/month.');
|
|
37
|
+
}
|
|
38
|
+
throw new Error(`Pexels API error: ${response.status} ${response.statusText}`);
|
|
39
|
+
}
|
|
40
|
+
const data = await response.json();
|
|
41
|
+
return data.photos.map((photo) => ({
|
|
42
|
+
id: photo.id,
|
|
43
|
+
url: photo.src.large2x || photo.src.large, // High quality image
|
|
44
|
+
photographer: photo.photographer,
|
|
45
|
+
photographerUrl: photo.photographer_url,
|
|
46
|
+
width: photo.width,
|
|
47
|
+
height: photo.height,
|
|
48
|
+
alt: photo.alt || input.query,
|
|
49
|
+
avgColor: photo.avg_color
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Lucide Icons Search
|
|
54
|
+
* Open-source icon library with 1,667+ icons
|
|
55
|
+
* No API key required - uses CDN
|
|
56
|
+
*/
|
|
57
|
+
// Embedded icon metadata for fast search
|
|
58
|
+
// This is a curated subset - full list at https://lucide.dev/icons/
|
|
59
|
+
const LUCIDE_ICONS = [
|
|
60
|
+
{ name: 'shopping-cart', tags: ['cart', 'shop', 'buy', 'purchase', 'ecommerce'], category: 'ecommerce' },
|
|
61
|
+
{ name: 'shopping-bag', tags: ['bag', 'shop', 'buy', 'purchase', 'ecommerce'], category: 'ecommerce' },
|
|
62
|
+
{ name: 'credit-card', tags: ['payment', 'card', 'pay', 'money'], category: 'payment' },
|
|
63
|
+
{ name: 'heart', tags: ['like', 'favorite', 'love', 'wishlist'], category: 'social' },
|
|
64
|
+
{ name: 'star', tags: ['favorite', 'rating', 'review'], category: 'social' },
|
|
65
|
+
{ name: 'user', tags: ['account', 'profile', 'person'], category: 'user' },
|
|
66
|
+
{ name: 'search', tags: ['find', 'magnifier', 'look'], category: 'ui' },
|
|
67
|
+
{ name: 'menu', tags: ['hamburger', 'navigation', 'nav'], category: 'ui' },
|
|
68
|
+
{ name: 'x', tags: ['close', 'cancel', 'dismiss'], category: 'ui' },
|
|
69
|
+
{ name: 'check', tags: ['success', 'done', 'complete'], category: 'ui' },
|
|
70
|
+
{ name: 'arrow-right', tags: ['next', 'forward', 'direction'], category: 'arrows' },
|
|
71
|
+
{ name: 'arrow-left', tags: ['back', 'previous', 'direction'], category: 'arrows' },
|
|
72
|
+
{ name: 'home', tags: ['house', 'main', 'start'], category: 'ui' },
|
|
73
|
+
{ name: 'mail', tags: ['email', 'message', 'envelope'], category: 'communication' },
|
|
74
|
+
{ name: 'phone', tags: ['call', 'contact', 'telephone'], category: 'communication' },
|
|
75
|
+
{ name: 'truck', tags: ['delivery', 'shipping', 'transport'], category: 'ecommerce' },
|
|
76
|
+
{ name: 'package', tags: ['box', 'product', 'shipping'], category: 'ecommerce' },
|
|
77
|
+
{ name: 'gift', tags: ['present', 'box', 'surprise'], category: 'ecommerce' },
|
|
78
|
+
{ name: 'tag', tags: ['price', 'label', 'discount'], category: 'ecommerce' },
|
|
79
|
+
{ name: 'percent', tags: ['discount', 'sale', 'offer'], category: 'ecommerce' },
|
|
80
|
+
// Add more as needed - this is just a starter set
|
|
81
|
+
];
|
|
82
|
+
export async function searchLucideIcons(input) {
|
|
83
|
+
const query = input.query.toLowerCase();
|
|
84
|
+
const limit = input.limit || 10;
|
|
85
|
+
// Search in name and tags
|
|
86
|
+
const results = LUCIDE_ICONS.filter(icon => {
|
|
87
|
+
return icon.name.includes(query) ||
|
|
88
|
+
icon.tags.some(tag => tag.includes(query)) ||
|
|
89
|
+
icon.category?.includes(query);
|
|
90
|
+
});
|
|
91
|
+
// Return top matches with CDN URLs
|
|
92
|
+
return results.slice(0, limit).map(icon => ({
|
|
93
|
+
name: icon.name,
|
|
94
|
+
url: `https://cdn.jsdelivr.net/npm/lucide-static@latest/icons/${icon.name}.svg`,
|
|
95
|
+
tags: icon.tags,
|
|
96
|
+
category: icon.category
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=external-apis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-apis.js","sourceRoot":"","sources":["../../../src/commands/asset/external-apis.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../../src/commands/asset/import.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../../src/commands/asset/import.ts"],"names":[],"mappings":"AAAA;;GAEG;AA0BH,wBAAsB,GAAG,CAAC,IAAI,GAAE,MAAM,EAA0B,iBAmD/D"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { getCredentials, getSessionId } from '../../lib/api-client.js';
|
|
5
5
|
import { parseArgs, hasHelpFlag } from '../../lib/args-parser.js';
|
|
6
6
|
import { AssetService } from './service.js';
|
|
7
|
+
import { requestApproval } from '../../lib/approval.js';
|
|
7
8
|
function showHelp() {
|
|
8
9
|
console.log(`
|
|
9
10
|
Bulk Import Assets
|
|
@@ -37,6 +38,19 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
37
38
|
try {
|
|
38
39
|
const sessionId = getSessionId(args.sessionId);
|
|
39
40
|
const credentials = await getCredentials(sessionId, args.backendUrl, args.jwt);
|
|
41
|
+
// Request approval before executing
|
|
42
|
+
const approved = await requestApproval({
|
|
43
|
+
command: `ecomcoder asset import --directory=${args.directory}`,
|
|
44
|
+
message: `This will bulk import assets to your live Shopify store`,
|
|
45
|
+
riskLevel: 'moderate'
|
|
46
|
+
});
|
|
47
|
+
if (!approved) {
|
|
48
|
+
console.log(JSON.stringify({
|
|
49
|
+
success: false,
|
|
50
|
+
error: 'Operation cancelled by user'
|
|
51
|
+
}));
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
40
54
|
const result = await AssetService.import(credentials, {
|
|
41
55
|
directory: args.directory,
|
|
42
56
|
pattern: args.pattern
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import.js","sourceRoot":"","sources":["../../../src/commands/asset/import.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"import.js","sourceRoot":"","sources":["../../../src/commands/asset/import.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,SAAS,QAAQ;IACf,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;CAcb,CAAC,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,OAAiB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9D,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,QAAQ,EAAE,CAAC;IACb,CAAC;IAED,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAE7B,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;YAC3B,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,wCAAwC;SAChD,CAAC,CAAC,CAAC;QACJ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/C,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QAE/E,oCAAoC;QACpC,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC;YACrC,OAAO,EAAE,sCAAsC,IAAI,CAAC,SAAS,EAAE;YAC/D,OAAO,EAAE,yDAAyD;YAClE,SAAS,EAAE,UAAU;SACtB,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC;gBACzB,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,6BAA6B;aACrC,CAAC,CAAC,CAAC;YACJ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,WAAW,EAAE;YACpD,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAE7C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;YAC3B,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,KAAK,CAAC,OAAO,IAAI,wBAAwB;SACjD,CAAC,CAAC,CAAC;QACJ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/asset/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,wBAAgB,qBAAqB,IAAI,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/asset/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,wBAAgB,qBAAqB,IAAI,IAAI,CA2E5C"}
|
|
@@ -54,5 +54,22 @@ export function registerAssetCommands() {
|
|
|
54
54
|
quickExample: 'ecomcoder asset import --directory=./images --pattern="*.png"',
|
|
55
55
|
handler: async () => await import('./import.js')
|
|
56
56
|
});
|
|
57
|
+
// External resources
|
|
58
|
+
registry.register({
|
|
59
|
+
command: 'asset',
|
|
60
|
+
subcommand: 'search-stock',
|
|
61
|
+
description: 'Search free stock photos (Pexels)',
|
|
62
|
+
category: 'Search',
|
|
63
|
+
quickExample: 'ecomcoder asset search-stock --query="mountains" --limit=5',
|
|
64
|
+
handler: async () => await import('./search-stock.js')
|
|
65
|
+
});
|
|
66
|
+
registry.register({
|
|
67
|
+
command: 'asset',
|
|
68
|
+
subcommand: 'search-icons',
|
|
69
|
+
description: 'Search open-source icons (Lucide)',
|
|
70
|
+
category: 'Search',
|
|
71
|
+
quickExample: 'ecomcoder asset search-icons --query="cart"',
|
|
72
|
+
handler: async () => await import('./search-icons.js')
|
|
73
|
+
});
|
|
57
74
|
}
|
|
58
75
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/asset/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D,MAAM,UAAU,qBAAqB;IACnC,iBAAiB;IACjB,QAAQ,CAAC,aAAa,CAAC;QACrB,OAAO,EAAE,OAAO;QAChB,WAAW,EAAE,6CAA6C;QAC1D,QAAQ,EAAE,GAAG,EAAE;YACb,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC;QACxD,CAAC;KACF,CAAC,CAAC;IAEH,kBAAkB;IAClB,QAAQ,CAAC,QAAQ,CAAC;QAChB,OAAO,EAAE,OAAO;QAChB,UAAU,EAAE,QAAQ;QACpB,WAAW,EAAE,yBAAyB;QACtC,QAAQ,EAAE,MAAM;QAChB,YAAY,EAAE,qDAAqD;QACnE,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,MAAM,CAAC,aAAa,CAAC;KACjD,CAAC,CAAC;IAEH,QAAQ,CAAC,QAAQ,CAAC;QAChB,OAAO,EAAE,OAAO;QAChB,UAAU,EAAE,KAAK;QACjB,WAAW,EAAE,yBAAyB;QACtC,QAAQ,EAAE,MAAM;QAChB,YAAY,EAAE,uDAAuD;QACrE,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,MAAM,CAAC,UAAU,CAAC;KAC9C,CAAC,CAAC;IAEH,QAAQ,CAAC,QAAQ,CAAC;QAChB,OAAO,EAAE,OAAO;QAChB,UAAU,EAAE,QAAQ;QACpB,WAAW,EAAE,2BAA2B;QACxC,QAAQ,EAAE,MAAM;QAChB,YAAY,EAAE,0DAA0D;QACxE,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,MAAM,CAAC,aAAa,CAAC;KACjD,CAAC,CAAC;IAEH,oBAAoB;IACpB,QAAQ,CAAC,QAAQ,CAAC;QAChB,OAAO,EAAE,OAAO;QAChB,UAAU,EAAE,MAAM;QAClB,WAAW,EAAE,iBAAiB;QAC9B,QAAQ,EAAE,QAAQ;QAClB,YAAY,EAAE,8CAA8C;QAC5D,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,MAAM,CAAC,WAAW,CAAC;KAC/C,CAAC,CAAC;IAEH,QAAQ,CAAC,QAAQ,CAAC;QAChB,OAAO,EAAE,OAAO;QAChB,UAAU,EAAE,QAAQ;QACpB,WAAW,EAAE,mCAAmC;QAChD,QAAQ,EAAE,QAAQ;QAClB,YAAY,EAAE,+DAA+D;QAC7E,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,MAAM,CAAC,aAAa,CAAC;KACjD,CAAC,CAAC;AACL,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/asset/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D,MAAM,UAAU,qBAAqB;IACnC,iBAAiB;IACjB,QAAQ,CAAC,aAAa,CAAC;QACrB,OAAO,EAAE,OAAO;QAChB,WAAW,EAAE,6CAA6C;QAC1D,QAAQ,EAAE,GAAG,EAAE;YACb,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC;QACxD,CAAC;KACF,CAAC,CAAC;IAEH,kBAAkB;IAClB,QAAQ,CAAC,QAAQ,CAAC;QAChB,OAAO,EAAE,OAAO;QAChB,UAAU,EAAE,QAAQ;QACpB,WAAW,EAAE,yBAAyB;QACtC,QAAQ,EAAE,MAAM;QAChB,YAAY,EAAE,qDAAqD;QACnE,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,MAAM,CAAC,aAAa,CAAC;KACjD,CAAC,CAAC;IAEH,QAAQ,CAAC,QAAQ,CAAC;QAChB,OAAO,EAAE,OAAO;QAChB,UAAU,EAAE,KAAK;QACjB,WAAW,EAAE,yBAAyB;QACtC,QAAQ,EAAE,MAAM;QAChB,YAAY,EAAE,uDAAuD;QACrE,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,MAAM,CAAC,UAAU,CAAC;KAC9C,CAAC,CAAC;IAEH,QAAQ,CAAC,QAAQ,CAAC;QAChB,OAAO,EAAE,OAAO;QAChB,UAAU,EAAE,QAAQ;QACpB,WAAW,EAAE,2BAA2B;QACxC,QAAQ,EAAE,MAAM;QAChB,YAAY,EAAE,0DAA0D;QACxE,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,MAAM,CAAC,aAAa,CAAC;KACjD,CAAC,CAAC;IAEH,oBAAoB;IACpB,QAAQ,CAAC,QAAQ,CAAC;QAChB,OAAO,EAAE,OAAO;QAChB,UAAU,EAAE,MAAM;QAClB,WAAW,EAAE,iBAAiB;QAC9B,QAAQ,EAAE,QAAQ;QAClB,YAAY,EAAE,8CAA8C;QAC5D,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,MAAM,CAAC,WAAW,CAAC;KAC/C,CAAC,CAAC;IAEH,QAAQ,CAAC,QAAQ,CAAC;QAChB,OAAO,EAAE,OAAO;QAChB,UAAU,EAAE,QAAQ;QACpB,WAAW,EAAE,mCAAmC;QAChD,QAAQ,EAAE,QAAQ;QAClB,YAAY,EAAE,+DAA+D;QAC7E,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,MAAM,CAAC,aAAa,CAAC;KACjD,CAAC,CAAC;IAEH,qBAAqB;IACrB,QAAQ,CAAC,QAAQ,CAAC;QAChB,OAAO,EAAE,OAAO;QAChB,UAAU,EAAE,cAAc;QAC1B,WAAW,EAAE,mCAAmC;QAChD,QAAQ,EAAE,QAAQ;QAClB,YAAY,EAAE,4DAA4D;QAC1E,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,MAAM,CAAC,mBAAmB,CAAC;KACvD,CAAC,CAAC;IAEH,QAAQ,CAAC,QAAQ,CAAC;QAChB,OAAO,EAAE,OAAO;QAChB,UAAU,EAAE,cAAc;QAC1B,WAAW,EAAE,mCAAmC;QAChD,QAAQ,EAAE,QAAQ;QAClB,YAAY,EAAE,6CAA6C;QAC3D,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,MAAM,CAAC,mBAAmB,CAAC;KACvD,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-icons.d.ts","sourceRoot":"","sources":["../../../src/commands/asset/search-icons.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAqDH,wBAAsB,GAAG,CAAC,IAAI,GAAE,MAAM,EAA0B,iBAiC/D"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search Icons Command
|
|
3
|
+
* Search open-source icons from Lucide library
|
|
4
|
+
*/
|
|
5
|
+
import { parseArgs, hasHelpFlag } from '../../lib/args-parser.js';
|
|
6
|
+
import { AssetService } from './service.js';
|
|
7
|
+
function showHelp() {
|
|
8
|
+
console.log(`
|
|
9
|
+
Search Icons (Lucide)
|
|
10
|
+
|
|
11
|
+
USAGE:
|
|
12
|
+
ecomcoder asset search-icons --query=<search> [OPTIONS]
|
|
13
|
+
|
|
14
|
+
OPTIONS:
|
|
15
|
+
--query <text> Search query (required)
|
|
16
|
+
--limit <number> Max results (default: 10)
|
|
17
|
+
--help, -h Show this help message
|
|
18
|
+
|
|
19
|
+
ABOUT LUCIDE:
|
|
20
|
+
- Open-source icon library (ISC license)
|
|
21
|
+
- 1,667+ icons and growing
|
|
22
|
+
- SVG format (lightweight, customizable)
|
|
23
|
+
- No API key required
|
|
24
|
+
- Free for commercial use
|
|
25
|
+
|
|
26
|
+
EXAMPLES:
|
|
27
|
+
# Search for shopping cart icons
|
|
28
|
+
ecomcoder asset search-icons --query="cart"
|
|
29
|
+
|
|
30
|
+
# Search for payment icons
|
|
31
|
+
ecomcoder asset search-icons --query="credit card"
|
|
32
|
+
|
|
33
|
+
# Search for social icons
|
|
34
|
+
ecomcoder asset search-icons --query="heart" --limit=5
|
|
35
|
+
|
|
36
|
+
USAGE IN LIQUID:
|
|
37
|
+
Icons are returned as CDN URLs. Use directly in your theme:
|
|
38
|
+
|
|
39
|
+
<img src="{{icon_url}}" alt="Icon" width="24" height="24">
|
|
40
|
+
|
|
41
|
+
Or download and customize:
|
|
42
|
+
|
|
43
|
+
ecomcoder asset upload --url=<icon_url>
|
|
44
|
+
|
|
45
|
+
CATEGORIES:
|
|
46
|
+
ecommerce: cart, bag, tag, truck, package, gift
|
|
47
|
+
payment: credit-card, dollar, percent
|
|
48
|
+
social: heart, star, share, thumbs-up
|
|
49
|
+
ui: menu, search, x, check, arrow
|
|
50
|
+
communication: mail, phone, message
|
|
51
|
+
`);
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
export async function run(argv = process.argv.slice(2)) {
|
|
55
|
+
if (hasHelpFlag(argv)) {
|
|
56
|
+
showHelp();
|
|
57
|
+
}
|
|
58
|
+
const args = parseArgs(argv);
|
|
59
|
+
if (!args.query) {
|
|
60
|
+
console.error(JSON.stringify({
|
|
61
|
+
success: false,
|
|
62
|
+
error: 'Missing required argument: --query'
|
|
63
|
+
}));
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const result = await AssetService.searchIcons({
|
|
68
|
+
query: args.query,
|
|
69
|
+
limit: args.limit ? parseInt(args.limit) : undefined
|
|
70
|
+
});
|
|
71
|
+
console.log(JSON.stringify(result, null, 2));
|
|
72
|
+
if (!result.success) {
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
console.error(JSON.stringify({
|
|
78
|
+
success: false,
|
|
79
|
+
error: error.message || 'Unknown error occurred'
|
|
80
|
+
}));
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=search-icons.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-icons.js","sourceRoot":"","sources":["../../../src/commands/asset/search-icons.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,SAAS,QAAQ;IACf,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2Cb,CAAC,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,OAAiB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9D,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,QAAQ,EAAE,CAAC;IACb,CAAC;IAED,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAE7B,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;YAC3B,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,oCAAoC;SAC5C,CAAC,CAAC,CAAC;QACJ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,WAAW,CAAC;YAC5C,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS;SACrD,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAE7C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;YAC3B,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,KAAK,CAAC,OAAO,IAAI,wBAAwB;SACjD,CAAC,CAAC,CAAC;QACJ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-stock.d.ts","sourceRoot":"","sources":["../../../src/commands/asset/search-stock.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA6CH,wBAAsB,GAAG,CAAC,IAAI,GAAE,MAAM,EAA0B,iBAoC/D"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search Stock Images Command
|
|
3
|
+
* Search free stock photos from Pexels API
|
|
4
|
+
*/
|
|
5
|
+
import { parseArgs, hasHelpFlag } from '../../lib/args-parser.js';
|
|
6
|
+
import { AssetService } from './service.js';
|
|
7
|
+
function showHelp() {
|
|
8
|
+
console.log(`
|
|
9
|
+
Search Stock Images (Pexels)
|
|
10
|
+
|
|
11
|
+
USAGE:
|
|
12
|
+
ecomcoder asset search-stock --query=<search> [OPTIONS]
|
|
13
|
+
|
|
14
|
+
OPTIONS:
|
|
15
|
+
--query <text> Search query (required)
|
|
16
|
+
--limit <number> Max results (default: 10, max: 80)
|
|
17
|
+
--orientation <type> Filter by orientation (landscape|portrait|square)
|
|
18
|
+
--size <size> Filter by size (large|medium|small)
|
|
19
|
+
--color <color> Filter by color (e.g., red, blue, green)
|
|
20
|
+
--help, -h Show this help message
|
|
21
|
+
|
|
22
|
+
SETUP:
|
|
23
|
+
Get your free API key at: https://www.pexels.com/api/
|
|
24
|
+
Set environment variable: export PEXELS_API_KEY=your-key-here
|
|
25
|
+
|
|
26
|
+
EXAMPLES:
|
|
27
|
+
# Search for mountains
|
|
28
|
+
ecomcoder asset search-stock --query="mountains"
|
|
29
|
+
|
|
30
|
+
# Landscape photos of ocean
|
|
31
|
+
ecomcoder asset search-stock --query="ocean" --orientation=landscape --limit=5
|
|
32
|
+
|
|
33
|
+
# Large photos of sunset
|
|
34
|
+
ecomcoder asset search-stock --query="sunset" --size=large
|
|
35
|
+
|
|
36
|
+
WORKFLOW:
|
|
37
|
+
1. Search for stock images
|
|
38
|
+
2. Use returned URL with: ecomcoder asset upload --url=<url>
|
|
39
|
+
3. Asset is uploaded to your Shopify store
|
|
40
|
+
|
|
41
|
+
RATE LIMITS:
|
|
42
|
+
Free tier: 200 requests/hour, 20,000 requests/month
|
|
43
|
+
`);
|
|
44
|
+
process.exit(0);
|
|
45
|
+
}
|
|
46
|
+
export async function run(argv = process.argv.slice(2)) {
|
|
47
|
+
if (hasHelpFlag(argv)) {
|
|
48
|
+
showHelp();
|
|
49
|
+
}
|
|
50
|
+
const args = parseArgs(argv);
|
|
51
|
+
if (!args.query) {
|
|
52
|
+
console.error(JSON.stringify({
|
|
53
|
+
success: false,
|
|
54
|
+
error: 'Missing required argument: --query'
|
|
55
|
+
}));
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const result = await AssetService.searchStock({
|
|
60
|
+
query: args.query,
|
|
61
|
+
limit: args.limit ? parseInt(args.limit) : undefined,
|
|
62
|
+
orientation: args.orientation,
|
|
63
|
+
size: args.size,
|
|
64
|
+
color: args.color
|
|
65
|
+
});
|
|
66
|
+
console.log(JSON.stringify(result, null, 2));
|
|
67
|
+
if (!result.success) {
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
console.error(JSON.stringify({
|
|
73
|
+
success: false,
|
|
74
|
+
error: error.message || 'Unknown error occurred'
|
|
75
|
+
}));
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=search-stock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-stock.js","sourceRoot":"","sources":["../../../src/commands/asset/search-stock.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,SAAS,QAAQ;IACf,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCb,CAAC,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,OAAiB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9D,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,QAAQ,EAAE,CAAC;IACb,CAAC;IAED,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAE7B,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;YAC3B,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,oCAAoC;SAC5C,CAAC,CAAC,CAAC;QACJ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,WAAW,CAAC;YAC5C,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS;YACpD,WAAW,EAAE,IAAI,CAAC,WAA8D;YAChF,IAAI,EAAE,IAAI,CAAC,IAAgD;YAC3D,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAE7C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;YAC3B,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,KAAK,CAAC,OAAO,IAAI,wBAAwB;SACjD,CAAC,CAAC,CAAC;QACJ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Following Service Layer Pattern
|
|
6
6
|
*/
|
|
7
7
|
import { ShopifyCredentials } from '../../lib/types.js';
|
|
8
|
-
import { CommandResult, UploadAssetInput, ListAssetsInput, GetAssetInput, DeleteAssetInput, ImportAssetsInput, FormattedAsset } from './types.js';
|
|
8
|
+
import { CommandResult, UploadAssetInput, ListAssetsInput, GetAssetInput, DeleteAssetInput, ImportAssetsInput, FormattedAsset, SearchStockInput, StockImage, SearchIconsInput, Icon } from './types.js';
|
|
9
9
|
export declare class AssetService {
|
|
10
10
|
/**
|
|
11
11
|
* Upload single asset to Shopify
|
|
@@ -46,5 +46,17 @@ export declare class AssetService {
|
|
|
46
46
|
failed: number;
|
|
47
47
|
errors: string[];
|
|
48
48
|
}>>;
|
|
49
|
+
/**
|
|
50
|
+
* Search stock images from Pexels
|
|
51
|
+
*/
|
|
52
|
+
static searchStock(input: SearchStockInput): Promise<CommandResult<{
|
|
53
|
+
images: StockImage[];
|
|
54
|
+
}>>;
|
|
55
|
+
/**
|
|
56
|
+
* Search icons from Lucide
|
|
57
|
+
*/
|
|
58
|
+
static searchIcons(input: SearchIconsInput): Promise<CommandResult<{
|
|
59
|
+
icons: Icon[];
|
|
60
|
+
}>>;
|
|
49
61
|
}
|
|
50
62
|
//# sourceMappingURL=service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/commands/asset/service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/commands/asset/service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAaxD,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EAMd,gBAAgB,EAChB,UAAU,EACV,gBAAgB,EAChB,IAAI,EACL,MAAM,YAAY,CAAC;AAEpB,qBAAa,YAAY;IACvB;;;;;;;OAOG;WACU,MAAM,CACjB,WAAW,EAAE,kBAAkB,EAC/B,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,aAAa,CAAC;QAAE,KAAK,EAAE,cAAc,CAAA;KAAE,CAAC,CAAC;IAiLpD;;OAEG;WACU,IAAI,CACf,WAAW,EAAE,kBAAkB,EAC/B,KAAK,GAAE,eAAoB,GAC1B,OAAO,CAAC,aAAa,CAAC;QAAE,MAAM,EAAE,cAAc,EAAE,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IAyChG;;OAEG;WACU,GAAG,CACd,WAAW,EAAE,kBAAkB,EAC/B,KAAK,EAAE,aAAa,GACnB,OAAO,CAAC,aAAa,CAAC;QAAE,KAAK,EAAE,cAAc,CAAA;KAAE,CAAC,CAAC;IA6BpD;;OAEG;WACU,MAAM,CACjB,WAAW,EAAE,kBAAkB,EAC/B,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,aAAa,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IA+BhD;;OAEG;WACU,MAAM,CACjB,WAAW,EAAE,kBAAkB,EAC/B,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAAC,aAAa,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IAmDjF;;OAEG;WACU,WAAW,CACtB,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,aAAa,CAAC;QAAE,MAAM,EAAE,UAAU,EAAE,CAAA;KAAE,CAAC,CAAC;IAiBnD;;OAEG;WACU,WAAW,CACtB,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,aAAa,CAAC;QAAE,KAAK,EAAE,IAAI,EAAE,CAAA;KAAE,CAAC,CAAC;CAgB7C"}
|
|
@@ -9,6 +9,7 @@ import * as fs from 'fs';
|
|
|
9
9
|
import * as path from 'path';
|
|
10
10
|
import FormData from 'form-data';
|
|
11
11
|
import { URL } from 'url';
|
|
12
|
+
import { downloadUrlToTemp } from './utils.js';
|
|
12
13
|
import { FILE_CREATE, FILES_LIST, FILE_GET, FILE_DELETE, STAGED_UPLOADS_CREATE } from './queries.js';
|
|
13
14
|
export class AssetService {
|
|
14
15
|
/**
|
|
@@ -20,18 +21,42 @@ export class AssetService {
|
|
|
20
21
|
* 3. Create file record in Shopify
|
|
21
22
|
*/
|
|
22
23
|
static async upload(credentials, input) {
|
|
24
|
+
let filePath;
|
|
25
|
+
let cleanup = null;
|
|
23
26
|
try {
|
|
27
|
+
// Validate: must provide either --file or --url
|
|
28
|
+
if (!input.file && !input.url) {
|
|
29
|
+
return {
|
|
30
|
+
success: false,
|
|
31
|
+
error: 'Must provide either --file or --url'
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (input.file && input.url) {
|
|
35
|
+
return {
|
|
36
|
+
success: false,
|
|
37
|
+
error: 'Cannot use both --file and --url'
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
// If URL provided, download to temp file
|
|
41
|
+
if (input.url) {
|
|
42
|
+
const downloaded = await downloadUrlToTemp(input.url);
|
|
43
|
+
filePath = downloaded.path;
|
|
44
|
+
cleanup = downloaded.cleanup;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
filePath = input.file;
|
|
48
|
+
}
|
|
24
49
|
// Step 1: Validate file exists
|
|
25
|
-
if (!fs.existsSync(
|
|
50
|
+
if (!fs.existsSync(filePath)) {
|
|
26
51
|
return {
|
|
27
52
|
success: false,
|
|
28
|
-
error: `File not found: ${
|
|
53
|
+
error: `File not found: ${filePath}`
|
|
29
54
|
};
|
|
30
55
|
}
|
|
31
56
|
// Step 2: Get file metadata
|
|
32
|
-
const stats = fs.statSync(
|
|
33
|
-
const fileName = path.basename(
|
|
34
|
-
const mimeType = getMimeType(
|
|
57
|
+
const stats = fs.statSync(filePath);
|
|
58
|
+
const fileName = path.basename(filePath);
|
|
59
|
+
const mimeType = getMimeType(filePath);
|
|
35
60
|
const fileSize = stats.size;
|
|
36
61
|
// Step 3: Detect content type
|
|
37
62
|
const contentType = input.contentType || detectContentType(mimeType);
|
|
@@ -56,7 +81,7 @@ export class AssetService {
|
|
|
56
81
|
// Step 5: Upload file to signed URL
|
|
57
82
|
// CRITICAL: GCS signed URLs require multipart/form-data with parameters
|
|
58
83
|
// Reference: https://community.shopify.com/c/shopify-apis-and-sdks/error-uploading-file-after-stageduploadscreate/td-p/1718315
|
|
59
|
-
const fileBuffer = fs.readFileSync(
|
|
84
|
+
const fileBuffer = fs.readFileSync(filePath);
|
|
60
85
|
const form = new FormData();
|
|
61
86
|
// Add parameters from stagedUploadsCreate response FIRST (required for GCS auth)
|
|
62
87
|
target.parameters.forEach(param => {
|
|
@@ -143,6 +168,12 @@ export class AssetService {
|
|
|
143
168
|
error: error.message || 'Unknown error during upload'
|
|
144
169
|
};
|
|
145
170
|
}
|
|
171
|
+
finally {
|
|
172
|
+
// Cleanup temp file if we downloaded from URL
|
|
173
|
+
if (cleanup) {
|
|
174
|
+
cleanup();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
146
177
|
}
|
|
147
178
|
/**
|
|
148
179
|
* List all assets
|
|
@@ -282,6 +313,44 @@ export class AssetService {
|
|
|
282
313
|
};
|
|
283
314
|
}
|
|
284
315
|
}
|
|
316
|
+
/**
|
|
317
|
+
* Search stock images from Pexels
|
|
318
|
+
*/
|
|
319
|
+
static async searchStock(input) {
|
|
320
|
+
try {
|
|
321
|
+
const { searchPexelsImages } = await import('./external-apis.js');
|
|
322
|
+
const images = await searchPexelsImages(input);
|
|
323
|
+
return {
|
|
324
|
+
success: true,
|
|
325
|
+
data: { images }
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
catch (error) {
|
|
329
|
+
return {
|
|
330
|
+
success: false,
|
|
331
|
+
error: error.message || 'Unknown error during stock image search'
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Search icons from Lucide
|
|
337
|
+
*/
|
|
338
|
+
static async searchIcons(input) {
|
|
339
|
+
try {
|
|
340
|
+
const { searchLucideIcons } = await import('./external-apis.js');
|
|
341
|
+
const icons = await searchLucideIcons(input);
|
|
342
|
+
return {
|
|
343
|
+
success: true,
|
|
344
|
+
data: { icons }
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
catch (error) {
|
|
348
|
+
return {
|
|
349
|
+
success: false,
|
|
350
|
+
error: error.message || 'Unknown error during icon search'
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
}
|
|
285
354
|
}
|
|
286
355
|
// Helper functions
|
|
287
356
|
function getMimeType(filePath) {
|