@foir/sdk 0.23.0 → 0.24.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/CHANGELOG.md CHANGED
@@ -108,6 +108,33 @@ nobody asking for `@foir/sdk` gets it early. The push that carries the commit to
108
108
 
109
109
  Changes on `dev` that have not been published to npm.
110
110
 
111
+ ## [0.24.0] — 2026-10-18
112
+
113
+ ### Changed
114
+
115
+ - **`joinWaitlist` resolves `true` for every address** (`@foir/sdk/auth`). It
116
+ used to resolve the waitlist entry, whose status told anyone who asked
117
+ whether an address had been approved. The server now answers every address
118
+ alike, whether it was queued, was already let in, or already has an account,
119
+ and what differs is only the email the address is sent. Migration: stop
120
+ reading `id`, `email` or `status` from the result; a resolved call means the
121
+ address was not refused.
122
+ - **`myProviderToken` and `logout` act for one sign-in** (`@foir/sdk/auth`). A
123
+ provider's token belongs to the sign-in that obtained it, so `logout` ends
124
+ this device's and no other device's, and a sign-in with nothing kept for it
125
+ resolves `linked: false` with `reauthenticate: true`. Migration: where
126
+ `reauthenticate` is true, show the user the way to sign in through the
127
+ provider again rather than an empty or failed page.
128
+
129
+ ### Removed
130
+
131
+ - **`WaitlistJoinResult`** (`@foir/sdk/auth`, type). `joinWaitlist` resolves a
132
+ boolean.
133
+ - **`verifyEmail`** (`@foir/sdk/auth`). It redeemed verification tokens that
134
+ only the console's own sign-up minted, and that lane is gone. An address is
135
+ proven by the code it is sent: `requestOTP`, then `loginWithOTP`, which marks
136
+ the address proven and lets in a person who was waiting to prove it.
137
+
111
138
  ## [0.23.0] — 2026-10-16
112
139
 
113
140
  ### Added
@@ -186,23 +213,23 @@ Changes on `dev` that have not been published to npm.
186
213
 
187
214
  ### Changed
188
215
 
189
- - **Breaking: everyone who signs in is a user, and nothing says customer or
190
- admin as a kind.** It needs the platform release that serves the same
216
+ - **Breaking: everyone who signs in is a user, and no name says what kind
217
+ of person somebody is.** It needs the platform release that serves the same
191
218
  names; an earlier platform refuses every call below by name.
192
219
  - `@foir/sdk/auth`: the raw calls take the server's op names: `login`,
193
220
  `register`, `requestOTP`, `loginWithOTP`, `refreshTokens` (the
194
221
  `refreshToken` op), `logout`, `joinWaitlist`, `signupContext`,
195
222
  `requestPasswordReset`, `resetPassword`, `updatePassword`, `verifyEmail`,
196
- `loginWithProvider`, `providerCallback`, `providerVerifyOTP` (were
197
- `customerLogin` and the rest), and `registerOrganization` founds an
198
- organization over the `registerOrganization` op (was
199
- `registerOperatorOrganization`). The helpers that save a session are
223
+ `loginWithProvider`, `providerCallback`, `providerVerifyOTP`, each
224
+ renamed from a name that said what kind of person called it, and
225
+ `registerOrganization` founds an organization over the
226
+ `registerOrganization` op. The helpers that save a session are
200
227
  `signInWithPassword`, `signUpWithPassword` and `signInWithOTP` (were
201
228
  `loginWithPassword`, `registerWithPassword`, `loginWithOTP`), beside
202
- `signOut`. `getSessionCustomer` is `getSessionUser`, `customerAccess` is
203
- `userAccess`, `CustomerAuthResult` is `AuthResult` and carries `userId`,
204
- `FoirCustomer` is `FoirUser` (`{ id, email }`), and `FoirAccess.customerId`
205
- is `userId`. A session is stored under `foir:userId`, so one saved by an
229
+ `signOut`. The session, access and result helpers are `getSessionUser`,
230
+ `userAccess` and `AuthResult` (which carries `userId`), the signed-in
231
+ person is `FoirUser` (`{ id, email }`), and `FoirAccess` names them as
232
+ `userId`. A session is stored under `foir:userId`, so one saved by an
206
233
  earlier version reads as signed out once.
207
234
  - `@foir/sdk/auth`: a provider sign-in that names an address somebody
208
235
  already holds waits for the code sent to it: `providerSignInRefusalOf`
@@ -211,23 +238,23 @@ Changes on `dev` that have not been published to npm.
211
238
  - `@foir/sdk/auth`: the hosted session answers `userId`
212
239
  (`HostedSession.userId`, `FoirSessionUser.userId`), from the platform's
213
240
  `user_id`, and its cookie is `foir_session`.
214
- - `@foir/sdk/react`: `useFoirSession()` answers `user` (was `customer`).
215
- - `@foir/sdk/app`: `records.user` and `users` (were `records.customer` and
216
- `customers`), over the platform's `saveUserRecord`, `userRecordByIdentity`,
241
+ - `@foir/sdk/react`: `useFoirSession()` answers `user`.
242
+ - `@foir/sdk/app`: `records.user` and `users`, over the platform's
243
+ `saveUserRecord`, `userRecordByIdentity`,
217
244
  `eraseUserRecord`, `createUser`, `user`, `users`, `userByIdentity` and
218
245
  `userIdentitiesById`. `users.list()` answers `{ users }`. `AppUser`,
219
246
  `AppUserList`, `AppUserSaveResult` (`userCreated`), `AppUserEraseResult`
220
247
  (`userDeleted`, `userKeptBecause`), `AppUserEmailUnavailableReason`,
221
- `appUserUnlinkedOf` and `appUserEmailUnavailableOf` replace the
222
- `AppCustomer` names. A notification, a consent change and an
248
+ `appUserUnlinkedOf` and `appUserEmailUnavailableOf` are the app client's
249
+ names for the people it reads. A notification, a consent change and an
223
250
  organization's first member name `userId`.
224
251
  - `@foir/sdk/server`: an operation's context names who started the run as
225
- `actorId` and the user it acts for as `userId` (was `userId` and
226
- `customerId`). `ScopedTokenIngress.userId` was `customerId`.
252
+ `actorId` and the user it acts for as `userId` (`userId` used to name
253
+ who started it). `ScopedTokenIngress` names the user as `userId`.
227
254
  - `@foir/sdk/data`: `FoirGranteeKind` is `'USER'`, a note's subject may be
228
- `'user'`, `FoirUserNote` and `FoirUserNoteAttachment` replace the
229
- `FoirCustomerNote` names, and `FoirAuthDowngrade.userToken` was
230
- `customerToken`.
255
+ `'user'`, a note of a user's is `FoirUserNote` with
256
+ `FoirUserNoteAttachment`, and `FoirAuthDowngrade` names the dropped
257
+ token `userToken`.
231
258
 
232
259
  ### Removed
233
260
 
@@ -235,8 +262,9 @@ Changes on `dev` that have not been published to npm.
235
262
  (`@foir/sdk/auth`). Nothing stores where a user stands: a request names the
