@inlang/sdk 2.2.1 → 2.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 (29) hide show
  1. package/dist/json-schema/pattern.d.ts +1 -1
  2. package/dist/json-schema/pattern.d.ts.map +1 -1
  3. package/dist/json-schema/pattern.js.map +1 -1
  4. package/dist/project/loadProjectFromDirectory.d.ts.map +1 -1
  5. package/dist/project/loadProjectFromDirectory.js +28 -3
  6. package/dist/project/loadProjectFromDirectory.js.map +1 -1
  7. package/dist/project/loadProjectFromDirectory.test.js +53 -0
  8. package/dist/project/loadProjectFromDirectory.test.js.map +1 -1
  9. package/dist/project/loadProjectInMemory.d.ts +2 -0
  10. package/dist/project/loadProjectInMemory.d.ts.map +1 -1
  11. package/dist/project/loadProjectInMemory.js +1 -0
  12. package/dist/project/loadProjectInMemory.js.map +1 -1
  13. package/dist/project/newProject.d.ts.map +1 -1
  14. package/dist/project/newProject.js +6 -2
  15. package/dist/project/newProject.js.map +1 -1
  16. package/dist/project/newProject.test.js +10 -3
  17. package/dist/project/newProject.test.js.map +1 -1
  18. package/dist/project/saveProjectToDirectory.test.js.map +1 -1
  19. package/dist/query-utilities/selectBundleNested.d.ts +17 -17
  20. package/dist/services/env-variables/index.js +1 -1
  21. package/dist/services/env-variables/index.js.map +1 -1
  22. package/package.json +4 -3
  23. package/src/json-schema/pattern.ts +1 -1
  24. package/src/project/loadProjectFromDirectory.test.ts +66 -0
  25. package/src/project/loadProjectFromDirectory.ts +34 -3
  26. package/src/project/loadProjectInMemory.ts +3 -1
  27. package/src/project/newProject.test.ts +11 -3
  28. package/src/project/newProject.ts +7 -2
  29. package/src/project/saveProjectToDirectory.test.ts +39 -39
@@ -1,6 +1,6 @@
1
1
  export const ENV_VARIABLES = {
2
2
  PUBLIC_POSTHOG_TOKEN: "phc_m5yJZCxjOGxF8CJvP5sQ3H0d76xpnLrsmiZHduT4jDz",
3
3
  PUBLIC_INLANG_SDK_SENTRY_DSN: "https://c3d92d5d011122e525e9f9b368e0905d@o4504345873285120.ingest.us.sentry.io/4507903389335553",
4
- SDK_VERSION: "2.2.1",
4
+ SDK_VERSION: "2.3.0",
5
5
  };
