@columnus/shared 0.1.61 → 0.1.62

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/fieldValueEqual.ts","../src/rowPatchWire.ts"],"names":[],"mappings":"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","file":"rowPatchWire.js","sourcesContent":["// Compare Convex field values for pending-edit diffing. Uses the same\n// JSON normalization as csv export so bigint/bytes compare consistently.\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n let s = \"\";\n for (const b of bytes) s += String.fromCharCode(b);\n return btoa(s);\n}\n\nfunction jsonReplacer(_key: string, value: unknown): unknown {\n if (typeof value === \"bigint\") return `${value.toString()}n`;\n if (value instanceof Uint8Array) return { __bytes__: bytesToBase64(value) };\n return value;\n}\n\nfunction normalizeForCompare(value: unknown): unknown {\n if (value === undefined || value === null) return undefined;\n return value;\n}\n\nfunction stableJsonEqual(a: unknown, b: unknown): boolean {\n try {\n return JSON.stringify(a, jsonReplacer) === JSON.stringify(b, jsonReplacer);\n } catch {\n return false;\n }\n}\n\n/** True when two stored field values are equivalent (missing ≡ undefined). */\nexport function fieldValuesEqual(a: unknown, b: unknown): boolean {\n const na = normalizeForCompare(a);\n const nb = normalizeForCompare(b);\n if (Object.is(na, nb)) return true;\n if (na === undefined && nb === undefined) return true;\n\n const ta = typeof na;\n const tb = typeof nb;\n if (ta !== tb) {\n // bigint stored as string in some editors vs bigint on server\n if (ta === \"bigint\" && tb === \"string\") {\n const naBig = na as bigint;\n const nbStr = nb as string;\n return `${naBig.toString()}n` === nbStr || naBig.toString() === nbStr.replace(/n$/, \"\");\n }\n if (ta === \"string\" && tb === \"bigint\") {\n const naStr = na as string;\n const nbBig = nb as bigint;\n return `${nbBig.toString()}n` === naStr || nbBig.toString() === naStr.replace(/n$/, \"\");\n }\n return false;\n }\n\n if (ta === \"object\" && na !== null && nb !== null) {\n return stableJsonEqual(na, nb);\n }\n\n return false;\n}\n\n/** Drop patch keys whose values match the server row baseline. */\nexport function filterChangedPatchFields(\n patch: Record<string, unknown>,\n baseline: Record<string, unknown> | undefined,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(patch)) {\n if (!fieldValuesEqual(value, baseline?.[key])) out[key] = value;\n }\n return out;\n}\n","import { fieldValuesEqual } from \"./fieldValueEqual.ts\";\n\n/** Wire shape for row update mutations (survives Convex JSON transport). */\nexport type RowPatchWire = {\n patch: Record<string, unknown>;\n clearFields?: string[];\n};\n\n/** Split `undefined` patch values into `clearFields` for mutation transport. */\nexport function prepareRowPatchWire(patch: Record<string, unknown>): RowPatchWire {\n const out: Record<string, unknown> = {};\n const clearFields: string[] = [];\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined) clearFields.push(key);\n else out[key] = value;\n }\n return clearFields.length > 0 ? { patch: out, clearFields } : { patch: out };\n}\n\nexport function hasRowPatchChanges(wire: RowPatchWire): boolean {\n return Object.keys(wire.patch).length > 0 || (wire.clearFields?.length ?? 0) > 0;\n}\n\n/** Merge patch values and explicit clears into a Convex `db.patch` object. */\nexport function applyRowPatchWire(\n patch: Record<string, unknown>,\n clearFields?: readonly string[],\n): Record<string, unknown> {\n const out = { ...patch };\n for (const field of clearFields ?? []) {\n out[field] = undefined;\n }\n return out;\n}\n\n/** Undo/redo inverse for a forward wire patch against a row baseline. */\nexport function buildInverseRowPatchWire(\n baseline: Record<string, unknown> | undefined,\n forward: RowPatchWire,\n): RowPatchWire {\n const base = baseline ?? {};\n const invPatch: Record<string, unknown> = {};\n const invClear: string[] = [];\n\n for (const key of Object.keys(forward.patch)) {\n const before = base[key];\n if (fieldValuesEqual(before, forward.patch[key])) continue;\n if (!fieldValuesEqual(before, undefined)) invPatch[key] = before;\n else invClear.push(key);\n }\n\n for (const key of forward.clearFields ?? []) {\n const before = base[key];\n if (!fieldValuesEqual(before, undefined)) invPatch[key] = before;\n }\n\n return invClear.length > 0 ? { patch: invPatch, clearFields: invClear } : { patch: invPatch };\n}\n"]}
1
+ {"version":3,"sources":["../src/fieldValueEqual.ts","../src/rowPatchWire.ts"],"names":[],"mappings":"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","file":"rowPatchWire.js","sourcesContent":["// Compare Convex field values for pending-edit diffing. Uses the same\n// JSON normalization as csv export so bigint/bytes compare consistently.\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n let s = \"\";\n for (const b of bytes) s += String.fromCharCode(b);\n return btoa(s);\n}\n\nfunction jsonReplacer(_key: string, value: unknown): unknown {\n if (typeof value === \"bigint\") return `${value.toString()}n`;\n if (value instanceof Uint8Array) return { __bytes__: bytesToBase64(value) };\n return value;\n}\n\nfunction normalizeForCompare(value: unknown): unknown {\n if (value === undefined || value === null) return undefined;\n return value;\n}\n\nfunction stableJsonEqual(a: unknown, b: unknown): boolean {\n try {\n return JSON.stringify(a, jsonReplacer) === JSON.stringify(b, jsonReplacer);\n } catch {\n return false;\n }\n}\n\n/** True when two stored field values are equivalent (missing ≡ undefined). */\nexport function fieldValuesEqual(a: unknown, b: unknown): boolean {\n const na = normalizeForCompare(a);\n const nb = normalizeForCompare(b);\n if (Object.is(na, nb)) return true;\n if (na === undefined && nb === undefined) return true;\n\n const ta = typeof na;\n const tb = typeof nb;\n if (ta !== tb) {\n // bigint stored as string in some editors vs bigint on server\n if (ta === \"bigint\" && tb === \"string\") {\n const naBig = na as bigint;\n const nbStr = nb as string;\n return `${naBig.toString()}n` === nbStr || naBig.toString() === nbStr.replace(/n$/, \"\");\n }\n if (ta === \"string\" && tb === \"bigint\") {\n const naStr = na as string;\n const nbBig = nb as bigint;\n return `${nbBig.toString()}n` === naStr || nbBig.toString() === naStr.replace(/n$/, \"\");\n }\n return false;\n }\n\n if (ta === \"object\" && na !== null && nb !== null) {\n return stableJsonEqual(na, nb);\n }\n\n return false;\n}\n\n/** Drop patch keys whose values match the server row baseline. */\nexport function filterChangedPatchFields(\n patch: Record<string, unknown>,\n baseline: Record<string, unknown> | undefined,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(patch)) {\n if (!fieldValuesEqual(value, baseline?.[key])) out[key] = value;\n }\n return out;\n}\n\n/**\n * Strict structural equality for stored Convex values (Media metadata drafts, defaults,\n * automated writes). Unlike `fieldValuesEqual`, an explicit `null` differs from a missing\n * value. bigint and bytes compare by value, and object key order is ignored.\n */\nexport function convexValuesEqual(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) return true;\n if (typeof a !== \"object\" || typeof b !== \"object\" || a === null || b === null) return false;\n if (a instanceof ArrayBuffer || b instanceof ArrayBuffer) {\n if (!(a instanceof ArrayBuffer && b instanceof ArrayBuffer)) return false;\n const left = new Uint8Array(a);\n const right = new Uint8Array(b);\n return left.length === right.length && left.every((byte, index) => byte === right[index]);\n }\n if (Array.isArray(a) || Array.isArray(b)) {\n if (!(Array.isArray(a) && Array.isArray(b)) || a.length !== b.length) return false;\n return a.every((item, index) => convexValuesEqual(item, b[index]));\n }\n // Convex drops `undefined` fields, so they count as absent.\n const left = Object.entries(a).filter(([, value]) => value !== undefined);\n const right = b as Record<string, unknown>;\n return (\n left.length === Object.values(right).filter((value) => value !== undefined).length &&\n left.every(([key, value]) => convexValuesEqual(value, right[key]))\n );\n}\n","import { fieldValuesEqual } from \"./fieldValueEqual.ts\";\n\n/** Wire shape for row update mutations (survives Convex JSON transport). */\nexport type RowPatchWire = {\n patch: Record<string, unknown>;\n clearFields?: string[];\n};\n\n/** Split `undefined` patch values into `clearFields` for mutation transport. */\nexport function prepareRowPatchWire(patch: Record<string, unknown>): RowPatchWire {\n const out: Record<string, unknown> = {};\n const clearFields: string[] = [];\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined) clearFields.push(key);\n else out[key] = value;\n }\n return clearFields.length > 0 ? { patch: out, clearFields } : { patch: out };\n}\n\nexport function hasRowPatchChanges(wire: RowPatchWire): boolean {\n return Object.keys(wire.patch).length > 0 || (wire.clearFields?.length ?? 0) > 0;\n}\n\n/** Merge patch values and explicit clears into a Convex `db.patch` object. */\nexport function applyRowPatchWire(\n patch: Record<string, unknown>,\n clearFields?: readonly string[],\n): Record<string, unknown> {\n const out = { ...patch };\n for (const field of clearFields ?? []) {\n out[field] = undefined;\n }\n return out;\n}\n\n/** Undo/redo inverse for a forward wire patch against a row baseline. */\nexport function buildInverseRowPatchWire(\n baseline: Record<string, unknown> | undefined,\n forward: RowPatchWire,\n): RowPatchWire {\n const base = baseline ?? {};\n const invPatch: Record<string, unknown> = {};\n const invClear: string[] = [];\n\n for (const key of Object.keys(forward.patch)) {\n const before = base[key];\n if (fieldValuesEqual(before, forward.patch[key])) continue;\n if (!fieldValuesEqual(before, undefined)) invPatch[key] = before;\n else invClear.push(key);\n }\n\n for (const key of forward.clearFields ?? []) {\n const before = base[key];\n if (!fieldValuesEqual(before, undefined)) invPatch[key] = before;\n }\n\n return invClear.length > 0 ? { patch: invPatch, clearFields: invClear } : { patch: invPatch };\n}\n"]}