@jaypie/dynamodb 0.1.0 → 0.1.2
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/client.d.ts +1 -1
- package/dist/cjs/entities.d.ts +16 -47
- package/dist/cjs/index.cjs +228 -140
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.ts +1 -2
- package/dist/cjs/mcp/admin/createTable.d.ts +8 -0
- package/dist/cjs/mcp/admin/dockerCompose.d.ts +12 -0
- package/dist/cjs/mcp/admin/index.d.ts +3 -0
- package/dist/cjs/mcp/admin/status.d.ts +9 -0
- package/dist/cjs/mcp/autoInit.d.ts +5 -0
- package/dist/cjs/mcp/index.cjs +1095 -0
- package/dist/cjs/mcp/index.cjs.map +1 -0
- package/dist/cjs/mcp/index.d.ts +17 -0
- package/dist/cjs/queries.d.ts +36 -25
- package/dist/cjs/types.d.ts +6 -6
- package/dist/esm/client.d.ts +1 -1
- package/dist/esm/entities.d.ts +16 -47
- package/dist/esm/index.d.ts +1 -2
- package/dist/esm/index.js +229 -141
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/mcp/admin/createTable.d.ts +8 -0
- package/dist/esm/mcp/admin/dockerCompose.d.ts +12 -0
- package/dist/esm/mcp/admin/index.d.ts +3 -0
- package/dist/esm/mcp/admin/status.d.ts +9 -0
- package/dist/esm/mcp/autoInit.d.ts +5 -0
- package/dist/esm/mcp/index.d.ts +17 -0
- package/dist/esm/mcp/index.js +1089 -0
- package/dist/esm/mcp/index.js.map +1 -0
- package/dist/esm/queries.d.ts +36 -25
- package/dist/esm/types.d.ts +6 -6
- package/package.json +16 -3
package/dist/esm/index.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
|
|
2
|
-
import { DynamoDBDocumentClient, PutCommand, DeleteCommand,
|
|
2
|
+
import { DynamoDBDocumentClient, GetCommand, PutCommand, DeleteCommand, QueryCommand } from '@aws-sdk/lib-dynamodb';
|
|
3
3
|
import { ConfigurationError } from '@jaypie/errors';
|
|
4
|
+
import { serviceHandler } from '@jaypie/vocabulary';
|
|
4
5
|
|
|
6
|
+
// Environment variable names
|
|
7
|
+
const ENV_AWS_REGION = "AWS_REGION";
|
|
8
|
+
const ENV_DYNAMODB_TABLE_NAME = "DYNAMODB_TABLE_NAME";
|
|
9
|
+
// Defaults
|
|
5
10
|
const DEFAULT_REGION = "us-east-1";
|
|
6
11
|
const LOCAL_CREDENTIALS = {
|
|
7
12
|
accessKeyId: "local",
|
|
@@ -24,8 +29,9 @@ function isLocalEndpoint(endpoint) {
|
|
|
24
29
|
*
|
|
25
30
|
* @param config - Client configuration
|
|
26
31
|
*/
|
|
27
|
-
function initClient(config) {
|
|
28
|
-
const { endpoint
|
|
32
|
+
function initClient(config = {}) {
|
|
33
|
+
const { endpoint } = config;
|
|
34
|
+
const region = config.region ?? process.env[ENV_AWS_REGION] ?? DEFAULT_REGION;
|
|
29
35
|
// Auto-detect local mode and use dummy credentials
|
|
30
36
|
const credentials = config.credentials ??
|
|
31
37
|
(isLocalEndpoint(endpoint) ? LOCAL_CREDENTIALS : undefined);
|
|
@@ -39,7 +45,7 @@ function initClient(config) {
|
|
|
39
45
|
removeUndefinedValues: true,
|
|
40
46
|
},
|
|
41
47
|
});
|
|
42
|
-
tableName = config.tableName;
|
|
48
|
+
tableName = config.tableName ?? process.env[ENV_DYNAMODB_TABLE_NAME] ?? null;
|
|
43
49
|
}
|
|
44
50
|
/**
|
|
45
51
|
* Get the initialized DynamoDB Document Client
|
|
@@ -185,25 +191,51 @@ function indexEntity(entity, suffix = "") {
|
|
|
185
191
|
}
|
|
186
192
|
|
|
187
193
|
/**
|
|
188
|
-
*
|
|
194
|
+
* Calculate suffix based on entity's archived/deleted state
|
|
189
195
|
*/
|
|
190
|
-
|
|
191
|
-
const
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
196
|
+
function calculateEntitySuffix(entity) {
|
|
197
|
+
const hasArchived = Boolean(entity.archivedAt);
|
|
198
|
+
const hasDeleted = Boolean(entity.deletedAt);
|
|
199
|
+
if (hasArchived && hasDeleted) {
|
|
200
|
+
return ARCHIVED_SUFFIX + DELETED_SUFFIX;
|
|
201
|
+
}
|
|
202
|
+
if (hasArchived) {
|
|
203
|
+
return ARCHIVED_SUFFIX;
|
|
204
|
+
}
|
|
205
|
+
if (hasDeleted) {
|
|
206
|
+
return DELETED_SUFFIX;
|
|
207
|
+
}
|
|
208
|
+
return "";
|
|
200
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* Get a single entity by primary key
|
|
212
|
+
*/
|
|
213
|
+
const getEntity = serviceHandler({
|
|
214
|
+
alias: "getEntity",
|
|
215
|
+
description: "Get a single entity by primary key",
|
|
216
|
+
input: {
|
|
217
|
+
id: { type: String, description: "Entity ID (sort key)" },
|
|
218
|
+
model: { type: String, description: "Entity model (partition key)" },
|
|
219
|
+
},
|
|
220
|
+
service: async ({ id, model }) => {
|
|
221
|
+
const docClient = getDocClient();
|
|
222
|
+
const tableName = getTableName();
|
|
223
|
+
const command = new GetCommand({
|
|
224
|
+
Key: { id, model },
|
|
225
|
+
TableName: tableName,
|
|
226
|
+
});
|
|
227
|
+
const response = await docClient.send(command);
|
|
228
|
+
return response.Item ?? null;
|
|
229
|
+
},
|
|
230
|
+
});
|
|
201
231
|
/**
|
|
202
232
|
* Put (create or replace) an entity
|
|
203
233
|
* Auto-populates GSI index keys via indexEntity
|
|
234
|
+
*
|
|
235
|
+
* Note: This is a regular async function (not serviceHandler) because it accepts
|
|
236
|
+
* complex FabricEntity objects that can't be coerced by vocabulary's type system.
|
|
204
237
|
*/
|
|
205
|
-
async function putEntity(
|
|
206
|
-
const { entity } = params;
|
|
238
|
+
async function putEntity({ entity, }) {
|
|
207
239
|
const docClient = getDocClient();
|
|
208
240
|
const tableName = getTableName();
|
|
209
241
|
// Auto-populate index keys
|
|
@@ -218,9 +250,11 @@ async function putEntity(params) {
|
|
|
218
250
|
/**
|
|
219
251
|
* Update an existing entity
|
|
220
252
|
* Auto-populates GSI index keys and sets updatedAt
|
|
253
|
+
*
|
|
254
|
+
* Note: This is a regular async function (not serviceHandler) because it accepts
|
|
255
|
+
* complex FabricEntity objects that can't be coerced by vocabulary's type system.
|
|
221
256
|
*/
|
|
222
|
-
async function updateEntity(
|
|
223
|
-
const { entity } = params;
|
|
257
|
+
async function updateEntity({ entity, }) {
|
|
224
258
|
const docClient = getDocClient();
|
|
225
259
|
const tableName = getTableName();
|
|
226
260
|
// Update timestamp and re-index
|
|
@@ -235,98 +269,102 @@ async function updateEntity(params) {
|
|
|
235
269
|
await docClient.send(command);
|
|
236
270
|
return updatedEntity;
|
|
237
271
|
}
|
|
238
|
-
/**
|
|
239
|
-
* Calculate suffix based on entity's archived/deleted state
|
|
240
|
-
*/
|
|
241
|
-
function calculateEntitySuffix(entity) {
|
|
242
|
-
const hasArchived = Boolean(entity.archivedAt);
|
|
243
|
-
const hasDeleted = Boolean(entity.deletedAt);
|
|
244
|
-
if (hasArchived && hasDeleted) {
|
|
245
|
-
return ARCHIVED_SUFFIX + DELETED_SUFFIX;
|
|
246
|
-
}
|
|
247
|
-
if (hasArchived) {
|
|
248
|
-
return ARCHIVED_SUFFIX;
|
|
249
|
-
}
|
|
250
|
-
if (hasDeleted) {
|
|
251
|
-
return DELETED_SUFFIX;
|
|
252
|
-
}
|
|
253
|
-
return "";
|
|
254
|
-
}
|
|
255
272
|
/**
|
|
256
273
|
* Soft delete an entity by setting deletedAt timestamp
|
|
257
274
|
* Re-indexes with appropriate suffix based on archived/deleted state
|
|
258
275
|
*/
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
276
|
+
const deleteEntity = serviceHandler({
|
|
277
|
+
alias: "deleteEntity",
|
|
278
|
+
description: "Soft delete an entity (sets deletedAt timestamp)",
|
|
279
|
+
input: {
|
|
280
|
+
id: { type: String, description: "Entity ID (sort key)" },
|
|
281
|
+
model: { type: String, description: "Entity model (partition key)" },
|
|
282
|
+
},
|
|
283
|
+
service: async ({ id, model }) => {
|
|
284
|
+
const docClient = getDocClient();
|
|
285
|
+
const tableName = getTableName();
|
|
286
|
+
// Fetch the current entity
|
|
287
|
+
const existing = await getEntity({ id, model });
|
|
288
|
+
if (!existing) {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
const now = new Date().toISOString();
|
|
292
|
+
// Build updated entity with deletedAt
|
|
293
|
+
const updatedEntity = {
|
|
294
|
+
...existing,
|
|
295
|
+
deletedAt: now,
|
|
296
|
+
updatedAt: now,
|
|
297
|
+
};
|
|
298
|
+
// Calculate suffix based on combined state (may already be archived)
|
|
299
|
+
const suffix = calculateEntitySuffix(updatedEntity);
|
|
300
|
+
const deletedEntity = indexEntity(updatedEntity, suffix);
|
|
301
|
+
const command = new PutCommand({
|
|
302
|
+
Item: deletedEntity,
|
|
303
|
+
TableName: tableName,
|
|
304
|
+
});
|
|
305
|
+
await docClient.send(command);
|
|
306
|
+
return true;
|
|
307
|
+
},
|
|
308
|
+
});
|
|
285
309
|
/**
|
|
286
310
|
* Archive an entity by setting archivedAt timestamp
|
|
287
311
|
* Re-indexes with appropriate suffix based on archived/deleted state
|
|
288
312
|
*/
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
313
|
+
const archiveEntity = serviceHandler({
|
|
314
|
+
alias: "archiveEntity",
|
|
315
|
+
description: "Archive an entity (sets archivedAt timestamp)",
|
|
316
|
+
input: {
|
|
317
|
+
id: { type: String, description: "Entity ID (sort key)" },
|
|
318
|
+
model: { type: String, description: "Entity model (partition key)" },
|
|
319
|
+
},
|
|
320
|
+
service: async ({ id, model }) => {
|
|
321
|
+
const docClient = getDocClient();
|
|
322
|
+
const tableName = getTableName();
|
|
323
|
+
// Fetch the current entity
|
|
324
|
+
const existing = await getEntity({ id, model });
|
|
325
|
+
if (!existing) {
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
const now = new Date().toISOString();
|
|
329
|
+
// Build updated entity with archivedAt
|
|
330
|
+
const updatedEntity = {
|
|
331
|
+
...existing,
|
|
332
|
+
archivedAt: now,
|
|
333
|
+
updatedAt: now,
|
|
334
|
+
};
|
|
335
|
+
// Calculate suffix based on combined state (may already be deleted)
|
|
336
|
+
const suffix = calculateEntitySuffix(updatedEntity);
|
|
337
|
+
const archivedEntity = indexEntity(updatedEntity, suffix);
|
|
338
|
+
const command = new PutCommand({
|
|
339
|
+
Item: archivedEntity,
|
|
340
|
+
TableName: tableName,
|
|
341
|
+
});
|
|
342
|
+
await docClient.send(command);
|
|
343
|
+
return true;
|
|
344
|
+
},
|
|
345
|
+
});
|
|
315
346
|
/**
|
|
316
347
|
* Hard delete an entity (permanently removes from table)
|
|
317
348
|
* Use with caution - prefer deleteEntity for soft delete
|
|
318
349
|
*/
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
})
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
350
|
+
const destroyEntity = serviceHandler({
|
|
351
|
+
alias: "destroyEntity",
|
|
352
|
+
description: "Hard delete an entity (permanently removes from table)",
|
|
353
|
+
input: {
|
|
354
|
+
id: { type: String, description: "Entity ID (sort key)" },
|
|
355
|
+
model: { type: String, description: "Entity model (partition key)" },
|
|
356
|
+
},
|
|
357
|
+
service: async ({ id, model }) => {
|
|
358
|
+
const docClient = getDocClient();
|
|
359
|
+
const tableName = getTableName();
|
|
360
|
+
const command = new DeleteCommand({
|
|
361
|
+
Key: { id, model },
|
|
362
|
+
TableName: tableName,
|
|
363
|
+
});
|
|
364
|
+
await docClient.send(command);
|
|
365
|
+
return true;
|
|
366
|
+
},
|
|
367
|
+
});
|
|
330
368
|
|
|
331
369
|
/**
|
|
332
370
|
* Calculate the suffix based on archived/deleted flags
|
|
@@ -375,76 +413,126 @@ async function executeQuery(indexName, keyValue, options = {}) {
|
|
|
375
413
|
* Query entities by organizational unit (parent hierarchy)
|
|
376
414
|
* Uses indexOu GSI
|
|
377
415
|
*
|
|
378
|
-
*
|
|
379
|
-
*
|
|
380
|
-
* @throws ConfigurationError if both archived and deleted are true
|
|
416
|
+
* Note: This is a regular async function (not serviceHandler) because it accepts
|
|
417
|
+
* complex startKey objects that can't be coerced by vocabulary's type system.
|
|
381
418
|
*/
|
|
382
|
-
async function queryByOu(
|
|
383
|
-
const { archived, deleted, model, ou, ...options } = params;
|
|
419
|
+
async function queryByOu({ archived = false, ascending = false, deleted = false, limit, model, ou, startKey, }) {
|
|
384
420
|
const suffix = calculateSuffix({ archived, deleted });
|
|
385
421
|
const keyValue = buildIndexOu(ou, model) + suffix;
|
|
386
|
-
return executeQuery(INDEX_OU, keyValue,
|
|
422
|
+
return executeQuery(INDEX_OU, keyValue, {
|
|
423
|
+
ascending,
|
|
424
|
+
limit,
|
|
425
|
+
startKey,
|
|
426
|
+
});
|
|
387
427
|
}
|
|
388
428
|
/**
|
|
389
429
|
* Query a single entity by human-friendly alias
|
|
390
430
|
* Uses indexAlias GSI
|
|
391
|
-
*
|
|
392
|
-
* @param params.archived - Query archived entities instead of active ones
|
|
393
|
-
* @param params.deleted - Query deleted entities instead of active ones
|
|
394
|
-
* @throws ConfigurationError if both archived and deleted are true
|
|
395
|
-
* @returns The matching entity or null if not found
|
|
396
431
|
*/
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
432
|
+
const queryByAlias = serviceHandler({
|
|
433
|
+
alias: "queryByAlias",
|
|
434
|
+
description: "Query a single entity by human-friendly alias",
|
|
435
|
+
input: {
|
|
436
|
+
alias: { type: String, description: "Human-friendly alias" },
|
|
437
|
+
archived: {
|
|
438
|
+
type: Boolean,
|
|
439
|
+
default: false,
|
|
440
|
+
required: false,
|
|
441
|
+
description: "Query archived entities instead of active ones",
|
|
442
|
+
},
|
|
443
|
+
deleted: {
|
|
444
|
+
type: Boolean,
|
|
445
|
+
default: false,
|
|
446
|
+
required: false,
|
|
447
|
+
description: "Query deleted entities instead of active ones",
|
|
448
|
+
},
|
|
449
|
+
model: { type: String, description: "Entity model name" },
|
|
450
|
+
ou: { type: String, description: "Organizational unit (@ for root)" },
|
|
451
|
+
},
|
|
452
|
+
service: async ({ alias, archived, deleted, model, ou, }) => {
|
|
453
|
+
const aliasStr = alias;
|
|
454
|
+
const archivedBool = archived;
|
|
455
|
+
const deletedBool = deleted;
|
|
456
|
+
const modelStr = model;
|
|
457
|
+
const ouStr = ou;
|
|
458
|
+
const suffix = calculateSuffix({ archived: archivedBool, deleted: deletedBool });
|
|
459
|
+
const keyValue = buildIndexAlias(ouStr, modelStr, aliasStr) + suffix;
|
|
460
|
+
const result = await executeQuery(INDEX_ALIAS, keyValue, {
|
|
461
|
+
limit: 1,
|
|
462
|
+
});
|
|
463
|
+
return result.items[0] ?? null;
|
|
464
|
+
},
|
|
465
|
+
});
|
|
404
466
|
/**
|
|
405
467
|
* Query entities by category classification
|
|
406
468
|
* Uses indexClass GSI
|
|
407
469
|
*
|
|
408
|
-
*
|
|
409
|
-
*
|
|
410
|
-
* @throws ConfigurationError if both archived and deleted are true
|
|
470
|
+
* Note: This is a regular async function (not serviceHandler) because it accepts
|
|
471
|
+
* complex startKey objects that can't be coerced by vocabulary's type system.
|
|
411
472
|
*/
|
|
412
|
-
async function queryByClass(
|
|
413
|
-
const { archived, deleted, model, ou, recordClass, ...options } = params;
|
|
473
|
+
async function queryByClass({ archived = false, ascending = false, deleted = false, limit, model, ou, recordClass, startKey, }) {
|
|
414
474
|
const suffix = calculateSuffix({ archived, deleted });
|
|
415
475
|
const keyValue = buildIndexClass(ou, model, recordClass) + suffix;
|
|
416
|
-
return executeQuery(INDEX_CLASS, keyValue,
|
|
476
|
+
return executeQuery(INDEX_CLASS, keyValue, {
|
|
477
|
+
ascending,
|
|
478
|
+
limit,
|
|
479
|
+
startKey,
|
|
480
|
+
});
|
|
417
481
|
}
|
|
418
482
|
/**
|
|
419
483
|
* Query entities by type classification
|
|
420
484
|
* Uses indexType GSI
|
|
421
485
|
*
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
* @throws ConfigurationError if both archived and deleted are true
|
|
486
|
+
* Note: This is a regular async function (not serviceHandler) because it accepts
|
|
487
|
+
* complex startKey objects that can't be coerced by vocabulary's type system.
|
|
425
488
|
*/
|
|
426
|
-
async function queryByType(
|
|
427
|
-
const { archived, deleted, model, ou, type, ...options } = params;
|
|
489
|
+
async function queryByType({ archived = false, ascending = false, deleted = false, limit, model, ou, startKey, type, }) {
|
|
428
490
|
const suffix = calculateSuffix({ archived, deleted });
|
|
429
491
|
const keyValue = buildIndexType(ou, model, type) + suffix;
|
|
430
|
-
return executeQuery(INDEX_TYPE, keyValue,
|
|
492
|
+
return executeQuery(INDEX_TYPE, keyValue, {
|
|
493
|
+
ascending,
|
|
494
|
+
limit,
|
|
495
|
+
startKey,
|
|
496
|
+
});
|
|
431
497
|
}
|
|
432
498
|
/**
|
|
433
499
|
* Query a single entity by external ID
|
|
434
500
|
* Uses indexXid GSI
|
|
435
|
-
*
|
|
436
|
-
* @param params.archived - Query archived entities instead of active ones
|
|
437
|
-
* @param params.deleted - Query deleted entities instead of active ones
|
|
438
|
-
* @throws ConfigurationError if both archived and deleted are true
|
|
439
|
-
* @returns The matching entity or null if not found
|
|
440
501
|
*/
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
502
|
+
const queryByXid = serviceHandler({
|
|
503
|
+
alias: "queryByXid",
|
|
504
|
+
description: "Query a single entity by external ID",
|
|
505
|
+
input: {
|
|
506
|
+
archived: {
|
|
507
|
+
type: Boolean,
|
|
508
|
+
default: false,
|
|
509
|
+
required: false,
|
|
510
|
+
description: "Query archived entities instead of active ones",
|
|
511
|
+
},
|
|
512
|
+
deleted: {
|
|
513
|
+
type: Boolean,
|
|
514
|
+
default: false,
|
|
515
|
+
required: false,
|
|
516
|
+
description: "Query deleted entities instead of active ones",
|
|
517
|
+
},
|
|
518
|
+
model: { type: String, description: "Entity model name" },
|
|
519
|
+
ou: { type: String, description: "Organizational unit (@ for root)" },
|
|
520
|
+
xid: { type: String, description: "External ID" },
|
|
521
|
+
},
|
|
522
|
+
service: async ({ archived, deleted, model, ou, xid, }) => {
|
|
523
|
+
const archivedBool = archived;
|
|
524
|
+
const deletedBool = deleted;
|
|
525
|
+
const modelStr = model;
|
|
526
|
+
const ouStr = ou;
|
|
527
|
+
const xidStr = xid;
|
|
528
|
+
const suffix = calculateSuffix({ archived: archivedBool, deleted: deletedBool });
|
|
529
|
+
const keyValue = buildIndexXid(ouStr, modelStr, xidStr) + suffix;
|
|
530
|
+
const result = await executeQuery(INDEX_XID, keyValue, {
|
|
531
|
+
limit: 1,
|
|
532
|
+
});
|
|
533
|
+
return result.items[0] ?? null;
|
|
534
|
+
},
|
|
535
|
+
});
|
|
448
536
|
|
|
449
537
|
export { APEX, ARCHIVED_SUFFIX, DELETED_SUFFIX, INDEX_ALIAS, INDEX_CLASS, INDEX_OU, INDEX_TYPE, INDEX_XID, SEPARATOR, archiveEntity, buildIndexAlias, buildIndexClass, buildIndexOu, buildIndexType, buildIndexXid, calculateOu, deleteEntity, destroyEntity, getDocClient, getEntity, getTableName, indexEntity, initClient, isInitialized, putEntity, queryByAlias, queryByClass, queryByOu, queryByType, queryByXid, resetClient, updateEntity };
|
|
450
538
|
//# sourceMappingURL=index.js.map
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../src/client.ts","../../../src/constants.ts","../../../src/keyBuilders.ts","../../../src/entities.ts","../../../src/queries.ts"],"sourcesContent":["import { DynamoDBClient } from \"@aws-sdk/client-dynamodb\";\nimport { DynamoDBDocumentClient } from \"@aws-sdk/lib-dynamodb\";\nimport { ConfigurationError } from \"@jaypie/errors\";\n\nimport type { DynamoClientConfig } from \"./types.js\";\n\nconst DEFAULT_REGION = \"us-east-1\";\nconst LOCAL_CREDENTIALS = {\n accessKeyId: \"local\",\n secretAccessKey: \"local\",\n};\n\n// Module-level state\nlet docClient: DynamoDBDocumentClient | null = null;\nlet tableName: string | null = null;\n\n/**\n * Check if endpoint indicates local development mode\n */\nfunction isLocalEndpoint(endpoint?: string): boolean {\n if (!endpoint) return false;\n return endpoint.includes(\"127.0.0.1\") || endpoint.includes(\"localhost\");\n}\n\n/**\n * Initialize the DynamoDB client\n * Must be called once at application startup before using query functions\n *\n * @param config - Client configuration\n */\nexport function initClient(config: DynamoClientConfig): void {\n const { endpoint, region = DEFAULT_REGION } = config;\n\n // Auto-detect local mode and use dummy credentials\n const credentials =\n config.credentials ??\n (isLocalEndpoint(endpoint) ? LOCAL_CREDENTIALS : undefined);\n\n const dynamoClient = new DynamoDBClient({\n ...(credentials && { credentials }),\n ...(endpoint && { endpoint }),\n region,\n });\n\n docClient = DynamoDBDocumentClient.from(dynamoClient, {\n marshallOptions: {\n removeUndefinedValues: true,\n },\n });\n\n tableName = config.tableName;\n}\n\n/**\n * Get the initialized DynamoDB Document Client\n * @throws ConfigurationError if client has not been initialized\n */\nexport function getDocClient(): DynamoDBDocumentClient {\n if (!docClient) {\n throw new ConfigurationError(\n \"DynamoDB client not initialized. Call initClient() first.\",\n );\n }\n return docClient;\n}\n\n/**\n * Get the configured table name\n * @throws ConfigurationError if client has not been initialized\n */\nexport function getTableName(): string {\n if (!tableName) {\n throw new ConfigurationError(\n \"DynamoDB client not initialized. Call initClient() first.\",\n );\n }\n return tableName;\n}\n\n/**\n * Check if the client has been initialized\n */\nexport function isInitialized(): boolean {\n return docClient !== null && tableName !== null;\n}\n\n/**\n * Reset the client state (primarily for testing)\n */\nexport function resetClient(): void {\n docClient = null;\n tableName = null;\n}\n","// Primary markers\nexport const APEX = \"@\"; // Root-level marker (DynamoDB prohibits empty strings)\nexport const SEPARATOR = \"#\"; // Composite key separator\n\n// GSI names\nexport const INDEX_ALIAS = \"indexAlias\";\nexport const INDEX_CLASS = \"indexClass\";\nexport const INDEX_OU = \"indexOu\";\nexport const INDEX_TYPE = \"indexType\";\nexport const INDEX_XID = \"indexXid\";\n\n// Index suffixes for soft state\nexport const ARCHIVED_SUFFIX = \"#archived\";\nexport const DELETED_SUFFIX = \"#deleted\";\n","import { APEX, SEPARATOR } from \"./constants.js\";\nimport type { FabricEntity, ParentReference } from \"./types.js\";\n\n/**\n * Build the indexOu key for hierarchical queries\n * @param ou - The organizational unit (APEX or \"{parent.model}#{parent.id}\")\n * @param model - The entity model name\n * @returns Composite key: \"{ou}#{model}\"\n */\nexport function buildIndexOu(ou: string, model: string): string {\n return `${ou}${SEPARATOR}${model}`;\n}\n\n/**\n * Build the indexAlias key for human-friendly lookups\n * @param ou - The organizational unit\n * @param model - The entity model name\n * @param alias - The human-friendly alias\n * @returns Composite key: \"{ou}#{model}#{alias}\"\n */\nexport function buildIndexAlias(\n ou: string,\n model: string,\n alias: string,\n): string {\n return `${ou}${SEPARATOR}${model}${SEPARATOR}${alias}`;\n}\n\n/**\n * Build the indexClass key for category filtering\n * @param ou - The organizational unit\n * @param model - The entity model name\n * @param recordClass - The category classification\n * @returns Composite key: \"{ou}#{model}#{class}\"\n */\nexport function buildIndexClass(\n ou: string,\n model: string,\n recordClass: string,\n): string {\n return `${ou}${SEPARATOR}${model}${SEPARATOR}${recordClass}`;\n}\n\n/**\n * Build the indexType key for type filtering\n * @param ou - The organizational unit\n * @param model - The entity model name\n * @param type - The type classification\n * @returns Composite key: \"{ou}#{model}#{type}\"\n */\nexport function buildIndexType(\n ou: string,\n model: string,\n type: string,\n): string {\n return `${ou}${SEPARATOR}${model}${SEPARATOR}${type}`;\n}\n\n/**\n * Build the indexXid key for external ID lookups\n * @param ou - The organizational unit\n * @param model - The entity model name\n * @param xid - The external ID\n * @returns Composite key: \"{ou}#{model}#{xid}\"\n */\nexport function buildIndexXid(ou: string, model: string, xid: string): string {\n return `${ou}${SEPARATOR}${model}${SEPARATOR}${xid}`;\n}\n\n/**\n * Calculate the organizational unit from a parent reference\n * @param parent - Optional parent entity reference\n * @returns APEX (\"@\") if no parent, otherwise \"{parent.model}#{parent.id}\"\n */\nexport function calculateOu(parent?: ParentReference): string {\n if (!parent) {\n return APEX;\n }\n return `${parent.model}${SEPARATOR}${parent.id}`;\n}\n\n/**\n * Auto-populate GSI index keys on an entity\n * - indexOu is always populated from ou + model\n * - indexAlias is populated only when alias is present\n * - indexClass is populated only when class is present\n * - indexType is populated only when type is present\n * - indexXid is populated only when xid is present\n *\n * @param entity - The entity to populate index keys for\n * @param suffix - Optional suffix to append to all index keys (e.g., \"#deleted\", \"#archived\")\n * @returns The entity with populated index keys\n */\nexport function indexEntity<T extends FabricEntity>(\n entity: T,\n suffix: string = \"\",\n): T {\n const result = { ...entity };\n\n // indexOu is always set (from ou + model)\n result.indexOu = buildIndexOu(entity.ou, entity.model) + suffix;\n\n // Optional indexes - only set when the source field is present\n if (entity.alias !== undefined) {\n result.indexAlias =\n buildIndexAlias(entity.ou, entity.model, entity.alias) + suffix;\n }\n\n if (entity.class !== undefined) {\n result.indexClass =\n buildIndexClass(entity.ou, entity.model, entity.class) + suffix;\n }\n\n if (entity.type !== undefined) {\n result.indexType =\n buildIndexType(entity.ou, entity.model, entity.type) + suffix;\n }\n\n if (entity.xid !== undefined) {\n result.indexXid =\n buildIndexXid(entity.ou, entity.model, entity.xid) + suffix;\n }\n\n return result;\n}\n","import { DeleteCommand, GetCommand, PutCommand } from \"@aws-sdk/lib-dynamodb\";\n\nimport { getDocClient, getTableName } from \"./client.js\";\nimport { ARCHIVED_SUFFIX, DELETED_SUFFIX } from \"./constants.js\";\nimport { indexEntity } from \"./keyBuilders.js\";\nimport type { FabricEntity } from \"./types.js\";\n\n/**\n * Parameters for getEntity\n */\nexport interface GetEntityParams {\n /** Entity ID (sort key) */\n id: string;\n /** Entity model (partition key) */\n model: string;\n}\n\n/**\n * Parameters for putEntity\n */\nexport interface PutEntityParams<T extends FabricEntity> {\n /** The entity to save */\n entity: T;\n}\n\n/**\n * Parameters for updateEntity\n */\nexport interface UpdateEntityParams<T extends FabricEntity> {\n /** The entity with updated fields */\n entity: T;\n}\n\n/**\n * Parameters for deleteEntity (soft delete)\n */\nexport interface DeleteEntityParams {\n /** Entity ID (sort key) */\n id: string;\n /** Entity model (partition key) */\n model: string;\n}\n\n/**\n * Parameters for archiveEntity\n */\nexport interface ArchiveEntityParams {\n /** Entity ID (sort key) */\n id: string;\n /** Entity model (partition key) */\n model: string;\n}\n\n/**\n * Get a single entity by primary key\n */\nexport async function getEntity<T extends FabricEntity = FabricEntity>(\n params: GetEntityParams,\n): Promise<T | null> {\n const { id, model } = params;\n const docClient = getDocClient();\n const tableName = getTableName();\n\n const command = new GetCommand({\n Key: { id, model },\n TableName: tableName,\n });\n\n const response = await docClient.send(command);\n return (response.Item as T) ?? null;\n}\n\n/**\n * Put (create or replace) an entity\n * Auto-populates GSI index keys via indexEntity\n */\nexport async function putEntity<T extends FabricEntity>(\n params: PutEntityParams<T>,\n): Promise<T> {\n const { entity } = params;\n const docClient = getDocClient();\n const tableName = getTableName();\n\n // Auto-populate index keys\n const indexedEntity = indexEntity(entity);\n\n const command = new PutCommand({\n Item: indexedEntity,\n TableName: tableName,\n });\n\n await docClient.send(command);\n return indexedEntity;\n}\n\n/**\n * Update an existing entity\n * Auto-populates GSI index keys and sets updatedAt\n */\nexport async function updateEntity<T extends FabricEntity>(\n params: UpdateEntityParams<T>,\n): Promise<T> {\n const { entity } = params;\n const docClient = getDocClient();\n const tableName = getTableName();\n\n // Update timestamp and re-index\n const updatedEntity = indexEntity({\n ...entity,\n updatedAt: new Date().toISOString(),\n });\n\n const command = new PutCommand({\n Item: updatedEntity,\n TableName: tableName,\n });\n\n await docClient.send(command);\n return updatedEntity;\n}\n\n/**\n * Calculate suffix based on entity's archived/deleted state\n */\nfunction calculateEntitySuffix(entity: {\n archivedAt?: string;\n deletedAt?: string;\n}): string {\n const hasArchived = Boolean(entity.archivedAt);\n const hasDeleted = Boolean(entity.deletedAt);\n\n if (hasArchived && hasDeleted) {\n return ARCHIVED_SUFFIX + DELETED_SUFFIX;\n }\n if (hasArchived) {\n return ARCHIVED_SUFFIX;\n }\n if (hasDeleted) {\n return DELETED_SUFFIX;\n }\n return \"\";\n}\n\n/**\n * Soft delete an entity by setting deletedAt timestamp\n * Re-indexes with appropriate suffix based on archived/deleted state\n */\nexport async function deleteEntity(\n params: DeleteEntityParams,\n): Promise<boolean> {\n const { id, model } = params;\n const docClient = getDocClient();\n const tableName = getTableName();\n\n // Fetch the current entity\n const existing = await getEntity({ id, model });\n if (!existing) {\n return false;\n }\n\n const now = new Date().toISOString();\n\n // Build updated entity with deletedAt\n const updatedEntity = {\n ...existing,\n deletedAt: now,\n updatedAt: now,\n };\n\n // Calculate suffix based on combined state (may already be archived)\n const suffix = calculateEntitySuffix(updatedEntity);\n const deletedEntity = indexEntity(updatedEntity, suffix);\n\n const command = new PutCommand({\n Item: deletedEntity,\n TableName: tableName,\n });\n\n await docClient.send(command);\n return true;\n}\n\n/**\n * Archive an entity by setting archivedAt timestamp\n * Re-indexes with appropriate suffix based on archived/deleted state\n */\nexport async function archiveEntity(\n params: ArchiveEntityParams,\n): Promise<boolean> {\n const { id, model } = params;\n const docClient = getDocClient();\n const tableName = getTableName();\n\n // Fetch the current entity\n const existing = await getEntity({ id, model });\n if (!existing) {\n return false;\n }\n\n const now = new Date().toISOString();\n\n // Build updated entity with archivedAt\n const updatedEntity = {\n ...existing,\n archivedAt: now,\n updatedAt: now,\n };\n\n // Calculate suffix based on combined state (may already be deleted)\n const suffix = calculateEntitySuffix(updatedEntity);\n const archivedEntity = indexEntity(updatedEntity, suffix);\n\n const command = new PutCommand({\n Item: archivedEntity,\n TableName: tableName,\n });\n\n await docClient.send(command);\n return true;\n}\n\n/**\n * Hard delete an entity (permanently removes from table)\n * Use with caution - prefer deleteEntity for soft delete\n */\nexport async function destroyEntity(\n params: DeleteEntityParams,\n): Promise<boolean> {\n const { id, model } = params;\n const docClient = getDocClient();\n const tableName = getTableName();\n\n const command = new DeleteCommand({\n Key: { id, model },\n TableName: tableName,\n });\n\n await docClient.send(command);\n return true;\n}\n","import { QueryCommand } from \"@aws-sdk/lib-dynamodb\";\n\nimport { getDocClient, getTableName } from \"./client.js\";\nimport {\n ARCHIVED_SUFFIX,\n DELETED_SUFFIX,\n INDEX_ALIAS,\n INDEX_CLASS,\n INDEX_OU,\n INDEX_TYPE,\n INDEX_XID,\n} from \"./constants.js\";\nimport {\n buildIndexAlias,\n buildIndexClass,\n buildIndexOu,\n buildIndexType,\n buildIndexXid,\n} from \"./keyBuilders.js\";\nimport type {\n BaseQueryOptions,\n FabricEntity,\n QueryByAliasParams,\n QueryByClassParams,\n QueryByOuParams,\n QueryByTypeParams,\n QueryByXidParams,\n QueryResult,\n} from \"./types.js\";\n\n/**\n * Calculate the suffix based on archived/deleted flags\n * When both are true, returns combined suffix (archived first, alphabetically)\n */\nfunction calculateSuffix({\n archived,\n deleted,\n}: {\n archived?: boolean;\n deleted?: boolean;\n}): string {\n if (archived && deleted) {\n return ARCHIVED_SUFFIX + DELETED_SUFFIX;\n }\n if (archived) {\n return ARCHIVED_SUFFIX;\n }\n if (deleted) {\n return DELETED_SUFFIX;\n }\n return \"\";\n}\n\n/**\n * Execute a GSI query with common options\n */\nasync function executeQuery<T extends FabricEntity>(\n indexName: string,\n keyValue: string,\n options: BaseQueryOptions = {},\n): Promise<QueryResult<T>> {\n const { ascending = false, limit, startKey } = options;\n\n const docClient = getDocClient();\n const tableName = getTableName();\n\n const command = new QueryCommand({\n ExclusiveStartKey: startKey as Record<string, unknown> | undefined,\n ExpressionAttributeNames: {\n \"#pk\": indexName,\n },\n ExpressionAttributeValues: {\n \":pkValue\": keyValue,\n },\n IndexName: indexName,\n KeyConditionExpression: \"#pk = :pkValue\",\n ...(limit && { Limit: limit }),\n ScanIndexForward: ascending,\n TableName: tableName,\n });\n\n const response = await docClient.send(command);\n\n return {\n items: (response.Items ?? []) as T[],\n lastEvaluatedKey: response.LastEvaluatedKey,\n };\n}\n\n/**\n * Query entities by organizational unit (parent hierarchy)\n * Uses indexOu GSI\n *\n * @param params.archived - Query archived entities instead of active ones\n * @param params.deleted - Query deleted entities instead of active ones\n * @throws ConfigurationError if both archived and deleted are true\n */\nexport async function queryByOu<T extends FabricEntity = FabricEntity>(\n params: QueryByOuParams,\n): Promise<QueryResult<T>> {\n const { archived, deleted, model, ou, ...options } = params;\n const suffix = calculateSuffix({ archived, deleted });\n const keyValue = buildIndexOu(ou, model) + suffix;\n return executeQuery<T>(INDEX_OU, keyValue, options);\n}\n\n/**\n * Query a single entity by human-friendly alias\n * Uses indexAlias GSI\n *\n * @param params.archived - Query archived entities instead of active ones\n * @param params.deleted - Query deleted entities instead of active ones\n * @throws ConfigurationError if both archived and deleted are true\n * @returns The matching entity or null if not found\n */\nexport async function queryByAlias<T extends FabricEntity = FabricEntity>(\n params: QueryByAliasParams,\n): Promise<T | null> {\n const { alias, archived, deleted, model, ou } = params;\n const suffix = calculateSuffix({ archived, deleted });\n const keyValue = buildIndexAlias(ou, model, alias) + suffix;\n const result = await executeQuery<T>(INDEX_ALIAS, keyValue, { limit: 1 });\n return result.items[0] ?? null;\n}\n\n/**\n * Query entities by category classification\n * Uses indexClass GSI\n *\n * @param params.archived - Query archived entities instead of active ones\n * @param params.deleted - Query deleted entities instead of active ones\n * @throws ConfigurationError if both archived and deleted are true\n */\nexport async function queryByClass<T extends FabricEntity = FabricEntity>(\n params: QueryByClassParams,\n): Promise<QueryResult<T>> {\n const { archived, deleted, model, ou, recordClass, ...options } = params;\n const suffix = calculateSuffix({ archived, deleted });\n const keyValue = buildIndexClass(ou, model, recordClass) + suffix;\n return executeQuery<T>(INDEX_CLASS, keyValue, options);\n}\n\n/**\n * Query entities by type classification\n * Uses indexType GSI\n *\n * @param params.archived - Query archived entities instead of active ones\n * @param params.deleted - Query deleted entities instead of active ones\n * @throws ConfigurationError if both archived and deleted are true\n */\nexport async function queryByType<T extends FabricEntity = FabricEntity>(\n params: QueryByTypeParams,\n): Promise<QueryResult<T>> {\n const { archived, deleted, model, ou, type, ...options } = params;\n const suffix = calculateSuffix({ archived, deleted });\n const keyValue = buildIndexType(ou, model, type) + suffix;\n return executeQuery<T>(INDEX_TYPE, keyValue, options);\n}\n\n/**\n * Query a single entity by external ID\n * Uses indexXid GSI\n *\n * @param params.archived - Query archived entities instead of active ones\n * @param params.deleted - Query deleted entities instead of active ones\n * @throws ConfigurationError if both archived and deleted are true\n * @returns The matching entity or null if not found\n */\nexport async function queryByXid<T extends FabricEntity = FabricEntity>(\n params: QueryByXidParams,\n): Promise<T | null> {\n const { archived, deleted, model, ou, xid } = params;\n const suffix = calculateSuffix({ archived, deleted });\n const keyValue = buildIndexXid(ou, model, xid) + suffix;\n const result = await executeQuery<T>(INDEX_XID, keyValue, { limit: 1 });\n return result.items[0] ?? null;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/client.ts","../../../src/constants.ts","../../../src/keyBuilders.ts","../../../src/entities.ts","../../../src/queries.ts"],"sourcesContent":["import { DynamoDBClient } from \"@aws-sdk/client-dynamodb\";\nimport { DynamoDBDocumentClient } from \"@aws-sdk/lib-dynamodb\";\nimport { ConfigurationError } from \"@jaypie/errors\";\n\nimport type { DynamoClientConfig } from \"./types.js\";\n\n// Environment variable names\nconst ENV_AWS_REGION = \"AWS_REGION\";\nconst ENV_DYNAMODB_TABLE_NAME = \"DYNAMODB_TABLE_NAME\";\n\n// Defaults\nconst DEFAULT_REGION = \"us-east-1\";\nconst LOCAL_CREDENTIALS = {\n accessKeyId: \"local\",\n secretAccessKey: \"local\",\n};\n\n// Module-level state\nlet docClient: DynamoDBDocumentClient | null = null;\nlet tableName: string | null = null;\n\n/**\n * Check if endpoint indicates local development mode\n */\nfunction isLocalEndpoint(endpoint?: string): boolean {\n if (!endpoint) return false;\n return endpoint.includes(\"127.0.0.1\") || endpoint.includes(\"localhost\");\n}\n\n/**\n * Initialize the DynamoDB client\n * Must be called once at application startup before using query functions\n *\n * @param config - Client configuration\n */\nexport function initClient(config: DynamoClientConfig = {}): void {\n const { endpoint } = config;\n const region =\n config.region ?? process.env[ENV_AWS_REGION] ?? DEFAULT_REGION;\n\n // Auto-detect local mode and use dummy credentials\n const credentials =\n config.credentials ??\n (isLocalEndpoint(endpoint) ? LOCAL_CREDENTIALS : undefined);\n\n const dynamoClient = new DynamoDBClient({\n ...(credentials && { credentials }),\n ...(endpoint && { endpoint }),\n region,\n });\n\n docClient = DynamoDBDocumentClient.from(dynamoClient, {\n marshallOptions: {\n removeUndefinedValues: true,\n },\n });\n\n tableName = config.tableName ?? process.env[ENV_DYNAMODB_TABLE_NAME] ?? null;\n}\n\n/**\n * Get the initialized DynamoDB Document Client\n * @throws ConfigurationError if client has not been initialized\n */\nexport function getDocClient(): DynamoDBDocumentClient {\n if (!docClient) {\n throw new ConfigurationError(\n \"DynamoDB client not initialized. Call initClient() first.\",\n );\n }\n return docClient;\n}\n\n/**\n * Get the configured table name\n * @throws ConfigurationError if client has not been initialized\n */\nexport function getTableName(): string {\n if (!tableName) {\n throw new ConfigurationError(\n \"DynamoDB client not initialized. Call initClient() first.\",\n );\n }\n return tableName;\n}\n\n/**\n * Check if the client has been initialized\n */\nexport function isInitialized(): boolean {\n return docClient !== null && tableName !== null;\n}\n\n/**\n * Reset the client state (primarily for testing)\n */\nexport function resetClient(): void {\n docClient = null;\n tableName = null;\n}\n","// Primary markers\nexport const APEX = \"@\"; // Root-level marker (DynamoDB prohibits empty strings)\nexport const SEPARATOR = \"#\"; // Composite key separator\n\n// GSI names\nexport const INDEX_ALIAS = \"indexAlias\";\nexport const INDEX_CLASS = \"indexClass\";\nexport const INDEX_OU = \"indexOu\";\nexport const INDEX_TYPE = \"indexType\";\nexport const INDEX_XID = \"indexXid\";\n\n// Index suffixes for soft state\nexport const ARCHIVED_SUFFIX = \"#archived\";\nexport const DELETED_SUFFIX = \"#deleted\";\n","import { APEX, SEPARATOR } from \"./constants.js\";\nimport type { FabricEntity, ParentReference } from \"./types.js\";\n\n/**\n * Build the indexOu key for hierarchical queries\n * @param ou - The organizational unit (APEX or \"{parent.model}#{parent.id}\")\n * @param model - The entity model name\n * @returns Composite key: \"{ou}#{model}\"\n */\nexport function buildIndexOu(ou: string, model: string): string {\n return `${ou}${SEPARATOR}${model}`;\n}\n\n/**\n * Build the indexAlias key for human-friendly lookups\n * @param ou - The organizational unit\n * @param model - The entity model name\n * @param alias - The human-friendly alias\n * @returns Composite key: \"{ou}#{model}#{alias}\"\n */\nexport function buildIndexAlias(\n ou: string,\n model: string,\n alias: string,\n): string {\n return `${ou}${SEPARATOR}${model}${SEPARATOR}${alias}`;\n}\n\n/**\n * Build the indexClass key for category filtering\n * @param ou - The organizational unit\n * @param model - The entity model name\n * @param recordClass - The category classification\n * @returns Composite key: \"{ou}#{model}#{class}\"\n */\nexport function buildIndexClass(\n ou: string,\n model: string,\n recordClass: string,\n): string {\n return `${ou}${SEPARATOR}${model}${SEPARATOR}${recordClass}`;\n}\n\n/**\n * Build the indexType key for type filtering\n * @param ou - The organizational unit\n * @param model - The entity model name\n * @param type - The type classification\n * @returns Composite key: \"{ou}#{model}#{type}\"\n */\nexport function buildIndexType(\n ou: string,\n model: string,\n type: string,\n): string {\n return `${ou}${SEPARATOR}${model}${SEPARATOR}${type}`;\n}\n\n/**\n * Build the indexXid key for external ID lookups\n * @param ou - The organizational unit\n * @param model - The entity model name\n * @param xid - The external ID\n * @returns Composite key: \"{ou}#{model}#{xid}\"\n */\nexport function buildIndexXid(ou: string, model: string, xid: string): string {\n return `${ou}${SEPARATOR}${model}${SEPARATOR}${xid}`;\n}\n\n/**\n * Calculate the organizational unit from a parent reference\n * @param parent - Optional parent entity reference\n * @returns APEX (\"@\") if no parent, otherwise \"{parent.model}#{parent.id}\"\n */\nexport function calculateOu(parent?: ParentReference): string {\n if (!parent) {\n return APEX;\n }\n return `${parent.model}${SEPARATOR}${parent.id}`;\n}\n\n/**\n * Auto-populate GSI index keys on an entity\n * - indexOu is always populated from ou + model\n * - indexAlias is populated only when alias is present\n * - indexClass is populated only when class is present\n * - indexType is populated only when type is present\n * - indexXid is populated only when xid is present\n *\n * @param entity - The entity to populate index keys for\n * @param suffix - Optional suffix to append to all index keys (e.g., \"#deleted\", \"#archived\")\n * @returns The entity with populated index keys\n */\nexport function indexEntity<T extends FabricEntity>(\n entity: T,\n suffix: string = \"\",\n): T {\n const result = { ...entity };\n\n // indexOu is always set (from ou + model)\n result.indexOu = buildIndexOu(entity.ou, entity.model) + suffix;\n\n // Optional indexes - only set when the source field is present\n if (entity.alias !== undefined) {\n result.indexAlias =\n buildIndexAlias(entity.ou, entity.model, entity.alias) + suffix;\n }\n\n if (entity.class !== undefined) {\n result.indexClass =\n buildIndexClass(entity.ou, entity.model, entity.class) + suffix;\n }\n\n if (entity.type !== undefined) {\n result.indexType =\n buildIndexType(entity.ou, entity.model, entity.type) + suffix;\n }\n\n if (entity.xid !== undefined) {\n result.indexXid =\n buildIndexXid(entity.ou, entity.model, entity.xid) + suffix;\n }\n\n return result;\n}\n","import { DeleteCommand, GetCommand, PutCommand } from \"@aws-sdk/lib-dynamodb\";\nimport { serviceHandler } from \"@jaypie/vocabulary\";\n\nimport { getDocClient, getTableName } from \"./client.js\";\nimport { ARCHIVED_SUFFIX, DELETED_SUFFIX } from \"./constants.js\";\nimport { indexEntity } from \"./keyBuilders.js\";\nimport type { FabricEntity } from \"./types.js\";\n\n/**\n * Calculate suffix based on entity's archived/deleted state\n */\nfunction calculateEntitySuffix(entity: {\n archivedAt?: string;\n deletedAt?: string;\n}): string {\n const hasArchived = Boolean(entity.archivedAt);\n const hasDeleted = Boolean(entity.deletedAt);\n\n if (hasArchived && hasDeleted) {\n return ARCHIVED_SUFFIX + DELETED_SUFFIX;\n }\n if (hasArchived) {\n return ARCHIVED_SUFFIX;\n }\n if (hasDeleted) {\n return DELETED_SUFFIX;\n }\n return \"\";\n}\n\n/**\n * Get a single entity by primary key\n */\nexport const getEntity = serviceHandler({\n alias: \"getEntity\",\n description: \"Get a single entity by primary key\",\n input: {\n id: { type: String, description: \"Entity ID (sort key)\" },\n model: { type: String, description: \"Entity model (partition key)\" },\n },\n service: async ({ id, model }): Promise<FabricEntity | null> => {\n const docClient = getDocClient();\n const tableName = getTableName();\n\n const command = new GetCommand({\n Key: { id, model },\n TableName: tableName,\n });\n\n const response = await docClient.send(command);\n return (response.Item as FabricEntity) ?? null;\n },\n});\n\n/**\n * Put (create or replace) an entity\n * Auto-populates GSI index keys via indexEntity\n *\n * Note: This is a regular async function (not serviceHandler) because it accepts\n * complex FabricEntity objects that can't be coerced by vocabulary's type system.\n */\nexport async function putEntity({\n entity,\n}: {\n entity: FabricEntity;\n}): Promise<FabricEntity> {\n const docClient = getDocClient();\n const tableName = getTableName();\n\n // Auto-populate index keys\n const indexedEntity = indexEntity(entity);\n\n const command = new PutCommand({\n Item: indexedEntity,\n TableName: tableName,\n });\n\n await docClient.send(command);\n return indexedEntity;\n}\n\n/**\n * Update an existing entity\n * Auto-populates GSI index keys and sets updatedAt\n *\n * Note: This is a regular async function (not serviceHandler) because it accepts\n * complex FabricEntity objects that can't be coerced by vocabulary's type system.\n */\nexport async function updateEntity({\n entity,\n}: {\n entity: FabricEntity;\n}): Promise<FabricEntity> {\n const docClient = getDocClient();\n const tableName = getTableName();\n\n // Update timestamp and re-index\n const updatedEntity = indexEntity({\n ...entity,\n updatedAt: new Date().toISOString(),\n });\n\n const command = new PutCommand({\n Item: updatedEntity,\n TableName: tableName,\n });\n\n await docClient.send(command);\n return updatedEntity;\n}\n\n/**\n * Soft delete an entity by setting deletedAt timestamp\n * Re-indexes with appropriate suffix based on archived/deleted state\n */\nexport const deleteEntity = serviceHandler({\n alias: \"deleteEntity\",\n description: \"Soft delete an entity (sets deletedAt timestamp)\",\n input: {\n id: { type: String, description: \"Entity ID (sort key)\" },\n model: { type: String, description: \"Entity model (partition key)\" },\n },\n service: async ({ id, model }): Promise<boolean> => {\n const docClient = getDocClient();\n const tableName = getTableName();\n\n // Fetch the current entity\n const existing = await getEntity({ id, model });\n if (!existing) {\n return false;\n }\n\n const now = new Date().toISOString();\n\n // Build updated entity with deletedAt\n const updatedEntity = {\n ...existing,\n deletedAt: now,\n updatedAt: now,\n };\n\n // Calculate suffix based on combined state (may already be archived)\n const suffix = calculateEntitySuffix(updatedEntity);\n const deletedEntity = indexEntity(updatedEntity, suffix);\n\n const command = new PutCommand({\n Item: deletedEntity,\n TableName: tableName,\n });\n\n await docClient.send(command);\n return true;\n },\n});\n\n/**\n * Archive an entity by setting archivedAt timestamp\n * Re-indexes with appropriate suffix based on archived/deleted state\n */\nexport const archiveEntity = serviceHandler({\n alias: \"archiveEntity\",\n description: \"Archive an entity (sets archivedAt timestamp)\",\n input: {\n id: { type: String, description: \"Entity ID (sort key)\" },\n model: { type: String, description: \"Entity model (partition key)\" },\n },\n service: async ({ id, model }): Promise<boolean> => {\n const docClient = getDocClient();\n const tableName = getTableName();\n\n // Fetch the current entity\n const existing = await getEntity({ id, model });\n if (!existing) {\n return false;\n }\n\n const now = new Date().toISOString();\n\n // Build updated entity with archivedAt\n const updatedEntity = {\n ...existing,\n archivedAt: now,\n updatedAt: now,\n };\n\n // Calculate suffix based on combined state (may already be deleted)\n const suffix = calculateEntitySuffix(updatedEntity);\n const archivedEntity = indexEntity(updatedEntity, suffix);\n\n const command = new PutCommand({\n Item: archivedEntity,\n TableName: tableName,\n });\n\n await docClient.send(command);\n return true;\n },\n});\n\n/**\n * Hard delete an entity (permanently removes from table)\n * Use with caution - prefer deleteEntity for soft delete\n */\nexport const destroyEntity = serviceHandler({\n alias: \"destroyEntity\",\n description: \"Hard delete an entity (permanently removes from table)\",\n input: {\n id: { type: String, description: \"Entity ID (sort key)\" },\n model: { type: String, description: \"Entity model (partition key)\" },\n },\n service: async ({ id, model }): Promise<boolean> => {\n const docClient = getDocClient();\n const tableName = getTableName();\n\n const command = new DeleteCommand({\n Key: { id, model },\n TableName: tableName,\n });\n\n await docClient.send(command);\n return true;\n },\n});\n","import { QueryCommand } from \"@aws-sdk/lib-dynamodb\";\nimport { serviceHandler } from \"@jaypie/vocabulary\";\n\nimport { getDocClient, getTableName } from \"./client.js\";\nimport {\n ARCHIVED_SUFFIX,\n DELETED_SUFFIX,\n INDEX_ALIAS,\n INDEX_CLASS,\n INDEX_OU,\n INDEX_TYPE,\n INDEX_XID,\n} from \"./constants.js\";\nimport {\n buildIndexAlias,\n buildIndexClass,\n buildIndexOu,\n buildIndexType,\n buildIndexXid,\n} from \"./keyBuilders.js\";\nimport type { BaseQueryOptions, FabricEntity, QueryResult } from \"./types.js\";\n\n/**\n * Calculate the suffix based on archived/deleted flags\n * When both are true, returns combined suffix (archived first, alphabetically)\n */\nfunction calculateSuffix({\n archived,\n deleted,\n}: {\n archived?: boolean;\n deleted?: boolean;\n}): string {\n if (archived && deleted) {\n return ARCHIVED_SUFFIX + DELETED_SUFFIX;\n }\n if (archived) {\n return ARCHIVED_SUFFIX;\n }\n if (deleted) {\n return DELETED_SUFFIX;\n }\n return \"\";\n}\n\n/**\n * Execute a GSI query with common options\n */\nasync function executeQuery<T extends FabricEntity>(\n indexName: string,\n keyValue: string,\n options: BaseQueryOptions = {},\n): Promise<QueryResult<T>> {\n const { ascending = false, limit, startKey } = options;\n\n const docClient = getDocClient();\n const tableName = getTableName();\n\n const command = new QueryCommand({\n ExclusiveStartKey: startKey as Record<string, unknown> | undefined,\n ExpressionAttributeNames: {\n \"#pk\": indexName,\n },\n ExpressionAttributeValues: {\n \":pkValue\": keyValue,\n },\n IndexName: indexName,\n KeyConditionExpression: \"#pk = :pkValue\",\n ...(limit && { Limit: limit }),\n ScanIndexForward: ascending,\n TableName: tableName,\n });\n\n const response = await docClient.send(command);\n\n return {\n items: (response.Items ?? []) as T[],\n lastEvaluatedKey: response.LastEvaluatedKey,\n };\n}\n\n/**\n * Query parameters for queryByOu\n */\ninterface QueryByOuParams extends BaseQueryOptions {\n model: string;\n ou: string;\n}\n\n/**\n * Query entities by organizational unit (parent hierarchy)\n * Uses indexOu GSI\n *\n * Note: This is a regular async function (not serviceHandler) because it accepts\n * complex startKey objects that can't be coerced by vocabulary's type system.\n */\nexport async function queryByOu({\n archived = false,\n ascending = false,\n deleted = false,\n limit,\n model,\n ou,\n startKey,\n}: QueryByOuParams): Promise<QueryResult<FabricEntity>> {\n const suffix = calculateSuffix({ archived, deleted });\n const keyValue = buildIndexOu(ou, model) + suffix;\n return executeQuery<FabricEntity>(INDEX_OU, keyValue, {\n ascending,\n limit,\n startKey,\n });\n}\n\n/**\n * Query a single entity by human-friendly alias\n * Uses indexAlias GSI\n */\nexport const queryByAlias = serviceHandler({\n alias: \"queryByAlias\",\n description: \"Query a single entity by human-friendly alias\",\n input: {\n alias: { type: String, description: \"Human-friendly alias\" },\n archived: {\n type: Boolean,\n default: false,\n required: false,\n description: \"Query archived entities instead of active ones\",\n },\n deleted: {\n type: Boolean,\n default: false,\n required: false,\n description: \"Query deleted entities instead of active ones\",\n },\n model: { type: String, description: \"Entity model name\" },\n ou: { type: String, description: \"Organizational unit (@ for root)\" },\n },\n service: async ({\n alias,\n archived,\n deleted,\n model,\n ou,\n }): Promise<FabricEntity | null> => {\n const aliasStr = alias as string;\n const archivedBool = archived as boolean | undefined;\n const deletedBool = deleted as boolean | undefined;\n const modelStr = model as string;\n const ouStr = ou as string;\n\n const suffix = calculateSuffix({ archived: archivedBool, deleted: deletedBool });\n const keyValue = buildIndexAlias(ouStr, modelStr, aliasStr) + suffix;\n const result = await executeQuery<FabricEntity>(INDEX_ALIAS, keyValue, {\n limit: 1,\n });\n return result.items[0] ?? null;\n },\n});\n\n/**\n * Query parameters for queryByClass\n */\ninterface QueryByClassParams extends BaseQueryOptions {\n model: string;\n ou: string;\n recordClass: string;\n}\n\n/**\n * Query entities by category classification\n * Uses indexClass GSI\n *\n * Note: This is a regular async function (not serviceHandler) because it accepts\n * complex startKey objects that can't be coerced by vocabulary's type system.\n */\nexport async function queryByClass({\n archived = false,\n ascending = false,\n deleted = false,\n limit,\n model,\n ou,\n recordClass,\n startKey,\n}: QueryByClassParams): Promise<QueryResult<FabricEntity>> {\n const suffix = calculateSuffix({ archived, deleted });\n const keyValue = buildIndexClass(ou, model, recordClass) + suffix;\n return executeQuery<FabricEntity>(INDEX_CLASS, keyValue, {\n ascending,\n limit,\n startKey,\n });\n}\n\n/**\n * Query parameters for queryByType\n */\ninterface QueryByTypeParams extends BaseQueryOptions {\n model: string;\n ou: string;\n type: string;\n}\n\n/**\n * Query entities by type classification\n * Uses indexType GSI\n *\n * Note: This is a regular async function (not serviceHandler) because it accepts\n * complex startKey objects that can't be coerced by vocabulary's type system.\n */\nexport async function queryByType({\n archived = false,\n ascending = false,\n deleted = false,\n limit,\n model,\n ou,\n startKey,\n type,\n}: QueryByTypeParams): Promise<QueryResult<FabricEntity>> {\n const suffix = calculateSuffix({ archived, deleted });\n const keyValue = buildIndexType(ou, model, type) + suffix;\n return executeQuery<FabricEntity>(INDEX_TYPE, keyValue, {\n ascending,\n limit,\n startKey,\n });\n}\n\n/**\n * Query a single entity by external ID\n * Uses indexXid GSI\n */\nexport const queryByXid = serviceHandler({\n alias: \"queryByXid\",\n description: \"Query a single entity by external ID\",\n input: {\n archived: {\n type: Boolean,\n default: false,\n required: false,\n description: \"Query archived entities instead of active ones\",\n },\n deleted: {\n type: Boolean,\n default: false,\n required: false,\n description: \"Query deleted entities instead of active ones\",\n },\n model: { type: String, description: \"Entity model name\" },\n ou: { type: String, description: \"Organizational unit (@ for root)\" },\n xid: { type: String, description: \"External ID\" },\n },\n service: async ({\n archived,\n deleted,\n model,\n ou,\n xid,\n }): Promise<FabricEntity | null> => {\n const archivedBool = archived as boolean | undefined;\n const deletedBool = deleted as boolean | undefined;\n const modelStr = model as string;\n const ouStr = ou as string;\n const xidStr = xid as string;\n\n const suffix = calculateSuffix({ archived: archivedBool, deleted: deletedBool });\n const keyValue = buildIndexXid(ouStr, modelStr, xidStr) + suffix;\n const result = await executeQuery<FabricEntity>(INDEX_XID, keyValue, {\n limit: 1,\n });\n return result.items[0] ?? null;\n },\n});\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate docker-compose.yml for local DynamoDB development
|
|
3
|
+
*/
|
|
4
|
+
export declare const dockerComposeHandler: import("@jaypie/vocabulary").ServiceHandlerFunction<Record<string, unknown>, {
|
|
5
|
+
dockerCompose: string;
|
|
6
|
+
envFile: string;
|
|
7
|
+
envVars: {
|
|
8
|
+
AWS_REGION: string;
|
|
9
|
+
DYNAMODB_ENDPOINT: string;
|
|
10
|
+
DYNAMODB_TABLE_NAME: unknown;
|
|
11
|
+
};
|
|
12
|
+
}>;
|