@eggjs/core
Advanced tools
| //#region src/loader/manifest.d.ts | ||
| interface ManifestInvalidation { | ||
| lockfileFingerprint: string; | ||
| configFingerprint: string; | ||
| serverEnv: string; | ||
| serverScope: string; | ||
| typescriptEnabled: boolean; | ||
| } | ||
| interface StartupManifest { | ||
| version: number; | ||
| generatedAt: string; | ||
| invalidation: ManifestInvalidation; | ||
| /** Plugin-specific manifest data, keyed by plugin name */ | ||
| extensions: Record<string, unknown>; | ||
| /** resolveModule cache: relative filepath -> resolved relative path | null */ | ||
| resolveCache: Record<string, string | null>; | ||
| /** relative directory path -> file relative paths */ | ||
| fileDiscovery: Record<string, string[]>; | ||
| } | ||
| declare class ManifestStore { | ||
| #private; | ||
| readonly data: StartupManifest; | ||
| readonly baseDir: string; | ||
| private constructor(); | ||
| /** | ||
| * Load and validate manifest from `.egg/manifest.json`. | ||
| * Returns null if manifest doesn't exist or is invalid. | ||
| */ | ||
| static load(baseDir: string, serverEnv: string, serverScope: string): ManifestStore | null; | ||
| /** | ||
| * Create a collector-only ManifestStore (no cached data). | ||
| * Used during normal startup to collect data for future manifest generation. | ||
| */ | ||
| static createCollector(baseDir: string): ManifestStore; | ||
| /** | ||
| * Resolve a module path. Checks cache first, falls back to resolver, collects result. | ||
| */ | ||
| resolveModule(filepath: string, fallback: () => string | undefined): string | undefined; | ||
| /** | ||
| * Get file list for a directory. Checks cache first, falls back to globber, collects result. | ||
| */ | ||
| globFiles(directory: string, fallback: () => string[]): string[]; | ||
| /** | ||
| * Look up a plugin extension by name. | ||
| */ | ||
| getExtension(name: string): unknown; | ||
| /** | ||
| * Register plugin extension data for manifest generation. | ||
| */ | ||
| setExtension(name: string, data: unknown): void; | ||
| /** | ||
| * Generate a StartupManifest from collected data. | ||
| */ | ||
| generateManifest(options: ManifestGenerateOptions): StartupManifest; | ||
| static write(baseDir: string, manifest: StartupManifest): Promise<void>; | ||
| static clean(baseDir: string): void; | ||
| } | ||
| interface ManifestGenerateOptions { | ||
| serverEnv: string; | ||
| serverScope: string; | ||
| typescriptEnabled: boolean; | ||
| } | ||
| //#endregion | ||
| export { ManifestGenerateOptions, ManifestInvalidation, ManifestStore, StartupManifest }; |
| import fs from "node:fs"; | ||
| import fsp from "node:fs/promises"; | ||
| import path from "node:path"; | ||
| import { debuglog } from "node:util"; | ||
| import { isSupportTypeScript } from "@eggjs/utils"; | ||
| import { createHash } from "node:crypto"; | ||
| //#region src/loader/manifest.ts | ||
| const debug = debuglog("egg/core/loader/manifest"); | ||
| const MANIFEST_VERSION = 1; | ||
| const LOCKFILE_NAMES = [ | ||
| "pnpm-lock.yaml", | ||
| "package-lock.json", | ||
| "yarn.lock" | ||
| ]; | ||
| var ManifestStore = class ManifestStore { | ||
| data; | ||
| baseDir; | ||
| #resolveCacheCollector = {}; | ||
| #fileDiscoveryCollector = {}; | ||
| #extensionCollector = {}; | ||
| constructor(data, baseDir) { | ||
| this.data = data; | ||
| this.baseDir = baseDir; | ||
| } | ||
| /** | ||
| * Load and validate manifest from `.egg/manifest.json`. | ||
| * Returns null if manifest doesn't exist or is invalid. | ||
| */ | ||
| static load(baseDir, serverEnv, serverScope) { | ||
| if (serverEnv === "local" && process.env.EGG_MANIFEST !== "true") { | ||
| debug("skip manifest in local env (set EGG_MANIFEST=true to enable)"); | ||
| return null; | ||
| } | ||
| const manifestPath = path.join(baseDir, ".egg", "manifest.json"); | ||
| let raw; | ||
| try { | ||
| raw = fs.readFileSync(manifestPath, "utf-8"); | ||
| } catch { | ||
| debug("manifest not found at %s", manifestPath); | ||
| return null; | ||
| } | ||
| let data; | ||
| try { | ||
| data = JSON.parse(raw); | ||
| } catch (e) { | ||
| debug("failed to parse manifest: %s", e); | ||
| return null; | ||
| } | ||
| if (!ManifestStore.#validate(data, baseDir, serverEnv, serverScope)) return null; | ||
| debug("manifest loaded successfully"); | ||
| return new ManifestStore(data, baseDir); | ||
| } | ||
| /** | ||
| * Create a collector-only ManifestStore (no cached data). | ||
| * Used during normal startup to collect data for future manifest generation. | ||
| */ | ||
| static createCollector(baseDir) { | ||
| return new ManifestStore({ | ||
| version: MANIFEST_VERSION, | ||
| generatedAt: "", | ||
| invalidation: { | ||
| lockfileFingerprint: "", | ||
| configFingerprint: "", | ||
| serverEnv: "", | ||
| serverScope: "", | ||
| typescriptEnabled: false | ||
| }, | ||
| extensions: {}, | ||
| resolveCache: {}, | ||
| fileDiscovery: {} | ||
| }, baseDir); | ||
| } | ||
| static #validate(data, baseDir, serverEnv, serverScope) { | ||
| if (data.version !== MANIFEST_VERSION) { | ||
| debug("manifest version mismatch: expected %d, got %d", MANIFEST_VERSION, data.version); | ||
| return false; | ||
| } | ||
| const inv = data.invalidation; | ||
| if (!inv) { | ||
| debug("manifest missing invalidation data"); | ||
| return false; | ||
| } | ||
| if (inv.serverEnv !== serverEnv) { | ||
| debug("manifest serverEnv mismatch: expected %s, got %s", serverEnv, inv.serverEnv); | ||
| return false; | ||
| } | ||
| if (inv.serverScope !== serverScope) { | ||
| debug("manifest serverScope mismatch: expected %s, got %s", serverScope, inv.serverScope); | ||
| return false; | ||
| } | ||
| const currentTypescriptEnabled = isSupportTypeScript(); | ||
| if (inv.typescriptEnabled !== currentTypescriptEnabled) { | ||
| debug("manifest typescriptEnabled mismatch: expected %s, got %s", currentTypescriptEnabled, inv.typescriptEnabled); | ||
| return false; | ||
| } | ||
| const currentLockfileFingerprint = ManifestStore.#lockfileFingerprint(baseDir); | ||
| if (inv.lockfileFingerprint !== currentLockfileFingerprint) { | ||
| debug("manifest lockfileFingerprint mismatch"); | ||
| return false; | ||
| } | ||
| const currentConfigFingerprint = ManifestStore.#directoryFingerprint(path.join(baseDir, "config")); | ||
| if (inv.configFingerprint !== currentConfigFingerprint) { | ||
| debug("manifest configFingerprint mismatch"); | ||
| return false; | ||
| } | ||
| return true; | ||
| } | ||
| /** | ||
| * Resolve a module path. Checks cache first, falls back to resolver, collects result. | ||
| */ | ||
| resolveModule(filepath, fallback) { | ||
| const relKey = this.#toRelative(filepath); | ||
| const cache = this.data.resolveCache; | ||
| if (cache && relKey in cache) { | ||
| const cached = cache[relKey]; | ||
| debug("[resolveModule:manifest] %o => %o", filepath, cached); | ||
| return cached !== null ? this.#toAbsolute(cached) : void 0; | ||
| } | ||
| const result = fallback(); | ||
| this.#resolveCacheCollector[relKey] = result !== void 0 ? this.#toRelative(result) : null; | ||
| return result; | ||
| } | ||
| /** | ||
| * Get file list for a directory. Checks cache first, falls back to globber, collects result. | ||
| */ | ||
| globFiles(directory, fallback) { | ||
| const relKey = this.#toRelative(directory); | ||
| const cache = this.data.fileDiscovery; | ||
| if (cache && relKey in cache) { | ||
| const cached = cache[relKey]; | ||
| debug("[globFiles:manifest] using cached files for %o, count: %d", directory, cached.length); | ||
| return cached; | ||
| } | ||
| const result = fallback(); | ||
| this.#fileDiscoveryCollector[relKey] = result; | ||
| return result; | ||
| } | ||
| /** | ||
| * Look up a plugin extension by name. | ||
| */ | ||
| getExtension(name) { | ||
| return this.data.extensions?.[name]; | ||
| } | ||
| /** | ||
| * Register plugin extension data for manifest generation. | ||
| */ | ||
| setExtension(name, data) { | ||
| this.#extensionCollector[name] = data; | ||
| } | ||
| /** | ||
| * Generate a StartupManifest from collected data. | ||
| */ | ||
| generateManifest(options) { | ||
| return { | ||
| version: MANIFEST_VERSION, | ||
| generatedAt: (/* @__PURE__ */ new Date()).toISOString(), | ||
| invalidation: { | ||
| lockfileFingerprint: ManifestStore.#lockfileFingerprint(this.baseDir), | ||
| configFingerprint: ManifestStore.#directoryFingerprint(path.join(this.baseDir, "config")), | ||
| serverEnv: options.serverEnv, | ||
| serverScope: options.serverScope, | ||
| typescriptEnabled: options.typescriptEnabled | ||
| }, | ||
| extensions: this.#extensionCollector, | ||
| resolveCache: this.#resolveCacheCollector, | ||
| fileDiscovery: this.#fileDiscoveryCollector | ||
| }; | ||
| } | ||
| static async write(baseDir, manifest) { | ||
| const dir = path.join(baseDir, ".egg"); | ||
| await fsp.mkdir(dir, { recursive: true }); | ||
| const manifestPath = path.join(dir, "manifest.json"); | ||
| await fsp.writeFile(manifestPath, JSON.stringify(manifest, null, 2)); | ||
| debug("manifest written to %s", manifestPath); | ||
| } | ||
| static clean(baseDir) { | ||
| const manifestPath = path.join(baseDir, ".egg", "manifest.json"); | ||
| try { | ||
| fs.unlinkSync(manifestPath); | ||
| debug("manifest removed: %s", manifestPath); | ||
| } catch (err) { | ||
| if (err.code !== "ENOENT") throw err; | ||
| } | ||
| } | ||
| #toRelative(absPath) { | ||
| return (path.isAbsolute(absPath) ? path.relative(this.baseDir, absPath) : absPath).replaceAll(path.sep, "/"); | ||
| } | ||
| #toAbsolute(relPath) { | ||
| if (path.isAbsolute(relPath)) return relPath; | ||
| return path.join(this.baseDir, relPath); | ||
| } | ||
| static #statFingerprint(filepath) { | ||
| try { | ||
| const stat$1 = fs.statSync(filepath); | ||
| return `${stat$1.mtimeMs}:${stat$1.size}`; | ||
| } catch { | ||
| return null; | ||
| } | ||
| } | ||
| static #lockfileFingerprint(baseDir) { | ||
| for (const name of LOCKFILE_NAMES) { | ||
| const fp = ManifestStore.#statFingerprint(path.join(baseDir, name)); | ||
| if (fp) return `${name}:${fp}`; | ||
| } | ||
| return ""; | ||
| } | ||
| static #directoryFingerprint(dirpath) { | ||
| const hash = createHash("md5"); | ||
| const visited = /* @__PURE__ */ new Set(); | ||
| ManifestStore.#fingerprintRecursive(dirpath, hash, visited); | ||
| return hash.digest("hex"); | ||
| } | ||
| static #fingerprintRecursive(dirpath, hash, visited) { | ||
| let realPath; | ||
| try { | ||
| realPath = fs.realpathSync(dirpath); | ||
| } catch { | ||
| return; | ||
| } | ||
| if (visited.has(realPath)) return; | ||
| visited.add(realPath); | ||
| let entries; | ||
| try { | ||
| entries = fs.readdirSync(dirpath, { withFileTypes: true }); | ||
| } catch { | ||
| return; | ||
| } | ||
| entries.sort((a, b) => a.name.localeCompare(b.name)); | ||
| for (const entry of entries) { | ||
| if (entry.isSymbolicLink()) continue; | ||
| const fullPath = path.join(dirpath, entry.name); | ||
| if (entry.isDirectory()) { | ||
| hash.update(`dir:${entry.name}\n`); | ||
| ManifestStore.#fingerprintRecursive(fullPath, hash, visited); | ||
| } else if (entry.isFile()) { | ||
| const fp = ManifestStore.#statFingerprint(fullPath); | ||
| hash.update(`file:${entry.name}:${fp ?? "missing"}\n`); | ||
| } | ||
| } | ||
| } | ||
| }; | ||
| //#endregion | ||
| export { ManifestStore }; |
+2
-0
@@ -21,2 +21,4 @@ import { Fun } from "./utils/index.js"; | ||
| env?: string; | ||
| /** Skip lifecycle hooks, only trigger loadMetadata for manifest generation */ | ||
| metadataOnly?: boolean; | ||
| } | ||
@@ -23,0 +25,0 @@ type EggCoreInitOptions = Partial<EggCoreOptions>; |
+2
-1
@@ -133,3 +133,4 @@ import utils_default from "./utils/index.js"; | ||
| env: options.env ?? "", | ||
| EggCoreClass: EggCore | ||
| EggCoreClass: EggCore, | ||
| metadataOnly: options.metadataOnly | ||
| }); | ||
@@ -136,0 +137,0 @@ } |
+2
-1
@@ -6,2 +6,3 @@ import { utils } from "./utils/index.js"; | ||
| import { CustomLoaderConfigItem, EggAppConfig, EggAppInfo, EggPluginInfo } from "./types.js"; | ||
| import { ManifestGenerateOptions, ManifestInvalidation, ManifestStore, StartupManifest } from "./loader/manifest.js"; | ||
| import { CaseStyle, CaseStyleFunction, EXPORTS, FULLPATH, FileLoader, FileLoaderFilter, FileLoaderInitializer, FileLoaderOptions, FileLoaderParseItem } from "./loader/file_loader.js"; | ||
@@ -13,2 +14,2 @@ import { ClassLoader, ClassLoaderOptions, ContextLoader, ContextLoaderOptions } from "./loader/context_loader.js"; | ||
| import { SequencifyResult, SequencifyTask, sequencify } from "./utils/sequencify.js"; | ||
| export { BaseContextClass, BootImplClass, CaseStyle, CaseStyleFunction, ClassLoader, ClassLoaderOptions, Context, ContextLoader, ContextLoaderOptions, CustomLoaderConfigItem, EGG_LOADER, EXPORTS, EggAppConfig, EggAppInfo, EggCore, EggCoreInitOptions, EggCoreOptions, EggDirInfo, EggDirInfoType, EggLoader, EggLoaderOptions, EggPluginInfo, FULLPATH, FileLoader, FileLoaderFilter, FileLoaderInitializer, FileLoaderOptions, FileLoaderParseItem, FunWithFullPath, ILifecycleBoot, KoaApplication, KoaContext, KoaMiddlewareFunc, KoaRequest, KoaResponse, Lifecycle, LifecycleOptions, MiddlewareFunc, Next, Request, Response, Router, SequencifyResult, SequencifyTask, Singleton, SingletonCreateMethod, SingletonOptions, Timing, TimingItem, sequencify, utils }; | ||
| export { BaseContextClass, BootImplClass, CaseStyle, CaseStyleFunction, ClassLoader, ClassLoaderOptions, Context, ContextLoader, ContextLoaderOptions, CustomLoaderConfigItem, EGG_LOADER, EXPORTS, EggAppConfig, EggAppInfo, EggCore, EggCoreInitOptions, EggCoreOptions, EggDirInfo, EggDirInfoType, EggLoader, EggLoaderOptions, EggPluginInfo, FULLPATH, FileLoader, FileLoaderFilter, FileLoaderInitializer, FileLoaderOptions, FileLoaderParseItem, FunWithFullPath, ILifecycleBoot, KoaApplication, KoaContext, KoaMiddlewareFunc, KoaRequest, KoaResponse, Lifecycle, LifecycleOptions, ManifestGenerateOptions, ManifestInvalidation, ManifestStore, MiddlewareFunc, Next, Request, Response, Router, SequencifyResult, SequencifyTask, Singleton, SingletonCreateMethod, SingletonOptions, StartupManifest, Timing, TimingItem, sequencify, utils }; |
+2
-1
@@ -8,2 +8,3 @@ import utils_default from "./utils/index.js"; | ||
| import { ClassLoader, ContextLoader } from "./loader/context_loader.js"; | ||
| import { ManifestStore } from "./loader/manifest.js"; | ||
| import { EggLoader } from "./loader/egg_loader.js"; | ||
@@ -13,2 +14,2 @@ import { Singleton } from "./singleton.js"; | ||
| export { BaseContextClass, CaseStyle, ClassLoader, Context, ContextLoader, EGG_LOADER, EXPORTS, EggCore, EggLoader, FULLPATH, FileLoader, KoaApplication, KoaContext, KoaRequest, KoaResponse, Lifecycle, Request, Response, Router, Singleton, Timing, sequencify, utils_default as utils }; | ||
| export { BaseContextClass, CaseStyle, ClassLoader, Context, ContextLoader, EGG_LOADER, EXPORTS, EggCore, EggLoader, FULLPATH, FileLoader, KoaApplication, KoaContext, KoaRequest, KoaResponse, Lifecycle, ManifestStore, Request, Response, Router, Singleton, Timing, sequencify, utils_default as utils }; |
@@ -43,2 +43,8 @@ import { Fun } from "./utils/index.js"; | ||
| beforeClose?(): Promise<void>; | ||
| /** | ||
| * Collect metadata for manifest generation (metadataOnly mode). | ||
| * Called instead of configWillLoad/configDidLoad/didLoad/willReady | ||
| * when the application is started with metadataOnly: true. | ||
| */ | ||
| loadMetadata?(): Promise<void> | void; | ||
| } | ||
@@ -82,4 +88,5 @@ type BootImplClass<T = ILifecycleBoot> = new (...args: any[]) => T; | ||
| triggerServerDidReady(): Promise<void>; | ||
| triggerLoadMetadata(): Promise<void>; | ||
| } | ||
| //#endregion | ||
| export { BootImplClass, FunWithFullPath, ILifecycleBoot, Lifecycle, LifecycleOptions }; |
+21
-1
@@ -18,2 +18,3 @@ import utils_default from "./utils/index.js"; | ||
| #isClosed; | ||
| #metadataOnly; | ||
| #closeFunctionSet; | ||
@@ -33,2 +34,3 @@ loadReady; | ||
| this.#isClosed = false; | ||
| this.#metadataOnly = false; | ||
| this.#init = false; | ||
@@ -46,3 +48,3 @@ this.timing.start(`${this.options.app.type} Start`); | ||
| this.ready((err) => { | ||
| this.triggerDidReady(err); | ||
| if (!this.#metadataOnly) this.triggerDidReady(err); | ||
| debug("app ready"); | ||
@@ -227,2 +229,20 @@ this.timing.end(`${this.options.app.type} Start`); | ||
| } | ||
| async triggerLoadMetadata() { | ||
| this.#metadataOnly = true; | ||
| debug("trigger loadMetadata start"); | ||
| let firstError; | ||
| for (const boot of this.#boots) if (typeof boot.loadMetadata === "function") { | ||
| debug("trigger loadMetadata at %o", boot.fullPath); | ||
| try { | ||
| await boot.loadMetadata(); | ||
| } catch (err) { | ||
| const error = err instanceof Error ? err : new Error(String(err)); | ||
| if (!firstError) firstError = error; | ||
| debug("trigger loadMetadata error at %o, error: %s", boot.fullPath, error); | ||
| this.emit("error", error); | ||
| } | ||
| } | ||
| debug("trigger loadMetadata end"); | ||
| this.ready(firstError ?? true); | ||
| } | ||
| #initReady() { | ||
@@ -229,0 +249,0 @@ debug("loadReady init"); |
| import { Timing } from "../utils/timing.js"; | ||
| import { Lifecycle } from "../lifecycle.js"; | ||
| import { EggAppConfig, EggAppInfo, EggPluginInfo } from "../types.js"; | ||
| import { ManifestStore, StartupManifest } from "./manifest.js"; | ||
| import { FileLoader, FileLoaderOptions } from "./file_loader.js"; | ||
@@ -24,2 +25,4 @@ import { ContextLoader, ContextLoaderOptions } from "./context_loader.js"; | ||
| plugins?: Record<string, EggPluginInfo>; | ||
| /** Skip lifecycle hooks, only trigger loadMetadata for manifest generation */ | ||
| metadataOnly?: boolean; | ||
| } | ||
@@ -42,2 +45,4 @@ type EggDirInfoType = "app" | "plugin" | "framework"; | ||
| dirs?: EggDirInfo[]; | ||
| /** Startup manifest — loaded from cache or collecting for generation */ | ||
| readonly manifest: ManifestStore; | ||
| /** | ||
@@ -374,4 +379,9 @@ * @class | ||
| resolveModule(filepath: string): string | undefined; | ||
| /** | ||
| * Generate startup manifest from collected data. | ||
| * Should be called after all loading phases complete. | ||
| */ | ||
| generateManifest(): StartupManifest; | ||
| } | ||
| //#endregion | ||
| export { EggDirInfo, EggDirInfoType, EggLoader, EggLoaderOptions }; |
@@ -6,2 +6,3 @@ import utils_default from "../utils/index.js"; | ||
| import { ContextLoader } from "./context_loader.js"; | ||
| import { ManifestStore } from "./manifest.js"; | ||
| import fs from "node:fs"; | ||
@@ -40,2 +41,4 @@ import path from "node:path"; | ||
| dirs; | ||
| /** Startup manifest — loaded from cache or collecting for generation */ | ||
| manifest; | ||
| /** | ||
@@ -109,2 +112,3 @@ * @class | ||
| this.appInfo = this.getAppInfo(); | ||
| this.manifest = ManifestStore.load(this.options.baseDir, this.serverEnv, this.serverScope) ?? ManifestStore.createCollector(this.options.baseDir); | ||
| } | ||
@@ -747,3 +751,4 @@ get app() { | ||
| await this.#loadBootHook("app"); | ||
| this.lifecycle.triggerConfigWillLoad(); | ||
| if (this.options.metadataOnly) await this.lifecycle.triggerLoadMetadata(); | ||
| else this.lifecycle.triggerConfigWillLoad(); | ||
| } | ||
@@ -755,3 +760,4 @@ /** | ||
| await this.#loadBootHook("agent"); | ||
| this.lifecycle.triggerConfigWillLoad(); | ||
| if (this.options.metadataOnly) await this.lifecycle.triggerLoadMetadata(); | ||
| else this.lifecycle.triggerConfigWillLoad(); | ||
| } | ||
@@ -1049,3 +1055,4 @@ loadBootHook() {} | ||
| target, | ||
| inject: this.app | ||
| inject: this.app, | ||
| manifest: this.manifest | ||
| }; | ||
@@ -1069,3 +1076,4 @@ const timingKey = `Load "${String(property)}" to Application`; | ||
| property, | ||
| inject: this.app | ||
| inject: this.app, | ||
| manifest: this.manifest | ||
| }; | ||
@@ -1100,2 +1108,5 @@ const timingKey = `Load "${String(property)}" to Context`; | ||
| resolveModule(filepath) { | ||
| return this.manifest.resolveModule(filepath, () => this.#doResolveModule(filepath)); | ||
| } | ||
| #doResolveModule(filepath) { | ||
| let fullPath; | ||
@@ -1135,2 +1146,13 @@ try { | ||
| } | ||
| /** | ||
| * Generate startup manifest from collected data. | ||
| * Should be called after all loading phases complete. | ||
| */ | ||
| generateManifest() { | ||
| return this.manifest.generateManifest({ | ||
| serverEnv: this.serverEnv, | ||
| serverScope: this.serverScope, | ||
| typescriptEnabled: isSupportTypeScript() | ||
| }); | ||
| } | ||
| }; | ||
@@ -1137,0 +1159,0 @@ function depCompatible(plugin) { |
| import { Fun } from "../utils/index.js"; | ||
| import { ManifestStore } from "./manifest.js"; | ||
@@ -40,2 +41,4 @@ //#region src/loader/file_loader.d.ts | ||
| lowercaseFirst?: boolean; | ||
| /** Startup manifest for caching globby scans and collecting results */ | ||
| manifest?: ManifestStore; | ||
| } | ||
@@ -42,0 +45,0 @@ interface FileLoaderParseItem { |
@@ -130,4 +130,5 @@ import utils_default from "../utils/index.js"; | ||
| for (const directory of directories) { | ||
| const filepaths = globby.sync(files, { cwd: directory }); | ||
| debug("[parse] globby files: %o, cwd: %o => %o", files, directory, filepaths); | ||
| const manifest = this.options.manifest; | ||
| const filepaths = manifest ? manifest.globFiles(directory, () => globby.sync(files, { cwd: directory })) : globby.sync(files, { cwd: directory }); | ||
| debug("[parse] files: %o, cwd: %o => %o", files, directory, filepaths); | ||
| for (const filepath of filepaths) { | ||
@@ -134,0 +135,0 @@ const fullpath = path.join(directory, filepath); |
+9
-9
| { | ||
| "name": "@eggjs/core", | ||
| "version": "7.0.2-beta.6", | ||
| "version": "7.0.2-beta.7", | ||
| "description": "A core plugin framework based on @eggjs/koa", | ||
@@ -44,7 +44,7 @@ "keywords": [ | ||
| "utility": "^2.5.0", | ||
| "@eggjs/extend2": "5.0.2-beta.6", | ||
| "@eggjs/router": "4.0.2-beta.6", | ||
| "@eggjs/utils": "5.0.2-beta.6", | ||
| "@eggjs/koa": "3.1.2-beta.6", | ||
| "@eggjs/path-matching": "3.0.2-beta.6" | ||
| "@eggjs/extend2": "5.0.2-beta.7", | ||
| "@eggjs/koa": "3.1.2-beta.7", | ||
| "@eggjs/path-matching": "3.0.2-beta.7", | ||
| "@eggjs/router": "4.0.2-beta.7", | ||
| "@eggjs/utils": "5.0.2-beta.7" | ||
| }, | ||
@@ -61,5 +61,5 @@ "devDependencies": { | ||
| "urllib": "^4.8.2", | ||
| "@eggjs/tsconfig": "3.1.2-beta.6", | ||
| "@eggjs/mock": "7.0.2-beta.6", | ||
| "@eggjs/supertest": "9.0.2-beta.6" | ||
| "@eggjs/mock": "7.0.2-beta.7", | ||
| "@eggjs/tsconfig": "3.1.2-beta.7", | ||
| "@eggjs/supertest": "9.0.2-beta.7" | ||
| }, | ||
@@ -66,0 +66,0 @@ "engines": { |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
145189
9.68%28
7.69%3952
10.42%15
7.14%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated
Updated
Updated