@idosgames/react 0.1.4 → 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/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- 'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime');var u=react.createContext(null);function f({client:e,children:t}){return jsxRuntime.jsx(u.Provider,{value:e,children:t})}function n(){let e=react.useContext(u);if(!e)throw new Error("useIDosGamesClient must be used within <IDosGamesProvider>.");return e}var l=react.createContext(null);function y({children:e}){let[t,o]=react.useState(null),s=react.useCallback((c,p="info")=>{o({text:c,kind:p});},[]),r=react.useCallback(()=>{o(null);},[]),i=react.useMemo(()=>({message:t,setStatus:s,clear:r}),[t,s,r]);return jsxRuntime.jsx(l.Provider,{value:i,children:e})}function D(){let e=react.useContext(l);if(!e)throw new Error("useStatus must be used within <StatusProvider>.");return e}function R(){let e=n(),[,t]=react.useReducer(o=>o+1,0);return react.useEffect(()=>e.on("user:anyUpdated",()=>{t();}),[e]),e.data.user.state}function N(e,t){let o=n();react.useEffect(()=>o.on(e,t),[o,e,t]);}function E(e){let t=react.createContext(null);function o({controller:r,children:i}){return jsxRuntime.jsx(t.Provider,{value:r,children:i})}function s(){let r=react.useContext(t);if(r===null)throw new Error(`use${e} must be used within its <${e}Provider>.`);return r}return [o,s]}exports.IDosGamesProvider=f;exports.StatusProvider=y;exports.createControllerContext=E;exports.useIDosGamesClient=n;exports.useSdkEvent=N;exports.useStatus=D;exports.useUserState=R;
1
+ 'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime');var m=react.createContext(null);function O({client:e,children:t}){return jsxRuntime.jsx(m.Provider,{value:e,children:t})}function a(){let e=react.useContext(m);if(!e)throw new Error("useIDosGamesClient must be used within <IDosGamesProvider>.");return e}var P=react.createContext(null);function G({children:e}){let[t,o]=react.useState(null),r=react.useCallback((l,c="info")=>{o({text:l,kind:c});},[]),n=react.useCallback(()=>{o(null);},[]),s=react.useMemo(()=>({message:t,setStatus:r,clear:n}),[t,r,n]);return jsxRuntime.jsx(P.Provider,{value:s,children:e})}function I(){let e=react.useContext(P);if(!e)throw new Error("useStatus must be used within <StatusProvider>.");return e}function K(){let e=a(),[,t]=react.useReducer(o=>o+1,0);return react.useEffect(()=>e.on("user:anyUpdated",()=>{t();}),[e]),e.data.user.state}function U(e,t){let o=a();react.useEffect(()=>o.on(e,t),[o,e,t]);}function q(e){let t=a(),[o,r]=react.useState("idle"),[n,s]=react.useState(null),l=react.useMemo(()=>t.checkout.availableOptions(e),[t,e]),c=react.useCallback(u=>t.checkout.requirementOf(u),[t]),v=react.useCallback(async(u,y)=>{let d=t.checkout.requirementOf(u);s(null),r(d.kind==="store"?"awaiting-store":d.shortfall?"awaiting-wallet":"purchasing");try{let i=await y(u);return i.ok?(r("done"),i):(s(i.error),r("failed"),i)}catch(i){return s(i instanceof Error?i.message:String(i)),r("failed"),null}},[t]),x=react.useCallback(()=>{r("idle"),s(null);},[]);return {options:l,requirementOf:c,stage:o,error:n,pay:v,reset:x}}function $(e){let t=react.createContext(null);function o({controller:n,children:s}){return jsxRuntime.jsx(t.Provider,{value:n,children:s})}function r(){let n=react.useContext(t);if(n===null)throw new Error(`use${e} must be used within its <${e}Provider>.`);return n}return [o,r]}exports.IDosGamesProvider=O;exports.StatusProvider=G;exports.createControllerContext=$;exports.useIDosGamesClient=a;exports.usePayment=q;exports.useSdkEvent=U;exports.useStatus=I;exports.useUserState=K;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ReactNode } from 'react';
2
- import { IDosGamesClient, SdkEvents, UserState } from '@idosgames/core';
2
+ import { IDosGamesClient, SdkEvents, UserState, PriceOption, PaymentRequirement, OperationResult, PriceOptions } from '@idosgames/core';
3
3
 
