I followed the instructions on the github readme and have imported the app into my AWS Mobile Hub project and downloaded my projects aws-config.js to src/assets. When I attempt to serve the app I get a runtime error:
Runtime Error:
aws_cognito_region is not defined
Stack:
ReferenceError: aws_cognito_region is not defined
at new Cognito (http://localhost:8100/build/main.js:112:36)
at _createClass (http://localhost:8100/build/vendor.js:10975:20)
at _createProviderInstance$1 (http://localhost:8100/build/vendor.js:10949:26)
at resolveNgModuleDep (http://localhost:8100/build/vendor.js:10934:17)
at _createClass (http://localhost:8100/build/vendor.js:10977:29)
at _createProviderInstance$1 (http://localhost:8100/build/vendor.js:10949:26)
at resolveNgModuleDep (http://localhost:8100/build/vendor.js:10934:17)
at NgModuleRef_.get (http://localhost:8100/build/vendor.js:12159:16)
at resolveDep (http://localhost:8100/build/vendor.js:12655:45)
at createClass (http://localhost:8100/build/vendor.js:12525:32)
Any insight would be greatly appreciated.
Edit: I have added below my app.config.ts code as well as a segment of my aws-config.js file (omitting the constant declarations at the top that contain my AWS mobile hub project details)
app.config.ts:
import { Injectable } from '#angular/core';
declare var AWS: any;
declare const aws_mobile_analytics_app_id;
declare const aws_cognito_region;
declare const aws_cognito_identity_pool_id;
declare const aws_user_pools_id;
declare const aws_user_pools_web_client_id;
declare const aws_user_files_s3_bucket;
#Injectable()
export class AwsConfig {
public load() {
// Expects global const values defined by aws-config.js
const cfg = {
"aws_mobile_analytics_app_id": aws_mobile_analytics_app_id,
"aws_cognito_region": aws_cognito_region,
"aws_cognito_identity_pool_id": aws_cognito_identity_pool_id,
"aws_user_pools_id": aws_user_pools_id,
"aws_user_pools_web_client_id": aws_user_pools_web_client_id,
"aws_user_files_s3_bucket": aws_user_files_s3_bucket
};
AWS.config.customUserAgent = AWS.config.customUserAgent + ' Ionic';
return cfg;
}
}
aws-config.js:
const 'aws_cognito_region' = 'us-east-1';
... etc
AWS.config.region = aws_project_region;
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: aws_cognito_identity_pool_id
}, {
region: aws_cognito_region
});
AWS.config.update({customUserAgent: 'MobileHub v0.1'});
I fixed this issue by going to the aws-config.js and removing the single quotes on each of the variables defined. So if you have this:
const 'aws_cognito_region' = 'us-east-1';
Change to this:
const aws_cognito_region = 'us-east-1';
You need to configure src/app/app.config with your AWS information (app id, pool id, etc.).
Related
I've following stack which deploys the two constructs within. The construct DynamoDBConstruct exports the table name, and the construct IAMRoleConstruct consumes it. However, during deployment, it fails stating No export named dbTableName found, despite the fact that dependency is added/specified, the IAMRoleConstruct gets deployed first, why?
Stack:
public AllStacks(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
{
var db = new DynamoDBConstruct(this, "DynamoDB");
var iam = new IAMRoleConstruct(this, "IAMRole");
iam.Node.AddDependency(db);
}
DynamoDBConstruct
public DynamoDBConstruct(Construct scope, string id): base(scope, id)
{
var dbTable = new Table(this, "dbTable", new TableProps()
{
PartitionKey = new Attribute
{
Name = "contactID",
Type = AttributeType.STRING
},
TableClass = TableClass.STANDARD,
TableName = (string)Node.TryGetContext("dbTableName"),
RemovalPolicy = RemovalPolicy.DESTROY
});
new CfnOutput(this, "OutputTableName", new CfnOutputProps()
{
ExportName = "dbTableName",
Value = dbTable.TableName
});
}
IAMRoleConstruct
public IAMRoleConstruct(Construct scope, string id) : base(scope, id)
{
var dbTableName = Fn.ImportValue("dbTableName");
/*
Some code
.
*/
}
With the disclaimer that I am not sure what language your code is in, I'm going to write in CDK's native language (which I recommend you to do as well) - Typescript.
The problem comes most likely from the fact that you are using the export within the same CDK/CFN stack. The export won't be available during stack creation, as that is part of the stack creation itself.
When you're working within a single stack, the simplest, most intuitive way of "moving data" from one construct to another is to just expose values through a public member of your class, e.g.:
class DynamoDBConstruct extends Construct {
public readonly tableName: string;
constructor(scope: Construct, id: string, props: Whatever) {
super(scope, id);
const table = new Table(this, 'Table', {
partitionKey: { name: 'id', type: AttributeType.STRING },
billingMode: BillingMode.PAY_PER_REQUEST,
// omitting table name on purpose - it will be generated by CDK
});
this.tableName = table.tableName;
}
}
Now inside your stack, you can simply use that table name:
class MyStack extends Stack {
constructor(scope: App, id: string, props: Whatever) {
const table = new DynamoDBConstruct(...);
const myOtherConstruct = new MyOtherConstruct(this, 'myOtherConstruct', {
// using table name here
tableName: table.tableName,
});
}
}
The reason for the error is that you are trying to produce and consume a Stack Output in the same stack. That won't work:
Docs: Output values are available after the stack operation is complete. Stack output values aren't available when a stack status is in any of the IN_PROGRESS status.
No worries! As #Victor says, there is a much easier alternative. Get rid of the Outputs. Instead, share data between your custom constructs by declaring public fields (e.g. public Table table) in the providing class, passing the references as props to the consuming class. This is what the CDK constructs do.
See the C# example stacks in the aws-cdk-examples repo.
So I have created an 'implementation contract' and a 'clone factory' which creates clones of the implementation contract. I have tested the functionality of the CloneFactory and it works in Remix.
However, I am now writing tests for the contract in Hardhat and it doesn't seem to be working correctly (Mocha and Chai). The issue I am facing is that the cloned contract is not being correctly initialised.
Here is my Clone Factory:
contract CloneFactory {
address public implementationContract;
address[] public allClones;
event NewClone(address indexed _instance);
mapping(address => address) public list;
constructor(address _implementation) {
implementationContract = _implementation;
}
function createClone(address _whoopyCreator) payable external returns(address instance) {
instance = Clones.clone(implementationContract);
(bool success, ) = instance.call{value: msg.value}(abi.encodeWithSignature("initialize(address)", _creator));
allClones.push(instance);
list[_creator] = instance;
emit NewClone(instance);
return instance;
}
Here is the initialiser function in my Implementation Contract:
function initialize(address _creator) public initializer {
VRFConsumerBaseV2.initialise(vrfCoordinatorV2);
i_vrfCoordinator = VRFCoordinatorV2Interface(vrfCoordinatorV2);
creator = _creator;
Here is the test I am running (this is where I believe there is an issue):
it("Initialises contract correctly", async function () {
Main = await ethers.getContractFactory("Main");
main = await Main.deploy();
await main.deployed();
const dir = path.resolve(
__dirname,
"/Users/xxx/hardhat-smartcontract-main/artifacts/contracts/Main.sol/Main.json"
)
const file = fs.readFileSync(dir, "utf8")
const json = JSON.parse(file)
const abi = json.abi
CloneFactory = await ethers.getContractFactory("CloneFactory");
cf = await CloneFactory.deploy(main.address);
await cf.deployed();
let currentProvider = new web3.providers.HttpProvider('http://localhost:8545');
let web3Provider = new ethers.providers.Web3Provider(currentProvider);
const [addr1, addr2] = await ethers.getSigners();
const tx = await cf.createClone(addr1.address, {
value: ethers.utils.parseUnits("0", "ether")
});
const txReceipt = await tx.wait(1)
const cloneAddress = await txReceipt.events[0].args._instance
const clonedContract = new ethers.Contract(cloneAddress, abi, web3Provider)
const accountConnectedClone = clonedContract.connect(addr1)
const creator = await accountConnectedClone.getCreator()
expect(addr1.address).to.equal(creator)
})
When I run this test, I get the following output:
AssertionError: expected '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb…' to equal '0x00000000000000000000000000000000000…'
+ expected - actual
-0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
+0x0000000000000000000000000000000000000000
Basically, the creator is not being saved as the address of the caller of the 'createClone' function (which means it is not being initialized. I don't think there is an issue with the Clone Factory since this works correctly in Remix.
My suspicion is this has something to do with either the ABI or with the ethers/web3 provider, however I could be wrong.
There doesn't seem to be much info online about testing clone or proxy smart contracts so I hope someone here can help me out.
Thanks in advance!
EthereumBoy
Does the clone Address returns right address?
I usually push all created clones in an array and the make a function in factory to return all address[] then receive addresses in test by calling that fucntion.
With an existing Step Functions definition JSON file, how can I use it directly in CDK to create a Step Function?
Use the L1 CfnStateMachine construct. It has a definitionString prop that accepts a stringified JSON definition.
Here is the code snippet if it is useful to anyone.
private createStepFunction(props: {
stepfunction_name: string;
stepfunctions_role_arn: string;
}): stepfunctions.CfnStateMachine {
const file = fs.readFileSync("../step_functions/definition.asl.json");
const stepFunction = new stepfunctions.CfnStateMachine(
this,
"cfnStepFunction",
{
roleArn: props.stepfunctions_role_arn,
definitionString: file.toString(),
stateMachineName: props.stepfunction_name,
}
);
return stepFunction;
}
I'm building the infrastructure for an application using AWS-CDK.
I have a construct that builds multiple S3 buckets and another construct that creates a lambda function that fetches data from these buckets.
In order to be able to give my lambda permissions to fetch data from the bucket I need the buckets ARN.
Is there a way in which I could export the bucket arn from the construct that produces the buckets and import it into the lambda construct?
Sure, maybe something like this:
export class ConsumingStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const producingStack = new BucketProducingStack(this, 'BucketProducingStack');
const { bucket1, bucket2 } = producingStack;
//Create new lambda stack here
//const lambdaStack = new LambdaStack(this, { bucket1, bucket2} );
}
}
export class BucketProducingStack extends cdk.NestedStack {
bucket1: string;
bucket2: string;
constructor(scope: cdk.Construct, id: string, props?: cdk.NestedStackProps) {
const bucket1 = new Bucket(this, 'BucketOne');
const bucket2 = new Bucket(this, 'BucketTwo');
this.bucket1 = bucket1.bucketArn;
this.bucket2 = bucket2.bucketArn;
}
}
No guarantee this compiles as it was written entirely in this window, but hopefully conveys the idea.
If you are using python, you can add
#property
def main_source_bucket(self) -> _s3.IBucket:
return self.bucket
Reference it in your app stack like this ..
bucket = S3Construct(self, "bucket", "bucket1")
LambdaConstruct(self, "lambda1", "dev", bucket.main_source_bucket
I have got follow code:
import std.stdio;
import database;
import router;
import config;
import vibe.d;
void main()
{
Config config = new Config();
auto settings = new HTTPServerSettings;
settings.port = 8081;
settings.bindAddresses = ["::1", "127.0.0.1"];
auto router = new URLRouter();
router.get("/*", serveStaticFiles("./html"));
Database database = new Database(config);
database.MySQLConnect(); // all DB methods are declared here
router.registerRestInterface(new MyRouter(database));
router.get("*", &myStuff); // all other request
listenHTTP(settings, router);
logInfo("Please open http://127.0.0.1:8081/ in your browser.");
runApplication();
}
void myStuff(HTTPServerRequest req, HTTPServerResponse res) // I need this to handle any accessed URLs
{
writeln(req.path); // getting URL that was request on server
// here I need access to DB methods to do processing and return some DB data
}
I was needed create router.get("*", &myStuff); to process any urls, that do not relate to any REST instance.
The problem that I do not know how to get access to DB methods from myStuff()
Haven't tried it but using 'partial' might be a solution.
https://dlang.org/phobos/std_functional.html#partial
void myStuff(Database db, HTTPServerRequest req, HTTPServerResponse res) { ... }
void main()
{
import std.functional : partial;
...
router.get("*", partial!(myStuff, database));
...
}
Partial creates a function with the first parameter bound to a given value - so the caller does not need to know about it. Personally I don't like globals/, singletons/ etc. and try to inject dependencies. Although the implementation might become a bit more complex this really simplifies testing a lot.
The example above injects dependencies in a way similar to Constructor Injection as mentioned here:
https://en.wikipedia.org/wiki/Dependency_injection#Constructor_injection
When injecting dependencies like this you also get a quick overview about the required components to call this function. If the number of dependencies increases think of using other approaches - eg. inject a ServiceLocator.
https://martinfowler.com/articles/injection.html#UsingAServiceLocator
Ronny
As an alternative to partial, you could achieve partial application with a closure:
router.get("*", (req, resp) => myStuff(database, req, resp));
// ...
void myStuff(Database db, HTTPServerRequest req, HTTPServerResponse res)
// ...
myStuff now has database injected from the surrounding scope.
I have no experience with vibe.d, but this may be one solution:
Database database;
shared static this(){
Config config = new Config();
database = new Database(config);
}
void main(){
(...)
void myStuff(HTTPServerRequest req, HTTPServerResponse res){
database.whatever;
}