mirror of
https://github.com/colanode/colanode.git
synced 2025-12-16 03:37:51 +01:00
Prepare for release 0.2.0 (#49)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
16
.github/workflows/server-docker-mark-latest.yml
vendored
16
.github/workflows/server-docker-mark-latest.yml
vendored
@@ -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 }}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
16
.github/workflows/web-docker-mark-latest.yml
vendored
16
.github/workflows/web-docker-mark-latest.yml
vendored
@@ -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 }}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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`,
|
||||
});
|
||||
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -85,7 +85,7 @@ export const fileDownloadRoute: FastifyPluginCallbackZod = (
|
||||
}
|
||||
|
||||
const command = new GetObjectCommand({
|
||||
Bucket: config.storage.bucketName,
|
||||
Bucket: config.storage.bucket,
|
||||
Key: upload.path,
|
||||
});
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
|
||||
@@ -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
35
package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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');
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user