Prepare for release 0.2.0 (#49)

This commit is contained in:
Hakan Shehu
2025-06-11 20:07:12 +02:00
committed by GitHub
parent 9e6d53d147
commit 29d7fcdb0d
18 changed files with 48 additions and 144 deletions

View File

@@ -1,4 +1,4 @@
name: Build and publish desktop app
name: Desktop - Build and publish electron app
on:
push:
@@ -31,7 +31,7 @@ jobs:
restore-keys: |
${{ runner.os }}-electron-cache-
- name: Set VERSION
- name: Extract version from tag
shell: pwsh
run: |
$version = $env:GITHUB_REF -replace '^refs/tags/v',''
@@ -110,7 +110,7 @@ jobs:
restore-keys: |
${{ runner.os }}-electron-cache-
- name: Set VERSION
- name: Extract version from tag
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
- name: Decode and Import macOS Certificate

View File

@@ -1,4 +1,4 @@
name: Build and push server docker image
name: Server - Build and push docker image
on:
push:
@@ -29,8 +29,7 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get the version
id: get_version
- name: Extract version from tag
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
- name: Set version and commit SHA into build.ts

View File

@@ -1,4 +1,4 @@
name: Mark server docker image as latest
name: Server - Mark docker image as latest
on:
release:
@@ -12,6 +12,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
@@ -19,14 +22,9 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get the version
id: get_version
- name: Extract version from tag
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
- name: Pull version image
run: docker pull ${{ env.REGISTRY }}/${{ vars.SERVER_IMAGE_NAME }}:${{ env.VERSION }}
- name: Tag and push as latest
- name: Tag as latest the version image
run: |
docker tag ${{ env.REGISTRY }}/${{ vars.SERVER_IMAGE_NAME }}:${{ env.VERSION }} ${{ env.REGISTRY }}/${{ vars.SERVER_IMAGE_NAME }}:latest
docker push ${{ env.REGISTRY }}/${{ vars.SERVER_IMAGE_NAME }}:latest
docker buildx imagetools create --tag ${{ env.REGISTRY }}/${{ vars.SERVER_IMAGE_NAME }}:latest ${{ env.REGISTRY }}/${{ vars.SERVER_IMAGE_NAME }}:${{ env.VERSION }}

View File

@@ -1,4 +1,4 @@
name: Build and deploy beta web app to Cloudflare
name: Web - Build and deploy beta to Cloudflare
on:
push:
@@ -18,8 +18,7 @@ jobs:
node-version: '22'
cache: 'npm'
- name: Get the version
id: get_version
- name: Extract version from tag
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
- name: Set version and commit SHA into build.ts
@@ -72,10 +71,11 @@ jobs:
}
EOF
- name: Deploy
- name: Deploy to Cloudflare
uses: cloudflare/wrangler-action@v3
with:
workingDirectory: ./apps/web
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
wranglerVersion: 4.19.2
command: deploy

View File

@@ -1,4 +1,4 @@
name: Build and deploy web app to Cloudflare
name: Web - Build and deploy to Cloudflare
on:
release:
@@ -17,8 +17,7 @@ jobs:
node-version: '22'
cache: 'npm'
- name: Get the version
id: get_version
- name: Extract version from tag
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
- name: Set version and commit SHA into build.ts
@@ -71,10 +70,11 @@ jobs:
}
EOF
- name: Deploy
- name: Deploy to Cloudflare
uses: cloudflare/wrangler-action@v3
with:
workingDirectory: ./apps/web
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
wranglerVersion: 4.19.2
command: deploy

View File

@@ -1,4 +1,4 @@
name: Build and push server docker image
name: Web - Build and push docker image
on:
push:
@@ -29,8 +29,7 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get the version
id: get_version
- name: Extract version from tag
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
- name: Set version and commit SHA into build.ts

View File

@@ -1,4 +1,4 @@
name: Mark web docker image as latest
name: Web - Mark docker image as latest
on:
release:
@@ -12,6 +12,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
@@ -19,14 +22,9 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get the version
id: get_version
- name: Extract version from tag
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
- name: Pull version image
run: docker pull ${{ env.REGISTRY }}/${{ vars.WEB_IMAGE_NAME }}:${{ env.VERSION }}
- name: Tag and push as latest
- name: Tag as latest the version image
run: |
docker tag ${{ env.REGISTRY }}/${{ vars.WEB_IMAGE_NAME }}:${{ env.VERSION }} ${{ env.REGISTRY }}/${{ vars.WEB_IMAGE_NAME }}:latest
docker push ${{ env.REGISTRY }}/${{ vars.WEB_IMAGE_NAME }}:latest
docker buildx imagetools create --tag ${{ env.REGISTRY }}/${{ vars.WEB_IMAGE_NAME }}:latest ${{ env.REGISTRY }}/${{ vars.WEB_IMAGE_NAME }}:${{ env.VERSION }}

