@electric-sql/client
Advanced tools
Comparing version 0.8.0 to 0.9.0
@@ -120,3 +120,2 @@ /** | ||
declare const DATABASE_ID_QUERY_PARAM = "database_id"; | ||
declare const COLUMNS_QUERY_PARAM = "columns"; | ||
@@ -132,36 +131,15 @@ declare const LIVE_CACHE_BUSTER_QUERY_PARAM = "cursor"; | ||
type Replica = `full` | `default`; | ||
type ReservedParamKeys = typeof DATABASE_ID_QUERY_PARAM | 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 ParamsRecord = Omit<Record<string, string>, ReservedParamKeys>; | ||
type RetryOpts = { | ||
params?: ParamsRecord; | ||
headers?: Record<string, string>; | ||
}; | ||
type ShapeStreamErrorHandler = (error: Error) => void | RetryOpts | Promise<void | RetryOpts>; | ||
/** | ||
* Options for constructing a ShapeStream. | ||
* PostgreSQL-specific shape parameters that can be provided externally | ||
*/ | ||
interface ShapeStreamOptions<T = never> { | ||
/** | ||
* The full URL to where the Shape is served. This can either be the Electric server | ||
* directly or a proxy. E.g. for a local Electric instance, you might set `http://localhost:3000/v1/shape` | ||
*/ | ||
url: string; | ||
/** | ||
* Which database to use. | ||
* This is optional unless Electric is used with multiple databases. | ||
*/ | ||
databaseId?: string; | ||
/** | ||
* The root table for the shape. Passed as a query parameter. Not required if you set the table in your proxy. | ||
*/ | ||
type PostgresParams = { | ||
/** The root table for the shape. Not required if you set the table in your proxy. */ | ||
table?: string; | ||
/** | ||
* The where clauses for the shape. | ||
*/ | ||
where?: string; | ||
/** | ||
* The columns to include in the shape. | ||
* Must include primary keys, and can only inlude valid columns. | ||
* Must include primary keys, and can only include valid columns. | ||
*/ | ||
columns?: string[]; | ||
/** The where clauses for the shape */ | ||
where?: string; | ||
/** | ||
@@ -174,7 +152,30 @@ * If `replica` is `default` (the default) then Electric will only send the | ||
* | ||
* Setting `replica` to `full` will obviously result in higher bandwidth | ||
* usage and so is not recommended. | ||
* Setting `replica` to `full` will result in higher bandwidth | ||
* usage and so is not generally recommended. | ||
*/ | ||
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; | ||
/** | ||
* External params type - what users provide. | ||
* Includes documented PostgreSQL params and allows string or string[] values for any additional params. | ||
*/ | ||
type ExternalParamsRecord = Partial<PostgresParams> & { | ||
[K in string as K extends ReservedParamKeys ? never : K]: string | string[]; | ||
}; | ||
type RetryOpts = { | ||
params?: ExternalParamsRecord; | ||
headers?: Record<string, string>; | ||
}; | ||
type ShapeStreamErrorHandler = (error: Error) => void | RetryOpts | Promise<void | RetryOpts>; | ||
/** | ||
* Options for constructing a ShapeStream. | ||
*/ | ||
interface ShapeStreamOptions<T = never> { | ||
/** | ||
* The full URL to where the Shape is served. This can either be the Electric server | ||
* directly or a proxy. E.g. for a local Electric instance, you might set `http://localhost:3000/v1/shape` | ||
*/ | ||
url: string; | ||
/** | ||
* The "offset" on the shape log. This is typically not set as the ShapeStream | ||
@@ -202,5 +203,8 @@ * will handle this automatically. A common scenario where you might pass an offset | ||
* Note: You cannot use Electric's reserved parameter names | ||
* (table, where, columns, offset, handle, live, cursor, database_id, replica). | ||
* (offset, handle, live, cursor). | ||
* | ||
* PostgreSQL-specific options like table, where, columns, and replica | ||
* should be specified here. | ||
*/ | ||
params?: ParamsRecord; | ||
params?: ExternalParamsRecord; | ||
/** | ||
@@ -218,3 +222,3 @@ * Automatically fetch updates to the Shape. If you just want to sync the current | ||
* This is optional, when it is not provided any shapestream errors will be thrown. | ||
* If the function is provided and returns an object containing parameters and/or headers | ||
* If the function returns an object containing parameters and/or headers | ||
* the shapestream will apply those changes and try syncing again. | ||
@@ -308,3 +312,8 @@ * If the function returns void the shapestream is stopped. | ||
* ``` | ||
* const shapeStream = new ShapeStream<{ foo: number }>(url: `http://localhost:3000/v1/shape`, table: `foo`}) | ||
* const shapeStream = new ShapeStream<{ foo: number }>({ | ||
* url: `http://localhost:3000/v1/shape`, | ||
* params: { | ||
* table: `foo` | ||
* } | ||
* }) | ||
* const shape = new Shape(shapeStream) | ||
@@ -311,0 +320,0 @@ * ``` |
@@ -253,3 +253,2 @@ var __defProp = Object.defineProperty; | ||
var CHUNK_UP_TO_DATE_HEADER = `electric-up-to-date`; | ||
var DATABASE_ID_QUERY_PARAM = `database_id`; | ||
var COLUMNS_QUERY_PARAM = `columns`; | ||
@@ -440,2 +439,3 @@ var LIVE_CACHE_BUSTER_QUERY_PARAM = `cursor`; | ||
nextUrl.searchParams.set(OFFSET_QUERY_PARAM, lastOffset); | ||
nextUrl.searchParams.sort(); | ||
return nextUrl.toString(); | ||
@@ -455,14 +455,16 @@ } | ||
var RESERVED_PARAMS = /* @__PURE__ */ new Set([ | ||
DATABASE_ID_QUERY_PARAM, | ||
COLUMNS_QUERY_PARAM, | ||
LIVE_CACHE_BUSTER_QUERY_PARAM, | ||
SHAPE_HANDLE_QUERY_PARAM, | ||
LIVE_QUERY_PARAM, | ||
OFFSET_QUERY_PARAM, | ||
TABLE_QUERY_PARAM, | ||
WHERE_QUERY_PARAM, | ||
REPLICA_PARAM | ||
OFFSET_QUERY_PARAM | ||
]); | ||
var _error, _fetchClient2, _messageParser, _subscribers, _lastOffset, _liveCacheBuster, _lastSyncedAt, _isUpToDate, _connected, _shapeHandle, _databaseId, _schema, _onError, _replica, _ShapeStream_instances, start_fn, publish_fn, sendErrorToSubscribers_fn, reset_fn; | ||
var _ShapeStream = class _ShapeStream { | ||
function toInternalParams(params) { | ||
const result = {}; | ||
for (const [key, value] of Object.entries(params)) { | ||
result[key] = Array.isArray(value) ? value.join(`,`) : value; | ||
} | ||
return result; | ||
} | ||
var _error, _fetchClient2, _messageParser, _subscribers, _lastOffset, _liveCacheBuster, _lastSyncedAt, _isUpToDate, _connected, _shapeHandle, _schema, _onError, _ShapeStream_instances, start_fn, publish_fn, sendErrorToSubscribers_fn, reset_fn; | ||
var ShapeStream = class { | ||
constructor(options) { | ||
@@ -482,6 +484,4 @@ __privateAdd(this, _ShapeStream_instances); | ||
__privateAdd(this, _shapeHandle); | ||
__privateAdd(this, _databaseId); | ||
__privateAdd(this, _schema); | ||
__privateAdd(this, _onError); | ||
__privateAdd(this, _replica); | ||
var _a, _b, _c; | ||
@@ -493,5 +493,3 @@ this.options = __spreadValues({ subscribe: true }, options); | ||
__privateSet(this, _shapeHandle, this.options.handle); | ||
__privateSet(this, _databaseId, this.options.databaseId); | ||
__privateSet(this, _messageParser, new MessageParser(options.parser)); | ||
__privateSet(this, _replica, this.options.replica); | ||
__privateSet(this, _onError, this.options.onError); | ||
@@ -562,12 +560,10 @@ const baseFetchClient = (_b = options.fetchClient) != null ? _b : (...args) => fetch(...args); | ||
_shapeHandle = new WeakMap(); | ||
_databaseId = new WeakMap(); | ||
_schema = new WeakMap(); | ||
_onError = new WeakMap(); | ||
_replica = new WeakMap(); | ||
_ShapeStream_instances = new WeakSet(); | ||
start_fn = async function() { | ||
var _a, _b, _c; | ||
var _a, _b; | ||
try { | ||
while (!((_a = this.options.signal) == null ? void 0 : _a.aborted) && !__privateGet(this, _isUpToDate) || this.options.subscribe) { | ||
const { url, table, where, columns, signal } = this.options; | ||
const { url, signal } = this.options; | ||
const fetchUrl = new URL(url); | ||
@@ -583,10 +579,20 @@ if (this.options.params) { | ||
} | ||
for (const [key, value] of Object.entries(this.options.params)) { | ||
const params = toInternalParams(this.options.params); | ||
if (params.table) | ||
fetchUrl.searchParams.set(TABLE_QUERY_PARAM, params.table); | ||
if (params.where) | ||
fetchUrl.searchParams.set(WHERE_QUERY_PARAM, params.where); | ||
if (params.columns) | ||
fetchUrl.searchParams.set(COLUMNS_QUERY_PARAM, params.columns); | ||
if (params.replica) | ||
fetchUrl.searchParams.set(REPLICA_PARAM, params.replica); | ||
const customParams = __spreadValues({}, params); | ||
delete customParams.table; | ||
delete customParams.where; | ||
delete customParams.columns; | ||
delete customParams.replica; | ||
for (const [key, value] of Object.entries(customParams)) { | ||
fetchUrl.searchParams.set(key, value); | ||
} | ||
} | ||
if (table) fetchUrl.searchParams.set(TABLE_QUERY_PARAM, table); | ||
if (where) fetchUrl.searchParams.set(WHERE_QUERY_PARAM, where); | ||
if (columns && columns.length > 0) | ||
fetchUrl.searchParams.set(COLUMNS_QUERY_PARAM, columns.join(`,`)); | ||
fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset)); | ||
@@ -606,8 +612,3 @@ if (__privateGet(this, _isUpToDate)) { | ||
} | ||
if (__privateGet(this, _databaseId)) { | ||
fetchUrl.searchParams.set(DATABASE_ID_QUERY_PARAM, __privateGet(this, _databaseId)); | ||
} | ||
if (((_b = __privateGet(this, _replica)) != null ? _b : _ShapeStream.Replica.DEFAULT) != _ShapeStream.Replica.DEFAULT) { | ||
fetchUrl.searchParams.set(REPLICA_PARAM, __privateGet(this, _replica)); | ||
} | ||
fetchUrl.searchParams.sort(); | ||
let response; | ||
@@ -650,3 +651,3 @@ try { | ||
}; | ||
__privateSet(this, _schema, (_c = __privateGet(this, _schema)) != null ? _c : getSchema()); | ||
__privateSet(this, _schema, (_b = __privateGet(this, _schema)) != null ? _b : getSchema()); | ||
const messages = status === 204 ? `[]` : await response.text(); | ||
@@ -717,7 +718,6 @@ if (status === 204) { | ||
}; | ||
_ShapeStream.Replica = { | ||
ShapeStream.Replica = { | ||
FULL: `full`, | ||
DEFAULT: `default` | ||
}; | ||
var ShapeStream = _ShapeStream; | ||
function validateOptions(options) { | ||
@@ -724,0 +724,0 @@ if (!options.url) { |
{ | ||
"name": "@electric-sql/client", | ||
"version": "0.8.0", | ||
"version": "0.9.0", | ||
"description": "Postgres everywhere - your data, in sync, wherever you need it.", | ||
@@ -5,0 +5,0 @@ "type": "module", |
@@ -54,3 +54,5 @@ <p align="center"> | ||
url: `${BASE_URL}/v1/shape`, | ||
table: `foo`, | ||
params: { | ||
table: `foo` | ||
} | ||
}) | ||
@@ -61,3 +63,2 @@ | ||
url: `${BASE_URL}/v1/shape`, | ||
table: `foo`, | ||
headers: { | ||
@@ -67,2 +68,3 @@ 'Authorization': 'Bearer token' | ||
params: { | ||
table: `foo`, | ||
'custom-param': 'value' | ||
@@ -86,3 +88,5 @@ } | ||
url: `${BASE_URL}/v1/shape`, | ||
table: `foo`, | ||
params: { | ||
table: `foo` | ||
} | ||
}) | ||
@@ -108,3 +112,5 @@ const shape = new Shape(stream) | ||
url: `${BASE_URL}/v1/shape`, | ||
table: `foo`, | ||
params: { | ||
table: `foo` | ||
}, | ||
onError: (error) => { | ||
@@ -111,0 +117,0 @@ // Handle all stream errors here |
@@ -37,3 +37,2 @@ import { | ||
WHERE_QUERY_PARAM, | ||
DATABASE_ID_QUERY_PARAM, | ||
TABLE_QUERY_PARAM, | ||
@@ -44,4 +43,2 @@ REPLICA_PARAM, | ||
const RESERVED_PARAMS = new Set([ | ||
DATABASE_ID_QUERY_PARAM, | ||
COLUMNS_QUERY_PARAM, | ||
LIVE_CACHE_BUSTER_QUERY_PARAM, | ||
@@ -51,5 +48,2 @@ SHAPE_HANDLE_QUERY_PARAM, | ||
OFFSET_QUERY_PARAM, | ||
TABLE_QUERY_PARAM, | ||
WHERE_QUERY_PARAM, | ||
REPLICA_PARAM, | ||
]) | ||
@@ -59,4 +53,32 @@ | ||
/** | ||
* PostgreSQL-specific shape parameters that can be provided externally | ||
*/ | ||
type PostgresParams = { | ||
/** The root table for the shape. Not required if you set the table in your proxy. */ | ||
table?: string | ||
/** | ||
* The columns to include in the shape. | ||
* Must include primary keys, and can only include valid columns. | ||
*/ | ||
columns?: string[] | ||
/** The where clauses for the shape */ | ||
where?: string | ||
/** | ||
* If `replica` is `default` (the default) then Electric will only send the | ||
* changed columns in an update. | ||
* | ||
* If it's `full` Electric will send the entire row with both changed and | ||
* unchanged values. | ||
* | ||
* Setting `replica` to `full` will result in higher bandwidth | ||
* usage and so is not generally recommended. | ||
*/ | ||
replica?: Replica | ||
} | ||
type ReservedParamKeys = | ||
| typeof DATABASE_ID_QUERY_PARAM | ||
| typeof COLUMNS_QUERY_PARAM | ||
@@ -71,8 +93,34 @@ | typeof LIVE_CACHE_BUSTER_QUERY_PARAM | ||
type ParamsRecord = Omit<Record<string, string>, ReservedParamKeys> | ||
/** | ||
* External params type - what users provide. | ||
* Includes documented PostgreSQL params and allows string or string[] values for any additional params. | ||
*/ | ||
type ExternalParamsRecord = Partial<PostgresParams> & { | ||
[K in string as K extends ReservedParamKeys ? never : K]: string | string[] | ||
} | ||
/** | ||
* Internal params type - used within the library. | ||
* All values are converted to strings. | ||
*/ | ||
type InternalParamsRecord = { | ||
[K in string as K extends ReservedParamKeys ? never : K]: string | ||
} | ||
/** | ||
* Helper function to convert external params to internal format | ||
*/ | ||
function toInternalParams(params: ExternalParamsRecord): InternalParamsRecord { | ||
const result: InternalParamsRecord = {} | ||
for (const [key, value] of Object.entries(params)) { | ||
result[key] = Array.isArray(value) ? value.join(`,`) : value | ||
} | ||
return result | ||
} | ||
type RetryOpts = { | ||
params?: ParamsRecord | ||
params?: ExternalParamsRecord | ||
headers?: Record<string, string> | ||
} | ||
type ShapeStreamErrorHandler = ( | ||
@@ -93,36 +141,2 @@ error: Error | ||
/** | ||
* Which database to use. | ||
* This is optional unless Electric is used with multiple databases. | ||
*/ | ||
databaseId?: string | ||
/** | ||
* The root table for the shape. Passed as a query parameter. Not required if you set the table in your proxy. | ||
*/ | ||
table?: string | ||
/** | ||
* The where clauses for the shape. | ||
*/ | ||
where?: string | ||
/** | ||
* The columns to include in the shape. | ||
* Must include primary keys, and can only inlude valid columns. | ||
*/ | ||
columns?: string[] | ||
/** | ||
* If `replica` is `default` (the default) then Electric will only send the | ||
* changed columns in an update. | ||
* | ||
* If it's `full` Electric will send the entire row with both changed and | ||
* unchanged values. | ||
* | ||
* Setting `replica` to `full` will obviously result in higher bandwidth | ||
* usage and so is not recommended. | ||
*/ | ||
replica?: Replica | ||
/** | ||
* The "offset" on the shape log. This is typically not set as the ShapeStream | ||
@@ -153,5 +167,8 @@ * will handle this automatically. A common scenario where you might pass an offset | ||
* Note: You cannot use Electric's reserved parameter names | ||
* (table, where, columns, offset, handle, live, cursor, database_id, replica). | ||
* (offset, handle, live, cursor). | ||
* | ||
* PostgreSQL-specific options like table, where, columns, and replica | ||
* should be specified here. | ||
*/ | ||
params?: ParamsRecord | ||
params?: ExternalParamsRecord | ||
@@ -172,3 +189,3 @@ /** | ||
* This is optional, when it is not provided any shapestream errors will be thrown. | ||
* If the function is provided and returns an object containing parameters and/or headers | ||
* If the function returns an object containing parameters and/or headers | ||
* the shapestream will apply those changes and try syncing again. | ||
@@ -257,6 +274,4 @@ * If the function returns void the shapestream is stopped. | ||
#shapeHandle?: string | ||
#databaseId?: string | ||
#schema?: Schema | ||
#onError?: ShapeStreamErrorHandler | ||
#replica?: Replica | ||
@@ -269,5 +284,3 @@ constructor(options: ShapeStreamOptions<GetExtensions<T>>) { | ||
this.#shapeHandle = this.options.handle | ||
this.#databaseId = this.options.databaseId | ||
this.#messageParser = new MessageParser<T>(options.parser) | ||
this.#replica = this.options.replica | ||
this.#onError = this.options.onError | ||
@@ -316,3 +329,3 @@ | ||
) { | ||
const { url, table, where, columns, signal } = this.options | ||
const { url, signal } = this.options | ||
@@ -333,4 +346,22 @@ const fetchUrl = new URL(url) | ||
for (const [key, value] of Object.entries(this.options.params)) { | ||
fetchUrl.searchParams.set(key, value) | ||
// Add PostgreSQL-specific parameters from params | ||
const params = toInternalParams(this.options.params) | ||
if (params.table) | ||
fetchUrl.searchParams.set(TABLE_QUERY_PARAM, params.table) | ||
if (params.where) | ||
fetchUrl.searchParams.set(WHERE_QUERY_PARAM, params.where) | ||
if (params.columns) | ||
fetchUrl.searchParams.set(COLUMNS_QUERY_PARAM, params.columns) | ||
if (params.replica) | ||
fetchUrl.searchParams.set(REPLICA_PARAM, params.replica) | ||
// Add any remaining custom parameters | ||
const customParams = { ...params } | ||
delete customParams.table | ||
delete customParams.where | ||
delete customParams.columns | ||
delete customParams.replica | ||
for (const [key, value] of Object.entries(customParams)) { | ||
fetchUrl.searchParams.set(key, value as string) | ||
} | ||
@@ -340,6 +371,2 @@ } | ||
// Add Electric's internal parameters | ||
if (table) fetchUrl.searchParams.set(TABLE_QUERY_PARAM, table) | ||
if (where) fetchUrl.searchParams.set(WHERE_QUERY_PARAM, where) | ||
if (columns && columns.length > 0) | ||
fetchUrl.searchParams.set(COLUMNS_QUERY_PARAM, columns.join(`,`)) | ||
fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, this.#lastOffset) | ||
@@ -363,13 +390,5 @@ | ||
if (this.#databaseId) { | ||
fetchUrl.searchParams.set(DATABASE_ID_QUERY_PARAM, this.#databaseId!) | ||
} | ||
// sort query params in-place for stable URLs and improved cache hits | ||
fetchUrl.searchParams.sort() | ||
if ( | ||
(this.#replica ?? ShapeStream.Replica.DEFAULT) != | ||
ShapeStream.Replica.DEFAULT | ||
) { | ||
fetchUrl.searchParams.set(REPLICA_PARAM, this.#replica as string) | ||
} | ||
let response!: Response | ||
@@ -376,0 +395,0 @@ try { |
@@ -6,3 +6,2 @@ export const LIVE_CACHE_BUSTER_HEADER = `electric-cursor` | ||
export const CHUNK_UP_TO_DATE_HEADER = `electric-up-to-date` | ||
export const DATABASE_ID_QUERY_PARAM = `database_id` | ||
export const COLUMNS_QUERY_PARAM = `columns` | ||
@@ -9,0 +8,0 @@ export const LIVE_CACHE_BUSTER_QUERY_PARAM = `cursor` |
@@ -315,2 +315,3 @@ import { | ||
nextUrl.searchParams.set(OFFSET_QUERY_PARAM, lastOffset) | ||
nextUrl.searchParams.sort() | ||
return nextUrl.toString() | ||
@@ -317,0 +318,0 @@ } |
@@ -24,3 +24,8 @@ import { Message, Offset, Row } from './types' | ||
* ``` | ||
* const shapeStream = new ShapeStream<{ foo: number }>(url: `http://localhost:3000/v1/shape`, table: `foo`}) | ||
* const shapeStream = new ShapeStream<{ foo: number }>({ | ||
* url: `http://localhost:3000/v1/shape`, | ||
* params: { | ||
* table: `foo` | ||
* } | ||
* }) | ||
* const shape = new Shape(shapeStream) | ||
@@ -27,0 +32,0 @@ * ``` |
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
436176
4545
178