Althnayi commited on
Commit
1e2c08f
·
verified ·
1 Parent(s): 0d5a385

Upload 70 files

Browse files
.htaccess CHANGED
@@ -1,4 +1,5 @@
1
  DirectoryIndex index.html
 
2
  <IfModule mod_rewrite.c>
3
  RewriteEngine On
4
  RewriteBase /
@@ -7,10 +8,26 @@ DirectoryIndex index.html
7
  RewriteCond %{REQUEST_FILENAME} !-d
8
  RewriteRule . /index.html [L]
9
  </IfModule>
 
10
  <IfModule mod_headers.c>
11
- <FilesMatch "r8x4m9q2v7z3c6n5t0y8p4w9h2k6w\.js$">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  Header set Cache-Control "no-cache, no-store, must-revalidate"
13
  </FilesMatch>
 
14
  <FilesMatch "manifest\.json$">
15
  Header set Content-Type "application/manifest+json"
16
  </FilesMatch>
 
1
  DirectoryIndex index.html
2
+
3
  <IfModule mod_rewrite.c>
4
  RewriteEngine On
5
  RewriteBase /
 
8
  RewriteCond %{REQUEST_FILENAME} !-d
9
  RewriteRule . /index.html [L]
10
  </IfModule>
11
+
12
  <IfModule mod_headers.c>
13
+ # Security Headers against Tampering & Embedding
14
+ Header always set X-Frame-Options "DENY"
15
+ Header always set X-Content-Type-Options "nosniff"
16
+ Header always set X-XSS-Protection "1; mode=block"
17
+ Header always set Referrer-Policy "no-referrer"
18
+ Header always set Permissions-Policy "camera=(self), microphone=(self), geolocation=(self)"
19
+
20
+ # Disable Source Maps to prevent code inspection
21
+ <FilesMatch "\.map$">
22
+ Order allow,deny
23
+ Deny from all
24
+ </FilesMatch>
25
+
26
+ # Cache Control for Service Worker & Manifest
27
+ <FilesMatch "(r8x4m9q2v7z3c6n5t0y8p4w9h2k6w\.js|manifest\.json)$">
28
  Header set Cache-Control "no-cache, no-store, must-revalidate"
29
  </FilesMatch>
30
+
31
  <FilesMatch "manifest\.json$">
32
  Header set Content-Type "application/manifest+json"
33
  </FilesMatch>
fricuit_animated_receiver.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Animated Multi-Frame QR Stream Receiver & Assembler
3
  * File: fricuit_animated_receiver.js
4
- * Responsibility: Ingesting rapid stream packets, validating CRC32 chunk integrity, tracking frame reception progress, and reassembling multi-part transfers.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -45,74 +45,82 @@
45
  if (!frameText || typeof frameText !== 'string') return false;
46
  if (!frameText.startsWith("FSTREAM:")) return false;
47
 
48
- const parts = frameText.split(':');
49
- const isV2 = parts[1] === 'v2';
50
- const sessionId = isV2 ? parts[2] : parts[1];
51
- const seq = parseInt(isV2 ? parts[3] : parts[2], 10);
52
- const total = parseInt(isV2 ? parts[4] : parts[3], 10);
53
- const crc = isV2 ? parts[5] : null;
54
- const chunkData = isV2 ? parts.slice(6).join(':') : parts.slice(4).join(':');
 
55
 
56
- if (isNaN(seq) || isNaN(total) || !sessionId || !chunkData) return false;
57
 
58
- // Validate CRC32 checksum for v2 frames
59
- if (crc && AnimatedStreamer.computeCRC32(chunkData) !== crc) {
60
- return false;
61
- }
62
-
63
- // New session detected
64
- if (this.activeSessionId !== sessionId) {
65
- this.activeSessionId = sessionId;
66
- this.totalChunks = total;
67
- this.collectedChunks.clear();
68
- this.isCompleted = false;
69
- }
70
-
71
- this.lastReceivedTime = Date.now();
72
-
73
- if (!this.collectedChunks.has(seq)) {
74
- this.collectedChunks.set(seq, chunkData);
75
- const count = this.collectedChunks.size;
76
- const percent = Math.round((count / this.totalChunks) * 100);
77
 
78
- if (typeof this.onProgress === 'function') {
79
- this.onProgress({
80
- received: count,
81
- total: this.totalChunks,
82
- percent: percent,
83
- sessionId: this.activeSessionId,
84
- missingCount: this.totalChunks - count
85
- });
86
  }
87
 
88
- if (count === this.totalChunks && !this.isCompleted) {
89
- this.isCompleted = true;
90
- this.assembleAndFinish();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  }
92
- }
93
 
94
- return true;
 
 
 
95
  }
96
 
97
  /**
98
  * Reassembles collected chunks and decompresses payload.
99
  */
100
  async assembleAndFinish() {
101
- let combinedPacked = "";
102
- for (let i = 0; i < this.totalChunks; i++) {
103
- combinedPacked += (this.collectedChunks.get(i) || "");
104
- }
 
105
 
106
- const fullDecodedString = await Compression.decompressTextPayload(combinedPacked);
107
 
108
- if (typeof this.onComplete === 'function') {
109
- this.onComplete(fullDecodedString, {
110
- sessionId: this.activeSessionId,
111
- totalChunks: this.totalChunks
112
- });
113
- }
114
 
115
- this.reset();
 
 
 
116
  }
117
 
118
  /**
@@ -135,13 +143,20 @@
135
  decompressTextPayload: Compression.decompressTextPayload
136
  };
137
 
138
- if (typeof globalThis !== 'undefined') {
139
- globalThis.FricuitAnimatedReceiver = FricuitQRReceiver;
140
- globalThis.FricuitAnimatedStream = FricuitAnimatedStream;
141
- } else if (typeof window !== 'undefined') {
142
- window.FricuitAnimatedReceiver = FricuitQRReceiver;
143
- window.FricuitAnimatedStream = FricuitAnimatedStream;
144
- } else {
 
 
 
 
 
 
 
145
  global.FricuitAnimatedReceiver = FricuitQRReceiver;
146
  global.FricuitAnimatedStream = FricuitAnimatedStream;
147
  }
 
1
  /**
2
  * Fricuit Ecosystem - Animated Multi-Frame QR Stream Receiver & Assembler
3
  * File: fricuit_animated_receiver.js
4
+ * Responsibility: Ingesting rapid stream packets, validating CRC32 chunk integrity, tracking frame reception progress, and reassembling multi-part transfers with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
45
  if (!frameText || typeof frameText !== 'string') return false;
46
  if (!frameText.startsWith("FSTREAM:")) return false;
47
 
48
+ try {
49
+ const parts = frameText.split(':');
50
+ const isV2 = parts[1] === 'v2';
51
+ const sessionId = isV2 ? parts[2] : parts[1];
52
+ const seq = parseInt(isV2 ? parts[3] : parts[2], 10);
53
+ const total = parseInt(isV2 ? parts[4] : parts[3], 10);
54
+ const crc = isV2 ? parts[5] : null;
55
+ const chunkData = isV2 ? parts.slice(6).join(':') : parts.slice(4).join(':');
56
 
57
+ if (isNaN(seq) || isNaN(total) || !sessionId || !chunkData) return false;
58
 
59
+ // Validate CRC32 checksum for v2 frames
60
+ if (crc && AnimatedStreamer.computeCRC32(chunkData) !== crc) {
61
+ return false;
62
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
64
+ // New session detected
65
+ if (this.activeSessionId !== sessionId) {
66
+ this.activeSessionId = sessionId;
67
+ this.totalChunks = total;
68
+ this.collectedChunks.clear();
69
+ this.isCompleted = false;
 
 
70
  }
71
 
72
+ this.lastReceivedTime = Date.now();
73
+
74
+ if (!this.collectedChunks.has(seq)) {
75
+ this.collectedChunks.set(seq, chunkData);
76
+ const count = this.collectedChunks.size;
77
+ const percent = Math.round((count / this.totalChunks) * 100);
78
+
79
+ if (typeof this.onProgress === 'function') {
80
+ this.onProgress({
81
+ received: count,
82
+ total: this.totalChunks,
83
+ percent: percent,
84
+ sessionId: this.activeSessionId,
85
+ missingCount: this.totalChunks - count
86
+ });
87
+ }
88
+
89
+ if (count === this.totalChunks && !this.isCompleted) {
90
+ this.isCompleted = true;
91
+ this.assembleAndFinish();
92
+ }
93
  }
 
94
 
95
+ return true;
96
+ } catch (e) {
97
+ return false;
98
+ }
99
  }
100
 
101
  /**
102
  * Reassembles collected chunks and decompresses payload.
103
  */
104
  async assembleAndFinish() {
105
+ try {
106
+ let combinedPacked = "";
107
+ for (let i = 0; i < this.totalChunks; i++) {
108
+ combinedPacked += (this.collectedChunks.get(i) || "");
109
+ }
110
 
111
+ const fullDecodedString = await Compression.decompressTextPayload(combinedPacked);
112
 
113
+ if (typeof this.onComplete === 'function') {
114
+ this.onComplete(fullDecodedString, {
115
+ sessionId: this.activeSessionId,
116
+ totalChunks: this.totalChunks
117
+ });
118
+ }
119
 
120
+ this.reset();
121
+ } catch (err) {
122
+ this.reset();
123
+ }
124
  }
125
 
126
  /**
 
143
  decompressTextPayload: Compression.decompressTextPayload
144
  };
145
 
146
+ Object.freeze(FricuitAnimatedStream);
147
+
148
+ try {
149
+ Object.defineProperty(global, 'FricuitAnimatedReceiver', {
150
+ value: FricuitQRReceiver,
151
+ writable: false,
152
+ configurable: false
153
+ });
154
+ Object.defineProperty(global, 'FricuitAnimatedStream', {
155
+ value: FricuitAnimatedStream,
156
+ writable: false,
157
+ configurable: false
158
+ });
159
+ } catch (e) {
160
  global.FricuitAnimatedReceiver = FricuitQRReceiver;
161
  global.FricuitAnimatedStream = FricuitAnimatedStream;
162
  }
fricuit_animated_streamer.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Animated Multi-Frame QR Stream Generator (FSTREAM:v2)
3
  * File: fricuit_animated_streamer.js
4
- * Responsibility: Chunking large payloads (>1200 chars), Deflate compression, CRC32 packet integrity hashing, and rapid FPS video-rate QR stream broadcasting.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -24,6 +24,8 @@
24
  return table;
25
  })();
26
 
 
 
27
  /**
28
  * Computes CRC32 checksum for payload chunk validation.
29
  * @param {string} str
@@ -62,29 +64,38 @@
62
  */
63
  async prepareStream(payloadString) {
64
  this.stopStream();
65
- const compressed = await Compression.compressTextPayload(payloadString);
66
- this.activeSessionId = "FS" + Math.random().toString(36).substring(2, 8).toUpperCase();
67
- this.chunks = [];
68
-
69
- const totalLen = compressed.length;
70
- const numChunks = Math.ceil(totalLen / this.chunkSize);
71
-
72
- for (let i = 0; i < numChunks; i++) {
73
- const start = i * this.chunkSize;
74
- const end = Math.min(start + this.chunkSize, totalLen);
75
- const chunkData = compressed.substring(start, end);
76
- const crc = computeCRC32(chunkData);
77
- const packet = `${STREAM_HEADER_PREFIX}:${this.activeSessionId}:${i}:${numChunks}:${crc}:${chunkData}`;
78
- this.chunks.push(packet);
79
- }
 
80
 
81
- this.currentIndex = 0;
82
- return {
83
- sessionId: this.activeSessionId,
84
- totalChunks: this.chunks.length,
85
- originalSize: payloadString.length,
86
- compressedSize: compressed.length
87
- };
 
 
 
 
 
 
 
 
88
  }
89
 
90
  /**
@@ -139,17 +150,21 @@
139
  }
140
  }
141
 
142
- // Export module to global scope
143
  const AnimatedStreamer = {
144
  computeCRC32,
145
  Streamer: FricuitQRStreamer
146
  };
147
 
148
- if (typeof globalThis !== 'undefined') {
149
- globalThis.FricuitAnimatedStreamer = AnimatedStreamer;
150
- } else if (typeof window !== 'undefined') {
151
- window.FricuitAnimatedStreamer = AnimatedStreamer;
152
- } else {
 
 
 
 
153
  global.FricuitAnimatedStreamer = AnimatedStreamer;
154
  }
155
 
 
1
  /**
2
  * Fricuit Ecosystem - Animated Multi-Frame QR Stream Generator (FSTREAM:v2)
3
  * File: fricuit_animated_streamer.js
4
+ * Responsibility: Chunking large payloads (>1200 chars), Deflate compression, CRC32 packet integrity hashing, and rapid FPS video-rate QR stream broadcasting with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
24
  return table;
25
  })();
26
 
27
+ Object.freeze(CRC32_TABLE);
28
+
29
  /**
30
  * Computes CRC32 checksum for payload chunk validation.
31
  * @param {string} str
 
64
  */
65
  async prepareStream(payloadString) {
66
  this.stopStream();
67
+ try {
68
+ const compressed = await Compression.compressTextPayload(payloadString);
69
+ this.activeSessionId = "FS" + Math.random().toString(36).substring(2, 8).toUpperCase();
70
+ this.chunks = [];
71
+
72
+ const totalLen = compressed.length;
73
+ const numChunks = Math.ceil(totalLen / this.chunkSize);
74
+
75
+ for (let i = 0; i < numChunks; i++) {
76
+ const start = i * this.chunkSize;
77
+ const end = Math.min(start + this.chunkSize, totalLen);
78
+ const chunkData = compressed.substring(start, end);
79
+ const crc = computeCRC32(chunkData);
80
+ const packet = `${STREAM_HEADER_PREFIX}:${this.activeSessionId}:${i}:${numChunks}:${crc}:${chunkData}`;
81
+ this.chunks.push(packet);
82
+ }
83
 
84
+ this.currentIndex = 0;
85
+ return {
86
+ sessionId: this.activeSessionId,
87
+ totalChunks: this.chunks.length,
88
+ originalSize: payloadString.length,
89
+ compressedSize: compressed.length
90
+ };
91
+ } catch (e) {
92
+ return {
93
+ sessionId: "FS_ERR",
94
+ totalChunks: 0,
95
+ originalSize: payloadString.length,
96
+ compressedSize: 0
97
+ };
98
+ }
99
  }