236
263
  organization it acts in (`orgId` or `orgUrl`), and the platform checks they
237
264
  stand there on that request. `myOrganizations` still lists where they may.
238
- - **Breaking: `requireAdmin` and `RequireAdminOptions`, and `isAdmin` on
239
- `FoirUser`** (`@foir/sdk/auth`). What a user may do is a role or a scope:
265
+ - **Breaking: the helpers that guarded on a person being of the managing
266
+ kind, and the flag on `FoirUser` that said so** (`@foir/sdk/auth`). What a
267
+ user may do is a role or a scope:
240
268
  guard on it with `requireRole` or `requireScope`. `requireAuth` takes the
241
269
  type `resolveUser` answers, for a project that reads its own profile.
242
270
 
@@ -246,7 +274,7 @@ Changes on `dev` that have not been published to npm.
246
274
 
247
275
  - **An operation provisions an organization** (`@foir/sdk/app`).
248
276
  `organizations.provision({ provisionId, name, parentId?, settings?, firstMember? })`
249
- makes an organization with a customer as its first member, in the role the
277
+ makes an organization with a user as its first member, in the role the
250
278
  project names for a founder, and answers `{ organizationId }`. It needs
251
279
  `organizations:create`. With `settings: { modelKey, data }` it writes the
252
280
  organization's settings record too and answers `settingsRecordId`; that
@@ -261,7 +289,7 @@ Changes on `dev` that have not been published to npm.
261
289
  needs the platform release that carries `scheduleOrganizationDeletion`.
262
290
  - **`FoirWriteNoteArgs`** (`@foir/sdk/data`): the arguments of
263
291
  `foir.ns.notes.writeNote`, the one field that writes a note for a signed-in
264
- customer and for a visitor. It asks `notes:create` and needs the platform
292
+ user and for a visitor. It asks `notes:create` and needs the platform
265
293
  release that carries `writeNote`. `foir.ns.notes` answers any field the
266
294
  platform serves, so the call itself needs no new SDK.
267
295
 
@@ -288,7 +316,7 @@ Changes on `dev` that have not been published to npm.
288
316
  itself uses `createServerClient` from `@foir/sdk/server`. A key minted
289
317
  before a key had a kind (`sk_`) is not refused here.
290
318
  - **A key's kind is read from its prefix in one place.** A key is publishable
291
- (`foir_pub_`), server (`foir_srv_`) or admin (`foir_adm_`), and a key minted
319
+ (`foir_pub_`), server (`foir_srv_`) or the console (`foir_adm_`), and a key minted
292
320
  earlier is `pk_`, `sk_` or `tc_`. Only a publishable key, in either format,
293
321
  is named in a URL and takes the shared cache lane. Earlier versions looked
294
322
  for the letters `pk_` alone, so a `foir_pub_` key was sent to the origin and
@@ -352,7 +380,7 @@ to this version then.
352
380
  reads it as what those were worth, exactly as the platform does.
353
381
 
354
382
  A record grant reaches the operation's own records: the project's, or those
355
- of the customer a run acts for. `records:read.all:<model>`, and the write,
383
+ of the user a run acts for. `records:read.all:<model>`, and the write,
356
384
  delete and publish forms like it, reach every owner's records of the model.
357
385
  An older token's write of a model was every owner's, so it is read as
358
386
  `records:write.all:<model>` and `records:create:<model>`, and takes that
@@ -381,19 +409,19 @@ to this version then.
381
409
  platform holds a running install's setting to a category the project has.
382
410
 
383
411
  - **An app can say what connecting changes** (`@foir/sdk/app/contract`).
384
- `Credentials.connectNotice` is the app's own words, shown to the operator
412
+ `Credentials.connectNotice` is the app's own words, shown to the user
385
413
  beside the step that connects their account and, for an install the vendor
386
414
  started, before the install is confirmed. A vendor that keeps one live
387
415
  connection per account (Shopify, per store) says here that connecting moves
388
416
  it from any other project. Empty when there is nothing to say.
389
417
 
390
- - **The roles a signed-in customer holds, and what they may do**
391
- (`@foir/sdk/auth`, `@foir/sdk/react`). A storefront can now ask which customer
392
- roles the signed-in customer holds and show the page to match, where before
418
+ - **The roles a signed-in user holds, and what they may do**
419
+ (`@foir/sdk/auth`, `@foir/sdk/react`). A storefront can now ask which user
420
+ roles the signed-in user holds and show the page to match, where before
393
421
  it had to treat one of a role's permissions as a stand-in for the role.
394
422
 
395
- - `getSessionAccess(adapter, env)` and `customerAccess(env, { bearerToken })`
396
- return a `FoirAccess`: the customer's id, the keys of the roles they hold
423
+ - `getSessionAccess(adapter, env)` and `userAccess(env, { bearerToken })`
424
+ return a `FoirAccess`: the user's id, the keys of the roles they hold
397
425
  (`roles`), and everything they may do through the key (`scopes`). Plain
398
426
  data, so a loader can return it. `null` when nobody is signed in.
399
427
  - `hasRole(access, key)` and `hasScope(access, scope)` read it. `hasScope`
@@ -412,7 +440,7 @@ to this version then.
412
440
  and a role taken away is gone the next time it is asked.
413
441
 
414
442
  `roles` is `null`, not an empty list, when the platform did not say which
415
- roles the customer holds. `hasRole` answers false for it and `requireRole`
443
+ roles the user holds. `hasRole` answers false for it and `requireRole`
416
444
  refuses with `roles_unknown`, so an outage is never read as "not staff". A
417
445
  platform that does not serve the field yet reads the same way: the role
418
446
  helpers need the platform release that carries it.
@@ -424,7 +452,7 @@ to this version then.
424
452
  `accessStatus`, `loadAccess` and `ensureAccess`.
425
453
 
426
454
  - **A save says when it made a record the operation may not read**
427
- (`@foir/sdk/app`). `records.upsert` and `records.customer.save` answer
455
+ (`@foir/sdk/app`). `records.upsert` and `records.user.save` answer
428
456
  `fieldsWithheld`. It is true when the operation declared the create of a
429
457
  model and not the read: the save made the record, and `record` carries its
430
458
  `id` and `modelKey` and nothing else. The record is not empty.
@@ -440,13 +468,13 @@ to this version then.
440
468
  app's operations are given the one they could use, so an installed app keeps
441
469
  running; a manifest served from then on says it.
442
470
 
443
- - **Breaking, with the platform release that carries it: erasing a customer
444
- takes `identities:delete`** (`@foir/sdk/app`). `records.customer.erase` needed
471
+ - **Breaking, with the platform release that carries it: erasing a user
472
+ takes `identities:delete`** (`@foir/sdk/app`). `records.user.erase` needed
445
473
  `users:create` beside the delete and the read of the model, and now needs
446
474
  `identities:delete` there. `APP_GRANTS` carries it, with `files:delete`,
447
475
  `notifications:read` and every owner's files (`files:read.all`,
448
476
  `files:write.all`, `files:delete.all`), which a manifest may now declare.
