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

@electric-sql/client

Package Overview
Dependencies
Maintainers
3
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 1.0.0-beta.1 to 1.0.0-beta.2

42

dist/index.d.ts

@@ -121,3 +121,2 @@ /**

declare const COLUMNS_QUERY_PARAM = "columns";
declare const LIVE_CACHE_BUSTER_QUERY_PARAM = "cursor";

@@ -127,5 +126,2 @@ declare const SHAPE_HANDLE_QUERY_PARAM = "handle";

declare const OFFSET_QUERY_PARAM = "offset";
declare const TABLE_QUERY_PARAM = "table";
declare const WHERE_QUERY_PARAM = "where";
declare const REPLICA_PARAM = "replica";

@@ -136,3 +132,3 @@ type Replica = `full` | `default`;

*/
type PostgresParams = {
interface PostgresParams {
/** The root table for the shape. Not required if you set the table in your proxy. */

@@ -158,14 +154,26 @@ table?: string;

replica?: Replica;
};
type ReservedParamKeys = typeof COLUMNS_QUERY_PARAM | typeof LIVE_CACHE_BUSTER_QUERY_PARAM | typeof SHAPE_HANDLE_QUERY_PARAM | typeof LIVE_QUERY_PARAM | typeof OFFSET_QUERY_PARAM | typeof TABLE_QUERY_PARAM | typeof WHERE_QUERY_PARAM | typeof REPLICA_PARAM;
}
type ParamValue = string | string[] | (() => string | string[] | Promise<string | string[]>);
/**
* External params type - what users provide.
* Includes documented PostgreSQL params and allows string or string[] values for any additional params.
* Excludes reserved parameters to prevent dynamic variations that could cause stream shape changes.
*/
type ExternalParamsRecord = Partial<PostgresParams> & {
[K in string as K extends ReservedParamKeys ? never : K]: string | string[];
type ExternalParamsRecord = {
[K in string as K extends ReservedParamKeys ? never : K]: ParamValue | undefined;
} & Partial<PostgresParams>;
type ReservedParamKeys = typeof LIVE_CACHE_BUSTER_QUERY_PARAM | typeof SHAPE_HANDLE_QUERY_PARAM | typeof LIVE_QUERY_PARAM | typeof OFFSET_QUERY_PARAM;
/**
* External headers type - what users provide.
* Allows string or function values for any header.
*/
type ExternalHeadersRecord = {
[key: string]: string | (() => string | Promise<string>);
};
/**
* Helper function to resolve a function or value to its final value
*/
declare function resolveValue<T>(value: T | (() => T | Promise<T>)): Promise<T>;
type RetryOpts = {
params?: ExternalParamsRecord;
headers?: Record<string, string>;
headers?: ExternalHeadersRecord;
};

@@ -198,7 +206,13 @@ type ShapeStreamErrorHandler = (error: Error) => void | RetryOpts | Promise<void | RetryOpts>;

* HTTP headers to attach to requests made by the client.
* Can be used for adding authentication headers.
* Values can be strings or functions (sync or async) that return strings.
* Function values are resolved in parallel when needed, making this useful
* for authentication tokens or other dynamic headers.
*/
headers?: Record<string, string>;
headers?: ExternalHeadersRecord;
/**
* Additional request parameters to attach to the URL.
* Values can be strings, string arrays, or functions (sync or async) that return these types.
* Function values are resolved in parallel when needed, making this useful
* for user-specific parameters or dynamic filters.
*
* These will be merged with Electric's standard parameters.

@@ -399,2 +413,2 @@ * Note: You cannot use Electric's reserved parameter names

export { BackoffDefaults, type BackoffOptions, type BitColumn, type BpcharColumn, type ChangeMessage, type ColumnInfo, type CommonColumnProps, type ControlMessage, FetchError, type GetExtensions, type IntervalColumn, type IntervalColumnWithPrecision, type MaybePromise, type Message, type NumericColumn, type Offset, type Operation, type RegularColumn, type Row, type Schema, Shape, type ShapeChangedCallback, type ShapeData, ShapeStream, type ShapeStreamInterface, type ShapeStreamOptions, type TimeColumn, type TypedMessages, type Value, type VarcharColumn, isChangeMessage, isControlMessage };
export { BackoffDefaults, type BackoffOptions, type BitColumn, type BpcharColumn, type ChangeMessage, type ColumnInfo, type CommonColumnProps, type ControlMessage, type ExternalHeadersRecord, type ExternalParamsRecord, FetchError, type GetExtensions, type IntervalColumn, type IntervalColumnWithPrecision, type MaybePromise, type Message, type NumericColumn, type Offset, type Operation, type PostgresParams, type RegularColumn, type Row, type Schema, Shape, type ShapeChangedCallback, type ShapeData, ShapeStream, type ShapeStreamInterface, type ShapeStreamOptions, type TimeColumn, type TypedMessages, type Value, type VarcharColumn, isChangeMessage, isControlMessage, resolveValue };

@@ -458,10 +458,33 @@ var __defProp = Object.defineProperty;

]);
function toInternalParams(params) {
const result = {};
for (const [key, value] of Object.entries(params)) {
result[key] = Array.isArray(value) ? value.join(`,`) : value;
async function resolveValue(value) {
if (typeof value === `function`) {
return value();
}
return result;
return value;
}
var _error, _fetchClient2, _messageParser, _subscribers, _lastOffset, _liveCacheBuster, _lastSyncedAt, _isUpToDate, _connected, _shapeHandle, _schema, _onError, _ShapeStream_instances, start_fn, publish_fn, sendErrorToSubscribers_fn, reset_fn;
async function toInternalParams(params) {
const entries = Object.entries(params);
const resolvedEntries = await Promise.all(
entries.map(async ([key, value]) => {
if (value === void 0) return [key, void 0];
const resolvedValue = await resolveValue(value);
return [
key,
Array.isArray(resolvedValue) ? resolvedValue.join(`,`) : resolvedValue
];
})
);
return Object.fromEntries(
resolvedEntries.filter(([_, value]) => value !== void 0)
);
}
async function resolveHeaders(headers) {
if (!headers) return {};
const entries = Object.entries(headers);
const resolvedEntries = await Promise.all(
entries.map(async ([key, value]) => [key, await resolveValue(value)])
);
return Object.fromEntries(resolvedEntries);
}
var _error, _fetchClient2, _messageParser, _subscribers, _started, _lastOffset, _liveCacheBuster, _lastSyncedAt, _isUpToDate, _connected, _shapeHandle, _schema, _onError, _ShapeStream_instances, start_fn, publish_fn, sendErrorToSubscribers_fn, reset_fn;
var ShapeStream = class {

@@ -474,2 +497,3 @@ constructor(options) {

__privateAdd(this, _subscribers, /* @__PURE__ */ new Map());
__privateAdd(this, _started, false);
__privateAdd(this, _lastOffset);