4
4
  declare function IDosGamesProvider({ client, children, }: {
5
5
  client: IDosGamesClient;
@@ -27,6 +27,35 @@ declare function useUserState(): UserState | null;
27
27
  /** Subscribe to a typed SDK event for the lifetime of the component. */
28
28
  declare function useSdkEvent<K extends keyof SdkEvents>(event: K, handler: (payload: SdkEvents[K]) => void): void;
29
29
 
30
+ /** Where a payment attempt currently is. */
31
+ type PaymentStage = "idle" | "awaiting-store" | "awaiting-wallet" | "purchasing" | "done" | "failed";
32
+ interface UsePaymentResult<T> {
33
+ /** Options this client may show, already filtered by platform and ordered as the server orders them. */
34
+ options: PriceOption[];
35
+ /** What the given option needs before it can be paid (receipt / resources / crypto shortfall). */
36
+ requirementOf: (option: PriceOption) => PaymentRequirement;
37
+ /** Current stage — drive the dialog from this, not from a local flag. */
38
+ stage: PaymentStage;
39
+ /** Last failure, cleared on the next attempt. */
40
+ error: string | null;
41
+ /** Runs a purchase, keeping `stage`/`error` in step. */
42
+ pay: (option: PriceOption, purchase: (option: PriceOption) => Promise<OperationResult<T>>) => Promise<OperationResult<T> | null>;
43
+ reset: () => void;
44
+ }
45
+ /**
46
+ * Payment state for one entity's price list.
47
+ *
48
+ * The hook does not buy anything by itself — the caller passes the purchase, because only it knows
49
+ * the module and the rest of the request. What the hook owns is the part every payment UI repeats:
50
+ * which options to show here, what each of them needs, and which stage the attempt is at.
51
+ *
52
+ * ⚠ Paying with an external wallet is two round-trips (deposit, then purchase), and the gap is
53
+ * visible to the player — tens of seconds while the deposit confirms. That is why `stage` exists
54
+ * as a value rather than a boolean: a dialog that shows only "loading" makes a working payment
55
+ * look hung, and the player taps again.
56
+ */
57
+ declare function usePayment<T>(priceOptions: PriceOptions | null | undefined): UsePaymentResult<T>;
58
+
30
59
  interface ControllerProviderProps<T> {
31
60
  controller: T;
32
61
  children: ReactNode;
@@ -41,4 +70,4 @@ interface ControllerProviderProps<T> {
41
70
  */
42
71
  declare function createControllerContext<T>(name: string): readonly [(props: ControllerProviderProps<T>) => ReactNode, () => T];
43
72
 
44
- export { type ControllerProviderProps, IDosGamesProvider, type StatusKind, type StatusMessage, StatusProvider, createControllerContext, useIDosGamesClient, useSdkEvent, useStatus, useUserState };
73
+ export { type ControllerProviderProps, IDosGamesProvider, type PaymentStage, type StatusKind, type StatusMessage, StatusProvider, type UsePaymentResult, createControllerContext, useIDosGamesClient, usePayment, useSdkEvent, useStatus, useUserState };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ReactNode } from 'react';
2
- import { IDosGamesClient, SdkEvents, UserState } from '@idosgames/core';
2
+ import { IDosGamesClient, SdkEvents, UserState, PriceOption, PaymentRequirement, OperationResult, PriceOptions } from '@idosgames/core';
3
3
 
4
4
  declare function IDosGamesProvider({ client, children, }: {
5
5
  client: IDosGamesClient;
@@ -27,6 +27,35 @@ declare function useUserState(): UserState | null;
27
27
  /** Subscribe to a typed SDK event for the lifetime of the component. */
28
28
  declare function useSdkEvent<K extends keyof SdkEvents>(event: K, handler: (payload: SdkEvents[K]) => void): void;
29
29
 
30
+ /** Where a payment attempt currently is. */
31
+ type PaymentStage = "idle" | "awaiting-store" | "awaiting-wallet" | "purchasing" | "done" | "failed";
32
+ interface UsePaymentResult<T> {
33
+ /** Options this client may show, already filtered by platform and ordered as the server orders them. */
34
+ options: PriceOption[];
35
+ /** What the given option needs before it can be paid (receipt / resources / crypto shortfall). */
36
+ requirementOf: (option: PriceOption) => PaymentRequirement;
37
+ /** Current stage — drive the dialog from this, not from a local flag. */
38
+ stage: PaymentStage;
39
+ /** Last failure, cleared on the next attempt. */
40
+ error: string | null;
41
+ /** Runs a purchase, keeping `stage`/`error` in step. */
42
+ pay: (option: PriceOption, purchase: (option: PriceOption) => Promise<OperationResult<T>>) => Promise<OperationResult<T> | null>;
43
+ reset: () => void;
44
+ }
45
+ /**
46
+ * Payment state for one entity's price list.
47
+ *
48
+ * The hook does not buy anything by itself — the caller passes the purchase, because only it knows
49
+ * the module and the rest of the request. What the hook owns is the part every payment UI repeats:
50
+ * which options to show here, what each of them needs, and which stage the attempt is at.
51
+ *
52
+ * ⚠ Paying with an external wallet is two round-trips (deposit, then purchase), and the gap is
53
+ * visible to the player — tens of seconds while the deposit confirms. That is why `stage` exists
54
+ * as a value rather than a boolean: a dialog that shows only "loading" makes a working payment
55
+ * look hung, and the player taps again.
56
+ */
57
+ declare function usePayment<T>(priceOptions: PriceOptions | null | undefined): UsePaymentResult<T>;
58
+
30
59
  interface ControllerProviderProps<T> {
31
60
  controller: T;
32
61
  children: ReactNode;
@@ -41,4 +70,4 @@ interface ControllerProviderProps<T> {
41
70
  */
42
71
  declare function createControllerContext<T>(name: string): readonly [(props: ControllerProviderProps<T>) => ReactNode, () => T];
43
72
 
44
- export { type ControllerProviderProps, IDosGamesProvider, type StatusKind, type StatusMessage, StatusProvider, createControllerContext, useIDosGamesClient, useSdkEvent, useStatus, useUserState };
73
+ export { type ControllerProviderProps, IDosGamesProvider, type PaymentStage, type StatusKind, type StatusMessage, StatusProvider, type UsePaymentResult, createControllerContext, useIDosGamesClient, usePayment, useSdkEvent, useStatus, useUserState };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import {createContext,useContext,useState,useCallback,useMemo,useReducer,useEffect}from'react';import {jsx}from'react/jsx-runtime';var u=createContext(null);function f({client:e,children:t}){return jsx(u.Provider,{value:e,children:t})}function n(){let e=useContext(u);if(!e)throw new Error("useIDosGamesClient must be used within <IDosGamesProvider>.");return e}var l=createContext(null);function y({children:e}){let[t,o]=useState(null),s=useCallback((c,p="info")=>{o({text:c,kind:p});},[]),r=useCallback(()=>{o(null);},[]),i=useMemo(()=>({message:t,setStatus:s,clear:r}),[t,s,r]);return jsx(l.Provider,{value:i,children:e})}function D(){let e=useContext(l);if(!e)throw new Error("useStatus must be used within <StatusProvider>.");return e}function R(){let e=n(),[,t]=useReducer(o=>o+1,0);return useEffect(()=>e.on("user:anyUpdated",()=>{t();}),[e]),e.data.user.state}function N(e,t){let o=n();useEffect(()=>o.on(e,t),[o,e,t]);}function E(e){let t=createContext(null);function o({controller:r,children:i}){return jsx(t.Provider,{value:r,children:i})}function s(){let r=useContext(t);if(r===null)throw new Error(`use${e} must be used within its <${e}Provider>.`);return r}return [o,s]}export{f as IDosGamesProvider,y as StatusProvider,E as createControllerContext,n as useIDosGamesClient,N as useSdkEvent,D as useStatus,R as useUserState};
1
+ import {createContext,useContext,useState,useCallback,useMemo,useReducer,useEffect}from'react';import {jsx}from'react/jsx-runtime';var m=createContext(null);function O({client:e,children:t}){return jsx(m.Provider,{value:e,children:t})}function a(){let e=useContext(m);if(!e)throw new Error("useIDosGamesClient must be used within <IDosGamesProvider>.");return e}var P=createContext(null);function G({children:e}){let[t,o]=useState(null),r=useCallback((l,c="info")=>{o({text:l,kind:c});},[]),n=useCallback(()=>{o(null);},[]),s=useMemo(()=>({message:t,setStatus:r,clear:n}),[t,r,n]);return jsx(P.Provider,{value:s,children:e})}function I(){let e=useContext(P);if(!e)throw new Error("useStatus must be used within <StatusProvider>.");return e}function K(){let e=a(),[,t]=useReducer(o=>o+1,0);return useEffect(()=>e.on("user:anyUpdated",()=>{t();}),[e]),e.data.user.state}function U(e,t){let o=a();useEffect(()=>o.on(e,t),[o,e,t]);}function q(e){let t=a(),[o,r]=useState("idle"),[n,s]=useState(null),l=useMemo(()=>t.checkout.availableOptions(e),[t,e]),c=useCallback(u=>t.checkout.requirementOf(u),[t]),v=useCallback(async(u,y)=>{let d=t.checkout.requirementOf(u);s(null),r(d.kind==="store"?"awaiting-store":d.shortfall?"awaiting-wallet":"purchasing");try{let i=await y(u);return i.ok?(r("done"),i):(s(i.error),r("failed"),i)}catch(i){return s(i instanceof Error?i.message:String(i)),r("failed"),null}},[t]),x=useCallback(()=>{r("idle"),s(null);},[]);return {options:l,requirementOf:c,stage:o,error:n,pay:v,reset:x}}function $(e){let t=createContext(null);function o({controller:n,children:s}){return jsx(t.Provider,{value:n,children:s})}function r(){let n=useContext(t);if(n===null)throw new Error(`use${e} must be used within its <${e}Provider>.`);return n}return [o,r]}export{O as IDosGamesProvider,G as StatusProvider,$ as createControllerContext,a as useIDosGamesClient,q as usePayment,U as useSdkEvent,I as useStatus,K as useUserState};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@idosgames/react",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "description": "Shared React glue for the iDosGames host shell and modules: the client provider, status provider, live-state hooks, and a controller-context factory. Extracted from what every template used to copy-paste.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "//": "react is a peer (consumer-provided, never bundled). @idosgames/core is a real range for the same reason as in @idosgames/wallet — a published package must pin the core whose types it references.",
47
47
  "dependencies": {
48
- "@idosgames/core": "^0.5.0"
48
+ "@idosgames/core": "^0.7.0"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "react": "^18.3.1 || ^19.0.0"