449
- `verifyScopedToken` reads a token minted before, that carried the customer
477
+ `verifyScopedToken` reads a token minted before, that carried the user
450
478
  create beside the delete of a model, as holding `identities:delete`, as the
451
479
  platform does.
452
480
 
@@ -464,17 +492,14 @@ to this version then.
464
492
  | `config:read` | `appconfig:read` |
465
493
  | `secrets:read.app`, `secrets:put.app`, `secrets:list.app`, `secrets:delete.app` | `appsecrets:read`, `appsecrets:put`, `appsecrets:list`, `appsecrets:delete` |
466
494
  | `files:list` | `files:read` |
467
- | `customers:write` | `users:create` |
468
- | `customers:read` | `users:read.all` |
469
- | `customers:read:named` | `users:read.named` |
470
- | `customers:read:identity` | `identities:read` |
495
+ | The names for writing and reading a project's users | `users:create`, `users:read.all`, `users:read.named`, `identities:read` |
471
496
  | `notifications:write` | `notifications:write.named` |
472
497
  | `records:write:<model>` | `records:write:<model>` and `records:create:<model>` |
473
498
 
474
499
  The last row is a change in what the name means. `records:write:<model>`
475
500
  changes a record that is there, and making one is `records:create:<model>`.
476
501
  An operation that does both declares both. `records.upsert` and
477
- `records.customer.save` are let through on either, and the platform asks for
502
+ `records.user.save` are let through on either, and the platform asks for
478
503
  the one the save turns out to need.
479
504
 
480
505
  - **Breaking, with the platform release that carries it: a full-page placement
@@ -487,7 +512,7 @@ to this version then.
487
512
  things change in what a placement writes:
488
513
 
489
514
  - **Every owner's records are written `.all`.** `records:read:order` was
490
- every order and is now the operator's own. Declare
515
+ every order and is now the user's own. Declare
491
516
  `records:read.all:order`.
492
517
  - **A write no longer includes its read.** `records:write:order` also read
493
518
  and created, and `apps:write` also read apps. Declare each one the page
@@ -496,8 +521,8 @@ to this version then.
496
521
  - **A wildcard and a permission that gives others are refused**, as `*`
497
522
  always was.
498
523
 
499
- The token then carries what the placement declares and the operator holds,
500
- permission by permission. An operator who holds part of a declared grant is
524
+ The token then carries what the placement declares and the user holds,
525
+ permission by permission. A user who holds part of a declared grant is
501
526
  given that part, where before the whole name was withheld.
502
527
 
503
528
  - **`session.can` answers by what the token covers** (`@foir/sdk/placement`).
@@ -538,11 +563,11 @@ to this version then.
538
563
  `records:read` for the model beside their own permission.
539
564
  - An operation that declares the create of a model and not the read
540
565
  (`@foir/sdk/app`) still makes its records. `records.upsert` landing on a
541
- record already there, `records.customer.save` likewise, `records.delete`,
566
+ record already there, `records.user.save` likewise, `records.delete`,
542
567
  `records.refresh`, `records.rename` and `records.updateMany` are refused
543
568
  until it declares the read too.
544
569
 
545
- - **Breaking, with the platform release that carries it: `records.customer.erase`
570
+ - **Breaking, with the platform release that carries it: `records.user.erase`
546
571
  needs the delete of the model** (`@foir/sdk/app`). An erase removes a record,
547
572
  so the operation declares `records:delete` and `records:read` for the model,
548
573
  and `users:create`. Until now the grant to save the record was enough. An
@@ -554,14 +579,14 @@ to this version then.
554
579
  `MyOrganizationRole.permissions` is gone and `MyOrganizationRole.grants`
555
580
  takes its place: what the role gives, in the permission catalogue's names. A
556
581
  grant stands for itself, so changing a record and creating one are two
557
- names (`records:write`, `records:create`), reading every customer's records
582
+ names (`records:write`, `records:create`), reading every user's records
558
583
  is `records:read.all`, and staffing an organization is `members:read` and
559
584
  `members:write`. Code that looked for `organizations:staff` or
560
585
  `records:list.all` in a role's list looks for the new names.
561
586
 
562
- - **Breaking, with the platform release that carries it: `customers.byIdentity`
563
- and `customers.identities` need `identities:read`, declared by name**
564
- (`@foir/sdk/app`). The read of every customer, `users:read.all`, no longer
587
+ - **Breaking, with the platform release that carries it: `users.byIdentity`
588
+ and `users.identities` need `identities:read`, declared by name**
589
+ (`@foir/sdk/app`). The read of every user, `users:read.all`, no longer
565
590
  includes them.
566
591
 
567
592
  ### Removed
@@ -632,29 +657,29 @@ the next promotion; `latest` moves to this version then.
632
657
  (`@foir/sdk/data`). Code that reads a drift is unaffected. Code that builds
633
658
  one by hand, for example to test a handler given to `onSchemaDrift` or made by
634
659
  `createFoirDriftHandler`, must add `incompatible: []`.
635
- - **Breaking (types): `AppConsentChange` names its customer one way**
636
- (`@foir/sdk/app`). It was an interface with a required `customerId`. It is
637
- now a type that holds a `customerId` or an `email`, never both. A change
638
- written as `{ customerId, ... }` is unaffected. An interface that extended
660
+ - **Breaking (types): `AppConsentChange` names its user one way**
661
+ (`@foir/sdk/app`). It was an interface with a required `userId`. It is
662
+ now a type that holds a `userId` or an `email`, never both. A change
663
+ written as `{ userId, ... }` is unaffected. An interface that extended
639
664
  `AppConsentChange` no longer compiles: intersect with it instead.
640
665
 
641
666
  ### Added
642
667
 
643
- - `notifications.setConsent` takes `email` in place of `customerId`
644
- (`@foir/sdk/app`), for an opt-in from somebody who may have no customer yet,
645
- such as a sign-up form. The platform finds the customer holding the address
668
+ - `notifications.setConsent` takes `email` in place of `userId`
669
+ (`@foir/sdk/app`), for an opt-in from somebody who may have no user yet,
670
+ such as a sign-up form. The platform finds the user holding the address
646
671
  at the install's level, or makes one, together with the change, so a change
647
672
  it refuses (a category the project does not have, a confirmation email the
648
- project cannot send) leaves no customer behind. Finding or making the
649
- customer first with `customers.ensure` did. The operation must declare
650
- `customers:write` as well as `notifications:consent`. `AppConsentSubject` is
673
+ project cannot send) leaves no user behind. Finding or making the
674
+ user first with `users.ensure` did. The operation must declare
675
+ `users:create` as well as `notifications:consent`. `AppConsentSubject` is
651
676
  exported.
652
677
 
653
678
  - `FoirSchemaDrift.incompatible`: what the generated module describes that the
654
679
  server no longer serves that way, as sorted paths into the manifest
655
680
  (`models.order.selection.status`, `models.order.ops.update`,
656
681
  `namespaces.search.ops.searchRecords.args.query`,
657
- `models.order.relations.customer`, `selectionUnions.Block.HeroBlock.title`).
682
+ `models.order.relations.buyer`, `selectionUnions.Block.HeroBlock.title`).
658
683
  Empty when the surface has only grown. `changed` keeps its meaning: what
