@private.me/xbind 3.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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.0-blue)
4
+ ![version](https://img.shields.io/badge/version-3.0.1-blue)
5
5
  ![tests](https://img.shields.io/badge/tests-2762%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,14 @@ 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.0** — **Major Features:** 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 v1.4.2: Runtime compatibility, API enhancements. Previous v1.3.5: ML-KEM deterministic key generation fix.
15
+ **Version 3.0.1** — **Major Features:** 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 v1.4.2: Runtime compatibility, API enhancements. Previous v1.3.5: ML-KEM deterministic key generation fix.
16
+
17
+ ## Pricing
18
+
19
+ **Free tier:** 100,000 operations/month (includes Vault Store access)
20
+ **Pro tier:** Unlimited operations
21
+
22
+ See [pricing](https://private.me/pricing) for current rates and purchase flow.
16
23
 
17
24
  ## Install
18
25
 
@@ -0,0 +1,84 @@
1
+ /**
2
+ * @module plugins/logging
3
+ * Logging plugin for xBind plugin system
4
+ *
5
+ * Captures send, receive, encrypt, and decrypt events for debugging and audit trails.
6
+ */
7
+ import type { Result } from '@private.me/shared';
8
+ import type { Plugin, PluginContext, HookResult } from '../plugin-system.js';
9
+ import type { AnyTransportEnvelope } from '../envelope.js';
10
+ /**
11
+ * Log level enum.
12
+ */
13
+ export declare enum LogLevel {
14
+ DEBUG = "debug",
15
+ INFO = "info",
16
+ WARN = "warn",
17
+ ERROR = "error"
18
+ }
19
+ /**
20
+ * Log entry structure.
21
+ */
22
+ export interface LogEntry {
23
+ timestamp: string;
24
+ level: LogLevel;
25
+ event: 'send' | 'receive' | 'encrypt' | 'decrypt';
26
+ agent: string;
27
+ recipient?: string;
28
+ scope?: string;
29
+ payloadSize?: number;
30
+ metadata?: Record<string, unknown>;
31
+ }
32
+ /**
33
+ * Logging plugin options.
34
+ */
35
+ export interface LoggingPluginOptions {
36
+ /** Log level threshold (default: INFO) */
37
+ level?: LogLevel;
38
+ /** Include payload sizes in logs (default: true) */
39
+ includeSize?: boolean;
40
+ /** Include metadata in logs (default: false) */
41
+ includeMetadata?: boolean;
42
+ /** Custom log handler (default: console.log) */
43
+ logHandler?: (entry: LogEntry) => void;
44
+ /** Filter function to exclude certain logs */
45
+ filter?: (entry: LogEntry) => boolean;
46
+ }
47
+ /**
48
+ * Logging plugin implementation.
49
+ * Captures all message processing events and outputs structured logs.
50
+ */
51
+ export declare class LoggingPlugin implements Plugin {
52
+ readonly name = "logging";
53
+ readonly version = "1.0.0";
54
+ readonly description = "Captures message processing events for debugging and audit trails";
55
+ readonly priority = 10;
56
+ private options;
57
+ private logs;
58
+ constructor(options?: LoggingPluginOptions);
59
+ onInit(): Result<void, string>;
60
+ onDestroy(): Result<void, string>;
61
+ onSend(payload: unknown, context: PluginContext): Result<HookResult<unknown>, string>;
62
+ onReceive(envelope: AnyTransportEnvelope, context: PluginContext): Result<HookResult<AnyTransportEnvelope>, string>;
63
+ onEncrypt(plaintext: Uint8Array, context: PluginContext): Result<HookResult<Uint8Array>, string>;
64
+ onDecrypt(plaintext: Uint8Array, context: PluginContext): Result<HookResult<Uint8Array>, string>;
65
+ /**
66
+ * Get all captured logs.
67
+ */
68
+ getLogs(): readonly LogEntry[];
69
+ /**
70
+ * Clear all logs.
71
+ */
72
+ clearLogs(): void;
73
+ /**
74
+ * Get logs filtered by criteria.
75
+ */
76
+ getFilteredLogs(filter: (entry: LogEntry) => boolean): LogEntry[];
77
+ private log;
78
+ private shouldLog;
79
+ private estimateSize;
80
+ }
81
+ /**
82
+ * Create a logging plugin with options.
83
+ */
84
+ export declare function createLoggingPlugin(options?: LoggingPluginOptions): LoggingPlugin;
@@ -0,0 +1 @@
1
+ import{ok}from"../_deps/shared/index.js";export var LogLevel;!function(e){e.DEBUG="debug",e.INFO="info",e.WARN="warn",e.ERROR="error"}(LogLevel||(LogLevel={}));export class LoggingPlugin{name="logging";version="1.0.0";description="Captures message processing events for debugging and audit trails";priority=10;options;logs=[];constructor(e={}){this.options={level:e.level??LogLevel.INFO,includeSize:e.includeSize??!0,includeMetadata:e.includeMetadata??!1,logHandler:e.logHandler??(e=>console.log(JSON.stringify(e))),filter:e.filter??(()=>!0)}}onInit(){return this.log({timestamp:(new Date).toISOString(),level:LogLevel.INFO,event:"send",agent:"system",metadata:{message:"Logging plugin initialized"}}),ok(void 0)}onDestroy(){return this.log({timestamp:(new Date).toISOString(),level:LogLevel.INFO,event:"send",agent:"system",metadata:{message:"Logging plugin destroyed",totalLogs:this.logs.length}}),this.logs=[],ok(void 0)}onSend(e,t){const i=this.options.includeSize?this.estimateSize(e):void 0;return this.log({timestamp:(new Date).toISOString(),level:LogLevel.INFO,event:"send",agent:t.agent.did,recipient:t.recipient,scope:t.scope,payloadSize:i,metadata:this.options.includeMetadata?t.metadata:void 0}),ok({payload:e})}onReceive(e,t){const i=this.options.includeSize?this.estimateSize(e):void 0;return this.log({timestamp:(new Date).toISOString(),level:LogLevel.INFO,event:"receive",agent:t.agent.did,recipient:e.sender,scope:t.scope,payloadSize:i,metadata:this.options.includeMetadata?t.metadata:void 0}),ok({payload:e})}onEncrypt(e,t){return this.log({timestamp:(new Date).toISOString(),level:LogLevel.DEBUG,event:"encrypt",agent:t.agent.did,recipient:t.recipient,scope:t.scope,payloadSize:this.options.includeSize?e.length:void 0,metadata:this.options.includeMetadata?t.metadata:void 0}),ok({payload:e})}onDecrypt(e,t){return this.log({timestamp:(new Date).toISOString(),level:LogLevel.DEBUG,event:"decrypt",agent:t.agent.did,scope:t.scope,payloadSize:this.options.includeSize?e.length:void 0,metadata:this.options.includeMetadata?t.metadata:void 0}),ok({payload:e})}getLogs(){return[...this.logs]}clearLogs(){this.logs=[]}getFilteredLogs(e){return this.logs.filter(e)}log(e){this.shouldLog(e.level)&&this.options.filter(e)&&(this.logs.push(e),this.options.logHandler(e))}shouldLog(e){const t=[LogLevel.DEBUG,LogLevel.INFO,LogLevel.WARN,LogLevel.ERROR],i=t.indexOf(this.options.level);return t.indexOf(e)>=i}estimateSize(e){if(e instanceof Uint8Array)return e.length;try{return JSON.stringify(e).length}catch{return 0}}}export function createLoggingPlugin(e){return new LoggingPlugin(e)}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * @module plugins/metrics
3
+ * Metrics plugin for xBind plugin system
4
+ *
5
+ * Tracks performance metrics, message counts, and error rates.
6
+ */
7
+ import type { Result } from '@private.me/shared';
8
+ import type { Plugin, PluginContext, HookResult } from '../plugin-system.js';
9
+ import type { AnyTransportEnvelope } from '../envelope.js';
10
+ /**
11
+ * Metric entry structure.
12
+ */
13
+ export interface MetricEntry {
14
+ timestamp: number;
15
+ event: 'send' | 'receive' | 'encrypt' | 'decrypt';
16
+ duration: number;
17
+ success: boolean;
18
+ error?: string;
19
+ metadata?: Record<string, unknown>;
20
+ }
21
+ /**
22
+ * Aggregated metrics.
23
+ */
24
+ export interface AggregatedMetrics {
25
+ /** Total number of send operations */
26
+ totalSends: number;
27
+ /** Total number of receive operations */
28
+ totalReceives: number;
29
+ /** Total number of encrypt operations */
30
+ totalEncrypts: number;
31
+ /** Total number of decrypt operations */
32
+ totalDecrypts: number;
33
+ /** Average send duration (ms) */
34
+ avgSendDuration: number;
35
+ /** Average receive duration (ms) */
36
+ avgReceiveDuration: number;
37
+ /** Average encrypt duration (ms) */
38
+ avgEncryptDuration: number;
39
+ /** Average decrypt duration (ms) */
40
+ avgDecryptDuration: number;
41
+ /** Total errors */
42
+ totalErrors: number;
43
+ /** Error rate (0-1) */
44
+ errorRate: number;
45
+ /** Uptime (ms) */
46
+ uptime: number;
47
+ }
48
+ /**
49
+ * Metrics plugin options.
50
+ */
51
+ export interface MetricsPluginOptions {
52
+ /** Enable high-resolution timing (default: true) */
53
+ highResolution?: boolean;
54
+ /** Maximum metrics to store in memory (default: 10000) */
55
+ maxMetrics?: number;
56
+ /** Metrics export callback */
57
+ onExport?: (metrics: MetricEntry[]) => void;
58
+ /** Export interval in milliseconds (default: 60000 - 1 minute) */
59
+ exportInterval?: number;
60
+ }
61
+ /**
62
+ * Metrics plugin implementation.
63
+ * Tracks performance and usage statistics for all operations.
64
+ */
65
+ export declare class MetricsPlugin implements Plugin {
66
+ readonly name = "metrics";
67
+ readonly version = "1.0.0";
68
+ readonly description = "Tracks performance metrics, message counts, and error rates";
69
+ readonly priority = 20;
70
+ private options;
71
+ private metrics;
72
+ private startTime;
73
+ private exportTimer?;
74
+ constructor(options?: MetricsPluginOptions);
75
+ onInit(): Result<void, string>;
76
+ onDestroy(): Result<void, string>;
77
+ onSend(payload: unknown, context: PluginContext): Result<HookResult<unknown>, string>;
78
+ onReceive(envelope: AnyTransportEnvelope, context: PluginContext): Result<HookResult<AnyTransportEnvelope>, string>;
79
+ onEncrypt(plaintext: Uint8Array, context: PluginContext): Result<HookResult<Uint8Array>, string>;
80
+ onDecrypt(plaintext: Uint8Array, context: PluginContext): Result<HookResult<Uint8Array>, string>;
81
+ /**
82
+ * Get all captured metrics.
83
+ */
84
+ getMetrics(): readonly MetricEntry[];
85
+ /**
86
+ * Get aggregated metrics summary.
87
+ */
88
+ getAggregatedMetrics(): AggregatedMetrics;
89
+ /**
90
+ * Clear all metrics.
91
+ */
92
+ clearMetrics(): void;
93
+ /**
94
+ * Export metrics using the configured callback.
95
+ */
96
+ export(): void;
97
+ /**
98
+ * Get metrics for a specific time range.
99
+ */
100
+ getMetricsInRange(startTime: number, endTime: number): MetricEntry[];
101
+ /**
102
+ * Get metrics for a specific event type.
103
+ */
104
+ getMetricsByEvent(event: 'send' | 'receive' | 'encrypt' | 'decrypt'): MetricEntry[];
105
+ private record;
106
+ private now;
107
+ }
108
+ /**
109
+ * Create a metrics plugin with options.
110
+ */
111
+ export declare function createMetricsPlugin(options?: MetricsPluginOptions): MetricsPlugin;
@@ -0,0 +1 @@
1
+ import{ok}from"../_deps/shared/index.js";export class MetricsPlugin{name="metrics";version="1.0.0";description="Tracks performance metrics, message counts, and error rates";priority=20;options;metrics=[];startTime=Date.now();exportTimer;constructor(t={}){this.options={highResolution:t.highResolution??!0,maxMetrics:t.maxMetrics??1e4,onExport:t.onExport??(()=>{}),exportInterval:t.exportInterval??6e4}}onInit(){return this.startTime=Date.now(),this.options.exportInterval>0&&(this.exportTimer=setInterval(()=>{this.export()},this.options.exportInterval)),ok(void 0)}onDestroy(){return this.exportTimer&&(clearInterval(this.exportTimer),this.exportTimer=void 0),this.export(),this.metrics=[],ok(void 0)}onSend(t,e){const r=this.now(),i=this.now();return this.record({timestamp:Date.now(),event:"send",duration:i-r,success:!0}),ok({payload:t})}onReceive(t,e){const r=this.now(),i=this.now();return this.record({timestamp:Date.now(),event:"receive",duration:i-r,success:!0}),ok({payload:t})}onEncrypt(t,e){const r=this.now(),i=this.now();return this.record({timestamp:Date.now(),event:"encrypt",duration:i-r,success:!0}),ok({payload:t})}onDecrypt(t,e){const r=this.now(),i=this.now();return this.record({timestamp:Date.now(),event:"decrypt",duration:i-r,success:!0}),ok({payload:t})}getMetrics(){return[...this.metrics]}getAggregatedMetrics(){const t=this.metrics.filter(t=>"send"===t.event),e=this.metrics.filter(t=>"receive"===t.event),r=this.metrics.filter(t=>"encrypt"===t.event),i=this.metrics.filter(t=>"decrypt"===t.event),s=this.metrics.filter(t=>!t.success),n=t=>0===t.length?0:t.reduce((t,e)=>t+e.duration,0)/t.length,o=this.metrics.length;return{totalSends:t.length,totalReceives:e.length,totalEncrypts:r.length,totalDecrypts:i.length,avgSendDuration:n(t),avgReceiveDuration:n(e),avgEncryptDuration:n(r),avgDecryptDuration:n(i),totalErrors:s.length,errorRate:o>0?s.length/o:0,uptime:Date.now()-this.startTime}}clearMetrics(){this.metrics=[],this.startTime=Date.now()}export(){this.metrics.length>0&&this.options.onExport([...this.metrics])}getMetricsInRange(t,e){return this.metrics.filter(r=>r.timestamp>=t&&r.timestamp<=e)}getMetricsByEvent(t){return this.metrics.filter(e=>e.event===t)}record(t){this.metrics.push(t),this.metrics.length>this.options.maxMetrics&&this.metrics.shift()}now(){return this.options.highResolution&&"undefined"!=typeof performance?performance.now():Date.now()}}export function createMetricsPlugin(t){return new MetricsPlugin(t)}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * @module plugins/validation
3
+ * Validation plugin for xBind plugin system
4
+ *
5
+ * Validates payloads, envelopes, and ensures data integrity before processing.
6
+ */
7
+ import type { Result } from '@private.me/shared';
8
+ import type { Plugin, PluginContext, HookResult } from '../plugin-system.js';
9
+ import type { AnyTransportEnvelope } from '../envelope.js';
10
+ /**
11
+ * Validation rule.
12
+ */
13
+ export interface ValidationRule {
14
+ /** Rule name */
15
+ name: string;
16
+ /** Validate function - returns error message on failure, null on success */
17
+ validate: (value: unknown, context: PluginContext) => string | null;
18
+ /** Apply to send operations */
19
+ appliesTo?: ('send' | 'receive' | 'encrypt' | 'decrypt')[];
20
+ }
21
+ /**
22
+ * Validation plugin options.
23
+ */
24
+ export interface ValidationPluginOptions {
25
+ /** Maximum payload size in bytes (default: 10MB) */
26
+ maxPayloadSize?: number;
27
+ /** Maximum envelope size in bytes (default: 15MB) */
28
+ maxEnvelopeSize?: number;
29
+ /** Allowed scopes (empty = all allowed) */
30
+ allowedScopes?: string[];
31
+ /** Custom validation rules */
32
+ customRules?: ValidationRule[];
33
+ /** Strict mode - reject any validation warning (default: false) */
34
+ strictMode?: boolean;
35
+ /** Enable payload schema validation (default: false) */
36
+ validateSchema?: boolean;
37
+ }
38
+ /**
39
+ * Validation plugin implementation.
40
+ * Validates all data before processing to ensure integrity and compliance.
41
+ */
42
+ export declare class ValidationPlugin implements Plugin {
43
+ readonly name = "validation";
44
+ readonly version = "1.0.0";
45
+ readonly description = "Validates payloads and envelopes before processing";
46
+ readonly priority = 5;
47
+ private options;
48
+ private validationErrors;
49
+ constructor(options?: ValidationPluginOptions);
50
+ onInit(): Result<void, string>;
51
+ onDestroy(): Result<void, string>;
52
+ onSend(payload: unknown, context: PluginContext): Result<HookResult<unknown>, string>;
53
+ onReceive(envelope: AnyTransportEnvelope, context: PluginContext): Result<HookResult<AnyTransportEnvelope>, string>;
54
+ onEncrypt(plaintext: Uint8Array, context: PluginContext): Result<HookResult<Uint8Array>, string>;
55
+ onDecrypt(plaintext: Uint8Array, context: PluginContext): Result<HookResult<Uint8Array>, string>;
56
+ /**
57
+ * Get all validation errors.
58
+ */
59
+ getValidationErrors(): ReadonlyArray<{
60
+ timestamp: number;
61
+ rule: string;
62
+ error: string;
63
+ }>;
64
+ /**
65
+ * Clear validation errors.
66
+ */
67
+ clearErrors(): void;
68
+ /**
69
+ * Add a custom validation rule.
70
+ */
71
+ addRule(rule: ValidationRule): void;
72
+ /**
73
+ * Remove a custom validation rule by name.
74
+ */
75
+ removeRule(name: string): boolean;
76
+ private validatePayloadSize;
77
+ private validateEnvelopeSize;
78
+ private validateScope;
79
+ private validatePayloadStructure;
80
+ private validateEnvelopeStructure;
81
+ private estimateSize;
82
+ private recordError;
83
+ }
84
+ /**
85
+ * Create a validation plugin with options.
86
+ */
87
+ export declare function createValidationPlugin(options?: ValidationPluginOptions): ValidationPlugin;
88
+ /**
89
+ * Common validation rules.
90
+ */
91
+ export declare const CommonRules: {
92
+ /**
93
+ * Validate payload contains required fields.
94
+ */
95
+ requireFields(fields: string[]): ValidationRule;
96
+ /**
97
+ * Validate DID format.
98
+ */
99
+ validateDIDFormat(): ValidationRule;
100
+ /**
101
+ * Validate timestamp is recent.
102
+ */
103
+ validateTimestamp(maxAgeMs?: number): ValidationRule;
104
+ };
@@ -0,0 +1 @@
1
+ import{ok,err}from"../_deps/shared/index.js";export class ValidationPlugin{name="validation";version="1.0.0";description="Validates payloads and envelopes before processing";priority=5;options;validationErrors=[];constructor(e={}){this.options={maxPayloadSize:e.maxPayloadSize??10485760,maxEnvelopeSize:e.maxEnvelopeSize??15728640,allowedScopes:e.allowedScopes??[],customRules:e.customRules??[],strictMode:e.strictMode??!1,validateSchema:e.validateSchema??!1}}onInit(){return ok(void 0)}onDestroy(){return this.validationErrors=[],ok(void 0)}onSend(e,r){const t=this.validatePayloadSize(e);if(!1===t.ok)return this.recordError("payload_size",t.error),err(t.error);if(r.scope){const e=this.validateScope(r.scope);if(!1===e.ok)return this.recordError("scope",e.error),err(e.error)}const o=this.validatePayloadStructure(e);if(!1===o.ok)return this.recordError("payload_structure",o.error),err(o.error);for(const t of this.options.customRules)if(!t.appliesTo||t.appliesTo.includes("send")){const o=t.validate(e,r);if(o)return this.recordError(t.name,o),err(`VALIDATION_FAILED:${t.name}:${o}`)}return ok({payload:e})}onReceive(e,r){const t=this.validateEnvelopeSize(e);if(!1===t.ok)return this.recordError("envelope_size",t.error),err(t.error);const o=this.validateEnvelopeStructure(e);if(!1===o.ok)return this.recordError("envelope_structure",o.error),err(o.error);for(const t of this.options.customRules)if(!t.appliesTo||t.appliesTo.includes("receive")){const o=t.validate(e,r);if(o)return this.recordError(t.name,o),err(`VALIDATION_FAILED:${t.name}:${o}`)}return ok({payload:e})}onEncrypt(e,r){if(0===e.length)return this.recordError("plaintext_empty","Plaintext cannot be empty"),err("VALIDATION_FAILED:PLAINTEXT_EMPTY");if(e.length>this.options.maxPayloadSize)return this.recordError("plaintext_size",`Plaintext exceeds max size: ${e.length} bytes`),err(`VALIDATION_FAILED:PLAINTEXT_TOO_LARGE:${e.length}`);for(const t of this.options.customRules)if(!t.appliesTo||t.appliesTo.includes("encrypt")){const o=t.validate(e,r);if(o)return this.recordError(t.name,o),err(`VALIDATION_FAILED:${t.name}:${o}`)}return ok({payload:e})}onDecrypt(e,r){if(0===e.length)return this.recordError("plaintext_empty","Decrypted plaintext is empty"),err("VALIDATION_FAILED:DECRYPTED_EMPTY");for(const t of this.options.customRules)if(!t.appliesTo||t.appliesTo.includes("decrypt")){const o=t.validate(e,r);if(o)return this.recordError(t.name,o),err(`VALIDATION_FAILED:${t.name}:${o}`)}return ok({payload:e})}getValidationErrors(){return[...this.validationErrors]}clearErrors(){this.validationErrors=[]}addRule(e){this.options.customRules.push(e)}removeRule(e){const r=this.options.customRules.findIndex(r=>r.name===e);return-1!==r&&(this.options.customRules.splice(r,1),!0)}validatePayloadSize(e){const r=this.estimateSize(e);return r>this.options.maxPayloadSize?err(`VALIDATION_FAILED:PAYLOAD_TOO_LARGE:${r}>${this.options.maxPayloadSize}`):ok(void 0)}validateEnvelopeSize(e){const r=this.estimateSize(e);return r>this.options.maxEnvelopeSize?err(`VALIDATION_FAILED:ENVELOPE_TOO_LARGE:${r}>${this.options.maxEnvelopeSize}`):ok(void 0)}validateScope(e){return this.options.allowedScopes.length>0&&!this.options.allowedScopes.includes(e)?err(`VALIDATION_FAILED:SCOPE_NOT_ALLOWED:${e}`):ok(void 0)}validatePayloadStructure(e){if(null==e)return err("VALIDATION_FAILED:PAYLOAD_NULL_OR_UNDEFINED");try{JSON.stringify(e)}catch(e){return err(`VALIDATION_FAILED:PAYLOAD_NOT_SERIALIZABLE:${String(e)}`)}return ok(void 0)}validateEnvelopeStructure(e){return"v"in e||"version"in e?e.sender?e.recipient?"payload"in e||"ciphertext"in e?ok(void 0):err("VALIDATION_FAILED:ENVELOPE_MISSING_CIPHERTEXT"):err("VALIDATION_FAILED:ENVELOPE_MISSING_RECIPIENT"):err("VALIDATION_FAILED:ENVELOPE_MISSING_SENDER"):err("VALIDATION_FAILED:ENVELOPE_MISSING_VERSION")}estimateSize(e){if(e instanceof Uint8Array)return e.length;try{return JSON.stringify(e).length}catch{return 0}}recordError(e,r){this.validationErrors.push({timestamp:Date.now(),rule:e,error:r}),this.validationErrors.length>1e3&&this.validationErrors.shift()}}export function createValidationPlugin(e){return new ValidationPlugin(e)}export const CommonRules={requireFields:e=>({name:"require_fields",appliesTo:["send"],validate:r=>{if("object"!=typeof r||null===r)return"Payload must be an object";const t=r,o=e.filter(e=>!(e in t));return o.length>0?`Missing required fields: ${o.join(", ")}`:null}}),validateDIDFormat:()=>({name:"did_format",appliesTo:["send","receive"],validate:(e,r)=>r.recipient&&!r.recipient.startsWith("did:")?`Invalid DID format: ${r.recipient}`:null}),validateTimestamp:(e=3e5)=>({name:"timestamp_freshness",appliesTo:["receive"],validate:(r,t)=>{const o=Date.now()-t.timestamp;return o>e?`Timestamp too old: ${o}ms > ${e}ms`:null}})};
@@ -0,0 +1,311 @@
1
+ /**
2
+ * Browser Runtime Compatibility Layer
3
+ *
4
+ * Provides polyfills and runtime detection for browser environments.
5
+ * Ensures xBind works seamlessly in Chrome, Firefox, Safari, and service workers.
6
+ *
7
+ * @module runtime/browser
8
+ * @packageDocumentation
9
+ */
10
+ import type { Result } from '@private.me/shared';
11
+ /**
12
+ * Runtime environment type.
13
+ */
14
+ export type RuntimeEnvironment = 'browser' | 'node' | 'service-worker' | 'web-worker' | 'unknown';
15
+ /**
16
+ * Detect the current runtime environment.
17
+ *
18
+ * @returns The detected runtime environment type
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * import { detectRuntime } from '@private.me/xbind/runtime/browser';
23
+ *
24
+ * const runtime = detectRuntime();
25
+ * console.log('Running in:', runtime);
26
+ * // => 'browser' | 'node' | 'service-worker' | 'web-worker' | 'unknown'
27
+ * ```
28
+ */
29
+ export declare function detectRuntime(): RuntimeEnvironment;
30
+ /**
31
+ * Check if running in a browser environment.
32
+ *
33
+ * @returns True if running in browser, service worker, or web worker
34
+ */
35
+ export declare function isBrowser(): boolean;
36
+ /**
37
+ * Check if running in Node.js environment.
38
+ *
39
+ * @returns True if running in Node.js
40
+ */
41
+ export declare function isNode(): boolean;
42
+ /**
43
+ * Check if running in a service worker.
44
+ *
45
+ * @returns True if running in service worker context
46
+ */
47
+ export declare function isServiceWorker(): boolean;
48
+ /**
49
+ * Browser-compatible random bytes generator.
50
+ * Uses Web Crypto API's getRandomValues.
51
+ *
52
+ * @param length - Number of random bytes to generate
53
+ * @returns Uint8Array of cryptographically secure random bytes
54
+ *
55
+ * @throws {Error} If Web Crypto API is not available
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * import { getRandomBytes } from '@private.me/xbind/runtime/browser';
60
+ *
61
+ * const nonce = getRandomBytes(16);
62
+ * console.log('Random nonce:', nonce);
63
+ * ```
64
+ */
65
+ export declare function getRandomBytes(length: number): Uint8Array;
66
+ /**
67
+ * Generate a cryptographically secure random UUID.
68
+ * Uses Web Crypto API's randomUUID if available, falls back to manual generation.
69
+ *
70
+ * @returns UUID v4 string (e.g., "550e8400-e29b-41d4-a716-446655440000")
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * import { generateUUID } from '@private.me/xbind/runtime/browser';
75
+ *
76
+ * const id = generateUUID();
77
+ * console.log('Generated UUID:', id);
78
+ * ```
79
+ */
80
+ export declare function generateUUID(): string;
81
+ /**
82
+ * Browser storage interface for persisting agent identity and state.
83
+ */
84
+ export interface BrowserStorage {
85
+ /**
86
+ * Store a value.
87
+ * @param key - Storage key
88
+ * @param value - Value to store (will be JSON serialized)
89
+ */
90
+ setItem(key: string, value: unknown): Promise<void>;
91
+ /**
92
+ * Retrieve a value.
93
+ * @param key - Storage key
94
+ * @returns Stored value or null if not found
95
+ */
96
+ getItem<T = unknown>(key: string): Promise<T | null>;
97
+ /**
98
+ * Remove a value.
99
+ * @param key - Storage key
100
+ */
101
+ removeItem(key: string): Promise<void>;
102
+ /**
103
+ * Clear all stored values.
104
+ */
105
+ clear(): Promise<void>;
106
+ }
107
+ /**
108
+ * LocalStorage-based implementation of BrowserStorage.
109
+ * Suitable for browser environments with persistent storage needs.
110
+ */
111
+ export declare class LocalStorageAdapter implements BrowserStorage {
112
+ private prefix;
113
+ /**
114
+ * Create a new LocalStorage adapter.
115
+ *
116
+ * @param prefix - Key prefix to avoid collisions (default: 'xbind:')
117
+ */
118
+ constructor(prefix?: string);
119
+ setItem(key: string, value: unknown): Promise<void>;
120
+ getItem<T = unknown>(key: string): Promise<T | null>;
121
+ removeItem(key: string): Promise<void>;
122
+ clear(): Promise<void>;
123
+ }
124
+ /**
125
+ * IndexedDB-based implementation of BrowserStorage.
126
+ * Suitable for larger datasets and service workers.
127
+ */
128
+ export declare class IndexedDBAdapter implements BrowserStorage {
129
+ private dbName;
130
+ private storeName;
131
+ private version;
132
+ private db;
133
+ /**
134
+ * Create a new IndexedDB adapter.
135
+ *
136
+ * @param dbName - Database name (default: 'xbind-storage')
137
+ * @param storeName - Object store name (default: 'keyval')
138
+ * @param version - Database version (default: 1)
139
+ */
140
+ constructor(dbName?: string, storeName?: string, version?: number);
141
+ /**
142
+ * Initialize the database connection.
143
+ * Called automatically by storage operations.
144
+ */
145
+ private ensureDB;
146
+ setItem(key: string, value: unknown): Promise<void>;
147
+ getItem<T = unknown>(key: string): Promise<T | null>;
148
+ removeItem(key: string): Promise<void>;
149
+ clear(): Promise<void>;
150
+ /**
151
+ * Close the database connection.
152
+ * Should be called when storage is no longer needed.
153
+ */
154
+ close(): void;
155
+ }
156
+ /**
157
+ * In-memory storage implementation for testing and ephemeral use cases.
158
+ */
159
+ export declare class MemoryStorageAdapter implements BrowserStorage {
160
+ private store;
161
+ setItem(key: string, value: unknown): Promise<void>;
162
+ getItem<T = unknown>(key: string): Promise<T | null>;
163
+ removeItem(key: string): Promise<void>;
164
+ clear(): Promise<void>;
165
+ }
166
+ /**
167
+ * Error codes for WASM operations.
168
+ */
169
+ export type WasmError = 'WASM_NOT_SUPPORTED' | 'WASM_LOAD_FAILED' | 'WASM_INIT_FAILED';
170
+ /**
171
+ * Check if WebAssembly is supported in the current environment.
172
+ *
173
+ * @returns True if WebAssembly is supported
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * import { isWasmSupported } from '@private.me/xbind/runtime/browser';
178
+ *
179
+ * if (isWasmSupported()) {
180
+ * console.log('WASM is supported - using post-quantum crypto');
181
+ * } else {
182
+ * console.log('WASM not supported - falling back to classical crypto');
183
+ * }
184
+ * ```
185
+ */
186
+ export declare function isWasmSupported(): boolean;
187
+ /**
188
+ * Load and instantiate a WebAssembly module from a URL.
189
+ *
190
+ * @param url - URL to WASM module
191
+ * @param importObject - Optional imports for WASM module
192
+ * @returns Result containing the WASM instance or error
193
+ *
194
+ * @example
195
+ * ```typescript
196
+ * import { loadWasmModule } from '@private.me/xbind/runtime/browser';
197
+ *
198
+ * const result = await loadWasmModule('/mldsa.wasm');
199
+ * if (!result.ok) {
200
+ * console.error('Failed to load WASM:', result.error);
201
+ * return;
202
+ * }
203
+ *
204
+ * const instance = result.value;
205
+ * // Use WASM exports...
206
+ * ```
207
+ */
208
+ export declare function loadWasmModule(url: string, importObject?: WebAssembly.Imports): Promise<Result<WebAssembly.Instance, WasmError>>;
209
+ /**
210
+ * Browser capabilities and feature support.
211
+ */
212
+ export interface BrowserCapabilities {
213
+ /** WebCrypto API available */
214
+ webCrypto: boolean;
215
+ /** SubtleCrypto API available */
216
+ subtleCrypto: boolean;
217
+ /** Ed25519 support in WebCrypto */
218
+ ed25519: boolean;
219
+ /** X25519 support in WebCrypto */
220
+ x25519: boolean;
221
+ /** WebAssembly support */
222
+ wasm: boolean;
223
+ /** IndexedDB support */
224
+ indexedDB: boolean;
225
+ /** LocalStorage support */
226
+ localStorage: boolean;
227
+ /** Service Worker support */
228
+ serviceWorker: boolean;
229
+ /** Web Worker support */
230
+ webWorker: boolean;
231
+ /** Fetch API support */
232
+ fetch: boolean;
233
+ /** TextEncoder/TextDecoder support */
234
+ textEncoding: boolean;
235
+ }
236
+ /**
237
+ * Detect browser capabilities and feature support.
238
+ *
239
+ * @returns Object describing available browser features
240
+ *
241
+ * @example
242
+ * ```typescript
243
+ * import { detectCapabilities } from '@private.me/xbind/runtime/browser';
244
+ *
245
+ * const caps = await detectCapabilities();
246
+ *
247
+ * if (!caps.webCrypto) {
248
+ * throw new Error('WebCrypto required for xBind');
249
+ * }
250
+ *
251
+ * if (!caps.ed25519) {
252
+ * console.warn('Ed25519 not supported - using polyfill');
253
+ * }
254
+ *
255
+ * if (caps.serviceWorker) {
256
+ * console.log('Service workers supported - can run in background');
257
+ * }
258
+ * ```
259
+ */
260
+ export declare function detectCapabilities(): Promise<BrowserCapabilities>;
261
+ /**
262
+ * Install Node.js compatibility shims for browser environments.
263
+ * Only installs missing APIs - does not override existing implementations.
264
+ *
265
+ * @example
266
+ * ```typescript
267
+ * import { installNodePolyfills } from '@private.me/xbind/runtime/browser';
268
+ *
269
+ * // Install polyfills at application startup
270
+ * installNodePolyfills();
271
+ *
272
+ * // Now Node.js-style code works in browser
273
+ * import { randomBytes } from 'crypto'; // Works!
274
+ * ```
275
+ */
276
+ export declare function installNodePolyfills(): void;
277
+ /**
278
+ * Configuration for service worker compatibility mode.
279
+ */
280
+ export interface ServiceWorkerConfig {
281
+ /** Cache strategy for WASM modules */
282
+ wasmCacheStrategy: 'cache-first' | 'network-first' | 'no-cache';
283
+ /** Maximum age for cached WASM modules (milliseconds) */
284
+ wasmCacheMaxAge: number;
285
+ /** Enable background sync for pending messages */
286
+ enableBackgroundSync: boolean;
287
+ }
288
+ /**
289
+ * Default service worker configuration.
290
+ */
291
+ export declare const DEFAULT_SERVICE_WORKER_CONFIG: ServiceWorkerConfig;
292
+ /**
293
+ * Initialize xBind for service worker environment.
294
+ * Sets up caching strategies and background sync handlers.
295
+ *
296
+ * @param config - Service worker configuration
297
+ *
298
+ * @example
299
+ * ```typescript
300
+ * // In your service worker (sw.js):
301
+ * import { initServiceWorker } from '@private.me/xbind/runtime/browser';
302
+ *
303
+ * initServiceWorker({
304
+ * wasmCacheStrategy: 'cache-first',
305
+ * wasmCacheMaxAge: 24 * 60 * 60 * 1000,
306
+ * enableBackgroundSync: true,
307
+ * });
308
+ * ```
309
+ */
310
+ export declare function initServiceWorker(config?: Partial<ServiceWorkerConfig>): void;
311
+ export type { Result, };
@@ -0,0 +1 @@
1
+ import{ok,err}from"../_deps/shared/index.js";export function detectRuntime(){return"undefined"!=typeof self&&"ServiceWorkerGlobalScope"in self?"service-worker":"undefined"!=typeof self&&"WorkerGlobalScope"in self&&"importScripts"in self?"web-worker":"undefined"!=typeof window&&"undefined"!=typeof document?"browser":"undefined"!=typeof process&&process.versions&&process.versions.node?"node":"unknown"}export function isBrowser(){const e=detectRuntime();return"browser"===e||"service-worker"===e||"web-worker"===e}export function isNode(){return"node"===detectRuntime()}export function isServiceWorker(){return"service-worker"===detectRuntime()}export function getRandomBytes(e){if("undefined"==typeof crypto||!crypto.getRandomValues)throw new Error("Web Crypto API not available - secure random generation impossible");const t=new Uint8Array(e);return crypto.getRandomValues(t),t}export function generateUUID(){if("undefined"!=typeof crypto&&crypto.randomUUID)return crypto.randomUUID();const e=getRandomBytes(16),t=e[6],r=e[8];void 0!==t&&(e[6]=15&t|64),void 0!==r&&(e[8]=63&r|128);const o=Array.from(e).map(e=>e.toString(16).padStart(2,"0")).join("");return[o.slice(0,8),o.slice(8,12),o.slice(12,16),o.slice(16,20),o.slice(20,32)].join("-")}export class LocalStorageAdapter{prefix;constructor(e="xbind:"){if(this.prefix=e,"undefined"==typeof localStorage)throw new Error("localStorage not available in this environment")}async setItem(e,t){const r=this.prefix+e,o=JSON.stringify(t);localStorage.setItem(r,o)}async getItem(e){const t=this.prefix+e,r=localStorage.getItem(t);if(null===r)return null;try{return JSON.parse(r)}catch{return null}}async removeItem(e){const t=this.prefix+e;localStorage.removeItem(t)}async clear(){Object.keys(localStorage).filter(e=>e.startsWith(this.prefix)).forEach(e=>localStorage.removeItem(e))}}export class IndexedDBAdapter{dbName;storeName;version;db=null;constructor(e="xbind-storage",t="keyval",r=1){this.dbName=e,this.storeName=t,this.version=r}async ensureDB(){return this.db?this.db:new Promise((e,t)=>{const r=indexedDB.open(this.dbName,this.version);r.onerror=()=>t(r.error),r.onsuccess=()=>{this.db=r.result,e(r.result)},r.onupgradeneeded=e=>{const t=e.target.result;t.objectStoreNames.contains(this.storeName)||t.createObjectStore(this.storeName)}})}async setItem(e,t){const r=(await this.ensureDB()).transaction(this.storeName,"readwrite").objectStore(this.storeName);return new Promise((o,n)=>{const s=r.put(t,e);s.onerror=()=>n(s.error),s.onsuccess=()=>o()})}async getItem(e){const t=(await this.ensureDB()).transaction(this.storeName,"readonly").objectStore(this.storeName);return new Promise((r,o)=>{const n=t.get(e);n.onerror=()=>o(n.error),n.onsuccess=()=>{const e=n.result;r(void 0===e?null:e)}})}async removeItem(e){const t=(await this.ensureDB()).transaction(this.storeName,"readwrite").objectStore(this.storeName);return new Promise((r,o)=>{const n=t.delete(e);n.onerror=()=>o(n.error),n.onsuccess=()=>r()})}async clear(){const e=(await this.ensureDB()).transaction(this.storeName,"readwrite").objectStore(this.storeName);return new Promise((t,r)=>{const o=e.clear();o.onerror=()=>r(o.error),o.onsuccess=()=>t()})}close(){this.db&&(this.db.close(),this.db=null)}}export class MemoryStorageAdapter{store=new Map;async setItem(e,t){this.store.set(e,t)}async getItem(e){const t=this.store.get(e);return void 0===t?null:t}async removeItem(e){this.store.delete(e)}async clear(){this.store.clear()}}export function isWasmSupported(){try{if("undefined"==typeof WebAssembly)return!1;const e=new WebAssembly.Module(new Uint8Array([0,97,115,109,1,0,0,0]));if(!(e instanceof WebAssembly.Module))return!1;return new WebAssembly.Instance(e)instanceof WebAssembly.Instance}catch{return!1}}export async function loadWasmModule(e,t){if(!isWasmSupported())return err("WASM_NOT_SUPPORTED");try{if(void 0!==WebAssembly.instantiateStreaming){const r=await fetch(e),o=await WebAssembly.instantiateStreaming(r,t);return ok(o.instance)}const r=await fetch(e),o=await r.arrayBuffer(),n=await WebAssembly.instantiate(o,t);return ok(n.instance)}catch(e){return console.error("WASM load failed:",e),err("WASM_LOAD_FAILED")}}export async function detectCapabilities(){const e={webCrypto:"undefined"!=typeof crypto&&!!crypto.subtle,subtleCrypto:"undefined"!=typeof crypto&&!!crypto.subtle,ed25519:!1,x25519:!1,wasm:isWasmSupported(),indexedDB:"undefined"!=typeof indexedDB,localStorage:"undefined"!=typeof localStorage,serviceWorker:"undefined"!=typeof navigator&&"serviceWorker"in navigator,webWorker:"undefined"!=typeof Worker,fetch:"undefined"!=typeof fetch,textEncoding:"undefined"!=typeof TextEncoder&&"undefined"!=typeof TextDecoder};if(e.subtleCrypto)try{await crypto.subtle.generateKey({name:"Ed25519"},!0,["sign","verify"]),e.ed25519=!0}catch{e.ed25519=!1}if(e.subtleCrypto)try{await crypto.subtle.generateKey({name:"X25519"},!0,["deriveBits"]),e.x25519=!0}catch{e.x25519=!1}return e}export function installNodePolyfills(){isBrowser()&&(void 0===globalThis.process&&(globalThis.process={env:{},versions:{},nextTick:e=>Promise.resolve().then(e)}),void 0===globalThis.Buffer&&(globalThis.Buffer={from:(e,t)=>{if(e instanceof Uint8Array)return e;if("base64"===t){const t=atob(e);return new Uint8Array(t.split("").map(e=>e.charCodeAt(0)))}return(new TextEncoder).encode(e)},alloc:e=>new Uint8Array(e)}),void 0===globalThis.global&&(globalThis.global=globalThis))}export const DEFAULT_SERVICE_WORKER_CONFIG={wasmCacheStrategy:"cache-first",wasmCacheMaxAge:864e5,enableBackgroundSync:!0};export function initServiceWorker(e={}){const t={...DEFAULT_SERVICE_WORKER_CONFIG,...e};if(!isServiceWorker())throw new Error("initServiceWorker() must be called from service worker context");self.__xbind_sw_config=t,console.log("[xBind] Service worker initialized with config:",t)}