shopify-starter-kit 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/.agent/skills/shopify-apps/SKILL.md +47 -0
  2. package/.agent/skills/shopify-automation/SKILL.md +172 -0
  3. package/.agent/skills/shopify-development/README.md +60 -0
  4. package/.agent/skills/shopify-development/SKILL.md +368 -0
  5. package/.agent/skills/shopify-development/references/app-development.md +578 -0
  6. package/.agent/skills/shopify-development/references/extensions.md +555 -0
  7. package/.agent/skills/shopify-development/references/themes.md +498 -0
  8. package/.agent/skills/shopify-development/scripts/requirements.txt +19 -0
  9. package/.agent/skills/shopify-development/scripts/shopify_graphql.py +428 -0
  10. package/.agent/skills/shopify-development/scripts/shopify_init.py +441 -0
  11. package/.agent/skills/shopify-development/scripts/tests/test_shopify_init.py +379 -0
  12. package/bin/cli.js +3 -0
  13. package/package.json +32 -0
  14. package/src/index.js +116 -0
  15. package/templates/.agent/skills/shopify-apps/SKILL.md +47 -0
  16. package/templates/.agent/skills/shopify-automation/SKILL.md +172 -0
  17. package/templates/.agent/skills/shopify-development/README.md +60 -0
  18. package/templates/.agent/skills/shopify-development/SKILL.md +368 -0
  19. package/templates/.agent/skills/shopify-development/references/app-development.md +578 -0
  20. package/templates/.agent/skills/shopify-development/references/extensions.md +555 -0
  21. package/templates/.agent/skills/shopify-development/references/themes.md +498 -0
  22. package/templates/.agent/skills/shopify-development/scripts/requirements.txt +19 -0
  23. package/templates/.agent/skills/shopify-development/scripts/shopify_graphql.py +428 -0
  24. package/templates/.agent/skills/shopify-development/scripts/shopify_init.py +441 -0
  25. package/templates/.agent/skills/shopify-development/scripts/tests/test_shopify_init.py +379 -0
  26. package/templates/.devcontainer/devcontainer.json +27 -0
  27. package/templates/tests/playwright.config.ts +26 -0
  28. package/templates/tests/vitest.config.ts +9 -0
