New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@electric-sql/client

Package Overview
Dependencies
Maintainers
0
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@electric-sql/client - npm Package Compare versions

Comparing version 0.3.4 to 0.4.0

8

dist/index.d.ts

@@ -180,3 +180,5 @@ type Value = string | number | boolean | bigint | null | Value[] | {

private messageParser;
private lastSyncedAt?;
isUpToDate: boolean;
private connected;
shapeId?: string;

@@ -191,2 +193,5 @@ constructor(options: ShapeStreamOptions);

unsubscribeAllUpToDateSubscribers(): void;
/** Time elapsed since last sync (in ms). Infinity if we did not yet sync. */
lastSynced(): number;
isConnected(): boolean;
private notifyUpToDateSubscribers;

@@ -240,3 +245,4 @@ private sendErrorToUpToDateSubscribers;

constructor(stream: ShapeStream<T>);
get isUpToDate(): boolean;
lastSynced(): number;
isConnected(): boolean;
get value(): Promise<ShapeData<T>>;

@@ -243,0 +249,0 @@ get valueSync(): ShapeData<T>;

135

dist/index.legacy-esm.js

@@ -207,3 +207,5 @@ var __defProp = Object.defineProperty;

this.upToDateSubscribers = /* @__PURE__ */ new Map();
// unix time
this.isUpToDate = false;
this.connected = false;
var _a, _b, _c;

@@ -223,54 +225,64 @@ this.validateOptions(options);

const { url, where, signal } = this.options;
while (!(signal == null ? void 0 : signal.aborted) && !this.isUpToDate || this.options.subscribe) {
const fetchUrl = new URL(url);
if (where) fetchUrl.searchParams.set(`where`, where);
fetchUrl.searchParams.set(`offset`, this.lastOffset);
if (this.isUpToDate) {
fetchUrl.searchParams.set(`live`, `true`);
}
if (this.shapeId) {
fetchUrl.searchParams.set(`shape_id`, this.shapeId);
}
let response;
try {
const maybeResponse = await this.fetchWithBackoff(fetchUrl);
if (maybeResponse) response = maybeResponse;
else break;
} catch (e) {
if (!(e instanceof FetchError)) throw e;
if (e.status == 409) {
const newShapeId = e.headers[`x-electric-shape-id`];
this.reset(newShapeId);
this.publish(e.json);
continue;
} else if (e.status >= 400 && e.status < 500) {
this.sendErrorToUpToDateSubscribers(e);
this.sendErrorToSubscribers(e);
throw e;
try {
while (!(signal == null ? void 0 : signal.aborted) && !this.isUpToDate || this.options.subscribe) {
const fetchUrl = new URL(url);
if (where) fetchUrl.searchParams.set(`where`, where);
fetchUrl.searchParams.set(`offset`, this.lastOffset);
if (this.isUpToDate) {
fetchUrl.searchParams.set(`live`, `true`);
}
}
const { headers, status } = response;
const shapeId = headers.get(`X-Electric-Shape-Id`);
if (shapeId) {
this.shapeId = shapeId;
}
const lastOffset = headers.get(`X-Electric-Chunk-Last-Offset`);
if (lastOffset) {
this.lastOffset = lastOffset;
}
const getSchema = () => {
const schemaHeader = headers.get(`X-Electric-Schema`);
return schemaHeader ? JSON.parse(schemaHeader) : {};
};
this.schema = (_a = this.schema) != null ? _a : getSchema();
const messages = status === 204 ? `[]` : await response.text();
const batch = this.messageParser.parse(messages, this.schema);
if (batch.length > 0) {
const lastMessage = batch[batch.length - 1];
if (isControlMessage(lastMessage) && lastMessage.headers.control === `up-to-date` && !this.isUpToDate) {
this.isUpToDate = true;
this.notifyUpToDateSubscribers();
if (this.shapeId) {
fetchUrl.searchParams.set(`shape_id`, this.shapeId);
}
this.publish(batch);
let response;
try {
const maybeResponse = await this.fetchWithBackoff(fetchUrl);
if (maybeResponse) response = maybeResponse;
else break;
} catch (e) {
if (!(e instanceof FetchError)) throw e;
if (e.status == 409) {
const newShapeId = e.headers[`x-electric-shape-id`];
this.reset(newShapeId);
this.publish(e.json);
continue;
} else if (e.status >= 400 && e.status < 500) {
this.sendErrorToUpToDateSubscribers(e);
this.sendErrorToSubscribers(e);
throw e;
}
}
const { headers, status } = response;
const shapeId = headers.get(`X-Electric-Shape-Id`);
if (shapeId) {
this.shapeId = shapeId;
}
const lastOffset = headers.get(`X-Electric-Chunk-Last-Offset`);
if (lastOffset) {
this.lastOffset = lastOffset;
}
const getSchema = () => {
const schemaHeader = headers.get(`X-Electric-Schema`);
return schemaHeader ? JSON.parse(schemaHeader) : {};
};
this.schema = (_a = this.schema) != null ? _a : getSchema();
const messages = status === 204 ? `[]` : await response.text();
if (status === 204) {
this.lastSyncedAt = Date.now();
}
const batch = this.messageParser.parse(messages, this.schema);
if (batch.length > 0) {
const lastMessage = batch[batch.length - 1];
if (isControlMessage(lastMessage) && lastMessage.headers.control === `up-to-date`) {
this.lastSyncedAt = Date.now();
if (!this.isUpToDate) {
this.isUpToDate = true;
this.notifyUpToDateSubscribers();
}
}
this.publish(batch);
}
}
} finally {
this.connected = false;
}

@@ -309,2 +321,10 @@ }

}
/** Time elapsed since last sync (in ms). Infinity if we did not yet sync. */
lastSynced() {
if (this.lastSyncedAt === void 0) return Infinity;
return Date.now() - this.lastSyncedAt;
}
isConnected() {
return this.connected;
}
notifyUpToDateSubscribers() {

@@ -328,2 +348,3 @@ this.upToDateSubscribers.forEach(([callback]) => {

this.isUpToDate = false;
this.connected = false;
this.schema = void 0;

@@ -354,5 +375,10 @@ }

const result = await this.fetchClient(url.toString(), { signal });
if (result.ok) return result;
else throw await FetchError.fromResponse(result, url.toString());
if (result.ok) {
if (this.options.subscribe) {
this.connected = true;
}
return result;
} else throw await FetchError.fromResponse(result, url.toString());
} catch (e) {
this.connected = false;
if (signal == null ? void 0 : signal.aborted) {

@@ -390,5 +416,8 @@ return void 0;

}
get isUpToDate() {
return this.stream.isUpToDate;
lastSynced() {
return this.stream.lastSynced();
}
isConnected() {
return this.stream.isConnected();
}
get value() {

@@ -395,0 +424,0 @@ return new Promise((resolve) => {

{
"name": "@electric-sql/client",
"version": "0.3.4",
"version": "0.4.0",
"description": "Postgres everywhere - your data, in sync, wherever you need it.",

@@ -31,3 +31,3 @@ "type": "module",

},
"homepage": "https://next.electric-sql.com",
"homepage": "https://electric-sql.com",
"dependencies": {},

@@ -34,0 +34,0 @@ "devDependencies": {

<p align="center">
<a href="https://next.electric-sql.com" target="_blank">
<a href="https://electric-sql.com" target="_blank">
<picture>

@@ -30,3 +30,3 @@ <source media="(prefers-color-scheme: dark)"

Electric provides an [HTTP interface](https://next.electric-sql.com/api/http) to Postgres to enable a massive number of clients to query and get real-time updates to subsets of the database, called [Shapes](https://next.electric-sql.com//guides/shapes). In this way, Electric turns Postgres into a real-time database.
Electric provides an [HTTP interface](https://electric-sql.com/docs/api/http) to Postgres to enable a massive number of clients to query and get real-time updates to subsets of the database, called [Shapes](https://electric-sql.com//docs/guides/shapes). In this way, Electric turns Postgres into a real-time database.

@@ -81,2 +81,2 @@ The TypeScript client helps ease reading Shapes from the HTTP API in the browser and other JavaScript environments, such as edge functions and server-side Node/Bun/Deno applications. It supports both fine-grained and coarse-grained reactivity patterns &mdash; you can subscribe to see every row that changes, or you can just subscribe to get the whole shape whenever it changes.

See the [Docs](https://next.electric-sql.com) and [Examples](https://next.electric-sql.com/examples/basic) for more information.
See the [Docs](https://electric-sql.com) and [Examples](https://electric-sql.com/examples/basic) for more information.

@@ -189,3 +189,5 @@ import { Message, Offset, Schema, Row } from './types'

private messageParser: MessageParser<T>
private lastSyncedAt?: number // unix time
public isUpToDate: boolean = false
private connected: boolean = false

@@ -214,76 +216,87 @@ shapeId?: string

while ((!signal?.aborted && !this.isUpToDate) || this.options.subscribe) {
const fetchUrl = new URL(url)
if (where) fetchUrl.searchParams.set(`where`, where)
fetchUrl.searchParams.set(`offset`, this.lastOffset)
try {
while ((!signal?.aborted && !this.isUpToDate) || this.options.subscribe) {
const fetchUrl = new URL(url)
if (where) fetchUrl.searchParams.set(`where`, where)
fetchUrl.searchParams.set(`offset`, this.lastOffset)
if (this.isUpToDate) {
fetchUrl.searchParams.set(`live`, `true`)
}
if (this.isUpToDate) {
fetchUrl.searchParams.set(`live`, `true`)
}
if (this.shapeId) {
// This should probably be a header for better cache breaking?
fetchUrl.searchParams.set(`shape_id`, this.shapeId!)
}
if (this.shapeId) {
// This should probably be a header for better cache breaking?
fetchUrl.searchParams.set(`shape_id`, this.shapeId!)
}
let response!: Response
let response!: Response
try {
const maybeResponse = await this.fetchWithBackoff(fetchUrl)
if (maybeResponse) response = maybeResponse
else break
} catch (e) {
if (!(e instanceof FetchError)) throw e // should never happen
if (e.status == 409) {
// Upon receiving a 409, we should start from scratch
// with the newly provided shape ID
const newShapeId = e.headers[`x-electric-shape-id`]
this.reset(newShapeId)
this.publish(e.json as Message<T>[])
continue
} else if (e.status >= 400 && e.status < 500) {
// Notify subscribers
this.sendErrorToUpToDateSubscribers(e)
this.sendErrorToSubscribers(e)
try {
const maybeResponse = await this.fetchWithBackoff(fetchUrl)
if (maybeResponse) response = maybeResponse
else break
} catch (e) {
if (!(e instanceof FetchError)) throw e // should never happen
if (e.status == 409) {
// Upon receiving a 409, we should start from scratch
// with the newly provided shape ID
const newShapeId = e.headers[`x-electric-shape-id`]
this.reset(newShapeId)
this.publish(e.json as Message<T>[])
continue
} else if (e.status >= 400 && e.status < 500) {
// Notify subscribers
this.sendErrorToUpToDateSubscribers(e)
this.sendErrorToSubscribers(e)
// 400 errors are not actionable without additional user input, so we're throwing them.
throw e
// 400 errors are not actionable without additional user input, so we're throwing them.
throw e
}
}
}
const { headers, status } = response
const shapeId = headers.get(`X-Electric-Shape-Id`)
if (shapeId) {
this.shapeId = shapeId
}
const { headers, status } = response
const shapeId = headers.get(`X-Electric-Shape-Id`)
if (shapeId) {
this.shapeId = shapeId
}
const lastOffset = headers.get(`X-Electric-Chunk-Last-Offset`)
if (lastOffset) {
this.lastOffset = lastOffset as Offset
}
const lastOffset = headers.get(`X-Electric-Chunk-Last-Offset`)
if (lastOffset) {
this.lastOffset = lastOffset as Offset
}
const getSchema = (): Schema => {
const schemaHeader = headers.get(`X-Electric-Schema`)
return schemaHeader ? JSON.parse(schemaHeader) : {}
}
this.schema = this.schema ?? getSchema()
const getSchema = (): Schema => {
const schemaHeader = headers.get(`X-Electric-Schema`)
return schemaHeader ? JSON.parse(schemaHeader) : {}
}
this.schema = this.schema ?? getSchema()
const messages = status === 204 ? `[]` : await response.text()
const messages = status === 204 ? `[]` : await response.text()
const batch = this.messageParser.parse(messages, this.schema)
if (status === 204) {
// There's no content so we are live and up to date
this.lastSyncedAt = Date.now()
}
// Update isUpToDate
if (batch.length > 0) {
const lastMessage = batch[batch.length - 1]
if (
isControlMessage(lastMessage) &&
lastMessage.headers.control === `up-to-date` &&
!this.isUpToDate
) {
this.isUpToDate = true
this.notifyUpToDateSubscribers()
const batch = this.messageParser.parse(messages, this.schema)
// Update isUpToDate
if (batch.length > 0) {
const lastMessage = batch[batch.length - 1]
if (
isControlMessage(lastMessage) &&
lastMessage.headers.control === `up-to-date`
) {
this.lastSyncedAt = Date.now()
if (!this.isUpToDate) {
this.isUpToDate = true
this.notifyUpToDateSubscribers()
}
}
this.publish(batch)
}
this.publish(batch)
}
} finally {
this.connected = false
}

@@ -339,2 +352,12 @@ }

/** Time elapsed since last sync (in ms). Infinity if we did not yet sync. */
lastSynced(): number {
if (this.lastSyncedAt === undefined) return Infinity
return Date.now() - this.lastSyncedAt
}
isConnected(): boolean {
return this.connected
}
private notifyUpToDateSubscribers() {

@@ -361,2 +384,3 @@ this.upToDateSubscribers.forEach(([callback]) => {

this.isUpToDate = false
this.connected = false
this.schema = undefined

@@ -397,5 +421,10 @@ }

const result = await this.fetchClient(url.toString(), { signal })
if (result.ok) return result
else throw await FetchError.fromResponse(result, url.toString())
if (result.ok) {
if (this.options.subscribe) {
this.connected = true
}
return result
} else throw await FetchError.fromResponse(result, url.toString())
} catch (e) {
this.connected = false
if (signal?.aborted) {

@@ -479,6 +508,10 @@ return undefined

get isUpToDate(): boolean {
return this.stream.isUpToDate
lastSynced(): number {
return this.stream.lastSynced()
}
isConnected(): boolean {
return this.stream.isConnected()
}
get value(): Promise<ShapeData<T>> {

@@ -485,0 +518,0 @@ return new Promise((resolve) => {

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