@stacksjs/ts-cloud 0.9.1 → 0.9.3
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/aws/index.js +10 -2
- package/dist/bin/chunk-09nwf2gy.js +34 -0
- package/dist/bin/chunk-14cwr6eh.js +70 -0
- package/dist/bin/chunk-271gk1n2.js +6 -0
- package/dist/bin/chunk-38pq971s.js +2 -0
- package/dist/bin/chunk-3gykfyq4.js +37 -0
- package/dist/bin/chunk-3r4fb59r.js +3 -0
- package/dist/bin/chunk-41x17hw1.js +1 -0
- package/dist/bin/chunk-4vrqm9h0.js +2 -0
- package/dist/bin/chunk-57y1zxbf.js +3 -0
- package/dist/bin/chunk-598yf4bs.js +1 -0
- package/dist/bin/chunk-8v7ddyvf.js +1 -0
- package/dist/bin/chunk-92mea34a.js +1 -0
- package/dist/bin/chunk-9pvsff8g.js +1 -0
- package/dist/bin/chunk-9v39615t.js +1 -0
- package/dist/bin/chunk-avm7tnwe.js +1 -0
- package/dist/bin/chunk-ax9mr6wm.js +44 -0
- package/dist/bin/chunk-axhnkn5g.js +2 -0
- package/dist/bin/chunk-b5gd39s8.js +512 -0
- package/dist/bin/chunk-b9qbp8j1.js +1 -0
- package/dist/bin/chunk-bz828v8q.js +3 -0
- package/dist/bin/chunk-c1vcdgvr.js +1 -0
- package/dist/bin/chunk-ctd2vg9w.js +2 -0
- package/dist/bin/chunk-dbgffky8.js +1 -0
- package/dist/bin/chunk-dwr30vbv.js +1 -0
- package/dist/bin/chunk-e3xrwh9z.js +1 -0
- package/dist/bin/chunk-fhc6ntvd.js +2 -0
- package/dist/bin/chunk-fpm59y25.js +6 -0
- package/dist/bin/chunk-fvbxvq6b.js +1 -0
- package/dist/bin/chunk-fy8j3y8p.js +92 -0
- package/dist/bin/chunk-fz21b57w.js +1 -0
- package/dist/bin/chunk-gavvf0pg.js +141 -0
- package/dist/bin/chunk-ggn7ax8p.js +4 -0
- package/dist/bin/chunk-gpe2prkm.js +1 -0
- package/dist/bin/chunk-gqf6jsmy.js +1 -0
- package/dist/bin/chunk-h5pa5men.js +2 -0
- package/dist/bin/chunk-hm08xdxf.js +2 -0
- package/dist/bin/chunk-hzgz13nf.js +1 -0
- package/dist/bin/chunk-hzqw8xm5.js +111 -0
- package/dist/bin/chunk-j703btc5.js +50 -0
- package/dist/bin/chunk-jpjamjey.js +6935 -0
- package/dist/bin/chunk-m2zwtapr.js +1 -0
- package/dist/bin/chunk-m669wtgr.js +1 -0
- package/dist/bin/chunk-mh0kdzqp.js +2 -0
- package/dist/bin/chunk-mr0atd2s.js +2 -0
- package/dist/bin/chunk-ngcyftm2.js +1 -0
- package/dist/bin/chunk-p66ptpmr.js +2 -0
- package/dist/bin/chunk-p8q9bq9g.js +1 -0
- package/dist/bin/chunk-r3kv0vm9.js +6 -0
- package/dist/bin/chunk-r9hjwcj9.js +6 -0
- package/dist/bin/chunk-rtczra13.js +1 -0
- package/dist/bin/chunk-ry030a6b.js +1507 -0
- package/dist/bin/chunk-rytk89az.js +60 -0
- package/dist/bin/chunk-sgyffpgm.js +581 -0
- package/dist/bin/chunk-vek8a0w6.js +1 -0
- package/dist/bin/chunk-waayf9ay.js +2 -0
- package/dist/bin/chunk-ynjvbphf.js +8 -0
- package/dist/bin/chunk-yv9sth30.js +1 -0
- package/dist/bin/cli.js +417 -10597
- package/dist/bin/dashboard-server.js +1 -6998
- package/dist/{chunk-hg7rhrgd.js → chunk-1c8dbv57.js} +5 -1
- package/dist/{chunk-5nr95wpj.js → chunk-728jvrr0.js} +3 -3
- package/dist/{chunk-ws47smxr.js → chunk-k4px0bnv.js} +2 -2
- package/dist/{chunk-hygwq9y2.js → chunk-q0st3se8.js} +2 -2
- package/dist/{chunk-atbgd8wz.js → chunk-qr803fye.js} +112 -1
- package/dist/deploy/attach-credentials.d.ts +57 -0
- package/dist/deploy/index.js +4 -4
- package/dist/deploy/site-ports.d.ts +151 -0
- package/dist/deploy/site-target.d.ts +24 -1
- package/dist/dns/declared-records.d.ts +87 -0
- package/dist/dns/declared-records.test.d.ts +1 -0
- package/dist/dns/index.d.ts +2 -0
- package/dist/dns/index.js +10 -2
- package/dist/drivers/index.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +13 -5
- package/dist/ui/404.html +16 -548
- package/dist/ui/_stx/chunk.5ddb5087.js +90 -0
- package/dist/ui/_stx/chunk.9fd39d5b.js +86 -0
- package/dist/ui/_stx/chunk.d5301f79.js +119 -0
- package/dist/ui/_stx/crosswind.222ed683.css +1 -0
- package/dist/ui/_stx/crosswind.616c25f3.css +1 -0
- package/dist/ui/_stx/crosswind.80baa894.css +320 -0
- package/dist/ui/_stx/crosswind.906ee17c.css +1 -0
- package/dist/ui/_stx/crosswind.996ed49e.css +1 -0
- package/dist/ui/_stx/crosswind.b7a99a5c.css +1 -0
- package/dist/ui/_stx/router.fa5bc4dc.js +4 -0
- package/dist/ui/_stx/runtime.c696d17a.js +1 -0
- package/dist/ui/_stx/style.448ab192.css +1 -0
- package/dist/ui/accept-invitation.html +2 -1133
- package/dist/ui/access-denied.html +7 -1130
- package/dist/ui/account/automation.html +12 -1134
- package/dist/ui/account/security.html +13 -1136
- package/dist/ui/applications/compose.html +12 -1134
- package/dist/ui/applications/new.html +13 -1137
- package/dist/ui/data/backups.html +91 -1136
- package/dist/ui/data/services.html +89 -1136
- package/dist/ui/data/volumes.html +61 -1136
- package/dist/ui/index.html +60 -1136
- package/dist/ui/infrastructure/topology.html +128 -1135
- package/dist/ui/integrations.html +13 -1138
- package/dist/ui/operations/alerts.html +59 -1136
- package/dist/ui/operations/configuration.html +13 -1135
- package/dist/ui/operations/jobs.html +87 -1136
- package/dist/ui/operations/maintenance.html +12 -1134
- package/dist/ui/operations/observability.html +93 -1136
- package/dist/ui/operations/previews.html +12 -1134
- package/dist/ui/operations/queue.html +12 -1134
- package/dist/ui/operations/regions.html +12 -1134
- package/dist/ui/operations/releases.html +12 -1134
- package/dist/ui/operations/spend.html +65 -1136
- package/dist/ui/operations/workloads.html +115 -1136
- package/dist/ui/robots.txt +2 -0
- package/dist/ui/security.html +24 -1136
- package/dist/ui/server/actions.html +67 -1138
- package/dist/ui/server/activity.html +7 -1130
- package/dist/ui/server/capacity.html +12 -1134
- package/dist/ui/server/database.html +166 -1135
- package/dist/ui/server/deployments.html +60 -1136
- package/dist/ui/server/diagnostics.html +7 -1130
- package/dist/ui/server/firewall.html +286 -1212
- package/dist/ui/server/fleet.html +45 -1136
- package/dist/ui/server/logs.html +34 -1135
- package/dist/ui/server/metrics.html +124 -1140
- package/dist/ui/server/security.html +7 -1130
- package/dist/ui/server/services.html +46 -1133
- package/dist/ui/server/sites.html +287 -1137
- package/dist/ui/server/ssh-keys.html +62 -1135
- package/dist/ui/server/team.html +155 -1136
- package/dist/ui/server/terminal.html +97 -1183
- package/dist/ui/serverless/alarms.html +62 -1135
- package/dist/ui/serverless/assets.html +47 -1132
- package/dist/ui/serverless/cost.html +7 -1130
- package/dist/ui/serverless/data.html +46 -1135
- package/dist/ui/serverless/deployments.html +47 -1132
- package/dist/ui/serverless/firewall.html +7 -1130
- package/dist/ui/serverless/functions.html +50 -1136
- package/dist/ui/serverless/logs.html +34 -1135
- package/dist/ui/serverless/metrics.html +7 -1130
- package/dist/ui/serverless/queues.html +58 -1135
- package/dist/ui/serverless/secrets.html +62 -1136
- package/dist/ui/serverless/traces.html +12 -1134
- package/dist/ui/serverless.html +64 -1137
- package/dist/ui-src/pages/server/firewall.stx +14 -14
- package/package.json +3 -3
|
@@ -1371,7 +1371,7 @@ function resolveSiteKind(site) {
|
|
|
1371
1371
|
function hasComputeConfigured(config) {
|
|
1372
1372
|
return config.infrastructure?.compute != null || Boolean(config.cloud?.attachTo?.trim());
|
|
1373
1373
|
}
|
|
1374
|
-
function validateDeploymentConfig(config) {
|
|
1374
|
+
function validateDeploymentConfig(config, options = {}) {
|
|
1375
1375
|
const errors = [];
|
|
1376
1376
|
const warnings = [];
|
|
1377
1377
|
const sites = config.sites || {};
|
|
@@ -1444,6 +1444,10 @@ function validateDeploymentConfig(config) {
|
|
|
1444
1444
|
errors.push(`Site '${name}' deploys to a server (deploy:'server'${site.deploy ? "" : " inferred from `start`"}) but no \`infrastructure.compute\` is configured. Set deploy:'bucket' or add a server (infrastructure.compute).`);
|
|
1445
1445
|
}
|
|
1446
1446
|
if (typeof site.port === "number") {
|
|
1447
|
+
const coTenant = options.occupiedPorts?.get(site.port);
|
|
1448
|
+
if (coTenant) {
|
|
1449
|
+
errors.push(`Site '${name}' wants port ${site.port}, which project '${coTenant}' already serves on this box. ` + `Attached projects share one port namespace. Give '${name}' a free port, or let the attach allocate one.`);
|
|
1450
|
+
}
|
|
1447
1451
|
const existing = portOwners.get(site.port);
|
|
1448
1452
|
if (existing) {
|
|
1449
1453
|
errors.push(`Sites '${existing}' and '${name}' both use port ${site.port}. Server apps sharing a box must use distinct ports.`);
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
Route53Provider,
|
|
8
8
|
UnifiedDnsValidator,
|
|
9
9
|
createDnsProvider
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-qr803fye.js";
|
|
11
11
|
import {
|
|
12
12
|
Route53Client
|
|
13
13
|
} from "./chunk-32e7ya18.js";
|
|
@@ -815,7 +815,7 @@ async function deployStaticSiteWithExternalDnsFull(config) {
|
|
|
815
815
|
}
|
|
816
816
|
}
|
|
817
817
|
onProgress?.("upload", "Uploading files to S3...");
|
|
818
|
-
const { uploadStaticFiles } = await import("./chunk-
|
|
818
|
+
const { uploadStaticFiles } = await import("./chunk-k4px0bnv.js");
|
|
819
819
|
const uploadResult = await uploadStaticFiles({
|
|
820
820
|
sourceDir,
|
|
821
821
|
bucket: infraResult.bucket,
|
|
@@ -835,7 +835,7 @@ async function deployStaticSiteWithExternalDnsFull(config) {
|
|
|
835
835
|
}
|
|
836
836
|
if (infraResult.distributionId && uploadResult.uploaded > 0) {
|
|
837
837
|
onProgress?.("invalidate", "Invalidating CloudFront cache...");
|
|
838
|
-
const { invalidateCache } = await import("./chunk-
|
|
838
|
+
const { invalidateCache } = await import("./chunk-k4px0bnv.js");
|
|
839
839
|
await invalidateCache(infraResult.distributionId);
|
|
840
840
|
}
|
|
841
841
|
onProgress?.("complete", "Deployment complete!");
|
|
@@ -5,9 +5,9 @@ import {
|
|
|
5
5
|
generateStaticSiteTemplate,
|
|
6
6
|
invalidateCache,
|
|
7
7
|
uploadStaticFiles
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-728jvrr0.js";
|
|
9
9
|
import"./chunk-01d86gt1.js";
|
|
10
|
-
import"./chunk-
|
|
10
|
+
import"./chunk-qr803fye.js";
|
|
11
11
|
import"./chunk-32e7ya18.js";
|
|
12
12
|
import"./chunk-4cjrg98a.js";
|
|
13
13
|
import"./chunk-rds0sy87.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
deployStaticSiteWithExternalDnsFull
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-728jvrr0.js";
|
|
4
4
|
import {
|
|
5
5
|
box,
|
|
6
6
|
error,
|
|
@@ -50,7 +50,7 @@ import {
|
|
|
50
50
|
resolveSiteKind,
|
|
51
51
|
resolveUiSource,
|
|
52
52
|
siteInstallBase
|
|
53
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-1c8dbv57.js";
|
|
54
54
|
import {
|
|
55
55
|
SSMClient
|
|
56
56
|
} from "./chunk-7m60qnc8.js";
|
|
@@ -956,6 +956,117 @@ function deepEqual(a, b) {
|
|
|
956
956
|
const bRecord = b;
|
|
957
957
|
return Object.keys(bRecord).every((key) => deepEqual(aRecord[key], bRecord[key]));
|
|
958
958
|
}
|
|
959
|
+
// src/dns/declared-records.ts
|
|
960
|
+
var SINGLETON_TYPES = new Set(["A", "AAAA", "CNAME", "ALIAS"]);
|
|
961
|
+
function policyTag(content) {
|
|
962
|
+
const normalized = content.trim().replace(/^"|"$/g, "").toLowerCase();
|
|
963
|
+
if (normalized.startsWith("v=spf1"))
|
|
964
|
+
return "v=spf1";
|
|
965
|
+
if (normalized.startsWith("v=dmarc1"))
|
|
966
|
+
return "v=dmarc1";
|
|
967
|
+
return;
|
|
968
|
+
}
|
|
969
|
+
function unquote(value) {
|
|
970
|
+
return value.trim().replace(/^"(.*)"$/s, "$1");
|
|
971
|
+
}
|
|
972
|
+
function normalizeName(name) {
|
|
973
|
+
return name.replace(/\.$/, "").toLowerCase();
|
|
974
|
+
}
|
|
975
|
+
function qualifyName(name, zone) {
|
|
976
|
+
const z = normalizeName(zone);
|
|
977
|
+
const raw = (name ?? "@").trim();
|
|
978
|
+
if (!raw || raw === "@")
|
|
979
|
+
return z;
|
|
980
|
+
const n = normalizeName(raw);
|
|
981
|
+
if (n === z || n.endsWith(`.${z}`))
|
|
982
|
+
return n;
|
|
983
|
+
return `${n}.${z}`;
|
|
984
|
+
}
|
|
985
|
+
function resolveDeclaredRecords(records, zone) {
|
|
986
|
+
return records.map((record) => ({
|
|
987
|
+
...record,
|
|
988
|
+
name: qualifyName(record.name, zone),
|
|
989
|
+
proxied: record.proxied ?? false
|
|
990
|
+
}));
|
|
991
|
+
}
|
|
992
|
+
function matches(existing, record) {
|
|
993
|
+
if (existing.type !== record.type)
|
|
994
|
+
return false;
|
|
995
|
+
if (normalizeName(existing.name) !== normalizeName(record.name))
|
|
996
|
+
return false;
|
|
997
|
+
if (SINGLETON_TYPES.has(record.type))
|
|
998
|
+
return true;
|
|
999
|
+
if (record.type === "TXT") {
|
|
1000
|
+
const tag = policyTag(record.content);
|
|
1001
|
+
if (tag)
|
|
1002
|
+
return policyTag(unquote(existing.content)) === tag;
|
|
1003
|
+
return unquote(existing.content) === unquote(record.content);
|
|
1004
|
+
}
|
|
1005
|
+
return unquote(existing.content) === unquote(record.content);
|
|
1006
|
+
}
|
|
1007
|
+
function isCurrent(existing, record) {
|
|
1008
|
+
if (unquote(existing.content) !== unquote(record.content))
|
|
1009
|
+
return false;
|
|
1010
|
+
if (record.priority !== undefined && existing.priority !== record.priority)
|
|
1011
|
+
return false;
|
|
1012
|
+
if (record.proxied !== undefined && existing.proxied !== undefined && existing.proxied !== record.proxied)
|
|
1013
|
+
return false;
|
|
1014
|
+
return true;
|
|
1015
|
+
}
|
|
1016
|
+
async function reconcileDeclaredRecords(options) {
|
|
1017
|
+
const { provider, zone, records } = options;
|
|
1018
|
+
const report = { outcomes: [], warnings: [] };
|
|
1019
|
+
if (records.length === 0)
|
|
1020
|
+
return report;
|
|
1021
|
+
const listed = await provider.listRecords(zone);
|
|
1022
|
+
if (!listed.success) {
|
|
1023
|
+
report.warnings.push(`could not list ${zone}: ${listed.message || "unknown provider error"} — records not reconciled`);
|
|
1024
|
+
return report;
|
|
1025
|
+
}
|
|
1026
|
+
const existing = listed.records;
|
|
1027
|
+
for (const record of records) {
|
|
1028
|
+
const current = existing.filter((e) => matches(e, record));
|
|
1029
|
+
if (current.length > 0 && current.every((e) => isCurrent(e, record))) {
|
|
1030
|
+
report.outcomes.push({ record, action: "unchanged" });
|
|
1031
|
+
continue;
|
|
1032
|
+
}
|
|
1033
|
+
const wire = {
|
|
1034
|
+
name: record.name,
|
|
1035
|
+
type: record.type,
|
|
1036
|
+
content: record.content,
|
|
1037
|
+
ttl: record.ttl ?? 3600,
|
|
1038
|
+
...record.priority !== undefined ? { priority: record.priority } : {},
|
|
1039
|
+
...record.proxied !== undefined ? { proxied: record.proxied } : {}
|
|
1040
|
+
};
|
|
1041
|
+
const supersedes = record.type === "TXT" && policyTag(record.content) !== undefined;
|
|
1042
|
+
if (supersedes) {
|
|
1043
|
+
for (const stale of current) {
|
|
1044
|
+
const removed = await provider.deleteRecord(zone, {
|
|
1045
|
+
name: stale.name,
|
|
1046
|
+
type: stale.type,
|
|
1047
|
+
content: stale.content
|
|
1048
|
+
});
|
|
1049
|
+
if (!removed.success)
|
|
1050
|
+
report.warnings.push(`could not remove superseded ${stale.type} at ${stale.name}: ${removed.message || "unknown error"}`);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
const result = supersedes || current.length === 0 ? await provider.createRecord(zone, wire) : await provider.upsertRecord(zone, wire);
|
|
1054
|
+
if (result.success)
|
|
1055
|
+
report.outcomes.push({ record, action: current.length > 0 ? "updated" : "created" });
|
|
1056
|
+
else
|
|
1057
|
+
report.outcomes.push({ record, action: "failed", message: result.message });
|
|
1058
|
+
}
|
|
1059
|
+
for (const type of ["MX"]) {
|
|
1060
|
+
const declaredNames = new Set(records.filter((r) => r.type === type).map((r) => normalizeName(r.name)));
|
|
1061
|
+
for (const name of declaredNames) {
|
|
1062
|
+
const declaredValues = new Set(records.filter((r) => r.type === type && normalizeName(r.name) === name).map((r) => unquote(r.content).toLowerCase()));
|
|
1063
|
+
const strays = existing.filter((e) => e.type === type && normalizeName(e.name) === name && !declaredValues.has(unquote(e.content).toLowerCase()));
|
|
1064
|
+
for (const stray of strays)
|
|
1065
|
+
report.warnings.push(`${name} has an undeclared ${type} record (${stray.content}) alongside the declared one — mail will be split between them. Remove it at the provider if it is stale.`);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
return report;
|
|
1069
|
+
}
|
|
959
1070
|
// src/dns/route53-adapter.ts
|
|
960
1071
|
class Route53Provider {
|
|
961
1072
|
name = "route53";
|
|
@@ -2008,4 +2119,4 @@ class DnsProviderFactory {
|
|
|
2008
2119
|
}
|
|
2009
2120
|
var dnsProviders = new DnsProviderFactory;
|
|
2010
2121
|
|
|
2011
|
-
export { PROXIABLE_RECORD_TYPES, PorkbunProvider, GoDaddyProvider, CLOUDFLARE_MANAGED_RULE_PREFIX, CloudflareProvider, Route53Provider, UnifiedDnsValidator, createPorkbunValidator, createGoDaddyValidator, createRoute53Validator, createDnsProvider, detectDnsProvider, DnsProviderFactory, dnsProviders, ACMClient, ACMDnsValidator };
|
|
2122
|
+
export { PROXIABLE_RECORD_TYPES, PorkbunProvider, GoDaddyProvider, CLOUDFLARE_MANAGED_RULE_PREFIX, CloudflareProvider, policyTag, qualifyName, resolveDeclaredRecords, reconcileDeclaredRecords, Route53Provider, UnifiedDnsValidator, createPorkbunValidator, createGoDaddyValidator, createRoute53Validator, createDnsProvider, detectDnsProvider, DnsProviderFactory, dnsProviders, ACMClient, ACMDnsValidator };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The minimum a driver has to produce for a server to be attributed.
|
|
3
|
+
*
|
|
4
|
+
* Structural rather than a provider type so a Hetzner server satisfies it as-is
|
|
5
|
+
* and another driver can satisfy it without importing anything.
|
|
6
|
+
*/
|
|
7
|
+
export interface ReachableServer {
|
|
8
|
+
name: string;
|
|
9
|
+
labels?: Record<string, string>;
|
|
10
|
+
}
|
|
11
|
+
export interface CredentialReach {
|
|
12
|
+
/** Every server the credential enumerated. */
|
|
13
|
+
total: number;
|
|
14
|
+
/** Servers belonging to the project being attached TO. Expected reach. */
|
|
15
|
+
owner: string[];
|
|
16
|
+
/** Servers belonging to the attaching project itself, if it has any. */
|
|
17
|
+
self: string[];
|
|
18
|
+
/** Servers owned by unrelated ts-cloud projects, keyed by project slug. */
|
|
19
|
+
others: Map<string, string[]>;
|
|
20
|
+
/**
|
|
21
|
+
* Servers carrying no ts-cloud project label.
|
|
22
|
+
*
|
|
23
|
+
* Counted separately because they are the reach most likely to surprise: not
|
|
24
|
+
* managed by ts-cloud at all, and so not visible in any ts-cloud config, yet
|
|
25
|
+
* just as writable by the token.
|
|
26
|
+
*/
|
|
27
|
+
unmanaged: string[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Attribute every server the credential can see to a project.
|
|
31
|
+
*
|
|
32
|
+
* `ownerSlug` is what `cloud.attachTo` names; `selfSlug` is the deploying
|
|
33
|
+
* project. Splitting those two out of `others` is the point: reach over the owner
|
|
34
|
+
* is the reach being asked for, reach over anything else is the reach nobody
|
|
35
|
+
* asked for, and only the second number is an argument against attaching.
|
|
36
|
+
*/
|
|
37
|
+
export declare function describeCredentialReach(servers: ReachableServer[], options: {
|
|
38
|
+
ownerSlug: string;
|
|
39
|
+
selfSlug?: string;
|
|
40
|
+
}): CredentialReach;
|
|
41
|
+
/** Servers the credential reaches that neither project being joined owns. */
|
|
42
|
+
export declare function unrelatedReachCount(reach: CredentialReach): number;
|
|
43
|
+
/**
|
|
44
|
+
* The credential radius as plan lines, ready to print.
|
|
45
|
+
*
|
|
46
|
+
* Returns lines rather than printing so the caller owns the output stream and
|
|
47
|
+
* this stays testable. Sorted, because a plan that reorders itself between runs
|
|
48
|
+
* is a plan nobody diffs.
|
|
49
|
+
*
|
|
50
|
+
* When the reach is exactly the owner's box and this project's own, there is
|
|
51
|
+
* nothing to warn about and the summary says so in one line - a warning that
|
|
52
|
+
* fires every time is a warning that gets skipped.
|
|
53
|
+
*/
|
|
54
|
+
export declare function formatCredentialReach(reach: CredentialReach, options: {
|
|
55
|
+
ownerSlug: string;
|
|
56
|
+
selfSlug?: string;
|
|
57
|
+
}): string[];
|
package/dist/deploy/index.js
CHANGED
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
synchronizeDashboardUsers,
|
|
37
37
|
trackDashboardOperation,
|
|
38
38
|
verifyStaticApiOrigin
|
|
39
|
-
} from "../chunk-
|
|
39
|
+
} from "../chunk-q0st3se8.js";
|
|
40
40
|
import {
|
|
41
41
|
deleteStaticSite,
|
|
42
42
|
deployStaticSite,
|
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
generateStaticSiteTemplate,
|
|
48
48
|
invalidateCache,
|
|
49
49
|
uploadStaticFiles
|
|
50
|
-
} from "../chunk-
|
|
50
|
+
} from "../chunk-728jvrr0.js";
|
|
51
51
|
import {
|
|
52
52
|
buildAndPushServerlessImage
|
|
53
53
|
} from "../chunk-fgk8cqew.js";
|
|
@@ -56,7 +56,7 @@ import"../chunk-nsgqsmrh.js";
|
|
|
56
56
|
import"../chunk-01d86gt1.js";
|
|
57
57
|
import"../chunk-50jpda9q.js";
|
|
58
58
|
import"../chunk-he9a874b.js";
|
|
59
|
-
import"../chunk-
|
|
59
|
+
import"../chunk-qr803fye.js";
|
|
60
60
|
import"../chunk-32e7ya18.js";
|
|
61
61
|
import {
|
|
62
62
|
IPV6_EXCLUDED_HOST_LABELS,
|
|
@@ -83,7 +83,7 @@ import {
|
|
|
83
83
|
siteInstallBase,
|
|
84
84
|
validateDeploymentConfig,
|
|
85
85
|
verifyAddressRecord
|
|
86
|
-
} from "../chunk-
|
|
86
|
+
} from "../chunk-1c8dbv57.js";
|
|
87
87
|
import"../chunk-7m60qnc8.js";
|
|
88
88
|
import"../chunk-4cjrg98a.js";
|
|
89
89
|
import"../chunk-rds0sy87.js";
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import type { CloudConfig } from '@ts-cloud/core';
|
|
2
|
+
/**
|
|
3
|
+
* Port ownership across the projects sharing one box.
|
|
4
|
+
*
|
|
5
|
+
* A box can host several independent projects: each one's deploy writes its own
|
|
6
|
+
* rpx registry fragment and the assembler merges them (see `RPX_SITES_DIR`).
|
|
7
|
+
* That composes cleanly for ROUTES, because routes are keyed by host. It does
|
|
8
|
+
* not compose for PORTS, because every app generated from the same template
|
|
9
|
+
* declares the same loopback ports, and `validateDeploymentConfig` only ever
|
|
10
|
+
* sees one project's `sites`.
|
|
11
|
+
*
|
|
12
|
+
* The second attach therefore passes validation, and then does something worse
|
|
13
|
+
* than failing: ts-cloud's units do not set exclusive binding, so both listeners
|
|
14
|
+
* bind and the kernel load-balances between them. Nothing errors, both services
|
|
15
|
+
* look healthy, and each domain answers with the other project's site for about
|
|
16
|
+
* half its requests. That is not hypothetical - it is what happened to
|
|
17
|
+
* predicthq.org when a storefront picked a port by reading other projects'
|
|
18
|
+
* config files rather than the box (see `assertPortsAreFree` in stacks).
|
|
19
|
+
*
|
|
20
|
+
* `assertPortsAreFree` catches this late, from the deploying box over SSH, by
|
|
21
|
+
* comparing wanted ports against live listeners. That is the better evidence and
|
|
22
|
+
* it stays the last line of defence. What it cannot do is avoid the clash: it
|
|
23
|
+
* exits and tells the operator to go pick free ports by hand. This module is the
|
|
24
|
+
* other half - deciding the ports before anything is shipped, from data a plan
|
|
25
|
+
* already has.
|
|
26
|
+
*
|
|
27
|
+
* The fix does not need new bookkeeping on the box. The fragments already record
|
|
28
|
+
* every upstream a project serves, so the host is its own port registry - it was
|
|
29
|
+
* simply never read. This module turns those fragments into a port -> owner map,
|
|
30
|
+
* finds the collisions, and allocates around them.
|
|
31
|
+
*
|
|
32
|
+
* Everything here is pure. The one thing that must touch the box, reading the
|
|
33
|
+
* fragments, is split into a script builder and a parser so both halves are
|
|
34
|
+
* testable without a server.
|
|
35
|
+
*
|
|
36
|
+
* @see https://github.com/stacksjs/ts-cloud/issues/168
|
|
37
|
+
*/
|
|
38
|
+
/**
|
|
39
|
+
* Where the rpx gateway keeps one registry fragment per project.
|
|
40
|
+
*
|
|
41
|
+
* Deliberately duplicated from `RPX_SITES_DIR` rather than imported:
|
|
42
|
+
* `rpx-gateway.ts` imports `site-target.ts`, and this module imports it too, so
|
|
43
|
+
* importing the constant from there would close a cycle. `site-ports.test.ts`
|
|
44
|
+
* asserts the two stay equal, so the duplicate cannot drift silently.
|
|
45
|
+
*/
|
|
46
|
+
export declare const HOST_SITES_DIR = "/etc/rpx/sites.d";
|
|
47
|
+
export interface SitePortRange {
|
|
48
|
+
/** Lowest port the allocator may hand out, inclusive. */
|
|
49
|
+
start: number;
|
|
50
|
+
/** Highest port the allocator may hand out, inclusive. */
|
|
51
|
+
end: number;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The window the allocator searches.
|
|
55
|
+
*
|
|
56
|
+
* Chosen to contain the template's own defaults (3022/3023) so that an app which
|
|
57
|
+
* has never thought about ports keeps the ports it already had whenever they are
|
|
58
|
+
* free - see {@link allocateSitePorts}, which only moves a site that actually
|
|
59
|
+
* collides.
|
|
60
|
+
*/
|
|
61
|
+
export declare const DEFAULT_SITE_PORT_RANGE: SitePortRange;
|
|
62
|
+
/**
|
|
63
|
+
* One project's registry fragment, as written by the deploy:
|
|
64
|
+
* `JSON.stringify({ slug, ...RpxGatewayConfig })`.
|
|
65
|
+
*
|
|
66
|
+
* Only the fields this module reads are declared. A fragment written by an older
|
|
67
|
+
* ts-cloud may be missing `slug`, which the writer defaults to `'app'`.
|
|
68
|
+
*/
|
|
69
|
+
export interface HostSiteFragment {
|
|
70
|
+
slug?: string;
|
|
71
|
+
proxies?: Array<{
|
|
72
|
+
from?: string | string[];
|
|
73
|
+
}>;
|
|
74
|
+
}
|
|
75
|
+
/** Port -> the slug of the project that already serves it on this box. */
|
|
76
|
+
export type PortOwners = Map<number, string>;
|
|
77
|
+
/**
|
|
78
|
+
* The port from an rpx upstream (`host:port`).
|
|
79
|
+
*
|
|
80
|
+
* Splits on the LAST colon so a bracketed IPv6 literal (`[::1]:3022`) parses as
|
|
81
|
+
* port 3022 rather than as part of the address. Returns `undefined` for anything
|
|
82
|
+
* that is not a valid TCP port, so a malformed fragment narrows the map instead
|
|
83
|
+
* of poisoning it with NaN.
|
|
84
|
+
*/
|
|
85
|
+
export declare function parseUpstreamPort(upstream: string): number | undefined;
|
|
86
|
+
/**
|
|
87
|
+
* Every port the box already serves, mapped to the project that owns it.
|
|
88
|
+
*
|
|
89
|
+
* `ignoreSlug` must be set to the deploying project's own slug. Its fragment is
|
|
90
|
+
* already on the box from the previous deploy, so without that the second deploy
|
|
91
|
+
* of an attached app reports a conflict with itself and can never succeed.
|
|
92
|
+
*
|
|
93
|
+
* First writer wins for a given port, which keeps the result deterministic when
|
|
94
|
+
* two fragments disagree - a state that is itself the bug being reported, so the
|
|
95
|
+
* caller sees one stable owner rather than an order-dependent one.
|
|
96
|
+
*/
|
|
97
|
+
export declare function occupiedHostPorts(fragments: HostSiteFragment[], options?: {
|
|
98
|
+
ignoreSlug?: string;
|
|
99
|
+
}): PortOwners;
|
|
100
|
+
/**
|
|
101
|
+
* A shell snippet that dumps every registry fragment on the box, one
|
|
102
|
+
* base64-encoded JSON document per line.
|
|
103
|
+
*
|
|
104
|
+
* base64 rather than raw `cat`, because the fragments are pretty-printed and so
|
|
105
|
+
* span many lines; encoding makes the output unambiguously one record per line
|
|
106
|
+
* without depending on a JSON tool being installed. Only POSIX utilities plus
|
|
107
|
+
* `base64` are used, both present on the provisioned image - the same reason
|
|
108
|
+
* `resize-remote.ts` enumerates these files with plain `find`.
|
|
109
|
+
*
|
|
110
|
+
* A missing directory is not an error: a box with no fragments yet prints
|
|
111
|
+
* nothing, and {@link parseHostSiteFragments} reads that as "no co-tenants".
|
|
112
|
+
*/
|
|
113
|
+
export declare function buildHostSitePortsScript(sitesDir?: string): string;
|
|
114
|
+
/**
|
|
115
|
+
* Parse the output of {@link buildHostSitePortsScript}.
|
|
116
|
+
*
|
|
117
|
+
* A fragment that will not decode or parse is skipped rather than thrown, which
|
|
118
|
+
* matches how the box's own assembler treats a corrupt fragment: one bad file
|
|
119
|
+
* must not take the operation down. The cost is that its ports are invisible to
|
|
120
|
+
* the collision check, which is strictly better than today, where every
|
|
121
|
+
* project's ports are.
|
|
122
|
+
*/
|
|
123
|
+
export declare function parseHostSiteFragments(stdout: string): HostSiteFragment[];
|
|
124
|
+
export interface SitePortAllocation {
|
|
125
|
+
/** Site name within the deploying project's `sites`. */
|
|
126
|
+
site: string;
|
|
127
|
+
/** The port the site should bind after allocation. */
|
|
128
|
+
port: number;
|
|
129
|
+
/** What the config asked for, when it asked for anything. */
|
|
130
|
+
declared?: number;
|
|
131
|
+
/** Did the allocation have to move the site off its declared port? */
|
|
132
|
+
moved: boolean;
|
|
133
|
+
}
|
|
134
|
+
export interface SitePortAllocationResult {
|
|
135
|
+
allocations: SitePortAllocation[];
|
|
136
|
+
errors: string[];
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Assign a free port to every server-app site, preferring the one it declared.
|
|
140
|
+
*
|
|
141
|
+
* The declared port is kept whenever it is free, so allocation is a no-op on a
|
|
142
|
+
* box with no co-tenants and an app's ports stay stable across deploys. A site
|
|
143
|
+
* whose port is taken walks upward to the next free one, which keeps the result
|
|
144
|
+
* deterministic and close to what the author wrote - a template app landing on
|
|
145
|
+
* 3024 rather than an arbitrary high port.
|
|
146
|
+
*
|
|
147
|
+
* Only `server-app` sites are considered. A bucket, static, redirect or proxy
|
|
148
|
+
* site binds nothing, and `validateDeploymentConfig` already warns when one of
|
|
149
|
+
* those declares a port.
|
|
150
|
+
*/
|
|
151
|
+
export declare function allocateSitePorts(config: CloudConfig, occupied: ReadonlyMap<number, string>, range?: SitePortRange): SitePortAllocationResult;
|
|
@@ -72,6 +72,29 @@ export interface DeploymentValidationResult {
|
|
|
72
72
|
errors: string[];
|
|
73
73
|
warnings: string[];
|
|
74
74
|
}
|
|
75
|
+
export interface ValidateDeploymentOptions {
|
|
76
|
+
/**
|
|
77
|
+
* Ports this box already serves for OTHER projects, as port -> owning slug.
|
|
78
|
+
*
|
|
79
|
+
* Validation is otherwise blind to co-tenants: it only ever sees one project's
|
|
80
|
+
* `sites`, so two apps attached to the same server can both declare the
|
|
81
|
+
* template's default port and both pass. The box does not reject the second
|
|
82
|
+
* one either - ts-cloud's units do not set exclusive binding, so both bind and
|
|
83
|
+
* the kernel load-balances, leaving each domain serving the other project's
|
|
84
|
+
* site about half the time with nothing logged as an error. Supplying this
|
|
85
|
+
* turns that into a plan-time error naming the project holding the port.
|
|
86
|
+
*
|
|
87
|
+
* Build it with `occupiedHostPorts()` from `./site-ports`, passing the
|
|
88
|
+
* deploying project's own slug as `ignoreSlug` - its fragment is already on the
|
|
89
|
+
* box from the last deploy, and counting it would make every redeploy conflict
|
|
90
|
+
* with itself.
|
|
91
|
+
*
|
|
92
|
+
* Omitted means "no co-tenant information", which validates exactly as before.
|
|
93
|
+
*
|
|
94
|
+
* @see https://github.com/stacksjs/ts-cloud/issues/168
|
|
95
|
+
*/
|
|
96
|
+
occupiedPorts?: ReadonlyMap<number, string>;
|
|
97
|
+
}
|
|
75
98
|
/**
|
|
76
99
|
* Validate the per-site deployment configuration up front, turning what used to
|
|
77
100
|
* be silent runtime failures (e.g. a `start` site with no compute server) into
|
|
@@ -80,7 +103,7 @@ export interface DeploymentValidationResult {
|
|
|
80
103
|
* Never throws — returns structured `{ errors, warnings }`. Callers should abort
|
|
81
104
|
* on any error and print warnings while continuing.
|
|
82
105
|
*/
|
|
83
|
-
export declare function validateDeploymentConfig(config: CloudConfig): DeploymentValidationResult;
|
|
106
|
+
export declare function validateDeploymentConfig(config: CloudConfig, options?: ValidateDeploymentOptions): DeploymentValidationResult;
|
|
84
107
|
/**
|
|
85
108
|
* Does this site produce a release the compute deploy has to build, package and
|
|
86
109
|
* ship?
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Publish the records a deploy cannot infer: mail, verification tokens,
|
|
3
|
+
* third-party CNAMEs — everything in `infrastructure.dns.records`.
|
|
4
|
+
*
|
|
5
|
+
* The address records for `sites` are derived from the deploy itself and live in
|
|
6
|
+
* {@link import('../deploy/server-dns')}. This module covers the other half of a
|
|
7
|
+
* zone, which is precisely the half that silently disappears in a nameserver
|
|
8
|
+
* migration: nothing in a normal deploy reads or writes MX or SPF, so their
|
|
9
|
+
* absence is invisible until someone reports that mail stopped days later.
|
|
10
|
+
*
|
|
11
|
+
* The whole module is upsert-only. A real zone holds records owned by other
|
|
12
|
+
* tools and other people, so "not declared here" never implies "safe to
|
|
13
|
+
* delete". The single deliberate exception is a policy TXT record — see
|
|
14
|
+
* {@link policyTag}.
|
|
15
|
+
*/
|
|
16
|
+
import type { DnsProvider, DnsRecordType } from './types';
|
|
17
|
+
/** A record to publish, already resolved to a fully-qualified name. */
|
|
18
|
+
export interface DeclaredRecord {
|
|
19
|
+
type: DnsRecordType;
|
|
20
|
+
/** Fully-qualified record name. */
|
|
21
|
+
name: string;
|
|
22
|
+
content: string;
|
|
23
|
+
ttl?: number;
|
|
24
|
+
priority?: number;
|
|
25
|
+
proxied?: boolean;
|
|
26
|
+
comment?: string;
|
|
27
|
+
}
|
|
28
|
+
/** The config shape, before names are qualified against the zone. */
|
|
29
|
+
export interface DeclaredRecordInput {
|
|
30
|
+
type: DnsRecordType;
|
|
31
|
+
name?: string;
|
|
32
|
+
content: string;
|
|
33
|
+
ttl?: number;
|
|
34
|
+
priority?: number;
|
|
35
|
+
proxied?: boolean;
|
|
36
|
+
comment?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The policy tag opening a TXT record whose duplicates are harmful, or
|
|
40
|
+
* `undefined` for an ordinary TXT.
|
|
41
|
+
*
|
|
42
|
+
* This is the one case where publishing a second record is not additive but
|
|
43
|
+
* destructive. Two `v=spf1` records at a name are a permerror: receivers do not
|
|
44
|
+
* merge them, they conclude the domain has no usable SPF, and mail that would
|
|
45
|
+
* have passed starts failing. Two `v=DMARC1` records are discarded wholesale,
|
|
46
|
+
* silently disabling the policy. So a policy record must REPLACE its
|
|
47
|
+
* predecessor, while every other TXT at that name is left alone.
|
|
48
|
+
*/
|
|
49
|
+
export declare function policyTag(content: string): string | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* Qualify a configured record name against the zone.
|
|
52
|
+
*
|
|
53
|
+
* `'@'`, `''` and an omitted name all mean the apex; a bare label is joined to
|
|
54
|
+
* the zone; an already-qualified name is left alone.
|
|
55
|
+
*/
|
|
56
|
+
export declare function qualifyName(name: string | undefined, zone: string): string;
|
|
57
|
+
/** Resolve config records into fully-qualified {@link DeclaredRecord}s. */
|
|
58
|
+
export declare function resolveDeclaredRecords(records: DeclaredRecordInput[], zone: string): DeclaredRecord[];
|
|
59
|
+
/** What the reconcile did with one record. */
|
|
60
|
+
export interface DeclaredRecordOutcome {
|
|
61
|
+
record: DeclaredRecord;
|
|
62
|
+
action: 'created' | 'updated' | 'unchanged' | 'failed';
|
|
63
|
+
message?: string;
|
|
64
|
+
}
|
|
65
|
+
export interface DeclaredRecordsReport {
|
|
66
|
+
outcomes: DeclaredRecordOutcome[];
|
|
67
|
+
/**
|
|
68
|
+
* Undeclared values sitting beside a declared multi-value record — a second
|
|
69
|
+
* MX from a previous provider, say. Reported and never removed: a stray MX
|
|
70
|
+
* splits mail delivery and the operator must see it, but silently deleting a
|
|
71
|
+
* record on a shared zone is the worse failure.
|
|
72
|
+
*/
|
|
73
|
+
warnings: string[];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Publish `records` into `zone`, updating what exists and creating what does
|
|
77
|
+
* not.
|
|
78
|
+
*
|
|
79
|
+
* Never throws: this runs at the tail of a deploy that has already shipped, so a
|
|
80
|
+
* provider rejecting one record is reported per-record rather than failing the
|
|
81
|
+
* whole run — and the outcome list says exactly which ones landed.
|
|
82
|
+
*/
|
|
83
|
+
export declare function reconcileDeclaredRecords(options: {
|
|
84
|
+
provider: DnsProvider;
|
|
85
|
+
zone: string;
|
|
86
|
+
records: DeclaredRecord[];
|
|
87
|
+
}): Promise<DeclaredRecordsReport>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/dns/index.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export * from './types';
|
|
|
6
6
|
export { PorkbunProvider } from './porkbun';
|
|
7
7
|
export { GoDaddyProvider } from './godaddy';
|
|
8
8
|
export { CloudflareProvider } from './cloudflare';
|
|
9
|
+
export type { DeclaredRecord, DeclaredRecordInput, DeclaredRecordOutcome, DeclaredRecordsReport, } from './declared-records';
|
|
10
|
+
export { policyTag, qualifyName, reconcileDeclaredRecords, resolveDeclaredRecords, } from './declared-records';
|
|
9
11
|
export { Route53Provider } from './route53-adapter';
|
|
10
12
|
export { UnifiedDnsValidator, createPorkbunValidator, createGoDaddyValidator, createRoute53Validator, } from './validator';
|
|
11
13
|
import type { DnsProvider, DnsProviderConfig } from './types';
|
package/dist/dns/index.js
CHANGED
|
@@ -11,12 +11,20 @@ import {
|
|
|
11
11
|
createPorkbunValidator,
|
|
12
12
|
createRoute53Validator,
|
|
13
13
|
detectDnsProvider,
|
|
14
|
-
dnsProviders
|
|
15
|
-
|
|
14
|
+
dnsProviders,
|
|
15
|
+
policyTag,
|
|
16
|
+
qualifyName,
|
|
17
|
+
reconcileDeclaredRecords,
|
|
18
|
+
resolveDeclaredRecords
|
|
19
|
+
} from "../chunk-qr803fye.js";
|
|
16
20
|
import"../chunk-32e7ya18.js";
|
|
17
21
|
import"../chunk-zqtpg06c.js";
|
|
18
22
|
import"../chunk-v0bahtg2.js";
|
|
19
23
|
export {
|
|
24
|
+
resolveDeclaredRecords,
|
|
25
|
+
reconcileDeclaredRecords,
|
|
26
|
+
qualifyName,
|
|
27
|
+
policyTag,
|
|
20
28
|
dnsProviders,
|
|
21
29
|
detectDnsProvider,
|
|
22
30
|
createRoute53Validator,
|
package/dist/drivers/index.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -41,7 +41,7 @@ export { createCloudDriver, CloudDriverFactory, cloudDrivers, AwsDriver, Hetzner
|
|
|
41
41
|
export type { CreateCloudDriverOptions } from './drivers/factory';
|
|
42
42
|
export { dashboardActions, resolveDashboardAction, sanitizeCloudConfig, startLocalDashboardServer, } from './deploy/local-dashboard-server';
|
|
43
43
|
export type { DashboardAction, LocalDashboardServer, LocalDashboardServerOptions, } from './deploy/local-dashboard-server';
|
|
44
|
-
export { createDnsProvider, detectDnsProvider, DnsProviderFactory, dnsProviders, PorkbunProvider, GoDaddyProvider, Route53Provider, CloudflareProvider, UnifiedDnsValidator, createPorkbunValidator, createGoDaddyValidator, createRoute53Validator, } from './dns';
|
|
44
|
+
export { createDnsProvider, detectDnsProvider, DnsProviderFactory, dnsProviders, PorkbunProvider, GoDaddyProvider, Route53Provider, CloudflareProvider, policyTag, qualifyName, reconcileDeclaredRecords, resolveDeclaredRecords, UnifiedDnsValidator, createPorkbunValidator, createGoDaddyValidator, createRoute53Validator, } from './dns';
|
|
45
45
|
export type { CloudflareProviderOptions, CloudflareRule, CloudflareRulesetPhase, CloudflareZoneSetting, } from './dns/cloudflare';
|
|
46
46
|
export { CLOUDFLARE_MANAGED_RULE_PREFIX } from './dns/cloudflare';
|
|
47
47
|
export * from './source';
|
|
@@ -50,5 +50,6 @@ export * from './backups';
|
|
|
50
50
|
export * from './configuration';
|
|
51
51
|
export type { DnsProvider, DnsProviderConfig, DnsRecord, DnsRecordType, DnsRecordResult, CreateRecordResult, DeleteRecordResult, ListRecordsResult, } from './dns';
|
|
52
52
|
export { PROXIABLE_RECORD_TYPES } from './dns';
|
|
53
|
+
export type { DeclaredRecord, DeclaredRecordInput, DeclaredRecordOutcome, DeclaredRecordsReport, } from './dns';
|
|
53
54
|
export * from '@ts-cloud/core';
|
|
54
55
|
export type { S3Bucket, S3BucketPolicy, CloudFrontDistribution, CloudFrontOriginAccessControl, CloudFrontCacheBehavior, CloudFrontOrigin, } from '@ts-cloud/aws-types';
|