@magicstoreai/hydrogen 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MagicStore
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,100 @@
1
+ # @magicstoreai/hydrogen
2
+
3
+ React building blocks for MagicStore storefronts, on top of
4
+ [`@magicstoreai/storefront-client`](../storefront-client). The backend is the same for every
5
+ storefront; this package is the part every storefront would otherwise write again.
6
+
7
+ | Entry | What | Runs |
8
+ | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
9
+ | `@magicstoreai/hydrogen` | `MagicStoreProvider`, `useCustomer`, `useCart`, `useWishlist`, `useAnalytics`, `useVariantSelection`, `ProductProvider`, `<Money>`, `<Image>`, `<Pagination>` | client (`"use client"`) |
10
+ | `@magicstoreai/hydrogen/core` | The same logic without React: `CartController`, `CustomerSessionController`, `WishlistController`, `AnalyticsController`, `formatMoney`, variant selection | anywhere |
11
+ | `@magicstoreai/hydrogen/server` | `createWebhookHandler`, `verifyWebhookSignature`, `nextCacheFetch`, cache tags | server, edge |
12
+ | `@magicstoreai/hydrogen/seo` | `pageMeta`, `productJsonLd`, `breadcrumbJsonLd`, `jsonLdScript` | anywhere |
13
+
14
+ Every export with its props or signature, an example and the API operations it calls:
15
+ [CATALOGUE.md](CATALOGUE.md) — generated from the sources (`pnpm --filter @magicstoreai/hydrogen
16
+ catalogue`) and shipped in the package. A test fails when it is stale or a component or hook has no
17
+ `@example` in its TSDoc; `@wraps Controller` gives a hook its controller's operations.
18
+
19
+ ## A storefront in a few lines
20
+
21
+ ```tsx
22
+ 'use client';
23
+ import { MagicStoreProvider, Money, useCart, useVariantSelection } from '@magicstoreai/hydrogen';
24
+
25
+ export function Providers({ shop, children }) {
26
+ return (
27
+ <MagicStoreProvider shopDomain="shop.example.uz" shop={shop} locale="uz">
28
+ {children}
29
+ </MagicStoreProvider>
30
+ );
31
+ }
32
+
33
+ export function BuyBox({ product }) {
34
+ const { selectedVariant, setOption, isAvailable } = useVariantSelection(product);
35
+ const { addLine, status } = useCart();
36
+ return (
37
+ <>
38
+ <Money data={selectedVariant?.price ?? product.price} />
39
+ {product.options.map((option) =>
40
+ option.values.map((value) => (
41
+ <button
42
+ key={value}
43
+ disabled={!isAvailable(option.name, value)}
44
+ onClick={() => setOption(option.name, value)}
45
+ >
46
+ {value}
47
+ </button>
48
+ )),
49
+ )}
50
+ <button
51
+ disabled={!selectedVariant?.availableForSale || status === 'updating'}
52
+ onClick={() => addLine({ productId: product.id, variantId: selectedVariant!.id })}
53
+ >
54
+ Add to cart
55
+ </button>
56
+ </>
57
+ );
58
+ }
59
+ ```
60
+
61
+ ## What it takes care of
62
+
63
+ - **Customer.** OTP, Telegram `initData`, OQ and Click sign-in; the session is kept in storage and the
64
+ hourly access token is refreshed before it expires — one refresh for every caller waiting.
65
+ - **Cart.** The cart id is kept, never shown; the first add creates the cart; quantity changes show
66
+ at once and roll back if the server refuses; changes go out in order; a cart the server no longer
67
+ has is dropped. On sign-in the cart becomes the customer's (merged into theirs if they had one);
68
+ on sign-out it stays with the customer.
69
+ - **Wishlist.** A guest's list lives in the browser and moves into the customer's list at sign-in.
70
+ - **Money.** `shop.moneyFormat` and the locale decide the symbol and its place (`12 500 сум`,
71
+ `$129.99`). Amounts are never rounded on the client.
72
+ - **Analytics.** Page, product, collection views and searches, batched; the visitor id also goes out
73
+ as `X-Session-Id`, so carts and orders join the visit. Cart and checkout steps are recorded by the
74
+ server.
75
+
76
+ ## Next.js cache + webhooks
77
+
78
+ ```ts
79
+ // lib/magicstore.ts — server side
80
+ import { createStorefrontClient } from '@magicstoreai/storefront-client';
81
+ import { nextCacheFetch } from '@magicstoreai/hydrogen/server';
82
+
83
+ export const api = createStorefrontClient({
84
+ shopDomain: process.env.SHOP_DOMAIN!,
85
+ fetch: nextCacheFetch(),
86
+ });
87
+
88
+ // app/api/magicstore/webhook/route.ts
89
+ import { revalidateTag } from 'next/cache';
90
+ import { createWebhookHandler } from '@magicstoreai/hydrogen/server';
91
+
92
+ export const POST = createWebhookHandler({
93
+ secret: process.env.MAGICSTORE_WEBHOOK_SECRET!,
94
+ revalidateTag,
95
+ });
96
+ ```
97
+
98
+ Public reads are cached under `magicstore:shop | catalog | pages | home`; the matching webhook topic
99
+ revalidates them. Anything personal (a customer token on the call, carts, checkouts, orders) is
100
+ `no-store`.