@inlang/sdk 2.4.0 → 2.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,16 +1,242 @@
1
- Developer-first localization infrastructure that is built on lix. Your lix is the single source of truth for localization for collaboration and automation.
2
-
3
- <div>
4
- <p align="center">
5
- <img width="300" src="https://cdn.jsdelivr.net/gh/opral/monorepo/inlang/assets/logo-white-background.png"/>
6
- </p>
7
- <h4 align="center">
8
- <!-- <a href="https://inlang.com/documentation" target="_blank">Get Started</a>
9
- · -->
10
- <a href="https://github.com/opral/monorepo/discussions" target="_blank">Discussions</a> · <a href="https://twitter.com/inlangHQ" target="_blank">Twitter</a>
11
- </h4>
12
- </div>
13
-
14
- # @inlang/sdk
15
-
16
- The core module bundles "sdk" modules that depend on each other and is everything one needs to build [plugins](https://inlang.com/documentation/plugin) or entire [apps](https://inlang.com/documentation/build-app) on inlang.
1
+ # Inlang file format SDK
2
+
3
+ [![NPM Downloads](https://img.shields.io/npm/dw/%40inlang%2Fsdk?logo=npm&logoColor=red&label=npm%20downloads)](https://www.npmjs.com/package/@inlang/sdk) [![Discord](https://img.shields.io/discord/897438559458430986?style=flat&logo=discord&labelColor=white)](https://discord.gg/ecsc6bFtZw)
4
+
5
+
6
+ <p align="center">
7
+ <img src="https://cdn.jsdelivr.net/gh/opral/monorepo/inlang/packages/sdk/assets/open-file.svg" alt="Inlang SDK opens .inlang files">
8
+ </p>
9
+
10
+ ## Outline
11
+
12
+ - [Introduction](#introduction)
13
+ - [Getting Started](#getting-started)
14
+ - [Plugins](#plugins)
15
+ - [API reference](#api-reference)
16
+ - [Listing on inlang.com](#listing-on-inlangcom)
17
+
18
+ ## Introduction
19
+
20
+ The inlang SDK is the official specification and parser for `.inlang` files.
21
+
22
+ `.inlang` files are designed to become the open standard for i18n and enable interoperability between i18n solutions. Such solutions involve apps like [Fink](https://inlang.com/m/tdozzpar/app-inlang-finkLocalizationEditor), libraries like [Paraglide JS](https://inlang.com/m/gerre34r/library-inlang-paraglideJs), or plugins that extend inlang.
23
+
24
+ ### Core Features
25
+
26
+ - 📁 **File-based**: Interoperability without cloud integrations or lock-in.
27
+ - 🖊️ **CRUD API**: Query messages with SQL.
28
+ - 🧩 **Plugin System**: Extend the capabilities with plugins.
29
+ - 📦 **Import/Export**: Import and export messages in different file formats.
30
+ - [<img src="https://raw.githubusercontent.com/opral/monorepo/refs/heads/main/lix/assets/lix-icon.svg" width="20" height="12" alt="Lix Icon">**Change control**](https://lix.opral.com/): Collaboration, change proposals, reviews, and automation.
31
+
32
+
33
+
34
+ ## Getting Started
35
+
36
+ > [!Note]
37
+ > Inlang files can be unpacked and [stored as directories](#unpacked-inlang-files-directories). The long-term goal is to have portable `.inlang` files. Hence, the documentation refers to files instead of directories.
38
+
39
+ ### Installation
40
+
41
+ ```bash
42
+ npm install @inlang/sdk
43
+ ```
44
+
45
+ ### Loading an inlang file
46
+
47
+ ```ts
48
+ import { loadProjectInMemory, newProject } from "@inlang/sdk";
49
+
50
+ const project = await loadProjectInMemory({
51
+ blob: await newProject()
52
+ });
53
+
54
+ // query the project
55
+ project.*
56
+ ```
57
+
58
+ ### Next steps
59
+
60
+ Go to the [API reference](#api-reference) to learn how to query messages, changes, and save the project.
61
+
62
+
63
+ ## Plugins
64
+
65
+ The inlang SDK supports plugins to extend its functionality.
66
+
67
+ Plugins can be used to import/export messages in different formats, add custom validation rules, and implement specialized workflows.
68
+
69
+ ### Available Plugins
70
+
71
+ Find available plugins on https://inlang.com/c/plugins.
72
+
73
+ ### Creating a Plugin
74
+
75
+ #### Getting started
76
+
77
+ Implement the `InlangPlugin` type.
78
+
79
+ Examples can be found [here](https://github.com/opral/monorepo/tree/main/inlang/packages/plugins). Particulary the [message format plugin](https://github.com/opral/monorepo/tree/main/inlang/packages/plugins/inlang-message-format) is a good starting point.
80
+
81
+ ```typescript
82
+ const myPlugin: InlangPlugin = {
83
+ key: "my-plugin",
84
+ importFiles: () => {
85
+ // Import files logic
86
+ },
87
+ exportFiles: () => {
88
+ // Export files logic
89
+ },
90
+ };
91
+ ```
92
+
93
+ #### Deploying a plugin
94
+
95
+ > [!NOTE]
96
+ > Why is a CDN requires instead of using npm to use plugins?
97
+ >
98
+ > Non-JS projects (Android, iOS, etc.) wouldn't be able to use inlang, and browser-based apps like [Fink](https://inlang.com/m/tdozzpar/app-inlang-finkLocalizationEditor) couldn't load plugins.
99
+
100
+ ```bash
101
+ npx @inlang/cli plugin build --entry ./src/plugin.js
102
+ ```
103
+
104
+ We recommend uploading the plugin to NPM which makes it automatically available on [JSDelivr](https://www.jsdelivr.com/) and enables users to pin the version of your plugin.
105
+
106
+ ```diff
107
+ https://cdn.jsdelivr.net/npm/my-plugin@1/dist/index.js
108
+ ```
109
+
110
+ ## API reference
111
+
112
+ ### Creating a new project
113
+
114
+ ```typescript
115
+ import { newProject } from "@inlang/sdk";
116
+
117
+ // Create a new project
118
+ const file = await newProject();
119
+
120
+ // write the file anywhere you want
121
+ await fs.writeFile("./project.inlang", file);
122
+ ```
123
+
124
+ ### Loading a project
125
+
126
+ ```typescript
127
+ import { loadProjectInMemory } from "@inlang/sdk";
128
+
129
+ const file = await fs.readFile("./project.inlang");
130
+
131
+ // Load a project from a directory
132
+ const project = await loadProjectInMemory({
133
+ blob: file
134
+ });
135
+ ```
136
+
137
+ ### Querying a project
138
+
139
+ ```typescript
140
+ // Accessing settings and plugins
141
+ const settings = await project.settings.get();
142
+ const plugins = await project.plugins.get();
143
+
144
+ // Querying messages
145
+ const messages = await project.db
146
+ .selectFrom("message")
147
+ .selectAll()
148
+ .execute();
149
+
150
+ console.log(messages);
151
+ ```
152
+
153
+ ### Querying changes
154
+
155
+ > [!NOTE]
156
+ > The inlang plugin for lix is work in progress. If you stumble on issues, please open an issue on the [GitHub](https://github.com/opral/inlang-sdk).
157
+
158
+ The inlang file format uses lix for change control. The lix APIs are exposed via `project.lix.*`. Visit the [lix documentation](https://lix.opral.com/) for more information on how to query changes.
159
+
160
+ ```typescript
161
+ const changes = await project.lix.db
162
+ .selectFrom("change")
163
+ .selectAll()
164
+ .execute();
165
+ ```
166
+
167
+ ### Saving a project
168
+
169
+ ```typescript
170
+ const newFile = await project.toBlob();
171
+
172
+ await fs.writeFile("./project.inlang", newFile);
173
+ ```
174
+
175
+ ### Importing and exporting translation files
176
+
177
+ The import and export of messages depends on the installed plugins. The following example shows how to import and export messages using a plugin that supports JSON files.
178
+
179
+ ```typescript
180
+ const file = await fs.readFile("./en.json");
181
+
182
+ // Import files
183
+ await project.importFiles({
184
+ pluginKey: "plugin.inlang.messageFormat",
185
+ files: [
186
+ { locale: "en", content: file },
187
+ ],
188
+ });
189
+
190
+ // Export files
191
+ const files = await project.exportFiles({
192
+ pluginKey: "plugin.inlang.messageFormat"
193
+ });
194
+
195
+ await fs.writeFile("./en.json", files[0].content);
196
+ ```
197
+
198
+ ### Installing plugins
199
+
200
+ ```typescript
201
+ const settings = await project.settings.get();
202
+
203
+ settings.modules.push(
204
+ "https://cdn.jsdelivr.net/npm/@inlang/plugin-i18next@latest/dist/index.js"
205
+ )
206
+
207
+ await project.settings.set(settings)
208
+ ```
209
+
210
+ ### Unpacked inlang files (directories)
211
+
212
+ > [!NOTE]
213
+ > Unpacked inlang files are a workaround to store inlang files in git.
214
+ >
215
+ > Git can't handle binary files. **If you don't intend to store the inlang file in git, do not use unpacked inlang files.**
216
+ >
217
+ > Unpacked inlang files are not portable. They depent on plugins that and do not persist [lix change control](https://lix.opral.com/) data.
218
+
219
+ ```typescript
220
+ import {
221
+ loadProjectFromDirectory,
222
+ saveProjectToDirectory
223
+ } from "@inlang/sdk";
224
+
225
+ const project = await loadProjectFromDirectory({
226
+ "path": "./project.inlang"
227
+ });
228
+
229
+ // modify the project
230
+
231
+ await saveProjectToDirectory({
232
+ "project": project,
233
+ "path": "./project.inlang"
234
+ });
235
+ ```
236
+
237
+
238
+ ## Listing on inlang.com
239
+
240
+ To list your app/plugin on inlang.com, please open a pull request to the [registry.json file](https://github.com/opral/monorepo/blob/main/inlang/packages/marketplace-registry/registry.json).
241
+
242
+ Make sure that the link you are contributing points to a `marketplace-manifest.json` file. An example of can be found [here](https://github.com/opral/monorepo/blob/main/inlang/packages/fink/marketplace-manifest.json)
@@ -63,11 +63,11 @@ export declare function withAbsolutePaths(fs: NodeFsPromisesSubsetLegacy, projec
63
63
  * Joins a path from a project path.
64
64
  *
65
65
  * @example
66
- * joinPathFromProject("/project.inlang", "./local-plugins/mock-plugin.js") -> "/local-plugins/mock-plugin.js"
66
+ * absolutePathFromProject("/project.inlang", "./local-plugins/mock-plugin.js") -> "/local-plugins/mock-plugin.js"
67
67
  *
68
- * joinPathFromProject("/website/project.inlang", "./mock-plugin.js") -> "/website/mock-plugin.js"
68
+ * absolutePathFromProject("/website/project.inlang", "./mock-plugin.js") -> "/website/mock-plugin.js"
69
69
  */
70
- export declare function absolutePathFromProject(projectPath: string, path: string): string;
70
+ export declare function absolutePathFromProject(projectPath: string, filePath: string): string;
71
71
  export declare class ResourceFileImportError extends Error {
72
72
  path: string;
73
73
  constructor(args: {
@@ -1 +1 @@
1
- {"version":3,"file":"loadProjectFromDirectory.d.ts","sourceRoot":"/","sources":["project/loadProjectFromDirectory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,OAAO,KAAK,EACX,YAAY,EACZ,0BAA0B,EAC1B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAIlE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC7C,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,OAAO,EAAE,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAClE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,EACzC,MAAM,CACN;;;;;;;;;;;;;;;;;;;;;;;;;;GA8ID;AA2eD,qBAAa,yBAA0B,SAAQ,KAAK;gBACvC,MAAM,EAAE,MAAM;CAM1B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAChC,EAAE,EAAE,0BAA0B,EAC9B,WAAW,EAAE,MAAM,GACjB,0BAA0B,CAgB5B;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAWxE;AAED,qBAAa,uBAAwB,SAAQ,KAAK;IACjD,IAAI,EAAE,MAAM,CAAC;gBAED,IAAI,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;CAMhD"}
1
+ {"version":3,"file":"loadProjectFromDirectory.d.ts","sourceRoot":"/","sources":["project/loadProjectFromDirectory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,OAAO,KAAK,EACX,YAAY,EACZ,0BAA0B,EAC1B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAIlE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC7C,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,OAAO,EAAE,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAClE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,EACzC,MAAM,CACN;;;;;;;;;;;;;;;;;;;;;;;;;;GA8ID;AA2eD,qBAAa,yBAA0B,SAAQ,KAAK;gBACvC,MAAM,EAAE,MAAM;CAM1B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAChC,EAAE,EAAE,0BAA0B,EAC9B,WAAW,EAAE,MAAM,GACjB,0BAA0B,CAgB5B;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACtC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACd,MAAM,CAoBR;AAED,qBAAa,uBAAwB,SAAQ,KAAK;IACjD,IAAI,EAAE,MAAM,CAAC;gBAED,IAAI,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;CAMhD"}
@@ -568,19 +568,26 @@ export function withAbsolutePaths(fs, projectPath) {
568
568
  * Joins a path from a project path.
569
569
  *
570
570
  * @example
571
- * joinPathFromProject("/project.inlang", "./local-plugins/mock-plugin.js") -> "/local-plugins/mock-plugin.js"
571
+ * absolutePathFromProject("/project.inlang", "./local-plugins/mock-plugin.js") -> "/local-plugins/mock-plugin.js"
572
572
  *
573
- * joinPathFromProject("/website/project.inlang", "./mock-plugin.js") -> "/website/mock-plugin.js"
573
+ * absolutePathFromProject("/website/project.inlang", "./mock-plugin.js") -> "/website/mock-plugin.js"
574
574
  */
575
- export function absolutePathFromProject(projectPath, path) {
576
- // need to remove the project path from the module path for legacy reasons
577
- // "/project.inlang/local-plugins/mock-plugin.js" -> "/local-plugins/mock-plugin.js"
578
- const pathWithoutProject = projectPath
579
- .split(nodePath.sep)
580
- .slice(0, -1)
581
- .join(nodePath.sep);
582
- const resolvedPath = nodePath.resolve(pathWithoutProject, path);
583
- return resolvedPath;
575
+ export function absolutePathFromProject(projectPath, filePath) {
576
+ // Normalize paths for consistency across platforms
577
+ const normalizedProjectPath = nodePath
578
+ .normalize(projectPath)
579
+ .replace(/\\/g, "/");
580
+ const normalizedFilePath = nodePath.normalize(filePath).replace(/\\/g, "/");
581
+ // Remove the last part of the project path (file name) to get the project root
582
+ const projectRoot = nodePath.dirname(normalizedProjectPath);
583
+ // If filePath is already absolute, return it directly
584
+ if (nodePath.isAbsolute(normalizedFilePath)) {
585
+ return normalizedFilePath;
586
+ }
587
+ // Compute absolute resolved path
588
+ const resolvedPath = nodePath.resolve(projectRoot, normalizedFilePath);
589
+ // Ensure final path always uses forward slashes
590
+ return resolvedPath.replace(/\\/g, "/");
584
591
  }
585
592
  export class ResourceFileImportError extends Error {
586
593
  path;
@@ -1 +1 @@
1
- {"version":3,"file":"loadProjectFromDirectory.js","sourceRoot":"/","sources":["project/loadProjectFromDirectory.ts"],"names":[],"mappings":"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","sourcesContent":["import { newProject } from \"./newProject.js\";\nimport { loadProjectInMemory } from \"./loadProjectInMemory.js\";\nimport { type Lix } from \"@lix-js/sdk\";\nimport fs from \"node:fs\";\nimport nodePath from \"node:path\";\nimport type {\n\tInlangPlugin,\n\tNodeFsPromisesSubsetLegacy,\n} from \"../plugin/schema.js\";\nimport { fromMessageV1 } from \"../json-schema/old-v1-message/fromMessageV1.js\";\nimport type { ProjectSettings } from \"../json-schema/settings.js\";\nimport type { PreprocessPluginBeforeImportFunction } from \"../plugin/importPlugins.js\";\nimport { PluginImportError } from \"../plugin/errors.js\";\nimport { upsertBundleNestedMatchByProperties } from \"../import-export/upsertBundleNestedMatchByProperties.js\";\nimport type { ImportFile } from \"./api.js\";\n\n/**\n * Loads a project from a directory.\n *\n * Main use case are dev tools that want to load a project from a directory\n * that is stored in git.\n */\nexport async function loadProjectFromDirectory(\n\targs: { path: string; fs: typeof fs; syncInterval?: number } & Omit<\n\t\tParameters<typeof loadProjectInMemory>[0],\n\t\t\"blob\"\n\t>\n) {\n\tconst settingsPath = nodePath.join(args.path, \"settings.json\");\n\tconst settings = JSON.parse(\n\t\tawait args.fs.promises.readFile(settingsPath, \"utf8\")\n\t) as ProjectSettings;\n\n\tlet inlangId: string | undefined = undefined;\n\n\ttry {\n\t\tinlangId = await args.fs.promises.readFile(\n\t\t\tnodePath.join(args.path, \"project_id\"),\n\t\t\t\"utf8\"\n\t\t);\n\t} catch {\n\t\t// await args.fs.promises.writeFile(\n\t\t// \tnodePath.join(args.path, \"project_id\"),\n\t\t// \t,\n\t\t// \t{ encoding: \"utf8\" }\n\t\t// );\n\t\t// file doesn't exist yet\n\t}\n\n\tconst localImport = await importLocalPlugins({\n\t\tfs: args.fs,\n\t\tsettings,\n\t\tpath: args.path,\n\t});\n\n\tconst providePluginsWithLocalPlugins = [\n\t\t...(args.providePlugins ?? []),\n\t\t...localImport.locallyImportedPlugins,\n\t];\n\n\t// TODO call tempProject.lix.settled() to wait for the new settings file, and remove reload of the proejct as soon as reactive settings has landed\n\t// NOTE: we need to ensure two things:\n\t// 1. settled needs to include the changes from the copyFiles call\n\t// 2. the changes created from the copyFiles call need to be realized and lead to a signal on the settings\n\tconst project = await loadProjectInMemory({\n\t\t...args,\n\t\tprovidePlugins: providePluginsWithLocalPlugins,\n\t\tlixKeyValues: inlangId\n\t\t\t? // reversing the id to have distinguishable lix ids from inlang ids\n\t\t\t\t[{ key: \"lix_id\", value: inlangId }]\n\t\t\t: undefined,\n\t\tblob: await newProject({\n\t\t\tsettings,\n\t\t}),\n\t});\n\n\tawait syncLixFsFiles({\n\t\tfs: args.fs,\n\t\tpath: args.path,\n\t\tlix: project.lix,\n\t\tsyncInterval: args.syncInterval,\n\t});\n\n\tconst allPlugins = await project.plugins.get();\n\tconst { loadSavePlugins, importExportPlugins } =\n\t\tcategorizePlugins(allPlugins);\n\n\t// TODO i guess we should move this validation logic into sdk2/src/project/loadProject.ts\n\t// Two scenarios could arise:\n\t// 1. set settings is called from an app - it should detect and reject the setting of settings -> app need to be able to validate before calling set\n\t// 2. the settings file loaded from disc here is corrupted -> user has to fix the file on disc\n\tif (loadSavePlugins.length > 1) {\n\t\tthrow new Error(\n\t\t\t\"Max one loadMessages (found: \" +\n\t\t\t\tloadSavePlugins.length +\n\t\t\t\t\") and one saveMessages plugins (found: \" +\n\t\t\t\tloadSavePlugins.length +\n\t\t\t\t\") are allowed \"\n\t\t);\n\t}\n\tconst importedResourceFileErrors: Error[] = [];\n\n\t// import files from local fs\n\tfor (const plugin of importExportPlugins) {\n\t\tconst files: ImportFile[] = [];\n\t\tif (plugin.toBeImportedFiles) {\n\t\t\tconst toBeImportedFiles = await plugin.toBeImportedFiles({\n\t\t\t\tsettings: await project.settings.get(),\n\t\t\t});\n\t\t\tfor (const toBeImported of toBeImportedFiles) {\n\t\t\t\tconst absolute = absolutePathFromProject(args.path, toBeImported.path);\n\t\t\t\ttry {\n\t\t\t\t\tconst data = await args.fs.promises.readFile(absolute);\n\t\t\t\t\tfiles.push({\n\t\t\t\t\t\tlocale: toBeImported.locale,\n\t\t\t\t\t\tcontent: data,\n\t\t\t\t\t\ttoBeImportedFilesMetadata: toBeImported.metadata,\n\t\t\t\t\t});\n\t\t\t\t} catch (e) {\n\t\t\t\t\t// https://github.com/opral/inlang-sdk/issues/202\n\t\t\t\t\tif ((e as any)?.code === \"ENOENT\") {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\timportedResourceFileErrors.push(\n\t\t\t\t\t\tnew ResourceFileImportError({\n\t\t\t\t\t\t\tcause: e as Error,\n\t\t\t\t\t\t\tpath: toBeImported.path,\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tawait project.importFiles({\n\t\t\tpluginKey: plugin.key,\n\t\t\tfiles,\n\t\t});\n\t}\n\n\tfor (const plugin of loadSavePlugins) {\n\t\tawait loadLegacyMessages({\n\t\t\tproject,\n\t\t\tpluginKey: plugin.key ?? plugin.id,\n\t\t\tloadMessagesFn: plugin.loadMessages!,\n\t\t\tprojectPath: args.path,\n\t\t\tfs: args.fs,\n\t\t});\n\t}\n\n\treturn {\n\t\t...project,\n\t\terrors: {\n\t\t\tget: async () => {\n\t\t\t\treturn [...localImport.errors, ...importedResourceFileErrors];\n\t\t\t},\n\t\t\t// subscribe: (\n\t\t\t// \tcallback: Parameters<InlangProject[\"errors\"][\"subscribe\"]>[0]\n\t\t\t// ) => {\n\t\t\t// \treturn project.errors.subscribe((value) => {\n\t\t\t// \t\tcallback([\n\t\t\t// \t\t\t...withLocallyImportedPluginWarning(value),\n\t\t\t// \t\t\t...localImport.errors,\n\t\t\t// \t\t\t...importedResourceFileErrors,\n\t\t\t// \t\t]);\n\t\t\t// \t});\n\t\t\t// },\n\t\t},\n\t};\n}\n\nasync function loadLegacyMessages(args: {\n\tproject: Awaited<ReturnType<typeof loadProjectInMemory>>;\n\tpluginKey: NonNullable<InlangPlugin[\"key\"] | InlangPlugin[\"id\"]>;\n\tloadMessagesFn: Required<InlangPlugin>[\"loadMessages\"];\n\tprojectPath: string;\n\tfs: typeof fs;\n}) {\n\tconst loadedLegacyMessages = await args.loadMessagesFn({\n\t\tsettings: await args.project.settings.get(),\n\t\t// @ts-expect-error - type mismatch\n\t\tnodeishFs: withAbsolutePaths(args.fs.promises, args.projectPath),\n\t});\n\tconst upsertQueries = [];\n\n\tfor (const legacyMessage of loadedLegacyMessages) {\n\t\tconst messageBundle = fromMessageV1(legacyMessage);\n\n\t\tupsertQueries.push(\n\t\t\tupsertBundleNestedMatchByProperties(args.project.db, messageBundle)\n\t\t);\n\t}\n\n\treturn await Promise.all(upsertQueries);\n}\n\ntype FsFileState = Record<\n\tstring,\n\t{\n\t\t/*mtime: number, hash: string, */ content: ArrayBuffer;\n\t\tstate: \"known\" | \"unknown\" | \"updated\" | \"gone\";\n\t}\n>;\n\nfunction arrayBuffersEqual(a: ArrayBuffer, b: ArrayBuffer) {\n\tif (a.byteLength !== b.byteLength) return false;\n\n\t// Create views for byte-by-byte comparison\n\tconst view1 = new Uint8Array(a);\n\tconst view2 = new Uint8Array(b);\n\n\t// Compare each byte\n\tfor (const [i, element] of view1.entries()) {\n\t\tif (element !== view2[i]) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\n/**\n * Watches a directory and copies files into lix, keeping them in sync.\n */\nasync function syncLixFsFiles(args: {\n\tfs: typeof fs;\n\tpath: string;\n\tlix: Lix;\n\tsyncInterval?: number;\n}) {\n\t// NOTE this function is async - while it runs 100% sync in the naiv implementation - we may want to change to an async version to optimize\n\tasync function checkFsStateRecursive(\n\t\tdirPath: string,\n\t\tcurrentState: FsFileState\n\t) {\n\t\tconst entries = args.fs.readdirSync(dirPath, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tconst fullPath = nodePath.join(dirPath, entry.name);\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tcheckFsStateRecursive(fullPath, currentState);\n\t\t\t} else {\n\t\t\t\t// NOTE we could start with comparing the mdate and skip file read completely...\n\t\t\t\tconst data = args.fs.readFileSync(fullPath) as unknown as ArrayBuffer;\n\n\t\t\t\tconst relativePath = \"/\" + nodePath.relative(args.path, fullPath);\n\n\t\t\t\tif (!currentState[relativePath]) {\n\t\t\t\t\tcurrentState[relativePath] = {\n\t\t\t\t\t\tcontent: data,\n\t\t\t\t\t\tstate: \"unknown\",\n\t\t\t\t\t};\n\t\t\t\t} else {\n\t\t\t\t\tif (arrayBuffersEqual(currentState[relativePath].content, data)) {\n\t\t\t\t\t\tcurrentState[relativePath].state = \"known\";\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcurrentState[relativePath].state = \"updated\";\n\t\t\t\t\t\tcurrentState[relativePath].content = data;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tasync function checkLixState(currentLixState: FsFileState) {\n\t\t// go through all files in lix and check there state\n\t\tconst filesInLix = await args.lix.db\n\t\t\t.selectFrom(\"file\")\n\t\t\t.where(\"path\", \"not like\", \"%db.sqlite\")\n\t\t\t.selectAll()\n\t\t\t.execute();\n\n\t\tfor (const fileInLix of filesInLix) {\n\t\t\tconst currentStateOfFileInLix = currentLixState[fileInLix.path];\n\t\t\t// NOTE we could start with comparing the mdate and skip file read completely...\n\t\t\tif (!currentStateOfFileInLix) {\n\t\t\t\tcurrentLixState[fileInLix.path] = {\n\t\t\t\t\tcontent: new Uint8Array(fileInLix.data).buffer,\n\t\t\t\t\tstate: \"unknown\",\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\tif (\n\t\t\t\t\tarrayBuffersEqual(\n\t\t\t\t\t\tcurrentStateOfFileInLix.content,\n\t\t\t\t\t\tfileInLix.data.buffer as ArrayBuffer\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tcurrentStateOfFileInLix.state = \"known\";\n\t\t\t\t} else {\n\t\t\t\t\tcurrentStateOfFileInLix.state = \"updated\";\n\t\t\t\t\tcurrentStateOfFileInLix.content = fileInLix.data\n\t\t\t\t\t\t.buffer as ArrayBuffer;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tasync function syncUpFsAndLixFiles(statesToSync: {\n\t\tfsFileStates: FsFileState;\n\t\tlixFileStates: FsFileState;\n\t}) {\n\t\t// for (const file of Object.keys(statesToSync.fsFileStates)) {\n\t\t// \tif (file.includes(\"gitignore\"))\n\t\t// \t\tconsole.log(\n\t\t// \t\t\t\"fsFileStates : \" +\n\t\t// \t\t\t\tfile +\n\t\t// \t\t\t\t\" fs \" +\n\t\t// \t\t\t\tstatesToSync.fsFileStates[file]?.state +\n\t\t// \t\t\t\t\" lix \" +\n\t\t// \t\t\t\tstatesToSync.lixFileStates[file]?.state\n\t\t// \t\t);\n\t\t// }\n\n\t\t// Sync cases:\n\t\t// fs - no state for file | fs - unkonwn | fs - known | fs - updated | fs - gone\n\t\t// lix - no state for file \tNOTHING\t(1)\t | ADD TO LIX(2) | ERROR (3) | ERROR (4) | ERROR (5)\n\t\t// lix - unknown\t\t\t\t\tADD TO FS (6) | USE FS VER.(7) | ERROR (8) | CASE (9) | CASE (10)\n\t\t// lix - known ERROR (11) | ERROR (12) | NOTHING(13) | ERROR (14) | ERROR (15)\n\t\t// lix - updated\t\t\t\t\tERROR (16) | ERROR (17) | USE LIX (18) | CASE (19) | CASE (20)\n\t\t// lix - gone \t\t\t\t\t\tERROR (21) | ERROR (22) | DELETE FS (23)| CASE (24) | CASE (25)\n\n\t\t// TODO check export import from saveFileToDirectory\n\n\t\tfor (const [path, fsState] of Object.entries(statesToSync.fsFileStates)) {\n\t\t\t// no state for file in LIX\n\t\t\tif (!statesToSync.lixFileStates[path]) {\n\t\t\t\tif (fsState.state === \"unknown\") {\n\t\t\t\t\t// ADD TO LIX(2)\n\t\t\t\t\tawait upsertFileInLix(args, path, fsState.content);\n\t\t\t\t\tstatesToSync.lixFileStates[path] = {\n\t\t\t\t\t\tstate: \"known\",\n\t\t\t\t\t\tcontent: fsState.content,\n\t\t\t\t\t};\n\t\t\t\t\tfsState.state = \"known\";\n\t\t\t\t} else {\n\t\t\t\t\t// ERROR (3), ERROR (4), ERROR (5)\n\t\t\t\t\t// The file does not exist in lix but its state differs from unknown?\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"Illeagal lix<->fs sync state. The file [\" +\n\t\t\t\t\t\t\tpath +\n\t\t\t\t\t\t\t\"] that was \" +\n\t\t\t\t\t\t\tfsState.state +\n\t\t\t\t\t\t\t\" on disc did not exit in lix\"\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst lixState = statesToSync.lixFileStates[path];\n\t\t\t\tif (fsState.state === \"unknown\") {\n\t\t\t\t\tif (lixState.state === \"unknown\") {\n\t\t\t\t\t\tif (arrayBuffersEqual(lixState.content, fsState.content)) {\n\t\t\t\t\t\t\tlixState.state = \"known\";\n\t\t\t\t\t\t\tfsState.state = \"known\";\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tawait upsertFileInLix(args, path, fsState.content);\n\t\t\t\t\t\t\tlixState.content = fsState.content;\n\t\t\t\t\t\t\tlixState.state = \"known\";\n\t\t\t\t\t\t\tfsState.state = \"known\";\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// ERROR 12, 17, 22\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\"Illeagal lix<->fs sync state. The file [\" +\n\t\t\t\t\t\t\t\tpath +\n\t\t\t\t\t\t\t\t\"] that was \" +\n\t\t\t\t\t\t\t\tfsState.state +\n\t\t\t\t\t\t\t\t\" but did exist in lix already\"\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} else if (fsState.state === \"known\") {\n\t\t\t\t\tif (lixState.state === \"known\") {\n\t\t\t\t\t\t// NO OP - NOTHING(13)\n\t\t\t\t\t} else if (lixState.state === \"updated\") {\n\t\t\t\t\t\t// USE LIX (18)\n\t\t\t\t\t\targs.fs.writeFileSync(\n\t\t\t\t\t\t\t// TODO check platform dependent folder separator\n\t\t\t\t\t\t\targs.path + path,\n\t\t\t\t\t\t\tBuffer.from(lixState.content)\n\t\t\t\t\t\t);\n\t\t\t\t\t\tfsState.content = lixState.content;\n\t\t\t\t\t\tfsState.state = \"known\";\n\t\t\t\t\t\tlixState.state = \"known\";\n\t\t\t\t\t} else if (lixState.state === \"gone\") {\n\t\t\t\t\t\t// DELETE FS (23)\n\t\t\t\t\t\targs.fs.unlinkSync(args.path + path);\n\t\t\t\t\t\tfsState.state = \"gone\";\n\t\t\t\t\t\tlixState.state = \"gone\";\n\t\t\t\t\t}\n\t\t\t\t} else if (fsState.state === \"updated\") {\n\t\t\t\t\tif (lixState.state === \"unknown\") {\n\t\t\t\t\t\t// TODO A file was added to lix while a known file from fs was updated?\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\"Illeagal lix<->fs sync state. The file [\" +\n\t\t\t\t\t\t\t\tpath +\n\t\t\t\t\t\t\t\t\"] that was \" +\n\t\t\t\t\t\t\t\tfsState.state +\n\t\t\t\t\t\t\t\t\" but it was not known by lix yet?\"\n\t\t\t\t\t\t);\n\t\t\t\t\t} else if (lixState.state === \"known\") {\n\t\t\t\t\t\tawait upsertFileInLix(args, path, fsState.content);\n\t\t\t\t\t\tlixState.content = fsState.content;\n\n\t\t\t\t\t\tfsState.state = \"known\";\n\t\t\t\t\t} else if (lixState.state === \"updated\") {\n\t\t\t\t\t\t// seems like we saw an update on the file in fs while some changes on lix have not been reached fs? FS -> Winns?\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\"seems like we saw an update on the file \" +\n\t\t\t\t\t\t\t\tpath +\n\t\t\t\t\t\t\t\t\" in fs while some changes on lix have not been reached fs? FS -> Winns?\"\n\t\t\t\t\t\t);\n\t\t\t\t\t\tawait upsertFileInLix(args, path, fsState.content);\n\t\t\t\t\t\tlixState.content = fsState.content;\n\t\t\t\t\t\tlixState.state = \"known\";\n\t\t\t\t\t\tfsState.state = \"known\";\n\t\t\t\t\t} else if (lixState.state === \"gone\") {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\"seems like we saw an delete in lix while some changes on fs have not been reached fs? FS -> Winns?\"\n\t\t\t\t\t\t);\n\t\t\t\t\t\t// TODO update the lix state\n\t\t\t\t\t\tlixState.content = fsState.content;\n\t\t\t\t\t\tlixState.state = \"known\";\n\t\t\t\t\t\tfsState.state = \"known\";\n\t\t\t\t\t}\n\t\t\t\t} else if (fsState.state === \"gone\") {\n\t\t\t\t\tif (lixState.state === \"unknown\") {\n\t\t\t\t\t\t// TODO A file was added to lix while a known file from fs was removed?\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\"Illeagal lix<->fs sync state. The file [\" +\n\t\t\t\t\t\t\t\tpath +\n\t\t\t\t\t\t\t\t\"] that was \" +\n\t\t\t\t\t\t\t\tfsState.state +\n\t\t\t\t\t\t\t\t\" but it was not known by lix yet?\"\n\t\t\t\t\t\t);\n\t\t\t\t\t} else if (lixState.state === \"known\") {\n\t\t\t\t\t\t// file is in known state with lix - means we have only changes on the fs - easy\n\t\t\t\t\t\tawait args.lix.db\n\t\t\t\t\t\t\t.deleteFrom(\"file\")\n\t\t\t\t\t\t\t.where(\"path\", \"=\", path)\n\t\t\t\t\t\t\t.execute();\n\t\t\t\t\t\t// NOTE: states where both are gone will get removed in the lix state loop\n\t\t\t\t\t\tlixState.state = \"gone\";\n\t\t\t\t\t} else if (lixState.state === \"updated\") {\n\t\t\t\t\t\t// seems like we saw an update on the file in fs while some changes on lix have not been reached fs? FS -> Winns?\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\"seems like we saw an update on the file in fs while some changes on lix have not been reached fs? FS -> Winns?\"\n\t\t\t\t\t\t);\n\t\t\t\t\t\tawait args.lix.db\n\t\t\t\t\t\t\t.deleteFrom(\"file\")\n\t\t\t\t\t\t\t.where(\"path\", \"=\", path)\n\t\t\t\t\t\t\t.execute();\n\t\t\t\t\t\t// NOTE: states where both are gone will get removed in the lix state loop\n\t\t\t\t\t\tlixState.state = \"gone\";\n\t\t\t\t\t\tfsState.state = \"gone\";\n\t\t\t\t\t} else if (lixState.state === \"gone\") {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\"seems like we saw an delete in lix while we have a delete in lix simultaniously?\"\n\t\t\t\t\t\t);\n\t\t\t\t\t\tlixState.state = \"gone\";\n\t\t\t\t\t\tfsState.state = \"gone\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const [path, lixState] of Object.entries(statesToSync.lixFileStates)) {\n\t\t\t// no state for file in fs\n\t\t\tif (!statesToSync.fsFileStates[path]) {\n\t\t\t\tif (lixState.state == \"unknown\") {\n\t\t\t\t\t// ADD TO FS (6)\n\t\t\t\t\t// create directory if not exists\n\t\t\t\t\ttry {\n\t\t\t\t\t\targs.fs.mkdirSync(\n\t\t\t\t\t\t\tnodePath.dirname(nodePath.join(args.path, path)),\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\trecursive: true,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t// ignore if directory already exists\n\t\t\t\t\t\t// https://github.com/opral/inlang-paraglide-js/issues/377\n\t\t\t\t\t\tif ((e as any)?.code !== \"EEXIST\") {\n\t\t\t\t\t\t\tthrow e;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// write file\n\t\t\t\t\targs.fs.writeFileSync(\n\t\t\t\t\t\tnodePath.join(args.path, path),\n\t\t\t\t\t\tBuffer.from(lixState.content)\n\t\t\t\t\t);\n\t\t\t\t\tstatesToSync.fsFileStates[path] = {\n\t\t\t\t\t\tstate: \"known\",\n\t\t\t\t\t\tcontent: lixState.content,\n\t\t\t\t\t};\n\t\t\t\t} else {\n\t\t\t\t\t// ERROR (11) 16 21\n\t\t\t\t\t// The file does not exist on fs but its state differs from unknown?\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"Illeagal lix<->fs sync state. The file [\" +\n\t\t\t\t\t\t\tpath +\n\t\t\t\t\t\t\t\"] that was in the state\" +\n\t\t\t\t\t\t\tlixState.state +\n\t\t\t\t\t\t\t\" for lix did not exist on disk\"\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (\n\t\t\t\t\tlixState.state === \"gone\" &&\n\t\t\t\t\tstatesToSync.fsFileStates[path].state === \"gone\"\n\t\t\t\t) {\n\t\t\t\t\tdelete statesToSync.lixFileStates[path];\n\t\t\t\t\tdelete statesToSync.fsFileStates[path];\n\t\t\t\t} else if (lixState.state !== statesToSync.fsFileStates[path].state) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"At this stage both states should be in sync lix state \" +\n\t\t\t\t\t\t\tlixState.state +\n\t\t\t\t\t\t\t\" fs state \" +\n\t\t\t\t\t\t\tstatesToSync.fsFileStates[path].state\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tasync function syncFiles(\n\t\tdirPath: string,\n\t\tfileStates: {\n\t\t\tlixFileStates: FsFileState;\n\t\t\tfsFileStates: FsFileState;\n\t\t},\n\t\tinterval?: number\n\t) {\n\t\t// mark all states as removed - checkFsStateRecursive will update those that exist on the disc correspondingly\n\t\tfor (const fsState of Object.values(fileStates.fsFileStates)) {\n\t\t\tfsState.state = \"gone\";\n\t\t}\n\n\t\t// mark all states as removed - checkFsStateRecursive will update those that exist on the disc correspondingly\n\t\tfor (const lixState of Object.values(fileStates.lixFileStates)) {\n\t\t\tlixState.state = \"gone\";\n\t\t}\n\n\t\t// read states from disc - detect changes\n\t\tawait checkFsStateRecursive(dirPath, fileStates.fsFileStates);\n\n\t\t// read states form lix - detect changes\n\t\tawait checkLixState(fileStates.lixFileStates);\n\n\t\t// sync fs<->lix\n\t\tawait syncUpFsAndLixFiles(fileStates);\n\n\t\tif (interval) {\n\t\t\tsetTimeout(() => {\n\t\t\t\tsyncFiles(dirPath, fileStates, interval);\n\t\t\t}, interval);\n\t\t}\n\n\t\treturn;\n\t}\n\n\t// Initial copy of all files\n\tawait syncFiles(\n\t\targs.path,\n\t\t{ fsFileStates: {}, lixFileStates: {} },\n\t\targs.syncInterval\n\t);\n\n\treturn;\n}\n\nasync function upsertFileInLix(\n\targs: { fs: typeof fs; path: string; lix: Lix },\n\tpath: string,\n\tdata: ArrayBuffer\n) {\n\t// force posix path when upserting into lix\n\t// https://github.com/opral/inlang-sdk/issues/229\n\tlet posixPath = path.split(nodePath.win32.sep).join(nodePath.posix.sep);\n\n\tif (posixPath.startsWith(\"/\") === false) {\n\t\tposixPath = \"/\" + posixPath;\n\t}\n\n\tawait args.lix.db\n\t\t.insertInto(\"file\") // change queue\n\t\t.values({\n\t\t\tpath: posixPath,\n\t\t\tdata: new Uint8Array(data),\n\t\t})\n\t\t.onConflict((oc) =>\n\t\t\toc.column(\"path\").doUpdateSet({ data: new Uint8Array(data) })\n\t\t)\n\t\t.execute();\n}\n/**\n * Filters legacy load and save messages plugins.\n *\n * Legacy plugins are plugins that implement loadMessages and saveMessages but not importFiles and exportFiles.\n */\nfunction categorizePlugins(plugins: readonly InlangPlugin[]) {\n\tconst loadSavePlugins: InlangPlugin[] = [];\n\tconst importExportPlugins: InlangPlugin[] = [];\n\n\tfor (const plugin of plugins) {\n\t\tif (\n\t\t\tplugin.loadMessages &&\n\t\t\tplugin.saveMessages &&\n\t\t\t!(plugin.importFiles && plugin.exportFiles)\n\t\t) {\n\t\t\tloadSavePlugins.push(plugin);\n\t\t} else if (plugin.importFiles || plugin.exportFiles) {\n\t\t\timportExportPlugins.push(plugin);\n\t\t}\n\t}\n\n\treturn { loadSavePlugins, importExportPlugins };\n}\n\n/**\n * Imports local plugins for backwards compatibility.\n *\n * https://github.com/opral/inlang-sdk/issues/171\n */\nasync function importLocalPlugins(args: {\n\tfs: typeof fs;\n\tsettings: ProjectSettings;\n\tpath: string;\n\tpreprocessPluginBeforeImport?: PreprocessPluginBeforeImportFunction;\n}) {\n\tconst errors: Error[] = [];\n\tconst locallyImportedPlugins = [];\n\tfor (const module of args.settings.modules ?? []) {\n\t\tif (module.startsWith(\"http\")) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst modulePath = absolutePathFromProject(args.path, module);\n\t\ttry {\n\t\t\tlet moduleAsText = await args.fs.promises.readFile(modulePath, \"utf8\");\n\t\t\tif (moduleAsText.includes(\"messageLintRule\")) {\n\t\t\t\terrors.push(new WarningDeprecatedLintRule(module));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (args.preprocessPluginBeforeImport) {\n\t\t\t\tmoduleAsText = await args.preprocessPluginBeforeImport(moduleAsText);\n\t\t\t}\n\t\t\tconst moduleWithMimeType =\n\t\t\t\t\"data:application/javascript,\" + encodeURIComponent(moduleAsText);\n\t\t\tconst { default: plugin } = await import(\n\t\t\t\t/* @vite-ignore */ moduleWithMimeType\n\t\t\t);\n\t\t\tlocallyImportedPlugins.push(plugin);\n\t\t} catch (e) {\n\t\t\terrors.push(new PluginImportError({ plugin: module, cause: e as Error }));\n\t\t\tcontinue;\n\t\t}\n\t}\n\treturn {\n\t\terrors,\n\t\tlocallyImportedPlugins,\n\t};\n}\n\nexport class WarningDeprecatedLintRule extends Error {\n\tconstructor(module: string) {\n\t\tsuper(\n\t\t\t`The lint rule ${module} is deprecated. Please remove the lint rule from the settings. Lint rules are interim built into apps and will be succeeded by more generilizable lix validation rules.`\n\t\t);\n\t\tthis.name = \"WarningDeprecatedLintRule\";\n\t}\n}\n\n/**\n * Resolving absolute paths for fs functions.\n *\n * This mapping is required for backwards compatibility.\n * Relative paths in the project.inlang/settings.json\n * file are resolved to absolute paths with `*.inlang`\n * being pruned.\n *\n * @example\n * \"/website/project.inlang\"\n * \"./local-plugins/mock-plugin.js\"\n * -> \"/website/local-plugins/mock-plugin.js\"\n *\n */\nexport function withAbsolutePaths(\n\tfs: NodeFsPromisesSubsetLegacy,\n\tprojectPath: string\n): NodeFsPromisesSubsetLegacy {\n\treturn {\n\t\t// @ts-expect-error - node type mismatch\n\t\treadFile: (path, options) => {\n\t\t\treturn fs.readFile(absolutePathFromProject(projectPath, path), options);\n\t\t},\n\t\twriteFile: (path, data) => {\n\t\t\treturn fs.writeFile(absolutePathFromProject(projectPath, path), data);\n\t\t},\n\t\tmkdir: (path) => {\n\t\t\treturn fs.mkdir(absolutePathFromProject(projectPath, path));\n\t\t},\n\t\treaddir: (path) => {\n\t\t\treturn fs.readdir(absolutePathFromProject(projectPath, path));\n\t\t},\n\t};\n}\n\n/**\n * Joins a path from a project path.\n *\n * @example\n * joinPathFromProject(\"/project.inlang\", \"./local-plugins/mock-plugin.js\") -> \"/local-plugins/mock-plugin.js\"\n *\n * joinPathFromProject(\"/website/project.inlang\", \"./mock-plugin.js\") -> \"/website/mock-plugin.js\"\n */\nexport function absolutePathFromProject(projectPath: string, path: string) {\n\t// need to remove the project path from the module path for legacy reasons\n\t// \"/project.inlang/local-plugins/mock-plugin.js\" -> \"/local-plugins/mock-plugin.js\"\n\tconst pathWithoutProject = projectPath\n\t\t.split(nodePath.sep)\n\t\t.slice(0, -1)\n\t\t.join(nodePath.sep);\n\n\tconst resolvedPath = nodePath.resolve(pathWithoutProject, path);\n\n\treturn resolvedPath;\n}\n\nexport class ResourceFileImportError extends Error {\n\tpath: string;\n\n\tconstructor(args: { cause: Error; path: string }) {\n\t\tsuper(\"Could not import a resource file\");\n\t\tthis.name = \"ResourceFileImportError\";\n\t\tthis.cause = args.cause;\n\t\tthis.path = args.path;\n\t}\n}\n"]}
1
+ {"version":3,"file":"loadProjectFromDirectory.js","sourceRoot":"/","sources":["project/loadProjectFromDirectory.ts"],"names":[],"mappings":"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","sourcesContent":["import { newProject } from \"./newProject.js\";\nimport { loadProjectInMemory } from \"./loadProjectInMemory.js\";\nimport { type Lix } from \"@lix-js/sdk\";\nimport fs from \"node:fs\";\nimport nodePath from \"node:path\";\nimport type {\n\tInlangPlugin,\n\tNodeFsPromisesSubsetLegacy,\n} from \"../plugin/schema.js\";\nimport { fromMessageV1 } from \"../json-schema/old-v1-message/fromMessageV1.js\";\nimport type { ProjectSettings } from \"../json-schema/settings.js\";\nimport type { PreprocessPluginBeforeImportFunction } from \"../plugin/importPlugins.js\";\nimport { PluginImportError } from \"../plugin/errors.js\";\nimport { upsertBundleNestedMatchByProperties } from \"../import-export/upsertBundleNestedMatchByProperties.js\";\nimport type { ImportFile } from \"./api.js\";\n\n/**\n * Loads a project from a directory.\n *\n * Main use case are dev tools that want to load a project from a directory\n * that is stored in git.\n */\nexport async function loadProjectFromDirectory(\n\targs: { path: string; fs: typeof fs; syncInterval?: number } & Omit<\n\t\tParameters<typeof loadProjectInMemory>[0],\n\t\t\"blob\"\n\t>\n) {\n\tconst settingsPath = nodePath.join(args.path, \"settings.json\");\n\tconst settings = JSON.parse(\n\t\tawait args.fs.promises.readFile(settingsPath, \"utf8\")\n\t) as ProjectSettings;\n\n\tlet inlangId: string | undefined = undefined;\n\n\ttry {\n\t\tinlangId = await args.fs.promises.readFile(\n\t\t\tnodePath.join(args.path, \"project_id\"),\n\t\t\t\"utf8\"\n\t\t);\n\t} catch {\n\t\t// await args.fs.promises.writeFile(\n\t\t// \tnodePath.join(args.path, \"project_id\"),\n\t\t// \t,\n\t\t// \t{ encoding: \"utf8\" }\n\t\t// );\n\t\t// file doesn't exist yet\n\t}\n\n\tconst localImport = await importLocalPlugins({\n\t\tfs: args.fs,\n\t\tsettings,\n\t\tpath: args.path,\n\t});\n\n\tconst providePluginsWithLocalPlugins = [\n\t\t...(args.providePlugins ?? []),\n\t\t...localImport.locallyImportedPlugins,\n\t];\n\n\t// TODO call tempProject.lix.settled() to wait for the new settings file, and remove reload of the proejct as soon as reactive settings has landed\n\t// NOTE: we need to ensure two things:\n\t// 1. settled needs to include the changes from the copyFiles call\n\t// 2. the changes created from the copyFiles call need to be realized and lead to a signal on the settings\n\tconst project = await loadProjectInMemory({\n\t\t...args,\n\t\tprovidePlugins: providePluginsWithLocalPlugins,\n\t\tlixKeyValues: inlangId\n\t\t\t? // reversing the id to have distinguishable lix ids from inlang ids\n\t\t\t\t[{ key: \"lix_id\", value: inlangId }]\n\t\t\t: undefined,\n\t\tblob: await newProject({\n\t\t\tsettings,\n\t\t}),\n\t});\n\n\tawait syncLixFsFiles({\n\t\tfs: args.fs,\n\t\tpath: args.path,\n\t\tlix: project.lix,\n\t\tsyncInterval: args.syncInterval,\n\t});\n\n\tconst allPlugins = await project.plugins.get();\n\tconst { loadSavePlugins, importExportPlugins } =\n\t\tcategorizePlugins(allPlugins);\n\n\t// TODO i guess we should move this validation logic into sdk2/src/project/loadProject.ts\n\t// Two scenarios could arise:\n\t// 1. set settings is called from an app - it should detect and reject the setting of settings -> app need to be able to validate before calling set\n\t// 2. the settings file loaded from disc here is corrupted -> user has to fix the file on disc\n\tif (loadSavePlugins.length > 1) {\n\t\tthrow new Error(\n\t\t\t\"Max one loadMessages (found: \" +\n\t\t\t\tloadSavePlugins.length +\n\t\t\t\t\") and one saveMessages plugins (found: \" +\n\t\t\t\tloadSavePlugins.length +\n\t\t\t\t\") are allowed \"\n\t\t);\n\t}\n\tconst importedResourceFileErrors: Error[] = [];\n\n\t// import files from local fs\n\tfor (const plugin of importExportPlugins) {\n\t\tconst files: ImportFile[] = [];\n\t\tif (plugin.toBeImportedFiles) {\n\t\t\tconst toBeImportedFiles = await plugin.toBeImportedFiles({\n\t\t\t\tsettings: await project.settings.get(),\n\t\t\t});\n\t\t\tfor (const toBeImported of toBeImportedFiles) {\n\t\t\t\tconst absolute = absolutePathFromProject(args.path, toBeImported.path);\n\t\t\t\ttry {\n\t\t\t\t\tconst data = await args.fs.promises.readFile(absolute);\n\t\t\t\t\tfiles.push({\n\t\t\t\t\t\tlocale: toBeImported.locale,\n\t\t\t\t\t\tcontent: data,\n\t\t\t\t\t\ttoBeImportedFilesMetadata: toBeImported.metadata,\n\t\t\t\t\t});\n\t\t\t\t} catch (e) {\n\t\t\t\t\t// https://github.com/opral/inlang-sdk/issues/202\n\t\t\t\t\tif ((e as any)?.code === \"ENOENT\") {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\timportedResourceFileErrors.push(\n\t\t\t\t\t\tnew ResourceFileImportError({\n\t\t\t\t\t\t\tcause: e as Error,\n\t\t\t\t\t\t\tpath: toBeImported.path,\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tawait project.importFiles({\n\t\t\tpluginKey: plugin.key,\n\t\t\tfiles,\n\t\t});\n\t}\n\n\tfor (const plugin of loadSavePlugins) {\n\t\tawait loadLegacyMessages({\n\t\t\tproject,\n\t\t\tpluginKey: plugin.key ?? plugin.id,\n\t\t\tloadMessagesFn: plugin.loadMessages!,\n\t\t\tprojectPath: args.path,\n\t\t\tfs: args.fs,\n\t\t});\n\t}\n\n\treturn {\n\t\t...project,\n\t\terrors: {\n\t\t\tget: async () => {\n\t\t\t\treturn [...localImport.errors, ...importedResourceFileErrors];\n\t\t\t},\n\t\t\t// subscribe: (\n\t\t\t// \tcallback: Parameters<InlangProject[\"errors\"][\"subscribe\"]>[0]\n\t\t\t// ) => {\n\t\t\t// \treturn project.errors.subscribe((value) => {\n\t\t\t// \t\tcallback([\n\t\t\t// \t\t\t...withLocallyImportedPluginWarning(value),\n\t\t\t// \t\t\t...localImport.errors,\n\t\t\t// \t\t\t...importedResourceFileErrors,\n\t\t\t// \t\t]);\n\t\t\t// \t});\n\t\t\t// },\n\t\t},\n\t};\n}\n\nasync function loadLegacyMessages(args: {\n\tproject: Awaited<ReturnType<typeof loadProjectInMemory>>;\n\tpluginKey: NonNullable<InlangPlugin[\"key\"] | InlangPlugin[\"id\"]>;\n\tloadMessagesFn: Required<InlangPlugin>[\"loadMessages\"];\n\tprojectPath: string;\n\tfs: typeof fs;\n}) {\n\tconst loadedLegacyMessages = await args.loadMessagesFn({\n\t\tsettings: await args.project.settings.get(),\n\t\t// @ts-expect-error - type mismatch\n\t\tnodeishFs: withAbsolutePaths(args.fs.promises, args.projectPath),\n\t});\n\tconst upsertQueries = [];\n\n\tfor (const legacyMessage of loadedLegacyMessages) {\n\t\tconst messageBundle = fromMessageV1(legacyMessage);\n\n\t\tupsertQueries.push(\n\t\t\tupsertBundleNestedMatchByProperties(args.project.db, messageBundle)\n\t\t);\n\t}\n\n\treturn await Promise.all(upsertQueries);\n}\n\ntype FsFileState = Record<\n\tstring,\n\t{\n\t\t/*mtime: number, hash: string, */ content: ArrayBuffer;\n\t\tstate: \"known\" | \"unknown\" | \"updated\" | \"gone\";\n\t}\n>;\n\nfunction arrayBuffersEqual(a: ArrayBuffer, b: ArrayBuffer) {\n\tif (a.byteLength !== b.byteLength) return false;\n\n\t// Create views for byte-by-byte comparison\n\tconst view1 = new Uint8Array(a);\n\tconst view2 = new Uint8Array(b);\n\n\t// Compare each byte\n\tfor (const [i, element] of view1.entries()) {\n\t\tif (element !== view2[i]) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\n/**\n * Watches a directory and copies files into lix, keeping them in sync.\n */\nasync function syncLixFsFiles(args: {\n\tfs: typeof fs;\n\tpath: string;\n\tlix: Lix;\n\tsyncInterval?: number;\n}) {\n\t// NOTE this function is async - while it runs 100% sync in the naiv implementation - we may want to change to an async version to optimize\n\tasync function checkFsStateRecursive(\n\t\tdirPath: string,\n\t\tcurrentState: FsFileState\n\t) {\n\t\tconst entries = args.fs.readdirSync(dirPath, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tconst fullPath = nodePath.join(dirPath, entry.name);\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tcheckFsStateRecursive(fullPath, currentState);\n\t\t\t} else {\n\t\t\t\t// NOTE we could start with comparing the mdate and skip file read completely...\n\t\t\t\tconst data = args.fs.readFileSync(fullPath) as unknown as ArrayBuffer;\n\n\t\t\t\tconst relativePath = \"/\" + nodePath.relative(args.path, fullPath);\n\n\t\t\t\tif (!currentState[relativePath]) {\n\t\t\t\t\tcurrentState[relativePath] = {\n\t\t\t\t\t\tcontent: data,\n\t\t\t\t\t\tstate: \"unknown\",\n\t\t\t\t\t};\n\t\t\t\t} else {\n\t\t\t\t\tif (arrayBuffersEqual(currentState[relativePath].content, data)) {\n\t\t\t\t\t\tcurrentState[relativePath].state = \"known\";\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcurrentState[relativePath].state = \"updated\";\n\t\t\t\t\t\tcurrentState[relativePath].content = data;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tasync function checkLixState(currentLixState: FsFileState) {\n\t\t// go through all files in lix and check there state\n\t\tconst filesInLix = await args.lix.db\n\t\t\t.selectFrom(\"file\")\n\t\t\t.where(\"path\", \"not like\", \"%db.sqlite\")\n\t\t\t.selectAll()\n\t\t\t.execute();\n\n\t\tfor (const fileInLix of filesInLix) {\n\t\t\tconst currentStateOfFileInLix = currentLixState[fileInLix.path];\n\t\t\t// NOTE we could start with comparing the mdate and skip file read completely...\n\t\t\tif (!currentStateOfFileInLix) {\n\t\t\t\tcurrentLixState[fileInLix.path] = {\n\t\t\t\t\tcontent: new Uint8Array(fileInLix.data).buffer,\n\t\t\t\t\tstate: \"unknown\",\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\tif (\n\t\t\t\t\tarrayBuffersEqual(\n\t\t\t\t\t\tcurrentStateOfFileInLix.content,\n\t\t\t\t\t\tfileInLix.data.buffer as ArrayBuffer\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tcurrentStateOfFileInLix.state = \"known\";\n\t\t\t\t} else {\n\t\t\t\t\tcurrentStateOfFileInLix.state = \"updated\";\n\t\t\t\t\tcurrentStateOfFileInLix.content = fileInLix.data\n\t\t\t\t\t\t.buffer as ArrayBuffer;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tasync function syncUpFsAndLixFiles(statesToSync: {\n\t\tfsFileStates: FsFileState;\n\t\tlixFileStates: FsFileState;\n\t}) {\n\t\t// for (const file of Object.keys(statesToSync.fsFileStates)) {\n\t\t// \tif (file.includes(\"gitignore\"))\n\t\t// \t\tconsole.log(\n\t\t// \t\t\t\"fsFileStates : \" +\n\t\t// \t\t\t\tfile +\n\t\t// \t\t\t\t\" fs \" +\n\t\t// \t\t\t\tstatesToSync.fsFileStates[file]?.state +\n\t\t// \t\t\t\t\" lix \" +\n\t\t// \t\t\t\tstatesToSync.lixFileStates[file]?.state\n\t\t// \t\t);\n\t\t// }\n\n\t\t// Sync cases:\n\t\t// fs - no state for file | fs - unkonwn | fs - known | fs - updated | fs - gone\n\t\t// lix - no state for file \tNOTHING\t(1)\t | ADD TO LIX(2) | ERROR (3) | ERROR (4) | ERROR (5)\n\t\t// lix - unknown\t\t\t\t\tADD TO FS (6) | USE FS VER.(7) | ERROR (8) | CASE (9) | CASE (10)\n\t\t// lix - known ERROR (11) | ERROR (12) | NOTHING(13) | ERROR (14) | ERROR (15)\n\t\t// lix - updated\t\t\t\t\tERROR (16) | ERROR (17) | USE LIX (18) | CASE (19) | CASE (20)\n\t\t// lix - gone \t\t\t\t\t\tERROR (21) | ERROR (22) | DELETE FS (23)| CASE (24) | CASE (25)\n\n\t\t// TODO check export import from saveFileToDirectory\n\n\t\tfor (const [path, fsState] of Object.entries(statesToSync.fsFileStates)) {\n\t\t\t// no state for file in LIX\n\t\t\tif (!statesToSync.lixFileStates[path]) {\n\t\t\t\tif (fsState.state === \"unknown\") {\n\t\t\t\t\t// ADD TO LIX(2)\n\t\t\t\t\tawait upsertFileInLix(args, path, fsState.content);\n\t\t\t\t\tstatesToSync.lixFileStates[path] = {\n\t\t\t\t\t\tstate: \"known\",\n\t\t\t\t\t\tcontent: fsState.content,\n\t\t\t\t\t};\n\t\t\t\t\tfsState.state = \"known\";\n\t\t\t\t} else {\n\t\t\t\t\t// ERROR (3), ERROR (4), ERROR (5)\n\t\t\t\t\t// The file does not exist in lix but its state differs from unknown?\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"Illeagal lix<->fs sync state. The file [\" +\n\t\t\t\t\t\t\tpath +\n\t\t\t\t\t\t\t\"] that was \" +\n\t\t\t\t\t\t\tfsState.state +\n\t\t\t\t\t\t\t\" on disc did not exit in lix\"\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst lixState = statesToSync.lixFileStates[path];\n\t\t\t\tif (fsState.state === \"unknown\") {\n\t\t\t\t\tif (lixState.state === \"unknown\") {\n\t\t\t\t\t\tif (arrayBuffersEqual(lixState.content, fsState.content)) {\n\t\t\t\t\t\t\tlixState.state = \"known\";\n\t\t\t\t\t\t\tfsState.state = \"known\";\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tawait upsertFileInLix(args, path, fsState.content);\n\t\t\t\t\t\t\tlixState.content = fsState.content;\n\t\t\t\t\t\t\tlixState.state = \"known\";\n\t\t\t\t\t\t\tfsState.state = \"known\";\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// ERROR 12, 17, 22\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\"Illeagal lix<->fs sync state. The file [\" +\n\t\t\t\t\t\t\t\tpath +\n\t\t\t\t\t\t\t\t\"] that was \" +\n\t\t\t\t\t\t\t\tfsState.state +\n\t\t\t\t\t\t\t\t\" but did exist in lix already\"\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} else if (fsState.state === \"known\") {\n\t\t\t\t\tif (lixState.state === \"known\") {\n\t\t\t\t\t\t// NO OP - NOTHING(13)\n\t\t\t\t\t} else if (lixState.state === \"updated\") {\n\t\t\t\t\t\t// USE LIX (18)\n\t\t\t\t\t\targs.fs.writeFileSync(\n\t\t\t\t\t\t\t// TODO check platform dependent folder separator\n\t\t\t\t\t\t\targs.path + path,\n\t\t\t\t\t\t\tBuffer.from(lixState.content)\n\t\t\t\t\t\t);\n\t\t\t\t\t\tfsState.content = lixState.content;\n\t\t\t\t\t\tfsState.state = \"known\";\n\t\t\t\t\t\tlixState.state = \"known\";\n\t\t\t\t\t} else if (lixState.state === \"gone\") {\n\t\t\t\t\t\t// DELETE FS (23)\n\t\t\t\t\t\targs.fs.unlinkSync(args.path + path);\n\t\t\t\t\t\tfsState.state = \"gone\";\n\t\t\t\t\t\tlixState.state = \"gone\";\n\t\t\t\t\t}\n\t\t\t\t} else if (fsState.state === \"updated\") {\n\t\t\t\t\tif (lixState.state === \"unknown\") {\n\t\t\t\t\t\t// TODO A file was added to lix while a known file from fs was updated?\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\"Illeagal lix<->fs sync state. The file [\" +\n\t\t\t\t\t\t\t\tpath +\n\t\t\t\t\t\t\t\t\"] that was \" +\n\t\t\t\t\t\t\t\tfsState.state +\n\t\t\t\t\t\t\t\t\" but it was not known by lix yet?\"\n\t\t\t\t\t\t);\n\t\t\t\t\t} else if (lixState.state === \"known\") {\n\t\t\t\t\t\tawait upsertFileInLix(args, path, fsState.content);\n\t\t\t\t\t\tlixState.content = fsState.content;\n\n\t\t\t\t\t\tfsState.state = \"known\";\n\t\t\t\t\t} else if (lixState.state === \"updated\") {\n\t\t\t\t\t\t// seems like we saw an update on the file in fs while some changes on lix have not been reached fs? FS -> Winns?\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\"seems like we saw an update on the file \" +\n\t\t\t\t\t\t\t\tpath +\n\t\t\t\t\t\t\t\t\" in fs while some changes on lix have not been reached fs? FS -> Winns?\"\n\t\t\t\t\t\t);\n\t\t\t\t\t\tawait upsertFileInLix(args, path, fsState.content);\n\t\t\t\t\t\tlixState.content = fsState.content;\n\t\t\t\t\t\tlixState.state = \"known\";\n\t\t\t\t\t\tfsState.state = \"known\";\n\t\t\t\t\t} else if (lixState.state === \"gone\") {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\"seems like we saw an delete in lix while some changes on fs have not been reached fs? FS -> Winns?\"\n\t\t\t\t\t\t);\n\t\t\t\t\t\t// TODO update the lix state\n\t\t\t\t\t\tlixState.content = fsState.content;\n\t\t\t\t\t\tlixState.state = \"known\";\n\t\t\t\t\t\tfsState.state = \"known\";\n\t\t\t\t\t}\n\t\t\t\t} else if (fsState.state === \"gone\") {\n\t\t\t\t\tif (lixState.state === \"unknown\") {\n\t\t\t\t\t\t// TODO A file was added to lix while a known file from fs was removed?\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\"Illeagal lix<->fs sync state. The file [\" +\n\t\t\t\t\t\t\t\tpath +\n\t\t\t\t\t\t\t\t\"] that was \" +\n\t\t\t\t\t\t\t\tfsState.state +\n\t\t\t\t\t\t\t\t\" but it was not known by lix yet?\"\n\t\t\t\t\t\t);\n\t\t\t\t\t} else if (lixState.state === \"known\") {\n\t\t\t\t\t\t// file is in known state with lix - means we have only changes on the fs - easy\n\t\t\t\t\t\tawait args.lix.db\n\t\t\t\t\t\t\t.deleteFrom(\"file\")\n\t\t\t\t\t\t\t.where(\"path\", \"=\", path)\n\t\t\t\t\t\t\t.execute();\n\t\t\t\t\t\t// NOTE: states where both are gone will get removed in the lix state loop\n\t\t\t\t\t\tlixState.state = \"gone\";\n\t\t\t\t\t} else if (lixState.state === \"updated\") {\n\t\t\t\t\t\t// seems like we saw an update on the file in fs while some changes on lix have not been reached fs? FS -> Winns?\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\"seems like we saw an update on the file in fs while some changes on lix have not been reached fs? FS -> Winns?\"\n\t\t\t\t\t\t);\n\t\t\t\t\t\tawait args.lix.db\n\t\t\t\t\t\t\t.deleteFrom(\"file\")\n\t\t\t\t\t\t\t.where(\"path\", \"=\", path)\n\t\t\t\t\t\t\t.execute();\n\t\t\t\t\t\t// NOTE: states where both are gone will get removed in the lix state loop\n\t\t\t\t\t\tlixState.state = \"gone\";\n\t\t\t\t\t\tfsState.state = \"gone\";\n\t\t\t\t\t} else if (lixState.state === \"gone\") {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\"seems like we saw an delete in lix while we have a delete in lix simultaniously?\"\n\t\t\t\t\t\t);\n\t\t\t\t\t\tlixState.state = \"gone\";\n\t\t\t\t\t\tfsState.state = \"gone\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const [path, lixState] of Object.entries(statesToSync.lixFileStates)) {\n\t\t\t// no state for file in fs\n\t\t\tif (!statesToSync.fsFileStates[path]) {\n\t\t\t\tif (lixState.state == \"unknown\") {\n\t\t\t\t\t// ADD TO FS (6)\n\t\t\t\t\t// create directory if not exists\n\t\t\t\t\ttry {\n\t\t\t\t\t\targs.fs.mkdirSync(\n\t\t\t\t\t\t\tnodePath.dirname(nodePath.join(args.path, path)),\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\trecursive: true,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t// ignore if directory already exists\n\t\t\t\t\t\t// https://github.com/opral/inlang-paraglide-js/issues/377\n\t\t\t\t\t\tif ((e as any)?.code !== \"EEXIST\") {\n\t\t\t\t\t\t\tthrow e;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// write file\n\t\t\t\t\targs.fs.writeFileSync(\n\t\t\t\t\t\tnodePath.join(args.path, path),\n\t\t\t\t\t\tBuffer.from(lixState.content)\n\t\t\t\t\t);\n\t\t\t\t\tstatesToSync.fsFileStates[path] = {\n\t\t\t\t\t\tstate: \"known\",\n\t\t\t\t\t\tcontent: lixState.content,\n\t\t\t\t\t};\n\t\t\t\t} else {\n\t\t\t\t\t// ERROR (11) 16 21\n\t\t\t\t\t// The file does not exist on fs but its state differs from unknown?\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"Illeagal lix<->fs sync state. The file [\" +\n\t\t\t\t\t\t\tpath +\n\t\t\t\t\t\t\t\"] that was in the state\" +\n\t\t\t\t\t\t\tlixState.state +\n\t\t\t\t\t\t\t\" for lix did not exist on disk\"\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (\n\t\t\t\t\tlixState.state === \"gone\" &&\n\t\t\t\t\tstatesToSync.fsFileStates[path].state === \"gone\"\n\t\t\t\t) {\n\t\t\t\t\tdelete statesToSync.lixFileStates[path];\n\t\t\t\t\tdelete statesToSync.fsFileStates[path];\n\t\t\t\t} else if (lixState.state !== statesToSync.fsFileStates[path].state) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"At this stage both states should be in sync lix state \" +\n\t\t\t\t\t\t\tlixState.state +\n\t\t\t\t\t\t\t\" fs state \" +\n\t\t\t\t\t\t\tstatesToSync.fsFileStates[path].state\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tasync function syncFiles(\n\t\tdirPath: string,\n\t\tfileStates: {\n\t\t\tlixFileStates: FsFileState;\n\t\t\tfsFileStates: FsFileState;\n\t\t},\n\t\tinterval?: number\n\t) {\n\t\t// mark all states as removed - checkFsStateRecursive will update those that exist on the disc correspondingly\n\t\tfor (const fsState of Object.values(fileStates.fsFileStates)) {\n\t\t\tfsState.state = \"gone\";\n\t\t}\n\n\t\t// mark all states as removed - checkFsStateRecursive will update those that exist on the disc correspondingly\n\t\tfor (const lixState of Object.values(fileStates.lixFileStates)) {\n\t\t\tlixState.state = \"gone\";\n\t\t}\n\n\t\t// read states from disc - detect changes\n\t\tawait checkFsStateRecursive(dirPath, fileStates.fsFileStates);\n\n\t\t// read states form lix - detect changes\n\t\tawait checkLixState(fileStates.lixFileStates);\n\n\t\t// sync fs<->lix\n\t\tawait syncUpFsAndLixFiles(fileStates);\n\n\t\tif (interval) {\n\t\t\tsetTimeout(() => {\n\t\t\t\tsyncFiles(dirPath, fileStates, interval);\n\t\t\t}, interval);\n\t\t}\n\n\t\treturn;\n\t}\n\n\t// Initial copy of all files\n\tawait syncFiles(\n\t\targs.path,\n\t\t{ fsFileStates: {}, lixFileStates: {} },\n\t\targs.syncInterval\n\t);\n\n\treturn;\n}\n\nasync function upsertFileInLix(\n\targs: { fs: typeof fs; path: string; lix: Lix },\n\tpath: string,\n\tdata: ArrayBuffer\n) {\n\t// force posix path when upserting into lix\n\t// https://github.com/opral/inlang-sdk/issues/229\n\tlet posixPath = path.split(nodePath.win32.sep).join(nodePath.posix.sep);\n\n\tif (posixPath.startsWith(\"/\") === false) {\n\t\tposixPath = \"/\" + posixPath;\n\t}\n\n\tawait args.lix.db\n\t\t.insertInto(\"file\") // change queue\n\t\t.values({\n\t\t\tpath: posixPath,\n\t\t\tdata: new Uint8Array(data),\n\t\t})\n\t\t.onConflict((oc) =>\n\t\t\toc.column(\"path\").doUpdateSet({ data: new Uint8Array(data) })\n\t\t)\n\t\t.execute();\n}\n/**\n * Filters legacy load and save messages plugins.\n *\n * Legacy plugins are plugins that implement loadMessages and saveMessages but not importFiles and exportFiles.\n */\nfunction categorizePlugins(plugins: readonly InlangPlugin[]) {\n\tconst loadSavePlugins: InlangPlugin[] = [];\n\tconst importExportPlugins: InlangPlugin[] = [];\n\n\tfor (const plugin of plugins) {\n\t\tif (\n\t\t\tplugin.loadMessages &&\n\t\t\tplugin.saveMessages &&\n\t\t\t!(plugin.importFiles && plugin.exportFiles)\n\t\t) {\n\t\t\tloadSavePlugins.push(plugin);\n\t\t} else if (plugin.importFiles || plugin.exportFiles) {\n\t\t\timportExportPlugins.push(plugin);\n\t\t}\n\t}\n\n\treturn { loadSavePlugins, importExportPlugins };\n}\n\n/**\n * Imports local plugins for backwards compatibility.\n *\n * https://github.com/opral/inlang-sdk/issues/171\n */\nasync function importLocalPlugins(args: {\n\tfs: typeof fs;\n\tsettings: ProjectSettings;\n\tpath: string;\n\tpreprocessPluginBeforeImport?: PreprocessPluginBeforeImportFunction;\n}) {\n\tconst errors: Error[] = [];\n\tconst locallyImportedPlugins = [];\n\tfor (const module of args.settings.modules ?? []) {\n\t\tif (module.startsWith(\"http\")) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst modulePath = absolutePathFromProject(args.path, module);\n\t\ttry {\n\t\t\tlet moduleAsText = await args.fs.promises.readFile(modulePath, \"utf8\");\n\t\t\tif (moduleAsText.includes(\"messageLintRule\")) {\n\t\t\t\terrors.push(new WarningDeprecatedLintRule(module));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (args.preprocessPluginBeforeImport) {\n\t\t\t\tmoduleAsText = await args.preprocessPluginBeforeImport(moduleAsText);\n\t\t\t}\n\t\t\tconst moduleWithMimeType =\n\t\t\t\t\"data:application/javascript,\" + encodeURIComponent(moduleAsText);\n\t\t\tconst { default: plugin } = await import(\n\t\t\t\t/* @vite-ignore */ moduleWithMimeType\n\t\t\t);\n\t\t\tlocallyImportedPlugins.push(plugin);\n\t\t} catch (e) {\n\t\t\terrors.push(new PluginImportError({ plugin: module, cause: e as Error }));\n\t\t\tcontinue;\n\t\t}\n\t}\n\treturn {\n\t\terrors,\n\t\tlocallyImportedPlugins,\n\t};\n}\n\nexport class WarningDeprecatedLintRule extends Error {\n\tconstructor(module: string) {\n\t\tsuper(\n\t\t\t`The lint rule ${module} is deprecated. Please remove the lint rule from the settings. Lint rules are interim built into apps and will be succeeded by more generilizable lix validation rules.`\n\t\t);\n\t\tthis.name = \"WarningDeprecatedLintRule\";\n\t}\n}\n\n/**\n * Resolving absolute paths for fs functions.\n *\n * This mapping is required for backwards compatibility.\n * Relative paths in the project.inlang/settings.json\n * file are resolved to absolute paths with `*.inlang`\n * being pruned.\n *\n * @example\n * \"/website/project.inlang\"\n * \"./local-plugins/mock-plugin.js\"\n * -> \"/website/local-plugins/mock-plugin.js\"\n *\n */\nexport function withAbsolutePaths(\n\tfs: NodeFsPromisesSubsetLegacy,\n\tprojectPath: string\n): NodeFsPromisesSubsetLegacy {\n\treturn {\n\t\t// @ts-expect-error - node type mismatch\n\t\treadFile: (path, options) => {\n\t\t\treturn fs.readFile(absolutePathFromProject(projectPath, path), options);\n\t\t},\n\t\twriteFile: (path, data) => {\n\t\t\treturn fs.writeFile(absolutePathFromProject(projectPath, path), data);\n\t\t},\n\t\tmkdir: (path) => {\n\t\t\treturn fs.mkdir(absolutePathFromProject(projectPath, path));\n\t\t},\n\t\treaddir: (path) => {\n\t\t\treturn fs.readdir(absolutePathFromProject(projectPath, path));\n\t\t},\n\t};\n}\n\n/**\n * Joins a path from a project path.\n *\n * @example\n * absolutePathFromProject(\"/project.inlang\", \"./local-plugins/mock-plugin.js\") -> \"/local-plugins/mock-plugin.js\"\n *\n * absolutePathFromProject(\"/website/project.inlang\", \"./mock-plugin.js\") -> \"/website/mock-plugin.js\"\n */\nexport function absolutePathFromProject(\n\tprojectPath: string,\n\tfilePath: string\n): string {\n\t// Normalize paths for consistency across platforms\n\tconst normalizedProjectPath = nodePath\n\t\t.normalize(projectPath)\n\t\t.replace(/\\\\/g, \"/\");\n\tconst normalizedFilePath = nodePath.normalize(filePath).replace(/\\\\/g, \"/\");\n\n\t// Remove the last part of the project path (file name) to get the project root\n\tconst projectRoot = nodePath.dirname(normalizedProjectPath);\n\n\t// If filePath is already absolute, return it directly\n\tif (nodePath.isAbsolute(normalizedFilePath)) {\n\t\treturn normalizedFilePath;\n\t}\n\n\t// Compute absolute resolved path\n\tconst resolvedPath = nodePath.resolve(projectRoot, normalizedFilePath);\n\n\t// Ensure final path always uses forward slashes\n\treturn resolvedPath.replace(/\\\\/g, \"/\");\n}\n\nexport class ResourceFileImportError extends Error {\n\tpath: string;\n\n\tconstructor(args: { cause: Error; path: string }) {\n\t\tsuper(\"Could not import a resource file\");\n\t\tthis.name = \"ResourceFileImportError\";\n\t\tthis.cause = args.cause;\n\t\tthis.path = args.path;\n\t}\n}\n"]}
@@ -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.4.0",
4
+ SDK_VERSION: "2.4.2",
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.4.0\",\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.4.2\",\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inlang/sdk",
3
- "version": "2.4.0",
3
+ "version": "2.4.2",
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.1",
32
+ "@lix-js/sdk": "0.4.2",
33
33
  "sqlite-wasm-kysely": "0.3.0"
34
34
  },
35
35
  "devDependencies": {
@@ -705,21 +705,33 @@ export function withAbsolutePaths(
705
705
  * Joins a path from a project path.
706
706
  *
707
707
  * @example
708
- * joinPathFromProject("/project.inlang", "./local-plugins/mock-plugin.js") -> "/local-plugins/mock-plugin.js"
708
+ * absolutePathFromProject("/project.inlang", "./local-plugins/mock-plugin.js") -> "/local-plugins/mock-plugin.js"
709
709
  *
710
- * joinPathFromProject("/website/project.inlang", "./mock-plugin.js") -> "/website/mock-plugin.js"
710
+ * absolutePathFromProject("/website/project.inlang", "./mock-plugin.js") -> "/website/mock-plugin.js"
711
711
  */
712
- export function absolutePathFromProject(projectPath: string, path: string) {
713
- // need to remove the project path from the module path for legacy reasons
714
- // "/project.inlang/local-plugins/mock-plugin.js" -> "/local-plugins/mock-plugin.js"
715
- const pathWithoutProject = projectPath
716
- .split(nodePath.sep)
717
- .slice(0, -1)
718
- .join(nodePath.sep);
712
+ export function absolutePathFromProject(
713
+ projectPath: string,
714
+ filePath: string
715
+ ): string {
716
+ // Normalize paths for consistency across platforms
717
+ const normalizedProjectPath = nodePath
718
+ .normalize(projectPath)
719
+ .replace(/\\/g, "/");
720
+ const normalizedFilePath = nodePath.normalize(filePath).replace(/\\/g, "/");
721
+
722
+ // Remove the last part of the project path (file name) to get the project root
723
+ const projectRoot = nodePath.dirname(normalizedProjectPath);
724
+
725
+ // If filePath is already absolute, return it directly
726
+ if (nodePath.isAbsolute(normalizedFilePath)) {
727
+ return normalizedFilePath;
728
+ }
719
729
 
720
- const resolvedPath = nodePath.resolve(pathWithoutProject, path);
730
+ // Compute absolute resolved path
731
+ const resolvedPath = nodePath.resolve(projectRoot, normalizedFilePath);
721
732
 
722
- return resolvedPath;
733
+ // Ensure final path always uses forward slashes
734
+ return resolvedPath.replace(/\\/g, "/");
723
735
  }
724
736
 
725
737
  export class ResourceFileImportError extends Error {