@stamprally/react 0.9.0 → 0.11.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 +11 -84
- package/dist/index.cjs +3 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,102 +1,29 @@
|
|
|
1
1
|
# @stamprally/react
|
|
2
2
|
|
|
3
|
-
React
|
|
4
|
-
The package provides the `useStampRally` hook with external-store updates,
|
|
5
|
-
optimistic stamp acquisition, persistence, reward redemption, and recovery-code
|
|
6
|
-
support.
|
|
7
|
-
|
|
8
|
-
## Install
|
|
9
|
-
|
|
10
|
-
```sh
|
|
11
|
-
npm install @stamprally/core @stamprally/react react
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
Or with pnpm:
|
|
15
|
-
|
|
16
|
-
```sh
|
|
17
|
-
pnpm add @stamprally/core @stamprally/react react
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
This package supports React `>=19.0.0 <20.0.0`.
|
|
21
|
-
|
|
22
|
-
## Quick start
|
|
3
|
+
React integration for `@stamprally/core`. `useStampRally` subscribes to immutable client state and exposes check-in, reward-claim, synchronization, and user-switching operations.
|
|
23
4
|
|
|
24
5
|
```tsx
|
|
25
6
|
import { useMemo } from "react";
|
|
26
|
-
import {
|
|
27
|
-
LocalStorageAdapter,
|
|
28
|
-
StampRallyClient,
|
|
29
|
-
type RallyConfig,
|
|
30
|
-
} from "@stamprally/core";
|
|
7
|
+
import { StampRallyClient, type PublicRallyConfig } from "@stamprally/core";
|
|
31
8
|
import { useStampRally } from "@stamprally/react";
|
|
32
9
|
|
|
33
|
-
const config:
|
|
10
|
+
const config: PublicRallyConfig = {
|
|
34
11
|
id: "city-tour",
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
condition: { type: "instant" },
|
|
40
|
-
},
|
|
41
|
-
],
|
|
12
|
+
version: "0.9.1",
|
|
13
|
+
title: "City Tour",
|
|
14
|
+
spots: [{ id: "station", orderIndex: 0, name: "Station", conditions: [{ type: "passcode" }] }],
|
|
15
|
+
rewards: [],
|
|
42
16
|
};
|
|
43
17
|
|
|
44
18
|
export function Rally() {
|
|
45
|
-
const client = useMemo(
|
|
46
|
-
|
|
47
|
-
[],
|
|
48
|
-
);
|
|
49
|
-
const { state, isLoading, isPending, error, acquire } = useStampRally(client);
|
|
50
|
-
|
|
19
|
+
const client = useMemo(() => new StampRallyClient(config), []);
|
|
20
|
+
const { state, isLoading, onCheckIn } = useStampRally(client);
|
|
51
21
|
if (isLoading) return <p>Loading…</p>;
|
|
52
|
-
|
|
53
|
-
return (
|
|
54
|
-
<section>
|
|
55
|
-
<p>
|
|
56
|
-
{state?.records.length ?? 0} stamp(s) collected
|
|
57
|
-
</p>
|
|
58
|
-
<button
|
|
59
|
-
disabled={isPending}
|
|
60
|
-
onClick={() => void acquire("station", { type: "instant" })}
|
|
61
|
-
>
|
|
62
|
-
Collect stamp
|
|
63
|
-
</button>
|
|
64
|
-
{error !== null && <p role="alert">Could not collect the stamp.</p>}
|
|
65
|
-
</section>
|
|
66
|
-
);
|
|
22
|
+
return <button onClick={() => void onCheckIn("station", "ARRIVED")}>{state?.records.length ?? 0} checked in</button>;
|
|
67
23
|
}
|
|
68
24
|
```
|
|
69
25
|
|
|
70
|
-
The hook
|
|
71
|
-
keeps the UI synchronized with persisted state. Keep the `StampRallyClient`
|
|
72
|
-
instance stable, for example with `useMemo`, so that the hook does not switch
|
|
73
|
-
clients on every render.
|
|
74
|
-
|
|
75
|
-
## Hook return value
|
|
76
|
-
|
|
77
|
-
`useStampRally(client)` returns:
|
|
78
|
-
|
|
79
|
-
- `state`: the current `StampRallyState`, or `null` while it is not initialized.
|
|
80
|
-
- `isLoading`: whether the client is initializing or changing clients.
|
|
81
|
-
- `isPending`: whether an acquisition, reset, redemption, or import is pending.
|
|
82
|
-
- `error`: the latest typed engine/reward error or storage error.
|
|
83
|
-
- `rewardsState`: the current reward states, or an empty array when rewards are not configured.
|
|
84
|
-
- `acquire(stampId, context, now?)`: validates and persists a stamp acquisition.
|
|
85
|
-
- `reset(now?)`: clears the persisted rally state.
|
|
86
|
-
- `redeem(rewardId, options?)`: redeems an available reward, optionally with a staff passcode and ID.
|
|
87
|
-
- `exportRecoveryCode()`: exports confirmed stamp and reward progress.
|
|
88
|
-
- `importRecoveryCode(token)`: restores a rally-scoped recovery code and returns whether it was valid.
|
|
89
|
-
|
|
90
|
-
Acquisitions are shown optimistically while persistence is pending. Engine
|
|
91
|
-
validation and storage failures roll the optimistic state back and are exposed
|
|
92
|
-
through the returned `error` value and the rejected promise where applicable.
|
|
93
|
-
|
|
94
|
-
## Browser and server rendering
|
|
95
|
-
|
|
96
|
-
The hook uses React's external-store API and provides a `null` server snapshot.
|
|
97
|
-
The core package's browser adapters and detectors access browser globals only
|
|
98
|
-
when called, so applications can choose a different `StampStorage` for server
|
|
99
|
-
rendering, tests, or non-browser environments.
|
|
26
|
+
The hook return value includes `state`, `isLoading`, `error`, `onCheckIn`, `onClaimReward`, `onSync`, `switchUser`, and `clearUserState`.
|
|
100
27
|
|
|
101
28
|
## License
|
|
102
29
|
|
package/dist/index.cjs
CHANGED
|
@@ -60,6 +60,9 @@ function useStampRally(client, options = {}) {
|
|
|
60
60
|
onCheckIn,
|
|
61
61
|
onClaimReward,
|
|
62
62
|
onSync,
|
|
63
|
+
retrySync: onSync,
|
|
64
|
+
syncState: client.syncState,
|
|
65
|
+
pendingCount: client.pendingCount,
|
|
63
66
|
switchUser: client.switchUser.bind(client),
|
|
64
67
|
clearUserState: client.clearUserState.bind(client)
|
|
65
68
|
};
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useStampRally.ts"],"names":["useCallback","useSyncExternalStore","useState","useEffect"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"sources":["../src/useStampRally.ts"],"names":["useCallback","useSyncExternalStore","useState","useEffect"],"mappings":";;;;;AAgCA,SAAS,cAAA,GAAuB;AAC9B,EAAA,OAAO,IAAA;AACT;AACA,SAAS,UAAU,KAAA,EAAuB;AACxC,EAAA,OAAO,iBAAiB,KAAA,GAAQ,KAAA,GAAQ,IAAI,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC,CAAA;AACjE;AACO,SAAS,aAAA,CACd,MAAA,EACA,OAAA,GAAgC,EAAC,EACZ;AACrB,EAAA,MAAM,SAAA,GAAYA,iBAAA,CAAY,CAAC,QAAA,KAAyB,MAAA,CAAO,UAAU,QAAQ,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAC5F,EAAA,MAAM,WAAA,GAAcA,kBAAY,MAAM,MAAA,CAAO,UAAS,EAAG,CAAC,MAAM,CAAC,CAAA;AACjE,EAAA,MAAM,KAAA,GAAQC,0BAAA,CAAqB,SAAA,EAAW,WAAA,EAAa,cAAc,CAAA;AACzE,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIC,eAAuB,IAAI,CAAA;AACrD,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,QAAQ,UAAA,KAAe,KAAA,IAAS,MAAA,CAAO,QAAA,OAAe,IAAA,EAAM;AAChE,IAAA,IAAI,MAAA,GAAS,IAAA;AACb,IAAA,KAAK,MAAA,CAAO,IAAA,EAAK,CAAE,KAAA,CAAM,CAAC,MAAA,KAAoB;AAC5C,MAAA,IAAI,MAAA,EAAQ,QAAA,CAAS,SAAA,CAAU,MAAM,CAAC,CAAA;AAAA,IACxC,CAAC,CAAA;AACD,IAAA,OAAO,MAAM;AACX,MAAA,MAAA,GAAS,KAAA;AAAA,IACX,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAA,EAAQ,OAAA,CAAQ,UAAU,CAAC,CAAA;AAC/B,EAAA,MAAM,SAAA,GAAYH,iBAAA;AAAA,IAChB,CAAC,MAAA,EAAgB,KAAA,EAAgB,cAAA,GAAiC,EAAC,KAAM;AACvE,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAA,OAAO,MAAA,CAAO,QAAQ,MAAA,EAAQ,KAAA,EAAO,cAAc,CAAA,CAAE,IAAA,CAAK,CAAC,MAAA,KAAW;AACpE,QAAA,IAAI,CAAC,MAAA,CAAO,EAAA,WAAa,SAAA,CAAU,MAAA,CAAO,KAAK,CAAC,CAAA;AAChD,QAAA,OAAO,MAAA;AAAA,MACT,CAAC,CAAA;AAAA,IACH,CAAA;AAAA,IACA,CAAC,MAAM;AAAA,GACT;AACA,EAAA,MAAM,aAAA,GAAgBA,iBAAA;AAAA,IACpB,CAAC,QAAA,EAAkB,YAAA,GAA6B,EAAC,KAAM;AACrD,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAA,OAAO,OAAO,WAAA,CAAY,QAAA,EAAU,YAAY,CAAA,CAAE,IAAA,CAAK,CAAC,MAAA,KAAW;AACjE,QAAA,IAAI,CAAC,MAAA,CAAO,EAAA,WAAa,SAAA,CAAU,MAAA,CAAO,KAAK,CAAC,CAAA;AAChD,QAAA,OAAO,MAAA;AAAA,MACT,CAAC,CAAA;AAAA,IACH,CAAA;AAAA,IACA,CAAC,MAAM;AAAA,GACT;AACA,EAAA,MAAM,MAAA,GAASA,kBAAY,MAAM;AAC/B,IAAA,QAAA,CAAS,IAAI,CAAA;AACb,IAAA,OAAO,MAAA,CAAO,IAAA,EAAK,CAAE,KAAA,CAAM,CAAC,MAAA,KAAoB;AAC9C,MAAA,MAAM,IAAA,GAAO,UAAU,MAAM,CAAA;AAC7B,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAA,MAAM,IAAA;AAAA,IACR,CAAC,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AACX,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,MAAA,EAAQ,OAAO,SAAA,EAAU;AAAA,IACzB,WAAW,KAAA,KAAU,IAAA;AAAA,IACrB,KAAA;AAAA,IACA,SAAA;AAAA,IACA,aAAA;AAAA,IACA,MAAA;AAAA,IACA,SAAA,EAAW,MAAA;AAAA,IACX,WAAW,MAAA,CAAO,SAAA;AAAA,IAClB,cAAc,MAAA,CAAO,YAAA;AAAA,IACrB,UAAA,EAAY,MAAA,CAAO,UAAA,CAAW,IAAA,CAAK,MAAM,CAAA;AAAA,IACzC,cAAA,EAAgB,MAAA,CAAO,cAAA,CAAe,IAAA,CAAK,MAAM;AAAA,GACnD;AACF","file":"index.cjs","sourcesContent":["import type {\n CheckInOptions,\n CheckInResult,\n ClaimOptions,\n ClaimResult,\n StampRallyClient,\n SyncState,\n UserRallyState,\n} from \"@stamprally/core\";\nimport { useCallback, useEffect, useState, useSyncExternalStore } from \"react\";\n\nexport interface UseStampRallyOptions {\n readonly initialize?: boolean;\n}\nexport interface UseStampRallyReturn {\n readonly state: UserRallyState | null;\n readonly config: ReturnType<StampRallyClient[\"getConfig\"]>;\n readonly isLoading: boolean;\n readonly error: Error | null;\n readonly onCheckIn: (\n spotId: string,\n proof: unknown,\n options?: CheckInOptions,\n ) => Promise<CheckInResult>;\n readonly onClaimReward: (rewardId: string, options?: ClaimOptions) => Promise<ClaimResult>;\n readonly onSync: () => Promise<void>;\n readonly retrySync: () => Promise<void>;\n readonly syncState: SyncState;\n readonly pendingCount: number;\n readonly switchUser: (userId: string | null) => Promise<UserRallyState>;\n readonly clearUserState: (userId?: string) => Promise<void>;\n}\nfunction serverSnapshot(): null {\n return null;\n}\nfunction errorFrom(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value));\n}\nexport function useStampRally(\n client: StampRallyClient,\n options: UseStampRallyOptions = {},\n): UseStampRallyReturn {\n const subscribe = useCallback((listener: () => void) => client.subscribe(listener), [client]);\n const getSnapshot = useCallback(() => client.getState(), [client]);\n const state = useSyncExternalStore(subscribe, getSnapshot, serverSnapshot);\n const [error, setError] = useState<Error | null>(null);\n useEffect(() => {\n if (options.initialize === false || client.getState() !== null) return;\n let active = true;\n void client.init().catch((reason: unknown) => {\n if (active) setError(errorFrom(reason));\n });\n return () => {\n active = false;\n };\n }, [client, options.initialize]);\n const onCheckIn = useCallback(\n (spotId: string, proof: unknown, checkInOptions: CheckInOptions = {}) => {\n setError(null);\n return client.checkIn(spotId, proof, checkInOptions).then((result) => {\n if (!result.ok) setError(errorFrom(result.error));\n return result;\n });\n },\n [client],\n );\n const onClaimReward = useCallback(\n (rewardId: string, claimOptions: ClaimOptions = {}) => {\n setError(null);\n return client.claimReward(rewardId, claimOptions).then((result) => {\n if (!result.ok) setError(errorFrom(result.error));\n return result;\n });\n },\n [client],\n );\n const onSync = useCallback(() => {\n setError(null);\n return client.sync().catch((reason: unknown) => {\n const next = errorFrom(reason);\n setError(next);\n throw next;\n });\n }, [client]);\n return {\n state,\n config: client.getConfig(),\n isLoading: state === null,\n error,\n onCheckIn,\n onClaimReward,\n onSync,\n retrySync: onSync,\n syncState: client.syncState,\n pendingCount: client.pendingCount,\n switchUser: client.switchUser.bind(client),\n clearUserState: client.clearUserState.bind(client),\n };\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { UserRallyState, StampRallyClient, CheckInOptions, CheckInResult, ClaimOptions, ClaimResult } from '@stamprally/core';
|
|
1
|
+
import { UserRallyState, StampRallyClient, CheckInOptions, CheckInResult, ClaimOptions, ClaimResult, SyncState } from '@stamprally/core';
|
|
2
2
|
|
|
3
3
|
interface UseStampRallyOptions {
|
|
4
4
|
readonly initialize?: boolean;
|
|
@@ -11,6 +11,9 @@ interface UseStampRallyReturn {
|
|
|
11
11
|
readonly onCheckIn: (spotId: string, proof: unknown, options?: CheckInOptions) => Promise<CheckInResult>;
|
|
12
12
|
readonly onClaimReward: (rewardId: string, options?: ClaimOptions) => Promise<ClaimResult>;
|
|
13
13
|
readonly onSync: () => Promise<void>;
|
|
14
|
+
readonly retrySync: () => Promise<void>;
|
|
15
|
+
readonly syncState: SyncState;
|
|
16
|
+
readonly pendingCount: number;
|
|
14
17
|
readonly switchUser: (userId: string | null) => Promise<UserRallyState>;
|
|
15
18
|
readonly clearUserState: (userId?: string) => Promise<void>;
|
|
16
19
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { UserRallyState, StampRallyClient, CheckInOptions, CheckInResult, ClaimOptions, ClaimResult } from '@stamprally/core';
|
|
1
|
+
import { UserRallyState, StampRallyClient, CheckInOptions, CheckInResult, ClaimOptions, ClaimResult, SyncState } from '@stamprally/core';
|
|
2
2
|
|
|
3
3
|
interface UseStampRallyOptions {
|
|
4
4
|
readonly initialize?: boolean;
|
|
@@ -11,6 +11,9 @@ interface UseStampRallyReturn {
|
|
|
11
11
|
readonly onCheckIn: (spotId: string, proof: unknown, options?: CheckInOptions) => Promise<CheckInResult>;
|
|
12
12
|
readonly onClaimReward: (rewardId: string, options?: ClaimOptions) => Promise<ClaimResult>;
|
|
13
13
|
readonly onSync: () => Promise<void>;
|
|
14
|
+
readonly retrySync: () => Promise<void>;
|
|
15
|
+
readonly syncState: SyncState;
|
|
16
|
+
readonly pendingCount: number;
|
|
14
17
|
readonly switchUser: (userId: string | null) => Promise<UserRallyState>;
|
|
15
18
|
readonly clearUserState: (userId?: string) => Promise<void>;
|
|
16
19
|
}
|
package/dist/index.js
CHANGED
|
@@ -58,6 +58,9 @@ function useStampRally(client, options = {}) {
|
|
|
58
58
|
onCheckIn,
|
|
59
59
|
onClaimReward,
|
|
60
60
|
onSync,
|
|
61
|
+
retrySync: onSync,
|
|
62
|
+
syncState: client.syncState,
|
|
63
|
+
pendingCount: client.pendingCount,
|
|
61
64
|
switchUser: client.switchUser.bind(client),
|
|
62
65
|
clearUserState: client.clearUserState.bind(client)
|
|
63
66
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useStampRally.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"sources":["../src/useStampRally.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type {\n CheckInOptions,\n CheckInResult,\n ClaimOptions,\n ClaimResult,\n StampRallyClient,\n SyncState,\n UserRallyState,\n} from \"@stamprally/core\";\nimport { useCallback, useEffect, useState, useSyncExternalStore } from \"react\";\n\nexport interface UseStampRallyOptions {\n readonly initialize?: boolean;\n}\nexport interface UseStampRallyReturn {\n readonly state: UserRallyState | null;\n readonly config: ReturnType<StampRallyClient[\"getConfig\"]>;\n readonly isLoading: boolean;\n readonly error: Error | null;\n readonly onCheckIn: (\n spotId: string,\n proof: unknown,\n options?: CheckInOptions,\n ) => Promise<CheckInResult>;\n readonly onClaimReward: (rewardId: string, options?: ClaimOptions) => Promise<ClaimResult>;\n readonly onSync: () => Promise<void>;\n readonly retrySync: () => Promise<void>;\n readonly syncState: SyncState;\n readonly pendingCount: number;\n readonly switchUser: (userId: string | null) => Promise<UserRallyState>;\n readonly clearUserState: (userId?: string) => Promise<void>;\n}\nfunction serverSnapshot(): null {\n return null;\n}\nfunction errorFrom(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value));\n}\nexport function useStampRally(\n client: StampRallyClient,\n options: UseStampRallyOptions = {},\n): UseStampRallyReturn {\n const subscribe = useCallback((listener: () => void) => client.subscribe(listener), [client]);\n const getSnapshot = useCallback(() => client.getState(), [client]);\n const state = useSyncExternalStore(subscribe, getSnapshot, serverSnapshot);\n const [error, setError] = useState<Error | null>(null);\n useEffect(() => {\n if (options.initialize === false || client.getState() !== null) return;\n let active = true;\n void client.init().catch((reason: unknown) => {\n if (active) setError(errorFrom(reason));\n });\n return () => {\n active = false;\n };\n }, [client, options.initialize]);\n const onCheckIn = useCallback(\n (spotId: string, proof: unknown, checkInOptions: CheckInOptions = {}) => {\n setError(null);\n return client.checkIn(spotId, proof, checkInOptions).then((result) => {\n if (!result.ok) setError(errorFrom(result.error));\n return result;\n });\n },\n [client],\n );\n const onClaimReward = useCallback(\n (rewardId: string, claimOptions: ClaimOptions = {}) => {\n setError(null);\n return client.claimReward(rewardId, claimOptions).then((result) => {\n if (!result.ok) setError(errorFrom(result.error));\n return result;\n });\n },\n [client],\n );\n const onSync = useCallback(() => {\n setError(null);\n return client.sync().catch((reason: unknown) => {\n const next = errorFrom(reason);\n setError(next);\n throw next;\n });\n }, [client]);\n return {\n state,\n config: client.getConfig(),\n isLoading: state === null,\n error,\n onCheckIn,\n onClaimReward,\n onSync,\n retrySync: onSync,\n syncState: client.syncState,\n pendingCount: client.pendingCount,\n switchUser: client.switchUser.bind(client),\n clearUserState: client.clearUserState.bind(client),\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stamprally/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "React hooks for @stamprally/core.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@stamprally/core": "0.
|
|
34
|
+
"@stamprally/core": "0.11.0"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"react": "^18.0.0 || ^19.0.0",
|