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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/code-verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,5 @@ jobs:
- name: NPM / Verify
working-directory: code
run: |
npm ci
npm ci --force
npm run verify
22 changes: 5 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,24 +103,12 @@ This backend is designed to demonstrate how Weave.js can be integrated into a fu
You can locally launch the backend showcase by:

- Install dependencies with: `npm install`
- Create a `.env` file on the folder `/code`, and setup the necessary configuration:
- Create your local environment file from the template (from `/code`): `cp .env.example .env`
- Update `/code/.env` with the required values (including PostgreSQL and Azure variables).

```
HOSTNAME=0.0.0.0
PORT=8081
LOG_LEVEL=debug

AZURE_WEB_PUBSUB_ENDPOINT=<azure-web-pubsub-endpoint>
AZURE_WEB_PUBSUB_KEY=<key>
AZURE_WEB_PUBSUB_HUB_NAME=weavejs
PERSIST_FREQUENCY_SEG=10

AZURE_STORAGE_CONNECTION_STRING=<azure-storage-connection-string>
AZURE_STORAGE_ROOMS_CONTAINER_NAME=rooms
AZURE_STORAGE_IMAGES_CONTAINER_NAME=images
```

- Run the frontend: `npm run dev`
- Start PostgreSQL with the provided compose file: `docker compose -f code/docker-compose.yml up -d db`
- Run database migrations (from `/code`): `cd code && npm run db:migrate:dev`
- Run the backend (from `/code`): `cd code && npm run dev`

You'll need access to a:

Expand Down
64 changes: 64 additions & 0 deletions code/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# SPDX-FileCopyrightText: 2025 2025 INDUSTRIA DE DISEÑO TEXTIL S.A. (INDITEX S.A.)
#
# SPDX-License-Identifier: Apache-2.0

DEV_WEAVEJS_REPO_PATH=<weavejs-repo-path>

NODE_ENV=development
HOSTNAME=0.0.0.0
PORT=8081
DEPLOY_ENVIRONMENT=local
LOG_LEVEL=info
HTTP_LOG_LEVEL=debug

# Development environment
AZURE_WEB_PUBSUB_ENDPOINT=<azure-web-pubsub-endpoint>
AZURE_WEB_PUBSUB_KEY=<key>
AZURE_WEB_PUBSUB_HUB_NAME=weavejs
PERSIST_FREQUENCY_SEG=10
CLEANUP_ROOMS_INTERVAL_SEG=60

AZURE_STORAGE_ACCOUNT_NAME=<azure-account-name>
AZURE_STORAGE_CONNECTION_STRING=<azure-storage-connection-string>
AZURE_STORAGE_ROOMS_CONTAINER_NAME=rooms
AZURE_STORAGE_IMAGES_CONTAINER_NAME=images
AZURE_STORAGE_VIDEOS_CONTAINER_NAME=videos
AZURE_STORAGE_GENERATED_IMAGES_CONTAINER_NAME=generated-images

AI_SERVICES=false
AI_PASSWORD=<password>

AZURE_CS_ENDPOINT=<azure-cs-endpoint>
AZURE_CS_API_KEY=<azure-cs-api-key>
AZURE_CS_TIMEOUT_SECS=240

APP_HOST=https://localhost:3000
GOOGLE_GENERATIVE_AI_API_KEY=<google-generative-ai-api-key>
GOOGLE_API_KEY=<google-api-key>

DATABASE_HOST=localhost
DATABASE_PORT=5434
DATABASE_NAME=weavejs
DATABASE_USERNAME=weave_dbuser
DATABASE_PASSWORD=weave_password
DATABASE_SSL=false
DATABASE_CLOUD_CREDENTIALS=false

FEATURE_WORKLOADS=true
FEATURE_THREADS=true

LITELLM_ENDPOINT=<litellm-endpoint>
LITELLM_API_KEY=<litellm-api-key>

DISABLE_ROOMS_CLEANUP=false

# Local
BETTER_AUTH_SECRET=<better-auth-secret>
BETTER_AUTH_URL=<better-auth-url>
GITHUB_CLIENT_ID=<github-client-id>
GITHUB_CLIENT_SECRET=<github-client-secret>
GOOGLE_CLIENT_ID=<google-client-id>
GOOGLE_CLIENT_SECRET=<google-client-secret>