@@ -0,0 +1,555 @@
1
+ # Extensions Reference
2
+
3
+ Guide for building UI extensions and Shopify Functions.
4
+
5
+ ## Checkout UI Extensions
6
+
7
+ Customize checkout and thank-you pages with native-rendered components.
8
+
9
+ ### Extension Points
10
+
11
+ **Block Targets (Merchant-Configurable):**
12
+
13
+ - `purchase.checkout.block.render` - Main checkout
14
+ - `purchase.thank-you.block.render` - Thank you page
15
+
16
+ **Static Targets (Fixed Position):**
17
+
18
+ - `purchase.checkout.header.render-after`
19
+ - `purchase.checkout.contact.render-before`
20
+ - `purchase.checkout.shipping-option-list.render-after`
21
+ - `purchase.checkout.payment-method-list.render-after`
22
+ - `purchase.checkout.footer.render-before`
23
+
24
+ ### Setup
25
+
26
+ ```bash
27
+ shopify app generate extension --type checkout_ui_extension
28
+ ```
29
+
30
+ Configuration (`shopify.extension.toml`):
31
+
32
+ ```toml
33
+ api_version = "2026-01"
34
+ name = "gift-message"
35
+ type = "ui_extension"
36
+
37
+ [[extensions.targeting]]
38
+ target = "purchase.checkout.block.render"
39
+
40
+ [capabilities]
41
+ network_access = true
42
+ api_access = true
43
+ ```
44
+
45
+ ### Basic Example
46
+
47
+ ```javascript
48
+ import {
49
+ reactExtension,
50
+ BlockStack,
51
+ TextField,
52
+ Checkbox,
53
+ useApi,
54
+ } from "@shopify/ui-extensions-react/checkout";
55
+
56
+ export default reactExtension("purchase.checkout.block.render", () => (
57
+ <Extension />
58
+ ));
59
+
60
+ function Extension() {
61
+ const [message, setMessage] = useState("");
62
+ const [isGift, setIsGift] = useState(false);
63
+ const { applyAttributeChange } = useApi();
64
+
65
+ useEffect(() => {
66
+ if (isGift) {
67
+ applyAttributeChange({
68
+ type: "updateAttribute",
69
+ key: "gift_message",
70
+ value: message,
71
+ });
72
+ }
73
+ }, [message, isGift]);
74
+
75
+ return (
76
+ <BlockStack spacing="loose">
77
+ <Checkbox checked={isGift} onChange={setIsGift}>
78
+ This is a gift
79
+ </Checkbox>
80
+ {isGift && (
81
+ <TextField
82
+ label="Gift Message"
83
+ value={message}
84
+ onChange={setMessage}
85
+ multiline={3}
86
+ />
87
+ )}
88
+ </BlockStack>
89
+ );
90
+ }
91
+ ```
92
+
93
+ ### Common Hooks
94
+
95
+ **useApi:**
96
+
97
+ ```javascript
98
+ const { extensionPoint, shop, storefront, i18n, sessionToken } = useApi();
99
+ ```
100
+
101
+ **useCartLines:**
102
+
103
+ ```javascript
104
+ const lines = useCartLines();
105
+ lines.forEach((line) => {
106
+ console.log(line.merchandise.product.title, line.quantity);
107
+ });
108
+ ```
109
+
110
+ **useShippingAddress:**
111
+
112
+ ```javascript
113
+ const address = useShippingAddress();
114
+ console.log(address.city, address.countryCode);
115
+ ```
116
+
117
+ **useApplyCartLinesChange:**
118
+
119
+ ```javascript
120
+ const applyChange = useApplyCartLinesChange();
121
+
122
+ async function addItem() {
123
+ await applyChange({
124
+ type: "addCartLine",
125
+ merchandiseId: "gid://shopify/ProductVariant/123",
126
+ quantity: 1,
127
+ });
128
+ }
129
+ ```
130
+
131
+ ### Core Components
132
+
133
+ **Layout:**
134
+
135
+ - `BlockStack` - Vertical stacking
136
+ - `InlineStack` - Horizontal layout
137
+ - `Grid`, `GridItem` - Grid layout
138
+ - `View` - Container
139
+ - `Divider` - Separator
140
+
141
+ **Input:**
142
+
143
+ - `TextField` - Text input
144
+ - `Checkbox` - Boolean
145
+ - `Select` - Dropdown
146
+ - `DatePicker` - Date selection
147
+ - `Form` - Form wrapper
148
+
149
+ **Display:**
150
+
151
+ - `Text`, `Heading` - Typography
152
+ - `Banner` - Messages
153
+ - `Badge` - Status
154
+ - `Image` - Images
155
+ - `Link` - Hyperlinks
156
+ - `List`, `ListItem` - Lists
157
+
158
+ **Interactive:**
159
+
160
+ - `Button` - Actions
161
+ - `Modal` - Overlays
162
+ - `Pressable` - Click areas
163
+
164
+ ## Admin UI Extensions
165
+
166
+ Extend Shopify admin interface.
167
+
168
+ ### Admin Action
169
+
170
+ Custom actions on resource pages.
171
+
172
+ ```bash
173
+ shopify app generate extension --type admin_action
174
+ ```
175
+
176
+ ```javascript
177
+ import {
178
+ reactExtension,
179
+ AdminAction,
180
+ Button,
181
+ } from "@shopify/ui-extensions-react/admin";
182
+
183
+ export default reactExtension("admin.product-details.action.render", () => (
184
+ <Extension />
185
+ ));
186
+
187
+ function Extension() {
188
+ const { data } = useData();
189
+
190
+ async function handleExport() {
191
+ const response = await fetch("/api/export", {
192
+ method: "POST",
193
+ body: JSON.stringify({ productId: data.product.id }),
194
+ });
195
+ console.log("Exported:", await response.json());
196
+ }
197
+
198
+ return (
199
+ <AdminAction
200
+ title="Export Product"
201
+ primaryAction={<Button onPress={handleExport}>Export</Button>}
202
+ />
203
+ );
204
+ }
205
+ ```
206
+
207
+ **Targets:**
208
+
209
+ - `admin.product-details.action.render`
210
+ - `admin.order-details.action.render`
211
+ - `admin.customer-details.action.render`
212
+
213
+ ### Admin Block
214
+
215
+ Embedded content in admin pages.
216
+
217
+ ```javascript
218
+ import {
219
+ reactExtension,
220
+ BlockStack,
221
+ Text,
222
+ Badge,
223
+ } from "@shopify/ui-extensions-react/admin";
224
+
225
+ export default reactExtension("admin.product-details.block.render", () => (
226
+ <Extension />
227
+ ));
228
+
229
+ function Extension() {
230
+ const { data } = useData();
231
+ const [analytics, setAnalytics] = useState(null);
232
+
233
+ useEffect(() => {
234
+ fetchAnalytics(data.product.id).then(setAnalytics);
235
+ }, []);
236
+
237
+ return (
238
+ <BlockStack>
239
+ <Text variant="headingMd">Product Analytics</Text>
240
+ <Text>Views: {analytics?.views || 0}</Text>
241
+ <Text>Conversions: {analytics?.conversions || 0}</Text>
242
+ <Badge tone={analytics?.trending ? "success" : "info"}>
243
+ {analytics?.trending ? "Trending" : "Normal"}
244
+ </Badge>
245
+ </BlockStack>
246
+ );
247
+ }
248
+ ```
249
+
250
+ **Targets:**
251
+
252
+ - `admin.product-details.block.render`
253
+ - `admin.order-details.block.render`
254
+ - `admin.customer-details.block.render`
255
+
256
+ ## POS UI Extensions
257
+
258
+ Customize Point of Sale experience.
259
+
260
+ ### Smart Grid Tile
261
+
262
+ Quick access action on POS home screen.
263
+
264
+ ```javascript
265
+ import {
266
+ reactExtension,
267
+ SmartGridTile,
268
+ } from "@shopify/ui-extensions-react/pos";
269
+
270
+ export default reactExtension("pos.home.tile.render", () => <Extension />);
271
+
272
+ function Extension() {
273
+ function handlePress() {
274
+ // Navigate to custom workflow
275
+ }
276
+
277
+ return (
278
+ <SmartGridTile
279
+ title="Gift Cards"
280
+ subtitle="Manage gift cards"
281
+ onPress={handlePress}
282
+ />
283
+ );
284
+ }
285
+ ```
286
+
287
+ ### POS Modal
288
+
289
+ Full-screen workflow.
290
+
291
+ ```javascript
292
+ import {
293
+ reactExtension,
294
+ Screen,
295
+ BlockStack,
296
+ Button,
297
+ TextField,
298
+ } from "@shopify/ui-extensions-react/pos";
299
+
300
+ export default reactExtension("pos.home.modal.render", () => <Extension />);
301
+
302
+ function Extension() {
303
+ const { navigation } = useApi();
304
+ const [amount, setAmount] = useState("");
305
+
306
+ function handleIssue() {
307
+ // Issue gift card
308
+ navigation.pop();
309
+ }
310
+
311
+ return (
312
+ <Screen name="Gift Card" title="Issue Gift Card">
313
+ <BlockStack>
314
+ <TextField label="Amount" value={amount} onChange={setAmount} />
315
+ <TextField label="Recipient Email" />
316
+ <Button onPress={handleIssue}>Issue</Button>
317
+ </BlockStack>
318
+ </Screen>
319
+ );
320
+ }
321
+ ```
322
+
323
+ ## Customer Account Extensions
324
+
325
+ Customize customer account pages.
326
+
327
+ ### Order Status Extension
328
+
329
+ ```javascript
330
+ import {
331
+ reactExtension,
332
+ BlockStack,
333
+ Text,
334
+ Button,
335
+ } from "@shopify/ui-extensions-react/customer-account";
336
+
337
+ export default reactExtension(
338
+ "customer-account.order-status.block.render",
339
+ () => <Extension />,
340
+ );
341
+
342
+ function Extension() {
343
+ const { order } = useApi();
344
+
345
+ function handleReturn() {
346
+ // Initiate return
347
+ }
348
+
349
+ return (
350
+ <BlockStack>
351
+ <Text variant="headingMd">Need to return?</Text>
352
+ <Text>Start return for order {order.name}</Text>
353
+ <Button onPress={handleReturn}>Start Return</Button>
354
+ </BlockStack>
355
+ );
356
+ }
357
+ ```
358
+
359
+ **Targets:**
360
+
361
+ - `customer-account.order-status.block.render`
362
+ - `customer-account.order-index.block.render`
363
+ - `customer-account.profile.block.render`
364
+
365
+ ## Shopify Functions
366
+
367
+ Serverless backend customization.
368
+
369
+ ### Function Types
370
+
371
+ **Discounts:**
372
+
373
+ - `order_discount` - Order-level discounts
374
+ - `product_discount` - Product-specific discounts
375
+ - `shipping_discount` - Shipping discounts
376
+
377
+ **Payment Customization:**
378
+
379
+ - Hide/rename/reorder payment methods
380
+
381
+ **Delivery Customization:**
382
+
383
+ - Custom shipping options
384
+ - Delivery rules
385
+
386
+ **Validation:**
387
+
388
+ - Cart validation rules
389
+ - Checkout validation
390
+
391
+ ### Create Function
392
+
393
+ ```bash
394
+ shopify app generate extension --type function
395
+ ```
396
+
397
+ ### Order Discount Function
398
+
399
+ ```javascript
400
+ // input.graphql
401
+ query Input {
402
+ cart {
403
+ lines {
404
+ quantity
405
+ merchandise {
406
+ ... on ProductVariant {
407
+ product {
408
+ hasTag(tag: "bulk-discount")
409
+ }
410
+ }
411
+ }
412
+ }
413
+ }
414
+ }
415
+
416
+ // function.js
417
+ export default function orderDiscount(input) {
418
+ const targets = input.cart.lines
419
+ .filter(line => line.merchandise.product.hasTag)
420
+ .map(line => ({
421
+ productVariant: { id: line.merchandise.id }
422
+ }));
423
+
424
+ if (targets.length === 0) {
425
+ return { discounts: [] };
426
+ }
427
+
428
+ return {
429
+ discounts: [{
430
+ targets,
431
+ value: {
432
+ percentage: {
433
+ value: 10 // 10% discount
434
+ }
435
+ }
436
+ }]
437
+ };
438
+ }
439
+ ```
440
+
441
+ ### Payment Customization Function
442
+
443
+ ```javascript
444
+ export default function paymentCustomization(input) {
445
+ const hidePaymentMethods = input.cart.lines.some(
446
+ (line) => line.merchandise.product.hasTag,
447
+ );
448
+
449
+ if (!hidePaymentMethods) {
450
+ return { operations: [] };
451
+ }
452
+
453
+ return {
454
+ operations: [
455
+ {
456
+ hide: {
457
+ paymentMethodId: "gid://shopify/PaymentMethod/123",
458
+ },
459
+ },
460
+ ],
461
+ };
462
+ }
463
+ ```
464
+
465
+ ### Validation Function
466
+
467
+ ```javascript
468
+ export default function cartValidation(input) {
469
+ const errors = [];
470
+
471
+ // Max 5 items per cart
472
+ if (input.cart.lines.length > 5) {
473
+ errors.push({
474
+ localizedMessage: "Maximum 5 items allowed per order",
475
+ target: "cart",
476
+ });
477
+ }
478
+
479
+ // Min $50 for wholesale
480
+ const isWholesale = input.cart.lines.some(
481
+ (line) => line.merchandise.product.hasTag,
482
+ );
483
+
484
+ if (isWholesale && input.cart.cost.totalAmount.amount < 50) {
485
+ errors.push({
486
+ localizedMessage: "Wholesale orders require $50 minimum",
487
+ target: "cart",
488
+ });
489
+ }
490
+
491
+ return { errors };
492
+ }
493
+ ```
494
+
495
+ ## Network Requests
496
+
497
+ Extensions can call external APIs.
498
+
499
+ ```javascript
500
+ import { useApi } from "@shopify/ui-extensions-react/checkout";
501
+
502
+ function Extension() {
503
+ const { sessionToken } = useApi();
504
+
505
+ async function fetchData() {
506
+ const token = await sessionToken.get();
507
+
508
+ const response = await fetch("https://your-app.com/api/data", {
509
+ headers: {
510
+ Authorization: `Bearer ${token}`,
511
+ "Content-Type": "application/json",
512
+ },
513
+ });
514
+
515
+ return await response.json();
516
+ }
517
+ }
518
+ ```
519
+
520
+ ## Best Practices
521
+
522
+ **Performance:**
523
+
524
+ - Lazy load data
525
+ - Memoize expensive computations
526
+ - Use loading states
527
+ - Minimize re-renders
528
+
529
+ **UX:**
530
+
531
+ - Provide clear error messages
532
+ - Show loading indicators
533
+ - Validate inputs
534
+ - Support keyboard navigation
535
+
536
+ **Security:**
537
+
538
+ - Verify session tokens on backend
539
+ - Sanitize user input
540
+ - Use HTTPS for all requests
541
+ - Don't expose sensitive data
542
+
543
+ **Testing:**
544
+
545
+ - Test on development stores
546
+ - Verify mobile/desktop
547
+ - Check accessibility
548
+ - Test edge cases
549
+
550
+ ## Resources
551
+
552
+ - Checkout Extensions: https://shopify.dev/docs/api/checkout-extensions
553
+ - Admin Extensions: https://shopify.dev/docs/apps/admin/extensions
554
+ - Functions: https://shopify.dev/docs/apps/functions
555
+ - Components: https://shopify.dev/docs/api/checkout-ui-extensions/components