@travetto/llm-support 8.0.0-alpha.20
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/README.md +101 -0
- package/__index__.ts +11 -0
- package/llm/consumer/INSTRUCTIONS.md +44 -0
- package/llm/maintainer/INSTRUCTIONS.md +37 -0
- package/package.json +56 -0
- package/resources/snippets/autograph-cli-orchestration.md +21 -0
- package/resources/snippets/code/aws-lambda-package-and-deploy.yml.tpl +36 -0
- package/resources/snippets/code/cache-enhancements.config.ts.tpl +6 -0
- package/resources/snippets/code/cache-enhancements.service.ts.tpl +16 -0
- package/resources/snippets/code/create-web-interceptor.ts.tpl +15 -0
- package/resources/snippets/code/create-web-route.controller.ts.tpl +15 -0
- package/resources/snippets/code/create-web-route.service.ts.tpl +8 -0
- package/resources/snippets/code/email-config.ts.tpl +6 -0
- package/resources/snippets/code/email-context-schema.ts.tpl +7 -0
- package/resources/snippets/code/email-create-template.mustache.tpl +2 -0
- package/resources/snippets/code/email-fixture.json.tpl +6 -0
- package/resources/snippets/code/email-preview-test.ts.tpl +14 -0
- package/resources/snippets/code/email-render-pipeline.ts.tpl +12 -0
- package/resources/snippets/code/email-send-controller.ts.tpl +18 -0
- package/resources/snippets/code/email-transport-provider.ts.tpl +8 -0
- package/resources/snippets/code/enable-auth-session.config.ts.tpl +34 -0
- package/resources/snippets/code/enable-auth-session.controller.ts.tpl +30 -0
- package/resources/snippets/code/enable-file-upload.config.ts.tpl +6 -0
- package/resources/snippets/code/enable-file-upload.controller.ts.tpl +16 -0
- package/resources/snippets/code/enable-linting.package.json.tpl +13 -0
- package/resources/snippets/code/generate-config.app-config.ts.tpl +7 -0
- package/resources/snippets/code/generate-config.application.yml.tpl +3 -0
- package/resources/snippets/code/generate-config.local.yml.tpl +2 -0
- package/resources/snippets/code/generate-test-suite.fixture.json.tpl +4 -0
- package/resources/snippets/code/generate-test-suite.unit.ts.tpl +11 -0
- package/resources/snippets/code/model-indexed.indexes.ts.tpl +14 -0
- package/resources/snippets/code/model-indexed.model.ts.tpl +8 -0
- package/resources/snippets/code/model-indexed.service.ts.tpl +15 -0
- package/resources/snippets/code/model-query.service.ts.tpl +18 -0
- package/resources/snippets/code/openapi-client-generation.readme.tpl +13 -0
- package/resources/snippets/code/openapi-client-generation.yml.tpl +20 -0
- package/resources/snippets/code/openapi-spec-pipeline.yml.tpl +21 -0
- package/resources/snippets/code/pack-docker-release.yml.tpl +21 -0
- package/resources/snippets/code/project-bootstrap.application.yml.tpl +2 -0
- package/resources/snippets/code/project-bootstrap.home-controller.ts.tpl +15 -0
- package/resources/snippets/code/project-bootstrap.home-service.ts.tpl +8 -0
- package/resources/snippets/code/project-bootstrap.monorepo.package.json.tpl +12 -0
- package/resources/snippets/code/project-bootstrap.package.json.tpl +18 -0
- package/resources/snippets/code/repo-version-release.yml.tpl +25 -0
- package/resources/snippets/code/rest-rpc-client.client.ts.tpl +8 -0
- package/resources/snippets/code/rest-rpc-client.index.ts.tpl +1 -0
- package/resources/snippets/code/workflow-cloudfront-deploy.yml.tpl +18 -0
- package/resources/snippets/code/workflow-gcp-deploy.yml.tpl +18 -0
- package/resources/snippets/core-aws-lambda-package-and-deploy.md +21 -0
- package/resources/snippets/core-email-compiler-pattern.md +21 -0
- package/resources/snippets/core-email-module-contract.md +21 -0
- package/resources/snippets/core-email-nodemailer-provider.md +21 -0
- package/resources/snippets/core-eslint-ruleset.md +21 -0
- package/resources/snippets/core-openapi-client-generation.md +21 -0
- package/resources/snippets/core-openapi-spec-pipeline.md +21 -0
- package/resources/snippets/core-pack-docker-release.md +21 -0
- package/resources/snippets/core-repo-version-release.md +21 -0
- package/resources/snippets/core-upload-pattern.md +21 -0
- package/resources/snippets/core-web-controller-pattern.md +23 -0
- package/resources/snippets/core-work-pool-pattern.md +23 -0
- package/resources/snippets/embracinglife-cloudfront-deploy.md +21 -0
- package/resources/snippets/embracinglife-gcp-deploy.md +21 -0
- package/resources/snippets/recipe-auth-google-oauth.md +21 -0
- package/resources/snippets/recipe-indexed-model-pattern.md +21 -0
- package/resources/snippets/recipe-upload-presigned.md +21 -0
- package/resources/snippets/todo-app-test-pattern.md +21 -0
- package/src/consumer-docs.ts +23 -0
- package/src/execute.ts +624 -0
- package/src/install-guidance.ts +187 -0
- package/src/mcp.ts +170 -0
- package/src/plan.ts +110 -0
- package/src/recommendation.ts +306 -0
- package/src/snippet-catalog.ts +80 -0
- package/src/snippet-shapes.ts +14 -0
- package/src/template-shapes.ts +13 -0
- package/src/tooling.ts +197 -0
- package/src/types.ts +215 -0
- package/src/workflow-guidance.ts +220 -0
- package/support/base-command.ts +57 -0
- package/support/cli.llm_support_execute.ts +80 -0
- package/support/cli.llm_support_mcp.ts +62 -0
- package/support/cli.llm_support_plan.ts +30 -0
- package/support/cli.llm_support_recommend.ts +34 -0
- package/support/cli.llm_support_status.ts +30 -0
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
<!-- This file was generated by @travetto/doc and should not be modified directly -->
|
|
2
|
+
<!-- Please modify https://github.com/travetto/travetto/tree/main/module/llm-support/DOC.tsx and execute "npx trv doc" to rebuild -->
|
|
3
|
+
# LLM Support
|
|
4
|
+
|
|
5
|
+
## Task-oriented synthesized LLM guidance for Travetto modules.
|
|
6
|
+
|
|
7
|
+
The [LLM Support](https://github.com/travetto/travetto/tree/main/module/llm-support#readme "Task-oriented synthesized LLM guidance for Travetto modules.") module provides guided LLM assistance for Travetto projects. It helps you move from a target outcome to a concrete plan by combining bundle recommendations, workflow guidance, operation planning, and snippet selection.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
In a Travetto workspace, install the module and use the standard CLI entrypoint:
|
|
11
|
+
|
|
12
|
+
**Code: Install the module**
|
|
13
|
+
```bash
|
|
14
|
+
npm install @travetto/llm-support
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The module is designed to be used through [Command Line Interface](https://github.com/travetto/travetto/tree/main/module/cli#readme "CLI infrastructure for Travetto framework") commands, so once the package is available you can invoke the LLM support workflow with `trv`.
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
The recommended flow is intentionally plan-first:
|
|
21
|
+
1. Run `trv llm:support:recommend` to choose a bundle, workflow, category, or snippet set.
|
|
22
|
+
1. Run `trv llm:support:plan` to preview the files and changes that would be produced.
|
|
23
|
+
1. Run `trv llm:support:execute` to apply the selected operations, with dry-run behavior available by default.
|
|
24
|
+
|
|
25
|
+
**Code: Recommended flow**
|
|
26
|
+
```bash
|
|
27
|
+
trv llm:support:recommend\ntrv llm:support:plan\ntrv llm:support:execute
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The recommendation command supports filtering by `bundles`, `workflows`, `categories`, and `snippet-tags`. The plan command focuses on selected `operations` and produces file-level change steps. Execution supports dry-run, overwrite, target directory selection, monorepo bootstrap selection (`--monorepo`), and several operation-specific hints such as route, controller, service, model, and email naming.
|
|
31
|
+
|
|
32
|
+
## What It Supports
|
|
33
|
+
The module covers the core assistant paths used by Travetto projects:
|
|
34
|
+
* **Project bootstrap** - guided module and backend selection for a new application.
|
|
35
|
+
* **Web** - route, controller, service, interceptor, and client-oriented flows.
|
|
36
|
+
* **Auth** - session-backed identity and auth-web guided setup.
|
|
37
|
+
* **Model** - persistence, query, indexed, and backend selection guidance.
|
|
38
|
+
* **Upload** - direct upload and presigned URL support.
|
|
39
|
+
* **Workflow** - deployment-oriented GitHub workflow generation.
|
|
40
|
+
* **Quality** - linting and test suite setup.
|
|
41
|
+
* **Email** - templates, rendering, transport, preview, and send flows.
|
|
42
|
+
* **Test** - fixture and suite generation guidance.
|
|
43
|
+
* **Config** - configuration class and file generation.
|
|
44
|
+
* **Cache** - cache decorators and evictions workflows.
|
|
45
|
+
|
|
46
|
+
The available categories exposed by the CLI are `project`, `web`, `auth`, `model`, `upload`, `workflow`, `quality`, `email`, `test`, `config`, and `cache`.
|
|
47
|
+
|
|
48
|
+
## Bundles And Workflows
|
|
49
|
+
Recommendations are grouped into install guidance bundles and workflow guidance:
|
|
50
|
+
* `web-api-baseline` - web application fundamentals with DI and schema support.
|
|
51
|
+
* `web-model-crud` - controller/service CRUD flows backed by model-query.
|
|
52
|
+
* `model-persistence-stack` - model persistence and adapter selection.
|
|
53
|
+
* `auth-enabled-web` - web auth with auth-web integration.
|
|
54
|
+
* `quality-lint-and-test` - linting and test guardrails.
|
|
55
|
+
* `email-generation-stack` - email template and delivery setup.
|
|
56
|
+
* `project-bootstrap` - guided new-project setup.
|
|
57
|
+
* `create-web-route` - route/controller/service generation workflow.
|
|
58
|
+
* `generate-web-model-crud` - model-backed CRUD generation workflow.
|
|
59
|
+
|
|
60
|
+
The recommendation output also includes snippets that match the selected operations and capability tags, so the generated plan stays tied to reusable implementation patterns.
|
|
61
|
+
|
|
62
|
+
## Command Options
|
|
63
|
+
The CLI surface is designed for narrow, predictable selection:
|
|
64
|
+
* `--module` - scope recommendations to the active module.
|
|
65
|
+
* `--bundles` - choose specific install guidance bundles.
|
|
66
|
+
* `--workflows` - choose specific workflow guidance entries.
|
|
67
|
+
* `--operations` - choose specific operations for planning.
|
|
68
|
+
* `--categories` - filter by capability category.
|
|
69
|
+
* `--snippet-tags` - narrow the snippet catalog.
|
|
70
|
+
* `--include-excluded` - include excluded operations when you need the full catalog.
|
|
71
|
+
* `--monorepo` - when used with `project-bootstrap`, generate a workspace root and `packages/app` project layout.
|
|
72
|
+
* `--workspace-path` - customize the monorepo app location (for example `packages/api`).
|
|
73
|
+
* `--workspace-name` - customize the generated workspace package name used by root scripts.
|
|
74
|
+
|
|
75
|
+
That combination lets you start broad, then narrow to exactly the path you want before making changes.
|
|
76
|
+
|
|
77
|
+
## MCP Integration
|
|
78
|
+
The module exposes a minimal stdio MCP entrypoint for tool-calling integrations:
|
|
79
|
+
|
|
80
|
+
**Code: Start MCP server**
|
|
81
|
+
```bash
|
|
82
|
+
trv llm:support:mcp
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Supported methods are `initialize`, `tools/list`, and `tools/call`. Requests and responses are newline-delimited JSON-RPC 2.0 payloads.
|
|
86
|
+
|
|
87
|
+
**Code: MCP request examples**
|
|
88
|
+
```json
|
|
89
|
+
{"jsonrpc":"2.0","id":1,"method":"initialize"}
|
|
90
|
+
{"jsonrpc":"2.0","id":2,"method":"tools/list"}
|
|
91
|
+
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"llm_support_plan","arguments":{"operations":["create-web-route"]}}}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Contract Model
|
|
95
|
+
Contributor contract model for this module:
|
|
96
|
+
* Boundary contracts are schema classes first (inputs and outputs).
|
|
97
|
+
* Public type names are derived from classes instead of parallel interface trees.
|
|
98
|
+
* Runtime boundaries validate both inbound payloads and outbound responses.
|
|
99
|
+
* Tests should prefer schema bind+validate over custom shape guards when practical.
|
|
100
|
+
|
|
101
|
+
For execution and tooling helpers in this module, prefer non-assertion-safe binding where required by project rules.
|
package/__index__.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from './src/types.ts';
|
|
2
|
+
export * from './src/install-guidance.ts';
|
|
3
|
+
export * from './src/workflow-guidance.ts';
|
|
4
|
+
export * from './src/snippet-catalog.ts';
|
|
5
|
+
export * from './src/snippet-shapes.ts';
|
|
6
|
+
export * from './src/recommendation.ts';
|
|
7
|
+
export * from './src/plan.ts';
|
|
8
|
+
export * from './src/execute.ts';
|
|
9
|
+
export * from './src/tooling.ts';
|
|
10
|
+
export * from './src/mcp.ts';
|
|
11
|
+
export * from './src/consumer-docs.ts';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# LLM Support Instructions
|
|
2
|
+
Task-oriented guidance and operations for generating Travetto projects and features.
|
|
3
|
+
|
|
4
|
+
## Core Intent
|
|
5
|
+
Use this module to discover and execute generation-ready guidance for:
|
|
6
|
+
- project bootstrap and model backend selection
|
|
7
|
+
- web/controller/service and interceptor creation
|
|
8
|
+
- auth, uploads, model-indexed/model-query flows
|
|
9
|
+
- lint/test quality enablement
|
|
10
|
+
- email generation and delivery sub-operations
|
|
11
|
+
|
|
12
|
+
## Scope Decisions
|
|
13
|
+
Do not recommend excluded operations unless explicitly requested:
|
|
14
|
+
- log:config
|
|
15
|
+
- log:instrumentation
|
|
16
|
+
- eslint:profile
|
|
17
|
+
- test:mock-service
|
|
18
|
+
|
|
19
|
+
## Usage Workflow
|
|
20
|
+
1. Discover command shapes with `npx trv cli:schema` when uncertain.
|
|
21
|
+
2. Request recommendations with `npx trv llm:support:recommend`.
|
|
22
|
+
3. Select bundles/workflows/operations and generate plan-first changes.
|
|
23
|
+
4. Validate with lint/test and targeted compile checks.
|
|
24
|
+
|
|
25
|
+
## Framework Development Principles
|
|
26
|
+
- Prefer explicit contracts over implicit behavior; generated guidance should map to named operations, modules, and outcomes.
|
|
27
|
+
- Keep module boundaries clear: routing, service logic, persistence, and transport concerns should remain separable.
|
|
28
|
+
- Optimize for composability; recommendations should combine cleanly without hidden coupling.
|
|
29
|
+
- Default to safe behavior (plan-first, dry-run-first, minimal scope changes) and require explicit opt-in for destructive actions.
|
|
30
|
+
- Favor deterministic outputs so repeated runs with the same inputs produce equivalent guidance.
|
|
31
|
+
|
|
32
|
+
## Best Practices
|
|
33
|
+
- Schema-first boundaries: define input/output contracts with schema classes at ownership boundaries.
|
|
34
|
+
- Dependency clarity: always separate required modules from optional adapters and explain why optional items exist.
|
|
35
|
+
- Compatibility discipline: preserve stable operation ids and tool names; additive changes are preferred over breaking renames.
|
|
36
|
+
- Validation before confidence: verify recommendations against command shape, then verify generated output with targeted tests/lint.
|
|
37
|
+
- Incremental adoption: start with baseline bundles and layer advanced features only when requirements justify complexity.
|
|
38
|
+
- Explain tradeoffs: when multiple stack choices exist, provide capability-based selection criteria (query, indexed, blob, expiry, etc.).
|
|
39
|
+
- Keep examples production-oriented: avoid toy guidance that skips error handling, configuration boundaries, or testability.
|
|
40
|
+
|
|
41
|
+
## Change Quality Expectations
|
|
42
|
+
- Every new operation should include clear intent, required modules, optional modules, and verification checks.
|
|
43
|
+
- Every guidance expansion should include corresponding tests for discoverability and metadata integrity.
|
|
44
|
+
- Every consumer-facing behavior change should be reflected in these instructions so agent behavior stays aligned with framework expectations.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Maintainer Notes
|
|
2
|
+
|
|
3
|
+
## Module Role
|
|
4
|
+
This module owns LLM-oriented generation guidance for Travetto.
|
|
5
|
+
|
|
6
|
+
## Implementation Rules
|
|
7
|
+
- Keep operation metadata explicit and testable.
|
|
8
|
+
- Track excluded operations in `src/recommendation.ts`.
|
|
9
|
+
- Keep install/workflow guidance focused on direct generation workflows.
|
|
10
|
+
- Avoid provider-specific integrations in this phase.
|
|
11
|
+
|
|
12
|
+
## Framework Principles
|
|
13
|
+
- Treat llm-support as framework guidance infrastructure, not app-specific scaffolding.
|
|
14
|
+
- Preserve stable public contracts (operation ids, tool names, output shapes) unless a versioned compatibility change is planned.
|
|
15
|
+
- Keep guidance declarative and data-driven when possible to reduce execution branching and drift.
|
|
16
|
+
- Favor explicit policy over convention: codify exclusions, defaults, and verification expectations in source.
|
|
17
|
+
|
|
18
|
+
## Engineering Best Practices
|
|
19
|
+
- Use schema classes for boundary contracts and runtime validation.
|
|
20
|
+
- Keep recommendations explainable: each operation should have intent, dependency rationale, and verification guidance.
|
|
21
|
+
- Maintain deterministic execution planning and artifact reporting for traceability.
|
|
22
|
+
- Prefer additive evolution of guidance catalogs and workflows over mutation of existing semantics.
|
|
23
|
+
- Ensure every new capability has at least one integrity test (metadata shape, discoverability, or execution coverage).
|
|
24
|
+
- Keep documentation synchronized with behavior changes in the same change set.
|
|
25
|
+
|
|
26
|
+
## Compatibility And Change Discipline
|
|
27
|
+
- Breaking contract changes require an explicit compatibility note and migration guidance.
|
|
28
|
+
- New operations should avoid overlapping semantics unless distinction is documented.
|
|
29
|
+
- Excluded operations must remain visible in policy/tests, even when omitted from default recommendations.
|
|
30
|
+
- Guidance should remain monorepo-aware and avoid assumptions that only apply to single-package apps.
|
|
31
|
+
|
|
32
|
+
## Catalog Evolution
|
|
33
|
+
When adding operations:
|
|
34
|
+
1. Add type-safe operation metadata.
|
|
35
|
+
2. Add workflow/install entries if module dependencies change.
|
|
36
|
+
3. Add/update tests for filtering and exclusion behavior.
|
|
37
|
+
4. Update consumer instructions if scope changes.
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@travetto/llm-support",
|
|
3
|
+
"version": "8.0.0-alpha.20",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Task-oriented synthesized LLM guidance for Travetto modules.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"travetto",
|
|
8
|
+
"llm",
|
|
9
|
+
"docs",
|
|
10
|
+
"guidance"
|
|
11
|
+
],
|
|
12
|
+
"main": "__index__.ts",
|
|
13
|
+
"homepage": "https://travetto.io",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"author": {
|
|
16
|
+
"email": "travetto.framework@gmail.com",
|
|
17
|
+
"name": "Travetto Framework"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"__index__.ts",
|
|
21
|
+
"src",
|
|
22
|
+
"support",
|
|
23
|
+
"resources",
|
|
24
|
+
"llm"
|
|
25
|
+
],
|
|
26
|
+
"repository": {
|
|
27
|
+
"url": "git+https://github.com/travetto/travetto.git",
|
|
28
|
+
"directory": "module/llm-support"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@travetto/runtime": "^8.0.0-alpha.0",
|
|
32
|
+
"@travetto/schema": "^8.0.0-alpha.0"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@travetto/cli": "^8.0.0-alpha.0",
|
|
36
|
+
"@travetto/test": "^8.0.0-alpha.0"
|
|
37
|
+
},
|
|
38
|
+
"peerDependenciesMeta": {
|
|
39
|
+
"@travetto/cli": {
|
|
40
|
+
"optional": true
|
|
41
|
+
},
|
|
42
|
+
"@travetto/test": {
|
|
43
|
+
"optional": true
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"travetto": {
|
|
47
|
+
"workspaceInclude": true,
|
|
48
|
+
"displayName": "LLM Support",
|
|
49
|
+
"roles": [
|
|
50
|
+
"build"
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
"publishConfig": {
|
|
54
|
+
"access": "public"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<!-- json
|
|
2
|
+
{
|
|
3
|
+
"sourceId": "autograph-cli-orchestration",
|
|
4
|
+
"repositoryId": "autograph-typesetter",
|
|
5
|
+
"filePath": "support/cli.render.ts",
|
|
6
|
+
"capabilityTags": ["project", "cli", "orchestration"],
|
|
7
|
+
"operationIds": ["project-bootstrap"],
|
|
8
|
+
"applicability": ["sample-project"],
|
|
9
|
+
"notes": [
|
|
10
|
+
"Reference complex CLI orchestration and staged execution patterns."
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
-->
|
|
14
|
+
|
|
15
|
+
# autograph-cli-orchestration
|
|
16
|
+
|
|
17
|
+
- Source: `support/cli.render.ts`
|
|
18
|
+
- Capability tags: project, cli, orchestration
|
|
19
|
+
- Applicability: sample-project
|
|
20
|
+
- Notes:
|
|
21
|
+
- Reference complex CLI orchestration and staged execution patterns.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: lambda-deploy
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
inputs:
|
|
8
|
+
environment:
|
|
9
|
+
description: Deployment environment
|
|
10
|
+
required: true
|
|
11
|
+
default: dev
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
package:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
- uses: actions/setup-node@v4
|
|
19
|
+
with:
|
|
20
|
+
node-version: 20
|
|
21
|
+
- run: npm ci
|
|
22
|
+
- run: npx trv pack:lambda --output dist/lambda
|
|
23
|
+
- uses: actions/upload-artifact@v4
|
|
24
|
+
with:
|
|
25
|
+
name: lambda-package
|
|
26
|
+
path: dist/lambda
|
|
27
|
+
|
|
28
|
+
deploy:
|
|
29
|
+
needs: package
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/download-artifact@v4
|
|
33
|
+
with:
|
|
34
|
+
name: lambda-package
|
|
35
|
+
path: dist/lambda
|
|
36
|
+
- run: echo "Deploy dist/lambda to AWS Lambda for ${{ inputs.environment }}"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Injectable } from '@travetto/di';
|
|
2
|
+
|
|
3
|
+
@Injectable()
|
|
4
|
+
export class CacheableService {
|
|
5
|
+
private readonly cache = new Map<string, string>();
|
|
6
|
+
|
|
7
|
+
getOrPopulate(key: string, producer: () => string): string {
|
|
8
|
+
const cached = this.cache.get(key);
|
|
9
|
+
if (cached !== undefined) {
|
|
10
|
+
return cached;
|
|
11
|
+
}
|
|
12
|
+
const value = producer();
|
|
13
|
+
this.cache.set(key, value);
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Injectable } from '@travetto/di';
|
|
2
|
+
import { Interceptor } from '@travetto/web';
|
|
3
|
+
|
|
4
|
+
@Injectable()
|
|
5
|
+
export class RequestLoggingInterceptor implements Interceptor {
|
|
6
|
+
async intercept<T>(next: () => Promise<T>): Promise<T> {
|
|
7
|
+
const start = Date.now();
|
|
8
|
+
try {
|
|
9
|
+
return await next();
|
|
10
|
+
} finally {
|
|
11
|
+
const duration = Date.now() - start;
|
|
12
|
+
console.log('request-duration-ms', duration);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Inject } from '@travetto/di';
|
|
2
|
+
import { Controller, Get } from '@travetto/web';
|
|
3
|
+
|
|
4
|
+
import { {{serviceName}} } from '../service/{{serviceFile}}.ts';
|
|
5
|
+
|
|
6
|
+
@Controller('/{{routePath}}')
|
|
7
|
+
export class {{controllerName}} {
|
|
8
|
+
@Inject()
|
|
9
|
+
service: {{serviceName}};
|
|
10
|
+
|
|
11
|
+
@Get('/')
|
|
12
|
+
list(): { items: string[] } {
|
|
13
|
+
return { items: this.service.getItems() };
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
|
|
3
|
+
import { Suite, Test } from '@travetto/test';
|
|
4
|
+
|
|
5
|
+
import { renderTransactionalEmail } from '../../src/email/render.ts';
|
|
6
|
+
|
|
7
|
+
@Suite()
|
|
8
|
+
class EmailPreviewTest {
|
|
9
|
+
@Test()
|
|
10
|
+
async preview() {
|
|
11
|
+
const html = await renderTransactionalEmail({ title: 'Hello', message: 'World' });
|
|
12
|
+
assert(html.includes('Hello'));
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
import mustache from 'mustache';
|
|
5
|
+
|
|
6
|
+
import type { TransactionalEmailContext } from './schema.ts';
|
|
7
|
+
|
|
8
|
+
export async function render{{renderName}}Email(ctx: TransactionalEmailContext): Promise<string> {
|
|
9
|
+
const tplPath = path.resolve(process.cwd(), 'src/email/templates/{{emailName}}.mustache');
|
|
10
|
+
const tpl = await fs.readFile(tplPath, 'utf8');
|
|
11
|
+
return mustache.render(tpl, ctx);
|
|
12
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Inject } from '@travetto/di';
|
|
2
|
+
import { Body, Controller, Post } from '@travetto/web';
|
|
3
|
+
|
|
4
|
+
import { EmailProvider } from '../email/provider.ts';
|
|
5
|
+
import { renderTransactionalEmail } from '../email/render.ts';
|
|
6
|
+
|
|
7
|
+
@Controller('/{{routePath}}')
|
|
8
|
+
export class EmailController {
|
|
9
|
+
@Inject()
|
|
10
|
+
provider: EmailProvider;
|
|
11
|
+
|
|
12
|
+
@Post('/')
|
|
13
|
+
async send(@Body() body: { to: string; subject: string; title: string; message: string }): Promise<{ sent: true }> {
|
|
14
|
+
const html = await renderTransactionalEmail({ title: body.title, message: body.message });
|
|
15
|
+
await this.provider.send(body.to, body.subject, html);
|
|
16
|
+
return { sent: true };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type Authenticator, AuthenticationError, type Principal } from '@travetto/auth';
|
|
2
|
+
import { SessionModelSymbol } from '@travetto/auth-session';
|
|
3
|
+
import { InjectableFactory } from '@travetto/di';
|
|
4
|
+
import { MemoryModelConfig, MemoryModelService } from '@travetto/model-memory';
|
|
5
|
+
|
|
6
|
+
export const BasicAuthSymbol = Symbol.for('AUTH_BASIC');
|
|
7
|
+
|
|
8
|
+
type User = { username: string; password: string };
|
|
9
|
+
|
|
10
|
+
export class AuthConfig {
|
|
11
|
+
|
|
12
|
+
@InjectableFactory(SessionModelSymbol)
|
|
13
|
+
static getSessionModel(): MemoryModelService {
|
|
14
|
+
return new MemoryModelService(new MemoryModelConfig());
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@InjectableFactory(BasicAuthSymbol)
|
|
18
|
+
static getAuthenticator(): Authenticator<User> {
|
|
19
|
+
return {
|
|
20
|
+
authenticate(user): Principal {
|
|
21
|
+
if (user.username && user.password === 'password') {
|
|
22
|
+
return {
|
|
23
|
+
issuer: 'self',
|
|
24
|
+
id: user.username,
|
|
25
|
+
permissions: [],
|
|
26
|
+
details: {},
|
|
27
|
+
source: 'insecure'
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
throw new AuthenticationError('Unknown user');
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Principal } from '@travetto/auth';
|
|
2
|
+
import { Authenticated, Login, Logout } from '@travetto/auth-web';
|
|
3
|
+
import { ContextParam, Controller, Get, Post, WebResponse } from '@travetto/web';
|
|
4
|
+
|
|
5
|
+
import { BasicAuthSymbol } from './auth.config.ts';
|
|
6
|
+
|
|
7
|
+
@Controller('/auth')
|
|
8
|
+
export class AuthController {
|
|
9
|
+
|
|
10
|
+
@ContextParam()
|
|
11
|
+
user: Principal;
|
|
12
|
+
|
|
13
|
+
@Post('/login')
|
|
14
|
+
@Login(BasicAuthSymbol)
|
|
15
|
+
async login(): Promise<WebResponse> {
|
|
16
|
+
return WebResponse.redirect('/auth/self');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@Get('/self')
|
|
20
|
+
@Authenticated()
|
|
21
|
+
async self(): Promise<Principal> {
|
|
22
|
+
return this.user;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@Get('/logout')
|
|
26
|
+
@Logout()
|
|
27
|
+
async logout(): Promise<WebResponse> {
|
|
28
|
+
return WebResponse.redirect('/auth/self');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Controller, Post } from '@travetto/web';
|
|
2
|
+
import { type FileMap, Upload } from '@travetto/web-upload';
|
|
3
|
+
|
|
4
|
+
@Controller('/upload')
|
|
5
|
+
export class UploadController {
|
|
6
|
+
|
|
7
|
+
@Post('/')
|
|
8
|
+
uploadOne(@Upload() file: File): { name: string; size: number } {
|
|
9
|
+
return { name: file.name, size: file.size };
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@Post('/batch')
|
|
13
|
+
async uploadMany(@Upload() files: FileMap): Promise<{ count: number }> {
|
|
14
|
+
return { count: Object.keys(files).length };
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sample-app",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"lint:register": "trv eslint:register",
|
|
7
|
+
"lint": "npm run lint:register && trv eslint",
|
|
8
|
+
"lint:fix": "npm run lint:register && trv eslint --fix"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"@travetto/eslint": "^8.0.0-alpha.20"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { keyedIndex, sortedIndex } from '@travetto/model-indexed';
|
|
2
|
+
|
|
3
|
+
import { {{modelName}} } from './{{modelFile}}.ts';
|
|
4
|
+
|
|
5
|
+
export const {{modelVar}}ByName = keyedIndex({{modelName}}, {
|
|
6
|
+
name: '{{modelFile}}_by_name',
|
|
7
|
+
key: { name: true }
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export const {{modelVar}}ByNameCreatedAt = sortedIndex({{modelName}}, {
|
|
11
|
+
name: '{{modelFile}}_by_name_created_at',
|
|
12
|
+
key: { name: true },
|
|
13
|
+
sort: { createdAt: -1 }
|
|
14
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Inject, Injectable } from '@travetto/di';
|
|
2
|
+
import type { ModelIndexedSupport } from '@travetto/model-indexed';
|
|
3
|
+
|
|
4
|
+
import { {{modelVar}}ByName } from '../model/{{modelFile}}.indexes.ts';
|
|
5
|
+
import { {{modelName}} } from '../model/{{modelFile}}.ts';
|
|
6
|
+
|
|
7
|
+
@Injectable()
|
|
8
|
+
export class {{modelName}}IndexedService {
|
|
9
|
+
@Inject()
|
|
10
|
+
source: ModelIndexedSupport;
|
|
11
|
+
|
|
12
|
+
getByName(name: string): Promise<{{modelName}}> {
|
|
13
|
+
return this.source.getByIndex({{modelName}}, {{modelVar}}ByName, { name });
|
|
14
|
+
}
|
|
15
|
+
}
|