@powersync/nuxt 0.0.0-dev-20260503073249 → 0.0.0-dev-20260630141119

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/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "powersync-nuxt",
3
3
  "configKey": "powersync",
4
- "version": "0.0.6",
4
+ "version": "0.0.7",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
@@ -54,7 +54,7 @@
54
54
  <div flex="~ col gap-2">
55
55
  <span text="sm gray-500">Upload Progress</span>
56
56
  <div flex="~ items-center gap-2">
57
- <span v-if="syncStatus?.dataFlowStatus.uploading">upload in progress...</span>
57
+ <span v-if="syncStatus?.uploading">upload in progress...</span>
58
58
  <span v-else text="sm gray-400">No active upload</span>
59
59
  </div>
60
60
  </div>
@@ -1,11 +1,11 @@
1
- import { type ILogHandler } from '@powersync/web';
1
+ import { type PowerSyncLogger } from '@powersync/common';
2
2
  /**
3
3
  * Provides a logger configured for PowerSync diagnostics.
4
4
  *
5
5
  * This composable creates a logger instance that is automatically configured for diagnostics
6
6
  * recording. The logger stores logs in session storage and emits events for real-time log monitoring.
7
7
  *
8
- * @param customHandler - Optional custom log handler to process log messages
8
+ * @param additional - Optional logger that messages will also be forwarded to.
9
9
  *
10
10
  * @returns An object containing:
11
11
  * - `logger` - The configured ILogHandler instance
@@ -20,8 +20,8 @@ import { type ILogHandler } from '@powersync/web';
20
20
  * // Use it in your PowerSync setup if needed
21
21
  * ```
22
22
  */
