Fix bin/publish: use correct .env path for rspade_system Fix bin/publish script: prevent grep exit code 1 from terminating script 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
199 lines
8.8 KiB
JavaScript
Executable File
199 lines
8.8 KiB
JavaScript
Executable File
// @FILE-SUBCLASS-01-EXCEPTION
|
|
|
|
/**
|
|
* Client-side Ajax class for making API calls to RSX controllers
|
|
*
|
|
* Mirrors the PHP Ajax::call (Ajax::internal) functionality for browser-side JavaScript
|
|
*/
|
|
class Ajax {
|
|
/**
|
|
* Make an AJAX call to an RSX controller action
|
|
*
|
|
* All calls are automatically batched using Rsx_Ajax_Batch unless
|
|
* window.rsxapp.ajax_disable_batching is true (for debugging).
|
|
*
|
|
* @param {string} controller - The controller class name (e.g., 'User_Controller')
|
|
* @param {string} action - The action method name (e.g., 'get_profile')
|
|
* @param {object} params - Parameters to send to the action
|
|
* @returns {Promise} - Resolves with the return value, rejects with error
|
|
*/
|
|
static async call(controller, action, params = {}) {
|
|
// Route through batch system
|
|
return Rsx_Ajax_Batch.call(controller, action, params);
|
|
}
|
|
|
|
/**
|
|
* DEPRECATED: Direct call implementation (preserved for reference)
|
|
* This is now handled by Rsx_Ajax_Batch
|
|
* @private
|
|
*/
|
|
static async _call_direct(controller, action, params = {}) {
|
|
// Build the endpoint URL
|
|
const url = `/_ajax/${controller}/${action}`;
|
|
|
|
// Log the AJAX call using console_debug
|
|
if (typeof Debugger !== 'undefined' && Debugger.console_debug) {
|
|
Debugger.console_debug('AJAX', `Calling ${controller}.${action}`, params);
|
|
}
|
|
|
|
return new Promise((resolve, reject) => {
|
|
$.ajax({
|
|
url: url,
|
|
method: 'POST',
|
|
data: params,
|
|
dataType: 'json',
|
|
__local_integration: true, // Bypass $.ajax override - this is the official Ajax endpoint pattern
|
|
success: (response) => {
|
|
// Handle console_debug messages if present
|
|
if (response.console_debug && Array.isArray(response.console_debug)) {
|
|
response.console_debug.forEach((msg) => {
|
|
// Messages must be structured as [channel, [arguments]]
|
|
if (!Array.isArray(msg) || msg.length !== 2) {
|
|
throw new Error('Invalid console_debug message format - expected [channel, [arguments]]');
|
|
}
|
|
const [channel, args] = msg;
|
|
// Output with channel as first argument, then spread the arguments
|
|
console.log(channel, ...args);
|
|
});
|
|
}
|
|
|
|
// Check if the response was successful
|
|
if (response.success === true) {
|
|
// Process the return value to instantiate any ORM models
|
|
const processedValue = Rsx_Js_Model._instantiate_models_recursive(response._ajax_return_value);
|
|
// Return the processed value
|
|
resolve(processedValue);
|
|
} else {
|
|
// Handle error responses
|
|
const error_type = response.error_type || 'unknown_error';
|
|
const reason = response.reason || 'Unknown error occurred';
|
|
const details = response.details || {};
|
|
|
|
// Handle specific error types
|
|
switch (error_type) {
|
|
case 'response_auth_required':
|
|
console.error(
|
|
'The user is no longer authenticated, this is a placeholder for future code which handles this scenario.'
|
|
);
|
|
// Create an error object similar to PHP exceptions
|
|
const auth_error = new Error(reason);
|
|
auth_error.type = 'auth_required';
|
|
auth_error.details = details;
|
|
reject(auth_error);
|
|
break;
|
|
|
|
case 'response_unauthorized':
|
|
console.error(
|
|
'The user is unauthorized to perform this action, this is a placeholder for future code which handles this scenario.'
|
|
);
|
|
const unauth_error = new Error(reason);
|
|
unauth_error.type = 'unauthorized';
|
|
unauth_error.details = details;
|
|
reject(unauth_error);
|
|
break;
|
|
|
|
case 'response_form_error':
|
|
// Form validation errors
|
|
const form_error = new Error(reason);
|
|
form_error.type = 'form_error';
|
|
form_error.details = details;
|
|
reject(form_error);
|
|
break;
|
|
|
|
case 'response_fatal_error':
|
|
// Fatal errors
|
|
const fatal_error = new Error(reason);
|
|
fatal_error.type = 'fatal_error';
|
|
fatal_error.details = details;
|
|
|
|
// Log to server if browser error logging is enabled
|
|
Debugger.log_error({
|
|
message: `Ajax Fatal Error: ${reason}`,
|
|
type: 'ajax_fatal',
|
|
endpoint: url,
|
|
details: details,
|
|
});
|
|
|
|
reject(fatal_error);
|
|
break;
|
|
|
|
default:
|
|
// Unknown error type
|
|
const generic_error = new Error(reason);
|
|
generic_error.type = error_type;
|
|
generic_error.details = details;
|
|
reject(generic_error);
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
error: (xhr, status, error) => {
|
|
// Handle network or server errors
|
|
let error_message = 'Network or server error';
|
|
|
|
if (xhr.responseJSON && xhr.responseJSON.message) {
|
|
error_message = xhr.responseJSON.message;
|
|
} else if (xhr.responseText) {
|
|
try {
|
|
const response = JSON.parse(xhr.responseText);
|
|
if (response.message) {
|
|
error_message = response.message;
|
|
}
|
|
} catch (e) {
|
|
// If response is not JSON, use the status text
|
|
error_message = `${status}: ${error}`;
|
|
}
|
|
} else {
|
|
error_message = `${status}: ${error}`;
|
|
}
|
|
|
|
const network_error = new Error(error_message);
|
|
network_error.type = 'network_error';
|
|
network_error.status = xhr.status;
|
|
network_error.statusText = status;
|
|
|
|
// Log server errors (500+) to the server if browser error logging is enabled
|
|
if (xhr.status >= 500) {
|
|
Debugger.log_error({
|
|
message: `Ajax Server Error ${xhr.status}: ${error_message}`,
|
|
type: 'ajax_server_error',
|
|
endpoint: url,
|
|
status: xhr.status,
|
|
statusText: status,
|
|
});
|
|
}
|
|
|
|
reject(network_error);
|
|
},
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Parses an AJAX URL into controller and action
|
|
* @param {string} url - URL in format '/_ajax/Controller_Name/action_name'
|
|
* @returns {Object} Object with {controller: string, action: string}
|
|
* @throws {Error} If URL doesn't start with /_ajax or has invalid structure
|
|
*/
|
|
static ajax_url_to_controller_action(url) {
|
|
if (!url.startsWith('/_ajax')) {
|
|
throw new Error(`URL must start with /_ajax, got: ${url}`);
|
|
}
|
|
|
|
const parts = url.split('/').filter((part) => part !== '');
|
|
|
|
if (parts.length < 2) {
|
|
throw new Error(`Invalid AJAX URL structure: ${url}`);
|
|
}
|
|
|
|
if (parts.length > 3) {
|
|
throw new Error(`AJAX URL has too many segments: ${url}`);
|
|
}
|
|
|
|
const controller = parts[1];
|
|
const action = parts[2] || 'index';
|
|
|
|
return { controller, action };
|
|
}
|
|
}
|