@@ -504,3 +528,2 @@ __privateAdd(this, _liveCacheBuster);

));
__privateMethod(this, _ShapeStream_instances, start_fn).call(this);
}

@@ -523,2 +546,3 @@ get shapeHandle() {

__privateGet(this, _subscribers).set(subscriptionId, [callback, onError]);
if (!__privateGet(this, _started)) __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
return () => {

@@ -553,2 +577,3 @@ __privateGet(this, _subscribers).delete(subscriptionId);

_subscribers = new WeakMap();
_started = new WeakMap();
_lastOffset = new WeakMap();

@@ -565,16 +590,16 @@ _liveCacheBuster = new WeakMap();

var _a, _b;
if (__privateGet(this, _started)) throw new Error(`Cannot start stream twice`);
__privateSet(this, _started, true);
try {
while (!((_a = this.options.signal) == null ? void 0 : _a.aborted) && !__privateGet(this, _isUpToDate) || this.options.subscribe) {
const { url, signal } = this.options;
const [requestHeaders, params] = await Promise.all([
resolveHeaders(this.options.headers),
this.options.params ? toInternalParams(this.options.params) : void 0
]);
if (params) {
validateParams(params);
}
const fetchUrl = new URL(url);
if (this.options.params) {
const reservedParams = Object.keys(this.options.params).filter(
(key) => RESERVED_PARAMS.has(key)
);
if (reservedParams.length > 0) {
throw new Error(
`Cannot use reserved Electric parameter names in custom params: ${reservedParams.join(`, `)}`
);
}
const params = toInternalParams(this.options.params);
if (params) {
if (params.table)

@@ -616,3 +641,3 @@ fetchUrl.searchParams.set(TABLE_QUERY_PARAM, params.table);

signal,
headers: this.options.headers
headers: requestHeaders
});

@@ -677,2 +702,3 @@ __privateSet(this, _connected, true);

}
__privateSet(this, _started, false);
__privateMethod(this, _ShapeStream_instances, start_fn).call(this);

@@ -721,2 +747,11 @@ }

};
function validateParams(params) {
if (!params) return;
const reservedParams = Object.keys(params).filter(
(key) => RESERVED_PARAMS.has(key)
);
if (reservedParams.length > 0) {
throw new ReservedParamError(reservedParams);
}
}
function validateOptions(options) {

@@ -732,10 +767,3 @@ if (!options.url) {

}
if (options.params) {
const reservedParams = Object.keys(options.params).filter(
(key) => RESERVED_PARAMS.has(key)
);
if (reservedParams.length > 0) {
throw new ReservedParamError(reservedParams);
}
}
validateParams(options.params);
return;

@@ -889,4 +917,5 @@ }

isChangeMessage,
isControlMessage
isControlMessage,
resolveValue
};
//# sourceMappingURL=index.legacy-esm.js.map
{
"name": "@electric-sql/client",
"description": "Postgres everywhere - your data, in sync, wherever you need it.",
"version": "1.0.0-beta.1",
"version": "1.0.0-beta.2",
"author": "ElectricSQL team and contributors.",

@@ -6,0 +6,0 @@ "bugs": {

@@ -21,3 +21,3 @@ <p align="center">

<a href="https://github.com/electric-sql/electric-n
ext/milestones"><img src="https://img.shields.io/badge/status-alpha-orange" alt="Status - Alpha"></a>
ext/milestones"><img src="https://img.shields.io/badge/status-beta-orange" alt="Status - Beta"></a>
<a href="https://discord.electric-sql.com"><img src="https://img.shields.io/discord/933657521581858818?color=5969EA&label=discord" alt="Chat - Discord"></a>

@@ -33,3 +33,3 @@ <a href="https://x.com/ElectricSQL" target="_blank"><img src="https://img.shields.io/twitter/follow/ElectricSQL.svg?style=social&label=Follow @ElectricSQL"></a>

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.
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. The client also supports dynamic options through function-based params and headers, making it easy to handle auth tokens, user context, and other runtime values.

@@ -148,3 +148,3 @@ ## Install

And in general, see the [docs website](https://electric-sql.com) and [examples folder](https://electric-sql.com/examples/basic) for more information.
And in general, see the [docs website](https://electric-sql.com) and [examples](https://electric-sql.com/demos) for more information.

@@ -151,0 +151,0 @@ ## Develop

@@ -41,3 +41,3 @@ import {

const RESERVED_PARAMS = new Set([
const RESERVED_PARAMS: Set<ReservedParamKeys> = new Set([
LIVE_CACHE_BUSTER_QUERY_PARAM,

@@ -54,3 +54,3 @@ SHAPE_HANDLE_QUERY_PARAM,

*/
type PostgresParams = {
export interface PostgresParams {
/** The root table for the shape. Not required if you set the table in your proxy. */

@@ -81,4 +81,18 @@ table?: string

type ParamValue =
| string
| string[]
| (() => string | string[] | Promise<string | string[]>)
/**
* External params type - what users provide.
* Excludes reserved parameters to prevent dynamic variations that could cause stream shape changes.
*/
export type ExternalParamsRecord = {
[K in string as K extends ReservedParamKeys ? never : K]:
| ParamValue
| undefined
} & Partial<PostgresParams>
type ReservedParamKeys =
| typeof COLUMNS_QUERY_PARAM
| typeof LIVE_CACHE_BUSTER_QUERY_PARAM

@@ -88,12 +102,9 @@ | typeof SHAPE_HANDLE_QUERY_PARAM

| typeof OFFSET_QUERY_PARAM
| typeof TABLE_QUERY_PARAM
| typeof WHERE_QUERY_PARAM
| typeof REPLICA_PARAM
/**
* External params type - what users provide.
* Includes documented PostgreSQL params and allows string or string[] values for any additional params.
* External headers type - what users provide.
* Allows string or function values for any header.
*/
type ExternalParamsRecord = Partial<PostgresParams> & {
[K in string as K extends ReservedParamKeys ? never : K]: string | string[]
export type ExternalHeadersRecord = {
[key: string]: string | (() => string | Promise<string>)
}

@@ -110,15 +121,55 @@

/**
* Helper function to convert external params to internal format
* Helper function to resolve a function or value to its final value
*/
function toInternalParams(params: ExternalParamsRecord): InternalParamsRecord {
const result: InternalParamsRecord = {}
for (const [key, value] of Object.entries(params)) {
result[key] = Array.isArray(value) ? value.join(`,`) : value
export async function resolveValue<T>(
value: T | (() => T | Promise<T>)
): Promise<T> {
if (typeof value === `function`) {
return (value as () => T | Promise<T>)()
}
return result
return value
}
/**
* Helper function to convert external params to internal format
*/
async function toInternalParams(
params: ExternalParamsRecord
): Promise<InternalParamsRecord> {
const entries = Object.entries(params)
const resolvedEntries = await Promise.all(
entries.map(async ([key, value]) => {
if (value === undefined) return [key, undefined]
const resolvedValue = await resolveValue(value)
return [
key,
Array.isArray(resolvedValue) ? resolvedValue.join(`,`) : resolvedValue,
]
})
)
return Object.fromEntries(
resolvedEntries.filter(([_, value]) => value !== undefined)
)
}
/**
* Helper function to resolve headers
*/
async function resolveHeaders(
headers?: ExternalHeadersRecord
): Promise<Record<string, string>> {
if (!headers) return {}
const entries = Object.entries(headers)
const resolvedEntries = await Promise.all(
entries.map(async ([key, value]) => [key, await resolveValue(value)])
)
return Object.fromEntries(resolvedEntries)
}
type RetryOpts = {
params?: ExternalParamsRecord
headers?: Record<string, string>
headers?: ExternalHeadersRecord
}

@@ -158,8 +209,14 @@

* HTTP headers to attach to requests made by the client.
* Can be used for adding authentication headers.
* Values can be strings or functions (sync or async) that return strings.
* Function values are resolved in parallel when needed, making this useful
* for authentication tokens or other dynamic headers.
*/
headers?: Record<string, string>
headers?: ExternalHeadersRecord
/**
* Additional request parameters to attach to the URL.
* Values can be strings, string arrays, or functions (sync or async) that return these types.
* Function values are resolved in parallel when needed, making this useful
* for user-specific parameters or dynamic filters.
*
* These will be merged with Electric's standard parameters.

@@ -266,2 +323,3 @@ * Note: You cannot use Electric's reserved parameter names

#started = false
#lastOffset: Offset

@@ -300,4 +358,2 @@ #liveCacheBuster: string // Seconds since our Electric Epoch 😎

)
this.#start()
}

@@ -322,2 +378,5 @@

async #start() {
if (this.#started) throw new Error(`Cannot start stream twice`)
this.#started = true
try {

@@ -330,18 +389,19 @@ while (

// Resolve headers and params in parallel
const [requestHeaders, params] = await Promise.all([
resolveHeaders(this.options.headers),
this.options.params
? toInternalParams(this.options.params)
: undefined,
])
// Validate params after resolution
if (params) {
validateParams(params)
}
const fetchUrl = new URL(url)
// Add any custom parameters first
if (this.options.params) {
// Check for reserved parameter names
const reservedParams = Object.keys(this.options.params).filter(
(key) => RESERVED_PARAMS.has(key)
)
if (reservedParams.length > 0) {
throw new Error(
`Cannot use reserved Electric parameter names in custom params: ${reservedParams.join(`, `)}`
)
}
// Add PostgreSQL-specific parameters from params
const params = toInternalParams(this.options.params)
// Add PostgreSQL-specific parameters
if (params) {
if (params.table)

@@ -394,3 +454,3 @@ fetchUrl.searchParams.set(TABLE_QUERY_PARAM, params.table)

signal,
headers: this.options.headers,
headers: requestHeaders,
})

@@ -476,2 +536,3 @@ this.#connected = true

// Restart
this.#started = false
this.#start()

@@ -496,2 +557,3 @@ }

this.#subscribers.set(subscriptionId, [callback, onError])
if (!this.#started) this.#start()

@@ -562,2 +624,17 @@ return () => {

/**
* Validates that no reserved parameter names are used in the provided params object
* @throws {ReservedParamError} if any reserved parameter names are found
*/
function validateParams(params: Record<string, unknown> | undefined): void {
if (!params) return
const reservedParams = Object.keys(params).filter((key) =>
RESERVED_PARAMS.has(key as ReservedParamKeys)
)
if (reservedParams.length > 0) {
throw new ReservedParamError(reservedParams)
}
}
function validateOptions<T>(options: Partial<ShapeStreamOptions<T>>): void {

@@ -579,12 +656,5 @@ if (!options.url) {

// Check for reserved parameter names
if (options.params) {
const reservedParams = Object.keys(options.params).filter((key) =>
RESERVED_PARAMS.has(key)
)
if (reservedParams.length > 0) {
throw new ReservedParamError(reservedParams)
}
}
validateParams(options.params)
return
}

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