PRINT_MEMORY_USAGE=false
PRINT_MEMORY_USAGE_INTERVAL=500
3 changes: 2 additions & 1 deletion code/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ vite.config.ts*

*.pem
.env*
!.env.example
.npmrc

temp
Expand All @@ -43,4 +44,4 @@ env.sh

.mastra

mcp.json
mcp.json
1 change: 0 additions & 1 deletion code/.tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
nodejs 24.11.1
ivm-node 24.11.1
90 changes: 90 additions & 0 deletions code/migrations/20251118164400-feature-auth.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
'use strict';

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up (queryInterface, Sequelize) {
const transaction = await queryInterface.sequelize.transaction();

try {
await queryInterface.sequelize.query('CREATE SCHEMA IF NOT EXISTS auth;', { transaction });

await queryInterface.sequelize.query(`
CREATE TABLE IF NOT EXISTS auth."user" (
"id" text NOT NULL PRIMARY KEY,
"name" text NOT NULL,
"email" text NOT NULL UNIQUE,
"emailVerified" boolean NOT NULL DEFAULT false,
"image" text,
"createdAt" timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP
);
`, { transaction });

await queryInterface.sequelize.query(`
CREATE TABLE IF NOT EXISTS auth."session" (
"id" text NOT NULL PRIMARY KEY,
"userId" text NOT NULL,
"token" text NOT NULL UNIQUE,
"expiresAt" timestamptz NOT NULL,
"ipAddress" text,
"userAgent" text,
"createdAt" timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY ("userId") REFERENCES auth."user" ("id") ON DELETE CASCADE
);
`, { transaction });

await queryInterface.sequelize.query(`
CREATE TABLE IF NOT EXISTS auth."account" (
"id" text NOT NULL PRIMARY KEY,
"userId" text NOT NULL,
"accountId" text NOT NULL,
"providerId" text NOT NULL,
"accessToken" text,
"refreshToken" text,
"accessTokenExpiresAt" timestamptz,
"refreshTokenExpiresAt" timestamptz,
"scope" text,
"idToken" text,
"password" text,
"createdAt" timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY ("userId") REFERENCES auth."user" ("id") ON DELETE CASCADE
);
`, { transaction });

await queryInterface.sequelize.query(`
CREATE TABLE IF NOT EXISTS auth."verification" (
"id" text NOT NULL PRIMARY KEY,
"identifier" text NOT NULL,
"value" text NOT NULL,
"expiresAt" timestamptz NOT NULL,
"createdAt" timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP
);
`, { transaction });

await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},

async down (queryInterface) {
const transaction = await queryInterface.sequelize.transaction();

try {
await queryInterface.sequelize.query('DROP TABLE IF EXISTS auth."verification";', { transaction });
await queryInterface.sequelize.query('DROP TABLE IF EXISTS auth."account";', { transaction });
await queryInterface.sequelize.query('DROP TABLE IF EXISTS auth."session";', { transaction });
await queryInterface.sequelize.query('DROP TABLE IF EXISTS auth."user";', { transaction });
await queryInterface.sequelize.query('DROP SCHEMA IF EXISTS auth;', { transaction });

await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
};
63 changes: 63 additions & 0 deletions code/migrations/20251118164500-feature-task.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
'use strict';

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up (queryInterface, Sequelize) {
const tableExists = await queryInterface.tableExists('weavejs_task');

if (tableExists) {
return;
}

await queryInterface.createTable('weavejs_task', {
jobId: {
type: Sequelize.STRING,
allowNull: false,
primaryKey: true,
},
roomId: {
type: Sequelize.STRING,
allowNull: false,
},
userId: {
type: Sequelize.STRING,
allowNull: false,
},
type: {
type: Sequelize.STRING,
allowNull: false,
},
status: {
type: Sequelize.STRING,
allowNull: false,
},
opened: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: false,
},
metadata: {
type: Sequelize.JSONB,
allowNull: true,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.fn('NOW'),
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.fn('NOW'),
},
});
},

async down (queryInterface) {
const table = await queryInterface.tableExists('weavejs_task');

if (table) {
await queryInterface.dropTable('weavejs_task');
}
},
};
Loading
Loading