@factorialco/fcode-cli 3.5.0 → 3.6.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.
- package/README.md +1 -1
- package/dist/commands/http.d.ts +2 -1
- package/dist/commands/http.js +4 -2
- package/dist/commands/settings/pull.js +5 -0
- package/dist/commands/settings/push.d.ts +6 -0
- package/dist/commands/settings/push.js +21 -26
- package/dist/config/workspace.d.ts +6 -0
- package/dist/config/workspace.js +9 -1
- package/dist/core/errors.d.ts +14 -0
- package/dist/core/errors.js +35 -1
- package/dist/core/executors/javascript-execution-task.js +21 -8
- package/dist/core/types.d.ts +40 -11
- package/dist/core/types.js +13 -1
- package/dist/repositories/settings.d.ts +22 -2
- package/dist/repositories/settings.js +129 -11
- package/dist/runtime/libs/python/fcode/context.py +28 -8
- package/dist/services/fcode-graphql-client.d.ts +8 -3
- package/dist/services/fcode-graphql-client.js +98 -48
- package/dist/services/locale-resolver.d.ts +6 -2
- package/dist/services/locale-resolver.js +35 -8
- package/dist/services/webhook-auth.d.ts +4 -2
- package/dist/services/webhook-auth.js +11 -5
- package/dist/utils/cli-version.d.ts +7 -0
- package/dist/utils/cli-version.js +20 -0
- package/dist/utils/gitignore.d.ts +2 -1
- package/dist/utils/gitignore.js +5 -1
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ $ npm install -g @factorialco/fcode-cli
|
|
|
20
20
|
$ fcode COMMAND
|
|
21
21
|
running command...
|
|
22
22
|
$ fcode (--version)
|
|
23
|
-
@factorialco/fcode-cli/3.
|
|
23
|
+
@factorialco/fcode-cli/3.6.0 linux-x64 node-v22.23.3
|
|
24
24
|
$ fcode --help [COMMAND]
|
|
25
25
|
USAGE
|
|
26
26
|
$ fcode COMMAND
|
package/dist/commands/http.d.ts
CHANGED
|
@@ -14,7 +14,8 @@ export default class Http extends Command {
|
|
|
14
14
|
* Enforces the webhook's configured auth, simulating the cloud webhook endpoint: the effective
|
|
15
15
|
* configuration names a variable, whose value is looked up in the workspace variables and compared
|
|
16
16
|
* against the configured header. A missing or malformed header, an undefined variable, a mismatch,
|
|
17
|
-
* or a webhook inheriting a workspace configuration that
|
|
17
|
+
* or a webhook inheriting a workspace configuration that is cleared or neither set nor inherited, is
|
|
18
|
+
* rejected.
|
|
18
19
|
* Returns true when the request may proceed, false after writing a 403.
|
|
19
20
|
*/
|
|
20
21
|
private _checkWebhookAuth;
|
package/dist/commands/http.js
CHANGED
|
@@ -122,7 +122,8 @@ class Http extends core_1.Command {
|
|
|
122
122
|
* Enforces the webhook's configured auth, simulating the cloud webhook endpoint: the effective
|
|
123
123
|
* configuration names a variable, whose value is looked up in the workspace variables and compared
|
|
124
124
|
* against the configured header. A missing or malformed header, an undefined variable, a mismatch,
|
|
125
|
-
* or a webhook inheriting a workspace configuration that
|
|
125
|
+
* or a webhook inheriting a workspace configuration that is cleared or neither set nor inherited, is
|
|
126
|
+
* rejected.
|
|
126
127
|
* Returns true when the request may proceed, false after writing a 403.
|
|
127
128
|
*/
|
|
128
129
|
async _checkWebhookAuth(req, res, processRepository, settingsRepository, slug) {
|
|
@@ -137,9 +138,10 @@ class Http extends core_1.Command {
|
|
|
137
138
|
// Read per request, like the process metadata above, so editing settings.json while the server
|
|
138
139
|
// runs takes effect without a restart.
|
|
139
140
|
const teamWebhookAuth = (await settingsRepository.find()).webhookAuth;
|
|
141
|
+
const inheritedTeamWebhookAuth = settingsRepository.findInherited().webhookAuth;
|
|
140
142
|
let effectiveAuth;
|
|
141
143
|
try {
|
|
142
|
-
effectiveAuth = (0, webhook_auth_1.resolveEffectiveAuth)(webhook, teamWebhookAuth);
|
|
144
|
+
effectiveAuth = (0, webhook_auth_1.resolveEffectiveAuth)(webhook, teamWebhookAuth, inheritedTeamWebhookAuth);
|
|
143
145
|
}
|
|
144
146
|
catch (error) {
|
|
145
147
|
// Fails closed, and says why: otherwise this reads as a wrong token rather than a local
|
|
@@ -5,6 +5,7 @@ const api_client_command_1 = require("../../core/commands/api-client-command");
|
|
|
5
5
|
const settings_1 = require("../../repositories/settings");
|
|
6
6
|
const types_1 = require("../../core/types");
|
|
7
7
|
const cli_1 = require("../../utils/cli");
|
|
8
|
+
const gitignore_1 = require("../../utils/gitignore");
|
|
8
9
|
class SettingsPullCommand extends api_client_command_1.default {
|
|
9
10
|
constructor() {
|
|
10
11
|
super(...arguments);
|
|
@@ -32,6 +33,10 @@ class SettingsPullCommand extends api_client_command_1.default {
|
|
|
32
33
|
const settings = await this._settingsRepository.fromRaw(raw);
|
|
33
34
|
this._settingsRepository.applyCloudVersioning(settings, versions, aliases);
|
|
34
35
|
this._settingsRepository.save(settings);
|
|
36
|
+
this._settingsRepository.saveInherited(await this._settingsRepository.inheritedFromRaw(raw));
|
|
37
|
+
// A read-only copy of the parents' values: keep it out of git even when this command runs on
|
|
38
|
+
// its own rather than inside `fcode pull`.
|
|
39
|
+
await (0, gitignore_1.syncInheritedGitignore)();
|
|
35
40
|
await this.workspaceConfig.setSettingsStoredHash(settings.contentHash);
|
|
36
41
|
}
|
|
37
42
|
}
|
|
@@ -8,6 +8,12 @@ export default class SettingsPushCommand extends ApiClientCommand {
|
|
|
8
8
|
};
|
|
9
9
|
_settingsRepository: SettingsRepository;
|
|
10
10
|
run(): Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* A settings.json some CLI synced (there is a stored hash) without marking it inheritance-aware was
|
|
13
|
+
* written by a CLI older than settings inheritance, with every effective value in it. Only a
|
|
14
|
+
* workspace with parents is affected: without any, its effective settings are its own.
|
|
15
|
+
*/
|
|
16
|
+
private pulledByAPreInheritanceCli;
|
|
11
17
|
/** Makes the cloud's versions/aliases match settings.json; returns failed manifest entries. */
|
|
12
18
|
private syncVersioning;
|
|
13
19
|
}
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const color_1 = require("@oclif/color");
|
|
4
4
|
const api_client_command_1 = require("../../core/commands/api-client-command");
|
|
5
|
+
const errors_1 = require("../../core/errors");
|
|
5
6
|
const settings_1 = require("../../repositories/settings");
|
|
6
7
|
const types_1 = require("../../core/types");
|
|
7
8
|
const team_versioning_1 = require("../../services/team-versioning");
|
|
8
9
|
const cli_1 = require("../../utils/cli");
|
|
10
|
+
const gitignore_1 = require("../../utils/gitignore");
|
|
9
11
|
class SettingsPushCommand extends api_client_command_1.default {
|
|
10
12
|
constructor() {
|
|
11
13
|
super(...arguments);
|
|
@@ -23,30 +25,19 @@ class SettingsPushCommand extends api_client_command_1.default {
|
|
|
23
25
|
cli_1.default.log('Workspace settings already up to date');
|
|
24
26
|
return;
|
|
25
27
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
update.zoneId = settings.zoneId;
|
|
28
|
+
if (await this.pulledByAPreInheritanceCli(settings, storedHash)) {
|
|
29
|
+
throw new errors_1.PreInheritanceSettingsFile();
|
|
29
30
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
update.webhookAuth = settings.webhookAuth
|
|
37
|
-
? { headerName: settings.webhookAuth.headerName ?? null, variableKey: settings.webhookAuth.variableKey }
|
|
38
|
-
: { variableKey: null };
|
|
39
|
-
// Sent unconditionally for the same reason as webhookAuth: settings.json is the source of truth,
|
|
40
|
-
// so removing primaryLocale from it must clear the cloud setting. Empty string is the clear.
|
|
41
|
-
update.primaryLocale = settings.primaryLocale ?? '';
|
|
42
|
-
await this._fcodeGraphQLClient.pushTeam(update);
|
|
31
|
+
const pushed = await this._fcodeGraphQLClient.pushTeam(await this._settingsRepository.toTeamUpdate(settings));
|
|
32
|
+
// What the workspace now inherits follows from what was just pushed.
|
|
33
|
+
this._settingsRepository.saveInherited(await this._settingsRepository.inheritedFromRaw(pushed));
|
|
34
|
+
// A read-only copy of the parents' values: keep it out of git even when this command runs on
|
|
35
|
+
// its own rather than inside `fcode pull`.
|
|
36
|
+
await (0, gitignore_1.syncInheritedGitignore)();
|
|
43
37
|
const failedEntities = await this.syncVersioning(settings, force);
|
|
44
38
|
// Re-read the cloud state so server-assigned fields (createdAt) and declined deletions
|
|
45
39
|
// land back in settings.json, then hash exactly what was written.
|
|
46
|
-
const [versions, aliases] = await Promise.all([
|
|
47
|
-
this._fcodeGraphQLClient.allTeamVersions(),
|
|
48
|
-
this._fcodeGraphQLClient.allTeamVersionAliases(),
|
|
49
|
-
]);
|
|
40
|
+
const [versions, aliases] = await Promise.all([this._fcodeGraphQLClient.allTeamVersions(), this._fcodeGraphQLClient.allTeamVersionAliases()]);
|
|
50
41
|
this._settingsRepository.applyCloudVersioning(settings, versions, aliases);
|
|
51
42
|
this._settingsRepository.save(settings);
|
|
52
43
|
await this.workspaceConfig.setSettingsStoredHash(settings.contentHash);
|
|
@@ -57,12 +48,17 @@ class SettingsPushCommand extends api_client_command_1.default {
|
|
|
57
48
|
this.error(`workspace versions pushed with ${failedEntities} failed entities`, { exit: 1 });
|
|
58
49
|
}
|
|
59
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* A settings.json some CLI synced (there is a stored hash) without marking it inheritance-aware was
|
|
53
|
+
* written by a CLI older than settings inheritance, with every effective value in it. Only a
|
|
54
|
+
* workspace with parents is affected: without any, its effective settings are its own.
|
|
55
|
+
*/
|
|
56
|
+
async pulledByAPreInheritanceCli(settings, storedHash) {
|
|
57
|
+
return storedHash !== undefined && settings.parentTeams.length > 0 && !(await this.workspaceConfig.isSettingsInheritanceAware());
|
|
58
|
+
}
|
|
60
59
|
/** Makes the cloud's versions/aliases match settings.json; returns failed manifest entries. */
|
|
61
60
|
async syncVersioning(settings, force) {
|
|
62
|
-
const [cloudVersions, cloudAliases] = await Promise.all([
|
|
63
|
-
this._fcodeGraphQLClient.allTeamVersions(),
|
|
64
|
-
this._fcodeGraphQLClient.allTeamVersionAliases(),
|
|
65
|
-
]);
|
|
61
|
+
const [cloudVersions, cloudAliases] = await Promise.all([this._fcodeGraphQLClient.allTeamVersions(), this._fcodeGraphQLClient.allTeamVersionAliases()]);
|
|
66
62
|
const plan = (0, team_versioning_1.planTeamVersioningSync)(settings, cloudVersions, cloudAliases);
|
|
67
63
|
if ((0, team_versioning_1.teamVersioningSyncPlanIsEmpty)(plan)) {
|
|
68
64
|
return 0;
|
|
@@ -96,8 +92,7 @@ class SettingsPushCommand extends api_client_command_1.default {
|
|
|
96
92
|
return failedEntities;
|
|
97
93
|
}
|
|
98
94
|
}
|
|
99
|
-
SettingsPushCommand.description = 'Update cloud workspace settings (timezone, error handler, inheritance, webhook auth) and sync ' +
|
|
100
|
-
'workspace versions/aliases from settings.json';
|
|
95
|
+
SettingsPushCommand.description = 'Update cloud workspace settings (timezone, error handler, inheritance, webhook auth) and sync ' + 'workspace versions/aliases from settings.json';
|
|
101
96
|
SettingsPushCommand.examples = ['$ fcode settings:push'];
|
|
102
97
|
SettingsPushCommand.flags = types_1.ForceFlag;
|
|
103
98
|
exports.default = SettingsPushCommand;
|
|
@@ -21,6 +21,12 @@ declare class WorkspaceConfig extends Config {
|
|
|
21
21
|
getStoredHash(resource: Resource): Promise<string>;
|
|
22
22
|
getSettingsStoredHash(): Promise<string | undefined>;
|
|
23
23
|
setSettingsStoredHash(contentHash: string): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Whether settings.json was last pulled or pushed by a CLI that knows settings inherit. One that
|
|
26
|
+
* did not wrote the values the workspace inherits as if they were its own, and records the hash
|
|
27
|
+
* without this mark.
|
|
28
|
+
*/
|
|
29
|
+
isSettingsInheritanceAware(): Promise<boolean>;
|
|
24
30
|
add(resourceType: string, resourceMetadata: ResourceMetadata): Promise<void>;
|
|
25
31
|
remove(resourceType: string, slug: string): Promise<void>;
|
|
26
32
|
}
|
package/dist/config/workspace.js
CHANGED
|
@@ -139,7 +139,15 @@ class WorkspaceConfig extends index_1.default {
|
|
|
139
139
|
}
|
|
140
140
|
async setSettingsStoredHash(contentHash) {
|
|
141
141
|
const team = await this.getActiveTeam();
|
|
142
|
-
await this.setTeam({ ...team, team: { contentHash } });
|
|
142
|
+
await this.setTeam({ ...team, team: { contentHash, inheritanceAware: true } });
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Whether settings.json was last pulled or pushed by a CLI that knows settings inherit. One that
|
|
146
|
+
* did not wrote the values the workspace inherits as if they were its own, and records the hash
|
|
147
|
+
* without this mark.
|
|
148
|
+
*/
|
|
149
|
+
async isSettingsInheritanceAware() {
|
|
150
|
+
return (await this.getActiveTeam()).team?.inheritanceAware === true;
|
|
143
151
|
}
|
|
144
152
|
async add(resourceType, resourceMetadata) {
|
|
145
153
|
const team = await this.getActiveTeam();
|
package/dist/core/errors.d.ts
CHANGED
|
@@ -54,6 +54,13 @@ export declare class TeamAccessDenied extends CLIError {
|
|
|
54
54
|
export declare class NotFcodeWorkspace extends CLIError {
|
|
55
55
|
constructor();
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* settings.json was last synced by a CLI older than settings inheritance, which wrote the settings
|
|
59
|
+
* the workspace inherits as if they were its own: pushing it would stop the workspace inheriting them.
|
|
60
|
+
*/
|
|
61
|
+
export declare class PreInheritanceSettingsFile extends CLIError {
|
|
62
|
+
constructor();
|
|
63
|
+
}
|
|
57
64
|
export declare class DependenciesNotInstalled extends CLIError {
|
|
58
65
|
constructor(programmingLanguage: ProgrammingLanguage);
|
|
59
66
|
}
|
|
@@ -63,3 +70,10 @@ export declare class ProcessDependenciesNotInstalled extends CLIError {
|
|
|
63
70
|
export declare class ErrorExecutingProcess extends CLIError {
|
|
64
71
|
constructor(message: string);
|
|
65
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* The platform answered without the team's inheritable settings: it predates settings inheritance,
|
|
75
|
+
* and reading its settings would take every one of them for inherited.
|
|
76
|
+
*/
|
|
77
|
+
export declare class PlatformPredatesSettingsInheritance extends CLIError {
|
|
78
|
+
constructor();
|
|
79
|
+
}
|
package/dist/core/errors.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ErrorExecutingProcess = exports.ProcessDependenciesNotInstalled = exports.DependenciesNotInstalled = exports.NotFcodeWorkspace = exports.TeamAccessDenied = exports.NotAuthenticated = exports.CloudProgrammingLanguageManifestNotFound = exports.LocalProgrammingLanguageManifestNotFound = exports.CloudLocaleNotFound = exports.LocalLocaleNotFound = exports.CloudVariableNotFound = exports.LocalVariableNotFound = exports.CloudScriptLibraryNotFound = exports.LocalScriptLibraryNotFound = exports.CloudProcessNotFound = exports.LocalProcessNotFound = exports.ResourceNotFound = exports.CLIError = void 0;
|
|
3
|
+
exports.PlatformPredatesSettingsInheritance = exports.ErrorExecutingProcess = exports.ProcessDependenciesNotInstalled = exports.DependenciesNotInstalled = exports.PreInheritanceSettingsFile = exports.NotFcodeWorkspace = exports.TeamAccessDenied = exports.NotAuthenticated = exports.CloudProgrammingLanguageManifestNotFound = exports.LocalProgrammingLanguageManifestNotFound = exports.CloudLocaleNotFound = exports.LocalLocaleNotFound = exports.CloudVariableNotFound = exports.LocalVariableNotFound = exports.CloudScriptLibraryNotFound = exports.LocalScriptLibraryNotFound = exports.CloudProcessNotFound = exports.LocalProcessNotFound = exports.ResourceNotFound = exports.CLIError = void 0;
|
|
4
4
|
exports.teamAccessDeniedMessage = teamAccessDeniedMessage;
|
|
5
5
|
const global_1 = require("../config/global");
|
|
6
6
|
class CLIError extends Error {
|
|
@@ -145,6 +145,25 @@ class NotFcodeWorkspace extends CLIError {
|
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
exports.NotFcodeWorkspace = NotFcodeWorkspace;
|
|
148
|
+
/**
|
|
149
|
+
* settings.json was last synced by a CLI older than settings inheritance, which wrote the settings
|
|
150
|
+
* the workspace inherits as if they were its own: pushing it would stop the workspace inheriting them.
|
|
151
|
+
*/
|
|
152
|
+
class PreInheritanceSettingsFile extends CLIError {
|
|
153
|
+
constructor() {
|
|
154
|
+
super('settings.json was last synced by an fcode CLI that predates settings inheritance: it holds the settings this ' +
|
|
155
|
+
'workspace inherits from its parent workspaces as if they were its own, and pushing it would stop the ' +
|
|
156
|
+
'workspace inheriting them.', {
|
|
157
|
+
code: 'ERR_PRE_INHERITANCE_SETTINGS_FILE',
|
|
158
|
+
exit: 1,
|
|
159
|
+
suggestions: [
|
|
160
|
+
'fcode settings:pull, then push again',
|
|
161
|
+
'fcode settings:pull --force if settings.json has local changes, then reapply them and push again',
|
|
162
|
+
],
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
exports.PreInheritanceSettingsFile = PreInheritanceSettingsFile;
|
|
148
167
|
class DependenciesNotInstalled extends CLIError {
|
|
149
168
|
constructor(programmingLanguage) {
|
|
150
169
|
super(`Dependencies not installed.`, {
|
|
@@ -175,3 +194,18 @@ class ErrorExecutingProcess extends CLIError {
|
|
|
175
194
|
}
|
|
176
195
|
}
|
|
177
196
|
exports.ErrorExecutingProcess = ErrorExecutingProcess;
|
|
197
|
+
/**
|
|
198
|
+
* The platform answered without the team's inheritable settings: it predates settings inheritance,
|
|
199
|
+
* and reading its settings would take every one of them for inherited.
|
|
200
|
+
*/
|
|
201
|
+
class PlatformPredatesSettingsInheritance extends CLIError {
|
|
202
|
+
constructor() {
|
|
203
|
+
super('This Factorial Code platform predates settings inheritance, which this fcode CLI requires to read and ' +
|
|
204
|
+
'push workspace settings.', {
|
|
205
|
+
code: 'ERR_PLATFORM_PREDATES_SETTINGS_INHERITANCE',
|
|
206
|
+
exit: 1,
|
|
207
|
+
suggestions: ['Wait for the platform to be updated, or use an fcode CLI older than 3.6.0 until then'],
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
exports.PlatformPredatesSettingsInheritance = PlatformPredatesSettingsInheritance;
|
|
@@ -606,25 +606,38 @@ const main = typeof _hooksModule['${fn}'] === 'function'
|
|
|
606
606
|
i18n: Object.assign((key, args, options) => {
|
|
607
607
|
const translations = ${JSON.stringify(metadata.i18n.translations, null, 2)};
|
|
608
608
|
const byLocale = ${JSON.stringify(metadata.i18n.byLocale, null, 2)};
|
|
609
|
+
const primaryLocale = ${JSON.stringify(metadata.i18n.primaryLocale ?? null)};
|
|
609
610
|
const requested = options && typeof options === 'object' && options.locale !== undefined && options.locale !== null
|
|
610
611
|
? String(options.locale)
|
|
611
612
|
: undefined;
|
|
612
613
|
// An identifier no locale matches is shortened one segment at a time ('en-gb' reads
|
|
613
|
-
// 'en'), by name first and ignoring case only as a last resort
|
|
614
|
-
//
|
|
614
|
+
// 'en'), by name first and ignoring case only as a last resort, and a language that
|
|
615
|
+
// still matches nothing is broadened to a regional locale of it ('es' reads 'es-ES',
|
|
616
|
+
// the primary one if it is among them, else the alphabetically first) — the same chain
|
|
617
|
+
// the cloud resolves, so a local run answers the same identifiers the same way.
|
|
618
|
+
const names = Object.keys(byLocale);
|
|
619
|
+
const matching = (candidate) => names.includes(candidate)
|
|
620
|
+
? candidate
|
|
621
|
+
: names.filter((name) => name.toLowerCase() === candidate.toLowerCase()).sort()[0];
|
|
615
622
|
const localeMaps = [];
|
|
616
|
-
|
|
617
|
-
const names = Object.keys(byLocale);
|
|
618
|
-
const lowered = candidate.toLowerCase();
|
|
619
|
-
const match = names.includes(candidate)
|
|
620
|
-
? candidate
|
|
621
|
-
: names.filter((name) => name.toLowerCase() === lowered).sort()[0];
|
|
623
|
+
const add = (match) => {
|
|
622
624
|
if (match !== undefined && !localeMaps.includes(byLocale[match])) {
|
|
623
625
|
localeMaps.push(byLocale[match]);
|
|
624
626
|
}
|
|
627
|
+
};
|
|
628
|
+
let language;
|
|
629
|
+
for (let candidate = requested; candidate; ) {
|
|
630
|
+
add(matching(candidate));
|
|
631
|
+
language = candidate;
|
|
625
632
|
const lastSeparator = Math.max(candidate.lastIndexOf('-'), candidate.lastIndexOf('_'));
|
|
626
633
|
candidate = lastSeparator > 0 ? candidate.slice(0, lastSeparator) : undefined;
|
|
627
634
|
}
|
|
635
|
+
if (language !== undefined && !/[-_]/.test(language) && matching(language) === undefined) {
|
|
636
|
+
const sameLanguage = names
|
|
637
|
+
.filter((name) => name.split(/[-_]/)[0].toLowerCase() === language.toLowerCase())
|
|
638
|
+
.sort();
|
|
639
|
+
add(sameLanguage.includes(primaryLocale) ? primaryLocale : sameLanguage[0]);
|
|
640
|
+
}
|
|
628
641
|
let template;
|
|
629
642
|
for (const localeMap of localeMaps) {
|
|
630
643
|
template = Object.hasOwn(localeMap, key) ? localeMap[key] : undefined;
|
package/dist/core/types.d.ts
CHANGED
|
@@ -49,6 +49,7 @@ export interface TeamMetadata {
|
|
|
49
49
|
};
|
|
50
50
|
team?: {
|
|
51
51
|
contentHash?: string;
|
|
52
|
+
inheritanceAware?: boolean;
|
|
52
53
|
};
|
|
53
54
|
}
|
|
54
55
|
export interface RemoteMetadata {
|
|
@@ -397,24 +398,34 @@ export interface ParentTeamRef {
|
|
|
397
398
|
slug: string;
|
|
398
399
|
version?: string;
|
|
399
400
|
}
|
|
400
|
-
/**
|
|
401
|
+
/**
|
|
402
|
+
* The workspace's settings.json: what `fcode settings:pull|push` syncs against the cloud team. It
|
|
403
|
+
* holds the team's own values only: an absent setting inherits, and null (error handler and webhook
|
|
404
|
+
* auth only) clears it, a parent's value included.
|
|
405
|
+
*/
|
|
401
406
|
export declare class WorkspaceSettings extends Resource {
|
|
402
407
|
id: string | undefined;
|
|
403
408
|
slug: string;
|
|
404
409
|
zoneId?: string;
|
|
405
|
-
errorHandlerConfig?: ErrorHandlerConfig;
|
|
410
|
+
errorHandlerConfig?: ErrorHandlerConfig | null;
|
|
406
411
|
parentTeams: ParentTeamRef[];
|
|
407
|
-
webhookAuth?: WebhookAuth;
|
|
412
|
+
webhookAuth?: WebhookAuth | null;
|
|
408
413
|
primaryLocale?: string;
|
|
409
414
|
versions?: TeamVersionFileEntry[];
|
|
410
415
|
aliases?: TeamAliasFileEntry[];
|
|
411
|
-
constructor(slug: string, parentTeams: ParentTeamRef[], zoneId?: string, errorHandlerConfig?: ErrorHandlerConfig, webhookAuth?: WebhookAuth, primaryLocale?: string);
|
|
416
|
+
constructor(slug: string, parentTeams: ParentTeamRef[], zoneId?: string, errorHandlerConfig?: ErrorHandlerConfig | null, webhookAuth?: WebhookAuth | null, primaryLocale?: string);
|
|
412
417
|
get contentHash(): string;
|
|
413
418
|
}
|
|
414
419
|
export interface RawErrorHandlerConfig {
|
|
415
420
|
processId: string;
|
|
416
421
|
tag?: string | null;
|
|
417
422
|
}
|
|
423
|
+
export type InheritableSetting = 'ERROR_HANDLER' | 'PARAMS_SCHEMA_VALIDATION' | 'PRIMARY_LOCALE' | 'WEBHOOK_AUTH' | 'ZONE_ID';
|
|
424
|
+
export type SettingMode = 'INHERIT' | 'NONE' | 'OWN';
|
|
425
|
+
export interface SettingOrigin {
|
|
426
|
+
mode: SettingMode;
|
|
427
|
+
from?: string | null;
|
|
428
|
+
}
|
|
418
429
|
export interface RawTeamSettings {
|
|
419
430
|
slug: string;
|
|
420
431
|
zoneId?: string;
|
|
@@ -422,16 +433,34 @@ export interface RawTeamSettings {
|
|
|
422
433
|
parentTeams: ParentTeamRef[];
|
|
423
434
|
webhookAuth?: WebhookAuth | null;
|
|
424
435
|
primaryLocale?: string | null;
|
|
436
|
+
origins?: Record<InheritableSetting, SettingOrigin>;
|
|
425
437
|
}
|
|
426
|
-
export interface
|
|
438
|
+
export interface InheritedWorkspaceSettings {
|
|
427
439
|
zoneId?: string;
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
webhookAuth?: {
|
|
431
|
-
headerName?: string | null;
|
|
432
|
-
variableKey?: string | null;
|
|
433
|
-
} | null;
|
|
440
|
+
errorHandlerConfig?: ErrorHandlerConfig;
|
|
441
|
+
webhookAuth?: WebhookAuth;
|
|
434
442
|
primaryLocale?: string;
|
|
443
|
+
inheritedFrom: Record<string, string>;
|
|
444
|
+
}
|
|
445
|
+
export type SettingInput<T> = {
|
|
446
|
+
mode: 'INHERIT';
|
|
447
|
+
} | {
|
|
448
|
+
mode: 'NONE';
|
|
449
|
+
} | {
|
|
450
|
+
mode: 'OWN';
|
|
451
|
+
value: T;
|
|
452
|
+
};
|
|
453
|
+
export interface TeamUpdateInput {
|
|
454
|
+
parentTeams?: ParentTeamRef[];
|
|
455
|
+
inheritableSettings?: {
|
|
456
|
+
zoneId?: SettingInput<string>;
|
|
457
|
+
errorHandlerConfig?: SettingInput<RawErrorHandlerConfig>;
|
|
458
|
+
webhookAuth?: SettingInput<{
|
|
459
|
+
headerName?: string | null;
|
|
460
|
+
variableKey: string;
|
|
461
|
+
}>;
|
|
462
|
+
primaryLocale?: SettingInput<string>;
|
|
463
|
+
};
|
|
435
464
|
}
|
|
436
465
|
export type ResourceMetadata = {
|
|
437
466
|
[key: string]: any;
|
package/dist/core/types.js
CHANGED
|
@@ -261,7 +261,11 @@ class ProgrammingLanguageManifest extends Resource {
|
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
263
|
exports.ProgrammingLanguageManifest = ProgrammingLanguageManifest;
|
|
264
|
-
/**
|
|
264
|
+
/**
|
|
265
|
+
* The workspace's settings.json: what `fcode settings:pull|push` syncs against the cloud team. It
|
|
266
|
+
* holds the team's own values only: an absent setting inherits, and null (error handler and webhook
|
|
267
|
+
* auth only) clears it, a parent's value included.
|
|
268
|
+
*/
|
|
265
269
|
class WorkspaceSettings extends Resource {
|
|
266
270
|
constructor(slug, parentTeams, zoneId, errorHandlerConfig, webhookAuth, primaryLocale) {
|
|
267
271
|
super();
|
|
@@ -293,6 +297,14 @@ class WorkspaceSettings extends Resource {
|
|
|
293
297
|
if (this.primaryLocale) {
|
|
294
298
|
payload.primaryLocale = this.primaryLocale;
|
|
295
299
|
}
|
|
300
|
+
// Cleared settings hash apart from inherited ones; inserted only when any is cleared.
|
|
301
|
+
const cleared = [
|
|
302
|
+
...(this.errorHandlerConfig === null ? ['ERROR_HANDLER'] : []),
|
|
303
|
+
...(this.webhookAuth === null ? ['WEBHOOK_AUTH'] : []),
|
|
304
|
+
];
|
|
305
|
+
if (cleared.length > 0) {
|
|
306
|
+
payload.cleared = cleared;
|
|
307
|
+
}
|
|
296
308
|
// Versions hash only their tags and aliases their name->tag pairs: createdAt is
|
|
297
309
|
// server-assigned and a comment is immutable once published (there is no update mutation),
|
|
298
310
|
// so neither can represent a pushable local change. Inserted only when non-empty, again to
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { RawTeamSettings, TeamVersion, TeamVersionAlias, WorkspaceSettings } from '../core/types';
|
|
1
|
+
import { InheritedWorkspaceSettings, RawTeamSettings, TeamUpdateInput, TeamVersion, TeamVersionAlias, WorkspaceSettings } from '../core/types';
|
|
2
2
|
import WorkspaceConfig from '../config/workspace';
|
|
3
3
|
export declare const SETTINGS_FILENAME = "settings.json";
|
|
4
|
+
export declare const INHERITED_SETTINGS_FILENAME = "settings.inherited.json";
|
|
4
5
|
/**
|
|
5
6
|
* Workspaces cloned before the file was renamed carry team.json. Renaming it on first access keeps
|
|
6
7
|
* the stored sync hash valid (it is computed over the content, not the name), so the workspace does
|
|
@@ -22,8 +23,23 @@ export default class SettingsRepository {
|
|
|
22
23
|
exists(): boolean;
|
|
23
24
|
find(): Promise<WorkspaceSettings>;
|
|
24
25
|
save(settings: WorkspaceSettings): void;
|
|
25
|
-
/**
|
|
26
|
+
/** The settings a local run inherits; empty when the workspace inherits none. */
|
|
27
|
+
findInherited(): InheritedWorkspaceSettings;
|
|
28
|
+
/** Writes settings.inherited.json, or removes it when the workspace inherits no setting. */
|
|
29
|
+
saveInherited(inherited: InheritedWorkspaceSettings | undefined): void;
|
|
30
|
+
/**
|
|
31
|
+
* Builds the settings.json view of the cloud's raw payload: only the team's own values, null for a
|
|
32
|
+
* cleared setting, and nothing for an inherited or default one. Resolves the error-handler id to a
|
|
33
|
+
* slug.
|
|
34
|
+
*/
|
|
26
35
|
fromRaw(raw: RawTeamSettings): Promise<WorkspaceSettings>;
|
|
36
|
+
/** The settings.inherited.json view of the cloud's raw payload; undefined when nothing is inherited. */
|
|
37
|
+
inheritedFromRaw(raw: RawTeamSettings): Promise<InheritedWorkspaceSettings | undefined>;
|
|
38
|
+
/**
|
|
39
|
+
* settings.json is the source of truth for the team's own values: a setting absent from it is
|
|
40
|
+
* reset to inherit, null leaves the team with none (a parent's included), and a value sets it.
|
|
41
|
+
*/
|
|
42
|
+
toTeamUpdate(settings: WorkspaceSettings): Promise<TeamUpdateInput>;
|
|
27
43
|
/**
|
|
28
44
|
* Writes the cloud's workspace versions and aliases into the settings as the settings.json
|
|
29
45
|
* versioning fields (sorted for stable git diffs). Cloud entries always carry a createdAt; only
|
|
@@ -32,6 +48,10 @@ export default class SettingsRepository {
|
|
|
32
48
|
applyCloudVersioning(settings: WorkspaceSettings, versions: TeamVersion[], aliases: TeamVersionAlias[]): void;
|
|
33
49
|
resolveSlugToId(processSlug: string): Promise<string>;
|
|
34
50
|
resolveIdToSlug(processId: string): Promise<string>;
|
|
51
|
+
/** Where each setting comes from; an API without it predates settings inheritance. */
|
|
52
|
+
private originsOf;
|
|
53
|
+
private resolveErrorHandler;
|
|
54
|
+
private parseString;
|
|
35
55
|
private parseErrorHandler;
|
|
36
56
|
/**
|
|
37
57
|
* settings.json is hand-edited to declare versions, so entries without a tag are dropped and a
|