@foir/cli 0.77.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
  */
@@ -704,14 +716,30 @@ interface ApplyConfigHookInput {
704
716
  interface ApplyConfigApiKeyInput {
705
717
  /** Name for this API key (e.g. "Tilly iOS", "Tilly CRM sync"). */
706
718
  name: string;
707
- /** Key type: 'public' for your app, 'secret' for a third-party client's own server. */
708
- keyType: 'public' | 'secret';
719
+ /**
720
+ * What the key is for. You choose it, and the platform holds the key to what
721
+ * that kind may hold and give:
722
+ *
723
+ * - `'publishable'` sits in a web page or an app, where anyone can read it.
724
+ * It gives a visitor only what is safe to give everyone.
725
+ * - `'server'` is held by the server that renders your pages. It is a
726
+ * publishable key that may also say who and where its visitor is
727
+ * (`visitors:forward`), and it never goes to a browser.
728
+ * - `'admin'` is a machine's own: a sync job, a pipeline, a tool. It does
729
+ * what it holds, gives nobody anything, and nobody signs in through it.
730
+ * It expires.
731
+ *
732
+ * A key's kind never changes. A config that declares another kind for a key
733
+ * that already exists is refused: declare a new key under a new name.
734
+ */
735
+ kind: 'publishable' | 'server' | 'admin';
709
736
  /** Environment variable name to write the key to in .env (e.g. "FOIR_PUBLIC_KEY"). */
710
737
  envVar: string;
711
738
  /**
712
- * What the key holds: the most anyone may do through it, in the permission
713
- * catalogue's names (e.g. ["records:read", "records:write"]). A secret key
714
- * may hold ["*"].
739
+ * What the key holds, in the permission catalogue's names (e.g.
740
+ * ["records:read", "records:write"]): for a publishable or a server key the
741
+ * most a signed-in user may do through it, and for an admin key what it
742
+ * does. An admin key may hold ["*"].
715
743
  *
716
744
  * Declared for every key. Nothing is filled in, so a key declared without
717
745
  * it would be minted holding nothing, and a push refuses one.
@@ -721,13 +749,14 @@ interface ApplyConfigApiKeyInput {
721
749
  */
722
750
  grants: string[];
723
751
  /**
724
- * What the key gives whoever comes through it, in the same names: a visitor
725
- * with no sign-in, on a public key, and a signed-in user beneath their role,
726
- * on either kind.
752
+ * What a publishable or a server key gives whoever comes through it, in the
753
+ * same names: a visitor with no sign-in, and a signed-in user beneath their
754
+ * role. An admin key gives nobody anything, and one declared with this list
755
+ * is refused.
727
756
  *
728
757
  * NOTHING IS FILLED IN. A key declared without this list gives a visitor
729
- * nothing, whatever it holds: a public key holding `records:read` and no
730
- * list here is a key no visitor can read with. Name each read a visitor
758
+ * nothing, whatever it holds: a publishable key holding `records:read` and
759
+ * no list here is a key no visitor can read with. Name each read a visitor
731
760
  * needs. A visitor may also be given one model to submit into
732
761
  * (`records:create:<model>`) and one operation to run
733
762
  * (`operations:execute:<operation>`), each naming something this config
@@ -737,6 +766,17 @@ interface ApplyConfigApiKeyInput {
737
766
  * place. Left out, a push leaves what the key gives as it is.
738
767
  */
739
768
  baselineGrants?: string[];
769
+ /**
770
+ * An admin key only: how long it lives from the push that makes it, in days
771
+ * (e.g. "90d", which is what it is given when nothing is said, up to
772
+ * "365d"). A publishable or a server key never expires, and one declared
773
+ * with this is refused.
774
+ *
775
+ * It is read when the key is made. A push never renews a key that exists:
776
+ * renew it with `foir api-keys renew`, so that a key is kept alive by
777
+ * somebody deciding to and not by a pipeline that happens to run.
778
+ */
779
+ expiresIn?: string;
740
780
  /** Restrict the key to specific model keys (e.g. ["tilly_note", "tilly_block"]). */
741
781
  allowedModels?: string[];
742
782
  /** Restrict file uploads: a MIME type ("image/png"), a whole type ("image/*"), or IMAGE, VIDEO, FILE. */
@@ -762,24 +802,24 @@ interface ApplyConfigApiKeyInput {
762
802
  org?: string;
763
803
  }
764
804
  /**
765
- * A customer role declared in foir.config.ts and reconciled by `foir push`.
766
- * 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:
767
807
  * their access token carries them. Roles are matched by `key` within the
768
808
  * project: a declared key that already exists is updated in place, and a new
769
809
  * key is created. A role on the platform that the config leaves out is left
770
810
  * as it is, never disabled.
771
811
  *
772
- * Without a role, a signed-in customer may do only what the key gives
773
- * 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
774
814
  * may do beyond that comes from a role they hold.
775
815
  */
776
- interface ApplyConfigCustomerRoleInput {
816
+ interface ApplyConfigUserRoleInput {
777
817
  /** Stable key, unique per project (e.g. "default", "member"). */
778
818
  key: string;
779
- /** Human-readable name (e.g. "Default Customer"). */
819
+ /** Human-readable name (e.g. "Default User"). */
780
820
  name: string;
781
821
  /**
782
- * 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
783
823
  * catalogue's names: records:read:<model>, records:write:<model>,
784
824
  * records:create:<model>, operations:execute, files:read and the rest of
785
825
  * the list at https://docs.foir.dev/api/role-permissions.
@@ -788,14 +828,12 @@ interface ApplyConfigCustomerRoleInput {
788
828
  * grants, so a role that should do both lists `records:write:<model>` and
789
829
  * `records:create:<model>`.
790
830
  *
791
- * The `self:*` shorthand is worked out when a customer signs in, into the
792
- * read, the write and the create of every model the project lets a customer
793
- * write. It does NOT include operations:execute, so list that explicitly
794
- * 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>`.
795
833
  *
796
834
  * `operations:execute` runs every operation the key exposes;
797
835
  * `operations:execute:<operation_key>` runs that one alone, so a role can
798
- * 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
799
837
  * role gives it. A push naming an operation the project does not have is
800
838
  * refused, by name.
801
839
  *
@@ -803,8 +841,8 @@ interface ApplyConfigCustomerRoleInput {
803
841
  */
804
842
  grants: string[];
805
843
  /**
806
- * When true, every customer in the project inherits this role with no
807
- * 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
808
846
  * single `isDefault: true` role. Defaults to false.
809
847
  */
810
848
  isDefault?: boolean;
@@ -815,7 +853,7 @@ interface ApplyConfigCustomerRoleInput {
815
853
  *
816
854
  * EXPLICIT, BECAUSE SILENCE IS THE WRONG DEFAULT HERE. An optional source left
817
855
  * out of the config could be a decision or an oversight, and the two have
818
- * 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
819
857
  * synced, the other is an operator who thinks they are and is wrong. So an
820
858
  * optional source that is neither mapped nor declined is refused at push, with
821
859
  * both spellings named. Nothing is submitted for a declined one, so the platform
@@ -824,7 +862,7 @@ interface ApplyConfigCustomerRoleInput {
824
862
  *
825
863
  * sources: {
826
864
  * product: { toModel: 'product', naturalKey: 'shopifyId', fields: { … } },
827
- * customer: false, // this project does not sync customers
865
+ * user: false, // this project does not sync users
828
866
  * }
829
867
  */
830
868
  type AppMappingDeclined = false;
@@ -872,15 +910,15 @@ interface AppInput {
872
910
  /** Opaque settings forwarded to the app's middleware. */
873
911
  settings?: Record<string, unknown>;
874
912
  /**
875
- * The customer sign-in this install pairs with the app, for an app whose own
876
- * system has customers: the key of one of the project's OAuth or OIDC
877
- * 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
878
916
  * names is resolved through it.
879
917
  *
880
918
  * `false` pairs none. Leave it out to leave the install's pairing alone: a
881
919
  * push never removes a pairing it was not told about.
882
920
  */
883
- customerSignIn?: string | false;
921
+ userSignIn?: string | false;
884
922
  mappings?: {
885
923
  /** `false` declines an OPTIONAL source. See AppMappingDeclined. */
886
924
  sources?: Record<string, AppSourceMappingInput | AppMappingDeclined>;
@@ -896,32 +934,32 @@ interface AppInput {
896
934
  * the column, `undefined` leaves it untouched.
897
935
  */
898
936
  interface ApplyConfigProjectSettingsInput {
899
- /** Display name in customer-facing emails / portal headers. */
937
+ /** Display name in the project's own emails and portal headers. */
900
938
  displayName?: string;
901
- /** Public URL of the project logo (rendered in customer emails). */
939
+ /** Public URL of the project logo (rendered in user emails). */
902
940
  logoUrl?: string;
903
- /** Hex color used as accent in customer-facing emails. */
941
+ /** Hex color used as accent in the project's own emails. */
904
942
  primaryColor?: string;
905
- /** "From" name on outbound customer emails. */
943
+ /** "From" name on outbound user emails. */
906
944
  fromName?: string;
907
- /** "Reply-To" address on outbound customer emails. */
945
+ /** "Reply-To" address on outbound user emails. */
908
946
  replyTo?: string;
909
947
  /** Support email surfaced in email footers. */
910
948
  supportEmail?: string;
911
949
  /**
912
950
  * Public base URL of the consumer-facing app (storefront, portal,
913
- * internal tool, …). Reset / verify / invitation links in customer
951
+ * internal tool, …). Reset / verify / invitation links in user
914
952
  * emails are built from this — required before the platform will mint
915
- * customer-email links.
953
+ * user-email links.
916
954
  */
917
955
  appBaseUrl?: string;
918
956
  /**
919
- * Whether the platform sends a welcome email on customer registration.
957
+ * Whether the platform sends a welcome email on user registration.
920
958
  * Default true. Disable for invite-style flows.
921
959
  */
922
- customerWelcomeEmailEnabled?: boolean;
960
+ welcomeEmailEnabled?: boolean;
923
961
  /**
924
- * Self-serve customer signup mode. Default `public`. `restricted` accepts only
962
+ * Self-serve user signup mode. Default `public`. `restricted` accepts only
925
963
  * invited emails, `waitlist` queues signups for approval, `closed` disables
926
964
  * self-serve signup entirely.
927
965
  */
@@ -936,28 +974,28 @@ interface ApplyConfigProjectSettingsInput {
936
974
  */
937
975
  signupRestrictions?: SignupRestrictionsInput;
938
976
  /**
939
- * Whether email/password customer login is exposed. Default true. Disable
977
+ * Whether email/password sign-in is exposed. Default true. Disable
940
978
  * for a passwordless project (one-time codes or single sign-on only).
941
979
  */
942
- customerPasswordEnabled?: boolean;
980
+ passwordEnabled?: boolean;
943
981
  /**
944
- * Whether email one-time-code customer login is exposed. Default false.
982
+ * Whether email one-time-code sign-in is exposed. Default false.
945
983
  */
946
- customerOtpEnabled?: boolean;
984
+ otpEnabled?: boolean;
947
985
  /**
948
- * Whether a signed-in customer may register an organization of their own
949
- * through `registerOperatorOrganization`. Default false. Needs
950
- * `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
951
989
  * platform refuses every registration.
952
990
  */
953
- operatorSignupEnabled?: boolean;
991
+ organizationSignupEnabled?: boolean;
954
992
  /**
955
- * The key of the customer role a self-registered organization's founder
993
+ * The key of the role a self-registered organization's founder
956
994
  * holds in it (a role of this project, e.g. `'operator'`). No default.
957
995
  */
958
- operatorSignupRole?: string;
996
+ organizationSignupRole?: string;
959
997
  /**
960
- * 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.
961
999
  *
962
1000
  * THE CEILING ON WHAT AN ORGANIZATION CAN BECOME, set by the party that is
963
1001
  * not inside it. An organization's staffer may add a member with a role only
@@ -970,7 +1008,7 @@ interface ApplyConfigProjectSettingsInput {
970
1008
  * take the capability away from every organization in the project. A bare
971
1009
  * "send nothing to clear" could not tell the last two apart.
972
1010
  *
973
- * 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
974
1012
  * refuses the whole list rather than dropping an entry it cannot resolve,
975
1013
  * because a list that quietly lost one is a capability an operator believes
976
1014
  * they granted and did not.
@@ -1053,8 +1091,8 @@ interface ApplyConfigDesignTokensInput {
1053
1091
  *
1054
1092
  * Organisation POLICY is manifest-shaped and belongs here: whether self-serve
1055
1093
  * sign-up is on, which role a founder is given, which roles an organisation may
1056
- * assign. Organisation INSTANCES are administrative state, like a customer or a
1057
- * 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
1058
1096
  * by a provisioning call, and suspended or deleted by deliberate acts with
1059
1097
  * their own confirmations and their own audit trail.
1060
1098
  *
@@ -1062,7 +1100,7 @@ interface ApplyConfigDesignTokensInput {
1062
1100
  * rule: a family a manifest OMITS is a family whose resources this config owns
1063
1101
  * and no longer wants. Apply that to organisations and a founder who pushed a
1064
1102
  * config without an organisations block would lose a live tenant — every row,
1065
- * every customer, every credential — because a file did not mention it.
1103
+ * every user, every credential — because a file did not mention it.
1066
1104
  */
1067
1105
  interface ApplyConfigInput {
1068
1106
  key: string;
@@ -1106,16 +1144,16 @@ interface ApplyConfigInput {
1106
1144
  schedules?: ApplyConfigScheduleInput[];
1107
1145
  hooks?: ApplyConfigHookInput[];
1108
1146
  authProviders?: ApplyConfigAuthProviderInput[];
1109
- relyingParties?: ApplyConfigRelyingPartyInput[];
1147
+ authClients?: ApplyConfigAuthClientInput[];
1110
1148
  placements?: ApplyConfigPlacementInput[];
1111
1149
  apiKeys?: ApplyConfigApiKeyInput[];
1112
1150
  /**
1113
- * Customer RBAC roles, reconciled by `foir push`. Declare an
1114
- * `isDefault: true` role to grant every customer the write/execute scopes
1115
- * 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
1116
1154
  * tokens after the Model B auth change.
1117
1155
  */
1118
- customerRoles?: ApplyConfigCustomerRoleInput[];
1156
+ userRoles?: ApplyConfigUserRoleInput[];
1119
1157
  /** Per-project app declarations, keyed by app name. */
1120
1158
  apps?: Record<string, AppInput>;
1121
1159
  /**
@@ -1246,8 +1284,8 @@ declare function defineVariantCatalogEntry(entry: ApplyConfigVariantCatalogEntry
1246
1284
  declare function defineSchedule(schedule: ApplyConfigScheduleInput): ApplyConfigScheduleInput;
1247
1285
  /** Define an auth provider. */
1248
1286
  declare function defineAuthProvider(provider: ApplyConfigAuthProviderInput): ApplyConfigAuthProviderInput;
1249
- /** Define a Login-with-Foir relying party (storefront / external app). */
1250
- declare function defineRelyingParty(client: ApplyConfigRelyingPartyInput): ApplyConfigRelyingPartyInput;
1287
+ /** Define a Login-with-Foir auth client (storefront / external app). */
1288
+ declare function defineAuthClient(client: ApplyConfigAuthClientInput): ApplyConfigAuthClientInput;
1251
1289
  /** Define a lifecycle hook. */
1252
1290
  declare function defineHook(hook: ApplyConfigHookInput): ApplyConfigHookInput;
1253
1291
  /** Define an editor placement (sidebar or main-editor tab). */
@@ -1286,4 +1324,4 @@ interface FoirSecretsConfig {
1286
1324
  */
1287
1325
  declare function defineSecrets(config: FoirSecretsConfig): FoirSecretsConfig;
1288
1326
 
1289
- 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,