@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.
- package/dist/cli.js +1604 -1196
- package/dist/lib/config-helpers.d.ts +128 -118
- package/dist/lib/config-helpers.js +2 -2
- package/package.json +3 -3
|
@@ -56,15 +56,16 @@ interface EnumFieldConfig {
|
|
|
56
56
|
placement?: FieldPlacement;
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
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
|
|
66
|
-
read?:
|
|
67
|
-
write?:
|
|
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
|
-
|
|
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
|
-
* - `'
|
|
188
|
-
*
|
|
189
|
-
*
|
|
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
|
|
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: '
|
|
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
|
-
*
|
|
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
|
|
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 (
|
|
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
|
-
/**
|
|
254
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
369
|
-
* (read one
|
|
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
|
|
372
|
-
* operation acting for a
|
|
373
|
-
* at an organisation reaches only its
|
|
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
|
|
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' (
|
|
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
|
-
*
|
|
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.
|
|
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
|
|
567
|
-
*
|
|
568
|
-
*
|
|
569
|
-
*
|
|
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-
|
|
573
|
-
* `
|
|
574
|
+
* push context), so consumers only declare the per-client fields. Pass to
|
|
575
|
+
* `authClients` on the manifest.
|
|
574
576
|
*/
|
|
575
577
|
/**
|
|
576
|
-
* Per-
|
|
577
|
-
* §Per-
|
|
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
|
|
584
|
+
interface ApplyConfigAuthClientLoginMethods {
|
|
583
585
|
/**
|
|
584
|
-
* Show email & password sign-in on this
|
|
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 (`
|
|
588
|
+
* project (`passwordEnabled`) has turned off.
|
|
587
589
|
*/
|
|
588
590
|
password?: boolean;
|
|
589
591
|
/**
|
|
590
|
-
* Show one-time code sign-in on this
|
|
591
|
-
* Only narrows the project capability (`
|
|
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
|
|
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
|
|
599
|
+
* "google") to omit it from this auth client only.
|
|
598
600
|
*/
|
|
599
601
|
disabledProviders?: string[];
|
|
600
602
|
}
|
|
601
|
-
interface
|
|
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
|
|
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
|
-
*
|
|
643
|
-
*
|
|
644
|
-
*
|
|
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
|
-
|
|
644
|
+
firstParty?: boolean;
|
|
647
645
|
/**
|
|
648
|
-
*
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
794
|
-
* The role's `grants` are what a
|
|
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
|
|
801
|
-
* everyone who comes through it (its `baselineGrants`). Anything a
|
|
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
|
|
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
|
|
819
|
+
/** Human-readable name (e.g. "Default User"). */
|
|
808
820
|
name: string;
|
|
809
821
|
/**
|
|
810
|
-
* What the role gives
|
|
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
|
-
*
|
|
820
|
-
* read
|
|
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
|
|
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
|
|
835
|
-
* per-
|
|
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
|
|
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
|
-
*
|
|
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
|
|
904
|
-
* system has
|
|
905
|
-
*
|
|
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
|
-
|
|
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
|
|
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
|
|
939
|
+
/** Public URL of the project logo (rendered in user emails). */
|
|
930
940
|
logoUrl?: string;
|
|
931
|
-
/** Hex color used as accent in
|
|
941
|
+
/** Hex color used as accent in the project's own emails. */
|
|
932
942
|
primaryColor?: string;
|
|
933
|
-
/** "From" name on outbound
|
|
943
|
+
/** "From" name on outbound user emails. */
|
|
934
944
|
fromName?: string;
|
|
935
|
-
/** "Reply-To" address on outbound
|
|
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
|
|
951
|
+
* internal tool, …). Reset / verify / invitation links in user
|
|
942
952
|
* emails are built from this — required before the platform will mint
|
|
943
|
-
*
|
|
953
|
+
* user-email links.
|
|
944
954
|
*/
|
|
945
955
|
appBaseUrl?: string;
|
|
946
956
|
/**
|
|
947
|
-
* Whether the platform sends a welcome email on
|
|
957
|
+
* Whether the platform sends a welcome email on user registration.
|
|
948
958
|
* Default true. Disable for invite-style flows.
|
|
949
959
|
*/
|
|
950
|
-
|
|
960
|
+
welcomeEmailEnabled?: boolean;
|
|
951
961
|
/**
|
|
952
|
-
* Self-serve
|
|
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
|
|
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
|
-
|
|
980
|
+
passwordEnabled?: boolean;
|
|
971
981
|
/**
|
|
972
|
-
* Whether email one-time-code
|
|
982
|
+
* Whether email one-time-code sign-in is exposed. Default false.
|
|
973
983
|
*/
|
|
974
|
-
|
|
984
|
+
otpEnabled?: boolean;
|
|
975
985
|
/**
|
|
976
|
-
* Whether a signed-in
|
|
977
|
-
* through `
|
|
978
|
-
* `
|
|
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
|
-
|
|
991
|
+
organizationSignupEnabled?: boolean;
|
|
982
992
|
/**
|
|
983
|
-
* The key of the
|
|
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
|
-
|
|
996
|
+
organizationSignupRole?: string;
|
|
987
997
|
/**
|
|
988
|
-
* The
|
|
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
|
|
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
|
|
1085
|
-
* credential's last use — created by an operator, by a
|
|
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
|
|
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
|
-
|
|
1147
|
+
authClients?: ApplyConfigAuthClientInput[];
|
|
1138
1148
|
placements?: ApplyConfigPlacementInput[];
|
|
1139
1149
|
apiKeys?: ApplyConfigApiKeyInput[];
|
|
1140
1150
|
/**
|
|
1141
|
-
*
|
|
1142
|
-
* `isDefault: true` role to grant every
|
|
1143
|
-
* their tokens need — without one,
|
|
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
|
-
|
|
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
|
|
1278
|
-
declare function
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
69
|
-
"@foir/console-routes": "0.0.0"
|
|
69
|
+
"@foir/sdk": "0.23.0"
|
|
70
70
|
},
|
|
71
71
|
"engines": {
|
|
72
72
|
"node": ">=18.0.0"
|