@lix-js/sdk 0.1.0 → 0.3.0
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/account/database-schema.d.ts.map +1 -1
- package/dist/account/database-schema.js +2 -6
- package/dist/account/database-schema.js.map +1 -1
- package/dist/account/database-schema.test.js +4 -8
- package/dist/account/database-schema.test.js.map +1 -1
- package/dist/database/apply-schema.js +2 -2
- package/dist/database/init-db.test.js +3 -3
- package/dist/database/init-db.test.js.map +1 -1
- package/dist/file-queue/file-queue-process.d.ts.map +1 -1
- package/dist/file-queue/file-queue-process.js +4 -1
- package/dist/file-queue/file-queue-process.js.map +1 -1
- package/dist/file-queue/file-queue-process.test.js +4 -5
- package/dist/file-queue/file-queue-process.test.js.map +1 -1
- package/dist/lix/open-lix.d.ts +16 -1
- package/dist/lix/open-lix.d.ts.map +1 -1
- package/dist/lix/open-lix.js +76 -0
- package/dist/lix/open-lix.js.map +1 -1
- package/dist/lix/open-lix.test.js +54 -0
- package/dist/lix/open-lix.test.js.map +1 -1
- package/dist/query-filter/change-has-label.d.ts +2 -2
- package/dist/query-filter/change-has-label.js +2 -2
- package/dist/query-filter/change-set-has-label.d.ts +2 -2
- package/dist/query-filter/change-set-has-label.js +2 -2
- package/dist/services/env-variables/index.d.ts +5 -0
- package/dist/services/env-variables/index.d.ts.map +1 -0
- package/dist/services/env-variables/index.js +5 -0
- package/dist/services/env-variables/index.js.map +1 -0
- package/dist/services/telemetry/capture.d.ts +30 -0
- package/dist/services/telemetry/capture.d.ts.map +1 -0
- package/dist/services/telemetry/capture.js +71 -0
- package/dist/services/telemetry/capture.js.map +1 -0
- package/dist/services/telemetry/capture.test.d.ts +2 -0
- package/dist/services/telemetry/capture.test.d.ts.map +1 -0
- package/dist/services/telemetry/capture.test.js +37 -0
- package/dist/services/telemetry/capture.test.js.map +1 -0
- package/dist/sync/sync-process.d.ts.map +1 -1
- package/dist/sync/sync-process.js +11 -5
- package/dist/sync/sync-process.js.map +1 -1
- package/package.json +4 -6
- package/src/account/database-schema.test.ts +6 -9
- package/src/account/database-schema.ts +2 -6
- package/src/database/apply-schema.ts +2 -2
- package/src/database/init-db.test.ts +3 -3
- package/src/file-queue/file-queue-process.test.ts +4 -5
- package/src/file-queue/file-queue-process.ts +4 -1
- package/src/lix/open-lix.test.ts +63 -0
- package/src/lix/open-lix.ts +98 -1
- package/src/query-filter/change-has-label.ts +2 -2
- package/src/query-filter/change-set-has-label.ts +2 -2
- package/src/services/env-variables/create-index-file.js +35 -0
- package/src/services/env-variables/index.d.ts +15 -0
- package/src/services/telemetry/capture.test.ts +44 -0
- package/src/services/telemetry/capture.ts +99 -0
- package/src/sync/sync-process.ts +11 -6
- package/node_modules/@lix-js/server-api-schema/.prettierrc.json +0 -3
- package/node_modules/@lix-js/server-api-schema/.vscode/extensions.json +0 -3
- package/node_modules/@lix-js/server-api-schema/CHANGELOG.md +0 -9
- package/node_modules/@lix-js/server-api-schema/LICENSE +0 -21
- package/node_modules/@lix-js/server-api-schema/dist/schema.js +0 -0
- package/node_modules/@lix-js/server-api-schema/package.json +0 -21
- package/node_modules/@lix-js/server-api-schema/src/schema.yaml +0 -290
- package/node_modules/@lix-js/server-api-schema/tsconfig.json +0 -20
- package/node_modules/sqlite-wasm-kysely/LICENSE +0 -21
- package/node_modules/sqlite-wasm-kysely/README.md +0 -11
- package/node_modules/sqlite-wasm-kysely/dist/dialect.d.ts +0 -11
- package/node_modules/sqlite-wasm-kysely/dist/dialect.js +0 -13
- package/node_modules/sqlite-wasm-kysely/dist/dialect.js.map +0 -1
- package/node_modules/sqlite-wasm-kysely/dist/index.d.ts +0 -2
- package/node_modules/sqlite-wasm-kysely/dist/index.js +0 -3
- package/node_modules/sqlite-wasm-kysely/dist/index.js.map +0 -1
- package/node_modules/sqlite-wasm-kysely/dist/kysely/ConnectionMutex.d.ts +0 -5
- package/node_modules/sqlite-wasm-kysely/dist/kysely/ConnectionMutex.js +0 -34
- package/node_modules/sqlite-wasm-kysely/dist/kysely/ConnectionMutex.js.map +0 -1
- package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmConnection.d.ts +0 -8
- package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmConnection.js +0 -57
- package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmConnection.js.map +0 -1
- package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmDialectConfig.d.ts +0 -18
- package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmDialectConfig.js +0 -2
- package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmDialectConfig.js.map +0 -1
- package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmDriver.d.ts +0 -13
- package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmDriver.js +0 -57
- package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmDriver.js.map +0 -1
- package/node_modules/sqlite-wasm-kysely/dist/kysely/index.d.ts +0 -4
- package/node_modules/sqlite-wasm-kysely/dist/kysely/index.js +0 -4
- package/node_modules/sqlite-wasm-kysely/dist/kysely/index.js.map +0 -1
- package/node_modules/sqlite-wasm-kysely/dist/kysely/sqliteModule.d.ts +0 -3
- package/node_modules/sqlite-wasm-kysely/dist/kysely/sqliteModule.js +0 -5
- package/node_modules/sqlite-wasm-kysely/dist/kysely/sqliteModule.js.map +0 -1
- package/node_modules/sqlite-wasm-kysely/dist/util/contentFromDatabase.d.ts +0 -9
- package/node_modules/sqlite-wasm-kysely/dist/util/contentFromDatabase.js +0 -12
- package/node_modules/sqlite-wasm-kysely/dist/util/contentFromDatabase.js.map +0 -1
- package/node_modules/sqlite-wasm-kysely/dist/util/createInMemoryDatabase.d.ts +0 -3
- package/node_modules/sqlite-wasm-kysely/dist/util/createInMemoryDatabase.js +0 -22
- package/node_modules/sqlite-wasm-kysely/dist/util/createInMemoryDatabase.js.map +0 -1
- package/node_modules/sqlite-wasm-kysely/dist/util/importDatabase.d.ts +0 -7
- package/node_modules/sqlite-wasm-kysely/dist/util/importDatabase.js +0 -15
- package/node_modules/sqlite-wasm-kysely/dist/util/importDatabase.js.map +0 -1
- package/node_modules/sqlite-wasm-kysely/dist/util/index.d.ts +0 -5
- package/node_modules/sqlite-wasm-kysely/dist/util/index.js +0 -5
- package/node_modules/sqlite-wasm-kysely/dist/util/index.js.map +0 -1
- package/node_modules/sqlite-wasm-kysely/dist/util/loadDatabaseInMemory.d.ts +0 -1
- package/node_modules/sqlite-wasm-kysely/dist/util/loadDatabaseInMemory.js +0 -13
- package/node_modules/sqlite-wasm-kysely/dist/util/loadDatabaseInMemory.js.map +0 -1
- package/node_modules/sqlite-wasm-kysely/dist/util/sqliteWasmBinary.d.ts +0 -7
- package/node_modules/sqlite-wasm-kysely/dist/util/sqliteWasmBinary.js +0 -17
- package/node_modules/sqlite-wasm-kysely/dist/util/sqliteWasmBinary.js.map +0 -1
- package/node_modules/sqlite-wasm-kysely/package.json +0 -34
- package/node_modules/sqlite-wasm-kysely/src/dialect.ts +0 -15
- package/node_modules/sqlite-wasm-kysely/src/index.ts +0 -2
- package/node_modules/sqlite-wasm-kysely/src/kysely/ConnectionMutex.ts +0 -23
- package/node_modules/sqlite-wasm-kysely/src/kysely/SqliteWasmConnection.ts +0 -57
- package/node_modules/sqlite-wasm-kysely/src/kysely/SqliteWasmDialectConfig.ts +0 -19
- package/node_modules/sqlite-wasm-kysely/src/kysely/SqliteWasmDriver.ts +0 -58
- package/node_modules/sqlite-wasm-kysely/src/kysely/index.ts +0 -4
- package/node_modules/sqlite-wasm-kysely/src/kysely/sqliteModule.ts +0 -7
- package/node_modules/sqlite-wasm-kysely/src/util/contentFromDatabase.ts +0 -13
- package/node_modules/sqlite-wasm-kysely/src/util/createInMemoryDatabase.ts +0 -30
- package/node_modules/sqlite-wasm-kysely/src/util/importDatabase.ts +0 -34
- package/node_modules/sqlite-wasm-kysely/src/util/index.ts +0 -5
- package/node_modules/sqlite-wasm-kysely/src/util/loadDatabaseInMemory.ts +0 -13
- package/node_modules/sqlite-wasm-kysely/src/util/sqliteWasmBinary.ts +0 -20
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @example
|
|
5
5
|
* ```ts
|
|
6
6
|
* await lix.db.selectFrom("change_set")
|
|
7
|
-
* .where(changeSetHasLabel("
|
|
7
|
+
* .where(changeSetHasLabel("checkpoint"))
|
|
8
8
|
* .selectAll()
|
|
9
9
|
* .execute();
|
|
10
10
|
* ```
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*
|
|
15
15
|
* ```ts
|
|
16
16
|
* await lix.db.selectFrom("change_set")
|
|
17
|
-
* .where((eb) => eb.not(changeSetHasLabel("
|
|
17
|
+
* .where((eb) => eb.not(changeSetHasLabel("checkpoint")))
|
|
18
18
|
* .selectAll()
|
|
19
19
|
* .execute();
|
|
20
20
|
* ```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/env-variables/index.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,aAAa;;;CAGzB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/env-variables/index.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,qBAAqB,EAAE,SAAS;IACjC,eAAe,EAAE,OAAO;CACxB,CAAA"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List of telemetry events for typesafety.
|
|
3
|
+
*
|
|
4
|
+
* - prefix with `SDK` to avoid collisions with other apps
|
|
5
|
+
* - use past tense to indicate that the event is completed
|
|
6
|
+
*/
|
|
7
|
+
type TelemetryEvent = "LIX-SDK lix opened";
|
|
8
|
+
/**
|
|
9
|
+
* Capture an event.
|
|
10
|
+
*
|
|
11
|
+
* - manually calling the PostHog API because the SDKs were not platform angostic (and generally bloated)
|
|
12
|
+
*/
|
|
13
|
+
export declare const capture: (event: TelemetryEvent, args: {
|
|
14
|
+
lixId: string;
|
|
15
|
+
accountId: string;
|
|
16
|
+
/**
|
|
17
|
+
* The value of the telemetry key-value pair.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* const telemetryKeyValue = await lix.db.selectFrom("key_value").select("value").where("key", "=", "lix_telemetry").executeTakeFirstOrThrow();
|
|
21
|
+
* await capture("LIX-SDK opened lix", { lixId: "test", accountId: "test", telemetryKeyValue: telemetryKeyValue.value, properties: {} });
|
|
22
|
+
*/
|
|
23
|
+
telemetryKeyValue: string;
|
|
24
|
+
/**
|
|
25
|
+
* Please use snake_case for property names.
|
|
26
|
+
*/
|
|
27
|
+
properties: Record<string, any>;
|
|
28
|
+
}) => Promise<void>;
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=capture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../../src/services/telemetry/capture.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,KAAK,cAAc,GAAG,oBAAoB,CAAC;AAE3C;;;;GAIG;AACH,eAAO,MAAM,OAAO,UACZ,cAAc,QACf;IACL,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC,KACC,OAAO,CAAC,IAAI,CA6Bd,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { ENV_VARIABLES } from "../env-variables/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Capture an event.
|
|
4
|
+
*
|
|
5
|
+
* - manually calling the PostHog API because the SDKs were not platform angostic (and generally bloated)
|
|
6
|
+
*/
|
|
7
|
+
export const capture = async (event, args) => {
|
|
8
|
+
if (ENV_VARIABLES.LIX_SDK_POSTHOG_TOKEN === undefined) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
else if (args.telemetryKeyValue === "off") {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
await fetch("https://eu.posthog.com/capture/", {
|
|
16
|
+
method: "POST",
|
|
17
|
+
body: JSON.stringify({
|
|
18
|
+
api_key: ENV_VARIABLES.LIX_SDK_POSTHOG_TOKEN,
|
|
19
|
+
event,
|
|
20
|
+
distinct_id: args.accountId,
|
|
21
|
+
properties: {
|
|
22
|
+
$groups: { lix_id: args.lixId },
|
|
23
|
+
...args.properties,
|
|
24
|
+
},
|
|
25
|
+
}),
|
|
26
|
+
});
|
|
27
|
+
await identifyLix({
|
|
28
|
+
lixId: args.lixId,
|
|
29
|
+
accountId: args.accountId,
|
|
30
|
+
// using the id for now as a name but can be changed in the future
|
|
31
|
+
// we need at least one property to make a project visible in the dashboard
|
|
32
|
+
properties: { name: args.lixId },
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
//
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Identifying a project is needed.
|
|
41
|
+
*
|
|
42
|
+
* Otherwise, the project will not be visible in the PostHog dashboard.
|
|
43
|
+
*/
|
|
44
|
+
const identifyLix = async (args) => {
|
|
45
|
+
// do not send events if the token is not set
|
|
46
|
+
// (assuming this eases testing)
|
|
47
|
+
if (ENV_VARIABLES.LIX_SDK_POSTHOG_TOKEN === undefined) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
await fetch("https://eu.posthog.com/capture/", {
|
|
52
|
+
method: "POST",
|
|
53
|
+
body: JSON.stringify({
|
|
54
|
+
api_key: ENV_VARIABLES.LIX_SDK_POSTHOG_TOKEN,
|
|
55
|
+
event: "$groupidentify",
|
|
56
|
+
distinct_id: args.accountId,
|
|
57
|
+
properties: {
|
|
58
|
+
$group_type: "lix",
|
|
59
|
+
$group_key: args.lixId,
|
|
60
|
+
$group_set: {
|
|
61
|
+
...args.properties,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
}),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
//
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
//# sourceMappingURL=capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../../src/services/telemetry/capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAU1D;;;;GAIG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,KAAK,EAC3B,KAAqB,EACrB,IAeC,EACe,EAAE;IAClB,IAAI,aAAa,CAAC,qBAAqB,KAAK,SAAS,EAAE,CAAC;QACvD,OAAO;IACR,CAAC;SAAM,IAAI,IAAI,CAAC,iBAAiB,KAAK,KAAK,EAAE,CAAC;QAC7C,OAAO;IACR,CAAC;IACD,IAAI,CAAC;QACJ,MAAM,KAAK,CAAC,iCAAiC,EAAE;YAC9C,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACpB,OAAO,EAAE,aAAa,CAAC,qBAAqB;gBAC5C,KAAK;gBACL,WAAW,EAAE,IAAI,CAAC,SAAS;gBAC3B,UAAU,EAAE;oBACX,OAAO,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE;oBAC/B,GAAG,IAAI,CAAC,UAAU;iBAClB;aACD,CAAC;SACF,CAAC,CAAC;QACH,MAAM,WAAW,CAAC;YACjB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,kEAAkE;YAClE,2EAA2E;YAC3E,UAAU,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE;SAChC,CAAC,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACR,EAAE;IACH,CAAC;AACF,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,WAAW,GAAG,KAAK,EAAE,IAI1B,EAAE,EAAE;IACJ,6CAA6C;IAC7C,gCAAgC;IAChC,IAAI,aAAa,CAAC,qBAAqB,KAAK,SAAS,EAAE,CAAC;QACvD,OAAO;IACR,CAAC;IACD,IAAI,CAAC;QACJ,MAAM,KAAK,CAAC,iCAAiC,EAAE;YAC9C,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACpB,OAAO,EAAE,aAAa,CAAC,qBAAqB;gBAC5C,KAAK,EAAE,gBAAgB;gBACvB,WAAW,EAAE,IAAI,CAAC,SAAS;gBAC3B,UAAU,EAAE;oBACX,WAAW,EAAE,KAAK;oBAClB,UAAU,EAAE,IAAI,CAAC,KAAK;oBACtB,UAAU,EAAE;wBACX,GAAG,IAAI,CAAC,UAAU;qBAClB;iBACD;aACD,CAAC;SACF,CAAC,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACR,EAAE;IACH,CAAC;AACF,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.test.d.ts","sourceRoot":"","sources":["../../../src/services/telemetry/capture.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { expect, test, vi } from "vitest";
|
|
2
|
+
import { capture } from "./capture.js";
|
|
3
|
+
test("it should not capture if telemetry is off", async () => {
|
|
4
|
+
global.fetch = vi.fn(() => Promise.resolve(new Response()));
|
|
5
|
+
vi.mock("../env-variables/index.js", async () => {
|
|
6
|
+
return {
|
|
7
|
+
ENV_VARIABLES: {
|
|
8
|
+
LIX_SDK_POSTHOG_TOKEN: "mock-defined",
|
|
9
|
+
},
|
|
10
|
+
};
|
|
11
|
+
});
|
|
12
|
+
await capture("LIX-SDK lix opened", {
|
|
13
|
+
lixId: "test",
|
|
14
|
+
accountId: "test",
|
|
15
|
+
telemetryKeyValue: "off",
|
|
16
|
+
properties: {},
|
|
17
|
+
});
|
|
18
|
+
expect(global.fetch).not.toHaveBeenCalled();
|
|
19
|
+
});
|
|
20
|
+
test("it should not capture if telemetry is NOT off", async () => {
|
|
21
|
+
global.fetch = vi.fn(() => Promise.resolve(new Response()));
|
|
22
|
+
vi.mock("../env-variables/index.js", async () => {
|
|
23
|
+
return {
|
|
24
|
+
ENV_VARIABLES: {
|
|
25
|
+
LIX_SDK_POSTHOG_TOKEN: "mock-defined",
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
await capture("LIX-SDK lix opened", {
|
|
30
|
+
lixId: "test",
|
|
31
|
+
accountId: "test",
|
|
32
|
+
telemetryKeyValue: "on",
|
|
33
|
+
properties: {},
|
|
34
|
+
});
|
|
35
|
+
expect(global.fetch).toHaveBeenCalled();
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=capture.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.test.js","sourceRoot":"","sources":["../../../src/services/telemetry/capture.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,IAAI,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;IAC5D,MAAM,CAAC,KAAK,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC;IAE5D,EAAE,CAAC,IAAI,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;QAC/C,OAAO;YACN,aAAa,EAAE;gBACd,qBAAqB,EAAE,cAAc;aACrC;SACD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,CAAC,oBAAoB,EAAE;QACnC,KAAK,EAAE,MAAM;QACb,SAAS,EAAE,MAAM;QACjB,iBAAiB,EAAE,KAAK;QACxB,UAAU,EAAE,EAAE;KACd,CAAC,CAAC;IAEH,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;AAC7C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;IAChE,MAAM,CAAC,KAAK,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC;IAE5D,EAAE,CAAC,IAAI,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;QAC/C,OAAO;YACN,aAAa,EAAE;gBACd,qBAAqB,EAAE,cAAc;aACrC;SACD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,CAAC,oBAAoB,EAAE;QACnC,KAAK,EAAE,MAAM;QACb,SAAS,EAAE,MAAM;QACjB,iBAAiB,EAAE,IAAI;QACvB,UAAU,EAAE,EAAE;KACd,CAAC,CAAC;IAEH,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,gBAAgB,EAAE,CAAC;AACzC,CAAC,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-process.d.ts","sourceRoot":"","sources":["../../src/sync/sync-process.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAK9C,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC3C,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAC;CAC3C,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"sync-process.d.ts","sourceRoot":"","sources":["../../src/sync/sync-process.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAK9C,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC3C,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAC;CAC3C,GAAG,OAAO,CAAC,IAAI,CAAC,CAkFhB"}
|
|
@@ -60,14 +60,20 @@ export async function initSyncProcess(args) {
|
|
|
60
60
|
};
|
|
61
61
|
// naive implementation that syncs every second
|
|
62
62
|
function schedulePullAndPush() {
|
|
63
|
-
if (args.lix.sqlite.isOpen()) {
|
|
64
|
-
|
|
65
|
-
console.error("Error in sync process", e);
|
|
66
|
-
});
|
|
63
|
+
if (args.lix.sqlite.isOpen() === false) {
|
|
64
|
+
return;
|
|
67
65
|
}
|
|
66
|
+
pullAndPush().catch((e) => {
|
|
67
|
+
if (e instanceof Error && e.message.includes("DB has been closed.")) {
|
|
68
|
+
// stop the syncing process, the database has been closed.
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
console.error("Error in sync process", e);
|
|
72
|
+
});
|
|
73
|
+
// schedule next sync
|
|
68
74
|
setTimeout(() => {
|
|
69
75
|
schedulePullAndPush();
|
|
70
|
-
},
|
|
76
|
+
}, 750);
|
|
71
77
|
}
|
|
72
78
|
schedulePullAndPush();
|
|
73
79
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-process.js","sourceRoot":"","sources":["../../src/sync/sync-process.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAErC;IACA,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,EAAE;SAC7B,UAAU,CAAC,WAAW,CAAC;SACvB,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,QAAQ,CAAC;SAC3B,MAAM,CAAC,OAAO,CAAC;SACf,uBAAuB,EAAE,CAAC;IAE5B,MAAM,WAAW,GAAG,KAAK,IAAI,EAAE;QAC9B,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,EAAE;aAClC,UAAU,CAAC,WAAW,CAAC;aACvB,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,UAAU,CAAC;aAC7B,MAAM,CAAC,OAAO,CAAC;aACf,gBAAgB,EAAE,CAAC;QAErB,IAAI,UAAU,EAAE,KAAK,KAAK,MAAM,EAAE,CAAC;YAClC,OAAO;QACR,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,EAAE;aAC3B,UAAU,CAAC,WAAW,CAAC;YACxB,yDAAyD;aACxD,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,gBAAgB,CAAC;aACnC,MAAM,CAAC,OAAO,CAAC;aACf,gBAAgB,EAAE,CAAC;QACrB,gDAAgD;QAChD,gDAAgD;QAChD,IAAI,CAAC,GAAG,EAAE,CAAC;YACV,OAAO;QACR,CAAC;
|
|
1
|
+
{"version":3,"file":"sync-process.js","sourceRoot":"","sources":["../../src/sync/sync-process.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lix-js/sdk",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": "./dist/index.js"
|
|
@@ -16,17 +16,13 @@
|
|
|
16
16
|
"engines": {
|
|
17
17
|
"node": ">=21"
|
|
18
18
|
},
|
|
19
|
-
"bundleDependencies": [
|
|
20
|
-
"@lix-js/server-api-schema",
|
|
21
|
-
"sqlite-wasm-kysely"
|
|
22
|
-
],
|
|
23
19
|
"dependencies": {
|
|
24
20
|
"dedent": "1.5.1",
|
|
25
21
|
"human-id": "^4.1.1",
|
|
26
22
|
"js-sha256": "^0.11.0",
|
|
27
23
|
"kysely": "^0.27.4",
|
|
28
24
|
"uuid": "^10.0.0",
|
|
29
|
-
"sqlite-wasm-kysely": "0.1.
|
|
25
|
+
"sqlite-wasm-kysely": "0.1.1"
|
|
30
26
|
},
|
|
31
27
|
"devDependencies": {
|
|
32
28
|
"@eslint/js": "^9.12.0",
|
|
@@ -41,9 +37,11 @@
|
|
|
41
37
|
"@lix-js/server-api-schema": "0.1.1"
|
|
42
38
|
},
|
|
43
39
|
"scripts": {
|
|
40
|
+
"prebuild": "npm run env-variables",
|
|
44
41
|
"build": "tsc --build",
|
|
45
42
|
"test": "tsc --noEmit && vitest run --coverage",
|
|
46
43
|
"test:watch": "vitest",
|
|
44
|
+
"env-variables": "node ./src/services/env-variables/create-index-file.js",
|
|
47
45
|
"bench": "vitest bench",
|
|
48
46
|
"lint": "eslint src/**/* --fix",
|
|
49
47
|
"dev": "tsc --watch",
|
|
@@ -18,7 +18,7 @@ type AccountSchema = {
|
|
|
18
18
|
active_account: ActiveAccountTable;
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
test("account table should have no entry
|
|
21
|
+
test("account table should have no entry but an active account", async () => {
|
|
22
22
|
const sqlite = await createInMemoryDatabase({
|
|
23
23
|
readOnly: false,
|
|
24
24
|
});
|
|
@@ -38,11 +38,8 @@ test("account table should have no entry in the beginning and activte account sh
|
|
|
38
38
|
}),
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
const account = await db
|
|
42
|
-
|
|
43
|
-
.selectAll()
|
|
44
|
-
.where("id", "=", "anonymous")
|
|
45
|
-
.execute();
|
|
41
|
+
const account = await db.selectFrom("account").selectAll().execute();
|
|
42
|
+
|
|
46
43
|
expect(account?.length).toBe(0);
|
|
47
44
|
|
|
48
45
|
const active_account = await db
|
|
@@ -50,7 +47,7 @@ test("account table should have no entry in the beginning and activte account sh
|
|
|
50
47
|
.selectAll()
|
|
51
48
|
.executeTakeFirst();
|
|
52
49
|
|
|
53
|
-
expect(active_account?.id).toBe("
|
|
50
|
+
expect(active_account?.id).toBe("mock_uuid_v7");
|
|
54
51
|
});
|
|
55
52
|
|
|
56
53
|
test("account.id should default to uuid_v7", async () => {
|
|
@@ -131,7 +128,7 @@ test('it should drop the temp "current_account" table on reboot to not persist t
|
|
|
131
128
|
id: "test",
|
|
132
129
|
});
|
|
133
130
|
|
|
134
|
-
const blob = contentFromDatabase(sqlite);
|
|
131
|
+
const blob = contentFromDatabase(sqlite) as unknown as ArrayBuffer;
|
|
135
132
|
|
|
136
133
|
// re-open the database
|
|
137
134
|
|
|
@@ -158,7 +155,7 @@ test('it should drop the temp "current_account" table on reboot to not persist t
|
|
|
158
155
|
.executeTakeFirst();
|
|
159
156
|
|
|
160
157
|
expect(account2).toMatchObject({
|
|
161
|
-
id: "
|
|
158
|
+
id: "mock_uuid_v7-2",
|
|
162
159
|
});
|
|
163
160
|
});
|
|
164
161
|
|
|
@@ -21,10 +21,6 @@ export function applyAccountDatabaseSchema(
|
|
|
21
21
|
name TEXT NOT NULL
|
|
22
22
|
) STRICT;
|
|
23
23
|
|
|
24
|
-
-- default anonymous account
|
|
25
|
-
-- INSERT OR IGNORE INTO account (id, name)
|
|
26
|
-
-- VALUES ('anonymous', 'anonymous');
|
|
27
|
-
|
|
28
24
|
-- current account(s)
|
|
29
25
|
-- temp table because current accounts are session
|
|
30
26
|
-- specific and should not be persisted
|
|
@@ -34,8 +30,8 @@ export function applyAccountDatabaseSchema(
|
|
|
34
30
|
-- can't use foreign keys in temp tables... :(
|
|
35
31
|
) STRICT;
|
|
36
32
|
|
|
37
|
-
-- default to
|
|
38
|
-
INSERT INTO active_account (id, name) values (
|
|
33
|
+
-- default to a new account
|
|
34
|
+
INSERT INTO active_account (id, name) values (uuid_v7(), '${anonymousAccountName}');
|
|
39
35
|
`;
|
|
40
36
|
|
|
41
37
|
return sqlite.exec(sql);
|
|
@@ -189,11 +189,11 @@ export function applySchema(args: { sqlite: SqliteDatabase }): SqliteDatabase {
|
|
|
189
189
|
CREATE TABLE IF NOT EXISTS label (
|
|
190
190
|
id TEXT PRIMARY KEY DEFAULT (nano_id(8)),
|
|
191
191
|
|
|
192
|
-
name TEXT NOT NULL UNIQUE -- e.g., '
|
|
192
|
+
name TEXT NOT NULL UNIQUE -- e.g., 'checkpoint', 'reviewed'
|
|
193
193
|
|
|
194
194
|
) STRICT;
|
|
195
195
|
|
|
196
|
-
INSERT OR IGNORE INTO label (name) VALUES ('
|
|
196
|
+
INSERT OR IGNORE INTO label (name) VALUES ('checkpoint');
|
|
197
197
|
INSERT OR IGNORE INTO label (name) VALUES ('grouped');
|
|
198
198
|
|
|
199
199
|
-- versions
|
|
@@ -362,7 +362,7 @@ test("creating multiple discussions for one change set should be possible", asyn
|
|
|
362
362
|
expect(discussions).toHaveLength(2);
|
|
363
363
|
});
|
|
364
364
|
|
|
365
|
-
test("the
|
|
365
|
+
test("the checkpoint label should be created if it doesn't exist", async () => {
|
|
366
366
|
const sqlite = await createInMemoryDatabase({
|
|
367
367
|
readOnly: false,
|
|
368
368
|
});
|
|
@@ -371,11 +371,11 @@ test("the confirmed label should be created if it doesn't exist", async () => {
|
|
|
371
371
|
const tag = await db
|
|
372
372
|
.selectFrom("label")
|
|
373
373
|
.selectAll()
|
|
374
|
-
.where("name", "=", "
|
|
374
|
+
.where("name", "=", "checkpoint")
|
|
375
375
|
.executeTakeFirst();
|
|
376
376
|
|
|
377
377
|
expect(tag).toMatchObject({
|
|
378
|
-
name: "
|
|
378
|
+
name: "checkpoint",
|
|
379
379
|
});
|
|
380
380
|
});
|
|
381
381
|
|
|
@@ -104,8 +104,7 @@ test("should use queue and settled correctly", async () => {
|
|
|
104
104
|
content: {
|
|
105
105
|
text: "insert text",
|
|
106
106
|
},
|
|
107
|
-
|
|
108
|
-
account_id: expect.stringMatching(/^anonymous_/),
|
|
107
|
+
account_id: expect.stringMatching(/./),
|
|
109
108
|
}),
|
|
110
109
|
])
|
|
111
110
|
);
|
|
@@ -209,7 +208,7 @@ test("should use queue and settled correctly", async () => {
|
|
|
209
208
|
content: {
|
|
210
209
|
text: "insert text",
|
|
211
210
|
},
|
|
212
|
-
account_id: expect.stringMatching(
|
|
211
|
+
account_id: expect.stringMatching(/./),
|
|
213
212
|
}),
|
|
214
213
|
expect.objectContaining({
|
|
215
214
|
entity_id: "test",
|
|
@@ -219,7 +218,7 @@ test("should use queue and settled correctly", async () => {
|
|
|
219
218
|
content: {
|
|
220
219
|
text: "updated text",
|
|
221
220
|
},
|
|
222
|
-
account_id: expect.stringMatching(
|
|
221
|
+
account_id: expect.stringMatching(/./),
|
|
223
222
|
}),
|
|
224
223
|
expect.objectContaining({
|
|
225
224
|
file_id: "test",
|
|
@@ -229,7 +228,7 @@ test("should use queue and settled correctly", async () => {
|
|
|
229
228
|
content: {
|
|
230
229
|
text: "second text update",
|
|
231
230
|
},
|
|
232
|
-
account_id: expect.stringMatching(
|
|
231
|
+
account_id: expect.stringMatching(/./),
|
|
233
232
|
}),
|
|
234
233
|
])
|
|
235
234
|
);
|
|
@@ -28,7 +28,6 @@ export async function initFileQueueProcess(args: {
|
|
|
28
28
|
|
|
29
29
|
async function queueWorker(trail = false) {
|
|
30
30
|
if (args.lix.sqlite.isOpen() === false) {
|
|
31
|
-
console.log("sqlite is closed");
|
|
32
31
|
return;
|
|
33
32
|
}
|
|
34
33
|
|
|
@@ -93,6 +92,10 @@ export async function initFileQueueProcess(args: {
|
|
|
93
92
|
queueWorker(true);
|
|
94
93
|
}
|
|
95
94
|
} catch (e) {
|
|
95
|
+
// database has been closed, ignore
|
|
96
|
+
if (e instanceof Error && e.message.includes("DB has been closed")) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
96
99
|
console.error("file queue failed ", e);
|
|
97
100
|
}
|
|
98
101
|
}
|
package/src/lix/open-lix.test.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { openLixInMemory } from "./open-lix-in-memory.js";
|
|
|
3
3
|
import { newLixFile } from "./new-lix.js";
|
|
4
4
|
import type { LixPlugin } from "../plugin/lix-plugin.js";
|
|
5
5
|
import { toBlob } from "./to-blob.js";
|
|
6
|
+
import { usedFileExtensions } from "./open-lix.js";
|
|
6
7
|
|
|
7
8
|
test("providing plugins should be possible", async () => {
|
|
8
9
|
const mockPlugin: LixPlugin = {
|
|
@@ -43,3 +44,65 @@ test("providing key values should be possible", async () => {
|
|
|
43
44
|
.executeTakeFirstOrThrow();
|
|
44
45
|
expect(value1).toMatchObject({ key: "mock_key", value: "value2" });
|
|
45
46
|
});
|
|
47
|
+
|
|
48
|
+
test("providing an account should be possible", async () => {
|
|
49
|
+
const mockAccount = {
|
|
50
|
+
id: "mock-account",
|
|
51
|
+
name: "peter",
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const lix = await openLixInMemory({
|
|
55
|
+
account: mockAccount,
|
|
56
|
+
blob: await newLixFile(),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const accounts = await lix.db
|
|
60
|
+
.selectFrom("active_account")
|
|
61
|
+
.selectAll()
|
|
62
|
+
.execute();
|
|
63
|
+
|
|
64
|
+
expect(accounts, "to be the provided account").toContainEqual(mockAccount);
|
|
65
|
+
expect(accounts, "no other active account is inserted").lengthOf(1);
|
|
66
|
+
|
|
67
|
+
await lix.db
|
|
68
|
+
.insertInto("key_value")
|
|
69
|
+
.values([{ key: "mock_key", value: "something" }])
|
|
70
|
+
.execute();
|
|
71
|
+
|
|
72
|
+
// lix automatically handles inserting the active account into the account table
|
|
73
|
+
const change = await lix.db
|
|
74
|
+
.selectFrom("change")
|
|
75
|
+
.innerJoin("change_author", "change_author.change_id", "change.id")
|
|
76
|
+
.where("schema_key", "=", "lix_key_value_table")
|
|
77
|
+
.where("entity_id", "=", "mock_key")
|
|
78
|
+
.select("change_author.account_id")
|
|
79
|
+
.executeTakeFirstOrThrow();
|
|
80
|
+
|
|
81
|
+
expect(change.account_id).toBe(mockAccount.id);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("usedFileExtensions", async () => {
|
|
85
|
+
const lix = await openLixInMemory({
|
|
86
|
+
blob: await newLixFile(),
|
|
87
|
+
});
|
|
88
|
+
await lix.db
|
|
89
|
+
.insertInto("file")
|
|
90
|
+
.values([
|
|
91
|
+
{
|
|
92
|
+
path: "/test.txt",
|
|
93
|
+
data: new Uint8Array(),
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
path: "/test2.txt",
|
|
97
|
+
data: new Uint8Array(),
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
path: "/folder/folderwithdot./doc.pdf",
|
|
101
|
+
data: new Uint8Array(),
|
|
102
|
+
},
|
|
103
|
+
])
|
|
104
|
+
.execute();
|
|
105
|
+
|
|
106
|
+
const extensions = await usedFileExtensions(lix.db);
|
|
107
|
+
expect(new Set(extensions)).toEqual(new Set(["txt", "pdf"]));
|
|
108
|
+
});
|
package/src/lix/open-lix.ts
CHANGED
|
@@ -3,10 +3,13 @@ import { loadPlugins } from "../plugin/load-plugin.js";
|
|
|
3
3
|
import { type SqliteDatabase } from "sqlite-wasm-kysely";
|
|
4
4
|
import { initDb } from "../database/init-db.js";
|
|
5
5
|
import { initFileQueueProcess } from "../file-queue/file-queue-process.js";
|
|
6
|
-
import type
|
|
6
|
+
import { sql, type Kysely } from "kysely";
|
|
7
7
|
import type { LixDatabaseSchema } from "../database/schema.js";
|
|
8
8
|
import { initSyncProcess } from "../sync/sync-process.js";
|
|
9
9
|
import type { NewKeyValue } from "../key-value/database-schema.js";
|
|
10
|
+
import { capture } from "../services/telemetry/capture.js";
|
|
11
|
+
import { ENV_VARIABLES } from "../services/env-variables/index.js";
|
|
12
|
+
import type { Account } from "../account/database-schema.js";
|
|
10
13
|
|
|
11
14
|
export type Lix = {
|
|
12
15
|
/**
|
|
@@ -30,6 +33,16 @@ export type Lix = {
|
|
|
30
33
|
* Common setup between different lix environments.
|
|
31
34
|
*/
|
|
32
35
|
export async function openLix(args: {
|
|
36
|
+
/**
|
|
37
|
+
* The account that is opening this lix.
|
|
38
|
+
*
|
|
39
|
+
* Lix will automatically set the active account to the provided account.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* const account = localStorage.getItem("account")
|
|
43
|
+
* const lix = await openLix({ account })
|
|
44
|
+
*/
|
|
45
|
+
account?: Account;
|
|
33
46
|
database: SqliteDatabase;
|
|
34
47
|
/**
|
|
35
48
|
* Usecase are lix apps that define their own file format,
|
|
@@ -65,6 +78,18 @@ export async function openLix(args: {
|
|
|
65
78
|
.execute();
|
|
66
79
|
}
|
|
67
80
|
|
|
81
|
+
if (args.account) {
|
|
82
|
+
await db.transaction().execute(async (trx) => {
|
|
83
|
+
// delete the default inserted active account from `initDb`
|
|
84
|
+
await trx.deleteFrom("active_account").execute();
|
|
85
|
+
await trx
|
|
86
|
+
.insertInto("active_account")
|
|
87
|
+
.values(args.account!)
|
|
88
|
+
.onConflict((oc) => oc.doUpdateSet(() => ({ ...args.account })))
|
|
89
|
+
.execute();
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
68
93
|
const plugins = await loadPlugins(db);
|
|
69
94
|
if (args.providePlugins && args.providePlugins.length > 0) {
|
|
70
95
|
plugins.push(...args.providePlugins);
|
|
@@ -78,9 +103,81 @@ export async function openLix(args: {
|
|
|
78
103
|
|
|
79
104
|
initSyncProcess({ lix: { db, plugin, sqlite: args.database } });
|
|
80
105
|
|
|
106
|
+
captureOpened({ db });
|
|
107
|
+
|
|
81
108
|
return {
|
|
82
109
|
db,
|
|
83
110
|
sqlite: args.database,
|
|
84
111
|
plugin,
|
|
85
112
|
};
|
|
86
113
|
}
|
|
114
|
+
|
|
115
|
+
async function captureOpened(args: { db: Kysely<LixDatabaseSchema> }) {
|
|
116
|
+
try {
|
|
117
|
+
const telemetry = await args.db
|
|
118
|
+
.selectFrom("key_value")
|
|
119
|
+
.select("value")
|
|
120
|
+
.where("key", "=", "lix_telemetry")
|
|
121
|
+
.executeTakeFirst();
|
|
122
|
+
|
|
123
|
+
if (telemetry?.value === "off") {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const activeAccount = await args.db
|
|
128
|
+
.selectFrom("active_account")
|
|
129
|
+
.select("id")
|
|
130
|
+
.executeTakeFirstOrThrow();
|
|
131
|
+
|
|
132
|
+
const lixId = await args.db
|
|
133
|
+
.selectFrom("key_value")
|
|
134
|
+
.select("value")
|
|
135
|
+
.where("key", "=", "lix_id")
|
|
136
|
+
.executeTakeFirstOrThrow();
|
|
137
|
+
|
|
138
|
+
const fileExtensions = await usedFileExtensions(args.db);
|
|
139
|
+
|
|
140
|
+
await capture("LIX-SDK lix opened", {
|
|
141
|
+
accountId: activeAccount.id,
|
|
142
|
+
lixId: lixId.value,
|
|
143
|
+
telemetryKeyValue: telemetry?.value ?? "on",
|
|
144
|
+
properties: {
|
|
145
|
+
lix_sdk_version: ENV_VARIABLES.LIX_SDK_VERSION,
|
|
146
|
+
stored_file_extensions: fileExtensions,
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
} catch {
|
|
150
|
+
// ignore
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Get all used file extensions.
|
|
156
|
+
*/
|
|
157
|
+
export async function usedFileExtensions(
|
|
158
|
+
db: Kysely<LixDatabaseSchema>
|
|
159
|
+
): Promise<any> {
|
|
160
|
+
const result = await sql`
|
|
161
|
+
WITH RECURSIVE numbers(i) AS (
|
|
162
|
+
SELECT 1
|
|
163
|
+
UNION ALL
|
|
164
|
+
SELECT i + 1 FROM numbers WHERE i < 1000 -- Limit to 1000 characters for path length
|
|
165
|
+
),
|
|
166
|
+
REVERSED AS (
|
|
167
|
+
SELECT id,
|
|
168
|
+
GROUP_CONCAT(SUBSTR(path, LENGTH(path) - i + 1, 1), '') AS reversed_path
|
|
169
|
+
FROM file, numbers
|
|
170
|
+
WHERE i <= LENGTH(path)
|
|
171
|
+
GROUP BY id, path
|
|
172
|
+
),
|
|
173
|
+
EXTENSIONS AS (
|
|
174
|
+
SELECT DISTINCT SUBSTR(path, LENGTH(path) - INSTR(reversed_path, '.') + 2) AS extension
|
|
175
|
+
FROM file
|
|
176
|
+
JOIN REVERSED ON file.id = REVERSED.id
|
|
177
|
+
WHERE INSTR(reversed_path, '.') > 0
|
|
178
|
+
)
|
|
179
|
+
SELECT extension FROM EXTENSIONS;
|
|
180
|
+
`.execute(db);
|
|
181
|
+
|
|
182
|
+
return result.rows.map((row) => (row as any).extension);
|
|
183
|
+
}
|