sovrium 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -185
- package/package.json +6 -6
- package/src/application/use-cases/server/static-content-generators.ts +18 -2
- package/src/domain/models/api/activity.ts +87 -0
- package/src/domain/models/api/comments.ts +131 -0
- package/src/domain/models/api/index.ts +9 -0
- package/src/domain/models/api/params.ts +83 -0
- package/src/infrastructure/server/route-setup/openapi-routes/activity-routes.ts +72 -0
- package/src/infrastructure/server/route-setup/openapi-routes/analytics-routes.ts +176 -0
- package/src/infrastructure/server/route-setup/openapi-routes/batch-routes.ts +215 -0
- package/src/infrastructure/server/route-setup/openapi-routes/health-routes.ts +38 -0
- package/src/infrastructure/server/route-setup/openapi-routes/record-routes.ts +444 -0
- package/src/infrastructure/server/route-setup/openapi-routes/table-routes.ts +100 -0
- package/src/infrastructure/server/route-setup/openapi-routes/view-routes.ts +104 -0
- package/src/infrastructure/server/route-setup/openapi-schema.ts +40 -40
- package/src/presentation/styling/parse-style.ts +17 -9
- package/schemas/0.0.1/app.openapi.json +0 -70
- package/schemas/0.0.1/app.schema.json +0 -7961
- package/schemas/0.0.2/app.openapi.json +0 -70
- package/schemas/0.0.2/app.schema.json +0 -7456
- package/schemas/0.1.0/app.openapi.json +0 -80
- package/schemas/0.1.0/app.schema.json +0 -8829
package/README.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<h1 align="center">Sovrium</h1>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
1
5
|
<h3 align="center">Build business apps with config. Own your data forever.</h3>
|
|
2
6
|
|
|
3
7
|
<p align="center">
|
|
@@ -7,7 +11,6 @@
|
|
|
7
11
|
|
|
8
12
|
<p align="center">
|
|
9
13
|
<a href="https://github.com/sovrium/sovrium/blob/main/LICENSE.md"><img src="https://img.shields.io/badge/license-BSL--1.1-blue" alt="License" /></a>
|
|
10
|
-
<a href="SPEC-PROGRESS.md"><img src="https://img.shields.io/badge/specs-99%25_passing-brightgreen" alt="Specs" /></a>
|
|
11
14
|
<a href="https://bun.sh"><img src="https://img.shields.io/badge/runtime-Bun_1.3-f472b6" alt="Bun" /></a>
|
|
12
15
|
<a href="https://www.typescriptlang.org"><img src="https://img.shields.io/badge/TypeScript-5.9-3178c6" alt="TypeScript" /></a>
|
|
13
16
|
<a href="https://www.npmjs.com/package/sovrium"><img src="https://img.shields.io/npm/v/sovrium" alt="npm" /></a>
|
|
@@ -15,21 +18,22 @@
|
|
|
15
18
|
</p>
|
|
16
19
|
|
|
17
20
|
<p align="center">
|
|
21
|
+
<a href="https://sovrium.com">Website</a> ·
|
|
18
22
|
<a href="VISION.md">Vision</a> ·
|
|
19
23
|
<a href="SPEC-PROGRESS.md">Roadmap</a> ·
|
|
20
24
|
<a href="CLAUDE.md">Docs</a> ·
|
|
21
25
|
<a href="https://github.com/sovrium/sovrium/issues">Issues</a>
|
|
22
26
|
</p>
|
|
23
27
|
|
|
28
|
+
<!-- TODO: Add a product screenshot or demo GIF here (recommended: 1200x800px). -->
|
|
29
|
+
|
|
24
30
|
---
|
|
25
31
|
|
|
26
32
|
## What is Sovrium?
|
|
27
33
|
|
|
28
|
-
Sovrium turns **configuration
|
|
29
|
-
|
|
30
|
-
No code generation. No external services. Just config and `sovrium start`.
|
|
34
|
+
Sovrium turns a **configuration file** into a complete web application — database, authentication, API, and pages included.
|
|
31
35
|
|
|
32
|
-
|
|
36
|
+
No code generation. No external services. Write a config file, run one command, and your app is live.
|
|
33
37
|
|
|
34
38
|
```yaml
|
|
35
39
|
# sovrium.yaml
|
|
@@ -60,11 +64,15 @@ pages:
|
|
|
60
64
|
content: Welcome to My CRM
|
|
61
65
|
```
|
|
62
66
|
|
|
67
|
+
```bash
|
|
68
|
+
sovrium start sovrium.yaml
|
|
69
|
+
# -> http://localhost:3000
|
|
70
|
+
```
|
|
71
|
+
|
|
63
72
|
<details>
|
|
64
|
-
<summary>
|
|
73
|
+
<summary>Prefer TypeScript? Use it for autocompletion and type checking.</summary>
|
|
65
74
|
|
|
66
75
|
```typescript
|
|
67
|
-
// app.ts
|
|
68
76
|
import { start } from 'sovrium'
|
|
69
77
|
|
|
70
78
|
await start({
|
|
@@ -93,229 +101,101 @@ await start({
|
|
|
93
101
|
|
|
94
102
|
</details>
|
|
95
103
|
|
|
96
|
-
```bash
|
|
97
|
-
sovrium start sovrium.yaml # Run with YAML
|
|
98
|
-
bun run app.ts # Or run with TypeScript
|
|
99
|
-
# -> http://localhost:3000
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
---
|
|
103
|
-
|
|
104
|
-
## Why Sovrium?
|
|
105
|
-
|
|
106
|
-
**The problem**: Organizations pay $10k+/month for 20+ SaaS tools, with data scattered everywhere and zero control.
|
|
107
|
-
|
|
108
|
-
**The solution**: One self-hosted platform that does what you need, configured in files you own.
|
|
109
|
-
|
|
110
|
-
| | Sovrium | SaaS Tools |
|
|
111
|
-
| ------------------- | :-------------: | :----------: |
|
|
112
|
-
| **Data ownership** | Your servers | Vendor cloud |
|
|
113
|
-
| **Monthly cost** | $0 (infra only) | $20-50/user |
|
|
114
|
-
| **Vendor lock-in** | None | Complete |
|
|
115
|
-
| **Customization** | Unlimited | Limited |
|
|
116
|
-
| **Version control** | Git-native | None |
|
|
117
|
-
|
|
118
104
|
---
|
|
119
105
|
|
|
120
|
-
## Quick Start
|
|
106
|
+
## 🚀 Quick Start
|
|
121
107
|
|
|
122
|
-
**
|
|
108
|
+
**You need**: [Bun](https://bun.sh) 1.3+ and [PostgreSQL](https://www.postgresql.org/) 15+
|
|
123
109
|
|
|
124
110
|
```bash
|
|
125
|
-
# Install
|
|
126
111
|
bun add sovrium
|
|
127
|
-
|
|
128
|
-
# Create config
|
|
129
|
-
cat > sovrium.yaml << EOF
|
|
130
|
-
name: my-app
|
|
131
|
-
pages:
|
|
132
|
-
- name: home
|
|
133
|
-
path: /
|
|
134
|
-
sections:
|
|
135
|
-
- type: h1
|
|
136
|
-
content: Hello World
|
|
137
|
-
EOF
|
|
138
|
-
|
|
139
|
-
# Run
|
|
140
112
|
sovrium start sovrium.yaml
|
|
141
|
-
|
|
142
|
-
# Or use environment variable (JSON, YAML, or URL)
|
|
143
|
-
APP_SCHEMA='{"name":"my-app"}' sovrium start
|
|
144
|
-
APP_SCHEMA='name: my-app' sovrium start
|
|
145
|
-
APP_SCHEMA='https://example.com/app.yaml' sovrium start
|
|
146
113
|
```
|
|
147
114
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
## Features
|
|
151
|
-
|
|
152
|
-
### Database & Tables
|
|
153
|
-
|
|
154
|
-
Define your data model in config. Sovrium creates PostgreSQL tables, handles migrations, and exposes a full REST API automatically.
|
|
155
|
-
|
|
156
|
-
- **40 field types** -- text, numeric, date/time, selection, media, relational, user tracking, and advanced types (formula, JSON, geolocation, barcode, autonumber, and more)
|
|
157
|
-
- **Relationships** -- one-to-many and many-to-many with lookup and rollup fields
|
|
158
|
-
- **Views** -- filtered, sorted, and grouped views with field-level visibility
|
|
159
|
-
- **Indexes and constraints** -- primary keys, unique constraints, check constraints
|
|
160
|
-
- **Soft delete** -- built-in trash with restore capability
|
|
161
|
-
- **Permissions** -- role-based table and field-level access control
|
|
162
|
-
- **Schema evolution** -- migration system for safe schema changes
|
|
115
|
+
Your app is running at `http://localhost:3000`.
|
|
163
116
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
Every table gets a full CRUD API with no additional code.
|
|
167
|
-
|
|
168
|
-
- **Records** -- create, read, update, delete with field validation
|
|
169
|
-
- **Batch operations** -- bulk create, update, and upsert
|
|
170
|
-
- **Filtering and sorting** -- query records with field-based filters
|
|
171
|
-
- **Pagination** -- cursor and offset-based pagination
|
|
172
|
-
- **Activity logs** -- audit trail for all record changes
|
|
173
|
-
- **Rate limiting** -- configurable per-endpoint rate limits
|
|
174
|
-
|
|
175
|
-
### Authentication
|
|
176
|
-
|
|
177
|
-
Production-ready auth out of the box.
|
|
178
|
-
|
|
179
|
-
- **Email/password** -- sign up, sign in, email verification, password reset
|
|
180
|
-
- **Magic link** -- passwordless email authentication
|
|
181
|
-
- **Two-factor** -- TOTP-based 2FA
|
|
182
|
-
- **OAuth** -- social login providers
|
|
183
|
-
- **Roles** -- admin, member, viewer with custom roles
|
|
184
|
-
- **Admin plugin** -- user management, banning, impersonation
|
|
185
|
-
- **Session management** -- list, revoke, and manage active sessions
|
|
186
|
-
|
|
187
|
-
### Pages & UI
|
|
188
|
-
|
|
189
|
-
Server-rendered pages with a component-based system.
|
|
190
|
-
|
|
191
|
-
- **Dynamic routing** -- path-based page routing
|
|
192
|
-
- **Sections** -- composable content sections with theming support
|
|
193
|
-
- **Reusable components** -- define once with `$ref`, customize with `$vars`
|
|
194
|
-
- **SEO metadata** -- title, description, Open Graph, structured data
|
|
195
|
-
- **Scripts** -- custom head and body scripts per page
|
|
196
|
-
|
|
197
|
-
### Theming
|
|
117
|
+
---
|
|
198
118
|
|
|
199
|
-
|
|
119
|
+
## ✨ Features
|
|
200
120
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
121
|
+
| | Feature | What you get |
|
|
122
|
+
| :-- | :----------------- | :-------------------------------------------------------------------------------------------------------------------------------------- |
|
|
123
|
+
| 🗄️ | **Tables** | 40 field types including formulas, lookups, and rollups. Views with filtering and sorting. Trash with restore. Granular access control. |
|
|
124
|
+
| 🔌 | **Automatic API** | Every table gets its own API. Filter, sort, paginate, and track changes — no code needed. |
|
|
125
|
+
| 🔐 | **Authentication** | Email/password, magic link, two-factor, social login. Built-in roles (admin, member, viewer) and user management. |
|
|
126
|
+
| 🖥️ | **Pages** | Build pages from reusable sections. Define once, customize with variables. SEO-ready out of the box. |
|
|
127
|
+
| 🎨 | **Theming** | Colors, fonts, spacing, shadows, animations, and responsive breakpoints — all defined in your config file. |
|
|
128
|
+
| 🌐 | **Multi-language** | Built-in translation system with browser language detection and user preference memory. |
|
|
129
|
+
| ⌨️ | **CLI** | `sovrium start` to run your app. `sovrium build` to export a static site. Supports YAML, JSON, and TypeScript. |
|
|
206
130
|
|
|
207
|
-
|
|
131
|
+
---
|
|
208
132
|
|
|
209
|
-
|
|
133
|
+
## 💡 Why Sovrium?
|
|
210
134
|
|
|
211
|
-
|
|
212
|
-
- **Translation tokens** -- `$t:` syntax for referencing translations in pages
|
|
213
|
-
- **Browser detection** -- automatic language detection
|
|
214
|
-
- **Persistence** -- remember user language preference
|
|
135
|
+
Organizations pay **$10k+/month** for 20+ SaaS tools, with data scattered everywhere and zero control.
|
|
215
136
|
|
|
216
|
-
|
|
137
|
+
Sovrium is **one self-hosted platform** that does what you need, configured in files you own.
|
|
217
138
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
139
|
+
| | Sovrium | SaaS Tools |
|
|
140
|
+
| ------------------- | :-------------: | :----------: |
|
|
141
|
+
| **Data ownership** | Your servers | Vendor cloud |
|
|
142
|
+
| **Monthly cost** | $0 (infra only) | $20-50/user |
|
|
143
|
+
| **Vendor lock-in** | None | Complete |
|
|
144
|
+
| **Customization** | Unlimited | Limited |
|
|
145
|
+
| **Version control** | Git-native | None |
|
|
221
146
|
|
|
222
147
|
---
|
|
223
148
|
|
|
224
|
-
##
|
|
149
|
+
## 📊 Status
|
|
225
150
|
|
|
226
|
-
|
|
227
|
-
Config File (YAML/JSON/TS)
|
|
228
|
-
|
|
|
229
|
-
v
|
|
230
|
-
Effect Schema (validation)
|
|
231
|
-
|
|
|
232
|
-
v
|
|
233
|
-
Sovrium Runtime
|
|
234
|
-
|
|
|
235
|
-
+---> PostgreSQL (tables, records, migrations)
|
|
236
|
-
+---> Hono (REST API + SSR)
|
|
237
|
-
+---> Better Auth (sessions, OAuth, 2FA)
|
|
238
|
-
+---> React + Tailwind (server-rendered UI)
|
|
239
|
-
```
|
|
151
|
+
Sovrium is under **active development**. The core feature set — tables, API, authentication, pages, theming, and i18n — is defined and tested across 272 user stories. Implementation is ongoing with automated pipelines.
|
|
240
152
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
| | |
|
|
244
|
-
| :---------------------------------------- | :------------- |
|
|
245
|
-
| [Bun](https://bun.sh) | Runtime |
|
|
246
|
-
| [Hono](https://hono.dev) | Web framework |
|
|
247
|
-
| [Drizzle](https://orm.drizzle.team) | Database ORM |
|
|
248
|
-
| [Effect](https://effect.website) | Type-safe FP |
|
|
249
|
-
| [React 19](https://react.dev) | UI (SSR) |
|
|
250
|
-
| [Tailwind CSS 4](https://tailwindcss.com) | Styling |
|
|
251
|
-
| [Better Auth](https://better-auth.com) | Authentication |
|
|
252
|
-
|
|
253
|
-
### Project Structure
|
|
254
|
-
|
|
255
|
-
```
|
|
256
|
-
src/
|
|
257
|
-
domain/ # Business logic, Effect Schema models
|
|
258
|
-
models/app/ # App configuration schema (tables, auth, pages, theme, ...)
|
|
259
|
-
models/api/ # API contracts (Zod schemas for OpenAPI)
|
|
260
|
-
application/ # Use cases, Effect programs
|
|
261
|
-
infrastructure/ # Database, auth, CSS compiler, email, logging
|
|
262
|
-
presentation/ # API routes, CLI, React components, styling
|
|
263
|
-
specs/ # 2,200+ E2E tests (Playwright)
|
|
264
|
-
docs/ # Architecture and infrastructure documentation
|
|
265
|
-
```
|
|
153
|
+
📋 [See the full roadmap →](SPEC-PROGRESS.md)
|
|
266
154
|
|
|
267
155
|
---
|
|
268
156
|
|
|
269
|
-
##
|
|
157
|
+
## 🤝 Contributing
|
|
270
158
|
|
|
271
|
-
|
|
159
|
+
We welcome contributions of all kinds!
|
|
272
160
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
| App Schema | 131 | 1,398 | 99% |
|
|
279
|
-
| CLI | 9 | 108 | 100% |
|
|
280
|
-
| Migrations | 17 | 139 | 100% |
|
|
281
|
-
| Templates | 1 | 11 | 100% |
|
|
161
|
+
```bash
|
|
162
|
+
git clone https://github.com/sovrium/sovrium
|
|
163
|
+
cd sovrium && bun install
|
|
164
|
+
bun run start
|
|
165
|
+
```
|
|
282
166
|
|
|
283
|
-
|
|
167
|
+
📖 See [CLAUDE.md](CLAUDE.md) for coding standards and architecture details.
|
|
284
168
|
|
|
285
169
|
---
|
|
286
170
|
|
|
287
|
-
##
|
|
171
|
+
## 💬 Community & Support
|
|
288
172
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
bun run quality --skip-e2e # Lint, format, typecheck, unit tests
|
|
293
|
-
bun test:unit # Unit tests only
|
|
294
|
-
bun test:e2e:regression # E2E regression tests
|
|
295
|
-
bun run progress # Spec analysis and progress report
|
|
296
|
-
```
|
|
173
|
+
- [GitHub Issues](https://github.com/sovrium/sovrium/issues) — Bug reports and feature requests
|
|
174
|
+
- [GitHub Discussions](https://github.com/sovrium/sovrium/discussions) — Questions, ideas, and general chat
|
|
175
|
+
- [Vision](VISION.md) — Where Sovrium is headed
|
|
297
176
|
|
|
298
177
|
---
|
|
299
178
|
|
|
300
|
-
|
|
179
|
+
<details>
|
|
180
|
+
<summary>🛠️ Built with</summary>
|
|
181
|
+
<br />
|
|
301
182
|
|
|
302
|
-
|
|
183
|
+
[Bun](https://bun.sh) · [Hono](https://hono.dev) · [Drizzle ORM](https://orm.drizzle.team) · [Effect](https://effect.website) · [React 19](https://react.dev) · [Tailwind CSS 4](https://tailwindcss.com) · [Better Auth](https://better-auth.com)
|
|
303
184
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
```
|
|
185
|
+
See [CLAUDE.md](CLAUDE.md) for the full architecture and project structure.
|
|
186
|
+
|
|
187
|
+
</details>
|
|
308
188
|
|
|
309
189
|
---
|
|
310
190
|
|
|
311
|
-
## License
|
|
191
|
+
## 📄 License
|
|
312
192
|
|
|
313
|
-
[BSL-1.1](LICENSE.md)
|
|
193
|
+
[BSL-1.1](LICENSE.md) — Free for internal and non-commercial use. Automatically converts to **Apache 2.0** on January 1, 2029.
|
|
314
194
|
|
|
315
195
|
---
|
|
316
196
|
|
|
317
197
|
<p align="center">
|
|
318
|
-
<
|
|
198
|
+
<strong>Own your data. Own your tools. Own your future.</strong>
|
|
319
199
|
</p>
|
|
320
200
|
|
|
321
201
|
<p align="center">
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sovrium",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"packageManager": "bun@1.3.10",
|
|
5
5
|
"description": "Configuration-driven web application platform built with Bun, Effect, React, and Tailwind CSS",
|
|
6
6
|
"module": "src/index.ts",
|
|
@@ -48,8 +48,6 @@
|
|
|
48
48
|
],
|
|
49
49
|
"files": [
|
|
50
50
|
"drizzle/**",
|
|
51
|
-
"schemas/**",
|
|
52
|
-
"!schemas/development/**",
|
|
53
51
|
"src/**/*.ts",
|
|
54
52
|
"src/**/*.tsx",
|
|
55
53
|
"src/**/*.css",
|
|
@@ -137,6 +135,7 @@
|
|
|
137
135
|
"globals": "^17.4.0",
|
|
138
136
|
"knip": "^5.85.0",
|
|
139
137
|
"otplib": "^13.3.0",
|
|
138
|
+
"pagefind": "^1.4.0",
|
|
140
139
|
"pg": "^8.19.0",
|
|
141
140
|
"playwright": "^1.58.2",
|
|
142
141
|
"prettier-plugin-tailwindcss": "^0.7.2",
|
|
@@ -147,19 +146,20 @@
|
|
|
147
146
|
"typescript": "^5.9.3"
|
|
148
147
|
},
|
|
149
148
|
"dependencies": {
|
|
149
|
+
"@better-auth/drizzle-adapter": "^1.5.3",
|
|
150
150
|
"@effect/experimental": "^0.58.0",
|
|
151
151
|
"@hono/zod-openapi": "^1.2.2",
|
|
152
152
|
"@hono/zod-validator": "^0.7.6",
|
|
153
153
|
"@hookform/resolvers": "^5.2.2",
|
|
154
|
-
"@scalar/hono-api-reference": "^0.9.
|
|
154
|
+
"@scalar/hono-api-reference": "^0.9.48",
|
|
155
155
|
"@tailwindcss/postcss": "^4.2.1",
|
|
156
156
|
"@tanstack/react-query": "^5.90.21",
|
|
157
157
|
"@tanstack/react-table": "^8.21.3",
|
|
158
|
-
"better-auth": "^1.5.
|
|
158
|
+
"better-auth": "^1.5.3",
|
|
159
159
|
"dompurify": "^3.3.1",
|
|
160
160
|
"drizzle-orm": "^0.45.1",
|
|
161
161
|
"effect": "^3.19.19",
|
|
162
|
-
"hono": "^4.12.
|
|
162
|
+
"hono": "^4.12.4",
|
|
163
163
|
"js-yaml": "^4.1.1",
|
|
164
164
|
"lucide-react": "^0.575.0",
|
|
165
165
|
"nanoid": "^5.1.6",
|
|
@@ -17,18 +17,34 @@ export interface HreflangConfig {
|
|
|
17
17
|
readonly defaultLanguage: string
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Repair whitespace inside <pre> tags that Prettier's HTML formatter damages.
|
|
22
|
+
*
|
|
23
|
+
* Prettier adds a newline + indentation after the opening `>` of `<pre>` tags.
|
|
24
|
+
* Because `<pre>` renders whitespace literally (CSS `white-space: pre`), this
|
|
25
|
+
* introduces a visible blank first line in code blocks.
|
|
26
|
+
*
|
|
27
|
+
* This function strips the newline and any spaces immediately after `<pre ...>`.
|
|
28
|
+
*/
|
|
29
|
+
const repairPreWhitespace = (html: string): string => html.replace(/(<pre[^>]*>)\n[ ]*/g, '$1')
|
|
30
|
+
|
|
20
31
|
/**
|
|
21
32
|
* Format HTML with Prettier for professional formatting
|
|
22
|
-
* Loads Prettier config and formats HTML using the HTML parser
|
|
33
|
+
* Loads Prettier config and formats HTML using the HTML parser.
|
|
34
|
+
*
|
|
35
|
+
* After formatting, repairs `<pre>` whitespace that Prettier damages
|
|
36
|
+
* (leading newline + indentation, trailing whitespace).
|
|
23
37
|
*/
|
|
24
38
|
export const formatHtmlWithPrettier = async (html: string): Promise<string> => {
|
|
25
39
|
const prettier = await import('prettier')
|
|
26
40
|
const config = await prettier.resolveConfig(process.cwd())
|
|
27
41
|
|
|
28
|
-
|
|
42
|
+
const formatted = await prettier.format(html, {
|
|
29
43
|
...config,
|
|
30
44
|
parser: 'html',
|
|
31
45
|
})
|
|
46
|
+
|
|
47
|
+
return repairPreWhitespace(formatted)
|
|
32
48
|
}
|
|
33
49
|
|
|
34
50
|
/**
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 ESSENTIAL SERVICES
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the Business Source License 1.1
|
|
5
|
+
* found in the LICENSE.md file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { z } from 'zod'
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Activity Log Schemas
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Activity log user reference schema
|
|
16
|
+
*/
|
|
17
|
+
export const activityLogUserSchema = z.object({
|
|
18
|
+
id: z.string().describe('User identifier'),
|
|
19
|
+
name: z.string().describe('User display name'),
|
|
20
|
+
email: z.string().describe('User email address'),
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Activity log entry schema (list view)
|
|
25
|
+
*/
|
|
26
|
+
export const activityLogSchema = z.object({
|
|
27
|
+
id: z.string().describe('Activity log identifier'),
|
|
28
|
+
createdAt: z.string().describe('ISO 8601 timestamp of the activity'),
|
|
29
|
+
userId: z.string().optional().describe('User who performed the action'),
|
|
30
|
+
action: z.enum(['create', 'update', 'delete', 'restore']).describe('Action type'),
|
|
31
|
+
tableName: z.string().describe('Name of the affected table'),
|
|
32
|
+
recordId: z.union([z.string(), z.number()]).describe('ID of the affected record'),
|
|
33
|
+
user: activityLogUserSchema.nullable().describe('User details (null for system activities)'),
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Activity log detail schema (single view, includes changes)
|
|
38
|
+
*/
|
|
39
|
+
export const activityLogDetailSchema = activityLogSchema.extend({
|
|
40
|
+
changes: z
|
|
41
|
+
.record(z.string(), z.unknown())
|
|
42
|
+
.nullable()
|
|
43
|
+
.describe('Field changes (null for delete actions)'),
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Activity log pagination schema
|
|
48
|
+
*/
|
|
49
|
+
export const activityPaginationSchema = z.object({
|
|
50
|
+
total: z.number().int().describe('Total count of activities'),
|
|
51
|
+
page: z.number().int().describe('Current page number'),
|
|
52
|
+
pageSize: z.number().int().describe('Items per page'),
|
|
53
|
+
totalPages: z.number().int().describe('Total number of pages'),
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
// ============================================================================
|
|
57
|
+
// Activity Log Response Schemas
|
|
58
|
+
// ============================================================================
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* List activity logs response schema
|
|
62
|
+
*
|
|
63
|
+
* GET /api/activity
|
|
64
|
+
*/
|
|
65
|
+
export const listActivityLogsResponseSchema = z.object({
|
|
66
|
+
activities: z.array(activityLogSchema).describe('List of activity log entries'),
|
|
67
|
+
pagination: activityPaginationSchema.describe('Pagination metadata'),
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get activity log detail response schema
|
|
72
|
+
*
|
|
73
|
+
* GET /api/activity/:activityId
|
|
74
|
+
*/
|
|
75
|
+
export const getActivityLogResponseSchema = activityLogDetailSchema.describe(
|
|
76
|
+
'Single activity log entry with change details'
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
// ============================================================================
|
|
80
|
+
// TypeScript Types
|
|
81
|
+
// ============================================================================
|
|
82
|
+
|
|
83
|
+
export type ActivityLogUser = z.infer<typeof activityLogUserSchema>
|
|
84
|
+
export type ActivityLog = z.infer<typeof activityLogSchema>
|
|
85
|
+
export type ActivityLogDetail = z.infer<typeof activityLogDetailSchema>
|
|
86
|
+
export type ListActivityLogsResponse = z.infer<typeof listActivityLogsResponseSchema>
|
|
87
|
+
export type GetActivityLogResponse = z.infer<typeof getActivityLogResponseSchema>
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 ESSENTIAL SERVICES
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the Business Source License 1.1
|
|
5
|
+
* found in the LICENSE.md file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { z } from 'zod'
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Comment Schemas
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Comment user metadata schema
|
|
16
|
+
*/
|
|
17
|
+
export const commentUserSchema = z.object({
|
|
18
|
+
id: z.string().describe('User identifier'),
|
|
19
|
+
name: z.string().describe('User display name'),
|
|
20
|
+
email: z.string().describe('User email address'),
|
|
21
|
+
image: z.string().nullable().optional().describe('User avatar URL'),
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Comment response schema
|
|
26
|
+
*/
|
|
27
|
+
export const commentSchema = z.object({
|
|
28
|
+
id: z.string().describe('Comment identifier'),
|
|
29
|
+
content: z.string().describe('Comment content'),
|
|
30
|
+
userId: z.string().describe('Author user ID'),
|
|
31
|
+
recordId: z.union([z.string(), z.number()]).describe('Parent record ID'),
|
|
32
|
+
tableId: z.union([z.string(), z.number()]).describe('Parent table ID'),
|
|
33
|
+
createdAt: z.string().describe('ISO 8601 creation timestamp'),
|
|
34
|
+
updatedAt: z.string().describe('ISO 8601 last update timestamp'),
|
|
35
|
+
user: commentUserSchema.describe('Comment author details'),
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Comment pagination schema
|
|
40
|
+
*/
|
|
41
|
+
export const commentPaginationSchema = z.object({
|
|
42
|
+
total: z.number().int().describe('Total count of comments'),
|
|
43
|
+
limit: z.number().int().describe('Items returned'),
|
|
44
|
+
offset: z.number().int().describe('Items skipped'),
|
|
45
|
+
hasMore: z.boolean().describe('Whether more results exist'),
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* List comments response schema
|
|
50
|
+
*
|
|
51
|
+
* GET /api/tables/:tableId/records/:recordId/comments
|
|
52
|
+
*/
|
|
53
|
+
export const listCommentsResponseSchema = z.object({
|
|
54
|
+
comments: z.array(commentSchema).describe('List of comments'),
|
|
55
|
+
pagination: commentPaginationSchema.describe('Pagination metadata'),
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Get single comment response schema
|
|
60
|
+
*
|
|
61
|
+
* GET /api/tables/:tableId/records/:recordId/comments/:commentId
|
|
62
|
+
*/
|
|
63
|
+
export const getCommentResponseSchema = commentSchema.describe('Single comment details')
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Create comment response schema
|
|
67
|
+
*
|
|
68
|
+
* POST /api/tables/:tableId/records/:recordId/comments
|
|
69
|
+
*/
|
|
70
|
+
export const createCommentResponseSchema = z.object({
|
|
71
|
+
comment: commentSchema.describe('Created comment'),
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Update comment response schema
|
|
76
|
+
*
|
|
77
|
+
* PATCH /api/tables/:tableId/records/:recordId/comments/:commentId
|
|
78
|
+
*/
|
|
79
|
+
export const updateCommentResponseSchema = commentSchema.describe('Updated comment details')
|
|
80
|
+
|
|
81
|
+
// ============================================================================
|
|
82
|
+
// Record History Schemas
|
|
83
|
+
// ============================================================================
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Record history entry schema
|
|
87
|
+
*/
|
|
88
|
+
export const recordHistoryEntrySchema = z.object({
|
|
89
|
+
id: z.string().describe('Activity log identifier'),
|
|
90
|
+
userId: z.string().optional().describe('User who performed the action'),
|
|
91
|
+
action: z.enum(['create', 'update', 'delete', 'restore']).describe('Action type'),
|
|
92
|
+
tableName: z.string().describe('Name of the affected table'),
|
|
93
|
+
recordId: z.union([z.string(), z.number()]).describe('ID of the affected record'),
|
|
94
|
+
changes: z
|
|
95
|
+
.record(z.string(), z.unknown())
|
|
96
|
+
.nullable()
|
|
97
|
+
.describe('Field changes (null for delete/restore)'),
|
|
98
|
+
createdAt: z.string().describe('ISO 8601 timestamp'),
|
|
99
|
+
user: z
|
|
100
|
+
.object({
|
|
101
|
+
id: z.string().describe('User identifier'),
|
|
102
|
+
name: z.string().describe('User display name'),
|
|
103
|
+
email: z.string().describe('User email address'),
|
|
104
|
+
})
|
|
105
|
+
.nullable()
|
|
106
|
+
.describe('User details (null for system activities)'),
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Get record history response schema
|
|
111
|
+
*
|
|
112
|
+
* GET /api/tables/:tableId/records/:recordId/history
|
|
113
|
+
*/
|
|
114
|
+
export const getRecordHistoryResponseSchema = z.object({
|
|
115
|
+
history: z.array(recordHistoryEntrySchema).describe('List of history entries'),
|
|
116
|
+
pagination: z
|
|
117
|
+
.object({
|
|
118
|
+
total: z.number().int().describe('Total activity count'),
|
|
119
|
+
limit: z.number().int().describe('Items returned'),
|
|
120
|
+
offset: z.number().int().describe('Items skipped'),
|
|
121
|
+
})
|
|
122
|
+
.optional()
|
|
123
|
+
.describe('Pagination metadata'),
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
// ============================================================================
|
|
127
|
+
// TypeScript Types
|
|
128
|
+
// ============================================================================
|
|
129
|
+
|
|
130
|
+
export type Comment = z.infer<typeof commentSchema>
|
|
131
|
+
export type RecordHistoryEntry = z.infer<typeof recordHistoryEntrySchema>
|
|
@@ -20,6 +20,9 @@
|
|
|
20
20
|
* - request: Request input validation
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
+
// Activity log schemas
|
|
24
|
+
export * from './activity'
|
|
25
|
+
|
|
23
26
|
// Analytics schemas
|
|
24
27
|
export * from './analytics'
|
|
25
28
|
|
|
@@ -35,8 +38,14 @@ export * from './health'
|
|
|
35
38
|
// Authentication schemas
|
|
36
39
|
export * from './auth'
|
|
37
40
|
|
|
41
|
+
// Comment and history schemas
|
|
42
|
+
export * from './comments'
|
|
43
|
+
|
|
38
44
|
// Table and record schemas
|
|
39
45
|
export * from './tables'
|
|
40
46
|
|
|
47
|
+
// OpenAPI parameter schemas
|
|
48
|
+
export * from './params'
|
|
49
|
+
|
|
41
50
|
// Request schemas (input validation)
|
|
42
51
|
export * from './request'
|