@jaypie/mcp 0.8.58 → 0.8.59

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.
@@ -9,7 +9,7 @@ import { gt } from 'semver';
9
9
  /**
10
10
  * Docs Suite - Documentation services (skill, version, release_notes)
11
11
  */
12
- const BUILD_VERSION_STRING = "@jaypie/mcp@0.8.58#340296a3"
12
+ const BUILD_VERSION_STRING = "@jaypie/mcp@0.8.59#659b659d"
13
13
  ;
14
14
  const __filename$1 = fileURLToPath(import.meta.url);
15
15
  const __dirname$1 = path.dirname(__filename$1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jaypie/mcp",
3
- "version": "0.8.58",
3
+ "version": "0.8.59",
4
4
  "description": "Jaypie MCP",
5
5
  "repository": {
6
6
  "type": "git",
@@ -0,0 +1,58 @@
1
+ ---
2
+ version: 1.2.56
3
+ date: 2026-05-10
4
+ summary: JaypieMigration waiter pattern (#346); fix JaypieEnvSecret cross-stack export name regression (#347)
5
+ ---
6
+
7
+ ## Changes
8
+
9
+ ### `JaypieEnvSecret` — fix cross-stack export name regression (#347)
10
+
11
+ Two bugs introduced by the shorthand detection feature (1.2.44+) that broke cross-stack `JaypieEnvSecret` wiring:
12
+
13
+ 1. **Export name drift** — when using shorthand (`new JaypieEnvSecret(scope, "SECRET_KEY")`), the CDK construct id was prefixed to `EnvSecret_SECRET_KEY`, causing the auto-generated `Export.Name` to change from `env-<env>-<project>-SECRETKEY` to `env-<env>-<project>-EnvSecretSECRETKEY`. CloudFormation refused to delete the old export while any consumer still imported it.
14
+
15
+ 2. **Consumer `undefined` env vars** — `exportEnvName` ignored the explicit `consumer: true` prop and fell through to an else branch when `PROJECT_ENV` was not `"personal"`, producing `env-undefined-undefined-...` in `Fn::ImportValue`.
16
+
17
+ **Fixes:**
18
+ - `exportEnvName` now accepts `consumer` and uses it alongside `checkEnvIsConsumer(env)`, so explicit `{ consumer: true }` always resolves to the sandbox-scoped import name regardless of `PROJECT_ENV`.
19
+ - The `exportEnvName` call site now passes `envKey || id` instead of `id`, restoring the original key as the name component and eliminating the `EnvSecret` prefix from the export name.
20
+
21
+ ### `JaypieMigration` — waiter pattern with `queryInterval` and `totalTimeout` (#346)
22
+
23
+ - `JaypieMigrationProps` accepts two new optional props:
24
+ - `queryInterval?: cdk.Duration` — polling interval between `isCompleteHandler` invocations. Default: **60 seconds**.
25
+ - `totalTimeout?: cdk.Duration` — maximum wall time across all invocations. Default: **2 hours**.
26
+ - `cr.Provider` is now wired with `isCompleteHandler: this.lambda` in addition to `onEventHandler`, activating Step Functions-backed polling. Each invocation of `isCompleteHandler` lives under the per-Lambda timeout cap, but the orchestration can run for `totalTimeout` (up to 2 h by default).
27
+ - `onEventHandler` now returns `PhysicalResourceId` immediately; the migration Lambda runs exclusively in `isCompleteHandler` invocations.
28
+
29
+ ```ts
30
+ new JaypieMigration(this, "Migration", {
31
+ code: "dist/migration",
32
+ handler: "index.handler",
33
+ tables: [table],
34
+ queryInterval: Duration.seconds(60), // optional, this is the default
35
+ totalTimeout: Duration.hours(2), // optional, this is the default
36
+ });
37
+ ```
38
+
39
+ ## Motivation
40
+
41
+ `JaypieMigration` previously ran all migrations synchronously inside a single Lambda invocation, bounded by Lambda's 15-minute hard cap. Multi-step migrations whose cumulative wall time exceeds 15 minutes — three back-to-back GSI creations being the canonical example — would be killed mid-flight, causing CloudFormation rollback and repeated partial teardown cycles.
42
+
43
+ AWS's canonical answer for this shape is `cr.Provider`'s waiter pattern: an `isCompleteHandler` Lambda is invoked repeatedly on a `queryInterval` until it returns `IsComplete: true`. Step Functions orchestrates the polling loop; each invocation is independently time-bounded by the Lambda timeout, while the total can span hours.
44
+
45
+ ## Migration
46
+
47
+ No action required for existing single-shot migrations. `migrationHandler` maps a handler that returns no `pending` flag to `IsComplete: true`, so `cr.Provider` calls `isCompleteHandler` exactly once and the deploy completes as before. The only observable difference is an extra `onEventHandler` invocation (which returns immediately) before the migration runs.
48
+
49
+ To enable multi-step migrations, return `{ pending: true }` from `migrationHandler` until all steps are complete:
50
+
51
+ ```typescript
52
+ import { migrationHandler } from "jaypie";
53
+
54
+ export const handler = migrationHandler(async (event) => {
55
+ const remaining = await runNextPendingMigration();
56
+ return { pending: remaining > 0 };
57
+ });
58
+ ```
@@ -0,0 +1,29 @@
1
+ ---
2
+ version: 1.2.7
3
+ date: 2026-05-10
4
+ summary: migrationHandler waiter protocol — onEventHandler/isCompleteHandler mode detection and pending flag (#346)
5
+ ---
6
+
7
+ ## Changes
8
+
9
+ - `migrationHandler` now detects whether the Lambda is being invoked as `onEventHandler` or `isCompleteHandler` (by `cr.Provider`'s Step Functions waiter) and branches accordingly:
10
+ - **`onEventHandler` mode** (event has no `Data` field): returns `{ PhysicalResourceId }` immediately without running the user's handler. This is the fast-return that lets CFN start the polling loop.
11
+ - **`isCompleteHandler` mode** (event has a top-level `Data` field): runs the user's handler and wraps the result in CFN's `IsComplete` protocol: `{ IsComplete: !pending, Data: result }`.
12
+ - The user handler may return `{ pending: true }` to signal more work remains; the waiter will re-invoke after `queryInterval`. Omitting `pending` (or `pending: false`) maps to `IsComplete: true`.
13
+
14
+ ```typescript
15
+ import { migrationHandler } from "jaypie";
16
+
17
+ export const handler = migrationHandler(async (event) => {
18
+ const remaining = await runNextPendingMigration();
19
+ return { pending: remaining > 0 };
20
+ });
21
+ ```
22
+
23
+ ## Motivation
24
+
25
+ `cr.Provider` uses a Step Functions state machine to poll `isCompleteHandler` independently from `onEventHandler`. When both handlers point to the same Lambda ARN, the Lambda must distinguish its role from the event shape. `isCompleteHandler` events always carry a top-level `Data` field (whatever `onEventHandler` returned); `onEventHandler` events do not. This is the discriminator.
26
+
27
+ ## Migration
28
+
29
+ Existing `migrationHandler` users are upgraded automatically when they deploy with `@jaypie/constructs@1.2.56` (which now always wires `isCompleteHandler`). The migration runs in `isCompleteHandler` instead of `onEventHandler`; CloudFormation behavior is identical for single-shot migrations that complete in one call.
@@ -0,0 +1,9 @@
1
+ ---
2
+ version: 1.2.35
3
+ date: 2026-05-10
4
+ summary: Downgrade tool-throw log level from error to warn
5
+ ---
6
+
7
+ ## Bug Fixes
8
+
9
+ - **Tool throw log level** — When a tool registered with the operate loop throws, the error is now logged at `log.warn` instead of `log.error` in both the streaming and non-streaming paths. Tool throws are a normal operating mode; the loop already feeds the error back to the model as a `tool_result`. Elevating every tool throw to `error` caused monitoring noise for routine outcomes like authorization refusals and allowlist misses. The existing `log.warn("Stopped after N consecutive tool errors")` continues to fire at warn for the terminal threshold case.
@@ -0,0 +1,13 @@
1
+ ---
2
+ version: 0.8.59
3
+ date: 2026-05-10
4
+ summary: Update migrations skill for waiter pattern — pending flag, queryInterval, totalTimeout (#346)
5
+ ---
6
+
7
+ ## Changes
8
+
9
+ - Updated `skills/migrations.md` to document the `cr.Provider` waiter pattern introduced in `@jaypie/constructs@1.2.56` and `@jaypie/lambda@1.2.7`:
10
+ - New `queryInterval` and `totalTimeout` props in the Props table
11
+ - Updated Behavior section to describe the `onEventHandler` / `isCompleteHandler` two-phase execution model
12
+ - New "Multi-step migrations" section explaining the `pending` flag and waiter protocol
13
+ - Updated Construct Internals to mention the Step Functions state machine
@@ -35,20 +35,23 @@ new JaypieMigration(this, "SeedData", {
35
35
  | `dependencies` | `Construct[]` | `[]` | Constructs that must be created before the migration runs |
36
36
  | `environment` | `Record<string, string> \| (Record<string, string> \| string)[]` | - | Environment variables for the migration Lambda |
37
37
  | `handler` | `string` | `"index.handler"` | Lambda entry point |
38
+ | `queryInterval` | `cdk.Duration` | `Duration.seconds(60)` | Polling interval between `isCompleteHandler` invocations |
38
39
  | `secrets` | `SecretsArrayItem[]` | `[]` | Secrets to make available to the Lambda |
39
40
  | `tables` | `dynamodb.ITable[]` | `[]` | DynamoDB tables to grant read/write access |
41
+ | `timeout` | `cdk.Duration` | `Duration.minutes(15)` | Per-invocation Lambda timeout |
42
+ | `totalTimeout` | `cdk.Duration` | `Duration.hours(2)` | Maximum wall time across all `isCompleteHandler` invocations |
40
43
 
41
44
  ## Behavior
42
45
 
43
- - **Timeout**: 5 minutes (vs 30s for API Lambdas) to accommodate long-running migrations
46
+ - **Timeout**: 15 minutes per invocation (Lambda max); `totalTimeout` controls the end-to-end ceiling across all polling invocations (default 2 hours)
44
47
  - **Role**: Tagged as `CDK.ROLE.PROCESSING`
45
- - **Execution**: Runs on every deploy via CloudFormation custom resource (uses a deploy nonce to force re-invocation even when only Lambda code changes)
48
+ - **Execution**: Uses `cr.Provider` with both `onEventHandler` and `isCompleteHandler` pointing to the same Lambda. The `onEventHandler` returns `PhysicalResourceId` immediately; the migration code runs in `isCompleteHandler` invocations, which are polled by Step Functions until `IsComplete: true`.
46
49
  - **Dependencies**: Use `dependencies` to ensure tables and other resources exist before the migration executes
47
50
  - **Permissions**: Tables passed via `tables` get data-plane (`grantReadWriteData`) plus control-plane access (`DescribeTable`, `UpdateTable`, `UpdateTimeToLive`, `UpdateContinuousBackups`) scoped to the table ARN and its indexes — migrations that add GSIs, toggle TTL, or change backups work without extra IAM
48
51
 
49
52
  ## Migration Lambda Handler
50
53
 
51
- The migration Lambda receives a CloudFormation custom resource event. Use `migrationHandler` so a thrown error fails the CFN custom resource (and the deploy) `lambdaHandler`'s default `throw: false` returns a success-shaped response on error and CFN reports `CREATE_COMPLETE` even when the migration failed.
54
+ Use `migrationHandler` from `jaypie` so errors propagate as CFN failures and the waiter protocol is handled automatically.
52
55
 
53
56
  ```typescript
54
57
  // src/migrations/seed/index.ts
@@ -69,6 +72,21 @@ export const handler = migrationHandler(async (event) => {
69
72
 
70
73
  `migrationHandler` is `lambdaHandler` with `throw: true` defaulted. Pass `{ throw: false }` to opt back into soft-fail behavior.
71
74
 
75
+ ### Multi-step migrations (waiter pattern)
76
+
77
+ Return `{ pending: true }` to request another invocation after `queryInterval`. The handler runs repeatedly until `pending` is omitted or `false`.
78
+
79
+ ```typescript
80
+ export const handler = migrationHandler(async (event) => {
81
+ const remaining = await runNextPendingMigration();
82
+ return { pending: remaining > 0 };
83
+ });
84
+ ```
85
+
86
+ `migrationHandler` maps the `pending` flag onto CFN's `IsComplete` protocol:
87
+ - `pending: true` → `{ IsComplete: false }` — waiter re-invokes after `queryInterval`
88
+ - `pending: false` or omitted → `{ IsComplete: true }` — deploy proceeds
89
+
72
90
  ## Building Migration Code
73
91
 
74
92
  Bundle migrations separately using esbuild, then reference the output directory:
@@ -110,11 +128,11 @@ new JaypieMigration(this, "DataMigration", {
110
128
 
111
129
  ## Construct Internals
112
130
 
113
- `JaypieMigration` creates three resources:
131
+ `JaypieMigration` creates:
114
132
 
115
133
  1. **`JaypieLambda`** - The migration function (exposed as `migration.lambda`)
116
- 2. **`cr.Provider`** - CloudFormation custom resource provider wrapping the Lambda
117
- 3. **`cdk.CustomResource`** - The custom resource that triggers on every deploy
134
+ 2. **`cr.Provider`** - Custom resource provider with `onEventHandler` and `isCompleteHandler` both pointing to the migration Lambda; backed by a Step Functions state machine for the waiter loop
135
+ 3. **`cdk.CustomResource`** - Triggers on every deploy via a `deployNonce` property
118
136
 
119
137
  Dependencies are attached to the custom resource so the migration waits for prerequisite resources.
120
138