Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .claude/memory/feedback_no_chrome_devtools.md +11 -0
- .gitattributes +7 -0
- backend/node_modules/.prisma/client/libquery_engine-darwin-arm64.dylib.node +3 -0
- backend/node_modules/.prisma/client/query_engine_bg.wasm +3 -0
- backend/node_modules/@prisma/engines/libquery_engine-darwin-arm64.dylib.node +3 -0
- backend/node_modules/@prisma/engines/schema-engine-darwin-arm64 +3 -0
- backend/node_modules/c12/dist/index.d.mts +157 -0
- backend/node_modules/c12/dist/index.mjs +112 -0
- backend/node_modules/c12/dist/shared/c12.BXpNC6YI.mjs +401 -0
- backend/node_modules/c12/dist/update.d.mts +53 -0
- backend/node_modules/c12/dist/update.mjs +74 -0
- backend/node_modules/chokidar/esm/handler.d.ts +90 -0
- backend/node_modules/chokidar/esm/handler.js +629 -0
- backend/node_modules/chokidar/esm/index.d.ts +215 -0
- backend/node_modules/chokidar/esm/index.js +798 -0
- backend/node_modules/chokidar/esm/package.json +1 -0
- backend/node_modules/dotenv/lib/cli-options.js +17 -0
- backend/node_modules/dotenv/lib/env-options.js +28 -0
- backend/node_modules/dotenv/lib/main.d.ts +162 -0
- backend/node_modules/dotenv/lib/main.js +386 -0
- backend/node_modules/effect/src/internal/layer/circular.ts +214 -0
- backend/node_modules/effect/src/internal/metric/label.ts +41 -0
- backend/node_modules/effect/src/internal/metric/pair.ts +48 -0
- backend/node_modules/effect/src/internal/metric/polling.ts +149 -0
- backend/node_modules/effect/src/internal/metric/state.ts +290 -0
- backend/node_modules/effect/src/internal/opCodes/channelUpstreamPullStrategy.ts +11 -0
- backend/node_modules/effect/src/internal/schema/util.ts +50 -0
- backend/node_modules/effect/src/internal/supervisor/patch.ts +190 -0
- backend/node_modules/perfect-debounce/dist/index.cjs +59 -0
- backend/node_modules/perfect-debounce/dist/index.d.ts +34 -0
- backend/node_modules/perfect-debounce/dist/index.mjs +57 -0
- backend/node_modules/prisma/build/child.js +0 -0
- backend/node_modules/prisma/build/prisma_schema_build_bg.wasm +3 -0
- backend/node_modules/prisma/build/public/assets/alert.60ea9f84.svg +5 -0
- backend/node_modules/prisma/build/public/assets/array.1a36c222.svg +4 -0
- backend/node_modules/prisma/build/public/assets/boolean.9188b434.svg +4 -0
- backend/node_modules/prisma/build/public/assets/chevron-down.24f76e3c.svg +3 -0
- backend/node_modules/prisma/build/public/assets/cross.c2610cf5.svg +11 -0
- backend/node_modules/prisma/build/public/assets/datetime.a3bf710a.svg +4 -0
- backend/node_modules/prisma/build/public/assets/download.8d34b65a.svg +4 -0
- backend/node_modules/prisma/build/public/assets/ellipsis.a8c5a34a.svg +10 -0
- backend/node_modules/prisma/build/public/assets/enum.7ec0b64c.svg +6 -0
- backend/node_modules/prisma/build/public/assets/folder.d77b8eaf.svg +6 -0
- backend/node_modules/prisma/build/public/assets/hamburger.5fdadeac.svg +4 -0
- backend/node_modules/prisma/build/public/assets/index.js +0 -0
- backend/node_modules/prisma/build/public/assets/inter-all-400-normal.4c1f8a0d.woff +3 -0
- backend/node_modules/prisma/build/public/assets/inter-all-600-normal.d0a7c8a9.woff +3 -0
- backend/node_modules/prisma/build/public/assets/inter-cyrillic-400-normal.ac97a49e.woff2 +0 -0
- backend/node_modules/prisma/build/public/assets/inter-cyrillic-600-normal.2c917f10.woff2 +0 -0
- backend/node_modules/prisma/build/public/assets/inter-cyrillic-ext-400-normal.f21a6a97.woff2 +0 -0
.claude/memory/feedback_no_chrome_devtools.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: No usar Chrome DevTools para verificar UI
|
| 3 |
+
description: El usuario prefiere verificar los cambios de UI él mismo, sin que Claude use Chrome DevTools
|
| 4 |
+
type: feedback
|
| 5 |
+
---
|
| 6 |
+
|
| 7 |
+
No usar Chrome DevTools MCP para tomar screenshots o interactuar con el navegador después de hacer cambios de UI. El usuario prefiere revisar los cambios visualmente por su cuenta.
|
| 8 |
+
|
| 9 |
+
**Why:** El usuario lo indicó explícitamente cuando se usaban las herramientas de Chrome para verificar cambios CSS/JS.
|
| 10 |
+
|
| 11 |
+
**How to apply:** Después de hacer cambios de CSS o JS en la UI, describir los cambios realizados y dejar que el usuario los verifique en el navegador.
|
.gitattributes
CHANGED
|
@@ -33,3 +33,10 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
backend/node_modules/prisma/libquery_engine-darwin-arm64.dylib.node filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
backend/node_modules/@prisma/engines/libquery_engine-darwin-arm64.dylib.node filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
backend/node_modules/@prisma/engines/schema-engine-darwin-arm64 filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
backend/node_modules/.prisma/client/libquery_engine-darwin-arm64.dylib.node filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
backend/node_modules/prisma/build/public/icon-1024.png filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
backend/node_modules/prisma/build/public/assets/inter-all-400-normal.4c1f8a0d.woff filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
backend/node_modules/prisma/build/public/assets/inter-all-600-normal.d0a7c8a9.woff filter=lfs diff=lfs merge=lfs -text
|
backend/node_modules/.prisma/client/libquery_engine-darwin-arm64.dylib.node
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:afb9cb5a12ea42caa6f6498e40e9cb75059cae17098aadcc1001c99bb262e1ee
|
| 3 |
+
size 19356128
|
backend/node_modules/.prisma/client/query_engine_bg.wasm
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:7ec8cd57e69e5e061c71accb0ae4ea5a258b074e51da112c6d871d398e259eba
|
| 3 |
+
size 2171299
|
backend/node_modules/@prisma/engines/libquery_engine-darwin-arm64.dylib.node
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:afb9cb5a12ea42caa6f6498e40e9cb75059cae17098aadcc1001c99bb262e1ee
|
| 3 |
+
size 19356128
|
backend/node_modules/@prisma/engines/schema-engine-darwin-arm64
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:caa2cf90d5b2cfe6cc06e47974f7e3275dd395b4d35cf140d5d4b2362c3b5bb1
|
| 3 |
+
size 21686160
|
backend/node_modules/c12/dist/index.d.mts
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { Jiti, JitiOptions } from 'jiti';
|
| 2 |
+
import { DownloadTemplateOptions } from 'giget';
|
| 3 |
+
import { ChokidarOptions } from 'chokidar';
|
| 4 |
+
import { diff } from 'ohash/utils';
|
| 5 |
+
|
| 6 |
+
interface DotenvOptions {
|
| 7 |
+
/**
|
| 8 |
+
* The project root directory (either absolute or relative to the current working directory).
|
| 9 |
+
*/
|
| 10 |
+
cwd: string;
|
| 11 |
+
/**
|
| 12 |
+
* What file to look in for environment variables (either absolute or relative
|
| 13 |
+
* to the current working directory). For example, `.env`.
|
| 14 |
+
*/
|
| 15 |
+
fileName?: string;
|
| 16 |
+
/**
|
| 17 |
+
* Whether to interpolate variables within .env.
|
| 18 |
+
*
|
| 19 |
+
* @example
|
| 20 |
+
* ```env
|
| 21 |
+
* BASE_DIR="/test"
|
| 22 |
+
* # resolves to "/test/further"
|
| 23 |
+
* ANOTHER_DIR="${BASE_DIR}/further"
|
| 24 |
+
* ```
|
| 25 |
+
*/
|
| 26 |
+
interpolate?: boolean;
|
| 27 |
+
/**
|
| 28 |
+
* An object describing environment variables (key, value pairs).
|
| 29 |
+
*/
|
| 30 |
+
env?: NodeJS.ProcessEnv;
|
| 31 |
+
}
|
| 32 |
+
type Env = typeof process.env;
|
| 33 |
+
/**
|
| 34 |
+
* Load and interpolate environment variables into `process.env`.
|
| 35 |
+
* If you need more control (or access to the values), consider using `loadDotenv` instead
|
| 36 |
+
*
|
| 37 |
+
*/
|
| 38 |
+
declare function setupDotenv(options: DotenvOptions): Promise<Env>;
|
| 39 |
+
/** Load environment variables into an object. */
|
| 40 |
+
declare function loadDotenv(options: DotenvOptions): Promise<Env>;
|
| 41 |
+
declare global {
|
| 42 |
+
var __c12_dotenv_vars__: Map<Record<string, any>, Set<string>>;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
interface ConfigLayerMeta {
|
| 46 |
+
name?: string;
|
| 47 |
+
[key: string]: any;
|
| 48 |
+
}
|
| 49 |
+
type UserInputConfig = Record<string, any>;
|
| 50 |
+
interface C12InputConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> {
|
| 51 |
+
$test?: T;
|
| 52 |
+
$development?: T;
|
| 53 |
+
$production?: T;
|
| 54 |
+
$env?: Record<string, T>;
|
| 55 |
+
$meta?: MT;
|
| 56 |
+
}
|
| 57 |
+
type InputConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> = C12InputConfig<T, MT> & T;
|
| 58 |
+
interface SourceOptions<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> {
|
| 59 |
+
/** Custom meta for layer */
|
| 60 |
+
meta?: MT;
|
| 61 |
+
/** Layer config overrides */
|
| 62 |
+
overrides?: T;
|
| 63 |
+
[key: string]: any;
|
| 64 |
+
/**
|
| 65 |
+
* Options for cloning remote sources
|
| 66 |
+
*
|
| 67 |
+
* @see https://giget.unjs.io
|
| 68 |
+
*/
|
| 69 |
+
giget?: DownloadTemplateOptions;
|
| 70 |
+
/**
|
| 71 |
+
* Install dependencies after cloning
|
| 72 |
+
*
|
| 73 |
+
* @see https://nypm.unjs.io
|
| 74 |
+
*/
|
| 75 |
+
install?: boolean;
|
| 76 |
+
/**
|
| 77 |
+
* Token for cloning private sources
|
| 78 |
+
*
|
| 79 |
+
* @see https://giget.unjs.io#providing-token-for-private-repositories
|
| 80 |
+
*/
|
| 81 |
+
auth?: string;
|
| 82 |
+
}
|
| 83 |
+
interface ConfigLayer<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> {
|
| 84 |
+
config: T | null;
|
| 85 |
+
source?: string;
|
| 86 |
+
sourceOptions?: SourceOptions<T, MT>;
|
| 87 |
+
meta?: MT;
|
| 88 |
+
cwd?: string;
|
| 89 |
+
configFile?: string;
|
| 90 |
+
}
|
| 91 |
+
interface ResolvedConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> extends ConfigLayer<T, MT> {
|
| 92 |
+
config: T;
|
| 93 |
+
layers?: ConfigLayer<T, MT>[];
|
| 94 |
+
cwd?: string;
|
| 95 |
+
}
|
| 96 |
+
type ConfigSource = "overrides" | "main" | "rc" | "packageJson" | "defaultConfig";
|
| 97 |
+
interface ResolvableConfigContext<T extends UserInputConfig = UserInputConfig> {
|
| 98 |
+
configs: Record<ConfigSource, T | null | undefined>;
|
| 99 |
+
rawConfigs: Record<ConfigSource, ResolvableConfig<T> | null | undefined>;
|
| 100 |
+
}
|
| 101 |
+
type MaybePromise<T> = T | Promise<T>;
|
| 102 |
+
type ResolvableConfig<T extends UserInputConfig = UserInputConfig> = MaybePromise<T | null | undefined> | ((ctx: ResolvableConfigContext<T>) => MaybePromise<T | null | undefined>);
|
| 103 |
+
interface LoadConfigOptions<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> {
|
| 104 |
+
name?: string;
|
| 105 |
+
cwd?: string;
|
| 106 |
+
configFile?: string;
|
| 107 |
+
rcFile?: false | string;
|
| 108 |
+
globalRc?: boolean;
|
| 109 |
+
dotenv?: boolean | DotenvOptions;
|
| 110 |
+
envName?: string | false;
|
| 111 |
+
packageJson?: boolean | string | string[];
|
| 112 |
+
defaults?: T;
|
| 113 |
+
defaultConfig?: ResolvableConfig<T>;
|
| 114 |
+
overrides?: ResolvableConfig<T>;
|
| 115 |
+
omit$Keys?: boolean;
|
| 116 |
+
resolve?: (id: string, options: LoadConfigOptions<T, MT>) => null | undefined | ResolvedConfig<T, MT> | Promise<ResolvedConfig<T, MT> | undefined | null>;
|
| 117 |
+
jiti?: Jiti;
|
| 118 |
+
jitiOptions?: JitiOptions;
|
| 119 |
+
giget?: false | DownloadTemplateOptions;
|
| 120 |
+
merger?: (...sources: Array<T | null | undefined>) => T;
|
| 121 |
+
extend?: false | {
|
| 122 |
+
extendKey?: string | string[];
|
| 123 |
+
};
|
| 124 |
+
}
|
| 125 |
+
type DefineConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> = (input: InputConfig<T, MT>) => InputConfig<T, MT>;
|
| 126 |
+
declare function createDefineConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta>(): DefineConfig<T, MT>;
|
| 127 |
+
|
| 128 |
+
declare const SUPPORTED_EXTENSIONS: string[];
|
| 129 |
+
declare function loadConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta>(options: LoadConfigOptions<T, MT>): Promise<ResolvedConfig<T, MT>>;
|
| 130 |
+
|
| 131 |
+
type DiffEntries = ReturnType<typeof diff>;
|
| 132 |
+
type ConfigWatcher<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> = ResolvedConfig<T, MT> & {
|
| 133 |
+
watchingFiles: string[];
|
| 134 |
+
unwatch: () => Promise<void>;
|
| 135 |
+
};
|
| 136 |
+
interface WatchConfigOptions<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> extends LoadConfigOptions<T, MT> {
|
| 137 |
+
chokidarOptions?: ChokidarOptions;
|
| 138 |
+
debounce?: false | number;
|
| 139 |
+
onWatch?: (event: {
|
| 140 |
+
type: "created" | "updated" | "removed";
|
| 141 |
+
path: string;
|
| 142 |
+
}) => void | Promise<void>;
|
| 143 |
+
acceptHMR?: (context: {
|
| 144 |
+
getDiff: () => DiffEntries;
|
| 145 |
+
newConfig: ResolvedConfig<T, MT>;
|
| 146 |
+
oldConfig: ResolvedConfig<T, MT>;
|
| 147 |
+
}) => void | boolean | Promise<void | boolean>;
|
| 148 |
+
onUpdate?: (context: {
|
| 149 |
+
getDiff: () => ReturnType<typeof diff>;
|
| 150 |
+
newConfig: ResolvedConfig<T, MT>;
|
| 151 |
+
oldConfig: ResolvedConfig<T, MT>;
|
| 152 |
+
}) => void | Promise<void>;
|
| 153 |
+
}
|
| 154 |
+
declare function watchConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta>(options: WatchConfigOptions<T, MT>): Promise<ConfigWatcher<T, MT>>;
|
| 155 |
+
|
| 156 |
+
export { SUPPORTED_EXTENSIONS, createDefineConfig, loadConfig, loadDotenv, setupDotenv, watchConfig };
|
| 157 |
+
export type { C12InputConfig, ConfigLayer, ConfigLayerMeta, ConfigSource, ConfigWatcher, DefineConfig, DotenvOptions, Env, InputConfig, LoadConfigOptions, ResolvableConfig, ResolvableConfigContext, ResolvedConfig, SourceOptions, UserInputConfig, WatchConfigOptions };
|
backend/node_modules/c12/dist/index.mjs
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { l as loadConfig, S as SUPPORTED_EXTENSIONS } from './shared/c12.BXpNC6YI.mjs';
|
| 2 |
+
export { a as loadDotenv, s as setupDotenv } from './shared/c12.BXpNC6YI.mjs';
|
| 3 |
+
import { debounce } from 'perfect-debounce';
|
| 4 |
+
import { resolve } from 'pathe';
|
| 5 |
+
import 'node:fs';
|
| 6 |
+
import 'node:fs/promises';
|
| 7 |
+
import 'node:url';
|
| 8 |
+
import 'node:os';
|
| 9 |
+
import 'exsolve';
|
| 10 |
+
import 'jiti';
|
| 11 |
+
import 'rc9';
|
| 12 |
+
import 'defu';
|
| 13 |
+
import 'pkg-types';
|
| 14 |
+
import 'dotenv';
|
| 15 |
+
|
| 16 |
+
function createDefineConfig() {
|
| 17 |
+
return (input) => input;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
const eventMap = {
|
| 21 |
+
add: "created",
|
| 22 |
+
change: "updated",
|
| 23 |
+
unlink: "removed"
|
| 24 |
+
};
|
| 25 |
+
async function watchConfig(options) {
|
| 26 |
+
let config = await loadConfig(options);
|
| 27 |
+
const configName = options.name || "config";
|
| 28 |
+
const configFileName = options.configFile ?? (options.name === "config" ? "config" : `${options.name}.config`);
|
| 29 |
+
const watchingFiles = [
|
| 30 |
+
...new Set(
|
| 31 |
+
(config.layers || []).filter((l) => l.cwd).flatMap((l) => [
|
| 32 |
+
...SUPPORTED_EXTENSIONS.flatMap((ext) => [
|
| 33 |
+
resolve(l.cwd, configFileName + ext),
|
| 34 |
+
resolve(l.cwd, ".config", configFileName + ext),
|
| 35 |
+
resolve(
|
| 36 |
+
l.cwd,
|
| 37 |
+
".config",
|
| 38 |
+
configFileName.replace(/\.config$/, "") + ext
|
| 39 |
+
)
|
| 40 |
+
]),
|
| 41 |
+
l.source && resolve(l.cwd, l.source),
|
| 42 |
+
// TODO: Support watching rc from home and workspace
|
| 43 |
+
options.rcFile && resolve(
|
| 44 |
+
l.cwd,
|
| 45 |
+
typeof options.rcFile === "string" ? options.rcFile : `.${configName}rc`
|
| 46 |
+
),
|
| 47 |
+
options.packageJson && resolve(l.cwd, "package.json")
|
| 48 |
+
]).filter(Boolean)
|
| 49 |
+
)
|
| 50 |
+
];
|
| 51 |
+
const watch = await import('chokidar').then((r) => r.watch || r.default || r);
|
| 52 |
+
const { diff } = await import('ohash/utils');
|
| 53 |
+
const _fswatcher = watch(watchingFiles, {
|
| 54 |
+
ignoreInitial: true,
|
| 55 |
+
...options.chokidarOptions
|
| 56 |
+
});
|
| 57 |
+
const onChange = async (event, path) => {
|
| 58 |
+
const type = eventMap[event];
|
| 59 |
+
if (!type) {
|
| 60 |
+
return;
|
| 61 |
+
}
|
| 62 |
+
if (options.onWatch) {
|
| 63 |
+
await options.onWatch({
|
| 64 |
+
type,
|
| 65 |
+
path
|
| 66 |
+
});
|
| 67 |
+
}
|
| 68 |
+
const oldConfig = config;
|
| 69 |
+
try {
|
| 70 |
+
config = await loadConfig(options);
|
| 71 |
+
} catch (error) {
|
| 72 |
+
console.warn(`Failed to load config ${path}
|
| 73 |
+
${error}`);
|
| 74 |
+
return;
|
| 75 |
+
}
|
| 76 |
+
const changeCtx = {
|
| 77 |
+
newConfig: config,
|
| 78 |
+
oldConfig,
|
| 79 |
+
getDiff: () => diff(oldConfig.config, config.config)
|
| 80 |
+
};
|
| 81 |
+
if (options.acceptHMR) {
|
| 82 |
+
const changeHandled = await options.acceptHMR(changeCtx);
|
| 83 |
+
if (changeHandled) {
|
| 84 |
+
return;
|
| 85 |
+
}
|
| 86 |
+
}
|
| 87 |
+
if (options.onUpdate) {
|
| 88 |
+
await options.onUpdate(changeCtx);
|
| 89 |
+
}
|
| 90 |
+
};
|
| 91 |
+
if (options.debounce === false) {
|
| 92 |
+
_fswatcher.on("all", onChange);
|
| 93 |
+
} else {
|
| 94 |
+
_fswatcher.on("all", debounce(onChange, options.debounce ?? 100));
|
| 95 |
+
}
|
| 96 |
+
const utils = {
|
| 97 |
+
watchingFiles,
|
| 98 |
+
unwatch: async () => {
|
| 99 |
+
await _fswatcher.close();
|
| 100 |
+
}
|
| 101 |
+
};
|
| 102 |
+
return new Proxy(utils, {
|
| 103 |
+
get(_, prop) {
|
| 104 |
+
if (prop in utils) {
|
| 105 |
+
return utils[prop];
|
| 106 |
+
}
|
| 107 |
+
return config[prop];
|
| 108 |
+
}
|
| 109 |
+
});
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
export { SUPPORTED_EXTENSIONS, createDefineConfig, loadConfig, watchConfig };
|
backend/node_modules/c12/dist/shared/c12.BXpNC6YI.mjs
ADDED
|
@@ -0,0 +1,401 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { statSync, promises, existsSync } from 'node:fs';
|
| 2 |
+
import { rm, readFile } from 'node:fs/promises';
|
| 3 |
+
import { pathToFileURL } from 'node:url';
|
| 4 |
+
import { homedir } from 'node:os';
|
| 5 |
+
import { resolve, join, dirname, basename, extname, normalize } from 'pathe';
|
| 6 |
+
import { resolveModulePath } from 'exsolve';
|
| 7 |
+
import { createJiti } from 'jiti';
|
| 8 |
+
import * as rc9 from 'rc9';
|
| 9 |
+
import { defu } from 'defu';
|
| 10 |
+
import { findWorkspaceDir, readPackageJSON } from 'pkg-types';
|
| 11 |
+
import * as dotenv from 'dotenv';
|
| 12 |
+
|
| 13 |
+
async function setupDotenv(options) {
|
| 14 |
+
const targetEnvironment = options.env ?? process.env;
|
| 15 |
+
const environment = await loadDotenv({
|
| 16 |
+
cwd: options.cwd,
|
| 17 |
+
fileName: options.fileName ?? ".env",
|
| 18 |
+
env: targetEnvironment,
|
| 19 |
+
interpolate: options.interpolate ?? true
|
| 20 |
+
});
|
| 21 |
+
const dotenvVars = getDotEnvVars(targetEnvironment);
|
| 22 |
+
for (const key in environment) {
|
| 23 |
+
if (key.startsWith("_")) {
|
| 24 |
+
continue;
|
| 25 |
+
}
|
| 26 |
+
if (targetEnvironment[key] === void 0 || dotenvVars.has(key)) {
|
| 27 |
+
targetEnvironment[key] = environment[key];
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
return environment;
|
| 31 |
+
}
|
| 32 |
+
async function loadDotenv(options) {
|
| 33 |
+
const environment = /* @__PURE__ */ Object.create(null);
|
| 34 |
+
const dotenvFile = resolve(options.cwd, options.fileName);
|
| 35 |
+
const dotenvVars = getDotEnvVars(options.env || {});
|
| 36 |
+
Object.assign(environment, options.env);
|
| 37 |
+
if (statSync(dotenvFile, { throwIfNoEntry: false })?.isFile()) {
|
| 38 |
+
const parsed = dotenv.parse(await promises.readFile(dotenvFile, "utf8"));
|
| 39 |
+
for (const key in parsed) {
|
| 40 |
+
if (key in environment && !dotenvVars.has(key)) {
|
| 41 |
+
continue;
|
| 42 |
+
}
|
| 43 |
+
environment[key] = parsed[key];
|
| 44 |
+
dotenvVars.add(key);
|
| 45 |
+
}
|
| 46 |
+
}
|
| 47 |
+
if (options.interpolate) {
|
| 48 |
+
interpolate(environment);
|
| 49 |
+
}
|
| 50 |
+
return environment;
|
| 51 |
+
}
|
| 52 |
+
function interpolate(target, source = {}, parse = (v) => v) {
|
| 53 |
+
function getValue(key) {
|
| 54 |
+
return source[key] === void 0 ? target[key] : source[key];
|
| 55 |
+
}
|
| 56 |
+
function interpolate2(value, parents = []) {
|
| 57 |
+
if (typeof value !== "string") {
|
| 58 |
+
return value;
|
| 59 |
+
}
|
| 60 |
+
const matches = value.match(/(.?\${?(?:[\w:]+)?}?)/g) || [];
|
| 61 |
+
return parse(
|
| 62 |
+
// eslint-disable-next-line unicorn/no-array-reduce
|
| 63 |
+
matches.reduce((newValue, match) => {
|
| 64 |
+
const parts = /(.?)\${?([\w:]+)?}?/g.exec(match) || [];
|
| 65 |
+
const prefix = parts[1];
|
| 66 |
+
let value2, replacePart;
|
| 67 |
+
if (prefix === "\\") {
|
| 68 |
+
replacePart = parts[0] || "";
|
| 69 |
+
value2 = replacePart.replace(String.raw`\$`, "$");
|
| 70 |
+
} else {
|
| 71 |
+
const key = parts[2];
|
| 72 |
+
replacePart = (parts[0] || "").slice(prefix.length);
|
| 73 |
+
if (parents.includes(key)) {
|
| 74 |
+
console.warn(
|
| 75 |
+
`Please avoid recursive environment variables ( loop: ${parents.join(
|
| 76 |
+
" > "
|
| 77 |
+
)} > ${key} )`
|
| 78 |
+
);
|
| 79 |
+
return "";
|
| 80 |
+
}
|
| 81 |
+
value2 = getValue(key);
|
| 82 |
+
value2 = interpolate2(value2, [...parents, key]);
|
| 83 |
+
}
|
| 84 |
+
return value2 === void 0 ? newValue : newValue.replace(replacePart, value2);
|
| 85 |
+
}, value)
|
| 86 |
+
);
|
| 87 |
+
}
|
| 88 |
+
for (const key in target) {
|
| 89 |
+
target[key] = interpolate2(getValue(key));
|
| 90 |
+
}
|
| 91 |
+
}
|
| 92 |
+
function getDotEnvVars(targetEnvironment) {
|
| 93 |
+
const globalRegistry = globalThis.__c12_dotenv_vars__ ||= /* @__PURE__ */ new Map();
|
| 94 |
+
if (!globalRegistry.has(targetEnvironment)) {
|
| 95 |
+
globalRegistry.set(targetEnvironment, /* @__PURE__ */ new Set());
|
| 96 |
+
}
|
| 97 |
+
return globalRegistry.get(targetEnvironment);
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
const _normalize = (p) => p?.replace(/\\/g, "/");
|
| 101 |
+
const ASYNC_LOADERS = {
|
| 102 |
+
".yaml": () => import('confbox/yaml').then((r) => r.parseYAML),
|
| 103 |
+
".yml": () => import('confbox/yaml').then((r) => r.parseYAML),
|
| 104 |
+
".jsonc": () => import('confbox/jsonc').then((r) => r.parseJSONC),
|
| 105 |
+
".json5": () => import('confbox/json5').then((r) => r.parseJSON5),
|
| 106 |
+
".toml": () => import('confbox/toml').then((r) => r.parseTOML)
|
| 107 |
+
};
|
| 108 |
+
const SUPPORTED_EXTENSIONS = Object.freeze([
|
| 109 |
+
// with jiti
|
| 110 |
+
".js",
|
| 111 |
+
".ts",
|
| 112 |
+
".mjs",
|
| 113 |
+
".cjs",
|
| 114 |
+
".mts",
|
| 115 |
+
".cts",
|
| 116 |
+
".json",
|
| 117 |
+
// with confbox
|
| 118 |
+
".jsonc",
|
| 119 |
+
".json5",
|
| 120 |
+
".yaml",
|
| 121 |
+
".yml",
|
| 122 |
+
".toml"
|
| 123 |
+
]);
|
| 124 |
+
async function loadConfig(options) {
|
| 125 |
+
options.cwd = resolve(process.cwd(), options.cwd || ".");
|
| 126 |
+
options.name = options.name || "config";
|
| 127 |
+
options.envName = options.envName ?? process.env.NODE_ENV;
|
| 128 |
+
options.configFile = options.configFile ?? (options.name === "config" ? "config" : `${options.name}.config`);
|
| 129 |
+
options.rcFile = options.rcFile ?? `.${options.name}rc`;
|
| 130 |
+
if (options.extend !== false) {
|
| 131 |
+
options.extend = {
|
| 132 |
+
extendKey: "extends",
|
| 133 |
+
...options.extend
|
| 134 |
+
};
|
| 135 |
+
}
|
| 136 |
+
const _merger = options.merger || defu;
|
| 137 |
+
options.jiti = options.jiti || createJiti(join(options.cwd, options.configFile), {
|
| 138 |
+
interopDefault: true,
|
| 139 |
+
moduleCache: false,
|
| 140 |
+
extensions: [...SUPPORTED_EXTENSIONS],
|
| 141 |
+
...options.jitiOptions
|
| 142 |
+
});
|
| 143 |
+
const r = {
|
| 144 |
+
config: {},
|
| 145 |
+
cwd: options.cwd,
|
| 146 |
+
configFile: resolve(options.cwd, options.configFile),
|
| 147 |
+
layers: []
|
| 148 |
+
};
|
| 149 |
+
const rawConfigs = {
|
| 150 |
+
overrides: options.overrides,
|
| 151 |
+
main: void 0,
|
| 152 |
+
rc: void 0,
|
| 153 |
+
packageJson: void 0,
|
| 154 |
+
defaultConfig: options.defaultConfig
|
| 155 |
+
};
|
| 156 |
+
if (options.dotenv) {
|
| 157 |
+
await setupDotenv({
|
| 158 |
+
cwd: options.cwd,
|
| 159 |
+
...options.dotenv === true ? {} : options.dotenv
|
| 160 |
+
});
|
| 161 |
+
}
|
| 162 |
+
const _mainConfig = await resolveConfig(".", options);
|
| 163 |
+
if (_mainConfig.configFile) {
|
| 164 |
+
rawConfigs.main = _mainConfig.config;
|
| 165 |
+
r.configFile = _mainConfig.configFile;
|
| 166 |
+
}
|
| 167 |
+
if (_mainConfig.meta) {
|
| 168 |
+
r.meta = _mainConfig.meta;
|
| 169 |
+
}
|
| 170 |
+
if (options.rcFile) {
|
| 171 |
+
const rcSources = [];
|
| 172 |
+
rcSources.push(rc9.read({ name: options.rcFile, dir: options.cwd }));
|
| 173 |
+
if (options.globalRc) {
|
| 174 |
+
const workspaceDir = await findWorkspaceDir(options.cwd).catch(() => {
|
| 175 |
+
});
|
| 176 |
+
if (workspaceDir) {
|
| 177 |
+
rcSources.push(rc9.read({ name: options.rcFile, dir: workspaceDir }));
|
| 178 |
+
}
|
| 179 |
+
rcSources.push(rc9.readUser({ name: options.rcFile, dir: options.cwd }));
|
| 180 |
+
}
|
| 181 |
+
rawConfigs.rc = _merger({}, ...rcSources);
|
| 182 |
+
}
|
| 183 |
+
if (options.packageJson) {
|
| 184 |
+
const keys = (Array.isArray(options.packageJson) ? options.packageJson : [
|
| 185 |
+
typeof options.packageJson === "string" ? options.packageJson : options.name
|
| 186 |
+
]).filter((t) => t && typeof t === "string");
|
| 187 |
+
const pkgJsonFile = await readPackageJSON(options.cwd).catch(() => {
|
| 188 |
+
});
|
| 189 |
+
const values = keys.map((key) => pkgJsonFile?.[key]);
|
| 190 |
+
rawConfigs.packageJson = _merger({}, ...values);
|
| 191 |
+
}
|
| 192 |
+
const configs = {};
|
| 193 |
+
for (const key in rawConfigs) {
|
| 194 |
+
const value = rawConfigs[key];
|
| 195 |
+
configs[key] = await (typeof value === "function" ? value({ configs, rawConfigs }) : value);
|
| 196 |
+
}
|
| 197 |
+
r.config = _merger(
|
| 198 |
+
configs.overrides,
|
| 199 |
+
configs.main,
|
| 200 |
+
configs.rc,
|
| 201 |
+
configs.packageJson,
|
| 202 |
+
configs.defaultConfig
|
| 203 |
+
);
|
| 204 |
+
if (options.extend) {
|
| 205 |
+
await extendConfig(r.config, options);
|
| 206 |
+
r.layers = r.config._layers;
|
| 207 |
+
delete r.config._layers;
|
| 208 |
+
r.config = _merger(r.config, ...r.layers.map((e) => e.config));
|
| 209 |
+
}
|
| 210 |
+
const baseLayers = [
|
| 211 |
+
configs.overrides && {
|
| 212 |
+
config: configs.overrides,
|
| 213 |
+
configFile: void 0,
|
| 214 |
+
cwd: void 0
|
| 215 |
+
},
|
| 216 |
+
{ config: configs.main, configFile: options.configFile, cwd: options.cwd },
|
| 217 |
+
configs.rc && { config: configs.rc, configFile: options.rcFile },
|
| 218 |
+
configs.packageJson && {
|
| 219 |
+
config: configs.packageJson,
|
| 220 |
+
configFile: "package.json"
|
| 221 |
+
}
|
| 222 |
+
].filter((l) => l && l.config);
|
| 223 |
+
r.layers = [...baseLayers, ...r.layers];
|
| 224 |
+
if (options.defaults) {
|
| 225 |
+
r.config = _merger(r.config, options.defaults);
|
| 226 |
+
}
|
| 227 |
+
if (options.omit$Keys) {
|
| 228 |
+
for (const key in r.config) {
|
| 229 |
+
if (key.startsWith("$")) {
|
| 230 |
+
delete r.config[key];
|
| 231 |
+
}
|
| 232 |
+
}
|
| 233 |
+
}
|
| 234 |
+
return r;
|
| 235 |
+
}
|
| 236 |
+
async function extendConfig(config, options) {
|
| 237 |
+
config._layers = config._layers || [];
|
| 238 |
+
if (!options.extend) {
|
| 239 |
+
return;
|
| 240 |
+
}
|
| 241 |
+
let keys = options.extend.extendKey;
|
| 242 |
+
if (typeof keys === "string") {
|
| 243 |
+
keys = [keys];
|
| 244 |
+
}
|
| 245 |
+
const extendSources = [];
|
| 246 |
+
for (const key of keys) {
|
| 247 |
+
extendSources.push(
|
| 248 |
+
...(Array.isArray(config[key]) ? config[key] : [config[key]]).filter(
|
| 249 |
+
Boolean
|
| 250 |
+
)
|
| 251 |
+
);
|
| 252 |
+
delete config[key];
|
| 253 |
+
}
|
| 254 |
+
for (let extendSource of extendSources) {
|
| 255 |
+
const originalExtendSource = extendSource;
|
| 256 |
+
let sourceOptions = {};
|
| 257 |
+
if (extendSource.source) {
|
| 258 |
+
sourceOptions = extendSource.options || {};
|
| 259 |
+
extendSource = extendSource.source;
|
| 260 |
+
}
|
| 261 |
+
if (Array.isArray(extendSource)) {
|
| 262 |
+
sourceOptions = extendSource[1] || {};
|
| 263 |
+
extendSource = extendSource[0];
|
| 264 |
+
}
|
| 265 |
+
if (typeof extendSource !== "string") {
|
| 266 |
+
console.warn(
|
| 267 |
+
`Cannot extend config from \`${JSON.stringify(
|
| 268 |
+
originalExtendSource
|
| 269 |
+
)}\` in ${options.cwd}`
|
| 270 |
+
);
|
| 271 |
+
continue;
|
| 272 |
+
}
|
| 273 |
+
const _config = await resolveConfig(extendSource, options, sourceOptions);
|
| 274 |
+
if (!_config.config) {
|
| 275 |
+
console.warn(
|
| 276 |
+
`Cannot extend config from \`${extendSource}\` in ${options.cwd}`
|
| 277 |
+
);
|
| 278 |
+
continue;
|
| 279 |
+
}
|
| 280 |
+
await extendConfig(_config.config, { ...options, cwd: _config.cwd });
|
| 281 |
+
config._layers.push(_config);
|
| 282 |
+
if (_config.config._layers) {
|
| 283 |
+
config._layers.push(..._config.config._layers);
|
| 284 |
+
delete _config.config._layers;
|
| 285 |
+
}
|
| 286 |
+
}
|
| 287 |
+
}
|
| 288 |
+
const GIGET_PREFIXES = [
|
| 289 |
+
"gh:",
|
| 290 |
+
"github:",
|
| 291 |
+
"gitlab:",
|
| 292 |
+
"bitbucket:",
|
| 293 |
+
"https://",
|
| 294 |
+
"http://"
|
| 295 |
+
];
|
| 296 |
+
const NPM_PACKAGE_RE = /^(@[\da-z~-][\d._a-z~-]*\/)?[\da-z~-][\d._a-z~-]*($|\/.*)/;
|
| 297 |
+
async function resolveConfig(source, options, sourceOptions = {}) {
|
| 298 |
+
if (options.resolve) {
|
| 299 |
+
const res2 = await options.resolve(source, options);
|
| 300 |
+
if (res2) {
|
| 301 |
+
return res2;
|
| 302 |
+
}
|
| 303 |
+
}
|
| 304 |
+
const _merger = options.merger || defu;
|
| 305 |
+
const customProviderKeys = Object.keys(
|
| 306 |
+
sourceOptions.giget?.providers || {}
|
| 307 |
+
).map((key) => `${key}:`);
|
| 308 |
+
const gigetPrefixes = customProviderKeys.length > 0 ? [.../* @__PURE__ */ new Set([...customProviderKeys, ...GIGET_PREFIXES])] : GIGET_PREFIXES;
|
| 309 |
+
if (options.giget !== false && gigetPrefixes.some((prefix) => source.startsWith(prefix))) {
|
| 310 |
+
const { downloadTemplate } = await import('giget');
|
| 311 |
+
const { digest } = await import('ohash');
|
| 312 |
+
const cloneName = source.replace(/\W+/g, "_").split("_").splice(0, 3).join("_") + "_" + digest(source).slice(0, 10).replace(/[-_]/g, "");
|
| 313 |
+
let cloneDir;
|
| 314 |
+
const localNodeModules = resolve(options.cwd, "node_modules");
|
| 315 |
+
const parentDir = dirname(options.cwd);
|
| 316 |
+
if (basename(parentDir) === ".c12") {
|
| 317 |
+
cloneDir = join(parentDir, cloneName);
|
| 318 |
+
} else if (existsSync(localNodeModules)) {
|
| 319 |
+
cloneDir = join(localNodeModules, ".c12", cloneName);
|
| 320 |
+
} else {
|
| 321 |
+
cloneDir = process.env.XDG_CACHE_HOME ? resolve(process.env.XDG_CACHE_HOME, "c12", cloneName) : resolve(homedir(), ".cache/c12", cloneName);
|
| 322 |
+
}
|
| 323 |
+
if (existsSync(cloneDir) && !sourceOptions.install) {
|
| 324 |
+
await rm(cloneDir, { recursive: true });
|
| 325 |
+
}
|
| 326 |
+
const cloned = await downloadTemplate(source, {
|
| 327 |
+
dir: cloneDir,
|
| 328 |
+
install: sourceOptions.install,
|
| 329 |
+
force: sourceOptions.install,
|
| 330 |
+
auth: sourceOptions.auth,
|
| 331 |
+
...options.giget,
|
| 332 |
+
...sourceOptions.giget
|
| 333 |
+
});
|
| 334 |
+
source = cloned.dir;
|
| 335 |
+
}
|
| 336 |
+
if (NPM_PACKAGE_RE.test(source)) {
|
| 337 |
+
source = tryResolve(source, options) || source;
|
| 338 |
+
}
|
| 339 |
+
const ext = extname(source);
|
| 340 |
+
const isDir = !ext || ext === basename(source);
|
| 341 |
+
const cwd = resolve(options.cwd, isDir ? source : dirname(source));
|
| 342 |
+
if (isDir) {
|
| 343 |
+
source = options.configFile;
|
| 344 |
+
}
|
| 345 |
+
const res = {
|
| 346 |
+
config: void 0,
|
| 347 |
+
configFile: void 0,
|
| 348 |
+
cwd,
|
| 349 |
+
source,
|
| 350 |
+
sourceOptions
|
| 351 |
+
};
|
| 352 |
+
res.configFile = tryResolve(resolve(cwd, source), options) || tryResolve(
|
| 353 |
+
resolve(cwd, ".config", source.replace(/\.config$/, "")),
|
| 354 |
+
options
|
| 355 |
+
) || tryResolve(resolve(cwd, ".config", source), options) || source;
|
| 356 |
+
if (!existsSync(res.configFile)) {
|
| 357 |
+
return res;
|
| 358 |
+
}
|
| 359 |
+
const configFileExt = extname(res.configFile) || "";
|
| 360 |
+
if (configFileExt in ASYNC_LOADERS) {
|
| 361 |
+
const asyncLoader = await ASYNC_LOADERS[configFileExt]();
|
| 362 |
+
const contents = await readFile(res.configFile, "utf8");
|
| 363 |
+
res.config = asyncLoader(contents);
|
| 364 |
+
} else {
|
| 365 |
+
res.config = await options.jiti.import(res.configFile, {
|
| 366 |
+
default: true
|
| 367 |
+
});
|
| 368 |
+
}
|
| 369 |
+
if (typeof res.config === "function") {
|
| 370 |
+
res.config = await res.config();
|
| 371 |
+
}
|
| 372 |
+
if (options.envName) {
|
| 373 |
+
const envConfig = {
|
| 374 |
+
...res.config["$" + options.envName],
|
| 375 |
+
...res.config.$env?.[options.envName]
|
| 376 |
+
};
|
| 377 |
+
if (Object.keys(envConfig).length > 0) {
|
| 378 |
+
res.config = _merger(envConfig, res.config);
|
| 379 |
+
}
|
| 380 |
+
}
|
| 381 |
+
res.meta = defu(res.sourceOptions.meta, res.config.$meta);
|
| 382 |
+
delete res.config.$meta;
|
| 383 |
+
if (res.sourceOptions.overrides) {
|
| 384 |
+
res.config = _merger(res.sourceOptions.overrides, res.config);
|
| 385 |
+
}
|
| 386 |
+
res.configFile = _normalize(res.configFile);
|
| 387 |
+
res.source = _normalize(res.source);
|
| 388 |
+
return res;
|
| 389 |
+
}
|
| 390 |
+
function tryResolve(id, options) {
|
| 391 |
+
const res = resolveModulePath(id, {
|
| 392 |
+
try: true,
|
| 393 |
+
from: pathToFileURL(join(options.cwd || ".", options.configFile || "/")),
|
| 394 |
+
suffixes: ["", "/index"],
|
| 395 |
+
extensions: SUPPORTED_EXTENSIONS,
|
| 396 |
+
cache: false
|
| 397 |
+
});
|
| 398 |
+
return res ? normalize(res) : void 0;
|
| 399 |
+
}
|
| 400 |
+
|
| 401 |
+
export { SUPPORTED_EXTENSIONS as S, loadDotenv as a, loadConfig as l, setupDotenv as s };
|
backend/node_modules/c12/dist/update.d.mts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import * as magicast from 'magicast';
|
| 2 |
+
|
| 3 |
+
/**
|
| 4 |
+
* @experimental Update a config file or create a new one.
|
| 5 |
+
*/
|
| 6 |
+
declare function updateConfig(opts: UpdateConfigOptions): Promise<UpdateConfigResult>;
|
| 7 |
+
interface UpdateConfigResult {
|
| 8 |
+
configFile?: string;
|
| 9 |
+
created?: boolean;
|
| 10 |
+
}
|
| 11 |
+
type MaybePromise<T> = T | Promise<T>;
|
| 12 |
+
type MagicAstOptions = Exclude<Parameters<(typeof magicast)["parseModule"]>[1], undefined>;
|
| 13 |
+
interface UpdateConfigOptions {
|
| 14 |
+
/**
|
| 15 |
+
* Current working directory
|
| 16 |
+
*/
|
| 17 |
+
cwd: string;
|
| 18 |
+
/**
|
| 19 |
+
* Config file name
|
| 20 |
+
*/
|
| 21 |
+
configFile: string;
|
| 22 |
+
/**
|
| 23 |
+
* Extension used for new config file.
|
| 24 |
+
*/
|
| 25 |
+
createExtension?: string;
|
| 26 |
+
/**
|
| 27 |
+
* Magicast options
|
| 28 |
+
*/
|
| 29 |
+
magicast?: MagicAstOptions;
|
| 30 |
+
/**
|
| 31 |
+
* Update function.
|
| 32 |
+
*/
|
| 33 |
+
onUpdate?: (config: any) => MaybePromise<void>;
|
| 34 |
+
/**
|
| 35 |
+
* Handle default config creation.
|
| 36 |
+
*
|
| 37 |
+
* Tip: you can use this option as a hook to prompt users about config creation.
|
| 38 |
+
*
|
| 39 |
+
* Context object:
|
| 40 |
+
* - path: determined full path to the config file
|
| 41 |
+
*
|
| 42 |
+
* Returns types:
|
| 43 |
+
* - string: custom config template
|
| 44 |
+
* - true: write the template
|
| 45 |
+
* - false: abort the operation
|
| 46 |
+
*/
|
| 47 |
+
onCreate?: (ctx: {
|
| 48 |
+
configFile: string;
|
| 49 |
+
}) => MaybePromise<string | boolean>;
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
export { updateConfig };
|
| 53 |
+
export type { UpdateConfigOptions, UpdateConfigResult };
|
backend/node_modules/c12/dist/update.mjs
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { resolveModulePath } from 'exsolve';
|
| 2 |
+
import { S as SUPPORTED_EXTENSIONS } from './shared/c12.BXpNC6YI.mjs';
|
| 3 |
+
import { join, normalize } from 'pathe';
|
| 4 |
+
import { mkdir, writeFile, readFile } from 'node:fs/promises';
|
| 5 |
+
import { dirname, extname } from 'node:path';
|
| 6 |
+
import 'node:fs';
|
| 7 |
+
import 'node:url';
|
| 8 |
+
import 'node:os';
|
| 9 |
+
import 'jiti';
|
| 10 |
+
import 'rc9';
|
| 11 |
+
import 'defu';
|
| 12 |
+
import 'pkg-types';
|
| 13 |
+
import 'dotenv';
|
| 14 |
+
|
| 15 |
+
const UPDATABLE_EXTS = [".js", ".ts", ".mjs", ".cjs", ".mts", ".cts"];
|
| 16 |
+
async function updateConfig(opts) {
|
| 17 |
+
const { parseModule } = await import('magicast');
|
| 18 |
+
let configFile = tryResolve(`./${opts.configFile}`, opts.cwd, SUPPORTED_EXTENSIONS) || tryResolve(
|
| 19 |
+
`./.config/${opts.configFile}`,
|
| 20 |
+
opts.cwd,
|
| 21 |
+
SUPPORTED_EXTENSIONS
|
| 22 |
+
) || tryResolve(
|
| 23 |
+
`./.config/${opts.configFile.split(".")[0]}`,
|
| 24 |
+
opts.cwd,
|
| 25 |
+
SUPPORTED_EXTENSIONS
|
| 26 |
+
);
|
| 27 |
+
let created = false;
|
| 28 |
+
if (!configFile) {
|
| 29 |
+
configFile = join(
|
| 30 |
+
opts.cwd,
|
| 31 |
+
opts.configFile + (opts.createExtension || ".ts")
|
| 32 |
+
);
|
| 33 |
+
const createResult = await opts.onCreate?.({ configFile }) ?? true;
|
| 34 |
+
if (!createResult) {
|
| 35 |
+
throw new Error("Config file creation aborted.");
|
| 36 |
+
}
|
| 37 |
+
const content = typeof createResult === "string" ? createResult : `export default {}
|
| 38 |
+
`;
|
| 39 |
+
await mkdir(dirname(configFile), { recursive: true });
|
| 40 |
+
await writeFile(configFile, content, "utf8");
|
| 41 |
+
created = true;
|
| 42 |
+
}
|
| 43 |
+
const ext = extname(configFile);
|
| 44 |
+
if (!UPDATABLE_EXTS.includes(ext)) {
|
| 45 |
+
throw new Error(
|
| 46 |
+
`Unsupported config file extension: ${ext} (${configFile}) (supported: ${UPDATABLE_EXTS.join(", ")})`
|
| 47 |
+
);
|
| 48 |
+
}
|
| 49 |
+
const contents = await readFile(configFile, "utf8");
|
| 50 |
+
const _module = parseModule(contents, opts.magicast);
|
| 51 |
+
const defaultExport = _module.exports.default;
|
| 52 |
+
if (!defaultExport) {
|
| 53 |
+
throw new Error("Default export is missing in the config file!");
|
| 54 |
+
}
|
| 55 |
+
const configObj = defaultExport.$type === "function-call" ? defaultExport.$args[0] : defaultExport;
|
| 56 |
+
await opts.onUpdate?.(configObj);
|
| 57 |
+
await writeFile(configFile, _module.generate().code);
|
| 58 |
+
return {
|
| 59 |
+
configFile,
|
| 60 |
+
created
|
| 61 |
+
};
|
| 62 |
+
}
|
| 63 |
+
function tryResolve(path, cwd, extensions) {
|
| 64 |
+
const res = resolveModulePath(path, {
|
| 65 |
+
try: true,
|
| 66 |
+
from: join(cwd, "/"),
|
| 67 |
+
extensions,
|
| 68 |
+
suffixes: ["", "/index"],
|
| 69 |
+
cache: false
|
| 70 |
+
});
|
| 71 |
+
return res ? normalize(res) : void 0;
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
export { updateConfig };
|
backend/node_modules/chokidar/esm/handler.d.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import type { WatchEventType, Stats, FSWatcher as NativeFsWatcher } from 'fs';
|
| 2 |
+
import type { FSWatcher, WatchHelper, Throttler } from './index.js';
|
| 3 |
+
import type { EntryInfo } from 'readdirp';
|
| 4 |
+
export type Path = string;
|
| 5 |
+
export declare const STR_DATA = "data";
|
| 6 |
+
export declare const STR_END = "end";
|
| 7 |
+
export declare const STR_CLOSE = "close";
|
| 8 |
+
export declare const EMPTY_FN: () => void;
|
| 9 |
+
export declare const IDENTITY_FN: (val: unknown) => unknown;
|
| 10 |
+
export declare const isWindows: boolean;
|
| 11 |
+
export declare const isMacos: boolean;
|
| 12 |
+
export declare const isLinux: boolean;
|
| 13 |
+
export declare const isFreeBSD: boolean;
|
| 14 |
+
export declare const isIBMi: boolean;
|
| 15 |
+
export declare const EVENTS: {
|
| 16 |
+
readonly ALL: "all";
|
| 17 |
+
readonly READY: "ready";
|
| 18 |
+
readonly ADD: "add";
|
| 19 |
+
readonly CHANGE: "change";
|
| 20 |
+
readonly ADD_DIR: "addDir";
|
| 21 |
+
readonly UNLINK: "unlink";
|
| 22 |
+
readonly UNLINK_DIR: "unlinkDir";
|
| 23 |
+
readonly RAW: "raw";
|
| 24 |
+
readonly ERROR: "error";
|
| 25 |
+
};
|
| 26 |
+
export type EventName = (typeof EVENTS)[keyof typeof EVENTS];
|
| 27 |
+
export type FsWatchContainer = {
|
| 28 |
+
listeners: (path: string) => void | Set<any>;
|
| 29 |
+
errHandlers: (err: unknown) => void | Set<any>;
|
| 30 |
+
rawEmitters: (ev: WatchEventType, path: string, opts: unknown) => void | Set<any>;
|
| 31 |
+
watcher: NativeFsWatcher;
|
| 32 |
+
watcherUnusable?: boolean;
|
| 33 |
+
};
|
| 34 |
+
export interface WatchHandlers {
|
| 35 |
+
listener: (path: string) => void;
|
| 36 |
+
errHandler: (err: unknown) => void;
|
| 37 |
+
rawEmitter: (ev: WatchEventType, path: string, opts: unknown) => void;
|
| 38 |
+
}
|
| 39 |
+
/**
|
| 40 |
+
* @mixin
|
| 41 |
+
*/
|
| 42 |
+
export declare class NodeFsHandler {
|
| 43 |
+
fsw: FSWatcher;
|
| 44 |
+
_boundHandleError: (error: unknown) => void;
|
| 45 |
+
constructor(fsW: FSWatcher);
|
| 46 |
+
/**
|
| 47 |
+
* Watch file for changes with fs_watchFile or fs_watch.
|
| 48 |
+
* @param path to file or dir
|
| 49 |
+
* @param listener on fs change
|
| 50 |
+
* @returns closer for the watcher instance
|
| 51 |
+
*/
|
| 52 |
+
_watchWithNodeFs(path: string, listener: (path: string, newStats?: any) => void | Promise<void>): (() => void) | undefined;
|
| 53 |
+
/**
|
| 54 |
+
* Watch a file and emit add event if warranted.
|
| 55 |
+
* @returns closer for the watcher instance
|
| 56 |
+
*/
|
| 57 |
+
_handleFile(file: Path, stats: Stats, initialAdd: boolean): (() => void) | undefined;
|
| 58 |
+
/**
|
| 59 |
+
* Handle symlinks encountered while reading a dir.
|
| 60 |
+
* @param entry returned by readdirp
|
| 61 |
+
* @param directory path of dir being read
|
| 62 |
+
* @param path of this item
|
| 63 |
+
* @param item basename of this item
|
| 64 |
+
* @returns true if no more processing is needed for this entry.
|
| 65 |
+
*/
|
| 66 |
+
_handleSymlink(entry: EntryInfo, directory: string, path: Path, item: string): Promise<boolean | undefined>;
|
| 67 |
+
_handleRead(directory: string, initialAdd: boolean, wh: WatchHelper, target: Path, dir: Path, depth: number, throttler: Throttler): Promise<unknown> | undefined;
|
| 68 |
+
/**
|
| 69 |
+
* Read directory to add / remove files from `@watched` list and re-read it on change.
|
| 70 |
+
* @param dir fs path
|
| 71 |
+
* @param stats
|
| 72 |
+
* @param initialAdd
|
| 73 |
+
* @param depth relative to user-supplied path
|
| 74 |
+
* @param target child path targeted for watch
|
| 75 |
+
* @param wh Common watch helpers for this path
|
| 76 |
+
* @param realpath
|
| 77 |
+
* @returns closer for the watcher instance.
|
| 78 |
+
*/
|
| 79 |
+
_handleDir(dir: string, stats: Stats, initialAdd: boolean, depth: number, target: string, wh: WatchHelper, realpath: string): Promise<(() => void) | undefined>;
|
| 80 |
+
/**
|
| 81 |
+
* Handle added file, directory, or glob pattern.
|
| 82 |
+
* Delegates call to _handleFile / _handleDir after checks.
|
| 83 |
+
* @param path to file or ir
|
| 84 |
+
* @param initialAdd was the file added at watch instantiation?
|
| 85 |
+
* @param priorWh depth relative to user-supplied path
|
| 86 |
+
* @param depth Child path actually targeted for watch
|
| 87 |
+
* @param target Child path actually targeted for watch
|
| 88 |
+
*/
|
| 89 |
+
_addToNodeFs(path: string, initialAdd: boolean, priorWh: WatchHelper | undefined, depth: number, target?: string): Promise<string | false | undefined>;
|
| 90 |
+
}
|
backend/node_modules/chokidar/esm/handler.js
ADDED
|
@@ -0,0 +1,629 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { watchFile, unwatchFile, watch as fs_watch } from 'fs';
|
| 2 |
+
import { open, stat, lstat, realpath as fsrealpath } from 'fs/promises';
|
| 3 |
+
import * as sysPath from 'path';
|
| 4 |
+
import { type as osType } from 'os';
|
| 5 |
+
export const STR_DATA = 'data';
|
| 6 |
+
export const STR_END = 'end';
|
| 7 |
+
export const STR_CLOSE = 'close';
|
| 8 |
+
export const EMPTY_FN = () => { };
|
| 9 |
+
export const IDENTITY_FN = (val) => val;
|
| 10 |
+
const pl = process.platform;
|
| 11 |
+
export const isWindows = pl === 'win32';
|
| 12 |
+
export const isMacos = pl === 'darwin';
|
| 13 |
+
export const isLinux = pl === 'linux';
|
| 14 |
+
export const isFreeBSD = pl === 'freebsd';
|
| 15 |
+
export const isIBMi = osType() === 'OS400';
|
| 16 |
+
export const EVENTS = {
|
| 17 |
+
ALL: 'all',
|
| 18 |
+
READY: 'ready',
|
| 19 |
+
ADD: 'add',
|
| 20 |
+
CHANGE: 'change',
|
| 21 |
+
ADD_DIR: 'addDir',
|
| 22 |
+
UNLINK: 'unlink',
|
| 23 |
+
UNLINK_DIR: 'unlinkDir',
|
| 24 |
+
RAW: 'raw',
|
| 25 |
+
ERROR: 'error',
|
| 26 |
+
};
|
| 27 |
+
const EV = EVENTS;
|
| 28 |
+
const THROTTLE_MODE_WATCH = 'watch';
|
| 29 |
+
const statMethods = { lstat, stat };
|
| 30 |
+
const KEY_LISTENERS = 'listeners';
|
| 31 |
+
const KEY_ERR = 'errHandlers';
|
| 32 |
+
const KEY_RAW = 'rawEmitters';
|
| 33 |
+
const HANDLER_KEYS = [KEY_LISTENERS, KEY_ERR, KEY_RAW];
|
| 34 |
+
// prettier-ignore
|
| 35 |
+
const binaryExtensions = new Set([
|
| 36 |
+
'3dm', '3ds', '3g2', '3gp', '7z', 'a', 'aac', 'adp', 'afdesign', 'afphoto', 'afpub', 'ai',
|
| 37 |
+
'aif', 'aiff', 'alz', 'ape', 'apk', 'appimage', 'ar', 'arj', 'asf', 'au', 'avi',
|
| 38 |
+
'bak', 'baml', 'bh', 'bin', 'bk', 'bmp', 'btif', 'bz2', 'bzip2',
|
| 39 |
+
'cab', 'caf', 'cgm', 'class', 'cmx', 'cpio', 'cr2', 'cur', 'dat', 'dcm', 'deb', 'dex', 'djvu',
|
| 40 |
+
'dll', 'dmg', 'dng', 'doc', 'docm', 'docx', 'dot', 'dotm', 'dra', 'DS_Store', 'dsk', 'dts',
|
| 41 |
+
'dtshd', 'dvb', 'dwg', 'dxf',
|
| 42 |
+
'ecelp4800', 'ecelp7470', 'ecelp9600', 'egg', 'eol', 'eot', 'epub', 'exe',
|
| 43 |
+
'f4v', 'fbs', 'fh', 'fla', 'flac', 'flatpak', 'fli', 'flv', 'fpx', 'fst', 'fvt',
|
| 44 |
+
'g3', 'gh', 'gif', 'graffle', 'gz', 'gzip',
|
| 45 |
+
'h261', 'h263', 'h264', 'icns', 'ico', 'ief', 'img', 'ipa', 'iso',
|
| 46 |
+
'jar', 'jpeg', 'jpg', 'jpgv', 'jpm', 'jxr', 'key', 'ktx',
|
| 47 |
+
'lha', 'lib', 'lvp', 'lz', 'lzh', 'lzma', 'lzo',
|
| 48 |
+
'm3u', 'm4a', 'm4v', 'mar', 'mdi', 'mht', 'mid', 'midi', 'mj2', 'mka', 'mkv', 'mmr', 'mng',
|
| 49 |
+
'mobi', 'mov', 'movie', 'mp3',
|
| 50 |
+
'mp4', 'mp4a', 'mpeg', 'mpg', 'mpga', 'mxu',
|
| 51 |
+
'nef', 'npx', 'numbers', 'nupkg',
|
| 52 |
+
'o', 'odp', 'ods', 'odt', 'oga', 'ogg', 'ogv', 'otf', 'ott',
|
| 53 |
+
'pages', 'pbm', 'pcx', 'pdb', 'pdf', 'pea', 'pgm', 'pic', 'png', 'pnm', 'pot', 'potm',
|
| 54 |
+
'potx', 'ppa', 'ppam',
|
| 55 |
+
'ppm', 'pps', 'ppsm', 'ppsx', 'ppt', 'pptm', 'pptx', 'psd', 'pya', 'pyc', 'pyo', 'pyv',
|
| 56 |
+
'qt',
|
| 57 |
+
'rar', 'ras', 'raw', 'resources', 'rgb', 'rip', 'rlc', 'rmf', 'rmvb', 'rpm', 'rtf', 'rz',
|
| 58 |
+
's3m', 's7z', 'scpt', 'sgi', 'shar', 'snap', 'sil', 'sketch', 'slk', 'smv', 'snk', 'so',
|
| 59 |
+
'stl', 'suo', 'sub', 'swf',
|
| 60 |
+
'tar', 'tbz', 'tbz2', 'tga', 'tgz', 'thmx', 'tif', 'tiff', 'tlz', 'ttc', 'ttf', 'txz',
|
| 61 |
+
'udf', 'uvh', 'uvi', 'uvm', 'uvp', 'uvs', 'uvu',
|
| 62 |
+
'viv', 'vob',
|
| 63 |
+
'war', 'wav', 'wax', 'wbmp', 'wdp', 'weba', 'webm', 'webp', 'whl', 'wim', 'wm', 'wma',
|
| 64 |
+
'wmv', 'wmx', 'woff', 'woff2', 'wrm', 'wvx',
|
| 65 |
+
'xbm', 'xif', 'xla', 'xlam', 'xls', 'xlsb', 'xlsm', 'xlsx', 'xlt', 'xltm', 'xltx', 'xm',
|
| 66 |
+
'xmind', 'xpi', 'xpm', 'xwd', 'xz',
|
| 67 |
+
'z', 'zip', 'zipx',
|
| 68 |
+
]);
|
| 69 |
+
const isBinaryPath = (filePath) => binaryExtensions.has(sysPath.extname(filePath).slice(1).toLowerCase());
|
| 70 |
+
// TODO: emit errors properly. Example: EMFILE on Macos.
|
| 71 |
+
const foreach = (val, fn) => {
|
| 72 |
+
if (val instanceof Set) {
|
| 73 |
+
val.forEach(fn);
|
| 74 |
+
}
|
| 75 |
+
else {
|
| 76 |
+
fn(val);
|
| 77 |
+
}
|
| 78 |
+
};
|
| 79 |
+
const addAndConvert = (main, prop, item) => {
|
| 80 |
+
let container = main[prop];
|
| 81 |
+
if (!(container instanceof Set)) {
|
| 82 |
+
main[prop] = container = new Set([container]);
|
| 83 |
+
}
|
| 84 |
+
container.add(item);
|
| 85 |
+
};
|
| 86 |
+
const clearItem = (cont) => (key) => {
|
| 87 |
+
const set = cont[key];
|
| 88 |
+
if (set instanceof Set) {
|
| 89 |
+
set.clear();
|
| 90 |
+
}
|
| 91 |
+
else {
|
| 92 |
+
delete cont[key];
|
| 93 |
+
}
|
| 94 |
+
};
|
| 95 |
+
const delFromSet = (main, prop, item) => {
|
| 96 |
+
const container = main[prop];
|
| 97 |
+
if (container instanceof Set) {
|
| 98 |
+
container.delete(item);
|
| 99 |
+
}
|
| 100 |
+
else if (container === item) {
|
| 101 |
+
delete main[prop];
|
| 102 |
+
}
|
| 103 |
+
};
|
| 104 |
+
const isEmptySet = (val) => (val instanceof Set ? val.size === 0 : !val);
|
| 105 |
+
const FsWatchInstances = new Map();
|
| 106 |
+
/**
|
| 107 |
+
* Instantiates the fs_watch interface
|
| 108 |
+
* @param path to be watched
|
| 109 |
+
* @param options to be passed to fs_watch
|
| 110 |
+
* @param listener main event handler
|
| 111 |
+
* @param errHandler emits info about errors
|
| 112 |
+
* @param emitRaw emits raw event data
|
| 113 |
+
* @returns {NativeFsWatcher}
|
| 114 |
+
*/
|
| 115 |
+
function createFsWatchInstance(path, options, listener, errHandler, emitRaw) {
|
| 116 |
+
const handleEvent = (rawEvent, evPath) => {
|
| 117 |
+
listener(path);
|
| 118 |
+
emitRaw(rawEvent, evPath, { watchedPath: path });
|
| 119 |
+
// emit based on events occurring for files from a directory's watcher in
|
| 120 |
+
// case the file's watcher misses it (and rely on throttling to de-dupe)
|
| 121 |
+
if (evPath && path !== evPath) {
|
| 122 |
+
fsWatchBroadcast(sysPath.resolve(path, evPath), KEY_LISTENERS, sysPath.join(path, evPath));
|
| 123 |
+
}
|
| 124 |
+
};
|
| 125 |
+
try {
|
| 126 |
+
return fs_watch(path, {
|
| 127 |
+
persistent: options.persistent,
|
| 128 |
+
}, handleEvent);
|
| 129 |
+
}
|
| 130 |
+
catch (error) {
|
| 131 |
+
errHandler(error);
|
| 132 |
+
return undefined;
|
| 133 |
+
}
|
| 134 |
+
}
|
| 135 |
+
/**
|
| 136 |
+
* Helper for passing fs_watch event data to a collection of listeners
|
| 137 |
+
* @param fullPath absolute path bound to fs_watch instance
|
| 138 |
+
*/
|
| 139 |
+
const fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
| 140 |
+
const cont = FsWatchInstances.get(fullPath);
|
| 141 |
+
if (!cont)
|
| 142 |
+
return;
|
| 143 |
+
foreach(cont[listenerType], (listener) => {
|
| 144 |
+
listener(val1, val2, val3);
|
| 145 |
+
});
|
| 146 |
+
};
|
| 147 |
+
/**
|
| 148 |
+
* Instantiates the fs_watch interface or binds listeners
|
| 149 |
+
* to an existing one covering the same file system entry
|
| 150 |
+
* @param path
|
| 151 |
+
* @param fullPath absolute path
|
| 152 |
+
* @param options to be passed to fs_watch
|
| 153 |
+
* @param handlers container for event listener functions
|
| 154 |
+
*/
|
| 155 |
+
const setFsWatchListener = (path, fullPath, options, handlers) => {
|
| 156 |
+
const { listener, errHandler, rawEmitter } = handlers;
|
| 157 |
+
let cont = FsWatchInstances.get(fullPath);
|
| 158 |
+
let watcher;
|
| 159 |
+
if (!options.persistent) {
|
| 160 |
+
watcher = createFsWatchInstance(path, options, listener, errHandler, rawEmitter);
|
| 161 |
+
if (!watcher)
|
| 162 |
+
return;
|
| 163 |
+
return watcher.close.bind(watcher);
|
| 164 |
+
}
|
| 165 |
+
if (cont) {
|
| 166 |
+
addAndConvert(cont, KEY_LISTENERS, listener);
|
| 167 |
+
addAndConvert(cont, KEY_ERR, errHandler);
|
| 168 |
+
addAndConvert(cont, KEY_RAW, rawEmitter);
|
| 169 |
+
}
|
| 170 |
+
else {
|
| 171 |
+
watcher = createFsWatchInstance(path, options, fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS), errHandler, // no need to use broadcast here
|
| 172 |
+
fsWatchBroadcast.bind(null, fullPath, KEY_RAW));
|
| 173 |
+
if (!watcher)
|
| 174 |
+
return;
|
| 175 |
+
watcher.on(EV.ERROR, async (error) => {
|
| 176 |
+
const broadcastErr = fsWatchBroadcast.bind(null, fullPath, KEY_ERR);
|
| 177 |
+
if (cont)
|
| 178 |
+
cont.watcherUnusable = true; // documented since Node 10.4.1
|
| 179 |
+
// Workaround for https://github.com/joyent/node/issues/4337
|
| 180 |
+
if (isWindows && error.code === 'EPERM') {
|
| 181 |
+
try {
|
| 182 |
+
const fd = await open(path, 'r');
|
| 183 |
+
await fd.close();
|
| 184 |
+
broadcastErr(error);
|
| 185 |
+
}
|
| 186 |
+
catch (err) {
|
| 187 |
+
// do nothing
|
| 188 |
+
}
|
| 189 |
+
}
|
| 190 |
+
else {
|
| 191 |
+
broadcastErr(error);
|
| 192 |
+
}
|
| 193 |
+
});
|
| 194 |
+
cont = {
|
| 195 |
+
listeners: listener,
|
| 196 |
+
errHandlers: errHandler,
|
| 197 |
+
rawEmitters: rawEmitter,
|
| 198 |
+
watcher,
|
| 199 |
+
};
|
| 200 |
+
FsWatchInstances.set(fullPath, cont);
|
| 201 |
+
}
|
| 202 |
+
// const index = cont.listeners.indexOf(listener);
|
| 203 |
+
// removes this instance's listeners and closes the underlying fs_watch
|
| 204 |
+
// instance if there are no more listeners left
|
| 205 |
+
return () => {
|
| 206 |
+
delFromSet(cont, KEY_LISTENERS, listener);
|
| 207 |
+
delFromSet(cont, KEY_ERR, errHandler);
|
| 208 |
+
delFromSet(cont, KEY_RAW, rawEmitter);
|
| 209 |
+
if (isEmptySet(cont.listeners)) {
|
| 210 |
+
// Check to protect against issue gh-730.
|
| 211 |
+
// if (cont.watcherUnusable) {
|
| 212 |
+
cont.watcher.close();
|
| 213 |
+
// }
|
| 214 |
+
FsWatchInstances.delete(fullPath);
|
| 215 |
+
HANDLER_KEYS.forEach(clearItem(cont));
|
| 216 |
+
// @ts-ignore
|
| 217 |
+
cont.watcher = undefined;
|
| 218 |
+
Object.freeze(cont);
|
| 219 |
+
}
|
| 220 |
+
};
|
| 221 |
+
};
|
| 222 |
+
// fs_watchFile helpers
|
| 223 |
+
// object to hold per-process fs_watchFile instances
|
| 224 |
+
// (may be shared across chokidar FSWatcher instances)
|
| 225 |
+
const FsWatchFileInstances = new Map();
|
| 226 |
+
/**
|
| 227 |
+
* Instantiates the fs_watchFile interface or binds listeners
|
| 228 |
+
* to an existing one covering the same file system entry
|
| 229 |
+
* @param path to be watched
|
| 230 |
+
* @param fullPath absolute path
|
| 231 |
+
* @param options options to be passed to fs_watchFile
|
| 232 |
+
* @param handlers container for event listener functions
|
| 233 |
+
* @returns closer
|
| 234 |
+
*/
|
| 235 |
+
const setFsWatchFileListener = (path, fullPath, options, handlers) => {
|
| 236 |
+
const { listener, rawEmitter } = handlers;
|
| 237 |
+
let cont = FsWatchFileInstances.get(fullPath);
|
| 238 |
+
// let listeners = new Set();
|
| 239 |
+
// let rawEmitters = new Set();
|
| 240 |
+
const copts = cont && cont.options;
|
| 241 |
+
if (copts && (copts.persistent < options.persistent || copts.interval > options.interval)) {
|
| 242 |
+
// "Upgrade" the watcher to persistence or a quicker interval.
|
| 243 |
+
// This creates some unlikely edge case issues if the user mixes
|
| 244 |
+
// settings in a very weird way, but solving for those cases
|
| 245 |
+
// doesn't seem worthwhile for the added complexity.
|
| 246 |
+
// listeners = cont.listeners;
|
| 247 |
+
// rawEmitters = cont.rawEmitters;
|
| 248 |
+
unwatchFile(fullPath);
|
| 249 |
+
cont = undefined;
|
| 250 |
+
}
|
| 251 |
+
if (cont) {
|
| 252 |
+
addAndConvert(cont, KEY_LISTENERS, listener);
|
| 253 |
+
addAndConvert(cont, KEY_RAW, rawEmitter);
|
| 254 |
+
}
|
| 255 |
+
else {
|
| 256 |
+
// TODO
|
| 257 |
+
// listeners.add(listener);
|
| 258 |
+
// rawEmitters.add(rawEmitter);
|
| 259 |
+
cont = {
|
| 260 |
+
listeners: listener,
|
| 261 |
+
rawEmitters: rawEmitter,
|
| 262 |
+
options,
|
| 263 |
+
watcher: watchFile(fullPath, options, (curr, prev) => {
|
| 264 |
+
foreach(cont.rawEmitters, (rawEmitter) => {
|
| 265 |
+
rawEmitter(EV.CHANGE, fullPath, { curr, prev });
|
| 266 |
+
});
|
| 267 |
+
const currmtime = curr.mtimeMs;
|
| 268 |
+
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
| 269 |
+
foreach(cont.listeners, (listener) => listener(path, curr));
|
| 270 |
+
}
|
| 271 |
+
}),
|
| 272 |
+
};
|
| 273 |
+
FsWatchFileInstances.set(fullPath, cont);
|
| 274 |
+
}
|
| 275 |
+
// const index = cont.listeners.indexOf(listener);
|
| 276 |
+
// Removes this instance's listeners and closes the underlying fs_watchFile
|
| 277 |
+
// instance if there are no more listeners left.
|
| 278 |
+
return () => {
|
| 279 |
+
delFromSet(cont, KEY_LISTENERS, listener);
|
| 280 |
+
delFromSet(cont, KEY_RAW, rawEmitter);
|
| 281 |
+
if (isEmptySet(cont.listeners)) {
|
| 282 |
+
FsWatchFileInstances.delete(fullPath);
|
| 283 |
+
unwatchFile(fullPath);
|
| 284 |
+
cont.options = cont.watcher = undefined;
|
| 285 |
+
Object.freeze(cont);
|
| 286 |
+
}
|
| 287 |
+
};
|
| 288 |
+
};
|
| 289 |
+
/**
|
| 290 |
+
* @mixin
|
| 291 |
+
*/
|
| 292 |
+
export class NodeFsHandler {
|
| 293 |
+
constructor(fsW) {
|
| 294 |
+
this.fsw = fsW;
|
| 295 |
+
this._boundHandleError = (error) => fsW._handleError(error);
|
| 296 |
+
}
|
| 297 |
+
/**
|
| 298 |
+
* Watch file for changes with fs_watchFile or fs_watch.
|
| 299 |
+
* @param path to file or dir
|
| 300 |
+
* @param listener on fs change
|
| 301 |
+
* @returns closer for the watcher instance
|
| 302 |
+
*/
|
| 303 |
+
_watchWithNodeFs(path, listener) {
|
| 304 |
+
const opts = this.fsw.options;
|
| 305 |
+
const directory = sysPath.dirname(path);
|
| 306 |
+
const basename = sysPath.basename(path);
|
| 307 |
+
const parent = this.fsw._getWatchedDir(directory);
|
| 308 |
+
parent.add(basename);
|
| 309 |
+
const absolutePath = sysPath.resolve(path);
|
| 310 |
+
const options = {
|
| 311 |
+
persistent: opts.persistent,
|
| 312 |
+
};
|
| 313 |
+
if (!listener)
|
| 314 |
+
listener = EMPTY_FN;
|
| 315 |
+
let closer;
|
| 316 |
+
if (opts.usePolling) {
|
| 317 |
+
const enableBin = opts.interval !== opts.binaryInterval;
|
| 318 |
+
options.interval = enableBin && isBinaryPath(basename) ? opts.binaryInterval : opts.interval;
|
| 319 |
+
closer = setFsWatchFileListener(path, absolutePath, options, {
|
| 320 |
+
listener,
|
| 321 |
+
rawEmitter: this.fsw._emitRaw,
|
| 322 |
+
});
|
| 323 |
+
}
|
| 324 |
+
else {
|
| 325 |
+
closer = setFsWatchListener(path, absolutePath, options, {
|
| 326 |
+
listener,
|
| 327 |
+
errHandler: this._boundHandleError,
|
| 328 |
+
rawEmitter: this.fsw._emitRaw,
|
| 329 |
+
});
|
| 330 |
+
}
|
| 331 |
+
return closer;
|
| 332 |
+
}
|
| 333 |
+
/**
|
| 334 |
+
* Watch a file and emit add event if warranted.
|
| 335 |
+
* @returns closer for the watcher instance
|
| 336 |
+
*/
|
| 337 |
+
_handleFile(file, stats, initialAdd) {
|
| 338 |
+
if (this.fsw.closed) {
|
| 339 |
+
return;
|
| 340 |
+
}
|
| 341 |
+
const dirname = sysPath.dirname(file);
|
| 342 |
+
const basename = sysPath.basename(file);
|
| 343 |
+
const parent = this.fsw._getWatchedDir(dirname);
|
| 344 |
+
// stats is always present
|
| 345 |
+
let prevStats = stats;
|
| 346 |
+
// if the file is already being watched, do nothing
|
| 347 |
+
if (parent.has(basename))
|
| 348 |
+
return;
|
| 349 |
+
const listener = async (path, newStats) => {
|
| 350 |
+
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
| 351 |
+
return;
|
| 352 |
+
if (!newStats || newStats.mtimeMs === 0) {
|
| 353 |
+
try {
|
| 354 |
+
const newStats = await stat(file);
|
| 355 |
+
if (this.fsw.closed)
|
| 356 |
+
return;
|
| 357 |
+
// Check that change event was not fired because of changed only accessTime.
|
| 358 |
+
const at = newStats.atimeMs;
|
| 359 |
+
const mt = newStats.mtimeMs;
|
| 360 |
+
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
| 361 |
+
this.fsw._emit(EV.CHANGE, file, newStats);
|
| 362 |
+
}
|
| 363 |
+
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats.ino) {
|
| 364 |
+
this.fsw._closeFile(path);
|
| 365 |
+
prevStats = newStats;
|
| 366 |
+
const closer = this._watchWithNodeFs(file, listener);
|
| 367 |
+
if (closer)
|
| 368 |
+
this.fsw._addPathCloser(path, closer);
|
| 369 |
+
}
|
| 370 |
+
else {
|
| 371 |
+
prevStats = newStats;
|
| 372 |
+
}
|
| 373 |
+
}
|
| 374 |
+
catch (error) {
|
| 375 |
+
// Fix issues where mtime is null but file is still present
|
| 376 |
+
this.fsw._remove(dirname, basename);
|
| 377 |
+
}
|
| 378 |
+
// add is about to be emitted if file not already tracked in parent
|
| 379 |
+
}
|
| 380 |
+
else if (parent.has(basename)) {
|
| 381 |
+
// Check that change event was not fired because of changed only accessTime.
|
| 382 |
+
const at = newStats.atimeMs;
|
| 383 |
+
const mt = newStats.mtimeMs;
|
| 384 |
+
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
| 385 |
+
this.fsw._emit(EV.CHANGE, file, newStats);
|
| 386 |
+
}
|
| 387 |
+
prevStats = newStats;
|
| 388 |
+
}
|
| 389 |
+
};
|
| 390 |
+
// kick off the watcher
|
| 391 |
+
const closer = this._watchWithNodeFs(file, listener);
|
| 392 |
+
// emit an add event if we're supposed to
|
| 393 |
+
if (!(initialAdd && this.fsw.options.ignoreInitial) && this.fsw._isntIgnored(file)) {
|
| 394 |
+
if (!this.fsw._throttle(EV.ADD, file, 0))
|
| 395 |
+
return;
|
| 396 |
+
this.fsw._emit(EV.ADD, file, stats);
|
| 397 |
+
}
|
| 398 |
+
return closer;
|
| 399 |
+
}
|
| 400 |
+
/**
|
| 401 |
+
* Handle symlinks encountered while reading a dir.
|
| 402 |
+
* @param entry returned by readdirp
|
| 403 |
+
* @param directory path of dir being read
|
| 404 |
+
* @param path of this item
|
| 405 |
+
* @param item basename of this item
|
| 406 |
+
* @returns true if no more processing is needed for this entry.
|
| 407 |
+
*/
|
| 408 |
+
async _handleSymlink(entry, directory, path, item) {
|
| 409 |
+
if (this.fsw.closed) {
|
| 410 |
+
return;
|
| 411 |
+
}
|
| 412 |
+
const full = entry.fullPath;
|
| 413 |
+
const dir = this.fsw._getWatchedDir(directory);
|
| 414 |
+
if (!this.fsw.options.followSymlinks) {
|
| 415 |
+
// watch symlink directly (don't follow) and detect changes
|
| 416 |
+
this.fsw._incrReadyCount();
|
| 417 |
+
let linkPath;
|
| 418 |
+
try {
|
| 419 |
+
linkPath = await fsrealpath(path);
|
| 420 |
+
}
|
| 421 |
+
catch (e) {
|
| 422 |
+
this.fsw._emitReady();
|
| 423 |
+
return true;
|
| 424 |
+
}
|
| 425 |
+
if (this.fsw.closed)
|
| 426 |
+
return;
|
| 427 |
+
if (dir.has(item)) {
|
| 428 |
+
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
| 429 |
+
this.fsw._symlinkPaths.set(full, linkPath);
|
| 430 |
+
this.fsw._emit(EV.CHANGE, path, entry.stats);
|
| 431 |
+
}
|
| 432 |
+
}
|
| 433 |
+
else {
|
| 434 |
+
dir.add(item);
|
| 435 |
+
this.fsw._symlinkPaths.set(full, linkPath);
|
| 436 |
+
this.fsw._emit(EV.ADD, path, entry.stats);
|
| 437 |
+
}
|
| 438 |
+
this.fsw._emitReady();
|
| 439 |
+
return true;
|
| 440 |
+
}
|
| 441 |
+
// don't follow the same symlink more than once
|
| 442 |
+
if (this.fsw._symlinkPaths.has(full)) {
|
| 443 |
+
return true;
|
| 444 |
+
}
|
| 445 |
+
this.fsw._symlinkPaths.set(full, true);
|
| 446 |
+
}
|
| 447 |
+
_handleRead(directory, initialAdd, wh, target, dir, depth, throttler) {
|
| 448 |
+
// Normalize the directory name on Windows
|
| 449 |
+
directory = sysPath.join(directory, '');
|
| 450 |
+
throttler = this.fsw._throttle('readdir', directory, 1000);
|
| 451 |
+
if (!throttler)
|
| 452 |
+
return;
|
| 453 |
+
const previous = this.fsw._getWatchedDir(wh.path);
|
| 454 |
+
const current = new Set();
|
| 455 |
+
let stream = this.fsw._readdirp(directory, {
|
| 456 |
+
fileFilter: (entry) => wh.filterPath(entry),
|
| 457 |
+
directoryFilter: (entry) => wh.filterDir(entry),
|
| 458 |
+
});
|
| 459 |
+
if (!stream)
|
| 460 |
+
return;
|
| 461 |
+
stream
|
| 462 |
+
.on(STR_DATA, async (entry) => {
|
| 463 |
+
if (this.fsw.closed) {
|
| 464 |
+
stream = undefined;
|
| 465 |
+
return;
|
| 466 |
+
}
|
| 467 |
+
const item = entry.path;
|
| 468 |
+
let path = sysPath.join(directory, item);
|
| 469 |
+
current.add(item);
|
| 470 |
+
if (entry.stats.isSymbolicLink() &&
|
| 471 |
+
(await this._handleSymlink(entry, directory, path, item))) {
|
| 472 |
+
return;
|
| 473 |
+
}
|
| 474 |
+
if (this.fsw.closed) {
|
| 475 |
+
stream = undefined;
|
| 476 |
+
return;
|
| 477 |
+
}
|
| 478 |
+
// Files that present in current directory snapshot
|
| 479 |
+
// but absent in previous are added to watch list and
|
| 480 |
+
// emit `add` event.
|
| 481 |
+
if (item === target || (!target && !previous.has(item))) {
|
| 482 |
+
this.fsw._incrReadyCount();
|
| 483 |
+
// ensure relativeness of path is preserved in case of watcher reuse
|
| 484 |
+
path = sysPath.join(dir, sysPath.relative(dir, path));
|
| 485 |
+
this._addToNodeFs(path, initialAdd, wh, depth + 1);
|
| 486 |
+
}
|
| 487 |
+
})
|
| 488 |
+
.on(EV.ERROR, this._boundHandleError);
|
| 489 |
+
return new Promise((resolve, reject) => {
|
| 490 |
+
if (!stream)
|
| 491 |
+
return reject();
|
| 492 |
+
stream.once(STR_END, () => {
|
| 493 |
+
if (this.fsw.closed) {
|
| 494 |
+
stream = undefined;
|
| 495 |
+
return;
|
| 496 |
+
}
|
| 497 |
+
const wasThrottled = throttler ? throttler.clear() : false;
|
| 498 |
+
resolve(undefined);
|
| 499 |
+
// Files that absent in current directory snapshot
|
| 500 |
+
// but present in previous emit `remove` event
|
| 501 |
+
// and are removed from @watched[directory].
|
| 502 |
+
previous
|
| 503 |
+
.getChildren()
|
| 504 |
+
.filter((item) => {
|
| 505 |
+
return item !== directory && !current.has(item);
|
| 506 |
+
})
|
| 507 |
+
.forEach((item) => {
|
| 508 |
+
this.fsw._remove(directory, item);
|
| 509 |
+
});
|
| 510 |
+
stream = undefined;
|
| 511 |
+
// one more time for any missed in case changes came in extremely quickly
|
| 512 |
+
if (wasThrottled)
|
| 513 |
+
this._handleRead(directory, false, wh, target, dir, depth, throttler);
|
| 514 |
+
});
|
| 515 |
+
});
|
| 516 |
+
}
|
| 517 |
+
/**
|
| 518 |
+
* Read directory to add / remove files from `@watched` list and re-read it on change.
|
| 519 |
+
* @param dir fs path
|
| 520 |
+
* @param stats
|
| 521 |
+
* @param initialAdd
|
| 522 |
+
* @param depth relative to user-supplied path
|
| 523 |
+
* @param target child path targeted for watch
|
| 524 |
+
* @param wh Common watch helpers for this path
|
| 525 |
+
* @param realpath
|
| 526 |
+
* @returns closer for the watcher instance.
|
| 527 |
+
*/
|
| 528 |
+
async _handleDir(dir, stats, initialAdd, depth, target, wh, realpath) {
|
| 529 |
+
const parentDir = this.fsw._getWatchedDir(sysPath.dirname(dir));
|
| 530 |
+
const tracked = parentDir.has(sysPath.basename(dir));
|
| 531 |
+
if (!(initialAdd && this.fsw.options.ignoreInitial) && !target && !tracked) {
|
| 532 |
+
this.fsw._emit(EV.ADD_DIR, dir, stats);
|
| 533 |
+
}
|
| 534 |
+
// ensure dir is tracked (harmless if redundant)
|
| 535 |
+
parentDir.add(sysPath.basename(dir));
|
| 536 |
+
this.fsw._getWatchedDir(dir);
|
| 537 |
+
let throttler;
|
| 538 |
+
let closer;
|
| 539 |
+
const oDepth = this.fsw.options.depth;
|
| 540 |
+
if ((oDepth == null || depth <= oDepth) && !this.fsw._symlinkPaths.has(realpath)) {
|
| 541 |
+
if (!target) {
|
| 542 |
+
await this._handleRead(dir, initialAdd, wh, target, dir, depth, throttler);
|
| 543 |
+
if (this.fsw.closed)
|
| 544 |
+
return;
|
| 545 |
+
}
|
| 546 |
+
closer = this._watchWithNodeFs(dir, (dirPath, stats) => {
|
| 547 |
+
// if current directory is removed, do nothing
|
| 548 |
+
if (stats && stats.mtimeMs === 0)
|
| 549 |
+
return;
|
| 550 |
+
this._handleRead(dirPath, false, wh, target, dir, depth, throttler);
|
| 551 |
+
});
|
| 552 |
+
}
|
| 553 |
+
return closer;
|
| 554 |
+
}
|
| 555 |
+
/**
|
| 556 |
+
* Handle added file, directory, or glob pattern.
|
| 557 |
+
* Delegates call to _handleFile / _handleDir after checks.
|
| 558 |
+
* @param path to file or ir
|
| 559 |
+
* @param initialAdd was the file added at watch instantiation?
|
| 560 |
+
* @param priorWh depth relative to user-supplied path
|
| 561 |
+
* @param depth Child path actually targeted for watch
|
| 562 |
+
* @param target Child path actually targeted for watch
|
| 563 |
+
*/
|
| 564 |
+
async _addToNodeFs(path, initialAdd, priorWh, depth, target) {
|
| 565 |
+
const ready = this.fsw._emitReady;
|
| 566 |
+
if (this.fsw._isIgnored(path) || this.fsw.closed) {
|
| 567 |
+
ready();
|
| 568 |
+
return false;
|
| 569 |
+
}
|
| 570 |
+
const wh = this.fsw._getWatchHelpers(path);
|
| 571 |
+
if (priorWh) {
|
| 572 |
+
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
| 573 |
+
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
| 574 |
+
}
|
| 575 |
+
// evaluate what is at the path we're being asked to watch
|
| 576 |
+
try {
|
| 577 |
+
const stats = await statMethods[wh.statMethod](wh.watchPath);
|
| 578 |
+
if (this.fsw.closed)
|
| 579 |
+
return;
|
| 580 |
+
if (this.fsw._isIgnored(wh.watchPath, stats)) {
|
| 581 |
+
ready();
|
| 582 |
+
return false;
|
| 583 |
+
}
|
| 584 |
+
const follow = this.fsw.options.followSymlinks;
|
| 585 |
+
let closer;
|
| 586 |
+
if (stats.isDirectory()) {
|
| 587 |
+
const absPath = sysPath.resolve(path);
|
| 588 |
+
const targetPath = follow ? await fsrealpath(path) : path;
|
| 589 |
+
if (this.fsw.closed)
|
| 590 |
+
return;
|
| 591 |
+
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
| 592 |
+
if (this.fsw.closed)
|
| 593 |
+
return;
|
| 594 |
+
// preserve this symlink's target path
|
| 595 |
+
if (absPath !== targetPath && targetPath !== undefined) {
|
| 596 |
+
this.fsw._symlinkPaths.set(absPath, targetPath);
|
| 597 |
+
}
|
| 598 |
+
}
|
| 599 |
+
else if (stats.isSymbolicLink()) {
|
| 600 |
+
const targetPath = follow ? await fsrealpath(path) : path;
|
| 601 |
+
if (this.fsw.closed)
|
| 602 |
+
return;
|
| 603 |
+
const parent = sysPath.dirname(wh.watchPath);
|
| 604 |
+
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
| 605 |
+
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
| 606 |
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path, wh, targetPath);
|
| 607 |
+
if (this.fsw.closed)
|
| 608 |
+
return;
|
| 609 |
+
// preserve this symlink's target path
|
| 610 |
+
if (targetPath !== undefined) {
|
| 611 |
+
this.fsw._symlinkPaths.set(sysPath.resolve(path), targetPath);
|
| 612 |
+
}
|
| 613 |
+
}
|
| 614 |
+
else {
|
| 615 |
+
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
| 616 |
+
}
|
| 617 |
+
ready();
|
| 618 |
+
if (closer)
|
| 619 |
+
this.fsw._addPathCloser(path, closer);
|
| 620 |
+
return false;
|
| 621 |
+
}
|
| 622 |
+
catch (error) {
|
| 623 |
+
if (this.fsw._handleError(error)) {
|
| 624 |
+
ready();
|
| 625 |
+
return path;
|
| 626 |
+
}
|
| 627 |
+
}
|
| 628 |
+
}
|
| 629 |
+
}
|
backend/node_modules/chokidar/esm/index.d.ts
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*! chokidar - MIT License (c) 2012 Paul Miller (paulmillr.com) */
|
| 2 |
+
import { Stats } from 'fs';
|
| 3 |
+
import { EventEmitter } from 'events';
|
| 4 |
+
import { ReaddirpStream, ReaddirpOptions, EntryInfo } from 'readdirp';
|
| 5 |
+
import { NodeFsHandler, EventName, Path, EVENTS as EV, WatchHandlers } from './handler.js';
|
| 6 |
+
type AWF = {
|
| 7 |
+
stabilityThreshold: number;
|
| 8 |
+
pollInterval: number;
|
| 9 |
+
};
|
| 10 |
+
type BasicOpts = {
|
| 11 |
+
persistent: boolean;
|
| 12 |
+
ignoreInitial: boolean;
|
| 13 |
+
followSymlinks: boolean;
|
| 14 |
+
cwd?: string;
|
| 15 |
+
usePolling: boolean;
|
| 16 |
+
interval: number;
|
| 17 |
+
binaryInterval: number;
|
| 18 |
+
alwaysStat?: boolean;
|
| 19 |
+
depth?: number;
|
| 20 |
+
ignorePermissionErrors: boolean;
|
| 21 |
+
atomic: boolean | number;
|
| 22 |
+
};
|
| 23 |
+
export type Throttler = {
|
| 24 |
+
timeoutObject: NodeJS.Timeout;
|
| 25 |
+
clear: () => void;
|
| 26 |
+
count: number;
|
| 27 |
+
};
|
| 28 |
+
export type ChokidarOptions = Partial<BasicOpts & {
|
| 29 |
+
ignored: Matcher | Matcher[];
|
| 30 |
+
awaitWriteFinish: boolean | Partial<AWF>;
|
| 31 |
+
}>;
|
| 32 |
+
export type FSWInstanceOptions = BasicOpts & {
|
| 33 |
+
ignored: Matcher[];
|
| 34 |
+
awaitWriteFinish: false | AWF;
|
| 35 |
+
};
|
| 36 |
+
export type ThrottleType = 'readdir' | 'watch' | 'add' | 'remove' | 'change';
|
| 37 |
+
export type EmitArgs = [path: Path, stats?: Stats];
|
| 38 |
+
export type EmitErrorArgs = [error: Error, stats?: Stats];
|
| 39 |
+
export type EmitArgsWithName = [event: EventName, ...EmitArgs];
|
| 40 |
+
export type MatchFunction = (val: string, stats?: Stats) => boolean;
|
| 41 |
+
export interface MatcherObject {
|
| 42 |
+
path: string;
|
| 43 |
+
recursive?: boolean;
|
| 44 |
+
}
|
| 45 |
+
export type Matcher = string | RegExp | MatchFunction | MatcherObject;
|
| 46 |
+
/**
|
| 47 |
+
* Directory entry.
|
| 48 |
+
*/
|
| 49 |
+
declare class DirEntry {
|
| 50 |
+
path: Path;
|
| 51 |
+
_removeWatcher: (dir: string, base: string) => void;
|
| 52 |
+
items: Set<Path>;
|
| 53 |
+
constructor(dir: Path, removeWatcher: (dir: string, base: string) => void);
|
| 54 |
+
add(item: string): void;
|
| 55 |
+
remove(item: string): Promise<void>;
|
| 56 |
+
has(item: string): boolean | undefined;
|
| 57 |
+
getChildren(): string[];
|
| 58 |
+
dispose(): void;
|
| 59 |
+
}
|
| 60 |
+
export declare class WatchHelper {
|
| 61 |
+
fsw: FSWatcher;
|
| 62 |
+
path: string;
|
| 63 |
+
watchPath: string;
|
| 64 |
+
fullWatchPath: string;
|
| 65 |
+
dirParts: string[][];
|
| 66 |
+
followSymlinks: boolean;
|
| 67 |
+
statMethod: 'stat' | 'lstat';
|
| 68 |
+
constructor(path: string, follow: boolean, fsw: FSWatcher);
|
| 69 |
+
entryPath(entry: EntryInfo): Path;
|
| 70 |
+
filterPath(entry: EntryInfo): boolean;
|
| 71 |
+
filterDir(entry: EntryInfo): boolean;
|
| 72 |
+
}
|
| 73 |
+
export interface FSWatcherKnownEventMap {
|
| 74 |
+
[EV.READY]: [];
|
| 75 |
+
[EV.RAW]: Parameters<WatchHandlers['rawEmitter']>;
|
| 76 |
+
[EV.ERROR]: Parameters<WatchHandlers['errHandler']>;
|
| 77 |
+
[EV.ALL]: [event: EventName, ...EmitArgs];
|
| 78 |
+
}
|
| 79 |
+
export type FSWatcherEventMap = FSWatcherKnownEventMap & {
|
| 80 |
+
[k in Exclude<EventName, keyof FSWatcherKnownEventMap>]: EmitArgs;
|
| 81 |
+
};
|
| 82 |
+
/**
|
| 83 |
+
* Watches files & directories for changes. Emitted events:
|
| 84 |
+
* `add`, `addDir`, `change`, `unlink`, `unlinkDir`, `all`, `error`
|
| 85 |
+
*
|
| 86 |
+
* new FSWatcher()
|
| 87 |
+
* .add(directories)
|
| 88 |
+
* .on('add', path => log('File', path, 'was added'))
|
| 89 |
+
*/
|
| 90 |
+
export declare class FSWatcher extends EventEmitter<FSWatcherEventMap> {
|
| 91 |
+
closed: boolean;
|
| 92 |
+
options: FSWInstanceOptions;
|
| 93 |
+
_closers: Map<string, Array<any>>;
|
| 94 |
+
_ignoredPaths: Set<Matcher>;
|
| 95 |
+
_throttled: Map<ThrottleType, Map<any, any>>;
|
| 96 |
+
_streams: Set<ReaddirpStream>;
|
| 97 |
+
_symlinkPaths: Map<Path, string | boolean>;
|
| 98 |
+
_watched: Map<string, DirEntry>;
|
| 99 |
+
_pendingWrites: Map<string, any>;
|
| 100 |
+
_pendingUnlinks: Map<string, EmitArgsWithName>;
|
| 101 |
+
_readyCount: number;
|
| 102 |
+
_emitReady: () => void;
|
| 103 |
+
_closePromise?: Promise<void>;
|
| 104 |
+
_userIgnored?: MatchFunction;
|
| 105 |
+
_readyEmitted: boolean;
|
| 106 |
+
_emitRaw: WatchHandlers['rawEmitter'];
|
| 107 |
+
_boundRemove: (dir: string, item: string) => void;
|
| 108 |
+
_nodeFsHandler: NodeFsHandler;
|
| 109 |
+
constructor(_opts?: ChokidarOptions);
|
| 110 |
+
_addIgnoredPath(matcher: Matcher): void;
|
| 111 |
+
_removeIgnoredPath(matcher: Matcher): void;
|
| 112 |
+
/**
|
| 113 |
+
* Adds paths to be watched on an existing FSWatcher instance.
|
| 114 |
+
* @param paths_ file or file list. Other arguments are unused
|
| 115 |
+
*/
|
| 116 |
+
add(paths_: Path | Path[], _origAdd?: string, _internal?: boolean): FSWatcher;
|
| 117 |
+
/**
|
| 118 |
+
* Close watchers or start ignoring events from specified paths.
|
| 119 |
+
*/
|
| 120 |
+
unwatch(paths_: Path | Path[]): FSWatcher;
|
| 121 |
+
/**
|
| 122 |
+
* Close watchers and remove all listeners from watched paths.
|
| 123 |
+
*/
|
| 124 |
+
close(): Promise<void>;
|
| 125 |
+
/**
|
| 126 |
+
* Expose list of watched paths
|
| 127 |
+
* @returns for chaining
|
| 128 |
+
*/
|
| 129 |
+
getWatched(): Record<string, string[]>;
|
| 130 |
+
emitWithAll(event: EventName, args: EmitArgs): void;
|
| 131 |
+
/**
|
| 132 |
+
* Normalize and emit events.
|
| 133 |
+
* Calling _emit DOES NOT MEAN emit() would be called!
|
| 134 |
+
* @param event Type of event
|
| 135 |
+
* @param path File or directory path
|
| 136 |
+
* @param stats arguments to be passed with event
|
| 137 |
+
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
| 138 |
+
*/
|
| 139 |
+
_emit(event: EventName, path: Path, stats?: Stats): Promise<this | undefined>;
|
| 140 |
+
/**
|
| 141 |
+
* Common handler for errors
|
| 142 |
+
* @returns The error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
| 143 |
+
*/
|
| 144 |
+
_handleError(error: Error): Error | boolean;
|
| 145 |
+
/**
|
| 146 |
+
* Helper utility for throttling
|
| 147 |
+
* @param actionType type being throttled
|
| 148 |
+
* @param path being acted upon
|
| 149 |
+
* @param timeout duration of time to suppress duplicate actions
|
| 150 |
+
* @returns tracking object or false if action should be suppressed
|
| 151 |
+
*/
|
| 152 |
+
_throttle(actionType: ThrottleType, path: Path, timeout: number): Throttler | false;
|
| 153 |
+
_incrReadyCount(): number;
|
| 154 |
+
/**
|
| 155 |
+
* Awaits write operation to finish.
|
| 156 |
+
* Polls a newly created file for size variations. When files size does not change for 'threshold' milliseconds calls callback.
|
| 157 |
+
* @param path being acted upon
|
| 158 |
+
* @param threshold Time in milliseconds a file size must be fixed before acknowledging write OP is finished
|
| 159 |
+
* @param event
|
| 160 |
+
* @param awfEmit Callback to be called when ready for event to be emitted.
|
| 161 |
+
*/
|
| 162 |
+
_awaitWriteFinish(path: Path, threshold: number, event: EventName, awfEmit: (err?: Error, stat?: Stats) => void): void;
|
| 163 |
+
/**
|
| 164 |
+
* Determines whether user has asked to ignore this path.
|
| 165 |
+
*/
|
| 166 |
+
_isIgnored(path: Path, stats?: Stats): boolean;
|
| 167 |
+
_isntIgnored(path: Path, stat?: Stats): boolean;
|
| 168 |
+
/**
|
| 169 |
+
* Provides a set of common helpers and properties relating to symlink handling.
|
| 170 |
+
* @param path file or directory pattern being watched
|
| 171 |
+
*/
|
| 172 |
+
_getWatchHelpers(path: Path): WatchHelper;
|
| 173 |
+
/**
|
| 174 |
+
* Provides directory tracking objects
|
| 175 |
+
* @param directory path of the directory
|
| 176 |
+
*/
|
| 177 |
+
_getWatchedDir(directory: string): DirEntry;
|
| 178 |
+
/**
|
| 179 |
+
* Check for read permissions: https://stackoverflow.com/a/11781404/1358405
|
| 180 |
+
*/
|
| 181 |
+
_hasReadPermissions(stats: Stats): boolean;
|
| 182 |
+
/**
|
| 183 |
+
* Handles emitting unlink events for
|
| 184 |
+
* files and directories, and via recursion, for
|
| 185 |
+
* files and directories within directories that are unlinked
|
| 186 |
+
* @param directory within which the following item is located
|
| 187 |
+
* @param item base path of item/directory
|
| 188 |
+
*/
|
| 189 |
+
_remove(directory: string, item: string, isDirectory?: boolean): void;
|
| 190 |
+
/**
|
| 191 |
+
* Closes all watchers for a path
|
| 192 |
+
*/
|
| 193 |
+
_closePath(path: Path): void;
|
| 194 |
+
/**
|
| 195 |
+
* Closes only file-specific watchers
|
| 196 |
+
*/
|
| 197 |
+
_closeFile(path: Path): void;
|
| 198 |
+
_addPathCloser(path: Path, closer: () => void): void;
|
| 199 |
+
_readdirp(root: Path, opts?: Partial<ReaddirpOptions>): ReaddirpStream | undefined;
|
| 200 |
+
}
|
| 201 |
+
/**
|
| 202 |
+
* Instantiates watcher with paths to be tracked.
|
| 203 |
+
* @param paths file / directory paths
|
| 204 |
+
* @param options opts, such as `atomic`, `awaitWriteFinish`, `ignored`, and others
|
| 205 |
+
* @returns an instance of FSWatcher for chaining.
|
| 206 |
+
* @example
|
| 207 |
+
* const watcher = watch('.').on('all', (event, path) => { console.log(event, path); });
|
| 208 |
+
* watch('.', { atomic: true, awaitWriteFinish: true, ignored: (f, stats) => stats?.isFile() && !f.endsWith('.js') })
|
| 209 |
+
*/
|
| 210 |
+
export declare function watch(paths: string | string[], options?: ChokidarOptions): FSWatcher;
|
| 211 |
+
declare const _default: {
|
| 212 |
+
watch: typeof watch;
|
| 213 |
+
FSWatcher: typeof FSWatcher;
|
| 214 |
+
};
|
| 215 |
+
export default _default;
|
backend/node_modules/chokidar/esm/index.js
ADDED
|
@@ -0,0 +1,798 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*! chokidar - MIT License (c) 2012 Paul Miller (paulmillr.com) */
|
| 2 |
+
import { stat as statcb } from 'fs';
|
| 3 |
+
import { stat, readdir } from 'fs/promises';
|
| 4 |
+
import { EventEmitter } from 'events';
|
| 5 |
+
import * as sysPath from 'path';
|
| 6 |
+
import { readdirp } from 'readdirp';
|
| 7 |
+
import { NodeFsHandler, EVENTS as EV, isWindows, isIBMi, EMPTY_FN, STR_CLOSE, STR_END, } from './handler.js';
|
| 8 |
+
const SLASH = '/';
|
| 9 |
+
const SLASH_SLASH = '//';
|
| 10 |
+
const ONE_DOT = '.';
|
| 11 |
+
const TWO_DOTS = '..';
|
| 12 |
+
const STRING_TYPE = 'string';
|
| 13 |
+
const BACK_SLASH_RE = /\\/g;
|
| 14 |
+
const DOUBLE_SLASH_RE = /\/\//;
|
| 15 |
+
const DOT_RE = /\..*\.(sw[px])$|~$|\.subl.*\.tmp/;
|
| 16 |
+
const REPLACER_RE = /^\.[/\\]/;
|
| 17 |
+
function arrify(item) {
|
| 18 |
+
return Array.isArray(item) ? item : [item];
|
| 19 |
+
}
|
| 20 |
+
const isMatcherObject = (matcher) => typeof matcher === 'object' && matcher !== null && !(matcher instanceof RegExp);
|
| 21 |
+
function createPattern(matcher) {
|
| 22 |
+
if (typeof matcher === 'function')
|
| 23 |
+
return matcher;
|
| 24 |
+
if (typeof matcher === 'string')
|
| 25 |
+
return (string) => matcher === string;
|
| 26 |
+
if (matcher instanceof RegExp)
|
| 27 |
+
return (string) => matcher.test(string);
|
| 28 |
+
if (typeof matcher === 'object' && matcher !== null) {
|
| 29 |
+
return (string) => {
|
| 30 |
+
if (matcher.path === string)
|
| 31 |
+
return true;
|
| 32 |
+
if (matcher.recursive) {
|
| 33 |
+
const relative = sysPath.relative(matcher.path, string);
|
| 34 |
+
if (!relative) {
|
| 35 |
+
return false;
|
| 36 |
+
}
|
| 37 |
+
return !relative.startsWith('..') && !sysPath.isAbsolute(relative);
|
| 38 |
+
}
|
| 39 |
+
return false;
|
| 40 |
+
};
|
| 41 |
+
}
|
| 42 |
+
return () => false;
|
| 43 |
+
}
|
| 44 |
+
function normalizePath(path) {
|
| 45 |
+
if (typeof path !== 'string')
|
| 46 |
+
throw new Error('string expected');
|
| 47 |
+
path = sysPath.normalize(path);
|
| 48 |
+
path = path.replace(/\\/g, '/');
|
| 49 |
+
let prepend = false;
|
| 50 |
+
if (path.startsWith('//'))
|
| 51 |
+
prepend = true;
|
| 52 |
+
const DOUBLE_SLASH_RE = /\/\//;
|
| 53 |
+
while (path.match(DOUBLE_SLASH_RE))
|
| 54 |
+
path = path.replace(DOUBLE_SLASH_RE, '/');
|
| 55 |
+
if (prepend)
|
| 56 |
+
path = '/' + path;
|
| 57 |
+
return path;
|
| 58 |
+
}
|
| 59 |
+
function matchPatterns(patterns, testString, stats) {
|
| 60 |
+
const path = normalizePath(testString);
|
| 61 |
+
for (let index = 0; index < patterns.length; index++) {
|
| 62 |
+
const pattern = patterns[index];
|
| 63 |
+
if (pattern(path, stats)) {
|
| 64 |
+
return true;
|
| 65 |
+
}
|
| 66 |
+
}
|
| 67 |
+
return false;
|
| 68 |
+
}
|
| 69 |
+
function anymatch(matchers, testString) {
|
| 70 |
+
if (matchers == null) {
|
| 71 |
+
throw new TypeError('anymatch: specify first argument');
|
| 72 |
+
}
|
| 73 |
+
// Early cache for matchers.
|
| 74 |
+
const matchersArray = arrify(matchers);
|
| 75 |
+
const patterns = matchersArray.map((matcher) => createPattern(matcher));
|
| 76 |
+
if (testString == null) {
|
| 77 |
+
return (testString, stats) => {
|
| 78 |
+
return matchPatterns(patterns, testString, stats);
|
| 79 |
+
};
|
| 80 |
+
}
|
| 81 |
+
return matchPatterns(patterns, testString);
|
| 82 |
+
}
|
| 83 |
+
const unifyPaths = (paths_) => {
|
| 84 |
+
const paths = arrify(paths_).flat();
|
| 85 |
+
if (!paths.every((p) => typeof p === STRING_TYPE)) {
|
| 86 |
+
throw new TypeError(`Non-string provided as watch path: ${paths}`);
|
| 87 |
+
}
|
| 88 |
+
return paths.map(normalizePathToUnix);
|
| 89 |
+
};
|
| 90 |
+
// If SLASH_SLASH occurs at the beginning of path, it is not replaced
|
| 91 |
+
// because "//StoragePC/DrivePool/Movies" is a valid network path
|
| 92 |
+
const toUnix = (string) => {
|
| 93 |
+
let str = string.replace(BACK_SLASH_RE, SLASH);
|
| 94 |
+
let prepend = false;
|
| 95 |
+
if (str.startsWith(SLASH_SLASH)) {
|
| 96 |
+
prepend = true;
|
| 97 |
+
}
|
| 98 |
+
while (str.match(DOUBLE_SLASH_RE)) {
|
| 99 |
+
str = str.replace(DOUBLE_SLASH_RE, SLASH);
|
| 100 |
+
}
|
| 101 |
+
if (prepend) {
|
| 102 |
+
str = SLASH + str;
|
| 103 |
+
}
|
| 104 |
+
return str;
|
| 105 |
+
};
|
| 106 |
+
// Our version of upath.normalize
|
| 107 |
+
// TODO: this is not equal to path-normalize module - investigate why
|
| 108 |
+
const normalizePathToUnix = (path) => toUnix(sysPath.normalize(toUnix(path)));
|
| 109 |
+
// TODO: refactor
|
| 110 |
+
const normalizeIgnored = (cwd = '') => (path) => {
|
| 111 |
+
if (typeof path === 'string') {
|
| 112 |
+
return normalizePathToUnix(sysPath.isAbsolute(path) ? path : sysPath.join(cwd, path));
|
| 113 |
+
}
|
| 114 |
+
else {
|
| 115 |
+
return path;
|
| 116 |
+
}
|
| 117 |
+
};
|
| 118 |
+
const getAbsolutePath = (path, cwd) => {
|
| 119 |
+
if (sysPath.isAbsolute(path)) {
|
| 120 |
+
return path;
|
| 121 |
+
}
|
| 122 |
+
return sysPath.join(cwd, path);
|
| 123 |
+
};
|
| 124 |
+
const EMPTY_SET = Object.freeze(new Set());
|
| 125 |
+
/**
|
| 126 |
+
* Directory entry.
|
| 127 |
+
*/
|
| 128 |
+
class DirEntry {
|
| 129 |
+
constructor(dir, removeWatcher) {
|
| 130 |
+
this.path = dir;
|
| 131 |
+
this._removeWatcher = removeWatcher;
|
| 132 |
+
this.items = new Set();
|
| 133 |
+
}
|
| 134 |
+
add(item) {
|
| 135 |
+
const { items } = this;
|
| 136 |
+
if (!items)
|
| 137 |
+
return;
|
| 138 |
+
if (item !== ONE_DOT && item !== TWO_DOTS)
|
| 139 |
+
items.add(item);
|
| 140 |
+
}
|
| 141 |
+
async remove(item) {
|
| 142 |
+
const { items } = this;
|
| 143 |
+
if (!items)
|
| 144 |
+
return;
|
| 145 |
+
items.delete(item);
|
| 146 |
+
if (items.size > 0)
|
| 147 |
+
return;
|
| 148 |
+
const dir = this.path;
|
| 149 |
+
try {
|
| 150 |
+
await readdir(dir);
|
| 151 |
+
}
|
| 152 |
+
catch (err) {
|
| 153 |
+
if (this._removeWatcher) {
|
| 154 |
+
this._removeWatcher(sysPath.dirname(dir), sysPath.basename(dir));
|
| 155 |
+
}
|
| 156 |
+
}
|
| 157 |
+
}
|
| 158 |
+
has(item) {
|
| 159 |
+
const { items } = this;
|
| 160 |
+
if (!items)
|
| 161 |
+
return;
|
| 162 |
+
return items.has(item);
|
| 163 |
+
}
|
| 164 |
+
getChildren() {
|
| 165 |
+
const { items } = this;
|
| 166 |
+
if (!items)
|
| 167 |
+
return [];
|
| 168 |
+
return [...items.values()];
|
| 169 |
+
}
|
| 170 |
+
dispose() {
|
| 171 |
+
this.items.clear();
|
| 172 |
+
this.path = '';
|
| 173 |
+
this._removeWatcher = EMPTY_FN;
|
| 174 |
+
this.items = EMPTY_SET;
|
| 175 |
+
Object.freeze(this);
|
| 176 |
+
}
|
| 177 |
+
}
|
| 178 |
+
const STAT_METHOD_F = 'stat';
|
| 179 |
+
const STAT_METHOD_L = 'lstat';
|
| 180 |
+
export class WatchHelper {
|
| 181 |
+
constructor(path, follow, fsw) {
|
| 182 |
+
this.fsw = fsw;
|
| 183 |
+
const watchPath = path;
|
| 184 |
+
this.path = path = path.replace(REPLACER_RE, '');
|
| 185 |
+
this.watchPath = watchPath;
|
| 186 |
+
this.fullWatchPath = sysPath.resolve(watchPath);
|
| 187 |
+
this.dirParts = [];
|
| 188 |
+
this.dirParts.forEach((parts) => {
|
| 189 |
+
if (parts.length > 1)
|
| 190 |
+
parts.pop();
|
| 191 |
+
});
|
| 192 |
+
this.followSymlinks = follow;
|
| 193 |
+
this.statMethod = follow ? STAT_METHOD_F : STAT_METHOD_L;
|
| 194 |
+
}
|
| 195 |
+
entryPath(entry) {
|
| 196 |
+
return sysPath.join(this.watchPath, sysPath.relative(this.watchPath, entry.fullPath));
|
| 197 |
+
}
|
| 198 |
+
filterPath(entry) {
|
| 199 |
+
const { stats } = entry;
|
| 200 |
+
if (stats && stats.isSymbolicLink())
|
| 201 |
+
return this.filterDir(entry);
|
| 202 |
+
const resolvedPath = this.entryPath(entry);
|
| 203 |
+
// TODO: what if stats is undefined? remove !
|
| 204 |
+
return this.fsw._isntIgnored(resolvedPath, stats) && this.fsw._hasReadPermissions(stats);
|
| 205 |
+
}
|
| 206 |
+
filterDir(entry) {
|
| 207 |
+
return this.fsw._isntIgnored(this.entryPath(entry), entry.stats);
|
| 208 |
+
}
|
| 209 |
+
}
|
| 210 |
+
/**
|
| 211 |
+
* Watches files & directories for changes. Emitted events:
|
| 212 |
+
* `add`, `addDir`, `change`, `unlink`, `unlinkDir`, `all`, `error`
|
| 213 |
+
*
|
| 214 |
+
* new FSWatcher()
|
| 215 |
+
* .add(directories)
|
| 216 |
+
* .on('add', path => log('File', path, 'was added'))
|
| 217 |
+
*/
|
| 218 |
+
export class FSWatcher extends EventEmitter {
|
| 219 |
+
// Not indenting methods for history sake; for now.
|
| 220 |
+
constructor(_opts = {}) {
|
| 221 |
+
super();
|
| 222 |
+
this.closed = false;
|
| 223 |
+
this._closers = new Map();
|
| 224 |
+
this._ignoredPaths = new Set();
|
| 225 |
+
this._throttled = new Map();
|
| 226 |
+
this._streams = new Set();
|
| 227 |
+
this._symlinkPaths = new Map();
|
| 228 |
+
this._watched = new Map();
|
| 229 |
+
this._pendingWrites = new Map();
|
| 230 |
+
this._pendingUnlinks = new Map();
|
| 231 |
+
this._readyCount = 0;
|
| 232 |
+
this._readyEmitted = false;
|
| 233 |
+
const awf = _opts.awaitWriteFinish;
|
| 234 |
+
const DEF_AWF = { stabilityThreshold: 2000, pollInterval: 100 };
|
| 235 |
+
const opts = {
|
| 236 |
+
// Defaults
|
| 237 |
+
persistent: true,
|
| 238 |
+
ignoreInitial: false,
|
| 239 |
+
ignorePermissionErrors: false,
|
| 240 |
+
interval: 100,
|
| 241 |
+
binaryInterval: 300,
|
| 242 |
+
followSymlinks: true,
|
| 243 |
+
usePolling: false,
|
| 244 |
+
// useAsync: false,
|
| 245 |
+
atomic: true, // NOTE: overwritten later (depends on usePolling)
|
| 246 |
+
..._opts,
|
| 247 |
+
// Change format
|
| 248 |
+
ignored: _opts.ignored ? arrify(_opts.ignored) : arrify([]),
|
| 249 |
+
awaitWriteFinish: awf === true ? DEF_AWF : typeof awf === 'object' ? { ...DEF_AWF, ...awf } : false,
|
| 250 |
+
};
|
| 251 |
+
// Always default to polling on IBM i because fs.watch() is not available on IBM i.
|
| 252 |
+
if (isIBMi)
|
| 253 |
+
opts.usePolling = true;
|
| 254 |
+
// Editor atomic write normalization enabled by default with fs.watch
|
| 255 |
+
if (opts.atomic === undefined)
|
| 256 |
+
opts.atomic = !opts.usePolling;
|
| 257 |
+
// opts.atomic = typeof _opts.atomic === 'number' ? _opts.atomic : 100;
|
| 258 |
+
// Global override. Useful for developers, who need to force polling for all
|
| 259 |
+
// instances of chokidar, regardless of usage / dependency depth
|
| 260 |
+
const envPoll = process.env.CHOKIDAR_USEPOLLING;
|
| 261 |
+
if (envPoll !== undefined) {
|
| 262 |
+
const envLower = envPoll.toLowerCase();
|
| 263 |
+
if (envLower === 'false' || envLower === '0')
|
| 264 |
+
opts.usePolling = false;
|
| 265 |
+
else if (envLower === 'true' || envLower === '1')
|
| 266 |
+
opts.usePolling = true;
|
| 267 |
+
else
|
| 268 |
+
opts.usePolling = !!envLower;
|
| 269 |
+
}
|
| 270 |
+
const envInterval = process.env.CHOKIDAR_INTERVAL;
|
| 271 |
+
if (envInterval)
|
| 272 |
+
opts.interval = Number.parseInt(envInterval, 10);
|
| 273 |
+
// This is done to emit ready only once, but each 'add' will increase that?
|
| 274 |
+
let readyCalls = 0;
|
| 275 |
+
this._emitReady = () => {
|
| 276 |
+
readyCalls++;
|
| 277 |
+
if (readyCalls >= this._readyCount) {
|
| 278 |
+
this._emitReady = EMPTY_FN;
|
| 279 |
+
this._readyEmitted = true;
|
| 280 |
+
// use process.nextTick to allow time for listener to be bound
|
| 281 |
+
process.nextTick(() => this.emit(EV.READY));
|
| 282 |
+
}
|
| 283 |
+
};
|
| 284 |
+
this._emitRaw = (...args) => this.emit(EV.RAW, ...args);
|
| 285 |
+
this._boundRemove = this._remove.bind(this);
|
| 286 |
+
this.options = opts;
|
| 287 |
+
this._nodeFsHandler = new NodeFsHandler(this);
|
| 288 |
+
// You’re frozen when your heart’s not open.
|
| 289 |
+
Object.freeze(opts);
|
| 290 |
+
}
|
| 291 |
+
_addIgnoredPath(matcher) {
|
| 292 |
+
if (isMatcherObject(matcher)) {
|
| 293 |
+
// return early if we already have a deeply equal matcher object
|
| 294 |
+
for (const ignored of this._ignoredPaths) {
|
| 295 |
+
if (isMatcherObject(ignored) &&
|
| 296 |
+
ignored.path === matcher.path &&
|
| 297 |
+
ignored.recursive === matcher.recursive) {
|
| 298 |
+
return;
|
| 299 |
+
}
|
| 300 |
+
}
|
| 301 |
+
}
|
| 302 |
+
this._ignoredPaths.add(matcher);
|
| 303 |
+
}
|
| 304 |
+
_removeIgnoredPath(matcher) {
|
| 305 |
+
this._ignoredPaths.delete(matcher);
|
| 306 |
+
// now find any matcher objects with the matcher as path
|
| 307 |
+
if (typeof matcher === 'string') {
|
| 308 |
+
for (const ignored of this._ignoredPaths) {
|
| 309 |
+
// TODO (43081j): make this more efficient.
|
| 310 |
+
// probably just make a `this._ignoredDirectories` or some
|
| 311 |
+
// such thing.
|
| 312 |
+
if (isMatcherObject(ignored) && ignored.path === matcher) {
|
| 313 |
+
this._ignoredPaths.delete(ignored);
|
| 314 |
+
}
|
| 315 |
+
}
|
| 316 |
+
}
|
| 317 |
+
}
|
| 318 |
+
// Public methods
|
| 319 |
+
/**
|
| 320 |
+
* Adds paths to be watched on an existing FSWatcher instance.
|
| 321 |
+
* @param paths_ file or file list. Other arguments are unused
|
| 322 |
+
*/
|
| 323 |
+
add(paths_, _origAdd, _internal) {
|
| 324 |
+
const { cwd } = this.options;
|
| 325 |
+
this.closed = false;
|
| 326 |
+
this._closePromise = undefined;
|
| 327 |
+
let paths = unifyPaths(paths_);
|
| 328 |
+
if (cwd) {
|
| 329 |
+
paths = paths.map((path) => {
|
| 330 |
+
const absPath = getAbsolutePath(path, cwd);
|
| 331 |
+
// Check `path` instead of `absPath` because the cwd portion can't be a glob
|
| 332 |
+
return absPath;
|
| 333 |
+
});
|
| 334 |
+
}
|
| 335 |
+
paths.forEach((path) => {
|
| 336 |
+
this._removeIgnoredPath(path);
|
| 337 |
+
});
|
| 338 |
+
this._userIgnored = undefined;
|
| 339 |
+
if (!this._readyCount)
|
| 340 |
+
this._readyCount = 0;
|
| 341 |
+
this._readyCount += paths.length;
|
| 342 |
+
Promise.all(paths.map(async (path) => {
|
| 343 |
+
const res = await this._nodeFsHandler._addToNodeFs(path, !_internal, undefined, 0, _origAdd);
|
| 344 |
+
if (res)
|
| 345 |
+
this._emitReady();
|
| 346 |
+
return res;
|
| 347 |
+
})).then((results) => {
|
| 348 |
+
if (this.closed)
|
| 349 |
+
return;
|
| 350 |
+
results.forEach((item) => {
|
| 351 |
+
if (item)
|
| 352 |
+
this.add(sysPath.dirname(item), sysPath.basename(_origAdd || item));
|
| 353 |
+
});
|
| 354 |
+
});
|
| 355 |
+
return this;
|
| 356 |
+
}
|
| 357 |
+
/**
|
| 358 |
+
* Close watchers or start ignoring events from specified paths.
|
| 359 |
+
*/
|
| 360 |
+
unwatch(paths_) {
|
| 361 |
+
if (this.closed)
|
| 362 |
+
return this;
|
| 363 |
+
const paths = unifyPaths(paths_);
|
| 364 |
+
const { cwd } = this.options;
|
| 365 |
+
paths.forEach((path) => {
|
| 366 |
+
// convert to absolute path unless relative path already matches
|
| 367 |
+
if (!sysPath.isAbsolute(path) && !this._closers.has(path)) {
|
| 368 |
+
if (cwd)
|
| 369 |
+
path = sysPath.join(cwd, path);
|
| 370 |
+
path = sysPath.resolve(path);
|
| 371 |
+
}
|
| 372 |
+
this._closePath(path);
|
| 373 |
+
this._addIgnoredPath(path);
|
| 374 |
+
if (this._watched.has(path)) {
|
| 375 |
+
this._addIgnoredPath({
|
| 376 |
+
path,
|
| 377 |
+
recursive: true,
|
| 378 |
+
});
|
| 379 |
+
}
|
| 380 |
+
// reset the cached userIgnored anymatch fn
|
| 381 |
+
// to make ignoredPaths changes effective
|
| 382 |
+
this._userIgnored = undefined;
|
| 383 |
+
});
|
| 384 |
+
return this;
|
| 385 |
+
}
|
| 386 |
+
/**
|
| 387 |
+
* Close watchers and remove all listeners from watched paths.
|
| 388 |
+
*/
|
| 389 |
+
close() {
|
| 390 |
+
if (this._closePromise) {
|
| 391 |
+
return this._closePromise;
|
| 392 |
+
}
|
| 393 |
+
this.closed = true;
|
| 394 |
+
// Memory management.
|
| 395 |
+
this.removeAllListeners();
|
| 396 |
+
const closers = [];
|
| 397 |
+
this._closers.forEach((closerList) => closerList.forEach((closer) => {
|
| 398 |
+
const promise = closer();
|
| 399 |
+
if (promise instanceof Promise)
|
| 400 |
+
closers.push(promise);
|
| 401 |
+
}));
|
| 402 |
+
this._streams.forEach((stream) => stream.destroy());
|
| 403 |
+
this._userIgnored = undefined;
|
| 404 |
+
this._readyCount = 0;
|
| 405 |
+
this._readyEmitted = false;
|
| 406 |
+
this._watched.forEach((dirent) => dirent.dispose());
|
| 407 |
+
this._closers.clear();
|
| 408 |
+
this._watched.clear();
|
| 409 |
+
this._streams.clear();
|
| 410 |
+
this._symlinkPaths.clear();
|
| 411 |
+
this._throttled.clear();
|
| 412 |
+
this._closePromise = closers.length
|
| 413 |
+
? Promise.all(closers).then(() => undefined)
|
| 414 |
+
: Promise.resolve();
|
| 415 |
+
return this._closePromise;
|
| 416 |
+
}
|
| 417 |
+
/**
|
| 418 |
+
* Expose list of watched paths
|
| 419 |
+
* @returns for chaining
|
| 420 |
+
*/
|
| 421 |
+
getWatched() {
|
| 422 |
+
const watchList = {};
|
| 423 |
+
this._watched.forEach((entry, dir) => {
|
| 424 |
+
const key = this.options.cwd ? sysPath.relative(this.options.cwd, dir) : dir;
|
| 425 |
+
const index = key || ONE_DOT;
|
| 426 |
+
watchList[index] = entry.getChildren().sort();
|
| 427 |
+
});
|
| 428 |
+
return watchList;
|
| 429 |
+
}
|
| 430 |
+
emitWithAll(event, args) {
|
| 431 |
+
this.emit(event, ...args);
|
| 432 |
+
if (event !== EV.ERROR)
|
| 433 |
+
this.emit(EV.ALL, event, ...args);
|
| 434 |
+
}
|
| 435 |
+
// Common helpers
|
| 436 |
+
// --------------
|
| 437 |
+
/**
|
| 438 |
+
* Normalize and emit events.
|
| 439 |
+
* Calling _emit DOES NOT MEAN emit() would be called!
|
| 440 |
+
* @param event Type of event
|
| 441 |
+
* @param path File or directory path
|
| 442 |
+
* @param stats arguments to be passed with event
|
| 443 |
+
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
| 444 |
+
*/
|
| 445 |
+
async _emit(event, path, stats) {
|
| 446 |
+
if (this.closed)
|
| 447 |
+
return;
|
| 448 |
+
const opts = this.options;
|
| 449 |
+
if (isWindows)
|
| 450 |
+
path = sysPath.normalize(path);
|
| 451 |
+
if (opts.cwd)
|
| 452 |
+
path = sysPath.relative(opts.cwd, path);
|
| 453 |
+
const args = [path];
|
| 454 |
+
if (stats != null)
|
| 455 |
+
args.push(stats);
|
| 456 |
+
const awf = opts.awaitWriteFinish;
|
| 457 |
+
let pw;
|
| 458 |
+
if (awf && (pw = this._pendingWrites.get(path))) {
|
| 459 |
+
pw.lastChange = new Date();
|
| 460 |
+
return this;
|
| 461 |
+
}
|
| 462 |
+
if (opts.atomic) {
|
| 463 |
+
if (event === EV.UNLINK) {
|
| 464 |
+
this._pendingUnlinks.set(path, [event, ...args]);
|
| 465 |
+
setTimeout(() => {
|
| 466 |
+
this._pendingUnlinks.forEach((entry, path) => {
|
| 467 |
+
this.emit(...entry);
|
| 468 |
+
this.emit(EV.ALL, ...entry);
|
| 469 |
+
this._pendingUnlinks.delete(path);
|
| 470 |
+
});
|
| 471 |
+
}, typeof opts.atomic === 'number' ? opts.atomic : 100);
|
| 472 |
+
return this;
|
| 473 |
+
}
|
| 474 |
+
if (event === EV.ADD && this._pendingUnlinks.has(path)) {
|
| 475 |
+
event = EV.CHANGE;
|
| 476 |
+
this._pendingUnlinks.delete(path);
|
| 477 |
+
}
|
| 478 |
+
}
|
| 479 |
+
if (awf && (event === EV.ADD || event === EV.CHANGE) && this._readyEmitted) {
|
| 480 |
+
const awfEmit = (err, stats) => {
|
| 481 |
+
if (err) {
|
| 482 |
+
event = EV.ERROR;
|
| 483 |
+
args[0] = err;
|
| 484 |
+
this.emitWithAll(event, args);
|
| 485 |
+
}
|
| 486 |
+
else if (stats) {
|
| 487 |
+
// if stats doesn't exist the file must have been deleted
|
| 488 |
+
if (args.length > 1) {
|
| 489 |
+
args[1] = stats;
|
| 490 |
+
}
|
| 491 |
+
else {
|
| 492 |
+
args.push(stats);
|
| 493 |
+
}
|
| 494 |
+
this.emitWithAll(event, args);
|
| 495 |
+
}
|
| 496 |
+
};
|
| 497 |
+
this._awaitWriteFinish(path, awf.stabilityThreshold, event, awfEmit);
|
| 498 |
+
return this;
|
| 499 |
+
}
|
| 500 |
+
if (event === EV.CHANGE) {
|
| 501 |
+
const isThrottled = !this._throttle(EV.CHANGE, path, 50);
|
| 502 |
+
if (isThrottled)
|
| 503 |
+
return this;
|
| 504 |
+
}
|
| 505 |
+
if (opts.alwaysStat &&
|
| 506 |
+
stats === undefined &&
|
| 507 |
+
(event === EV.ADD || event === EV.ADD_DIR || event === EV.CHANGE)) {
|
| 508 |
+
const fullPath = opts.cwd ? sysPath.join(opts.cwd, path) : path;
|
| 509 |
+
let stats;
|
| 510 |
+
try {
|
| 511 |
+
stats = await stat(fullPath);
|
| 512 |
+
}
|
| 513 |
+
catch (err) {
|
| 514 |
+
// do nothing
|
| 515 |
+
}
|
| 516 |
+
// Suppress event when fs_stat fails, to avoid sending undefined 'stat'
|
| 517 |
+
if (!stats || this.closed)
|
| 518 |
+
return;
|
| 519 |
+
args.push(stats);
|
| 520 |
+
}
|
| 521 |
+
this.emitWithAll(event, args);
|
| 522 |
+
return this;
|
| 523 |
+
}
|
| 524 |
+
/**
|
| 525 |
+
* Common handler for errors
|
| 526 |
+
* @returns The error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
| 527 |
+
*/
|
| 528 |
+
_handleError(error) {
|
| 529 |
+
const code = error && error.code;
|
| 530 |
+
if (error &&
|
| 531 |
+
code !== 'ENOENT' &&
|
| 532 |
+
code !== 'ENOTDIR' &&
|
| 533 |
+
(!this.options.ignorePermissionErrors || (code !== 'EPERM' && code !== 'EACCES'))) {
|
| 534 |
+
this.emit(EV.ERROR, error);
|
| 535 |
+
}
|
| 536 |
+
return error || this.closed;
|
| 537 |
+
}
|
| 538 |
+
/**
|
| 539 |
+
* Helper utility for throttling
|
| 540 |
+
* @param actionType type being throttled
|
| 541 |
+
* @param path being acted upon
|
| 542 |
+
* @param timeout duration of time to suppress duplicate actions
|
| 543 |
+
* @returns tracking object or false if action should be suppressed
|
| 544 |
+
*/
|
| 545 |
+
_throttle(actionType, path, timeout) {
|
| 546 |
+
if (!this._throttled.has(actionType)) {
|
| 547 |
+
this._throttled.set(actionType, new Map());
|
| 548 |
+
}
|
| 549 |
+
const action = this._throttled.get(actionType);
|
| 550 |
+
if (!action)
|
| 551 |
+
throw new Error('invalid throttle');
|
| 552 |
+
const actionPath = action.get(path);
|
| 553 |
+
if (actionPath) {
|
| 554 |
+
actionPath.count++;
|
| 555 |
+
return false;
|
| 556 |
+
}
|
| 557 |
+
// eslint-disable-next-line prefer-const
|
| 558 |
+
let timeoutObject;
|
| 559 |
+
const clear = () => {
|
| 560 |
+
const item = action.get(path);
|
| 561 |
+
const count = item ? item.count : 0;
|
| 562 |
+
action.delete(path);
|
| 563 |
+
clearTimeout(timeoutObject);
|
| 564 |
+
if (item)
|
| 565 |
+
clearTimeout(item.timeoutObject);
|
| 566 |
+
return count;
|
| 567 |
+
};
|
| 568 |
+
timeoutObject = setTimeout(clear, timeout);
|
| 569 |
+
const thr = { timeoutObject, clear, count: 0 };
|
| 570 |
+
action.set(path, thr);
|
| 571 |
+
return thr;
|
| 572 |
+
}
|
| 573 |
+
_incrReadyCount() {
|
| 574 |
+
return this._readyCount++;
|
| 575 |
+
}
|
| 576 |
+
/**
|
| 577 |
+
* Awaits write operation to finish.
|
| 578 |
+
* Polls a newly created file for size variations. When files size does not change for 'threshold' milliseconds calls callback.
|
| 579 |
+
* @param path being acted upon
|
| 580 |
+
* @param threshold Time in milliseconds a file size must be fixed before acknowledging write OP is finished
|
| 581 |
+
* @param event
|
| 582 |
+
* @param awfEmit Callback to be called when ready for event to be emitted.
|
| 583 |
+
*/
|
| 584 |
+
_awaitWriteFinish(path, threshold, event, awfEmit) {
|
| 585 |
+
const awf = this.options.awaitWriteFinish;
|
| 586 |
+
if (typeof awf !== 'object')
|
| 587 |
+
return;
|
| 588 |
+
const pollInterval = awf.pollInterval;
|
| 589 |
+
let timeoutHandler;
|
| 590 |
+
let fullPath = path;
|
| 591 |
+
if (this.options.cwd && !sysPath.isAbsolute(path)) {
|
| 592 |
+
fullPath = sysPath.join(this.options.cwd, path);
|
| 593 |
+
}
|
| 594 |
+
const now = new Date();
|
| 595 |
+
const writes = this._pendingWrites;
|
| 596 |
+
function awaitWriteFinishFn(prevStat) {
|
| 597 |
+
statcb(fullPath, (err, curStat) => {
|
| 598 |
+
if (err || !writes.has(path)) {
|
| 599 |
+
if (err && err.code !== 'ENOENT')
|
| 600 |
+
awfEmit(err);
|
| 601 |
+
return;
|
| 602 |
+
}
|
| 603 |
+
const now = Number(new Date());
|
| 604 |
+
if (prevStat && curStat.size !== prevStat.size) {
|
| 605 |
+
writes.get(path).lastChange = now;
|
| 606 |
+
}
|
| 607 |
+
const pw = writes.get(path);
|
| 608 |
+
const df = now - pw.lastChange;
|
| 609 |
+
if (df >= threshold) {
|
| 610 |
+
writes.delete(path);
|
| 611 |
+
awfEmit(undefined, curStat);
|
| 612 |
+
}
|
| 613 |
+
else {
|
| 614 |
+
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
| 615 |
+
}
|
| 616 |
+
});
|
| 617 |
+
}
|
| 618 |
+
if (!writes.has(path)) {
|
| 619 |
+
writes.set(path, {
|
| 620 |
+
lastChange: now,
|
| 621 |
+
cancelWait: () => {
|
| 622 |
+
writes.delete(path);
|
| 623 |
+
clearTimeout(timeoutHandler);
|
| 624 |
+
return event;
|
| 625 |
+
},
|
| 626 |
+
});
|
| 627 |
+
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval);
|
| 628 |
+
}
|
| 629 |
+
}
|
| 630 |
+
/**
|
| 631 |
+
* Determines whether user has asked to ignore this path.
|
| 632 |
+
*/
|
| 633 |
+
_isIgnored(path, stats) {
|
| 634 |
+
if (this.options.atomic && DOT_RE.test(path))
|
| 635 |
+
return true;
|
| 636 |
+
if (!this._userIgnored) {
|
| 637 |
+
const { cwd } = this.options;
|
| 638 |
+
const ign = this.options.ignored;
|
| 639 |
+
const ignored = (ign || []).map(normalizeIgnored(cwd));
|
| 640 |
+
const ignoredPaths = [...this._ignoredPaths];
|
| 641 |
+
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
| 642 |
+
this._userIgnored = anymatch(list, undefined);
|
| 643 |
+
}
|
| 644 |
+
return this._userIgnored(path, stats);
|
| 645 |
+
}
|
| 646 |
+
_isntIgnored(path, stat) {
|
| 647 |
+
return !this._isIgnored(path, stat);
|
| 648 |
+
}
|
| 649 |
+
/**
|
| 650 |
+
* Provides a set of common helpers and properties relating to symlink handling.
|
| 651 |
+
* @param path file or directory pattern being watched
|
| 652 |
+
*/
|
| 653 |
+
_getWatchHelpers(path) {
|
| 654 |
+
return new WatchHelper(path, this.options.followSymlinks, this);
|
| 655 |
+
}
|
| 656 |
+
// Directory helpers
|
| 657 |
+
// -----------------
|
| 658 |
+
/**
|
| 659 |
+
* Provides directory tracking objects
|
| 660 |
+
* @param directory path of the directory
|
| 661 |
+
*/
|
| 662 |
+
_getWatchedDir(directory) {
|
| 663 |
+
const dir = sysPath.resolve(directory);
|
| 664 |
+
if (!this._watched.has(dir))
|
| 665 |
+
this._watched.set(dir, new DirEntry(dir, this._boundRemove));
|
| 666 |
+
return this._watched.get(dir);
|
| 667 |
+
}
|
| 668 |
+
// File helpers
|
| 669 |
+
// ------------
|
| 670 |
+
/**
|
| 671 |
+
* Check for read permissions: https://stackoverflow.com/a/11781404/1358405
|
| 672 |
+
*/
|
| 673 |
+
_hasReadPermissions(stats) {
|
| 674 |
+
if (this.options.ignorePermissionErrors)
|
| 675 |
+
return true;
|
| 676 |
+
return Boolean(Number(stats.mode) & 0o400);
|
| 677 |
+
}
|
| 678 |
+
/**
|
| 679 |
+
* Handles emitting unlink events for
|
| 680 |
+
* files and directories, and via recursion, for
|
| 681 |
+
* files and directories within directories that are unlinked
|
| 682 |
+
* @param directory within which the following item is located
|
| 683 |
+
* @param item base path of item/directory
|
| 684 |
+
*/
|
| 685 |
+
_remove(directory, item, isDirectory) {
|
| 686 |
+
// if what is being deleted is a directory, get that directory's paths
|
| 687 |
+
// for recursive deleting and cleaning of watched object
|
| 688 |
+
// if it is not a directory, nestedDirectoryChildren will be empty array
|
| 689 |
+
const path = sysPath.join(directory, item);
|
| 690 |
+
const fullPath = sysPath.resolve(path);
|
| 691 |
+
isDirectory =
|
| 692 |
+
isDirectory != null ? isDirectory : this._watched.has(path) || this._watched.has(fullPath);
|
| 693 |
+
// prevent duplicate handling in case of arriving here nearly simultaneously
|
| 694 |
+
// via multiple paths (such as _handleFile and _handleDir)
|
| 695 |
+
if (!this._throttle('remove', path, 100))
|
| 696 |
+
return;
|
| 697 |
+
// if the only watched file is removed, watch for its return
|
| 698 |
+
if (!isDirectory && this._watched.size === 1) {
|
| 699 |
+
this.add(directory, item, true);
|
| 700 |
+
}
|
| 701 |
+
// This will create a new entry in the watched object in either case
|
| 702 |
+
// so we got to do the directory check beforehand
|
| 703 |
+
const wp = this._getWatchedDir(path);
|
| 704 |
+
const nestedDirectoryChildren = wp.getChildren();
|
| 705 |
+
// Recursively remove children directories / files.
|
| 706 |
+
nestedDirectoryChildren.forEach((nested) => this._remove(path, nested));
|
| 707 |
+
// Check if item was on the watched list and remove it
|
| 708 |
+
const parent = this._getWatchedDir(directory);
|
| 709 |
+
const wasTracked = parent.has(item);
|
| 710 |
+
parent.remove(item);
|
| 711 |
+
// Fixes issue #1042 -> Relative paths were detected and added as symlinks
|
| 712 |
+
// (https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L612),
|
| 713 |
+
// but never removed from the map in case the path was deleted.
|
| 714 |
+
// This leads to an incorrect state if the path was recreated:
|
| 715 |
+
// https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L553
|
| 716 |
+
if (this._symlinkPaths.has(fullPath)) {
|
| 717 |
+
this._symlinkPaths.delete(fullPath);
|
| 718 |
+
}
|
| 719 |
+
// If we wait for this file to be fully written, cancel the wait.
|
| 720 |
+
let relPath = path;
|
| 721 |
+
if (this.options.cwd)
|
| 722 |
+
relPath = sysPath.relative(this.options.cwd, path);
|
| 723 |
+
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
| 724 |
+
const event = this._pendingWrites.get(relPath).cancelWait();
|
| 725 |
+
if (event === EV.ADD)
|
| 726 |
+
return;
|
| 727 |
+
}
|
| 728 |
+
// The Entry will either be a directory that just got removed
|
| 729 |
+
// or a bogus entry to a file, in either case we have to remove it
|
| 730 |
+
this._watched.delete(path);
|
| 731 |
+
this._watched.delete(fullPath);
|
| 732 |
+
const eventName = isDirectory ? EV.UNLINK_DIR : EV.UNLINK;
|
| 733 |
+
if (wasTracked && !this._isIgnored(path))
|
| 734 |
+
this._emit(eventName, path);
|
| 735 |
+
// Avoid conflicts if we later create another file with the same name
|
| 736 |
+
this._closePath(path);
|
| 737 |
+
}
|
| 738 |
+
/**
|
| 739 |
+
* Closes all watchers for a path
|
| 740 |
+
*/
|
| 741 |
+
_closePath(path) {
|
| 742 |
+
this._closeFile(path);
|
| 743 |
+
const dir = sysPath.dirname(path);
|
| 744 |
+
this._getWatchedDir(dir).remove(sysPath.basename(path));
|
| 745 |
+
}
|
| 746 |
+
/**
|
| 747 |
+
* Closes only file-specific watchers
|
| 748 |
+
*/
|
| 749 |
+
_closeFile(path) {
|
| 750 |
+
const closers = this._closers.get(path);
|
| 751 |
+
if (!closers)
|
| 752 |
+
return;
|
| 753 |
+
closers.forEach((closer) => closer());
|
| 754 |
+
this._closers.delete(path);
|
| 755 |
+
}
|
| 756 |
+
_addPathCloser(path, closer) {
|
| 757 |
+
if (!closer)
|
| 758 |
+
return;
|
| 759 |
+
let list = this._closers.get(path);
|
| 760 |
+
if (!list) {
|
| 761 |
+
list = [];
|
| 762 |
+
this._closers.set(path, list);
|
| 763 |
+
}
|
| 764 |
+
list.push(closer);
|
| 765 |
+
}
|
| 766 |
+
_readdirp(root, opts) {
|
| 767 |
+
if (this.closed)
|
| 768 |
+
return;
|
| 769 |
+
const options = { type: EV.ALL, alwaysStat: true, lstat: true, ...opts, depth: 0 };
|
| 770 |
+
let stream = readdirp(root, options);
|
| 771 |
+
this._streams.add(stream);
|
| 772 |
+
stream.once(STR_CLOSE, () => {
|
| 773 |
+
stream = undefined;
|
| 774 |
+
});
|
| 775 |
+
stream.once(STR_END, () => {
|
| 776 |
+
if (stream) {
|
| 777 |
+
this._streams.delete(stream);
|
| 778 |
+
stream = undefined;
|
| 779 |
+
}
|
| 780 |
+
});
|
| 781 |
+
return stream;
|
| 782 |
+
}
|
| 783 |
+
}
|
| 784 |
+
/**
|
| 785 |
+
* Instantiates watcher with paths to be tracked.
|
| 786 |
+
* @param paths file / directory paths
|
| 787 |
+
* @param options opts, such as `atomic`, `awaitWriteFinish`, `ignored`, and others
|
| 788 |
+
* @returns an instance of FSWatcher for chaining.
|
| 789 |
+
* @example
|
| 790 |
+
* const watcher = watch('.').on('all', (event, path) => { console.log(event, path); });
|
| 791 |
+
* watch('.', { atomic: true, awaitWriteFinish: true, ignored: (f, stats) => stats?.isFile() && !f.endsWith('.js') })
|
| 792 |
+
*/
|
| 793 |
+
export function watch(paths, options = {}) {
|
| 794 |
+
const watcher = new FSWatcher(options);
|
| 795 |
+
watcher.add(paths);
|
| 796 |
+
return watcher;
|
| 797 |
+
}
|
| 798 |
+
export default { watch, FSWatcher };
|
backend/node_modules/chokidar/esm/package.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{ "type": "module", "sideEffects": false }
|
backend/node_modules/dotenv/lib/cli-options.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const re = /^dotenv_config_(encoding|path|quiet|debug|override|DOTENV_KEY)=(.+)$/
|
| 2 |
+
|
| 3 |
+
module.exports = function optionMatcher (args) {
|
| 4 |
+
const options = args.reduce(function (acc, cur) {
|
| 5 |
+
const matches = cur.match(re)
|
| 6 |
+
if (matches) {
|
| 7 |
+
acc[matches[1]] = matches[2]
|
| 8 |
+
}
|
| 9 |
+
return acc
|
| 10 |
+
}, {})
|
| 11 |
+
|
| 12 |
+
if (!('quiet' in options)) {
|
| 13 |
+
options.quiet = 'true'
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
return options
|
| 17 |
+
}
|
backend/node_modules/dotenv/lib/env-options.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// ../config.js accepts options via environment variables
|
| 2 |
+
const options = {}
|
| 3 |
+
|
| 4 |
+
if (process.env.DOTENV_CONFIG_ENCODING != null) {
|
| 5 |
+
options.encoding = process.env.DOTENV_CONFIG_ENCODING
|
| 6 |
+
}
|
| 7 |
+
|
| 8 |
+
if (process.env.DOTENV_CONFIG_PATH != null) {
|
| 9 |
+
options.path = process.env.DOTENV_CONFIG_PATH
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
if (process.env.DOTENV_CONFIG_QUIET != null) {
|
| 13 |
+
options.quiet = process.env.DOTENV_CONFIG_QUIET
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
if (process.env.DOTENV_CONFIG_DEBUG != null) {
|
| 17 |
+
options.debug = process.env.DOTENV_CONFIG_DEBUG
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
if (process.env.DOTENV_CONFIG_OVERRIDE != null) {
|
| 21 |
+
options.override = process.env.DOTENV_CONFIG_OVERRIDE
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
if (process.env.DOTENV_CONFIG_DOTENV_KEY != null) {
|
| 25 |
+
options.DOTENV_KEY = process.env.DOTENV_CONFIG_DOTENV_KEY
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
module.exports = options
|
backend/node_modules/dotenv/lib/main.d.ts
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// TypeScript Version: 3.0
|
| 2 |
+
/// <reference types="node" />
|
| 3 |
+
import type { URL } from 'url';
|
| 4 |
+
|
| 5 |
+
export interface DotenvParseOutput {
|
| 6 |
+
[name: string]: string;
|
| 7 |
+
}
|
| 8 |
+
|
| 9 |
+
/**
|
| 10 |
+
* Parses a string or buffer in the .env file format into an object.
|
| 11 |
+
*
|
| 12 |
+
* See https://dotenvx.com/docs
|
| 13 |
+
*
|
| 14 |
+
* @param src - contents to be parsed. example: `'DB_HOST=localhost'`
|
| 15 |
+
* @returns an object with keys and values based on `src`. example: `{ DB_HOST : 'localhost' }`
|
| 16 |
+
*/
|
| 17 |
+
export function parse<T extends DotenvParseOutput = DotenvParseOutput>(
|
| 18 |
+
src: string | Buffer
|
| 19 |
+
): T;
|
| 20 |
+
|
| 21 |
+
export interface DotenvConfigOptions {
|
| 22 |
+
/**
|
| 23 |
+
* Default: `path.resolve(process.cwd(), '.env')`
|
| 24 |
+
*
|
| 25 |
+
* Specify a custom path if your file containing environment variables is located elsewhere.
|
| 26 |
+
* Can also be an array of strings, specifying multiple paths.
|
| 27 |
+
*
|
| 28 |
+
* example: `require('dotenv').config({ path: '/custom/path/to/.env' })`
|
| 29 |
+
* example: `require('dotenv').config({ path: ['/path/to/first.env', '/path/to/second.env'] })`
|
| 30 |
+
*/
|
| 31 |
+
path?: string | string[] | URL;
|
| 32 |
+
|
| 33 |
+
/**
|
| 34 |
+
* Default: `utf8`
|
| 35 |
+
*
|
| 36 |
+
* Specify the encoding of your file containing environment variables.
|
| 37 |
+
*
|
| 38 |
+
* example: `require('dotenv').config({ encoding: 'latin1' })`
|
| 39 |
+
*/
|
| 40 |
+
encoding?: string;
|
| 41 |
+
|
| 42 |
+
/**
|
| 43 |
+
* Default: `false`
|
| 44 |
+
*
|
| 45 |
+
* Suppress all output (except errors).
|
| 46 |
+
*
|
| 47 |
+
* example: `require('dotenv').config({ quiet: true })`
|
| 48 |
+
*/
|
| 49 |
+
quiet?: boolean;
|
| 50 |
+
|
| 51 |
+
/**
|
| 52 |
+
* Default: `false`
|
| 53 |
+
*
|
| 54 |
+
* Turn on logging to help debug why certain keys or values are not being set as you expect.
|
| 55 |
+
*
|
| 56 |
+
* example: `require('dotenv').config({ debug: process.env.DEBUG })`
|
| 57 |
+
*/
|
| 58 |
+
debug?: boolean;
|
| 59 |
+
|
| 60 |
+
/**
|
| 61 |
+
* Default: `false`
|
| 62 |
+
*
|
| 63 |
+
* Override any environment variables that have already been set on your machine with values from your .env file.
|
| 64 |
+
*
|
| 65 |
+
* example: `require('dotenv').config({ override: true })`
|
| 66 |
+
*/
|
| 67 |
+
override?: boolean;
|
| 68 |
+
|
| 69 |
+
/**
|
| 70 |
+
* Default: `process.env`
|
| 71 |
+
*
|
| 72 |
+
* Specify an object to write your secrets to. Defaults to process.env environment variables.
|
| 73 |
+
*
|
| 74 |
+
* example: `const processEnv = {}; require('dotenv').config({ processEnv: processEnv })`
|
| 75 |
+
*/
|
| 76 |
+
processEnv?: DotenvPopulateInput;
|
| 77 |
+
|
| 78 |
+
/**
|
| 79 |
+
* Default: `undefined`
|
| 80 |
+
*
|
| 81 |
+
* Pass the DOTENV_KEY directly to config options. Defaults to looking for process.env.DOTENV_KEY environment variable. Note this only applies to decrypting .env.vault files. If passed as null or undefined, or not passed at all, dotenv falls back to its traditional job of parsing a .env file.
|
| 82 |
+
*
|
| 83 |
+
* example: `require('dotenv').config({ DOTENV_KEY: 'dotenv://:key_1234…@dotenvx.com/vault/.env.vault?environment=production' })`
|
| 84 |
+
*/
|
| 85 |
+
DOTENV_KEY?: string;
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
export interface DotenvConfigOutput {
|
| 89 |
+
error?: Error;
|
| 90 |
+
parsed?: DotenvParseOutput;
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
export interface DotenvPopulateOptions {
|
| 94 |
+
/**
|
| 95 |
+
* Default: `false`
|
| 96 |
+
*
|
| 97 |
+
* Turn on logging to help debug why certain keys or values are not being set as you expect.
|
| 98 |
+
*
|
| 99 |
+
* example: `require('dotenv').config({ debug: process.env.DEBUG })`
|
| 100 |
+
*/
|
| 101 |
+
debug?: boolean;
|
| 102 |
+
|
| 103 |
+
/**
|
| 104 |
+
* Default: `false`
|
| 105 |
+
*
|
| 106 |
+
* Override any environment variables that have already been set on your machine with values from your .env file.
|
| 107 |
+
*
|
| 108 |
+
* example: `require('dotenv').config({ override: true })`
|
| 109 |
+
*/
|
| 110 |
+
override?: boolean;
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
export interface DotenvPopulateInput {
|
| 114 |
+
[name: string]: string;
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
/**
|
| 118 |
+
* Loads `.env` file contents into process.env by default. If `DOTENV_KEY` is present, it smartly attempts to load encrypted `.env.vault` file contents into process.env.
|
| 119 |
+
*
|
| 120 |
+
* See https://dotenvx.com/docs
|
| 121 |
+
*
|
| 122 |
+
* @param options - additional options. example: `{ path: './custom/path', encoding: 'latin1', quiet: false, debug: true, override: false }`
|
| 123 |
+
* @returns an object with a `parsed` key if successful or `error` key if an error occurred. example: { parsed: { KEY: 'value' } }
|
| 124 |
+
*
|
| 125 |
+
*/
|
| 126 |
+
export function config(options?: DotenvConfigOptions): DotenvConfigOutput;
|
| 127 |
+
|
| 128 |
+
/**
|
| 129 |
+
* Loads `.env` file contents into process.env.
|
| 130 |
+
*
|
| 131 |
+
* See https://dotenvx.com/docs
|
| 132 |
+
*
|
| 133 |
+
* @param options - additional options. example: `{ path: './custom/path', encoding: 'latin1', quiet: false, debug: true, override: false }`
|
| 134 |
+
* @returns an object with a `parsed` key if successful or `error` key if an error occurred. example: { parsed: { KEY: 'value' } }
|
| 135 |
+
*
|
| 136 |
+
*/
|
| 137 |
+
export function configDotenv(options?: DotenvConfigOptions): DotenvConfigOutput;
|
| 138 |
+
|
| 139 |
+
/**
|
| 140 |
+
* Loads `source` json contents into `target` like process.env.
|
| 141 |
+
*
|
| 142 |
+
* See https://dotenvx.com/docs
|
| 143 |
+
*
|
| 144 |
+
* @param processEnv - the target JSON object. in most cases use process.env but you can also pass your own JSON object
|
| 145 |
+
* @param parsed - the source JSON object
|
| 146 |
+
* @param options - additional options. example: `{ quiet: false, debug: true, override: false }`
|
| 147 |
+
* @returns {void}
|
| 148 |
+
*
|
| 149 |
+
*/
|
| 150 |
+
export function populate(processEnv: DotenvPopulateInput, parsed: DotenvPopulateInput, options?: DotenvConfigOptions): void;
|
| 151 |
+
|
| 152 |
+
/**
|
| 153 |
+
* Decrypt ciphertext
|
| 154 |
+
*
|
| 155 |
+
* See https://dotenvx.com/docs
|
| 156 |
+
*
|
| 157 |
+
* @param encrypted - the encrypted ciphertext string
|
| 158 |
+
* @param keyStr - the decryption key string
|
| 159 |
+
* @returns {string}
|
| 160 |
+
*
|
| 161 |
+
*/
|
| 162 |
+
export function decrypt(encrypted: string, keyStr: string): string;
|
backend/node_modules/dotenv/lib/main.js
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const fs = require('fs')
|
| 2 |
+
const path = require('path')
|
| 3 |
+
const os = require('os')
|
| 4 |
+
const crypto = require('crypto')
|
| 5 |
+
const packageJson = require('../package.json')
|
| 6 |
+
|
| 7 |
+
const version = packageJson.version
|
| 8 |
+
|
| 9 |
+
const LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg
|
| 10 |
+
|
| 11 |
+
// Parse src into an Object
|
| 12 |
+
function parse (src) {
|
| 13 |
+
const obj = {}
|
| 14 |
+
|
| 15 |
+
// Convert buffer to string
|
| 16 |
+
let lines = src.toString()
|
| 17 |
+
|
| 18 |
+
// Convert line breaks to same format
|
| 19 |
+
lines = lines.replace(/\r\n?/mg, '\n')
|
| 20 |
+
|
| 21 |
+
let match
|
| 22 |
+
while ((match = LINE.exec(lines)) != null) {
|
| 23 |
+
const key = match[1]
|
| 24 |
+
|
| 25 |
+
// Default undefined or null to empty string
|
| 26 |
+
let value = (match[2] || '')
|
| 27 |
+
|
| 28 |
+
// Remove whitespace
|
| 29 |
+
value = value.trim()
|
| 30 |
+
|
| 31 |
+
// Check if double quoted
|
| 32 |
+
const maybeQuote = value[0]
|
| 33 |
+
|
| 34 |
+
// Remove surrounding quotes
|
| 35 |
+
value = value.replace(/^(['"`])([\s\S]*)\1$/mg, '$2')
|
| 36 |
+
|
| 37 |
+
// Expand newlines if double quoted
|
| 38 |
+
if (maybeQuote === '"') {
|
| 39 |
+
value = value.replace(/\\n/g, '\n')
|
| 40 |
+
value = value.replace(/\\r/g, '\r')
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
// Add to object
|
| 44 |
+
obj[key] = value
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
return obj
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
function _parseVault (options) {
|
| 51 |
+
options = options || {}
|
| 52 |
+
|
| 53 |
+
const vaultPath = _vaultPath(options)
|
| 54 |
+
options.path = vaultPath // parse .env.vault
|
| 55 |
+
const result = DotenvModule.configDotenv(options)
|
| 56 |
+
if (!result.parsed) {
|
| 57 |
+
const err = new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`)
|
| 58 |
+
err.code = 'MISSING_DATA'
|
| 59 |
+
throw err
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
// handle scenario for comma separated keys - for use with key rotation
|
| 63 |
+
// example: DOTENV_KEY="dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=prod,dotenv://:key_7890@dotenvx.com/vault/.env.vault?environment=prod"
|
| 64 |
+
const keys = _dotenvKey(options).split(',')
|
| 65 |
+
const length = keys.length
|
| 66 |
+
|
| 67 |
+
let decrypted
|
| 68 |
+
for (let i = 0; i < length; i++) {
|
| 69 |
+
try {
|
| 70 |
+
// Get full key
|
| 71 |
+
const key = keys[i].trim()
|
| 72 |
+
|
| 73 |
+
// Get instructions for decrypt
|
| 74 |
+
const attrs = _instructions(result, key)
|
| 75 |
+
|
| 76 |
+
// Decrypt
|
| 77 |
+
decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key)
|
| 78 |
+
|
| 79 |
+
break
|
| 80 |
+
} catch (error) {
|
| 81 |
+
// last key
|
| 82 |
+
if (i + 1 >= length) {
|
| 83 |
+
throw error
|
| 84 |
+
}
|
| 85 |
+
// try next key
|
| 86 |
+
}
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
// Parse decrypted .env string
|
| 90 |
+
return DotenvModule.parse(decrypted)
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
function _warn (message) {
|
| 94 |
+
console.log(`[dotenv@${version}][WARN] ${message}`)
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
function _debug (message) {
|
| 98 |
+
console.log(`[dotenv@${version}][DEBUG] ${message}`)
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
function _log (message) {
|
| 102 |
+
console.log(`[dotenv@${version}] ${message}`)
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
function _dotenvKey (options) {
|
| 106 |
+
// prioritize developer directly setting options.DOTENV_KEY
|
| 107 |
+
if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) {
|
| 108 |
+
return options.DOTENV_KEY
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
// secondary infra already contains a DOTENV_KEY environment variable
|
| 112 |
+
if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) {
|
| 113 |
+
return process.env.DOTENV_KEY
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
// fallback to empty string
|
| 117 |
+
return ''
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
function _instructions (result, dotenvKey) {
|
| 121 |
+
// Parse DOTENV_KEY. Format is a URI
|
| 122 |
+
let uri
|
| 123 |
+
try {
|
| 124 |
+
uri = new URL(dotenvKey)
|
| 125 |
+
} catch (error) {
|
| 126 |
+
if (error.code === 'ERR_INVALID_URL') {
|
| 127 |
+
const err = new Error('INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=development')
|
| 128 |
+
err.code = 'INVALID_DOTENV_KEY'
|
| 129 |
+
throw err
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
throw error
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
// Get decrypt key
|
| 136 |
+
const key = uri.password
|
| 137 |
+
if (!key) {
|
| 138 |
+
const err = new Error('INVALID_DOTENV_KEY: Missing key part')
|
| 139 |
+
err.code = 'INVALID_DOTENV_KEY'
|
| 140 |
+
throw err
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
// Get environment
|
| 144 |
+
const environment = uri.searchParams.get('environment')
|
| 145 |
+
if (!environment) {
|
| 146 |
+
const err = new Error('INVALID_DOTENV_KEY: Missing environment part')
|
| 147 |
+
err.code = 'INVALID_DOTENV_KEY'
|
| 148 |
+
throw err
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
// Get ciphertext payload
|
| 152 |
+
const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`
|
| 153 |
+
const ciphertext = result.parsed[environmentKey] // DOTENV_VAULT_PRODUCTION
|
| 154 |
+
if (!ciphertext) {
|
| 155 |
+
const err = new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`)
|
| 156 |
+
err.code = 'NOT_FOUND_DOTENV_ENVIRONMENT'
|
| 157 |
+
throw err
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
return { ciphertext, key }
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
function _vaultPath (options) {
|
| 164 |
+
let possibleVaultPath = null
|
| 165 |
+
|
| 166 |
+
if (options && options.path && options.path.length > 0) {
|
| 167 |
+
if (Array.isArray(options.path)) {
|
| 168 |
+
for (const filepath of options.path) {
|
| 169 |
+
if (fs.existsSync(filepath)) {
|
| 170 |
+
possibleVaultPath = filepath.endsWith('.vault') ? filepath : `${filepath}.vault`
|
| 171 |
+
}
|
| 172 |
+
}
|
| 173 |
+
} else {
|
| 174 |
+
possibleVaultPath = options.path.endsWith('.vault') ? options.path : `${options.path}.vault`
|
| 175 |
+
}
|
| 176 |
+
} else {
|
| 177 |
+
possibleVaultPath = path.resolve(process.cwd(), '.env.vault')
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
if (fs.existsSync(possibleVaultPath)) {
|
| 181 |
+
return possibleVaultPath
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
return null
|
| 185 |
+
}
|
| 186 |
+
|
| 187 |
+
function _resolveHome (envPath) {
|
| 188 |
+
return envPath[0] === '~' ? path.join(os.homedir(), envPath.slice(1)) : envPath
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
function _configVault (options) {
|
| 192 |
+
const debug = Boolean(options && options.debug)
|
| 193 |
+
const quiet = options && 'quiet' in options ? options.quiet : true
|
| 194 |
+
|
| 195 |
+
if (debug || !quiet) {
|
| 196 |
+
_log('Loading env from encrypted .env.vault')
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
const parsed = DotenvModule._parseVault(options)
|
| 200 |
+
|
| 201 |
+
let processEnv = process.env
|
| 202 |
+
if (options && options.processEnv != null) {
|
| 203 |
+
processEnv = options.processEnv
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
DotenvModule.populate(processEnv, parsed, options)
|
| 207 |
+
|
| 208 |
+
return { parsed }
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
function configDotenv (options) {
|
| 212 |
+
const dotenvPath = path.resolve(process.cwd(), '.env')
|
| 213 |
+
let encoding = 'utf8'
|
| 214 |
+
const debug = Boolean(options && options.debug)
|
| 215 |
+
const quiet = options && 'quiet' in options ? options.quiet : true
|
| 216 |
+
|
| 217 |
+
if (options && options.encoding) {
|
| 218 |
+
encoding = options.encoding
|
| 219 |
+
} else {
|
| 220 |
+
if (debug) {
|
| 221 |
+
_debug('No encoding is specified. UTF-8 is used by default')
|
| 222 |
+
}
|
| 223 |
+
}
|
| 224 |
+
|
| 225 |
+
let optionPaths = [dotenvPath] // default, look for .env
|
| 226 |
+
if (options && options.path) {
|
| 227 |
+
if (!Array.isArray(options.path)) {
|
| 228 |
+
optionPaths = [_resolveHome(options.path)]
|
| 229 |
+
} else {
|
| 230 |
+
optionPaths = [] // reset default
|
| 231 |
+
for (const filepath of options.path) {
|
| 232 |
+
optionPaths.push(_resolveHome(filepath))
|
| 233 |
+
}
|
| 234 |
+
}
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
// Build the parsed data in a temporary object (because we need to return it). Once we have the final
|
| 238 |
+
// parsed data, we will combine it with process.env (or options.processEnv if provided).
|
| 239 |
+
let lastError
|
| 240 |
+
const parsedAll = {}
|
| 241 |
+
for (const path of optionPaths) {
|
| 242 |
+
try {
|
| 243 |
+
// Specifying an encoding returns a string instead of a buffer
|
| 244 |
+
const parsed = DotenvModule.parse(fs.readFileSync(path, { encoding }))
|
| 245 |
+
|
| 246 |
+
DotenvModule.populate(parsedAll, parsed, options)
|
| 247 |
+
} catch (e) {
|
| 248 |
+
if (debug) {
|
| 249 |
+
_debug(`Failed to load ${path} ${e.message}`)
|
| 250 |
+
}
|
| 251 |
+
lastError = e
|
| 252 |
+
}
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
let processEnv = process.env
|
| 256 |
+
if (options && options.processEnv != null) {
|
| 257 |
+
processEnv = options.processEnv
|
| 258 |
+
}
|
| 259 |
+
|
| 260 |
+
DotenvModule.populate(processEnv, parsedAll, options)
|
| 261 |
+
|
| 262 |
+
if (debug || !quiet) {
|
| 263 |
+
const keysCount = Object.keys(parsedAll).length
|
| 264 |
+
const shortPaths = []
|
| 265 |
+
for (const filePath of optionPaths) {
|
| 266 |
+
try {
|
| 267 |
+
const relative = path.relative(process.cwd(), filePath)
|
| 268 |
+
shortPaths.push(relative)
|
| 269 |
+
} catch (e) {
|
| 270 |
+
if (debug) {
|
| 271 |
+
_debug(`Failed to load ${filePath} ${e.message}`)
|
| 272 |
+
}
|
| 273 |
+
lastError = e
|
| 274 |
+
}
|
| 275 |
+
}
|
| 276 |
+
|
| 277 |
+
_log(`injecting env (${keysCount}) from ${shortPaths.join(',')}`)
|
| 278 |
+
}
|
| 279 |
+
|
| 280 |
+
if (lastError) {
|
| 281 |
+
return { parsed: parsedAll, error: lastError }
|
| 282 |
+
} else {
|
| 283 |
+
return { parsed: parsedAll }
|
| 284 |
+
}
|
| 285 |
+
}
|
| 286 |
+
|
| 287 |
+
// Populates process.env from .env file
|
| 288 |
+
function config (options) {
|
| 289 |
+
// fallback to original dotenv if DOTENV_KEY is not set
|
| 290 |
+
if (_dotenvKey(options).length === 0) {
|
| 291 |
+
return DotenvModule.configDotenv(options)
|
| 292 |
+
}
|
| 293 |
+
|
| 294 |
+
const vaultPath = _vaultPath(options)
|
| 295 |
+
|
| 296 |
+
// dotenvKey exists but .env.vault file does not exist
|
| 297 |
+
if (!vaultPath) {
|
| 298 |
+
_warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`)
|
| 299 |
+
|
| 300 |
+
return DotenvModule.configDotenv(options)
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
return DotenvModule._configVault(options)
|
| 304 |
+
}
|
| 305 |
+
|
| 306 |
+
function decrypt (encrypted, keyStr) {
|
| 307 |
+
const key = Buffer.from(keyStr.slice(-64), 'hex')
|
| 308 |
+
let ciphertext = Buffer.from(encrypted, 'base64')
|
| 309 |
+
|
| 310 |
+
const nonce = ciphertext.subarray(0, 12)
|
| 311 |
+
const authTag = ciphertext.subarray(-16)
|
| 312 |
+
ciphertext = ciphertext.subarray(12, -16)
|
| 313 |
+
|
| 314 |
+
try {
|
| 315 |
+
const aesgcm = crypto.createDecipheriv('aes-256-gcm', key, nonce)
|
| 316 |
+
aesgcm.setAuthTag(authTag)
|
| 317 |
+
return `${aesgcm.update(ciphertext)}${aesgcm.final()}`
|
| 318 |
+
} catch (error) {
|
| 319 |
+
const isRange = error instanceof RangeError
|
| 320 |
+
const invalidKeyLength = error.message === 'Invalid key length'
|
| 321 |
+
const decryptionFailed = error.message === 'Unsupported state or unable to authenticate data'
|
| 322 |
+
|
| 323 |
+
if (isRange || invalidKeyLength) {
|
| 324 |
+
const err = new Error('INVALID_DOTENV_KEY: It must be 64 characters long (or more)')
|
| 325 |
+
err.code = 'INVALID_DOTENV_KEY'
|
| 326 |
+
throw err
|
| 327 |
+
} else if (decryptionFailed) {
|
| 328 |
+
const err = new Error('DECRYPTION_FAILED: Please check your DOTENV_KEY')
|
| 329 |
+
err.code = 'DECRYPTION_FAILED'
|
| 330 |
+
throw err
|
| 331 |
+
} else {
|
| 332 |
+
throw error
|
| 333 |
+
}
|
| 334 |
+
}
|
| 335 |
+
}
|
| 336 |
+
|
| 337 |
+
// Populate process.env with parsed values
|
| 338 |
+
function populate (processEnv, parsed, options = {}) {
|
| 339 |
+
const debug = Boolean(options && options.debug)
|
| 340 |
+
const override = Boolean(options && options.override)
|
| 341 |
+
|
| 342 |
+
if (typeof parsed !== 'object') {
|
| 343 |
+
const err = new Error('OBJECT_REQUIRED: Please check the processEnv argument being passed to populate')
|
| 344 |
+
err.code = 'OBJECT_REQUIRED'
|
| 345 |
+
throw err
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
// Set process.env
|
| 349 |
+
for (const key of Object.keys(parsed)) {
|
| 350 |
+
if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
|
| 351 |
+
if (override === true) {
|
| 352 |
+
processEnv[key] = parsed[key]
|
| 353 |
+
}
|
| 354 |
+
|
| 355 |
+
if (debug) {
|
| 356 |
+
if (override === true) {
|
| 357 |
+
_debug(`"${key}" is already defined and WAS overwritten`)
|
| 358 |
+
} else {
|
| 359 |
+
_debug(`"${key}" is already defined and was NOT overwritten`)
|
| 360 |
+
}
|
| 361 |
+
}
|
| 362 |
+
} else {
|
| 363 |
+
processEnv[key] = parsed[key]
|
| 364 |
+
}
|
| 365 |
+
}
|
| 366 |
+
}
|
| 367 |
+
|
| 368 |
+
const DotenvModule = {
|
| 369 |
+
configDotenv,
|
| 370 |
+
_configVault,
|
| 371 |
+
_parseVault,
|
| 372 |
+
config,
|
| 373 |
+
decrypt,
|
| 374 |
+
parse,
|
| 375 |
+
populate
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
module.exports.configDotenv = DotenvModule.configDotenv
|
| 379 |
+
module.exports._configVault = DotenvModule._configVault
|
| 380 |
+
module.exports._parseVault = DotenvModule._parseVault
|
| 381 |
+
module.exports.config = DotenvModule.config
|
| 382 |
+
module.exports.decrypt = DotenvModule.decrypt
|
| 383 |
+
module.exports.parse = DotenvModule.parse
|
| 384 |
+
module.exports.populate = DotenvModule.populate
|
| 385 |
+
|
| 386 |
+
module.exports = DotenvModule
|
backend/node_modules/effect/src/internal/layer/circular.ts
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import type * as ConfigProvider from "../../ConfigProvider.js"
|
| 2 |
+
import * as Context from "../../Context.js"
|
| 3 |
+
import type * as Effect from "../../Effect.js"
|
| 4 |
+
import type * as Exit from "../../Exit.js"
|
| 5 |
+
import { dual } from "../../Function.js"
|
| 6 |
+
import * as HashSet from "../../HashSet.js"
|
| 7 |
+
import type * as Layer from "../../Layer.js"
|
| 8 |
+
import type * as Logger from "../../Logger.js"
|
| 9 |
+
import type * as LogLevel from "../../LogLevel.js"
|
| 10 |
+
import type { Scope } from "../../Scope.js"
|
| 11 |
+
import type * as Supervisor from "../../Supervisor.js"
|
| 12 |
+
import type * as Tracer from "../../Tracer.js"
|
| 13 |
+
import * as core from "../core.js"
|
| 14 |
+
import * as fiberRuntime from "../fiberRuntime.js"
|
| 15 |
+
import * as layer from "../layer.js"
|
| 16 |
+
import * as runtimeFlags from "../runtimeFlags.js"
|
| 17 |
+
import * as runtimeFlagsPatch from "../runtimeFlagsPatch.js"
|
| 18 |
+
import * as supervisor_ from "../supervisor.js"
|
| 19 |
+
import * as tracer from "../tracer.js"
|
| 20 |
+
|
| 21 |
+
// circular with Logger
|
| 22 |
+
|
| 23 |
+
/** @internal */
|
| 24 |
+
export const minimumLogLevel = (level: LogLevel.LogLevel): Layer.Layer<never> =>
|
| 25 |
+
layer.scopedDiscard(
|
| 26 |
+
fiberRuntime.fiberRefLocallyScoped(
|
| 27 |
+
fiberRuntime.currentMinimumLogLevel,
|
| 28 |
+
level
|
| 29 |
+
)
|
| 30 |
+
)
|
| 31 |
+
|
| 32 |
+
/** @internal */
|
| 33 |
+
export const withMinimumLogLevel = dual<
|
| 34 |
+
(level: LogLevel.LogLevel) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>,
|
| 35 |
+
<A, E, R>(self: Effect.Effect<A, E, R>, level: LogLevel.LogLevel) => Effect.Effect<A, E, R>
|
| 36 |
+
>(2, (self, level) =>
|
| 37 |
+
core.fiberRefLocally(
|
| 38 |
+
fiberRuntime.currentMinimumLogLevel,
|
| 39 |
+
level
|
| 40 |
+
)(self))
|
| 41 |
+
|
| 42 |
+
/** @internal */
|
| 43 |
+
export const addLogger = <A>(logger: Logger.Logger<unknown, A>): Layer.Layer<never> =>
|
| 44 |
+
layer.scopedDiscard(
|
| 45 |
+
fiberRuntime.fiberRefLocallyScopedWith(
|
| 46 |
+
fiberRuntime.currentLoggers,
|
| 47 |
+
HashSet.add(logger)
|
| 48 |
+
)
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
/** @internal */
|
| 52 |
+
export const addLoggerEffect = <A, E, R>(
|
| 53 |
+
effect: Effect.Effect<Logger.Logger<unknown, A>, E, R>
|
| 54 |
+
): Layer.Layer<never, E, R> =>
|
| 55 |
+
layer.unwrapEffect(
|
| 56 |
+
core.map(effect, addLogger)
|
| 57 |
+
)
|
| 58 |
+
|
| 59 |
+
/** @internal */
|
| 60 |
+
export const addLoggerScoped = <A, E, R>(
|
| 61 |
+
effect: Effect.Effect<Logger.Logger<unknown, A>, E, R>
|
| 62 |
+
): Layer.Layer<never, E, Exclude<R, Scope>> =>
|
| 63 |
+
layer.unwrapScoped(
|
| 64 |
+
core.map(effect, addLogger)
|
| 65 |
+
)
|
| 66 |
+
|
| 67 |
+
/** @internal */
|
| 68 |
+
export const removeLogger = <A>(logger: Logger.Logger<unknown, A>): Layer.Layer<never> =>
|
| 69 |
+
layer.scopedDiscard(
|
| 70 |
+
fiberRuntime.fiberRefLocallyScopedWith(
|
| 71 |
+
fiberRuntime.currentLoggers,
|
| 72 |
+
HashSet.remove(logger)
|
| 73 |
+
)
|
| 74 |
+
)
|
| 75 |
+
|
| 76 |
+
/** @internal */
|
| 77 |
+
export const replaceLogger = dual<
|
| 78 |
+
<B>(that: Logger.Logger<unknown, B>) => <A>(self: Logger.Logger<unknown, A>) => Layer.Layer<never>,
|
| 79 |
+
<A, B>(self: Logger.Logger<unknown, A>, that: Logger.Logger<unknown, B>) => Layer.Layer<never>
|
| 80 |
+
>(2, (self, that) => layer.flatMap(removeLogger(self), () => addLogger(that)))
|
| 81 |
+
|
| 82 |
+
/** @internal */
|
| 83 |
+
export const replaceLoggerEffect = dual<
|
| 84 |
+
<B, E, R>(
|
| 85 |
+
that: Effect.Effect<Logger.Logger<unknown, B>, E, R>
|
| 86 |
+
) => <A>(self: Logger.Logger<unknown, A>) => Layer.Layer<never, E, R>,
|
| 87 |
+
<A, B, E, R>(
|
| 88 |
+
self: Logger.Logger<unknown, A>,
|
| 89 |
+
that: Effect.Effect<Logger.Logger<unknown, B>, E, R>
|
| 90 |
+
) => Layer.Layer<never, E, R>
|
| 91 |
+
>(2, (self, that) => layer.flatMap(removeLogger(self), () => addLoggerEffect(that)))
|
| 92 |
+
|
| 93 |
+
/** @internal */
|
| 94 |
+
export const replaceLoggerScoped = dual<
|
| 95 |
+
<B, E, R>(
|
| 96 |
+
that: Effect.Effect<Logger.Logger<unknown, B>, E, R>
|
| 97 |
+
) => <A>(self: Logger.Logger<unknown, A>) => Layer.Layer<never, E, Exclude<R, Scope>>,
|
| 98 |
+
<A, B, E, R>(
|
| 99 |
+
self: Logger.Logger<unknown, A>,
|
| 100 |
+
that: Effect.Effect<Logger.Logger<unknown, B>, E, R>
|
| 101 |
+
) => Layer.Layer<never, E, Exclude<R, Scope>>
|
| 102 |
+
>(2, (self, that) => layer.flatMap(removeLogger(self), () => addLoggerScoped(that)))
|
| 103 |
+
|
| 104 |
+
/** @internal */
|
| 105 |
+
export const addSupervisor = <A>(supervisor: Supervisor.Supervisor<A>): Layer.Layer<never> =>
|
| 106 |
+
layer.scopedDiscard(
|
| 107 |
+
fiberRuntime.fiberRefLocallyScopedWith(
|
| 108 |
+
fiberRuntime.currentSupervisor,
|
| 109 |
+
(current) => new supervisor_.Zip(current, supervisor)
|
| 110 |
+
)
|
| 111 |
+
)
|
| 112 |
+
|
| 113 |
+
/** @internal */
|
| 114 |
+
export const enableCooperativeYielding: Layer.Layer<never> = layer.scopedDiscard(
|
| 115 |
+
fiberRuntime.withRuntimeFlagsScoped(
|
| 116 |
+
runtimeFlagsPatch.enable(runtimeFlags.CooperativeYielding)
|
| 117 |
+
)
|
| 118 |
+
)
|
| 119 |
+
|
| 120 |
+
/** @internal */
|
| 121 |
+
export const enableInterruption: Layer.Layer<never> = layer.scopedDiscard(
|
| 122 |
+
fiberRuntime.withRuntimeFlagsScoped(
|
| 123 |
+
runtimeFlagsPatch.enable(runtimeFlags.Interruption)
|
| 124 |
+
)
|
| 125 |
+
)
|
| 126 |
+
|
| 127 |
+
/** @internal */
|
| 128 |
+
export const enableOpSupervision: Layer.Layer<never> = layer.scopedDiscard(
|
| 129 |
+
fiberRuntime.withRuntimeFlagsScoped(
|
| 130 |
+
runtimeFlagsPatch.enable(runtimeFlags.OpSupervision)
|
| 131 |
+
)
|
| 132 |
+
)
|
| 133 |
+
|
| 134 |
+
/** @internal */
|
| 135 |
+
export const enableRuntimeMetrics: Layer.Layer<never> = layer.scopedDiscard(
|
| 136 |
+
fiberRuntime.withRuntimeFlagsScoped(
|
| 137 |
+
runtimeFlagsPatch.enable(runtimeFlags.RuntimeMetrics)
|
| 138 |
+
)
|
| 139 |
+
)
|
| 140 |
+
|
| 141 |
+
/** @internal */
|
| 142 |
+
export const enableWindDown: Layer.Layer<never> = layer.scopedDiscard(
|
| 143 |
+
fiberRuntime.withRuntimeFlagsScoped(
|
| 144 |
+
runtimeFlagsPatch.enable(runtimeFlags.WindDown)
|
| 145 |
+
)
|
| 146 |
+
)
|
| 147 |
+
|
| 148 |
+
/** @internal */
|
| 149 |
+
export const disableCooperativeYielding: Layer.Layer<never> = layer.scopedDiscard(
|
| 150 |
+
fiberRuntime.withRuntimeFlagsScoped(
|
| 151 |
+
runtimeFlagsPatch.disable(runtimeFlags.CooperativeYielding)
|
| 152 |
+
)
|
| 153 |
+
)
|
| 154 |
+
|
| 155 |
+
/** @internal */
|
| 156 |
+
export const disableInterruption: Layer.Layer<never> = layer.scopedDiscard(
|
| 157 |
+
fiberRuntime.withRuntimeFlagsScoped(
|
| 158 |
+
runtimeFlagsPatch.disable(runtimeFlags.Interruption)
|
| 159 |
+
)
|
| 160 |
+
)
|
| 161 |
+
|
| 162 |
+
/** @internal */
|
| 163 |
+
export const disableOpSupervision: Layer.Layer<never> = layer.scopedDiscard(
|
| 164 |
+
fiberRuntime.withRuntimeFlagsScoped(
|
| 165 |
+
runtimeFlagsPatch.disable(runtimeFlags.OpSupervision)
|
| 166 |
+
)
|
| 167 |
+
)
|
| 168 |
+
|
| 169 |
+
/** @internal */
|
| 170 |
+
export const disableRuntimeMetrics: Layer.Layer<never> = layer.scopedDiscard(
|
| 171 |
+
fiberRuntime.withRuntimeFlagsScoped(
|
| 172 |
+
runtimeFlagsPatch.disable(runtimeFlags.RuntimeMetrics)
|
| 173 |
+
)
|
| 174 |
+
)
|
| 175 |
+
|
| 176 |
+
/** @internal */
|
| 177 |
+
export const disableWindDown: Layer.Layer<never> = layer.scopedDiscard(
|
| 178 |
+
fiberRuntime.withRuntimeFlagsScoped(
|
| 179 |
+
runtimeFlagsPatch.disable(runtimeFlags.WindDown)
|
| 180 |
+
)
|
| 181 |
+
)
|
| 182 |
+
|
| 183 |
+
/** @internal */
|
| 184 |
+
export const setConfigProvider = (configProvider: ConfigProvider.ConfigProvider): Layer.Layer<never> =>
|
| 185 |
+
layer.scopedDiscard(fiberRuntime.withConfigProviderScoped(configProvider))
|
| 186 |
+
|
| 187 |
+
/** @internal */
|
| 188 |
+
export const parentSpan = (span: Tracer.AnySpan): Layer.Layer<Tracer.ParentSpan> =>
|
| 189 |
+
layer.succeedContext(Context.make(tracer.spanTag, span))
|
| 190 |
+
|
| 191 |
+
/** @internal */
|
| 192 |
+
export const span = (
|
| 193 |
+
name: string,
|
| 194 |
+
options?: Tracer.SpanOptions & {
|
| 195 |
+
readonly onEnd?:
|
| 196 |
+
| ((span: Tracer.Span, exit: Exit.Exit<unknown, unknown>) => Effect.Effect<void>)
|
| 197 |
+
| undefined
|
| 198 |
+
}
|
| 199 |
+
): Layer.Layer<Tracer.ParentSpan> => {
|
| 200 |
+
options = tracer.addSpanStackTrace(options) as any
|
| 201 |
+
return layer.scoped(
|
| 202 |
+
tracer.spanTag,
|
| 203 |
+
options?.onEnd
|
| 204 |
+
? core.tap(
|
| 205 |
+
fiberRuntime.makeSpanScoped(name, options),
|
| 206 |
+
(span) => fiberRuntime.addFinalizer((exit) => options.onEnd!(span, exit))
|
| 207 |
+
)
|
| 208 |
+
: fiberRuntime.makeSpanScoped(name, options)
|
| 209 |
+
)
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
/** @internal */
|
| 213 |
+
export const setTracer = (tracer: Tracer.Tracer): Layer.Layer<never> =>
|
| 214 |
+
layer.scopedDiscard(fiberRuntime.withTracerScoped(tracer))
|
backend/node_modules/effect/src/internal/metric/label.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import * as Equal from "../../Equal.js"
|
| 2 |
+
import * as Hash from "../../Hash.js"
|
| 3 |
+
import type * as MetricLabel from "../../MetricLabel.js"
|
| 4 |
+
import { pipeArguments } from "../../Pipeable.js"
|
| 5 |
+
import { hasProperty } from "../../Predicate.js"
|
| 6 |
+
|
| 7 |
+
/** @internal */
|
| 8 |
+
const MetricLabelSymbolKey = "effect/MetricLabel"
|
| 9 |
+
|
| 10 |
+
/** @internal */
|
| 11 |
+
export const MetricLabelTypeId: MetricLabel.MetricLabelTypeId = Symbol.for(
|
| 12 |
+
MetricLabelSymbolKey
|
| 13 |
+
) as MetricLabel.MetricLabelTypeId
|
| 14 |
+
|
| 15 |
+
/** @internal */
|
| 16 |
+
class MetricLabelImpl implements MetricLabel.MetricLabel {
|
| 17 |
+
readonly [MetricLabelTypeId]: MetricLabel.MetricLabelTypeId = MetricLabelTypeId
|
| 18 |
+
readonly _hash: number
|
| 19 |
+
constructor(readonly key: string, readonly value: string) {
|
| 20 |
+
this._hash = Hash.string(MetricLabelSymbolKey + this.key + this.value)
|
| 21 |
+
}
|
| 22 |
+
[Hash.symbol](): number {
|
| 23 |
+
return this._hash
|
| 24 |
+
}
|
| 25 |
+
[Equal.symbol](that: unknown): boolean {
|
| 26 |
+
return isMetricLabel(that) &&
|
| 27 |
+
this.key === that.key &&
|
| 28 |
+
this.value === that.value
|
| 29 |
+
}
|
| 30 |
+
pipe() {
|
| 31 |
+
return pipeArguments(this, arguments)
|
| 32 |
+
}
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
/** @internal */
|
| 36 |
+
export const make = (key: string, value: string): MetricLabel.MetricLabel => {
|
| 37 |
+
return new MetricLabelImpl(key, value)
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
/** @internal */
|
| 41 |
+
export const isMetricLabel = (u: unknown): u is MetricLabel.MetricLabel => hasProperty(u, MetricLabelTypeId)
|
backend/node_modules/effect/src/internal/metric/pair.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import type * as MetricKey from "../../MetricKey.js"
|
| 2 |
+
import type * as MetricKeyType from "../../MetricKeyType.js"
|
| 3 |
+
import type * as MetricPair from "../../MetricPair.js"
|
| 4 |
+
import type * as MetricState from "../../MetricState.js"
|
| 5 |
+
import { pipeArguments } from "../../Pipeable.js"
|
| 6 |
+
|
| 7 |
+
/** @internal */
|
| 8 |
+
const MetricPairSymbolKey = "effect/MetricPair"
|
| 9 |
+
|
| 10 |
+
/** @internal */
|
| 11 |
+
export const MetricPairTypeId: MetricPair.MetricPairTypeId = Symbol.for(
|
| 12 |
+
MetricPairSymbolKey
|
| 13 |
+
) as MetricPair.MetricPairTypeId
|
| 14 |
+
|
| 15 |
+
const metricPairVariance = {
|
| 16 |
+
/* c8 ignore next */
|
| 17 |
+
_Type: (_: never) => _
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
/** @internal */
|
| 21 |
+
export const make = <Type extends MetricKeyType.MetricKeyType<any, any>>(
|
| 22 |
+
metricKey: MetricKey.MetricKey<Type>,
|
| 23 |
+
metricState: MetricState.MetricState<MetricKeyType.MetricKeyType.OutType<Type>>
|
| 24 |
+
): MetricPair.MetricPair.Untyped => {
|
| 25 |
+
return {
|
| 26 |
+
[MetricPairTypeId]: metricPairVariance,
|
| 27 |
+
metricKey,
|
| 28 |
+
metricState,
|
| 29 |
+
pipe() {
|
| 30 |
+
return pipeArguments(this, arguments)
|
| 31 |
+
}
|
| 32 |
+
}
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
/** @internal */
|
| 36 |
+
export const unsafeMake = <Type extends MetricKeyType.MetricKeyType<any, any>>(
|
| 37 |
+
metricKey: MetricKey.MetricKey<Type>,
|
| 38 |
+
metricState: MetricState.MetricState.Untyped
|
| 39 |
+
): MetricPair.MetricPair.Untyped => {
|
| 40 |
+
return {
|
| 41 |
+
[MetricPairTypeId]: metricPairVariance,
|
| 42 |
+
metricKey,
|
| 43 |
+
metricState,
|
| 44 |
+
pipe() {
|
| 45 |
+
return pipeArguments(this, arguments)
|
| 46 |
+
}
|
| 47 |
+
}
|
| 48 |
+
}
|
backend/node_modules/effect/src/internal/metric/polling.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import type * as Effect from "../../Effect.js"
|
| 2 |
+
import type * as Fiber from "../../Fiber.js"
|
| 3 |
+
import { dual, pipe } from "../../Function.js"
|
| 4 |
+
import type * as Metric from "../../Metric.js"
|
| 5 |
+
import type * as MetricPolling from "../../MetricPolling.js"
|
| 6 |
+
import { pipeArguments } from "../../Pipeable.js"
|
| 7 |
+
import type * as Schedule from "../../Schedule.js"
|
| 8 |
+
import type * as Scope from "../../Scope.js"
|
| 9 |
+
import * as core from "../core.js"
|
| 10 |
+
import * as metric from "../metric.js"
|
| 11 |
+
import * as schedule_ from "../schedule.js"
|
| 12 |
+
|
| 13 |
+
/** @internal */
|
| 14 |
+
const MetricPollingSymbolKey = "effect/MetricPolling"
|
| 15 |
+
|
| 16 |
+
/** @internal */
|
| 17 |
+
export const MetricPollingTypeId: MetricPolling.MetricPollingTypeId = Symbol.for(
|
| 18 |
+
MetricPollingSymbolKey
|
| 19 |
+
) as MetricPolling.MetricPollingTypeId
|
| 20 |
+
|
| 21 |
+
/** @internal */
|
| 22 |
+
export const make = <Type, In, Out, R, E>(
|
| 23 |
+
metric: Metric.Metric<Type, In, Out>,
|
| 24 |
+
poll: Effect.Effect<In, E, R>
|
| 25 |
+
): MetricPolling.MetricPolling<Type, In, R, E, Out> => {
|
| 26 |
+
return {
|
| 27 |
+
[MetricPollingTypeId]: MetricPollingTypeId,
|
| 28 |
+
pipe() {
|
| 29 |
+
return pipeArguments(this, arguments)
|
| 30 |
+
},
|
| 31 |
+
metric,
|
| 32 |
+
poll
|
| 33 |
+
}
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
/** @internal */
|
| 37 |
+
export const collectAll = <R, E, Out>(
|
| 38 |
+
iterable: Iterable<MetricPolling.MetricPolling<any, any, R, E, Out>>
|
| 39 |
+
): MetricPolling.MetricPolling<Array<any>, Array<any>, R, E, Array<Out>> => {
|
| 40 |
+
const metrics = Array.from(iterable)
|
| 41 |
+
return {
|
| 42 |
+
[MetricPollingTypeId]: MetricPollingTypeId,
|
| 43 |
+
pipe() {
|
| 44 |
+
return pipeArguments(this, arguments)
|
| 45 |
+
},
|
| 46 |
+
metric: metric.make(
|
| 47 |
+
Array.of<any>(void 0) as Array<any>,
|
| 48 |
+
(inputs: Array<any>, extraTags) => {
|
| 49 |
+
for (let i = 0; i < inputs.length; i++) {
|
| 50 |
+
const pollingMetric = metrics[i]!
|
| 51 |
+
const input = pipe(inputs, (x) => x[i])
|
| 52 |
+
pollingMetric.metric.unsafeUpdate(input, extraTags)
|
| 53 |
+
}
|
| 54 |
+
},
|
| 55 |
+
(extraTags) =>
|
| 56 |
+
Array.from(
|
| 57 |
+
metrics.map((pollingMetric) => pollingMetric.metric.unsafeValue(extraTags))
|
| 58 |
+
),
|
| 59 |
+
(inputs: Array<any>, extraTags) => {
|
| 60 |
+
for (let i = 0; i < inputs.length; i++) {
|
| 61 |
+
const pollingMetric = metrics[i]!
|
| 62 |
+
const input = pipe(inputs, (x) => x[i])
|
| 63 |
+
pollingMetric.metric.unsafeModify(input, extraTags)
|
| 64 |
+
}
|
| 65 |
+
}
|
| 66 |
+
),
|
| 67 |
+
poll: core.forEachSequential(metrics, (metric) => metric.poll)
|
| 68 |
+
}
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
/** @internal */
|
| 72 |
+
export const launch = dual<
|
| 73 |
+
<A2, R2>(
|
| 74 |
+
schedule: Schedule.Schedule<A2, unknown, R2>
|
| 75 |
+
) => <Type, In, R, E, Out>(
|
| 76 |
+
self: MetricPolling.MetricPolling<Type, In, R, E, Out>
|
| 77 |
+
) => Effect.Effect<Fiber.Fiber<A2, E>, never, R | R2 | Scope.Scope>,
|
| 78 |
+
<Type, In, R, E, Out, A2, R2>(
|
| 79 |
+
self: MetricPolling.MetricPolling<Type, In, R, E, Out>,
|
| 80 |
+
schedule: Schedule.Schedule<A2, unknown, R2>
|
| 81 |
+
) => Effect.Effect<Fiber.Fiber<A2, E>, never, R | R2 | Scope.Scope>
|
| 82 |
+
>(2, (self, schedule) =>
|
| 83 |
+
pipe(
|
| 84 |
+
pollAndUpdate(self),
|
| 85 |
+
core.zipRight(metric.value(self.metric)),
|
| 86 |
+
schedule_.scheduleForked(schedule)
|
| 87 |
+
))
|
| 88 |
+
|
| 89 |
+
/** @internal */
|
| 90 |
+
export const poll = <Type, In, R, E, Out>(
|
| 91 |
+
self: MetricPolling.MetricPolling<Type, In, R, E, Out>
|
| 92 |
+
): Effect.Effect<In, E, R> => self.poll
|
| 93 |
+
|
| 94 |
+
/** @internal */
|
| 95 |
+
export const pollAndUpdate = <Type, In, R, E, Out>(
|
| 96 |
+
self: MetricPolling.MetricPolling<Type, In, R, E, Out>
|
| 97 |
+
): Effect.Effect<void, E, R> => core.flatMap(self.poll, (value) => metric.update(self.metric, value))
|
| 98 |
+
|
| 99 |
+
/** @internal */
|
| 100 |
+
export const retry = dual<
|
| 101 |
+
<X, E, R2>(
|
| 102 |
+
policy: Schedule.Schedule<X, E, R2>
|
| 103 |
+
) => <Type, In, R, Out>(
|
| 104 |
+
self: MetricPolling.MetricPolling<Type, In, R, E, Out>
|
| 105 |
+
) => MetricPolling.MetricPolling<Type, In, R | R2, E, Out>,
|
| 106 |
+
<Type, In, R, E, Out, X, R2>(
|
| 107 |
+
self: MetricPolling.MetricPolling<Type, In, R, E, Out>,
|
| 108 |
+
policy: Schedule.Schedule<X, E, R2>
|
| 109 |
+
) => MetricPolling.MetricPolling<Type, In, R | R2, E, Out>
|
| 110 |
+
>(2, (self, policy) => ({
|
| 111 |
+
[MetricPollingTypeId]: MetricPollingTypeId,
|
| 112 |
+
pipe() {
|
| 113 |
+
return pipeArguments(this, arguments)
|
| 114 |
+
},
|
| 115 |
+
metric: self.metric,
|
| 116 |
+
poll: schedule_.retry_Effect(self.poll, policy)
|
| 117 |
+
}))
|
| 118 |
+
|
| 119 |
+
/** @internal */
|
| 120 |
+
export const zip = dual<
|
| 121 |
+
<Type2, In2, R2, E2, Out2>(
|
| 122 |
+
that: MetricPolling.MetricPolling<Type2, In2, R2, E2, Out2>
|
| 123 |
+
) => <Type, In, R, E, Out>(
|
| 124 |
+
self: MetricPolling.MetricPolling<Type, In, R, E, Out>
|
| 125 |
+
) => MetricPolling.MetricPolling<
|
| 126 |
+
readonly [Type, Type2],
|
| 127 |
+
readonly [In, In2],
|
| 128 |
+
R | R2,
|
| 129 |
+
E | E2,
|
| 130 |
+
[Out, Out2]
|
| 131 |
+
>,
|
| 132 |
+
<Type, In, R, E, Out, Type2, In2, R2, E2, Out2>(
|
| 133 |
+
self: MetricPolling.MetricPolling<Type, In, R, E, Out>,
|
| 134 |
+
that: MetricPolling.MetricPolling<Type2, In2, R2, E2, Out2>
|
| 135 |
+
) => MetricPolling.MetricPolling<
|
| 136 |
+
readonly [Type, Type2],
|
| 137 |
+
readonly [In, In2],
|
| 138 |
+
R | R2,
|
| 139 |
+
E | E2,
|
| 140 |
+
[Out, Out2]
|
| 141 |
+
>
|
| 142 |
+
>(2, (self, that) => ({
|
| 143 |
+
[MetricPollingTypeId]: MetricPollingTypeId,
|
| 144 |
+
pipe() {
|
| 145 |
+
return pipeArguments(this, arguments)
|
| 146 |
+
},
|
| 147 |
+
metric: pipe(self.metric, metric.zip(that.metric)),
|
| 148 |
+
poll: core.zip(self.poll, that.poll)
|
| 149 |
+
}))
|
backend/node_modules/effect/src/internal/metric/state.ts
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import * as Arr from "../../Array.js"
|
| 2 |
+
import * as Equal from "../../Equal.js"
|
| 3 |
+
import { pipe } from "../../Function.js"
|
| 4 |
+
import * as Hash from "../../Hash.js"
|
| 5 |
+
import type * as MetricState from "../../MetricState.js"
|
| 6 |
+
import type * as Option from "../../Option.js"
|
| 7 |
+
import { pipeArguments } from "../../Pipeable.js"
|
| 8 |
+
import { hasProperty } from "../../Predicate.js"
|
| 9 |
+
|
| 10 |
+
/** @internal */
|
| 11 |
+
const MetricStateSymbolKey = "effect/MetricState"
|
| 12 |
+
|
| 13 |
+
/** @internal */
|
| 14 |
+
export const MetricStateTypeId: MetricState.MetricStateTypeId = Symbol.for(
|
| 15 |
+
MetricStateSymbolKey
|
| 16 |
+
) as MetricState.MetricStateTypeId
|
| 17 |
+
|
| 18 |
+
/** @internal */
|
| 19 |
+
const CounterStateSymbolKey = "effect/MetricState/Counter"
|
| 20 |
+
|
| 21 |
+
/** @internal */
|
| 22 |
+
export const CounterStateTypeId: MetricState.CounterStateTypeId = Symbol.for(
|
| 23 |
+
CounterStateSymbolKey
|
| 24 |
+
) as MetricState.CounterStateTypeId
|
| 25 |
+
|
| 26 |
+
/** @internal */
|
| 27 |
+
const FrequencyStateSymbolKey = "effect/MetricState/Frequency"
|
| 28 |
+
|
| 29 |
+
/** @internal */
|
| 30 |
+
export const FrequencyStateTypeId: MetricState.FrequencyStateTypeId = Symbol.for(
|
| 31 |
+
FrequencyStateSymbolKey
|
| 32 |
+
) as MetricState.FrequencyStateTypeId
|
| 33 |
+
|
| 34 |
+
/** @internal */
|
| 35 |
+
const GaugeStateSymbolKey = "effect/MetricState/Gauge"
|
| 36 |
+
|
| 37 |
+
/** @internal */
|
| 38 |
+
export const GaugeStateTypeId: MetricState.GaugeStateTypeId = Symbol.for(
|
| 39 |
+
GaugeStateSymbolKey
|
| 40 |
+
) as MetricState.GaugeStateTypeId
|
| 41 |
+
|
| 42 |
+
/** @internal */
|
| 43 |
+
const HistogramStateSymbolKey = "effect/MetricState/Histogram"
|
| 44 |
+
|
| 45 |
+
/** @internal */
|
| 46 |
+
export const HistogramStateTypeId: MetricState.HistogramStateTypeId = Symbol.for(
|
| 47 |
+
HistogramStateSymbolKey
|
| 48 |
+
) as MetricState.HistogramStateTypeId
|
| 49 |
+
|
| 50 |
+
/** @internal */
|
| 51 |
+
const SummaryStateSymbolKey = "effect/MetricState/Summary"
|
| 52 |
+
|
| 53 |
+
/** @internal */
|
| 54 |
+
export const SummaryStateTypeId: MetricState.SummaryStateTypeId = Symbol.for(
|
| 55 |
+
SummaryStateSymbolKey
|
| 56 |
+
) as MetricState.SummaryStateTypeId
|
| 57 |
+
|
| 58 |
+
const metricStateVariance = {
|
| 59 |
+
/* c8 ignore next */
|
| 60 |
+
_A: (_: unknown) => _
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
/** @internal */
|
| 64 |
+
class CounterState<A extends (number | bigint)> implements MetricState.MetricState.Counter<A> {
|
| 65 |
+
readonly [MetricStateTypeId] = metricStateVariance
|
| 66 |
+
readonly [CounterStateTypeId]: MetricState.CounterStateTypeId = CounterStateTypeId
|
| 67 |
+
constructor(readonly count: A) {}
|
| 68 |
+
[Hash.symbol](): number {
|
| 69 |
+
return pipe(
|
| 70 |
+
Hash.hash(CounterStateSymbolKey),
|
| 71 |
+
Hash.combine(Hash.hash(this.count)),
|
| 72 |
+
Hash.cached(this)
|
| 73 |
+
)
|
| 74 |
+
}
|
| 75 |
+
[Equal.symbol](that: unknown): boolean {
|
| 76 |
+
return isCounterState(that) && this.count === that.count
|
| 77 |
+
}
|
| 78 |
+
pipe() {
|
| 79 |
+
return pipeArguments(this, arguments)
|
| 80 |
+
}
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
const arrayEquals = Arr.getEquivalence(Equal.equals)
|
| 84 |
+
|
| 85 |
+
/** @internal */
|
| 86 |
+
class FrequencyState implements MetricState.MetricState.Frequency {
|
| 87 |
+
readonly [MetricStateTypeId] = metricStateVariance
|
| 88 |
+
readonly [FrequencyStateTypeId]: MetricState.FrequencyStateTypeId = FrequencyStateTypeId
|
| 89 |
+
constructor(readonly occurrences: ReadonlyMap<string, number>) {}
|
| 90 |
+
_hash: number | undefined;
|
| 91 |
+
[Hash.symbol](): number {
|
| 92 |
+
return pipe(
|
| 93 |
+
Hash.string(FrequencyStateSymbolKey),
|
| 94 |
+
Hash.combine(Hash.array(Arr.fromIterable(this.occurrences.entries()))),
|
| 95 |
+
Hash.cached(this)
|
| 96 |
+
)
|
| 97 |
+
}
|
| 98 |
+
[Equal.symbol](that: unknown): boolean {
|
| 99 |
+
return isFrequencyState(that) && arrayEquals(
|
| 100 |
+
Arr.fromIterable(this.occurrences.entries()),
|
| 101 |
+
Arr.fromIterable(that.occurrences.entries())
|
| 102 |
+
)
|
| 103 |
+
}
|
| 104 |
+
pipe() {
|
| 105 |
+
return pipeArguments(this, arguments)
|
| 106 |
+
}
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
/** @internal */
|
| 110 |
+
class GaugeState<A extends (number | bigint)> implements MetricState.MetricState.Gauge<A> {
|
| 111 |
+
readonly [MetricStateTypeId] = metricStateVariance
|
| 112 |
+
readonly [GaugeStateTypeId]: MetricState.GaugeStateTypeId = GaugeStateTypeId
|
| 113 |
+
constructor(readonly value: A) {}
|
| 114 |
+
[Hash.symbol](): number {
|
| 115 |
+
return pipe(
|
| 116 |
+
Hash.hash(GaugeStateSymbolKey),
|
| 117 |
+
Hash.combine(Hash.hash(this.value)),
|
| 118 |
+
Hash.cached(this)
|
| 119 |
+
)
|
| 120 |
+
}
|
| 121 |
+
[Equal.symbol](u: unknown): boolean {
|
| 122 |
+
return isGaugeState(u) && this.value === u.value
|
| 123 |
+
}
|
| 124 |
+
pipe() {
|
| 125 |
+
return pipeArguments(this, arguments)
|
| 126 |
+
}
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
/** @internal */
|
| 130 |
+
export class HistogramState implements MetricState.MetricState.Histogram {
|
| 131 |
+
readonly [MetricStateTypeId] = metricStateVariance
|
| 132 |
+
readonly [HistogramStateTypeId]: MetricState.HistogramStateTypeId = HistogramStateTypeId
|
| 133 |
+
constructor(
|
| 134 |
+
readonly buckets: ReadonlyArray<readonly [number, number]>,
|
| 135 |
+
readonly count: number,
|
| 136 |
+
readonly min: number,
|
| 137 |
+
readonly max: number,
|
| 138 |
+
readonly sum: number
|
| 139 |
+
) {}
|
| 140 |
+
[Hash.symbol](): number {
|
| 141 |
+
return pipe(
|
| 142 |
+
Hash.hash(HistogramStateSymbolKey),
|
| 143 |
+
Hash.combine(Hash.hash(this.buckets)),
|
| 144 |
+
Hash.combine(Hash.hash(this.count)),
|
| 145 |
+
Hash.combine(Hash.hash(this.min)),
|
| 146 |
+
Hash.combine(Hash.hash(this.max)),
|
| 147 |
+
Hash.combine(Hash.hash(this.sum)),
|
| 148 |
+
Hash.cached(this)
|
| 149 |
+
)
|
| 150 |
+
}
|
| 151 |
+
[Equal.symbol](that: unknown): boolean {
|
| 152 |
+
return isHistogramState(that) &&
|
| 153 |
+
Equal.equals(this.buckets, that.buckets) &&
|
| 154 |
+
this.count === that.count &&
|
| 155 |
+
this.min === that.min &&
|
| 156 |
+
this.max === that.max &&
|
| 157 |
+
this.sum === that.sum
|
| 158 |
+
}
|
| 159 |
+
pipe() {
|
| 160 |
+
return pipeArguments(this, arguments)
|
| 161 |
+
}
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
/** @internal */
|
| 165 |
+
export class SummaryState implements MetricState.MetricState.Summary {
|
| 166 |
+
readonly [MetricStateTypeId] = metricStateVariance
|
| 167 |
+
readonly [SummaryStateTypeId]: MetricState.SummaryStateTypeId = SummaryStateTypeId
|
| 168 |
+
constructor(
|
| 169 |
+
readonly error: number,
|
| 170 |
+
readonly quantiles: ReadonlyArray<readonly [number, Option.Option<number>]>,
|
| 171 |
+
readonly count: number,
|
| 172 |
+
readonly min: number,
|
| 173 |
+
readonly max: number,
|
| 174 |
+
readonly sum: number
|
| 175 |
+
) {}
|
| 176 |
+
[Hash.symbol](): number {
|
| 177 |
+
return pipe(
|
| 178 |
+
Hash.hash(SummaryStateSymbolKey),
|
| 179 |
+
Hash.combine(Hash.hash(this.error)),
|
| 180 |
+
Hash.combine(Hash.hash(this.quantiles)),
|
| 181 |
+
Hash.combine(Hash.hash(this.count)),
|
| 182 |
+
Hash.combine(Hash.hash(this.min)),
|
| 183 |
+
Hash.combine(Hash.hash(this.max)),
|
| 184 |
+
Hash.combine(Hash.hash(this.sum)),
|
| 185 |
+
Hash.cached(this)
|
| 186 |
+
)
|
| 187 |
+
}
|
| 188 |
+
[Equal.symbol](that: unknown): boolean {
|
| 189 |
+
return isSummaryState(that) &&
|
| 190 |
+
this.error === that.error &&
|
| 191 |
+
Equal.equals(this.quantiles, that.quantiles) &&
|
| 192 |
+
this.count === that.count &&
|
| 193 |
+
this.min === that.min &&
|
| 194 |
+
this.max === that.max &&
|
| 195 |
+
this.sum === that.sum
|
| 196 |
+
}
|
| 197 |
+
pipe() {
|
| 198 |
+
return pipeArguments(this, arguments)
|
| 199 |
+
}
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
/** @internal */
|
| 203 |
+
export const counter: {
|
| 204 |
+
(count: number): MetricState.MetricState.Counter<number>
|
| 205 |
+
(count: bigint): MetricState.MetricState.Counter<bigint>
|
| 206 |
+
} = (count) => new CounterState(count) as any
|
| 207 |
+
|
| 208 |
+
/** @internal */
|
| 209 |
+
export const frequency = (occurrences: ReadonlyMap<string, number>): MetricState.MetricState.Frequency => {
|
| 210 |
+
return new FrequencyState(occurrences)
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
+
/** @internal */
|
| 214 |
+
export const gauge: {
|
| 215 |
+
(count: number): MetricState.MetricState.Gauge<number>
|
| 216 |
+
(count: bigint): MetricState.MetricState.Gauge<bigint>
|
| 217 |
+
} = (count) => new GaugeState(count) as any
|
| 218 |
+
|
| 219 |
+
/** @internal */
|
| 220 |
+
export const histogram = (
|
| 221 |
+
options: {
|
| 222 |
+
readonly buckets: ReadonlyArray<readonly [number, number]>
|
| 223 |
+
readonly count: number
|
| 224 |
+
readonly min: number
|
| 225 |
+
readonly max: number
|
| 226 |
+
readonly sum: number
|
| 227 |
+
}
|
| 228 |
+
): MetricState.MetricState.Histogram =>
|
| 229 |
+
new HistogramState(
|
| 230 |
+
options.buckets,
|
| 231 |
+
options.count,
|
| 232 |
+
options.min,
|
| 233 |
+
options.max,
|
| 234 |
+
options.sum
|
| 235 |
+
)
|
| 236 |
+
|
| 237 |
+
/** @internal */
|
| 238 |
+
export const summary = (
|
| 239 |
+
options: {
|
| 240 |
+
readonly error: number
|
| 241 |
+
readonly quantiles: ReadonlyArray<readonly [number, Option.Option<number>]>
|
| 242 |
+
readonly count: number
|
| 243 |
+
readonly min: number
|
| 244 |
+
readonly max: number
|
| 245 |
+
readonly sum: number
|
| 246 |
+
}
|
| 247 |
+
): MetricState.MetricState.Summary =>
|
| 248 |
+
new SummaryState(
|
| 249 |
+
options.error,
|
| 250 |
+
options.quantiles,
|
| 251 |
+
options.count,
|
| 252 |
+
options.min,
|
| 253 |
+
options.max,
|
| 254 |
+
options.sum
|
| 255 |
+
)
|
| 256 |
+
|
| 257 |
+
/** @internal */
|
| 258 |
+
export const isMetricState = (u: unknown): u is MetricState.MetricState.Counter<number | bigint> =>
|
| 259 |
+
hasProperty(u, MetricStateTypeId)
|
| 260 |
+
|
| 261 |
+
/** @internal */
|
| 262 |
+
export const isCounterState = (u: unknown): u is MetricState.MetricState.Counter<number | bigint> =>
|
| 263 |
+
hasProperty(u, CounterStateTypeId)
|
| 264 |
+
|
| 265 |
+
/**
|
| 266 |
+
* @since 2.0.0
|
| 267 |
+
* @category refinements
|
| 268 |
+
*/
|
| 269 |
+
export const isFrequencyState = (u: unknown): u is MetricState.MetricState.Frequency =>
|
| 270 |
+
hasProperty(u, FrequencyStateTypeId)
|
| 271 |
+
|
| 272 |
+
/**
|
| 273 |
+
* @since 2.0.0
|
| 274 |
+
* @category refinements
|
| 275 |
+
*/
|
| 276 |
+
export const isGaugeState = (u: unknown): u is MetricState.MetricState.Gauge<number | bigint> =>
|
| 277 |
+
hasProperty(u, GaugeStateTypeId)
|
| 278 |
+
|
| 279 |
+
/**
|
| 280 |
+
* @since 2.0.0
|
| 281 |
+
* @category refinements
|
| 282 |
+
*/
|
| 283 |
+
export const isHistogramState = (u: unknown): u is MetricState.MetricState.Histogram =>
|
| 284 |
+
hasProperty(u, HistogramStateTypeId)
|
| 285 |
+
|
| 286 |
+
/**
|
| 287 |
+
* @since 2.0.0
|
| 288 |
+
* @category refinements
|
| 289 |
+
*/
|
| 290 |
+
export const isSummaryState = (u: unknown): u is MetricState.MetricState.Summary => hasProperty(u, SummaryStateTypeId)
|
backend/node_modules/effect/src/internal/opCodes/channelUpstreamPullStrategy.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/** @internal */
|
| 2 |
+
export const OP_PULL_AFTER_NEXT = "PullAfterNext" as const
|
| 3 |
+
|
| 4 |
+
/** @internal */
|
| 5 |
+
export type OP_PULL_AFTER_NEXT = typeof OP_PULL_AFTER_NEXT
|
| 6 |
+
|
| 7 |
+
/** @internal */
|
| 8 |
+
export const OP_PULL_AFTER_ALL_ENQUEUED = "PullAfterAllEnqueued" as const
|
| 9 |
+
|
| 10 |
+
/** @internal */
|
| 11 |
+
export type OP_PULL_AFTER_ALL_ENQUEUED = typeof OP_PULL_AFTER_ALL_ENQUEUED
|
backend/node_modules/effect/src/internal/schema/util.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import type { NonEmptyReadonlyArray } from "../../Array.js"
|
| 2 |
+
import * as Inspectable from "../../Inspectable.js"
|
| 3 |
+
import type * as ParseResult from "../../ParseResult.js"
|
| 4 |
+
import type * as AST from "../../SchemaAST.js"
|
| 5 |
+
|
| 6 |
+
/** @internal */
|
| 7 |
+
export const getKeysForIndexSignature = (
|
| 8 |
+
input: { readonly [x: PropertyKey]: unknown },
|
| 9 |
+
parameter: AST.Parameter
|
| 10 |
+
): ReadonlyArray<string> | ReadonlyArray<symbol> => {
|
| 11 |
+
switch (parameter._tag) {
|
| 12 |
+
case "StringKeyword":
|
| 13 |
+
case "TemplateLiteral":
|
| 14 |
+
return Object.keys(input)
|
| 15 |
+
case "SymbolKeyword":
|
| 16 |
+
return Object.getOwnPropertySymbols(input)
|
| 17 |
+
case "Refinement":
|
| 18 |
+
return getKeysForIndexSignature(input, parameter.from)
|
| 19 |
+
}
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
/** @internal */
|
| 23 |
+
export const memoizeThunk = <A>(f: () => A): () => A => {
|
| 24 |
+
let done = false
|
| 25 |
+
let a: A
|
| 26 |
+
return () => {
|
| 27 |
+
if (done) {
|
| 28 |
+
return a
|
| 29 |
+
}
|
| 30 |
+
a = f()
|
| 31 |
+
done = true
|
| 32 |
+
return a
|
| 33 |
+
}
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
/** @internal */
|
| 37 |
+
export type SingleOrArray<A> = A | ReadonlyArray<A>
|
| 38 |
+
|
| 39 |
+
/** @internal */
|
| 40 |
+
export const isNonEmpty = <A>(x: ParseResult.SingleOrNonEmpty<A>): x is NonEmptyReadonlyArray<A> => Array.isArray(x)
|
| 41 |
+
|
| 42 |
+
/** @internal */
|
| 43 |
+
export const isSingle = <A>(x: A | ReadonlyArray<A>): x is A => !Array.isArray(x)
|
| 44 |
+
|
| 45 |
+
/** @internal */
|
| 46 |
+
export const formatPathKey = (key: PropertyKey): string => `[${Inspectable.formatPropertyKey(key)}]`
|
| 47 |
+
|
| 48 |
+
/** @internal */
|
| 49 |
+
export const formatPath = (path: ParseResult.Path): string =>
|
| 50 |
+
isNonEmpty(path) ? path.map(formatPathKey).join("") : formatPathKey(path)
|
backend/node_modules/effect/src/internal/supervisor/patch.ts
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import * as Chunk from "../../Chunk.js"
|
| 2 |
+
import * as Differ from "../../Differ.js"
|
| 3 |
+
import * as Equal from "../../Equal.js"
|
| 4 |
+
import { pipe } from "../../Function.js"
|
| 5 |
+
import * as HashSet from "../../HashSet.js"
|
| 6 |
+
import type * as Supervisor from "../../Supervisor.js"
|
| 7 |
+
import * as supervisor from "../supervisor.js"
|
| 8 |
+
|
| 9 |
+
/** @internal */
|
| 10 |
+
export type SupervisorPatch = Empty | AddSupervisor | RemoveSupervisor | AndThen
|
| 11 |
+
|
| 12 |
+
/** @internal */
|
| 13 |
+
export const OP_EMPTY = "Empty" as const
|
| 14 |
+
|
| 15 |
+
/** @internal */
|
| 16 |
+
export type OP_EMPTY = typeof OP_EMPTY
|
| 17 |
+
|
| 18 |
+
/** @internal */
|
| 19 |
+
export const OP_ADD_SUPERVISOR = "AddSupervisor" as const
|
| 20 |
+
|
| 21 |
+
/** @internal */
|
| 22 |
+
export type OP_ADD_SUPERVISOR = typeof OP_ADD_SUPERVISOR
|
| 23 |
+
|
| 24 |
+
/** @internal */
|
| 25 |
+
export const OP_REMOVE_SUPERVISOR = "RemoveSupervisor" as const
|
| 26 |
+
|
| 27 |
+
/** @internal */
|
| 28 |
+
export type OP_REMOVE_SUPERVISOR = typeof OP_REMOVE_SUPERVISOR
|
| 29 |
+
|
| 30 |
+
/** @internal */
|
| 31 |
+
export const OP_AND_THEN = "AndThen" as const
|
| 32 |
+
|
| 33 |
+
/** @internal */
|
| 34 |
+
export type OP_AND_THEN = typeof OP_AND_THEN
|
| 35 |
+
|
| 36 |
+
/** @internal */
|
| 37 |
+
export interface Empty {
|
| 38 |
+
readonly _tag: OP_EMPTY
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
/** @internal */
|
| 42 |
+
export interface AddSupervisor {
|
| 43 |
+
readonly _tag: OP_ADD_SUPERVISOR
|
| 44 |
+
readonly supervisor: Supervisor.Supervisor<any>
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
/** @internal */
|
| 48 |
+
export interface RemoveSupervisor {
|
| 49 |
+
readonly _tag: OP_REMOVE_SUPERVISOR
|
| 50 |
+
readonly supervisor: Supervisor.Supervisor<any>
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
/** @internal */
|
| 54 |
+
export interface AndThen {
|
| 55 |
+
readonly _tag: OP_AND_THEN
|
| 56 |
+
readonly first: SupervisorPatch
|
| 57 |
+
readonly second: SupervisorPatch
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
/**
|
| 61 |
+
* The empty `SupervisorPatch`.
|
| 62 |
+
*
|
| 63 |
+
* @internal
|
| 64 |
+
*/
|
| 65 |
+
export const empty: SupervisorPatch = { _tag: OP_EMPTY }
|
| 66 |
+
|
| 67 |
+
/**
|
| 68 |
+
* Combines two patches to produce a new patch that describes applying the
|
| 69 |
+
* updates from this patch and then the updates from the specified patch.
|
| 70 |
+
*
|
| 71 |
+
* @internal
|
| 72 |
+
*/
|
| 73 |
+
export const combine = (self: SupervisorPatch, that: SupervisorPatch): SupervisorPatch => {
|
| 74 |
+
return {
|
| 75 |
+
_tag: OP_AND_THEN,
|
| 76 |
+
first: self,
|
| 77 |
+
second: that
|
| 78 |
+
}
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
/**
|
| 82 |
+
* Applies a `SupervisorPatch` to a `Supervisor` to produce a new `Supervisor`.
|
| 83 |
+
*
|
| 84 |
+
* @internal
|
| 85 |
+
*/
|
| 86 |
+
export const patch = (
|
| 87 |
+
self: SupervisorPatch,
|
| 88 |
+
supervisor: Supervisor.Supervisor<any>
|
| 89 |
+
): Supervisor.Supervisor<any> => {
|
| 90 |
+
return patchLoop(supervisor, Chunk.of(self))
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
/** @internal */
|
| 94 |
+
const patchLoop = (
|
| 95 |
+
_supervisor: Supervisor.Supervisor<any>,
|
| 96 |
+
_patches: Chunk.Chunk<SupervisorPatch>
|
| 97 |
+
): Supervisor.Supervisor<any> => {
|
| 98 |
+
let supervisor = _supervisor
|
| 99 |
+
let patches = _patches
|
| 100 |
+
while (Chunk.isNonEmpty(patches)) {
|
| 101 |
+
const head = Chunk.headNonEmpty(patches)
|
| 102 |
+
switch (head._tag) {
|
| 103 |
+
case OP_EMPTY: {
|
| 104 |
+
patches = Chunk.tailNonEmpty(patches)
|
| 105 |
+
break
|
| 106 |
+
}
|
| 107 |
+
case OP_ADD_SUPERVISOR: {
|
| 108 |
+
supervisor = supervisor.zip(head.supervisor)
|
| 109 |
+
patches = Chunk.tailNonEmpty(patches)
|
| 110 |
+
break
|
| 111 |
+
}
|
| 112 |
+
case OP_REMOVE_SUPERVISOR: {
|
| 113 |
+
supervisor = removeSupervisor(supervisor, head.supervisor)
|
| 114 |
+
patches = Chunk.tailNonEmpty(patches)
|
| 115 |
+
break
|
| 116 |
+
}
|
| 117 |
+
case OP_AND_THEN: {
|
| 118 |
+
patches = Chunk.prepend(head.first)(Chunk.prepend(head.second)(Chunk.tailNonEmpty(patches)))
|
| 119 |
+
break
|
| 120 |
+
}
|
| 121 |
+
}
|
| 122 |
+
}
|
| 123 |
+
return supervisor
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
/** @internal */
|
| 127 |
+
const removeSupervisor = (
|
| 128 |
+
self: Supervisor.Supervisor<any>,
|
| 129 |
+
that: Supervisor.Supervisor<any>
|
| 130 |
+
): Supervisor.Supervisor<any> => {
|
| 131 |
+
if (Equal.equals(self, that)) {
|
| 132 |
+
return supervisor.none
|
| 133 |
+
} else {
|
| 134 |
+
if (supervisor.isZip(self)) {
|
| 135 |
+
return removeSupervisor(self.left, that).zip(removeSupervisor(self.right, that))
|
| 136 |
+
} else {
|
| 137 |
+
return self
|
| 138 |
+
}
|
| 139 |
+
}
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
/** @internal */
|
| 143 |
+
const toSet = (self: Supervisor.Supervisor<any>): HashSet.HashSet<Supervisor.Supervisor<any>> => {
|
| 144 |
+
if (Equal.equals(self, supervisor.none)) {
|
| 145 |
+
return HashSet.empty()
|
| 146 |
+
} else {
|
| 147 |
+
if (supervisor.isZip(self)) {
|
| 148 |
+
return pipe(toSet(self.left), HashSet.union(toSet(self.right)))
|
| 149 |
+
} else {
|
| 150 |
+
return HashSet.make(self)
|
| 151 |
+
}
|
| 152 |
+
}
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
/** @internal */
|
| 156 |
+
export const diff = (
|
| 157 |
+
oldValue: Supervisor.Supervisor<any>,
|
| 158 |
+
newValue: Supervisor.Supervisor<any>
|
| 159 |
+
): SupervisorPatch => {
|
| 160 |
+
if (Equal.equals(oldValue, newValue)) {
|
| 161 |
+
return empty
|
| 162 |
+
}
|
| 163 |
+
const oldSupervisors = toSet(oldValue)
|
| 164 |
+
const newSupervisors = toSet(newValue)
|
| 165 |
+
const added = pipe(
|
| 166 |
+
newSupervisors,
|
| 167 |
+
HashSet.difference(oldSupervisors),
|
| 168 |
+
HashSet.reduce(
|
| 169 |
+
empty as SupervisorPatch,
|
| 170 |
+
(patch, supervisor) => combine(patch, { _tag: OP_ADD_SUPERVISOR, supervisor })
|
| 171 |
+
)
|
| 172 |
+
)
|
| 173 |
+
const removed = pipe(
|
| 174 |
+
oldSupervisors,
|
| 175 |
+
HashSet.difference(newSupervisors),
|
| 176 |
+
HashSet.reduce(
|
| 177 |
+
empty as SupervisorPatch,
|
| 178 |
+
(patch, supervisor) => combine(patch, { _tag: OP_REMOVE_SUPERVISOR, supervisor })
|
| 179 |
+
)
|
| 180 |
+
)
|
| 181 |
+
return combine(added, removed)
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
/** @internal */
|
| 185 |
+
export const differ = Differ.make<Supervisor.Supervisor<any>, SupervisorPatch>({
|
| 186 |
+
empty,
|
| 187 |
+
patch,
|
| 188 |
+
combine,
|
| 189 |
+
diff
|
| 190 |
+
})
|
backend/node_modules/perfect-debounce/dist/index.cjs
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use strict';
|
| 2 |
+
|
| 3 |
+
const DEBOUNCE_DEFAULTS = {
|
| 4 |
+
trailing: true
|
| 5 |
+
};
|
| 6 |
+
function debounce(fn, wait = 25, options = {}) {
|
| 7 |
+
options = { ...DEBOUNCE_DEFAULTS, ...options };
|
| 8 |
+
if (!Number.isFinite(wait)) {
|
| 9 |
+
throw new TypeError("Expected `wait` to be a finite number");
|
| 10 |
+
}
|
| 11 |
+
let leadingValue;
|
| 12 |
+
let timeout;
|
| 13 |
+
let resolveList = [];
|
| 14 |
+
let currentPromise;
|
| 15 |
+
let trailingArgs;
|
| 16 |
+
const applyFn = (_this, args) => {
|
| 17 |
+
currentPromise = _applyPromised(fn, _this, args);
|
| 18 |
+
currentPromise.finally(() => {
|
| 19 |
+
currentPromise = null;
|
| 20 |
+
if (options.trailing && trailingArgs && !timeout) {
|
| 21 |
+
const promise = applyFn(_this, trailingArgs);
|
| 22 |
+
trailingArgs = null;
|
| 23 |
+
return promise;
|
| 24 |
+
}
|
| 25 |
+
});
|
| 26 |
+
return currentPromise;
|
| 27 |
+
};
|
| 28 |
+
return function(...args) {
|
| 29 |
+
if (currentPromise) {
|
| 30 |
+
if (options.trailing) {
|
| 31 |
+
trailingArgs = args;
|
| 32 |
+
}
|
| 33 |
+
return currentPromise;
|
| 34 |
+
}
|
| 35 |
+
return new Promise((resolve) => {
|
| 36 |
+
const shouldCallNow = !timeout && options.leading;
|
| 37 |
+
clearTimeout(timeout);
|
| 38 |
+
timeout = setTimeout(() => {
|
| 39 |
+
timeout = null;
|
| 40 |
+
const promise = options.leading ? leadingValue : applyFn(this, args);
|
| 41 |
+
for (const _resolve of resolveList) {
|
| 42 |
+
_resolve(promise);
|
| 43 |
+
}
|
| 44 |
+
resolveList = [];
|
| 45 |
+
}, wait);
|
| 46 |
+
if (shouldCallNow) {
|
| 47 |
+
leadingValue = applyFn(this, args);
|
| 48 |
+
resolve(leadingValue);
|
| 49 |
+
} else {
|
| 50 |
+
resolveList.push(resolve);
|
| 51 |
+
}
|
| 52 |
+
});
|
| 53 |
+
};
|
| 54 |
+
}
|
| 55 |
+
async function _applyPromised(fn, _this, args) {
|
| 56 |
+
return await fn.apply(_this, args);
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
exports.debounce = debounce;
|
backend/node_modules/perfect-debounce/dist/index.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
interface DebounceOptions {
|
| 2 |
+
/**
|
| 3 |
+
Call the `fn` on the [leading edge of the timeout](https://css-tricks.com/debouncing-throttling-explained-examples/#article-header-id-1).
|
| 4 |
+
Meaning immediately, instead of waiting for `wait` milliseconds.
|
| 5 |
+
@default false
|
| 6 |
+
*/
|
| 7 |
+
readonly leading?: boolean;
|
| 8 |
+
/**
|
| 9 |
+
Call the `fn` on trailing edge with last used arguments. Result of call is from previous call.
|
| 10 |
+
@default false
|
| 11 |
+
*/
|
| 12 |
+
readonly trailing?: boolean;
|
| 13 |
+
}
|
| 14 |
+
/**
|
| 15 |
+
Debounce functions
|
| 16 |
+
@param fn - Promise-returning/async function to debounce.
|
| 17 |
+
@param wait - Milliseconds to wait before calling `fn`. Default value is 25ms
|
| 18 |
+
@returns A function that delays calling `fn` until after `wait` milliseconds have elapsed since the last time it was called.
|
| 19 |
+
@example
|
| 20 |
+
```
|
| 21 |
+
import { debounce } from 'perfect-debounce';
|
| 22 |
+
const expensiveCall = async input => input;
|
| 23 |
+
const debouncedFn = debounce(expensiveCall, 200);
|
| 24 |
+
for (const number of [1, 2, 3]) {
|
| 25 |
+
console.log(await debouncedFn(number));
|
| 26 |
+
}
|
| 27 |
+
//=> 3
|
| 28 |
+
//=> 3
|
| 29 |
+
//=> 3
|
| 30 |
+
```
|
| 31 |
+
*/
|
| 32 |
+
declare function debounce<ArgumentsT extends unknown[], ReturnT>(fn: (...args: ArgumentsT) => PromiseLike<ReturnT> | ReturnT, wait?: number, options?: DebounceOptions): (...args: ArgumentsT) => Promise<ReturnT>;
|
| 33 |
+
|
| 34 |
+
export { DebounceOptions, debounce };
|
backend/node_modules/perfect-debounce/dist/index.mjs
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const DEBOUNCE_DEFAULTS = {
|
| 2 |
+
trailing: true
|
| 3 |
+
};
|
| 4 |
+
function debounce(fn, wait = 25, options = {}) {
|
| 5 |
+
options = { ...DEBOUNCE_DEFAULTS, ...options };
|
| 6 |
+
if (!Number.isFinite(wait)) {
|
| 7 |
+
throw new TypeError("Expected `wait` to be a finite number");
|
| 8 |
+
}
|
| 9 |
+
let leadingValue;
|
| 10 |
+
let timeout;
|
| 11 |
+
let resolveList = [];
|
| 12 |
+
let currentPromise;
|
| 13 |
+
let trailingArgs;
|
| 14 |
+
const applyFn = (_this, args) => {
|
| 15 |
+
currentPromise = _applyPromised(fn, _this, args);
|
| 16 |
+
currentPromise.finally(() => {
|
| 17 |
+
currentPromise = null;
|
| 18 |
+
if (options.trailing && trailingArgs && !timeout) {
|
| 19 |
+
const promise = applyFn(_this, trailingArgs);
|
| 20 |
+
trailingArgs = null;
|
| 21 |
+
return promise;
|
| 22 |
+
}
|
| 23 |
+
});
|
| 24 |
+
return currentPromise;
|
| 25 |
+
};
|
| 26 |
+
return function(...args) {
|
| 27 |
+
if (currentPromise) {
|
| 28 |
+
if (options.trailing) {
|
| 29 |
+
trailingArgs = args;
|
| 30 |
+
}
|
| 31 |
+
return currentPromise;
|
| 32 |
+
}
|
| 33 |
+
return new Promise((resolve) => {
|
| 34 |
+
const shouldCallNow = !timeout && options.leading;
|
| 35 |
+
clearTimeout(timeout);
|
| 36 |
+
timeout = setTimeout(() => {
|
| 37 |
+
timeout = null;
|
| 38 |
+
const promise = options.leading ? leadingValue : applyFn(this, args);
|
| 39 |
+
for (const _resolve of resolveList) {
|
| 40 |
+
_resolve(promise);
|
| 41 |
+
}
|
| 42 |
+
resolveList = [];
|
| 43 |
+
}, wait);
|
| 44 |
+
if (shouldCallNow) {
|
| 45 |
+
leadingValue = applyFn(this, args);
|
| 46 |
+
resolve(leadingValue);
|
| 47 |
+
} else {
|
| 48 |
+
resolveList.push(resolve);
|
| 49 |
+
}
|
| 50 |
+
});
|
| 51 |
+
};
|
| 52 |
+
}
|
| 53 |
+
async function _applyPromised(fn, _this, args) {
|
| 54 |
+
return await fn.apply(_this, args);
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
export { debounce };
|
backend/node_modules/prisma/build/child.js
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
backend/node_modules/prisma/build/prisma_schema_build_bg.wasm
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:bca8b35bd5ebe0164323d5f761a7a5075fa6ad00e1dfc7906e9da5d4c13c0287
|
| 3 |
+
size 2966822
|
backend/node_modules/prisma/build/public/assets/alert.60ea9f84.svg
ADDED
|
|
backend/node_modules/prisma/build/public/assets/array.1a36c222.svg
ADDED
|
|
backend/node_modules/prisma/build/public/assets/boolean.9188b434.svg
ADDED
|
|
backend/node_modules/prisma/build/public/assets/chevron-down.24f76e3c.svg
ADDED
|
|
backend/node_modules/prisma/build/public/assets/cross.c2610cf5.svg
ADDED
|
|
backend/node_modules/prisma/build/public/assets/datetime.a3bf710a.svg
ADDED
|
|
backend/node_modules/prisma/build/public/assets/download.8d34b65a.svg
ADDED
|
|
backend/node_modules/prisma/build/public/assets/ellipsis.a8c5a34a.svg
ADDED
|
|
backend/node_modules/prisma/build/public/assets/enum.7ec0b64c.svg
ADDED
|
|
backend/node_modules/prisma/build/public/assets/folder.d77b8eaf.svg
ADDED
|
|
backend/node_modules/prisma/build/public/assets/hamburger.5fdadeac.svg
ADDED
|
|
backend/node_modules/prisma/build/public/assets/index.js
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
backend/node_modules/prisma/build/public/assets/inter-all-400-normal.4c1f8a0d.woff
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4c1f8a0d5ef1e04d7e14d194a4ef624345e7c7c1cdb4ff61d4552e32a60ac1d0
|
| 3 |
+
size 121716
|
backend/node_modules/prisma/build/public/assets/inter-all-600-normal.d0a7c8a9.woff
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d0a7c8a993b9310ebb74a893fa564133bc129f6af41126eb98d207c813b96093
|
| 3 |
+
size 131632
|
backend/node_modules/prisma/build/public/assets/inter-cyrillic-400-normal.ac97a49e.woff2
ADDED
|
Binary file (6.5 kB). View file
|
|
|
backend/node_modules/prisma/build/public/assets/inter-cyrillic-600-normal.2c917f10.woff2
ADDED
|
Binary file (6.93 kB). View file
|
|
|
backend/node_modules/prisma/build/public/assets/inter-cyrillic-ext-400-normal.f21a6a97.woff2
ADDED
|
Binary file (9.75 kB). View file
|
|
|