@oxy.so/core 7.17.0 → 7.19.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/HttpService.js +2 -0
- package/dist/cjs/OxyServices.errors.js +21 -0
- package/dist/cjs/OxyServices.js +86 -75
- package/dist/cjs/client/callOptions.js +66 -0
- package/dist/cjs/index.js +5 -4
- package/dist/cjs/server/OxyServer.js +10 -27
- package/dist/cjs/server/callerAccess.js +20 -1
- package/dist/cjs/server/namespaces.js +85 -26
- package/dist/cjs/server/requesterClient.js +1 -3
- package/dist/cjs/server/safeFetch.js +43 -12
- package/dist/esm/HttpService.js +2 -1
- package/dist/esm/OxyServices.errors.js +20 -0
- package/dist/esm/OxyServices.js +86 -75
- package/dist/esm/client/callOptions.js +61 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/server/OxyServer.js +10 -27
- package/dist/esm/server/callerAccess.js +20 -1
- package/dist/esm/server/namespaces.js +86 -27
- package/dist/esm/server/requesterClient.js +1 -3
- package/dist/esm/server/safeFetch.js +43 -12
- package/dist/types/HttpService.d.ts +2 -0
- package/dist/types/OxyServices.d.ts +38 -25
- package/dist/types/OxyServices.errors.d.ts +6 -0
- package/dist/types/client/callOptions.d.ts +45 -0
- package/dist/types/index.d.ts +4 -3
- package/dist/types/models/interfaces.d.ts +23 -0
- package/dist/types/server/OxyServer.d.ts +0 -9
- package/dist/types/server/callerAccess.d.ts +14 -1
- package/dist/types/server/namespaces.d.ts +50 -13
- package/dist/types/server/requesterClient.d.ts +0 -1
- package/dist/types/server/safeFetch.d.ts +16 -0
- package/package.json +1 -1
- package/src/HttpService.ts +2 -1
- package/src/OxyServices.errors.ts +19 -0
- package/src/OxyServices.ts +129 -75
- package/src/client/callOptions.ts +88 -0
- package/src/index.ts +12 -1
- package/src/models/interfaces.ts +25 -0
- package/src/server/OxyServer.ts +15 -33
- package/src/server/callerAccess.ts +34 -2
- package/src/server/namespaces.ts +128 -43
- package/src/server/requesterClient.ts +1 -3
- package/src/server/safeFetch.ts +69 -11
package/dist/cjs/HttpService.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
exports.HttpService = void 0;
|
|
18
|
+
exports.linkAbort = linkAbort;
|
|
18
19
|
const cache_1 = require("./utils/cache");
|
|
19
20
|
const requestUtils_1 = require("./utils/requestUtils");
|
|
20
21
|
const asyncUtils_1 = require("./utils/asyncUtils");
|
|
@@ -301,6 +302,7 @@ function isAbortLike(error) {
|
|
|
301
302
|
error !== null &&
|
|
302
303
|
error.name === 'AbortError');
|
|
303
304
|
}
|
|
305
|
+
/** @internal Shared with `client/callOptions.ts`; see the note above `isAbortLike`. */
|
|
304
306
|
function linkAbort(parent, child) {
|
|
305
307
|
if (parent.aborted) {
|
|
306
308
|
child.abort(parent.reason);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.OxyApiError = exports.OxyAuthenticationTimeoutError = exports.ServiceLinkedDownloadUrlError = exports.ServiceAssetMetadataError = exports.AssetUrlResolutionError = exports.OxyAuthenticationError = void 0;
|
|
4
|
+
exports.retryAfterSecondsOf = retryAfterSecondsOf;
|
|
4
5
|
exports.toOxyApiError = toOxyApiError;
|
|
5
6
|
const errorUtils_1 = require("./utils/errorUtils");
|
|
6
7
|
/**
|
|
@@ -146,6 +147,26 @@ class OxyApiError extends Error {
|
|
|
146
147
|
}
|
|
147
148
|
}
|
|
148
149
|
exports.OxyApiError = OxyApiError;
|
|
150
|
+
/**
|
|
151
|
+
* How long Oxy asked the caller to wait before trying again, in seconds — the
|
|
152
|
+
* `Retry-After` of a 429 (`details.retryAfterSeconds` of its body) — or
|
|
153
|
+
* `undefined` when the error is no such refusal or names no wait.
|
|
154
|
+
*/
|
|
155
|
+
function retryAfterSecondsOf(error) {
|
|
156
|
+
if (!error || typeof error !== 'object')
|
|
157
|
+
return undefined;
|
|
158
|
+
const candidates = [
|
|
159
|
+
error.details,
|
|
160
|
+
error.response
|
|
161
|
+
?.data?.details,
|
|
162
|
+
];
|
|
163
|
+
for (const details of candidates) {
|
|
164
|
+
const seconds = details?.retryAfterSeconds;
|
|
165
|
+
if (typeof seconds === 'number' && Number.isFinite(seconds) && seconds > 0)
|
|
166
|
+
return seconds;
|
|
167
|
+
}
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
149
170
|
/**
|
|
150
171
|
* Normalise anything a request rejected with into an `OxyApiError`. An error
|
|
151
172
|
* that already is one (or a typed SDK error such as `OxyAuthenticationError`)
|
package/dist/cjs/OxyServices.js
CHANGED
|
@@ -28,6 +28,7 @@ const contentClaims_1 = require("./api/contentClaims");
|
|
|
28
28
|
*/
|
|
29
29
|
const HttpService_1 = require("./HttpService");
|
|
30
30
|
const OxyServices_errors_1 = require("./OxyServices.errors");
|
|
31
|
+
const callOptions_1 = require("./client/callOptions");
|
|
31
32
|
const session_1 = require("./api/session");
|
|
32
33
|
const auth_1 = require("./api/auth");
|
|
33
34
|
const users_1 = require("./api/users");
|
|
@@ -67,6 +68,9 @@ class OxyServices {
|
|
|
67
68
|
deletePrefix: (prefix) => this.http.clearCacheByPrefix(prefix),
|
|
68
69
|
stats: () => this.http.getCacheStats(),
|
|
69
70
|
};
|
|
71
|
+
// ── Namespaces (created on first access) ─────────────────────────────────
|
|
72
|
+
/** Each namespace, created on first access and kept for the client's life. */
|
|
73
|
+
this.namespaceInstances = new Map();
|
|
70
74
|
if (!config || typeof config !== 'object') {
|
|
71
75
|
throw new Error('OxyConfig is required');
|
|
72
76
|
}
|
|
@@ -169,151 +173,158 @@ class OxyServices {
|
|
|
169
173
|
dispose() {
|
|
170
174
|
this.http.dispose();
|
|
171
175
|
}
|
|
176
|
+
/** The namespace `name`, created with this client's context on first access. */
|
|
177
|
+
namespace(name, create) {
|
|
178
|
+
let instance = this.namespaceInstances.get(name);
|
|
179
|
+
if (instance === undefined) {
|
|
180
|
+
instance = create(this.context);
|
|
181
|
+
this.namespaceInstances.set(name, instance);
|
|
182
|
+
}
|
|
183
|
+
return instance;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* This client's namespaces with per-call transport options: every request
|
|
187
|
+
* made through them carries `options`, on top of what each method sets.
|
|
188
|
+
*
|
|
189
|
+
* ```ts
|
|
190
|
+
* // One slow write, one tight read — one client.
|
|
191
|
+
* await oxy.withCallOptions({ timeout: 60_000 }).assets.setVisibility(id, 'public');
|
|
192
|
+
* const page = await oxy.withCallOptions({ deadline: 2_500 }).users.byUsername(name);
|
|
193
|
+
* // A server's own namespaces too:
|
|
194
|
+
* await server.withCallOptions({ retry: false }).assets.references.add(refs);
|
|
195
|
+
* ```
|
|
196
|
+
*
|
|
197
|
+
* - `timeout` / `deadline` replace the method's own and the client's.
|
|
198
|
+
* - `retry: false` sends each request once; `retry: true` never re-enables
|
|
199
|
+
* a request the method sends once on purpose.
|
|
200
|
+
* - `signal` aborts the call; a method's own signal still applies too.
|
|
201
|
+
*
|
|
202
|
+
* The scope is a view, not a client: it shares this client's session,
|
|
203
|
+
* cache, credentials and service lane, holds no resource and needs no
|
|
204
|
+
* disposal. A namespace one call makes into another (`privacy` reading
|
|
205
|
+
* `users.me()`) keeps the options. `session` is not part of it.
|
|
206
|
+
*/
|
|
207
|
+
withCallOptions(options) {
|
|
208
|
+
(0, callOptions_1.assertCallOptions)(options);
|
|
209
|
+
const scope = { ...options };
|
|
210
|
+
const base = this.context;
|
|
211
|
+
const lane = base.service;
|
|
212
|
+
const view = Object.create(this);
|
|
213
|
+
const context = {
|
|
214
|
+
oxy: view,
|
|
215
|
+
http: base.http,
|
|
216
|
+
request: (method, url, data, requestOptions) => (0, callOptions_1.sendWithCallOptions)(requestOptions, scope, (merged) => base.request(method, url, data, merged)),
|
|
217
|
+
service: lane && {
|
|
218
|
+
get available() {
|
|
219
|
+
return lane.available;
|
|
220
|
+
},
|
|
221
|
+
request: (method, url, data, requestOptions) => (0, callOptions_1.sendWithCallOptions)(requestOptions, scope, (merged) => lane.request(method, url, data, merged)),
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
// The view's own namespaces are built on the scoped context; everything
|
|
225
|
+
// else (http, cache, config, credentials) is this client's, by prototype.
|
|
226
|
+
Object.defineProperties(view, {
|
|
227
|
+
context: { value: context },
|
|
228
|
+
namespaceInstances: { value: new Map() },
|
|
229
|
+
session: { get: () => this.session },
|
|
230
|
+
});
|
|
231
|
+
return view;
|
|
232
|
+
}
|
|
172
233
|
/** This client's auth state (token, user id) and its server session. */
|
|
173
234
|
get session() {
|
|
174
|
-
|
|
175
|
-
this._session = new session_1.SessionApi(this.context);
|
|
176
|
-
return this._session;
|
|
235
|
+
return this.namespace('session', (context) => new session_1.SessionApi(context));
|
|
177
236
|
}
|
|
178
237
|
/** Signing in, signing up, and the account's credentials. */
|
|
179
238
|
get auth() {
|
|
180
|
-
|
|
181
|
-
this._auth = new auth_1.AuthApi(this.context);
|
|
182
|
-
return this._auth;
|
|
239
|
+
return this.namespace('auth', (context) => new auth_1.AuthApi(context));
|
|
183
240
|
}
|
|
184
241
|
/** People and their profiles. */
|
|
185
242
|
get users() {
|
|
186
|
-
|
|
187
|
-
this._users = new users_1.UsersApi(this.context);
|
|
188
|
-
return this._users;
|
|
243
|
+
return this.namespace('users', (context) => new users_1.UsersApi(context));
|
|
189
244
|
}
|
|
190
245
|
/** The follow graph: people and every other followable target. */
|
|
191
246
|
get follows() {
|
|
192
|
-
|
|
193
|
-
this._follows = new follows_1.FollowsApi(this.context);
|
|
194
|
-
return this._follows;
|
|
247
|
+
return this.namespace('follows', (context) => new follows_1.FollowsApi(context));
|
|
195
248
|
}
|
|
196
249
|
/** Privacy settings, blocks and restrictions. */
|
|
197
250
|
get privacy() {
|
|
198
|
-
|
|
199
|
-
this._privacy = new privacy_1.PrivacyApi(this.context);
|
|
200
|
-
return this._privacy;
|
|
251
|
+
return this.namespace('privacy', (context) => new privacy_1.PrivacyApi(context));
|
|
201
252
|
}
|
|
202
253
|
/** The in-app inbox and push tokens. */
|
|
203
254
|
get notifications() {
|
|
204
|
-
|
|
205
|
-
this._notifications = new notifications_1.NotificationsApi(this.context);
|
|
206
|
-
return this._notifications;
|
|
255
|
+
return this.namespace('notifications', (context) => new notifications_1.NotificationsApi(context));
|
|
207
256
|
}
|
|
208
257
|
/** Files: upload, link, URLs, content. */
|
|
209
258
|
get assets() {
|
|
210
|
-
|
|
211
|
-
this._assets = new assets_1.AssetsApi(this.context);
|
|
212
|
-
return this._assets;
|
|
259
|
+
return this.namespace('assets', (context) => new assets_1.AssetsApi(context));
|
|
213
260
|
}
|
|
214
261
|
/** DID, keys, identity links, domains, backup and the signed export. */
|
|
215
262
|
get identity() {
|
|
216
|
-
|
|
217
|
-
this._identity = new identity_1.IdentityApi(this.context);
|
|
218
|
-
return this._identity;
|
|
263
|
+
return this.namespace('identity', (context) => new identity_1.IdentityApi(context));
|
|
219
264
|
}
|
|
220
265
|
/** The account graph: accounts and their members. */
|
|
221
266
|
get safety() {
|
|
222
|
-
|
|
223
|
-
this._safety = new safety_1.SafetyApi(this.context);
|
|
224
|
-
return this._safety;
|
|
267
|
+
return this.namespace('safety', (context) => new safety_1.SafetyApi(context));
|
|
225
268
|
}
|
|
226
269
|
/** Content claims: an owner's counter-notice to a takedown (ADR 0043 D10). */
|
|
227
270
|
get contentClaims() {
|
|
228
|
-
|
|
229
|
-
this._contentClaims = new contentClaims_1.ContentClaimsApi(this.context);
|
|
230
|
-
return this._contentClaims;
|
|
271
|
+
return this.namespace('contentClaims', (context) => new contentClaims_1.ContentClaimsApi(context));
|
|
231
272
|
}
|
|
232
273
|
get organizations() {
|
|
233
|
-
|
|
234
|
-
this._organizations = new organizations_1.OrganizationsApi(this.context);
|
|
235
|
-
return this._organizations;
|
|
274
|
+
return this.namespace('organizations', (context) => new organizations_1.OrganizationsApi(context));
|
|
236
275
|
}
|
|
237
276
|
get accounts() {
|
|
238
|
-
|
|
239
|
-
this._accounts = new accounts_1.AccountsApi(this.context);
|
|
240
|
-
return this._accounts;
|
|
277
|
+
return this.namespace('accounts', (context) => new accounts_1.AccountsApi(context));
|
|
241
278
|
}
|
|
242
279
|
/** Applications an account owns, and the ones this user granted access. */
|
|
243
280
|
get apps() {
|
|
244
|
-
|
|
245
|
-
this._apps = new apps_1.AppsApi(this.context);
|
|
246
|
-
return this._apps;
|
|
281
|
+
return this.namespace('apps', (context) => new apps_1.AppsApi(context));
|
|
247
282
|
}
|
|
248
283
|
/** External accounts (Mastodon, Bluesky) linked by OAuth. */
|
|
249
284
|
get linkedAccounts() {
|
|
250
|
-
|
|
251
|
-
this._linkedAccounts = new linkedAccounts_1.LinkedAccountsApi(this.context);
|
|
252
|
-
return this._linkedAccounts;
|
|
285
|
+
return this.namespace('linkedAccounts', (context) => new linkedAccounts_1.LinkedAccountsApi(context));
|
|
253
286
|
}
|
|
254
287
|
/** Delegated capabilities for agents. */
|
|
255
288
|
get agency() {
|
|
256
|
-
|
|
257
|
-
this._agency = new agency_1.AgencyApi(this.context);
|
|
258
|
-
return this._agency;
|
|
289
|
+
return this.namespace('agency', (context) => new agency_1.AgencyApi(context));
|
|
259
290
|
}
|
|
260
291
|
/** The app store: storefront, reviews, and a publisher's listing. */
|
|
261
292
|
get store() {
|
|
262
|
-
|
|
263
|
-
this._store = new store_1.StoreApi(this.context);
|
|
264
|
-
return this._store;
|
|
293
|
+
return this.namespace('store', (context) => new store_1.StoreApi(context));
|
|
265
294
|
}
|
|
266
295
|
/** Subscription, wallet and payments. */
|
|
267
296
|
get billing() {
|
|
268
|
-
|
|
269
|
-
this._billing = new billing_1.BillingApi(this.context);
|
|
270
|
-
return this._billing;
|
|
297
|
+
return this.namespace('billing', (context) => new billing_1.BillingApi(context));
|
|
271
298
|
}
|
|
272
299
|
/** Oxy Trust reputation (read-only for people; apps award it). */
|
|
273
300
|
get reputation() {
|
|
274
|
-
|
|
275
|
-
this._reputation = new reputation_1.ReputationApi(this.context);
|
|
276
|
-
return this._reputation;
|
|
301
|
+
return this.namespace('reputation', (context) => new reputation_1.ReputationApi(context));
|
|
277
302
|
}
|
|
278
303
|
/** Oxy ID: cards, attestations, vouching, personhood, credentials. */
|
|
279
304
|
get civic() {
|
|
280
|
-
|
|
281
|
-
this._civic = new civic_1.CivicApi(this.context);
|
|
282
|
-
return this._civic;
|
|
305
|
+
return this.namespace('civic', (context) => new civic_1.CivicApi(context));
|
|
283
306
|
}
|
|
284
307
|
/** The user's personal data node. */
|
|
285
308
|
get nodes() {
|
|
286
|
-
|
|
287
|
-
this._nodes = new nodes_1.NodesApi(this.context);
|
|
288
|
-
return this._nodes;
|
|
309
|
+
return this.namespace('nodes', (context) => new nodes_1.NodesApi(context));
|
|
289
310
|
}
|
|
290
311
|
/** This user's devices, their sessions, and device sign-in. */
|
|
291
312
|
get devices() {
|
|
292
|
-
|
|
293
|
-
this._devices = new devices_1.DevicesApi(this.context);
|
|
294
|
-
return this._devices;
|
|
313
|
+
return this.namespace('devices', (context) => new devices_1.DevicesApi(context));
|
|
295
314
|
}
|
|
296
315
|
get topics() {
|
|
297
|
-
|
|
298
|
-
this._topics = new topics_1.TopicsApi(this.context);
|
|
299
|
-
return this._topics;
|
|
316
|
+
return this.namespace('topics', (context) => new topics_1.TopicsApi(context));
|
|
300
317
|
}
|
|
301
318
|
/** Per-app key/value data stored on the user's account. */
|
|
302
319
|
get appData() {
|
|
303
|
-
|
|
304
|
-
this._appData = new appData_1.AppDataApi(this.context);
|
|
305
|
-
return this._appData;
|
|
320
|
+
return this.namespace('appData', (context) => new appData_1.AppDataApi(context));
|
|
306
321
|
}
|
|
307
322
|
/** Oxy Console: first-run onboarding (terms and use cases) for the signed-in person. */
|
|
308
323
|
get console() {
|
|
309
|
-
|
|
310
|
-
this._console = new console_1.ConsoleApi(this.context);
|
|
311
|
-
return this._console;
|
|
324
|
+
return this.namespace('console', (context) => new console_1.ConsoleApi(context));
|
|
312
325
|
}
|
|
313
326
|
get contacts() {
|
|
314
|
-
|
|
315
|
-
this._contacts = new contacts_1.ContactsApi(this.context);
|
|
316
|
-
return this._contacts;
|
|
327
|
+
return this.namespace('contacts', (context) => new contacts_1.ContactsApi(context));
|
|
317
328
|
}
|
|
318
329
|
}
|
|
319
330
|
exports.OxyServices = OxyServices;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assertCallOptions = assertCallOptions;
|
|
4
|
+
exports.applyCallOptions = applyCallOptions;
|
|
5
|
+
exports.sendWithCallOptions = sendWithCallOptions;
|
|
6
|
+
/**
|
|
7
|
+
* Per-call transport options, for any namespace call.
|
|
8
|
+
*
|
|
9
|
+
* `oxy.withCallOptions({ timeout: 60_000 }).assets.setVisibility(id, 'public')`
|
|
10
|
+
* sends that one call with its own budget, without a second client and without
|
|
11
|
+
* every method growing an options parameter of its own. The scope is a view of
|
|
12
|
+
* the same client: same session, cache, service lane and namespaces' state.
|
|
13
|
+
*/
|
|
14
|
+
const HttpService_1 = require("../HttpService");
|
|
15
|
+
/** Throws for a budget the transport cannot honour (0, negative, NaN, Infinity). */
|
|
16
|
+
function assertCallOptions(options) {
|
|
17
|
+
for (const key of ['timeout', 'deadline']) {
|
|
18
|
+
const value = options[key];
|
|
19
|
+
if (value !== undefined && (!Number.isFinite(value) || value <= 0)) {
|
|
20
|
+
throw new RangeError(`${key} must be a positive number of milliseconds`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The request options a method chose, with the scope's applied on top. The
|
|
26
|
+
* signal is NOT merged here: two signals need a linked controller that lives
|
|
27
|
+
* exactly as long as the request ({@link sendWithCallOptions}).
|
|
28
|
+
*/
|
|
29
|
+
function applyCallOptions(method, scope) {
|
|
30
|
+
const merged = { ...method };
|
|
31
|
+
if (scope.timeout !== undefined)
|
|
32
|
+
merged.timeout = scope.timeout;
|
|
33
|
+
if (scope.deadline !== undefined)
|
|
34
|
+
merged.deadline = scope.deadline;
|
|
35
|
+
if (scope.retry === false)
|
|
36
|
+
merged.retry = false;
|
|
37
|
+
else if (scope.retry === true && merged.retry === undefined)
|
|
38
|
+
merged.retry = true;
|
|
39
|
+
return merged;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Send one request with the scope applied: `send` receives the merged
|
|
43
|
+
* options, with a signal that aborts when either the method's or the scope's
|
|
44
|
+
* does. The link between them is released when the request settles.
|
|
45
|
+
*/
|
|
46
|
+
async function sendWithCallOptions(method, scope, send) {
|
|
47
|
+
const merged = applyCallOptions(method, scope);
|
|
48
|
+
const own = method?.signal;
|
|
49
|
+
if (!scope.signal || !own || own === scope.signal) {
|
|
50
|
+
const signal = scope.signal ?? own;
|
|
51
|
+
if (signal)
|
|
52
|
+
merged.signal = signal;
|
|
53
|
+
return send(merged);
|
|
54
|
+
}
|
|
55
|
+
const controller = new AbortController();
|
|
56
|
+
const unlinkOwn = (0, HttpService_1.linkAbort)(own, controller);
|
|
57
|
+
const unlinkScope = (0, HttpService_1.linkAbort)(scope.signal, controller);
|
|
58
|
+
merged.signal = controller.signal;
|
|
59
|
+
try {
|
|
60
|
+
return await send(merged);
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
unlinkOwn();
|
|
64
|
+
unlinkScope();
|
|
65
|
+
}
|
|
66
|
+
}
|
package/dist/cjs/index.js
CHANGED
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
* If a symbol does not appear here, it is NOT part of the public API.
|
|
22
22
|
*/
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
-
exports.
|
|
25
|
-
exports.
|
|
26
|
-
exports.
|
|
27
|
-
exports.packageInfo = exports.consumeOAuthReturnPath = exports.persistOAuthReturnPath = exports.clearOAuthHandshake = exports.readOAuthHandshake = exports.persistOAuthHandshake = exports.canonicalizeOAuthRedirectUri = exports.normalizeOAuthRedirectUri = exports.OXY_OAUTH_RETURN_PATH_STORAGE_KEY = exports.OXY_OAUTH_REDIRECT_URI_STORAGE_KEY = exports.OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY = exports.OXY_OAUTH_STATE_STORAGE_KEY = exports.OXY_AUTHORIZE_URL = exports.DEFAULT_OAUTH_SCOPE = exports.generatePkcePair = exports.generateOAuthState = exports.computeCodeChallenge = exports.buildOAuthAuthorizeUrl = exports.CENTRAL_IDP_APEX = exports.AUTH_WEB_ORIGIN = exports.getAccountColor = exports.formatPublicKeyHandle = exports.getAccountFallbackHandle = exports.getAccountDisplayName = exports.createQuickAccount = exports.buildAccountsArray = exports.updateAvatarVisibility = exports.isDev = exports.consoleSink = exports.resetLoggerConfig = exports.getLoggerConfig = exports.configureLogger = exports.createLogger = exports.logger = exports.normalizeMultilineText = void 0;
|
|
24
|
+
exports.SUPPORTED_LANGUAGES = exports.TopicSource = exports.TopicType = exports.SECURITY_EVENT_SEVERITY_MAP = exports.sessionsArraysEqual = exports.normalizeAndSortSessions = exports.mergeSessions = exports.authenticatedApiCall = exports.withAuthErrorHandling = exports.isAuthenticationError = exports.ensureValidToken = exports.AuthenticationFailedError = exports.SessionSyncRequiredError = exports.normalizeProfileLinks = exports.getNormalizedUserHandle = exports.getCanonicalUserHandle = exports.normalizeUserIdentityOrNull = exports.normalizeUserIdentity = exports.getNormalizedUserId = exports.commonsDeliveryPlatform = exports.pushTargetsFromDelivery = exports.selectCommonsDelivery = exports.parseCommonsApprovalExpiresAt = exports.getCommonsApprovalBlockingReason = exports.OxyAppDataIdentifierError = exports.AccountNotOnDeviceError = exports.REPUTATION_CACHE_PREFIX = exports.StoreInstallerError = exports.setStoreInstaller = exports.getStoreInstaller = exports.kindAcceptsAccountCategories = exports.isSelectableAccountCategoryId = exports.SELECTABLE_ACCOUNT_CATEGORY_IDS = exports.MAX_ACCOUNT_CATEGORIES = exports.ACCOUNT_CATEGORY_IDS = exports.buildUserDid = exports.DirectUploadInterruptedError = exports.MAX_UPLOAD_BYTES = exports.assetUrlCacheTTL = exports.ASSET_MULTIPART_UPLOAD_MAX_BYTES = exports.sameHolderIdentity = exports.retryAfterSecondsOf = exports.ServiceAssetMetadataError = exports.AssetUrlResolutionError = exports.OxyAuthenticationTimeoutError = exports.OxyAuthenticationError = exports.OxyApiError = exports.OXY_CLOUD_URL = exports.OXY_API_URL = exports.OxyServices = void 0;
|
|
25
|
+
exports.translate = exports.withRetry = exports.delay = exports.shouldAllowRequest = exports.recordSuccess = exports.recordFailure = exports.calculateBackoffInterval = exports.createCircuitBreakerState = exports.DEFAULT_CIRCUIT_BREAKER_CONFIG = exports.isRetryableError = exports.isNetworkError = exports.isServerError = exports.isRateLimitError = exports.isNotFoundError = exports.isForbiddenError = exports.isUnauthorizedError = exports.isAlreadyRegisteredError = exports.getErrorMessage = exports.getErrorStatus = exports.HttpStatus = exports.getSystemColorScheme = exports.systemPrefersDarkMode = exports.getOppositeTheme = exports.normalizeColorScheme = exports.normalizeTheme = exports.getContrastTextColor = exports.isLightColor = exports.withOpacity = exports.rgbToHex = exports.hexToRgb = exports.lightenColor = exports.darkenColor = exports.isWebBrowser = exports.isAndroid = exports.isIOS = exports.isNative = exports.isWeb = exports.setPlatformOS = exports.getPlatformOS = exports.coerceToSupportedLocale = exports.getPrimaryLanguage = exports.getUserLanguages = exports.isRTLLocale = exports.getNativeLanguageName = exports.getLanguageName = exports.getLanguageMetadata = exports.isSupportedLocale = exports.normalizeLocale = exports.getBaseLanguage = exports.FALLBACK_LOCALE = void 0;
|
|
26
|
+
exports.validateAndSanitizeUserInput = exports.isValidObjectId = exports.sanitizeHTML = exports.sanitizeString = exports.isValidFileType = exports.isValidFileSize = exports.isValidDate = exports.isValidURL = exports.isValidUUID = exports.isValidObject = exports.isValidArray = exports.isRequiredBoolean = exports.isRequiredNumber = exports.isRequiredString = exports.DISPLAY_NAME_UNFLANKED_SEPARATOR_SOURCE = exports.DISPLAY_NAME_ORPHANED_MARK_SOURCE = exports.DISPLAY_NAME_DISALLOWED_SOURCE = exports.DISPLAY_NAME_ALLOWED_SCRIPTS = exports.accountNameInvalidKey = exports.accountNameInvalidMessage = exports.accountNameMaxLength = exports.isValidAccountName = exports.isValidDisplayName = exports.isValidPassword = exports.isValidEmail = exports.ACCOUNT_TITLE_INVALID_MESSAGE = exports.DISPLAY_NAME_INVALID_MESSAGE = exports.MAX_DISPLAY_NAME_LENGTH = exports.PASSWORD_REGEX = exports.EMAIL_REGEX = exports.retryAsync = exports.validateRequiredFields = exports.parseHttpErrorBody = exports.isHttpRequestError = exports.handleHttpError = exports.createApiError = exports.ErrorCodes = exports.safeJsonParse = exports.buildPaginationParams = exports.buildUrl = exports.buildSearchParams = exports.buildQueryParams = exports.trustTierLabel = exports.reputationCategoryLabel = exports.accountRoleLabel = exports.accountCategoryLabel = exports.getLocalesVersion = exports.subscribeLocales = exports.isLocaleLoaded = exports.loadLocale = void 0;
|
|
27
|
+
exports.packageInfo = exports.consumeOAuthReturnPath = exports.persistOAuthReturnPath = exports.clearOAuthHandshake = exports.readOAuthHandshake = exports.persistOAuthHandshake = exports.canonicalizeOAuthRedirectUri = exports.normalizeOAuthRedirectUri = exports.OXY_OAUTH_RETURN_PATH_STORAGE_KEY = exports.OXY_OAUTH_REDIRECT_URI_STORAGE_KEY = exports.OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY = exports.OXY_OAUTH_STATE_STORAGE_KEY = exports.OXY_AUTHORIZE_URL = exports.DEFAULT_OAUTH_SCOPE = exports.generatePkcePair = exports.generateOAuthState = exports.computeCodeChallenge = exports.buildOAuthAuthorizeUrl = exports.CENTRAL_IDP_APEX = exports.AUTH_WEB_ORIGIN = exports.getAccountColor = exports.formatPublicKeyHandle = exports.getAccountFallbackHandle = exports.getAccountDisplayName = exports.createQuickAccount = exports.buildAccountsArray = exports.updateAvatarVisibility = exports.isDev = exports.consoleSink = exports.resetLoggerConfig = exports.getLoggerConfig = exports.configureLogger = exports.createLogger = exports.logger = exports.normalizeMultilineText = exports.normalizeInlineText = void 0;
|
|
28
28
|
// The crypto shim MUST stay the first import. The root itself ships no crypto
|
|
29
29
|
// library (`__tests__/rootEntryGraph.test.ts`), but `@oxy.so/protocol`'s root
|
|
30
30
|
// entry (reached by the OAuth/PKCE and device helpers) does, and Metro does not
|
|
@@ -44,6 +44,7 @@ Object.defineProperty(exports, "OxyAuthenticationError", { enumerable: true, get
|
|
|
44
44
|
Object.defineProperty(exports, "OxyAuthenticationTimeoutError", { enumerable: true, get: function () { return OxyServices_errors_1.OxyAuthenticationTimeoutError; } });
|
|
45
45
|
Object.defineProperty(exports, "AssetUrlResolutionError", { enumerable: true, get: function () { return OxyServices_errors_1.AssetUrlResolutionError; } });
|
|
46
46
|
Object.defineProperty(exports, "ServiceAssetMetadataError", { enumerable: true, get: function () { return OxyServices_errors_1.ServiceAssetMetadataError; } });
|
|
47
|
+
Object.defineProperty(exports, "retryAfterSecondsOf", { enumerable: true, get: function () { return OxyServices_errors_1.retryAfterSecondsOf; } });
|
|
47
48
|
var holderEvidence_1 = require("./api/holderEvidence");
|
|
48
49
|
Object.defineProperty(exports, "sameHolderIdentity", { enumerable: true, get: function () { return holderEvidence_1.sameHolderIdentity; } });
|
|
49
50
|
var assets_1 = require("./api/assets");
|
|
@@ -325,59 +325,42 @@ class OxyServer extends OxyServices_1.OxyServices {
|
|
|
325
325
|
throw new Error('Requester context requires an authenticated service');
|
|
326
326
|
return new requesterClient_1.OxyRequesterClient(this.baseURL, this.cloudURL, service, proof);
|
|
327
327
|
}
|
|
328
|
+
// ── Server-side namespaces ───────────────────────────────────────────────
|
|
328
329
|
/** The account graph, plus the service-only `accessFor` membership verdict. */
|
|
329
330
|
get accounts() {
|
|
330
|
-
|
|
331
|
-
this._serverAccounts = new namespaces_1.ServerAccountsApi(this.context);
|
|
332
|
-
return this._serverAccounts;
|
|
331
|
+
return this.namespace('accounts', (context) => new namespaces_1.ServerAccountsApi(context));
|
|
333
332
|
}
|
|
334
333
|
/** Files, plus the service-only metadata and linked-URL lookups. */
|
|
335
334
|
get assets() {
|
|
336
|
-
|
|
337
|
-
this._serverAssets = new namespaces_1.ServerAssetsApi(this.context);
|
|
338
|
-
return this._serverAssets;
|
|
335
|
+
return this.namespace('assets', (context) => new namespaces_1.ServerAssetsApi(context));
|
|
339
336
|
}
|
|
340
337
|
/** The inbox and push tokens, plus `create`. */
|
|
341
338
|
get notifications() {
|
|
342
|
-
|
|
343
|
-
this._serverNotifications = new namespaces_1.ServerNotificationsApi(this.context);
|
|
344
|
-
return this._serverNotifications;
|
|
339
|
+
return this.namespace('notifications', (context) => new namespaces_1.ServerNotificationsApi(context));
|
|
345
340
|
}
|
|
346
341
|
/** Linked external accounts, plus `forUser`. */
|
|
347
342
|
get linkedAccounts() {
|
|
348
|
-
|
|
349
|
-
this._serverLinkedAccounts = new namespaces_1.ServerLinkedAccountsApi(this.context);
|
|
350
|
-
return this._serverLinkedAccounts;
|
|
343
|
+
return this.namespace('linkedAccounts', (context) => new namespaces_1.ServerLinkedAccountsApi(context));
|
|
351
344
|
}
|
|
352
345
|
/** Delegated capabilities, with the service-only authority calls. */
|
|
353
346
|
get agency() {
|
|
354
|
-
|
|
355
|
-
this._serverAgency = new namespaces_1.ServerAgencyApi(this.context);
|
|
356
|
-
return this._serverAgency;
|
|
347
|
+
return this.namespace('agency', (context) => new namespaces_1.ServerAgencyApi(context));
|
|
357
348
|
}
|
|
358
349
|
/** Application management, plus the receiver-bound Alia machine-key lookup. */
|
|
359
350
|
get apps() {
|
|
360
|
-
|
|
361
|
-
this._serverApps = new namespaces_1.ServerAppsApi(this.context);
|
|
362
|
-
return this._serverApps;
|
|
351
|
+
return this.namespace('apps', (context) => new namespaces_1.ServerAppsApi(context));
|
|
363
352
|
}
|
|
364
353
|
/** Reputation reads, plus `award`. */
|
|
365
354
|
get reputation() {
|
|
366
|
-
|
|
367
|
-
this._serverReputation = new namespaces_1.ServerReputationApi(this.context);
|
|
368
|
-
return this._serverReputation;
|
|
355
|
+
return this.namespace('reputation', (context) => new namespaces_1.ServerReputationApi(context));
|
|
369
356
|
}
|
|
370
357
|
/** Policy reads, plus the consumer-service decision lanes (ADR 0041). */
|
|
371
358
|
get safety() {
|
|
372
|
-
|
|
373
|
-
this._serverSafety = new safety_1.ServerSafetyApi(this.context);
|
|
374
|
-
return this._serverSafety;
|
|
359
|
+
return this.namespace('safety', (context) => new safety_1.ServerSafetyApi(context));
|
|
375
360
|
}
|
|
376
361
|
/** Session state, plus validation through a reviewed supervised action. */
|
|
377
362
|
get session() {
|
|
378
|
-
|
|
379
|
-
this._serverSession = new session_1.ServerSessionApi(this.context, this.sessionValidationTtlMs, () => this.revocationFeedEpoch());
|
|
380
|
-
return this._serverSession;
|
|
363
|
+
return this.namespace('session', (context) => new session_1.ServerSessionApi(context, this.sessionValidationTtlMs, () => this.revocationFeedEpoch()));
|
|
381
364
|
}
|
|
382
365
|
/** Close the revocation feed along with the HTTP client. */
|
|
383
366
|
dispose() {
|
|
@@ -58,6 +58,19 @@ function stringArray(value) {
|
|
|
58
58
|
: null;
|
|
59
59
|
}
|
|
60
60
|
const RELATIONSHIPS = ['self', 'owner', 'member'];
|
|
61
|
+
const APPLICATION_TYPES = [
|
|
62
|
+
'first_party',
|
|
63
|
+
'third_party',
|
|
64
|
+
'internal',
|
|
65
|
+
'system',
|
|
66
|
+
];
|
|
67
|
+
const OFFICIAL_TYPES = ['first_party', 'internal', 'system'];
|
|
68
|
+
/** `deleted` is absent on purpose: Oxy answers a deleted application 404. */
|
|
69
|
+
const APPLICATION_STATUSES = [
|
|
70
|
+
'active',
|
|
71
|
+
'suspended',
|
|
72
|
+
'pending_review',
|
|
73
|
+
];
|
|
61
74
|
/** `GET /accounts/:id` → the caller's effective access, or `null` for a malformed answer. */
|
|
62
75
|
function parseAccountAccess(accountId, answer) {
|
|
63
76
|
const node = record(answer);
|
|
@@ -84,11 +97,16 @@ function parseApplicationAccess(applicationId, answer) {
|
|
|
84
97
|
if (!application || application._id !== applicationId)
|
|
85
98
|
return null;
|
|
86
99
|
const ownerAccountId = application.ownerAccountId;
|
|
100
|
+
const type = application.type;
|
|
101
|
+
const status = application.status;
|
|
87
102
|
const membership = record(application.callerMembership);
|
|
88
103
|
const permissions = stringArray(membership?.permissions);
|
|
89
104
|
if (typeof ownerAccountId !== 'string' ||
|
|
90
105
|
ownerAccountId === '' ||
|
|
91
106
|
typeof application.isOfficial !== 'boolean' ||
|
|
107
|
+
typeof application.isInternal !== 'boolean' ||
|
|
108
|
+
!APPLICATION_TYPES.includes(type) ||
|
|
109
|
+
!APPLICATION_STATUSES.includes(status) ||
|
|
92
110
|
!membership ||
|
|
93
111
|
typeof membership.role !== 'string' ||
|
|
94
112
|
membership.role === '' ||
|
|
@@ -99,7 +117,8 @@ function parseApplicationAccess(applicationId, answer) {
|
|
|
99
117
|
return Object.freeze({
|
|
100
118
|
applicationId,
|
|
101
119
|
ownerAccountId,
|
|
102
|
-
official: application.isOfficial,
|
|
120
|
+
official: application.isOfficial || application.isInternal || OFFICIAL_TYPES.includes(type),
|
|
121
|
+
status,
|
|
103
122
|
role: membership.role,
|
|
104
123
|
...(0, callerAuthority_1.permissionSet)(permissions),
|
|
105
124
|
});
|