@eide/foir-cli 0.11.3 → 0.13.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 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
+ appBaseUrl: params.appBaseUrl,
859
+ customerWelcomeEmailEnabled: params.customerWelcomeEmailEnabled,
860
+ customerSignupEnabled: params.customerSignupEnabled
852
861
  })
853
862
  );
854
863
  return { project: resp.project ?? null };
@@ -5697,17 +5706,17 @@ function registerPushCommand(program2, globalOpts) {
5697
5706
  }
5698
5707
  const gOpts = globalOpts();
5699
5708
  const resolved = await resolveProjectContext(gOpts);
5700
- const pin = config2.project;
5701
- if (pin) {
5709
+ const projectBlock = config2.project;
5710
+ if (projectBlock) {
5702
5711
  if (!resolved) {
5703
5712
  throw new Error(
5704
- `foir.config.ts is pinned to project "${pin.name ?? pin.id}" (${pin.id}), but no project context is selected. Run \`foir select-project\` first.`
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.`
5705
5714
  );
5706
5715
  }
5707
- if (resolved.project.id !== pin.id || resolved.project.tenantId !== pin.tenantId) {
5716
+ if (resolved.project.id !== projectBlock.id || resolved.project.tenantId !== projectBlock.tenantId) {
5708
5717
  throw new Error(
5709
5718
  `Project mismatch \u2014 refusing to push.
5710
- foir.config.ts pin: ${pin.name ?? pin.id} (${pin.id})
5719
+ foir.config.ts pin: ${projectBlock.name ?? projectBlock.id} (${projectBlock.id})
5711
5720
  resolved (${resolved.source}): ${resolved.project.name} (${resolved.project.id})
5712
5721
  Hand-edit foir.config.ts or run \`foir select-project\` to align them.`
5713
5722
  );
@@ -5766,7 +5775,23 @@ function registerPushCommand(program2, globalOpts) {
5766
5775
  console.log(` Config Key: ${chalk6.cyan(config2.key)}`);
5767
5776
  console.log();
5768
5777
  printSummary(summary);
5769
- if (!pin && resolved) {
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
+ appBaseUrl: s.appBaseUrl,
5789
+ customerWelcomeEmailEnabled: s.customerWelcomeEmailEnabled,
5790
+ customerSignupEnabled: s.customerSignupEnabled
5791
+ });
5792
+ console.log(chalk6.dim(" Project settings: applied"));
5793
+ }
5794
+ if (!projectBlock && resolved) {
5770
5795
  console.log();
5771
5796
  console.log(chalk6.dim("Tip: pin this folder to its project by adding the following to foir.config.ts:"));
5772
5797
  console.log(chalk6.dim(" project: {"));
@@ -5877,6 +5902,7 @@ function registerPullCommand(program2, globalOpts) {
5877
5902
  }
5878
5903
  const resolved = await resolveProjectContext(globalOpts());
5879
5904
  let apps;
5905
+ let projectBlock;
5880
5906
  if (resolved) {
5881
5907
  const projectId = resolved.project.id;
5882
5908
  const tenantId = resolved.project.tenantId;
@@ -5887,9 +5913,18 @@ function registerPullCommand(program2, globalOpts) {
5887
5913
  apps[a.name] = appToInput(a);
5888
5914
  }
5889
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
+ };
5890
5923
  }
5891
5924
  const configDataNoInteg = { ...configData };
5892
5925
  delete configDataNoInteg.apps;
5926
+ const configDataNoProject = { ...configDataNoInteg };
5927
+ delete configDataNoProject.project;
5893
5928
  const manifest = {
5894
5929
  key: config2.key,
5895
5930
  name: config2.name,
@@ -5897,7 +5932,8 @@ function registerPullCommand(program2, globalOpts) {
5897
5932
  ...config2.direction ? { direction: config2.direction } : {},
5898
5933
  ...config2.description ? { description: config2.description } : {},
5899
5934
  ...config2.connectionDomain ? { operationBaseUrl: config2.connectionDomain } : {},
5900
- ...configDataNoInteg,
5935
+ ...projectBlock ? { project: projectBlock } : {},
5936
+ ...configDataNoProject,
5901
5937
  ...apps ? { apps } : {}
5902
5938
  };
5903
5939
  delete manifest.force;
@@ -5988,6 +6024,24 @@ export default defineConfig(${jsonContent});
5988
6024
  )
5989
6025
  );
5990
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.appBaseUrl) out.appBaseUrl = p.appBaseUrl;
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
+ }
5991
6045
  function appToInput(a) {
5992
6046
  const mappingsBlob = a.mappings ?? {};
5993
6047
  const out = { source: a.manifestUrl };
@@ -252,6 +252,63 @@ 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
+ * Public base URL of the consumer-facing app (storefront, portal,
276
+ * internal tool, …). Reset / verify / invitation links in customer
277
+ * emails are built from this — required before the platform will mint
278
+ * customer-email links.
279
+ */
280
+ appBaseUrl?: string;
281
+ /**
282
+ * Whether the platform sends a welcome email on customer registration.
283
+ * Default true. Disable for invite-style flows.
284
+ */
285
+ customerWelcomeEmailEnabled?: boolean;
286
+ /**
287
+ * Whether the public CustomerRegister mutation is allowed. Default true.
288
+ * When false, customers can only be created via secret-key admin paths
289
+ * (CreateCustomer, CreateCustomerInvitation).
290
+ */
291
+ customerSignupEnabled?: boolean;
292
+ }
293
+ /**
294
+ * Project pin + declarative settings. The pin (id / tenantId) is a guard
295
+ * against pushing one folder's config into another folder's project; the
296
+ * settings are applied to the platform via UpdateProject.
297
+ */
298
+ interface ApplyConfigProjectInput {
299
+ /** Project id this folder is bound to. */
300
+ id: string;
301
+ /** Tenant id of the bound project. */
302
+ tenantId: string;
303
+ /** Optional human-friendly name for diff readability. */
304
+ name?: string;
305
+ /**
306
+ * Project-level settings reconciled by `foir push`. Omit to leave the
307
+ * platform settings untouched. `foir pull` populates this block from
308
+ * the live project state so the local config can be version-controlled.
309
+ */
310
+ settings?: ApplyConfigProjectSettingsInput;
311
+ }
255
312
  interface ApplyConfigInput {
256
313
  key: string;
257
314
  name: string;
@@ -259,6 +316,12 @@ interface ApplyConfigInput {
259
316
  force?: boolean;
260
317
  /** Base URL prepended to relative operation endpoints. */
261
318
  operationBaseUrl?: string;
319
+ /**
320
+ * Project pin + declarative project-level settings. The pin guards
321
+ * against cross-folder mis-pushes; the settings (when present) are
322
+ * applied to the platform alongside the model / operation reconcile.
323
+ */
324
+ project?: ApplyConfigProjectInput;
262
325
  models?: ApplyConfigModelInput[];
263
326
  operations?: ApplyConfigOperationInput[];
264
327
  segments?: ApplyConfigSegmentInput[];
@@ -292,4 +355,4 @@ declare function defineHook(hook: ApplyConfigHookInput): ApplyConfigHookInput;
292
355
  /** Define an editor placement (sidebar or main-editor tab). */
293
356
  declare function definePlacement(placement: ApplyConfigPlacementInput): ApplyConfigPlacementInput;
294
357
 
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 };
358
+ 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.11.3",
3
+ "version": "0.13.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.29.1",
53
+ "@eide/foir-proto-ts": "^0.31.0",
54
54
  "chalk": "^5.3.0",
55
55
  "commander": "^12.1.0",
56
56
  "dotenv": "^16.4.5",