100
 
101
  /**
 
150
  }
151
  }
152
 
153
+ // Export module to global scope with immutable descriptor
154
  const AnimatedStreamer = {
155
  computeCRC32,
156
  Streamer: FricuitQRStreamer
157
  };
158
 
159
+ Object.freeze(AnimatedStreamer);
160
+
161
+ try {
162
+ Object.defineProperty(global, 'FricuitAnimatedStreamer', {
163
+ value: AnimatedStreamer,
164
+ writable: false,
165
+ configurable: false
166
+ });
167
+ } catch (e) {
168
  global.FricuitAnimatedStreamer = AnimatedStreamer;
169
  }
170
 
fricuit_audio_transmitter.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Acoustic Voucher & Chirp Audio Transmitter
3
  * File: fricuit_audio_transmitter.js
4
- * Responsibility: Frequency-Shift Keying (FSK) modulation, audio buffer synthesis, embedding token metadata into WAV container, and speaker broadcasting.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -27,8 +27,12 @@
27
  }
28
  };
29
 
 
 
 
 
30
  const WavEncoder = global.FricuitAudioWavEncoder || {
31
- createWavBlobFromAudioSamples: (samples, rate, payload) => new Blob([], { type: 'audio/wav' }),
32
  triggerWavDownload: () => false
33
  };
34
 
@@ -69,7 +73,6 @@
69
  const cleanStr = (payloadString || '').trim();
70
  const symbols = [];
71
 
72
- // Add Preamble
73
  this.cfg.PREAMBLE.forEach(f => symbols.push(f));
74
 
75
  let checksum = 0;
@@ -82,7 +85,6 @@
82
  symbols.push(this.cfg.BASE_FREQ + (lowNibble * this.cfg.STEP_FREQ));
83
  }
84
 
85
- // Append checksum symbol and postamble
86
  symbols.push(this.cfg.BASE_FREQ + (checksum * this.cfg.STEP_FREQ));
87
  this.cfg.POSTAMBLE.forEach(f => symbols.push(f));
88
 
@@ -168,18 +170,22 @@
168
  }
169
  }
170
 
171
- // Export module to global scope
172
  const AudioTransmitter = {
173
  CHIRP_CONFIG,
174
  Transmitter: FricuitAudioTransmitter,
175
  getOrCreateAudioContext
176
  };
177
 
178
- if (typeof globalThis !== 'undefined') {
179
- globalThis.FricuitAudioTransmitter = AudioTransmitter;
180
- } else if (typeof window !== 'undefined') {
181
- window.FricuitAudioTransmitter = AudioTransmitter;
182
- } else {
 
 
 
 
183
  global.FricuitAudioTransmitter = AudioTransmitter;
184
  }
185
 
 
1
  /**
2
  * Fricuit Ecosystem - Acoustic Voucher & Chirp Audio Transmitter
3
  * File: fricuit_audio_transmitter.js
4
+ * Responsibility: Frequency-Shift Keying (FSK) modulation, audio buffer synthesis, embedding token metadata into WAV container, and speaker broadcasting with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
27
  }
28
  };
29
 
30
+ Object.freeze(CHIRP_CONFIG.AUDIBLE);
31
+ Object.freeze(CHIRP_CONFIG.ULTRASONIC);
32
+ Object.freeze(CHIRP_CONFIG);
33
+
34
  const WavEncoder = global.FricuitAudioWavEncoder || {
35
+ createWavBlobFromAudioSamples: () => new Blob([], { type: 'audio/wav' }),
36
  triggerWavDownload: () => false
37
  };
38
 
 
73
  const cleanStr = (payloadString || '').trim();
74
  const symbols = [];
75
 
 
76
  this.cfg.PREAMBLE.forEach(f => symbols.push(f));
77
 
78
  let checksum = 0;
 
85
  symbols.push(this.cfg.BASE_FREQ + (lowNibble * this.cfg.STEP_FREQ));
86
  }
87
 
 
88
  symbols.push(this.cfg.BASE_FREQ + (checksum * this.cfg.STEP_FREQ));
89
  this.cfg.POSTAMBLE.forEach(f => symbols.push(f));
90
 
 
170
  }
171
  }
172
 
173
+ // Export module to global scope with immutable descriptor
174
  const AudioTransmitter = {
175
  CHIRP_CONFIG,
176
  Transmitter: FricuitAudioTransmitter,
177
  getOrCreateAudioContext
178
  };
179
 
180
+ Object.freeze(AudioTransmitter);
181
+
182
+ try {
183
+ Object.defineProperty(global, 'FricuitAudioTransmitter', {
184
+ value: AudioTransmitter,
185
+ writable: false,
186
+ configurable: false
187
+ });
188
+ } catch (e) {
189
  global.FricuitAudioTransmitter = AudioTransmitter;
190
  }
191
 
fricuit_budget_planner.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Monthly Budget Planner & Spending Limits Guard
3
  * File: fricuit_budget_planner.js
4
- * Responsibility: Dynamic DOM injection of Budget Planner pane, defining currency-specific monthly spending caps, auditing real-time expense ratios, rendering progress bars, and generating threshold warning alerts.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -151,14 +151,13 @@
151
  renderBudgetsList();
152
  }
153
 
154
- // Auto-inject budget planner DOM on startup
155
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
156
  ensureBudgetPlannerPaneDOM();
157
  } else {
158
  document.addEventListener('DOMContentLoaded', ensureBudgetPlannerPaneDOM);
159
  }
160
 
161
- // Export module to global scope
162
  const BudgetPlanner = {
163
  renderBudgetsList,
164
  saveBudgetLimit,
@@ -166,11 +165,15 @@
166
  ensureBudgetPlannerPaneDOM
167
  };
168
 
169
- if (typeof globalThis !== 'undefined') {
170
- globalThis.FricuitBudgetPlanner = BudgetPlanner;
171
- } else if (typeof window !== 'undefined') {
172
- window.FricuitBudgetPlanner = BudgetPlanner;
173
- } else {
 
 
 
 
174
  global.FricuitBudgetPlanner = BudgetPlanner;
175
  }
176
 
 
1
  /**
2
  * Fricuit Ecosystem - Monthly Budget Planner & Spending Limits Guard
3
  * File: fricuit_budget_planner.js
4
+ * Responsibility: Dynamic DOM injection of Budget Planner pane, defining currency-specific monthly spending caps, auditing real-time expense ratios, rendering progress bars, and generating threshold warning alerts with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
151
  renderBudgetsList();
152
  }
153
 
 
154
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
155
  ensureBudgetPlannerPaneDOM();
156
  } else {
157
  document.addEventListener('DOMContentLoaded', ensureBudgetPlannerPaneDOM);
158
  }
159
 
160
+ // Export module to global scope with immutable descriptor
161
  const BudgetPlanner = {
162
  renderBudgetsList,
163
  saveBudgetLimit,
 
165
  ensureBudgetPlannerPaneDOM
166
  };
167
 
168
+ Object.freeze(BudgetPlanner);
169
+
170
+ try {
171
+ Object.defineProperty(global, 'FricuitBudgetPlanner', {
172
+ value: BudgetPlanner,
173
+ writable: false,
174
+ configurable: false
175
+ });
176
+ } catch (e) {
177
  global.FricuitBudgetPlanner = BudgetPlanner;
178
  }
179
 
fricuit_camera_scanner_pipeline.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - WebRTC Camera Scanner & Viewfinder Pipeline
3
  * File: fricuit_camera_scanner_pipeline.js
4
- * Responsibility: Camera constraints negotiation, torch/flashlight control, front/back lens switching, OffscreenCanvas/Worker frame transfer, and live QR detection loop.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -46,7 +46,6 @@
46
  */
47
  initWorker() {
48
  try {
49
- // Workers are blocked on file:/// protocol by browser security policies
50
  const isSupportedProtocol = typeof location !== 'undefined' &&
51
  (location.protocol.startsWith('http') || location.protocol.includes('extension'));
52
 
@@ -126,7 +125,7 @@
126
  }
127
 
128
  if (!activeStream) {
129
- throw (lastError || new Error("Unable to access device camera. Please ensure camera permissions are granted."));
130
  }
131
 
132
  this.stream = activeStream;
@@ -313,12 +312,16 @@
313
  }
314
  }
315
 
316
- // Export module to global scope
317
- if (typeof globalThis !== 'undefined') {
318
- globalThis.FricuitCameraPipeline = FricuitCameraPipeline;
319
- } else if (typeof window !== 'undefined') {
320
- window.FricuitCameraPipeline = FricuitCameraPipeline;
321
- } else {
 
 
 
 
322
  global.FricuitCameraPipeline = FricuitCameraPipeline;
323
  }
324
 
 
1
  /**
2
  * Fricuit Ecosystem - WebRTC Camera Scanner & Viewfinder Pipeline
3
  * File: fricuit_camera_scanner_pipeline.js
4
+ * Responsibility: Camera constraints negotiation, torch/flashlight control, front/back lens switching, OffscreenCanvas/Worker frame transfer, and live QR detection loop with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
46
  */
47
  initWorker() {
48
  try {
 
49
  const isSupportedProtocol = typeof location !== 'undefined' &&
50
  (location.protocol.startsWith('http') || location.protocol.includes('extension'));
51
 
 
125
  }
126
 
127
  if (!activeStream) {
128
+ throw (lastError || new Error("Camera stream access unavailable"));
129
  }
130
 
131
  this.stream = activeStream;
 
312
  }
313
  }
314
 
315
+ Object.freeze(FricuitCameraPipeline.prototype);
316
+ Object.freeze(FricuitCameraPipeline);
317
+
318
+ try {
319
+ Object.defineProperty(global, 'FricuitCameraPipeline', {
320
+ value: FricuitCameraPipeline,
321
+ writable: false,
322
+ configurable: false
323
+ });
324
+ } catch (e) {
325
  global.FricuitCameraPipeline = FricuitCameraPipeline;
326
  }
327
 
fricuit_contacts_address_book.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Address Book & Verified Contacts Manager
3
  * File: fricuit_contacts_address_book.js
4
- * Responsibility: Dynamic DOM injection of Address Book pane and Contact modals, saving 128-character account IDs with human-readable aliases, contact search, editing, modal pickers, and bulk multi-selection deletion.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -495,14 +495,13 @@
495
  });
496
  }
497
 
498
- // Auto-inject address book DOM on startup
499
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
500
  ensureAddressBookDOM();
501
  } else {
502
  document.addEventListener('DOMContentLoaded', ensureAddressBookDOM);
503
  }
504
 
505
- // Export module to global scope
506
  const ContactsManager = {
507
  renderAddressBookList,
508
  saveNewContact,
@@ -518,11 +517,15 @@
518
  ensureAddressBookDOM
519
  };
520
 
521
- if (typeof globalThis !== 'undefined') {
522
- globalThis.FricuitContactsManager = ContactsManager;
523
- } else if (typeof window !== 'undefined') {
524
- window.FricuitContactsManager = ContactsManager;
525
- } else {
 
 
 
 
526
  global.FricuitContactsManager = ContactsManager;
527
  }
528
 
 
1
  /**
2
  * Fricuit Ecosystem - Address Book & Verified Contacts Manager
3
  * File: fricuit_contacts_address_book.js
4
+ * Responsibility: Dynamic DOM injection of Address Book pane and Contact modals, saving 128-character account IDs with human-readable aliases, contact search, editing, modal pickers, and bulk multi-selection deletion with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
495
  });
496
  }
497
 
 
498
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
499
  ensureAddressBookDOM();
500
  } else {
501
  document.addEventListener('DOMContentLoaded', ensureAddressBookDOM);
502
  }
503
 
504
+ // Export module to global scope with immutable descriptor
505
  const ContactsManager = {
506
  renderAddressBookList,
507
  saveNewContact,
 
517
  ensureAddressBookDOM
518
  };
519
 
520
+ Object.freeze(ContactsManager);
521
+
522
+ try {
523
+ Object.defineProperty(global, 'FricuitContactsManager', {
524
+ value: ContactsManager,
525
+ writable: false,
526
+ configurable: false
527
+ });
528
+ } catch (e) {
529
  global.FricuitContactsManager = ContactsManager;
530
  }
531
 
fricuit_country_database.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Standalone Global Country & Nationality Registry
3
  * File: fricuit_country_database.js
4
- * Responsibility: Complete, normalized registry of all 249 recognized countries and sovereign territories (ISO 3166-1 alpha-2, dial codes, flags, continents) with zero external dependencies.
5
  * Pure Offline - 100% Client-Side.
6
  */
7
 
@@ -257,15 +257,16 @@
257
  { name: "Zimbabwe", code: "ZW", dialCode: "+263", flag: "🇿🇼", continent: "Africa" }
258
  ];
259
 
260
- // Alphabetical Sorting by Country Name
261
  COUNTRY_DATABASE.sort((a, b) => a.name.localeCompare(b.name, 'en'));
262
 
263
- // Fast Indexed Map by ISO 3166-1 alpha-2 Code
264
  const COUNTRY_MAP_BY_CODE = {};
265
  COUNTRY_DATABASE.forEach(item => {
266
  COUNTRY_MAP_BY_CODE[item.code.toUpperCase()] = item;
267
  });
268
 
 
 
 
269
  /**
270
  * Retrieves full metadata for a given country code.
271
  * @param {string} isoCode - 2-character ISO code (e.g., "EG", "US")
@@ -299,7 +300,7 @@
299
  });
300
  }
301
 
302
- // Export module to global scope
303
  const CountryRegistry = {
304
  COUNTRIES: COUNTRY_DATABASE,
305
  COUNTRY_MAP: COUNTRY_MAP_BY_CODE,
@@ -308,11 +309,15 @@
308
  DEFAULT_COUNTRY: COUNTRY_MAP_BY_CODE["EG"]
309
  };
310
 
311
- if (typeof globalThis !== 'undefined') {
312
- globalThis.FricuitCountryDatabase = CountryRegistry;
313
- } else if (typeof window !== 'undefined') {
314
- window.FricuitCountryDatabase = CountryRegistry;
315
- } else {
 
 
 
 
316
  global.FricuitCountryDatabase = CountryRegistry;
317
  }
318
 
 
1
  /**
2
  * Fricuit Ecosystem - Standalone Global Country & Nationality Registry
3
  * File: fricuit_country_database.js
4
+ * Responsibility: Complete, normalized registry of all 249 recognized countries and sovereign territories (ISO 3166-1 alpha-2, dial codes, flags, continents) with zero console logging.
5
  * Pure Offline - 100% Client-Side.
6
  */
