Framework updates
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
1
node_modules/@jqhtml/core/dist/component.d.ts
generated
vendored
1
node_modules/@jqhtml/core/dist/component.d.ts
generated
vendored
@@ -317,6 +317,7 @@ export declare class Jqhtml_Component {
|
||||
on_render(): void;
|
||||
on_create(): void;
|
||||
on_load(): void | Promise<void>;
|
||||
after_load(): void | Promise<void>;
|
||||
on_ready(): Promise<void>;
|
||||
on_stop(): void;
|
||||
/**
|
||||
|
||||
2
node_modules/@jqhtml/core/dist/component.d.ts.map
generated
vendored
2
node_modules/@jqhtml/core/dist/component.d.ts.map
generated
vendored
@@ -1 +1 @@
|
||||
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../src/component.ts"],"names":[],"mappings":"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"}
|
||||
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../src/component.ts"],"names":[],"mappings":"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"}
|
||||
15
node_modules/@jqhtml/core/dist/index.cjs
generated
vendored
15
node_modules/@jqhtml/core/dist/index.cjs
generated
vendored
@@ -2800,6 +2800,9 @@ class Jqhtml_Component {
|
||||
Jqhtml_Local_Storage.set(cache_key, this.data);
|
||||
}
|
||||
}
|
||||
// Call after_load() on the real component (this.data frozen, full access to this.$, this.state)
|
||||
await this._call_lifecycle('after_load');
|
||||
this.trigger('after_load');
|
||||
return data_changed;
|
||||
}
|
||||
/**
|
||||
@@ -2943,6 +2946,8 @@ class Jqhtml_Component {
|
||||
this._update_debug_attrs();
|
||||
this._log_lifecycle('load', 'complete (use_cached_data - skipped on_load)');
|
||||
this.trigger('load');
|
||||
await this._call_lifecycle('after_load');
|
||||
this.trigger('after_load');
|
||||
return;
|
||||
}
|
||||
// Check if component implements cache_id() for custom cache key
|
||||
@@ -3019,6 +3024,8 @@ class Jqhtml_Component {
|
||||
this._update_debug_attrs();
|
||||
this._log_lifecycle('load', 'complete (follower)');
|
||||
this.trigger('load');
|
||||
await this._call_lifecycle('after_load');
|
||||
this.trigger('after_load');
|
||||
return;
|
||||
}
|
||||
// This component is a leader - execute on_load() on detached proxy
|
||||
@@ -3239,6 +3246,11 @@ class Jqhtml_Component {
|
||||
this._log_lifecycle('load', 'complete');
|
||||
// Emit lifecycle event
|
||||
this.trigger('load');
|
||||
// Call after_load() - runs on the REAL component (not detached proxy)
|
||||
// this.data is frozen (read-only), but this.$, this.state, this.args are accessible
|
||||
// Primary use case: clone this.data to this.state for widgets with complex in-memory manipulations
|
||||
await this._call_lifecycle('after_load');
|
||||
this.trigger('after_load');
|
||||
}
|
||||
finally {
|
||||
// Signal next in queue
|
||||
@@ -3714,6 +3726,7 @@ class Jqhtml_Component {
|
||||
on_render() { }
|
||||
on_create() { }
|
||||
on_load() { } // Override to fetch data asynchronously
|
||||
after_load() { } // Override to process loaded data (e.g., clone this.data to this.state)
|
||||
async on_ready() { }
|
||||
on_stop() { }
|
||||
/**
|
||||
@@ -5097,7 +5110,7 @@ function init(jQuery) {
|
||||
}
|
||||
}
|
||||
// Version - will be replaced during build with actual version from package.json
|
||||
const version = '2.3.36';
|
||||
const version = '2.3.37';
|
||||
// Default export with all functionality
|
||||
const jqhtml = {
|
||||
// Core
|
||||
|
||||
2
node_modules/@jqhtml/core/dist/index.cjs.map
generated
vendored
2
node_modules/@jqhtml/core/dist/index.cjs.map
generated
vendored
File diff suppressed because one or more lines are too long
15
node_modules/@jqhtml/core/dist/index.js
generated
vendored
15
node_modules/@jqhtml/core/dist/index.js
generated
vendored
@@ -2796,6 +2796,9 @@ class Jqhtml_Component {
|
||||
Jqhtml_Local_Storage.set(cache_key, this.data);
|
||||
}
|
||||
}
|
||||
// Call after_load() on the real component (this.data frozen, full access to this.$, this.state)
|
||||
await this._call_lifecycle('after_load');
|
||||
this.trigger('after_load');
|
||||
return data_changed;
|
||||
}
|
||||
/**
|
||||
@@ -2939,6 +2942,8 @@ class Jqhtml_Component {
|
||||
this._update_debug_attrs();
|
||||
this._log_lifecycle('load', 'complete (use_cached_data - skipped on_load)');
|
||||
this.trigger('load');
|
||||
await this._call_lifecycle('after_load');
|
||||
this.trigger('after_load');
|
||||
return;
|
||||
}
|
||||
// Check if component implements cache_id() for custom cache key
|
||||
@@ -3015,6 +3020,8 @@ class Jqhtml_Component {
|
||||
this._update_debug_attrs();
|
||||
this._log_lifecycle('load', 'complete (follower)');
|
||||
this.trigger('load');
|
||||
await this._call_lifecycle('after_load');
|
||||
this.trigger('after_load');
|
||||
return;
|
||||
}
|
||||
// This component is a leader - execute on_load() on detached proxy
|
||||
@@ -3235,6 +3242,11 @@ class Jqhtml_Component {
|
||||
this._log_lifecycle('load', 'complete');
|
||||
// Emit lifecycle event
|
||||
this.trigger('load');
|
||||
// Call after_load() - runs on the REAL component (not detached proxy)
|
||||
// this.data is frozen (read-only), but this.$, this.state, this.args are accessible
|
||||
// Primary use case: clone this.data to this.state for widgets with complex in-memory manipulations
|
||||
await this._call_lifecycle('after_load');
|
||||
this.trigger('after_load');
|
||||
}
|
||||
finally {
|
||||
// Signal next in queue
|
||||
@@ -3710,6 +3722,7 @@ class Jqhtml_Component {
|
||||
on_render() { }
|
||||
on_create() { }
|
||||
on_load() { } // Override to fetch data asynchronously
|
||||
after_load() { } // Override to process loaded data (e.g., clone this.data to this.state)
|
||||
async on_ready() { }
|
||||
on_stop() { }
|
||||
/**
|
||||
@@ -5093,7 +5106,7 @@ function init(jQuery) {
|
||||
}
|
||||
}
|
||||
// Version - will be replaced during build with actual version from package.json
|
||||
const version = '2.3.36';
|
||||
const version = '2.3.37';
|
||||
// Default export with all functionality
|
||||
const jqhtml = {
|
||||
// Core
|
||||
|
||||
2
node_modules/@jqhtml/core/dist/index.js.map
generated
vendored
2
node_modules/@jqhtml/core/dist/index.js.map
generated
vendored
File diff suppressed because one or more lines are too long
17
node_modules/@jqhtml/core/dist/jqhtml-core.esm.js
generated
vendored
17
node_modules/@jqhtml/core/dist/jqhtml-core.esm.js
generated
vendored
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* JQHTML Core v2.3.36
|
||||
* JQHTML Core v2.3.37
|
||||
* (c) 2025 JQHTML Team
|
||||
* Released under the MIT License
|
||||
*/
|
||||
@@ -2801,6 +2801,9 @@ class Jqhtml_Component {
|
||||
Jqhtml_Local_Storage.set(cache_key, this.data);
|
||||
}
|
||||
}
|
||||
// Call after_load() on the real component (this.data frozen, full access to this.$, this.state)
|
||||
await this._call_lifecycle('after_load');
|
||||
this.trigger('after_load');
|
||||
return data_changed;
|
||||
}
|
||||
/**
|
||||
@@ -2944,6 +2947,8 @@ class Jqhtml_Component {
|
||||
this._update_debug_attrs();
|
||||
this._log_lifecycle('load', 'complete (use_cached_data - skipped on_load)');
|
||||
this.trigger('load');
|
||||
await this._call_lifecycle('after_load');
|
||||
this.trigger('after_load');
|
||||
return;
|
||||
}
|
||||
// Check if component implements cache_id() for custom cache key
|
||||
@@ -3020,6 +3025,8 @@ class Jqhtml_Component {
|
||||
this._update_debug_attrs();
|
||||
this._log_lifecycle('load', 'complete (follower)');
|
||||
this.trigger('load');
|
||||
await this._call_lifecycle('after_load');
|
||||
this.trigger('after_load');
|
||||
return;
|
||||
}
|
||||
// This component is a leader - execute on_load() on detached proxy
|
||||
@@ -3240,6 +3247,11 @@ class Jqhtml_Component {
|
||||
this._log_lifecycle('load', 'complete');
|
||||
// Emit lifecycle event
|
||||
this.trigger('load');
|
||||
// Call after_load() - runs on the REAL component (not detached proxy)
|
||||
// this.data is frozen (read-only), but this.$, this.state, this.args are accessible
|
||||
// Primary use case: clone this.data to this.state for widgets with complex in-memory manipulations
|
||||
await this._call_lifecycle('after_load');
|
||||
this.trigger('after_load');
|
||||
}
|
||||
finally {
|
||||
// Signal next in queue
|
||||
@@ -3715,6 +3727,7 @@ class Jqhtml_Component {
|
||||
on_render() { }
|
||||
on_create() { }
|
||||
on_load() { } // Override to fetch data asynchronously
|
||||
after_load() { } // Override to process loaded data (e.g., clone this.data to this.state)
|
||||
async on_ready() { }
|
||||
on_stop() { }
|
||||
/**
|
||||
@@ -5098,7 +5111,7 @@ function init(jQuery) {
|
||||
}
|
||||
}
|
||||
// Version - will be replaced during build with actual version from package.json
|
||||
const version = '2.3.36';
|
||||
const version = '2.3.37';
|
||||
// Default export with all functionality
|
||||
const jqhtml = {
|
||||
// Core
|
||||
|
||||
2
node_modules/@jqhtml/core/dist/jqhtml-core.esm.js.map
generated
vendored
2
node_modules/@jqhtml/core/dist/jqhtml-core.esm.js.map
generated
vendored
File diff suppressed because one or more lines are too long
2
node_modules/@jqhtml/core/package.json
generated
vendored
2
node_modules/@jqhtml/core/package.json
generated
vendored
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@jqhtml/core",
|
||||
"version": "2.3.36",
|
||||
"version": "2.3.37",
|
||||
"description": "Core runtime library for JQHTML",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
|
||||
2
node_modules/@jqhtml/parser/dist/codegen.js
generated
vendored
2
node_modules/@jqhtml/parser/dist/codegen.js
generated
vendored
@@ -1385,7 +1385,7 @@ export class CodeGenerator {
|
||||
for (const [name, component] of this.components) {
|
||||
code += `// Component: ${name}\n`;
|
||||
code += `jqhtml_components.set('${name}', {\n`;
|
||||
code += ` _jqhtml_version: '2.3.36',\n`; // Version will be replaced during build
|
||||
code += ` _jqhtml_version: '2.3.37',\n`; // Version will be replaced during build
|
||||
code += ` name: '${name}',\n`;
|
||||
code += ` tag: '${component.tagName}',\n`;
|
||||
code += ` defaultAttributes: ${this.serializeAttributeObject(component.defaultAttributes)},\n`;
|
||||
|
||||
2
node_modules/@jqhtml/parser/package.json
generated
vendored
2
node_modules/@jqhtml/parser/package.json
generated
vendored
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@jqhtml/parser",
|
||||
"version": "2.3.36",
|
||||
"version": "2.3.37",
|
||||
"description": "JQHTML template parser - converts templates to JavaScript",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
|
||||
4
node_modules/@jqhtml/ssr/QUICKSTART.md
generated
vendored
4
node_modules/@jqhtml/ssr/QUICKSTART.md
generated
vendored
@@ -5,8 +5,8 @@
|
||||
Create `.npmrc` in your project root:
|
||||
|
||||
```
|
||||
@jqhtml:registry=https://privatenpm.hanson.xyz/
|
||||
//privatenpm.hanson.xyz/:_auth=anFodG1sOkFHbTMyNStFdklOQXdUMnN0S0g2cXc9PQ==
|
||||
@jqhtml:registry=https://npm.internal.hanson.xyz/
|
||||
//npm.internal.hanson.xyz/:_auth=anFodG1sOkFHbTMyNStFdklOQXdUMnN0S0g2cXc9PQ==
|
||||
```
|
||||
|
||||
## 2. Install
|
||||
|
||||
4
node_modules/@jqhtml/ssr/package.json
generated
vendored
4
node_modules/@jqhtml/ssr/package.json
generated
vendored
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@jqhtml/ssr",
|
||||
"version": "2.3.36",
|
||||
"version": "2.3.37",
|
||||
"description": "Server-Side Rendering for JQHTML components - renders components to HTML for SEO",
|
||||
"main": "src/index.js",
|
||||
"bin": {
|
||||
@@ -10,7 +10,7 @@
|
||||
"scripts": {
|
||||
"start": "node src/server.js --tcp 9876",
|
||||
"start:socket": "node src/server.js --socket /tmp/jqhtml-ssr.sock",
|
||||
"test": "node test/test-protocol.js && node test/test-storage.js && node test/test-server.js",
|
||||
"test": "node test/test-protocol.js && node test/test-storage.js && node test/test-server.js && node test/test-ajax-transport.js && node test/test-render-spa.js",
|
||||
"example": "node bin/jqhtml-ssr-example.js --help"
|
||||
},
|
||||
"keywords": [
|
||||
|
||||
15
node_modules/@jqhtml/ssr/src/bundle-cache.js
generated
vendored
15
node_modules/@jqhtml/ssr/src/bundle-cache.js
generated
vendored
@@ -5,6 +5,8 @@
|
||||
* Uses LRU (Least Recently Used) eviction strategy.
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
/**
|
||||
* LRU Cache for bundle sets
|
||||
*/
|
||||
@@ -123,8 +125,19 @@ function prepareBundleCode(bundles) {
|
||||
const codeChunks = [];
|
||||
|
||||
for (const bundle of bundles) {
|
||||
// Load code from filesystem path or use inline content
|
||||
let raw;
|
||||
if (bundle.path) {
|
||||
if (!fs.existsSync(bundle.path)) {
|
||||
throw new Error(`Bundle file not found: ${bundle.path}`);
|
||||
}
|
||||
raw = fs.readFileSync(bundle.path, 'utf-8');
|
||||
} else {
|
||||
raw = bundle.content;
|
||||
}
|
||||
|
||||
// Remove sourcemap comments
|
||||
let code = bundle.content.replace(/\/\/# sourceMappingURL=.*/g, '');
|
||||
let code = raw.replace(/\/\/# sourceMappingURL=.*/g, '');
|
||||
|
||||
// Add bundle marker comment for debugging
|
||||
code = `\n/* === Bundle: ${bundle.id} === */\n${code}`;
|
||||
|
||||
163
node_modules/@jqhtml/ssr/src/environment.js
generated
vendored
163
node_modules/@jqhtml/ssr/src/environment.js
generated
vendored
@@ -8,7 +8,7 @@
|
||||
const { JSDOM } = require('jsdom');
|
||||
const vm = require('vm');
|
||||
const { createStoragePair } = require('./storage.js');
|
||||
const { installHttpIntercept } = require('./http-intercept.js');
|
||||
const { installHttpIntercept, installAjaxTransport } = require('./http-intercept.js');
|
||||
|
||||
// CRITICAL: Require jQuery BEFORE any global.window is set
|
||||
// This ensures jQuery returns a factory function, not an auto-bound object
|
||||
@@ -21,7 +21,11 @@ class SSREnvironment {
|
||||
constructor(options = {}) {
|
||||
this.options = {
|
||||
baseUrl: options.baseUrl || 'http://localhost',
|
||||
timeout: options.timeout || 30000
|
||||
timeout: options.timeout || 30000,
|
||||
ssrToken: options.ssrToken || null,
|
||||
rsxapp: options.rsxapp || null,
|
||||
extractMeta: options.extractMeta || false,
|
||||
readySelector: options.readySelector || '#spa-root > *:first-child'
|
||||
};
|
||||
|
||||
this.dom = null;
|
||||
@@ -94,8 +98,8 @@ class SSREnvironment {
|
||||
this.window.__SSR__ = true;
|
||||
this.window.__JQHTML_SSR_MODE__ = true;
|
||||
|
||||
// Install HTTP interception (fetch + XHR URL rewriting)
|
||||
installHttpIntercept(this.window, this.options.baseUrl);
|
||||
// Install HTTP interception (fetch + XHR URL rewriting + optional SSR token)
|
||||
installHttpIntercept(this.window, this.options.baseUrl, this.options.ssrToken);
|
||||
|
||||
// Create jQuery bound to jsdom window
|
||||
this.$ = jqueryFactory(this.window);
|
||||
@@ -106,12 +110,20 @@ class SSREnvironment {
|
||||
this.window.$ = this.$;
|
||||
this.window.jQuery = this.$;
|
||||
|
||||
// Install $.ajaxTransport for real HTTP requests via jQuery $.ajax()
|
||||
// This ensures $.ajax() → Node fetch() instead of jsdom's limited XHR
|
||||
installAjaxTransport(this.window, this.options.baseUrl, this.options.ssrToken);
|
||||
|
||||
// Stub console_debug if bundles use it
|
||||
this.window.console_debug = function() {};
|
||||
global.console_debug = function() {};
|
||||
|
||||
// rsxapp config object (some bundles expect this)
|
||||
this.window.rsxapp = this.window.rsxapp || {};
|
||||
// rsxapp config object - inject from request or create empty default
|
||||
if (this.options.rsxapp) {
|
||||
this.window.rsxapp = this.options.rsxapp;
|
||||
} else {
|
||||
this.window.rsxapp = this.window.rsxapp || {};
|
||||
}
|
||||
global.rsxapp = this.window.rsxapp;
|
||||
|
||||
this.initialized = true;
|
||||
@@ -208,6 +220,145 @@ class SSREnvironment {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a SPA page by URL
|
||||
*
|
||||
* Assumes bundles have already been executed via execute(), which triggers
|
||||
* SPA framework boot (rsxapp.is_spa = true → route dispatch to URL).
|
||||
* Waits for the root component to reach ready state, then extracts HTML.
|
||||
*
|
||||
* @param {string} url - The URL path being rendered (for logging/errors)
|
||||
* @returns {Promise<{ html: string, meta: object, cache: object }>}
|
||||
*/
|
||||
async renderSpa(url) {
|
||||
if (!this.initialized) {
|
||||
throw new Error('SSR environment not initialized. Call init() first.');
|
||||
}
|
||||
|
||||
const $ = global.$;
|
||||
const readySelector = this.options.readySelector;
|
||||
|
||||
// Poll for root component to appear (SPA dispatch may be async)
|
||||
const component = await this._waitForComponent(readySelector);
|
||||
|
||||
// Wait for component ready (full lifecycle including children)
|
||||
const timeoutPromise = new Promise((_, reject) => {
|
||||
setTimeout(() => {
|
||||
reject(new Error(`SPA render exceeded ${this.options.timeout}ms timeout`));
|
||||
}, this.options.timeout);
|
||||
});
|
||||
|
||||
await Promise.race([
|
||||
component.ready(),
|
||||
timeoutPromise
|
||||
]);
|
||||
|
||||
// Extract HTML from #spa-root or the component itself
|
||||
const $root = $('#spa-root');
|
||||
const html = $root.length ? $root.html() : component.$.prop('outerHTML');
|
||||
|
||||
// Extract metadata if requested
|
||||
let meta = {};
|
||||
if (this.options.extractMeta) {
|
||||
meta = this._extractMeta(component);
|
||||
}
|
||||
|
||||
// Export cache state
|
||||
const cache = this.storage.exportAll();
|
||||
|
||||
return { html, meta, cache };
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll for a jqhtml component on the given selector
|
||||
* @param {string} selector - CSS selector to find the component element
|
||||
* @returns {Promise<object>} Component instance
|
||||
* @private
|
||||
*/
|
||||
_waitForComponent(selector) {
|
||||
const $ = global.$;
|
||||
const timeout = this.options.timeout;
|
||||
const startTime = Date.now();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const check = () => {
|
||||
const elapsed = Date.now() - startTime;
|
||||
if (elapsed > timeout) {
|
||||
reject(new Error(`SPA component not found on "${selector}" within ${timeout}ms timeout`));
|
||||
return;
|
||||
}
|
||||
|
||||
const $el = $(selector);
|
||||
if ($el.length > 0) {
|
||||
const component = $el.component ? $el.component() : null;
|
||||
if (component) {
|
||||
resolve(component);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(check, 10);
|
||||
};
|
||||
|
||||
check();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract page metadata from the rendered DOM and component
|
||||
* @param {object} component - The root component instance
|
||||
* @returns {{ title: string|null, description: string|null, og_image: string|null }}
|
||||
* @private
|
||||
*/
|
||||
_extractMeta(component) {
|
||||
const doc = global.document;
|
||||
const meta = {
|
||||
title: null,
|
||||
description: null,
|
||||
og_image: null
|
||||
};
|
||||
|
||||
// Check document.title
|
||||
if (doc && doc.title) {
|
||||
meta.title = doc.title;
|
||||
}
|
||||
|
||||
// Check if component has a page_title method
|
||||
if (component && typeof component.page_title === 'function') {
|
||||
try {
|
||||
const title = component.page_title();
|
||||
if (title && typeof title === 'string') {
|
||||
meta.title = title;
|
||||
}
|
||||
} catch (e) {
|
||||
// page_title() may throw - ignore
|
||||
}
|
||||
}
|
||||
|
||||
// Check meta tags in DOM
|
||||
if (doc) {
|
||||
const descEl = doc.querySelector('meta[name="description"]');
|
||||
if (descEl) {
|
||||
meta.description = descEl.getAttribute('content');
|
||||
}
|
||||
|
||||
const ogImageEl = doc.querySelector('meta[property="og:image"]');
|
||||
if (ogImageEl) {
|
||||
meta.og_image = ogImageEl.getAttribute('content');
|
||||
}
|
||||
|
||||
// Also check og:description as fallback
|
||||
if (!meta.description) {
|
||||
const ogDescEl = doc.querySelector('meta[property="og:description"]');
|
||||
if (ogDescEl) {
|
||||
meta.description = ogDescEl.getAttribute('content');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the environment and clean up globals
|
||||
*
|
||||
|
||||
131
node_modules/@jqhtml/ssr/src/http-intercept.js
generated
vendored
131
node_modules/@jqhtml/ssr/src/http-intercept.js
generated
vendored
@@ -138,12 +138,132 @@ function createXHRWrapper(baseUrl, OriginalXHR) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap an existing fetch function to inject the SSR token header on all requests
|
||||
* @param {function} fetchFn - The fetch function to wrap
|
||||
* @param {string} ssrToken - SSR token value
|
||||
* @returns {function} Wrapped fetch function
|
||||
*/
|
||||
function wrapFetchWithSsrToken(fetchFn, ssrToken) {
|
||||
return function ssrTokenFetch(url, options = {}) {
|
||||
const headers = { ...(options.headers || {}) };
|
||||
headers['X-SSR-Token'] = ssrToken;
|
||||
return fetchFn(url, { ...options, headers });
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Install SSR token injection on fetch and XHR
|
||||
* @param {Window} window - jsdom window object
|
||||
* @param {string} ssrToken - SSR token value
|
||||
*/
|
||||
function installSsrTokenIntercept(window, ssrToken) {
|
||||
if (!ssrToken) return;
|
||||
|
||||
// Wrap fetch with SSR token
|
||||
const currentFetch = window.fetch;
|
||||
window.fetch = wrapFetchWithSsrToken(currentFetch, ssrToken);
|
||||
|
||||
if (typeof global !== 'undefined') {
|
||||
global.fetch = window.fetch;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a custom jQuery $.ajaxTransport that uses Node's fetch() for real HTTP.
|
||||
*
|
||||
* This solves the problem of jsdom's XMLHttpRequest not making real network requests.
|
||||
* jQuery's $.ajax() will use this transport instead of XHR, so the chain becomes:
|
||||
* $.ajax() → ajaxTransport → Node fetch() → real HTTP request
|
||||
*
|
||||
* @param {Window} window - jsdom window object (must have jQuery on window.$)
|
||||
* @param {string} baseUrl - Base URL for resolving relative URLs
|
||||
* @param {string} [ssrToken] - Optional SSR token to include in requests
|
||||
*/
|
||||
function installAjaxTransport(window, baseUrl, ssrToken) {
|
||||
const $ = window.$;
|
||||
if (!$ || !$.ajaxTransport) return;
|
||||
|
||||
$.ajaxTransport('+*', function(options, originalOptions, jqXHR) {
|
||||
return {
|
||||
send: function(headers, completeCallback) {
|
||||
// Build absolute URL
|
||||
const url = resolveUrl(options.url || '', baseUrl);
|
||||
|
||||
// Build fetch options
|
||||
const fetchHeaders = {};
|
||||
|
||||
// Copy headers from jQuery, stripping auth headers
|
||||
for (const [name, value] of Object.entries(headers)) {
|
||||
const lowerName = name.toLowerCase();
|
||||
if (lowerName === 'authorization' || lowerName === 'cookie') continue;
|
||||
fetchHeaders[name] = value;
|
||||
}
|
||||
|
||||
// Inject SSR token if provided
|
||||
if (ssrToken) {
|
||||
fetchHeaders['X-SSR-Token'] = ssrToken;
|
||||
}
|
||||
|
||||
// Set content type if not already set
|
||||
if (options.contentType && !fetchHeaders['Content-Type']) {
|
||||
fetchHeaders['Content-Type'] = options.contentType;
|
||||
}
|
||||
|
||||
const fetchOptions = {
|
||||
method: options.type || 'GET',
|
||||
headers: fetchHeaders
|
||||
};
|
||||
|
||||
// Add body for non-GET requests
|
||||
if (options.data && options.type && options.type.toUpperCase() !== 'GET') {
|
||||
fetchOptions.body = typeof options.data === 'string'
|
||||
? options.data
|
||||
: JSON.stringify(options.data);
|
||||
}
|
||||
|
||||
// Use the globally available fetch (already has URL rewriting from createFetch)
|
||||
const fetchFn = globalThis.fetch || window.fetch;
|
||||
|
||||
fetchFn(url, fetchOptions)
|
||||
.then(async (response) => {
|
||||
const responseText = await response.text();
|
||||
const responseHeaders = {};
|
||||
if (response.headers && typeof response.headers.forEach === 'function') {
|
||||
response.headers.forEach((value, name) => {
|
||||
responseHeaders[name] = value;
|
||||
});
|
||||
}
|
||||
|
||||
const headerString = Object.entries(responseHeaders)
|
||||
.map(([k, v]) => `${k}: ${v}`)
|
||||
.join('\r\n');
|
||||
|
||||
completeCallback(
|
||||
response.status,
|
||||
response.statusText,
|
||||
{ text: responseText },
|
||||
headerString
|
||||
);
|
||||
})
|
||||
.catch((err) => {
|
||||
completeCallback(0, 'Network Error: ' + err.message, {}, '');
|
||||
});
|
||||
},
|
||||
abort: function() {
|
||||
// Cannot abort native fetch, but jQuery expects this method
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Install HTTP interception on a jsdom window
|
||||
* @param {Window} window - jsdom window object
|
||||
* @param {string} baseUrl - Base URL for URL resolution
|
||||
* @param {string} [ssrToken] - Optional SSR token for outgoing requests
|
||||
*/
|
||||
function installHttpIntercept(window, baseUrl) {
|
||||
function installHttpIntercept(window, baseUrl, ssrToken) {
|
||||
// Override fetch
|
||||
window.fetch = createFetch(baseUrl);
|
||||
|
||||
@@ -161,11 +281,18 @@ function installHttpIntercept(window, baseUrl) {
|
||||
global.XMLHttpRequest = WrappedXHR;
|
||||
}
|
||||
}
|
||||
|
||||
// Install SSR token on fetch/XHR if provided
|
||||
if (ssrToken) {
|
||||
installSsrTokenIntercept(window, ssrToken);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
resolveUrl,
|
||||
createFetch,
|
||||
createXHRWrapper,
|
||||
installHttpIntercept
|
||||
installHttpIntercept,
|
||||
installSsrTokenIntercept,
|
||||
installAjaxTransport
|
||||
};
|
||||
|
||||
6
node_modules/@jqhtml/ssr/src/index.js
generated
vendored
6
node_modules/@jqhtml/ssr/src/index.js
generated
vendored
@@ -8,13 +8,14 @@ const { SSRServer } = require('./server.js');
|
||||
const { SSREnvironment } = require('./environment.js');
|
||||
const { BundleCache, prepareBundleCode } = require('./bundle-cache.js');
|
||||
const { createStoragePair, SSR_Storage } = require('./storage.js');
|
||||
const { resolveUrl, createFetch, installHttpIntercept } = require('./http-intercept.js');
|
||||
const { resolveUrl, createFetch, installHttpIntercept, installAjaxTransport, installSsrTokenIntercept } = require('./http-intercept.js');
|
||||
const {
|
||||
ErrorCodes,
|
||||
parseRequest,
|
||||
successResponse,
|
||||
errorResponse,
|
||||
renderResponse,
|
||||
renderSpaResponse,
|
||||
pingResponse,
|
||||
flushCacheResponse,
|
||||
MessageBuffer
|
||||
@@ -39,6 +40,8 @@ module.exports = {
|
||||
resolveUrl,
|
||||
createFetch,
|
||||
installHttpIntercept,
|
||||
installAjaxTransport,
|
||||
installSsrTokenIntercept,
|
||||
|
||||
// Protocol
|
||||
ErrorCodes,
|
||||
@@ -46,6 +49,7 @@ module.exports = {
|
||||
successResponse,
|
||||
errorResponse,
|
||||
renderResponse,
|
||||
renderSpaResponse,
|
||||
pingResponse,
|
||||
flushCacheResponse,
|
||||
MessageBuffer
|
||||
|
||||
153
node_modules/@jqhtml/ssr/src/protocol.js
generated
vendored
153
node_modules/@jqhtml/ssr/src/protocol.js
generated
vendored
@@ -25,7 +25,11 @@ const ErrorCodes = {
|
||||
COMPONENT_NOT_FOUND: 'COMPONENT_NOT_FOUND', // 404 - Component not registered
|
||||
RENDER_ERROR: 'RENDER_ERROR', // 500 - Component threw during lifecycle
|
||||
RENDER_TIMEOUT: 'RENDER_TIMEOUT', // 504 - Render exceeded timeout
|
||||
INTERNAL_ERROR: 'INTERNAL_ERROR' // 500 - Unexpected server error
|
||||
INTERNAL_ERROR: 'INTERNAL_ERROR', // 500 - Unexpected server error
|
||||
ROUTE_NOT_FOUND: 'ROUTE_NOT_FOUND', // 404 - No SPA action matched the URL
|
||||
BUNDLE_LOAD_ERROR: 'BUNDLE_LOAD_ERROR', // 400 - Failed to read bundle from filesystem
|
||||
SPA_BOOT_ERROR: 'SPA_BOOT_ERROR', // 500 - SPA framework failed to initialize
|
||||
DATA_FETCH_ERROR: 'DATA_FETCH_ERROR' // 502 - on_load() HTTP request(s) failed
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -70,7 +74,7 @@ function parseRequest(message) {
|
||||
};
|
||||
}
|
||||
|
||||
const validTypes = ['render', 'ping', 'flush_cache'];
|
||||
const validTypes = ['render', 'render_spa', 'ping', 'flush_cache'];
|
||||
if (!validTypes.includes(parsed.type)) {
|
||||
return {
|
||||
ok: false,
|
||||
@@ -89,6 +93,13 @@ function parseRequest(message) {
|
||||
}
|
||||
}
|
||||
|
||||
if (parsed.type === 'render_spa') {
|
||||
const validation = validateRenderSpaPayload(parsed.payload);
|
||||
if (!validation.ok) {
|
||||
return validation;
|
||||
}
|
||||
}
|
||||
|
||||
return { ok: true, request: parsed };
|
||||
}
|
||||
|
||||
@@ -207,6 +218,142 @@ function validateRenderPayload(payload) {
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate render_spa request payload
|
||||
* @param {object} payload
|
||||
* @returns {{ ok: true } | { ok: false, error: object }}
|
||||
*/
|
||||
function validateRenderSpaPayload(payload) {
|
||||
if (!payload || typeof payload !== 'object') {
|
||||
return {
|
||||
ok: false,
|
||||
error: {
|
||||
code: ErrorCodes.PARSE_ERROR,
|
||||
message: 'Missing or invalid "payload" field for render_spa request'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Validate bundles
|
||||
if (!Array.isArray(payload.bundles) || payload.bundles.length === 0) {
|
||||
return {
|
||||
ok: false,
|
||||
error: {
|
||||
code: ErrorCodes.PARSE_ERROR,
|
||||
message: 'payload.bundles must be a non-empty array'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
for (let i = 0; i < payload.bundles.length; i++) {
|
||||
const bundle = payload.bundles[i];
|
||||
if (!bundle.id || typeof bundle.id !== 'string') {
|
||||
return {
|
||||
ok: false,
|
||||
error: {
|
||||
code: ErrorCodes.PARSE_ERROR,
|
||||
message: `payload.bundles[${i}].id must be a string`
|
||||
}
|
||||
};
|
||||
}
|
||||
// Must have either path or content
|
||||
const hasPath = bundle.path && typeof bundle.path === 'string';
|
||||
const hasContent = bundle.content && typeof bundle.content === 'string';
|
||||
if (!hasPath && !hasContent) {
|
||||
return {
|
||||
ok: false,
|
||||
error: {
|
||||
code: ErrorCodes.PARSE_ERROR,
|
||||
message: `payload.bundles[${i}] must have either "path" (string) or "content" (string)`
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Validate URL
|
||||
if (!payload.url || typeof payload.url !== 'string') {
|
||||
return {
|
||||
ok: false,
|
||||
error: {
|
||||
code: ErrorCodes.PARSE_ERROR,
|
||||
message: 'payload.url must be a string'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Validate rsxapp
|
||||
if (!payload.rsxapp || typeof payload.rsxapp !== 'object') {
|
||||
return {
|
||||
ok: false,
|
||||
error: {
|
||||
code: ErrorCodes.PARSE_ERROR,
|
||||
message: 'payload.rsxapp must be an object'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Validate options
|
||||
if (!payload.options || typeof payload.options !== 'object') {
|
||||
return {
|
||||
ok: false,
|
||||
error: {
|
||||
code: ErrorCodes.PARSE_ERROR,
|
||||
message: 'payload.options is required (must include baseUrl)'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (!payload.options.baseUrl || typeof payload.options.baseUrl !== 'string') {
|
||||
return {
|
||||
ok: false,
|
||||
error: {
|
||||
code: ErrorCodes.PARSE_ERROR,
|
||||
message: 'payload.options.baseUrl is required and must be a string'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (payload.options.timeout !== undefined && typeof payload.options.timeout !== 'number') {
|
||||
return {
|
||||
ok: false,
|
||||
error: {
|
||||
code: ErrorCodes.PARSE_ERROR,
|
||||
message: 'payload.options.timeout must be a number'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (payload.options.ssr_token !== undefined && typeof payload.options.ssr_token !== 'string') {
|
||||
return {
|
||||
ok: false,
|
||||
error: {
|
||||
code: ErrorCodes.PARSE_ERROR,
|
||||
message: 'payload.options.ssr_token must be a string'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a render_spa success response
|
||||
* @param {string} id - Request ID
|
||||
* @param {string} html - Rendered HTML
|
||||
* @param {object} meta - Page metadata { title, description, og_image }
|
||||
* @param {object} cache - Cache state { localStorage, sessionStorage }
|
||||
* @param {object} timing - Timing info { total_ms, bundle_load_ms, render_ms }
|
||||
* @returns {string} JSON string with newline
|
||||
*/
|
||||
function renderSpaResponse(id, html, meta, cache, timing) {
|
||||
return successResponse(id, {
|
||||
html,
|
||||
meta,
|
||||
cache,
|
||||
timing
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a success response
|
||||
* @param {string} id - Request ID
|
||||
@@ -329,9 +476,11 @@ module.exports = {
|
||||
ErrorCodes,
|
||||
parseRequest,
|
||||
validateRenderPayload,
|
||||
validateRenderSpaPayload,
|
||||
successResponse,
|
||||
errorResponse,
|
||||
renderResponse,
|
||||
renderSpaResponse,
|
||||
pingResponse,
|
||||
flushCacheResponse,
|
||||
MessageBuffer
|
||||
|
||||
92
node_modules/@jqhtml/ssr/src/server.js
generated
vendored
92
node_modules/@jqhtml/ssr/src/server.js
generated
vendored
@@ -14,6 +14,7 @@ const {
|
||||
ErrorCodes,
|
||||
parseRequest,
|
||||
renderResponse,
|
||||
renderSpaResponse,
|
||||
pingResponse,
|
||||
flushCacheResponse,
|
||||
errorResponse,
|
||||
@@ -153,6 +154,10 @@ class SSRServer {
|
||||
response = await this._handleRender(request);
|
||||
break;
|
||||
|
||||
case 'render_spa':
|
||||
response = await this._handleRenderSpa(request);
|
||||
break;
|
||||
|
||||
default:
|
||||
response = errorResponse(
|
||||
request.id,
|
||||
@@ -299,6 +304,93 @@ class SSRServer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle render_spa request
|
||||
* @param {object} request
|
||||
* @returns {Promise<string>} Response
|
||||
* @private
|
||||
*/
|
||||
async _handleRenderSpa(request) {
|
||||
const startTime = Date.now();
|
||||
const payload = request.payload;
|
||||
|
||||
// Get or prepare bundle code
|
||||
const cacheKey = BundleCache.generateKey(payload.bundles);
|
||||
let bundleCode = this.bundleCache.get(cacheKey);
|
||||
let bundleLoadMs = 0;
|
||||
|
||||
if (!bundleCode) {
|
||||
const bundleStartTime = Date.now();
|
||||
try {
|
||||
bundleCode = prepareBundleCode(payload.bundles);
|
||||
} catch (err) {
|
||||
return errorResponse(
|
||||
request.id,
|
||||
ErrorCodes.BUNDLE_LOAD_ERROR,
|
||||
err.message,
|
||||
err.stack
|
||||
);
|
||||
}
|
||||
this.bundleCache.set(cacheKey, bundleCode);
|
||||
bundleLoadMs = Date.now() - bundleStartTime;
|
||||
}
|
||||
|
||||
// Build the jsdom URL from baseUrl + requested URL path
|
||||
const baseUrlObj = new URL(payload.options.baseUrl);
|
||||
const spaUrl = `${baseUrlObj.protocol}//${baseUrlObj.host}${payload.url}`;
|
||||
|
||||
// Create fresh environment with SPA options
|
||||
const env = new SSREnvironment({
|
||||
baseUrl: spaUrl,
|
||||
timeout: payload.options.timeout || this.options.defaultTimeout,
|
||||
ssrToken: payload.options.ssr_token || null,
|
||||
rsxapp: payload.rsxapp || {},
|
||||
extractMeta: payload.options.extract_meta || false,
|
||||
readySelector: payload.options.ready_selector || '#spa-root > *:first-child'
|
||||
});
|
||||
|
||||
try {
|
||||
// Initialize environment
|
||||
env.init();
|
||||
|
||||
// Execute bundle code (SPA framework boots if rsxapp.is_spa === true)
|
||||
const execStartTime = Date.now();
|
||||
env.execute(bundleCode, `spa-bundles:${cacheKey}`);
|
||||
bundleLoadMs += Date.now() - execStartTime;
|
||||
|
||||
// Render SPA (waits for route dispatch + component ready)
|
||||
const renderStartTime = Date.now();
|
||||
const result = await env.renderSpa(payload.url);
|
||||
const renderMs = Date.now() - renderStartTime;
|
||||
|
||||
const totalMs = Date.now() - startTime;
|
||||
|
||||
return renderSpaResponse(request.id, result.html, result.meta, result.cache, {
|
||||
total_ms: totalMs,
|
||||
bundle_load_ms: bundleLoadMs,
|
||||
render_ms: renderMs
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
// Determine error type
|
||||
let errorCode = ErrorCodes.RENDER_ERROR;
|
||||
|
||||
if (err.message.includes('timeout')) {
|
||||
errorCode = ErrorCodes.RENDER_TIMEOUT;
|
||||
} else if (err.message.includes('Bundle file not found')) {
|
||||
errorCode = ErrorCodes.BUNDLE_LOAD_ERROR;
|
||||
} else if (err.message.includes('SPA')) {
|
||||
errorCode = ErrorCodes.SPA_BOOT_ERROR;
|
||||
}
|
||||
|
||||
return errorResponse(request.id, errorCode, err.message, err.stack);
|
||||
|
||||
} finally {
|
||||
// Always destroy environment to free resources
|
||||
env.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the server
|
||||
* @returns {Promise<void>}
|
||||
|
||||
2
node_modules/@jqhtml/vscode-extension/.version
generated
vendored
2
node_modules/@jqhtml/vscode-extension/.version
generated
vendored
@@ -1 +1 @@
|
||||
2.3.36
|
||||
2.3.37
|
||||
|
||||
Binary file not shown.
4
node_modules/@jqhtml/vscode-extension/package.json
generated
vendored
4
node_modules/@jqhtml/vscode-extension/package.json
generated
vendored
@@ -2,12 +2,12 @@
|
||||
"name": "@jqhtml/vscode-extension",
|
||||
"displayName": "JQHTML",
|
||||
"description": "Syntax highlighting and language support for JQHTML template files",
|
||||
"version": "2.3.36",
|
||||
"version": "2.3.37",
|
||||
"publisher": "jqhtml",
|
||||
"license": "MIT",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://privatenpm.hanson.xyz/"
|
||||
"registry": "https://npm.internal.hanson.xyz/"
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "echo Skipping prepublish",
|
||||
|
||||
Reference in New Issue
Block a user