Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@push-rpc/next

Package Overview
Dependencies
Maintainers
1
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@push-rpc/next - npm Package Compare versions

Comparing version 2.0.10 to 2.0.11

4

dist/client/HttpClient.d.ts

@@ -1,2 +0,1 @@

import { ClientCookies } from "../utils/cookies.js";
export declare class HttpClient {

@@ -6,4 +5,3 @@ private url;

private getHeaders;
private cookies;
constructor(url: string, clientId: string, getHeaders: () => Promise<Record<string, string>>, cookies: ClientCookies);
constructor(url: string, clientId: string, getHeaders: () => Promise<Record<string, string>>);
call(itemName: string, params: unknown[], callTimeout: number): Promise<unknown>;

@@ -10,0 +8,0 @@ subscribe(itemName: string, params: unknown[], callTimeout: number): Promise<unknown>;

@@ -6,9 +6,7 @@ "use strict";

const json_js_1 = require("../utils/json.js");
const env_js_1 = require("../utils/env.js");
class HttpClient {
constructor(url, clientId, getHeaders, cookies) {
constructor(url, clientId, getHeaders) {
this.url = url;
this.clientId = clientId;
this.getHeaders = getHeaders;
this.cookies = cookies;
}

@@ -31,8 +29,2 @@ async call(itemName, params, callTimeout) {

const { signal, finished } = timeoutSignal(callTimeout);
if (env_js_1.environment != env_js_1.Environment.Browser) {
const cookie = this.cookies.getCookieString();
if (cookie) {
headers["Cookie"] = cookie;
}
}
const response = await fetch(itemUrl, {

@@ -49,8 +41,2 @@ method,

finished();
if (env_js_1.environment != env_js_1.Environment.Browser) {
const cookie = response.headers.get("set-cookie");
if (cookie) {
this.cookies.updateCookies(cookie.split(","));
}
}
if (response.status == 204) {

@@ -57,0 +43,0 @@ return;

@@ -19,2 +19,3 @@ import { RpcContext, Services } from "../rpc.js";

middleware: Middleware<RpcContext>[];
updatesMiddleware: Middleware<RpcContext>[];
connectOnCreate: boolean;

@@ -21,0 +22,0 @@ onConnected: () => void;

@@ -30,2 +30,3 @@ "use strict";

middleware: [],
updatesMiddleware: [],
connectOnCreate: false,

@@ -32,0 +33,0 @@ onConnected: () => { },

@@ -11,3 +11,2 @@ import { Services } from "../rpc.js";

private readonly connection;
private readonly cookies;
isConnected(): boolean;

@@ -14,0 +13,0 @@ close(): Promise<void>;

@@ -11,3 +11,2 @@ "use strict";

const middleware_js_1 = require("../utils/middleware.js");
const cookies_js_1 = require("../utils/cookies.js");
class RpcClientImpl {

@@ -17,3 +16,2 @@ constructor(url, options) {

this.clientId = (0, nanoid_1.nanoid)();
this.cookies = new cookies_js_1.ClientCookies();
this.call = (itemName, parameters, callOptions) => {

@@ -65,5 +63,5 @@ return this.invoke(itemName, rpc_js_1.InvocationType.Call, (...parameters) => this.httpClient.call(itemName, parameters, callOptions?.timeout ?? this.options.callTimeout), parameters);

};
this.httpClient = new HttpClient_js_1.HttpClient(url, this.clientId, options.getHeaders, this.cookies);
this.httpClient = new HttpClient_js_1.HttpClient(url, this.clientId, options.getHeaders);
this.remoteSubscriptions = new RemoteSubscriptions_js_1.RemoteSubscriptions();
this.connection = new WebSocketConnection_js_1.WebSocketConnection(options.getSubscriptionsUrl(url), this.clientId, this.cookies, {
this.connection = new WebSocketConnection_js_1.WebSocketConnection(options.getSubscriptionsUrl(url), this.clientId, {
subscriptions: options.subscriptions,

@@ -74,3 +72,9 @@ errorDelayMaxDuration: options.errorDelayMaxDuration,

}, (itemName, parameters, data) => {
this.remoteSubscriptions.consume(itemName, parameters, data);
const ctx = {
clientId: this.clientId,
itemName,
invocationType: rpc_js_1.InvocationType.Update,
};
const next = async (p = data) => this.remoteSubscriptions.consume(itemName, parameters, p);
return (0, middleware_js_1.withMiddlewares)(ctx, this.options.updatesMiddleware, next, data);
}, () => {

@@ -77,0 +81,0 @@ this.resubscribe();

@@ -1,6 +0,4 @@

import { ClientCookies } from "../utils/cookies.js";
export declare class WebSocketConnection {
private readonly url;
private readonly clientId;
private readonly cookies;
private readonly options;

@@ -10,3 +8,3 @@ private readonly consume;

private readonly onDisconnected;
constructor(url: string, clientId: string, cookies: ClientCookies, options: {
constructor(url: string, clientId: string, options: {
subscriptions: boolean;

@@ -13,0 +11,0 @@ reconnectDelay: number;

@@ -7,8 +7,6 @@ "use strict";

const promises_js_1 = require("../utils/promises.js");
const env_js_1 = require("../utils/env.js");
class WebSocketConnection {
constructor(url, clientId, cookies, options, consume, onConnected, onDisconnected) {
constructor(url, clientId, options, consume, onConnected, onDisconnected) {
this.url = url;
this.clientId = clientId;
this.cookies = cookies;
this.options = options;

@@ -95,20 +93,3 @@ this.consume = consume;

try {
let socket;
if ([env_js_1.Environment.ReactNative, env_js_1.Environment.Node].includes(env_js_1.environment)) {
// use RN WS or node-ws headers extensions to set cookie
let options = undefined;
const cookie = this.cookies.getCookieString();
if (cookie) {
options = {
headers: {
Cookie: cookie,
},
};
}
socket = new WebSocket(this.url, this.clientId, options);
}
else {
// rely on browser cookie handling
socket = new WebSocket(this.url, this.clientId);
}
const socket = new WebSocket(this.url, this.clientId);
let connected = false;

@@ -115,0 +96,0 @@ socket.addEventListener("open", () => {

@@ -6,2 +6,3 @@ export type { RemoteFunction, Services, Consumer, RpcContext, RpcConnectionContext } from "./rpc.js";

export type { RpcServer, PublishServicesOptions } from "./server/index.js";
export type { HttpServerHooks } from "./server/http.js";
export { publishServices } from "./server/index.js";

@@ -8,0 +9,0 @@ export type { ServicesWithTriggers } from "./server/local.js";

@@ -35,3 +35,4 @@ import { ExtractPromiseResult } from "./utils/types.js";

Unsubscribe = "Unsubscribe",// client only
Update = "Update",// client only
Trigger = "Trigger"
}

@@ -30,4 +30,5 @@ "use strict";

InvocationType["Unsubscribe"] = "Unsubscribe";
InvocationType["Update"] = "Update";
InvocationType["Trigger"] = "Trigger";
})(InvocationType || (exports.InvocationType = InvocationType = {}));
//# sourceMappingURL=rpc.js.map

@@ -6,2 +6,3 @@ /// <reference types="node" />

import http, { IncomingMessage } from "http";
import { HttpServerHooks } from "./http";
export declare function publishServices<S extends Services<S>, C extends RpcContext>(services: S, overrideOptions: Partial<PublishServicesOptions<C>> & ({

@@ -27,2 +28,3 @@ port: number;

createConnectionContext(req: IncomingMessage): Promise<RpcConnectionContext>;
createServerHooks?(hooks: HttpServerHooks, req: IncomingMessage): HttpServerHooks;
} & ({

@@ -29,0 +31,0 @@ server: http.Server;

@@ -115,7 +115,12 @@ "use strict";

}
this.httpServer.addListener("request", (req, res) => (0, http_js_1.serveHttpRequest)(req, res, options.path, {
call: this.call,
subscribe: this.subscribe,
unsubscribe: this.unsubscribe,
}, options.createConnectionContext));
this.httpServer.addListener("request", (req, res) => {
const hooks = {
call: this.call,
subscribe: this.subscribe,
unsubscribe: this.unsubscribe,
};
(0, http_js_1.serveHttpRequest)(req, res, options.path, options.createServerHooks ? options.createServerHooks(hooks, req) : hooks, options.createConnectionContext).catch((e) => {
logger_js_1.log.warn("Unhandled error serving HTTP request", e);
});
});
}

@@ -122,0 +127,0 @@ async createConnectionsServer() {

{
"name": "@push-rpc/next",
"version": "2.0.10",
"version": "2.0.11",
"main": "dist/index.js",

@@ -5,0 +5,0 @@ "types": "dist/index.d.ts",

@@ -23,3 +23,3 @@ Client/server framework

**Middlewares**. Middlewares are used to intercept client and server requests. Both calls and subscriptions can be
intercepted?. Middlewares can be attached on both client and server side. Middlewares receive context as the last
intercepted. Middlewares can be attached on both client and server side. Middlewares receive context as the last
arguments in the invocation. Middleware can modify context.

@@ -46,5 +46,5 @@

document). Bun/Deno should also work, but not officially supported.
- Limited cookie support. Due to limited support in React Native, Cookies can be set and read during HTTP requests and
set during WS connection establishment. So if you need to share cookies between HTTP and WS, you need to make call (
HTTP POST) right after creating client, and establish WS connection (ie make subscribe, HTTP PUT) only after that.
Cookies cannot be shared when `connectOnCreate` client option is true.
# Limitations
- Cookies are not been sent during HTTP & WS requests.
import {CLIENT_ID_HEADER, RpcErrors} from "../rpc.js"
import {safeParseJson, safeStringify} from "../utils/json.js"
import {ClientCookies} from "../utils/cookies.js"
import {environment, Environment} from "../utils/env.js"

@@ -10,4 +8,3 @@ export class HttpClient {

private clientId: string,
private getHeaders: () => Promise<Record<string, string>>,
private cookies: ClientCookies
private getHeaders: () => Promise<Record<string, string>>
) {}

@@ -43,10 +40,2 @@

if (environment != Environment.Browser) {
const cookie = this.cookies.getCookieString()
if (cookie) {
headers["Cookie"] = cookie
}
}
const response = await fetch(itemUrl, {

@@ -65,10 +54,2 @@ method,

if (environment != Environment.Browser) {
const cookie = response.headers.get("set-cookie")
if (cookie) {
this.cookies.updateCookies(cookie.split(","))
}
}
if (response.status == 204) {

@@ -75,0 +56,0 @@ return

@@ -25,2 +25,3 @@ import {RpcContext, Services} from "../rpc.js"

middleware: Middleware<RpcContext>[]
updatesMiddleware: Middleware<RpcContext>[]
connectOnCreate: boolean

@@ -68,2 +69,3 @@ onConnected: () => void

middleware: [],
updatesMiddleware: [],
connectOnCreate: false,

@@ -70,0 +72,0 @@ onConnected: () => {},

@@ -9,3 +9,2 @@ import {CallOptions, InvocationType, RpcContext, Services} from "../rpc.js"

import {withMiddlewares} from "../utils/middleware.js"
import {ClientCookies} from "../utils/cookies.js"

@@ -17,3 +16,3 @@ export class RpcClientImpl<S extends Services<S>> implements RpcClient {

) {
this.httpClient = new HttpClient(url, this.clientId, options.getHeaders, this.cookies)
this.httpClient = new HttpClient(url, this.clientId, options.getHeaders)
this.remoteSubscriptions = new RemoteSubscriptions()

@@ -24,3 +23,2 @@

this.clientId,
this.cookies,
{

@@ -33,3 +31,10 @@ subscriptions: options.subscriptions,

(itemName, parameters, data) => {
this.remoteSubscriptions.consume(itemName, parameters, data)
const ctx: RpcContext = {
clientId: this.clientId,
itemName,
invocationType: InvocationType.Update,
}
const next = async (p = data) => this.remoteSubscriptions.consume(itemName, parameters, p)
return withMiddlewares(ctx, this.options.updatesMiddleware, next, data)
},

@@ -50,3 +55,2 @@ () => {

private readonly connection: WebSocketConnection
private readonly cookies: ClientCookies = new ClientCookies()

@@ -53,0 +57,0 @@ isConnected() {

import {log} from "../logger.js"
import {safeParseJson} from "../utils/json.js"
import {adelay} from "../utils/promises.js"
import {environment, Environment} from "../utils/env.js"
import {ClientCookies} from "../utils/cookies.js"
import type {IncomingMessage} from "http"

@@ -12,3 +9,2 @@ export class WebSocketConnection {

private readonly clientId: string,
private readonly cookies: ClientCookies,
private readonly options: {

@@ -126,23 +122,4 @@ subscriptions: boolean

try {
let socket: WebSocket
const socket = new WebSocket(this.url, this.clientId)
if ([Environment.ReactNative, Environment.Node].includes(environment)) {
// use RN WS or node-ws headers extensions to set cookie
let options = undefined
const cookie = this.cookies.getCookieString()
if (cookie) {
options = {
headers: {
Cookie: cookie,
},
}
}
socket = new (WebSocket as any)(this.url, this.clientId, options)
} else {
// rely on browser cookie handling
socket = new WebSocket(this.url, this.clientId)
}
let connected = false

@@ -149,0 +126,0 @@

@@ -8,2 +8,3 @@ export type {RemoteFunction, Services, Consumer, RpcContext, RpcConnectionContext} from "./rpc.js"

export type {RpcServer, PublishServicesOptions} from "./server/index.js"
export type {HttpServerHooks} from "./server/http.js"
export {publishServices} from "./server/index.js"

@@ -10,0 +11,0 @@

@@ -50,3 +50,4 @@ import {ExtractPromiseResult} from "./utils/types.js"

Unsubscribe = "Unsubscribe", // client only
Update = "Update", // client only
Trigger = "Trigger", // server only
}

@@ -6,2 +6,3 @@ import {CLIENT_ID_HEADER, RpcConnectionContext, RpcContext, Services} from "../rpc.js"

import http, {IncomingMessage} from "http"
import {HttpServerHooks} from "./http"

@@ -45,2 +46,3 @@ export async function publishServices<S extends Services<S>, C extends RpcContext>(

createConnectionContext(req: IncomingMessage): Promise<RpcConnectionContext>
createServerHooks?(hooks: HttpServerHooks, req: IncomingMessage): HttpServerHooks
} & (

@@ -47,0 +49,0 @@ | {

@@ -41,3 +41,9 @@ import {PublishServicesOptions, RpcServer} from "./index.js"

this.httpServer.addListener("request", (req, res) =>
this.httpServer.addListener("request", (req, res) => {
const hooks = {
call: this.call,
subscribe: this.subscribe,
unsubscribe: this.unsubscribe,
}
serveHttpRequest(

@@ -47,10 +53,8 @@ req,

options.path,
{
call: this.call,
subscribe: this.subscribe,
unsubscribe: this.unsubscribe,
},
options.createServerHooks ? options.createServerHooks(hooks, req) : hooks,
options.createConnectionContext
)
)
).catch((e) => {
log.warn("Unhandled error serving HTTP request", e)
})
})
}

@@ -57,0 +61,0 @@

import {assert} from "chai"
import {createTestClient, startTestServer, TEST_PORT, testClient, testServer} from "./testUtils.js"
import WebSocket, {WebSocketServer} from "ws"
import {createTestClient, startTestServer, testClient, testServer} from "./testUtils.js"
import WebSocket from "ws"
import {adelay} from "../src/utils/promises.js"
import http, {IncomingMessage} from "http"
import {parseCookies} from "../src/utils/cookies.js"

@@ -137,85 +135,2 @@ describe("connection", () => {

})
describe("cookies", () => {
it("handle cookies in subseq requests", async () => {
let call = 0
let sentClientCookies: Record<string, string> = {}
const httpServer = http.createServer((req, res) => {
const headers: Record<string, string> = {"Content-Type": "text/plain"}
if (!call++) {
headers["Set-Cookie"] = `name=value; path=/; secure; samesite=none; httponly`
} else {
sentClientCookies = parseCookies(req.headers.cookie || "")
}
res.writeHead(200, headers)
res.end("ok")
})
let resolveStarted = () => {}
const started = new Promise<void>((r) => (resolveStarted = r))
httpServer.listen(TEST_PORT, () => resolveStarted())
await started
const client = await createTestClient<{call(): Promise<string>}>()
await client.call()
await client.call()
assert.equal(Object.keys(sentClientCookies).length, 1)
assert.equal(sentClientCookies["name"], "value")
let resolveStopped = () => {}
const stopped = new Promise<void>((r) => (resolveStopped = r))
httpServer.closeAllConnections()
httpServer.close(() => resolveStopped())
await stopped
})
it("set cookie in http, use in ws", async () => {
const httpServer = http.createServer((req, res) => {
const headers: Record<string, string> = {
"Content-Type": "text/plain",
"Set-Cookie": "name=value; path=/; secure; samesite=none; httponly",
}
res.writeHead(200, headers)
res.end("ok")
})
const wss = new WebSocketServer({server: httpServer})
let sentClientCookies: Record<string, string> = {}
wss.on("connection", (ws: unknown, req: IncomingMessage) => {
sentClientCookies = parseCookies(req.headers.cookie || "")
})
let resolveStarted = () => {}
const started = new Promise<void>((r) => (resolveStarted = r))
httpServer.listen(TEST_PORT, () => resolveStarted())
await started
const client = await createTestClient<{call(): Promise<string>}>()
await client.call()
await client.call.subscribe(() => {})
assert.equal(Object.keys(sentClientCookies).length, 1)
assert.equal(sentClientCookies["name"], "value")
await testClient!.close()
let resolveStopped = () => {}
const stopped = new Promise<void>((r) => (resolveStopped = r))
httpServer.closeIdleConnections()
httpServer.closeAllConnections()
httpServer.close(() => resolveStopped())
await stopped
})
})
})

@@ -112,2 +112,33 @@ import {assert} from "chai"

})
it("updates middlewares", async () => {
let count = 1
const services = await startTestServer({
async remote() {
return count++
},
})
const client = await createTestClient<typeof services>({
updatesMiddleware: [
(ctx, next, r) => {
assert.ok(ctx.itemName)
return next((r as number) + 1)
},
],
})
let response
await client.remote.subscribe((r) => {
response = r
})
services.remote.trigger()
await adelay(20)
assert.equal(response, 3)
})
})

@@ -39,2 +39,8 @@ import {

): Promise<ServicesWithSubscriptions<S>> {
if (!options) options = {}
if (!options.middleware) options.middleware = []
options.middleware = [logMiddleware, ...options.middleware]
if (!options.updatesMiddleware) options.updatesMiddleware = []
options.updatesMiddleware = [logUpdatesMiddleware, ...options.updatesMiddleware]
const r = await consumeServices<S>(`http://127.0.0.1:${TEST_PORT}/rpc`, options)

@@ -57,1 +63,20 @@ testClient = r.client

})
async function logMiddleware(ctx: RpcContext, next: any, ...params: any) {
try {
console.log(`OUT:${ctx.invocationType} '${ctx.itemName}'`, ...params)
const r = await next()
console.log(`IN:${ctx.invocationType} '${ctx.itemName}'`, r)
return r
} catch (e) {
console.log(`ERR:${ctx.invocationType} '${ctx.itemName}'`, e)
throw e
}
}
async function logUpdatesMiddleware(ctx: RpcContext, next: any, res: any) {
console.log(`IN:${ctx.invocationType} '${ctx.itemName}'`, res)
return next()
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc