@inlang/sdk 0.22.0 → 0.24.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 (46) hide show
  1. package/README.md +2 -2
  2. package/dist/adapter/solidAdapter.test.js +13 -6
  3. package/dist/createNodeishFsWithWatcher.js +1 -1
  4. package/dist/env-variables/index.d.ts +4 -0
  5. package/dist/env-variables/index.d.ts.map +1 -0
  6. package/dist/env-variables/index.js +3 -0
  7. package/dist/listProjects.d.ts.map +1 -1
  8. package/dist/listProjects.js +15 -9
  9. package/dist/listProjects.test.js +14 -1
  10. package/dist/loadProject.d.ts +28 -9
  11. package/dist/loadProject.d.ts.map +1 -1
  12. package/dist/loadProject.js +49 -50
  13. package/dist/loadProject.test.js +70 -33
  14. package/dist/migrations/maybeCreateFirstProjectId.d.ts +16 -0
  15. package/dist/migrations/maybeCreateFirstProjectId.d.ts.map +1 -0
  16. package/dist/migrations/maybeCreateFirstProjectId.js +37 -0
  17. package/dist/migrations/maybeCreateFirstProjectId.test.d.ts +2 -0
  18. package/dist/migrations/maybeCreateFirstProjectId.test.d.ts.map +1 -0
  19. package/dist/migrations/maybeCreateFirstProjectId.test.js +27 -0
  20. package/dist/migrations/migrateToDirectory.d.ts +1 -1
  21. package/dist/migrations/migrateToDirectory.js +3 -3
  22. package/dist/telemetry/capture.d.ts +21 -0
  23. package/dist/telemetry/capture.d.ts.map +1 -0
  24. package/dist/telemetry/capture.js +39 -0
  25. package/package.json +13 -12
  26. package/src/adapter/solidAdapter.test.ts +13 -6
  27. package/src/createNodeishFsWithWatcher.ts +1 -1
  28. package/src/env-variables/.prettierignore +1 -0
  29. package/src/env-variables/createIndexFile.js +28 -0
  30. package/src/env-variables/index.d.ts +13 -0
  31. package/src/listProjects.test.ts +21 -2
  32. package/src/listProjects.ts +14 -7
  33. package/src/loadProject.test.ts +73 -33
  34. package/src/loadProject.ts +91 -48
  35. package/src/migrations/maybeCreateFirstProjectId.test.ts +34 -0
  36. package/src/migrations/maybeCreateFirstProjectId.ts +43 -0
  37. package/src/migrations/migrateToDirectory.ts +3 -3
  38. package/src/telemetry/capture.ts +49 -0
  39. package/dist/generateProjectId.d.ts +0 -3
  40. package/dist/generateProjectId.d.ts.map +0 -1
  41. package/dist/generateProjectId.js +0 -11
  42. package/dist/generateProjectId.test.d.ts +0 -2
  43. package/dist/generateProjectId.test.d.ts.map +0 -1
  44. package/dist/generateProjectId.test.js +0 -18
  45. package/src/generateProjectId.test.ts +0 -22
  46. package/src/generateProjectId.ts +0 -14
@@ -5,7 +5,12 @@ import { LoadProjectInvalidArgument, ProjectSettingsFileJSONSyntaxError, Project
5
5
  import { createNodeishMemoryFs, normalizePath } from "@lix-js/fs";
6
6
  import { createMessage } from "./test-utilities/createMessage.js";
7
7
  import { tryCatch } from "@inlang/result";
8
- import { mockRepo } from "@lix-js/client";
8
+ import { mockRepo, openRepository } from "@lix-js/client";
9
+ import {} from "@lix-js/fs";
10
+ // eslint-disable-next-line no-restricted-imports -- test
11
+ import { readFileSync } from "node:fs";
12
+ // eslint-disable-next-line no-restricted-imports -- test
13
+ import { resolve } from "node:path";
9
14
  // ------------------------------------------------------------------------------------------------
10
15
  const getValue = (subscribable) => {
11
16
  let value;
@@ -80,6 +85,13 @@ const mockMessageLintRule = {
80
85
  const _import = async (name) => ({
81
86
  default: name === "plugin.js" ? mockPlugin : mockMessageLintRule,
82
87
  });
88
+ async function openCiTestRepo() {
89
+ return await mockRepo({
90
+ fromSnapshot: JSON.parse(readFileSync(resolve(__dirname, "../mocks/ci-test-repo-no-shallow.json"), {
91
+ encoding: "utf-8",
92
+ })),
93
+ });
94
+ }
83
95
  // ------------------------------------------------------------------------------------------------
84
96
  /**
85
97
  * Dear Developers,
@@ -89,15 +101,17 @@ const _import = async (name) => ({
89
101
  */
90
102
  it("should throw if a project (path) does not have a name", async () => {
91
103
  const fs = createNodeishMemoryFs();
104
+ const repo = await openRepository("file://", { nodeishFs: fs });
92
105
  const project = await tryCatch(() => loadProject({
93
106
  projectPath: "/source-code/.inlang",
94
- nodeishFs: fs,
107
+ repo,
95
108
  _import,
96
109
  }));
97
110
  expect(project.error).toBeInstanceOf(LoadProjectInvalidArgument);
98
111
  });
99
112
  it("should throw if a project path does not end with .inlang", async () => {
100
113
  const fs = createNodeishMemoryFs();
114
+ const repo = await openRepository("file://", { nodeishFs: fs });
101
115
  const invalidPaths = [
102
116
  "/source-code/frontend.inlang/settings",
103
117
  "/source-code/frontend.inlang/settings.json",
@@ -106,7 +120,7 @@ it("should throw if a project path does not end with .inlang", async () => {
106
120
  for (const invalidPath of invalidPaths) {
107
121
  const project = await tryCatch(() => loadProject({
108
122
  projectPath: invalidPath,
109
- nodeishFs: fs,
123
+ repo,
110
124
  _import,
111
125
  }));
112
126
  expect(project.error).toBeInstanceOf(LoadProjectInvalidArgument);
@@ -115,16 +129,17 @@ it("should throw if a project path does not end with .inlang", async () => {
115
129
  describe("initialization", () => {
116
130
  it("should throw if projectPath is not an absolute path", async () => {
117
131
  const fs = createNodeishMemoryFs();
132
+ const repo = await openRepository("file://", { nodeishFs: fs });
118
133
  const result = await tryCatch(() => loadProject({
119
134
  projectPath: "relative/path",
120
- nodeishFs: fs,
135
+ repo,
121
136
  _import,
122
137
  }));
123
138
  expect(result.error).toBeInstanceOf(LoadProjectInvalidArgument);
124
139
  expect(result.data).toBeUndefined();
125
140
  });
126
141
  it("should generate projectId on missing projectid", async () => {
127
- const repo = await mockRepo();
142
+ const repo = await openCiTestRepo();
128
143
  const existing = await repo.nodeishFs
129
144
  .readFile("/project.inlang/project_id", {
130
145
  encoding: "utf-8",
@@ -136,7 +151,6 @@ describe("initialization", () => {
136
151
  expect(existing.error.code).toBe("ENOENT");
137
152
  const result = await tryCatch(() => loadProject({
138
153
  projectPath: "/project.inlang",
139
- nodeishFs: repo.nodeishFs,
140
154
  repo,
141
155
  _import,
142
156
  }));
@@ -147,16 +161,15 @@ describe("initialization", () => {
147
161
  .catch((error) => {
148
162
  return { error };
149
163
  });
150
- expect(newId).toBe("7cd6c2b7cf12febf99496408917123fdfe158b6bc442914f5fb42aa74346bd50");
164
+ expect(newId).toBe("aef225403be8b526dfb492a4617fd59d8181e8fef2c7f4aff56ab299046e36ed");
151
165
  expect(result.error).toBeUndefined();
152
166
  expect(result.data).toBeDefined();
153
167
  });
154
168
  it("should reuse projectId on existing projectid", async () => {
155
- const repo = await mockRepo();
169
+ const repo = await openCiTestRepo();
156
170
  repo.nodeishFs.writeFile("/project.inlang/project_id", "testId");
157
171
  const result = await tryCatch(() => loadProject({
158
172
  projectPath: "/project.inlang",
159
- nodeishFs: repo.nodeishFs,
160
173
  repo,
161
174
  _import,
162
175
  }));
@@ -175,9 +188,10 @@ describe("initialization", () => {
175
188
  const fs = createNodeishMemoryFs();
176
189
  fs.mkdir("C:\\Users\\user\\project.inlang", { recursive: true });
177
190
  fs.writeFile("C:\\Users\\user\\project.inlang\\settings.json", JSON.stringify(settings));
191
+ const repo = await openRepository("file://", { nodeishFs: fs });
178
192
  const result = await tryCatch(() => loadProject({
179
193
  projectPath: "C:\\Users\\user\\project.inlang",
180
- nodeishFs: fs,
194
+ repo,
181
195
  _import,
182
196
  }));
183
197
  expect(result.error).toBeUndefined();
@@ -187,9 +201,10 @@ describe("initialization", () => {
187
201
  it("should return an error if settings file is not found", async () => {
188
202
  const fs = createNodeishMemoryFs();
189
203
  fs.mkdir("/user/project", { recursive: true });
204
+ const repo = await openRepository("file://", { nodeishFs: fs });
190
205
  const project = await loadProject({
191
206
  projectPath: "/user/non-existend-project.inlang",
192
- nodeishFs: fs,
207
+ repo,
193
208
  _import,
194
209
  });
195
210
  expect(project.errors()[0]).toBeInstanceOf(ProjectSettingsFileNotFoundError);
@@ -198,9 +213,10 @@ describe("initialization", () => {
198
213
  const fs = await createNodeishMemoryFs();
199
214
  await fs.mkdir("/user/project.inlang", { recursive: true });
200
215
  await fs.writeFile("/user/project.inlang/settings.json", "invalid json");
216
+ const repo = await openRepository("file://", { nodeishFs: fs });
201
217
  const project = await loadProject({
202
218
  projectPath: "/user/project.inlang",
203
- nodeishFs: fs,
219
+ repo,
204
220
  _import,
205
221
  });
206
222
  expect(project.errors()[0]).toBeInstanceOf(ProjectSettingsFileJSONSyntaxError);
@@ -209,9 +225,10 @@ describe("initialization", () => {
209
225
  const fs = await createNodeishMemoryFs();
210
226
  await fs.mkdir("/user/project.inlang", { recursive: true });
211
227
  await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify({}));
228
+ const repo = await openRepository("file://", { nodeishFs: fs });
212
229
  const project = await loadProject({
213
230
  projectPath: "/user/project.inlang",
214
- nodeishFs: fs,
231
+ repo,
215
232
  _import,
216
233
  });
217
234
  expect(project.errors()[0]).toBeInstanceOf(ProjectSettingsInvalidError);
@@ -220,9 +237,10 @@ describe("initialization", () => {
220
237
  const fs = await createNodeishMemoryFs();
221
238
  await fs.mkdir("/user/project.inlang", { recursive: true });
222
239
  await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
240
+ const repo = await openRepository("file://", { nodeishFs: fs });
223
241
  const project = await loadProject({
224
242
  projectPath: "/user/project.inlang",
225
- nodeishFs: fs,
243
+ repo,
226
244
  _import,
227
245
  });
228
246
  expect(project.settings()).toStrictEqual(settings);
@@ -232,9 +250,10 @@ describe("initialization", () => {
232
250
  const settingsWithDeifferentFormatting = JSON.stringify(settings, undefined, 4);
233
251
  await fs.mkdir("/user/project.inlang", { recursive: true });
234
252
  await fs.writeFile("/user/project.inlang/settings.json", settingsWithDeifferentFormatting);
253
+ const repo = await openRepository("file://", { nodeishFs: fs });
235
254
  const project = await loadProject({
236
255
  projectPath: "/user/project.inlang",
237
- nodeishFs: fs,
256
+ repo,
238
257
  _import,
239
258
  });
240
259
  const settingsOnDisk = await fs.readFile("/user/project.inlang/settings.json", {
@@ -258,9 +277,10 @@ describe("initialization", () => {
258
277
  const fs = createNodeishMemoryFs();
259
278
  await fs.mkdir("/user/project.inlang", { recursive: true });
260
279
  await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
280
+ const repo = await openRepository("file://", { nodeishFs: fs });
261
281
  const project = await loadProject({
262
282
  projectPath: "/user/project.inlang",
263
- nodeishFs: fs,
283
+ repo,
264
284
  _import: $badImport,
265
285
  });
266
286
  expect(project.errors()).not.toHaveLength(0);
@@ -286,9 +306,10 @@ describe("functionality", () => {
286
306
  const fs = await createNodeishMemoryFs();
287
307
  await fs.mkdir("/user/project.inlang", { recursive: true });
288
308
  await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
309
+ const repo = await openRepository("file://", { nodeishFs: fs });
289
310
  const project = await loadProject({
290
311
  projectPath: "/user/project.inlang",
291
- nodeishFs: fs,
312
+ repo,
292
313
  _import,
293
314
  });
294
315
  expect(getValue(project.settings)).toStrictEqual(settings);
@@ -297,9 +318,10 @@ describe("functionality", () => {
297
318
  const fs = await createNodeishMemoryFs();
298
319
  await fs.mkdir("/user/project.inlang", { recursive: true });
299
320
  await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
321
+ const repo = await openRepository("file://", { nodeishFs: fs });
300
322
  const project = await loadProject({
301
323
  projectPath: "/user/project.inlang",
302
- nodeishFs: fs,
324
+ repo,
303
325
  _import,
304
326
  });
305
327
  expect(project.settings()).toStrictEqual(settings);
@@ -319,9 +341,10 @@ describe("functionality", () => {
319
341
  const fs = await createNodeishMemoryFs();
320
342
  await fs.mkdir("/user/project.inlang", { recursive: true });
321
343
  await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
344
+ const repo = await openRepository("file://", { nodeishFs: fs });
322
345
  const project = await loadProject({
323
346
  projectPath: "/user/project.inlang",
324
- nodeishFs: fs,
347
+ repo,
325
348
  _import,
326
349
  });
327
350
  const result = project.setSettings({});
@@ -337,9 +360,10 @@ describe("functionality", () => {
337
360
  modules: [],
338
361
  };
339
362
  await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
363
+ const repo = await openRepository("file://", { nodeishFs: fs });
340
364
  const project = await loadProject({
341
365
  projectPath: "/user/project.inlang",
342
- nodeishFs: fs,
366
+ repo,
343
367
  _import,
344
368
  });
345
369
  expect(project.errors()).toHaveLength(1);
@@ -349,9 +373,10 @@ describe("functionality", () => {
349
373
  const fs = await createNodeishMemoryFs();
350
374
  await fs.mkdir("/user/project.inlang", { recursive: true });
351
375
  await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
376
+ const repo = await openRepository("file://", { nodeishFs: fs });
352
377
  const project = await loadProject({
353
378
  projectPath: "/user/project.inlang",
354
- nodeishFs: fs,
379
+ repo,
355
380
  _import,
356
381
  });
357
382
  const before = await fs.readFile("/user/project.inlang/settings.json", { encoding: "utf-8" });
@@ -376,9 +401,10 @@ describe("functionality", () => {
376
401
  };
377
402
  await fs.mkdir("/user/project.inlang", { recursive: true });
378
403
  await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
404
+ const repo = await openRepository("file://", { nodeishFs: fs });
379
405
  const project = await loadProject({
380
406
  projectPath: "/user/project.inlang",
381
- nodeishFs: fs,
407
+ repo,
382
408
  _import,
383
409
  });
384
410
  expect(project.installed.plugins()[0]).toStrictEqual({
@@ -404,9 +430,10 @@ describe("functionality", () => {
404
430
  };
405
431
  await fs.mkdir("/user/project.inlang", { recursive: true });
406
432
  await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
433
+ const repo = await openRepository("file://", { nodeishFs: fs });
407
434
  const project = await loadProject({
408
435
  projectPath: "/user/project.inlang",
409
- nodeishFs: fs,
436
+ repo,
410
437
  _import,
411
438
  });
412
439
  expect(project.installed.messageLintRules()[0]?.level).toBe("warning");
@@ -439,6 +466,7 @@ describe("functionality", () => {
439
466
  languageTags: ["en"],
440
467
  modules: ["plugin.js", "lintRule.js"],
441
468
  }));
469
+ const repo = await openRepository("file://", { nodeishFs: fs });
442
470
  const _import = async (name) => {
443
471
  return {
444
472
  default: name === "plugin.js" ? _mockPlugin : _mockLintRule,
@@ -446,7 +474,7 @@ describe("functionality", () => {
446
474
  };
447
475
  const project = await loadProject({
448
476
  projectPath: "/user/project.inlang",
449
- nodeishFs: fs,
477
+ repo,
450
478
  _import,
451
479
  });
452
480
  await new Promise((resolve) => setTimeout(resolve, 510));
@@ -481,6 +509,7 @@ describe("functionality", () => {
481
509
  languageTags: ["en"],
482
510
  modules: ["plugin.js", "lintRule.js"],
483
511
  }));
512
+ const repo = await openRepository("file://", { nodeishFs: fs });
484
513
  const _import = async (name) => {
485
514
  return {
486
515
  default: name === "plugin.js" ? _mockPlugin : _mockLintRule,
@@ -488,7 +517,7 @@ describe("functionality", () => {
488
517
  };
489
518
  const project = await loadProject({
490
519
  projectPath: "/user/project.inlang",
491
- nodeishFs: fs,
520
+ repo,
492
521
  _import,
493
522
  });
494
523
  await new Promise((resolve) => setTimeout(resolve, 510));
@@ -500,9 +529,10 @@ describe("functionality", () => {
500
529
  const fs = await createNodeishMemoryFs();
501
530
  await fs.mkdir("/user/project.inlang", { recursive: true });
502
531
  await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
532
+ const repo = await openRepository("file://", { nodeishFs: fs });
503
533
  const project = await loadProject({
504
534
  projectPath: "/user/project.inlang",
505
- nodeishFs: fs,
535
+ repo,
506
536
  _import,
507
537
  });
508
538
  project.errors.subscribe((errors) => {
@@ -515,9 +545,10 @@ describe("functionality", () => {
515
545
  const fs = await createNodeishMemoryFs();
516
546
  await fs.mkdir("/user/project.inlang", { recursive: true });
517
547
  await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
548
+ const repo = await openRepository("file://", { nodeishFs: fs });
518
549
  const project = await loadProject({
519
550
  projectPath: "/user/project.inlang",
520
- nodeishFs: fs,
551
+ repo,
521
552
  _import,
522
553
  });
523
554
  project.customApi.subscribe((api) => {
@@ -530,9 +561,10 @@ describe("functionality", () => {
530
561
  const fs = await createNodeishMemoryFs();
531
562
  await fs.mkdir("/user/project.inlang", { recursive: true });
532
563
  await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
564
+ const repo = await openRepository("file://", { nodeishFs: fs });
533
565
  const project = await loadProject({
534
566
  projectPath: "/user/project.inlang",
535
- nodeishFs: fs,
567
+ repo,
536
568
  _import,
537
569
  });
538
570
  expect(Object.values(project.query.messages.getAll())).toEqual(exampleMessages);
@@ -552,6 +584,7 @@ describe("functionality", () => {
552
584
  await fs.mkdir("/user/project.inlang", { recursive: true });
553
585
  await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
554
586
  await fs.mkdir("./resources");
587
+ const repo = await openRepository("file://", { nodeishFs: fs });
555
588
  const mockSaveFn = vi.fn();
556
589
  const _mockPlugin = {
557
590
  id: "plugin.project.json",
@@ -567,7 +600,7 @@ describe("functionality", () => {
567
600
  };
568
601
  const project = await loadProject({
569
602
  projectPath: "/user/project.inlang",
570
- nodeishFs: fs,
603
+ repo,
571
604
  _import,
572
605
  });
573
606
  await project.query.messages.upsert({
@@ -713,6 +746,7 @@ describe("functionality", () => {
713
746
  };
714
747
  await fs.mkdir("./project.inlang", { recursive: true });
715
748
  await fs.writeFile("./project.inlang/settings.json", JSON.stringify(settings));
749
+ const repo = await openRepository("file://", { nodeishFs: fs });
716
750
  const mockSaveFn = vi.fn();
717
751
  const _mockPlugin = {
718
752
  id: "plugin.placeholder.name",
@@ -732,7 +766,7 @@ describe("functionality", () => {
732
766
  };
733
767
  const project = await loadProject({
734
768
  projectPath: "/project.inlang",
735
- nodeishFs: fs,
769
+ repo,
736
770
  _import,
737
771
  });
738
772
  project.query.messages.create({ data: createMessage("fourth", { en: "fourth message" }) });
@@ -746,9 +780,10 @@ describe("functionality", () => {
746
780
  const fs = await createNodeishMemoryFs();
747
781
  await fs.mkdir("/user/project", { recursive: true });
748
782
  await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings));
783
+ const repo = await openRepository("file://", { nodeishFs: fs });
749
784
  const project = await loadProject({
750
785
  projectPath: "/user/project/project.inlang.json",
751
- nodeishFs: fs,
786
+ repo,
752
787
  _import,
753
788
  });
754
789
  // TODO: test with real lint rules
@@ -769,9 +804,10 @@ describe("functionality", () => {
769
804
  const fs = createNodeishMemoryFs();
770
805
  await fs.mkdir("/user/project.inlang", { recursive: true });
771
806
  await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
807
+ const repo = await openRepository("file://", { nodeishFs: fs });
772
808
  const project = await loadProject({
773
809
  projectPath: "/user/project.inlang",
774
- nodeishFs: fs,
810
+ repo,
775
811
  _import: async () => ({
776
812
  default: mockMessageLintRule,
777
813
  }),
@@ -826,10 +862,11 @@ describe("functionality", () => {
826
862
  };
827
863
  await fs.mkdir("./project.inlang", { recursive: true });
828
864
  await fs.writeFile("./project.inlang/settings.json", JSON.stringify(settings));
865
+ const repo = await openRepository("file://", { nodeishFs: fs });
829
866
  // establish watcher
830
867
  const project = await loadProject({
831
868
  projectPath: normalizePath("/project.inlang"),
832
- nodeishFs: fs,
869
+ repo,
833
870
  _import: async () => ({
834
871
  default: mockMessageFormatPlugin,
835
872
  }),
@@ -0,0 +1,16 @@
1
+ import type { Repository } from "@lix-js/client";
2
+ /**
3
+ * Creates a project id if it does not exist yet.
4
+ *
5
+ * - this is a migration to ensure that all projects have a project id
6
+ * - new projects are created with a project id (in the future)
7
+ */
8
+ export declare function maybeCreateFirstProjectId(args: {
9
+ projectPath: string;
10
+ repo?: Repository;
11
+ }): Promise<void>;
12
+ export declare function generateProjectId(args: {
13
+ repo?: Repository;
14
+ projectPath: string;
15
+ }): Promise<string | undefined>;
16
+ //# sourceMappingURL=maybeCreateFirstProjectId.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maybeCreateFirstProjectId.d.ts","sourceRoot":"","sources":["../../src/migrations/maybeCreateFirstProjectId.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAGhD;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAAC,IAAI,EAAE;IACrD,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,UAAU,CAAA;CACjB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBhB;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,UAAU,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,+BAUvF"}
@@ -0,0 +1,37 @@
1
+ import { hash } from "@lix-js/client";
2
+ /**
3
+ * Creates a project id if it does not exist yet.
4
+ *
5
+ * - this is a migration to ensure that all projects have a project id
6
+ * - new projects are created with a project id (in the future)
7
+ */
8
+ export async function maybeCreateFirstProjectId(args) {
9
+ // the migration assumes a repository
10
+ if (args.repo === undefined) {
11
+ return;
12
+ }
13
+ try {
14
+ await args.repo.nodeishFs.readFile(args.projectPath + "/project_id", {
15
+ encoding: "utf-8",
16
+ });
17
+ }
18
+ catch (error) {
19
+ // @ts-ignore
20
+ if (error.code === "ENOENT" && args.repo) {
21
+ const projectId = await generateProjectId({ repo: args.repo, projectPath: args.projectPath });
22
+ if (projectId) {
23
+ await args.repo.nodeishFs.writeFile(args.projectPath + "/project_id", projectId);
24
+ }
25
+ }
26
+ }
27
+ }
28
+ export async function generateProjectId(args) {
29
+ if (!args.repo || !args.projectPath) {
30
+ return undefined;
31
+ }
32
+ const firstCommitHash = await args.repo.getFirstCommitHash();
33
+ if (firstCommitHash) {
34
+ return hash(`${firstCommitHash + args.projectPath}`);
35
+ }
36
+ return undefined;
37
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=maybeCreateFirstProjectId.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maybeCreateFirstProjectId.test.d.ts","sourceRoot":"","sources":["../../src/migrations/maybeCreateFirstProjectId.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,27 @@
1
+ import { generateProjectId } from "./maybeCreateFirstProjectId.js";
2
+ import { it, expect } from "vitest";
3
+ import { openRepository } from "@lix-js/client/src/openRepository.ts";
4
+ import { mockRepo, createNodeishMemoryFs } from "@lix-js/client";
5
+ import {} from "@lix-js/fs";
6
+ // eslint-disable-next-line no-restricted-imports -- test
7
+ import { readFileSync } from "node:fs";
8
+ const ciTestRepo = JSON.parse(readFileSync("./mocks/ci-test-repo-no-shallow.json", { encoding: "utf-8" }));
9
+ const repo = await mockRepo({ fromSnapshot: ciTestRepo });
10
+ it("should return if repo is undefined", async () => {
11
+ const projectId = await generateProjectId({ repo: undefined, projectPath: "mocked_project_path" });
12
+ expect(projectId).toBeUndefined();
13
+ });
14
+ it("should generate a project id", async () => {
15
+ const projectId = await generateProjectId({ repo, projectPath: "mocked_project_path" });
16
+ expect(projectId).toBe("432d7ef29c510e99d95e2d14ef57a0797a1603859b5a851b7dff7e77161b8c08");
17
+ });
18
+ it("should return undefined if repoMeta contains error", async () => {
19
+ const repoWithError = await openRepository("https://github.com/inlang/no-exist", {
20
+ nodeishFs: createNodeishMemoryFs(),
21
+ });
22
+ const projectId = await generateProjectId({
23
+ repo: repoWithError,
24
+ projectPath: "mocked_project_path",
25
+ });
26
+ expect(projectId).toBeUndefined();
27
+ });
@@ -1,7 +1,7 @@
1
1
  import type { NodeishFilesystem } from "@lix-js/fs";
2
2
  /**
3
3
  * Migrates to the new project directory structure
4
- * https://github.com/inlang/monorepo/issues/1678
4
+ * https://github.com/opral/monorepo/issues/1678
5
5
  */
6
6
  export declare const maybeMigrateToDirectory: (args: {
7
7
  nodeishFs: NodeishFilesystem;
@@ -1,7 +1,7 @@
1
1
  import { tryCatch } from "@inlang/result";
2
2
  /**
3
3
  * Migrates to the new project directory structure
4
- * https://github.com/inlang/monorepo/issues/1678
4
+ * https://github.com/opral/monorepo/issues/1678
5
5
  */
6
6
  export const maybeMigrateToDirectory = async (args) => {
7
7
  // the migration assumes that the projectPath ends with project.inlang
@@ -38,9 +38,9 @@ The \`project.inlang.json\` file is now contained in a project directory e.g. \`
38
38
  ## Why is this happening?
39
39
 
40
40
  See this RFC https://docs.google.com/document/d/1OYyA1wYfQRbIJOIBDliYoWjiUlkFBNxH_U2R4WpVRZ4/edit#heading=h.pecv6xb7ial6
41
- and the following GitHub issue for more information https://github.com/inlang/monorepo/issues/1678.
41
+ and the following GitHub issue for more information https://github.com/opral/monorepo/issues/1678.
42
42
 
43
- - Monorepo support https://github.com/inlang/monorepo/discussions/258.
43
+ - Monorepo support https://github.com/opral/monorepo/discussions/258.
44
44
  - Required for many other future features like caching, first class offline support, and more.
45
45
  - Stablize the inlang project format.
46
46
  `;
@@ -0,0 +1,21 @@
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
+ declare const events: readonly ["SDK loaded project"];
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: (typeof events)[number], args: {
14
+ projectId: string;
15
+ /**
16
+ * Please use snake_case for property names.
17
+ */
18
+ properties: Record<string, any>;
19
+ }) => Promise<void>;
20
+ export {};
21
+ //# sourceMappingURL=capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../src/telemetry/capture.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,QAAA,MAAM,MAAM,iCAAkC,CAAA;AAE9C;;;;GAIG;AACH,eAAO,MAAM,OAAO,UACZ,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,QACxB;IACL,SAAS,EAAE,MAAM,CAAA;IACjB;;OAEG;IACH,UAAU,EAAE,OAAO,MAAM,EAAE,GAAG,CAAC,CAAA;CAC/B,kBAyBD,CAAA"}
@@ -0,0 +1,39 @@
1
+ import { ENV_VARIABLES } from "../env-variables/index.js";
2
+ /**
3
+ * List of telemetry events for typesafety.
4
+ *
5
+ * - prefix with `SDK` to avoid collisions with other apps
6
+ * - use past tense to indicate that the event is completed
7
+ */
8
+ const events = ["SDK loaded project"];
9
+ /**
10
+ * Capture an event.
11
+ *
12
+ * - manually calling the PostHog API because the SDKs were not platform angostic (and generally bloated)
13
+ */
14
+ export const capture = async (event, args) => {
15
+ // do not send events if the token is not set
16
+ // (assuming this eases testing)
17
+ if (ENV_VARIABLES.PUBLIC_POSTHOG_TOKEN === undefined) {
18
+ return;
19
+ }
20
+ try {
21
+ await fetch("https://eu.posthog.com/capture/", {
22
+ method: "POST",
23
+ body: JSON.stringify({
24
+ api_key: ENV_VARIABLES.PUBLIC_POSTHOG_TOKEN,
25
+ event,
26
+ // id is "unknown" because no user information is available
27
+ distinct_id: "unknown",
28
+ properties: {
29
+ $groups: { project: args.projectId },
30
+ ...args.properties,
31
+ },
32
+ }),
33
+ });
34
+ }
35
+ catch (e) {
36
+ // TODO implement sentry logging
37
+ // do not console.log and avoid exposing internal errors to the user
38
+ }
39
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@inlang/sdk",
3
3
  "type": "module",
4
- "version": "0.22.0",
4
+ "version": "0.24.0",
5
5
  "license": "Apache-2.0",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -26,16 +26,16 @@
26
26
  "solid-js": "1.6.12",
27
27
  "throttle-debounce": "^5.0.0",
28
28
  "@inlang/json-types": "1.1.0",
29
- "@inlang/language-tag": "1.3.0",
30
- "@inlang/message-lint-rule": "1.4.0",
31
- "@inlang/message": "2.0.0",
32
- "@inlang/module": "1.2.1",
33
- "@inlang/plugin": "2.4.1",
34
- "@inlang/project-settings": "2.2.0",
29
+ "@inlang/language-tag": "1.4.0",
30
+ "@inlang/message": "2.0.1",
31
+ "@inlang/message-lint-rule": "1.4.1",
32
+ "@inlang/module": "1.2.3",
33
+ "@inlang/plugin": "2.4.3",
35
34
  "@inlang/result": "1.1.0",
36
- "@inlang/translatable": "1.2.0",
37
- "@lix-js/client": "0.5.0",
38
- "@lix-js/fs": "0.5.0"
35
+ "@inlang/translatable": "1.2.1",
36
+ "@inlang/project-settings": "2.2.1",
37
+ "@lix-js/fs": "0.6.0",
38
+ "@lix-js/client": "0.6.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/throttle-debounce": "5.0.0",
@@ -47,8 +47,9 @@
47
47
  "vitest": "^0.33.0"
48
48
  },
49
49
  "scripts": {
50
- "build": "tsc --build",
51
- "dev": "tsc --watch",
50
+ "build": "npm run prepare-env-variables && tsc --build",
51
+ "dev": "npm run prepare-env-variables && tsc --watch",
52
+ "prepare-env-variables": "node ./src/env-variables/createIndexFile.js",
52
53
  "test": "tsc --noEmit && vitest run --passWithNoTests --coverage",
53
54
  "lint": "eslint ./src --fix",
54
55
  "format": "prettier ./src --write",