659
684
  moved, not what broke.
660
685
 
@@ -665,26 +690,26 @@ platform serves from the next promotion; `latest` moves to it then.
665
690
 
666
691
  ### Changed
667
692
 
668
- - **Breaking: an app finds a customer by identity through its install, not
669
- through a model** (`@foir/sdk/app`). The customer sign-in an app's customers
693
+ - **Breaking: an app finds a user by identity through its install, not
694
+ through a model** (`@foir/sdk/app`). The user sign-in an app's users
670
695
  come through is paired with the install as a whole, so the two reads that
671
- walk it no longer name a model and have moved beside the other customer
696
+ walk it no longer name a model and have moved beside the other user
672
697
  reads:
673
- - `records.customer.identities(model, customerId)` is now
674
- `customers.identities(customerId)`.
675
- - `customers.byIdentity(identity)` is new: the id of the customer who holds
698
+ - `records.user.identities(model, userId)` is now
699
+ `users.identities(userId)`.
700
+ - `users.byIdentity(identity)` is new: the id of the user who holds
676
701
  an identity at the app's own system, or `null`. It replaces reading a
677
- customer's record for its owner.
702
+ user's record for its owner.
678
703
 
679
- Both need the new capability `customers:read:identity` (or `customers:read`),
704
+ Both need the new capability `identities:read` (or `users:read.all`),
680
705
  declared by the operation, and are refused at an install that pairs no
681
706
  sign-in. Reading or writing a model is no longer what admits them.
682
- - `install.config()` asks the platform for `customerSignIn`, a field a platform
707
+ - `install.config()` asks the platform for `userSignIn`, a field a platform
683
708
  older than this release does not have.
684
709
 
685
710
  ### Added
686
711
 
687
- - `install.config()` answers `customerSignIn`: the key of the customer sign-in
712
+ - `install.config()` answers `userSignIn`: the key of the user sign-in
688
713
  the install pairs, or `null` when it pairs none.
689
714
 
690
715
  ## [0.17.0] — 2026-10-02
@@ -694,19 +719,19 @@ platform serves from the next promotion; `latest` moves to it then.
694
719
 
695
720
  ### Added
696
721
 
697
- - **An app is told when a project cannot email its customers**
722
+ - **An app is told when a project cannot email its users**
698
723
  (`@foir/sdk/app`). A project with no App base URL used to accept a
699
724
  notification's email and drop it. The platform now refuses a notification
700
725
  that carries an email, and an opt-in to a category confirmed by email, with
701
- the reason as data. `appCustomerEmailUnavailableOf(error)` reads it:
726
+ the reason as data. `appUserEmailUnavailableOf(error)` reads it:
702
727
  `{ reason: 'NO_APP_BASE_URL' }`, or `null` for any other failure.
703
- - `install.config()` answers `customerEmailUnavailable`: the same reason ahead
704
- of time, or `null` when the project can send. `AppCustomerEmailUnavailableReason`
728
+ - `install.config()` answers `userEmailUnavailable`: the same reason ahead
729
+ of time, or `null` when the project can send. `AppUserEmailUnavailableReason`
705
730
  is the type.
706
731
 
707
732
  ### Changed
708
733
 
709
- - `install.config()` asks the platform for `customerEmailUnavailable`, a field
734
+ - `install.config()` asks the platform for `userEmailUnavailable`, a field
710
735
  a platform older than this release does not have.
711
736
 
712
737
  ## [0.16.0] — 2026-10-02
@@ -717,11 +742,11 @@ it at the next promotion.
717
742
  ### Added
718
743
 
719
744
  - **An embedded page is told how the console looks** (`@foir/sdk/placement`).
720
- The console's theme is the operator's own setting, which a framed page cannot
745
+ The console's theme is the user's own setting, which a framed page cannot
721
746
  see, so a page that followed the system's preference could sit dark inside a
722
747
  light console. `connectPlacement` takes `onAppearance`, called with
723
748
  `{ theme: 'light' | 'dark' }` as soon as the console says (before the token
724
- arrives) and again whenever the operator changes it; `session.appearance`
749
+ arrives) and again whenever the user changes it; `session.appearance`
725
750
  holds the current one. `PlacementAppearance` is the type, and
726
751
  `PLACEMENT_MESSAGE.appearance` the message.
727
752
  - A console older than this says nothing: `onAppearance` is not called and
@@ -739,7 +764,7 @@ then.
739
764
  - **`notifications.setConsent` answers `confirmationPending`**, and takes
740
765
  `givenElsewhere` and `locale` (`@foir/sdk/app`). A project can ask that an
741
766
  opt-in an app collects in a category is confirmed by email before it counts.
742
- In such a category an opt-in writes nothing: the platform sends the customer
767
+ In such a category an opt-in writes nothing: the platform sends the user
743
768
  one confirmation email, in the page's `locale` when they have stated no
744
769
  language of their own, and the answer says `confirmationPending`. The
745
770
  preference turns on when they follow the link. Everywhere else an opt-in is
@@ -760,17 +785,17 @@ then.
760
785
 
761
786
  ### Added
762
787
 
763
- - **`customers.get`, `customers.byEmail` and `customers.list`** on the app
764
- client (`@foir/sdk/app`): an operation reads the customers its work is about.
765
- `get(id)` and `byEmail(email)` answer one customer or null, and need
766
- `customers:read:named`: the customer the operation names, by id or by their
788
+ - **`users.get`, `users.byEmail` and `users.list`** on the app
789
+ client (`@foir/sdk/app`): an operation reads the users its work is about.
790
+ `get(id)` and `byEmail(email)` answer one user or null, and need
791
+ `users:read.named`: the user the operation names, by id or by their
767
792
  exact email address at the install's level, and nothing wider. `list` pages
768
- through the customers at the install's level and needs `customers:read`,
793
+ through the users at the install's level and needs `users:read.all`,
769
794
  which covers the two lookups as well. An operation declaring only the named
770
- read is refused the list. `AppCustomer` and `AppCustomerList` are their types.
771
- - **`customers.ensure` answers `verified`**: whether the customer it found or
772
- made has proved the address is theirs. It finds the customer holding the
773
- email either way, so one shopper asking twice is one customer; a caller with
795
+ read is refused the list. `AppUser` and `AppUserList` are their types.
796
+ - **`users.ensure` answers `verified`**: whether the user it found or
797
+ made has proved the address is theirs. It finds the user holding the
798
+ email either way, so one shopper asking twice is one user; a caller with
774
799
  something that should wait for proof asks the flag first.
775
800
 
776
801
  ## [0.13.0] — 2026-10-01
@@ -797,7 +822,7 @@ then.
797
822
  order, at most `first` of them, with `hasMore` saying the filter matched more.
798
823
  For work an app hands out in turn, such as the next ten people waiting: list
799
824
  them, then update the ones listed by id. A model's list is named by its
800
- plural, which its operator may set, so the first list a client makes reads
825
+ plural, which its user may set, so the first list a client makes reads
801
826
  the data API's surface descriptor (`GET /v1/manifest`) as the same token,
802
827
  once. `AppRecordList` is its query's type.
