Fix bin/publish: copy docs.dist from project root

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>
This commit is contained in:
root
2025-10-21 02:08:33 +00:00
commit f6fac6c4bc
79758 changed files with 10547827 additions and 0 deletions

View File

@@ -0,0 +1,215 @@
<?php
namespace App\Providers;
use App\RSpade\Core\Providers\Rsx_Preboot_Service;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\ViewErrorBag;
use Log;
class AppServiceProvider extends ServiceProvider
{
/**
* Query logging modes
*/
public const QUERY_LOG_NONE = 0; // Default - no logging
public const QUERY_LOG_ALL_STDOUT = 1; // Log all queries to stdout
public const QUERY_LOG_DESTRUCTIVE_STDOUT = 2; // Log only destructive queries to stdout
public const QUERY_LOG_ALL_LARAVEL = 3; // Log all queries to Laravel log
public const QUERY_LOG_DESTRUCTIVE_LARAVEL = 4; // Log only destructive queries to Laravel log
/**
* Current query logging mode
*
* @var int
*/
protected static $query_log_mode = self::QUERY_LOG_NONE;
/**
* Enable query echoing (backwards compatibility - sets ALL_STDOUT mode)
*
* @return void
*/
public static function enable_query_echo()
{
self::$query_log_mode = self::QUERY_LOG_ALL_STDOUT;
}
/**
* Disable query echoing
*
* @return void
*/
public static function disable_query_echo()
{
self::$query_log_mode = self::QUERY_LOG_NONE;
}
/**
* Set query logging mode
*
* @param int $mode One of the QUERY_LOG_* constants
* @return void
*/
public static function set_query_log_mode(int $mode)
{
self::$query_log_mode = $mode;
}
/**
* Check if a query is destructive (modifies data)
*
* @param string $sql
* @return bool
*/
protected static function is_destructive_query(string $sql): bool
{
$sql_upper = strtoupper(trim($sql));
// Check for destructive SQL operations
$destructive_patterns = [
'INSERT ',
'UPDATE ',
'DELETE ',
'ALTER ',
'CREATE ',
'DROP ',
'TRUNCATE ',
'REPLACE ',
'RENAME ',
'MODIFY ',
'ADD COLUMN',
'DROP COLUMN',
'ADD INDEX',
'DROP INDEX',
'ADD CONSTRAINT',
'DROP CONSTRAINT',
];
foreach ($destructive_patterns as $pattern) {
if (strpos($sql_upper, $pattern) === 0) {
return true;
}
}
return false;
}
/**
* Register any application services.
*
* @return void
*/
public function register()
{
// Initialize RSpade pre-boot services (debug locks, cache clearing, trace mode)
Rsx_Preboot_Service::init();
// Load JQHTML Laravel Bridge from node_modules
$jqhtmlBridge = base_path('node_modules/@jqhtml/core/laravel-bridge/autoload.php');
if (file_exists($jqhtmlBridge)) {
require_once $jqhtmlBridge;
}
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
// Override Ignition's exception renderer with our custom one that fixes multi-line display
if (!app()->environment('production')) {
$this->app->bind(
'Illuminate\Contracts\Foundation\ExceptionRenderer',
fn ($app) => $app->make(\App\RSpade\Integrations\Jqhtml\JqhtmlExceptionRenderer::class)
);
}
// Configure MySQL connection to use custom grammar with millisecond precision
$connection = DB::connection();
if ($connection->getDriverName() === 'mysql') {
$connection->setQueryGrammar(new \App\RSpade\Core\Database\Query\Grammars\Query_MySqlGrammar());
$connection->setSchemaGrammar(new \App\RSpade\Core\Database\Schema\Grammars\Schema_MySqlGrammar());
}
// Set up query listener for migration/normalize debugging
DB::listen(function ($query) {
if (self::$query_log_mode === self::QUERY_LOG_NONE) {
return;
}
$sql = $query->sql;
$is_destructive = self::is_destructive_query($sql);
switch (self::$query_log_mode) {
case self::QUERY_LOG_ALL_STDOUT:
echo $sql . "\n";
break;
case self::QUERY_LOG_DESTRUCTIVE_STDOUT:
if ($is_destructive) {
echo $sql . "\n";
}
break;
case self::QUERY_LOG_ALL_LARAVEL:
Log::debug('SQL Query: ' . $sql);
break;
case self::QUERY_LOG_DESTRUCTIVE_LARAVEL:
if ($is_destructive) {
Log::debug('SQL Query (Destructive): ' . $sql);
}
break;
}
});
// Share $errors variable with all views for @error directive
// Disabled for custom session handler
// View::composer('*', function ($view) {
// $view->with('errors', session()->get('errors', new ViewErrorBag));
// });
// Register custom database session handler to preserve user_id and site_id columns
// Disabled for custom session handler
// Session::extend('database', function ($app) {
// $connection = $app['db']->connection($app['config']['session.connection']);
// $table = $app['config']['session.table'];
// $lifetime = $app['config']['session.lifetime'];
//
// return new \App\RSpade\Core\Session\Custom_DatabaseSessionHandler(
// $connection,
// $table,
// $lifetime,
// $app
// );
// });
// Override cache:clear to integrate RSX clearing
if ($this->app->runningInConsole()) {
$this->override_cache_clear();
}
}
/**
* Override Laravel's cache:clear command to integrate with RSX
*
* @return void
*/
protected function override_cache_clear()
{
// Only override cache:clear to also clear RSX caches
$this->app->extend('command.cache.clear', function ($command, $app) {
return new \App\Console\Commands\CacheClearCommand();
});
}
}

