@foir/sdk 0.21.0 → 0.23.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 +135 -1
- package/README.md +15 -15
- package/dist/app/client.d.ts +93 -86
- package/dist/app/contract/proto/apps/v1/apps_pb.d.ts +14 -13
- package/dist/app/dispatch.d.ts +5 -5
- package/dist/app/errors.d.ts +17 -15
- package/dist/app/index.d.ts +4 -4
- package/dist/app/naming.d.ts +1 -1
- package/dist/app/ticket.d.ts +2 -2
- package/dist/app/vocabulary.generated.d.ts +2 -2
- package/dist/app-contract.js +3 -3
- package/dist/app.js +92 -90
- package/dist/auth/access.d.ts +19 -19
- package/dist/auth/auth.d.ts +251 -117
- package/dist/auth/grant-table.generated.d.ts +5 -4
- package/dist/auth/hosted.d.ts +38 -14
- package/dist/auth/index.d.ts +9 -9
- package/dist/auth/operations.d.ts +153 -33
- package/dist/auth/ops.d.ts +39 -21
- package/dist/auth/session-client.d.ts +3 -3
- package/dist/auth-session.js +3 -3
- package/dist/auth.js +400 -250
- package/dist/client.js +5 -8
- package/dist/codegen/preset.d.ts +1 -1
- package/dist/data/builtins.d.ts +26 -26
- package/dist/data/client.d.ts +3 -3
- package/dist/data/decimal.d.ts +1 -1
- package/dist/data/index.d.ts +1 -1
- package/dist/data/manifest.d.ts +1 -1
- package/dist/data/schema.d.ts +2 -2
- package/dist/data/transport.d.ts +14 -13
- package/dist/data/ws-transport.d.ts +1 -1
- package/dist/data.js +8 -11
- package/dist/graphql/content-client.d.ts +13 -13
- package/dist/index.js +1 -4
- package/dist/live/drift.d.ts +1 -1
- package/dist/media/screen-capture.d.ts +1 -1
- package/dist/next/index.d.ts +2 -2
- package/dist/next/session.d.ts +10 -10
- package/dist/next.js +78 -60
- package/dist/placement/index.d.ts +13 -13
- package/dist/placement.js +127 -116
- package/dist/push.js +62 -44
- package/dist/react/FoirFeedback.d.ts +2 -2
- package/dist/react/FoirProvider.d.ts +24 -24
- package/dist/react/SignIn.d.ts +4 -4
- package/dist/react/UserButton.d.ts +1 -1
- package/dist/react/feedback-notes.d.ts +8 -6
- package/dist/react/index.d.ts +3 -3
- package/dist/react.js +238 -209
- package/dist/realtime/index.d.ts +1 -1
- package/dist/server/callback-client.d.ts +4 -4
- package/dist/server/events-client.d.ts +21 -21
- package/dist/server/operation-types.d.ts +8 -8
- package/dist/server/require-scoped-token.d.ts +3 -3
- package/dist/server/types.d.ts +2 -2
- package/dist/server/verify-scoped-token.d.ts +3 -3
- package/dist/server.js +130 -126
- package/dist/transport/foir-http.d.ts +14 -14
- package/dist/transport/key-kind.d.ts +1 -12
- package/dist/types/index.d.ts +2 -2
- package/package.json +1 -1
package/dist/app/client.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* The client an installed app calls Foir with.
|
|
3
3
|
*
|
|
4
4
|
* An app is installed in many projects, and each install maps the app's
|
|
5
|
-
* sources onto whichever models that project
|
|
5
|
+
* sources onto whichever models that project chose. So an app has
|
|
6
6
|
* no schema to generate a client from: it learns the model keys at request
|
|
7
7
|
* time, from the install's own configuration, and names them in each call.
|
|
8
8
|
* `createFoirClient` is the client for an endpoint that knows its project;
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
*/
|
|
29
29
|
import type { FoirDispatchCredential } from '../data/transport';
|
|
30
30
|
import { type FoirRetryPolicy } from '../transport/retry';
|
|
31
|
-
import type {
|
|
31
|
+
import type { AppUserEmailUnavailableReason } from './errors';
|
|
32
32
|
type Json = null | boolean | number | string | Json[] | {
|
|
33
33
|
[key: string]: Json;
|
|
34
34
|
};
|
|
@@ -65,18 +65,18 @@ export interface AppFieldMapping {
|
|
|
65
65
|
/** The project model's field key. */
|
|
66
66
|
modelField: string;
|
|
67
67
|
/**
|
|
68
|
-
* SINK_ONLY means the
|
|
68
|
+
* SINK_ONLY means the project has said Foir owns the field: a value from
|
|
69
69
|
* the app's side must not be written over it. An unrecognised direction
|
|
70
70
|
* reads as SINK_ONLY, which withholds the field rather than writing on a
|
|
71
71
|
* guess.
|
|
72
72
|
*/
|
|
73
73
|
direction: AppSyncDirection;
|
|
74
74
|
}
|
|
75
|
-
/** One of the
|
|
75
|
+
/** One of the install's mappings: a source or sink of the app onto a model. */
|
|
76
76
|
export interface AppBinding {
|
|
77
77
|
/** The app's source or sink name. */
|
|
78
78
|
key: string;
|
|
79
|
-
/** The project model
|
|
79
|
+
/** The project model it was mapped onto. */
|
|
80
80
|
model: string;
|
|
81
81
|
/** The model field the app's records are keyed on. Empty when the mapping names none. */
|
|
82
82
|
naturalKey: string;
|
|
@@ -84,7 +84,7 @@ export interface AppBinding {
|
|
|
84
84
|
/** REFERENCE: Foir reads the source's fields live. SYNC: it holds a copy. A sink is a copy. */
|
|
85
85
|
mode: 'SYNC' | 'REFERENCE';
|
|
86
86
|
}
|
|
87
|
-
/** An install's own configuration, as the
|
|
87
|
+
/** An install's own configuration, as the project left it. */
|
|
88
88
|
export interface AppInstallConfig {
|
|
89
89
|
name: string;
|
|
90
90
|
enabled: boolean;
|
|
@@ -92,25 +92,26 @@ export interface AppInstallConfig {
|
|
|
92
92
|
targetModels: string[];
|
|
93
93
|
/** The address the app's vendor is told to deliver webhooks to. Empty when the app declares none. */
|
|
94
94
|
webhookUrl: string;
|
|
95
|
-
/** The
|
|
95
|
+
/** The project's answers to the manifest's settings schema. */
|
|
96
96
|
settings: JsonObject;
|
|
97
97
|
sources: AppBinding[];
|
|
98
98
|
sinks: AppBinding[];
|
|
99
99
|
/**
|
|
100
|
-
* Why the
|
|
101
|
-
* sits at, or null when
|
|
102
|
-
*
|
|
103
|
-
* (`
|
|
100
|
+
* Why the app's emails to users cannot link into the app at the level this
|
|
101
|
+
* install sits at, or null when they can. While it is set, a notification
|
|
102
|
+
* whose email links into the app with `{base}` is refused
|
|
103
|
+
* (`appUserEmailUnavailableOf`), so say so before one is. Every other email
|
|
104
|
+
* is sent.
|
|
104
105
|
*/
|
|
105
|
-
|
|
106
|
+
userEmailUnavailable: AppUserEmailUnavailableReason | null;
|
|
106
107
|
/**
|
|
107
|
-
* The
|
|
108
|
-
*
|
|
108
|
+
* The sign-in this install pairs with the app, by key, for an app whose own
|
|
109
|
+
* system has its own users; null when it pairs none. Every identity
|
|
109
110
|
* the app names is resolved through it, so while it is null nothing finds a
|
|
110
|
-
*
|
|
111
|
+
* user by identity: `users.byIdentity` and `users.identities`
|
|
111
112
|
* are refused, and an operation that needs them is not registered.
|
|
112
113
|
*/
|
|
113
|
-
|
|
114
|
+
userSignIn: string | null;
|
|
114
115
|
}
|
|
115
116
|
/**
|
|
116
117
|
* The status an install reports. Leaving out `subscriptionHealth`,
|
|
@@ -136,7 +137,7 @@ export interface AppRecord {
|
|
|
136
137
|
/** The platform's own id. What `records.delete` takes. */
|
|
137
138
|
id: string;
|
|
138
139
|
naturalKey: string | null;
|
|
139
|
-
/** The
|
|
140
|
+
/** The user the record belongs to, or null. */
|
|
140
141
|
ownerId: string | null;
|
|
141
142
|
/** The fields that were asked for and could be read, by model field key. */
|
|
142
143
|
fields: JsonObject;
|
|
@@ -163,21 +164,21 @@ export interface AppUpsertResult {
|
|
|
163
164
|
/** True when nothing was written because Foir already holds a newer copy (`sourceModifiedAt`). */
|
|
164
165
|
stale: boolean;
|
|
165
166
|
}
|
|
166
|
-
export type
|
|
167
|
+
export type AppUserSaveResult = (AppUpsertResult & {
|
|
167
168
|
unlinked: false;
|
|
168
|
-
|
|
169
|
+
userCreated: boolean;
|
|
169
170
|
}) | {
|
|
170
171
|
unlinked: true;
|
|
171
172
|
};
|
|
172
|
-
export interface
|
|
173
|
+
export interface AppUserEraseResult {
|
|
173
174
|
recordDeleted: boolean;
|
|
174
175
|
identityRemoved: boolean;
|
|
175
|
-
|
|
176
|
-
/** Another sign-in method, or something else they own; null when the
|
|
177
|
-
|
|
176
|
+
userDeleted: boolean;
|
|
177
|
+
/** Another sign-in method, or something else they own; null when the user went or none was found. */
|
|
178
|
+
userKeptBecause: string | null;
|
|
178
179
|
}
|
|
179
180
|
export interface AppNotification {
|
|
180
|
-
|
|
181
|
+
userId: string;
|
|
181
182
|
/** The in-app title, and the email's subject when `email` names none. */
|
|
182
183
|
title: string;
|
|
183
184
|
message?: string;
|
|
@@ -194,10 +195,10 @@ export interface AppNotification {
|
|
|
194
195
|
url: string;
|
|
195
196
|
}>;
|
|
196
197
|
};
|
|
197
|
-
/** Makes the send safe to repeat: the same key from the same operation tells the
|
|
198
|
+
/** Makes the send safe to repeat: the same key from the same operation tells the user once. */
|
|
198
199
|
idempotencyKey?: string;
|
|
199
200
|
}
|
|
200
|
-
/** An organisation an operation makes for one of its
|
|
201
|
+
/** An organisation an operation makes for one of its users. */
|
|
201
202
|
export interface AppOrganizationProvision {
|
|
202
203
|
/**
|
|
203
204
|
* Yours to choose and to keep. Sending the same one again with the same
|
|
@@ -221,30 +222,36 @@ export interface AppOrganizationProvision {
|
|
|
221
222
|
data: Record<string, unknown>;
|
|
222
223
|
};
|
|
223
224
|
/**
|
|
224
|
-
* The
|
|
225
|
+
* The user who becomes its first member. They are given the role the
|
|
225
226
|
* project names for an organisation's founder, in its settings: the
|
|
226
227
|
* operation chooses who, and the project decides what they hold.
|
|
227
228
|
*/
|
|
228
229
|
firstMember?: {
|
|
229
|
-
|
|
230
|
+
userId: string;
|
|
230
231
|
};
|
|
232
|
+
/**
|
|
233
|
+
* The organisation signs its own people in, to a pool of its own, apart
|
|
234
|
+
* from its parent's and the project's. Its descendants share that pool
|
|
235
|
+
* unless one of them starts another. Chosen now, when it is made.
|
|
236
|
+
*/
|
|
237
|
+
ownPool?: boolean;
|
|
231
238
|
}
|
|
232
239
|
/**
|
|
233
|
-
* Who a consent change is for: a
|
|
240
|
+
* Who a consent change is for: a user whose id the app holds, or an
|
|
234
241
|
* address.
|
|
235
242
|
*
|
|
236
|
-
* By `email`, the
|
|
243
|
+
* By `email`, the user holding the address at the operation's level is
|
|
237
244
|
* found, or made, together with the change, so a change the platform refuses
|
|
238
|
-
* leaves no
|
|
239
|
-
*
|
|
245
|
+
* leaves no user behind. It is for an opt-in from somebody who may not be a
|
|
246
|
+
* user yet (a sign-up form), and the operation must declare
|
|
240
247
|
* `users:create` as well as `notifications:consent`.
|
|
241
248
|
*/
|
|
242
249
|
export type AppConsentSubject = {
|
|
243
|
-
|
|
250
|
+
userId: string;
|
|
244
251
|
email?: undefined;
|
|
245
252
|
} | {
|
|
246
253
|
email: string;
|
|
247
|
-
|
|
254
|
+
userId?: undefined;
|
|
248
255
|
};
|
|
249
256
|
export type AppConsentChange = AppConsentSubject & {
|
|
250
257
|
/** A notification category the project makes opt-in. */
|
|
@@ -259,19 +266,19 @@ export type AppConsentChange = AppConsentSubject & {
|
|
|
259
266
|
*/
|
|
260
267
|
sourceModifiedAt?: string;
|
|
261
268
|
/**
|
|
262
|
-
* True when the
|
|
269
|
+
* True when the user gave this consent in another system and the app is
|
|
263
270
|
* carrying it over (a mirror). It is applied as it stands.
|
|
264
271
|
*
|
|
265
272
|
* Left out, the app collected the consent itself (a sign-up form), and an
|
|
266
273
|
* opt-in is applied the way its category says: at once, or, in a category
|
|
267
|
-
* that confirms by email, only when the
|
|
274
|
+
* that confirms by email, only when the user follows the link the
|
|
268
275
|
* platform sends them. Until then nothing is written and the answer says
|
|
269
276
|
* `confirmationPending`.
|
|
270
277
|
*/
|
|
271
278
|
givenElsewhere?: boolean;
|
|
272
279
|
/**
|
|
273
280
|
* The language of the page the consent was collected on. The confirmation
|
|
274
|
-
* email is written in it when the
|
|
281
|
+
* email is written in it when the user has stated none of their own.
|
|
275
282
|
*/
|
|
276
283
|
locale?: string;
|
|
277
284
|
};
|
|
@@ -308,7 +315,7 @@ export interface AppClient {
|
|
|
308
315
|
whoami(): Promise<AppWhoami>;
|
|
309
316
|
/** The install this token acts for: its configuration, its credential, its status. */
|
|
310
317
|
install: {
|
|
311
|
-
/** The
|
|
318
|
+
/** The install's settings and mappings. Needs `appconfig:read`. */
|
|
312
319
|
config(): Promise<AppInstallConfig>;
|
|
313
320
|
/**
|
|
314
321
|
* The install's credential, by the manifest's credential field names.
|
|
@@ -330,7 +337,7 @@ export interface AppClient {
|
|
|
330
337
|
* Write the record at a natural key, making it when there is none.
|
|
331
338
|
* Changing the record there needs `records:write:<model>` and making one
|
|
332
339
|
* needs `records:create:<model>`, so an operation that does both declares
|
|
333
|
-
* both. `ownerId` names the
|
|
340
|
+
* both. `ownerId` names the user it belongs to (needs
|
|
334
341
|
* `records:attribute:<model>`); `sourceModifiedAt` is when the object this
|
|
335
342
|
* mirrors last changed at its source, so an older copy arriving late is
|
|
336
343
|
* not written.
|
|
@@ -365,7 +372,7 @@ export interface AppClient {
|
|
|
365
372
|
* other is refused, naming it. `hasMore` says the filter matched more than
|
|
366
373
|
* were answered. Like `read`, it sees the PUBLISHED version.
|
|
367
374
|
*
|
|
368
|
-
* The name of a model's list is the
|
|
375
|
+
* The name of a model's list is the project's to set, so the first list a
|
|
369
376
|
* client makes asks the data API what this token is served (`GET
|
|
370
377
|
* /v1/manifest`), once.
|
|
371
378
|
*/
|
|
@@ -420,16 +427,16 @@ export interface AppClient {
|
|
|
420
427
|
truncated: boolean;
|
|
421
428
|
}>;
|
|
422
429
|
/**
|
|
423
|
-
* The record of a
|
|
430
|
+
* The record of a user the app names by identity: their id at the
|
|
424
431
|
* external system, which is also the subject of their sign-in with it. For
|
|
425
|
-
* a source that declares an identity. The platform finds the
|
|
432
|
+
* a source that declares an identity. The platform finds the user
|
|
426
433
|
* through the sign-in the install pairs with the source, at the install's
|
|
427
434
|
* level, and never by email.
|
|
428
435
|
*/
|
|
429
|
-
|
|
436
|
+
user: {
|
|
430
437
|
/**
|
|
431
|
-
* Merge `data` into the
|
|
432
|
-
* have none, and the
|
|
438
|
+
* Merge `data` into the user's record, making the record when they
|
|
439
|
+
* have none, and the user when `email` is given and nobody holds the
|
|
433
440
|
* identity. An identity nobody holds, with no email, is `{ unlinked:
|
|
434
441
|
* true }`: nothing was written, and they are known once they sign in.
|
|
435
442
|
*/
|
|
@@ -439,29 +446,29 @@ export interface AppClient {
|
|
|
439
446
|
data: JsonObject;
|
|
440
447
|
email?: string;
|
|
441
448
|
sourceModifiedAt?: string;
|
|
442
|
-
}): Promise<
|
|
443
|
-
/** The
|
|
449
|
+
}): Promise<AppUserSaveResult>;
|
|
450
|
+
/** The user's record, or null when nobody holds the identity or they hold no record. */
|
|
444
451
|
read(model: string, identity: string): Promise<AppRecord | null>;
|
|
445
452
|
/**
|
|
446
|
-
* Erase what the app holds for the
|
|
447
|
-
* their record and the identity's link, and the
|
|
453
|
+
* Erase what the app holds for the user, as a privacy request asks:
|
|
454
|
+
* their record and the identity's link, and the user when nothing
|
|
448
455
|
* else is attached to them. It removes a record, so it needs
|
|
449
456
|
* `records:delete` and `records:read` for the model, and
|
|
450
457
|
* `identities:delete`. The grant to save the record is not enough.
|
|
451
458
|
*/
|
|
452
|
-
erase(model: string, identity: string): Promise<
|
|
459
|
+
erase(model: string, identity: string): Promise<AppUserEraseResult>;
|
|
453
460
|
};
|
|
454
461
|
};
|
|
455
|
-
|
|
462
|
+
users: {
|
|
456
463
|
/**
|
|
457
|
-
* The
|
|
458
|
-
* is none. The same
|
|
464
|
+
* The user who has this email at the install's level, made when there
|
|
465
|
+
* is none. The same user every time for one email. Needs
|
|
459
466
|
* `users:create`.
|
|
460
467
|
*
|
|
461
|
-
* `verified` says whether that address is one the
|
|
462
|
-
* theirs. A
|
|
468
|
+
* `verified` says whether that address is one the user has proved is
|
|
469
|
+
* theirs. A user this call makes has not, and neither has one an
|
|
463
470
|
* earlier call made: anybody can type an address. So what is written for
|
|
464
|
-
* an unverified
|
|
471
|
+
* an unverified user is written for whoever holds the address, and
|
|
465
472
|
* anything that should wait for proof asks `verified` first.
|
|
466
473
|
*/
|
|
467
474
|
ensure(email: string): Promise<{
|
|
@@ -470,53 +477,53 @@ export interface AppClient {
|
|
|
470
477
|
verified: boolean;
|
|
471
478
|
}>;
|
|
472
479
|
/**
|
|
473
|
-
* One
|
|
480
|
+
* One user by id, or null when there is none at the install's level.
|
|
474
481
|
* Needs `users:read.named`, or `users:read.all`.
|
|
475
482
|
*/
|
|
476
|
-
get(id: string): Promise<
|
|
483
|
+
get(id: string): Promise<AppUser | null>;
|
|
477
484
|
/**
|
|
478
|
-
* The
|
|
485
|
+
* The user who has this email at the install's level, or null. The
|
|
479
486
|
* exact address, as `ensure` matches it, and nothing wider: it finds one
|
|
480
|
-
*
|
|
487
|
+
* user and never searches. Needs `users:read.named`, or
|
|
481
488
|
* `users:read.all`.
|
|
482
489
|
*/
|
|
483
|
-
byEmail(email: string): Promise<
|
|
490
|
+
byEmail(email: string): Promise<AppUser | null>;
|
|
484
491
|
/**
|
|
485
|
-
* The id of the
|
|
492
|
+
* The id of the user who holds this identity at the app's own system,
|
|
486
493
|
* or null when nobody does: for an app hearing from its system about one
|
|
487
|
-
* of its
|
|
488
|
-
* with that system, and it is resolved through the
|
|
489
|
-
* install pairs (`install.config().
|
|
494
|
+
* of its own users. The identity is the subject of the user's sign-in
|
|
495
|
+
* with that system, and it is resolved through the sign-in the
|
|
496
|
+
* install pairs (`install.config().userSignIn`) and no other. Never
|
|
490
497
|
* matched by email. Needs `identities:read`, declared by name:
|
|
491
498
|
* `users:read.all` does not include it.
|
|
492
499
|
*/
|
|
493
500
|
byIdentity(identity: string): Promise<string | null>;
|
|
494
501
|
/**
|
|
495
|
-
* The other direction: the identities a
|
|
502
|
+
* The other direction: the identities a user the app names by id
|
|
496
503
|
* holds at the app's own system, most recently seen first, through the
|
|
497
504
|
* same pairing. Empty when they have never signed in that way. For an app
|
|
498
|
-
* acting on an event that names the Foir
|
|
505
|
+
* acting on an event that names the Foir user. Needs
|
|
499
506
|
* `identities:read`, declared by name.
|
|
500
507
|
*/
|
|
501
|
-
identities(
|
|
508
|
+
identities(userId: string): Promise<string[]>;
|
|
502
509
|
/**
|
|
503
|
-
* The
|
|
510
|
+
* The users at the install's level, a page at a time, newest first.
|
|
504
511
|
* Needs `users:read.all`: an operation declaring only
|
|
505
|
-
* `users:read.named` reads the
|
|
512
|
+
* `users:read.named` reads the users it names and is refused the
|
|
506
513
|
* list.
|
|
507
514
|
*/
|
|
508
|
-
list(query?:
|
|
509
|
-
|
|
515
|
+
list(query?: AppUserList): Promise<{
|
|
516
|
+
users: AppUser[];
|
|
510
517
|
hasMore: boolean;
|
|
511
518
|
endCursor: string | null;
|
|
512
519
|
}>;
|
|
513
520
|
};
|
|
514
521
|
organizations: {
|
|
515
522
|
/**
|
|
516
|
-
* Make an organisation, with its settings record and a
|
|
523
|
+
* Make an organisation, with its settings record and a user as its
|
|
517
524
|
* first member. Needs `organizations:create`, and for `settings` the write
|
|
518
525
|
* of the settings model. Sign-up is the use: one operation creates the
|
|
519
|
-
*
|
|
526
|
+
* user (`users.ensure`) and then the organisation that is theirs.
|
|
520
527
|
*
|
|
521
528
|
* The first member is given the role the project names for an
|
|
522
529
|
* organisation's founder. A project that names none refuses it, saying
|
|
@@ -551,20 +558,20 @@ export interface AppClient {
|
|
|
551
558
|
}>;
|
|
552
559
|
};
|
|
553
560
|
notifications: {
|
|
554
|
-
/** Tell a
|
|
561
|
+
/** Tell a user something. Needs `notifications:write.named`. */
|
|
555
562
|
send(notification: AppNotification): Promise<void>;
|
|
556
563
|
/**
|
|
557
|
-
* Set a named
|
|
564
|
+
* Set a named user's consent in an opt-in category. Needs
|
|
558
565
|
* `notifications:consent`, which only an operation's token carries.
|
|
559
566
|
*
|
|
560
567
|
* `confirmationPending` is true when an opt-in the app collected was not
|
|
561
|
-
* applied because its category confirms by email first: the
|
|
568
|
+
* applied because its category confirms by email first: the user has
|
|
562
569
|
* been sent a link, or was sent one recently, and the preference turns on
|
|
563
|
-
* when they follow it. The answer is the same whether or not
|
|
564
|
-
*
|
|
570
|
+
* when they follow it. The answer is the same whether or not anybody
|
|
571
|
+
* held the address already.
|
|
565
572
|
*
|
|
566
|
-
* Name the
|
|
567
|
-
*
|
|
573
|
+
* Name the user by `userId`, or by `email` for somebody who may not be
|
|
574
|
+
* a user yet: the platform finds or makes them with the change,
|
|
568
575
|
* and that also needs `users:create`.
|
|
569
576
|
*/
|
|
570
577
|
setConsent(change: AppConsentChange): Promise<{
|
|
@@ -580,7 +587,7 @@ export interface AppClient {
|
|
|
580
587
|
*
|
|
581
588
|
* For work a delivery cannot do in place. A delivery is not a run, so it
|
|
582
589
|
* holds none of the authority the platform gives only inside one (setting
|
|
583
|
-
* a
|
|
590
|
+
* a user's consent is one), and it has the few seconds its vendor
|
|
584
591
|
* waits. Hand the work to an operation and answer the vendor.
|
|
585
592
|
*
|
|
586
593
|
* Only the token a delivery arrived with may call it, for an operation
|
|
@@ -590,16 +597,16 @@ export interface AppClient {
|
|
|
590
597
|
start(operationKey: string, options?: AppOperationStart): Promise<AppStartedOperation>;
|
|
591
598
|
};
|
|
592
599
|
}
|
|
593
|
-
/** A
|
|
594
|
-
export interface
|
|
600
|
+
/** A user, as an operation that declared a user read sees them. */
|
|
601
|
+
export interface AppUser {
|
|
595
602
|
id: string;
|
|
596
603
|
email: string;
|
|
597
|
-
/** Whether the
|
|
604
|
+
/** Whether the user has proved the address is theirs. */
|
|
598
605
|
verified: boolean;
|
|
599
606
|
/** `ACTIVE`, `SUSPENDED` or `PENDING`, as the platform holds it. */
|
|
600
607
|
status: string;
|
|
601
608
|
}
|
|
602
|
-
export interface
|
|
609
|
+
export interface AppUserList {
|
|
603
610
|
/** Part of an email address to look for. Absent lists everyone. */
|
|
604
611
|
search?: string;
|
|
605
612
|
/** How many to answer, at most. The platform's own page size when absent. */
|
|
@@ -121,9 +121,9 @@ export declare type AppConfig = Message<"apps.v1.AppConfig"> & {
|
|
|
121
121
|
* OPTIONAL. The app's own system has customers who sign in to it. See
|
|
122
122
|
* CustomerSignIn.
|
|
123
123
|
*
|
|
124
|
-
* @generated from field: apps.v1.
|
|
124
|
+
* @generated from field: apps.v1.UserSignIn user_sign_in = 14;
|
|
125
125
|
*/
|
|
126
|
-
|
|
126
|
+
userSignIn?: UserSignIn | undefined;
|
|
127
127
|
};
|
|
128
128
|
|
|
129
129
|
/**
|
|
@@ -150,9 +150,9 @@ export declare const AppConfigSchema: GenMessage<AppConfig>;
|
|
|
150
150
|
* feature that finds customers through it (Feature.customer_sign_in), and an
|
|
151
151
|
* operation that asks who holds an identity (customers:read:identity).
|
|
152
152
|
*
|
|
153
|
-
* @generated from message apps.v1.
|
|
153
|
+
* @generated from message apps.v1.UserSignIn
|
|
154
154
|
*/
|
|
155
|
-
export declare type
|
|
155
|
+
export declare type UserSignIn = Message<"apps.v1.UserSignIn"> & {
|
|
156
156
|
/**
|
|
157
157
|
* What the setup tells the operator they are choosing, in a sentence: which
|
|
158
158
|
* customers these are and what identifies them.
|
|
@@ -163,10 +163,10 @@ export declare type CustomerSignIn = Message<"apps.v1.CustomerSignIn"> & {
|
|
|
163
163
|
};
|
|
164
164
|
|
|
165
165
|
/**
|
|
166
|
-
* Describes the message apps.v1.
|
|
167
|
-
* Use `create(
|
|
166
|
+
* Describes the message apps.v1.UserSignIn.
|
|
167
|
+
* Use `create(UserSignInSchema)` to create a new message.
|
|
168
168
|
*/
|
|
169
|
-
export declare const
|
|
169
|
+
export declare const UserSignInSchema: GenMessage<UserSignIn>;
|
|
170
170
|
|
|
171
171
|
/**
|
|
172
172
|
* A feature of the app: something the operator turns on or off as a whole at
|
|
@@ -230,9 +230,9 @@ export declare type Feature = Message<"apps.v1.Feature"> & {
|
|
|
230
230
|
* be on at an install that pairs none: the setup asks for the sign-in at the
|
|
231
231
|
* switch, and the platform refuses the switch without one.
|
|
232
232
|
*
|
|
233
|
-
* @generated from field: bool
|
|
233
|
+
* @generated from field: bool user_sign_in = 6;
|
|
234
234
|
*/
|
|
235
|
-
|
|
235
|
+
userSignIn: boolean;
|
|
236
236
|
|
|
237
237
|
/**
|
|
238
238
|
* The notification category the feature sends under, when it sends
|
|
@@ -1520,7 +1520,7 @@ export declare const FieldSyncDirectionSchema: GenEnum<FieldSyncDirection>;
|
|
|
1520
1520
|
|
|
1521
1521
|
/**
|
|
1522
1522
|
* The level that owns each row of an app's storage: the three levels a model
|
|
1523
|
-
* can be owned at
|
|
1523
|
+
* can be owned at.
|
|
1524
1524
|
*
|
|
1525
1525
|
* @generated from enum apps.v1.StorageOwner
|
|
1526
1526
|
*/
|
|
@@ -1545,11 +1545,12 @@ export enum StorageOwner {
|
|
|
1545
1545
|
ORGANIZATION = 2,
|
|
1546
1546
|
|
|
1547
1547
|
/**
|
|
1548
|
-
* Each row belongs to a
|
|
1548
|
+
* Each row belongs to a user, and only they and whoever holds every user's
|
|
1549
|
+
* rows read it.
|
|
1549
1550
|
*
|
|
1550
|
-
* @generated from enum value:
|
|
1551
|
+
* @generated from enum value: STORAGE_OWNER_USER = 4;
|
|
1551
1552
|
*/
|
|
1552
|
-
|
|
1553
|
+
USER = 4,
|
|
1553
1554
|
}
|
|
1554
1555
|
|
|
1555
1556
|
/**
|
package/dist/app/dispatch.d.ts
CHANGED
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
* and every run a hook, a schedule or `execute<Op>`
|
|
11
11
|
* starts.
|
|
12
12
|
* a direct call `{ project, app, operation, triggered_by,
|
|
13
|
-
* execution_id, input? }`:
|
|
13
|
+
* execution_id, input? }`: somebody running a SYNC
|
|
14
14
|
* operation from the console, discovery during setup,
|
|
15
15
|
* and the uninstall teardown. Nothing is queued, so
|
|
16
16
|
* `execution_id` is the id of the token the call
|
|
17
17
|
* carried and no execution holds it.
|
|
18
18
|
* the credential probe `{ project, app, operation, values }`: the reserved
|
|
19
19
|
* `__validate_credentials` operation, sent the
|
|
20
|
-
* credential
|
|
20
|
+
* credential somebody is about to save.
|
|
21
21
|
*
|
|
22
22
|
* `readAppDispatch` reads the first two as one shape. `readCredentialProbe`
|
|
23
23
|
* reads the third.
|
|
@@ -44,19 +44,19 @@ export interface AppDispatch {
|
|
|
44
44
|
* Read an app operation's dispatch body, already parsed from JSON.
|
|
45
45
|
*
|
|
46
46
|
* It does not refuse a body it cannot place: a direct call may carry no input
|
|
47
|
-
* and no id, and an endpoint that answered 4xx to one would fail
|
|
47
|
+
* and no id, and an endpoint that answered 4xx to one would fail somebody's
|
|
48
48
|
* action over a field it does not need. What is absent is absent on the
|
|
49
49
|
* answer.
|
|
50
50
|
*/
|
|
51
51
|
export declare function readAppDispatch(body: unknown): AppDispatch;
|
|
52
52
|
/**
|
|
53
|
-
* Read the credential probe's body: the values
|
|
53
|
+
* Read the credential probe's body: the values somebody submitted, by the
|
|
54
54
|
* manifest's credential field names. Every value the credential store accepts
|
|
55
55
|
* is a string, so anything else is left out rather than handed on as a
|
|
56
56
|
* surprise.
|
|
57
57
|
*
|
|
58
58
|
* The probe carries no `X-Foir-Context`, and whatever answers it with a
|
|
59
|
-
* non-2xx blocks
|
|
59
|
+
* non-2xx blocks their save. So answer 400 only for a value they can
|
|
60
60
|
* retype, and 200 for everything else, including a check you could not run.
|
|
61
61
|
*/
|
|
62
62
|
export declare function readCredentialProbe(body: unknown): {
|
package/dist/app/errors.d.ts
CHANGED
|
@@ -25,34 +25,36 @@ export interface AppLookupConflict {
|
|
|
25
25
|
*/
|
|
26
26
|
export declare function appLookupConflictOf(error: unknown): AppLookupConflict | null;
|
|
27
27
|
/**
|
|
28
|
-
* A save to a
|
|
28
|
+
* A save to a user's record refused because no user holds the
|
|
29
29
|
* identity at the install's level and no email came to make one, or null for
|
|
30
|
-
* any other failure. Nothing is wrong with the row: the
|
|
30
|
+
* any other failure. Nothing is wrong with the row: the user is known once
|
|
31
31
|
* they sign in with the sign-in the install pairs with the source.
|
|
32
32
|
*/
|
|
33
|
-
export declare function
|
|
33
|
+
export declare function appUserUnlinkedOf(error: unknown): {
|
|
34
34
|
model: string;
|
|
35
35
|
identityProvider: string;
|
|
36
36
|
} | null;
|
|
37
37
|
/**
|
|
38
|
-
* Why a project cannot send a
|
|
39
|
-
*
|
|
40
|
-
* this build does not know arrives as
|
|
38
|
+
* Why a project cannot send a user an email. `NO_APP_BASE_URL`: the email
|
|
39
|
+
* links into the app with `{base}`, and no App base URL is set for the project
|
|
40
|
+
* or for the user's organization. A reason this build does not know arrives as
|
|
41
|
+
* the platform spelled it.
|
|
41
42
|
*/
|
|
42
|
-
export type
|
|
43
|
+
export type AppUserEmailUnavailableReason = 'NO_APP_BASE_URL' | (string & {});
|
|
43
44
|
/** The reason as the platform sent it, or null when it sent none. */
|
|
44
|
-
export declare function
|
|
45
|
+
export declare function userEmailUnavailableReasonOf(value: unknown): AppUserEmailUnavailableReason | null;
|
|
45
46
|
/**
|
|
46
|
-
* A request refused because it would send a
|
|
47
|
-
* cannot
|
|
48
|
-
* was queued.
|
|
49
|
-
*
|
|
47
|
+
* A request refused because it would send a user an email the project
|
|
48
|
+
* cannot build, or null for any other failure. Nothing was written and nothing
|
|
49
|
+
* was queued. A notification whose email links into the app with `{base}` is
|
|
50
|
+
* refused this way where no App base URL is set, and so is an opt-in whose
|
|
51
|
+
* confirmation email the project's copy links into the app.
|
|
50
52
|
*
|
|
51
|
-
* It is about the project, not the
|
|
53
|
+
* It is about the project, not the user: the project's team fixes it,
|
|
52
54
|
* and the same request goes once they have.
|
|
53
55
|
*/
|
|
54
|
-
export declare function
|
|
55
|
-
reason:
|
|
56
|
+
export declare function appUserEmailUnavailableOf(error: unknown): {
|
|
57
|
+
reason: AppUserEmailUnavailableReason;
|
|
56
58
|
} | null;
|
|
57
59
|
/**
|
|
58
60
|
* Whether a read failed because the token is not served the field it asked
|
package/dist/app/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* createAppClient call Foir as the install, with the token a dispatch
|
|
12
12
|
* carried: its configuration, credential and status,
|
|
13
|
-
* records of the models it maps,
|
|
13
|
+
* records of the models it maps, users and
|
|
14
14
|
* notifications.
|
|
15
15
|
* readAppDispatch the body of a dispatch, whichever way it arrived,
|
|
16
16
|
* readCredentialProbe and of the credential probe.
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
* The manifest's own messages are on `@foir/sdk/app/contract`.
|
|
22
22
|
*/
|
|
23
23
|
export { createAppClient } from './client';
|
|
24
|
-
export type { AppBinding, AppClient, AppClientConfig, AppConsentChange, AppConsentSubject,
|
|
25
|
-
export {
|
|
26
|
-
export type {
|
|
24
|
+
export type { AppBinding, AppClient, AppClientConfig, AppConsentChange, AppConsentSubject, AppUser, AppUserEraseResult, AppUserList, AppUserSaveResult, AppFieldMapping, AppInstallConfig, AppNotification, AppOperationStart, AppOrganizationProvision, AppRecord, AppRecordList, AppStartedOperation, AppStatusReport, AppSyncDirection, AppUpsertResult, AppWhoami, } from './client';
|
|
25
|
+
export { appUserEmailUnavailableOf, appUserUnlinkedOf, appLookupConflictOf, isAppFieldWithheld } from './errors';
|
|
26
|
+
export type { AppUserEmailUnavailableReason, AppLookupConflict } from './errors';
|
|
27
27
|
export { appModelFieldName, appModelTypeName, appSelectorEnumValue } from './naming';
|
|
28
28
|
export { RECORD_KEY_RULE, recordKeyRefusal } from './record-key';
|
|
29
29
|
export { readAppDispatch, readCredentialProbe } from './dispatch';
|
package/dist/app/naming.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* model's key: the singular query, `delete<Type>`, `<Type>WhereInput` and the
|
|
6
6
|
* rest. A client generated for one project reads those names off the schema.
|
|
7
7
|
* An app installed in many projects cannot, because the model is whichever one
|
|
8
|
-
* each
|
|
8
|
+
* each project mapped, so it derives them from the key the same way the
|
|
9
9
|
* schema does.
|
|
10
10
|
*
|
|
11
11
|
* The rule: split the key on every run of characters that are not letters or
|
package/dist/app/ticket.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* The exchange ticket: how an app's own OAuth callback gets to write the
|
|
3
3
|
* credential it was just granted.
|
|
4
4
|
*
|
|
5
|
-
* An install that needs a vendor's consent sends
|
|
5
|
+
* An install that needs a vendor's consent sends whoever is installing it to the app's
|
|
6
6
|
* authorize route with a single-use ticket. When the vendor returns them, the
|
|
7
7
|
* app redeems the ticket for a short-lived token that can do one thing: write
|
|
8
8
|
* this install's credential. It cannot read the configuration, report status
|
|
@@ -26,7 +26,7 @@ export interface RedeemedExchangeTicket {
|
|
|
26
26
|
/**
|
|
27
27
|
* Redeem an exchange ticket. ONE ATTEMPT, on purpose: the ticket is single-use,
|
|
28
28
|
* so repeating a call whose answer was lost would find the ticket spent, and
|
|
29
|
-
*
|
|
29
|
+
* their only way forward would be to start the install again. A
|
|
30
30
|
* failure here is the answer.
|
|
31
31
|
*/
|
|
32
32
|
export declare function redeemExchangeTicket(options: {
|