Implement JQHTML function cache ID system and fix bundle compilation Implement underscore prefix for system tables Fix JS syntax linter to support decorators and grant exception to Task system SPA: Update planning docs and wishlists with remaining features SPA: Document Navigation API abandonment and future enhancements Implement SPA browser integration with History API (Phase 1) Convert contacts view page to SPA action Convert clients pages to SPA actions and document conversion procedure SPA: Merge GET parameters and update documentation Implement SPA route URL generation in JavaScript and PHP Implement SPA bootstrap controller architecture Add SPA routing manual page (rsx:man spa) Add SPA routing documentation to CLAUDE.md Phase 4 Complete: Client-side SPA routing implementation Update get_routes() consumers for unified route structure Complete SPA Phase 3: PHP-side route type detection and is_spa flag Restore unified routes structure and Manifest_Query class Refactor route indexing and add SPA infrastructure Phase 3 Complete: SPA route registration in manifest Implement SPA Phase 2: Extract router code and test decorators Rename Jqhtml_Component to Component and complete SPA foundation setup 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
268 lines
9.5 KiB
Plaintext
Executable File
268 lines
9.5 KiB
Plaintext
Executable File
RSX_STORAGE(1) RSpade Manual RSX_STORAGE(1)
|
|
|
|
NAME
|
|
Rsx_Storage - Scoped browser storage helper with automatic fallback
|
|
|
|
SYNOPSIS
|
|
// Session storage (cleared on tab close)
|
|
Rsx_Storage.session_set(key, value)
|
|
Rsx_Storage.session_get(key)
|
|
Rsx_Storage.session_remove(key)
|
|
|
|
// Local storage (persists across sessions)
|
|
Rsx_Storage.local_set(key, value)
|
|
Rsx_Storage.local_get(key)
|
|
Rsx_Storage.local_remove(key)
|
|
|
|
DESCRIPTION
|
|
Rsx_Storage provides safe, scoped access to browser sessionStorage and
|
|
localStorage with automatic handling of unavailable storage, quota exceeded
|
|
errors, and scope invalidation.
|
|
|
|
Key features:
|
|
- Automatic scoping by session, user, site, and build version
|
|
- Graceful degradation when storage unavailable (returns null)
|
|
- Automatic quota management (clears and retries when full)
|
|
- Scope validation (clears stale data on scope change)
|
|
- Developer-friendly key format for easy inspection
|
|
|
|
SCOPING SYSTEM
|
|
All storage keys are automatically scoped to prevent data leakage between:
|
|
- Different sessions (window.rsxapp.session_hash - hashed, non-reversible)
|
|
- Different users (window.rsxapp.user.id)
|
|
- Different sites (window.rsxapp.site.id)
|
|
- Different builds (window.rsxapp.build_key)
|
|
|
|
The scope is calculated by combining these values into a suffix:
|
|
session_hash_user_id_site_id_build_key
|
|
|
|
This scope is stored in the special key `_rsx_scope_key`. On page load, if
|
|
this key doesn't exist or doesn't match the current scope, all RSpade keys
|
|
are cleared and the new scope is stored.
|
|
|
|
The session_hash is a server-generated HMAC hash of the session cookie using
|
|
the application's encryption key, making it non-reversible while maintaining
|
|
consistency per session.
|
|
|
|
Example scope suffix:
|
|
a1b2c3d4e5f6_42_1_v2.1.0
|
|
└─ session ──┘ │ │ └─ build
|
|
user │
|
|
site
|
|
|
|
KEY FORMAT
|
|
Keys are stored with an `rsx::` namespace prefix, followed by the developer
|
|
key, followed by the scope suffix:
|
|
|
|
rsx::developer_key::scope_suffix
|
|
|
|
Example:
|
|
rsx::flash_queue::abc123def456_42_1_v2.1.0
|
|
|
|
The `rsx::` prefix serves two purposes:
|
|
1. Identifies RSpade keys for safe selective clearing (scope changes, quota)
|
|
2. Prevents collisions with other JavaScript libraries
|
|
|
|
This format allows developers to easily identify keys in browser developer
|
|
tools while maintaining proper scoping and coexistence with third-party
|
|
libraries. When inspecting storage, you'll see the `rsx::` prefix, your
|
|
original key name, and the scope suffix.
|
|
|
|
STORAGE AVAILABILITY
|
|
Rsx_Storage automatically detects if sessionStorage or localStorage are
|
|
available. Storage may be unavailable due to:
|
|
|
|
- Private browsing mode (some browsers block storage)
|
|
- Browser security settings
|
|
- Storage quota set to 0
|
|
- Browser bugs or incompatibilities
|
|
|
|
When storage is unavailable:
|
|
- set() operations are silently ignored (no error)
|
|
- get() operations return null
|
|
- remove() operations are silently ignored
|
|
|
|
This allows the application to continue functioning even when storage is
|
|
unavailable, as long as the stored data is non-critical.
|
|
|
|
SIZE LIMIT
|
|
Individual values larger than 1 MB are automatically rejected and not stored.
|
|
|
|
When attempting to store data > 1 MB:
|
|
- Operation is silently skipped (no error thrown)
|
|
- Console warning logged with actual size
|
|
- get() will return null for that key
|
|
|
|
This prevents quota issues and ensures browser storage remains performant.
|
|
If you need to store large data, consider:
|
|
- Storing server-side in database
|
|
- Using IndexedDB for large client-side data
|
|
- Splitting data into smaller chunks
|
|
|
|
QUOTA EXCEEDED HANDLING
|
|
When a set() operation fails due to quota exceeded (storage full), Rsx_Storage
|
|
automatically:
|
|
|
|
1. Clears only RSpade keys (keys starting with `rsx::`)
|
|
2. Preserves other libraries' data
|
|
3. Restores the _rsx_scope_key
|
|
4. Retries the set() operation once
|
|
|
|
If the retry also fails, the error is logged and the operation is abandoned.
|
|
|
|
This ensures the application continues functioning even when storage is full,
|
|
and minimizes impact on other JavaScript libraries sharing the same storage.
|
|
Only RSpade's previously stored data will be lost.
|
|
|
|
SCOPE INVALIDATION
|
|
Storage is automatically validated before every write operation. When the scope
|
|
changes, only RSpade keys (starting with `rsx::`) are cleared, preserving other
|
|
libraries' data.
|
|
|
|
Scope changes occur when:
|
|
|
|
- User logs in/out (user ID changes)
|
|
- User switches sites (site ID changes)
|
|
- Application is updated (build key changes)
|
|
- Session changes (rsx cookie changes)
|
|
|
|
This prevents stale data from one context bleeding into another context.
|
|
|
|
Example: User A logs in, stores preferences, logs out. User B logs in on the
|
|
same browser. User B sees clean RSpade storage, not User A's data. Other
|
|
libraries' data (e.g., analytics cookies, third-party preferences) remains
|
|
intact.
|
|
|
|
VOLATILE STORAGE WARNING
|
|
Browser storage is VOLATILE and can be cleared at any time. Never store data
|
|
critical to application functionality.
|
|
|
|
Storage can be lost due to:
|
|
- User clearing browser data
|
|
- Private browsing mode restrictions
|
|
- Quota exceeded errors (automatic clear + retry)
|
|
- Scope changes (logout, build update, session change)
|
|
- Browser storage unavailable
|
|
- Storage corruption or browser bugs
|
|
|
|
ONLY store data that is:
|
|
- Cached for performance (can be re-fetched)
|
|
- UI convenience state (non-essential)
|
|
- Transient messages (flash alerts, notifications)
|
|
|
|
If data is REQUIRED for the application to function correctly, store it
|
|
server-side in the database or PHP session.
|
|
|
|
EXAMPLES
|
|
Cache API response data (sessionStorage)
|
|
// Store cached data
|
|
const users = await fetch_users();
|
|
Rsx_Storage.session_set('cached_users', users);
|
|
|
|
// Retrieve cached data
|
|
let users = Rsx_Storage.session_get('cached_users');
|
|
if (!users) {
|
|
users = await fetch_users();
|
|
Rsx_Storage.session_set('cached_users', users);
|
|
}
|
|
|
|
Persist UI preferences (localStorage)
|
|
// Save theme preference
|
|
Rsx_Storage.local_set('theme', 'dark');
|
|
|
|
// Load theme preference
|
|
const theme = Rsx_Storage.local_get('theme') || 'light';
|
|
apply_theme(theme);
|
|
|
|
Store flash alert queue (sessionStorage)
|
|
// Queue persists across page navigation
|
|
Rsx_Storage.session_set('flash_queue', messages);
|
|
|
|
// Restore queue on next page
|
|
const messages = Rsx_Storage.session_get('flash_queue') || [];
|
|
|
|
Complex data structures
|
|
// Automatically JSON serialized
|
|
Rsx_Storage.local_set('user_prefs', {
|
|
theme: 'dark',
|
|
sidebar_collapsed: true,
|
|
recent_items: [1, 2, 3]
|
|
});
|
|
|
|
// Automatically JSON parsed
|
|
const prefs = Rsx_Storage.local_get('user_prefs');
|
|
console.log(prefs.theme); // 'dark'
|
|
|
|
Handling unavailable storage
|
|
// Always check for null (storage unavailable or key not found)
|
|
const cached = Rsx_Storage.session_get('data');
|
|
if (cached) {
|
|
use_cached_data(cached);
|
|
} else {
|
|
fetch_fresh_data();
|
|
}
|
|
|
|
Removing stale data
|
|
// Clean up when no longer needed
|
|
Rsx_Storage.session_remove('temp_data');
|
|
|
|
SESSIONSTORAGE VS LOCALSTORAGE
|
|
sessionStorage:
|
|
- Cleared when tab/window closes
|
|
- Not shared across tabs/windows
|
|
- Use for: temporary data, current session state, flash messages
|
|
|
|
localStorage:
|
|
- Persists across browser sessions
|
|
- Shared across all tabs/windows of same origin
|
|
- Use for: user preferences, cached data, long-term UI state
|
|
|
|
Both are scoped identically by Rsx_Storage (cookie, user, site, build).
|
|
|
|
MIGRATION FROM NATIVE STORAGE
|
|
If you're currently using sessionStorage/localStorage directly:
|
|
|
|
Before:
|
|
sessionStorage.setItem('my_key', JSON.stringify(data));
|
|
const data = JSON.parse(sessionStorage.getItem('my_key'));
|
|
sessionStorage.removeItem('my_key');
|
|
|
|
After:
|
|
Rsx_Storage.session_set('my_key', data);
|
|
const data = Rsx_Storage.session_get('my_key');
|
|
Rsx_Storage.session_remove('my_key');
|
|
|
|
Benefits:
|
|
- No manual JSON.stringify/parse
|
|
- Automatic scoping (prevents data leakage)
|
|
- Graceful handling of unavailable storage
|
|
- Automatic quota management
|
|
- Scope validation
|
|
|
|
DEBUGGING
|
|
Inspect storage in browser developer tools:
|
|
|
|
1. Open Developer Tools (F12)
|
|
2. Navigate to Application tab (Chrome) or Storage tab (Firefox)
|
|
3. Expand Session Storage or Local Storage
|
|
4. Look for keys matching: rsx::your_key::scope_suffix
|
|
|
|
The _rsx_scope_key shows the current active scope.
|
|
All RSpade keys are prefixed with `rsx::` for easy identification.
|
|
|
|
Console logging:
|
|
- Scope changes: "[Rsx_Storage] Scope changed, clearing RSpade keys only"
|
|
- First use: "[Rsx_Storage] Initializing scope (first use)"
|
|
- Quota exceeded: "[Rsx_Storage] Quota exceeded, clearing RSpade keys"
|
|
- Keys cleared: "[Rsx_Storage] Cleared X RSpade keys"
|
|
- Errors: "[Rsx_Storage] Failed to..."
|
|
|
|
FILE LOCATION
|
|
/system/app/RSpade/Core/Js/Rsx_Storage.js
|
|
|
|
SEE ALSO
|
|
Flash Alert system (uses Rsx_Storage for queue persistence)
|
|
php artisan rsx:man flash_alert
|
|
|
|
RSPADE January 2025 RSX_STORAGE(1)
|