@private.me/xbind 3.0.3 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/MIGRATING.md ADDED
@@ -0,0 +1,205 @@
1
+ # xBind Migration Guide
2
+
3
+ ## 3.0.4 → 3.1.0 (Current)
4
+
5
+ ### Documentation Improvements
6
+
7
+ **No Breaking Changes** - This is a documentation-only release:
8
+
9
+ - ✅ **Migration Guide:** Added this MIGRATING.md file with upgrade paths for all versions
10
+ - ✅ **Error Reference:** Comprehensive error code documentation with fixes for common issues
11
+ - ✅ **Security API:** Clarified `security` parameter (official API) vs `payload.risk` (application data)
12
+ - ✅ **Bundled README:** Fixed broken relative links, removed internal tracking codes, consistent PQ examples
13
+
14
+ **Migration:** Update package version - no code changes required:
15
+ ```bash
16
+ npm install @private.me/xbind@3.1.0
17
+ ```
18
+
19
+ ---
20
+
21
+ ## 3.0.3 → 3.0.4
22
+
23
+ ### Bug Fixes
24
+
25
+ **H1 Security Tier Fix:**
26
+ - **Issue:** `agent.send({ security: 'high' })` threw synchronously instead of returning `Result<T,E>`
27
+ - **Fixed:** Now returns `Result` with error code `SPLIT_FAILED:CRYPTO_NOT_LOADED` when crypto package unavailable
28
+ - **Migration:** No code changes required. If you had try-catch around `send()`, you can now use standard Result handling
29
+
30
+ **Loopback URL Support:**
31
+ - **Issue:** v3.0.3 broke dev/test workflows by rejecting `http://127.0.0.1` and `http://localhost`
32
+ - **Fixed:** RFC 6761 loopback addresses now work without HTTPS requirement
33
+ - **Migration:** No code changes required. Remove any HTTPS workarounds for local development
34
+
35
+ ### Supported Loopback Addresses
36
+ - `http://127.0.0.1` (IPv4 loopback)
37
+ - `http://localhost` (standard hostname)
38
+ - `http://[::1]` or `http://::1` (IPv6 loopback)
39
+ - `http://*.localhost` (RFC 6761 reserved)
40
+
41
+ ---
42
+
43
+ ## 1.x → 3.x (Major Version)
44
+
45
+ ### Breaking Changes
46
+
47
+ **1. Full Control IP Protection**
48
+
49
+ v3.x introduced 2-share XorIDA (Store Front + Vault Store) for IP protection:
50
+
51
+ ```typescript
52
+ // v1.x: All crypto bundled in npm package
53
+ npm install @private.me/xbind@1.4.2 // 8MB package
54
+
55
+ // v3.x: Share 1 in npm, Share 2 payment-gated on EC2
56
+ npm install @private.me/xbind@3.1.0 // 1.2MB package
57
+ // Share 2 auto-fetched with billing OR set FULL_CONTROL_MASTER_KEY
58
+ ```
59
+
60
+ **Migration:**
61
+ - **No code changes** if you have active billing (Share 2 auto-fetched)
62
+ - **For offline/dev:** Set `FULL_CONTROL_MASTER_KEY` environment variable (contact contact@private.me for key)
63
+
64
+ **2. Result<T,E> Error Handling**
65
+
66
+ All APIs now return `Result<T,E>` instead of throwing:
67
+
68
+ ```typescript
69
+ // v1.x: Exception-based
70
+ try {
71
+ const agent = await Agent.create({ ... });
72
+ await agent.send({ ... });
73
+ } catch (error) {
74
+ console.error('Failed:', error);
75
+ }
76
+
77
+ // v3.x: Result-based
78
+ const agentResult = await Agent.create({ ... });
79
+ if (!agentResult.ok) {
80
+ console.error('Agent creation failed:', agentResult.error);
81
+ return;
82
+ }
83
+
84
+ const agent = agentResult.value;
85
+ const sendResult = await agent.send({ ... });
86
+ if (!sendResult.ok) {
87
+ console.error('Send failed:', sendResult.error);
88
+ }
89
+ ```
90
+
91
+ **3. Security Tier API**
92
+
93
+ Explicit `security` parameter for split-channel:
94
+
95
+ ```typescript
96
+ // v1.x: Implicit/auto-detection
97
+ await agent.send({
98
+ to: recipientDid,
99
+ payload: { sensitive: true }
100
+ });
101
+
102
+ // v3.x: Explicit security parameter
103
+ await agent.send({
104
+ to: recipientDid,
105
+ security: 'high', // 2-of-3 threshold
106
+ payload: { sensitive: true }
107
+ });
108
+ ```
109
+
110
+ Options: `'standard'` (default), `'high'` (2-of-3), `'critical'` (3-of-5)
111
+
112
+ **4. Transport Configuration**
113
+
114
+ v3.x requires explicit transport configuration:
115
+
116
+ ```typescript
117
+ // v1.x: Auto-configured
118
+ const agent = await Agent.create({ name: 'MyAgent' });
119
+
120
+ // v3.x: Explicit transport
121
+ import { HttpsTransportAdapter } from '@private.me/xbind';
122
+
123
+ const agent = await Agent.create({
124
+ name: 'MyAgent',
125
+ transport: new HttpsTransportAdapter({
126
+ baseUrl: 'https://private.me/relay'
127
+ })
128
+ });
129
+ ```
130
+
131
+ ---
132
+
133
+ ## Common Migration Issues
134
+
135
+ ### Issue: npm install silently downgrades version
136
+
137
+ **Symptom:** Running `npm install @private.me/xbind@latest` after local `file:` testing uninstalls xBind
138
+
139
+ **Cause:** npm's `file:` protocol creates a local package reference that persists across installs
140
+
141
+ **Fix:**
142
+ ```bash
143
+ # Remove cached local reference
144
+ npm uninstall @private.me/xbind
145
+ rm -rf node_modules/@private.me
146
+ rm package-lock.json
147
+
148
+ # Clean install from registry
149
+ npm install @private.me/xbind@3.1.0
150
+ ```
151
+
152
+ ### Issue: ENVELOPE_FAILED:SPLIT error
153
+
154
+ **Symptom:** `security:'high'` or `security:'critical'` returns `ENVELOPE_FAILED:SPLIT`
155
+
156
+ **Cause:** Split-channel requires 3+ transports for `'high'`, 5+ for `'critical'`
157
+
158
+ **Fix:**
159
+ ```typescript
160
+ // Add multiple transports
161
+ const agent = await Agent.create({
162
+ name: 'MyAgent',
163
+ transport: new HttpsTransportAdapter({ baseUrl: 'https://relay1.private.me' }),
164
+ // OR use quickstart which auto-configures transports
165
+ });
166
+
167
+ // Add more transports after creation
168
+ agent.addTransport(new HttpsTransportAdapter({ baseUrl: 'https://relay2.private.me' }));
169
+ agent.addTransport(new HttpsTransportAdapter({ baseUrl: 'https://relay3.private.me' }));
170
+
171
+ // Now 'high' security will work
172
+ const result = await agent.send({
173
+ to: recipientDid,
174
+ security: 'high',
175
+ payload: { message: 'Secured' }
176
+ });
177
+ ```
178
+
179
+ ### Issue: IDENTITY_FAILED:VAULT_STORE error
180
+
181
+ **Symptom:** Agent creation fails with `IDENTITY_FAILED:VAULT_STORE`
182
+
183
+ **Cause:** Share 2 (Vault Store) unavailable - no billing and no `FULL_CONTROL_MASTER_KEY`
184
+
185
+ **Fix (Production):**
186
+ - Ensure billing is active (free tier: 100K ops/month)
187
+ - Check internet connectivity
188
+
189
+ **Fix (Development/Offline):**
190
+ ```bash
191
+ # Add to .env
192
+ FULL_CONTROL_MASTER_KEY=<your-key>
193
+
194
+ # Contact contact@private.me for development key
195
+ ```
196
+
197
+ ---
198
+
199
+ ## Support
200
+
201
+ - **Documentation:** https://private.me/docs/xbind.html
202
+ - **npm:** https://www.npmjs.com/package/@private.me/xbind
203
+ - **Email:** contact@private.me
204
+
205
+ For enterprise migration assistance, contact contact@private.me
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # @private.me/xbind
2
2
 
