@oxyhq/contracts 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/accountGraph.js +80 -3
- package/dist/cjs/index.js +11 -5
- package/dist/cjs/userResponse.js +21 -1
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/accountGraph.js +77 -2
- package/dist/esm/index.js +1 -1
- package/dist/esm/userResponse.js +22 -2
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/accountGraph.d.ts +77 -6
- package/dist/types/index.d.ts +2 -2
- package/dist/types/recommendations.d.ts +14 -14
- package/dist/types/userResponse.d.ts +278 -28
- package/package.json +1 -1
package/dist/esm/accountGraph.js
CHANGED
|
@@ -1,11 +1,71 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Account graph wire contracts —
|
|
2
|
+
* Account graph wire contracts — the account-kind vocabulary, organization
|
|
3
|
+
* taxonomy, and create-account input.
|
|
3
4
|
*
|
|
4
5
|
* `organizationCategory` classifies `kind: 'organization'` accounts (agency,
|
|
5
6
|
* cooperative, landlord, …) without polluting `User.kind`. Meaningful only when
|
|
6
7
|
* `kind === 'organization'`.
|
|
7
8
|
*/
|
|
8
9
|
import { z } from 'zod';
|
|
10
|
+
/**
|
|
11
|
+
* The union is spelled out above and the array proves coverage BOTH ways
|
|
12
|
+
* (`satisfies` here, the `Gap` alias below) — the same shape this package's
|
|
13
|
+
* `ORGANIZATION_CATEGORIES` / `TRUST_TIERS` pairs use, and the one
|
|
14
|
+
* `db/schema/users.ts` mirrors to keep the `users_kind_check` CHECK honest.
|
|
15
|
+
*
|
|
16
|
+
* Deriving the union from the array instead would cost nothing here and be paid
|
|
17
|
+
* by consumers: `kind` travels into `@oxyhq/services` through
|
|
18
|
+
* `SwitchableAccount`, where an indexed-access type is materially more
|
|
19
|
+
* expensive to check than a literal union.
|
|
20
|
+
*/
|
|
21
|
+
export const ACCOUNT_KINDS = [
|
|
22
|
+
'personal',
|
|
23
|
+
'organization',
|
|
24
|
+
'project',
|
|
25
|
+
'bot',
|
|
26
|
+
'channel',
|
|
27
|
+
];
|
|
28
|
+
export const accountKindSchema = z.enum(ACCOUNT_KINDS);
|
|
29
|
+
export const CHILD_ACCOUNT_KINDS = [
|
|
30
|
+
'organization',
|
|
31
|
+
'project',
|
|
32
|
+
'bot',
|
|
33
|
+
'channel',
|
|
34
|
+
];
|
|
35
|
+
export const childAccountKindSchema = z.enum(CHILD_ACCOUNT_KINDS);
|
|
36
|
+
/**
|
|
37
|
+
* Whether an operator may ACT AS an account of this kind — switch the whole app
|
|
38
|
+
* into it (`POST /accounts/:id/switch`) or authorise an app to act as it
|
|
39
|
+
* (an OAuth delegated subject).
|
|
40
|
+
*
|
|
41
|
+
* Two kinds are refused, for opposite reasons:
|
|
42
|
+
*
|
|
43
|
+
* - `personal` is a human login, so assuming it would be impersonation.
|
|
44
|
+
* - `channel` is a CONTENT identity, not an operating one. A channel exists so
|
|
45
|
+
* that posts can be authored BY it; it is never a seat anybody occupies. Its
|
|
46
|
+
* operators act on it through their own membership, and an application
|
|
47
|
+
* publishes to it with its own credential. Refusing act-as is what makes
|
|
48
|
+
* "no login, ever" structural rather than incidental: no session can be
|
|
49
|
+
* minted whose subject is a channel, so no bearer exists that could add an
|
|
50
|
+
* auth method to one (every auth-method write resolves its target from the
|
|
51
|
+
* authenticated subject, never from a parameter).
|
|
52
|
+
*
|
|
53
|
+
* Consumers must gate on this predicate rather than testing `kind === 'personal'`,
|
|
54
|
+
* which silently admits every kind added after it was written.
|
|
55
|
+
*/
|
|
56
|
+
export function isActAsEligibleKind(kind) {
|
|
57
|
+
return kind === 'organization' || kind === 'project' || kind === 'bot';
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Narrow an unknown value to an {@link AccountKind}.
|
|
61
|
+
*
|
|
62
|
+
* The user-DTO serializers read from structurally-permissive `unknown` sources
|
|
63
|
+
* (a Drizzle row, a Mongo document, an already-formatted object), so each one
|
|
64
|
+
* would otherwise hand-roll this check and they would drift on what counts.
|
|
65
|
+
*/
|
|
66
|
+
export function isAccountKind(value) {
|
|
67
|
+
return typeof value === 'string' && ACCOUNT_KINDS.includes(value);
|
|
68
|
+
}
|
|
9
69
|
export const ORGANIZATION_CATEGORIES = [
|
|
10
70
|
'agency',
|
|
11
71
|
'cooperative',
|
|
@@ -13,10 +73,25 @@ export const ORGANIZATION_CATEGORIES = [
|
|
|
13
73
|
'other',
|
|
14
74
|
];
|
|
15
75
|
export const organizationCategorySchema = z.enum(ORGANIZATION_CATEGORIES);
|
|
76
|
+
/**
|
|
77
|
+
* An account's name on the create/update wire.
|
|
78
|
+
*
|
|
79
|
+
* `displayName` is EXPLICIT and stored, not derived. `first`/`last` model a
|
|
80
|
+
* human name, and composing a display string from them is right for a person —
|
|
81
|
+
* but a non-personal account has a TITLE, not a given and family name. Without
|
|
82
|
+
* this field the only way to name a channel "Notas de Nate" was to put the whole
|
|
83
|
+
* title in `first`, which renders correctly by accident while recording it as
|
|
84
|
+
* somebody's given name.
|
|
85
|
+
*
|
|
86
|
+
* When present it wins over the composed `first`/`last` (see the API's
|
|
87
|
+
* `composeDisplayName`, which already preferred an explicit value — only the
|
|
88
|
+
* storage for one was missing).
|
|
89
|
+
*/
|
|
16
90
|
const accountNameSchema = z
|
|
17
91
|
.object({
|
|
18
92
|
first: z.string().trim().max(100).optional(),
|
|
19
93
|
last: z.string().trim().max(100).optional(),
|
|
94
|
+
displayName: z.string().trim().max(100).optional(),
|
|
20
95
|
})
|
|
21
96
|
.optional();
|
|
22
97
|
/**
|
|
@@ -26,7 +101,7 @@ const accountNameSchema = z
|
|
|
26
101
|
export const createAccountRequestSchema = z
|
|
27
102
|
.object({
|
|
28
103
|
parentAccountId: z.string().trim().min(1).optional(),
|
|
29
|
-
kind:
|
|
104
|
+
kind: childAccountKindSchema,
|
|
30
105
|
username: z.string().trim().min(1).max(100),
|
|
31
106
|
name: accountNameSchema,
|
|
32
107
|
bio: z.string().trim().max(500).optional(),
|
package/dist/esm/index.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* Platform-agnostic — zod is the only runtime dependency. No react/react-native/
|
|
10
10
|
* expo, no `require()` in the ESM build.
|
|
11
11
|
*/
|
|
12
|
-
export { ORGANIZATION_CATEGORIES, organizationCategorySchema, createAccountRequestSchema, } from './accountGraph.js';
|
|
12
|
+
export { ACCOUNT_KINDS, accountKindSchema, CHILD_ACCOUNT_KINDS, childAccountKindSchema, isAccountKind, isActAsEligibleKind, ORGANIZATION_CATEGORIES, organizationCategorySchema, createAccountRequestSchema, } from './accountGraph.js';
|
|
13
13
|
export {
|
|
14
14
|
// Schemas
|
|
15
15
|
userNameSchema, userRelationshipSchema, themePreferenceSchema, userResponseSchema, userProfileUpdateSchema, currentUserResponseSchema, deviceLinkedSessionSchema, deviceLinkedSessionsResponseSchema,
|
package/dist/esm/userResponse.js
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
*/
|
|
31
31
|
import { z } from 'zod';
|
|
32
32
|
import { verifiedDomainSchema } from './identity.js';
|
|
33
|
-
import { organizationCategorySchema } from './accountGraph.js';
|
|
33
|
+
import { accountKindSchema, organizationCategorySchema } from './accountGraph.js';
|
|
34
34
|
export const userNameSchema = z
|
|
35
35
|
.object({
|
|
36
36
|
first: z.string().optional(),
|
|
@@ -100,9 +100,23 @@ export const userResponseSchema = z
|
|
|
100
100
|
* entry; present only when the account has verified at least one domain.
|
|
101
101
|
*/
|
|
102
102
|
verifiedDomains: z.array(verifiedDomainSchema).optional(),
|
|
103
|
+
/**
|
|
104
|
+
* Account-graph classification — what KIND of account this is.
|
|
105
|
+
*
|
|
106
|
+
* ORTHOGONAL to `type` (`local` / `federated` / `agent` / `automated`),
|
|
107
|
+
* which says where the account lives and how it is driven; the two
|
|
108
|
+
* coexist and neither substitutes for the other. A `channel` is a
|
|
109
|
+
* publishing identity nobody can act as, so a consumer that renders
|
|
110
|
+
* authored content reads THIS to tell a channel's post from a person's.
|
|
111
|
+
*
|
|
112
|
+
* Optional because a DTO produced from a source that never carried the
|
|
113
|
+
* column omits it; absent should be read as `personal`, the column's
|
|
114
|
+
* default, not as unknown.
|
|
115
|
+
*/
|
|
116
|
+
kind: accountKindSchema.optional(),
|
|
103
117
|
/**
|
|
104
118
|
* Real-estate / team taxonomy for `kind: 'organization'` accounts.
|
|
105
|
-
* Absent on personal, project, and
|
|
119
|
+
* Absent on personal, project, bot, and channel accounts.
|
|
106
120
|
*/
|
|
107
121
|
organizationCategory: organizationCategorySchema.optional(),
|
|
108
122
|
/**
|
|
@@ -126,6 +140,12 @@ export const userProfileUpdateSchema = z
|
|
|
126
140
|
.object({
|
|
127
141
|
first: z.string().optional(),
|
|
128
142
|
last: z.string().optional(),
|
|
143
|
+
/**
|
|
144
|
+
* Explicit display name, stored rather than composed. Wins over
|
|
145
|
+
* `first`/`last` when set; send `''` to clear it and fall back
|
|
146
|
+
* to the composed pair.
|
|
147
|
+
*/
|
|
148
|
+
displayName: z.string().optional(),
|
|
129
149
|
})
|
|
130
150
|
.optional(),
|
|
131
151
|
username: z.string().optional(),
|