@spektre/veil 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,8 @@
1
1
  import React from 'react';
2
2
  import type { SecurityGateProps } from './types';
3
3
  export declare const SecurityGate: React.FC<SecurityGateProps>;
4
+ declare global {
5
+ interface Window {
6
+ __spektreDevDisabled?: boolean;
7
+ }
8
+ }
@@ -0,0 +1,7 @@
1
+ export declare function initializeDevUI(): void;
2
+ export declare function isSpektreDisabled(): boolean;
3
+ declare global {
4
+ interface Window {
5
+ __spektreDevDisabled?: boolean;
6
+ }
7
+ }
package/dist/index.esm.js CHANGED
@@ -1,5 +1,397 @@
1
1
  import React, { createContext, useState, useEffect, useContext } from 'react';
2
2
 
3
+ const DEV_UI_STORAGE_KEY = 'spektre_dev_enabled';
4
+ // Inject styles directly into the document
5
+ function injectDevUIStyles() {
6
+ if (document.getElementById('spektre-dev-ui-styles')) {
7
+ return; // Already injected
8
+ }
9
+ const styleSheet = document.createElement('style');
10
+ styleSheet.id = 'spektre-dev-ui-styles';
11
+ styleSheet.textContent = `
12
+ /* Spektre Dev UI Dot */
13
+ .spektre-dev-dot {
14
+ position: fixed;
15
+ bottom: 24px;
16
+ right: 24px;
17
+ width: 16px;
18
+ height: 16px;
19
+ background-color: #f97316;
20
+ border-radius: 50%;
21
+ cursor: pointer;
22
+ z-index: 9998;
23
+ box-shadow: 0 4px 12px rgba(249, 115, 22, 0.4);
24
+ transition: all 0.2s ease;
25
+ outline: none;
26
+ border: none;
27
+ }
28
+
29
+ .spektre-dev-dot:hover {
30
+ width: 20px;
31
+ height: 20px;
32
+ bottom: 22px;
33
+ right: 22px;
34
+ box-shadow: 0 6px 16px rgba(249, 115, 22, 0.6);
35
+ transform: scale(1.1);
36
+ }
37
+
38
+ .spektre-dev-dot.disabled {
39
+ background-color: #64748b;
40
+ box-shadow: 0 4px 12px rgba(100, 116, 139, 0.4);
41
+ }
42
+
43
+ .spektre-dev-dot.disabled:hover {
44
+ box-shadow: 0 6px 16px rgba(100, 116, 139, 0.6);
45
+ }
46
+
47
+ /* Modal Overlay */
48
+ .spektre-dev-modal-overlay {
49
+ position: fixed;
50
+ top: 0;
51
+ left: 0;
52
+ right: 0;
53
+ bottom: 0;
54
+ background-color: rgba(0, 0, 0, 0.7);
55
+ display: flex;
56
+ align-items: center;
57
+ justify-content: center;
58
+ z-index: 9999;
59
+ animation: spektre-fade-in 0.2s ease;
60
+ }
61
+
62
+ @keyframes spektre-fade-in {
63
+ from {
64
+ opacity: 0;
65
+ }
66
+ to {
67
+ opacity: 1;
68
+ }
69
+ }
70
+
71
+ /* Modal Container */
72
+ .spektre-dev-modal {
73
+ background-color: #000000;
74
+ border: 1px solid #1e293b;
75
+ border-radius: 12px;
76
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.8);
77
+ width: 90%;
78
+ max-width: 400px;
79
+ overflow: hidden;
80
+ animation: spektre-slide-up 0.3s ease;
81
+ }
82
+
83
+ @keyframes spektre-slide-up {
84
+ from {
85
+ transform: translateY(20px);
86
+ opacity: 0;
87
+ }
88
+ to {
89
+ transform: translateY(0);
90
+ opacity: 1;
91
+ }
92
+ }
93
+
94
+ /* Modal Header */
95
+ .spektre-dev-modal-header {
96
+ display: flex;
97
+ justify-content: space-between;
98
+ align-items: center;
99
+ padding: 20px;
100
+ border-bottom: 1px solid #1e293b;
101
+ background: linear-gradient(135deg, rgba(249, 115, 22, 0.1) 0%, rgba(0, 0, 0, 0.5) 100%);
102
+ }
103
+
104
+ .spektre-dev-modal-header h2 {
105
+ margin: 0;
106
+ font-size: 18px;
107
+ font-weight: 600;
108
+ color: #ffffff;
109
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
110
+ }
111
+
112
+ .spektre-dev-modal-close {
113
+ background: none;
114
+ border: none;
115
+ color: #94a3b8;
116
+ font-size: 24px;
117
+ cursor: pointer;
118
+ padding: 0;
119
+ width: 28px;
120
+ height: 28px;
121
+ display: flex;
122
+ align-items: center;
123
+ justify-content: center;
124
+ transition: color 0.2s ease;
125
+ border-radius: 4px;
126
+ }
127
+
128
+ .spektre-dev-modal-close:hover {
129
+ color: #f97316;
130
+ background-color: rgba(249, 115, 22, 0.1);
131
+ }
132
+
133
+ /* Modal Body */
134
+ .spektre-dev-modal-body {
135
+ padding: 24px;
136
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
137
+ }
138
+
139
+ .spektre-dev-modal-info {
140
+ margin: 0 0 16px 0;
141
+ font-size: 14px;
142
+ color: #cbd5e1;
143
+ line-height: 1.5;
144
+ }
145
+
146
+ /* Status Badge */
147
+ .spektre-dev-modal-status {
148
+ display: inline-block;
149
+ padding: 8px 12px;
150
+ border-radius: 6px;
151
+ font-size: 14px;
152
+ font-weight: 500;
153
+ margin-bottom: 20px;
154
+ font-family: monospace;
155
+ transition: all 0.2s ease;
156
+ }
157
+
158
+ .spektre-dev-modal-status.enabled {
159
+ background-color: rgba(34, 197, 94, 0.15);
160
+ color: #86efac;
161
+ border: 1px solid rgba(34, 197, 94, 0.3);
162
+ }
163
+
164
+ .spektre-dev-modal-status.disabled {
165
+ background-color: rgba(100, 116, 139, 0.15);
166
+ color: #cbd5e1;
167
+ border: 1px solid rgba(100, 116, 139, 0.3);
168
+ }
169
+
170
+ /* Toggle Container */
171
+ .spektre-dev-modal-toggle-container {
172
+ display: flex;
173
+ align-items: center;
174
+ margin-bottom: 16px;
175
+ }
176
+
177
+ .spektre-dev-toggle-label {
178
+ display: flex;
179
+ align-items: center;
180
+ gap: 12px;
181
+ cursor: pointer;
182
+ font-size: 14px;
183
+ color: #e2e8f0;
184
+ user-select: none;
185
+ }
186
+
187
+ /* Toggle Switch */
188
+ .spektre-dev-toggle {
189
+ appearance: none;
190
+ -webkit-appearance: none;
191
+ width: 44px;
192
+ height: 24px;
193
+ background-color: #1e293b;
194
+ border: 1px solid #334155;
195
+ border-radius: 12px;
196
+ cursor: pointer;
197
+ position: relative;
198
+ transition: all 0.3s ease;
199
+ padding: 2px;
200
+ flex-shrink: 0;
201
+ }
202
+
203
+ .spektre-dev-toggle:checked {
204
+ background-color: #f97316;
205
+ border-color: #f97316;
206
+ }
207
+
208
+ .spektre-dev-toggle::before {
209
+ content: '';
210
+ position: absolute;
211
+ width: 18px;
212
+ height: 18px;
213
+ background-color: white;
214
+ border-radius: 10px;
215
+ top: 3px;
216
+ left: 3px;
217
+ transition: left 0.3s ease;
218
+ }
219
+
220
+ .spektre-dev-toggle:checked::before {
221
+ left: 23px;
222
+ }
223
+
224
+ .spektre-dev-toggle:focus {
225
+ outline: none;
226
+ box-shadow: 0 0 0 3px rgba(249, 115, 22, 0.2);
227
+ }
228
+
229
+ /* Reload Message */
230
+ .spektre-dev-modal-reload-msg {
231
+ margin: 0;
232
+ padding: 12px;
233
+ background-color: rgba(249, 115, 22, 0.15);
234
+ border: 1px solid rgba(249, 115, 22, 0.3);
235
+ border-radius: 6px;
236
+ font-size: 13px;
237
+ color: #fed7aa;
238
+ text-align: center;
239
+ transition: opacity 0.2s ease;
240
+ font-weight: 500;
241
+ }
242
+
243
+ /* Accessibility */
244
+ @media (prefers-reduced-motion: reduce) {
245
+ .spektre-dev-dot,
246
+ .spektre-dev-modal-overlay,
247
+ .spektre-dev-modal,
248
+ .spektre-dev-toggle,
249
+ .spektre-dev-toggle::before {
250
+ animation: none;
251
+ transition: none;
252
+ }
253
+ }
254
+
255
+ /* Mobile responsiveness */
256
+ @media (max-width: 480px) {
257
+ .spektre-dev-dot {
258
+ bottom: 16px;
259
+ right: 16px;
260
+ width: 14px;
261
+ height: 14px;
262
+ }
263
+
264
+ .spektre-dev-dot:hover {
265
+ width: 18px;
266
+ height: 18px;
267
+ bottom: 14px;
268
+ right: 14px;
269
+ }
270
+
271
+ .spektre-dev-modal {
272
+ width: 85%;
273
+ max-width: 320px;
274
+ }
275
+
276
+ .spektre-dev-modal-header h2 {
277
+ font-size: 16px;
278
+ }
279
+
280
+ .spektre-dev-modal-body {
281
+ padding: 16px;
282
+ }
283
+ }
284
+ `;
285
+ document.head.appendChild(styleSheet);
286
+ }
287
+ function initializeDevUI() {
288
+ // Inject styles first
289
+ injectDevUIStyles();
290
+ // Check if Spektre is enabled in localStorage (default to true)
291
+ const isEnabled = localStorage.getItem(DEV_UI_STORAGE_KEY);
292
+ const spektreEnabled = isEnabled === null ? true : isEnabled === 'true';
293
+ // If disabled, prevent core Spektre from initializing
294
+ if (!spektreEnabled) {
295
+ window.__spektreDevDisabled = true;
296
+ }
297
+ // Create and inject the orange dot
298
+ createDevDot();
299
+ }
300
+ function createDevDot() {
301
+ const dot = document.createElement('div');
302
+ dot.id = 'spektre-dev-dot';
303
+ dot.className = 'spektre-dev-dot';
304
+ dot.setAttribute('aria-label', 'Spektre development environment controls');
305
+ dot.addEventListener('click', () => {
306
+ openDevModal();
307
+ });
308
+ document.body.appendChild(dot);
309
+ }
310
+ function openDevModal() {
311
+ // Check if modal already exists
312
+ if (document.getElementById('spektre-dev-modal')) {
313
+ return;
314
+ }
315
+ const isEnabled = localStorage.getItem(DEV_UI_STORAGE_KEY) !== 'false';
316
+ const modal = document.createElement('div');
317
+ modal.id = 'spektre-dev-modal';
318
+ modal.className = 'spektre-dev-modal-overlay';
319
+ const modalContent = document.createElement('div');
320
+ modalContent.className = 'spektre-dev-modal';
321
+ const header = document.createElement('div');
322
+ header.className = 'spektre-dev-modal-header';
323
+ header.innerHTML = '<h2>Spektre Development Mode</h2>';
324
+ const closeButton = document.createElement('button');
325
+ closeButton.className = 'spektre-dev-modal-close';
326
+ closeButton.innerHTML = '✕';
327
+ closeButton.setAttribute('aria-label', 'Close modal');
328
+ closeButton.addEventListener('click', () => {
329
+ modal.remove();
330
+ });
331
+ header.appendChild(closeButton);
332
+ const body = document.createElement('div');
333
+ body.className = 'spektre-dev-modal-body';
334
+ const infoText = document.createElement('p');
335
+ infoText.className = 'spektre-dev-modal-info';
336
+ infoText.textContent = 'You are in a development environment. Spektre is currently:';
337
+ const statusBadge = document.createElement('div');
338
+ statusBadge.className = `spektre-dev-modal-status ${isEnabled ? 'enabled' : 'disabled'}`;
339
+ statusBadge.textContent = isEnabled ? '● Enabled' : '● Disabled';
340
+ const toggleContainer = document.createElement('div');
341
+ toggleContainer.className = 'spektre-dev-modal-toggle-container';
342
+ const toggleLabel = document.createElement('label');
343
+ toggleLabel.className = 'spektre-dev-toggle-label';
344
+ const toggleSwitch = document.createElement('input');
345
+ toggleSwitch.type = 'checkbox';
346
+ toggleSwitch.className = 'spektre-dev-toggle';
347
+ toggleSwitch.checked = isEnabled;
348
+ toggleSwitch.setAttribute('aria-label', 'Toggle Spektre');
349
+ toggleSwitch.addEventListener('change', (e) => {
350
+ const enabled = e.target.checked;
351
+ localStorage.setItem(DEV_UI_STORAGE_KEY, String(enabled));
352
+ // Update status badge
353
+ statusBadge.className = `spektre-dev-modal-status ${enabled ? 'enabled' : 'disabled'}`;
354
+ statusBadge.textContent = enabled ? '● Enabled' : '● Disabled';
355
+ // Update dot visual
356
+ const dot = document.getElementById('spektre-dev-dot');
357
+ if (dot) {
358
+ dot.classList.toggle('disabled', !enabled);
359
+ }
360
+ // Show reload message
361
+ const reloadMsg = document.querySelector('.spektre-dev-modal-reload-msg');
362
+ if (reloadMsg) {
363
+ reloadMsg.textContent = 'Reload the page for changes to take effect';
364
+ reloadMsg.style.opacity = '1';
365
+ }
366
+ });
367
+ toggleLabel.appendChild(toggleSwitch);
368
+ toggleLabel.appendChild(document.createTextNode('Enable Spektre'));
369
+ toggleContainer.appendChild(toggleLabel);
370
+ const reloadMessage = document.createElement('p');
371
+ reloadMessage.className = 'spektre-dev-modal-reload-msg';
372
+ reloadMessage.style.opacity = '0';
373
+ body.appendChild(infoText);
374
+ body.appendChild(statusBadge);
375
+ body.appendChild(toggleContainer);
376
+ body.appendChild(reloadMessage);
377
+ modalContent.appendChild(header);
378
+ modalContent.appendChild(body);
379
+ modal.appendChild(modalContent);
380
+ // Close on overlay click
381
+ modal.addEventListener('click', (e) => {
382
+ if (e.target === modal) {
383
+ modal.remove();
384
+ }
385
+ });
386
+ // Close on escape key
387
+ document.addEventListener('keydown', (e) => {
388
+ if (e.key === 'Escape' && document.getElementById('spektre-dev-modal')) {
389
+ modal.remove();
390
+ }
391
+ }, { once: true });
392
+ document.body.appendChild(modal);
393
+ }
394
+
3
395
  const SpektreContext = createContext(null);
