@powersync/service-rsocket-router 0.0.0-dev-20250507154604 → 0.0.0-dev-20250611110033
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.
|
@@ -1,8 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is a small Router wrapper which uses the RSocket lib
|
|
3
|
+
* to expose reactive websocket stream in an interface similar to
|
|
4
|
+
* other Journey micro routers.
|
|
5
|
+
*/
|
|
6
|
+
import { Logger } from '@powersync/lib-services-framework';
|
|
1
7
|
import * as http from 'http';
|
|
2
8
|
import { Payload } from 'rsocket-core';
|
|
3
9
|
import { SocketRouterObserver } from './SocketRouterListener.js';
|
|
4
10
|
import { CommonParams, IReactiveStream, IReactiveStreamInput, ReactiveSocketRouterOptions, SocketResponder } from './types.js';
|
|
5
|
-
export
|
|
11
|
+
export interface ReactiveStreamRequest {
|
|
12
|
+
payload: Payload;
|
|
13
|
+
metadataMimeType: string;
|
|
14
|
+
dataMimeType: string;
|
|
15
|
+
initialN: number;
|
|
16
|
+
responder: SocketResponder;
|
|
17
|
+
}
|
|
18
|
+
export interface SocketBaseContext {
|
|
19
|
+
logger: Logger;
|
|
20
|
+
}
|
|
21
|
+
export declare class ReactiveSocketRouter<C extends SocketBaseContext> {
|
|
6
22
|
protected options?: ReactiveSocketRouterOptions<C> | undefined;
|
|
7
23
|
constructor(options?: ReactiveSocketRouterOptions<C> | undefined);
|
|
8
24
|
reactiveStream<I, O>(path: string, stream: IReactiveStreamInput<I, O, C>): IReactiveStream<I, O, C>;
|
|
@@ -12,8 +28,4 @@ export declare class ReactiveSocketRouter<C> {
|
|
|
12
28
|
*/
|
|
13
29
|
applyWebSocketEndpoints<I>(server: http.Server, params: CommonParams<C>): Promise<import("rsocket-core").Closeable>;
|
|
14
30
|
}
|
|
15
|
-
export declare function handleReactiveStream<Context>(context: Context, request:
|
|
16
|
-
payload: Payload;
|
|
17
|
-
initialN: number;
|
|
18
|
-
responder: SocketResponder;
|
|
19
|
-
}, observer: SocketRouterObserver, abortController: AbortController, params: CommonParams<Context>): Promise<void>;
|
|
31
|
+
export declare function handleReactiveStream<Context extends SocketBaseContext>(context: Context, request: ReactiveStreamRequest, observer: SocketRouterObserver, abortController: AbortController, params: CommonParams<Context>): Promise<void>;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* to expose reactive websocket stream in an interface similar to
|
|
4
4
|
* other Journey micro routers.
|
|
5
5
|
*/
|
|
6
|
-
import { errors, logger } from '@powersync/lib-services-framework';
|
|
6
|
+
import { ErrorCode, errors, logger } from '@powersync/lib-services-framework';
|
|
7
7
|
import { RSocketServer } from 'rsocket-core';
|
|
8
8
|
import * as ws from 'ws';
|
|
9
9
|
import { SocketRouterObserver } from './SocketRouterListener.js';
|
|
@@ -61,17 +61,22 @@ export class ReactiveSocketRouter {
|
|
|
61
61
|
// Throwing an exception in this context will be returned to the client side request
|
|
62
62
|
if (!payload.metadata) {
|
|
63
63
|
// Meta data is required for endpoint handler path matching
|
|
64
|
-
throw new errors.AuthorizationError('No context meta data provided');
|
|
64
|
+
throw new errors.AuthorizationError(ErrorCode.PSYNC_S2101, 'No context meta data provided');
|
|
65
65
|
}
|
|
66
|
-
const
|
|
66
|
+
const metadataMimeType = payload.metadataMimeType;
|
|
67
|
+
const dataMimeType = payload.dataMimeType;
|
|
68
|
+
const context = await params.contextProvider({
|
|
69
|
+
mimeType: payload.metadataMimeType,
|
|
70
|
+
contents: payload.metadata
|
|
71
|
+
});
|
|
67
72
|
return {
|
|
68
73
|
// RequestStream is currently the only supported connection type
|
|
69
74
|
requestStream: (payload, initialN, responder) => {
|
|
70
75
|
const observer = new SocketRouterObserver();
|
|
71
76
|
const abortController = new AbortController();
|
|
72
77
|
// TODO: Consider limiting the number of active streams per connection to prevent abuse
|
|
73
|
-
handleReactiveStream(context, { payload, initialN, responder }, observer, abortController, params).catch((ex) => {
|
|
74
|
-
logger.error(ex);
|
|
78
|
+
handleReactiveStream(context, { payload, initialN, responder, dataMimeType, metadataMimeType }, observer, abortController, params).catch((ex) => {
|
|
79
|
+
context.logger.error(ex);
|
|
75
80
|
responder.onError(ex);
|
|
76
81
|
responder.onComplete();
|
|
77
82
|
});
|
|
@@ -105,14 +110,22 @@ export async function handleReactiveStream(context, request, observer, abortCont
|
|
|
105
110
|
if (!metadata) {
|
|
106
111
|
return exitWithError(new errors.ValidationError('Metadata is not provided'));
|
|
107
112
|
}
|
|
108
|
-
const meta = await params.metaDecoder(
|
|
113
|
+
const meta = await params.metaDecoder({
|
|
114
|
+
mimeType: request.metadataMimeType,
|
|
115
|
+
contents: metadata
|
|
116
|
+
});
|
|
109
117
|
const { path } = meta;
|
|
110
118
|
const route = params.endpoints.find((e) => e.path == path && e.type == RS_ENDPOINT_TYPE.STREAM);
|
|
111
119
|
if (!route) {
|
|
112
120
|
return exitWithError(new errors.RouteNotFound(path));
|
|
113
121
|
}
|
|
114
122
|
const { handler, authorize, validator, decoder = params.payloadDecoder } = route;
|
|
115
|
-
const requestPayload = await decoder(payload.data
|
|
123
|
+
const requestPayload = await decoder(payload.data
|
|
124
|
+
? {
|
|
125
|
+
contents: payload.data,
|
|
126
|
+
mimeType: request.dataMimeType
|
|
127
|
+
}
|
|
128
|
+
: undefined);
|
|
116
129
|
if (validator) {
|
|
117
130
|
const isValid = validator.validate(requestPayload);
|
|
118
131
|
if (!isValid.valid) {
|
|
@@ -128,7 +141,7 @@ export async function handleReactiveStream(context, request, observer, abortCont
|
|
|
128
141
|
responder
|
|
129
142
|
});
|
|
130
143
|
if (!isAuthorized.authorized) {
|
|
131
|
-
return exitWithError(new errors.AuthorizationError(
|
|
144
|
+
return exitWithError(isAuthorized.error ?? new errors.AuthorizationError(ErrorCode.PSYNC_S2101, 'Authorization failed'));
|
|
132
145
|
}
|
|
133
146
|
}
|
|
134
147
|
try {
|
|
@@ -147,7 +160,7 @@ export async function handleReactiveStream(context, request, observer, abortCont
|
|
|
147
160
|
responder.onComplete();
|
|
148
161
|
}
|
|
149
162
|
finally {
|
|
150
|
-
logger.info(`STREAM ${path}`, {
|
|
163
|
+
context.logger.info(`STREAM ${path}`, {
|
|
151
164
|
duration_ms: Math.round(new Date().valueOf() - startTime.valueOf() + Number.EPSILON)
|
|
152
165
|
});
|
|
153
166
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReactiveSocketRouter.js","sourceRoot":"","sources":["../../src/router/ReactiveSocketRouter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"ReactiveSocketRouter.js","sourceRoot":"","sources":["../../src/router/ReactiveSocketRouter.ts"],"names":[],"mappings":"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"}
|
package/dist/router/types.d.ts
CHANGED
|
@@ -27,13 +27,20 @@ export type IReactiveStream<I = any, O = any, C = any> = Omit<router.Endpoint<I,
|
|
|
27
27
|
* Decodes raw payload buffer to [I].
|
|
28
28
|
* Falls back to router level decoder if not specified.
|
|
29
29
|
*/
|
|
30
|
-
decoder?: (rawData?:
|
|
30
|
+
decoder?: (rawData?: TypedBuffer) => Promise<I>;
|
|
31
31
|
};
|
|
32
|
+
/**
|
|
33
|
+
* A {@link Buffer} with an associated mimeType inferred from the RSocket `SETUP` frame.
|
|
34
|
+
*/
|
|
35
|
+
export interface TypedBuffer {
|
|
36
|
+
mimeType: string;
|
|
37
|
+
contents: Buffer;
|
|
38
|
+
}
|
|
32
39
|
export type IReactiveStreamInput<I, O, C> = Omit<IReactiveStream<I, O, C>, 'path' | 'type' | 'method'>;
|
|
33
40
|
export type ReactiveEndpoint = IReactiveStream;
|
|
34
41
|
export type CommonParams<C> = {
|
|
35
42
|
endpoints: Array<ReactiveEndpoint>;
|
|
36
|
-
contextProvider: (metaData:
|
|
37
|
-
metaDecoder: (meta:
|
|
38
|
-
payloadDecoder: (rawData?:
|
|
43
|
+
contextProvider: (metaData: TypedBuffer) => Promise<C>;
|
|
44
|
+
metaDecoder: (meta: TypedBuffer) => Promise<RequestMeta>;
|
|
45
|
+
payloadDecoder: (rawData?: TypedBuffer) => Promise<any>;
|
|
39
46
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powersync/service-rsocket-router",
|
|
3
3
|
"repository": "https://github.com/powersync-ja/powersync-service",
|
|
4
|
-
"version": "0.0.0-dev-
|
|
4
|
+
"version": "0.0.0-dev-20250611110033",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"license": "FSL-1.1-Apache-2.0",
|
|
@@ -15,12 +15,11 @@
|
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"rsocket-core": "1.0.0-alpha.3",
|
|
17
17
|
"ts-codec": "^1.3.0",
|
|
18
|
-
"uuid": "^
|
|
18
|
+
"uuid": "^11.1.0",
|
|
19
19
|
"ws": "^8.17.0",
|
|
20
|
-
"@powersync/lib-services-framework": "0.0.0-dev-
|
|
20
|
+
"@powersync/lib-services-framework": "0.0.0-dev-20250611110033"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@types/uuid": "^9.0.4",
|
|
24
23
|
"@types/ws": "~8.2.0",
|
|
25
24
|
"bson": "^6.10.3",
|
|
26
25
|
"rsocket-websocket-client": "1.0.0-alpha.3"
|