pulse-js-framework 1.10.4 → 1.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +11 -0
  2. package/cli/build.js +13 -3
  3. package/compiler/directives.js +356 -0
  4. package/compiler/lexer.js +18 -3
  5. package/compiler/parser/core.js +6 -0
  6. package/compiler/parser/view.js +2 -6
  7. package/compiler/preprocessor.js +43 -23
  8. package/compiler/sourcemap.js +3 -1
  9. package/compiler/transformer/actions.js +329 -0
  10. package/compiler/transformer/export.js +7 -0
  11. package/compiler/transformer/expressions.js +85 -33
  12. package/compiler/transformer/imports.js +3 -0
  13. package/compiler/transformer/index.js +2 -0
  14. package/compiler/transformer/store.js +1 -1
  15. package/compiler/transformer/style.js +45 -16
  16. package/compiler/transformer/view.js +23 -2
  17. package/loader/rollup-plugin-server-components.js +391 -0
  18. package/loader/vite-plugin-server-components.js +420 -0
  19. package/loader/webpack-loader-server-components.js +356 -0
  20. package/package.json +124 -82
  21. package/runtime/async.js +4 -0
  22. package/runtime/context.js +16 -3
  23. package/runtime/dom-adapter.js +5 -3
  24. package/runtime/dom-virtual-list.js +2 -1
  25. package/runtime/form.js +8 -3
  26. package/runtime/graphql/cache.js +1 -1
  27. package/runtime/graphql/client.js +22 -0
  28. package/runtime/graphql/hooks.js +12 -6
  29. package/runtime/graphql/subscriptions.js +2 -0
  30. package/runtime/hmr.js +6 -3
  31. package/runtime/http.js +1 -0
  32. package/runtime/i18n.js +2 -0
  33. package/runtime/lru-cache.js +3 -1
  34. package/runtime/native.js +46 -20
  35. package/runtime/pulse.js +3 -0
  36. package/runtime/router/core.js +5 -1
  37. package/runtime/router/index.js +17 -1
  38. package/runtime/router/psc-integration.js +301 -0
  39. package/runtime/security.js +58 -29
  40. package/runtime/server-components/actions-server.js +798 -0
  41. package/runtime/server-components/actions.js +389 -0
  42. package/runtime/server-components/client.js +447 -0
  43. package/runtime/server-components/error-sanitizer.js +438 -0
  44. package/runtime/server-components/index.js +275 -0
  45. package/runtime/server-components/security-csrf.js +593 -0
  46. package/runtime/server-components/security-errors.js +227 -0
  47. package/runtime/server-components/security-ratelimit.js +733 -0
  48. package/runtime/server-components/security-validation.js +467 -0
  49. package/runtime/server-components/security.js +598 -0
  50. package/runtime/server-components/serializer.js +617 -0
  51. package/runtime/server-components/server.js +382 -0
  52. package/runtime/server-components/types.js +383 -0
  53. package/runtime/server-components/utils/mutex.js +60 -0
  54. package/runtime/server-components/utils/path-sanitizer.js +109 -0
  55. package/runtime/ssr.js +2 -1
  56. package/runtime/store.js +19 -10
  57. package/runtime/utils.js +12 -128
  58. package/types/animation.d.ts +300 -0
  59. package/types/i18n.d.ts +283 -0
  60. package/types/persistence.d.ts +267 -0
  61. package/types/sse.d.ts +248 -0
  62. package/types/sw.d.ts +150 -0
  63. package/runtime/a11y.js.original +0 -1844
  64. package/runtime/graphql.js.original +0 -1326
  65. package/runtime/router.js.original +0 -1605
