Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Seed poc #1626

Draft
wants to merge 38 commits into
base: feature/seed-poc
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
e2cdecb
setup sample app
sobolk Jun 4, 2024
aad3252
Revert "setup sample app"
sobolk Jun 4, 2024
46aa201
create test project
sobolk Jun 4, 2024
4c956d3
importing script - this isn't great
sobolk Jun 4, 2024
61da3d0
tsx the script
sobolk Jun 4, 2024
2cbda4b
add backend seed package
sobolk Jun 5, 2024
21f06f5
add comment here
sobolk Jun 5, 2024
a9ce68d
add comment here
sobolk Jun 5, 2024
1be2a32
defineSeed
sobolk Jun 5, 2024
8836481
read sandbox client config
sobolk Jun 5, 2024
f89808e
kind of ugly but works
sobolk Jun 5, 2024
29cc5e0
auth client skeleton
sobolk Jun 7, 2024
a89d173
auth create user works
sobolk Jun 7, 2024
b7b1299
remove timeout for now
sobolk Jun 7, 2024
ffeffdc
api
sobolk Jun 7, 2024
8d6b8d9
readme
sobolk Jun 7, 2024
22d3b93
more
sobolk Jun 7, 2024
251d1d8
more
sobolk Jun 7, 2024
edfe052
more comments
sobolk Jun 10, 2024
e1832ca
more comments
sobolk Jun 10, 2024
2729dbc
more comments
sobolk Jun 10, 2024
edb7b50
this kind of works
sobolk Jun 11, 2024
5b45403
this kind of works
sobolk Jun 11, 2024
773760a
it seems smuggling type is possible.
sobolk Jun 17, 2024
0c7173e
add second project
sobolk Jun 18, 2024
09b6d5a
add second project
sobolk Jun 18, 2024
ee0c527
version with some magic
sobolk Jun 19, 2024
bb9ae3a
this kind of works
sobolk Jun 19, 2024
1c00a42
readme
sobolk Jun 19, 2024
a04c7a9
well.. storage is easy
sobolk Jun 19, 2024
86d8983
delete that
sobolk Jun 19, 2024
e383500
more readme
sobolk Jun 19, 2024
5d12b6b
storage
sobolk Jun 19, 2024
6b0e84e
tweaks
sobolk Jun 19, 2024
21e0edb
tweaks
sobolk Jun 20, 2024
e576c28
fix that
sobolk Jun 21, 2024
b3ec956
Seed access.
sobolk Sep 13, 2024
d40d6a0
feed pr base sha and ref into envs before scripts (#2168)
rtpascual Oct 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 24 additions & 98 deletions package-lock.json

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions packages/backend-seed/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Be very careful editing this file. It is crafted to work around [this issue](https://github.com/npm/npm/issues/4479)

# First ignore everything
**/*

# Then add back in transpiled js and ts declaration files
!lib/**/*.js
!lib/**/*.d.ts

# Then ignore test js and ts declaration files
*.test.js
*.test.d.ts

# This leaves us with including only js and ts declaration files of functional code
15 changes: 15 additions & 0 deletions packages/backend-seed/API.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## API Report File for "@aws-amplify/backend-seed"

> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).

```ts

// @public (undocumented)
export const defineSeed: (seedFunction: SeedFunction) => void;

// @public (undocumented)
export type SeedFunction = () => Promise<void>;

// (No @packageDocumentation comment for this package)

```
3 changes: 3 additions & 0 deletions packages/backend-seed/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Description

Replace with a description of this package
3 changes: 3 additions & 0 deletions packages/backend-seed/api-extractor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "../../api-extractor.base.json"
}
30 changes: 30 additions & 0 deletions packages/backend-seed/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "@aws-amplify/backend-seed",
"version": "0.1.0",
"type": "module",
"publishConfig": {
"access": "public"
},
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./lib/index.js",
"require": "./lib/index.js"
}
},
"types": "lib/index.d.ts",
"scripts": {
"update:api": "api-extractor run --local"
},
"license": "Apache-2.0",
"dependencies": {
"@aws-amplify/client-config": "^1.0.3",
"@aws-amplify/platform-core": "^1.0.1",
"@aws-sdk/client-cognito-identity-provider": "^3.465.0",
"aws-amplify": "^6.2.0",
"semver": "^7.5.4"
},
"peerDependencies": {
"@aws-amplify/api-graphql": "^4.1.0"
}
}
64 changes: 64 additions & 0 deletions packages/backend-seed/src/async_lock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* Example usage:
* const myLock = new AsyncLock();
*
* async function asyncFunction() {
* await myLock.acquire();
* try {
* // Code that requires exclusive access to a shared resource
* console.log('Accessing shared resource...');
* await someAsyncOperation();
* } finally {
* myLock.release();
* }
* }
*
* asyncFunction();
*/
// TODO this is a copy for the POC purposes.
export class AsyncLock {
private isLocked: boolean;
private readonly queue: Array<(value?: never) => void>;

/**
* Creates async lock.
*/
constructor(private readonly defaultTimeoutMs?: number) {
this.isLocked = false;
this.queue = [];
}

acquire = async (timeoutMs?: number): Promise<void> => {
const lockPromise = new Promise<void>((resolve) => {
if (!this.isLocked) {
this.isLocked = true;
resolve();
} else {
this.queue.push(resolve);
}
});
timeoutMs = timeoutMs ?? this.defaultTimeoutMs;
if (timeoutMs) {
const timeoutPromise = new Promise<void>((resolve, reject) =>
setTimeout(
() =>
reject(
new Error(`Unable to acquire async lock in ${timeoutMs}ms.`)
),
timeoutMs
)
);
return Promise.race<void>([lockPromise, timeoutPromise]);
}
return lockPromise;
};

release = (): void => {
const resolve = this.queue.shift();
if (resolve) {
resolve();
} else {
this.isLocked = false;
}
};
}
97 changes: 97 additions & 0 deletions packages/backend-seed/src/auth_client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { AsyncLock } from './async_lock.js';
import { AuthClient, AuthUser } from './types.js';
import {
AdminCreateUserCommand,
CognitoIdentityProviderClient,
} from '@aws-sdk/client-cognito-identity-provider';
import { randomUUID } from 'node:crypto';
import { ClientConfigVersionTemplateType } from '@aws-amplify/client-config';
import * as auth from 'aws-amplify/auth';
import assert from 'assert';
import { SemVer } from 'semver';
import crypto from 'node:crypto';

