@jwilleke/ngdpbase-types 5.28.0 → 5.29.1
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/lib/packages/ngdpbase-types/index.d.ts +1 -1
- package/lib/src/context/ApiContext.d.ts +17 -4
- package/lib/src/context/ApiContext.js +22 -6
- package/lib/src/ice/runImport.d.ts +26 -0
- package/lib/src/ice/types.d.ts +7 -0
- package/lib/src/managers/ImportManager.d.ts +31 -3
- package/lib/src/managers/PersonManager.d.ts +17 -8
- package/lib/src/managers/RoleManager.d.ts +3 -2
- package/lib/src/managers/UserManager.d.ts +16 -0
- package/lib/src/types/Consent.js +22 -0
- package/lib/src/types/Organization.d.ts +16 -4
- package/lib/src/types/Person.d.ts +3 -3
- package/lib/src/utils/contactAccess.d.ts +7 -0
- package/package.json +1 -1
|
@@ -42,6 +42,6 @@ export type { User, UserPreferences } from '../../src/types/User.js';
|
|
|
42
42
|
export type { default as PersonManager, LinkOfferOutcome } from '../../src/managers/PersonManager.js';
|
|
43
43
|
export type { default as OrganizationManager } from '../../src/managers/OrganizationManager.js';
|
|
44
44
|
export type { Person, PersonAffiliation, PersonInput, PersonUpdate } from '../../src/types/Person.js';
|
|
45
|
-
export type { Organization, OrganizationInput, OrganizationUpdate } from '../../src/types/Organization.js';
|
|
45
|
+
export type { Organization, OrganizationInput, OrganizationUpdate, ContactPoint, ContactPointEntry, PostalAddress } from '../../src/types/Organization.js';
|
|
46
46
|
export type { ContactRefusedError } from '../../src/utils/contactAccess.js';
|
|
47
47
|
export type { default as RoleManager } from '../../src/managers/RoleManager.js';
|
|
@@ -40,21 +40,34 @@ export declare class ApiError extends Error {
|
|
|
40
40
|
* offer the way forward, as core routes do (`{ error, reauth }`).
|
|
41
41
|
*/
|
|
42
42
|
readonly reauth?: string | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* For a refusal because the user has documents to accept (#2027): this
|
|
45
|
+
* site's consent prompt, returning to the page they were on. Sent with
|
|
46
|
+
* the 403 as `consent`; a page is redirected there.
|
|
47
|
+
*/
|
|
48
|
+
readonly consent?: string | undefined;
|
|
43
49
|
constructor(status: number, message: string,
|
|
44
50
|
/**
|
|
45
51
|
* For a step-up refusal (#1745): where the person re-authenticates,
|
|
46
52
|
* returning to the page they were on. Send it with the 403 so the page can
|
|
47
53
|
* offer the way forward, as core routes do (`{ error, reauth }`).
|
|
48
54
|
*/
|
|
49
|
-
reauth?: string | undefined
|
|
55
|
+
reauth?: string | undefined,
|
|
56
|
+
/**
|
|
57
|
+
* For a refusal because the user has documents to accept (#2027): this
|
|
58
|
+
* site's consent prompt, returning to the page they were on. Sent with
|
|
59
|
+
* the 403 as `consent`; a page is redirected there.
|
|
60
|
+
*/
|
|
61
|
+
consent?: string | undefined);
|
|
50
62
|
}
|
|
51
63
|
/**
|
|
52
64
|
* Send a refusal — the one way it reaches the client, from core routes and
|
|
53
65
|
* every add-on route alike (#1749). JSON is `{ success: false, error, reauth? }`;
|
|
54
66
|
* text is the message, then where to sign in again for a step-up refusal.
|
|
55
|
-
* `page` is for a link the
|
|
56
|
-
* redirects to the re-authenticate page, a
|
|
57
|
-
*
|
|
67
|
+
* `page` is for a link the user followed or a form they sent in the browser:
|
|
68
|
+
* a step-up refusal redirects to the re-authenticate page, a consent refusal
|
|
69
|
+
* to the consent prompt (#2027), a 401 to sign-in (returning here), anything
|
|
70
|
+
* else is the message as text. JSON carries the consent link as `consent`. A route never writes its own refusal:
|
|
58
71
|
* the step-up `reauth` is easy to drop.
|
|
59
72
|
*/
|
|
60
73
|
export declare function sendApiError(res: Response, err: ApiError, mode?: ReauthMode): void;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import '../types/express.js';
|
|
5
5
|
import { BaseContext } from './BaseContext.js';
|
|
6
6
|
import { STEP_UP_REASON } from '../types/Policy.js';
|
|
7
|
+
import { CONSENT_PATH } from '../types/Consent.js';
|
|
7
8
|
// ── ApiError ────────────────────────────────────────────────────────────────
|
|
8
9
|
/**
|
|
9
10
|
* Thrown by ApiContext guard methods (requirePermission, actingUsername).
|
|
@@ -12,16 +13,24 @@ import { STEP_UP_REASON } from '../types/Policy.js';
|
|
|
12
13
|
export class ApiError extends Error {
|
|
13
14
|
status;
|
|
14
15
|
reauth;
|
|
16
|
+
consent;
|
|
15
17
|
constructor(status, message,
|
|
16
18
|
/**
|
|
17
19
|
* For a step-up refusal (#1745): where the person re-authenticates,
|
|
18
20
|
* returning to the page they were on. Send it with the 403 so the page can
|
|
19
21
|
* offer the way forward, as core routes do (`{ error, reauth }`).
|
|
20
22
|
*/
|
|
21
|
-
reauth
|
|
23
|
+
reauth,
|
|
24
|
+
/**
|
|
25
|
+
* For a refusal because the user has documents to accept (#2027): this
|
|
26
|
+
* site's consent prompt, returning to the page they were on. Sent with
|
|
27
|
+
* the 403 as `consent`; a page is redirected there.
|
|
28
|
+
*/
|
|
29
|
+
consent) {
|
|
22
30
|
super(message);
|
|
23
31
|
this.status = status;
|
|
24
32
|
this.reauth = reauth;
|
|
33
|
+
this.consent = consent;
|
|
25
34
|
this.name = 'ApiError';
|
|
26
35
|
}
|
|
27
36
|
}
|
|
@@ -29,19 +38,26 @@ export class ApiError extends Error {
|
|
|
29
38
|
* Send a refusal — the one way it reaches the client, from core routes and
|
|
30
39
|
* every add-on route alike (#1749). JSON is `{ success: false, error, reauth? }`;
|
|
31
40
|
* text is the message, then where to sign in again for a step-up refusal.
|
|
32
|
-
* `page` is for a link the
|
|
33
|
-
* redirects to the re-authenticate page, a
|
|
34
|
-
*
|
|
41
|
+
* `page` is for a link the user followed or a form they sent in the browser:
|
|
42
|
+
* a step-up refusal redirects to the re-authenticate page, a consent refusal
|
|
43
|
+
* to the consent prompt (#2027), a 401 to sign-in (returning here), anything
|
|
44
|
+
* else is the message as text. JSON carries the consent link as `consent`. A route never writes its own refusal:
|
|
35
45
|
* the step-up `reauth` is easy to drop.
|
|
36
46
|
*/
|
|
37
47
|
export function sendApiError(res, err, mode = 'json') {
|
|
38
48
|
// Only this site's re-authenticate page: an add-on's ApiError cannot send the person elsewhere.
|
|
39
49
|
const reauth = typeof err.reauth === 'string' && err.reauth.startsWith('/auth/reauth?') ? err.reauth : undefined;
|
|
50
|
+
// Likewise only this site's consent prompt.
|
|
51
|
+
const consent = typeof err.consent === 'string' && (err.consent === CONSENT_PATH || err.consent.startsWith(`${CONSENT_PATH}?`)) ? err.consent : undefined;
|
|
40
52
|
if (mode === 'page') {
|
|
41
53
|
if (reauth) {
|
|
42
54
|
res.redirect(reauth);
|
|
43
55
|
return;
|
|
44
56
|
}
|
|
57
|
+
if (consent) {
|
|
58
|
+
res.redirect(consent);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
45
61
|
if (err.status === 401) {
|
|
46
62
|
res.redirect('/login?redirect=' + encodeURIComponent(res.req?.originalUrl || '/'));
|
|
47
63
|
return;
|
|
@@ -50,10 +66,10 @@ export function sendApiError(res, err, mode = 'json') {
|
|
|
50
66
|
return;
|
|
51
67
|
}
|
|
52
68
|
if (mode === 'text') {
|
|
53
|
-
res.status(err.status).send(reauth ? `${err.message}: ${reauth}` : err.message);
|
|
69
|
+
res.status(err.status).send(reauth ? `${err.message}: ${reauth}` : consent ? `${err.message} Read and accept them at ${consent}` : err.message);
|
|
54
70
|
return;
|
|
55
71
|
}
|
|
56
|
-
res.status(err.status).json({ success: false, error: err.message, ...(reauth ? { reauth } : {}) });
|
|
72
|
+
res.status(err.status).json({ success: false, error: err.message, ...(reauth ? { reauth } : {}), ...(consent ? { consent } : {}) });
|
|
57
73
|
}
|
|
58
74
|
/**
|
|
59
75
|
* The subject a request carries, refused when there is none (#1399).
|
|
@@ -43,6 +43,32 @@ export interface ChainSpec {
|
|
|
43
43
|
* warnings first. Partial notes are collected into `partial`.
|
|
44
44
|
*/
|
|
45
45
|
export declare function convertChain(shim: RegisteredShim, input: IceItem, chain: string[], spec: ChainSpec, partial: string[]): Promise<ChainLeaf[]>;
|
|
46
|
+
/** Does this run keep its originals during the upload (#2034)? */
|
|
47
|
+
export declare function keepsAtUpload(receiver: RegisteredReceiver | undefined, original: OriginalChoice): boolean;
|
|
48
|
+
/** What keeping at upload did: how many it kept, or the first file it could not keep. */
|
|
49
|
+
export interface UploadKeepResult {
|
|
50
|
+
kept: number;
|
|
51
|
+
refused?: {
|
|
52
|
+
name: string;
|
|
53
|
+
message: string;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Keep the originals of a run whose receiver keeps into an encrypted store,
|
|
58
|
+
* now, during the upload (#2034). `ctx` is the REQUEST's context: it holds
|
|
59
|
+
* the user's unlocked key, so the receiver's `keepOriginal` seals the bytes
|
|
60
|
+
* and the store's sealed index entry while the key is live. Each kept
|
|
61
|
+
* original is recorded in the ledger by fingerprint and door (#2011), so the
|
|
62
|
+
* queued run reuses it and never keeps again.
|
|
63
|
+
*
|
|
64
|
+
* The files are decided exactly as the run decides them ({@link planFile}):
|
|
65
|
+
* noise, a file too large, one nothing reads and one already imported are
|
|
66
|
+
* not kept. An original already kept through this door is not kept again.
|
|
67
|
+
* Stops at the first refusal (or failure) and says which file: the caller
|
|
68
|
+
* then queues nothing. Originals kept before it stay kept, and recorded, so
|
|
69
|
+
* the next try reuses them.
|
|
70
|
+
*/
|
|
71
|
+
export declare function keepOriginalsAtUpload(deps: IceRunDeps, request: IceRunRequest, ctx: ActorContext, scope: string): Promise<UploadKeepResult>;
|
|
46
72
|
/**
|
|
47
73
|
* Run one import. Fills and returns `report`, which the caller may be
|
|
48
74
|
* showing while it runs. Never throws for one file's failure; that file's
|
package/lib/src/ice/types.d.ts
CHANGED
|
@@ -182,6 +182,13 @@ export interface IceReceiver {
|
|
|
182
182
|
* store). Without this, `keep` hands the original to the files receiver.
|
|
183
183
|
*/
|
|
184
184
|
keepOriginal?(original: IceItem, ctx: ActorContext): Promise<ReceiveOutcome>;
|
|
185
|
+
/**
|
|
186
|
+
* `keepOriginal` writes into an encrypted store (phr's vault), which only a
|
|
187
|
+
* request holding the user's unlocked key can write (#2034). The engine then
|
|
188
|
+
* keeps each original during the upload, with the request's own context,
|
|
189
|
+
* before the run is queued; the run reuses what was kept and needs no key.
|
|
190
|
+
*/
|
|
191
|
+
keepsEncrypted?: boolean;
|
|
185
192
|
/** The original-file choices this receiver offers (D11). Without it: all three. */
|
|
186
193
|
originals?: IceOriginalChoices;
|
|
187
194
|
}
|
|
@@ -31,7 +31,7 @@ import BaseManager, { BackupData } from './BaseManager.js';
|
|
|
31
31
|
import type { WikiEngine } from '../types/WikiEngine.js';
|
|
32
32
|
import { IContentConverter } from '../converters/IContentConverter.js';
|
|
33
33
|
import { type ZipReadLimits } from '../utils/zipArchive.js';
|
|
34
|
-
import type
|
|
34
|
+
import { type JobContext } from '../context/JobContext.js';
|
|
35
35
|
import type { IceLedger, IceOriginalChoices, IceReceiver, IceRunReport, IceRunRequest, IceShim, RegisteredShim } from '../ice/types.js';
|
|
36
36
|
/**
|
|
37
37
|
* Options for import operations
|
|
@@ -207,6 +207,16 @@ export declare class TakeoutImportRefused extends Error {
|
|
|
207
207
|
readonly reason: 'not-owner' | 'no-such-store' | 'locked' | 'unreadable';
|
|
208
208
|
constructor(reason: 'not-owner' | 'no-such-store' | 'locked' | 'unreadable', message: string);
|
|
209
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* An import refused at upload, before anything was queued (#2034): keeping
|
|
212
|
+
* the original of `file` in the receiver's encrypted store was refused or
|
|
213
|
+
* failed. `message` is written for the user who uploaded.
|
|
214
|
+
*/
|
|
215
|
+
export declare class ImportUploadRefused extends Error {
|
|
216
|
+
readonly file: string;
|
|
217
|
+
readonly reason: string;
|
|
218
|
+
constructor(file: string, reason: string);
|
|
219
|
+
}
|
|
210
220
|
/** One page's outcome in a takeout import (#1472). */
|
|
211
221
|
export type TakeoutPageOutcome = {
|
|
212
222
|
title: string;
|
|
@@ -344,11 +354,27 @@ declare class ImportManager extends BaseManager {
|
|
|
344
354
|
runImport(request: IceRunRequest, ctx: ActorContext): Promise<IceRunReport>;
|
|
345
355
|
/**
|
|
346
356
|
* Queue an import as background work and return its run id at once. The
|
|
347
|
-
* run carries `ctx` — the
|
|
357
|
+
* run carries `ctx` — the user who asked (`jobContextFromRequest`), or a
|
|
348
358
|
* job's context with its reason — and each receiver checks its own
|
|
349
|
-
* permission with it when the run reaches it (D5).
|
|
359
|
+
* permission with it when the run reaches it (D5). A user's upload, from
|
|
360
|
+
* a request, goes through {@link enqueueUpload} instead.
|
|
350
361
|
*/
|
|
351
362
|
enqueueImport(request: IceRunRequest, ctx: JobContext): Promise<string>;
|
|
363
|
+
/**
|
|
364
|
+
* Queue a user's upload, from the request it arrived in (#2034). `ctx` is
|
|
365
|
+
* the REQUEST's context; the run carries the job context derived from it
|
|
366
|
+
* (`jobContextFromRequest`), as {@link enqueueImport} does.
|
|
367
|
+
*
|
|
368
|
+
* When the run keeps originals through a receiver that keeps into an
|
|
369
|
+
* encrypted store (`keepsEncrypted`), they are kept first, here, with
|
|
370
|
+
* `ctx`, while the user's key is in the request: the bytes are sealed and
|
|
371
|
+
* the store's sealed index entry written. Each is recorded in the ledger
|
|
372
|
+
* as the keep-once record (#2011), so the run reuses it and needs no key.
|
|
373
|
+
*
|
|
374
|
+
* @throws ImportUploadRefused when an original could not be kept; nothing is queued
|
|
375
|
+
*/
|
|
376
|
+
enqueueUpload(request: IceRunRequest, ctx: ActorContext): Promise<string>;
|
|
377
|
+
private enqueueResolved;
|
|
352
378
|
/** A run's report, to the person it runs as; null to anyone else. */
|
|
353
379
|
getImportRun(runId: string, ctx: ActorContext): IceRunReport | null;
|
|
354
380
|
/** The runs this process holds for the user `ctx` names, newest first (#2021): their own, never anyone else's. */
|
|
@@ -357,6 +383,8 @@ declare class ImportManager extends BaseManager {
|
|
|
357
383
|
setImportLedger(ledger: IceLedger): void;
|
|
358
384
|
private newRunReport;
|
|
359
385
|
private executeRun;
|
|
386
|
+
/** What a run, or keeping at upload, works with. */
|
|
387
|
+
private iceDeps;
|
|
360
388
|
private enabledShims;
|
|
361
389
|
/**
|
|
362
390
|
* Hand the queue to the background job. One job run drains every queued
|
|
@@ -37,8 +37,8 @@ export type LinkOfferOutcome = 'sent' | 'no-match' | 'several' | 'unavailable' |
|
|
|
37
37
|
* person keeps its `@id` and takes the account; the person made for the new
|
|
38
38
|
* account is folded into it and removed, so there is never a second person.
|
|
39
39
|
*
|
|
40
|
-
* `getByUserIdentifier(ctx, username)`
|
|
41
|
-
*
|
|
40
|
+
* `getByUserIdentifier(ctx, username)` returns a user's identity record and
|
|
41
|
+
* makes it when the user has none (#2037): every user has exactly one.
|
|
42
42
|
*/
|
|
43
43
|
declare class PersonManager extends BaseManager {
|
|
44
44
|
readonly description = "Canonical Person records (#617)";
|
|
@@ -51,6 +51,8 @@ declare class PersonManager extends BaseManager {
|
|
|
51
51
|
private metricsRef;
|
|
52
52
|
/** Sign-up link offers by token (#1930). In memory: a restart drops them, and an administrator links by hand. */
|
|
53
53
|
private linkOffers;
|
|
54
|
+
/** #2037: making a user's missing identity record, one at a time per username. */
|
|
55
|
+
private readonly accountRecords;
|
|
54
56
|
constructor(engine: WikiEngine);
|
|
55
57
|
initialize(config?: Record<string, unknown>): Promise<void>;
|
|
56
58
|
/** `ngdpbase.application.persons.storagedir`, resolved: where the records are. */
|
|
@@ -155,13 +157,20 @@ declare class PersonManager extends BaseManager {
|
|
|
155
157
|
*/
|
|
156
158
|
invalidateCache(): void;
|
|
157
159
|
/**
|
|
158
|
-
*
|
|
160
|
+
* The identity record of the user `username`, made when the user has none
|
|
161
|
+
* (#2037). Every user has exactly one identity record; one made outside
|
|
162
|
+
* `UserManager.createUser` (an account written straight into the user
|
|
163
|
+
* store) gets it here, from the account's display name and email.
|
|
159
164
|
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
+
* The read is decided as {@link getByIdentifier} (#2018): a signed-in user's
|
|
166
|
+
* own under `profile-manage`, anyone else's under `contact-read`, core's own
|
|
167
|
+
* work under the system context. Making the missing record is core's
|
|
168
|
+
* bookkeeping, not the caller's contact management, so it goes through
|
|
169
|
+
* {@link create} under the system context, naming the caller, and is
|
|
170
|
+
* recorded as `contact-manage`. One at a time per username, so two lookups
|
|
171
|
+
* never make two records. Null when there is no account by that name.
|
|
172
|
+
* Never a second record: a contact with the same email is left alone
|
|
173
|
+
* (an administrator links it, {@link linkAccount}).
|
|
165
174
|
*/
|
|
166
175
|
getByUserIdentifier(ctx: ActorContext, username: string): Promise<Person | null>;
|
|
167
176
|
private requireProvider;
|
|
@@ -67,8 +67,9 @@ declare class RoleManager extends BaseManager {
|
|
|
67
67
|
* The pseudo-roles `'Authenticated'` and `'All'` are NOT added here — the
|
|
68
68
|
* caller adds those when constructing `userContext.roles`.
|
|
69
69
|
*
|
|
70
|
-
* Returns `[]` when PersonManager is unavailable,
|
|
71
|
-
*
|
|
70
|
+
* Returns `[]` when PersonManager is unavailable, there is no account by
|
|
71
|
+
* that username, no record lists them, or the lookup throws. An account
|
|
72
|
+
* missing its identity record gets it here (#2037).
|
|
72
73
|
*
|
|
73
74
|
* `ctx` is who is asking (#2018), decided by PersonManager's door: a user
|
|
74
75
|
* about themselves under `profile-manage`, about anyone else under
|
|
@@ -340,6 +340,17 @@ declare class UserManager extends BaseManager {
|
|
|
340
340
|
private withAccountRoles;
|
|
341
341
|
/** `ngdpbase.user.account-roles`: the roles every account holds (#1539). */
|
|
342
342
|
private accountRoles;
|
|
343
|
+
/**
|
|
344
|
+
* Every account has exactly one identity record, made by `createUser`
|
|
345
|
+
* (#2037). One that has none (written straight into the user store, or
|
|
346
|
+
* whose record was lost) gets it at boot, once, through PersonManager's
|
|
347
|
+
* door under the system context, each creation recorded as
|
|
348
|
+
* `contact-manage`. The identity records are listed once and only the
|
|
349
|
+
* missing ones are made, so a large user store costs one read. A failure
|
|
350
|
+
* is logged and the boot goes on: the role paths make the record when the
|
|
351
|
+
* account is next used (`getByUserIdentifier`).
|
|
352
|
+
*/
|
|
353
|
+
private giveIdentityRecordsToAccountsWithout;
|
|
343
354
|
/**
|
|
344
355
|
* Accounts made before a role joined `ngdpbase.user.account-roles` get it
|
|
345
356
|
* once, at boot (#1539) — RoleManager decides "once" and records each grant.
|
|
@@ -506,6 +517,11 @@ declare class UserManager extends BaseManager {
|
|
|
506
517
|
/**
|
|
507
518
|
* Search users by username, displayName, or email (case-insensitive substring).
|
|
508
519
|
* Optionally filter by role and active status.
|
|
520
|
+
*
|
|
521
|
+
* Decides `search-user` itself, with `ctx` (#2018): every user holds it as
|
|
522
|
+
* shipped, anonymous does not. A refusal throws `ContactRefusedError`. Core's
|
|
523
|
+
* own lookups (a notice's recipients, a role's holders) pass the system
|
|
524
|
+
* context with a reason, allowed without a policy evaluation.
|
|
509
525
|
*/
|
|
510
526
|
searchUsers(query: string, options: {
|
|
511
527
|
role?: string;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consent to a site's documents (#1603): the shapes ConsentManager and its
|
|
3
|
+
* callers share, and what an add-on registers.
|
|
4
|
+
*/
|
|
5
|
+
/** Where a person is asked to accept (#1603): `?scope=` (core when absent) and `?returnTo=`. */
|
|
6
|
+
export const CONSENT_PATH = '/consent';
|
|
7
|
+
/** The scope of core's own documents, `ngdpbase.consent.documents`. */
|
|
8
|
+
export const CORE_CONSENT_SCOPE = 'core';
|
|
9
|
+
/**
|
|
10
|
+
* Thrown when a per-person add-on is turned on before its documents are
|
|
11
|
+
* accepted (#1603). `documents` names what is still to accept.
|
|
12
|
+
*/
|
|
13
|
+
export class ConsentRequiredError extends Error {
|
|
14
|
+
scope;
|
|
15
|
+
documents;
|
|
16
|
+
name = 'ConsentRequiredError';
|
|
17
|
+
constructor(scope, documents) {
|
|
18
|
+
super(`Turning ${scope} on needs its ${documents.join(' and ')} accepted first`);
|
|
19
|
+
this.scope = scope;
|
|
20
|
+
this.documents = documents;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -12,11 +12,15 @@
|
|
|
12
12
|
* @see https://schema.org/Organization
|
|
13
13
|
*/
|
|
14
14
|
/**
|
|
15
|
-
* Schema.org PostalAddress (subset used by Organization)
|
|
15
|
+
* Schema.org PostalAddress (subset used by Organization/Person).
|
|
16
|
+
*
|
|
17
|
+
* In schema.org a PostalAddress is a ContactPoint, so it carries the
|
|
18
|
+
* ContactPoint fields too: a `contactPoint[]` entry may be one (a mailing or
|
|
19
|
+
* business address, with its `contactType`, `name` and `telephone`).
|
|
16
20
|
*
|
|
17
21
|
* @see https://schema.org/PostalAddress
|
|
18
22
|
*/
|
|
19
|
-
export interface PostalAddress {
|
|
23
|
+
export interface PostalAddress extends Omit<ContactPoint, '@type'> {
|
|
20
24
|
'@type': 'PostalAddress';
|
|
21
25
|
streetAddress?: string | null;
|
|
22
26
|
addressLocality?: string | null;
|
|
@@ -32,11 +36,19 @@ export interface PostalAddress {
|
|
|
32
36
|
export interface ContactPoint {
|
|
33
37
|
'@type': 'ContactPoint';
|
|
34
38
|
contactType?: string;
|
|
39
|
+
/** Who or what this contact point reaches, e.g. an agent's or an emergency contact's name (schema.org Thing.name). */
|
|
40
|
+
name?: string;
|
|
35
41
|
email?: string;
|
|
36
42
|
telephone?: string;
|
|
37
43
|
url?: string;
|
|
38
44
|
availableLanguage?: string[];
|
|
39
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* One `contactPoint[]` entry: a ContactPoint, or a PostalAddress (schema.org's
|
|
48
|
+
* ContactPoint subtype). Typed by `contactType` (`mailing`, `business`,
|
|
49
|
+
* `agent`, `emergency`, …); the home address stays in `address`.
|
|
50
|
+
*/
|
|
51
|
+
export type ContactPointEntry = ContactPoint | PostalAddress;
|
|
40
52
|
/**
|
|
41
53
|
* Canonical Organization record.
|
|
42
54
|
*
|
|
@@ -62,8 +74,8 @@ export interface Organization {
|
|
|
62
74
|
foundingDate?: string;
|
|
63
75
|
/** Postal address */
|
|
64
76
|
address?: PostalAddress;
|
|
65
|
-
/** Contact points (support, sales, etc.) */
|
|
66
|
-
contactPoint?:
|
|
77
|
+
/** Contact points (support, sales, a mailing address, etc.) */
|
|
78
|
+
contactPoint?: ContactPointEntry[];
|
|
67
79
|
/** Other URLs that identify this org (LinkedIn, Twitter, etc.) */
|
|
68
80
|
sameAs?: string[];
|
|
69
81
|
/** Optional legacy slug or external identifier */
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* @see https://schema.org/Person
|
|
17
17
|
*/
|
|
18
|
-
import type { PostalAddress,
|
|
18
|
+
import type { PostalAddress, ContactPointEntry } from './Organization.js';
|
|
19
19
|
/**
|
|
20
20
|
* One organization a person is affiliated with (#1930): schema.org
|
|
21
21
|
* `affiliation`, with the person's role or title there when one is known.
|
|
@@ -51,8 +51,8 @@ export interface Person {
|
|
|
51
51
|
email?: string;
|
|
52
52
|
/** Postal address */
|
|
53
53
|
address?: PostalAddress;
|
|
54
|
-
/**
|
|
55
|
-
contactPoint?:
|
|
54
|
+
/** Everything but the home address: phones, a mailing or business address (a PostalAddress), an agent, an emergency contact; each typed by `contactType`. */
|
|
55
|
+
contactPoint?: ContactPointEntry[];
|
|
56
56
|
/** ISO language tags this person knows */
|
|
57
57
|
knowsLanguage?: string[];
|
|
58
58
|
/** Profile/avatar image URL */
|
|
@@ -67,6 +67,13 @@ export declare function isSystemWork(engine: EngineLike, ctx: ActorContext | nul
|
|
|
67
67
|
export declare function requireRecordAccess(engine: EngineLike, ctx: ActorContext, kind: keyof typeof CONTACT_PERMISSION, record?: {
|
|
68
68
|
identifier?: unknown;
|
|
69
69
|
} | null): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* A lookup of users (#2018): `UserManager.searchUsers` asks `permission`
|
|
72
|
+
* (`search-user`) with the caller's context, and throws
|
|
73
|
+
* {@link ContactRefusedError} on a refusal. Core's own work
|
|
74
|
+
* ({@link isSystemWork}) is allowed without a policy evaluation.
|
|
75
|
+
*/
|
|
76
|
+
export declare function requireLookupPermission(engine: EngineLike, ctx: ActorContext, permission: CorePermission): Promise<void>;
|
|
70
77
|
/** What a contacts record says was done. Names fields, never their values. */
|
|
71
78
|
export interface ContactChange {
|
|
72
79
|
kind: 'person' | 'organization';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jwilleke/ngdpbase-types",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.29.1",
|
|
4
4
|
"description": "TypeScript types for ngdpbase add-ons, and a test kit of core's own values. A dev dependency, versioned with ngdpbase.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Jim Willeke",
|