7
 
 
257
  { name: "Zimbabwe", code: "ZW", dialCode: "+263", flag: "🇿🇼", continent: "Africa" }
258
  ];
259
 
 
260
  COUNTRY_DATABASE.sort((a, b) => a.name.localeCompare(b.name, 'en'));
261
 
 
262
  const COUNTRY_MAP_BY_CODE = {};
263
  COUNTRY_DATABASE.forEach(item => {
264
  COUNTRY_MAP_BY_CODE[item.code.toUpperCase()] = item;
265
  });
266
 
267
+ Object.freeze(COUNTRY_DATABASE);
268
+ Object.freeze(COUNTRY_MAP_BY_CODE);
269
+
270
  /**
271
  * Retrieves full metadata for a given country code.
272
  * @param {string} isoCode - 2-character ISO code (e.g., "EG", "US")
 
300
  });
301
  }
302
 
303
+ // Export module to global scope with immutable descriptor
304
  const CountryRegistry = {
305
  COUNTRIES: COUNTRY_DATABASE,
306
  COUNTRY_MAP: COUNTRY_MAP_BY_CODE,
 
309
  DEFAULT_COUNTRY: COUNTRY_MAP_BY_CODE["EG"]
310
  };
311
 
312
+ Object.freeze(CountryRegistry);
313
+
314
+ try {
315
+ Object.defineProperty(global, 'FricuitCountryDatabase', {
316
+ value: CountryRegistry,
317
+ writable: false,
318
+ configurable: false
319
+ });
320
+ } catch (e) {
321
  global.FricuitCountryDatabase = CountryRegistry;
322
  }
323
 
fricuit_currency_database.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Global 140+ Currencies Database & Matrix
3
  * File: fricuit_currency_database.js
4
- * Responsibility: Complete registry of all official world currencies, regional currency unions, symbols, classifications, and metadata.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -155,7 +155,6 @@
155
  { code: "FCC", name: "Fricuit Decentralized Currency", continent: "Global (Decentralized)", region: "Fricuit Economic Ecosystem", country: "Fricuit Digital Network", symbol: "FCC", isInternational: true, isShared: true, sharedZoneName: "Fricuit Global Decentralized Network" }
156
  ];
157
 
158
- // Alphabetical sort by English name
159
  CURRENCY_DATABASE.sort((a, b) => a.name.localeCompare(b.name, 'en'));
160
 
161
  const CURRENCY_MAP = {};
@@ -163,6 +162,9 @@
163
  CURRENCY_MAP[c.code] = c;
164
  });
165
 
 
 
 
166
  /**
167
  * Retrieves metadata for a specific currency code.
168
  * @param {string} code
@@ -182,18 +184,22 @@
182
  };
183
  }
184
 
185
- // Export module to global scope
186
  const CurrencyDatabase = {
187
  CURRENCIES: CURRENCY_DATABASE,
188
  CURRENCY_MAP: CURRENCY_MAP,
189
  getCurrencyMeta
190
  };
191
 
192
- if (typeof globalThis !== 'undefined') {
193
- globalThis.FricuitCurrencyDatabase = CurrencyDatabase;
194
- } else if (typeof window !== 'undefined') {
195
- window.FricuitCurrencyDatabase = CurrencyDatabase;
196
- } else {
 
 
 
 
197
  global.FricuitCurrencyDatabase = CurrencyDatabase;
198
  }
199
 
 
1
  /**
2
  * Fricuit Ecosystem - Global 140+ Currencies Database & Matrix
3
  * File: fricuit_currency_database.js
4
+ * Responsibility: Complete registry of all official world currencies, regional currency unions, symbols, classifications, and metadata with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
155
  { code: "FCC", name: "Fricuit Decentralized Currency", continent: "Global (Decentralized)", region: "Fricuit Economic Ecosystem", country: "Fricuit Digital Network", symbol: "FCC", isInternational: true, isShared: true, sharedZoneName: "Fricuit Global Decentralized Network" }
156
  ];
157
 
 
158
  CURRENCY_DATABASE.sort((a, b) => a.name.localeCompare(b.name, 'en'));
159
 
160
  const CURRENCY_MAP = {};
 
162
  CURRENCY_MAP[c.code] = c;
163
  });
164
 
165
+ Object.freeze(CURRENCY_DATABASE);
166
+ Object.freeze(CURRENCY_MAP);
167
+
168
  /**
169
  * Retrieves metadata for a specific currency code.
170
  * @param {string} code
 
184
  };
185
  }
186
 
187
+ // Export module to global scope with immutable descriptor
188
  const CurrencyDatabase = {
189
  CURRENCIES: CURRENCY_DATABASE,
190
  CURRENCY_MAP: CURRENCY_MAP,
191
  getCurrencyMeta
192
  };
193
 
194
+ Object.freeze(CurrencyDatabase);
195
+
196
+ try {
197
+ Object.defineProperty(global, 'FricuitCurrencyDatabase', {
198
+ value: CurrencyDatabase,
199
+ writable: false,
200
+ configurable: false
201
+ });
202
+ } catch (e) {
203
  global.FricuitCurrencyDatabase = CurrencyDatabase;
204
  }
205
 
fricuit_currency_gold_market.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Implied Gold Index & FX Market Quotes Engine
3
  * File: fricuit_currency_gold_market.js
4
- * Responsibility: Computing implied international gold ounce, 24K and 21K gram pricing per currency, bid/ask spread margins, and liquidity quotes.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -88,7 +88,7 @@
88
  return MarketState.goldOunceUSD * rate;
89
  }
90
 
91
- // Export module to global scope
92
  const GoldMarket = {
93
  MarketState,
94
  calculateMarketQuotes,
@@ -96,11 +96,15 @@
96
  getGoldOuncePrice
97
  };
98
 
99
- if (typeof globalThis !== 'undefined') {
100
- globalThis.FricuitCurrencyGoldMarket = GoldMarket;
101
- } else if (typeof window !== 'undefined') {
102
- window.FricuitCurrencyGoldMarket = GoldMarket;
103
- } else {
 
 
 
 
104
  global.FricuitCurrencyGoldMarket = GoldMarket;
105
  }
106
 
 
1
  /**
2
  * Fricuit Ecosystem - Implied Gold Index & FX Market Quotes Engine
3
  * File: fricuit_currency_gold_market.js
4
+ * Responsibility: Computing implied international gold ounce, 24K and 21K gram pricing per currency, bid/ask spread margins, and liquidity quotes with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
88
  return MarketState.goldOunceUSD * rate;
89
  }
90
 
91
+ // Export module to global scope with immutable descriptor
92
  const GoldMarket = {
93
  MarketState,
94
  calculateMarketQuotes,
 
96
  getGoldOuncePrice
97
  };
98
 
99
+ Object.freeze(GoldMarket);
100
+
101
+ try {
102
+ Object.defineProperty(global, 'FricuitCurrencyGoldMarket', {
103
+ value: GoldMarket,
104
+ writable: false,
105
+ configurable: false
106
+ });
107
+ } catch (e) {
108
  global.FricuitCurrencyGoldMarket = GoldMarket;
109
  }
110
 
fricuit_currency_rates_fetcher.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Currency Rates Fetcher & Offline Matrix Engine
3
  * File: fricuit_currency_rates_fetcher.js
4
- * Responsibility: Multi-endpoint real-time currency exchange rates fetcher, rate validation, and offline emergency static matrix synchronization.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -20,6 +20,8 @@
20
  });
21
  }
22
 
 
 
23
  const RatesState = {
24
  liveRates: { ...ZERO_RATES_MATRIX },
25
  isRatesLoaded: false,
@@ -128,7 +130,7 @@
128
  return RatesState.liveRates || ZERO_RATES_MATRIX;
129
  }
130
 
131
- // Export module to global scope
132
  const CurrencyRatesFetcher = {
133
  RatesState,
134
  ZERO_RATES_MATRIX,
@@ -137,11 +139,15 @@
137
  getRates
138
  };
139
 
140
- if (typeof globalThis !== 'undefined') {
141
- globalThis.FricuitCurrencyRatesFetcher = CurrencyRatesFetcher;
142
- } else if (typeof window !== 'undefined') {
143
- window.FricuitCurrencyRatesFetcher = CurrencyRatesFetcher;
144
- } else {
 
 
 
 
145
  global.FricuitCurrencyRatesFetcher = CurrencyRatesFetcher;
146
  }
147
 
 
1
  /**
2
  * Fricuit Ecosystem - Currency Rates Fetcher & Offline Matrix Engine
3
  * File: fricuit_currency_rates_fetcher.js
4
+ * Responsibility: Multi-endpoint real-time currency exchange rates fetcher, rate validation, and offline emergency static matrix synchronization with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
20
  });
21
  }
22
 
23
+ Object.freeze(ZERO_RATES_MATRIX);
24
+
25
  const RatesState = {
26
  liveRates: { ...ZERO_RATES_MATRIX },
27
  isRatesLoaded: false,
 
130
  return RatesState.liveRates || ZERO_RATES_MATRIX;
131
  }
132
 
133
+ // Export module to global scope with immutable descriptor
134
  const CurrencyRatesFetcher = {
135
  RatesState,
136
  ZERO_RATES_MATRIX,
 
139
  getRates
140
  };
141
 
142
+ Object.freeze(CurrencyRatesFetcher);
143
+
144
+ try {
145
+ Object.defineProperty(global, 'FricuitCurrencyRatesFetcher', {
146
+ value: CurrencyRatesFetcher,
147
+ writable: false,
148
+ configurable: false
149
+ });
150
+ } catch (e) {
151
  global.FricuitCurrencyRatesFetcher = CurrencyRatesFetcher;
152
  }
153
 
fricuit_device_telemetry.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Deep Hardware, Device, High-Entropy OS & Context Telemetry Engine
3
  * File: fricuit_device_telemetry.js
4
- * Responsibility: Accurate high-entropy identification of operating systems (exact Windows 11 builds vs Windows 10, macOS versions, exact iOS/iPadOS releases, Android OS, Linux, ChromeOS), device form factors, browser engines, runtime sandbox modes, and silent background persistence of hardware diagnostics into the encrypted database.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -27,7 +27,6 @@
27
  let osVersion = '';
28
 
29
  if (/Win(dows )?NT 10\.0/i.test(ua)) {
30
- // Heuristic baseline; will be refined by High-Entropy Client Hints if available
31
  osName = 'Windows 10 / 11';
32
  osCode = 'windows';
33
  osVersion = '10.0';
@@ -190,7 +189,6 @@
190
 
191
  /**
192
  * High-Entropy Client Hints Asynchronous OS Version Resolver.
193
- * Accurately distinguishes Windows 11 build releases from Windows 10, exact device models, and CPU architectures.
194
  * @returns {Promise<Object>}
195
  */
196
  async function detectEnvironmentAsync() {
@@ -216,8 +214,6 @@
216
  baseEnv.deviceModel = hints.model;
217
  }
218
 
219
- // Refine Windows 11 vs Windows 10
220
- // On Windows, Chromium returns platformVersion major >= 13 for Windows 11
221
  if (hints.platform === 'Windows' || baseEnv.osCode === 'windows') {
222
  if (hints.platformVersion) {
223
  const majorVersion = parseInt(hints.platformVersion.split('.')[0], 10);
@@ -234,9 +230,7 @@
234
  baseEnv.osVersion = hints.platformVersion || baseEnv.osVersion;
235
  }
236
  }
237
- } catch (hintsErr) {
238
- // High entropy query restricted or rejected; retain regex parsed baseline
239
- }
240
  }
241
 
242
  return baseEnv;
@@ -320,7 +314,6 @@
320
  timestamp: new Date().toISOString()
321
  };
322
 
323
- // Silently record telemetry snapshot into Fricuit local database
324
  try {
325
  if (global.FricuitStorage && typeof global.FricuitStorage.set === 'function') {
326
  await global.FricuitStorage.set('fricuit_device_telemetry_snapshot', report);
@@ -345,7 +338,7 @@
345
  document.addEventListener('DOMContentLoaded', autoCollectAndPersistTelemetry);
346
  }
347
 
348
- // Export module to global scope
349
  const DeviceTelemetry = {
350
  detectEnvironment: detectEnvironmentSync,
351
  detectEnvironmentAsync,
@@ -355,11 +348,15 @@
355
  autoCollectAndPersistTelemetry
356
  };
357
 
358
- if (typeof globalThis !== 'undefined') {
359
- globalThis.FricuitDeviceTelemetry = DeviceTelemetry;
360
- } else if (typeof window !== 'undefined') {
361
- window.FricuitDeviceTelemetry = DeviceTelemetry;
362
- } else {
 
 
 
 
363
  global.FricuitDeviceTelemetry = DeviceTelemetry;
364
  }
365
 
 
1
  /**
2
  * Fricuit Ecosystem - Deep Hardware, Device, High-Entropy OS & Context Telemetry Engine
3
  * File: fricuit_device_telemetry.js
4
+ * Responsibility: Accurate high-entropy identification of operating systems (exact Windows 11 builds vs Windows 10, macOS versions, exact iOS/iPadOS releases, Android OS, Linux, ChromeOS), device form factors, browser engines, runtime sandbox modes, and silent background persistence of hardware diagnostics with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
27
  let osVersion = '';
28
 
29
  if (/Win(dows )?NT 10\.0/i.test(ua)) {
 
30
  osName = 'Windows 10 / 11';
31
  osCode = 'windows';
32
  osVersion = '10.0';
 
189
 
190
  /**
191
  * High-Entropy Client Hints Asynchronous OS Version Resolver.
 
192
  * @returns {Promise<Object>}
193
  */
194
  async function detectEnvironmentAsync() {
 
214
  baseEnv.deviceModel = hints.model;
215
  }
216
 
 
 
217
  if (hints.platform === 'Windows' || baseEnv.osCode === 'windows') {
218
  if (hints.platformVersion) {
219
  const majorVersion = parseInt(hints.platformVersion.split('.')[0], 10);
 
230
  baseEnv.osVersion = hints.platformVersion || baseEnv.osVersion;
231
  }
232
  }
233
+ } catch (hintsErr) {}
 
 
234
  }
235
 
236
  return baseEnv;
 
314
  timestamp: new Date().toISOString()
315
  };
