@oxy.so/core 7.26.0 → 7.27.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.
@@ -118,9 +118,26 @@ class IdentityApi {
118
118
  * Resolve the W3C DID document for any user. The API derives it on demand
119
119
  * from the account's `authMethods` + `publicKey` — there is no stored
120
120
  * document. Public (no auth required); short-TTL cached.
121
+ *
122
+ * `{ fresh: true }` reads the document as it is NOW: it skips (and drops)
123
+ * this client's cached copy, is not joined to an in-flight read, and sends
124
+ * `Cache-Control: no-cache` so no HTTP cache on the way answers for the
125
+ * origin. Use it whenever the answer decides where money goes: `#key-1` is
126
+ * the account's Peable receive key and changes on a rotation or an
127
+ * organization key replacement, and a cached copy would derive an address
128
+ * from the previous key for up to the cache TTL.
121
129
  */
122
- async resolveDid(userId) {
123
- return this.ctx.request('GET', `/u/${encodeURIComponent(userId)}/did.json`, undefined, {
130
+ async resolveDid(userId, options = {}) {
131
+ const path = `/u/${encodeURIComponent(userId)}/did.json`;
132
+ if (options.fresh) {
133
+ this.ctx.http.invalidateCache({ keys: [`GET:${path}`] });
134
+ return this.ctx.request('GET', path, undefined, {
135
+ cache: false,
136
+ deduplicate: false,
137
+ headers: { 'Cache-Control': 'no-cache' },
138
+ });
139
+ }
140
+ return this.ctx.request('GET', path, undefined, {
124
141
  cache: true,
125
142
  cacheTTL: SHORT_TTL,
126
143
  });
@@ -65,6 +65,12 @@ function deriveScopedSeedFromKey(privateKeyHex, info) {
65
65
  * `HMAC-SHA256(SOCIAL_RECEIVE_CHAIN_CODE_KEY, compressed identity public key)`.
66
66
  * Identical to `@fairco.in/core`'s `deriveSocialReceiveSpendingKey`.
67
67
  *
68
+ * INTERNAL to `@oxy.so/core` (not exported from `@oxy.so/core/crypto`): the
69
+ * derivation is non-hardened and the chain code is a public function of the
70
+ * identity public key, so `identity = child - I_L mod n` — whoever holds one
71
+ * child private key and the public key holds the identity key. Callers get
72
+ * signatures ({@link signSocialReceiveDigest}), never the child key.
73
+ *
68
74
  * @returns the child private key and its compressed public key, lowercase hex.
69
75
  */
70
76
  function deriveSocialReceiveKey(privateKeyHex, index) {
@@ -12,7 +12,7 @@
12
12
  * common chunk, which is the cost the lazy loading exists to avoid.
13
13
  */
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.verifySignature = exports.signMessage = exports.loadCommonsIdentityBridge = exports.canonicalize = exports.createContentHasher = exports.solveRegistrationPow = exports.deriveIdentityLinkCode = exports.signIdentityProof = exports.digestIdentityPayload = exports.authChallengeDigest = exports.signSocialReceiveDigest = exports.deriveSocialReceiveKey = exports.deriveScopedSeedFromKey = exports.MAX_SOCIAL_RECEIVE_INDEX = exports.SOCIAL_RECEIVE_CHAIN_CODE_KEY = exports.SCOPED_SEED_KDF_SALT = exports.deriveSharedSecret = exports.AEAD_NONCE_LENGTH = exports.AEAD_KEY_LENGTH = exports.decryptAead = exports.encryptAead = exports.hkdfSha256 = exports.BACKUP_KDF_ENCRYPTION_INFO = exports.RecoveryPhraseService = exports.SignatureService = exports.isHealthyOrganizationKeyPair = exports.isOrganizationAccountId = exports.syncOrganizationKeys = exports.deleteOrganizationKey = exports.listOrganizationKeys = exports.getOrganizationRecoveryPhrase = exports.getOrganizationPrivateKey = exports.getOrganizationPublicKey = exports.storeOrganizationKey = exports.organizationKeyFromPhrase = exports.generateOrganizationKey = exports.updateIdentityMarker = exports.readIdentityMarker = exports.IdentityUnavailableError = exports.IdentityPersistError = exports.IdentityAlreadyExistsError = exports.KeyManager = void 0;
15
+ exports.verifySignature = exports.signMessage = exports.loadCommonsIdentityBridge = exports.canonicalize = exports.createContentHasher = exports.solveRegistrationPow = exports.deriveIdentityLinkCode = exports.signIdentityProof = exports.digestIdentityPayload = exports.authChallengeDigest = exports.signSocialReceiveDigest = exports.deriveScopedSeedFromKey = exports.MAX_SOCIAL_RECEIVE_INDEX = exports.SOCIAL_RECEIVE_CHAIN_CODE_KEY = exports.SCOPED_SEED_KDF_SALT = exports.deriveSharedSecret = exports.AEAD_NONCE_LENGTH = exports.AEAD_KEY_LENGTH = exports.decryptAead = exports.encryptAead = exports.hkdfSha256 = exports.BACKUP_KDF_ENCRYPTION_INFO = exports.RecoveryPhraseService = exports.SignatureService = exports.isHealthyOrganizationKeyPair = exports.isOrganizationAccountId = exports.syncOrganizationKeys = exports.deleteOrganizationKey = exports.listOrganizationKeys = exports.getOrganizationRecoveryPhrase = exports.getOrganizationPrivateKey = exports.getOrganizationPublicKey = exports.storeOrganizationKey = exports.organizationKeyFromPhrase = exports.generateOrganizationKey = exports.updateIdentityMarker = exports.readIdentityMarker = exports.IdentityUnavailableError = exports.IdentityPersistError = exports.IdentityAlreadyExistsError = exports.KeyManager = void 0;
16
16
  // MUST stay the first import: the shim has to exist before any module below
17
17
  // evaluates or draws randomness (see `./polyfill`).
18
18
  require("./polyfill");
@@ -53,13 +53,16 @@ Object.defineProperty(exports, "AEAD_NONCE_LENGTH", { enumerable: true, get: fun
53
53
  var ecdh_1 = require("./ecdh");
54
54
  Object.defineProperty(exports, "deriveSharedSecret", { enumerable: true, get: function () { return ecdh_1.deriveSharedSecret; } });
55
55
  // What the identity key computes without leaving its holder: the same functions
56
- // Commons' identity host implements natively on Android.
56
+ // Commons' identity host implements natively on Android. The social-receive
57
+ // CHILD private key (`deriveSocialReceiveKey`) is deliberately not here: the
58
+ // derivation is non-hardened under a chain code anyone can compute from the
59
+ // public key, so one leaked child private key reveals the identity key. Only
60
+ // signatures (`signSocialReceiveDigest`) leave this module.
57
61
  var identityDerivations_1 = require("./identityDerivations");
58
62
  Object.defineProperty(exports, "SCOPED_SEED_KDF_SALT", { enumerable: true, get: function () { return identityDerivations_1.SCOPED_SEED_KDF_SALT; } });
59
63
  Object.defineProperty(exports, "SOCIAL_RECEIVE_CHAIN_CODE_KEY", { enumerable: true, get: function () { return identityDerivations_1.SOCIAL_RECEIVE_CHAIN_CODE_KEY; } });
60
64
  Object.defineProperty(exports, "MAX_SOCIAL_RECEIVE_INDEX", { enumerable: true, get: function () { return identityDerivations_1.MAX_SOCIAL_RECEIVE_INDEX; } });
61
65
  Object.defineProperty(exports, "deriveScopedSeedFromKey", { enumerable: true, get: function () { return identityDerivations_1.deriveScopedSeedFromKey; } });
62
- Object.defineProperty(exports, "deriveSocialReceiveKey", { enumerable: true, get: function () { return identityDerivations_1.deriveSocialReceiveKey; } });
63
66
  Object.defineProperty(exports, "signSocialReceiveDigest", { enumerable: true, get: function () { return identityDerivations_1.signSocialReceiveDigest; } });
64
67
  Object.defineProperty(exports, "authChallengeDigest", { enumerable: true, get: function () { return identityDerivations_1.authChallengeDigest; } });
65
68
  // Identity proofs — the one signed format for operations on a personal root
@@ -80,9 +80,26 @@ export class IdentityApi {
80
80
  * Resolve the W3C DID document for any user. The API derives it on demand
81
81
  * from the account's `authMethods` + `publicKey` — there is no stored
82
82
  * document. Public (no auth required); short-TTL cached.
83
+ *
84
+ * `{ fresh: true }` reads the document as it is NOW: it skips (and drops)
85
+ * this client's cached copy, is not joined to an in-flight read, and sends
86
+ * `Cache-Control: no-cache` so no HTTP cache on the way answers for the
87
+ * origin. Use it whenever the answer decides where money goes: `#key-1` is
88
+ * the account's Peable receive key and changes on a rotation or an
89
+ * organization key replacement, and a cached copy would derive an address
90
+ * from the previous key for up to the cache TTL.
83
91
  */
84
- async resolveDid(userId) {
85
- return this.ctx.request('GET', `/u/${encodeURIComponent(userId)}/did.json`, undefined, {
92
+ async resolveDid(userId, options = {}) {
93
+ const path = `/u/${encodeURIComponent(userId)}/did.json`;
94
+ if (options.fresh) {
95
+ this.ctx.http.invalidateCache({ keys: [`GET:${path}`] });
96
+ return this.ctx.request('GET', path, undefined, {
97
+ cache: false,
98
+ deduplicate: false,
99
+ headers: { 'Cache-Control': 'no-cache' },
100
+ });
101
+ }
102
+ return this.ctx.request('GET', path, undefined, {
86
103
  cache: true,
87
104
  cacheTTL: SHORT_TTL,
88
105
  });
@@ -58,6 +58,12 @@ export function deriveScopedSeedFromKey(privateKeyHex, info) {
58
58
  * `HMAC-SHA256(SOCIAL_RECEIVE_CHAIN_CODE_KEY, compressed identity public key)`.
59
59
  * Identical to `@fairco.in/core`'s `deriveSocialReceiveSpendingKey`.
60
60
  *
61
+ * INTERNAL to `@oxy.so/core` (not exported from `@oxy.so/core/crypto`): the
62
+ * derivation is non-hardened and the chain code is a public function of the
63
+ * identity public key, so `identity = child - I_L mod n` — whoever holds one
64
+ * child private key and the public key holds the identity key. Callers get
65
+ * signatures ({@link signSocialReceiveDigest}), never the child key.
66
+ *
61
67
  * @returns the child private key and its compressed public key, lowercase hex.
62
68
  */
63
69
  export function deriveSocialReceiveKey(privateKeyHex, index) {
@@ -24,8 +24,12 @@ export { hkdfSha256 } from './kdf.js';
24
24
  export { encryptAead, decryptAead, AEAD_KEY_LENGTH, AEAD_NONCE_LENGTH } from './aead.js';
25
25
  export { deriveSharedSecret } from './ecdh.js';
26
26
  // What the identity key computes without leaving its holder: the same functions
27
- // Commons' identity host implements natively on Android.
28
- export { SCOPED_SEED_KDF_SALT, SOCIAL_RECEIVE_CHAIN_CODE_KEY, MAX_SOCIAL_RECEIVE_INDEX, deriveScopedSeedFromKey, deriveSocialReceiveKey, signSocialReceiveDigest, authChallengeDigest, } from './identityDerivations.js';
27
+ // Commons' identity host implements natively on Android. The social-receive
28
+ // CHILD private key (`deriveSocialReceiveKey`) is deliberately not here: the
29
+ // derivation is non-hardened under a chain code anyone can compute from the
30
+ // public key, so one leaked child private key reveals the identity key. Only
31
+ // signatures (`signSocialReceiveDigest`) leave this module.
32
+ export { SCOPED_SEED_KDF_SALT, SOCIAL_RECEIVE_CHAIN_CODE_KEY, MAX_SOCIAL_RECEIVE_INDEX, deriveScopedSeedFromKey, signSocialReceiveDigest, authChallengeDigest, } from './identityDerivations.js';
29
33
  // Identity proofs — the one signed format for operations on a personal root
30
34
  // (docs/adr/0024-one-oxy-account-root-holders.md D7)
31
35
  export { digestIdentityPayload, signIdentityProof } from './identityProof.js';
@@ -10,6 +10,15 @@ export interface VerifyDomainResult {
10
10
  export interface RemoveDomainResult {
11
11
  success: boolean;
12
12
  }
13
+ /** Options for {@link IdentityApi.resolveDid}. */
14
+ export interface ResolveDidOptions {
15
+ /**
16
+ * Read the document from the origin now, never from a cache. Required when
17
+ * `#key-1` decides where money goes (deriving a Peable receive address): the
18
+ * key changes on a rotation or an organization key replacement.
19
+ */
20
+ fresh?: boolean;
21
+ }
13
22
  /** How the caller proves control of the CURRENT key during a key rotation. */
14
23
  export type RotateKeyProof = 'device' | 'phrase';
15
24
  /** Options for {@link IdentityApi.rotateKey}. */
@@ -93,8 +102,16 @@ export declare class IdentityApi {
93
102
  * Resolve the W3C DID document for any user. The API derives it on demand
94
103
  * from the account's `authMethods` + `publicKey` — there is no stored
95
104
  * document. Public (no auth required); short-TTL cached.
105
+ *
106
+ * `{ fresh: true }` reads the document as it is NOW: it skips (and drops)
107
+ * this client's cached copy, is not joined to an in-flight read, and sends
108
+ * `Cache-Control: no-cache` so no HTTP cache on the way answers for the
109
+ * origin. Use it whenever the answer decides where money goes: `#key-1` is
110
+ * the account's Peable receive key and changes on a rotation or an
111
+ * organization key replacement, and a cached copy would derive an address
112
+ * from the previous key for up to the cache TTL.
96
113
  */
97
- resolveDid(userId: string): Promise<DidDocument>;
114
+ resolveDid(userId: string, options?: ResolveDidOptions): Promise<DidDocument>;
98
115
  /**
99
116
  * The signed-in user's linked authentication methods plus their DID. Each
100
117
  * `identity` method carries a `verificationMethodId` linking it to its DID
@@ -37,6 +37,12 @@ export declare function deriveScopedSeedFromKey(privateKeyHex: string, info: str
37
37
  * `HMAC-SHA256(SOCIAL_RECEIVE_CHAIN_CODE_KEY, compressed identity public key)`.
38
38
  * Identical to `@fairco.in/core`'s `deriveSocialReceiveSpendingKey`.
39
39
  *
40
+ * INTERNAL to `@oxy.so/core` (not exported from `@oxy.so/core/crypto`): the
41
+ * derivation is non-hardened and the chain code is a public function of the
42
+ * identity public key, so `identity = child - I_L mod n` — whoever holds one
43
+ * child private key and the public key holds the identity key. Callers get
44
+ * signatures ({@link signSocialReceiveDigest}), never the child key.
45
+ *
40
46
  * @returns the child private key and its compressed public key, lowercase hex.
41
47
  */
42
48
  export declare function deriveSocialReceiveKey(privateKeyHex: string, index: number): {
@@ -27,7 +27,7 @@ export { hkdfSha256 } from './kdf';
27
27
  export { encryptAead, decryptAead, AEAD_KEY_LENGTH, AEAD_NONCE_LENGTH } from './aead';
28
28
  export type { AeadResult } from './aead';
29
29
  export { deriveSharedSecret } from './ecdh';
30
- export { SCOPED_SEED_KDF_SALT, SOCIAL_RECEIVE_CHAIN_CODE_KEY, MAX_SOCIAL_RECEIVE_INDEX, deriveScopedSeedFromKey, deriveSocialReceiveKey, signSocialReceiveDigest, authChallengeDigest, } from './identityDerivations';
30
+ export { SCOPED_SEED_KDF_SALT, SOCIAL_RECEIVE_CHAIN_CODE_KEY, MAX_SOCIAL_RECEIVE_INDEX, deriveScopedSeedFromKey, signSocialReceiveDigest, authChallengeDigest, } from './identityDerivations';
31
31
  export { digestIdentityPayload, signIdentityProof } from './identityProof';
32
32
  export { deriveIdentityLinkCode } from './identityLink';
33
33
  export { solveRegistrationPow } from './registrationPow';
@@ -41,7 +41,7 @@ export { DirectUploadInterruptedError } from './api/directUpload';
41
41
  export type { DirectUploadProgress } from './api/directUpload';
42
42
  export type { AssetsApi, AssetRecord, UploadedAsset, AssetLinkState, AssetUploadOptions, AssetUploadStageProgress, AssetLinkTarget, AssetDeleteResult, CompletedAssetUpload, LargeUploadOptions, LargeUploadProgress, LargeUploadResult, } from './api/assets';
43
43
  export { buildUserDid } from './api/identity';
44
- export type { IdentityApi, VerifyDomainResult, RemoveDomainResult, RotateKeyProof, RotateKeyOptions, RotateKeyResult, } from './api/identity';
44
+ export type { IdentityApi, VerifyDomainResult, RemoveDomainResult, ResolveDidOptions, RotateKeyProof, RotateKeyOptions, RotateKeyResult, } from './api/identity';
45
45
  export { ACCOUNT_CATEGORY_IDS, MAX_ACCOUNT_CATEGORIES, SELECTABLE_ACCOUNT_CATEGORY_IDS, isSelectableAccountCategoryId, kindAcceptsAccountCategories, } from './api/accounts';
46
46
  export type { AccountsApi, AccountKind, AccountCategoryId, AccountRelationship, AccountRole, AccountMemberStatus, AccountMemberSource, AccountMember, AccountNode, ListAccountsOptions, CreateAccountInput, UpdateAccountInput, UpdateAccountMemberInput, TransferAccountOwnershipInput, AccountSuccessResult, SwitchAccountResult, } from './api/accounts';
47
47
  export type { AppsApi, AppAssertionsApi, Application, ApplicationCallerMembership, ApplicationType, ApplicationStatus, ApplicationCredential, ApplicationCredentialType, ApplicationCredentialStatus, ApplicationEnvironment, CreateApplicationInput, UpdateApplicationInput, CreateApplicationCredentialInput, RotateApplicationCredentialInput, ApplicationCredentialWithSecret, RotateApplicationCredentialResult, ApplicationUsagePeriod, ApplicationUsageSummary, ApplicationUsageByDay, ApplicationUsageByEndpoint, ApplicationUsageStats, PublicApplication, ConnectedApp, ConnectedMcpClient, ApplicationDeleteResult, ApplicationFilesWebhook, } from './api/apps';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxy.so/core",
3
- "version": "7.26.0",
3
+ "version": "7.27.0",
4
4
  "description": "OxyHQ SDK Foundation — API client, authentication, cryptographic identity, and shared utilities",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -68,6 +68,16 @@ export interface RemoveDomainResult {
68
68
  success: boolean;
69
69
  }
70
70
 
71
+ /** Options for {@link IdentityApi.resolveDid}. */
72
+ export interface ResolveDidOptions {
73
+ /**
74
+ * Read the document from the origin now, never from a cache. Required when
75
+ * `#key-1` decides where money goes (deriving a Peable receive address): the
76
+ * key changes on a rotation or an organization key replacement.
77
+ */
78
+ fresh?: boolean;
79
+ }
80
+
71
81
  /** How the caller proves control of the CURRENT key during a key rotation. */
72
82
  export type RotateKeyProof = 'device' | 'phrase';
73
83
 
@@ -191,17 +201,29 @@ export class IdentityApi {
191
201
  * Resolve the W3C DID document for any user. The API derives it on demand
192
202
  * from the account's `authMethods` + `publicKey` — there is no stored
193
203
  * document. Public (no auth required); short-TTL cached.
204
+ *
205
+ * `{ fresh: true }` reads the document as it is NOW: it skips (and drops)
206
+ * this client's cached copy, is not joined to an in-flight read, and sends
207
+ * `Cache-Control: no-cache` so no HTTP cache on the way answers for the
208
+ * origin. Use it whenever the answer decides where money goes: `#key-1` is
209
+ * the account's Peable receive key and changes on a rotation or an
210
+ * organization key replacement, and a cached copy would derive an address
211
+ * from the previous key for up to the cache TTL.
194
212
  */
195
- async resolveDid(userId: string): Promise<DidDocument> {
196
- return this.ctx.request<DidDocument>(
197
- 'GET',
198
- `/u/${encodeURIComponent(userId)}/did.json`,
199
- undefined,
200
- {
201
- cache: true,
202
- cacheTTL: SHORT_TTL,
203
- },
204
- );
213
+ async resolveDid(userId: string, options: ResolveDidOptions = {}): Promise<DidDocument> {
214
+ const path = `/u/${encodeURIComponent(userId)}/did.json`;
215
+ if (options.fresh) {
216
+ this.ctx.http.invalidateCache({ keys: [`GET:${path}`] });
217
+ return this.ctx.request<DidDocument>('GET', path, undefined, {
218
+ cache: false,
219
+ deduplicate: false,
220
+ headers: { 'Cache-Control': 'no-cache' },
221
+ });
222
+ }
223
+ return this.ctx.request<DidDocument>('GET', path, undefined, {
224
+ cache: true,
225
+ cacheTTL: SHORT_TTL,
226
+ });
205
227
  }
206
228
 
207
229
  /**
@@ -73,6 +73,12 @@ export function deriveScopedSeedFromKey(privateKeyHex: string, info: string): Ui
73
73
  * `HMAC-SHA256(SOCIAL_RECEIVE_CHAIN_CODE_KEY, compressed identity public key)`.
74
74
  * Identical to `@fairco.in/core`'s `deriveSocialReceiveSpendingKey`.
75
75
  *
76
+ * INTERNAL to `@oxy.so/core` (not exported from `@oxy.so/core/crypto`): the
77
+ * derivation is non-hardened and the chain code is a public function of the
78
+ * identity public key, so `identity = child - I_L mod n` — whoever holds one
79
+ * child private key and the public key holds the identity key. Callers get
80
+ * signatures ({@link signSocialReceiveDigest}), never the child key.
81
+ *
76
82
  * @returns the child private key and its compressed public key, lowercase hex.
77
83
  */
78
84
  export function deriveSocialReceiveKey(
@@ -57,13 +57,16 @@ export type { AeadResult } from './aead';
57
57
  export { deriveSharedSecret } from './ecdh';
58
58
 
59
59
  // What the identity key computes without leaving its holder: the same functions
60
- // Commons' identity host implements natively on Android.
60
+ // Commons' identity host implements natively on Android. The social-receive
61
+ // CHILD private key (`deriveSocialReceiveKey`) is deliberately not here: the
62
+ // derivation is non-hardened under a chain code anyone can compute from the
63
+ // public key, so one leaked child private key reveals the identity key. Only
64
+ // signatures (`signSocialReceiveDigest`) leave this module.
61
65
  export {
62
66
  SCOPED_SEED_KDF_SALT,
63
67
  SOCIAL_RECEIVE_CHAIN_CODE_KEY,
64
68
  MAX_SOCIAL_RECEIVE_INDEX,
65
69
  deriveScopedSeedFromKey,
66
- deriveSocialReceiveKey,
67
70
  signSocialReceiveDigest,
68
71
  authChallengeDigest,
69
72
  } from './identityDerivations';
package/src/index.ts CHANGED
@@ -133,6 +133,7 @@ export type {
133
133
  IdentityApi,
134
134
  VerifyDomainResult,
135
135
  RemoveDomainResult,
136
+ ResolveDidOptions,
136
137
  RotateKeyProof,
137
138
  RotateKeyOptions,
138
139
  RotateKeyResult,