23
- export declare const useDiagnosticsLogger: (customHandler?: ILogHandler) => {
24
- logger: import("@powersync/common").GlobalLogger;
23
+ export declare const useDiagnosticsLogger: (additional?: PowerSyncLogger) => {
24
+ logger: PowerSyncLogger;
25
25
  logsStorage: import("unstorage").Storage<import("unstorage").StorageValue>;
26
26
  emitter: import("mitt").Emitter<Record<import("mitt").EventType, unknown>>;
27
27
  };
@@ -1,4 +1,4 @@
1
- import { createBaseLogger, LogLevel } from "@powersync/web";
1
+ import { createConsoleLogger, LogLevels } from "@powersync/common";
2
2
  import { createStorage } from "unstorage";
3
3
  import localStorageDriver from "unstorage/drivers/session-storage";
4
4
  import mitt from "mitt";
@@ -6,28 +6,35 @@ const emitter = mitt();
6
6
  const logsStorage = createStorage({
7
7
  driver: localStorageDriver({ base: "powersync:" })
8
8
  });
9
- export const useDiagnosticsLogger = (customHandler) => {
10
- const logger = createBaseLogger();
11
- const consoleHandler = logger.createDefaultHandler({
12
- formatter: (messages, context) => {
13
- messages.unshift(`[PowerSync]${context.name ? ` [${context.name}]` : ""}`);
9
+ export const useDiagnosticsLogger = (additional) => {
10
+ const consoleLogger = createConsoleLogger({ minLevel: LogLevels.debug });
11
+ const logger = {
12
+ async log(record) {
13
+ consoleLogger.log(record);
14
+ const logObject = {
15
+ date: /* @__PURE__ */ new Date(),
16
+ message: record.message,
17
+ error: record.error,
18
+ level: nameOfLogLevel(record.level)
19
+ };
20
+ const key = `log:${logObject.date.toISOString()}`;
21
+ await logsStorage.set(key, logObject);
22
+ emitter.emit("log", { key, value: logObject });
23
+ additional?.log(record);
14
24
  }
15
- });
16
- logger.setLevel(LogLevel.DEBUG);
17
- logger.setHandler(async (messages, context) => {
18
- consoleHandler(messages, context);
19
- const messageArray = Array.from(messages);
20
- const mainMessage = String(messageArray[0] ?? "Empty log message");
21
- const extra = messageArray.length > 1 ? messageArray.length === 2 ? messageArray[1] : messageArray.slice(1) : void 0;
22
- const logObject = {
23
- date: /* @__PURE__ */ new Date(),
24
- type: context.level.name.toLowerCase(),
25
- args: [mainMessage, extra, context]
26
- };
27
- const key = `log:${logObject.date.toISOString()}`;
28
- await logsStorage.set(key, logObject);
29
- emitter.emit("log", { key, value: logObject });
30
- await customHandler?.(messages, context);
31
- });
25
+ };
32
26
  return { logger, logsStorage, emitter };
33
27
  };
28
+ const levelNames = [
29
+ ["ERROR", LogLevels.error],
30
+ ["WARNING", LogLevels.warn],
31
+ ["INFO", LogLevels.info],
32
+ ["DEBUG", LogLevels.debug],
33
+ ["TRACE", LogLevels.trace]
34
+ ];
35
+ function nameOfLogLevel(level) {
36
+ for (const [name, minLevel] of levelNames) {
37
+ if (level >= minLevel) return name;
38
+ }
39
+ return void 0;
40
+ }
@@ -1,4 +1,3 @@
1
- import { RecordingStorageAdapter } from '../utils/RecordingStorageAdapter.js';
2
1
  import { DynamicSchemaManager } from '../utils/DynamicSchemaManager.js';
3
2
  declare function getCurrentSchemaManager(): DynamicSchemaManager;
4
3
  /**
@@ -9,7 +8,6 @@ declare function getCurrentSchemaManager(): DynamicSchemaManager;
9
8
  *
10
9
  * @returns An object containing:
11
10
  * - `diagnosticsSchema` - The schema for diagnostics data collection. Use this to extend your app schema with diagnostic tables.
12
- * - `RecordingStorageAdapter` - Used internally. Storage adapter class that records operations for diagnostic purposes.
13
11
  * - `getCurrentSchemaManager()` - Used internally. Gets the current schema manager instance for dynamic schema operations.
14
12
  *
15
13
  * @example
@@ -36,7 +34,6 @@ export declare function usePowerSyncInspector(): {
36
34
  data: import("@powersync/common").BaseColumnType<string | null>;
37
35
  }>;
38
36
  }>;
39
- RecordingStorageAdapter: typeof RecordingStorageAdapter;
40
37
  getCurrentSchemaManager: typeof getCurrentSchemaManager;
41
38
  };
42
39
  export {};
@@ -1,5 +1,4 @@
1
1
  import { DiagnosticsAppSchema } from "../utils/AppSchema.js";
2
- import { RecordingStorageAdapter } from "../utils/RecordingStorageAdapter.js";
3
2
  import { DynamicSchemaManager } from "../utils/DynamicSchemaManager.js";
4
3
  let currentSchemaManager = null;
5
4
  function getCurrentSchemaManager() {
@@ -13,7 +12,6 @@ export function usePowerSyncInspector() {
13
12
  const diagnosticsSchema = DiagnosticsAppSchema;
14
13
  return {
15
14
  diagnosticsSchema,
16
- RecordingStorageAdapter,
17
15
  getCurrentSchemaManager
18
16
  };
19
17
  }
@@ -1,4 +1,4 @@
1
- import type { AbstractPowerSyncDatabase, PowerSyncBackendConnector, PowerSyncConnectionOptions, SyncStatus, UploadQueueStats } from '@powersync/web';
1
+ import type { CommonPowerSyncDatabase, PowerSyncBackendConnector, SyncOptions, SyncStatus, UploadQueueStats } from '@powersync/common';
2
2
  import type { ComputedRef, Ref } from 'vue';
3
3
  export type BucketRow = {
4
4
  name: string;
@@ -33,9 +33,9 @@ type ReadonlyRef<T> = Readonly<Ref<T>>;
33
33
  * Uses named types so the signature stays readable in docs and IDE.
34
34
  */
35
35
  export interface UsePowerSyncInspectorDiagnosticsReturn {
36
- db: Ref<AbstractPowerSyncDatabase> | undefined;
36
+ db: Ref<CommonPowerSyncDatabase> | undefined;
37
37
  connector: ComputedRef<PowerSyncBackendConnector | null>;
38
- connectionOptions: ComputedRef<PowerSyncConnectionOptions | null>;
38
+ connectionOptions: ComputedRef<SyncOptions | null>;
39
39
  isDiagnosticSchemaSetup: ReadonlyRef<boolean>;
40
40
  /** Current sync status. Typed as SyncStatus for a concise doc signature; at runtime it may be a readonly proxy. */
41
41
  syncStatus: ReadonlyRef<SyncStatus>;
@@ -73,12 +73,12 @@ export function usePowerSyncInspectorDiagnostics() {
73
73
  const hasSynced = ref(syncStatus.value?.hasSynced || false);
74
74
  const isConnected = ref(syncStatus.value?.connected || false);
75
75
  const isSyncing = ref(false);
76
- const isDownloading = ref(syncStatus.value?.dataFlowStatus.downloading || false);
77
- const isUploading = ref(syncStatus.value?.dataFlowStatus.uploading || false);
76
+ const isDownloading = ref(syncStatus.value?.downloading || false);
77
+ const isUploading = ref(syncStatus.value?.uploading || false);
78
78
  const lastSyncedAt = ref(syncStatus.value?.lastSyncedAt || null);
79
- const uploadError = ref(syncStatus.value?.dataFlowStatus.uploadError || null);
80
- const downloadError = ref(syncStatus.value?.dataFlowStatus.downloadError || null);
81
- const downloadProgressDetails = ref(syncStatus.value?.dataFlowStatus.downloadProgress || null);
79
+ const uploadError = ref(syncStatus.value?.uploadError || null);
80
+ const downloadError = ref(syncStatus.value?.downloadError || null);
81
+ const downloadProgressDetails = ref(syncStatus.value?.downloadProgress || null);
82
82
  const bucketRows = ref(null);
83
83
  const tableRows = ref(null);
84
84
  const uploadQueueStats = ref(null);
@@ -111,7 +111,7 @@ export function usePowerSyncInspectorDiagnostics() {
111
111
  const uploadQueueSize = computed(() => formatBytes(uploadQueueStats.value?.size ?? 0));
112
112
  const uploadQueueCount = computed(() => uploadQueueStats.value?.count ?? 0);
113
113
  const clearData = async () => {
114
- await db.value?.syncStreamImplementation?.disconnect();
114
+ await db.value?.disconnect();
115
115
  const connector2 = db.value.connector;
116
116
  const connectionOptions2 = db.value.connectionOptions;
117
117
  await db.value?.disconnectAndClear();
@@ -126,7 +126,7 @@ export function usePowerSyncInspectorDiagnostics() {
126
126
  "SELECT powersync_last_synced_at() as synced_at"
127
127
  );
128
128
  uploadQueueStats.value = await db.value?.getUploadQueueStats(true);
129
- if (synced_at != null && !syncStatus.value?.dataFlowStatus.downloading) {
129
+ if (synced_at != null && !syncStatus.value?.downloading) {
130
130
  bucketRows.value = await db.value.getAll(BUCKETS_QUERY);
131
131
  tableRows.value = await db.value.getAll(TABLES_QUERY);
132
132
  } else if (synced_at != null) {
@@ -146,16 +146,16 @@ export function usePowerSyncInspectorDiagnostics() {
146
146
  statusChanged: (newStatus) => {
147
147
  hasSynced.value = !!newStatus.hasSynced;
148
148
  isConnected.value = !!newStatus.connected;
149
- isDownloading.value = !!newStatus.dataFlowStatus.downloading;
150
- isUploading.value = !!newStatus.dataFlowStatus.uploading;
149
+ isDownloading.value = !!newStatus.downloading;
150
+ isUploading.value = !!newStatus.uploading;
151
151
  lastSyncedAt.value = newStatus.lastSyncedAt || null;
152
- uploadError.value = newStatus.dataFlowStatus.uploadError || null;
153
- downloadError.value = newStatus.dataFlowStatus.downloadError || null;
154
- downloadProgressDetails.value = newStatus.dataFlowStatus.downloadProgress || null;
152
+ uploadError.value = newStatus.uploadError || null;
153
+ downloadError.value = newStatus.downloadError || null;
154
+ downloadProgressDetails.value = newStatus.downloadProgress || null;
155
155
  if (newStatus?.hasSynced === void 0 || newStatus?.priorityStatusEntries?.length && newStatus.priorityStatusEntries.length > 0) {
156
156
  hasSynced.value = newStatus?.priorityStatusEntries.every((entry) => entry.hasSynced) ?? false;
157
157
  }
158
- if (newStatus?.dataFlowStatus.downloading || newStatus?.dataFlowStatus.uploading) {
158
+ if (newStatus?.downloading || newStatus?.uploading) {
159
159
  isSyncing.value = true;
160
160
  } else {
161
161
  isSyncing.value = false;
@@ -169,7 +169,6 @@ export function usePowerSyncInspectorDiagnostics() {
169
169
  }
170
170
  },
171
171
  {
172
- rawTableNames: true,
173
172
  tables: ["ps_oplog", "ps_buckets", "ps_data_local__local_bucket_data", "ps_crud"],
174
173
  throttleMs: 500
175
174
  }
@@ -1,5 +1,6 @@
1
- import type { DBAdapter, SyncDataBatch } from '@powersync/web';
1
+ import type { DBAdapter } from '@powersync/web';
2
2
  import { Schema } from '@powersync/web';
3
+ import type { SyncDataBucketJSON } from '@powersync/shared-internals/internal/sync_protocol';
3
4
  /**
4
5
  * Record fields from downloaded data, then build a schema from it.
5
6
  */
@@ -8,7 +9,7 @@ export declare class DynamicSchemaManager {
8
9
  private dirty;
9
10
  constructor();
10
11
  clear(): Promise<void>;
11
- updateFromOperations(batch: SyncDataBatch): Promise<void>;
12
+ updateFromOperations(batch: SyncDataBucketJSON): Promise<void>;
12
13
  refreshSchema(db: DBAdapter): Promise<void>;
13
14
  buildSchema(): Schema;
14
15
  schemaToString(): string;
@@ -1,4 +1,4 @@
1
- import { Column, ColumnType, OpTypeEnum, Schema, Table } from "@powersync/web";
1
+ import { Column, ColumnType, ResolvedTable, Schema } from "@powersync/web";
2
2
  import { DiagnosticsAppSchema as AppSchema } from "./AppSchema.js";
3
3
  import { JsSchemaGenerator } from "./JsSchemaGenerator.js";
4
4
  export class DynamicSchemaManager {
@@ -15,34 +15,32 @@ export class DynamicSchemaManager {
15
15
  }
16
16
  async updateFromOperations(batch) {
17
17
  let schemaDirty = false;
18
- for (const bucket of batch.buckets) {
19
- for (const op of bucket.data) {
20
- if (op.op.value == OpTypeEnum.PUT && op.data != null) {
21
- this.tables[op.object_type] ??= {};
22
- const table = this.tables[op.object_type];
23
- const data = JSON.parse(op.data);
24
- for (const [key, value] of Object.entries(data)) {
25
- if (key == "id") {
26
- continue;
27
- }
28
- if (table) {
29
- const existing = table[key];
30
- if (typeof value == "number" && Number.isInteger(value) && existing != ColumnType.REAL && existing != ColumnType.TEXT) {
31
- if (table[key] != ColumnType.INTEGER) {
32
- schemaDirty = true;
33
- }
34
- table[key] = ColumnType.INTEGER;
35
- } else if (typeof value == "number" && existing != ColumnType.TEXT) {
36
- if (table[key] != ColumnType.REAL) {
37
- schemaDirty = true;
38
- }
39
- table[key] = ColumnType.REAL;
40
- } else if (typeof value == "string") {
41
- if (table[key] != ColumnType.TEXT) {
42
- schemaDirty = true;
43
- }
44
- table[key] = ColumnType.TEXT;
18
+ for (const op of batch.data) {
19
+ if (op.op == "PUT" && op.data != null) {
20
+ this.tables[op.object_type] ??= {};
21
+ const table = this.tables[op.object_type];
22
+ const data = JSON.parse(op.data);
23
+ for (const [key, value] of Object.entries(data)) {
24
+ if (key == "id") {
25
+ continue;
26
+ }
27
+ if (table) {
28
+ const existing = table[key];
29
+ if (typeof value == "number" && Number.isInteger(value) && existing != ColumnType.REAL && existing != ColumnType.TEXT) {
30
+ if (table[key] != ColumnType.INTEGER) {
31
+ schemaDirty = true;
32
+ }
33
+ table[key] = ColumnType.INTEGER;
34
+ } else if (typeof value == "number" && existing != ColumnType.TEXT) {
35
+ if (table[key] != ColumnType.REAL) {
36
+ schemaDirty = true;
37
+ }
38
+ table[key] = ColumnType.REAL;
39
+ } else if (typeof value == "string") {
40
+ if (table[key] != ColumnType.TEXT) {
41
+ schemaDirty = true;
45
42
  }
43
+ table[key] = ColumnType.TEXT;
46
44
  }
47
45
  }
48
46
  }
@@ -64,7 +62,7 @@ export class DynamicSchemaManager {
64
62
  const base = AppSchema;
65
63
  const tables = [...base.tables];
66
64
  for (const [key, value] of Object.entries(this.tables)) {
67
- const table = new Table({
65
+ const table = new ResolvedTable({
68
66
  name: key,
69
67
  columns: Object.entries(value).map(
70
68
  ([cname, ctype]) => new Column({
@@ -1,4 +1,17 @@
1
- import { PowerSyncDatabase, type DisconnectAndClearOptions, type PowerSyncBackendConnector, type PowerSyncConnectionOptions, type RequiredAdditionalConnectionOptions, type StreamingSyncImplementation, type WebPowerSyncDatabaseOptions } from '@powersync/web';
1
+ import { WebPowerSyncDatabase, type DisconnectAndClearOptions, type PowerSyncBackendConnector, type WebPowerSyncDatabaseOptions, type SyncOptions, type CommonPowerSyncDatabase, type PowerSyncDatabaseConstructor } from '@powersync/web';
2
+ import { type StreamingSyncImplementation, type CreateSyncImplementationOptions } from '@powersync/shared-internals';
3
+ export declare class NuxtDatabaseImplementation extends WebPowerSyncDatabase {
4
+ private schemaManager;
5
+ private _connector;
6
+ private useDiagnostics;
7
+ get dbOptions(): WebPowerSyncDatabaseOptions;
8
+ get connector(): PowerSyncBackendConnector | null;
9
+ constructor(options: WebPowerSyncDatabaseOptions);
10
+ protected generateSyncStreamImplementation(connector: PowerSyncBackendConnector, options: CreateSyncImplementationOptions): StreamingSyncImplementation;
11
+ connect(connector: PowerSyncBackendConnector, options?: SyncOptions): Promise<void>;
12
+ disconnect(): Promise<void>;
13
+ disconnectAndClear(options?: DisconnectAndClearOptions): Promise<void>;
14
+ }
2
15
  /**
3
16
  * An extended PowerSync database class that includes diagnostic capabilities for use with the PowerSync Inspector.
4
17
  *
@@ -24,17 +37,6 @@ import { PowerSyncDatabase, type DisconnectAndClearOptions, type PowerSyncBacken
24
37
  * - Automatically configures logging when diagnostics are enabled
25
38
  * - When diagnostics are disabled, behaves like a standard `PowerSyncDatabase`
26
39
  */
27
- export declare class NuxtPowerSyncDatabase extends PowerSyncDatabase {
28
- private schemaManager;
29
- private _connector;
30
- private _connectionOptions;
31
- private useDiagnostics;
32
- get dbOptions(): WebPowerSyncDatabaseOptions;
33
- get connector(): PowerSyncBackendConnector | null;
34
- get connectionOptions(): PowerSyncConnectionOptions | null;
35
- constructor(options: WebPowerSyncDatabaseOptions);
36
- protected generateSyncStreamImplementation(connector: PowerSyncBackendConnector, options: RequiredAdditionalConnectionOptions): StreamingSyncImplementation;
37
- connect(connector: PowerSyncBackendConnector, options?: PowerSyncConnectionOptions): Promise<void>;
38
- disconnect(): Promise<void>;
39
- disconnectAndClear(options?: DisconnectAndClearOptions): Promise<void>;
40
+ export declare const NuxtPowerSyncDatabase: PowerSyncDatabaseConstructor<WebPowerSyncDatabaseOptions>;
41
+ export interface NuxtPowerSyncDatabase extends CommonPowerSyncDatabase {
40
42
  }
@@ -1,22 +1,19 @@
1
1
  import {
2
- DEFAULT_SYNC_CLIENT_IMPLEMENTATION,
3
- PowerSyncDatabase,
2
+ WebPowerSyncDatabase,
4
3
  Schema,
5
4
  SharedWebStreamingSyncImplementation,
6
- SyncClientImplementation,
7
5
  WebRemote,
8
- WebStreamingSyncImplementation
6
+ WebStreamingSyncImplementation,
7
+ LogLevels
9
8
  } from "@powersync/web";
10
- import { RecordingStorageAdapter } from "./RecordingStorageAdapter.js";
11
9
  import { usePowerSyncInspector } from "../composables/usePowerSyncInspector.js";
12
10
  import { useDiagnosticsLogger } from "../composables/useDiagnosticsLogger.js";
13
11
  import { shallowRef } from "vue";
14
12
  import { useRuntimeConfig } from "#app";
15
13
  import { RustClientInterceptor } from "./RustClientInterceptor.js";
16
- export class NuxtPowerSyncDatabase extends PowerSyncDatabase {
14
+ export class NuxtDatabaseImplementation extends WebPowerSyncDatabase {
17
15
  schemaManager;
18
16
  _connector = null;
19
- _connectionOptions = null;
20
17
  useDiagnostics = false;
21
18
  get dbOptions() {
22
19
  return this.options;
@@ -24,20 +21,16 @@ export class NuxtPowerSyncDatabase extends PowerSyncDatabase {
24
21
  get connector() {
25
22
  return this._connector ?? super.connector;
26
23
  }
27
- get connectionOptions() {
28
- return this._connectionOptions ?? super.connectionOptions;
29
- }
30
24
  constructor(options) {
31
25
  const useDiagnostics = useRuntimeConfig().public.powerSyncModuleOptions.useDiagnostics ?? false;
32
26
  if (useDiagnostics) {
33
27
  const { logger } = useDiagnosticsLogger();
34
28
  const { getCurrentSchemaManager, diagnosticsSchema } = usePowerSyncInspector();
35
29
  const currentSchemaManager = getCurrentSchemaManager();
36
- options.flags = {
37
- ...options.flags,
38
- enableMultiTabs: true,
39
- broadcastLogs: true
40
- };
30
+ if ("database" in options) {
31
+ options.database.enableMultiTabs = true;
32
+ options.broadcastLogs = true;
33
+ }
41
34
  options.logger = logger;
42
35
  options.schema = new Schema([...options.schema.tables, ...diagnosticsSchema.tables]);
43
36
  super(options);
@@ -54,22 +47,17 @@ export class NuxtPowerSyncDatabase extends PowerSyncDatabase {
54
47
  const { getCurrentSchemaManager } = usePowerSyncInspector();
55
48
  const currentSchemaManager = getCurrentSchemaManager();
56
49
  const schemaManager = currentSchemaManager || this.schemaManager;
57
- const clientImplementation = this.connectionOptions?.clientImplementation ?? DEFAULT_SYNC_CLIENT_IMPLEMENTATION;
58
- const adapter = clientImplementation === SyncClientImplementation.RUST ? new RustClientInterceptor(
59
- shallowRef(this),
60
- new WebRemote(connector, logger),
61
- shallowRef(schemaManager)
62
- ) : new RecordingStorageAdapter(
50
+ const adapter = new RustClientInterceptor(
63
51
  shallowRef(this),
64
52
  shallowRef(schemaManager)
65
53
  );
66
- if (this.options.flags?.enableMultiTabs) {
67
- if (!this.resolvedFlags.broadcastLogs) {
54
+ if (this.resolvedOpenOptions.enableMultiTabs) {
55
+ if (!this.enableBroadcastLogs) {
68
56
  const warning = `
69
57
  Multiple tabs are enabled, but broadcasting of logs is disabled.
70
58
  Logs for shared sync worker will only be available in the shared worker context
71
59
  `;
72
- logger ? logger.warn(warning) : console.warn(warning);
60
+ logger ? logger.log({ level: LogLevels.warn, message: warning }) : console.warn(warning);
73
61
  }
74
62
  return new SharedWebStreamingSyncImplementation({
75
63
  ...options,
@@ -80,7 +68,9 @@ export class NuxtPowerSyncDatabase extends PowerSyncDatabase {
80
68
  await connector.uploadData(this);
81
69
  },
82
70
  logger,
83
- db: this.database
71
+ db: this.database,
72
+ logLevel: this.resolvedOpenOptions.databaseWorkerLogLevel ?? LogLevels.info,
73
+ enableBroadcastLogs: this.enableBroadcastLogs
84
74
  });
85
75
  } else {
86
76
  return new WebStreamingSyncImplementation({
@@ -91,7 +81,7 @@ export class NuxtPowerSyncDatabase extends PowerSyncDatabase {
91
81
  await this.waitForReady();
92
82
  await connector.uploadData(this);
93
83
  },
94
- identifier: "dbFilename" in this.options.database ? this.options.database.dbFilename : "diagnostics-sync",
84
+ identifier: "database" in this.options ? this.options.database.dbFilename : "diagnostics-sync",
95
85
  logger
96
86
  });
97
87
  }
@@ -101,17 +91,15 @@ export class NuxtPowerSyncDatabase extends PowerSyncDatabase {
101
91
  }
102
92
  async connect(connector, options) {
103
93
  this._connector = connector;
104
- this._connectionOptions = options ?? null;
105
94
  await super.connect(connector, options);
106
95
  }
107
96
  async disconnect() {
108
97
  this._connector = null;
109
- this._connectionOptions = null;
110
98
  await super.disconnect();
111
99
  }
112
100
  async disconnectAndClear(options) {
113
101
  this._connector = null;
114
- this._connectionOptions = null;
115
102
  await super.disconnectAndClear(options);
116
103
  }
117
104
  }
105
+ export const NuxtPowerSyncDatabase = NuxtDatabaseImplementation;
@@ -1,5 +1,5 @@
1
- import type { AbstractRemote, ColumnType, PowerSyncDatabase } from '@powersync/web';
2
- import { PowerSyncControlCommand, SqliteBucketStorage } from '@powersync/web';
1
+ import type { ColumnType, PowerSyncDatabase } from '@powersync/web';
2
+ import { PowerSyncControlCommand, SqliteBucketStorage } from '@powersync/shared-internals';
3
3
  import type { DynamicSchemaManager } from './DynamicSchemaManager.js';
4
4
  import type { ShallowRef } from 'vue';
5
5
  /**
@@ -10,12 +10,12 @@ import type { ShallowRef } from 'vue';
10
10
  * `powersync_control` calls to decode sync lines and derive progress information.
11
11
  */
12
12
  export declare class RustClientInterceptor extends SqliteBucketStorage {
13
- private remote;
14
13
  private schemaManager;
14
+ private bson?;
15
15
  private rdb;
16
16
  private lastStartedCheckpoint;
17
17
  tables: Record<string, Record<string, ColumnType>>;
18
- constructor(db: ShallowRef<PowerSyncDatabase>, remote: AbstractRemote, schemaManager: ShallowRef<DynamicSchemaManager>);
18
+ constructor(db: ShallowRef<PowerSyncDatabase>, schemaManager: ShallowRef<DynamicSchemaManager>);
19
19
  control(op: PowerSyncControlCommand, payload: string | Uint8Array | ArrayBuffer | null): Promise<string>;
20
20
  private processTextLine;
21
21
  private processBinaryLine;
@@ -1,21 +1,11 @@
1
- import {
2
- AbstractPowerSyncDatabase,
3
- isStreamingSyncCheckpoint,
4
- isStreamingSyncCheckpointComplete,
5
- isStreamingSyncCheckpointDiff,
6
- isStreamingSyncCheckpointPartiallyComplete,
7
- isStreamingSyncData,
8
- PowerSyncControlCommand,
9
- SqliteBucketStorage,
10
- SyncDataBucket
11
- } from "@powersync/web";
1
+ import { BasePowerSyncDatabase, PowerSyncControlCommand, SqliteBucketStorage } from "@powersync/shared-internals";
12
2
  export class RustClientInterceptor extends SqliteBucketStorage {
13
- constructor(db, remote, schemaManager) {
14
- super(db.value.database, AbstractPowerSyncDatabase.transactionMutex);
15
- this.remote = remote;
3
+ constructor(db, schemaManager) {
4
+ super(db.value.database, BasePowerSyncDatabase.transactionMutex);
16
5
  this.schemaManager = schemaManager;
17
6
  this.rdb = db.value.database;
18
7
  }
8
+ bson;
19
9
  rdb;
20
10
  lastStartedCheckpoint = null;
21
11
  tables = {};
@@ -32,14 +22,14 @@ export class RustClientInterceptor extends SqliteBucketStorage {
32
22
  return this.processParsedLine(JSON.parse(line));
33
23
  }
34
24
  async processBinaryLine(line) {
35
- const bson = await this.remote.getBSON();
25
+ const bson = this.bson ??= await import("bson");
36
26
  await this.processParsedLine(bson.deserialize(line));
37
27
  }
38
28
  async processParsedLine(line) {
39
- if (isStreamingSyncCheckpoint(line)) {
29
+ if ("checkpoint" in line) {
40
30
  this.lastStartedCheckpoint = line.checkpoint;
41
31
  await this.trackCheckpoint(line.checkpoint);
42
- } else if (isStreamingSyncCheckpointDiff(line) && this.lastStartedCheckpoint) {
32
+ } else if ("checkpoint_diff" in line && this.lastStartedCheckpoint) {
43
33
  const diff = line.checkpoint_diff;
44
34
  const newBuckets = /* @__PURE__ */ new Map();
45
35
  for (const checksum of this.lastStartedCheckpoint.buckets) {
@@ -58,24 +48,22 @@ export class RustClientInterceptor extends SqliteBucketStorage {
58
48
  };
59
49
  this.lastStartedCheckpoint = newCheckpoint;
60
50
  await this.trackCheckpoint(newCheckpoint);
61
- } else if (isStreamingSyncData(line)) {
62
- const batch = { buckets: [SyncDataBucket.fromRow(line.data)] };
51
+ } else if ("data" in line) {
52
+ const bucket = line.data;
63
53
  await this.rdb.writeTransaction(async (tx) => {
64
- for (const bucket of batch.buckets) {
65
- const size = JSON.stringify(bucket.data).length;
66
- await tx.execute(
67
- `UPDATE local_bucket_data SET
54
+ const size = JSON.stringify(bucket.data).length;
55
+ await tx.execute(
56
+ `UPDATE local_bucket_data SET
68
57
  download_size = IFNULL(download_size, 0) + ?,
69
58
  last_op = ?,
70
59
  downloading = ?,
71
60
  downloaded_operations = IFNULL(downloaded_operations, 0) + ?
72
61
  WHERE id = ?`,
73
- [size, bucket.next_after, bucket.has_more, bucket.data.length, bucket.bucket]
74
- );
75
- }
62
+ [size, bucket.next_after, bucket.has_more, bucket.data.length, bucket.bucket]
63
+ );
76
64
  });
77
- await this.schemaManager.value.updateFromOperations(batch);
78
- } else if (isStreamingSyncCheckpointPartiallyComplete(line) || isStreamingSyncCheckpointComplete(line)) {
65
+ await this.schemaManager.value.updateFromOperations(bucket);
66
+ } else if ("partial_checkpoint_complete" in line || "checkpoint_complete" in line) {
79
67
  setTimeout(() => {
80
68
  this.schemaManager.value.refreshSchema(this.rdb);
81
69
  }, 60);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@powersync/nuxt",
3
- "version": "0.0.0-dev-20260503073249",
3
+ "version": "0.0.0-dev-20260630141119",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"
@@ -48,13 +48,15 @@
48
48
  "reka-ui": "^2.9.1",
49
49
  "shiki": "^3.23.0",
50
50
  "unocss": "^66.6.6",
51
- "unstorage": "^1.17.4"
51
+ "unstorage": "^1.17.4",
52
+ "bson": "^6.10.4"
52
53
  },
53
54
  "peerDependencies": {
54
55
  "@journeyapps/wa-sqlite": "^1.7.0",
55
- "@powersync/kysely-driver": "1.3.3",
56
- "@powersync/vue": "0.5.1",
57
- "@powersync/web": "0.0.0-dev-20260503073249"
56
+ "@powersync/kysely-driver": "0.0.0-dev-20260630141119",
57
+ "@powersync/vue": "0.0.0-dev-20260630141119",
58
+ "@powersync/web": "0.0.0-dev-20260630141119",
59
+ "@powersync/shared-internals": "1.0.0"
58
60
  },
59
61
  "peerDependenciesMeta": {
60
62
  "@powersync/kysely-driver": {
@@ -65,16 +67,16 @@
65
67
  "@journeyapps/wa-sqlite": "^1.7.0",
66
68
  "@nuxt/module-builder": "^1.0.2",
67
69
  "@nuxt/schema": "^4.3.1",
68
- "@nuxt/test-utils": "^4.0.0",
69
- "bson": "^6.10.4",
70
+ "@nuxt/test-utils": "^4.0.3",
70
71
  "comlink": "^4.4.2",
71
72
  "nuxt": "^4.3.1",
72
- "vitest": "^3.2.4",
73
+ "vitest": "^4.1.8",
73
74
  "vue": "^3.5.30",
74
75
  "vue-tsc": "^3.2.5",
75
- "@powersync/vue": "0.5.1",
76
- "@powersync/kysely-driver": "1.3.3",
77
- "@powersync/web": "0.0.0-dev-20260503073249"
76
+ "@powersync/kysely-driver": "0.0.0-dev-20260630141119",
77
+ "@powersync/vue": "0.0.0-dev-20260630141119",
78
+ "@powersync/web": "0.0.0-dev-20260630141119",
79
+ "@powersync/common": "0.0.0-dev-20260630141119"
78
80
  },
79
81
  "scripts": {
80
82
  "prebuild": "nuxt-module-build prepare",
@@ -1,13 +0,0 @@
1
- import type { Checkpoint, ColumnType, PowerSyncDatabase, SyncDataBatch } from '@powersync/web';
2
- import { SqliteBucketStorage } from '@powersync/web';
3
- import type { DynamicSchemaManager } from './DynamicSchemaManager.js';
4
- import type { ShallowRef } from 'vue';
5
- export declare class RecordingStorageAdapter extends SqliteBucketStorage {
6
- private rdb;
7
- private schemaManager;
8
- tables: Record<string, Record<string, ColumnType>>;
9
- constructor(db: ShallowRef<PowerSyncDatabase>, schemaManager: ShallowRef<DynamicSchemaManager>);
10
- setTargetCheckpoint(checkpoint: Checkpoint): Promise<void>;
11
- syncLocalDatabase(checkpoint: Checkpoint, priority?: number): Promise<import("@powersync/common").SyncLocalDatabaseResult>;
12
- saveSyncData(batch: SyncDataBatch): Promise<void>;
13
- }
@@ -1,58 +0,0 @@
1
- import { AbstractPowerSyncDatabase, SqliteBucketStorage } from "@powersync/web";
2
- export class RecordingStorageAdapter extends SqliteBucketStorage {
3
- rdb;
4
- schemaManager;
5
- tables = {};
6
- constructor(db, schemaManager) {
7
- super(db.value.database, AbstractPowerSyncDatabase.transactionMutex);
8
- this.rdb = db.value.database;
9
- this.schemaManager = schemaManager.value;
10
- }
11
- async setTargetCheckpoint(checkpoint) {
12
- await super.setTargetCheckpoint(checkpoint);
13
- await this.rdb.writeTransaction(async (tx) => {
14
- for (const bucket of checkpoint.buckets) {
15
- await tx.execute(
16
- `INSERT OR REPLACE INTO local_bucket_data(id, total_operations, last_op, download_size, downloading, downloaded_operations)
17
- VALUES (
18
- ?,
19
- ?,
20
- IFNULL((SELECT last_op FROM local_bucket_data WHERE id = ?), '0'),
21
- IFNULL((SELECT download_size FROM local_bucket_data WHERE id = ?), 0),
22
- IFNULL((SELECT downloading FROM local_bucket_data WHERE id = ?), TRUE),
23
- IFNULL((SELECT downloaded_operations FROM local_bucket_data WHERE id = ?), TRUE)
24
- )`,
25
- [bucket.bucket, bucket.count, bucket.bucket, bucket.bucket, bucket.bucket, bucket.bucket]
26
- );
27
- }
28
- });
29
- }
30
- async syncLocalDatabase(checkpoint, priority) {
31
- const r = await super.syncLocalDatabase(checkpoint, priority);
32
- setTimeout(() => {
33
- this.schemaManager.refreshSchema(this.rdb);
34
- }, 60);
35
- if (r.checkpointValid) {
36
- await this.rdb.execute("UPDATE local_bucket_data SET downloading = FALSE");
37
- }
38
- return r;
39
- }
40
- async saveSyncData(batch) {
41
- await super.saveSyncData(batch);
42
- await this.rdb.writeTransaction(async (tx) => {
43
- for (const bucket of batch.buckets) {
44
- const size = JSON.stringify(bucket.data).length;
45
- await tx.execute(
46
- `UPDATE local_bucket_data SET
47
- download_size = IFNULL(download_size, 0) + ?,
48
- last_op = ?,
49
- downloading = ?,
50
- downloaded_operations = IFNULL(downloaded_operations, 0) + ?
51
- WHERE id = ?`,
52
- [size, bucket.next_after, bucket.has_more, bucket.data.length, bucket.bucket]
53
- );
54
- }
55
- });
56
- await this.schemaManager.updateFromOperations(batch);
57
- }
58
- }