316
 
 
317
  try {
318
  if (global.FricuitStorage && typeof global.FricuitStorage.set === 'function') {
319
  await global.FricuitStorage.set('fricuit_device_telemetry_snapshot', report);
 
338
  document.addEventListener('DOMContentLoaded', autoCollectAndPersistTelemetry);
339
  }
340
 
341
+ // Export module to global scope with immutable descriptor
342
  const DeviceTelemetry = {
343
  detectEnvironment: detectEnvironmentSync,
344
  detectEnvironmentAsync,
 
348
  autoCollectAndPersistTelemetry
349
  };
350
 
351
+ Object.freeze(DeviceTelemetry);
352
+
353
+ try {
354
+ Object.defineProperty(global, 'FricuitDeviceTelemetry', {
355
+ value: DeviceTelemetry,
356
+ writable: false,
357
+ configurable: false
358
+ });
359
+ } catch (e) {
360
  global.FricuitDeviceTelemetry = DeviceTelemetry;
361
  }
362
 
fricuit_image_qr_extractor.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Multi-Scale Image QR Extraction Engine
3
  * File: fricuit_image_qr_extractor.js
4
- * Responsibility: Multi-pass image extraction, hardware BarcodeDetector acceleration, flexible jsQR global resolution, adaptive scale downsampling, aspect ratio crops, 90/180/270 rotations, and payload sanitization.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -28,7 +28,7 @@
28
  }
29
 
30
  /**
31
- * Cleans, sanitizes, and strips zero-width non-printing characters and quotes from extracted QR payload.
32
  * @param {string} rawText
33
  * @returns {string|null}
34
  */
@@ -36,11 +36,59 @@
36
  if (!rawText || typeof rawText !== 'string') return null;
37
  let str = rawText.trim().replace(/^[\uFEFF\x00-\x1F\x7F-\x9F]+|[\uFEFF\x00-\x1F\x7F-\x9F]+$/g, '');
