tf-checkout-react-native 2.0.0-beta.19 → 2.0.0-beta.22
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 +77 -20
- package/dist/index.d.mts +92 -63
- package/dist/index.d.ts +92 -63
- package/dist/index.js +221 -113
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +263 -148
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -5
- package/src/configure.ts +40 -10
- package/src/index.tsx +5 -2
- package/src/sections/Tickets.tsx +5 -3
- package/src/useCheckout.ts +1 -1
- package/src/storage.ts +0 -26
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tf-checkout-react-native",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.22",
|
|
4
4
|
"description": "TheTicketFairy ReactNative Checkout library",
|
|
5
5
|
"homepage": "https://github.com/theticketfairy/tf-shared-libraries#readme",
|
|
6
6
|
"author": "The Ticket Fairy",
|
|
@@ -102,7 +102,6 @@
|
|
|
102
102
|
"react": "19.1.0",
|
|
103
103
|
"react-dom": "19.1.0",
|
|
104
104
|
"react-native": "0.81.4",
|
|
105
|
-
"react-native-mmkv": "^3.3.1",
|
|
106
105
|
"react-native-render-html": "6.3.4",
|
|
107
106
|
"react-native-webview": "13.15.0",
|
|
108
107
|
"react-test-renderer": "19.1.0",
|
|
@@ -169,18 +168,17 @@
|
|
|
169
168
|
"entities": "^7.0.1",
|
|
170
169
|
"htmlparser2": "10.1.0"
|
|
171
170
|
},
|
|
172
|
-
"//peerDependencies": "
|
|
171
|
+
"//peerDependencies": "React contexts and native modules are peers so the host has exactly one copy. A second React Query context hides its provider, and a second native module duplicates its pod. Credential storage is supplied by the host through an explicit synchronous adapter; the SDK installs no storage module.",
|
|
173
172
|
"peerDependencies": {
|
|
174
173
|
"@react-native-clipboard/clipboard": ">=1.14.0",
|
|
175
174
|
"@stripe/stripe-react-native": ">=0.45.0",
|
|
176
175
|
"@tanstack/react-query": ">=5",
|
|
177
176
|
"react": ">=19.1",
|
|
178
177
|
"react-native": ">=0.81",
|
|
179
|
-
"react-native-mmkv": "^3.0.0",
|
|
180
178
|
"react-native-render-html": ">=6.3.4 <7",
|
|
181
179
|
"react-native-webview": ">=13.15.0"
|
|
182
180
|
},
|
|
183
|
-
"//dependencies": "
|
|
181
|
+
"//dependencies": "The private shared core is inlined into this bundle. Its axios, entities and htmlparser2 runtime dependencies must stay declared here; bundling axios would bring Node's stream into a browser build. Hosts never install the private shared package.",
|
|
184
182
|
"engines": {
|
|
185
183
|
"node": ">=20.19.4"
|
|
186
184
|
}
|
package/src/configure.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* React Native SDK setup. Hydrate the host's secure synchronous storage adapter
|
|
3
|
+
* before configuring checkout, calling an API or mounting a hook:
|
|
4
4
|
*
|
|
5
|
-
* configureCheckout({ env: 'PROD', clientId: 'PUBLIC_SDK_CLIENT_ID', clientSecret: '' })
|
|
5
|
+
* configureCheckout({ env: 'PROD', clientId: 'PUBLIC_SDK_CLIENT_ID', clientSecret: '', storage })
|
|
6
6
|
*
|
|
7
7
|
* Public checkout sign-in preserves the event-bound guest carrier and keeps
|
|
8
8
|
* its buyer credential server-side; it does not return a full-account ticket
|
|
@@ -13,16 +13,38 @@
|
|
|
13
13
|
* handling. Owned credentials use the SDK's header-backed storage; the backend
|
|
14
14
|
* still validates a restored session.
|
|
15
15
|
*/
|
|
16
|
-
import { configure, type TtfConfig } from 'tf-checkout-shared'
|
|
16
|
+
import { configure, type StorageAdapter, type TtfConfig } from 'tf-checkout-shared'
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
export type NativeCheckoutConfig = Omit<TtfConfig, 'storage'> & {
|
|
19
|
+
/** Host-owned OS-protected credential adapter. Async persistence also requires
|
|
20
|
+
* the host to await flush() after credential changes before reporting success. */
|
|
21
|
+
storage: StorageAdapter
|
|
22
|
+
}
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
const requireStorage = (storage: StorageAdapter | undefined): void => {
|
|
25
|
+
if (
|
|
26
|
+
!storage ||
|
|
27
|
+
typeof storage !== 'object' ||
|
|
28
|
+
Array.isArray(storage) ||
|
|
29
|
+
(['getItem', 'setItem', 'removeItem'] as const).some(
|
|
30
|
+
(method) =>
|
|
31
|
+
typeof storage[method] !== 'function' ||
|
|
32
|
+
Object.prototype.toString.call(storage[method]) === '[object AsyncFunction]'
|
|
33
|
+
) ||
|
|
34
|
+
(storage.flush !== undefined && typeof storage.flush !== 'function')
|
|
35
|
+
) {
|
|
36
|
+
throw new Error(
|
|
37
|
+
'Ticket Fairy native checkout requires a synchronous storage adapter. ' +
|
|
38
|
+
'Pass storage backed by iOS Keychain or Android Keystore; hydrate an async-backed mirror before configuration and await flush() after credential changes.'
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
22
42
|
|
|
23
|
-
export const configureCheckout = (config:
|
|
43
|
+
export const configureCheckout = (config: NativeCheckoutConfig): void => {
|
|
44
|
+
// Invalid setup must leave an existing buyer/configuration untouched. Shape
|
|
45
|
+
// checks do not read credentials or certify the host's persistence security.
|
|
46
|
+
requireStorage(config?.storage)
|
|
24
47
|
configure({
|
|
25
|
-
storage: mmkvStorageAdapter,
|
|
26
48
|
cookieAuth: true,
|
|
27
49
|
...config,
|
|
28
50
|
// NSURLSession/RCTNetworking would otherwise accept Set-Cookie outside
|
|
@@ -31,7 +53,15 @@ export const configureCheckout = (config: TtfConfig): void =>
|
|
|
31
53
|
// Native owns no browser cookie jar. Ask the canonical session owner to
|
|
32
54
|
// return its guest carrier and resume that exact carrier on later requests.
|
|
33
55
|
auth: () => ({
|
|
34
|
-
...
|
|
56
|
+
...Object.fromEntries(
|
|
57
|
+
Object.entries(config.auth?.() ?? {}).filter(
|
|
58
|
+
([name]) => name.toLowerCase() !== 'cache-control'
|
|
59
|
+
)
|
|
60
|
+
),
|
|
35
61
|
'X-TF-Session-Mode': 'header-only',
|
|
62
|
+
// Account/ticket responses must not be saved by the native HTTP cache.
|
|
63
|
+
// Revalidate any older cached response as well as forbidding a new store.
|
|
64
|
+
'Cache-Control': 'no-store, no-cache',
|
|
36
65
|
}),
|
|
37
66
|
})
|
|
67
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -18,8 +18,11 @@ export {
|
|
|
18
18
|
type UseCheckoutOptions,
|
|
19
19
|
type NativeUseCheckout,
|
|
20
20
|
} from './useCheckout'
|
|
21
|
-
export {
|
|
22
|
-
|
|
21
|
+
export {
|
|
22
|
+
configureCheckout,
|
|
23
|
+
configureCheckout as configure,
|
|
24
|
+
type NativeCheckoutConfig,
|
|
25
|
+
} from './configure'
|
|
23
26
|
export { CardInput, claimCardField, type CardInputProps } from './CardInput'
|
|
24
27
|
|
|
25
28
|
// Component library: themeable provider + primitives + sections + auth.
|
package/src/sections/Tickets.tsx
CHANGED
|
@@ -23,6 +23,7 @@ import { Pressable, StyleSheet, Text, View } from 'react-native'
|
|
|
23
23
|
import {
|
|
24
24
|
ConfirmerBusyError,
|
|
25
25
|
changeTicketQuantity,
|
|
26
|
+
ticketPriceContext,
|
|
26
27
|
errorMessage,
|
|
27
28
|
hooks,
|
|
28
29
|
ticketQuantityRange,
|
|
@@ -232,8 +233,9 @@ export const Tickets: FC<TicketsProps> = ({
|
|
|
232
233
|
const originals = useRef<Record<string, number>>({})
|
|
233
234
|
useEffect(() => {
|
|
234
235
|
for (const t of tickets)
|
|
235
|
-
if (originals.current[t
|
|
236
|
-
|
|
236
|
+
if (originals.current[ticketPriceContext(catalog.scope, t)] == null)
|
|
237
|
+
originals.current[ticketPriceContext(catalog.scope, t)] = t.price
|
|
238
|
+
}, [tickets, catalog.scope])
|
|
237
239
|
|
|
238
240
|
const selected = tickets.filter((t) => (qty[t.id] ?? 0) > 0)
|
|
239
241
|
// The current selection's kind — drives the CTA label and the mutual-exclusion
|
|
@@ -329,7 +331,7 @@ export const Tickets: FC<TicketsProps> = ({
|
|
|
329
331
|
const renderRow = (t: TicketType) => {
|
|
330
332
|
const notStarted = !t.salesStarted
|
|
331
333
|
const unavailable = t.soldOut || t.salesEnded || notStarted
|
|
332
|
-
const original = originals.current[t
|
|
334
|
+
const original = originals.current[ticketPriceContext(catalog.scope, t)]
|
|
333
335
|
const discounted = original != null && original > t.price
|
|
334
336
|
const isFree = Number(t.price) === 0
|
|
335
337
|
const sym = t.priceSymbol || t.currency
|
package/src/useCheckout.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* the flat snapshot) lives in the SDK's hook, so web and native share it — this
|
|
6
6
|
* file only supplies what's platform-specific.
|
|
7
7
|
*
|
|
8
|
-
* configureCheckout({ env: 'PROD', clientId, clientSecret }) //
|
|
8
|
+
* configureCheckout({ env: 'PROD', clientId, clientSecret, storage }) // after storage hydration
|
|
9
9
|
* const checkout = useCheckout()
|
|
10
10
|
* await checkout.setTickets(eventId, selections)
|
|
11
11
|
* checkout.setBilling(b)
|
package/src/storage.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* React Native storage adapter for the SDK's persisted session credentials.
|
|
3
|
-
*
|
|
4
|
-
* The shared transport uses a SYNCHRONOUS `StorageAdapter` (see shared
|
|
5
|
-
* `client/storage.ts`). MMKV 3 provides persisted get/set/delete operations,
|
|
6
|
-
* keeping the SDK's session credentials available across app restarts.
|
|
7
|
-
*
|
|
8
|
-
* Default native cookie auth stores its ecommerce ticket here and sends it in
|
|
9
|
-
* request headers; the ambient OS cookie jar stays disabled. Other configured
|
|
10
|
-
* SDK token credentials use this same adapter. Hosts may inject another
|
|
11
|
-
* synchronous adapter when configuring checkout.
|
|
12
|
-
*/
|
|
13
|
-
import { MMKV } from 'react-native-mmkv'
|
|
14
|
-
|
|
15
|
-
import type { StorageAdapter } from 'tf-checkout-shared'
|
|
16
|
-
|
|
17
|
-
/** Build a `StorageAdapter` backed by an MMKV instance (its own `id` namespace
|
|
18
|
-
* so it never collides with the host app's MMKV data). */
|
|
19
|
-
export const createMmkvStorage = (id = 'tf-checkout'): StorageAdapter => {
|
|
20
|
-
const mmkv = new MMKV({ id })
|
|
21
|
-
return {
|
|
22
|
-
getItem: (key) => mmkv.getString(key) ?? null,
|
|
23
|
-
setItem: (key, value) => mmkv.set(key, value),
|
|
24
|
-
removeItem: (key) => mmkv.delete(key),
|
|
25
|
-
}
|
|
26
|
-
}
|