react-broadcast-sync 1.0.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.
@@ -0,0 +1,128 @@
1
+ const INTERNAL_PREFIX = '__INTERNAL__';
2
+ const SECRET = 'react-broadcast-sync';
3
+
4
+ // Generate a random 9-character alphanumeric string
5
+ export const generateRandomPart = () => Math.random().toString(36).substr(2, 9);
6
+
7
+ // Generate a unique source name for a tab
8
+ export const generateSourceName = () => `tab-${generateRandomPart()}`;
9
+
10
+ // Generate a unique message ID
11
+ export const generateMessageId = (source: string, timestamp: number) => {
12
+ const raw = `${generateRandomPart()}-${source}-${timestamp}`;
13
+ return btoa(raw).replace(/=+$/, '');
14
+ };
15
+
16
+ // Check if a message is valid
17
+ export const isValidMessage = (message: any): boolean => {
18
+ return Boolean(message && typeof message === 'object' && 'id' in message);
19
+ };
20
+
21
+ // Check if a message has expired
22
+ export const isMessageExpired = (message: { expirationDate?: number }): boolean => {
23
+ return message.expirationDate ? message.expirationDate < Date.now() : false;
24
+ };
25
+
26
+ // Create a new message object
27
+ export const createMessage = (
28
+ type: string,
29
+ content: any,
30
+ source: string,
31
+ options: { expirationDate?: number; expirationDuration?: number } = {}
32
+ ): any => {
33
+ const timestamp = Date.now();
34
+ return {
35
+ id: generateMessageId(source, timestamp),
36
+ type,
37
+ message: content,
38
+ timestamp,
39
+ source,
40
+ expirationDate: options.expirationDate ??
41
+ (options.expirationDuration ? timestamp + options.expirationDuration : undefined),
42
+ };
43
+ };
44
+
45
+
46
+ export const getInternalMessageType = (
47
+ baseType: 'CLEAR_MESSAGE' | 'CLEAR_ALL_MESSAGES',
48
+ channelName: string,
49
+ namespace = ''
50
+ ): string => {
51
+ const fullChannel = `${channelName}-${namespace}`;
52
+ const input = `${SECRET}:${baseType}:${fullChannel}`;
53
+ const hash = btoa(input); // optional: use sha256 if added
54
+ return `${INTERNAL_PREFIX}:${baseType}:${hash}`;
55
+ };
56
+
57
+ export const isInternalType = (type: string): boolean => {
58
+ return type.startsWith(`${INTERNAL_PREFIX}:`);
59
+ };
60
+
61
+ export const isValidInternalClearMessage = (message: any): message is { id: string, type: string, source: string } => {
62
+ return (
63
+ message &&
64
+ typeof message === 'object' &&
65
+ typeof message.id === 'string' &&
66
+ typeof message.source === 'string' &&
67
+ typeof message.type === 'string' &&
68
+ isInternalType(message.type)
69
+ );
70
+ }
71
+
72
+ export const debounce = <T extends (...args: any[]) => any>(
73
+ fn: T,
74
+ wait: number
75
+ ): ((...args: Parameters<T>) => void) & {
76
+ cancel: () => void;
77
+ flush: () => ReturnType<T> | undefined;
78
+ } => {
79
+ let timeoutId: ReturnType<typeof setTimeout> | null = null;
80
+ let lastArgs: Parameters<T> | null = null;
81
+ let lastThis: any = null;
82
+ let result: ReturnType<T> | undefined;
83
+
84
+ const debounced = function(this: any, ...args: Parameters<T>) {
85
+ lastArgs = args;
86
+ lastThis = this;
87
+
88
+ if (timeoutId !== null) {
89
+ clearTimeout(timeoutId);
90
+ }
91
+
92
+ timeoutId = setTimeout(() => {
93
+ timeoutId = null;
94
+ if (lastArgs !== null) {
95
+ result = fn.apply(lastThis, lastArgs);
96
+ lastArgs = null;
97
+ lastThis = null;
98
+ }
99
+ }, wait);
100
+ };
101
+
102
+ debounced.cancel = () => {
103
+ if (timeoutId !== null) {
104
+ clearTimeout(timeoutId);
105
+ timeoutId = null;
106
+ lastArgs = null;
107
+ lastThis = null;
108
+ }
109
+ };
110
+
111
+ debounced.flush = () => {
112
+ if (timeoutId !== null) {
113
+ clearTimeout(timeoutId);
114
+ timeoutId = null;
115
+ if (lastArgs !== null) {
116
+ result = fn.apply(lastThis, lastArgs);
117
+ lastArgs = null;
118
+ lastThis = null;
119
+ }
120
+ }
121
+ return result;
122
+ };
123
+
124
+ return debounced as typeof debounced & {
125
+ cancel: () => void;
126
+ flush: () => ReturnType<T> | undefined;
127
+ };
128
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES6",
4
+ "lib": ["DOM", "ES2017"],
5
+ "module": "ESNext",
6
+ "moduleResolution": "node",
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "jsx": "react-jsx",
12
+ "outDir": "./dist",
13
+ "declaration": true,
14
+ "declarationDir": "./dist",
15
+ "emitDeclarationOnly": false,
16
+ "isolatedModules": true,
17
+ "resolveJsonModule": true,
18
+ "allowSyntheticDefaultImports": true,
19
+ "noImplicitAny": true,
20
+ "strictNullChecks": true,
21
+ "strictFunctionTypes": true,
22
+ "strictBindCallApply": true,
23
+ "strictPropertyInitialization": true,
24
+ "noImplicitThis": true,
25
+ "alwaysStrict": true,
26
+ "noUnusedLocals": true,
27
+ "noUnusedParameters": true,
28
+ "noImplicitReturns": true,
29
+ "noFallthroughCasesInSwitch": true,
30
+ "allowJs": true,
31
+ "checkJs": false,
32
+ "types": ["jest", "node", "react"]
33
+ },
34
+ "include": ["src/**/*"],
35
+ "exclude": ["node_modules", "dist"]
36
+ }