Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .github/workflows/web-sync-server-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:

- uses: actions/setup-node@v4
with:
node-version: "20"
node-version: "26"

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/web-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ jobs:

- uses: actions/setup-node@v4
with:
node-version: '20'
node-version: '26'

- name: Setup pnpm
uses: pnpm/action-setup@v4.0.0
uses: pnpm/action-setup@v4
with:
version: 9
package_json_file: moon/package.json

- name: Get pnpm store directory
shell: bash
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ orion-server/docker-compose.override.yml
# Claude Code configuration and cache
.claude

# pnpm content-addressable store (local / custom store-dir)
.pnpm-store

tools/**

.libra
Expand Down
1 change: 1 addition & 0 deletions moon/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
node_modules
.pnp
.pnp.js
.pnpm-store
dist
*.tsbuildinfo

Expand Down
2 changes: 1 addition & 1 deletion moon/.nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20
26
6 changes: 3 additions & 3 deletions moon/apps/sync-server/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# syntax = docker/dockerfile:1

FROM node:22-slim AS base
FROM node:26-slim AS base

# configure pnpm
# configure pnpm (node:26 images no longer ship corepack)
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME/bin:$PNPM_HOME:$PATH"
RUN corepack enable && corepack prepare pnpm@9.7.1 --activate
RUN npm install -g pnpm@11.17.0


# ENV SENTRY_PROPERTIES=sentry.properties
Expand Down
3 changes: 0 additions & 3 deletions moon/apps/sync-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"build": "tsup",
"clean": "rm -rf .turbo dist node_modules",
"dev": "tsup --watch --onSuccess \"node dist/index.mjs\"",
"sentry:sourcemaps": "sentry-cli sourcemaps inject --org mega --project sync-server ./dist && sentry-cli sourcemaps upload --org mega --project sync-server --log-level=debug ./dist",
"start": "node dist/index.mjs"
},
"dependencies": {
Expand All @@ -16,7 +15,6 @@
"@hocuspocus/extension-logger": "catalog:",
"@hocuspocus/server": "catalog:",
"@hocuspocus/transformer": "catalog:",
"@sentry/node": "catalog:",
"@tiptap/core": "catalog:",
"@tiptap/html": "catalog:",
"@tiptap/pm": "catalog:",
Expand All @@ -27,7 +25,6 @@
"devDependencies": {
"@flydotio/dockerfile": "catalog:",
"@gitmono/tsconfig": "workspace:*",
"@sentry/cli": "catalog:",
"tsup": "catalog:",
"typescript": "catalog:"
}
Expand Down
72 changes: 41 additions & 31 deletions moon/apps/sync-server/src/database.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Database } from '@hocuspocus/extension-database'
import { Document } from '@hocuspocus/server'
import { TiptapTransformer } from '@hocuspocus/transformer'
import * as Sentry from '@sentry/node'
import { generateHTML, generateJSON } from '@tiptap/html'
import { fromUint8Array, toUint8Array } from 'js-base64'
import * as Y from 'yjs'
Expand All @@ -14,14 +13,14 @@ import { Context } from './types'
const extensions = getNoteExtensions()

export function sendVersionToConnections(document: Document, version: number) {
document.connections.forEach((connection) => {
const connectionSchemaVersion = connection.connection.context.schemaVersion ?? 0
document.getConnections().forEach((connection) => {
const connectionSchemaVersion = (connection.context as Context | undefined)?.schemaVersion ?? 0

// Update connections to readOnly if the schema version is lower than the current version
connection.connection.readOnly = connectionSchemaVersion < version
connection.readOnly = connectionSchemaVersion < version

// Send the schema version to the client
connection.connection.sendStateless(
connection.sendStateless(
JSON.stringify({
type: 'schema',
version
Expand All @@ -45,20 +44,41 @@ export async function getResource({ token, id, type, organization }: GetResource
}
}

function resolveContext(data: {
context?: Context
lastContext?: Context
requestParameters?: URLSearchParams
}): Context | undefined {
const fromPayload = data.lastContext ?? data.context

if (fromPayload?.token && fromPayload.organization) {
return fromPayload
}

const organization = data.requestParameters?.get('organization') ?? fromPayload?.organization
const type = data.requestParameters?.get('type') ?? fromPayload?.type ?? null
const token = fromPayload?.token
const schemaVersion = fromPayload?.schemaVersion ?? 0

if (!token || !organization) return fromPayload

return { token, schemaVersion, organization, type }
}

export const database = new Database({
/**
* Fetch the document state from Campsite, or generate a new document from the existing
* HTML if the document has never been edited before.
*/
async fetch(data) {
const context: Context = data.context
const context = resolveContext(data)

const id = data.documentName
const organization = data.requestParameters.get('organization')
const type = data.requestParameters.get('type')
const organization = context?.organization
const type = context?.type ?? null

try {
if (!organization) return new Uint8Array()
if (!context?.token || !organization) return new Uint8Array()

const state = await getResource({ token: context.token, id, type, organization })

Expand All @@ -79,16 +99,11 @@ export const database = new Database({

return Y.encodeStateAsUpdate(ydoc)
} catch (error) {
Sentry.setContext('document', {
id,
organization,
type
})
Sentry.setContext('context', {
schemaVersion: context.schemaVersion,
token: context.token
console.error('database.fetch failed', {
document: { id, organization, type },
schemaVersion: context?.schemaVersion,
error
})
Sentry.captureException(error)
throw error
}
},
Expand All @@ -97,14 +112,14 @@ export const database = new Database({
* Store the document state in Campsite.
*/
async store(data) {
const context: Context = data.context
const context = resolveContext(data)

const id = data.documentName
const organization = data.requestParameters.get('organization')
const type = data.requestParameters.get('type')
const organization = context?.organization
const type = context?.type ?? null

try {
if (!organization) return
if (!context?.token || !organization) return

// Generate a state from the Yjs document
const state = Y.encodeStateAsUpdate(data.document)
Expand All @@ -128,16 +143,11 @@ export const database = new Database({
}
)
} catch (error) {
Sentry.setContext('document', {
id,
organization,
type
})
Sentry.setContext('context', {
schemaVersion: context.schemaVersion,
token: context.token
console.error('database.store failed', {
document: { id, organization, type },
schemaVersion: context?.schemaVersion,
error
})
Sentry.captureException(error)
throw error
}
}
Expand Down
24 changes: 10 additions & 14 deletions moon/apps/sync-server/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { Logger } from '@hocuspocus/extension-logger'
import { Hocuspocus } from '@hocuspocus/server'
import * as Sentry from '@sentry/node'
import { Server } from '@hocuspocus/server'

import { PORT } from './config'
import { database, getResource, sendVersionToConnections } from './database'
import { AuthenticationError, Context } from './types'

const server = new Hocuspocus({
const server = new Server({
port: PORT,

async onAuthenticate(data): Promise<Context> {
Expand All @@ -32,23 +31,20 @@ const server = new Hocuspocus({
const document = data.instance.documents.get(data.documentName)

if (document) sendVersionToConnections(document, state.description_schema_version)
data.connection.readOnly = schemaVersion < state.description_schema_version
data.connectionConfig.readOnly = schemaVersion < state.description_schema_version

return {
token: data.token,
schemaVersion
}
} catch (error) {
Sentry.setContext('document', {
id: data.documentName,
schemaVersion,
organization,
type
}
} catch (error) {
console.error('onAuthenticate failed', {
document: { id: data.documentName, organization, type },
schemaVersion,
error
})
Sentry.setContext('context', {
schemaVersion: schemaVersion,
token: data.token
})
Sentry.captureException(error)
throw error
}
},
Expand Down
2 changes: 2 additions & 0 deletions moon/apps/sync-server/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export interface Context {
token: string
schemaVersion: number
organization: string
type: string | null
}

export type AuthenticationErrorType = 'no-token' | 'invalid-type'
Expand Down
3 changes: 0 additions & 3 deletions moon/apps/sync-server/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
"outDir": "./dist",
"sourceMap": true,
"inlineSources": true,
// Set `sourceRoot` to "/" to strip the build path prefix
// from generated source code references.
// This improves issue grouping in Sentry.
"sourceRoot": "/"
}
}
7 changes: 2 additions & 5 deletions moon/apps/sync-server/turbo.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@
"extends": ["//"],
"tasks": {
"dev": {
"dependsOn": ["build"],
"dependsOn": ["^build", "build"],
"passThroughEnv": ["PORT"]
},
"build": {
"env": ["SENTRY_AUTH_TOKEN", "SENTRY_ORG", "SENTRY_PROJECT", "TIPTAP_PRIVATE_REGISTRY_KEY", "NODE_ENV", "PORT"]
},
"sentry:sourcemaps": {
"env": ["SENTRY_AUTH_TOKEN", "SENTRY_ORG", "SENTRY_PROJECT"]
"env": ["TIPTAP_PRIVATE_REGISTRY_KEY", "NODE_ENV", "PORT"]
}
}
}
9 changes: 0 additions & 9 deletions moon/apps/web/.eslintrc.js

This file was deleted.

8 changes: 2 additions & 6 deletions moon/apps/web/.storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,7 @@ function getAbsolutePath(value) {
/** @type { import('@storybook/nextjs').StorybookConfig } */
const config = {
stories: ['../**/*.stories.@(js|jsx|mjs|ts|tsx)', '../../../packages/ui/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
addons: [
getAbsolutePath('@storybook/addon-links'),
getAbsolutePath('@storybook/addon-essentials'),
getAbsolutePath('@storybook/addon-interactions'),
getAbsolutePath('@storybook/addon-docs')
],
addons: [getAbsolutePath('@storybook/addon-links'), getAbsolutePath('@storybook/addon-docs')],
framework: {
name: getAbsolutePath('@storybook/nextjs'),
options: {}
Expand All @@ -36,4 +31,5 @@ const config = {
// },
staticDirs: ['../public']
}

export default config
6 changes: 3 additions & 3 deletions moon/apps/web/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# syntax = docker/dockerfile:1

FROM node:20-slim AS base
FROM node:26-slim AS base

# configure pnpm
# configure pnpm (node:26 images no longer ship corepack)
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME/bin:$PNPM_HOME:$PATH"
RUN corepack enable && corepack prepare pnpm@9.7.1 --activate
RUN npm install -g pnpm@11.17.0


# Throw-away build stage to reduce size of final image
Expand Down
24 changes: 0 additions & 24 deletions moon/apps/web/atoms/call.ts

This file was deleted.

21 changes: 0 additions & 21 deletions moon/apps/web/atoms/callToasts.ts

This file was deleted.

Loading
Loading