pulse-js-framework 1.7.32 → 1.7.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,282 @@
1
+ /**
2
+ * Pulse Framework - Native Mobile Bridge Type Definitions
3
+ * @module pulse-js-framework/runtime/native
4
+ */
5
+
6
+ import { Pulse } from './pulse';
7
+
8
+ // ============================================================================
9
+ // Types
10
+ // ============================================================================
11
+
12
+ /** Supported platform identifiers */
13
+ export type Platform = 'ios' | 'android' | 'web';
14
+
15
+ /** Network connectivity status */
16
+ export interface NetworkStatus {
17
+ connected: boolean;
18
+ type: string;
19
+ }
20
+
21
+ /** Device information data */
22
+ export interface DeviceInfoData {
23
+ platform: string;
24
+ userAgent: string;
25
+ language: string;
26
+ [key: string]: unknown;
27
+ }
28
+
29
+ // ============================================================================
30
+ // Interfaces
31
+ // ============================================================================
32
+
33
+ /** Reactive native storage with automatic persistence */
34
+ export interface NativeStorage {
35
+ /**
36
+ * Get a reactive value from native storage.
37
+ * Returns a Pulse signal that auto-persists changes.
38
+ *
39
+ * @param key - Storage key
40
+ * @param defaultValue - Default value if key not found
41
+ * @returns A Pulse that syncs with native storage
42
+ *
43
+ * @example
44
+ * const storage = createNativeStorage('app_');
45
+ * const theme = storage.get('theme', 'light');
46
+ * theme.set('dark'); // Auto-saves to storage
47
+ */
48
+ get<T = unknown>(key: string, defaultValue?: T): Pulse<T>;
49
+
50
+ /**
51
+ * Remove a value from storage
52
+ *
53
+ * @param key - Storage key to remove
54
+ */
55
+ remove(key: string): Promise<void>;
56
+
57
+ /**
58
+ * Clear all storage entries with the configured prefix
59
+ */
60
+ clear(): Promise<void>;
61
+ }
62
+
63
+ /** Reactive device information */
64
+ export interface DeviceInfo {
65
+ /** Device info as a reactive Pulse */
66
+ info: Pulse<DeviceInfoData | null>;
67
+
68
+ /** Network status as a reactive Pulse */
69
+ network: Pulse<NetworkStatus>;
70
+
71
+ /** Current platform */
72
+ readonly platform: Platform;
73
+
74
+ /** Whether running in a native app */
75
+ readonly isNative: boolean;
76
+
77
+ /** Whether the device is currently online */
78
+ readonly isOnline: boolean;
79
+ }
80
+
81
+ // ============================================================================
82
+ // Functions
83
+ // ============================================================================
84
+
85
+ /**
86
+ * Check if PulseMobile bridge is available and valid.
87
+ *
88
+ * Security: This function validates the bridge structure, version,
89
+ * and API surface before returning true. Malicious or malformed
90
+ * bridges will be rejected.
91
+ *
92
+ * @returns True if a valid PulseMobile bridge is available
93
+ */
94
+ export declare function isNativeAvailable(): boolean;
95
+
96
+ /**
97
+ * Get the PulseMobile instance (validated).
98
+ *
99
+ * @throws {Error} If bridge is not available or validation failed
100
+ * @returns The validated PulseMobile bridge object
101
+ */
102
+ export declare function getNative(): object;
103
+
104
+ /**
105
+ * Get current platform.
106
+ *
107
+ * @returns 'ios', 'android', or 'web'
108
+ */
109
+ export declare function getPlatform(): Platform;
110
+
111
+ /**
112
+ * Check if running in a native environment.
113
+ *
114
+ * @returns True if running inside a Pulse native mobile app
115
+ */
116
+ export declare function isNative(): boolean;
117
+
118
+ /**
119
+ * Create reactive native storage.
120
+ * Syncs between native storage and Pulse reactivity system.
121
+ * Falls back to localStorage on web.
122
+ *
123
+ * @param prefix - Key prefix for all storage operations (default: '')
124
+ * @returns A NativeStorage instance with reactive get, remove, and clear methods
125
+ *
126
+ * @example
127
+ * const storage = createNativeStorage('app_');
128
+ * const theme = storage.get('theme', 'light');
129
+ * theme.set('dark'); // Auto-persists to storage
130
+ * await storage.remove('theme');
131
+ * await storage.clear();
132
+ */
133
+ export declare function createNativeStorage(prefix?: string): NativeStorage;
134
+
135
+ /**
136
+ * Create reactive device info.
137
+ * Provides platform, network status, and device details as reactive Pulses.
138
+ *
139
+ * @returns A DeviceInfo object with reactive properties
140
+ *
141
+ * @example
142
+ * const device = createDeviceInfo();
143
+ * device.info.get(); // { platform, userAgent, language, ... }
144
+ * device.network.get(); // { connected: true, type: 'wifi' }
145
+ * device.isOnline; // true/false
146
+ * device.platform; // 'ios' | 'android' | 'web'
147
+ */
148
+ export declare function createDeviceInfo(): DeviceInfo;
149
+
150
+ /**
151
+ * Register a callback for when the app is paused/backgrounded.
152
+ * On web, this listens for visibilitychange events.
153
+ *
154
+ * @param callback - Function to call when app is paused
155
+ */
156
+ export declare function onAppPause(callback: () => void): void;
157
+
158
+ /**
159
+ * Register a callback for when the app is resumed/foregrounded.
160
+ * On web, this listens for visibilitychange events.
161
+ *
162
+ * @param callback - Function to call when app is resumed
163
+ */
164
+ export declare function onAppResume(callback: () => void): void;
165
+
166
+ /**
167
+ * Register a callback for the Android back button.
168
+ * Only works in native Android environments.
169
+ *
170
+ * @param callback - Function to call when back button is pressed
171
+ */
172
+ export declare function onBackButton(callback: () => void): void;
173
+
174
+ /**
175
+ * Register a callback for when the native bridge is ready.
176
+ * If the bridge is already ready, the callback is called asynchronously.
177
+ *
178
+ * @param callback - Function to call with platform details
179
+ *
180
+ * @example
181
+ * onNativeReady(({ platform }) => {
182
+ * console.log('Native ready on', platform);
183
+ * });
184
+ */
185
+ export declare function onNativeReady(callback: (detail: { platform: Platform }) => void): void;
186
+
187
+ /**
188
+ * Exit the app (Android only).
189
+ * Logs a warning on non-Android platforms.
190
+ *
191
+ * @returns Promise that resolves when the app exits
192
+ */
193
+ export declare function exitApp(): Promise<void>;
194
+
195
+ /**
196
+ * Minimize the app.
197
+ * Only works in native environments.
198
+ *
199
+ * @returns Promise that resolves when the app is minimized
200
+ */
201
+ export declare function minimizeApp(): Promise<void>;
202
+
203
+ /**
204
+ * Clear the bridge validation cache.
205
+ * Useful for testing or after bridge changes.
206
+ */
207
+ export declare function clearBridgeValidationCache(): void;
208
+
209
+ /**
210
+ * Get the last bridge validation error (if any).
211
+ *
212
+ * @returns The validation error message, or null if validation passed
213
+ */
214
+ export declare function getBridgeValidationError(): string | null;
215
+
216
+ // ============================================================================
217
+ // Constants
218
+ // ============================================================================
219
+
220
+ /** Native UI helpers (toast, vibration) */
221
+ export declare const NativeUI: {
222
+ /**
223
+ * Show a toast message.
224
+ * Falls back to console logging on web.
225
+ *
226
+ * @param message - Toast message text
227
+ * @param isLong - Whether to show a long-duration toast (default: false)
228
+ */
229
+ toast(message: string, isLong?: boolean): Promise<void>;
230
+
231
+ /**
232
+ * Trigger haptic feedback / vibration.
233
+ * Falls back to navigator.vibrate on web.
234
+ *
235
+ * @param duration - Vibration duration in ms (default: 100)
236
+ */
237
+ vibrate(duration?: number): Promise<void>;
238
+ };
239
+
240
+ /** Native clipboard helpers */
241
+ export declare const NativeClipboard: {
242
+ /**
243
+ * Copy text to clipboard.
244
+ * Falls back to navigator.clipboard on web.
245
+ *
246
+ * @param text - Text to copy
247
+ */
248
+ copy(text: string): Promise<void>;
249
+
250
+ /**
251
+ * Read text from clipboard.
252
+ * Falls back to navigator.clipboard on web.
253
+ *
254
+ * @returns The clipboard text content
255
+ */
256
+ read(): Promise<string>;
257
+ };
258
+
259
+ // ============================================================================
260
+ // Default Export
261
+ // ============================================================================
262
+
263
+ declare const native: {
264
+ isNativeAvailable: typeof isNativeAvailable;
265
+ getNative: typeof getNative;
266
+ getPlatform: typeof getPlatform;
267
+ isNative: typeof isNative;
268
+ createNativeStorage: typeof createNativeStorage;
269
+ createDeviceInfo: typeof createDeviceInfo;
270
+ NativeUI: typeof NativeUI;
271
+ NativeClipboard: typeof NativeClipboard;
272
+ onAppPause: typeof onAppPause;
273
+ onAppResume: typeof onAppResume;
274
+ onBackButton: typeof onBackButton;
275
+ onNativeReady: typeof onNativeReady;
276
+ exitApp: typeof exitApp;
277
+ minimizeApp: typeof minimizeApp;
278
+ clearBridgeValidationCache: typeof clearBridgeValidationCache;
279
+ getBridgeValidationError: typeof getBridgeValidationError;
280
+ };
281
+
282
+ export default native;
package/types/pulse.d.ts CHANGED
@@ -172,11 +172,80 @@ export interface ReactiveContext {
172
172
 
173
173
  /**
174
174
  * Global reactive context
175
+ * @deprecated Use globalContext instead
175
176
  */
176
- export declare const context: ReactiveContext;
177
+ export declare const context: ReactiveContextClass;
178
+
179
+ /**
180
+ * Global reactive context instance
181
+ */
182
+ export declare const globalContext: ReactiveContextClass;
183
+
184
+ /**
185
+ * Reactive context class for isolated state management (testing, SSR)
186
+ */
187
+ export declare class ReactiveContextClass {
188
+ readonly name: string;
189
+ currentEffect: EffectFn | null;
190
+ batchDepth: number;
191
+ pendingEffects: Set<EffectFn>;
192
+ isRunningEffects: boolean;
193
+
194
+ constructor(options?: { name?: string });
195
+
196
+ /** Run a function within this context */
197
+ run<T>(fn: () => T): T;
198
+
199
+ /** Reset context to initial state */
200
+ reset(): void;
201
+ }
177
202
 
178
203
  /**
179
204
  * Reset the reactive context to initial state.
180
205
  * Use this in tests to ensure isolation between test cases.
181
206
  */
182
207
  export declare function resetContext(): void;
208
+
209
+ /**
210
+ * Create an isolated reactive context for testing or SSR
211
+ */
212
+ export declare function createContext(options?: { name?: string }): ReactiveContextClass;
213
+
214
+ /**
215
+ * Get the currently active reactive context
216
+ */
217
+ export declare function getActiveContext(): ReactiveContextClass;
218
+
219
+ /**
220
+ * Run a function within a specific reactive context
221
+ */
222
+ export declare function withContext<T>(ctx: ReactiveContextClass, fn: () => T): T;
223
+
224
+ /**
225
+ * Effect error with context information
226
+ */
227
+ export declare class EffectError extends Error {
228
+ readonly effectId: string;
229
+ readonly phase: string;
230
+ readonly cause: Error;
231
+ }
232
+
233
+ /**
234
+ * Register a global error handler for effect errors
235
+ * @returns Cleanup function
236
+ */
237
+ export declare function onEffectError(handler: (error: EffectError) => void): () => void;
238
+
239
+ /**
240
+ * Create a reactive prop from component props object
241
+ */
242
+ export declare function useProp<T>(props: Record<string, unknown>, name: string, defaultValue?: T): Pulse<T>;
243
+
244
+ /** HMR support - set the current module for effect tracking */
245
+ export declare function setCurrentModule(moduleId: string): void;
246
+
247
+ /** HMR support - clear the current module */
248
+ export declare function clearCurrentModule(): void;
249
+
250
+ /** HMR support - dispose all effects registered to a module */
251
+ export declare function disposeModule(moduleId: string): void;
@@ -0,0 +1,286 @@
1
+ /**
2
+ * Pulse Security Module - Type Definitions
3
+ * @module pulse-js-framework/runtime/security
4
+ *
5
+ * Centralized security utilities and constants for the Pulse framework.
6
+ * Provides protection against:
7
+ * - Prototype pollution
8
+ * - XSS attacks
9
+ * - Injection attacks
10
+ */
11
+
12
+ // =============================================================================
13
+ // Constants
14
+ // =============================================================================
15
+
16
+ /**
17
+ * Properties that could be used for prototype pollution attacks.
18
+ * These should never be accepted as user-provided keys.
19
+ *
20
+ * Includes: `__proto__`, `constructor`, `prototype`, `eval`, `Function`,
21
+ * and various property descriptor manipulation methods.
22
+ */
23
+ export declare const DANGEROUS_KEYS: Set<string>;
24
+
25
+ /**
26
+ * Event handler attributes that could execute JavaScript.
27
+ *
28
+ * Includes all standard DOM event handler attributes such as
29
+ * `onclick`, `onerror`, `onload`, `oninput`, etc.
30
+ */
31
+ export declare const EVENT_HANDLER_ATTRS: Set<string>;
32
+
33
+ /**
34
+ * Dangerous URL protocols that could execute JavaScript.
35
+ *
36
+ * Includes: `javascript:`, `vbscript:`, `data:`, `blob:`
37
+ */
38
+ export declare const DANGEROUS_PROTOCOLS: Set<string>;
39
+
40
+ /**
41
+ * Safe URL protocols that are allowed by default.
42
+ *
43
+ * Includes: `http:`, `https:`, `mailto:`, `tel:`, `sms:`, `ftp:`, `sftp:`
44
+ */
45
+ export declare const SAFE_PROTOCOLS: Set<string>;
46
+
47
+ /**
48
+ * Default HTML tags allowed in sanitized HTML output.
49
+ *
50
+ * Includes text formatting (`p`, `strong`, `em`, etc.), headings,
51
+ * lists, tables, links, images, and semantic elements.
52
+ */
53
+ export declare const DEFAULT_ALLOWED_TAGS: Set<string>;
54
+
55
+ /**
56
+ * Default attributes allowed in sanitized HTML output.
57
+ *
58
+ * Includes global attributes (`id`, `class`, `title`), link attributes
59
+ * (`href`, `target`, `rel`), image attributes (`src`, `alt`, `width`, `height`),
60
+ * table attributes (`colspan`, `rowspan`), and accessibility attributes
61
+ * (`role`, `aria-label`, `tabindex`, etc.).
62
+ */
63
+ export declare const DEFAULT_ALLOWED_ATTRS: Set<string>;
64
+
65
+ // =============================================================================
66
+ // Options Interfaces
67
+ // =============================================================================
68
+
69
+ /**
70
+ * Options for sanitizing object keys against prototype pollution.
71
+ */
72
+ export interface SanitizeObjectKeysOptions {
73
+ /**
74
+ * Throw an error when a dangerous key is encountered instead of
75
+ * silently filtering it out.
76
+ * @default false
77
+ */
78
+ throwOnDangerous?: boolean;
79
+
80
+ /**
81
+ * Log warnings to the console when dangerous keys are filtered.
82
+ * @default true
83
+ */
84
+ logWarnings?: boolean;
85
+ }
86
+
87
+ /**
88
+ * Options for HTML sanitization.
89
+ */
90
+ export interface SanitizeHtmlOptions {
91
+ /**
92
+ * Set of HTML tags to allow in the output.
93
+ * Tags not in this set will be removed (their children are preserved).
94
+ * @default DEFAULT_ALLOWED_TAGS
95
+ */
96
+ allowedTags?: Set<string>;
97
+
98
+ /**
99
+ * Set of attributes to allow on elements.
100
+ * Attributes not in this set will be stripped.
101
+ * @default DEFAULT_ALLOWED_ATTRS
102
+ */
103
+ allowedAttrs?: Set<string>;
104
+
105
+ /**
106
+ * Allow `data:` URLs in `src` and `href` attributes.
107
+ * Even when enabled, `data:text/html` and `data:text/javascript` are blocked.
108
+ * @default false
109
+ */
110
+ allowDataUrls?: boolean;
111
+ }
112
+
113
+ /**
114
+ * Options for URL sanitization.
115
+ */
116
+ export interface SanitizeUrlOptions {
117
+ /**
118
+ * Allow `data:` URLs.
119
+ * Even when enabled, `data:text/html` and `data:text/javascript` are blocked.
120
+ * @default false
121
+ */
122
+ allowData?: boolean;
123
+
124
+ /**
125
+ * Allow `blob:` URLs.
126
+ * @default false
127
+ */
128
+ allowBlob?: boolean;
129
+
130
+ /**
131
+ * Allow relative URLs (URLs without a protocol).
132
+ * @default true
133
+ */
134
+ allowRelative?: boolean;
135
+ }
136
+
137
+ // =============================================================================
138
+ // Validation Functions
139
+ // =============================================================================
140
+
141
+ /**
142
+ * Check if a key is potentially dangerous (prototype pollution risk).
143
+ *
144
+ * @param key - The key to check
145
+ * @returns `true` if the key is in the {@link DANGEROUS_KEYS} set
146
+ *
147
+ * @example
148
+ * ```typescript
149
+ * if (isDangerousKey(userProvidedKey)) {
150
+ * throw new Error('Invalid key');
151
+ * }
152
+ * ```
153
+ */
154
+ export declare function isDangerousKey(key: string): boolean;
155
+
156
+ /**
157
+ * Validate and filter an object's keys to prevent prototype pollution.
158
+ * Recursively processes nested objects and arrays, removing any keys
159
+ * found in {@link DANGEROUS_KEYS}.
160
+ *
161
+ * @template T - The type of the object being sanitized
162
+ * @param obj - Object to validate
163
+ * @param options - Sanitization options
164
+ * @returns Cleaned object with dangerous keys removed
165
+ *
166
+ * @example
167
+ * ```typescript
168
+ * const safeData = sanitizeObjectKeys(userInput);
169
+ *
170
+ * // Throw on dangerous keys instead of silently filtering
171
+ * const strict = sanitizeObjectKeys(userInput, { throwOnDangerous: true });
172
+ * ```
173
+ */
174
+ export declare function sanitizeObjectKeys<T>(
175
+ obj: T,
176
+ options?: SanitizeObjectKeysOptions
177
+ ): T;
178
+
179
+ // =============================================================================
180
+ // HTML Sanitization
181
+ // =============================================================================
182
+
183
+ /**
184
+ * Escape HTML special characters to prevent XSS.
185
+ *
186
+ * Escapes the following characters: `&`, `<`, `>`, `"`, `'`
187
+ *
188
+ * @param str - String to escape (null/undefined returns empty string)
189
+ * @returns Escaped string safe for HTML insertion
190
+ *
191
+ * @example
192
+ * ```typescript
193
+ * const safe = escapeHtml('<script>alert("xss")</script>');
194
+ * // Returns: '&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;'
195
+ * ```
196
+ */
197
+ export declare function escapeHtml(str: string | null | undefined): string;
198
+
199
+ /**
200
+ * Sanitize an HTML string to remove potentially dangerous content.
201
+ *
202
+ * Uses the browser's DOMParser for safe parsing when available.
203
+ * In non-browser environments, falls back to stripping all tags.
204
+ *
205
+ * This is a basic sanitizer. For production use with untrusted content,
206
+ * consider using a dedicated library like DOMPurify.
207
+ *
208
+ * @param html - HTML string to sanitize
209
+ * @param options - Sanitization options
210
+ * @returns Sanitized HTML string with only allowed tags and attributes
211
+ *
212
+ * @example
213
+ * ```typescript
214
+ * const safe = sanitizeHtml('<script>alert("xss")</script><p>Hello</p>');
215
+ * // Returns: '<p>Hello</p>'
216
+ *
217
+ * // Custom allowed tags
218
+ * const minimal = sanitizeHtml(userHtml, {
219
+ * allowedTags: new Set(['p', 'br', 'strong', 'em']),
220
+ * allowedAttrs: new Set(['class'])
221
+ * });
222
+ * ```
223
+ */
224
+ export declare function sanitizeHtml(
225
+ html: string | null | undefined,
226
+ options?: SanitizeHtmlOptions
227
+ ): string;
228
+
229
+ // =============================================================================
230
+ // URL Sanitization
231
+ // =============================================================================
232
+
233
+ /**
234
+ * Sanitize a URL to prevent JavaScript execution.
235
+ *
236
+ * Blocks `javascript:` and `vbscript:` protocols. Optionally allows
237
+ * `data:` and `blob:` URLs. Decodes HTML entities and URI encoding
238
+ * to catch encoded attacks.
239
+ *
240
+ * @param url - URL to sanitize
241
+ * @param options - Sanitization options
242
+ * @returns Sanitized URL string, or `null` if the URL is dangerous
243
+ *
244
+ * @example
245
+ * ```typescript
246
+ * const safe = sanitizeUrl('javascript:alert("xss")');
247
+ * // Returns: null
248
+ *
249
+ * const valid = sanitizeUrl('https://example.com');
250
+ * // Returns: 'https://example.com'
251
+ *
252
+ * // Allow data: URLs for images
253
+ * const dataUrl = sanitizeUrl('data:image/png;base64,...', { allowData: true });
254
+ * ```
255
+ */
256
+ export declare function sanitizeUrl(
257
+ url: string | null | undefined,
258
+ options?: SanitizeUrlOptions
259
+ ): string | null;
260
+
261
+ // =============================================================================
262
+ // Default Export
263
+ // =============================================================================
264
+
265
+ declare const security: {
266
+ // Constants
267
+ DANGEROUS_KEYS: typeof DANGEROUS_KEYS;
268
+ EVENT_HANDLER_ATTRS: typeof EVENT_HANDLER_ATTRS;
269
+ DANGEROUS_PROTOCOLS: typeof DANGEROUS_PROTOCOLS;
270
+ SAFE_PROTOCOLS: typeof SAFE_PROTOCOLS;
271
+ DEFAULT_ALLOWED_TAGS: typeof DEFAULT_ALLOWED_TAGS;
272
+ DEFAULT_ALLOWED_ATTRS: typeof DEFAULT_ALLOWED_ATTRS;
273
+
274
+ // Validation
275
+ isDangerousKey: typeof isDangerousKey;
276
+ sanitizeObjectKeys: typeof sanitizeObjectKeys;
277
+
278
+ // HTML
279
+ escapeHtml: typeof escapeHtml;
280
+ sanitizeHtml: typeof sanitizeHtml;
281
+
282
+ // URL
283
+ sanitizeUrl: typeof sanitizeUrl;
284
+ };
285
+
286
+ export default security;