@epochcore/qaas-sdk 1.0.0 → 1.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/dist/index.mjs CHANGED
@@ -1,86 +1,232 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
1
8
  // src/index.ts
9
+ var SDK_VERSION = "1.1.0";
10
+ var SDK_USER_AGENT = `EpochCore-QaaS-SDK/${SDK_VERSION}`;
11
+ var _crypto = typeof globalThis.crypto !== "undefined" ? globalThis.crypto : __require("crypto").webcrypto;
12
+ var MIN_TIMEOUT_MS = 5e3;
13
+ var MAX_TIMEOUT_MS = 12e4;
14
+ var DEFAULT_TIMEOUT_MS = 3e4;
15
+ var SIGNATURE_MAX_AGE_MS = 3e5;
16
+ var DEFAULT_RATE_LIMIT = 10;
17
+ var DEFAULT_RATE_BURST = 20;
18
+ var MAX_BODY_SIZE = 1048576;
19
+ var MAX_SHOTS = 1e5;
20
+ var MIN_SHOTS = 1;
21
+ var MAX_ALGORITHM_ID_LENGTH = 64;
22
+ var MAX_RETRY_ATTEMPTS = 3;
23
+ var RETRY_BASE_MS = 500;
24
+ var VALID_BACKENDS = /* @__PURE__ */ new Set([
25
+ "simulator",
26
+ "qiskit_aer",
27
+ "cirq",
28
+ "pennylane",
29
+ "ibm_quantum"
30
+ ]);
31
+ var TokenBucket = class {
32
+ constructor(capacity, refillRate) {
33
+ this.capacity = capacity;
34
+ this.refillRate = refillRate;
35
+ this.tokens = capacity;
36
+ this.lastRefill = Date.now();
37
+ }
38
+ tryConsume() {
39
+ this.refill();
40
+ if (this.tokens >= 1) {
41
+ this.tokens -= 1;
42
+ return true;
43
+ }
44
+ return false;
45
+ }
46
+ refill() {
47
+ const now = Date.now();
48
+ const elapsed = (now - this.lastRefill) / 1e3;
49
+ this.tokens = Math.min(this.capacity, this.tokens + elapsed * this.refillRate);
50
+ this.lastRefill = now;
51
+ }
52
+ };
53
+ async function hmacSign(secret, message) {
54
+ const enc = new TextEncoder();
55
+ const key = await _crypto.subtle.importKey(
56
+ "raw",
57
+ enc.encode(secret),
58
+ { name: "HMAC", hash: "SHA-256" },
59
+ false,
60
+ ["sign"]
61
+ );
62
+ const sig = await _crypto.subtle.sign("HMAC", key, enc.encode(message));
63
+ return Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("");
64
+ }
65
+ function generateNonce() {
66
+ const bytes = new Uint8Array(16);
67
+ _crypto.getRandomValues(bytes);
68
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
69
+ }
70
+ function validateRunRequest(req) {
71
+ if (!req.algorithm_id || typeof req.algorithm_id !== "string") {
72
+ throw new QaaSValidationError("algorithm_id is required and must be a string");
73
+ }
74
+ if (req.algorithm_id.length > MAX_ALGORITHM_ID_LENGTH) {
75
+ throw new QaaSValidationError(`algorithm_id exceeds max length of ${MAX_ALGORITHM_ID_LENGTH}`);
76
+ }
77
+ if (!/^[A-Z0-9_]+$/.test(req.algorithm_id)) {
78
+ throw new QaaSValidationError("algorithm_id must contain only uppercase letters, digits, and underscores");
79
+ }
80
+ if (req.backend !== void 0) {
81
+ if (!VALID_BACKENDS.has(req.backend)) {
82
+ throw new QaaSValidationError(
83
+ `Invalid backend "${req.backend}". Must be one of: ${[...VALID_BACKENDS].join(", ")}`
84
+ );
85
+ }
86
+ }
87
+ if (req.shots !== void 0) {
88
+ if (typeof req.shots !== "number" || !Number.isInteger(req.shots)) {
89
+ throw new QaaSValidationError("shots must be an integer");
90
+ }
91
+ if (req.shots < MIN_SHOTS || req.shots > MAX_SHOTS) {
92
+ throw new QaaSValidationError(`shots must be between ${MIN_SHOTS} and ${MAX_SHOTS}`);
93
+ }
94
+ }
95
+ if (!req.parameters || typeof req.parameters !== "object" || Array.isArray(req.parameters)) {
96
+ throw new QaaSValidationError("parameters must be a non-null object");
97
+ }
98
+ const serialized = JSON.stringify(req.parameters);
99
+ if (serialized.length > MAX_BODY_SIZE) {
100
+ throw new QaaSValidationError(`parameters exceed max size of ${MAX_BODY_SIZE} bytes`);
101
+ }
102
+ }
2
103
  var QaaSClient = class {
3
104
  constructor(config = {}) {
4
- this.baseUrl = config.baseUrl || "https://api.qaas.epochcoreqcs.com";
105
+ this.baseUrl = (config.baseUrl || "https://api.qaas.epochcoreqcs.com").replace(/\/+$/, "");
5
106
  this.apiKey = config.apiKey;
6
- this.timeout = config.timeout || 3e4;
107
+ this.apiSecret = config.apiSecret;
108
+ this.enableSigning = config.enableSigning ?? !!config.apiSecret;
109
+ this.maxRetries = Math.min(Math.max(config.maxRetries ?? MAX_RETRY_ATTEMPTS, 0), 5);
110
+ const raw = config.timeout ?? DEFAULT_TIMEOUT_MS;
111
+ this.timeout = Math.min(Math.max(raw, MIN_TIMEOUT_MS), MAX_TIMEOUT_MS);
112
+ this.rateLimiter = new TokenBucket(
113
+ config.rateBurst ?? DEFAULT_RATE_BURST,
114
+ config.rateLimit ?? DEFAULT_RATE_LIMIT
115
+ );
7
116
  }
8
- async request(path, options = {}) {
117
+ async request(method, path, body) {
118
+ if (!this.rateLimiter.tryConsume()) {
119
+ throw new QaaSRateLimitError("Client-side rate limit exceeded. Wait and retry.");
120
+ }
121
+ if (body && body.length > MAX_BODY_SIZE) {
122
+ throw new QaaSValidationError(`Request body exceeds max size of ${MAX_BODY_SIZE} bytes`);
123
+ }
124
+ const requestId = generateNonce();
125
+ const timestamp = Date.now().toString();
9
126
  const headers = {
10
127
  "Content-Type": "application/json",
11
- ...options.headers || {}
128
+ "User-Agent": SDK_USER_AGENT,
129
+ "X-Request-Id": requestId,
130
+ "X-Timestamp": timestamp
12
131
  };
13
132
  if (this.apiKey) {
14
133
  headers["X-API-Key"] = this.apiKey;
15
134
  }
16
- const controller = new AbortController();
17
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
18
- try {
19
- const response = await fetch(`${this.baseUrl}${path}`, {
20
- ...options,
21
- headers,
22
- signal: controller.signal
23
- });
24
- if (!response.ok) {
25
- const error = await response.json().catch(() => ({ error: "Unknown error" }));
26
- throw new QaaSError(
27
- error.error || `Request failed with status ${response.status}`,
28
- response.status,
29
- error
135
+ if (this.enableSigning && this.apiSecret) {
136
+ const nonce = generateNonce();
137
+ const sigPayload = [method, path, timestamp, nonce, body || ""].join("\n");
138
+ const signature = await hmacSign(this.apiSecret, sigPayload);
139
+ headers["X-Signature"] = signature;
140
+ headers["X-Nonce"] = nonce;
141
+ }
142
+ let lastError;
143
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
144
+ if (attempt > 0) {
145
+ const delay = RETRY_BASE_MS * Math.pow(2, attempt - 1);
146
+ const jitter = Math.random() * delay * 0.5;
147
+ await new Promise((r) => setTimeout(r, delay + jitter));
148
+ }
149
+ const controller = new AbortController();
150
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
151
+ try {
152
+ const response = await fetch(`${this.baseUrl}${path}`, {
153
+ method,
154
+ headers,
155
+ body: body || void 0,
156
+ signal: controller.signal
157
+ });
158
+ if (response.status === 429 && attempt < this.maxRetries) {
159
+ const retryAfter = response.headers.get("Retry-After");
160
+ if (retryAfter) {
161
+ await new Promise((r) => setTimeout(r, parseInt(retryAfter, 10) * 1e3));
162
+ }
163
+ lastError = new QaaSError("Rate limited by server", 429);
164
+ continue;
165
+ }
166
+ if ([502, 503, 504].includes(response.status) && attempt < this.maxRetries) {
167
+ lastError = new QaaSError(`Server error ${response.status}`, response.status);
168
+ continue;
169
+ }
170
+ if (!response.ok) {
171
+ const error = await response.json().catch(() => ({}));
172
+ throw new QaaSError(
173
+ typeof error.error === "string" ? error.error : `Request failed (${response.status})`,
174
+ response.status
175
+ );
176
+ }
177
+ return await response.json();
178
+ } catch (err) {
179
+ if (err instanceof QaaSError) throw err;
180
+ if (err instanceof QaaSValidationError) throw err;
181
+ if (err instanceof DOMException && err.name === "AbortError") {
182
+ lastError = new QaaSError(`Request timed out after ${this.timeout}ms`, 408);
183
+ if (attempt < this.maxRetries) continue;
184
+ throw lastError;
185
+ }
186
+ lastError = new QaaSError(
187
+ err instanceof Error ? err.message : "Network error",
188
+ 0
30
189
  );
190
+ if (attempt < this.maxRetries) continue;
191
+ } finally {
192
+ clearTimeout(timeoutId);
31
193
  }
32
- return await response.json();
33
- } finally {
34
- clearTimeout(timeoutId);
35
194
  }
195
+ throw lastError ?? new QaaSError("Request failed after retries", 0);
36
196
  }
37
- /**
38
- * Check API health and status
39
- */
197
+ // ═══════════════════════════════════════════════════════════════════
198
+ // API Methods
199
+ // ═══════════════════════════════════════════════════════════════════
40
200
  async health() {
41
- return this.request("/health");
201
+ return this.request("GET", "/health");
42
202
  }
43
- /**
44
- * Get pricing information for all tiers
45
- */
46
203
  async getPricing() {
47
- return this.request("/api/pricing");
204
+ return this.request("GET", "/api/pricing");
48
205
  }
49
- /**
50
- * Get available algorithms for your tier
51
- */
52
206
  async getAlgorithms() {
53
- return this.request("/api/quantum/algorithms");
207
+ return this.request("GET", "/api/quantum/algorithms");
54
208
  }
55
- /**
56
- * Get algorithms filtered by category
57
- */
58
209
  async getAlgorithmsByCategory(category) {
59
210
  const response = await this.getAlgorithms();
60
211
  return response.algorithms.filter((algo) => algo.category === category);
61
212
  }
62
- /**
63
- * Run a quantum algorithm
64
- */
65
213
  async runAlgorithm(request) {
66
- return this.request("/api/quantum/run", {
67
- method: "POST",
68
- body: JSON.stringify(request)
69
- });
214
+ validateRunRequest(request);
215
+ return this.request("POST", "/api/quantum/run", JSON.stringify(request));
70
216
  }
71
- /**
72
- * Get current usage statistics
73
- */
74
217
  async getUsage() {
75
- return this.request("/api/quantum/usage");
76
- }
77
- // ==========================================
78
- // Convenience methods for common algorithms
79
- // ==========================================
80
- /**
81
- * Run Markowitz portfolio optimization (QAOA)
82
- */
218
+ return this.request("GET", "/api/quantum/usage");
219
+ }
220
+ // ═══════════════════════════════════════════════════════════════════
221
+ // Convenience methods
222
+ // ═══════════════════════════════════════════════════════════════════
83
223
  async optimizePortfolio(params) {
224
+ if (!Array.isArray(params.assets) || params.assets.length === 0) {
225
+ throw new QaaSValidationError("assets must be a non-empty array of strings");
226
+ }
227
+ if (params.assets.length !== params.returns.length) {
228
+ throw new QaaSValidationError("assets and returns arrays must have equal length");
229
+ }
84
230
  return this.runAlgorithm({
85
231
  algorithm_id: "QAOA_PORT_001",
86
232
  parameters: {
@@ -92,24 +238,31 @@ var QaaSClient = class {
92
238
  backend: params.backend || "simulator"
93
239
  });
94
240
  }
95
- /**
96
- * Run Value at Risk (VaR) estimation
97
- */
98
241
  async estimateVaR(params) {
242
+ if (typeof params.portfolio_value !== "number" || params.portfolio_value <= 0) {
243
+ throw new QaaSValidationError("portfolio_value must be a positive number");
244
+ }
245
+ if (!Array.isArray(params.returns_history) || params.returns_history.length === 0) {
246
+ throw new QaaSValidationError("returns_history must be a non-empty array");
247
+ }
248
+ const cl = params.confidence_level ?? 0.95;
249
+ if (cl <= 0 || cl >= 1) {
250
+ throw new QaaSValidationError("confidence_level must be between 0 and 1 (exclusive)");
251
+ }
99
252
  return this.runAlgorithm({
100
253
  algorithm_id: "AE_PROB_004",
101
254
  parameters: {
102
255
  portfolio_value: params.portfolio_value,
103
256
  returns_history: params.returns_history,
104
- confidence_level: params.confidence_level ?? 0.95
257
+ confidence_level: cl
105
258
  },
106
259
  backend: params.backend || "simulator"
107
260
  });
108
261
  }
109
- /**
110
- * Run Grover search for arbitrage opportunities
111
- */
112
262
  async findArbitrage(params) {
263
+ if (!Array.isArray(params.price_matrix) || params.price_matrix.length === 0) {
264
+ throw new QaaSValidationError("price_matrix must be a non-empty 2D array");
265
+ }
113
266
  return this.runAlgorithm({
114
267
  algorithm_id: "GROVER_BOOL_003",
115
268
  parameters: {
@@ -119,23 +272,30 @@ var QaaSClient = class {
119
272
  backend: params.backend || "simulator"
120
273
  });
121
274
  }
122
- /**
123
- * Solve a QUBO problem
124
- */
125
275
  async solveQUBO(params) {
276
+ if (!Array.isArray(params.Q_matrix) || params.Q_matrix.length === 0) {
277
+ throw new QaaSValidationError("Q_matrix must be a non-empty 2D array");
278
+ }
279
+ const reads = params.num_reads ?? 1e3;
280
+ if (reads < 1 || reads > 1e5) {
281
+ throw new QaaSValidationError("num_reads must be between 1 and 100,000");
282
+ }
126
283
  return this.runAlgorithm({
127
284
  algorithm_id: "QAOA_QUBO_001",
128
285
  parameters: {
129
286
  Q: params.Q_matrix,
130
- num_reads: params.num_reads ?? 1e3
287
+ num_reads: reads
131
288
  },
132
289
  backend: params.backend || "simulator"
133
290
  });
134
291
  }
135
- /**
136
- * Run Monte Carlo amplitude estimation
137
- */
138
292
  async monteCarloEstimate(params) {
293
+ if (!params.target_function || typeof params.target_function !== "string") {
294
+ throw new QaaSValidationError("target_function is required");
295
+ }
296
+ if (params.target_function.length > 1e4) {
297
+ throw new QaaSValidationError("target_function exceeds max length of 10,000 characters");
298
+ }
139
299
  return this.runAlgorithm({
140
300
  algorithm_id: "AE_PROB_002",
141
301
  parameters: {
@@ -146,18 +306,57 @@ var QaaSClient = class {
146
306
  backend: params.backend || "simulator"
147
307
  });
148
308
  }
309
+ // ═══════════════════════════════════════════════════════════════════
310
+ // Quantum Teleportation (GROT) — via godel-task-router
311
+ // ═══════════════════════════════════════════════════════════════════
312
+ async quantumTeleport(params = {}) {
313
+ return this.request(
314
+ "POST",
315
+ "/v1/quantum/multi-hop/teleport",
316
+ JSON.stringify({
317
+ qubits: params.qubits ?? 8,
318
+ state: params.state ?? "ghz",
319
+ oscillation_cycles: params.oscillation_cycles ?? 3,
320
+ source_backend: params.source_backend,
321
+ destination_backend: params.destination_backend
322
+ })
323
+ );
324
+ }
325
+ async quantumTeleportStatus() {
326
+ return this.request("GET", "/v1/quantum/multi-hop/status");
327
+ }
328
+ async quantumTeleportPlan(params = {}) {
329
+ return this.request(
330
+ "POST",
331
+ "/v1/quantum/multi-hop/plan",
332
+ JSON.stringify({
333
+ qubits: params.qubits ?? 8,
334
+ state: params.state ?? "ghz",
335
+ strategy: params.strategy ?? "combined"
336
+ })
337
+ );
338
+ }
149
339
  };
150
340
  var QaaSError = class extends Error {
151
- constructor(message, statusCode, response) {
341
+ constructor(message, statusCode) {
152
342
  super(message);
153
343
  this.statusCode = statusCode;
154
- this.response = response;
155
344
  this.name = "QaaSError";
156
345
  }
157
346
  };
158
- var qaas = new QaaSClient();
347
+ var QaaSValidationError = class extends Error {
348
+ constructor(message) {
349
+ super(message);
350
+ this.name = "QaaSValidationError";
351
+ }
352
+ };
353
+ var QaaSRateLimitError = class extends Error {
354
+ constructor(message) {
355
+ super(message);
356
+ this.name = "QaaSRateLimitError";
357
+ }
358
+ };
159
359
  var ALGORITHMS = {
160
- // Amplitude Estimation
161
360
  AMPLITUDE_ESTIMATION: {
162
361
  PROB_001: "AE_PROB_001",
163
362
  PROB_002: "AE_PROB_002",
@@ -165,7 +364,6 @@ var ALGORITHMS = {
165
364
  VAR: "AE_PROB_004",
166
365
  CVAR: "AE_PROB_005"
167
366
  },
168
- // Grover Search
169
367
  GROVER: {
170
368
  BOOLEAN_SAT: "GROVER_BOOL_001",
171
369
  PORTFOLIO_CONSTRAINT: "GROVER_BOOL_002",
@@ -173,7 +371,6 @@ var ALGORITHMS = {
173
371
  COMPLIANCE: "GROVER_BOOL_004",
174
372
  PATTERN: "GROVER_BOOL_005"
175
373
  },
176
- // QAOA Portfolio
177
374
  QAOA_PORTFOLIO: {
178
375
  MARKOWITZ: "QAOA_PORT_001",
179
376
  RISK_PARITY: "QAOA_PORT_002",
@@ -181,7 +378,6 @@ var ALGORITHMS = {
181
378
  MIN_VARIANCE: "QAOA_PORT_004",
182
379
  BLACK_LITTERMAN: "QAOA_PORT_005"
183
380
  },
184
- // QUBO
185
381
  QUBO: {
186
382
  GENERAL: "QAOA_QUBO_001",
187
383
  MAX_CUT: "QAOA_QUBO_002",
@@ -194,5 +390,7 @@ export {
194
390
  ALGORITHMS,
195
391
  QaaSClient,
196
392
  QaaSError,
197
- qaas
393
+ QaaSRateLimitError,
394
+ QaaSValidationError,
395
+ SIGNATURE_MAX_AGE_MS
198
396
  };
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@epochcore/qaas-sdk",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Official SDK for EpochCore Quantum as a Service (QaaS) API - Access 100 quantum computing algorithms",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",
8
8
  "exports": {
9
9
  ".": {
10
- "require": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
11
  "import": "./dist/index.mjs",
12
- "types": "./dist/index.d.ts"
12
+ "require": "./dist/index.js"
13
13
  }
14
14
  },
15
15
  "scripts": {