tunli 0.0.19

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.
Files changed (63) hide show
  1. package/LICENSE.md +595 -0
  2. package/README.md +135 -0
  3. package/bin/tunli +11 -0
  4. package/client.js +31 -0
  5. package/package.json +51 -0
  6. package/src/cli-app/Dashboard.js +146 -0
  7. package/src/cli-app/Screen.js +135 -0
  8. package/src/cli-app/elements/ElementNode.js +97 -0
  9. package/src/cli-app/elements/Line.js +21 -0
  10. package/src/cli-app/elements/List/List.js +227 -0
  11. package/src/cli-app/elements/List/ListCell.js +83 -0
  12. package/src/cli-app/elements/List/ListColumn.js +52 -0
  13. package/src/cli-app/elements/List/ListRow.js +118 -0
  14. package/src/cli-app/elements/Row.js +38 -0
  15. package/src/cli-app/helper/utils.js +42 -0
  16. package/src/commands/Action/addDelValuesAction.js +56 -0
  17. package/src/commands/CommandAuth.js +32 -0
  18. package/src/commands/CommandClearAll.js +27 -0
  19. package/src/commands/CommandConfig.js +57 -0
  20. package/src/commands/CommandHTTP.js +131 -0
  21. package/src/commands/CommandInvite.js +38 -0
  22. package/src/commands/CommandRefresh.js +35 -0
  23. package/src/commands/CommandRegister.js +48 -0
  24. package/src/commands/Option/DeleteOption.js +6 -0
  25. package/src/commands/Option/SelectConfigOption.js +52 -0
  26. package/src/commands/SubCommand/AllowDenyCidrCommand.js +28 -0
  27. package/src/commands/SubCommand/HostCommand.js +22 -0
  28. package/src/commands/SubCommand/PortCommand.js +20 -0
  29. package/src/commands/helper/AliasResolver.js +13 -0
  30. package/src/commands/helper/BindArgs.js +53 -0
  31. package/src/commands/helper/SharedArg.js +32 -0
  32. package/src/commands/utils.js +96 -0
  33. package/src/config/ConfigAbstract.js +318 -0
  34. package/src/config/ConfigManager.js +70 -0
  35. package/src/config/GlobalConfig.js +14 -0
  36. package/src/config/GlobalLocalShardConfigAbstract.js +76 -0
  37. package/src/config/LocalConfig.js +7 -0
  38. package/src/config/PropertyConfig.js +122 -0
  39. package/src/config/SystemConfig.js +31 -0
  40. package/src/core/FS/utils.js +60 -0
  41. package/src/core/Ref.js +70 -0
  42. package/src/lib/Flow/getCurrentIp.js +18 -0
  43. package/src/lib/Flow/getLatestVersion.js +13 -0
  44. package/src/lib/Flow/proxyUrl.js +32 -0
  45. package/src/lib/Flow/validateAuthToken.js +19 -0
  46. package/src/lib/HttpClient.js +61 -0
  47. package/src/lib/defs.js +10 -0
  48. package/src/net/IPV4.js +139 -0
  49. package/src/net/http/IncomingMessage.js +92 -0
  50. package/src/net/http/ServerResponse.js +126 -0
  51. package/src/net/http/TunliRequest.js +1 -0
  52. package/src/net/http/TunliResponse.js +1 -0
  53. package/src/net/http/TunnelRequest.js +177 -0
  54. package/src/net/http/TunnelResponse.js +119 -0
  55. package/src/tunnel-client/TunnelClient.js +136 -0
  56. package/src/utils/arrayFunctions.js +45 -0
  57. package/src/utils/checkFunctions.js +161 -0
  58. package/src/utils/cliFunctions.js +62 -0
  59. package/src/utils/createRequest.js +12 -0
  60. package/src/utils/httpFunction.js +23 -0
  61. package/src/utils/npmFunctions.js +27 -0
  62. package/src/utils/stringFunctions.js +34 -0
  63. package/types/index.d.ts +112 -0