803
828
 
@@ -822,12 +847,12 @@ production serves from the next promotion; `latest` moves to it then.
822
847
  `whoami`, `install.config`, `install.credentials`,
823
848
  `install.writeCredentials`, `install.reportStatus`, `records.upsert`,
824
849
  `read`, `delete`, `refresh`, `rename`, `updateMany` and `aggregate`,
825
- `records.customer.save`, `read`, `erase` and `identities`,
826
- `customers.ensure`, `notifications.send` and `notifications.setConsent`, and
850
+ `records.user.save`, `read`, `erase` and `identities`,
851
+ `users.ensure`, `notifications.send` and `notifications.setConsent`, and
827
852
  `request` for a document of your own. Nothing is checked before a call: what
828
853
  the token may do is the platform's to hold it to, and a refusal is a
829
854
  `FoirRequestError` carrying the platform's answer.
830
- - `appLookupConflictOf`, `appCustomerUnlinkedOf` and `isAppFieldWithheld` read
855
+ - `appLookupConflictOf`, `appUserUnlinkedOf` and `isAppFieldWithheld` read
831
856
  the refusals an app acts on, as data.
832
857
  - `readAppDispatch` and `readCredentialProbe` read the two bodies the platform
833
858
  posts to an app, and `redeemExchangeTicket` trades an OAuth exchange ticket
@@ -855,7 +880,7 @@ production serves from the next promotion; `latest` moves to it then.
855
880
  what it throws when it has no keys to judge a token by.
856
881
  - **`requireScopedToken` answers more about who is calling.** The ingress it
857
882
  resolves with gains `orgId` (the organisation level the token was minted at,
858
- `null` when it states none), `customerId`, `expiresAt` and `tokenId`.
883
+ `null` when it states none), `userId`, `expiresAt` and `tokenId`.
859
884
  `ScopedTokenError` gains `reason` (`missing`, `invalid`, `forbidden` or
860
885
  `unavailable`), and its `status` may now be 503: keys that cannot be fetched
861
886
  are this service's outage, which the platform retries, and not a verdict on
@@ -867,7 +892,7 @@ production serves from the next promotion; `latest` moves to it then.
867
892
  passed. It takes `apiUrl`, used when a dispatch names no address to report
868
893
  to, `retry`, and `signal`. A call the platform did not answer, or answered
869
894
  with a 5xx or a 429, is tried again, with the same signed bytes.
870
- - **`@foir/sdk/placement`**, a new subpath for an app's own admin console shown
895
+ - **`@foir/sdk/placement`**, a new subpath for an app's own console shown
871
896
  inside Foir's as a full-page placement. `connectPlacement` tells the console
872
897
  the page is ready, takes the token it posts into the frame (only from the
873
898
  consoles you list), keeps it fresh, and gives you `request`, `can` and
@@ -926,8 +951,8 @@ production serves from the next promotion; `latest` moves to it then.
926
951
  once and asks again, failing with `FoirSessionExpiredError` when the session
927
952
  is over.
928
953
  - A request that sent no bearer is untouched.
929
- - **A refresh that names no customer keeps the session's identity.**
930
- `saveSession` used to write the customer id and email unconditionally, so a
954
+ - **A refresh that names no user keeps the session's identity.**
955
+ `saveSession` used to write the user id and email unconditionally, so a
931
956
  refresh answered without them left a valid token beside an empty identity, and
932
957
  `requireAuth` turned the session away. Given `env`, `requireAuth` now reads a
933
958
  missing identity once from `currentUser` rather than failing.
@@ -985,10 +1010,10 @@ surface version instead of the schema counter.
985
1010
  credential.
986
1011
 
987
1012
  Two things a dispatch client does not do. It does not subscribe: the
988
- subscription socket authenticates a key, an admin token or a customer bearer
1013
+ subscription socket authenticates a key, a console user token or a user bearer
989
1014
  and has no path for a dispatch token, so `onChange` and friends throw, naming
990
1015
  why. And it takes no key-side option (`apiKey`, `bearerToken`, `orgId`,
991
- `channel`, the socket options), because the token carries its own customer,
1016
+ `channel`, the socket options), because the token carries its own user,
992
1017
  organization and channel; each is a compile error and a runtime refusal.
993
1018
 
994
1019
  - `readDispatch(request)` and `OperationPayloadError` on `@foir/sdk/server`.
@@ -1015,7 +1040,7 @@ surface version instead of the schema counter.
1015
1040
 
1016
1041
  - `FoirRecordOwner` on `@foir/sdk/data`: `{ id, ownerId, ownerKind }`, what
1017
1042
  `setOwner` answers with. An operation that declares `records:attribute:<model>`
1018
- hands a record to another customer with `foir.<model>.setOwner({ id, ownerId })`,
1043
+ hands a record to another user with `foir.<model>.setOwner({ id, ownerId })`,
1019
1044
  and names the owner of a record it creates with `create({ input, ownerId })`.
1020
1045
  The answer carries the owner and not the record, because an operation acting
1021
1046
  for the previous holder may no longer read it.
@@ -1259,14 +1284,14 @@ returns a result object rather than `HostedSession | null`, and
1259
1284
  silent wrong answer for a thrown one that discards the answer. Nothing changes
1260
1285
  for a caller that does not pass it.
1261
1286
 
1262
- - `registerOrganization(env, { key, name }, { bearerToken })` on `@foir/sdk/auth`: a customer founds an organization of their own and becomes its first member, holding the role the project's `organizationSignupRole` setting names. Returns the same `MyOrganization` entry `myOrganizations` lists. Present on the wire only while the project's `organizationSignupEnabled` setting is on.
1263
- - **The operator's organization context, on `@foir/sdk/auth`** — `myOrganizations`
1287
+ - `registerOrganization(env, { key, name }, { bearerToken })` on `@foir/sdk/auth`: a user founds an organization of their own and becomes its first member, holding the role the project's `organizationSignupRole` setting names. Returns the same `MyOrganization` entry `myOrganizations` lists. Present on the wire only while the project's `organizationSignupEnabled` setting is on.
1288
+ - **The user's organization context, on `@foir/sdk/auth`** — `myOrganizations`
1264
1289
  and `selectOrganization`, plus the types `MyOrganization` and
1265
1290
  `SelectedOrganization`, and two entries on `AUTH_OPS`.
1266
1291
 
1267
1292
  A Fóir project can be partitioned into organizations, one per tenant of a SaaS
1268
- built on Fóir. An *operator* is a customer who runs one or more of them.
1269
- `myOrganizations()` answers which ones this customer may stand in — from their
1293
+ built on Fóir. An *user* is a user who runs one or more of them.
1294
+ `myOrganizations()` answers which ones this user may stand in — from their
1270
1295
  own membership rows, so it is not the project's inventory and cannot be used as
1271
1296
  one — and `selectOrganization({ orgId })` says which. An empty `orgId` clears
1272
1297
  the selection.
@@ -1276,7 +1301,7 @@ returns a result object rather than `HostedSession | null`, and
1276
1301
  caller's membership on every request. An application therefore cannot forget
