@scaleway/configuration-loader 2.1.0 → 2.3.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.
@@ -1,18 +1,23 @@
1
1
 
2
- > @scaleway/configuration-loader@2.1.0 build /home/runner/work/scaleway-sdk-js/scaleway-sdk-js/packages/configuration-loader
2
+ > @scaleway/configuration-loader@2.2.0 build /home/runner/work/scaleway-sdk-js/scaleway-sdk-js/packages/configuration-loader
3
3
  > vite build --config ../../vite.config.ts && pnpm run type:generate
4
4
 
5
- vite v7.2.4 building ssr environment for production...
6
- transforming...
7
- ✓ 5 modules transformed.
5
+ vite v8.0.1 building ssr environment for production...
6
+ 
8
7
  rendering chunks...
9
- dist/index.js 0.27 kB
10
- dist/env.js 0.62 kB
11
- dist/path-resolver.js 0.75 kB
12
- dist/yml-loader.js 1.27 kB
13
- dist/config-loader.js 1.93 kB
14
- ✓ built in 136ms
8
+ computing gzip size...
9
+ dist/types.js 0.00 kB │ gzip: 0.02 kB
10
+ dist/index.js 0.51 kB │ gzip: 0.16 kB
11
+ dist/env.js 0.94 kB │ gzip: 0.41 kB
12
+ dist/path-resolver.js 0.96 kB │ gzip: 0.41 kB
13
+ dist/__tests__/path-resolver.test.js 1.50 kB │ gzip: 0.57 kB
14
+ dist/__tests__/yml-loader.test.js 2.63 kB │ gzip: 0.81 kB
15
+ dist/yml-loader.js 2.78 kB │ gzip: 1.09 kB
16
+ dist/__tests__/config-loader.test.js 3.08 kB │ gzip: 1.04 kB
17
+ dist/config-loader.js 4.34 kB │ gzip: 0.95 kB
15
18
 
16
- > @scaleway/configuration-loader@2.1.0 type:generate /home/runner/work/scaleway-sdk-js/scaleway-sdk-js/packages/configuration-loader
19
+ ✓ built in 32ms
20
+
21
+ > @scaleway/configuration-loader@2.2.0 type:generate /home/runner/work/scaleway-sdk-js/scaleway-sdk-js/packages/configuration-loader
17
22
  > tsc --declaration -p tsconfig.build.json
18
23
 
