@heossi/qnsi 0.3.2
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/CHANGELOG.md +67 -0
- package/LICENSE.md +8 -0
- package/README.md +200 -0
- package/dist/_activation/activation-client.d.ts +65 -0
- package/dist/_activation/activation-client.d.ts.map +1 -0
- package/dist/_activation/activation-client.js +164 -0
- package/dist/_activation/activation-client.js.map +1 -0
- package/dist/_activation/index.d.ts +10 -0
- package/dist/_activation/index.d.ts.map +1 -0
- package/dist/_activation/index.js +10 -0
- package/dist/_activation/index.js.map +1 -0
- package/dist/_activation/types.d.ts +128 -0
- package/dist/_activation/types.d.ts.map +1 -0
- package/dist/_activation/types.js +94 -0
- package/dist/_activation/types.js.map +1 -0
- package/dist/_internal.d.ts +52 -0
- package/dist/_internal.d.ts.map +1 -0
- package/dist/_internal.js +235 -0
- package/dist/_internal.js.map +1 -0
- package/dist/access.d.ts +32 -0
- package/dist/access.d.ts.map +1 -0
- package/dist/access.js +33 -0
- package/dist/access.js.map +1 -0
- package/dist/ai.d.ts +51 -0
- package/dist/ai.d.ts.map +1 -0
- package/dist/ai.js +53 -0
- package/dist/ai.js.map +1 -0
- package/dist/audit.d.ts +18 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +21 -0
- package/dist/audit.js.map +1 -0
- package/dist/auth.d.ts +31 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +69 -0
- package/dist/auth.js.map +1 -0
- package/dist/autogen/executor.d.ts +200 -0
- package/dist/autogen/executor.d.ts.map +1 -0
- package/dist/autogen/executor.js +277 -0
- package/dist/autogen/executor.js.map +1 -0
- package/dist/autogen/index.d.ts +18 -0
- package/dist/autogen/index.d.ts.map +1 -0
- package/dist/autogen/index.js +17 -0
- package/dist/autogen/index.js.map +1 -0
- package/dist/billing.d.ts +22 -0
- package/dist/billing.d.ts.map +1 -0
- package/dist/billing.js +33 -0
- package/dist/billing.js.map +1 -0
- package/dist/browser/encrypt.d.ts +68 -0
- package/dist/browser/encrypt.d.ts.map +1 -0
- package/dist/browser/encrypt.js +191 -0
- package/dist/browser/encrypt.js.map +1 -0
- package/dist/browser/index.d.ts +39 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +41 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/noble-provider.d.ts +10 -0
- package/dist/browser/noble-provider.d.ts.map +1 -0
- package/dist/browser/noble-provider.js +130 -0
- package/dist/browser/noble-provider.js.map +1 -0
- package/dist/browser/pqc-types.d.ts +40 -0
- package/dist/browser/pqc-types.d.ts.map +1 -0
- package/dist/browser/pqc-types.js +2 -0
- package/dist/browser/pqc-types.js.map +1 -0
- package/dist/browser/provider-setup.d.ts +70 -0
- package/dist/browser/provider-setup.d.ts.map +1 -0
- package/dist/browser/provider-setup.js +101 -0
- package/dist/browser/provider-setup.js.map +1 -0
- package/dist/browser/sdk-package-version.d.ts +12 -0
- package/dist/browser/sdk-package-version.d.ts.map +1 -0
- package/dist/browser/sdk-package-version.js +12 -0
- package/dist/browser/sdk-package-version.js.map +1 -0
- package/dist/browser/sign.d.ts +65 -0
- package/dist/browser/sign.d.ts.map +1 -0
- package/dist/browser/sign.js +124 -0
- package/dist/browser/sign.js.map +1 -0
- package/dist/browser/telemetry.d.ts +98 -0
- package/dist/browser/telemetry.d.ts.map +1 -0
- package/dist/browser/telemetry.js +93 -0
- package/dist/browser/telemetry.js.map +1 -0
- package/dist/cli/commands/access-control.d.ts +4 -0
- package/dist/cli/commands/access-control.d.ts.map +1 -0
- package/dist/cli/commands/access-control.js +183 -0
- package/dist/cli/commands/access-control.js.map +1 -0
- package/dist/cli/commands/audit.d.ts +4 -0
- package/dist/cli/commands/audit.d.ts.map +1 -0
- package/dist/cli/commands/audit.js +70 -0
- package/dist/cli/commands/audit.js.map +1 -0
- package/dist/cli/commands/auth.d.ts +4 -0
- package/dist/cli/commands/auth.d.ts.map +1 -0
- package/dist/cli/commands/auth.js +46 -0
- package/dist/cli/commands/auth.js.map +1 -0
- package/dist/cli/commands/billing.d.ts +4 -0
- package/dist/cli/commands/billing.d.ts.map +1 -0
- package/dist/cli/commands/billing.js +179 -0
- package/dist/cli/commands/billing.js.map +1 -0
- package/dist/cli/commands/crypto-policy.d.ts +4 -0
- package/dist/cli/commands/crypto-policy.d.ts.map +1 -0
- package/dist/cli/commands/crypto-policy.js +130 -0
- package/dist/cli/commands/crypto-policy.js.map +1 -0
- package/dist/cli/commands/kms.d.ts +4 -0
- package/dist/cli/commands/kms.d.ts.map +1 -0
- package/dist/cli/commands/kms.js +153 -0
- package/dist/cli/commands/kms.js.map +1 -0
- package/dist/cli/commands/observability.d.ts +4 -0
- package/dist/cli/commands/observability.d.ts.map +1 -0
- package/dist/cli/commands/observability.js +97 -0
- package/dist/cli/commands/observability.js.map +1 -0
- package/dist/cli/commands/search.d.ts +4 -0
- package/dist/cli/commands/search.d.ts.map +1 -0
- package/dist/cli/commands/search.js +66 -0
- package/dist/cli/commands/search.js.map +1 -0
- package/dist/cli/commands/security.d.ts +4 -0
- package/dist/cli/commands/security.d.ts.map +1 -0
- package/dist/cli/commands/security.js +136 -0
- package/dist/cli/commands/security.js.map +1 -0
- package/dist/cli/commands/storage.d.ts +4 -0
- package/dist/cli/commands/storage.d.ts.map +1 -0
- package/dist/cli/commands/storage.js +85 -0
- package/dist/cli/commands/storage.js.map +1 -0
- package/dist/cli/commands/tenant.d.ts +4 -0
- package/dist/cli/commands/tenant.d.ts.map +1 -0
- package/dist/cli/commands/tenant.js +82 -0
- package/dist/cli/commands/tenant.js.map +1 -0
- package/dist/cli/commands/test-utils.d.ts +15 -0
- package/dist/cli/commands/test-utils.d.ts.map +1 -0
- package/dist/cli/commands/test-utils.js +72 -0
- package/dist/cli/commands/test-utils.js.map +1 -0
- package/dist/cli/commands/vault.d.ts +4 -0
- package/dist/cli/commands/vault.d.ts.map +1 -0
- package/dist/cli/commands/vault.js +111 -0
- package/dist/cli/commands/vault.js.map +1 -0
- package/dist/cli/config.d.ts +32 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +105 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +54 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/utils/audit-logger.d.ts +17 -0
- package/dist/cli/utils/audit-logger.d.ts.map +1 -0
- package/dist/cli/utils/audit-logger.js +52 -0
- package/dist/cli/utils/audit-logger.js.map +1 -0
- package/dist/cli/utils/auth.d.ts +4 -0
- package/dist/cli/utils/auth.d.ts.map +1 -0
- package/dist/cli/utils/auth.js +100 -0
- package/dist/cli/utils/auth.js.map +1 -0
- package/dist/cli/utils/backend-validator.d.ts +19 -0
- package/dist/cli/utils/backend-validator.d.ts.map +1 -0
- package/dist/cli/utils/backend-validator.js +72 -0
- package/dist/cli/utils/backend-validator.js.map +1 -0
- package/dist/cli/utils/command-config.d.ts +4 -0
- package/dist/cli/utils/command-config.d.ts.map +1 -0
- package/dist/cli/utils/command-config.js +29 -0
- package/dist/cli/utils/command-config.js.map +1 -0
- package/dist/cli/utils/fetcher.d.ts +3 -0
- package/dist/cli/utils/fetcher.d.ts.map +1 -0
- package/dist/cli/utils/fetcher.js +30 -0
- package/dist/cli/utils/fetcher.js.map +1 -0
- package/dist/cli/utils/https-validator.d.ts +9 -0
- package/dist/cli/utils/https-validator.d.ts.map +1 -0
- package/dist/cli/utils/https-validator.js +35 -0
- package/dist/cli/utils/https-validator.js.map +1 -0
- package/dist/cli/utils/output.d.ts +6 -0
- package/dist/cli/utils/output.d.ts.map +1 -0
- package/dist/cli/utils/output.js +29 -0
- package/dist/cli/utils/output.js.map +1 -0
- package/dist/cli/utils/pqc-validator.d.ts +17 -0
- package/dist/cli/utils/pqc-validator.d.ts.map +1 -0
- package/dist/cli/utils/pqc-validator.js +62 -0
- package/dist/cli/utils/pqc-validator.js.map +1 -0
- package/dist/cli/utils/prompt.d.ts +4 -0
- package/dist/cli/utils/prompt.d.ts.map +1 -0
- package/dist/cli/utils/prompt.js +30 -0
- package/dist/cli/utils/prompt.js.map +1 -0
- package/dist/cli/utils/rate-limiter.d.ts +15 -0
- package/dist/cli/utils/rate-limiter.d.ts.map +1 -0
- package/dist/cli/utils/rate-limiter.js +46 -0
- package/dist/cli/utils/rate-limiter.js.map +1 -0
- package/dist/cli/utils/sanitize.d.ts +3 -0
- package/dist/cli/utils/sanitize.d.ts.map +1 -0
- package/dist/cli/utils/sanitize.js +44 -0
- package/dist/cli/utils/sanitize.js.map +1 -0
- package/dist/cli/utils/security-headers.d.ts +18 -0
- package/dist/cli/utils/security-headers.d.ts.map +1 -0
- package/dist/cli/utils/security-headers.js +32 -0
- package/dist/cli/utils/security-headers.js.map +1 -0
- package/dist/cli/utils/token-cache.d.ts +4 -0
- package/dist/cli/utils/token-cache.d.ts.map +1 -0
- package/dist/cli/utils/token-cache.js +22 -0
- package/dist/cli/utils/token-cache.js.map +1 -0
- package/dist/client.d.ts +52 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +78 -0
- package/dist/client.js.map +1 -0
- package/dist/crypto-inventory.d.ts +21 -0
- package/dist/crypto-inventory.d.ts.map +1 -0
- package/dist/crypto-inventory.js +28 -0
- package/dist/crypto-inventory.js.map +1 -0
- package/dist/errors.d.ts +35 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +64 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/kms.d.ts +30 -0
- package/dist/kms.d.ts.map +1 -0
- package/dist/kms.js +92 -0
- package/dist/kms.js.map +1 -0
- package/dist/langchain/index.d.ts +22 -0
- package/dist/langchain/index.d.ts.map +1 -0
- package/dist/langchain/index.js +23 -0
- package/dist/langchain/index.js.map +1 -0
- package/dist/langchain/toolkit.d.ts +85 -0
- package/dist/langchain/toolkit.d.ts.map +1 -0
- package/dist/langchain/toolkit.js +146 -0
- package/dist/langchain/toolkit.js.map +1 -0
- package/dist/langchain/tools/audit.d.ts +43 -0
- package/dist/langchain/tools/audit.d.ts.map +1 -0
- package/dist/langchain/tools/audit.js +78 -0
- package/dist/langchain/tools/audit.js.map +1 -0
- package/dist/langchain/tools/kms.d.ts +62 -0
- package/dist/langchain/tools/kms.d.ts.map +1 -0
- package/dist/langchain/tools/kms.js +120 -0
- package/dist/langchain/tools/kms.js.map +1 -0
- package/dist/langchain/tools/vault.d.ts +69 -0
- package/dist/langchain/tools/vault.d.ts.map +1 -0
- package/dist/langchain/tools/vault.js +107 -0
- package/dist/langchain/tools/vault.js.map +1 -0
- package/dist/langchain/vault-client.d.ts +82 -0
- package/dist/langchain/vault-client.d.ts.map +1 -0
- package/dist/langchain/vault-client.js +133 -0
- package/dist/langchain/vault-client.js.map +1 -0
- package/dist/llamaindex/index.d.ts +16 -0
- package/dist/llamaindex/index.d.ts.map +1 -0
- package/dist/llamaindex/index.js +15 -0
- package/dist/llamaindex/index.js.map +1 -0
- package/dist/llamaindex/sse.d.ts +36 -0
- package/dist/llamaindex/sse.d.ts.map +1 -0
- package/dist/llamaindex/sse.js +151 -0
- package/dist/llamaindex/sse.js.map +1 -0
- package/dist/llamaindex/vector-store.d.ts +101 -0
- package/dist/llamaindex/vector-store.d.ts.map +1 -0
- package/dist/llamaindex/vector-store.js +348 -0
- package/dist/llamaindex/vector-store.js.map +1 -0
- package/dist/search.d.ts +32 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +27 -0
- package/dist/search.js.map +1 -0
- package/dist/storage.d.ts +32 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +58 -0
- package/dist/storage.js.map +1 -0
- package/dist/tenant.d.ts +25 -0
- package/dist/tenant.d.ts.map +1 -0
- package/dist/tenant.js +36 -0
- package/dist/tenant.js.map +1 -0
- package/dist/vault.d.ts +22 -0
- package/dist/vault.d.ts.map +1 -0
- package/dist/vault.js +43 -0
- package/dist/vault.js.map +1 -0
- package/dist/webhooks.d.ts +32 -0
- package/dist/webhooks.d.ts.map +1 -0
- package/dist/webhooks.js +77 -0
- package/dist/webhooks.js.map +1 -0
- package/package.json +118 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QNSP AutoGen Executor — `@heossi/qnsi/autogen` subpath.
|
|
3
|
+
*
|
|
4
|
+
* Submits code-execution workloads to QNSP AI orchestrator enclaves and waits
|
|
5
|
+
* for completion, returning structured output with the enclave attestation
|
|
6
|
+
* proof. Provides a function-executor interface compatible with AutoGen's code
|
|
7
|
+
* execution pattern — without importing from `autogen` directly.
|
|
8
|
+
*
|
|
9
|
+
* Folded in from the former standalone `@heossi/qnsi-autogen-qnsp` package
|
|
10
|
+
* (2026-05-16). The workload submit/get HTTP is inlined here (faithful to the
|
|
11
|
+
* former `@heossi/qnsi-ai-sdk` `AiOrchestratorClient`: Bearer auth,
|
|
12
|
+
* `idempotency-key` header, `env` defaulted, bounded retry) so this subpath
|
|
13
|
+
* has no `@heossi/qnsi-*` workspace dependency — same pattern as
|
|
14
|
+
* `../_activation`. Tier/enclave access is enforced authoritatively by the
|
|
15
|
+
* edge-gateway + ai-orchestrator server side (a 402/403 surfaces as an Error);
|
|
16
|
+
* the former client-side tier pre-check was advisory only and is intentionally
|
|
17
|
+
* dropped (single source of truth = server).
|
|
18
|
+
*/
|
|
19
|
+
import { z } from "zod";
|
|
20
|
+
import { activateSdk } from "../_activation/index.js";
|
|
21
|
+
const SDK_VERSION = "0.3.0";
|
|
22
|
+
const SDK_ID = "autogen-qnsp";
|
|
23
|
+
// Activation handshake — keeps telemetry and tier limits consistent. Returns
|
|
24
|
+
// the tenantId so callers can attach it to workload submissions.
|
|
25
|
+
async function resolveActivationTenantId(apiKey, baseUrl) {
|
|
26
|
+
const activation = await activateSdk({
|
|
27
|
+
apiKey,
|
|
28
|
+
sdkId: SDK_ID,
|
|
29
|
+
sdkVersion: SDK_VERSION,
|
|
30
|
+
platformUrl: baseUrl,
|
|
31
|
+
});
|
|
32
|
+
return activation.tenantId;
|
|
33
|
+
}
|
|
34
|
+
// ─── Zod schema for workload security profile ─────────────────────────────────
|
|
35
|
+
const securityProfileSchema = z.object({
|
|
36
|
+
attestationProof: z.string().nullable(),
|
|
37
|
+
hardwareProvider: z.string().nullable(),
|
|
38
|
+
attestationStatus: z.string().nullable(),
|
|
39
|
+
controlPlaneTokenSha256: z.string().nullable(),
|
|
40
|
+
pqcSignatures: z.array(z.object({ provider: z.string(), algorithm: z.string() })),
|
|
41
|
+
});
|
|
42
|
+
// ─── Terminal status set ──────────────────────────────────────────────────────
|
|
43
|
+
const TERMINAL_STATUSES = new Set(["succeeded", "failed", "canceled"]);
|
|
44
|
+
// ─── Language → command mapping ───────────────────────────────────────────────
|
|
45
|
+
const LANGUAGE_COMMANDS = {
|
|
46
|
+
python: ["python", "-c"],
|
|
47
|
+
bash: ["bash", "-c"],
|
|
48
|
+
javascript: ["node", "-e"],
|
|
49
|
+
};
|
|
50
|
+
// ─── QnspExecutor ─────────────────────────────────────────────────────────────
|
|
51
|
+
/**
|
|
52
|
+
* AutoGen-compatible code executor backed by QNSP AI orchestrator enclaves.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* import { QnspExecutor } from "@heossi/qnsi/autogen";
|
|
57
|
+
*
|
|
58
|
+
* const executor = new QnspExecutor({ apiKey: process.env.QNSP_API_KEY });
|
|
59
|
+
* const result = await executor.execute({ code: "print('hi')", language: "python" });
|
|
60
|
+
* console.log(result.status, result.attestationProof);
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export class QnspExecutor {
|
|
64
|
+
#apiKey;
|
|
65
|
+
#baseUrl;
|
|
66
|
+
#containerImage;
|
|
67
|
+
#cpu;
|
|
68
|
+
#memoryGiB;
|
|
69
|
+
#gpu;
|
|
70
|
+
#acceleratorType;
|
|
71
|
+
#pollTimeoutMs;
|
|
72
|
+
#pollIntervalMs;
|
|
73
|
+
#requestTimeoutMs;
|
|
74
|
+
#resolvedTenantId;
|
|
75
|
+
#activationPromise = null;
|
|
76
|
+
constructor(config) {
|
|
77
|
+
this.#resolvedTenantId = config.tenantId ?? null;
|
|
78
|
+
this.#containerImage = config.containerImage ?? "qnsp/enclave-python-runtime:latest";
|
|
79
|
+
this.#cpu = config.cpu ?? 1;
|
|
80
|
+
this.#memoryGiB = config.memoryGiB ?? 2;
|
|
81
|
+
this.#gpu = config.gpu ?? 0;
|
|
82
|
+
this.#acceleratorType = config.acceleratorType ?? "nvidia-a100";
|
|
83
|
+
this.#pollTimeoutMs = config.pollTimeoutMs ?? 300_000;
|
|
84
|
+
this.#pollIntervalMs = config.pollIntervalMs ?? 2_000;
|
|
85
|
+
this.#requestTimeoutMs = config.requestTimeoutMs ?? 30_000;
|
|
86
|
+
this.#apiKey = config.apiKey;
|
|
87
|
+
this.#baseUrl = (config.baseUrl ?? "https://api.qnsp.cuilabs.io").replace(/\/$/, "");
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Resolve the effective tenant ID — either from config or via SDK activation.
|
|
91
|
+
* Caches the result after the first call.
|
|
92
|
+
*/
|
|
93
|
+
async #ensureTenantId() {
|
|
94
|
+
if (this.#resolvedTenantId) {
|
|
95
|
+
return this.#resolvedTenantId;
|
|
96
|
+
}
|
|
97
|
+
if (!this.#activationPromise) {
|
|
98
|
+
this.#activationPromise = resolveActivationTenantId(this.#apiKey, this.#baseUrl).then((tenantId) => {
|
|
99
|
+
this.#resolvedTenantId = tenantId;
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
await this.#activationPromise;
|
|
103
|
+
if (!this.#resolvedTenantId) {
|
|
104
|
+
throw new Error("QNSP AutoGen: tenantId could not be resolved. Ensure your API key is valid.");
|
|
105
|
+
}
|
|
106
|
+
return this.#resolvedTenantId;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Authenticated request against the AI orchestrator via the edge gateway.
|
|
110
|
+
* Faithful to the former @heossi/qnsi-ai-sdk request: Bearer apiKey, JSON,
|
|
111
|
+
* bounded retry (3 attempts, 1s backoff) on network / 5xx.
|
|
112
|
+
*/
|
|
113
|
+
async #request(method, path, body, extraHeaders) {
|
|
114
|
+
const url = `${this.#baseUrl}${path}`;
|
|
115
|
+
const headers = {
|
|
116
|
+
authorization: `Bearer ${this.#apiKey}`,
|
|
117
|
+
accept: "application/json",
|
|
118
|
+
...extraHeaders,
|
|
119
|
+
};
|
|
120
|
+
const init = { method, headers };
|
|
121
|
+
if (body !== undefined) {
|
|
122
|
+
headers["content-type"] = "application/json";
|
|
123
|
+
init.body = JSON.stringify(body);
|
|
124
|
+
}
|
|
125
|
+
const maxAttempts = 3;
|
|
126
|
+
let lastErr;
|
|
127
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
128
|
+
const controller = new AbortController();
|
|
129
|
+
const timer = setTimeout(() => controller.abort(), this.#requestTimeoutMs);
|
|
130
|
+
try {
|
|
131
|
+
const response = await fetch(url, { ...init, signal: controller.signal });
|
|
132
|
+
const text = await response.text().catch(() => "");
|
|
133
|
+
if (!response.ok) {
|
|
134
|
+
// Retry only transient 5xx; surface 4xx (incl. tier 402/403) immediately.
|
|
135
|
+
if (response.status >= 500 && attempt < maxAttempts) {
|
|
136
|
+
lastErr = new Error(`AI orchestrator ${response.status}: ${text}`);
|
|
137
|
+
await delay(1_000);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
let message = `AI orchestrator request failed (${response.status})`;
|
|
141
|
+
try {
|
|
142
|
+
const parsed = JSON.parse(text);
|
|
143
|
+
if (typeof parsed["message"] === "string")
|
|
144
|
+
message = parsed["message"];
|
|
145
|
+
else if (typeof parsed["error"] === "string")
|
|
146
|
+
message = parsed["error"];
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
if (text.length > 0)
|
|
150
|
+
message = text;
|
|
151
|
+
}
|
|
152
|
+
throw new Error(message);
|
|
153
|
+
}
|
|
154
|
+
if (response.status === 204 || text.length === 0) {
|
|
155
|
+
return {};
|
|
156
|
+
}
|
|
157
|
+
return JSON.parse(text);
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
lastErr = err;
|
|
161
|
+
const isAbort = err instanceof Error && err.name === "AbortError";
|
|
162
|
+
if (attempt < maxAttempts && (isAbort || err instanceof TypeError)) {
|
|
163
|
+
await delay(1_000);
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
throw err;
|
|
167
|
+
}
|
|
168
|
+
finally {
|
|
169
|
+
clearTimeout(timer);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
throw lastErr instanceof Error ? lastErr : new Error("AI orchestrator request failed");
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Execute code inside a QNSP enclave and wait for the result.
|
|
176
|
+
*/
|
|
177
|
+
async execute(request) {
|
|
178
|
+
const language = request.language ?? "python";
|
|
179
|
+
const command = LANGUAGE_COMMANDS[language];
|
|
180
|
+
if (!command) {
|
|
181
|
+
throw new Error(`Unsupported language: ${language}. Supported: python, bash, javascript`);
|
|
182
|
+
}
|
|
183
|
+
const workloadName = request.name ?? `autogen-${language}-${Date.now()}`;
|
|
184
|
+
const issuedAt = new Date().toISOString();
|
|
185
|
+
const tenantId = await this.#ensureTenantId();
|
|
186
|
+
const workloadRequest = {
|
|
187
|
+
tenantId,
|
|
188
|
+
name: workloadName,
|
|
189
|
+
priority: "normal",
|
|
190
|
+
schedulingPolicy: this.#gpu > 0 ? "on-demand" : "spot",
|
|
191
|
+
containerImage: this.#containerImage,
|
|
192
|
+
command: [...command, request.code],
|
|
193
|
+
env: request.env ?? {},
|
|
194
|
+
resources: {
|
|
195
|
+
cpu: this.#cpu,
|
|
196
|
+
memoryGiB: this.#memoryGiB,
|
|
197
|
+
gpu: this.#gpu,
|
|
198
|
+
acceleratorType: this.#acceleratorType,
|
|
199
|
+
},
|
|
200
|
+
artifacts: [],
|
|
201
|
+
manifest: {
|
|
202
|
+
pqcSignature: "",
|
|
203
|
+
algorithm: "none",
|
|
204
|
+
issuedAt,
|
|
205
|
+
language,
|
|
206
|
+
executor: "autogen-qnsp",
|
|
207
|
+
},
|
|
208
|
+
labels: {
|
|
209
|
+
"qnsp.io/executor": "autogen-qnsp",
|
|
210
|
+
"qnsp.io/language": language,
|
|
211
|
+
},
|
|
212
|
+
...(request.idempotencyKey !== undefined ? { idempotencyKey: request.idempotencyKey } : {}),
|
|
213
|
+
};
|
|
214
|
+
const submitted = await this.#submitWorkload(workloadRequest);
|
|
215
|
+
// If already in a terminal state (e.g. replayed idempotent result), return immediately
|
|
216
|
+
if (TERMINAL_STATUSES.has(submitted.status)) {
|
|
217
|
+
return {
|
|
218
|
+
workloadId: submitted.workloadId,
|
|
219
|
+
status: submitted.status,
|
|
220
|
+
replayed: submitted.replayed,
|
|
221
|
+
attestationProof: null,
|
|
222
|
+
hardwareProvider: null,
|
|
223
|
+
acceptedAt: submitted.acceptedAt,
|
|
224
|
+
completedAt: null,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
const detail = await this.#pollUntilComplete(submitted.workloadId);
|
|
228
|
+
const security = securityProfileSchema.safeParse(detail.security);
|
|
229
|
+
return {
|
|
230
|
+
workloadId: detail.id,
|
|
231
|
+
status: detail.status,
|
|
232
|
+
replayed: submitted.replayed,
|
|
233
|
+
attestationProof: security.success ? security.data.attestationProof : null,
|
|
234
|
+
hardwareProvider: security.success ? security.data.hardwareProvider : null,
|
|
235
|
+
acceptedAt: detail.acceptedAt,
|
|
236
|
+
completedAt: detail.completedAt,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Submit a workload. Faithful to @heossi/qnsi-ai-sdk: `idempotencyKey` is
|
|
241
|
+
* stripped from the body and sent as the `idempotency-key` header; `env`
|
|
242
|
+
* defaults to `{}`.
|
|
243
|
+
*/
|
|
244
|
+
async #submitWorkload(input) {
|
|
245
|
+
const { idempotencyKey, ...payload } = input;
|
|
246
|
+
const extraHeaders = {};
|
|
247
|
+
if (idempotencyKey) {
|
|
248
|
+
extraHeaders["idempotency-key"] = idempotencyKey;
|
|
249
|
+
}
|
|
250
|
+
return this.#request("POST", "/ai/v1/workloads", { ...payload, env: payload.env ?? {} }, extraHeaders);
|
|
251
|
+
}
|
|
252
|
+
async #getWorkload(workloadId) {
|
|
253
|
+
return this.#request("GET", `/ai/v1/workloads/${encodeURIComponent(workloadId)}`);
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Poll a workload until it reaches a terminal state or the timeout is exceeded.
|
|
257
|
+
*/
|
|
258
|
+
async #pollUntilComplete(workloadId) {
|
|
259
|
+
const deadline = Date.now() + this.#pollTimeoutMs;
|
|
260
|
+
while (Date.now() < deadline) {
|
|
261
|
+
const detail = await this.#getWorkload(workloadId);
|
|
262
|
+
if (TERMINAL_STATUSES.has(detail.status)) {
|
|
263
|
+
return detail;
|
|
264
|
+
}
|
|
265
|
+
const remaining = deadline - Date.now();
|
|
266
|
+
const wait = Math.min(this.#pollIntervalMs, remaining);
|
|
267
|
+
if (wait > 0) {
|
|
268
|
+
await delay(wait);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
throw new Error(`Workload ${workloadId} did not complete within ${this.#pollTimeoutMs}ms poll timeout`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
function delay(ms) {
|
|
275
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
276
|
+
}
|
|
277
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/autogen/executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@heossi/qnsi/autogen` — AutoGen function executor for QNSP.
|
|
3
|
+
*
|
|
4
|
+
* Submits code workloads to QNSP AI orchestrator enclaves with PQC
|
|
5
|
+
* attestation. Folded in from the former standalone
|
|
6
|
+
* `@heossi/qnsi-autogen-qnsp` package (2026-05-16).
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { QnspExecutor } from "@heossi/qnsi/autogen";
|
|
11
|
+
*
|
|
12
|
+
* const executor = new QnspExecutor({ apiKey: process.env.QNSP_API_KEY });
|
|
13
|
+
* const result = await executor.execute({ code: "print('Hello')", language: "python" });
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export type { ExecuteCodeRequest, ExecuteCodeResult, QnspExecutorConfig, SubmitWorkloadRequest, WorkloadDetail, WorkloadStatus, } from "./executor.js";
|
|
17
|
+
export { QnspExecutor } from "./executor.js";
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/autogen/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,YAAY,EACX,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EACrB,cAAc,EACd,cAAc,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@heossi/qnsi/autogen` — AutoGen function executor for QNSP.
|
|
3
|
+
*
|
|
4
|
+
* Submits code workloads to QNSP AI orchestrator enclaves with PQC
|
|
5
|
+
* attestation. Folded in from the former standalone
|
|
6
|
+
* `@heossi/qnsi-autogen-qnsp` package (2026-05-16).
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { QnspExecutor } from "@heossi/qnsi/autogen";
|
|
11
|
+
*
|
|
12
|
+
* const executor = new QnspExecutor({ apiKey: process.env.QNSP_API_KEY });
|
|
13
|
+
* const result = await executor.execute({ code: "print('Hello')", language: "python" });
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export { QnspExecutor } from "./executor.js";
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/autogen/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAUH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QNSP Billing — entitlement queries, usage meters, invoice listing,
|
|
3
|
+
* credit balance. Wraps `apps/billing-service` (`/billing/v1`).
|
|
4
|
+
*/
|
|
5
|
+
import type { Internal, RequestOptions } from "./_internal.js";
|
|
6
|
+
export interface IngestMeterRequest {
|
|
7
|
+
readonly meterId: string;
|
|
8
|
+
readonly quantity: number;
|
|
9
|
+
readonly occurredAt?: string;
|
|
10
|
+
readonly metadata?: Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
export declare class BillingClient {
|
|
13
|
+
private readonly internal;
|
|
14
|
+
constructor(internal: Internal);
|
|
15
|
+
getEntitlements(): Promise<Record<string, unknown>>;
|
|
16
|
+
ingestMeter(req: IngestMeterRequest, opts?: Pick<RequestOptions, "idempotencyKey">): Promise<Record<string, unknown>>;
|
|
17
|
+
ingestMeters(meters: readonly IngestMeterRequest[], opts?: Pick<RequestOptions, "idempotencyKey">): Promise<Record<string, unknown>>;
|
|
18
|
+
listInvoices(query?: RequestOptions["query"]): Promise<Record<string, unknown>>;
|
|
19
|
+
getInvoice(invoiceId: string): Promise<Record<string, unknown>>;
|
|
20
|
+
getCreditBalance(tenantId: string): Promise<Record<string, unknown>>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=billing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"billing.d.ts","sourceRoot":"","sources":["../src/billing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAI/D,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC5C;AAED,qBAAa,aAAa;IACb,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,QAAQ;IAEzC,eAAe;IAOrB,WAAW,CAAC,GAAG,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,gBAAgB,CAAC;IAIlF,YAAY,CACX,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,IAAI,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,gBAAgB,CAAC;IAK9C,YAAY,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC;IAI5C,UAAU,CAAC,SAAS,EAAE,MAAM;IAI5B,gBAAgB,CAAC,QAAQ,EAAE,MAAM;CAGjC"}
|
package/dist/billing.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QNSP Billing — entitlement queries, usage meters, invoice listing,
|
|
3
|
+
* credit balance. Wraps `apps/billing-service` (`/billing/v1`).
|
|
4
|
+
*/
|
|
5
|
+
const PATH_PREFIX = "/proxy/billing/v1";
|
|
6
|
+
export class BillingClient {
|
|
7
|
+
internal;
|
|
8
|
+
constructor(internal) {
|
|
9
|
+
this.internal = internal;
|
|
10
|
+
}
|
|
11
|
+
async getEntitlements() {
|
|
12
|
+
// reaudit 2026-06-13 #30: the bare /entitlements path does not exist on billing-service.
|
|
13
|
+
// The resolved entitlements live at /billing/v1/entitlements/resolved/:tenantId.
|
|
14
|
+
const tenantId = await this.internal.resolveTenantId();
|
|
15
|
+
return this.internal.request("GET", `${PATH_PREFIX}/entitlements/resolved/${tenantId}`);
|
|
16
|
+
}
|
|
17
|
+
ingestMeter(req, opts) {
|
|
18
|
+
return this.internal.request("POST", `${PATH_PREFIX}/meters`, req, opts);
|
|
19
|
+
}
|
|
20
|
+
ingestMeters(meters, opts) {
|
|
21
|
+
return this.internal.request("POST", `${PATH_PREFIX}/meters/batch`, { meters }, opts);
|
|
22
|
+
}
|
|
23
|
+
listInvoices(query) {
|
|
24
|
+
return this.internal.request("GET", `${PATH_PREFIX}/invoices`, undefined, { query });
|
|
25
|
+
}
|
|
26
|
+
getInvoice(invoiceId) {
|
|
27
|
+
return this.internal.request("GET", `${PATH_PREFIX}/invoices/${invoiceId}`);
|
|
28
|
+
}
|
|
29
|
+
getCreditBalance(tenantId) {
|
|
30
|
+
return this.internal.request("GET", `${PATH_PREFIX}/credits/balance/${tenantId}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=billing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"billing.js","sourceRoot":"","sources":["../src/billing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,GAAG,mBAAmB,CAAC;AASxC,MAAM,OAAO,aAAa;IACI;IAA7B,YAA6B,QAAkB;QAAlB,aAAQ,GAAR,QAAQ,CAAU;IAAG,CAAC;IAEnD,KAAK,CAAC,eAAe;QACpB,yFAAyF;QACzF,iFAAiF;QACjF,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE,CAAC;QACvD,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,WAAW,0BAA0B,QAAQ,EAAE,CAAC,CAAC;IACzF,CAAC;IAED,WAAW,CAAC,GAAuB,EAAE,IAA6C;QACjF,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,WAAW,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAC1E,CAAC;IAED,YAAY,CACX,MAAqC,EACrC,IAA6C;QAE7C,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,WAAW,eAAe,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC;IACvF,CAAC;IAED,YAAY,CAAC,KAA+B;QAC3C,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,WAAW,WAAW,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IACtF,CAAC;IAED,UAAU,CAAC,SAAiB;QAC3B,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,WAAW,aAAa,SAAS,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED,gBAAgB,CAAC,QAAgB;QAChC,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,WAAW,oBAAoB,QAAQ,EAAE,CAAC,CAAC;IACnF,CAAC;CACD"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side encryption (CSE) helpers for browser PQC operations.
|
|
3
|
+
*
|
|
4
|
+
* Provides encrypt-before-upload and decrypt-after-download using:
|
|
5
|
+
* - ML-KEM (FIPS 203) for key encapsulation → derives AES-256-GCM key
|
|
6
|
+
* - AES-256-GCM via WebCrypto API for bulk data encryption (hardware-accelerated)
|
|
7
|
+
*
|
|
8
|
+
* No node: imports. Works in browsers, Deno, Bun, and Node.js 20+.
|
|
9
|
+
*
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
12
|
+
import type { PqcAlgorithm } from "./pqc-types.js";
|
|
13
|
+
/**
|
|
14
|
+
* CSE envelope: contains everything needed to decrypt the data.
|
|
15
|
+
* The recipient needs their private key + this envelope to recover plaintext.
|
|
16
|
+
*/
|
|
17
|
+
export interface CseEnvelope {
|
|
18
|
+
/** PQC algorithm used for key encapsulation. */
|
|
19
|
+
readonly algorithm: PqcAlgorithm;
|
|
20
|
+
/** KEM ciphertext (encapsulated shared secret). */
|
|
21
|
+
readonly kemCiphertext: Uint8Array;
|
|
22
|
+
/** AES-256-GCM initialization vector. */
|
|
23
|
+
readonly iv: Uint8Array;
|
|
24
|
+
/** AES-256-GCM encrypted data (includes authentication tag). */
|
|
25
|
+
readonly ciphertext: Uint8Array;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Encrypt data using PQC key encapsulation + AES-256-GCM.
|
|
29
|
+
*
|
|
30
|
+
* Flow:
|
|
31
|
+
* 1. ML-KEM encapsulate with recipient's public key → shared secret + KEM ciphertext
|
|
32
|
+
* 2. Derive AES-256-GCM key from shared secret (first 32 bytes)
|
|
33
|
+
* 3. Generate random IV
|
|
34
|
+
* 4. AES-256-GCM encrypt the plaintext
|
|
35
|
+
* 5. Return CSE envelope (KEM ciphertext + IV + AES ciphertext)
|
|
36
|
+
*
|
|
37
|
+
* @param plaintext - Data to encrypt
|
|
38
|
+
* @param publicKey - Recipient's PQC public key (from ML-KEM keygen)
|
|
39
|
+
* @param algorithm - KEM algorithm to use (kyber-512, kyber-768, kyber-1024)
|
|
40
|
+
* @returns CSE envelope containing all data needed for decryption
|
|
41
|
+
*/
|
|
42
|
+
export declare function encryptBeforeUpload(plaintext: Uint8Array, publicKey: Uint8Array, algorithm: PqcAlgorithm): Promise<CseEnvelope>;
|
|
43
|
+
/**
|
|
44
|
+
* Decrypt a CSE envelope using PQC key decapsulation + AES-256-GCM.
|
|
45
|
+
*
|
|
46
|
+
* Flow:
|
|
47
|
+
* 1. ML-KEM decapsulate with recipient's private key → shared secret
|
|
48
|
+
* 2. Derive AES-256-GCM key from shared secret (first 32 bytes)
|
|
49
|
+
* 3. AES-256-GCM decrypt using IV from envelope
|
|
50
|
+
* 4. Return plaintext
|
|
51
|
+
*
|
|
52
|
+
* @param envelope - CSE envelope from encryptBeforeUpload()
|
|
53
|
+
* @param privateKey - Recipient's PQC private key (from ML-KEM keygen)
|
|
54
|
+
* @returns Decrypted plaintext
|
|
55
|
+
*/
|
|
56
|
+
export declare function decryptAfterDownload(envelope: CseEnvelope, privateKey: Uint8Array): Promise<Uint8Array>;
|
|
57
|
+
/**
|
|
58
|
+
* Serialize a CSE envelope to a single Uint8Array for storage/transmission.
|
|
59
|
+
*
|
|
60
|
+
* Format: [algorithmLen(2)] [algorithm] [kemCtLen(4)] [kemCt] [ivLen(1)] [iv] [ciphertext]
|
|
61
|
+
* All lengths are big-endian unsigned integers.
|
|
62
|
+
*/
|
|
63
|
+
export declare function serializeCseEnvelope(envelope: CseEnvelope): Uint8Array;
|
|
64
|
+
/**
|
|
65
|
+
* Deserialize a CSE envelope from a Uint8Array.
|
|
66
|
+
*/
|
|
67
|
+
export declare function deserializeCseEnvelope(data: Uint8Array): CseEnvelope;
|
|
68
|
+
//# sourceMappingURL=encrypt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encrypt.d.ts","sourceRoot":"","sources":["../../src/browser/encrypt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAenD;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC3B,gDAAgD;IAChD,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,mDAAmD;IACnD,QAAQ,CAAC,aAAa,EAAE,UAAU,CAAC;IACnC,yCAAyC;IACzC,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC;IACxB,gEAAgE;IAChE,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CAChC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,mBAAmB,CACxC,SAAS,EAAE,UAAU,EACrB,SAAS,EAAE,UAAU,EACrB,SAAS,EAAE,YAAY,GACrB,OAAO,CAAC,WAAW,CAAC,CAgDtB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,oBAAoB,CACzC,QAAQ,EAAE,WAAW,EACrB,UAAU,EAAE,UAAU,GACpB,OAAO,CAAC,UAAU,CAAC,CAuCrB;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,WAAW,GAAG,UAAU,CAqCtE;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,UAAU,GAAG,WAAW,CAkDpE"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side encryption (CSE) helpers for browser PQC operations.
|
|
3
|
+
*
|
|
4
|
+
* Provides encrypt-before-upload and decrypt-after-download using:
|
|
5
|
+
* - ML-KEM (FIPS 203) for key encapsulation → derives AES-256-GCM key
|
|
6
|
+
* - AES-256-GCM via WebCrypto API for bulk data encryption (hardware-accelerated)
|
|
7
|
+
*
|
|
8
|
+
* No node: imports. Works in browsers, Deno, Bun, and Node.js 20+.
|
|
9
|
+
*
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
12
|
+
import { getActiveProvider } from "./provider-setup.js";
|
|
13
|
+
/** KEM algorithms supported for CSE operations. */
|
|
14
|
+
const KEM_ALGORITHMS = new Set(["kyber-512", "kyber-768", "kyber-1024"]);
|
|
15
|
+
/** AES-256-GCM IV size in bytes. */
|
|
16
|
+
const AES_GCM_IV_BYTES = 12;
|
|
17
|
+
/** AES-256-GCM key size in bytes. */
|
|
18
|
+
const AES_GCM_KEY_BYTES = 32;
|
|
19
|
+
/** AES-256-GCM tag size in bits. */
|
|
20
|
+
const AES_GCM_TAG_BITS = 128;
|
|
21
|
+
/**
|
|
22
|
+
* Encrypt data using PQC key encapsulation + AES-256-GCM.
|
|
23
|
+
*
|
|
24
|
+
* Flow:
|
|
25
|
+
* 1. ML-KEM encapsulate with recipient's public key → shared secret + KEM ciphertext
|
|
26
|
+
* 2. Derive AES-256-GCM key from shared secret (first 32 bytes)
|
|
27
|
+
* 3. Generate random IV
|
|
28
|
+
* 4. AES-256-GCM encrypt the plaintext
|
|
29
|
+
* 5. Return CSE envelope (KEM ciphertext + IV + AES ciphertext)
|
|
30
|
+
*
|
|
31
|
+
* @param plaintext - Data to encrypt
|
|
32
|
+
* @param publicKey - Recipient's PQC public key (from ML-KEM keygen)
|
|
33
|
+
* @param algorithm - KEM algorithm to use (kyber-512, kyber-768, kyber-1024)
|
|
34
|
+
* @returns CSE envelope containing all data needed for decryption
|
|
35
|
+
*/
|
|
36
|
+
export async function encryptBeforeUpload(plaintext, publicKey, algorithm) {
|
|
37
|
+
if (!KEM_ALGORITHMS.has(algorithm)) {
|
|
38
|
+
throw new Error(`Algorithm '${algorithm}' is not a supported KEM algorithm for CSE. ` +
|
|
39
|
+
`Supported: ${[...KEM_ALGORITHMS].join(", ")}`);
|
|
40
|
+
}
|
|
41
|
+
if (plaintext.length === 0) {
|
|
42
|
+
throw new Error("Plaintext must not be empty");
|
|
43
|
+
}
|
|
44
|
+
if (publicKey.length === 0) {
|
|
45
|
+
throw new Error("Public key must not be empty");
|
|
46
|
+
}
|
|
47
|
+
const provider = getActiveProvider();
|
|
48
|
+
// Step 1: KEM encapsulate → shared secret + ciphertext
|
|
49
|
+
const { ciphertext: kemCiphertext, sharedSecret } = await provider.encapsulate({
|
|
50
|
+
algorithm,
|
|
51
|
+
publicKey,
|
|
52
|
+
});
|
|
53
|
+
// Step 2: Derive AES-256-GCM key from shared secret
|
|
54
|
+
const aesKeyBytes = new Uint8Array(sharedSecret.buffer.slice(sharedSecret.byteOffset, sharedSecret.byteOffset + AES_GCM_KEY_BYTES));
|
|
55
|
+
const aesKey = await crypto.subtle.importKey("raw", aesKeyBytes, { name: "AES-GCM" }, false, [
|
|
56
|
+
"encrypt",
|
|
57
|
+
]);
|
|
58
|
+
// Step 3: Generate random IV
|
|
59
|
+
const iv = crypto.getRandomValues(new Uint8Array(AES_GCM_IV_BYTES));
|
|
60
|
+
// Step 4: AES-256-GCM encrypt
|
|
61
|
+
const encrypted = await crypto.subtle.encrypt({ name: "AES-GCM", iv, tagLength: AES_GCM_TAG_BITS }, aesKey, new Uint8Array(plaintext));
|
|
62
|
+
return {
|
|
63
|
+
algorithm,
|
|
64
|
+
kemCiphertext: new Uint8Array(kemCiphertext),
|
|
65
|
+
iv: new Uint8Array(iv),
|
|
66
|
+
ciphertext: new Uint8Array(encrypted),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Decrypt a CSE envelope using PQC key decapsulation + AES-256-GCM.
|
|
71
|
+
*
|
|
72
|
+
* Flow:
|
|
73
|
+
* 1. ML-KEM decapsulate with recipient's private key → shared secret
|
|
74
|
+
* 2. Derive AES-256-GCM key from shared secret (first 32 bytes)
|
|
75
|
+
* 3. AES-256-GCM decrypt using IV from envelope
|
|
76
|
+
* 4. Return plaintext
|
|
77
|
+
*
|
|
78
|
+
* @param envelope - CSE envelope from encryptBeforeUpload()
|
|
79
|
+
* @param privateKey - Recipient's PQC private key (from ML-KEM keygen)
|
|
80
|
+
* @returns Decrypted plaintext
|
|
81
|
+
*/
|
|
82
|
+
export async function decryptAfterDownload(envelope, privateKey) {
|
|
83
|
+
if (!KEM_ALGORITHMS.has(envelope.algorithm)) {
|
|
84
|
+
throw new Error(`Algorithm '${envelope.algorithm}' is not a supported KEM algorithm for CSE. ` +
|
|
85
|
+
`Supported: ${[...KEM_ALGORITHMS].join(", ")}`);
|
|
86
|
+
}
|
|
87
|
+
if (privateKey.length === 0) {
|
|
88
|
+
throw new Error("Private key must not be empty");
|
|
89
|
+
}
|
|
90
|
+
const provider = getActiveProvider();
|
|
91
|
+
// Step 1: KEM decapsulate → shared secret
|
|
92
|
+
const sharedSecret = await provider.decapsulate({
|
|
93
|
+
algorithm: envelope.algorithm,
|
|
94
|
+
ciphertext: envelope.kemCiphertext,
|
|
95
|
+
privateKey,
|
|
96
|
+
});
|
|
97
|
+
// Step 2: Derive AES-256-GCM key from shared secret
|
|
98
|
+
const aesKeyBytes = new Uint8Array(sharedSecret.buffer.slice(sharedSecret.byteOffset, sharedSecret.byteOffset + AES_GCM_KEY_BYTES));
|
|
99
|
+
const aesKey = await crypto.subtle.importKey("raw", aesKeyBytes, { name: "AES-GCM" }, false, [
|
|
100
|
+
"decrypt",
|
|
101
|
+
]);
|
|
102
|
+
// Step 3: AES-256-GCM decrypt
|
|
103
|
+
const ciphertextBuf = new Uint8Array(envelope.ciphertext);
|
|
104
|
+
const ivBuf = new Uint8Array(envelope.iv);
|
|
105
|
+
const decrypted = await crypto.subtle.decrypt({ name: "AES-GCM", iv: ivBuf, tagLength: AES_GCM_TAG_BITS }, aesKey, ciphertextBuf);
|
|
106
|
+
return new Uint8Array(decrypted);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Serialize a CSE envelope to a single Uint8Array for storage/transmission.
|
|
110
|
+
*
|
|
111
|
+
* Format: [algorithmLen(2)] [algorithm] [kemCtLen(4)] [kemCt] [ivLen(1)] [iv] [ciphertext]
|
|
112
|
+
* All lengths are big-endian unsigned integers.
|
|
113
|
+
*/
|
|
114
|
+
export function serializeCseEnvelope(envelope) {
|
|
115
|
+
const algorithmBytes = new TextEncoder().encode(envelope.algorithm);
|
|
116
|
+
const totalLen = 2 +
|
|
117
|
+
algorithmBytes.length +
|
|
118
|
+
4 +
|
|
119
|
+
envelope.kemCiphertext.length +
|
|
120
|
+
1 +
|
|
121
|
+
envelope.iv.length +
|
|
122
|
+
envelope.ciphertext.length;
|
|
123
|
+
const result = new Uint8Array(totalLen);
|
|
124
|
+
const view = new DataView(result.buffer);
|
|
125
|
+
let offset = 0;
|
|
126
|
+
// Algorithm name length (2 bytes) + algorithm name
|
|
127
|
+
view.setUint16(offset, algorithmBytes.length);
|
|
128
|
+
offset += 2;
|
|
129
|
+
result.set(algorithmBytes, offset);
|
|
130
|
+
offset += algorithmBytes.length;
|
|
131
|
+
// KEM ciphertext length (4 bytes) + KEM ciphertext
|
|
132
|
+
view.setUint32(offset, envelope.kemCiphertext.length);
|
|
133
|
+
offset += 4;
|
|
134
|
+
result.set(envelope.kemCiphertext, offset);
|
|
135
|
+
offset += envelope.kemCiphertext.length;
|
|
136
|
+
// IV length (1 byte) + IV
|
|
137
|
+
result[offset] = envelope.iv.length;
|
|
138
|
+
offset += 1;
|
|
139
|
+
result.set(envelope.iv, offset);
|
|
140
|
+
offset += envelope.iv.length;
|
|
141
|
+
// Remaining bytes = AES ciphertext
|
|
142
|
+
result.set(envelope.ciphertext, offset);
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Deserialize a CSE envelope from a Uint8Array.
|
|
147
|
+
*/
|
|
148
|
+
export function deserializeCseEnvelope(data) {
|
|
149
|
+
if (data.length < 9) {
|
|
150
|
+
throw new Error("Invalid CSE envelope: too short");
|
|
151
|
+
}
|
|
152
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
153
|
+
let offset = 0;
|
|
154
|
+
// Algorithm name
|
|
155
|
+
const algorithmLen = view.getUint16(offset);
|
|
156
|
+
offset += 2;
|
|
157
|
+
if (offset + algorithmLen > data.length) {
|
|
158
|
+
throw new Error("Invalid CSE envelope: algorithm length exceeds data");
|
|
159
|
+
}
|
|
160
|
+
const algorithm = new TextDecoder().decode(data.slice(offset, offset + algorithmLen));
|
|
161
|
+
offset += algorithmLen;
|
|
162
|
+
// KEM ciphertext
|
|
163
|
+
if (offset + 4 > data.length) {
|
|
164
|
+
throw new Error("Invalid CSE envelope: missing KEM ciphertext length");
|
|
165
|
+
}
|
|
166
|
+
const kemCtLen = view.getUint32(offset);
|
|
167
|
+
offset += 4;
|
|
168
|
+
if (offset + kemCtLen > data.length) {
|
|
169
|
+
throw new Error("Invalid CSE envelope: KEM ciphertext length exceeds data");
|
|
170
|
+
}
|
|
171
|
+
const kemCiphertext = data.slice(offset, offset + kemCtLen);
|
|
172
|
+
offset += kemCtLen;
|
|
173
|
+
// IV
|
|
174
|
+
if (offset + 1 > data.length) {
|
|
175
|
+
throw new Error("Invalid CSE envelope: missing IV length");
|
|
176
|
+
}
|
|
177
|
+
const ivLen = data[offset] ?? 0;
|
|
178
|
+
offset += 1;
|
|
179
|
+
if (offset + ivLen > data.length) {
|
|
180
|
+
throw new Error("Invalid CSE envelope: IV length exceeds data");
|
|
181
|
+
}
|
|
182
|
+
const iv = data.slice(offset, offset + ivLen);
|
|
183
|
+
offset += ivLen;
|
|
184
|
+
// AES ciphertext (remaining bytes)
|
|
185
|
+
const ciphertext = data.slice(offset);
|
|
186
|
+
if (ciphertext.length === 0) {
|
|
187
|
+
throw new Error("Invalid CSE envelope: empty ciphertext");
|
|
188
|
+
}
|
|
189
|
+
return { algorithm, kemCiphertext, iv, ciphertext };
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=encrypt.js.map
|