btca-server 2.0.2 → 2.0.3

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.
@@ -41,13 +41,13 @@ export type ResourcesService = {
41
41
  options?: {
42
42
  quiet?: boolean;
43
43
  }
44
- ) => Promise<BtcaFsResource>;
45
- loadEffect: (
44
+ ) => Effect.Effect<BtcaFsResource, ResourceError, never>;
45
+ loadPromise: (
46
46
  name: string,
47
47
  options?: {
48
48
  quiet?: boolean;
49
49
  }
50
- ) => Effect.Effect<BtcaFsResource, ResourceError>;
50
+ ) => Promise<BtcaFsResource>;
51
51
  };
52
52
 
53
53
  const normalizeSearchPaths = (definition: GitResource): string[] => {
@@ -154,55 +154,56 @@ export const resolveResourceDefinition = (
154
154
  };
155
155
 
156
156
  export const createResourcesService = (config: ConfigServiceShape): ResourcesService => {
157
- const loadEffect: ResourcesService['loadEffect'] = (name, options) =>
158
- Effect.gen(function* () {
159
- const quiet = options?.quiet ?? false;
160
- const definition = yield* Effect.try({
161
- try: () => resolveResourceDefinition(name, config.getResource),
162
- catch: (cause) =>
163
- cause instanceof ResourceError
164
- ? cause
165
- : new ResourceError({
166
- message: `Failed to resolve resource "${name}"`,
167
- hint: `${CommonHints.LIST_RESOURCES} ${CommonHints.ADD_RESOURCE}`,
168
- cause
169
- })
170
- });
171
-
172
- if (isGitResource(definition)) {
173
- return yield* Effect.tryPromise({
174
- try: () =>
175
- loadGitResource(definitionToGitArgs(definition, config.resourcesDirectory, quiet)),
176
- catch: (cause) =>
177
- cause instanceof ResourceError
178
- ? cause
179
- : new ResourceError({
180
- message: `Failed to load git resource "${name}"`,
181
- hint: CommonHints.CLEAR_CACHE,
182
- cause
183
- })
157
+ const loadPromise: ResourcesService['loadPromise'] = async (name, options) => {
158
+ const quiet = options?.quiet ?? false;
159
+ const definition = resolveResourceDefinition(name, config.getResource);
160
+
161
+ if (isGitResource(definition)) {
162
+ try {
163
+ return await loadGitResource(
164
+ definitionToGitArgs(definition, config.resourcesDirectory, quiet)
165
+ );
166
+ } catch (cause) {
167
+ if (cause instanceof ResourceError) throw cause;
168
+ throw new ResourceError({
169
+ message: `Failed to load git resource "${name}"`,
170
+ hint: CommonHints.CLEAR_CACHE,
171
+ cause
184
172
  });
185
173
  }
174
+ }
186
175
 
187
- if (isNpmResource(definition)) {
188
- return yield* Effect.tryPromise({
189
- try: () => loadNpmResource(definitionToNpmArgs(definition, config.resourcesDirectory)),
190
- catch: (cause) =>
191
- cause instanceof ResourceError
192
- ? cause
193
- : new ResourceError({
194
- message: `Failed to load npm resource "${name}"`,
195
- hint: CommonHints.CLEAR_CACHE,
196
- cause
197
- })
176
+ if (isNpmResource(definition)) {
177
+ try {
178
+ return await loadNpmResource(definitionToNpmArgs(definition, config.resourcesDirectory));
179
+ } catch (cause) {
180
+ if (cause instanceof ResourceError) throw cause;
181
+ throw new ResourceError({
182
+ message: `Failed to load npm resource "${name}"`,
183
+ hint: CommonHints.CLEAR_CACHE,
184
+ cause
198
185
  });
199
186
  }
187
+ }
188
+
189
+ return loadLocalResource(definitionToLocalArgs(definition));
190
+ };
200
191
 
201
- return loadLocalResource(definitionToLocalArgs(definition));
192
+ const load: ResourcesService['load'] = (name, options) =>
193
+ Effect.tryPromise({
194
+ try: () => loadPromise(name, options),
195
+ catch: (cause) =>
196
+ cause instanceof ResourceError
197
+ ? cause
198
+ : new ResourceError({
199
+ message: `Failed to resolve resource "${name}"`,
200
+ hint: `${CommonHints.LIST_RESOURCES} ${CommonHints.ADD_RESOURCE}`,
201
+ cause
202
+ })
202
203
  });
203
204
 
204
205
  return {
205
- load: (name, options) => Effect.runPromise(loadEffect(name, options)),
206
- loadEffect
206
+ load,
207
+ loadPromise
207
208
  };
208
209
  };
@@ -281,3 +281,76 @@ export const importDirectoryIntoVirtualFs = async (args: {
281
281
  await mkdirVirtualFs(dest, { recursive: true }, vfsId);
282
282
  await walk(base);
283
283
  };
284
+
285
+ export const importPathsIntoVirtualFs = async (args: {
286
+ sourcePath: string;
287
+ destinationPath: string;
288
+ relativePaths: readonly string[];
289
+ vfsId?: string;
290
+ }) => {
291
+ const base = path.resolve(args.sourcePath);
292
+ const dest = normalizeVfsPath(args.destinationPath);
293
+ const vfsId = args.vfsId;
294
+ const uniquePaths = Array.from(
295
+ new Set(
296
+ args.relativePaths
297
+ .map((relativePath) => relativePath.trim())
298
+ .filter((relativePath) => relativePath.length > 0 && relativePath !== '.')
299
+ )
300
+ ).sort((left, right) => left.localeCompare(right));
301
+
302
+ await mkdirVirtualFs(dest, { recursive: true }, vfsId);
303
+
304
+ for (const relativePath of uniquePaths) {
305
+ const sourcePath = path.join(base, relativePath);
306
+ const destinationPath = normalizeVfsPath(
307
+ posix.join(dest, relativePath.split(path.sep).join('/'))
308
+ );
309
+
310
+ let stat: Awaited<ReturnType<typeof fs.lstat>> | null = null;
311
+ try {
312
+ stat = await fs.lstat(sourcePath);
313
+ } catch {
314
+ stat = null;
315
+ }
316
+ if (!stat) continue;
317
+
318
+ await mkdirVirtualFs(posix.dirname(destinationPath), { recursive: true }, vfsId);
319
+
320
+ if (stat.isDirectory()) {
321
+ await mkdirVirtualFs(destinationPath, { recursive: true }, vfsId);
322
+ continue;
323
+ }
324
+
325
+ if (stat.isSymbolicLink()) {
326
+ let target: string | null = null;
327
+ try {
328
+ target = await fs.readlink(sourcePath);
329
+ } catch {
330
+ target = null;
331
+ }
332
+ if (!target) continue;
333
+ try {
334
+ await symlinkVirtualFs(target, destinationPath, vfsId);
335
+ } catch {
336
+ // Ignore invalid symlink entries while importing.
337
+ }
338
+ continue;
339
+ }
340
+
341
+ if (!stat.isFile()) continue;
342
+
343
+ let buffer: Buffer | null = null;
344
+ try {
345
+ buffer = await fs.readFile(sourcePath);
346
+ } catch {
347
+ buffer = null;
348
+ }
349
+ if (!buffer) continue;
350
+ try {
351
+ await writeVirtualFsFile(destinationPath, buffer, vfsId);
352
+ } catch {
353
+ // Ignore individual file write errors while importing.
354
+ }
355
+ }
356
+ };