dynamodb-reactive 0.1.1 → 0.1.4

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/server.js CHANGED
@@ -2,7 +2,7 @@ import { SystemTableNames } from './chunk-HZ6JHAJJ.js';
2
2
  import { DynamoDBClient, ExecuteStatementCommand } from '@aws-sdk/client-dynamodb';
3
3
  import { UpdateCommand, DeleteCommand, PutCommand, GetCommand, DynamoDBDocumentClient, QueryCommand } from '@aws-sdk/lib-dynamodb';
4
4
  import { unmarshall } from '@aws-sdk/util-dynamodb';
5
- import { compare, applyPatch } from 'fast-json-patch';
5
+ import jsonpatch from 'fast-json-patch';
6
6
  import { ApiGatewayManagementApiClient, PostToConnectionCommand, GoneException } from '@aws-sdk/client-apigatewaymanagementapi';
7
7
 
8
8
  // ../server/src/procedure.ts
@@ -683,6 +683,7 @@ var DependencyTracker = class {
683
683
  this.operations = [];
684
684
  }
685
685
  };
686
+ var { applyPatch, compare } = jsonpatch;
686
687
  function generatePatches(oldValue, newValue) {
687
688
  const operations = compare(
688
689
  oldValue,
@@ -741,31 +742,35 @@ function batchPatches(patchSets) {
741
742
  }
742
743
  function createReactiveHandler(config) {
743
744
  const ttlSeconds = config.ttlSeconds ?? 3600;
744
- const connectionsTable = config.connectionsTableName ?? SystemTableNames.connections;
745
- const dependenciesTable = config.dependenciesTableName ?? SystemTableNames.dependencies;
746
- const queriesTable = config.queriesTableName ?? SystemTableNames.queries;
745
+ const prefix = config.tablePrefix ? `${config.tablePrefix}-` : "";
746
+ const connectionsTable = `${prefix}${SystemTableNames.connections}`;
747
+ const dependenciesTable = `${prefix}${SystemTableNames.dependencies}`;
748
+ const queriesTable = `${prefix}${SystemTableNames.queries}`;
747
749
  const ddbClient = new DynamoDBClient({
748
750
  region: config.dbConfig?.region ?? process.env.AWS_REGION
749
751
  });
750
- const docClient = DynamoDBDocumentClient.from(ddbClient);
751
- async function handleRequest(connectionId, request) {
752
+ const docClient = DynamoDBDocumentClient.from(ddbClient, {
753
+ marshallOptions: { removeUndefinedValues: true }
754
+ });
755
+ async function handleRequest(request, headers) {
752
756
  try {
753
- const ctx = await config.getContext(connectionId);
757
+ const connectionId = request.connectionId;
758
+ const ctx = await config.getContext({ connectionId, headers });
754
759
  const dependencyTracker = new DependencyTracker();
755
760
  const db = createDbContext(config.dbConfig ?? {}, dependencyTracker);
756
761
  const fullCtx = { ...ctx, db };
757
762
  switch (request.type) {
758
763
  case "subscribe":
759
- return handleSubscribe(
764
+ return await handleSubscribe(
760
765
  connectionId,
761
766
  request,
762
767
  fullCtx,
763
768
  dependencyTracker
764
769
  );
765
770
  case "unsubscribe":
766
- return handleUnsubscribe(connectionId, request);
771
+ return await handleUnsubscribe(connectionId, request);
767
772
  case "call":
768
- return handleCall(request, fullCtx);
773
+ return await handleCall(request, fullCtx);
769
774
  default:
770
775
  return {
771
776
  type: "error",
@@ -776,6 +781,7 @@ function createReactiveHandler(config) {
776
781
  return {
777
782
  type: "error",
778
783
  message: error instanceof Error ? error.message : "Unknown error",
784
+ code: error.code,
779
785
  subscriptionId: "subscriptionId" in request ? request.subscriptionId : void 0
780
786
  };
781
787
  }
@@ -910,13 +916,38 @@ function createReactiveHandler(config) {
910
916
  );
911
917
  console.log("Connection unregistered:", connectionId);
912
918
  }
919
+ async function query(path, input, headers) {
920
+ const ctx = await config.getContext({ connectionId: "query", headers });
921
+ const dependencyTracker = new DependencyTracker();
922
+ const db = createDbContext(config.dbConfig ?? {}, dependencyTracker);
923
+ const fullCtx = { ...ctx, db };
924
+ return config.router.execute(path, fullCtx, input);
925
+ }
926
+ function createCaller() {
927
+ function buildProxy(path = []) {
928
+ return new Proxy(() => {
929
+ }, {
930
+ get(_target, prop) {
931
+ return buildProxy([...path, prop]);
932
+ },
933
+ apply(_target, _thisArg, args) {
934
+ const procedurePath = path.join(".");
935
+ return query(procedurePath, args[0]);
936
+ }
937
+ });
938
+ }
939
+ return buildProxy();
940
+ }
913
941
  return {
914
942
  handleRequest,
915
943
  registerConnection,
916
- unregisterConnection
944
+ unregisterConnection,
945
+ query,
946
+ createCaller
917
947
  };
918
948
  }
919
949
  function createStreamHandler(config) {
950
+ const connectionsTable = config.connectionsTableName ?? SystemTableNames.connections;
920
951
  const dependenciesTable = config.dependenciesTableName ?? SystemTableNames.dependencies;
921
952
  const queriesTable = config.queriesTableName ?? SystemTableNames.queries;
922
953
  const ddbClient = new DynamoDBClient({
@@ -1083,6 +1114,7 @@ function createStreamHandler(config) {
1083
1114
  return `"${field}" <= ${escapedValue}`;
1084
1115
  case "between":
1085
1116
  return `"${field}" BETWEEN ${escapedValue} AND ${escapeValue(value2)}`;
1117
+ case void 0:
1086
1118
  default:
1087
1119
  return "";
1088
1120
  }
@@ -1094,6 +1126,7 @@ function createStreamHandler(config) {
1094
1126
  return `begins_with("${field}", ${escapedValue})`;
1095
1127
  case "contains":
1096
1128
  return `contains("${field}", ${escapedValue})`;
1129
+ case void 0:
1097
1130
  default:
1098
1131
  return "";
1099
1132
  }
@@ -1108,6 +1141,7 @@ function createStreamHandler(config) {
1108
1141
  return `(${subclauses.join(" OR ")})`;
1109
1142
  case "not":
1110
1143
  return subclauses.length > 0 ? `NOT (${subclauses[0]})` : "";
1144
+ case void 0:
1111
1145
  default:
1112
1146
  return "";
1113
1147
  }
@@ -1168,6 +1202,54 @@ function createStreamHandler(config) {
1168
1202
  }
1169
1203
  async function cleanupConnection(connectionId) {
1170
1204
  console.log("Cleaning up disconnected connection:", connectionId);
1205
+ try {
1206
+ const queriesResponse = await docClient.send(
1207
+ new QueryCommand({
1208
+ TableName: queriesTable,
1209
+ KeyConditionExpression: "pk = :pk",
1210
+ ExpressionAttributeValues: {
1211
+ ":pk": connectionId
1212
+ }
1213
+ })
1214
+ );
1215
+ const subscriptions = queriesResponse.Items ?? [];
1216
+ for (const sub of subscriptions) {
1217
+ const deps = sub.dependencies ?? [];
1218
+ for (const depKey of deps) {
1219
+ await docClient.send(
1220
+ new DeleteCommand({
1221
+ TableName: dependenciesTable,
1222
+ Key: {
1223
+ pk: depKey,
1224
+ sk: `${connectionId}#${sub.sk}`
1225
+ }
1226
+ })
1227
+ );
1228
+ }
1229
+ await docClient.send(
1230
+ new DeleteCommand({
1231
+ TableName: queriesTable,
1232
+ Key: {
1233
+ pk: connectionId,
1234
+ sk: sub.sk
1235
+ }
1236
+ })
1237
+ );
1238
+ }
1239
+ await docClient.send(
1240
+ new DeleteCommand({
1241
+ TableName: connectionsTable,
1242
+ Key: {
1243
+ connectionId
1244
+ }
1245
+ })
1246
+ );
1247
+ console.log(
1248
+ `Cleaned up connection ${connectionId}: ${subscriptions.length} subscriptions removed`
1249
+ );
1250
+ } catch (error) {
1251
+ console.error("Error cleaning up connection:", error);
1252
+ }
1171
1253
  }
1172
1254
  return { handler };
1173
1255
  }
@@ -1287,6 +1369,13 @@ function createLambdaHandlers() {
1287
1369
  const { type, subscriptionId } = body;
1288
1370
  let response;
1289
1371
  switch (type) {
1372
+ case "init": {
1373
+ response = {
1374
+ type: "connected",
1375
+ connectionId
1376
+ };
1377
+ break;
1378
+ }
1290
1379
  case "unsubscribe": {
1291
1380
  const subResponse = await docClient.send(
1292
1381
  new GetCommand({
@@ -1416,7 +1505,9 @@ function createLambdaHandlers() {
1416
1505
  );
1417
1506
  return;
1418
1507
  }
1419
- const newResult = await executeQueryFromMetadata(queryState.queryMetadata);
1508
+ const newResult = await executeQueryFromMetadata(
1509
+ queryState.queryMetadata
1510
+ );
1420
1511
  if (!hasChanges(queryState.lastResult, newResult)) {
1421
1512
  return;
1422
1513
  }
@@ -1490,6 +1581,7 @@ function createLambdaHandlers() {
1490
1581
  return `"${field}" <= ${escapedValue}`;
1491
1582
  case "between":
1492
1583
  return `"${field}" BETWEEN ${escapedValue} AND ${escapeValue(value2)}`;
1584
+ case void 0:
1493
1585
  default:
1494
1586
  return "";
1495
1587
  }
@@ -1501,6 +1593,7 @@ function createLambdaHandlers() {
1501
1593
  return `begins_with("${field}", ${escapedValue})`;
1502
1594
  case "contains":
1503
1595
  return `contains("${field}", ${escapedValue})`;
1596
+ case void 0:
1504
1597
  default:
1505
1598
  return "";
1506
1599
  }
@@ -1515,6 +1608,7 @@ function createLambdaHandlers() {
1515
1608
  return `(${subclauses.join(" OR ")})`;
1516
1609
  case "not":
1517
1610
  return subclauses.length > 0 ? `NOT (${subclauses[0]})` : "";
1611
+ case void 0:
1518
1612
  default:
1519
1613
  return "";
1520
1614
  }