@lix-js/sdk 0.1.0 → 0.2.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.
Files changed (110) hide show
  1. package/dist/account/database-schema.d.ts.map +1 -1
  2. package/dist/account/database-schema.js +2 -6
  3. package/dist/account/database-schema.js.map +1 -1
  4. package/dist/account/database-schema.test.js +4 -8
  5. package/dist/account/database-schema.test.js.map +1 -1
  6. package/dist/file-queue/file-queue-process.d.ts.map +1 -1
  7. package/dist/file-queue/file-queue-process.js +4 -1
  8. package/dist/file-queue/file-queue-process.js.map +1 -1
  9. package/dist/file-queue/file-queue-process.test.js +4 -5
  10. package/dist/file-queue/file-queue-process.test.js.map +1 -1
  11. package/dist/lix/open-lix.d.ts +16 -1
  12. package/dist/lix/open-lix.d.ts.map +1 -1
  13. package/dist/lix/open-lix.js +76 -0
  14. package/dist/lix/open-lix.js.map +1 -1
  15. package/dist/lix/open-lix.test.js +54 -0
  16. package/dist/lix/open-lix.test.js.map +1 -1
  17. package/dist/services/env-variables/index.d.ts +5 -0
  18. package/dist/services/env-variables/index.d.ts.map +1 -0
  19. package/dist/services/env-variables/index.js +5 -0
  20. package/dist/services/env-variables/index.js.map +1 -0
  21. package/dist/services/telemetry/capture.d.ts +30 -0
  22. package/dist/services/telemetry/capture.d.ts.map +1 -0
  23. package/dist/services/telemetry/capture.js +71 -0
  24. package/dist/services/telemetry/capture.js.map +1 -0
  25. package/dist/services/telemetry/capture.test.d.ts +2 -0
  26. package/dist/services/telemetry/capture.test.d.ts.map +1 -0
  27. package/dist/services/telemetry/capture.test.js +37 -0
  28. package/dist/services/telemetry/capture.test.js.map +1 -0
  29. package/dist/sync/sync-process.d.ts.map +1 -1
  30. package/dist/sync/sync-process.js +11 -5
  31. package/dist/sync/sync-process.js.map +1 -1
  32. package/package.json +4 -6
  33. package/src/account/database-schema.test.ts +6 -9
  34. package/src/account/database-schema.ts +2 -6
  35. package/src/file-queue/file-queue-process.test.ts +4 -5
  36. package/src/file-queue/file-queue-process.ts +4 -1
  37. package/src/lix/open-lix.test.ts +63 -0
  38. package/src/lix/open-lix.ts +98 -1
  39. package/src/services/env-variables/create-index-file.js +35 -0
  40. package/src/services/env-variables/index.d.ts +15 -0
  41. package/src/services/telemetry/capture.test.ts +44 -0
  42. package/src/services/telemetry/capture.ts +99 -0
  43. package/src/sync/sync-process.ts +11 -6
  44. package/node_modules/@lix-js/server-api-schema/.prettierrc.json +0 -3
  45. package/node_modules/@lix-js/server-api-schema/.vscode/extensions.json +0 -3
  46. package/node_modules/@lix-js/server-api-schema/CHANGELOG.md +0 -9
  47. package/node_modules/@lix-js/server-api-schema/LICENSE +0 -21
  48. package/node_modules/@lix-js/server-api-schema/dist/schema.js +0 -0
  49. package/node_modules/@lix-js/server-api-schema/package.json +0 -21
  50. package/node_modules/@lix-js/server-api-schema/src/schema.yaml +0 -290
  51. package/node_modules/@lix-js/server-api-schema/tsconfig.json +0 -20
  52. package/node_modules/sqlite-wasm-kysely/LICENSE +0 -21
  53. package/node_modules/sqlite-wasm-kysely/README.md +0 -11
  54. package/node_modules/sqlite-wasm-kysely/dist/dialect.d.ts +0 -11
  55. package/node_modules/sqlite-wasm-kysely/dist/dialect.js +0 -13
  56. package/node_modules/sqlite-wasm-kysely/dist/dialect.js.map +0 -1
  57. package/node_modules/sqlite-wasm-kysely/dist/index.d.ts +0 -2
  58. package/node_modules/sqlite-wasm-kysely/dist/index.js +0 -3
  59. package/node_modules/sqlite-wasm-kysely/dist/index.js.map +0 -1
  60. package/node_modules/sqlite-wasm-kysely/dist/kysely/ConnectionMutex.d.ts +0 -5
  61. package/node_modules/sqlite-wasm-kysely/dist/kysely/ConnectionMutex.js +0 -34
  62. package/node_modules/sqlite-wasm-kysely/dist/kysely/ConnectionMutex.js.map +0 -1
  63. package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmConnection.d.ts +0 -8
  64. package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmConnection.js +0 -57
  65. package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmConnection.js.map +0 -1
  66. package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmDialectConfig.d.ts +0 -18
  67. package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmDialectConfig.js +0 -2
  68. package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmDialectConfig.js.map +0 -1
  69. package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmDriver.d.ts +0 -13
  70. package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmDriver.js +0 -57
  71. package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmDriver.js.map +0 -1
  72. package/node_modules/sqlite-wasm-kysely/dist/kysely/index.d.ts +0 -4
  73. package/node_modules/sqlite-wasm-kysely/dist/kysely/index.js +0 -4
  74. package/node_modules/sqlite-wasm-kysely/dist/kysely/index.js.map +0 -1
  75. package/node_modules/sqlite-wasm-kysely/dist/kysely/sqliteModule.d.ts +0 -3
  76. package/node_modules/sqlite-wasm-kysely/dist/kysely/sqliteModule.js +0 -5
  77. package/node_modules/sqlite-wasm-kysely/dist/kysely/sqliteModule.js.map +0 -1
  78. package/node_modules/sqlite-wasm-kysely/dist/util/contentFromDatabase.d.ts +0 -9
  79. package/node_modules/sqlite-wasm-kysely/dist/util/contentFromDatabase.js +0 -12
  80. package/node_modules/sqlite-wasm-kysely/dist/util/contentFromDatabase.js.map +0 -1
  81. package/node_modules/sqlite-wasm-kysely/dist/util/createInMemoryDatabase.d.ts +0 -3
  82. package/node_modules/sqlite-wasm-kysely/dist/util/createInMemoryDatabase.js +0 -22
  83. package/node_modules/sqlite-wasm-kysely/dist/util/createInMemoryDatabase.js.map +0 -1
  84. package/node_modules/sqlite-wasm-kysely/dist/util/importDatabase.d.ts +0 -7
  85. package/node_modules/sqlite-wasm-kysely/dist/util/importDatabase.js +0 -15
  86. package/node_modules/sqlite-wasm-kysely/dist/util/importDatabase.js.map +0 -1
  87. package/node_modules/sqlite-wasm-kysely/dist/util/index.d.ts +0 -5
  88. package/node_modules/sqlite-wasm-kysely/dist/util/index.js +0 -5
  89. package/node_modules/sqlite-wasm-kysely/dist/util/index.js.map +0 -1
  90. package/node_modules/sqlite-wasm-kysely/dist/util/loadDatabaseInMemory.d.ts +0 -1
  91. package/node_modules/sqlite-wasm-kysely/dist/util/loadDatabaseInMemory.js +0 -13
  92. package/node_modules/sqlite-wasm-kysely/dist/util/loadDatabaseInMemory.js.map +0 -1
  93. package/node_modules/sqlite-wasm-kysely/dist/util/sqliteWasmBinary.d.ts +0 -7
  94. package/node_modules/sqlite-wasm-kysely/dist/util/sqliteWasmBinary.js +0 -17
  95. package/node_modules/sqlite-wasm-kysely/dist/util/sqliteWasmBinary.js.map +0 -1
  96. package/node_modules/sqlite-wasm-kysely/package.json +0 -34
  97. package/node_modules/sqlite-wasm-kysely/src/dialect.ts +0 -15
  98. package/node_modules/sqlite-wasm-kysely/src/index.ts +0 -2
  99. package/node_modules/sqlite-wasm-kysely/src/kysely/ConnectionMutex.ts +0 -23
  100. package/node_modules/sqlite-wasm-kysely/src/kysely/SqliteWasmConnection.ts +0 -57
  101. package/node_modules/sqlite-wasm-kysely/src/kysely/SqliteWasmDialectConfig.ts +0 -19
  102. package/node_modules/sqlite-wasm-kysely/src/kysely/SqliteWasmDriver.ts +0 -58
  103. package/node_modules/sqlite-wasm-kysely/src/kysely/index.ts +0 -4
  104. package/node_modules/sqlite-wasm-kysely/src/kysely/sqliteModule.ts +0 -7
  105. package/node_modules/sqlite-wasm-kysely/src/util/contentFromDatabase.ts +0 -13
  106. package/node_modules/sqlite-wasm-kysely/src/util/createInMemoryDatabase.ts +0 -30
  107. package/node_modules/sqlite-wasm-kysely/src/util/importDatabase.ts +0 -34
  108. package/node_modules/sqlite-wasm-kysely/src/util/index.ts +0 -5
  109. package/node_modules/sqlite-wasm-kysely/src/util/loadDatabaseInMemory.ts +0 -13
  110. package/node_modules/sqlite-wasm-kysely/src/util/sqliteWasmBinary.ts +0 -20
