diff --git a/package.json b/package.json index c9a7a46b42..da1500ca7e 100644 --- a/package.json +++ b/package.json @@ -221,6 +221,7 @@ "json-stable", "json-text", "json-type", + "json-type-value", "reactive-rpc", "util" ] diff --git a/src/json-type-cli/Cli.ts b/src/json-type-cli/Cli.ts index da8e8d43ac..84c6d92dc5 100644 --- a/src/json-type-cli/Cli.ts +++ b/src/json-type-cli/Cli.ts @@ -7,10 +7,10 @@ import {formatError} from './util'; import {defineBuiltinRoutes} from './methods'; import {defaultParams} from './defaultParams'; import type {CliCodecs} from './CliCodecs'; -import type {Value} from '../reactive-rpc/common/messages/Value'; import type {TypeBuilder} from '../json-type/type/TypeBuilder'; import type {WriteStream, ReadStream} from 'tty'; import type {CliCodec, CliContext, CliParam, CliParamInstance} from './types'; +import type {Value} from '../json-type-value'; export interface CliOptions> { codecs: CliCodecs; diff --git a/src/json-type-cli/util.ts b/src/json-type-cli/util.ts index 6743305dbf..a4c19af85c 100644 --- a/src/json-type-cli/util.ts +++ b/src/json-type-cli/util.ts @@ -1,4 +1,4 @@ -import {Value} from '../reactive-rpc/common/messages/Value'; +import {Value} from '../json-type-value'; import {RpcError} from '../reactive-rpc/common/rpc/caller'; export const formatError = (err: unknown): unknown => { diff --git a/src/json-type-value/AnyValue.ts b/src/json-type-value/AnyValue.ts new file mode 100644 index 0000000000..f30279b432 --- /dev/null +++ b/src/json-type-value/AnyValue.ts @@ -0,0 +1,10 @@ +import {t, AnyType} from '../json-type'; +import {Value} from './Value'; + +const anyType = t.any; + +export class AnyValue extends Value { + constructor(public data: unknown) { + super(anyType, data); + } +} diff --git a/src/json-type-value/ObjectValue.ts b/src/json-type-value/ObjectValue.ts new file mode 100644 index 0000000000..8e8251e0ef --- /dev/null +++ b/src/json-type-value/ObjectValue.ts @@ -0,0 +1,94 @@ +import {Value} from './Value'; +import {toText} from '../json-type/typescript/toText'; +import type {ResolveType} from '../json-type'; +import type * as classes from '../json-type/type'; +import type * as ts from '../json-type/typescript/types'; + +type UnObjectType = T extends classes.ObjectType ? U : never; +type UnObjectFieldTypeVal = T extends classes.ObjectFieldType ? U : never; + +// export type MergeObjectsTypes = +// A extends classes.ObjectType +// ? B extends classes.ObjectType +// ? classes.ObjectType<[...A2, ...B2]> : +// never : +// never; + +// export type MergeObjectValues = +// A extends ObjectValue +// ? B extends ObjectValue +// ? ObjectValue> : +// never : +// never; + +export class ObjectValue> extends Value { + public field>(field: F, data: ResolveType>): ObjectValue, F]>> { + const extendedData = {...this.data, [field.key]: data}; + const type = this.type; + const system = type.system; + if (!system) throw new Error('NO_SYSTEM'); + const extendedType = system.t.Object(...type.fields, field); + return new ObjectValue(extendedType, extendedData) as any; + } + + public prop(key: K, type: V, data: ResolveType) { + const system = type.system; + if (!system) throw new Error('NO_SYSTEM'); + return this.field(system.t.prop(key, type), data); + } + + public merge>(obj: O): ObjectValue, ...UnObjectType]>> { + const extendedData = {...this.data, ...obj.data}; + const type = this.type; + const system = type.system; + if (!system) throw new Error('NO_SYSTEM'); + const extendedType = system.t.Object(...type.fields, ...obj.type.fields); + return new ObjectValue(extendedType, extendedData) as any; + } + + public toTypeScriptAst(): ts.TsTypeLiteral { + const node: ts.TsTypeLiteral = { + node: 'TypeLiteral', + members: [], + }; + const data = this.data as Record; + for (const [name, type] of Object.entries(data)) { + const schema = type.getSchema(); + const property: ts.TsPropertySignature = { + node: 'PropertySignature', + name, + type: type.toTypeScriptAst(), + }; + if (schema.title) property.comment = schema.title; + node.members.push(property); + } + return node; + } + + public toTypeScriptModuleAst(): ts.TsModuleDeclaration { + const node: ts.TsModuleDeclaration = { + node: 'ModuleDeclaration', + name: 'Router', + export: true, + statements: [ + { + node: 'TypeAliasDeclaration', + name: 'Routes', + type: this.toTypeScriptAst(), + export: true, + }, + ], + }; + const system = this.type.system; + if (!system) throw new Error('system is undefined'); + for (const alias of system.aliases.values()) node.statements.push({...alias.toTypeScriptAst(), export: true}); + return node; + } + + /** + * @todo This could go into {@link ObjectType}. + */ + public toTypeScript(): string { + return toText(this.toTypeScriptModuleAst()); + } +} diff --git a/src/json-type-value/Value.ts b/src/json-type-value/Value.ts new file mode 100644 index 0000000000..c563094934 --- /dev/null +++ b/src/json-type-value/Value.ts @@ -0,0 +1,12 @@ +import type {JsonValueCodec} from '../json-pack/codecs/types'; +import type {ResolveType, Type} from '../json-type'; + +export class Value { + constructor(public type: T, public data: ResolveType) {} + + public encode(codec: JsonValueCodec): void { + const data = this.data; + if (data === undefined) return; + this.type.encoder(codec.format)(this.data, codec.encoder); + } +} diff --git a/src/json-type-value/index.ts b/src/json-type-value/index.ts new file mode 100644 index 0000000000..5f01ea0d83 --- /dev/null +++ b/src/json-type-value/index.ts @@ -0,0 +1,4 @@ +export * from './Value'; +export * from './AnyValue'; +export * from './ObjectValue'; +export * from './util'; diff --git a/src/json-type-value/util.ts b/src/json-type-value/util.ts new file mode 100644 index 0000000000..6325e73f95 --- /dev/null +++ b/src/json-type-value/util.ts @@ -0,0 +1,14 @@ +import {Value} from './Value'; +import {AnyValue} from './AnyValue'; +import {ObjectValue} from './ObjectValue'; +import * as classes from '../json-type/type'; + +export const makeValue: { + (type: undefined | classes.Type, data: unknown): AnyValue; + (type: T, data: unknown): ObjectValue; + (type: T, data: unknown): Value; +} = (type: any, data: any): any => { + if (!type) return new AnyValue(data); + if (type instanceof classes.ObjectType) return new ObjectValue(type as classes.ObjectType, data); + return new Value(type as classes.Type, data); +}; diff --git a/src/json-type/codegen/binary/BinaryEncoderCodegenContext.ts b/src/json-type/codegen/binary/BinaryEncoderCodegenContext.ts index 5d8f8b3835..76a159c8b3 100644 --- a/src/json-type/codegen/binary/BinaryEncoderCodegenContext.ts +++ b/src/json-type/codegen/binary/BinaryEncoderCodegenContext.ts @@ -1,7 +1,7 @@ import {Codegen, CodegenStepExecJs} from '../../../util/codegen'; import {WriteBlobStep} from '../WriteBlobStep'; import {concat} from '../../../util/buffers/concat'; -import {Value} from '../../../reactive-rpc/common/messages/Value'; +import {Value} from '../../../json-type-value'; import type {TypeSystem} from '../../system'; import type {Type} from '../../type'; import type {CompiledBinaryEncoder} from '../types'; diff --git a/src/json-type/codegen/capacity/CapacityEstimatorCodegenContext.ts b/src/json-type/codegen/capacity/CapacityEstimatorCodegenContext.ts index 470bbbf6f8..2aa8990074 100644 --- a/src/json-type/codegen/capacity/CapacityEstimatorCodegenContext.ts +++ b/src/json-type/codegen/capacity/CapacityEstimatorCodegenContext.ts @@ -1,6 +1,6 @@ import {Codegen, CodegenStepExecJs} from '../../../util/codegen'; import {maxEncodingCapacity} from '../../../json-size'; -import {Value} from '../../../reactive-rpc/common/messages/Value'; +import {Value} from '../../../json-type-value'; import type {TypeSystem} from '../../system'; import type {Type} from '../../type'; diff --git a/src/json-type/system/TypeRouter.ts b/src/json-type/system/TypeRouter.ts index 40d9688be6..733d3bc826 100644 --- a/src/json-type/system/TypeRouter.ts +++ b/src/json-type/system/TypeRouter.ts @@ -100,7 +100,6 @@ export class TypeRouter { } public toTypeScript(): string { - this.system.exportTypes; return toText(this.toTypeScriptModuleAst()); } } diff --git a/src/json-type/type/types.ts b/src/json-type/type/types.ts index c93485d917..4b8b82ebd3 100644 --- a/src/json-type/type/types.ts +++ b/src/json-type/type/types.ts @@ -1,6 +1,8 @@ import type * as schema from '../schema'; import type * as classes from './classes'; +export type * from './classes'; + export interface BaseType { getSchema(): S; } diff --git a/src/reactive-rpc/common/codec/binary/__tests__/smoke-tests.spec.ts b/src/reactive-rpc/common/codec/binary/__tests__/smoke-tests.spec.ts index 51f6d93e7c..7df5034ad1 100644 --- a/src/reactive-rpc/common/codec/binary/__tests__/smoke-tests.spec.ts +++ b/src/reactive-rpc/common/codec/binary/__tests__/smoke-tests.spec.ts @@ -13,8 +13,8 @@ import { ResponseErrorMessage, ResponseUnsubscribeMessage, } from '../../../messages'; -import {Value} from '../../../messages/Value'; import {messages} from '../../../messages/__tests__/fixtures'; +import {AnyValue} from '../../../../../json-type-value/AnyValue'; const writer = new Writer(8 * Math.round(Math.random() * 100)); const codecs = new Codecs(writer); @@ -31,25 +31,25 @@ for (const jsonCodec of codecList) { describe(jsonCodec.id, () => { test('Notification message', () => { - const value = new Value({foo: 'bar'}, undefined); + const value = new AnyValue({foo: 'bar'}); const message = new NotificationMessage('abc', value); assertMessage(message); }); test('Request Data message', () => { - const value = new Value([1, 2, 3], undefined); + const value = new AnyValue([1, 2, 3]); const message = new RequestDataMessage(9999, 'a', value); assertMessage(message); }); test('Request Complete message', () => { - const value = new Value(true, undefined); + const value = new AnyValue(true); const message = new RequestCompleteMessage(3, 'abc', value); assertMessage(message); }); test('Request Error message', () => { - const value = new Value({message: 'Error!', errno: 123, code: 'ERROR'}, undefined); + const value = new AnyValue({message: 'Error!', errno: 123, code: 'ERROR'}); const message = new RequestErrorMessage(0, 'wtf', value); assertMessage(message); }); @@ -60,19 +60,19 @@ for (const jsonCodec of codecList) { }); test('Response Data message', () => { - const value = new Value([1, 2, 3], undefined); + const value = new AnyValue([1, 2, 3]); const message = new ResponseDataMessage(30000, value); assertMessage(message); }); test('Response Complete message', () => { - const value = new Value(true, undefined); + const value = new AnyValue(true); const message = new ResponseCompleteMessage(3, value); assertMessage(message); }); test('Response Error message', () => { - const value = new Value({message: 'Error!', errno: 123, code: 'ERROR'}, undefined); + const value = new AnyValue({message: 'Error!', errno: 123, code: 'ERROR'}); const message = new ResponseErrorMessage(0, value); assertMessage(message); }); @@ -85,7 +85,7 @@ for (const jsonCodec of codecList) { } describe('batch of messages', () => { - const value = new Value({foo: 'bar'}, undefined); + const value = new AnyValue({foo: 'bar'}); const message1 = new NotificationMessage('abc', value); const message2 = new RequestDataMessage(888, 'a', value); const message3 = new ResponseCompleteMessage(3, value); diff --git a/src/reactive-rpc/common/codec/binary/decode.ts b/src/reactive-rpc/common/codec/binary/decode.ts index 9dab0d77d8..f506b41004 100644 --- a/src/reactive-rpc/common/codec/binary/decode.ts +++ b/src/reactive-rpc/common/codec/binary/decode.ts @@ -11,8 +11,8 @@ import { ResponseErrorMessage, ResponseUnsubscribeMessage, } from '../../messages'; -import {Value} from '../../messages/Value'; import {BinaryMessageType} from './constants'; +import {AnyValue} from '../../../../json-type-value/AnyValue'; import type {Reader} from '../../../../util/buffers/Reader'; export const decode = (reader: Reader): ReactiveRpcMessage => { @@ -24,7 +24,7 @@ export const decode = (reader: Reader): ReactiveRpcMessage => { const x = word >>> 8; const name = reader.ascii(z); const cut = new Uint8ArrayCut(reader.uint8, reader.x, x); - const value = new Value(cut, undefined); + const value = new AnyValue(cut); reader.skip(x); return new NotificationMessage(name, value); } @@ -52,7 +52,7 @@ export const decode = (reader: Reader): ReactiveRpcMessage => { reader.skip(x); } const cut = new Uint8ArrayCut(reader.uint8, cutStart, x); - const value = new Value(cut, undefined); + const value = new AnyValue(cut); switch (type) { case BinaryMessageType.RequestData: return new RequestDataMessage(y, name, value); @@ -85,7 +85,7 @@ export const decode = (reader: Reader): ReactiveRpcMessage => { reader.skip(x); } const cut = new Uint8ArrayCut(reader.uint8, cutStart, x); - const value = new Value(cut, undefined); + const value = new AnyValue(cut); switch (type) { case BinaryMessageType.ResponseData: return new ResponseDataMessage(y, value); diff --git a/src/reactive-rpc/common/codec/compact/CompactRpcMessageCodec.ts b/src/reactive-rpc/common/codec/compact/CompactRpcMessageCodec.ts index 1b86e0461a..096b71de62 100644 --- a/src/reactive-rpc/common/codec/compact/CompactRpcMessageCodec.ts +++ b/src/reactive-rpc/common/codec/compact/CompactRpcMessageCodec.ts @@ -2,10 +2,10 @@ import {RpcMessageFormat} from '../constants'; import {RpcError, RpcErrorCodes} from '../../rpc/caller/error'; import * as msg from '../../messages'; import {CompactMessageType} from './constants'; -import {Value} from '../../messages/Value'; import {CborEncoder} from '../../../../json-pack/cbor/CborEncoder'; import {MsgPackEncoder} from '../../../../json-pack/msgpack'; import {JsonEncoder} from '../../../../json-pack/json/JsonEncoder'; +import {AnyValue} from '../../../../json-type-value/AnyValue'; import type {RpcMessageCodec} from '../types'; import type {JsonValueCodec} from '../../../../json-pack/codecs/types'; import type * as types from './types'; @@ -16,36 +16,36 @@ const fromJson = (arr: unknown | unknown[] | types.CompactMessage): msg.Reactive switch (type) { case CompactMessageType.RequestComplete: { const data = arr[3]; - const value = data === undefined ? data : new Value(data, undefined); + const value = data === undefined ? data : new AnyValue(data); return new msg.RequestCompleteMessage(arr[1], arr[2], value); } case CompactMessageType.RequestData: { const data = arr[3]; - const value = data === undefined ? data : new Value(data, undefined); + const value = data === undefined ? data : new AnyValue(data); return new msg.RequestDataMessage(arr[1], arr[2], value); } case CompactMessageType.RequestError: { - return new msg.RequestErrorMessage(arr[1], arr[2], new Value(arr[3], undefined)); + return new msg.RequestErrorMessage(arr[1], arr[2], new AnyValue(arr[3])); } case CompactMessageType.RequestUnsubscribe: { return new msg.RequestUnsubscribeMessage(arr[1]); } case CompactMessageType.ResponseComplete: { const data = arr[2]; - const value = data === undefined ? data : new Value(data, undefined); + const value = data === undefined ? data : new AnyValue(data); return new msg.ResponseCompleteMessage(arr[1], value); } case CompactMessageType.ResponseData: { - return new msg.ResponseDataMessage(arr[1], new Value(arr[2], undefined)); + return new msg.ResponseDataMessage(arr[1], new AnyValue(arr[2])); } case CompactMessageType.ResponseError: { - return new msg.ResponseErrorMessage(arr[1], new Value(arr[2], undefined)); + return new msg.ResponseErrorMessage(arr[1], new AnyValue(arr[2])); } case CompactMessageType.ResponseUnsubscribe: { return new msg.ResponseUnsubscribeMessage(arr[1]); } case CompactMessageType.Notification: { - return new msg.NotificationMessage(arr[1], new Value(arr[2], undefined)); + return new msg.NotificationMessage(arr[1], new AnyValue(arr[2])); } } throw RpcError.value(RpcError.validation('Unknown message type')); diff --git a/src/reactive-rpc/common/codec/compact/__tests__/smoke-tests.spec.ts b/src/reactive-rpc/common/codec/compact/__tests__/smoke-tests.spec.ts index b4aa178ded..7af4ee4124 100644 --- a/src/reactive-rpc/common/codec/compact/__tests__/smoke-tests.spec.ts +++ b/src/reactive-rpc/common/codec/compact/__tests__/smoke-tests.spec.ts @@ -13,8 +13,8 @@ import { ResponseErrorMessage, ResponseUnsubscribeMessage, } from '../../../messages'; -import {Value} from '../../../messages/Value'; import {RpcError} from '../../../rpc/caller/error'; +import {AnyValue} from '../../../../../json-type-value/AnyValue'; const writer = new Writer(8 * Math.round(Math.random() * 100)); const codecs = new Codecs(writer); @@ -32,25 +32,25 @@ for (const jsonCodec of codecList) { describe(jsonCodec.id, () => { test('Notification message', () => { - const value = new Value({foo: 'bar'}, undefined); + const value = new AnyValue({foo: 'bar'}); const message = new NotificationMessage('abc', value); assertMessage(message); }); test('Request Data message', () => { - const value = new Value([1, 2, 3], undefined); + const value = new AnyValue([1, 2, 3]); const message = new RequestDataMessage(123456, 'a', value); assertMessage(message); }); test('Request Complete message', () => { - const value = new Value(true, undefined); + const value = new AnyValue(true); const message = new RequestCompleteMessage(3, 'abc', value); assertMessage(message); }); test('Request Error message', () => { - const value = new Value({message: 'Error!', errno: 123, code: 'ERROR'}, undefined); + const value = new AnyValue({message: 'Error!', errno: 123, code: 'ERROR'}); const message = new RequestErrorMessage(0, 'wtf', value); assertMessage(message); }); @@ -61,19 +61,19 @@ for (const jsonCodec of codecList) { }); test('Response Data message', () => { - const value = new Value([1, 2, 3], undefined); + const value = new AnyValue([1, 2, 3]); const message = new ResponseDataMessage(123456, value); assertMessage(message); }); test('Response Complete message', () => { - const value = new Value(true, undefined); + const value = new AnyValue(true); const message = new ResponseCompleteMessage(3, value); assertMessage(message); }); test('Response Error message', () => { - const value = new Value({message: 'Error!', errno: 123, code: 'ERROR'}, undefined); + const value = new AnyValue({message: 'Error!', errno: 123, code: 'ERROR'}); const message = new ResponseErrorMessage(0, value); assertMessage(message); }); @@ -96,7 +96,7 @@ for (const jsonCodec of codecList) { } describe('batch of messages', () => { - const value = new Value({foo: 'bar'}, undefined); + const value = new AnyValue({foo: 'bar'}); const message1 = new NotificationMessage('abc', value); const message2 = new RequestDataMessage(123456, 'a', value); const message3 = new ResponseCompleteMessage(3, value); diff --git a/src/reactive-rpc/common/codec/json-rpc-2/JsonRpc2RpcMessageCodec.ts b/src/reactive-rpc/common/codec/json-rpc-2/JsonRpc2RpcMessageCodec.ts index c04c8f5f75..9eb5fc61e7 100644 --- a/src/reactive-rpc/common/codec/json-rpc-2/JsonRpc2RpcMessageCodec.ts +++ b/src/reactive-rpc/common/codec/json-rpc-2/JsonRpc2RpcMessageCodec.ts @@ -1,9 +1,9 @@ import {RpcMessageFormat} from '../constants'; import {RpcError} from '../../rpc/caller/error'; -import {Value} from '../../messages/Value'; import {EncodingFormat} from '../../../../json-pack/constants'; import {TlvBinaryJsonEncoder} from '../../../../json-pack/types'; import {JsonJsonValueCodec} from '../../../../json-pack/codecs/json'; +import {AnyValue} from '../../../../json-type-value/AnyValue'; import * as msg from '../../messages'; import * as schema from './schema'; import type {RpcMessageCodec} from '../types'; @@ -123,13 +123,13 @@ export class JsonRpc2RpcMessageCodec implements RpcMessageCodec { if ((message as any).id === undefined) { const notification = message as schema.JsonRpc2NotificationMessage; const data = notification.params; - const value = new Value(data, undefined); + const value = new AnyValue(data); return new msg.NotificationMessage(notification.method, value); } if (typeof (message as schema.JsonRpc2RequestMessage).method === 'string') { const request = message as schema.JsonRpc2RequestMessage; const data = request.params; - const value = data === undefined ? undefined : new Value(request.params, undefined); + const value = data === undefined ? undefined : new AnyValue(request.params); if (typeof request.id !== 'number') throw RpcError.badRequest(); return new msg.RequestCompleteMessage(request.id, request.method, value); } @@ -137,12 +137,12 @@ export class JsonRpc2RpcMessageCodec implements RpcMessageCodec { const response = message as schema.JsonRpc2ResponseMessage; if (typeof response.id !== 'number') throw RpcError.badRequest(); const data = response.result; - const value = data === undefined ? undefined : new Value(response.result, undefined); + const value = data === undefined ? undefined : new AnyValue(response.result); return new msg.ResponseCompleteMessage(response.id, value); } if ((message as schema.JsonRpc2ErrorMessage).error !== undefined) { const response = message as schema.JsonRpc2ErrorMessage; - const value = new Value(response.error.data, undefined); + const value = new AnyValue(response.error.data); if (typeof response.id !== 'number') throw RpcError.badRequest(); return new msg.ResponseErrorMessage(response.id, value); } diff --git a/src/reactive-rpc/common/messages/Value.ts b/src/reactive-rpc/common/messages/Value.ts deleted file mode 100644 index 6a36d73c88..0000000000 --- a/src/reactive-rpc/common/messages/Value.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type {JsonValueCodec} from '../../../json-pack/codecs/types'; -import type {Type} from '../../../json-type'; - -export class Value { - constructor(public data: V, public type: Type | undefined) {} - - public encode(codec: JsonValueCodec): void { - const value = this.data; - const type = this.type; - if (value === undefined) return; - const encoder = codec.encoder; - if (!type) encoder.writeAny(value); - else type.encoder(codec.format)(value, encoder); - } -} diff --git a/src/reactive-rpc/common/messages/__tests__/fixtures.ts b/src/reactive-rpc/common/messages/__tests__/fixtures.ts index da9f618605..7ba7453b57 100644 --- a/src/reactive-rpc/common/messages/__tests__/fixtures.ts +++ b/src/reactive-rpc/common/messages/__tests__/fixtures.ts @@ -1,7 +1,7 @@ -import {Value} from '../Value'; +import {AnyValue} from '../../../../json-type-value/AnyValue'; import * as msg from '../messages'; -const val = (data: unknown = undefined) => new Value(data, undefined); +const val = (data: unknown = undefined) => new AnyValue(data); const notification1 = new msg.NotificationMessage('a', val('a')); const notification2 = new msg.NotificationMessage('test', val(null)); diff --git a/src/reactive-rpc/common/messages/messages.ts b/src/reactive-rpc/common/messages/messages.ts index b275eee461..45c757fd63 100644 --- a/src/reactive-rpc/common/messages/messages.ts +++ b/src/reactive-rpc/common/messages/messages.ts @@ -4,11 +4,11 @@ import {validateId, validateMethod} from '../rpc/validation'; import {CborEncoder} from '../../../json-pack/cbor/CborEncoder'; import {MsgPackEncoder} from '../../../json-pack/msgpack'; import {JsonEncoder} from '../../../json-pack/json/JsonEncoder'; -import type {Value} from './Value'; import type {JsonValueCodec} from '../../../json-pack/codecs/types'; import type {BinaryJsonEncoder} from '../../../json-pack/types'; import type * as cmsg from '../codec/compact/types'; import type {Message} from './types'; +import {Value} from '../../../json-type-value'; const encodeHeader = ( writer: BinaryJsonEncoder['writer'], diff --git a/src/reactive-rpc/common/rpc/RpcMessageStreamProcessor.ts b/src/reactive-rpc/common/rpc/RpcMessageStreamProcessor.ts index 8371e7b4c1..3b753873f1 100644 --- a/src/reactive-rpc/common/rpc/RpcMessageStreamProcessor.ts +++ b/src/reactive-rpc/common/rpc/RpcMessageStreamProcessor.ts @@ -2,7 +2,7 @@ import * as msg from '../messages'; import {subscribeCompleteObserver} from '../util/subscribeCompleteObserver'; import {TimedQueue} from '../util/TimedQueue'; import {RpcErrorCodes, RpcError} from './caller/error'; -import {Value} from '../messages/Value'; +import type {Value} from '../../../json-type-value'; import type {RpcCaller} from './caller/RpcCaller'; import type {Call, RpcApiMap} from './caller/types'; diff --git a/src/reactive-rpc/common/rpc/__tests__/RpcMessageStreamProcessor-api.spec.ts b/src/reactive-rpc/common/rpc/__tests__/RpcMessageStreamProcessor-api.spec.ts index c4e646dca1..7deaf1b06d 100644 --- a/src/reactive-rpc/common/rpc/__tests__/RpcMessageStreamProcessor-api.spec.ts +++ b/src/reactive-rpc/common/rpc/__tests__/RpcMessageStreamProcessor-api.spec.ts @@ -1,9 +1,9 @@ import {Subject} from 'rxjs'; import {RequestCompleteMessage, ResponseCompleteMessage} from '../../messages'; import {ApiRpcCaller} from '../caller/ApiRpcCaller'; -import {Value} from '../../messages/Value'; import {RpcMessageStreamProcessor, RpcMessageStreamProcessorFromApiOptions} from '../RpcMessageStreamProcessor'; import {sampleApi} from './sample-api'; +import {AnyValue} from '../../../../json-type-value/AnyValue'; const setup = (params: Partial = {}) => { const send = jest.fn(); @@ -27,7 +27,7 @@ test('can create server', async () => { test('can execute static RPC method', async () => { const {server, send} = setup(); expect(send).toHaveBeenCalledTimes(0); - server.onMessage(new RequestCompleteMessage(4, 'ping', new Value({}, undefined)), {}); + server.onMessage(new RequestCompleteMessage(4, 'ping', new AnyValue({})), {}); expect(send).toHaveBeenCalledTimes(0); await new Promise((r) => setTimeout(r, 1)); expect(send).toHaveBeenCalledTimes(1); diff --git a/src/reactive-rpc/common/rpc/__tests__/RpcPersistentClient.spec.ts b/src/reactive-rpc/common/rpc/__tests__/RpcPersistentClient.spec.ts index 80bd1abf1f..f57c9b17c1 100644 --- a/src/reactive-rpc/common/rpc/__tests__/RpcPersistentClient.spec.ts +++ b/src/reactive-rpc/common/rpc/__tests__/RpcPersistentClient.spec.ts @@ -3,11 +3,11 @@ import {RpcPersistentClient} from '../RpcPersistentClient'; import {createWebSocketMock} from '../../channel/mock'; import {RequestCompleteMessage} from '../..'; import {until} from '../../../../__tests__/util'; -import {Value} from '../../messages/Value'; import {RpcCodec} from '../../codec/RpcCodec'; import {Codecs} from '../../../../json-pack/codecs/Codecs'; import {Writer} from '../../../../util/buffers/Writer'; import {RpcMessageCodecs} from '../../codec/RpcMessageCodecs'; +import {AnyValue} from '../../../../json-type-value/AnyValue'; test('on remote method execution, sends message over WebSocket only once', async () => { const onSend = jest.fn(); @@ -39,6 +39,6 @@ test('on remote method execution, sends message over WebSocket only once', async const decoded = codec.decode(message, codec.req); const messageDecoded = decoded[0]; expect(messageDecoded).toBeInstanceOf(RequestCompleteMessage); - expect(messageDecoded).toMatchObject(new RequestCompleteMessage(1, 'foo.bar', new Value({foo: 'bar'}, undefined))); + expect(messageDecoded).toMatchObject(new RequestCompleteMessage(1, 'foo.bar', new AnyValue({foo: 'bar'}))); client.stop(); }); diff --git a/src/reactive-rpc/common/rpc/caller/RpcCaller.ts b/src/reactive-rpc/common/rpc/caller/RpcCaller.ts index 3d825199ce..3fa622f29a 100644 --- a/src/reactive-rpc/common/rpc/caller/RpcCaller.ts +++ b/src/reactive-rpc/common/rpc/caller/RpcCaller.ts @@ -2,8 +2,8 @@ import {firstValueFrom, from, Observable, Subject} from 'rxjs'; import {catchError, finalize, first, map, mergeWith, share, switchMap, take, tap} from 'rxjs/operators'; import {BufferSubject} from '../../../../util/rx/BufferSubject'; import {RpcError, RpcErrorCodes, RpcErrorValue} from './error'; -import {Value} from '../../messages/Value'; import {StaticRpcMethod} from '../methods/StaticRpcMethod'; +import {makeValue, Value} from '../../../../json-type-value'; import type {Call} from './types'; import type {RpcMethod} from '../types'; import type {StreamingRpcMethod} from '../methods/StreamingRpcMethod'; @@ -85,14 +85,14 @@ export class RpcCaller { * @param ctx Server context object. * @returns Response data. */ - public async call(name: string, request: unknown, ctx: Ctx): Promise> { + public async call(name: string, request: unknown, ctx: Ctx): Promise> { const method = this.getMethodStrict(name); this.validate(method, request); try { const preCall = method.onPreCall; if (preCall) await preCall(ctx, request); const data = await method.call(request, ctx); - return new Value(data, method.res); + return makeValue(method.res, data); } catch (error) { throw this.wrapInternalError(error); } @@ -190,7 +190,7 @@ export class RpcCaller { requestBuffered$.flush(); }); return method.call$(requestBuffered$, ctx).pipe( - map((response) => new Value(response, methodResponseType)), + map((response) => makeValue(methodResponseType, response)), finalize(() => { error$.complete(); }), @@ -222,7 +222,7 @@ export class RpcCaller { } } - public call$(name: string, request$: Observable, ctx: Ctx): Observable { + public call$(name: string, request$: Observable, ctx: Ctx): Observable> { const call = this.createCall(name, ctx); request$.subscribe(call.req$); return call.res$; diff --git a/src/reactive-rpc/common/rpc/caller/TypeRouterCaller.ts b/src/reactive-rpc/common/rpc/caller/TypeRouterCaller.ts index 8021c7b025..a4beaa9c51 100644 --- a/src/reactive-rpc/common/rpc/caller/TypeRouterCaller.ts +++ b/src/reactive-rpc/common/rpc/caller/TypeRouterCaller.ts @@ -1,11 +1,11 @@ -import {RpcError, RpcErrorCodes} from './error'; +import {RpcError, RpcErrorType} from './error'; import {RpcCaller, type RpcApiCallerOptions} from './RpcCaller'; import {type AbstractType, FunctionStreamingType, FunctionType} from '../../../../json-type/type/classes'; import {StaticRpcMethod, type StaticRpcMethodOptions} from '../methods/StaticRpcMethod'; import {StreamingRpcMethod, type StreamingRpcMethodOptions} from '../methods/StreamingRpcMethod'; +import {Value} from '../../../../json-type-value'; import type {Schema, SchemaOf, TypeOf, TypeSystem} from '../../../../json-type'; import type {TypeRouter} from '../../../../json-type/system/TypeRouter'; -import type {Value} from '../../messages/Value'; import type {Observable} from 'rxjs'; export interface TypedApiCallerOptions, Ctx = unknown> @@ -80,9 +80,9 @@ export class TypeRouterCaller, Ctx = unknown> ext ): Promise[K]>> { try { const res = await this.call(id as string, request, ctx); - return res.data; + return (res as Value).data; } catch (err) { - const error = err as Value; + const error = err as Value; throw error.data; } } diff --git a/src/reactive-rpc/common/rpc/caller/error/RpcError.ts b/src/reactive-rpc/common/rpc/caller/error/RpcError.ts index 36ef63d139..a6c3510b3f 100644 --- a/src/reactive-rpc/common/rpc/caller/error/RpcError.ts +++ b/src/reactive-rpc/common/rpc/caller/error/RpcError.ts @@ -1,4 +1,4 @@ -import {Value} from '../../../messages/Value'; +import {Value} from '../../../../../json-type-value'; import {IRpcError, RpcErrorType} from './RpcErrorType'; export enum RpcErrorCodes { @@ -31,7 +31,7 @@ export enum RpcErrorCodes { BUFFER_OVERFLOW, } -export type RpcErrorValue = Value; +export type RpcErrorValue = Value; export class RpcError extends Error implements IRpcError { public static from(error: unknown) { @@ -62,7 +62,7 @@ export class RpcError extends Error implements IRpcError { } public static value(error: RpcError): RpcErrorValue { - return new Value(error, RpcErrorType); + return new Value(RpcErrorType, error); } public static valueFrom(error: unknown, def = RpcError.internalErrorValue(error)): RpcErrorValue { diff --git a/src/reactive-rpc/common/rpc/caller/types.ts b/src/reactive-rpc/common/rpc/caller/types.ts index 33714d712a..a3244976bf 100644 --- a/src/reactive-rpc/common/rpc/caller/types.ts +++ b/src/reactive-rpc/common/rpc/caller/types.ts @@ -1,6 +1,6 @@ import type {Observable, Observer} from 'rxjs'; -import type {IStaticRpcMethod, IStreamingRpcMethod, RpcMethod} from '../methods/types'; -import type {Value} from '../../messages/Value'; +import type {IStaticRpcMethod, IStreamingRpcMethod} from '../methods/types'; +import type {Value} from '../../../../json-type-value'; export type RpcApiMap = { [name: string]: IStaticRpcMethod | IStreamingRpcMethod; @@ -12,5 +12,5 @@ export type RpcApiMap = { export interface Call { req$: Observer; reqUnsubscribe$: Observable; - res$: Observable>; + res$: Observable; } diff --git a/src/reactive-rpc/common/rpc/client/StaticRpcClient.ts b/src/reactive-rpc/common/rpc/client/StaticRpcClient.ts index d6398d0964..cea178c531 100644 --- a/src/reactive-rpc/common/rpc/client/StaticRpcClient.ts +++ b/src/reactive-rpc/common/rpc/client/StaticRpcClient.ts @@ -1,8 +1,8 @@ import * as msg from '../../messages'; import {TimedQueue} from '../../util/TimedQueue'; -import {Value} from '../../messages/Value'; import {Defer} from '../../../../util/Defer'; import {Observable, of, switchMap} from 'rxjs'; +import {AnyValue} from '../../../../json-type-value'; import type {RpcClient} from './types'; /** @@ -85,7 +85,7 @@ export class StaticRpcClient implements RpcClient { public async call(method: string, request: unknown): Promise { const id = this.id; this.id = (id + 1) % 0xffff; - const value = new Value(request, undefined); + const value = new AnyValue(request); const message = new msg.RequestCompleteMessage(id, method, value); const future = new Defer(); this.calls.set(id, future); @@ -94,7 +94,7 @@ export class StaticRpcClient implements RpcClient { } public notify(method: string, data: undefined | unknown): void { - const value = new Value(data, undefined); + const value = new AnyValue(data); this.buffer.push(new msg.NotificationMessage(method, value)); } diff --git a/src/reactive-rpc/common/rpc/client/StreamingRpcClient.ts b/src/reactive-rpc/common/rpc/client/StreamingRpcClient.ts index 6894c0408e..993d1536c5 100644 --- a/src/reactive-rpc/common/rpc/client/StreamingRpcClient.ts +++ b/src/reactive-rpc/common/rpc/client/StreamingRpcClient.ts @@ -2,7 +2,7 @@ import {firstValueFrom, isObservable, Observable, Observer, Subject} from 'rxjs' import * as msg from '../../messages'; import {subscribeCompleteObserver} from '../../util/subscribeCompleteObserver'; import {TimedQueue} from '../../util/TimedQueue'; -import {Value} from '../../messages/Value'; +import {AnyValue} from '../../../../json-type-value'; import type {RpcClient} from './types'; /** @@ -188,25 +188,25 @@ export class StreamingRpcClient implements RpcClient { next: (value) => { const messageMethod = firstMessageSent ? '' : method; firstMessageSent = true; - const message = new msg.RequestDataMessage(id, messageMethod, new Value(value, undefined)); + const message = new msg.RequestDataMessage(id, messageMethod, new AnyValue(value)); this.buffer.push(message); }, error: (error) => { cleanup(); const messageMethod = firstMessageSent ? '' : method; - const message = new msg.RequestErrorMessage(id, messageMethod, new Value(error, undefined)); + const message = new msg.RequestErrorMessage(id, messageMethod, new AnyValue(error)); this.buffer.push(message); }, complete: (value) => { cleanup(); const messageMethod = firstMessageSent ? '' : method; - const message = new msg.RequestCompleteMessage(id, messageMethod, new Value(value, undefined)); + const message = new msg.RequestCompleteMessage(id, messageMethod, new AnyValue(value)); this.buffer.push(message); }, }); data.subscribe(req$); } else { - this.buffer.push(new msg.RequestCompleteMessage(id, method, new Value(data, undefined))); + this.buffer.push(new msg.RequestCompleteMessage(id, method, new AnyValue(data))); req$.complete(); cleanup(); } @@ -230,7 +230,7 @@ export class StreamingRpcClient implements RpcClient { * @param data Static payload data. */ public notify(method: string, data: undefined | unknown): void { - const value = new Value(data, undefined); + const value = new AnyValue(data); this.buffer.push(new msg.NotificationMessage(method, value)); } diff --git a/src/reactive-rpc/common/rpc/client/__tests__/StreamingRpcClient.spec.ts b/src/reactive-rpc/common/rpc/client/__tests__/StreamingRpcClient.spec.ts index bf4d439b84..498e079949 100644 --- a/src/reactive-rpc/common/rpc/client/__tests__/StreamingRpcClient.spec.ts +++ b/src/reactive-rpc/common/rpc/client/__tests__/StreamingRpcClient.spec.ts @@ -11,7 +11,7 @@ import { } from '../../../messages'; import {firstValueFrom, Subject} from 'rxjs'; import {until} from '../../../../../__tests__/util'; -import {Value} from '../../../messages/Value'; +import {AnyValue} from '../../../../../json-type-value'; test('can create client', async () => { const send = jest.fn(); @@ -31,7 +31,7 @@ test('sends notification message on .notify() call', async () => { client.notify('foo', Buffer.from('bar')); await new Promise((r) => setTimeout(r, 2)); expect(send).toHaveBeenCalledTimes(1); - const value = new Value(Buffer.from('bar'), undefined); + const value = new AnyValue(Buffer.from('bar')); expect(send).toHaveBeenCalledWith([new NotificationMessage('foo', value)]); }); @@ -41,7 +41,7 @@ test('sends notification with no payload', async () => { client.notify('foo', undefined); await new Promise((r) => setTimeout(r, 2)); expect(send).toHaveBeenCalledTimes(1); - const value = new Value(undefined, undefined); + const value = new AnyValue(undefined); expect(send).toHaveBeenCalledWith([new NotificationMessage('foo', value)]); }); @@ -70,7 +70,7 @@ test('sends Request Complete Message to the server', async () => { const result = client.call$('test', Buffer.from("{foo: 'bar'}")); await new Promise((r) => setTimeout(r, 2)); expect(send).toHaveBeenCalledTimes(1); - const value = new Value(Buffer.from("{foo: 'bar'}"), undefined); + const value = new AnyValue(Buffer.from("{foo: 'bar'}")); expect(send).toHaveBeenCalledWith([new RequestCompleteMessage(1, 'test', value)]); }); @@ -113,7 +113,7 @@ test('server can immediately complete the subscription with payload', async () = const complete = jest.fn(); result.subscribe({next, error, complete}); await new Promise((r) => setTimeout(r, 20)); - const value = new Value(Buffer.from("{x: 'y'}"), undefined); + const value = new AnyValue(Buffer.from("{x: 'y'}")); const completeMsg = new ResponseCompleteMessage(1, value); client.onMessages([completeMsg]); expect(next).toHaveBeenCalledTimes(1); @@ -131,13 +131,13 @@ test('server can send multiple values before completing', async () => { const complete = jest.fn(); result.subscribe({next, error, complete}); await new Promise((r) => setTimeout(r, 20)); - const value1 = new Value(Buffer.from("{x: 'y'}"), undefined); + const value1 = new AnyValue(Buffer.from("{x: 'y'}")); client.onMessages([new ResponseDataMessage(1, value1)]); await new Promise((r) => setTimeout(r, 20)); - const value2 = new Value(Buffer.from("{z: 'a'}"), undefined); + const value2 = new AnyValue(Buffer.from("{z: 'a'}")); client.onMessages([new ResponseDataMessage(1, value2)]); await new Promise((r) => setTimeout(r, 20)); - const value3 = new Value(Buffer.from("{b: 'c'}"), undefined); + const value3 = new AnyValue(Buffer.from("{b: 'c'}")); client.onMessages([new ResponseCompleteMessage(1, value3)]); await new Promise((r) => setTimeout(r, 20)); expect(next).toHaveBeenCalledTimes(3); @@ -157,12 +157,12 @@ test('values are not emitted after observable is unsubscribed', async () => { const complete = jest.fn(); const subscription = result.subscribe({next, error, complete}); await new Promise((r) => setTimeout(r, 20)); - client.onMessages([new ResponseDataMessage(1, new Value(Buffer.from([1]), undefined))]); + client.onMessages([new ResponseDataMessage(1, new AnyValue(Buffer.from([1])))]); await new Promise((r) => setTimeout(r, 20)); - client.onMessages([new ResponseDataMessage(1, new Value(Buffer.from([2]), undefined))]); + client.onMessages([new ResponseDataMessage(1, new AnyValue(Buffer.from([2])))]); await new Promise((r) => setTimeout(r, 20)); subscription.unsubscribe(); - client.onMessages([new ResponseCompleteMessage(1, new Value(Buffer.from([3]), undefined))]); + client.onMessages([new ResponseCompleteMessage(1, new AnyValue(Buffer.from([3])))]); await new Promise((r) => setTimeout(r, 20)); expect(next).toHaveBeenCalledTimes(2); expect(error).toHaveBeenCalledTimes(0); @@ -192,23 +192,23 @@ test('can subscribe to multiple methods', async () => { await new Promise((r) => setTimeout(r, 2)); expect(send).toHaveBeenCalledTimes(2); - expect(send).toHaveBeenCalledWith([new RequestCompleteMessage(1, 'foo', new Value(Buffer.from([1]), undefined))]); - expect(send).toHaveBeenCalledWith([new RequestCompleteMessage(2, 'bar', new Value(Buffer.from([2]), undefined))]); + expect(send).toHaveBeenCalledWith([new RequestCompleteMessage(1, 'foo', new AnyValue(Buffer.from([1])))]); + expect(send).toHaveBeenCalledWith([new RequestCompleteMessage(2, 'bar', new AnyValue(Buffer.from([2])))]); - client.onMessages([new ResponseDataMessage(2, new Value(Buffer.from('gg'), undefined))]); + client.onMessages([new ResponseDataMessage(2, new AnyValue(Buffer.from('gg')))]); await new Promise((r) => setTimeout(r, 20)); expect(next1).toHaveBeenCalledTimes(0); expect(next2).toHaveBeenCalledWith(Buffer.from('gg')); - client.onMessages([new ResponseDataMessage(1, new Value(Buffer.from('lala'), undefined))]); + client.onMessages([new ResponseDataMessage(1, new AnyValue(Buffer.from('lala')))]); await new Promise((r) => setTimeout(r, 20)); expect(next1).toHaveBeenCalledWith(Buffer.from('lala')); expect(next1).toHaveBeenCalledTimes(1); expect(next2).toHaveBeenCalledTimes(1); - client.onMessages([new ResponseCompleteMessage(1, new Value(Buffer.from('1'), undefined))]); + client.onMessages([new ResponseCompleteMessage(1, new AnyValue(Buffer.from('1')))]); client.onMessages([new ResponseCompleteMessage(2, undefined)]); expect(next1).toHaveBeenCalledWith(Buffer.from('1')); @@ -230,7 +230,7 @@ test('can respond with error', async () => { const complete = jest.fn(); const subscription = result.subscribe({next, error, complete}); await new Promise((r) => setTimeout(r, 20)); - client.onMessages([new ResponseErrorMessage(1, new Value(Buffer.from([1]), undefined))]); + client.onMessages([new ResponseErrorMessage(1, new AnyValue(Buffer.from([1])))]); await new Promise((r) => setTimeout(r, 20)); expect(next).toHaveBeenCalledTimes(0); expect(error).toHaveBeenCalledTimes(1); @@ -265,7 +265,7 @@ test('does not send unsubscribe when complete has been received', async () => { await new Promise((r) => setTimeout(r, 20)); expect(send).toHaveBeenCalledTimes(1); expect(next).toHaveBeenCalledTimes(0); - client.onMessages([new ResponseCompleteMessage(1, new Value(Buffer.from([1]), undefined))]); + client.onMessages([new ResponseCompleteMessage(1, new AnyValue(Buffer.from([1])))]); await new Promise((r) => setTimeout(r, 20)); expect(next).toHaveBeenCalledTimes(1); expect(send).toHaveBeenCalledTimes(1); @@ -282,7 +282,7 @@ test('does not send unsubscribe when complete has been received - 2', async () = const promise = firstValueFrom(observable); await new Promise((r) => setTimeout(r, 2)); expect(send).toHaveBeenCalledTimes(1); - const value = new Value(Buffer.from([25]), undefined); + const value = new AnyValue(Buffer.from([25])); client.onMessages([new ResponseCompleteMessage(1, value)]); await new Promise((r) => setTimeout(r, 2)); expect(send).toHaveBeenCalledTimes(1); @@ -303,7 +303,7 @@ test('does not send unsubscribe when error has been received', async () => { const promise = firstValueFrom(observable); await new Promise((r) => setTimeout(r, 2)); expect(send).toHaveBeenCalledTimes(1); - const value = new Value(Buffer.from([25]), undefined); + const value = new AnyValue(Buffer.from([25])); client.onMessages([new ResponseErrorMessage(1, value)]); expect(send).toHaveBeenCalledTimes(1); let error; @@ -328,12 +328,12 @@ test('after .stop() completes subscriptions', async () => { await new Promise((r) => setTimeout(r, 2)); expect(send).toHaveBeenCalledTimes(1); expect(data).toHaveBeenCalledTimes(0); - client.onMessages([new ResponseDataMessage(1, new Value(Buffer.from([1]), undefined))]); + client.onMessages([new ResponseDataMessage(1, new AnyValue(Buffer.from([1])))]); expect(data).toHaveBeenCalledTimes(1); - client.onMessages([new ResponseDataMessage(1, new Value(Buffer.from([2]), undefined))]); + client.onMessages([new ResponseDataMessage(1, new AnyValue(Buffer.from([2])))]); expect(data).toHaveBeenCalledTimes(2); client.stop(); - client.onMessages([new ResponseDataMessage(1, new Value(Buffer.from([3]), undefined))]); + client.onMessages([new ResponseDataMessage(1, new AnyValue(Buffer.from([3])))]); expect(data).toHaveBeenCalledTimes(2); }); @@ -378,8 +378,8 @@ test('can receive and process a batch from server', async () => { expect(send).toHaveBeenCalledTimes(1); expect(data1).toHaveBeenCalledTimes(0); expect(data2).toHaveBeenCalledTimes(0); - const value1 = new Value(Buffer.from("{foo: 'bar'}"), undefined); - const value2 = new Value(Buffer.from("{foo: 'baz'}"), undefined); + const value1 = new AnyValue(Buffer.from("{foo: 'bar'}")); + const value2 = new AnyValue(Buffer.from("{foo: 'baz'}")); client.onMessages([new ResponseCompleteMessage(1, value1), new ResponseCompleteMessage(2, value2)]); await new Promise((r) => setTimeout(r, 2)); expect(data1).toHaveBeenCalledTimes(1); @@ -415,7 +415,7 @@ describe('streaming request', () => { client.call$('a.b', data$).subscribe({next, error, complete}); await new Promise((r) => setTimeout(r, 1)); expect(send).toHaveBeenCalledTimes(0); - const value1 = new Value('1', undefined); + const value1 = new AnyValue('1'); data$.next('1'); await until(() => send.mock.calls.length === 1); expect(send).toHaveBeenCalledTimes(1); @@ -423,12 +423,12 @@ describe('streaming request', () => { data$.next('1.1'); await until(() => send.mock.calls.length === 2); expect(send).toHaveBeenCalledTimes(2); - expect(send).toHaveBeenCalledWith([new RequestDataMessage(1, '', new Value('1.1', undefined))]); + expect(send).toHaveBeenCalledWith([new RequestDataMessage(1, '', new AnyValue('1.1'))]); data$.next('1.1.1'); data$.complete(); await until(() => send.mock.calls.length === 3); expect(send).toHaveBeenCalledTimes(3); - expect(send).toHaveBeenCalledWith([new RequestDataMessage(1, '', new Value('1.1.1', undefined))]); + expect(send).toHaveBeenCalledWith([new RequestDataMessage(1, '', new AnyValue('1.1.1'))]); }); test('request payload error is sent to server', async () => { @@ -447,12 +447,12 @@ describe('streaming request', () => { await until(() => send.mock.calls.length === 1); expect(send).toHaveBeenCalledTimes(1); expect(send.mock.calls[0][0][0]).toBeInstanceOf(RequestDataMessage); - expect(send).toHaveBeenCalledWith([new RequestDataMessage(1, 'a.b', new Value('1', undefined))]); + expect(send).toHaveBeenCalledWith([new RequestDataMessage(1, 'a.b', new AnyValue('1'))]); data$.error('1.1'); await until(() => send.mock.calls.length === 2); expect(send).toHaveBeenCalledTimes(2); expect(send.mock.calls[1][0][0]).toBeInstanceOf(RequestErrorMessage); - expect(send).toHaveBeenCalledWith([new RequestErrorMessage(1, '', new Value('1.1', undefined))]); + expect(send).toHaveBeenCalledWith([new RequestErrorMessage(1, '', new AnyValue('1.1'))]); data$.next('1.1.1'); expect(send).toHaveBeenCalledTimes(2); }); @@ -473,12 +473,12 @@ describe('streaming request', () => { await until(() => send.mock.calls.length === 1); expect(send).toHaveBeenCalledTimes(1); expect(send.mock.calls[0][0][0]).toBeInstanceOf(RequestDataMessage); - expect(send).toHaveBeenCalledWith([new RequestDataMessage(1, 'a.b', new Value('1', undefined))]); + expect(send).toHaveBeenCalledWith([new RequestDataMessage(1, 'a.b', new AnyValue('1'))]); data$.complete(); await until(() => send.mock.calls.length === 2); expect(send).toHaveBeenCalledTimes(2); expect(send.mock.calls[1][0][0]).toBeInstanceOf(RequestCompleteMessage); - expect(send).toHaveBeenCalledWith([new RequestErrorMessage(1, '', new Value(undefined, undefined))]); + expect(send).toHaveBeenCalledWith([new RequestErrorMessage(1, '', new AnyValue(undefined))]); data$.next('1.1.1'); expect(send).toHaveBeenCalledTimes(2); }); @@ -499,7 +499,7 @@ describe('streaming request', () => { await until(() => send.mock.calls.length === 1); expect(send).toHaveBeenCalledTimes(1); expect(send.mock.calls[0][0][0]).toBeInstanceOf(RequestErrorMessage); - expect(send).toHaveBeenCalledWith([new RequestErrorMessage(1, 'a.b', new Value({foo: 'bar'}, undefined))]); + expect(send).toHaveBeenCalledWith([new RequestErrorMessage(1, 'a.b', new AnyValue({foo: 'bar'}))]); data$.complete(); data$.next('1.1.1'); await new Promise((r) => setTimeout(r, 4)); @@ -522,7 +522,7 @@ describe('streaming request', () => { await new Promise((r) => setTimeout(r, 4)); expect(send).toHaveBeenCalledTimes(1); expect(send.mock.calls[0][0][0]).toBeInstanceOf(RequestCompleteMessage); - expect(send).toHaveBeenCalledWith([new RequestCompleteMessage(1, 'a.b', new Value(undefined, undefined))]); + expect(send).toHaveBeenCalledWith([new RequestCompleteMessage(1, 'a.b', new AnyValue(undefined))]); data$.complete(); data$.error(123); data$.next('1.1.1'); @@ -548,7 +548,7 @@ describe('memory leaks', () => { expect(next).toHaveBeenCalledTimes(0); expect(complete).toHaveBeenCalledTimes(0); expect(client.getInflightCallCount()).toBe(1); - client.onMessages([new ResponseCompleteMessage(1, new Value('gaga', undefined))]); + client.onMessages([new ResponseCompleteMessage(1, new AnyValue('gaga'))]); await new Promise((r) => setTimeout(r, 4)); expect(next).toHaveBeenCalledTimes(1); expect(complete).toHaveBeenCalledTimes(1); diff --git a/src/reactive-rpc/server/uws/RpcApp.ts b/src/reactive-rpc/server/uws/RpcApp.ts index de1dd40e3d..9bb3dee82c 100644 --- a/src/reactive-rpc/server/uws/RpcApp.ts +++ b/src/reactive-rpc/server/uws/RpcApp.ts @@ -4,11 +4,11 @@ import {IncomingBatchMessage, RpcMessageBatchProcessor} from '../../common/rpc/R import {RpcError, RpcErrorCodes, RpcErrorType} from '../../common/rpc/caller/error'; import {ConnectionContext} from '../context'; import {RpcMessageCodecs} from '../../common/codec/RpcMessageCodecs'; -import {Value} from '../../common/messages/Value'; import {RpcCodecs} from '../../common/codec/RpcCodecs'; import {Codecs} from '../../../json-pack/codecs/Codecs'; import {Writer} from '../../../util/buffers/Writer'; import {copy} from '../../../util/buffers/copy'; +import {Value} from '../../../json-type-value'; import {type ReactiveRpcMessage, RpcMessageStreamProcessor, ReactiveRpcClientMessage} from '../../common'; import type * as types from './types'; import type {RouteHandler} from './types'; diff --git a/src/server/routes/index.ts b/src/server/routes/index.ts index ed967ebd72..f7d61f1f3f 100644 --- a/src/server/routes/index.ts +++ b/src/server/routes/index.ts @@ -3,7 +3,7 @@ import {system} from './system'; import {TypeRouter} from '../../json-type/system/TypeRouter'; import {TypeRouterCaller} from '../../reactive-rpc/common/rpc/caller/TypeRouterCaller'; import {RpcError} from '../../reactive-rpc/common/rpc/caller'; -import {Value} from '../../reactive-rpc/common/messages/Value'; +import {Value} from '../../json-type-value'; import type {Services} from '../services/Services'; import type {RouteDeps} from './types';