@oxy.so/core 1.0.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/OxyServices.errors.js +28 -1
- package/dist/cjs/crypto/keyManager.js +5 -3
- package/dist/cjs/i18n/locales/en-US.json +18 -5
- package/dist/cjs/i18n/locales/es-ES.json +18 -5
- package/dist/cjs/i18n/locales/locales/en-US.json +18 -5
- package/dist/cjs/i18n/locales/locales/es-ES.json +18 -5
- package/dist/cjs/mixins/OxyServices.agency.js +113 -0
- package/dist/cjs/mixins/OxyServices.assets.js +90 -0
- package/dist/cjs/mixins/OxyServices.connectedApps.js +20 -3
- package/dist/cjs/mixins/OxyServices.utility.js +1 -21
- package/dist/cjs/mixins/index.js +3 -4
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/server/index.js +6 -1
- package/dist/cjs/server/traffic.js +107 -0
- package/dist/cjs/server/trafficNodeHttp.js +86 -0
- package/dist/cjs/utils/textNormalization.js +1 -1
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/OxyServices.errors.js +26 -0
- package/dist/esm/crypto/keyManager.js +5 -3
- package/dist/esm/i18n/locales/en-US.json +18 -5
- package/dist/esm/i18n/locales/es-ES.json +18 -5
- package/dist/esm/i18n/locales/locales/en-US.json +18 -5
- package/dist/esm/i18n/locales/locales/es-ES.json +18 -5
- package/dist/esm/mixins/OxyServices.agency.js +110 -0
- package/dist/esm/mixins/OxyServices.assets.js +91 -1
- package/dist/esm/mixins/OxyServices.connectedApps.js +20 -3
- package/dist/esm/mixins/OxyServices.utility.js +1 -21
- package/dist/esm/mixins/index.js +3 -4
- package/dist/esm/package.json +3 -0
- package/dist/esm/server/index.js +2 -0
- package/dist/esm/server/traffic.js +104 -0
- package/dist/esm/server/trafficNodeHttp.js +79 -0
- package/dist/esm/utils/textNormalization.js +1 -1
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/OxyServices.errors.d.ts +24 -0
- package/dist/types/crypto/keyManager.d.ts +4 -2
- package/dist/types/index.d.ts +2 -1
- package/dist/types/mixins/OxyServices.agency.d.ts +135 -0
- package/dist/types/mixins/OxyServices.assets.d.ts +43 -1
- package/dist/types/mixins/OxyServices.connectedApps.d.ts +15 -0
- package/dist/types/mixins/OxyServices.utility.d.ts +0 -9
- package/dist/types/mixins/index.d.ts +2 -2
- package/dist/types/models/interfaces.d.ts +26 -0
- package/dist/types/server/index.d.ts +3 -0
- package/dist/types/server/traffic.d.ts +27 -0
- package/dist/types/server/trafficNodeHttp.d.ts +6 -0
- package/dist/types/utils/textNormalization.d.ts +1 -1
- package/package.json +7 -6
- package/src/OxyServices.errors.ts +36 -0
- package/src/crypto/keyManager.ts +5 -4
- package/src/i18n/locales/en-US.json +18 -5
- package/src/i18n/locales/es-ES.json +18 -5
- package/src/index.ts +15 -0
- package/src/mixins/OxyServices.agency.ts +277 -0
- package/src/mixins/OxyServices.assets.ts +105 -2
- package/src/mixins/OxyServices.connectedApps.ts +42 -4
- package/src/mixins/OxyServices.utility.ts +1 -26
- package/src/mixins/__tests__/OxyServices.serviceLinkedDownloadUrl.test.ts +139 -0
- package/src/mixins/__tests__/agency.test.ts +120 -0
- package/src/mixins/__tests__/connectedApps.test.ts +23 -0
- package/src/mixins/index.ts +4 -5
- package/src/models/interfaces.ts +27 -0
- package/src/server/__tests__/traffic.test.ts +49 -0
- package/src/server/__tests__/trafficNodeHttp.test.ts +38 -0
- package/src/server/index.ts +5 -0
- package/src/server/traffic.ts +116 -0
- package/src/server/trafficNodeHttp.ts +69 -0
- package/src/utils/textNormalization.ts +1 -1
- package/dist/cjs/mixins/OxyServices.links.js +0 -72
- package/dist/esm/mixins/OxyServices.links.js +0 -69
- package/dist/types/mixins/OxyServices.links.d.ts +0 -104
- package/src/mixins/OxyServices.links.ts +0 -107
- package/src/mixins/__tests__/OxyServices.links.test.ts +0 -154
|
@@ -79,6 +79,30 @@ export declare class ServiceAssetMetadataError extends Error {
|
|
|
79
79
|
readonly cause?: unknown;
|
|
80
80
|
constructor(unresolvedIds: string[], statuses: number[], cause?: unknown);
|
|
81
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* A chunk of `POST /assets/service/linked-url` failed, so the SDK cannot say
|
|
84
|
+
* whether those ids have URLs.
|
|
85
|
+
*
|
|
86
|
+
* Its own class rather than a reuse of {@link ServiceAssetMetadataError}, and
|
|
87
|
+
* deliberately WITHOUT that one's `{ partial: true }` escape hatch, because the
|
|
88
|
+
* two mistakes cost different things. Reading a failed metadata lookup as
|
|
89
|
+
* "absent" embedded a media item with no hash. Reading a failed DOWNLOAD mint as
|
|
90
|
+
* "absent" tells a buyer who paid that the file they own is not there — and
|
|
91
|
+
* "not there" is already this route's answer for "not yours", so a best-effort
|
|
92
|
+
* mode would make a throttled request indistinguishable from a refusal. There is
|
|
93
|
+
* no download path that legitimately wants that, so there is no option to ask
|
|
94
|
+
* for it.
|
|
95
|
+
*/
|
|
96
|
+
export declare class ServiceLinkedDownloadUrlError extends Error {
|
|
97
|
+
readonly code = "SERVICE_LINKED_DOWNLOAD_URL_UNRESOLVED";
|
|
98
|
+
/** Every id belonging to a chunk whose request failed. */
|
|
99
|
+
readonly unresolvedIds: string[];
|
|
100
|
+
/** HTTP statuses observed across the failed chunks (deduped, ascending). */
|
|
101
|
+
readonly statuses: number[];
|
|
102
|
+
/** The first underlying transport/API failure — see the sibling class. */
|
|
103
|
+
readonly cause?: unknown;
|
|
104
|
+
constructor(unresolvedIds: string[], statuses: number[], cause?: unknown);
|
|
105
|
+
}
|
|
82
106
|
export declare class OxyAuthenticationTimeoutError extends OxyAuthenticationError {
|
|
83
107
|
constructor(operationName: string, timeoutMs: number);
|
|
84
108
|
}
|
|
@@ -559,12 +559,14 @@ export declare class KeyManager {
|
|
|
559
559
|
*
|
|
560
560
|
* The domain separation is carried by `info` (e.g. `"oxypay/faircoin/v1"`),
|
|
561
561
|
* so distinct apps/purposes get independent seeds from the same identity.
|
|
562
|
+
* That legacy Peable tag is a cryptographic contract and must not be renamed:
|
|
563
|
+
* changing it would derive a different wallet for every existing user.
|
|
562
564
|
* The output is HKDF keying material, never the private key itself — a
|
|
563
|
-
* consumer (e.g.
|
|
565
|
+
* consumer (e.g. Peable's FairCoin HD wallet) can feed it straight into
|
|
564
566
|
* `HDKey.fromMasterSeed` and never touches the identity key.
|
|
565
567
|
*
|
|
566
568
|
* Key source (native only): prefers the shared ecosystem identity written to
|
|
567
|
-
* `group.so.oxy.shared` (what a Relying Party like
|
|
569
|
+
* `group.so.oxy.shared` (what a Relying Party like Peable reads), then falls
|
|
568
570
|
* back to this device's primary identity (Commons/Accounts). Both reproduce
|
|
569
571
|
* from the user's Oxy recovery phrase, so the derived seed is recoverable.
|
|
570
572
|
*
|
package/dist/types/index.d.ts
CHANGED
|
@@ -38,7 +38,8 @@ export { getCanonicalUserHandle, getNormalizedUserHandle, } from './utils/userHa
|
|
|
38
38
|
export type { CanonicalUserHandleInput, UserHandleInput } from './utils/userHandle';
|
|
39
39
|
export { normalizeProfileLinks } from './utils/profileLinks';
|
|
40
40
|
export type { ProfileLink, ProfileLinkMetadata } from './utils/profileLinks';
|
|
41
|
-
export type { PublicApplication, ConnectedApp, } from './mixins/OxyServices.connectedApps';
|
|
41
|
+
export type { PublicApplication, ConnectedApp, ConnectedMcpClient, } from './mixins/OxyServices.connectedApps';
|
|
42
|
+
export type { AccountCapabilityPolicy, AvailableCapabilityCatalog, CapabilityExecutionAuthorization, CreateDelegationGrantInput, DelegationCatalogBinding, DelegationGrantView, PutAccountCapabilityPolicyInput, UpdateDelegationGrantInput, } from './mixins/OxyServices.agency';
|
|
42
43
|
export type { StoreCategory, StoreRating, StoreListingSummary, StoreListingDetail, StoreScreenshot, StoreScreenshotPlatform, StoreReview, StoreOwnReview, WriteStoreReviewInput, StoreListingStatus, PublisherListing, WriteListingInput, AddScreenshotInput, UpdateScreenshotInput, StorePage, StorePageOptions, StoreReviewsOptions, } from './mixins/OxyServices.store';
|
|
43
44
|
export type { AccountKind, AccountCategoryId, AccountRelationship, AccountRole, AccountMemberStatus, AccountMemberSource, AccountMember, AccountNode, ListAccountsOptions, CreateAccountInput, UpdateAccountInput, ProvisionChannelInput, ProvisionChannelMemberInput, ProvisionChannelResult, InviteAccountMemberInput, UpdateAccountMemberInput, TransferAccountOwnershipInput, AccountSuccessResult, SwitchAccountResult, Application, ApplicationType, ApplicationStatus, ApplicationCredential, ApplicationCredentialType, ApplicationCredentialStatus, ApplicationEnvironment, CreateApplicationInput, UpdateApplicationInput, CreateApplicationCredentialInput, RotateApplicationCredentialInput, ApplicationCredentialWithSecret, RotateApplicationCredentialResult, ApplicationUsagePeriod, ApplicationUsageSummary, ApplicationUsageByDay, ApplicationUsageByEndpoint, ApplicationUsageStats, } from './mixins/OxyServices.accounts';
|
|
44
45
|
export { ACCOUNT_CATEGORY_IDS, MAX_ACCOUNT_CATEGORIES, SELECTABLE_ACCOUNT_CATEGORY_IDS, isSelectableAccountCategoryId, kindAcceptsAccountCategories, } from './mixins/OxyServices.accounts';
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native Alia and digital-agent authority.
|
|
3
|
+
*
|
|
4
|
+
* These methods manage Oxy-owned delegation grants, account autonomy policy,
|
|
5
|
+
* execution authorizations and their audit trail. They deliberately use the
|
|
6
|
+
* signed-in account session: capability tickets and app service credentials
|
|
7
|
+
* stay on the server and are never exposed to Settings clients.
|
|
8
|
+
*/
|
|
9
|
+
import type { AppCapabilityCatalog, AuditEvent, AutonomyLevel, CapabilityCatalogBinding, CapabilityPackage, DelegationGrant, GrantLimit, ResourceRef, ToolGrantOverride } from '@oxy.so/contracts';
|
|
10
|
+
import type { OxyServicesBase } from '../OxyServices.base';
|
|
11
|
+
export type DelegationCatalogBinding = CapabilityCatalogBinding;
|
|
12
|
+
export type DelegationGrantView = DelegationGrant;
|
|
13
|
+
export interface CreateDelegationGrantInput {
|
|
14
|
+
ownerAccountId: string;
|
|
15
|
+
actorAccountId: string;
|
|
16
|
+
resource: ResourceRef;
|
|
17
|
+
capabilityPackages: CapabilityPackage[];
|
|
18
|
+
capabilities: string[];
|
|
19
|
+
toolOverrides?: ToolGrantOverride[];
|
|
20
|
+
limits?: GrantLimit[];
|
|
21
|
+
maximumAutonomy: AutonomyLevel;
|
|
22
|
+
canRedelegate?: boolean;
|
|
23
|
+
expiresAt?: string | null;
|
|
24
|
+
}
|
|
25
|
+
export type UpdateDelegationGrantInput = Pick<CreateDelegationGrantInput, 'capabilityPackages' | 'capabilities' | 'toolOverrides' | 'limits' | 'maximumAutonomy' | 'canRedelegate' | 'expiresAt'>;
|
|
26
|
+
export interface AvailableCapabilityCatalog {
|
|
27
|
+
id: string;
|
|
28
|
+
appId: string;
|
|
29
|
+
version: string;
|
|
30
|
+
digest: string;
|
|
31
|
+
audience: string;
|
|
32
|
+
catalog: AppCapabilityCatalog;
|
|
33
|
+
}
|
|
34
|
+
export interface AccountCapabilityPolicy {
|
|
35
|
+
id: string;
|
|
36
|
+
accountId: string;
|
|
37
|
+
appSlug: string;
|
|
38
|
+
maximumAutonomy: AutonomyLevel;
|
|
39
|
+
deniedCapabilities: string[];
|
|
40
|
+
createdAt: string;
|
|
41
|
+
updatedAt: string;
|
|
42
|
+
}
|
|
43
|
+
export interface PutAccountCapabilityPolicyInput {
|
|
44
|
+
accountId: string;
|
|
45
|
+
maximumAutonomy: AutonomyLevel;
|
|
46
|
+
deniedCapabilities: string[];
|
|
47
|
+
}
|
|
48
|
+
export interface CapabilityExecutionAuthorization {
|
|
49
|
+
id: string;
|
|
50
|
+
kind: 'direct_request' | 'automation';
|
|
51
|
+
requesterAccountId: string;
|
|
52
|
+
ownerAccountId: string;
|
|
53
|
+
coordinatorApplicationId: string;
|
|
54
|
+
coordinatorCredentialId: string;
|
|
55
|
+
actorType: 'alia' | 'agent';
|
|
56
|
+
actorAccountId: string | null;
|
|
57
|
+
resourceApp: string;
|
|
58
|
+
effectiveAccountId: string;
|
|
59
|
+
resourceType: string;
|
|
60
|
+
resourceKey: string;
|
|
61
|
+
tool: string;
|
|
62
|
+
runId: string | null;
|
|
63
|
+
stepId: string | null;
|
|
64
|
+
automationId: string | null;
|
|
65
|
+
maximumAutonomy: AutonomyLevel;
|
|
66
|
+
limits: GrantLimit[];
|
|
67
|
+
expiresAt: string;
|
|
68
|
+
revokedAt: string | null;
|
|
69
|
+
createdAt: string;
|
|
70
|
+
updatedAt: string;
|
|
71
|
+
}
|
|
72
|
+
export declare function OxyServicesAgencyMixin<T extends typeof OxyServicesBase>(Base: T): {
|
|
73
|
+
new (...args: any[]): {
|
|
74
|
+
listAvailableCapabilityCatalogs(accountId: string): Promise<AvailableCapabilityCatalog[]>;
|
|
75
|
+
listDelegationGrants(ownerAccountId: string): Promise<DelegationGrantView[]>;
|
|
76
|
+
createDelegationGrant(input: CreateDelegationGrantInput): Promise<DelegationGrantView>;
|
|
77
|
+
revokeDelegationGrant(grantId: string, ownerAccountId: string): Promise<void>;
|
|
78
|
+
updateDelegationGrant(grantId: string, ownerAccountId: string, input: UpdateDelegationGrantInput): Promise<DelegationGrantView>;
|
|
79
|
+
listAccountCapabilityPolicies(accountId: string): Promise<AccountCapabilityPolicy[]>;
|
|
80
|
+
putAccountCapabilityPolicy(appId: string, input: PutAccountCapabilityPolicyInput): Promise<AccountCapabilityPolicy>;
|
|
81
|
+
deleteAccountCapabilityPolicy(appId: string, accountId: string): Promise<void>;
|
|
82
|
+
listCapabilityExecutionAuthorizations(ownerAccountId: string): Promise<CapabilityExecutionAuthorization[]>;
|
|
83
|
+
revokeCapabilityExecutionAuthorization(authorizationId: string, ownerAccountId: string): Promise<void>;
|
|
84
|
+
listCapabilityAuditEvents(accountId: string): Promise<AuditEvent[]>;
|
|
85
|
+
httpService: import("../HttpService").HttpService;
|
|
86
|
+
cloudURL: string;
|
|
87
|
+
config: import("../OxyServices.base").OxyConfig;
|
|
88
|
+
__resetTokensForTests(): void;
|
|
89
|
+
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
90
|
+
getBaseURL(): string;
|
|
91
|
+
getClient(): import("../HttpService").HttpService;
|
|
92
|
+
createLinkedClient(config: import("../OxyServices.base").OxyConfig): import("..").LinkedHttpClient;
|
|
93
|
+
getMetrics(): {
|
|
94
|
+
totalRequests: number;
|
|
95
|
+
successfulRequests: number;
|
|
96
|
+
failedRequests: number;
|
|
97
|
+
cacheHits: number;
|
|
98
|
+
cacheMisses: number;
|
|
99
|
+
averageResponseTime: number;
|
|
100
|
+
};
|
|
101
|
+
clearCache(): void;
|
|
102
|
+
clearCacheEntry(key: string): void;
|
|
103
|
+
clearCacheByPrefix(prefix: string): number;
|
|
104
|
+
getCacheStats(): {
|
|
105
|
+
size: number;
|
|
106
|
+
hits: number;
|
|
107
|
+
misses: number;
|
|
108
|
+
hitRate: number;
|
|
109
|
+
};
|
|
110
|
+
getCloudURL(): string;
|
|
111
|
+
setTokens(accessToken: string): void;
|
|
112
|
+
clearTokens(): void;
|
|
113
|
+
onTokensChanged(listener: (accessToken: string | null) => void): () => void;
|
|
114
|
+
_cachedUserId: string | null | undefined;
|
|
115
|
+
_cachedAccessToken: string | null;
|
|
116
|
+
getCurrentUserId(): string | null;
|
|
117
|
+
hasValidToken(): boolean;
|
|
118
|
+
getAccessToken(): string | null;
|
|
119
|
+
getAccessTokenExpiry(): number | null;
|
|
120
|
+
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
121
|
+
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
122
|
+
maxRetries?: number;
|
|
123
|
+
retryDelay?: number;
|
|
124
|
+
authTimeoutMs?: number;
|
|
125
|
+
}): Promise<T_1>;
|
|
126
|
+
validate(): Promise<boolean>;
|
|
127
|
+
handleError(error: unknown): Error;
|
|
128
|
+
healthCheck(): Promise<{
|
|
129
|
+
status: string;
|
|
130
|
+
users?: number;
|
|
131
|
+
timestamp?: string;
|
|
132
|
+
[key: string]: any;
|
|
133
|
+
}>;
|
|
134
|
+
};
|
|
135
|
+
} & T;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AccountStorageUsageResponse, AssetUploadInput, AssetUrlResponse, AssetVariant, BatchFileAccessResponse, ServiceAssetMetadata, ServiceAssetMetadataBySha } from '../models/interfaces';
|
|
1
|
+
import type { AccountStorageUsageResponse, AssetUploadInput, AssetUrlResponse, AssetVariant, BatchFileAccessResponse, ServiceAssetMetadata, ServiceAssetMetadataBySha, ServiceLinkedDownloadUrl } from '../models/interfaces';
|
|
2
2
|
import type { OxyServicesBase } from '../OxyServices.base';
|
|
3
3
|
export declare function OxyServicesAssetsMixin<T extends typeof OxyServicesBase>(Base: T): {
|
|
4
4
|
new (...args: any[]): {
|
|
@@ -181,6 +181,48 @@ export declare function OxyServicesAssetsMixin<T extends typeof OxyServicesBase>
|
|
|
181
181
|
getServiceAssetMetadataByIds(ids: string[], options?: {
|
|
182
182
|
partial?: boolean;
|
|
183
183
|
}): Promise<ServiceAssetMetadata[]>;
|
|
184
|
+
/**
|
|
185
|
+
* Mint short-lived direct download URLs for files the calling application's
|
|
186
|
+
* own users attached to it, via `POST /assets/service/linked-url`.
|
|
187
|
+
*
|
|
188
|
+
* This is the ONLY path in this SDK by which a service token reaches file
|
|
189
|
+
* BYTES. {@link getServiceAssetMetadataByIds} is metadata-only, and every
|
|
190
|
+
* other download helper here — {@link getFileDownloadUrl},
|
|
191
|
+
* {@link getFileDownloadUrlAsync}, {@link getBatchFileAccess} — resolves a URL
|
|
192
|
+
* for the CURRENT USER through `makeRequest`, which is a different question: a
|
|
193
|
+
* relying service holds no user session, and the buyer whose entitlement it is
|
|
194
|
+
* enforcing is not a viewer Oxy knows anything about.
|
|
195
|
+
*
|
|
196
|
+
* **Service-token auth (required), plus the `files:linked:read` scope**, which
|
|
197
|
+
* is NOT implied by `files:read`. The calling client must be service-configured
|
|
198
|
+
* (`configureServiceAuth(apiKey, apiSecret)`); a user-session request is
|
|
199
|
+
* rejected by the route's service-auth guard.
|
|
200
|
+
*
|
|
201
|
+
* **What the server will and will not give you.** A URL comes back only for a
|
|
202
|
+
* file whose OWN OWNER linked it to this application (`file_links.created_by =
|
|
203
|
+
* files.owner_user_id`). Every other id is omitted: unknown, deleted,
|
|
204
|
+
* system-owned, linked by somebody else, or not linked here at all. So the
|
|
205
|
+
* result is routinely shorter than the input and must be mapped by `id`.
|
|
206
|
+
*
|
|
207
|
+
* ABSENCE IS A REFUSAL, NOT A FACT ABOUT THE FILE, and the caller is the only
|
|
208
|
+
* party that can tell the difference. The route deliberately cannot — it
|
|
209
|
+
* answers identically for "no such file" and "not yours" so it leaks nothing —
|
|
210
|
+
* which means a service must decide what to tell its user from its OWN
|
|
211
|
+
* entitlement record, never from this response. Do not surface "file not
|
|
212
|
+
* found" on the strength of an omission.
|
|
213
|
+
*
|
|
214
|
+
* FAILURE IS NOT ABSENCE EITHER, and here it cannot be opted out of: a failed
|
|
215
|
+
* chunk throws {@link ServiceLinkedDownloadUrlError} carrying its ids, with no
|
|
216
|
+
* `{ partial: true }` mode. Swallowing a 429 would tell a user who paid for a
|
|
217
|
+
* file that it is not there. An empty input resolves to `[]` with no network
|
|
218
|
+
* call.
|
|
219
|
+
*
|
|
220
|
+
* Never cached at the SDK layer, and that is a stronger statement than the
|
|
221
|
+
* sibling methods' "low hit rate": each entry is a live credential for the
|
|
222
|
+
* bytes, so caching one keeps it usable after the service has decided the
|
|
223
|
+
* caller's entitlement ended.
|
|
224
|
+
*/
|
|
225
|
+
getServiceLinkedDownloadUrls(ids: string[]): Promise<ServiceLinkedDownloadUrl[]>;
|
|
184
226
|
/**
|
|
185
227
|
* Reverse content-address lookup: resolve many content `sha256` digests to
|
|
186
228
|
* the servable Oxy asset holding each, in one round-trip per chunk via
|
|
@@ -77,6 +77,17 @@ export interface ConnectedApp {
|
|
|
77
77
|
/** ISO timestamp of when the grant was last exercised. */
|
|
78
78
|
lastUsedAt: string;
|
|
79
79
|
}
|
|
80
|
+
/** An external MCP client authorized for one exact app resource and account. */
|
|
81
|
+
export interface ConnectedMcpClient {
|
|
82
|
+
id: string;
|
|
83
|
+
appSlug: string;
|
|
84
|
+
resource: string;
|
|
85
|
+
scopes: string[];
|
|
86
|
+
clientId: string;
|
|
87
|
+
clientName: string;
|
|
88
|
+
createdAt: string;
|
|
89
|
+
lastUsedAt: string;
|
|
90
|
+
}
|
|
80
91
|
export declare function OxyServicesConnectedAppsMixin<T extends typeof OxyServicesBase>(Base: T): {
|
|
81
92
|
new (...args: any[]): {
|
|
82
93
|
/**
|
|
@@ -116,6 +127,10 @@ export declare function OxyServicesConnectedAppsMixin<T extends typeof OxyServic
|
|
|
116
127
|
* @param applicationId - The connected application's Mongo `_id`.
|
|
117
128
|
*/
|
|
118
129
|
revokeAppGrant(applicationId: string): Promise<void>;
|
|
130
|
+
/** List resource-bound external MCP connections for the active Oxy account. */
|
|
131
|
+
listConnectedMcpClients(): Promise<ConnectedMcpClient[]>;
|
|
132
|
+
/** Revoke one external MCP connection and every token in its family. */
|
|
133
|
+
revokeConnectedMcpClient(grantId: string): Promise<void>;
|
|
119
134
|
httpService: import("../HttpService").HttpService;
|
|
120
135
|
cloudURL: string;
|
|
121
136
|
config: import("../OxyServices.base").OxyConfig;
|
|
@@ -121,15 +121,6 @@ export declare function OxyServicesUtilityMixin<T extends typeof OxyServicesBase
|
|
|
121
121
|
* @internal Used by the auth() middleware — not part of the public API
|
|
122
122
|
*/
|
|
123
123
|
verifyServiceActingAs(appId: string, userId: string): Promise<ServiceActingAsVerification | null>;
|
|
124
|
-
/**
|
|
125
|
-
* Fetch link metadata
|
|
126
|
-
*/
|
|
127
|
-
fetchLinkMetadata(url: string): Promise<{
|
|
128
|
-
url: string;
|
|
129
|
-
title: string;
|
|
130
|
-
description: string;
|
|
131
|
-
image?: string;
|
|
132
|
-
}>;
|
|
133
124
|
/**
|
|
134
125
|
* Express.js authentication middleware
|
|
135
126
|
*
|
|
@@ -16,6 +16,7 @@ import { OxyServicesReputationMixin } from './OxyServices.reputation';
|
|
|
16
16
|
import { OxyServicesAssetsMixin } from './OxyServices.assets';
|
|
17
17
|
import { OxyServicesAccountsMixin } from './OxyServices.accounts';
|
|
18
18
|
import { OxyServicesConnectedAppsMixin } from './OxyServices.connectedApps';
|
|
19
|
+
import { OxyServicesAgencyMixin } from './OxyServices.agency';
|
|
19
20
|
import { OxyServicesStoreMixin } from './OxyServices.store';
|
|
20
21
|
import { OxyServicesLocationMixin } from './OxyServices.location';
|
|
21
22
|
import { OxyServicesAnalyticsMixin } from './OxyServices.analytics';
|
|
@@ -30,7 +31,6 @@ import { OxyServicesAppDataMixin } from './OxyServices.appData';
|
|
|
30
31
|
import { OxyServicesCivicMixin } from './OxyServices.civic';
|
|
31
32
|
import { OxyServicesChainsMixin } from './OxyServices.chains';
|
|
32
33
|
import { OxyServicesNodesMixin } from './OxyServices.nodes';
|
|
33
|
-
import { OxyServicesLinksMixin } from './OxyServices.links';
|
|
34
34
|
import { OxyServicesFollowGraphMixin } from './OxyServices.followGraph';
|
|
35
35
|
import { OxyServicesInferenceMixin } from './OxyServices.inference';
|
|
36
36
|
import { OxyServicesDeviceBootMixin } from './OxyServices.deviceBoot';
|
|
@@ -44,7 +44,7 @@ import { OxyServicesDeviceTransferMixin } from './OxyServices.deviceTransfer';
|
|
|
44
44
|
* If you add a new mixin to `MIXIN_PIPELINE`, add it here too so its methods
|
|
45
45
|
* are visible without a cast.
|
|
46
46
|
*/
|
|
47
|
-
type AllMixinInstances = InstanceType<ReturnType<typeof OxyServicesAuthMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesUserMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesIdentityMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesIdentityBackupMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesPrivacyMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesLanguageMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesPaymentMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesReputationMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesAssetsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesAccountsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesConnectedAppsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof
|
|
47
|
+
type AllMixinInstances = InstanceType<ReturnType<typeof OxyServicesAuthMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesUserMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesIdentityMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesIdentityBackupMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesPrivacyMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesLanguageMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesPaymentMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesReputationMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesAssetsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesAccountsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesConnectedAppsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesAgencyMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesStoreMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesLocationMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesAnalyticsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesDevicesMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesSecurityMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesFeaturesMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesTopicsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesContactsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesNotificationsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesAppDataMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesCivicMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesChainsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesNodesMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesFollowGraphMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesInferenceMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesDeviceBootMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesDeviceTransferMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesUtilityMixin<typeof OxyServicesBase>>>;
|
|
48
48
|
/**
|
|
49
49
|
* Constructor type for the fully composed mixin pipeline. Each mixin returns
|
|
50
50
|
* a new constructor that augments its input; reducing across the pipeline
|
|
@@ -525,6 +525,32 @@ export interface AssetUpdateVisibilityResponse {
|
|
|
525
525
|
* deleted ids are omitted from the response (never error the whole batch),
|
|
526
526
|
* so the result may be shorter than the requested id list.
|
|
527
527
|
*/
|
|
528
|
+
/**
|
|
529
|
+
* A short-lived direct download URL for a file the calling application's own
|
|
530
|
+
* user attached to it, from `POST /assets/service/linked-url`.
|
|
531
|
+
*
|
|
532
|
+
* `url` is BEARER AUTHORITY over the bytes for `expiresIn` seconds: whoever
|
|
533
|
+
* holds the string is the reader, and nothing about the calling service's
|
|
534
|
+
* entitlement is re-evaluated when it is used. Hand it only to a caller the
|
|
535
|
+
* service has itself authorized, and never log it.
|
|
536
|
+
*
|
|
537
|
+
* `expiresIn` bounds when a transfer may START, not how long one may take. A
|
|
538
|
+
* large file downloads fine on a slow link; a RESUMED range request after the
|
|
539
|
+
* deadline does not, and needs a fresh URL.
|
|
540
|
+
*
|
|
541
|
+
* Unlike {@link ServiceAssetMetadata}, the absence of an id from the response is
|
|
542
|
+
* an AUTHORIZATION answer as often as an existence one — see
|
|
543
|
+
* `getServiceLinkedDownloadUrls`.
|
|
544
|
+
*/
|
|
545
|
+
export interface ServiceLinkedDownloadUrl {
|
|
546
|
+
id: string;
|
|
547
|
+
url: string;
|
|
548
|
+
/** Seconds from issue until `url` stops being accepted. */
|
|
549
|
+
expiresIn: number;
|
|
550
|
+
mime: string;
|
|
551
|
+
size: number;
|
|
552
|
+
sha256: string;
|
|
553
|
+
}
|
|
528
554
|
export interface ServiceAssetMetadata {
|
|
529
555
|
id: string;
|
|
530
556
|
sha256: string;
|
|
@@ -33,3 +33,6 @@ export { evictOxyIdentityCache, oxyUserByIdCacheKey, OXY_IDENTITY_CACHE_PREFIXES
|
|
|
33
33
|
export type { OxyIdentityCacheEvictor } from '../utils/identityCacheSweep';
|
|
34
34
|
export { registrableApex } from '../utils/registrableApex';
|
|
35
35
|
export { isOfficialWebOrigin } from '../utils/officialOrigins';
|
|
36
|
+
export { createEcosystemTraffic } from './traffic';
|
|
37
|
+
export type { EcosystemTrafficOptions } from './traffic';
|
|
38
|
+
export { observeNodeHttp, withoutNodeHttpObservation } from './trafficNodeHttp';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { observeTrafficSocket, observeTrafficWebSocket, type TrafficWebSocket, type TrafficSocket } from '@oxy.so/telemetry/socket';
|
|
2
|
+
import type { RequestHandler } from 'express';
|
|
3
|
+
import { trafficMiddleware, type TrafficFlow, type ServiceEndpoint } from '@oxy.so/telemetry/collector';
|
|
4
|
+
export interface EcosystemTrafficOptions {
|
|
5
|
+
service: string;
|
|
6
|
+
region?: string;
|
|
7
|
+
baseURL?: string;
|
|
8
|
+
credential?: () => Promise<string>;
|
|
9
|
+
resolveEndpoint?: (url: URL) => ServiceEndpoint | undefined;
|
|
10
|
+
onError?: () => void;
|
|
11
|
+
ready?: () => boolean;
|
|
12
|
+
location?: {
|
|
13
|
+
label: string;
|
|
14
|
+
coordinates: [number, number];
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/** Install once per service process, before registering HTTP routes. */
|
|
18
|
+
export declare function createEcosystemTraffic(options: EcosystemTrafficOptions): {
|
|
19
|
+
middleware: RequestHandler;
|
|
20
|
+
record(flow: Omit<TrafficFlow, 'service' | 'region'>): void;
|
|
21
|
+
wrapFetch(fetcher: typeof fetch): typeof fetch;
|
|
22
|
+
installFetch(): void;
|
|
23
|
+
observeHttp: ReturnType<typeof trafficMiddleware>;
|
|
24
|
+
observeSocket(socket: TrafficSocket, options?: Parameters<typeof observeTrafficSocket>[4]): () => void;
|
|
25
|
+
observeWebSocket(socket: TrafficWebSocket, options?: Parameters<typeof observeTrafficWebSocket>[4]): () => void;
|
|
26
|
+
stop(): Promise<void>;
|
|
27
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type TrafficFlow, type ServiceEndpoint } from '@oxy.so/telemetry/collector';
|
|
2
|
+
export declare function withoutNodeHttpObservation<T>(callback: () => T): T;
|
|
3
|
+
/** Node and Bun share the HTTP facade; Bun does not emit Node's HTTP diagnostic channels. */
|
|
4
|
+
export declare function observeNodeHttp(collector: {
|
|
5
|
+
record(flow: TrafficFlow): void;
|
|
6
|
+
}, service: string, region: string, resolveEndpoint: (url: URL) => ServiceEndpoint | undefined): () => void;
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
* normalize whitespace and Unicode form.
|
|
44
44
|
*/
|
|
45
45
|
/**
|
|
46
|
-
* Normalize a SINGLE-LINE text value
|
|
46
|
+
* Normalize a SINGLE-LINE text value such as a page title or `siteName`,
|
|
47
47
|
* display names, image alt text, handles, profile field labels.
|
|
48
48
|
*
|
|
49
49
|
* A line break in such a value is never meaningful — it is an artifact of the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oxy.so/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
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",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"node": ">=18.0.0"
|
|
87
87
|
},
|
|
88
88
|
"scripts": {
|
|
89
|
-
"build": "bun run build:cjs && bun run build:esm && bun run build:types && bun run copy-assets",
|
|
89
|
+
"build": "bun run --filter @oxy.so/telemetry build && bun run build:cjs && bun run build:esm && bun run build:types && bun run copy-assets && node scripts/mark-module-formats.mjs",
|
|
90
90
|
"copy-assets": "cp -r src/i18n/locales dist/cjs/i18n/locales && cp -r src/i18n/locales dist/esm/i18n/locales",
|
|
91
91
|
"build:cjs": "tsc -p tsconfig.cjs.json",
|
|
92
92
|
"build:esm": "tsc -p tsconfig.esm.json && node scripts/fix-esm-imports.mjs",
|
|
@@ -94,8 +94,9 @@
|
|
|
94
94
|
"clean": "rm -rf dist",
|
|
95
95
|
"typescript": "tsc --noEmit",
|
|
96
96
|
"test": "jest --passWithNoTests",
|
|
97
|
+
"test:package": "node scripts/verify-package-formats.mjs",
|
|
97
98
|
"lint": "biome lint --error-on-warnings ./src",
|
|
98
|
-
"prepublishOnly": "node ../../scripts/assert-bun-publish.mjs && bun run clean && bun run build",
|
|
99
|
+
"prepublishOnly": "node ../../scripts/assert-bun-publish.mjs && bun run clean && bun run build && bun run test:package",
|
|
99
100
|
"release": "rm -rf dist && bun run build && release-it",
|
|
100
101
|
"generate:display-name-policy": "node scripts/generateDisplayNamePolicyRanges.mjs"
|
|
101
102
|
},
|
|
@@ -114,11 +115,11 @@
|
|
|
114
115
|
}
|
|
115
116
|
},
|
|
116
117
|
"dependencies": {
|
|
117
|
-
"@oxy.so/telemetry": "^1.
|
|
118
|
+
"@oxy.so/telemetry": "^1.1.1",
|
|
118
119
|
"@noble/ciphers": "^1.3.0",
|
|
119
120
|
"@noble/hashes": "^1.8.0",
|
|
120
|
-
"@oxy.so/contracts": "^1.
|
|
121
|
-
"@oxy.so/protocol": "^1.0.
|
|
121
|
+
"@oxy.so/contracts": "^1.1.1",
|
|
122
|
+
"@oxy.so/protocol": "^1.0.1",
|
|
122
123
|
"@scure/bip39": "^1.6.0",
|
|
123
124
|
"buffer": "^6.0.3",
|
|
124
125
|
"express-rate-limit": "^8.6.0",
|
|
@@ -109,6 +109,42 @@ export class ServiceAssetMetadataError extends Error {
|
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
/**
|
|
113
|
+
* A chunk of `POST /assets/service/linked-url` failed, so the SDK cannot say
|
|
114
|
+
* whether those ids have URLs.
|
|
115
|
+
*
|
|
116
|
+
* Its own class rather than a reuse of {@link ServiceAssetMetadataError}, and
|
|
117
|
+
* deliberately WITHOUT that one's `{ partial: true }` escape hatch, because the
|
|
118
|
+
* two mistakes cost different things. Reading a failed metadata lookup as
|
|
119
|
+
* "absent" embedded a media item with no hash. Reading a failed DOWNLOAD mint as
|
|
120
|
+
* "absent" tells a buyer who paid that the file they own is not there — and
|
|
121
|
+
* "not there" is already this route's answer for "not yours", so a best-effort
|
|
122
|
+
* mode would make a throttled request indistinguishable from a refusal. There is
|
|
123
|
+
* no download path that legitimately wants that, so there is no option to ask
|
|
124
|
+
* for it.
|
|
125
|
+
*/
|
|
126
|
+
export class ServiceLinkedDownloadUrlError extends Error {
|
|
127
|
+
public readonly code = 'SERVICE_LINKED_DOWNLOAD_URL_UNRESOLVED';
|
|
128
|
+
/** Every id belonging to a chunk whose request failed. */
|
|
129
|
+
public readonly unresolvedIds: string[];
|
|
130
|
+
/** HTTP statuses observed across the failed chunks (deduped, ascending). */
|
|
131
|
+
public readonly statuses: number[];
|
|
132
|
+
/** The first underlying transport/API failure — see the sibling class. */
|
|
133
|
+
public readonly cause?: unknown;
|
|
134
|
+
|
|
135
|
+
constructor(unresolvedIds: string[], statuses: number[], cause?: unknown) {
|
|
136
|
+
const uniqueStatuses = Array.from(new Set(statuses)).sort((a, b) => a - b);
|
|
137
|
+
const statusSuffix = uniqueStatuses.length > 0 ? ` — status ${uniqueStatuses.join(', ')}` : '';
|
|
138
|
+
super(
|
|
139
|
+
`Could not mint download URLs for ${unresolvedIds.length} id(s)${statusSuffix}. Treat this as unknown, never as "the caller holds no right".`,
|
|
140
|
+
);
|
|
141
|
+
this.name = 'ServiceLinkedDownloadUrlError';
|
|
142
|
+
this.unresolvedIds = unresolvedIds;
|
|
143
|
+
this.statuses = uniqueStatuses;
|
|
144
|
+
this.cause = cause;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
112
148
|
export class OxyAuthenticationTimeoutError extends OxyAuthenticationError {
|
|
113
149
|
constructor(operationName: string, timeoutMs: number) {
|
|
114
150
|
super(
|
package/src/crypto/keyManager.ts
CHANGED
|
@@ -146,7 +146,7 @@ export type IdentityRecoveryResult =
|
|
|
146
146
|
/**
|
|
147
147
|
* HKDF salt that domain-separates every identity-scoped seed produced by
|
|
148
148
|
* {@link KeyManager.deriveScopedSeed}. Versioned so a future scheme change is a
|
|
149
|
-
* new, non-colliding tag. The per-app domain (e.g.
|
|
149
|
+
* new, non-colliding tag. The per-app domain (e.g. Peable's FairCoin wallet)
|
|
150
150
|
* is carried by the caller's `info` string, not this salt.
|
|
151
151
|
*/
|
|
152
152
|
const SCOPED_SEED_KDF_SALT = 'oxy-identity-scoped-seed-v1';
|
|
@@ -2567,12 +2567,14 @@ export class KeyManager {
|
|
|
2567
2567
|
*
|
|
2568
2568
|
* The domain separation is carried by `info` (e.g. `"oxypay/faircoin/v1"`),
|
|
2569
2569
|
* so distinct apps/purposes get independent seeds from the same identity.
|
|
2570
|
+
* That legacy Peable tag is a cryptographic contract and must not be renamed:
|
|
2571
|
+
* changing it would derive a different wallet for every existing user.
|
|
2570
2572
|
* The output is HKDF keying material, never the private key itself — a
|
|
2571
|
-
* consumer (e.g.
|
|
2573
|
+
* consumer (e.g. Peable's FairCoin HD wallet) can feed it straight into
|
|
2572
2574
|
* `HDKey.fromMasterSeed` and never touches the identity key.
|
|
2573
2575
|
*
|
|
2574
2576
|
* Key source (native only): prefers the shared ecosystem identity written to
|
|
2575
|
-
* `group.so.oxy.shared` (what a Relying Party like
|
|
2577
|
+
* `group.so.oxy.shared` (what a Relying Party like Peable reads), then falls
|
|
2576
2578
|
* back to this device's primary identity (Commons/Accounts). Both reproduce
|
|
2577
2579
|
* from the user's Oxy recovery phrase, so the derived seed is recoverable.
|
|
2578
2580
|
*
|
|
@@ -2604,4 +2606,3 @@ export class KeyManager {
|
|
|
2604
2606
|
}
|
|
2605
2607
|
|
|
2606
2608
|
export default KeyManager;
|
|
2607
|
-
|
|
@@ -1412,7 +1412,7 @@
|
|
|
1412
1412
|
},
|
|
1413
1413
|
"details": {
|
|
1414
1414
|
"cardDetails": "Card Details",
|
|
1415
|
-
"
|
|
1415
|
+
"peable": "Peable",
|
|
1416
1416
|
"faircoinPayment": "FairCoin Payment",
|
|
1417
1417
|
"paymentDetails": "Payment Details",
|
|
1418
1418
|
"creditCard": "Credit Card",
|
|
@@ -1438,7 +1438,7 @@
|
|
|
1438
1438
|
"amount": "Amount",
|
|
1439
1439
|
"paymentMethod": "Payment Method",
|
|
1440
1440
|
"card": "Card",
|
|
1441
|
-
"
|
|
1441
|
+
"peableAccount": "Peable Account",
|
|
1442
1442
|
"faircoinWallet": "FairCoin Wallet",
|
|
1443
1443
|
"paidViaQR": "Paid via QR",
|
|
1444
1444
|
"processing": "Processing...",
|
|
@@ -1465,8 +1465,8 @@
|
|
|
1465
1465
|
"description": "Pay securely with your credit or debit card."
|
|
1466
1466
|
},
|
|
1467
1467
|
"oxy": {
|
|
1468
|
-
"label": "
|
|
1469
|
-
"description": "Use your
|
|
1468
|
+
"label": "Peable",
|
|
1469
|
+
"description": "Use your Peable in-app balance."
|
|
1470
1470
|
},
|
|
1471
1471
|
"faircoin": {
|
|
1472
1472
|
"label": "FAIRWallet",
|
|
@@ -2127,6 +2127,18 @@
|
|
|
2127
2127
|
"title": "Permissions requested",
|
|
2128
2128
|
"basic": "Sign you in and read your basic profile"
|
|
2129
2129
|
},
|
|
2130
|
+
"resource": {
|
|
2131
|
+
"title": "Oxy app and protected resource"
|
|
2132
|
+
},
|
|
2133
|
+
"writeActions": {
|
|
2134
|
+
"title": "Actions this connection can perform"
|
|
2135
|
+
},
|
|
2136
|
+
"effects": {
|
|
2137
|
+
"write": "Write",
|
|
2138
|
+
"external": "External",
|
|
2139
|
+
"financial": "Financial",
|
|
2140
|
+
"security": "Security"
|
|
2141
|
+
},
|
|
2130
2142
|
"scopes": {
|
|
2131
2143
|
"openid": "Confirm your identity",
|
|
2132
2144
|
"profile": "Read your basic profile",
|
|
@@ -2147,7 +2159,8 @@
|
|
|
2147
2159
|
"federationWrite": "Act across federated services"
|
|
2148
2160
|
},
|
|
2149
2161
|
"account": {
|
|
2150
|
-
"title": "Signing in as"
|
|
2162
|
+
"title": "Signing in as",
|
|
2163
|
+
"id": "Account ID: {{id}}"
|
|
2151
2164
|
},
|
|
2152
2165
|
"links": {
|
|
2153
2166
|
"website": "Website",
|