@@ -0,0 +1,283 @@
1
+ /**
2
+ * Pulse i18n Module Type Definitions
3
+ * @module pulse-js-framework/runtime/i18n
4
+ */
5
+
6
+ import { Pulse } from './pulse';
7
+
8
+ // ============================================================================
9
+ // I18n Error
10
+ // ============================================================================
11
+
12
+ /**
13
+ * I18n-specific error
14
+ */
15
+ export declare class I18nError extends Error {
16
+ readonly name: 'I18nError';
17
+
18
+ constructor(message: string, options?: {
19
+ suggestion?: string;
20
+ });
21
+
22
+ /** Check if an error is an I18nError */
23
+ static isI18nError(error: unknown): error is I18nError;
24
+ }
25
+
26
+ // ============================================================================
27
+ // Types
28
+ // ============================================================================
29
+
30
+ /** Nested message object where leaves are translation strings */
31
+ export interface MessageObject {
32
+ [key: string]: string | MessageObject;
33
+ }
34
+
35
+ /** Messages organized by locale */
36
+ export interface Messages {
37
+ [locale: string]: MessageObject;
38
+ }
39
+
40
+ /** Plural rule function: takes a count and returns the plural form index */
41
+ export type PluralRule = (count: number) => number;
42
+
43
+ /** Plural rules organized by locale */
44
+ export interface PluralRules {
45
+ [locale: string]: PluralRule;
46
+ }
47
+
48
+ /** Missing key handler */
49
+ export type MissingHandler = (locale: string, key: string) => string;
50
+
51
+ /** Text modifier function (used with pipe syntax) */
52
+ export type Modifier = (value: string) => string;
53
+
54
+ /** Modifier map */
55
+ export interface Modifiers {
56
+ [name: string]: Modifier;
57
+ }
58
+
59
+ /** Interpolation parameters */
60
+ export interface InterpolationParams {
61
+ [key: string]: string | number | boolean;
62
+ }
63
+
64
+ // ============================================================================
65
+ // createI18n Options
66
+ // ============================================================================
67
+
68
+ /** Options for createI18n */
69
+ export interface I18nOptions {
70
+ /** Initial locale (default: 'en') */
71
+ locale?: string;
72
+
73
+ /** Fallback locale when a key is missing (default: 'en') */
74
+ fallbackLocale?: string;
75
+
76
+ /** Message dictionaries organized by locale */
77
+ messages?: Messages;
78
+
79
+ /** Custom pluralization rules by locale */
80
+ pluralRules?: PluralRules | null;
81
+
82
+ /** Handler called when a translation key is missing */
83
+ missing?: MissingHandler | null;
84
+
85
+ /** Text modifiers for pipe syntax (e.g., 'key | upper') */
86
+ modifiers?: Modifiers | null;
87
+ }
88
+
89
+ // ============================================================================
90
+ // I18n Instance
91
+ // ============================================================================
92
+
93
+ /** I18n instance returned by createI18n */
94
+ export interface I18nInstance {
95
+ /** Reactive current locale */
96
+ locale: Pulse<string>;
97
+
98
+ /** List of available locale codes */
99
+ readonly availableLocales: string[];
100
+
101
+ /**
102
+ * Translate a key with optional interpolation.
103
+ * Supports dot notation (e.g., 'nav.home') and pipe modifiers (e.g., 'greeting | upper').
104
+ *
105
+ * @param key Translation key
106
+ * @param params Interpolation parameters (replaces {param} in message)
107
+ * @returns Translated string, or the key itself if not found
108
+ */
109
+ t(key: string, params?: InterpolationParams): string;
110
+
111
+ /**
112
+ * Translate with pluralization.
113
+ * The message value should contain plural forms separated by ' | '.
114
+ * (e.g., 'no items | one item | {count} items')
115
+ *
116
+ * @param key Translation key
117
+ * @param count Count for pluralization
118
+ * @param params Additional interpolation parameters (count is added automatically)
119
+ * @returns Pluralized translated string
120
+ */
121
+ tc(key: string, count: number, params?: InterpolationParams): string;
122
+
123
+ /**
124
+ * Check if a translation key exists.
125
+ *
126
+ * @param key Translation key
127
+ * @param locale Locale to check (defaults to current locale)
128
+ * @returns True if the key exists
129
+ */
130
+ te(key: string, locale?: string): boolean;
131
+
132
+ /**
133
+ * Get the raw message value without interpolation.
134
+ *
135
+ * @param key Translation key
136
+ * @returns Raw message value (string, nested object, or undefined)
137
+ */
138
+ tm(key: string): string | MessageObject | undefined;
139
+
140
+ /**
141
+ * Change the current locale.
142
+ * Triggers reactive updates in all computed translations.
143
+ *
144
+ * @param newLocale Locale code to switch to
145
+ */
146
+ setLocale(newLocale: string): void;
147
+
148
+ /**
149
+ * Dynamically load messages for a locale.
150
+ * Merges with existing messages if the locale is already loaded.
151
+ *
152
+ * @param locale Locale code
153
+ * @param messages Message dictionary
154
+ */
155
+ loadMessages(locale: string, messages: MessageObject): void;
156
+
157
+ /**
158
+ * Set this instance as the global default for useI18n().
159
+ */
160
+ install(): void;
161
+
162
+ /**
163
+ * Format a number using Intl.NumberFormat with the current locale.
164
+ *
165
+ * @param value Number to format
166
+ * @param options Intl.NumberFormat options
167
+ * @returns Formatted number string
168
+ */
169
+ n(value: number, options?: Intl.NumberFormatOptions): string;
170
+
171
+ /**
172
+ * Format a date using Intl.DateTimeFormat with the current locale.
173
+ *
174
+ * @param value Date or timestamp to format
175
+ * @param options Intl.DateTimeFormat options
176
+ * @returns Formatted date string
177
+ */
178
+ d(value: Date | number, options?: Intl.DateTimeFormatOptions): string;
179
+ }
180
+
181
+ /**
182
+ * Create an i18n instance with reactive locale switching,
183
+ * interpolation, pluralization, and modifiers.
184
+ *
185
+ * @param options Configuration options
186
+ * @returns I18n instance
187
+ *
188
+ * @example
189
+ * const i18n = createI18n({
190
+ * locale: 'en',
191
+ * fallbackLocale: 'en',
192
+ * messages: {
193
+ * en: {
194
+ * greeting: 'Hello, {name}!',
195
+ * items: 'no items | one item | {count} items',
196
+ * nav: { home: 'Home', about: 'About' },
197
+ * },
198
+ * fr: {
199
+ * greeting: 'Bonjour, {name} !',
200
+ * items: 'aucun | un | {count} articles',
201
+ * nav: { home: 'Accueil', about: 'A propos' },
202
+ * },
203
+ * },
204
+ * modifiers: {
205
+ * upper: (v) => v.toUpperCase(),
206
+ * lower: (v) => v.toLowerCase(),
207
+ * },
208
+ * });
209
+ *
210
+ * i18n.install(); // Set as global default
211
+ *
212
+ * i18n.t('greeting', { name: 'Alice' }); // 'Hello, Alice!'
213
+ * i18n.tc('items', 5); // '5 items'
214
+ * i18n.t('greeting | upper', { name: 'Alice' }); // 'HELLO, ALICE!'
215
+ *
216
+ * i18n.setLocale('fr'); // Switch locale reactively
217
+ * i18n.t('greeting', { name: 'Alice' }); // 'Bonjour, Alice !'
218
+ */
219
+ export declare function createI18n(options?: I18nOptions): I18nInstance;
220
+
221
+ // ============================================================================
222
+ // useI18n Hook
223
+ // ============================================================================
224
+
225
+ /** Return type of useI18n() */
226
+ export interface UseI18nReturn {
227
+ /** Translate a key with optional interpolation */
228
+ t: I18nInstance['t'];
229
+
230
+ /** Translate with pluralization */
231
+ tc: I18nInstance['tc'];
232
+
233
+ /** Check if a translation key exists */
234
+ te: I18nInstance['te'];
235
+
236
+ /** Get the raw message value */
237
+ tm: I18nInstance['tm'];
238
+
239
+ /** Reactive current locale */
240
+ locale: Pulse<string>;
241
+
242
+ /** Change the current locale */
243
+ setLocale: I18nInstance['setLocale'];
244
+
245
+ /** List of available locale codes */
246
+ availableLocales: string[];
247
+
248
+ /** Format a number using Intl.NumberFormat */
249
+ n: I18nInstance['n'];
250
+
251
+ /** Format a date using Intl.DateTimeFormat */
252
+ d: I18nInstance['d'];
253
+ }
254
+
255
+ /**
256
+ * Get the global i18n instance (set via createI18n().install()).
257
+ * Throws I18nError if no instance has been installed.
258
+ *
259
+ * @returns I18n methods and reactive locale
260
+ * @throws I18nError if no i18n instance is installed
261
+ *
262
+ * @example
263
+ * // First, install a global instance
264
+ * const i18n = createI18n({ ... });
265
+ * i18n.install();
266
+ *
267
+ * // Then use in components
268
+ * const { t, locale, setLocale } = useI18n();
269
+ * const greeting = computed(() => t('greeting', { name: user.get() }));
270
+ */
271
+ export declare function useI18n(): UseI18nReturn;
272
+
273
+ // ============================================================================
274
+ // Default Export
275
+ // ============================================================================
276
+
277
+ declare const _default: {
278
+ createI18n: typeof createI18n;
279
+ useI18n: typeof useI18n;
280
+ I18nError: typeof I18nError;
281
+ };
282
+
283
+ export default _default;
@@ -0,0 +1,267 @@
1
+ /**
2
+ * Pulse Persistence Adapters Type Definitions
3
+ * @module pulse-js-framework/runtime/persistence
4
+ */
5
+
6
+ // ============================================================================
7
+ // Persistence Error
8
+ // ============================================================================
9
+
10
+ /**
11
+ * Persistence-specific error with adapter context
12
+ */
13
+ export declare class PersistenceError extends Error {
14
+ readonly name: 'PersistenceError';
15
+
16
+ /** Name of the adapter that caused the error (or null) */
17
+ readonly adapterName: string | null;
18
+
19
+ constructor(message: string, options?: {
20
+ adapterName?: string;
21
+ suggestion?: string;
22
+ });
23
+
24
+ /** Check if an error is a PersistenceError */
25
+ static isPersistenceError(error: unknown): error is PersistenceError;
26
+ }
27
+
28
+ // ============================================================================
29
+ // Persistence Adapter Interface
30
+ // ============================================================================
31
+
32
+ /**
33
+ * Persistence adapter interface for storage backends.
34
+ * All methods are async to support both synchronous (localStorage) and
35
+ * asynchronous (IndexedDB) storage backends.
36
+ */
37
+ export interface PersistenceAdapter {
38
+ /** Adapter name (e.g., 'localStorage', 'sessionStorage', 'IndexedDB', 'Memory') */
39
+ readonly name: string;
40
+
41
+ /**
42
+ * Get an item from storage
43
+ * @param key Storage key
44
+ * @returns The stored value, or null if not found
45
+ */
46
+ getItem(key: string): Promise<unknown | null>;
47
+
48
+ /**
49
+ * Set an item in storage
50
+ * @param key Storage key
51
+ * @param value Value to store
52
+ */
53
+ setItem(key: string, value: unknown): Promise<void>;
54
+
55
+ /**
56
+ * Remove an item from storage
57
+ * @param key Storage key
58
+ */
59
+ removeItem(key: string): Promise<void>;
60
+
61
+ /** Clear all items from storage */
62
+ clear(): Promise<void>;
63
+
64
+ /**
65
+ * Get all storage keys
66
+ * @returns Array of key strings
67
+ */
68
+ keys(): Promise<string[]>;
69
+ }
70
+
71
+ // ============================================================================
72
+ // Adapter Type
73
+ // ============================================================================
74
+
75
+ /** Supported persistence adapter type names */
76
+ export type PersistenceAdapterType = 'localStorage' | 'sessionStorage' | 'indexedDB' | 'memory';
77
+
78
+ // ============================================================================
79
+ // Adapter Factory Functions
80
+ // ============================================================================
81
+
82
+ /**
83
+ * Create a localStorage persistence adapter.
84
+ * Falls back to memory adapter if localStorage is not available.
85
+ *
86
+ * @returns PersistenceAdapter backed by localStorage
87
+ *
88
+ * @example
89
+ * const adapter = createLocalStorageAdapter();
90
+ * await adapter.setItem('theme', 'dark');
91
+ * const theme = await adapter.getItem('theme'); // 'dark'
92
+ */
93
+ export declare function createLocalStorageAdapter(): PersistenceAdapter;
94
+
95
+ /**
96
+ * Create a sessionStorage persistence adapter.
97
+ * Falls back to memory adapter if sessionStorage is not available.
98
+ *
99
+ * @returns PersistenceAdapter backed by sessionStorage
100
+ *
101
+ * @example
102
+ * const adapter = createSessionStorageAdapter();
103
+ * await adapter.setItem('token', 'abc123');
104
+ */
105
+ export declare function createSessionStorageAdapter(): PersistenceAdapter;
106
+
107
+ /** Options for createIndexedDBAdapter */
108
+ export interface IndexedDBAdapterOptions {
109
+ /** Database name (default: 'pulse-store') */
110
+ dbName?: string;
111
+
112
+ /** Object store name (default: 'state') */
113
+ storeName?: string;
114
+
115
+ /** Database version (default: 1) */
116
+ version?: number;
117
+ }
118
+
119
+ /**
120
+ * Create an IndexedDB persistence adapter for large datasets.
121
+ * Falls back to memory adapter if IndexedDB is not available.
122
+ *
123
+ * @param options IndexedDB configuration options
124
+ * @returns PersistenceAdapter backed by IndexedDB
125
+ *
126
+ * @example
127
+ * const adapter = createIndexedDBAdapter({
128
+ * dbName: 'my-app',
129
+ * storeName: 'state',
130
+ * version: 1,
131
+ * });
132
+ * await adapter.setItem('largeData', bigObject);
133
+ */
134
+ export declare function createIndexedDBAdapter(options?: IndexedDBAdapterOptions): PersistenceAdapter;
135
+
136
+ /**
137
+ * Create an in-memory persistence adapter (for testing or SSR).
138
+ * Data is lost when the adapter instance is garbage collected.
139
+ *
140
+ * @returns PersistenceAdapter backed by an in-memory Map
141
+ *
142
+ * @example
143
+ * const adapter = createMemoryAdapter();
144
+ * await adapter.setItem('key', 'value');
145
+ */
146
+ export declare function createMemoryAdapter(): PersistenceAdapter;
147
+
148
+ /**
149
+ * Create a persistence adapter by type name.
150
+ *
151
+ * @param type Adapter type: 'localStorage' | 'sessionStorage' | 'indexedDB' | 'memory'
152
+ * @param options Adapter-specific options (only used for 'indexedDB')
153
+ * @returns PersistenceAdapter instance
154
+ * @throws PersistenceError if the type is unknown
155
+ *
156
+ * @example
157
+ * const adapter = createPersistenceAdapter('indexedDB', { dbName: 'my-app' });
158
+ */
159
+ export declare function createPersistenceAdapter(
160
+ type: PersistenceAdapterType,
161
+ options?: IndexedDBAdapterOptions
162
+ ): PersistenceAdapter;
163
+
164
+ // ============================================================================
165
+ // Store Persistence Integration
166
+ // ============================================================================
167
+
168
+ /** Options for withPersistence */
169
+ export interface PersistenceOptions {
170
+ /** Storage key for persisted data (default: 'pulse-store') */
171
+ key?: string;
172
+
173
+ /** Debounce delay for auto-save in ms (default: 100) */
174
+ debounce?: number;
175
+
176
+ /** Only persist these keys (default: null = all keys) */
177
+ include?: string[] | null;
178
+
179
+ /** Exclude these keys from persistence (default: null = none excluded) */
180
+ exclude?: string[] | null;
181
+
182
+ /** Custom serialization function (default: JSON.stringify) */
183
+ serialize?: (value: unknown) => string;
184
+
185
+ /** Custom deserialization function (default: JSON.parse) */
186
+ deserialize?: (value: string) => unknown;
187
+
188
+ /** Maximum nesting depth for sanitization (default: 10) */
189
+ maxDepth?: number;
190
+
191
+ /** Error callback invoked on persistence failures */
192
+ onError?: ((error: Error) => void) | null;
193
+ }
194
+
195
+ /** Return type of withPersistence */
196
+ export interface PersistenceHandle {
197
+ /**
198
+ * Restore persisted state into the store
199
+ * @returns True if state was successfully restored
200
+ */
201
+ restore(): Promise<boolean>;
202
+
203
+ /**
204
+ * Clear persisted data from storage
205
+ */
206
+ clear(): Promise<void>;
207
+
208
+ /**
209
+ * Force an immediate save, bypassing debounce
210
+ */
211
+ flush(): Promise<void>;
212
+
213
+ /**
214
+ * Dispose of persistence (stop auto-saving)
215
+ */
216
+ dispose(): void;
217
+ }
218
+
219
+ /**
220
+ * Attach persistence to an existing Pulse store.
221
+ * Auto-saves store changes to the adapter with debouncing.
222
+ *
223
+ * @param store A Pulse store created by createStore()
224
+ * @param adapter A PersistenceAdapter instance
225
+ * @param options Persistence options
226
+ * @returns Handle with restore, clear, flush, and dispose methods
227
+ *
228
+ * @example
229
+ * import { createStore } from 'pulse-js-framework/runtime/store';
230
+ *
231
+ * const store = createStore({ theme: 'light', user: null });
232
+ * const adapter = createLocalStorageAdapter();
233
+ *
234
+ * const persistence = withPersistence(store, adapter, {
235
+ * key: 'my-app-state',
236
+ * debounce: 200,
237
+ * exclude: ['user'],
238
+ * });
239
+ *
240
+ * // Restore previously saved state
241
+ * await persistence.restore();
242
+ *
243
+ * // Later: force save and clean up
244
+ * await persistence.flush();
245
+ * persistence.dispose();
246
+ */
247
+ export declare function withPersistence(
248
+ store: Record<string, unknown>,
249
+ adapter: PersistenceAdapter,
250
+ options?: PersistenceOptions
251
+ ): PersistenceHandle;
252
+
253
+ // ============================================================================
254
+ // Default Export
255
+ // ============================================================================
256
+
257
+ declare const _default: {
258
+ createPersistenceAdapter: typeof createPersistenceAdapter;
259
+ createLocalStorageAdapter: typeof createLocalStorageAdapter;
260
+ createSessionStorageAdapter: typeof createSessionStorageAdapter;
261
+ createIndexedDBAdapter: typeof createIndexedDBAdapter;
262
+ createMemoryAdapter: typeof createMemoryAdapter;
263
+ withPersistence: typeof withPersistence;
264
+ PersistenceError: typeof PersistenceError;
265
+ };
266
+
267
+ export default _default;