@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.
Files changed (121) 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/database/apply-schema.js +2 -2
  7. package/dist/database/init-db.test.js +3 -3
  8. package/dist/database/init-db.test.js.map +1 -1
  9. package/dist/file-queue/file-queue-process.d.ts.map +1 -1
  10. package/dist/file-queue/file-queue-process.js +4 -1
  11. package/dist/file-queue/file-queue-process.js.map +1 -1
  12. package/dist/file-queue/file-queue-process.test.js +4 -5
  13. package/dist/file-queue/file-queue-process.test.js.map +1 -1
  14. package/dist/lix/open-lix.d.ts +16 -1
  15. package/dist/lix/open-lix.d.ts.map +1 -1
  16. package/dist/lix/open-lix.js +76 -0
  17. package/dist/lix/open-lix.js.map +1 -1
  18. package/dist/lix/open-lix.test.js +54 -0
  19. package/dist/lix/open-lix.test.js.map +1 -1
  20. package/dist/query-filter/change-has-label.d.ts +2 -2
  21. package/dist/query-filter/change-has-label.js +2 -2
  22. package/dist/query-filter/change-set-has-label.d.ts +2 -2
  23. package/dist/query-filter/change-set-has-label.js +2 -2
  24. package/dist/services/env-variables/index.d.ts +5 -0
  25. package/dist/services/env-variables/index.d.ts.map +1 -0
  26. package/dist/services/env-variables/index.js +5 -0
  27. package/dist/services/env-variables/index.js.map +1 -0
  28. package/dist/services/telemetry/capture.d.ts +30 -0
  29. package/dist/services/telemetry/capture.d.ts.map +1 -0
  30. package/dist/services/telemetry/capture.js +71 -0
  31. package/dist/services/telemetry/capture.js.map +1 -0
  32. package/dist/services/telemetry/capture.test.d.ts +2 -0
  33. package/dist/services/telemetry/capture.test.d.ts.map +1 -0
  34. package/dist/services/telemetry/capture.test.js +37 -0
  35. package/dist/services/telemetry/capture.test.js.map +1 -0
  36. package/dist/sync/sync-process.d.ts.map +1 -1
  37. package/dist/sync/sync-process.js +11 -5
  38. package/dist/sync/sync-process.js.map +1 -1
  39. package/package.json +4 -6
  40. package/src/account/database-schema.test.ts +6 -9
  41. package/src/account/database-schema.ts +2 -6
  42. package/src/database/apply-schema.ts +2 -2
  43. package/src/database/init-db.test.ts +3 -3
  44. package/src/file-queue/file-queue-process.test.ts +4 -5
  45. package/src/file-queue/file-queue-process.ts +4 -1
  46. package/src/lix/open-lix.test.ts +63 -0
  47. package/src/lix/open-lix.ts +98 -1
  48. package/src/query-filter/change-has-label.ts +2 -2
  49. package/src/query-filter/change-set-has-label.ts +2 -2
  50. package/src/services/env-variables/create-index-file.js +35 -0
  51. package/src/services/env-variables/index.d.ts +15 -0
  52. package/src/services/telemetry/capture.test.ts +44 -0
  53. package/src/services/telemetry/capture.ts +99 -0
  54. package/src/sync/sync-process.ts +11 -6
  55. package/node_modules/@lix-js/server-api-schema/.prettierrc.json +0 -3
  56. package/node_modules/@lix-js/server-api-schema/.vscode/extensions.json +0 -3
  57. package/node_modules/@lix-js/server-api-schema/CHANGELOG.md +0 -9
  58. package/node_modules/@lix-js/server-api-schema/LICENSE +0 -21
  59. package/node_modules/@lix-js/server-api-schema/dist/schema.js +0 -0
  60. package/node_modules/@lix-js/server-api-schema/package.json +0 -21
  61. package/node_modules/@lix-js/server-api-schema/src/schema.yaml +0 -290
  62. package/node_modules/@lix-js/server-api-schema/tsconfig.json +0 -20
  63. package/node_modules/sqlite-wasm-kysely/LICENSE +0 -21
  64. package/node_modules/sqlite-wasm-kysely/README.md +0 -11
  65. package/node_modules/sqlite-wasm-kysely/dist/dialect.d.ts +0 -11
  66. package/node_modules/sqlite-wasm-kysely/dist/dialect.js +0 -13
  67. package/node_modules/sqlite-wasm-kysely/dist/dialect.js.map +0 -1
  68. package/node_modules/sqlite-wasm-kysely/dist/index.d.ts +0 -2
  69. package/node_modules/sqlite-wasm-kysely/dist/index.js +0 -3
  70. package/node_modules/sqlite-wasm-kysely/dist/index.js.map +0 -1
  71. package/node_modules/sqlite-wasm-kysely/dist/kysely/ConnectionMutex.d.ts +0 -5
  72. package/node_modules/sqlite-wasm-kysely/dist/kysely/ConnectionMutex.js +0 -34
  73. package/node_modules/sqlite-wasm-kysely/dist/kysely/ConnectionMutex.js.map +0 -1
  74. package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmConnection.d.ts +0 -8
  75. package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmConnection.js +0 -57
  76. package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmConnection.js.map +0 -1
  77. package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmDialectConfig.d.ts +0 -18
  78. package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmDialectConfig.js +0 -2
  79. package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmDialectConfig.js.map +0 -1
  80. package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmDriver.d.ts +0 -13
  81. package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmDriver.js +0 -57
  82. package/node_modules/sqlite-wasm-kysely/dist/kysely/SqliteWasmDriver.js.map +0 -1
  83. package/node_modules/sqlite-wasm-kysely/dist/kysely/index.d.ts +0 -4
  84. package/node_modules/sqlite-wasm-kysely/dist/kysely/index.js +0 -4
  85. package/node_modules/sqlite-wasm-kysely/dist/kysely/index.js.map +0 -1
  86. package/node_modules/sqlite-wasm-kysely/dist/kysely/sqliteModule.d.ts +0 -3
  87. package/node_modules/sqlite-wasm-kysely/dist/kysely/sqliteModule.js +0 -5
  88. package/node_modules/sqlite-wasm-kysely/dist/kysely/sqliteModule.js.map +0 -1
  89. package/node_modules/sqlite-wasm-kysely/dist/util/contentFromDatabase.d.ts +0 -9
  90. package/node_modules/sqlite-wasm-kysely/dist/util/contentFromDatabase.js +0 -12
  91. package/node_modules/sqlite-wasm-kysely/dist/util/contentFromDatabase.js.map +0 -1
  92. package/node_modules/sqlite-wasm-kysely/dist/util/createInMemoryDatabase.d.ts +0 -3
  93. package/node_modules/sqlite-wasm-kysely/dist/util/createInMemoryDatabase.js +0 -22
  94. package/node_modules/sqlite-wasm-kysely/dist/util/createInMemoryDatabase.js.map +0 -1
  95. package/node_modules/sqlite-wasm-kysely/dist/util/importDatabase.d.ts +0 -7
  96. package/node_modules/sqlite-wasm-kysely/dist/util/importDatabase.js +0 -15
  97. package/node_modules/sqlite-wasm-kysely/dist/util/importDatabase.js.map +0 -1
  98. package/node_modules/sqlite-wasm-kysely/dist/util/index.d.ts +0 -5
  99. package/node_modules/sqlite-wasm-kysely/dist/util/index.js +0 -5
  100. package/node_modules/sqlite-wasm-kysely/dist/util/index.js.map +0 -1
  101. package/node_modules/sqlite-wasm-kysely/dist/util/loadDatabaseInMemory.d.ts +0 -1
  102. package/node_modules/sqlite-wasm-kysely/dist/util/loadDatabaseInMemory.js +0 -13
  103. package/node_modules/sqlite-wasm-kysely/dist/util/loadDatabaseInMemory.js.map +0 -1
  104. package/node_modules/sqlite-wasm-kysely/dist/util/sqliteWasmBinary.d.ts +0 -7
  105. package/node_modules/sqlite-wasm-kysely/dist/util/sqliteWasmBinary.js +0 -17
  106. package/node_modules/sqlite-wasm-kysely/dist/util/sqliteWasmBinary.js.map +0 -1
  107. package/node_modules/sqlite-wasm-kysely/package.json +0 -34
  108. package/node_modules/sqlite-wasm-kysely/src/dialect.ts +0 -15
  109. package/node_modules/sqlite-wasm-kysely/src/index.ts +0 -2
  110. package/node_modules/sqlite-wasm-kysely/src/kysely/ConnectionMutex.ts +0 -23
  111. package/node_modules/sqlite-wasm-kysely/src/kysely/SqliteWasmConnection.ts +0 -57
  112. package/node_modules/sqlite-wasm-kysely/src/kysely/SqliteWasmDialectConfig.ts +0 -19
  113. package/node_modules/sqlite-wasm-kysely/src/kysely/SqliteWasmDriver.ts +0 -58
  114. package/node_modules/sqlite-wasm-kysely/src/kysely/index.ts +0 -4
  115. package/node_modules/sqlite-wasm-kysely/src/kysely/sqliteModule.ts +0 -7
  116. package/node_modules/sqlite-wasm-kysely/src/util/contentFromDatabase.ts +0 -13
  117. package/node_modules/sqlite-wasm-kysely/src/util/createInMemoryDatabase.ts +0 -30
  118. package/node_modules/sqlite-wasm-kysely/src/util/importDatabase.ts +0 -34
  119. package/node_modules/sqlite-wasm-kysely/src/util/index.ts +0 -5
  120. package/node_modules/sqlite-wasm-kysely/src/util/loadDatabaseInMemory.ts +0 -13
  121. 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("confirmed"))
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("confirmed")))
17
+ * .where((eb) => eb.not(changeSetHasLabel("checkpoint")))
18
18
  * .selectAll()
19
19
  * .execute();
20
20
  * ```
@@ -0,0 +1,5 @@
1
+ export declare const ENV_VARIABLES: {
2
+ LIX_SDK_POSTHOG_TOKEN: undefined;
3
+ LIX_SDK_VERSION: string;
4
+ };
5
+ //# sourceMappingURL=index.d.ts.map
@@ -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,5 @@
1
+ export const ENV_VARIABLES = {
2
+ LIX_SDK_POSTHOG_TOKEN: undefined,
3
+ LIX_SDK_VERSION: "0.2.0",
4
+ };
5
+ //# sourceMappingURL=index.js.map
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=capture.test.d.ts.map
@@ -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,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.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.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);
@@ -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., 'confirmed', 'reviewed'
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 ('confirmed');
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 confirmed label should be created if it doesn't exist", async () => {
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", "=", "confirmed")
374
+ .where("name", "=", "checkpoint")
375
375
  .executeTakeFirst();
376
376
 
377
377
  expect(tag).toMatchObject({
378
- name: "confirmed",
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
- // 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
+ }