@oxy.so/core 1.0.1 → 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.
Files changed (68) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/OxyServices.errors.js +28 -1
  3. package/dist/cjs/i18n/locales/en-US.json +14 -1
  4. package/dist/cjs/i18n/locales/es-ES.json +14 -1
  5. package/dist/cjs/i18n/locales/locales/en-US.json +14 -1
  6. package/dist/cjs/i18n/locales/locales/es-ES.json +14 -1
  7. package/dist/cjs/mixins/OxyServices.agency.js +113 -0
  8. package/dist/cjs/mixins/OxyServices.assets.js +90 -0
  9. package/dist/cjs/mixins/OxyServices.connectedApps.js +20 -3
  10. package/dist/cjs/mixins/OxyServices.utility.js +1 -21
  11. package/dist/cjs/mixins/index.js +3 -4
  12. package/dist/cjs/server/index.js +6 -1
  13. package/dist/cjs/server/traffic.js +107 -0
  14. package/dist/cjs/server/trafficNodeHttp.js +86 -0
  15. package/dist/cjs/utils/textNormalization.js +1 -1
  16. package/dist/esm/.tsbuildinfo +1 -1
  17. package/dist/esm/OxyServices.errors.js +26 -0
  18. package/dist/esm/i18n/locales/en-US.json +14 -1
  19. package/dist/esm/i18n/locales/es-ES.json +14 -1
  20. package/dist/esm/i18n/locales/locales/en-US.json +14 -1
  21. package/dist/esm/i18n/locales/locales/es-ES.json +14 -1
  22. package/dist/esm/mixins/OxyServices.agency.js +110 -0
  23. package/dist/esm/mixins/OxyServices.assets.js +91 -1
  24. package/dist/esm/mixins/OxyServices.connectedApps.js +20 -3
  25. package/dist/esm/mixins/OxyServices.utility.js +1 -21
  26. package/dist/esm/mixins/index.js +3 -4
  27. package/dist/esm/server/index.js +2 -0
  28. package/dist/esm/server/traffic.js +104 -0
  29. package/dist/esm/server/trafficNodeHttp.js +79 -0
  30. package/dist/esm/utils/textNormalization.js +1 -1
  31. package/dist/types/.tsbuildinfo +1 -1
  32. package/dist/types/OxyServices.errors.d.ts +24 -0
  33. package/dist/types/index.d.ts +2 -1
  34. package/dist/types/mixins/OxyServices.agency.d.ts +135 -0
  35. package/dist/types/mixins/OxyServices.assets.d.ts +43 -1
  36. package/dist/types/mixins/OxyServices.connectedApps.d.ts +15 -0
  37. package/dist/types/mixins/OxyServices.utility.d.ts +0 -9
  38. package/dist/types/mixins/index.d.ts +2 -2
  39. package/dist/types/models/interfaces.d.ts +26 -0
  40. package/dist/types/server/index.d.ts +3 -0
  41. package/dist/types/server/traffic.d.ts +27 -0
  42. package/dist/types/server/trafficNodeHttp.d.ts +6 -0
  43. package/dist/types/utils/textNormalization.d.ts +1 -1
  44. package/package.json +4 -4
  45. package/src/OxyServices.errors.ts +36 -0
  46. package/src/i18n/locales/en-US.json +14 -1
  47. package/src/i18n/locales/es-ES.json +14 -1
  48. package/src/index.ts +15 -0
  49. package/src/mixins/OxyServices.agency.ts +277 -0
  50. package/src/mixins/OxyServices.assets.ts +105 -2
  51. package/src/mixins/OxyServices.connectedApps.ts +42 -4
  52. package/src/mixins/OxyServices.utility.ts +1 -26
  53. package/src/mixins/__tests__/OxyServices.serviceLinkedDownloadUrl.test.ts +139 -0
  54. package/src/mixins/__tests__/agency.test.ts +120 -0
  55. package/src/mixins/__tests__/connectedApps.test.ts +23 -0
  56. package/src/mixins/index.ts +4 -5
  57. package/src/models/interfaces.ts +27 -0
  58. package/src/server/__tests__/traffic.test.ts +49 -0
  59. package/src/server/__tests__/trafficNodeHttp.test.ts +38 -0
  60. package/src/server/index.ts +5 -0
  61. package/src/server/traffic.ts +116 -0
  62. package/src/server/trafficNodeHttp.ts +69 -0
  63. package/src/utils/textNormalization.ts +1 -1
  64. package/dist/cjs/mixins/OxyServices.links.js +0 -72
  65. package/dist/esm/mixins/OxyServices.links.js +0 -69
  66. package/dist/types/mixins/OxyServices.links.d.ts +0 -104
  67. package/src/mixins/OxyServices.links.ts +0 -107
  68. 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
  }
