@kensio/yulin 1.20.9 → 1.20.10
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/serve/controller/host/sim-aws-service-hosts.d.ts +4 -0
- package/dist/serve/controller/host/sim-aws-service-hosts.js +4 -0
- package/dist/service/apigatewayv2/domain/sim-http-api-domain-endpoint.d.ts +59 -0
- package/dist/service/apigatewayv2/domain/sim-http-api-domain-endpoint.js +67 -0
- package/dist/service/apigatewayv2/domain/sim-http-api-domain-name.d.ts +42 -10
- package/dist/service/apigatewayv2/domain/sim-http-api-domain-name.js +57 -13
- package/dist/service/apigatewayv2/registry/sim-http-api-domain-registry.d.ts +7 -1
- package/dist/service/apigatewayv2/registry/sim-http-api-domain-registry.js +15 -3
- package/dist/service/apigatewayv2/serve/sim-http-api-serving.js +3 -1
- package/dist/service/aws/factory/sim-aws-account-service-cache.d.ts +2 -0
- package/dist/service/aws/factory/sim-aws-account-service-cache.js +3 -0
- package/dist/service/aws/factory/sim-aws-scoped-service-registries.d.ts +7 -0
- package/dist/service/aws/factory/sim-aws-scoped-service-registries.js +9 -2
- package/dist/service/aws/factory/sim-aws-service-factory.js +3 -1
- package/dist/service/cloudformation/resource/cfn/apigatewayv2/sim-http-api-domain-name-cfn.d.ts +4 -4
- package/dist/service/cloudformation/resource/cfn/apigatewayv2/sim-http-api-domain-name-cfn.js +4 -4
- package/dist/service/route53/resolve/sim-r53-service-target-resolver.d.ts +12 -0
- package/dist/service/route53/resolve/sim-r53-service-target-resolver.js +24 -0
- package/dist/service/route53/resolve/sim-route53-resolver.d.ts +9 -1
- package/dist/service/route53/resolve/sim-route53-resolver.js +10 -2
- package/dist/service/route53/sim-route53.d.ts +6 -0
- package/dist/service/route53/sim-route53.js +1 -0
- package/dist/service/s3/mount/sim-s3-mount.type.d.ts +1 -1
- package/dist/service/s3/storage/filesystem/s3-filesystem-allowed.js +1 -0
- package/dist/service/s3/storage/filesystem/s3-filesystem-object-metadata.js +1 -0
- package/package.json +1 -1
|
@@ -32,6 +32,10 @@ export declare class SimAwsNoServiceHosts implements SimAwsServiceHosts {
|
|
|
32
32
|
* project picked rather than names AWS generated. Resolution asks one thing
|
|
33
33
|
* about a hostname, so the holders are gathered here rather than each being
|
|
34
34
|
* threaded separately through it.
|
|
35
|
+
*
|
|
36
|
+
* Resolution asks twice. A hosted-zone record outranks some claims and leaves
|
|
37
|
+
* others alone, and which of these a holder is gathered into is what says when
|
|
38
|
+
* the hostnames it holds are answered for.
|
|
35
39
|
*/
|
|
36
40
|
export declare class SimAwsAnyServiceHosts implements SimAwsServiceHosts {
|
|
37
41
|
private readonly holders;
|
|
@@ -18,6 +18,10 @@ export class SimAwsNoServiceHosts {
|
|
|
18
18
|
* project picked rather than names AWS generated. Resolution asks one thing
|
|
19
19
|
* about a hostname, so the holders are gathered here rather than each being
|
|
20
20
|
* threaded separately through it.
|
|
21
|
+
*
|
|
22
|
+
* Resolution asks twice. A hosted-zone record outranks some claims and leaves
|
|
23
|
+
* others alone, and which of these a holder is gathered into is what says when
|
|
24
|
+
* the hostnames it holds are answered for.
|
|
21
25
|
*/
|
|
22
26
|
export class SimAwsAnyServiceHosts {
|
|
23
27
|
holders;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Brand } from "../../../util/brand.type.js";
|
|
2
|
+
/**
|
|
3
|
+
* The id API Gateway allocates for the regional endpoint of one custom domain,
|
|
4
|
+
* which is the leading DNS label of that endpoint's hostname.
|
|
5
|
+
*/
|
|
6
|
+
export type SimHttpApiDomainId = Brand<string, "SimHttpApiDomainId">;
|
|
7
|
+
/**
|
|
8
|
+
* What a custom domain's regional endpoint hostname is built from.
|
|
9
|
+
*/
|
|
10
|
+
export interface SimHttpApiDomainEndpointParts {
|
|
11
|
+
readonly domainId: SimHttpApiDomainId;
|
|
12
|
+
readonly regionName: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Allocate a domain endpoint id in the shape real API Gateway uses: `d-`
|
|
16
|
+
* followed by 10 lowercase alphanumeric characters, forming one DNS label.
|
|
17
|
+
*/
|
|
18
|
+
export declare function makeSimHttpApiDomainId(): SimHttpApiDomainId;
|
|
19
|
+
/**
|
|
20
|
+
* Whether a DNS label is a custom domain endpoint id rather than an API id.
|
|
21
|
+
*
|
|
22
|
+
* A custom domain and an API are issued endpoints of the same shape, so this
|
|
23
|
+
* is what decides which of the two a hostname names. API ids carry no hyphen,
|
|
24
|
+
* which is what leaves the prefix free to say it.
|
|
25
|
+
*/
|
|
26
|
+
export declare function isSimHttpApiDomainId(label: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Build the real AWS endpoint hostname for a custom domain, which is what
|
|
29
|
+
* `RegionalDomainName` answers with and what a record for the custom domain
|
|
30
|
+
* name points at.
|
|
31
|
+
*/
|
|
32
|
+
export declare function simHttpApiDomainEndpointHost(parts: SimHttpApiDomainEndpointParts): string;
|
|
33
|
+
/**
|
|
34
|
+
* Build the logical hostname for a custom domain endpoint: the AWS endpoint
|
|
35
|
+
* hostname without the real AWS domain, which is the form Yulin serves on
|
|
36
|
+
* localhost.
|
|
37
|
+
*/
|
|
38
|
+
export declare function simHttpApiDomainEndpointLogicalHost(parts: SimHttpApiDomainEndpointParts): string;
|
|
39
|
+
/**
|
|
40
|
+
* A custom domain's regional endpoint hostname, as it was read.
|
|
41
|
+
*/
|
|
42
|
+
export interface SimHttpApiDomainEndpointHost {
|
|
43
|
+
/**
|
|
44
|
+
* The hostname without the AWS domain, which is the name simulated DNS
|
|
45
|
+
* resolves and the domain registry holds.
|
|
46
|
+
*/
|
|
47
|
+
readonly logicalHost: string;
|
|
48
|
+
readonly regionName: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Read a custom domain's regional endpoint hostname, in either the form real
|
|
52
|
+
* API Gateway reports it or the local form the AWS domain is dropped from.
|
|
53
|
+
*
|
|
54
|
+
* Both forms are read here because a request arriving over HTTP has had the
|
|
55
|
+
* AWS domain rewritten away and a record value written as `RegionalDomainName`
|
|
56
|
+
* answered has not, and a record pointing the custom domain name at the
|
|
57
|
+
* endpoint is how the domain is reached on AWS.
|
|
58
|
+
*/
|
|
59
|
+
export declare function readSimHttpApiDomainEndpointHost(hostname: string): SimHttpApiDomainEndpointHost | undefined;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { faker } from "@faker-js/faker";
|
|
2
|
+
import { executeApiDomain, executeApiHostLabel, } from "../api/sim-http-api-host.js";
|
|
3
|
+
/**
|
|
4
|
+
* The first character of the id API Gateway allocates a custom domain, which
|
|
5
|
+
* is what tells its endpoint hostname apart from the one an API gets.
|
|
6
|
+
*/
|
|
7
|
+
const domainIdPrefix = "d-";
|
|
8
|
+
/**
|
|
9
|
+
* Allocate a domain endpoint id in the shape real API Gateway uses: `d-`
|
|
10
|
+
* followed by 10 lowercase alphanumeric characters, forming one DNS label.
|
|
11
|
+
*/
|
|
12
|
+
export function makeSimHttpApiDomainId() {
|
|
13
|
+
return `${domainIdPrefix}${faker.helpers.fromRegExp(/[a-z0-9]{10}/)}`;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Whether a DNS label is a custom domain endpoint id rather than an API id.
|
|
17
|
+
*
|
|
18
|
+
* A custom domain and an API are issued endpoints of the same shape, so this
|
|
19
|
+
* is what decides which of the two a hostname names. API ids carry no hyphen,
|
|
20
|
+
* which is what leaves the prefix free to say it.
|
|
21
|
+
*/
|
|
22
|
+
export function isSimHttpApiDomainId(label) {
|
|
23
|
+
return label.startsWith(domainIdPrefix);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Build the real AWS endpoint hostname for a custom domain, which is what
|
|
27
|
+
* `RegionalDomainName` answers with and what a record for the custom domain
|
|
28
|
+
* name points at.
|
|
29
|
+
*/
|
|
30
|
+
export function simHttpApiDomainEndpointHost(parts) {
|
|
31
|
+
return `${simHttpApiDomainEndpointLogicalHost(parts)}.${executeApiDomain}`;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Build the logical hostname for a custom domain endpoint: the AWS endpoint
|
|
35
|
+
* hostname without the real AWS domain, which is the form Yulin serves on
|
|
36
|
+
* localhost.
|
|
37
|
+
*/
|
|
38
|
+
export function simHttpApiDomainEndpointLogicalHost(parts) {
|
|
39
|
+
return `${parts.domainId}.${executeApiHostLabel}.${parts.regionName}`;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Read a custom domain's regional endpoint hostname, in either the form real
|
|
43
|
+
* API Gateway reports it or the local form the AWS domain is dropped from.
|
|
44
|
+
*
|
|
45
|
+
* Both forms are read here because a request arriving over HTTP has had the
|
|
46
|
+
* AWS domain rewritten away and a record value written as `RegionalDomainName`
|
|
47
|
+
* answered has not, and a record pointing the custom domain name at the
|
|
48
|
+
* endpoint is how the domain is reached on AWS.
|
|
49
|
+
*/
|
|
50
|
+
export function readSimHttpApiDomainEndpointHost(hostname) {
|
|
51
|
+
const awsDomainSuffix = `.${executeApiDomain}`;
|
|
52
|
+
const logicalHost = hostname.endsWith(awsDomainSuffix)
|
|
53
|
+
? hostname.slice(0, -awsDomainSuffix.length)
|
|
54
|
+
: hostname;
|
|
55
|
+
const labels = logicalHost.split(".");
|
|
56
|
+
if (labels.length !== 3) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
const [domainId, service, regionName] = labels;
|
|
60
|
+
if (domainId === undefined ||
|
|
61
|
+
regionName === undefined ||
|
|
62
|
+
service !== executeApiHostLabel ||
|
|
63
|
+
!isSimHttpApiDomainId(domainId)) {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
return { logicalHost, regionName };
|
|
67
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SimAwsAccountRegionScope } from "../../aws/sim-aws-account-region-scope.js";
|
|
2
|
+
import { type SimHttpApiDomainId } from "./sim-http-api-domain-endpoint.js";
|
|
2
3
|
import { SimApiMappingStore } from "./sim-api-mapping-store.js";
|
|
3
4
|
/**
|
|
4
5
|
* The expression API Gateway selects an API mapping with, which is the request
|
|
@@ -12,7 +13,7 @@ export declare const simApiMappingSelectionExpression = "$request.basepath";
|
|
|
12
13
|
* Real API Gateway publishes a different id per Region. One fixed value stands
|
|
13
14
|
* for all of them here, the way `simElbV2CanonicalHostedZoneId` does for a
|
|
14
15
|
* load balancer: nothing resolves through it, and an alias record reaches the
|
|
15
|
-
* domain by the name it points at.
|
|
16
|
+
* domain by the regional endpoint name it points at.
|
|
16
17
|
*/
|
|
17
18
|
export declare const simHttpApiRegionalHostedZoneId = "Z0000000000001";
|
|
18
19
|
/**
|
|
@@ -29,13 +30,21 @@ export interface SimHttpApiDomainNameConfiguration {
|
|
|
29
30
|
EndpointType?: string | undefined;
|
|
30
31
|
SecurityPolicy?: string | undefined;
|
|
31
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* One entry of a domain's `DomainNameConfigurations` as a command reports it,
|
|
35
|
+
* which is what was written plus the endpoint API Gateway made for it.
|
|
36
|
+
*/
|
|
37
|
+
export interface SimHttpApiDomainNameConfigurationView extends SimHttpApiDomainNameConfiguration {
|
|
38
|
+
ApiGatewayDomainName: string;
|
|
39
|
+
HostedZoneId: string;
|
|
40
|
+
}
|
|
32
41
|
/**
|
|
33
42
|
* Minimal structural domain name view, as the Create and Get commands return.
|
|
34
43
|
*/
|
|
35
44
|
export interface SimHttpApiDomainNameView {
|
|
36
45
|
DomainName: string;
|
|
37
46
|
ApiMappingSelectionExpression: string;
|
|
38
|
-
DomainNameConfigurations: readonly
|
|
47
|
+
DomainNameConfigurations: readonly SimHttpApiDomainNameConfigurationView[];
|
|
39
48
|
}
|
|
40
49
|
interface SimHttpApiDomainNameProperties {
|
|
41
50
|
readonly domainName: string;
|
|
@@ -45,9 +54,11 @@ interface SimHttpApiDomainNameProperties {
|
|
|
45
54
|
/**
|
|
46
55
|
* A simulated API Gateway custom domain name.
|
|
47
56
|
*
|
|
48
|
-
* The domain
|
|
49
|
-
*
|
|
50
|
-
*
|
|
57
|
+
* The domain has the two names real API Gateway gives it. One is the hostname
|
|
58
|
+
* the project owns, which is how an HTTP API is reached under a name of its
|
|
59
|
+
* own. The other is the regional endpoint API Gateway issues alongside it,
|
|
60
|
+
* which a record for the custom domain name points at. The domain answers on
|
|
61
|
+
* both. It owns its API mappings, because a mapping is addressed by domain on
|
|
51
62
|
* real AWS and none of them outlives the domain.
|
|
52
63
|
*
|
|
53
64
|
* A domain and the APIs it maps live in one Account and Region, as they do on
|
|
@@ -58,6 +69,10 @@ export declare class SimHttpApiDomainName {
|
|
|
58
69
|
readonly accountRegionScope: SimAwsAccountRegionScope;
|
|
59
70
|
readonly configurations: readonly SimHttpApiDomainNameConfiguration[];
|
|
60
71
|
readonly apiMappings: SimApiMappingStore;
|
|
72
|
+
/**
|
|
73
|
+
* The id API Gateway allocated this domain's regional endpoint.
|
|
74
|
+
*/
|
|
75
|
+
readonly domainId: SimHttpApiDomainId;
|
|
61
76
|
constructor(properties: SimHttpApiDomainNameProperties);
|
|
62
77
|
/**
|
|
63
78
|
* The hostname this domain answers requests on.
|
|
@@ -67,13 +82,17 @@ export declare class SimHttpApiDomainName {
|
|
|
67
82
|
* The hostname a DNS record pointing at this domain names, which is what
|
|
68
83
|
* `Fn::GetAtt RegionalDomainName` answers with.
|
|
69
84
|
*
|
|
70
|
-
*
|
|
71
|
-
* and
|
|
72
|
-
*
|
|
73
|
-
* alias built on it reaches the domain. An `execute-api` name would be read
|
|
74
|
-
* as a generated API endpoint by simulated DNS and route to no API at all.
|
|
85
|
+
* This is the domain's published address. A CloudFront Origin points at it
|
|
86
|
+
* directly, and a record for the custom domain name points at it. The custom
|
|
87
|
+
* domain name is reached through that record.
|
|
75
88
|
*/
|
|
76
89
|
get regionalDomainName(): string;
|
|
90
|
+
/**
|
|
91
|
+
* The hostnames a request can reach this domain by. They are the custom
|
|
92
|
+
* domain name and the regional endpoint, the second without the AWS domain
|
|
93
|
+
* the local URL rewriting drops.
|
|
94
|
+
*/
|
|
95
|
+
get hostnames(): readonly string[];
|
|
77
96
|
/**
|
|
78
97
|
* The ARN of this domain, which `Fn::GetAtt DomainNameArn` answers with.
|
|
79
98
|
*
|
|
@@ -86,5 +105,18 @@ export declare class SimHttpApiDomainName {
|
|
|
86
105
|
* Get the AWS-like view of this domain name.
|
|
87
106
|
*/
|
|
88
107
|
view(): SimHttpApiDomainNameView;
|
|
108
|
+
/**
|
|
109
|
+
* What this domain's regional endpoint hostname is built from.
|
|
110
|
+
*/
|
|
111
|
+
private get endpointParts();
|
|
112
|
+
/**
|
|
113
|
+
* The domain's configurations as a command reports them.
|
|
114
|
+
*
|
|
115
|
+
* Each one is what was written plus the endpoint API Gateway made for it. A
|
|
116
|
+
* domain created without a configuration still reports one, because the
|
|
117
|
+
* endpoint exists whether or not anything was written about the certificate
|
|
118
|
+
* in front of it, and real API Gateway reports it there.
|
|
119
|
+
*/
|
|
120
|
+
private configurationViews;
|
|
89
121
|
}
|
|
90
122
|
export {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { makeSimHttpApiDomainId, simHttpApiDomainEndpointHost, simHttpApiDomainEndpointLogicalHost, } from "./sim-http-api-domain-endpoint.js";
|
|
1
2
|
import { SimApiMappingStore } from "./sim-api-mapping-store.js";
|
|
2
3
|
/**
|
|
3
4
|
* The expression API Gateway selects an API mapping with, which is the request
|
|
@@ -11,15 +12,17 @@ export const simApiMappingSelectionExpression = "$request.basepath";
|
|
|
11
12
|
* Real API Gateway publishes a different id per Region. One fixed value stands
|
|
12
13
|
* for all of them here, the way `simElbV2CanonicalHostedZoneId` does for a
|
|
13
14
|
* load balancer: nothing resolves through it, and an alias record reaches the
|
|
14
|
-
* domain by the name it points at.
|
|
15
|
+
* domain by the regional endpoint name it points at.
|
|
15
16
|
*/
|
|
16
17
|
export const simHttpApiRegionalHostedZoneId = "Z0000000000001";
|
|
17
18
|
/**
|
|
18
19
|
* A simulated API Gateway custom domain name.
|
|
19
20
|
*
|
|
20
|
-
* The domain
|
|
21
|
-
*
|
|
22
|
-
*
|
|
21
|
+
* The domain has the two names real API Gateway gives it. One is the hostname
|
|
22
|
+
* the project owns, which is how an HTTP API is reached under a name of its
|
|
23
|
+
* own. The other is the regional endpoint API Gateway issues alongside it,
|
|
24
|
+
* which a record for the custom domain name points at. The domain answers on
|
|
25
|
+
* both. It owns its API mappings, because a mapping is addressed by domain on
|
|
23
26
|
* real AWS and none of them outlives the domain.
|
|
24
27
|
*
|
|
25
28
|
* A domain and the APIs it maps live in one Account and Region, as they do on
|
|
@@ -30,6 +33,10 @@ export class SimHttpApiDomainName {
|
|
|
30
33
|
accountRegionScope;
|
|
31
34
|
configurations;
|
|
32
35
|
apiMappings = new SimApiMappingStore();
|
|
36
|
+
/**
|
|
37
|
+
* The id API Gateway allocated this domain's regional endpoint.
|
|
38
|
+
*/
|
|
39
|
+
domainId = makeSimHttpApiDomainId();
|
|
33
40
|
constructor(properties) {
|
|
34
41
|
this.domainName = properties.domainName;
|
|
35
42
|
this.accountRegionScope = properties.accountRegionScope;
|
|
@@ -45,14 +52,23 @@ export class SimHttpApiDomainName {
|
|
|
45
52
|
* The hostname a DNS record pointing at this domain names, which is what
|
|
46
53
|
* `Fn::GetAtt RegionalDomainName` answers with.
|
|
47
54
|
*
|
|
48
|
-
*
|
|
49
|
-
* and
|
|
50
|
-
*
|
|
51
|
-
* alias built on it reaches the domain. An `execute-api` name would be read
|
|
52
|
-
* as a generated API endpoint by simulated DNS and route to no API at all.
|
|
55
|
+
* This is the domain's published address. A CloudFront Origin points at it
|
|
56
|
+
* directly, and a record for the custom domain name points at it. The custom
|
|
57
|
+
* domain name is reached through that record.
|
|
53
58
|
*/
|
|
54
59
|
get regionalDomainName() {
|
|
55
|
-
return this.
|
|
60
|
+
return simHttpApiDomainEndpointHost(this.endpointParts);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The hostnames a request can reach this domain by. They are the custom
|
|
64
|
+
* domain name and the regional endpoint, the second without the AWS domain
|
|
65
|
+
* the local URL rewriting drops.
|
|
66
|
+
*/
|
|
67
|
+
get hostnames() {
|
|
68
|
+
return [
|
|
69
|
+
this.hostname,
|
|
70
|
+
simHttpApiDomainEndpointLogicalHost(this.endpointParts),
|
|
71
|
+
];
|
|
56
72
|
}
|
|
57
73
|
/**
|
|
58
74
|
* The ARN of this domain, which `Fn::GetAtt DomainNameArn` answers with.
|
|
@@ -71,9 +87,37 @@ export class SimHttpApiDomainName {
|
|
|
71
87
|
return {
|
|
72
88
|
DomainName: this.domainName,
|
|
73
89
|
ApiMappingSelectionExpression: simApiMappingSelectionExpression,
|
|
74
|
-
DomainNameConfigurations: this.
|
|
75
|
-
|
|
76
|
-
|
|
90
|
+
DomainNameConfigurations: this.configurationViews(),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* What this domain's regional endpoint hostname is built from.
|
|
95
|
+
*/
|
|
96
|
+
get endpointParts() {
|
|
97
|
+
return {
|
|
98
|
+
domainId: this.domainId,
|
|
99
|
+
regionName: this.accountRegionScope.regionName,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* The domain's configurations as a command reports them.
|
|
104
|
+
*
|
|
105
|
+
* Each one is what was written plus the endpoint API Gateway made for it. A
|
|
106
|
+
* domain created without a configuration still reports one, because the
|
|
107
|
+
* endpoint exists whether or not anything was written about the certificate
|
|
108
|
+
* in front of it, and real API Gateway reports it there.
|
|
109
|
+
*/
|
|
110
|
+
configurationViews() {
|
|
111
|
+
const endpoint = {
|
|
112
|
+
ApiGatewayDomainName: this.regionalDomainName,
|
|
113
|
+
HostedZoneId: simHttpApiRegionalHostedZoneId,
|
|
77
114
|
};
|
|
115
|
+
if (this.configurations.length === 0) {
|
|
116
|
+
return [endpoint];
|
|
117
|
+
}
|
|
118
|
+
return this.configurations.map((configuration) => ({
|
|
119
|
+
...configuration,
|
|
120
|
+
...endpoint,
|
|
121
|
+
}));
|
|
78
122
|
}
|
|
79
123
|
}
|
|
@@ -14,6 +14,11 @@ import type { SimHttpApiDomainName } from "../domain/sim-http-api-domain-name.js
|
|
|
14
14
|
* and nothing saying it is an API Gateway hostname at all. That makes this the
|
|
15
15
|
* answer to which simulated service a hostname belongs to, which is what
|
|
16
16
|
* `SimAwsServiceHosts` asks.
|
|
17
|
+
*
|
|
18
|
+
* Simulated DNS asks a hosted-zone record about a custom domain name first,
|
|
19
|
+
* the way the custom domain name reaches the domain through a record on AWS.
|
|
20
|
+
* This answers where no record names the hostname. That is how a test that
|
|
21
|
+
* creates only a domain reaches it.
|
|
17
22
|
*/
|
|
18
23
|
export declare class SimHttpApiDomainRegistry implements SimAwsServiceHosts {
|
|
19
24
|
private readonly domainsByHost;
|
|
@@ -28,7 +33,8 @@ export declare class SimHttpApiDomainRegistry implements SimAwsServiceHosts {
|
|
|
28
33
|
*/
|
|
29
34
|
deregister(domain: SimHttpApiDomainName): void;
|
|
30
35
|
/**
|
|
31
|
-
* Find the domain a request's hostname reaches
|
|
36
|
+
* Find the domain a request's hostname reaches, by either of the two names
|
|
37
|
+
* the domain answers on.
|
|
32
38
|
*/
|
|
33
39
|
findByHost(hostname: string): SimHttpApiDomainName | undefined;
|
|
34
40
|
/**
|
|
@@ -12,6 +12,11 @@ import { SimApiGatewayV2BadRequest } from "../error/sim-api-gateway-v2.error.js"
|
|
|
12
12
|
* and nothing saying it is an API Gateway hostname at all. That makes this the
|
|
13
13
|
* answer to which simulated service a hostname belongs to, which is what
|
|
14
14
|
* `SimAwsServiceHosts` asks.
|
|
15
|
+
*
|
|
16
|
+
* Simulated DNS asks a hosted-zone record about a custom domain name first,
|
|
17
|
+
* the way the custom domain name reaches the domain through a record on AWS.
|
|
18
|
+
* This answers where no record names the hostname. That is how a test that
|
|
19
|
+
* creates only a domain reaches it.
|
|
15
20
|
*/
|
|
16
21
|
export class SimHttpApiDomainRegistry {
|
|
17
22
|
domainsByHost = new Map();
|
|
@@ -24,18 +29,25 @@ export class SimHttpApiDomainRegistry {
|
|
|
24
29
|
*/
|
|
25
30
|
register(domain) {
|
|
26
31
|
this.requireUnused(domain);
|
|
27
|
-
|
|
32
|
+
for (const hostname of domain.hostnames) {
|
|
33
|
+
this.domainsByHost.set(hostname.toLowerCase(), domain);
|
|
34
|
+
}
|
|
35
|
+
// Only the custom domain name is claimed. The regional endpoint is a name
|
|
36
|
+
// API Gateway made up, and takes no hostname away from another service.
|
|
28
37
|
this.claims.claim(domain.hostname);
|
|
29
38
|
}
|
|
30
39
|
/**
|
|
31
40
|
* Forget a deleted domain, so its hostname stops resolving.
|
|
32
41
|
*/
|
|
33
42
|
deregister(domain) {
|
|
34
|
-
|
|
43
|
+
for (const hostname of domain.hostnames) {
|
|
44
|
+
this.domainsByHost.delete(hostname.toLowerCase());
|
|
45
|
+
}
|
|
35
46
|
this.claims.release(domain.hostname);
|
|
36
47
|
}
|
|
37
48
|
/**
|
|
38
|
-
* Find the domain a request's hostname reaches
|
|
49
|
+
* Find the domain a request's hostname reaches, by either of the two names
|
|
50
|
+
* the domain answers on.
|
|
39
51
|
*/
|
|
40
52
|
findByHost(hostname) {
|
|
41
53
|
return this.domainsByHost.get(hostname.toLowerCase());
|
|
@@ -76,7 +76,9 @@ export class SimHttpApiServingResolver {
|
|
|
76
76
|
*/
|
|
77
77
|
mapped(target, method, path) {
|
|
78
78
|
const domain = this.domains.route(target);
|
|
79
|
-
|
|
79
|
+
// A regional endpoint hostname is recognised by its shape, as a generated
|
|
80
|
+
// API endpoint is, so one naming no domain arrives here and is answered
|
|
81
|
+
// the way a path no mapping claims is.
|
|
80
82
|
if (domain === undefined) {
|
|
81
83
|
return notFound;
|
|
82
84
|
}
|
|
@@ -20,6 +20,7 @@ interface SimAwsAccountServiceCacheProperties {
|
|
|
20
20
|
readonly route53Registry: SimRoute53Registry;
|
|
21
21
|
readonly kmsRegistry: SimKmsRegistry;
|
|
22
22
|
readonly serviceHosts: SimAwsServiceHosts;
|
|
23
|
+
readonly shadowableServiceHosts: SimAwsServiceHosts;
|
|
23
24
|
readonly iamRegistry: SimIamRegistry;
|
|
24
25
|
readonly accessKeyRegistry: SimIamAccessKeyRegistry;
|
|
25
26
|
}
|
|
@@ -54,6 +55,7 @@ export declare class SimAwsAccountServiceCache {
|
|
|
54
55
|
private readonly route53Registry;
|
|
55
56
|
private readonly kmsRegistry;
|
|
56
57
|
private readonly serviceHosts;
|
|
58
|
+
private readonly shadowableServiceHosts;
|
|
57
59
|
/**
|
|
58
60
|
* Shared memo for account-scoped service instances.
|
|
59
61
|
*
|
|
@@ -40,6 +40,7 @@ export class SimAwsAccountServiceCache {
|
|
|
40
40
|
route53Registry;
|
|
41
41
|
kmsRegistry;
|
|
42
42
|
serviceHosts;
|
|
43
|
+
shadowableServiceHosts;
|
|
43
44
|
/**
|
|
44
45
|
* Shared memo for account-scoped service instances.
|
|
45
46
|
*
|
|
@@ -58,6 +59,7 @@ export class SimAwsAccountServiceCache {
|
|
|
58
59
|
this.route53Registry = properties.route53Registry;
|
|
59
60
|
this.kmsRegistry = properties.kmsRegistry;
|
|
60
61
|
this.serviceHosts = properties.serviceHosts;
|
|
62
|
+
this.shadowableServiceHosts = properties.shadowableServiceHosts;
|
|
61
63
|
}
|
|
62
64
|
/**
|
|
63
65
|
* The collaborators every Account/Region scoped service takes.
|
|
@@ -128,6 +130,7 @@ export class SimAwsAccountServiceCache {
|
|
|
128
130
|
background: this.background,
|
|
129
131
|
route53Registry: this.route53Registry,
|
|
130
132
|
serviceHosts: this.serviceHosts,
|
|
133
|
+
shadowableServiceHosts: this.shadowableServiceHosts,
|
|
131
134
|
// A DNSSEC key-signing key names a KMS key by ARN, in whichever
|
|
132
135
|
// Region holds it, so Route53 resolves it through the registry.
|
|
133
136
|
kmsKeys: this.kmsRegistry,
|
|
@@ -94,6 +94,13 @@ export declare class SimAwsScopedServiceRegistries {
|
|
|
94
94
|
* simulated DNS resolution asks after the built-in hostname shapes.
|
|
95
95
|
*/
|
|
96
96
|
readonly serviceHosts: SimAwsServiceHosts;
|
|
97
|
+
/**
|
|
98
|
+
* Where a hostname a hosted-zone record outranks is looked up. An API
|
|
99
|
+
* Gateway custom domain name is reached through a record on AWS, so a record
|
|
100
|
+
* for one decides where the name goes and the domain answers where no record
|
|
101
|
+
* names it.
|
|
102
|
+
*/
|
|
103
|
+
readonly shadowableServiceHosts: SimAwsServiceHosts;
|
|
97
104
|
/**
|
|
98
105
|
* The hostnames the domain registries have handed out. A public hostname is
|
|
99
106
|
* unique across the whole of AWS rather than within one service, so the two
|
|
@@ -95,6 +95,13 @@ export class SimAwsScopedServiceRegistries {
|
|
|
95
95
|
* simulated DNS resolution asks after the built-in hostname shapes.
|
|
96
96
|
*/
|
|
97
97
|
serviceHosts;
|
|
98
|
+
/**
|
|
99
|
+
* Where a hostname a hosted-zone record outranks is looked up. An API
|
|
100
|
+
* Gateway custom domain name is reached through a record on AWS, so a record
|
|
101
|
+
* for one decides where the name goes and the domain answers where no record
|
|
102
|
+
* names it.
|
|
103
|
+
*/
|
|
104
|
+
shadowableServiceHosts;
|
|
98
105
|
/**
|
|
99
106
|
* The hostnames the domain registries have handed out. A public hostname is
|
|
100
107
|
* unique across the whole of AWS rather than within one service, so the two
|
|
@@ -104,8 +111,8 @@ export class SimAwsScopedServiceRegistries {
|
|
|
104
111
|
constructor() {
|
|
105
112
|
this.cognitoDomains = new SimCognitoDomainRegistry(this.hostnameClaims);
|
|
106
113
|
this.httpApiDomains = new SimHttpApiDomainRegistry(this.hostnameClaims);
|
|
107
|
-
this.serviceHosts = new SimAwsAnyServiceHosts([
|
|
108
|
-
|
|
114
|
+
this.serviceHosts = new SimAwsAnyServiceHosts([this.cognitoDomains]);
|
|
115
|
+
this.shadowableServiceHosts = new SimAwsAnyServiceHosts([
|
|
109
116
|
this.httpApiDomains,
|
|
110
117
|
]);
|
|
111
118
|
}
|
|
@@ -88,8 +88,10 @@ export class SimAwsServiceFactory {
|
|
|
88
88
|
kmsRegistry: this.registries.kms,
|
|
89
89
|
// A Cognito hosted domain and an API Gateway custom domain each answer
|
|
90
90
|
// on a hostname of their own, so DNS resolution asks the registries
|
|
91
|
-
// holding those domains about it.
|
|
91
|
+
// holding those domains about it. A record outranks the API Gateway one,
|
|
92
|
+
// as it does on AWS, which is what keeps the two apart here.
|
|
92
93
|
serviceHosts: this.registries.serviceHosts,
|
|
94
|
+
shadowableServiceHosts: this.registries.shadowableServiceHosts,
|
|
93
95
|
iamRegistry: this.iamRegistry,
|
|
94
96
|
accessKeyRegistry: this.requestAuth.accessKeyRegistry,
|
|
95
97
|
});
|
package/dist/service/cloudformation/resource/cfn/apigatewayv2/sim-http-api-domain-name-cfn.d.ts
CHANGED
|
@@ -19,10 +19,10 @@ export declare class SimHttpApiDomainNameCfn implements SimCfnResourceValueAdapt
|
|
|
19
19
|
* AWS::ApiGatewayV2::DomainName publishes RegionalDomainName,
|
|
20
20
|
* RegionalHostedZoneId and DomainNameArn.
|
|
21
21
|
*
|
|
22
|
-
* `RegionalDomainName` is the
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
22
|
+
* `RegionalDomainName` is the `d-<id>.execute-api.<region>` endpoint API
|
|
23
|
+
* Gateway issued the domain, which is the published address a CloudFront
|
|
24
|
+
* Origin reaches directly and a Route53 alias points the custom domain name
|
|
25
|
+
* at.
|
|
26
26
|
*/
|
|
27
27
|
attributeValue(attributeName: string): SimCfnTemplateValue;
|
|
28
28
|
}
|
package/dist/service/cloudformation/resource/cfn/apigatewayv2/sim-http-api-domain-name-cfn.js
CHANGED
|
@@ -18,10 +18,10 @@ export class SimHttpApiDomainNameCfn {
|
|
|
18
18
|
* AWS::ApiGatewayV2::DomainName publishes RegionalDomainName,
|
|
19
19
|
* RegionalHostedZoneId and DomainNameArn.
|
|
20
20
|
*
|
|
21
|
-
* `RegionalDomainName` is the
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
21
|
+
* `RegionalDomainName` is the `d-<id>.execute-api.<region>` endpoint API
|
|
22
|
+
* Gateway issued the domain, which is the published address a CloudFront
|
|
23
|
+
* Origin reaches directly and a Route53 alias points the custom domain name
|
|
24
|
+
* at.
|
|
25
25
|
*/
|
|
26
26
|
attributeValue(attributeName) {
|
|
27
27
|
if (attributeName === "RegionalDomainName") {
|
|
@@ -24,6 +24,18 @@ export declare class SimRoute53ServiceTargetResolver {
|
|
|
24
24
|
* name that simulated AWS services expose.
|
|
25
25
|
*/
|
|
26
26
|
resolve(hostname: string): SimAwsServiceTarget | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Resolve the regional endpoint hostname of an API Gateway custom domain:
|
|
29
|
+
*
|
|
30
|
+
* d-<id>.execute-api.<region>.amazonaws.com
|
|
31
|
+
*
|
|
32
|
+
* This is read ahead of the endpoints below, because a domain endpoint and
|
|
33
|
+
* the endpoint of an API have the same shape and only the `d-` prefix tells
|
|
34
|
+
* them apart. The whole hostname is the resource name, since the domain
|
|
35
|
+
* registry answers about both of the names a domain has and the custom
|
|
36
|
+
* domain name is a hostname too.
|
|
37
|
+
*/
|
|
38
|
+
private apiGatewayDomainServiceTarget;
|
|
27
39
|
/**
|
|
28
40
|
* Resolve Yulin's own Route53 introspection hostname.
|
|
29
41
|
*
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readSimHttpApiDomainEndpointHost } from "../../apigatewayv2/domain/sim-http-api-domain-endpoint.js";
|
|
1
2
|
import { readSimElbV2LoadBalancerHost } from "../../elbv2/load-balancer/sim-elbv2-load-balancer-host.js";
|
|
2
3
|
import { simRoute53LogicalName } from "../local-name/sim-route53-local-name.js";
|
|
3
4
|
import { simRoute53DnsHostName } from "../serve/sim-route53-dns-host.js";
|
|
@@ -38,8 +39,31 @@ export class SimRoute53ServiceTargetResolver {
|
|
|
38
39
|
this.s3Targets.resolve(logicalName) ??
|
|
39
40
|
this.cloudFrontServiceTarget(logicalName) ??
|
|
40
41
|
this.loadBalancerServiceTarget(logicalName) ??
|
|
42
|
+
this.apiGatewayDomainServiceTarget(logicalName) ??
|
|
41
43
|
this.regionalTargets.resolve(logicalName));
|
|
42
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Resolve the regional endpoint hostname of an API Gateway custom domain:
|
|
47
|
+
*
|
|
48
|
+
* d-<id>.execute-api.<region>.amazonaws.com
|
|
49
|
+
*
|
|
50
|
+
* This is read ahead of the endpoints below, because a domain endpoint and
|
|
51
|
+
* the endpoint of an API have the same shape and only the `d-` prefix tells
|
|
52
|
+
* them apart. The whole hostname is the resource name, since the domain
|
|
53
|
+
* registry answers about both of the names a domain has and the custom
|
|
54
|
+
* domain name is a hostname too.
|
|
55
|
+
*/
|
|
56
|
+
apiGatewayDomainServiceTarget(logicalName) {
|
|
57
|
+
const endpoint = readSimHttpApiDomainEndpointHost(logicalName);
|
|
58
|
+
if (endpoint === undefined) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
service: "apiGatewayDomain",
|
|
63
|
+
resourceName: endpoint.logicalHost,
|
|
64
|
+
regionName: endpoint.regionName,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
43
67
|
/**
|
|
44
68
|
* Resolve Yulin's own Route53 introspection hostname.
|
|
45
69
|
*
|
|
@@ -8,6 +8,11 @@ interface SimRoute53ResolverProperties {
|
|
|
8
8
|
* such as a Cognito user pool custom domain.
|
|
9
9
|
*/
|
|
10
10
|
readonly serviceHosts?: SimAwsServiceHosts | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Where a hostname a hosted-zone record outranks is looked up, which is a
|
|
13
|
+
* claim answering only where no record names the hostname.
|
|
14
|
+
*/
|
|
15
|
+
readonly shadowableServiceHosts?: SimAwsServiceHosts | undefined;
|
|
11
16
|
}
|
|
12
17
|
/**
|
|
13
18
|
* Resolves Yulin-local hostnames through simulated Route53 hosted-zone records.
|
|
@@ -16,6 +21,7 @@ export declare class SimRoute53Resolver {
|
|
|
16
21
|
private readonly recordFinder;
|
|
17
22
|
private readonly serviceTargetResolver;
|
|
18
23
|
private readonly serviceHosts;
|
|
24
|
+
private readonly shadowableServiceHosts;
|
|
19
25
|
constructor(properties: SimRoute53ResolverProperties);
|
|
20
26
|
/**
|
|
21
27
|
* Resolve an HTTP hostname to a simulated AWS service target.
|
|
@@ -26,7 +32,9 @@ export declare class SimRoute53Resolver {
|
|
|
26
32
|
* logical Route53 name.
|
|
27
33
|
* 2. Check whether that name already points at a built-in simulated service.
|
|
28
34
|
* 3. If not, follow CNAME or alias records to the next hostname.
|
|
29
|
-
* 4.
|
|
35
|
+
* 4. Where no record names it, answer with a hostname a resource claimed for
|
|
36
|
+
* itself, such as an API Gateway custom domain.
|
|
37
|
+
* 5. Stop when a service target is found, a chain breaks, a cycle appears, or
|
|
30
38
|
* the maximum CNAME depth is reached.
|
|
31
39
|
*
|
|
32
40
|
* The suffix is optional because the simulated DNS server answers for logical
|
|
@@ -10,9 +10,12 @@ export class SimRoute53Resolver {
|
|
|
10
10
|
recordFinder;
|
|
11
11
|
serviceTargetResolver = new SimRoute53ServiceTargetResolver();
|
|
12
12
|
serviceHosts;
|
|
13
|
+
shadowableServiceHosts;
|
|
13
14
|
constructor(properties) {
|
|
14
15
|
this.recordFinder = new SimRoute53HostedZoneRecordFinder(properties.hostedZones);
|
|
15
16
|
this.serviceHosts = properties.serviceHosts ?? new SimAwsNoServiceHosts();
|
|
17
|
+
this.shadowableServiceHosts =
|
|
18
|
+
properties.shadowableServiceHosts ?? new SimAwsNoServiceHosts();
|
|
16
19
|
}
|
|
17
20
|
/**
|
|
18
21
|
* Resolve an HTTP hostname to a simulated AWS service target.
|
|
@@ -23,7 +26,9 @@ export class SimRoute53Resolver {
|
|
|
23
26
|
* logical Route53 name.
|
|
24
27
|
* 2. Check whether that name already points at a built-in simulated service.
|
|
25
28
|
* 3. If not, follow CNAME or alias records to the next hostname.
|
|
26
|
-
* 4.
|
|
29
|
+
* 4. Where no record names it, answer with a hostname a resource claimed for
|
|
30
|
+
* itself, such as an API Gateway custom domain.
|
|
31
|
+
* 5. Stop when a service target is found, a chain breaks, a cycle appears, or
|
|
27
32
|
* the maximum CNAME depth is reached.
|
|
28
33
|
*
|
|
29
34
|
* The suffix is optional because the simulated DNS server answers for logical
|
|
@@ -63,7 +68,10 @@ export class SimRoute53Resolver {
|
|
|
63
68
|
const nextRecord = this.findNextResolutionRecord(logicalName);
|
|
64
69
|
const nextTarget = nextRecord?.values[0];
|
|
65
70
|
if (nextTarget === undefined || nextTarget.length === 0) {
|
|
66
|
-
|
|
71
|
+
// An API Gateway custom domain is reached through a record on AWS, so
|
|
72
|
+
// the record decides where the name goes and the claim answers only
|
|
73
|
+
// where no record names it.
|
|
74
|
+
return this.shadowableServiceHosts.targetForHost(logicalName);
|
|
67
75
|
}
|
|
68
76
|
localName = simRoute53LocalName(nextTarget);
|
|
69
77
|
}
|
|
@@ -23,6 +23,12 @@ interface SimRoute53Properties {
|
|
|
23
23
|
* one arrives at the service holding it.
|
|
24
24
|
*/
|
|
25
25
|
readonly serviceHosts?: SimAwsServiceHosts | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Where a hostname a hosted-zone record outranks is looked up, such as an
|
|
28
|
+
* API Gateway custom domain, which is reached through a record on AWS. A
|
|
29
|
+
* claim there answers only where no record names the hostname.
|
|
30
|
+
*/
|
|
31
|
+
readonly shadowableServiceHosts?: SimAwsServiceHosts | undefined;
|
|
26
32
|
/**
|
|
27
33
|
* Where a KMS key ARN is looked up. A DNSSEC key-signing key is built on a
|
|
28
34
|
* customer managed key, and Route53 checks that key before it takes one.
|
|
@@ -24,6 +24,7 @@ export class SimRoute53 {
|
|
|
24
24
|
this.resolver = new SimRoute53Resolver({
|
|
25
25
|
hostedZones: route53Registry.hostedZones,
|
|
26
26
|
serviceHosts: properties.serviceHosts,
|
|
27
|
+
shadowableServiceHosts: properties.shadowableServiceHosts,
|
|
27
28
|
});
|
|
28
29
|
this.commands = new SimRoute53Commands({
|
|
29
30
|
hostedZones: this.hostedZones,
|
|
@@ -35,7 +35,7 @@ export interface SimS3MountFilesystemOptions {
|
|
|
35
35
|
* the web's own types, and nothing else — so that pointing a Bucket at a
|
|
36
36
|
* directory cannot be talked into reading whatever else is in it. A site
|
|
37
37
|
* serving a data file of its own needs its extension named here: a pinyin
|
|
38
|
-
* dictionary's `.freq`, a `.wasm` module, a `.
|
|
38
|
+
* dictionary's `.freq`, a `.wasm` module, a `.parquet` table.
|
|
39
39
|
*
|
|
40
40
|
* Added to the list rather than replacing it, and a leading dot is optional.
|
|
41
41
|
*/
|
package/package.json
CHANGED