@livestore/common 0.4.0-dev.22 → 0.4.0-dev.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/ClientSessionLeaderThreadProxy.d.ts +9 -9
- package/dist/ClientSessionLeaderThreadProxy.d.ts.map +1 -1
- package/dist/WorkerTransportError.d.ts +11 -0
- package/dist/WorkerTransportError.d.ts.map +1 -0
- package/dist/WorkerTransportError.js +11 -0
- package/dist/WorkerTransportError.js.map +1 -0
- package/dist/adapter-types.d.ts +3 -3
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/adapter-types.js.map +1 -1
- package/dist/bounded-collections.d.ts.map +1 -1
- package/dist/bounded-collections.js +6 -4
- package/dist/bounded-collections.js.map +1 -1
- package/dist/debug-info.js +4 -4
- package/dist/debug-info.js.map +1 -1
- package/dist/devtools/devtools-messages-common.js +1 -1
- package/dist/devtools/devtools-messages-common.js.map +1 -1
- package/dist/devtools/mod.js +1 -1
- package/dist/devtools/mod.js.map +1 -1
- package/dist/errors.d.ts +15 -15
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +11 -11
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.d.ts +20 -6
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.js +287 -257
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
- package/dist/leader-thread/RejectedPushError.d.ts +107 -0
- package/dist/leader-thread/RejectedPushError.d.ts.map +1 -0
- package/dist/leader-thread/RejectedPushError.js +78 -0
- package/dist/leader-thread/RejectedPushError.js.map +1 -0
- package/dist/leader-thread/connection.js +1 -1
- package/dist/leader-thread/connection.js.map +1 -1
- package/dist/leader-thread/eventlog.d.ts.map +1 -1
- package/dist/leader-thread/eventlog.js +12 -11
- package/dist/leader-thread/eventlog.js.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.d.ts +1 -2
- package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.js +25 -14
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts +8 -3
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +7 -10
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.test.js +1 -1
- package/dist/leader-thread/make-leader-thread-layer.test.js.map +1 -1
- package/dist/leader-thread/materialize-event.js +4 -4
- package/dist/leader-thread/materialize-event.js.map +1 -1
- package/dist/leader-thread/recreate-db.js +1 -1
- package/dist/leader-thread/recreate-db.js.map +1 -1
- package/dist/leader-thread/shutdown-channel.d.ts +2 -2
- package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
- package/dist/leader-thread/shutdown-channel.js +2 -2
- package/dist/leader-thread/shutdown-channel.js.map +1 -1
- package/dist/leader-thread/stream-events.d.ts.map +1 -1
- package/dist/leader-thread/stream-events.js +4 -3
- package/dist/leader-thread/stream-events.js.map +1 -1
- package/dist/leader-thread/types.d.ts +7 -6
- package/dist/leader-thread/types.d.ts.map +1 -1
- package/dist/leader-thread/types.js.map +1 -1
- package/dist/logging.js +4 -4
- package/dist/logging.js.map +1 -1
- package/dist/make-client-session.js +2 -2
- package/dist/make-client-session.js.map +1 -1
- package/dist/materializer-helper.js +6 -6
- package/dist/materializer-helper.js.map +1 -1
- package/dist/otel.d.ts +1 -1
- package/dist/otel.d.ts.map +1 -1
- package/dist/otel.js +2 -2
- package/dist/otel.js.map +1 -1
- package/dist/rematerialize-from-eventlog.d.ts +1 -1
- package/dist/rematerialize-from-eventlog.d.ts.map +1 -1
- package/dist/rematerialize-from-eventlog.js +11 -9
- package/dist/rematerialize-from-eventlog.js.map +1 -1
- package/dist/schema/EventDef/define.d.ts +2 -2
- package/dist/schema/EventDef/define.d.ts.map +1 -1
- package/dist/schema/EventDef/define.js +4 -4
- package/dist/schema/EventDef/define.js.map +1 -1
- package/dist/schema/EventDef/deprecated.js +3 -3
- package/dist/schema/EventDef/deprecated.js.map +1 -1
- package/dist/schema/EventDef/deprecated.test.js +1 -1
- package/dist/schema/EventDef/deprecated.test.js.map +1 -1
- package/dist/schema/EventSequenceNumber/client.d.ts.map +1 -1
- package/dist/schema/EventSequenceNumber/client.js +11 -11
- package/dist/schema/EventSequenceNumber/client.js.map +1 -1
- package/dist/schema/EventSequenceNumber.test.js +1 -1
- package/dist/schema/EventSequenceNumber.test.js.map +1 -1
- package/dist/schema/LiveStoreEvent/client.d.ts.map +1 -1
- package/dist/schema/LiveStoreEvent/client.js +6 -3
- package/dist/schema/LiveStoreEvent/client.js.map +1 -1
- package/dist/schema/LiveStoreEvent/client.test.d.ts +2 -0
- package/dist/schema/LiveStoreEvent/client.test.d.ts.map +1 -0
- package/dist/schema/LiveStoreEvent/client.test.js +83 -0
- package/dist/schema/LiveStoreEvent/client.test.js.map +1 -0
- package/dist/schema/schema.d.ts.map +1 -1
- package/dist/schema/schema.js +7 -4
- package/dist/schema/schema.js.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.js +18 -6
- package/dist/schema/state/sqlite/client-document-def.js.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.test.js +1 -1
- package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -1
- package/dist/schema/state/sqlite/column-annotations.d.ts.map +1 -1
- package/dist/schema/state/sqlite/column-annotations.js +1 -1
- package/dist/schema/state/sqlite/column-annotations.js.map +1 -1
- package/dist/schema/state/sqlite/column-annotations.test.js +1 -1
- package/dist/schema/state/sqlite/column-annotations.test.js.map +1 -1
- package/dist/schema/state/sqlite/column-def.d.ts.map +1 -1
- package/dist/schema/state/sqlite/column-def.js +36 -34
- package/dist/schema/state/sqlite/column-def.js.map +1 -1
- package/dist/schema/state/sqlite/column-def.test.js +7 -6
- package/dist/schema/state/sqlite/column-def.test.js.map +1 -1
- package/dist/schema/state/sqlite/column-spec.d.ts.map +1 -1
- package/dist/schema/state/sqlite/column-spec.js +8 -8
- package/dist/schema/state/sqlite/column-spec.js.map +1 -1
- package/dist/schema/state/sqlite/column-spec.test.js +1 -1
- package/dist/schema/state/sqlite/column-spec.test.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.js +2 -2
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts +2 -2
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js +11 -2
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/mod.js +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/mod.js.map +1 -1
- package/dist/schema/state/sqlite/mod.d.ts.map +1 -1
- package/dist/schema/state/sqlite/mod.js +3 -5
- package/dist/schema/state/sqlite/mod.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/api.d.ts +10 -2
- package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -1
- package/dist/schema/state/sqlite/query-builder/astToSql.js +11 -11
- package/dist/schema/state/sqlite/query-builder/astToSql.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.d.ts +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.js +28 -14
- package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.test.js +3 -2
- package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -1
- package/dist/schema/state/sqlite/schema-helpers.js +2 -2
- package/dist/schema/state/sqlite/schema-helpers.js.map +1 -1
- package/dist/schema/state/sqlite/table-def.d.ts +5 -3
- package/dist/schema/state/sqlite/table-def.d.ts.map +1 -1
- package/dist/schema/state/sqlite/table-def.js +1 -1
- package/dist/schema/state/sqlite/table-def.js.map +1 -1
- package/dist/schema/state/sqlite/table-def.test.js +57 -4
- package/dist/schema/state/sqlite/table-def.test.js.map +1 -1
- package/dist/schema/unknown-events.d.ts +1 -1
- package/dist/schema/unknown-events.d.ts.map +1 -1
- package/dist/schema/unknown-events.js +1 -1
- package/dist/schema/unknown-events.js.map +1 -1
- package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js +1 -1
- package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js.map +1 -1
- package/dist/schema-management/common.js +2 -2
- package/dist/schema-management/common.js.map +1 -1
- package/dist/schema-management/migrations.js +1 -1
- package/dist/schema-management/migrations.js.map +1 -1
- package/dist/sql-queries/sql-queries.js +8 -6
- package/dist/sql-queries/sql-queries.js.map +1 -1
- package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
- package/dist/sql-queries/sql-query-builder.js.map +1 -1
- package/dist/sqlite-db-helper.js +3 -3
- package/dist/sqlite-db-helper.js.map +1 -1
- package/dist/sqlite-types.d.ts +2 -2
- package/dist/sqlite-types.d.ts.map +1 -1
- package/dist/sqlite-types.js.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.d.ts +8 -9
- package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.js +95 -113
- package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
- package/dist/sync/errors.d.ts +0 -38
- package/dist/sync/errors.d.ts.map +1 -1
- package/dist/sync/errors.js +3 -20
- package/dist/sync/errors.js.map +1 -1
- package/dist/sync/mock-sync-backend.d.ts +5 -3
- package/dist/sync/mock-sync-backend.d.ts.map +1 -1
- package/dist/sync/mock-sync-backend.js +70 -68
- package/dist/sync/mock-sync-backend.js.map +1 -1
- package/dist/sync/next/compact-events.js +6 -6
- package/dist/sync/next/compact-events.js.map +1 -1
- package/dist/sync/next/facts.d.ts.map +1 -1
- package/dist/sync/next/facts.js +6 -6
- package/dist/sync/next/facts.js.map +1 -1
- package/dist/sync/next/history-dag-common.d.ts.map +1 -1
- package/dist/sync/next/history-dag-common.js +6 -6
- package/dist/sync/next/history-dag-common.js.map +1 -1
- package/dist/sync/next/history-dag.js +3 -3
- package/dist/sync/next/history-dag.js.map +1 -1
- package/dist/sync/next/rebase-events.js +1 -1
- package/dist/sync/next/rebase-events.js.map +1 -1
- package/dist/sync/next/test/compact-events.calculator.test.js +2 -2
- package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
- package/dist/sync/next/test/compact-events.test.d.ts.map +1 -1
- package/dist/sync/next/test/compact-events.test.js +2 -2
- package/dist/sync/next/test/compact-events.test.js.map +1 -1
- package/dist/sync/next/test/event-fixtures.d.ts.map +1 -1
- package/dist/sync/next/test/event-fixtures.js +2 -2
- package/dist/sync/next/test/event-fixtures.js.map +1 -1
- package/dist/sync/sync-backend-kv.d.ts.map +1 -1
- package/dist/sync/sync-backend-kv.js.map +1 -1
- package/dist/sync/sync-backend.d.ts +3 -3
- package/dist/sync/sync-backend.d.ts.map +1 -1
- package/dist/sync/sync-backend.js +1 -1
- package/dist/sync/sync-backend.js.map +1 -1
- package/dist/sync/sync.d.ts +20 -0
- package/dist/sync/sync.d.ts.map +1 -1
- package/dist/sync/syncstate.d.ts +4 -17
- package/dist/sync/syncstate.d.ts.map +1 -1
- package/dist/sync/syncstate.js +51 -74
- package/dist/sync/syncstate.js.map +1 -1
- package/dist/sync/syncstate.test.js +112 -96
- package/dist/sync/syncstate.test.js.map +1 -1
- package/dist/sync/transport-chunking.js +3 -3
- package/dist/sync/transport-chunking.js.map +1 -1
- package/dist/sync/validate-push-payload.d.ts +2 -2
- package/dist/sync/validate-push-payload.d.ts.map +1 -1
- package/dist/sync/validate-push-payload.js +4 -6
- package/dist/sync/validate-push-payload.js.map +1 -1
- package/dist/util.js +2 -2
- package/dist/util.js.map +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +2 -5
- package/dist/version.js.map +1 -1
- package/package.json +66 -12
- package/src/ClientSessionLeaderThreadProxy.ts +9 -9
- package/src/WorkerTransportError.ts +12 -0
- package/src/adapter-types.ts +9 -3
- package/src/bounded-collections.ts +6 -5
- package/src/debug-info.ts +4 -4
- package/src/devtools/devtools-messages-common.ts +1 -1
- package/src/devtools/mod.ts +1 -1
- package/src/errors.ts +18 -17
- package/src/index.ts +2 -0
- package/src/leader-thread/LeaderSyncProcessor.ts +421 -392
- package/src/leader-thread/RejectedPushError.ts +106 -0
- package/src/leader-thread/connection.ts +1 -1
- package/src/leader-thread/eventlog.ts +16 -14
- package/src/leader-thread/leader-worker-devtools.ts +96 -66
- package/src/leader-thread/make-leader-thread-layer.test.ts +1 -1
- package/src/leader-thread/make-leader-thread-layer.ts +33 -31
- package/src/leader-thread/materialize-event.ts +4 -4
- package/src/leader-thread/recreate-db.ts +1 -1
- package/src/leader-thread/shutdown-channel.ts +2 -6
- package/src/leader-thread/stream-events.ts +10 -5
- package/src/leader-thread/types.ts +7 -6
- package/src/logging.ts +4 -4
- package/src/make-client-session.ts +2 -2
- package/src/materializer-helper.ts +9 -9
- package/src/otel.ts +3 -2
- package/src/rematerialize-from-eventlog.ts +60 -60
- package/src/schema/EventDef/define.ts +6 -6
- package/src/schema/EventDef/deprecated.test.ts +2 -1
- package/src/schema/EventDef/deprecated.ts +3 -3
- package/src/schema/EventSequenceNumber/client.ts +11 -11
- package/src/schema/EventSequenceNumber.test.ts +2 -1
- package/src/schema/LiveStoreEvent/client.test.ts +97 -0
- package/src/schema/LiveStoreEvent/client.ts +6 -3
- package/src/schema/schema.ts +9 -4
- package/src/schema/state/sqlite/client-document-def.test.ts +2 -1
- package/src/schema/state/sqlite/client-document-def.ts +20 -6
- package/src/schema/state/sqlite/column-annotations.test.ts +2 -1
- package/src/schema/state/sqlite/column-annotations.ts +2 -1
- package/src/schema/state/sqlite/column-def.test.ts +8 -6
- package/src/schema/state/sqlite/column-def.ts +41 -36
- package/src/schema/state/sqlite/column-spec.test.ts +3 -1
- package/src/schema/state/sqlite/column-spec.ts +9 -8
- package/src/schema/state/sqlite/db-schema/ast/sqlite.ts +2 -2
- package/src/schema/state/sqlite/db-schema/dsl/field-defs.test.ts +2 -1
- package/src/schema/state/sqlite/db-schema/dsl/field-defs.ts +13 -4
- package/src/schema/state/sqlite/db-schema/dsl/mod.ts +3 -3
- package/src/schema/state/sqlite/mod.ts +4 -5
- package/src/schema/state/sqlite/query-builder/api.ts +12 -5
- package/src/schema/state/sqlite/query-builder/astToSql.ts +11 -11
- package/src/schema/state/sqlite/query-builder/impl.test.ts +4 -2
- package/src/schema/state/sqlite/query-builder/impl.ts +26 -12
- package/src/schema/state/sqlite/schema-helpers.ts +2 -2
- package/src/schema/state/sqlite/table-def.test.ts +67 -4
- package/src/schema/state/sqlite/table-def.ts +8 -15
- package/src/schema/unknown-events.ts +2 -2
- package/src/schema-management/__tests__/migrations-autoincrement-quoting.test.ts +3 -1
- package/src/schema-management/common.ts +2 -2
- package/src/schema-management/migrations.ts +1 -1
- package/src/sql-queries/sql-queries.ts +10 -6
- package/src/sql-queries/sql-query-builder.ts +1 -0
- package/src/sqlite-db-helper.ts +3 -3
- package/src/sqlite-types.ts +3 -2
- package/src/sync/ClientSessionSyncProcessor.ts +148 -152
- package/src/sync/errors.ts +10 -22
- package/src/sync/mock-sync-backend.ts +139 -97
- package/src/sync/next/compact-events.ts +5 -5
- package/src/sync/next/facts.ts +7 -6
- package/src/sync/next/history-dag-common.ts +9 -6
- package/src/sync/next/history-dag.ts +3 -3
- package/src/sync/next/rebase-events.ts +1 -1
- package/src/sync/next/test/compact-events.calculator.test.ts +3 -2
- package/src/sync/next/test/compact-events.test.ts +4 -3
- package/src/sync/next/test/event-fixtures.ts +2 -2
- package/src/sync/sync-backend-kv.ts +1 -0
- package/src/sync/sync-backend.ts +5 -4
- package/src/sync/sync.ts +21 -0
- package/src/sync/syncstate.test.ts +513 -435
- package/src/sync/syncstate.ts +80 -86
- package/src/sync/transport-chunking.ts +3 -3
- package/src/sync/validate-push-payload.ts +4 -6
- package/src/util.ts +2 -2
- package/src/version.ts +2 -6
|
@@ -23,7 +23,7 @@ export const findManyRows = <TColumns extends SqliteDsl.Columns>({
|
|
|
23
23
|
}): [string, BindValues] => {
|
|
24
24
|
const whereSql = buildWhereSql({ where })
|
|
25
25
|
const whereModifier = whereSql === '' ? '' : `WHERE ${whereSql}`
|
|
26
|
-
const limitModifier = limit ? `LIMIT ${limit}` : ''
|
|
26
|
+
const limitModifier = limit !== undefined ? `LIMIT ${limit}` : ''
|
|
27
27
|
|
|
28
28
|
const whereBindValues = makeBindValues({ columns, values: where, variablePrefix: 'where_', skipNil: true })
|
|
29
29
|
|
|
@@ -80,7 +80,7 @@ export const insertRowPrepared = <TColumns extends SqliteDsl.Columns>({
|
|
|
80
80
|
const keysStr = keys.join(', ')
|
|
81
81
|
const valuesStr = keys.map((key) => `$${key}`).join(', ')
|
|
82
82
|
|
|
83
|
-
return sql`INSERT ${options.orReplace ? 'OR REPLACE ' : ''}INTO ${tableName} (${keysStr}) VALUES (${valuesStr})`
|
|
83
|
+
return sql`INSERT ${options.orReplace === true ? 'OR REPLACE ' : ''}INTO ${tableName} (${keysStr}) VALUES (${valuesStr})`
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
export const insertRows = <TColumns extends SqliteDsl.Columns>({
|
|
@@ -134,7 +134,7 @@ export const insertOrIgnoreRow = <TColumns extends SqliteDsl.Columns>({
|
|
|
134
134
|
.join(', ')
|
|
135
135
|
|
|
136
136
|
const bindValues = makeBindValues({ columns, values })
|
|
137
|
-
const returningStmt = returnRow ? 'RETURNING *' : ''
|
|
137
|
+
const returningStmt = returnRow === true ? 'RETURNING *' : ''
|
|
138
138
|
|
|
139
139
|
return [sql`INSERT OR IGNORE INTO ${tableName} (${keysStr}) VALUES (${valuesStr}) ${returningStmt}`, bindValues]
|
|
140
140
|
}
|
|
@@ -251,7 +251,7 @@ export const createTable = ({
|
|
|
251
251
|
if (columnDef.default._tag === 'None') return ''
|
|
252
252
|
const defaultValue = columnDef.default.value
|
|
253
253
|
if (typeof defaultValue === 'function') return ''
|
|
254
|
-
if (defaultValue && typeof defaultValue === 'object' && 'sql' in defaultValue) {
|
|
254
|
+
if (defaultValue !== undefined && typeof defaultValue === 'object' && 'sql' in defaultValue) {
|
|
255
255
|
return `DEFAULT ${defaultValue.sql}`
|
|
256
256
|
}
|
|
257
257
|
return `DEFAULT ${defaultValue}`
|
|
@@ -301,7 +301,7 @@ Error: ${parseErrorStr}
|
|
|
301
301
|
Value:`,
|
|
302
302
|
value,
|
|
303
303
|
)
|
|
304
|
-
//
|
|
304
|
+
// oxlint-disable-next-line eslint(no-debugger) -- intentional breakpoint for SQL decode errors
|
|
305
305
|
debugger
|
|
306
306
|
throw res.left
|
|
307
307
|
} else {
|
|
@@ -349,7 +349,11 @@ const buildWhereSql = <TColumns extends SqliteDsl.Columns>({
|
|
|
349
349
|
const getWhereOp = (columnName: string, value: ClientTypes.WhereValueForDecoded<any>) => {
|
|
350
350
|
if (value === null) {
|
|
351
351
|
return `IS NULL`
|
|
352
|
-
} else if (
|
|
352
|
+
} else if (
|
|
353
|
+
typeof value === 'object' &&
|
|
354
|
+
typeof value.op === 'string' &&
|
|
355
|
+
ClientTypes.isValidWhereOp(value.op) === true
|
|
356
|
+
) {
|
|
353
357
|
return `${value.op} $where_${columnName}`
|
|
354
358
|
} else if (typeof value === 'object' && typeof value.op === 'string' && value.op === 'in') {
|
|
355
359
|
return `in (${value.val.map((_: any, i: number) => `$where_${columnName}_${i}`).join(', ')})`
|
package/src/sqlite-db-helper.ts
CHANGED
|
@@ -14,7 +14,7 @@ export const makeExecute = (
|
|
|
14
14
|
return (...args: any[]) => {
|
|
15
15
|
const [queryStrOrQueryBuilder, bindValuesOrOptions, maybeOptions] = args
|
|
16
16
|
|
|
17
|
-
if (isQueryBuilder(queryStrOrQueryBuilder)) {
|
|
17
|
+
if (isQueryBuilder(queryStrOrQueryBuilder) === true) {
|
|
18
18
|
const { query, bindValues } = queryStrOrQueryBuilder.asSql()
|
|
19
19
|
return execute(query, bindValues as unknown as PreparedBindValues, bindValuesOrOptions)
|
|
20
20
|
} else {
|
|
@@ -29,7 +29,7 @@ export const makeSelect = <T>(
|
|
|
29
29
|
return (...args: any[]) => {
|
|
30
30
|
const [queryStrOrQueryBuilder, maybeBindValues] = args
|
|
31
31
|
|
|
32
|
-
if (isQueryBuilder(queryStrOrQueryBuilder)) {
|
|
32
|
+
if (isQueryBuilder(queryStrOrQueryBuilder) === true) {
|
|
33
33
|
const { query, bindValues } = queryStrOrQueryBuilder.asSql()
|
|
34
34
|
const resultSchema = getResultSchema(queryStrOrQueryBuilder)
|
|
35
35
|
const results = select(query, bindValues as unknown as PreparedBindValues)
|
|
@@ -44,7 +44,7 @@ export const validateSnapshot = (snapshot: Uint8Array) => {
|
|
|
44
44
|
const headerBytes = new TextDecoder().decode(snapshot.slice(0, 16))
|
|
45
45
|
const hasValidHeader = headerBytes.startsWith('SQLite format 3')
|
|
46
46
|
|
|
47
|
-
if (
|
|
47
|
+
if (hasValidHeader === false) {
|
|
48
48
|
throw new SqliteError({
|
|
49
49
|
cause: 'Invalid SQLite header',
|
|
50
50
|
note: `Expected header to start with 'SQLite format 3', but got: ${headerBytes}`,
|
package/src/sqlite-types.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Effect, Schema } from '@livestore/utils/effect'
|
|
2
|
+
|
|
2
3
|
import type { SqliteError, UnknownError } from './errors.ts'
|
|
3
4
|
import type { EventSequenceNumber } from './schema/mod.ts'
|
|
4
5
|
import type { QueryBuilder } from './schema/state/sqlite/query-builder/api.ts'
|
|
@@ -17,12 +18,12 @@ export interface SqliteDb<TReq = any, TMetadata extends TReq = TReq> {
|
|
|
17
18
|
prepare(queryStr: string): PreparedStatement
|
|
18
19
|
execute(
|
|
19
20
|
queryStr: string,
|
|
20
|
-
bindValues?: PreparedBindValues
|
|
21
|
+
bindValues?: PreparedBindValues ,
|
|
21
22
|
options?: { onRowsChanged?: (rowsChanged: number) => void },
|
|
22
23
|
): void
|
|
23
24
|
execute(queryBuilder: QueryBuilder.Any, options?: { onRowsChanged?: (rowsChanged: number) => void }): void
|
|
24
25
|
|
|
25
|
-
select<T>(queryStr: string, bindValues?: PreparedBindValues
|
|
26
|
+
select<T>(queryStr: string, bindValues?: PreparedBindValues ): ReadonlyArray<T>
|
|
26
27
|
select<T>(queryBuilder: QueryBuilder<T, any, any>): T
|
|
27
28
|
|
|
28
29
|
export(): Uint8Array<ArrayBuffer>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
|
-
import { LS_DEV,
|
|
2
|
+
import { LS_DEV, TRACE_VERBOSE } from '@livestore/utils'
|
|
3
3
|
import {
|
|
4
4
|
BucketQueue,
|
|
5
5
|
Effect,
|
|
@@ -7,25 +7,22 @@ import {
|
|
|
7
7
|
FiberHandle,
|
|
8
8
|
Option,
|
|
9
9
|
Queue,
|
|
10
|
-
type Runtime,
|
|
11
10
|
Schema,
|
|
12
11
|
type Scope,
|
|
13
12
|
Stream,
|
|
14
13
|
Subscribable,
|
|
15
14
|
} from '@livestore/utils/effect'
|
|
16
|
-
import type * as otel from '@opentelemetry/api'
|
|
17
15
|
|
|
18
|
-
import {
|
|
16
|
+
import type { ClientSession } from '../adapter-types.ts'
|
|
19
17
|
import type { MaterializeError } from '../errors.ts'
|
|
18
|
+
import { isRejectedPushError } from '../leader-thread/RejectedPushError.ts'
|
|
20
19
|
import * as EventSequenceNumber from '../schema/EventSequenceNumber/mod.ts'
|
|
21
20
|
import * as LiveStoreEvent from '../schema/LiveStoreEvent/mod.ts'
|
|
22
21
|
import type { LiveStoreSchema } from '../schema/mod.ts'
|
|
23
22
|
import * as SyncState from './syncstate.ts'
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
// Upstream: https://github.com/Effect-TS/effect/pull/5929
|
|
28
|
-
// TODO: simplify back to the 2-arg overload once the upstream fix is released and adopted.
|
|
24
|
+
/** Serialize value to JSON string for trace attributes */
|
|
25
|
+
const jsonStringify = Schema.encodeSync(Schema.parseJson())
|
|
29
26
|
|
|
30
27
|
/**
|
|
31
28
|
* Rebase behaviour:
|
|
@@ -42,20 +39,17 @@ import * as SyncState from './syncstate.ts'
|
|
|
42
39
|
* - The leader sync processor pulls regular LiveStore events, while the session sync processor pulls SyncState.PayloadUpstream items
|
|
43
40
|
* - The session sync processor has no downstream nodes.
|
|
44
41
|
*/
|
|
45
|
-
export const makeClientSessionSyncProcessor = ({
|
|
42
|
+
export const makeClientSessionSyncProcessor = Effect.fn('makeClientSessionSyncProcessor')(function* ({
|
|
46
43
|
schema,
|
|
47
44
|
clientSession,
|
|
48
|
-
runtime,
|
|
49
45
|
materializeEvent,
|
|
50
46
|
rollback,
|
|
51
47
|
refreshTables,
|
|
52
|
-
span,
|
|
53
48
|
params,
|
|
54
49
|
confirmUnsavedChanges,
|
|
55
50
|
}: {
|
|
56
51
|
schema: LiveStoreSchema
|
|
57
52
|
clientSession: ClientSession
|
|
58
|
-
runtime: Runtime.Runtime<Scope.Scope>
|
|
59
53
|
materializeEvent: (
|
|
60
54
|
eventEncoded: LiveStoreEvent.Client.EncodedWithMeta,
|
|
61
55
|
options: { withChangeset: boolean; materializerHashLeader: Option.Option<number> },
|
|
@@ -72,7 +66,6 @@ export const makeClientSessionSyncProcessor = ({
|
|
|
72
66
|
>
|
|
73
67
|
rollback: (changeset: Uint8Array<ArrayBuffer>) => void
|
|
74
68
|
refreshTables: (tables: Set<string>) => void
|
|
75
|
-
span: otel.Span
|
|
76
69
|
params: {
|
|
77
70
|
leaderPushBatchSize: number
|
|
78
71
|
simulation?: ClientSessionSyncProcessorSimulationParams
|
|
@@ -82,7 +75,7 @@ export const makeClientSessionSyncProcessor = ({
|
|
|
82
75
|
* If true, registers a beforeunload event listener to confirm unsaved changes.
|
|
83
76
|
*/
|
|
84
77
|
confirmUnsavedChanges: boolean
|
|
85
|
-
}): ClientSessionSyncProcessor
|
|
78
|
+
}): Effect.fn.Return<ClientSessionSyncProcessor> {
|
|
86
79
|
const eventSchema = LiveStoreEvent.Client.makeSchemaMemo(schema)
|
|
87
80
|
|
|
88
81
|
const simSleep = <TKey extends keyof ClientSessionSyncProcessorSimulationParams>(
|
|
@@ -101,100 +94,19 @@ export const makeClientSessionSyncProcessor = ({
|
|
|
101
94
|
}
|
|
102
95
|
|
|
103
96
|
/** Only used for debugging / observability / testing, it's not relied upon for correctness of the sync processor. */
|
|
104
|
-
const syncStateUpdateQueue = Queue.unbounded<SyncState.SyncState>()
|
|
97
|
+
const syncStateUpdateQueue = yield* Queue.unbounded<SyncState.SyncState>()
|
|
105
98
|
const isClientEvent = (eventEncoded: LiveStoreEvent.Client.EncodedWithMeta) =>
|
|
106
99
|
schema.eventsDefsMap.get(eventEncoded.name)?.options.clientOnly ?? false
|
|
107
100
|
|
|
108
101
|
/** We're queuing push requests to reduce the number of messages sent to the leader by batching them */
|
|
109
|
-
const leaderPushQueue = BucketQueue.make<LiveStoreEvent.Client.EncodedWithMeta>()
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (eventDef === undefined) {
|
|
118
|
-
return shouldNeverHappen(`No event definition found for \`${name}\`.`)
|
|
119
|
-
}
|
|
120
|
-
const nextNumPair = EventSequenceNumber.Client.nextPair({
|
|
121
|
-
seqNum: baseEventSequenceNumber,
|
|
122
|
-
isClient: eventDef.options.clientOnly,
|
|
123
|
-
rebaseGeneration: baseEventSequenceNumber.rebaseGeneration,
|
|
124
|
-
})
|
|
125
|
-
baseEventSequenceNumber = nextNumPair.seqNum
|
|
126
|
-
return new LiveStoreEvent.Client.EncodedWithMeta(
|
|
127
|
-
Schema.encodeUnknownSync(eventSchema)({
|
|
128
|
-
name,
|
|
129
|
-
args,
|
|
130
|
-
...nextNumPair,
|
|
131
|
-
clientId: clientSession.clientId,
|
|
132
|
-
sessionId: clientSession.sessionId,
|
|
133
|
-
}),
|
|
134
|
-
)
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
const mergeResult = SyncState.merge({
|
|
138
|
-
syncState: syncStateRef.current,
|
|
139
|
-
payload: { _tag: 'local-push', newEvents: encodedEventDefs },
|
|
140
|
-
isClientEvent,
|
|
141
|
-
isEqualEvent: LiveStoreEvent.Client.isEqualEncoded,
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
yield* Effect.annotateCurrentSpan({
|
|
145
|
-
batchSize: encodedEventDefs.length,
|
|
146
|
-
mergeResultTag: mergeResult._tag,
|
|
147
|
-
eventCounts: encodedEventDefs.reduce<Record<string, number>>((acc, event) => {
|
|
148
|
-
acc[event.name] = (acc[event.name] ?? 0) + 1
|
|
149
|
-
return acc
|
|
150
|
-
}, {}),
|
|
151
|
-
...(TRACE_VERBOSE && { mergeResult: JSON.stringify(mergeResult) }),
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
if (mergeResult._tag === 'unknown-error') {
|
|
155
|
-
return shouldNeverHappen('Unknown error in client-session-sync-processor', mergeResult.message)
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (mergeResult._tag !== 'advance') {
|
|
159
|
-
return shouldNeverHappen(`Expected advance, got ${mergeResult._tag}`)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
syncStateRef.current = mergeResult.newSyncState
|
|
163
|
-
yield* syncStateUpdateQueue.offer(mergeResult.newSyncState)
|
|
164
|
-
|
|
165
|
-
// Materialize events to state
|
|
166
|
-
const writeTables = new Set<string>()
|
|
167
|
-
for (const event of mergeResult.newEvents) {
|
|
168
|
-
const {
|
|
169
|
-
writeTables: newWriteTables,
|
|
170
|
-
sessionChangeset,
|
|
171
|
-
materializerHash,
|
|
172
|
-
} = yield* materializeEvent(event, {
|
|
173
|
-
withChangeset: true,
|
|
174
|
-
materializerHashLeader: Option.none(),
|
|
175
|
-
})
|
|
176
|
-
for (const table of newWriteTables) {
|
|
177
|
-
writeTables.add(table)
|
|
178
|
-
}
|
|
179
|
-
event.meta.sessionChangeset = sessionChangeset
|
|
180
|
-
event.meta.materializerHashSession = materializerHash
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Trigger push to leader
|
|
184
|
-
// console.debug('pushToLeader', encodedEventDefs.length, ...encodedEventDefs.map((_) => _.toJSON()))
|
|
185
|
-
yield* BucketQueue.offerAll(leaderPushQueue, encodedEventDefs)
|
|
186
|
-
|
|
187
|
-
return { writeTables }
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
const debugInfo = {
|
|
191
|
-
rebaseCount: 0,
|
|
192
|
-
advanceCount: 0,
|
|
193
|
-
rejectCount: 0,
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const boot: ClientSessionSyncProcessor['boot'] = Effect.gen(function* () {
|
|
197
|
-
if (confirmUnsavedChanges && typeof window !== 'undefined' && typeof window.addEventListener === 'function') {
|
|
102
|
+
const leaderPushQueue = yield* BucketQueue.make<LiveStoreEvent.Client.EncodedWithMeta>()
|
|
103
|
+
|
|
104
|
+
const boot: ClientSessionSyncProcessor['boot'] = Effect.fn('client-session-sync-processor:boot')(function* () {
|
|
105
|
+
if (
|
|
106
|
+
confirmUnsavedChanges === true &&
|
|
107
|
+
typeof window !== 'undefined' &&
|
|
108
|
+
typeof window.addEventListener === 'function'
|
|
109
|
+
) {
|
|
198
110
|
const onBeforeUnload = (event: BeforeUnloadEvent) => {
|
|
199
111
|
if (syncStateRef.current.pending.length > 0) {
|
|
200
112
|
// Trigger the default browser dialog
|
|
@@ -213,12 +125,17 @@ export const makeClientSessionSyncProcessor = ({
|
|
|
213
125
|
const backgroundLeaderPushing = Effect.gen(function* () {
|
|
214
126
|
const batch = yield* BucketQueue.takeBetween(leaderPushQueue, 1, params.leaderPushBatchSize)
|
|
215
127
|
yield* clientSession.leaderThread.events.push(batch).pipe(
|
|
216
|
-
Effect.
|
|
128
|
+
Effect.catchIf(isRejectedPushError, () => {
|
|
217
129
|
debugInfo.rejectCount++
|
|
218
130
|
return BucketQueue.clear(leaderPushQueue)
|
|
219
131
|
}),
|
|
220
132
|
)
|
|
221
|
-
}).pipe(
|
|
133
|
+
}).pipe(
|
|
134
|
+
Effect.forever,
|
|
135
|
+
Effect.interruptible,
|
|
136
|
+
Effect.tapCauseLogPretty,
|
|
137
|
+
Effect.catchAllCause((cause) => clientSession.shutdown(Exit.failCause(cause))),
|
|
138
|
+
)
|
|
222
139
|
|
|
223
140
|
yield* FiberHandle.run(leaderPushingFiberHandle, backgroundLeaderPushing)
|
|
224
141
|
|
|
@@ -230,52 +147,47 @@ export const makeClientSessionSyncProcessor = ({
|
|
|
230
147
|
Effect.gen(function* () {
|
|
231
148
|
// yield* Effect.logDebug('ClientSessionSyncProcessor:pull', payload)
|
|
232
149
|
|
|
233
|
-
if (clientSession.devtools.enabled) {
|
|
150
|
+
if (clientSession.devtools.enabled === true) {
|
|
234
151
|
yield* clientSession.devtools.pullLatch.await
|
|
235
152
|
}
|
|
236
153
|
|
|
237
|
-
const mergeResult = SyncState.merge({
|
|
154
|
+
const mergeResult = yield* SyncState.merge({
|
|
238
155
|
syncState: syncStateRef.current,
|
|
239
156
|
payload,
|
|
240
157
|
isClientEvent,
|
|
241
158
|
isEqualEvent: LiveStoreEvent.Client.isEqualEncoded,
|
|
242
|
-
})
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
159
|
+
}).pipe(
|
|
160
|
+
Effect.filterOrDieMessage(
|
|
161
|
+
(r) => r._tag !== 'reject',
|
|
162
|
+
'Unexpected reject in client-session-sync-processor',
|
|
163
|
+
),
|
|
164
|
+
)
|
|
249
165
|
|
|
250
166
|
syncStateRef.current = mergeResult.newSyncState
|
|
251
167
|
|
|
252
168
|
if (mergeResult._tag === 'rebase') {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
{
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
res: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
|
|
261
|
-
},
|
|
262
|
-
undefined,
|
|
263
|
-
)
|
|
169
|
+
yield* Effect.spanEvent('merge:pull:rebase', {
|
|
170
|
+
payloadTag: payload._tag,
|
|
171
|
+
...(TRACE_VERBOSE === true ? { payload: jsonStringify(payload) } : {}),
|
|
172
|
+
newEventsCount: mergeResult.newEvents.length,
|
|
173
|
+
rollbackCount: mergeResult.rollbackEvents.length,
|
|
174
|
+
...(TRACE_VERBOSE === true ? { res: jsonStringify(mergeResult) } : {}),
|
|
175
|
+
})
|
|
264
176
|
|
|
265
177
|
debugInfo.rebaseCount++
|
|
266
178
|
|
|
267
|
-
if (SIMULATION_ENABLED) yield* simSleep('pull', '1_before_leader_push_fiber_interrupt')
|
|
179
|
+
if (SIMULATION_ENABLED === true) yield* simSleep('pull', '1_before_leader_push_fiber_interrupt')
|
|
268
180
|
|
|
269
181
|
yield* FiberHandle.clear(leaderPushingFiberHandle)
|
|
270
182
|
|
|
271
|
-
if (SIMULATION_ENABLED) yield* simSleep('pull', '2_before_leader_push_queue_clear')
|
|
183
|
+
if (SIMULATION_ENABLED === true) yield* simSleep('pull', '2_before_leader_push_queue_clear')
|
|
272
184
|
|
|
273
185
|
// Reset the leader push queue since we're rebasing and will push again
|
|
274
186
|
yield* BucketQueue.clear(leaderPushQueue)
|
|
275
187
|
|
|
276
|
-
if (SIMULATION_ENABLED) yield* simSleep('pull', '3_before_rebase_rollback')
|
|
188
|
+
if (SIMULATION_ENABLED === true) yield* simSleep('pull', '3_before_rebase_rollback')
|
|
277
189
|
|
|
278
|
-
if (LS_DEV) {
|
|
190
|
+
if (LS_DEV === true) {
|
|
279
191
|
yield* Effect.logDebug(
|
|
280
192
|
'merge:pull:rebase: rollback',
|
|
281
193
|
mergeResult.rollbackEvents.length,
|
|
@@ -291,24 +203,20 @@ export const makeClientSessionSyncProcessor = ({
|
|
|
291
203
|
}
|
|
292
204
|
}
|
|
293
205
|
|
|
294
|
-
if (SIMULATION_ENABLED) yield* simSleep('pull', '4_before_leader_push_queue_offer')
|
|
206
|
+
if (SIMULATION_ENABLED === true) yield* simSleep('pull', '4_before_leader_push_queue_offer')
|
|
295
207
|
|
|
296
208
|
yield* BucketQueue.offerAll(leaderPushQueue, mergeResult.newSyncState.pending)
|
|
297
209
|
|
|
298
|
-
if (SIMULATION_ENABLED) yield* simSleep('pull', '5_before_leader_push_fiber_run')
|
|
210
|
+
if (SIMULATION_ENABLED === true) yield* simSleep('pull', '5_before_leader_push_fiber_run')
|
|
299
211
|
|
|
300
212
|
yield* FiberHandle.run(leaderPushingFiberHandle, backgroundLeaderPushing)
|
|
301
213
|
} else {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
{
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
res: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
|
|
309
|
-
},
|
|
310
|
-
undefined,
|
|
311
|
-
)
|
|
214
|
+
yield* Effect.spanEvent('merge:pull:advance', {
|
|
215
|
+
payloadTag: payload._tag,
|
|
216
|
+
...(TRACE_VERBOSE === true ? { payload: jsonStringify(payload) } : {}),
|
|
217
|
+
newEventsCount: mergeResult.newEvents.length,
|
|
218
|
+
...(TRACE_VERBOSE === true ? { res: jsonStringify(mergeResult) } : {}),
|
|
219
|
+
})
|
|
312
220
|
|
|
313
221
|
debugInfo.advanceCount++
|
|
314
222
|
}
|
|
@@ -353,17 +261,99 @@ export const makeClientSessionSyncProcessor = ({
|
|
|
353
261
|
Effect.tapCauseLogPretty,
|
|
354
262
|
Effect.forkScoped,
|
|
355
263
|
)
|
|
264
|
+
})()
|
|
265
|
+
|
|
266
|
+
const encodeEvents: ClientSessionSyncProcessor['encodeEvents'] = Effect.fn('client-session-sync-processor:encode-events')(function* (
|
|
267
|
+
events,
|
|
268
|
+
) {
|
|
269
|
+
let baseEventSequenceNumber = syncStateRef.current.localHead
|
|
270
|
+
return yield* Effect.forEach(events, ({ name, args }) =>
|
|
271
|
+
Effect.gen(function* () {
|
|
272
|
+
const eventDef = yield* Effect.fromNullable(schema.eventsDefsMap.get(name)).pipe(Effect.orDieDebugger)
|
|
273
|
+
const nextNumPair = EventSequenceNumber.Client.nextPair({
|
|
274
|
+
seqNum: baseEventSequenceNumber,
|
|
275
|
+
isClient: eventDef.options.clientOnly,
|
|
276
|
+
rebaseGeneration: baseEventSequenceNumber.rebaseGeneration,
|
|
277
|
+
})
|
|
278
|
+
baseEventSequenceNumber = nextNumPair.seqNum
|
|
279
|
+
return new LiveStoreEvent.Client.EncodedWithMeta(
|
|
280
|
+
Schema.encodeUnknownSync(eventSchema)({
|
|
281
|
+
name,
|
|
282
|
+
args,
|
|
283
|
+
...nextNumPair,
|
|
284
|
+
clientId: clientSession.clientId,
|
|
285
|
+
sessionId: clientSession.sessionId,
|
|
286
|
+
}),
|
|
287
|
+
)
|
|
288
|
+
}),
|
|
289
|
+
)
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
const materializeEvents: ClientSessionSyncProcessor['materializeEvents'] = Effect.fn('client-session-sync-processor:materialize-events')(function* (
|
|
293
|
+
events,
|
|
294
|
+
) {
|
|
295
|
+
const writeTables = new Set<string>()
|
|
296
|
+
for (const event of events) {
|
|
297
|
+
const {
|
|
298
|
+
writeTables: newWriteTables,
|
|
299
|
+
sessionChangeset,
|
|
300
|
+
materializerHash,
|
|
301
|
+
} = yield* materializeEvent(event, {
|
|
302
|
+
withChangeset: true,
|
|
303
|
+
materializerHashLeader: Option.none(),
|
|
304
|
+
})
|
|
305
|
+
for (const table of newWriteTables) {
|
|
306
|
+
writeTables.add(table)
|
|
307
|
+
}
|
|
308
|
+
event.meta.sessionChangeset = sessionChangeset
|
|
309
|
+
event.meta.materializerHashSession = materializerHash
|
|
310
|
+
}
|
|
311
|
+
return { writeTables }
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
const push: ClientSessionSyncProcessor['push'] = Effect.fn('client-session-sync-processor:push')(function* (
|
|
315
|
+
encodedEvents,
|
|
316
|
+
) {
|
|
317
|
+
const mergeResult = yield* SyncState.merge({
|
|
318
|
+
syncState: syncStateRef.current,
|
|
319
|
+
payload: { _tag: 'local-push', newEvents: encodedEvents },
|
|
320
|
+
isClientEvent,
|
|
321
|
+
isEqualEvent: LiveStoreEvent.Client.isEqualEncoded,
|
|
322
|
+
}).pipe(
|
|
323
|
+
Effect.filterOrDieMessage(
|
|
324
|
+
(r) => r._tag === 'advance',
|
|
325
|
+
'Expected advance from local-push merge',
|
|
326
|
+
),
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
yield* Effect.annotateCurrentSpan({
|
|
330
|
+
batchSize: encodedEvents.length,
|
|
331
|
+
mergeResultTag: mergeResult._tag,
|
|
332
|
+
eventCounts: encodedEvents.reduce<Record<string, number>>((acc, event) => {
|
|
333
|
+
acc[event.name] = (acc[event.name] ?? 0) + 1
|
|
334
|
+
return acc
|
|
335
|
+
}, {}),
|
|
336
|
+
...(TRACE_VERBOSE === true ? { mergeResult: jsonStringify(mergeResult) } : {}),
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
syncStateRef.current = mergeResult.newSyncState
|
|
340
|
+
yield* syncStateUpdateQueue.offer(mergeResult.newSyncState)
|
|
341
|
+
yield* BucketQueue.offerAll(leaderPushQueue, mergeResult.newEvents)
|
|
356
342
|
})
|
|
357
343
|
|
|
344
|
+
const debugInfo = {
|
|
345
|
+
rebaseCount: 0,
|
|
346
|
+
advanceCount: 0,
|
|
347
|
+
rejectCount: 0,
|
|
348
|
+
}
|
|
349
|
+
|
|
358
350
|
return {
|
|
359
|
-
push,
|
|
360
351
|
boot,
|
|
352
|
+
encodeEvents,
|
|
353
|
+
materializeEvents,
|
|
354
|
+
push,
|
|
361
355
|
syncState: Subscribable.make({
|
|
362
|
-
get: Effect.
|
|
363
|
-
const syncState = syncStateRef.current
|
|
364
|
-
if (syncStateRef === undefined) return shouldNeverHappen('Not initialized')
|
|
365
|
-
return syncState
|
|
366
|
-
}),
|
|
356
|
+
get: Effect.sync(() => syncStateRef.current),
|
|
367
357
|
changes: Stream.fromQueue(syncStateUpdateQueue),
|
|
368
358
|
}),
|
|
369
359
|
debug: {
|
|
@@ -378,17 +368,23 @@ export const makeClientSessionSyncProcessor = ({
|
|
|
378
368
|
'pushQueueItems',
|
|
379
369
|
pushQueueItems.map((_) => _.toJSON()),
|
|
380
370
|
)
|
|
381
|
-
}).pipe(Effect.
|
|
371
|
+
}).pipe(Effect.runSync),
|
|
382
372
|
debugInfo: () => debugInfo,
|
|
383
373
|
},
|
|
384
374
|
} satisfies ClientSessionSyncProcessor
|
|
385
|
-
}
|
|
375
|
+
})
|
|
386
376
|
|
|
387
377
|
export interface ClientSessionSyncProcessor {
|
|
378
|
+
boot: Effect.Effect<void, never, Scope.Scope>
|
|
379
|
+
encodeEvents: (
|
|
380
|
+
events: ReadonlyArray<LiveStoreEvent.Input.Decoded>,
|
|
381
|
+
) => Effect.Effect<ReadonlyArray<LiveStoreEvent.Client.EncodedWithMeta>>
|
|
388
382
|
push: (
|
|
389
|
-
|
|
383
|
+
events: ReadonlyArray<LiveStoreEvent.Client.EncodedWithMeta>,
|
|
384
|
+
) => Effect.Effect<void>
|
|
385
|
+
materializeEvents: (
|
|
386
|
+
events: ReadonlyArray<LiveStoreEvent.Client.EncodedWithMeta>,
|
|
390
387
|
) => Effect.Effect<{ writeTables: Set<string> }, MaterializeError>
|
|
391
|
-
boot: Effect.Effect<void, UnknownError, Scope.Scope>
|
|
392
388
|
/**
|
|
393
389
|
* Only used for debugging / observability.
|
|
394
390
|
*/
|
package/src/sync/errors.ts
CHANGED
|
@@ -1,38 +1,26 @@
|
|
|
1
1
|
import { Schema } from '@livestore/utils/effect'
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
import { EventSequenceNumber } from '../schema/mod.ts'
|
|
4
4
|
|
|
5
|
-
export class IsOfflineError extends Schema.TaggedError<IsOfflineError>(
|
|
5
|
+
export class IsOfflineError extends Schema.TaggedError<IsOfflineError>(
|
|
6
|
+
'~@livestore/common/IsOfflineError',
|
|
7
|
+
)('IsOfflineError', {
|
|
6
8
|
cause: Schema.Defect,
|
|
7
9
|
}) {}
|
|
8
10
|
|
|
9
11
|
/** Unique ID generated by the backend when its created. Used to check whether the backend identity has changed. */
|
|
10
12
|
export const BackendId = Schema.String.annotations({ title: '@livestore/sync-cf:BackendId' })
|
|
11
13
|
|
|
12
|
-
export class BackendIdMismatchError extends Schema.TaggedError<BackendIdMismatchError>(
|
|
14
|
+
export class BackendIdMismatchError extends Schema.TaggedError<BackendIdMismatchError>(
|
|
15
|
+
'~@livestore/common/BackendIdMismatchError',
|
|
16
|
+
)('BackendIdMismatchError', {
|
|
13
17
|
expected: BackendId,
|
|
14
18
|
received: BackendId,
|
|
15
19
|
}) {}
|
|
16
20
|
|
|
17
|
-
export class ServerAheadError extends Schema.TaggedError<ServerAheadError>(
|
|
21
|
+
export class ServerAheadError extends Schema.TaggedError<ServerAheadError>(
|
|
22
|
+
'~@livestore/common/ServerAheadError',
|
|
23
|
+
)('ServerAheadError', {
|
|
18
24
|
minimumExpectedNum: EventSequenceNumber.Global.Schema,
|
|
19
25
|
providedNum: EventSequenceNumber.Global.Schema,
|
|
20
26
|
}) {}
|
|
21
|
-
|
|
22
|
-
export class InvalidPushError extends Schema.TaggedError<InvalidPushError>()('InvalidPushError', {
|
|
23
|
-
cause: Schema.Union(UnknownError, ServerAheadError, BackendIdMismatchError),
|
|
24
|
-
}) {}
|
|
25
|
-
|
|
26
|
-
export class InvalidPullError extends Schema.TaggedError<InvalidPullError>()('InvalidPullError', {
|
|
27
|
-
cause: Schema.Defect,
|
|
28
|
-
}) {}
|
|
29
|
-
|
|
30
|
-
export class LeaderAheadError extends Schema.TaggedError<LeaderAheadError>()('LeaderAheadError', {
|
|
31
|
-
minimumExpectedNum: EventSequenceNumber.Client.Composite,
|
|
32
|
-
providedNum: EventSequenceNumber.Client.Composite,
|
|
33
|
-
/** Generation number the client session should use for subsequent pushes */
|
|
34
|
-
// nextGeneration: Schema.Number,
|
|
35
|
-
}) {}
|
|
36
|
-
|
|
37
|
-
export const SyncError = Schema.Union(InvalidPushError, InvalidPullError)
|
|
38
|
-
export type SyncError = typeof SyncError.Type
|