package/CHANGELOG.md CHANGED
@@ -3,6 +3,18 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # 2.3.0 (2026-04-02)
7
+
8
+ ### Features
9
+
10
+ - **configuration-loader:** add async config loading and file permission check ([#2860](https://github.com/scaleway/scaleway-sdk-js/issues/2860)) ([1377d94](https://github.com/scaleway/scaleway-sdk-js/commit/1377d94a2a01c6a717781513affd634c7fc61b98))
11
+
12
+ # 2.2.0 (2026-03-05)
13
+
14
+ ### Features
15
+
16
+ - **sdk-react:** add react sdk ([#2794](https://github.com/scaleway/scaleway-sdk-js/issues/2794)) ([7dfbf6b](https://github.com/scaleway/scaleway-sdk-js/commit/7dfbf6b4d4eae5f95cd05ff7433e30c522619475))
17
+
6
18
  # 2.1.0 (2025-12-19)
7
19
 
8
20
  ### Bug Fixes
package/biome.jsonc ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "$schema": "../../node_modules/@biomejs/biome/configuration_schema.json",
3
+ "assist": {
4
+ "actions": {
5
+ "source": {
6
+ "organizeImports": "on"
7
+ }
8
+ },
9
+ "enabled": true
10
+ },
11
+ "extends": "//",
12
+ "root": false
13
+ }
@@ -32,3 +32,32 @@ export declare const loadAllProfilesFromConfigurationFile: (params?: Readonly<Al
32
32
  * @public
33
33
  */
34
34
  export declare const loadProfileFromConfigurationFile: (params?: Readonly<ProfileFromFileParams>) => Profile;
35
+ /**
36
+ * Loads all profiles from configuration file (asynchronous).
37
+ *
38
+ * Non-blocking alternative to {@link loadAllProfilesFromConfigurationFile}.
39
+ *
40
+ * @param params - The parameters to load the profile
41
+ * @returns The profiles filled with values found in the configuration profile
42
+ *
43
+ * @throws Error
44
+ * Thrown if the configuration file couldn't be found.
45
+ *
46
+ * @public
47
+ */
48
+ export declare const loadAllProfilesFromConfigurationFileAsync: (params?: Readonly<AllProfilesFromFileParams>) => Promise<Record<string, Profile>>;
49
+ /**
50
+ * Loads profile from configuration file (asynchronous).
51
+ *
52
+ * Non-blocking alternative to {@link loadProfileFromConfigurationFile}.
53
+ *
54
+ * @param params - The parameters to load the profile
55
+ * @returns The profile filled with values found in the configuration profile
56
+ *
57
+ * @throws Error
58
+ * Thrown if the configuration file couldn't be found,
59
+ * or if the specified profile can't be found.
60
+ *
61
+ * @public
62
+ */
63
+ export declare const loadProfileFromConfigurationFileAsync: (params?: Readonly<ProfileFromFileParams>) => Promise<Profile>;
@@ -1,50 +1,112 @@
1
- import { env } from "node:process";
2
1
  import { EnvironmentKey } from "./env.js";
3
2
  import { resolveConfigurationFilePath } from "./path-resolver.js";
4
- import { loadConfigurationFromFile } from "./yml-loader.js";
5
- const convertFileConfigToSDK = (obj) => ({
6
- accessKey: obj.access_key,
7
- apiURL: obj.api_url,
8
- defaultOrganizationId: obj.default_organization_id,
9
- defaultProjectId: obj.default_project_id,
10
- defaultRegion: obj.default_region,
11
- defaultZone: obj.default_zone,
12
- secretKey: obj.secret_key
3
+ import { loadConfigurationFromFile, loadConfigurationFromFileAsync } from "./yml-loader.js";
4
+ import { env } from "node:process";
5
+ //#region src/config-loader.ts
6
+ var convertFileConfigToSDK = (obj) => ({
7
+ accessKey: obj.access_key,
8
+ apiURL: obj.api_url,
9
+ defaultOrganizationId: obj.default_organization_id,
10
+ defaultProjectId: obj.default_project_id,
11
+ defaultRegion: obj.default_region,
12
+ defaultZone: obj.default_zone,
13
+ secretKey: obj.secret_key
13
14
  });
14
- const loadProfileFromEnvironmentValues = () => ({
15
- accessKey: env[EnvironmentKey.ScwAccessKey],
16
- apiURL: env[EnvironmentKey.ScwAPIURL],
17
- defaultOrganizationId: env[EnvironmentKey.ScwDefaultOrganizationId],
18
- defaultProjectId: env[EnvironmentKey.ScwDefaultProjectId],
19
- defaultRegion: env[EnvironmentKey.ScwDefaultRegion],
20
- defaultZone: env[EnvironmentKey.ScwDefaultZone],
21
- secretKey: env[EnvironmentKey.ScwSecretKey]
15
+ /**
16
+ * Loads profile from environment values.
17
+ *
18
+ * @returns The profile filled with values found in the environment
19
+ *
20
+ * @public
21
+ */
22
+ var loadProfileFromEnvironmentValues = () => ({
23
+ accessKey: env[EnvironmentKey.ScwAccessKey],
24
+ apiURL: env[EnvironmentKey.ScwAPIURL],
25
+ defaultOrganizationId: env[EnvironmentKey.ScwDefaultOrganizationId],
26
+ defaultProjectId: env[EnvironmentKey.ScwDefaultProjectId],
27
+ defaultRegion: env[EnvironmentKey.ScwDefaultRegion],
28
+ defaultZone: env[EnvironmentKey.ScwDefaultZone],
29
+ secretKey: env[EnvironmentKey.ScwSecretKey]
22
30
  });
23
- const loadAllProfilesFromConfigurationFile = (params) => {
24
- const filePath = params?.filepath ?? resolveConfigurationFilePath();
25
- if (typeof filePath !== "string" || filePath.length === 0) {
26
- throw new Error("Could not find the path to the configuration file.");
27
- }
28
- const configs = loadConfigurationFromFile(filePath);
29
- const result = {};
30
- for (const pKey of Object.keys(configs)) {
31
- result[pKey] = convertFileConfigToSDK(configs[pKey]);
32
- }
33
- return result;
31
+ /**
32
+ * Loads all the profiles from configuration file.
33
+ *
34
+ * @param params - The parameters to load the profile
35
+ * @returns The profiles filled with values found in the configuration profile
36
+ *
37
+ * @throws Error
38
+ * Thrown if the configuration file couldn't be found.
39
+ *
40
+ * @public
41
+ */
42
+ var loadAllProfilesFromConfigurationFile = (params) => {
43
+ const filePath = params?.filepath ?? resolveConfigurationFilePath();
44
+ if (typeof filePath !== "string" || filePath.length === 0) throw new Error("Could not find the path to the configuration file.");
45
+ const configs = loadConfigurationFromFile(filePath);
46
+ const result = {};
47
+ for (const pKey of Object.keys(configs)) result[pKey] = convertFileConfigToSDK(configs[pKey]);
48
+ return result;
49
+ };
50
+ /**
51
+ * Loads profile from configuration file.
52
+ *
53
+ * @param params - The parameters to load the profile
54
+ * @returns The profile filled with values found in the configuration profile
55
+ *
56
+ * @throws Error
57
+ * Thrown if the configuration file couldn't be found,
58
+ * or if the specified profile can't be found.
59
+ *
60
+ * @public
61
+ */
62
+ var loadProfileFromConfigurationFile = (params) => {
63
+ const configs = loadAllProfilesFromConfigurationFile(params);
64
+ const profileName = params?.profileName ?? "default";
65
+ const profileMap = configs[profileName];
66
+ if (typeof profileMap !== "object") throw new Error(`Could not find the desired profile '${profileName}' in the configuration file.`);
67
+ return profileMap;
34
68
  };
35
- const loadProfileFromConfigurationFile = (params) => {
36
- const configs = loadAllProfilesFromConfigurationFile(params);
37
- const profileName = params?.profileName ?? "default";
38
- const profileMap = configs[profileName];
39
- if (typeof profileMap !== "object") {
40
- throw new Error(
41
- `Could not find the desired profile '${profileName}' in the configuration file.`
42
- );
43
- }
44
- return profileMap;
69
+ /**
70
+ * Loads all profiles from configuration file (asynchronous).
71
+ *
72
+ * Non-blocking alternative to {@link loadAllProfilesFromConfigurationFile}.
73
+ *
74
+ * @param params - The parameters to load the profile
75
+ * @returns The profiles filled with values found in the configuration profile
76
+ *
77
+ * @throws Error
78
+ * Thrown if the configuration file couldn't be found.
79
+ *
80
+ * @public
81
+ */
82
+ var loadAllProfilesFromConfigurationFileAsync = async (params) => {
83
+ const filePath = params?.filepath ?? resolveConfigurationFilePath();
84
+ if (typeof filePath !== "string" || filePath.length === 0) throw new Error("Could not find the path to the configuration file.");
85
+ const configs = await loadConfigurationFromFileAsync(filePath);
86
+ const result = {};
87
+ for (const pKey of Object.keys(configs)) result[pKey] = convertFileConfigToSDK(configs[pKey]);
88
+ return result;
45
89
  };
46
- export {
47
- loadAllProfilesFromConfigurationFile,
48
- loadProfileFromConfigurationFile,
49
- loadProfileFromEnvironmentValues
90
+ /**
91
+ * Loads profile from configuration file (asynchronous).
92
+ *
93
+ * Non-blocking alternative to {@link loadProfileFromConfigurationFile}.
94
+ *
95
+ * @param params - The parameters to load the profile
96
+ * @returns The profile filled with values found in the configuration profile
97
+ *
98
+ * @throws Error
99
+ * Thrown if the configuration file couldn't be found,
100
+ * or if the specified profile can't be found.
101
+ *
102
+ * @public
103
+ */
104
+ var loadProfileFromConfigurationFileAsync = async (params) => {
105
+ const configs = await loadAllProfilesFromConfigurationFileAsync(params);
106
+ const profileName = params?.profileName ?? "default";
107
+ const profileMap = configs[profileName];
108
+ if (typeof profileMap !== "object") throw new Error(`Could not find the desired profile '${profileName}' in the configuration file.`);
109
+ return profileMap;
50
110
  };
111
+ //#endregion
112
+ export { loadAllProfilesFromConfigurationFile, loadAllProfilesFromConfigurationFileAsync, loadProfileFromConfigurationFile, loadProfileFromConfigurationFileAsync, loadProfileFromEnvironmentValues };
package/dist/env.js CHANGED
@@ -1,14 +1,28 @@
1
- var EnvironmentKey = /* @__PURE__ */ ((EnvironmentKey2) => {
2
- EnvironmentKey2["ScwConfigPath"] = "SCW_CONFIG_PATH";
3
- EnvironmentKey2["ScwAccessKey"] = "SCW_ACCESS_KEY";
4
- EnvironmentKey2["ScwSecretKey"] = "SCW_SECRET_KEY";
5
- EnvironmentKey2["ScwAPIURL"] = "SCW_API_URL";
6
- EnvironmentKey2["ScwDefaultOrganizationId"] = "SCW_DEFAULT_ORGANIZATION_ID";
7
- EnvironmentKey2["ScwDefaultProjectId"] = "SCW_DEFAULT_PROJECT_ID";
8
- EnvironmentKey2["ScwDefaultRegion"] = "SCW_DEFAULT_REGION";
9
- EnvironmentKey2["ScwDefaultZone"] = "SCW_DEFAULT_ZONE";
10
- return EnvironmentKey2;
11
- })(EnvironmentKey || {});
12
- export {
13
- EnvironmentKey
14
- };
1
+ //#region src/env.ts
2
+ /**
3
+ * Environment Key.
4
+ */
5
+ var EnvironmentKey = /* @__PURE__ */ function(EnvironmentKey) {
6
+ /** Path to the Scaleway configuration file */
7
+ EnvironmentKey["ScwConfigPath"] = "SCW_CONFIG_PATH";
8
+ /** Scaleway access key */
9
+ EnvironmentKey["ScwAccessKey"] = "SCW_ACCESS_KEY";
10
+ /**
11
+ * Scaleway secret key
12
+ * @remarks #nosec G101
13
+ */
14
+ EnvironmentKey["ScwSecretKey"] = "SCW_SECRET_KEY";
15
+ /** Scaleway API URL */
16
+ EnvironmentKey["ScwAPIURL"] = "SCW_API_URL";
17
+ /** Scaleway default organization ID */
18
+ EnvironmentKey["ScwDefaultOrganizationId"] = "SCW_DEFAULT_ORGANIZATION_ID";
19
+ /** Scaleway default project ID */
20
+ EnvironmentKey["ScwDefaultProjectId"] = "SCW_DEFAULT_PROJECT_ID";
21
+ /** Scaleway default region */
22
+ EnvironmentKey["ScwDefaultRegion"] = "SCW_DEFAULT_REGION";
23
+ /** Scaleway default zone */
24
+ EnvironmentKey["ScwDefaultZone"] = "SCW_DEFAULT_ZONE";
25
+ return EnvironmentKey;
26
+ }({});
27
+ //#endregion
28
+ export { EnvironmentKey };
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
- export { loadAllProfilesFromConfigurationFile, loadProfileFromConfigurationFile, loadProfileFromEnvironmentValues, } from './config-loader.js';
1
+ export { loadAllProfilesFromConfigurationFile, loadAllProfilesFromConfigurationFileAsync, loadProfileFromConfigurationFile, loadProfileFromConfigurationFileAsync, loadProfileFromEnvironmentValues, } from './config-loader.js';
2
2
  export type { AllProfilesFromFileParams, Profile, ProfileFromFileParams, } from './types.js';
3
+ export { hasSecureFilePermissions } from './yml-loader.js';
package/dist/index.js CHANGED
@@ -1,6 +1,3 @@
1
- import { loadAllProfilesFromConfigurationFile, loadProfileFromConfigurationFile, loadProfileFromEnvironmentValues } from "./config-loader.js";
2
- export {
3
- loadAllProfilesFromConfigurationFile,
4
- loadProfileFromConfigurationFile,
5
- loadProfileFromEnvironmentValues
6
- };
1
+ import { hasSecureFilePermissions } from "./yml-loader.js";
2
+ import { loadAllProfilesFromConfigurationFile, loadAllProfilesFromConfigurationFileAsync, loadProfileFromConfigurationFile, loadProfileFromConfigurationFileAsync, loadProfileFromEnvironmentValues } from "./config-loader.js";
3
+ export { hasSecureFilePermissions, loadAllProfilesFromConfigurationFile, loadAllProfilesFromConfigurationFileAsync, loadProfileFromConfigurationFile, loadProfileFromConfigurationFileAsync, loadProfileFromEnvironmentValues };
@@ -1,22 +1,31 @@
1
+ import { EnvironmentKey } from "./env.js";
1
2
  import { homedir } from "node:os";
2
3
  import * as path from "node:path";
3
4
  import { env } from "node:process";
4
- import { EnvironmentKey } from "./env.js";
5
- const getScwConfigurationDirectory = () => {
6
- const xdgConfigPath = env.XDG_CONFIG_HOME;
7
- if (typeof xdgConfigPath === "string" && xdgConfigPath.length > 0) {
8
- return path.join(xdgConfigPath, "scw");
9
- }
10
- return path.join(homedir(), ".config", "scw");
11
- };
12
- const resolveConfigurationFilePath = () => {
13
- const envFilePath = env[EnvironmentKey.ScwConfigPath];
14
- if (typeof envFilePath === "string" && envFilePath.length > 0) {
15
- return envFilePath;
16
- }
17
- return path.join(getScwConfigurationDirectory(), "config.yaml");
5
+ //#region src/path-resolver.ts
6
+ /**
7
+ * Gets the Scaleway directory.
8
+ *
9
+ * @returns The path to the Scaleway diretory
10
+ *
11
+ * @internal
12
+ */
13
+ var getScwConfigurationDirectory = () => {
14
+ const xdgConfigPath = env.XDG_CONFIG_HOME;
15
+ if (typeof xdgConfigPath === "string" && xdgConfigPath.length > 0) return path.join(xdgConfigPath, "scw");
16
+ return path.join(homedir(), ".config", "scw");
18
17
  };
19
- export {
20
- getScwConfigurationDirectory,
21
- resolveConfigurationFilePath
18
+ /**
19
+ * Gets the configuration file path.
20
+ *
21
+ * @returns The path to the configuration file
22
+ *
23
+ * @internal
24
+ */
25
+ var resolveConfigurationFilePath = () => {
26
+ const envFilePath = env[EnvironmentKey.ScwConfigPath];
27
+ if (typeof envFilePath === "string" && envFilePath.length > 0) return envFilePath;
28
+ return path.join(getScwConfigurationDirectory(), "config.yaml");
22
29
  };
30
+ //#endregion
31
+ export { getScwConfigurationDirectory, resolveConfigurationFilePath };
package/dist/types.js ADDED
File without changes
@@ -9,7 +9,7 @@ import type { ConfigurationType } from './types.js';
9
9
  */
10
10
  export declare const convertYamlToConfiguration: (input: string | null) => ConfigurationType;
11
11
  /**
12
- * Loads configuration from a file.
12
+ * Loads configuration from a file (synchronous).
13
13
  *
14
14
  * @param filePath - Path to the configuration file
15
15
  * @returns The configuration
@@ -20,3 +20,32 @@ export declare const convertYamlToConfiguration: (input: string | null) => Confi
20
20
  * @internal
21
21
  */
22
22
  export declare const loadConfigurationFromFile: (filePath: string) => ConfigurationType;
23
+ /**
24
+ * Loads configuration from a file (asynchronous).
25
+ *
26
+ * Non-blocking alternative to {@link loadConfigurationFromFile} that avoids
27
+ * stalling the event loop on slow filesystems or large config files.
28
+ *
29
+ * @param filePath - Path to the configuration file
30
+ * @returns The configuration
31
+ *
32
+ * @throws Error
33
+ * Thrown if the file doesn't exist.
34
+ *
35
+ * @public
36
+ */
37
+ export declare const loadConfigurationFromFileAsync: (filePath: string) => Promise<ConfigurationType>;
38
+ /**
39
+ * Checks whether a configuration file has secure permissions.
40
+ *
41
+ * The Scaleway config file contains secret keys that grant full API access.
42
+ * On POSIX systems this function verifies the file is not readable by group
43
+ * or others (mode 0o600 or stricter). Returns `true` on Windows where POSIX
44
+ * permission bits are not meaningful.
45
+ *
46
+ * @param filePath - Path to the configuration file
47
+ * @returns `true` if the file has secure permissions (or on Windows)
48
+ *
49
+ * @public
50
+ */
51
+ export declare const hasSecureFilePermissions: (filePath: string) => Promise<boolean>;
@@ -1,41 +1,88 @@
1
- import { readFileSync } from "node:fs";
2
- const STRIP_COMMENT_REGEX = /(^|\s)[;#]/;
3
- const DETECT_SECTION_REGEX = /^\s*([\s\S]+?):\s*$/;
4
- const DETECT_ITEM_REGEX = /^\s*(.+?)\s*:\s*(.+?)\s*$/;
5
- const convertYamlToConfiguration = (input) => {
6
- let foundProfilesKey = false;
7
- let currentSection = "default";
8
- const map = {};
9
- if (typeof input !== "string") {
10
- return map;
11
- }
12
- input.split(/\r?\n/).forEach((rawLine) => {
13
- const line = rawLine.split(STRIP_COMMENT_REGEX)[0];
14
- const newSection = DETECT_SECTION_REGEX.exec(line);
15
- if (newSection) {
16
- currentSection = void 0;
17
- if (newSection[1] === "profiles") {
18
- foundProfilesKey = true;
19
- } else if (foundProfilesKey) {
20
- [, currentSection] = newSection;
21
- }
22
- } else if (currentSection) {
23
- const item = DETECT_ITEM_REGEX.exec(line);
24
- if (item) {
25
- if (typeof map[currentSection] !== "object") {
26
- map[currentSection] = {};
27
- }
28
- [, , map[currentSection][item[1]]] = item;
29
- }
30
- }
31
- });
32
- return map;
1
+ import { readFile, readFileSync, stat } from "node:fs";
2
+ import { promisify } from "node:util";
3
+ //#region src/yml-loader.ts
4
+ var readFileAsync = promisify(readFile);
5
+ var statAsync = promisify(stat);
6
+ var STRIP_COMMENT_REGEX = /(^|\s)[;#]/;
7
+ var DETECT_SECTION_REGEX = /^\s*([\s\S]+?):\s*$/;
8
+ var DETECT_ITEM_REGEX = /^\s*(.+?)\s*:\s*(.+?)\s*$/;
9
+ /**
10
+ * Converts YAML to configuration map.
11
+ *
12
+ * @param input - YAML string
13
+ * @returns The configuration map
14
+ *
15
+ * @internal
16
+ */
17
+ var convertYamlToConfiguration = (input) => {
18
+ let foundProfilesKey = false;
19
+ let currentSection = "default";
20
+ const map = {};
21
+ if (typeof input !== "string") return map;
22
+ input.split(/\r?\n/).forEach((rawLine) => {
23
+ const line = rawLine.split(STRIP_COMMENT_REGEX)[0];
24
+ const newSection = DETECT_SECTION_REGEX.exec(line);
25
+ if (newSection) {
26
+ currentSection = void 0;
27
+ if (newSection[1] === "profiles") foundProfilesKey = true;
28
+ else if (foundProfilesKey) [, currentSection] = newSection;
29
+ } else if (currentSection) {
30
+ const item = DETECT_ITEM_REGEX.exec(line);
31
+ if (item) {
32
+ if (typeof map[currentSection] !== "object") map[currentSection] = {};
33
+ [, , map[currentSection][item[1]]] = item;
34
+ }
35
+ }
36
+ });
37
+ return map;
33
38
  };
34
- const loadConfigurationFromFile = (filePath) => {
35
- const fileContent = readFileSync(filePath, "utf-8");
36
- return convertYamlToConfiguration(fileContent);
39
+ /**
40
+ * Loads configuration from a file (synchronous).
41
+ *
42
+ * @param filePath - Path to the configuration file
43
+ * @returns The configuration
44
+ *
45
+ * @throws Error
46
+ * Thrown if the file doesn't exist.
47
+ *
48
+ * @internal
49
+ */
50
+ var loadConfigurationFromFile = (filePath) => {
51
+ return convertYamlToConfiguration(readFileSync(filePath, "utf-8"));
37
52
  };
38
- export {
39
- convertYamlToConfiguration,
40
- loadConfigurationFromFile
53
+ /**
54
+ * Loads configuration from a file (asynchronous).
55
+ *
56
+ * Non-blocking alternative to {@link loadConfigurationFromFile} that avoids
57
+ * stalling the event loop on slow filesystems or large config files.
58
+ *
59
+ * @param filePath - Path to the configuration file
60
+ * @returns The configuration
61
+ *
62
+ * @throws Error
63
+ * Thrown if the file doesn't exist.
64
+ *
65
+ * @public
66
+ */
67
+ var loadConfigurationFromFileAsync = async (filePath) => {
68
+ return convertYamlToConfiguration(await readFileAsync(filePath, "utf-8"));
41
69
  };
70
+ /**
71
+ * Checks whether a configuration file has secure permissions.
72
+ *
73
+ * The Scaleway config file contains secret keys that grant full API access.
74
+ * On POSIX systems this function verifies the file is not readable by group
75
+ * or others (mode 0o600 or stricter). Returns `true` on Windows where POSIX
76
+ * permission bits are not meaningful.
77
+ *
78
+ * @param filePath - Path to the configuration file
79
+ * @returns `true` if the file has secure permissions (or on Windows)
80
+ *
81
+ * @public
82
+ */
83
+ var hasSecureFilePermissions = async (filePath) => {
84
+ if (process.platform === "win32") return true;
85
+ return ((await statAsync(filePath)).mode & 63) === 0;
86
+ };
87
+ //#endregion
88
+ export { convertYamlToConfiguration, hasSecureFilePermissions, loadConfigurationFromFile, loadConfigurationFromFileAsync };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scaleway/configuration-loader",
3
- "version": "2.1.0",
3
+ "version": "2.3.0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Load configuration via file or environment for NodeJS.",
6
6
  "publishConfig": {
@@ -22,7 +22,7 @@
22
22
  }
23
23
  },
24
24
  "devDependencies": {
25
- "@types/node": "18.19.130"
25
+ "@types/node": "20.19.35"
26
26
  },
27
27
  "scripts": {
28
28
  "typecheck": "tsc --noEmit",