@portalshq/capabilities-redirect 0.0.2
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/package.json +23 -0
- package/src/index.ts +69 -0
- package/tsconfig.json +10 -0
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@portalshq/capabilities-redirect",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/portalshq/portals-cloud"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc -p tsconfig.json",
|
|
13
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
14
|
+
},
|
|
15
|
+
"peerDependencies": {
|
|
16
|
+
"express": "^4.0.0"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"typescript": "^5.4.0",
|
|
20
|
+
"@types/express": "^4.17.21",
|
|
21
|
+
"@types/node": "^20.0.0"
|
|
22
|
+
}
|
|
23
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { Request, Response, NextFunction } from "express";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Anything that can answer "what's live right now, in priority order" can
|
|
5
|
+
* back the redirect. Today there's at most one live channel, so order is
|
|
6
|
+
* moot -- but this is deliberately the same shape a future ranked feed
|
|
7
|
+
* (the "scroll between channels" experience) would implement, so wiring
|
|
8
|
+
* that in later doesn't require touching this middleware at all.
|
|
9
|
+
*/
|
|
10
|
+
export interface LiveChannelRegistry {
|
|
11
|
+
/** Live channel ids, most-preferred first. Empty array if nothing is live. */
|
|
12
|
+
listLive(): string[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Minimal in-memory implementation of LiveChannelRegistry. Intended to be
|
|
17
|
+
* driven directly by your RealtimeEngine's onActivate/onTick/onDeactivate
|
|
18
|
+
* callbacks (markLive when a session starts, markEnded when it ends) --
|
|
19
|
+
* see the integration guide. Swappable later for a ranked-feed
|
|
20
|
+
* implementation without changing any caller.
|
|
21
|
+
*/
|
|
22
|
+
export class InMemoryLiveChannelRegistry implements LiveChannelRegistry {
|
|
23
|
+
private live = new Set<string>();
|
|
24
|
+
|
|
25
|
+
markLive(channelId: string): void {
|
|
26
|
+
this.live.add(channelId);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
markEnded(channelId: string): void {
|
|
30
|
+
this.live.delete(channelId);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
listLive(): string[] {
|
|
34
|
+
return [...this.live];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface InstantRedirectOptions {
|
|
39
|
+
registry: LiveChannelRegistry;
|
|
40
|
+
/** Default: (id) => `/channel/${id}` */
|
|
41
|
+
channelPath?: (channelId: string) => string;
|
|
42
|
+
/** Default: "/upcoming" */
|
|
43
|
+
fallbackPath?: string;
|
|
44
|
+
/** Which incoming path triggers the redirect check. Default "/" */
|
|
45
|
+
matchPath?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Express middleware that redirects GET "/" straight to a live channel
|
|
50
|
+
* (or "/upcoming" if nothing's live) using only an in-memory lookup --
|
|
51
|
+
* no DB query, no client JS needs to run first. Mount this BEFORE your
|
|
52
|
+
* static/SPA-catch-all handlers.
|
|
53
|
+
*/
|
|
54
|
+
export function createInstantRedirectMiddleware(opts: InstantRedirectOptions) {
|
|
55
|
+
const channelPath = opts.channelPath ?? ((id: string) => `/channel/${id}`);
|
|
56
|
+
const fallbackPath = opts.fallbackPath ?? "/upcoming";
|
|
57
|
+
const matchPath = opts.matchPath ?? "/";
|
|
58
|
+
|
|
59
|
+
return function instantRedirect(req: Request, res: Response, next: NextFunction): void {
|
|
60
|
+
if (req.method !== "GET" || req.path !== matchPath) {
|
|
61
|
+
next();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const [preferredChannelId] = opts.registry.listLive();
|
|
66
|
+
const destination = preferredChannelId ? channelPath(preferredChannelId) : fallbackPath;
|
|
67
|
+
res.redirect(302, destination);
|
|
68
|
+
};
|
|
69
|
+
}
|