@mostajs/media-server 0.2.2 → 0.2.3

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.
Files changed (2) hide show
  1. package/llms.txt +153 -0
  2. package/package.json +9 -4
package/llms.txt ADDED
@@ -0,0 +1,153 @@
1
+ # @mostajs/media-server — fiche LLM
2
+ > Factory + schema + handlers Next.js pour persister les recordings de @mostajs/media : blob via @mostajs/storage, métadonnées via un ORM injecté.
3
+
4
+ - Version: 0.2.2 · Licence: AGPL-3.0-or-later · Auteur: Dr Hamid MADANI <drmdh@msn.com>
5
+ - Chemin: mostajs/mosta-media-stack/mosta-media-server · Statut audit: complet (dist/)
6
+
7
+ ## RÔLE
8
+ Couche serveur de persistance des enregistrements media — PAS une topologie WebRTC.
9
+ Découple les bytes (gérés par `@mostajs/storage` : FS/S3) de la row métadonnée
10
+ (gérée par un `MediaRepository` que le consumer implémente au-dessus de son ORM).
11
+ Fournit : un `MediaService` pur (`createMedia`) et des route handlers Next.js App
12
+ Router prêts à monter (`createRecordingsRoute`, `createMediaByIdRoute`). Le handler
13
+ reste responsable du RBAC (extraction `accountId` tenant) et de la sérialisation HTTP.
14
+ ESM only. Surface storage déclarée localement (`StorageLike`) → pas de hard-dep build.
15
+
16
+ ## INSTALLATION
17
+ ```
18
+ npm i @mostajs/media-server
19
+ ```
20
+ peerDependencies (non optionnelles) : `@mostajs/media ^2.0.4`, `@mostajs/storage ^0.1.2`.
21
+
22
+ ## EXPORTS
23
+ - `createMedia(opts: CreateMediaOptions): MediaService`
24
+ - `createRecordingsRoute(opts: RecordingsRouteOptions): RecordingsRouteHandlers`
25
+ - `createMediaByIdRoute(opts: MediaByIdRouteOptions): MediaByIdRouteHandlers`
26
+ - Types : `MediaKind`, `MediaStatus`, `MediaRow`, `MediaListFilter`, `MediaListResult`,
27
+ `MediaRepository`, `CreateRecordingInput`, `CreateRecordingResult`,
28
+ `MediaWithSignedUrl`, `MediaService`, `StorageLike`, `CreateMediaOptions`,
29
+ `RecordingsRouteOptions`, `RecordingsRouteHandlers`, `MediaByIdRouteOptions`,
30
+ `MediaByIdRouteHandlers`, `GetAccountIdFromRequest`, `MimeAcceptor`
31
+
32
+ ## EXPORTS PAR SOUS-CHEMIN
33
+ Aucun — un seul point d'entrée `"."` dans `exports`. Tout passe par `@mostajs/media-server`.
34
+
35
+ ## API — SIGNATURES
36
+ ```ts
37
+ createMedia(opts: CreateMediaOptions): MediaService
38
+ createRecordingsRoute(opts: RecordingsRouteOptions): RecordingsRouteHandlers
39
+ createMediaByIdRoute(opts: MediaByIdRouteOptions): MediaByIdRouteHandlers
40
+
41
+ interface MediaService {
42
+ createRecording(input: CreateRecordingInput): Promise<CreateRecordingResult>
43
+ updateRecording(id, input: UpdateRecordingInput): Promise<CreateRecordingResult | null> // saveOrUpdate
44
+ getMedia(id): Promise<MediaWithSignedUrl | null>
45
+ reissueSignedUrl(id, ttlSec?): Promise<MediaWithSignedUrl | null>
46
+ deleteMedia(id): Promise<void> // soft-delete + purge blob
47
+ listForAccount(accountId, filter?: MediaListFilter): Promise<MediaListResult>
48
+ }
49
+
50
+ // RecordingsRouteHandlers : POST(req) -> POST /api/media/recordings (multipart)
51
+ // MediaByIdRouteHandlers : GET / PUT / DELETE -> /api/media/[id]
52
+ // GET -> row + signed URL frais (404 absent, 403 tenant mismatch)
53
+ // PUT -> remplace le blob (multipart { blob, mimeType?, durationMs?, metadata? })
54
+ // DELETE -> soft-delete row + purge storage
55
+ ```
56
+
57
+ ## TYPES CLÉS
58
+ ```ts
59
+ type MediaKind = 'video' | 'audio' | 'image' | 'data' // 'data' = blob non-média
60
+ type MediaStatus = 'uploading' | 'ready' | 'deleted' | 'failed'
61
+
62
+ interface MediaRow {
63
+ id: string // UUID/ULID, stable cross-restart
64
+ accountId: string // tenant — clé d'isolation multi-tenant
65
+ ownerEmail?: string | null
66
+ bucket: string // bucket @mostajs/storage, défaut 'media-recordings'
67
+ key: string // path relatif, convention '<accountId>/<id>.<ext>'
68
+ mimeType: string; sizeBytes: number; durationMs: number // durationMs 0 pour image
69
+ kind: MediaKind; status: MediaStatus
70
+ sessionId?: string | null; takeIndex?: number | null // groupage multi-take
71
+ checksum?: string | null; metadata?: Record<string,string> | null
72
+ createdAt: Date | string; updatedAt?: Date | string | null
73
+ }
74
+ // MediaRepository (à implémenter par le consumer, au-dessus de @mostajs/orm/Prisma…) :
75
+ // insert, findById, update, delete, list(accountId, filter?)
76
+ // StorageLike (compatible @mostajs/storage FileStore) : put, delete, signedUrl
77
+
78
+ interface CreateMediaOptions {
79
+ storage: StorageLike // adapter storage
80
+ repo: MediaRepository // repository métadonnée ORM
81
+ defaultBucket?: string // override per-request via input.bucket
82
+ signedUrlTtlSec?: number // défaut 1h
83
+ generateId?: () => string // défaut ULID-like
84
+ }
85
+ interface CreateRecordingInput {
86
+ accountId: string; ownerEmail?: string
87
+ body: Uint8Array | Blob | ArrayBuffer
88
+ mimeType: string; durationMs: number
89
+ kind?: MediaKind // sinon dérivé du mimeType
90
+ sessionId?: string; takeIndex?: number; bucket?: string
91
+ metadata?: Record<string, string>
92
+ }
93
+ interface RecordingsRouteOptions {
94
+ mediaService: MediaService
95
+ getAccountIdFromRequest: GetAccountIdFromRequest // (req) => string | null (null => 401)
96
+ acceptMimeType?: MimeAcceptor // défaut video/* audio/* image/*
97
+ maxSizeBytes?: number // défaut 500 MB
98
+ getOwnerEmail?: (req) => Promise<string|null> | string | null
99
+ }
100
+ ```
101
+
102
+ ## PATTERN
103
+ ```ts
104
+ // lib/media-service.ts
105
+ import { createMedia } from '@mostajs/media-server'
106
+ export const mediaService = createMedia({
107
+ storage, // @mostajs/storage FileStore
108
+ repo: mediaRepository, // implémente MediaRepository sur l'ORM
109
+ signedUrlTtlSec: 3600,
110
+ })
111
+
112
+ // app/api/media/recordings/route.ts
113
+ import { createRecordingsRoute } from '@mostajs/media-server'
114
+ export const runtime = 'nodejs'
115
+ const { POST } = createRecordingsRoute({
116
+ mediaService,
117
+ getAccountIdFromRequest: (req) => getAccountIdFromSession(req),
118
+ maxSizeBytes: 200 * 1024 * 1024,
119
+ })
120
+ export { POST }
121
+
122
+ // app/api/media/[id]/route.ts
123
+ import { createMediaByIdRoute } from '@mostajs/media-server'
124
+ const { GET, PUT, DELETE } = createMediaByIdRoute({ mediaService, getAccountIdFromRequest })
125
+ export { GET, PUT, DELETE }
126
+ ```
127
+
128
+ ## DÉPEND DE
129
+ - `@mostajs/media` (peer requis, ^2.0.4) — fournit les recordings côté client.
130
+ - `@mostajs/storage` (peer requis, ^0.1.2) — persistance des bytes (FileStore).
131
+ La surface attendue est aussi déclarée localement via `StorageLike` (pas de
132
+ hard-dep build-time).
133
+
134
+ ## PIÈGES
135
+ - Le `MediaRepository` n'est PAS fourni : le consumer doit l'implémenter au-dessus
136
+ de son ORM (`@mostajs/orm`, Prisma, repo maison). Il ne manipule que la row.
137
+ - Flux `createRecording` : insert row(status=uploading) → put storage → update
138
+ row(status=ready) → sign URL. Si le put échoue, la row passe à `status=failed`
139
+ (conservée pour audit, blob inexistant/orphelin).
140
+ - RBAC à la charge du handler : `getAccountIdFromRequest` retourne `null` → 401.
141
+ `accountId` ≠ `userId` (clé tenant). GET `/api/media/[id]` renvoie 403 si tenant
142
+ mismatch.
143
+ - `createRecording` (nouveau média) vs `updateRecording` (ré-enregistre, même
144
+ bucket/key, écrase le blob) : pattern saveOrUpdate côté consumer.
145
+ - Build : `tsc` puis script `fix-esm` (ajoute les extensions `.js` aux imports
146
+ relatifs). Les `.d.ts` du dist sont la source de vérité de l'API.
147
+ - `RouteParamsCtx` accepte `params` objet (Next ≤ 14) ET `Promise` (Next ≥ 15).
148
+ - `MediaListFilter` : pagination forward-only par curseur (`cursor` = id dernière
149
+ row), `limit` défaut 50 / max 200, status filtré par défaut sur `ready`.
150
+
151
+ ## RÉFÉRENCES
152
+ - README.md (mosta-media-server) — guide d'intégration.
153
+ - docs/ — documentation complémentaire.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mostajs/media-server",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Server-side factory + schema + service contract for @mostajs/media recordings — pairs with @mostajs/storage for blob persistence and an injected ORM repository for row metadata.",
5
5
  "author": "Dr Hamid MADANI <drmdh@msn.com>",
6
6
  "license": "AGPL-3.0-or-later",
@@ -18,7 +18,8 @@
18
18
  "dist",
19
19
  "README.md",
20
20
  "LICENSE",
21
- "docs"
21
+ "docs",
22
+ "llms.txt"
22
23
  ],
23
24
  "scripts": {
24
25
  "build": "tsc && npm run fix-esm",
@@ -30,8 +31,12 @@
30
31
  "@mostajs/storage": "^0.1.2"
31
32
  },
32
33
  "peerDependenciesMeta": {
33
- "@mostajs/media": { "optional": false },
34
- "@mostajs/storage": { "optional": false }
34
+ "@mostajs/media": {
35
+ "optional": false
36
+ },
37
+ "@mostajs/storage": {
38
+ "optional": false
39
+ }
35
40
  },
36
41
  "devDependencies": {
37
42
  "typescript": "^5.4.0"