38
  str = str.replace(/^["']|["']$/g, '').trim();
 
 
 
 
 
 
 
 
 
 
 
39
  return str.length > 0 ? str : null;
40
  }
41
 
42
  /**
43
- * Attempts decoding on raw ImageData using available decoders (BarcodeDetector + jsQR).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  * @param {ImageData} imgData
45
  * @param {number} width
46
  * @param {number} height
@@ -61,6 +109,25 @@
61
  return null;
62
  }
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  /**
65
  * Converts a File or Blob into an ImageBitmap or HTMLImageElement.
66
  * @param {Blob|File} fileBlob
@@ -69,7 +136,7 @@
69
  async function loadSourceImage(fileBlob) {
70
  if (typeof createImageBitmap === 'function') {
71
  try {
72
- const bitmap = await createImageBitmap(fileBlob);
73
  if (bitmap && bitmap.width > 0 && bitmap.height > 0) {
74
  return bitmap;
75
  }
@@ -108,27 +175,19 @@
108
  const natH = sourceImg.height || sourceImg.naturalHeight;
109
  if (!natW || !natH) return null;
110
 
111
- // 1. Hardware BarcodeDetector Pass (GPU Accelerated if available)
112
- if (typeof window !== 'undefined' && typeof window.BarcodeDetector !== 'undefined') {
113
- try {
114
- const detector = new window.BarcodeDetector({ formats: ['qr_code'] });
115
- const barcodes = await detector.detect(sourceImg);
116
- if (barcodes && barcodes.length > 0 && barcodes[0].rawValue) {
117
- const detectedText = cleanExtractedQRPayload(barcodes[0].rawValue);
118
- if (detectedText) return detectedText;
119
- }
120
- } catch (hwErr) {}
121
- }
122
 
123
  const canvas = document.createElement('canvas');
124
  const ctx = canvas.getContext('2d', { willReadFrequently: true });
125
  if (!ctx) return null;
126
 
127
- // Build target scale list (Original size first, then progressive standard downscales)
128
- const targetScales = [{ w: natW, h: natH }];
129
- const standardMaxDimensions = [1200, 900, 700, 500, 350, 1500];
130
 
131
- for (const maxDim of standardMaxDimensions) {
132
  if (natW > maxDim || natH > maxDim) {
133
  if (natW >= natH) {
134
  const w = maxDim;
@@ -141,23 +200,32 @@
141
  }
142
  }
143
  }
 
144
 
145
  for (const scale of targetScales) {
146
  const w = scale.w;
147
  const h = scale.h;
 
 
148
  canvas.width = w;
149
  canvas.height = h;
150
- ctx.clearRect(0, 0, w, h);
 
151
  ctx.drawImage(sourceImg, 0, 0, w, h);
152
 
 
 
 
 
153
  let rawImgData = null;
154
  try {
155
  rawImgData = ctx.getImageData(0, 0, w, h);
 
156
  } catch (ctxErr) {
157
  continue;
158
  }
159
 
160
- // Pass 1: Raw Image
161
  let result = tryDecodeImageData(rawImgData, w, h);
162
  if (result) return result;
163
 
@@ -169,7 +237,15 @@
169
  if (result) return result;
170
  } catch (e) {}
171
 
172
- // Pass 3: Otsu Global Binarization
 
 
 
 
 
 
 
 
173
  try {
174
  const otsuData = VisionFilters.applyOtsuThreshold(rawImgData.data, w, h);
175
  const otsuImgData = new ImageData(otsuData, w, h);
@@ -177,7 +253,7 @@
177
  if (result) return result;
178
  } catch (e) {}
179
 
180
- // Pass 4: Bradley-Roth Adaptive Thresholding
181
  try {
182
  const adaptiveData = VisionFilters.applyAdaptiveThreshold(rawImgData.data, w, h, 0.15);
183
  const adaptiveImgData = new ImageData(adaptiveData, w, h);
@@ -185,44 +261,90 @@
185
  if (result) return result;
186
  } catch (e) {}
187
 
188
- // Pass 5: Sharpening Filter
189
  try {
190
  const sharpData = VisionFilters.applySharpeningKernel(rawImgData.data, w, h);
191
  const sharpImgData = new ImageData(sharpData, w, h);
192
  result = tryDecodeImageData(sharpImgData, w, h);
193
  if (result) return result;
194
  } catch (e) {}
 
195
 
196
- // Pass 6: Center Crop (85%)
 
 
197
  try {
198
- const cropW = Math.floor(w * 0.85);
199
- const cropH = Math.floor(h * 0.85);
200
- const cropX = Math.floor((w - cropW) / 2);
201
- const cropY = Math.floor((h - cropH) / 2);
 
 
 
 
202
  const cropCanvas = document.createElement('canvas');
203
- cropCanvas.width = cropW;
204
- cropCanvas.height = cropH;
205
  const cropCtx = cropCanvas.getContext('2d', { willReadFrequently: true });
206
  if (cropCtx) {
207
- cropCtx.drawImage(sourceImg, cropX, cropY, cropW, cropH, 0, 0, cropW, cropH);
208
- const cropImgData = cropCtx.getImageData(0, 0, cropW, cropH);
209
- result = tryDecodeImageData(cropImgData, cropW, cropH);
210
- if (result) return result;
 
 
 
 
 
 
 
 
 
 
 
211
  }
212
  } catch (e) {}
213
  }
214
 
215
- // Pass 7: Rotations (90°, 180°, 270°)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  const rotations = [90, 180, 270];
217
  for (const angle of rotations) {
218
  try {
219
  const rotW = (angle === 90 || angle === 270) ? natH : natW;
220
  const rotH = (angle === 90 || angle === 270) ? natW : natH;
221
- const scaledW = Math.min(900, rotW);
222
  const scaledH = Math.round(scaledW * (rotH / rotW));
 
223
  canvas.width = scaledW;
224
  canvas.height = scaledH;
225
- ctx.clearRect(0, 0, scaledW, scaledH);
 
226
  ctx.save();
227
  ctx.translate(scaledW / 2, scaledH / 2);
228
  ctx.rotate((angle * Math.PI) / 180);
@@ -232,7 +354,12 @@
232
  ctx.drawImage(sourceImg, -scaledW / 2, -scaledH / 2, scaledW, scaledH);
233
  }
234
  ctx.restore();
 
 
 
 
235
  const rotData = ctx.getImageData(0, 0, scaledW, scaledH);
 
236
  const result = tryDecodeImageData(rotData, scaledW, scaledH);
237
  if (result) return result;
238
  } catch (e) {}
@@ -241,7 +368,7 @@
241
  return null;
242
  }
243
 
244
- // Export module to global scope
245
  const OmniTransfer = {
246
  cleanExtractedQRPayload,
247
  extractQRFromImageBlob,
@@ -249,13 +376,20 @@
249
  OmniVision: VisionFilters
250
  };
251
 
252
- if (typeof globalThis !== 'undefined') {
253
- globalThis.FricuitImageQRExtractor = OmniTransfer;
254
- globalThis.FricuitOmniTransfer = OmniTransfer;
255
- } else if (typeof window !== 'undefined') {
256
- window.FricuitImageQRExtractor = OmniTransfer;
257
- window.FricuitOmniTransfer = OmniTransfer;
258
- } else {
 
 
 
 
 
 
 
259
  global.FricuitImageQRExtractor = OmniTransfer;
260
  global.FricuitOmniTransfer = OmniTransfer;
261
  }
 
1
  /**
2
  * Fricuit Ecosystem - Multi-Scale Image QR Extraction Engine
3
  * File: fricuit_image_qr_extractor.js
4
+ * Responsibility: Multi-pass image extraction, hardware BarcodeDetector acceleration, white-fill alpha blending, optimal scale ladder, aspect ratio crops, quiet-zone padding, 90/180/270 rotations, and payload sanitization with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
28
  }
29
 
30
  /**
31
+ * Cleans, sanitizes, and strips zero-width non-printing characters, quotes, and URI wrappers from extracted QR payload.
32
  * @param {string} rawText
33
  * @returns {string|null}
34
  */
 
36
  if (!rawText || typeof rawText !== 'string') return null;
37
  let str = rawText.trim().replace(/^[\uFEFF\x00-\x1F\x7F-\x9F]+|[\uFEFF\x00-\x1F\x7F-\x9F]+$/g, '');
38
  str = str.replace(/^["']|["']$/g, '').trim();
39
+
40
+ // Extract nested pay_uri or token parameters if wrapped inside URL query parameters
41
+ if (str.includes('pay_uri=')) {
42
+ const match = str.match(/pay_uri=([^&]+)/);
43
+ if (match && match[1]) {
44
+ try {
45
+ str = decodeURIComponent(match[1]).trim();
46
+ } catch (e) {}
47
+ }
48
+ }
49
+
50
  return str.length > 0 ? str : null;
51
  }
52
 
53
  /**
54
+ * Normalizes RGBA buffer by blending alpha channel over pure white background.
55
+ * @param {Uint8ClampedArray} data
56
+ * @param {number} width
57
+ * @param {number} height
58
+ */
59
+ function blendAlphaOverWhite(data, width, height) {
60
+ const len = width * height * 4;
61
+ for (let i = 0; i < len; i += 4) {
62
+ const a = data[i + 3] / 255;
63
+ if (a < 1) {
64
+ data[i] = Math.round(data[i] * a + 255 * (1 - a));
65
+ data[i + 1] = Math.round(data[i + 1] * a + 255 * (1 - a));
66
+ data[i + 2] = Math.round(data[i + 2] * a + 255 * (1 - a));
67
+ data[i + 3] = 255;
68
+ }
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Inverts colors (for Dark Mode screenshots: white QR on dark background).
74
+ * @param {Uint8ClampedArray} data
75
+ * @param {number} width
76
+ * @param {number} height
77
+ * @returns {Uint8ClampedArray}
78
+ */
79
+ function invertColors(data, width, height) {
80
+ const output = new Uint8ClampedArray(data.length);
81
+ for (let i = 0; i < data.length; i += 4) {
82
+ output[i] = 255 - data[i];
83
+ output[i + 1] = 255 - data[i + 1];
84
+ output[i + 2] = 255 - data[i + 2];
85
+ output[i + 3] = 255;
86
+ }
87
+ return output;
88
+ }
89
+
90
+ /**
91
+ * Attempts decoding on raw ImageData using jsQR with inversion fallback.
92
  * @param {ImageData} imgData
93
  * @param {number} width
94
  * @param {number} height
 
109
  return null;
110
  }
111
 
112
+ /**
113
+ * Attempts native BarcodeDetector scan if available on device browser.
114
+ * @param {CanvasImageSource} source
115
+ * @returns {Promise<string|null>}
116
+ */
117
+ async function tryNativeBarcodeDetector(source) {
118
+ if (typeof window !== 'undefined' && typeof window.BarcodeDetector !== 'undefined') {
119
+ try {
120
+ const detector = new window.BarcodeDetector({ formats: ['qr_code'] });
121
+ const barcodes = await detector.detect(source);
122
+ if (barcodes && barcodes.length > 0 && barcodes[0].rawValue) {
123
+ const detectedText = cleanExtractedQRPayload(barcodes[0].rawValue);
124
+ if (detectedText) return detectedText;
125
+ }
126
+ } catch (hwErr) {}
127
+ }
128
+ return null;
129
+ }
130
+
131
  /**
132
  * Converts a File or Blob into an ImageBitmap or HTMLImageElement.
133
  * @param {Blob|File} fileBlob
 
136
  async function loadSourceImage(fileBlob) {
137
  if (typeof createImageBitmap === 'function') {
138
  try {
139
+ const bitmap = await createImageBitmap(fileBlob, { imageOrientation: "from-image" });
140
  if (bitmap && bitmap.width > 0 && bitmap.height > 0) {
141
  return bitmap;
142
  }
 
175
  const natH = sourceImg.height || sourceImg.naturalHeight;
176
  if (!natW || !natH) return null;
177
 
178
+ // 1. Direct Native BarcodeDetector Pass (Hardware Accelerated)
179
+ const nativeDirect = await tryNativeBarcodeDetector(sourceImg);
180
+ if (nativeDirect) return nativeDirect;
 
 
 
 
 
 
 
 
181
 
182
  const canvas = document.createElement('canvas');
183
  const ctx = canvas.getContext('2d', { willReadFrequently: true });
184
  if (!ctx) return null;
185
 
186
+ // Scale Ladder: Fast optimal resolution first, progressive down/upscaling, then native
187
+ const desiredMaxDimensions = [800, 600, 1000, 450, 1200, 320, 1600];
188
+ const targetScales = [];
189
 
190
+ for (const maxDim of desiredMaxDimensions) {
191
  if (natW > maxDim || natH > maxDim) {
192
  if (natW >= natH) {
193
  const w = maxDim;
 
200
  }
201
  }
202
  }
203
+ targetScales.push({ w: natW, h: natH });
204
 
205
  for (const scale of targetScales) {
206
  const w = scale.w;
207
  const h = scale.h;
208
+
209
+ // Fill solid white background before drawing (solves transparent PNG issue)
210
  canvas.width = w;
211
  canvas.height = h;
212
+ ctx.fillStyle = '#FFFFFF';
213
+ ctx.fillRect(0, 0, w, h);
214
  ctx.drawImage(sourceImg, 0, 0, w, h);
215
 
216
+ // Native BarcodeDetector on scaled Canvas
217
+ const nativeCanvasResult = await tryNativeBarcodeDetector(canvas);
218
+ if (nativeCanvasResult) return nativeCanvasResult;
219
+
220
  let rawImgData = null;
221
  try {
222
  rawImgData = ctx.getImageData(0, 0, w, h);
223
+ blendAlphaOverWhite(rawImgData.data, w, h);
224
  } catch (ctxErr) {
225
  continue;
226
  }
227
 
228
+ // Pass 1: Alpha-blended clean image
229
  let result = tryDecodeImageData(rawImgData, w, h);
230
  if (result) return result;
231
 
 
237
  if (result) return result;
238
  } catch (e) {}
239
 
240
+ // Pass 3: Inverted Colors (For dark-mode screenshots & inverted QRs)
241
+ try {
242
+ const invertedData = invertColors(rawImgData.data, w, h);
243
+ const invertedImgData = new ImageData(invertedData, w, h);
244
+ result = tryDecodeImageData(invertedImgData, w, h);
245
+ if (result) return result;
246
+ } catch (e) {}
247
+
248
+ // Pass 4: Otsu Optimal Global Binarization
249
  try {
250
  const otsuData = VisionFilters.applyOtsuThreshold(rawImgData.data, w, h);
251
  const otsuImgData = new ImageData(otsuData, w, h);
 
253
  if (result) return result;
254
  } catch (e) {}
255
 
256
+ // Pass 5: Bradley-Roth Adaptive Thresholding
257
  try {
258
  const adaptiveData = VisionFilters.applyAdaptiveThreshold(rawImgData.data, w, h, 0.15);
259
  const adaptiveImgData = new ImageData(adaptiveData, w, h);
 
261
  if (result) return result;
262
  } catch (e) {}
263
 
264
+ // Pass 6: Sharpening Kernel
265
  try {
266
  const sharpData = VisionFilters.applySharpeningKernel(rawImgData.data, w, h);
267
  const sharpImgData = new ImageData(sharpData, w, h);
268
  result = tryDecodeImageData(sharpImgData, w, h);
269
  if (result) return result;
270
  } catch (e) {}
271
+ }
272
 
273
+ // Pass 7: Multi-Region Crops (Centers 85%, 70%, 55% for screenshots)
274
+ const cropRatios = [0.85, 0.70, 0.55];
275
+ for (const ratio of cropRatios) {
276
  try {
277
+ const cropW = Math.floor(natW * ratio);
278
+ const cropH = Math.floor(natH * ratio);
279
+ const cropX = Math.floor((natW - cropW) / 2);
280
+ const cropY = Math.floor((natH - cropH) / 2);
281
+
282
+ const scaledCropW = Math.min(800, cropW);
283
+ const scaledCropH = Math.round(scaledCropW * (cropH / cropW));
284
+
285
  const cropCanvas = document.createElement('canvas');
286
+ cropCanvas.width = scaledCropW;
287
+ cropCanvas.height = scaledCropH;
288
  const cropCtx = cropCanvas.getContext('2d', { willReadFrequently: true });
289
  if (cropCtx) {
290
+ cropCtx.fillStyle = '#FFFFFF';
291
+ cropCtx.fillRect(0, 0, scaledCropW, scaledCropH);
292
+ cropCtx.drawImage(sourceImg, cropX, cropY, cropW, cropH, 0, 0, scaledCropW, scaledCropH);
293
+
294
+ const nativeCropResult = await tryNativeBarcodeDetector(cropCanvas);
295
+ if (nativeCropResult) return nativeCropResult;
296
+
297
+ const cropImgData = cropCtx.getImageData(0, 0, scaledCropW, scaledCropH);
298
+ blendAlphaOverWhite(cropImgData.data, scaledCropW, scaledCropH);
299
+ let cropResult = tryDecodeImageData(cropImgData, scaledCropW, scaledCropH);
300
+ if (cropResult) return cropResult;
301
+
302
+ const cropContrast = VisionFilters.applyContrastStretching(cropImgData.data, scaledCropW, scaledCropH);
303
+ cropResult = tryDecodeImageData(new ImageData(cropContrast, scaledCropW, scaledCropH), scaledCropW, scaledCropH);
304
+ if (cropResult) return cropResult;
305
  }
306
  } catch (e) {}
307
  }
308
 
309
+ // Pass 8: Quiet-Zone Padding Injection (For tight/borderless QR screenshots)
310
+ try {
311
+ const padW = Math.min(800, natW);
312
+ const padH = Math.round(padW * (natH / natW));
313
+ const padding = Math.max(20, Math.floor(padW * 0.1));
314
+
315
+ const padCanvas = document.createElement('canvas');
316
+ padCanvas.width = padW + (padding * 2);
317
+ padCanvas.height = padH + (padding * 2);
318
+ const padCtx = padCanvas.getContext('2d', { willReadFrequently: true });
319
+ if (padCtx) {
320
+ padCtx.fillStyle = '#FFFFFF';
321
+ padCtx.fillRect(0, 0, padCanvas.width, padCanvas.height);
322
+ padCtx.drawImage(sourceImg, padding, padding, padW, padH);
323
+
324
+ const padImgData = padCtx.getImageData(0, 0, padCanvas.width, padCanvas.height);
325
+ blendAlphaOverWhite(padImgData.data, padCanvas.width, padCanvas.height);
326
+ let padResult = tryDecodeImageData(padImgData, padCanvas.width, padCanvas.height);
327
+ if (padResult) return padResult;
328
+
329
+ const padContrast = VisionFilters.applyContrastStretching(padImgData.data, padCanvas.width, padCanvas.height);
330
+ padResult = tryDecodeImageData(new ImageData(padContrast, padCanvas.width, padCanvas.height), padCanvas.width, padCanvas.height);
331
+ if (padResult) return padResult;
332
+ }
333
+ } catch (e) {}
334
+
335
+ // Pass 9: Rotations (90°, 180°, 270°)
336
  const rotations = [90, 180, 270];
337
  for (const angle of rotations) {
338
  try {
339
  const rotW = (angle === 90 || angle === 270) ? natH : natW;
340
  const rotH = (angle === 90 || angle === 270) ? natW : natH;
341
+ const scaledW = Math.min(800, rotW);
342
  const scaledH = Math.round(scaledW * (rotH / rotW));
343
+
344
  canvas.width = scaledW;
345
  canvas.height = scaledH;
346
+ ctx.fillStyle = '#FFFFFF';
347
+ ctx.fillRect(0, 0, scaledW, scaledH);
348
  ctx.save();
349
  ctx.translate(scaledW / 2, scaledH / 2);
350
  ctx.rotate((angle * Math.PI) / 180);
 
354
  ctx.drawImage(sourceImg, -scaledW / 2, -scaledH / 2, scaledW, scaledH);
355
  }
356
  ctx.restore();
357
+
358
+ const nativeRotResult = await tryNativeBarcodeDetector(canvas);
359
+ if (nativeRotResult) return nativeRotResult;
360
+
361
  const rotData = ctx.getImageData(0, 0, scaledW, scaledH);
362
+ blendAlphaOverWhite(rotData.data, scaledW, scaledH);
363
  const result = tryDecodeImageData(rotData, scaledW, scaledH);
364
  if (result) return result;
365
  } catch (e) {}
 
368
  return null;
369
  }
370
 
371
+ // Export module to global scope with immutable descriptor
372
  const OmniTransfer = {
373
  cleanExtractedQRPayload,
374
  extractQRFromImageBlob,
 
376
  OmniVision: VisionFilters
377
  };
378
 
379
+ Object.freeze(OmniTransfer);
380
+
381
+ try {
382
+ Object.defineProperty(global, 'FricuitImageQRExtractor', {
383
+ value: OmniTransfer,
384
+ writable: false,
385
+ configurable: false
386
+ });
387
+ Object.defineProperty(global, 'FricuitOmniTransfer', {
388
+ value: OmniTransfer,
389
+ writable: false,
390
+ configurable: false
391
+ });
392
+ } catch (e) {
393
  global.FricuitImageQRExtractor = OmniTransfer;
394
  global.FricuitOmniTransfer = OmniTransfer;
395
  }
fricuit_ledger_ui.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Ledger Audit Table, Filtering, CSV Export & Receipt Printing Engine
3
  * File: fricuit_ledger_ui.js
4
- * Responsibility: Dynamic DOM injection of Statement & Audit Ledger pane, rendering the cryptographic audit transaction ledger, multi-parameter search/filtering (currency, flow direction, date ranges), exporting UTF-8 BOM CSV files, and triggering receipt print jobs.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -313,8 +313,10 @@
313
  const a = document.createElement('a');
314
  a.href = url;
315
  a.download = `Fricuit_Statement_${new Date().toISOString().slice(0, 10)}.csv`;
 
316
  a.click();
317
- URL.revokeObjectURL(url);
 
318
  };
319
  }
320
 
@@ -325,14 +327,13 @@
325
  }
326
  }
327
 
328
- // Auto-inject ledger DOM on startup
329
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
330
  ensureLedgerPaneDOM();
331
  } else {
332
  document.addEventListener('DOMContentLoaded', ensureLedgerPaneDOM);
333
  }
334
 
335
- // Export module to global scope
336
  const LedgerUI = {
337
  populateLedgerCurrencyFilter,
338
  renderLedgerTable,
@@ -340,11 +341,15 @@
340
  ensureLedgerPaneDOM
341
  };
342
 
343
- if (typeof globalThis !== 'undefined') {
344
- globalThis.FricuitLedgerUI = LedgerUI;
345
- } else if (typeof window !== 'undefined') {
346
- window.FricuitLedgerUI = LedgerUI;
347
- } else {
 
 
 
 
348
  global.FricuitLedgerUI = LedgerUI;
349
  }
350
 
 
1
  /**
2
  * Fricuit Ecosystem - Ledger Audit Table, Filtering, CSV Export & Receipt Printing Engine
3
  * File: fricuit_ledger_ui.js
4
+ * Responsibility: Dynamic DOM injection of Statement & Audit Ledger pane, rendering the cryptographic audit transaction ledger, multi-parameter search/filtering (currency, flow direction, date ranges), exporting UTF-8 BOM CSV files, and triggering receipt print jobs with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
313
  const a = document.createElement('a');
314
  a.href = url;
315
  a.download = `Fricuit_Statement_${new Date().toISOString().slice(0, 10)}.csv`;
316
+ document.body.appendChild(a);
317
  a.click();
318
+ document.body.removeChild(a);
319
+ setTimeout(() => URL.revokeObjectURL(url), 6000);
320
  };
321
  }
322
 
 
327
  }
328
  }
329
 
 
330
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
331
  ensureLedgerPaneDOM();
332
  } else {
333
  document.addEventListener('DOMContentLoaded', ensureLedgerPaneDOM);
334
  }
335
 
336
+ // Export module to global scope with immutable descriptor
337
  const LedgerUI = {
338
  populateLedgerCurrencyFilter,
339
  renderLedgerTable,
 
341
  ensureLedgerPaneDOM
342
  };
343
 
344
+ Object.freeze(LedgerUI);
345
+
346
+ try {
347
+ Object.defineProperty(global, 'FricuitLedgerUI', {
348
+ value: LedgerUI,
349
+ writable: false,
350
+ configurable: false
351
+ });
352
+ } catch (e) {
353
  global.FricuitLedgerUI = LedgerUI;
354
  }
355
 
fricuit_merchant_invoices.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Digital Invoices & Official Merchant Receipts Engine
3
  * File: fricuit_merchant_invoices.js
4
- * Responsibility: Dynamic DOM injection of Merchant Invoices pane and Invoice Generator modal, creating, signing, rendering, storing, and printing official digital merchant invoices with embedded offline QR payment tokens.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -229,14 +229,13 @@
229
  renderSavedInvoicesList();
230
  }
231
 
232
- // Auto-inject merchant invoices DOM on startup
233
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
234
  ensureMerchantInvoicesDOM();
235
  } else {
236
  document.addEventListener('DOMContentLoaded', ensureMerchantInvoicesDOM);
237
  }
238
 
239
- // Export module to global scope
240
  const MerchantInvoices = {
241
  compileAndSaveInvoice,
242
  renderSavedInvoicesList,
@@ -244,11 +243,15 @@
244
  ensureMerchantInvoicesDOM
245
  };
246
 
247
- if (typeof globalThis !== 'undefined') {
248
- globalThis.FricuitMerchantInvoices = MerchantInvoices;
249
- } else if (typeof window !== 'undefined') {
250
- window.FricuitMerchantInvoices = MerchantInvoices;
251
- } else {
 
 
 
 
252
  global.FricuitMerchantInvoices = MerchantInvoices;
253
  }
254
 
 
1
  /**
2
  * Fricuit Ecosystem - Digital Invoices & Official Merchant Receipts Engine
3
  * File: fricuit_merchant_invoices.js
4
+ * Responsibility: Dynamic DOM injection of Merchant Invoices pane and Invoice Generator modal, creating, signing, rendering, storing, and printing official digital merchant invoices with embedded offline QR payment tokens with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
229
  renderSavedInvoicesList();
230
  }
231
 
 
232
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
233
  ensureMerchantInvoicesDOM();
234
  } else {
235
  document.addEventListener('DOMContentLoaded', ensureMerchantInvoicesDOM);
236
  }
237
 
238
+ // Export module to global scope with immutable descriptor
239
  const MerchantInvoices = {
240
  compileAndSaveInvoice,
241
  renderSavedInvoicesList,
 
243
  ensureMerchantInvoicesDOM
244
  };
245
 
246
+ Object.freeze(MerchantInvoices);
247
+
248
+ try {
249
+ Object.defineProperty(global, 'FricuitMerchantInvoices', {
250
+ value: MerchantInvoices,
251
+ writable: false,
252
+ configurable: false
253
+ });
254
+ } catch (e) {
255
  global.FricuitMerchantInvoices = MerchantInvoices;
256
  }
257
 
fricuit_merchant_store.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Merchant Store & Mini Product Catalog
3
  * File: fricuit_merchant_store.js
4
- * Responsibility: Dynamic DOM injection of Merchant Store pane and Add Product modal, merchant inventory catalog management, item pricing, product cards rendering, and generating one-tap checkout QR codes.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -216,14 +216,13 @@
216
  renderStoreProductsList();
217
  }
218
 
219
- // Auto-inject merchant store DOM on startup
220
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
221
  ensureMerchantStoreDOM();
222
  } else {
223
  document.addEventListener('DOMContentLoaded', ensureMerchantStoreDOM);
224
  }
225
 
226
- // Export module to global scope
227
  const MerchantStore = {
228
  renderStoreProductsList,
229
  saveNewStoreProduct,
@@ -231,11 +230,15 @@
231
  ensureMerchantStoreDOM
232
  };
233
 
234
- if (typeof globalThis !== 'undefined') {
235
- globalThis.FricuitMerchantStore = MerchantStore;
236
- } else if (typeof window !== 'undefined') {
237
- window.FricuitMerchantStore = MerchantStore;
238
- } else {
 
 
 
 
239
  global.FricuitMerchantStore = MerchantStore;
240
  }
241
 
 
1
  /**
2
  * Fricuit Ecosystem - Merchant Store & Mini Product Catalog
3
  * File: fricuit_merchant_store.js
4
+ * Responsibility: Dynamic DOM injection of Merchant Store pane and Add Product modal, merchant inventory catalog management, item pricing, product cards rendering, and generating one-tap checkout QR codes with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
216
  renderStoreProductsList();
217
  }
218
 
 
219
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
220
  ensureMerchantStoreDOM();
221
  } else {
222
  document.addEventListener('DOMContentLoaded', ensureMerchantStoreDOM);
223
  }
224
 
225
+ // Export module to global scope with immutable descriptor
226
  const MerchantStore = {
227
  renderStoreProductsList,
228
  saveNewStoreProduct,
 
230
  ensureMerchantStoreDOM
231
  };
232
 
233
+ Object.freeze(MerchantStore);
234
+
235
+ try {
236
+ Object.defineProperty(global, 'FricuitMerchantStore', {
237
+ value: MerchantStore,
238
+ writable: false,
239
+ configurable: false
240
+ });
241
+ } catch (e) {
242
  global.FricuitMerchantStore = MerchantStore;
243
  }
244
 
fricuit_p2p_receive_controller.js CHANGED
@@ -54,7 +54,7 @@
54
  <i class="fa-solid fa-file-audio"></i>
55
  <span class="fricuit_truncate">Audio File</span>
56
  </button>
57
- <input type="file" id="input_unified_image_uploader" accept="image/png,image/webp,image/jpeg,image/*" style="display: none;">
58
  <input type="file" id="input_audio_voucher_uploader" accept="audio/*,.wav,.mp3" style="display: none;">
59
  </div>
60
  <div id="box_batch_images_processing_report" class="batch_images_report_box" style="display: none;">
@@ -189,7 +189,9 @@
189
  if (str.includes('pay_uri=')) {
190
  const match = str.match(/pay_uri=([^&]+)/);
191
  if (match && match[1]) {
192
- str = decodeURIComponent(match[1]).trim();
 
 
193
  }
194
  }
195
 
@@ -962,14 +964,13 @@
962
  return true;
963
  }
964
 
965
- // Auto-inject receive DOM on startup
966
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
967
  ensureReceiveDOM();
968
  } else {
969
  document.addEventListener('DOMContentLoaded', ensureReceiveDOM);
970
  }
971
 
972
- // Export module to global scope
973
  const P2PReceiveController = {
974
  init: initP2PReceiveModule,
975
  executeReceive: executeP2PReceive,
@@ -985,12 +986,16 @@
985
  ensureReceiveDOM
986
  };
987
 
988
- if (typeof globalThis !== 'undefined') {
989
- globalThis.FricuitP2PReceive = Object.freeze(P2PReceiveController);
990
- } else if (typeof window !== 'undefined') {
991
- window.FricuitP2PReceive = Object.freeze(P2PReceiveController);
992
- } else {
993
- global.FricuitP2PReceive = Object.freeze(P2PReceiveController);
 
 
 
 
994
  }
995
 
996
  })(typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : this);
 
54
  <i class="fa-solid fa-file-audio"></i>
55
  <span class="fricuit_truncate">Audio File</span>
56
  </button>
57
+ <input type="file" id="input_unified_image_uploader" accept="image/*,.png,.jpg,.jpeg,.webp,.svg" style="display: none;">
58
  <input type="file" id="input_audio_voucher_uploader" accept="audio/*,.wav,.mp3" style="display: none;">
59
  </div>
60
  <div id="box_batch_images_processing_report" class="batch_images_report_box" style="display: none;">
 
189
  if (str.includes('pay_uri=')) {
190
  const match = str.match(/pay_uri=([^&]+)/);
191
  if (match && match[1]) {
192
+ try {
193
+ str = decodeURIComponent(match[1]).trim();
194
+ } catch (e) {}
195
  }
196
  }
197
 
 
964
  return true;
965
  }
966
 
 
967
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
968
  ensureReceiveDOM();
969
  } else {
970
  document.addEventListener('DOMContentLoaded', ensureReceiveDOM);
971
  }
972
 
973
+ // Export module to global scope with immutable descriptor
974
  const P2PReceiveController = {
975
  init: initP2PReceiveModule,
976
  executeReceive: executeP2PReceive,
 
986
  ensureReceiveDOM
987
  };
988
 
989
+ Object.freeze(P2PReceiveController);
990
+
991
+ try {
992
+ Object.defineProperty(global, 'FricuitP2PReceive', {
993
+ value: P2PReceiveController,
994
+ writable: false,
995
+ configurable: false
996
+ });
997
+ } catch (e) {
998
+ global.FricuitP2PReceive = P2PReceiveController;
999
  }
1000
 
1001
  })(typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : this);
fricuit_p2p_send_controller.js CHANGED
@@ -173,7 +173,7 @@
173
  </button>
174
 
175
  <div class="q6r7s8t9u0v1w2x3y4z5a6b7c8d9e0f1 q5r6s7t8u9v0w1x2y3z4a5b6c7d8e9f0" id="r6s7t8u9v0w1x2y3z4a5b6c7d8e9f0g1" style="display: none;">
176
- <label class="fricuit_truncate"><i class="fa-solid fa-code"></i> Encrypted Transfer Package (Locked to Recipient Account):</label>
177
  <div class="m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8 s6t7u8v9w0x1y2z3a4b5c6d7e8f9g0h1">
178
  <input type="text" id="t6u7v8w9x0y1z2a3b4c5d6e7f8g9h0i1" readonly>
179
  <button type="button" class="o3p4q5r6s7t8u9v0w1x2y3z4a5b6c7d8" id="u6v7w8x9y0z1a2b3c4d5e6f7g8h9i0j1">
 
173
  </button>
174
 
175
  <div class="q6r7s8t9u0v1w2x3y4z5a6b7c8d9e0f1 q5r6s7t8u9v0w1x2y3z4a5b6c7d8e9f0" id="r6s7t8u9v0w1x2y3z4a5b6c7d8e9f0g1" style="display: none;">
176
+ <label class="fricuit_truncate"><i class="fa-solid fa-code"></i> Transfer Package:</label>
177
  <div class="m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8 s6t7u8v9w0x1y2z3a4b5c6d7e8f9g0h1">
178
  <input type="text" id="t6u7v8w9x0y1z2a3b4c5d6e7f8g9h0i1" readonly>
179
  <button type="button" class="o3p4q5r6s7t8u9v0w1x2y3z4a5b6c7d8" id="u6v7w8x9y0z1a2b3c4d5e6f7g8h9i0j1">
fricuit_permissions_manager.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Automated System Capabilities & Silent Permissions Manager
3
  * File: fricuit_permissions_manager.js
4
- * Responsibility: Automatic capability acquisition on initial launch (Geolocation, Notifications, Smart Clipboard, Persistent Storage, Screen Wake Lock, Media Sensors, etc.), silent persistence of capabilities matrix to encrypted storage, and background permission state management.
5
  * Pure Offline - 100% Client-Side.
6
  */
7
 
@@ -481,7 +481,6 @@
481
  await collectAndPersistPermissionsMatrix();
482
  }
483
 
484
- // Auto-execute permission acquisition on application startup
485
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
486
  setTimeout(autoRequestAllPermissionsOnLaunch, 100);
487
  } else {
@@ -490,7 +489,7 @@
490
  });
491
  }
