Persistence
Jspreadsheet Server provides an abstract, event-driven layer for handling data persistence. You implement five handlers (load, create, change, destroy and replace) backed by any database, version-control scheme or queue. The server never talks to storage directly.
The handlers
The exact payloads, ordering guarantees and failure semantics are specified in the persistence contract.
load
load(guid, auth, cachedConfiguration) returns the document configuration for a GUID, as an object or a JSON string, or false for not found. When the document is already live in the server cache, its current configuration is passed as cachedConfiguration and can be returned directly, skipping the database read.
create
create(guid, config, auth) persists a new spreadsheet. The configuration arrives parsed and validated: every worksheet has a worksheetName and a minted worksheetId, and document-level namespace and version are set.
change
change(guid, changes, auth, onerror) is called once per applied operation, in order, with { instance, worksheet, method, args }. On persistence failure, call onerror(error): the server then emits forceRefresh to the document's room.
destroy
destroy(guid, auth) deletes the spreadsheet. When the handler returns truthy, the server also drops the document from its memory cache, emits forceRefresh to the room and disconnects every connected socket.
replace
replace(guid, config, auth) performs a full-document overwrite. The snapshot-restore route calls it to write a restored configuration wholesale; when no replace handler is defined, the server falls back to destroy followed by create. The incremental adapters also use their own replace internally for failure resynchronization.
destroyCache (optional)
destroyCache(guid, config) is called when the server removes a document from its memory cache (deletion, garbage collection or cache-size eviction). The final serialized configuration is only computed, an expensive operation on large documents, when this handler is defined. Adapters that keep a hot copy outside the server process use it to drop that copy.
Example: raw handlers against Redis
Complete implementation against a Redis client
The event layer does not require an adapter. The following is a complete implementation directly against a Redis client, with no access control, to show the structure:
const server = require('@jspreadsheet/server');
const { createClient } = require("redis");
require('dotenv').config();
const client = createClient({
socket: {
host: 'localhost',
port: 6379
},
});
// Connect to Redis
client.connect();
server({
port: 3000,
// Socket.IO server configuration
config: {
cors: {
origin: "*"
},
},
error: async function(e) {
console.log(e);
},
beforeConnect: async function(auth) {
return true;
},
load: async function(guid) {
return await client.get(guid);
},
create: async function(guid, config) {
const result = await client.exists(guid);
if (result) {
// A spreadsheet already exists
return false;
} else {
// Create a new spreadsheet
await client.set(guid, JSON.stringify(config));
return true;
}
},
destroy: async function(guid) {
return await client.del(guid)
.then(() => true)
.catch(() => false);
},
change: async function(guid, changes) {
// Get the live configuration from the server cache
let config = changes.instance.getConfig();
// Save it wholesale on Redis
await client.set(guid, JSON.stringify(config));
},
license: {
clientId: process.env.JSS_CLIENT,
licenseKey: process.env.JSS_LICENSE,
},
});
Full-document write caveat
This example re-serializes the full document on every update, regardless of size. That is acceptable for small documents; for larger documents, batch the writes or persist the operations themselves. The upgrade path is described step by step in Build your own adapter.
Adapters
For convenience, prebuilt implementations of this event layer exist for MongoDB, PostgreSQL and Redis. The MongoDB and PostgreSQL adapters provide incremental per-operation writes, per-document write queues and failure recovery; the Redis adapter is a snapshot store, as covered in Adapters. The PostgreSQL adapter is documented in depth as a reference implementation.