@jaypie/dynamodb 0.2.0 → 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/dist/cjs/constants.d.ts +2 -2
- package/dist/cjs/entities.d.ts +6 -6
- package/dist/cjs/index.cjs +112 -106
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.ts +3 -3
- package/dist/cjs/keyBuilders.d.ts +21 -21
- package/dist/cjs/mcp/admin/createTable.d.ts +1 -1
- package/dist/cjs/mcp/admin/dockerCompose.d.ts +1 -1
- package/dist/cjs/mcp/admin/status.d.ts +1 -1
- package/dist/cjs/mcp/index.cjs +143 -121
- package/dist/cjs/mcp/index.cjs.map +1 -1
- package/dist/cjs/queries.d.ts +15 -15
- package/dist/cjs/query.d.ts +7 -7
- package/dist/cjs/seedExport.d.ts +7 -7
- package/dist/cjs/types.d.ts +20 -20
- package/dist/esm/constants.d.ts +2 -2
- package/dist/esm/entities.d.ts +6 -6
- package/dist/esm/index.d.ts +3 -3
- package/dist/esm/index.js +91 -85
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/keyBuilders.d.ts +21 -21
- package/dist/esm/mcp/admin/createTable.d.ts +1 -1
- package/dist/esm/mcp/admin/dockerCompose.d.ts +1 -1
- package/dist/esm/mcp/admin/status.d.ts +1 -1
- package/dist/esm/mcp/index.js +133 -111
- package/dist/esm/mcp/index.js.map +1 -1
- package/dist/esm/queries.d.ts +15 -15
- package/dist/esm/query.d.ts +7 -7
- package/dist/esm/seedExport.d.ts +7 -7
- package/dist/esm/types.d.ts +20 -20
- package/package.json +2 -2
package/dist/cjs/mcp/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var mcp = require('@jaypie/
|
|
4
|
-
var
|
|
3
|
+
var mcp = require('@jaypie/fabric/mcp');
|
|
4
|
+
var fabric = require('@jaypie/fabric');
|
|
5
5
|
var clientDynamodb = require('@aws-sdk/client-dynamodb');
|
|
6
6
|
var libDynamodb = require('@aws-sdk/lib-dynamodb');
|
|
7
7
|
var errors = require('@jaypie/errors');
|
|
@@ -77,11 +77,11 @@ function isInitialized() {
|
|
|
77
77
|
return docClient !== null && tableName !== null;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
// Re-export shared constants from
|
|
80
|
+
// Re-export shared constants from fabric
|
|
81
81
|
// GSI names (derived from DEFAULT_INDEXES)
|
|
82
82
|
const INDEX_ALIAS = "indexAlias";
|
|
83
83
|
const INDEX_CLASS = "indexClass";
|
|
84
|
-
const
|
|
84
|
+
const INDEX_SCOPE = "indexScope";
|
|
85
85
|
const INDEX_TYPE = "indexType";
|
|
86
86
|
const INDEX_XID = "indexXid";
|
|
87
87
|
|
|
@@ -89,53 +89,53 @@ const INDEX_XID = "indexXid";
|
|
|
89
89
|
// Key Builders
|
|
90
90
|
// =============================================================================
|
|
91
91
|
/**
|
|
92
|
-
* Build the
|
|
93
|
-
* @param
|
|
92
|
+
* Build the indexScope key for hierarchical queries
|
|
93
|
+
* @param scope - The scope (APEX or "{parent.model}#{parent.id}")
|
|
94
94
|
* @param model - The entity model name
|
|
95
|
-
* @returns Composite key: "{
|
|
95
|
+
* @returns Composite key: "{scope}#{model}"
|
|
96
96
|
*/
|
|
97
|
-
function
|
|
98
|
-
return `${
|
|
97
|
+
function buildIndexScope(scope, model) {
|
|
98
|
+
return `${scope}${fabric.SEPARATOR}${model}`;
|
|
99
99
|
}
|
|
100
100
|
/**
|
|
101
101
|
* Build the indexAlias key for human-friendly lookups
|
|
102
|
-
* @param
|
|
102
|
+
* @param scope - The scope
|
|
103
103
|
* @param model - The entity model name
|
|
104
104
|
* @param alias - The human-friendly alias
|
|
105
|
-
* @returns Composite key: "{
|
|
105
|
+
* @returns Composite key: "{scope}#{model}#{alias}"
|
|
106
106
|
*/
|
|
107
|
-
function buildIndexAlias(
|
|
108
|
-
return `${
|
|
107
|
+
function buildIndexAlias(scope, model, alias) {
|
|
108
|
+
return `${scope}${fabric.SEPARATOR}${model}${fabric.SEPARATOR}${alias}`;
|
|
109
109
|
}
|
|
110
110
|
/**
|
|
111
111
|
* Build the indexClass key for category filtering
|
|
112
|
-
* @param
|
|
112
|
+
* @param scope - The scope
|
|
113
113
|
* @param model - The entity model name
|
|
114
114
|
* @param recordClass - The category classification
|
|
115
|
-
* @returns Composite key: "{
|
|
115
|
+
* @returns Composite key: "{scope}#{model}#{class}"
|
|
116
116
|
*/
|
|
117
|
-
function buildIndexClass(
|
|
118
|
-
return `${
|
|
117
|
+
function buildIndexClass(scope, model, recordClass) {
|
|
118
|
+
return `${scope}${fabric.SEPARATOR}${model}${fabric.SEPARATOR}${recordClass}`;
|
|
119
119
|
}
|
|
120
120
|
/**
|
|
121
121
|
* Build the indexType key for type filtering
|
|
122
|
-
* @param
|
|
122
|
+
* @param scope - The scope
|
|
123
123
|
* @param model - The entity model name
|
|
124
124
|
* @param type - The type classification
|
|
125
|
-
* @returns Composite key: "{
|
|
125
|
+
* @returns Composite key: "{scope}#{model}#{type}"
|
|
126
126
|
*/
|
|
127
|
-
function buildIndexType(
|
|
128
|
-
return `${
|
|
127
|
+
function buildIndexType(scope, model, type) {
|
|
128
|
+
return `${scope}${fabric.SEPARATOR}${model}${fabric.SEPARATOR}${type}`;
|
|
129
129
|
}
|
|
130
130
|
/**
|
|
131
131
|
* Build the indexXid key for external ID lookups
|
|
132
|
-
* @param
|
|
132
|
+
* @param scope - The scope
|
|
133
133
|
* @param model - The entity model name
|
|
134
134
|
* @param xid - The external ID
|
|
135
|
-
* @returns Composite key: "{
|
|
135
|
+
* @returns Composite key: "{scope}#{model}#{xid}"
|
|
136
136
|
*/
|
|
137
|
-
function buildIndexXid(
|
|
138
|
-
return `${
|
|
137
|
+
function buildIndexXid(scope, model, xid) {
|
|
138
|
+
return `${scope}${fabric.SEPARATOR}${model}${fabric.SEPARATOR}${xid}`;
|
|
139
139
|
}
|
|
140
140
|
/**
|
|
141
141
|
* Auto-populate GSI index keys on an entity
|
|
@@ -143,7 +143,7 @@ function buildIndexXid(ou, model, xid) {
|
|
|
143
143
|
* Uses the model's registered indexes (from vocabulary registry) or
|
|
144
144
|
* DEFAULT_INDEXES if no custom indexes are registered.
|
|
145
145
|
*
|
|
146
|
-
* -
|
|
146
|
+
* - indexScope is always populated from scope + model
|
|
147
147
|
* - indexAlias is populated only when alias is present
|
|
148
148
|
* - indexClass is populated only when class is present
|
|
149
149
|
* - indexType is populated only when type is present
|
|
@@ -154,9 +154,9 @@ function buildIndexXid(ou, model, xid) {
|
|
|
154
154
|
* @returns The entity with populated index keys
|
|
155
155
|
*/
|
|
156
156
|
function indexEntity(entity, suffix = "") {
|
|
157
|
-
const indexes =
|
|
158
|
-
// Cast through unknown to bridge the type gap between StorableEntity and
|
|
159
|
-
return
|
|
157
|
+
const indexes = fabric.getModelIndexes(entity.model);
|
|
158
|
+
// Cast through unknown to bridge the type gap between StorableEntity and IndexableModel
|
|
159
|
+
return fabric.populateIndexKeys(entity, indexes, suffix);
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
/**
|
|
@@ -166,20 +166,20 @@ function calculateEntitySuffix(entity) {
|
|
|
166
166
|
const hasArchived = Boolean(entity.archivedAt);
|
|
167
167
|
const hasDeleted = Boolean(entity.deletedAt);
|
|
168
168
|
if (hasArchived && hasDeleted) {
|
|
169
|
-
return
|
|
169
|
+
return fabric.ARCHIVED_SUFFIX + fabric.DELETED_SUFFIX;
|
|
170
170
|
}
|
|
171
171
|
if (hasArchived) {
|
|
172
|
-
return
|
|
172
|
+
return fabric.ARCHIVED_SUFFIX;
|
|
173
173
|
}
|
|
174
174
|
if (hasDeleted) {
|
|
175
|
-
return
|
|
175
|
+
return fabric.DELETED_SUFFIX;
|
|
176
176
|
}
|
|
177
177
|
return "";
|
|
178
178
|
}
|
|
179
179
|
/**
|
|
180
180
|
* Get a single entity by primary key
|
|
181
181
|
*/
|
|
182
|
-
const getEntity =
|
|
182
|
+
const getEntity = fabric.fabricService({
|
|
183
183
|
alias: "getEntity",
|
|
184
184
|
description: "Get a single entity by primary key",
|
|
185
185
|
input: {
|
|
@@ -201,7 +201,7 @@ const getEntity = vocabulary.serviceHandler({
|
|
|
201
201
|
* Put (create or replace) an entity
|
|
202
202
|
* Auto-populates GSI index keys via indexEntity
|
|
203
203
|
*
|
|
204
|
-
* Note: This is a regular async function (not
|
|
204
|
+
* Note: This is a regular async function (not fabricService) because it accepts
|
|
205
205
|
* complex StorableEntity objects that can't be coerced by vocabulary's type system.
|
|
206
206
|
*/
|
|
207
207
|
async function putEntity({ entity, }) {
|
|
@@ -220,7 +220,7 @@ async function putEntity({ entity, }) {
|
|
|
220
220
|
* Update an existing entity
|
|
221
221
|
* Auto-populates GSI index keys and sets updatedAt
|
|
222
222
|
*
|
|
223
|
-
* Note: This is a regular async function (not
|
|
223
|
+
* Note: This is a regular async function (not fabricService) because it accepts
|
|
224
224
|
* complex StorableEntity objects that can't be coerced by vocabulary's type system.
|
|
225
225
|
*/
|
|
226
226
|
async function updateEntity({ entity, }) {
|
|
@@ -242,7 +242,7 @@ async function updateEntity({ entity, }) {
|
|
|
242
242
|
* Soft delete an entity by setting deletedAt timestamp
|
|
243
243
|
* Re-indexes with appropriate suffix based on archived/deleted state
|
|
244
244
|
*/
|
|
245
|
-
const deleteEntity =
|
|
245
|
+
const deleteEntity = fabric.fabricService({
|
|
246
246
|
alias: "deleteEntity",
|
|
247
247
|
description: "Soft delete an entity (sets deletedAt timestamp)",
|
|
248
248
|
input: {
|
|
@@ -279,7 +279,7 @@ const deleteEntity = vocabulary.serviceHandler({
|
|
|
279
279
|
* Archive an entity by setting archivedAt timestamp
|
|
280
280
|
* Re-indexes with appropriate suffix based on archived/deleted state
|
|
281
281
|
*/
|
|
282
|
-
const archiveEntity =
|
|
282
|
+
const archiveEntity = fabric.fabricService({
|
|
283
283
|
alias: "archiveEntity",
|
|
284
284
|
description: "Archive an entity (sets archivedAt timestamp)",
|
|
285
285
|
input: {
|
|
@@ -316,7 +316,7 @@ const archiveEntity = vocabulary.serviceHandler({
|
|
|
316
316
|
* Hard delete an entity (permanently removes from table)
|
|
317
317
|
* Use with caution - prefer deleteEntity for soft delete
|
|
318
318
|
*/
|
|
319
|
-
const destroyEntity =
|
|
319
|
+
const destroyEntity = fabric.fabricService({
|
|
320
320
|
alias: "destroyEntity",
|
|
321
321
|
description: "Hard delete an entity (permanently removes from table)",
|
|
322
322
|
input: {
|
|
@@ -341,13 +341,13 @@ const destroyEntity = vocabulary.serviceHandler({
|
|
|
341
341
|
*/
|
|
342
342
|
function calculateSuffix({ archived, deleted, }) {
|
|
343
343
|
if (archived && deleted) {
|
|
344
|
-
return
|
|
344
|
+
return fabric.ARCHIVED_SUFFIX + fabric.DELETED_SUFFIX;
|
|
345
345
|
}
|
|
346
346
|
if (archived) {
|
|
347
|
-
return
|
|
347
|
+
return fabric.ARCHIVED_SUFFIX;
|
|
348
348
|
}
|
|
349
349
|
if (deleted) {
|
|
350
|
-
return
|
|
350
|
+
return fabric.DELETED_SUFFIX;
|
|
351
351
|
}
|
|
352
352
|
return "";
|
|
353
353
|
}
|
|
@@ -379,16 +379,16 @@ async function executeQuery(indexName, keyValue, options = {}) {
|
|
|
379
379
|
};
|
|
380
380
|
}
|
|
381
381
|
/**
|
|
382
|
-
* Query entities by
|
|
383
|
-
* Uses
|
|
382
|
+
* Query entities by scope (parent hierarchy)
|
|
383
|
+
* Uses indexScope GSI
|
|
384
384
|
*
|
|
385
|
-
* Note: This is a regular async function (not
|
|
385
|
+
* Note: This is a regular async function (not fabricService) because it accepts
|
|
386
386
|
* complex startKey objects that can't be coerced by vocabulary's type system.
|
|
387
387
|
*/
|
|
388
|
-
async function
|
|
388
|
+
async function queryByScope({ archived = false, ascending = false, deleted = false, limit, model, scope, startKey, }) {
|
|
389
389
|
const suffix = calculateSuffix({ archived, deleted });
|
|
390
|
-
const keyValue =
|
|
391
|
-
return executeQuery(
|
|
390
|
+
const keyValue = buildIndexScope(scope, model) + suffix;
|
|
391
|
+
return executeQuery(INDEX_SCOPE, keyValue, {
|
|
392
392
|
ascending,
|
|
393
393
|
limit,
|
|
394
394
|
startKey,
|
|
@@ -398,7 +398,7 @@ async function queryByOu({ archived = false, ascending = false, deleted = false,
|
|
|
398
398
|
* Query a single entity by human-friendly alias
|
|
399
399
|
* Uses indexAlias GSI
|
|
400
400
|
*/
|
|
401
|
-
const queryByAlias =
|
|
401
|
+
const queryByAlias = fabric.fabricService({
|
|
402
402
|
alias: "queryByAlias",
|
|
403
403
|
description: "Query a single entity by human-friendly alias",
|
|
404
404
|
input: {
|
|
@@ -416,16 +416,19 @@ const queryByAlias = vocabulary.serviceHandler({
|
|
|
416
416
|
description: "Query deleted entities instead of active ones",
|
|
417
417
|
},
|
|
418
418
|
model: { type: String, description: "Entity model name" },
|
|
419
|
-
|
|
419
|
+
scope: { type: String, description: "Scope (@ for root)" },
|
|
420
420
|
},
|
|
421
|
-
service: async ({ alias, archived, deleted, model,
|
|
421
|
+
service: async ({ alias, archived, deleted, model, scope, }) => {
|
|
422
422
|
const aliasStr = alias;
|
|
423
423
|
const archivedBool = archived;
|
|
424
424
|
const deletedBool = deleted;
|
|
425
425
|
const modelStr = model;
|
|
426
|
-
const
|
|
427
|
-
const suffix = calculateSuffix({
|
|
428
|
-
|
|
426
|
+
const scopeStr = scope;
|
|
427
|
+
const suffix = calculateSuffix({
|
|
428
|
+
archived: archivedBool,
|
|
429
|
+
deleted: deletedBool,
|
|
430
|
+
});
|
|
431
|
+
const keyValue = buildIndexAlias(scopeStr, modelStr, aliasStr) + suffix;
|
|
429
432
|
const result = await executeQuery(INDEX_ALIAS, keyValue, {
|
|
430
433
|
limit: 1,
|
|
431
434
|
});
|
|
@@ -436,12 +439,12 @@ const queryByAlias = vocabulary.serviceHandler({
|
|
|
436
439
|
* Query entities by category classification
|
|
437
440
|
* Uses indexClass GSI
|
|
438
441
|
*
|
|
439
|
-
* Note: This is a regular async function (not
|
|
442
|
+
* Note: This is a regular async function (not fabricService) because it accepts
|
|
440
443
|
* complex startKey objects that can't be coerced by vocabulary's type system.
|
|
441
444
|
*/
|
|
442
|
-
async function queryByClass({ archived = false, ascending = false, deleted = false, limit, model,
|
|
445
|
+
async function queryByClass({ archived = false, ascending = false, deleted = false, limit, model, scope, recordClass, startKey, }) {
|
|
443
446
|
const suffix = calculateSuffix({ archived, deleted });
|
|
444
|
-
const keyValue = buildIndexClass(
|
|
447
|
+
const keyValue = buildIndexClass(scope, model, recordClass) + suffix;
|
|
445
448
|
return executeQuery(INDEX_CLASS, keyValue, {
|
|
446
449
|
ascending,
|
|
447
450
|
limit,
|
|
@@ -452,12 +455,12 @@ async function queryByClass({ archived = false, ascending = false, deleted = fal
|
|
|
452
455
|
* Query entities by type classification
|
|
453
456
|
* Uses indexType GSI
|
|
454
457
|
*
|
|
455
|
-
* Note: This is a regular async function (not
|
|
458
|
+
* Note: This is a regular async function (not fabricService) because it accepts
|
|
456
459
|
* complex startKey objects that can't be coerced by vocabulary's type system.
|
|
457
460
|
*/
|
|
458
|
-
async function queryByType({ archived = false, ascending = false, deleted = false, limit, model,
|
|
461
|
+
async function queryByType({ archived = false, ascending = false, deleted = false, limit, model, scope, startKey, type, }) {
|
|
459
462
|
const suffix = calculateSuffix({ archived, deleted });
|
|
460
|
-
const keyValue = buildIndexType(
|
|
463
|
+
const keyValue = buildIndexType(scope, model, type) + suffix;
|
|
461
464
|
return executeQuery(INDEX_TYPE, keyValue, {
|
|
462
465
|
ascending,
|
|
463
466
|
limit,
|
|
@@ -468,7 +471,7 @@ async function queryByType({ archived = false, ascending = false, deleted = fals
|
|
|
468
471
|
* Query a single entity by external ID
|
|
469
472
|
* Uses indexXid GSI
|
|
470
473
|
*/
|
|
471
|
-
const queryByXid =
|
|
474
|
+
const queryByXid = fabric.fabricService({
|
|
472
475
|
alias: "queryByXid",
|
|
473
476
|
description: "Query a single entity by external ID",
|
|
474
477
|
input: {
|
|
@@ -485,17 +488,20 @@ const queryByXid = vocabulary.serviceHandler({
|
|
|
485
488
|
description: "Query deleted entities instead of active ones",
|
|
486
489
|
},
|
|
487
490
|
model: { type: String, description: "Entity model name" },
|
|
488
|
-
|
|
491
|
+
scope: { type: String, description: "Scope (@ for root)" },
|
|
489
492
|
xid: { type: String, description: "External ID" },
|
|
490
493
|
},
|
|
491
|
-
service: async ({ archived, deleted, model,
|
|
494
|
+
service: async ({ archived, deleted, model, scope, xid, }) => {
|
|
492
495
|
const archivedBool = archived;
|
|
493
496
|
const deletedBool = deleted;
|
|
494
497
|
const modelStr = model;
|
|
495
|
-
const
|
|
498
|
+
const scopeStr = scope;
|
|
496
499
|
const xidStr = xid;
|
|
497
|
-
const suffix = calculateSuffix({
|
|
498
|
-
|
|
500
|
+
const suffix = calculateSuffix({
|
|
501
|
+
archived: archivedBool,
|
|
502
|
+
deleted: deletedBool,
|
|
503
|
+
});
|
|
504
|
+
const keyValue = buildIndexXid(scopeStr, modelStr, xidStr) + suffix;
|
|
499
505
|
const result = await executeQuery(INDEX_XID, keyValue, {
|
|
500
506
|
limit: 1,
|
|
501
507
|
});
|
|
@@ -524,12 +530,12 @@ function generateIndexName(pk) {
|
|
|
524
530
|
function collectAllIndexes() {
|
|
525
531
|
const indexMap = new Map();
|
|
526
532
|
// Add DEFAULT_INDEXES first
|
|
527
|
-
for (const index of
|
|
533
|
+
for (const index of fabric.DEFAULT_INDEXES) {
|
|
528
534
|
const name = index.name ?? generateIndexName(index.pk);
|
|
529
535
|
indexMap.set(name, { ...index, name });
|
|
530
536
|
}
|
|
531
537
|
// Add registered model indexes (will not overwrite if name already exists)
|
|
532
|
-
for (const index of
|
|
538
|
+
for (const index of fabric.getAllRegisteredIndexes()) {
|
|
533
539
|
const name = index.name ?? generateIndexName(index.pk);
|
|
534
540
|
if (!indexMap.has(name)) {
|
|
535
541
|
indexMap.set(name, { ...index, name });
|
|
@@ -616,7 +622,7 @@ function createTableParams(tableName, billingMode) {
|
|
|
616
622
|
/**
|
|
617
623
|
* Create DynamoDB table with Jaypie GSI schema
|
|
618
624
|
*/
|
|
619
|
-
const createTableHandler =
|
|
625
|
+
const createTableHandler = fabric.fabricService({
|
|
620
626
|
alias: "dynamodb_create_table",
|
|
621
627
|
description: "Create DynamoDB table with Jaypie GSI schema",
|
|
622
628
|
input: {
|
|
@@ -680,7 +686,7 @@ const DEFAULT_TABLE_NAME = "jaypie-local";
|
|
|
680
686
|
/**
|
|
681
687
|
* Generate docker-compose.yml for local DynamoDB development
|
|
682
688
|
*/
|
|
683
|
-
const dockerComposeHandler =
|
|
689
|
+
const dockerComposeHandler = fabric.fabricService({
|
|
684
690
|
alias: "dynamodb_generate_docker_compose",
|
|
685
691
|
description: "Generate docker-compose.yml for local DynamoDB development",
|
|
686
692
|
input: {
|
|
@@ -778,7 +784,7 @@ function ensureInitialized() {
|
|
|
778
784
|
/**
|
|
779
785
|
* Check DynamoDB connection status and configuration
|
|
780
786
|
*/
|
|
781
|
-
const statusHandler =
|
|
787
|
+
const statusHandler = fabric.fabricService({
|
|
782
788
|
alias: "dynamodb_status",
|
|
783
789
|
description: "Check DynamoDB connection status and configuration",
|
|
784
790
|
service: async () => {
|
|
@@ -809,12 +815,12 @@ function wrapWithInit(handler) {
|
|
|
809
815
|
return wrapped;
|
|
810
816
|
}
|
|
811
817
|
// MCP-specific serviceHandler wrappers for functions with complex inputs
|
|
812
|
-
// Note: These wrap the regular async functions to make them work with
|
|
818
|
+
// Note: These wrap the regular async functions to make them work with fabricMcp
|
|
813
819
|
/**
|
|
814
820
|
* MCP wrapper for putEntity
|
|
815
821
|
* Accepts entity JSON directly from LLM
|
|
816
822
|
*/
|
|
817
|
-
const mcpPutEntity =
|
|
823
|
+
const mcpPutEntity = fabric.fabricService({
|
|
818
824
|
alias: "dynamodb_put",
|
|
819
825
|
description: "Create or replace an entity in DynamoDB (auto-indexes GSI keys)",
|
|
820
826
|
input: {
|
|
@@ -822,10 +828,18 @@ const mcpPutEntity = vocabulary.serviceHandler({
|
|
|
822
828
|
id: { type: String, description: "Entity ID (sort key)" },
|
|
823
829
|
model: { type: String, description: "Entity model name (partition key)" },
|
|
824
830
|
name: { type: String, description: "Entity name" },
|
|
825
|
-
|
|
831
|
+
scope: { type: String, description: "Scope (@ for root)" },
|
|
826
832
|
// Optional fields
|
|
827
|
-
alias: {
|
|
828
|
-
|
|
833
|
+
alias: {
|
|
834
|
+
type: String,
|
|
835
|
+
required: false,
|
|
836
|
+
description: "Human-friendly alias",
|
|
837
|
+
},
|
|
838
|
+
class: {
|
|
839
|
+
type: String,
|
|
840
|
+
required: false,
|
|
841
|
+
description: "Category classification",
|
|
842
|
+
},
|
|
829
843
|
type: { type: String, required: false, description: "Type classification" },
|
|
830
844
|
xid: { type: String, required: false, description: "External ID" },
|
|
831
845
|
},
|
|
@@ -838,7 +852,7 @@ const mcpPutEntity = vocabulary.serviceHandler({
|
|
|
838
852
|
id: input.id,
|
|
839
853
|
model: input.model,
|
|
840
854
|
name: input.name,
|
|
841
|
-
|
|
855
|
+
scope: input.scope,
|
|
842
856
|
sequence: Date.now(),
|
|
843
857
|
type: input.type,
|
|
844
858
|
updatedAt: now,
|
|
@@ -851,7 +865,7 @@ const mcpPutEntity = vocabulary.serviceHandler({
|
|
|
851
865
|
* MCP wrapper for updateEntity
|
|
852
866
|
* Accepts entity JSON directly from LLM
|
|
853
867
|
*/
|
|
854
|
-
const mcpUpdateEntity =
|
|
868
|
+
const mcpUpdateEntity = fabric.fabricService({
|
|
855
869
|
alias: "dynamodb_update",
|
|
856
870
|
description: "Update an entity in DynamoDB (sets updatedAt, re-indexes GSI keys)",
|
|
857
871
|
input: {
|
|
@@ -860,9 +874,17 @@ const mcpUpdateEntity = vocabulary.serviceHandler({
|
|
|
860
874
|
model: { type: String, description: "Entity model name (partition key)" },
|
|
861
875
|
// Fields that can be updated
|
|
862
876
|
name: { type: String, required: false, description: "Entity name" },
|
|
863
|
-
|
|
864
|
-
alias: {
|
|
865
|
-
|
|
877
|
+
scope: { type: String, required: false, description: "Scope" },
|
|
878
|
+
alias: {
|
|
879
|
+
type: String,
|
|
880
|
+
required: false,
|
|
881
|
+
description: "Human-friendly alias",
|
|
882
|
+
},
|
|
883
|
+
class: {
|
|
884
|
+
type: String,
|
|
885
|
+
required: false,
|
|
886
|
+
description: "Category classification",
|
|
887
|
+
},
|
|
866
888
|
type: { type: String, required: false, description: "Type classification" },
|
|
867
889
|
xid: { type: String, required: false, description: "External ID" },
|
|
868
890
|
},
|
|
@@ -881,7 +903,7 @@ const mcpUpdateEntity = vocabulary.serviceHandler({
|
|
|
881
903
|
...(input.alias !== undefined && { alias: input.alias }),
|
|
882
904
|
...(input.class !== undefined && { class: input.class }),
|
|
883
905
|
...(input.name !== undefined && { name: input.name }),
|
|
884
|
-
...(input.
|
|
906
|
+
...(input.scope !== undefined && { scope: input.scope }),
|
|
885
907
|
...(input.type !== undefined && { type: input.type }),
|
|
886
908
|
...(input.xid !== undefined && { xid: input.xid }),
|
|
887
909
|
};
|
|
@@ -889,15 +911,15 @@ const mcpUpdateEntity = vocabulary.serviceHandler({
|
|
|
889
911
|
},
|
|
890
912
|
});
|
|
891
913
|
/**
|
|
892
|
-
* MCP wrapper for
|
|
914
|
+
* MCP wrapper for queryByScope
|
|
893
915
|
* Note: Pagination via startKey is not exposed to MCP; use limit instead
|
|
894
916
|
*/
|
|
895
|
-
const
|
|
896
|
-
alias: "
|
|
897
|
-
description: "Query entities by
|
|
917
|
+
const mcpQueryByScope = fabric.fabricService({
|
|
918
|
+
alias: "dynamodb_query_scope",
|
|
919
|
+
description: "Query entities by scope (parent hierarchy)",
|
|
898
920
|
input: {
|
|
899
921
|
model: { type: String, description: "Entity model name" },
|
|
900
|
-
|
|
922
|
+
scope: { type: String, description: "Scope (@ for root)" },
|
|
901
923
|
archived: {
|
|
902
924
|
type: Boolean,
|
|
903
925
|
default: false,
|
|
@@ -923,13 +945,13 @@ const mcpQueryByOu = vocabulary.serviceHandler({
|
|
|
923
945
|
},
|
|
924
946
|
},
|
|
925
947
|
service: async (input) => {
|
|
926
|
-
return
|
|
948
|
+
return queryByScope({
|
|
927
949
|
archived: input.archived,
|
|
928
950
|
ascending: input.ascending,
|
|
929
951
|
deleted: input.deleted,
|
|
930
952
|
limit: input.limit,
|
|
931
953
|
model: input.model,
|
|
932
|
-
|
|
954
|
+
scope: input.scope,
|
|
933
955
|
});
|
|
934
956
|
},
|
|
935
957
|
});
|
|
@@ -937,12 +959,12 @@ const mcpQueryByOu = vocabulary.serviceHandler({
|
|
|
937
959
|
* MCP wrapper for queryByClass
|
|
938
960
|
* Note: Pagination via startKey is not exposed to MCP; use limit instead
|
|
939
961
|
*/
|
|
940
|
-
const mcpQueryByClass =
|
|
962
|
+
const mcpQueryByClass = fabric.fabricService({
|
|
941
963
|
alias: "dynamodb_query_class",
|
|
942
964
|
description: "Query entities by category classification",
|
|
943
965
|
input: {
|
|
944
966
|
model: { type: String, description: "Entity model name" },
|
|
945
|
-
|
|
967
|
+
scope: { type: String, description: "Scope (@ for root)" },
|
|
946
968
|
recordClass: { type: String, description: "Category classification" },
|
|
947
969
|
archived: {
|
|
948
970
|
type: Boolean,
|
|
@@ -975,7 +997,7 @@ const mcpQueryByClass = vocabulary.serviceHandler({
|
|
|
975
997
|
deleted: input.deleted,
|
|
976
998
|
limit: input.limit,
|
|
977
999
|
model: input.model,
|
|
978
|
-
|
|
1000
|
+
scope: input.scope,
|
|
979
1001
|
recordClass: input.recordClass,
|
|
980
1002
|
});
|
|
981
1003
|
},
|
|
@@ -984,12 +1006,12 @@ const mcpQueryByClass = vocabulary.serviceHandler({
|
|
|
984
1006
|
* MCP wrapper for queryByType
|
|
985
1007
|
* Note: Pagination via startKey is not exposed to MCP; use limit instead
|
|
986
1008
|
*/
|
|
987
|
-
const mcpQueryByType =
|
|
1009
|
+
const mcpQueryByType = fabric.fabricService({
|
|
988
1010
|
alias: "dynamodb_query_type",
|
|
989
1011
|
description: "Query entities by type classification",
|
|
990
1012
|
input: {
|
|
991
1013
|
model: { type: String, description: "Entity model name" },
|
|
992
|
-
|
|
1014
|
+
scope: { type: String, description: "Scope (@ for root)" },
|
|
993
1015
|
type: { type: String, description: "Type classification" },
|
|
994
1016
|
archived: {
|
|
995
1017
|
type: Boolean,
|
|
@@ -1022,7 +1044,7 @@ const mcpQueryByType = vocabulary.serviceHandler({
|
|
|
1022
1044
|
deleted: input.deleted,
|
|
1023
1045
|
limit: input.limit,
|
|
1024
1046
|
model: input.model,
|
|
1025
|
-
|
|
1047
|
+
scope: input.scope,
|
|
1026
1048
|
type: input.type,
|
|
1027
1049
|
});
|
|
1028
1050
|
},
|
|
@@ -1034,80 +1056,80 @@ function registerDynamoDbTools(config) {
|
|
|
1034
1056
|
const { includeAdmin = true, server } = config;
|
|
1035
1057
|
const tools = [];
|
|
1036
1058
|
// Entity operations
|
|
1037
|
-
mcp.
|
|
1038
|
-
|
|
1059
|
+
mcp.fabricMcp({
|
|
1060
|
+
service: wrapWithInit(getEntity),
|
|
1039
1061
|
name: "dynamodb_get",
|
|
1040
1062
|
server,
|
|
1041
1063
|
});
|
|
1042
1064
|
tools.push("dynamodb_get");
|
|
1043
|
-
mcp.
|
|
1044
|
-
|
|
1065
|
+
mcp.fabricMcp({
|
|
1066
|
+
service: wrapWithInit(mcpPutEntity),
|
|
1045
1067
|
name: "dynamodb_put",
|
|
1046
1068
|
server,
|
|
1047
1069
|
});
|
|
1048
1070
|
tools.push("dynamodb_put");
|
|
1049
|
-
mcp.
|
|
1050
|
-
|
|
1071
|
+
mcp.fabricMcp({
|
|
1072
|
+
service: wrapWithInit(mcpUpdateEntity),
|
|
1051
1073
|
name: "dynamodb_update",
|
|
1052
1074
|
server,
|
|
1053
1075
|
});
|
|
1054
1076
|
tools.push("dynamodb_update");
|
|
1055
|
-
mcp.
|
|
1056
|
-
|
|
1077
|
+
mcp.fabricMcp({
|
|
1078
|
+
service: wrapWithInit(deleteEntity),
|
|
1057
1079
|
name: "dynamodb_delete",
|
|
1058
1080
|
server,
|
|
1059
1081
|
});
|
|
1060
1082
|
tools.push("dynamodb_delete");
|
|
1061
|
-
mcp.
|
|
1062
|
-
|
|
1083
|
+
mcp.fabricMcp({
|
|
1084
|
+
service: wrapWithInit(archiveEntity),
|
|
1063
1085
|
name: "dynamodb_archive",
|
|
1064
1086
|
server,
|
|
1065
1087
|
});
|
|
1066
1088
|
tools.push("dynamodb_archive");
|
|
1067
|
-
mcp.
|
|
1068
|
-
|
|
1089
|
+
mcp.fabricMcp({
|
|
1090
|
+
service: wrapWithInit(destroyEntity),
|
|
1069
1091
|
name: "dynamodb_destroy",
|
|
1070
1092
|
server,
|
|
1071
1093
|
});
|
|
1072
1094
|
tools.push("dynamodb_destroy");
|
|
1073
1095
|
// Query operations
|
|
1074
|
-
mcp.
|
|
1075
|
-
|
|
1076
|
-
name: "
|
|
1096
|
+
mcp.fabricMcp({
|
|
1097
|
+
service: wrapWithInit(mcpQueryByScope),
|
|
1098
|
+
name: "dynamodb_query_scope",
|
|
1077
1099
|
server,
|
|
1078
1100
|
});
|
|
1079
|
-
tools.push("
|
|
1080
|
-
mcp.
|
|
1081
|
-
|
|
1101
|
+
tools.push("dynamodb_query_scope");
|
|
1102
|
+
mcp.fabricMcp({
|
|
1103
|
+
service: wrapWithInit(queryByAlias),
|
|
1082
1104
|
name: "dynamodb_query_alias",
|
|
1083
1105
|
server,
|
|
1084
1106
|
});
|
|
1085
1107
|
tools.push("dynamodb_query_alias");
|
|
1086
|
-
mcp.
|
|
1087
|
-
|
|
1108
|
+
mcp.fabricMcp({
|
|
1109
|
+
service: wrapWithInit(mcpQueryByClass),
|
|
1088
1110
|
name: "dynamodb_query_class",
|
|
1089
1111
|
server,
|
|
1090
1112
|
});
|
|
1091
1113
|
tools.push("dynamodb_query_class");
|
|
1092
|
-
mcp.
|
|
1093
|
-
|
|
1114
|
+
mcp.fabricMcp({
|
|
1115
|
+
service: wrapWithInit(mcpQueryByType),
|
|
1094
1116
|
name: "dynamodb_query_type",
|
|
1095
1117
|
server,
|
|
1096
1118
|
});
|
|
1097
1119
|
tools.push("dynamodb_query_type");
|
|
1098
|
-
mcp.
|
|
1099
|
-
|
|
1120
|
+
mcp.fabricMcp({
|
|
1121
|
+
service: wrapWithInit(queryByXid),
|
|
1100
1122
|
name: "dynamodb_query_xid",
|
|
1101
1123
|
server,
|
|
1102
1124
|
});
|
|
1103
1125
|
tools.push("dynamodb_query_xid");
|
|
1104
1126
|
// Admin tools (MCP-only)
|
|
1105
1127
|
if (includeAdmin) {
|
|
1106
|
-
mcp.
|
|
1128
|
+
mcp.fabricMcp({ service: statusHandler, server });
|
|
1107
1129
|
tools.push("dynamodb_status");
|
|
1108
|
-
mcp.
|
|
1130
|
+
mcp.fabricMcp({ service: createTableHandler, server });
|
|
1109
1131
|
tools.push("dynamodb_create_table");
|
|
1110
|
-
mcp.
|
|
1132
|
+
mcp.fabricMcp({ service: dockerComposeHandler, server });
|
|
1111
1133
|
tools.push("dynamodb_generate_docker_compose");
|
|
1112
1134
|
}
|
|
1113
1135
|
return { tools };
|