Check failure on line 12 in packages/backend-seed/src/auth_client.ts

View workflow job for this annotation

GitHub Actions / lint

'node:crypto' import is duplicated

// TODO: this is a work around
// it seems like as of amplify v6 , some of the code only runs in the browser ...
// see https://github.com/aws-amplify/amplify-js/issues/12751
if (process.versions.node) {
// node >= 20 now exposes crypto by default. This workaround is not needed: https://github.com/nodejs/node/pull/42083
if (new SemVer(process.versions.node).major < 20) {
// @ts-expect-error altering typing for global to make compiler happy is not worth the effort assuming this is temporary workaround
globalThis.crypto = crypto;
}
}

export class DefaultAuthClient implements AuthClient {

Check failure on line 25 in packages/backend-seed/src/auth_client.ts

View workflow job for this annotation

GitHub Actions / lint

Missing JSDoc comment
/**
* Asynchronous lock is used to assure that all calls to Amplify JS library are
* made in single transaction. This is because that library maintains global state,
* for example auth session.
*/
private readonly lock: AsyncLock = new AsyncLock(60 * 1000);

private readonly userPoolId: string;
private readonly userPoolClientId: string;
private readonly identityPoolId: string;
private readonly allowGuestAccess: boolean | undefined;

/**
* Creates Amplify Auth client.
*/
constructor(
private readonly cognitoIdentityProviderClient: CognitoIdentityProviderClient,
authConfig: NonNullable<ClientConfigVersionTemplateType<'1'>['auth']>
) {
if (!authConfig.identity_pool_id) {
throw new Error('Client config must have identity pool id.');
}
this.userPoolId = authConfig.user_pool_id;
this.userPoolClientId = authConfig.user_pool_client_id;
this.identityPoolId = authConfig.identity_pool_id;
this.allowGuestAccess = authConfig.unauthenticated_identities_enabled;
}

createUser = async (
username: string,

Check failure

Code scanning / CodeQL

Insecure randomness High

This uses a cryptographically insecure random number generated at
Math.random()
in a security context.
This uses a cryptographically insecure random number generated at
Math.random()
in a security context.

Copilot Autofix AI 3 months ago

To fix the problem, we need to replace the use of Math.random() with a cryptographically secure random number generator. In Node.js, we can use the crypto module's randomUUID method to generate secure random values. This method provides a cryptographically secure way to generate random UUIDs, which can be used to create secure usernames and passwords.

We will update the test-projects/seed-poc3/amplify/seed.ts file to use crypto.randomUUID() instead of Math.random() for generating random parts of usernames and passwords.

Suggested changeset 1
test-projects/seed-poc3/amplify/seed.ts
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/test-projects/seed-poc3/amplify/seed.ts b/test-projects/seed-poc3/amplify/seed.ts
--- a/test-projects/seed-poc3/amplify/seed.ts
+++ b/test-projects/seed-poc3/amplify/seed.ts
@@ -9,2 +9,3 @@
 import { generateClient } from 'aws-amplify/api';
+import { randomUUID } from 'crypto';
 
@@ -24,3 +25,3 @@
 await dataClient.models.Todo.create({
-  content: `Todo@${Math.random().toString()}`,
+  content: `Todo@${randomUUID()}`,
 });
@@ -28,4 +29,4 @@
 const user1 = await authClient.createUser(
-  `user${Math.random().toString()}@amazon.com`,
-  `P@ssword${Math.random().toString()}`
+  `user${randomUUID()}@amazon.com`,
+  `P@ssword${randomUUID()}`
 );
@@ -33,4 +34,4 @@
 const user2 = await authClient.createUser(
-  `user${Math.random().toString()}@amazon.com`,
-  `P@ssword${Math.random().toString()}`
+  `user${randomUUID()}@amazon.com`,
+  `P@ssword${randomUUID()}`
 );
@@ -44,3 +45,3 @@
   {
-    content: `Todo@${user1?.username ?? ''}@${Math.random().toString()}`,
+    content: `Todo@${user1?.username ?? ''}@${randomUUID()}`,
   },
@@ -63,3 +64,3 @@
   {
-    content: `Todo@${user2?.username ?? ''}@${Math.random().toString()}`,
+    content: `Todo@${user2?.username ?? ''}@${randomUUID()}`,
   },
@@ -74,4 +75,4 @@
 const uploadTask = storage.uploadData({
-  data: `Some Content ${Math.random().toString()}`,
-  path: `foo/${Math.random().toString()}`,
+  data: `Some Content ${randomUUID()}`,
+  path: `foo/${randomUUID()}`,
 });
@@ -103,3 +104,3 @@
   {
-    content: `Todo2@${Math.random().toString()}`,
+    content: `Todo2@${randomUUID()}`,
   },
@@ -118,3 +119,2 @@
 
-
 // TODO: how can we use IAM creds with data client?? (and other clients?)
EOF
@@ -9,2 +9,3 @@
import { generateClient } from 'aws-amplify/api';
import { randomUUID } from 'crypto';

@@ -24,3 +25,3 @@
await dataClient.models.Todo.create({
content: `Todo@${Math.random().toString()}`,
content: `Todo@${randomUUID()}`,
});
@@ -28,4 +29,4 @@
const user1 = await authClient.createUser(
`user${Math.random().toString()}@amazon.com`,
`P@ssword${Math.random().toString()}`
`user${randomUUID()}@amazon.com`,
`P@ssword${randomUUID()}`
);
@@ -33,4 +34,4 @@
const user2 = await authClient.createUser(
`user${Math.random().toString()}@amazon.com`,
`P@ssword${Math.random().toString()}`
`user${randomUUID()}@amazon.com`,
`P@ssword${randomUUID()}`
);
@@ -44,3 +45,3 @@
{
content: `Todo@${user1?.username ?? ''}@${Math.random().toString()}`,
content: `Todo@${user1?.username ?? ''}@${randomUUID()}`,
},
@@ -63,3 +64,3 @@
{
content: `Todo@${user2?.username ?? ''}@${Math.random().toString()}`,
content: `Todo@${user2?.username ?? ''}@${randomUUID()}`,
},
@@ -74,4 +75,4 @@
const uploadTask = storage.uploadData({
data: `Some Content ${Math.random().toString()}`,
path: `foo/${Math.random().toString()}`,
data: `Some Content ${randomUUID()}`,
path: `foo/${randomUUID()}`,
});
@@ -103,3 +104,3 @@
{
content: `Todo2@${Math.random().toString()}`,
content: `Todo2@${randomUUID()}`,
},
@@ -118,3 +119,2 @@


// TODO: how can we use IAM creds with data client?? (and other clients?)
Copilot is powered by AI and may make mistakes. Always verify output.
Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
password: string

Check failure

Code scanning / CodeQL

Insecure randomness High

This uses a cryptographically insecure random number generated at
Math.random()
in a security context.
This uses a cryptographically insecure random number generated at
Math.random()
in a security context.

Copilot Autofix AI 3 months ago

To fix the problem, we need to replace the use of Math.random() with a cryptographically secure random number generator. In Node.js, we can use the crypto module's randomBytes method to generate secure random values. We will update the code in test-projects/seed-poc3/amplify/seed.ts to use crypto.randomBytes instead of Math.random() for generating passwords.

Suggested changeset 1
test-projects/seed-poc3/amplify/seed.ts
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/test-projects/seed-poc3/amplify/seed.ts b/test-projects/seed-poc3/amplify/seed.ts
--- a/test-projects/seed-poc3/amplify/seed.ts
+++ b/test-projects/seed-poc3/amplify/seed.ts
@@ -9,2 +9,3 @@
 import { generateClient } from 'aws-amplify/api';
+import { randomBytes } from 'crypto';
 
@@ -24,3 +25,3 @@
 await dataClient.models.Todo.create({
-  content: `Todo@${Math.random().toString()}`,
+  content: `Todo@${randomBytes(4).toString('hex')}`,
 });
@@ -28,4 +29,4 @@
 const user1 = await authClient.createUser(
-  `user${Math.random().toString()}@amazon.com`,
-  `P@ssword${Math.random().toString()}`
+  `user${randomBytes(4).toString('hex')}@amazon.com`,
+  `P@ssword${randomBytes(4).toString('hex')}`
 );
@@ -33,4 +34,4 @@
 const user2 = await authClient.createUser(
-  `user${Math.random().toString()}@amazon.com`,
-  `P@ssword${Math.random().toString()}`
+  `user${randomBytes(4).toString('hex')}@amazon.com`,
+  `P@ssword${randomBytes(4).toString('hex')}`
 );
@@ -44,3 +45,3 @@
   {
-    content: `Todo@${user1?.username ?? ''}@${Math.random().toString()}`,
+    content: `Todo@${user1?.username ?? ''}@${randomBytes(4).toString('hex')}`,
   },
@@ -63,3 +64,3 @@
   {
-    content: `Todo@${user2?.username ?? ''}@${Math.random().toString()}`,
+    content: `Todo@${user2?.username ?? ''}@${randomBytes(4).toString('hex')}`,
   },
@@ -74,4 +75,4 @@
 const uploadTask = storage.uploadData({
-  data: `Some Content ${Math.random().toString()}`,
-  path: `foo/${Math.random().toString()}`,
+  data: `Some Content ${randomBytes(4).toString('hex')}`,
+  path: `foo/${randomBytes(4).toString('hex')}`,
 });
@@ -103,3 +104,3 @@
   {
-    content: `Todo2@${Math.random().toString()}`,
+    content: `Todo2@${randomBytes(4).toString('hex')}`,
   },
@@ -118,3 +119,2 @@
 
-
 // TODO: how can we use IAM creds with data client?? (and other clients?)
EOF
@@ -9,2 +9,3 @@
import { generateClient } from 'aws-amplify/api';
import { randomBytes } from 'crypto';

@@ -24,3 +25,3 @@
await dataClient.models.Todo.create({
content: `Todo@${Math.random().toString()}`,
content: `Todo@${randomBytes(4).toString('hex')}`,
});
@@ -28,4 +29,4 @@
const user1 = await authClient.createUser(
`user${Math.random().toString()}@amazon.com`,
`P@ssword${Math.random().toString()}`
`user${randomBytes(4).toString('hex')}@amazon.com`,
`P@ssword${randomBytes(4).toString('hex')}`
);
@@ -33,4 +34,4 @@
const user2 = await authClient.createUser(
`user${Math.random().toString()}@amazon.com`,
`P@ssword${Math.random().toString()}`
`user${randomBytes(4).toString('hex')}@amazon.com`,
`P@ssword${randomBytes(4).toString('hex')}`
);
@@ -44,3 +45,3 @@
{
content: `Todo@${user1?.username ?? ''}@${Math.random().toString()}`,
content: `Todo@${user1?.username ?? ''}@${randomBytes(4).toString('hex')}`,
},
@@ -63,3 +64,3 @@
{
content: `Todo@${user2?.username ?? ''}@${Math.random().toString()}`,
content: `Todo@${user2?.username ?? ''}@${randomBytes(4).toString('hex')}`,
},
@@ -74,4 +75,4 @@
const uploadTask = storage.uploadData({
data: `Some Content ${Math.random().toString()}`,
path: `foo/${Math.random().toString()}`,
data: `Some Content ${randomBytes(4).toString('hex')}`,
path: `foo/${randomBytes(4).toString('hex')}`,
});
@@ -103,3 +104,3 @@
{
content: `Todo2@${Math.random().toString()}`,
content: `Todo2@${randomBytes(4).toString('hex')}`,
},
@@ -118,3 +119,2 @@


// TODO: how can we use IAM creds with data client?? (and other clients?)
Copilot is powered by AI and may make mistakes. Always verify output.
Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
): Promise<AuthUser> => {
await this.lock.acquire();
try {
console.log(`creating ${username}, ${password}`);

Check failure on line 60 in packages/backend-seed/src/auth_client.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected console statement

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information High

This logs sensitive data returned by
an access to password
as clear text.

Copilot Autofix AI 3 months ago

To fix the problem, we need to remove the logging of sensitive information such as passwords. Instead of logging the password, we can log a message indicating that a user is being created without including the sensitive details. This way, we maintain the ability to debug and monitor the process without exposing sensitive information.

  • Remove the logging of the password in the createUser method.
  • Log a message that does not include sensitive information.
Suggested changeset 1
packages/backend-seed/src/auth_client.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/packages/backend-seed/src/auth_client.ts b/packages/backend-seed/src/auth_client.ts
--- a/packages/backend-seed/src/auth_client.ts
+++ b/packages/backend-seed/src/auth_client.ts
@@ -60,3 +60,3 @@
     try {
-      console.log(`creating ${username}, ${password}`);
+      console.log(`creating user: ${username}`);
       const temporaryPassword = `Test1@Temp${randomUUID().toString()}`;
EOF
@@ -60,3 +60,3 @@
try {
console.log(`creating ${username}, ${password}`);
console.log(`creating user: ${username}`);
const temporaryPassword = `Test1@Temp${randomUUID().toString()}`;
Copilot is powered by AI and may make mistakes. Always verify output.
Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
const temporaryPassword = `Test1@Temp${randomUUID().toString()}`;
await this.cognitoIdentityProviderClient.send(
new AdminCreateUserCommand({
Username: username,
TemporaryPassword: temporaryPassword,
UserPoolId: this.userPoolId,
MessageAction: 'SUPPRESS',
})
);

// in case there's already signed user in the session.
await auth.signOut();

const signInResult = await auth.signIn({
username,
password: temporaryPassword,
});

assert.strictEqual(
signInResult.nextStep.signInStep,
'CONFIRM_SIGN_IN_WITH_NEW_PASSWORD_REQUIRED'
);

await auth.confirmSignIn({
challengeResponse: password,
});

return {
username,
password,
};
} finally {
console.log(`user ${username} created`);

Check failure on line 93 in packages/backend-seed/src/auth_client.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected console statement
this.lock.release();
}
};
}
41 changes: 41 additions & 0 deletions packages/backend-seed/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { generateClientConfig } from '@aws-amplify/client-config';
import { SandboxBackendIdResolver } from './sandbox_id_resolver.js';
import { LocalNamespaceResolver } from './local_namespace_resolver.js';
import { PackageJsonReader } from '@aws-amplify/platform-core';
import { Amplify } from 'aws-amplify';
import { generateClient } from 'aws-amplify/data';
import { AuthClient, AuthUser, SeedFunction } from './types.js';
import { DefaultAuthClient } from './auth_client.js';
import { CognitoIdentityProviderClient } from '@aws-sdk/client-cognito-identity-provider';

export { AuthClient, AuthUser, SeedFunction };

const seedFunctions: Array<SeedFunction<Record<any, any>>> = [];

Check failure on line 13 in packages/backend-seed/src/index.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type

Check failure on line 13 in packages/backend-seed/src/index.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type

export const defineSeed = <SchemaType extends Record<any, any>>(

Check failure on line 15 in packages/backend-seed/src/index.ts

View workflow job for this annotation

GitHub Actions / lint

Missing JSDoc comment

Check failure on line 15 in packages/backend-seed/src/index.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type

Check failure on line 15 in packages/backend-seed/src/index.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
seedFunction: SeedFunction<SchemaType>
) => {
seedFunctions.push(seedFunction);
};

process.once('beforeExit', async () => {

Check failure on line 21 in packages/backend-seed/src/index.ts

View workflow job for this annotation

GitHub Actions / lint

Promise returned in function argument where a void return was expected
const backendId = await new SandboxBackendIdResolver(
new LocalNamespaceResolver(new PackageJsonReader())
).resolve();
const clientConfig = await generateClientConfig(backendId, '0');
Amplify.configure(clientConfig);
const dataClient = generateClient<Record<any, any>>();
const authClient = new DefaultAuthClient(
new CognitoIdentityProviderClient(),
clientConfig['auth']
);
try {
for (const seedFunction of seedFunctions) {
await seedFunction(dataClient, authClient);
}
} catch (e) {
console.log(e);
} finally {
console.log('after seed functions');
}
});
34 changes: 34 additions & 0 deletions packages/backend-seed/src/local_namespace_resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {
AmplifyUserError,
PackageJsonReader,
} from '@aws-amplify/platform-core';
import { EOL } from 'os';

// TODO This is copy pasted for the purpose of POC

export type NamespaceResolver = {
resolve: () => Promise<string>;
};

/**
* Reads the local app name from package.json#name in the current directory
*/
export class LocalNamespaceResolver implements NamespaceResolver {
/**
* packageJsonReader is assigned to an instance member for testing.
* resolve is bound to this so that it can be passed as a function reference
*/
constructor(private readonly packageJsonReader: PackageJsonReader) {}

/**
* Returns the value of package.json#name from the current working directory
*/
resolve = async () => {
const name = this.packageJsonReader.readFromCwd().name;
if (name) return name;
throw new AmplifyUserError('InvalidPackageJsonError', {
message: 'Cannot load name from the package.json',
resolution: `Ensure you are running ampx commands in root of your project (i.e. in the parent of the 'amplify' directory).${EOL}Also ensure that your root package.json file has a "name" field.`,
});
};
}
32 changes: 32 additions & 0 deletions packages/backend-seed/src/sandbox_id_resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { userInfo as _userInfo } from 'os';
import { BackendIdentifier } from '@aws-amplify/plugin-types';
import { NamespaceResolver } from "./local_namespace_resolver.js";

// TODO This is copy pasted for the purpose of POC

/**
* Resolves an ID that can be used to uniquely identify sandbox environments
*/
export class SandboxBackendIdResolver {
/**
* Initialize with an appName resolver
*/
constructor(
private readonly namespaceResolver: NamespaceResolver,
private readonly userInfo = _userInfo
) {}

/**
* Returns a concatenation of the resolved appName and the current username
*/
resolve = async (identifier?: string): Promise<BackendIdentifier> => {
const namespace = await this.namespaceResolver.resolve();
const name = identifier || this.userInfo().username;

return {
namespace,
name,
type: 'sandbox',
};
};
}
17 changes: 17 additions & 0 deletions packages/backend-seed/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { V6Client } from '@aws-amplify/api-graphql';

// TODO is there a better way to bring in schema typings? It must come from customer project.

Check warning on line 3 in packages/backend-seed/src/types.ts

View workflow job for this annotation

GitHub Actions / lint

You have a misspelled word: typings on Comment
export type SeedFunction<SchemaType extends Record<any, any>> = (
// TODO how can data client dynamically typed here?
dataClient: V6Client<SchemaType>,
authClient: AuthClient
) => Promise<void>;

export type AuthUser = {
username: string;
password: string;
};

export type AuthClient = {
createUser: (username: string, password: string) => Promise<AuthUser>;
};
5 changes: 5 additions & 0 deletions packages/backend-seed/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": { "rootDir": "src", "outDir": "lib" },
"references": [{ "path": "../client-config" }, { "path": "../platform-core" }]
}
3 changes: 3 additions & 0 deletions packages/backend-seed/typedoc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"entryPoints": ["src/index.ts"]
}
3 changes: 3 additions & 0 deletions packages/backend/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { DeepPartialAmplifyGeneratedConfigs } from '@aws-amplify/plugin-types';
import { defineAuth } from '@aws-amplify/backend-auth';
import { defineData } from '@aws-amplify/backend-data';
import { defineFunction } from '@aws-amplify/backend-function';
import { defineSeed } from '@aws-amplify/backend-seed';
import { defineStorage } from '@aws-amplify/backend-storage';
import { FunctionResources } from '@aws-amplify/plugin-types';
import { GenerateContainerEntryProps } from '@aws-amplify/plugin-types';
Expand Down Expand Up @@ -81,6 +82,8 @@ export { defineData }

export { defineFunction }

export { defineSeed }

export { defineStorage }

export { FunctionResources }
Expand Down
1 change: 1 addition & 0 deletions packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@aws-amplify/backend-output-schemas": "^1.1.0",
"@aws-amplify/backend-output-storage": "^1.0.1",
"@aws-amplify/backend-secret": "^1.0.0",
"@aws-amplify/backend-seed": "^0.1.0",
"@aws-amplify/backend-storage": "^1.0.2",
"@aws-amplify/client-config": "^1.0.3",
"@aws-amplify/platform-core": "^1.0.1",
Expand Down
Loading
Loading