4
396
  SpektreContext.displayName = 'SpektreContext';
5
397
 
@@ -16,6 +408,16 @@ const SecurityGate = ({ apiKey, children, config, fallback, loadingComponent, })
16
408
  sessionId: null,
17
409
  });
18
410
  useEffect(() => {
411
+ // Check if Spektre is disabled in dev mode
412
+ if (window.__spektreDevDisabled) {
413
+ setState({
414
+ isVerified: true,
415
+ isLoading: false,
416
+ error: null,
417
+ sessionId: 'dev-disabled',
418
+ });
419
+ return;
420
+ }
19
421
  // Set tampering detection marker
20
422
  sessionStorage.setItem('spektre_js_enabled', 'true');
21
423
  sessionStorage.setItem('spektre_init_time', Date.now().toString());
@@ -430,5 +832,10 @@ const useProtectedFetch = () => {
430
832
  return protectedFetch;
431
833
  };
432
834
 
835
+ // Check if we're in an iframe (development environment) and initialize dev UI
836
+ if (typeof window !== 'undefined' && window.self !== window.top) {
837
+ initializeDevUI();
838
+ }
839
+
433
840
  export { SecurityGate, SpektreContext, SpektreProvider, useProtectedFetch, useSpektre };
434
841
  //# sourceMappingURL=index.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/index.js CHANGED
@@ -2,6 +2,398 @@
2
2
 
3
3
  var React = require('react');
4
4
 
5
+ const DEV_UI_STORAGE_KEY = 'spektre_dev_enabled';
6
+ // Inject styles directly into the document
7
+ function injectDevUIStyles() {
8
+ if (document.getElementById('spektre-dev-ui-styles')) {
9
+ return; // Already injected
10
+ }
11
+ const styleSheet = document.createElement('style');
12
+ styleSheet.id = 'spektre-dev-ui-styles';
13
+ styleSheet.textContent = `
14
+ /* Spektre Dev UI Dot */
15
+ .spektre-dev-dot {
16
+ position: fixed;
17
+ bottom: 24px;
18
+ right: 24px;
19
+ width: 16px;
20
+ height: 16px;
21
+ background-color: #f97316;
22
+ border-radius: 50%;
23
+ cursor: pointer;
24
+ z-index: 9998;
25
+ box-shadow: 0 4px 12px rgba(249, 115, 22, 0.4);
26
+ transition: all 0.2s ease;
27
+ outline: none;
28
+ border: none;
29
+ }
30
+
31
+ .spektre-dev-dot:hover {
32
+ width: 20px;
33
+ height: 20px;
34
+ bottom: 22px;
35
+ right: 22px;
36
+ box-shadow: 0 6px 16px rgba(249, 115, 22, 0.6);
37
+ transform: scale(1.1);
38
+ }
39
+
40
+ .spektre-dev-dot.disabled {
41
+ background-color: #64748b;
42
+ box-shadow: 0 4px 12px rgba(100, 116, 139, 0.4);
43
+ }
44
+
45
+ .spektre-dev-dot.disabled:hover {
46
+ box-shadow: 0 6px 16px rgba(100, 116, 139, 0.6);
47
+ }
48
+
49
+ /* Modal Overlay */
50
+ .spektre-dev-modal-overlay {
51
+ position: fixed;
52
+ top: 0;
53
+ left: 0;
54
+ right: 0;
55
+ bottom: 0;
56
+ background-color: rgba(0, 0, 0, 0.7);
57
+ display: flex;
58
+ align-items: center;
59
+ justify-content: center;
60
+ z-index: 9999;
61
+ animation: spektre-fade-in 0.2s ease;
62
+ }
63
+
64
+ @keyframes spektre-fade-in {
65
+ from {
66
+ opacity: 0;
67
+ }
68
+ to {
69
+ opacity: 1;
70
+ }
71
+ }
72
+
73
+ /* Modal Container */
74
+ .spektre-dev-modal {
75
+ background-color: #000000;
76
+ border: 1px solid #1e293b;
77
+ border-radius: 12px;
78
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.8);
79
+ width: 90%;
80
+ max-width: 400px;
81
+ overflow: hidden;
82
+ animation: spektre-slide-up 0.3s ease;
83
+ }
84
+
85
+ @keyframes spektre-slide-up {
86
+ from {
87
+ transform: translateY(20px);
88
+ opacity: 0;
89
+ }
90
+ to {
91
+ transform: translateY(0);
92
+ opacity: 1;
93
+ }
94
+ }
95
+
96
+ /* Modal Header */
97
+ .spektre-dev-modal-header {
98
+ display: flex;
99
+ justify-content: space-between;
100
+ align-items: center;
101
+ padding: 20px;
102
+ border-bottom: 1px solid #1e293b;
103
+ background: linear-gradient(135deg, rgba(249, 115, 22, 0.1) 0%, rgba(0, 0, 0, 0.5) 100%);
104
+ }
105
+
106
+ .spektre-dev-modal-header h2 {
107
+ margin: 0;
108
+ font-size: 18px;
109
+ font-weight: 600;
110
+ color: #ffffff;
111
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
112
+ }
113
+
114
+ .spektre-dev-modal-close {
115
+ background: none;
116
+ border: none;
117
+ color: #94a3b8;
118
+ font-size: 24px;
119
+ cursor: pointer;
120
+ padding: 0;
121
+ width: 28px;
122
+ height: 28px;
123
+ display: flex;
124
+ align-items: center;
125
+ justify-content: center;
126
+ transition: color 0.2s ease;
127
+ border-radius: 4px;
128
+ }
129
+
130
+ .spektre-dev-modal-close:hover {
131
+ color: #f97316;
132
+ background-color: rgba(249, 115, 22, 0.1);
133
+ }
134
+
135
+ /* Modal Body */
136
+ .spektre-dev-modal-body {
137
+ padding: 24px;
138
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
139
+ }
140
+
141
+ .spektre-dev-modal-info {
142
+ margin: 0 0 16px 0;
143
+ font-size: 14px;
144
+ color: #cbd5e1;
145
+ line-height: 1.5;
146
+ }
147
+
148
+ /* Status Badge */
149
+ .spektre-dev-modal-status {
150
+ display: inline-block;
151
+ padding: 8px 12px;
152
+ border-radius: 6px;
153
+ font-size: 14px;
154
+ font-weight: 500;
155
+ margin-bottom: 20px;
156
+ font-family: monospace;
157
+ transition: all 0.2s ease;
158
+ }
159
+
160
+ .spektre-dev-modal-status.enabled {
161
+ background-color: rgba(34, 197, 94, 0.15);
162
+ color: #86efac;
163
+ border: 1px solid rgba(34, 197, 94, 0.3);
164
+ }
165
+
166
+ .spektre-dev-modal-status.disabled {
167
+ background-color: rgba(100, 116, 139, 0.15);
168
+ color: #cbd5e1;
169
+ border: 1px solid rgba(100, 116, 139, 0.3);
170
+ }
171
+
172
+ /* Toggle Container */
173
+ .spektre-dev-modal-toggle-container {
174
+ display: flex;
175
+ align-items: center;
176
+ margin-bottom: 16px;
177
+ }
178
+
179
+ .spektre-dev-toggle-label {
180
+ display: flex;
181
+ align-items: center;
182
+ gap: 12px;
183
+ cursor: pointer;
184
+ font-size: 14px;
185
+ color: #e2e8f0;
186
+ user-select: none;
187
+ }
188
+
189
+ /* Toggle Switch */
190
+ .spektre-dev-toggle {
191
+ appearance: none;
192
+ -webkit-appearance: none;
193
+ width: 44px;
194
+ height: 24px;
195
+ background-color: #1e293b;
196
+ border: 1px solid #334155;
197
+ border-radius: 12px;
198
+ cursor: pointer;
199
+ position: relative;
200
+ transition: all 0.3s ease;
201
+ padding: 2px;
202
+ flex-shrink: 0;
203
+ }
204
+
205
+ .spektre-dev-toggle:checked {
206
+ background-color: #f97316;
207
+ border-color: #f97316;
208
+ }
209
+
210
+ .spektre-dev-toggle::before {
211
+ content: '';
212
+ position: absolute;
213
+ width: 18px;
214
+ height: 18px;
215
+ background-color: white;
216
+ border-radius: 10px;
217
+ top: 3px;
218
+ left: 3px;
219
+ transition: left 0.3s ease;
220
+ }
221
+
222
+ .spektre-dev-toggle:checked::before {
223
+ left: 23px;
224
+ }
225
+
226
+ .spektre-dev-toggle:focus {
227
+ outline: none;
228
+ box-shadow: 0 0 0 3px rgba(249, 115, 22, 0.2);
229
+ }
230
+
231
+ /* Reload Message */
232
+ .spektre-dev-modal-reload-msg {
233
+ margin: 0;
234
+ padding: 12px;
235
+ background-color: rgba(249, 115, 22, 0.15);
236
+ border: 1px solid rgba(249, 115, 22, 0.3);
237
+ border-radius: 6px;
238
+ font-size: 13px;
239
+ color: #fed7aa;
240
+ text-align: center;
241
+ transition: opacity 0.2s ease;
242
+ font-weight: 500;
243
+ }
244
+
245
+ /* Accessibility */
246
+ @media (prefers-reduced-motion: reduce) {
247
+ .spektre-dev-dot,
248
+ .spektre-dev-modal-overlay,
249
+ .spektre-dev-modal,
250
+ .spektre-dev-toggle,
251
+ .spektre-dev-toggle::before {
252
+ animation: none;
253
+ transition: none;
254
+ }
255
+ }
256
+
257
+ /* Mobile responsiveness */
258
+ @media (max-width: 480px) {
259
+ .spektre-dev-dot {
260
+ bottom: 16px;
261
+ right: 16px;
262
+ width: 14px;
263
+ height: 14px;
264
+ }
265
+
266
+ .spektre-dev-dot:hover {
267
+ width: 18px;
268
+ height: 18px;
269
+ bottom: 14px;
270
+ right: 14px;
271
+ }
272
+
273
+ .spektre-dev-modal {
274
+ width: 85%;
275
+ max-width: 320px;
276
+ }
277
+
278
+ .spektre-dev-modal-header h2 {
279
+ font-size: 16px;
280
+ }
281
+
282
+ .spektre-dev-modal-body {
283
+ padding: 16px;
284
+ }
285
+ }
286
+ `;
287
+ document.head.appendChild(styleSheet);
288
+ }
289
+ function initializeDevUI() {
290
+ // Inject styles first
291
+ injectDevUIStyles();
292
+ // Check if Spektre is enabled in localStorage (default to true)
293
+ const isEnabled = localStorage.getItem(DEV_UI_STORAGE_KEY);
294
+ const spektreEnabled = isEnabled === null ? true : isEnabled === 'true';
295
+ // If disabled, prevent core Spektre from initializing
296
+ if (!spektreEnabled) {
297
+ window.__spektreDevDisabled = true;
298
+ }
299
+ // Create and inject the orange dot
300
+ createDevDot();
301
+ }
302
+ function createDevDot() {
303
+ const dot = document.createElement('div');
304
+ dot.id = 'spektre-dev-dot';
305
+ dot.className = 'spektre-dev-dot';
306
+ dot.setAttribute('aria-label', 'Spektre development environment controls');
307
+ dot.addEventListener('click', () => {
308
+ openDevModal();
309
+ });
310
+ document.body.appendChild(dot);
311
+ }
312
+ function openDevModal() {
313
+ // Check if modal already exists
314
+ if (document.getElementById('spektre-dev-modal')) {
315
+ return;
316
+ }
317
+ const isEnabled = localStorage.getItem(DEV_UI_STORAGE_KEY) !== 'false';
318
+ const modal = document.createElement('div');
319
+ modal.id = 'spektre-dev-modal';
320
+ modal.className = 'spektre-dev-modal-overlay';
321
+ const modalContent = document.createElement('div');
322
+ modalContent.className = 'spektre-dev-modal';
323
+ const header = document.createElement('div');
324
+ header.className = 'spektre-dev-modal-header';
325
+ header.innerHTML = '<h2>Spektre Development Mode</h2>';
326
+ const closeButton = document.createElement('button');
327
+ closeButton.className = 'spektre-dev-modal-close';
328
+ closeButton.innerHTML = '✕';
329
+ closeButton.setAttribute('aria-label', 'Close modal');
330
+ closeButton.addEventListener('click', () => {
331
+ modal.remove();
332
+ });
333
+ header.appendChild(closeButton);
334
+ const body = document.createElement('div');
335
+ body.className = 'spektre-dev-modal-body';
336
+ const infoText = document.createElement('p');
337
+ infoText.className = 'spektre-dev-modal-info';
338
+ infoText.textContent = 'You are in a development environment. Spektre is currently:';
339
+ const statusBadge = document.createElement('div');
340
+ statusBadge.className = `spektre-dev-modal-status ${isEnabled ? 'enabled' : 'disabled'}`;
341
+ statusBadge.textContent = isEnabled ? '● Enabled' : '● Disabled';
342
+ const toggleContainer = document.createElement('div');
343
+ toggleContainer.className = 'spektre-dev-modal-toggle-container';
344
+ const toggleLabel = document.createElement('label');
345
+ toggleLabel.className = 'spektre-dev-toggle-label';
346
+ const toggleSwitch = document.createElement('input');
347
+ toggleSwitch.type = 'checkbox';
348
+ toggleSwitch.className = 'spektre-dev-toggle';
349
+ toggleSwitch.checked = isEnabled;
350
+ toggleSwitch.setAttribute('aria-label', 'Toggle Spektre');
351
+ toggleSwitch.addEventListener('change', (e) => {
352
+ const enabled = e.target.checked;
353
+ localStorage.setItem(DEV_UI_STORAGE_KEY, String(enabled));
354
+ // Update status badge
355
+ statusBadge.className = `spektre-dev-modal-status ${enabled ? 'enabled' : 'disabled'}`;
356
+ statusBadge.textContent = enabled ? '● Enabled' : '● Disabled';
357
+ // Update dot visual
358
+ const dot = document.getElementById('spektre-dev-dot');
359
+ if (dot) {
360
+ dot.classList.toggle('disabled', !enabled);
361
+ }
362
+ // Show reload message
363
+ const reloadMsg = document.querySelector('.spektre-dev-modal-reload-msg');
364
+ if (reloadMsg) {
365
+ reloadMsg.textContent = 'Reload the page for changes to take effect';
366
+ reloadMsg.style.opacity = '1';
367
+ }
368
+ });
369
+ toggleLabel.appendChild(toggleSwitch);
370
+ toggleLabel.appendChild(document.createTextNode('Enable Spektre'));
371
+ toggleContainer.appendChild(toggleLabel);
372
+ const reloadMessage = document.createElement('p');
373
+ reloadMessage.className = 'spektre-dev-modal-reload-msg';
374
+ reloadMessage.style.opacity = '0';
375
+ body.appendChild(infoText);
376
+ body.appendChild(statusBadge);
377
+ body.appendChild(toggleContainer);
378
+ body.appendChild(reloadMessage);
379
+ modalContent.appendChild(header);
380
+ modalContent.appendChild(body);
381
+ modal.appendChild(modalContent);
382
+ // Close on overlay click
383
+ modal.addEventListener('click', (e) => {
384
+ if (e.target === modal) {
385
+ modal.remove();
386
+ }
387
+ });
388
+ // Close on escape key
389
+ document.addEventListener('keydown', (e) => {
390
+ if (e.key === 'Escape' && document.getElementById('spektre-dev-modal')) {
391
+ modal.remove();
392
+ }
393
+ }, { once: true });
394
+ document.body.appendChild(modal);
395
+ }
396
+
5
397
  const SpektreContext = React.createContext(null);
6
398
  SpektreContext.displayName = 'SpektreContext';
7
399
 
@@ -18,6 +410,16 @@ const SecurityGate = ({ apiKey, children, config, fallback, loadingComponent, })
18
410
  sessionId: null,
19
411
  });
20
412
  React.useEffect(() => {
413
+ // Check if Spektre is disabled in dev mode
414
+ if (window.__spektreDevDisabled) {
415
+ setState({
416
+ isVerified: true,
417
+ isLoading: false,
418
+ error: null,
419
+ sessionId: 'dev-disabled',
420
+ });
421
+ return;
422
+ }
21
423
  // Set tampering detection marker
22
424
  sessionStorage.setItem('spektre_js_enabled', 'true');
23
425
  sessionStorage.setItem('spektre_init_time', Date.now().toString());
@@ -432,6 +834,11 @@ const useProtectedFetch = () => {
432
834
  return protectedFetch;
433
835
  };
434
836
 
837
+ // Check if we're in an iframe (development environment) and initialize dev UI
838
+ if (typeof window !== 'undefined' && window.self !== window.top) {
839
+ initializeDevUI();
840
+ }
841
+
435
842
  exports.SecurityGate = SecurityGate;
436
843
  exports.SpektreContext = SpektreContext;
437
844
  exports.SpektreProvider = SpektreProvider;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spektre/veil",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "type": "module",
5
5
  "description": "Security and monitoring wrapper for React apps built with AI tools",
6
6
  "main": "dist/index.js",