@@ -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,CA6EhB"}
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
- pullAndPush().catch((e) => {
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
- }, 1000);
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;QAED,IAAI,CAAC;YACJ,6DAA6D;YAC7D,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC;gBACxC,SAAS,EAAE,GAAG,CAAC,KAAK;gBACpB,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,EAAE,EAAE,KAAK,CAAC,KAAK;aACf,CAAC,CAAC;YACH,eAAe;YACf,+EAA+E;YAC/E,eAAe;YACf,KAAK;YACL,2DAA2D;YAC3D,MAAM,YAAY,CAAC;gBAClB,SAAS,EAAE,GAAG,CAAC,KAAK;gBACpB,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,EAAE,EAAE,KAAK,CAAC,KAAK;gBACf,iBAAiB,EAAE,WAAW;aAC9B,CAAC,CAAC;QACJ,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACZ,6CAA6C;YAC7C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAC3B,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,aAAa,EAAE;gBACtC,MAAM,EAAE,MAAM;gBACd,IAAI,EAAE,MAAM,MAAM,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC;aACrC,CAAC,CACF,CAAC;YACF,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC7C,MAAM,CAAC,CAAC;YACT,CAAC;QACF,CAAC;QACD,gEAAgE;IACjE,CAAC,CAAC;IAEF,+CAA+C;IAE/C,SAAS,mBAAmB;QAC3B,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;YAC9B,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;gBACzB,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,CAAC,CAAC,CAAC;YAC3C,CAAC,CAAC,CAAC;QACJ,CAAC;QACD,UAAU,CAAC,GAAG,EAAE;YACf,mBAAmB,EAAE,CAAC;QACvB,CAAC,EAAE,IAAI,CAAC,CAAC;IACV,CAAC;IAED,mBAAmB,EAAE,CAAC;AACvB,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.1.0",
4
+ "version": "0.2.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.0"
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 in the beginning and activte account should be an anonymous account", async () => {
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
- .selectFrom("account")
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("anonymous_mock_uuid_v7");
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: "anonymous_mock_uuid_v7-2",
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 the anonymous account
38
- INSERT INTO active_account (id, name) values ('anonymous_' || uuid_v7(), '${anonymousAccountName}');
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);
@@ -104,8 +104,7 @@ test("should use queue and settled correctly", async () => {
104
104
  content: {
105
105
  text: "insert text",
106
106
  },
107
- // handles the author (which defaults to anonymous)
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(/^anonymous_/),
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(/^anonymous_/),
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(/^anonymous_/),
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
  }
@@ -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
+ });
@@ -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 { Kysely } from "kysely";
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
+ }
@@ -0,0 +1,35 @@
1
+ /* eslint-disable no-undef */
2
+ /**
3
+ * This script writes public environment variables
4
+ * to an importable env file.
5
+ *
6
+ * - The SDK must bundle this file with the rest of the SDK
7
+ * - This scripts avoids the need for a bundler
8
+ * - Must be ran before building the SDK
9
+ */
10
+
11
+ import fs from "node:fs/promises";
12
+ import url from "node:url";
13
+ import path from "node:path";
14
+
15
+ const dirname = path.dirname(url.fileURLToPath(import.meta.url));
16
+
17
+ const packageJson = JSON.parse(
18
+ await fs.readFile(path.resolve(dirname, "../../../package.json"), "utf-8")
19
+ );
20
+
21
+ await fs.writeFile(
22
+ dirname + "/index.ts",
23
+ `
24
+ export const ENV_VARIABLES = {
25
+ LIX_SDK_POSTHOG_TOKEN: ${ifDefined(process.env.LIX_SDK_POSTHOG_TOKEN)},
26
+ LIX_SDK_VERSION: ${ifDefined(packageJson.version)},
27
+ }
28
+ `
29
+ );
30
+
31
+ // console.log("✅ Created env variable index file.");
32
+
33
+ function ifDefined(value) {
34
+ return value ? `"${value}"` : undefined;
35
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Avoiding TypeScript errors before the `createIndexFile` script
3
+ * is invoked by defining the type ahead of time.
4
+ */
5
+
6
+ /**
7
+ * Env variables that are available at runtime.
8
+ */
9
+ export declare const ENV_VARIABLES: {
10
+ LIX_SDK_POSTHOG_TOKEN?: string;
11
+ /**
12
+ * As defined in the package.json
13
+ */
14
+ LIX_SDK_VERSION?: string;
15
+ };
@@ -0,0 +1,44 @@
1
+ import { expect, test, vi } from "vitest";
2
+ import { capture } from "./capture.js";
3
+
4
+ test("it should not capture if telemetry is off", async () => {
5
+ global.fetch = vi.fn(() => Promise.resolve(new Response()));
6
+
7
+ vi.mock("../env-variables/index.js", async () => {
8
+ return {
9
+ ENV_VARIABLES: {
10
+ LIX_SDK_POSTHOG_TOKEN: "mock-defined",
11
+ },
12
+ };
13
+ });
14
+
15
+ await capture("LIX-SDK lix opened", {
16
+ lixId: "test",
17
+ accountId: "test",
18
+ telemetryKeyValue: "off",
19
+ properties: {},
20
+ });
21
+
22
+ expect(global.fetch).not.toHaveBeenCalled();
23
+ });
24
+
25
+ test("it should not capture if telemetry is NOT off", async () => {
26
+ global.fetch = vi.fn(() => Promise.resolve(new Response()));
27
+
28
+ vi.mock("../env-variables/index.js", async () => {
29
+ return {
30
+ ENV_VARIABLES: {
31
+ LIX_SDK_POSTHOG_TOKEN: "mock-defined",
32
+ },
33
+ };
34
+ });
35
+
36
+ await capture("LIX-SDK lix opened", {
37
+ lixId: "test",
38
+ accountId: "test",
39
+ telemetryKeyValue: "on",
40
+ properties: {},
41
+ });
42
+
43
+ expect(global.fetch).toHaveBeenCalled();
44
+ });
@@ -0,0 +1,99 @@
1
+ import { ENV_VARIABLES } from "../env-variables/index.js";
2
+
3
+ /**
4
+ * List of telemetry events for typesafety.
5
+ *
6
+ * - prefix with `SDK` to avoid collisions with other apps
7
+ * - use past tense to indicate that the event is completed
8
+ */
9
+ type TelemetryEvent = "LIX-SDK lix opened";
10
+
11
+ /**
12
+ * Capture an event.
13
+ *
14
+ * - manually calling the PostHog API because the SDKs were not platform angostic (and generally bloated)
15
+ */
16
+ export const capture = async (
17
+ event: TelemetryEvent,
18
+ args: {
19
+ lixId: string;
20
+ accountId: string;
21
+ /**
22
+ * The value of the telemetry key-value pair.
23
+ *
24
+ * @example
25
+ * const telemetryKeyValue = await lix.db.selectFrom("key_value").select("value").where("key", "=", "lix_telemetry").executeTakeFirstOrThrow();
26
+ * await capture("LIX-SDK opened lix", { lixId: "test", accountId: "test", telemetryKeyValue: telemetryKeyValue.value, properties: {} });
27
+ */
28
+ telemetryKeyValue: string;
29
+ /**
30
+ * Please use snake_case for property names.
31
+ */
32
+ properties: Record<string, any>;
33
+ }
34
+ ): Promise<void> => {
35
+ if (ENV_VARIABLES.LIX_SDK_POSTHOG_TOKEN === undefined) {
36
+ return;
37
+ } else if (args.telemetryKeyValue === "off") {
38
+ return;
39
+ }
40
+ try {
41
+ await fetch("https://eu.posthog.com/capture/", {
42
+ method: "POST",
43
+ body: JSON.stringify({
44
+ api_key: ENV_VARIABLES.LIX_SDK_POSTHOG_TOKEN,
45
+ event,
46
+ distinct_id: args.accountId,
47
+ properties: {
48
+ $groups: { lix_id: args.lixId },
49
+ ...args.properties,
50
+ },
51
+ }),
52
+ });
53
+ await identifyLix({
54
+ lixId: args.lixId,
55
+ accountId: args.accountId,
56
+ // using the id for now as a name but can be changed in the future
57
+ // we need at least one property to make a project visible in the dashboard
58
+ properties: { name: args.lixId },
59
+ });
60
+ } catch {
61
+ //
62
+ }
63
+ };
64
+
65
+ /**
66
+ * Identifying a project is needed.
67
+ *
68
+ * Otherwise, the project will not be visible in the PostHog dashboard.
69
+ */
70
+ const identifyLix = async (args: {
71
+ lixId: string;
72
+ accountId: string;
73
+ properties: Record<string, string>;
74
+ }) => {
75
+ // do not send events if the token is not set
76
+ // (assuming this eases testing)
77
+ if (ENV_VARIABLES.LIX_SDK_POSTHOG_TOKEN === undefined) {
78
+ return;
79
+ }
80
+ try {
81
+ await fetch("https://eu.posthog.com/capture/", {
82
+ method: "POST",
83
+ body: JSON.stringify({
84
+ api_key: ENV_VARIABLES.LIX_SDK_POSTHOG_TOKEN,
85
+ event: "$groupidentify",
86
+ distinct_id: args.accountId,
87
+ properties: {
88
+ $group_type: "lix",
89
+ $group_key: args.lixId,
90
+ $group_set: {
91
+ ...args.properties,
92
+ },
93
+ },
94
+ }),
95
+ });
96
+ } catch {
97
+ //
98
+ }
99
+ };