@codyswann/lisa 1.0.0
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/LICENSE +21 -0
- package/README.md +867 -0
- package/all/copy-overwrite/.claude/README.md +205 -0
- package/all/copy-overwrite/.claude/agents/agent-architect.md +311 -0
- package/all/copy-overwrite/.claude/agents/codebase-analyzer.md +146 -0
- package/all/copy-overwrite/.claude/agents/codebase-locator.md +125 -0
- package/all/copy-overwrite/.claude/agents/codebase-pattern-finder.md +237 -0
- package/all/copy-overwrite/.claude/agents/git-history-analyzer.md +183 -0
- package/all/copy-overwrite/.claude/agents/hooks-expert.md +74 -0
- package/all/copy-overwrite/.claude/agents/skill-evaluator.md +246 -0
- package/all/copy-overwrite/.claude/agents/slash-command-architect.md +87 -0
- package/all/copy-overwrite/.claude/agents/web-search-researcher.md +112 -0
- package/all/copy-overwrite/.claude/commands/git/commit-and-submit-pr.md +8 -0
- package/all/copy-overwrite/.claude/commands/git/commit.md +44 -0
- package/all/copy-overwrite/.claude/commands/git/prune.md +34 -0
- package/all/copy-overwrite/.claude/commands/git/submit-pr.md +50 -0
- package/all/copy-overwrite/.claude/commands/jira/create.md +50 -0
- package/all/copy-overwrite/.claude/commands/jira/verify.md +34 -0
- package/all/copy-overwrite/.claude/commands/project/archive.md +8 -0
- package/all/copy-overwrite/.claude/commands/project/bootstrap.md +49 -0
- package/all/copy-overwrite/.claude/commands/project/complete-task.md +7 -0
- package/all/copy-overwrite/.claude/commands/project/debrief.md +65 -0
- package/all/copy-overwrite/.claude/commands/project/execute.md +94 -0
- package/all/copy-overwrite/.claude/commands/project/implement.md +42 -0
- package/all/copy-overwrite/.claude/commands/project/local-code-review.md +88 -0
- package/all/copy-overwrite/.claude/commands/project/lower-code-complexity.md +74 -0
- package/all/copy-overwrite/.claude/commands/project/plan.md +314 -0
- package/all/copy-overwrite/.claude/commands/project/research.md +248 -0
- package/all/copy-overwrite/.claude/commands/project/review.md +63 -0
- package/all/copy-overwrite/.claude/commands/project/setup.md +19 -0
- package/all/copy-overwrite/.claude/commands/project/verify.md +38 -0
- package/all/copy-overwrite/.claude/commands/pull-request/review.md +12 -0
- package/all/copy-overwrite/.claude/commands/rules/format-md.md +72 -0
- package/all/copy-overwrite/.claude/commands/sonarqube/check.md +6 -0
- package/all/copy-overwrite/.claude/commands/sonarqube/fix.md +3 -0
- package/all/copy-overwrite/.claude/hooks/README.md +301 -0
- package/all/copy-overwrite/.claude/hooks/notify-ntfy.sh +181 -0
- package/all/copy-overwrite/.claude/settings.json +41 -0
- package/all/copy-overwrite/.claude/settings.local.json.example +14 -0
- package/all/copy-overwrite/.claude/skills/coding-philosophy/SKILL.md +405 -0
- package/all/copy-overwrite/.claude/skills/coding-philosophy/references/function-structure.md +416 -0
- package/all/copy-overwrite/.claude/skills/coding-philosophy/references/immutable-patterns.md +316 -0
- package/all/copy-overwrite/.claude/skills/prompt-complexity-scorer/SKILL.md +118 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/LICENSE.txt +202 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/SKILL.md +210 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/__pycache__/quick_validate.cpython-312.pyc +0 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/init_skill.py +303 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/package_skill.py +110 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/quick_validate.py +65 -0
- package/all/copy-overwrite/CLAUDE.md +77 -0
- package/all/copy-overwrite/HUMAN.md +17 -0
- package/all/copy-overwrite/specs/.keep +0 -0
- package/all/create-only/PROJECT_RULES.md +0 -0
- package/cdk/merge/package.json +20 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +107 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/prompts.d.ts +45 -0
- package/dist/cli/prompts.d.ts.map +1 -0
- package/dist/cli/prompts.js +58 -0
- package/dist/cli/prompts.js.map +1 -0
- package/dist/core/config.d.ts +73 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +36 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +4 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/lisa.d.ts +81 -0
- package/dist/core/lisa.d.ts.map +1 -0
- package/dist/core/lisa.js +459 -0
- package/dist/core/lisa.js.map +1 -0
- package/dist/core/manifest.d.ts +58 -0
- package/dist/core/manifest.d.ts.map +1 -0
- package/dist/core/manifest.js +104 -0
- package/dist/core/manifest.js.map +1 -0
- package/dist/detection/detector.interface.d.ts +15 -0
- package/dist/detection/detector.interface.d.ts.map +1 -0
- package/dist/detection/detector.interface.js +2 -0
- package/dist/detection/detector.interface.js.map +1 -0
- package/dist/detection/detectors/cdk.d.ts +10 -0
- package/dist/detection/detectors/cdk.d.ts.map +1 -0
- package/dist/detection/detectors/cdk.js +34 -0
- package/dist/detection/detectors/cdk.js.map +1 -0
- package/dist/detection/detectors/expo.d.ts +10 -0
- package/dist/detection/detectors/expo.d.ts.map +1 -0
- package/dist/detection/detectors/expo.js +30 -0
- package/dist/detection/detectors/expo.js.map +1 -0
- package/dist/detection/detectors/nestjs.d.ts +10 -0
- package/dist/detection/detectors/nestjs.d.ts.map +1 -0
- package/dist/detection/detectors/nestjs.js +34 -0
- package/dist/detection/detectors/nestjs.js.map +1 -0
- package/dist/detection/detectors/npm-package.d.ts +13 -0
- package/dist/detection/detectors/npm-package.d.ts.map +1 -0
- package/dist/detection/detectors/npm-package.js +30 -0
- package/dist/detection/detectors/npm-package.js.map +1 -0
- package/dist/detection/detectors/typescript.d.ts +10 -0
- package/dist/detection/detectors/typescript.d.ts.map +1 -0
- package/dist/detection/detectors/typescript.js +25 -0
- package/dist/detection/detectors/typescript.js.map +1 -0
- package/dist/detection/index.d.ts +24 -0
- package/dist/detection/index.d.ts.map +1 -0
- package/dist/detection/index.js +57 -0
- package/dist/detection/index.js.map +1 -0
- package/dist/errors/index.d.ts +69 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +110 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/console-logger.d.ts +12 -0
- package/dist/logging/console-logger.d.ts.map +1 -0
- package/dist/logging/console-logger.js +22 -0
- package/dist/logging/console-logger.js.map +1 -0
- package/dist/logging/index.d.ts +4 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +3 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/logger.interface.d.ts +20 -0
- package/dist/logging/logger.interface.d.ts.map +1 -0
- package/dist/logging/logger.interface.js +2 -0
- package/dist/logging/logger.interface.js.map +1 -0
- package/dist/logging/silent-logger.d.ts +12 -0
- package/dist/logging/silent-logger.d.ts.map +1 -0
- package/dist/logging/silent-logger.js +21 -0
- package/dist/logging/silent-logger.js.map +1 -0
- package/dist/strategies/copy-contents.d.ts +14 -0
- package/dist/strategies/copy-contents.d.ts.map +1 -0
- package/dist/strategies/copy-contents.js +69 -0
- package/dist/strategies/copy-contents.js.map +1 -0
- package/dist/strategies/copy-overwrite.d.ts +14 -0
- package/dist/strategies/copy-overwrite.d.ts.map +1 -0
- package/dist/strategies/copy-overwrite.js +47 -0
- package/dist/strategies/copy-overwrite.js.map +1 -0
- package/dist/strategies/create-only.d.ts +13 -0
- package/dist/strategies/create-only.d.ts.map +1 -0
- package/dist/strategies/create-only.js +30 -0
- package/dist/strategies/create-only.js.map +1 -0
- package/dist/strategies/index.d.ts +31 -0
- package/dist/strategies/index.d.ts.map +1 -0
- package/dist/strategies/index.js +52 -0
- package/dist/strategies/index.js.map +1 -0
- package/dist/strategies/merge.d.ts +13 -0
- package/dist/strategies/merge.d.ts.map +1 -0
- package/dist/strategies/merge.js +60 -0
- package/dist/strategies/merge.js.map +1 -0
- package/dist/strategies/strategy.interface.d.ts +31 -0
- package/dist/strategies/strategy.interface.d.ts.map +1 -0
- package/dist/strategies/strategy.interface.js +2 -0
- package/dist/strategies/strategy.interface.js.map +1 -0
- package/dist/transaction/backup.d.ts +38 -0
- package/dist/transaction/backup.d.ts.map +1 -0
- package/dist/transaction/backup.js +97 -0
- package/dist/transaction/backup.js.map +1 -0
- package/dist/transaction/index.d.ts +4 -0
- package/dist/transaction/index.d.ts.map +1 -0
- package/dist/transaction/index.js +3 -0
- package/dist/transaction/index.js.map +1 -0
- package/dist/transaction/transaction.d.ts +34 -0
- package/dist/transaction/transaction.d.ts.map +1 -0
- package/dist/transaction/transaction.js +68 -0
- package/dist/transaction/transaction.js.map +1 -0
- package/dist/utils/file-operations.d.ts +29 -0
- package/dist/utils/file-operations.d.ts.map +1 -0
- package/dist/utils/file-operations.js +84 -0
- package/dist/utils/file-operations.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/json-utils.d.ts +22 -0
- package/dist/utils/json-utils.d.ts.map +1 -0
- package/dist/utils/json-utils.js +57 -0
- package/dist/utils/json-utils.js.map +1 -0
- package/dist/utils/path-utils.d.ts +21 -0
- package/dist/utils/path-utils.d.ts.map +1 -0
- package/dist/utils/path-utils.js +35 -0
- package/dist/utils/path-utils.js.map +1 -0
- package/eslint-plugin-code-organization/README.md +149 -0
- package/eslint-plugin-code-organization/__tests__/enforce-statement-order.test.js +468 -0
- package/eslint-plugin-code-organization/index.js +23 -0
- package/eslint-plugin-code-organization/package.json +10 -0
- package/eslint-plugin-code-organization/rules/enforce-statement-order.js +157 -0
- package/expo/copy-overwrite/.claude/skills/apollo-client/SKILL.md +238 -0
- package/expo/copy-overwrite/.claude/skills/apollo-client/references/mutation-patterns.md +360 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/SKILL.md +360 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/atomic-levels.md +417 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/folder-structure.md +257 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/gluestack-mapping.md +233 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/scripts/validate_atomic_structure.py +327 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/SKILL.md +299 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/references/examples.md +749 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/references/patterns.md +318 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/scripts/create_component.py +198 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/scripts/validate_component.py +207 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/SKILL.md +268 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/common-issues.md +619 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/file-extensions.md +340 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/platform-api.md +276 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/scripts/validate_cross_platform.py +414 -0
- package/expo/copy-overwrite/.claude/skills/directory-structure/SKILL.md +202 -0
- package/expo/copy-overwrite/.claude/skills/directory-structure/scripts/validate_structure.py +443 -0
- package/expo/copy-overwrite/.claude/skills/expo-env-config/SKILL.md +309 -0
- package/expo/copy-overwrite/.claude/skills/expo-env-config/references/validation-patterns.md +417 -0
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/SKILL.md +431 -0
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/references/official-docs.md +290 -0
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/scripts/generate-route.py +169 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/SKILL.md +411 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/color-tokens.md +343 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/component-mapping.md +307 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/spacing-scale.md +300 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/scripts/validate_styling.py +354 -0
- package/expo/copy-overwrite/.claude/skills/local-state/SKILL.md +362 -0
- package/expo/copy-overwrite/.claude/skills/local-state/references/async-storage.md +505 -0
- package/expo/copy-overwrite/.claude/skills/local-state/references/persistence-patterns.md +711 -0
- package/expo/copy-overwrite/.claude/skills/local-state/references/reactive-variables.md +446 -0
- package/expo/copy-overwrite/.claude/skills/playwright-selectors/SKILL.md +223 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/SKILL.md +319 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/async-patterns.md +420 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/expo-router-testing.md +556 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/mocking-patterns.md +590 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/query-priority.md +291 -0
- package/expo/copy-overwrite/.easignore.extra +2 -0
- package/expo/copy-overwrite/.mcp.json +33 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/README.md +234 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/plugin-index.test.js +84 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/require-memo-in-view.test.js +196 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/single-component-per-file.test.js +289 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/index.js +32 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/package.json +10 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/enforce-component-structure.js +230 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/no-return-in-view.js +91 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/require-memo-in-view.js +178 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/single-component-per-file.js +238 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/README.md +260 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/index.js +29 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/package.json +10 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-classname-outside-ui.js +51 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-direct-rn-imports.js +55 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-inline-styles.js +73 -0
- package/expo/copy-overwrite/eslint.config.mjs +560 -0
- package/expo/copy-overwrite/lighthouserc.js +194 -0
- package/expo/create-only/lighthouserc-config.json +28 -0
- package/expo/merge/package.json +132 -0
- package/lisa.sh +35 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/SKILL.md +176 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/advanced-features.md +527 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/project-patterns.md +483 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/quick-start.md +257 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/resolvers-mutations.md +413 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/types-scalars.md +513 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-rules/SKILL.md +536 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/SKILL.md +275 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/configuration-patterns.md +487 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/entity-patterns.md +450 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/observability-patterns.md +536 -0
- package/nestjs/merge/package.json +75 -0
- package/package.json +124 -0
- package/typescript/copy-contents/.husky/commit-msg +91 -0
- package/typescript/copy-contents/.husky/pre-commit +96 -0
- package/typescript/copy-contents/.husky/pre-push +211 -0
- package/typescript/copy-overwrite/.claude/hooks/format-on-edit.sh +74 -0
- package/typescript/copy-overwrite/.claude/hooks/install_pkgs.sh +59 -0
- package/typescript/copy-overwrite/.claude/hooks/lint-on-edit.sh +103 -0
- package/typescript/copy-overwrite/.claude/skills/jsdoc-best-practices/SKILL.md +388 -0
- package/typescript/copy-overwrite/.github/README.md +455 -0
- package/typescript/copy-overwrite/.github/dependabot.yml +40 -0
- package/typescript/copy-overwrite/.github/k6/BROWSER_TESTING_NOTE.md +129 -0
- package/typescript/copy-overwrite/.github/k6/INTEGRATION_GUIDE.md +354 -0
- package/typescript/copy-overwrite/.github/k6/README.md +386 -0
- package/typescript/copy-overwrite/.github/k6/SCENARIO_SELECTION_GUIDE.md +264 -0
- package/typescript/copy-overwrite/.github/k6/examples/customer-deploy-integration.yml +115 -0
- package/typescript/copy-overwrite/.github/k6/examples/data-driven-test.js +268 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/load.js +142 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/load.json +27 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/smoke.js +26 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/smoke.json +20 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/soak.js +244 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/soak.json +29 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/spike.js +180 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/spike.json +32 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/stress.js +206 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/stress.json +38 -0
- package/typescript/copy-overwrite/.github/k6/scripts/api-test.js +452 -0
- package/typescript/copy-overwrite/.github/k6/scripts/default-test.js +185 -0
- package/typescript/copy-overwrite/.github/k6/thresholds/normal.json +30 -0
- package/typescript/copy-overwrite/.github/k6/thresholds/relaxed.json +21 -0
- package/typescript/copy-overwrite/.github/k6/thresholds/strict.json +29 -0
- package/typescript/copy-overwrite/.github/workflows/build.yml +72 -0
- package/typescript/copy-overwrite/.github/workflows/ci.yml +49 -0
- package/typescript/copy-overwrite/.github/workflows/claude.yml +51 -0
- package/typescript/copy-overwrite/.github/workflows/create-github-issue-on-failure.yml +113 -0
- package/typescript/copy-overwrite/.github/workflows/create-jira-issue-on-failure.yml +195 -0
- package/typescript/copy-overwrite/.github/workflows/create-sentry-issue-on-failure.yml +267 -0
- package/typescript/copy-overwrite/.github/workflows/deploy.yml +228 -0
- package/typescript/copy-overwrite/.github/workflows/k6-load-test-README.md +230 -0
- package/typescript/copy-overwrite/.github/workflows/lighthouse.yml +68 -0
- package/typescript/copy-overwrite/.github/workflows/load-test.yml +282 -0
- package/typescript/copy-overwrite/.github/workflows/quality.yml +1737 -0
- package/typescript/copy-overwrite/.github/workflows/release.yml +1599 -0
- package/typescript/copy-overwrite/.gitleaksignore +28 -0
- package/typescript/copy-overwrite/.nvmrc +1 -0
- package/typescript/copy-overwrite/.prettierignore +23 -0
- package/typescript/copy-overwrite/.prettierrc.json +22 -0
- package/typescript/copy-overwrite/.versionrc +42 -0
- package/typescript/copy-overwrite/.yamllint +20 -0
- package/typescript/copy-overwrite/commitlint.config.js +11 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/README.md +149 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/__tests__/enforce-statement-order.test.js +468 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/index.js +23 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/package.json +10 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/rules/enforce-statement-order.js +157 -0
- package/typescript/copy-overwrite/eslint.config.mjs +390 -0
- package/typescript/copy-overwrite/eslint.ignore.config.json +57 -0
- package/typescript/copy-overwrite/eslint.thresholds.config.json +5 -0
- package/typescript/github-rulesets/base.json +106 -0
- package/typescript/merge/.claude/settings.json +28 -0
- package/typescript/merge/package.json +71 -0
package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/observability-patterns.md
ADDED
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
# Observability Patterns
|
|
2
|
+
|
|
3
|
+
Detailed patterns for TypeORM observability including the X-Ray logger implementation with graceful degradation for local development.
|
|
4
|
+
|
|
5
|
+
## Custom X-Ray Logger
|
|
6
|
+
|
|
7
|
+
The custom logger provides distributed tracing in production while working gracefully in local environments where X-Ray is unavailable.
|
|
8
|
+
|
|
9
|
+
### typeorm-xray-logger.ts
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { Logger as NestLogger } from "@nestjs/common";
|
|
13
|
+
import type { Logger as TypeOrmLogger, QueryRunner } from "typeorm";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* X-Ray segment interface for type safety.
|
|
17
|
+
*/
|
|
18
|
+
interface XRaySegment {
|
|
19
|
+
addNewSubsegment(name: string): XRaySubsegment;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* X-Ray subsegment interface for type safety.
|
|
24
|
+
*/
|
|
25
|
+
interface XRaySubsegment {
|
|
26
|
+
addAnnotation(key: string, value: string | number | boolean): void;
|
|
27
|
+
addMetadata(key: string, value: unknown): void;
|
|
28
|
+
addError(error: Error): void;
|
|
29
|
+
close(): void;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* X-Ray SDK namespace interface.
|
|
34
|
+
*/
|
|
35
|
+
interface XRayNamespace {
|
|
36
|
+
getSegment(): XRaySegment | null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Query type extracted from SQL.
|
|
41
|
+
*/
|
|
42
|
+
type QueryType = "SELECT" | "INSERT" | "UPDATE" | "DELETE" | "OTHER";
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Extract query type from SQL string.
|
|
46
|
+
*
|
|
47
|
+
* @param query - The SQL query string
|
|
48
|
+
* @returns The query type
|
|
49
|
+
*/
|
|
50
|
+
const extractQueryType = (query: string): QueryType => {
|
|
51
|
+
const normalized = query.trim().toUpperCase();
|
|
52
|
+
if (normalized.startsWith("SELECT")) return "SELECT";
|
|
53
|
+
if (normalized.startsWith("INSERT")) return "INSERT";
|
|
54
|
+
if (normalized.startsWith("UPDATE")) return "UPDATE";
|
|
55
|
+
if (normalized.startsWith("DELETE")) return "DELETE";
|
|
56
|
+
return "OTHER";
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Extract table name from SQL string.
|
|
61
|
+
*
|
|
62
|
+
* @param query - The SQL query string
|
|
63
|
+
* @returns The table name or "unknown"
|
|
64
|
+
*/
|
|
65
|
+
const extractTableName = (query: string): string => {
|
|
66
|
+
const patterns = [
|
|
67
|
+
/FROM\s+["']?(\w+)["']?/i,
|
|
68
|
+
/INTO\s+["']?(\w+)["']?/i,
|
|
69
|
+
/UPDATE\s+["']?(\w+)["']?/i,
|
|
70
|
+
/DELETE\s+FROM\s+["']?(\w+)["']?/i,
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
const results = patterns
|
|
74
|
+
.map(pattern => query.match(pattern))
|
|
75
|
+
.filter((match): match is RegExpMatchArray => match !== null);
|
|
76
|
+
|
|
77
|
+
return results[0]?.[1] ?? "unknown";
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Sanitize query parameters to prevent logging sensitive data.
|
|
82
|
+
*
|
|
83
|
+
* @param parameters - The query parameters
|
|
84
|
+
* @returns Sanitized parameter representation
|
|
85
|
+
*/
|
|
86
|
+
const sanitizeParameters = (
|
|
87
|
+
parameters: readonly unknown[] | undefined
|
|
88
|
+
): string => {
|
|
89
|
+
if (!parameters || parameters.length === 0) return "[]";
|
|
90
|
+
return `[${parameters.length} parameters]`;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Attempt to get X-Ray namespace with graceful fallback.
|
|
95
|
+
*
|
|
96
|
+
* @returns X-Ray namespace or null if unavailable
|
|
97
|
+
*/
|
|
98
|
+
const getXRayNamespace = (): XRayNamespace | null => {
|
|
99
|
+
try {
|
|
100
|
+
// Dynamic import to avoid hard dependency on X-Ray SDK
|
|
101
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports -- Dynamic require for optional dependency
|
|
102
|
+
const AWSXRay = require("aws-xray-sdk-core");
|
|
103
|
+
return AWSXRay.getNamespace() as XRayNamespace;
|
|
104
|
+
} catch {
|
|
105
|
+
// X-Ray SDK not available (local development)
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* TypeORM logger with AWS X-Ray distributed tracing integration.
|
|
112
|
+
*
|
|
113
|
+
* @remarks
|
|
114
|
+
* This logger provides:
|
|
115
|
+
* - AWS X-Ray subsegment creation for each query
|
|
116
|
+
* - Query type and table name extraction for metrics
|
|
117
|
+
* - Parameter sanitization (no sensitive data logged)
|
|
118
|
+
* - Graceful degradation when X-Ray is unavailable
|
|
119
|
+
* - Never throws exceptions (defensive programming)
|
|
120
|
+
*
|
|
121
|
+
* In local development without X-Ray, falls back to NestJS Logger.
|
|
122
|
+
*/
|
|
123
|
+
export class TypeOrmXRayLogger implements TypeOrmLogger {
|
|
124
|
+
private readonly logger = new NestLogger("TypeORM");
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Create an X-Ray subsegment for a database operation.
|
|
128
|
+
*
|
|
129
|
+
* @param name - The subsegment name
|
|
130
|
+
* @returns The subsegment or null if X-Ray unavailable
|
|
131
|
+
*/
|
|
132
|
+
private createSubsegment(name: string): XRaySubsegment | null {
|
|
133
|
+
try {
|
|
134
|
+
const namespace = getXRayNamespace();
|
|
135
|
+
const segment = namespace?.getSegment();
|
|
136
|
+
return segment?.addNewSubsegment(name) ?? null;
|
|
137
|
+
} catch {
|
|
138
|
+
// Silently fail - X-Ray tracing is optional
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Close a subsegment safely.
|
|
145
|
+
*
|
|
146
|
+
* @param subsegment - The subsegment to close
|
|
147
|
+
*/
|
|
148
|
+
private closeSubsegment(subsegment: XRaySubsegment | null): void {
|
|
149
|
+
try {
|
|
150
|
+
subsegment?.close();
|
|
151
|
+
} catch {
|
|
152
|
+
// Silently fail - never throw from logger
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Log a query with X-Ray tracing.
|
|
158
|
+
*
|
|
159
|
+
* @param query - The SQL query
|
|
160
|
+
* @param parameters - Query parameters
|
|
161
|
+
* @param _queryRunner - TypeORM query runner (unused)
|
|
162
|
+
*/
|
|
163
|
+
logQuery(
|
|
164
|
+
query: string,
|
|
165
|
+
parameters?: readonly unknown[],
|
|
166
|
+
_queryRunner?: QueryRunner
|
|
167
|
+
): void {
|
|
168
|
+
const queryType = extractQueryType(query);
|
|
169
|
+
const tableName = extractTableName(query);
|
|
170
|
+
const subsegment = this.createSubsegment(`db-${queryType.toLowerCase()}`);
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
subsegment?.addAnnotation("db.type", "postgresql");
|
|
174
|
+
subsegment?.addAnnotation("db.operation", queryType);
|
|
175
|
+
subsegment?.addAnnotation("db.table", tableName);
|
|
176
|
+
subsegment?.addMetadata("query", query);
|
|
177
|
+
subsegment?.addMetadata("parameters", sanitizeParameters(parameters));
|
|
178
|
+
|
|
179
|
+
this.logger.debug(
|
|
180
|
+
`[${queryType}] ${tableName}: ${query.substring(0, 100)}...`
|
|
181
|
+
);
|
|
182
|
+
} finally {
|
|
183
|
+
this.closeSubsegment(subsegment);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Log a failed query with X-Ray error tracking.
|
|
189
|
+
*
|
|
190
|
+
* @param error - The error message or Error object
|
|
191
|
+
* @param query - The SQL query that failed
|
|
192
|
+
* @param parameters - Query parameters
|
|
193
|
+
* @param _queryRunner - TypeORM query runner (unused)
|
|
194
|
+
*/
|
|
195
|
+
logQueryError(
|
|
196
|
+
error: string | Error,
|
|
197
|
+
query: string,
|
|
198
|
+
parameters?: readonly unknown[],
|
|
199
|
+
_queryRunner?: QueryRunner
|
|
200
|
+
): void {
|
|
201
|
+
const queryType = extractQueryType(query);
|
|
202
|
+
const tableName = extractTableName(query);
|
|
203
|
+
const subsegment = this.createSubsegment(`db-${queryType.toLowerCase()}-error`);
|
|
204
|
+
|
|
205
|
+
try {
|
|
206
|
+
const errorObj = typeof error === "string" ? new Error(error) : error;
|
|
207
|
+
|
|
208
|
+
subsegment?.addAnnotation("db.type", "postgresql");
|
|
209
|
+
subsegment?.addAnnotation("db.operation", queryType);
|
|
210
|
+
subsegment?.addAnnotation("db.table", tableName);
|
|
211
|
+
subsegment?.addAnnotation("db.error", true);
|
|
212
|
+
subsegment?.addError(errorObj);
|
|
213
|
+
subsegment?.addMetadata("query", query);
|
|
214
|
+
subsegment?.addMetadata("parameters", sanitizeParameters(parameters));
|
|
215
|
+
|
|
216
|
+
this.logger.error(
|
|
217
|
+
`[${queryType}] ${tableName} FAILED: ${errorObj.message}`,
|
|
218
|
+
errorObj.stack
|
|
219
|
+
);
|
|
220
|
+
} finally {
|
|
221
|
+
this.closeSubsegment(subsegment);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Log a slow query with X-Ray annotation.
|
|
227
|
+
*
|
|
228
|
+
* @param time - Query execution time in milliseconds
|
|
229
|
+
* @param query - The SQL query
|
|
230
|
+
* @param parameters - Query parameters
|
|
231
|
+
* @param _queryRunner - TypeORM query runner (unused)
|
|
232
|
+
*/
|
|
233
|
+
logQuerySlow(
|
|
234
|
+
time: number,
|
|
235
|
+
query: string,
|
|
236
|
+
parameters?: readonly unknown[],
|
|
237
|
+
_queryRunner?: QueryRunner
|
|
238
|
+
): void {
|
|
239
|
+
const queryType = extractQueryType(query);
|
|
240
|
+
const tableName = extractTableName(query);
|
|
241
|
+
const subsegment = this.createSubsegment(`db-${queryType.toLowerCase()}-slow`);
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
subsegment?.addAnnotation("db.type", "postgresql");
|
|
245
|
+
subsegment?.addAnnotation("db.operation", queryType);
|
|
246
|
+
subsegment?.addAnnotation("db.table", tableName);
|
|
247
|
+
subsegment?.addAnnotation("db.slow", true);
|
|
248
|
+
subsegment?.addAnnotation("db.duration_ms", time);
|
|
249
|
+
subsegment?.addMetadata("query", query);
|
|
250
|
+
subsegment?.addMetadata("parameters", sanitizeParameters(parameters));
|
|
251
|
+
|
|
252
|
+
this.logger.warn(
|
|
253
|
+
`[SLOW ${time}ms] [${queryType}] ${tableName}: ${query.substring(0, 100)}...`
|
|
254
|
+
);
|
|
255
|
+
} finally {
|
|
256
|
+
this.closeSubsegment(subsegment);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Log schema build operations.
|
|
262
|
+
*
|
|
263
|
+
* @param message - The log message
|
|
264
|
+
* @param _queryRunner - TypeORM query runner (unused)
|
|
265
|
+
*/
|
|
266
|
+
logSchemaBuild(message: string, _queryRunner?: QueryRunner): void {
|
|
267
|
+
this.logger.log(`[Schema] ${message}`);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Log migration operations.
|
|
272
|
+
*
|
|
273
|
+
* @param message - The log message
|
|
274
|
+
* @param _queryRunner - TypeORM query runner (unused)
|
|
275
|
+
*/
|
|
276
|
+
logMigration(message: string, _queryRunner?: QueryRunner): void {
|
|
277
|
+
this.logger.log(`[Migration] ${message}`);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Log general TypeORM messages.
|
|
282
|
+
*
|
|
283
|
+
* @param level - The log level
|
|
284
|
+
* @param message - The log message
|
|
285
|
+
* @param _queryRunner - TypeORM query runner (unused)
|
|
286
|
+
*/
|
|
287
|
+
log(
|
|
288
|
+
level: "log" | "info" | "warn",
|
|
289
|
+
message: unknown,
|
|
290
|
+
_queryRunner?: QueryRunner
|
|
291
|
+
): void {
|
|
292
|
+
const messageStr = typeof message === "string" ? message : JSON.stringify(message);
|
|
293
|
+
|
|
294
|
+
const logMethod = level === "warn" ? "warn" : "log";
|
|
295
|
+
this.logger[logMethod](messageStr);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Usage in Configuration
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
import { TypeOrmXRayLogger } from "./typeorm-xray-logger";
|
|
304
|
+
|
|
305
|
+
const createBaseConfig = (): Partial<DataSourceOptions> => ({
|
|
306
|
+
type: "postgres",
|
|
307
|
+
// ... other config
|
|
308
|
+
logging: ["query", "error", "warn"],
|
|
309
|
+
logger: new TypeOrmXRayLogger(),
|
|
310
|
+
});
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## Logging Levels
|
|
314
|
+
|
|
315
|
+
Configure which operations to log:
|
|
316
|
+
|
|
317
|
+
| Option | Description |
|
|
318
|
+
|--------|-------------|
|
|
319
|
+
| `"query"` | Log all queries |
|
|
320
|
+
| `"error"` | Log failed queries |
|
|
321
|
+
| `"warn"` | Log warnings |
|
|
322
|
+
| `"schema"` | Log schema build operations |
|
|
323
|
+
| `"migration"` | Log migration operations |
|
|
324
|
+
| `true` | Log everything |
|
|
325
|
+
| `false` | Disable logging |
|
|
326
|
+
|
|
327
|
+
### Recommended Configuration
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
// Development - verbose logging
|
|
331
|
+
logging: true,
|
|
332
|
+
|
|
333
|
+
// Production - errors and slow queries only
|
|
334
|
+
logging: ["error", "warn"],
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## X-Ray Annotations vs Metadata
|
|
338
|
+
|
|
339
|
+
| Type | Purpose | Searchable | Size Limit |
|
|
340
|
+
|------|---------|------------|------------|
|
|
341
|
+
| **Annotation** | Filter and search traces | Yes | 50 per segment |
|
|
342
|
+
| **Metadata** | Additional context | No | 64KB total |
|
|
343
|
+
|
|
344
|
+
### Best Practices
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
// Annotations - use for filtering
|
|
348
|
+
subsegment.addAnnotation("db.operation", "SELECT"); // Searchable
|
|
349
|
+
subsegment.addAnnotation("db.table", "users"); // Searchable
|
|
350
|
+
subsegment.addAnnotation("db.error", true); // Searchable
|
|
351
|
+
|
|
352
|
+
// Metadata - use for debugging context
|
|
353
|
+
subsegment.addMetadata("query", query); // Not searchable
|
|
354
|
+
subsegment.addMetadata("parameters", params); // Not searchable
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## Health Check Integration
|
|
358
|
+
|
|
359
|
+
Combine with NestJS Terminus for production-ready health monitoring.
|
|
360
|
+
|
|
361
|
+
### health.controller.ts
|
|
362
|
+
|
|
363
|
+
```typescript
|
|
364
|
+
import { Controller, Get } from "@nestjs/common";
|
|
365
|
+
import {
|
|
366
|
+
HealthCheck,
|
|
367
|
+
HealthCheckResult,
|
|
368
|
+
HealthCheckService,
|
|
369
|
+
TypeOrmHealthIndicator,
|
|
370
|
+
} from "@nestjs/terminus";
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Health check controller for load balancer probes.
|
|
374
|
+
*/
|
|
375
|
+
@Controller("health")
|
|
376
|
+
export class HealthController {
|
|
377
|
+
constructor(
|
|
378
|
+
private readonly health: HealthCheckService,
|
|
379
|
+
private readonly db: TypeOrmHealthIndicator
|
|
380
|
+
) {}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Perform health check including database connectivity.
|
|
384
|
+
*
|
|
385
|
+
* @returns Health check result with database status
|
|
386
|
+
*/
|
|
387
|
+
@Get()
|
|
388
|
+
@HealthCheck()
|
|
389
|
+
check(): Promise<HealthCheckResult> {
|
|
390
|
+
return this.health.check([
|
|
391
|
+
() => this.db.pingCheck("database", { timeout: 3000 }),
|
|
392
|
+
]);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### health.module.ts
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
import { Module } from "@nestjs/common";
|
|
401
|
+
import { TerminusModule } from "@nestjs/terminus";
|
|
402
|
+
import { HealthController } from "./health.controller";
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Health check module for application monitoring.
|
|
406
|
+
*/
|
|
407
|
+
@Module({
|
|
408
|
+
imports: [TerminusModule],
|
|
409
|
+
controllers: [HealthController],
|
|
410
|
+
})
|
|
411
|
+
export class HealthModule {}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
## Testing the Logger
|
|
415
|
+
|
|
416
|
+
### typeorm-xray-logger.test.ts
|
|
417
|
+
|
|
418
|
+
```typescript
|
|
419
|
+
import { TypeOrmXRayLogger } from "./typeorm-xray-logger";
|
|
420
|
+
|
|
421
|
+
describe("TypeOrmXRayLogger", () => {
|
|
422
|
+
const logger = new TypeOrmXRayLogger();
|
|
423
|
+
|
|
424
|
+
describe("logQuery", () => {
|
|
425
|
+
it("should log SELECT queries without throwing", () => {
|
|
426
|
+
expect(() => {
|
|
427
|
+
logger.logQuery("SELECT * FROM users WHERE id = $1", ["uuid"]);
|
|
428
|
+
}).not.toThrow();
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
it("should log INSERT queries without throwing", () => {
|
|
432
|
+
expect(() => {
|
|
433
|
+
logger.logQuery(
|
|
434
|
+
"INSERT INTO users (email) VALUES ($1)",
|
|
435
|
+
["test@example.com"]
|
|
436
|
+
);
|
|
437
|
+
}).not.toThrow();
|
|
438
|
+
});
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
describe("logQueryError", () => {
|
|
442
|
+
it("should log errors without throwing", () => {
|
|
443
|
+
expect(() => {
|
|
444
|
+
logger.logQueryError(
|
|
445
|
+
new Error("Connection refused"),
|
|
446
|
+
"SELECT * FROM users",
|
|
447
|
+
[]
|
|
448
|
+
);
|
|
449
|
+
}).not.toThrow();
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
it("should handle string errors", () => {
|
|
453
|
+
expect(() => {
|
|
454
|
+
logger.logQueryError("Timeout", "SELECT * FROM users", []);
|
|
455
|
+
}).not.toThrow();
|
|
456
|
+
});
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
describe("logQuerySlow", () => {
|
|
460
|
+
it("should log slow queries without throwing", () => {
|
|
461
|
+
expect(() => {
|
|
462
|
+
logger.logQuerySlow(5000, "SELECT * FROM users", []);
|
|
463
|
+
}).not.toThrow();
|
|
464
|
+
});
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
describe("graceful degradation", () => {
|
|
468
|
+
it("should work without X-Ray SDK installed", () => {
|
|
469
|
+
// X-Ray SDK is not installed in test environment
|
|
470
|
+
// Logger should fall back to NestJS Logger
|
|
471
|
+
expect(() => {
|
|
472
|
+
logger.logQuery("SELECT 1", []);
|
|
473
|
+
logger.logQueryError("Test error", "SELECT 1", []);
|
|
474
|
+
logger.logQuerySlow(1000, "SELECT 1", []);
|
|
475
|
+
}).not.toThrow();
|
|
476
|
+
});
|
|
477
|
+
});
|
|
478
|
+
});
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
## Production X-Ray Setup
|
|
482
|
+
|
|
483
|
+
For production environments with X-Ray:
|
|
484
|
+
|
|
485
|
+
### Install X-Ray SDK (production only)
|
|
486
|
+
|
|
487
|
+
```bash
|
|
488
|
+
bun add aws-xray-sdk-core
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
### Lambda Handler Integration
|
|
492
|
+
|
|
493
|
+
```typescript
|
|
494
|
+
import * as AWSXRay from "aws-xray-sdk-core";
|
|
495
|
+
|
|
496
|
+
// Capture all AWS SDK calls
|
|
497
|
+
AWSXRay.captureAWS(require("aws-sdk"));
|
|
498
|
+
|
|
499
|
+
// Capture HTTP calls
|
|
500
|
+
AWSXRay.captureHTTPsGlobal(require("http"));
|
|
501
|
+
AWSXRay.captureHTTPsGlobal(require("https"));
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
### serverless.yml Configuration
|
|
505
|
+
|
|
506
|
+
```yaml
|
|
507
|
+
provider:
|
|
508
|
+
tracing:
|
|
509
|
+
lambda: true
|
|
510
|
+
apiGateway: true
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
## Metrics Dashboard
|
|
514
|
+
|
|
515
|
+
X-Ray annotations enable CloudWatch dashboards:
|
|
516
|
+
|
|
517
|
+
### Sample CloudWatch Insights Query
|
|
518
|
+
|
|
519
|
+
```sql
|
|
520
|
+
-- Query latency by table
|
|
521
|
+
fields @timestamp, @message
|
|
522
|
+
| filter annotation.db.type = 'postgresql'
|
|
523
|
+
| stats avg(annotation.db.duration_ms) as avg_latency by annotation.db.table
|
|
524
|
+
| sort avg_latency desc
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
### Alerting on Slow Queries
|
|
528
|
+
|
|
529
|
+
```sql
|
|
530
|
+
-- Find slow queries over 1 second
|
|
531
|
+
fields @timestamp, metadata.query
|
|
532
|
+
| filter annotation.db.slow = true
|
|
533
|
+
| filter annotation.db.duration_ms > 1000
|
|
534
|
+
| sort @timestamp desc
|
|
535
|
+
| limit 100
|
|
536
|
+
```
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"scripts": {
|
|
3
|
+
"start:local": "IS_OFFLINE=true sls offline start --noTimeout",
|
|
4
|
+
"start:dev": "IS_OFFLINE=true sls offline start --stage dev",
|
|
5
|
+
"start:docker": "docker-compose up",
|
|
6
|
+
"start:docker:build": "docker-compose up --build",
|
|
7
|
+
"start:docker:down": "docker-compose down",
|
|
8
|
+
"deploy:dev": "sls deploy --stage dev",
|
|
9
|
+
"deploy:staging": "sls deploy --stage staging",
|
|
10
|
+
"deploy:production": "sls deploy --stage production",
|
|
11
|
+
"fetch:graphql:schema:dev": "./scripts/fetch-graphql-schema.sh development",
|
|
12
|
+
"fetch:graphql:schema:staging": "./scripts/fetch-graphql-schema.sh staging",
|
|
13
|
+
"fetch:graphql:schema:production": "./scripts/fetch-graphql-schema.sh production",
|
|
14
|
+
"migration:generate": "typeorm-ts-node-commonjs migration:generate -d typeorm.config.ts src/database/migrations/$npm_config_name",
|
|
15
|
+
"migration:run": "typeorm-ts-node-commonjs migration:run -d typeorm.config.ts",
|
|
16
|
+
"migration:revert": "typeorm-ts-node-commonjs migration:revert -d typeorm.config.ts",
|
|
17
|
+
"//k6-docs": "K6 load testing scripts - run locally or with Docker",
|
|
18
|
+
"k6": "./scripts/k6-run.sh",
|
|
19
|
+
"k6:smoke": "./scripts/k6-run.sh --scenario smoke",
|
|
20
|
+
"k6:load": "./scripts/k6-run.sh --scenario load",
|
|
21
|
+
"k6:stress": "./scripts/k6-run.sh --scenario stress",
|
|
22
|
+
"k6:spike": "./scripts/k6-run.sh --scenario spike",
|
|
23
|
+
"k6:soak": "./scripts/k6-run.sh --scenario soak",
|
|
24
|
+
"k6:docker:smoke": "./scripts/k6-run.sh --scenario smoke --docker",
|
|
25
|
+
"k6:docker:load": "./scripts/k6-run.sh --scenario load --docker"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@apollo/server": "^5.2.0",
|
|
29
|
+
"@as-integrations/express5": "^1.1.2",
|
|
30
|
+
"@aws-sdk/client-apigatewaymanagementapi": "^3.967.0",
|
|
31
|
+
"@aws-sdk/client-cognito-identity-provider": "^3.969.0",
|
|
32
|
+
"@aws-sdk/rds-signer": "^3.968.0",
|
|
33
|
+
"@graphql-tools/utils": "^11.0.0",
|
|
34
|
+
"@nestjs/apollo": "^13.2.3",
|
|
35
|
+
"@nestjs/common": "^11.1.11",
|
|
36
|
+
"@nestjs/config": "^4.0.2",
|
|
37
|
+
"@nestjs/core": "^11.1.11",
|
|
38
|
+
"@nestjs/graphql": "^13.2.3",
|
|
39
|
+
"@nestjs/platform-express": "^11.1.11",
|
|
40
|
+
"@nestjs/terminus": "^11.0.0",
|
|
41
|
+
"@nestjs/typeorm": "^11.0.0",
|
|
42
|
+
"@vendia/serverless-express": "^4.12.6",
|
|
43
|
+
"aws-jwt-verify": "^5.1.1",
|
|
44
|
+
"aws-xray-sdk-core": "^3.12.0",
|
|
45
|
+
"class-transformer": "^0.5.1",
|
|
46
|
+
"class-validator": "^0.14.3",
|
|
47
|
+
"dataloader": "^2.2.3",
|
|
48
|
+
"graphql": "^16.12.0",
|
|
49
|
+
"graphql-query-complexity": "^1.1.0",
|
|
50
|
+
"graphql-subscriptions": "^3.0.0",
|
|
51
|
+
"graphql-ws": "^6.0.6",
|
|
52
|
+
"ioredis": "^5.9.1",
|
|
53
|
+
"pg": "^8.16.3",
|
|
54
|
+
"reflect-metadata": "^0.2.2",
|
|
55
|
+
"rxjs": "^7.8.2",
|
|
56
|
+
"typeorm": "^0.3.28",
|
|
57
|
+
"typeorm-naming-strategies": "^4.1.0"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@graphql-codegen/cli": "^6.1.0",
|
|
61
|
+
"@graphql-codegen/typescript": "^4.1.6",
|
|
62
|
+
"@graphql-codegen/typescript-operations": "^4.4.2",
|
|
63
|
+
"@graphql-codegen/typescript-react-apollo": "^4.3.4",
|
|
64
|
+
"@nestjs/cli": "^11.0.14",
|
|
65
|
+
"@nestjs/schematics": "^11.0.9",
|
|
66
|
+
"@nestjs/testing": "^11.1.11",
|
|
67
|
+
"@types/aws-lambda": "^8.10.159",
|
|
68
|
+
"@types/express": "^5.0.6",
|
|
69
|
+
"@types/jest": "^30.0.0",
|
|
70
|
+
"serverless": "^4.30.0",
|
|
71
|
+
"serverless-esbuild": "^1.57.0",
|
|
72
|
+
"serverless-offline": "^14.4.0"
|
|
73
|
+
},
|
|
74
|
+
"resolutions": {}
|
|
75
|
+
}
|