@jaypie/mcp 0.2.10 → 0.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jaypie/mcp",
3
- "version": "0.2.10",
3
+ "version": "0.3.0",
4
4
  "description": "Jaypie MCP",
5
5
  "repository": {
6
6
  "type": "git",
@@ -102,33 +102,27 @@ Preconfigured with API-optimized timeouts and role tags.
102
102
 
103
103
  ### Streaming Lambda Functions
104
104
 
105
- Use `JaypieStreamingLambda` for Express apps with AWS Lambda Web Adapter and streaming support:
105
+ For streaming responses (SSE, real-time updates), use `createLambdaStreamHandler` from `@jaypie/express` with `JaypieDistribution`:
106
106
 
107
107
  ```typescript
108
- import { JaypieStreamingLambda, JaypieDistribution } from "@jaypie/constructs";
108
+ import { JaypieExpressLambda, JaypieDistribution } from "@jaypie/constructs";
109
+ import * as lambda from "aws-cdk-lib/aws-lambda";
109
110
 
110
- // Create streaming Lambda with Web Adapter
111
- const streamingLambda = new JaypieStreamingLambda(this, "StreamingApi", {
111
+ // Create Lambda (handler uses createLambdaStreamHandler internally)
112
+ const streamingApi = new JaypieExpressLambda(this, "StreamingApi", {
112
113
  code: "dist/api",
113
- handler: "run.sh", // Shell script to start Express app
114
- streaming: true, // Enables RESPONSE_STREAM invoke mode
115
- port: 8000, // Port your app listens on (default: 8000)
114
+ handler: "index.handler",
116
115
  });
117
116
 
118
- // CloudFront auto-detects invokeMode from JaypieStreamingLambda
117
+ // Use with CloudFront and RESPONSE_STREAM invoke mode
119
118
  new JaypieDistribution(this, "Distribution", {
120
- handler: streamingLambda,
119
+ handler: streamingApi,
120
+ invokeMode: lambda.InvokeMode.RESPONSE_STREAM,
121
121
  host: "api.example.com",
122
122
  zone: "example.com",
123
123
  });
124
124
  ```
125
125
 
126
- Features:
127
- - Automatically adds AWS Lambda Web Adapter layer (supports ARM64 and x86_64)
128
- - Sets `AWS_LAMBDA_EXEC_WRAPPER` and `AWS_LWA_INVOKE_MODE` environment variables
129
- - Exposes `invokeMode` property for auto-detection by `JaypieDistribution`
130
- - Use `streaming: false` for buffered mode (traditional Lambda behavior)
131
-
132
126
  For direct Function URL access (bypass CloudFront):
133
127
  ```typescript
134
128
  import { FunctionUrlAuthType, InvokeMode } from "aws-cdk-lib/aws-lambda";
@@ -147,7 +141,7 @@ const functionUrl = streamingLambda.addFunctionUrl({
147
141
  new cdk.CfnOutput(this, "StreamingUrl", { value: functionUrl.url });
148
142
  ```
149
143
 
150
- Note: API Gateway has a 29-second timeout limit. For longer streaming operations, use Function URLs or CloudFront with Lambda Function URLs.
144
+ Note: Streaming requires Lambda Function URLs (not API Gateway). `JaypieDistribution` uses Function URLs by default.
151
145
 
152
146
  ### Stack Types
153
147
 
@@ -323,21 +317,22 @@ Common usage:
323
317
 
324
318
  ### DynamoDB Tables
325
319
 
326
- Use `JaypieDynamoDb` for single-table design with Jaypie GSI patterns:
320
+ Use `JaypieDynamoDb` for single-table design with Jaypie patterns:
327
321
  ```typescript
328
322
  // Shorthand: tableName becomes "myApp", construct id is "JaypieDynamoDb-myApp"
329
323
  const table = new JaypieDynamoDb(this, "myApp");
330
324
 
331
- // No GSIs
332
- const table = new JaypieDynamoDb(this, "MyTable", {
333
- globalSecondaryIndexes: false,
325
+ // With standard Jaypie GSIs (indexScope, indexAlias, indexClass, indexType, indexXid)
326
+ const tableWithIndexes = new JaypieDynamoDb(this, "myApp", {
327
+ indexes: JaypieDynamoDb.DEFAULT_INDEXES,
334
328
  });
335
329
 
336
- // Use only specific GSIs
337
- const table = new JaypieDynamoDb(this, "MyTable", {
338
- globalSecondaryIndexes: [
339
- JaypieDynamoDb.GlobalSecondaryIndex.Ou,
340
- JaypieDynamoDb.GlobalSecondaryIndex.Type,
330
+ // With custom indexes using IndexDefinition from @jaypie/fabric
331
+ const customTable = new JaypieDynamoDb(this, "myApp", {
332
+ indexes: [
333
+ { pk: ["scope", "model"], sk: ["sequence"] }, // indexScopeModel
334
+ { pk: ["scope", "model", "type"], sparse: true }, // indexScopeModelType
335
+ { name: "byAlias", pk: ["alias"], sk: ["createdAt"] }, // custom name
341
336
  ],
342
337
  });
343
338
 
@@ -352,9 +347,9 @@ Features:
352
347
  - Default partition key: `model` (string), sort key: `id` (string)
353
348
  - PAY_PER_REQUEST billing mode by default
354
349
  - RETAIN removal policy in production, DESTROY otherwise
355
- - GSI options: `true`/omit = all five, `false` = none, array = specific GSIs
356
- - Static constants: `JaypieDynamoDb.GlobalSecondaryIndex.*` and `JaypieDynamoDb.GlobalSecondaryIndexes`
357
- - All GSIs use partition key (string) + `sequence` (number) sort key
350
+ - No GSIs by default - use `indexes` prop to add them
351
+ - `JaypieDynamoDb.DEFAULT_INDEXES` provides standard Jaypie GSIs from `@jaypie/fabric`
352
+ - Uses `IndexDefinition` from `@jaypie/fabric` for GSI configuration
358
353
  - Implements `ITableV2` interface
359
354
 
360
355
  For single-table design patterns, key builders, and query utilities, see `Jaypie_DynamoDB_Package.md`.
@@ -6,6 +6,14 @@ description: conventions around deployment and environment variables, especially
6
6
 
7
7
  Reference for Jaypie CI/CD conventions. For setup instructions, see `Jaypie_Init_CICD_with_GitHub_Actions.md`.
8
8
 
9
+ ## Workspace Naming Conventions
10
+
11
+ | Directory | Purpose |
12
+ |-----------|---------|
13
+ | `packages/` | Default workspace for npm packages (preferred when only one namespace needed) |
14
+ | `stacks/` | CDK-deployed infrastructure and sites (as opposed to npm-published) |
15
+ | `workspaces/` | Generic workspace for other work |
16
+
9
17
  ## Jaypie Environments
10
18
 
11
19
  Jaypie assumes multiple deployed environments:
@@ -19,11 +27,21 @@ Jaypie assumes multiple deployed environments:
19
27
 
20
28
  ## Naming Conventions
21
29
 
22
- Workflow files lead with the most important keyword and end with the environment:
23
- - `deploy-personal-build.yml`
24
- - `deploy-sandbox.yml`
25
- - `deploy-production.yml`
26
- - `npm-deploy.yml`
30
+ ### Workflow File Naming
31
+
32
+ | Pattern | Purpose | Example |
33
+ |---------|---------|---------|
34
+ | `deploy-env-$ENV.yml` | Deploy all stacks to an environment | `deploy-env-sandbox.yml` |
35
+ | `deploy-$ENV.yml` | Legacy alias for environment deploy | `deploy-sandbox.yml` |
36
+ | `deploy-stack-$STACK.yml` | Deploy specific stack content | `deploy-stack-documentation.yml` |
37
+
38
+ ### Tag Naming
39
+
40
+ | Pattern | Purpose | Example |
41
+ |---------|---------|---------|
42
+ | `v*` | Production version release | `v1.2.3` |
43
+ | `$ENV-*` | Deploy to specific environment | `sandbox-hotfix` |
44
+ | `stack-$STACK-*` | Deploy specific stack | `stack-documentation-v1.0.0` |
27
45
 
28
46
  Always prefer full words for maximum clarity.
29
47
 
@@ -54,11 +72,17 @@ jobs: # alphabetical
54
72
 
55
73
  | Environment | Trigger |
56
74
  |-------------|---------|
57
- | production | tags: `v*` |
58
- | development | branches: `[main]` |
59
- | sandbox | branches: `[main, develop, sandbox, sandbox-*, sandbox/*]` |
75
+ | production | tags: `v*`, `production-*` |
76
+ | development | branches: `[main, development/*]`, tags: `development-*` |
77
+ | sandbox | branches: `[feat/*, sandbox/*]`, tags: `sandbox-*` |
60
78
  | personal | branches-ignore: `[main, develop, nobuild-*, nobuild/*, sandbox, sandbox-*, sandbox/*]` |
61
79
 
80
+ ### Stack Triggers
81
+
82
+ | Stack | Trigger |
83
+ |-------|---------|
84
+ | documentation | Push to `main` with path filter, tags: `stack-documentation-*` |
85
+
62
86
  ### Dependencies
63
87
 
64
88
  | Environment | Lint/Test Dependency |
@@ -74,14 +98,20 @@ Use `npm run lint` and `npm run test`. Verify the test script uses `vitest run`
74
98
 
75
99
  ## Concurrency
76
100
 
77
- New builds cancel in-progress builds. Environments run in parallel between each other but concurrently within an environment.
101
+ Use concurrency groups without `cancel-in-progress` to avoid stuck deployments. Environments run in parallel between each other but concurrently within an environment.
102
+
103
+ ### Environment Builds
104
+
105
+ ```yaml
106
+ concurrency:
107
+ group: deploy-env-production
108
+ ```
78
109
 
79
- ### Static Builds
110
+ ### Stack Builds
80
111
 
81
112
  ```yaml
82
113
  concurrency:
83
- group: deploy-production
84
- cancel-in-progress: true
114
+ group: deploy-stack-documentation-${{ github.event.inputs.environment || 'development' }}
85
115
  ```
86
116
 
87
117
  ### Personal Builds
@@ -89,7 +119,6 @@ concurrency:
89
119
  ```yaml
90
120
  concurrency:
91
121
  group: deploy-personal-build-${{ github.actor }}
92
- cancel-in-progress: true
93
122
  ```
94
123
 
95
124
  ## Personal Builds
@@ -122,6 +151,48 @@ Create GitHub environments matching deployment targets:
122
151
 
123
152
  Each environment contains variables and secrets specific to that deployment target.
124
153
 
154
+ ## GitHub Variable Scoping
155
+
156
+ Variables are configured at different levels in GitHub Settings:
157
+
158
+ ### Organization Level
159
+
160
+ | Variable | Description | Default |
161
+ |----------|-------------|---------|
162
+ | `AWS_REGION` | AWS region | `us-east-1` |
163
+ | `LOG_LEVEL` | Application log level | `debug` |
164
+ | `MODULE_LOG_LEVEL` | Module log level | `warn` |
165
+ | `PROJECT_SPONSOR` | Organization name | `finlaysonstudio` |
166
+
167
+ ### Repository Level
168
+
169
+ | Variable | Description | Default |
170
+ |----------|-------------|---------|
171
+ | `AWS_HOSTED_ZONE` | Route53 hosted zone | `example.com` |
172
+ | `PROJECT_KEY` | Project identifier | `myapp` |
173
+ | `PROJECT_SERVICE` | Service name | `stacks` |
174
+
175
+ ### Environment Level
176
+
177
+ | Variable | Description | Required |
178
+ |----------|-------------|----------|
179
+ | `AWS_ROLE_ARN` | IAM role ARN for OIDC | Yes |
180
+ | `DATADOG_API_KEY_ARN` | Datadog API key ARN in Secrets Manager | No |
181
+ | `PROJECT_ENV` | Environment identifier | Yes |
182
+ | `PROJECT_NONCE` | Unique resource identifier | No |
183
+
184
+ ### Auto-Generated Variables
185
+
186
+ These variables are set automatically from GitHub context:
187
+
188
+ | Variable | Source | Description |
189
+ |----------|--------|-------------|
190
+ | `CDK_DEFAULT_ACCOUNT` | `${{ github.repository_owner }}` | Repository owner |
191
+ | `CDK_DEFAULT_REGION` | `AWS_REGION` | Same as AWS region |
192
+ | `CDK_ENV_REPO` | `${{ github.repository }}` | Repository name (owner/repo) |
193
+ | `PROJECT_COMMIT` | `${{ github.sha }}` | Current commit SHA |
194
+ | `PROJECT_VERSION` | `package.json` | Version from package.json |
195
+
125
196
  ## Environment Variables Reference
126
197
 
127
198
  ### Application Variables
@@ -169,6 +240,8 @@ Follow naming from vendor documentation. If documentation does not reference env
169
240
 
170
241
  ## Secrets
171
242
 
243
+ By default, no secrets are required. Dependencies add secrets as needed.
244
+
172
245
  ### Secret Naming
173
246
 
174
247
  Secrets follow the same conventions as variables. Use `SECRET_` prefix for secrets that will be resolved at runtime:
@@ -177,6 +250,8 @@ Secrets follow the same conventions as variables. Use `SECRET_` prefix for secre
177
250
 
178
251
  ### Passing Secrets
179
252
 
253
+ Secrets are passed to CDK via `JaypieEnvSecret` construct and made available at runtime.
254
+
180
255
  Pass secrets only to steps that need them:
181
256
 
182
257
  ```yaml
@@ -190,6 +265,30 @@ Pass secrets only to steps that need them:
190
265
 
191
266
  Never expose secrets in logs or workflow outputs.
192
267
 
268
+ ### Adding Dependency Secrets
269
+
270
+ When adding dependencies that require secrets, update the workflow accordingly.
271
+
272
+ #### Example: Auth0 Integration
273
+
274
+ **Environment Variables:**
275
+ - `AUTH0_AUDIENCE` - API identifier
276
+ - `AUTH0_CLIENT_ID` - Application client ID
277
+ - `AUTH0_DOMAIN` - Auth0 tenant domain
278
+
279
+ **Environment Secrets:**
280
+ - `AUTH0_CLIENT_SECRET` - Application client secret
281
+
282
+ Add to workflow:
283
+ ```yaml
284
+ - name: Deploy CDK Stack
285
+ uses: ./.github/actions/cdk-deploy
286
+ with:
287
+ stack-name: AppStack
288
+ env:
289
+ AUTH0_CLIENT_SECRET: ${{ secrets.AUTH0_CLIENT_SECRET }}
290
+ ```
291
+
193
292
  ## CDK Stack Names
194
293
 
195
294
  The `stack-name` parameter in deploy workflows must match the stack ID defined in `packages/cdk/bin/cdk.ts`:
@@ -200,7 +299,7 @@ new AppStack(app, "AppStack"); // "AppStack" is the stack ID
200
299
  ```
201
300
 
202
301
  ```yaml
203
- # deploy-*.yml
302
+ # deploy-env-*.yml
204
303
  - name: Deploy CDK Stack
205
304
  uses: ./.github/actions/cdk-deploy
206
305
  with:
@@ -209,6 +308,34 @@ new AppStack(app, "AppStack"); // "AppStack" is the stack ID
209
308
 
210
309
  If you rename the stack ID (e.g., to "MyProjectAppStack" for clarity in AWS), update all deploy workflows to match. Mismatched names cause "No stacks match the name(s)" errors.
211
310
 
311
+ ## Environment-Aware Hostnames
312
+
313
+ Jaypie CDK constructs use `envHostname()` from `@jaypie/constructs` to determine deployment hostnames based on `PROJECT_ENV`:
314
+
315
+ | `PROJECT_ENV` | Example Hostname |
316
+ |---------------|------------------|
317
+ | `production` | `example.com` (apex domain) |
318
+ | `sandbox` | `sandbox.example.com` |
319
+ | `development` | `development.example.com` |
320
+ | `personal` | `personal.example.com` |
321
+
322
+ **CRITICAL**: If `PROJECT_ENV` is not set or is set incorrectly in the GitHub environment, deployments may target the wrong hostname (e.g., deploying sandbox changes to production apex).
323
+
324
+ ### How It Works
325
+
326
+ 1. The `setup-environment` action reads `${{ vars.PROJECT_ENV }}` from the GitHub environment
327
+ 2. This is exported as `PROJECT_ENV` to `$GITHUB_ENV`
328
+ 3. CDK constructs read `process.env.PROJECT_ENV` via `envHostname()`
329
+ 4. For production, the environment prefix is omitted (apex domain)
330
+ 5. For all other environments, the prefix is prepended
331
+
332
+ ### Troubleshooting Wrong Hostname
333
+
334
+ If deployment targets the wrong hostname:
335
+ 1. Go to GitHub Settings → Environments
336
+ 2. Select the environment (sandbox, development, production)
337
+ 3. Verify `PROJECT_ENV` variable matches the environment name exactly
338
+
212
339
  ## Integrations
213
340
 
214
341
  ### AWS
@@ -21,21 +21,21 @@ All entities share a single DynamoDB table with:
21
21
  - **Primary Key**: `model` (partition) + `id` (sort)
22
22
  - **Five GSIs**: All use `sequence` as sort key for chronological ordering
23
23
 
24
- ### Organizational Unit (OU)
24
+ ### Scope
25
25
 
26
- The `ou` field creates hierarchical relationships:
27
- - Root entities: `ou = "@"` (APEX constant)
28
- - Child entities: `ou = "{parent.model}#{parent.id}"`
26
+ The `scope` field creates hierarchical relationships:
27
+ - Root entities: `scope = "@"` (APEX constant)
28
+ - Child entities: `scope = "{parent.model}#{parent.id}"`
29
29
 
30
30
  ### GSI Pattern
31
31
 
32
32
  | GSI Name | Partition Key | Use Case |
33
33
  |----------|---------------|----------|
34
- | `indexOu` | `{ou}#{model}` | List all entities under a parent |
35
- | `indexAlias` | `{ou}#{model}#{alias}` | Human-friendly slug lookup |
36
- | `indexClass` | `{ou}#{model}#{class}` | Category filtering |
37
- | `indexType` | `{ou}#{model}#{type}` | Type filtering |
38
- | `indexXid` | `{ou}#{model}#{xid}` | External system ID lookup |
34
+ | `indexScope` | `{scope}#{model}` | List all entities under a parent |
35
+ | `indexAlias` | `{scope}#{model}#{alias}` | Human-friendly slug lookup |
36
+ | `indexClass` | `{scope}#{model}#{class}` | Category filtering |
37
+ | `indexType` | `{scope}#{model}#{type}` | Type filtering |
38
+ | `indexXid` | `{scope}#{model}#{xid}` | External system ID lookup |
39
39
 
40
40
  ## Client Initialization
41
41
 
@@ -75,7 +75,7 @@ interface MyRecord extends StorableEntity {
75
75
 
76
76
  // Required fields
77
77
  name: string;
78
- ou: string; // APEX or hierarchical
78
+ scope: string; // APEX or hierarchical
79
79
  sequence: number; // Date.now()
80
80
 
81
81
  // Timestamps (ISO 8601)
@@ -108,7 +108,7 @@ const record = await putEntity({
108
108
  model: "record",
109
109
  id: crypto.randomUUID(),
110
110
  name: "Daily Log",
111
- ou: APEX,
111
+ scope: APEX,
112
112
  sequence: Date.now(),
113
113
  alias: "2026-01-07", // Optional
114
114
  class: "memory", // Optional
@@ -118,7 +118,7 @@ const record = await putEntity({
118
118
  });
119
119
 
120
120
  // Result includes auto-populated indexes:
121
- // indexOu: "@#record"
121
+ // indexScope: "@#record"
122
122
  // indexAlias: "@#record#2026-01-07"
123
123
  // indexClass: "@#record#memory"
124
124
  ```
@@ -187,16 +187,16 @@ await destroyEntity({ id: "123", model: "record" });
187
187
 
188
188
  ### Hierarchical Entities
189
189
 
190
- Use `calculateOu` to derive OU from parent:
190
+ Use `calculateScope` to derive scope from parent:
191
191
 
192
192
  ```typescript
193
- import { calculateOu, putEntity, queryByOu } from "@jaypie/dynamodb";
193
+ import { calculateScope, putEntity, queryByScope } from "@jaypie/dynamodb";
194
194
 
195
195
  // Parent reference
196
196
  const chat = { model: "chat", id: "abc-123" };
197
197
 
198
- // Calculate child OU
199
- const messageOu = calculateOu(chat); // "chat#abc-123"
198
+ // Calculate child scope
199
+ const messageScope = calculateScope(chat); // "chat#abc-123"
200
200
 
201
201
  // Create child entity
202
202
  const message = await putEntity({
@@ -204,39 +204,39 @@ const message = await putEntity({
204
204
  model: "message",
205
205
  id: crypto.randomUUID(),
206
206
  name: "First message",
207
- ou: messageOu,
207
+ scope: messageScope,
208
208
  sequence: Date.now(),
209
209
  createdAt: now,
210
210
  updatedAt: now,
211
211
  },
212
212
  });
213
- // indexOu: "chat#abc-123#message"
213
+ // indexScope: "chat#abc-123#message"
214
214
 
215
215
  // Query all messages in chat
216
- const { items } = await queryByOu({ model: "message", ou: messageOu });
216
+ const { items } = await queryByScope({ model: "message", scope: messageScope });
217
217
  ```
218
218
 
219
219
  ## Query Functions
220
220
 
221
221
  All queries use object parameters and filter soft-deleted and archived records by default.
222
222
 
223
- ### queryByOu - List by Parent
223
+ ### queryByScope - List by Parent
224
224
 
225
225
  List all entities of a model under a parent:
226
226
 
227
227
  ```typescript
228
- import { APEX, queryByOu } from "@jaypie/dynamodb";
228
+ import { APEX, queryByScope } from "@jaypie/dynamodb";
229
229
 
230
230
  // Root-level records
231
- const { items, lastEvaluatedKey } = await queryByOu({
231
+ const { items, lastEvaluatedKey } = await queryByScope({
232
232
  model: "record",
233
- ou: APEX,
233
+ scope: APEX,
234
234
  });
235
235
 
236
236
  // Messages under a chat
237
- const { items: messages } = await queryByOu({
237
+ const { items: messages } = await queryByScope({
238
238
  model: "message",
239
- ou: "chat#abc-123",
239
+ scope: "chat#abc-123",
240
240
  });
241
241
  ```
242
242
 
@@ -250,7 +250,7 @@ import { APEX, queryByAlias } from "@jaypie/dynamodb";
250
250
  const record = await queryByAlias({
251
251
  alias: "2026-01-07",
252
252
  model: "record",
253
- ou: APEX,
253
+ scope: APEX,
254
254
  });
255
255
  // Returns entity or null
256
256
  ```
@@ -263,14 +263,14 @@ import { APEX, queryByClass, queryByType } from "@jaypie/dynamodb";
263
263
  // All memory records
264
264
  const { items } = await queryByClass({
265
265
  model: "record",
266
- ou: APEX,
266
+ scope: APEX,
267
267
  recordClass: "memory",
268
268
  });
269
269
 
270
270
  // All note-type records
271
271
  const { items: notes } = await queryByType({
272
272
  model: "record",
273
- ou: APEX,
273
+ scope: APEX,
274
274
  type: "note",
275
275
  });
276
276
  ```
@@ -284,7 +284,7 @@ import { APEX, queryByXid } from "@jaypie/dynamodb";
284
284
 
285
285
  const record = await queryByXid({
286
286
  model: "record",
287
- ou: APEX,
287
+ scope: APEX,
288
288
  xid: "ext-12345",
289
289
  });
290
290
  // Returns entity or null
@@ -295,9 +295,9 @@ const record = await queryByXid({
295
295
  ```typescript
296
296
  import type { BaseQueryOptions } from "@jaypie/dynamodb";
297
297
 
298
- const result = await queryByOu({
298
+ const result = await queryByScope({
299
299
  model: "record",
300
- ou: APEX,
300
+ scope: APEX,
301
301
  // BaseQueryOptions:
302
302
  limit: 25, // Max items to return
303
303
  ascending: true, // Oldest first (default: false = newest first)
@@ -310,15 +310,15 @@ const result = await queryByOu({
310
310
  ### Pagination
311
311
 
312
312
  ```typescript
313
- import { APEX, queryByOu } from "@jaypie/dynamodb";
313
+ import { APEX, queryByScope } from "@jaypie/dynamodb";
314
314
 
315
315
  let startKey: Record<string, unknown> | undefined;
316
316
  const allItems: StorableEntity[] = [];
317
317
 
318
318
  do {
319
- const { items, lastEvaluatedKey } = await queryByOu({
319
+ const { items, lastEvaluatedKey } = await queryByScope({
320
320
  model: "record",
321
- ou: APEX,
321
+ scope: APEX,
322
322
  limit: 100,
323
323
  startKey,
324
324
  });
@@ -337,11 +337,11 @@ import { indexEntity } from "@jaypie/dynamodb";
337
337
  const indexed = indexEntity({
338
338
  model: "record",
339
339
  id: "123",
340
- ou: "@",
340
+ scope: "@",
341
341
  alias: "my-alias",
342
342
  // ...
343
343
  });
344
- // indexOu: "@#record"
344
+ // indexScope: "@#record"
345
345
  // indexAlias: "@#record#my-alias"
346
346
  ```
347
347
 
@@ -349,14 +349,14 @@ Use individual key builders for manual key construction:
349
349
 
350
350
  ```typescript
351
351
  import {
352
- buildIndexOu,
352
+ buildIndexScope,
353
353
  buildIndexAlias,
354
354
  buildIndexClass,
355
355
  buildIndexType,
356
356
  buildIndexXid,
357
357
  } from "@jaypie/dynamodb";
358
358
 
359
- buildIndexOu("@", "record"); // "@#record"
359
+ buildIndexScope("@", "record"); // "@#record"
360
360
  buildIndexAlias("@", "record", "my-alias"); // "@#record#my-alias"
361
361
  buildIndexClass("@", "record", "memory"); // "@#record#memory"
362
362
  buildIndexType("@", "record", "note"); // "@#record#note"
@@ -369,7 +369,7 @@ buildIndexXid("@", "record", "ext-123"); // "@#record#ext-123"
369
369
  import {
370
370
  APEX, // "@" - Root-level marker
371
371
  SEPARATOR, // "#" - Composite key separator
372
- INDEX_OU, // "indexOu"
372
+ INDEX_SCOPE, // "indexScope"
373
373
  INDEX_ALIAS, // "indexAlias"
374
374
  INDEX_CLASS, // "indexClass"
375
375
  INDEX_TYPE, // "indexType"
@@ -385,7 +385,7 @@ AttributeDefinitions:
385
385
  AttributeType: S
386
386
  - AttributeName: id
387
387
  AttributeType: S
388
- - AttributeName: indexOu
388
+ - AttributeName: indexScope
389
389
  AttributeType: S
390
390
  - AttributeName: indexAlias
391
391
  AttributeType: S
@@ -405,9 +405,9 @@ KeySchema:
405
405
  KeyType: RANGE
406
406
 
407
407
  GlobalSecondaryIndexes:
408
- - IndexName: indexOu
408
+ - IndexName: indexScope
409
409
  KeySchema:
410
- - AttributeName: indexOu
410
+ - AttributeName: indexScope
411
411
  KeyType: HASH
412
412
  - AttributeName: sequence
413
413
  KeyType: RANGE
@@ -445,7 +445,7 @@ const created = await seedEntityIfNotExists({
445
445
  alias: "config-main",
446
446
  model: "config",
447
447
  name: "Main Configuration",
448
- ou: APEX,
448
+ scope: APEX,
449
449
  });
450
450
  // Returns true if created, false if already exists
451
451
  ```
@@ -458,8 +458,8 @@ Seed multiple entities with idempotency:
458
458
  import { APEX, seedEntities } from "@jaypie/dynamodb";
459
459
 
460
460
  const result = await seedEntities([
461
- { alias: "vocab-en", model: "vocabulary", name: "English", ou: APEX },
462
- { alias: "vocab-es", model: "vocabulary", name: "Spanish", ou: APEX },
461
+ { alias: "vocab-en", model: "vocabulary", name: "English", scope: APEX },
462
+ { alias: "vocab-es", model: "vocabulary", name: "Spanish", scope: APEX },
463
463
  ]);
464
464
  // result.created: aliases of created entities
465
465
  // result.skipped: aliases of entities that already existed
@@ -476,7 +476,7 @@ Auto-generates `id` (UUID), `createdAt`, `updatedAt`, and `sequence` if missing.
476
476
 
477
477
  ### exportEntities
478
478
 
479
- Export entities by model and organizational unit:
479
+ Export entities by model and scope:
480
480
 
481
481
  ```typescript
482
482
  import { APEX, exportEntities } from "@jaypie/dynamodb";
@@ -546,11 +546,11 @@ import {
546
546
  exportEntities,
547
547
  getEntity,
548
548
  putEntity,
549
- queryByOu,
549
+ queryByScope,
550
550
  seedEntities,
551
551
  } from "@jaypie/testkit/mock";
552
552
 
553
- queryByOu.mockResolvedValue({
553
+ queryByScope.mockResolvedValue({
554
554
  items: [{ id: "123", name: "Test" }],
555
555
  lastEvaluatedKey: undefined,
556
556
  });
@@ -644,12 +644,12 @@ await deleteEntity({ id: "123", model: "record" });
644
644
  await archiveEntity({ id: "123", model: "record" });
645
645
 
646
646
  // Queries exclude both by default
647
- const { items } = await queryByOu({ model: "record", ou: APEX });
647
+ const { items } = await queryByScope({ model: "record", scope: APEX });
648
648
 
649
649
  // Include if needed
650
- const { items: all } = await queryByOu({
650
+ const { items: all } = await queryByScope({
651
651
  model: "record",
652
- ou: APEX,
652
+ scope: APEX,
653
653
  includeDeleted: true,
654
654
  includeArchived: true,
655
655
  });
@@ -704,7 +704,7 @@ const { tools } = registerDynamoDbTools({ server });
704
704
  #### Query Operations
705
705
  | Tool | Description |
706
706
  |------|-------------|
707
- | `dynamodb_query_ou` | Query by organizational unit |
707
+ | `dynamodb_query_scope` | Query by scope |
708
708
  | `dynamodb_query_alias` | Query by human-friendly alias |
709
709
  | `dynamodb_query_class` | Query by category classification |
710
710
  | `dynamodb_query_type` | Query by type classification |
@@ -753,15 +753,15 @@ Generate docker-compose and create table:
753
753
  "id": "abc-123",
754
754
  "model": "record",
755
755
  "name": "My Record",
756
- "ou": "@",
756
+ "scope": "@",
757
757
  "alias": "my-record",
758
758
  "class": "memory"
759
759
  }
760
760
 
761
- // dynamodb_query_ou
761
+ // dynamodb_query_scope
762
762
  {
763
763
  "model": "record",
764
- "ou": "@",
764
+ "scope": "@",
765
765
  "limit": 10
766
766
  }
767
767