@phis/contracts 0.2.0 → 0.4.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/NOTICE +1 -1
- package/README.md +175 -67
- package/dist/access.d.ts +63 -0
- package/dist/access.js +78 -0
- package/dist/addon-index.d.ts +5 -0
- package/dist/addon-index.js +5 -0
- package/dist/addon.d.ts +181 -57
- package/dist/addon.js +2 -2
- package/dist/assets.d.ts +165 -0
- package/dist/assets.js +1 -0
- package/dist/capabilities.d.ts +175 -33
- package/dist/capabilities.js +2 -2
- package/dist/catalog.d.ts +104 -0
- package/dist/catalog.js +116 -0
- package/dist/cms.d.ts +120 -0
- package/dist/cms.js +270 -0
- package/dist/core.d.ts +52 -6
- package/dist/core.js +55 -8
- package/dist/http.d.ts +33 -0
- package/dist/http.js +33 -0
- package/dist/locale.d.ts +14 -0
- package/dist/locale.js +14 -0
- package/dist/logging.d.ts +49 -0
- package/dist/logging.js +17 -0
- package/dist/media-storage.d.ts +371 -0
- package/dist/media-storage.js +84 -0
- package/dist/media.d.ts +272 -0
- package/dist/media.js +421 -0
- package/dist/queries.d.ts +280 -48
- package/dist/queries.js +10 -1
- package/dist/resource-links.d.ts +94 -0
- package/dist/resource-links.js +27 -0
- package/dist/schema.d.ts +160 -26
- package/dist/schema.js +11 -2
- package/dist/server-capabilities.d.ts +37 -0
- package/dist/server-capabilities.js +17 -0
- package/dist/signals.d.ts +58 -0
- package/dist/signals.js +118 -0
- package/dist/site-groups.d.ts +53 -0
- package/dist/site-groups.js +54 -0
- package/dist/support.d.ts +390 -0
- package/dist/support.js +148 -0
- package/dist/threads.d.ts +363 -0
- package/dist/threads.js +146 -0
- package/dist/translation.d.ts +125 -0
- package/dist/translation.js +15 -0
- package/dist/user-state.d.ts +132 -0
- package/dist/user-state.js +92 -0
- package/package.json +64 -4
- package/dist/index.d.ts +0 -6
- package/dist/index.js +0 -6
package/NOTICE
CHANGED
package/README.md
CHANGED
|
@@ -1,102 +1,210 @@
|
|
|
1
1
|
# @phis/contracts
|
|
2
2
|
|
|
3
|
-
The agreements
|
|
4
|
-
|
|
3
|
+
The agreements phis (`@phis/server`) keeps with what surrounds it: the site UI (`@phis/ui`), Sites, and
|
|
4
|
+
separately shipped Add-ons. Each lives under its own subpath, because they hold between different parties
|
|
5
|
+
and change at different moments.
|
|
5
6
|
|
|
6
7
|
```
|
|
7
|
-
@phis/contracts/addon
|
|
8
|
-
@phis/contracts/access
|
|
9
|
-
@phis/contracts/signals
|
|
8
|
+
@phis/contracts/addon what phis and a separately shipped Add-on promise each other
|
|
9
|
+
@phis/contracts/access the authorization vocabulary phis and @phis/ui both evaluate
|
|
10
|
+
@phis/contracts/signals the signal vocabulary and address grammar the UI declares in and phis validates
|
|
11
|
+
@phis/contracts/catalog the Module categories an Add-on declares, the UI groups by and a market filters on
|
|
12
|
+
@phis/contracts/cms the CMS node identity both sides derive, and must derive alike
|
|
13
|
+
@phis/contracts/media the Asset vocabularies both sides store, filter on and judge
|
|
14
|
+
@phis/contracts/http the request headers phis and the site UI must spell the same way
|
|
15
|
+
@phis/contracts/locale the locale this software is authored in
|
|
16
|
+
@phis/contracts/logging the structured log vocabulary a Site writes and phis reads back
|
|
17
|
+
@phis/contracts/server-capabilities the capability snapshot phis reports and the UI acts on
|
|
18
|
+
@phis/contracts/site-groups the membership levels of a Site group, as both ends count them
|
|
19
|
+
@phis/contracts/user-state the shapes a Module may keep a person's decisions in, and the key grammar
|
|
10
20
|
```
|
|
11
21
|
|
|
12
|
-
|
|
13
|
-
two of our packages happen to share; a subpath makes you say which agreement you mean.
|
|
22
|
+
## Before the v1 release, interface versions stay at 1
|
|
14
23
|
|
|
15
|
-
|
|
24
|
+
`PHIS_SERVICE_INTERFACE_VERSIONS` and `PHIS_SERVICE_INTERFACE_DIGESTS` in `@phis/contracts/addon` are not
|
|
25
|
+
raised while phis is pre-v1, however much an interface changes. The mechanism they drive is real and
|
|
26
|
+
deliberate -- Core refuses an Add-on whose recorded manifest names a digest this release does not offer --
|
|
27
|
+
and that is exactly why raising a version now is the wrong move: there is no released Add-on to protect, so
|
|
28
|
+
it buys no compatibility, and it takes the installation down. The recorded manifest in
|
|
29
|
+
`config/phis-addons.json` stops matching, the capability snapshot refuses the desired state, and every
|
|
30
|
+
request that resolves a viewer answers 500 until each installed Add-on has been rebundled and upgraded.
|
|
16
31
|
|
|
17
|
-
|
|
18
|
-
|
|
32
|
+
An interface that changes before v1 is simply the interface. Both sides are rebuilt from one tree, and the
|
|
33
|
+
version is raised once, when there is something in the field that a wrong assumption would break.
|
|
19
34
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
against; it must not depend on phi-server itself.
|
|
35
|
+
There is deliberately no root export. A package you can import from the top invites everything two of
|
|
36
|
+
our packages happen to share; a subpath makes you say which agreement you mean.
|
|
23
37
|
|
|
24
38
|
```sh
|
|
25
|
-
npm install
|
|
39
|
+
npm install @phis/contracts
|
|
26
40
|
```
|
|
27
41
|
|
|
28
|
-
|
|
29
|
-
|
|
42
|
+
## `/addon`
|
|
43
|
+
|
|
44
|
+
The types and constants an Add-on declares or implements. Types and constants only: no runtime code, no
|
|
45
|
+
`server-only`, no React, no Next.
|
|
46
|
+
|
|
47
|
+
An Add-on is compiled to a single ESM artifact and installed into a running phis through the `phis` CLI;
|
|
48
|
+
it is never built into the server. This subpath is the only thing an Add-on compiles against, and it must
|
|
49
|
+
not depend on phis itself. For an Add-on author it is a build-time dependency: everything it exports is
|
|
50
|
+
erased at compile time apart from a handful of constants.
|
|
51
|
+
|
|
52
|
+
What it covers:
|
|
53
|
+
|
|
54
|
+
- **Manifest** -- `PhisAddonManifestV1`: identity, version, required Core capabilities, the routes an
|
|
55
|
+
Add-on claims, the services it provides.
|
|
56
|
+
- **Runtime** -- `PhisAddonRuntimeV1`, `PhisAddonHandler`, `PhisAddonRequestContext`. The artifact
|
|
57
|
+
exports it under the name `phisAddon` (`PhisAddonRuntimeModuleV1`).
|
|
58
|
+
- **Schema** -- `PhisAddonSchemaDescriptor` and its column, index and constraint descriptors. Tables are
|
|
59
|
+
declared, not migrated by hand; phis applies them.
|
|
60
|
+
- **Service kinds** -- the Core-owned kinds an Add-on may supply an implementation of: Media Storage
|
|
61
|
+
(`PhisMediaStorageAdapter`, upload plans, object I/O) and Directory. `PHIS_SERVICE_KINDS` names them
|
|
62
|
+
and `PHIS_SERVICE_INTERFACE_DIGESTS` holds the digest of each kind's current interface; Core refuses an
|
|
63
|
+
Add-on built against a different digest at install.
|
|
64
|
+
- **Core capabilities** -- `PHIS_CORE_CAPABILITIES`, the capability ids an Add-on may require. Declare
|
|
65
|
+
against these constants rather than spelling the ids out. The list is the vocabulary and may reserve a
|
|
66
|
+
name before Core delivers it (`resource-links`, `support`); an Add-on that requires a capability this
|
|
67
|
+
release does not deliver is refused rather than handed a missing object.
|
|
68
|
+
|
|
69
|
+
`PHIS_ADDON_ABI_VERSION` is the single number phis checks an Add-on against.
|
|
70
|
+
|
|
71
|
+
How an Add-on is laid out, compiled, installed, activated and upgraded is described in phis's
|
|
72
|
+
[`ADDON_HOWTO.md`](https://github.com/phis-dev/phis-server/blob/main/ADDON_HOWTO.md); the rules behind it
|
|
73
|
+
are in [`SERVER_ADDONS.md`](https://github.com/phis-dev/phis-server/blob/main/SERVER_ADDONS.md).
|
|
30
74
|
|
|
31
75
|
## `/access`
|
|
32
76
|
|
|
33
|
-
Claim shapes, policy shapes, and the evaluator that decides them. Unlike `/addon`, this
|
|
34
|
-
|
|
77
|
+
Claim shapes, policy shapes, and the evaluator that decides them. Unlike `/addon`, this is runtime code
|
|
78
|
+
and a real dependency of both packages that use it.
|
|
35
79
|
|
|
36
|
-
Two processes decide the same question.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
80
|
+
Two processes decide the same question. phis decides it in its guards and API routes; a Site decides it
|
|
81
|
+
while rendering -- per navigation entry, per tree node, and in the browser, where phis is not reachable
|
|
82
|
+
without a round trip. Neither can defer to the other, so both evaluate, and one compiled source is the
|
|
83
|
+
only way both reach the same answer: a stored claim normalised on one side and not on the other admits
|
|
84
|
+
on one and refuses on the other, and neither copy looks wrong on its own.
|
|
40
85
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
looked wrong on its own, which is why it went unnoticed.
|
|
86
|
+
Each side keeps its own viewer type and passes a projection onto `PhiAccessSubject`, so neither package
|
|
87
|
+
adopts the other's shape.
|
|
44
88
|
|
|
45
|
-
|
|
46
|
-
|
|
89
|
+
## `/cms`
|
|
90
|
+
|
|
91
|
+
The encoding of a CMS node's identity: how a Preset node's id is derived from the Module, the preset and
|
|
92
|
+
the node key, and how a draft node's id is derived from the revision it was made in.
|
|
93
|
+
|
|
94
|
+
It is arithmetic both sides must compute alike. A Preset id is derived rather than allocated, so the site
|
|
95
|
+
UI can address a node before any row exists and phis can check that stored wiring points at nodes that
|
|
96
|
+
really exist. A changed constant on one side produces ids that are still well formed and simply name
|
|
97
|
+
nothing. The Page-key convention and the map helper built on top stay with `@phis/ui`.
|
|
47
98
|
|
|
48
99
|
## `/signals`
|
|
49
100
|
|
|
50
|
-
The closed vocabularies a
|
|
51
|
-
|
|
101
|
+
The closed vocabularies a Widget's wiring is written in -- scopes, actions, value types -- the shape of a
|
|
102
|
+
value schema name, and the address families.
|
|
52
103
|
|
|
53
|
-
A
|
|
54
|
-
the
|
|
55
|
-
|
|
56
|
-
|
|
104
|
+
A Widget declares what it emits and listens for, the Builder stores that, phis validates it on the way
|
|
105
|
+
in, and the Site delivers it at runtime, so all of them parse the same strings. The rule that says which
|
|
106
|
+
receivers a scope admits, and the controller address the Site scope privileges, live here for the same
|
|
107
|
+
reason.
|
|
57
108
|
|
|
58
|
-
Which schemas exist stays with the UI.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
every third party's schema for never having heard of it.
|
|
109
|
+
Which schemas exist stays with the UI. phis checks that a JSON signal names *a* schema, never which one:
|
|
110
|
+
`isPhiSignalValueSchemaShape` checks the shape, not membership. The UI asks the stricter question because
|
|
111
|
+
it holds the Module registry; phis must not, or it would refuse every third party's schema.
|
|
62
112
|
|
|
63
|
-
##
|
|
113
|
+
## `/catalog`
|
|
64
114
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
`PhiServerAddonRequestContext`: the shape the artifact's default export must have.
|
|
69
|
-
- **Schema** — `PhiServerAddonSchemaDescriptor` and its column, index, and constraint
|
|
70
|
-
descriptors. Tables are declared, not migrated by hand; phi-server applies them.
|
|
71
|
-
- **Service kinds** — the interfaces an Add-on may provide or consume, currently the media
|
|
72
|
-
storage adapter (`PhisMediaStorageAdapter`, upload plans, object I/O).
|
|
73
|
-
- **What Core offers** — `PHI_SERVER_CORE_CAPABILITIES`, the capability ids an Add-on may
|
|
74
|
-
require; `PHI_SERVER_SERVICE_KINDS`, the service kinds Core owns; and
|
|
75
|
-
`PHI_SERVER_SERVICE_INTERFACE_DIGESTS`, the digest of each kind's current interface. Declare
|
|
76
|
-
against these names rather than spelling them out: Core refuses an Add-on whose digest is not
|
|
77
|
-
the one this release offers, and a literal cannot be checked before you ship it.
|
|
115
|
+
What a Module is for, as one closed list: `foundation`, `workspace`, `content`, `media`, `commerce`,
|
|
116
|
+
`identity`, `communication`, `events`, `analytics`, `integration`, `operations`, `other`
|
|
117
|
+
(`PHI_RUNTIME_MODULE_CATEGORIES`).
|
|
78
118
|
|
|
79
|
-
|
|
80
|
-
|
|
119
|
+
An Add-on declares it per Module, because a package may ship a shop and a report and neither answer would
|
|
120
|
+
be true of the other. The site UI groups the Modules page by it, and a marketplace Add-on -- which
|
|
121
|
+
compiles against this package and nothing else -- filters on it.
|
|
81
122
|
|
|
82
|
-
`
|
|
123
|
+
It is not in `/addon` on purpose: `/addon` is the ABI a third party compiles against, and this list grows
|
|
124
|
+
with the product. phis does not ask the membership question either; a manifest carries categories as
|
|
125
|
+
plain strings, Core checks the shape, and the strict question is asked where a registry is held. The
|
|
126
|
+
labels an operator reads are label-set keys owned by the UI; this subpath holds identifiers only.
|
|
83
127
|
|
|
84
|
-
|
|
128
|
+
Beside the vocabulary sits the shape a Module package declares itself in, under `phis` in its
|
|
129
|
+
`package.json`: which Modules it carries, each one's category, and the language their titles and
|
|
130
|
+
descriptions are written in. Reading that from `package.json` means nobody has to execute a stranger's
|
|
131
|
+
package to list it. The author writes it; `phis module` checks that the entries are present and well
|
|
132
|
+
formed, and a package that declares nothing is refused at intake.
|
|
133
|
+
|
|
134
|
+
## `/media`
|
|
135
|
+
|
|
136
|
+
The words and numbers a Site and phis must read the same way about an Asset: the Space kind's wire name,
|
|
137
|
+
the media kinds, the Folder flags, the presentation flags, the image variant keys, and the two closed
|
|
138
|
+
vocabularies that decide deliverability -- `lifecycle_status` and `delivery_policy`.
|
|
139
|
+
|
|
140
|
+
These values travel and are judged on the other side. The site UI sends a flag mask as a list filter and
|
|
141
|
+
flag values when metadata is saved, and phis filters with `presentation_flags & mask <> 0` and refuses a
|
|
142
|
+
value it does not know. An Asset payload carries `lifecycleStatus` and `deliveryPolicy` as stored, and
|
|
143
|
+
the UI decides from them whether `next/image` may be pointed at the original.
|
|
144
|
+
|
|
145
|
+
The resolvers come with their vocabulary: `normalizePhiMediaKind` and `resolvePhiMediaKindFromContentType`
|
|
146
|
+
map onto the kind list, so an upload is filed and listed as the same kind on both sides. How a delivery
|
|
147
|
+
URL is built stays with each side, and phis's numeric Space kind never reaches a Site.
|
|
148
|
+
|
|
149
|
+
## `/http`
|
|
85
150
|
|
|
86
|
-
|
|
151
|
+
The request header names phis reads and the site UI writes: `PHIS_TOKEN_HEADER` (`x-phis-token`),
|
|
152
|
+
`PHIS_SITE_KEY_HEADER`, `PHIS_AREA_HEADER`, `PHIS_REQUEST_PATH_HEADER` and `PHIS_REQUEST_SEARCH_HEADER`.
|
|
153
|
+
A disagreement here is not a type error but a 403 or 400 at runtime.
|
|
87
154
|
|
|
88
|
-
|
|
89
|
-
|
|
155
|
+
## `/locale`
|
|
156
|
+
|
|
157
|
+
`PHI_CANONICAL_SOURCE_LOCALE`: the locale every label, email template and global message is authored in,
|
|
158
|
+
and therefore the one a translation starts from. It is not a Site's default locale, which is per-Site
|
|
159
|
+
configuration.
|
|
160
|
+
|
|
161
|
+
## `/logging`
|
|
162
|
+
|
|
163
|
+
The structured log vocabulary: `PhiLogService` (`phis`, `ui`, `site`, `cli`), `PhiLogLevel`,
|
|
164
|
+
`PhiLoggerContext`, `PhiLogEvent` and the `PhiLogger` interface. A Site and phis both write these records
|
|
165
|
+
to journald, and the log surface in phis parses them back, filtering by exactly these services and
|
|
166
|
+
fields. How a line is serialised is each writer's own concern.
|
|
167
|
+
|
|
168
|
+
## `/server-capabilities`
|
|
169
|
+
|
|
170
|
+
The snapshot `/api/v1/site/capabilities` reports: per provider (Core or an Add-on), the capabilities it
|
|
171
|
+
offers and its state (`PhiCapabilitySnapshot`, `PhiCapabilityProvider`, `PhiCapabilityState`). phis
|
|
172
|
+
decides the verdict; the site UI acts on it, deactivating a Module whose provider is not `available` and
|
|
173
|
+
naming the reason in its diagnostics.
|
|
174
|
+
|
|
175
|
+
## `/site-groups`
|
|
176
|
+
|
|
177
|
+
The membership ladder of a Site group: `PhiGroupMembershipFlags` (`Member`, `Author`, `Editor`,
|
|
178
|
+
`Manager`, cumulative bits), `PHI_GROUP_MEMBERSHIP_LEVELS` and `readPhiGroupMembershipLevel`. The site UI
|
|
179
|
+
sends `membershipFlags` as an integer and offers the levels to choose from, so both ends must count the
|
|
180
|
+
same bits. The Add-on boundary names levels instead (`PHIS_GROUP_LEVELS` in `/addon`).
|
|
181
|
+
|
|
182
|
+
## `/user-state`
|
|
183
|
+
|
|
184
|
+
What a Module may keep per Site about a person who decided something: the closed shape set
|
|
185
|
+
(`PHIS_USER_STATE_SHAPES` -- `flag`, `marker`, `value`, `set`), the `<package>/<key>` grammar, the
|
|
186
|
+
declaration a Module makes (`PhisDeclarableUserStateKey`), and `readPhisUserStateWrite`, which both ends
|
|
187
|
+
call so a refused write is refused the same way in both. phis stores it and is the only party that
|
|
188
|
+
validates; the site UI declares the keys and reads them while rendering. Core's own account facts stay
|
|
189
|
+
bit flags on the membership and account rows and are not this.
|
|
190
|
+
|
|
191
|
+
## Admission rule
|
|
90
192
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
convenience, not a contract, and belongs to neither.
|
|
193
|
+
Per subpath, and narrow on purpose. Name the two parties and the sentence they promise each other; if that
|
|
194
|
+
sentence cannot be written down, it does not go in here.
|
|
94
195
|
|
|
95
|
-
|
|
96
|
-
|
|
196
|
+
- `/addon`: only what phis and a separately shipped Add-on must agree on. Declarations, never
|
|
197
|
+
implementations.
|
|
198
|
+
- `/access`: only what phis and `@phis/ui` must both evaluate, each in its own process. A helper both
|
|
199
|
+
happen to use is convenience, not a contract.
|
|
200
|
+
- `/catalog`: only vocabularies an Add-on declares a Module in and another party reads back -- closed
|
|
201
|
+
lists of identifiers, never the words an operator sees.
|
|
202
|
+
- `/media`, `/http`, `/logging`, `/site-groups`, `/server-capabilities`: only what crosses the wire as a
|
|
203
|
+
value and is judged on the other side. A copy is a contract when disagreeing about it changes what a
|
|
204
|
+
request returns.
|
|
205
|
+
- `/user-state`: only the shapes and the key grammar both ends check a write against. What a Module keeps
|
|
206
|
+
under its keys is the Module's business and never named here.
|
|
97
207
|
|
|
98
|
-
##
|
|
208
|
+
## License
|
|
99
209
|
|
|
100
|
-
|
|
101
|
-
upgraded — lives in phi-server's `ADDON_HOWTO.md`, with the design rationale in
|
|
102
|
-
`SERVER_ADDONS.md`.
|
|
210
|
+
Apache-2.0. See `LICENSE` and `NOTICE`.
|
package/dist/access.d.ts
CHANGED
|
@@ -29,7 +29,70 @@ export declare const PhiBaseRole: {
|
|
|
29
29
|
readonly Developer: number;
|
|
30
30
|
readonly Supporter: number;
|
|
31
31
|
readonly Accountant: number;
|
|
32
|
+
/**
|
|
33
|
+
* Works here, and needs nothing else.
|
|
34
|
+
*
|
|
35
|
+
* It grants no capability at all, which is what it is for: being Staff decides who may be written to
|
|
36
|
+
* and who may open a thread with a colleague, and until this bit existed the only way to say it was to
|
|
37
|
+
* hand out a role that also grants something -- a developer bit to somebody who never touches a log.
|
|
38
|
+
*
|
|
39
|
+
* Staff is whoever holds *any* Core role, so every role above implies it and this is the one to give
|
|
40
|
+
* somebody who holds none of them. Roles an Add-on defines never make anybody Staff: they are
|
|
41
|
+
* provider-local and say what a person may do inside that Add-on, which is how somebody outside the
|
|
42
|
+
* company can hold one and remain outside it.
|
|
43
|
+
*/
|
|
44
|
+
readonly Staff: number;
|
|
32
45
|
};
|
|
46
|
+
/**
|
|
47
|
+
* What a stored email address says about itself, as bit flags.
|
|
48
|
+
*
|
|
49
|
+
* `user_emails` holds several addresses per account and marks one of them primary. That mark is a flag
|
|
50
|
+
* rather than its own column because the schema keeps every other such answer in `flags`, and a lone
|
|
51
|
+
* boolean is the one place a reader has to remember an exception.
|
|
52
|
+
*
|
|
53
|
+
* The position is fixed from the first row, and here more strictly than elsewhere: the unique index that
|
|
54
|
+
* enforces "one primary address per account" is partial on this very bit. Move the bit and the index
|
|
55
|
+
* silently guards a different question.
|
|
56
|
+
*/
|
|
57
|
+
export declare const PhiUserEmailFlag: {
|
|
58
|
+
readonly Primary: number;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Where a stored email address came from.
|
|
62
|
+
*
|
|
63
|
+
* The question this answers is asked after the fact and cannot be reconstructed: did this person type
|
|
64
|
+
* their address themselves, did an administrator set it, or did an identity provider hand it over? An
|
|
65
|
+
* account that can be created from a command line makes that difference worth keeping.
|
|
66
|
+
*
|
|
67
|
+
* Numbers rather than free text, because the set is Core's and a string column accepts every typo as a
|
|
68
|
+
* new source. Below 20 are Core's own origins; from 20 upward are named providers, and they are named
|
|
69
|
+
* rather than left to the Add-on that connects them: the Add-on may be replaced, Google will not be.
|
|
70
|
+
* A provider without a number is `Provider`, and which one it was stands in `user_auth_identities`.
|
|
71
|
+
*
|
|
72
|
+
* There is deliberately no `unknown`. Every writer knows why it writes, and a zero default would let
|
|
73
|
+
* the one that does not pass unnoticed.
|
|
74
|
+
*/
|
|
75
|
+
export declare const PhiUserEmailSource: {
|
|
76
|
+
readonly Operator: 1;
|
|
77
|
+
readonly Admin: 2;
|
|
78
|
+
readonly Registration: 3;
|
|
79
|
+
readonly Self: 4;
|
|
80
|
+
readonly Directory: 5;
|
|
81
|
+
readonly Provider: 9;
|
|
82
|
+
readonly Google: 20;
|
|
83
|
+
readonly Apple: 21;
|
|
84
|
+
readonly Microsoft: 22;
|
|
85
|
+
readonly GitHub: 23;
|
|
86
|
+
};
|
|
87
|
+
export type PhiUserEmailSourceValue = (typeof PhiUserEmailSource)[keyof typeof PhiUserEmailSource];
|
|
88
|
+
export declare function isPhiUserEmailSource(value: unknown): value is PhiUserEmailSourceValue;
|
|
89
|
+
/**
|
|
90
|
+
* Which source a login provider's key stands for.
|
|
91
|
+
*
|
|
92
|
+
* The mapping lives here because the numbers do: it is this file that says 20 means Google. A key with
|
|
93
|
+
* no number of its own is `Provider` rather than a guess, and `user_auth_identities` keeps the detail.
|
|
94
|
+
*/
|
|
95
|
+
export declare function phiUserEmailSourceForProvider(providerKey: string): PhiUserEmailSourceValue;
|
|
33
96
|
export type PhiRoleProviderId = `@${string}/${string}`;
|
|
34
97
|
export type PhiGroupProviderId = `@${string}/${string}`;
|
|
35
98
|
export type PhiViewerRoleClaim = {
|
package/dist/access.js
CHANGED
|
@@ -29,7 +29,85 @@ export const PhiBaseRole = {
|
|
|
29
29
|
Developer: 1 << 4,
|
|
30
30
|
Supporter: 1 << 5,
|
|
31
31
|
Accountant: 1 << 6,
|
|
32
|
+
/**
|
|
33
|
+
* Works here, and needs nothing else.
|
|
34
|
+
*
|
|
35
|
+
* It grants no capability at all, which is what it is for: being Staff decides who may be written to
|
|
36
|
+
* and who may open a thread with a colleague, and until this bit existed the only way to say it was to
|
|
37
|
+
* hand out a role that also grants something -- a developer bit to somebody who never touches a log.
|
|
38
|
+
*
|
|
39
|
+
* Staff is whoever holds *any* Core role, so every role above implies it and this is the one to give
|
|
40
|
+
* somebody who holds none of them. Roles an Add-on defines never make anybody Staff: they are
|
|
41
|
+
* provider-local and say what a person may do inside that Add-on, which is how somebody outside the
|
|
42
|
+
* company can hold one and remain outside it.
|
|
43
|
+
*/
|
|
44
|
+
Staff: 1 << 7,
|
|
32
45
|
};
|
|
46
|
+
/**
|
|
47
|
+
* What a stored email address says about itself, as bit flags.
|
|
48
|
+
*
|
|
49
|
+
* `user_emails` holds several addresses per account and marks one of them primary. That mark is a flag
|
|
50
|
+
* rather than its own column because the schema keeps every other such answer in `flags`, and a lone
|
|
51
|
+
* boolean is the one place a reader has to remember an exception.
|
|
52
|
+
*
|
|
53
|
+
* The position is fixed from the first row, and here more strictly than elsewhere: the unique index that
|
|
54
|
+
* enforces "one primary address per account" is partial on this very bit. Move the bit and the index
|
|
55
|
+
* silently guards a different question.
|
|
56
|
+
*/
|
|
57
|
+
export const PhiUserEmailFlag = {
|
|
58
|
+
Primary: 1 << 0,
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Where a stored email address came from.
|
|
62
|
+
*
|
|
63
|
+
* The question this answers is asked after the fact and cannot be reconstructed: did this person type
|
|
64
|
+
* their address themselves, did an administrator set it, or did an identity provider hand it over? An
|
|
65
|
+
* account that can be created from a command line makes that difference worth keeping.
|
|
66
|
+
*
|
|
67
|
+
* Numbers rather than free text, because the set is Core's and a string column accepts every typo as a
|
|
68
|
+
* new source. Below 20 are Core's own origins; from 20 upward are named providers, and they are named
|
|
69
|
+
* rather than left to the Add-on that connects them: the Add-on may be replaced, Google will not be.
|
|
70
|
+
* A provider without a number is `Provider`, and which one it was stands in `user_auth_identities`.
|
|
71
|
+
*
|
|
72
|
+
* There is deliberately no `unknown`. Every writer knows why it writes, and a zero default would let
|
|
73
|
+
* the one that does not pass unnoticed.
|
|
74
|
+
*/
|
|
75
|
+
export const PhiUserEmailSource = {
|
|
76
|
+
Operator: 1,
|
|
77
|
+
Admin: 2,
|
|
78
|
+
Registration: 3,
|
|
79
|
+
Self: 4,
|
|
80
|
+
Directory: 5,
|
|
81
|
+
Provider: 9,
|
|
82
|
+
Google: 20,
|
|
83
|
+
Apple: 21,
|
|
84
|
+
Microsoft: 22,
|
|
85
|
+
GitHub: 23,
|
|
86
|
+
};
|
|
87
|
+
export function isPhiUserEmailSource(value) {
|
|
88
|
+
return typeof value === "number"
|
|
89
|
+
&& Object.values(PhiUserEmailSource).includes(value);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Which source a login provider's key stands for.
|
|
93
|
+
*
|
|
94
|
+
* The mapping lives here because the numbers do: it is this file that says 20 means Google. A key with
|
|
95
|
+
* no number of its own is `Provider` rather than a guess, and `user_auth_identities` keeps the detail.
|
|
96
|
+
*/
|
|
97
|
+
export function phiUserEmailSourceForProvider(providerKey) {
|
|
98
|
+
switch (providerKey.trim().toLowerCase()) {
|
|
99
|
+
case "google":
|
|
100
|
+
return PhiUserEmailSource.Google;
|
|
101
|
+
case "apple":
|
|
102
|
+
return PhiUserEmailSource.Apple;
|
|
103
|
+
case "microsoft":
|
|
104
|
+
return PhiUserEmailSource.Microsoft;
|
|
105
|
+
case "github":
|
|
106
|
+
return PhiUserEmailSource.GitHub;
|
|
107
|
+
default:
|
|
108
|
+
return PhiUserEmailSource.Provider;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
33
111
|
/**
|
|
34
112
|
* Flags as they may be trusted.
|
|
35
113
|
*
|
package/dist/addon-index.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
export * from "./addon.js";
|
|
2
|
+
export * from "./assets.js";
|
|
2
3
|
export * from "./capabilities.js";
|
|
3
4
|
export * from "./core.js";
|
|
4
5
|
export * from "./media-storage.js";
|
|
5
6
|
export * from "./queries.js";
|
|
7
|
+
export * from "./resource-links.js";
|
|
6
8
|
export * from "./schema.js";
|
|
9
|
+
export * from "./support.js";
|
|
10
|
+
export * from "./threads.js";
|
|
11
|
+
export * from "./translation.js";
|
package/dist/addon-index.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
export * from "./addon.js";
|
|
2
|
+
export * from "./assets.js";
|
|
2
3
|
export * from "./capabilities.js";
|
|
3
4
|
export * from "./core.js";
|
|
4
5
|
export * from "./media-storage.js";
|
|
5
6
|
export * from "./queries.js";
|
|
7
|
+
export * from "./resource-links.js";
|
|
6
8
|
export * from "./schema.js";
|
|
9
|
+
export * from "./support.js";
|
|
10
|
+
export * from "./threads.js";
|
|
11
|
+
export * from "./translation.js";
|