@eide/foir-cli 0.11.2 → 0.12.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/dist/cli.js +91 -6
- package/dist/lib/config-helpers.d.ts +63 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -848,7 +848,16 @@ function createIdentityMethods(client) {
|
|
|
848
848
|
create(UpdateProjectRequestSchema, {
|
|
849
849
|
id: params.id,
|
|
850
850
|
name: params.name,
|
|
851
|
-
description: params.description
|
|
851
|
+
description: params.description,
|
|
852
|
+
displayName: params.displayName,
|
|
853
|
+
logoUrl: params.logoUrl,
|
|
854
|
+
primaryColor: params.primaryColor,
|
|
855
|
+
fromName: params.fromName,
|
|
856
|
+
replyTo: params.replyTo,
|
|
857
|
+
supportEmail: params.supportEmail,
|
|
858
|
+
customerPortalBaseUrl: params.customerPortalBaseUrl,
|
|
859
|
+
customerWelcomeEmailEnabled: params.customerWelcomeEmailEnabled,
|
|
860
|
+
customerSignupEnabled: params.customerSignupEnabled
|
|
852
861
|
})
|
|
853
862
|
);
|
|
854
863
|
return { project: resp.project ?? null };
|
|
@@ -3478,9 +3487,12 @@ function registerSelectProjectCommand(program2, globalOpts) {
|
|
|
3478
3487
|
selectedProject = projects.find((p) => p.id === projectId);
|
|
3479
3488
|
}
|
|
3480
3489
|
console.log("\nProvisioning API key for CLI access...");
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3490
|
+
const scopedClient = createPlatformClientWithHeaders(apiUrl, {
|
|
3491
|
+
Authorization: `Bearer ${credentials.accessToken}`,
|
|
3492
|
+
"x-tenant-id": selectedProject.tenantId,
|
|
3493
|
+
"x-project-id": selectedProject.id
|
|
3494
|
+
});
|
|
3495
|
+
const { apiKey, apiKeyId } = await provisionApiKey(scopedClient);
|
|
3484
3496
|
await writeProjectContext(
|
|
3485
3497
|
{
|
|
3486
3498
|
id: selectedProject.id,
|
|
@@ -5693,8 +5705,24 @@ function registerPushCommand(program2, globalOpts) {
|
|
|
5693
5705
|
);
|
|
5694
5706
|
}
|
|
5695
5707
|
const gOpts = globalOpts();
|
|
5696
|
-
const client = await createPlatformClient(gOpts);
|
|
5697
5708
|
const resolved = await resolveProjectContext(gOpts);
|
|
5709
|
+
const projectBlock = config2.project;
|
|
5710
|
+
if (projectBlock) {
|
|
5711
|
+
if (!resolved) {
|
|
5712
|
+
throw new Error(
|
|
5713
|
+
`foir.config.ts is pinned to project "${projectBlock.name ?? projectBlock.id}" (${projectBlock.id}), but no project context is selected. Run \`foir select-project\` first.`
|
|
5714
|
+
);
|
|
5715
|
+
}
|
|
5716
|
+
if (resolved.project.id !== projectBlock.id || resolved.project.tenantId !== projectBlock.tenantId) {
|
|
5717
|
+
throw new Error(
|
|
5718
|
+
`Project mismatch \u2014 refusing to push.
|
|
5719
|
+
foir.config.ts pin: ${projectBlock.name ?? projectBlock.id} (${projectBlock.id})
|
|
5720
|
+
resolved (${resolved.source}): ${resolved.project.name} (${resolved.project.id})
|
|
5721
|
+
Hand-edit foir.config.ts or run \`foir select-project\` to align them.`
|
|
5722
|
+
);
|
|
5723
|
+
}
|
|
5724
|
+
}
|
|
5725
|
+
const client = await createPlatformClient(gOpts);
|
|
5698
5726
|
console.log(
|
|
5699
5727
|
chalk6.dim(`Pushing config "${config2.key}" to platform...`)
|
|
5700
5728
|
);
|
|
@@ -5747,6 +5775,34 @@ function registerPushCommand(program2, globalOpts) {
|
|
|
5747
5775
|
console.log(` Config Key: ${chalk6.cyan(config2.key)}`);
|
|
5748
5776
|
console.log();
|
|
5749
5777
|
printSummary(summary);
|
|
5778
|
+
if (projectBlock?.settings && resolved) {
|
|
5779
|
+
const s = projectBlock.settings;
|
|
5780
|
+
await client.identity.updateProject({
|
|
5781
|
+
id: resolved.project.id,
|
|
5782
|
+
displayName: s.displayName,
|
|
5783
|
+
logoUrl: s.logoUrl,
|
|
5784
|
+
primaryColor: s.primaryColor,
|
|
5785
|
+
fromName: s.fromName,
|
|
5786
|
+
replyTo: s.replyTo,
|
|
5787
|
+
supportEmail: s.supportEmail,
|
|
5788
|
+
customerPortalBaseUrl: s.customerPortalBaseUrl,
|
|
5789
|
+
customerWelcomeEmailEnabled: s.customerWelcomeEmailEnabled,
|
|
5790
|
+
customerSignupEnabled: s.customerSignupEnabled
|
|
5791
|
+
});
|
|
5792
|
+
console.log(chalk6.dim(" Project settings: applied"));
|
|
5793
|
+
}
|
|
5794
|
+
if (!projectBlock && resolved) {
|
|
5795
|
+
console.log();
|
|
5796
|
+
console.log(chalk6.dim("Tip: pin this folder to its project by adding the following to foir.config.ts:"));
|
|
5797
|
+
console.log(chalk6.dim(" project: {"));
|
|
5798
|
+
console.log(chalk6.dim(` id: '${resolved.project.id}',`));
|
|
5799
|
+
console.log(chalk6.dim(` tenantId: '${resolved.project.tenantId}',`));
|
|
5800
|
+
if (resolved.project.name) {
|
|
5801
|
+
console.log(chalk6.dim(` name: '${resolved.project.name}',`));
|
|
5802
|
+
}
|
|
5803
|
+
console.log(chalk6.dim(" },"));
|
|
5804
|
+
console.log(chalk6.dim("Future pushes will refuse to run if the resolved project drifts from this id."));
|
|
5805
|
+
}
|
|
5750
5806
|
const envPath = resolve4(opts.env ?? ".env");
|
|
5751
5807
|
const envWrites = [];
|
|
5752
5808
|
for (const pk of summary.apiKeys) {
|
|
@@ -5846,6 +5902,7 @@ function registerPullCommand(program2, globalOpts) {
|
|
|
5846
5902
|
}
|
|
5847
5903
|
const resolved = await resolveProjectContext(globalOpts());
|
|
5848
5904
|
let apps;
|
|
5905
|
+
let projectBlock;
|
|
5849
5906
|
if (resolved) {
|
|
5850
5907
|
const projectId = resolved.project.id;
|
|
5851
5908
|
const tenantId = resolved.project.tenantId;
|
|
@@ -5856,9 +5913,18 @@ function registerPullCommand(program2, globalOpts) {
|
|
|
5856
5913
|
apps[a.name] = appToInput(a);
|
|
5857
5914
|
}
|
|
5858
5915
|
}
|
|
5916
|
+
const { project } = await client.identity.getProject(projectId);
|
|
5917
|
+
projectBlock = {
|
|
5918
|
+
id: projectId,
|
|
5919
|
+
tenantId,
|
|
5920
|
+
...project?.name ? { name: project.name } : {},
|
|
5921
|
+
settings: projectSettingsFromGetProject(project)
|
|
5922
|
+
};
|
|
5859
5923
|
}
|
|
5860
5924
|
const configDataNoInteg = { ...configData };
|
|
5861
5925
|
delete configDataNoInteg.apps;
|
|
5926
|
+
const configDataNoProject = { ...configDataNoInteg };
|
|
5927
|
+
delete configDataNoProject.project;
|
|
5862
5928
|
const manifest = {
|
|
5863
5929
|
key: config2.key,
|
|
5864
5930
|
name: config2.name,
|
|
@@ -5866,7 +5932,8 @@ function registerPullCommand(program2, globalOpts) {
|
|
|
5866
5932
|
...config2.direction ? { direction: config2.direction } : {},
|
|
5867
5933
|
...config2.description ? { description: config2.description } : {},
|
|
5868
5934
|
...config2.connectionDomain ? { operationBaseUrl: config2.connectionDomain } : {},
|
|
5869
|
-
...
|
|
5935
|
+
...projectBlock ? { project: projectBlock } : {},
|
|
5936
|
+
...configDataNoProject,
|
|
5870
5937
|
...apps ? { apps } : {}
|
|
5871
5938
|
};
|
|
5872
5939
|
delete manifest.force;
|
|
@@ -5957,6 +6024,24 @@ export default defineConfig(${jsonContent});
|
|
|
5957
6024
|
)
|
|
5958
6025
|
);
|
|
5959
6026
|
}
|
|
6027
|
+
function projectSettingsFromGetProject(p) {
|
|
6028
|
+
if (!p) return void 0;
|
|
6029
|
+
const out = {};
|
|
6030
|
+
if (p.displayName) out.displayName = p.displayName;
|
|
6031
|
+
if (p.logoUrl) out.logoUrl = p.logoUrl;
|
|
6032
|
+
if (p.primaryColor) out.primaryColor = p.primaryColor;
|
|
6033
|
+
if (p.fromName) out.fromName = p.fromName;
|
|
6034
|
+
if (p.replyTo) out.replyTo = p.replyTo;
|
|
6035
|
+
if (p.supportEmail) out.supportEmail = p.supportEmail;
|
|
6036
|
+
if (p.customerPortalBaseUrl) out.customerPortalBaseUrl = p.customerPortalBaseUrl;
|
|
6037
|
+
if (typeof p.customerWelcomeEmailEnabled === "boolean") {
|
|
6038
|
+
out.customerWelcomeEmailEnabled = p.customerWelcomeEmailEnabled;
|
|
6039
|
+
}
|
|
6040
|
+
if (typeof p.customerSignupEnabled === "boolean") {
|
|
6041
|
+
out.customerSignupEnabled = p.customerSignupEnabled;
|
|
6042
|
+
}
|
|
6043
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
6044
|
+
}
|
|
5960
6045
|
function appToInput(a) {
|
|
5961
6046
|
const mappingsBlob = a.mappings ?? {};
|
|
5962
6047
|
const out = { source: a.manifestUrl };
|
|
@@ -252,6 +252,62 @@ interface AppInput {
|
|
|
252
252
|
placementFields?: Record<string, AppPlacementFieldChoiceInput>;
|
|
253
253
|
};
|
|
254
254
|
}
|
|
255
|
+
/**
|
|
256
|
+
* Project-level settings applied via UpdateProject at push time and
|
|
257
|
+
* read via GetProject at pull time. Branding fields are empty-string-as-
|
|
258
|
+
* clear on the platform side: `''` clears the column, `undefined` leaves
|
|
259
|
+
* it untouched.
|
|
260
|
+
*/
|
|
261
|
+
interface ApplyConfigProjectSettingsInput {
|
|
262
|
+
/** Display name in customer-facing emails / portal headers. */
|
|
263
|
+
displayName?: string;
|
|
264
|
+
/** Public URL of the project logo (rendered in customer emails). */
|
|
265
|
+
logoUrl?: string;
|
|
266
|
+
/** Hex color used as accent in customer-facing emails. */
|
|
267
|
+
primaryColor?: string;
|
|
268
|
+
/** "From" name on outbound customer emails. */
|
|
269
|
+
fromName?: string;
|
|
270
|
+
/** "Reply-To" address on outbound customer emails. */
|
|
271
|
+
replyTo?: string;
|
|
272
|
+
/** Support email surfaced in email footers. */
|
|
273
|
+
supportEmail?: string;
|
|
274
|
+
/**
|
|
275
|
+
* Base URL of the customer-facing portal. Reset / verify / invitation
|
|
276
|
+
* links in customer emails are built from this — required before the
|
|
277
|
+
* platform will mint customer-portal links.
|
|
278
|
+
*/
|
|
279
|
+
customerPortalBaseUrl?: string;
|
|
280
|
+
/**
|
|
281
|
+
* Whether the platform sends a welcome email on customer registration.
|
|
282
|
+
* Default true. Disable for invite-style flows.
|
|
283
|
+
*/
|
|
284
|
+
customerWelcomeEmailEnabled?: boolean;
|
|
285
|
+
/**
|
|
286
|
+
* Whether the public CustomerRegister mutation is allowed. Default true.
|
|
287
|
+
* When false, customers can only be created via secret-key admin paths
|
|
288
|
+
* (CreateCustomer, CreateCustomerInvitation).
|
|
289
|
+
*/
|
|
290
|
+
customerSignupEnabled?: boolean;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Project pin + declarative settings. The pin (id / tenantId) is a guard
|
|
294
|
+
* against pushing one folder's config into another folder's project; the
|
|
295
|
+
* settings are applied to the platform via UpdateProject.
|
|
296
|
+
*/
|
|
297
|
+
interface ApplyConfigProjectInput {
|
|
298
|
+
/** Project id this folder is bound to. */
|
|
299
|
+
id: string;
|
|
300
|
+
/** Tenant id of the bound project. */
|
|
301
|
+
tenantId: string;
|
|
302
|
+
/** Optional human-friendly name for diff readability. */
|
|
303
|
+
name?: string;
|
|
304
|
+
/**
|
|
305
|
+
* Project-level settings reconciled by `foir push`. Omit to leave the
|
|
306
|
+
* platform settings untouched. `foir pull` populates this block from
|
|
307
|
+
* the live project state so the local config can be version-controlled.
|
|
308
|
+
*/
|
|
309
|
+
settings?: ApplyConfigProjectSettingsInput;
|
|
310
|
+
}
|
|
255
311
|
interface ApplyConfigInput {
|
|
256
312
|
key: string;
|
|
257
313
|
name: string;
|
|
@@ -259,6 +315,12 @@ interface ApplyConfigInput {
|
|
|
259
315
|
force?: boolean;
|
|
260
316
|
/** Base URL prepended to relative operation endpoints. */
|
|
261
317
|
operationBaseUrl?: string;
|
|
318
|
+
/**
|
|
319
|
+
* Project pin + declarative project-level settings. The pin guards
|
|
320
|
+
* against cross-folder mis-pushes; the settings (when present) are
|
|
321
|
+
* applied to the platform alongside the model / operation reconcile.
|
|
322
|
+
*/
|
|
323
|
+
project?: ApplyConfigProjectInput;
|
|
262
324
|
models?: ApplyConfigModelInput[];
|
|
263
325
|
operations?: ApplyConfigOperationInput[];
|
|
264
326
|
segments?: ApplyConfigSegmentInput[];
|
|
@@ -292,4 +354,4 @@ declare function defineHook(hook: ApplyConfigHookInput): ApplyConfigHookInput;
|
|
|
292
354
|
/** Define an editor placement (sidebar or main-editor tab). */
|
|
293
355
|
declare function definePlacement(placement: ApplyConfigPlacementInput): ApplyConfigPlacementInput;
|
|
294
356
|
|
|
295
|
-
export { type AppInput, type AppPlacementFieldChoiceInput, type AppSinkMappingInput, type AppSourceMappingInput, type ApplyConfigApiKeyInput, type ApplyConfigAuthProviderInput, type ApplyConfigHookInput, type ApplyConfigInput, type ApplyConfigModelInput, type ApplyConfigOperationInput, type ApplyConfigPlacementInput, type ApplyConfigScheduleInput, type ApplyConfigSegmentInput, type ExpressionPrecondition, type FieldDefinitionInput, type Precondition, type QuotaRule, type SegmentPrecondition, type SelectFieldConfig, type SelectFieldDefinitionInput, defineAuthProvider, defineConfig, defineField, defineHook, defineModel, defineOperation, definePlacement, defineSchedule, defineSegment, defineSelectField };
|
|
357
|
+
export { type AppInput, type AppPlacementFieldChoiceInput, type AppSinkMappingInput, type AppSourceMappingInput, type ApplyConfigApiKeyInput, type ApplyConfigAuthProviderInput, type ApplyConfigHookInput, type ApplyConfigInput, type ApplyConfigModelInput, type ApplyConfigOperationInput, type ApplyConfigPlacementInput, type ApplyConfigProjectInput, type ApplyConfigProjectSettingsInput, type ApplyConfigScheduleInput, type ApplyConfigSegmentInput, type ExpressionPrecondition, type FieldDefinitionInput, type Precondition, type QuotaRule, type SegmentPrecondition, type SelectFieldConfig, type SelectFieldDefinitionInput, defineAuthProvider, defineConfig, defineField, defineHook, defineModel, defineOperation, definePlacement, defineSchedule, defineSegment, defineSelectField };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eide/foir-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Universal platform CLI for Foir platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@bufbuild/protovalidate": "^1.1.1",
|
|
51
51
|
"@connectrpc/connect": "^2.0.0",
|
|
52
52
|
"@connectrpc/connect-node": "^2.0.0",
|
|
53
|
-
"@eide/foir-proto-ts": "^0.
|
|
53
|
+
"@eide/foir-proto-ts": "^0.30.0",
|
|
54
54
|
"chalk": "^5.3.0",
|
|
55
55
|
"commander": "^12.1.0",
|
|
56
56
|
"dotenv": "^16.4.5",
|