declapract-typescript-ehmpathy 0.49.2 → 0.49.4
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/getVariables.ts +6 -2
- package/dist/practices/cicd-app-react-native-expo/best-practice/.github/workflows/.deploy-expo.yml +1 -1
- package/dist/practices/cicd-app-react-native-expo/best-practice/.github/workflows/deploy.yml +8 -8
- package/dist/practices/cicd-app-react-native-expo/best-practice/.github/workflows/test.yml +3 -3
- package/dist/practices/cicd-app-react-native-expo/best-practice/package.json +9 -9
- package/dist/practices/cicd-common/best-practice/.github/workflows/.test.yml +4 -4
- package/dist/practices/cicd-common/best-practice/.github/workflows/test.yml +1 -1
- package/dist/practices/cicd-package/best-practice/.github/workflows/publish.yml +1 -1
- package/dist/practices/cicd-service/best-practice/.agent/repo=.this/skills/use.rds.capacity.sh +1 -1
- package/dist/practices/cicd-service/best-practice/.declapract.readme.md +1 -1
- package/dist/practices/cicd-service/best-practice/.github/workflows/deploy.yml +3 -3
- package/dist/practices/cicd-service/best-practice/.github/workflows/provision.yml +9 -9
- package/dist/practices/config/bad-practices/configs-contain-wrong-account-id/config/prod.json.declapract.ts +2 -2
- package/dist/practices/config/bad-practices/divergent-config-shapes/.declapract.readme.md +1 -1
- package/dist/practices/config/bad-practices/divergent-config-shapes/config/{dev.json.declapract.ts → prep.json.declapract.ts} +7 -7
- package/dist/practices/config/bad-practices/old-dev-config-location/config/dev.json.declapract.ts +4 -1
- package/dist/practices/config/best-practice/config/prep.json +1 -1
- package/dist/practices/config/best-practice/config/test.json +1 -1
- package/dist/practices/environments/bad-practices/old-dev-scripts/package.json.declapract.ts +57 -0
- package/dist/practices/environments/best-practice/.declapract.readme.md +1 -1
- package/dist/practices/environments/best-practice/src/utils/environment.ts +2 -2
- package/dist/practices/husky/best-practice/.husky/check.timestamps.sh +48 -0
- package/dist/practices/husky/best-practice/.husky/pre-commit +2 -0
- package/dist/practices/husky/check.timestamps.play.declapract.integration.test.ts +148 -0
- package/dist/practices/node-service/bad-practices/simple-lambda-client/.declapract.readme.md +55 -0
- package/dist/practices/node-service/bad-practices/simple-lambda-client/package.json +5 -0
- package/dist/practices/node-service/bad-practices/simple-lambda-client/package.json.declapract.ts +27 -0
- package/dist/practices/node-service/bad-practices/simple-lambda-client/src/<star><star>/<star>.ts.declapract.ts +44 -0
- package/dist/practices/node-service/bad-practices/simple-lambda-handlers/.declapract.readme.md +52 -0
- package/dist/practices/node-service/bad-practices/simple-lambda-handlers/package.json +5 -0
- package/dist/practices/node-service/bad-practices/simple-lambda-handlers/package.json.declapract.ts +27 -0
- package/dist/practices/node-service/bad-practices/simple-lambda-handlers/src/<star><star>/<star>.ts.declapract.ts +50 -0
- package/dist/practices/node-service/best-practice/package.json +4 -1
- package/dist/practices/package-json-order/best-practice/package.json.declapract.ts +11 -11
- package/dist/practices/persist-with-rds/best-practice/.declapract.readme.md +21 -1
- package/dist/practices/persist-with-rds/best-practice/provision/aws/product/parameter-store.tf +39 -0
- package/dist/practices/persist-with-rds/best-practice/provision/schema/deploy.database.sh +9 -9
- package/dist/practices/provision-github/best-practice/.declapract.readme.md +7 -0
- package/dist/practices/rhachet/bad-practices/review-peer-artifacts/.behavior/<star><star>/.reviews/<star><star>/<star>peer-review<star>.md.declapract.ts +16 -0
- package/dist/practices/rhachet/bad-practices/review-peer-artifacts/.behavior/<star><star>/.reviews/peer/<star><star>/<star>.md.declapract.ts +16 -0
- package/dist/practices/rhachet/bad-practices/review-peer-artifacts/.declapract.readme.md +12 -0
- package/dist/practices/{runtime-type-checking → runtime-schemas}/bad-practices/joi/package.json.declapract.ts +4 -0
- package/dist/practices/runtime-schemas/bad-practices/joi/src/<star><star>/<star>.ts.declapract.ts +50 -0
- package/dist/practices/serverless/best-practice/package.json +2 -2
- package/dist/practices/serverless/best-practice/serverless.yml +3 -3
- package/dist/practices/serverless/best-practice/serverless.yml.declapract.ts +2 -2
- package/dist/practices/terraform-aws/bad-practices/old-dev-env-dir/provision/aws/environments/dev/<star>.declapract.ts +14 -0
- package/dist/practices/terraform-aws/best-practice/provision/aws/environments/{dev → prep}/main.tf +2 -2
- package/dist/practices/terraform-aws/best-practice/provision/aws/environments/test/main.tf +1 -1
- package/dist/useCases.yml +1 -3
- package/package.json +6 -5
- package/dist/practices/lambda-clients/bad-practices/lambda-service-client-package/.declapract.readme.md +0 -1
- package/dist/practices/lambda-clients/bad-practices/lambda-service-client-package/package.json +0 -5
- package/dist/practices/lambda-clients/bad-practices/lambda-service-client-package/package.json.declapract.ts +0 -16
- package/dist/practices/lambda-clients/best-practice/package.json +0 -5
- package/dist/practices/lambda-clients/best-practice/src/data/clients/<star>.ts +0 -1
- package/dist/practices/lambda-clients/best-practice/src/data/clients/<star>.ts.declapract.ts +0 -3
- package/dist/practices/lambda-handlers/best-practice/package.json +0 -6
- package/dist/practices/lambda-handlers/best-practice/package.json.declapract.ts +0 -3
- package/dist/practices/lambda-handlers/best-practice/src/contract/handlers/<star><star>/<star>.declapract.ts +0 -3
- package/dist/practices/runtime-type-checking/bad-practices/joi-types/package.json +0 -5
- package/dist/practices/runtime-type-checking/bad-practices/joi-types/package.json.declapract.ts +0 -18
- package/dist/practices/runtime-type-checking/bad-practices/old-joi-syntax-valid-input-cant-be-array/.declapract.readme.md +0 -1
- package/dist/practices/runtime-type-checking/bad-practices/old-joi-syntax-valid-input-cant-be-array/src/<star><star>/<star>.ts.declapract.ts +0 -15
- package/dist/practices/runtime-type-checking/best-practice/package.json.declapract.ts +0 -3
- /package/dist/practices/config/bad-practices/configs-contain-wrong-account-id/config/{dev.json.declapract.ts → prep.json.declapract.ts} +0 -0
- /package/dist/practices/{runtime-type-checking → runtime-schemas}/bad-practices/joi/.declapract.readme.md +0 -0
- /package/dist/practices/{runtime-type-checking → runtime-schemas}/bad-practices/joi/package.json +0 -0
- /package/dist/practices/{runtime-type-checking → runtime-schemas}/best-practice/package.json +0 -0
- /package/dist/practices/{lambda-clients → runtime-schemas}/best-practice/package.json.declapract.ts +0 -0
- /package/dist/practices/terraform-aws/best-practice/provision/aws/environments/{dev → prep}/versions.tf +0 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# simple-lambda-client
|
|
2
|
+
|
|
3
|
+
## what
|
|
4
|
+
|
|
5
|
+
detects and transforms simple-lambda-client usage to sdk-aws-lambda.
|
|
6
|
+
|
|
7
|
+
## why
|
|
8
|
+
|
|
9
|
+
sdk-aws-lambda provides modern lambda client patterns:
|
|
10
|
+
- context-based configuration
|
|
11
|
+
- trail.exid auto-propagation through call chain
|
|
12
|
+
- better cache support
|
|
13
|
+
|
|
14
|
+
## transforms
|
|
15
|
+
|
|
16
|
+
| old | new |
|
|
17
|
+
|-----|-----|
|
|
18
|
+
| `import { invokeLambdaFunction } from 'simple-lambda-client'` | `import { askLambdaEndpoint } from 'sdk-aws-lambda'` |
|
|
19
|
+
| `invokeLambdaFunction(...)` | `askLambdaEndpoint(...)` |
|
|
20
|
+
|
|
21
|
+
## limitations
|
|
22
|
+
|
|
23
|
+
these patterns require manual migration:
|
|
24
|
+
|
|
25
|
+
- `{ service, function, stage, event }` → `{ which: { service, function }, event }, context`
|
|
26
|
+
- `stage: string` → `context.env.access: string`
|
|
27
|
+
- `logDebug?: LogMethod` → `context.log: LogMethods` (required)
|
|
28
|
+
- `cache?: SimpleCache<O>` → `context.cache?: { response?, dedupe? }`
|
|
29
|
+
|
|
30
|
+
## example
|
|
31
|
+
|
|
32
|
+
before:
|
|
33
|
+
```ts
|
|
34
|
+
import { invokeLambdaFunction } from 'simple-lambda-client';
|
|
35
|
+
|
|
36
|
+
const result = await invokeLambdaFunction({
|
|
37
|
+
service: 'svc-users',
|
|
38
|
+
function: 'getUser',
|
|
39
|
+
stage: 'prod',
|
|
40
|
+
event: { userId: '123' },
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
after (requires manual refinement):
|
|
45
|
+
```ts
|
|
46
|
+
import { askLambdaEndpoint } from 'sdk-aws-lambda';
|
|
47
|
+
|
|
48
|
+
const result = await askLambdaEndpoint(
|
|
49
|
+
{
|
|
50
|
+
which: { service: 'svc-users', function: 'getUser' },
|
|
51
|
+
event: { userId: '123' },
|
|
52
|
+
},
|
|
53
|
+
{ log, env: { access: 'prod' } },
|
|
54
|
+
);
|
|
55
|
+
```
|
package/dist/practices/node-service/bad-practices/simple-lambda-client/package.json.declapract.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { FileCheckType, type FileFixFunction } from 'declapract';
|
|
2
|
+
|
|
3
|
+
export const check = FileCheckType.CONTAINS;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* .what = removes simple-lambda-client and adds sdk-aws-lambda
|
|
7
|
+
* .why = sdk-aws-lambda is the modern replacement with better patterns
|
|
8
|
+
*/
|
|
9
|
+
export const fix: FileFixFunction = (contents) => {
|
|
10
|
+
if (!contents) return { contents };
|
|
11
|
+
|
|
12
|
+
const packageJSON = JSON.parse(contents);
|
|
13
|
+
|
|
14
|
+
const updatedPackageJSON = {
|
|
15
|
+
...packageJSON,
|
|
16
|
+
dependencies: {
|
|
17
|
+
...packageJSON.dependencies,
|
|
18
|
+
'simple-lambda-client': undefined,
|
|
19
|
+
'sdk-aws-lambda':
|
|
20
|
+
packageJSON.dependencies?.['sdk-aws-lambda'] ?? '^0.1.0',
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
contents: JSON.stringify(updatedPackageJSON, null, 2),
|
|
26
|
+
};
|
|
27
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { FileCheckFunction, FileFixFunction } from 'declapract';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* .what = detects simple-lambda-client imports in source files
|
|
5
|
+
* .why = simple-lambda-client should be replaced with sdk-aws-lambda
|
|
6
|
+
*/
|
|
7
|
+
export const check: FileCheckFunction = (contents) => {
|
|
8
|
+
// match if file imports from simple-lambda-client
|
|
9
|
+
if (contents?.includes("from 'simple-lambda-client'")) return;
|
|
10
|
+
if (contents?.includes('from "simple-lambda-client"')) return;
|
|
11
|
+
|
|
12
|
+
// no match
|
|
13
|
+
throw new Error('does not import from simple-lambda-client');
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* .what = transforms simple-lambda-client imports to sdk-aws-lambda
|
|
18
|
+
* .why = automated migration reduces manual toil
|
|
19
|
+
*
|
|
20
|
+
* .note = basic transforms only; complex patterns require manual fix
|
|
21
|
+
*
|
|
22
|
+
* API map:
|
|
23
|
+
* - invokeLambdaFunction → askLambdaEndpoint
|
|
24
|
+
*/
|
|
25
|
+
export const fix: FileFixFunction = (contents) => {
|
|
26
|
+
if (!contents) return {};
|
|
27
|
+
|
|
28
|
+
const updated = contents
|
|
29
|
+
// transform imports
|
|
30
|
+
.replace(
|
|
31
|
+
/import\s+\{([^}]*)\}\s+from\s+['"]simple-lambda-client['"]/g,
|
|
32
|
+
(match, imports) => {
|
|
33
|
+
const updatedImports = imports.replace(
|
|
34
|
+
/invokeLambdaFunction/g,
|
|
35
|
+
'askLambdaEndpoint',
|
|
36
|
+
);
|
|
37
|
+
return `import {${updatedImports}} from 'sdk-aws-lambda'`;
|
|
38
|
+
},
|
|
39
|
+
)
|
|
40
|
+
// transform function calls
|
|
41
|
+
.replace(/invokeLambdaFunction/g, 'askLambdaEndpoint');
|
|
42
|
+
|
|
43
|
+
return { contents: updated };
|
|
44
|
+
};
|
package/dist/practices/node-service/bad-practices/simple-lambda-handlers/.declapract.readme.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# simple-lambda-handlers
|
|
2
|
+
|
|
3
|
+
## what
|
|
4
|
+
|
|
5
|
+
detects and transforms simple-lambda-handlers usage to sdk-aws-lambda.
|
|
6
|
+
|
|
7
|
+
## why
|
|
8
|
+
|
|
9
|
+
sdk-aws-lambda provides modern lambda handler patterns:
|
|
10
|
+
- better schema validation with zod (input + output)
|
|
11
|
+
- log context passed to invoke function
|
|
12
|
+
- trail.exid auto-propagation
|
|
13
|
+
|
|
14
|
+
## transforms
|
|
15
|
+
|
|
16
|
+
| old | new |
|
|
17
|
+
|-----|-----|
|
|
18
|
+
| `import { createStandardHandler } from 'simple-lambda-handlers'` | `import { genLambdaEndpoint } from 'sdk-aws-lambda'` |
|
|
19
|
+
| `import { createApiGatewayHandler } from 'simple-lambda-handlers'` | `import { genLambdaEndpoint } from 'sdk-aws-lambda'` |
|
|
20
|
+
| `createStandardHandler(...)` | `genLambdaEndpoint(...)` |
|
|
21
|
+
| `createApiGatewayHandler(...)` | `genLambdaEndpoint.for.apiGateway(...)` |
|
|
22
|
+
|
|
23
|
+
## limitations
|
|
24
|
+
|
|
25
|
+
these patterns require manual migration:
|
|
26
|
+
|
|
27
|
+
- `schema` (single joi) → `schema: { input, output }` (split zod)
|
|
28
|
+
- `logic: (event) => O` → `invoke: ({ event }, { log }) => O`
|
|
29
|
+
- `log` passed at creation → `log` also received in invoke context
|
|
30
|
+
|
|
31
|
+
## example
|
|
32
|
+
|
|
33
|
+
before:
|
|
34
|
+
```ts
|
|
35
|
+
import { createStandardHandler } from 'simple-lambda-handlers';
|
|
36
|
+
|
|
37
|
+
export const handler = createStandardHandler({
|
|
38
|
+
log,
|
|
39
|
+
schema,
|
|
40
|
+
logic: async (event) => doStuff(event),
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
after (requires manual refinement):
|
|
45
|
+
```ts
|
|
46
|
+
import { genLambdaEndpoint } from 'sdk-aws-lambda';
|
|
47
|
+
|
|
48
|
+
export const handler = genLambdaEndpoint({
|
|
49
|
+
schema: { input: inputSchema, output: outputSchema },
|
|
50
|
+
invoke: async ({ event }, { log }) => doStuff(event),
|
|
51
|
+
}, { log });
|
|
52
|
+
```
|
package/dist/practices/node-service/bad-practices/simple-lambda-handlers/package.json.declapract.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { FileCheckType, type FileFixFunction } from 'declapract';
|
|
2
|
+
|
|
3
|
+
export const check = FileCheckType.CONTAINS;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* .what = removes simple-lambda-handlers and adds sdk-aws-lambda
|
|
7
|
+
* .why = sdk-aws-lambda is the modern replacement with better patterns
|
|
8
|
+
*/
|
|
9
|
+
export const fix: FileFixFunction = (contents) => {
|
|
10
|
+
if (!contents) return { contents };
|
|
11
|
+
|
|
12
|
+
const packageJSON = JSON.parse(contents);
|
|
13
|
+
|
|
14
|
+
const updatedPackageJSON = {
|
|
15
|
+
...packageJSON,
|
|
16
|
+
dependencies: {
|
|
17
|
+
...packageJSON.dependencies,
|
|
18
|
+
'simple-lambda-handlers': undefined,
|
|
19
|
+
'sdk-aws-lambda':
|
|
20
|
+
packageJSON.dependencies?.['sdk-aws-lambda'] ?? '^0.1.0',
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
contents: JSON.stringify(updatedPackageJSON, null, 2),
|
|
26
|
+
};
|
|
27
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { FileCheckFunction, FileFixFunction } from 'declapract';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* .what = detects simple-lambda-handlers imports in source files
|
|
5
|
+
* .why = simple-lambda-handlers should be replaced with sdk-aws-lambda
|
|
6
|
+
*/
|
|
7
|
+
export const check: FileCheckFunction = (contents) => {
|
|
8
|
+
// match if file imports from simple-lambda-handlers
|
|
9
|
+
if (contents?.includes("from 'simple-lambda-handlers'")) return;
|
|
10
|
+
if (contents?.includes('from "simple-lambda-handlers"')) return;
|
|
11
|
+
|
|
12
|
+
// no match
|
|
13
|
+
throw new Error('does not import from simple-lambda-handlers');
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* .what = transforms simple-lambda-handlers imports to sdk-aws-lambda
|
|
18
|
+
* .why = automated migration reduces manual toil
|
|
19
|
+
*
|
|
20
|
+
* .note = basic transforms only; complex patterns require manual fix
|
|
21
|
+
*
|
|
22
|
+
* API map:
|
|
23
|
+
* - createStandardHandler → genLambdaEndpoint
|
|
24
|
+
* - createApiGatewayHandler → genLambdaEndpoint.for.apiGateway
|
|
25
|
+
*/
|
|
26
|
+
export const fix: FileFixFunction = (contents) => {
|
|
27
|
+
if (!contents) return {};
|
|
28
|
+
|
|
29
|
+
const updated = contents
|
|
30
|
+
// transform imports (dedupe to avoid duplicate genLambdaEndpoint)
|
|
31
|
+
.replace(
|
|
32
|
+
/import\s+\{([^}]*)\}\s+from\s+['"]simple-lambda-handlers['"]/g,
|
|
33
|
+
(match, imports) => {
|
|
34
|
+
// split, replace, dedupe, join
|
|
35
|
+
const importList = imports.split(',').map((s: string) => s.trim());
|
|
36
|
+
const transformed = importList.map((name: string) => {
|
|
37
|
+
if (name === 'createStandardHandler') return 'genLambdaEndpoint';
|
|
38
|
+
if (name === 'createApiGatewayHandler') return 'genLambdaEndpoint';
|
|
39
|
+
return name;
|
|
40
|
+
});
|
|
41
|
+
const deduped = [...new Set(transformed)];
|
|
42
|
+
return `import { ${deduped.join(', ')} } from 'sdk-aws-lambda'`;
|
|
43
|
+
},
|
|
44
|
+
)
|
|
45
|
+
// transform function calls
|
|
46
|
+
.replace(/createStandardHandler/g, 'genLambdaEndpoint')
|
|
47
|
+
.replace(/createApiGatewayHandler/g, 'genLambdaEndpoint.for.apiGateway');
|
|
48
|
+
|
|
49
|
+
return { contents: updated };
|
|
50
|
+
};
|
|
@@ -53,7 +53,7 @@ export const desiredRelativeKeyOrder = {
|
|
|
53
53
|
'provision:testdb:docker:down',
|
|
54
54
|
'provision:testdb',
|
|
55
55
|
'start:testdb',
|
|
56
|
-
'start:livedb:
|
|
56
|
+
'start:livedb:prep',
|
|
57
57
|
'test:auth',
|
|
58
58
|
'test:commits',
|
|
59
59
|
'test:types',
|
|
@@ -82,34 +82,34 @@ export const desiredRelativeKeyOrder = {
|
|
|
82
82
|
'deploy:prune',
|
|
83
83
|
'deploy:release',
|
|
84
84
|
'deploy:send-notification',
|
|
85
|
-
'deploy:
|
|
85
|
+
'deploy:prep',
|
|
86
86
|
'deploy:prod',
|
|
87
87
|
'deploy',
|
|
88
88
|
|
|
89
89
|
// from app-react-native-expo
|
|
90
90
|
'start:hot:proxy',
|
|
91
|
-
'start:hot:
|
|
92
|
-
'start:hot:
|
|
93
|
-
'start:hot:
|
|
91
|
+
'start:hot:prep',
|
|
92
|
+
'start:hot:prep:link',
|
|
93
|
+
'start:hot:prep:proxy',
|
|
94
94
|
'start:hot:prod',
|
|
95
95
|
'start:hot:prod:link',
|
|
96
96
|
'start:hot:prod:proxy',
|
|
97
97
|
'start:cold:proxy',
|
|
98
|
-
'start:cold:
|
|
99
|
-
'start:cold:
|
|
100
|
-
'start:cold:
|
|
98
|
+
'start:cold:prep',
|
|
99
|
+
'start:cold:prep:link',
|
|
100
|
+
'start:cold:prep:proxy',
|
|
101
101
|
'start:cold:prod',
|
|
102
102
|
'start:cold:prod:link',
|
|
103
103
|
'register:device:apple:info',
|
|
104
104
|
'register:device:apple:inclusions:rebuild:prod',
|
|
105
|
-
'register:device:apple:inclusions:rebuild:
|
|
105
|
+
'register:device:apple:inclusions:rebuild:prep',
|
|
106
106
|
'register:device:apple:add',
|
|
107
107
|
'register:device:apple:list',
|
|
108
108
|
'register:device:apple:delete',
|
|
109
109
|
'register:device:apple:rename',
|
|
110
110
|
'register:profile:apple:list',
|
|
111
|
-
'build:
|
|
112
|
-
'build:
|
|
111
|
+
'build:prep:ios',
|
|
112
|
+
'build:prep:android',
|
|
113
113
|
'build:web',
|
|
114
114
|
'deploy:prod:ios:metadata',
|
|
115
115
|
'open:store:android',
|
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
we use:
|
|
2
2
|
- postgres database
|
|
3
|
-
- provisioned by aws rds aurora when in
|
|
3
|
+
- provisioned by aws rds aurora when in prep and prod env
|
|
4
4
|
- provisioned by docker when in test env
|
|
5
5
|
- sql-schema-control to manage sql schema
|
|
6
6
|
- sql-dao-generator to generate the sql-schemas + daos
|
|
7
|
+
|
|
8
|
+
## required variables
|
|
9
|
+
|
|
10
|
+
| variable | description | example |
|
|
11
|
+
|----------|-------------|---------|
|
|
12
|
+
| `databaseTunnelHost.{prep,prod}` | ssm proxy host for database tunnel | `aws.ssmproxy.ahbodedb.prep` |
|
|
13
|
+
| `databaseClusterHost.{prep,prod}` | rds cluster endpoint | `ahbodedb.cluster-xxx.us-east-1.rds.amazonaws.com` |
|
|
14
|
+
|
|
15
|
+
## ssm parameters
|
|
16
|
+
|
|
17
|
+
terraform provisions these ssm parameters for database credentials:
|
|
18
|
+
|
|
19
|
+
| parameter name | description | environments |
|
|
20
|
+
|----------------|-------------|--------------|
|
|
21
|
+
| `{namespace}.database.role.cicd.password` | password for cicd database user | prep, prod |
|
|
22
|
+
| `{namespace}.database.role.crud.password` | password for crud database user | prep, prod |
|
|
23
|
+
|
|
24
|
+
legacy parameters (kept for backwards compatibility):
|
|
25
|
+
- `{namespace}.database.admin.password`
|
|
26
|
+
- `{namespace}.database.service.password`
|
package/dist/practices/persist-with-rds/best-practice/provision/aws/product/parameter-store.tf
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
# ====================
|
|
2
|
+
# legacy params (kept for backwards compatibility)
|
|
3
|
+
# ====================
|
|
1
4
|
resource "aws_ssm_parameter" "secret_database_admin_password" {
|
|
2
5
|
name = "${local.parameter_store_namespace}.database.admin.password"
|
|
3
6
|
type = "SecureString"
|
|
@@ -22,3 +25,39 @@ resource "aws_ssm_parameter" "secret_database_service_password" {
|
|
|
22
25
|
]
|
|
23
26
|
}
|
|
24
27
|
}
|
|
28
|
+
|
|
29
|
+
# ====================
|
|
30
|
+
# new role-based params (standard naming)
|
|
31
|
+
# ====================
|
|
32
|
+
# read legacy params to copy values (prod only)
|
|
33
|
+
data "aws_ssm_parameter" "legacy_admin_password" {
|
|
34
|
+
name = "${local.parameter_store_namespace}.database.admin.password"
|
|
35
|
+
count = var.environment == "prod" ? 1 : 0
|
|
36
|
+
with_decryption = true
|
|
37
|
+
}
|
|
38
|
+
data "aws_ssm_parameter" "legacy_service_password" {
|
|
39
|
+
name = "${local.parameter_store_namespace}.database.service.password"
|
|
40
|
+
count = var.environment == "prod" ? 1 : 0
|
|
41
|
+
with_decryption = true
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
resource "aws_ssm_parameter" "secret_database_role_cicd_password" {
|
|
45
|
+
name = "${local.parameter_store_namespace}.database.role.cicd.password"
|
|
46
|
+
type = "SecureString"
|
|
47
|
+
value = var.environment == "prod" ? data.aws_ssm_parameter.legacy_admin_password[0].value : "__CHANG3_ME__"
|
|
48
|
+
tags = local.tags
|
|
49
|
+
count = var.environment != "test" ? 1 : 0
|
|
50
|
+
lifecycle {
|
|
51
|
+
ignore_changes = [value]
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
resource "aws_ssm_parameter" "secret_database_role_crud_password" {
|
|
55
|
+
name = "${local.parameter_store_namespace}.database.role.crud.password"
|
|
56
|
+
type = "SecureString"
|
|
57
|
+
value = var.environment == "prod" ? data.aws_ssm_parameter.legacy_service_password[0].value : "__CHANG3_ME__"
|
|
58
|
+
tags = local.tags
|
|
59
|
+
count = var.environment != "test" ? 1 : 0
|
|
60
|
+
lifecycle {
|
|
61
|
+
ignore_changes = [value]
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -13,20 +13,20 @@
|
|
|
13
13
|
##
|
|
14
14
|
## usage example:
|
|
15
15
|
## ```sh
|
|
16
|
-
## ./provision/schema/deploy.database.sh
|
|
16
|
+
## ./provision/schema/deploy.database.sh prep $(op item get ahbodedb.prep.postgres --fields label=password --format json | jq -r .value)
|
|
17
17
|
## ```
|
|
18
18
|
#####################################################
|
|
19
19
|
|
|
20
20
|
# check that user has defined the environment that they want this key created for correctly
|
|
21
21
|
ENVIRONMENT=$1;
|
|
22
|
-
if [ "$ENVIRONMENT" != "prod" ] && [ "$ENVIRONMENT" != "
|
|
23
|
-
echo "\nerror: Environment, the first argument, must be specified as either 'prod' or '
|
|
22
|
+
if [ "$ENVIRONMENT" != "prod" ] && [ "$ENVIRONMENT" != "prep" ]; then
|
|
23
|
+
echo "\nerror: Environment, the first argument, must be specified as either 'prod' or 'prep'. You specified '$ENVIRONMENT'";
|
|
24
24
|
exit 1;
|
|
25
25
|
fi
|
|
26
26
|
|
|
27
27
|
# check that user is authed into correct account
|
|
28
28
|
AWS_ACCOUNT_ID=$(aws sts get-caller-identity | jq -r '.Account');
|
|
29
|
-
EXPECTED_AWS_ACCOUNT_ID=$([ "$ENVIRONMENT" = 'prod' ] && echo "@declapract{variable.awsAccountId.prod}" || echo "@declapract{variable.awsAccountId.
|
|
29
|
+
EXPECTED_AWS_ACCOUNT_ID=$([ "$ENVIRONMENT" = 'prod' ] && echo "@declapract{variable.awsAccountId.prod}" || echo "@declapract{variable.awsAccountId.prep}");
|
|
30
30
|
if [ "$AWS_ACCOUNT_ID" != "$EXPECTED_AWS_ACCOUNT_ID" ]; then
|
|
31
31
|
echo "\nerror: the AWS_ACCOUNT that you are signed into is not correct for the environment you specified. You are authed into account '$AWS_ACCOUNT_ID' but the correct account id for '$ENVIRONMENT' IS '$EXPECTED_AWS_ACCOUNT_ID'";
|
|
32
32
|
exit 1;
|
|
@@ -41,20 +41,20 @@ fi;
|
|
|
41
41
|
|
|
42
42
|
# check that the cicd password was provisioned, if in prod, since this is used to create the cicd user
|
|
43
43
|
if [ "$ENVIRONMENT" = "prod" ]; then
|
|
44
|
-
CICD_USER_PASSWORD=$(aws ssm get-parameter --name "@declapract{variable.organizationName}.@declapract{variable.projectName}.$ENVIRONMENT.database.
|
|
44
|
+
CICD_USER_PASSWORD=$(aws ssm get-parameter --name "@declapract{variable.organizationName}.@declapract{variable.projectName}.$ENVIRONMENT.database.role.cicd.password" --with-decryption --output text --query Parameter.Value)
|
|
45
45
|
if [ -z "$CICD_USER_PASSWORD" ]; then
|
|
46
46
|
echo "\nerror: CICD_USER_PASSWORD must be provisioned with terraform before running this"
|
|
47
47
|
exit 1;
|
|
48
48
|
fi;
|
|
49
|
-
if [ "$CICD_USER_PASSWORD" = "__IGNORED__" ]; then
|
|
50
|
-
echo "\nerror: CICD_USER_PASSWORD must be set to a value other than the default
|
|
49
|
+
if [ "$CICD_USER_PASSWORD" = "__IGNORED__" ] || [ "$CICD_USER_PASSWORD" = "__CHANG3_ME__" ]; then
|
|
50
|
+
echo "\nerror: CICD_USER_PASSWORD must be set to a value other than the default placeholder"
|
|
51
51
|
exit 1;
|
|
52
52
|
fi;
|
|
53
53
|
fi;
|
|
54
54
|
|
|
55
55
|
|
|
56
56
|
# define the postgres connecition string
|
|
57
|
-
CLUSTER_HOST=$([ "$ENVIRONMENT" = 'prod' ] && echo "@declapract{variable.databaseTunnelHost.prod}" || echo "@declapract{variable.databaseTunnelHost.
|
|
57
|
+
CLUSTER_HOST=$([ "$ENVIRONMENT" = 'prod' ] && echo "@declapract{variable.databaseTunnelHost.prod}" || echo "@declapract{variable.databaseTunnelHost.prep}");
|
|
58
58
|
CLUSTER_CONNECTION_STRING=postgresql://postgres:$POSTGRES_ADMIN_PASSWORD@$CLUSTER_HOST:5432
|
|
59
59
|
ROOT_DB_CONNECTION_STRING=$CLUSTER_CONNECTION_STRING/postgres
|
|
60
60
|
SVC_DB_CONNECTION_STRING=$CLUSTER_CONNECTION_STRING/@declapract{variable.databaseName}
|
|
@@ -75,7 +75,7 @@ echo "\n 🔨 creating the schema..."
|
|
|
75
75
|
psql $SVC_DB_CONNECTION_STRING -f $INIT_SQLS_DIR/.schema.sql
|
|
76
76
|
|
|
77
77
|
if [ "$ENVIRONMENT" = "prod" ]; then
|
|
78
|
-
echo "\n 🔨 granting reads to the datalakedb user..." # only in prod env; we dont want
|
|
78
|
+
echo "\n 🔨 granting reads to the datalakedb user..." # only in prod env; we dont want prep's test data in our datalake
|
|
79
79
|
psql $SVC_DB_CONNECTION_STRING -f $INIT_SQLS_DIR/.user.datalakedb.sql
|
|
80
80
|
fi;
|
|
81
81
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
provisions github repository settings and environments via declastruct-github-sdk.
|
|
2
|
+
|
|
3
|
+
## required variables
|
|
4
|
+
|
|
5
|
+
| variable | description | example |
|
|
6
|
+
|----------|-------------|---------|
|
|
7
|
+
| `reviewers.users` | github usernames for production deployment reviewers | `['whodisio', 'ehmpathy']` |
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { FileCheckType, type FileFixFunction } from 'declapract';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* .what = detects committed peer-review artifacts under .behavior/**\/.reviews
|
|
5
|
+
* .why = peer-review files are noise; far less important than the root behavior
|
|
6
|
+
* files, so they should not be tracked in git
|
|
7
|
+
*
|
|
8
|
+
* .note = matches the old flat shape, where peer-review files sit directly in
|
|
9
|
+
* .reviews with `peer-review` in the filename
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export const check = FileCheckType.EXISTS;
|
|
13
|
+
|
|
14
|
+
export const fix: FileFixFunction = () => {
|
|
15
|
+
return { contents: null }; // delete the file
|
|
16
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { FileCheckType, type FileFixFunction } from 'declapract';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* .what = detects committed peer-review artifacts under .behavior/**\/.reviews/peer
|
|
5
|
+
* .why = peer-review files are noise; far less important than the root behavior
|
|
6
|
+
* files, so they should not be tracked in git
|
|
7
|
+
*
|
|
8
|
+
* .note = matches the new shape, where all peer-review files live under a
|
|
9
|
+
* dedicated `peer` directory
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export const check = FileCheckType.EXISTS;
|
|
13
|
+
|
|
14
|
+
export const fix: FileFixFunction = () => {
|
|
15
|
+
return { contents: null }; // delete the file
|
|
16
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
peer review artifacts should not be committed to git
|
|
2
|
+
|
|
3
|
+
these files live under `.behavior/**/.reviews/` and capture peer-review feedback
|
|
4
|
+
from the behavior build lifecycle. they are noise for the most part — far less
|
|
5
|
+
important than the root behavior files themselves.
|
|
6
|
+
|
|
7
|
+
two path shapes are removed:
|
|
8
|
+
|
|
9
|
+
- old (flat): `.behavior/**/.reviews/**/*peer-review*.md`
|
|
10
|
+
- new (peer dir): `.behavior/**/.reviews/peer/**/*.md`
|
|
11
|
+
|
|
12
|
+
self-reviews and other non-peer artifacts under `.reviews/` are intentionally left alone.
|
|
@@ -12,6 +12,10 @@ export const fix: FileFixFunction = (contents) => {
|
|
|
12
12
|
joi: undefined,
|
|
13
13
|
zod: packageJSON.dependencies?.zod ?? '^3.24.0',
|
|
14
14
|
},
|
|
15
|
+
devDependencies: {
|
|
16
|
+
...packageJSON.devDependencies,
|
|
17
|
+
'@types/joi': undefined,
|
|
18
|
+
},
|
|
15
19
|
};
|
|
16
20
|
return {
|
|
17
21
|
contents: JSON.stringify(updatedPackageJSON, null, 2),
|
package/dist/practices/runtime-schemas/bad-practices/joi/src/<star><star>/<star>.ts.declapract.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { FileCheckFunction, FileFixFunction } from 'declapract';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* .what = detects joi imports in source files
|
|
5
|
+
* .why = joi should be replaced with zod for better typescript integration
|
|
6
|
+
*/
|
|
7
|
+
export const check: FileCheckFunction = (contents) => {
|
|
8
|
+
// match if file imports from joi
|
|
9
|
+
if (contents?.includes("from 'joi'")) return;
|
|
10
|
+
if (contents?.includes('from "joi"')) return;
|
|
11
|
+
|
|
12
|
+
// no match
|
|
13
|
+
throw new Error('does not import from joi');
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* .what = transforms joi imports and basic schema patterns to zod
|
|
18
|
+
* .why = automated migration reduces manual toil
|
|
19
|
+
*
|
|
20
|
+
* .note = basic transforms only; complex patterns require manual fix
|
|
21
|
+
*/
|
|
22
|
+
export const fix: FileFixFunction = (contents) => {
|
|
23
|
+
if (!contents) return {};
|
|
24
|
+
|
|
25
|
+
const updated = contents
|
|
26
|
+
// transform imports: import Joi from 'joi' → import { z } from 'zod'
|
|
27
|
+
.replace(/import\s+Joi\s+from\s+['"]joi['"]/g, "import { z } from 'zod'")
|
|
28
|
+
// transform imports: import * as Joi from 'joi' → import { z } from 'zod'
|
|
29
|
+
.replace(
|
|
30
|
+
/import\s+\*\s+as\s+Joi\s+from\s+['"]joi['"]/g,
|
|
31
|
+
"import { z } from 'zod'",
|
|
32
|
+
)
|
|
33
|
+
// transform imports: import { ... } from 'joi' → import { z } from 'zod'
|
|
34
|
+
.replace(
|
|
35
|
+
/import\s+\{[^}]*\}\s+from\s+['"]joi['"]/g,
|
|
36
|
+
"import { z } from 'zod'",
|
|
37
|
+
)
|
|
38
|
+
// transform basic schema patterns: Joi.* → z.*
|
|
39
|
+
.replace(/Joi\.object/g, 'z.object')
|
|
40
|
+
.replace(/Joi\.string/g, 'z.string')
|
|
41
|
+
.replace(/Joi\.number/g, 'z.number')
|
|
42
|
+
.replace(/Joi\.boolean/g, 'z.boolean')
|
|
43
|
+
.replace(/Joi\.array/g, 'z.array')
|
|
44
|
+
.replace(/Joi\.date/g, 'z.date')
|
|
45
|
+
.replace(/Joi\.any/g, 'z.any')
|
|
46
|
+
// transform .required() → remove (zod is required by default)
|
|
47
|
+
.replace(/\.required\(\)/g, '');
|
|
48
|
+
|
|
49
|
+
return { contents: updated };
|
|
50
|
+
};
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
"if-env": "@declapract{check.minVersion('1.0.4')}"
|
|
6
6
|
},
|
|
7
7
|
"scripts": {
|
|
8
|
-
"deploy:prune": "SLS_STAGE=$(
|
|
9
|
-
"deploy:release": "SLS_STAGE=$(
|
|
8
|
+
"deploy:prune": "export COMMIT=$(npx sdk-environment get commit) && export SLS_STAGE=$([ \"$ACCESS\" = 'prep' ] && echo 'dev' || echo \"$ACCESS\") && npx sls prune -n 7 --stage $SLS_STAGE",
|
|
9
|
+
"deploy:release": "export COMMIT=$(npx sdk-environment get commit) && export SLS_STAGE=$([ \"$ACCESS\" = 'prep' ] && echo 'dev' || echo \"$ACCESS\") && npm run build && sls deploy --verbose --stage $SLS_STAGE",
|
|
10
10
|
"deploy:send-notification": "curl -X POST -H 'Content-type: application/json' --data \"{\\\"text\\\":\\\"$([ -z $DEPLOYER_NAME ] && git config user.name || echo $DEPLOYER_NAME) has deployed $npm_package_name@v$npm_package_version:\nhttps://github.com/@declapract{variable.organizationName}/$npm_package_name/tree/v$npm_package_version\\\"}\" @declapract{variable.slackWebhookUrl}",
|
|
11
11
|
"deploy:prep": "ACCESS=prep npm run deploy:release",
|
|
12
12
|
"deploy:prod": "ACCESS=prod npm run deploy:release && npm run deploy:send-notification",
|
|
@@ -10,7 +10,7 @@ plugins:
|
|
|
10
10
|
|
|
11
11
|
custom:
|
|
12
12
|
accessByStage:
|
|
13
|
-
dev: prep
|
|
13
|
+
dev: prep # stage=dev deploys to $service-dev but uses ACCESS=prep (config/prep.json)
|
|
14
14
|
prod: prod
|
|
15
15
|
|
|
16
16
|
provider:
|
|
@@ -25,8 +25,8 @@ provider:
|
|
|
25
25
|
product: ${self:service}
|
|
26
26
|
environment:
|
|
27
27
|
TZ: UTC # guarantee that utc timezone will be used explicitly, to facilitate a pit of success
|
|
28
|
-
NODE_ENV: production # deploy with production optimizations of all resources, to make `
|
|
29
|
-
ACCESS: ${self:custom.accessByStage.${opt:stage}, 'prep'} # sdk-environment access tier, to target the correct config + resources (e.g., hit
|
|
28
|
+
NODE_ENV: production # deploy with production optimizations of all resources, to make `prep` and `prod` stage deployments equivalent functionally (i.e., the same code paths in prep and prod)
|
|
29
|
+
ACCESS: ${self:custom.accessByStage.${opt:stage}, 'prep'} # sdk-environment access tier, to target the correct config + resources (e.g., hit prep db -vs- prod db)
|
|
30
30
|
COMMIT: ${env:COMMIT} # sdk-environment commit slug, must be set by deploy command
|
|
31
31
|
AWS_NODEJS_CONNECTION_REUSE_ENABLED: true # https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/node-reusing-connections.html
|
|
32
32
|
deploymentBucket: serverless-deployment-@declapract{variable.infrastructureNamespaceId}-${self:provider.stage}
|
|
@@ -11,7 +11,7 @@ const accessInferencePolicy = ` # allow access inference from account name
|
|
|
11
11
|
|
|
12
12
|
const accessByStageCustom = `custom:
|
|
13
13
|
accessByStage:
|
|
14
|
-
dev: prep
|
|
14
|
+
dev: prep # stage=dev deploys to $service-dev but uses ACCESS=prep (config/prep.json)
|
|
15
15
|
prod: prod
|
|
16
16
|
|
|
17
17
|
`;
|
|
@@ -70,7 +70,7 @@ export const fix: FileFixFunction = (contents) => {
|
|
|
70
70
|
) {
|
|
71
71
|
fixed = fixed.replace(
|
|
72
72
|
/STAGE: \$\{self:provider\.stage\}[^\n]*/,
|
|
73
|
-
"ACCESS: ${self:custom.accessByStage.${opt:stage}, 'prep'} # sdk-environment access tier, to target the correct config + resources (e.g., hit
|
|
73
|
+
"ACCESS: ${self:custom.accessByStage.${opt:stage}, 'prep'} # sdk-environment access tier, to target the correct config + resources (e.g., hit prep db -vs- prod db)\n COMMIT: ${env:COMMIT} # sdk-environment commit slug, must be set by deploy command",
|
|
74
74
|
);
|
|
75
75
|
}
|
|
76
76
|
|