This commit is contained in:
seb
2026-10-28 19:31:41 +01:00
parent 01d6aa0e3f
commit 1881830b0a
13 changed files with 81 additions and 27 deletions

View File

@@ -1,6 +1,5 @@
import * as db from '../../../db/googleAuth.js';
import { clearCachedUser } from '../../middleware/auth.js';
import { setUserCompany } from '../../sse.js';
/**
* Registers the selected-company route (requires auth middleware).
@@ -18,7 +17,7 @@ export function register(app, basePath = '') {
* security:
* - cookieAuth: []
* x-markdown: auth/selected-company.md
* x-signals: [company]
* x-signals: [user, company]
* requestBody:
* required: true
* content:
@@ -78,7 +77,6 @@ export function register(app, basePath = '') {
selectedCompanyId: updated.selectedCompanyId,
};
setUserCompany(req.user.id, updated.selectedCompanyId);
res.status(200).json({ user });
} catch (error) {
console.error('Set selected company failed:', error);

View File

@@ -5,7 +5,7 @@ import JSZip from 'jszip';
import * as db from '../../db/company.js';
import * as googleAuth from '../../db/googleAuth.js';
import { clearCachedUser } from '../middleware/auth.js';
import { clearDeletedCompany, emit, setUserCompany } from '../sse.js';
import { emit } from '../sse.js';
import { initCompanyVfs } from '../../tools/vfs.js';
import { executeCompanyImport } from '../../services/companyImport.js';
import { executeCompanyExport } from '../../services/companyExport.js';
@@ -138,7 +138,7 @@ export function register(app, basePath = '') {
* security:
* - cookieAuth: []
* x-markdown: company/create.md
* x-signals: [company]
* x-signals: [user, company]
* requestBody:
* required: true
* content:
@@ -217,7 +217,6 @@ export function register(app, basePath = '') {
console.error('Failed to initialize company VFS:', vfsErr);
}
const authRow = await googleAuth.getAllowedEmail(req.user.email);
setUserCompany(req.user.id, authRow.selectedCompanyId);
res.status(201).json({ company, user: userPayload(authRow) });
} catch (error) {
const status = companyErrorStatus(error);
@@ -895,7 +894,7 @@ export function register(app, basePath = '') {
* security:
* - cookieAuth: []
* x-markdown: company/delete.md
* x-signals: [company]
* x-signals: [user, company]
* parameters:
* - in: path
* name: id
@@ -960,7 +959,6 @@ export function register(app, basePath = '') {
try {
await db.deleteCompany(parsedId.companyId);
clearDeletedCompany(parsedId.companyId);
res.sendStatus(204);
} catch (error) {
console.error('Delete company failed:', error);

View File

@@ -15,8 +15,9 @@ export function register(app, basePath = '') {
* description: |
* Opens a Server-Sent Events stream for the authenticated user.
* Can be opened before a company is selected (`selectedCompanyId == null`);
* when a company is selected or changed, the stream receives a `company`
* event (`{ companyId }`) and updates its company scope in-place.
* when a company is selected or changed, the stream receives `user`
* (`{ selectedCompanyId }`) and `company` (`{ companyId }`) events and
* updates its company scope in-place.
* Clients also receive named signals when another request successfully
* mutates shared data for the active company (including the same
* browser's other tabs).
@@ -25,6 +26,7 @@ export function register(app, basePath = '') {
*
* ```js
* const es = new EventSource('https://…/api/events', { withCredentials: true });
* es.addEventListener('user', () => { refetchAuthMe(); });
* es.addEventListener('company', () => { refetchCompany(); });
* es.addEventListener('category', () => { refetchCategoryTree(); });
* es.addEventListener('articles', () => { refetchArticleIndex(); });
@@ -36,11 +38,13 @@ export function register(app, basePath = '') {
* ## Signals
*
* Every SSE event uses the event name as the signal id; payloads are
* JSON and most events send an empty object `{}`. `company` emits
* `{ companyId }` and `brand` emits `{ sender, brandId }`.
* JSON and most events send an empty object `{}`. `user` emits
* `{ selectedCompanyId }`, `company` emits `{ companyId }`, and `brand`
* emits `{ sender, brandId }`.
*
* | Signal | Payload | Emitted after successful |
* |--------|---------|--------------------------|
* | `user` | `{ selectedCompanyId }` | `PUT /auth/selected-company`, `POST /company`, `DELETE /company/{id}` |
* | `company` | `{ companyId }` | `PUT /auth/selected-company`, `POST /company`, `PUT /company/{id}`, `DELETE /company/{id}` |
* | `category` | `{}` | `POST /category`, `PATCH /category/{id}`, `PUT /category/order`, `DELETE /category/{id}`, `POST /category/{id}/image`, `DELETE /category/{id}/image`, `PUT /category/{id}/property` |
* | `articles` | `{}` | `POST /article`, `PATCH /article/{sku}`, `DELETE /article/{sku}`, `PUT /article/{sku}/articles`-style list-level changes, `POST /category/{id}/article` and related article-assigning category mutations |
@@ -70,6 +74,8 @@ export function register(app, basePath = '') {
* - cookieAuth: []
* x-markdown: events.md
* x-sse-events:
* - name: user
* payload: "{ selectedCompanyId }"
* - name: company
* payload: "{ companyId }"
* - name: category
@@ -105,13 +111,17 @@ export function register(app, basePath = '') {
* description: |
* SSE stream (`text/event-stream`). Each signal is an SSE event
* whose name is the signal id. Most signals send `{}` as data;
* `company` sends `{ "companyId": 1 }` and `brand` sends
* `user` sends `{ "selectedCompanyId": 1 }`, `company` sends
* `{ "companyId": 1 }`, and `brand` sends
* `{ "sender": "<x-client-id>", "brandId": 12 }`.
* content:
* text/event-stream:
* schema:
* type: string
* example: |
* event: user
* data: {"selectedCompanyId":1}
*
* event: company
* data: {"companyId":1}
*