mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-14 21:26:15 -08:00
* feat(interfaces): add the server storage HTTP contract Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(web-backend): read server storage configuration Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(web-backend): open the server database and track revisions Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(web-backend): playlist and user-state repositories Playlist documents use the shared desktop row codec, so the server writes the same rows. keepPayload upserts take the stored playlist/items/header fields when the client leaves them out. Xtream user data lives in the server-only server_user_state table, one JSON value per namespace and playlist. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(web-backend): storage error mapping and access token guard Storage errors map to JSON status bodies and are logged by name and code only. An optional bearer token guards every route except /, /health, /config.js and /v1/instance, provider proxy routes included. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(web-backend): serve the /v1 server storage API /v1/instance is always public and reports whether server storage is on. With storage, /v1/playlists serves whole documents with ETags and 304s, accepts keepPayload upserts, and deletes playlists with their user state; /v1/user-state and /v1/app-state store the rest. The proxy routes are unchanged unless an access token is configured. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(web-backend): open server storage on start and close on shutdown With IPTVNATOR_STORAGE=server, main.ts opens the database before it listens and exits with a clear message when the data directory is not writable. SIGTERM and SIGINT close the server and the database. The native better-sqlite3 module stays outside the esbuild bundle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(web-backend): match weakened ETags on playlist reads nginx weakens the ETag of a gzipped response, and clients send the weak form back in If-None-Match. The route now compares tags weakly, as RFC 9110 requires for GET, so it answers 304 before reading the document. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(docker): persist server storage on a volume The image builds better-sqlite3 in a native stage per target platform, enables server storage on the /data volume, and raises the nginx body limit to 64 MB for /api with gzip for JSON. The compose file mounts a named volume and documents the optional access token. The PWA does not use the storage yet; docs say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(web-backend): type the storage route responses Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(web-backend): harden server storage reads, deletes and app state - Metadata reads return the stored document without its payload fields, so fields that live only in the JSON survive a metadata round-trip. - A conditional GET checks that the playlist exists before answering 304. - Deleting a playlist and its user state commits in one transaction; the ETag moves only after the commit. - Browser app state is stored under a client: prefix and the instance id is repaired when empty, so a client write cannot stop the backend. - User-state buckets have no prototype, so ids like __proto__ round-trip. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(self-hosted): keep the access token unset until the PWA sends it Add the release note for the Docker server storage volume. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(web-backend): bound shutdown and reject padded playlist ids - SIGTERM closes idle connections at once and cuts the rest after five seconds, so a long provider download cannot keep the backend running. - Playlist ids with surrounding whitespace are rejected: the row codec trims ids, so storage and ETags would track different keys. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(web-backend): clear optional columns on whole-document upserts The row codec maps empty values to undefined, which ON CONFLICT DO UPDATE skips, so a cleared User-Agent, Referrer or credential kept its old column value and came back on the next read. Server upserts now write NULL to every replaceable column the document no longer sets. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(self-hosted): linear token parsing, no-store app state, longer start - The access guard reads the Bearer token by string scanning instead of a regular expression that CodeQL flagged as polynomial on long whitespace. - GET /v1/app-state/:key sends Cache-Control: no-store like the other state routes, so devices never reuse a stale value. - The entrypoint waits up to IPTVNATOR_BACKEND_START_TIMEOUT (300 s) for /health, because the backend migrates its database before it listens. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(self-hosted): metadata reads skip payloads, redact JSON parse warnings List playlist metadata from a server-only payload-free copy of each document instead of running json_remove over every payload blob, and log only the error name when a stored JSON value fails to parse, since the parser's message quotes the stored text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(web-backend): copy carried-over panel clock into playlist metadata When an upsert keeps the stored serverTimezone, build the metadata copy from the saved payload so metadata and full reads agree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
116 lines
5.2 KiB
TypeScript
116 lines
5.2 KiB
TypeScript
export * from './lib/app-update-channel.util';
|
|
export * from './lib/channel-drm.interface';
|
|
export * from './lib/channel.interface';
|
|
export * from './lib/channel.model';
|
|
export * from './lib/content-metadata.interface';
|
|
export * from './lib/dev-logger.util';
|
|
export * from './lib/download-metadata.interface';
|
|
export * from './lib/embedded-mpv-session.interface';
|
|
export * from './lib/embedded-mpv-support-watch.util';
|
|
export * from './lib/subtitle-style.util';
|
|
export * from './lib/zoom-level.util';
|
|
export * from './lib/macos-traffic-lights';
|
|
export * from './lib/electron-api.interface';
|
|
export * from './lib/epg-channel-metadata.model';
|
|
export * from './lib/epg-channel-with-programs.interface';
|
|
export * from './lib/epg-channel.model';
|
|
export * from './lib/epg-display-offset.util';
|
|
export * from './lib/epg-item.interface';
|
|
export * from './lib/epg-mapping-key.util';
|
|
export * from './lib/epg-program.model';
|
|
export * from './lib/epg-source-reference.util';
|
|
export * from './lib/external-player-arguments.utils';
|
|
export * from './lib/embedded-mpv-extra-options.util';
|
|
export * from './lib/external-player-session.interface';
|
|
export * from './lib/global-search-result.interface';
|
|
export * from './lib/host-connectivity.util';
|
|
export * from './lib/indexed-db.config';
|
|
export * from './lib/ipc-command.class';
|
|
export * from './lib/ipc-commands';
|
|
export * from './lib/language.enum';
|
|
export * from './lib/m3u-favorite-channel.interface';
|
|
export * from './lib/parental-lock.util';
|
|
export * from './lib/parental-lock-pin.util';
|
|
export * from './lib/parental-lock-pin-throttle.util';
|
|
export * from './lib/parsed-playlist.interface';
|
|
export * from './lib/performance-phase.interface';
|
|
export * from './lib/playback-position.interface';
|
|
export * from './lib/playlist-auto-update.interface';
|
|
export * from './lib/playlist-backup.interface';
|
|
export * from './lib/playlist-meta.type';
|
|
export * from './lib/portal-account-playlist.utils';
|
|
export * from './lib/preload-performance-marker.interface';
|
|
export * from './lib/playlist-recently-viewed.interface';
|
|
export * from './lib/playlist-recently-viewed.utils';
|
|
export * from './lib/playlist-refresh.interface';
|
|
export * from './lib/playlist.interface';
|
|
export * from './lib/portal-activity-item.interface';
|
|
export * from './lib/portal-debug.interface';
|
|
export * from './lib/playlist-display-label.util';
|
|
export * from './lib/portal-playback.interface';
|
|
export * from './lib/provider-import-detection.util';
|
|
export * from './lib/source-type-icons.util';
|
|
export * from './lib/provider-overview.util';
|
|
export * from './lib/random-id.util';
|
|
export * from './lib/recording-metadata.interface';
|
|
export * from './lib/recording-program-overlap.util';
|
|
export * from './lib/renderer-reload-route.util';
|
|
export * from './lib/security-policy-error.utils';
|
|
export * from './lib/settings.interface';
|
|
export * from './lib/stalker-auth-failure.util';
|
|
export * from './lib/stalker-cmd-encoding.util';
|
|
export * from './lib/stalker-portal-actions.enum';
|
|
export * from './lib/stalker-portal-mode.util';
|
|
export * from './lib/store-keys.enum';
|
|
export * from './lib/stream-format.enum';
|
|
export * from './lib/catalog-title-match.interface';
|
|
export * from './lib/theme.enum';
|
|
export * from './lib/season-marker.util';
|
|
export * from './lib/search-text-fold.util';
|
|
export * from './lib/stalker-account-info-dialog-data.interface';
|
|
export * from './lib/title-normalization.util';
|
|
export * from './lib/tmdb.interface';
|
|
export * from './lib/vod-source.interface';
|
|
export * from './lib/vod-source-language.util';
|
|
export * from './lib/vod-source-match-key.util';
|
|
export * from './lib/xtream-account-info-dialog-data.interface';
|
|
export * from './lib/xtream-category.interface';
|
|
export * from './lib/xtream-code-actions';
|
|
export * from './lib/xtream-item.interface';
|
|
export * from './lib/xtream-live-stream.interface';
|
|
export * from './lib/xtream-response.interface';
|
|
export * from './lib/xtream-portal.utils';
|
|
export * from './lib/xtream-restore-state.util';
|
|
export * from './lib/xtream-server-timezone.util';
|
|
export * from './lib/xtream-recently-added.utils';
|
|
export * from './lib/xtream-performance-marker.interface';
|
|
export * from './lib/xtream-serie-details.interface';
|
|
export * from './lib/xtream-serie-item.interface';
|
|
export * from './lib/xtream-vod-details.interface';
|
|
export * from './lib/xtream-vod-stream.interface';
|
|
|
|
// Stalker interfaces
|
|
export * from './lib/stalker-item.normalizer';
|
|
export * from './lib/stalker-item-tmdb-hints';
|
|
export * from './lib/stalker-identity.utils';
|
|
export * from './lib/stalker-mac-address.util';
|
|
export * from './lib/stalker-request-identity.util';
|
|
export * from './lib/stalker-stb-profile.const';
|
|
export * from './lib/stalker-request-url.util';
|
|
export * from './lib/stalker-portal-item.interface';
|
|
export * from './lib/stalker-stream-profile.util';
|
|
export * from './lib/stalker-serial-details.interface';
|
|
export * from './lib/stalker-vod-details.interface';
|
|
|
|
// Unified VOD details (discriminated union + adapters)
|
|
export * from './lib/vod-details-adapters';
|
|
export * from './lib/vod-details-item.interface';
|
|
|
|
export * from './lib/catchup-download.interface';
|
|
|
|
export * from './lib/xtream-connection-test';
|
|
export * from './lib/portal-request-failure.util';
|
|
|
|
export * from './lib/source-health';
|
|
export * from './lib/server-storage.contract';
|