1277
1302
  to send it, cannot send another organization's, and cannot be made to cross
1278
1303
  the boundary by a query it built wrong. These two functions are the entire
1279
- per-customer surface; everything downstream names no organization at all.
1304
+ per-user surface; everything downstream names no organization at all.
1280
1305
  (The project credential's side of the same boundary is the client-level
1281
1306
  `orgId` option below — a property of the client, still never of a call.)
1282
1307
 
@@ -1390,7 +1415,7 @@ returns a result object rather than `HostedSession | null`, and
1390
1415
  Schema drift is a different problem with the same remedy. A deploy that
1391
1416
  renames a field leaves every cached entry perfectly current and quietly wrong:
1392
1417
  no record changed, nothing is out of order, and the bytes describe a schema
1393
- that no longer exists — until the tab is reloaded, which on a long admin
1418
+ that no longer exists — until the tab is reloaded, which on a long console
1394
1419
  session can be days. `createFoirDriftHandler` wires the `FoirSchemaDrift` the
1395
1420
  data client already reports to a full clear.
1396
1421
 
@@ -1511,7 +1536,7 @@ returns a result object rather than `HostedSession | null`, and
1511
1536
  credential and the bearer is re-exchanged when it dies. A consumer that cannot
1512
1537
  see the lifetime has to hardcode the platform's (coupling itself to a server
1513
1538
  constant it cannot observe) or decode `exp` off the JWT — or, as happened,
1514
- treat a 15-minute bearer as good forever and have customers appear signed out
1539
+ treat a 15-minute bearer as good forever and have users appear signed out
1515
1540
  mid-session. `createFoirSessionClient` on the SPA path has read `expires_in`
1516
1541
  and scheduled a proactive refresh all along; this closes the asymmetry.
1517
1542
 
@@ -1521,10 +1546,10 @@ returns a result object rather than `HostedSession | null`, and
1521
1546
  - **`HostedSessionResult`** exported from `./auth`.
1522
1547
 
1523
1548
  - **`FoirAuthDowngrade`** on `./data` and `./server`, plus `extensions` on the
1524
- response envelope — Foir now reports when it DISCARDED a customer token you
1549
+ response envelope — Foir now reports when it DISCARDED a user token you
1525
1550
  sent, and the SDK stops dropping that report on the floor.
1526
1551
 
1527
- A customer JWT is optional: one that fails to verify is not refused, the read
1552
+ A user JWT is optional: one that fails to verify is not refused, the read
1528
1553
  is served anonymously and returns `200`. So a lapsed token and a genuinely
1529
1554
  anonymous request were indistinguishable — nothing threw, no refresh armed,
1530
1555
  and auth-targeted content quietly resolved to its anonymous variant. The
@@ -1533,7 +1558,7 @@ returns a result object rather than `HostedSession | null`, and
1533
1558
  ```json
1534
1559
  { "data": { "…": "…" },
1535
1560
  "extensions": { "auth": {
1536
- "customerToken": "rejected", "reason": "expired", "servedAs": "anonymous"
1561
+ "userToken": "rejected", "reason": "expired", "servedAs": "anonymous"
1537
1562
  } } }
1538
1563
  ```
1539
1564
 
@@ -1553,7 +1578,7 @@ returns a result object rather than `HostedSession | null`, and
1553
1578
 
1554
1579
  The GraphQL `events` subscription has been live on the public schema since the
1555
1580
  events spine shipped, with no client able to reach it. It is an `sk_`-only
1556
- operator surface, so it lives on `./server` beside the rest of the events
1581
+ console surface, so it lives on `./server` beside the rest of the events
1557
1582
  client and inherits its `pk_` and `Authorization` refusals unchanged.
1558
1583
 
1559
1584
  New exports: `FoirEventsSubscribeParams`, plus `FoirSubscription` and
@@ -1575,7 +1600,7 @@ returns a result object rather than `HostedSession | null`, and
1575
1600
  It collapsed every failure to `null`: no cookie, a `401`, a `502`, a rate
1576
1601
  limit, a DNS failure. Consumers have to act on that `null`, and the only
1577
1602
  safe-looking action is to clear the session and redirect to the front door —
1578
- so one blip on `/session/token` signed out a customer whose 30-day cookie was
1603
+ so one blip on `/session/token` signed out a user whose 30-day cookie was
1579
1604
  perfectly valid, and nothing recorded that it had happened. The route's own
1580
1605
  rate limiter is deliberately fail-open for the opposite reason.
1581
1606
 
@@ -1594,7 +1619,7 @@ returns a result object rather than `HostedSession | null`, and
1594
1619
  `outcome` says what to DO; `reason` says what happened. Only `401` and a
1595
1620
  missing cookie are `signed-out`. A `403` reports as `unavailable` with reason
1596
1621
  `forbidden` — it means the CSRF header did not arrive, which is a
1597
- misconfiguration rather than a blip, but signing the customer out over it
1622
+ misconfiguration rather than a blip, but signing the user out over it
1598
1623
  would still be wrong.
1599
1624
 
1600
1625
  - **`foir.ns.operations.onExecution` delivers `status` as the
@@ -1634,14 +1659,14 @@ Everything additive, so a MINOR either way under the pre-1.0 note.
1634
1659
  ### Added
1635
1660
 
1636
1661
  - **`hostedLogoutUrl(config, clientId, returnTo?)` on `./auth`** — the mirror of
1637
- `hostedLoginUrl`, and the only thing that actually signs a customer out on the
1662
+ `hostedLoginUrl`, and the only thing that actually signs a user out on the
1638
1663
  hosted-cookie flow.
1639
1664
 
1640
1665
  Login on that flow is symmetric across browser and server; logout was not.
1641
- The apex `foir_customer_session` cookie is the durable credential, and
1666
+ The apex `foir_session` cookie is the durable credential, and
1642
1667
  disposing of a bearer, clearing a local session, or calling the
1643
- `customerLogout` mutation all leave it in place — the next request
1644
- re-establishes the customer from it. The only surface that ended a session was
1668
+ `logout` mutation all leave it in place — the next request
1669
+ re-establishes the user from it. The only surface that ended a session was
1645
1670
  `POST /session/logout`, cookie-authenticated and CSRF-header-gated, which only
1646
1671
  a browser sending `credentials: 'include'` can reach.
1647
1672
 
@@ -2013,7 +2038,7 @@ note above.
2013
2038
 
2014
2039
  Reads take the shared, cacheable lane where they can:
2015
2040
  `GET /cdn/graphql?key=pk_…` with the persisted-query hash in the URL when the
2016
- call is a query, on a `pk_` key, with no customer bearer, on the published
2041
+ call is a query, on a `pk_` key, with no user bearer, on the published
2017
2042
  channel — and `POST /graphql` otherwise. The server's gate refuses on five
2018
2043
  conditions and the client decides all five before the request: the fifth,
2019
2044
  "the credential is in the URL", it satisfies by construction. The server is
@@ -2035,7 +2060,7 @@ note above.
2035
2060
  hand-written document may legitimately have several. As a document it reaches
2036
2061
  everything the credential can reach — including the two dozen root fields no