6
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"/","sources":["services/env-variables/index.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,oBAAoB,EAAE,iDAAiD;IACxE,4BAA4B,EAAE,iGAAiG;IAC/H,WAAW,EAAE,OAAO;CACpB,CAAA","sourcesContent":["\nexport const ENV_VARIABLES = {\n PUBLIC_POSTHOG_TOKEN: \"phc_m5yJZCxjOGxF8CJvP5sQ3H0d76xpnLrsmiZHduT4jDz\",\n\tPUBLIC_INLANG_SDK_SENTRY_DSN: \"https://c3d92d5d011122e525e9f9b368e0905d@o4504345873285120.ingest.us.sentry.io/4507903389335553\",\n\tSDK_VERSION: \"2.2.1\",\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"/","sources":["services/env-variables/index.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,oBAAoB,EAAE,iDAAiD;IACxE,4BAA4B,EAAE,iGAAiG;IAC/H,WAAW,EAAE,OAAO;CACpB,CAAA","sourcesContent":["\nexport const ENV_VARIABLES = {\n PUBLIC_POSTHOG_TOKEN: \"phc_m5yJZCxjOGxF8CJvP5sQ3H0d76xpnLrsmiZHduT4jDz\",\n\tPUBLIC_INLANG_SDK_SENTRY_DSN: \"https://c3d92d5d011122e525e9f9b368e0905d@o4504345873285120.ingest.us.sentry.io/4507903389335553\",\n\tSDK_VERSION: \"2.3.0\",\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inlang/sdk",
3
- "version": "2.2.1",
3
+ "version": "2.3.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -29,7 +29,7 @@
29
29
  "@sinclair/typebox": "^0.31.17",
30
30
  "kysely": "^0.27.4",
31
31
  "uuid": "^10.0.0",
32
- "@lix-js/sdk": "0.4.0",
32
+ "@lix-js/sdk": "0.4.1",
33
33
  "sqlite-wasm-kysely": "0.3.0"
34
34
  },
35
35
  "devDependencies": {
@@ -38,9 +38,10 @@
38
38
  "@types/uuid": "^10.0.0",
39
39
  "@vitest/coverage-v8": "^2.0.5",
40
40
  "eslint": "^9.12.0",
41
- "typescript-eslint": "^8.9.0",
42
41
  "memfs": "4.6.0",
42
+ "prettier": "^3.5.1",
43
43
  "typescript": "^5.5.2",
44
+ "typescript-eslint": "^8.9.0",
44
45
  "vitest": "^2.0.5",
45
46
  "@opral/tsconfig": "1.1.0"
46
47
  },
@@ -38,7 +38,7 @@ export const Text = Type.Object({
38
38
  value: Type.String(),
39
39
  });
40
40
 
41
- export type LocalVariable = Static<typeof VariableReference>;
41
+ export type LocalVariable = Static<typeof LocalVariable>;
42
42
  export const LocalVariable = Type.Object({
43
43
  type: Type.Literal("local-variable"),
44
44
  name: Type.String(),
@@ -966,3 +966,69 @@ test("providing multiple plugins that have legacy loadMessages and saveMessages
966
966
  expect(mockPlugin2.importFiles).toHaveBeenCalled();
967
967
  expect(mockPlugin2.loadMessages).not.toHaveBeenCalled();
968
968
  });
969
+
970
+ // https://github.com/opral/inlang-sdk/issues/228
971
+ test("the lix id should be stable between loadings of the same project", async () => {
972
+ const mockRepo = {
973
+ "/project.inlang/settings.json": JSON.stringify({
974
+ baseLocale: "en",
975
+ locales: ["en"],
976
+ modules: [],
977
+ } satisfies ProjectSettings),
978
+ };
979
+
980
+ const fs = Volume.fromJSON(mockRepo);
981
+
982
+ const project1 = await loadProjectFromDirectory({
983
+ fs: fs as any,
984
+ path: "/project.inlang",
985
+ });
986
+
987
+ const inlangId = await project1.id.get();
988
+
989
+ const { value: lixId } = await project1.lix.db
990
+ .selectFrom("key_value")
991
+ .where("key", "=", "lix_id")
992
+ .selectAll()
993
+ .executeTakeFirstOrThrow();
994
+
995
+ // the project_id file does not exist on the first load
996
+ await saveProjectToDirectory({
997
+ fs: fs.promises as any,
998
+ path: "/project.inlang",
999
+ project: project1,
1000
+ });
1001
+
1002
+ const project2 = await loadProjectFromDirectory({
1003
+ fs: fs as any,
1004
+ path: "/project.inlang",
1005
+ });
1006
+
1007
+ const inlangId2 = await project2.id.get();
1008
+
1009
+ const { value: lixId2 } = await project2.lix.db
1010
+ .selectFrom("key_value")
1011
+ .where("key", "=", "lix_id")
1012
+ .selectAll()
1013
+ .executeTakeFirstOrThrow();
1014
+
1015
+ const project3 = await loadProjectFromDirectory({
1016
+ fs: fs as any,
1017
+ path: "/project.inlang",
1018
+ });
1019
+
1020
+ const inlangId3 = await project3.id.get();
1021
+ const { value: lixId3 } = await project3.lix.db
1022
+ .selectFrom("key_value")
1023
+ .where("key", "=", "lix_id")
1024
+ .selectAll()
1025
+ .executeTakeFirstOrThrow();
1026
+
1027
+ expect(inlangId).not.toBeUndefined();
1028
+ expect(inlangId).toBe(inlangId2);
1029
+ expect(inlangId).toBe(inlangId3);
1030
+
1031
+ expect(lixId).not.toBeUndefined();
1032
+ expect(lixId).toBe(lixId2);
1033
+ expect(lixId).toBe(lixId3);
1034
+ });
@@ -31,6 +31,22 @@ export async function loadProjectFromDirectory(
31
31
  await args.fs.promises.readFile(settingsPath, "utf8")
32
32
  ) as ProjectSettings;
33
33
 
34
+ let inlangId: string | undefined = undefined;
35
+
36
+ try {
37
+ inlangId = await args.fs.promises.readFile(
38
+ nodePath.join(args.path, "project_id"),
39
+ "utf8"
40
+ );
41
+ } catch {
42
+ // await args.fs.promises.writeFile(
43
+ // nodePath.join(args.path, "project_id"),
44
+ // ,
45
+ // { encoding: "utf8" }
46
+ // );
47
+ // file doesn't exist yet
48
+ }
49
+
34
50
  const localImport = await importLocalPlugins({
35
51
  fs: args.fs,
36
52
  settings,
@@ -49,6 +65,10 @@ export async function loadProjectFromDirectory(
49
65
  const project = await loadProjectInMemory({
50
66
  ...args,
51
67
  providePlugins: providePluginsWithLocalPlugins,
68
+ lixKeyValues: inlangId
69
+ ? // reversing the id to have distinguishable lix ids from inlang ids
70
+ [{ key: "lix_id", value: inlangId }]
71
+ : undefined,
52
72
  blob: await newProject({
53
73
  settings,
54
74
  }),
@@ -446,9 +466,20 @@ async function syncLixFsFiles(args: {
446
466
  if (lixState.state == "unknown") {
447
467
  // ADD TO FS (6)
448
468
  // create directory if not exists
449
- args.fs.mkdirSync(nodePath.dirname(nodePath.join(args.path, path)), {
450
- recursive: true,
451
- });
469
+ try {
470
+ args.fs.mkdirSync(
471
+ nodePath.dirname(nodePath.join(args.path, path)),
472
+ {
473
+ recursive: true,
474
+ }
475
+ );
476
+ } catch (e) {
477
+ // ignore if directory already exists
478
+ // https://github.com/opral/inlang-paraglide-js/issues/377
479
+ if ((e as any)?.code !== "EEXIST") {
480
+ throw e;
481
+ }
482
+ }
452
483
  // write file
453
484
  args.fs.writeFileSync(
454
485
  nodePath.join(args.path, path),
@@ -1,4 +1,4 @@
1
- import { openLixInMemory } from "@lix-js/sdk";
1
+ import { openLixInMemory, type NewKeyValue } from "@lix-js/sdk";
2
2
  import { createInMemoryDatabase, importDatabase } from "sqlite-wasm-kysely";
3
3
  import { loadProject } from "./loadProject.js";
4
4
 
@@ -8,11 +8,13 @@ import { loadProject } from "./loadProject.js";
8
8
  export async function loadProjectInMemory(
9
9
  args: {
10
10
  blob: Blob;
11
+ lixKeyValues?: NewKeyValue[];
11
12
  } & Omit<Parameters<typeof loadProject>[0], "sqlite" | "lix">
12
13
  ) {
13
14
  const lix = await openLixInMemory({
14
15
  blob: args.blob,
15
16
  account: args.account,
17
+ keyValues: args.lixKeyValues,
16
18
  providePlugins: [
17
19
  // inlangLixPluginV1
18
20
  ],
@@ -1,7 +1,6 @@
1
1
  import { expect, test } from "vitest";
2
2
  import { defaultProjectSettings, newProject } from "./newProject.js";
3
3
  import { loadProjectInMemory } from "./loadProjectInMemory.js";
4
- import { validate } from "uuid";
5
4
 
6
5
  test("it should be possible to provide settings for testing or other purposes", async () => {
7
6
  const project = await loadProjectInMemory({
@@ -26,11 +25,20 @@ test("it should be possible to create a project with default settings", async ()
26
25
  expect(settings).toStrictEqual(defaultProjectSettings);
27
26
  });
28
27
 
29
- test("it should have a uuid as project id", async () => {
28
+ // for historical reasons, inlang files introduced a project id
29
+ // before lix'es got their own id. having two ids for the same
30
+ // file is not needed anymore.
31
+ test("it should have the lix id as project id", async () => {
30
32
  const project = await loadProjectInMemory({
31
33
  blob: await newProject(),
32
34
  });
35
+ const { value: lixId } = await project.lix.db
36
+ .selectFrom("key_value")
37
+ .select("value")
38
+ .where("key", "=", "lix_id")
39
+ .executeTakeFirstOrThrow();
40
+
33
41
  const projectId = await project.id.get();
34
42
  expect(projectId).toBeDefined();
35
- expect(validate(projectId)).toBe(true);
43
+ expect(projectId).toBe(lixId);
36
44
  });
@@ -1,5 +1,4 @@
1
1
  import { newLixFile, openLixInMemory, toBlob } from "@lix-js/sdk";
2
- import { v4 } from "uuid";
3
2
  import type { ProjectSettings } from "../json-schema/settings.js";
4
3
  import {
5
4
  contentFromDatabase,
@@ -26,6 +25,12 @@ export async function newProject(args?: {
26
25
 
27
26
  const lix = await openLixInMemory({ blob: await newLixFile() });
28
27
 
28
+ const { value: lixId } = await lix.db
29
+ .selectFrom("key_value")
30
+ .select("value")
31
+ .where("key", "=", "lix_id")
32
+ .executeTakeFirstOrThrow();
33
+
29
34
  // write files to lix
30
35
  await lix.db
31
36
  .insertInto("file")
@@ -46,7 +51,7 @@ export async function newProject(args?: {
46
51
  },
47
52
  {
48
53
  path: "/project_id",
49
- data: new TextEncoder().encode(v4()),
54
+ data: new TextEncoder().encode(lixId),
50
55
  },
51
56
  ])
52
57
  .execute();
@@ -329,43 +329,43 @@ test("adds a gitignore file if it doesn't exist", async () => {
329
329
  expect(gitignore).toBe("cache");
330
330
  });
331
331
 
332
- test("uses exportFiles when both exportFiles and saveMessages are defined", async () => {
333
- const exportFilesSpy = vi.fn().mockResolvedValue([]);
334
- const saveMessagesSpy = vi.fn();
335
- const mockPlugin: InlangPlugin = {
336
- key: "mock",
337
- exportFiles: exportFilesSpy,
338
- saveMessages: saveMessagesSpy,
339
- };
340
- const volume = Volume.fromJSON({});
341
- const project = await loadProjectInMemory({
342
- blob: await newProject(),
343
- providePlugins: [mockPlugin],
344
- });
345
- await saveProjectToDirectory({
346
- path: "/foo/project.inlang",
347
- fs: volume.promises as any,
348
- project,
349
- });
350
- expect(exportFilesSpy).toHaveBeenCalled();
351
- expect(saveMessagesSpy).not.toHaveBeenCalled();
352
- });
332
+ test("uses exportFiles when both exportFiles and saveMessages are defined", async () => {
333
+ const exportFilesSpy = vi.fn().mockResolvedValue([]);
334
+ const saveMessagesSpy = vi.fn();
335
+ const mockPlugin: InlangPlugin = {
336
+ key: "mock",
337
+ exportFiles: exportFilesSpy,
338
+ saveMessages: saveMessagesSpy,
339
+ };
340
+ const volume = Volume.fromJSON({});
341
+ const project = await loadProjectInMemory({
342
+ blob: await newProject(),
343
+ providePlugins: [mockPlugin],
344
+ });
345
+ await saveProjectToDirectory({
346
+ path: "/foo/project.inlang",
347
+ fs: volume.promises as any,
348
+ project,
349
+ });
350
+ expect(exportFilesSpy).toHaveBeenCalled();
351
+ expect(saveMessagesSpy).not.toHaveBeenCalled();
352
+ });
353
353
 
354
- test("uses saveMessages when exportFiles is not defined", async () => {
355
- const saveMessagesSpy = vi.fn().mockResolvedValue([]);
356
- const mockPlugin: InlangPlugin = {
357
- key: "mock",
358
- saveMessages: saveMessagesSpy,
359
- };
360
- const volume = Volume.fromJSON({});
361
- const project = await loadProjectInMemory({
362
- blob: await newProject(),
363
- providePlugins: [mockPlugin],
364
- });
365
- await saveProjectToDirectory({
366
- path: "/foo/project.inlang",
367
- fs: volume.promises as any,
368
- project,
369
- });
370
- expect(saveMessagesSpy).toHaveBeenCalled();
371
- });
354
+ test("uses saveMessages when exportFiles is not defined", async () => {
355
+ const saveMessagesSpy = vi.fn().mockResolvedValue([]);
356
+ const mockPlugin: InlangPlugin = {
357
+ key: "mock",
358
+ saveMessages: saveMessagesSpy,
359
+ };
360
+ const volume = Volume.fromJSON({});
361
+ const project = await loadProjectInMemory({
362
+ blob: await newProject(),
363
+ providePlugins: [mockPlugin],
364
+ });
365
+ await saveProjectToDirectory({
366
+ path: "/foo/project.inlang",
367
+ fs: volume.promises as any,
368
+ project,
369
+ });
370
+ expect(saveMessagesSpy).toHaveBeenCalled();
371
+ });