Skip to content
Merged

Dev #235

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions packages/ducjs/src/restore/restoreDataState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1475,10 +1475,24 @@ export const isValidUint8Array = (value: unknown): Uint8Array | undefined => {
return value.byteLength > 0 ? value : undefined;
}

if (ArrayBuffer.isView(value)) {
const bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
return bytes.byteLength > 0 ? bytes : undefined;
}

if (value instanceof ArrayBuffer) {
return value.byteLength > 0 ? new Uint8Array(value) : undefined;
}

if (Array.isArray(value)) {
if (value.length === 0 || !value.every((entry) => typeof entry === "number")) {
return undefined;
}

const bytes = new Uint8Array(value);
return bytes.byteLength > 0 ? bytes : undefined;
}

if (typeof value === "string") {
let base64String = value;

Expand Down Expand Up @@ -1512,6 +1526,14 @@ export const isValidUint8Array = (value: unknown): Uint8Array | undefined => {
}
}

if (value && typeof value === "object") {
const entries = Object.values(value);
if (entries.length > 0 && entries.every((entry) => typeof entry === "number")) {
const bytes = new Uint8Array(entries as number[]);
return bytes.byteLength > 0 ? bytes : undefined;
}
}

return undefined;
};

Expand Down
41 changes: 27 additions & 14 deletions packages/ducjs/src/serialize.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { restore, type ElementsConfig, type RestoreConfig } from "./restore";
import { isValidUint8Array, restore, type ElementsConfig, type RestoreConfig } from "./restore";
import { transformToRust } from "./transform";
import type { ExportedDataState } from "./types";
import { ensureWasm, wasmGetCurrentSchemaVersion, wasmParseDuc, wasmSerializeDuc } from "./wasm";
Expand Down Expand Up @@ -148,23 +148,36 @@ function prepareVersionGraphForSerialization(vg: any): any {
if (!vg || typeof vg !== "object") return undefined;

const checkpoints = Array.isArray(vg.checkpoints)
? vg.checkpoints.filter((cp: any) => {
const data = cp?.data;
if (data instanceof Uint8Array) return data.byteLength > 0;
if (data instanceof ArrayBuffer) return data.byteLength > 0;
// Accept base64 strings (from JSON imports)
if (typeof data === "string" && data.length > 0) return true;
return false;
? vg.checkpoints.flatMap((checkpoint: any) => {
const data = isValidUint8Array(checkpoint?.data);
if (!data?.byteLength) {
return [];
}

return [{
...checkpoint,
data,
}];
})
: [];

const validCheckpointIds = new Set(
checkpoints
.map((checkpoint: any) => checkpoint?.id)
.filter((checkpointId: unknown): checkpointId is string => typeof checkpointId === "string" && checkpointId.length > 0),
);

const deltas = Array.isArray(vg.deltas)
? vg.deltas.filter((d: any) => {
const payload = d?.payload;
if (payload instanceof Uint8Array) return payload.byteLength > 0;
if (payload instanceof ArrayBuffer) return payload.byteLength > 0;
if (typeof payload === "string" && payload.length > 0) return true;
return false;
? vg.deltas.flatMap((delta: any) => {
const payload = isValidUint8Array(delta?.payload);
if (!payload?.byteLength || typeof delta?.baseCheckpointId !== "string" || !validCheckpointIds.has(delta.baseCheckpointId)) {
return [];
}

return [{
...delta,
payload,
}];
})
: [];

Expand Down
Loading