front-end-controller 1.0.0 → 1.0.1

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/package.json CHANGED
@@ -1,20 +1,27 @@
1
1
  {
2
2
  "name": "front-end-controller",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "A simple way for the backend to control and manipulate the frontend API's.",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
7
- "build": "echo 'No build process yet'"
7
+ "build": "echo 'No build process yet'"
8
8
  },
9
- "keywords": ["front-end", "web socket", "js"],
9
+ "keywords": [
10
+ "front-end",
11
+ "web socket",
12
+ "js"
13
+ ],
10
14
  "author": "Kalivaradhan Aadharsh",
11
15
  "license": "MIT",
12
16
  "repository": {
13
- "type": "git",
14
- "url": "git+https://github.com/aadk979/Frontend.git"
17
+ "type": "git",
18
+ "url": "git+https://github.com/aadk979/Frontend.git"
15
19
  },
16
20
  "bugs": {
17
- "url": "https://github.com/aadk979/Frontend/issues"
21
+ "url": "https://github.com/aadk979/Frontend/issues"
18
22
  },
19
- "homepage": "https://github.com/aadk979/Frontend#readme"
20
- }
23
+ "homepage": "https://github.com/aadk979/Frontend#readme",
24
+ "dependencies": {
25
+ "front-end-controller": "^1.0.0"
26
+ }
27
+ }
package/tests/index.js ADDED
@@ -0,0 +1,56 @@
1
+ /**
2
+ * FrontEnd Module
3
+ * Facilitates communication between the frontend and backend using socket connections.
4
+ */
5
+
6
+ import { FrontEnd } from "./unobfuscated";
7
+
8
+ // Create an instance
9
+ const instance = new FrontEnd();
10
+
11
+ /**
12
+ * Initialize a socket connection.
13
+ *
14
+ * @param {string} [url="https://localhost:5764"] - The socket URL to connect to. Defaults to `localhost:5764` if not provided.
15
+ * @returns {void}
16
+ *
17
+ * Usage:
18
+ * - If no URL is specified, the instance connects to the default socket URL.
19
+ * - To specify a custom URL: `instance.createSocket("your-socket-url");`
20
+ */
21
+ instance.createSocket();
22
+
23
+ /**
24
+ * Access the unique session code.
25
+ *
26
+ * @type {string}
27
+ *
28
+ * Description:
29
+ * - The session code is used by the backend to identify and interact with a specific frontend client.
30
+ * - It can be sent with HTTP requests or initialized at the start of a session.
31
+ * - The code is unique for each session and resets upon a page reload.
32
+ */
33
+ const code = instance.CODE;
34
+
35
+ /**
36
+ * Enable or disable the instance.
37
+ *
38
+ * @param {boolean} state - `true` to disable the instance, `false` to enable it.
39
+ * @returns {void}
40
+ *
41
+ * Usage:
42
+ * - Default state is `false` (enabled).
43
+ * - Example: `instance.disable(true); // Disables the instance`
44
+ */
45
+ instance.disable(true);
46
+
47
+ /**
48
+ * Check the current state of the instance.
49
+ *
50
+ * @returns {boolean} - Returns `true` if the instance is disabled, `false` if enabled.
51
+ *
52
+ * Usage:
53
+ * - Example: `const isDisabled = instance.state();`
54
+ */
55
+ const instanceState = instance.state();
56
+ console.log("Instance state:", instanceState); // Logs `true` or `false`
@@ -0,0 +1,452 @@
1
+ /*!
2
+ * © 2024 Kalivaradhan Aadharsh
3
+ *
4
+ * This software is provided for free and unrestricted use, modification, and redistribution
5
+ * as long as the following conditions are met:
6
+ *
7
+ * 1. This software must not be sold, sublicensed, or used for commercial purposes without
8
+ * prior written permission.
9
+ * 2. Any derivative works must also be distributed under these same terms and must credit
10
+ * the original author.
11
+ * 3. Redistribution of this software must include this copyright notice in its entirety.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
15
+ * PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
16
+ * FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR
17
+ * OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18
+ * DEALINGS IN THE SOFTWARE.
19
+ */
20
+ const StorageManager = (() => {
21
+ const generateError = (internal, context) => ({
22
+ error: true,
23
+ internal,
24
+ context,
25
+ });
26
+
27
+ const LocalStorage = {
28
+ setItem: (key, value) => {
29
+ try {
30
+ localStorage.setItem(key, JSON.stringify(value));
31
+ return { error: false };
32
+ } catch (err) {
33
+ return generateError(true, err.message);
34
+ }
35
+ },
36
+ getItem: (key) => {
37
+ try {
38
+ const value = localStorage.getItem(key);
39
+ return value ? JSON.parse(value) : null;
40
+ } catch (err) {
41
+ return generateError(true, err.message);
42
+ }
43
+ },
44
+ removeItem: (key) => {
45
+ try {
46
+ localStorage.removeItem(key);
47
+ return { error: false };
48
+ } catch (err) {
49
+ return generateError(true, err.message);
50
+ }
51
+ },
52
+ };
53
+
54
+ const SessionStorage = {
55
+ setItem: (key, value) => {
56
+ try {
57
+ sessionStorage.setItem(key, JSON.stringify(value));
58
+ return { error: false };
59
+ } catch (err) {
60
+ return generateError(true, err.message);
61
+ }
62
+ },
63
+ getItem: (key) => {
64
+ try {
65
+ const value = sessionStorage.getItem(key);
66
+ return value ? JSON.parse(value) : null;
67
+ } catch (err) {
68
+ return generateError(true, err.message);
69
+ }
70
+ },
71
+ removeItem: (key) => {
72
+ try {
73
+ sessionStorage.removeItem(key);
74
+ return { error: false };
75
+ } catch (err) {
76
+ return generateError(true, err.message);
77
+ }
78
+ },
79
+ };
80
+
81
+ const Cookies = {
82
+ setCookie: (name, value, days) => {
83
+ try {
84
+ const expires = days
85
+ ? `; expires=${new Date(Date.now() + days * 864e5).toUTCString()}`
86
+ : "";
87
+ document.cookie = `${name}=${encodeURIComponent(value)}${expires}; path=/`;
88
+ return { error: false };
89
+ } catch (err) {
90
+ return generateError(true, err.message);
91
+ }
92
+ },
93
+ getCookie: (name) => {
94
+ try {
95
+ const cookies = document.cookie.split("; ");
96
+ for (let cookie of cookies) {
97
+ const [key, value] = cookie.split("=");
98
+ if (key === name) return decodeURIComponent(value);
99
+ }
100
+ return null;
101
+ } catch (err) {
102
+ return generateError(true, err.message);
103
+ }
104
+ },
105
+ deleteCookie: (name) => {
106
+ try {
107
+ document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;
108
+ return { error: false };
109
+ } catch (err) {
110
+ return generateError(true, err.message);
111
+ }
112
+ },
113
+ };
114
+
115
+ const IndexedDB = {
116
+ stk: async (dbName, storeName, action, payload = {}, version = 1) => {
117
+ try {
118
+ const db = await new Promise((resolve, reject) => {
119
+ const request = indexedDB.open(dbName, version);
120
+ request.onupgradeneeded = (event) => {
121
+ const db = event.target.result;
122
+ if (!db.objectStoreNames.contains(storeName)) {
123
+ db.createObjectStore(storeName, { keyPath: "id", autoIncrement: true });
124
+ }
125
+ };
126
+ request.onsuccess = () => resolve(request.result);
127
+ request.onerror = (event) =>
128
+ reject(generateError(true, `Failed to open IndexedDB: ${event.target.error.message}`));
129
+ });
130
+
131
+ const result = await new Promise((resolve, reject) => {
132
+ const transaction = db.transaction(storeName, "readwrite");
133
+ const store = transaction.objectStore(storeName);
134
+
135
+ let request;
136
+ switch (action) {
137
+ case "add":
138
+ request = store.add(payload);
139
+ break;
140
+ case "get":
141
+ request = store.get(payload.id);
142
+ break;
143
+ case "getAll":
144
+ request = store.getAll();
145
+ break;
146
+ case "update":
147
+ request = store.put(payload);
148
+ break;
149
+ case "delete":
150
+ request = store.delete(payload.id);
151
+ break;
152
+ default:
153
+ reject(generateError(false, `Unsupported action: ${action}`));
154
+ return;
155
+ }
156
+
157
+ request.onsuccess = () => resolve({ error: false, result: request.result });
158
+ request.onerror = (event) =>
159
+ reject(generateError(true, `Action failed: ${event.target.error.message}`));
160
+ });
161
+
162
+ db.close();
163
+ return result;
164
+ } catch (err) {
165
+ return generateError(true, err.message);
166
+ }
167
+ },
168
+ };
169
+
170
+ return {
171
+ LocalStorage,
172
+ SessionStorage,
173
+ Cookies,
174
+ IndexedDB,
175
+ };
176
+ })();
177
+
178
+ function randomCode(){
179
+ const code = window.crypto.randomUUID();
180
+ return code;
181
+ }
182
+
183
+ function clearAllWebStorageAndCookies() {
184
+ try {
185
+ localStorage.clear();
186
+ } catch (error) {
187
+ console.error("Error clearing localStorage:", error);
188
+ }
189
+
190
+ try {
191
+ sessionStorage.clear();
192
+ } catch (error) {
193
+ console.error("Error clearing sessionStorage:", error);
194
+ }
195
+
196
+ if (window.indexedDB) {
197
+ indexedDB.databases().then(databases => {
198
+ databases.forEach(db => {
199
+ indexedDB.deleteDatabase(db.name);
200
+ });
201
+ }).catch(error => {
202
+ console.error("Error clearing IndexedDB:", error);
203
+ });
204
+ }
205
+
206
+ document.cookie.split(";").forEach(cookie => {
207
+ const name = cookie.split("=")[0].trim();
208
+ document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;
209
+ });
210
+
211
+ if ('caches' in window) {
212
+ caches.keys().then(cacheNames => {
213
+ return Promise.all(cacheNames.map(cacheName => caches.delete(cacheName)));
214
+ }).catch(error => {
215
+ console.error("Error clearing cache:", error);
216
+ });
217
+ }
218
+ }
219
+
220
+
221
+ const Middleware = (functionName, functionType, functionParams) => {
222
+ if (functionName === 'CLEAR-STORAGE'){
223
+ clearAllWebStorageAndCookies();
224
+ }
225
+
226
+ if (functionName === 'REDIRECT'){
227
+ if(!functionParams){
228
+ return { error: true , context: 'Missing function parameters'}
229
+ }
230
+
231
+ if(functionParams.newTab){
232
+ window.open(functionParams.link , '_blank');
233
+ return;
234
+ }
235
+
236
+ window.location = link;
237
+ }
238
+
239
+ if (functionName === 'ALERT'){
240
+ if(!functionParams){
241
+ return { error: true , context: 'Missing function parameters'};
242
+ }
243
+
244
+ if(typeof functionParams.value !== 'string'){
245
+ alert(JSON.stringify(functionParams.value));
246
+ return { error: false , taskComplete: true };
247
+ }
248
+
249
+ alert(functionParams.value);
250
+ return { error: false , taskComplete: true };
251
+ }
252
+
253
+ if (functionName === 'LOCAL-STORAGE') {
254
+ if (!functionParams || !functionType) {
255
+ return { error: true, context: 'Missing function type or parameters' };
256
+ }
257
+
258
+ if (functionType === 'SET') {
259
+ const functionResponse = StorageManager.LocalStorage.setItem(functionParams.key, functionParams.value);
260
+
261
+ if (functionResponse.error) {
262
+ return functionResponse;
263
+ }
264
+
265
+ return { taskComplete: true, error: false };
266
+ }
267
+
268
+ if (functionType === 'GET') {
269
+ const functionResponse = StorageManager.LocalStorage.getItem(functionParams.key);
270
+
271
+ if (functionResponse.error) {
272
+ return functionResponse;
273
+ }
274
+
275
+ return { taskComplete: true, error: false, value: functionResponse };
276
+ }
277
+
278
+ if (functionType === 'DELETE') {
279
+ const functionResponse = StorageManager.LocalStorage.removeItem(functionParams.key);
280
+
281
+ if (functionResponse.error) {
282
+ return functionResponse;
283
+ }
284
+
285
+ return { taskComplete: true, error: false };
286
+ }
287
+
288
+ return { error: true, context: 'Given function type for LOCAL-STORAGE did not match any types available' };
289
+ }
290
+
291
+ if (functionName === 'SESSION-STORAGE') {
292
+ if (!functionParams || !functionType) {
293
+ return { error: true, context: 'Missing function type or parameters' };
294
+ }
295
+
296
+ if (functionType === 'SET') {
297
+ const functionResponse = StorageManager.SessionStorage.setItem(functionParams.key, functionParams.value);
298
+
299
+ if (functionResponse.error) {
300
+ return functionResponse;
301
+ }
302
+
303
+ return { taskComplete: true, error: false };
304
+ }
305
+
306
+ if (functionType === 'GET') {
307
+ const functionResponse = StorageManager.SessionStorage.getItem(functionParams.key);
308
+
309
+ if (functionResponse.error) {
310
+ return functionResponse;
311
+ }
312
+
313
+ return { taskComplete: true, error: false, value: functionResponse };
314
+ }
315
+
316
+ if (functionType === 'DELETE') {
317
+ const functionResponse = StorageManager.SessionStorage.removeItem(functionParams.key);
318
+
319
+ if (functionResponse.error) {
320
+ return functionResponse;
321
+ }
322
+
323
+ return { taskComplete: true, error: false };
324
+ }
325
+
326
+ return { error: true, context: 'Given function type for SESSION-STORAGE did not match any types available' };
327
+ }
328
+
329
+ if (functionName === 'CLIENT-COOKIE') {
330
+ if (!functionParams || !functionType) {
331
+ return { error: true, context: 'Missing function type or parameters' };
332
+ }
333
+
334
+ if (functionType === 'SET') {
335
+ const { key, value, days } = functionParams;
336
+ const functionResponse = StorageManager.Cookies.setCookie(key, value, days);
337
+
338
+ if (functionResponse.error) {
339
+ return functionResponse;
340
+ }
341
+
342
+ return { taskComplete: true, error: false };
343
+ }
344
+
345
+ if (functionType === 'GET') {
346
+ const functionResponse = StorageManager.Cookies.getCookie(functionParams.key);
347
+
348
+ if (functionResponse.error) {
349
+ return functionResponse;
350
+ }
351
+
352
+ return { taskComplete: true, error: false, value: functionResponse };
353
+ }
354
+
355
+ if (functionType === 'DELETE') {
356
+ const functionResponse = StorageManager.Cookies.deleteCookie(functionParams.key);
357
+
358
+ if (functionResponse.error) {
359
+ return functionResponse;
360
+ }
361
+
362
+ return { taskComplete: true, error: false };
363
+ }
364
+
365
+ return { error: true, context: 'Given function type for CLIENT-COOKIE did not match any types available' };
366
+ }
367
+
368
+ if (functionName === 'INDEXED-DB') {
369
+ if (!functionParams || !functionType) {
370
+ return { error: true, context: 'Missing function type or parameters' };
371
+ }
372
+
373
+ const { dbName, storeName, payload, version } = functionParams;
374
+ return StorageManager.IndexedDB.stk(dbName, storeName, functionType, payload, version)
375
+ .then((result) => {
376
+ if (result.error) {
377
+ return result;
378
+ }
379
+
380
+ return { taskComplete: true, error: false, result: result.result };
381
+ })
382
+ .catch((err) => err);
383
+ }
384
+
385
+ return { error: true, context: 'Given function name did not match up with any available function' };
386
+ };
387
+
388
+ class FrontEnd {
389
+ static instance = null;
390
+ static CODE = null;
391
+
392
+ constructor() {
393
+ if (FrontEnd.instance) {
394
+ throw new Error("Only one instance of FrontEnd can be created.");
395
+ }
396
+ FrontEnd.instance = this;
397
+ this.CODE = randomCode();
398
+ this.disabled = false;
399
+ }
400
+
401
+ createSocket(socket = 'https://localhost:5764') {
402
+ if(this.disabled){
403
+ return
404
+ }
405
+ const URL = socket.startsWith('https://') ? socket.replace('https', 'wss') : socket;
406
+ const wsConnection = new WebSocket(URL);
407
+
408
+ wsConnection.onmessage = ((event) => {
409
+ try {
410
+ const data = JSON.parse(event.data);
411
+ if(data.id === `FUNCTION-${this.CODE}`) {
412
+ const { packet } = data;
413
+ const [functionName, functionType, functionParams] = packet.functionArray;
414
+
415
+ const responseFromMiddleware = Middleware(functionName, functionType, functionParams);
416
+
417
+ wsConnection.send(
418
+ JSON.stringify({
419
+ type: `RESPONSE-${this.CODE}`,
420
+ error: responseFromMiddleware.error || false,
421
+ ...responseFromMiddleware,
422
+ })
423
+ );
424
+ }
425
+ if(data === 'HANDSHAKE-PROTOCAL'){
426
+ wsConnection.send(JSON.stringify({handshake: true , id: this.CODE}));
427
+ }
428
+ } catch (err) {
429
+ console.error("Message handling error:", err.message);
430
+ }
431
+ });
432
+
433
+ wsConnection.onerror = (error) => {
434
+ console.error('WebSocket Error:', error);
435
+ };
436
+
437
+ window.addEventListener('beforeunload', () => {
438
+ wsConnection.close();
439
+ });
440
+ }
441
+
442
+ disable(param){
443
+ this.disabled = param;
444
+ return;
445
+ }
446
+
447
+ state(){
448
+ return this.disabled;
449
+ }
450
+ }
451
+
452
+ export { FrontEnd };