@@ -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 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 OxyServicesLinksMixin<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>>>;
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: page/link-preview titles, `siteName`,
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.0.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 && node scripts/mark-module-formats.mjs",
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",
@@ -115,10 +115,10 @@
115
115
  }
116
116
  },
117
117
  "dependencies": {
118
- "@oxy.so/telemetry": "^1.0.0",
118
+ "@oxy.so/telemetry": "^1.1.1",
119
119
  "@noble/ciphers": "^1.3.0",
120
120
  "@noble/hashes": "^1.8.0",
121
- "@oxy.so/contracts": "^1.0.1",
121
+ "@oxy.so/contracts": "^1.1.1",
122
122
  "@oxy.so/protocol": "^1.0.1",
123
123
  "@scure/bip39": "^1.6.0",
124
124
  "buffer": "^6.0.3",
@@ -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(
@@ -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",
@@ -2127,6 +2127,18 @@
2127
2127
  "title": "Permisos solicitados",
2128
2128
  "basic": "Iniciar sesión y leer tu perfil básico"
2129
2129
  },
2130
+ "resource": {
2131
+ "title": "App de Oxy y recurso protegido"
2132
+ },
2133
+ "writeActions": {
2134
+ "title": "Acciones que puede realizar esta conexión"
2135
+ },
2136
+ "effects": {
2137
+ "write": "Escritura",
2138
+ "external": "Externa",
2139
+ "financial": "Financiera",
2140
+ "security": "Seguridad"
2141
+ },
2130
2142
  "scopes": {
2131
2143
  "openid": "Confirmar tu identidad",
2132
2144
  "profile": "Leer tu perfil básico",
@@ -2147,7 +2159,8 @@
2147
2159
  "federationWrite": "Actuar en servicios federados"
2148
2160
  },
2149
2161
  "account": {
2150
- "title": "Iniciando sesión como"
2162
+ "title": "Iniciando sesión como",
2163
+ "id": "ID de cuenta: {{id}}"
2151
2164
  },
2152
2165
  "links": {
2153
2166
  "website": "Sitio web",
package/src/index.ts CHANGED
@@ -122,8 +122,23 @@ export type { ProfileLink, ProfileLinkMetadata } from './utils/profileLinks';
122
122
  export type {
123
123
  PublicApplication,
124
124
  ConnectedApp,
125
+ ConnectedMcpClient,
125
126
  } from './mixins/OxyServices.connectedApps';
126
127
 
128
+ // ---------------------------------------------------------------------------
129
+ // Native Alia and digital-agent authority
130
+ // ---------------------------------------------------------------------------
131
+ export type {
132
+ AccountCapabilityPolicy,
133
+ AvailableCapabilityCatalog,
134
+ CapabilityExecutionAuthorization,
135
+ CreateDelegationGrantInput,
136
+ DelegationCatalogBinding,
137
+ DelegationGrantView,
138
+ PutAccountCapabilityPolicyInput,
139
+ UpdateDelegationGrantInput,
140
+ } from './mixins/OxyServices.agency';
141
+
127
142
  // ---------------------------------------------------------------------------
128
143
  // App store (public storefront + reviews + the listing a publisher edits)
129
144
  // ---------------------------------------------------------------------------