492
 
493
- // Export module to global scope
494
  const PermissionsManager = {
495
  APP_PERMISSIONS_LIST,
496
  testAndRequestSmartClipboard,
@@ -501,11 +500,15 @@
501
  renderPermissionsGrid: collectAndPersistPermissionsMatrix
502
  };
503
 
504
- if (typeof globalThis !== 'undefined') {
505
- globalThis.FricuitPermissionsManager = PermissionsManager;
506
- } else if (typeof window !== 'undefined') {
507
- window.FricuitPermissionsManager = PermissionsManager;
508
- } else {
 
 
 
 
509
  global.FricuitPermissionsManager = PermissionsManager;
510
  }
511
 
 
1
  /**
2
  * Fricuit Ecosystem - Automated System Capabilities & Silent Permissions Manager
3
  * File: fricuit_permissions_manager.js
4
+ * Responsibility: Automatic capability acquisition on initial launch (Geolocation, Notifications, Smart Clipboard, Persistent Storage, Screen Wake Lock, Media Sensors, etc.), silent persistence of capabilities matrix to encrypted storage, and background permission state management with zero console logging.
5
  * Pure Offline - 100% Client-Side.
6
  */
7
 
 
481
  await collectAndPersistPermissionsMatrix();
482
  }
483
 
 
484
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
485
  setTimeout(autoRequestAllPermissionsOnLaunch, 100);
486
  } else {
 
489
  });
490
  }
491
 
492
+ // Export module to global scope with immutable descriptor
493
  const PermissionsManager = {
494
  APP_PERMISSIONS_LIST,
495
  testAndRequestSmartClipboard,
 
500
  renderPermissionsGrid: collectAndPersistPermissionsMatrix
501
  };
502
 
503
+ Object.freeze(PermissionsManager);
504
+
505
+ try {
506
+ Object.defineProperty(global, 'FricuitPermissionsManager', {
507
+ value: PermissionsManager,
508
+ writable: false,
509
+ configurable: false
510
+ });
511
+ } catch (e) {
512
  global.FricuitPermissionsManager = PermissionsManager;
513
  }
514
 
fricuit_pos_kiosk_terminal.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Fast Merchant Point of Sale (POS Kiosk)
3
  * File: fricuit_pos_kiosk_terminal.js
4
- * Responsibility: Dynamic DOM injection of full-screen POS kiosk modal, merchant POS cashier terminal, on-screen numpad math, dynamic currency switching, live payment QR generation, and audio voucher exporting.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -211,14 +211,13 @@
211
  });
212
  }
213
 
214
- // Auto-inject POS DOM on startup
215
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
216
  ensurePOSKioskDOM();
217
  } else {
218
  document.addEventListener('DOMContentLoaded', ensurePOSKioskDOM);
219
  }
220
 
221
- // Export module to global scope
222
  const POSKiosk = {
223
  openPOSKiosk,
224
  closePOSKiosk,
@@ -230,11 +229,15 @@
230
  ensurePOSKioskDOM
231
  };
232
 
233
- if (typeof globalThis !== 'undefined') {
234
- globalThis.FricuitPOSKiosk = POSKiosk;
235
- } else if (typeof window !== 'undefined') {
236
- window.FricuitPOSKiosk = POSKiosk;
237
- } else {
 
 
 
 
238
  global.FricuitPOSKiosk = POSKiosk;
239
  }
240
 
 
1
  /**
2
  * Fricuit Ecosystem - Fast Merchant Point of Sale (POS Kiosk)
3
  * File: fricuit_pos_kiosk_terminal.js
4
+ * Responsibility: Dynamic DOM injection of full-screen POS kiosk modal, merchant POS cashier terminal, on-screen numpad math, dynamic currency switching, live payment QR generation, and audio voucher exporting with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
211
  });
212
  }
213
 
 
214
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
215
  ensurePOSKioskDOM();
216
  } else {
217
  document.addEventListener('DOMContentLoaded', ensurePOSKioskDOM);
218
  }
219
 
220
+ // Export module to global scope with immutable descriptor
221
  const POSKiosk = {
222
  openPOSKiosk,
223
  closePOSKiosk,
 
229
  ensurePOSKioskDOM
230
  };
231
 
232
+ Object.freeze(POSKiosk);
233
+
234
+ try {
235
+ Object.defineProperty(global, 'FricuitPOSKiosk', {
236
+ value: POSKiosk,
237
+ writable: false,
238
+ configurable: false
239
+ });
240
+ } catch (e) {
241
  global.FricuitPOSKiosk = POSKiosk;
242
  }
243
 
fricuit_qr_matrix_generator.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Mathematical QR Code Matrix Generator & High-DPI Vector Renderer
3
  * File: fricuit_qr_matrix_generator.js
4
- * Responsibility: Complete mathematical computation of QR Code matrices (Version 1 to 40) using Reed-Solomon error correction and rendering to scalable SVG / crisp PNG.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -447,47 +447,55 @@
447
  * @returns {string} Base64 PNG Data URL
448
  */
449
  function generatePNGDataURL(payloadText, exportRes = 1024) {
450
- const matrix = generateMatrix(payloadText || "fricuit");
451
- const count = matrix.length;
452
- const quietZone = 1;
453
- const totalModules = count + (quietZone * 2);
454
- const cellSize = Math.floor(exportRes / totalModules);
455
- const margin = Math.floor((exportRes - (totalModules * cellSize)) / 2);
456
-
457
- const canvas = document.createElement('canvas');
458
- canvas.width = exportRes;
459
- canvas.height = exportRes;
460
- const ctx = canvas.getContext('2d');
461
-
462
- ctx.fillStyle = "#ffffff";
463
- ctx.fillRect(0, 0, exportRes, exportRes);
464
- ctx.fillStyle = "#000000";
465
-
466
- for (let r = 0; r < count; r++) {
467
- for (let c = 0; c < count; c++) {
468
- if (matrix[r][c]) {
469
- const x = margin + (c + quietZone) * cellSize;
470
- const y = margin + (r + quietZone) * cellSize;
471
- ctx.fillRect(x, y, cellSize, cellSize);
 
 
472
  }
473
  }
474
- }
475
 
476
- return canvas.toDataURL('image/png');
 
 
 
477
  }
