@izara_frontend/service-schemas 1.0.4 → 1.0.6
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 +133 -0
- package/index.js +1 -0
- package/package.json +1 -1
- package/src/getObjectSchema.js +106 -0
package/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# @izara_frontend/service-schemas
|
|
2
|
+
|
|
3
|
+
Quick guide — initialize the schema tools and use the provided hooks (e.g. `getObjectLinks`).
|
|
4
|
+
|
|
5
|
+
**Requirement**
|
|
6
|
+
- react: "^18.3.1",
|
|
7
|
+
- react-dom: "^18.3.1"
|
|
8
|
+
|
|
9
|
+
**Purpose**
|
|
10
|
+
- This package exports helpers and hook-like functions to fetch and work with service object schemas (links, object schemas, validators, etc.).
|
|
11
|
+
- It expects you to initialize a small runtime integration once (injecting reducers and the posts API) and then use the exported functions inside components or utility modules.
|
|
12
|
+
|
|
13
|
+
**Install**
|
|
14
|
+
- This package is intended to be consumed from your monorepo packages. Example (if published):
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @izara_frontend/service-schemas
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Initialization (required once, before using hooks)**
|
|
21
|
+
- Call `initGetSchemaTools` in a parent component or application bootstrap code. The `initGetSchemaTools` call persists across components and only needs to be done once per app lifetime.
|
|
22
|
+
|
|
23
|
+
Example (typical place: app entry or parent module):
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
import { initGetSchemaTools } from "@izara_frontend/service-schemas";
|
|
27
|
+
|
|
28
|
+
// These values come from your app: an injection helper, the Redux store, and your RTK Query postsApi factory.
|
|
29
|
+
initGetSchemaTools({
|
|
30
|
+
injectReducer: injectReducerV2,
|
|
31
|
+
store,
|
|
32
|
+
createPostsApi: createPostsApiV2
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- `injectReducer` should be a function that knows how to inject a reducer into your store (your app's implementation). If you use a helper `injectReducerV2` in your repo, pass it.
|
|
37
|
+
- `store` is the Redux store instance used by your app.
|
|
38
|
+
- `createPostsApi` is the factory that creates the postsApi used by the package; pass your app variant if you have one.
|
|
39
|
+
|
|
40
|
+
**Using exported helpers (example: `getObjectLinks`)**
|
|
41
|
+
- Each helper follows a small pattern: when called it returns a tuple and a callable object you can use directly.
|
|
42
|
+
|
|
43
|
+
Typical usage inside a component:
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
import React, { useEffect } from 'react';
|
|
47
|
+
import { getObjectLinks } from '@izara_frontend/service-schemas';
|
|
48
|
+
|
|
49
|
+
export default function MyComponent() {
|
|
50
|
+
// call at top-level of component
|
|
51
|
+
const [objLinksResults, getObjectLinksFn, objLinksOption] = getObjectLinks();
|
|
52
|
+
|
|
53
|
+
// objLinksResults and objLinksOption are React state objects managed by the hook
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
async function load() {
|
|
56
|
+
// "normal" call: the helper will update objLinksResults and objLinksOption state
|
|
57
|
+
const [schema, errorsFound] = await getObjectLinksFn({ serviceTag: 'xx', objectType: 'xx' });
|
|
58
|
+
// schema and errorsFound are the results of this call
|
|
59
|
+
}
|
|
60
|
+
load();
|
|
61
|
+
}, []);
|
|
62
|
+
|
|
63
|
+
return <div>...render using objLinksResults...</div>;
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Direct-trigger usage via `.initiate` (RTK-style)
|
|
68
|
+
|
|
69
|
+
- Some helper callables expose an `.initiate(params)` method. This returns a promise with the response and does NOT automatically push results into the returned React state tuple — it gives the result directly.
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
// using initiate to get the value directly
|
|
73
|
+
const [schema, errorsFound] = await getObjectLinksFn().initiate({ serviceTag: 'xx', objectType: 'xx' });
|
|
74
|
+
// This returns the fetched value immediately; it does not mutate objLinksResults / objLinksOption state.
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Difference between "normal" and `.initiate()`**
|
|
78
|
+
- Normal call (calling `getObjectLinksFn(params)`):
|
|
79
|
+
- Updates the returned `objLinksResults` and `objLinksOption` React state (so components re-render and you can read them directly).
|
|
80
|
+
- Useful when you want to keep the result in component state and react to changes.
|
|
81
|
+
- `.initiate(params)` call:
|
|
82
|
+
- Returns the response directly (a promise). It is useful when you want a one-off result (for example inside an async handler) and don't need the returned hook state to update.
|
|
83
|
+
- That call is usually useful for programmatic flows or server-side usage where you only need the returned value.
|
|
84
|
+
|
|
85
|
+
**Return shapes / tuple explained**
|
|
86
|
+
- The pattern is typically:
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
const [resultsState, actionFn, optionsState] = someGetFunction();
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
- `resultsState` — React state managed by the helper: contains last response (schema, data) and flags.
|
|
93
|
+
- `actionFn` — a callable function you can call with params to fetch. Also may expose `.initiate()` for direct returns.
|
|
94
|
+
- `optionsState` — optional object with metadata such as isLoading, isError, status, etc.
|
|
95
|
+
|
|
96
|
+
**Examples**
|
|
97
|
+
- Normal usage (keeps result in state):
|
|
98
|
+
|
|
99
|
+
```js
|
|
100
|
+
const [objLinksResults, getObjectLinksFn, objLinksOption] = getObjectLinks();
|
|
101
|
+
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
getObjectLinksFn({ serviceTag: 'shop', objectType: 'product' });
|
|
104
|
+
}, []);
|
|
105
|
+
|
|
106
|
+
// read results from objLinksResults
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- One-off result via `.initiate` (direct):
|
|
110
|
+
|
|
111
|
+
```js
|
|
112
|
+
const [, getObjectLinksFn] = getObjectLinks();
|
|
113
|
+
|
|
114
|
+
async function fetchNow() {
|
|
115
|
+
const [schema, errorsFound] = await getObjectLinksFn().initiate({ serviceTag: 'shop', objectType: 'product' });
|
|
116
|
+
// use schema directly
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Notes & best practices**
|
|
121
|
+
- Initialize `initGetSchemaTools` before using any of the exported helpers. A safe place is your app root or a parent component that mounts early.
|
|
122
|
+
- Place the `getObjectX` call (the `someGetFunction()` call) at top-level of your React component (not inside conditionals) so hooks rules are respected.
|
|
123
|
+
- Many helpers accept different params — check the helper signature you use. The package provides multiple fetch helpers (links, object schema, validators, etc.) each with their own param set.
|
|
124
|
+
- `.initiate()` will not update the hook-managed state; use it when you need a single direct result.
|
|
125
|
+
|
|
126
|
+
**Troubleshooting**
|
|
127
|
+
- If results are not appearing in `resultsState` after a normal call:
|
|
128
|
+
- Ensure `initGetSchemaTools` was called with the correct `store` and `createPostsApi`.
|
|
129
|
+
- Ensure the helper is used inside a component where the hook can run.
|
|
130
|
+
- If you get multiple or stale values, check cache keys and parameters passed to the helper.
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
---
|
package/index.js
CHANGED
package/package.json
CHANGED
package/src/getObjectSchema.js
CHANGED
|
@@ -819,6 +819,112 @@ export function getObjSchemaWithHierarchy() {
|
|
|
819
819
|
return [result, run, { errorsFound }];
|
|
820
820
|
}
|
|
821
821
|
|
|
822
|
+
export function collectObjectSchemaWithHierarchy() {
|
|
823
|
+
const [, getObjectSchemaWithHierarchyFn] = getObjSchemaWithHierarchy();
|
|
824
|
+
|
|
825
|
+
const [result, setResult] = useState(null);
|
|
826
|
+
const [errorsFound, setErrorsFound] = useState([]);
|
|
827
|
+
|
|
828
|
+
|
|
829
|
+
|
|
830
|
+
// ref to always read latest result inside async functions (avoids stale closures)
|
|
831
|
+
const resultRef = useRef(result);
|
|
832
|
+
useEffect(() => { resultRef.current = result; }, [result]);
|
|
833
|
+
|
|
834
|
+
// core executor that does the actual work and optionally updates hook state
|
|
835
|
+
const execute = useCallback(async (objType, { updateState = true } = {}) => {
|
|
836
|
+
|
|
837
|
+
async function collectObjectSchemaWithHierarchyMain(objType) {
|
|
838
|
+
|
|
839
|
+
// validate objType (some validators throw, some return errors)
|
|
840
|
+
try {
|
|
841
|
+
validateObjType(objType);
|
|
842
|
+
} catch (err) {
|
|
843
|
+
return [null, [err.message]];
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// compute mainObjTypeConcat and validate
|
|
847
|
+
const [mainObjTypeConcat, mainObjTypeErrors] = createObjTypeConcat(objType);
|
|
848
|
+
if (mainObjTypeErrors && mainObjTypeErrors.length) {
|
|
849
|
+
return [null, mainObjTypeErrors];
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// short-circuit: if updateState and we already have this objType in result, return cached value
|
|
853
|
+
if (updateState && resultRef.current && resultRef.current.hasOwnProperty(mainObjTypeConcat)) {
|
|
854
|
+
return [{ [mainObjTypeConcat]: resultRef.current[mainObjTypeConcat] }, []];
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
|
|
858
|
+
const [objSchema, getObjSchemaErrors] = await getObjectSchemaWithHierarchyFn().initiate(objType);
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
return [objSchema, getObjSchemaErrors];
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
try {
|
|
865
|
+
|
|
866
|
+
|
|
867
|
+
const [returnSchema, errorsFound] = await collectObjectSchemaWithHierarchyMain(objType);
|
|
868
|
+
// const schema = returnSchema ? { [createObjTypeConcat(objType)]: schema } : null;
|
|
869
|
+
|
|
870
|
+
let schema = null;
|
|
871
|
+
if (returnSchema) {
|
|
872
|
+
schema = { [createObjTypeConcat(objType)[0]]: returnSchema }
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
if (updateState) {
|
|
876
|
+
if (errorsFound && errorsFound.length) {
|
|
877
|
+
setErrorsFound(errorsFound);
|
|
878
|
+
setResult(null);
|
|
879
|
+
} else {
|
|
880
|
+
const [currentObjTypeConcat] = createObjTypeConcat(objType);
|
|
881
|
+
setResult(prev => {
|
|
882
|
+
// nothing to add
|
|
883
|
+
if (!schema || !Object.keys(schema).length) return prev;
|
|
884
|
+
|
|
885
|
+
// first-time fill
|
|
886
|
+
if (!prev) return schema;
|
|
887
|
+
|
|
888
|
+
// already have this objType => no update
|
|
889
|
+
if (prev.hasOwnProperty(currentObjTypeConcat)) return prev;
|
|
890
|
+
// merge but return a NEW object to trigger React update (do not mutate prev)
|
|
891
|
+
return { ...prev, ...schema };
|
|
892
|
+
});
|
|
893
|
+
|
|
894
|
+
setErrorsFound([]);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
return [schema, errorsFound];
|
|
899
|
+
} catch (err) {
|
|
900
|
+
const msg = err?.message || String(err);
|
|
901
|
+
if (updateState) {
|
|
902
|
+
setErrorsFound([msg]);
|
|
903
|
+
setResult(null);
|
|
904
|
+
}
|
|
905
|
+
return [null, [msg]];
|
|
906
|
+
}
|
|
907
|
+
}, [getObjectSchemaWithHierarchyFn]);
|
|
908
|
+
|
|
909
|
+
|
|
910
|
+
// run can be used two ways:
|
|
911
|
+
// 1) run(objType) -> updates hook state and returns Promise<[collected, errors]>
|
|
912
|
+
// 2) run().initiate(objType) -> does NOT touch hook state, returns Promise<[collected, errors]>
|
|
913
|
+
const run = useCallback((objType) => {
|
|
914
|
+
if (typeof objType === "undefined") {
|
|
915
|
+
return {
|
|
916
|
+
initiate: (objType) => execute(objType, { updateState: false }),
|
|
917
|
+
clear: () => { setResult(null); setErrorsFound([]); }
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
// direct call: update state
|
|
921
|
+
return execute(objType, { updateState: true });
|
|
922
|
+
}, [execute]);
|
|
923
|
+
|
|
924
|
+
return [result, run, { errorsFound }];
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
|
|
822
928
|
export function getObjSchemaCombineFieldNames() {
|
|
823
929
|
|
|
824
930
|
const [, getObjSchemaWithHierarchyFn] = getObjSchemaWithHierarchy();
|