@@ -0,0 +1,318 @@
1
+ import {writeFileSync} from "fs"
2
+ import {dirname} from 'path'
3
+ import {ensureDirectoryExists} from "#src/core/FS/utils";
4
+ import {PropertyConfig} from "#src/config/PropertyConfig";
5
+
6
+ const callerStack = new Map()
7
+
8
+ /**
9
+ * Mark a value with a caller reference.
10
+ * @param {Object} callee - The caller object.
11
+ * @param {*} value - The value to be marked.
12
+ * @returns {*} - The marked value.
13
+ */
14
+ const caller = (callee, value) => {
15
+ value = {value}
16
+ callerStack.set(value, callee)
17
+ return value
18
+ }
19
+
20
+ /**
21
+ * Check if a value is marked with a caller reference.
22
+ * @param {*} value - The value to check.
23
+ * @returns {boolean} - True if the value is marked, false otherwise.
24
+ */
25
+ const isCaller = (value) => {
26
+ return callerStack.has(value)
27
+ }
28
+
29
+ /**
30
+ * Retrieve the caller reference for a value.
31
+ * @param {*} value - The value with the caller reference.
32
+ * @returns {Object} - The caller object.
33
+ */
34
+ const callee = (value) => {
35
+ return callerStack.get(value)
36
+ }
37
+
38
+ export const VISIBILITY_PRIVATE = 0
39
+ export const VISIBILITY_PUBLIC = 1
40
+
41
+ /**
42
+ * Abstract class representing the basic configuration functionality.
43
+ * @implements {AppConfig}
44
+ */
45
+ export class ConfigAbstract {
46
+ /**
47
+ * Configuration data.
48
+ * @type {Object}
49
+ * @private
50
+ */
51
+ #data = {}
52
+
53
+ /**
54
+ * Profile and system configuration data.
55
+ * @type {Object}
56
+ * @private
57
+ */
58
+ #profileData = {
59
+ profile: {}, system: {},
60
+ }
61
+
62
+ /**
63
+ * Path to the configuration file.
64
+ * @type {string}
65
+ * @private
66
+ */
67
+ #path
68
+
69
+ /**
70
+ * Fallback configuration instance.
71
+ * @type {ConfigAbstract}
72
+ * @private
73
+ */
74
+ #fallbackConfig
75
+
76
+ /**
77
+ * Defined properties.
78
+ * @type {Array<string>}
79
+ * @private
80
+ */
81
+ #definedProperties = []
82
+
83
+ /**
84
+ * Property configuration.
85
+ * @type {Object<string, PropertyConfig>}
86
+ * @private
87
+ */
88
+ #propertyConfig
89
+
90
+ /**
91
+ * Defined properties with inheritance.
92
+ * @type {Array<string>}
93
+ * @private
94
+ */
95
+ #definedWithInheritProperties
96
+
97
+ /**
98
+ * Active profile name.
99
+ * @type {string}
100
+ * @private
101
+ */
102
+ #activeProfile = 'default'
103
+
104
+ /**
105
+ * Create a ConfigAbstract instance.
106
+ * @param {Object} prefillData - Initial data to prefill the configuration.
107
+ * @param {string} path - The path to the configuration file.
108
+ * @param {ConfigAbstract} [fallbackConfig] - The fallback configuration.
109
+ */
110
+ constructor(prefillData = {}, path, fallbackConfig) {
111
+ this.#profileData = prefillData
112
+ this.#profileData.profile ??= {}
113
+ this.#profileData.system ??= {}
114
+ this.#path = path
115
+ this.#fallbackConfig = fallbackConfig
116
+ }
117
+
118
+ /**
119
+ * Get the fallback configuration.
120
+ * @return {ConfigAbstract}
121
+ */
122
+ get fallbackConfig() {
123
+ return this.#fallbackConfig
124
+ }
125
+
126
+ /**
127
+ * Get the profile data.
128
+ * @return {profileConfig}
129
+ */
130
+ get profileData() {
131
+ return this.#profileData
132
+ }
133
+
134
+ /**
135
+ * Get the configuration path.
136
+ * @return {string}
137
+ */
138
+ get configPath() {
139
+ return this.#path
140
+ }
141
+
142
+ get profile() {
143
+ return this.#activeProfile
144
+ }
145
+
146
+ /**
147
+ * Prepare the configuration by defining properties.
148
+ * @param {{[p: string]: PropertyConfig}} propertyConfig - The configuration properties.
149
+ */
150
+ prepare(propertyConfig = {}) {
151
+ this.#propertyConfig = propertyConfig
152
+
153
+ /**
154
+ * Define a property.
155
+ * @param {string} name - The name of the property.
156
+ * @param {PropertyConfig} propertyConfig - The configuration of the property.
157
+ */
158
+ const defineProperty = (name, propertyConfig) => {
159
+
160
+ let {writeable, visibility, type, defaultValue} = propertyConfig
161
+
162
+ this.#definedProperties.push(name)
163
+ const attributes = {
164
+ get: () => {
165
+ return this.#data[name] ?? this.#fallbackConfig?.[name] ?? defaultValue
166
+ }
167
+ }
168
+
169
+ if (writeable) {
170
+ /**
171
+ * Set the value of the property.
172
+ * This method checks if the value is marked with a caller reference
173
+ * and handles the writeable state accordingly. If the property is
174
+ * not writeable, an error is thrown. The value is also validated
175
+ * if a validation function is provided. Finally, the validated
176
+ * value is stored in the configuration data.
177
+ *
178
+ * @param {*} value - The value to set.
179
+ * @throws {Error} If the property is not writeable.
180
+ */
181
+ attributes.set = (value) => {
182
+ if (isCaller(value)) {
183
+ const writer = callee(value)
184
+ if (writeable && writeable !== true) {
185
+ writeable = writer instanceof writeable
186
+ }
187
+ value = value.value
188
+ }
189
+
190
+ if (!writeable) {
191
+ throw new Error(`property ${name} is not writeable`)
192
+ }
193
+
194
+ if (propertyConfig.validate) {
195
+ value = propertyConfig.validate(value)
196
+ }
197
+
198
+ this.#data[name] = value
199
+ }
200
+ }
201
+
202
+ Object.defineProperty(this, name, attributes)
203
+ }
204
+
205
+ for (const [name, setting] of Object.entries(propertyConfig)) {
206
+ defineProperty(name, setting)
207
+ }
208
+
209
+ this.#definedWithInheritProperties = Array.from(new Set([
210
+ ...this.#definedProperties,
211
+ ...(this.#fallbackConfig?.#definedWithInheritProperties ?? [])
212
+ ]))
213
+
214
+ for (const name of this.#fallbackConfig?.#definedWithInheritProperties ?? []) {
215
+ if (this.#definedProperties.includes(name)) {
216
+ continue
217
+ }
218
+
219
+ Object.defineProperty(this, name, {
220
+ get: () => {
221
+ return this.#fallbackConfig[name]
222
+ },
223
+ set: (value) => {
224
+ if (!isCaller(value)) {
225
+ value = caller(this, value)
226
+ }
227
+ this.#fallbackConfig[name] = value
228
+ }
229
+ })
230
+ }
231
+ }
232
+
233
+ /**
234
+ * Check if a property is public.
235
+ * @param {string} key - The property key.
236
+ * @returns {boolean} - True if the property is public, false otherwise.
237
+ */
238
+ isPublic(key) {
239
+ return this.#propertyConfig[key]?.visibility === VISIBILITY_PUBLIC
240
+ }
241
+
242
+ /**
243
+ * Save the configuration to the file system.
244
+ * @returns {ConfigAbstract} - The instance of the configuration.
245
+ */
246
+ save() {
247
+ ensureDirectoryExists(dirname(this.#path))
248
+ console.log(this.#path)
249
+ const isGlobal = this.constructor.name === 'GlobalConfig'
250
+ const isSystem = this.constructor.name === 'SystemConfig'
251
+
252
+ if (!isGlobal && !isSystem) {
253
+ delete this.#profileData.system
254
+ }
255
+
256
+ writeFileSync(this.#path, JSON.stringify(this.#profileData, null, 2) + "\n")
257
+ return this
258
+ }
259
+
260
+ /**
261
+ * Use the system configuration.
262
+ * @returns {ConfigAbstract} - The instance of the configuration.
263
+ */
264
+ useSystem() {
265
+ this.#data = this.#profileData.system
266
+ return this
267
+ }
268
+
269
+ /**
270
+ * Use a specific profile configuration.
271
+ * @param {string} profile - The profile name.
272
+ * @returns {ConfigAbstract} - The instance of the configuration.
273
+ */
274
+ use(profile) {
275
+ this.#profileData.profile[profile] ??= {}
276
+ this.#data = this.#profileData.profile[profile]
277
+ this.#activeProfile = profile
278
+ return this
279
+ }
280
+
281
+ /**
282
+ * Delete a property from the configuration.
283
+ * @param {string} key - The property key.
284
+ * @returns {ConfigAbstract} - The instance of the configuration.
285
+ */
286
+ del(key) {
287
+ this.#data[key] = undefined
288
+ return this
289
+ }
290
+
291
+ /**
292
+ * Copy the current profile to a new profile.
293
+ * @param {string} profile - The new profile name.
294
+ * @returns {ConfigAbstract} - The instance of the configuration.
295
+ */
296
+ copyCurrentProfileTo(profile) {
297
+ this.#profileData.profile[profile] = {...this.#data}
298
+ return this
299
+ }
300
+
301
+ /**
302
+ * Dump the configuration properties.
303
+ * @returns {Object} - The dumped properties.
304
+ */
305
+ dump() {
306
+ return Object.fromEntries(this.#definedProperties.map(x => {
307
+ let t = this[x]
308
+ if (Array.isArray(t)) {
309
+ if (t.length) {
310
+ t = t.join(', ')
311
+ } else {
312
+ t = undefined
313
+ }
314
+ }
315
+ return [x, t]
316
+ }))
317
+ }
318
+ }
@@ -0,0 +1,70 @@
1
+ import {resolve} from "path";
2
+ import {CONFIG_DIR_NAME, CONFIG_FILENAME, GLOBAL_CONFIG_DIR} from "#lib/defs";
3
+ import {readJsonFile, searchDirInDirectoryTree} from "#src/core/FS/utils";
4
+ import {existsSync} from "fs";
5
+
6
+ import {GlobalConfig} from "#src/config/GlobalConfig";
7
+ import {SystemConfig} from "#src/config/SystemConfig";
8
+ import {LocalConfig} from "#src/config/LocalConfig";
9
+
10
+ const LOCAL_CONFIG_DIR = resolve(process.cwd(), CONFIG_DIR_NAME)
11
+ export const WORKDIR_CONFIG_DIR = resolve(process.cwd(), CONFIG_DIR_NAME)
12
+
13
+ const searchConfigInDirectoryTree = () => {
14
+ return searchDirInDirectoryTree(CONFIG_DIR_NAME, undefined, [GLOBAL_CONFIG_DIR])
15
+ }
16
+
17
+ export class ConfigManager {
18
+
19
+ static loadLocalOnly(profile = 'default', searchInDirectoryTree = true) {
20
+ profile = normalizeProfileAlias(profile)
21
+
22
+ let configDirectory
23
+ if (searchInDirectoryTree) {
24
+ configDirectory = searchConfigInDirectoryTree() ?? LOCAL_CONFIG_DIR
25
+ } else {
26
+ configDirectory = LOCAL_CONFIG_DIR
27
+ }
28
+
29
+ const configFilePath = resolve(configDirectory, CONFIG_FILENAME);
30
+ const data = existsSync(configFilePath) ? readJsonFile(configFilePath) : {}
31
+
32
+ return new LocalConfig(data, configFilePath).use(profile)
33
+ }
34
+
35
+ static loadCombined(profile = 'default') {
36
+ profile = normalizeProfileAlias(profile)
37
+
38
+ const globalConfig = ConfigManager.loadGlobalOnly()
39
+ const localConfigDirectory = searchConfigInDirectoryTree() ?? LOCAL_CONFIG_DIR
40
+
41
+ const localConfigFilePath = resolve(localConfigDirectory, CONFIG_FILENAME);
42
+ const localExists = existsSync(localConfigFilePath)
43
+
44
+ if (localExists) {
45
+ return new LocalConfig(readJsonFile(localConfigFilePath), localConfigFilePath, globalConfig).use(profile)
46
+ }
47
+
48
+ return globalConfig.use(profile)
49
+ }
50
+
51
+ static loadSystem() {
52
+ const configFilePath = resolve(GLOBAL_CONFIG_DIR, CONFIG_FILENAME);
53
+ const data = existsSync(configFilePath) ? readJsonFile(configFilePath) : {}
54
+ return new SystemConfig(data)
55
+ }
56
+
57
+ static loadGlobalOnly(profile = 'default') {
58
+ profile = normalizeProfileAlias(profile)
59
+ const configFilePath = resolve(GLOBAL_CONFIG_DIR, CONFIG_FILENAME);
60
+ const data = existsSync(configFilePath) ? readJsonFile(configFilePath) : {}
61
+ return new GlobalConfig(data).use(profile)
62
+ }
63
+ }
64
+
65
+ const normalizeProfileAlias = (profileAlias) => {
66
+ if (typeof profileAlias === 'string' && profileAlias.startsWith('@')) {
67
+ profileAlias = profileAlias.toString().substring(1)
68
+ }
69
+ return profileAlias.toLowerCase()
70
+ }
@@ -0,0 +1,14 @@
1
+ import {GLOBAL_CONFIG_DIR} from "#lib/defs";
2
+ import {resolve} from "path";
3
+ import {GlobalLocalShardConfigAbstract} from "#src/config/GlobalLocalShardConfigAbstract";
4
+ import {SystemConfig} from "#src/config/SystemConfig";
5
+
6
+ export class GlobalConfig extends GlobalLocalShardConfigAbstract {
7
+
8
+ constructor(data) {
9
+ const alias = 'default'
10
+ const configFilePath = resolve(GLOBAL_CONFIG_DIR, `${alias}.json`);
11
+
12
+ super({}, data, configFilePath, new SystemConfig(data));
13
+ }
14
+ }
@@ -0,0 +1,76 @@
1
+ import {checkHost, checkIpV4Cidr, checkPort, checkUrl} from "#src/utils/checkFunctions";
2
+ import {ConfigAbstract, VISIBILITY_PUBLIC} from "#src/config/ConfigAbstract";
3
+ import {property} from "#src/config/PropertyConfig";
4
+ import {ConfigManager} from "#src/config/ConfigManager";
5
+
6
+ /**
7
+ * Abstract class for managing global and local shard configurations.
8
+ * Extends the ConfigAbstract class to include properties specific to network configuration.
9
+ */
10
+ export class GlobalLocalShardConfigAbstract extends ConfigAbstract {
11
+
12
+ #config = {
13
+
14
+ allowCidr: property({
15
+ visibility: VISIBILITY_PUBLIC,
16
+ writeable: true,
17
+ type: Array,
18
+ defaultValue: [],
19
+ validate(val) {
20
+ return val.map(checkIpV4Cidr)
21
+ }
22
+ }),
23
+ proxyURL: property({
24
+ visibility: VISIBILITY_PUBLIC,
25
+ writeable: true,
26
+ type: String,
27
+ validate(val) {
28
+ if (!val) {
29
+ return
30
+ }
31
+ return checkUrl(val)
32
+ }
33
+ }),
34
+ denyCidr: property({
35
+ visibility: VISIBILITY_PUBLIC,
36
+ writeable: true,
37
+ type: Array,
38
+ defaultValue: [],
39
+ validate(val) {
40
+ return val.map(checkIpV4Cidr)
41
+ }
42
+ }),
43
+ port: property({
44
+ visibility: VISIBILITY_PUBLIC,
45
+ writeable: true,
46
+ type: Number,
47
+ defaultValue: 80,
48
+ validate(val) {
49
+ return checkPort(val)
50
+ }
51
+ }),
52
+ host: property({
53
+ visibility: VISIBILITY_PUBLIC,
54
+ writeable: true,
55
+ type: String,
56
+ defaultValue: '127.0.0.1',
57
+ validate(val) {
58
+ return checkHost(val)
59
+ }
60
+ }),
61
+ }
62
+
63
+ /**
64
+ * Create a GlobalLocalShardConfigAbstract.
65
+ * @param {Object} additionalConfig - Additional configuration properties to be merged with the default config.
66
+ * @param {Object} prefillData - Initial data to prefill the configuration.
67
+ * @param {string} path - The path to the configuration file.
68
+ * @param {ConfigAbstract} fallbackConfig - The fallback configuration to be used when specific data is not available.
69
+ */
70
+ constructor(additionalConfig = {}, prefillData = {}, path, fallbackConfig) {
71
+ fallbackConfig ??= ConfigManager.loadSystem()
72
+ super(prefillData, path, fallbackConfig)
73
+ this.prepare({...this.#config, ...additionalConfig})
74
+ this.use('default')
75
+ }
76
+ }
@@ -0,0 +1,7 @@
1
+ import {GlobalLocalShardConfigAbstract} from "#src/config/GlobalLocalShardConfigAbstract";
2
+
3
+ export class LocalConfig extends GlobalLocalShardConfigAbstract {
4
+ constructor(data, path, globalConfig) {
5
+ super({}, data, path, globalConfig);
6
+ }
7
+ }
@@ -0,0 +1,122 @@
1
+ /**
2
+ * @callback validationCallback
3
+ * @template T
4
+ * @param {T} value
5
+ * @throws Error
6
+ * @returns {T}
7
+ */
8
+
9
+ /**
10
+ * Class representing the configuration of a property.
11
+ */
12
+ export class PropertyConfig {
13
+ /**
14
+ * The raw configuration data.
15
+ * @type {Object}
16
+ */
17
+ #data
18
+
19
+ /**
20
+ * The visibility level of the property.
21
+ * @type {number}
22
+ */
23
+ #visibility
24
+
25
+ /**
26
+ * Indicates if the property is writeable.
27
+ * When true, the property can be written to.
28
+ * If an instance of ConfigAbstract, only that instance can change the value.
29
+ * @type {boolean|ConfigAbstract}
30
+ */
31
+ #writeable
32
+
33
+ /**
34
+ * The validation function for the property.
35
+ * @type {validationCallback}
36
+ */
37
+ #validate
38
+
39
+ /**
40
+ * Default value for the property.
41
+ * @type {any}
42
+ */
43
+ #defaultValue
44
+
45
+ /**
46
+ * The type of the property.
47
+ * @type {Object}
48
+ */
49
+ #type
50
+
51
+ /**
52
+ * Create a PropertyConfig.
53
+ * @param {Object} data - The configuration data for the property.
54
+ * @param {number} data.visibility - The visibility level of the property.
55
+ * @param {boolean|ConfigAbstract} data.writeable - Indicates if the property is writeable.
56
+ * @param {validationCallback} data.validate - The validation function for the property.
57
+ * @param {any} data.defaultValue - The default value of the property.
58
+ * @param {Object} data.type - The type of the property.
59
+ */
60
+ constructor(data) {
61
+ this.#data = data
62
+ this.#visibility = data.visibility
63
+ this.#writeable = data.writeable
64
+ this.#validate = data.validate
65
+ this.#defaultValue = data.defaultValue
66
+ this.#type = data.type
67
+ }
68
+
69
+ /**
70
+ * Get the visibility of the property.
71
+ * @returns {number} The visibility level of the property.
72
+ */
73
+ get visibility() {
74
+ return this.#visibility
75
+ }
76
+
77
+ /**
78
+ * Check if the property is writeable.
79
+ * @returns {boolean|ConfigAbstract} True if the property is writeable, false otherwise.
80
+ */
81
+ get writeable() {
82
+ return this.#writeable
83
+ }
84
+
85
+ /**
86
+ * Get the validation function for the property.
87
+ * @returns {validationCallback} The validation function.
88
+ */
89
+ get validate() {
90
+ return this.#validate
91
+ }
92
+
93
+ /**
94
+ * Get the default value of the property.
95
+ * @returns {*} The default value of the property.
96
+ */
97
+ get defaultValue() {
98
+ return this.#defaultValue
99
+ }
100
+
101
+ /**
102
+ * Get the type of the property.
103
+ * @returns {Object} The type of the property.
104
+ */
105
+ get type() {
106
+ return this.#type
107
+ }
108
+ }
109
+
110
+ /**
111
+ * Factory function to create a PropertyConfig instance.
112
+ * @param {Object} propertySetup - The setup configuration for the property.
113
+ * @param {boolean|ConfigAbstract} propertySetup.writeable - Indicates if the property is writeable.
114
+ * @param {Object} propertySetup.type - The type of the property.
115
+ * @param {function} [propertySetup.validate] - The validation function for the property.
116
+ * @param {number} propertySetup.visibility - The visibility level of the property.
117
+ * @param {any} [propertySetup.defaultValue] - The default value of the property.
118
+ * @returns {PropertyConfig} The instance of PropertyConfig.
119
+ */
120
+ export const property = (propertySetup) => {
121
+ return new PropertyConfig(propertySetup)
122
+ }
@@ -0,0 +1,31 @@
1
+ import {GLOBAL_CONFIG_DIR} from "#lib/defs";
2
+ import {resolve} from "path";
3
+ import {ConfigAbstract, VISIBILITY_PRIVATE} from "#src/config/ConfigAbstract";
4
+ import {property} from "#src/config/PropertyConfig";
5
+
6
+
7
+ /**
8
+ * Class representing the system configuration.
9
+ * Extends ConfigAbstract to provide specific configuration for system settings.
10
+ */
11
+ export class SystemConfig extends ConfigAbstract {
12
+ /**
13
+ * Create a SystemConfig instance.
14
+ * @param {Object} data - Initial data to prefill the configuration.
15
+ */
16
+ constructor(data) {
17
+ const alias = 'default'
18
+ const configFilePath = resolve(GLOBAL_CONFIG_DIR, `${alias}.json`)
19
+
20
+ super(data, configFilePath)
21
+
22
+ this.prepare({
23
+ authToken: property({
24
+ visibility: VISIBILITY_PRIVATE,
25
+ writeable: SystemConfig,
26
+ type: String
27
+ })
28
+ })
29
+ this.useSystem()
30
+ }
31
+ }
@@ -0,0 +1,60 @@
1
+ import {existsSync, lstatSync, mkdirSync, readFileSync} from "fs";
2
+ import {dirname, join, parse} from "path";
3
+ import {fileURLToPath} from "url";
4
+
5
+ export const ensureDirectoryExists = (directory) => {
6
+ if (!existsSync(directory)) {
7
+ mkdirSync(directory)
8
+ }
9
+ }
10
+
11
+ export const searchDirInDirectoryTree = (dirnameToSearch, dir = process.cwd(), excludeDirectories = []) => {
12
+
13
+ dir ??= process.cwd()
14
+
15
+ while (dir !== parse(dir).root) {
16
+ const configPath = join(dir, dirnameToSearch);
17
+
18
+ dir = dirname(dir);
19
+
20
+ if (excludeDirectories.includes(configPath)) {
21
+ continue
22
+ }
23
+
24
+ if (existsSync(configPath) && lstatSync(configPath).isDirectory()) {
25
+ return configPath
26
+ }
27
+ }
28
+
29
+ return null;
30
+ }
31
+ export const searchFileInDirectoryTree = (filenameToSearch, dir = process.cwd(), excludeDirectories = []) => {
32
+
33
+ dir ??= process.cwd()
34
+
35
+ while (dir !== parse(dir).root) {
36
+ const configPath = join(dir, filenameToSearch);
37
+ dir = dirname(dir);
38
+
39
+ if (excludeDirectories.includes(configPath)) {
40
+ continue
41
+ }
42
+
43
+ if (existsSync(configPath) && lstatSync(configPath).isFile()) {
44
+ return configPath
45
+ }
46
+ }
47
+
48
+ return null;
49
+ }
50
+
51
+ export const readJsonFile = (configFilePath) => {
52
+ return JSON.parse(readFileSync(configFilePath, 'utf8'))
53
+ }
54
+
55
+ export const dirnameFromMeta = (importMeta) => {
56
+ return dirname(filenameFromMeta(importMeta));
57
+ }
58
+ export const filenameFromMeta = (importMeta) => {
59
+ return fileURLToPath(importMeta.url);
60
+ }