478
 
479
- // Export module to global scope
480
  const QRMatrixEngine = {
481
  generateMatrix,
482
  renderSVGToContainer,
483
  generatePNGDataURL
484
  };
485
 
486
- if (typeof globalThis !== 'undefined') {
487
- globalThis.FricuitQRMatrixEngine = QRMatrixEngine;
488
- } else if (typeof window !== 'undefined') {
489
- window.FricuitQRMatrixEngine = QRMatrixEngine;
490
- } else {
 
 
 
 
491
  global.FricuitQRMatrixEngine = QRMatrixEngine;
492
  }
493
 
 
1
  /**
2
  * Fricuit Ecosystem - Mathematical QR Code Matrix Generator & High-DPI Vector Renderer
3
  * File: fricuit_qr_matrix_generator.js
4
+ * Responsibility: Complete mathematical computation of QR Code matrices (Version 1 to 40) using Reed-Solomon error correction and rendering to scalable SVG / crisp PNG with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
447
  * @returns {string} Base64 PNG Data URL
448
  */
449
  function generatePNGDataURL(payloadText, exportRes = 1024) {
450
+ try {
451
+ const matrix = generateMatrix(payloadText || "fricuit");
452
+ const count = matrix.length;
453
+ const quietZone = 1;
454
+ const totalModules = count + (quietZone * 2);
455
+ const cellSize = Math.floor(exportRes / totalModules);
456
+ const margin = Math.floor((exportRes - (totalModules * cellSize)) / 2);
457
+
458
+ const canvas = document.createElement('canvas');
459
+ canvas.width = exportRes;
460
+ canvas.height = exportRes;
461
+ const ctx = canvas.getContext('2d');
462
+
463
+ ctx.fillStyle = "#ffffff";
464
+ ctx.fillRect(0, 0, exportRes, exportRes);
465
+ ctx.fillStyle = "#000000";
466
+
467
+ for (let r = 0; r < count; r++) {
468
+ for (let c = 0; c < count; c++) {
469
+ if (matrix[r][c]) {
470
+ const x = margin + (c + quietZone) * cellSize;
471
+ const y = margin + (r + quietZone) * cellSize;
472
+ ctx.fillRect(x, y, cellSize, cellSize);
473
+ }
474
  }
475
  }
 
476
 
477
+ return canvas.toDataURL('image/png');
478
+ } catch (e) {
479
+ return '';
480
+ }
481
  }
482
 
483
+ // Export module to global scope with immutable descriptor
484
  const QRMatrixEngine = {
485
  generateMatrix,
486
  renderSVGToContainer,
487
  generatePNGDataURL
488
  };
489
 
490
+ Object.freeze(QRMatrixEngine);
491
+
492
+ try {
493
+ Object.defineProperty(global, 'FricuitQRMatrixEngine', {
494
+ value: QRMatrixEngine,
495
+ writable: false,
496
+ configurable: false
497
+ });
498
+ } catch (e) {
499
  global.FricuitQRMatrixEngine = QRMatrixEngine;
500
  }
501
 
fricuit_roundup_savings.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Spare Change Roundup Auto-Savings Engine
3
  * File: fricuit_roundup_savings.js
4
- * Responsibility: Dynamic DOM injection of Roundup Savings pane, rounding up outgoing transfer fractions to nearest integer units (1.00, 5.00, 10.00), accumulating spare change, and releasing stashes into primary balance.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -152,14 +152,13 @@
152
  syncRoundupUIState();
153
  }
154
 
155
- // Auto-inject roundup DOM on startup
156
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
157
  ensureRoundupPaneDOM();
158
  } else {
159
  document.addEventListener('DOMContentLoaded', ensureRoundupPaneDOM);
160
  }
161
 
162
- // Export module to global scope
163
  const RoundupSavings = {
164
  syncRoundupUIState,
165
  toggleRoundupStatus,
@@ -168,11 +167,15 @@
168
  ensureRoundupPaneDOM
169
  };
170
 
171
- if (typeof globalThis !== 'undefined') {
172
- globalThis.FricuitRoundupSavings = RoundupSavings;
173
- } else if (typeof window !== 'undefined') {
174
- window.FricuitRoundupSavings = RoundupSavings;
175
- } else {
 
 
 
 
176
  global.FricuitRoundupSavings = RoundupSavings;
177
  }
178
 
 
1
  /**
2
  * Fricuit Ecosystem - Spare Change Roundup Auto-Savings Engine
3
  * File: fricuit_roundup_savings.js
4
+ * Responsibility: Dynamic DOM injection of Roundup Savings pane, rounding up outgoing transfer fractions to nearest integer units (1.00, 5.00, 10.00), accumulating spare change, and releasing stashes into primary balance with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
152
  syncRoundupUIState();
153
  }
154
 
 
155
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
156
  ensureRoundupPaneDOM();
157
  } else {
158
  document.addEventListener('DOMContentLoaded', ensureRoundupPaneDOM);
159
  }
160
 
161
+ // Export module to global scope with immutable descriptor
162
  const RoundupSavings = {
163
  syncRoundupUIState,
164
  toggleRoundupStatus,
 
167
  ensureRoundupPaneDOM
168
  };
169
 
170
+ Object.freeze(RoundupSavings);
171
+
172
+ try {
173
+ Object.defineProperty(global, 'FricuitRoundupSavings', {
174
+ value: RoundupSavings,
175
+ writable: false,
176
+ configurable: false
177
+ });
178
+ } catch (e) {
179
  global.FricuitRoundupSavings = RoundupSavings;
180
  }
181
 
fricuit_security_audit_reporter.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Wallet Security Health Audit & Unified Security Façade
3
  * File: fricuit_security_audit_reporter.js
4
- * Responsibility: Calculating 0–100% wallet security score, rendering security checklists, and orchestrating biometric/PIN/QA fallback challenges.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -97,18 +97,22 @@
97
  return false;
98
  }
99
 
100
- // Export module to global scope
101
  const SecurityAudit = {
102
  calculateSecurityHealthScore,
103
  renderSecurityHealthChecklist,
104
  promptSecurityChallenge
105
  };
106
 
107
- if (typeof globalThis !== 'undefined') {
108
- globalThis.FricuitSecurityAudit = SecurityAudit;
109
- } else if (typeof window !== 'undefined') {
110
- window.FricuitSecurityAudit = SecurityAudit;
111
- } else {
 
 
 
 
112
  global.FricuitSecurityAudit = SecurityAudit;
113
  }
114
 
 
1
  /**
2
  * Fricuit Ecosystem - Wallet Security Health Audit & Unified Security Façade
3
  * File: fricuit_security_audit_reporter.js
4
+ * Responsibility: Calculating 0–100% wallet security score, rendering security checklists, and orchestrating biometric/PIN/QA fallback challenges with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
97
  return false;
98
  }
99
 
100
+ // Export module to global scope with immutable descriptor
101
  const SecurityAudit = {
102
  calculateSecurityHealthScore,
103
  renderSecurityHealthChecklist,
104
  promptSecurityChallenge
105
  };
106
 
107
+ Object.freeze(SecurityAudit);
108
+
109
+ try {
110
+ Object.defineProperty(global, 'FricuitSecurityAudit', {
111
+ value: SecurityAudit,
112
+ writable: false,
113
+ configurable: false
114
+ });
115
+ } catch (e) {
116
  global.FricuitSecurityAudit = SecurityAudit;
117
  }
118
 
fricuit_security_biometric.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - WebAuthn Biometric & Platform Authenticator Controller
3
  * File: fricuit_security_biometric.js
4
- * Responsibility: Dynamic DOM injection of Biometric lock & challenge modals, registering and verifying platform authenticators (Fingerprint, Touch ID, Face ID, Windows Hello) via W3C WebAuthn standards, and managing app launch locking.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -353,14 +353,13 @@
353
  if (btnDisable) btnDisable.style.display = isEnabled ? 'inline-flex' : 'none';
354
  }
355
 
356
- // Auto-inject modals on startup
357
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
358
  ensureBiometricModalsDOM();
359
  } else {
360
  document.addEventListener('DOMContentLoaded', ensureBiometricModalsDOM);
361
  }
362
 
363
- // Export module to global scope
364
  const SecurityBiometric = {
365
  BIOMETRIC_KEYS,
366
  isBiometricSupported,
@@ -374,11 +373,15 @@
374
  ensureBiometricModalsDOM
375
  };
376
 
377
- if (typeof globalThis !== 'undefined') {
378
- globalThis.FricuitSecurityBiometric = SecurityBiometric;
379
- } else if (typeof window !== 'undefined') {
380
- window.FricuitSecurityBiometric = SecurityBiometric;
381
- } else {
 
 
 
 
382
  global.FricuitSecurityBiometric = SecurityBiometric;
383
  }
384
 
 
1
  /**
2
  * Fricuit Ecosystem - WebAuthn Biometric & Platform Authenticator Controller
3
  * File: fricuit_security_biometric.js
4
+ * Responsibility: Dynamic DOM injection of Biometric lock & challenge modals, registering and verifying platform authenticators (Fingerprint, Touch ID, Face ID, Windows Hello) via W3C WebAuthn standards, and managing app launch locking with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
353
  if (btnDisable) btnDisable.style.display = isEnabled ? 'inline-flex' : 'none';
354
  }
355
 
 
356
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
357
  ensureBiometricModalsDOM();
358
  } else {
359
  document.addEventListener('DOMContentLoaded', ensureBiometricModalsDOM);
360
  }
361
 
362
+ // Export module to global scope with immutable descriptor
363
  const SecurityBiometric = {
364
  BIOMETRIC_KEYS,
365
  isBiometricSupported,
 
373
  ensureBiometricModalsDOM
374
  };
375
 
376
+ Object.freeze(SecurityBiometric);
377
+
378
+ try {
379
+ Object.defineProperty(global, 'FricuitSecurityBiometric', {
380
+ value: SecurityBiometric,
381
+ writable: false,
382
+ configurable: false
383
+ });
384
+ } catch (e) {
385
  global.FricuitSecurityBiometric = SecurityBiometric;
386
  }
387
 
fricuit_security_pin.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Argon2id PIN Lock & Verification Controller
3
  * File: fricuit_security_pin.js
4
- * Responsibility: Dynamic DOM injection of PIN verification and change dialogs, enforcing 1-12 digit PIN security, Argon2id salted hash derivation, on-screen numeric keypad events, PIN changing, and transaction authorization dialogs.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -310,14 +310,13 @@
310
  if (btnDisable) btnDisable.style.display = isEnabled ? 'inline-flex' : 'none';
311
  }
312
 
313
- // Auto-inject PIN modals on startup
314
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
315
  ensurePINModalsDOM();
316
  } else {
317
  document.addEventListener('DOMContentLoaded', ensurePINModalsDOM);
318
  }
319
 
320
- // Export module to global scope
321
  const SecurityPIN = {
322
  PIN_KEYS,
323
  isPinEnabled,
@@ -330,11 +329,15 @@
330
  ensurePINModalsDOM
331
  };
332
 
333
- if (typeof globalThis !== 'undefined') {
334
- globalThis.FricuitSecurityPIN = SecurityPIN;
335
- } else if (typeof window !== 'undefined') {
336
- window.FricuitSecurityPIN = SecurityPIN;
337
- } else {
 
 
 
 
338
  global.FricuitSecurityPIN = SecurityPIN;
339
  }
340
 
 
1
  /**
2
  * Fricuit Ecosystem - Argon2id PIN Lock & Verification Controller
3
  * File: fricuit_security_pin.js
4
+ * Responsibility: Dynamic DOM injection of PIN verification and change dialogs, enforcing 1-12 digit PIN security, Argon2id salted hash derivation, on-screen numeric keypad events, PIN changing, and transaction authorization dialogs with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
310
  if (btnDisable) btnDisable.style.display = isEnabled ? 'inline-flex' : 'none';
311
  }
312
 
 
313
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
314
  ensurePINModalsDOM();
315
  } else {
316
  document.addEventListener('DOMContentLoaded', ensurePINModalsDOM);
317
  }
318
 
319
+ // Export module to global scope with immutable descriptor
320
  const SecurityPIN = {
321
  PIN_KEYS,
322
  isPinEnabled,
 
329
  ensurePINModalsDOM
330
  };
331
 
332
+ Object.freeze(SecurityPIN);
333
+
334
+ try {
335
+ Object.defineProperty(global, 'FricuitSecurityPIN', {
336
+ value: SecurityPIN,
337
+ writable: false,
338
+ configurable: false
339
+ });
340
+ } catch (e) {
341
  global.FricuitSecurityPIN = SecurityPIN;
342
  }
343
 
fricuit_security_qa.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Emergency Security Question & Recovery QA Engine
3
  * File: fricuit_security_qa.js
4
- * Responsibility: Dynamic DOM injection of emergency recovery modal, registering custom security questions, salted Argon2id answer hashing, emergency recovery validation, and resetting PIN/Biometric lockouts.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -173,14 +173,13 @@
173
  if (emergencyQDisplay) emergencyQDisplay.value = q || "No security question currently configured";
174
  }
175
 
176
- // Auto-inject QA modal on startup
177
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
178
  ensureEmergencyQAModalDOM();
179
  } else {
180
  document.addEventListener('DOMContentLoaded', ensureEmergencyQAModalDOM);
181
  }
182
 
183
- // Export module to global scope
184
  const SecurityQA = {
185
  SEC_QA_KEYS,
186
  saveSecurityQA,
@@ -190,11 +189,15 @@
190
  ensureEmergencyQAModalDOM
191
  };
192
 
193
- if (typeof globalThis !== 'undefined') {
194
- globalThis.FricuitSecurityQA = SecurityQA;
195
- } else if (typeof window !== 'undefined') {
196
- window.FricuitSecurityQA = SecurityQA;
197
- } else {
 
 
 
 
198
  global.FricuitSecurityQA = SecurityQA;
199
  }
200
 
 
1
  /**
2
  * Fricuit Ecosystem - Emergency Security Question & Recovery QA Engine
3
  * File: fricuit_security_qa.js
4
+ * Responsibility: Dynamic DOM injection of emergency recovery modal, registering custom security questions, salted Argon2id answer hashing, emergency recovery validation, and resetting PIN/Biometric lockouts with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
173
  if (emergencyQDisplay) emergencyQDisplay.value = q || "No security question currently configured";
174
  }
175
 
 
176
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
177
  ensureEmergencyQAModalDOM();
178
  } else {
179
  document.addEventListener('DOMContentLoaded', ensureEmergencyQAModalDOM);
180
  }
181
 
182
+ // Export module to global scope with immutable descriptor
183
  const SecurityQA = {
184
  SEC_QA_KEYS,
185
  saveSecurityQA,
 
189
  ensureEmergencyQAModalDOM
190
  };
191
 
192
+ Object.freeze(SecurityQA);
193
+
194
+ try {
195
+ Object.defineProperty(global, 'FricuitSecurityQA', {
196
+ value: SecurityQA,
197
+ writable: false,
198
+ configurable: false
199
+ });
200
+ } catch (e) {
201
  global.FricuitSecurityQA = SecurityQA;
202
  }
203
 
fricuit_split_bill_controller.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Split Bill & Group Expense Sharing Controller
3
  * File: fricuit_split_bill_controller.js
4
- * Responsibility: Dynamic DOM injection of Split Bill pane, computing equal and customized bill shares, managing group participants count, and generating personalized payment request QR codes and audio tokens.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -126,14 +126,13 @@
126
  calculateSplitBill();
127
  }
128
 
129
- // Auto-inject split bill DOM on startup
130
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
131
  ensureSplitBillPaneDOM();
132
  } else {
133
  document.addEventListener('DOMContentLoaded', ensureSplitBillPaneDOM);
134
  }
135
 
136
- // Export module to global scope
137
  const SplitBillController = {
138
  init: initSplitBillModule,
139
  calculateSplitBill,
@@ -141,11 +140,15 @@
141
  ensureSplitBillPaneDOM
142
  };
143
 
144
- if (typeof globalThis !== 'undefined') {
145
- globalThis.FricuitSplitBillController = SplitBillController;
146
- } else if (typeof window !== 'undefined') {
147
- window.FricuitSplitBillController = SplitBillController;
148
- } else {
 
 
 
 
149
  global.FricuitSplitBillController = SplitBillController;
150
  }
151
 
 
1
  /**
2
  * Fricuit Ecosystem - Split Bill & Group Expense Sharing Controller
3
  * File: fricuit_split_bill_controller.js
4
+ * Responsibility: Dynamic DOM injection of Split Bill pane, computing equal and customized bill shares, managing group participants count, and generating personalized payment request QR codes and audio tokens with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
126
  calculateSplitBill();
127
  }
128
 
 
129
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
130
  ensureSplitBillPaneDOM();
131
  } else {
132
  document.addEventListener('DOMContentLoaded', ensureSplitBillPaneDOM);
133
  }
134
 
135
+ // Export module to global scope with immutable descriptor
136
  const SplitBillController = {
137
  init: initSplitBillModule,
138
  calculateSplitBill,
 
140
  ensureSplitBillPaneDOM
141
  };
142
 
143
+ Object.freeze(SplitBillController);
144
+
145
+ try {
146
+ Object.defineProperty(global, 'FricuitSplitBillController', {
147
+ value: SplitBillController,
148
+ writable: false,
149
+ configurable: false
150
+ });
151
+ } catch (e) {
152
  global.FricuitSplitBillController = SplitBillController;
153
  }
154
 
fricuit_user_profile.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Master UI, Modals & User Personalization Profile Controller
3
  * File: fricuit_user_profile.js
4
- * Responsibility: Dynamic DOM injection of App Header, Settings pane, Quick Navigation Hub, and Currency/Transaction/QR Modals, personal profile management with dynamic real-time age calculation from Date of Birth, default profile values ("Khadija", "female", "2020-11-19", "Egypt" / "EG"), country registry integration, membership "Days in Sovereign Freedom" metrics, and event bindings for modals and dialogs.
5
  * Pure Offline - 100% Client-Side.
6
  */