3
3
  ![npm version](https://img.shields.io/npm/v/@private.me/xbind)
4
- ![version](https://img.shields.io/badge/version-3.0.3-blue)
4
+ ![version](https://img.shields.io/badge/version-3.1.0-blue)
5
5
  ![tests](https://img.shields.io/badge/tests-2951%20passing-brightgreen)
6
6
  ![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue)
7
7
  ![license](https://img.shields.io/badge/license-Proprietary-blue)
@@ -12,7 +12,7 @@ Build AI agents that communicate securely using ML-DSA-65 DID identity, ML-KEM-7
12
12
 
13
13
  Part of the **Private.Me** platform—where APIs have keys, but ACIs have identity.
14
14
 
15
- **Version 3.0.3** — **Major Features:** LoopbackTransport export for testing (GAP-CORE-2), describeSecurityModeStructured export (GAP-API-3), Agent.quickstart() signature fixes. Full Control IP Protection (PLAN-13) - Vault Store architecture with payment-gated algorithm delivery. Store Front (npm) contains Share 1 only, Vault Store (EC2) contains Share 2 (payment-gated). Runtime crypto loading, 4-layer security (DID auth + usage quotas + rate limiting + audit logging). Usage-based model: Free tier 100K ops/month (includes vault access), Pro tier unlimited. Previous v3.0.2: Full Control IP Protection launch. Previous v1.4.2: Runtime compatibility, API enhancements.
15
+ **Version 3.1.0** — **Documentation Improvements:** Migration guide (MIGRATING.md), comprehensive error reference, security API clarification, fixed all bundled README issues. **Bug Fixes (v3.0.4):** H1 security tier fix (security:'high'|'critical' now returns Result instead of throwing), loopback URL support restored (http://127.0.0.1 for dev/test workflows), deployment health endpoint added. Full Control IP Protection - Vault Store architecture with payment-gated algorithm delivery. Store Front (npm) contains Share 1 only, Vault Store (EC2) contains Share 2 (payment-gated). Runtime crypto loading, 4-layer security (DID auth + usage quotas + rate limiting + audit logging). Usage-based model: Free tier 100K ops/month (includes vault access), Pro tier unlimited. Previous v3.0.3: LoopbackTransport export, describeSecurityModeStructured export, Agent.quickstart() fixes. Previous v3.0.2: Full Control IP Protection launch.
16
16
 
17
17
  ## Install
18
18
 
@@ -26,7 +26,7 @@ pip install private-me-xbind
26
26
 
27
27
  **Distribution Model:** xBind uses Full Control IP protection (2-share XorIDA). Share 1 (Store Front) is distributed via npm registry. Share 2 (Vault Store) is served via `/api/full-control/share2/:package/:version` and requires payment verification and xBind authentication.
28
28
 
29
- [Python SDK documentation](./python/README.md) • [Complete docs](./docs/README.md) • [White paper](https://private.me/docs/xbind.html)
29
+ [Migration Guide](./MIGRATING.md) • [Python SDK](https://pypi.org/project/private-me-xbind/) • [White paper](https://private.me/docs/xbind.html) • [npm](https://www.npmjs.com/package/@private.me/xbind)
30
30
 
31
31
  ## Security Notice
32
32
 
@@ -106,7 +106,7 @@ const seed = await getSeed();
106
106
  const result = await Agent.fromSeed(Buffer.from(seed, 'hex'), {
107
107
  registry: new HttpTrustRegistry({ baseUrl: 'https://private.me/registry' }),
108
108
  transport: new HttpsTransportAdapter({ baseUrl: 'https://private.me/relay' }),
109
- postQuantumSig: false
109
+ postQuantumSig: true // ML-DSA-65 post-quantum signatures (default)
110
110
  });
111
111
 
112
112
  if (!result.ok) {
@@ -136,7 +136,7 @@ if (!seed) throw new Error('Seed not found in credential store');
136
136
  const result = await Agent.fromSeed(Buffer.from(seed, 'hex'), {
137
137
  registry: new HttpTrustRegistry({ baseUrl: 'https://private.me/registry' }),
138
138
  transport: new HttpsTransportAdapter({ baseUrl: 'https://private.me/relay' }),
139
- postQuantumSig: false
139
+ postQuantumSig: true // ML-DSA-65 post-quantum signatures (default)
140
140
  });
141
141
 
142
142
  if (!result.ok) {
@@ -165,7 +165,7 @@ if (!seed) throw new Error('Seed not found in Secret Service');
165
165
  const result = await Agent.fromSeed(Buffer.from(seed, 'hex'), {
166
166
  registry: new HttpTrustRegistry({ baseUrl: 'https://private.me/registry' }),
167
167
  transport: new HttpsTransportAdapter({ baseUrl: 'https://private.me/relay' }),
168
- postQuantumSig: false
168
+ postQuantumSig: true // ML-DSA-65 post-quantum signatures (default)
169
169
  });
170
170
 
171
171
  if (!result.ok) {
@@ -211,7 +211,7 @@ const decryptedSeed = await kms.send(new DecryptCommand({
211
211
  const result = await Agent.fromSeed(Buffer.from(decryptedSeed.Plaintext), {
212
212
  registry: new HttpTrustRegistry({ baseUrl: 'https://private.me/registry' }),
213
213
  transport: new HttpsTransportAdapter({ baseUrl: 'https://private.me/relay' }),
214
- postQuantumSig: false
214
+ postQuantumSig: true // ML-DSA-65 post-quantum signatures (default)
215
215
  });
216
216
 
217
217
  if (!result.ok) {
@@ -543,7 +543,7 @@ console.log('Scope:', message.scope);
543
543
 
544
544
  **JITR (Just-in-Time Registration):** Agents created with `Agent.fromSeed()` automatically register with the trust registry on first use. No manual registration scripts required. Includes all encryption keys (Ed25519, X25519, ML-KEM, ML-DSA) for zero-config encrypted messaging.
545
545
 
546
- [More examples](./docs/examples.md) • [Python examples](./python/README.md)
546
+ [White paper](https://private.me/docs/xbind.html) • [Python SDK](https://pypi.org/project/private-me-xbind/)
547
547
 
548
548
  ## Programmatic Quickstart
549
549
 
@@ -622,7 +622,7 @@ Transport type: HttpsTransportAdapter
622
622
  - Exceeding 100K operations/month
623
623
  - Accessing production features
624
624
 
625
- [More examples](./docs/examples.md) • [Python examples](./python/README.md)
625
+ [White paper](https://private.me/docs/xbind.html) • [Python SDK](https://pypi.org/project/private-me-xbind/)
626
626
 
627
627
  ## Post-Quantum Cryptography & Envelopes
628
628
 
@@ -1684,7 +1684,7 @@ else:
1684
1684
  print(f"Error: {result['error']['message']}")
1685
1685
  ```
1686
1686
 
1687
- See [Python SDK documentation](./python/README.md) for complete API reference and examples.
1687
+ See [Python SDK on PyPI](https://pypi.org/project/private-me-xbind/) for complete API reference and examples.
1688
1688
 
1689
1689
  ## Why xBind?
1690
1690
 
@@ -1768,11 +1768,11 @@ Zero key management, zero cascade failures, zero bearer credentials. Cryptograph
1768
1768
  - **End-to-end integration:** Full message flow tests (Agent A → Gateway → Agent B)
1769
1769
  - **Gateway concurrency:** 100 concurrent sends, race condition detection
1770
1770
  - **Network partition recovery:** Disconnect/reconnect cycles with retry logic
1771
- - **PLAN-3 hybrid signatures:** Bilateral authorization with composite verification
1771
+ - **Hybrid signatures:** Bilateral authorization with composite verification
1772
1772
 
1773
1773
  ## Bundle Size Optimization (Tree-Shaking)
1774
1774
 
1775
- **New in v3.0.3:** LoopbackTransport export (testing workflow), describeSecurityModeStructured export (white paper examples), Agent.quickstart() signature fixes (README correctness). Full Control IP Protection (v3.0.2) - cryptographic algorithms delivered via payment-gated Vault Store. Share 1 in npm (useless alone), Share 2 in EC2 (completes algorithm). Information-theoretic security for proprietary IP.
1775
+ **New in v3.1.0:** Documentation improvements - Migration guide (MIGRATING.md), comprehensive error reference section, security API clarification (security parameter vs payload.risk), fixed all customer-reported README issues (broken links, tracking codes, PQ example consistency). Previous v3.0.4: Bug fixes - H1 security tier fix, loopback URL support, deployment health endpoint. Full Control IP Protection (v3.0.2) - cryptographic algorithms delivered via payment-gated Vault Store. Share 1 in npm (useless alone), Share 2 in EC2 (completes algorithm). Information-theoretic security for proprietary IP.
1776
1776
 
1777
1777
  ### Full Import (Convenience)
1778
1778
 
@@ -1810,36 +1810,35 @@ import { generateIdentity } from '@private.me/xbind/identity';
1810
1810
 
1811
1811
  xBind automatically activates information-theoretic XorIDA threshold sharing for high-risk operations. No code changes required—security is transparent.
1812
1812
 
1813
- ### Risk Tags (Recommended for Crypto)
1813
+ ### Security Tiers (Official API)
1814
1814
 
1815
- For cryptocurrency transactions (BTC, ETH, etc.), use explicit risk tags in your payload:
1815
+ **Use the `security` parameter to control split-channel protection level:**
1816
1816
 
1817
1817
  ```typescript
1818
- // Low risk: 2-of-2 threshold
1818
+ // Standard: Single-channel delivery (default, fastest)
1819
1819
  await agent.send({
1820
1820
  to: recipientDid,
1821
- payload: { amount: 0.5, currency: 'BTC', risk: 'low' }
1821
+ security: 'standard', // Default, no split-channel
1822
+ payload: { amount: 0.5, currency: 'BTC' }
1822
1823
  });
1823
1824
 
1824
- // Medium risk: 2-of-3 threshold
1825
+ // High: 2-of-3 threshold sharing (recommended for crypto)
1825
1826
  await agent.send({
1826
1827
  to: recipientDid,
1827
- payload: { amount: 5.0, currency: 'ETH', risk: 'medium' }
1828
+ security: 'high', // Requires 3+ transports
1829
+ payload: { amount: 50, currency: 'BTC' }
1828
1830
  });
1829
1831
 
1830
- // High risk: 3-of-5 threshold
1832
+ // Critical: 3-of-5 threshold sharing (maximum security)
1831
1833
  await agent.send({
1832
1834
  to: recipientDid,
1833
- payload: { amount: 50, currency: 'BTC', risk: 'high' }
1834
- });
1835
-
1836
- // Critical risk: 3-of-5 threshold
1837
- await agent.send({
1838
- to: recipientDid,
1839
- payload: { amount: 100, currency: 'BTC', risk: 'critical' }
1835
+ security: 'critical', // Requires 5+ transports
1836
+ payload: { amount: 100, currency: 'BTC' }
1840
1837
  });
1841
1838
  ```
1842
1839
 
1840
+ **Note:** The `security` parameter controls xBind's cryptographic protection. Application-level risk assessment (like `payload.risk`) is separate from xBind's security tier and has no effect on split-channel behavior.
1841
+
1843
1842
  ### Fiat Currency Auto-Detection
1844
1843
 
1845
1844
  For fiat currencies (USD, EUR, GBP), xBind uses numeric thresholds:
@@ -2739,7 +2738,7 @@ await registry.register(
2739
2738
  mlDsaPublicKey,
2740
2739
  true, // xchange enabled
2741
2740
  ['billing', 'auth'], // receive scopes
2742
- '3.0.3', // SDK version
2741
+ '3.0.4', // SDK version
2743
2742
  1, // minEnvelopeVersion
2744
2743
  4 // maxEnvelopeVersion
2745
2744
  );
@@ -2948,6 +2947,70 @@ const received = await bob.receive(envelope);
2948
2947
  - CI/CD pipelines that need fast, deterministic tests
2949
2948
  - Integration testing of multi-agent workflows
2950
2949
 
2950
+ ## Error Reference
2951
+
2952
+ xBind returns detailed error codes via `Result<T,E>` pattern. All errors follow the format `CATEGORY:SUBCODE` for precise diagnostics.
2953
+
2954
+ ### Common Errors
2955
+
2956
+ **ENVELOPE_FAILED Family** - Message envelope creation/processing failures:
2957
+
2958
+ - `ENVELOPE_FAILED:SPLIT` - Split-channel requires 3+ transports. **Fix:** Add more transports to your agent configuration OR disable split-channel (use `security:'standard'` instead of `'high'`/`'critical'`)
2959
+ - `ENVELOPE_FAILED:SIGNATURE` - Message signing failed (corrupted keys or invalid DID)
2960
+ - `ENVELOPE_FAILED:ENCRYPTION` - Key agreement or encryption failed
2961
+
2962
+ **IDENTITY_FAILED Family** - Agent identity/key issues:
2963
+
2964
+ - `IDENTITY_FAILED:KEYGEN` - Cryptographic key generation failed
2965
+ - `IDENTITY_FAILED:VAULT_STORE` - Share 2 (Vault Store) unavailable. **Fix:** Check internet connectivity, verify billing status, or set `FULL_CONTROL_MASTER_KEY` environment variable for offline mode
2966
+ - `SPLIT_FAILED:CRYPTO_NOT_LOADED` - Crypto package not loaded (missing Share 2). **Fix:** Ensure `loadCryptoPackage()` is called OR billing is active for automatic Vault Store access
2967
+
2968
+ **Network/Transport Errors:**
2969
+
2970
+ - `RECIPIENT_UNREACHABLE` - Unable to deliver message to recipient DID
2971
+ - `TIMEOUT` - Network operation exceeded timeout threshold (default: 10s)
2972
+ - `NETWORK_ERROR` - General network failure (DNS, connection refused, etc.)
2973
+ - `HTTPS_REQUIRED` - Non-loopback HTTP URL rejected (security policy). **Fix:** Use HTTPS URLs for production OR use loopback addresses (127.0.0.1, localhost, ::1) for development
2974
+
2975
+ **Registry Errors:**
2976
+
2977
+ - `REGISTRATION_FAILED:ALREADY_REGISTERED` - DID already exists in trust registry
2978
+ - `REGISTRATION_FAILED:NETWORK_ERROR` - Registry unreachable or network failure
2979
+ - `RESOLVE_FAILED:NOT_FOUND` - Recipient DID not found in trust registry
2980
+
2981
+ ### Error Handling Example
2982
+
2983
+ ```typescript
2984
+ const result = await agent.send({
2985
+ to: recipientDid,
2986
+ security: 'high', // Requires 3+ transports
2987
+ payload: { message: 'Hello' }
2988
+ });
2989
+
2990
+ if (!result.ok) {
2991
+ switch (result.error) {
2992
+ case 'ENVELOPE_FAILED:SPLIT':
2993
+ console.error('Need 3+ transports for high security. Add more transports or use security:"standard"');
2994
+ break;
2995
+ case 'IDENTITY_FAILED:VAULT_STORE':
2996
+ console.error('Vault Store unavailable. Check billing or set FULL_CONTROL_MASTER_KEY');
2997
+ break;
2998
+ case 'RECIPIENT_UNREACHABLE':
2999
+ console.error('Cannot reach recipient. Check DID and network connectivity');
3000
+ break;
3001
+ default:
3002
+ console.error('Send failed:', result.error);
3003
+ }
3004
+ }
3005
+ ```
3006
+
3007
+ ### Debugging Tips
3008
+
3009
+ 1. **Split-channel errors:** Ensure `agent.transports.length >= 3` before using `security:'high'` or `'critical'`
3010
+ 2. **Vault Store errors:** Check `.env` for `FULL_CONTROL_MASTER_KEY` (offline mode) or verify billing status (online mode)
3011
+ 3. **Network errors:** Enable debug logging with `DEBUG=xbind:* npm start`
3012
+ 4. **Type safety:** Use TypeScript for autocomplete on all error codes
3013
+
2951
3014
  ## Full Control IP Protection
2952
3015
 
2953
3016
  xBind uses **Full Control** (2-share XorIDA) to protect proprietary cryptographic algorithms while maintaining a seamless developer experience.
@@ -3138,7 +3201,7 @@ This package contains cryptographic software. Export restrictions may apply. Use
3138
3201
 
3139
3202
  ---
3140
3203
 
3141
- **Questions?** [Documentation](./docs/README.md) • [White paper](https://private.me/docs/xbind.html) • [Issues](https://github.com/xail-io/xail/issues)
3204
+ **Questions?** [White paper](https://private.me/docs/xbind.html) • [npm](https://www.npmjs.com/package/@private.me/xbind) • contact@private.me
3142
3205
 
3143
3206
  ### Stream Processing Utilities
3144
3207
 
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.DEFAULT_SPLIT_CONFIG=void 0,exports.splitForChannel=splitForChannel,exports.splitForChannelWithGroupId=splitForChannelWithGroupId,exports.reconstructFromChannel=reconstructFromChannel;const shared_1=require("../_deps/shared/index.js"),crypto_utils_js_1=require("./crypto-utils.js");async function splitForChannel(r,t=exports.DEFAULT_SPLIT_CONFIG){const{totalShares:e,threshold:s}=t;if(e<2||s<2||s>e)return(0,shared_1.err)("SPLIT_FAILED:INVALID_PARAMS");return splitForChannelWithGroupId(r,t,(0,crypto_utils_js_1.generateUUID)())}async function splitForChannelWithGroupId(r,t,e){const{totalShares:s,threshold:_}=t;if(s<2||_<2||_>s)return(0,shared_1.err)("SPLIT_FAILED:INVALID_PARAMS");const o=(0,crypto_utils_js_1.nextOddPrime)(s)-1,a=(0,crypto_utils_js_1.pkcs7Pad)(r,o),{key:n,signature:i}=await(0,crypto_utils_js_1.generateHMAC)(a);let c;try{c=(0,crypto_utils_js_1.splitXorIDA)(a,s,_)}catch{return(0,shared_1.err)("SPLIT_FAILED")}const u=(0,crypto_utils_js_1.toBase64)(n),l=(0,crypto_utils_js_1.toBase64)(i),d=c.map((r,t)=>({data:(0,crypto_utils_js_1.formatShareHeader)((0,crypto_utils_js_1.toBase64)(r)),index:t,total:s,threshold:_,groupId:e,hmacKey:u,hmacSig:l}));return(0,shared_1.ok)(d)}async function reconstructFromChannel(r){const t=validateShares(r);if(!t.ok)return t;const{k:e,n:s}=t.value;return reconstructValidated(r.slice(0,e),s,e)}function validateShares(r){if(0===r.length)return(0,shared_1.err)("INSUFFICIENT_SHARES");const t=r[0],e=t.threshold,s=t.total;if(r.length<e)return(0,shared_1.err)("INSUFFICIENT_SHARES");const _=new Set;for(const o of r){if(o.groupId!==t.groupId)return(0,shared_1.err)("INCONSISTENT_SHARES");if(o.total!==s||o.threshold!==e)return(0,shared_1.err)("INCONSISTENT_SHARES");if(o.index<0||o.index>=s)return(0,shared_1.err)("INVALID_SHARE_DATA");if(_.has(o.index))return(0,shared_1.err)("INVALID_SHARE_DATA");_.add(o.index)}return(0,shared_1.ok)({k:e,n:s,groupId:t.groupId})}async function reconstructValidated(r,t,e){let s;try{s=r.map(r=>(0,crypto_utils_js_1.fromBase64)((0,crypto_utils_js_1.parseShareHeader)(r.data)))}catch{return(0,shared_1.err)("INVALID_SHARE_DATA:BASE64")}const _=r.map(r=>r.index);let o;try{o=(0,crypto_utils_js_1.reconstructXorIDA)(s,_,t,e)}catch{return(0,shared_1.err)("SPLIT_FAILED:RECONSTRUCT")}const a=r[0];let n,i;try{n=(0,crypto_utils_js_1.fromBase64)(a.hmacKey),i=(0,crypto_utils_js_1.fromBase64)(a.hmacSig)}catch{return(0,shared_1.err)("INVALID_SHARE_DATA:HMAC_DECODE")}if(!await(0,crypto_utils_js_1.verifyHMAC)(n,o,i))return(0,shared_1.err)("HMAC_VERIFICATION_FAILED");const c=(0,crypto_utils_js_1.nextOddPrime)(t)-1,u=(0,crypto_utils_js_1.pkcs7Unpad)(o,c);return u.ok?(0,shared_1.ok)(u.value):(0,shared_1.err)("UNPAD_FAILED")}exports.DEFAULT_SPLIT_CONFIG={totalShares:3,threshold:2};
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.DEFAULT_SPLIT_CONFIG=void 0,exports.splitForChannel=splitForChannel,exports.splitForChannelWithGroupId=splitForChannelWithGroupId,exports.reconstructFromChannel=reconstructFromChannel;const shared_1=require("../_deps/shared/index.js"),crypto_utils_js_1=require("./crypto-utils.js");async function splitForChannel(r,t=exports.DEFAULT_SPLIT_CONFIG){const{totalShares:e,threshold:s}=t;if(e<2||s<2||s>e)return(0,shared_1.err)("SPLIT_FAILED:INVALID_PARAMS");return splitForChannelWithGroupId(r,t,(0,crypto_utils_js_1.generateUUID)())}async function splitForChannelWithGroupId(r,t,e){const{totalShares:s,threshold:_}=t;if(s<2||_<2||_>s)return(0,shared_1.err)("SPLIT_FAILED:INVALID_PARAMS");let o,a,n;try{const t=(0,crypto_utils_js_1.nextOddPrime)(s)-1,e=(0,crypto_utils_js_1.pkcs7Pad)(r,t),i=await(0,crypto_utils_js_1.generateHMAC)(e);a=i.key,n=i.signature,o=(0,crypto_utils_js_1.splitXorIDA)(e,s,_)}catch(r){return(0,shared_1.err)("SPLIT_FAILED:CRYPTO_NOT_LOADED")}const i=(0,crypto_utils_js_1.toBase64)(a),c=(0,crypto_utils_js_1.toBase64)(n),u=o.map((r,t)=>({data:(0,crypto_utils_js_1.formatShareHeader)((0,crypto_utils_js_1.toBase64)(r)),index:t,total:s,threshold:_,groupId:e,hmacKey:i,hmacSig:c}));return(0,shared_1.ok)(u)}async function reconstructFromChannel(r){const t=validateShares(r);if(!t.ok)return t;const{k:e,n:s}=t.value;return reconstructValidated(r.slice(0,e),s,e)}function validateShares(r){if(0===r.length)return(0,shared_1.err)("INSUFFICIENT_SHARES");const t=r[0],e=t.threshold,s=t.total;if(r.length<e)return(0,shared_1.err)("INSUFFICIENT_SHARES");const _=new Set;for(const o of r){if(o.groupId!==t.groupId)return(0,shared_1.err)("INCONSISTENT_SHARES");if(o.total!==s||o.threshold!==e)return(0,shared_1.err)("INCONSISTENT_SHARES");if(o.index<0||o.index>=s)return(0,shared_1.err)("INVALID_SHARE_DATA");if(_.has(o.index))return(0,shared_1.err)("INVALID_SHARE_DATA");_.add(o.index)}return(0,shared_1.ok)({k:e,n:s,groupId:t.groupId})}async function reconstructValidated(r,t,e){let s;try{s=r.map(r=>(0,crypto_utils_js_1.fromBase64)((0,crypto_utils_js_1.parseShareHeader)(r.data)))}catch{return(0,shared_1.err)("INVALID_SHARE_DATA:BASE64")}const _=r.map(r=>r.index),o=r[0];let a,n;try{a=(0,crypto_utils_js_1.fromBase64)(o.hmacKey),n=(0,crypto_utils_js_1.fromBase64)(o.hmacSig)}catch{return(0,shared_1.err)("INVALID_SHARE_DATA:HMAC_DECODE")}try{const r=(0,crypto_utils_js_1.reconstructXorIDA)(s,_,t,e);if(!await(0,crypto_utils_js_1.verifyHMAC)(a,r,n))return(0,shared_1.err)("HMAC_VERIFICATION_FAILED");const o=(0,crypto_utils_js_1.nextOddPrime)(t)-1,i=(0,crypto_utils_js_1.pkcs7Unpad)(r,o);return i.ok?(0,shared_1.ok)(i.value):(0,shared_1.err)("UNPAD_FAILED")}catch(r){return(0,shared_1.err)("SPLIT_FAILED:CRYPTO_NOT_LOADED")}}exports.DEFAULT_SPLIT_CONFIG={totalShares:3,threshold:2};
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.HttpsTransportAdapter=void 0;const shared_1=require("../_deps/shared/index.js");class HttpsTransportAdapter{baseUrl;timeoutMs;fetchFn;handlers=[];constructor(t){if(!t.baseUrl||"string"!=typeof t.baseUrl)throw new TypeError("HttpsTransportOptions.baseUrl is required and must be a string");if(0===t.baseUrl.trim().length)throw new TypeError("HttpsTransportOptions.baseUrl cannot be empty");try{if("https:"!==new URL(t.baseUrl).protocol)throw new TypeError("HttpsTransportOptions.baseUrl must use HTTPS protocol")}catch(r){if(r instanceof TypeError&&r.message.includes("HTTPS protocol"))throw r;throw new TypeError(`HttpsTransportOptions.baseUrl is not a valid URL: ${t.baseUrl}`)}this.baseUrl=t.baseUrl.replace(/\/$/,""),this.timeoutMs=t.timeoutMs??1e4,this.fetchFn=t.fetch??globalThis.fetch.bind(globalThis)}async send(t,r){const e=`${this.baseUrl}/deliver/${encodeURIComponent(r)}`;try{const r=new AbortController,s=setTimeout(()=>r.abort(),this.timeoutMs),o=await this.fetchFn(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t),signal:r.signal});return clearTimeout(s),o.ok?(0,shared_1.ok)(void 0):(0,shared_1.err)(404===o.status?"RECIPIENT_UNREACHABLE":"SEND_FAILED")}catch(t){return t instanceof DOMException&&"AbortError"===t.name?(0,shared_1.err)("TIMEOUT"):(0,shared_1.err)("NETWORK_ERROR")}}onReceive(t){this.handlers.push(t)}dispatch(t){for(const r of this.handlers)r(t)}dispose(){this.handlers=[]}}exports.HttpsTransportAdapter=HttpsTransportAdapter;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.HttpsTransportAdapter=void 0;const shared_1=require("../_deps/shared/index.js");class HttpsTransportAdapter{baseUrl;timeoutMs;fetchFn;handlers=[];constructor(t){if(!t.baseUrl||"string"!=typeof t.baseUrl)throw new TypeError("HttpsTransportOptions.baseUrl is required and must be a string");if(0===t.baseUrl.trim().length)throw new TypeError("HttpsTransportOptions.baseUrl cannot be empty");this.baseUrl=t.baseUrl.replace(/\/$/,""),this.timeoutMs=t.timeoutMs??1e4,this.fetchFn=t.fetch??globalThis.fetch.bind(globalThis)}async send(t,e){try{const t=new URL(this.baseUrl),e=t.hostname.toLowerCase(),r="127.0.0.1"===e||"localhost"===e||"[::1]"===e||"::1"===e||e.startsWith("127.")||e.endsWith(".localhost");if("https:"!==t.protocol&&!r)return(0,shared_1.err)("HTTPS_REQUIRED")}catch{return(0,shared_1.err)("INVALID_URL")}const r=`${this.baseUrl}/deliver/${encodeURIComponent(e)}`;try{const e=new AbortController,s=setTimeout(()=>e.abort(),this.timeoutMs),o=await this.fetchFn(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t),signal:e.signal});return clearTimeout(s),o.ok?(0,shared_1.ok)(void 0):(0,shared_1.err)(404===o.status?"RECIPIENT_UNREACHABLE":"SEND_FAILED")}catch(t){return t instanceof DOMException&&"AbortError"===t.name?(0,shared_1.err)("TIMEOUT"):(0,shared_1.err)("NETWORK_ERROR")}}onReceive(t){this.handlers.push(t)}dispatch(t){for(const e of this.handlers)e(t)}dispose(){this.handlers=[]}}exports.HttpsTransportAdapter=HttpsTransportAdapter;
@@ -35,7 +35,7 @@ export interface ChannelShare {
35
35
  readonly hmacSig: string;
36
36
  }
37
37
  /** Error codes for split-channel operations. Sub-codes give context. */
38
- export type SplitChannelError = 'SPLIT_FAILED' | 'SPLIT_FAILED:INVALID_PARAMS' | 'SPLIT_FAILED:RECONSTRUCT' | 'INSUFFICIENT_SHARES' | 'INCONSISTENT_SHARES' | 'HMAC_VERIFICATION_FAILED' | 'UNPAD_FAILED' | 'INVALID_SHARE_DATA' | 'INVALID_SHARE_DATA:BASE64' | 'INVALID_SHARE_DATA:HMAC_DECODE';
38
+ export type SplitChannelError = 'SPLIT_FAILED' | 'SPLIT_FAILED:INVALID_PARAMS' | 'SPLIT_FAILED:RECONSTRUCT' | 'SPLIT_FAILED:CRYPTO_NOT_LOADED' | 'INSUFFICIENT_SHARES' | 'INCONSISTENT_SHARES' | 'HMAC_VERIFICATION_FAILED' | 'UNPAD_FAILED' | 'INVALID_SHARE_DATA' | 'INVALID_SHARE_DATA:BASE64' | 'INVALID_SHARE_DATA:HMAC_DECODE';
39
39
  /** Default split-channel configuration: 3 shares, threshold 2. */
40
40
  export declare const DEFAULT_SPLIT_CONFIG: SplitChannelConfig;
41
41
  /**
@@ -1 +1 @@
1
- import{ok,err}from"./_deps/shared/index.js";import{splitXorIDA,reconstructXorIDA,nextOddPrime,pkcs7Pad,pkcs7Unpad,generateHMAC,verifyHMAC,toBase64,fromBase64,generateUUID,formatShareHeader,parseShareHeader}from"./crypto-utils.js";export const DEFAULT_SPLIT_CONFIG={totalShares:3,threshold:2};export async function splitForChannel(r,e=DEFAULT_SPLIT_CONFIG){const{totalShares:t,threshold:n}=e;if(t<2||n<2||n>t)return err("SPLIT_FAILED:INVALID_PARAMS");return splitForChannelWithGroupId(r,e,generateUUID())}export async function splitForChannelWithGroupId(r,e,t){const{totalShares:n,threshold:a}=e;if(n<2||a<2||a>n)return err("SPLIT_FAILED:INVALID_PARAMS");const o=nextOddPrime(n),s=pkcs7Pad(r,o-1),{key:I,signature:c}=await generateHMAC(s);let i;try{i=splitXorIDA(s,n,a)}catch{return err("SPLIT_FAILED")}const A=toBase64(I),d=toBase64(c),u=i.map((r,e)=>({data:formatShareHeader(toBase64(r)),index:e,total:n,threshold:a,groupId:t,hmacKey:A,hmacSig:d}));return ok(u)}export async function reconstructFromChannel(r){const e=validateShares(r);if(!e.ok)return e;const{k:t,n:n}=e.value;return reconstructValidated(r.slice(0,t),n,t)}function validateShares(r){if(0===r.length)return err("INSUFFICIENT_SHARES");const e=r[0],t=e.threshold,n=e.total;if(r.length<t)return err("INSUFFICIENT_SHARES");const a=new Set;for(const o of r){if(o.groupId!==e.groupId)return err("INCONSISTENT_SHARES");if(o.total!==n||o.threshold!==t)return err("INCONSISTENT_SHARES");if(o.index<0||o.index>=n)return err("INVALID_SHARE_DATA");if(a.has(o.index))return err("INVALID_SHARE_DATA");a.add(o.index)}return ok({k:t,n:n,groupId:e.groupId})}async function reconstructValidated(r,e,t){let n;try{n=r.map(r=>fromBase64(parseShareHeader(r.data)))}catch{return err("INVALID_SHARE_DATA:BASE64")}const a=r.map(r=>r.index);let o;try{o=reconstructXorIDA(n,a,e,t)}catch{return err("SPLIT_FAILED:RECONSTRUCT")}const s=r[0];let I,c;try{I=fromBase64(s.hmacKey),c=fromBase64(s.hmacSig)}catch{return err("INVALID_SHARE_DATA:HMAC_DECODE")}if(!await verifyHMAC(I,o,c))return err("HMAC_VERIFICATION_FAILED");const i=nextOddPrime(e),A=pkcs7Unpad(o,i-1);return A.ok?ok(A.value):err("UNPAD_FAILED")}
1
+ import{ok,err}from"./_deps/shared/index.js";import{splitXorIDA,reconstructXorIDA,nextOddPrime,pkcs7Pad,pkcs7Unpad,generateHMAC,verifyHMAC,toBase64,fromBase64,generateUUID,formatShareHeader,parseShareHeader}from"./crypto-utils.js";export const DEFAULT_SPLIT_CONFIG={totalShares:3,threshold:2};export async function splitForChannel(r,e=DEFAULT_SPLIT_CONFIG){const{totalShares:t,threshold:n}=e;if(t<2||n<2||n>t)return err("SPLIT_FAILED:INVALID_PARAMS");return splitForChannelWithGroupId(r,e,generateUUID())}export async function splitForChannelWithGroupId(r,e,t){const{totalShares:n,threshold:a}=e;if(n<2||a<2||a>n)return err("SPLIT_FAILED:INVALID_PARAMS");let o,s,I;try{const e=nextOddPrime(n),t=pkcs7Pad(r,e-1),c=await generateHMAC(t);s=c.key,I=c.signature,o=splitXorIDA(t,n,a)}catch(r){return err("SPLIT_FAILED:CRYPTO_NOT_LOADED")}const c=toBase64(s),A=toBase64(I),i=o.map((r,e)=>({data:formatShareHeader(toBase64(r)),index:e,total:n,threshold:a,groupId:t,hmacKey:c,hmacSig:A}));return ok(i)}export async function reconstructFromChannel(r){const e=validateShares(r);if(!e.ok)return e;const{k:t,n:n}=e.value;return reconstructValidated(r.slice(0,t),n,t)}function validateShares(r){if(0===r.length)return err("INSUFFICIENT_SHARES");const e=r[0],t=e.threshold,n=e.total;if(r.length<t)return err("INSUFFICIENT_SHARES");const a=new Set;for(const o of r){if(o.groupId!==e.groupId)return err("INCONSISTENT_SHARES");if(o.total!==n||o.threshold!==t)return err("INCONSISTENT_SHARES");if(o.index<0||o.index>=n)return err("INVALID_SHARE_DATA");if(a.has(o.index))return err("INVALID_SHARE_DATA");a.add(o.index)}return ok({k:t,n:n,groupId:e.groupId})}async function reconstructValidated(r,e,t){let n;try{n=r.map(r=>fromBase64(parseShareHeader(r.data)))}catch{return err("INVALID_SHARE_DATA:BASE64")}const a=r.map(r=>r.index),o=r[0];let s,I;try{s=fromBase64(o.hmacKey),I=fromBase64(o.hmacSig)}catch{return err("INVALID_SHARE_DATA:HMAC_DECODE")}try{const r=reconstructXorIDA(n,a,e,t);if(!await verifyHMAC(s,r,I))return err("HMAC_VERIFICATION_FAILED");const o=nextOddPrime(e),c=pkcs7Unpad(r,o-1);return c.ok?ok(c.value):err("UNPAD_FAILED")}catch(r){return err("SPLIT_FAILED:CRYPTO_NOT_LOADED")}}
@@ -1,7 +1,7 @@
1
1
  import type { Result } from '@private.me/shared';
2
2
  import type { AnyTransportEnvelope } from './envelope.js';
3
3
  /** Transport-level error codes. */
4
- export type TransportError = 'SEND_FAILED' | 'NETWORK_ERROR' | 'RECIPIENT_UNREACHABLE' | 'TIMEOUT';
4
+ export type TransportError = 'SEND_FAILED' | 'NETWORK_ERROR' | 'RECIPIENT_UNREACHABLE' | 'TIMEOUT' | 'HTTPS_REQUIRED' | 'INVALID_URL';
5
5
  /** Handler invoked when an envelope is received. */
6
6
  export type EnvelopeHandler = (envelope: AnyTransportEnvelope) => void;
7
7
  /**
@@ -1 +1 @@
1
- import{ok,err}from"./_deps/shared/index.js";export class HttpsTransportAdapter{baseUrl;timeoutMs;fetchFn;handlers=[];constructor(t){if(!t.baseUrl||"string"!=typeof t.baseUrl)throw new TypeError("HttpsTransportOptions.baseUrl is required and must be a string");if(0===t.baseUrl.trim().length)throw new TypeError("HttpsTransportOptions.baseUrl cannot be empty");try{if("https:"!==new URL(t.baseUrl).protocol)throw new TypeError("HttpsTransportOptions.baseUrl must use HTTPS protocol")}catch(r){if(r instanceof TypeError&&r.message.includes("HTTPS protocol"))throw r;throw new TypeError(`HttpsTransportOptions.baseUrl is not a valid URL: ${t.baseUrl}`)}this.baseUrl=t.baseUrl.replace(/\/$/,""),this.timeoutMs=t.timeoutMs??1e4,this.fetchFn=t.fetch??globalThis.fetch.bind(globalThis)}async send(t,r){const e=`${this.baseUrl}/deliver/${encodeURIComponent(r)}`;try{const r=new AbortController,s=setTimeout(()=>r.abort(),this.timeoutMs),o=await this.fetchFn(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t),signal:r.signal});return clearTimeout(s),o.ok?ok(void 0):err(404===o.status?"RECIPIENT_UNREACHABLE":"SEND_FAILED")}catch(t){return t instanceof DOMException&&"AbortError"===t.name?err("TIMEOUT"):err("NETWORK_ERROR")}}onReceive(t){this.handlers.push(t)}dispatch(t){for(const r of this.handlers)r(t)}dispose(){this.handlers=[]}}
1
+ import{ok,err}from"./_deps/shared/index.js";export class HttpsTransportAdapter{baseUrl;timeoutMs;fetchFn;handlers=[];constructor(t){if(!t.baseUrl||"string"!=typeof t.baseUrl)throw new TypeError("HttpsTransportOptions.baseUrl is required and must be a string");if(0===t.baseUrl.trim().length)throw new TypeError("HttpsTransportOptions.baseUrl cannot be empty");this.baseUrl=t.baseUrl.replace(/\/$/,""),this.timeoutMs=t.timeoutMs??1e4,this.fetchFn=t.fetch??globalThis.fetch.bind(globalThis)}async send(t,e){try{const t=new URL(this.baseUrl),e=t.hostname.toLowerCase(),r="127.0.0.1"===e||"localhost"===e||"[::1]"===e||"::1"===e||e.startsWith("127.")||e.endsWith(".localhost");if("https:"!==t.protocol&&!r)return err("HTTPS_REQUIRED")}catch{return err("INVALID_URL")}const r=`${this.baseUrl}/deliver/${encodeURIComponent(e)}`;try{const e=new AbortController,s=setTimeout(()=>e.abort(),this.timeoutMs),o=await this.fetchFn(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t),signal:e.signal});return clearTimeout(s),o.ok?ok(void 0):err(404===o.status?"RECIPIENT_UNREACHABLE":"SEND_FAILED")}catch(t){return t instanceof DOMException&&"AbortError"===t.name?err("TIMEOUT"):err("NETWORK_ERROR")}}onReceive(t){this.handlers.push(t)}dispatch(t){for(const e of this.handlers)e(t)}dispose(){this.handlers=[]}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@private.me/xbind",
3
- "version": "3.0.3",
3
+ "version": "3.1.0",
4
4
  "description": "Identity-based M2M authentication (Contains encryption - export restrictions apply)",
5
5
  "license": "Proprietary",
6
6
  "author": "Private.Me Contributors",
@@ -83,6 +83,7 @@
83
83
  "!dist-standalone/_deps/crypto/**",
84
84
  "share1.dat",
85
85
  "README.md",
86
+ "MIGRATING.md",
86
87
  "LICENSE.md",
87
88
  "LICENSES.md",
88
89
  "AGENTS.md",
package/share1.dat CHANGED
Binary file