@contrail/flexplm 1.7.4-alpha.aaaa660 → 1.7.4-alpha.ad2bc4e

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,249 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.ConfigUploadCommand = void 0;
27
- const child_process_1 = require("child_process");
28
- const fs = __importStar(require("fs"));
29
- const path = __importStar(require("path"));
30
- const readline = __importStar(require("readline"));
31
- const sdk_1 = require("@contrail/sdk");
32
- class ConfigUploadCommand {
33
- static parseArgs(args) {
34
- let filePath;
35
- let message;
36
- let branch;
37
- let skipGit = false;
38
- let updateConfig = false;
39
- for (let i = 0; i < args.length; i++) {
40
- const a = args[i];
41
- if (a === '-m') {
42
- message = args[++i];
43
- if (message === undefined) {
44
- throw new Error('-m requires a commit message argument');
45
- }
46
- }
47
- else if (a === '-b') {
48
- branch = args[++i];
49
- if (branch === undefined) {
50
- throw new Error('-b requires a branch name argument');
51
- }
52
- }
53
- else if (a === '--skip-git' || a === '--skipGit') {
54
- skipGit = true;
55
- }
56
- else if (a === '--update-config') {
57
- updateConfig = true;
58
- }
59
- else if (a.startsWith('-')) {
60
- throw new Error(`Unknown option: ${a}`);
61
- }
62
- else if (!filePath) {
63
- filePath = a;
64
- }
65
- else {
66
- throw new Error(`Unexpected argument: ${a}`);
67
- }
68
- }
69
- if (!filePath) {
70
- throw new Error('upload: missing <path.json> argument');
71
- }
72
- return { filePath, message, branch, skipGit, updateConfig };
73
- }
74
- static buildCommitMessage(userMessage, fileId) {
75
- const lines = userMessage.split(/\r?\n/);
76
- lines[0] = `${lines[0]} [fileId: ${fileId}]`;
77
- return lines.join('\n');
78
- }
79
- prompt(question) {
80
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
81
- return new Promise((resolve) => {
82
- rl.question(question, (answer) => {
83
- rl.close();
84
- resolve(answer.trim());
85
- });
86
- });
87
- }
88
- promptHidden(question) {
89
- return new Promise((resolve) => {
90
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
91
- const rlAny = rl;
92
- rlAny._writeToOutput = (str) => {
93
- if (str.includes(question)) {
94
- rlAny.output.write(str);
95
- }
96
- };
97
- rl.question(question, (answer) => {
98
- rl.close();
99
- process.stdout.write('\n');
100
- resolve(answer);
101
- });
102
- });
103
- }
104
- runGit(args, cwd) {
105
- return (0, child_process_1.execFileSync)('git', args, { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
106
- }
107
- tryRunGit(args, cwd) {
108
- try {
109
- const stdout = this.runGit(args, cwd);
110
- return { ok: true, stdout, stderr: '' };
111
- }
112
- catch (err) {
113
- return {
114
- ok: false,
115
- stdout: err && err.stdout ? err.stdout.toString() : '',
116
- stderr: err && err.stderr ? err.stderr.toString() : (err && err.message) || '',
117
- };
118
- }
119
- }
120
- async commitToGit(absPath, fileId, options) {
121
- const repoDir = path.dirname(absPath);
122
- const relPath = path.basename(absPath);
123
- const versionCheck = this.tryRunGit(['--version'], repoDir);
124
- if (!versionCheck.ok) {
125
- console.log('git command not available; skipping git commit.');
126
- return;
127
- }
128
- const insideRepo = this.tryRunGit(['rev-parse', '--is-inside-work-tree'], repoDir);
129
- if (!insideRepo.ok || insideRepo.stdout.trim() !== 'true') {
130
- console.log(`Not inside a git working tree (${repoDir}); skipping git commit.`);
131
- return;
132
- }
133
- const tracked = this.tryRunGit(['ls-files', '--error-unmatch', relPath], repoDir);
134
- if (!tracked.ok) {
135
- const answer = (await this.prompt(`File is not tracked by git: ${relPath}\nAdd it to git? (Y/n): `)).toLowerCase();
136
- if (answer === 'n' || answer === 'no') {
137
- console.log('Nothing was done in git.');
138
- return;
139
- }
140
- }
141
- if (options.branch) {
142
- const branchResult = this.tryRunGit(['checkout', '-b', options.branch], repoDir);
143
- if (!branchResult.ok) {
144
- throw new Error(`Failed to create branch "${options.branch}": ${branchResult.stderr.trim()}`);
145
- }
146
- console.log(`Created and switched to branch "${options.branch}"`);
147
- }
148
- let message = options.message;
149
- if (!message) {
150
- message = await this.prompt('Commit message: ');
151
- if (!message) {
152
- throw new Error('A commit message is required');
153
- }
154
- }
155
- const finalMessage = ConfigUploadCommand.buildCommitMessage(message, fileId);
156
- const addResult = this.tryRunGit(['add', '--', relPath], repoDir);
157
- if (!addResult.ok) {
158
- throw new Error(`git add failed: ${addResult.stderr.trim()}`);
159
- }
160
- const commitResult = this.tryRunGit(['commit', '-m', finalMessage, '--', relPath], repoDir);
161
- if (!commitResult.ok) {
162
- throw new Error(`git commit failed: ${commitResult.stderr.trim() || commitResult.stdout.trim()}`);
163
- }
164
- console.log(commitResult.stdout.trim());
165
- }
166
- async run(args) {
167
- const options = ConfigUploadCommand.parseArgs(args);
168
- const absPath = path.resolve(process.cwd(), options.filePath);
169
- if (!fs.existsSync(absPath)) {
170
- throw new Error(`File not found: ${absPath}`);
171
- }
172
- if (!absPath.endsWith('.json')) {
173
- throw new Error(`Expected a .json file, got: ${absPath}`);
174
- }
175
- const raw = fs.readFileSync(absPath, 'utf8');
176
- let config;
177
- try {
178
- config = JSON.parse(raw);
179
- }
180
- catch (err) {
181
- throw new Error(`File is not valid JSON: ${absPath}\n${err && err.message ? err.message : err}`);
182
- }
183
- const orgName = config && config.orgName;
184
- const appIdentifier = config && config.appIdentifier;
185
- if (!orgName) {
186
- throw new Error(`Config file is missing "orgName": ${absPath}`);
187
- }
188
- if (!appIdentifier) {
189
- throw new Error(`Config file is missing "appIdentifier": ${absPath}`);
190
- }
191
- let email = process.env.CONTRAIL_CLI_EMAIL;
192
- let password = process.env.CONTRAIL_CLI_PASSWORD;
193
- if (!email) {
194
- email = await this.prompt('Email: ');
195
- }
196
- if (!password) {
197
- password = await this.promptHidden('Password: ');
198
- }
199
- if (!email || !password) {
200
- throw new Error('Email and password are required');
201
- }
202
- await (0, sdk_1.login)({ orgSlug: orgName, email, password });
203
- console.log(`Logged in to org "${orgName}" as ${email}`);
204
- const apps = await new sdk_1.Entities().get({
205
- entityName: 'app',
206
- criteria: { identifier: appIdentifier },
207
- });
208
- if (!apps || apps.length !== 1) {
209
- throw new Error(`Expected exactly one app with identifier "${appIdentifier}" in org "${orgName}", found ${apps ? apps.length : 0}`);
210
- }
211
- const app = apps[0];
212
- const buffer = fs.readFileSync(absPath);
213
- const fileName = path.basename(absPath);
214
- const fileOwner = `app:${app.id}`;
215
- const uploadedFile = await new sdk_1.Files().createAndUploadFileFromBuffer(buffer, 'application/json', fileName, fileOwner);
216
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
217
- const responsePath = `${absPath}.uploaded-${timestamp}.json`;
218
- fs.writeFileSync(responsePath, JSON.stringify(uploadedFile, null, 2), 'utf8');
219
- console.log(`Wrote response to ${responsePath}`);
220
- console.log(`FILE ID: ${uploadedFile.id}`);
221
- if (!options.skipGit) {
222
- await this.commitToGit(absPath, uploadedFile.id, options);
223
- }
224
- if (options.updateConfig) {
225
- await this.setConfigFileOnAppOrg(app.id, appIdentifier, orgName, uploadedFile.id);
226
- }
227
- }
228
- async setConfigFileOnAppOrg(appId, appIdentifier, orgName, fileId) {
229
- const appOrgs = await new sdk_1.Entities().get({
230
- entityName: 'app-org',
231
- criteria: { appId },
232
- });
233
- if (!appOrgs || appOrgs.length === 0) {
234
- throw new Error(`Failed to set the file onto the app config for "${appIdentifier}" because it is not installed in org "${orgName}". Install it via the admin console before using --update-config. You can paste the uploaded file's ID into the app config without needing to re-run this command.`);
235
- }
236
- if (appOrgs.length > 1) {
237
- throw new Error(`Failed to set the file onto the app config for "${appIdentifier}" in org "${orgName}" because ${appOrgs.length} installations were identified. Expected one. Please contact customer support for assistance.`);
238
- }
239
- const appOrg = appOrgs[0];
240
- const nextAppConfig = { ...(appOrg.appConfig || {}), configFile: fileId };
241
- await new sdk_1.Entities().update({
242
- entityName: 'app-org',
243
- id: appOrg.id,
244
- object: { appConfig: nextAppConfig },
245
- });
246
- console.log(`Successfully set "appConfig.configFile" for installed "${appIdentifier}" to new FILE ID: "${fileId}" on org "${orgName}"`);
247
- }
248
- }
249
- exports.ConfigUploadCommand = ConfigUploadCommand;
@@ -1 +0,0 @@
1
- export {};
@@ -1,130 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- jest.mock('@contrail/sdk', () => ({
4
- Entities: jest.fn(),
5
- Files: jest.fn(),
6
- login: jest.fn(),
7
- }));
8
- const config_upload_1 = require("./config-upload");
9
- describe('ConfigUploadCommand.parseArgs', () => {
10
- it('parses a bare file path', () => {
11
- const opts = config_upload_1.ConfigUploadCommand.parseArgs(['config.json']);
12
- expect(opts).toEqual({
13
- filePath: 'config.json',
14
- message: undefined,
15
- branch: undefined,
16
- skipGit: false,
17
- updateConfig: false,
18
- });
19
- });
20
- it('parses -m commit message option', () => {
21
- const opts = config_upload_1.ConfigUploadCommand.parseArgs(['config.json', '-m', 'my message']);
22
- expect(opts.message).toEqual('my message');
23
- expect(opts.skipGit).toBe(false);
24
- });
25
- it('parses -b branch option', () => {
26
- const opts = config_upload_1.ConfigUploadCommand.parseArgs(['config.json', '-b', 'feature/x']);
27
- expect(opts.branch).toEqual('feature/x');
28
- });
29
- it('parses options before the file path', () => {
30
- const opts = config_upload_1.ConfigUploadCommand.parseArgs(['-m', 'msg', '-b', 'br', 'config.json']);
31
- expect(opts).toEqual({
32
- filePath: 'config.json',
33
- message: 'msg',
34
- branch: 'br',
35
- skipGit: false,
36
- updateConfig: false,
37
- });
38
- });
39
- it('parses --skip-git flag', () => {
40
- const opts = config_upload_1.ConfigUploadCommand.parseArgs(['config.json', '--skip-git']);
41
- expect(opts.skipGit).toBe(true);
42
- });
43
- it('accepts the legacy --skipGit alias', () => {
44
- const opts = config_upload_1.ConfigUploadCommand.parseArgs(['config.json', '--skipGit']);
45
- expect(opts.skipGit).toBe(true);
46
- });
47
- it('parses --update-config flag', () => {
48
- const opts = config_upload_1.ConfigUploadCommand.parseArgs(['config.json', '--update-config']);
49
- expect(opts.updateConfig).toBe(true);
50
- });
51
- it('parses all options together', () => {
52
- const opts = config_upload_1.ConfigUploadCommand.parseArgs(['config.json', '-m', 'msg', '-b', 'br', '--skip-git', '--update-config']);
53
- expect(opts).toEqual({
54
- filePath: 'config.json',
55
- message: 'msg',
56
- branch: 'br',
57
- skipGit: true,
58
- updateConfig: true,
59
- });
60
- });
61
- it('throws when -m is missing its value', () => {
62
- expect(() => config_upload_1.ConfigUploadCommand.parseArgs(['config.json', '-m'])).toThrow(/-m requires a commit message/);
63
- });
64
- it('throws when -b is missing its value', () => {
65
- expect(() => config_upload_1.ConfigUploadCommand.parseArgs(['config.json', '-b'])).toThrow(/-b requires a branch name/);
66
- });
67
- it('throws on unknown option', () => {
68
- expect(() => config_upload_1.ConfigUploadCommand.parseArgs(['config.json', '--bogus'])).toThrow(/Unknown option: --bogus/);
69
- });
70
- it('throws when an extra positional argument is supplied', () => {
71
- expect(() => config_upload_1.ConfigUploadCommand.parseArgs(['config.json', 'extra.json'])).toThrow(/Unexpected argument: extra\.json/);
72
- });
73
- it('throws when no file path is provided', () => {
74
- expect(() => config_upload_1.ConfigUploadCommand.parseArgs([])).toThrow(/missing <path\.json>/);
75
- });
76
- it('throws when only options are provided', () => {
77
- expect(() => config_upload_1.ConfigUploadCommand.parseArgs(['--skip-git'])).toThrow(/missing <path\.json>/);
78
- });
79
- });
80
- describe('ConfigUploadCommand.buildCommitMessage', () => {
81
- it('appends fileId to the first line of a single-line message', () => {
82
- expect(config_upload_1.ConfigUploadCommand.buildCommitMessage('initial commit', 'abc123')).toEqual('initial commit [fileId: abc123]');
83
- });
84
- it('only appends fileId to the first line of a multi-line message', () => {
85
- const result = config_upload_1.ConfigUploadCommand.buildCommitMessage('header line\nbody line 1\nbody line 2', 'xyz');
86
- expect(result).toEqual('header line [fileId: xyz]\nbody line 1\nbody line 2');
87
- });
88
- it('handles CRLF line endings', () => {
89
- const result = config_upload_1.ConfigUploadCommand.buildCommitMessage('header\r\nbody', 'fid');
90
- expect(result).toEqual('header [fileId: fid]\nbody');
91
- });
92
- it('handles an empty message', () => {
93
- expect(config_upload_1.ConfigUploadCommand.buildCommitMessage('', 'fid')).toEqual(' [fileId: fid]');
94
- });
95
- });
96
- describe('ConfigUploadCommand.run', () => {
97
- const fs = require('fs');
98
- const os = require('os');
99
- const path = require('path');
100
- let tempDir;
101
- beforeEach(() => {
102
- tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'flexplm-config-upload-'));
103
- });
104
- afterEach(() => {
105
- fs.rmSync(tempDir, { recursive: true, force: true });
106
- });
107
- it('throws when the config file is missing orgName', async () => {
108
- const filePath = path.join(tempDir, 'bad.json');
109
- fs.writeFileSync(filePath, JSON.stringify({ appIdentifier: '@vibeiq/flexplm-connector' }), 'utf8');
110
- await expect(new config_upload_1.ConfigUploadCommand().run([filePath, '--skip-git'])).rejects.toThrow(/missing "orgName"/);
111
- });
112
- it('throws when the config file is missing appIdentifier', async () => {
113
- const filePath = path.join(tempDir, 'bad.json');
114
- fs.writeFileSync(filePath, JSON.stringify({ orgName: 'acme' }), 'utf8');
115
- await expect(new config_upload_1.ConfigUploadCommand().run([filePath, '--skip-git'])).rejects.toThrow(/missing "appIdentifier"/);
116
- });
117
- it('throws when the file is not valid JSON', async () => {
118
- const filePath = path.join(tempDir, 'bad.json');
119
- fs.writeFileSync(filePath, '{not json', 'utf8');
120
- await expect(new config_upload_1.ConfigUploadCommand().run([filePath, '--skip-git'])).rejects.toThrow(/not valid JSON/);
121
- });
122
- it('throws when the file does not exist', async () => {
123
- await expect(new config_upload_1.ConfigUploadCommand().run([path.join(tempDir, 'nope.json'), '--skip-git'])).rejects.toThrow(/File not found/);
124
- });
125
- it('throws when the file is not a .json file', async () => {
126
- const filePath = path.join(tempDir, 'config.txt');
127
- fs.writeFileSync(filePath, '{}', 'utf8');
128
- await expect(new config_upload_1.ConfigUploadCommand().run([filePath, '--skip-git'])).rejects.toThrow(/Expected a \.json file/);
129
- });
130
- });
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env node
2
- export declare class ConfigCli {
3
- main(): Promise<void>;
4
- }
5
- export declare function main(): Promise<void>;
@@ -1,61 +0,0 @@
1
- #!/usr/bin/env node
2
- "use strict";
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.main = exports.ConfigCli = void 0;
5
- const config_create_1 = require("./commands/config-create");
6
- const config_upload_1 = require("./commands/config-upload");
7
- const USAGE = `Usage: flexplm-config <command> [args]
8
-
9
- Commands:
10
- create Scaffold a new connector config .json file in the current directory
11
- upload <path.json> [opts] Upload a connector config .json file to VibeIQ
12
-
13
- Upload options:
14
- -m <message> Git commit message (prompted if omitted)
15
- -b <branch> Create a new git branch before committing
16
- --skip-git Skip the post-upload git commit (default: commit)
17
- --update-config Patch the app-org appConfig.configFile with the uploaded file ID without needing to paste into the admin console
18
-
19
- Environment (upload):
20
- CONTRAIL_CLI_EMAIL VibeIQ user email
21
- CONTRAIL_CLI_PASSWORD VibeIQ user password
22
- `;
23
- class ConfigCli {
24
- async main() {
25
- const [, , command, ...rest] = process.argv;
26
- switch (command) {
27
- case 'create':
28
- await new config_create_1.ConfigCreateCommand().run();
29
- return;
30
- case 'upload':
31
- if (!rest[0]) {
32
- console.error('upload: missing <path.json> argument');
33
- console.error(USAGE);
34
- process.exit(1);
35
- }
36
- await new config_upload_1.ConfigUploadCommand().run(rest);
37
- return;
38
- case undefined:
39
- case '-h':
40
- case '--help':
41
- case 'help':
42
- console.log(USAGE);
43
- return;
44
- default:
45
- console.error(`Unknown command: ${command}`);
46
- console.error(USAGE);
47
- process.exit(1);
48
- }
49
- }
50
- }
51
- exports.ConfigCli = ConfigCli;
52
- function main() {
53
- return new ConfigCli().main();
54
- }
55
- exports.main = main;
56
- if (require.main === module) {
57
- main().catch((err) => {
58
- console.error(err && err.message ? err.message : err);
59
- process.exit(1);
60
- });
61
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,68 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const createRunMock = jest.fn().mockResolvedValue(undefined);
4
- const uploadRunMock = jest.fn().mockResolvedValue(undefined);
5
- jest.mock('./commands/config-create', () => ({
6
- ConfigCreateCommand: jest.fn().mockImplementation(() => ({ run: createRunMock })),
7
- }));
8
- jest.mock('./commands/config-upload', () => ({
9
- ConfigUploadCommand: jest.fn().mockImplementation(() => ({ run: uploadRunMock })),
10
- }));
11
- const config_index_1 = require("./config-index");
12
- describe('config cli main dispatcher', () => {
13
- let originalArgv;
14
- let logSpy;
15
- let errorSpy;
16
- let exitSpy;
17
- beforeEach(() => {
18
- originalArgv = process.argv;
19
- createRunMock.mockClear();
20
- uploadRunMock.mockClear();
21
- logSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
22
- errorSpy = jest.spyOn(console, 'error').mockImplementation(() => { });
23
- exitSpy = jest.spyOn(process, 'exit').mockImplementation(((code) => {
24
- throw new Error(`__EXIT__:${code}`);
25
- }));
26
- });
27
- afterEach(() => {
28
- process.argv = originalArgv;
29
- logSpy.mockRestore();
30
- errorSpy.mockRestore();
31
- exitSpy.mockRestore();
32
- });
33
- function setArgv(...args) {
34
- process.argv = ['node', 'cli', ...args];
35
- }
36
- it('dispatches the create command', async () => {
37
- setArgv('create');
38
- await (0, config_index_1.main)();
39
- expect(createRunMock).toHaveBeenCalledTimes(1);
40
- expect(uploadRunMock).not.toHaveBeenCalled();
41
- });
42
- it('dispatches the upload command and forwards remaining args', async () => {
43
- setArgv('upload', 'config.json', '-m', 'msg', '--skip-git');
44
- await (0, config_index_1.main)();
45
- expect(uploadRunMock).toHaveBeenCalledWith(['config.json', '-m', 'msg', '--skip-git']);
46
- });
47
- it('exits when upload is missing its argument', async () => {
48
- setArgv('upload');
49
- await expect((0, config_index_1.main)()).rejects.toThrow('__EXIT__:1');
50
- expect(uploadRunMock).not.toHaveBeenCalled();
51
- expect(errorSpy).toHaveBeenCalledWith(expect.stringMatching(/missing <path\.json>/));
52
- });
53
- it.each(['help', '-h', '--help'])('prints usage for %s', async (helpFlag) => {
54
- setArgv(helpFlag);
55
- await (0, config_index_1.main)();
56
- expect(logSpy).toHaveBeenCalledWith(expect.stringMatching(/Usage: flexplm-config/));
57
- });
58
- it('prints usage when no command is provided', async () => {
59
- setArgv();
60
- await (0, config_index_1.main)();
61
- expect(logSpy).toHaveBeenCalledWith(expect.stringMatching(/Usage: flexplm-config/));
62
- });
63
- it('exits on an unknown command', async () => {
64
- setArgv('bogus');
65
- await expect((0, config_index_1.main)()).rejects.toThrow('__EXIT__:1');
66
- expect(errorSpy).toHaveBeenCalledWith(expect.stringMatching(/Unknown command: bogus/));
67
- });
68
- });
@@ -1,30 +0,0 @@
1
- {
2
- "orgName": "<ORG_NAME>",
3
- "appIdentifier": "<APP_IDENTIFIER>",
4
-
5
- "_availableAttributes": {
6
- "_note": "Reference only — the connector never reads this key. Add any of the attributes below as real top-level keys if this org needs them, then delete this whole \"_availableAttributes\" block.",
7
- "apiHost": "FlexPLM API host base URL. Required — throws NEED_CONFIG_VALUES if missing",
8
- "userName": "FlexPLM user name used for Basic Auth. Required; rewritten to a () => string getter",
9
- "password": "FlexPLM password used for Basic Auth. Required; rewritten to a () => string getter",
10
- "urlContext": "Path prefix for FlexPLM URLs. Default: '/Windchill'",
11
- "itemPreDevelopmentLifecycleStages": "Item lifecycle stages during which items are not synced to FlexPLM. Default: ['concept']",
12
- "logLevel": "Possible values: error/warn/info/debug. Default: info",
13
- "identifierAtts": "Deprecated. Map of FlexPLM object class to identifier attribute name(s), e.g. { \"LCSProduct\": [\"itemNumber\"] }",
14
- "plmEnviornment": "Sent as the PLM_ENV header on every FlexPLM request. Only used by 1 customer. NOTE: this key is intentionally spelled \"plmEnviornment\" (matching the connector's actual config key) — do not \"fix\" the spelling to \"plmEnvironment\", it will silently stop working",
15
- "propertyMapping": "Deprecated. Reserved for custom property-mapping overrides",
16
- "complexConfig": "Object of additional attributes (see below) merged onto the top level of the config, then deleted; __proto__/constructor/prototype keys are stripped for safety. e.g. { \"complexConfig\": { \"csrfEndpoint\": \"...\" } }",
17
- "csrfEndpoint (in complexConfig)": "CSRF token endpoint path. Default: '/servlet/rest/security/csrf'",
18
- "dataConverter.useDisplayForEnumerationMatching (in complexConfig)": "Default: false",
19
- "dataConverter.verboseDebug (in complexConfig)": "Default: false",
20
- "flexplmConnect.staticHeaders (in complexConfig)": "Extra static headers added to every FlexPLM request",
21
- "LCSMaterial.processAsItem (in complexConfig)": "true routes LCSMaterial to item:material instead of custom-entity. Default: false",
22
- "max_thumbnail_size (in complexConfig)": "Max thumbnail size in bytes. Default: 5 MB",
23
- "payloadDefaultAsArray (in complexConfig)": "Whether outbound payload values default to arrays. Default: true",
24
- "search.<entityType>.useIdentityServiceForInboundData (in complexConfig)": "entityType is one of: item, color, custom-entity, project-item. Default: false",
25
- "sendMode.ASYNC_PUBLISH_SEASON (in complexConfig)": "Default: 'vibeiqfile'",
26
- "syncOptionSets (in complexConfig)": "Array of { flexInternalName, vibeSlug }",
27
- "useDistinctRestEndPointForImages (in complexConfig)": "Default: false; when true routes image fetch through /rfa/vibeiq/image instead of the raw URL",
28
- "vibeEventEndpoint (in complexConfig)": "Endpoint VibeIQ posts inbound events to. Default: '/rfa/vibeiq/vibeEvents'"
29
- }
30
- }