@oxyhq/core 4.0.1 → 5.0.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.
Files changed (109) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/HttpService.js +6 -18
  3. package/dist/cjs/OxyServices.base.js +0 -21
  4. package/dist/cjs/crypto/keyManager.js +7 -7
  5. package/dist/cjs/crypto/polyfill.js +6 -5
  6. package/dist/cjs/crypto/signatureService.js +44 -220
  7. package/dist/cjs/index.js +4 -8
  8. package/dist/cjs/mixins/OxyServices.accounts.js +54 -0
  9. package/dist/cjs/mixins/OxyServices.assets.js +2 -2
  10. package/dist/cjs/mixins/OxyServices.auth.js +3 -3
  11. package/dist/cjs/mixins/OxyServices.civic.js +3 -3
  12. package/dist/cjs/mixins/OxyServices.language.js +2 -2
  13. package/dist/cjs/mixins/OxyServices.utility.js +7 -95
  14. package/dist/cjs/utils/cacheKey.js +17 -19
  15. package/dist/cjs/utils/deviceManager.js +2 -2
  16. package/dist/cjs/utils/platform.js +0 -14
  17. package/dist/esm/.tsbuildinfo +1 -1
  18. package/dist/esm/HttpService.js +6 -18
  19. package/dist/esm/OxyServices.base.js +0 -21
  20. package/dist/esm/crypto/keyManager.js +4 -4
  21. package/dist/esm/crypto/polyfill.js +5 -4
  22. package/dist/esm/crypto/signatureService.js +39 -214
  23. package/dist/esm/index.js +1 -2
  24. package/dist/esm/mixins/OxyServices.accounts.js +54 -0
  25. package/dist/esm/mixins/OxyServices.assets.js +1 -1
  26. package/dist/esm/mixins/OxyServices.auth.js +1 -1
  27. package/dist/esm/mixins/OxyServices.civic.js +3 -3
  28. package/dist/esm/mixins/OxyServices.language.js +1 -1
  29. package/dist/esm/mixins/OxyServices.utility.js +6 -94
  30. package/dist/esm/utils/cacheKey.js +17 -19
  31. package/dist/esm/utils/deviceManager.js +1 -1
  32. package/dist/esm/utils/platform.js +0 -12
  33. package/dist/types/.tsbuildinfo +1 -1
  34. package/dist/types/HttpService.d.ts +3 -6
  35. package/dist/types/OxyServices.base.d.ts +0 -17
  36. package/dist/types/crypto/polyfill.d.ts +2 -2
  37. package/dist/types/crypto/signatureService.d.ts +18 -84
  38. package/dist/types/index.d.ts +3 -4
  39. package/dist/types/mixins/OxyServices.accounts.d.ts +57 -5
  40. package/dist/types/mixins/OxyServices.analytics.d.ts +0 -2
  41. package/dist/types/mixins/OxyServices.appData.d.ts +0 -2
  42. package/dist/types/mixins/OxyServices.assets.d.ts +0 -2
  43. package/dist/types/mixins/OxyServices.auth.d.ts +0 -2
  44. package/dist/types/mixins/OxyServices.civic.d.ts +3 -5
  45. package/dist/types/mixins/OxyServices.connectedApps.d.ts +0 -2
  46. package/dist/types/mixins/OxyServices.contacts.d.ts +0 -2
  47. package/dist/types/mixins/OxyServices.devices.d.ts +0 -2
  48. package/dist/types/mixins/OxyServices.features.d.ts +0 -2
  49. package/dist/types/mixins/OxyServices.fedcm.d.ts +0 -2
  50. package/dist/types/mixins/OxyServices.identity.d.ts +8 -5
  51. package/dist/types/mixins/OxyServices.language.d.ts +0 -2
  52. package/dist/types/mixins/OxyServices.links.d.ts +0 -2
  53. package/dist/types/mixins/OxyServices.location.d.ts +0 -2
  54. package/dist/types/mixins/OxyServices.nodes.d.ts +0 -44
  55. package/dist/types/mixins/OxyServices.payment.d.ts +0 -2
  56. package/dist/types/mixins/OxyServices.privacy.d.ts +0 -2
  57. package/dist/types/mixins/OxyServices.redirect.d.ts +0 -2
  58. package/dist/types/mixins/OxyServices.reputation.d.ts +0 -2
  59. package/dist/types/mixins/OxyServices.security.d.ts +0 -2
  60. package/dist/types/mixins/OxyServices.silent.d.ts +0 -2
  61. package/dist/types/mixins/OxyServices.sso.d.ts +0 -2
  62. package/dist/types/mixins/OxyServices.topics.d.ts +0 -2
  63. package/dist/types/mixins/OxyServices.user.d.ts +0 -2
  64. package/dist/types/mixins/OxyServices.utility.d.ts +0 -32
  65. package/dist/types/server/auth.d.ts +0 -6
  66. package/dist/types/server/index.d.ts +1 -1
  67. package/dist/types/utils/cacheKey.d.ts +6 -7
  68. package/dist/types/utils/platform.d.ts +0 -8
  69. package/package.json +4 -7
  70. package/src/HttpService.ts +6 -22
  71. package/src/OxyServices.base.ts +0 -23
  72. package/src/__tests__/httpServiceCache.test.ts +0 -19
  73. package/src/crypto/__tests__/keyManager.atomicity.test.ts +2 -1
  74. package/src/crypto/__tests__/keyManager.test.ts +9 -7
  75. package/src/crypto/__tests__/signChallengeShared.test.ts +2 -1
  76. package/src/crypto/__tests__/signedRecord.test.ts +37 -150
  77. package/src/crypto/keyManager.ts +28 -17
  78. package/src/crypto/polyfill.ts +5 -4
  79. package/src/crypto/signatureService.ts +67 -255
  80. package/src/index.ts +3 -3
  81. package/src/mixins/OxyServices.accounts.ts +91 -3
  82. package/src/mixins/OxyServices.assets.ts +1 -1
  83. package/src/mixins/OxyServices.auth.ts +1 -1
  84. package/src/mixins/OxyServices.civic.ts +6 -17
  85. package/src/mixins/OxyServices.identity.ts +8 -2
  86. package/src/mixins/OxyServices.language.ts +1 -1
  87. package/src/mixins/OxyServices.nodes.ts +1 -12
  88. package/src/mixins/OxyServices.utility.ts +6 -119
  89. package/src/mixins/__tests__/OxyServices.civic.test.ts +2 -2
  90. package/src/mixins/__tests__/accounts.test.ts +70 -0
  91. package/src/server/auth.ts +0 -7
  92. package/src/server/index.ts +0 -1
  93. package/src/utils/__tests__/cacheKey.test.ts +0 -0
  94. package/src/utils/cacheKey.ts +16 -21
  95. package/src/utils/deviceManager.ts +1 -1
  96. package/src/utils/platform.ts +0 -14
  97. package/dist/cjs/crypto/canonicalJson.js +0 -107
  98. package/dist/cjs/utils/platformCrypto.js +0 -165
  99. package/dist/cjs/utils/platformCrypto.native.js +0 -123
  100. package/dist/esm/crypto/canonicalJson.js +0 -104
  101. package/dist/esm/utils/platformCrypto.js +0 -125
  102. package/dist/esm/utils/platformCrypto.native.js +0 -80
  103. package/dist/types/crypto/canonicalJson.d.ts +0 -44
  104. package/dist/types/utils/platformCrypto.d.ts +0 -87
  105. package/dist/types/utils/platformCrypto.native.d.ts +0 -54
  106. package/src/crypto/__tests__/canonicalJson.test.ts +0 -116
  107. package/src/crypto/canonicalJson.ts +0 -120
  108. package/src/utils/platformCrypto.native.ts +0 -101
  109. package/src/utils/platformCrypto.ts +0 -145
