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.
- package/README.md +11 -0
- package/cli/build.js +13 -3
- package/compiler/directives.js +356 -0
- package/compiler/lexer.js +18 -3
- package/compiler/parser/core.js +6 -0
- package/compiler/parser/view.js +2 -6
- package/compiler/preprocessor.js +43 -23
- package/compiler/sourcemap.js +3 -1
- package/compiler/transformer/actions.js +329 -0
- package/compiler/transformer/export.js +7 -0
- package/compiler/transformer/expressions.js +85 -33
- package/compiler/transformer/imports.js +3 -0
- package/compiler/transformer/index.js +2 -0
- package/compiler/transformer/store.js +1 -1
- package/compiler/transformer/style.js +45 -16
- package/compiler/transformer/view.js +23 -2
- package/loader/rollup-plugin-server-components.js +391 -0
- package/loader/vite-plugin-server-components.js +420 -0
- package/loader/webpack-loader-server-components.js +356 -0
- package/package.json +124 -82
- package/runtime/async.js +4 -0
- package/runtime/context.js +16 -3
- package/runtime/dom-adapter.js +5 -3
- package/runtime/dom-virtual-list.js +2 -1
- package/runtime/form.js +8 -3
- package/runtime/graphql/cache.js +1 -1
- package/runtime/graphql/client.js +22 -0
- package/runtime/graphql/hooks.js +12 -6
- package/runtime/graphql/subscriptions.js +2 -0
- package/runtime/hmr.js +6 -3
- package/runtime/http.js +1 -0
- package/runtime/i18n.js +2 -0
- package/runtime/lru-cache.js +3 -1
- package/runtime/native.js +46 -20
- package/runtime/pulse.js +3 -0
- package/runtime/router/core.js +5 -1
- package/runtime/router/index.js +17 -1
- package/runtime/router/psc-integration.js +301 -0
- package/runtime/security.js +58 -29
- package/runtime/server-components/actions-server.js +798 -0
- package/runtime/server-components/actions.js +389 -0
- package/runtime/server-components/client.js +447 -0
- package/runtime/server-components/error-sanitizer.js +438 -0
- package/runtime/server-components/index.js +275 -0
- package/runtime/server-components/security-csrf.js +593 -0
- package/runtime/server-components/security-errors.js +227 -0
- package/runtime/server-components/security-ratelimit.js +733 -0
- package/runtime/server-components/security-validation.js +467 -0
- package/runtime/server-components/security.js +598 -0
- package/runtime/server-components/serializer.js +617 -0
- package/runtime/server-components/server.js +382 -0
- package/runtime/server-components/types.js +383 -0
- package/runtime/server-components/utils/mutex.js +60 -0
- package/runtime/server-components/utils/path-sanitizer.js +109 -0
- package/runtime/ssr.js +2 -1
- package/runtime/store.js +19 -10
- package/runtime/utils.js +12 -128
- package/types/animation.d.ts +300 -0
- package/types/i18n.d.ts +283 -0
- package/types/persistence.d.ts +267 -0
- package/types/sse.d.ts +248 -0
- package/types/sw.d.ts +150 -0
- package/runtime/a11y.js.original +0 -1844
- package/runtime/graphql.js.original +0 -1326
- package/runtime/router.js.original +0 -1605
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pulse Server Components - Webpack Loader Extension
|
|
3
|
+
*
|
|
4
|
+
* Extends webpack-loader.js with Server Components support:
|
|
5
|
+
* - Detects Client Components via __directive metadata
|
|
6
|
+
* - Generates client manifest (component ID → chunk URL mapping)
|
|
7
|
+
* - Writes manifest to filesystem
|
|
8
|
+
*
|
|
9
|
+
* Usage in webpack.config.js:
|
|
10
|
+
* ```js
|
|
11
|
+
* const { addServerComponentsSupport } = require('pulse-js-framework/loader/webpack-loader-server-components');
|
|
12
|
+
*
|
|
13
|
+
* module.exports = {
|
|
14
|
+
* module: {
|
|
15
|
+
* rules: [
|
|
16
|
+
* {
|
|
17
|
+
* test: /\.pulse$/,
|
|
18
|
+
* use: [
|
|
19
|
+
* 'style-loader',
|
|
20
|
+
* 'css-loader',
|
|
21
|
+
* 'pulse-js-framework/loader/webpack-loader'
|
|
22
|
+
* ]
|
|
23
|
+
* }
|
|
24
|
+
* ]
|
|
25
|
+
* },
|
|
26
|
+
* plugins: [
|
|
27
|
+
* addServerComponentsSupport({
|
|
28
|
+
* manifestPath: 'dist/.pulse-manifest.json'
|
|
29
|
+
* })
|
|
30
|
+
* ]
|
|
31
|
+
* };
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @module pulse-js-framework/loader/webpack-loader-server-components
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
import { writeFileSync, mkdirSync } from 'fs';
|
|
38
|
+
import { dirname, posix, relative } from 'path';
|
|
39
|
+
import { getComponentTypeFromSource } from '../compiler/directives.js';
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Default options for Server Components Webpack plugin
|
|
43
|
+
*/
|
|
44
|
+
const DEFAULT_OPTIONS = {
|
|
45
|
+
// Output directory for client manifest
|
|
46
|
+
manifestPath: 'dist/.pulse-manifest.json',
|
|
47
|
+
|
|
48
|
+
// Public base path for chunk URLs (empty for relative paths)
|
|
49
|
+
base: '',
|
|
50
|
+
|
|
51
|
+
// Custom manifest filename
|
|
52
|
+
manifestFilename: '.pulse-manifest.json'
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Storage for Client Components per compilation
|
|
57
|
+
* WeakMap<Compilation, Map<componentId, { file, chunk }>>
|
|
58
|
+
*/
|
|
59
|
+
const compilationClientComponents = new WeakMap();
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Get or create Client Components map for a compilation
|
|
63
|
+
*/
|
|
64
|
+
function getClientComponentsMap(compilation) {
|
|
65
|
+
if (!compilationClientComponents.has(compilation)) {
|
|
66
|
+
compilationClientComponents.set(compilation, new Map());
|
|
67
|
+
}
|
|
68
|
+
return compilationClientComponents.get(compilation);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Webpack plugin for Pulse Server Components support
|
|
73
|
+
*/
|
|
74
|
+
class PulseServerComponentsPlugin {
|
|
75
|
+
constructor(options = {}) {
|
|
76
|
+
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
apply(compiler) {
|
|
80
|
+
const pluginName = 'PulseServerComponentsPlugin';
|
|
81
|
+
|
|
82
|
+
compiler.hooks.thisCompilation.tap(pluginName, (compilation) => {
|
|
83
|
+
const clientComponents = getClientComponentsMap(compilation);
|
|
84
|
+
const componentTypes = new Map(); // module.resource → 'client' | 'server' | 'shared'
|
|
85
|
+
|
|
86
|
+
// Hook into module processing to detect Client Components and track types
|
|
87
|
+
compilation.hooks.succeedModule.tap(pluginName, (module) => {
|
|
88
|
+
if (!module.resource) return;
|
|
89
|
+
|
|
90
|
+
// Get the compiled source
|
|
91
|
+
const source = module._source?.source?.();
|
|
92
|
+
if (!source || typeof source !== 'string') {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Determine component type for all JS/TS files
|
|
97
|
+
if (/\.(js|ts|jsx|tsx|pulse)$/.test(module.resource)) {
|
|
98
|
+
const componentType = getComponentTypeFromSource(source, module.resource);
|
|
99
|
+
componentTypes.set(module.resource, componentType);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Only process .pulse files for Client Component detection
|
|
103
|
+
if (!module.resource.endsWith('.pulse')) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Check if this module exports a Client Component
|
|
108
|
+
// Look for: __directive: "use client"
|
|
109
|
+
const directiveMatch = source.match(/__directive:\s*["']use client["']/);
|
|
110
|
+
|
|
111
|
+
if (directiveMatch) {
|
|
112
|
+
// Extract component ID
|
|
113
|
+
const componentIdMatch = source.match(/__componentId:\s*["'](\w+)["']/);
|
|
114
|
+
const exportMatch = source.match(/export const (\w+) = \{/);
|
|
115
|
+
|
|
116
|
+
const componentId = componentIdMatch ? componentIdMatch[1] : (exportMatch ? exportMatch[1] : null);
|
|
117
|
+
|
|
118
|
+
if (componentId) {
|
|
119
|
+
// Store this as a Client Component
|
|
120
|
+
clientComponents.set(componentId, {
|
|
121
|
+
file: module.resource,
|
|
122
|
+
chunk: null, // Will be filled later
|
|
123
|
+
moduleId: module.id
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const relativePath = relative(process.cwd(), module.resource);
|
|
127
|
+
console.log(`[Pulse Server Components] Detected Client Component: ${componentId} (${relativePath})`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Validate imports after module graph is built
|
|
133
|
+
compilation.hooks.finishModules.tap(pluginName, (modules) => {
|
|
134
|
+
for (const module of modules) {
|
|
135
|
+
if (!module.resource) continue;
|
|
136
|
+
|
|
137
|
+
const moduleType = componentTypes.get(module.resource);
|
|
138
|
+
if (moduleType !== 'client') continue;
|
|
139
|
+
|
|
140
|
+
// Check all dependencies
|
|
141
|
+
for (const dependency of module.dependencies || []) {
|
|
142
|
+
const depModule = compilation.moduleGraph?.getModule?.(dependency);
|
|
143
|
+
if (!depModule || !depModule.resource) continue;
|
|
144
|
+
|
|
145
|
+
const depType = componentTypes.get(depModule.resource);
|
|
146
|
+
|
|
147
|
+
// Client → Server violation
|
|
148
|
+
if (depType === 'server') {
|
|
149
|
+
const error = new Error(createImportViolationError(
|
|
150
|
+
module.resource,
|
|
151
|
+
depModule.resource,
|
|
152
|
+
dependency.userRequest || depModule.resource
|
|
153
|
+
));
|
|
154
|
+
compilation.errors.push(error);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Generate manifest after all assets are processed
|
|
161
|
+
compilation.hooks.processAssets.tap(
|
|
162
|
+
{
|
|
163
|
+
name: pluginName,
|
|
164
|
+
stage: compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE
|
|
165
|
+
},
|
|
166
|
+
(assets) => {
|
|
167
|
+
// Skip if no Client Components detected
|
|
168
|
+
if (clientComponents.size === 0) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Map modules to their chunks
|
|
173
|
+
for (const [componentId, info] of clientComponents.entries()) {
|
|
174
|
+
// Find chunk(s) containing this module
|
|
175
|
+
for (const chunk of compilation.chunks) {
|
|
176
|
+
for (const module of compilation.chunkGraph.getChunkModulesIterable(chunk)) {
|
|
177
|
+
if (module.resource === info.file) {
|
|
178
|
+
// Get chunk filename
|
|
179
|
+
const chunkFiles = Array.from(chunk.files);
|
|
180
|
+
const jsFile = chunkFiles.find(f => f.endsWith('.js'));
|
|
181
|
+
|
|
182
|
+
if (jsFile) {
|
|
183
|
+
info.chunk = jsFile;
|
|
184
|
+
console.log(`[Pulse Server Components] Mapped ${componentId} → ${jsFile}`);
|
|
185
|
+
}
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Build client manifest
|
|
193
|
+
const manifest = {
|
|
194
|
+
version: '1.0',
|
|
195
|
+
components: {}
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
for (const [componentId, info] of clientComponents.entries()) {
|
|
199
|
+
if (info.chunk) {
|
|
200
|
+
const base = this.options.base || '';
|
|
201
|
+
const chunkUrl = posix.join(base, info.chunk);
|
|
202
|
+
|
|
203
|
+
manifest.components[componentId] = {
|
|
204
|
+
id: componentId,
|
|
205
|
+
chunk: chunkUrl,
|
|
206
|
+
exports: ['default', componentId]
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Emit manifest as asset
|
|
212
|
+
const manifestJson = JSON.stringify(manifest, null, 2);
|
|
213
|
+
const { RawSource } = compilation.compiler.webpack.sources;
|
|
214
|
+
|
|
215
|
+
compilation.emitAsset(
|
|
216
|
+
this.options.manifestFilename,
|
|
217
|
+
new RawSource(manifestJson)
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
console.log(`[Pulse Server Components] Generated client manifest with ${clientComponents.size} components`);
|
|
221
|
+
}
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
// Write manifest to filesystem after emit
|
|
225
|
+
compilation.hooks.afterProcessAssets.tap(pluginName, () => {
|
|
226
|
+
if (clientComponents.size === 0) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Build manifest object
|
|
231
|
+
const manifest = {
|
|
232
|
+
version: '1.0',
|
|
233
|
+
components: {}
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
for (const [componentId, info] of clientComponents.entries()) {
|
|
237
|
+
if (info.chunk) {
|
|
238
|
+
const base = this.options.base || '';
|
|
239
|
+
const chunkUrl = posix.join(base, info.chunk);
|
|
240
|
+
|
|
241
|
+
manifest.components[componentId] = {
|
|
242
|
+
id: componentId,
|
|
243
|
+
chunk: chunkUrl,
|
|
244
|
+
exports: ['default', componentId]
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Write to file system
|
|
250
|
+
if (this.options.manifestPath) {
|
|
251
|
+
try {
|
|
252
|
+
const manifestDir = dirname(this.options.manifestPath);
|
|
253
|
+
mkdirSync(manifestDir, { recursive: true });
|
|
254
|
+
writeFileSync(this.options.manifestPath, JSON.stringify(manifest, null, 2), 'utf-8');
|
|
255
|
+
console.log(`[Pulse Server Components] Manifest written to ${this.options.manifestPath}`);
|
|
256
|
+
} catch (error) {
|
|
257
|
+
console.warn(`[Pulse Server Components] Failed to write manifest: ${error.message}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// ============================================================================
|
|
266
|
+
// Helper Functions
|
|
267
|
+
// ============================================================================
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Create import violation error message
|
|
271
|
+
* @param {string} clientPath - Client Component path
|
|
272
|
+
* @param {string} serverPath - Server Component path
|
|
273
|
+
* @param {string} importSource - Import statement source
|
|
274
|
+
* @returns {string} Error message
|
|
275
|
+
*/
|
|
276
|
+
function createImportViolationError(clientPath, serverPath, importSource) {
|
|
277
|
+
const clientRelative = relative(process.cwd(), clientPath);
|
|
278
|
+
const serverRelative = relative(process.cwd(), serverPath);
|
|
279
|
+
|
|
280
|
+
return `
|
|
281
|
+
[Pulse] Import Violation: Client Component cannot import Server Component
|
|
282
|
+
at ${clientRelative}
|
|
283
|
+
importing ${importSource}
|
|
284
|
+
resolved to ${serverRelative}
|
|
285
|
+
|
|
286
|
+
Client Components can only import:
|
|
287
|
+
• Other Client Components ('use client')
|
|
288
|
+
• Shared utilities (no directive)
|
|
289
|
+
• Third-party packages
|
|
290
|
+
|
|
291
|
+
→ Move shared logic to a Client Component
|
|
292
|
+
→ Use Server Actions for server-side operations
|
|
293
|
+
→ Create a wrapper Client Component that calls Server Actions
|
|
294
|
+
|
|
295
|
+
See: https://pulse-js.fr/server-components#import-rules
|
|
296
|
+
`.trim();
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Helper function to add Server Components support to Webpack config
|
|
301
|
+
*
|
|
302
|
+
* @param {Object} options - Plugin options
|
|
303
|
+
* @returns {PulseServerComponentsPlugin} Webpack plugin instance
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* const { addServerComponentsSupport } = require('pulse-js-framework/loader/webpack-loader-server-components');
|
|
307
|
+
*
|
|
308
|
+
* module.exports = {
|
|
309
|
+
* plugins: [
|
|
310
|
+
* addServerComponentsSupport({ manifestPath: 'dist/.pulse-manifest.json' })
|
|
311
|
+
* ]
|
|
312
|
+
* };
|
|
313
|
+
*/
|
|
314
|
+
export function addServerComponentsSupport(options = {}) {
|
|
315
|
+
return new PulseServerComponentsPlugin(options);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Helper function to load client manifest (for SSR)
|
|
320
|
+
*
|
|
321
|
+
* @param {string} manifestPath - Path to manifest file
|
|
322
|
+
* @returns {Object} Client manifest
|
|
323
|
+
*/
|
|
324
|
+
export function loadClientManifest(manifestPath) {
|
|
325
|
+
try {
|
|
326
|
+
const { readFileSync } = require('fs');
|
|
327
|
+
const content = readFileSync(manifestPath, 'utf-8');
|
|
328
|
+
return JSON.parse(content);
|
|
329
|
+
} catch (error) {
|
|
330
|
+
console.warn(`Failed to load client manifest from ${manifestPath}:`, error.message);
|
|
331
|
+
return { version: '1.0', components: {} };
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Helper function to get client component chunk URL
|
|
337
|
+
*
|
|
338
|
+
* @param {Object} manifest - Client manifest
|
|
339
|
+
* @param {string} componentId - Component ID
|
|
340
|
+
* @returns {string|null} Chunk URL or null if not found
|
|
341
|
+
*/
|
|
342
|
+
export function getComponentChunk(manifest, componentId) {
|
|
343
|
+
return manifest.components[componentId]?.chunk || null;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Helper function to get all client component IDs
|
|
348
|
+
*
|
|
349
|
+
* @param {Object} manifest - Client manifest
|
|
350
|
+
* @returns {Set<string>} Set of component IDs
|
|
351
|
+
*/
|
|
352
|
+
export function getClientComponentIds(manifest) {
|
|
353
|
+
return new Set(Object.keys(manifest.components));
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export default PulseServerComponentsPlugin;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pulse-js-framework",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.1",
|
|
4
4
|
"description": "A declarative DOM framework with CSS selector-based structure and reactive pulsations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -90,13 +90,24 @@
|
|
|
90
90
|
"./compiler/parser": "./compiler/parser.js",
|
|
91
91
|
"./compiler/transformer": "./compiler/transformer.js",
|
|
92
92
|
"./compiler/preprocessor": "./compiler/preprocessor.js",
|
|
93
|
+
"./runtime/context": {
|
|
94
|
+
"types": "./types/context.d.ts",
|
|
95
|
+
"default": "./runtime/context.js"
|
|
96
|
+
},
|
|
97
|
+
"./runtime/errors": {
|
|
98
|
+
"types": "./types/errors.d.ts",
|
|
99
|
+
"default": "./runtime/errors.js"
|
|
100
|
+
},
|
|
93
101
|
"./core/errors": "./runtime/errors.js",
|
|
94
102
|
"./vite": {
|
|
95
103
|
"types": "./types/index.d.ts",
|
|
96
104
|
"default": "./loader/vite-plugin.js"
|
|
97
105
|
},
|
|
106
|
+
"./vite/server-components": "./loader/vite-plugin-server-components.js",
|
|
98
107
|
"./webpack": "./loader/webpack-loader.js",
|
|
108
|
+
"./webpack/server-components": "./loader/webpack-loader-server-components.js",
|
|
99
109
|
"./rollup": "./loader/rollup-plugin.js",
|
|
110
|
+
"./rollup/server-components": "./loader/rollup-plugin-server-components.js",
|
|
100
111
|
"./esbuild": "./loader/esbuild-plugin.js",
|
|
101
112
|
"./parcel": "./loader/parcel-plugin.js",
|
|
102
113
|
"./swc": "./loader/swc-plugin.js",
|
|
@@ -105,6 +116,7 @@
|
|
|
105
116
|
"./runtime/ssr-stream": "./runtime/ssr-stream.js",
|
|
106
117
|
"./runtime/ssr-mismatch": "./runtime/ssr-mismatch.js",
|
|
107
118
|
"./runtime/ssr-preload": "./runtime/ssr-preload.js",
|
|
119
|
+
"./runtime/server-components": "./runtime/server-components/index.js",
|
|
108
120
|
"./server": "./server/index.js",
|
|
109
121
|
"./server/express": "./server/express.js",
|
|
110
122
|
"./server/hono": "./server/hono.js",
|
|
@@ -135,7 +147,6 @@
|
|
|
135
147
|
"files": [
|
|
136
148
|
"index.js",
|
|
137
149
|
"cli/",
|
|
138
|
-
"core/",
|
|
139
150
|
"runtime/",
|
|
140
151
|
"compiler/",
|
|
141
152
|
"loader/",
|
|
@@ -147,108 +158,139 @@
|
|
|
147
158
|
"LICENSE"
|
|
148
159
|
],
|
|
149
160
|
"scripts": {
|
|
150
|
-
"
|
|
161
|
+
"bench": "node benchmarks/index.js",
|
|
162
|
+
"bench:json": "node benchmarks/index.js --json",
|
|
163
|
+
"build:netlify": "node scripts/build-netlify.js",
|
|
164
|
+
"docs": "node cli/index.js dev docs",
|
|
165
|
+
"test": "node scripts/sync-tests.js --fix && node scripts/run-all-tests.js",
|
|
166
|
+
"test:a11y": "node test/a11y.test.js",
|
|
167
|
+
"test:a11y-enhanced": "node test/a11y-enhanced.test.js",
|
|
168
|
+
"test:a11y-focus-coverage-boost": "node --test test/a11y-focus-coverage-boost.test.js",
|
|
169
|
+
"test:a11y-widgets-coverage-boost": "node --test test/a11y-widgets-coverage-boost.test.js",
|
|
170
|
+
"test:analyze": "node test/analyze.test.js",
|
|
171
|
+
"test:animation": "node --test test/animation.test.js",
|
|
172
|
+
"test:async": "node test/async.test.js",
|
|
173
|
+
"test:async-coverage": "node test/async-coverage.test.js",
|
|
174
|
+
"test:benchmarks": "node test/benchmarks.test.js",
|
|
175
|
+
"test:build": "node test/build.test.js",
|
|
176
|
+
"test:build-extended": "node --test test/build-extended.test.js",
|
|
177
|
+
"test:cli": "node test/cli.test.js",
|
|
178
|
+
"test:cli-create": "node test/cli-create.test.js",
|
|
179
|
+
"test:cli-help": "node --test test/cli-help.test.js",
|
|
180
|
+
"test:cli-logger": "node --test test/cli-logger.test.js",
|
|
181
|
+
"test:cli-mobile": "node --test test/cli-mobile.test.js",
|
|
182
|
+
"test:cli-release": "node --test test/cli-release.test.js",
|
|
183
|
+
"test:cli-ui": "node test/cli-ui.test.js",
|
|
151
184
|
"test:compiler": "node test/compiler.test.js",
|
|
152
|
-
"test:
|
|
153
|
-
"test:
|
|
154
|
-
"test:sourcemap-coverage-boost": "node --test test/sourcemap-coverage-boost.test.js",
|
|
185
|
+
"test:context": "node test/context.test.js",
|
|
186
|
+
"test:context-stress": "node test/context-stress.test.js",
|
|
155
187
|
"test:css-parsing": "node test/css-parsing.test.js",
|
|
156
|
-
"test:
|
|
157
|
-
"test:
|
|
188
|
+
"test:dev-server": "node --test test/dev-server.test.js",
|
|
189
|
+
"test:devtools": "node test/devtools.test.js",
|
|
190
|
+
"test:docs": "node test/docs.test.js",
|
|
191
|
+
"test:docs-nav": "node test/docs-navigation.test.js",
|
|
192
|
+
"test:docs-navigation": "node test/docs-navigation.test.js",
|
|
193
|
+
"test:doctor": "node test/doctor.test.js",
|
|
158
194
|
"test:dom": "node test/dom.test.js",
|
|
195
|
+
"test:dom-adapter": "node test/dom-adapter.test.js",
|
|
196
|
+
"test:dom-advanced": "node test/dom-advanced.test.js",
|
|
197
|
+
"test:dom-binding": "node test/dom-binding.test.js",
|
|
198
|
+
"test:dom-conditional": "node test/dom-conditional.test.js",
|
|
159
199
|
"test:dom-element": "node test/dom-element.test.js",
|
|
160
200
|
"test:dom-element-coverage-boost": "node --test test/dom-element-coverage-boost.test.js",
|
|
161
|
-
"test:dom-
|
|
162
|
-
"test:dom-conditional": "node test/dom-conditional.test.js",
|
|
201
|
+
"test:dom-event-delegate": "node test/dom-event-delegate.test.js",
|
|
163
202
|
"test:dom-lifecycle": "node test/dom-lifecycle.test.js",
|
|
203
|
+
"test:dom-list": "node test/dom-list.test.js",
|
|
204
|
+
"test:dom-recycle": "node test/dom-recycle.test.js",
|
|
164
205
|
"test:dom-selector": "node test/dom-selector.test.js",
|
|
165
|
-
"test:dom-
|
|
166
|
-
"test:dom-advanced": "node test/dom-advanced.test.js",
|
|
206
|
+
"test:dom-virtual-list": "node test/dom-virtual-list.test.js",
|
|
167
207
|
"test:enhanced-mock-adapter": "node test/enhanced-mock-adapter.test.js",
|
|
168
|
-
"test:
|
|
169
|
-
"test:
|
|
170
|
-
"test:
|
|
171
|
-
"test:hmr": "node test/hmr.test.js",
|
|
172
|
-
"test:hmr-coverage-boost": "node --test test/hmr-coverage-boost.test.js",
|
|
173
|
-
"test:lint": "node test/lint.test.js",
|
|
174
|
-
"test:format": "node test/format.test.js",
|
|
175
|
-
"test:analyze": "node test/analyze.test.js",
|
|
176
|
-
"test:cli": "node test/cli.test.js",
|
|
177
|
-
"test:cli-ui": "node test/cli-ui.test.js",
|
|
178
|
-
"test:cli-create": "node test/cli-create.test.js",
|
|
179
|
-
"test:lru-cache": "node test/lru-cache.test.js",
|
|
180
|
-
"test:utils": "node test/utils.test.js",
|
|
181
|
-
"test:utils-coverage": "node test/utils-coverage.test.js",
|
|
182
|
-
"test:docs": "node test/docs.test.js",
|
|
183
|
-
"test:docs-nav": "node test/docs-navigation.test.js",
|
|
184
|
-
"test:async": "node test/async.test.js",
|
|
185
|
-
"test:async-coverage": "node test/async-coverage.test.js",
|
|
208
|
+
"test:error-sanitizer": "node --test test/error-sanitizer.test.js",
|
|
209
|
+
"test:errors": "node test/errors.test.js",
|
|
210
|
+
"test:esbuild-plugin": "node test/esbuild-plugin.test.js",
|
|
186
211
|
"test:form": "node test/form.test.js",
|
|
212
|
+
"test:form-coverage": "node test/form-coverage.test.js",
|
|
213
|
+
"test:form-edge-cases": "node test/form-edge-cases.test.js",
|
|
187
214
|
"test:form-v2": "node test/form-v2.test.js",
|
|
188
|
-
"test:
|
|
189
|
-
"test:devtools": "node test/devtools.test.js",
|
|
190
|
-
"test:native": "node test/native.test.js",
|
|
191
|
-
"test:native-coverage-boost": "node --test test/native-coverage-boost.test.js",
|
|
192
|
-
"test:a11y": "node test/a11y.test.js",
|
|
193
|
-
"test:a11y-enhanced": "node test/a11y-enhanced.test.js",
|
|
194
|
-
"test:a11y-widgets-coverage-boost": "node --test test/a11y-widgets-coverage-boost.test.js",
|
|
195
|
-
"test:a11y-focus-coverage-boost": "node --test test/a11y-focus-coverage-boost.test.js",
|
|
196
|
-
"test:logger": "node test/logger.test.js",
|
|
197
|
-
"test:logger-prod": "node test/logger-prod.test.js",
|
|
198
|
-
"test:logger-coverage-boost": "node --test test/logger-coverage-boost.test.js",
|
|
199
|
-
"test:errors": "node test/errors.test.js",
|
|
200
|
-
"test:security": "node test/security.test.js",
|
|
201
|
-
"test:security-coverage-boost": "node --test test/security-coverage-boost.test.js",
|
|
202
|
-
"test:websocket": "node test/websocket.test.js",
|
|
203
|
-
"test:websocket-coverage-boost": "node --test test/websocket-coverage-boost.test.js",
|
|
215
|
+
"test:format": "node test/format.test.js",
|
|
204
216
|
"test:graphql": "node test/graphql.test.js",
|
|
205
217
|
"test:graphql-coverage": "node test/graphql-coverage.test.js",
|
|
206
|
-
"test:doctor": "node test/doctor.test.js",
|
|
207
|
-
"test:scaffold": "node test/scaffold.test.js",
|
|
208
|
-
"test:test-runner": "node test/test-runner.test.js",
|
|
209
|
-
"test:build": "node test/build.test.js",
|
|
210
|
-
"test:integration": "node test/integration.test.js",
|
|
211
|
-
"test:context-stress": "node test/context-stress.test.js",
|
|
212
|
-
"test:form-edge-cases": "node test/form-edge-cases.test.js",
|
|
213
|
-
"test:form-coverage": "node test/form-coverage.test.js",
|
|
214
218
|
"test:graphql-subscriptions": "node test/graphql-subscriptions.test.js",
|
|
215
219
|
"test:graphql-subscriptions-coverage-boost": "node --test test/graphql-subscriptions-coverage-boost.test.js",
|
|
220
|
+
"test:hmr": "node test/hmr.test.js",
|
|
221
|
+
"test:hmr-coverage-boost": "node --test test/hmr-coverage-boost.test.js",
|
|
222
|
+
"test:http": "node test/http.test.js",
|
|
216
223
|
"test:http-edge-cases": "node test/http-edge-cases.test.js",
|
|
224
|
+
"test:i18n": "node --test test/i18n.test.js",
|
|
225
|
+
"test:integration": "node test/integration.test.js",
|
|
217
226
|
"test:integration-advanced": "node test/integration-advanced.test.js",
|
|
218
|
-
"test:websocket-stress": "node test/websocket-stress.test.js",
|
|
219
|
-
"test:ssr": "node test/ssr.test.js",
|
|
220
|
-
"test:ssr-hydrator": "node test/ssr-hydrator.test.js",
|
|
221
|
-
"test:webpack-loader": "node test/webpack-loader.test.js",
|
|
222
|
-
"test:rollup-plugin": "node test/rollup-plugin.test.js",
|
|
223
|
-
"test:esbuild-plugin": "node test/esbuild-plugin.test.js",
|
|
224
|
-
"test:parcel-plugin": "node test/parcel-plugin.test.js",
|
|
225
|
-
"test:swc-plugin": "node test/swc-plugin.test.js",
|
|
226
|
-
"test:dom-recycle": "node test/dom-recycle.test.js",
|
|
227
|
-
"test:dom-virtual-list": "node test/dom-virtual-list.test.js",
|
|
228
|
-
"test:dom-event-delegate": "node test/dom-event-delegate.test.js",
|
|
229
|
-
"test:dom-binding": "node test/dom-binding.test.js",
|
|
230
227
|
"test:interceptor-manager": "node test/interceptor-manager.test.js",
|
|
231
|
-
"test:
|
|
228
|
+
"test:lint": "node test/lint.test.js",
|
|
229
|
+
"test:lite": "node test/lite.test.js",
|
|
230
|
+
"test:logger": "node test/logger.test.js",
|
|
231
|
+
"test:logger-coverage-boost": "node --test test/logger-coverage-boost.test.js",
|
|
232
|
+
"test:logger-prod": "node test/logger-prod.test.js",
|
|
233
|
+
"test:lru-cache": "node test/lru-cache.test.js",
|
|
232
234
|
"test:memory-cleanup": "node --test test/memory-cleanup.test.js",
|
|
233
|
-
"test:
|
|
235
|
+
"test:mutex": "node --test test/mutex.test.js",
|
|
236
|
+
"test:native": "node test/native.test.js",
|
|
237
|
+
"test:native-coverage-boost": "node --test test/native-coverage-boost.test.js",
|
|
238
|
+
"test:parcel-plugin": "node test/parcel-plugin.test.js",
|
|
239
|
+
"test:path-sanitizer": "node --test test/path-sanitizer.test.js",
|
|
240
|
+
"test:parser-coverage": "node test/parser-coverage.test.js",
|
|
234
241
|
"test:persistence": "node --test test/persistence.test.js",
|
|
235
242
|
"test:persistence-coverage-boost": "node --test test/persistence-coverage-boost.test.js",
|
|
236
|
-
"test:i18n": "node --test test/i18n.test.js",
|
|
237
243
|
"test:portal": "node --test test/portal.test.js",
|
|
238
|
-
"test:
|
|
239
|
-
"test:
|
|
240
|
-
"test:
|
|
241
|
-
"test:
|
|
244
|
+
"test:preprocessor": "node test/preprocessor.test.js",
|
|
245
|
+
"test:pulse": "node test/pulse.test.js",
|
|
246
|
+
"test:rollup-plugin": "node test/rollup-plugin.test.js",
|
|
247
|
+
"test:router": "node test/router.test.js",
|
|
248
|
+
"test:router-psc": "node --test test/router-psc-integration.test.js",
|
|
249
|
+
"test:router-psc-integration": "node test/router-psc-integration.test.js",
|
|
250
|
+
"test:scaffold": "node test/scaffold.test.js",
|
|
251
|
+
"test:security": "node test/security.test.js",
|
|
252
|
+
"test:security-coverage-boost": "node --test test/security-coverage-boost.test.js",
|
|
253
|
+
"test:security-regression": "node test/security-regression.test.js",
|
|
254
|
+
"test:server-utils": "node --test test/server-utils.test.js",
|
|
255
|
+
"test:server-actions": "node --test test/server-actions.test.js",
|
|
256
|
+
"test:server-actions-client": "node --test test/server-actions-client.test.js",
|
|
257
|
+
"test:server-actions-server-extended": "node --test test/server-actions-server-extended.test.js",
|
|
258
|
+
"test:server-adapters": "node --test test/server-adapters.test.js",
|
|
259
|
+
"test:server-components-build-tools": "node --test test/server-components-build-tools.test.js",
|
|
260
|
+
"test:server-components-client": "node --test test/server-components-client.test.js",
|
|
261
|
+
"test:server-components-compiler": "node --test test/server-components-compiler.test.js",
|
|
262
|
+
"test:server-components-core": "node --test test/server-components-core.test.js",
|
|
263
|
+
"test:server-components-csrf": "node --test test/server-components-csrf.test.js",
|
|
264
|
+
"test:server-components-ratelimit": "node --test test/server-components-ratelimit.test.js",
|
|
265
|
+
"test:server-components-ratelimit-extended": "node --test test/server-components-ratelimit-extended.test.js",
|
|
266
|
+
"test:server-components-security": "node --test test/server-components-security.test.js",
|
|
267
|
+
"test:server-components-security-comprehensive": "node --test test/server-components-security-comprehensive.test.js",
|
|
268
|
+
"test:server-components-serializer": "node --test test/server-components-serializer.test.js",
|
|
269
|
+
"test:server-components-validation": "node --test test/server-components-validation.test.js",
|
|
270
|
+
"test:sourcemap": "node test/sourcemap.test.js",
|
|
271
|
+
"test:sourcemap-coverage-boost": "node --test test/sourcemap-coverage-boost.test.js",
|
|
272
|
+
"test:sse": "node --test test/sse.test.js",
|
|
273
|
+
"test:ssg": "node --test test/ssg.test.js",
|
|
274
|
+
"test:ssr": "node test/ssr.test.js",
|
|
275
|
+
"test:ssr-directives": "node --test test/ssr-directives.test.js",
|
|
276
|
+
"test:ssr-hydrator": "node test/ssr-hydrator.test.js",
|
|
242
277
|
"test:ssr-mismatch": "node --test test/ssr-mismatch.test.js",
|
|
243
278
|
"test:ssr-preload": "node --test test/ssr-preload.test.js",
|
|
244
|
-
"test:ssr-
|
|
245
|
-
"test:
|
|
246
|
-
"test:
|
|
247
|
-
"
|
|
248
|
-
"
|
|
249
|
-
"
|
|
250
|
-
"
|
|
251
|
-
"
|
|
279
|
+
"test:ssr-stream": "node --test test/ssr-stream.test.js",
|
|
280
|
+
"test:store": "node test/store.test.js",
|
|
281
|
+
"test:sw": "node --test test/sw.test.js",
|
|
282
|
+
"test:swc-plugin": "node test/swc-plugin.test.js",
|
|
283
|
+
"test:sync": "node scripts/sync-tests.js",
|
|
284
|
+
"test:sync:fix": "node scripts/sync-tests.js --fix",
|
|
285
|
+
"test:test-runner": "node test/test-runner.test.js",
|
|
286
|
+
"test:utils": "node test/utils.test.js",
|
|
287
|
+
"test:utils-coverage": "node test/utils-coverage.test.js",
|
|
288
|
+
"test:vite-plugin": "node --test test/vite-plugin.test.js",
|
|
289
|
+
"test:webpack-loader": "node test/webpack-loader.test.js",
|
|
290
|
+
"test:websocket": "node test/websocket.test.js",
|
|
291
|
+
"test:websocket-coverage-boost": "node --test test/websocket-coverage-boost.test.js",
|
|
292
|
+
"test:websocket-stress": "node test/websocket-stress.test.js",
|
|
293
|
+
"version": "node scripts/sync-version.js"
|
|
252
294
|
},
|
|
253
295
|
"keywords": [
|
|
254
296
|
"framework",
|
|
@@ -275,7 +317,7 @@
|
|
|
275
317
|
"url": "https://github.com/vincenthirtz/pulse-js-framework/issues"
|
|
276
318
|
},
|
|
277
319
|
"engines": {
|
|
278
|
-
"node": ">=
|
|
320
|
+
"node": ">=20.0.0"
|
|
279
321
|
},
|
|
280
322
|
"dependencies": {},
|
|
281
323
|
"devDependencies": {}
|
package/runtime/async.js
CHANGED
|
@@ -795,6 +795,10 @@ export function usePolling(asyncFn, options) {
|
|
|
795
795
|
onError
|
|
796
796
|
} = options;
|
|
797
797
|
|
|
798
|
+
if (!interval || typeof interval !== 'number' || interval <= 0) {
|
|
799
|
+
throw new Error('usePolling: options.interval must be a positive number (milliseconds)');
|
|
800
|
+
}
|
|
801
|
+
|
|
798
802
|
const data = pulse(null);
|
|
799
803
|
const error = pulse(null);
|
|
800
804
|
const isPolling = pulse(false);
|