ras-stack 0.4.0 → 0.5.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 +30 -5
- package/dist/realtime/client.d.ts +29 -0
- package/dist/realtime/client.js +133 -0
- package/dist/realtime/client.js.map +1 -0
- package/dist/realtime/index.d.ts +1 -0
- package/dist/realtime/index.js +1 -0
- package/dist/realtime/index.js.map +1 -1
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ The package contains independent helpers for common application infrastructure:
|
|
|
14
14
|
|
|
15
15
|
- **Authentication:** secure defaults and utilities for sessions, rate limits, secrets, social providers, tokens, and trusted origins.
|
|
16
16
|
- **Server requests:** same-origin mutation guards, error-normalizing RPC wrappers, canonical-host redirects, and health responses.
|
|
17
|
-
- **Realtime:** Centrifugo token signing and a bounded publisher with retries and graceful shutdown.
|
|
17
|
+
- **Realtime:** Centrifugo client lifecycle, token signing, presence synchronization, and a bounded publisher with retries and graceful shutdown.
|
|
18
18
|
- **Email:** SMTP environment parsing and a small Nodemailer delivery interface.
|
|
19
19
|
- **Uploads:** a promise-based wrapper around resumable `tus-js-client` uploads.
|
|
20
20
|
- **Project configuration:** shared TypeScript and Oxlint bases.
|
|
@@ -35,10 +35,11 @@ The libraries underneath remain available normally. Applications still configure
|
|
|
35
35
|
pnpm add ras-stack
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
Nodemailer and `tus-js-client` are optional peer dependencies. Install one only when using its
|
|
38
|
+
Nodemailer, Centrifuge, and `tus-js-client` are optional peer dependencies. Install one only when using its integration:
|
|
39
39
|
|
|
40
40
|
```sh
|
|
41
41
|
pnpm add nodemailer
|
|
42
|
+
pnpm add centrifuge
|
|
42
43
|
pnpm add tus-js-client
|
|
43
44
|
```
|
|
44
45
|
|
|
@@ -89,10 +90,18 @@ Only enable `trustForwardedHeaders` behind a proxy that replaces incoming forwar
|
|
|
89
90
|
|
|
90
91
|
## Realtime updates
|
|
91
92
|
|
|
92
|
-
Applications choose their channel names, authorize subscriptions, and define payloads. `ras-stack` handles Centrifugo's HTTP publication and
|
|
93
|
+
Applications choose their channel names, authorize subscriptions, and define payloads. `ras-stack` handles Centrifugo's HTTP publication, signed tokens, and repeated browser lifecycle mechanics:
|
|
93
94
|
|
|
94
95
|
```ts
|
|
95
|
-
import {
|
|
96
|
+
import {
|
|
97
|
+
CentrifugoPublisher,
|
|
98
|
+
connectRealtimeClient,
|
|
99
|
+
createSameOriginRealtimeClient,
|
|
100
|
+
openRealtimeSubscription,
|
|
101
|
+
requestRealtimeTicket,
|
|
102
|
+
signRealtimeToken,
|
|
103
|
+
watchSubscriptionPresence,
|
|
104
|
+
} from 'ras-stack/realtime'
|
|
96
105
|
|
|
97
106
|
const publisher = new CentrifugoPublisher({
|
|
98
107
|
apiUrl,
|
|
@@ -107,9 +116,25 @@ publisher.publish(`battle:${battle.id}`, { type: 'change' })
|
|
|
107
116
|
const token = signRealtimeToken(user.id, { channel: `battle:${battle.id}`, info: presence }, { secret })
|
|
108
117
|
|
|
109
118
|
await publisher.close()
|
|
119
|
+
|
|
120
|
+
const client = createSameOriginRealtimeClient({
|
|
121
|
+
getToken: () => requestRealtimeTicket('/api/realtime/token', { parse: (value) => (value as { token: string }).token }),
|
|
122
|
+
})
|
|
123
|
+
const channelToken = (channel: string) =>
|
|
124
|
+
requestRealtimeTicket('/api/realtime/token', {
|
|
125
|
+
init: { method: 'POST', body: JSON.stringify({ channel }) },
|
|
126
|
+
parse: (value) => (value as { token: string }).token,
|
|
127
|
+
})
|
|
128
|
+
const disconnect = connectRealtimeClient(client)
|
|
129
|
+
const live = openRealtimeSubscription(client, channel, { getToken: ({ channel }) => channelToken(channel) }, (subscription) =>
|
|
130
|
+
watchSubscriptionPresence(subscription, setClients),
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
live.close()
|
|
134
|
+
disconnect()
|
|
110
135
|
```
|
|
111
136
|
|
|
112
|
-
`publish()` returns `false` when the publisher is closed, disabled, or at capacity. `close()` rejects new work and waits for accepted publications and their bounded retries to finish.
|
|
137
|
+
The client helpers return the underlying Centrifuge client and subscription. React ownership, channel conventions, ticket validation, event parsing, presence models, and query invalidation remain application code. `publish()` returns `false` when the publisher is closed, disabled, or at capacity. `close()` rejects new work and waits for accepted publications and their bounded retries to finish.
|
|
113
138
|
|
|
114
139
|
## Email and uploads
|
|
115
140
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Centrifuge, type ClientInfo, type Options, type ServerPublicationContext, type ServerSubscribedContext, type Subscription, type SubscriptionOptions } from 'centrifuge';
|
|
2
|
+
type BrowserLocation = Pick<Location, 'host' | 'protocol'>;
|
|
3
|
+
export declare function sameOriginWebSocketUrl(location: BrowserLocation, path?: string): string;
|
|
4
|
+
export type RealtimeTicketOptions<T> = {
|
|
5
|
+
fetch?: typeof fetch;
|
|
6
|
+
init?: RequestInit;
|
|
7
|
+
parse: (value: unknown) => T;
|
|
8
|
+
unauthorizedStatuses?: readonly number[];
|
|
9
|
+
errorMessage?: (status: number) => string;
|
|
10
|
+
};
|
|
11
|
+
export declare function requestRealtimeTicket<T>(input: RequestInfo | URL, options: RealtimeTicketOptions<T>): Promise<T>;
|
|
12
|
+
export declare function createSameOriginRealtimeClient(options: Partial<Options>, config?: {
|
|
13
|
+
location?: BrowserLocation;
|
|
14
|
+
path?: string;
|
|
15
|
+
}): Centrifuge;
|
|
16
|
+
export declare function connectRealtimeClient(client: Centrifuge): () => void;
|
|
17
|
+
export type RealtimeSubscription = {
|
|
18
|
+
subscription: Subscription;
|
|
19
|
+
close: () => void;
|
|
20
|
+
};
|
|
21
|
+
export declare function openRealtimeSubscription(client: Centrifuge, channel: string, options?: SubscriptionOptions, configure?: (subscription: Subscription) => void | (() => void)): RealtimeSubscription;
|
|
22
|
+
export declare function watchServerChannel(client: Centrifuge, channel: string, handlers: {
|
|
23
|
+
publication?: (context: ServerPublicationContext) => void;
|
|
24
|
+
unrecovered?: (context: ServerSubscribedContext) => void;
|
|
25
|
+
}): () => void;
|
|
26
|
+
export declare function watchSubscriptionPresence(subscription: Subscription, update: (clients: Record<string, ClientInfo>) => void, options?: {
|
|
27
|
+
onError?: (error: unknown) => void;
|
|
28
|
+
}): () => void;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { Centrifuge, UnauthorizedError, } from 'centrifuge';
|
|
2
|
+
export function sameOriginWebSocketUrl(location, path = '/connection/websocket') {
|
|
3
|
+
if (!path.startsWith('/') || path.startsWith('//'))
|
|
4
|
+
throw new Error('WebSocket path must be same-origin');
|
|
5
|
+
const url = new URL(path, `${location.protocol}//${location.host}`);
|
|
6
|
+
url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
7
|
+
return url.toString();
|
|
8
|
+
}
|
|
9
|
+
export async function requestRealtimeTicket(input, options) {
|
|
10
|
+
const response = await (options.fetch ?? fetch)(input, options.init);
|
|
11
|
+
if ((options.unauthorizedStatuses ?? [401, 403]).includes(response.status))
|
|
12
|
+
throw new UnauthorizedError('unauthorized');
|
|
13
|
+
if (!response.ok)
|
|
14
|
+
throw new Error(options.errorMessage?.(response.status) ?? `Realtime authentication failed with status ${response.status}`);
|
|
15
|
+
return options.parse(await response.json());
|
|
16
|
+
}
|
|
17
|
+
export function createSameOriginRealtimeClient(options, config = {}) {
|
|
18
|
+
const location = config.location ?? window.location;
|
|
19
|
+
return new Centrifuge(sameOriginWebSocketUrl(location, config.path), options);
|
|
20
|
+
}
|
|
21
|
+
export function connectRealtimeClient(client) {
|
|
22
|
+
client.connect();
|
|
23
|
+
return () => client.disconnect();
|
|
24
|
+
}
|
|
25
|
+
export function openRealtimeSubscription(client, channel, options = {}, configure) {
|
|
26
|
+
const subscription = client.newSubscription(channel, options);
|
|
27
|
+
let cleanup;
|
|
28
|
+
try {
|
|
29
|
+
cleanup = configure?.(subscription);
|
|
30
|
+
subscription.subscribe();
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
client.removeSubscription(subscription);
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
let closed = false;
|
|
37
|
+
return {
|
|
38
|
+
subscription,
|
|
39
|
+
close: () => {
|
|
40
|
+
if (closed)
|
|
41
|
+
return;
|
|
42
|
+
closed = true;
|
|
43
|
+
try {
|
|
44
|
+
cleanup?.();
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
client.removeSubscription(subscription);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export function watchServerChannel(client, channel, handlers) {
|
|
53
|
+
const publication = (context) => {
|
|
54
|
+
if (context.channel === channel)
|
|
55
|
+
handlers.publication?.(context);
|
|
56
|
+
};
|
|
57
|
+
const subscribed = (context) => {
|
|
58
|
+
if (context.channel === channel && context.wasRecovering && !context.recovered)
|
|
59
|
+
handlers.unrecovered?.(context);
|
|
60
|
+
};
|
|
61
|
+
client.on('publication', publication);
|
|
62
|
+
client.on('subscribed', subscribed);
|
|
63
|
+
return () => {
|
|
64
|
+
client.off('publication', publication);
|
|
65
|
+
client.off('subscribed', subscribed);
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
export function watchSubscriptionPresence(subscription, update, options = {}) {
|
|
69
|
+
const clients = new Map();
|
|
70
|
+
let active = true;
|
|
71
|
+
let revision = 0;
|
|
72
|
+
let refreshing;
|
|
73
|
+
const render = () => update(Object.fromEntries(clients));
|
|
74
|
+
const sync = async () => {
|
|
75
|
+
const requestedAt = revision;
|
|
76
|
+
try {
|
|
77
|
+
const snapshot = await subscription.presence();
|
|
78
|
+
if (!active)
|
|
79
|
+
return;
|
|
80
|
+
if (revision !== requestedAt)
|
|
81
|
+
return sync();
|
|
82
|
+
clients.clear();
|
|
83
|
+
for (const [id, info] of Object.entries(snapshot.clients))
|
|
84
|
+
clients.set(id, info);
|
|
85
|
+
render();
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (!active)
|
|
89
|
+
return;
|
|
90
|
+
if (revision !== requestedAt)
|
|
91
|
+
return sync();
|
|
92
|
+
clients.clear();
|
|
93
|
+
render();
|
|
94
|
+
options.onError?.(error);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const refresh = () => {
|
|
98
|
+
if (refreshing)
|
|
99
|
+
return refreshing;
|
|
100
|
+
refreshing = sync().finally(() => {
|
|
101
|
+
refreshing = undefined;
|
|
102
|
+
});
|
|
103
|
+
return refreshing;
|
|
104
|
+
};
|
|
105
|
+
const subscribed = () => {
|
|
106
|
+
revision++;
|
|
107
|
+
void refresh();
|
|
108
|
+
};
|
|
109
|
+
const join = ({ info }) => {
|
|
110
|
+
revision++;
|
|
111
|
+
clients.set(info.client, info);
|
|
112
|
+
render();
|
|
113
|
+
};
|
|
114
|
+
const leave = ({ info }) => {
|
|
115
|
+
revision++;
|
|
116
|
+
clients.delete(info.client);
|
|
117
|
+
render();
|
|
118
|
+
};
|
|
119
|
+
subscription.on('subscribed', subscribed);
|
|
120
|
+
subscription.on('join', join);
|
|
121
|
+
subscription.on('leave', leave);
|
|
122
|
+
return () => {
|
|
123
|
+
if (!active)
|
|
124
|
+
return;
|
|
125
|
+
active = false;
|
|
126
|
+
subscription.off('subscribed', subscribed);
|
|
127
|
+
subscription.off('join', join);
|
|
128
|
+
subscription.off('leave', leave);
|
|
129
|
+
clients.clear();
|
|
130
|
+
render();
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/realtime/client.ts"],"names":[],"mappings":"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"}
|
package/dist/realtime/index.d.ts
CHANGED
package/dist/realtime/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/realtime/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/realtime/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ras-stack",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Composable full-stack primitives shared across Richard Solomou's applications.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"authentication",
|
|
@@ -76,6 +76,7 @@
|
|
|
76
76
|
"@tanstack/react-start": "^1.168.32",
|
|
77
77
|
"@types/node": "^26.0.0",
|
|
78
78
|
"@types/nodemailer": "^8.0.1",
|
|
79
|
+
"centrifuge": "5.7.0",
|
|
79
80
|
"nodemailer": "^9.0.3",
|
|
80
81
|
"oxfmt": "^0.59.0",
|
|
81
82
|
"oxlint": "^1.74.0",
|
|
@@ -87,6 +88,7 @@
|
|
|
87
88
|
"peerDependencies": {
|
|
88
89
|
"@tanstack/react-query": ">=5 <6",
|
|
89
90
|
"@tanstack/react-start": ">=1 <2",
|
|
91
|
+
"centrifuge": ">=5 <6",
|
|
90
92
|
"nodemailer": ">=9 <10",
|
|
91
93
|
"tus-js-client": ">=4 <5"
|
|
92
94
|
},
|
|
@@ -97,6 +99,9 @@
|
|
|
97
99
|
"@tanstack/react-start": {
|
|
98
100
|
"optional": true
|
|
99
101
|
},
|
|
102
|
+
"centrifuge": {
|
|
103
|
+
"optional": true
|
|
104
|
+
},
|
|
100
105
|
"nodemailer": {
|
|
101
106
|
"optional": true
|
|
102
107
|
},
|