@foir/cli 0.78.0 → 0.79.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.
@@ -56,15 +56,16 @@ interface EnumFieldConfig {
56
56
  placement?: FieldPlacement;
57
57
  }
58
58
  /**
59
- * Per-field {read, write} principal allow-lists. A non-empty `write` names
60
- * the only principals permitted to write the field — "public" | "self" |
61
- * "scoped" | "service" | "admin" — and any other principal is rejected by the
62
- * platform on every write path. Omit for the default (writable by any
63
- * authenticated principal). `read` governs client API exposure only.
59
+ * Which sides of a field are guarded. A guarded side is read, or written, only
60
+ * by a holder of the grant that names the field: `records:read:<model>.<field>`
61
+ * or `records:write:<model>.<field>`, at a reach that covers the record. A
62
+ * grant on the model does not reach a guarded side, and one on every owner's
63
+ * records of every model does. Give the field's grants to the roles, keys and
64
+ * operations that read or write it. Omit for a field that follows its model.
64
65
  */
65
- interface FieldAccessInput {
66
- read?: string[];
67
- write?: string[];
66
+ interface FieldGuardInput {
67
+ read?: boolean;
68
+ write?: boolean;
68
69
  }
69
70
  interface BaseFieldDefinitionInput {
70
71
  key: string;
@@ -93,7 +94,7 @@ interface BaseFieldDefinitionInput {
93
94
  storage?: string;
94
95
  templateZone?: string;
95
96
  zoneOrder?: number;
96
- access?: FieldAccessInput;
97
+ guarded?: FieldGuardInput;
97
98
  }
98
99
  type SelectFieldDefinitionInput = BaseFieldDefinitionInput & {
99
100
  type: 'select';
@@ -184,11 +185,9 @@ interface LookupDefinitionInput {
184
185
  interface AccessInput {
185
186
  /**
186
187
  * Which plane owns records of this model:
187
- * - `'customer'` — owned by the customer who created them. Per-customer RLS
188
- * isolation, private response-cache, per-owner lookups. Required for a
189
- * customer-context singleton.
190
- * - `'admin'` — owned by the operator who created them; operator-private
191
- * (other operators can't see them unless shared).
188
+ * - `'user'`: owned by a person: the one the write names as the owner,
189
+ * else the person who writes it. Per-owner RLS isolation, private
190
+ * response-cache, per-owner lookups. Required for a per-user singleton.
192
191
  * - `'project'` — no individual owner; records belong to the project. The
193
192
  * platform default.
194
193
  * - `'organization'` — owned by one of the project's ORGANIZATIONS (the
@@ -196,27 +195,27 @@ interface AccessInput {
196
195
  * the row stays in the project plane, so the project credential finds
197
196
  * every organization's rows — which is how a multi-tenant app resolves
198
197
  * `<sub>.theapp.com` to an org before it knows which org the request is
199
- * for. Written by the project (never for a customer), owner
198
+ * for. Written by the project (never for a person), owner
200
199
  * named by `ownerId` or by the org the caller acts in (`X-Org-Id`);
201
200
  * `singleton` means one record per organization. Refused on a project
202
201
  * with no organizations and on a shared (layered/group) model.
203
202
  */
204
- ownerPlane: 'customer' | 'admin' | 'project' | 'organization';
203
+ ownerPlane: 'user' | 'project' | 'organization';
205
204
  /**
206
205
  * Visibility new records start at (the record descriptor modes):
207
206
  * - `'private'` — only the owner and explicit grants.
208
207
  * - `'public'` — readable by anyone with API access, including signed-in
209
- * customers on the public API.
208
+ * users on the public API.
210
209
  *
211
210
  * On a PROJECT-plane model, omitting this defaults to `'public'` at
212
211
  * CREATION — project content is meant to be read, and `'private'` there does
213
212
  * not mean what it looks like: a project record has no owner, so it stays
214
213
  * readable by anonymous and server-side callers while being hidden from
215
- * signed-in customers. Set `'private'` explicitly to opt a project model out.
214
+ * signed-in users. Set `'private'` explicitly to opt a project model out.
216
215
  *
217
216
  * The default is applied by the platform, at the create path only. Omitting it
218
217
  * on a model that already exists means "leave it alone" — it will not reset a
219
- * visibility you changed in the console. Owned planes (customer/admin) are
218
+ * visibility you changed in the console. Owned planes (user, organization) are
220
219
  * always private (the platform rejects a public default there) regardless of
221
220
  * this value.
222
221
  */
@@ -250,8 +249,11 @@ interface QuotaRule {
250
249
  points: number;
251
250
  /** Window duration in seconds (3600=1hr, 86400=1day, 604800=7day, 2592000=30day). */
252
251
  duration: number;
253
- /** Scope for tracking: per customer, per user, or per tenant. */
254
- scope: 'customer' | 'user' | 'tenant';
252
+ /**
253
+ * Whose counter a run is charged to: `user`, the person the run is for;
254
+ * `actor`, whoever started it; or `tenant`, the workspace.
255
+ */
256
+ scope: 'user' | 'actor' | 'tenant';
255
257
  /** Optional rule expression condition. */
256
258
  condition?: Record<string, unknown>;
257
259
  /** Optional expiry — rule is ignored after this date (ISO 8601). */
@@ -286,7 +288,7 @@ interface ApplyConfigOperationInput {
286
288
  timeoutMs?: number;
287
289
  inputSchema?: Record<string, unknown>;
288
290
  outputSchema?: Record<string, unknown>;
289
- /** Usage quota rules (rate limits per customer/user/tenant). */
291
+ /** Usage quota rules (rate limits per user, actor or tenant). */
290
292
  quotas?: {
291
293
  rules: QuotaRule[];
292
294
  };
@@ -358,19 +360,19 @@ interface ApplyConfigOperationInput {
358
360
  * that does both declares both. List every model the operation touches.
359
361
  *
360
362
  * Ownership, `records:attribute:<model_key>` (or `records:attribute` for
361
- * every model), lets the operation name the customer a record belongs to
363
+ * every model), lets the operation name the user a record belongs to
362
364
  * when it creates one (`create<Model>(input, ownerId)`) and hand a record
363
- * to another customer (`set<Model>Owner`). It is held only by an
365
+ * to another user (`set<Model>Owner`). It is held only by an
364
366
  * operation: no API key of any type can be minted with it.
365
367
  *
366
368
  * The rest are written as the catalogue writes them: `embeddings:read`,
367
369
  * `embeddings:write`, `files:read`, `files:write`, `users:create` (create
368
- * a customer, such as the buyer at a guest checkout), `users:read.named`
369
- * (read one customer the operation names, by id or by their exact email
370
+ * a user, such as the buyer at a guest checkout), `users:read.named`
371
+ * (read one user the operation names, by id or by their exact email
370
372
  * address), `users:read.all` (that, and the list),
371
- * `notifications:write.named` (notify the project's customers; an
372
- * operation acting for a customer notifies that customer alone, and one
373
- * at an organisation reaches only its customers), `status:write`, and
373
+ * `notifications:write.named` (notify the project's users; an
374
+ * operation acting for a user notifies that user alone, and one
375
+ * at an organisation reaches only its users), `status:write`, and
374
376
  * `secrets:read`. A grant an operation may not declare is refused at
375
377
  * push, by name. The whole list is at
376
378
  * https://docs.foir.dev/api/operation-permissions.
@@ -448,7 +450,7 @@ interface ApplyConfigOperationInput {
448
450
  /**
449
451
  * A context dimension — the home for segments. `sourceType: 'segment'`
450
452
  * carries an `evaluationRules` RuleExpression (evaluated fresh at request time
451
- * into segment.<key>); `sourceType: 'model'` designates a customer-context
453
+ * into segment.<key>); `sourceType: 'model'` designates a user-context
452
454
  * source model via `sourceModelKey`; `sourceType: 'request'` is a value the
453
455
  * application sends in the contexts argument of a read, one of the records of
454
456
  * the model `sourceModelKey` names. Reconciled config-scoped by `foir push`
@@ -460,7 +462,7 @@ interface ApplyConfigContextDimensionInput {
460
462
  name: string;
461
463
  description?: string;
462
464
  /**
463
- * 'segment' (rule-based) | 'model' (customer-context source) | 'request'
465
+ * 'segment' (rule-based) | 'model' (user-context source) | 'request'
464
466
  * (a value sent with the read) | custom.
465
467
  */
466
468
  sourceType: string;
@@ -468,7 +470,7 @@ interface ApplyConfigContextDimensionInput {
468
470
  evaluationRules?: Record<string, unknown>;
469
471
  /**
470
472
  * The model the dimension is backed by. For sourceType 'model', a
471
- * customer-owned singleton. For sourceType 'request', a model whose records
473
+ * user-owned singleton. For sourceType 'request', a model whose records
472
474
  * belong to the project as a whole: each record's natural key is one value.
473
475
  */
474
476
  sourceModelKey?: string;
@@ -508,7 +510,7 @@ interface ApplyConfigVariantCatalogEntryInput {
508
510
  /**
509
511
  * One transactional email's wording, keyed by the action that sends it.
510
512
  *
511
- * `actionKey` names a send path — `email.customer.welcome`, or a notification
513
+ * `actionKey` names a send path — `email.project.welcome`, or a notification
512
514
  * hook's own key. The platform refuses one it does not recognise, because a row
513
515
  * written under a typo is read by nothing and looks applied.
514
516
  *
@@ -563,49 +565,43 @@ interface ApplyConfigAuthProviderInput {
563
565
  priority?: number;
564
566
  }
565
567
  /**
566
- * Login-with-Foir customer-lane relying party. Each entry registers a
567
- * storefront or third-party app that can launch the hosted customer
568
- * login at auth.foir.dev/authorize?client_id=… and exchange the auth
569
- * code at /customer/oauth/token.
568
+ * A Login-with-Foir auth client. Each entry registers a storefront or
569
+ * other app that signs the project's users in at the hosted login
570
+ * (auth.foir.dev/authorize?client_id=…) and exchanges the code at
571
+ * /oauth/token.
570
572
  *
571
573
  * The reconciler is project-scoped (tenant + project come from the
572
- * push context), so consumers only declare the per-RP fields. Pass to
573
- * `relyingParties` on the manifest.
574
+ * push context), so consumers only declare the per-client fields. Pass to
575
+ * `authClients` on the manifest.
574
576
  */
575
577
  /**
576
- * Per-RP login method config (login-with-foir-full-workstream-plan.md
577
- * §Per-RP login method toggle). All fields optional — missing keys
578
+ * Per-client login method config (login-with-foir-full-workstream-plan.md
579
+ * §Per-client login method toggle). All fields optional — missing keys
578
580
  * default to enabled. Lets a project's storefront opt to only Sign in
579
581
  * with Shopify (disable password/OTP + don't list Apple) without
580
582
  * touching the project-level provider catalogue.
581
583
  */
582
- interface ApplyConfigRelyingPartyLoginMethods {
584
+ interface ApplyConfigAuthClientLoginMethods {
583
585
  /**
584
- * Show email & password sign-in on this RP's hosted login? Defaults to
586
+ * Show email & password sign-in on this auth client's hosted login? Defaults to
585
587
  * true. Only narrows the project capability — can't enable a method the
586
- * project (`customerPasswordEnabled`) has turned off.
588
+ * project (`passwordEnabled`) has turned off.
587
589
  */
588
590
  password?: boolean;
589
591
  /**
590
- * Show one-time code sign-in on this RP's hosted login? Defaults to true.
591
- * Only narrows the project capability (`customerOtpEnabled`).
592
+ * Show one-time code sign-in on this auth client's hosted login? Defaults to true.
593
+ * Only narrows the project capability (`otpEnabled`).
592
594
  */
593
595
  otp?: boolean;
594
596
  /**
595
- * Provider keys to HIDE on this RP's login page. Empty/missing = show
597
+ * Provider keys to HIDE on this auth client's login page. Empty/missing = show
596
598
  * every provider configured at the project level. List a key (e.g.
597
- * "google") to omit it from this RP only.
599
+ * "google") to omit it from this auth client only.
598
600
  */
599
601
  disabledProviders?: string[];
600
602
  }
601
- interface ApplyConfigRelyingPartyInput {
602
- /**
603
- * Which lane this RP authenticates. `foir push` is project-scoped, so
604
- * RPs declared in config are customer-lane (the default); admin RPs are
605
- * platform-managed and not part of project config.
606
- */
607
- kind?: 'customer' | 'admin';
608
- /** Public RP slug, unique per project (e.g. `acme-storefront`). */
603
+ interface ApplyConfigAuthClientInput {
604
+ /** Public auth client slug, unique per project (e.g. `acme-storefront`). */
609
605
  clientId: string;
610
606
  /** Display name shown on the hosted login. */
611
607
  name: string;
@@ -623,7 +619,7 @@ interface ApplyConfigRelyingPartyInput {
623
619
  redirectUris: string[];
624
620
  /**
625
621
  * The most a sign-in through this app may carry of what the person's roles
626
- * give them, in the permission catalogue's names: the same names a customer
622
+ * give them, in the permission catalogue's names: the same names a user
627
623
  * role is declared with (https://docs.foir.dev/api/role-permissions).
628
624
  *
629
625
  * The list gives nobody anything. A person holds what their roles give, and
@@ -639,25 +635,41 @@ interface ApplyConfigRelyingPartyInput {
639
635
  */
640
636
  grants: string[];
641
637
  /**
642
- * Per-RP login method filter (customer-lane). Combines with the project-
643
- * level customer auth settings (project may have password OFF entirely; an
644
- * RP can't override-up, only override-down).
638
+ * Whether this app is the project's own. A sign-in through the project's own
639
+ * app asks nobody to agree to it. Through any other app, each user is shown
640
+ * what it asks to carry for them and agrees to it once, and the token
641
+ * carries no more than they agreed. Leave it off for an app someone else
642
+ * runs.
645
643
  */
646
- loginMethods?: ApplyConfigRelyingPartyLoginMethods;
644
+ firstParty?: boolean;
647
645
  /**
648
- * White-label custom login domains for this RP, e.g.
646
+ * Per-client login method filter. Combines with the project-
647
+ * level user auth settings (project may have password OFF entirely; an
648
+ * auth client can't override-up, only override-down).
649
+ */
650
+ loginMethods?: ApplyConfigAuthClientLoginMethods;
651
+ /**
652
+ * White-label custom login domains for this auth client, e.g.
649
653
  * `['login.eide.clothing']`. `foir push` registers each (creating a pending
650
654
  * row + a DNS-TXT challenge) and prunes any not listed. Verification is a
651
655
  * separate step — add the CNAME + `_foir-challenge` TXT records the push
652
- * output prints, then verify. Customer-lane only.
656
+ * output prints, then verify.
653
657
  */
654
658
  customDomains?: string[];
655
659
  /**
656
660
  * Where a bare custom-domain (front-door) login lands after Foir sets the
657
661
  * first-party session cookie — the app's landing, not an OAuth
658
- * callback. Empty falls back to the redirect URI. Customer-lane only.
662
+ * callback. Empty falls back to the redirect URI.
659
663
  */
660
664
  postLoginUrl?: string;
665
+ /**
666
+ * An address in your app that starts its sign-in (OIDC's
667
+ * `initiate_login_uri`). When someone accepts an invitation or resets their
668
+ * password on Foir's hosted pages, they are sent here with `iss`,
669
+ * `login_hint` and `target_link_uri`, and your app signs them in as usual.
670
+ * Absent, they finish on the hosted page. https, or http on localhost.
671
+ */
672
+ initiateLoginUri?: string;
661
673
  /**
662
674
  * Browser origins allowed to exchange the first-party session cookie for an
663
675
  * access token — i.e. the origins your SPA runs on, e.g.
@@ -670,7 +682,7 @@ interface ApplyConfigRelyingPartyInput {
670
682
  * origin on your domain, including a subdomain takeover or anything serving
671
683
  * user content there.
672
684
  *
673
- * Absent leaves the list untouched; `[]` clears it. Customer-lane only, and
685
+ * Absent leaves the list untouched; `[]` clears it. It is
674
686
  * only meaningful alongside a verified `customDomains` entry (the cookie is
675
687
  * only ever issued on one).
676
688
  */
@@ -790,24 +802,24 @@ interface ApplyConfigApiKeyInput {
790
802
  org?: string;
791
803
  }
792
804
  /**
793
- * A customer role declared in foir.config.ts and reconciled by `foir push`.
794
- * The role's `grants` are what a customer who holds it may do once signed in:
805
+ * A role declared in foir.config.ts and reconciled by `foir push`.
806
+ * The role's `grants` are what a user who holds it may do once signed in:
795
807
  * their access token carries them. Roles are matched by `key` within the
796
808
  * project: a declared key that already exists is updated in place, and a new
797
809
  * key is created. A role on the platform that the config leaves out is left
798
810
  * as it is, never disabled.
799
811
  *
800
- * Without a role, a signed-in customer may do only what the key gives
801
- * everyone who comes through it (its `baselineGrants`). Anything a customer
812
+ * Without a role, a signed-in user may do only what the key gives
813
+ * everyone who comes through it (its `baselineGrants`). Anything a user
802
814
  * may do beyond that comes from a role they hold.
803
815
  */
804
- interface ApplyConfigCustomerRoleInput {
816
+ interface ApplyConfigUserRoleInput {
805
817
  /** Stable key, unique per project (e.g. "default", "member"). */
806
818
  key: string;
807
- /** Human-readable name (e.g. "Default Customer"). */
819
+ /** Human-readable name (e.g. "Default User"). */
808
820
  name: string;
809
821
  /**
810
- * What the role gives customers who hold it, as grants in the permission
822
+ * What the role gives users who hold it, as grants in the permission
811
823
  * catalogue's names: records:read:<model>, records:write:<model>,
812
824
  * records:create:<model>, operations:execute, files:read and the rest of
813
825
  * the list at https://docs.foir.dev/api/role-permissions.
@@ -816,14 +828,12 @@ interface ApplyConfigCustomerRoleInput {
816
828
  * grants, so a role that should do both lists `records:write:<model>` and
817
829
  * `records:create:<model>`.
818
830
  *
819
- * The `self:*` shorthand is worked out when a customer signs in, into the
820
- * read, the write and the create of every model the project lets a customer
821
- * write. It does NOT include operations:execute, so list that explicitly
822
- * when the app's customers run operations.
831
+ * A guarded field is given by the grants that name it,
832
+ * `records:read:<model>.<field>` and `records:write:<model>.<field>`.
823
833
  *
824
834
  * `operations:execute` runs every operation the key exposes;
825
835
  * `operations:execute:<operation_key>` runs that one alone, so a role can
826
- * let every customer check out and keep rebooking for the customers whose
836
+ * let every user check out and keep rebooking for the users whose
827
837
  * role gives it. A push naming an operation the project does not have is
828
838
  * refused, by name.
829
839
  *
@@ -831,8 +841,8 @@ interface ApplyConfigCustomerRoleInput {
831
841
  */
832
842
  grants: string[];
833
843
  /**
834
- * When true, every customer in the project inherits this role with no
835
- * per-customer assignment. An app's baseline customer grant should be a
844
+ * When true, every user in the project inherits this role with no
845
+ * per-user assignment. An app's baseline user grant should be a
836
846
  * single `isDefault: true` role. Defaults to false.
837
847
  */
838
848
  isDefault?: boolean;
@@ -843,7 +853,7 @@ interface ApplyConfigCustomerRoleInput {
843
853
  *
844
854
  * EXPLICIT, BECAUSE SILENCE IS THE WRONG DEFAULT HERE. An optional source left
845
855
  * out of the config could be a decision or an oversight, and the two have
846
- * opposite consequences: one is an operator who does not want their customers
856
+ * opposite consequences: one is an operator who does not want their users
847
857
  * synced, the other is an operator who thinks they are and is wrong. So an
848
858
  * optional source that is neither mapped nor declined is refused at push, with
849
859
  * both spellings named. Nothing is submitted for a declined one, so the platform
@@ -852,7 +862,7 @@ interface ApplyConfigCustomerRoleInput {
852
862
  *
853
863
  * sources: {
854
864
  * product: { toModel: 'product', naturalKey: 'shopifyId', fields: { … } },
855
- * customer: false, // this project does not sync customers
865
+ * user: false, // this project does not sync users
856
866
  * }
857
867
  */
858
868
  type AppMappingDeclined = false;
@@ -900,15 +910,15 @@ interface AppInput {
900
910
  /** Opaque settings forwarded to the app's middleware. */
901
911
  settings?: Record<string, unknown>;
902
912
  /**
903
- * The customer sign-in this install pairs with the app, for an app whose own
904
- * system has customers: the key of one of the project's OAuth or OIDC
905
- * customer sign-ins, declared under `authProviders`. Every identity the app
913
+ * The user sign-in this install pairs with the app, for an app whose own
914
+ * system has users: the key of one of the project's OAuth or OIDC
915
+ * user sign-ins, declared under `authProviders`. Every identity the app
906
916
  * names is resolved through it.
907
917
  *
908
918
  * `false` pairs none. Leave it out to leave the install's pairing alone: a
909
919
  * push never removes a pairing it was not told about.
910
920
  */
911
- customerSignIn?: string | false;
921
+ userSignIn?: string | false;
912
922
  mappings?: {
913
923
  /** `false` declines an OPTIONAL source. See AppMappingDeclined. */
914
924
  sources?: Record<string, AppSourceMappingInput | AppMappingDeclined>;
@@ -924,32 +934,32 @@ interface AppInput {
924
934
  * the column, `undefined` leaves it untouched.
925
935
  */
926
936
  interface ApplyConfigProjectSettingsInput {
927
- /** Display name in customer-facing emails / portal headers. */
937
+ /** Display name in the project's own emails and portal headers. */
928
938
  displayName?: string;
929
- /** Public URL of the project logo (rendered in customer emails). */
939
+ /** Public URL of the project logo (rendered in user emails). */
930
940
  logoUrl?: string;
931
- /** Hex color used as accent in customer-facing emails. */
941
+ /** Hex color used as accent in the project's own emails. */
932
942
  primaryColor?: string;
933
- /** "From" name on outbound customer emails. */
943
+ /** "From" name on outbound user emails. */
934
944
  fromName?: string;
935
- /** "Reply-To" address on outbound customer emails. */
945
+ /** "Reply-To" address on outbound user emails. */
936
946
  replyTo?: string;
937
947
  /** Support email surfaced in email footers. */
938
948
  supportEmail?: string;
939
949
  /**
940
950
  * Public base URL of the consumer-facing app (storefront, portal,
941
- * internal tool, …). Reset / verify / invitation links in customer
951
+ * internal tool, …). Reset / verify / invitation links in user
942
952
  * emails are built from this — required before the platform will mint
943
- * customer-email links.
953
+ * user-email links.
944
954
  */
945
955
  appBaseUrl?: string;
946
956
  /**
947
- * Whether the platform sends a welcome email on customer registration.
957
+ * Whether the platform sends a welcome email on user registration.
948
958
  * Default true. Disable for invite-style flows.
949
959
  */
950
- customerWelcomeEmailEnabled?: boolean;
960
+ welcomeEmailEnabled?: boolean;
951
961
  /**
952
- * Self-serve customer signup mode. Default `public`. `restricted` accepts only
962
+ * Self-serve user signup mode. Default `public`. `restricted` accepts only
953
963
  * invited emails, `waitlist` queues signups for approval, `closed` disables
954
964
  * self-serve signup entirely.
955
965
  */
@@ -964,28 +974,28 @@ interface ApplyConfigProjectSettingsInput {
964
974
  */
965
975
  signupRestrictions?: SignupRestrictionsInput;
966
976
  /**
967
- * Whether email/password customer login is exposed. Default true. Disable
977
+ * Whether email/password sign-in is exposed. Default true. Disable
968
978
  * for a passwordless project (one-time codes or single sign-on only).
969
979
  */
970
- customerPasswordEnabled?: boolean;
980
+ passwordEnabled?: boolean;
971
981
  /**
972
- * Whether email one-time-code customer login is exposed. Default false.
982
+ * Whether email one-time-code sign-in is exposed. Default false.
973
983
  */
974
- customerOtpEnabled?: boolean;
984
+ otpEnabled?: boolean;
975
985
  /**
976
- * Whether a signed-in customer may register an organization of their own
977
- * through `registerOperatorOrganization`. Default false. Needs
978
- * `operatorSignupRole` to name the role the founder is given, or the
986
+ * Whether a signed-in user may register an organization of their own
987
+ * through `registerOrganization`. Default false. Needs
988
+ * `organizationSignupRole` to name the role the founder is given, or the
979
989
  * platform refuses every registration.
980
990
  */
981
- operatorSignupEnabled?: boolean;
991
+ organizationSignupEnabled?: boolean;
982
992
  /**
983
- * The key of the customer role a self-registered organization's founder
993
+ * The key of the role a self-registered organization's founder
984
994
  * holds in it (a role of this project, e.g. `'operator'`). No default.
985
995
  */
986
- operatorSignupRole?: string;
996
+ organizationSignupRole?: string;
987
997
  /**
988
- * The customer roles an organization's own staffer may hand out, by key.
998
+ * The roles an organization's own staffer may hand out, by key.
989
999
  *
990
1000
  * THE CEILING ON WHAT AN ORGANIZATION CAN BECOME, set by the party that is
991
1001
  * not inside it. An organization's staffer may add a member with a role only
@@ -998,7 +1008,7 @@ interface ApplyConfigProjectSettingsInput {
998
1008
  * take the capability away from every organization in the project. A bare
999
1009
  * "send nothing to clear" could not tell the last two apart.
1000
1010
  *
1001
- * Every key must name a live customer role of this project. The platform
1011
+ * Every key must name a live role of this project. The platform
1002
1012
  * refuses the whole list rather than dropping an entry it cannot resolve,
1003
1013
  * because a list that quietly lost one is a capability an operator believes
1004
1014
  * they granted and did not.
@@ -1081,8 +1091,8 @@ interface ApplyConfigDesignTokensInput {
1081
1091
  *
1082
1092
  * Organisation POLICY is manifest-shaped and belongs here: whether self-serve
1083
1093
  * sign-up is on, which role a founder is given, which roles an organisation may
1084
- * assign. Organisation INSTANCES are administrative state, like a customer or a
1085
- * credential's last use — created by an operator, by a customer signing up, or
1094
+ * assign. Organisation INSTANCES are administrative state, like a user or a
1095
+ * credential's last use — created by an operator, by a user signing up, or
1086
1096
  * by a provisioning call, and suspended or deleted by deliberate acts with
1087
1097
  * their own confirmations and their own audit trail.
1088
1098
  *
@@ -1090,7 +1100,7 @@ interface ApplyConfigDesignTokensInput {
1090
1100
  * rule: a family a manifest OMITS is a family whose resources this config owns
1091
1101
  * and no longer wants. Apply that to organisations and a founder who pushed a
1092
1102
  * config without an organisations block would lose a live tenant — every row,
1093
- * every customer, every credential — because a file did not mention it.
1103
+ * every user, every credential — because a file did not mention it.
1094
1104
  */
1095
1105
  interface ApplyConfigInput {
1096
1106
  key: string;
@@ -1134,16 +1144,16 @@ interface ApplyConfigInput {
1134
1144
  schedules?: ApplyConfigScheduleInput[];
1135
1145
  hooks?: ApplyConfigHookInput[];
1136
1146
  authProviders?: ApplyConfigAuthProviderInput[];
1137
- relyingParties?: ApplyConfigRelyingPartyInput[];
1147
+ authClients?: ApplyConfigAuthClientInput[];
1138
1148
  placements?: ApplyConfigPlacementInput[];
1139
1149
  apiKeys?: ApplyConfigApiKeyInput[];
1140
1150
  /**
1141
- * Customer RBAC roles, reconciled by `foir push`. Declare an
1142
- * `isDefault: true` role to grant every customer the write/execute scopes
1143
- * their tokens need — without one, customers get read-only
1151
+ * User RBAC roles, reconciled by `foir push`. Declare an
1152
+ * `isDefault: true` role to grant every user the write/execute scopes
1153
+ * their tokens need — without one, users get read-only
1144
1154
  * tokens after the Model B auth change.
1145
1155
  */
1146
- customerRoles?: ApplyConfigCustomerRoleInput[];
1156
+ userRoles?: ApplyConfigUserRoleInput[];
1147
1157
  /** Per-project app declarations, keyed by app name. */
1148
1158
  apps?: Record<string, AppInput>;
1149
1159
  /**
@@ -1274,8 +1284,8 @@ declare function defineVariantCatalogEntry(entry: ApplyConfigVariantCatalogEntry
1274
1284
  declare function defineSchedule(schedule: ApplyConfigScheduleInput): ApplyConfigScheduleInput;
1275
1285
  /** Define an auth provider. */
1276
1286
  declare function defineAuthProvider(provider: ApplyConfigAuthProviderInput): ApplyConfigAuthProviderInput;
1277
- /** Define a Login-with-Foir relying party (storefront / external app). */
1278
- declare function defineRelyingParty(client: ApplyConfigRelyingPartyInput): ApplyConfigRelyingPartyInput;
1287
+ /** Define a Login-with-Foir auth client (storefront / external app). */
1288
+ declare function defineAuthClient(client: ApplyConfigAuthClientInput): ApplyConfigAuthClientInput;
1279
1289
  /** Define a lifecycle hook. */
1280
1290
  declare function defineHook(hook: ApplyConfigHookInput): ApplyConfigHookInput;
1281
1291
  /** Define an editor placement (sidebar or main-editor tab). */
@@ -1314,4 +1324,4 @@ interface FoirSecretsConfig {
1314
1324
  */
1315
1325
  declare function defineSecrets(config: FoirSecretsConfig): FoirSecretsConfig;
1316
1326
 
1317
- export { type AccessInput, type AppInput, type AppMappingDeclined, type AppPlacementFieldChoiceInput, type AppSinkMappingInput, type AppSourceMappingInput, type ApplyConfigApiKeyInput, type ApplyConfigAuthProviderInput, type ApplyConfigContextDimensionInput, type ApplyConfigCustomerRoleInput, type ApplyConfigDesignTokensInput, type ApplyConfigEmailCopyInput, type ApplyConfigHookInput, type ApplyConfigInput, type ApplyConfigLocaleInput, type ApplyConfigModelInput, type ApplyConfigOperationInput, type ApplyConfigPlacementInput, type ApplyConfigProjectEmailInput, type ApplyConfigProjectInput, type ApplyConfigProjectSettingsInput, type ApplyConfigRelyingPartyInput, type ApplyConfigRelyingPartyLoginMethods, type ApplyConfigScheduleInput, type ApplyConfigVariantCatalogEntryInput, type DestinationValue, type DestinationValues, type EnumFieldConfig, type EnumFieldDefinitionInput, type EnumFieldOption, type FieldAccessInput, type FieldDefinitionInput, type FieldPlacement, type FieldRelationshipInput, type FoirProjectsConfig, type FoirSecretsConfig, type LookupDefinitionInput, type NamedProjectInput, type NamedProjectManifest, type QuotaRule, type ReferenceFieldConfig, type ReferenceFieldDefinitionInput, type SecretDeclaration, type SecretOwnerKind, type SelectFieldConfig, type SelectFieldDefinitionInput, type SelectedNamedProject, type SignupModeName, type SignupRestrictionsInput, defineAuthProvider, defineConfig, defineContextDimension, defineDesignTokens, defineEmailCopy, defineEnumField, defineField, defineHook, defineLocale, defineModel, defineOperation, definePlacement, defineRelyingParty, defineSchedule, defineSecrets, defineSelectField, defineVariantCatalogEntry };
1327
+ export { type AccessInput, type AppInput, type AppMappingDeclined, type AppPlacementFieldChoiceInput, type AppSinkMappingInput, type AppSourceMappingInput, type ApplyConfigApiKeyInput, type ApplyConfigAuthClientInput, type ApplyConfigAuthClientLoginMethods, type ApplyConfigAuthProviderInput, type ApplyConfigContextDimensionInput, type ApplyConfigDesignTokensInput, type ApplyConfigEmailCopyInput, type ApplyConfigHookInput, type ApplyConfigInput, type ApplyConfigLocaleInput, type ApplyConfigModelInput, type ApplyConfigOperationInput, type ApplyConfigPlacementInput, type ApplyConfigProjectEmailInput, type ApplyConfigProjectInput, type ApplyConfigProjectSettingsInput, type ApplyConfigScheduleInput, type ApplyConfigUserRoleInput, type ApplyConfigVariantCatalogEntryInput, type DestinationValue, type DestinationValues, type EnumFieldConfig, type EnumFieldDefinitionInput, type EnumFieldOption, type FieldDefinitionInput, type FieldGuardInput, type FieldPlacement, type FieldRelationshipInput, type FoirProjectsConfig, type FoirSecretsConfig, type LookupDefinitionInput, type NamedProjectInput, type NamedProjectManifest, type QuotaRule, type ReferenceFieldConfig, type ReferenceFieldDefinitionInput, type SecretDeclaration, type SecretOwnerKind, type SelectFieldConfig, type SelectFieldDefinitionInput, type SelectedNamedProject, type SignupModeName, type SignupRestrictionsInput, defineAuthClient, defineAuthProvider, defineConfig, defineContextDimension, defineDesignTokens, defineEmailCopy, defineEnumField, defineField, defineHook, defineLocale, defineModel, defineOperation, definePlacement, defineSchedule, defineSecrets, defineSelectField, defineVariantCatalogEntry };
@@ -38,7 +38,7 @@ function defineSchedule(schedule) {
38
38
  function defineAuthProvider(provider) {
39
39
  return provider;
40
40
  }
41
- function defineRelyingParty(client) {
41
+ function defineAuthClient(client) {
42
42
  return client;
43
43
  }
44
44
  function defineHook(hook) {
@@ -51,6 +51,7 @@ function defineSecrets(config) {
51
51
  return config;
52
52
  }
53
53
  export {
54
+ defineAuthClient,
54
55
  defineAuthProvider,
55
56
  defineConfig,
56
57
  defineContextDimension,
@@ -63,7 +64,6 @@ export {
63
64
  defineModel,
64
65
  defineOperation,
65
66
  definePlacement,
66
- defineRelyingParty,
67
67
  defineSchedule,
68
68
  defineSecrets,
69
69
  defineSelectField,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@foir/cli",
3
- "version": "0.78.0",
3
+ "version": "0.79.0",
4
4
  "description": "Universal platform CLI for Foir platform",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -63,10 +63,10 @@
63
63
  "vitest": "^3.2.4",
64
64
  "@foir/access-vocab": "0.0.0",
65
65
  "@foir/assistant": "0.0.0",
66
+ "@foir/console-routes": "0.0.0",
66
67
  "@foir/proto-ts": "0.109.0",
67
68
  "@foir/rpc-node": "0.0.0",
68
- "@foir/sdk": "0.21.0",
69
- "@foir/console-routes": "0.0.0"
69
+ "@foir/sdk": "0.23.0"
70
70
  },
71
71
  "engines": {
72
72
  "node": ">=18.0.0"