structured-fw 1.7.4 → 1.7.7
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
CHANGED
|
@@ -206,6 +206,8 @@ Session allows you to store temporary data for the users of your web application
|
|
|
206
206
|
|
|
207
207
|
Session data is tied to a visitor via sessionId, which is always available on `RequestContext`, which means you can interact with session data from routes and server side part of your components.
|
|
208
208
|
|
|
209
|
+
*Session data is stored in memory, which means it is lost when you restart the app. If you want to have persistent sessions that survive restart, you can use [structured-plugin-session-redis](https://www.npmjs.com/package/structured-plugin-session-redis).*
|
|
210
|
+
|
|
209
211
|
**Configuration**\
|
|
210
212
|
`StructuredConfig`.`session`:
|
|
211
213
|
```
|
|
@@ -590,6 +592,9 @@ Your lucky number is {{luckyNumber}}<br>
|
|
|
590
592
|
```
|
|
591
593
|
|
|
592
594
|
That's it. `AnotherComponent` will receive the `luckyNumber` as a number, you can pass any type of data, string, number, boolean, object, array... it will be received by the child as the same type of data. However, *keep in mind the data gets serialized and de-serialized in the process, so if you pass an object to a child, it won't be a reference to the original object, rather a copy of it*.
|
|
595
|
+
|
|
596
|
+
Since version 1.7.6, additional data types can be passed to child components without them breaking due to serialization: Date, BigInt, RegExp, Map, Uint8Array. *Let me know if you need support for more types that JSON.stringify breaks.*
|
|
597
|
+
|
|
593
598
|
\
|
|
594
599
|
Let's see how we can use the passed data within `AnotherComponent`, create `/app/views/AnotherComponent/AnotherComponent.html`:
|
|
595
600
|
```
|
package/build/system/Util.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SerializableDate, SerializableRegExp, Serializable, ValueSerializable, SerializableBigInt, SerializableMap, SerializableUint8Array } from './types/component.types.js';
|
|
1
2
|
import { LooseObject } from './types/general.types.js';
|
|
2
3
|
import { PostedDataDecoded } from "./types/request.types.js";
|
|
3
4
|
export declare function queryStringDecode(queryString: string, initialValue?: PostedDataDecoded, trimValues?: boolean): PostedDataDecoded;
|
|
@@ -10,13 +11,22 @@ export declare function isAsync(fn: Function): boolean;
|
|
|
10
11
|
export declare function randomString(len: number, method?: 'alphanumeric' | 'numbers' | 'letters' | 'lettersUppercase' | 'lettersLowercase'): string;
|
|
11
12
|
export declare function unique<T>(arr: Array<T>): Array<T>;
|
|
12
13
|
export declare function stripTags(contentWithHTML: string, keepTags?: Array<string>): string;
|
|
14
|
+
export declare function toSerializableValue(value: any): ValueSerializable;
|
|
15
|
+
export declare function fromSerializableValue(data: SerializableDate): Date;
|
|
16
|
+
export declare function fromSerializableValue(data: SerializableRegExp): RegExp;
|
|
17
|
+
export declare function fromSerializableValue(data: SerializableMap): Map<any, any>;
|
|
18
|
+
export declare function fromSerializableValue(data: SerializableBigInt): BigInt;
|
|
19
|
+
export declare function fromSerializableValue(data: SerializableUint8Array): Uint8Array;
|
|
20
|
+
export declare function fromSerializableValue(data: Serializable): any;
|
|
21
|
+
export declare function serializableObject(data: LooseObject): LooseObject;
|
|
22
|
+
export declare function deserializeObject(data: LooseObject): LooseObject;
|
|
13
23
|
export declare function attributeValueToString(key: string, value: any): string;
|
|
14
24
|
export declare function attributeValueFromString(attributeValue: string): string | {
|
|
15
25
|
key: string;
|
|
16
26
|
value: any;
|
|
17
27
|
};
|
|
18
28
|
export declare function attributeValueEscape(str: string): string;
|
|
19
|
-
export declare function isObject(
|
|
29
|
+
export declare function isObject(value: any): boolean;
|
|
20
30
|
export declare function equalDeep(a: LooseObject, b: LooseObject): boolean;
|
|
21
31
|
export declare function mergeDeep(target: any, ...sources: Array<any>): LooseObject;
|
|
22
32
|
export declare function stripBOM(str: string): string;
|
package/build/system/Util.js
CHANGED
|
@@ -235,8 +235,103 @@ function bytesToBase64(bytes) {
|
|
|
235
235
|
return prev + String.fromCharCode(curr);
|
|
236
236
|
}, ''));
|
|
237
237
|
}
|
|
238
|
+
export function toSerializableValue(value) {
|
|
239
|
+
if (value instanceof Date) {
|
|
240
|
+
return {
|
|
241
|
+
__structured_value: true,
|
|
242
|
+
type: 'date',
|
|
243
|
+
value: value.toISOString(),
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
if (typeof value === 'bigint') {
|
|
247
|
+
return {
|
|
248
|
+
__structured_value: true,
|
|
249
|
+
type: 'bigint',
|
|
250
|
+
value: value.toString(),
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
if (value instanceof RegExp) {
|
|
254
|
+
return {
|
|
255
|
+
__structured_value: true,
|
|
256
|
+
type: 'regexp',
|
|
257
|
+
value: {
|
|
258
|
+
source: value.source,
|
|
259
|
+
flags: value.flags,
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
if (value instanceof Map) {
|
|
264
|
+
return {
|
|
265
|
+
__structured_value: true,
|
|
266
|
+
type: 'map',
|
|
267
|
+
value: [...value.entries()],
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
if (value instanceof Uint8Array) {
|
|
271
|
+
return {
|
|
272
|
+
__structured_value: true,
|
|
273
|
+
type: 'uint8array',
|
|
274
|
+
value: Array.from(value),
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
__structured_value: true,
|
|
279
|
+
value,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
export function fromSerializableValue(data) {
|
|
283
|
+
if (!('type' in data)) {
|
|
284
|
+
return data.value;
|
|
285
|
+
}
|
|
286
|
+
if (data.type === 'date') {
|
|
287
|
+
return new Date(data.value);
|
|
288
|
+
}
|
|
289
|
+
if (data.type === 'regexp') {
|
|
290
|
+
return new RegExp(data.value.source, data.value.flags);
|
|
291
|
+
}
|
|
292
|
+
if (data.type === 'map') {
|
|
293
|
+
return new Map(data.value);
|
|
294
|
+
}
|
|
295
|
+
if (data.type === 'bigint') {
|
|
296
|
+
return BigInt(data.value);
|
|
297
|
+
}
|
|
298
|
+
if (data.type === 'uint8array') {
|
|
299
|
+
return new Uint8Array(data.value);
|
|
300
|
+
}
|
|
301
|
+
return undefined;
|
|
302
|
+
}
|
|
303
|
+
export function serializableObject(data) {
|
|
304
|
+
const copy = {};
|
|
305
|
+
objectEach(data, (key, val) => {
|
|
306
|
+
if (isObject(val)) {
|
|
307
|
+
copy[key] = serializableObject(val);
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
copy[key] = toSerializableValue(val);
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
return copy;
|
|
314
|
+
}
|
|
315
|
+
export function deserializeObject(data) {
|
|
316
|
+
const copy = {};
|
|
317
|
+
objectEach(data, (key, val) => {
|
|
318
|
+
if (typeof val === 'object' && val !== null && val !== undefined) {
|
|
319
|
+
if ('__structured_value' in val) {
|
|
320
|
+
copy[key] = fromSerializableValue(val);
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
copy[key] = deserializeObject(val);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
copy[key] = fromSerializableValue(val);
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
return copy;
|
|
331
|
+
}
|
|
238
332
|
export function attributeValueToString(key, value) {
|
|
239
|
-
|
|
333
|
+
const data = serializableObject({ key, data: value });
|
|
334
|
+
return 'base64:' + bytesToBase64(new TextEncoder().encode(JSON.stringify(data)));
|
|
240
335
|
}
|
|
241
336
|
export function attributeValueFromString(attributeValue) {
|
|
242
337
|
if (attributeValue.indexOf('base64:') === 0) {
|
|
@@ -245,11 +340,14 @@ export function attributeValueFromString(attributeValue) {
|
|
|
245
340
|
if (decoded.indexOf('{') !== 0) {
|
|
246
341
|
return attributeValue;
|
|
247
342
|
}
|
|
248
|
-
const valObj = JSON.parse(decoded);
|
|
343
|
+
const valObj = deserializeObject(JSON.parse(decoded));
|
|
249
344
|
if (!('key' in valObj)) {
|
|
250
345
|
return decoded;
|
|
251
346
|
}
|
|
252
|
-
return
|
|
347
|
+
return {
|
|
348
|
+
key: valObj.key,
|
|
349
|
+
value: valObj.data,
|
|
350
|
+
};
|
|
253
351
|
}
|
|
254
352
|
catch (e) {
|
|
255
353
|
return attributeValue;
|
|
@@ -260,11 +358,11 @@ export function attributeValueFromString(attributeValue) {
|
|
|
260
358
|
export function attributeValueEscape(str) {
|
|
261
359
|
return str.replaceAll('"', '"');
|
|
262
360
|
}
|
|
263
|
-
export function isObject(
|
|
264
|
-
if (typeof
|
|
265
|
-
return
|
|
266
|
-
|
|
267
|
-
return
|
|
361
|
+
export function isObject(value) {
|
|
362
|
+
if (value === null || typeof value !== 'object')
|
|
363
|
+
return false;
|
|
364
|
+
const proto = Object.getPrototypeOf(value);
|
|
365
|
+
return proto === Object.prototype || proto === null;
|
|
268
366
|
}
|
|
269
367
|
export function equalDeep(a, b) {
|
|
270
368
|
if (a === b) {
|
|
@@ -26,7 +26,7 @@ export declare class Application {
|
|
|
26
26
|
constructor(config: StructuredConfig);
|
|
27
27
|
init(): Promise<void>;
|
|
28
28
|
private start;
|
|
29
|
-
on<E extends ApplicationEvents>(evt: E, callback: (payload: E extends 'beforeRequestHandler' | 'afterRequestHandler' | 'beforeAssetAccess' | 'afterAssetAccess' | 'pageNotFound' | 'requestHandleError' ? RequestContext<RequestContextData> : E extends 'documentCreated' ? Document : E extends 'afterComponentsLoaded' ? Components : E extends 'serverStarted' ? Server : E extends 'sessionsStart' ? Session : E extends 'sessionsStop' ? Session : E extends 'sessionCreated' ? SessionEntry : E extends 'sessionExpired' ? string : E extends 'sessionValueSet' ? [string, string, any] : E extends 'sessionValueRemove' ? [string, string] :
|
|
29
|
+
on<E extends ApplicationEvents>(evt: E, callback: (payload: E extends 'beforeRequestHandler' | 'afterRequestHandler' | 'beforeAssetAccess' | 'afterAssetAccess' | 'pageNotFound' | 'requestHandleError' ? RequestContext<RequestContextData> : E extends 'documentCreated' ? Document : E extends 'afterComponentsLoaded' ? Components : E extends 'serverStarted' ? Server : E extends 'sessionsStart' ? Session : E extends 'sessionsStop' ? Session : E extends 'sessionCreated' ? SessionEntry : E extends 'sessionExpired' | 'sessionExtended' | 'sessionClear' ? string : E extends 'sessionValueSet' ? [string, string, any] : E extends 'sessionValueRemove' ? [string, string] : undefined) => void): void;
|
|
30
30
|
emit(eventName: ApplicationEvents, payload?: any): Promise<Array<any>>;
|
|
31
31
|
importEnv<T extends LooseObject>(smartPrimitives?: boolean): T;
|
|
32
32
|
exportContextFields(...fields: Array<keyof RequestContextData>): void;
|
|
@@ -39,6 +39,43 @@ export type ComponentEvents = {
|
|
|
39
39
|
componentCreated: Component;
|
|
40
40
|
ready: undefined;
|
|
41
41
|
};
|
|
42
|
+
export type Serializable = {
|
|
43
|
+
__structured_value: true;
|
|
44
|
+
value: any;
|
|
45
|
+
};
|
|
46
|
+
export type SerializableDate = {
|
|
47
|
+
__structured_value: true;
|
|
48
|
+
type: 'date';
|
|
49
|
+
value: string;
|
|
50
|
+
};
|
|
51
|
+
export type SerializableRegExp = {
|
|
52
|
+
__structured_value: true;
|
|
53
|
+
type: 'regexp';
|
|
54
|
+
value: {
|
|
55
|
+
source: string;
|
|
56
|
+
flags: string;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
export type SerializableMap = {
|
|
60
|
+
__structured_value: true;
|
|
61
|
+
type: 'map';
|
|
62
|
+
value: Array<[any, any]>;
|
|
63
|
+
};
|
|
64
|
+
export type SerializableBigInt = {
|
|
65
|
+
__structured_value: true;
|
|
66
|
+
type: 'bigint';
|
|
67
|
+
value: string;
|
|
68
|
+
};
|
|
69
|
+
export type SerializableUint8Array = {
|
|
70
|
+
__structured_value: true;
|
|
71
|
+
type: 'uint8array';
|
|
72
|
+
value: Array<number>;
|
|
73
|
+
};
|
|
74
|
+
export type ValueSerializable = Serializable | SerializableDate | SerializableRegExp | SerializableMap | SerializableBigInt | SerializableUint8Array;
|
|
75
|
+
export type AttributeEncodedObject = {
|
|
76
|
+
key: string;
|
|
77
|
+
data: ValueSerializable;
|
|
78
|
+
};
|
|
42
79
|
export type ClientComponentTransition = {
|
|
43
80
|
fade: false | number;
|
|
44
81
|
slide: false | number;
|
package/package.json
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"type": "module",
|
|
21
21
|
"main": "build/index",
|
|
22
|
-
"version": "1.7.
|
|
22
|
+
"version": "1.7.7",
|
|
23
23
|
"scripts": {
|
|
24
24
|
"develop": "tsc --watch",
|
|
25
25
|
"startDev": "cd build && nodemon --watch '../app/**/*' --watch '../build/**/*' -e js,html,hbs,css index.js",
|