@absolutejs/deploy 0.24.0 → 0.25.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/README.md +34 -0
- package/dist/appStoreConnect.js +11 -9
- package/dist/appStoreConnect.js.map +2 -2
- package/dist/cloudTarget.d.ts +4 -4
- package/dist/cloudflare.d.ts +2 -2
- package/dist/cloudflare.js +11 -9
- package/dist/cloudflare.js.map +3 -3
- package/dist/deployer.d.ts +9 -9
- package/dist/digitalocean.d.ts +5 -5
- package/dist/digitalocean.js +21 -13
- package/dist/digitalocean.js.map +5 -5
- package/dist/digitaloceanDns.d.ts +2 -2
- package/dist/digitaloceanDns.js +16 -8
- package/dist/digitaloceanDns.js.map +6 -6
- package/dist/digitaloceanEphemeralInfrastructure.js +16 -8
- package/dist/digitaloceanEphemeralInfrastructure.js.map +5 -5
- package/dist/digitaloceanInfrastructure.js +16 -8
- package/dist/digitaloceanInfrastructure.js.map +6 -6
- package/dist/digitaloceanIngress.js +16 -8
- package/dist/digitaloceanIngress.js.map +5 -5
- package/dist/dns.d.ts +1 -1
- package/dist/dns.js +9 -7
- package/dist/dns.js.map +3 -3
- package/dist/edgeIngress.js +11 -9
- package/dist/edgeIngress.js.map +2 -2
- package/dist/env.d.ts +1 -1
- package/dist/env.js +13 -11
- package/dist/env.js.map +3 -3
- package/dist/gcp.js +99 -93
- package/dist/gcp.js.map +3 -3
- package/dist/gcpIngress.js +93 -91
- package/dist/gcpIngress.js.map +2 -2
- package/dist/googlePlay.js +93 -91
- package/dist/googlePlay.js.map +2 -2
- package/dist/hetzner.d.ts +3 -3
- package/dist/hetzner.js +21 -13
- package/dist/hetzner.js.map +5 -5
- package/dist/hetznerDns.d.ts +2 -2
- package/dist/hetznerDns.js +11 -9
- package/dist/hetznerDns.js.map +3 -3
- package/dist/hetznerInfrastructure.js +16 -8
- package/dist/hetznerInfrastructure.js.map +7 -7
- package/dist/index.d.ts +2 -0
- package/dist/index.js +759 -285
- package/dist/index.js.map +7 -6
- package/dist/linode.d.ts +3 -3
- package/dist/linode.js +21 -13
- package/dist/linode.js.map +5 -5
- package/dist/linodeInfrastructure.js +21 -9
- package/dist/linodeInfrastructure.js.map +7 -7
- package/dist/managedPreview.js +9 -7
- package/dist/managedPreview.js.map +2 -2
- package/dist/mobileUpdate.d.ts +109 -0
- package/dist/mobileUpdate.js +464 -0
- package/dist/mobileUpdate.js.map +10 -0
- package/dist/nativeRelease.js +11 -9
- package/dist/nativeRelease.js.map +2 -2
- package/dist/preview.d.ts +3 -3
- package/dist/preview.js +15 -10
- package/dist/preview.js.map +3 -3
- package/dist/processManagers.d.ts +4 -4
- package/dist/releaseArtifact.js +12 -10
- package/dist/releaseArtifact.js.map +2 -2
- package/dist/route53.d.ts +2 -2
- package/dist/route53.js +9 -7
- package/dist/route53.js.map +3 -3
- package/dist/targets.d.ts +1 -1
- package/dist/tls.d.ts +5 -5
- package/dist/tls.js +23 -18
- package/dist/tls.js.map +3 -3
- package/dist/vultr.d.ts +4 -4
- package/dist/vultr.js +21 -13
- package/dist/vultr.js.map +5 -5
- package/dist/vultrInfrastructure.js +16 -8
- package/dist/vultrInfrastructure.js.map +7 -7
- package/package.json +7 -2
package/dist/tls.js
CHANGED
|
@@ -19,12 +19,14 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
19
19
|
}
|
|
20
20
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
21
21
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
if (mod && typeof mod === "object" || typeof mod === "function") {
|
|
23
|
+
for (let key of __getOwnPropNames(mod))
|
|
24
|
+
if (!__hasOwnProp.call(to, key))
|
|
25
|
+
__defProp(to, key, {
|
|
26
|
+
get: __accessProp.bind(mod, key),
|
|
27
|
+
enumerable: true
|
|
28
|
+
});
|
|
29
|
+
}
|
|
28
30
|
if (canCache)
|
|
29
31
|
cache.set(mod, to);
|
|
30
32
|
return to;
|
|
@@ -219,7 +221,10 @@ var buildExtensionRequestAttribute = (domains) => {
|
|
|
219
221
|
derSet([extensions])
|
|
220
222
|
]);
|
|
221
223
|
};
|
|
222
|
-
var generateCertKeyPair = async () => crypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, true, [
|
|
224
|
+
var generateCertKeyPair = async () => crypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, true, [
|
|
225
|
+
"sign",
|
|
226
|
+
"verify"
|
|
227
|
+
]);
|
|
223
228
|
var buildCsr = async (domains, keypair) => {
|
|
224
229
|
if (domains.length === 0) {
|
|
225
230
|
throw new Error("[deploy/tls] CSR requires at least one domain");
|
|
@@ -552,18 +557,18 @@ var renewCertificate = async (options) => {
|
|
|
552
557
|
return { certificate, reason: "expiring-soon", renewed: true };
|
|
553
558
|
};
|
|
554
559
|
export {
|
|
555
|
-
|
|
556
|
-
issueCertificate,
|
|
557
|
-
installCertificateOnTarget,
|
|
558
|
-
inspectCertificate,
|
|
559
|
-
importAccount,
|
|
560
|
-
generateAccountKey,
|
|
561
|
-
exportAccount,
|
|
562
|
-
__testing,
|
|
563
|
-
LETSENCRYPT_STAGING,
|
|
560
|
+
AcmeError,
|
|
564
561
|
LETSENCRYPT_PRODUCTION,
|
|
565
|
-
|
|
562
|
+
LETSENCRYPT_STAGING,
|
|
563
|
+
__testing,
|
|
564
|
+
exportAccount,
|
|
565
|
+
generateAccountKey,
|
|
566
|
+
importAccount,
|
|
567
|
+
inspectCertificate,
|
|
568
|
+
installCertificateOnTarget,
|
|
569
|
+
issueCertificate,
|
|
570
|
+
renewCertificate
|
|
566
571
|
};
|
|
567
572
|
|
|
568
|
-
//# debugId=
|
|
573
|
+
//# debugId=78F873482F18940A64756E2164756E21
|
|
569
574
|
//# sourceMappingURL=tls.js.map
|
package/dist/tls.js.map
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/tls.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * @absolutejs/deploy/tls — ACME (RFC 8555) client for Let's Encrypt and\n * compatible CAs. DNS-01 challenges only — uses the {@link DnsProvider}\n * abstraction from `./dns`, so the same Cloudflare / Route 53 /\n * Hetzner-DNS providers that point hostnames at boxes also satisfy\n * ACME's challenge requirement.\n *\n * Zero peer deps. Bun's `crypto.subtle` covers JWS signing and ECDSA\n * key generation; a small DER encoder builds the CSR.\n *\n * Public API:\n *\n * issueCertificate({ domains, dnsProvider, email })\n * → { certificatePem, privateKeyPem, account, domains }\n *\n * installCertificateOnTarget(target, cert, { certPath, keyPath, reload? })\n * → uploads PEM files via Target.upload + optional reload exec\n *\n * exportAccountKey / importAccountKey for persistence between runs\n * (reuse the same account across cert renewals — cheaper, doesn't\n * hit Let's Encrypt's account-creation rate limit)\n */\n\nimport { X509Certificate } from 'node:crypto';\nimport type { Target } from './targets';\nimport type { DnsProvider } from './dns';\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nexport const LETSENCRYPT_PRODUCTION =\n\t'https://acme-v02.api.letsencrypt.org/directory';\nexport const LETSENCRYPT_STAGING =\n\t'https://acme-staging-v02.api.letsencrypt.org/directory';\n\n// =============================================================================\n// base64url\n// =============================================================================\n\nconst base64UrlEncode = (bytes: Uint8Array | ArrayBuffer): string => {\n\tconst buf = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);\n\tlet binary = '';\n\tfor (const byte of buf) binary += String.fromCharCode(byte);\n\treturn btoa(binary).replaceAll('+', '-').replaceAll('/', '_').replaceAll('=', '');\n};\n\nconst base64UrlEncodeString = (value: string): string =>\n\tbase64UrlEncode(new TextEncoder().encode(value));\n\nconst base64UrlDecode = (value: string): Uint8Array => {\n\tconst padded = value.replaceAll('-', '+').replaceAll('_', '/').padEnd(\n\t\tMath.ceil(value.length / 4) * 4,\n\t\t'='\n\t);\n\tconst binary = atob(padded);\n\tconst bytes = new Uint8Array(binary.length);\n\tfor (let index = 0; index < binary.length; index += 1) {\n\t\tbytes[index] = binary.charCodeAt(index);\n\t}\n\treturn bytes;\n};\n\n// =============================================================================\n// DER encoding (minimal subset for CSR)\n// =============================================================================\n\nconst derLength = (length: number): Uint8Array => {\n\tif (length < 0x80) return Uint8Array.from([length]);\n\tconst bytes: number[] = [];\n\tlet remaining = length;\n\twhile (remaining > 0) {\n\t\tbytes.unshift(remaining & 0xff);\n\t\tremaining >>= 8;\n\t}\n\treturn Uint8Array.from([0x80 | bytes.length, ...bytes]);\n};\n\nconst derTag = (tag: number, payload: Uint8Array): Uint8Array => {\n\tconst length = derLength(payload.length);\n\tconst out = new Uint8Array(1 + length.length + payload.length);\n\tout[0] = tag;\n\tout.set(length, 1);\n\tout.set(payload, 1 + length.length);\n\treturn out;\n};\n\nconst derSeq = (children: Uint8Array[]): Uint8Array => {\n\tconst total = children.reduce((sum, child) => sum + child.length, 0);\n\tconst payload = new Uint8Array(total);\n\tlet offset = 0;\n\tfor (const child of children) {\n\t\tpayload.set(child, offset);\n\t\toffset += child.length;\n\t}\n\treturn derTag(0x30, payload);\n};\n\nconst derSet = (children: Uint8Array[]): Uint8Array => {\n\tconst total = children.reduce((sum, child) => sum + child.length, 0);\n\tconst payload = new Uint8Array(total);\n\tlet offset = 0;\n\tfor (const child of children) {\n\t\tpayload.set(child, offset);\n\t\toffset += child.length;\n\t}\n\treturn derTag(0x31, payload);\n};\n\nconst derInt = (value: number | Uint8Array): Uint8Array => {\n\tif (typeof value === 'number') {\n\t\t// Small unsigned int — used for the CSR version field (0).\n\t\tif (value === 0) return derTag(0x02, Uint8Array.from([0]));\n\t\tconst bytes: number[] = [];\n\t\tlet remaining = value;\n\t\twhile (remaining > 0) {\n\t\t\tbytes.unshift(remaining & 0xff);\n\t\t\tremaining >>= 8;\n\t\t}\n\t\tif ((bytes[0] as number) & 0x80) bytes.unshift(0); // ensure positive\n\t\treturn derTag(0x02, Uint8Array.from(bytes));\n\t}\n\t// Big-endian unsigned bytes — strip leading zeros, then prepend 0x00 if\n\t// the high bit is set (DER INTEGER is signed two's complement).\n\tlet start = 0;\n\twhile (start < value.length - 1 && value[start] === 0) start += 1;\n\tlet payload = value.subarray(start);\n\tif ((payload[0] as number) & 0x80) {\n\t\tconst padded = new Uint8Array(payload.length + 1);\n\t\tpadded.set(payload, 1);\n\t\tpayload = padded;\n\t}\n\treturn derTag(0x02, payload);\n};\n\nconst derOid = (oid: string): Uint8Array => {\n\tconst parts = oid.split('.').map((part) => Number.parseInt(part, 10));\n\tconst first = parts[0];\n\tconst second = parts[1];\n\tif (first === undefined || second === undefined) {\n\t\tthrow new Error(`[deploy/tls] invalid OID: ${oid}`);\n\t}\n\tconst bytes: number[] = [first * 40 + second];\n\tfor (let index = 2; index < parts.length; index += 1) {\n\t\tconst value = parts[index] as number;\n\t\tconst chunks: number[] = [];\n\t\tlet remaining = value;\n\t\tdo {\n\t\t\tchunks.unshift(remaining & 0x7f);\n\t\t\tremaining >>= 7;\n\t\t} while (remaining > 0);\n\t\tfor (let chunkIndex = 0; chunkIndex < chunks.length - 1; chunkIndex += 1) {\n\t\t\tchunks[chunkIndex] = (chunks[chunkIndex] as number) | 0x80;\n\t\t}\n\t\tbytes.push(...chunks);\n\t}\n\treturn derTag(0x06, Uint8Array.from(bytes));\n};\n\nconst derPrintableString = (value: string): Uint8Array =>\n\tderTag(0x13, new TextEncoder().encode(value));\n\nconst derUtf8String = (value: string): Uint8Array =>\n\tderTag(0x0c, new TextEncoder().encode(value));\n\nconst derIa5String = (value: string): Uint8Array =>\n\tderTag(0x16, new TextEncoder().encode(value));\n\nconst derOctetString = (payload: Uint8Array): Uint8Array =>\n\tderTag(0x04, payload);\n\nconst derBitString = (payload: Uint8Array): Uint8Array => {\n\t// 0x00 prefix = number of unused bits in the final byte; for byte-aligned\n\t// signatures + keys this is always zero.\n\tconst bits = new Uint8Array(payload.length + 1);\n\tbits[0] = 0;\n\tbits.set(payload, 1);\n\treturn derTag(0x03, bits);\n};\n\nconst derContextTag = (\n\ttag: number,\n\tpayload: Uint8Array,\n\tconstructed = true\n): Uint8Array => derTag(0xa0 + tag + (constructed ? 0 : -0x20), payload);\n\n// =============================================================================\n// ECDSA signature: raw r||s ↔ DER SEQUENCE\n// =============================================================================\n\nconst ecdsaRawToDer = (rawSig: Uint8Array): Uint8Array => {\n\tconst half = rawSig.length / 2;\n\tconst r = rawSig.subarray(0, half);\n\tconst s = rawSig.subarray(half);\n\treturn derSeq([derInt(r), derInt(s)]);\n};\n\n// =============================================================================\n// JWS (RFC 7515) Flattened JSON Serialization for ACME\n// =============================================================================\n\ntype JwsHeader = {\n\talg: 'ES256';\n\tnonce: string;\n\turl: string;\n\tjwk?: JsonWebKey;\n\tkid?: string;\n};\n\ntype JwsBody = {\n\tprotected: string;\n\tpayload: string;\n\tsignature: string;\n};\n\nconst signJws = async (\n\tprivateKey: CryptoKey,\n\theader: JwsHeader,\n\tpayload: object | string\n): Promise<JwsBody> => {\n\tconst protectedHeader = base64UrlEncodeString(JSON.stringify(header));\n\tconst payloadEncoded =\n\t\tpayload === ''\n\t\t\t? '' // POST-as-GET: empty string, NOT empty object\n\t\t\t: base64UrlEncodeString(JSON.stringify(payload));\n\tconst signingInput = new TextEncoder().encode(\n\t\t`${protectedHeader}.${payloadEncoded}`\n\t);\n\tconst rawSig = new Uint8Array(\n\t\tawait crypto.subtle.sign(\n\t\t\t{ hash: 'SHA-256', name: 'ECDSA' },\n\t\t\tprivateKey,\n\t\t\tsigningInput\n\t\t)\n\t);\n\treturn {\n\t\tpayload: payloadEncoded,\n\t\tprotected: protectedHeader,\n\t\tsignature: base64UrlEncode(rawSig)\n\t};\n};\n\n// =============================================================================\n// JWK helpers — canonical thumbprint, public-key extraction\n// =============================================================================\n\nconst exportPublicJwk = async (publicKey: CryptoKey): Promise<JsonWebKey> => {\n\tconst jwk = await crypto.subtle.exportKey('jwk', publicKey);\n\t// Strip private fields if the export included them (shouldn't, on a\n\t// public key, but be defensive).\n\treturn {\n\t\tcrv: jwk.crv,\n\t\tkty: jwk.kty,\n\t\tx: jwk.x,\n\t\ty: jwk.y\n\t};\n};\n\nconst jwkThumbprint = async (publicJwk: JsonWebKey): Promise<string> => {\n\t// RFC 7638 — canonical JSON: required fields only, lex order.\n\tconst canonical = JSON.stringify({\n\t\tcrv: publicJwk.crv,\n\t\tkty: publicJwk.kty,\n\t\tx: publicJwk.x,\n\t\ty: publicJwk.y\n\t});\n\tconst hash = await crypto.subtle.digest(\n\t\t'SHA-256',\n\t\tnew TextEncoder().encode(canonical)\n\t);\n\treturn base64UrlEncode(hash);\n};\n\n// =============================================================================\n// Account key — generation + JSON export/import for persistence\n// =============================================================================\n\nexport type AcmeAccount = {\n\tkey: CryptoKeyPair;\n\t/** Account URL — set after first registration; persisted for renewals. */\n\tkid?: string;\n};\n\nexport type AcmeAccountJson = {\n\tpublicJwk: JsonWebKey;\n\tprivateJwk: JsonWebKey;\n\tkid?: string;\n};\n\nexport const generateAccountKey = async (): Promise<AcmeAccount> => {\n\tconst key = await crypto.subtle.generateKey(\n\t\t{ name: 'ECDSA', namedCurve: 'P-256' },\n\t\ttrue,\n\t\t['sign', 'verify']\n\t);\n\treturn { key };\n};\n\nexport const exportAccount = async (\n\taccount: AcmeAccount\n): Promise<AcmeAccountJson> => {\n\tconst publicJwk = await crypto.subtle.exportKey('jwk', account.key.publicKey);\n\tconst privateJwk = await crypto.subtle.exportKey(\n\t\t'jwk',\n\t\taccount.key.privateKey\n\t);\n\treturn {\n\t\tprivateJwk,\n\t\tpublicJwk,\n\t\t...(account.kid !== undefined ? { kid: account.kid } : {})\n\t};\n};\n\nexport const importAccount = async (\n\tjson: AcmeAccountJson\n): Promise<AcmeAccount> => {\n\tconst publicKey = await crypto.subtle.importKey(\n\t\t'jwk',\n\t\tjson.publicJwk,\n\t\t{ name: 'ECDSA', namedCurve: 'P-256' },\n\t\ttrue,\n\t\t['verify']\n\t);\n\tconst privateKey = await crypto.subtle.importKey(\n\t\t'jwk',\n\t\tjson.privateJwk,\n\t\t{ name: 'ECDSA', namedCurve: 'P-256' },\n\t\ttrue,\n\t\t['sign']\n\t);\n\treturn {\n\t\tkey: { privateKey, publicKey },\n\t\t...(json.kid !== undefined ? { kid: json.kid } : {})\n\t};\n};\n\n// =============================================================================\n// CSR — Certificate Signing Request\n// =============================================================================\n\nconst buildSanExtension = (domains: string[]): Uint8Array => {\n\t// SubjectAltName extension value: SEQUENCE OF GeneralName\n\tconst generalNames = domains.map((domain) =>\n\t\tderTag(0x82, new TextEncoder().encode(domain))\n\t);\n\tconst sanSequence = derSeq(generalNames);\n\tconst extensionValue = derOctetString(sanSequence);\n\treturn derSeq([derOid('2.5.29.17'), extensionValue]);\n};\n\nconst buildExtensionRequestAttribute = (domains: string[]): Uint8Array => {\n\tconst extensions = derSeq([buildSanExtension(domains)]);\n\treturn derSeq([\n\t\tderOid('1.2.840.113549.1.9.14'), // PKCS#9 extensionRequest\n\t\tderSet([extensions])\n\t]);\n};\n\nconst generateCertKeyPair = async (): Promise<CryptoKeyPair> =>\n\tcrypto.subtle.generateKey(\n\t\t{ name: 'ECDSA', namedCurve: 'P-256' },\n\t\ttrue,\n\t\t['sign', 'verify']\n\t);\n\nconst buildCsr = async (\n\tdomains: string[],\n\tkeypair: CryptoKeyPair\n): Promise<Uint8Array> => {\n\tif (domains.length === 0) {\n\t\tthrow new Error('[deploy/tls] CSR requires at least one domain');\n\t}\n\tconst commonName = domains[0] as string;\n\n\tconst spkiDer = new Uint8Array(\n\t\tawait crypto.subtle.exportKey('spki', keypair.publicKey)\n\t);\n\n\tconst version = derInt(0);\n\tconst subject = derSeq([\n\t\tderSet([\n\t\t\tderSeq([\n\t\t\t\tderOid('2.5.4.3'), // commonName\n\t\t\t\tderUtf8String(commonName)\n\t\t\t])\n\t\t])\n\t]);\n\n\tconst attributes = derContextTag(0, buildExtensionRequestAttribute(domains));\n\n\tconst certificationRequestInfo = derSeq([\n\t\tversion,\n\t\tsubject,\n\t\tspkiDer,\n\t\tattributes\n\t]);\n\n\tconst rawSig = new Uint8Array(\n\t\tawait crypto.subtle.sign(\n\t\t\t{ hash: 'SHA-256', name: 'ECDSA' },\n\t\t\tkeypair.privateKey,\n\t\t\tcertificationRequestInfo as BufferSource\n\t\t)\n\t);\n\tconst sigDer = ecdsaRawToDer(rawSig);\n\n\tconst sigAlgorithm = derSeq([derOid('1.2.840.10045.4.3.2')]);\n\t// ecdsa-with-SHA256\n\tconst signatureBits = derBitString(sigDer);\n\n\treturn derSeq([certificationRequestInfo, sigAlgorithm, signatureBits]);\n};\n\n// =============================================================================\n// PEM\n// =============================================================================\n\nconst derToPem = (label: string, der: Uint8Array): string => {\n\tconst b64 = btoa(String.fromCharCode(...der));\n\tconst lines = b64.match(/.{1,64}/g) ?? [];\n\treturn `-----BEGIN ${label}-----\\n${lines.join('\\n')}\\n-----END ${label}-----\\n`;\n};\n\nconst exportEcPrivateKeyPem = async (\n\tkeypair: CryptoKeyPair\n): Promise<string> => {\n\tconst pkcs8 = new Uint8Array(\n\t\tawait crypto.subtle.exportKey('pkcs8', keypair.privateKey)\n\t);\n\treturn derToPem('PRIVATE KEY', pkcs8);\n};\n\n// =============================================================================\n// ACME client\n// =============================================================================\n\ntype AcmeDirectory = {\n\tnewNonce: string;\n\tnewAccount: string;\n\tnewOrder: string;\n};\n\ntype AcmeOrder = {\n\tstatus: string;\n\tidentifiers: Array<{ type: string; value: string }>;\n\tauthorizations: string[];\n\tfinalize: string;\n\tcertificate?: string;\n};\n\ntype AcmeAuthorization = {\n\tstatus: string;\n\tidentifier: { type: string; value: string };\n\tchallenges: Array<{\n\t\ttype: string;\n\t\tstatus: string;\n\t\turl: string;\n\t\ttoken: string;\n\t}>;\n};\n\nexport type IssueCertificateOptions = {\n\t/** Domain(s) to include. First is the CN; all are SANs. */\n\tdomains: string[];\n\t/** DNS provider used for DNS-01 challenges (must own the zone). */\n\tdnsProvider: DnsProvider;\n\t/**\n\t * Map the public ACME challenge name to the record name written through\n\t * `dnsProvider`. Use this for CNAME-delegated DNS-01, where customers point\n\t * `_acme-challenge.app.example.com` at a platform-owned validation zone.\n\t * The propagation checker still receives the public challenge name because\n\t * that is what the certificate authority resolves.\n\t */\n\tmapDnsChallengeRecord?: (context: {\n\t\tdomain: string;\n\t\trecordName: string;\n\t}) => string;\n\t/** Contact email for the ACME account. */\n\temail: string;\n\t/** ACME directory URL. Default Let's Encrypt production. */\n\tdirectoryUrl?: string;\n\t/** Reuse an existing account. Pass `exportAccount`'s output via `importAccount`. */\n\taccount?: AcmeAccount;\n\t/** Override fetch (tests). Default global fetch. */\n\tfetch?: typeof fetch;\n\t/** Poll interval. Default 3 s. */\n\tpollIntervalMs?: number;\n\t/**\n\t * Max wait before notifying ACME that the DNS challenge is ready.\n\t * Set ~30-60s for Cloudflare; longer for slower providers. Default 30 s.\n\t */\n\tdnsPropagationDelayMs?: number;\n\t/** Max wait for the order to become valid. Default 5 min. */\n\torderTimeoutMs?: number;\n\t/** Status log lines. */\n\tonLog?: (line: string) => void;\n\t/** Override sleep (tests). */\n\tsleep?: (ms: number) => Promise<void>;\n\t/**\n\t * Optional pre-check: returns true when DNS has propagated globally.\n\t * Default: just wait `dnsPropagationDelayMs` then proceed. Override\n\t * for production to actually verify (e.g. resolve from multiple\n\t * public resolvers).\n\t */\n\tcheckDnsPropagated?: (\n\t\trecordName: string,\n\t\texpectedValue: string\n\t) => Promise<boolean>;\n};\n\nexport type IssuedCertificate = {\n\tcertificatePem: string;\n\tprivateKeyPem: string;\n\taccount: AcmeAccount;\n\tdomains: string[];\n};\n\nexport class AcmeError extends Error {\n\treadonly status: number;\n\treadonly body: unknown;\n\tconstructor(message: string, status: number, body: unknown) {\n\t\tsuper(message);\n\t\tthis.name = 'AcmeError';\n\t\tthis.status = status;\n\t\tthis.body = body;\n\t}\n}\n\nconst defaultSleep = (ms: number): Promise<void> =>\n\tnew Promise((resolve) => setTimeout(resolve, ms));\n\nexport const issueCertificate = async (\n\toptions: IssueCertificateOptions\n): Promise<IssuedCertificate> => {\n\tconst log = options.onLog ?? (() => {});\n\tconst sleep = options.sleep ?? defaultSleep;\n\tconst fetcher = options.fetch ?? fetch;\n\tconst directoryUrl = options.directoryUrl ?? LETSENCRYPT_PRODUCTION;\n\tconst pollMs = options.pollIntervalMs ?? 3_000;\n\tconst dnsDelay = options.dnsPropagationDelayMs ?? 30_000;\n\tconst orderTimeout = options.orderTimeoutMs ?? 5 * 60_000;\n\tconst account = options.account ?? (await generateAccountKey());\n\n\tif (options.domains.length === 0) {\n\t\tthrow new Error('[deploy/tls] at least one domain is required');\n\t}\n\n\t// 1. Fetch directory.\n\tlog(`[tls] fetching ACME directory ${directoryUrl}`);\n\tconst directoryResponse = await fetcher(directoryUrl);\n\tif (!directoryResponse.ok) {\n\t\tthrow new AcmeError(\n\t\t\t`failed to fetch ACME directory: ${directoryResponse.status}`,\n\t\t\tdirectoryResponse.status,\n\t\t\tawait directoryResponse.text()\n\t\t);\n\t}\n\tconst directory = (await directoryResponse.json()) as AcmeDirectory;\n\n\t// 2. Get initial nonce.\n\tlet nonce = await fetchNonce(fetcher, directory.newNonce);\n\n\t// Helper: signed POST. Tracks nonce; returns parsed JSON body + headers.\n\tconst post = async (\n\t\turl: string,\n\t\tpayload: object | string,\n\t\tidentification: { kid?: string; jwk?: JsonWebKey }\n\t): Promise<{ status: number; body: unknown; headers: Headers }> => {\n\t\tconst header: JwsHeader = {\n\t\t\talg: 'ES256',\n\t\t\tnonce,\n\t\t\turl,\n\t\t\t...(identification.kid !== undefined ? { kid: identification.kid } : {}),\n\t\t\t...(identification.jwk !== undefined ? { jwk: identification.jwk } : {})\n\t\t};\n\t\tconst jws = await signJws(account.key.privateKey, header, payload);\n\t\tconst response = await fetcher(url, {\n\t\t\tbody: JSON.stringify(jws),\n\t\t\theaders: { 'content-type': 'application/jose+json' },\n\t\t\tmethod: 'POST'\n\t\t});\n\t\tconst newNonce = response.headers.get('replay-nonce');\n\t\tif (newNonce !== null) nonce = newNonce;\n\t\tconst text = await response.text();\n\t\tconst body =\n\t\t\ttext.length > 0 && response.headers.get('content-type')?.includes('json')\n\t\t\t\t? JSON.parse(text)\n\t\t\t\t: text;\n\t\tif (!response.ok) {\n\t\t\tthrow new AcmeError(\n\t\t\t\t`ACME ${url} → ${response.status}`,\n\t\t\t\tresponse.status,\n\t\t\t\tbody\n\t\t\t);\n\t\t}\n\t\treturn { body, headers: response.headers, status: response.status };\n\t};\n\n\t// 3. Register the account (or reuse if kid is set).\n\tconst publicJwk = await exportPublicJwk(account.key.publicKey);\n\tif (account.kid === undefined) {\n\t\tlog(`[tls] registering ACME account for ${options.email}`);\n\t\tconst result = await post(\n\t\t\tdirectory.newAccount,\n\t\t\t{\n\t\t\t\tcontact: [`mailto:${options.email}`],\n\t\t\t\ttermsOfServiceAgreed: true\n\t\t\t},\n\t\t\t{ jwk: publicJwk }\n\t\t);\n\t\taccount.kid = result.headers.get('location') ?? undefined;\n\t\tif (account.kid === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t'[deploy/tls] ACME newAccount response missing Location header'\n\t\t\t);\n\t\t}\n\t\tlog(`[tls] account registered: ${account.kid}`);\n\t} else {\n\t\tlog(`[tls] reusing account ${account.kid}`);\n\t}\n\n\tconst accountKid = account.kid;\n\n\t// 4. Submit the order.\n\tlog(`[tls] submitting order for ${options.domains.join(', ')}`);\n\tconst orderResult = await post(\n\t\tdirectory.newOrder,\n\t\t{\n\t\t\tidentifiers: options.domains.map((domain) => ({\n\t\t\t\ttype: 'dns',\n\t\t\t\tvalue: domain\n\t\t\t}))\n\t\t},\n\t\t{ kid: accountKid }\n\t);\n\tlet order = orderResult.body as AcmeOrder;\n\tconst orderUrl = orderResult.headers.get('location');\n\tif (orderUrl === null) {\n\t\tthrow new Error(\n\t\t\t'[deploy/tls] ACME newOrder response missing Location header'\n\t\t);\n\t}\n\n\t// 5. For each authorization, complete the DNS-01 challenge.\n\tconst cleanups: Array<() => Promise<void>> = [];\n\tconst dnsCreated: Array<{\n\t\trecordId: string;\n\t\trecordName: string;\n\t\trecordValue: string;\n\t}> = [];\n\n\ttry {\n\t\tconst thumbprint = await jwkThumbprint(publicJwk);\n\n\t\tfor (const authUrl of order.authorizations) {\n\t\t\tconst authResult = await post(authUrl, '', { kid: accountKid });\n\t\t\tconst auth = authResult.body as AcmeAuthorization;\n\t\t\tconst challenge = auth.challenges.find((c) => c.type === 'dns-01');\n\t\t\tif (challenge === undefined) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`[deploy/tls] no dns-01 challenge for ${auth.identifier.value}`\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst keyAuthorization = `${challenge.token}.${thumbprint}`;\n\t\t\tconst txtBytes = new Uint8Array(\n\t\t\t\tawait crypto.subtle.digest(\n\t\t\t\t\t'SHA-256',\n\t\t\t\t\tnew TextEncoder().encode(keyAuthorization)\n\t\t\t\t)\n\t\t\t);\n\t\t\tconst txtValue = base64UrlEncode(txtBytes);\n\t\t\tconst recordName = `_acme-challenge.${auth.identifier.value}`;\n\t\t\tconst providerRecordName =\n\t\t\t\toptions.mapDnsChallengeRecord?.({\n\t\t\t\t\tdomain: auth.identifier.value,\n\t\t\t\t\trecordName\n\t\t\t\t}) ?? recordName;\n\t\t\tif (providerRecordName.trim().length === 0) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'[deploy/tls] mapped DNS-01 record name must not be empty'\n\t\t\t\t);\n\t\t\t}\n\t\t\tlog(\n\t\t\t\tproviderRecordName === recordName\n\t\t\t\t\t? `[tls] DNS-01: setting ${recordName} = \"${txtValue}\"`\n\t\t\t\t\t: `[tls] DNS-01: setting delegated ${providerRecordName} for ${recordName} = \"${txtValue}\"`\n\t\t\t);\n\t\t\tconst record = await options.dnsProvider.upsert({\n\t\t\t\tcontent: txtValue,\n\t\t\t\tname: providerRecordName,\n\t\t\t\tttl: 60,\n\t\t\t\ttype: 'TXT'\n\t\t\t});\n\t\t\tdnsCreated.push({\n\t\t\t\trecordId: record.id,\n\t\t\t\trecordName: providerRecordName,\n\t\t\t\trecordValue: txtValue\n\t\t\t});\n\t\t\tcleanups.push(() => options.dnsProvider.delete(record.id));\n\n\t\t\tif (options.checkDnsPropagated !== undefined) {\n\t\t\t\tlog('[tls] waiting for DNS propagation (custom checker)…');\n\t\t\t\tconst deadline = Date.now() + dnsDelay;\n\t\t\t\twhile (Date.now() < deadline) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tawait options.checkDnsPropagated(recordName, txtValue)\n\t\t\t\t\t) break;\n\t\t\t\t\tawait sleep(pollMs);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlog(`[tls] sleeping ${dnsDelay}ms for DNS propagation`);\n\t\t\t\tawait sleep(dnsDelay);\n\t\t\t}\n\n\t\t\tlog(`[tls] notifying ACME of dns-01 readiness for ${auth.identifier.value}`);\n\t\t\tawait post(challenge.url, {}, { kid: accountKid });\n\n\t\t\t// Poll the authorization until valid/invalid.\n\t\t\tconst authDeadline = Date.now() + orderTimeout;\n\t\t\twhile (Date.now() < authDeadline) {\n\t\t\t\tconst polledResult = await post(authUrl, '', { kid: accountKid });\n\t\t\t\tconst polled = polledResult.body as AcmeAuthorization;\n\t\t\t\tif (polled.status === 'valid') break;\n\t\t\t\tif (polled.status === 'invalid') {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`[deploy/tls] authorization failed for ${auth.identifier.value}: ${JSON.stringify(polled.challenges)}`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tawait sleep(pollMs);\n\t\t\t}\n\t\t}\n\n\t\t// 6. Finalize — generate cert keypair + CSR.\n\t\tlog('[tls] generating cert keypair + CSR');\n\t\tconst certKey = await generateCertKeyPair();\n\t\tconst csrDer = await buildCsr(options.domains, certKey);\n\t\tconst csr = base64UrlEncode(csrDer);\n\n\t\tawait post(order.finalize, { csr }, { kid: accountKid });\n\n\t\t// 7. Poll the order until valid + certificate URL appears.\n\t\tconst orderDeadline = Date.now() + orderTimeout;\n\t\twhile (Date.now() < orderDeadline) {\n\t\t\tconst refreshed = await post(orderUrl, '', { kid: accountKid });\n\t\t\torder = refreshed.body as AcmeOrder;\n\t\t\tif (order.status === 'valid' && order.certificate !== undefined) break;\n\t\t\tif (order.status === 'invalid') {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`[deploy/tls] order failed: ${JSON.stringify(order)}`\n\t\t\t\t);\n\t\t\t}\n\t\t\tawait sleep(pollMs);\n\t\t}\n\n\t\tif (order.certificate === undefined) {\n\t\t\tthrow new Error('[deploy/tls] order timed out before issuing certificate');\n\t\t}\n\n\t\t// 8. Download the cert (PEM bundle).\n\t\tlog(`[tls] downloading certificate from ${order.certificate}`);\n\t\tconst certResult = await post(order.certificate, '', { kid: accountKid });\n\t\tconst certificatePem =\n\t\t\ttypeof certResult.body === 'string'\n\t\t\t\t? certResult.body\n\t\t\t\t: String(certResult.body);\n\n\t\tconst privateKeyPem = await exportEcPrivateKeyPem(certKey);\n\n\t\treturn {\n\t\t\taccount,\n\t\t\tcertificatePem,\n\t\t\tdomains: options.domains,\n\t\t\tprivateKeyPem\n\t\t};\n\t} finally {\n\t\tfor (const cleanup of cleanups) {\n\t\t\ttry {\n\t\t\t\tawait cleanup();\n\t\t\t} catch (error) {\n\t\t\t\tlog(`[tls] cleanup failed (continuing): ${String(error)}`);\n\t\t\t}\n\t\t}\n\t\t// Suppress unused-variable lint without changing behavior.\n\t\tvoid dnsCreated;\n\t}\n};\n\nconst fetchNonce = async (\n\tfetcher: typeof fetch,\n\turl: string\n): Promise<string> => {\n\tconst response = await fetcher(url, { method: 'HEAD' });\n\tconst nonce = response.headers.get('replay-nonce');\n\tif (nonce === null) {\n\t\tthrow new Error('[deploy/tls] newNonce response missing Replay-Nonce header');\n\t}\n\treturn nonce;\n};\n\n// =============================================================================\n// installCertificateOnTarget\n// =============================================================================\n\nexport type InstallCertificateOptions = {\n\t/** Remote path for the cert chain. Default `/etc/ssl/<firstDomain>/fullchain.pem`. */\n\tcertPath?: string;\n\t/** Remote path for the private key. Default `/etc/ssl/<firstDomain>/privkey.pem`. */\n\tkeyPath?: string;\n\t/** Mode (chmod) for the cert + key. Default `600`. */\n\tmode?: string;\n\t/** Owner (chown) for the cert + key. Default unchanged. */\n\towner?: string;\n\t/** Optional reload command run after install (e.g. `'systemctl reload nginx'`). */\n\treload?: string;\n\t/** Override the writeTo helper (tests). */\n\twriteFile?: (target: Target, path: string, contents: string) => Promise<void>;\n};\n\nconst defaultWriteFile = async (\n\ttarget: Target,\n\tremotePath: string,\n\tcontents: string\n): Promise<void> => {\n\tconst escaped = contents.replaceAll(\"'\", \"'\\\\''\");\n\tawait target.exec(`mkdir -p \"$(dirname '${remotePath}')\"`);\n\tawait target.exec(`cat > '${remotePath}' <<'__ABS_TLS_EOF__'\\n${contents}__ABS_TLS_EOF__\\n`);\n\tvoid escaped;\n};\n\n/**\n * @internal — exposed for unit testing of cryptographic primitives.\n * Not part of the public API; consumers should NOT depend on this.\n */\nexport const __testing = {\n\tbase64UrlDecode,\n\tbase64UrlEncode,\n\tbase64UrlEncodeString,\n\tbuildCsr,\n\tderBitString,\n\tderInt,\n\tderOid,\n\tderSeq,\n\tderSet,\n\tecdsaRawToDer,\n\texportEcPrivateKeyPem,\n\texportPublicJwk,\n\tgenerateCertKeyPair,\n\tjwkThumbprint,\n\tsignJws\n};\n\n/**\n * Upload cert + private key to the target. Composable with the deploy\n * pipeline as a verify-step or post-deploy hook.\n */\nexport const installCertificateOnTarget = async (\n\ttarget: Target,\n\tcert: IssuedCertificate,\n\toptions: InstallCertificateOptions = {}\n): Promise<{ certPath: string; keyPath: string }> => {\n\tconst domain = cert.domains[0];\n\tif (domain === undefined) {\n\t\tthrow new Error('[deploy/tls] certificate has no domains');\n\t}\n\tconst certPath = options.certPath ?? `/etc/ssl/${domain}/fullchain.pem`;\n\tconst keyPath = options.keyPath ?? `/etc/ssl/${domain}/privkey.pem`;\n\tconst mode = options.mode ?? '600';\n\tconst writer = options.writeFile ?? defaultWriteFile;\n\n\tawait writer(target, certPath, cert.certificatePem);\n\tawait writer(target, keyPath, cert.privateKeyPem);\n\tawait target.exec(`chmod ${mode} '${certPath}' '${keyPath}'`);\n\tif (options.owner !== undefined) {\n\t\tawait target.exec(`chown ${options.owner} '${certPath}' '${keyPath}'`);\n\t}\n\tif (options.reload !== undefined) {\n\t\tawait target.exec(options.reload);\n\t}\n\n\treturn { certPath, keyPath };\n};\n\n// =============================================================================\n// Certificate inspection + renewal scheduling\n// =============================================================================\n\nexport type CertificateInspection = {\n\t/** CN + every SAN, deduplicated. */\n\tsubjects: string[];\n\t/** Issuance time, ms since epoch. */\n\tvalidFrom: number;\n\t/** Expiration time, ms since epoch. */\n\tvalidTo: number;\n\t/** Whole days remaining before `validTo`. Negative if expired. */\n\tdaysRemaining: number;\n\t/** True when the cert is past `validTo`. */\n\texpired: boolean;\n\t/** Issuer DN string (for \"Let's Encrypt vs staging vs other CA\" checks). */\n\tissuer: string;\n};\n\nconst parseSubjects = (x509: X509Certificate): string[] => {\n\tconst subjects = new Set<string>();\n\tconst cnMatch = x509.subject.match(/CN=([^,\\n]+)/);\n\tif (cnMatch !== null && cnMatch[1] !== undefined) {\n\t\tsubjects.add(cnMatch[1].trim());\n\t}\n\tconst san = x509.subjectAltName;\n\tif (san !== undefined && san !== null) {\n\t\tfor (const part of san.split(',')) {\n\t\t\tconst dnsMatch = part.trim().match(/^DNS:(.+)$/);\n\t\t\tif (dnsMatch !== null && dnsMatch[1] !== undefined) {\n\t\t\t\tsubjects.add(dnsMatch[1].trim());\n\t\t\t}\n\t\t}\n\t}\n\treturn [...subjects];\n};\n\n/**\n * Parse a PEM certificate into operator-shaped metadata. Used by\n * {@link renewCertificate} to decide whether to re-issue; also fine\n * for status pages and observability.\n */\nexport const inspectCertificate = (\n\tpem: string,\n\toptions: { now?: () => number } = {}\n): CertificateInspection => {\n\tconst x509 = new X509Certificate(pem);\n\tconst validFrom = new Date(x509.validFrom).getTime();\n\tconst validTo = new Date(x509.validTo).getTime();\n\tconst now = (options.now ?? Date.now)();\n\tconst daysRemaining = Math.floor(\n\t\t(validTo - now) / (24 * 60 * 60 * 1000)\n\t);\n\treturn {\n\t\tdaysRemaining,\n\t\texpired: validTo < now,\n\t\tissuer: x509.issuer,\n\t\tsubjects: parseSubjects(x509),\n\t\tvalidFrom,\n\t\tvalidTo\n\t};\n};\n\nexport type RenewCertificateOptions = IssueCertificateOptions & {\n\t/**\n\t * Current cert PEM. When provided, the cert's `validTo` decides\n\t * whether to re-issue; when absent, renewal always issues.\n\t */\n\tcurrentCertificatePem?: string;\n\t/**\n\t * Re-issue when fewer than this many days remain. Default 30,\n\t * matching certbot's standard schedule (Let's Encrypt issues 90-day\n\t * certs; renewing at 30 days leaves a 60-day error budget).\n\t */\n\trenewWhenDaysRemaining?: number;\n\t/** Force re-issue regardless of remaining days. Default false. */\n\tforce?: boolean;\n\t/** Override `Date.now()` for testing. */\n\tnow?: () => number;\n};\n\nexport type RenewalResult =\n\t| {\n\t\t\trenewed: true;\n\t\t\tcertificate: IssuedCertificate;\n\t\t\treason: 'forced' | 'no-current-cert' | 'expiring-soon';\n\t }\n\t| {\n\t\t\trenewed: false;\n\t\t\treason: 'still-fresh';\n\t\t\tinspection: CertificateInspection;\n\t };\n\n/**\n * Conditional cert renewal. Parses the supplied cert (if any),\n * decides whether to re-issue based on remaining days, and either\n * returns the existing cert info (\"still fresh\") or issues a new\n * one via {@link issueCertificate}.\n *\n * Wire to a scheduled function (cron / @absolutejs/sync schedule /\n * GitHub Action) running at least once a week. Idempotent: a fresh\n * cert returns `renewed: false` cheaply (one PEM parse, zero\n * network IO).\n *\n * @example\n * const result = await renewCertificate({\n * currentCertificatePem: existingPem, // omit to force first-issue\n * domains: ['api.example.com'],\n * dnsProvider: dns,\n * email: 'ops@example.com',\n * account: persistedAccount, // reuse to avoid CA rate limit\n * });\n * if (result.renewed) {\n * await installCertificateOnTarget(target, result.certificate, { reload });\n * }\n */\nexport const renewCertificate = async (\n\toptions: RenewCertificateOptions\n): Promise<RenewalResult> => {\n\tconst threshold = options.renewWhenDaysRemaining ?? 30;\n\tif (threshold < 0) {\n\t\tthrow new Error(\n\t\t\t'[deploy/tls] renewWhenDaysRemaining must be non-negative'\n\t\t);\n\t}\n\n\tif (options.force === true) {\n\t\tconst certificate = await issueCertificate(options);\n\t\treturn { certificate, reason: 'forced', renewed: true };\n\t}\n\n\tif (options.currentCertificatePem === undefined) {\n\t\tconst certificate = await issueCertificate(options);\n\t\treturn { certificate, reason: 'no-current-cert', renewed: true };\n\t}\n\n\tconst nowFn = options.now ?? Date.now;\n\tconst inspection = inspectCertificate(options.currentCertificatePem, {\n\t\tnow: nowFn\n\t});\n\n\tif (!inspection.expired && inspection.daysRemaining >= threshold) {\n\t\treturn { inspection, reason: 'still-fresh', renewed: false };\n\t}\n\n\tconst certificate = await issueCertificate(options);\n\treturn { certificate, reason: 'expiring-soon', renewed: true };\n};\n"
|
|
5
|
+
"/**\n * @absolutejs/deploy/tls — ACME (RFC 8555) client for Let's Encrypt and\n * compatible CAs. DNS-01 challenges only — uses the {@link DnsProvider}\n * abstraction from `./dns`, so the same Cloudflare / Route 53 /\n * Hetzner-DNS providers that point hostnames at boxes also satisfy\n * ACME's challenge requirement.\n *\n * Zero peer deps. Bun's `crypto.subtle` covers JWS signing and ECDSA\n * key generation; a small DER encoder builds the CSR.\n *\n * Public API:\n *\n * issueCertificate({ domains, dnsProvider, email })\n * → { certificatePem, privateKeyPem, account, domains }\n *\n * installCertificateOnTarget(target, cert, { certPath, keyPath, reload? })\n * → uploads PEM files via Target.upload + optional reload exec\n *\n * exportAccountKey / importAccountKey for persistence between runs\n * (reuse the same account across cert renewals — cheaper, doesn't\n * hit Let's Encrypt's account-creation rate limit)\n */\n\nimport { X509Certificate } from \"node:crypto\";\nimport type { Target } from \"./targets\";\nimport type { DnsProvider } from \"./dns\";\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nexport const LETSENCRYPT_PRODUCTION =\n \"https://acme-v02.api.letsencrypt.org/directory\";\nexport const LETSENCRYPT_STAGING =\n \"https://acme-staging-v02.api.letsencrypt.org/directory\";\n\n// =============================================================================\n// base64url\n// =============================================================================\n\nconst base64UrlEncode = (bytes: Uint8Array | ArrayBuffer): string => {\n const buf = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);\n let binary = \"\";\n for (const byte of buf) binary += String.fromCharCode(byte);\n return btoa(binary)\n .replaceAll(\"+\", \"-\")\n .replaceAll(\"/\", \"_\")\n .replaceAll(\"=\", \"\");\n};\n\nconst base64UrlEncodeString = (value: string): string =>\n base64UrlEncode(new TextEncoder().encode(value));\n\nconst base64UrlDecode = (value: string): Uint8Array => {\n const padded = value\n .replaceAll(\"-\", \"+\")\n .replaceAll(\"_\", \"/\")\n .padEnd(Math.ceil(value.length / 4) * 4, \"=\");\n const binary = atob(padded);\n const bytes = new Uint8Array(binary.length);\n for (let index = 0; index < binary.length; index += 1) {\n bytes[index] = binary.charCodeAt(index);\n }\n return bytes;\n};\n\n// =============================================================================\n// DER encoding (minimal subset for CSR)\n// =============================================================================\n\nconst derLength = (length: number): Uint8Array => {\n if (length < 0x80) return Uint8Array.from([length]);\n const bytes: number[] = [];\n let remaining = length;\n while (remaining > 0) {\n bytes.unshift(remaining & 0xff);\n remaining >>= 8;\n }\n return Uint8Array.from([0x80 | bytes.length, ...bytes]);\n};\n\nconst derTag = (tag: number, payload: Uint8Array): Uint8Array => {\n const length = derLength(payload.length);\n const out = new Uint8Array(1 + length.length + payload.length);\n out[0] = tag;\n out.set(length, 1);\n out.set(payload, 1 + length.length);\n return out;\n};\n\nconst derSeq = (children: Uint8Array[]): Uint8Array => {\n const total = children.reduce((sum, child) => sum + child.length, 0);\n const payload = new Uint8Array(total);\n let offset = 0;\n for (const child of children) {\n payload.set(child, offset);\n offset += child.length;\n }\n return derTag(0x30, payload);\n};\n\nconst derSet = (children: Uint8Array[]): Uint8Array => {\n const total = children.reduce((sum, child) => sum + child.length, 0);\n const payload = new Uint8Array(total);\n let offset = 0;\n for (const child of children) {\n payload.set(child, offset);\n offset += child.length;\n }\n return derTag(0x31, payload);\n};\n\nconst derInt = (value: number | Uint8Array): Uint8Array => {\n if (typeof value === \"number\") {\n // Small unsigned int — used for the CSR version field (0).\n if (value === 0) return derTag(0x02, Uint8Array.from([0]));\n const bytes: number[] = [];\n let remaining = value;\n while (remaining > 0) {\n bytes.unshift(remaining & 0xff);\n remaining >>= 8;\n }\n if ((bytes[0] as number) & 0x80) bytes.unshift(0); // ensure positive\n return derTag(0x02, Uint8Array.from(bytes));\n }\n // Big-endian unsigned bytes — strip leading zeros, then prepend 0x00 if\n // the high bit is set (DER INTEGER is signed two's complement).\n let start = 0;\n while (start < value.length - 1 && value[start] === 0) start += 1;\n let payload = value.subarray(start);\n if ((payload[0] as number) & 0x80) {\n const padded = new Uint8Array(payload.length + 1);\n padded.set(payload, 1);\n payload = padded;\n }\n return derTag(0x02, payload);\n};\n\nconst derOid = (oid: string): Uint8Array => {\n const parts = oid.split(\".\").map((part) => Number.parseInt(part, 10));\n const first = parts[0];\n const second = parts[1];\n if (first === undefined || second === undefined) {\n throw new Error(`[deploy/tls] invalid OID: ${oid}`);\n }\n const bytes: number[] = [first * 40 + second];\n for (let index = 2; index < parts.length; index += 1) {\n const value = parts[index] as number;\n const chunks: number[] = [];\n let remaining = value;\n do {\n chunks.unshift(remaining & 0x7f);\n remaining >>= 7;\n } while (remaining > 0);\n for (let chunkIndex = 0; chunkIndex < chunks.length - 1; chunkIndex += 1) {\n chunks[chunkIndex] = (chunks[chunkIndex] as number) | 0x80;\n }\n bytes.push(...chunks);\n }\n return derTag(0x06, Uint8Array.from(bytes));\n};\n\nconst derPrintableString = (value: string): Uint8Array =>\n derTag(0x13, new TextEncoder().encode(value));\n\nconst derUtf8String = (value: string): Uint8Array =>\n derTag(0x0c, new TextEncoder().encode(value));\n\nconst derIa5String = (value: string): Uint8Array =>\n derTag(0x16, new TextEncoder().encode(value));\n\nconst derOctetString = (payload: Uint8Array): Uint8Array =>\n derTag(0x04, payload);\n\nconst derBitString = (payload: Uint8Array): Uint8Array => {\n // 0x00 prefix = number of unused bits in the final byte; for byte-aligned\n // signatures + keys this is always zero.\n const bits = new Uint8Array(payload.length + 1);\n bits[0] = 0;\n bits.set(payload, 1);\n return derTag(0x03, bits);\n};\n\nconst derContextTag = (\n tag: number,\n payload: Uint8Array,\n constructed = true,\n): Uint8Array => derTag(0xa0 + tag + (constructed ? 0 : -0x20), payload);\n\n// =============================================================================\n// ECDSA signature: raw r||s ↔ DER SEQUENCE\n// =============================================================================\n\nconst ecdsaRawToDer = (rawSig: Uint8Array): Uint8Array => {\n const half = rawSig.length / 2;\n const r = rawSig.subarray(0, half);\n const s = rawSig.subarray(half);\n return derSeq([derInt(r), derInt(s)]);\n};\n\n// =============================================================================\n// JWS (RFC 7515) Flattened JSON Serialization for ACME\n// =============================================================================\n\ntype JwsHeader = {\n alg: \"ES256\";\n nonce: string;\n url: string;\n jwk?: JsonWebKey;\n kid?: string;\n};\n\ntype JwsBody = {\n protected: string;\n payload: string;\n signature: string;\n};\n\nconst signJws = async (\n privateKey: CryptoKey,\n header: JwsHeader,\n payload: object | string,\n): Promise<JwsBody> => {\n const protectedHeader = base64UrlEncodeString(JSON.stringify(header));\n const payloadEncoded =\n payload === \"\"\n ? \"\" // POST-as-GET: empty string, NOT empty object\n : base64UrlEncodeString(JSON.stringify(payload));\n const signingInput = new TextEncoder().encode(\n `${protectedHeader}.${payloadEncoded}`,\n );\n const rawSig = new Uint8Array(\n await crypto.subtle.sign(\n { hash: \"SHA-256\", name: \"ECDSA\" },\n privateKey,\n signingInput,\n ),\n );\n return {\n payload: payloadEncoded,\n protected: protectedHeader,\n signature: base64UrlEncode(rawSig),\n };\n};\n\n// =============================================================================\n// JWK helpers — canonical thumbprint, public-key extraction\n// =============================================================================\n\nconst exportPublicJwk = async (publicKey: CryptoKey): Promise<JsonWebKey> => {\n const jwk = await crypto.subtle.exportKey(\"jwk\", publicKey);\n // Strip private fields if the export included them (shouldn't, on a\n // public key, but be defensive).\n return {\n crv: jwk.crv,\n kty: jwk.kty,\n x: jwk.x,\n y: jwk.y,\n };\n};\n\nconst jwkThumbprint = async (publicJwk: JsonWebKey): Promise<string> => {\n // RFC 7638 — canonical JSON: required fields only, lex order.\n const canonical = JSON.stringify({\n crv: publicJwk.crv,\n kty: publicJwk.kty,\n x: publicJwk.x,\n y: publicJwk.y,\n });\n const hash = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(canonical),\n );\n return base64UrlEncode(hash);\n};\n\n// =============================================================================\n// Account key — generation + JSON export/import for persistence\n// =============================================================================\n\nexport type AcmeAccount = {\n key: CryptoKeyPair;\n /** Account URL — set after first registration; persisted for renewals. */\n kid?: string;\n};\n\nexport type AcmeAccountJson = {\n publicJwk: JsonWebKey;\n privateJwk: JsonWebKey;\n kid?: string;\n};\n\nexport const generateAccountKey = async (): Promise<AcmeAccount> => {\n const key = await crypto.subtle.generateKey(\n { name: \"ECDSA\", namedCurve: \"P-256\" },\n true,\n [\"sign\", \"verify\"],\n );\n return { key };\n};\n\nexport const exportAccount = async (\n account: AcmeAccount,\n): Promise<AcmeAccountJson> => {\n const publicJwk = await crypto.subtle.exportKey(\"jwk\", account.key.publicKey);\n const privateJwk = await crypto.subtle.exportKey(\n \"jwk\",\n account.key.privateKey,\n );\n return {\n privateJwk,\n publicJwk,\n ...(account.kid !== undefined ? { kid: account.kid } : {}),\n };\n};\n\nexport const importAccount = async (\n json: AcmeAccountJson,\n): Promise<AcmeAccount> => {\n const publicKey = await crypto.subtle.importKey(\n \"jwk\",\n json.publicJwk,\n { name: \"ECDSA\", namedCurve: \"P-256\" },\n true,\n [\"verify\"],\n );\n const privateKey = await crypto.subtle.importKey(\n \"jwk\",\n json.privateJwk,\n { name: \"ECDSA\", namedCurve: \"P-256\" },\n true,\n [\"sign\"],\n );\n return {\n key: { privateKey, publicKey },\n ...(json.kid !== undefined ? { kid: json.kid } : {}),\n };\n};\n\n// =============================================================================\n// CSR — Certificate Signing Request\n// =============================================================================\n\nconst buildSanExtension = (domains: string[]): Uint8Array => {\n // SubjectAltName extension value: SEQUENCE OF GeneralName\n const generalNames = domains.map((domain) =>\n derTag(0x82, new TextEncoder().encode(domain)),\n );\n const sanSequence = derSeq(generalNames);\n const extensionValue = derOctetString(sanSequence);\n return derSeq([derOid(\"2.5.29.17\"), extensionValue]);\n};\n\nconst buildExtensionRequestAttribute = (domains: string[]): Uint8Array => {\n const extensions = derSeq([buildSanExtension(domains)]);\n return derSeq([\n derOid(\"1.2.840.113549.1.9.14\"), // PKCS#9 extensionRequest\n derSet([extensions]),\n ]);\n};\n\nconst generateCertKeyPair = async (): Promise<CryptoKeyPair> =>\n crypto.subtle.generateKey({ name: \"ECDSA\", namedCurve: \"P-256\" }, true, [\n \"sign\",\n \"verify\",\n ]);\n\nconst buildCsr = async (\n domains: string[],\n keypair: CryptoKeyPair,\n): Promise<Uint8Array> => {\n if (domains.length === 0) {\n throw new Error(\"[deploy/tls] CSR requires at least one domain\");\n }\n const commonName = domains[0] as string;\n\n const spkiDer = new Uint8Array(\n await crypto.subtle.exportKey(\"spki\", keypair.publicKey),\n );\n\n const version = derInt(0);\n const subject = derSeq([\n derSet([\n derSeq([\n derOid(\"2.5.4.3\"), // commonName\n derUtf8String(commonName),\n ]),\n ]),\n ]);\n\n const attributes = derContextTag(0, buildExtensionRequestAttribute(domains));\n\n const certificationRequestInfo = derSeq([\n version,\n subject,\n spkiDer,\n attributes,\n ]);\n\n const rawSig = new Uint8Array(\n await crypto.subtle.sign(\n { hash: \"SHA-256\", name: \"ECDSA\" },\n keypair.privateKey,\n certificationRequestInfo as BufferSource,\n ),\n );\n const sigDer = ecdsaRawToDer(rawSig);\n\n const sigAlgorithm = derSeq([derOid(\"1.2.840.10045.4.3.2\")]);\n // ecdsa-with-SHA256\n const signatureBits = derBitString(sigDer);\n\n return derSeq([certificationRequestInfo, sigAlgorithm, signatureBits]);\n};\n\n// =============================================================================\n// PEM\n// =============================================================================\n\nconst derToPem = (label: string, der: Uint8Array): string => {\n const b64 = btoa(String.fromCharCode(...der));\n const lines = b64.match(/.{1,64}/g) ?? [];\n return `-----BEGIN ${label}-----\\n${lines.join(\"\\n\")}\\n-----END ${label}-----\\n`;\n};\n\nconst exportEcPrivateKeyPem = async (\n keypair: CryptoKeyPair,\n): Promise<string> => {\n const pkcs8 = new Uint8Array(\n await crypto.subtle.exportKey(\"pkcs8\", keypair.privateKey),\n );\n return derToPem(\"PRIVATE KEY\", pkcs8);\n};\n\n// =============================================================================\n// ACME client\n// =============================================================================\n\ntype AcmeDirectory = {\n newNonce: string;\n newAccount: string;\n newOrder: string;\n};\n\ntype AcmeOrder = {\n status: string;\n identifiers: Array<{ type: string; value: string }>;\n authorizations: string[];\n finalize: string;\n certificate?: string;\n};\n\ntype AcmeAuthorization = {\n status: string;\n identifier: { type: string; value: string };\n challenges: Array<{\n type: string;\n status: string;\n url: string;\n token: string;\n }>;\n};\n\nexport type IssueCertificateOptions = {\n /** Domain(s) to include. First is the CN; all are SANs. */\n domains: string[];\n /** DNS provider used for DNS-01 challenges (must own the zone). */\n dnsProvider: DnsProvider;\n /**\n * Map the public ACME challenge name to the record name written through\n * `dnsProvider`. Use this for CNAME-delegated DNS-01, where customers point\n * `_acme-challenge.app.example.com` at a platform-owned validation zone.\n * The propagation checker still receives the public challenge name because\n * that is what the certificate authority resolves.\n */\n mapDnsChallengeRecord?: (context: {\n domain: string;\n recordName: string;\n }) => string;\n /** Contact email for the ACME account. */\n email: string;\n /** ACME directory URL. Default Let's Encrypt production. */\n directoryUrl?: string;\n /** Reuse an existing account. Pass `exportAccount`'s output via `importAccount`. */\n account?: AcmeAccount;\n /** Override fetch (tests). Default global fetch. */\n fetch?: typeof fetch;\n /** Poll interval. Default 3 s. */\n pollIntervalMs?: number;\n /**\n * Max wait before notifying ACME that the DNS challenge is ready.\n * Set ~30-60s for Cloudflare; longer for slower providers. Default 30 s.\n */\n dnsPropagationDelayMs?: number;\n /** Max wait for the order to become valid. Default 5 min. */\n orderTimeoutMs?: number;\n /** Status log lines. */\n onLog?: (line: string) => void;\n /** Override sleep (tests). */\n sleep?: (ms: number) => Promise<void>;\n /**\n * Optional pre-check: returns true when DNS has propagated globally.\n * Default: just wait `dnsPropagationDelayMs` then proceed. Override\n * for production to actually verify (e.g. resolve from multiple\n * public resolvers).\n */\n checkDnsPropagated?: (\n recordName: string,\n expectedValue: string,\n ) => Promise<boolean>;\n};\n\nexport type IssuedCertificate = {\n certificatePem: string;\n privateKeyPem: string;\n account: AcmeAccount;\n domains: string[];\n};\n\nexport class AcmeError extends Error {\n readonly status: number;\n readonly body: unknown;\n constructor(message: string, status: number, body: unknown) {\n super(message);\n this.name = \"AcmeError\";\n this.status = status;\n this.body = body;\n }\n}\n\nconst defaultSleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\nexport const issueCertificate = async (\n options: IssueCertificateOptions,\n): Promise<IssuedCertificate> => {\n const log = options.onLog ?? (() => {});\n const sleep = options.sleep ?? defaultSleep;\n const fetcher = options.fetch ?? fetch;\n const directoryUrl = options.directoryUrl ?? LETSENCRYPT_PRODUCTION;\n const pollMs = options.pollIntervalMs ?? 3_000;\n const dnsDelay = options.dnsPropagationDelayMs ?? 30_000;\n const orderTimeout = options.orderTimeoutMs ?? 5 * 60_000;\n const account = options.account ?? (await generateAccountKey());\n\n if (options.domains.length === 0) {\n throw new Error(\"[deploy/tls] at least one domain is required\");\n }\n\n // 1. Fetch directory.\n log(`[tls] fetching ACME directory ${directoryUrl}`);\n const directoryResponse = await fetcher(directoryUrl);\n if (!directoryResponse.ok) {\n throw new AcmeError(\n `failed to fetch ACME directory: ${directoryResponse.status}`,\n directoryResponse.status,\n await directoryResponse.text(),\n );\n }\n const directory = (await directoryResponse.json()) as AcmeDirectory;\n\n // 2. Get initial nonce.\n let nonce = await fetchNonce(fetcher, directory.newNonce);\n\n // Helper: signed POST. Tracks nonce; returns parsed JSON body + headers.\n const post = async (\n url: string,\n payload: object | string,\n identification: { kid?: string; jwk?: JsonWebKey },\n ): Promise<{ status: number; body: unknown; headers: Headers }> => {\n const header: JwsHeader = {\n alg: \"ES256\",\n nonce,\n url,\n ...(identification.kid !== undefined ? { kid: identification.kid } : {}),\n ...(identification.jwk !== undefined ? { jwk: identification.jwk } : {}),\n };\n const jws = await signJws(account.key.privateKey, header, payload);\n const response = await fetcher(url, {\n body: JSON.stringify(jws),\n headers: { \"content-type\": \"application/jose+json\" },\n method: \"POST\",\n });\n const newNonce = response.headers.get(\"replay-nonce\");\n if (newNonce !== null) nonce = newNonce;\n const text = await response.text();\n const body =\n text.length > 0 && response.headers.get(\"content-type\")?.includes(\"json\")\n ? JSON.parse(text)\n : text;\n if (!response.ok) {\n throw new AcmeError(\n `ACME ${url} → ${response.status}`,\n response.status,\n body,\n );\n }\n return { body, headers: response.headers, status: response.status };\n };\n\n // 3. Register the account (or reuse if kid is set).\n const publicJwk = await exportPublicJwk(account.key.publicKey);\n if (account.kid === undefined) {\n log(`[tls] registering ACME account for ${options.email}`);\n const result = await post(\n directory.newAccount,\n {\n contact: [`mailto:${options.email}`],\n termsOfServiceAgreed: true,\n },\n { jwk: publicJwk },\n );\n account.kid = result.headers.get(\"location\") ?? undefined;\n if (account.kid === undefined) {\n throw new Error(\n \"[deploy/tls] ACME newAccount response missing Location header\",\n );\n }\n log(`[tls] account registered: ${account.kid}`);\n } else {\n log(`[tls] reusing account ${account.kid}`);\n }\n\n const accountKid = account.kid;\n\n // 4. Submit the order.\n log(`[tls] submitting order for ${options.domains.join(\", \")}`);\n const orderResult = await post(\n directory.newOrder,\n {\n identifiers: options.domains.map((domain) => ({\n type: \"dns\",\n value: domain,\n })),\n },\n { kid: accountKid },\n );\n let order = orderResult.body as AcmeOrder;\n const orderUrl = orderResult.headers.get(\"location\");\n if (orderUrl === null) {\n throw new Error(\n \"[deploy/tls] ACME newOrder response missing Location header\",\n );\n }\n\n // 5. For each authorization, complete the DNS-01 challenge.\n const cleanups: Array<() => Promise<void>> = [];\n const dnsCreated: Array<{\n recordId: string;\n recordName: string;\n recordValue: string;\n }> = [];\n\n try {\n const thumbprint = await jwkThumbprint(publicJwk);\n\n for (const authUrl of order.authorizations) {\n const authResult = await post(authUrl, \"\", { kid: accountKid });\n const auth = authResult.body as AcmeAuthorization;\n const challenge = auth.challenges.find((c) => c.type === \"dns-01\");\n if (challenge === undefined) {\n throw new Error(\n `[deploy/tls] no dns-01 challenge for ${auth.identifier.value}`,\n );\n }\n const keyAuthorization = `${challenge.token}.${thumbprint}`;\n const txtBytes = new Uint8Array(\n await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(keyAuthorization),\n ),\n );\n const txtValue = base64UrlEncode(txtBytes);\n const recordName = `_acme-challenge.${auth.identifier.value}`;\n const providerRecordName =\n options.mapDnsChallengeRecord?.({\n domain: auth.identifier.value,\n recordName,\n }) ?? recordName;\n if (providerRecordName.trim().length === 0) {\n throw new Error(\n \"[deploy/tls] mapped DNS-01 record name must not be empty\",\n );\n }\n log(\n providerRecordName === recordName\n ? `[tls] DNS-01: setting ${recordName} = \"${txtValue}\"`\n : `[tls] DNS-01: setting delegated ${providerRecordName} for ${recordName} = \"${txtValue}\"`,\n );\n const record = await options.dnsProvider.upsert({\n content: txtValue,\n name: providerRecordName,\n ttl: 60,\n type: \"TXT\",\n });\n dnsCreated.push({\n recordId: record.id,\n recordName: providerRecordName,\n recordValue: txtValue,\n });\n cleanups.push(() => options.dnsProvider.delete(record.id));\n\n if (options.checkDnsPropagated !== undefined) {\n log(\"[tls] waiting for DNS propagation (custom checker)…\");\n const deadline = Date.now() + dnsDelay;\n while (Date.now() < deadline) {\n if (await options.checkDnsPropagated(recordName, txtValue)) break;\n await sleep(pollMs);\n }\n } else {\n log(`[tls] sleeping ${dnsDelay}ms for DNS propagation`);\n await sleep(dnsDelay);\n }\n\n log(\n `[tls] notifying ACME of dns-01 readiness for ${auth.identifier.value}`,\n );\n await post(challenge.url, {}, { kid: accountKid });\n\n // Poll the authorization until valid/invalid.\n const authDeadline = Date.now() + orderTimeout;\n while (Date.now() < authDeadline) {\n const polledResult = await post(authUrl, \"\", { kid: accountKid });\n const polled = polledResult.body as AcmeAuthorization;\n if (polled.status === \"valid\") break;\n if (polled.status === \"invalid\") {\n throw new Error(\n `[deploy/tls] authorization failed for ${auth.identifier.value}: ${JSON.stringify(polled.challenges)}`,\n );\n }\n await sleep(pollMs);\n }\n }\n\n // 6. Finalize — generate cert keypair + CSR.\n log(\"[tls] generating cert keypair + CSR\");\n const certKey = await generateCertKeyPair();\n const csrDer = await buildCsr(options.domains, certKey);\n const csr = base64UrlEncode(csrDer);\n\n await post(order.finalize, { csr }, { kid: accountKid });\n\n // 7. Poll the order until valid + certificate URL appears.\n const orderDeadline = Date.now() + orderTimeout;\n while (Date.now() < orderDeadline) {\n const refreshed = await post(orderUrl, \"\", { kid: accountKid });\n order = refreshed.body as AcmeOrder;\n if (order.status === \"valid\" && order.certificate !== undefined) break;\n if (order.status === \"invalid\") {\n throw new Error(`[deploy/tls] order failed: ${JSON.stringify(order)}`);\n }\n await sleep(pollMs);\n }\n\n if (order.certificate === undefined) {\n throw new Error(\n \"[deploy/tls] order timed out before issuing certificate\",\n );\n }\n\n // 8. Download the cert (PEM bundle).\n log(`[tls] downloading certificate from ${order.certificate}`);\n const certResult = await post(order.certificate, \"\", { kid: accountKid });\n const certificatePem =\n typeof certResult.body === \"string\"\n ? certResult.body\n : String(certResult.body);\n\n const privateKeyPem = await exportEcPrivateKeyPem(certKey);\n\n return {\n account,\n certificatePem,\n domains: options.domains,\n privateKeyPem,\n };\n } finally {\n for (const cleanup of cleanups) {\n try {\n await cleanup();\n } catch (error) {\n log(`[tls] cleanup failed (continuing): ${String(error)}`);\n }\n }\n // Suppress unused-variable lint without changing behavior.\n void dnsCreated;\n }\n};\n\nconst fetchNonce = async (\n fetcher: typeof fetch,\n url: string,\n): Promise<string> => {\n const response = await fetcher(url, { method: \"HEAD\" });\n const nonce = response.headers.get(\"replay-nonce\");\n if (nonce === null) {\n throw new Error(\n \"[deploy/tls] newNonce response missing Replay-Nonce header\",\n );\n }\n return nonce;\n};\n\n// =============================================================================\n// installCertificateOnTarget\n// =============================================================================\n\nexport type InstallCertificateOptions = {\n /** Remote path for the cert chain. Default `/etc/ssl/<firstDomain>/fullchain.pem`. */\n certPath?: string;\n /** Remote path for the private key. Default `/etc/ssl/<firstDomain>/privkey.pem`. */\n keyPath?: string;\n /** Mode (chmod) for the cert + key. Default `600`. */\n mode?: string;\n /** Owner (chown) for the cert + key. Default unchanged. */\n owner?: string;\n /** Optional reload command run after install (e.g. `'systemctl reload nginx'`). */\n reload?: string;\n /** Override the writeTo helper (tests). */\n writeFile?: (target: Target, path: string, contents: string) => Promise<void>;\n};\n\nconst defaultWriteFile = async (\n target: Target,\n remotePath: string,\n contents: string,\n): Promise<void> => {\n const escaped = contents.replaceAll(\"'\", \"'\\\\''\");\n await target.exec(`mkdir -p \"$(dirname '${remotePath}')\"`);\n await target.exec(\n `cat > '${remotePath}' <<'__ABS_TLS_EOF__'\\n${contents}__ABS_TLS_EOF__\\n`,\n );\n void escaped;\n};\n\n/**\n * @internal — exposed for unit testing of cryptographic primitives.\n * Not part of the public API; consumers should NOT depend on this.\n */\nexport const __testing = {\n base64UrlDecode,\n base64UrlEncode,\n base64UrlEncodeString,\n buildCsr,\n derBitString,\n derInt,\n derOid,\n derSeq,\n derSet,\n ecdsaRawToDer,\n exportEcPrivateKeyPem,\n exportPublicJwk,\n generateCertKeyPair,\n jwkThumbprint,\n signJws,\n};\n\n/**\n * Upload cert + private key to the target. Composable with the deploy\n * pipeline as a verify-step or post-deploy hook.\n */\nexport const installCertificateOnTarget = async (\n target: Target,\n cert: IssuedCertificate,\n options: InstallCertificateOptions = {},\n): Promise<{ certPath: string; keyPath: string }> => {\n const domain = cert.domains[0];\n if (domain === undefined) {\n throw new Error(\"[deploy/tls] certificate has no domains\");\n }\n const certPath = options.certPath ?? `/etc/ssl/${domain}/fullchain.pem`;\n const keyPath = options.keyPath ?? `/etc/ssl/${domain}/privkey.pem`;\n const mode = options.mode ?? \"600\";\n const writer = options.writeFile ?? defaultWriteFile;\n\n await writer(target, certPath, cert.certificatePem);\n await writer(target, keyPath, cert.privateKeyPem);\n await target.exec(`chmod ${mode} '${certPath}' '${keyPath}'`);\n if (options.owner !== undefined) {\n await target.exec(`chown ${options.owner} '${certPath}' '${keyPath}'`);\n }\n if (options.reload !== undefined) {\n await target.exec(options.reload);\n }\n\n return { certPath, keyPath };\n};\n\n// =============================================================================\n// Certificate inspection + renewal scheduling\n// =============================================================================\n\nexport type CertificateInspection = {\n /** CN + every SAN, deduplicated. */\n subjects: string[];\n /** Issuance time, ms since epoch. */\n validFrom: number;\n /** Expiration time, ms since epoch. */\n validTo: number;\n /** Whole days remaining before `validTo`. Negative if expired. */\n daysRemaining: number;\n /** True when the cert is past `validTo`. */\n expired: boolean;\n /** Issuer DN string (for \"Let's Encrypt vs staging vs other CA\" checks). */\n issuer: string;\n};\n\nconst parseSubjects = (x509: X509Certificate): string[] => {\n const subjects = new Set<string>();\n const cnMatch = x509.subject.match(/CN=([^,\\n]+)/);\n if (cnMatch !== null && cnMatch[1] !== undefined) {\n subjects.add(cnMatch[1].trim());\n }\n const san = x509.subjectAltName;\n if (san !== undefined && san !== null) {\n for (const part of san.split(\",\")) {\n const dnsMatch = part.trim().match(/^DNS:(.+)$/);\n if (dnsMatch !== null && dnsMatch[1] !== undefined) {\n subjects.add(dnsMatch[1].trim());\n }\n }\n }\n return [...subjects];\n};\n\n/**\n * Parse a PEM certificate into operator-shaped metadata. Used by\n * {@link renewCertificate} to decide whether to re-issue; also fine\n * for status pages and observability.\n */\nexport const inspectCertificate = (\n pem: string,\n options: { now?: () => number } = {},\n): CertificateInspection => {\n const x509 = new X509Certificate(pem);\n const validFrom = new Date(x509.validFrom).getTime();\n const validTo = new Date(x509.validTo).getTime();\n const now = (options.now ?? Date.now)();\n const daysRemaining = Math.floor((validTo - now) / (24 * 60 * 60 * 1000));\n return {\n daysRemaining,\n expired: validTo < now,\n issuer: x509.issuer,\n subjects: parseSubjects(x509),\n validFrom,\n validTo,\n };\n};\n\nexport type RenewCertificateOptions = IssueCertificateOptions & {\n /**\n * Current cert PEM. When provided, the cert's `validTo` decides\n * whether to re-issue; when absent, renewal always issues.\n */\n currentCertificatePem?: string;\n /**\n * Re-issue when fewer than this many days remain. Default 30,\n * matching certbot's standard schedule (Let's Encrypt issues 90-day\n * certs; renewing at 30 days leaves a 60-day error budget).\n */\n renewWhenDaysRemaining?: number;\n /** Force re-issue regardless of remaining days. Default false. */\n force?: boolean;\n /** Override `Date.now()` for testing. */\n now?: () => number;\n};\n\nexport type RenewalResult =\n | {\n renewed: true;\n certificate: IssuedCertificate;\n reason: \"forced\" | \"no-current-cert\" | \"expiring-soon\";\n }\n | {\n renewed: false;\n reason: \"still-fresh\";\n inspection: CertificateInspection;\n };\n\n/**\n * Conditional cert renewal. Parses the supplied cert (if any),\n * decides whether to re-issue based on remaining days, and either\n * returns the existing cert info (\"still fresh\") or issues a new\n * one via {@link issueCertificate}.\n *\n * Wire to a scheduled function (cron / @absolutejs/sync schedule /\n * GitHub Action) running at least once a week. Idempotent: a fresh\n * cert returns `renewed: false` cheaply (one PEM parse, zero\n * network IO).\n *\n * @example\n * const result = await renewCertificate({\n * currentCertificatePem: existingPem, // omit to force first-issue\n * domains: ['api.example.com'],\n * dnsProvider: dns,\n * email: 'ops@example.com',\n * account: persistedAccount, // reuse to avoid CA rate limit\n * });\n * if (result.renewed) {\n * await installCertificateOnTarget(target, result.certificate, { reload });\n * }\n */\nexport const renewCertificate = async (\n options: RenewCertificateOptions,\n): Promise<RenewalResult> => {\n const threshold = options.renewWhenDaysRemaining ?? 30;\n if (threshold < 0) {\n throw new Error(\"[deploy/tls] renewWhenDaysRemaining must be non-negative\");\n }\n\n if (options.force === true) {\n const certificate = await issueCertificate(options);\n return { certificate, reason: \"forced\", renewed: true };\n }\n\n if (options.currentCertificatePem === undefined) {\n const certificate = await issueCertificate(options);\n return { certificate, reason: \"no-current-cert\", renewed: true };\n }\n\n const nowFn = options.now ?? Date.now;\n const inspection = inspectCertificate(options.currentCertificatePem, {\n now: nowFn,\n });\n\n if (!inspection.expired && inspection.daysRemaining >= threshold) {\n return { inspection, reason: \"still-fresh\", renewed: false };\n }\n\n const certificate = await issueCertificate(options);\n return { certificate, reason: \"expiring-soon\", renewed: true };\n};\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "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",
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "78F873482F18940A64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/vultr.d.ts
CHANGED
|
@@ -8,16 +8,16 @@
|
|
|
8
8
|
* Vultr and referenced by UUID — different from Linode (raw keys)
|
|
9
9
|
* and DO/Hetzner (fingerprints/ids/names).
|
|
10
10
|
*/
|
|
11
|
-
import type { Target } from
|
|
11
|
+
import type { Target } from "./targets";
|
|
12
12
|
export type VultrClientLike = {
|
|
13
|
-
request: <T = unknown>(method:
|
|
13
|
+
request: <T = unknown>(method: "GET" | "POST" | "DELETE" | "PATCH", path: string, body?: unknown) => Promise<T>;
|
|
14
14
|
};
|
|
15
15
|
/** A Vultr instance, narrowed to what we inspect. */
|
|
16
16
|
export type VultrInstance = {
|
|
17
17
|
id: string;
|
|
18
18
|
label: string;
|
|
19
|
-
status:
|
|
20
|
-
power_status?:
|
|
19
|
+
status: "active" | "pending" | "suspended" | "resizing";
|
|
20
|
+
power_status?: "running" | "stopped" | "starting";
|
|
21
21
|
server_status?: string;
|
|
22
22
|
main_ip: string;
|
|
23
23
|
internal_ip?: string;
|
package/dist/vultr.js
CHANGED
|
@@ -19,12 +19,14 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
19
19
|
}
|
|
20
20
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
21
21
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
if (mod && typeof mod === "object" || typeof mod === "function") {
|
|
23
|
+
for (let key of __getOwnPropNames(mod))
|
|
24
|
+
if (!__hasOwnProp.call(to, key))
|
|
25
|
+
__defProp(to, key, {
|
|
26
|
+
get: __accessProp.bind(mod, key),
|
|
27
|
+
enumerable: true
|
|
28
|
+
});
|
|
29
|
+
}
|
|
28
30
|
if (canCache)
|
|
29
31
|
cache.set(mod, to);
|
|
30
32
|
return to;
|
|
@@ -199,7 +201,13 @@ var sshTarget = (options) => {
|
|
|
199
201
|
}
|
|
200
202
|
return;
|
|
201
203
|
}
|
|
202
|
-
const argv = [
|
|
204
|
+
const argv = [
|
|
205
|
+
"scp",
|
|
206
|
+
"-r",
|
|
207
|
+
...sshBaseFlags(options),
|
|
208
|
+
localPath,
|
|
209
|
+
`${remote}:${remotePath}`
|
|
210
|
+
];
|
|
203
211
|
const result = await runSpawn(argv, { timeoutMs: 600000 });
|
|
204
212
|
if (result.exitCode !== 0) {
|
|
205
213
|
throw new Error(`scp upload failed (exit ${result.exitCode}): ${result.stderr || result.stdout}`);
|
|
@@ -441,13 +449,13 @@ var vultrTarget = async (options) => {
|
|
|
441
449
|
};
|
|
442
450
|
};
|
|
443
451
|
export {
|
|
444
|
-
|
|
445
|
-
listVultrInstances,
|
|
446
|
-
findVultrInstance,
|
|
447
|
-
destroyVultrInstance,
|
|
452
|
+
VultrError,
|
|
448
453
|
createVultrClient,
|
|
449
|
-
|
|
454
|
+
destroyVultrInstance,
|
|
455
|
+
findVultrInstance,
|
|
456
|
+
listVultrInstances,
|
|
457
|
+
vultrTarget
|
|
450
458
|
};
|
|
451
459
|
|
|
452
|
-
//# debugId=
|
|
460
|
+
//# debugId=35AB619173B7752464756E2164756E21
|
|
453
461
|
//# sourceMappingURL=vultr.js.map
|