@valbuild/server 0.60.24 → 0.61.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.
@@ -2,7 +2,7 @@
2
2
  import { Service } from "./Service.js";
3
3
  import { result } from "@valbuild/core/fp";
4
4
  import { Patch } from "./patch/validation.js";
5
- import { ApiGetPatchResponse, ApiPostPatchResponse, ModuleId, PatchId, ApiDeletePatchResponse, FileMetadata, ImageMetadata } from "@valbuild/core";
5
+ import { ApiGetPatchResponse, ApiPostPatchResponse, ModuleId, PatchId, ApiDeletePatchResponse, FileMetadata, ImageMetadata, ValModules } from "@valbuild/core";
6
6
  import { VAL_ENABLE_COOKIE_NAME, VAL_SESSION_COOKIE, VAL_STATE_COOKIE, ValServerError, ValServerJsonResult, ValServerRedirectResult, ValServerResult, ValSession } from "@valbuild/shared/internal";
7
7
  import { ValServer, ValServerCallbacks } from "./ValServer.js";
8
8
  import { SerializedModuleContent } from "./SerializedModuleContent.js";
@@ -20,13 +20,14 @@ export interface ValServerBufferHost {
20
20
  readBuffer: (fileName: string) => Promise<Buffer | undefined>;
21
21
  }
