@oxy.so/core 4.5.0 → 4.8.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.
@@ -0,0 +1,246 @@
1
+ import { type OrganizationCuration, type OrganizationImportBatch, type OrganizationClaimListQuery, type CreateOrganization, type OrganizationSearch, type UpdateOrganization, type OrganizationClaimInput, type OrganizationClaimReview, type OrganizationExternalInput, type OrganizationMerge } from '@oxy.so/contracts';
2
+ import type { OxyContext } from '../client/context';
3
+ /** The public canonical organization directory. Claiming changes authority, never identity. */
4
+ export declare class OrganizationsApi {
5
+ private readonly ctx;
6
+ constructor(ctx: OxyContext);
7
+ search(input: OrganizationSearch): Promise<{
8
+ items: {
9
+ status: "active" | "inactive" | "merged" | "suppressed";
10
+ name: string;
11
+ organizationType: "business" | "nonprofit" | "public_body" | "community" | "other";
12
+ legalName: string | null;
13
+ websiteUrl: string | null;
14
+ countryCode: string | null;
15
+ aliases: {
16
+ alias: string;
17
+ kind: "name_variant" | "former_name" | "localized_name" | "marketing_name" | "misspelling";
18
+ language?: string | undefined;
19
+ }[];
20
+ accountId: string;
21
+ username: string | null;
22
+ avatar: string | null;
23
+ verifiedDomains: string[];
24
+ claimStatus: "unclaimed" | "claimed";
25
+ mergedIntoAccountId: string | null;
26
+ createdAt: string;
27
+ updatedAt: string;
28
+ }[];
29
+ nextCursor: string | null;
30
+ }>;
31
+ get(accountId: string): Promise<{
32
+ status: "active" | "inactive" | "merged" | "suppressed";
33
+ name: string;
34
+ organizationType: "business" | "nonprofit" | "public_body" | "community" | "other";
35
+ legalName: string | null;
36
+ websiteUrl: string | null;
37
+ countryCode: string | null;
38
+ aliases: {
39
+ alias: string;
40
+ kind: "name_variant" | "former_name" | "localized_name" | "marketing_name" | "misspelling";
41
+ language?: string | undefined;
42
+ }[];
43
+ accountId: string;
44
+ username: string | null;
45
+ avatar: string | null;
46
+ verifiedDomains: string[];
47
+ claimStatus: "unclaimed" | "claimed";
48
+ mergedIntoAccountId: string | null;
49
+ createdAt: string;
50
+ updatedAt: string;
51
+ }>;
52
+ batch(input: {
53
+ ids: string[];
54
+ }): Promise<{
55
+ items: {
56
+ requestedAccountId: string;
57
+ organization: {
58
+ status: "active" | "inactive" | "merged" | "suppressed";
59
+ name: string;
60
+ organizationType: "business" | "nonprofit" | "public_body" | "community" | "other";
61
+ legalName: string | null;
62
+ websiteUrl: string | null;
63
+ countryCode: string | null;
64
+ aliases: {
65
+ alias: string;
66
+ kind: "name_variant" | "former_name" | "localized_name" | "marketing_name" | "misspelling";
67
+ language?: string | undefined;
68
+ }[];
69
+ accountId: string;
70
+ username: string | null;
71
+ avatar: string | null;
72
+ verifiedDomains: string[];
73
+ claimStatus: "unclaimed" | "claimed";
74
+ mergedIntoAccountId: string | null;
75
+ createdAt: string;
76
+ updatedAt: string;
77
+ };
78
+ }[];
79
+ missingIds: string[];
80
+ }>;
81
+ create(input: CreateOrganization): Promise<{
82
+ status: "active" | "inactive" | "merged" | "suppressed";
83
+ name: string;
84
+ organizationType: "business" | "nonprofit" | "public_body" | "community" | "other";
85
+ legalName: string | null;
86
+ websiteUrl: string | null;
87
+ countryCode: string | null;
88
+ aliases: {
89
+ alias: string;
90
+ kind: "name_variant" | "former_name" | "localized_name" | "marketing_name" | "misspelling";
91
+ language?: string | undefined;
92
+ }[];
93
+ accountId: string;
94
+ username: string | null;
95
+ avatar: string | null;
96
+ verifiedDomains: string[];
97
+ claimStatus: "unclaimed" | "claimed";
98
+ mergedIntoAccountId: string | null;
99
+ createdAt: string;
100
+ updatedAt: string;
101
+ }>;
102
+ update(accountId: string, input: UpdateOrganization): Promise<{
103
+ status: "active" | "inactive" | "merged" | "suppressed";
104
+ name: string;
105
+ organizationType: "business" | "nonprofit" | "public_body" | "community" | "other";
106
+ legalName: string | null;
107
+ websiteUrl: string | null;
108
+ countryCode: string | null;
109
+ aliases: {
110
+ alias: string;
111
+ kind: "name_variant" | "former_name" | "localized_name" | "marketing_name" | "misspelling";
112
+ language?: string | undefined;
113
+ }[];
114
+ accountId: string;
115
+ username: string | null;
116
+ avatar: string | null;
117
+ verifiedDomains: string[];
118
+ claimStatus: "unclaimed" | "claimed";
119
+ mergedIntoAccountId: string | null;
120
+ createdAt: string;
121
+ updatedAt: string;
122
+ }>;
123
+ claim(accountId: string, input: OrganizationClaimInput): Promise<{
124
+ status: "pending" | "approved" | "rejected";
125
+ accountId: string;
126
+ createdAt: string;
127
+ id: string;
128
+ claimantUserId: string;
129
+ }>;
130
+ myClaims(input?: OrganizationClaimListQuery): Promise<{
131
+ items: {
132
+ status: "pending" | "approved" | "rejected";
133
+ accountId: string;
134
+ createdAt: string;
135
+ evidenceReference: string;
136
+ id: string;
137
+ claimantUserId: string;
138
+ reviewEvidenceReference: string | null;
139
+ reviewedAt: string | null;
140
+ }[];
141
+ nextCursor: string | null;
142
+ }>;
143
+ myClaim(claimId: string): Promise<{
144
+ status: "pending" | "approved" | "rejected";
145
+ accountId: string;
146
+ createdAt: string;
147
+ evidenceReference: string;
148
+ id: string;
149
+ claimantUserId: string;
150
+ reviewEvidenceReference: string | null;
151
+ reviewedAt: string | null;
152
+ }>;
153
+ reviewClaims(input?: OrganizationClaimListQuery): Promise<{
154
+ items: {
155
+ status: "pending" | "approved" | "rejected";
156
+ accountId: string;
157
+ createdAt: string;
158
+ evidenceReference: string;
159
+ id: string;
160
+ claimantUserId: string;
161
+ reviewEvidenceReference: string | null;
162
+ reviewedAt: string | null;
163
+ }[];
164
+ nextCursor: string | null;
165
+ }>;
166
+ reviewClaimDetail(claimId: string): Promise<{
167
+ status: "pending" | "approved" | "rejected";
168
+ accountId: string;
169
+ createdAt: string;
170
+ evidenceReference: string;
171
+ id: string;
172
+ claimantUserId: string;
173
+ reviewEvidenceReference: string | null;
174
+ reviewedAt: string | null;
175
+ }>;
176
+ reviewClaim(claimId: string, input: OrganizationClaimReview): Promise<{
177
+ status: "pending" | "approved" | "rejected";
178
+ accountId: string;
179
+ createdAt: string;
180
+ id: string;
181
+ claimantUserId: string;
182
+ }>;
183
+ importBatch(input: OrganizationImportBatch): Promise<{
184
+ items: {
185
+ accountId: string;
186
+ externalId: string;
187
+ created: boolean;
188
+ }[];
189
+ }>;
190
+ importExternal(input: OrganizationExternalInput): Promise<{
191
+ accountId: string;
192
+ created: boolean;
193
+ }>;
194
+ resolveExternal(input: {
195
+ namespace: string;
196
+ externalId: string;
197
+ }): Promise<{
198
+ accountId: string;
199
+ }>;
200
+ curate(accountId: string, input: OrganizationCuration): Promise<{
201
+ status: "active" | "inactive" | "suppressed";
202
+ accountId: string;
203
+ }>;
204
+ merge(accountId: string, input: OrganizationMerge): Promise<{
205
+ status: "active" | "inactive" | "merged" | "suppressed";
206
+ name: string;
207
+ organizationType: "business" | "nonprofit" | "public_body" | "community" | "other";
208
+ legalName: string | null;
209
+ websiteUrl: string | null;
210
+ countryCode: string | null;
211
+ aliases: {
212
+ alias: string;
213
+ kind: "name_variant" | "former_name" | "localized_name" | "marketing_name" | "misspelling";
214
+ language?: string | undefined;
215
+ }[];
216
+ accountId: string;
217
+ username: string | null;
218
+ avatar: string | null;
219
+ verifiedDomains: string[];
220
+ claimStatus: "unclaimed" | "claimed";
221
+ mergedIntoAccountId: string | null;
222
+ createdAt: string;
223
+ updatedAt: string;
224
+ }>;
225
+ iterate(input: OrganizationSearch): AsyncGenerator<{
226
+ status: "active" | "inactive" | "merged" | "suppressed";
227
+ name: string;
228
+ organizationType: "business" | "nonprofit" | "public_body" | "community" | "other";
229
+ legalName: string | null;
230
+ websiteUrl: string | null;
231
+ countryCode: string | null;
232
+ aliases: {
233
+ alias: string;
234
+ kind: "name_variant" | "former_name" | "localized_name" | "marketing_name" | "misspelling";
235
+ language?: string | undefined;
236
+ }[];
237
+ accountId: string;
238
+ username: string | null;
239
+ avatar: string | null;
240
+ verifiedDomains: string[];
241
+ claimStatus: "unclaimed" | "claimed";
242
+ mergedIntoAccountId: string | null;
243
+ createdAt: string;
244
+ updatedAt: string;
245
+ }, void, unknown>;
246
+ }
@@ -0,0 +1,14 @@
1
+ import { type ProfileAccessInput } from '@oxy.so/contracts';
2
+ import type { OxyContext } from '../client/context';
3
+ export declare class SafetyApi {
4
+ private readonly ctx;
5
+ constructor(ctx: OxyContext);
6
+ /** Server callers must explicitly supply the incoming user bearer or null for anonymous access. */
7
+ profileAccess(input: ProfileAccessInput, options?: {
8
+ accessToken: string | null;
9
+ }): Promise<{
10
+ allowed: boolean;
11
+ reason: "public" | "owner" | "private" | "blocked" | "unavailable";
12
+ policyVersion: "1";
13
+ }>;
14
+ }
@@ -1,4 +1,65 @@
1
1
  declare const dict: {
2
+ organizationDirectory: {
3
+ invalidName: string;
4
+ review: {
5
+ title: string;
6
+ forbidden: string;
7
+ empty: string;
8
+ hint: string;
9
+ independent: string;
10
+ evidence: string;
11
+ approved: string;
12
+ rejected: string;
13
+ conflict: string;
14
+ failed: string;
15
+ };
16
+ title: string;
17
+ search: string;
18
+ searchHint: string;
19
+ empty: string;
20
+ retry: string;
21
+ loadMore: string;
22
+ failed: string;
23
+ unclaimed: string;
24
+ claimed: string;
25
+ inactive: string;
26
+ newAccount: string;
27
+ newAccountHint: string;
28
+ addDirectory: string;
29
+ directoryHint: string;
30
+ added: string;
31
+ back: string;
32
+ type: string;
33
+ types: {
34
+ business: string;
35
+ nonprofit: string;
36
+ public_body: string;
37
+ community: string;
38
+ other: string;
39
+ };
40
+ name: string;
41
+ legalName: string;
42
+ website: string;
43
+ country: string;
44
+ save: string;
45
+ saved: string;
46
+ invalid: string;
47
+ saveFailed: string;
48
+ claim: string;
49
+ claimHint: string;
50
+ evidence: string;
51
+ evidenceHint: string;
52
+ claimSent: string;
53
+ claimFailed: string;
54
+ claimedHint: string;
55
+ requests: string;
56
+ pending: string;
57
+ approved: string;
58
+ rejected: string;
59
+ requestError: string;
60
+ view: string;
61
+ readonly: string;
62
+ };
2
63
  signin: {
3
64
  title: string;
4
65
  subtitle: string;
@@ -1,4 +1,65 @@
1
1
  declare const dict: {
2
+ organizationDirectory: {
3
+ invalidName: string;
4
+ review: {
5
+ title: string;
6
+ forbidden: string;
7
+ empty: string;
8
+ hint: string;
9
+ independent: string;
10
+ evidence: string;
11
+ approved: string;
12
+ rejected: string;
13
+ conflict: string;
14
+ failed: string;
15
+ };
16
+ title: string;
17
+ search: string;
18
+ searchHint: string;
19
+ empty: string;
20
+ retry: string;
21
+ loadMore: string;
22
+ failed: string;
23
+ unclaimed: string;
24
+ claimed: string;
25
+ inactive: string;
26
+ newAccount: string;
27
+ newAccountHint: string;
28
+ addDirectory: string;
29
+ directoryHint: string;
30
+ added: string;
31
+ back: string;
32
+ type: string;
33
+ types: {
34
+ business: string;
35
+ nonprofit: string;
36
+ public_body: string;
37
+ community: string;
38
+ other: string;
39
+ };
40
+ name: string;
41
+ legalName: string;
42
+ website: string;
43
+ country: string;
44
+ save: string;
45
+ saved: string;
46
+ invalid: string;
47
+ saveFailed: string;
48
+ claim: string;
49
+ claimHint: string;
50
+ evidence: string;
51
+ evidenceHint: string;
52
+ claimSent: string;
53
+ claimFailed: string;
54
+ claimedHint: string;
55
+ requests: string;
56
+ pending: string;
57
+ approved: string;
58
+ rejected: string;
59
+ requestError: string;
60
+ view: string;
61
+ readonly: string;
62
+ };
2
63
  signin: {
3
64
  title: string;
4
65
  subtitle: string;
@@ -99,3 +99,5 @@ export { AUTH_WEB_ORIGIN, CENTRAL_IDP_APEX } from './utils/authWebUrl';
99
99
  export { buildOAuthAuthorizeUrl, computeCodeChallenge, generateOAuthState, generatePkcePair, DEFAULT_OAUTH_SCOPE, OXY_AUTHORIZE_URL, OXY_OAUTH_STATE_STORAGE_KEY, OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY, OXY_OAUTH_REDIRECT_URI_STORAGE_KEY, OXY_OAUTH_RETURN_PATH_STORAGE_KEY, normalizeOAuthRedirectUri, canonicalizeOAuthRedirectUri, persistOAuthHandshake, readOAuthHandshake, clearOAuthHandshake, persistOAuthReturnPath, consumeOAuthReturnPath, } from './utils/oauthPkce';
100
100
  export type { PkcePair, BuildOAuthAuthorizeUrlParams, OxyAuthScreen } from './utils/oauthPkce';
101
101
  export { packageInfo } from './constants/version';
102
+ export type { Organization, OrganizationType, CreateOrganization, UpdateOrganization, OrganizationSearch, OrganizationClaim, } from '@oxy.so/contracts';
103
+ export type { ProfileAccessInput, ProfileAccessDecision } from '@oxy.so/contracts';
@@ -1,4 +1,4 @@
1
- import type { AccountKind, AccountCategoryId, UserNameResponse, UserRelationship, ThemePreference, OxyNotificationEntityType, OxyNotificationType } from '@oxy.so/contracts';
1
+ import type { AccountKind, AccountCategoryId, AvatarCharacter, UserNameResponse, UserRelationship, ThemePreference, OxyNotificationEntityType, OxyNotificationType } from '@oxy.so/contracts';
2
2
  export interface OxyConfig {
3
3
  baseURL: string;
4
4
  cloudURL?: string;
@@ -160,7 +160,15 @@ export interface User {
160
160
  isFederated?: boolean;
161
161
  /** Allow sharing this user's content on the fediverse. Defaults to true. */
162
162
  fediverseSharing?: boolean;
163
+ /**
164
+ * Derived from `kind === 'bot'` (the SOLE definition), NOT from `type`.
165
+ */
163
166
  isAgent?: boolean;
167
+ /**
168
+ * The 3D avatar character of a `kind: 'bot'` account, drawn by Bloom's
169
+ * `Avatar`. Present ONLY on a bot; absent for every other kind.
170
+ */
171
+ character?: AvatarCharacter;
164
172
  isAutomated?: boolean;
165
173
  instance?: string;
166
174
  federation?: {
@@ -36,8 +36,8 @@ export declare const oxyRequesterAssertionClaimsSchema: z.ZodObject<{
36
36
  /** The one native agent this requester may reach with it. */
37
37
  agentId: z.ZodString;
38
38
  }, "strict", z.ZodTypeAny, {
39
- exp: number;
40
39
  sub: string;
40
+ exp: number;
41
41
  aud: string;
42
42
  iss: string;
43
43
  jti: string;
@@ -46,8 +46,8 @@ export declare const oxyRequesterAssertionClaimsSchema: z.ZodObject<{
46
46
  cid: string;
47
47
  agentId: string;
48
48
  }, {
49
- exp: number;
50
49
  sub: string;
50
+ exp: number;
51
51
  aud: string;
52
52
  iss: string;
53
53
  jti: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxy.so/core",
3
- "version": "4.5.0",
3
+ "version": "4.8.0",
4
4
  "description": "OxyHQ SDK Foundation — API client, authentication, cryptographic identity, and shared utilities",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -176,11 +176,11 @@
176
176
  }
177
177
  },
178
178
  "dependencies": {
179
- "@oxy.so/telemetry": "^1.2.0",
180
179
  "@noble/ciphers": "^1.3.0",
181
180
  "@noble/hashes": "^1.8.0",
182
- "@oxy.so/contracts": "4.12.0",
181
+ "@oxy.so/contracts": "4.14.0",
183
182
  "@oxy.so/protocol": "^1.2.2",
183
+ "@oxy.so/telemetry": "^1.2.0",
184
184
  "@scure/bip39": "^1.6.0",
185
185
  "buffer": "^6.0.3",
186
186
  "express-rate-limit": "^8.6.0",
@@ -217,7 +217,7 @@
217
217
  "@types/invariant": "^2.2.34",
218
218
  "@types/node": "^20.19.43",
219
219
  "expo-crypto": "~56.0.3",
220
- "expo-secure-store": "~56.0.4",
220
+ "expo-secure-store": "~57.0.4",
221
221
  "express": "^4.22.2",
222
222
  "express-rate-limit": "^8.6.0",
223
223
  "jest": "^30.5.1",
@@ -1,3 +1,4 @@
1
+ import { SafetyApi } from './api/safety';
1
2
  /**
2
3
  * `OxyServices` — the Oxy API client.
3
4
  *
@@ -32,6 +33,7 @@ import { PrivacyApi } from './api/privacy';
32
33
  import { NotificationsApi } from './api/notifications';
33
34
  import { AssetsApi } from './api/assets';
34
35
  import { IdentityApi } from './api/identity';
36
+ import { OrganizationsApi } from './api/organizations';
35
37
  import { AccountsApi } from './api/accounts';
36
38
  import { AppsApi } from './api/apps';
37
39
  import { LinkedAccountsApi } from './api/linkedAccounts';
@@ -191,6 +193,8 @@ export class OxyServices {
191
193
  private _assets?: AssetsApi;
192
194
  private _identity?: IdentityApi;
193
195
  private _accounts?: AccountsApi;
196
+ private _organizations?: OrganizationsApi;
197
+ private _safety?: SafetyApi;
194
198
  private _apps?: AppsApi;
195
199
  private _linkedAccounts?: LinkedAccountsApi;
196
200
  private _agency?: AgencyApi;
@@ -245,6 +249,16 @@ export class OxyServices {
245
249
  return this._identity;
246
250
  }
247
251
  /** The account graph: accounts and their members. */
252
+ get safety(): SafetyApi {
253
+ if (!this._safety) this._safety = new SafetyApi(this.context);
254
+ return this._safety;
255
+ }
256
+
257
+ get organizations(): OrganizationsApi {
258
+ if (!this._organizations) this._organizations = new OrganizationsApi(this.context);
259
+ return this._organizations;
260
+ }
261
+
248
262
  get accounts(): AccountsApi {
249
263
  if (!this._accounts) this._accounts = new AccountsApi(this.context);
250
264
  return this._accounts;
@@ -1,3 +1,4 @@
1
+ import type { OrganizationType } from '@oxy.so/contracts';
1
2
  /**
2
3
  * `oxy.accounts` — the unified account graph (`/accounts`).
3
4
  *
@@ -27,7 +28,12 @@ import {
27
28
  type AgentKeyOperationProof,
28
29
  } from '@oxy.so/contracts';
29
30
  import type { User } from '../models/interfaces';
30
- import type { AccountCategoryId, AccountKind, ChildAccountKind } from '@oxy.so/contracts';
31
+ import type {
32
+ AccountCategoryId,
33
+ AccountKind,
34
+ AvatarCharacter,
35
+ ChildAccountKind,
36
+ } from '@oxy.so/contracts';
31
37
  import type { SessionLoginResponse } from '../models/session';
32
38
  import type { OxyContext } from '../client/context';
33
39
  import { normalizeUserIdentity } from '../utils/userIdentity';
@@ -57,7 +63,7 @@ const enc = encodeURIComponent;
57
63
  *
58
64
  * Single source of truth is `@oxy.so/contracts`.
59
65
  */
60
- export type { AccountCategoryId, AccountKind } from '@oxy.so/contracts';
66
+ export type { AccountCategoryId, AccountKind, AvatarCharacter } from '@oxy.so/contracts';
61
67
  export {
62
68
  ACCOUNT_CATEGORY_IDS,
63
69
  ACCOUNT_KINDS,
@@ -231,6 +237,7 @@ export interface CreateAccountInput {
231
237
  * keep working. At most `MAX_ACCOUNT_CATEGORIES`, no duplicates.
232
238
  */
233
239
  accountCategories?: AccountCategoryId[];
240
+ organizationType?: OrganizationType;
234
241
  /**
235
242
  * Create the account already opted OUT of discovery — kept out of people
236
243
  * search, the follow-graph lists, `/similar` and the recommendation pools,
@@ -247,6 +254,13 @@ export interface CreateAccountInput {
247
254
  * discoverable at all, rather than discoverable until a second call lands.
248
255
  */
249
256
  isPrivateAccount?: boolean;
257
+ /**
258
+ * The 3D avatar character, for `kind: 'bot'` ONLY (any other kind is a 400).
259
+ * Optional: a bot created without one is given a look seeded from its
260
+ * handle, so every bot has a character from birth and its owner changes it
261
+ * afterwards with `accounts.update`.
262
+ */
263
+ character?: AvatarCharacter;
250
264
  }
251
265
 
252
266
  /** Input accepted by `accounts.update`. Tree placement changes go through `/move`. */
@@ -283,6 +297,13 @@ export interface UpdateAccountInput {
283
297
  * always allowed.
284
298
  */
285
299
  accountCategories?: AccountCategoryId[];
300
+ /**
301
+ * Replaces the WHOLE character of a `bot` account. Rejected (400) for any
302
+ * other kind, and not nullable: a bot always has one. Same authorization as
303
+ * every other field here (`account:update`).
304
+ */
305
+ character?: AvatarCharacter;
306
+ organizationType?: OrganizationType;
286
307
  }
287
308
 
288
309
  /** Input accepted by `accounts.members.invite`. The owner role cannot be invited. */