@geekmidas/cli 10.0.0-alpha.110 → 10.0.0-alpha.112
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{GoDaddyProvider-CjeOduia.mjs → GoDaddyProvider-CPabc3XW.mjs} +2 -2
- package/dist/{GoDaddyProvider-CjeOduia.mjs.map → GoDaddyProvider-CPabc3XW.mjs.map} +1 -1
- package/dist/{GoDaddyProvider-qNUzTXI7.cjs → GoDaddyProvider-DWrDIXzQ.cjs} +2 -2
- package/dist/{GoDaddyProvider-qNUzTXI7.cjs.map → GoDaddyProvider-DWrDIXzQ.cjs.map} +1 -1
- package/dist/{LegacyStateStore-pgscYsiG.mjs → LegacyStateStore-BdXoAlYY.mjs} +3 -3
- package/dist/{LegacyStateStore-pgscYsiG.mjs.map → LegacyStateStore-BdXoAlYY.mjs.map} +1 -1
- package/dist/{LegacyStateStore-MxiSu7KJ.cjs → LegacyStateStore-fsyPGBWu.cjs} +3 -3
- package/dist/{LegacyStateStore-MxiSu7KJ.cjs.map → LegacyStateStore-fsyPGBWu.cjs.map} +1 -1
- package/dist/{LocalStateStore-Bm8Vmwjb.cjs → LocalStateStore-AtviUBky.cjs} +2 -2
- package/dist/{LocalStateStore-Bm8Vmwjb.cjs.map → LocalStateStore-AtviUBky.cjs.map} +1 -1
- package/dist/{LocalStateStore-BcvyKbAw.mjs → LocalStateStore-BrAX5yy7.mjs} +2 -2
- package/dist/{LocalStateStore-BcvyKbAw.mjs.map → LocalStateStore-BrAX5yy7.mjs.map} +1 -1
- package/dist/{S3StateStore-H2XsAzpJ.mjs → S3StateStore-Cx7njkBz.mjs} +2 -2
- package/dist/{S3StateStore-H2XsAzpJ.mjs.map → S3StateStore-Cx7njkBz.mjs.map} +1 -1
- package/dist/{S3StateStore-DXHSBVsV.cjs → S3StateStore-tn5g80Sx.cjs} +2 -2
- package/dist/{S3StateStore-DXHSBVsV.cjs.map → S3StateStore-tn5g80Sx.cjs.map} +1 -1
- package/dist/{SSMStateStore-BLPSNl-U.cjs → SSMStateStore-CAFde-Fq.cjs} +2 -2
- package/dist/{SSMStateStore-BLPSNl-U.cjs.map → SSMStateStore-CAFde-Fq.cjs.map} +1 -1
- package/dist/{SSMStateStore-CENciQEM.mjs → SSMStateStore-sqZ3oDmn.mjs} +2 -2
- package/dist/{SSMStateStore-CENciQEM.mjs.map → SSMStateStore-sqZ3oDmn.mjs.map} +1 -1
- package/dist/{add-Cdg1kEqN.cjs → add-Cs8yT5iH.cjs} +3 -3
- package/dist/{add-Cdg1kEqN.cjs.map → add-Cs8yT5iH.cjs.map} +1 -1
- package/dist/{add-snhdVmR-.mjs → add-DJE7zqJ4.mjs} +3 -3
- package/dist/{add-snhdVmR-.mjs.map → add-DJE7zqJ4.mjs.map} +1 -1
- package/dist/{bundler-Wd9H4QLJ.mjs → bundler-DrySVbXF.mjs} +5 -5
- package/dist/{bundler-Wd9H4QLJ.mjs.map → bundler-DrySVbXF.mjs.map} +1 -1
- package/dist/{bundler-B4GDxImV.cjs → bundler-NrtItVBp.cjs} +5 -5
- package/dist/{bundler-B4GDxImV.cjs.map → bundler-NrtItVBp.cjs.map} +1 -1
- package/dist/{cli-BZYz55tO.cjs → cli-CHzpFBh-.cjs} +2 -2
- package/dist/{cli-BZYz55tO.cjs.map → cli-CHzpFBh-.cjs.map} +1 -1
- package/dist/{cli-BzrDSNSg.mjs → cli-DDY3jfTt.mjs} +4 -4
- package/dist/{cli-BzrDSNSg.mjs.map → cli-DDY3jfTt.mjs.map} +1 -1
- package/dist/{compose-DN9zySvQ.cjs → compose-ByIbIrzs.cjs} +20 -5
- package/dist/compose-ByIbIrzs.cjs.map +1 -0
- package/dist/{compose-Gsd1Nq7R.mjs → compose-CDC2bCme.mjs} +20 -5
- package/dist/compose-CDC2bCme.mjs.map +1 -0
- package/dist/deploy/public.cjs +6 -6
- package/dist/deploy/public.mjs +6 -6
- package/dist/{deploy-H2S8_mTx.mjs → deploy-DLq9-m6H.mjs} +5 -5
- package/dist/{deploy-H2S8_mTx.mjs.map → deploy-DLq9-m6H.mjs.map} +1 -1
- package/dist/{deploy-CFvq8daZ.cjs → deploy-Dl_NavYE.cjs} +5 -5
- package/dist/{deploy-CFvq8daZ.cjs.map → deploy-Dl_NavYE.cjs.map} +1 -1
- package/dist/{dns-BdETzP10.cjs → dns-C2TGXUF4.cjs} +2 -2
- package/dist/{dns-BdETzP10.cjs.map → dns-C2TGXUF4.cjs.map} +1 -1
- package/dist/{dns-pFMShDqW.mjs → dns-pzftumxg.mjs} +2 -2
- package/dist/{dns-pFMShDqW.mjs.map → dns-pzftumxg.mjs.map} +1 -1
- package/dist/{dokploy-oDJbnvCb.mjs → dokploy-B7-OwY2s.mjs} +2 -2
- package/dist/{dokploy-oDJbnvCb.mjs.map → dokploy-B7-OwY2s.mjs.map} +1 -1
- package/dist/{dokploy-HioAjP7K.cjs → dokploy-OqBh8G4g.cjs} +2 -2
- package/dist/{dokploy-HioAjP7K.cjs.map → dokploy-OqBh8G4g.cjs.map} +1 -1
- package/dist/eas-Cne743nQ.cjs +337 -0
- package/dist/eas-Cne743nQ.cjs.map +1 -0
- package/dist/eas-DEpwISrQ.mjs +334 -0
- package/dist/eas-DEpwISrQ.mjs.map +1 -0
- package/dist/{encryption-D5pDJyp2.mjs → encryption-DJv_jEXi.mjs} +2 -2
- package/dist/{encryption-D5pDJyp2.mjs.map → encryption-DJv_jEXi.mjs.map} +1 -1
- package/dist/{encryption-DVCxD-gV.cjs → encryption-DoVnVU82.cjs} +2 -2
- package/dist/{encryption-DVCxD-gV.cjs.map → encryption-DoVnVU82.cjs.map} +1 -1
- package/dist/{engine-BaJGPzte.cjs → engine-CJhQb50j.cjs} +3 -3
- package/dist/{engine-BaJGPzte.cjs.map → engine-CJhQb50j.cjs.map} +1 -1
- package/dist/{engine-CfAKgr2_.mjs → engine-Db71-OZL.mjs} +3 -3
- package/dist/{engine-CfAKgr2_.mjs.map → engine-Db71-OZL.mjs.map} +1 -1
- package/dist/{github-E-ZxqFPq.mjs → github-D2eABlxM.mjs} +4 -4
- package/dist/{github-E-ZxqFPq.mjs.map → github-D2eABlxM.mjs.map} +1 -1
- package/dist/{github-D902Vwr9.cjs → github-DDOHjdS9.cjs} +4 -4
- package/dist/{github-D902Vwr9.cjs.map → github-DDOHjdS9.cjs.map} +1 -1
- package/dist/googlePlay-B6uiHi65.cjs +931 -0
- package/dist/googlePlay-B6uiHi65.cjs.map +1 -0
- package/dist/googlePlay-BYZ-J5sC.mjs +931 -0
- package/dist/googlePlay-BYZ-J5sC.mjs.map +1 -0
- package/dist/index.cjs +268 -94
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +268 -97
- package/dist/index.mjs.map +1 -1
- package/dist/{migrate-BZ0GnSZQ.mjs → migrate-CQUGbptv.mjs} +2 -2
- package/dist/{migrate-BZ0GnSZQ.mjs.map → migrate-CQUGbptv.mjs.map} +1 -1
- package/dist/{migrate-Df81ew0k.cjs → migrate-GLBZlrlJ.cjs} +2 -2
- package/dist/{migrate-Df81ew0k.cjs.map → migrate-GLBZlrlJ.cjs.map} +1 -1
- package/dist/{migrate-CTqhWtev.cjs → migrate-bDQzFvBN.cjs} +2 -2
- package/dist/{migrate-CTqhWtev.cjs.map → migrate-bDQzFvBN.cjs.map} +1 -1
- package/dist/{migrate-DCXwHcWX.mjs → migrate-xHYaeBkd.mjs} +3 -3
- package/dist/{migrate-DCXwHcWX.mjs.map → migrate-xHYaeBkd.mjs.map} +1 -1
- package/dist/publish-CSctCNf4.mjs +123 -0
- package/dist/publish-CSctCNf4.mjs.map +1 -0
- package/dist/publish-SDG1WfYn.cjs +124 -0
- package/dist/publish-SDG1WfYn.cjs.map +1 -0
- package/dist/{resolve-BMpPd8x3.mjs → resolve-CxDqDmCD.mjs} +3 -3
- package/dist/{resolve-BMpPd8x3.mjs.map → resolve-CxDqDmCD.mjs.map} +1 -1
- package/dist/{resolve-D043YmW9.cjs → resolve-wG49Woex.cjs} +3 -3
- package/dist/{resolve-D043YmW9.cjs.map → resolve-wG49Woex.cjs.map} +1 -1
- package/dist/{rollback-CDs_XNb0.mjs → rollback-BQgEdr_p.mjs} +4 -4
- package/dist/{rollback-CDs_XNb0.mjs.map → rollback-BQgEdr_p.mjs.map} +1 -1
- package/dist/{rollback-CBiYsQ3T.cjs → rollback-Cw-Z0mWn.cjs} +4 -4
- package/dist/{rollback-CBiYsQ3T.cjs.map → rollback-Cw-Z0mWn.cjs.map} +1 -1
- package/dist/{seeds-BjcO4DDa.mjs → seeds-CIk0l4SC.mjs} +13 -10
- package/dist/seeds-CIk0l4SC.mjs.map +1 -0
- package/dist/{seeds-DNqRA1aQ.cjs → seeds-Dk8YkLkM.cjs} +18 -15
- package/dist/seeds-Dk8YkLkM.cjs.map +1 -0
- package/dist/{sniffer-DipSS8r8.cjs → sniffer-2aK7cB2u.cjs} +6 -6
- package/dist/{sniffer-DipSS8r8.cjs.map → sniffer-2aK7cB2u.cjs.map} +1 -1
- package/dist/{sniffer-b0XPmSyT.mjs → sniffer-CABMO-Bh.mjs} +6 -6
- package/dist/{sniffer-b0XPmSyT.mjs.map → sniffer-CABMO-Bh.mjs.map} +1 -1
- package/dist/{stage-DrDmZusd.mjs → stage-ClKTHQoM.mjs} +69 -33
- package/dist/stage-ClKTHQoM.mjs.map +1 -0
- package/dist/{stage-C_y2UovO.cjs → stage-DrCS0vKD.cjs} +79 -32
- package/dist/stage-DrCS0vKD.cjs.map +1 -0
- package/dist/target/public.cjs +1 -1
- package/dist/target/public.mjs +1 -1
- package/dist/{terminal-CvRLxz6g.mjs → terminal-CybB-cjk.mjs} +2 -2
- package/dist/{terminal-CvRLxz6g.mjs.map → terminal-CybB-cjk.mjs.map} +1 -1
- package/package.json +15 -15
- package/dist/compose-DN9zySvQ.cjs.map +0 -1
- package/dist/compose-Gsd1Nq7R.mjs.map +0 -1
- package/dist/seeds-BjcO4DDa.mjs.map +0 -1
- package/dist/seeds-DNqRA1aQ.cjs.map +0 -1
- package/dist/stage-C_y2UovO.cjs.map +0 -1
- package/dist/stage-DrDmZusd.mjs.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as GkmError } from "./errors-D8Gwp5kU.mjs";
|
|
2
2
|
import { r as storedCredentials, t as MissingCredential } from "./credentials-B5N5yKk6.mjs";
|
|
3
|
-
import { D as DnsRecordsUnreadable } from "./seeds-
|
|
3
|
+
import { D as DnsRecordsUnreadable } from "./seeds-CIk0l4SC.mjs";
|
|
4
4
|
/** The record types gkm writes. Never MX, TXT, NS, SOA, SRV or CAA. */
|
|
5
5
|
const GODADDY_MANAGED_TYPES = [
|
|
6
6
|
"A",
|
|
@@ -385,4 +385,4 @@ var GoDaddyProvider = class {
|
|
|
385
385
|
//#endregion
|
|
386
386
|
export { GoDaddyProvider };
|
|
387
387
|
|
|
388
|
-
//# sourceMappingURL=GoDaddyProvider-
|
|
388
|
+
//# sourceMappingURL=GoDaddyProvider-CPabc3XW.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GoDaddyProvider-CjeOduia.mjs","names":[],"sources":["../src/target/dokploy/dns/godaddy-api.ts","../src/target/dokploy/dns/GoDaddyProvider.ts"],"sourcesContent":["/**\n * GoDaddy's v1 DNS API, as gkm uses it: one record set — a name and a type —\n * at a time.\n *\n * - read: `GET /v1/domains/{domain}/records/{type}/{name}`\n * - write: `PUT /v1/domains/{domain}/records/{type}/{name}` with `[{ data, ttl }]`,\n * which replaces that one name's records of that one type\n * - delete: `DELETE /v1/domains/{domain}/records/{type}/{name}`\n *\n * Never the zone-wide `PUT /v1/domains/{domain}/records`, which replaces every\n * record the domain has — mail, verification TXT records and all — and never\n * a domain or account endpoint (`GET /v1/domains`, `GET /v1/domains/{domain}`):\n * a token scoped to `domains.dns:update` alone is enough. A domain that is not\n * in the token's account is told apart by the records endpoint's own 404 or 422.\n *\n * Authenticated with a Personal Access Token — `Authorization: Bearer <token>`,\n * the API's one security scheme. GoDaddy allows about 60 requests a minute per\n * token; a 429 carries `retryAfterSec`, which is waited out a few times before\n * the run gives up with {@link GoDaddyRateLimited}. A 504 is retried the same\n * way. GoDaddy refuses a TTL under 600 seconds (a 422), so every write is\n * sent with at least that.\n */\n\nimport type { GoDaddyCredential } from '../../../deploy/credentials';\nimport { GkmError } from '../../../errors';\n\nexport const GODADDY_API_BASE = 'https://api.godaddy.com';\n\n/** GoDaddy refuses a TTL below this. */\nexport const GODADDY_MIN_TTL = 600;\n\n/** The record types gkm writes. Never MX, TXT, NS, SOA, SRV or CAA. */\nexport const GODADDY_MANAGED_TYPES = ['A', 'AAAA', 'CNAME'] as const;\n\nexport type GoDaddyRecordType = (typeof GODADDY_MANAGED_TYPES)[number];\n\n/** One record as GoDaddy returns it. */\nexport interface GoDaddyRecord {\n\ttype: string;\n\tname: string;\n\tdata: string;\n\tttl?: number;\n}\n\n/** GoDaddy's error body. */\ninterface GoDaddyErrorBody {\n\tcode?: string;\n\tmessage?: string;\n\tretryAfterSec?: number;\n}\n\n/**\n * The token is good, and GoDaddy will not let it use the API: since 2024 the\n * Domains and DNS APIs answer only accounts with 10 or more domains, or a\n * Discount Domain Club Premier membership.\n */\nexport class GoDaddyApiAccessDenied extends GkmError {\n\tconstructor(\n\t\treadonly domain: string,\n\t\treadonly detail?: string,\n\t) {\n\t\tsuper(\n\t\t\t`GoDaddy refused API access for ${domain} (403 ACCESS_DENIED${detail ? `: ${detail}` : ''}). ` +\n\t\t\t\t'GoDaddy only opens its DNS API to accounts with 10 or more domains, or ' +\n\t\t\t\t'with a Discount Domain Club Premier membership, so a valid token on a ' +\n\t\t\t\t'smaller account is refused. Either qualify the account, move the ' +\n\t\t\t\t\"domain's DNS hosting to Route53 (provider: 'route53') or Cloudflare \" +\n\t\t\t\t\"by changing its nameservers at GoDaddy, or set provider: 'manual' \" +\n\t\t\t\t'and create the records gkm prints yourself. (A scoped token without ' +\n\t\t\t\t'domains.dns:update is refused the same way — check its scopes too.)',\n\t\t);\n\t\tthis.name = 'GoDaddyApiAccessDenied';\n\t}\n}\n\n/** The token lacks the scope a records call needs. */\nexport class GoDaddyScopeMissing extends GkmError {\n\tconstructor(\n\t\treadonly method: string,\n\t\treadonly domain: string,\n\t\treadonly scope: string,\n\t\treadonly detail?: string,\n\t) {\n\t\tsuper(\n\t\t\t`GoDaddy refused ${method} on ${domain}'s DNS records (403${detail ? `: ${detail}` : ''}): ` +\n\t\t\t\t`the token lacks the ${scope} scope. Create a Personal Access Token ` +\n\t\t\t\t'in the GoDaddy developer dashboard with domains.dns:update — no ' +\n\t\t\t\t'domain or account scope is needed — and set GODADDY_API_TOKEN or ' +\n\t\t\t\t'run `gkm login --provider godaddy` again.',\n\t\t);\n\t\tthis.name = 'GoDaddyScopeMissing';\n\t}\n}\n\n/** GoDaddy did not accept the token at all. */\nexport class GoDaddyCredentialsInvalid extends GkmError {\n\tconstructor(readonly code?: string) {\n\t\tsuper(\n\t\t\t`GoDaddy did not accept the API token (401${code ? ` ${code}` : ''}). ` +\n\t\t\t\t'Check GODADDY_API_TOKEN, or run `gkm login --provider godaddy` ' +\n\t\t\t\t'again with a Personal Access Token from the GoDaddy developer ' +\n\t\t\t\t'dashboard that has not expired or been revoked.',\n\t\t);\n\t\tthis.name = 'GoDaddyCredentialsInvalid';\n\t}\n}\n\n/** The domain is not in the account the token belongs to. */\nexport class GoDaddyDomainNotFound extends GkmError {\n\tconstructor(\n\t\treadonly domain: string,\n\t\treadonly code?: string,\n\t) {\n\t\tsuper(\n\t\t\t`GoDaddy has no domain ${domain} in this token's account${code ? ` (${code})` : ''}. ` +\n\t\t\t\t'Check the root domain in dns, and that the token belongs to the account the domain is registered in.',\n\t\t);\n\t\tthis.name = 'GoDaddyDomainNotFound';\n\t}\n}\n\n/** Still rate limited after waiting it out. */\nexport class GoDaddyRateLimited extends GkmError {\n\tconstructor(\n\t\treadonly attempts: number,\n\t\treadonly retryAfterSec?: number,\n\t) {\n\t\tsuper(\n\t\t\t`GoDaddy is still rate limiting this token after ${attempts} attempts ` +\n\t\t\t\t'(429 TOO_MANY_REQUESTS — about 60 requests a minute are allowed). ' +\n\t\t\t\t`Wait${retryAfterSec ? ` ${retryAfterSec} seconds` : ' a minute'} and run it again; ` +\n\t\t\t\t'records already written are left as they are.',\n\t\t);\n\t\tthis.name = 'GoDaddyRateLimited';\n\t}\n}\n\n/** Any other failure from GoDaddy. */\nexport class GoDaddyRequestFailed extends Error {\n\tconstructor(\n\t\treadonly method: string,\n\t\treadonly path: string,\n\t\treadonly status: number,\n\t\treadonly code?: string,\n\t\treadonly detail?: string,\n\t) {\n\t\tsuper(\n\t\t\t`GoDaddy answered ${method} ${path} with ${status}${code ? ` ${code}` : ''}` +\n\t\t\t\t`${detail ? `: ${detail}` : ''}.` +\n\t\t\t\t(status === 422\n\t\t\t\t\t? ' A name with a CNAME cannot also have an A or AAAA record, and the reverse — remove the other one first.'\n\t\t\t\t\t: ''),\n\t\t);\n\t\tthis.name = 'GoDaddyRequestFailed';\n\t}\n}\n\n/**\n * A write gkm was about to make to a record type it never manages, or to a\n * name it was not asked for.\n */\nexport class GoDaddyRecordNotAllowed extends GkmError {\n\tconstructor(\n\t\treadonly domain: string,\n\t\treadonly type: string,\n\t\treadonly recordName: string,\n\t\treadonly reason: string,\n\t) {\n\t\tsuper(\n\t\t\t`Refused to change the ${type} record '${recordName}' on ${domain}: ${reason}. ` +\n\t\t\t\t'gkm only ever writes the A, AAAA and CNAME records of the hosts it serves.',\n\t\t);\n\t\tthis.name = 'GoDaddyRecordNotAllowed';\n\t}\n}\n\nexport interface GoDaddyApiOptions {\n\tcredential: GoDaddyCredential;\n\t/** The API's base URL. GoDaddy's production API by default. */\n\tbaseUrl?: string;\n\t/** How a 429 or 504 is waited out — `setTimeout` by default; tests pass their own. */\n\tsleep?: (ms: number) => Promise<void>;\n\t/** How many times one request is sent before a 429 or 504 is final. Default 4. */\n\tmaxAttempts?: number;\n}\n\n/** A record name GoDaddy's path takes: `@` for the apex, else relative. */\nfunction isRecordName(name: string): boolean {\n\treturn (\n\t\tname === '@' ||\n\t\t/^(\\*\\.)?[a-z0-9_](?:[a-z0-9_-]{0,61}[a-z0-9])?(\\.[a-z0-9_](?:[a-z0-9_-]{0,61}[a-z0-9])?)*$/i.test(\n\t\t\tname,\n\t\t)\n\t);\n}\n\n/** The client. Every method touches one record set, by type and name. */\nexport class GoDaddyApi {\n\tprivate readonly baseUrl: string;\n\tprivate readonly sleep: (ms: number) => Promise<void>;\n\tprivate readonly maxAttempts: number;\n\tprivate readonly authorization: string;\n\t/** Whether a read has succeeded: a later 403 is then the token's scope. */\n\tprivate readSucceeded = false;\n\n\tconstructor(options: GoDaddyApiOptions) {\n\t\tthis.baseUrl = (options.baseUrl ?? GODADDY_API_BASE).replace(/\\/$/, '');\n\t\tthis.sleep =\n\t\t\toptions.sleep ??\n\t\t\t((ms) => new Promise((resolve) => setTimeout(resolve, ms)));\n\t\tthis.maxAttempts = options.maxAttempts ?? 4;\n\t\tthis.authorization = `Bearer ${options.credential.token}`;\n\t}\n\n\t/** The records of one name and type — empty when there are none. */\n\tasync getRecordSet(\n\t\tdomain: string,\n\t\ttype: GoDaddyRecordType,\n\t\tname: string,\n\t): Promise<GoDaddyRecord[]> {\n\t\tthis.guard(domain, type, name);\n\t\tconst records = await this.request<GoDaddyRecord[]>(\n\t\t\t'GET',\n\t\t\tdomain,\n\t\t\tthis.recordPath(domain, type, name),\n\t\t);\n\t\treturn Array.isArray(records) ? records : [];\n\t}\n\n\t/** Replace one name's records of one type with `values`. */\n\tasync replaceRecordSet(\n\t\tdomain: string,\n\t\ttype: GoDaddyRecordType,\n\t\tname: string,\n\t\tvalues: readonly string[],\n\t\tttl: number,\n\t): Promise<void> {\n\t\tthis.guard(domain, type, name);\n\t\tawait this.request(\n\t\t\t'PUT',\n\t\t\tdomain,\n\t\t\tthis.recordPath(domain, type, name),\n\t\t\tvalues.map((data) => ({\n\t\t\t\tdata,\n\t\t\t\tttl: Math.max(ttl, GODADDY_MIN_TTL),\n\t\t\t})),\n\t\t);\n\t}\n\n\t/** Delete one name's records of one type. */\n\tasync deleteRecordSet(\n\t\tdomain: string,\n\t\ttype: GoDaddyRecordType,\n\t\tname: string,\n\t): Promise<void> {\n\t\tthis.guard(domain, type, name);\n\t\tawait this.request('DELETE', domain, this.recordPath(domain, type, name));\n\t}\n\n\tprivate recordPath(domain: string, type: string, name: string): string {\n\t\treturn `/v1/domains/${encodeURIComponent(domain)}/records/${type}/${encodeURIComponent(name)}`;\n\t}\n\n\t/** Only A, AAAA and CNAME, at a real record name. */\n\tprivate guard(domain: string, type: string, name: string): void {\n\t\tif (!(GODADDY_MANAGED_TYPES as readonly string[]).includes(type)) {\n\t\t\tthrow new GoDaddyRecordNotAllowed(\n\t\t\t\tdomain,\n\t\t\t\ttype,\n\t\t\t\tname,\n\t\t\t\t'it is not a type gkm manages',\n\t\t\t);\n\t\t}\n\t\tif (!isRecordName(name)) {\n\t\t\tthrow new GoDaddyRecordNotAllowed(\n\t\t\t\tdomain,\n\t\t\t\ttype,\n\t\t\t\tname,\n\t\t\t\t'it is not a record name relative to the domain',\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async request<T = unknown>(\n\t\tmethod: 'GET' | 'PUT' | 'DELETE',\n\t\tdomain: string,\n\t\tpath: string,\n\t\tbody?: unknown,\n\t): Promise<T> {\n\t\tlet retryAfterSec: number | undefined;\n\t\tfor (let attempt = 1; attempt <= this.maxAttempts; attempt++) {\n\t\t\tconst response = await fetch(`${this.baseUrl}${path}`, {\n\t\t\t\tmethod,\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: this.authorization,\n\t\t\t\t\tAccept: 'application/json',\n\t\t\t\t\t...(body !== undefined ? { 'Content-Type': 'application/json' } : {}),\n\t\t\t\t},\n\t\t\t\t...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n\t\t\t});\n\n\t\t\tif (response.ok) {\n\t\t\t\tif (method === 'GET') this.readSucceeded = true;\n\t\t\t\tif (response.status === 204) return undefined as T;\n\t\t\t\tconst text = await response.text();\n\t\t\t\treturn (text ? JSON.parse(text) : undefined) as T;\n\t\t\t}\n\n\t\t\tconst error = await errorBody(response);\n\t\t\tif (response.status === 504 && attempt < this.maxAttempts) {\n\t\t\t\tawait this.sleep(Math.min(2 ** attempt * 1000, 30_000));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (response.status === 429) {\n\t\t\t\tretryAfterSec = error.retryAfterSec;\n\t\t\t\tif (attempt === this.maxAttempts) break;\n\t\t\t\t// GoDaddy says how long; without it, back off exponentially.\n\t\t\t\tconst waitMs =\n\t\t\t\t\tretryAfterSec !== undefined\n\t\t\t\t\t\t? Math.min(retryAfterSec, 60) * 1000\n\t\t\t\t\t\t: Math.min(2 ** attempt * 1000, 60_000);\n\t\t\t\tawait this.sleep(waitMs);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (response.status === 401) {\n\t\t\t\tthrow new GoDaddyCredentialsInvalid(error.code);\n\t\t\t}\n\t\t\tif (response.status === 403) {\n\t\t\t\t// The account restriction says ACCESS_DENIED; a scoped token that\n\t\t\t\t// may not make this call says so, or — after a read went\n\t\t\t\t// through — can only be that.\n\t\t\t\tconst scoped =\n\t\t\t\t\t/scope/i.test(`${error.code ?? ''} ${error.message ?? ''}`) ||\n\t\t\t\t\t(method !== 'GET' && this.readSucceeded);\n\t\t\t\tif (scoped) {\n\t\t\t\t\tthrow new GoDaddyScopeMissing(\n\t\t\t\t\t\tmethod,\n\t\t\t\t\t\tdomain,\n\t\t\t\t\t\tmethod === 'GET' ? 'DNS records read' : 'domains.dns:update',\n\t\t\t\t\t\terror.message ?? error.code,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthrow new GoDaddyApiAccessDenied(domain, error.message ?? error.code);\n\t\t\t}\n\t\t\tif (response.status === 404) {\n\t\t\t\tthrow new GoDaddyDomainNotFound(domain, error.code);\n\t\t\t}\n\t\t\tif (\n\t\t\t\tresponse.status === 422 &&\n\t\t\t\t/domain/i.test(error.code ?? '') &&\n\t\t\t\t!/record/i.test(`${error.code ?? ''} ${error.message ?? ''}`)\n\t\t\t) {\n\t\t\t\tthrow new GoDaddyDomainNotFound(domain, error.code);\n\t\t\t}\n\t\t\tthrow new GoDaddyRequestFailed(\n\t\t\t\tmethod,\n\t\t\t\tpath,\n\t\t\t\tresponse.status,\n\t\t\t\terror.code,\n\t\t\t\terror.message,\n\t\t\t);\n\t\t}\n\t\tthrow new GoDaddyRateLimited(this.maxAttempts, retryAfterSec);\n\t}\n}\n\nasync function errorBody(response: Response): Promise<GoDaddyErrorBody> {\n\ttry {\n\t\tconst parsed = (await response.json()) as GoDaddyErrorBody;\n\t\treturn parsed && typeof parsed === 'object' ? parsed : {};\n\t} catch {\n\t\treturn {};\n\t}\n}\n","/**\n * GoDaddy DNS Provider\n *\n * Implements DnsProvider against GoDaddy's v1 API, one record set — a name\n * and a type — at a time: it reads and writes only the A, AAAA and CNAME\n * records of the names it is handed, and never the zone as a whole, a domain\n * or the account. A Personal Access Token scoped to `domains.dns:update` is all it needs.\n *\n * A token that may write records and not read them puts the provider in\n * write-only mode: every record is PUT — idempotent, so one that already has\n * its value is left as it was — and nothing is compared or deleted.\n *\n * Credentials: `GODADDY_API_TOKEN`, else what `gkm login --provider godaddy`\n * stored. Never logged.\n */\n\nimport {\n\ttype GoDaddyCredential,\n\tMissingCredential,\n\tstoredCredentials,\n} from '../../../deploy/credentials';\nimport { GkmError } from '../../../errors';\nimport {\n\ttype DeleteDnsRecord,\n\ttype DeleteResult,\n\ttype DnsProvider,\n\ttype DnsRecord,\n\tDnsRecordsUnreadable,\n\ttype UpsertDnsRecord,\n\ttype UpsertResult,\n} from './DnsProvider';\nimport {\n\tGODADDY_MANAGED_TYPES,\n\tGODADDY_MIN_TTL,\n\tGoDaddyApi,\n\tGoDaddyApiAccessDenied,\n\ttype GoDaddyApiOptions,\n\tGoDaddyDomainNotFound,\n\ttype GoDaddyRecord,\n\tGoDaddyRecordNotAllowed,\n\ttype GoDaddyRecordType,\n\tGoDaddyScopeMissing,\n} from './godaddy-api';\n\nexport interface GoDaddyProviderOptions {\n\t/** The token, when the caller already has it. */\n\tcredential?: GoDaddyCredential;\n\t/** Where the variables are read — `process.env` by default. */\n\tenv?: NodeJS.ProcessEnv;\n\t/** The CLI's home, whose `credentials.json` holds a stored login. */\n\thome?: string;\n\t/** The API's base URL, for tests. */\n\tbaseUrl?: string;\n\t/** How a 429 is waited out, for tests. */\n\tsleep?: GoDaddyApiOptions['sleep'];\n\tmaxAttempts?: number;\n\t/** Where the write-only notice goes — `console.log` by default. */\n\tlog?: (line: string) => void;\n}\n\n/** GoDaddy cannot list a zone through the records-by-name endpoints. */\nexport class GoDaddyZoneListingUnsupported extends GkmError {\n\tconstructor(readonly domain: string) {\n\t\tsuper(\n\t\t\t`gkm reads GoDaddy records by name and type only — it never lists ` +\n\t\t\t\t`${domain}'s whole zone, so a token scoped to DNS updates is enough. ` +\n\t\t\t\t'Use readRecords(domain, [{ name, type }]) instead of getRecords.',\n\t\t);\n\t\tthis.name = 'GoDaddyZoneListingUnsupported';\n\t}\n}\n\n/** A value compared the way DNS does: case-insensitive, no trailing dot. */\nfunction normalize(value: string): string {\n\treturn value.trim().replace(/\\.$/, '').toLowerCase();\n}\n\nfunction managed(type: string): type is GoDaddyRecordType {\n\treturn (GODADDY_MANAGED_TYPES as readonly string[]).includes(type);\n}\n\n/** A read GoDaddy refused: write-only, rather than a failure. */\nfunction readDenied(error: unknown): boolean {\n\treturn (\n\t\terror instanceof GoDaddyScopeMissing ||\n\t\terror instanceof GoDaddyApiAccessDenied\n\t);\n}\n\nexport class GoDaddyProvider implements DnsProvider {\n\treadonly name = 'godaddy';\n\tprivate api: GoDaddyApi | null = null;\n\t/** Set once a read is refused: every write is then a blind PUT. */\n\tprivate writeOnly = false;\n\n\tconstructor(private readonly options: GoDaddyProviderOptions = {}) {}\n\n\t/** Whether the token turned out unable to read records. */\n\tget readsDenied(): boolean {\n\t\treturn this.writeOnly;\n\t}\n\n\tprivate async getApi(): Promise<GoDaddyApi> {\n\t\tif (this.api) return this.api;\n\t\tconst credential =\n\t\t\tthis.options.credential ??\n\t\t\t(await storedCredentials({\n\t\t\t\tenv: this.options.env ?? process.env,\n\t\t\t\t...(this.options.home ? { home: this.options.home } : {}),\n\t\t\t}).get({ kind: 'godaddy' }));\n\t\tif (!credential) throw new MissingCredential('godaddy', undefined);\n\t\tthis.api = new GoDaddyApi({\n\t\t\tcredential,\n\t\t\t...(this.options.baseUrl ? { baseUrl: this.options.baseUrl } : {}),\n\t\t\t...(this.options.sleep ? { sleep: this.options.sleep } : {}),\n\t\t\t...(this.options.maxAttempts\n\t\t\t\t? { maxAttempts: this.options.maxAttempts }\n\t\t\t\t: {}),\n\t\t});\n\t\treturn this.api;\n\t}\n\n\tprivate assertManaged(domain: string, type: string, name: string): void {\n\t\tif (!managed(type)) {\n\t\t\tthrow new GoDaddyRecordNotAllowed(\n\t\t\t\tdomain,\n\t\t\t\ttype,\n\t\t\t\tname,\n\t\t\t\t'it is not a type gkm manages',\n\t\t\t);\n\t\t}\n\t}\n\n\t/** Never: the whole zone is not read. See {@link GoDaddyZoneListingUnsupported}. */\n\tasync getRecords(domain: string): Promise<DnsRecord[]> {\n\t\tthrow new GoDaddyZoneListingUnsupported(domain);\n\t}\n\n\t/**\n\t * The records of exactly these names and types, one request each.\n\t *\n\t * @throws {DnsRecordsUnreadable} when the token may not read records\n\t */\n\tasync readRecords(\n\t\tdomain: string,\n\t\twanted: readonly DeleteDnsRecord[],\n\t): Promise<DnsRecord[]> {\n\t\tfor (const { name, type } of wanted) this.assertManaged(domain, type, name);\n\t\tconst api = await this.getApi();\n\t\tconst found: DnsRecord[] = [];\n\t\tfor (const { name, type } of wanted) {\n\t\t\tlet records: GoDaddyRecord[];\n\t\t\ttry {\n\t\t\t\trecords = await api.getRecordSet(\n\t\t\t\t\tdomain,\n\t\t\t\t\ttype as GoDaddyRecordType,\n\t\t\t\t\tname,\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tif (!readDenied(error)) throw error;\n\t\t\t\tthis.writeOnly = true;\n\t\t\t\tthrow new DnsRecordsUnreadable(\n\t\t\t\t\tthis.name,\n\t\t\t\t\tdomain,\n\t\t\t\t\t(error as Error).name,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (records.length === 0) continue;\n\t\t\tfound.push({\n\t\t\t\tname,\n\t\t\t\ttype,\n\t\t\t\tttl: records[0]!.ttl ?? GODADDY_MIN_TTL,\n\t\t\t\tvalues: records.map((r) => r.data),\n\t\t\t});\n\t\t}\n\t\treturn found;\n\t}\n\n\t/**\n\t * Each record set to exactly its one value: read it, and write it only\n\t * when it differs — or, with a token that cannot read, write it. Only the\n\t * name and type of each record handed in is touched.\n\t */\n\tasync upsertRecords(\n\t\tdomain: string,\n\t\trecords: UpsertDnsRecord[],\n\t): Promise<UpsertResult[]> {\n\t\t// Every record is checked before any is written, so a refused one\n\t\t// leaves the zone as it was.\n\t\tfor (const record of records) {\n\t\t\tthis.assertManaged(domain, record.type, record.name);\n\t\t}\n\t\tconst api = await this.getApi();\n\n\t\tconst results: UpsertResult[] = [];\n\t\tfor (const record of records) {\n\t\t\tconst type = record.type as GoDaddyRecordType;\n\t\t\tlet existing: GoDaddyRecord[] | undefined;\n\t\t\tif (!this.writeOnly) {\n\t\t\t\ttry {\n\t\t\t\t\texisting = await api.getRecordSet(domain, type, record.name);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!readDenied(error)) throw error;\n\t\t\t\t\tthis.writeOnly = true;\n\t\t\t\t\t(this.options.log ?? console.log)(\n\t\t\t\t\t\t` ℹ The GoDaddy token cannot read ${domain}'s DNS records, so changes cannot be diffed: writing each record (idempotent).`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (existing) {\n\t\t\t\tconst values = existing.map((r) => normalize(r.data));\n\t\t\t\tif (values.length === 1 && values[0] === normalize(record.value)) {\n\t\t\t\t\tresults.push({ record, created: false, unchanged: true });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait api.replaceRecordSet(\n\t\t\t\tdomain,\n\t\t\t\ttype,\n\t\t\t\trecord.name,\n\t\t\t\t[record.value],\n\t\t\t\tMath.max(record.ttl, GODADDY_MIN_TTL),\n\t\t\t);\n\t\t\tresults.push({\n\t\t\t\trecord,\n\t\t\t\tcreated: existing !== undefined && existing.length === 0,\n\t\t\t\tunchanged: false,\n\t\t\t});\n\t\t}\n\t\treturn results;\n\t}\n\n\tasync deleteRecords(\n\t\tdomain: string,\n\t\trecords: DeleteDnsRecord[],\n\t): Promise<DeleteResult[]> {\n\t\tfor (const record of records) {\n\t\t\tthis.assertManaged(domain, record.type, record.name);\n\t\t}\n\t\tconst api = await this.getApi();\n\t\tconst results: DeleteResult[] = [];\n\t\tfor (const record of records) {\n\t\t\tconst type = record.type as GoDaddyRecordType;\n\t\t\tif (!this.writeOnly) {\n\t\t\t\tlet existing: GoDaddyRecord[] | undefined;\n\t\t\t\ttry {\n\t\t\t\t\texisting = await api.getRecordSet(domain, type, record.name);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!readDenied(error)) throw error;\n\t\t\t\t\tthis.writeOnly = true;\n\t\t\t\t}\n\t\t\t\tif (existing && existing.length === 0) {\n\t\t\t\t\tresults.push({ record, deleted: false, notFound: true });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait api.deleteRecordSet(domain, type, record.name);\n\t\t\t} catch (error) {\n\t\t\t\t// Write-only, nothing was read: a record that is not there is a 404.\n\t\t\t\tif (this.writeOnly && error instanceof GoDaddyDomainNotFound) {\n\t\t\t\t\tresults.push({ record, deleted: false, notFound: true });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tresults.push({ record, deleted: true, notFound: false });\n\t\t}\n\t\treturn results;\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"GoDaddyProvider-CPabc3XW.mjs","names":[],"sources":["../src/target/dokploy/dns/godaddy-api.ts","../src/target/dokploy/dns/GoDaddyProvider.ts"],"sourcesContent":["/**\n * GoDaddy's v1 DNS API, as gkm uses it: one record set — a name and a type —\n * at a time.\n *\n * - read: `GET /v1/domains/{domain}/records/{type}/{name}`\n * - write: `PUT /v1/domains/{domain}/records/{type}/{name}` with `[{ data, ttl }]`,\n * which replaces that one name's records of that one type\n * - delete: `DELETE /v1/domains/{domain}/records/{type}/{name}`\n *\n * Never the zone-wide `PUT /v1/domains/{domain}/records`, which replaces every\n * record the domain has — mail, verification TXT records and all — and never\n * a domain or account endpoint (`GET /v1/domains`, `GET /v1/domains/{domain}`):\n * a token scoped to `domains.dns:update` alone is enough. A domain that is not\n * in the token's account is told apart by the records endpoint's own 404 or 422.\n *\n * Authenticated with a Personal Access Token — `Authorization: Bearer <token>`,\n * the API's one security scheme. GoDaddy allows about 60 requests a minute per\n * token; a 429 carries `retryAfterSec`, which is waited out a few times before\n * the run gives up with {@link GoDaddyRateLimited}. A 504 is retried the same\n * way. GoDaddy refuses a TTL under 600 seconds (a 422), so every write is\n * sent with at least that.\n */\n\nimport type { GoDaddyCredential } from '../../../deploy/credentials';\nimport { GkmError } from '../../../errors';\n\nexport const GODADDY_API_BASE = 'https://api.godaddy.com';\n\n/** GoDaddy refuses a TTL below this. */\nexport const GODADDY_MIN_TTL = 600;\n\n/** The record types gkm writes. Never MX, TXT, NS, SOA, SRV or CAA. */\nexport const GODADDY_MANAGED_TYPES = ['A', 'AAAA', 'CNAME'] as const;\n\nexport type GoDaddyRecordType = (typeof GODADDY_MANAGED_TYPES)[number];\n\n/** One record as GoDaddy returns it. */\nexport interface GoDaddyRecord {\n\ttype: string;\n\tname: string;\n\tdata: string;\n\tttl?: number;\n}\n\n/** GoDaddy's error body. */\ninterface GoDaddyErrorBody {\n\tcode?: string;\n\tmessage?: string;\n\tretryAfterSec?: number;\n}\n\n/**\n * The token is good, and GoDaddy will not let it use the API: since 2024 the\n * Domains and DNS APIs answer only accounts with 10 or more domains, or a\n * Discount Domain Club Premier membership.\n */\nexport class GoDaddyApiAccessDenied extends GkmError {\n\tconstructor(\n\t\treadonly domain: string,\n\t\treadonly detail?: string,\n\t) {\n\t\tsuper(\n\t\t\t`GoDaddy refused API access for ${domain} (403 ACCESS_DENIED${detail ? `: ${detail}` : ''}). ` +\n\t\t\t\t'GoDaddy only opens its DNS API to accounts with 10 or more domains, or ' +\n\t\t\t\t'with a Discount Domain Club Premier membership, so a valid token on a ' +\n\t\t\t\t'smaller account is refused. Either qualify the account, move the ' +\n\t\t\t\t\"domain's DNS hosting to Route53 (provider: 'route53') or Cloudflare \" +\n\t\t\t\t\"by changing its nameservers at GoDaddy, or set provider: 'manual' \" +\n\t\t\t\t'and create the records gkm prints yourself. (A scoped token without ' +\n\t\t\t\t'domains.dns:update is refused the same way — check its scopes too.)',\n\t\t);\n\t\tthis.name = 'GoDaddyApiAccessDenied';\n\t}\n}\n\n/** The token lacks the scope a records call needs. */\nexport class GoDaddyScopeMissing extends GkmError {\n\tconstructor(\n\t\treadonly method: string,\n\t\treadonly domain: string,\n\t\treadonly scope: string,\n\t\treadonly detail?: string,\n\t) {\n\t\tsuper(\n\t\t\t`GoDaddy refused ${method} on ${domain}'s DNS records (403${detail ? `: ${detail}` : ''}): ` +\n\t\t\t\t`the token lacks the ${scope} scope. Create a Personal Access Token ` +\n\t\t\t\t'in the GoDaddy developer dashboard with domains.dns:update — no ' +\n\t\t\t\t'domain or account scope is needed — and set GODADDY_API_TOKEN or ' +\n\t\t\t\t'run `gkm login --provider godaddy` again.',\n\t\t);\n\t\tthis.name = 'GoDaddyScopeMissing';\n\t}\n}\n\n/** GoDaddy did not accept the token at all. */\nexport class GoDaddyCredentialsInvalid extends GkmError {\n\tconstructor(readonly code?: string) {\n\t\tsuper(\n\t\t\t`GoDaddy did not accept the API token (401${code ? ` ${code}` : ''}). ` +\n\t\t\t\t'Check GODADDY_API_TOKEN, or run `gkm login --provider godaddy` ' +\n\t\t\t\t'again with a Personal Access Token from the GoDaddy developer ' +\n\t\t\t\t'dashboard that has not expired or been revoked.',\n\t\t);\n\t\tthis.name = 'GoDaddyCredentialsInvalid';\n\t}\n}\n\n/** The domain is not in the account the token belongs to. */\nexport class GoDaddyDomainNotFound extends GkmError {\n\tconstructor(\n\t\treadonly domain: string,\n\t\treadonly code?: string,\n\t) {\n\t\tsuper(\n\t\t\t`GoDaddy has no domain ${domain} in this token's account${code ? ` (${code})` : ''}. ` +\n\t\t\t\t'Check the root domain in dns, and that the token belongs to the account the domain is registered in.',\n\t\t);\n\t\tthis.name = 'GoDaddyDomainNotFound';\n\t}\n}\n\n/** Still rate limited after waiting it out. */\nexport class GoDaddyRateLimited extends GkmError {\n\tconstructor(\n\t\treadonly attempts: number,\n\t\treadonly retryAfterSec?: number,\n\t) {\n\t\tsuper(\n\t\t\t`GoDaddy is still rate limiting this token after ${attempts} attempts ` +\n\t\t\t\t'(429 TOO_MANY_REQUESTS — about 60 requests a minute are allowed). ' +\n\t\t\t\t`Wait${retryAfterSec ? ` ${retryAfterSec} seconds` : ' a minute'} and run it again; ` +\n\t\t\t\t'records already written are left as they are.',\n\t\t);\n\t\tthis.name = 'GoDaddyRateLimited';\n\t}\n}\n\n/** Any other failure from GoDaddy. */\nexport class GoDaddyRequestFailed extends Error {\n\tconstructor(\n\t\treadonly method: string,\n\t\treadonly path: string,\n\t\treadonly status: number,\n\t\treadonly code?: string,\n\t\treadonly detail?: string,\n\t) {\n\t\tsuper(\n\t\t\t`GoDaddy answered ${method} ${path} with ${status}${code ? ` ${code}` : ''}` +\n\t\t\t\t`${detail ? `: ${detail}` : ''}.` +\n\t\t\t\t(status === 422\n\t\t\t\t\t? ' A name with a CNAME cannot also have an A or AAAA record, and the reverse — remove the other one first.'\n\t\t\t\t\t: ''),\n\t\t);\n\t\tthis.name = 'GoDaddyRequestFailed';\n\t}\n}\n\n/**\n * A write gkm was about to make to a record type it never manages, or to a\n * name it was not asked for.\n */\nexport class GoDaddyRecordNotAllowed extends GkmError {\n\tconstructor(\n\t\treadonly domain: string,\n\t\treadonly type: string,\n\t\treadonly recordName: string,\n\t\treadonly reason: string,\n\t) {\n\t\tsuper(\n\t\t\t`Refused to change the ${type} record '${recordName}' on ${domain}: ${reason}. ` +\n\t\t\t\t'gkm only ever writes the A, AAAA and CNAME records of the hosts it serves.',\n\t\t);\n\t\tthis.name = 'GoDaddyRecordNotAllowed';\n\t}\n}\n\nexport interface GoDaddyApiOptions {\n\tcredential: GoDaddyCredential;\n\t/** The API's base URL. GoDaddy's production API by default. */\n\tbaseUrl?: string;\n\t/** How a 429 or 504 is waited out — `setTimeout` by default; tests pass their own. */\n\tsleep?: (ms: number) => Promise<void>;\n\t/** How many times one request is sent before a 429 or 504 is final. Default 4. */\n\tmaxAttempts?: number;\n}\n\n/** A record name GoDaddy's path takes: `@` for the apex, else relative. */\nfunction isRecordName(name: string): boolean {\n\treturn (\n\t\tname === '@' ||\n\t\t/^(\\*\\.)?[a-z0-9_](?:[a-z0-9_-]{0,61}[a-z0-9])?(\\.[a-z0-9_](?:[a-z0-9_-]{0,61}[a-z0-9])?)*$/i.test(\n\t\t\tname,\n\t\t)\n\t);\n}\n\n/** The client. Every method touches one record set, by type and name. */\nexport class GoDaddyApi {\n\tprivate readonly baseUrl: string;\n\tprivate readonly sleep: (ms: number) => Promise<void>;\n\tprivate readonly maxAttempts: number;\n\tprivate readonly authorization: string;\n\t/** Whether a read has succeeded: a later 403 is then the token's scope. */\n\tprivate readSucceeded = false;\n\n\tconstructor(options: GoDaddyApiOptions) {\n\t\tthis.baseUrl = (options.baseUrl ?? GODADDY_API_BASE).replace(/\\/$/, '');\n\t\tthis.sleep =\n\t\t\toptions.sleep ??\n\t\t\t((ms) => new Promise((resolve) => setTimeout(resolve, ms)));\n\t\tthis.maxAttempts = options.maxAttempts ?? 4;\n\t\tthis.authorization = `Bearer ${options.credential.token}`;\n\t}\n\n\t/** The records of one name and type — empty when there are none. */\n\tasync getRecordSet(\n\t\tdomain: string,\n\t\ttype: GoDaddyRecordType,\n\t\tname: string,\n\t): Promise<GoDaddyRecord[]> {\n\t\tthis.guard(domain, type, name);\n\t\tconst records = await this.request<GoDaddyRecord[]>(\n\t\t\t'GET',\n\t\t\tdomain,\n\t\t\tthis.recordPath(domain, type, name),\n\t\t);\n\t\treturn Array.isArray(records) ? records : [];\n\t}\n\n\t/** Replace one name's records of one type with `values`. */\n\tasync replaceRecordSet(\n\t\tdomain: string,\n\t\ttype: GoDaddyRecordType,\n\t\tname: string,\n\t\tvalues: readonly string[],\n\t\tttl: number,\n\t): Promise<void> {\n\t\tthis.guard(domain, type, name);\n\t\tawait this.request(\n\t\t\t'PUT',\n\t\t\tdomain,\n\t\t\tthis.recordPath(domain, type, name),\n\t\t\tvalues.map((data) => ({\n\t\t\t\tdata,\n\t\t\t\tttl: Math.max(ttl, GODADDY_MIN_TTL),\n\t\t\t})),\n\t\t);\n\t}\n\n\t/** Delete one name's records of one type. */\n\tasync deleteRecordSet(\n\t\tdomain: string,\n\t\ttype: GoDaddyRecordType,\n\t\tname: string,\n\t): Promise<void> {\n\t\tthis.guard(domain, type, name);\n\t\tawait this.request('DELETE', domain, this.recordPath(domain, type, name));\n\t}\n\n\tprivate recordPath(domain: string, type: string, name: string): string {\n\t\treturn `/v1/domains/${encodeURIComponent(domain)}/records/${type}/${encodeURIComponent(name)}`;\n\t}\n\n\t/** Only A, AAAA and CNAME, at a real record name. */\n\tprivate guard(domain: string, type: string, name: string): void {\n\t\tif (!(GODADDY_MANAGED_TYPES as readonly string[]).includes(type)) {\n\t\t\tthrow new GoDaddyRecordNotAllowed(\n\t\t\t\tdomain,\n\t\t\t\ttype,\n\t\t\t\tname,\n\t\t\t\t'it is not a type gkm manages',\n\t\t\t);\n\t\t}\n\t\tif (!isRecordName(name)) {\n\t\t\tthrow new GoDaddyRecordNotAllowed(\n\t\t\t\tdomain,\n\t\t\t\ttype,\n\t\t\t\tname,\n\t\t\t\t'it is not a record name relative to the domain',\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async request<T = unknown>(\n\t\tmethod: 'GET' | 'PUT' | 'DELETE',\n\t\tdomain: string,\n\t\tpath: string,\n\t\tbody?: unknown,\n\t): Promise<T> {\n\t\tlet retryAfterSec: number | undefined;\n\t\tfor (let attempt = 1; attempt <= this.maxAttempts; attempt++) {\n\t\t\tconst response = await fetch(`${this.baseUrl}${path}`, {\n\t\t\t\tmethod,\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: this.authorization,\n\t\t\t\t\tAccept: 'application/json',\n\t\t\t\t\t...(body !== undefined ? { 'Content-Type': 'application/json' } : {}),\n\t\t\t\t},\n\t\t\t\t...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n\t\t\t});\n\n\t\t\tif (response.ok) {\n\t\t\t\tif (method === 'GET') this.readSucceeded = true;\n\t\t\t\tif (response.status === 204) return undefined as T;\n\t\t\t\tconst text = await response.text();\n\t\t\t\treturn (text ? JSON.parse(text) : undefined) as T;\n\t\t\t}\n\n\t\t\tconst error = await errorBody(response);\n\t\t\tif (response.status === 504 && attempt < this.maxAttempts) {\n\t\t\t\tawait this.sleep(Math.min(2 ** attempt * 1000, 30_000));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (response.status === 429) {\n\t\t\t\tretryAfterSec = error.retryAfterSec;\n\t\t\t\tif (attempt === this.maxAttempts) break;\n\t\t\t\t// GoDaddy says how long; without it, back off exponentially.\n\t\t\t\tconst waitMs =\n\t\t\t\t\tretryAfterSec !== undefined\n\t\t\t\t\t\t? Math.min(retryAfterSec, 60) * 1000\n\t\t\t\t\t\t: Math.min(2 ** attempt * 1000, 60_000);\n\t\t\t\tawait this.sleep(waitMs);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (response.status === 401) {\n\t\t\t\tthrow new GoDaddyCredentialsInvalid(error.code);\n\t\t\t}\n\t\t\tif (response.status === 403) {\n\t\t\t\t// The account restriction says ACCESS_DENIED; a scoped token that\n\t\t\t\t// may not make this call says so, or — after a read went\n\t\t\t\t// through — can only be that.\n\t\t\t\tconst scoped =\n\t\t\t\t\t/scope/i.test(`${error.code ?? ''} ${error.message ?? ''}`) ||\n\t\t\t\t\t(method !== 'GET' && this.readSucceeded);\n\t\t\t\tif (scoped) {\n\t\t\t\t\tthrow new GoDaddyScopeMissing(\n\t\t\t\t\t\tmethod,\n\t\t\t\t\t\tdomain,\n\t\t\t\t\t\tmethod === 'GET' ? 'DNS records read' : 'domains.dns:update',\n\t\t\t\t\t\terror.message ?? error.code,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthrow new GoDaddyApiAccessDenied(domain, error.message ?? error.code);\n\t\t\t}\n\t\t\tif (response.status === 404) {\n\t\t\t\tthrow new GoDaddyDomainNotFound(domain, error.code);\n\t\t\t}\n\t\t\tif (\n\t\t\t\tresponse.status === 422 &&\n\t\t\t\t/domain/i.test(error.code ?? '') &&\n\t\t\t\t!/record/i.test(`${error.code ?? ''} ${error.message ?? ''}`)\n\t\t\t) {\n\t\t\t\tthrow new GoDaddyDomainNotFound(domain, error.code);\n\t\t\t}\n\t\t\tthrow new GoDaddyRequestFailed(\n\t\t\t\tmethod,\n\t\t\t\tpath,\n\t\t\t\tresponse.status,\n\t\t\t\terror.code,\n\t\t\t\terror.message,\n\t\t\t);\n\t\t}\n\t\tthrow new GoDaddyRateLimited(this.maxAttempts, retryAfterSec);\n\t}\n}\n\nasync function errorBody(response: Response): Promise<GoDaddyErrorBody> {\n\ttry {\n\t\tconst parsed = (await response.json()) as GoDaddyErrorBody;\n\t\treturn parsed && typeof parsed === 'object' ? parsed : {};\n\t} catch {\n\t\treturn {};\n\t}\n}\n","/**\n * GoDaddy DNS Provider\n *\n * Implements DnsProvider against GoDaddy's v1 API, one record set — a name\n * and a type — at a time: it reads and writes only the A, AAAA and CNAME\n * records of the names it is handed, and never the zone as a whole, a domain\n * or the account. A Personal Access Token scoped to `domains.dns:update` is all it needs.\n *\n * A token that may write records and not read them puts the provider in\n * write-only mode: every record is PUT — idempotent, so one that already has\n * its value is left as it was — and nothing is compared or deleted.\n *\n * Credentials: `GODADDY_API_TOKEN`, else what `gkm login --provider godaddy`\n * stored. Never logged.\n */\n\nimport {\n\ttype GoDaddyCredential,\n\tMissingCredential,\n\tstoredCredentials,\n} from '../../../deploy/credentials';\nimport { GkmError } from '../../../errors';\nimport {\n\ttype DeleteDnsRecord,\n\ttype DeleteResult,\n\ttype DnsProvider,\n\ttype DnsRecord,\n\tDnsRecordsUnreadable,\n\ttype UpsertDnsRecord,\n\ttype UpsertResult,\n} from './DnsProvider';\nimport {\n\tGODADDY_MANAGED_TYPES,\n\tGODADDY_MIN_TTL,\n\tGoDaddyApi,\n\tGoDaddyApiAccessDenied,\n\ttype GoDaddyApiOptions,\n\tGoDaddyDomainNotFound,\n\ttype GoDaddyRecord,\n\tGoDaddyRecordNotAllowed,\n\ttype GoDaddyRecordType,\n\tGoDaddyScopeMissing,\n} from './godaddy-api';\n\nexport interface GoDaddyProviderOptions {\n\t/** The token, when the caller already has it. */\n\tcredential?: GoDaddyCredential;\n\t/** Where the variables are read — `process.env` by default. */\n\tenv?: NodeJS.ProcessEnv;\n\t/** The CLI's home, whose `credentials.json` holds a stored login. */\n\thome?: string;\n\t/** The API's base URL, for tests. */\n\tbaseUrl?: string;\n\t/** How a 429 is waited out, for tests. */\n\tsleep?: GoDaddyApiOptions['sleep'];\n\tmaxAttempts?: number;\n\t/** Where the write-only notice goes — `console.log` by default. */\n\tlog?: (line: string) => void;\n}\n\n/** GoDaddy cannot list a zone through the records-by-name endpoints. */\nexport class GoDaddyZoneListingUnsupported extends GkmError {\n\tconstructor(readonly domain: string) {\n\t\tsuper(\n\t\t\t`gkm reads GoDaddy records by name and type only — it never lists ` +\n\t\t\t\t`${domain}'s whole zone, so a token scoped to DNS updates is enough. ` +\n\t\t\t\t'Use readRecords(domain, [{ name, type }]) instead of getRecords.',\n\t\t);\n\t\tthis.name = 'GoDaddyZoneListingUnsupported';\n\t}\n}\n\n/** A value compared the way DNS does: case-insensitive, no trailing dot. */\nfunction normalize(value: string): string {\n\treturn value.trim().replace(/\\.$/, '').toLowerCase();\n}\n\nfunction managed(type: string): type is GoDaddyRecordType {\n\treturn (GODADDY_MANAGED_TYPES as readonly string[]).includes(type);\n}\n\n/** A read GoDaddy refused: write-only, rather than a failure. */\nfunction readDenied(error: unknown): boolean {\n\treturn (\n\t\terror instanceof GoDaddyScopeMissing ||\n\t\terror instanceof GoDaddyApiAccessDenied\n\t);\n}\n\nexport class GoDaddyProvider implements DnsProvider {\n\treadonly name = 'godaddy';\n\tprivate api: GoDaddyApi | null = null;\n\t/** Set once a read is refused: every write is then a blind PUT. */\n\tprivate writeOnly = false;\n\n\tconstructor(private readonly options: GoDaddyProviderOptions = {}) {}\n\n\t/** Whether the token turned out unable to read records. */\n\tget readsDenied(): boolean {\n\t\treturn this.writeOnly;\n\t}\n\n\tprivate async getApi(): Promise<GoDaddyApi> {\n\t\tif (this.api) return this.api;\n\t\tconst credential =\n\t\t\tthis.options.credential ??\n\t\t\t(await storedCredentials({\n\t\t\t\tenv: this.options.env ?? process.env,\n\t\t\t\t...(this.options.home ? { home: this.options.home } : {}),\n\t\t\t}).get({ kind: 'godaddy' }));\n\t\tif (!credential) throw new MissingCredential('godaddy', undefined);\n\t\tthis.api = new GoDaddyApi({\n\t\t\tcredential,\n\t\t\t...(this.options.baseUrl ? { baseUrl: this.options.baseUrl } : {}),\n\t\t\t...(this.options.sleep ? { sleep: this.options.sleep } : {}),\n\t\t\t...(this.options.maxAttempts\n\t\t\t\t? { maxAttempts: this.options.maxAttempts }\n\t\t\t\t: {}),\n\t\t});\n\t\treturn this.api;\n\t}\n\n\tprivate assertManaged(domain: string, type: string, name: string): void {\n\t\tif (!managed(type)) {\n\t\t\tthrow new GoDaddyRecordNotAllowed(\n\t\t\t\tdomain,\n\t\t\t\ttype,\n\t\t\t\tname,\n\t\t\t\t'it is not a type gkm manages',\n\t\t\t);\n\t\t}\n\t}\n\n\t/** Never: the whole zone is not read. See {@link GoDaddyZoneListingUnsupported}. */\n\tasync getRecords(domain: string): Promise<DnsRecord[]> {\n\t\tthrow new GoDaddyZoneListingUnsupported(domain);\n\t}\n\n\t/**\n\t * The records of exactly these names and types, one request each.\n\t *\n\t * @throws {DnsRecordsUnreadable} when the token may not read records\n\t */\n\tasync readRecords(\n\t\tdomain: string,\n\t\twanted: readonly DeleteDnsRecord[],\n\t): Promise<DnsRecord[]> {\n\t\tfor (const { name, type } of wanted) this.assertManaged(domain, type, name);\n\t\tconst api = await this.getApi();\n\t\tconst found: DnsRecord[] = [];\n\t\tfor (const { name, type } of wanted) {\n\t\t\tlet records: GoDaddyRecord[];\n\t\t\ttry {\n\t\t\t\trecords = await api.getRecordSet(\n\t\t\t\t\tdomain,\n\t\t\t\t\ttype as GoDaddyRecordType,\n\t\t\t\t\tname,\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tif (!readDenied(error)) throw error;\n\t\t\t\tthis.writeOnly = true;\n\t\t\t\tthrow new DnsRecordsUnreadable(\n\t\t\t\t\tthis.name,\n\t\t\t\t\tdomain,\n\t\t\t\t\t(error as Error).name,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (records.length === 0) continue;\n\t\t\tfound.push({\n\t\t\t\tname,\n\t\t\t\ttype,\n\t\t\t\tttl: records[0]!.ttl ?? GODADDY_MIN_TTL,\n\t\t\t\tvalues: records.map((r) => r.data),\n\t\t\t});\n\t\t}\n\t\treturn found;\n\t}\n\n\t/**\n\t * Each record set to exactly its one value: read it, and write it only\n\t * when it differs — or, with a token that cannot read, write it. Only the\n\t * name and type of each record handed in is touched.\n\t */\n\tasync upsertRecords(\n\t\tdomain: string,\n\t\trecords: UpsertDnsRecord[],\n\t): Promise<UpsertResult[]> {\n\t\t// Every record is checked before any is written, so a refused one\n\t\t// leaves the zone as it was.\n\t\tfor (const record of records) {\n\t\t\tthis.assertManaged(domain, record.type, record.name);\n\t\t}\n\t\tconst api = await this.getApi();\n\n\t\tconst results: UpsertResult[] = [];\n\t\tfor (const record of records) {\n\t\t\tconst type = record.type as GoDaddyRecordType;\n\t\t\tlet existing: GoDaddyRecord[] | undefined;\n\t\t\tif (!this.writeOnly) {\n\t\t\t\ttry {\n\t\t\t\t\texisting = await api.getRecordSet(domain, type, record.name);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!readDenied(error)) throw error;\n\t\t\t\t\tthis.writeOnly = true;\n\t\t\t\t\t(this.options.log ?? console.log)(\n\t\t\t\t\t\t` ℹ The GoDaddy token cannot read ${domain}'s DNS records, so changes cannot be diffed: writing each record (idempotent).`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (existing) {\n\t\t\t\tconst values = existing.map((r) => normalize(r.data));\n\t\t\t\tif (values.length === 1 && values[0] === normalize(record.value)) {\n\t\t\t\t\tresults.push({ record, created: false, unchanged: true });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait api.replaceRecordSet(\n\t\t\t\tdomain,\n\t\t\t\ttype,\n\t\t\t\trecord.name,\n\t\t\t\t[record.value],\n\t\t\t\tMath.max(record.ttl, GODADDY_MIN_TTL),\n\t\t\t);\n\t\t\tresults.push({\n\t\t\t\trecord,\n\t\t\t\tcreated: existing !== undefined && existing.length === 0,\n\t\t\t\tunchanged: false,\n\t\t\t});\n\t\t}\n\t\treturn results;\n\t}\n\n\tasync deleteRecords(\n\t\tdomain: string,\n\t\trecords: DeleteDnsRecord[],\n\t): Promise<DeleteResult[]> {\n\t\tfor (const record of records) {\n\t\t\tthis.assertManaged(domain, record.type, record.name);\n\t\t}\n\t\tconst api = await this.getApi();\n\t\tconst results: DeleteResult[] = [];\n\t\tfor (const record of records) {\n\t\t\tconst type = record.type as GoDaddyRecordType;\n\t\t\tif (!this.writeOnly) {\n\t\t\t\tlet existing: GoDaddyRecord[] | undefined;\n\t\t\t\ttry {\n\t\t\t\t\texisting = await api.getRecordSet(domain, type, record.name);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!readDenied(error)) throw error;\n\t\t\t\t\tthis.writeOnly = true;\n\t\t\t\t}\n\t\t\t\tif (existing && existing.length === 0) {\n\t\t\t\t\tresults.push({ record, deleted: false, notFound: true });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait api.deleteRecordSet(domain, type, record.name);\n\t\t\t} catch (error) {\n\t\t\t\t// Write-only, nothing was read: a record that is not there is a 404.\n\t\t\t\tif (this.writeOnly && error instanceof GoDaddyDomainNotFound) {\n\t\t\t\t\tresults.push({ record, deleted: false, notFound: true });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tresults.push({ record, deleted: true, notFound: false });\n\t\t}\n\t\treturn results;\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require_errors = require("./errors-DMC4Umsb.cjs");
|
|
2
2
|
const require_credentials = require("./credentials-Zqr3QQYB.cjs");
|
|
3
|
-
const require_seeds = require("./seeds-
|
|
3
|
+
const require_seeds = require("./seeds-Dk8YkLkM.cjs");
|
|
4
4
|
/** The record types gkm writes. Never MX, TXT, NS, SOA, SRV or CAA. */
|
|
5
5
|
const GODADDY_MANAGED_TYPES = [
|
|
6
6
|
"A",
|
|
@@ -385,4 +385,4 @@ var GoDaddyProvider = class {
|
|
|
385
385
|
//#endregion
|
|
386
386
|
exports.GoDaddyProvider = GoDaddyProvider;
|
|
387
387
|
|
|
388
|
-
//# sourceMappingURL=GoDaddyProvider-
|
|
388
|
+
//# sourceMappingURL=GoDaddyProvider-DWrDIXzQ.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GoDaddyProvider-qNUzTXI7.cjs","names":["GkmError","GkmError","storedCredentials","MissingCredential","DnsRecordsUnreadable"],"sources":["../src/target/dokploy/dns/godaddy-api.ts","../src/target/dokploy/dns/GoDaddyProvider.ts"],"sourcesContent":["/**\n * GoDaddy's v1 DNS API, as gkm uses it: one record set — a name and a type —\n * at a time.\n *\n * - read: `GET /v1/domains/{domain}/records/{type}/{name}`\n * - write: `PUT /v1/domains/{domain}/records/{type}/{name}` with `[{ data, ttl }]`,\n * which replaces that one name's records of that one type\n * - delete: `DELETE /v1/domains/{domain}/records/{type}/{name}`\n *\n * Never the zone-wide `PUT /v1/domains/{domain}/records`, which replaces every\n * record the domain has — mail, verification TXT records and all — and never\n * a domain or account endpoint (`GET /v1/domains`, `GET /v1/domains/{domain}`):\n * a token scoped to `domains.dns:update` alone is enough. A domain that is not\n * in the token's account is told apart by the records endpoint's own 404 or 422.\n *\n * Authenticated with a Personal Access Token — `Authorization: Bearer <token>`,\n * the API's one security scheme. GoDaddy allows about 60 requests a minute per\n * token; a 429 carries `retryAfterSec`, which is waited out a few times before\n * the run gives up with {@link GoDaddyRateLimited}. A 504 is retried the same\n * way. GoDaddy refuses a TTL under 600 seconds (a 422), so every write is\n * sent with at least that.\n */\n\nimport type { GoDaddyCredential } from '../../../deploy/credentials';\nimport { GkmError } from '../../../errors';\n\nexport const GODADDY_API_BASE = 'https://api.godaddy.com';\n\n/** GoDaddy refuses a TTL below this. */\nexport const GODADDY_MIN_TTL = 600;\n\n/** The record types gkm writes. Never MX, TXT, NS, SOA, SRV or CAA. */\nexport const GODADDY_MANAGED_TYPES = ['A', 'AAAA', 'CNAME'] as const;\n\nexport type GoDaddyRecordType = (typeof GODADDY_MANAGED_TYPES)[number];\n\n/** One record as GoDaddy returns it. */\nexport interface GoDaddyRecord {\n\ttype: string;\n\tname: string;\n\tdata: string;\n\tttl?: number;\n}\n\n/** GoDaddy's error body. */\ninterface GoDaddyErrorBody {\n\tcode?: string;\n\tmessage?: string;\n\tretryAfterSec?: number;\n}\n\n/**\n * The token is good, and GoDaddy will not let it use the API: since 2024 the\n * Domains and DNS APIs answer only accounts with 10 or more domains, or a\n * Discount Domain Club Premier membership.\n */\nexport class GoDaddyApiAccessDenied extends GkmError {\n\tconstructor(\n\t\treadonly domain: string,\n\t\treadonly detail?: string,\n\t) {\n\t\tsuper(\n\t\t\t`GoDaddy refused API access for ${domain} (403 ACCESS_DENIED${detail ? `: ${detail}` : ''}). ` +\n\t\t\t\t'GoDaddy only opens its DNS API to accounts with 10 or more domains, or ' +\n\t\t\t\t'with a Discount Domain Club Premier membership, so a valid token on a ' +\n\t\t\t\t'smaller account is refused. Either qualify the account, move the ' +\n\t\t\t\t\"domain's DNS hosting to Route53 (provider: 'route53') or Cloudflare \" +\n\t\t\t\t\"by changing its nameservers at GoDaddy, or set provider: 'manual' \" +\n\t\t\t\t'and create the records gkm prints yourself. (A scoped token without ' +\n\t\t\t\t'domains.dns:update is refused the same way — check its scopes too.)',\n\t\t);\n\t\tthis.name = 'GoDaddyApiAccessDenied';\n\t}\n}\n\n/** The token lacks the scope a records call needs. */\nexport class GoDaddyScopeMissing extends GkmError {\n\tconstructor(\n\t\treadonly method: string,\n\t\treadonly domain: string,\n\t\treadonly scope: string,\n\t\treadonly detail?: string,\n\t) {\n\t\tsuper(\n\t\t\t`GoDaddy refused ${method} on ${domain}'s DNS records (403${detail ? `: ${detail}` : ''}): ` +\n\t\t\t\t`the token lacks the ${scope} scope. Create a Personal Access Token ` +\n\t\t\t\t'in the GoDaddy developer dashboard with domains.dns:update — no ' +\n\t\t\t\t'domain or account scope is needed — and set GODADDY_API_TOKEN or ' +\n\t\t\t\t'run `gkm login --provider godaddy` again.',\n\t\t);\n\t\tthis.name = 'GoDaddyScopeMissing';\n\t}\n}\n\n/** GoDaddy did not accept the token at all. */\nexport class GoDaddyCredentialsInvalid extends GkmError {\n\tconstructor(readonly code?: string) {\n\t\tsuper(\n\t\t\t`GoDaddy did not accept the API token (401${code ? ` ${code}` : ''}). ` +\n\t\t\t\t'Check GODADDY_API_TOKEN, or run `gkm login --provider godaddy` ' +\n\t\t\t\t'again with a Personal Access Token from the GoDaddy developer ' +\n\t\t\t\t'dashboard that has not expired or been revoked.',\n\t\t);\n\t\tthis.name = 'GoDaddyCredentialsInvalid';\n\t}\n}\n\n/** The domain is not in the account the token belongs to. */\nexport class GoDaddyDomainNotFound extends GkmError {\n\tconstructor(\n\t\treadonly domain: string,\n\t\treadonly code?: string,\n\t) {\n\t\tsuper(\n\t\t\t`GoDaddy has no domain ${domain} in this token's account${code ? ` (${code})` : ''}. ` +\n\t\t\t\t'Check the root domain in dns, and that the token belongs to the account the domain is registered in.',\n\t\t);\n\t\tthis.name = 'GoDaddyDomainNotFound';\n\t}\n}\n\n/** Still rate limited after waiting it out. */\nexport class GoDaddyRateLimited extends GkmError {\n\tconstructor(\n\t\treadonly attempts: number,\n\t\treadonly retryAfterSec?: number,\n\t) {\n\t\tsuper(\n\t\t\t`GoDaddy is still rate limiting this token after ${attempts} attempts ` +\n\t\t\t\t'(429 TOO_MANY_REQUESTS — about 60 requests a minute are allowed). ' +\n\t\t\t\t`Wait${retryAfterSec ? ` ${retryAfterSec} seconds` : ' a minute'} and run it again; ` +\n\t\t\t\t'records already written are left as they are.',\n\t\t);\n\t\tthis.name = 'GoDaddyRateLimited';\n\t}\n}\n\n/** Any other failure from GoDaddy. */\nexport class GoDaddyRequestFailed extends Error {\n\tconstructor(\n\t\treadonly method: string,\n\t\treadonly path: string,\n\t\treadonly status: number,\n\t\treadonly code?: string,\n\t\treadonly detail?: string,\n\t) {\n\t\tsuper(\n\t\t\t`GoDaddy answered ${method} ${path} with ${status}${code ? ` ${code}` : ''}` +\n\t\t\t\t`${detail ? `: ${detail}` : ''}.` +\n\t\t\t\t(status === 422\n\t\t\t\t\t? ' A name with a CNAME cannot also have an A or AAAA record, and the reverse — remove the other one first.'\n\t\t\t\t\t: ''),\n\t\t);\n\t\tthis.name = 'GoDaddyRequestFailed';\n\t}\n}\n\n/**\n * A write gkm was about to make to a record type it never manages, or to a\n * name it was not asked for.\n */\nexport class GoDaddyRecordNotAllowed extends GkmError {\n\tconstructor(\n\t\treadonly domain: string,\n\t\treadonly type: string,\n\t\treadonly recordName: string,\n\t\treadonly reason: string,\n\t) {\n\t\tsuper(\n\t\t\t`Refused to change the ${type} record '${recordName}' on ${domain}: ${reason}. ` +\n\t\t\t\t'gkm only ever writes the A, AAAA and CNAME records of the hosts it serves.',\n\t\t);\n\t\tthis.name = 'GoDaddyRecordNotAllowed';\n\t}\n}\n\nexport interface GoDaddyApiOptions {\n\tcredential: GoDaddyCredential;\n\t/** The API's base URL. GoDaddy's production API by default. */\n\tbaseUrl?: string;\n\t/** How a 429 or 504 is waited out — `setTimeout` by default; tests pass their own. */\n\tsleep?: (ms: number) => Promise<void>;\n\t/** How many times one request is sent before a 429 or 504 is final. Default 4. */\n\tmaxAttempts?: number;\n}\n\n/** A record name GoDaddy's path takes: `@` for the apex, else relative. */\nfunction isRecordName(name: string): boolean {\n\treturn (\n\t\tname === '@' ||\n\t\t/^(\\*\\.)?[a-z0-9_](?:[a-z0-9_-]{0,61}[a-z0-9])?(\\.[a-z0-9_](?:[a-z0-9_-]{0,61}[a-z0-9])?)*$/i.test(\n\t\t\tname,\n\t\t)\n\t);\n}\n\n/** The client. Every method touches one record set, by type and name. */\nexport class GoDaddyApi {\n\tprivate readonly baseUrl: string;\n\tprivate readonly sleep: (ms: number) => Promise<void>;\n\tprivate readonly maxAttempts: number;\n\tprivate readonly authorization: string;\n\t/** Whether a read has succeeded: a later 403 is then the token's scope. */\n\tprivate readSucceeded = false;\n\n\tconstructor(options: GoDaddyApiOptions) {\n\t\tthis.baseUrl = (options.baseUrl ?? GODADDY_API_BASE).replace(/\\/$/, '');\n\t\tthis.sleep =\n\t\t\toptions.sleep ??\n\t\t\t((ms) => new Promise((resolve) => setTimeout(resolve, ms)));\n\t\tthis.maxAttempts = options.maxAttempts ?? 4;\n\t\tthis.authorization = `Bearer ${options.credential.token}`;\n\t}\n\n\t/** The records of one name and type — empty when there are none. */\n\tasync getRecordSet(\n\t\tdomain: string,\n\t\ttype: GoDaddyRecordType,\n\t\tname: string,\n\t): Promise<GoDaddyRecord[]> {\n\t\tthis.guard(domain, type, name);\n\t\tconst records = await this.request<GoDaddyRecord[]>(\n\t\t\t'GET',\n\t\t\tdomain,\n\t\t\tthis.recordPath(domain, type, name),\n\t\t);\n\t\treturn Array.isArray(records) ? records : [];\n\t}\n\n\t/** Replace one name's records of one type with `values`. */\n\tasync replaceRecordSet(\n\t\tdomain: string,\n\t\ttype: GoDaddyRecordType,\n\t\tname: string,\n\t\tvalues: readonly string[],\n\t\tttl: number,\n\t): Promise<void> {\n\t\tthis.guard(domain, type, name);\n\t\tawait this.request(\n\t\t\t'PUT',\n\t\t\tdomain,\n\t\t\tthis.recordPath(domain, type, name),\n\t\t\tvalues.map((data) => ({\n\t\t\t\tdata,\n\t\t\t\tttl: Math.max(ttl, GODADDY_MIN_TTL),\n\t\t\t})),\n\t\t);\n\t}\n\n\t/** Delete one name's records of one type. */\n\tasync deleteRecordSet(\n\t\tdomain: string,\n\t\ttype: GoDaddyRecordType,\n\t\tname: string,\n\t): Promise<void> {\n\t\tthis.guard(domain, type, name);\n\t\tawait this.request('DELETE', domain, this.recordPath(domain, type, name));\n\t}\n\n\tprivate recordPath(domain: string, type: string, name: string): string {\n\t\treturn `/v1/domains/${encodeURIComponent(domain)}/records/${type}/${encodeURIComponent(name)}`;\n\t}\n\n\t/** Only A, AAAA and CNAME, at a real record name. */\n\tprivate guard(domain: string, type: string, name: string): void {\n\t\tif (!(GODADDY_MANAGED_TYPES as readonly string[]).includes(type)) {\n\t\t\tthrow new GoDaddyRecordNotAllowed(\n\t\t\t\tdomain,\n\t\t\t\ttype,\n\t\t\t\tname,\n\t\t\t\t'it is not a type gkm manages',\n\t\t\t);\n\t\t}\n\t\tif (!isRecordName(name)) {\n\t\t\tthrow new GoDaddyRecordNotAllowed(\n\t\t\t\tdomain,\n\t\t\t\ttype,\n\t\t\t\tname,\n\t\t\t\t'it is not a record name relative to the domain',\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async request<T = unknown>(\n\t\tmethod: 'GET' | 'PUT' | 'DELETE',\n\t\tdomain: string,\n\t\tpath: string,\n\t\tbody?: unknown,\n\t): Promise<T> {\n\t\tlet retryAfterSec: number | undefined;\n\t\tfor (let attempt = 1; attempt <= this.maxAttempts; attempt++) {\n\t\t\tconst response = await fetch(`${this.baseUrl}${path}`, {\n\t\t\t\tmethod,\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: this.authorization,\n\t\t\t\t\tAccept: 'application/json',\n\t\t\t\t\t...(body !== undefined ? { 'Content-Type': 'application/json' } : {}),\n\t\t\t\t},\n\t\t\t\t...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n\t\t\t});\n\n\t\t\tif (response.ok) {\n\t\t\t\tif (method === 'GET') this.readSucceeded = true;\n\t\t\t\tif (response.status === 204) return undefined as T;\n\t\t\t\tconst text = await response.text();\n\t\t\t\treturn (text ? JSON.parse(text) : undefined) as T;\n\t\t\t}\n\n\t\t\tconst error = await errorBody(response);\n\t\t\tif (response.status === 504 && attempt < this.maxAttempts) {\n\t\t\t\tawait this.sleep(Math.min(2 ** attempt * 1000, 30_000));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (response.status === 429) {\n\t\t\t\tretryAfterSec = error.retryAfterSec;\n\t\t\t\tif (attempt === this.maxAttempts) break;\n\t\t\t\t// GoDaddy says how long; without it, back off exponentially.\n\t\t\t\tconst waitMs =\n\t\t\t\t\tretryAfterSec !== undefined\n\t\t\t\t\t\t? Math.min(retryAfterSec, 60) * 1000\n\t\t\t\t\t\t: Math.min(2 ** attempt * 1000, 60_000);\n\t\t\t\tawait this.sleep(waitMs);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (response.status === 401) {\n\t\t\t\tthrow new GoDaddyCredentialsInvalid(error.code);\n\t\t\t}\n\t\t\tif (response.status === 403) {\n\t\t\t\t// The account restriction says ACCESS_DENIED; a scoped token that\n\t\t\t\t// may not make this call says so, or — after a read went\n\t\t\t\t// through — can only be that.\n\t\t\t\tconst scoped =\n\t\t\t\t\t/scope/i.test(`${error.code ?? ''} ${error.message ?? ''}`) ||\n\t\t\t\t\t(method !== 'GET' && this.readSucceeded);\n\t\t\t\tif (scoped) {\n\t\t\t\t\tthrow new GoDaddyScopeMissing(\n\t\t\t\t\t\tmethod,\n\t\t\t\t\t\tdomain,\n\t\t\t\t\t\tmethod === 'GET' ? 'DNS records read' : 'domains.dns:update',\n\t\t\t\t\t\terror.message ?? error.code,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthrow new GoDaddyApiAccessDenied(domain, error.message ?? error.code);\n\t\t\t}\n\t\t\tif (response.status === 404) {\n\t\t\t\tthrow new GoDaddyDomainNotFound(domain, error.code);\n\t\t\t}\n\t\t\tif (\n\t\t\t\tresponse.status === 422 &&\n\t\t\t\t/domain/i.test(error.code ?? '') &&\n\t\t\t\t!/record/i.test(`${error.code ?? ''} ${error.message ?? ''}`)\n\t\t\t) {\n\t\t\t\tthrow new GoDaddyDomainNotFound(domain, error.code);\n\t\t\t}\n\t\t\tthrow new GoDaddyRequestFailed(\n\t\t\t\tmethod,\n\t\t\t\tpath,\n\t\t\t\tresponse.status,\n\t\t\t\terror.code,\n\t\t\t\terror.message,\n\t\t\t);\n\t\t}\n\t\tthrow new GoDaddyRateLimited(this.maxAttempts, retryAfterSec);\n\t}\n}\n\nasync function errorBody(response: Response): Promise<GoDaddyErrorBody> {\n\ttry {\n\t\tconst parsed = (await response.json()) as GoDaddyErrorBody;\n\t\treturn parsed && typeof parsed === 'object' ? parsed : {};\n\t} catch {\n\t\treturn {};\n\t}\n}\n","/**\n * GoDaddy DNS Provider\n *\n * Implements DnsProvider against GoDaddy's v1 API, one record set — a name\n * and a type — at a time: it reads and writes only the A, AAAA and CNAME\n * records of the names it is handed, and never the zone as a whole, a domain\n * or the account. A Personal Access Token scoped to `domains.dns:update` is all it needs.\n *\n * A token that may write records and not read them puts the provider in\n * write-only mode: every record is PUT — idempotent, so one that already has\n * its value is left as it was — and nothing is compared or deleted.\n *\n * Credentials: `GODADDY_API_TOKEN`, else what `gkm login --provider godaddy`\n * stored. Never logged.\n */\n\nimport {\n\ttype GoDaddyCredential,\n\tMissingCredential,\n\tstoredCredentials,\n} from '../../../deploy/credentials';\nimport { GkmError } from '../../../errors';\nimport {\n\ttype DeleteDnsRecord,\n\ttype DeleteResult,\n\ttype DnsProvider,\n\ttype DnsRecord,\n\tDnsRecordsUnreadable,\n\ttype UpsertDnsRecord,\n\ttype UpsertResult,\n} from './DnsProvider';\nimport {\n\tGODADDY_MANAGED_TYPES,\n\tGODADDY_MIN_TTL,\n\tGoDaddyApi,\n\tGoDaddyApiAccessDenied,\n\ttype GoDaddyApiOptions,\n\tGoDaddyDomainNotFound,\n\ttype GoDaddyRecord,\n\tGoDaddyRecordNotAllowed,\n\ttype GoDaddyRecordType,\n\tGoDaddyScopeMissing,\n} from './godaddy-api';\n\nexport interface GoDaddyProviderOptions {\n\t/** The token, when the caller already has it. */\n\tcredential?: GoDaddyCredential;\n\t/** Where the variables are read — `process.env` by default. */\n\tenv?: NodeJS.ProcessEnv;\n\t/** The CLI's home, whose `credentials.json` holds a stored login. */\n\thome?: string;\n\t/** The API's base URL, for tests. */\n\tbaseUrl?: string;\n\t/** How a 429 is waited out, for tests. */\n\tsleep?: GoDaddyApiOptions['sleep'];\n\tmaxAttempts?: number;\n\t/** Where the write-only notice goes — `console.log` by default. */\n\tlog?: (line: string) => void;\n}\n\n/** GoDaddy cannot list a zone through the records-by-name endpoints. */\nexport class GoDaddyZoneListingUnsupported extends GkmError {\n\tconstructor(readonly domain: string) {\n\t\tsuper(\n\t\t\t`gkm reads GoDaddy records by name and type only — it never lists ` +\n\t\t\t\t`${domain}'s whole zone, so a token scoped to DNS updates is enough. ` +\n\t\t\t\t'Use readRecords(domain, [{ name, type }]) instead of getRecords.',\n\t\t);\n\t\tthis.name = 'GoDaddyZoneListingUnsupported';\n\t}\n}\n\n/** A value compared the way DNS does: case-insensitive, no trailing dot. */\nfunction normalize(value: string): string {\n\treturn value.trim().replace(/\\.$/, '').toLowerCase();\n}\n\nfunction managed(type: string): type is GoDaddyRecordType {\n\treturn (GODADDY_MANAGED_TYPES as readonly string[]).includes(type);\n}\n\n/** A read GoDaddy refused: write-only, rather than a failure. */\nfunction readDenied(error: unknown): boolean {\n\treturn (\n\t\terror instanceof GoDaddyScopeMissing ||\n\t\terror instanceof GoDaddyApiAccessDenied\n\t);\n}\n\nexport class GoDaddyProvider implements DnsProvider {\n\treadonly name = 'godaddy';\n\tprivate api: GoDaddyApi | null = null;\n\t/** Set once a read is refused: every write is then a blind PUT. */\n\tprivate writeOnly = false;\n\n\tconstructor(private readonly options: GoDaddyProviderOptions = {}) {}\n\n\t/** Whether the token turned out unable to read records. */\n\tget readsDenied(): boolean {\n\t\treturn this.writeOnly;\n\t}\n\n\tprivate async getApi(): Promise<GoDaddyApi> {\n\t\tif (this.api) return this.api;\n\t\tconst credential =\n\t\t\tthis.options.credential ??\n\t\t\t(await storedCredentials({\n\t\t\t\tenv: this.options.env ?? process.env,\n\t\t\t\t...(this.options.home ? { home: this.options.home } : {}),\n\t\t\t}).get({ kind: 'godaddy' }));\n\t\tif (!credential) throw new MissingCredential('godaddy', undefined);\n\t\tthis.api = new GoDaddyApi({\n\t\t\tcredential,\n\t\t\t...(this.options.baseUrl ? { baseUrl: this.options.baseUrl } : {}),\n\t\t\t...(this.options.sleep ? { sleep: this.options.sleep } : {}),\n\t\t\t...(this.options.maxAttempts\n\t\t\t\t? { maxAttempts: this.options.maxAttempts }\n\t\t\t\t: {}),\n\t\t});\n\t\treturn this.api;\n\t}\n\n\tprivate assertManaged(domain: string, type: string, name: string): void {\n\t\tif (!managed(type)) {\n\t\t\tthrow new GoDaddyRecordNotAllowed(\n\t\t\t\tdomain,\n\t\t\t\ttype,\n\t\t\t\tname,\n\t\t\t\t'it is not a type gkm manages',\n\t\t\t);\n\t\t}\n\t}\n\n\t/** Never: the whole zone is not read. See {@link GoDaddyZoneListingUnsupported}. */\n\tasync getRecords(domain: string): Promise<DnsRecord[]> {\n\t\tthrow new GoDaddyZoneListingUnsupported(domain);\n\t}\n\n\t/**\n\t * The records of exactly these names and types, one request each.\n\t *\n\t * @throws {DnsRecordsUnreadable} when the token may not read records\n\t */\n\tasync readRecords(\n\t\tdomain: string,\n\t\twanted: readonly DeleteDnsRecord[],\n\t): Promise<DnsRecord[]> {\n\t\tfor (const { name, type } of wanted) this.assertManaged(domain, type, name);\n\t\tconst api = await this.getApi();\n\t\tconst found: DnsRecord[] = [];\n\t\tfor (const { name, type } of wanted) {\n\t\t\tlet records: GoDaddyRecord[];\n\t\t\ttry {\n\t\t\t\trecords = await api.getRecordSet(\n\t\t\t\t\tdomain,\n\t\t\t\t\ttype as GoDaddyRecordType,\n\t\t\t\t\tname,\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tif (!readDenied(error)) throw error;\n\t\t\t\tthis.writeOnly = true;\n\t\t\t\tthrow new DnsRecordsUnreadable(\n\t\t\t\t\tthis.name,\n\t\t\t\t\tdomain,\n\t\t\t\t\t(error as Error).name,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (records.length === 0) continue;\n\t\t\tfound.push({\n\t\t\t\tname,\n\t\t\t\ttype,\n\t\t\t\tttl: records[0]!.ttl ?? GODADDY_MIN_TTL,\n\t\t\t\tvalues: records.map((r) => r.data),\n\t\t\t});\n\t\t}\n\t\treturn found;\n\t}\n\n\t/**\n\t * Each record set to exactly its one value: read it, and write it only\n\t * when it differs — or, with a token that cannot read, write it. Only the\n\t * name and type of each record handed in is touched.\n\t */\n\tasync upsertRecords(\n\t\tdomain: string,\n\t\trecords: UpsertDnsRecord[],\n\t): Promise<UpsertResult[]> {\n\t\t// Every record is checked before any is written, so a refused one\n\t\t// leaves the zone as it was.\n\t\tfor (const record of records) {\n\t\t\tthis.assertManaged(domain, record.type, record.name);\n\t\t}\n\t\tconst api = await this.getApi();\n\n\t\tconst results: UpsertResult[] = [];\n\t\tfor (const record of records) {\n\t\t\tconst type = record.type as GoDaddyRecordType;\n\t\t\tlet existing: GoDaddyRecord[] | undefined;\n\t\t\tif (!this.writeOnly) {\n\t\t\t\ttry {\n\t\t\t\t\texisting = await api.getRecordSet(domain, type, record.name);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!readDenied(error)) throw error;\n\t\t\t\t\tthis.writeOnly = true;\n\t\t\t\t\t(this.options.log ?? console.log)(\n\t\t\t\t\t\t` ℹ The GoDaddy token cannot read ${domain}'s DNS records, so changes cannot be diffed: writing each record (idempotent).`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (existing) {\n\t\t\t\tconst values = existing.map((r) => normalize(r.data));\n\t\t\t\tif (values.length === 1 && values[0] === normalize(record.value)) {\n\t\t\t\t\tresults.push({ record, created: false, unchanged: true });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait api.replaceRecordSet(\n\t\t\t\tdomain,\n\t\t\t\ttype,\n\t\t\t\trecord.name,\n\t\t\t\t[record.value],\n\t\t\t\tMath.max(record.ttl, GODADDY_MIN_TTL),\n\t\t\t);\n\t\t\tresults.push({\n\t\t\t\trecord,\n\t\t\t\tcreated: existing !== undefined && existing.length === 0,\n\t\t\t\tunchanged: false,\n\t\t\t});\n\t\t}\n\t\treturn results;\n\t}\n\n\tasync deleteRecords(\n\t\tdomain: string,\n\t\trecords: DeleteDnsRecord[],\n\t): Promise<DeleteResult[]> {\n\t\tfor (const record of records) {\n\t\t\tthis.assertManaged(domain, record.type, record.name);\n\t\t}\n\t\tconst api = await this.getApi();\n\t\tconst results: DeleteResult[] = [];\n\t\tfor (const record of records) {\n\t\t\tconst type = record.type as GoDaddyRecordType;\n\t\t\tif (!this.writeOnly) {\n\t\t\t\tlet existing: GoDaddyRecord[] | undefined;\n\t\t\t\ttry {\n\t\t\t\t\texisting = await api.getRecordSet(domain, type, record.name);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!readDenied(error)) throw error;\n\t\t\t\t\tthis.writeOnly = true;\n\t\t\t\t}\n\t\t\t\tif (existing && existing.length === 0) {\n\t\t\t\t\tresults.push({ record, deleted: false, notFound: true });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait api.deleteRecordSet(domain, type, record.name);\n\t\t\t} catch (error) {\n\t\t\t\t// Write-only, nothing was read: a record that is not there is a 404.\n\t\t\t\tif (this.writeOnly && error instanceof GoDaddyDomainNotFound) {\n\t\t\t\t\tresults.push({ record, deleted: false, notFound: true });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tresults.push({ record, deleted: true, notFound: false });\n\t\t}\n\t\treturn results;\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"GoDaddyProvider-DWrDIXzQ.cjs","names":["GkmError","GkmError","storedCredentials","MissingCredential","DnsRecordsUnreadable"],"sources":["../src/target/dokploy/dns/godaddy-api.ts","../src/target/dokploy/dns/GoDaddyProvider.ts"],"sourcesContent":["/**\n * GoDaddy's v1 DNS API, as gkm uses it: one record set — a name and a type —\n * at a time.\n *\n * - read: `GET /v1/domains/{domain}/records/{type}/{name}`\n * - write: `PUT /v1/domains/{domain}/records/{type}/{name}` with `[{ data, ttl }]`,\n * which replaces that one name's records of that one type\n * - delete: `DELETE /v1/domains/{domain}/records/{type}/{name}`\n *\n * Never the zone-wide `PUT /v1/domains/{domain}/records`, which replaces every\n * record the domain has — mail, verification TXT records and all — and never\n * a domain or account endpoint (`GET /v1/domains`, `GET /v1/domains/{domain}`):\n * a token scoped to `domains.dns:update` alone is enough. A domain that is not\n * in the token's account is told apart by the records endpoint's own 404 or 422.\n *\n * Authenticated with a Personal Access Token — `Authorization: Bearer <token>`,\n * the API's one security scheme. GoDaddy allows about 60 requests a minute per\n * token; a 429 carries `retryAfterSec`, which is waited out a few times before\n * the run gives up with {@link GoDaddyRateLimited}. A 504 is retried the same\n * way. GoDaddy refuses a TTL under 600 seconds (a 422), so every write is\n * sent with at least that.\n */\n\nimport type { GoDaddyCredential } from '../../../deploy/credentials';\nimport { GkmError } from '../../../errors';\n\nexport const GODADDY_API_BASE = 'https://api.godaddy.com';\n\n/** GoDaddy refuses a TTL below this. */\nexport const GODADDY_MIN_TTL = 600;\n\n/** The record types gkm writes. Never MX, TXT, NS, SOA, SRV or CAA. */\nexport const GODADDY_MANAGED_TYPES = ['A', 'AAAA', 'CNAME'] as const;\n\nexport type GoDaddyRecordType = (typeof GODADDY_MANAGED_TYPES)[number];\n\n/** One record as GoDaddy returns it. */\nexport interface GoDaddyRecord {\n\ttype: string;\n\tname: string;\n\tdata: string;\n\tttl?: number;\n}\n\n/** GoDaddy's error body. */\ninterface GoDaddyErrorBody {\n\tcode?: string;\n\tmessage?: string;\n\tretryAfterSec?: number;\n}\n\n/**\n * The token is good, and GoDaddy will not let it use the API: since 2024 the\n * Domains and DNS APIs answer only accounts with 10 or more domains, or a\n * Discount Domain Club Premier membership.\n */\nexport class GoDaddyApiAccessDenied extends GkmError {\n\tconstructor(\n\t\treadonly domain: string,\n\t\treadonly detail?: string,\n\t) {\n\t\tsuper(\n\t\t\t`GoDaddy refused API access for ${domain} (403 ACCESS_DENIED${detail ? `: ${detail}` : ''}). ` +\n\t\t\t\t'GoDaddy only opens its DNS API to accounts with 10 or more domains, or ' +\n\t\t\t\t'with a Discount Domain Club Premier membership, so a valid token on a ' +\n\t\t\t\t'smaller account is refused. Either qualify the account, move the ' +\n\t\t\t\t\"domain's DNS hosting to Route53 (provider: 'route53') or Cloudflare \" +\n\t\t\t\t\"by changing its nameservers at GoDaddy, or set provider: 'manual' \" +\n\t\t\t\t'and create the records gkm prints yourself. (A scoped token without ' +\n\t\t\t\t'domains.dns:update is refused the same way — check its scopes too.)',\n\t\t);\n\t\tthis.name = 'GoDaddyApiAccessDenied';\n\t}\n}\n\n/** The token lacks the scope a records call needs. */\nexport class GoDaddyScopeMissing extends GkmError {\n\tconstructor(\n\t\treadonly method: string,\n\t\treadonly domain: string,\n\t\treadonly scope: string,\n\t\treadonly detail?: string,\n\t) {\n\t\tsuper(\n\t\t\t`GoDaddy refused ${method} on ${domain}'s DNS records (403${detail ? `: ${detail}` : ''}): ` +\n\t\t\t\t`the token lacks the ${scope} scope. Create a Personal Access Token ` +\n\t\t\t\t'in the GoDaddy developer dashboard with domains.dns:update — no ' +\n\t\t\t\t'domain or account scope is needed — and set GODADDY_API_TOKEN or ' +\n\t\t\t\t'run `gkm login --provider godaddy` again.',\n\t\t);\n\t\tthis.name = 'GoDaddyScopeMissing';\n\t}\n}\n\n/** GoDaddy did not accept the token at all. */\nexport class GoDaddyCredentialsInvalid extends GkmError {\n\tconstructor(readonly code?: string) {\n\t\tsuper(\n\t\t\t`GoDaddy did not accept the API token (401${code ? ` ${code}` : ''}). ` +\n\t\t\t\t'Check GODADDY_API_TOKEN, or run `gkm login --provider godaddy` ' +\n\t\t\t\t'again with a Personal Access Token from the GoDaddy developer ' +\n\t\t\t\t'dashboard that has not expired or been revoked.',\n\t\t);\n\t\tthis.name = 'GoDaddyCredentialsInvalid';\n\t}\n}\n\n/** The domain is not in the account the token belongs to. */\nexport class GoDaddyDomainNotFound extends GkmError {\n\tconstructor(\n\t\treadonly domain: string,\n\t\treadonly code?: string,\n\t) {\n\t\tsuper(\n\t\t\t`GoDaddy has no domain ${domain} in this token's account${code ? ` (${code})` : ''}. ` +\n\t\t\t\t'Check the root domain in dns, and that the token belongs to the account the domain is registered in.',\n\t\t);\n\t\tthis.name = 'GoDaddyDomainNotFound';\n\t}\n}\n\n/** Still rate limited after waiting it out. */\nexport class GoDaddyRateLimited extends GkmError {\n\tconstructor(\n\t\treadonly attempts: number,\n\t\treadonly retryAfterSec?: number,\n\t) {\n\t\tsuper(\n\t\t\t`GoDaddy is still rate limiting this token after ${attempts} attempts ` +\n\t\t\t\t'(429 TOO_MANY_REQUESTS — about 60 requests a minute are allowed). ' +\n\t\t\t\t`Wait${retryAfterSec ? ` ${retryAfterSec} seconds` : ' a minute'} and run it again; ` +\n\t\t\t\t'records already written are left as they are.',\n\t\t);\n\t\tthis.name = 'GoDaddyRateLimited';\n\t}\n}\n\n/** Any other failure from GoDaddy. */\nexport class GoDaddyRequestFailed extends Error {\n\tconstructor(\n\t\treadonly method: string,\n\t\treadonly path: string,\n\t\treadonly status: number,\n\t\treadonly code?: string,\n\t\treadonly detail?: string,\n\t) {\n\t\tsuper(\n\t\t\t`GoDaddy answered ${method} ${path} with ${status}${code ? ` ${code}` : ''}` +\n\t\t\t\t`${detail ? `: ${detail}` : ''}.` +\n\t\t\t\t(status === 422\n\t\t\t\t\t? ' A name with a CNAME cannot also have an A or AAAA record, and the reverse — remove the other one first.'\n\t\t\t\t\t: ''),\n\t\t);\n\t\tthis.name = 'GoDaddyRequestFailed';\n\t}\n}\n\n/**\n * A write gkm was about to make to a record type it never manages, or to a\n * name it was not asked for.\n */\nexport class GoDaddyRecordNotAllowed extends GkmError {\n\tconstructor(\n\t\treadonly domain: string,\n\t\treadonly type: string,\n\t\treadonly recordName: string,\n\t\treadonly reason: string,\n\t) {\n\t\tsuper(\n\t\t\t`Refused to change the ${type} record '${recordName}' on ${domain}: ${reason}. ` +\n\t\t\t\t'gkm only ever writes the A, AAAA and CNAME records of the hosts it serves.',\n\t\t);\n\t\tthis.name = 'GoDaddyRecordNotAllowed';\n\t}\n}\n\nexport interface GoDaddyApiOptions {\n\tcredential: GoDaddyCredential;\n\t/** The API's base URL. GoDaddy's production API by default. */\n\tbaseUrl?: string;\n\t/** How a 429 or 504 is waited out — `setTimeout` by default; tests pass their own. */\n\tsleep?: (ms: number) => Promise<void>;\n\t/** How many times one request is sent before a 429 or 504 is final. Default 4. */\n\tmaxAttempts?: number;\n}\n\n/** A record name GoDaddy's path takes: `@` for the apex, else relative. */\nfunction isRecordName(name: string): boolean {\n\treturn (\n\t\tname === '@' ||\n\t\t/^(\\*\\.)?[a-z0-9_](?:[a-z0-9_-]{0,61}[a-z0-9])?(\\.[a-z0-9_](?:[a-z0-9_-]{0,61}[a-z0-9])?)*$/i.test(\n\t\t\tname,\n\t\t)\n\t);\n}\n\n/** The client. Every method touches one record set, by type and name. */\nexport class GoDaddyApi {\n\tprivate readonly baseUrl: string;\n\tprivate readonly sleep: (ms: number) => Promise<void>;\n\tprivate readonly maxAttempts: number;\n\tprivate readonly authorization: string;\n\t/** Whether a read has succeeded: a later 403 is then the token's scope. */\n\tprivate readSucceeded = false;\n\n\tconstructor(options: GoDaddyApiOptions) {\n\t\tthis.baseUrl = (options.baseUrl ?? GODADDY_API_BASE).replace(/\\/$/, '');\n\t\tthis.sleep =\n\t\t\toptions.sleep ??\n\t\t\t((ms) => new Promise((resolve) => setTimeout(resolve, ms)));\n\t\tthis.maxAttempts = options.maxAttempts ?? 4;\n\t\tthis.authorization = `Bearer ${options.credential.token}`;\n\t}\n\n\t/** The records of one name and type — empty when there are none. */\n\tasync getRecordSet(\n\t\tdomain: string,\n\t\ttype: GoDaddyRecordType,\n\t\tname: string,\n\t): Promise<GoDaddyRecord[]> {\n\t\tthis.guard(domain, type, name);\n\t\tconst records = await this.request<GoDaddyRecord[]>(\n\t\t\t'GET',\n\t\t\tdomain,\n\t\t\tthis.recordPath(domain, type, name),\n\t\t);\n\t\treturn Array.isArray(records) ? records : [];\n\t}\n\n\t/** Replace one name's records of one type with `values`. */\n\tasync replaceRecordSet(\n\t\tdomain: string,\n\t\ttype: GoDaddyRecordType,\n\t\tname: string,\n\t\tvalues: readonly string[],\n\t\tttl: number,\n\t): Promise<void> {\n\t\tthis.guard(domain, type, name);\n\t\tawait this.request(\n\t\t\t'PUT',\n\t\t\tdomain,\n\t\t\tthis.recordPath(domain, type, name),\n\t\t\tvalues.map((data) => ({\n\t\t\t\tdata,\n\t\t\t\tttl: Math.max(ttl, GODADDY_MIN_TTL),\n\t\t\t})),\n\t\t);\n\t}\n\n\t/** Delete one name's records of one type. */\n\tasync deleteRecordSet(\n\t\tdomain: string,\n\t\ttype: GoDaddyRecordType,\n\t\tname: string,\n\t): Promise<void> {\n\t\tthis.guard(domain, type, name);\n\t\tawait this.request('DELETE', domain, this.recordPath(domain, type, name));\n\t}\n\n\tprivate recordPath(domain: string, type: string, name: string): string {\n\t\treturn `/v1/domains/${encodeURIComponent(domain)}/records/${type}/${encodeURIComponent(name)}`;\n\t}\n\n\t/** Only A, AAAA and CNAME, at a real record name. */\n\tprivate guard(domain: string, type: string, name: string): void {\n\t\tif (!(GODADDY_MANAGED_TYPES as readonly string[]).includes(type)) {\n\t\t\tthrow new GoDaddyRecordNotAllowed(\n\t\t\t\tdomain,\n\t\t\t\ttype,\n\t\t\t\tname,\n\t\t\t\t'it is not a type gkm manages',\n\t\t\t);\n\t\t}\n\t\tif (!isRecordName(name)) {\n\t\t\tthrow new GoDaddyRecordNotAllowed(\n\t\t\t\tdomain,\n\t\t\t\ttype,\n\t\t\t\tname,\n\t\t\t\t'it is not a record name relative to the domain',\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async request<T = unknown>(\n\t\tmethod: 'GET' | 'PUT' | 'DELETE',\n\t\tdomain: string,\n\t\tpath: string,\n\t\tbody?: unknown,\n\t): Promise<T> {\n\t\tlet retryAfterSec: number | undefined;\n\t\tfor (let attempt = 1; attempt <= this.maxAttempts; attempt++) {\n\t\t\tconst response = await fetch(`${this.baseUrl}${path}`, {\n\t\t\t\tmethod,\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: this.authorization,\n\t\t\t\t\tAccept: 'application/json',\n\t\t\t\t\t...(body !== undefined ? { 'Content-Type': 'application/json' } : {}),\n\t\t\t\t},\n\t\t\t\t...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n\t\t\t});\n\n\t\t\tif (response.ok) {\n\t\t\t\tif (method === 'GET') this.readSucceeded = true;\n\t\t\t\tif (response.status === 204) return undefined as T;\n\t\t\t\tconst text = await response.text();\n\t\t\t\treturn (text ? JSON.parse(text) : undefined) as T;\n\t\t\t}\n\n\t\t\tconst error = await errorBody(response);\n\t\t\tif (response.status === 504 && attempt < this.maxAttempts) {\n\t\t\t\tawait this.sleep(Math.min(2 ** attempt * 1000, 30_000));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (response.status === 429) {\n\t\t\t\tretryAfterSec = error.retryAfterSec;\n\t\t\t\tif (attempt === this.maxAttempts) break;\n\t\t\t\t// GoDaddy says how long; without it, back off exponentially.\n\t\t\t\tconst waitMs =\n\t\t\t\t\tretryAfterSec !== undefined\n\t\t\t\t\t\t? Math.min(retryAfterSec, 60) * 1000\n\t\t\t\t\t\t: Math.min(2 ** attempt * 1000, 60_000);\n\t\t\t\tawait this.sleep(waitMs);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (response.status === 401) {\n\t\t\t\tthrow new GoDaddyCredentialsInvalid(error.code);\n\t\t\t}\n\t\t\tif (response.status === 403) {\n\t\t\t\t// The account restriction says ACCESS_DENIED; a scoped token that\n\t\t\t\t// may not make this call says so, or — after a read went\n\t\t\t\t// through — can only be that.\n\t\t\t\tconst scoped =\n\t\t\t\t\t/scope/i.test(`${error.code ?? ''} ${error.message ?? ''}`) ||\n\t\t\t\t\t(method !== 'GET' && this.readSucceeded);\n\t\t\t\tif (scoped) {\n\t\t\t\t\tthrow new GoDaddyScopeMissing(\n\t\t\t\t\t\tmethod,\n\t\t\t\t\t\tdomain,\n\t\t\t\t\t\tmethod === 'GET' ? 'DNS records read' : 'domains.dns:update',\n\t\t\t\t\t\terror.message ?? error.code,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthrow new GoDaddyApiAccessDenied(domain, error.message ?? error.code);\n\t\t\t}\n\t\t\tif (response.status === 404) {\n\t\t\t\tthrow new GoDaddyDomainNotFound(domain, error.code);\n\t\t\t}\n\t\t\tif (\n\t\t\t\tresponse.status === 422 &&\n\t\t\t\t/domain/i.test(error.code ?? '') &&\n\t\t\t\t!/record/i.test(`${error.code ?? ''} ${error.message ?? ''}`)\n\t\t\t) {\n\t\t\t\tthrow new GoDaddyDomainNotFound(domain, error.code);\n\t\t\t}\n\t\t\tthrow new GoDaddyRequestFailed(\n\t\t\t\tmethod,\n\t\t\t\tpath,\n\t\t\t\tresponse.status,\n\t\t\t\terror.code,\n\t\t\t\terror.message,\n\t\t\t);\n\t\t}\n\t\tthrow new GoDaddyRateLimited(this.maxAttempts, retryAfterSec);\n\t}\n}\n\nasync function errorBody(response: Response): Promise<GoDaddyErrorBody> {\n\ttry {\n\t\tconst parsed = (await response.json()) as GoDaddyErrorBody;\n\t\treturn parsed && typeof parsed === 'object' ? parsed : {};\n\t} catch {\n\t\treturn {};\n\t}\n}\n","/**\n * GoDaddy DNS Provider\n *\n * Implements DnsProvider against GoDaddy's v1 API, one record set — a name\n * and a type — at a time: it reads and writes only the A, AAAA and CNAME\n * records of the names it is handed, and never the zone as a whole, a domain\n * or the account. A Personal Access Token scoped to `domains.dns:update` is all it needs.\n *\n * A token that may write records and not read them puts the provider in\n * write-only mode: every record is PUT — idempotent, so one that already has\n * its value is left as it was — and nothing is compared or deleted.\n *\n * Credentials: `GODADDY_API_TOKEN`, else what `gkm login --provider godaddy`\n * stored. Never logged.\n */\n\nimport {\n\ttype GoDaddyCredential,\n\tMissingCredential,\n\tstoredCredentials,\n} from '../../../deploy/credentials';\nimport { GkmError } from '../../../errors';\nimport {\n\ttype DeleteDnsRecord,\n\ttype DeleteResult,\n\ttype DnsProvider,\n\ttype DnsRecord,\n\tDnsRecordsUnreadable,\n\ttype UpsertDnsRecord,\n\ttype UpsertResult,\n} from './DnsProvider';\nimport {\n\tGODADDY_MANAGED_TYPES,\n\tGODADDY_MIN_TTL,\n\tGoDaddyApi,\n\tGoDaddyApiAccessDenied,\n\ttype GoDaddyApiOptions,\n\tGoDaddyDomainNotFound,\n\ttype GoDaddyRecord,\n\tGoDaddyRecordNotAllowed,\n\ttype GoDaddyRecordType,\n\tGoDaddyScopeMissing,\n} from './godaddy-api';\n\nexport interface GoDaddyProviderOptions {\n\t/** The token, when the caller already has it. */\n\tcredential?: GoDaddyCredential;\n\t/** Where the variables are read — `process.env` by default. */\n\tenv?: NodeJS.ProcessEnv;\n\t/** The CLI's home, whose `credentials.json` holds a stored login. */\n\thome?: string;\n\t/** The API's base URL, for tests. */\n\tbaseUrl?: string;\n\t/** How a 429 is waited out, for tests. */\n\tsleep?: GoDaddyApiOptions['sleep'];\n\tmaxAttempts?: number;\n\t/** Where the write-only notice goes — `console.log` by default. */\n\tlog?: (line: string) => void;\n}\n\n/** GoDaddy cannot list a zone through the records-by-name endpoints. */\nexport class GoDaddyZoneListingUnsupported extends GkmError {\n\tconstructor(readonly domain: string) {\n\t\tsuper(\n\t\t\t`gkm reads GoDaddy records by name and type only — it never lists ` +\n\t\t\t\t`${domain}'s whole zone, so a token scoped to DNS updates is enough. ` +\n\t\t\t\t'Use readRecords(domain, [{ name, type }]) instead of getRecords.',\n\t\t);\n\t\tthis.name = 'GoDaddyZoneListingUnsupported';\n\t}\n}\n\n/** A value compared the way DNS does: case-insensitive, no trailing dot. */\nfunction normalize(value: string): string {\n\treturn value.trim().replace(/\\.$/, '').toLowerCase();\n}\n\nfunction managed(type: string): type is GoDaddyRecordType {\n\treturn (GODADDY_MANAGED_TYPES as readonly string[]).includes(type);\n}\n\n/** A read GoDaddy refused: write-only, rather than a failure. */\nfunction readDenied(error: unknown): boolean {\n\treturn (\n\t\terror instanceof GoDaddyScopeMissing ||\n\t\terror instanceof GoDaddyApiAccessDenied\n\t);\n}\n\nexport class GoDaddyProvider implements DnsProvider {\n\treadonly name = 'godaddy';\n\tprivate api: GoDaddyApi | null = null;\n\t/** Set once a read is refused: every write is then a blind PUT. */\n\tprivate writeOnly = false;\n\n\tconstructor(private readonly options: GoDaddyProviderOptions = {}) {}\n\n\t/** Whether the token turned out unable to read records. */\n\tget readsDenied(): boolean {\n\t\treturn this.writeOnly;\n\t}\n\n\tprivate async getApi(): Promise<GoDaddyApi> {\n\t\tif (this.api) return this.api;\n\t\tconst credential =\n\t\t\tthis.options.credential ??\n\t\t\t(await storedCredentials({\n\t\t\t\tenv: this.options.env ?? process.env,\n\t\t\t\t...(this.options.home ? { home: this.options.home } : {}),\n\t\t\t}).get({ kind: 'godaddy' }));\n\t\tif (!credential) throw new MissingCredential('godaddy', undefined);\n\t\tthis.api = new GoDaddyApi({\n\t\t\tcredential,\n\t\t\t...(this.options.baseUrl ? { baseUrl: this.options.baseUrl } : {}),\n\t\t\t...(this.options.sleep ? { sleep: this.options.sleep } : {}),\n\t\t\t...(this.options.maxAttempts\n\t\t\t\t? { maxAttempts: this.options.maxAttempts }\n\t\t\t\t: {}),\n\t\t});\n\t\treturn this.api;\n\t}\n\n\tprivate assertManaged(domain: string, type: string, name: string): void {\n\t\tif (!managed(type)) {\n\t\t\tthrow new GoDaddyRecordNotAllowed(\n\t\t\t\tdomain,\n\t\t\t\ttype,\n\t\t\t\tname,\n\t\t\t\t'it is not a type gkm manages',\n\t\t\t);\n\t\t}\n\t}\n\n\t/** Never: the whole zone is not read. See {@link GoDaddyZoneListingUnsupported}. */\n\tasync getRecords(domain: string): Promise<DnsRecord[]> {\n\t\tthrow new GoDaddyZoneListingUnsupported(domain);\n\t}\n\n\t/**\n\t * The records of exactly these names and types, one request each.\n\t *\n\t * @throws {DnsRecordsUnreadable} when the token may not read records\n\t */\n\tasync readRecords(\n\t\tdomain: string,\n\t\twanted: readonly DeleteDnsRecord[],\n\t): Promise<DnsRecord[]> {\n\t\tfor (const { name, type } of wanted) this.assertManaged(domain, type, name);\n\t\tconst api = await this.getApi();\n\t\tconst found: DnsRecord[] = [];\n\t\tfor (const { name, type } of wanted) {\n\t\t\tlet records: GoDaddyRecord[];\n\t\t\ttry {\n\t\t\t\trecords = await api.getRecordSet(\n\t\t\t\t\tdomain,\n\t\t\t\t\ttype as GoDaddyRecordType,\n\t\t\t\t\tname,\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tif (!readDenied(error)) throw error;\n\t\t\t\tthis.writeOnly = true;\n\t\t\t\tthrow new DnsRecordsUnreadable(\n\t\t\t\t\tthis.name,\n\t\t\t\t\tdomain,\n\t\t\t\t\t(error as Error).name,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (records.length === 0) continue;\n\t\t\tfound.push({\n\t\t\t\tname,\n\t\t\t\ttype,\n\t\t\t\tttl: records[0]!.ttl ?? GODADDY_MIN_TTL,\n\t\t\t\tvalues: records.map((r) => r.data),\n\t\t\t});\n\t\t}\n\t\treturn found;\n\t}\n\n\t/**\n\t * Each record set to exactly its one value: read it, and write it only\n\t * when it differs — or, with a token that cannot read, write it. Only the\n\t * name and type of each record handed in is touched.\n\t */\n\tasync upsertRecords(\n\t\tdomain: string,\n\t\trecords: UpsertDnsRecord[],\n\t): Promise<UpsertResult[]> {\n\t\t// Every record is checked before any is written, so a refused one\n\t\t// leaves the zone as it was.\n\t\tfor (const record of records) {\n\t\t\tthis.assertManaged(domain, record.type, record.name);\n\t\t}\n\t\tconst api = await this.getApi();\n\n\t\tconst results: UpsertResult[] = [];\n\t\tfor (const record of records) {\n\t\t\tconst type = record.type as GoDaddyRecordType;\n\t\t\tlet existing: GoDaddyRecord[] | undefined;\n\t\t\tif (!this.writeOnly) {\n\t\t\t\ttry {\n\t\t\t\t\texisting = await api.getRecordSet(domain, type, record.name);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!readDenied(error)) throw error;\n\t\t\t\t\tthis.writeOnly = true;\n\t\t\t\t\t(this.options.log ?? console.log)(\n\t\t\t\t\t\t` ℹ The GoDaddy token cannot read ${domain}'s DNS records, so changes cannot be diffed: writing each record (idempotent).`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (existing) {\n\t\t\t\tconst values = existing.map((r) => normalize(r.data));\n\t\t\t\tif (values.length === 1 && values[0] === normalize(record.value)) {\n\t\t\t\t\tresults.push({ record, created: false, unchanged: true });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait api.replaceRecordSet(\n\t\t\t\tdomain,\n\t\t\t\ttype,\n\t\t\t\trecord.name,\n\t\t\t\t[record.value],\n\t\t\t\tMath.max(record.ttl, GODADDY_MIN_TTL),\n\t\t\t);\n\t\t\tresults.push({\n\t\t\t\trecord,\n\t\t\t\tcreated: existing !== undefined && existing.length === 0,\n\t\t\t\tunchanged: false,\n\t\t\t});\n\t\t}\n\t\treturn results;\n\t}\n\n\tasync deleteRecords(\n\t\tdomain: string,\n\t\trecords: DeleteDnsRecord[],\n\t): Promise<DeleteResult[]> {\n\t\tfor (const record of records) {\n\t\t\tthis.assertManaged(domain, record.type, record.name);\n\t\t}\n\t\tconst api = await this.getApi();\n\t\tconst results: DeleteResult[] = [];\n\t\tfor (const record of records) {\n\t\t\tconst type = record.type as GoDaddyRecordType;\n\t\t\tif (!this.writeOnly) {\n\t\t\t\tlet existing: GoDaddyRecord[] | undefined;\n\t\t\t\ttry {\n\t\t\t\t\texisting = await api.getRecordSet(domain, type, record.name);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!readDenied(error)) throw error;\n\t\t\t\t\tthis.writeOnly = true;\n\t\t\t\t}\n\t\t\t\tif (existing && existing.length === 0) {\n\t\t\t\t\tresults.push({ record, deleted: false, notFound: true });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait api.deleteRecordSet(domain, type, record.name);\n\t\t\t} catch (error) {\n\t\t\t\t// Write-only, nothing was read: a record that is not there is a 404.\n\t\t\t\tif (this.writeOnly && error instanceof GoDaddyDomainNotFound) {\n\t\t\t\t\tresults.push({ record, deleted: false, notFound: true });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tresults.push({ record, deleted: true, notFound: false });\n\t\t}\n\t\treturn results;\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { s as currentActor } from "./seeds-
|
|
2
|
-
import { T as upgradeV2State, _ as appendHistory, d as StageStateMissing, g as StateVersionConflict, h as StateStoreWithoutLocking, w as newLockHolder, x as contentVersion } from "./sniffer-
|
|
1
|
+
import { s as currentActor } from "./seeds-CIk0l4SC.mjs";
|
|
2
|
+
import { T as upgradeV2State, _ as appendHistory, d as StageStateMissing, g as StateVersionConflict, h as StateStoreWithoutLocking, w as newLockHolder, x as contentVersion } from "./sniffer-CABMO-Bh.mjs";
|
|
3
3
|
//#region src/deploy/LegacyStateStore.ts
|
|
4
4
|
/**
|
|
5
5
|
* A custom `StateProvider` as a `StateStore`.
|
|
@@ -121,4 +121,4 @@ function versionOf(state) {
|
|
|
121
121
|
//#endregion
|
|
122
122
|
export { LegacyStateStore };
|
|
123
123
|
|
|
124
|
-
//# sourceMappingURL=LegacyStateStore-
|
|
124
|
+
//# sourceMappingURL=LegacyStateStore-BdXoAlYY.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LegacyStateStore-
|
|
1
|
+
{"version":3,"file":"LegacyStateStore-BdXoAlYY.mjs","names":[],"sources":["../src/deploy/LegacyStateStore.ts"],"sourcesContent":["/**\n * A custom `StateProvider` as a `StateStore`.\n *\n * A provider only reads and writes whole states, so this adapter can check a\n * version before it writes but cannot make the check and the write one step,\n * and cannot lock. It warns once (`StateStoreWithoutLocking`) the first time\n * a caller relies on either, and otherwise behaves as a store. Resource\n * records travel inside the state the provider stores, under `resources`.\n */\n\nimport { currentActor } from './actor';\nimport type { StateProvider } from './StateProvider';\nimport {\n\tappendHistory,\n\tcontentVersion,\n\ttype HistoryEntry,\n\ttype LockHolder,\n\ttype LockOptions,\n\tnewLockHolder,\n\ttype ResourceInput,\n\ttype ResourceRecord,\n\ttype ResourceWriteOptions,\n\tStageStateMissing,\n\ttype StateLock,\n\ttype StateStore,\n\tStateStoreWithoutLocking,\n\ttype StateVersion,\n\tStateVersionConflict,\n\ttype StoredStageState,\n\tupgradeV2State,\n\ttype WriteOptions,\n} from './StateStore';\nimport type { StageState } from './state';\n\ntype ProviderState = StageState & {\n\tresources?: Record<string, ResourceRecord>;\n\thistory?: HistoryEntry[];\n};\n\nexport interface LegacyStateStoreOptions {\n\t/** Where the warning goes; `process.emitWarning` by default. */\n\twarn?: (warning: StateStoreWithoutLocking) => void;\n}\n\nexport class LegacyStateStore implements StateStore {\n\tprivate warned = false;\n\t/** The operation of the lock each stage is held for. */\n\tprivate readonly held = new Map<string, LockHolder>();\n\tprivate readonly logged = new Map<string, string>();\n\tprivate readonly warn: (warning: StateStoreWithoutLocking) => void;\n\n\tconstructor(\n\t\treadonly provider: StateProvider,\n\t\toptions: LegacyStateStoreOptions = {},\n\t) {\n\t\tthis.warn = options.warn ?? ((warning) => process.emitWarning(warning));\n\t}\n\n\tasync lock(stage: string, options?: LockOptions): Promise<StateLock> {\n\t\tthis.warnOnce();\n\t\tconst holder = newLockHolder(options);\n\t\tthis.held.set(stage, holder);\n\t\treturn {\n\t\t\tstage,\n\t\t\tholder,\n\t\t\trelease: async () => {\n\t\t\t\tif (this.held.get(stage)?.id === holder.id) this.held.delete(stage);\n\t\t\t},\n\t\t};\n\t}\n\n\tasync forceUnlock(_stage: string): Promise<LockHolder | null> {\n\t\treturn null;\n\t}\n\n\tasync read(stage: string): Promise<StoredStageState | null> {\n\t\tconst stored = (await this.provider.read(stage)) as ProviderState | null;\n\t\tif (!stored) return null;\n\t\tconst {\n\t\t\tresources: storedResources = {},\n\t\t\thistory = [],\n\t\t\t...storedState\n\t\t} = stored;\n\t\tconst { state, resources } =\n\t\t\tstoredState.provider === 'dokploy'\n\t\t\t\t? upgradeV2State(storedState, storedResources)\n\t\t\t\t: { state: storedState as StageState, resources: storedResources };\n\t\treturn { state, resources, history, version: versionOf(stored) };\n\t}\n\n\tasync write(\n\t\tstage: string,\n\t\tstate: StageState,\n\t\toptions: WriteOptions,\n\t): Promise<StateVersion> {\n\t\tconst current = await this.read(stage);\n\t\tthis.check(stage, options.expectedVersion, current);\n\t\treturn this.put(stage, current, {\n\t\t\t...state,\n\t\t\tresources: current?.resources ?? {},\n\t\t});\n\t}\n\n\tasync putResource(\n\t\tstage: string,\n\t\trecord: ResourceInput,\n\t\toptions?: ResourceWriteOptions,\n\t): Promise<StateVersion> {\n\t\tconst current = await this.current(stage, options);\n\t\treturn this.put(stage, current, {\n\t\t\t...current.state,\n\t\t\tresources: {\n\t\t\t\t...current.resources,\n\t\t\t\t[record.key]: {\n\t\t\t\t\t...record,\n\t\t\t\t\tupdatedAt: new Date().toISOString(),\n\t\t\t\t\tupdatedBy: currentActor(),\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\t}\n\n\tasync deleteResource(\n\t\tstage: string,\n\t\tkey: string,\n\t\toptions?: ResourceWriteOptions,\n\t): Promise<StateVersion> {\n\t\tconst current = await this.current(stage, options);\n\t\tconst { [key]: _removed, ...resources } = current.resources;\n\t\treturn this.put(stage, current, { ...current.state, resources });\n\t}\n\n\tprivate async current(\n\t\tstage: string,\n\t\toptions?: ResourceWriteOptions,\n\t): Promise<StoredStageState> {\n\t\tconst current = await this.read(stage);\n\t\tif (options?.expectedVersion !== undefined) {\n\t\t\tthis.check(stage, options.expectedVersion, current);\n\t\t}\n\t\tif (!current) throw new StageStateMissing(stage);\n\t\treturn current;\n\t}\n\n\tprivate check(\n\t\tstage: string,\n\t\texpected: StateVersion | null,\n\t\tcurrent: StoredStageState | null,\n\t): void {\n\t\tconst actual = current?.version ?? null;\n\t\tif (actual !== expected) {\n\t\t\tthrow new StateVersionConflict(stage, expected, actual);\n\t\t}\n\t}\n\n\tprivate async put(\n\t\tstage: string,\n\t\tcurrent: StoredStageState | null,\n\t\tstate: ProviderState,\n\t): Promise<StateVersion> {\n\t\tthis.warnOnce();\n\t\tconst holder = this.held.get(stage);\n\t\tconst operation = holder?.operation ?? 'write';\n\t\tconst history = current?.history ?? [];\n\t\tconst sameRun =\n\t\t\tholder !== undefined &&\n\t\t\tthis.logged.get(stage) === holder.id &&\n\t\t\thistory[0]?.operation === operation;\n\t\tif (holder) this.logged.set(stage, holder.id);\n\t\tconst serial = (history[0]?.serial ?? 0) + 1;\n\t\tstate.history = appendHistory(\n\t\t\thistory,\n\t\t\t{ serial, at: new Date().toISOString(), by: currentActor(), operation },\n\t\t\tsameRun,\n\t\t);\n\t\t// Providers stamp `lastDeployedAt` on the object they are given, so the\n\t\t// version is taken after the write, from what was actually stored.\n\t\tawait this.provider.write(stage, state);\n\t\treturn versionOf(state);\n\t}\n\n\tprivate warnOnce(): void {\n\t\tif (this.warned) return;\n\t\tthis.warned = true;\n\t\tthis.warn(\n\t\t\tnew StateStoreWithoutLocking(\n\t\t\t\tthis.provider.constructor?.name || 'anonymous',\n\t\t\t),\n\t\t);\n\t}\n}\n\n/** Key order is the provider's, so this is stable for a given stored state. */\nfunction versionOf(state: ProviderState): StateVersion {\n\treturn contentVersion(JSON.stringify(state));\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const require_seeds = require("./seeds-
|
|
2
|
-
const require_sniffer = require("./sniffer-
|
|
1
|
+
const require_seeds = require("./seeds-Dk8YkLkM.cjs");
|
|
2
|
+
const require_sniffer = require("./sniffer-2aK7cB2u.cjs");
|
|
3
3
|
//#region src/deploy/LegacyStateStore.ts
|
|
4
4
|
/**
|
|
5
5
|
* A custom `StateProvider` as a `StateStore`.
|
|
@@ -121,4 +121,4 @@ function versionOf(state) {
|
|
|
121
121
|
//#endregion
|
|
122
122
|
exports.LegacyStateStore = LegacyStateStore;
|
|
123
123
|
|
|
124
|
-
//# sourceMappingURL=LegacyStateStore-
|
|
124
|
+
//# sourceMappingURL=LegacyStateStore-fsyPGBWu.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LegacyStateStore-
|
|
1
|
+
{"version":3,"file":"LegacyStateStore-fsyPGBWu.cjs","names":["newLockHolder","upgradeV2State","currentActor","StageStateMissing","StateVersionConflict","appendHistory","StateStoreWithoutLocking","contentVersion"],"sources":["../src/deploy/LegacyStateStore.ts"],"sourcesContent":["/**\n * A custom `StateProvider` as a `StateStore`.\n *\n * A provider only reads and writes whole states, so this adapter can check a\n * version before it writes but cannot make the check and the write one step,\n * and cannot lock. It warns once (`StateStoreWithoutLocking`) the first time\n * a caller relies on either, and otherwise behaves as a store. Resource\n * records travel inside the state the provider stores, under `resources`.\n */\n\nimport { currentActor } from './actor';\nimport type { StateProvider } from './StateProvider';\nimport {\n\tappendHistory,\n\tcontentVersion,\n\ttype HistoryEntry,\n\ttype LockHolder,\n\ttype LockOptions,\n\tnewLockHolder,\n\ttype ResourceInput,\n\ttype ResourceRecord,\n\ttype ResourceWriteOptions,\n\tStageStateMissing,\n\ttype StateLock,\n\ttype StateStore,\n\tStateStoreWithoutLocking,\n\ttype StateVersion,\n\tStateVersionConflict,\n\ttype StoredStageState,\n\tupgradeV2State,\n\ttype WriteOptions,\n} from './StateStore';\nimport type { StageState } from './state';\n\ntype ProviderState = StageState & {\n\tresources?: Record<string, ResourceRecord>;\n\thistory?: HistoryEntry[];\n};\n\nexport interface LegacyStateStoreOptions {\n\t/** Where the warning goes; `process.emitWarning` by default. */\n\twarn?: (warning: StateStoreWithoutLocking) => void;\n}\n\nexport class LegacyStateStore implements StateStore {\n\tprivate warned = false;\n\t/** The operation of the lock each stage is held for. */\n\tprivate readonly held = new Map<string, LockHolder>();\n\tprivate readonly logged = new Map<string, string>();\n\tprivate readonly warn: (warning: StateStoreWithoutLocking) => void;\n\n\tconstructor(\n\t\treadonly provider: StateProvider,\n\t\toptions: LegacyStateStoreOptions = {},\n\t) {\n\t\tthis.warn = options.warn ?? ((warning) => process.emitWarning(warning));\n\t}\n\n\tasync lock(stage: string, options?: LockOptions): Promise<StateLock> {\n\t\tthis.warnOnce();\n\t\tconst holder = newLockHolder(options);\n\t\tthis.held.set(stage, holder);\n\t\treturn {\n\t\t\tstage,\n\t\t\tholder,\n\t\t\trelease: async () => {\n\t\t\t\tif (this.held.get(stage)?.id === holder.id) this.held.delete(stage);\n\t\t\t},\n\t\t};\n\t}\n\n\tasync forceUnlock(_stage: string): Promise<LockHolder | null> {\n\t\treturn null;\n\t}\n\n\tasync read(stage: string): Promise<StoredStageState | null> {\n\t\tconst stored = (await this.provider.read(stage)) as ProviderState | null;\n\t\tif (!stored) return null;\n\t\tconst {\n\t\t\tresources: storedResources = {},\n\t\t\thistory = [],\n\t\t\t...storedState\n\t\t} = stored;\n\t\tconst { state, resources } =\n\t\t\tstoredState.provider === 'dokploy'\n\t\t\t\t? upgradeV2State(storedState, storedResources)\n\t\t\t\t: { state: storedState as StageState, resources: storedResources };\n\t\treturn { state, resources, history, version: versionOf(stored) };\n\t}\n\n\tasync write(\n\t\tstage: string,\n\t\tstate: StageState,\n\t\toptions: WriteOptions,\n\t): Promise<StateVersion> {\n\t\tconst current = await this.read(stage);\n\t\tthis.check(stage, options.expectedVersion, current);\n\t\treturn this.put(stage, current, {\n\t\t\t...state,\n\t\t\tresources: current?.resources ?? {},\n\t\t});\n\t}\n\n\tasync putResource(\n\t\tstage: string,\n\t\trecord: ResourceInput,\n\t\toptions?: ResourceWriteOptions,\n\t): Promise<StateVersion> {\n\t\tconst current = await this.current(stage, options);\n\t\treturn this.put(stage, current, {\n\t\t\t...current.state,\n\t\t\tresources: {\n\t\t\t\t...current.resources,\n\t\t\t\t[record.key]: {\n\t\t\t\t\t...record,\n\t\t\t\t\tupdatedAt: new Date().toISOString(),\n\t\t\t\t\tupdatedBy: currentActor(),\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\t}\n\n\tasync deleteResource(\n\t\tstage: string,\n\t\tkey: string,\n\t\toptions?: ResourceWriteOptions,\n\t): Promise<StateVersion> {\n\t\tconst current = await this.current(stage, options);\n\t\tconst { [key]: _removed, ...resources } = current.resources;\n\t\treturn this.put(stage, current, { ...current.state, resources });\n\t}\n\n\tprivate async current(\n\t\tstage: string,\n\t\toptions?: ResourceWriteOptions,\n\t): Promise<StoredStageState> {\n\t\tconst current = await this.read(stage);\n\t\tif (options?.expectedVersion !== undefined) {\n\t\t\tthis.check(stage, options.expectedVersion, current);\n\t\t}\n\t\tif (!current) throw new StageStateMissing(stage);\n\t\treturn current;\n\t}\n\n\tprivate check(\n\t\tstage: string,\n\t\texpected: StateVersion | null,\n\t\tcurrent: StoredStageState | null,\n\t): void {\n\t\tconst actual = current?.version ?? null;\n\t\tif (actual !== expected) {\n\t\t\tthrow new StateVersionConflict(stage, expected, actual);\n\t\t}\n\t}\n\n\tprivate async put(\n\t\tstage: string,\n\t\tcurrent: StoredStageState | null,\n\t\tstate: ProviderState,\n\t): Promise<StateVersion> {\n\t\tthis.warnOnce();\n\t\tconst holder = this.held.get(stage);\n\t\tconst operation = holder?.operation ?? 'write';\n\t\tconst history = current?.history ?? [];\n\t\tconst sameRun =\n\t\t\tholder !== undefined &&\n\t\t\tthis.logged.get(stage) === holder.id &&\n\t\t\thistory[0]?.operation === operation;\n\t\tif (holder) this.logged.set(stage, holder.id);\n\t\tconst serial = (history[0]?.serial ?? 0) + 1;\n\t\tstate.history = appendHistory(\n\t\t\thistory,\n\t\t\t{ serial, at: new Date().toISOString(), by: currentActor(), operation },\n\t\t\tsameRun,\n\t\t);\n\t\t// Providers stamp `lastDeployedAt` on the object they are given, so the\n\t\t// version is taken after the write, from what was actually stored.\n\t\tawait this.provider.write(stage, state);\n\t\treturn versionOf(state);\n\t}\n\n\tprivate warnOnce(): void {\n\t\tif (this.warned) return;\n\t\tthis.warned = true;\n\t\tthis.warn(\n\t\t\tnew StateStoreWithoutLocking(\n\t\t\t\tthis.provider.constructor?.name || 'anonymous',\n\t\t\t),\n\t\t);\n\t}\n}\n\n/** Key order is the provider's, so this is stable for a given stored state. */\nfunction versionOf(state: ProviderState): StateVersion {\n\treturn contentVersion(JSON.stringify(state));\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
|
|
2
|
-
const require_sniffer = require("./sniffer-
|
|
2
|
+
const require_sniffer = require("./sniffer-2aK7cB2u.cjs");
|
|
3
3
|
let node_path = require("node:path");
|
|
4
4
|
let node_fs_promises = require("node:fs/promises");
|
|
5
5
|
let node_crypto = require("node:crypto");
|
|
@@ -175,4 +175,4 @@ Object.defineProperty(exports, "LocalStateStore_exports", {
|
|
|
175
175
|
}
|
|
176
176
|
});
|
|
177
177
|
|
|
178
|
-
//# sourceMappingURL=LocalStateStore-
|
|
178
|
+
//# sourceMappingURL=LocalStateStore-AtviUBky.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LocalStateStore-
|
|
1
|
+
{"version":3,"file":"LocalStateStore-AtviUBky.cjs","names":["DocumentStateStore","join","readFile","contentVersion","StateVersionConflict","randomUUID","open","rename","rm","writeFile","link","StateLocked","unlink","mkdir","StateStoreBusy","stat"],"sources":["../src/deploy/LocalStateStore.ts"],"sourcesContent":["/**\n * Local filesystem state store.\n *\n * `.gkm/deploy-<stage>.json` holds the state, `.gkm/deploy-<stage>.lock` the\n * lock. Every file is mode 0600: state holds database passwords and IAM keys.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport {\n\tlink,\n\tmkdir,\n\topen,\n\treadFile,\n\trename,\n\trm,\n\tstat,\n\tunlink,\n\twriteFile,\n} from 'node:fs/promises';\nimport { join } from 'node:path';\nimport {\n\tcontentVersion,\n\tDocumentStateStore,\n\ttype LockHolder,\n\ttype RawState,\n\tStateLocked,\n\tStateStoreBusy,\n\ttype StateVersion,\n\tStateVersionConflict,\n} from './StateStore';\n\nconst FILE_MODE = 0o600;\n\n/** How long a write waits for another process's write to finish. */\nconst MUTEX_TIMEOUT_MS = 5_000;\n/**\n * A write holds the mutex for milliseconds, so one this old was left by a\n * process that died mid-write and is safe to take over.\n */\nconst MUTEX_STALE_MS = 30_000;\n\nfunction isCode(error: unknown, code: string): boolean {\n\treturn (error as NodeJS.ErrnoException)?.code === code;\n}\n\nexport class LocalStateStore extends DocumentStateStore {\n\tconstructor(readonly workspaceRoot: string) {\n\t\tsuper();\n\t}\n\n\tprivate get dir(): string {\n\t\treturn join(this.workspaceRoot, '.gkm');\n\t}\n\n\tstatePath(stage: string): string {\n\t\treturn join(this.dir, `deploy-${stage}.json`);\n\t}\n\n\tlockPath(stage: string): string {\n\t\treturn join(this.dir, `deploy-${stage}.lock`);\n\t}\n\n\tbackupPath(stage: string): string {\n\t\treturn join(this.dir, `deploy-${stage}.v1.json`);\n\t}\n\n\tprivate mutexPath(stage: string): string {\n\t\treturn join(this.dir, `deploy-${stage}.json.mutex`);\n\t}\n\n\tprotected location(stage: string): string {\n\t\treturn this.statePath(stage);\n\t}\n\n\tprotected async readRaw(stage: string): Promise<RawState | null> {\n\t\ttry {\n\t\t\tconst body = await readFile(this.statePath(stage), 'utf-8');\n\t\t\treturn { body, version: contentVersion(body) };\n\t\t} catch (error) {\n\t\t\tif (isCode(error, 'ENOENT')) return null;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprotected async writeRaw(\n\t\tstage: string,\n\t\tbody: string,\n\t\texpectedVersion: StateVersion | null,\n\t): Promise<StateVersion> {\n\t\tawait this.ensureDir();\n\t\treturn this.withMutex(stage, async () => {\n\t\t\tconst current = await this.readRaw(stage);\n\t\t\tconst actual = current?.version ?? null;\n\t\t\tif (actual !== expectedVersion) {\n\t\t\t\tthrow new StateVersionConflict(stage, expectedVersion, actual);\n\t\t\t}\n\n\t\t\t// Written beside the target and renamed over it: a reader sees the\n\t\t\t// old file or the new one, never half of either.\n\t\t\tconst target = this.statePath(stage);\n\t\t\tconst temp = `${target}.${randomUUID()}.tmp`;\n\t\t\ttry {\n\t\t\t\tconst handle = await open(temp, 'wx', FILE_MODE);\n\t\t\t\ttry {\n\t\t\t\t\tawait handle.writeFile(body);\n\t\t\t\t\tawait handle.sync();\n\t\t\t\t} finally {\n\t\t\t\t\tawait handle.close();\n\t\t\t\t}\n\t\t\t\tawait rename(temp, target);\n\t\t\t} catch (error) {\n\t\t\t\tawait rm(temp, { force: true });\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn contentVersion(body);\n\t\t});\n\t}\n\n\tprotected async writeV1Backup(stage: string, body: string): Promise<void> {\n\t\ttry {\n\t\t\tawait writeFile(this.backupPath(stage), body, {\n\t\t\t\tflag: 'wx',\n\t\t\t\tmode: FILE_MODE,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\t// The first migration's backup is the one worth keeping.\n\t\t\tif (!isCode(error, 'EEXIST')) throw error;\n\t\t}\n\t}\n\n\tprotected async createLock(stage: string, holder: LockHolder): Promise<void> {\n\t\tawait this.ensureDir();\n\t\t// Written whole, then linked into place: `link` fails if the lock\n\t\t// exists, so taking it is atomic — and a racing runner that loses never\n\t\t// reads a lock its winner has created but not yet written to.\n\t\tconst lock = this.lockPath(stage);\n\t\tconst temp = `${lock}.${randomUUID()}.tmp`;\n\t\tawait writeFile(temp, JSON.stringify(holder, null, 2), {\n\t\t\tflag: 'wx',\n\t\t\tmode: FILE_MODE,\n\t\t});\n\t\ttry {\n\t\t\tawait link(temp, lock);\n\t\t} catch (error) {\n\t\t\tif (isCode(error, 'EEXIST')) {\n\t\t\t\tthrow new StateLocked(stage, await this.readLock(stage), lock);\n\t\t\t}\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tawait unlink(temp).catch(() => {});\n\t\t}\n\t}\n\n\tprotected async readLock(stage: string): Promise<LockHolder | null> {\n\t\ttry {\n\t\t\treturn JSON.parse(\n\t\t\t\tawait readFile(this.lockPath(stage), 'utf-8'),\n\t\t\t) as LockHolder;\n\t\t} catch {\n\t\t\t// Missing, or created by a process that died before writing to it.\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprotected async removeLock(\n\t\tstage: string,\n\t\tholder: LockHolder | null,\n\t): Promise<void> {\n\t\tif (holder) {\n\t\t\tconst current = await this.readLock(stage);\n\t\t\tif (current?.id !== holder.id) return;\n\t\t}\n\t\tawait rm(this.lockPath(stage), { force: true });\n\t}\n\n\tprivate async ensureDir(): Promise<void> {\n\t\tawait mkdir(this.dir, { recursive: true, mode: 0o700 });\n\t}\n\n\t/**\n\t * Serialises the check-then-rename of a conditional write across\n\t * processes. The stage lock is for whole runs; this is for the instant of\n\t * a single write, so even writers that skip the lock never interleave.\n\t */\n\tprivate async withMutex<T>(stage: string, fn: () => Promise<T>): Promise<T> {\n\t\tconst path = this.mutexPath(stage);\n\t\tconst deadline = Date.now() + MUTEX_TIMEOUT_MS;\n\n\t\tfor (;;) {\n\t\t\ttry {\n\t\t\t\tconst handle = await open(path, 'wx', FILE_MODE);\n\t\t\t\tawait handle.close();\n\t\t\t\tbreak;\n\t\t\t} catch (error) {\n\t\t\t\tif (!isCode(error, 'EEXIST')) throw error;\n\t\t\t\tif (await this.isStale(path)) {\n\t\t\t\t\tawait unlink(path).catch(() => {});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (Date.now() > deadline) throw new StateStoreBusy(stage, path);\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 10));\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\treturn await fn();\n\t\t} finally {\n\t\t\tawait rm(path, { force: true });\n\t\t}\n\t}\n\n\tprivate async isStale(path: string): Promise<boolean> {\n\t\ttry {\n\t\t\treturn Date.now() - (await stat(path)).mtimeMs > MUTEX_STALE_MS;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;AA+BA,MAAM,YAAY;;AAGlB,MAAM,mBAAmB;;;;;AAKzB,MAAM,iBAAiB;AAEvB,SAAS,OAAO,OAAgB,MAAuB;CACtD,OAAQ,OAAiC,SAAS;AACnD;AAEA,IAAa,kBAAb,cAAqCA,gBAAAA,mBAAmB;CAClC;CAArB,YAAY,eAAgC;EAC3C,MAAM;EADc,KAAA,gBAAA;CAErB;CAEA,IAAY,MAAc;EACzB,QAAA,GAAOC,UAAAA,KAAAA,CAAK,KAAK,eAAe,MAAM;CACvC;CAEA,UAAU,OAAuB;EAChC,QAAA,GAAOA,UAAAA,KAAAA,CAAK,KAAK,KAAK,UAAU,MAAM,MAAM;CAC7C;CAEA,SAAS,OAAuB;EAC/B,QAAA,GAAOA,UAAAA,KAAAA,CAAK,KAAK,KAAK,UAAU,MAAM,MAAM;CAC7C;CAEA,WAAW,OAAuB;EACjC,QAAA,GAAOA,UAAAA,KAAAA,CAAK,KAAK,KAAK,UAAU,MAAM,SAAS;CAChD;CAEA,UAAkB,OAAuB;EACxC,QAAA,GAAOA,UAAAA,KAAAA,CAAK,KAAK,KAAK,UAAU,MAAM,YAAY;CACnD;CAEA,SAAmB,OAAuB;EACzC,OAAO,KAAK,UAAU,KAAK;CAC5B;CAEA,MAAgB,QAAQ,OAAyC;EAChE,IAAI;GACH,MAAM,OAAO,OAAA,GAAMC,iBAAAA,SAAAA,CAAS,KAAK,UAAU,KAAK,GAAG,OAAO;GAC1D,OAAO;IAAE;IAAM,SAASC,gBAAAA,eAAe,IAAI;GAAE;EAC9C,SAAS,OAAO;GACf,IAAI,OAAO,OAAO,QAAQ,GAAG,OAAO;GACpC,MAAM;EACP;CACD;CAEA,MAAgB,SACf,OACA,MACA,iBACwB;EACxB,MAAM,KAAK,UAAU;EACrB,OAAO,KAAK,UAAU,OAAO,YAAY;GAExC,MAAM,UAAS,MADO,KAAK,QAAQ,KAAK,EAAA,EAChB,WAAW;GACnC,IAAI,WAAW,iBACd,MAAM,IAAIC,gBAAAA,qBAAqB,OAAO,iBAAiB,MAAM;GAK9D,MAAM,SAAS,KAAK,UAAU,KAAK;GACnC,MAAM,OAAO,GAAG,OAAO,IAAA,GAAGC,YAAAA,WAAAA,CAAW,EAAE;GACvC,IAAI;IACH,MAAM,SAAS,OAAA,GAAMC,iBAAAA,KAAAA,CAAK,MAAM,MAAM,SAAS;IAC/C,IAAI;KACH,MAAM,OAAO,UAAU,IAAI;KAC3B,MAAM,OAAO,KAAK;IACnB,UAAU;KACT,MAAM,OAAO,MAAM;IACpB;IACA,OAAA,GAAMC,iBAAAA,OAAAA,CAAO,MAAM,MAAM;GAC1B,SAAS,OAAO;IACf,OAAA,GAAMC,iBAAAA,GAAAA,CAAG,MAAM,EAAE,OAAO,KAAK,CAAC;IAC9B,MAAM;GACP;GACA,OAAOL,gBAAAA,eAAe,IAAI;EAC3B,CAAC;CACF;CAEA,MAAgB,cAAc,OAAe,MAA6B;EACzE,IAAI;GACH,OAAA,GAAMM,iBAAAA,UAAAA,CAAU,KAAK,WAAW,KAAK,GAAG,MAAM;IAC7C,MAAM;IACN,MAAM;GACP,CAAC;EACF,SAAS,OAAO;GAEf,IAAI,CAAC,OAAO,OAAO,QAAQ,GAAG,MAAM;EACrC;CACD;CAEA,MAAgB,WAAW,OAAe,QAAmC;EAC5E,MAAM,KAAK,UAAU;EAIrB,MAAM,OAAO,KAAK,SAAS,KAAK;EAChC,MAAM,OAAO,GAAG,KAAK,IAAA,GAAGJ,YAAAA,WAAAA,CAAW,EAAE;EACrC,OAAA,GAAMI,iBAAAA,UAAAA,CAAU,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG;GACtD,MAAM;GACN,MAAM;EACP,CAAC;EACD,IAAI;GACH,OAAA,GAAMC,iBAAAA,KAAAA,CAAK,MAAM,IAAI;EACtB,SAAS,OAAO;GACf,IAAI,OAAO,OAAO,QAAQ,GACzB,MAAM,IAAIC,gBAAAA,YAAY,OAAO,MAAM,KAAK,SAAS,KAAK,GAAG,IAAI;GAE9D,MAAM;EACP,UAAU;GACT,OAAA,GAAMC,iBAAAA,OAAAA,CAAO,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC;EAClC;CACD;CAEA,MAAgB,SAAS,OAA2C;EACnE,IAAI;GACH,OAAO,KAAK,MACX,OAAA,GAAMV,iBAAAA,SAAAA,CAAS,KAAK,SAAS,KAAK,GAAG,OAAO,CAC7C;EACD,QAAQ;GAEP,OAAO;EACR;CACD;CAEA,MAAgB,WACf,OACA,QACgB;EAChB,IAAI,QAEC;QAAA,MADkB,KAAK,SAAS,KAAK,EAAA,EAC5B,OAAO,OAAO,IAAI;EAAA;EAEhC,OAAA,GAAMM,iBAAAA,GAAAA,CAAG,KAAK,SAAS,KAAK,GAAG,EAAE,OAAO,KAAK,CAAC;CAC/C;CAEA,MAAc,YAA2B;EACxC,OAAA,GAAMK,iBAAAA,MAAAA,CAAM,KAAK,KAAK;GAAE,WAAW;GAAM,MAAM;EAAM,CAAC;CACvD;;;;;;CAOA,MAAc,UAAa,OAAe,IAAkC;EAC3E,MAAM,OAAO,KAAK,UAAU,KAAK;EACjC,MAAM,WAAW,KAAK,IAAI,IAAI;EAE9B,SACC,IAAI;GAEH,OAAM,OAAA,GADeP,iBAAAA,KAAAA,CAAK,MAAM,MAAM,SAAS,EAAA,CAClC,MAAM;GACnB;EACD,SAAS,OAAO;GACf,IAAI,CAAC,OAAO,OAAO,QAAQ,GAAG,MAAM;GACpC,IAAI,MAAM,KAAK,QAAQ,IAAI,GAAG;IAC7B,OAAA,GAAMM,iBAAAA,OAAAA,CAAO,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC;IACjC;GACD;GACA,IAAI,KAAK,IAAI,IAAI,UAAU,MAAM,IAAIE,gBAAAA,eAAe,OAAO,IAAI;GAC/D,MAAM,IAAI,SAAS,YAAY,WAAW,SAAS,EAAE,CAAC;EACvD;EAGD,IAAI;GACH,OAAO,MAAM,GAAG;EACjB,UAAU;GACT,OAAA,GAAMN,iBAAAA,GAAAA,CAAG,MAAM,EAAE,OAAO,KAAK,CAAC;EAC/B;CACD;CAEA,MAAc,QAAQ,MAAgC;EACrD,IAAI;GACH,OAAO,KAAK,IAAI,KAAK,OAAA,GAAMO,iBAAAA,KAAAA,CAAK,IAAI,EAAA,CAAG,UAAU;EAClD,QAAQ;GACP,OAAO;EACR;CACD;AACD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-BhDjJH2R.mjs";
|
|
2
|
-
import { f as StateLocked, g as StateVersionConflict, l as DocumentStateStore, m as StateStoreBusy, x as contentVersion } from "./sniffer-
|
|
2
|
+
import { f as StateLocked, g as StateVersionConflict, l as DocumentStateStore, m as StateStoreBusy, x as contentVersion } from "./sniffer-CABMO-Bh.mjs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { link, mkdir, open, readFile, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
5
5
|
import { randomUUID } from "node:crypto";
|
|
@@ -164,4 +164,4 @@ var LocalStateStore = class extends DocumentStateStore {
|
|
|
164
164
|
//#endregion
|
|
165
165
|
export { LocalStateStore_exports as n, LocalStateStore as t };
|
|
166
166
|
|
|
167
|
-
//# sourceMappingURL=LocalStateStore-
|
|
167
|
+
//# sourceMappingURL=LocalStateStore-BrAX5yy7.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LocalStateStore-
|
|
1
|
+
{"version":3,"file":"LocalStateStore-BrAX5yy7.mjs","names":[],"sources":["../src/deploy/LocalStateStore.ts"],"sourcesContent":["/**\n * Local filesystem state store.\n *\n * `.gkm/deploy-<stage>.json` holds the state, `.gkm/deploy-<stage>.lock` the\n * lock. Every file is mode 0600: state holds database passwords and IAM keys.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport {\n\tlink,\n\tmkdir,\n\topen,\n\treadFile,\n\trename,\n\trm,\n\tstat,\n\tunlink,\n\twriteFile,\n} from 'node:fs/promises';\nimport { join } from 'node:path';\nimport {\n\tcontentVersion,\n\tDocumentStateStore,\n\ttype LockHolder,\n\ttype RawState,\n\tStateLocked,\n\tStateStoreBusy,\n\ttype StateVersion,\n\tStateVersionConflict,\n} from './StateStore';\n\nconst FILE_MODE = 0o600;\n\n/** How long a write waits for another process's write to finish. */\nconst MUTEX_TIMEOUT_MS = 5_000;\n/**\n * A write holds the mutex for milliseconds, so one this old was left by a\n * process that died mid-write and is safe to take over.\n */\nconst MUTEX_STALE_MS = 30_000;\n\nfunction isCode(error: unknown, code: string): boolean {\n\treturn (error as NodeJS.ErrnoException)?.code === code;\n}\n\nexport class LocalStateStore extends DocumentStateStore {\n\tconstructor(readonly workspaceRoot: string) {\n\t\tsuper();\n\t}\n\n\tprivate get dir(): string {\n\t\treturn join(this.workspaceRoot, '.gkm');\n\t}\n\n\tstatePath(stage: string): string {\n\t\treturn join(this.dir, `deploy-${stage}.json`);\n\t}\n\n\tlockPath(stage: string): string {\n\t\treturn join(this.dir, `deploy-${stage}.lock`);\n\t}\n\n\tbackupPath(stage: string): string {\n\t\treturn join(this.dir, `deploy-${stage}.v1.json`);\n\t}\n\n\tprivate mutexPath(stage: string): string {\n\t\treturn join(this.dir, `deploy-${stage}.json.mutex`);\n\t}\n\n\tprotected location(stage: string): string {\n\t\treturn this.statePath(stage);\n\t}\n\n\tprotected async readRaw(stage: string): Promise<RawState | null> {\n\t\ttry {\n\t\t\tconst body = await readFile(this.statePath(stage), 'utf-8');\n\t\t\treturn { body, version: contentVersion(body) };\n\t\t} catch (error) {\n\t\t\tif (isCode(error, 'ENOENT')) return null;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprotected async writeRaw(\n\t\tstage: string,\n\t\tbody: string,\n\t\texpectedVersion: StateVersion | null,\n\t): Promise<StateVersion> {\n\t\tawait this.ensureDir();\n\t\treturn this.withMutex(stage, async () => {\n\t\t\tconst current = await this.readRaw(stage);\n\t\t\tconst actual = current?.version ?? null;\n\t\t\tif (actual !== expectedVersion) {\n\t\t\t\tthrow new StateVersionConflict(stage, expectedVersion, actual);\n\t\t\t}\n\n\t\t\t// Written beside the target and renamed over it: a reader sees the\n\t\t\t// old file or the new one, never half of either.\n\t\t\tconst target = this.statePath(stage);\n\t\t\tconst temp = `${target}.${randomUUID()}.tmp`;\n\t\t\ttry {\n\t\t\t\tconst handle = await open(temp, 'wx', FILE_MODE);\n\t\t\t\ttry {\n\t\t\t\t\tawait handle.writeFile(body);\n\t\t\t\t\tawait handle.sync();\n\t\t\t\t} finally {\n\t\t\t\t\tawait handle.close();\n\t\t\t\t}\n\t\t\t\tawait rename(temp, target);\n\t\t\t} catch (error) {\n\t\t\t\tawait rm(temp, { force: true });\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn contentVersion(body);\n\t\t});\n\t}\n\n\tprotected async writeV1Backup(stage: string, body: string): Promise<void> {\n\t\ttry {\n\t\t\tawait writeFile(this.backupPath(stage), body, {\n\t\t\t\tflag: 'wx',\n\t\t\t\tmode: FILE_MODE,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\t// The first migration's backup is the one worth keeping.\n\t\t\tif (!isCode(error, 'EEXIST')) throw error;\n\t\t}\n\t}\n\n\tprotected async createLock(stage: string, holder: LockHolder): Promise<void> {\n\t\tawait this.ensureDir();\n\t\t// Written whole, then linked into place: `link` fails if the lock\n\t\t// exists, so taking it is atomic — and a racing runner that loses never\n\t\t// reads a lock its winner has created but not yet written to.\n\t\tconst lock = this.lockPath(stage);\n\t\tconst temp = `${lock}.${randomUUID()}.tmp`;\n\t\tawait writeFile(temp, JSON.stringify(holder, null, 2), {\n\t\t\tflag: 'wx',\n\t\t\tmode: FILE_MODE,\n\t\t});\n\t\ttry {\n\t\t\tawait link(temp, lock);\n\t\t} catch (error) {\n\t\t\tif (isCode(error, 'EEXIST')) {\n\t\t\t\tthrow new StateLocked(stage, await this.readLock(stage), lock);\n\t\t\t}\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tawait unlink(temp).catch(() => {});\n\t\t}\n\t}\n\n\tprotected async readLock(stage: string): Promise<LockHolder | null> {\n\t\ttry {\n\t\t\treturn JSON.parse(\n\t\t\t\tawait readFile(this.lockPath(stage), 'utf-8'),\n\t\t\t) as LockHolder;\n\t\t} catch {\n\t\t\t// Missing, or created by a process that died before writing to it.\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprotected async removeLock(\n\t\tstage: string,\n\t\tholder: LockHolder | null,\n\t): Promise<void> {\n\t\tif (holder) {\n\t\t\tconst current = await this.readLock(stage);\n\t\t\tif (current?.id !== holder.id) return;\n\t\t}\n\t\tawait rm(this.lockPath(stage), { force: true });\n\t}\n\n\tprivate async ensureDir(): Promise<void> {\n\t\tawait mkdir(this.dir, { recursive: true, mode: 0o700 });\n\t}\n\n\t/**\n\t * Serialises the check-then-rename of a conditional write across\n\t * processes. The stage lock is for whole runs; this is for the instant of\n\t * a single write, so even writers that skip the lock never interleave.\n\t */\n\tprivate async withMutex<T>(stage: string, fn: () => Promise<T>): Promise<T> {\n\t\tconst path = this.mutexPath(stage);\n\t\tconst deadline = Date.now() + MUTEX_TIMEOUT_MS;\n\n\t\tfor (;;) {\n\t\t\ttry {\n\t\t\t\tconst handle = await open(path, 'wx', FILE_MODE);\n\t\t\t\tawait handle.close();\n\t\t\t\tbreak;\n\t\t\t} catch (error) {\n\t\t\t\tif (!isCode(error, 'EEXIST')) throw error;\n\t\t\t\tif (await this.isStale(path)) {\n\t\t\t\t\tawait unlink(path).catch(() => {});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (Date.now() > deadline) throw new StateStoreBusy(stage, path);\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 10));\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\treturn await fn();\n\t\t} finally {\n\t\t\tawait rm(path, { force: true });\n\t\t}\n\t}\n\n\tprivate async isStale(path: string): Promise<boolean> {\n\t\ttry {\n\t\t\treturn Date.now() - (await stat(path)).mtimeMs > MUTEX_STALE_MS;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as __require } from "./rolldown-runtime-BhDjJH2R.mjs";
|
|
2
2
|
import { n as deployIdentity } from "./identity-CBXr4wNi.mjs";
|
|
3
|
-
import { f as StateLocked, g as StateVersionConflict, l as DocumentStateStore } from "./sniffer-
|
|
3
|
+
import { f as StateLocked, g as StateVersionConflict, l as DocumentStateStore } from "./sniffer-CABMO-Bh.mjs";
|
|
4
4
|
import { a as findProjectBucket, i as ensureProjectBucket, o as projectBucketName, r as callerAccountId } from "./projectBucket-C_DN4WzF.mjs";
|
|
5
5
|
import { DeleteObjectCommand, GetObjectCommand, PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
|
|
6
6
|
import { STSClient } from "@aws-sdk/client-sts";
|
|
@@ -220,4 +220,4 @@ var S3StateStore = class S3StateStore extends DocumentStateStore {
|
|
|
220
220
|
//#endregion
|
|
221
221
|
export { S3StateStore };
|
|
222
222
|
|
|
223
|
-
//# sourceMappingURL=S3StateStore-
|
|
223
|
+
//# sourceMappingURL=S3StateStore-Cx7njkBz.mjs.map
|