22
22
  export declare class LocalValServer extends ValServer {
23
+ readonly valModules: ValModules;
23
24
  readonly options: LocalValServerOptions;
24
25
  readonly callbacks: ValServerCallbacks;
25
26
  private readonly host;
26
27
  private static readonly PATCHES_DIR;
27
28
  private static readonly FILES_DIR;
28
29
  private readonly patchesRootPath;
29
- constructor(options: LocalValServerOptions, callbacks: ValServerCallbacks);
30
+ constructor(valModules: ValModules, options: LocalValServerOptions, callbacks: ValServerCallbacks);
30
31
  session(): Promise<ValServerJsonResult<ValSession>>;
31
32
  deletePatches(query: {
32
33
  id?: string[];
@@ -44,10 +45,8 @@ export declare class LocalValServer extends ValServer {
44
45
  private getPatchFilePath;
45
46
  private badRequest;
46
47
  protected ensureInitialized(): Promise<result.Result<undefined, ValServerError>>;
47
- protected getModule(moduleId: ModuleId, options: {
48
- source: boolean;
49
- schema: boolean;
50
- }): Promise<SerializedModuleContent>;
48
+ private getSerializedModules;
49
+ protected getModule(moduleId: ModuleId): Promise<SerializedModuleContent>;
51
50
  protected getAllModules(treePath: string): Promise<ModuleId[]>;
52
51
  protected execCommit(patches: [PatchId, ModuleId, Patch][]): Promise<{
53
52
  status: 200;
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { ApiCommitResponse, ApiGetPatchResponse, ApiPostPatchResponse, ApiPostValidationErrorResponse, ApiTreeResponse, ApiDeletePatchResponse, ApiPostValidationResponse } from "@valbuild/core";
2
+ import { ApiCommitResponse, ApiGetPatchResponse, ApiPostPatchResponse, ApiPostValidationErrorResponse, ApiTreeResponse, ApiDeletePatchResponse, ApiPostValidationResponse, ValModules } from "@valbuild/core";
3
3
  import { VAL_ENABLE_COOKIE_NAME, VAL_SESSION_COOKIE, VAL_STATE_COOKIE, ValCookies, ValServerError, ValServerJsonResult, ValServerRedirectResult, ValServerResult, ValSession } from "@valbuild/shared/internal";
4
4
  import { result } from "@valbuild/core/fp";
5
5
  import { Operation } from "@valbuild/core/patch";
@@ -16,9 +16,10 @@ export type ValServerOptions = {
16
16
  };
17
17
  export declare abstract class ValServer implements IValServer {
18
18
  readonly cwd: string;
19
+ readonly valModules: ValModules;
19
20
  readonly options: ValServerOptions;
20
21
  readonly callbacks: ValServerCallbacks;
21
- constructor(cwd: string, options: ValServerOptions, callbacks: ValServerCallbacks);
22
+ constructor(cwd: string, valModules: ValModules, options: ValServerOptions, callbacks: ValServerCallbacks);
22
23
  enable(query: {
23
24
  redirect_to?: string;
24
25
  }): Promise<ValServerRedirectResult<VAL_ENABLE_COOKIE_NAME>>;
@@ -1,6 +1,6 @@
1
1
  import { ServiceOptions } from "./Service.js";
2
2
  import { IValServer, ValServerCallbacks } from "./ValServer.js";
3
- import { ValConfig } from "@valbuild/core";
3
+ import { ValConfig, ValModules } from "@valbuild/core";
4
4
  import { ValServerGenericResult } from "@valbuild/shared/internal";
5
5
  type Versions = {
6
6
  versions?: {
@@ -114,7 +114,7 @@ type ValServerOverrides = Partial<{
114
114
  */
115
115
  disableCache?: boolean;
116
116
  }>;
117
- export declare function createValServer(route: string, opts: ValApiOptions, callbacks: ValServerCallbacks): Promise<IValServer>;
117
+ export declare function createValServer(valModules: ValModules, route: string, opts: ValApiOptions, callbacks: ValServerCallbacks): Promise<IValServer>;
118
118
  export declare function safeReadGit(cwd: string): Promise<{
119
119
  commit?: string;
120
120
  branch?: string;
@@ -4,5 +4,5 @@ import { type ValSyntaxErrorTree } from "./patch/ts/syntax.js";
4
4
  import { ValSourceFileHandler } from "./ValSourceFileHandler.js";
5
5
  import { QuickJSRuntime } from "quickjs-emscripten";
6
6
  import ts from "typescript";
7
- export declare const patchValFile: (id: string, valConfigPath: string, patch: Patch, sourceFileHandler: ValSourceFileHandler, runtime: QuickJSRuntime) => Promise<void>;
7
+ export declare const patchValFile: (id: string, rootDir: string, patch: Patch, sourceFileHandler: ValSourceFileHandler, runtime: QuickJSRuntime) => Promise<void>;
8
8
  export declare const patchSourceFile: (sourceFile: ts.SourceFile | string, patch: Patch) => result.Result<ts.SourceFile, ValSyntaxErrorTree | PatchError>;
@@ -633,6 +633,10 @@ class TSOps {
633
633
  }
634
634
  }
635
635
 
636
+ function getSyntheticContainingPath(rootDir) {
637
+ return path__namespace["default"].join(rootDir, "<val>"); // TODO: this is the synthetic path used when evaluating / patching modules. I am not sure <val> is the best choice: val.ts / js better? But that is weird too. At least now it is clear(er) that it is indeed a synthetic file (i.e. not an actual file)
638
+ }
639
+
636
640
  const ops$1 = new TSOps(document => {
637
641
  return fp.pipe(analyzeValModule(document), fp.result.map(({
638
642
  source
@@ -640,10 +644,10 @@ const ops$1 = new TSOps(document => {
640
644
  });
641
645
 
642
646
  // TODO: rename to patchValFiles since we may write multiple files
643
- const patchValFile = async (id, valConfigPath, patch$1, sourceFileHandler, runtime) => {
647
+ const patchValFile = async (id, rootDir, patch$1, sourceFileHandler, runtime) => {
644
648
  // const timeId = randomUUID();
645
649
  // console.time("patchValFile" + timeId);
646
- const filePath = sourceFileHandler.resolveSourceModulePath(valConfigPath, `.${id}.val`);
650
+ const filePath = sourceFileHandler.resolveSourceModulePath(getSyntheticContainingPath(rootDir), `.${id}.val`);
647
651
  const sourceFile = sourceFileHandler.getSourceFile(filePath);
648
652
  if (!sourceFile) {
649
653
  throw Error(`Source file ${filePath} not found`);
@@ -741,9 +745,7 @@ globalThis.valModule = {
741
745
  defaultExport: !!valModule?.default,
742
746
  };
743
747
  `;
744
- const result = context.evalCode(code,
745
- // Synthetic module name
746
- path__namespace["default"].join(rootDirPath, "<val>"));
748
+ const result = context.evalCode(code, getSyntheticContainingPath(rootDirPath));
747
749
  const fatalErrors = [];
748
750
  if (result.error) {
749
751
  const error = result.error.consume(context.dump);
@@ -1412,8 +1414,9 @@ function getValidationErrorMetadata(validationError) {
1412
1414
 
1413
1415
  const ops = new patch.JSONOps();
1414
1416
  class ValServer {
1415
- constructor(cwd, options, callbacks) {
1417
+ constructor(cwd, valModules, options, callbacks) {
1416
1418
  this.cwd = cwd;
1419
+ this.valModules = valModules;
1417
1420
  this.options = options;
1418
1421
  this.callbacks = callbacks;
1419
1422
  }
@@ -2050,8 +2053,9 @@ const textEncoder = new TextEncoder();
2050
2053
  class LocalValServer extends ValServer {
2051
2054
  static PATCHES_DIR = "patches";
2052
2055
  static FILES_DIR = "files";
2053
- constructor(options, callbacks) {
2054
- super(options.service.sourceFileHandler.projectRoot, options, callbacks);
2056
+ constructor(valModules, options, callbacks) {
2057
+ super(options.service.sourceFileHandler.projectRoot, valModules, options, callbacks);
2058
+ this.valModules = valModules;
2055
2059
  this.options = options;
2056
2060
  this.callbacks = callbacks;
2057
2061
  this.patchesRootPath = options.cacheDir || path__namespace["default"].join(options.service.sourceFileHandler.projectRoot, ".val");
@@ -2320,19 +2324,59 @@ class LocalValServer extends ValServer {
2320
2324
  // No RemoteFS so nothing to ensure
2321
2325
  return fp.result.ok(undefined);
2322
2326
  }
2323
- getModule(moduleId, options) {
2324
- return this.options.service.get(moduleId, "", {
2325
- ...options,
2326
- validate: false
2327
+ getSerializedModules() {
2328
+ return Promise.all(this.valModules.modules.map(({
2329
+ def
2330
+ }, i) => {
2331
+ return def().then(({
2332
+ default: valModule
2333
+ }) => {
2334
+ var _Internal$getSchema;
2335
+ const path = core.Internal.getValPath(valModule);
2336
+ if (!path) {
2337
+ throw Error(`Module defined at pos: ${i} is missing path`);
2338
+ }
2339
+ const source = core.Internal.getSource(valModule);
2340
+ if (!source) {
2341
+ // TODO
2342
+ throw Error(`Module defined at pos: ${i} is missing source`);
2343
+ }
2344
+ const schema = (_Internal$getSchema = core.Internal.getSchema(valModule)) === null || _Internal$getSchema === void 0 ? void 0 : _Internal$getSchema.serialize();
2345
+ if (!schema) {
2346
+ // TODO
2347
+ throw Error(`Module defined at pos: ${i} is missing schema`);
2348
+ }
2349
+ return {
2350
+ path,
2351
+ source: source,
2352
+ errors: false,
2353
+ //valModule[GetSchema]?.validate(path, source),
2354
+ schema: schema
2355
+ };
2356
+ });
2357
+ }));
2358
+ }
2359
+ getModule(moduleId) {
2360
+ // TODO: do not get all modules - we only should only get the ones we need
2361
+ return this.getSerializedModules().then(all => {
2362
+ const found = all.find(valModule => valModule.path === moduleId);
2363
+ if (!found) {
2364
+ throw Error(`Module ${moduleId} not found`);
2365
+ }
2366
+ return found;
2327
2367
  });
2328
2368
  }
2329
2369
  async getAllModules(treePath) {
2330
- const moduleIds = this.host.readDirectory(this.cwd, ["ts", "js"], ["node_modules", ".*"], ["**/*.val.ts", "**/*.val.js"]).filter(file => {
2370
+ const moduleIds = (await this.getSerializedModules()).filter(({
2371
+ path
2372
+ }) => {
2331
2373
  if (treePath) {
2332
- return file.replace(this.cwd, "").startsWith(treePath);
2374
+ return path.startsWith(treePath);
2333
2375
  }
2334
2376
  return true;
2335
- }).map(file => file.replace(this.cwd, "").replace(".val.js", "").replace(".val.ts", "").split(path__namespace["default"].sep).join("/"));
2377
+ }).map(({
2378
+ path
2379
+ }) => path);
2336
2380
  return moduleIds;
2337
2381
  }
2338
2382
  async execCommit(patches) {
@@ -2423,30 +2467,72 @@ function encodeJwt(payload, sessionKey) {
2423
2467
 
2424
2468
  class ProxyValServer extends ValServer {
2425
2469
  moduleCache = null;
2426
- constructor(cwd, options, apiOptions, callbacks) {
2427
- super(cwd, options, callbacks);
2470
+ constructor(cwd, valModules, options, apiOptions, callbacks) {
2471
+ super(cwd, valModules, options, callbacks);
2428
2472
  this.cwd = cwd;
2473
+ this.valModules = valModules;
2429
2474
  this.options = options;
2430
2475
  this.apiOptions = apiOptions;
2431
2476
  this.callbacks = callbacks;
2432
2477
  this.moduleCache = null;
2433
2478
  }
2434
2479
 
2435
- /** Remote FS dependent methods: */
2480
+ // TODO: restructure this
2436
2481
 
2437
- async getModule(moduleId,
2438
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2439
- _options) {
2440
- if (this.moduleCache) {
2441
- return this.moduleCache[moduleId];
2442
- }
2443
- throw new Error("Module cache not initialized");
2482
+ getSerializedModules() {
2483
+ return Promise.all(this.valModules.modules.map(({
2484
+ def
2485
+ }, i) => {
2486
+ return def().then(({
2487
+ default: valModule
2488
+ }) => {
2489
+ var _Internal$getSchema;
2490
+ const path = core.Internal.getValPath(valModule);
2491
+ if (!path) {
2492
+ throw Error(`Module defined at pos: ${i} is missing path`);
2493
+ }
2494
+ const source = core.Internal.getSource(valModule);
2495
+ if (!source) {
2496
+ // TODO
2497
+ throw Error(`Module defined at pos: ${i} is missing source`);
2498
+ }
2499
+ const schema = (_Internal$getSchema = core.Internal.getSchema(valModule)) === null || _Internal$getSchema === void 0 ? void 0 : _Internal$getSchema.serialize();
2500
+ if (!schema) {
2501
+ // TODO
2502
+ throw Error(`Module defined at pos: ${i} is missing schema`);
2503
+ }
2504
+ return {
2505
+ path,
2506
+ source: source,
2507
+ errors: false,
2508
+ //valModule[GetSchema]?.validate(path, source),
2509
+ schema: schema
2510
+ };
2511
+ });
2512
+ }));
2513
+ }
2514
+ getModule(moduleId) {
2515
+ // TODO: do not get all modules - we only should only get the ones we need
2516
+ return this.getSerializedModules().then(all => {
2517
+ const found = all.find(valModule => valModule.path === moduleId);
2518
+ if (!found) {
2519
+ throw Error(`Module ${moduleId} not found`);
2520
+ }
2521
+ return found;
2522
+ });
2444
2523
  }
2445
2524
  async getAllModules(treePath) {
2446
- if (!this.moduleCache) {
2447
- throw new Error("Module cache not initialized");
2448
- }
2449
- return Object.keys(this.moduleCache).filter(moduleId => moduleId.startsWith(treePath));
2525
+ const moduleIds = (await this.getSerializedModules()).filter(({
2526
+ path
2527
+ }) => {
2528
+ if (treePath) {
2529
+ return path.startsWith(treePath);
2530
+ }
2531
+ return true;
2532
+ }).map(({
2533
+ path
2534
+ }) => path);
2535
+ return moduleIds;
2450
2536
  }
2451
2537
  execCommit(patches, cookies) {
2452
2538
  return withAuth(this.options.valSecret, cookies, "execCommit", async ({
@@ -2487,67 +2573,14 @@ class ProxyValServer extends ValServer {
2487
2573
  }
2488
2574
  });
2489
2575
  }
2490
- async init(commit, token) {
2491
- const params = createParams({
2492
- root: this.apiOptions.root,
2493
- commit,
2494
- ext: ["ts", "js", "json"],
2495
- package: ["@valbuild/core@" + this.options.versions.core, "@valbuild/next@" + this.options.versions.next],
2496
- include: ["**/*.val.{js,ts},package.json,tsconfig.json,jsconfig.json"]
2497
- });
2498
- const url = new URL(`/v1/eval/${this.options.remote}/heads/${this.options.git.branch}/~?${params}`, this.options.valContentUrl);
2499
- try {
2500
- const fetchRes = await fetch(url, {
2501
- headers: getAuthHeaders(token, "application/json")
2502
- });
2503
- if (fetchRes.status === 200) {
2504
- const json = await fetchRes.json();
2505
- let error = false;
2506
- if (typeof json !== "object") {
2507
- error = {
2508
- details: "Invalid response: not an object"
2509
- };
2510
- }
2511
- if (typeof json.git !== "object") {
2512
- error = {
2513
- details: "Invalid response: missing git"
2514
- };
2515
- }
2516
- if (typeof json.git.commit !== "string") {
2517
- error = {
2518
- details: "Invalid response: missing git.commit"
2519
- };
2520
- }
2521
- if (typeof json.modules !== "object" || json.modules === null) {
2522
- error = {
2523
- details: "Invalid response: missing modules"
2524
- };
2525
- }
2526
- if (error) {
2527
- console.error("Could not initialize remote modules", error);
2528
- return {
2529
- status: 500,
2530
- json: {
2531
- message: "Failed to fetch remote modules",
2532
- ...error
2533
- }
2534
- };
2535
- }
2536
- this.moduleCache = json.modules;
2537
- return {
2538
- status: 200
2539
- };
2540
- } else {
2541
- return createJsonError(fetchRes);
2542
- }
2543
- } catch (err) {
2544
- return {
2545
- status: 500,
2546
- json: {
2547
- message: "Failed to fetch: check network connection"
2548
- }
2549
- };
2550
- }
2576
+ async init(
2577
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2578
+ _commit,
2579
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2580
+ _token) {
2581
+ return {
2582
+ status: 200
2583
+ };
2551
2584
  }
2552
2585
  async ensureInitialized(errorMessageType, cookies) {
2553
2586
  const commit = this.options.git.commit;
@@ -3116,13 +3149,13 @@ function createParams(params) {
3116
3149
  return paramsString;
3117
3150
  }
3118
3151
 
3119
- async function createValServer(route, opts, callbacks) {
3152
+ async function createValServer(valModules, route, opts, callbacks) {
3120
3153
  const serverOpts = await initHandlerOptions(route, opts);
3121
3154
  if (serverOpts.mode === "proxy") {
3122
3155
  const projectRoot = process.cwd(); //[process.cwd(), opts.root || ""] .filter((seg) => seg) .join("/");
3123
- return new ProxyValServer(projectRoot, serverOpts, opts, callbacks);
3156
+ return new ProxyValServer(projectRoot, valModules, serverOpts, opts, callbacks);
3124
3157
  } else {
3125
- return new LocalValServer(serverOpts, callbacks);
3158
+ return new LocalValServer(valModules, serverOpts, callbacks);
3126
3159
  }
3127
3160
  }
3128
3161
  async function initHandlerOptions(route, opts) {
@@ -633,6 +633,10 @@ class TSOps {
633
633
  }
634
634
  }
635
635
 
636
+ function getSyntheticContainingPath(rootDir) {
637
+ return path__namespace["default"].join(rootDir, "<val>"); // TODO: this is the synthetic path used when evaluating / patching modules. I am not sure <val> is the best choice: val.ts / js better? But that is weird too. At least now it is clear(er) that it is indeed a synthetic file (i.e. not an actual file)
638
+ }
639
+
636
640
  const ops$1 = new TSOps(document => {
637
641
  return fp.pipe(analyzeValModule(document), fp.result.map(({
638
642
  source
@@ -640,10 +644,10 @@ const ops$1 = new TSOps(document => {
640
644
  });
641
645
 
642
646
  // TODO: rename to patchValFiles since we may write multiple files
643
- const patchValFile = async (id, valConfigPath, patch$1, sourceFileHandler, runtime) => {
647
+ const patchValFile = async (id, rootDir, patch$1, sourceFileHandler, runtime) => {
644
648
  // const timeId = randomUUID();
645
649
  // console.time("patchValFile" + timeId);
646
- const filePath = sourceFileHandler.resolveSourceModulePath(valConfigPath, `.${id}.val`);
650
+ const filePath = sourceFileHandler.resolveSourceModulePath(getSyntheticContainingPath(rootDir), `.${id}.val`);
647
651
  const sourceFile = sourceFileHandler.getSourceFile(filePath);
648
652
  if (!sourceFile) {
649
653
  throw Error(`Source file ${filePath} not found`);
@@ -741,9 +745,7 @@ globalThis.valModule = {
741
745
  defaultExport: !!valModule?.default,
742
746
  };
743
747
  `;
744
- const result = context.evalCode(code,
745
- // Synthetic module name
746
- path__namespace["default"].join(rootDirPath, "<val>"));
748
+ const result = context.evalCode(code, getSyntheticContainingPath(rootDirPath));
747
749
  const fatalErrors = [];
748
750
  if (result.error) {
749
751
  const error = result.error.consume(context.dump);
@@ -1412,8 +1414,9 @@ function getValidationErrorMetadata(validationError) {
1412
1414
 
1413
1415
  const ops = new patch.JSONOps();
1414
1416
  class ValServer {
1415
- constructor(cwd, options, callbacks) {
1417
+ constructor(cwd, valModules, options, callbacks) {
1416
1418
  this.cwd = cwd;
1419
+ this.valModules = valModules;
1417
1420
  this.options = options;
1418
1421
  this.callbacks = callbacks;
1419
1422
  }
@@ -2050,8 +2053,9 @@ const textEncoder = new TextEncoder();
2050
2053
  class LocalValServer extends ValServer {
2051
2054
  static PATCHES_DIR = "patches";
2052
2055
  static FILES_DIR = "files";
2053
- constructor(options, callbacks) {
2054
- super(options.service.sourceFileHandler.projectRoot, options, callbacks);
2056
+ constructor(valModules, options, callbacks) {
2057
+ super(options.service.sourceFileHandler.projectRoot, valModules, options, callbacks);
2058
+ this.valModules = valModules;
2055
2059
  this.options = options;
2056
2060
  this.callbacks = callbacks;
2057
2061
  this.patchesRootPath = options.cacheDir || path__namespace["default"].join(options.service.sourceFileHandler.projectRoot, ".val");
@@ -2320,19 +2324,59 @@ class LocalValServer extends ValServer {
2320
2324
  // No RemoteFS so nothing to ensure
2321
2325
  return fp.result.ok(undefined);
2322
2326
  }
2323
- getModule(moduleId, options) {
2324
- return this.options.service.get(moduleId, "", {
2325
- ...options,
2326
- validate: false
2327
+ getSerializedModules() {
2328
+ return Promise.all(this.valModules.modules.map(({
2329
+ def
2330
+ }, i) => {
2331
+ return def().then(({
2332
+ default: valModule
2333
+ }) => {
2334
+ var _Internal$getSchema;
2335
+ const path = core.Internal.getValPath(valModule);
2336
+ if (!path) {
2337
+ throw Error(`Module defined at pos: ${i} is missing path`);
2338
+ }
2339
+ const source = core.Internal.getSource(valModule);
2340
+ if (!source) {
2341
+ // TODO
2342
+ throw Error(`Module defined at pos: ${i} is missing source`);
2343
+ }
2344
+ const schema = (_Internal$getSchema = core.Internal.getSchema(valModule)) === null || _Internal$getSchema === void 0 ? void 0 : _Internal$getSchema.serialize();
2345
+ if (!schema) {
2346
+ // TODO
2347
+ throw Error(`Module defined at pos: ${i} is missing schema`);
2348
+ }
2349
+ return {
2350
+ path,
2351
+ source: source,
2352
+ errors: false,
2353
+ //valModule[GetSchema]?.validate(path, source),
2354
+ schema: schema
2355
+ };
2356
+ });
2357
+ }));
2358
+ }
2359
+ getModule(moduleId) {
2360
+ // TODO: do not get all modules - we only should only get the ones we need
2361
+ return this.getSerializedModules().then(all => {
2362
+ const found = all.find(valModule => valModule.path === moduleId);
2363
+ if (!found) {
2364
+ throw Error(`Module ${moduleId} not found`);
2365
+ }
2366
+ return found;
2327
2367
  });
2328
2368
  }
2329
2369
  async getAllModules(treePath) {
2330
- const moduleIds = this.host.readDirectory(this.cwd, ["ts", "js"], ["node_modules", ".*"], ["**/*.val.ts", "**/*.val.js"]).filter(file => {
2370
+ const moduleIds = (await this.getSerializedModules()).filter(({
2371
+ path
2372
+ }) => {
2331
2373
  if (treePath) {
2332
- return file.replace(this.cwd, "").startsWith(treePath);
2374
+ return path.startsWith(treePath);
2333
2375
  }
2334
2376
  return true;
2335
- }).map(file => file.replace(this.cwd, "").replace(".val.js", "").replace(".val.ts", "").split(path__namespace["default"].sep).join("/"));
2377
+ }).map(({
2378
+ path
2379
+ }) => path);
2336
2380
  return moduleIds;
2337
2381
  }
2338
2382
  async execCommit(patches) {
@@ -2423,30 +2467,72 @@ function encodeJwt(payload, sessionKey) {
2423
2467
 
2424
2468
  class ProxyValServer extends ValServer {
2425
2469
  moduleCache = null;
2426
- constructor(cwd, options, apiOptions, callbacks) {
2427
- super(cwd, options, callbacks);
2470
+ constructor(cwd, valModules, options, apiOptions, callbacks) {
2471
+ super(cwd, valModules, options, callbacks);
2428
2472
  this.cwd = cwd;
2473
+ this.valModules = valModules;
2429
2474
  this.options = options;
2430
2475
  this.apiOptions = apiOptions;
2431
2476
  this.callbacks = callbacks;
2432
2477
  this.moduleCache = null;
2433
2478
  }
2434
2479
 
2435
- /** Remote FS dependent methods: */
2480
+ // TODO: restructure this
2436
2481
 
2437
- async getModule(moduleId,
2438
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2439
- _options) {
2440
- if (this.moduleCache) {
2441
- return this.moduleCache[moduleId];
2442
- }
2443
- throw new Error("Module cache not initialized");
2482
+ getSerializedModules() {
2483
+ return Promise.all(this.valModules.modules.map(({
2484
+ def
2485
+ }, i) => {
2486
+ return def().then(({
2487
+ default: valModule
2488
+ }) => {
2489
+ var _Internal$getSchema;
2490
+ const path = core.Internal.getValPath(valModule);
2491
+ if (!path) {
2492
+ throw Error(`Module defined at pos: ${i} is missing path`);
2493
+ }
2494
+ const source = core.Internal.getSource(valModule);
2495
+ if (!source) {
2496
+ // TODO
2497
+ throw Error(`Module defined at pos: ${i} is missing source`);
2498
+ }
2499
+ const schema = (_Internal$getSchema = core.Internal.getSchema(valModule)) === null || _Internal$getSchema === void 0 ? void 0 : _Internal$getSchema.serialize();
2500
+ if (!schema) {
2501
+ // TODO
2502
+ throw Error(`Module defined at pos: ${i} is missing schema`);
2503
+ }
2504
+ return {
2505
+ path,
2506
+ source: source,
2507
+ errors: false,
2508
+ //valModule[GetSchema]?.validate(path, source),
2509
+ schema: schema
2510
+ };
2511
+ });
2512
+ }));
2513
+ }
2514
+ getModule(moduleId) {
2515
+ // TODO: do not get all modules - we only should only get the ones we need
2516
+ return this.getSerializedModules().then(all => {
2517
+ const found = all.find(valModule => valModule.path === moduleId);
2518
+ if (!found) {
2519
+ throw Error(`Module ${moduleId} not found`);
2520
+ }
2521
+ return found;
2522
+ });
2444
2523
  }
2445
2524
  async getAllModules(treePath) {
2446
- if (!this.moduleCache) {
2447
- throw new Error("Module cache not initialized");
2448
- }
2449
- return Object.keys(this.moduleCache).filter(moduleId => moduleId.startsWith(treePath));
2525
+ const moduleIds = (await this.getSerializedModules()).filter(({
2526
+ path
2527
+ }) => {
2528
+ if (treePath) {
2529
+ return path.startsWith(treePath);
2530
+ }
2531
+ return true;
2532
+ }).map(({
2533
+ path
2534
+ }) => path);
2535
+ return moduleIds;
2450
2536
  }
2451
2537
  execCommit(patches, cookies) {
2452
2538
  return withAuth(this.options.valSecret, cookies, "execCommit", async ({
@@ -2487,67 +2573,14 @@ class ProxyValServer extends ValServer {
2487
2573
  }
2488
2574
  });
2489
2575
  }
2490
- async init(commit, token) {
2491
- const params = createParams({
2492
- root: this.apiOptions.root,
2493
- commit,
2494
- ext: ["ts", "js", "json"],
2495
- package: ["@valbuild/core@" + this.options.versions.core, "@valbuild/next@" + this.options.versions.next],
2496
- include: ["**/*.val.{js,ts},package.json,tsconfig.json,jsconfig.json"]
2497
- });
2498
- const url = new URL(`/v1/eval/${this.options.remote}/heads/${this.options.git.branch}/~?${params}`, this.options.valContentUrl);
2499
- try {
2500
- const fetchRes = await fetch(url, {
2501
- headers: getAuthHeaders(token, "application/json")
2502
- });
2503
- if (fetchRes.status === 200) {
2504
- const json = await fetchRes.json();
2505
- let error = false;
2506
- if (typeof json !== "object") {
2507
- error = {
2508
- details: "Invalid response: not an object"
2509
- };
2510
- }
2511
- if (typeof json.git !== "object") {
2512
- error = {
2513
- details: "Invalid response: missing git"
2514
- };
2515
- }
2516
- if (typeof json.git.commit !== "string") {
2517
- error = {
2518
- details: "Invalid response: missing git.commit"
2519
- };
2520
- }
2521
- if (typeof json.modules !== "object" || json.modules === null) {
2522
- error = {
2523
- details: "Invalid response: missing modules"
2524
- };
2525
- }
2526
- if (error) {
2527
- console.error("Could not initialize remote modules", error);
2528
- return {
2529
- status: 500,
2530
- json: {
2531
- message: "Failed to fetch remote modules",
2532
- ...error
2533
- }
2534
- };
2535
- }
2536
- this.moduleCache = json.modules;
2537
- return {
2538
- status: 200
2539
- };
2540
- } else {
2541
- return createJsonError(fetchRes);
2542
- }
2543
- } catch (err) {
2544
- return {
2545
- status: 500,
2546
- json: {
2547
- message: "Failed to fetch: check network connection"
2548
- }
2549
- };
2550
- }
2576
+ async init(
2577
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2578
+ _commit,
2579
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2580
+ _token) {
2581
+ return {
2582
+ status: 200
2583
+ };
2551
2584
  }
2552
2585
  async ensureInitialized(errorMessageType, cookies) {
2553
2586
  const commit = this.options.git.commit;
@@ -3116,13 +3149,13 @@ function createParams(params) {
3116
3149
  return paramsString;
3117
3150
  }
3118
3151
 
3119
- async function createValServer(route, opts, callbacks) {
3152
+ async function createValServer(valModules, route, opts, callbacks) {
3120
3153
  const serverOpts = await initHandlerOptions(route, opts);
3121
3154
  if (serverOpts.mode === "proxy") {
3122
3155
  const projectRoot = process.cwd(); //[process.cwd(), opts.root || ""] .filter((seg) => seg) .join("/");
3123
- return new ProxyValServer(projectRoot, serverOpts, opts, callbacks);
3156
+ return new ProxyValServer(projectRoot, valModules, serverOpts, opts, callbacks);
3124
3157
  } else {
3125
- return new LocalValServer(serverOpts, callbacks);
3158
+ return new LocalValServer(valModules, serverOpts, callbacks);
3126
3159
  }
3127
3160
  }
3128
3161
  async function initHandlerOptions(route, opts) {
@@ -603,6 +603,10 @@ class TSOps {
603
603
  }
604
604
  }
605
605
 
606
+ function getSyntheticContainingPath(rootDir) {
607
+ return path__default.join(rootDir, "<val>"); // TODO: this is the synthetic path used when evaluating / patching modules. I am not sure <val> is the best choice: val.ts / js better? But that is weird too. At least now it is clear(er) that it is indeed a synthetic file (i.e. not an actual file)
608
+ }
609
+
606
610
  const ops$1 = new TSOps(document => {
607
611
  return pipe(analyzeValModule(document), result.map(({
608
612
  source
@@ -610,10 +614,10 @@ const ops$1 = new TSOps(document => {
610
614
  });
611
615
 
612
616
  // TODO: rename to patchValFiles since we may write multiple files
613
- const patchValFile = async (id, valConfigPath, patch, sourceFileHandler, runtime) => {
617
+ const patchValFile = async (id, rootDir, patch, sourceFileHandler, runtime) => {
614
618
  // const timeId = randomUUID();
615
619
  // console.time("patchValFile" + timeId);
616
- const filePath = sourceFileHandler.resolveSourceModulePath(valConfigPath, `.${id}.val`);
620
+ const filePath = sourceFileHandler.resolveSourceModulePath(getSyntheticContainingPath(rootDir), `.${id}.val`);
617
621
  const sourceFile = sourceFileHandler.getSourceFile(filePath);
618
622
  if (!sourceFile) {
619
623
  throw Error(`Source file ${filePath} not found`);
@@ -711,9 +715,7 @@ globalThis.valModule = {
711
715
  defaultExport: !!valModule?.default,
712
716
  };
713
717
  `;
714
- const result = context.evalCode(code,
715
- // Synthetic module name
716
- path__default.join(rootDirPath, "<val>"));
718
+ const result = context.evalCode(code, getSyntheticContainingPath(rootDirPath));
717
719
  const fatalErrors = [];
718
720
  if (result.error) {
719
721
  const error = result.error.consume(context.dump);
@@ -1382,8 +1384,9 @@ function getValidationErrorMetadata(validationError) {
1382
1384
 
1383
1385
  const ops = new JSONOps();
1384
1386
  class ValServer {
1385
- constructor(cwd, options, callbacks) {
1387
+ constructor(cwd, valModules, options, callbacks) {
1386
1388
  this.cwd = cwd;
1389
+ this.valModules = valModules;
1387
1390
  this.options = options;
1388
1391
  this.callbacks = callbacks;
1389
1392
  }
@@ -2020,8 +2023,9 @@ const textEncoder = new TextEncoder();
2020
2023
  class LocalValServer extends ValServer {
2021
2024
  static PATCHES_DIR = "patches";
2022
2025
  static FILES_DIR = "files";
2023
- constructor(options, callbacks) {
2024
- super(options.service.sourceFileHandler.projectRoot, options, callbacks);
2026
+ constructor(valModules, options, callbacks) {
2027
+ super(options.service.sourceFileHandler.projectRoot, valModules, options, callbacks);
2028
+ this.valModules = valModules;
2025
2029
  this.options = options;
2026
2030
  this.callbacks = callbacks;
2027
2031
  this.patchesRootPath = options.cacheDir || path__default.join(options.service.sourceFileHandler.projectRoot, ".val");
@@ -2290,19 +2294,59 @@ class LocalValServer extends ValServer {
2290
2294
  // No RemoteFS so nothing to ensure
2291
2295
  return result.ok(undefined);
2292
2296
  }
2293
- getModule(moduleId, options) {
2294
- return this.options.service.get(moduleId, "", {
2295
- ...options,
2296
- validate: false
2297
+ getSerializedModules() {
2298
+ return Promise.all(this.valModules.modules.map(({
2299
+ def
2300
+ }, i) => {
2301
+ return def().then(({
2302
+ default: valModule
2303
+ }) => {
2304
+ var _Internal$getSchema;
2305
+ const path = Internal.getValPath(valModule);
2306
+ if (!path) {
2307
+ throw Error(`Module defined at pos: ${i} is missing path`);
2308
+ }
2309
+ const source = Internal.getSource(valModule);
2310
+ if (!source) {
2311
+ // TODO
2312
+ throw Error(`Module defined at pos: ${i} is missing source`);
2313
+ }
2314
+ const schema = (_Internal$getSchema = Internal.getSchema(valModule)) === null || _Internal$getSchema === void 0 ? void 0 : _Internal$getSchema.serialize();
2315
+ if (!schema) {
2316
+ // TODO
2317
+ throw Error(`Module defined at pos: ${i} is missing schema`);
2318
+ }
2319
+ return {
2320
+ path,
2321
+ source: source,
2322
+ errors: false,
2323
+ //valModule[GetSchema]?.validate(path, source),
2324
+ schema: schema
2325
+ };
2326
+ });
2327
+ }));
2328
+ }
2329
+ getModule(moduleId) {
2330
+ // TODO: do not get all modules - we only should only get the ones we need
2331
+ return this.getSerializedModules().then(all => {
2332
+ const found = all.find(valModule => valModule.path === moduleId);
2333
+ if (!found) {
2334
+ throw Error(`Module ${moduleId} not found`);
2335
+ }
2336
+ return found;
2297
2337
  });
2298
2338
  }
2299
2339
  async getAllModules(treePath) {
2300
- const moduleIds = this.host.readDirectory(this.cwd, ["ts", "js"], ["node_modules", ".*"], ["**/*.val.ts", "**/*.val.js"]).filter(file => {
2340
+ const moduleIds = (await this.getSerializedModules()).filter(({
2341
+ path
2342
+ }) => {
2301
2343
  if (treePath) {
2302
- return file.replace(this.cwd, "").startsWith(treePath);
2344
+ return path.startsWith(treePath);
2303
2345
  }
2304
2346
  return true;
2305
- }).map(file => file.replace(this.cwd, "").replace(".val.js", "").replace(".val.ts", "").split(path__default.sep).join("/"));
2347
+ }).map(({
2348
+ path
2349
+ }) => path);
2306
2350
  return moduleIds;
2307
2351
  }
2308
2352
  async execCommit(patches) {
@@ -2393,30 +2437,72 @@ function encodeJwt(payload, sessionKey) {
2393
2437
 
2394
2438
  class ProxyValServer extends ValServer {
2395
2439
  moduleCache = null;
2396
- constructor(cwd, options, apiOptions, callbacks) {
2397
- super(cwd, options, callbacks);
2440
+ constructor(cwd, valModules, options, apiOptions, callbacks) {
2441
+ super(cwd, valModules, options, callbacks);
2398
2442
  this.cwd = cwd;
2443
+ this.valModules = valModules;
2399
2444
  this.options = options;
2400
2445
  this.apiOptions = apiOptions;
2401
2446
  this.callbacks = callbacks;
2402
2447
  this.moduleCache = null;
2403
2448
  }
2404
2449
 
2405
- /** Remote FS dependent methods: */
2450
+ // TODO: restructure this
2406
2451
 
2407
- async getModule(moduleId,
2408
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2409
- _options) {
2410
- if (this.moduleCache) {
2411
- return this.moduleCache[moduleId];
2412
- }
2413
- throw new Error("Module cache not initialized");
2452
+ getSerializedModules() {
2453
+ return Promise.all(this.valModules.modules.map(({
2454
+ def
2455
+ }, i) => {
2456
+ return def().then(({
2457
+ default: valModule
2458
+ }) => {
2459
+ var _Internal$getSchema;
2460
+ const path = Internal.getValPath(valModule);
2461
+ if (!path) {
2462
+ throw Error(`Module defined at pos: ${i} is missing path`);
2463
+ }
2464
+ const source = Internal.getSource(valModule);
2465
+ if (!source) {
2466
+ // TODO
2467
+ throw Error(`Module defined at pos: ${i} is missing source`);
2468
+ }
2469
+ const schema = (_Internal$getSchema = Internal.getSchema(valModule)) === null || _Internal$getSchema === void 0 ? void 0 : _Internal$getSchema.serialize();
2470
+ if (!schema) {
2471
+ // TODO
2472
+ throw Error(`Module defined at pos: ${i} is missing schema`);
2473
+ }
2474
+ return {
2475
+ path,
2476
+ source: source,
2477
+ errors: false,
2478
+ //valModule[GetSchema]?.validate(path, source),
2479
+ schema: schema
2480
+ };
2481
+ });
2482
+ }));
2483
+ }
2484
+ getModule(moduleId) {
2485
+ // TODO: do not get all modules - we only should only get the ones we need
2486
+ return this.getSerializedModules().then(all => {
2487
+ const found = all.find(valModule => valModule.path === moduleId);
2488
+ if (!found) {
2489
+ throw Error(`Module ${moduleId} not found`);
2490
+ }
2491
+ return found;
2492
+ });
2414
2493
  }
2415
2494
  async getAllModules(treePath) {
2416
- if (!this.moduleCache) {
2417
- throw new Error("Module cache not initialized");
2418
- }
2419
- return Object.keys(this.moduleCache).filter(moduleId => moduleId.startsWith(treePath));
2495
+ const moduleIds = (await this.getSerializedModules()).filter(({
2496
+ path
2497
+ }) => {
2498
+ if (treePath) {
2499
+ return path.startsWith(treePath);
2500
+ }
2501
+ return true;
2502
+ }).map(({
2503
+ path
2504
+ }) => path);
2505
+ return moduleIds;
2420
2506
  }
2421
2507
  execCommit(patches, cookies) {
2422
2508
  return withAuth(this.options.valSecret, cookies, "execCommit", async ({
@@ -2457,67 +2543,14 @@ class ProxyValServer extends ValServer {
2457
2543
  }
2458
2544
  });
2459
2545
  }
2460
- async init(commit, token) {
2461
- const params = createParams({
2462
- root: this.apiOptions.root,
2463
- commit,
2464
- ext: ["ts", "js", "json"],
2465
- package: ["@valbuild/core@" + this.options.versions.core, "@valbuild/next@" + this.options.versions.next],
2466
- include: ["**/*.val.{js,ts},package.json,tsconfig.json,jsconfig.json"]
2467
- });
2468
- const url = new URL(`/v1/eval/${this.options.remote}/heads/${this.options.git.branch}/~?${params}`, this.options.valContentUrl);
2469
- try {
2470
- const fetchRes = await fetch(url, {
2471
- headers: getAuthHeaders(token, "application/json")
2472
- });
2473
- if (fetchRes.status === 200) {
2474
- const json = await fetchRes.json();
2475
- let error = false;
2476
- if (typeof json !== "object") {
2477
- error = {
2478
- details: "Invalid response: not an object"
2479
- };
2480
- }
2481
- if (typeof json.git !== "object") {
2482
- error = {
2483
- details: "Invalid response: missing git"
2484
- };
2485
- }
2486
- if (typeof json.git.commit !== "string") {
2487
- error = {
2488
- details: "Invalid response: missing git.commit"
2489
- };
2490
- }
2491
- if (typeof json.modules !== "object" || json.modules === null) {
2492
- error = {
2493
- details: "Invalid response: missing modules"
2494
- };
2495
- }
2496
- if (error) {
2497
- console.error("Could not initialize remote modules", error);
2498
- return {
2499
- status: 500,
2500
- json: {
2501
- message: "Failed to fetch remote modules",
2502
- ...error
2503
- }
2504
- };
2505
- }
2506
- this.moduleCache = json.modules;
2507
- return {
2508
- status: 200
2509
- };
2510
- } else {
2511
- return createJsonError(fetchRes);
2512
- }
2513
- } catch (err) {
2514
- return {
2515
- status: 500,
2516
- json: {
2517
- message: "Failed to fetch: check network connection"
2518
- }
2519
- };
2520
- }
2546
+ async init(
2547
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2548
+ _commit,
2549
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2550
+ _token) {
2551
+ return {
2552
+ status: 200
2553
+ };
2521
2554
  }
2522
2555
  async ensureInitialized(errorMessageType, cookies) {
2523
2556
  const commit = this.options.git.commit;
@@ -3086,13 +3119,13 @@ function createParams(params) {
3086
3119
  return paramsString;
3087
3120
  }
3088
3121
 
3089
- async function createValServer(route, opts, callbacks) {
3122
+ async function createValServer(valModules, route, opts, callbacks) {
3090
3123
  const serverOpts = await initHandlerOptions(route, opts);
3091
3124
  if (serverOpts.mode === "proxy") {
3092
3125
  const projectRoot = process.cwd(); //[process.cwd(), opts.root || ""] .filter((seg) => seg) .join("/");
3093
- return new ProxyValServer(projectRoot, serverOpts, opts, callbacks);
3126
+ return new ProxyValServer(projectRoot, valModules, serverOpts, opts, callbacks);
3094
3127
  } else {
3095
- return new LocalValServer(serverOpts, callbacks);
3128
+ return new LocalValServer(valModules, serverOpts, callbacks);
3096
3129
  }
3097
3130
  }
3098
3131
  async function initHandlerOptions(route, opts) {
package/package.json CHANGED
@@ -12,7 +12,7 @@
12
12
  "./package.json": "./package.json"
13
13
  },
14
14
  "types": "dist/valbuild-server.cjs.d.ts",
15
- "version": "0.60.24",
15
+ "version": "0.61.0",
16
16
  "scripts": {
17
17
  "typecheck": "tsc --noEmit",
18
18
  "test": "jest",
@@ -24,9 +24,9 @@
24
24
  "concurrently": "^7.6.0"
25
25
  },
26
26
  "dependencies": {
27
- "@valbuild/core": "~0.60.24",
28
- "@valbuild/shared": "~0.60.24",
29
- "@valbuild/ui": "~0.60.24",
27
+ "@valbuild/core": "~0.61.0",
28
+ "@valbuild/shared": "~0.61.0",
29
+ "@valbuild/ui": "~0.61.0",
30
30
  "express": "^4.18.2",
31
31
  "image-size": "^1.0.2",
32
32
  "minimatch": "^3.0.4",