@@ -79,7 +79,6 @@ export declare class HttpService {
79
79
  * Each listener receives the resulting access token, or `null` when cleared.
80
80
  */
81
81
  private _tokenChangeListeners;
82
- private _actingAsUserId;
83
82
  private requestMetrics;
84
83
  constructor(config: OxyConfig);
85
84
  private syncAccessTokenFromProvider;
@@ -153,9 +152,9 @@ export declare class HttpService {
153
152
  * Derive a stable, non-sensitive identity discriminator for cache scoping.
154
153
  *
155
154
  * Thin instance wrapper over the pure {@link computeIdentityTag} helper —
156
- * binds it to this instance's live access token and acting-as id. See that
157
- * function's docs for the full resolution contract (anon fallback, decoded
158
- * `userId || id`, token-hash fallback for undecodable tokens).
155
+ * binds it to this instance's live access token. See that function's docs for
156
+ * the full resolution contract (anon fallback, decoded `userId || id`,
157
+ * token-hash fallback for undecodable tokens).
159
158
  */
160
159
  private computeIdentityTag;
161
160
  /**
@@ -209,8 +208,6 @@ export declare class HttpService {
209
208
  put<T = unknown>(url: string, data?: unknown, config?: Omit<RequestConfig, 'method' | 'url' | 'data'>): Promise<T>;
210
209
  patch<T = unknown>(url: string, data?: unknown, config?: Omit<RequestConfig, 'method' | 'url' | 'data'>): Promise<T>;
211
210
  delete<T = unknown>(url: string, config?: Omit<RequestConfig, 'method' | 'url'>): Promise<T>;
212
- setActingAs(userId: string | null): void;
213
- getActingAs(): string | null;
214
211
  setTokens(accessToken: string): void;
215
212
  setAuthRefreshHandler(handler: AuthRefreshHandler | null): void;
216
213
  setAccessTokenProvider(provider: AccessTokenProvider | null): void;
@@ -153,23 +153,6 @@ export declare class OxyServicesBase {
153
153
  * the per-request preflight refresh; this powers the idle/background timer.
154
154
  */
155
155
  getAccessTokenExpiry(): number | null;
156
- /**
157
- * Set the acting-as identity for managed accounts.
158
- *
159
- * When set, all subsequent API requests will include the `X-Acting-As` header,
160
- * causing the server to attribute actions to the managed account. The
161
- * authenticated user must be an authorized manager of the target account.
162
- *
163
- * Pass `null` to clear and revert to the authenticated user's own identity.
164
- *
165
- * @param userId - The managed account user ID, or null to clear
166
- */
167
- setActingAs(userId: string | null): void;
168
- /**
169
- * Get the current acting-as identity (managed account user ID), or null
170
- * if operating as the authenticated user's own identity.
171
- */
172
- getActingAs(): string | null;
173
156
  /**
174
157
  * Wait for authentication to be ready
175
158
  *
@@ -6,8 +6,8 @@
6
6
  *
7
7
  * - Browser/Node.js: Uses native crypto
8
8
  * - React Native: Uses expo-crypto (statically imported via the
9
- * per-platform `platformCrypto` module — see that file's doc-comment for
10
- * how platform routing works).
9
+ * per-platform `platform/crypto` module in `@oxyhq/protocol` — see that
10
+ * file's doc-comment for how platform routing works).
11
11
  */
12
12
  import { Buffer } from 'buffer';
13
13
  export { Buffer };
@@ -1,51 +1,13 @@
1
1
  /**
2
- * Signature Service - ECDSA Digital Signatures
2
+ * Signature Service - ECDSA Digital Signatures (device-key bound)
3
3
  *
4
- * Handles signing and verification of messages using ECDSA secp256k1.
5
- * Used for authenticating requests and proving identity ownership.
4
+ * Handles signing and verification of messages with the user's DEVICE identity
5
+ * key (read from {@link KeyManager} / secure storage). All cryptography itself —
6
+ * canonical signing input, SHA-256, secp256k1 sign/verify, envelope assembly —
7
+ * is delegated to `@oxyhq/protocol`; this service only resolves the key from
8
+ * storage and orchestrates the protocol primitives.
6
9
  */
7
10
  import type { SignedRecordEnvelope } from '@oxyhq/contracts';
8
- /**
9
- * The signing-input portion of a {@link SignedRecordEnvelope}: every field
10
- * EXCEPT the `publicKey` and `signature`. Both the client (when signing) and
11
- * the server (when verifying) canonicalize exactly these fields, so they agree
12
- * on the bytes that the signature covers.
13
- *
14
- * The v2 chain fields (`seq`/`prev`/`collection`/`rkey`) are optional: a v1
15
- * envelope omits them and is signed over only the base fields; a v2 envelope
16
- * carries them and includes them in the signed bytes.
17
- */
18
- export type SignedRecordSigningFields = Pick<SignedRecordEnvelope, 'version' | 'type' | 'subject' | 'issuer' | 'record' | 'issuedAt'> & Partial<Pick<SignedRecordEnvelope, 'seq' | 'prev' | 'collection' | 'rkey'>>;
19
- /**
20
- * Compute the canonical signing input for a signed-record envelope.
21
- *
22
- * This is the single definition of "what the signature covers". `@oxyhq/core`
23
- * (client signing) and `@oxyhq/api` (server verification) both call this, so a
24
- * record signed by a client and verified by the server cannot drift.
25
- *
26
- * - **v1**: the canonical JSON of `{version, type, subject, issuer, record,
27
- * issuedAt}` — BYTE-IDENTICAL to the original scheme, so every signature
28
- * already in production keeps verifying.
29
- * - **v2**: the canonical JSON additionally includes the hash-chain fields
30
- * `{seq, prev, collection, rkey}`. Because {@link canonicalize} sorts keys,
31
- * the on-the-wire field order is irrelevant; the resulting canonical key
32
- * order is `collection, issuedAt, issuer, prev, record, rkey, seq, subject,
33
- * type, version`. `prev` is `null` at genesis (serialized as `null`, not
34
- * omitted), so it is always part of the signed bytes.
35
- */
36
- export declare function signedRecordSigningInput(fields: SignedRecordSigningFields): string;
37
- /**
38
- * Compute the `recordId` (content address) of a signed record: the SHA-256 hex
39
- * digest of its canonical {@link signedRecordSigningInput}.
40
- *
41
- * Deterministic and stable across runtimes (it reuses the same canonicalization
42
- * + SHA-256 the signature itself is built on). The recordId is what `prev`
43
- * references in the per-subject hash chain, so `@oxyhq/core` (client) and
44
- * `@oxyhq/api` (server) MUST compute it identically — both call this function.
45
- * It is taken over the SIGNING input (excluding `publicKey`/`signature`), so it
46
- * is a pure content address of the record's meaning, independent of who signed.
47
- */
48
- export declare function computeRecordId(fields: SignedRecordSigningFields): Promise<string>;
49
11
  export interface SignedMessage {
50
12
  message: string;
51
13
  signature: string;
@@ -68,29 +30,10 @@ export declare class SignatureService {
68
30
  */
69
31
  static hashMessage(message: string): Promise<string>;
70
32
  /**
71
- * Sign a message using the stored private key
33
+ * Sign a message using the stored device private key
72
34
  * Returns the signature in DER format (hex encoded)
73
35
  */
74
36
  static sign(message: string): Promise<string>;
75
- /**
76
- * Sign a message with an explicit private key (without storing)
77
- * Useful for one-time operations or testing
78
- */
79
- static signWithKey(message: string, privateKey: string): Promise<string>;
80
- /**
81
- * Verify a signature against a message and public key
82
- *
83
- * Returns false on any error (invalid signature, malformed input, etc.).
84
- * Errors are logged at debug level so they're available when troubleshooting
85
- * signature mismatches but don't surface to the caller.
86
- */
87
- static verify(message: string, signature: string, publicKey: string): Promise<boolean>;
88
- /**
89
- * Synchronous verification (for Node.js backend)
90
- * Uses crypto module directly for hashing
91
- * Note: This method should only be used in Node.js environments
92
- */
93
- static verifySync(message: string, signature: string, publicKey: string): boolean;
94
37
  /**
95
38
  * Create a signed message object with metadata
96
39
  */
@@ -113,9 +56,10 @@ export declare class SignatureService {
113
56
  * Mirrors {@link signChallenge} exactly — same message format
114
57
  * (`auth:${publicKey}:${challenge}:${timestamp}`) so the server verification
115
58
  * path is unchanged — but sources the shared public/private key from
116
- * `KeyManager` and signs with `signWithKey`. Used by "Sign in with Oxy"
117
- * same-device shared-keychain SSO (Mechanism A): a sibling native app proves
118
- * control of the shared identity to mint its own session.
59
+ * `KeyManager` and signs with the protocol's explicit-key {@link signMessage}.
60
+ * Used by "Sign in with Oxy" same-device shared-keychain SSO (Mechanism A): a
61
+ * sibling native app proves control of the shared identity to mint its own
62
+ * session.
119
63
  *
120
64
  * Throws if no shared identity exists (native-only; the shared keychain is
121
65
  * unavailable on web).
@@ -149,9 +93,11 @@ export declare class SignatureService {
149
93
  *
150
94
  * The envelope is self-issued: `issuer` equals `subject` (the signer's DID).
151
95
  * The signature covers the canonical JSON of every field EXCEPT `publicKey`
152
- * and `signature` (see {@link signedRecordSigningInput}); `alg` is
153
- * `ES256K-DER-SHA256` (secp256k1 over the SHA-256 of the canonical bytes,
154
- * DER-encoded), the same scheme this service uses everywhere else.
96
+ * and `signature`; `alg` is `ES256K-DER-SHA256` (secp256k1 over the SHA-256 of
97
+ * the canonical bytes, DER-encoded). The cryptography is delegated to the
98
+ * protocol's {@link signEnvelope}, which derives the (uncompressed-hex)
99
+ * `publicKey` from the stored device key — identical to the registered
100
+ * verification method.
155
101
  *
156
102
  * Requires a stored identity (native secure storage); throws if none exists.
157
103
  *
@@ -165,8 +111,8 @@ export declare class SignatureService {
165
111
  * fields.
166
112
  *
167
113
  * Identical to {@link signRecord} (self-issued: `issuer === subject`; same
168
- * `ES256K-DER-SHA256` scheme over {@link signedRecordSigningInput}) but
169
- * `version` is `2` and the signed bytes additionally cover the chain fields:
114
+ * `ES256K-DER-SHA256` scheme) but `version` is `2` and the signed bytes
115
+ * additionally cover the chain fields:
170
116
  *
171
117
  * @param type - The record category.
172
118
  * @param subject - The subject DID the record is about (also the issuer).
@@ -186,17 +132,5 @@ export declare class SignatureService {
186
132
  collection: string;
187
133
  rkey: string;
188
134
  }): Promise<SignedRecordEnvelope>;
189
- /**
190
- * Verify a signed-record envelope: recompute the canonical signing input from
191
- * the envelope's own fields and check the signature against the envelope's
192
- * `publicKey`.
193
- *
194
- * Note: this confirms the signature is internally consistent with the
195
- * embedded `publicKey`. It does NOT establish that `publicKey` is an
196
- * authorized verification method for `subject` — that authorization check is
197
- * the server's responsibility (it asserts the key is a current verification
198
- * method on the subject's DID).
199
- */
200
- static verifyRecord(envelope: SignedRecordEnvelope): Promise<boolean>;
201
135
  }
202
136
  export default SignatureService;
@@ -42,7 +42,7 @@ export type { CanonicalUserHandleInput, UserHandleInput } from './utils/userHand
42
42
  export { normalizeProfileLinks } from './utils/profileLinks';
43
43
  export type { ProfileLink, ProfileLinkMetadata } from './utils/profileLinks';
44
44
  export type { PublicApplication, ConnectedApp, } from './mixins/OxyServices.connectedApps';
45
- export type { AccountKind, AccountRelationship, AccountRole, AccountMemberStatus, AccountMemberSource, AccountMember, AccountNode, AccountCredentialType, AccountCredentialEnvironment, AccountCredentialStatus, AccountCredential, AccountCredentialWithSecret, RotateAccountCredentialResult, ListAccountsOptions, CreateAccountInput, UpdateAccountInput, InviteAccountMemberInput, UpdateAccountMemberInput, TransferAccountOwnershipInput, CreateAccountCredentialInput, AccountSuccessResult, Application, ApplicationType, ApplicationStatus, ApplicationCredential, ApplicationCredentialType, ApplicationCredentialStatus, ApplicationEnvironment, CreateApplicationInput, UpdateApplicationInput, CreateApplicationCredentialInput, ApplicationCredentialWithSecret, RotateApplicationCredentialResult, ApplicationUsagePeriod, ApplicationUsageSummary, ApplicationUsageByDay, ApplicationUsageByEndpoint, ApplicationUsageStats, } from './mixins/OxyServices.accounts';
45
+ export type { AccountKind, AccountRelationship, AccountRole, AccountMemberStatus, AccountMemberSource, AccountMember, AccountNode, AccountCredentialType, AccountCredentialEnvironment, AccountCredentialStatus, AccountCredential, AccountCredentialWithSecret, RotateAccountCredentialResult, ListAccountsOptions, CreateAccountInput, UpdateAccountInput, InviteAccountMemberInput, UpdateAccountMemberInput, TransferAccountOwnershipInput, CreateAccountCredentialInput, AccountSuccessResult, SwitchAccountResult, Application, ApplicationType, ApplicationStatus, ApplicationCredential, ApplicationCredentialType, ApplicationCredentialStatus, ApplicationEnvironment, CreateApplicationInput, UpdateApplicationInput, CreateApplicationCredentialInput, ApplicationCredentialWithSecret, RotateApplicationCredentialResult, ApplicationUsagePeriod, ApplicationUsageSummary, ApplicationUsageByDay, ApplicationUsageByEndpoint, ApplicationUsageStats, } from './mixins/OxyServices.accounts';
46
46
  export type { ReputationCategory, TrustTier, ReputationTransactionStatus, ReputationTargetEntityType, ReputationDisputeStatus, ReputationInfluenceContext, ReputationTransaction, ReputationBalanceBreakdown, ReputationInfluence, ReputationReliability, ReputationBalance, ReputationDispute, ReputationRule, ReputationLeaderboardEntry, ReputationInfluenceResult, ReverseReputationTransactionResult, AwardReputationInput, CreateReputationDisputeInput, ResolveReputationDisputeInput, UpsertReputationRuleInput, ReverseReputationTransactionInput, } from './mixins/OxyServices.reputation';
47
47
  export { buildUserDid } from './mixins/OxyServices.identity';
48
48
  export type { IdentityRecordType, UnlinkableAuthMethodType, LinkAuthMethodResult, PublishRecordResult, VerifyRecordResult, VerifyDomainResult, RemoveDomainResult, } from './mixins/OxyServices.identity';
@@ -56,9 +56,8 @@ export type { ClientSession, StorageKeys, MinimalUserData, SessionLoginResponse,
56
56
  export type { RefreshAllResponse, RefreshAllAccount, RefreshAllAccountUser, RefreshCookieResponse, } from './models/interfaces';
57
57
  export { KeyManager, IdentityAlreadyExistsError, IdentityPersistError, } from './crypto/keyManager';
58
58
  export type { KeyPair } from './crypto/keyManager';
59
- export { SignatureService, signedRecordSigningInput, computeRecordId } from './crypto/signatureService';
60
- export type { SignedMessage, AuthChallenge, SignedRecordSigningFields } from './crypto/signatureService';
61
- export { canonicalize } from './crypto/canonicalJson';
59
+ export { SignatureService } from './crypto/signatureService';
60
+ export type { SignedMessage, AuthChallenge } from './crypto/signatureService';
62
61
  export { RecoveryPhraseService } from './crypto/recoveryPhrase';
63
62
  export type { RecoveryPhraseResult } from './crypto/recoveryPhrase';
64
63
  export { DeviceManager } from './utils/deviceManager';
@@ -25,11 +25,14 @@
25
25
  * member `_id`, and credentials by their `credentialId`. Never by name, slug, or
26
26
  * handle.
27
27
  *
28
- * NOTE: acting-as (delegated identity) is NOT part of this mixin — `setActingAs`
29
- * / `getActingAs` live on `OxyServices.base` and `verifyActingAs` on the utility
30
- * mixin (it verifies against `GET /accounts/verify-acting-as`).
28
+ * SWITCHING INTO AN ACCOUNT: `switchToAccount(accountId)` mints a REAL session
29
+ * for the target account and plants it as the active session — there is no
30
+ * per-request "acting-as" header. Identity is carried by the session/token, not
31
+ * a delegation header, so a switch propagates through reload and `refresh-all`
32
+ * exactly like a login.
31
33
  */
32
34
  import type { User } from '../models/interfaces';
35
+ import type { SessionLoginResponse } from '../models/session';
33
36
  import type { OxyServicesBase } from '../OxyServices.base';
34
37
  /**
35
38
  * Account classification, orthogonal to the federation `type`
@@ -381,6 +384,28 @@ export interface ApplicationUsageStats {
381
384
  export interface AccountSuccessResult {
382
385
  success: boolean;
383
386
  }
387
+ /**
388
+ * Result of {@link OxyServicesAccountsMixin.switchToAccount} — the freshly
389
+ * minted session for the target account, in the SAME shape the canonical login
390
+ * / `claimSessionByToken` responses use (`SessionLoginResponse`), plus the
391
+ * device-local refresh-cookie slot index.
392
+ *
393
+ * `accessToken` is the first access token for the new session (already planted
394
+ * as the active token by `switchToAccount`). The refresh token is NOT in the
395
+ * body — the server sets it as the httpOnly `oxy_rt_<authuser>` cookie, which
396
+ * joins the device multi-account set so the switched session survives reload and
397
+ * propagates cross-domain via `/auth/refresh-all`. `user` is the target account.
398
+ */
399
+ export interface SwitchAccountResult extends SessionLoginResponse {
400
+ /**
401
+ * The device-local refresh-cookie slot index (`oxy_rt_<authuser>`) the server
402
+ * assigned to the minted session. Surfaced so the consumer can register the
403
+ * new session in its device multi-account set exactly like a login response.
404
+ * Absent only when the server could not set the cookie (best-effort — the
405
+ * switch itself still succeeds).
406
+ */
407
+ authuser?: number;
408
+ }
384
409
  export declare function OxyServicesAccountsMixin<T extends typeof OxyServicesBase>(Base: T): {
385
410
  new (...args: any[]): {
386
411
  /**
@@ -399,6 +424,35 @@ export declare function OxyServicesAccountsMixin<T extends typeof OxyServicesBas
399
424
  * @param accountId - The account's Mongo `_id`.
400
425
  */
401
426
  getAccount(accountId: string): Promise<AccountNode>;
427
+ /**
428
+ * Switch the active session INTO a managed account.
429
+ *
430
+ * Calls `POST /accounts/:id/switch` with the signed-in operator's bearer.
431
+ * The server authorises the operator (must hold `account:act_as` over the
432
+ * target, directly or inherited — else 403; 404 if missing/archived; 403 if
433
+ * the target is a personal account), then mints a REAL session for the
434
+ * target account and returns it in the canonical login / `claimSessionByToken`
435
+ * shape (`{ sessionId, deviceId, expiresAt, accessToken, user, authuser }`).
436
+ *
437
+ * Unlike the removed `X-Acting-As` delegation header, the returned session
438
+ * IS the new identity: this plants `accessToken` as the active token —
439
+ * exactly like `claimSessionByToken` / `verifyChallenge` — so every
440
+ * subsequent request authenticates as the target account. The refresh token
441
+ * is the server-set httpOnly `oxy_rt_<authuser>` cookie (never in the body),
442
+ * so it joins the device multi-account set and survives reload /
443
+ * `refresh-all` with no extra client work.
444
+ *
445
+ * After planting, the SDK's identity-scoped GET cache is fully cleared so
446
+ * every cached read re-fetches as the new account. (The consuming
447
+ * `OxyContext` additionally invalidates its React Query cache and updates
448
+ * session state from the returned `user`; this clears the SDK's own HTTP
449
+ * cache at the source — `setTokens` deliberately preserves the warm cache for
450
+ * same-user silent refreshes, so the sweep here is explicit.)
451
+ *
452
+ * @param accountId - The target account's Mongo `_id`.
453
+ * @returns The minted session (planted) plus the device `authuser` slot.
454
+ */
455
+ switchToAccount(accountId: string): Promise<SwitchAccountResult>;
402
456
  /**
403
457
  * Create a new (non-personal) account. The caller becomes its `owner`.
404
458
  * @param data - Account configuration: kind, optional parent, and profile.
@@ -622,8 +676,6 @@ export declare function OxyServicesAccountsMixin<T extends typeof OxyServicesBas
622
676
  hasValidToken(): boolean;
623
677
  getAccessToken(): string | null;
624
678
  getAccessTokenExpiry(): number | null;
625
- setActingAs(userId: string | null): void;
626
- getActingAs(): string | null;
627
679
  waitForAuth(timeoutMs?: number): Promise<boolean>;
628
680
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
629
681
  maxRetries?: number;
@@ -55,8 +55,6 @@ export declare function OxyServicesAnalyticsMixin<T extends typeof OxyServicesBa
55
55
  hasValidToken(): boolean;
56
56
  getAccessToken(): string | null;
57
57
  getAccessTokenExpiry(): number | null;
58
- setActingAs(userId: string | null): void;
59
- getActingAs(): string | null;
60
58
  waitForAuth(timeoutMs?: number): Promise<boolean>;
61
59
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
62
60
  maxRetries?: number;
@@ -91,8 +91,6 @@ export declare function OxyServicesAppDataMixin<T extends typeof OxyServicesBase
91
91
  hasValidToken(): boolean;
92
92
  getAccessToken(): string | null;
93
93
  getAccessTokenExpiry(): number | null;
94
- setActingAs(userId: string | null): void;
95
- getActingAs(): string | null;
96
94
  waitForAuth(timeoutMs?: number): Promise<boolean>;
97
95
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
98
96
  maxRetries?: number;
@@ -135,8 +135,6 @@ export declare function OxyServicesAssetsMixin<T extends typeof OxyServicesBase>
135
135
  hasValidToken(): boolean;
136
136
  getAccessToken(): string | null;
137
137
  getAccessTokenExpiry(): number | null;
138
- setActingAs(userId: string | null): void;
139
- getActingAs(): string | null;
140
138
  waitForAuth(timeoutMs?: number): Promise<boolean>;
141
139
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
142
140
  maxRetries?: number;
@@ -570,8 +570,6 @@ export declare function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(B
570
570
  hasValidToken(): boolean;
571
571
  getAccessToken(): string | null;
572
572
  getAccessTokenExpiry(): number | null;
573
- setActingAs(userId: string | null): void;
574
- getActingAs(): string | null;
575
573
  waitForAuth(timeoutMs?: number): Promise<boolean>;
576
574
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
577
575
  maxRetries?: number;
@@ -48,7 +48,7 @@
48
48
  * platform-agnostic; deriving the current user's DID requires an authenticated
49
49
  * session.
50
50
  */
51
- import type { CredentialIssueResult, CredentialListResult, CredentialStatus, CredentialVerifyResult, ExportAttestation, PersonhoodStatusResult, PublicCard, RealLifeAttestationResult, SignedPublicCard, SignedRecordEnvelope, SignedRecordType, ValidationRequestSummary, ValidationVerdict, ValidationVoteResult, VerifiableCredentialResponse, VouchResult } from '@oxyhq/contracts';
51
+ import type { CredentialIssueResult, CredentialListResult, CredentialStatus, CredentialVerifyResult, ExportAttestation, OxySignedRecordType, PersonhoodStatusResult, PublicCard, RealLifeAttestationResult, SignedPublicCard, SignedRecordEnvelope, ValidationRequestSummary, ValidationVerdict, ValidationVoteResult, VerifiableCredentialResponse, VouchResult } from '@oxyhq/contracts';
52
52
  import type { OxyServicesBase } from '../OxyServices.base';
53
53
  /**
54
54
  * A {@link SignedPublicCard} augmented with the client's verification verdict.
@@ -132,7 +132,7 @@ export declare function parseAttestPayload(raw: string): ParsedAttestPayload | n
132
132
  * key, matching the server which omits absent keys entirely) and checks the
133
133
  * `ES256K-DER-SHA256` signature against `attestation.publicKey`.
134
134
  *
135
- * NEVER throws: `SignatureService.verify` already swallows malformed-input
135
+ * NEVER throws: `verifySignature` already swallows malformed-input
136
136
  * errors and returns `false`, and an absent attestation short-circuits to
137
137
  * `false`. A pure, reusable helper (Commons can call it on a cached card).
138
138
  *
@@ -456,7 +456,7 @@ export declare function OxyServicesCivicMixin<T extends typeof OxyServicesBase>(
456
456
  * @param collection - The AtProto-style collection namespace.
457
457
  * @param rkey - The AtProto-style record key within the collection.
458
458
  */
459
- _signMyCivicRecordV2(type: SignedRecordType, record: Record<string, unknown>, collection: string, rkey: string): Promise<SignedRecordEnvelope>;
459
+ _signMyCivicRecordV2(type: OxySignedRecordType, record: Record<string, unknown>, collection: string, rkey: string): Promise<SignedRecordEnvelope>;
460
460
  httpService: import("../HttpService").HttpService;
461
461
  cloudURL: string;
462
462
  config: import("../OxyServices.base").OxyConfig;
@@ -493,8 +493,6 @@ export declare function OxyServicesCivicMixin<T extends typeof OxyServicesBase>(
493
493
  hasValidToken(): boolean;
494
494
  getAccessToken(): string | null;
495
495
  getAccessTokenExpiry(): number | null;
496
- setActingAs(userId: string | null): void;
497
- getActingAs(): string | null;
498
496
  waitForAuth(timeoutMs?: number): Promise<boolean>;
499
497
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
500
498
  maxRetries?: number;
@@ -148,8 +148,6 @@ export declare function OxyServicesConnectedAppsMixin<T extends typeof OxyServic
148
148
  hasValidToken(): boolean;
149
149
  getAccessToken(): string | null;
150
150
  getAccessTokenExpiry(): number | null;
151
- setActingAs(userId: string | null): void;
152
- getActingAs(): string | null;
153
151
  waitForAuth(timeoutMs?: number): Promise<boolean>;
154
152
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
155
153
  maxRetries?: number;
@@ -83,8 +83,6 @@ export declare function OxyServicesContactsMixin<T extends typeof OxyServicesBas
83
83
  hasValidToken(): boolean;
84
84
  getAccessToken(): string | null;
85
85
  getAccessTokenExpiry(): number | null;
86
- setActingAs(userId: string | null): void;
87
- getActingAs(): string | null;
88
86
  waitForAuth(timeoutMs?: number): Promise<boolean>;
89
87
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
90
88
  maxRetries?: number;
@@ -85,8 +85,6 @@ export declare function OxyServicesDevicesMixin<T extends typeof OxyServicesBase
85
85
  hasValidToken(): boolean;
86
86
  getAccessToken(): string | null;
87
87
  getAccessTokenExpiry(): number | null;
88
- setActingAs(userId: string | null): void;
89
- getActingAs(): string | null;
90
88
  waitForAuth(timeoutMs?: number): Promise<boolean>;
91
89
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
92
90
  maxRetries?: number;
@@ -233,8 +233,6 @@ export declare function OxyServicesFeaturesMixin<T extends typeof OxyServicesBas
233
233
  hasValidToken(): boolean;
234
234
  getAccessToken(): string | null;
235
235
  getAccessTokenExpiry(): number | null;
236
- setActingAs(userId: string | null): void;
237
- getActingAs(): string | null;
238
236
  waitForAuth(timeoutMs?: number): Promise<boolean>;
239
237
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
240
238
  maxRetries?: number;
@@ -287,8 +287,6 @@ export declare function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(
287
287
  hasValidToken(): boolean;
288
288
  getAccessToken(): string | null;
289
289
  getAccessTokenExpiry(): number | null;
290
- setActingAs(userId: string | null): void;
291
- getActingAs(): string | null;
292
290
  waitForAuth(timeoutMs?: number): Promise<boolean>;
293
291
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
294
292
  maxRetries?: number;
@@ -23,10 +23,15 @@
23
23
  * on-device identity and throw on web (where `KeyManager.getPublicKey()` is
24
24
  * always `null`).
25
25
  */
26
- import type { AuthMethodsResponse, DidDocument, DomainVerificationInstructions, ExportBundle, SignedRecordEnvelope, VerifiedDomain } from '@oxyhq/contracts';
26
+ import type { AuthMethodsResponse, DidDocument, DomainVerificationInstructions, ExportBundle, OxySignedRecordType, SignedRecordEnvelope, VerifiedDomain } from '@oxyhq/contracts';
27
27
  import type { OxyServicesBase } from '../OxyServices.base';
28
- /** Record categories a client may sign and publish. */
29
- export type IdentityRecordType = SignedRecordEnvelope['type'];
28
+ /**
29
+ * Record categories a client may sign and publish to the Oxy store. The base
30
+ * envelope `type` is now an open string (any app may define its own records on
31
+ * the shared grammar); the Oxy identity store re-narrows it to the closed Oxy
32
+ * record set.
33
+ */
34
+ export type IdentityRecordType = OxySignedRecordType;
30
35
  /** Auth-method types that can be unlinked via {@link OxyServicesIdentityMixin}. */
31
36
  export type UnlinkableAuthMethodType = 'identity' | 'password' | 'google' | 'apple' | 'github';
32
37
  /**
@@ -230,8 +235,6 @@ export declare function OxyServicesIdentityMixin<T extends typeof OxyServicesBas
230
235
  hasValidToken(): boolean;
231
236
  getAccessToken(): string | null;
232
237
  getAccessTokenExpiry(): number | null;
233
- setActingAs(userId: string | null): void;
234
- getActingAs(): string | null;
235
238
  waitForAuth(timeoutMs?: number): Promise<boolean>;
236
239
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
237
240
  maxRetries?: number;
@@ -70,8 +70,6 @@ export declare function OxyServicesLanguageMixin<T extends typeof OxyServicesBas
70
70
  hasValidToken(): boolean;
71
71
  getAccessToken(): string | null;
72
72
  getAccessTokenExpiry(): number | null;
73
- setActingAs(userId: string | null): void;
74
- getActingAs(): string | null;
75
73
  waitForAuth(timeoutMs?: number): Promise<boolean>;
76
74
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
77
75
  maxRetries?: number;
@@ -87,8 +87,6 @@ export declare function OxyServicesLinksMixin<T extends typeof OxyServicesBase>(
87
87
  hasValidToken(): boolean;
88
88
  getAccessToken(): string | null;
89
89
  getAccessTokenExpiry(): number | null;
90
- setActingAs(userId: string | null): void;
91
- getActingAs(): string | null;
92
90
  waitForAuth(timeoutMs?: number): Promise<boolean>;
93
91
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
94
92
  maxRetries?: number;
@@ -53,8 +53,6 @@ export declare function OxyServicesLocationMixin<T extends typeof OxyServicesBas
53
53
  hasValidToken(): boolean;
54
54
  getAccessToken(): string | null;
55
55
  getAccessTokenExpiry(): number | null;
56
- setActingAs(userId: string | null): void;
57
- getActingAs(): string | null;
58
56
  waitForAuth(timeoutMs?: number): Promise<boolean>;
59
57
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
60
58
  maxRetries?: number;
@@ -1,45 +1,3 @@
1
- /**
2
- * User-Node Methods Mixin (self-sovereign identity layer — Fase 5 user nodes)
3
- *
4
- * The client surface for a user's personal data NODE — the decentralised store
5
- * that holds an authentic copy of their signed-record chain. Commons drives all
6
- * of this:
7
- *
8
- * - {@link OxyServicesNodesMixin.registerNode} registers (or re-registers) a
9
- * SELF-HOSTED node. Registration is NOT a bespoke endpoint — it is a signed
10
- * `type:'node'` v2 record (`collection: 'app.oxy.node'`, `rkey: 'self'`,
11
- * last-writer-wins) published through the EXISTING `POST /identity/records`
12
- * path; the server verifies it and materializes the operational
13
- * {@link UserNodeStatus} cache as a side effect, so the registration's
14
- * authority is the user's own signature, never an Oxy grant.
15
- * - {@link OxyServicesNodesMixin.getMyNode} reads the caller's cached node
16
- * status (`GET /nodes/me`) — the fast, stale-but-instant projection plus the
17
- * live liveness badge Oxy maintains with background probes.
18
- * - {@link OxyServicesNodesMixin.removeMyNode} revokes the registration
19
- * (`DELETE /nodes/me`) so the node leaves the DID document and the liveness
20
- * sweeps.
21
- * - {@link OxyServicesNodesMixin.provisionManagedVault} asks Oxy to operate a
22
- * MANAGED vault on the caller's behalf (`POST /nodes/managed`) — the
23
- * "Create your vault" convenience for non-technical users (Oxy custodial-signs
24
- * the node record; `managed:true, controller:'oxy'`).
25
- * - {@link OxyServicesNodesMixin.notifyNodeIngest} sends an unauthenticated
26
- * HINT (`POST /nodes/ingest/notify/:userId`) that a user's node has new
27
- * records; the server fully re-verifies before ingesting, so the hint can
28
- * never inject data.
29
- *
30
- * `registerNode` signs on the caller's per-subject hash chain with the on-device
31
- * identity key (reusing {@link SignatureService.signRecordV2} — the same
32
- * `ES256K-DER-SHA256` scheme + {@link signedRecordSigningInput} the identity and
33
- * civic mixins use), so it is NATIVE-ONLY: it throws on web (where `KeyManager`
34
- * has no key) and when no user is authenticated. Reading the node status,
35
- * revoking, provisioning a managed vault, and sending an ingest hint are plain
36
- * authenticated/public requests with no signing.
37
- *
38
- * The wire shapes here are API-INTERNAL (the F5 user-node surface is not yet a
39
- * published `@oxyhq/contracts` schema), so {@link UserNodeStatus} mirrors the
40
- * server's `serializeNode` projection exactly. Dates cross the wire as ISO
41
- * strings.
42
- */
43
1
  import type { OxyServicesBase } from '../OxyServices.base';
44
2
  /** How Oxy and the node move records: the node pulls (default), or Oxy pushes. */
45
3
  export type UserNodeMode = 'pull' | 'push';
@@ -223,8 +181,6 @@ export declare function OxyServicesNodesMixin<T extends typeof OxyServicesBase>(
223
181
  hasValidToken(): boolean;
224
182
  getAccessToken(): string | null;
225
183
  getAccessTokenExpiry(): number | null;
226
- setActingAs(userId: string | null): void;
227
- getActingAs(): string | null;
228
184
  waitForAuth(timeoutMs?: number): Promise<boolean>;
229
185
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
230
186
  maxRetries?: number;
@@ -100,8 +100,6 @@ export declare function OxyServicesPaymentMixin<T extends typeof OxyServicesBase
100
100
  hasValidToken(): boolean;
101
101
  getAccessToken(): string | null;
102
102
  getAccessTokenExpiry(): number | null;
103
- setActingAs(userId: string | null): void;
104
- getActingAs(): string | null;
105
103
  waitForAuth(timeoutMs?: number): Promise<boolean>;
106
104
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
107
105
  maxRetries?: number;
@@ -129,8 +129,6 @@ export declare function OxyServicesPrivacyMixin<T extends typeof OxyServicesBase
129
129
  hasValidToken(): boolean;
130
130
  getAccessToken(): string | null;
131
131
  getAccessTokenExpiry(): number | null;
132
- setActingAs(userId: string | null): void;
133
- getActingAs(): string | null;
134
132
  waitForAuth(timeoutMs?: number): Promise<boolean>;
135
133
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
136
134
  maxRetries?: number;
@@ -72,8 +72,6 @@ export declare function OxyServicesRedirectAuthMixin<T extends typeof OxyService
72
72
  hasValidToken(): boolean;
73
73
  getAccessToken(): string | null;
74
74
  getAccessTokenExpiry(): number | null;
75
- setActingAs(userId: string | null): void;
76
- getActingAs(): string | null;
77
75
  waitForAuth(timeoutMs?: number): Promise<boolean>;
78
76
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
79
77
  maxRetries?: number;
@@ -418,8 +418,6 @@ export declare function OxyServicesReputationMixin<T extends typeof OxyServicesB
418
418
  hasValidToken(): boolean;
419
419
  getAccessToken(): string | null;
420
420
  getAccessTokenExpiry(): number | null;
421
- setActingAs(userId: string | null): void;
422
- getActingAs(): string | null;
423
421
  waitForAuth(timeoutMs?: number): Promise<boolean>;
424
422
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
425
423
  maxRetries?: number;
@@ -67,8 +67,6 @@ export declare function OxyServicesSecurityMixin<T extends typeof OxyServicesBas
67
67
  hasValidToken(): boolean;
68
68
  getAccessToken(): string | null;
69
69
  getAccessTokenExpiry(): number | null;
70
- setActingAs(userId: string | null): void;
71
- getActingAs(): string | null;
72
70
  waitForAuth(timeoutMs?: number): Promise<boolean>;
73
71
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
74
72
  maxRetries?: number;
@@ -110,8 +110,6 @@ export declare function OxyServicesSilentAuthMixin<T extends typeof OxyServicesB
110
110
  hasValidToken(): boolean;
111
111
  getAccessToken(): string | null;
112
112
  getAccessTokenExpiry(): number | null;
113
- setActingAs(userId: string | null): void;
114
- getActingAs(): string | null;
115
113
  waitForAuth(timeoutMs?: number): Promise<boolean>;
116
114
  withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
117
115
  maxRetries?: number;