@webround/commerce 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +192 -2
- package/dist/account/account.d.ts +54 -0
- package/dist/account/account.js +40 -0
- package/dist/account/index.d.ts +3 -0
- package/dist/account/index.js +2 -0
- package/dist/addresses/api.d.ts +16 -0
- package/dist/addresses/api.js +13 -0
- package/dist/addresses/book.d.ts +40 -0
- package/dist/addresses/book.js +144 -0
- package/dist/addresses/index.d.ts +8 -0
- package/dist/addresses/index.js +5 -0
- package/dist/addresses/rules.d.ts +4 -0
- package/dist/addresses/rules.js +9 -0
- package/dist/addresses/types.d.ts +48 -0
- package/dist/addresses/types.js +6 -0
- package/dist/auth/api.d.ts +43 -0
- package/dist/auth/api.js +22 -0
- package/dist/auth/auth.d.ts +32 -0
- package/dist/auth/auth.js +23 -0
- package/dist/auth/cookies.d.ts +46 -0
- package/dist/auth/cookies.js +156 -0
- package/dist/auth/index.d.ts +14 -0
- package/dist/auth/index.js +8 -0
- package/dist/auth/renewal.d.ts +4 -0
- package/dist/auth/renewal.js +37 -0
- package/dist/auth/store.d.ts +70 -0
- package/dist/auth/store.js +284 -0
- package/dist/auth/types.d.ts +105 -0
- package/dist/auth/types.js +5 -0
- package/dist/auth/wake.d.ts +18 -0
- package/dist/auth/wake.js +23 -0
- package/dist/cache.d.ts +49 -0
- package/dist/cache.js +144 -0
- package/dist/canonical.d.ts +7 -0
- package/dist/canonical.js +32 -0
- package/dist/cart/api.d.ts +25 -0
- package/dist/cart/api.js +16 -0
- package/dist/cart/index.d.ts +10 -0
- package/dist/cart/index.js +6 -0
- package/dist/cart/lines.d.ts +15 -0
- package/dist/cart/lines.js +23 -0
- package/dist/cart/storage.d.ts +30 -0
- package/dist/cart/storage.js +82 -0
- package/dist/cart/store.d.ts +58 -0
- package/dist/cart/store.js +218 -0
- package/dist/cart/types.d.ts +194 -0
- package/dist/cart/types.js +11 -0
- package/dist/catalog/cached.d.ts +47 -0
- package/dist/catalog/cached.js +52 -0
- package/dist/catalog/catalog.d.ts +10 -0
- package/dist/catalog/catalog.js +7 -0
- package/dist/catalog/named.d.ts +3 -0
- package/dist/catalog/named.js +7 -0
- package/dist/catalog/products.d.ts +28 -0
- package/dist/catalog/products.js +12 -0
- package/dist/catalog/store-data.d.ts +13 -0
- package/dist/catalog/store-data.js +6 -0
- package/dist/catalog/types.d.ts +430 -0
- package/dist/catalog/types.js +4 -0
- package/dist/checkout/api.d.ts +14 -0
- package/dist/checkout/api.js +7 -0
- package/dist/checkout/errors.d.ts +23 -0
- package/dist/checkout/errors.js +18 -0
- package/dist/checkout/index.d.ts +10 -0
- package/dist/checkout/index.js +6 -0
- package/dist/checkout/return-urls.d.ts +7 -0
- package/dist/checkout/return-urls.js +11 -0
- package/dist/checkout/store.d.ts +98 -0
- package/dist/checkout/store.js +179 -0
- package/dist/checkout/types.d.ts +225 -0
- package/dist/checkout/types.js +28 -0
- package/dist/commerce.d.ts +55 -0
- package/dist/commerce.js +55 -0
- package/dist/customer-resources.d.ts +18 -0
- package/dist/customer-resources.js +40 -0
- package/dist/errors.d.ts +65 -0
- package/dist/errors.js +96 -0
- package/dist/http.d.ts +49 -0
- package/dist/http.js +94 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +22 -0
- package/dist/orders/api.d.ts +16 -0
- package/dist/orders/api.js +13 -0
- package/dist/orders/index.d.ts +6 -0
- package/dist/orders/index.js +3 -0
- package/dist/orders/orders.d.ts +19 -0
- package/dist/orders/orders.js +18 -0
- package/dist/orders/types.d.ts +88 -0
- package/dist/orders/types.js +4 -0
- package/dist/react/index.d.ts +23 -0
- package/dist/react/index.js +15 -0
- package/dist/react/use-account.d.ts +12 -0
- package/dist/react/use-account.js +9 -0
- package/dist/react/use-addresses.d.ts +20 -0
- package/dist/react/use-addresses.js +20 -0
- package/dist/react/use-auth.d.ts +24 -0
- package/dist/react/use-auth.js +20 -0
- package/dist/react/use-cart.d.ts +27 -0
- package/dist/react/use-cart.js +23 -0
- package/dist/react/use-checkout.d.ts +37 -0
- package/dist/react/use-checkout.js +33 -0
- package/dist/react/use-customer-resource.d.ts +5 -0
- package/dist/react/use-customer-resource.js +9 -0
- package/dist/react/use-orders.d.ts +14 -0
- package/dist/react/use-orders.js +6 -0
- package/dist/react/use-resource.d.ts +25 -0
- package/dist/react/use-resource.js +60 -0
- package/dist/react/use-returns.d.ts +14 -0
- package/dist/react/use-returns.js +7 -0
- package/dist/react/use-reviews.d.ts +14 -0
- package/dist/react/use-reviews.js +10 -0
- package/dist/react/use-shop-address.d.ts +12 -0
- package/dist/react/use-shop-address.js +39 -0
- package/dist/react/use-shop.d.ts +34 -0
- package/dist/react/use-shop.js +31 -0
- package/dist/react/use-wishlist.d.ts +15 -0
- package/dist/react/use-wishlist.js +12 -0
- package/dist/resource.d.ts +19 -0
- package/dist/resource.js +15 -0
- package/dist/returns/api.d.ts +27 -0
- package/dist/returns/api.js +19 -0
- package/dist/returns/index.d.ts +6 -0
- package/dist/returns/index.js +3 -0
- package/dist/returns/returns.d.ts +30 -0
- package/dist/returns/returns.js +31 -0
- package/dist/returns/rules.d.ts +7 -0
- package/dist/returns/rules.js +45 -0
- package/dist/returns/types.d.ts +99 -0
- package/dist/returns/types.js +2 -0
- package/dist/reviews/api.d.ts +19 -0
- package/dist/reviews/api.js +15 -0
- package/dist/reviews/index.d.ts +9 -0
- package/dist/reviews/index.js +5 -0
- package/dist/reviews/reviews.d.ts +23 -0
- package/dist/reviews/reviews.js +37 -0
- package/dist/reviews/rules.d.ts +8 -0
- package/dist/reviews/rules.js +7 -0
- package/dist/reviews/types.d.ts +54 -0
- package/dist/reviews/types.js +10 -0
- package/dist/shop/address-store.d.ts +14 -0
- package/dist/shop/address-store.js +28 -0
- package/dist/shop/address.d.ts +12 -0
- package/dist/shop/address.js +95 -0
- package/dist/shop/index.d.ts +16 -0
- package/dist/shop/index.js +9 -0
- package/dist/shop/question.d.ts +15 -0
- package/dist/shop/question.js +12 -0
- package/dist/shop/range.d.ts +7 -0
- package/dist/shop/range.js +38 -0
- package/dist/shop/sort.d.ts +19 -0
- package/dist/shop/sort.js +18 -0
- package/dist/shop/state.d.ts +47 -0
- package/dist/shop/state.js +51 -0
- package/dist/shop/store.d.ts +26 -0
- package/dist/shop/store.js +47 -0
- package/dist/shop/to-search.d.ts +14 -0
- package/dist/shop/to-search.js +53 -0
- package/dist/site.d.ts +7 -0
- package/dist/site.js +41 -0
- package/dist/store-kit.d.ts +39 -0
- package/dist/store-kit.js +81 -0
- package/dist/wishlist/api.d.ts +12 -0
- package/dist/wishlist/api.js +10 -0
- package/dist/wishlist/index.d.ts +7 -0
- package/dist/wishlist/index.js +4 -0
- package/dist/wishlist/types.d.ts +30 -0
- package/dist/wishlist/types.js +4 -0
- package/dist/wishlist/wishlist.d.ts +45 -0
- package/dist/wishlist/wishlist.js +84 -0
- package/package.json +67 -5
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useEffect, useMemo, useSyncExternalStore } from 'react';
|
|
2
|
+
export function addressActions(book) {
|
|
3
|
+
return {
|
|
4
|
+
save: (input) => book.save(input),
|
|
5
|
+
remember: (input) => book.remember(input),
|
|
6
|
+
update: (id, patch) => book.update(id, patch),
|
|
7
|
+
remove: (id) => book.remove(id),
|
|
8
|
+
setDefault: (id, kind) => book.setDefault(id, kind),
|
|
9
|
+
refresh: () => book.refresh(),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/** `commerce` is what `createCommerce` made (or `@webround/commerce/site`'s). Any number of components can use it: the book starts once. A server render says `unknown` and no addresses. */
|
|
13
|
+
export function useAddresses(commerce) {
|
|
14
|
+
const { addresses: book } = commerce;
|
|
15
|
+
const state = useSyncExternalStore(book.subscribe, book.getState, book.getState);
|
|
16
|
+
const actions = useMemo(() => addressActions(book), [book]);
|
|
17
|
+
useEffect(() => { void book.start(); }, [book]);
|
|
18
|
+
return { state, addresses: state.addresses, actions };
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=use-addresses.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Auth } from '../auth/auth.js';
|
|
2
|
+
import type { AuthState, AuthStatus, AuthStore, Customer } from '../auth/store.js';
|
|
3
|
+
import type { TwoFactorChallenge } from '../auth/types.js';
|
|
4
|
+
/** What changes the session. A call that fails THROWS what the store said (a wrong password, a validation list in `issues`): it belongs to the form that made it. */
|
|
5
|
+
export interface AuthActions {
|
|
6
|
+
signup: AuthStore['signup'];
|
|
7
|
+
login: AuthStore['login'];
|
|
8
|
+
verifyTwoFactor: AuthStore['verifyTwoFactor'];
|
|
9
|
+
cancelChallenge: AuthStore['cancelChallenge'];
|
|
10
|
+
logout: AuthStore['logout'];
|
|
11
|
+
}
|
|
12
|
+
export interface UseAuthResult {
|
|
13
|
+
state: AuthState;
|
|
14
|
+
/** `unknown` until it is known whether a customer is kept (and on a server render: no window, nobody to take back). */
|
|
15
|
+
status: AuthStatus;
|
|
16
|
+
customer: Customer | null;
|
|
17
|
+
/** The code of the authenticator app is wanted (status `challenge`). */
|
|
18
|
+
challenge: TwoFactorChallenge | null;
|
|
19
|
+
actions: AuthActions;
|
|
20
|
+
}
|
|
21
|
+
export declare function authActions(store: AuthStore): AuthActions;
|
|
22
|
+
/** `auth` is what `createAuth` made. Any number of components can use it: the customer is taken back once. */
|
|
23
|
+
export declare function useAuth(auth: Pick<Auth, 'store'>): UseAuthResult;
|
|
24
|
+
//# sourceMappingURL=use-auth.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useEffect, useMemo, useSyncExternalStore } from 'react';
|
|
2
|
+
export function authActions(store) {
|
|
3
|
+
return {
|
|
4
|
+
signup: (input, options) => store.signup(input, options),
|
|
5
|
+
login: (input) => store.login(input),
|
|
6
|
+
verifyTwoFactor: (code) => store.verifyTwoFactor(code),
|
|
7
|
+
cancelChallenge: () => store.cancelChallenge(),
|
|
8
|
+
logout: () => store.logout(),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
/** `auth` is what `createAuth` made. Any number of components can use it: the customer is taken back once. */
|
|
12
|
+
export function useAuth(auth) {
|
|
13
|
+
const { store } = auth;
|
|
14
|
+
const state = useSyncExternalStore(store.subscribe, store.getState, store.getState);
|
|
15
|
+
const actions = useMemo(() => authActions(store), [store]);
|
|
16
|
+
// Not in render: a server render asks nothing. `restore` is one call for whoever asks while it is under way, and nothing once it is known
|
|
17
|
+
useEffect(() => { void store.restore(); }, [store]);
|
|
18
|
+
return { state, status: state.status, customer: state.customer, challenge: state.challenge, actions };
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=use-auth.js.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { CartState, CartStore } from '../cart/store.js';
|
|
2
|
+
export interface CartActions {
|
|
3
|
+
add: CartStore['add'];
|
|
4
|
+
setQuantity: CartStore['setQuantity'];
|
|
5
|
+
remove: CartStore['remove'];
|
|
6
|
+
/** Empties the cart (a guest's and a customer's). */
|
|
7
|
+
clear: CartStore['clear'];
|
|
8
|
+
refresh: CartStore['refresh'];
|
|
9
|
+
}
|
|
10
|
+
export interface UseCartResult {
|
|
11
|
+
state: CartState;
|
|
12
|
+
/** How many items are in the cart: known before the store has priced anything. */
|
|
13
|
+
count: number;
|
|
14
|
+
/** What the store says the cart costs (null until it said); `state.isStale` when it is one change behind. */
|
|
15
|
+
priced: CartState['priced'];
|
|
16
|
+
actions: CartActions;
|
|
17
|
+
}
|
|
18
|
+
export declare function cartActions(store: CartStore): CartActions;
|
|
19
|
+
/**
|
|
20
|
+
* To step a quantity (a "+" button), read it from `state.lines`, not from `priced`: `lines` is what the cart is NOW (a change shows in it at once), `priced` is the store's answer, which can be one change behind
|
|
21
|
+
* (`state.isStale`), so three quick clicks on a "+" that reads `priced` ask for the same quantity three times.
|
|
22
|
+
*/
|
|
23
|
+
/** `commerce` is what `createCommerce` made (or `@webround/commerce/site`'s). Any number of components can use it: the cart starts once. A server render says `unknown` and zero items, as the first render in the browser does. */
|
|
24
|
+
export declare function useCart(commerce: {
|
|
25
|
+
cart: CartStore;
|
|
26
|
+
}): UseCartResult;
|
|
27
|
+
//# sourceMappingURL=use-cart.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { useEffect, useMemo, useSyncExternalStore } from 'react';
|
|
2
|
+
export function cartActions(store) {
|
|
3
|
+
return {
|
|
4
|
+
add: (line) => store.add(line),
|
|
5
|
+
setQuantity: (variantId, quantity) => store.setQuantity(variantId, quantity),
|
|
6
|
+
remove: (variantId) => store.remove(variantId),
|
|
7
|
+
clear: () => store.clear(),
|
|
8
|
+
refresh: () => store.refresh(),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* To step a quantity (a "+" button), read it from `state.lines`, not from `priced`: `lines` is what the cart is NOW (a change shows in it at once), `priced` is the store's answer, which can be one change behind
|
|
13
|
+
* (`state.isStale`), so three quick clicks on a "+" that reads `priced` ask for the same quantity three times.
|
|
14
|
+
*/
|
|
15
|
+
/** `commerce` is what `createCommerce` made (or `@webround/commerce/site`'s). Any number of components can use it: the cart starts once. A server render says `unknown` and zero items, as the first render in the browser does. */
|
|
16
|
+
export function useCart(commerce) {
|
|
17
|
+
const { cart } = commerce;
|
|
18
|
+
const state = useSyncExternalStore(cart.subscribe, cart.getState, cart.getState);
|
|
19
|
+
const actions = useMemo(() => cartActions(cart), [cart]);
|
|
20
|
+
useEffect(() => { void cart.start(); }, [cart]);
|
|
21
|
+
return { state, count: state.count, priced: state.priced, actions };
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=use-cart.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { CheckoutState, CheckoutStore } from '../checkout/store.js';
|
|
2
|
+
export interface CheckoutActions {
|
|
3
|
+
setDeliveryMethod: CheckoutStore['setDeliveryMethod'];
|
|
4
|
+
setShippingAddress: CheckoutStore['setShippingAddress'];
|
|
5
|
+
setBillingAddress: CheckoutStore['setBillingAddress'];
|
|
6
|
+
selectShippingMethod: CheckoutStore['selectShippingMethod'];
|
|
7
|
+
setPromotionCodes: CheckoutStore['setPromotionCodes'];
|
|
8
|
+
setAdditionalData: CheckoutStore['setAdditionalData'];
|
|
9
|
+
setEmail: CheckoutStore['setEmail'];
|
|
10
|
+
setInvoice: CheckoutStore['setInvoice'];
|
|
11
|
+
/** Asks the preview now (what it asked automatically is asked again). Throws what the store refuses. */
|
|
12
|
+
quote: CheckoutStore['quote'];
|
|
13
|
+
/** Starts the payment; give the customer the `url` it answers (`location.assign(url)`). Throws what the store refuses. */
|
|
14
|
+
pay: CheckoutStore['pay'];
|
|
15
|
+
reset: CheckoutStore['reset'];
|
|
16
|
+
/** The payment is done (the success page): empties the cart and forgets the checkout. */
|
|
17
|
+
complete: CheckoutStore['complete'];
|
|
18
|
+
}
|
|
19
|
+
export interface UseCheckoutOptions {
|
|
20
|
+
/**
|
|
21
|
+
* Ask the preview by itself when the cart or what the customer chose changes (default: yes). Not for an empty cart, and not again for what already failed (ask again with `actions.quote`). A refusal is not thrown
|
|
22
|
+
* here: it is in `state.error`.
|
|
23
|
+
*/
|
|
24
|
+
autoQuote?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface UseCheckoutResult {
|
|
27
|
+
state: CheckoutState;
|
|
28
|
+
/** What the store says it costs (null until it said); `state.isStale` when it is the answer to something the customer has since changed. */
|
|
29
|
+
quote: CheckoutState['quote'];
|
|
30
|
+
actions: CheckoutActions;
|
|
31
|
+
}
|
|
32
|
+
export declare function checkoutActions(store: CheckoutStore): CheckoutActions;
|
|
33
|
+
/** `commerce` is what `createCommerce` made (or `@webround/commerce/site`'s). Reading `commerce.checkout` needs the checkout API's address. */
|
|
34
|
+
export declare function useCheckout(commerce: {
|
|
35
|
+
checkout: CheckoutStore;
|
|
36
|
+
}, options?: UseCheckoutOptions): UseCheckoutResult;
|
|
37
|
+
//# sourceMappingURL=use-checkout.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { useEffect, useMemo, useSyncExternalStore } from 'react';
|
|
2
|
+
export function checkoutActions(store) {
|
|
3
|
+
return {
|
|
4
|
+
setDeliveryMethod: (variantId, method) => store.setDeliveryMethod(variantId, method),
|
|
5
|
+
setShippingAddress: (address) => store.setShippingAddress(address),
|
|
6
|
+
setBillingAddress: (address) => store.setBillingAddress(address),
|
|
7
|
+
selectShippingMethod: (id) => store.selectShippingMethod(id),
|
|
8
|
+
setPromotionCodes: (codes) => store.setPromotionCodes(codes),
|
|
9
|
+
setAdditionalData: (data) => store.setAdditionalData(data),
|
|
10
|
+
setEmail: (email) => store.setEmail(email),
|
|
11
|
+
setInvoice: (invoice) => store.setInvoice(invoice),
|
|
12
|
+
quote: (options) => store.quote(options),
|
|
13
|
+
pay: (returnUrls) => store.pay(returnUrls),
|
|
14
|
+
reset: () => store.reset(),
|
|
15
|
+
complete: () => store.complete(),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/** `commerce` is what `createCommerce` made (or `@webround/commerce/site`'s). Reading `commerce.checkout` needs the checkout API's address. */
|
|
19
|
+
export function useCheckout(commerce, options = {}) {
|
|
20
|
+
const { checkout } = commerce;
|
|
21
|
+
const autoQuote = options.autoQuote ?? true;
|
|
22
|
+
const state = useSyncExternalStore(checkout.subscribe, checkout.getState, checkout.getState);
|
|
23
|
+
const actions = useMemo(() => checkoutActions(checkout), [checkout]);
|
|
24
|
+
useEffect(() => { checkout.start(); }, [checkout]);
|
|
25
|
+
// Which questions were asked is the store's to remember (one for all the components): a refusal is not asked again by itself, and the same question is never asked twice
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (!autoQuote)
|
|
28
|
+
return;
|
|
29
|
+
checkout.ensureQuote().catch(() => { });
|
|
30
|
+
}, [checkout, autoQuote, state.requestKey, state.lineCount]);
|
|
31
|
+
return { state, quote: state.quote, actions };
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=use-checkout.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Auth } from '../auth/auth.js';
|
|
2
|
+
import type { Resource } from '../resource.js';
|
|
3
|
+
import { type UseResourceOptions, type UseResourceResult } from './use-resource.js';
|
|
4
|
+
export declare function useCustomerResource<T>(auth: Pick<Auth, 'store'>, make: () => Resource<T> | null, options?: UseResourceOptions): UseResourceResult<T>;
|
|
5
|
+
//# sourceMappingURL=use-customer-resource.d.ts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { useSyncExternalStore } from 'react';
|
|
2
|
+
import { useResource } from './use-resource.js';
|
|
3
|
+
// A resource that is about the logged-in customer, shown by a component: the same as `useResource`, plus that the component follows who is logged in. Nobody logged in is no resource (`idle`), and logging in or out draws
|
|
4
|
+
// the component again with the right one (the cache forgets what was the customer's when they go).
|
|
5
|
+
export function useCustomerResource(auth, make, options) {
|
|
6
|
+
useSyncExternalStore(auth.store.subscribe, auth.store.getState, auth.store.getState);
|
|
7
|
+
return useResource(make(), options);
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=use-customer-resource.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Auth } from '../auth/auth.js';
|
|
2
|
+
import type { Orders } from '../orders/orders.js';
|
|
3
|
+
import type { Order, OrderPage, PageQuery, Subscription, SubscriptionPage } from '../orders/types.js';
|
|
4
|
+
import type { UseResourceOptions, UseResourceResult } from './use-resource.js';
|
|
5
|
+
type Source = {
|
|
6
|
+
auth: Pick<Auth, 'store'>;
|
|
7
|
+
orders: Orders;
|
|
8
|
+
};
|
|
9
|
+
export declare const useOrders: (commerce: Source, query?: PageQuery, options?: UseResourceOptions) => UseResourceResult<OrderPage>;
|
|
10
|
+
export declare const useOrder: (commerce: Source, id: string | null | undefined) => UseResourceResult<Order>;
|
|
11
|
+
export declare const useSubscriptions: (commerce: Source, query?: PageQuery, options?: UseResourceOptions) => UseResourceResult<SubscriptionPage>;
|
|
12
|
+
export declare const useSubscription: (commerce: Source, id: string | null | undefined) => UseResourceResult<Subscription>;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=use-orders.d.ts.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { useCustomerResource } from './use-customer-resource.js';
|
|
2
|
+
export const useOrders = (commerce, query, options = { keepPrevious: true }) => useCustomerResource(commerce.auth, () => commerce.orders.list(query), options);
|
|
3
|
+
export const useOrder = (commerce, id) => useCustomerResource(commerce.auth, () => (id ? commerce.orders.get(id) : null));
|
|
4
|
+
export const useSubscriptions = (commerce, query, options = { keepPrevious: true }) => useCustomerResource(commerce.auth, () => commerce.orders.subscriptions.list(query), options);
|
|
5
|
+
export const useSubscription = (commerce, id) => useCustomerResource(commerce.auth, () => (id ? commerce.orders.subscriptions.get(id) : null));
|
|
6
|
+
//# sourceMappingURL=use-orders.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Resource } from '../resource.js';
|
|
2
|
+
export interface UseResourceOptions {
|
|
3
|
+
/**
|
|
4
|
+
* When the question changes (another page of the results, another search), keep showing the answer of the one before until the new one comes, instead of nothing: `data` is that
|
|
5
|
+
* answer and `isStale` says it is not the one asked for. Off by default: what is shown is always the answer to what is asked.
|
|
6
|
+
*/
|
|
7
|
+
keepPrevious?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface UseResourceResult<T> {
|
|
10
|
+
/** `idle`: nothing is asked (no resource was given). `pending`: the answer is being waited for. `ready`: it is there. `error`: it could not be had. */
|
|
11
|
+
status: 'idle' | 'pending' | 'ready' | 'error';
|
|
12
|
+
/** The answer to what is asked, or (with `keepPrevious`, while the new one is awaited) the answer to the question before; undefined when there is none. */
|
|
13
|
+
data: T | undefined;
|
|
14
|
+
/** Why it failed (a `CommerceError` for what the store did, or a network error): set with `status: 'error'`, undefined otherwise. */
|
|
15
|
+
error: unknown;
|
|
16
|
+
/** The answer to what is asked is being waited for. */
|
|
17
|
+
isFetching: boolean;
|
|
18
|
+
/** `data` is the answer to an earlier question (`keepPrevious`), not to the one asked now. */
|
|
19
|
+
isStale: boolean;
|
|
20
|
+
/** Asks again after an error. It does nothing in any other state: what is there is not asked for again (to forget it, invalidate it in the catalog). */
|
|
21
|
+
retry: () => void;
|
|
22
|
+
}
|
|
23
|
+
/** A resource asked for by a component: `null`/`undefined` is "not asked yet" (a slug that is not known, a search that is not made). */
|
|
24
|
+
export declare function useResource<T>(resource: Resource<T> | null | undefined, options?: UseResourceOptions): UseResourceResult<T>;
|
|
25
|
+
//# sourceMappingURL=use-resource.d.ts.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useSyncExternalStore } from 'react';
|
|
2
|
+
const NOTHING = { status: 'idle' };
|
|
3
|
+
const noSubscription = () => () => undefined;
|
|
4
|
+
/** A resource asked for by a component: `null`/`undefined` is "not asked yet" (a slug that is not known, a search that is not made). */
|
|
5
|
+
export function useResource(resource, options = {}) {
|
|
6
|
+
const keepPrevious = options.keepPrevious === true;
|
|
7
|
+
const key = resource?.key;
|
|
8
|
+
// A resource is made again at every render, and the same key is the same question: only a new key is a new one (what is subscribed to must not change on every render)
|
|
9
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
10
|
+
const asked = useMemo(() => resource ?? null, [key]);
|
|
11
|
+
const subscribe = useCallback((listener) => (asked ? asked.subscribe(listener) : noSubscription()), [asked]);
|
|
12
|
+
const read = useCallback(() => (asked ? asked.snapshot() : NOTHING), [asked]);
|
|
13
|
+
// The server has the same state as the client: what the cache holds when it renders (a prerender fills it before)
|
|
14
|
+
const snapshot = useSyncExternalStore(subscribe, read, read);
|
|
15
|
+
// Asks when the question is there, and gives it up when it is gone: a question nobody waits for any more is not asked (the cache sees to that)
|
|
16
|
+
const waiting = useRef(null);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (!asked)
|
|
19
|
+
return;
|
|
20
|
+
const controller = (waiting.current = new AbortController());
|
|
21
|
+
if (asked.snapshot().status !== 'ready')
|
|
22
|
+
asked.load({ signal: controller.signal }).catch(() => undefined); // the failure is the state of the key, read above
|
|
23
|
+
return () => { controller.abort(); if (waiting.current === controller)
|
|
24
|
+
waiting.current = null; };
|
|
25
|
+
}, [asked]);
|
|
26
|
+
// What is watched was forgotten (it was invalidated in the catalog): it is asked again, so that what is on the screen is never "nothing" for good
|
|
27
|
+
const forgotten = asked !== null && snapshot.status === 'idle';
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (forgotten && waiting.current && asked && asked.snapshot().status === 'idle')
|
|
30
|
+
asked.load({ signal: waiting.current.signal }).catch(() => undefined);
|
|
31
|
+
}, [forgotten, asked]);
|
|
32
|
+
const retrying = useRef(null);
|
|
33
|
+
useEffect(() => () => { retrying.current?.abort(); retrying.current = null; }, [asked]);
|
|
34
|
+
const retry = useCallback(() => {
|
|
35
|
+
if (!asked || asked.snapshot().status !== 'error')
|
|
36
|
+
return;
|
|
37
|
+
retrying.current?.abort();
|
|
38
|
+
const controller = (retrying.current = new AbortController());
|
|
39
|
+
asked.load({ signal: controller.signal }).catch(() => undefined);
|
|
40
|
+
}, [asked]);
|
|
41
|
+
// The last answer that was shown, for `keepPrevious`: kept once it is on the screen
|
|
42
|
+
const shown = useRef(undefined);
|
|
43
|
+
const hasShown = useRef(false);
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (snapshot.status === 'ready') {
|
|
46
|
+
shown.current = snapshot.data;
|
|
47
|
+
hasShown.current = true;
|
|
48
|
+
}
|
|
49
|
+
}, [snapshot]);
|
|
50
|
+
if (!asked)
|
|
51
|
+
return { status: 'idle', data: undefined, error: undefined, isFetching: false, isStale: false, retry };
|
|
52
|
+
if (snapshot.status === 'ready')
|
|
53
|
+
return { status: 'ready', data: snapshot.data, error: undefined, isFetching: false, isStale: false, retry };
|
|
54
|
+
if (snapshot.status === 'error')
|
|
55
|
+
return { status: 'error', data: undefined, error: snapshot.error, isFetching: false, isStale: false, retry };
|
|
56
|
+
// `idle` here is a question that is about to be asked (the effect has not run yet): it is awaited, there is no frame in which it is "nothing"
|
|
57
|
+
const stale = keepPrevious && hasShown.current;
|
|
58
|
+
return { status: 'pending', data: stale ? shown.current : undefined, error: undefined, isFetching: true, isStale: stale, retry };
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=use-resource.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Auth } from '../auth/auth.js';
|
|
2
|
+
import type { Returns } from '../returns/returns.js';
|
|
3
|
+
import type { GuestReturnSession, PageQuery, ReturnRequest, ReturnRequestPage } from '../returns/types.js';
|
|
4
|
+
import { type UseResourceOptions, type UseResourceResult } from './use-resource.js';
|
|
5
|
+
type Source = {
|
|
6
|
+
auth: Pick<Auth, 'store'>;
|
|
7
|
+
returns: Returns;
|
|
8
|
+
};
|
|
9
|
+
export declare const useReturnRequests: (commerce: Source, query?: PageQuery, options?: UseResourceOptions) => UseResourceResult<ReturnRequestPage>;
|
|
10
|
+
export declare const useReturnRequest: (commerce: Source, id: string | null | undefined) => UseResourceResult<ReturnRequest>;
|
|
11
|
+
/** The order a guest's link opens (the `token` of the page's address; none yet is no question). */
|
|
12
|
+
export declare const useGuestReturnSession: (commerce: Pick<Source, "returns">, token: string | null | undefined) => UseResourceResult<GuestReturnSession>;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=use-returns.d.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { useCustomerResource } from './use-customer-resource.js';
|
|
2
|
+
import { useResource } from './use-resource.js';
|
|
3
|
+
export const useReturnRequests = (commerce, query, options = { keepPrevious: true }) => useCustomerResource(commerce.auth, () => commerce.returns.list(query), options);
|
|
4
|
+
export const useReturnRequest = (commerce, id) => useCustomerResource(commerce.auth, () => (id ? commerce.returns.get(id) : null));
|
|
5
|
+
/** The order a guest's link opens (the `token` of the page's address; none yet is no question). */
|
|
6
|
+
export const useGuestReturnSession = (commerce, token) => useResource(token ? commerce.returns.guest.session(token) : null);
|
|
7
|
+
//# sourceMappingURL=use-returns.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Auth } from '../auth/auth.js';
|
|
2
|
+
import { type ReviewAbility } from '../reviews/rules.js';
|
|
3
|
+
import type { Reviews } from '../reviews/reviews.js';
|
|
4
|
+
import type { MyReviewPage, MyReviewsQuery } from '../reviews/types.js';
|
|
5
|
+
import type { UseResourceOptions, UseResourceResult } from './use-resource.js';
|
|
6
|
+
type Source = {
|
|
7
|
+
auth: Pick<Auth, 'store'>;
|
|
8
|
+
reviews: Reviews;
|
|
9
|
+
};
|
|
10
|
+
export declare const useMyReviews: (commerce: Source, query?: MyReviewsQuery, options?: UseResourceOptions) => UseResourceResult<MyReviewPage>;
|
|
11
|
+
/** Who can write a review now: a guest has to log in, a customer whose address is not verified has to verify it, one whose is can. It follows the session. */
|
|
12
|
+
export declare function useReviewAbility(commerce: Pick<Source, 'auth'>): ReviewAbility;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=use-reviews.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { useSyncExternalStore } from 'react';
|
|
2
|
+
import { reviewAbility } from '../reviews/rules.js';
|
|
3
|
+
import { useCustomerResource } from './use-customer-resource.js';
|
|
4
|
+
export const useMyReviews = (commerce, query, options = { keepPrevious: true }) => useCustomerResource(commerce.auth, () => commerce.reviews.mine(query), options);
|
|
5
|
+
/** Who can write a review now: a guest has to log in, a customer whose address is not verified has to verify it, one whose is can. It follows the session. */
|
|
6
|
+
export function useReviewAbility(commerce) {
|
|
7
|
+
const state = useSyncExternalStore(commerce.auth.store.subscribe, commerce.auth.store.getState, commerce.auth.store.getState);
|
|
8
|
+
return reviewAbility(state);
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=use-reviews.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AddressOptions } from '../shop/address.js';
|
|
2
|
+
import type { ShopStore } from '../shop/store.js';
|
|
3
|
+
export interface UseShopAddressOptions extends AddressOptions {
|
|
4
|
+
/** The query string of the address NOW, as the router gives it (`location.search`). */
|
|
5
|
+
search: string;
|
|
6
|
+
/** Goes to this query string, on the same page, adding a history entry (`navigate({ search })` of react-router). */
|
|
7
|
+
navigate: (search: string) => void;
|
|
8
|
+
/** The collection the page is for (from its route): it is not in the query. */
|
|
9
|
+
collectionId?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function useShopAddress(options: UseShopAddressOptions): ShopStore;
|
|
12
|
+
//# sourceMappingURL=use-shop-address.d.ts.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { useEffect, useMemo, useRef } from 'react';
|
|
2
|
+
import { createAddressShopStore } from '../shop/address-store.js';
|
|
3
|
+
export function useShopAddress(options) {
|
|
4
|
+
const { search, collectionId, limit } = options;
|
|
5
|
+
// What the port calls is always the latest the site gave, without the store being made again at every render
|
|
6
|
+
const navigate = useRef(options.navigate);
|
|
7
|
+
navigate.current = options.navigate;
|
|
8
|
+
const listeners = useRef(new Set());
|
|
9
|
+
// What the address says now: what the router said last, or what was written since (until the router says it too)
|
|
10
|
+
const shown = useRef(search);
|
|
11
|
+
const routerSaid = useRef(search);
|
|
12
|
+
// The router says something else than before (the back button, a link): THAT is the address, already in this render (no frame with the old one). Only a change of what the router says counts:
|
|
13
|
+
// a render that comes between a write and the router's answer must not take the address back.
|
|
14
|
+
if (routerSaid.current !== search) {
|
|
15
|
+
routerSaid.current = search;
|
|
16
|
+
shown.current = search;
|
|
17
|
+
}
|
|
18
|
+
const port = useMemo(() => ({
|
|
19
|
+
read: () => shown.current,
|
|
20
|
+
write(next) {
|
|
21
|
+
shown.current = next;
|
|
22
|
+
for (const listener of [...listeners.current])
|
|
23
|
+
listener();
|
|
24
|
+
navigate.current(next);
|
|
25
|
+
},
|
|
26
|
+
subscribe(listener) {
|
|
27
|
+
listeners.current.add(listener);
|
|
28
|
+
return () => { listeners.current.delete(listener); };
|
|
29
|
+
},
|
|
30
|
+
}), []);
|
|
31
|
+
// Whoever listens (another component with the same store) is told that the address may have changed: if what the shop says is the same, it is the same state and nothing is drawn again
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
for (const listener of [...listeners.current])
|
|
34
|
+
listener();
|
|
35
|
+
}, [search]);
|
|
36
|
+
// A new store when the page's collection or the shop's limit change: it is the same address read with other defaults
|
|
37
|
+
return useMemo(() => createAddressShopStore(port, { collectionId, limit }), [port, collectionId, limit]);
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=use-shop-address.js.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { CachedCatalog } from '../catalog/cached.js';
|
|
2
|
+
import type { ProductPage, ProductSearch, StoreDataResponse } from '../catalog/types.js';
|
|
3
|
+
import { type SortOption } from '../shop/sort.js';
|
|
4
|
+
import type { ShopState } from '../shop/state.js';
|
|
5
|
+
import { type ShopActions, type ShopStore } from '../shop/store.js';
|
|
6
|
+
import type { SearchContext } from '../shop/to-search.js';
|
|
7
|
+
import { type UseResourceResult } from './use-resource.js';
|
|
8
|
+
export interface UseShopOptions {
|
|
9
|
+
catalog: CachedCatalog;
|
|
10
|
+
/** What the question needs besides what the customer chose: the currency, the language, the cadence, what the products are loaded with. */
|
|
11
|
+
context: SearchContext;
|
|
12
|
+
/** The state the shop starts in (only when the hook keeps the state itself: it is not read again). */
|
|
13
|
+
initial?: ShopState;
|
|
14
|
+
/** Where the state lives, when it is not in memory in the hook (an address bar, a store the page owns). */
|
|
15
|
+
store?: ShopStore;
|
|
16
|
+
/** While a new question is awaited, keep showing the answer to the one before (marked `isStale`), so a listing does not empty at every click. On by default. */
|
|
17
|
+
keepPrevious?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface UseShopResult {
|
|
20
|
+
/** What the customer chose. */
|
|
21
|
+
state: ShopState;
|
|
22
|
+
/** What changes it. */
|
|
23
|
+
actions: ShopActions;
|
|
24
|
+
/** The store's own data (its tags, collections, filters, currencies): what the controls are drawn from. */
|
|
25
|
+
storeData: UseResourceResult<StoreDataResponse>;
|
|
26
|
+
/** The orders that can be offered now (with the store's data in hand, and a text or not); none until it is. */
|
|
27
|
+
sortOptions: SortOption[];
|
|
28
|
+
/** The question the catalog is being asked now, or null while the store's data is awaited. */
|
|
29
|
+
question: ProductSearch | null;
|
|
30
|
+
/** The products. While the store's data is awaited this is `pending` (or its error, with a `retry` that asks for the store again). */
|
|
31
|
+
results: UseResourceResult<ProductPage>;
|
|
32
|
+
}
|
|
33
|
+
export declare function useShop(options: UseShopOptions): UseShopResult;
|
|
34
|
+
//# sourceMappingURL=use-shop.d.ts.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useCallback, useMemo, useRef, useSyncExternalStore } from 'react';
|
|
2
|
+
import { canonicalJson } from '../canonical.js';
|
|
3
|
+
import { shopQuestion } from '../shop/question.js';
|
|
4
|
+
import { sortOptionsOf } from '../shop/sort.js';
|
|
5
|
+
import { createShopStore, shopActions } from '../shop/store.js';
|
|
6
|
+
import { useResource } from './use-resource.js';
|
|
7
|
+
export function useShop(options) {
|
|
8
|
+
const { catalog, context, keepPrevious = true } = options;
|
|
9
|
+
// The state: in memory, in the hook, unless a store was given
|
|
10
|
+
const own = useRef(null);
|
|
11
|
+
if (!options.store && !own.current)
|
|
12
|
+
own.current = createShopStore(options.initial);
|
|
13
|
+
const store = options.store ?? own.current;
|
|
14
|
+
const state = useSyncExternalStore(store.subscribe, store.getState, store.getState);
|
|
15
|
+
const actions = useMemo(() => shopActions(store), [store]);
|
|
16
|
+
const storeData = useResource(catalog.resource.storeData.get(context.langCode === undefined ? undefined : { langCode: context.langCode }));
|
|
17
|
+
const data = storeData.data?.data;
|
|
18
|
+
// A new `context` object at every render is the same context: only what is in it makes a new question
|
|
19
|
+
const contextKey = canonicalJson(context);
|
|
20
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
21
|
+
const asked = useMemo(() => shopQuestion(catalog, data, state, context), [catalog, data, state, contextKey]);
|
|
22
|
+
const products = useResource(asked?.resource ?? null, { keepPrevious });
|
|
23
|
+
const sortOptions = useMemo(() => (data ? sortOptionsOf(data) : []), [data]);
|
|
24
|
+
// With no question yet the products are waiting for the store's data (or failed with it): say that, so the screen has one thing to look at
|
|
25
|
+
const retry = useCallback(() => storeData.retry(), [storeData]);
|
|
26
|
+
const results = asked
|
|
27
|
+
? products
|
|
28
|
+
: { status: storeData.status === 'error' ? 'error' : 'pending', data: undefined, error: storeData.error, isFetching: storeData.status !== 'error', isStale: false, retry };
|
|
29
|
+
return { state, actions, storeData, sortOptions, question: asked?.question ?? null, results };
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=use-shop.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Wishlist, type WishlistState } from '../wishlist/wishlist.js';
|
|
2
|
+
export interface UseWishlistResult {
|
|
3
|
+
state: WishlistState;
|
|
4
|
+
count: number;
|
|
5
|
+
/** Whether a variant is in the wishlist. */
|
|
6
|
+
has(variantId: string): boolean;
|
|
7
|
+
/** The switch: adds a variant that is not in the wishlist, removes one that is. Throws what the store refuses; `LOGIN_REQUIRED` for a guest. */
|
|
8
|
+
toggle: Wishlist['toggle'];
|
|
9
|
+
refresh: Wishlist['refresh'];
|
|
10
|
+
}
|
|
11
|
+
/** `commerce` is what `createCommerce` made (or `@webround/commerce/site`'s). Any number of components can use it (a heart on each product): the wishlist starts once. A server render says `unknown` and nothing in it. */
|
|
12
|
+
export declare function useWishlist(commerce: {
|
|
13
|
+
wishlist: Wishlist;
|
|
14
|
+
}): UseWishlistResult;
|
|
15
|
+
//# sourceMappingURL=use-wishlist.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useSyncExternalStore } from 'react';
|
|
2
|
+
import { isInWishlist } from '../wishlist/wishlist.js';
|
|
3
|
+
/** `commerce` is what `createCommerce` made (or `@webround/commerce/site`'s). Any number of components can use it (a heart on each product): the wishlist starts once. A server render says `unknown` and nothing in it. */
|
|
4
|
+
export function useWishlist(commerce) {
|
|
5
|
+
const { wishlist } = commerce;
|
|
6
|
+
const state = useSyncExternalStore(wishlist.subscribe, wishlist.getState, wishlist.getState);
|
|
7
|
+
useEffect(() => { void wishlist.start(); }, [wishlist]);
|
|
8
|
+
const has = useCallback((variantId) => isInWishlist(state, variantId), [state.variantIds]);
|
|
9
|
+
const actions = useMemo(() => ({ toggle: (variantId) => wishlist.toggle(variantId), refresh: () => wishlist.refresh() }), [wishlist]);
|
|
10
|
+
return { state, count: state.count, has, toggle: actions.toggle, refresh: actions.refresh };
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=use-wishlist.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Cache, type CacheSnapshot, type LoadOptions } from './cache.js';
|
|
2
|
+
import type { CallOptions } from './catalog/types.js';
|
|
3
|
+
/** The cache's view of ONE question: its key, how to ask it, how it stands now, and how to be told when that changes. What a framework's binding is made of. */
|
|
4
|
+
export interface Resource<T> {
|
|
5
|
+
key: string;
|
|
6
|
+
/** The answer: from the cache if it has it, joining the request under way if there is one, else asking. */
|
|
7
|
+
load(options?: LoadOptions): Promise<T>;
|
|
8
|
+
/** How the question stands now. It never asks anything, and is the same object until it changes. */
|
|
9
|
+
snapshot(): CacheSnapshot<T>;
|
|
10
|
+
subscribe(listener: () => void): () => void;
|
|
11
|
+
}
|
|
12
|
+
/** What tells one store's questions from another's in the cache: where the backend is, and which store. */
|
|
13
|
+
export type ResourceIdentity = {
|
|
14
|
+
baseUrl: string;
|
|
15
|
+
storeId: string;
|
|
16
|
+
};
|
|
17
|
+
/** Makes the resources of one backend and store, over one cache. */
|
|
18
|
+
export declare function createResourceFactory(cache: Cache, identity: ResourceIdentity): <T>(call: string, subject: string | undefined, params: unknown, fetch: (options: CallOptions) => Promise<T>) => Resource<T>;
|
|
19
|
+
//# sourceMappingURL=resource.d.ts.map
|
package/dist/resource.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { cacheKey } from './cache.js';
|
|
2
|
+
/** Makes the resources of one backend and store, over one cache. */
|
|
3
|
+
export function createResourceFactory(cache, identity) {
|
|
4
|
+
return function resource(call, subject, params, fetch) {
|
|
5
|
+
const key = cacheKey({ base: identity.baseUrl, storeId: identity.storeId, call, subject, params });
|
|
6
|
+
return {
|
|
7
|
+
key,
|
|
8
|
+
// The signal the request gets is the cache's (aborted when nobody is waiting any more); the caller's own is only for that caller
|
|
9
|
+
load: (options) => cache.load(key, (signal) => fetch({ signal }), options),
|
|
10
|
+
snapshot: () => cache.snapshot(key),
|
|
11
|
+
subscribe: (listener) => cache.subscribe(key, listener),
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=resource.js.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { HttpClient } from '../http.js';
|
|
2
|
+
import type { CallOptions } from '../catalog/types.js';
|
|
3
|
+
import type { AccessTokenOptions } from '../auth/api.js';
|
|
4
|
+
import type { CreateGuestReturnInput, CreateReturnInput, GuestReturnSession, GuestVerifyAnswer, GuestVerifyInput, PageQuery, ReturnRequest, ReturnRequestPage } from './types.js';
|
|
5
|
+
export interface ReturnApi {
|
|
6
|
+
/** `GET /store-customer-return-requests` (JWT): the customer's requests, a page at a time. */
|
|
7
|
+
list(input?: PageQuery, options?: CallOptions & AccessTokenOptions): Promise<ReturnRequestPage>;
|
|
8
|
+
/** `GET /store-customer-return-requests/:id` (JWT). */
|
|
9
|
+
get(id: string, options?: CallOptions & AccessTokenOptions): Promise<ReturnRequest>;
|
|
10
|
+
/** `POST /store-customer-return-requests` (JWT): asks to return some of the items of an order (`201`). The store emails the customer (and the shop). */
|
|
11
|
+
create(input: CreateReturnInput, options?: CallOptions & AccessTokenOptions): Promise<ReturnRequest>;
|
|
12
|
+
/** `DELETE /store-customer-return-requests/:id` (JWT): cancels a request that is still `pending` (400 for any other); gives back the one it cancelled. */
|
|
13
|
+
cancel(id: string, options?: CallOptions & AccessTokenOptions): Promise<ReturnRequest>;
|
|
14
|
+
/**
|
|
15
|
+
* `POST …/guest/verify` (no JWT): asks the store to email a link to the address of the order, for a guest. It answers the same whether the order exists or not. An order that belongs to an account is refused
|
|
16
|
+
* (400): its customer has to log in.
|
|
17
|
+
*/
|
|
18
|
+
verifyGuest(input: GuestVerifyInput, options?: CallOptions): Promise<GuestVerifyAnswer>;
|
|
19
|
+
/** `GET …/guest/session?token=` (no JWT): the order the link's token opens. 401 for a token that is not good or has ended. */
|
|
20
|
+
guestSession(token: string, options?: CallOptions): Promise<GuestReturnSession>;
|
|
21
|
+
/** `POST …/guest` (no JWT, the token in the body): a guest asks to return some of the items of their order (`201`). */
|
|
22
|
+
createGuest(input: CreateGuestReturnInput, options?: CallOptions): Promise<ReturnRequest>;
|
|
23
|
+
/** `DELETE …/guest/:id?token=` (no JWT): cancels a guest's request that is still `pending`. */
|
|
24
|
+
cancelGuest(id: string, token: string, options?: CallOptions): Promise<ReturnRequest>;
|
|
25
|
+
}
|
|
26
|
+
export declare function createReturnApi(http: HttpClient): ReturnApi;
|
|
27
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// The calls of commerce-core that are about returns (`/store-customer-return-requests`), each asking one thing and giving back what the store answers, unchanged. A customer's need their JWT. A guest's need none: what proves
|
|
2
|
+
// who they are is a TOKEN, in the link the store emailed to the address of the order (`guest/verify` asks for the email; the site's page `/returns?token=…` is where the link leads, and reads the token from the address).
|
|
3
|
+
const PATH = '/store-customer-return-requests';
|
|
4
|
+
const bearer = (options) => (options?.accessToken ? { Authorization: `Bearer ${options.accessToken}` } : {});
|
|
5
|
+
const part = (id) => encodeURIComponent(id);
|
|
6
|
+
const query = (q) => ({ page: q?.page, limit: q?.limit, sortBy: q?.sortBy, sortDirection: q?.sortDirection, lang: q?.lang });
|
|
7
|
+
export function createReturnApi(http) {
|
|
8
|
+
return {
|
|
9
|
+
list: (input, options) => http.request({ path: PATH, query: query(input), headers: bearer(options), signal: options?.signal }),
|
|
10
|
+
get: (id, options) => http.request({ path: `${PATH}/${part(id)}`, headers: bearer(options), signal: options?.signal }),
|
|
11
|
+
create: (input, options) => http.request({ method: 'POST', path: PATH, body: input, headers: bearer(options), signal: options?.signal }),
|
|
12
|
+
cancel: (id, options) => http.request({ method: 'DELETE', path: `${PATH}/${part(id)}`, headers: bearer(options), signal: options?.signal }),
|
|
13
|
+
verifyGuest: (input, options) => http.request({ method: 'POST', path: `${PATH}/guest/verify`, body: input, signal: options?.signal }),
|
|
14
|
+
guestSession: (token, options) => http.request({ path: `${PATH}/guest/session`, query: { token }, signal: options?.signal }),
|
|
15
|
+
createGuest: (input, options) => http.request({ method: 'POST', path: `${PATH}/guest`, body: input, signal: options?.signal }),
|
|
16
|
+
cancelGuest: (id, token, options) => http.request({ method: 'DELETE', path: `${PATH}/guest/${part(id)}`, query: { token }, signal: options?.signal }),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { createReturnApi } from './api.js';
|
|
2
|
+
export type { ReturnApi } from './api.js';
|
|
3
|
+
export { createReturns } from './returns.js';
|
|
4
|
+
export type { Returns } from './returns.js';
|
|
5
|
+
export type { CreateGuestReturnInput, CreateReturnInput, GuestOrderItem, GuestReturnSession, GuestVerifyAnswer, GuestVerifyInput, ReturnItem, ReturnItemInput, ReturnRequest, ReturnRequestPage, ReturnStatus, } from './types.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|