-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathpackage-json-source.ts
More file actions
116 lines (101 loc) · 3.59 KB
/
package-json-source.ts
File metadata and controls
116 lines (101 loc) · 3.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/*
* Copyright (c) 2025, Salesforce, Inc.
* SPDX-License-Identifier: Apache-2
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
*/
/**
* package.json configuration source.
*
* Reads configuration from the `b2c` key in package.json.
* Only loads from cwd (project root), not from parent directories.
*
* @internal This module is internal to the SDK. Use ConfigResolver instead.
*/
import * as fs from 'node:fs';
import * as path from 'node:path';
import type {ConfigSource, ConfigLoadResult, ResolveConfigOptions, NormalizedConfig} from '../types.js';
import {getPopulatedFields} from '../mapping.js';
import {getLogger} from '../../logging/logger.js';
/**
* Fields allowed to be configured in package.json.
* These are non-sensitive, non-instance-specific configuration.
*/
const ALLOWED_FIELDS: (keyof NormalizedConfig)[] = [
'shortCode',
'clientId',
'mrtProject',
'mrtOrigin',
'accountManagerHost',
];
/**
* Structure of the b2c config in package.json
*/
interface PackageJsonB2CConfig {
shortCode?: string;
clientId?: string;
mrtProject?: string;
mrtOrigin?: string;
accountManagerHost?: string;
[key: string]: unknown;
}
/**
* Configuration source that loads from package.json `b2c` key.
*
* This source has the lowest priority (1000) and only provides
* non-sensitive, project-level defaults.
*
* @internal
*/
export class PackageJsonSource implements ConfigSource {
readonly name = 'PackageJsonSource';
readonly priority = 1000;
load(options: ResolveConfigOptions): ConfigLoadResult | undefined {
const logger = getLogger();
// Only look in cwd (or startDir if provided)
const searchDir = options.startDir ?? process.cwd();
const packageJsonPath = path.join(searchDir, 'package.json');
logger.trace({location: packageJsonPath}, '[PackageJsonSource] Checking for package.json');
if (!fs.existsSync(packageJsonPath)) {
logger.trace('[PackageJsonSource] No package.json found');
return undefined;
}
try {
const content = fs.readFileSync(packageJsonPath, 'utf8');
const packageJson = JSON.parse(content) as {b2c?: PackageJsonB2CConfig};
if (!packageJson.b2c) {
logger.trace('[PackageJsonSource] No b2c key in package.json');
return undefined;
}
const b2cConfig = packageJson.b2c;
const config: NormalizedConfig = {};
// Only copy allowed fields
for (const field of ALLOWED_FIELDS) {
const value = b2cConfig[field];
if (value !== undefined) {
(config as Record<string, unknown>)[field] = value;
}
}
// Warn about disallowed fields
const disallowedFields = Object.keys(b2cConfig).filter(
(key) => !ALLOWED_FIELDS.includes(key as keyof NormalizedConfig),
);
if (disallowedFields.length > 0) {
logger.warn(
{disallowedFields},
'[PackageJsonSource] Ignoring sensitive/instance-specific fields in package.json b2c config',
);
}
const fields = getPopulatedFields(config);
if (fields.length === 0) {
logger.trace('[PackageJsonSource] b2c key present but no allowed fields populated');
return undefined;
}
logger.trace({location: packageJsonPath, fields}, '[PackageJsonSource] Loaded config');
return {config, location: packageJsonPath};
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
logger.trace({location: packageJsonPath, error: message}, '[PackageJsonSource] Failed to parse package.json');
return undefined;
}
}
}