mirror of
https://github.com/Gimanh/taskview-community.git
synced 2026-09-10 22:25:56 +00:00
chore: version 1.32.0
This commit is contained in:
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "taskview-ce-api-server",
|
||||
"version": "1.24.0",
|
||||
"version": "1.32.0",
|
||||
"scripts": {
|
||||
"dev": "bun run --watch ./server.ts",
|
||||
"start": "NODE_ENV=production node ./dist/taskview-server.js",
|
||||
@@ -74,4 +74,4 @@
|
||||
"engines": {
|
||||
"node": ">=24 <25"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { $logger } from '../modules/logget';
|
||||
|
||||
interface CentrifugoPublishPayload {
|
||||
@@ -57,8 +58,7 @@ export class CentrifugoClient {
|
||||
}
|
||||
|
||||
static generateConnectionToken(userId: number): string {
|
||||
const jwt = require('jsonwebtoken');
|
||||
const secret = process.env.CENTRIFUGO_TOKEN_SECRET || process.env.JWT_SIGN;
|
||||
const secret = process.env.CENTRIFUGO_TOKEN_SECRET || process.env.JWT_SIGN || '';
|
||||
return jwt.sign(
|
||||
{ sub: String(userId) },
|
||||
secret,
|
||||
|
||||
@@ -89,15 +89,12 @@ export class NotificationsController {
|
||||
return res.status(401).send('Unauthorized');
|
||||
}
|
||||
|
||||
const publicPort = process.env.CENTRIFUGO_PUBLIC_PORT;
|
||||
if (!publicPort) {
|
||||
const publicUrl = process.env.CENTRIFUGO_PUBLIC_URL;
|
||||
if (!publicUrl) {
|
||||
return res.tvJson({ token: null, url: null });
|
||||
}
|
||||
|
||||
const appUrl = process.env.APP_URL || 'http://localhost:3000';
|
||||
const parsed = new URL(appUrl);
|
||||
const protocol = parsed.protocol === 'http:' ? 'ws' : 'wss';
|
||||
const url = `${protocol}://${parsed.hostname}:${publicPort}/connection/websocket`;
|
||||
const url = publicUrl;
|
||||
|
||||
const token = CentrifugoClient.generateConnectionToken(userId);
|
||||
return res.tvJson({ token, url });
|
||||
|
||||
@@ -24,7 +24,7 @@ Notifications can be sent through two channels (with email planned for the futur
|
||||
| Channel | Description | Required configuration |
|
||||
|---|---|---|
|
||||
| **Push** | Native push notifications on iOS/Android via Firebase Cloud Messaging | `FIREBASE_CREDENTIALS_PATH` |
|
||||
| **In-app (WebSocket)** | Real-time delivery to the browser via Centrifugo | `CENTRIFUGO_API_URL`, `CENTRIFUGO_API_KEY`, `CENTRIFUGO_TOKEN_SECRET`, `CENTRIFUGO_PUBLIC_PORT` |
|
||||
| **In-app (WebSocket)** | Real-time delivery to the browser via Centrifugo | `CENTRIFUGO_API_URL`, `CENTRIFUGO_API_KEY`, `CENTRIFUGO_TOKEN_SECRET`, `CENTRIFUGO_PUBLIC_URL` |
|
||||
|
||||
Both channels are optional. If Firebase is not configured, push notifications are silently skipped. If Centrifugo is not configured, in-app real-time delivery is skipped. Notifications are always saved to the database regardless of channel availability.
|
||||
|
||||
|
||||
@@ -105,9 +105,9 @@ Required for in-app real-time notification delivery. Without Centrifugo, notific
|
||||
| Variable | Required | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `CENTRIFUGO_API_URL` | No | - | Internal Centrifugo API URL (e.g. `http://centrifugo:8000`) |
|
||||
| `CENTRIFUGO_API_KEY` | No | - | Centrifugo API key for server-to-server communication |
|
||||
| `CENTRIFUGO_TOKEN_SECRET` | No | - | Secret for generating client connection tokens (HMAC) |
|
||||
| `CENTRIFUGO_PUBLIC_PORT` | No | - | Public port that browser clients use to connect to Centrifugo WebSocket |
|
||||
| `CENTRIFUGO_API_KEY` | No | - | Centrifugo API key for server-to-server communication. Must match `http_api.key` in Centrifugo config. |
|
||||
| `CENTRIFUGO_TOKEN_SECRET` | No | - | Secret for generating client connection tokens (HMAC). Must match `client.token.hmac_secret_key` in Centrifugo config. |
|
||||
| `CENTRIFUGO_PUBLIC_URL` | No | - | Full WebSocket URL for browser clients (e.g. `wss://api.example.com/centrifugo/connection/websocket`) |
|
||||
|
||||
### Firebase Cloud Messaging (mobile push notifications)
|
||||
|
||||
@@ -117,6 +117,56 @@ Required for native push notifications on iOS and Android. Without Firebase, pus
|
||||
|---|---|---|---|
|
||||
| `FIREBASE_CREDENTIALS_PATH` | No | - | Path to Firebase service account JSON file (e.g. `./firebase-credentials.json`) |
|
||||
|
||||
### Centrifugo configuration file
|
||||
|
||||
Centrifugo v6 uses a nested JSON config. Create `centrifugo/config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"client": {
|
||||
"allowed_origins": ["https://app.example.com"],
|
||||
"token": {
|
||||
"hmac_secret_key": "your_centrifugo_token_secret"
|
||||
}
|
||||
},
|
||||
"channel": {
|
||||
"namespaces": [
|
||||
{
|
||||
"name": "personal",
|
||||
"presence": false,
|
||||
"join_leave": false,
|
||||
"history_size": 0,
|
||||
"history_ttl": "0s"
|
||||
}
|
||||
]
|
||||
},
|
||||
"http_api": {
|
||||
"key": "your_centrifugo_api_key"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `http_api.key` must match `CENTRIFUGO_API_KEY` in `.env.taskview`
|
||||
- `client.token.hmac_secret_key` must match `CENTRIFUGO_TOKEN_SECRET` in `.env.taskview`
|
||||
- `client.allowed_origins` should list your frontend domain(s). Use `["*"]` only for development.
|
||||
|
||||
### Nginx WebSocket proxy
|
||||
|
||||
To serve Centrifugo through your existing HTTPS domain, add to your nginx server block:
|
||||
|
||||
```nginx
|
||||
location /centrifugo/ {
|
||||
proxy_pass http://localhost:8000/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
```
|
||||
|
||||
Then set `CENTRIFUGO_PUBLIC_URL=wss://api.example.com/centrifugo/connection/websocket`.
|
||||
|
||||
::callout{icon="i-lucide-info" color="info"}
|
||||
Both Centrifugo and Firebase are optional. If not configured, their respective channels are skipped. Notifications are always persisted to the database.
|
||||
::
|
||||
@@ -178,5 +228,5 @@ ENCRYPTION_KEY=
|
||||
# CENTRIFUGO_API_URL=http://centrifugo:8000
|
||||
# CENTRIFUGO_API_KEY=your_centrifugo_api_key
|
||||
# CENTRIFUGO_TOKEN_SECRET=your_centrifugo_token_secret
|
||||
# CENTRIFUGO_PUBLIC_PORT=8000
|
||||
# CENTRIFUGO_PUBLIC_URL=wss://api.example.com/centrifugo/connection/websocket
|
||||
```
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "taskview-ce-monorepo",
|
||||
"version": "1.24.0",
|
||||
"version": "1.32.0",
|
||||
"private": true,
|
||||
"description": "TaskView CE monorepo containing web, API, and packages",
|
||||
"workspaces": [
|
||||
|
||||
@@ -7,8 +7,8 @@ android {
|
||||
applicationId "com.handscreamgnl.taskview.app"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 1201
|
||||
versionName "1.20.1"
|
||||
versionCode 1300
|
||||
versionName "1.30.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
aaptOptions {
|
||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||
|
||||
@@ -9,10 +9,12 @@ android {
|
||||
|
||||
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
||||
dependencies {
|
||||
implementation project(':capacitor-firebase-messaging')
|
||||
implementation project(':capacitor-app')
|
||||
implementation project(':capacitor-browser')
|
||||
implementation project(':capacitor-device')
|
||||
implementation project(':capacitor-preferences')
|
||||
implementation project(':capacitor-push-notifications')
|
||||
implementation project(':capacitor-splash-screen')
|
||||
implementation project(':capgo-capacitor-updater')
|
||||
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
|
||||
include ':capacitor-android'
|
||||
project(':capacitor-android').projectDir = new File('../../../node_modules/.pnpm/@capacitor+android@8.1.0_@capacitor+core@8.1.0/node_modules/@capacitor/android/capacitor')
|
||||
project(':capacitor-android').projectDir = new File('../../node_modules/.pnpm/@capacitor+android@8.1.0_@capacitor+core@8.1.0/node_modules/@capacitor/android/capacitor')
|
||||
|
||||
include ':capacitor-firebase-messaging'
|
||||
project(':capacitor-firebase-messaging').projectDir = new File('../../node_modules/.pnpm/@capacitor-firebase+messaging@8.1.0_@capacitor+core@8.1.0_firebase@12.10.0/node_modules/@capacitor-firebase/messaging/android')
|
||||
|
||||
include ':capacitor-app'
|
||||
project(':capacitor-app').projectDir = new File('../../../node_modules/.pnpm/@capacitor+app@8.0.1_@capacitor+core@8.1.0/node_modules/@capacitor/app/android')
|
||||
project(':capacitor-app').projectDir = new File('../../node_modules/.pnpm/@capacitor+app@8.0.1_@capacitor+core@8.1.0/node_modules/@capacitor/app/android')
|
||||
|
||||
include ':capacitor-browser'
|
||||
project(':capacitor-browser').projectDir = new File('../../../node_modules/.pnpm/@capacitor+browser@8.0.1_@capacitor+core@8.1.0/node_modules/@capacitor/browser/android')
|
||||
project(':capacitor-browser').projectDir = new File('../../node_modules/.pnpm/@capacitor+browser@8.0.1_@capacitor+core@8.1.0/node_modules/@capacitor/browser/android')
|
||||
|
||||
include ':capacitor-device'
|
||||
project(':capacitor-device').projectDir = new File('../../../node_modules/.pnpm/@capacitor+device@8.0.1_@capacitor+core@8.1.0/node_modules/@capacitor/device/android')
|
||||
project(':capacitor-device').projectDir = new File('../../node_modules/.pnpm/@capacitor+device@8.0.1_@capacitor+core@8.1.0/node_modules/@capacitor/device/android')
|
||||
|
||||
include ':capacitor-preferences'
|
||||
project(':capacitor-preferences').projectDir = new File('../../../node_modules/.pnpm/@capacitor+preferences@8.0.1_@capacitor+core@8.1.0/node_modules/@capacitor/preferences/android')
|
||||
project(':capacitor-preferences').projectDir = new File('../../node_modules/.pnpm/@capacitor+preferences@8.0.1_@capacitor+core@8.1.0/node_modules/@capacitor/preferences/android')
|
||||
|
||||
include ':capacitor-push-notifications'
|
||||
project(':capacitor-push-notifications').projectDir = new File('../../node_modules/.pnpm/@capacitor+push-notifications@8.0.2_@capacitor+core@8.1.0/node_modules/@capacitor/push-notifications/android')
|
||||
|
||||
include ':capacitor-splash-screen'
|
||||
project(':capacitor-splash-screen').projectDir = new File('../../../node_modules/.pnpm/@capacitor+splash-screen@8.0.1_@capacitor+core@8.1.0/node_modules/@capacitor/splash-screen/android')
|
||||
project(':capacitor-splash-screen').projectDir = new File('../../node_modules/.pnpm/@capacitor+splash-screen@8.0.1_@capacitor+core@8.1.0/node_modules/@capacitor/splash-screen/android')
|
||||
|
||||
include ':capgo-capacitor-updater'
|
||||
project(':capgo-capacitor-updater').projectDir = new File('../../../node_modules/.pnpm/@capgo+capacitor-updater@8.43.2_@capacitor+core@8.1.0/node_modules/@capgo/capacitor-updater/android')
|
||||
project(':capgo-capacitor-updater').projectDir = new File('../../node_modules/.pnpm/@capgo+capacitor-updater@8.43.8_@capacitor+core@8.1.0/node_modules/@capgo/capacitor-updater/android')
|
||||
|
||||
@@ -301,9 +301,10 @@
|
||||
baseConfigurationReference = 958DCC722DB07C7200EA8C5F /* debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = App/App.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1.20.1;
|
||||
CURRENT_PROJECT_VERSION = 1.30.0;
|
||||
DEVELOPMENT_TEAM = H2W2SG48JT;
|
||||
INFOPLIST_FILE = App/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
@@ -311,7 +312,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.20.1;
|
||||
MARKETING_VERSION = 1.30.0;
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.handscream.taskview.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -325,9 +326,10 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = App/App.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1.20.1;
|
||||
CURRENT_PROJECT_VERSION = 1.30.0;
|
||||
DEVELOPMENT_TEAM = H2W2SG48JT;
|
||||
INFOPLIST_FILE = App/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
@@ -335,7 +337,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.20.1;
|
||||
MARKETING_VERSION = 1.30.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.handscream.taskview.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
"name": "web-nuxt-ui",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "1.24.0",
|
||||
"version": "1.32.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build:packages": "pnpm --filter taskview-db-schemas build && pnpm --filter taskview-api build",
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
import { ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import { WEBHOOK_EVENTS } from 'taskview-api'
|
||||
import { WEBHOOK_EVENTS, type WebhookEvent } from 'taskview-api'
|
||||
import { useWebhooksStore } from '@/stores/webhooks.store'
|
||||
import { useTaskView } from '@/composables/useTaskView'
|
||||
|
||||
@@ -101,7 +101,7 @@ const webhooksStore = useWebhooksStore()
|
||||
const { copy } = useClipboard()
|
||||
|
||||
const url = ref('')
|
||||
const selectedEvents = ref<string[]>([])
|
||||
const selectedEvents = ref<WebhookEvent[]>([])
|
||||
const saving = ref(false)
|
||||
const showSecret = ref(false)
|
||||
const createdSecret = ref('')
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { WEBHOOK_EVENTS } from 'taskview-api'
|
||||
import { WEBHOOK_EVENTS, type WebhookEvent } from 'taskview-api'
|
||||
import type { WebhookItem } from 'taskview-api'
|
||||
import { useWebhooksStore } from '@/stores/webhooks.store'
|
||||
import { useTaskView } from '@/composables/useTaskView'
|
||||
@@ -68,7 +68,7 @@ const { isMobile } = useTaskView()
|
||||
const webhooksStore = useWebhooksStore()
|
||||
|
||||
const url = ref('')
|
||||
const selectedEvents = ref<string[]>([])
|
||||
const selectedEvents = ref<WebhookEvent[]>([])
|
||||
const saving = ref(false)
|
||||
|
||||
const eventOptions = WEBHOOK_EVENTS.map((e) => ({
|
||||
@@ -79,7 +79,7 @@ const eventOptions = WEBHOOK_EVENTS.map((e) => ({
|
||||
watch(isOpen, (open) => {
|
||||
if (open && props.webhook) {
|
||||
url.value = props.webhook.url
|
||||
selectedEvents.value = [...props.webhook.events]
|
||||
selectedEvents.value = [...props.webhook.events] as WebhookEvent[]
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user