@redotech/redo-hydrogen 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/cjs/index.js +11 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/esm/index.js +11 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/types.d.ts +57 -0
- package/package.json +45 -0
- package/rollup.config.js +41 -0
- package/src/components/redo-checkout-buttons.tsx +163 -0
- package/src/index.ts +23 -0
- package/src/providers/redo-coverage-client.tsx +157 -0
- package/src/types.ts +40 -0
- package/src/utils/cart.ts +195 -0
- package/src/utils/react-utils.ts +50 -0
- package/src/utils/security.ts +13 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { useFetcher } from "@remix-run/react";
|
|
2
|
+
import { CartReturn } from "@shopify/hydrogen";
|
|
3
|
+
import { createContext, ReactNode, useContext, useEffect, useState } from "react";
|
|
4
|
+
import { CartProductVariantFragment, CartAttributeKey, CartInfoToEnable, RedoContextValue, RedoCoverageClient } from "../types";
|
|
5
|
+
import { REDO_PUBLIC_API_HOSTNAME_LOCAL } from "../utils/security";
|
|
6
|
+
import { addProductToCartIfNeeded, removeProductFromCartIfNeeded, setCartRedoEnabledAttribute, useFetcherWithPromise } from "../utils/cart";
|
|
7
|
+
|
|
8
|
+
const DEFAULT_REDO_CONTEXT_VALUE: RedoContextValue = {
|
|
9
|
+
enabled: false,
|
|
10
|
+
loading: true,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const RedoContext = createContext(DEFAULT_REDO_CONTEXT_VALUE);
|
|
14
|
+
|
|
15
|
+
const RedoProvider = ({
|
|
16
|
+
cart,
|
|
17
|
+
storeId,
|
|
18
|
+
children
|
|
19
|
+
}: {
|
|
20
|
+
cart: CartReturn,
|
|
21
|
+
storeId: string,
|
|
22
|
+
children: ReactNode,
|
|
23
|
+
}): ReactNode => {
|
|
24
|
+
const [cartProduct, setCartProduct] = useState();
|
|
25
|
+
const [cartAttribute, setCartAttribute] = useState<CartAttributeKey>();
|
|
26
|
+
const [cartInfoToEnable, setCartInfoToEnable] = useState<CartInfoToEnable>();
|
|
27
|
+
const [loading, setLoading] = useState<boolean>(true);
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
fetch(`http://${REDO_PUBLIC_API_HOSTNAME_LOCAL}/v2.2/stores/${storeId}/coverage-products`, {
|
|
31
|
+
method: 'POST',
|
|
32
|
+
headers: {
|
|
33
|
+
"Content-Type": "application/json"
|
|
34
|
+
},
|
|
35
|
+
body: JSON.stringify({
|
|
36
|
+
cart: {
|
|
37
|
+
lineItems: cart.lines.nodes.map((cartLine) => ({
|
|
38
|
+
id: cartLine.id,
|
|
39
|
+
originalPrice: {
|
|
40
|
+
amount: cartLine.merchandise?.price?.amount,
|
|
41
|
+
currency: cartLine.merchandise?.price?.currencyCode
|
|
42
|
+
},
|
|
43
|
+
priceTotal: {
|
|
44
|
+
amount: cartLine.cost?.totalAmount?.amount,
|
|
45
|
+
currency: cartLine.cost?.totalAmount?.currencyCode
|
|
46
|
+
},
|
|
47
|
+
product: {
|
|
48
|
+
id: cartLine.merchandise?.product?.id
|
|
49
|
+
},
|
|
50
|
+
variant: {
|
|
51
|
+
id: cartLine.merchandise?.id
|
|
52
|
+
},
|
|
53
|
+
quantity: cartLine.quantity,
|
|
54
|
+
})),
|
|
55
|
+
priceTotal: {
|
|
56
|
+
amount: cart.cost?.totalAmount?.amount,
|
|
57
|
+
currency: cart.cost?.totalAmount?.currencyCode
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
customer: {
|
|
61
|
+
id: cart.buyerIdentity?.customer?.id || '',
|
|
62
|
+
country: cart.buyerIdentity?.countryCode
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
.then(async (res) => {
|
|
67
|
+
let json = await res.json();
|
|
68
|
+
|
|
69
|
+
setLoading(false);
|
|
70
|
+
|
|
71
|
+
setCartInfoToEnable(json.cartInfoToEnable);
|
|
72
|
+
// setCartInfoToEnable(json.coverageProducts[0].cartInfoToEnable);
|
|
73
|
+
})
|
|
74
|
+
}, [cart]);
|
|
75
|
+
|
|
76
|
+
const contextVal: RedoContextValue = {
|
|
77
|
+
enabled: true,
|
|
78
|
+
loading,
|
|
79
|
+
storeId,
|
|
80
|
+
cartInfoToEnable,
|
|
81
|
+
cart,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<RedoContext.Provider value={contextVal}>
|
|
86
|
+
{children}
|
|
87
|
+
</RedoContext.Provider>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const useRedoCoverageClient = (): RedoCoverageClient => {
|
|
92
|
+
const redoContext = useContext(RedoContext);
|
|
93
|
+
const fetcher = useFetcherWithPromise();
|
|
94
|
+
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
if(redoContext.loading || !redoContext.cartInfoToEnable) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
removeProductFromCartIfNeeded({
|
|
100
|
+
fetcher,
|
|
101
|
+
cart: redoContext.cart,
|
|
102
|
+
cartInfoToEnable: redoContext.cartInfoToEnable
|
|
103
|
+
});
|
|
104
|
+
}, [redoContext.loading])
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
enable: async () => {
|
|
108
|
+
if(redoContext.loading || !redoContext.cartInfoToEnable) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
let addProductResult = await addProductToCartIfNeeded({
|
|
112
|
+
fetcher,
|
|
113
|
+
cart: redoContext.cart,
|
|
114
|
+
cartInfoToEnable: redoContext.cartInfoToEnable,
|
|
115
|
+
});
|
|
116
|
+
await setCartRedoEnabledAttribute({
|
|
117
|
+
fetcher,
|
|
118
|
+
cartInfoToEnable: redoContext.cartInfoToEnable,
|
|
119
|
+
enabled: true
|
|
120
|
+
});
|
|
121
|
+
return true;
|
|
122
|
+
},
|
|
123
|
+
disable: async () => {
|
|
124
|
+
if(!redoContext.cartInfoToEnable) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
await removeProductFromCartIfNeeded({
|
|
128
|
+
fetcher,
|
|
129
|
+
cart: redoContext.cart,
|
|
130
|
+
cartInfoToEnable: redoContext.cartInfoToEnable
|
|
131
|
+
});
|
|
132
|
+
await setCartRedoEnabledAttribute({
|
|
133
|
+
fetcher,
|
|
134
|
+
cartInfoToEnable: redoContext.cartInfoToEnable,
|
|
135
|
+
enabled: false
|
|
136
|
+
});
|
|
137
|
+
return true;
|
|
138
|
+
},
|
|
139
|
+
get enabled() {
|
|
140
|
+
return redoContext.enabled;
|
|
141
|
+
},
|
|
142
|
+
get price() {
|
|
143
|
+
return Number(redoContext.cartInfoToEnable?.selectedVariant.price.amount);
|
|
144
|
+
},
|
|
145
|
+
get cartProduct() {
|
|
146
|
+
return redoContext.cartInfoToEnable?.selectedVariant;
|
|
147
|
+
},
|
|
148
|
+
get cartAttribute() {
|
|
149
|
+
return redoContext.cartInfoToEnable?.cartAttribute
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export {
|
|
155
|
+
RedoProvider,
|
|
156
|
+
useRedoCoverageClient
|
|
157
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { CartReturn } from "@shopify/hydrogen";
|
|
2
|
+
import { ProductVariant } from "@shopify/hydrogen-react/storefront-api-types";
|
|
3
|
+
|
|
4
|
+
type CartProductVariantFragment = Omit<ProductVariant,
|
|
5
|
+
"components" | "metafields" | "quantityPriceBreaks" | "quantityRule" | "requiresComponents" | "requiresShipping" | "storeAvailability" | "taxable" | "weightUnit"
|
|
6
|
+
>;
|
|
7
|
+
|
|
8
|
+
type CartAttributeKey = string;
|
|
9
|
+
|
|
10
|
+
interface RedoCoverageClient {
|
|
11
|
+
enable(): Promise<boolean>;
|
|
12
|
+
disable(): Promise<boolean>;
|
|
13
|
+
get enabled(): boolean;
|
|
14
|
+
get price(): number;
|
|
15
|
+
get cartProduct(): CartProductVariantFragment | undefined
|
|
16
|
+
get cartAttribute(): CartAttributeKey | undefined
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type CartInfoToEnable = {
|
|
20
|
+
productId: string,
|
|
21
|
+
variantId: string,
|
|
22
|
+
cartAttribute: CartAttributeKey,
|
|
23
|
+
selectedVariant: CartProductVariantFragment
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type RedoContextValue = {
|
|
27
|
+
enabled: boolean,
|
|
28
|
+
loading: boolean,
|
|
29
|
+
storeId?: string,
|
|
30
|
+
cartInfoToEnable?: CartInfoToEnable,
|
|
31
|
+
cart?: CartReturn
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type {
|
|
35
|
+
CartAttributeKey,
|
|
36
|
+
CartInfoToEnable,
|
|
37
|
+
RedoContextValue,
|
|
38
|
+
RedoCoverageClient,
|
|
39
|
+
CartProductVariantFragment
|
|
40
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { FetcherWithComponents, useFetcher } from "@remix-run/react";
|
|
2
|
+
import { CartInfoToEnable } from "../types";
|
|
3
|
+
import { CartForm, CartReturn } from "@shopify/hydrogen";
|
|
4
|
+
import { CartLine } from "@shopify/hydrogen-react/storefront-api-types";
|
|
5
|
+
import type { AppData } from '@remix-run/react/dist/data';
|
|
6
|
+
import React from 'react'
|
|
7
|
+
|
|
8
|
+
const DEFAULT_REDO_ENABLED_CART_ATTRIBUTE = 'redo_opted_in_from_cart';
|
|
9
|
+
|
|
10
|
+
const addProductToCartIfNeeded = async ({
|
|
11
|
+
cart,
|
|
12
|
+
fetcher,
|
|
13
|
+
cartInfoToEnable
|
|
14
|
+
}: {
|
|
15
|
+
cart: CartReturn | undefined,
|
|
16
|
+
fetcher: FetcherWithComponents<unknown>,
|
|
17
|
+
cartInfoToEnable: CartInfoToEnable
|
|
18
|
+
}) => {
|
|
19
|
+
if(!cart) {
|
|
20
|
+
return await addProductToCart({ fetcher, cartInfoToEnable });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const redoProductsInCart = cart.lines.nodes.filter((cartLine) => {
|
|
24
|
+
return cartLine.merchandise.product.vendor === 're:do';
|
|
25
|
+
});
|
|
26
|
+
const correctRedoProductInCart = redoProductsInCart?.filter((cartLine) => {
|
|
27
|
+
return cartLine.merchandise.id === `gid://shopify/ProductVariant/${cartInfoToEnable.variantId}`;
|
|
28
|
+
});
|
|
29
|
+
if(redoProductsInCart.length === 0) {
|
|
30
|
+
return await addProductToCart({ fetcher, cartInfoToEnable });
|
|
31
|
+
} else if (redoProductsInCart.length === 1 && correctRedoProductInCart.length === 1 && correctRedoProductInCart[0].quantity === 1) {
|
|
32
|
+
// No action needed
|
|
33
|
+
return;
|
|
34
|
+
} else {
|
|
35
|
+
let isSuccess = true;
|
|
36
|
+
|
|
37
|
+
await removeLinesFromCart({ fetcher, lineIds: redoProductsInCart.map((cartLine) => cartLine.id) });
|
|
38
|
+
await addProductToCart({ fetcher, cartInfoToEnable });
|
|
39
|
+
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const removeLinesFromCart = async ({
|
|
45
|
+
fetcher,
|
|
46
|
+
lineIds
|
|
47
|
+
}: {
|
|
48
|
+
fetcher: FetcherWithComponents<unknown>,
|
|
49
|
+
lineIds: string[]
|
|
50
|
+
}) => {
|
|
51
|
+
const formInput = {
|
|
52
|
+
action: CartForm.ACTIONS.LinesRemove,
|
|
53
|
+
inputs: {
|
|
54
|
+
lineIds
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
await fetcher.submit(
|
|
59
|
+
{
|
|
60
|
+
[CartForm.INPUT_NAME]: JSON.stringify(formInput),
|
|
61
|
+
},
|
|
62
|
+
{method: 'POST', action: '/cart'},
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const removeProductFromCartIfNeeded = async ({
|
|
67
|
+
cart,
|
|
68
|
+
fetcher,
|
|
69
|
+
cartInfoToEnable
|
|
70
|
+
}: {
|
|
71
|
+
cart: CartReturn | undefined,
|
|
72
|
+
fetcher: FetcherWithComponents<unknown>,
|
|
73
|
+
cartInfoToEnable: CartInfoToEnable
|
|
74
|
+
}) => {
|
|
75
|
+
if(!cart) {
|
|
76
|
+
console.error('No cart');
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const redoProductsInCart = cart.lines.nodes.filter((cartLine) => {
|
|
81
|
+
return cartLine.merchandise.product.vendor === 're:do';
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
if(redoProductsInCart.length !== 0) {
|
|
85
|
+
await removeLinesFromCart({ fetcher, lineIds: redoProductsInCart.map((cartLine) => cartLine.id) });
|
|
86
|
+
} else {
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const addProductToCart = async ({
|
|
91
|
+
fetcher,
|
|
92
|
+
cartInfoToEnable
|
|
93
|
+
}: {
|
|
94
|
+
fetcher: FetcherWithComponents<unknown>,
|
|
95
|
+
cartInfoToEnable: CartInfoToEnable
|
|
96
|
+
}) => {
|
|
97
|
+
const redoProductLine = {
|
|
98
|
+
"merchandiseId": `gid://shopify/ProductVariant/${cartInfoToEnable.variantId}`,
|
|
99
|
+
"quantity": 1,
|
|
100
|
+
"selectedVariant": cartInfoToEnable.selectedVariant
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const formInput = {
|
|
104
|
+
action: CartForm.ACTIONS.LinesAdd,
|
|
105
|
+
inputs: {
|
|
106
|
+
lines: [
|
|
107
|
+
redoProductLine
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
await fetcher.submit(
|
|
113
|
+
{
|
|
114
|
+
[CartForm.INPUT_NAME]: JSON.stringify(formInput),
|
|
115
|
+
},
|
|
116
|
+
{method: 'POST', action: '/cart'},
|
|
117
|
+
);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const setCartRedoEnabledAttribute = async ({
|
|
121
|
+
fetcher,
|
|
122
|
+
cartInfoToEnable,
|
|
123
|
+
enabled
|
|
124
|
+
}: {
|
|
125
|
+
fetcher: FetcherWithComponents<unknown>,
|
|
126
|
+
cartInfoToEnable: CartInfoToEnable | null,
|
|
127
|
+
enabled: boolean
|
|
128
|
+
}) => {
|
|
129
|
+
const formInput = {
|
|
130
|
+
action: CartForm.ACTIONS.AttributesUpdateInput,
|
|
131
|
+
inputs: {
|
|
132
|
+
attributes: [
|
|
133
|
+
{
|
|
134
|
+
key: cartInfoToEnable?.cartAttribute || DEFAULT_REDO_ENABLED_CART_ATTRIBUTE,
|
|
135
|
+
value: enabled.toString()
|
|
136
|
+
}
|
|
137
|
+
]
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
await fetcher.submit(
|
|
142
|
+
{
|
|
143
|
+
[CartForm.INPUT_NAME]: JSON.stringify(formInput),
|
|
144
|
+
},
|
|
145
|
+
{method: 'POST', action: '/cart'},
|
|
146
|
+
);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
type FetcherData<T> = NonNullable<T | unknown> // FIXME: used to use SerializeFrom which is deprecated. Can this be better typed?
|
|
150
|
+
type ResolveFunction<T> = (value: FetcherData<T>) => void
|
|
151
|
+
|
|
152
|
+
function useFetcherWithPromise<TData = AppData>(opts?: Parameters<typeof useFetcher>[0]) {
|
|
153
|
+
const fetcher = useFetcher<TData>(opts)
|
|
154
|
+
const resolveRef = React.useRef<ResolveFunction<TData>>(null)
|
|
155
|
+
const promiseRef = React.useRef<Promise<FetcherData<TData>>>(null)
|
|
156
|
+
|
|
157
|
+
if (!promiseRef.current) {
|
|
158
|
+
promiseRef.current = new Promise<FetcherData<TData>>((resolve) => {
|
|
159
|
+
resolveRef.current = resolve
|
|
160
|
+
})
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const resetResolver = React.useCallback(() => {
|
|
164
|
+
promiseRef.current = new Promise((resolve) => {
|
|
165
|
+
resolveRef.current = resolve
|
|
166
|
+
})
|
|
167
|
+
}, [promiseRef, resolveRef])
|
|
168
|
+
|
|
169
|
+
const submit = React.useCallback(
|
|
170
|
+
async (...args: Parameters<typeof fetcher.submit>) => {
|
|
171
|
+
fetcher.submit(...args);
|
|
172
|
+
return promiseRef.current
|
|
173
|
+
},
|
|
174
|
+
[fetcher, promiseRef]
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
React.useEffect(() => {
|
|
178
|
+
if (fetcher.state === 'idle') {
|
|
179
|
+
if (fetcher.data) {
|
|
180
|
+
resolveRef.current?.(fetcher.data)
|
|
181
|
+
}
|
|
182
|
+
resetResolver()
|
|
183
|
+
}
|
|
184
|
+
}, [fetcher, resetResolver])
|
|
185
|
+
|
|
186
|
+
return { ...fetcher, submit }
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export {
|
|
190
|
+
DEFAULT_REDO_ENABLED_CART_ATTRIBUTE,
|
|
191
|
+
addProductToCartIfNeeded,
|
|
192
|
+
removeProductFromCartIfNeeded,
|
|
193
|
+
setCartRedoEnabledAttribute,
|
|
194
|
+
useFetcherWithPromise
|
|
195
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DependencyList,
|
|
3
|
+
useCallback,
|
|
4
|
+
useEffect,
|
|
5
|
+
useRef,
|
|
6
|
+
useState,
|
|
7
|
+
} from "react";
|
|
8
|
+
|
|
9
|
+
export interface Loader<T> {
|
|
10
|
+
(abort: AbortSignal): Promise<T>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface LoadState<T> {
|
|
14
|
+
error?: any;
|
|
15
|
+
pending: boolean;
|
|
16
|
+
value?: T;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function useLoad<T>(fn: Loader<T>, deps: DependencyList): LoadState<T> {
|
|
20
|
+
const [state, setState] = useState<LoadState<T>>({ pending: false });
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
const abortController = new AbortController();
|
|
24
|
+
setState((state) => ({ ...state, pending: true }));
|
|
25
|
+
fn(abortController.signal).then(
|
|
26
|
+
(value) => setState({ pending: false, value }),
|
|
27
|
+
(error) => {
|
|
28
|
+
if (
|
|
29
|
+
!(
|
|
30
|
+
error.message.includes("Request aborted for RPC method") ||
|
|
31
|
+
error.code === "ERR_CANCELED" ||
|
|
32
|
+
error.message === "Another request is in flight"
|
|
33
|
+
)
|
|
34
|
+
) {
|
|
35
|
+
setState({ pending: false, error });
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
);
|
|
39
|
+
return () => {
|
|
40
|
+
abortController.abort();
|
|
41
|
+
setState((state) => ({ ...state, pending: false }));
|
|
42
|
+
};
|
|
43
|
+
// The way useLoad() is designed, we have no choice but to trust that the user gave us the correct deps for fn().
|
|
44
|
+
// We could fix this by marking useLoad() as a custom hook, and then exhaustive-deps would enforce that for us.
|
|
45
|
+
// https://www.npmjs.com/package/eslint-plugin-react-hooks#advanced-configuration
|
|
46
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
47
|
+
}, deps);
|
|
48
|
+
|
|
49
|
+
return state;
|
|
50
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const REDO_PUBLIC_API_HOSTNAME = 'api.getredo.com';
|
|
2
|
+
const REDO_PUBLIC_API_HOSTNAME_LOCAL = 'localhost:8001';
|
|
3
|
+
|
|
4
|
+
const REDO_REQUIRED_HOSTNAMES = [
|
|
5
|
+
REDO_PUBLIC_API_HOSTNAME,
|
|
6
|
+
REDO_PUBLIC_API_HOSTNAME_LOCAL
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
REDO_REQUIRED_HOSTNAMES,
|
|
11
|
+
REDO_PUBLIC_API_HOSTNAME,
|
|
12
|
+
REDO_PUBLIC_API_HOSTNAME_LOCAL,
|
|
13
|
+
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "es5",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"allowSyntheticDefaultImports": true,
|
|
9
|
+
"strict": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"noFallthroughCasesInSwitch": true,
|
|
12
|
+
"module": "esnext",
|
|
13
|
+
"moduleResolution": "node",
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"isolatedModules": true,
|
|
16
|
+
"noEmit": true,
|
|
17
|
+
"jsx": "react-jsx"
|
|
18
|
+
},
|
|
19
|
+
"include": ["src", "src/index.ts"]
|
|
20
|
+
}
|