create-agent-rig 0.9.1 → 0.10.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/CHANGELOG.md +419 -3
- package/README.md +267 -305
- package/package.json +8 -14
- package/packages/cli/dist/commands/create.js +56 -88
- package/packages/cli/dist/commands/doctor.js +213 -0
- package/packages/cli/dist/commands/init.js +111 -50
- package/packages/cli/dist/commands/integrations.js +468 -0
- package/packages/cli/dist/commands/setup-wizard.js +61 -0
- package/packages/cli/dist/commands/uninstall.js +1223 -0
- package/packages/cli/dist/commands/upgrade.js +472 -90
- package/packages/cli/dist/index.js +651 -46
- package/packages/cli/dist/integrations/declaration.js +158 -0
- package/packages/cli/dist/integrations/doctor-guards.js +126 -0
- package/packages/cli/dist/integrations/doctor-workflow.js +25 -0
- package/packages/cli/dist/integrations/mcp-json.js +107 -0
- package/packages/cli/dist/integrations/memory-doctor.js +124 -0
- package/packages/cli/dist/integrations/registry.js +22 -0
- package/packages/cli/dist/integrations/spawn.js +228 -0
- package/packages/cli/dist/integrations/spec-kit.js +280 -0
- package/packages/cli/dist/integrations/verify.js +193 -0
- package/packages/cli/dist/integrations/windows-job.js +275 -0
- package/packages/cli/dist/lib/elevated-paths.js +74 -0
- package/packages/cli/dist/lib/install-set.js +1 -44
- package/packages/cli/dist/lib/manifest.js +64 -5
- package/packages/cli/dist/lib/prompts.js +0 -23
- package/packages/cli/dist/lib/safe-path.js +193 -2
- package/packages/cli/dist/lib/safe-text.js +78 -0
- package/packages/cli/dist/lib/substitute.js +1 -52
- package/packages/cli/dist/lib/summary.js +5 -5
- package/packages/cli/dist/templates.js +4 -14
- package/scripts/prepare.mjs +28 -12
- package/templates/agent-os/subagent-routing.json +4 -4
- package/templates/agent-os/universal/.agents/skills/check-premises/SKILL.md +13 -9
- package/templates/agent-os/universal/.agents/skills/loop/SKILL.md +31 -6
- package/templates/agent-os/universal/.agents/skills/new-invariant/SKILL.md +5 -5
- package/templates/agent-os/universal/.agents/skills/pr-ship/SKILL.md +1 -1
- package/templates/agent-os/universal/.agents/skills/worktree-task/SKILL.md +3 -3
- package/templates/agent-os/universal/.claude/agents/code-reviewer.md +8 -6
- package/templates/agent-os/universal/.claude/agents/implementation-agent.md +41 -0
- package/templates/agent-os/universal/.claude/agents/prose-reviewer.md +8 -4
- package/templates/agent-os/universal/.claude/agents/security-scanner.md +4 -2
- package/templates/agent-os/universal/.claude/agents/test-writer.md +2 -2
- package/templates/agent-os/universal/.claude/hooks/inject-rules.mjs +83 -4
- package/templates/agent-os/universal/.claude/rules/autonomy.md +55 -27
- package/templates/agent-os/universal/.claude/rules/invariants.md +9 -8
- package/templates/agent-os/universal/.claude/rules/workflow.md +47 -22
- package/templates/agent-os/universal/.claude/scripts/decision-router.mjs +1 -1
- package/templates/agent-os/universal/.claude/scripts/detect-missed-gate.mjs +12 -9
- package/templates/agent-os/universal/.claude/scripts/doctor.mjs +100 -2
- package/templates/agent-os/universal/.claude/scripts/lib/claim-records.mjs +236 -6
- package/templates/agent-os/universal/.claude/scripts/queue/state.mjs +2 -2
- package/templates/agent-os/universal/.claude/scripts/reconcile-external-prs.mjs +4 -3
- package/templates/agent-os/universal/.claude/scripts/revalidate.mjs +16 -0
- package/templates/agent-os/universal/.claude/settings.json +0 -8
- package/templates/agent-os/universal/.claude/skills/check-premises/SKILL.md +13 -9
- package/templates/agent-os/universal/.claude/skills/loop/SKILL.md +31 -6
- package/templates/agent-os/universal/.claude/skills/new-invariant/SKILL.md +5 -5
- package/templates/agent-os/universal/.claude/skills/pr-ship/SKILL.md +1 -1
- package/templates/agent-os/universal/.claude/skills/worktree-task/SKILL.md +3 -3
- package/templates/agent-os/universal/.codex/agents/code-reviewer.toml +2 -2
- package/templates/agent-os/universal/.codex/agents/implementation-agent.toml +6 -0
- package/templates/agent-os/universal/.codex/agents/prose-reviewer.toml +2 -2
- package/templates/agent-os/universal/.codex/agents/security-scanner.toml +1 -1
- package/templates/agent-os/universal/.codex/agents/test-writer.toml +1 -1
- package/templates/agent-os/universal/.codex/hooks.json +0 -10
- package/templates/agent-os/universal/AGENTS.md +208 -107
- package/templates/agent-os/universal/CLAUDE.md +15 -162
- package/templates/agent-os/universal/PLAN.md +17 -10
- package/templates/agent-os/universal/docs/decisions/agents-md-canonical.md +313 -0
- package/templates/agent-os/universal/docs/decisions/codex-adapter.md +15 -10
- package/templates/agent-os/universal/docs/decisions/review-lanes.md +12 -8
- package/templates/agent-os/universal/docs/decisions/session-start-wire-format.md +206 -0
- package/templates/agent-os/universal/docs/decisions/subagent-routing.md +6 -3
- package/templates/agent-os/universal/docs/decisions/workflow-layer-split.md +235 -0
- package/templates/agent-os/universal/layers.json +25 -30
- package/templates/hash-history.json +8 -4
- package/templates/release-ledger.json +2 -1
- package/packages/cli/dist/lib/composition.js +0 -20
- package/packages/cli/dist/lib/targets.js +0 -28
- package/packages/cli/dist/policy/benchmark/corpus.js +0 -165
- package/packages/cli/dist/policy/core/adapter.js +0 -18
- package/packages/cli/dist/policy/core/coverage.js +0 -253
- package/packages/cli/dist/policy/core/decision-record.js +0 -287
- package/packages/cli/dist/policy/core/declaration.js +0 -127
- package/packages/cli/dist/policy/core/evidence-matrix.js +0 -94
- package/packages/cli/dist/policy/core/probe.js +0 -442
- package/packages/cli/dist/policy/core/registry.js +0 -115
- package/packages/cli/dist/policy/core/validation.js +0 -275
- package/packages/cli/dist/policy/core/vocabulary.js +0 -123
- package/packages/cli/dist/policy/harness/claude.js +0 -47
- package/packages/cli/dist/policy/harness/codex.js +0 -87
- package/packages/cli/dist/policy/harness/index.js +0 -15
- package/packages/cli/dist/policy/harness/shared-hooks.js +0 -28
- package/packages/cli/dist/policy/index.js +0 -17
- package/templates/agent-os/init/AGENTS.md +0 -201
- package/templates/agent-os/init/CLAUDE.md +0 -201
- package/templates/agent-os/stack/aws-cdk/.agents/skills/post-deploy-verify/SKILL.md +0 -105
- package/templates/agent-os/stack/aws-cdk/.agents/skills/ro-debug/SKILL.md +0 -117
- package/templates/agent-os/stack/aws-cdk/.claude/agents/cdk-diff-reviewer.md +0 -89
- package/templates/agent-os/stack/aws-cdk/.claude/rules/aws-cdk.md +0 -105
- package/templates/agent-os/stack/aws-cdk/.claude/skills/post-deploy-verify/SKILL.md +0 -105
- package/templates/agent-os/stack/aws-cdk/.claude/skills/ro-debug/SKILL.md +0 -117
- package/templates/agent-os/stack/aws-cdk/.codex/agents/cdk-diff-reviewer.toml +0 -6
- package/templates/agent-os/stack/node-ts/.claude/hooks/dod-checks.json +0 -1
- package/templates/agent-os/stack/node-ts/.claude/rules/node-ts.md +0 -85
- package/templates/agent-os/universal/.claude/hooks/guard-core-purity.mjs +0 -89
- package/templates/agent-os/universal/.claude/hooks/guard-web-boundary.mjs +0 -68
- package/templates/agent-os/universal/.claude/rules/architecture.md +0 -81
- package/templates/skeleton/aws-serverless/.github/workflows/ci.yml +0 -28
- package/templates/skeleton/aws-serverless/.github/workflows/deploy.yml +0 -90
- package/templates/skeleton/aws-serverless/README.md +0 -181
- package/templates/skeleton/aws-serverless/apps/web/next.config.mjs +0 -17
- package/templates/skeleton/aws-serverless/apps/web/package.json +0 -19
- package/templates/skeleton/aws-serverless/apps/web/src/app/layout.tsx +0 -17
- package/templates/skeleton/aws-serverless/apps/web/src/app/page.tsx +0 -96
- package/templates/skeleton/aws-serverless/apps/web/src/lib/api.ts +0 -36
- package/templates/skeleton/aws-serverless/apps/web/src/lib/validate.ts +0 -23
- package/templates/skeleton/aws-serverless/apps/web/test/shared-validation.test.ts +0 -38
- package/templates/skeleton/aws-serverless/apps/web/tsconfig.json +0 -14
- package/templates/skeleton/aws-serverless/eslint.config.mjs +0 -20
- package/templates/skeleton/aws-serverless/gitignore +0 -56
- package/templates/skeleton/aws-serverless/infra/bin/app.ts +0 -79
- package/templates/skeleton/aws-serverless/infra/cdk.json +0 -3
- package/templates/skeleton/aws-serverless/infra/lib/app-stack.ts +0 -248
- package/templates/skeleton/aws-serverless/infra/lib/web-stack.ts +0 -45
- package/templates/skeleton/aws-serverless/infra/package.json +0 -18
- package/templates/skeleton/aws-serverless/infra/test/allowed-origins.test.ts +0 -301
- package/templates/skeleton/aws-serverless/infra/test/app-composition.test.ts +0 -137
- package/templates/skeleton/aws-serverless/infra/test/app-stack.test.ts +0 -120
- package/templates/skeleton/aws-serverless/infra/test/web-stack.test.ts +0 -44
- package/templates/skeleton/aws-serverless/package.json +0 -30
- package/templates/skeleton/aws-serverless/packages/core/package.json +0 -11
- package/templates/skeleton/aws-serverless/packages/core/src/events.ts +0 -14
- package/templates/skeleton/aws-serverless/packages/core/src/index.ts +0 -15
- package/templates/skeleton/aws-serverless/packages/core/src/note.ts +0 -69
- package/templates/skeleton/aws-serverless/packages/core/test/events.test.ts +0 -23
- package/templates/skeleton/aws-serverless/packages/core/test/note.test.ts +0 -101
- package/templates/skeleton/aws-serverless/packages/db/package.json +0 -14
- package/templates/skeleton/aws-serverless/packages/db/src/client.ts +0 -17
- package/templates/skeleton/aws-serverless/packages/db/src/index.ts +0 -2
- package/templates/skeleton/aws-serverless/packages/db/src/note-model.ts +0 -52
- package/templates/skeleton/aws-serverless/packages/db/test/note-model.test.ts +0 -91
- package/templates/skeleton/aws-serverless/packages/shared/package.json +0 -11
- package/templates/skeleton/aws-serverless/packages/shared/src/env.ts +0 -17
- package/templates/skeleton/aws-serverless/packages/shared/src/errors.ts +0 -33
- package/templates/skeleton/aws-serverless/packages/shared/src/index.ts +0 -3
- package/templates/skeleton/aws-serverless/packages/shared/src/logger.ts +0 -20
- package/templates/skeleton/aws-serverless/packages/shared/test/env.test.ts +0 -26
- package/templates/skeleton/aws-serverless/packages/shared/test/errors.test.ts +0 -28
- package/templates/skeleton/aws-serverless/packages/shared/test/logger.test.ts +0 -19
- package/templates/skeleton/aws-serverless/pnpm-lock.yaml +0 -2855
- package/templates/skeleton/aws-serverless/pnpm-workspace.yaml +0 -14
- package/templates/skeleton/aws-serverless/services/api/package.json +0 -15
- package/templates/skeleton/aws-serverless/services/api/src/adapters/sqs-publisher.ts +0 -26
- package/templates/skeleton/aws-serverless/services/api/src/handlers/create-note.ts +0 -69
- package/templates/skeleton/aws-serverless/services/api/src/handlers/list-notes.ts +0 -37
- package/templates/skeleton/aws-serverless/services/api/src/list-main.ts +0 -12
- package/templates/skeleton/aws-serverless/services/api/src/main.ts +0 -21
- package/templates/skeleton/aws-serverless/services/api/src/usecases/create-note.ts +0 -41
- package/templates/skeleton/aws-serverless/services/api/src/usecases/list-notes.ts +0 -14
- package/templates/skeleton/aws-serverless/services/api/test/create-note.handler.test.ts +0 -211
- package/templates/skeleton/aws-serverless/services/api/test/create-note.usecase.test.ts +0 -45
- package/templates/skeleton/aws-serverless/services/api/test/list-notes.test.ts +0 -122
- package/templates/skeleton/aws-serverless/services/api/test/sqs-publisher.test.ts +0 -22
- package/templates/skeleton/aws-serverless/services/worker/package.json +0 -12
- package/templates/skeleton/aws-serverless/services/worker/src/handlers/note-created.ts +0 -15
- package/templates/skeleton/aws-serverless/services/worker/src/main.ts +0 -7
- package/templates/skeleton/aws-serverless/services/worker/src/usecases/process-note-created.ts +0 -37
- package/templates/skeleton/aws-serverless/services/worker/test/note-created.test.ts +0 -61
- package/templates/skeleton/aws-serverless/tsconfig.base.json +0 -15
- package/templates/skeleton/aws-serverless/tsconfig.json +0 -16
- package/templates/skeleton/aws-serverless/vitest.config.ts +0 -14
- package/templates/skeleton/node-service/.github/workflows/ci.yml +0 -27
- package/templates/skeleton/node-service/.github/workflows/deploy.yml +0 -29
- package/templates/skeleton/node-service/README.md +0 -104
- package/templates/skeleton/node-service/apps/web/next.config.mjs +0 -17
- package/templates/skeleton/node-service/apps/web/package.json +0 -19
- package/templates/skeleton/node-service/apps/web/src/app/layout.tsx +0 -17
- package/templates/skeleton/node-service/apps/web/src/app/page.tsx +0 -96
- package/templates/skeleton/node-service/apps/web/src/lib/api.ts +0 -29
- package/templates/skeleton/node-service/apps/web/src/lib/validate.ts +0 -23
- package/templates/skeleton/node-service/apps/web/test/shared-validation.test.ts +0 -38
- package/templates/skeleton/node-service/apps/web/tsconfig.json +0 -14
- package/templates/skeleton/node-service/eslint.config.mjs +0 -20
- package/templates/skeleton/node-service/gitignore +0 -54
- package/templates/skeleton/node-service/package.json +0 -30
- package/templates/skeleton/node-service/packages/core/package.json +0 -11
- package/templates/skeleton/node-service/packages/core/src/events.ts +0 -14
- package/templates/skeleton/node-service/packages/core/src/index.ts +0 -15
- package/templates/skeleton/node-service/packages/core/src/note.ts +0 -69
- package/templates/skeleton/node-service/packages/core/test/events.test.ts +0 -23
- package/templates/skeleton/node-service/packages/core/test/note.test.ts +0 -101
- package/templates/skeleton/node-service/packages/db/package.json +0 -12
- package/templates/skeleton/node-service/packages/db/src/index.ts +0 -1
- package/templates/skeleton/node-service/packages/db/src/note-store.ts +0 -100
- package/templates/skeleton/node-service/packages/db/test/note-store.test.ts +0 -100
- package/templates/skeleton/node-service/packages/shared/package.json +0 -11
- package/templates/skeleton/node-service/packages/shared/src/env.ts +0 -17
- package/templates/skeleton/node-service/packages/shared/src/errors.ts +0 -33
- package/templates/skeleton/node-service/packages/shared/src/index.ts +0 -3
- package/templates/skeleton/node-service/packages/shared/src/logger.ts +0 -20
- package/templates/skeleton/node-service/packages/shared/test/env.test.ts +0 -26
- package/templates/skeleton/node-service/packages/shared/test/errors.test.ts +0 -28
- package/templates/skeleton/node-service/packages/shared/test/logger.test.ts +0 -19
- package/templates/skeleton/node-service/pnpm-lock.yaml +0 -2402
- package/templates/skeleton/node-service/pnpm-workspace.yaml +0 -13
- package/templates/skeleton/node-service/scripts/build-artifact.mjs +0 -34
- package/templates/skeleton/node-service/services/api/package.json +0 -17
- package/templates/skeleton/node-service/services/api/src/adapters/spool-publisher.ts +0 -23
- package/templates/skeleton/node-service/services/api/src/handlers/create-note.ts +0 -40
- package/templates/skeleton/node-service/services/api/src/handlers/list-notes.ts +0 -23
- package/templates/skeleton/node-service/services/api/src/main.ts +0 -40
- package/templates/skeleton/node-service/services/api/src/server.ts +0 -172
- package/templates/skeleton/node-service/services/api/src/static-dir.ts +0 -20
- package/templates/skeleton/node-service/services/api/src/usecases/create-note.ts +0 -30
- package/templates/skeleton/node-service/services/api/src/usecases/list-notes.ts +0 -14
- package/templates/skeleton/node-service/services/api/test/artifact.test.ts +0 -92
- package/templates/skeleton/node-service/services/api/test/create-note.handler.test.ts +0 -64
- package/templates/skeleton/node-service/services/api/test/create-note.usecase.test.ts +0 -43
- package/templates/skeleton/node-service/services/api/test/list-notes.test.ts +0 -48
- package/templates/skeleton/node-service/services/api/test/package-manager.test.ts +0 -40
- package/templates/skeleton/node-service/services/api/test/package-manager.ts +0 -51
- package/templates/skeleton/node-service/services/api/test/server.test.ts +0 -208
- package/templates/skeleton/node-service/services/api/test/spool-publisher.test.ts +0 -32
- package/templates/skeleton/node-service/services/api/test/static-dir.test.ts +0 -29
- package/templates/skeleton/node-service/services/worker/package.json +0 -16
- package/templates/skeleton/node-service/services/worker/src/main.ts +0 -28
- package/templates/skeleton/node-service/services/worker/src/spool.ts +0 -60
- package/templates/skeleton/node-service/services/worker/src/usecases/process-note-created.ts +0 -38
- package/templates/skeleton/node-service/services/worker/test/process-note-created.test.ts +0 -34
- package/templates/skeleton/node-service/services/worker/test/spool.test.ts +0 -76
- package/templates/skeleton/node-service/tsconfig.base.json +0 -15
- package/templates/skeleton/node-service/tsconfig.json +0 -13
- package/templates/skeleton/node-service/vitest.config.ts +0 -12
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
// THE load-bearing test of the frontend (web brief §5): the browser-side
|
|
2
|
-
// validator and the server-side schema must be the same decision procedure.
|
|
3
|
-
// No jsdom, no rendering — the boundary is the point, not the pixels.
|
|
4
|
-
import { InvalidNoteError, NewNoteSchema, createNote } from '@app/core';
|
|
5
|
-
import { describe, expect, it } from 'vitest';
|
|
6
|
-
import { validateNewNote } from '../src/lib/validate';
|
|
7
|
-
|
|
8
|
-
const identity = { id: 'n1', createdAt: '2024-01-01T00:00:00.000Z' };
|
|
9
|
-
|
|
10
|
-
const CASES: Array<{ name: string; input: unknown }> = [
|
|
11
|
-
{ name: 'valid minimal', input: { title: 'Hello' } },
|
|
12
|
-
{ name: 'valid with tags', input: { title: 'Hello', tags: ['a', 'b'] } },
|
|
13
|
-
{ name: 'empty title', input: { title: '' } },
|
|
14
|
-
{ name: 'whitespace title', input: { title: ' ' } },
|
|
15
|
-
{ name: 'title too long', input: { title: 'x'.repeat(201) } },
|
|
16
|
-
{ name: 'too many tags', input: { title: 'T', tags: Array.from({ length: 11 }, (_, i) => `${i}`) } },
|
|
17
|
-
{ name: 'empty tag', input: { title: 'T', tags: [''] } },
|
|
18
|
-
{ name: 'wrong types', input: { title: 42 } },
|
|
19
|
-
{ name: 'not an object', input: 'nope' },
|
|
20
|
-
];
|
|
21
|
-
|
|
22
|
-
describe('one schema, both sides of the wire', () => {
|
|
23
|
-
for (const { name, input } of CASES) {
|
|
24
|
-
it(`web and core agree on: ${name}`, () => {
|
|
25
|
-
const webVerdict = validateNewNote(input);
|
|
26
|
-
const coreVerdict = NewNoteSchema.safeParse(input);
|
|
27
|
-
expect(webVerdict.ok).toBe(coreVerdict.success);
|
|
28
|
-
|
|
29
|
-
// …and the domain function (used by the API usecase) agrees with both.
|
|
30
|
-
if (coreVerdict.success) {
|
|
31
|
-
expect(() => createNote(input, identity)).not.toThrow();
|
|
32
|
-
} else {
|
|
33
|
-
expect(() => createNote(input, identity)).toThrow(InvalidNoteError);
|
|
34
|
-
expect(webVerdict.issues.length).toBeGreaterThan(0);
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../../tsconfig.base.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"module": "esnext",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"jsx": "preserve",
|
|
7
|
-
"lib": ["dom", "dom.iterable", "es2022"],
|
|
8
|
-
"noEmit": true,
|
|
9
|
-
"allowJs": true,
|
|
10
|
-
"plugins": [{ "name": "next" }]
|
|
11
|
-
},
|
|
12
|
-
"include": ["src/**/*.ts", "src/**/*.tsx", "test/**/*.ts"],
|
|
13
|
-
"exclude": ["node_modules", "out", ".next"]
|
|
14
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import eslint from '@eslint/js';
|
|
2
|
-
import globals from 'globals';
|
|
3
|
-
import tseslint from 'typescript-eslint';
|
|
4
|
-
|
|
5
|
-
export default tseslint.config(
|
|
6
|
-
{
|
|
7
|
-
ignores: [
|
|
8
|
-
'**/node_modules/**',
|
|
9
|
-
'**/dist/**',
|
|
10
|
-
'**/cdk.out/**',
|
|
11
|
-
'**/coverage/**',
|
|
12
|
-
'**/.next/**',
|
|
13
|
-
'**/out/**',
|
|
14
|
-
'**/next-env.d.ts',
|
|
15
|
-
],
|
|
16
|
-
},
|
|
17
|
-
eslint.configs.recommended,
|
|
18
|
-
...tseslint.configs.recommended,
|
|
19
|
-
{ languageOptions: { globals: globals.node } },
|
|
20
|
-
);
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
node_modules/
|
|
2
|
-
dist/
|
|
3
|
-
coverage/
|
|
4
|
-
cdk.out/
|
|
5
|
-
# what `cdk deploy --outputs-file` writes: bucket names, distribution ids,
|
|
6
|
-
# endpoints. Harmless today, and the file that accumulates the ones that are not.
|
|
7
|
-
cdk-outputs.json
|
|
8
|
-
*.tsbuildinfo
|
|
9
|
-
.DS_Store
|
|
10
|
-
.next/
|
|
11
|
-
out/
|
|
12
|
-
next-env.d.ts
|
|
13
|
-
.claude/worktrees/
|
|
14
|
-
# per-checkout queue state: the tier the last close recorded. The queue CONFIG
|
|
15
|
-
# is composed and tracked; this is runtime state and must never be committed.
|
|
16
|
-
.claude/queue.state.json
|
|
17
|
-
# per-checkout board selector (`queue/index.mjs board <name>`); the boards are in the config
|
|
18
|
-
.claude/queue.board
|
|
19
|
-
# gate rounds, one count per branch
|
|
20
|
-
.claude/gate-rounds.json
|
|
21
|
-
# per-run machine trace (.claude/scripts/run-journal.mjs): forensics that churn
|
|
22
|
-
# on every gate and collide across concurrent sessions. Unlike a committed
|
|
23
|
-
# evidence directory, this one is per-run and stays out of the repository.
|
|
24
|
-
.claude/runs/
|
|
25
|
-
|
|
26
|
-
# secrets — never commit these
|
|
27
|
-
*.env
|
|
28
|
-
.env
|
|
29
|
-
.env.*
|
|
30
|
-
!.env.example
|
|
31
|
-
.envrc
|
|
32
|
-
.npmrc
|
|
33
|
-
.netrc
|
|
34
|
-
.pgpass
|
|
35
|
-
id_rsa
|
|
36
|
-
id_ed25519
|
|
37
|
-
*.pem
|
|
38
|
-
*.key
|
|
39
|
-
*.p12
|
|
40
|
-
*.pfx
|
|
41
|
-
*.keystore
|
|
42
|
-
*.jks
|
|
43
|
-
*.secret
|
|
44
|
-
*.secrets
|
|
45
|
-
*.token
|
|
46
|
-
*.tokens
|
|
47
|
-
*.password
|
|
48
|
-
*.passwords
|
|
49
|
-
*.credential
|
|
50
|
-
*.credentials
|
|
51
|
-
*.apikey
|
|
52
|
-
*.apikeys
|
|
53
|
-
*.passwd
|
|
54
|
-
*.creds
|
|
55
|
-
*.jwt
|
|
56
|
-
*.bearer
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { realpathSync } from 'node:fs';
|
|
2
|
-
import { fileURLToPath } from 'node:url';
|
|
3
|
-
import { App } from 'aws-cdk-lib';
|
|
4
|
-
import { AppStack, nothingGiven } from '../lib/app-stack.js';
|
|
5
|
-
import { WebStack } from '../lib/web-stack.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* The composition, as a function so a test can synthesise the same wiring the
|
|
9
|
-
* CLI gets. A test that re-wires the stacks itself would pass while this file
|
|
10
|
-
* stayed broken, which is the one failure worth catching here.
|
|
11
|
-
*/
|
|
12
|
-
export function createApp(): App {
|
|
13
|
-
const app = new App();
|
|
14
|
-
|
|
15
|
-
// Region-agnostic by default; `cdk deploy` uses your CLI profile. Pin it here
|
|
16
|
-
// when the project settles (the generator's default region is __REGION__).
|
|
17
|
-
const env = { region: process.env.CDK_DEFAULT_REGION };
|
|
18
|
-
|
|
19
|
-
// The web stack first: the API has to allow the origin the browser loads the
|
|
20
|
-
// app from, and that origin is a CloudFront domain this stack owns. Passing
|
|
21
|
-
// it makes CORS correct on the first deploy instead of after someone
|
|
22
|
-
// discovers the app is blocked and reaches for `*`.
|
|
23
|
-
//
|
|
24
|
-
// The price, so it is not discovered later: this is a cross-stack export, so
|
|
25
|
-
// WebStack is deploy-ordered before AppStack and cannot be torn down while
|
|
26
|
-
// AppStack still imports it — CDK warns about the reference strength on
|
|
27
|
-
// synth. Pass `allowedOrigins` explicitly (a custom domain, several origins)
|
|
28
|
-
// and the export disappears with it.
|
|
29
|
-
const web = new WebStack(app, 'WebStack', {
|
|
30
|
-
description: 'Static web serving for __PROJECT_NAME__ (generated by create-agent-rig)',
|
|
31
|
-
env,
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
// `-c allowedOrigins=…` wins over the wired default — a custom domain is a
|
|
35
|
-
// deliberate act, and props short-circuit the context inside AppStack, so
|
|
36
|
-
// passing them unconditionally would accept the flag and ignore it. Omitting
|
|
37
|
-
// the prop hands the flag to AppStack's own validation instead of dropping
|
|
38
|
-
// it: an unusable value is refused at synth rather than deployed.
|
|
39
|
-
// `nothingGiven` is imported rather than restated: this file and the stack
|
|
40
|
-
// both decide whether the operator supplied an origin, and two spellings of
|
|
41
|
-
// that question is how `"allowedOrigins": null` in cdk.json comes to mean
|
|
42
|
-
// "they chose one" here and "use the default" there — a green synth whose
|
|
43
|
-
// deployed API allows only localhost.
|
|
44
|
-
const override = app.node.tryGetContext('allowedOrigins');
|
|
45
|
-
|
|
46
|
-
new AppStack(app, 'AppStack', {
|
|
47
|
-
description: 'API + worker for __PROJECT_NAME__ (generated by create-agent-rig)',
|
|
48
|
-
env,
|
|
49
|
-
...(nothingGiven(override) ? { allowedOrigins: [web.origin] } : {}),
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
return app;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Only when the CDK CLI runs this file. A test importing `createApp` would
|
|
57
|
-
* otherwise build a second composition — and re-bundle three Lambdas — for an
|
|
58
|
-
* App nobody looks at.
|
|
59
|
-
*
|
|
60
|
-
* Both sides go through realpath: ESM resolves `import.meta.url` through
|
|
61
|
-
* symlinks while `process.argv[1]` keeps the path as typed, so a checkout
|
|
62
|
-
* behind a link (a macOS temp dir, a symlinked home) would fail a plain
|
|
63
|
-
* comparison and synthesise an empty app.
|
|
64
|
-
*/
|
|
65
|
-
function invokedDirectly(): boolean {
|
|
66
|
-
if (!process.argv[1]) return false;
|
|
67
|
-
const real = (p: string) => {
|
|
68
|
-
try {
|
|
69
|
-
return realpathSync(p);
|
|
70
|
-
} catch {
|
|
71
|
-
return p;
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
return real(fileURLToPath(import.meta.url)) === real(process.argv[1]);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (invokedDirectly()) {
|
|
78
|
-
createApp();
|
|
79
|
-
}
|
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { fileURLToPath } from 'node:url';
|
|
3
|
-
import {
|
|
4
|
-
Annotations,
|
|
5
|
-
CfnOutput,
|
|
6
|
-
Duration,
|
|
7
|
-
RemovalPolicy,
|
|
8
|
-
Stack,
|
|
9
|
-
Token,
|
|
10
|
-
type StackProps,
|
|
11
|
-
} from 'aws-cdk-lib';
|
|
12
|
-
import { CorsHttpMethod, HttpApi, HttpMethod } from 'aws-cdk-lib/aws-apigatewayv2';
|
|
13
|
-
import { HttpLambdaIntegration } from 'aws-cdk-lib/aws-apigatewayv2-integrations';
|
|
14
|
-
import { ComparisonOperator, TreatMissingData } from 'aws-cdk-lib/aws-cloudwatch';
|
|
15
|
-
import { AttributeType, BillingMode, Table } from 'aws-cdk-lib/aws-dynamodb';
|
|
16
|
-
import { Runtime } from 'aws-cdk-lib/aws-lambda';
|
|
17
|
-
import { SqsEventSource } from 'aws-cdk-lib/aws-lambda-event-sources';
|
|
18
|
-
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
|
|
19
|
-
import { Queue } from 'aws-cdk-lib/aws-sqs';
|
|
20
|
-
import type { Construct } from 'constructs';
|
|
21
|
-
|
|
22
|
-
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
23
|
-
const workspaceRoot = path.resolve(here, '..', '..');
|
|
24
|
-
|
|
25
|
-
export interface AppStackProps extends StackProps {
|
|
26
|
-
/**
|
|
27
|
-
* Browser origins allowed to call the API.
|
|
28
|
-
*
|
|
29
|
-
* `bin/app.ts` passes the CloudFront origin from `WebStack`, so a deployed
|
|
30
|
-
* app works without configuring anything. Pass this (or
|
|
31
|
-
* `-c allowedOrigins=https://…`, comma-separated, which the entrypoint
|
|
32
|
-
* prefers when given) for a custom domain, a staging origin, or several.
|
|
33
|
-
*/
|
|
34
|
-
allowedOrigins?: string[];
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Local dev only: a real origin is a deliberate act, not a default.
|
|
39
|
-
*
|
|
40
|
-
* The port belongs to `apps/web`'s `dev` script — that is the source of truth,
|
|
41
|
-
* and a test reads it from there rather than restating it. A default naming a
|
|
42
|
-
* port nothing serves is worse than no default: it looks configured.
|
|
43
|
-
*/
|
|
44
|
-
const DEFAULT_ALLOWED_ORIGINS = ['http://localhost:3001'];
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Props win, then `-c allowedOrigins=a,b`, then the local default.
|
|
48
|
-
*
|
|
49
|
-
* Anything given but unusable — an empty list, a context value that trims away
|
|
50
|
-
* to nothing, a value that is not a string — throws rather than falling back.
|
|
51
|
-
* The failure this prevents is silent: an API synthesised with an empty
|
|
52
|
-
* allow-list blocks every browser call, and the symptom appears far from the
|
|
53
|
-
* flag that caused it.
|
|
54
|
-
*
|
|
55
|
-
* Exported for the tests, and only for them — nothing else imports it. The
|
|
56
|
-
* alternative was a case per branch built on its own `AppStack`, which cost a
|
|
57
|
-
* full synth and three Lambda bundles each and put the generated project's
|
|
58
|
-
* suite over its hook timeout.
|
|
59
|
-
*/
|
|
60
|
-
export function resolveAllowedOrigins(fromProps: string[] | undefined, fromContext: unknown): string[] {
|
|
61
|
-
if (fromProps !== undefined) {
|
|
62
|
-
if (fromProps.length === 0) {
|
|
63
|
-
throw new Error('allowedOrigins was given as an empty list — name an origin, or omit it');
|
|
64
|
-
}
|
|
65
|
-
return fromProps.map(checkedOrigin);
|
|
66
|
-
}
|
|
67
|
-
if (nothingGiven(fromContext)) return DEFAULT_ALLOWED_ORIGINS;
|
|
68
|
-
if (typeof fromContext !== 'string') {
|
|
69
|
-
throw new Error(
|
|
70
|
-
`allowedOrigins must be a comma-separated string, got ${typeof fromContext} — ` +
|
|
71
|
-
'use -c allowedOrigins=https://example.com',
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
const origins = fromContext
|
|
75
|
-
.split(',')
|
|
76
|
-
.map((origin) => origin.trim())
|
|
77
|
-
.filter(Boolean);
|
|
78
|
-
if (origins.length === 0) {
|
|
79
|
-
throw new Error(`allowedOrigins parsed to no origin at all from ${JSON.stringify(fromContext)}`);
|
|
80
|
-
}
|
|
81
|
-
return origins.map(checkedOrigin);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Whether the caller supplied nothing. Exported because `bin/app.ts` decides
|
|
86
|
-
* the same question about the same value, and two spellings of "nothing given"
|
|
87
|
-
* is how a `null` in `cdk.json` ends up meaning "the operator chose an origin"
|
|
88
|
-
* in one file and "use the default" in the other.
|
|
89
|
-
*/
|
|
90
|
-
export function nothingGiven(contextValue: unknown): boolean {
|
|
91
|
-
return contextValue === undefined || contextValue === null;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* An origin a browser could actually send: `*`, or a scheme plus a host.
|
|
96
|
-
*
|
|
97
|
-
* The check exists because the near-misses synthesise green and fail in the
|
|
98
|
-
* browser, far from the flag that caused them — `app.example.com` with the
|
|
99
|
-
* scheme left off is the likeliest of them, since an `Origin` header always
|
|
100
|
-
* carries one.
|
|
101
|
-
*/
|
|
102
|
-
function checkedOrigin(origin: string): string {
|
|
103
|
-
if (origin === '*') return origin;
|
|
104
|
-
// A cross-stack origin is a token here and a domain only at deploy time —
|
|
105
|
-
// there is nothing to parse yet, and refusing it would refuse the wiring
|
|
106
|
-
// this stack ships with.
|
|
107
|
-
if (Token.isUnresolved(origin)) return origin;
|
|
108
|
-
let parsed: URL;
|
|
109
|
-
try {
|
|
110
|
-
parsed = new URL(origin);
|
|
111
|
-
} catch {
|
|
112
|
-
throw new Error(
|
|
113
|
-
`allowedOrigins entry ${JSON.stringify(origin)} is not an origin — ` +
|
|
114
|
-
'a browser sends scheme://host[:port], as in https://app.example.com',
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
118
|
-
throw new Error(`allowedOrigins entry ${JSON.stringify(origin)} is not an http(s) origin`);
|
|
119
|
-
}
|
|
120
|
-
// The NORMALISED form, not what was typed: a trailing slash, an uppercase
|
|
121
|
-
// scheme, a path, a unicode host or a redundant :443 all synthesise green and
|
|
122
|
-
// then match no Origin header a browser sends.
|
|
123
|
-
return parsed.origin;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export class AppStack extends Stack {
|
|
127
|
-
constructor(scope: Construct, id: string, props?: AppStackProps) {
|
|
128
|
-
super(scope, id, props);
|
|
129
|
-
|
|
130
|
-
const allowedOrigins = resolveAllowedOrigins(
|
|
131
|
-
props?.allowedOrigins,
|
|
132
|
-
this.node.tryGetContext('allowedOrigins'),
|
|
133
|
-
);
|
|
134
|
-
|
|
135
|
-
// `*` is honoured — an operator who typed it into a flag has chosen it, and
|
|
136
|
-
// refusing would push them to edit this stack instead, which is worse. It
|
|
137
|
-
// does not get to be quiet about it: the whole point of not shipping the
|
|
138
|
-
// wildcard is that reaching for it should be a visible act.
|
|
139
|
-
if (allowedOrigins.includes('*')) {
|
|
140
|
-
// V2 because it can be acknowledged: `addWarning` hard-blocks
|
|
141
|
-
// `cdk synth --strict`, which would turn "loud" into "refused" for an
|
|
142
|
-
// operator who chose the wildcard deliberately.
|
|
143
|
-
Annotations.of(this).addWarningV2(
|
|
144
|
-
'@app/allowed-origins:wildcard',
|
|
145
|
-
'allowedOrigins includes "*": every site may call this API from a browser. ' +
|
|
146
|
-
'Name the origins instead unless this is a throwaway environment.',
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// --- storage: one single-table DynamoDB table --------------------------
|
|
151
|
-
const table = new Table(this, 'NotesTable', {
|
|
152
|
-
partitionKey: { name: 'pk', type: AttributeType.STRING },
|
|
153
|
-
sortKey: { name: 'sk', type: AttributeType.STRING },
|
|
154
|
-
billingMode: BillingMode.PAY_PER_REQUEST,
|
|
155
|
-
// Skeleton default: destroyable. Flip to RETAIN before storing real data.
|
|
156
|
-
removalPolicy: RemovalPolicy.DESTROY,
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
// --- queue with DLQ + alarm -------------------------------------------
|
|
160
|
-
const deadLetterQueue = new Queue(this, 'NotesDlq', {
|
|
161
|
-
retentionPeriod: Duration.days(14),
|
|
162
|
-
});
|
|
163
|
-
const queue = new Queue(this, 'NotesQueue', {
|
|
164
|
-
visibilityTimeout: Duration.seconds(30),
|
|
165
|
-
deadLetterQueue: { queue: deadLetterQueue, maxReceiveCount: 3 },
|
|
166
|
-
});
|
|
167
|
-
deadLetterQueue
|
|
168
|
-
.metricApproximateNumberOfMessagesVisible({ period: Duration.minutes(1) })
|
|
169
|
-
.createAlarm(this, 'DlqNotEmptyAlarm', {
|
|
170
|
-
alarmDescription: 'A message reached the DLQ — a consumer is failing.',
|
|
171
|
-
threshold: 1,
|
|
172
|
-
evaluationPeriods: 1,
|
|
173
|
-
comparisonOperator: ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
|
|
174
|
-
treatMissingData: TreatMissingData.NOT_BREACHING,
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
// --- functions ---------------------------------------------------------
|
|
178
|
-
const bundling = { sourceMap: false } as const;
|
|
179
|
-
const apiFunction = new NodejsFunction(this, 'CreateNoteFunction', {
|
|
180
|
-
entry: path.join(workspaceRoot, 'services', 'api', 'src', 'main.ts'),
|
|
181
|
-
handler: 'handler',
|
|
182
|
-
runtime: Runtime.NODEJS_22_X,
|
|
183
|
-
memorySize: 256,
|
|
184
|
-
timeout: Duration.seconds(10),
|
|
185
|
-
depsLockFilePath: path.join(workspaceRoot, 'pnpm-lock.yaml'),
|
|
186
|
-
bundling,
|
|
187
|
-
environment: {
|
|
188
|
-
TABLE_NAME: table.tableName,
|
|
189
|
-
QUEUE_URL: queue.queueUrl,
|
|
190
|
-
},
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
const listFunction = new NodejsFunction(this, 'ListNotesFunction', {
|
|
194
|
-
entry: path.join(workspaceRoot, 'services', 'api', 'src', 'list-main.ts'),
|
|
195
|
-
handler: 'handler',
|
|
196
|
-
runtime: Runtime.NODEJS_22_X,
|
|
197
|
-
memorySize: 256,
|
|
198
|
-
timeout: Duration.seconds(10),
|
|
199
|
-
depsLockFilePath: path.join(workspaceRoot, 'pnpm-lock.yaml'),
|
|
200
|
-
bundling,
|
|
201
|
-
environment: {
|
|
202
|
-
TABLE_NAME: table.tableName,
|
|
203
|
-
},
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
const workerFunction = new NodejsFunction(this, 'NoteCreatedWorker', {
|
|
207
|
-
entry: path.join(workspaceRoot, 'services', 'worker', 'src', 'main.ts'),
|
|
208
|
-
handler: 'handler',
|
|
209
|
-
runtime: Runtime.NODEJS_22_X,
|
|
210
|
-
memorySize: 256,
|
|
211
|
-
timeout: Duration.seconds(10),
|
|
212
|
-
depsLockFilePath: path.join(workspaceRoot, 'pnpm-lock.yaml'),
|
|
213
|
-
bundling,
|
|
214
|
-
});
|
|
215
|
-
workerFunction.addEventSource(new SqsEventSource(queue, { batchSize: 1 }));
|
|
216
|
-
|
|
217
|
-
// --- least-privilege grants: exactly what each function does ----------
|
|
218
|
-
table.grantWriteData(apiFunction); // the creator only puts
|
|
219
|
-
queue.grantSendMessages(apiFunction); // and publishes
|
|
220
|
-
table.grantReadData(listFunction); // the lister only reads
|
|
221
|
-
|
|
222
|
-
// --- the HTTP routes ---------------------------------------------------
|
|
223
|
-
// CORS: the web bundle is served from another origin (CloudFront), so the
|
|
224
|
-
// API has to name who may call it. `*` is not that name — a starter
|
|
225
|
-
// multiplies whatever it ships, and a wildcard here becomes the default of
|
|
226
|
-
// every project generated from it.
|
|
227
|
-
const httpApi = new HttpApi(this, 'NotesApi', {
|
|
228
|
-
corsPreflight: {
|
|
229
|
-
allowOrigins: allowedOrigins,
|
|
230
|
-
allowMethods: [CorsHttpMethod.GET, CorsHttpMethod.POST],
|
|
231
|
-
allowHeaders: ['content-type'],
|
|
232
|
-
},
|
|
233
|
-
});
|
|
234
|
-
httpApi.addRoutes({
|
|
235
|
-
path: '/notes',
|
|
236
|
-
methods: [HttpMethod.POST],
|
|
237
|
-
integration: new HttpLambdaIntegration('CreateNoteIntegration', apiFunction),
|
|
238
|
-
});
|
|
239
|
-
httpApi.addRoutes({
|
|
240
|
-
path: '/notes',
|
|
241
|
-
methods: [HttpMethod.GET],
|
|
242
|
-
integration: new HttpLambdaIntegration('ListNotesIntegration', listFunction),
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
new CfnOutput(this, 'ApiUrl', { value: httpApi.apiEndpoint });
|
|
246
|
-
new CfnOutput(this, 'DlqUrl', { value: deadLetterQueue.queueUrl });
|
|
247
|
-
}
|
|
248
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
// Stateless serving for the static web export: a private S3 bucket behind
|
|
2
|
-
// CloudFront. Deliberately no BucketDeployment construct — synth must never
|
|
3
|
-
// depend on `next build` having run. The bundle ships via `aws s3 sync`
|
|
4
|
-
// (see README), keeping the stack small and the dependency one-way.
|
|
5
|
-
import { CfnOutput, RemovalPolicy, Stack, type StackProps } from 'aws-cdk-lib';
|
|
6
|
-
import { Distribution, ViewerProtocolPolicy } from 'aws-cdk-lib/aws-cloudfront';
|
|
7
|
-
import { S3BucketOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
|
|
8
|
-
import { BlockPublicAccess, Bucket } from 'aws-cdk-lib/aws-s3';
|
|
9
|
-
import type { Construct } from 'constructs';
|
|
10
|
-
|
|
11
|
-
export class WebStack extends Stack {
|
|
12
|
-
/**
|
|
13
|
-
* Where the browser loads the app from — and therefore the origin the API
|
|
14
|
-
* has to allow. A synth-time token: CDK resolves it across stacks as an
|
|
15
|
-
* `Fn::ImportValue`, so `AppStack` can name it without either stack having
|
|
16
|
-
* been deployed yet.
|
|
17
|
-
*/
|
|
18
|
-
public readonly origin: string;
|
|
19
|
-
|
|
20
|
-
constructor(scope: Construct, id: string, props?: StackProps) {
|
|
21
|
-
super(scope, id, props);
|
|
22
|
-
|
|
23
|
-
const bucket = new Bucket(this, 'WebBucket', {
|
|
24
|
-
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
|
|
25
|
-
// Skeleton default: destroyable. Flip to RETAIN before real traffic.
|
|
26
|
-
removalPolicy: RemovalPolicy.DESTROY,
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
const distribution = new Distribution(this, 'WebDistribution', {
|
|
30
|
-
defaultBehavior: {
|
|
31
|
-
origin: S3BucketOrigin.withOriginAccessControl(bucket),
|
|
32
|
-
viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
|
|
33
|
-
},
|
|
34
|
-
defaultRootObject: 'index.html',
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
this.origin = `https://${distribution.domainName}`;
|
|
38
|
-
|
|
39
|
-
new CfnOutput(this, 'WebBucketName', { value: bucket.bucketName });
|
|
40
|
-
new CfnOutput(this, 'WebUrl', { value: this.origin });
|
|
41
|
-
// The upload step needs this to invalidate the edge cache: a synced bucket
|
|
42
|
-
// whose distribution still serves the old objects has not deployed.
|
|
43
|
-
new CfnOutput(this, 'WebDistributionId', { value: distribution.distributionId });
|
|
44
|
-
}
|
|
45
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@app/infra",
|
|
3
|
-
"version": "0.1.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"type": "module",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"synth": "cdk synth --quiet",
|
|
8
|
-
"deploy": "cdk deploy",
|
|
9
|
-
"destroy": "cdk destroy"
|
|
10
|
-
},
|
|
11
|
-
"dependencies": {
|
|
12
|
-
"aws-cdk-lib": "^2.261.0",
|
|
13
|
-
"constructs": "^10.7.1"
|
|
14
|
-
},
|
|
15
|
-
"devDependencies": {
|
|
16
|
-
"aws-cdk": "^2.1132.0"
|
|
17
|
-
}
|
|
18
|
-
}
|