Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
71 lines
2.4 KiB
JavaScript
71 lines
2.4 KiB
JavaScript
import * as Y from 'yjs'
|
|
|
|
/**
|
|
* Durable persistence for collaborative documents.
|
|
*
|
|
* Hocuspocus only syncs the Y.js document in memory (and across instances via
|
|
* Redis). On its own nothing is written to Postgres, so edits are lost on room
|
|
* eviction. This extension implements `onStoreDocument` — which Hocuspocus
|
|
* calls debounced while editing and again when the last client disconnects —
|
|
* and ships the Y.js state to an internal app endpoint that converts it to
|
|
* ProseMirror JSON and writes it to document_block_content.
|
|
*
|
|
* Only `document:<tenant>:<id>` rooms are persisted. Ticket / notification /
|
|
* AI rooms are ignored. Errors are logged, never thrown: a failed persist must
|
|
* not disrupt the live editing session — Hocuspocus retries on the next
|
|
* debounce / unload.
|
|
*/
|
|
export class CollabPersistenceExtension {
|
|
constructor(config = {}) {
|
|
this.apiUrl = config.apiUrl || 'http://localhost:3000/api/internal/collab/persist'
|
|
this.apiKey = config.apiKey || ''
|
|
}
|
|
|
|
async onStoreDocument({ document, documentName }) {
|
|
if (!documentName || !documentName.startsWith('document:')) {
|
|
return
|
|
}
|
|
const parts = documentName.split(':')
|
|
if (parts.length !== 3) {
|
|
return
|
|
}
|
|
const [, tenantId, documentId] = parts
|
|
if (!tenantId || !documentId) {
|
|
return
|
|
}
|
|
|
|
const fragment = document.getXmlFragment('prosemirror')
|
|
if (!fragment || fragment.length === 0) {
|
|
// Fresh/empty room — don't overwrite stored content before the client
|
|
// has seeded it from the database.
|
|
return
|
|
}
|
|
|
|
if (!this.apiKey) {
|
|
console.error('[CollabPersistenceExtension] COLLAB_PERSIST_API_KEY not set; skipping persistence')
|
|
return
|
|
}
|
|
|
|
try {
|
|
const update = Buffer.from(Y.encodeStateAsUpdate(document)).toString('base64')
|
|
const response = await fetch(this.apiUrl, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'x-api-key': this.apiKey,
|
|
},
|
|
body: JSON.stringify({ tenantId, documentId, update }),
|
|
})
|
|
|
|
if (!response.ok) {
|
|
const errorBody = await response.text().catch(() => '')
|
|
console.error(
|
|
`[CollabPersistenceExtension] persist failed ${response.status} for ${documentName}: ${errorBody}`
|
|
)
|
|
}
|
|
} catch (error) {
|
|
console.error(`[CollabPersistenceExtension] persist error for ${documentName}:`, error)
|
|
}
|
|
}
|
|
}
|