@kikiutils/shared 13.3.0 → 13.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,133 @@
1
+ import { Decimal } from "decimal.js";
2
+
3
+ //#region src/classes/precision-number.ts
4
+ /**
5
+ * Class representing a precision number with configurable decimal places and rounding.
6
+ *
7
+ * This class leverages the Decimal.js library to ensure accurate arithmetic operations
8
+ * with floating point numbers. It provides methods for various arithmetic operations
9
+ * (addition, subtraction, multiplication, division) as well as comparison and utility
10
+ * methods to check the state of the number (e.g., if it is finite, an integer, zero, etc.).
11
+ *
12
+ * The class also includes custom symbol methods to support Node.js inspection and primitive
13
+ * type conversion.
14
+ *
15
+ * The class supports in-place modification methods that alter the current instance's value,
16
+ * such as `plus`, `minus`, `times`, `dividedBy`, and others. Additionally, methods prefixed
17
+ * with `to` (e.g., `toPlus`, `toMinus`) return a new instance of `PrecisionNumber` with the
18
+ * modified value, leaving the original instance unchanged.
19
+ */
20
+ var PrecisionNumber = class PrecisionNumber {
21
+ #decimalPlaces;
22
+ #rounding;
23
+ #decimal;
24
+ constructor(value = "0", decimalPlaces = 2, rounding = Decimal.ROUND_DOWN) {
25
+ this.#decimalPlaces = decimalPlaces;
26
+ this.#rounding = rounding;
27
+ this.#decimal = this.#decimalToFixedDecimal(new Decimal(value.toString().trim()));
28
+ }
29
+ [Symbol.for("nodejs.util.inspect.custom")]() {
30
+ return this.value;
31
+ }
32
+ [Symbol.toPrimitive](hint) {
33
+ if (hint === "number") return this.#decimal.toNumber();
34
+ return this.value;
35
+ }
36
+ #decimalToFixedDecimal(decimal) {
37
+ return decimal.toDecimalPlaces(this.#decimalPlaces, this.#rounding);
38
+ }
39
+ get value() {
40
+ return this.#decimal.toFixed(this.#decimalPlaces, this.#rounding);
41
+ }
42
+ static toFixed(value, decimalPlaces = 2, rounding = Decimal.ROUND_DOWN) {
43
+ return new Decimal(value.toString().trim()).toFixed(decimalPlaces, rounding);
44
+ }
45
+ absoluteValue() {
46
+ this.#decimal = this.#decimalToFixedDecimal(this.#decimal.absoluteValue());
47
+ return this;
48
+ }
49
+ dividedBy(value) {
50
+ this.#decimal = this.#decimalToFixedDecimal(this.#decimal.dividedBy(value.toString().trim()));
51
+ return this;
52
+ }
53
+ equals(value) {
54
+ return this.#decimal.equals(value.toString().trim());
55
+ }
56
+ gt(value) {
57
+ return this.#decimal.gt(value.toString().trim());
58
+ }
59
+ gte(value) {
60
+ return this.#decimal.gte(value.toString().trim());
61
+ }
62
+ isFinite() {
63
+ return this.#decimal.isFinite();
64
+ }
65
+ isInteger() {
66
+ return this.#decimal.isInteger();
67
+ }
68
+ isNaN() {
69
+ return this.#decimal.isNaN();
70
+ }
71
+ isNegative() {
72
+ return this.#decimal.isNegative();
73
+ }
74
+ isPositive() {
75
+ return this.#decimal.isPositive();
76
+ }
77
+ isZero() {
78
+ return this.#decimal.isZero();
79
+ }
80
+ lt(value) {
81
+ return this.#decimal.lt(value.toString().trim());
82
+ }
83
+ lte(value) {
84
+ return this.#decimal.lte(value.toString().trim());
85
+ }
86
+ minus(value) {
87
+ this.#decimal = this.#decimalToFixedDecimal(this.#decimal.minus(value.toString().trim()));
88
+ return this;
89
+ }
90
+ negate() {
91
+ this.#decimal = this.#decimalToFixedDecimal(this.#decimal.negated());
92
+ return this;
93
+ }
94
+ plus(value) {
95
+ this.#decimal = this.#decimalToFixedDecimal(this.#decimal.plus(value.toString().trim()));
96
+ return this;
97
+ }
98
+ times(value) {
99
+ this.#decimal = this.#decimalToFixedDecimal(this.#decimal.times(value.toString().trim()));
100
+ return this;
101
+ }
102
+ toAbsoluteValue() {
103
+ return new PrecisionNumber(this.#decimal.absoluteValue(), this.#decimalPlaces, this.#rounding);
104
+ }
105
+ toDividedBy(value) {
106
+ return new PrecisionNumber(this.#decimal.dividedBy(value.toString().trim()), this.#decimalPlaces, this.#rounding);
107
+ }
108
+ toJSON() {
109
+ return this.value;
110
+ }
111
+ toMinus(value) {
112
+ return new PrecisionNumber(this.#decimal.minus(value.toString().trim()), this.#decimalPlaces, this.#rounding);
113
+ }
114
+ toNegated() {
115
+ return new PrecisionNumber(this.#decimal.negated(), this.#decimalPlaces, this.#rounding);
116
+ }
117
+ toPlus(value) {
118
+ return new PrecisionNumber(this.#decimal.plus(value.toString().trim()), this.#decimalPlaces, this.#rounding);
119
+ }
120
+ toString() {
121
+ return this.value;
122
+ }
123
+ toFixed(decimalPlaces = this.#decimalPlaces, rounding = this.#rounding) {
124
+ return this.#decimal.toFixed(decimalPlaces, rounding);
125
+ }
126
+ toTimes(value) {
127
+ return new PrecisionNumber(this.#decimal.times(value.toString().trim()), this.#decimalPlaces, this.#rounding);
128
+ }
129
+ };
130
+
131
+ //#endregion
132
+ export { PrecisionNumber };
133
+ //# sourceMappingURL=precision-number.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"precision-number.js","names":["#decimalPlaces","#rounding","#decimal","#decimalToFixedDecimal"],"sources":["../../src/classes/precision-number.ts"],"sourcesContent":["import { Decimal } from 'decimal.js';\n\nexport type PrecisionNumberValue = Decimal.Value | PrecisionNumber | { toString: () => string };\n\n/**\n * Class representing a precision number with configurable decimal places and rounding.\n *\n * This class leverages the Decimal.js library to ensure accurate arithmetic operations\n * with floating point numbers. It provides methods for various arithmetic operations\n * (addition, subtraction, multiplication, division) as well as comparison and utility\n * methods to check the state of the number (e.g., if it is finite, an integer, zero, etc.).\n *\n * The class also includes custom symbol methods to support Node.js inspection and primitive\n * type conversion.\n *\n * The class supports in-place modification methods that alter the current instance's value,\n * such as `plus`, `minus`, `times`, `dividedBy`, and others. Additionally, methods prefixed\n * with `to` (e.g., `toPlus`, `toMinus`) return a new instance of `PrecisionNumber` with the\n * modified value, leaving the original instance unchanged.\n */\nexport class PrecisionNumber {\n // Private properties\n readonly #decimalPlaces: number;\n readonly #rounding: Decimal.Rounding;\n #decimal: Decimal;\n\n constructor(\n value: PrecisionNumberValue = '0',\n decimalPlaces: number = 2,\n rounding: Decimal.Rounding = Decimal.ROUND_DOWN,\n ) {\n this.#decimalPlaces = decimalPlaces;\n this.#rounding = rounding;\n this.#decimal = this.#decimalToFixedDecimal(new Decimal(value.toString().trim()));\n }\n\n // Symbols\n [Symbol.for('nodejs.util.inspect.custom')]() {\n return this.value;\n }\n\n [Symbol.toPrimitive](hint: string) {\n if (hint === 'number') return this.#decimal.toNumber();\n return this.value;\n }\n\n // Private methods\n #decimalToFixedDecimal(decimal: Decimal) {\n return decimal.toDecimalPlaces(this.#decimalPlaces, this.#rounding);\n }\n\n // Public getters\n get value() {\n return this.#decimal.toFixed(this.#decimalPlaces, this.#rounding);\n }\n\n // Static methods\n static toFixed(\n value: PrecisionNumberValue,\n decimalPlaces: number = 2,\n rounding: Decimal.Rounding = Decimal.ROUND_DOWN,\n ) {\n return new Decimal(value.toString().trim()).toFixed(decimalPlaces, rounding);\n }\n\n // Public methods\n absoluteValue() {\n this.#decimal = this.#decimalToFixedDecimal(this.#decimal.absoluteValue());\n return this;\n }\n\n dividedBy(value: PrecisionNumberValue) {\n this.#decimal = this.#decimalToFixedDecimal(this.#decimal.dividedBy(value.toString().trim()));\n return this;\n }\n\n equals(value: PrecisionNumberValue) {\n return this.#decimal.equals(value.toString().trim());\n }\n\n gt(value: PrecisionNumberValue) {\n return this.#decimal.gt(value.toString().trim());\n }\n\n gte(value: PrecisionNumberValue) {\n return this.#decimal.gte(value.toString().trim());\n }\n\n isFinite() {\n return this.#decimal.isFinite();\n }\n\n isInteger() {\n return this.#decimal.isInteger();\n }\n\n isNaN() {\n return this.#decimal.isNaN();\n }\n\n isNegative() {\n return this.#decimal.isNegative();\n }\n\n isPositive() {\n return this.#decimal.isPositive();\n }\n\n isZero() {\n return this.#decimal.isZero();\n }\n\n lt(value: PrecisionNumberValue) {\n return this.#decimal.lt(value.toString().trim());\n }\n\n lte(value: PrecisionNumberValue) {\n return this.#decimal.lte(value.toString().trim());\n }\n\n minus(value: PrecisionNumberValue) {\n this.#decimal = this.#decimalToFixedDecimal(this.#decimal.minus(value.toString().trim()));\n return this;\n }\n\n negate() {\n this.#decimal = this.#decimalToFixedDecimal(this.#decimal.negated());\n return this;\n }\n\n plus(value: PrecisionNumberValue) {\n this.#decimal = this.#decimalToFixedDecimal(this.#decimal.plus(value.toString().trim()));\n return this;\n }\n\n times(value: PrecisionNumberValue) {\n this.#decimal = this.#decimalToFixedDecimal(this.#decimal.times(value.toString().trim()));\n return this;\n }\n\n toAbsoluteValue() {\n return new PrecisionNumber(this.#decimal.absoluteValue(), this.#decimalPlaces, this.#rounding);\n }\n\n toDividedBy(value: PrecisionNumberValue) {\n return new PrecisionNumber(\n this.#decimal.dividedBy(value.toString().trim()),\n this.#decimalPlaces,\n this.#rounding,\n );\n }\n\n toJSON() {\n return this.value;\n }\n\n toMinus(value: PrecisionNumberValue) {\n return new PrecisionNumber(this.#decimal.minus(value.toString().trim()), this.#decimalPlaces, this.#rounding);\n }\n\n toNegated() {\n return new PrecisionNumber(this.#decimal.negated(), this.#decimalPlaces, this.#rounding);\n }\n\n toPlus(value: PrecisionNumberValue) {\n return new PrecisionNumber(this.#decimal.plus(value.toString().trim()), this.#decimalPlaces, this.#rounding);\n }\n\n toString() {\n return this.value;\n }\n\n toFixed(decimalPlaces: number = this.#decimalPlaces, rounding: Decimal.Rounding = this.#rounding) {\n return this.#decimal.toFixed(decimalPlaces, rounding);\n }\n\n toTimes(value: PrecisionNumberValue) {\n return new PrecisionNumber(this.#decimal.times(value.toString().trim()), this.#decimalPlaces, this.#rounding);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { PathLike } from "./path.js";
2
+ import { Nullable } from "../types/index.js";
3
+ import * as node_ssh0 from "node-ssh";
4
+ import { Config, NodeSSH, SSHExecCommandOptions, SSHGetPutDirectoryOptions, SSHPutFilesOptions } from "node-ssh";
5
+ import { SFTPWrapper, TransferOptions } from "ssh2";
6
+
7
+ //#region src/classes/ssh-client.d.ts
8
+ declare const loggerLevelStringToConsolaLogLevelMap: {
9
+ readonly debug: 4;
10
+ readonly error: 0;
11
+ readonly fatal: 0;
12
+ readonly info: 3;
13
+ readonly normal: 2;
14
+ readonly silent: -999;
15
+ readonly trace: 5;
16
+ readonly verbose: 999;
17
+ readonly warn: 1;
18
+ };
19
+ declare class SshClient {
20
+ #private;
21
+ constructor(host: string, username: string, password: string, port?: number, connectConfig?: Config);
22
+ get nodeSsh(): NodeSSH;
23
+ connect(): Promise<boolean>;
24
+ disconnect(): boolean;
25
+ execCommand(command: string, options?: SSHExecCommandOptions): Promise<void | node_ssh0.SSHExecCommandResponse>;
26
+ execCommandWithIo(command: string, options?: SSHExecCommandOptions): Promise<void | node_ssh0.SSHExecCommandResponse>;
27
+ getDir: (localDirectory: PathLike, remoteDirectory: PathLike, options?: SSHGetPutDirectoryOptions) => Promise<boolean>;
28
+ getDirectory(localDirectory: PathLike, remoteDirectory: PathLike, options?: SSHGetPutDirectoryOptions): Promise<boolean>;
29
+ getFile(localFile: PathLike, remoteFile: PathLike, givenSftp?: Nullable<SFTPWrapper>, transferOptions?: Nullable<TransferOptions>): Promise<boolean>;
30
+ isConnected(): boolean;
31
+ mkdir(path: PathLike): Promise<boolean>;
32
+ putDir: (localDirectory: PathLike, remoteDirectory: PathLike, options?: SSHGetPutDirectoryOptions) => Promise<boolean>;
33
+ putDirectory(localDirectory: PathLike, remoteDirectory: PathLike, options?: SSHGetPutDirectoryOptions): Promise<boolean>;
34
+ putFile(localFile: PathLike, remoteFile: PathLike, givenSftp?: Nullable<SFTPWrapper>, transferOptions?: Nullable<TransferOptions>): Promise<boolean>;
35
+ putFiles(files: {
36
+ local: PathLike;
37
+ remote: PathLike;
38
+ }[], options?: SSHPutFilesOptions): Promise<boolean>;
39
+ setLoggerLevel(level: keyof typeof loggerLevelStringToConsolaLogLevelMap): void;
40
+ }
41
+ //#endregion
42
+ export { SshClient };
43
+ //# sourceMappingURL=ssh-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssh-client.d.ts","names":[],"sources":["../../src/classes/ssh-client.ts"],"sourcesContent":[],"mappings":";;;;;;;cAkBM;;EAAA,SAAA,KAAA,EAAA,CAAA;EAYO,SAAA,KAAS,EAAA,CAAA;EAAA,SAAA,IAAA,EAAA,CAAA;WAM+E,MAAA,EAAA,CAAA;WActF,MAAA,EAAA,CAAA,GAAA;WAIE,KAAA,EAAA,CAAA;WAoB0B,OAAA,EAAA,GAAA;WAAqB,IAAA,EAAA,CAAA;;AAIf,cAhDpC,SAAA,CAgDoC;UAAqB;aAAA,CAAA,IAAA,EAAA,MAAA,EAAA,QAAA,EAAA,MAAA,EAAA,QAAA,EAAA,MAAA,EAAA,IAAA,CAAA,EAAA,MAAA,EAAA,aAAA,CAAA,EA1C+B,MA0C/B;MAa/B,OAAA,CAAA,CAAA,EAzCxB,OAyCwB;SAA2B,CAAA,CAAA,EArCjD,OAqCiD,CAAA,OAAA,CAAA;YAAoB,CAAA,CAAA,EAAA,OAAA;aAAyB,CAAA,OAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAjBpE,qBAiBoE,CAAA,EAjB/C,OAiB+C,CAAA,IAAA,GAjB/C,SAAA,CAAA,sBAiB+C,CAAA;mBAAxE,CAAA,OAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAbU,qBAaV,CAAA,EAb+B,OAa/B,CAAA,IAAA,GAb+B,SAAA,CAAA,sBAa/B,CAAA;QAA2B,EAAA,CAAA,cAAA,EAA3B,QAA2B,EAAA,eAAA,EAAA,QAAA,EAAA,OAAA,CAAA,EAAoB,yBAApB,EAAA,GAA6C,OAA7C,CAAA,OAAA,CAAA;cAAoB,CAAA,cAAA,EAA/C,QAA+C,EAAA,eAAA,EAApB,QAAoB,EAAA,OAAA,CAAA,EAAA,yBAAA,CAAA,EAAyB,OAAzB,CAAA,OAAA,CAAA;SAAyB,CAAA,SAAA,EAU5F,QAV4F,EAAA,UAAA,EAW3F,QAX2F,EAAA,SAAA,CAAA,EAY3F,QAZ2F,CAYlF,WAZkF,CAAA,EAAA,eAAA,CAAA,EAarF,QAbqF,CAa5E,eAb4E,CAAA,CAAA,EAa5D,OAb4D,CAAA,OAAA,CAAA;aAU5F,CAAA,CAAA,EAAA,OAAA;OACC,CAAA,IAAA,EAiBE,QAjBF,CAAA,EAiBU,OAjBV,CAAA,OAAA,CAAA;QACS,EAAA,CAAA,cAAA,EA4BU,QA5BV,EAAA,eAAA,EA4BqC,QA5BrC,EAAA,OAAA,CAAA,EA4ByD,yBA5BzD,EAAA,GA4BkF,OA5BlF,CAAA,OAAA,CAAA;cAAT,CAAA,cAAA,EA4BmB,QA5BnB,EAAA,eAAA,EA4B8C,QA5B9C,EAAA,OAAA,CAAA,EA4BkE,yBA5BlE,CAAA,EA4B2F,OA5B3F,CAAA,OAAA,CAAA;SACe,CAAA,SAAA,EAqChB,QArCgB,EAAA,UAAA,EAsCf,QAtCe,EAAA,SAAA,CAAA,EAuCf,QAvCe,CAuCN,WAvCM,CAAA,EAAA,eAAA,CAAA,EAwCT,QAxCS,CAwCA,eAxCA,CAAA,CAAA,EAwCgB,OAxChB,CAAA,OAAA,CAAA;UAAT,CAAA,KAAA,EAAA;IAAyB,KAAA,EAmDhB,QAnDgB;IAe7B,MAAA,EAoC+B,QApC/B;KAAQ,EAAA,OAAA,CAAA,EAoC+C,kBApC/C,CAAA,EAoCiE,OApCjE,CAAA,OAAA,CAAA;gBAYS,CAAA,KAAA,EAAA,MAAA,OAuCA,qCAvCA,CAAA,EAAA,IAAA"}
@@ -0,0 +1,131 @@
1
+ import { createConsola } from "consola";
2
+ import { NodeSSH } from "node-ssh";
3
+
4
+ //#region src/classes/ssh-client.ts
5
+ const loggerLevelStringToConsolaLogLevelMap = {
6
+ debug: 4,
7
+ error: 0,
8
+ fatal: 0,
9
+ info: 3,
10
+ normal: 2,
11
+ silent: -999,
12
+ trace: 5,
13
+ verbose: 999,
14
+ warn: 1
15
+ };
16
+ var SshClient = class {
17
+ #connectConfig;
18
+ #logger;
19
+ #nodeSsh;
20
+ constructor(host, username, password, port = 22, connectConfig) {
21
+ this.#connectConfig = {
22
+ ...connectConfig,
23
+ host,
24
+ password,
25
+ port,
26
+ username
27
+ };
28
+ this.#logger = createConsola();
29
+ this.#nodeSsh = new NodeSSH();
30
+ if (process.env.NODE_ENV === "production") this.setLoggerLevel("error");
31
+ }
32
+ get nodeSsh() {
33
+ return this.#nodeSsh;
34
+ }
35
+ async connect() {
36
+ try {
37
+ this.#nodeSsh = await this.#nodeSsh.connect(this.#connectConfig);
38
+ return true;
39
+ } catch (error) {
40
+ this.#logger.error(error);
41
+ return false;
42
+ }
43
+ }
44
+ disconnect() {
45
+ try {
46
+ this.#nodeSsh.dispose();
47
+ return true;
48
+ } catch (error) {
49
+ this.#logger.error(error);
50
+ return false;
51
+ }
52
+ }
53
+ execCommand(command, options) {
54
+ return this.#nodeSsh.execCommand(command, options).catch(() => {});
55
+ }
56
+ execCommandWithIo(command, options) {
57
+ return this.execCommand(command, {
58
+ ...options,
59
+ onStderr: (data) => process.stderr.write(data.toString()),
60
+ onStdout: (data) => process.stdout.write(data.toString())
61
+ });
62
+ }
63
+ getDir = this.getDirectory;
64
+ async getDirectory(localDirectory, remoteDirectory, options) {
65
+ try {
66
+ return await this.#nodeSsh.getDirectory(localDirectory.toString(), remoteDirectory.toString(), options);
67
+ } catch (error) {
68
+ this.#logger.error(error);
69
+ return false;
70
+ }
71
+ }
72
+ async getFile(localFile, remoteFile, givenSftp, transferOptions) {
73
+ try {
74
+ await this.#nodeSsh.getFile(localFile.toString(), remoteFile.toString(), givenSftp, transferOptions);
75
+ return true;
76
+ } catch (error) {
77
+ this.#logger.error(error);
78
+ return false;
79
+ }
80
+ }
81
+ isConnected() {
82
+ return this.#nodeSsh.isConnected();
83
+ }
84
+ async mkdir(path) {
85
+ try {
86
+ await this.#nodeSsh.mkdir(path.toString());
87
+ return true;
88
+ } catch (error) {
89
+ this.#logger.error(error);
90
+ return false;
91
+ }
92
+ }
93
+ putDir = this.putDirectory;
94
+ async putDirectory(localDirectory, remoteDirectory, options) {
95
+ try {
96
+ return await this.#nodeSsh.putDirectory(localDirectory.toString(), remoteDirectory.toString(), options);
97
+ } catch (error) {
98
+ this.#logger.error(error);
99
+ return false;
100
+ }
101
+ }
102
+ async putFile(localFile, remoteFile, givenSftp, transferOptions) {
103
+ try {
104
+ await this.#nodeSsh.putFile(localFile.toString(), remoteFile.toString(), givenSftp, transferOptions);
105
+ return true;
106
+ } catch (error) {
107
+ this.#logger.error(error);
108
+ return false;
109
+ }
110
+ }
111
+ async putFiles(files, options) {
112
+ try {
113
+ const convertedFiles = files.map(({ local, remote }) => ({
114
+ local: local.toString(),
115
+ remote: remote.toString()
116
+ }));
117
+ await this.#nodeSsh.putFiles(convertedFiles, options);
118
+ return true;
119
+ } catch (error) {
120
+ this.#logger.error(error);
121
+ return false;
122
+ }
123
+ }
124
+ setLoggerLevel(level) {
125
+ this.#logger.level = loggerLevelStringToConsolaLogLevelMap[level];
126
+ }
127
+ };
128
+
129
+ //#endregion
130
+ export { SshClient };
131
+ //# sourceMappingURL=ssh-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssh-client.js","names":["#connectConfig","#logger","#nodeSsh"],"sources":["../../src/classes/ssh-client.ts"],"sourcesContent":["import { createConsola } from 'consola';\nimport type { ConsolaInstance } from 'consola';\nimport { NodeSSH } from 'node-ssh';\nimport type {\n Config,\n SSHExecCommandOptions,\n SSHGetPutDirectoryOptions,\n SSHPutFilesOptions,\n} from 'node-ssh';\nimport type {\n SFTPWrapper,\n TransferOptions,\n} from 'ssh2';\n\nimport type { Nullable } from '../types';\n\nimport type { PathLike } from './path';\n\nconst loggerLevelStringToConsolaLogLevelMap = {\n debug: 4,\n error: 0,\n fatal: 0,\n info: 3,\n normal: 2,\n silent: -999,\n trace: 5,\n verbose: 999,\n warn: 1,\n} as const;\n\nexport class SshClient {\n readonly #connectConfig: Config;\n readonly #logger: ConsolaInstance;\n\n #nodeSsh: NodeSSH;\n\n constructor(host: string, username: string, password: string, port: number = 22, connectConfig?: Config) {\n this.#connectConfig = {\n ...connectConfig,\n host,\n password,\n port,\n username,\n };\n\n this.#logger = createConsola();\n this.#nodeSsh = new NodeSSH();\n if (process.env.NODE_ENV === 'production') this.setLoggerLevel('error');\n }\n\n get nodeSsh() {\n return this.#nodeSsh;\n }\n\n async connect() {\n try {\n this.#nodeSsh = await this.#nodeSsh.connect(this.#connectConfig);\n return true;\n } catch (error) {\n this.#logger.error(error);\n return false;\n }\n }\n\n disconnect() {\n try {\n this.#nodeSsh.dispose();\n return true;\n } catch (error) {\n this.#logger.error(error);\n return false;\n }\n }\n\n execCommand(command: string, options?: SSHExecCommandOptions) {\n return this.#nodeSsh.execCommand(command, options).catch(() => {});\n }\n\n execCommandWithIo(command: string, options?: SSHExecCommandOptions) {\n return this.execCommand(\n command,\n {\n ...options,\n onStderr: (data) => process.stderr.write(data.toString()),\n onStdout: (data) => process.stdout.write(data.toString()),\n },\n );\n }\n\n getDir = this.getDirectory;\n\n async getDirectory(localDirectory: PathLike, remoteDirectory: PathLike, options?: SSHGetPutDirectoryOptions) {\n try {\n return await this.#nodeSsh.getDirectory(localDirectory.toString(), remoteDirectory.toString(), options);\n } catch (error) {\n this.#logger.error(error);\n return false;\n }\n }\n\n async getFile(\n localFile: PathLike,\n remoteFile: PathLike,\n givenSftp?: Nullable<SFTPWrapper>,\n transferOptions?: Nullable<TransferOptions>,\n ) {\n try {\n await this.#nodeSsh.getFile(localFile.toString(), remoteFile.toString(), givenSftp, transferOptions);\n return true;\n } catch (error) {\n this.#logger.error(error);\n return false;\n }\n }\n\n isConnected() {\n return this.#nodeSsh.isConnected();\n }\n\n async mkdir(path: PathLike) {\n try {\n await this.#nodeSsh.mkdir(path.toString());\n return true;\n } catch (error) {\n this.#logger.error(error);\n return false;\n }\n }\n\n putDir = this.putDirectory;\n\n async putDirectory(localDirectory: PathLike, remoteDirectory: PathLike, options?: SSHGetPutDirectoryOptions) {\n try {\n return await this.#nodeSsh.putDirectory(localDirectory.toString(), remoteDirectory.toString(), options);\n } catch (error) {\n this.#logger.error(error);\n return false;\n }\n }\n\n async putFile(\n localFile: PathLike,\n remoteFile: PathLike,\n givenSftp?: Nullable<SFTPWrapper>,\n transferOptions?: Nullable<TransferOptions>,\n ) {\n try {\n await this.#nodeSsh.putFile(localFile.toString(), remoteFile.toString(), givenSftp, transferOptions);\n return true;\n } catch (error) {\n this.#logger.error(error);\n return false;\n }\n }\n\n async putFiles(files: { local: PathLike; remote: PathLike }[], options?: SSHPutFilesOptions) {\n try {\n const convertedFiles = files.map(({ local, remote }) => ({\n local: local.toString(),\n remote: remote.toString(),\n }));\n\n await this.#nodeSsh.putFiles(convertedFiles, options);\n return true;\n } catch (error) {\n this.#logger.error(error);\n return false;\n }\n }\n\n setLoggerLevel(level: keyof typeof loggerLevelStringToConsolaLogLevelMap) {\n this.#logger.level = loggerLevelStringToConsolaLogLevelMap[level];\n }\n}\n"],"mappings":"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"}
@@ -22,6 +22,16 @@ declare class EventAwaiter<T> {
22
22
  * May be `undefined` to indicate no result or a timeout-like behavior.
23
23
  */
24
24
  trigger(key: string, value: T | undefined): void;
25
+ /**
26
+ * Triggers and resolves all pending promises across all keys.
27
+ *
28
+ * This is typically used during shutdown or cleanup to ensure that
29
+ * no consumer is left waiting indefinitely.
30
+ *
31
+ * @param {T | undefined} [value] - Optional value to resolve all waiters with.
32
+ * Defaults to `undefined`, which usually indicates cancellation or shutdown.
33
+ */
34
+ triggerAll(value?: T | undefined): void;
25
35
  /**
26
36
  * Waits for an event associated with the given key.
27
37
  *
@@ -1 +1 @@
1
- {"version":3,"file":"event-awaiter.d.ts","names":[],"sources":["../src/event-awaiter.ts"],"sourcesContent":[],"mappings":";;AAYA;;;;;;;;;;;AAmHoE,cAnHvD,YAmHuD,CAAA,CAAA,CAAA,CAAA;EAAA,CAAA,OAAA;;;;;;;;;8BAxGpC;;;;;;;;;;;;;;;;;;;;;;;;+EA+BiD,cAAW,QAAA;;;;;;;;;;;0DA2DhC,cAAW,QAAA;;;;;;;;;;;uDAcd,cAAW,QAAA"}
1
+ {"version":3,"file":"event-awaiter.d.ts","names":[],"sources":["../src/event-awaiter.ts"],"sourcesContent":[],"mappings":";;AAYA;;;;;;;;;;;AAiIoE,cAjIvD,YAiIuD,CAAA,CAAA,CAAA,CAAA;UAAA;EAAA;;;;;;;;8BAtHpC;;;;;;;;;;qBAiBV;;;;;;;;;;;;;;;;;;;;;;;;+EA4B2D,cAAW,QAAA;;;;;;;;;;;0DA2DhC,cAAW,QAAA;;;;;;;;;;;uDAcd,cAAW,QAAA"}
@@ -29,6 +29,19 @@ var EventAwaiter = class {
29
29
  }
30
30
  }
31
31
  /**
32
+ * Triggers and resolves all pending promises across all keys.
33
+ *
34
+ * This is typically used during shutdown or cleanup to ensure that
35
+ * no consumer is left waiting indefinitely.
36
+ *
37
+ * @param {T | undefined} [value] - Optional value to resolve all waiters with.
38
+ * Defaults to `undefined`, which usually indicates cancellation or shutdown.
39
+ */
40
+ triggerAll(value = void 0) {
41
+ for (const [_, resolvers] of this.#promiseResolvers.entries()) resolvers.forEach((resolve) => resolve(value));
42
+ this.#promiseResolvers.clear();
43
+ }
44
+ /**
32
45
  * Waits for an event associated with the given key.
33
46
  *
34
47
  * The returned promise will resolve when:
@@ -1 +1 @@
1
- {"version":3,"file":"event-awaiter.js","names":["#promiseResolvers","resolvers"],"sources":["../src/event-awaiter.ts"],"sourcesContent":["/**\n * EventAwaiter provides a mechanism to wait for events (by key) asynchronously.\n *\n * This class allows multiple consumers to `wait` for a specific key\n * and be resolved when `trigger` is called for that key, or automatically\n * resolved with `undefined` if a timeout occurs or an AbortSignal is triggered.\n *\n * Typical use cases include long-polling, request coordination,\n * or implementing event-driven primitives in applications or services.\n *\n * @template T - The type of value that will be resolved when the event is triggered\n */\nexport class EventAwaiter<T> {\n #promiseResolvers = new Map<string, ((value: PromiseLike<T | undefined> | T | undefined) => void)[]>();\n\n /**\n * Triggers all pending promises waiting for the given key.\n * Each promise will be resolved with the provided value.\n *\n * @param {string} key - Identifier for the awaited event\n * @param {T | undefined} value - The value to resolve the awaiting promises with.\n * May be `undefined` to indicate no result or a timeout-like behavior.\n */\n trigger(key: string, value: T | undefined) {\n const resolvers = this.#promiseResolvers.get(key);\n if (resolvers) {\n this.#promiseResolvers.delete(key);\n resolvers?.forEach((resolve) => resolve(value));\n }\n }\n\n /**\n * Waits for an event associated with the given key.\n *\n * The returned promise will resolve when:\n * - `trigger(key)` is called, in which case it resolves with the provided value.\n * - The optional timeout is reached, in which case it resolves with `undefined`.\n * - The optional `AbortSignal` is aborted, in which case it resolves with `undefined`.\n *\n * Behavior when multiple waiters exist for the same key:\n * - Default (no mode): multiple waiters are allowed, all will be resolved when triggered.\n * - `strict` mode: throws an error if a waiter already exists for the given key.\n * - `override` mode: cancels all existing waiters (resolving them with `undefined`)\n * and only keeps the latest one.\n *\n * @param {string} key - Identifier for the awaited event\n * @param {number} [timeoutMs] - Optional timeout (in milliseconds).\n * If reached, the promise resolves with `undefined`.\n * @param {'override' | 'strict'} [mode] - Optional behavior mode for handling multiple waiters\n * @param {AbortSignal} [signal] - Optional AbortSignal. If aborted, the promise resolves with `undefined`\n *\n * @returns {Promise<T | undefined>} A promise that resolves with the triggered value,\n * or `undefined` if timeout or abort occurs\n */\n wait(key: string, timeoutMs?: number, mode?: 'override' | 'strict', signal?: AbortSignal) {\n return new Promise<T | undefined>((resolve) => {\n const resolvers = this.#promiseResolvers.get(key) || [];\n if (resolvers.length) {\n switch (mode) {\n case 'override':\n resolvers.forEach((r) => r(undefined));\n resolvers.length = 0;\n break;\n case 'strict':\n throw new Error(`Duplicate wait detected for key: ${key}`);\n }\n }\n\n resolvers.push(resolve);\n this.#promiseResolvers.set(key, resolvers);\n if (timeoutMs) {\n setTimeout(\n () => {\n const resolvers = this.#promiseResolvers.get(key);\n if (resolvers?.includes(resolve)) {\n resolve(undefined);\n const newResolvers = resolvers.filter((r) => r !== resolve);\n if (newResolvers.length) this.#promiseResolvers.set(key, newResolvers);\n else this.#promiseResolvers.delete(key);\n }\n },\n timeoutMs,\n );\n }\n\n if (signal) {\n signal.addEventListener(\n 'abort',\n () => {\n const resolvers = this.#promiseResolvers.get(key);\n if (resolvers?.includes(resolve)) {\n resolve(undefined);\n const newResolvers = resolvers.filter((r) => r !== resolve);\n if (newResolvers.length) this.#promiseResolvers.set(key, newResolvers);\n else this.#promiseResolvers.delete(key);\n }\n },\n { once: true },\n );\n }\n });\n }\n\n /**\n * Waits for an event in strict mode.\n * Only one waiter is allowed per key. If another waiter already exists,\n * this method will throw an error.\n *\n * @param {string} key - Identifier for the awaited event\n * @param {number} [timeoutMs] - Optional timeout (in milliseconds).\n * If reached, the promise resolves with `undefined`.\n * @param {AbortSignal} [signal] - Optional AbortSignal. If aborted, the promise resolves with `undefined`\n */\n waitExclusive(key: string, timeoutMs?: number, signal?: AbortSignal) {\n return this.wait(key, timeoutMs, 'strict', signal);\n }\n\n /**\n * Waits for an event in override mode.\n * If another waiter already exists for the given key, it will be canceled\n * (resolved with `undefined`) and replaced by the new waiter.\n *\n * @param {string} key - Identifier for the awaited event\n * @param {number} [timeoutMs] - Optional timeout (in milliseconds).\n * If reached, the promise resolves with `undefined`.\n * @param {AbortSignal} [signal] - Optional AbortSignal. If aborted, the promise resolves with `undefined`\n */\n waitLatest(key: string, timeoutMs?: number, signal?: AbortSignal) {\n return this.wait(key, timeoutMs, 'override', signal);\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,IAAa,eAAb,MAA6B;CACzB,oCAAoB,IAAI,KAA8E;;;;;;;;;CAUtG,QAAQ,KAAa,OAAsB;EACvC,MAAM,YAAY,MAAKA,iBAAkB,IAAI,IAAI;AACjD,MAAI,WAAW;AACX,SAAKA,iBAAkB,OAAO,IAAI;AAClC,cAAW,SAAS,YAAY,QAAQ,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BvD,KAAK,KAAa,WAAoB,MAA8B,QAAsB;AACtF,SAAO,IAAI,SAAwB,YAAY;GAC3C,MAAM,YAAY,MAAKA,iBAAkB,IAAI,IAAI,IAAI,EAAE;AACvD,OAAI,UAAU,OACV,SAAQ,MAAR;IACI,KAAK;AACD,eAAU,SAAS,MAAM,EAAE,OAAU,CAAC;AACtC,eAAU,SAAS;AACnB;IACJ,KAAK,SACD,OAAM,IAAI,MAAM,oCAAoC,MAAM;;AAItE,aAAU,KAAK,QAAQ;AACvB,SAAKA,iBAAkB,IAAI,KAAK,UAAU;AAC1C,OAAI,UACA,kBACU;IACF,MAAMC,cAAY,MAAKD,iBAAkB,IAAI,IAAI;AACjD,QAAIC,aAAW,SAAS,QAAQ,EAAE;AAC9B,aAAQ,OAAU;KAClB,MAAM,eAAeA,YAAU,QAAQ,MAAM,MAAM,QAAQ;AAC3D,SAAI,aAAa,OAAQ,OAAKD,iBAAkB,IAAI,KAAK,aAAa;SACjE,OAAKA,iBAAkB,OAAO,IAAI;;MAG/C,UACH;AAGL,OAAI,OACA,QAAO,iBACH,eACM;IACF,MAAMC,cAAY,MAAKD,iBAAkB,IAAI,IAAI;AACjD,QAAIC,aAAW,SAAS,QAAQ,EAAE;AAC9B,aAAQ,OAAU;KAClB,MAAM,eAAeA,YAAU,QAAQ,MAAM,MAAM,QAAQ;AAC3D,SAAI,aAAa,OAAQ,OAAKD,iBAAkB,IAAI,KAAK,aAAa;SACjE,OAAKA,iBAAkB,OAAO,IAAI;;MAG/C,EAAE,MAAM,MAAM,CACjB;IAEP;;;;;;;;;;;;CAaN,cAAc,KAAa,WAAoB,QAAsB;AACjE,SAAO,KAAK,KAAK,KAAK,WAAW,UAAU,OAAO;;;;;;;;;;;;CAatD,WAAW,KAAa,WAAoB,QAAsB;AAC9D,SAAO,KAAK,KAAK,KAAK,WAAW,YAAY,OAAO"}
1
+ {"version":3,"file":"event-awaiter.js","names":["#promiseResolvers","resolvers"],"sources":["../src/event-awaiter.ts"],"sourcesContent":["/**\n * EventAwaiter provides a mechanism to wait for events (by key) asynchronously.\n *\n * This class allows multiple consumers to `wait` for a specific key\n * and be resolved when `trigger` is called for that key, or automatically\n * resolved with `undefined` if a timeout occurs or an AbortSignal is triggered.\n *\n * Typical use cases include long-polling, request coordination,\n * or implementing event-driven primitives in applications or services.\n *\n * @template T - The type of value that will be resolved when the event is triggered\n */\nexport class EventAwaiter<T> {\n #promiseResolvers = new Map<string, ((value: PromiseLike<T | undefined> | T | undefined) => void)[]>();\n\n /**\n * Triggers all pending promises waiting for the given key.\n * Each promise will be resolved with the provided value.\n *\n * @param {string} key - Identifier for the awaited event\n * @param {T | undefined} value - The value to resolve the awaiting promises with.\n * May be `undefined` to indicate no result or a timeout-like behavior.\n */\n trigger(key: string, value: T | undefined) {\n const resolvers = this.#promiseResolvers.get(key);\n if (resolvers) {\n this.#promiseResolvers.delete(key);\n resolvers?.forEach((resolve) => resolve(value));\n }\n }\n\n /**\n * Triggers and resolves all pending promises across all keys.\n *\n * This is typically used during shutdown or cleanup to ensure that\n * no consumer is left waiting indefinitely.\n *\n * @param {T | undefined} [value] - Optional value to resolve all waiters with.\n * Defaults to `undefined`, which usually indicates cancellation or shutdown.\n */\n triggerAll(value: T | undefined = undefined) {\n for (const [_, resolvers] of this.#promiseResolvers.entries()) resolvers.forEach((resolve) => resolve(value));\n this.#promiseResolvers.clear();\n }\n\n /**\n * Waits for an event associated with the given key.\n *\n * The returned promise will resolve when:\n * - `trigger(key)` is called, in which case it resolves with the provided value.\n * - The optional timeout is reached, in which case it resolves with `undefined`.\n * - The optional `AbortSignal` is aborted, in which case it resolves with `undefined`.\n *\n * Behavior when multiple waiters exist for the same key:\n * - Default (no mode): multiple waiters are allowed, all will be resolved when triggered.\n * - `strict` mode: throws an error if a waiter already exists for the given key.\n * - `override` mode: cancels all existing waiters (resolving them with `undefined`)\n * and only keeps the latest one.\n *\n * @param {string} key - Identifier for the awaited event\n * @param {number} [timeoutMs] - Optional timeout (in milliseconds).\n * If reached, the promise resolves with `undefined`.\n * @param {'override' | 'strict'} [mode] - Optional behavior mode for handling multiple waiters\n * @param {AbortSignal} [signal] - Optional AbortSignal. If aborted, the promise resolves with `undefined`\n *\n * @returns {Promise<T | undefined>} A promise that resolves with the triggered value,\n * or `undefined` if timeout or abort occurs\n */\n wait(key: string, timeoutMs?: number, mode?: 'override' | 'strict', signal?: AbortSignal) {\n return new Promise<T | undefined>((resolve) => {\n const resolvers = this.#promiseResolvers.get(key) || [];\n if (resolvers.length) {\n switch (mode) {\n case 'override':\n resolvers.forEach((r) => r(undefined));\n resolvers.length = 0;\n break;\n case 'strict':\n throw new Error(`Duplicate wait detected for key: ${key}`);\n }\n }\n\n resolvers.push(resolve);\n this.#promiseResolvers.set(key, resolvers);\n if (timeoutMs) {\n setTimeout(\n () => {\n const resolvers = this.#promiseResolvers.get(key);\n if (resolvers?.includes(resolve)) {\n resolve(undefined);\n const newResolvers = resolvers.filter((r) => r !== resolve);\n if (newResolvers.length) this.#promiseResolvers.set(key, newResolvers);\n else this.#promiseResolvers.delete(key);\n }\n },\n timeoutMs,\n );\n }\n\n if (signal) {\n signal.addEventListener(\n 'abort',\n () => {\n const resolvers = this.#promiseResolvers.get(key);\n if (resolvers?.includes(resolve)) {\n resolve(undefined);\n const newResolvers = resolvers.filter((r) => r !== resolve);\n if (newResolvers.length) this.#promiseResolvers.set(key, newResolvers);\n else this.#promiseResolvers.delete(key);\n }\n },\n { once: true },\n );\n }\n });\n }\n\n /**\n * Waits for an event in strict mode.\n * Only one waiter is allowed per key. If another waiter already exists,\n * this method will throw an error.\n *\n * @param {string} key - Identifier for the awaited event\n * @param {number} [timeoutMs] - Optional timeout (in milliseconds).\n * If reached, the promise resolves with `undefined`.\n * @param {AbortSignal} [signal] - Optional AbortSignal. If aborted, the promise resolves with `undefined`\n */\n waitExclusive(key: string, timeoutMs?: number, signal?: AbortSignal) {\n return this.wait(key, timeoutMs, 'strict', signal);\n }\n\n /**\n * Waits for an event in override mode.\n * If another waiter already exists for the given key, it will be canceled\n * (resolved with `undefined`) and replaced by the new waiter.\n *\n * @param {string} key - Identifier for the awaited event\n * @param {number} [timeoutMs] - Optional timeout (in milliseconds).\n * If reached, the promise resolves with `undefined`.\n * @param {AbortSignal} [signal] - Optional AbortSignal. If aborted, the promise resolves with `undefined`\n */\n waitLatest(key: string, timeoutMs?: number, signal?: AbortSignal) {\n return this.wait(key, timeoutMs, 'override', signal);\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,IAAa,eAAb,MAA6B;CACzB,oCAAoB,IAAI,KAA8E;;;;;;;;;CAUtG,QAAQ,KAAa,OAAsB;EACvC,MAAM,YAAY,MAAKA,iBAAkB,IAAI,IAAI;AACjD,MAAI,WAAW;AACX,SAAKA,iBAAkB,OAAO,IAAI;AAClC,cAAW,SAAS,YAAY,QAAQ,MAAM,CAAC;;;;;;;;;;;;CAavD,WAAW,QAAuB,QAAW;AACzC,OAAK,MAAM,CAAC,GAAG,cAAc,MAAKA,iBAAkB,SAAS,CAAE,WAAU,SAAS,YAAY,QAAQ,MAAM,CAAC;AAC7G,QAAKA,iBAAkB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;CA0BlC,KAAK,KAAa,WAAoB,MAA8B,QAAsB;AACtF,SAAO,IAAI,SAAwB,YAAY;GAC3C,MAAM,YAAY,MAAKA,iBAAkB,IAAI,IAAI,IAAI,EAAE;AACvD,OAAI,UAAU,OACV,SAAQ,MAAR;IACI,KAAK;AACD,eAAU,SAAS,MAAM,EAAE,OAAU,CAAC;AACtC,eAAU,SAAS;AACnB;IACJ,KAAK,SACD,OAAM,IAAI,MAAM,oCAAoC,MAAM;;AAItE,aAAU,KAAK,QAAQ;AACvB,SAAKA,iBAAkB,IAAI,KAAK,UAAU;AAC1C,OAAI,UACA,kBACU;IACF,MAAMC,cAAY,MAAKD,iBAAkB,IAAI,IAAI;AACjD,QAAIC,aAAW,SAAS,QAAQ,EAAE;AAC9B,aAAQ,OAAU;KAClB,MAAM,eAAeA,YAAU,QAAQ,MAAM,MAAM,QAAQ;AAC3D,SAAI,aAAa,OAAQ,OAAKD,iBAAkB,IAAI,KAAK,aAAa;SACjE,OAAKA,iBAAkB,OAAO,IAAI;;MAG/C,UACH;AAGL,OAAI,OACA,QAAO,iBACH,eACM;IACF,MAAMC,cAAY,MAAKD,iBAAkB,IAAI,IAAI;AACjD,QAAIC,aAAW,SAAS,QAAQ,EAAE;AAC9B,aAAQ,OAAU;KAClB,MAAM,eAAeA,YAAU,QAAQ,MAAM,MAAM,QAAQ;AAC3D,SAAI,aAAa,OAAQ,OAAKD,iBAAkB,IAAI,KAAK,aAAa;SACjE,OAAKA,iBAAkB,OAAO,IAAI;;MAG/C,EAAE,MAAM,MAAM,CACjB;IAEP;;;;;;;;;;;;CAaN,cAAc,KAAa,WAAoB,QAAsB;AACjE,SAAO,KAAK,KAAK,KAAK,WAAW,UAAU,OAAO;;;;;;;;;;;;CAatD,WAAW,KAAa,WAAoB,QAAsB;AAC9D,SAAO,KAAK,KAAK,KAAK,WAAW,YAAY,OAAO"}
@@ -0,0 +1,30 @@
1
+ import { ObjectId } from "bson";
2
+
3
+ //#region src/types/filtered-key-path.d.ts
4
+
5
+ /**
6
+ * The following types are based on or inspired by types from the Element Plus project.
7
+ * Source: https://github.com/element-plus/element-plus
8
+ * License: MIT (https://opensource.org/licenses/MIT)
9
+ *
10
+ * Original types might have been modified to suit this project’s needs.
11
+ */
12
+ /***/
13
+ type ConditionalPath<K extends number | string, V, U> = V extends U ? `${K}` : DefaultPath<K, V, U, never>;
14
+ type DefaultPath<K extends number | string, V, U = never, RK = `${K}`> = V extends TerminalType ? RK : `${K}.${FilteredKeyPath<V, U>}`;
15
+ /**
16
+ * A utility type that generates a union of key paths from a given object type `T`,
17
+ * filtered by a specific type `U`. If `U` is
18
+ * not provided, it defaults to including all key paths.
19
+ *
20
+ * @template T - The object type to traverse.
21
+ * @template U - The type used to filter key paths. Defaults to `never`, meaning no filtering.
22
+ */
23
+ type FilteredKeyPath<T, U = never> = T extends ReadonlyArray<infer V> ? (IsTuple<T> extends true ? { [K in TupleKey<T>]-?: PathImpl<Exclude<K, symbol>, T[K], U> }[TupleKey<T>] : PathImpl<number, V, U>) : { [K in keyof T]-?: PathImpl<Exclude<K, symbol>, T[K], U> }[keyof T];
24
+ type IsTuple<T extends ReadonlyArray<any>> = number extends T['length'] ? false : true;
25
+ type PathImpl<K extends number | string, V, U> = [U] extends [never] ? DefaultPath<K, V> : ConditionalPath<K, V, U>;
26
+ type TerminalType = bigint | Blob | boolean | Date | File | null | number | ObjectId | RegExp | string | symbol | undefined;
27
+ type TupleKey<T extends ReadonlyArray<any>> = Exclude<keyof T, keyof any[]>;
28
+ //#endregion
29
+ export { FilteredKeyPath };
30
+ //# sourceMappingURL=filtered-key-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filtered-key-path.d.ts","names":[],"sources":["../../src/types/filtered-key-path.ts"],"sourcesContent":[],"mappings":";;;;;;AAAqC;;;;;;KAWhC,eAAyF,CAAA,UAAA,MAAA,GAAA,MAAA,EAAA,CAAA,EAAA,CAAA,CAAA,GAAtC,CAAsC,SAA5B,CAA4B,GAAA,GAArB,CAAqB,EAAA,GAAf,WAAe,CAAH,CAAG,EAAA,CAAA,EAAG,CAAH,EAAA,KAAA,CAAA;KACzF,WAD4F,CAAA,UAAA,MAAA,GAAA,MAAA,EAAA,CAAA,EAAA,IAAA,KAAA,EAAA,KAAA,GAKrF,CALqF,EAAA,CAAA,GAM7F,CAN6F,SAMnF,YANmF,GAMpE,EANoE,GAAA,GAM5D,CAN4D,IAMvD,eANuD,CAMvC,CANuC,EAMpC,CANoC,CAAA,EAAA;;;AAAP;;;;;;AAMrD,KAWzB,eAXyB,CAAA,CAAA,EAAA,IAAA,KAAA,CAAA,GAWO,CAXP,SAWiB,aAXjB,CAAA,KAAA,EAAA,CAAA,GAAA,CAW2C,OAX3C,CAWmD,CAXnD,CAAA,SAAA,IAAA,GAAA,QAW6E,QAXxD,CAWiE,CAXjE,CAAA,KAWwE,QAXxE,CAWiF,OAXjF,CAWyF,CAXzF,EAAA,MAAA,CAAA,EAWqG,CAXrG,CAWuG,CAXvG,CAAA,EAW2G,CAX3G,CAAA,GAWgH,QAX7G,CAWsH,CAXtH,CAAA,CAAA,GAW4H,QAX5H,CAAA,MAAA,EAW6I,CAX7I,EAWgJ,CAXhJ,CAAA,CAAA,GAAA,QAAnB,MAWuL,CAXvL,KAW6L,QAX7L,CAWsM,OAXtM,CAW8M,CAX9M,EAAA,MAAA,CAAA,EAW0N,CAX1N,CAW4N,CAX5N,CAAA,EAWgO,CAXhO,CAAA,EAAe,CAAA,MAW4N,CAX5N,CAAA;AAWzD,KACK,OADO,CAAA,UACW,aADI,CAAA,GAAA,CAAA,CAAA,GAAA,MAAA,SACiC,CADjC,CAAA,QAAA,CAAA,GAAA,KAAA,GAAA,IAAA;KAEtB,QAFsB,CAAA,UAAA,MAAA,GAAA,MAAA,EAAA,CAAA,EAAA,CAAA,CAAA,GAAA,CAEuB,CAFvB,CAAA,SAAA,CAAA,KAAA,CAAA,GAE4C,WAF5C,CAEwD,CAFxD,EAE2D,CAF3D,CAAA,GAEgE,eAFhE,CAEgF,CAFhF,EAEmF,CAFnF,EAEsF,CAFtF,CAAA;KAGtB,YAAA,GAHuC,MAAA,GAKxC,IALwC,GAAA,OAAA,GAOxC,IAPwC,GAQxC,IARwC,GAAA,IAAA,GAAA,MAAA,GAWxC,QAXwC,GAYxC,MAZwC,GAAA,MAAA,GAAA,MAAA,GAAA,SAAA;KAiBvC,QAjBiD,CAAA,UAiB9B,aAjB8B,CAAA,GAAA,CAAA,CAAA,GAiBR,OAjBQ,CAAA,MAiBM,CAjBN,EAAA,MAAA,GAAA,EAAA,CAAA"}
@@ -0,0 +1,17 @@
1
+ import { FilteredKeyPath } from "./filtered-key-path.js";
2
+ import { Blob as Blob$1, Buffer, File as File$1 } from "node:buffer";
3
+
4
+ //#region src/types/index.d.ts
5
+ type AnyRecord = Record<string, any>;
6
+ type BinaryInput = Blob | Buffer | File | Blob$1 | File$1;
7
+ type Booleanish = 'false' | 'true' | boolean;
8
+ type MaybePartial<T> = Partial<T> | T;
9
+ type MaybeReadonly<T> = Readonly<T> | T;
10
+ type Nullable<T> = null | T;
11
+ type Numberish = number | string;
12
+ type PartialRecord<K extends keyof any, T> = Partial<Record<K, T>>;
13
+ type ReadonlyPartialRecord<K extends keyof any, T> = Readonly<PartialRecord<K, T>>;
14
+ type ReadonlyRecord<K extends keyof any, T> = Readonly<Record<K, T>>;
15
+ //#endregion
16
+ export { AnyRecord, BinaryInput, Booleanish, type FilteredKeyPath, MaybePartial, MaybeReadonly, Nullable, Numberish, PartialRecord, ReadonlyPartialRecord, ReadonlyRecord };
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/types/index.ts"],"sourcesContent":[],"mappings":";;;;KAQY,SAAA,GAAY;KACZ,WAAA,GAAc,OAAO,SAAS,OAAO,SAAW;AADhD,KAEA,UAAA,GAFS,OAAG,GAAM,MAAA,GAAA,OAAA;AAClB,KAEA,YAFW,CAAA,CAAA,CAAA,GAEO,OAFP,CAEe,CAFf,CAAA,GAEoB,CAFpB;AAAA,KAGX,aAHW,CAAA,CAAA,CAAA,GAGQ,QAHR,CAGiB,CAHjB,CAAA,GAGsB,CAHtB;AAAG,KAId,QAJc,CAAA,CAAA,CAAA,GAAA,IAAA,GAIO,CAJP;AAAO,KAKrB,SAAA,GALqB,MAAA,GAAA,MAAA;AAAS,KAM9B,aAN8B,CAAA,UAAA,MAAA,GAAA,EAAA,CAAA,CAAA,GAMU,OANV,CAMkB,MANlB,CAMyB,CANzB,EAM4B,CAN5B,CAAA,CAAA;AAAO,KAOrC,qBAPqC,CAAA,UAAA,MAAA,GAAA,EAAA,CAAA,CAAA,GAOW,QAPX,CAOoB,aAPpB,CAOkC,CAPlC,EAOqC,CAPrC,CAAA,CAAA;AAAW,KAQhD,cARgD,CAAA,UAAA,MAAA,GAAA,EAAA,CAAA,CAAA,GAQP,QARO,CAQE,MARF,CAQS,CART,EAQY,CARZ,CAAA,CAAA"}
@@ -0,0 +1,22 @@
1
+ import { Nullable } from "./index.js";
2
+ import { GlobalComponents } from "vue";
3
+
4
+ //#region src/types/vue.d.ts
5
+
6
+ /**
7
+ * A type that represents a reference to a Vue component instance.
8
+ * The reference can be either an instance of the specified component or null.
9
+ *
10
+ * @template K - The key of the component in the GlobalComponents.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import type { ComponentRef } from '@kikiutils/types/vue';
15
+ *
16
+ * const keepAliveRef = ref<ComponentRef<'KeepAlive'>>(null);
17
+ * ```
18
+ */
19
+ type ComponentRef<K extends keyof GlobalComponents> = Nullable<InstanceType<GlobalComponents[K]>>;
20
+ //#endregion
21
+ export { ComponentRef };
22
+ //# sourceMappingURL=vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vue.d.ts","names":[],"sources":["../../src/types/vue.ts"],"sourcesContent":[],"mappings":";;;;;;;AAiBA;;;;;;;;;;;KAAY,6BAA6B,oBAAoB,SAAS,aAAa,iBAAiB"}
package/dist/vue.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { Nullable } from "./types/index.js";
1
2
  import { Ref } from "vue";
2
3
 
3
4
  //#region src/vue.d.ts
@@ -13,24 +14,24 @@ declare function appendRedirectParamFromCurrentRouteToUrl(url: string): string;
13
14
  /**
14
15
  * Clears an interval referenced by a Vue ref and sets it to null.
15
16
  *
16
- * @param {Ref<null | ReturnType<typeof setInterval>>} intervalRef - A Vue ref holding a NodeJS.Timeout or null
17
+ * @param {Ref<Nullable<ReturnType<typeof setInterval>>>} intervalRef - A Vue ref holding a NodeJS.Timeout or null
17
18
  */
18
- declare function clearIntervalRef(intervalRef: Ref<null | ReturnType<typeof setInterval>>): void;
19
+ declare function clearIntervalRef(intervalRef: Ref<Nullable<ReturnType<typeof setInterval>>>): void;
19
20
  /**
20
21
  * Clears a timeout referenced by a Vue ref and sets it to null.
21
22
  *
22
- * @param {Ref<null | ReturnType<typeof setTimeout>>} timeoutRef - A Vue ref holding a NodeJS.Timeout or null
23
+ * @param {Ref<Nullable<ReturnType<typeof setTimeout>>>} timeoutRef - A Vue ref holding a NodeJS.Timeout or null
23
24
  */
24
- declare function clearTimeoutRef(timeoutRef: Ref<null | ReturnType<typeof setTimeout>>): void;
25
+ declare function clearTimeoutRef(timeoutRef: Ref<Nullable<ReturnType<typeof setTimeout>>>): void;
25
26
  /**
26
27
  * A Vue composition function that remembers and restores scroll position
27
28
  * of a scrollable container across route changes and keep-alive activation.
28
29
  *
29
30
  * @template T - The type of the scrollable element (defaults to HTMLElement)
30
31
  *
31
- * @param {Ref<null | T>} containerRef - A ref to the scrollable HTML element
32
+ * @param {Ref<Nullable<T>>} containerRef - A ref to the scrollable HTML element
32
33
  */
33
- declare function usePreserveScroll<T extends Element = HTMLElement>(containerRef: Ref<null | T>): void;
34
+ declare function usePreserveScroll<T extends Element = HTMLElement>(containerRef: Ref<Nullable<T>>): void;
34
35
  //#endregion
35
36
  export { appendRedirectParamFromCurrentRouteToUrl, clearIntervalRef, clearTimeoutRef, usePreserveScroll };
36
37
  //# sourceMappingURL=vue.d.ts.map
package/dist/vue.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"vue.d.ts","names":[],"sources":["../src/vue.ts"],"sourcesContent":[],"mappings":";;;;;;AAgBA;AASA;;;;AAA8C,iBAT9B,wCAAA,CAS8B,GAAA,EAAA,MAAA,CAAA,EAAA,MAAA;;AAU9C;;;;AAA4C,iBAV5B,gBAAA,CAU4B,WAAA,EAVE,GAUF,CAAA,IAAA,GAVa,UAUb,CAAA,OAV+B,WAU/B,CAAA,CAAA,CAAA,EAAA,IAAA;;AAa5C;;;;AAA4F,iBAb5E,eAAA,CAa4E,UAAA,EAbhD,GAagD,CAAA,IAAA,GAbrC,UAaqC,CAAA,OAbnB,UAamB,CAAA,CAAA,CAAA,EAAA,IAAA;;;;;;;;;iBAA5E,4BAA4B,UAAU,2BAA2B,WAAW"}
1
+ {"version":3,"file":"vue.d.ts","names":[],"sources":["../src/vue.ts"],"sourcesContent":[],"mappings":";;;;;;;AAiBA;AASA;;;;AAAkD,iBATlC,wCAAA,CASkC,GAAA,EAAA,MAAA,CAAA,EAAA,MAAA;;;AAUlD;;;AAAyD,iBAVzC,gBAAA,CAUyC,WAAA,EAVX,GAUW,CAVP,QAUO,CAVE,UAUF,CAAA,OAVoB,WAUpB,CAAA,CAAA,CAAA,CAAA,EAAA,IAAA;;;;AAazD;;AAA4C,iBAb5B,eAAA,CAa4B,UAAA,EAbA,GAaA,CAbI,QAaJ,CAba,UAab,CAAA,OAb+B,UAa/B,CAAA,CAAA,CAAA,CAAA,EAAA,IAAA;;;;;;;;;iBAA5B,4BAA4B,UAAU,2BAA2B,IAAI,SAAS"}
package/dist/vue.js CHANGED
@@ -16,7 +16,7 @@ function appendRedirectParamFromCurrentRouteToUrl(url) {
16
16
  /**
17
17
  * Clears an interval referenced by a Vue ref and sets it to null.
18
18
  *
19
- * @param {Ref<null | ReturnType<typeof setInterval>>} intervalRef - A Vue ref holding a NodeJS.Timeout or null
19
+ * @param {Ref<Nullable<ReturnType<typeof setInterval>>>} intervalRef - A Vue ref holding a NodeJS.Timeout or null
20
20
  */
21
21
  function clearIntervalRef(intervalRef) {
22
22
  if (intervalRef.value) clearInterval(intervalRef.value);
@@ -25,7 +25,7 @@ function clearIntervalRef(intervalRef) {
25
25
  /**
26
26
  * Clears a timeout referenced by a Vue ref and sets it to null.
27
27
  *
28
- * @param {Ref<null | ReturnType<typeof setTimeout>>} timeoutRef - A Vue ref holding a NodeJS.Timeout or null
28
+ * @param {Ref<Nullable<ReturnType<typeof setTimeout>>>} timeoutRef - A Vue ref holding a NodeJS.Timeout or null
29
29
  */
30
30
  function clearTimeoutRef(timeoutRef) {
31
31
  if (timeoutRef.value) clearTimeout(timeoutRef.value);
@@ -37,7 +37,7 @@ function clearTimeoutRef(timeoutRef) {
37
37
  *
38
38
  * @template T - The type of the scrollable element (defaults to HTMLElement)
39
39
  *
40
- * @param {Ref<null | T>} containerRef - A ref to the scrollable HTML element
40
+ * @param {Ref<Nullable<T>>} containerRef - A ref to the scrollable HTML element
41
41
  */
42
42
  function usePreserveScroll(containerRef) {
43
43
  let scrollLeft = 0;
package/dist/vue.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"vue.js","names":[],"sources":["../src/vue.ts"],"sourcesContent":["import { onActivated } from 'vue';\nimport type { Ref } from 'vue';\nimport {\n onBeforeRouteLeave,\n useRoute,\n} from 'vue-router';\n\nimport { appendRedirectParamToUrl } from '@/url';\n\n/**\n * Appends the current Vue Router route's fullPath as the `redirect` query parameter to the given URL.\n *\n * @param {string} url - The base URL to modify\n *\n * @returns {string} A new URL with the current route fullPath as the `redirect` parameter\n */\nexport function appendRedirectParamFromCurrentRouteToUrl(url: string) {\n return appendRedirectParamToUrl(url, useRoute().fullPath);\n}\n\n/**\n * Clears an interval referenced by a Vue ref and sets it to null.\n *\n * @param {Ref<null | ReturnType<typeof setInterval>>} intervalRef - A Vue ref holding a NodeJS.Timeout or null\n */\nexport function clearIntervalRef(intervalRef: Ref<null | ReturnType<typeof setInterval>>) {\n if (intervalRef.value) clearInterval(intervalRef.value);\n intervalRef.value = null;\n}\n\n/**\n * Clears a timeout referenced by a Vue ref and sets it to null.\n *\n * @param {Ref<null | ReturnType<typeof setTimeout>>} timeoutRef - A Vue ref holding a NodeJS.Timeout or null\n */\nexport function clearTimeoutRef(timeoutRef: Ref<null | ReturnType<typeof setTimeout>>) {\n if (timeoutRef.value) clearTimeout(timeoutRef.value);\n timeoutRef.value = null;\n}\n\n/**\n * A Vue composition function that remembers and restores scroll position\n * of a scrollable container across route changes and keep-alive activation.\n *\n * @template T - The type of the scrollable element (defaults to HTMLElement)\n *\n * @param {Ref<null | T>} containerRef - A ref to the scrollable HTML element\n */\nexport function usePreserveScroll<T extends Element = HTMLElement>(containerRef: Ref<null | T>) {\n let scrollLeft = 0;\n let scrollTop = 0;\n onActivated(() => {\n if (!containerRef.value) return;\n containerRef.value.scrollLeft = scrollLeft;\n containerRef.value.scrollTop = scrollTop;\n });\n\n onBeforeRouteLeave(() => {\n scrollLeft = containerRef.value?.scrollLeft || 0;\n scrollTop = containerRef.value?.scrollTop || 0;\n });\n}\n"],"mappings":";;;;;;;;;;;;AAgBA,SAAgB,yCAAyC,KAAa;AAClE,QAAO,yBAAyB,KAAK,UAAU,CAAC,SAAS;;;;;;;AAQ7D,SAAgB,iBAAiB,aAAyD;AACtF,KAAI,YAAY,MAAO,eAAc,YAAY,MAAM;AACvD,aAAY,QAAQ;;;;;;;AAQxB,SAAgB,gBAAgB,YAAuD;AACnF,KAAI,WAAW,MAAO,cAAa,WAAW,MAAM;AACpD,YAAW,QAAQ;;;;;;;;;;AAWvB,SAAgB,kBAAmD,cAA6B;CAC5F,IAAI,aAAa;CACjB,IAAI,YAAY;AAChB,mBAAkB;AACd,MAAI,CAAC,aAAa,MAAO;AACzB,eAAa,MAAM,aAAa;AAChC,eAAa,MAAM,YAAY;GACjC;AAEF,0BAAyB;AACrB,eAAa,aAAa,OAAO,cAAc;AAC/C,cAAY,aAAa,OAAO,aAAa;GAC/C"}
1
+ {"version":3,"file":"vue.js","names":[],"sources":["../src/vue.ts"],"sourcesContent":["import { onActivated } from 'vue';\nimport type { Ref } from 'vue';\nimport {\n onBeforeRouteLeave,\n useRoute,\n} from 'vue-router';\n\nimport type { Nullable } from './types';\nimport { appendRedirectParamToUrl } from './url';\n\n/**\n * Appends the current Vue Router route's fullPath as the `redirect` query parameter to the given URL.\n *\n * @param {string} url - The base URL to modify\n *\n * @returns {string} A new URL with the current route fullPath as the `redirect` parameter\n */\nexport function appendRedirectParamFromCurrentRouteToUrl(url: string) {\n return appendRedirectParamToUrl(url, useRoute().fullPath);\n}\n\n/**\n * Clears an interval referenced by a Vue ref and sets it to null.\n *\n * @param {Ref<Nullable<ReturnType<typeof setInterval>>>} intervalRef - A Vue ref holding a NodeJS.Timeout or null\n */\nexport function clearIntervalRef(intervalRef: Ref<Nullable<ReturnType<typeof setInterval>>>) {\n if (intervalRef.value) clearInterval(intervalRef.value);\n intervalRef.value = null;\n}\n\n/**\n * Clears a timeout referenced by a Vue ref and sets it to null.\n *\n * @param {Ref<Nullable<ReturnType<typeof setTimeout>>>} timeoutRef - A Vue ref holding a NodeJS.Timeout or null\n */\nexport function clearTimeoutRef(timeoutRef: Ref<Nullable<ReturnType<typeof setTimeout>>>) {\n if (timeoutRef.value) clearTimeout(timeoutRef.value);\n timeoutRef.value = null;\n}\n\n/**\n * A Vue composition function that remembers and restores scroll position\n * of a scrollable container across route changes and keep-alive activation.\n *\n * @template T - The type of the scrollable element (defaults to HTMLElement)\n *\n * @param {Ref<Nullable<T>>} containerRef - A ref to the scrollable HTML element\n */\nexport function usePreserveScroll<T extends Element = HTMLElement>(containerRef: Ref<Nullable<T>>) {\n let scrollLeft = 0;\n let scrollTop = 0;\n onActivated(() => {\n if (!containerRef.value) return;\n containerRef.value.scrollLeft = scrollLeft;\n containerRef.value.scrollTop = scrollTop;\n });\n\n onBeforeRouteLeave(() => {\n scrollLeft = containerRef.value?.scrollLeft || 0;\n scrollTop = containerRef.value?.scrollTop || 0;\n });\n}\n"],"mappings":";;;;;;;;;;;;AAiBA,SAAgB,yCAAyC,KAAa;AAClE,QAAO,yBAAyB,KAAK,UAAU,CAAC,SAAS;;;;;;;AAQ7D,SAAgB,iBAAiB,aAA4D;AACzF,KAAI,YAAY,MAAO,eAAc,YAAY,MAAM;AACvD,aAAY,QAAQ;;;;;;;AAQxB,SAAgB,gBAAgB,YAA0D;AACtF,KAAI,WAAW,MAAO,cAAa,WAAW,MAAM;AACpD,YAAW,QAAQ;;;;;;;;;;AAWvB,SAAgB,kBAAmD,cAAgC;CAC/F,IAAI,aAAa;CACjB,IAAI,YAAY;AAChB,mBAAkB;AACd,MAAI,CAAC,aAAa,MAAO;AACzB,eAAa,MAAM,aAAa;AAChC,eAAa,MAAM,YAAY;GACjC;AAEF,0BAAyB;AACrB,eAAa,aAAa,OAAO,cAAc;AAC/C,cAAY,aAAa,OAAO,aAAa;GAC/C"}
package/dist/web.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"web.js","names":[],"sources":["../src/web.ts"],"sourcesContent":["import { appendRedirectParamToUrl } from '@/url';\n\n/**\n * Appends the current browser URL (including path, query, and hash) as the `redirect` query parameter to the given URL.\n *\n * @param {string} url - The base URL to modify\n *\n * @returns {string} A new URL with the current location as the `redirect` parameter\n */\nexport function appendRedirectParamFromCurrentLocationToUrl(url: string) {\n const currentPath = `${window.location.pathname}${window.location.search}${window.location.hash}`;\n return appendRedirectParamToUrl(url, currentPath);\n}\n\n/**\n * Navigates to the given URL, appending the current browser location\n * (path, query, and hash) as the `redirect` query parameter.\n *\n * Useful for redirecting to login or other gateways while preserving\n * the current location for post-auth navigation.\n *\n * @param {string} url - The destination URL to navigate to\n * @param {number} [delayMs] - Optional delay in milliseconds before navigation\n */\nexport function assignUrlWithRedirectParamFromCurrentLocation(url: string, delayMs?: number) {\n if (delayMs === undefined) window.location.assign(appendRedirectParamFromCurrentLocationToUrl(url));\n else return setTimeout(() => window.location.assign(appendRedirectParamFromCurrentLocationToUrl(url)), delayMs);\n}\n"],"mappings":";;;;;;;;;;AASA,SAAgB,4CAA4C,KAAa;CACrE,MAAM,cAAc,GAAG,OAAO,SAAS,WAAW,OAAO,SAAS,SAAS,OAAO,SAAS;AAC3F,QAAO,yBAAyB,KAAK,YAAY;;;;;;;;;;;;AAarD,SAAgB,8CAA8C,KAAa,SAAkB;AACzF,KAAI,YAAY,OAAW,QAAO,SAAS,OAAO,4CAA4C,IAAI,CAAC;KAC9F,QAAO,iBAAiB,OAAO,SAAS,OAAO,4CAA4C,IAAI,CAAC,EAAE,QAAQ"}
1
+ {"version":3,"file":"web.js","names":[],"sources":["../src/web.ts"],"sourcesContent":["import { appendRedirectParamToUrl } from './url';\n\n/**\n * Appends the current browser URL (including path, query, and hash) as the `redirect` query parameter to the given URL.\n *\n * @param {string} url - The base URL to modify\n *\n * @returns {string} A new URL with the current location as the `redirect` parameter\n */\nexport function appendRedirectParamFromCurrentLocationToUrl(url: string) {\n const currentPath = `${window.location.pathname}${window.location.search}${window.location.hash}`;\n return appendRedirectParamToUrl(url, currentPath);\n}\n\n/**\n * Navigates to the given URL, appending the current browser location\n * (path, query, and hash) as the `redirect` query parameter.\n *\n * Useful for redirecting to login or other gateways while preserving\n * the current location for post-auth navigation.\n *\n * @param {string} url - The destination URL to navigate to\n * @param {number} [delayMs] - Optional delay in milliseconds before navigation\n */\nexport function assignUrlWithRedirectParamFromCurrentLocation(url: string, delayMs?: number) {\n if (delayMs === undefined) window.location.assign(appendRedirectParamFromCurrentLocationToUrl(url));\n else return setTimeout(() => window.location.assign(appendRedirectParamFromCurrentLocationToUrl(url)), delayMs);\n}\n"],"mappings":";;;;;;;;;;AASA,SAAgB,4CAA4C,KAAa;CACrE,MAAM,cAAc,GAAG,OAAO,SAAS,WAAW,OAAO,SAAS,SAAS,OAAO,SAAS;AAC3F,QAAO,yBAAyB,KAAK,YAAY;;;;;;;;;;;;AAarD,SAAgB,8CAA8C,KAAa,SAAkB;AACzF,KAAI,YAAY,OAAW,QAAO,SAAS,OAAO,4CAA4C,IAAI,CAAC;KAC9F,QAAO,iBAAiB,OAAO,SAAS,OAAO,4CAA4C,IAAI,CAAC,EAAE,QAAQ"}