View File

@@ -21,7 +21,7 @@ Built for both individuals and teams, Colanode adapts to your needs, whether you
## How it works
Colanode includes a desktop app and a self-hosted server. You can connect to multiple servers with a single app, each containing one or more **workspaces** for different teams or projects. After logging in, you pick a workspace to start collaborating—sending messages, editing pages, or updating database records.
Colanode includes a client app (web or desktop) and a self-hosted server. You can connect to multiple servers with a single app, each containing one or more **workspaces** for different teams or projects. After logging in, you pick a workspace to start collaborating—sending messages, editing pages, or updating database records.
### Local-first workflow
@@ -33,12 +33,14 @@ Colanode relies on **Conflict-free Replicated Data Types (CRDTs)** - powered by
## Get started for free
To begin using Colanode, **download the official desktop app** from the [website](https://colanode.com/downloads). Once installed, you can connect to any Colanode server—including our free beta cloud servers:
The easiest way to start using Colanode is through our **web app**, accessible instantly at [app.colanode.com](https://app.colanode.com). Simply log in to get started immediately, without any installation. _Please note, the web app is currently in early preview and under testing; you may encounter bugs or compatibility issues in certain browsers._
For optimal performance, you can install our **desktop app**, available from our [downloads page](https://colanode.com/downloads). Both the web and desktop apps allow you to connect to any of our free beta cloud servers:
- **Colanode Cloud (EU)** hosted in Europe.
- **Colanode Cloud (US)** hosted in the United States.
Both cloud servers are currently in beta and free to use; pricing will be announced soon.
Both cloud servers are currently available in beta and free to use; pricing details will be announced soon.
### Self-host with Docker

View File

@@ -29,7 +29,6 @@
},
"dependencies": {
"@aws-sdk/client-s3": "^3.826.0",
"@aws-sdk/s3-request-presigner": "^3.826.0",
"@colanode/core": "*",
"@colanode/crdt": "*",
"@fastify/cors": "^11.0.1",

View File

@@ -25,7 +25,7 @@ export const avatarDownloadRoute: FastifyPluginCallbackZod = (
try {
const avatarId = request.params.avatarId;
const command = new GetObjectCommand({
Bucket: config.storage.bucketName,
Bucket: config.storage.bucket,
Key: `avatars/${avatarId}.jpeg`,
});

View File

@@ -71,7 +71,7 @@ export const avatarUploadRoute: FastifyPluginCallbackZod = (
const avatarId = generateId(IdType.Avatar);
const command = new PutObjectCommand({
Bucket: config.storage.bucketName,
Bucket: config.storage.bucket,
Key: `avatars/${avatarId}.jpeg`,
Body: jpegBuffer,
ContentType: 'image/jpeg',

View File

@@ -85,7 +85,7 @@ export const fileDownloadRoute: FastifyPluginCallbackZod = (
}
const command = new GetObjectCommand({
Bucket: config.storage.bucketName,
Bucket: config.storage.bucket,
Key: upload.path,
});

View File

@@ -107,7 +107,7 @@ export const fileUploadRoute: FastifyPluginCallbackZod = (
const stream = request.raw;
const uploadCommand = new PutObjectCommand({
Bucket: config.storage.bucketName,
Bucket: config.storage.bucket,
Key: path,
Body: stream,
ContentType: file.attributes.mimeType,

View File

@@ -2,11 +2,11 @@ import { z } from 'zod/v4';
export const storageConfigSchema = z.object({
type: z.literal('s3'),
endpoint: z.string({ error: 'S3_ENDPOINT is required' }),
accessKey: z.string({ error: 'S3_ACCESS_KEY is required' }),
secretKey: z.string({ error: 'S3_SECRET_KEY is required' }),
bucketName: z.string({ error: 'S3_BUCKET_NAME is required' }),
region: z.string({ error: 'S3_REGION is required' }),
endpoint: z.string({ error: 'STORAGE_S3_ENDPOINT is required' }),
accessKey: z.string({ error: 'STORAGE_S3_ACCESS_KEY is required' }),
secretKey: z.string({ error: 'STORAGE_S3_SECRET_KEY is required' }),
bucket: z.string({ error: 'STORAGE_S3_BUCKET is required' }),
region: z.string({ error: 'STORAGE_S3_REGION is required' }),
});
export type StorageConfig = z.infer<typeof storageConfigSchema>;
@@ -17,7 +17,7 @@ export const readStorageConfigVariables = () => {
endpoint: process.env.STORAGE_S3_ENDPOINT,
accessKey: process.env.STORAGE_S3_ACCESS_KEY,
secretKey: process.env.STORAGE_S3_SECRET_KEY,
bucketName: process.env.STORAGE_S3_BUCKET_NAME,
bucket: process.env.STORAGE_S3_BUCKET,
region: process.env.STORAGE_S3_REGION,
};
};

View File

@@ -1,10 +1,4 @@
import {
PutObjectCommand,
DeleteObjectCommand,
GetObjectCommand,
HeadObjectCommand,
} from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { DeleteObjectCommand } from '@aws-sdk/client-s3';
import { FileAttributes } from '@colanode/core';
import { s3Client } from '@colanode/server/data/storage';
@@ -18,59 +12,9 @@ export const buildFilePath = (
return `files/${workspaceId}/${fileId}_${fileAttributes.version}${fileAttributes.extension}`;
};
export const buildUploadUrl = async (
path: string,
size: number,
mimeType: string
) => {
const command = new PutObjectCommand({
Bucket: config.storage.bucketName,
Key: path,
ContentLength: size,
ContentType: mimeType,
});
const expiresIn = 60 * 60 * 4; // 4 hours
const presignedUrl = await getSignedUrl(s3Client, command, {
expiresIn,
});
return presignedUrl;
};
export const buildDownloadUrl = async (path: string) => {
const command = new GetObjectCommand({
Bucket: config.storage.bucketName,
Key: path,
});
const presignedUrl = await getSignedUrl(s3Client, command, {
expiresIn: 60 * 60 * 4, // 4 hours
});
return presignedUrl;
};
export const fetchFileMetadata = async (path: string) => {
const command = new HeadObjectCommand({
Bucket: config.storage.bucketName,
Key: path,
});
try {
const headObject = await s3Client.send(command);
return {
size: headObject.ContentLength,
mimeType: headObject.ContentType,
};
} catch {
return null;
}
};
export const deleteFile = async (path: string) => {
const command = new DeleteObjectCommand({
Bucket: config.storage.bucketName,
Bucket: config.storage.bucket,
Key: path,
});

View File

@@ -144,7 +144,7 @@ services:
STORAGE_S3_ENDPOINT: 'http://minio:9000'
STORAGE_S3_ACCESS_KEY: 'minioadmin'
STORAGE_S3_SECRET_KEY: 'your_minio_password'
STORAGE_S3_BUCKET_NAME: 'colanode-avatars'
STORAGE_S3_BUCKET: 'colanode-avatars'
STORAGE_S3_REGION: 'us-east-1'
# ───────────────────────────────────────────────────────────────

35
package-lock.json generated
View File

@@ -85,7 +85,6 @@
"version": "1.0.0",
"dependencies": {
"@aws-sdk/client-s3": "^3.826.0",
"@aws-sdk/s3-request-presigner": "^3.826.0",
"@colanode/core": "*",
"@colanode/crdt": "*",
"@fastify/cors": "^11.0.1",
@@ -894,25 +893,6 @@
"node": ">=18.0.0"
}
},
"node_modules/@aws-sdk/s3-request-presigner": {
"version": "3.826.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.826.0.tgz",
"integrity": "sha512-47IcILH3CfVzUmGwJhwuZQyuZ5zXNsFyvtpQWR2s2dkoT7TJCMAKY0MtWE+y2T99b20OGbUhQHz/9qlx7dR3zw==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/signature-v4-multi-region": "3.826.0",
"@aws-sdk/types": "3.821.0",
"@aws-sdk/util-format-url": "3.821.0",
"@smithy/middleware-endpoint": "^4.1.11",
"@smithy/protocol-http": "^5.1.2",
"@smithy/smithy-client": "^4.4.3",
"@smithy/types": "^4.3.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@aws-sdk/signature-v4-multi-region": {
"version": "3.826.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.826.0.tgz",
@@ -988,21 +968,6 @@
"node": ">=18.0.0"
}
},
"node_modules/@aws-sdk/util-format-url": {
"version": "3.821.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.821.0.tgz",
"integrity": "sha512-h+xqmPToxDrZ0a7rxE1a8Oh4zpWfZe9oiQUphGtfiGFA6j75UiURH5J3MmGHa/G4t15I3iLLbYtUXxvb1i7evg==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/types": "3.821.0",
"@smithy/querystring-builder": "^4.0.4",
"@smithy/types": "^4.3.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@aws-sdk/util-locate-window": {
"version": "3.804.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.804.0.tgz",

View File

@@ -10,5 +10,5 @@ export const isServerOutdated = (version: string) => {
return true;
}
return semver.gte(parsedVersion, '0.2.0');
return semver.lt(parsedVersion, '0.2.0');
};