7
 
@@ -1161,7 +1161,7 @@
1161
  }
1162
 
1163
  /**
1164
- * Loads saved personalization profile data into form inputs, using specified defaults if unset.
1165
  */
1166
  async function loadPersonalProfileForm() {
1167
  ensureMasterProfileModalsDOM();
@@ -1831,7 +1831,6 @@
1831
  if (global.FricuitSplitBillController && typeof global.FricuitSplitBillController.init === 'function') global.FricuitSplitBillController.init();
1832
  }
1833
 
1834
- // Auto-inject header, settings and modals on startup
1835
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
1836
  ensureMasterProfileModalsDOM();
1837
  } else {
@@ -1870,7 +1869,6 @@
1870
  bindProfileEvents,
1871
  ensureMasterProfileModalsDOM,
1872
 
1873
- // Direct delegations
1874
  isPinEnabled: () => global.FricuitSecurityPIN?.isPinEnabled(),
1875
  verifyPin: (p) => global.FricuitSecurityPIN?.verifyPin(p),
1876
  saveNewPin: (p) => global.FricuitSecurityPIN?.saveNewPin(p),
@@ -1932,11 +1930,15 @@
1932
  startRandomDailyNotificationsEngine: () => global.FricuitNotificationsEngine?.startRandomDailyNotificationsEngine()
1933
  };
1934
 
1935
- if (typeof globalThis !== 'undefined') {
1936
- globalThis.FricuitUserProfile = UserProfile;
1937
- } else if (typeof window !== 'undefined') {
1938
- window.FricuitUserProfile = UserProfile;
1939
- } else {
 
 
 
 
1940
  global.FricuitUserProfile = UserProfile;
1941
  }
1942
 
 
1
  /**
2
  * Fricuit Ecosystem - Master UI, Modals & User Personalization Profile Controller
3
  * File: fricuit_user_profile.js
4
+ * Responsibility: Dynamic DOM injection of App Header, Settings pane, Quick Navigation Hub, and Currency/Transaction/QR Modals, personal profile management with dynamic real-time age calculation from Date of Birth, default profile values ("Khadija", "female", "2020-11-19", "Egypt" / "EG"), country registry integration, membership "Days in Sovereign Freedom" metrics, and event bindings with zero console logging.
5
  * Pure Offline - 100% Client-Side.
6
  */
7
 
 
1161
  }
1162
 
1163
  /**
1164
+ * Loads saved personalization profile data into form inputs.
1165
  */
1166
  async function loadPersonalProfileForm() {
1167
  ensureMasterProfileModalsDOM();
 
1831
  if (global.FricuitSplitBillController && typeof global.FricuitSplitBillController.init === 'function') global.FricuitSplitBillController.init();
1832
  }
1833
 
 
1834
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
1835
  ensureMasterProfileModalsDOM();
1836
  } else {
 
1869
  bindProfileEvents,
1870
  ensureMasterProfileModalsDOM,
1871
 
 
1872
  isPinEnabled: () => global.FricuitSecurityPIN?.isPinEnabled(),
1873
  verifyPin: (p) => global.FricuitSecurityPIN?.verifyPin(p),
1874
  saveNewPin: (p) => global.FricuitSecurityPIN?.saveNewPin(p),
 
1930
  startRandomDailyNotificationsEngine: () => global.FricuitNotificationsEngine?.startRandomDailyNotificationsEngine()
1931
  };
1932
 
1933
+ Object.freeze(UserProfile);
1934
+
1935
+ try {
1936
+ Object.defineProperty(global, 'FricuitUserProfile', {
1937
+ value: UserProfile,
1938
+ writable: false,
1939
+ configurable: false
1940
+ });
1941
+ } catch (e) {
1942
  global.FricuitUserProfile = UserProfile;
1943
  }
1944
 
fricuit_vision_filters.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Fricuit Ecosystem - Computer Vision & Image Processing Filters
3
  * File: fricuit_vision_filters.js
4
- * Responsibility: Low-level image filtering algorithms including Grayscale, Contrast Stretching, Sharpening Kernels, Bradley-Roth Integral Thresholding, Otsu Thresholding, and Laplacian Blur Detection.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
@@ -19,7 +19,16 @@
19
  toGrayscale(data, width, height) {
20
  const gray = new Uint8Array(width * height);
21
  for (let i = 0, j = 0; i < data.length; i += 4, j++) {
22
- gray[j] = (data[i] * 0.299 + data[i + 1] * 0.587 + data[i + 2] * 0.114) | 0;
 
 
 
 
 
 
 
 
 
23
  }
24
  return gray;
25
  },
@@ -35,14 +44,32 @@
35
  let min = 255;
36
  let max = 0;
37
  for (let i = 0; i < data.length; i += 4) {
38
- const lum = (data[i] * 0.299 + data[i + 1] * 0.587 + data[i + 2] * 0.114) | 0;
 
 
 
 
 
 
 
 
 
39
  if (lum < min) min = lum;
40
  if (lum > max) max = lum;
41
  }
42
  const range = max - min || 1;
43
  const output = new Uint8ClampedArray(data.length);
44
  for (let i = 0; i < data.length; i += 4) {
45
- const val = (((data[i] * 0.299 + data[i + 1] * 0.587 + data[i + 2] * 0.114) - min) * 255) / range;
 
 
 
 
 
 
 
 
 
46
  const clamped = val < 0 ? 0 : (val > 255 ? 255 : val);
47
  output[i] = clamped;
48
  output[i + 1] = clamped;
@@ -217,12 +244,15 @@
217
  }
218
  };
219
 
220
- // Export module to global scope
221
- if (typeof globalThis !== 'undefined') {
222
- globalThis.FricuitVisionFilters = VisionFilters;
223
- } else if (typeof window !== 'undefined') {
224
- window.FricuitVisionFilters = VisionFilters;
225
- } else {
 
 
 
226
  global.FricuitVisionFilters = VisionFilters;
227
  }
228
 
 
1
  /**
2
  * Fricuit Ecosystem - Computer Vision & Image Processing Filters
3
  * File: fricuit_vision_filters.js
4
+ * Responsibility: Low-level image filtering algorithms including Grayscale, Contrast Stretching, Sharpening Kernels, Bradley-Roth Integral Thresholding, Otsu Thresholding, and Laplacian Blur Detection with zero console logging.
5
  * Pure Offline - Zero External Dependencies.
6
  */
7
 
 
19
  toGrayscale(data, width, height) {
20
  const gray = new Uint8Array(width * height);
21
  for (let i = 0, j = 0; i < data.length; i += 4, j++) {
22
+ const a = data[i + 3] / 255;
23
+ let r = data[i];
24
+ let g = data[i + 1];
25
+ let b = data[i + 2];
26
+ if (a < 1) {
27
+ r = Math.round(r * a + 255 * (1 - a));
28
+ g = Math.round(g * a + 255 * (1 - a));
29
+ b = Math.round(b * a + 255 * (1 - a));
30
+ }
31
+ gray[j] = (r * 0.299 + g * 0.587 + b * 0.114) | 0;
32
  }
33
  return gray;
34
  },
 
44
  let min = 255;
45
  let max = 0;
46
  for (let i = 0; i < data.length; i += 4) {
47
+ const a = data[i + 3] / 255;
48
+ let r = data[i];
49
+ let g = data[i + 1];
50
+ let b = data[i + 2];
51
+ if (a < 1) {
52
+ r = Math.round(r * a + 255 * (1 - a));
53
+ g = Math.round(g * a + 255 * (1 - a));
54
+ b = Math.round(b * a + 255 * (1 - a));
55
+ }
56
+ const lum = (r * 0.299 + g * 0.587 + b * 0.114) | 0;
57
  if (lum < min) min = lum;
58
  if (lum > max) max = lum;
59
  }
60
  const range = max - min || 1;
61
  const output = new Uint8ClampedArray(data.length);
62
  for (let i = 0; i < data.length; i += 4) {
63
+ const a = data[i + 3] / 255;
64
+ let r = data[i];
65
+ let g = data[i + 1];
66
+ let b = data[i + 2];
67
+ if (a < 1) {
68
+ r = Math.round(r * a + 255 * (1 - a));
69
+ g = Math.round(g * a + 255 * (1 - a));
70
+ b = Math.round(b * a + 255 * (1 - a));
71
+ }
72
+ const val = (((r * 0.299 + g * 0.587 + b * 0.114) - min) * 255) / range;
73
  const clamped = val < 0 ? 0 : (val > 255 ? 255 : val);
74
  output[i] = clamped;
75
  output[i + 1] = clamped;
 
244
  }
245
  };
246
 
247
+ Object.freeze(VisionFilters);
248
+
249
+ try {
250
+ Object.defineProperty(global, 'FricuitVisionFilters', {
251
+ value: VisionFilters,
252
+ writable: false,
253
+ configurable: false
254
+ });
255
+ } catch (e) {
256
  global.FricuitVisionFilters = VisionFilters;
257
  }
258
 
vercel.json CHANGED
@@ -1,5 +1,30 @@
1
  {
2
  "rewrites": [
3
  { "source": "/(.*)", "destination": "/index.html" }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  ]
5
  }
 
1
  {
2
  "rewrites": [
3
  { "source": "/(.*)", "destination": "/index.html" }
4
+ ],
5
+ "headers": [
6
+ {
7
+ "source": "/(.*)",
8
+ "headers": [
9
+ { "key": "X-Frame-Options", "value": "DENY" },
10
+ { "key": "X-Content-Type-Options", "value": "nosniff" },
11
+ { "key": "X-XSS-Protection", "value": "1; mode=block" },
12
+ { "key": "Referrer-Policy", "value": "no-referrer" },
13
+ { "key": "Permissions-Policy", "value": "camera=(self), microphone=(self), geolocation=(self)" }
14
+ ]
15
+ },
16
+ {
17
+ "source": "/r8x4m9q2v7z3c6n5t0y8p4w9h2k6w.js",
18
+ "headers": [
19
+ { "key": "Cache-Control", "value": "no-cache, no-store, must-revalidate" }
20
+ ]
21
+ },
22
+ {
23
+ "source": "/manifest.json",
24
+ "headers": [
25
+ { "key": "Content-Type", "value": "application/manifest+json" },
26
+ { "key": "Cache-Control", "value": "no-cache, no-store, must-revalidate" }
27
+ ]
28
+ }
29
  ]
30
  }