2037
2062
  model and no namespace claims (`designTokens`, `record`, `locales`, the
2038
- customer-auth mutations), which is the point of an escape hatch and is more
2063
+ user-auth mutations), which is the point of an escape hatch and is more
2039
2064
  than the old shape could address.
2040
2065
 
2041
2066
  - **Every op prints, and there is one wire format rather than two.** The
@@ -2098,19 +2123,19 @@ note above.
2098
2123
  schema knowledge the client is not allowed to hold. The manifest publishes
2099
2124
  each op's result shape, so the table has nothing left to answer. Neither
2100
2125
  symbol has appeared in a published release.
2101
- - **`customerResendVerificationEmail` from `@foir/sdk/auth`** — and the
2102
- `AUTH_OPS.customerResendVerificationEmail` entry with it. **It never sent an
2103
- email.** The resolver behind it checked that the request carried a customer id,
2104
- returned `true`, and called no RPC; there is no customer verification-code
2105
- column and no customer verification email in the action catalogue for it to
2126
+ - **`resendVerificationEmail` from `@foir/sdk/auth`** — and the
2127
+ `AUTH_OPS.resendVerificationEmail` entry with it. **It never sent an
2128
+ email.** The resolver behind it checked that the request carried a user id,
2129
+ returned `true`, and called no RPC; there is no user verification-code
2130
+ column and no user verification email in the action catalogue for it to
2106
2131
  have used. A caller got a success response every time and nothing was
2107
2132
  delivered, which is worse than an error, because there is no signal to act on.
2108
2133
 
2109
- **Use the OTP flow for mailbox proof:** `customerRequestOTP(env, email)` emails
2110
- a code, and `customerLoginOTP(env, { email, otp })` redeems it — activating a
2134
+ **Use the OTP flow for mailbox proof:** `requestOTP(env, email)` emails
2135
+ a code, and `loginWithOTP(env, { email, otp })` redeems it — activating a
2111
2136
  pending account on redemption and returning a session, so possession of the
2112
- mailbox is proven by the same call that signs the customer in. That is a live,
2113
- delivered path today; `customerVerifyEmail` remains for redeeming a token that
2137
+ mailbox is proven by the same call that signs the user in. That is a live,
2138
+ delivered path today; `verifyEmail` remains for redeeming a token that
2114
2139
  arrived by some other route.
2115
2140
 
2116
2141
  Like the two entries above, this symbol has not appeared in a published
@@ -2143,11 +2168,11 @@ note above.
2143
2168
  id are what the note is filed against and never appear on screen.
2144
2169
 
2145
2170
  Opening the panel reads `noteConfig`, which the API charges `notes:write` and
2146
- refuses to a caller with no customer session, so one probe settles whether the
2171
+ refuses to a caller with no session, so one probe settles whether the
2147
2172
  visitor is signed in, whether their role may write notes, and whether
2148
2173
  screenshot capture may be offered. A missing scope reads like a bad API key and
2149
- is not one, so it is reported as what it is: the signed-in customer's ROLE is
2150
- short `notes:write`, which a new project's default customer role does not
2174
+ is not one, so it is reported as what it is: the signed-in user's ROLE is
2175
+ short `notes:write`, which a new project's default user role does not
2151
2176
  carry.
2152
2177
 
2153
2178
  Screenshot capture is offered only when the project allows it and the browser
@@ -2177,11 +2202,11 @@ note above.
2177
2202
  New exports on `./media`: `captureFoirScreen`, `isFoirScreenCaptureSupported`,
2178
2203
  `FoirScreenCapture`, `FoirScreenCaptureOptions`.
2179
2204
 
2180
- - **Note attachments and note config on `./data`.** `FoirCustomerNote` gains
2205
+ - **Note attachments and note config on `./data`.** `FoirUserNote` gains
2181
2206
  `attachments`, `FoirCreateMyNoteArgs` gains an optional `attachmentFileIds`,
2182
2207
  and `FoirNoteConfig` is the shape `foir.ns.notes.noteConfig()` answers with.
2183
2208
 
2184
- New exports on `./data`: `FoirCustomerNoteAttachment`, `FoirNoteConfig`.
2209
+ New exports on `./data`: `FoirUserNoteAttachment`, `FoirNoteConfig`.
2185
2210
 
2186
2211
  - **A subject registry — the records a client fetched, so an annotation can
2187
2212
  anchor to the record instead of to a URL.** `createFoirSubjectRegistry()`
@@ -2225,11 +2250,11 @@ note above.
2225
2250
  `FoirSubject`, `FoirSubjectEntry`, `FoirSubjectOptions`, `FoirSubjectOrigin`,
2226
2251
  `FoirSubjectRegistry`, `FoirRecordPath`.
2227
2252
 
2228
- - **Types for the customer notes surface.** `foir.ns.notes.myNotes()` and
2253
+ - **Types for the user notes surface.** `foir.ns.notes.myNotes()` and
2229
2254
  `foir.ns.notes.createMyNote()` already worked — `notes` is a namespace the
2230
2255
  manifest publishes like any other — but their shapes had to be written out by
2231
2256
  hand at each call site. They are platform-owned and identical in every project,
2232
- so they now ship: `FoirCustomerNote`, `FoirMyNotesArgs`, `FoirMyNotesResult`,
2257
+ so they now ship: `FoirUserNote`, `FoirMyNotesArgs`, `FoirMyNotesResult`,
2233
2258
  `FoirCreateMyNoteArgs`, `FoirNoteSubjectType`.
2234
2259
 
2235
2260
  ```ts
@@ -2237,7 +2262,7 @@ note above.
2237
2262
  ```
2238
2263
 
2239
2264
  `FoirNoteSubjectType` is the closed set the platform's write path enforces
2240
- (`record`, `file`, `model`, `operation`, `schedule`, `customer`) and is never a
2265
+ (`record`, `file`, `model`, `operation`, `schedule`, `user`) and is never a
2241
2266
  model key — a note on a record is `'record'` plus the key on
2242
2267
  `subjectModelKey`. Like every mirrored platform table in `builtins.ts`, a kind
2243
2268
  added upstream widens this union in a minor release.
@@ -2394,12 +2419,12 @@ note above.
2394
2419
  `FoirEventsClientConfig`, `FoirEventsListParams`, `FoirEventsStreamParams`.
2395
2420
 
2396
2421
  **On `@foir/sdk/server` and no other subpath, deliberately.** The event log is
2397
- an OPERATOR surface (DECIDED 2026-08-04): reachable by an `sk_` key or
2398
- an admin session, never by a customer token, and `events:list.project` is not
2422
+ an USER surface (DECIDED 2026-08-04): reachable by an `sk_` key or
2423
+ a console session, never by a user token, and `events:list.project` is not
2399
2424
  mintable on a `pk_` key at all. `events.view` is plain tenant+project
2400
2425
  containment while `record.view` carries owner/grantee/borrow terms on top, so a
2401
2426
  containment-only read over the log describes rows whose records the same caller
2402
- could not read — and each row's `actor` names which *other* customer acted.
2427
+ could not read — and each row's `actor` names which *other* user acted.
2403
2428
  `createEventsClient` therefore throws on a `pk_` key and on an `Authorization`
