@carbonorm/carbonreact 6.0.1 → 6.0.3
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/core/CarbonReact.d.ts +4 -0
- package/dist/index.cjs +92 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.esm.js +88 -61
- package/dist/index.esm.js.map +1 -1
- package/dist/state/deleteRestfulObjectArrays.d.ts +3 -1
- package/dist/state/stateAdapter.d.ts +16 -0
- package/dist/state/updateRestfulObjectArrays.d.ts +3 -1
- package/package.json +1 -1
- package/src/components/WebSocket/CarbonWebSocket.tsx +45 -65
- package/src/core/CarbonReact.tsx +7 -1
- package/src/index.ts +1 -0
- package/src/state/deleteRestfulObjectArrays.tsx +20 -4
- package/src/state/stateAdapter.ts +37 -0
- package/src/state/updateRestfulObjectArrays.tsx +21 -7
|
@@ -4,6 +4,7 @@ import { iRestfulObjectArrayTypes } from "schema/C6";
|
|
|
4
4
|
import { iCarbonWebSocketProps } from "components/WebSocket/CarbonWebSocket";
|
|
5
5
|
import { iUpdateRestfulObjectArrays } from "state/updateRestfulObjectArrays";
|
|
6
6
|
import { iDeleteRestfulObjectArrays } from "state/deleteRestfulObjectArrays";
|
|
7
|
+
import { iStateAdapter } from "state/stateAdapter";
|
|
7
8
|
export type tStatefulApiData<T extends {
|
|
8
9
|
[key: string]: any;
|
|
9
10
|
} = {}> = T[] | undefined | null;
|
|
@@ -28,6 +29,7 @@ declare abstract class CarbonReact<P = {}, S extends iCarbonReactState = iCarbon
|
|
|
28
29
|
persistentState?: boolean;
|
|
29
30
|
routerType?: eRouterType;
|
|
30
31
|
websocket?: Omit<iCarbonWebSocketProps<P, S>, "instance"> | false;
|
|
32
|
+
stateAdapter?: iStateAdapter<S>;
|
|
31
33
|
} & P, S> {
|
|
32
34
|
private static allInstances;
|
|
33
35
|
context: Context<S & iCarbonReactState>;
|
|
@@ -49,7 +51,9 @@ declare abstract class CarbonReact<P = {}, S extends iCarbonReactState = iCarbon
|
|
|
49
51
|
websocket?: boolean | iCarbonWebSocketProps<P, S> | undefined;
|
|
50
52
|
instanceId?: string;
|
|
51
53
|
persistentState?: boolean;
|
|
54
|
+
stateAdapter?: iStateAdapter<S>;
|
|
52
55
|
} & P);
|
|
56
|
+
stateAdapter?: iStateAdapter<S>;
|
|
53
57
|
private static generateIdentifier;
|
|
54
58
|
private generateIdentifier;
|
|
55
59
|
shouldComponentUpdate(nextProps: Readonly<P>, nextState: Readonly<S>, _nextContext: any): boolean;
|
package/dist/index.cjs
CHANGED
|
@@ -2654,9 +2654,10 @@ exports.eUpdateInsertMethod = void 0;
|
|
|
2654
2654
|
* @param insertUpdateOrder - The order in which new data should be inserted/updated.
|
|
2655
2655
|
* @param callback - Optional callback function to run after state update.
|
|
2656
2656
|
*/
|
|
2657
|
-
function updateRestfulObjectArrays({ instance, dataOrCallback, stateKey, uniqueObjectId, insertUpdateOrder = exports.eUpdateInsertMethod.LAST, callback, }) {
|
|
2657
|
+
function updateRestfulObjectArrays({ instance, dataOrCallback, stateKey, uniqueObjectId, insertUpdateOrder = exports.eUpdateInsertMethod.LAST, callback, stateAdapter, }) {
|
|
2658
2658
|
const uniqueObjectIds = Array.isArray(uniqueObjectId) ? uniqueObjectId : [uniqueObjectId];
|
|
2659
|
-
|
|
2659
|
+
const resolvedStateAdapter = stateAdapter ?? instance.stateAdapter;
|
|
2660
|
+
const computeNextState = (previousBootstrapState, props) => {
|
|
2660
2661
|
let newOrReplacementData = [];
|
|
2661
2662
|
if (Array.isArray(dataOrCallback)) {
|
|
2662
2663
|
newOrReplacementData = dataOrCallback;
|
|
@@ -2711,12 +2712,23 @@ function updateRestfulObjectArrays({ instance, dataOrCallback, stateKey, uniqueO
|
|
|
2711
2712
|
throw new Error("The insertUpdateOrder (eUpdateInsertMethod) was not implemented");
|
|
2712
2713
|
}
|
|
2713
2714
|
return newState;
|
|
2714
|
-
}
|
|
2715
|
+
};
|
|
2716
|
+
if (resolvedStateAdapter) {
|
|
2717
|
+
const previousBootstrapState = resolvedStateAdapter.getState();
|
|
2718
|
+
const nextState = computeNextState(previousBootstrapState, instance.props);
|
|
2719
|
+
if (nextState !== null) {
|
|
2720
|
+
resolvedStateAdapter.setState(nextState);
|
|
2721
|
+
callback?.();
|
|
2722
|
+
}
|
|
2723
|
+
return;
|
|
2724
|
+
}
|
|
2725
|
+
instance.setState(computeNextState, callback);
|
|
2715
2726
|
}
|
|
2716
2727
|
|
|
2717
|
-
function deleteRestfulObjectArrays({ instance, dataOrCallback, stateKey, uniqueObjectId, callback }) {
|
|
2728
|
+
function deleteRestfulObjectArrays({ instance, dataOrCallback, stateKey, uniqueObjectId, callback, stateAdapter }) {
|
|
2718
2729
|
const uniqueObjectIds = Array.isArray(uniqueObjectId) ? uniqueObjectId : [uniqueObjectId];
|
|
2719
|
-
|
|
2730
|
+
const resolvedStateAdapter = stateAdapter ?? instance.stateAdapter;
|
|
2731
|
+
const computeNextState = (previousBootstrapState, props) => {
|
|
2720
2732
|
let newOrReplacementData = [];
|
|
2721
2733
|
if (Array.isArray(dataOrCallback)) {
|
|
2722
2734
|
newOrReplacementData = dataOrCallback;
|
|
@@ -2736,7 +2748,17 @@ function deleteRestfulObjectArrays({ instance, dataOrCallback, stateKey, uniqueO
|
|
|
2736
2748
|
return {
|
|
2737
2749
|
[stateKey]: updatedStateProperty
|
|
2738
2750
|
};
|
|
2739
|
-
}
|
|
2751
|
+
};
|
|
2752
|
+
if (resolvedStateAdapter) {
|
|
2753
|
+
const previousBootstrapState = resolvedStateAdapter.getState();
|
|
2754
|
+
const nextState = computeNextState(previousBootstrapState, instance.props);
|
|
2755
|
+
if (nextState !== null) {
|
|
2756
|
+
resolvedStateAdapter.setState(nextState);
|
|
2757
|
+
callback?.();
|
|
2758
|
+
}
|
|
2759
|
+
return;
|
|
2760
|
+
}
|
|
2761
|
+
instance.setState(computeNextState, callback);
|
|
2740
2762
|
}
|
|
2741
2763
|
|
|
2742
2764
|
const initialRequiredCarbonORMState = {
|
|
@@ -2812,11 +2834,13 @@ class CarbonReact extends react.Component {
|
|
|
2812
2834
|
CarbonReact.allInstances.set(identifier, this);
|
|
2813
2835
|
}
|
|
2814
2836
|
this.target = new.target;
|
|
2837
|
+
this.stateAdapter = props.stateAdapter;
|
|
2815
2838
|
console.log('CarbonORM TSX CONSTRUCTOR');
|
|
2816
2839
|
Object.assign(this.target, {
|
|
2817
2840
|
_instance: this
|
|
2818
2841
|
});
|
|
2819
2842
|
}
|
|
2843
|
+
stateAdapter;
|
|
2820
2844
|
static generateIdentifier(instanceId) {
|
|
2821
2845
|
const className = this.name;
|
|
2822
2846
|
return instanceId ? `${className}-${instanceId}` : className;
|
|
@@ -2961,15 +2985,8 @@ function initiateWebsocket(props) {
|
|
|
2961
2985
|
const METHOD = parsedData?.REST?.METHOD;
|
|
2962
2986
|
const REQUEST = parsedData?.REST?.REQUEST;
|
|
2963
2987
|
const REQUEST_PRIMARY_KEY = parsedData?.REST?.REQUEST_PRIMARY_KEY ?? null;
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
console.log('WebSocket updates without a primary key are not yet supported.');
|
|
2967
|
-
}
|
|
2968
|
-
return;
|
|
2969
|
-
}
|
|
2970
|
-
if (verbose) {
|
|
2971
|
-
console.log('todo - going to impl REST', TABLE_NAME, METHOD, REQUEST_PRIMARY_KEY, parsedData?.REST);
|
|
2972
|
-
}
|
|
2988
|
+
const RESPONSE_PRIMARY_KEY = parsedData?.REST?.RESPONSE_PRIMARY_KEY ?? null;
|
|
2989
|
+
const RESPONSE = parsedData?.REST?.RESPONSE ?? null;
|
|
2973
2990
|
const TABLE_NAME_SHORT = TABLE_NAME.startsWith(TABLE_PREFIX)
|
|
2974
2991
|
? TABLE_NAME.substring(TABLE_PREFIX.length)
|
|
2975
2992
|
: TABLE_NAME;
|
|
@@ -2995,20 +3012,36 @@ function initiateWebsocket(props) {
|
|
|
2995
3012
|
}
|
|
2996
3013
|
return normalized;
|
|
2997
3014
|
};
|
|
2998
|
-
const normalizedPrimaryKey = normalizeRecord(REQUEST_PRIMARY_KEY);
|
|
2999
|
-
const
|
|
3015
|
+
const normalizedPrimaryKey = normalizeRecord(REQUEST_PRIMARY_KEY ?? {});
|
|
3016
|
+
const normalizedResponsePrimaryKey = normalizeRecord(RESPONSE_PRIMARY_KEY ?? {});
|
|
3017
|
+
const primaryKeyKeys = Object.keys(Object.keys(normalizedPrimaryKey).length
|
|
3018
|
+
? normalizedPrimaryKey
|
|
3019
|
+
: normalizedResponsePrimaryKey);
|
|
3000
3020
|
if (primaryKeyKeys.length === 0) {
|
|
3001
3021
|
if (verbose) {
|
|
3002
|
-
console.error('WebSocket update could not map primary keys for', TABLE_NAME_SHORT, REQUEST_PRIMARY_KEY);
|
|
3022
|
+
console.error('WebSocket update could not map primary keys for', TABLE_NAME_SHORT, REQUEST_PRIMARY_KEY, RESPONSE_PRIMARY_KEY);
|
|
3003
3023
|
}
|
|
3004
3024
|
return;
|
|
3005
3025
|
}
|
|
3006
3026
|
// todo - which direction should we filter
|
|
3007
|
-
const elementsToUpdate = currentCache?.filter((row) => primaryKeyKeys.every((key) =>
|
|
3027
|
+
const elementsToUpdate = currentCache?.filter((row) => primaryKeyKeys.every((key) => {
|
|
3028
|
+
const expected = normalizedPrimaryKey[key] ?? normalizedResponsePrimaryKey[key];
|
|
3029
|
+
return expected === row[key];
|
|
3030
|
+
})) ?? [];
|
|
3008
3031
|
if (verbose) {
|
|
3009
3032
|
console.log('elementsToUpdate', elementsToUpdate);
|
|
3010
3033
|
}
|
|
3011
3034
|
if (elementsToUpdate.length === 0) {
|
|
3035
|
+
if (RESPONSE) {
|
|
3036
|
+
const responseRows = Array.isArray(RESPONSE) ? RESPONSE : [RESPONSE];
|
|
3037
|
+
const normalizedResponseRows = responseRows.map((row) => normalizeRecord(row));
|
|
3038
|
+
instance.updateRestfulObjectArrays({
|
|
3039
|
+
dataOrCallback: normalizedResponseRows,
|
|
3040
|
+
stateKey: TABLE_NAME_SHORT,
|
|
3041
|
+
uniqueObjectId: c6Table.PRIMARY_SHORT,
|
|
3042
|
+
});
|
|
3043
|
+
return;
|
|
3044
|
+
}
|
|
3012
3045
|
if (verbose) {
|
|
3013
3046
|
console.error('Could not find any elements to update in the cache.', elementsToUpdate, primaryKeyKeys, REQUEST_PRIMARY_KEY, currentCache);
|
|
3014
3047
|
}
|
|
@@ -3054,58 +3087,29 @@ function initiateWebsocket(props) {
|
|
|
3054
3087
|
console.log(`WebSocket reconnect will be attempted in ${retrySeconds} second(s).`);
|
|
3055
3088
|
connectInterval = setTimeout(() => initiateWebsocket(props), retrySeconds);
|
|
3056
3089
|
};
|
|
3057
|
-
|
|
3090
|
+
if (event.code === 1000) {
|
|
3091
|
+
console.log("WebSocket: closed cleanly");
|
|
3092
|
+
return;
|
|
3093
|
+
}
|
|
3058
3094
|
switch (event.code) {
|
|
3059
|
-
case 1000:
|
|
3060
|
-
reason = "Normal closure, meaning that the purpose for which the connection was established has been fulfilled.";
|
|
3061
|
-
break;
|
|
3062
|
-
case 1001:
|
|
3063
|
-
retry(); //call check function after timeout
|
|
3064
|
-
reason = "An endpoint is \"going away\", such as a server going down or a browser having navigated away from a page.";
|
|
3065
|
-
break;
|
|
3066
|
-
case 1002:
|
|
3067
|
-
reason = "An endpoint is terminating the connection due to a protocol error";
|
|
3068
|
-
break;
|
|
3069
|
-
case 1003:
|
|
3070
|
-
reason = "An endpoint is terminating the connection because it has received a type of data it cannot accept (e.g., an endpoint that understands only text data MAY send this if it receives a binary message).";
|
|
3071
|
-
break;
|
|
3072
|
-
case 1004:
|
|
3073
|
-
reason = "Reserved. The specific meaning might be defined in the future.";
|
|
3074
|
-
break;
|
|
3075
|
-
case 1005:
|
|
3076
|
-
reason = "No status code was actually present.";
|
|
3077
|
-
break;
|
|
3078
3095
|
case 1006:
|
|
3079
|
-
|
|
3080
|
-
reason = "The connection was closed abnormally, e.g., without sending or receiving a close control frame";
|
|
3081
|
-
break;
|
|
3082
|
-
case 1007:
|
|
3083
|
-
reason = "An endpoint is terminating the connection because it has received data within a message that was not consistent with the type of the message (e.g., non-UTF-8 [https://www.rfc-editor.org/rfc/rfc3629] data within a text message).";
|
|
3084
|
-
break;
|
|
3085
|
-
case 1008:
|
|
3086
|
-
reason = "An endpoint is terminating the connection because it has received a message that \"violates its policy\". This reason is given either if there is no other suitable reason, or if there is a need to hide specific details about the policy.";
|
|
3096
|
+
reason = "Abnormal closure";
|
|
3087
3097
|
break;
|
|
3088
|
-
case
|
|
3089
|
-
reason = "
|
|
3090
|
-
break;
|
|
3091
|
-
case 1010:
|
|
3092
|
-
reason = "An endpoint (client) is terminating the connection because it has expected the server to negotiate one or more extension, but the server didn't return them in the response message of the WebSocket handshake. <br /> Specifically, the extensions that are needed are: " + event.reason;
|
|
3098
|
+
case 1001:
|
|
3099
|
+
reason = "Going away";
|
|
3093
3100
|
break;
|
|
3094
3101
|
case 1011:
|
|
3095
|
-
reason = "
|
|
3096
|
-
break;
|
|
3097
|
-
case 1015:
|
|
3098
|
-
reason = "The connection was closed due to a failure to perform a TLS handshake (e.g., the server certificate can't be verified).";
|
|
3102
|
+
reason = "Internal server error";
|
|
3099
3103
|
break;
|
|
3100
3104
|
default:
|
|
3101
|
-
reason = "Unknown
|
|
3105
|
+
reason = "Unknown";
|
|
3102
3106
|
}
|
|
3103
|
-
console.log(
|
|
3107
|
+
console.log(`WebSocket: closed with code ${event.code} (${reason})`);
|
|
3108
|
+
retry();
|
|
3104
3109
|
});
|
|
3105
3110
|
// websocket onerror event listener
|
|
3106
3111
|
connection.addEventListener('websocket error', (e) => {
|
|
3107
|
-
console.error("
|
|
3108
|
-
connection.close();
|
|
3112
|
+
console.error("WebSocket error observed:", e);
|
|
3109
3113
|
});
|
|
3110
3114
|
});
|
|
3111
3115
|
}
|
|
@@ -3262,6 +3266,29 @@ function useWindowDimensions() {
|
|
|
3262
3266
|
return windowDimensions;
|
|
3263
3267
|
}
|
|
3264
3268
|
|
|
3269
|
+
class InMemoryStateAdapter {
|
|
3270
|
+
state;
|
|
3271
|
+
constructor(initialState) {
|
|
3272
|
+
this.state = initialState;
|
|
3273
|
+
}
|
|
3274
|
+
getState() {
|
|
3275
|
+
return this.state;
|
|
3276
|
+
}
|
|
3277
|
+
setState(partial) {
|
|
3278
|
+
this.state = { ...this.state, ...partial };
|
|
3279
|
+
}
|
|
3280
|
+
snapshot() {
|
|
3281
|
+
return this.state;
|
|
3282
|
+
}
|
|
3283
|
+
hydrate(snapshot) {
|
|
3284
|
+
this.state = snapshot;
|
|
3285
|
+
}
|
|
3286
|
+
}
|
|
3287
|
+
const serializeStateSnapshot = (state) => JSON.stringify(state);
|
|
3288
|
+
const deserializeStateSnapshot = (serialized) => JSON.parse(serialized);
|
|
3289
|
+
const getStateSnapshot = (adapter) => adapter.getState();
|
|
3290
|
+
const createInMemoryStateAdapter = (initialState) => new InMemoryStateAdapter(initialState);
|
|
3291
|
+
|
|
3265
3292
|
const addValidSQL = [];
|
|
3266
3293
|
function addValidSQL$1 (sql) {
|
|
3267
3294
|
const { expect } = require("@jest/globals");
|
|
@@ -3390,6 +3417,7 @@ exports.CarbonReact = CarbonReact;
|
|
|
3390
3417
|
exports.CarbonWebSocket = CarbonWebSocket;
|
|
3391
3418
|
exports.ErrorHttpCode = ErrorHttpCode;
|
|
3392
3419
|
exports.GlobalHistory = GlobalHistory;
|
|
3420
|
+
exports.InMemoryStateAdapter = InMemoryStateAdapter;
|
|
3393
3421
|
exports.Loading = Loading;
|
|
3394
3422
|
exports.OutsideClickHandler = OutsideClickHandler;
|
|
3395
3423
|
exports.PageNotFound = PageNotFound;
|
|
@@ -3400,12 +3428,15 @@ exports.addValidSQL = addValidSQL$1;
|
|
|
3400
3428
|
exports.carbons = carbons;
|
|
3401
3429
|
exports.changed = changed;
|
|
3402
3430
|
exports.comments = comments;
|
|
3431
|
+
exports.createInMemoryStateAdapter = createInMemoryStateAdapter;
|
|
3403
3432
|
exports.deleteRestfulObjectArrays = deleteRestfulObjectArrays;
|
|
3433
|
+
exports.deserializeStateSnapshot = deserializeStateSnapshot;
|
|
3404
3434
|
exports.documentation = documentation;
|
|
3405
3435
|
exports.feature_group_references = feature_group_references;
|
|
3406
3436
|
exports.features = features;
|
|
3407
3437
|
exports.getEnv = getEnv;
|
|
3408
3438
|
exports.getRootStyleValue = getRootStyleValue;
|
|
3439
|
+
exports.getStateSnapshot = getStateSnapshot;
|
|
3409
3440
|
exports.getStatefulObjectWithWhere = getStatefulObjectWithWhere;
|
|
3410
3441
|
exports.getStyles = getStyles;
|
|
3411
3442
|
exports.group_references = group_references;
|
|
@@ -3425,6 +3456,7 @@ exports.parseMultipleJson = parseMultipleJson;
|
|
|
3425
3456
|
exports.photos = photos;
|
|
3426
3457
|
exports.reports = reports;
|
|
3427
3458
|
exports.scrollIntoView = ScrollIntoViewDirective;
|
|
3459
|
+
exports.serializeStateSnapshot = serializeStateSnapshot;
|
|
3428
3460
|
exports.setCookies = setCookies;
|
|
3429
3461
|
exports.setupTests = setupTests;
|
|
3430
3462
|
exports.toDataURL = toDataURL;
|