npm install @lix-js/sdk @lix-js/plugin-jsonPlugins (.json, .xlsx, etc.) make Lix file-format aware. The environment can be swapped for persistence.
import { openLix, selectWorkingDiff, InMemoryEnvironment } from "@lix-js/sdk";
import { plugin as json } from "@lix-js/plugin-json";
const lix = await openLix({
environment: new InMemoryEnvironment(),
providePlugins: [json],
});Lix is powered by SQL under the hood. Writing a file, querying diffs, etc. happens all via SQL.
await lix.db
.insertInto("file")
.values({
path: "/config.json",
data: new TextEncoder().encode(JSON.stringify({ theme: "light" })),
})
.execute();Lix tracks changes on the entity level. You can query the history of a specific entity, or the diff between two versions.
const diff = await selectWorkingDiff({ lix }).execute();
console.log(diff);A more detailed example showing Lix tracking property-level changes in a JSON config file.
We'll track changes in this config file:
{
"theme": "light",
"notifications": true,
"language": "en"
}When the config changes, Lix detects exactly which property changed:
{
- "theme": "light",
+ "theme": "dark",
"notifications": true,
"language": "en"
}Open a Lix with the JSON plugin. Plugins teach Lix what a "meaningful change" is for each file format.
import { InMemoryEnvironment, openLix } from "@lix-js/sdk";
import { plugin as jsonPlugin } from "@lix-js/plugin-json";
const lix = await openLix({
environment: new InMemoryEnvironment(),
providePlugins: [jsonPlugin],
});The JavaScript SDK uses Kysely for type-safe query building. Insert the config file into the file table. Files are stored as binary (Uint8Array), making Lix format-agnostic.
import { InMemoryEnvironment, openLix } from "@lix-js/sdk";
import { plugin as jsonPlugin } from "@lix-js/plugin-json";
const lix = await openLix({
environment: new InMemoryEnvironment(),
providePlugins: [jsonPlugin],
});const config = {
theme: "light",
notifications: true,
language: "en",
};
await lix.db
.insertInto("file")
.values({
path: "/config.json",
data: new TextEncoder().encode(JSON.stringify(config, null, 2)),
})
.execute();Update the config by changing theme from "light" to "dark":
import { InMemoryEnvironment, openLix } from "@lix-js/sdk";
import { plugin as jsonPlugin } from "@lix-js/plugin-json";
const lix = await openLix({
environment: new InMemoryEnvironment(),
providePlugins: [jsonPlugin],
});
const config = {
theme: "light",
notifications: true,
language: "en",
};
await lix.db
.insertInto("file")
.values({
path: "/config.json",
data: new TextEncoder().encode(JSON.stringify(config, null, 2)),
})
.execute();// Update the config: change theme to dark
await lix.db
.updateTable("file")
.where("path", "=", "/config.json")
.set({
data: new TextEncoder().encode(
JSON.stringify(
{ theme: "dark", notifications: true, language: "en" },
null,
2,
),
),
})
.execute();Lix detects that theme changed, not just "the file changed":
{
- "theme": "light",
+ "theme": "dark",
"notifications": true,
"language": "en"
}Query the file's history using the file_history view. The lixcol_root_commit_id specifies the starting point. Here we use the active version's commit to get history from the current state. The lixcol_depth indicates how far back (0 = current, 1 = previous, etc.):
import { InMemoryEnvironment, openLix } from "@lix-js/sdk";
import { plugin as jsonPlugin } from "@lix-js/plugin-json";
const lix = await openLix({
environment: new InMemoryEnvironment(),
providePlugins: [jsonPlugin],
});
const config = {
theme: "light",
notifications: true,
language: "en",
};
await lix.db
.insertInto("file")
.values({
path: "/config.json",
data: new TextEncoder().encode(JSON.stringify(config, null, 2)),
})
.execute();
// Update the config: change theme to dark
await lix.db
.updateTable("file")
.where("path", "=", "/config.json")
.set({
data: new TextEncoder().encode(
JSON.stringify(
{ theme: "dark", notifications: true, language: "en" },
null,
2,
),
),
})
.execute();// Get the active version's commit_id
const activeVersionCommitId = lix.db
.selectFrom("active_version")
.innerJoin("version", "active_version.version_id", "version.id")
.select("version.commit_id");
// Query file history from the active version
const history = await lix.db
.selectFrom("file_history")
.where("path", "=", "/config.json")
.where("lixcol_root_commit_id", "=", activeVersionCommitId)
.select(["path", "data", "lixcol_depth"])
.orderBy("lixcol_depth", "asc")
.execute();
for (const row of history) {
console.log(`Depth ${row.lixcol_depth}:`, {
path: row.path,
data: JSON.parse(new TextDecoder().decode(row.data)),
});
}// Output:
// Depth 0: { path: '/config.json', data: { theme: 'dark', notifications: true, language: 'en' } }
// Depth 1: { path: '/config.json', data: { theme: 'light', notifications: true, language: 'en' } }