2404
2429
  header rather than letting either reach the wire, and an import-graph test
2405
2430
  fails if the module becomes reachable from a subpath that ships to a browser.
@@ -2420,12 +2445,12 @@ note above.
2420
2445
  is the entire cost of GraphQL paid for one screen. Ten root fields closed:
2421
2446
 
2422
2447
  `getAuthConfig`, `getDefaultAuthProvider`, `currentUser`, `myProviderToken`,
2423
- `customerLogout`, `customerRequestPasswordReset`, `customerResetPassword`,
2424
- `customerUpdatePassword`, `customerVerifyEmail`, `deleteMyAccount`.
2448
+ `logout`, `requestPasswordReset`, `resetPassword`,
2449
+ `updatePassword`, `verifyEmail`, `deleteMyAccount`.
2425
2450
 
2426
2451
  Plus the session-layer pairings for the flows that need one:
2427
2452
  `resetPasswordAndSignIn` (redeem the emailed token and persist the session it
2428
- mints — the peer of `loginWithPassword` for the branch where the customer
2453
+ mints — the peer of `loginWithPassword` for the branch where the user
2429
2454
  cannot log in), `signOut` (revoke server-side, then clear locally, and clear
2430
2455
  locally even if the revoke fails), and `authedOp` (`authedRequest`'s twin for
2431
2456
  auth ops: refresh once, retry once, on a 401-shaped failure).
@@ -2442,10 +2467,10 @@ note above.
2442
2467
  ### Removed
2443
2468
 
2444
2469
  - **The nine auth operation documents on `@foir/sdk/auth`** —
2445
- `CustomerLoginDocument`, `CustomerRegisterDocument`,
2446
- `CustomerRefreshTokenDocument`, `CustomerRequestOTPDocument`,
2447
- `CustomerLoginOTPDocument`, `CustomerLoginWithProviderDocument`,
2448
- `CustomerProviderCallbackDocument`, `CustomerProviderVerifyOTPDocument`,
2470
+ `UserLoginDocument`, `UserRegisterDocument`,
2471
+ `UserRefreshTokenDocument`, `UserRequestOTPDocument`,
2472
+ `UserLoginOTPDocument`, `UserLoginWithProviderDocument`,
2473
+ `UserProviderCallbackDocument`, `UserProviderVerifyOTPDocument`,
2449
2474
  `AuthProvidersDocument`.
2450
2475
 
2451
2476
  **Breaking, so the next release is a MINOR** per the pre-1.0 note above.
@@ -2457,15 +2482,15 @@ note above.
2457
2482
  eleven were unreachable. The flows now address the server's generated `auth`
2458
2483
  namespace, so `@foir/sdk/auth` carries no transport of its own.
2459
2484
 
2460
- *Migration.* Nothing that called a FUNCTION changes: `customerLogin(env, …)`,
2485
+ *Migration.* Nothing that called a FUNCTION changes: `login(env, …)`,
2461
2486
  `getAuthProviders(env)`, `loginWithPassword(adapter, env, …)`, `refreshSession`,
2462
2487
  `requireAuth`, `authedRequest` and every React hook in `@foir/sdk/react` keep
2463
2488
  their exact signatures. Only code importing a `*Document` const is affected,
2464
2489
  and only if it was executing the document itself through its own GraphQL
2465
2490
  client. Two options:
2466
2491
 
2467
- - call the SDK function instead (`customerLogin(env, vars)` rather than running
2468
- `CustomerLoginDocument` through Apollo/urql), which is what the exports were
2492
+ - call the SDK function instead (`login(env, vars)` rather than running
2493
+ `UserLoginDocument` through Apollo/urql), which is what the exports were
2469
2494
  for; or
2470
2495
  - keep your own client and write the document in your own codebase — these are
2471
2496
  fixed-shape platform operations, so the text does not vary by project.
@@ -2529,7 +2554,7 @@ actually happened.
2529
2554
 
2530
2555
  Purely additive: `./auth` keeps exporting all four, unchanged, and nothing is
2531
2556
  moved or renamed. What changes is the cost of reaching them. `./auth` also
2532
- exports the customer-auth GraphQL documents, which build their
2557
+ exports the user-auth GraphQL documents, which build their
2533
2558
  TypedDocumentNodes with a top-level `parse()` that no bundler can treat as
2534
2559
  pure — so a browser app importing only `createFoirSessionClient` was shipping
2535
2560
  the whole `graphql` package to get it. `src/auth/session-client.ts` imports
@@ -2590,7 +2615,7 @@ on its own, which is the intended behaviour for a release that adds exports.
2590
2615
 
2591
2616
  ### Added
2592
2617
 
2593
- - `@foir/sdk/auth`: `customerSignupContext` and `customerJoinWaitlist`, plus the
2618
+ - `@foir/sdk/auth`: `signupContext` and `joinWaitlist`, plus the
2594
2619
  `SignupContext`, `SignupMode` and `WaitlistJoinResult` types — waitlist and
2595
2620
  restricted-signup flows for projects that are not open-registration.
2596
2621
  - A pinned public-export surface: `public-exports.snapshot.json` plus
@@ -2617,7 +2642,7 @@ on its own, which is the intended behaviour for a release that adds exports.
2617
2642
 
2618
2643
  ### Added
2619
2644
 
2620
- - `@foir/sdk/client`: `createFoirContentClient` — forwards the customer bearer
2645
+ - `@foir/sdk/client`: `createFoirContentClient` — forwards the user bearer
2621
2646
  token on content reads, so authenticated and segment-targeted content works
2622
2647
  without hand-rolling the header.
2623
2648
 
@@ -2634,7 +2659,7 @@ on its own, which is the intended behaviour for a release that adds exports.
2634
2659
 
2635
2660
  ### Added
2636
2661
 
2637
- - **New subpath `@foir/sdk/react`** — drop-in React customer auth: `FoirProvider`,
2662
+ - **New subpath `@foir/sdk/react`** — drop-in React user auth: `FoirProvider`,
2638
2663
  `SignIn`, `OAuthButtons`, `UserButton`, `useFoirAuth`, `useFoirSession`,
2639
2664
  `useFoirUser`.
2640
2665
  - **New subpath `@foir/sdk/next`** — Next.js App Router BFF auth adapter: cookie
@@ -2662,7 +2687,7 @@ First public release. Ten subpaths:
2662
2687
  - `@foir/sdk/media` — progressive media components and adapters.
2663
2688
  - `@foir/sdk/content` — `createContentRenderer` and `RichTextRenderer` with
2664
2689
  injected typography tokens.
2665
- - `@foir/sdk/auth` — customer auth flows, token lifecycle, hosted-login bridge.
2690
+ - `@foir/sdk/auth` — user auth flows, token lifecycle, hosted-login bridge.
2666
2691
  - `@foir/sdk/realtime` — `createCollabSession`, a thin y-websocket helper.
2667
2692
  - `@foir/sdk/codegen`, `@foir/sdk/codegen/block-registry`,
2668
2693
  `@foir/sdk/codegen/block-scaffold` — the `foirCodegen` preset and the