26
app/Providers/CLAUDE.md Executable file
View File

@@ -0,0 +1,26 @@
# Providers Directory
This CLAUDE.md file contains a brief synopsis of the purpose of this directory, then a list of files in this directory with the file sizes of each file, and a short description and relevant key points of information for every file which is important in this directory. Unimportant files like images or temporary data directories are not listed in this file. When visiting this directory, the AI agent is instructed to do an ls on the directory to get the directory contents and file sizes - and if the file size diverges from the size in CLAUDE.md, that means the file has changed, and the description in CLAUDE.md is not up to date. This doesn't trigger this to be regenerated immediately, but let's say we wanted to know about a specific file by viewing CLAUDE.md and we discovered it was out of date, we would need to reread and update the documentation for that file in the CLAUDE.md at that time before we considered any details about it. CLAUDE.md might also contain other bits of information that is critical to know if you are looking at notes in the directory where the CLAUDE.md file lives.
## Directory Purpose
The Providers directory contains Laravel service providers which are the central configuration mechanism in Laravel applications. Service providers bootstrap the application by binding services in the service container, registering events, middleware, routes, and configuration.
## File Index
| File | Size | Description |
|------|------|-------------|
| AppServiceProvider.php | 940 bytes | General application service provider that refreshes session lifetime with each page request and shares constants (states and date formats) with all views. |
| AuthServiceProvider.php | 751 bytes | Authentication provider that defines model-to-policy mappings for authorization, registers Bridge and Talkgroup policies, and calls registerPolicies() to load these mappings. |
| BroadcastServiceProvider.php | 380 bytes | Broadcasting provider that registers routes for broadcasting and loads the routes/channels.php file for channel authorization. |
| EventServiceProvider.php | 926 bytes | Event handler provider that maps the Registered event to SendEmailVerificationNotification listener and disables automatic event discovery. |
| RecaptchaServiceProvider.php | 1,383 bytes | Custom provider for Google reCAPTCHA integration that adds a 'recaptcha' validator, skips validation in testing environment, and verifies reCAPTCHA responses via Google's API. |
| RouteServiceProvider.php | 1,452 bytes | Route configuration provider that defines HOME constant for redirection after authentication, configures rate limiting for API routes, and loads API, multi-tenant, and RSpade routes with appropriate middleware. |
## Implementation Notes
1. All service providers follow the Laravel provider pattern with register() and boot() methods.
2. The register() method happens before all providers are loaded, while boot() happens after all providers are loaded.
3. Custom providers like RecaptchaServiceProvider extend Laravel's base ServiceProvider.
4. The RouteServiceProvider has been extended to support multi-tenant and RSpade route files.
5. AppServiceProvider handles session management and constants sharing with views.

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class RouteServiceProvider extends ServiceProvider
{
/**
* Define your route model bindings, pattern filters, etc.
*
* @return void
*/
public function boot()
{
$this->routes(function () {
Route::middleware('web')
->group(base_path('routes/web.php'));
});
}
}