aws-classify-server 0.1.3 → 0.1.5

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/README.md CHANGED
@@ -274,7 +274,7 @@ plugins:
274
274
  - serverless-dynamodb-local
275
275
  - serverless-offline
276
276
  ```
277
- The provider section details configuration the Serverless Framework handles. Many of the details are in included files to keep this simple and resiliant to change
277
+ The provider section details configuration the Serverless Framework handles. Many of the details are in included files to keep this simple and resilient to change
278
278
  ```
279
279
  provider:
280
280
  name: aws
@@ -285,6 +285,7 @@ provider:
285
285
  websocket: true
286
286
  environment:
287
287
  APIG_ENDPOINT: ${file(${self:custom.yml}/apig.yml)}
288
+ DOMAIN: ${self:custom.domainName}
288
289
  iam:
289
290
  role:
290
291
  statements:
@@ -4,7 +4,9 @@ export declare class ClassifyServerless {
4
4
  logLevel: Partial<typeof EndPointsLogging>;
5
5
  classDefs: Map<any, ClassDef<any, any>>;
6
6
  requests: Map<any, any>;
7
+ expirationMinutes: number;
7
8
  log: (_message: string) => void;
9
+ setExpirationMinutes(minutes: number): void;
8
10
  setLogger(log: (_message: string) => void): void;
9
11
  setLogLevel(logLevel: Partial<typeof EndPointsLogging>): void;
10
12
  registerResponse<T>(responseClass: new () => T, authorizer?: (_endPoint: T, _method: string, _args: IArguments) => Promise<boolean>): void;
@@ -17,9 +19,12 @@ export declare class ClassifyServerless {
17
19
  createRequestForSession<T>(sessionId: string, requestClass: new () => T): Promise<T>;
18
20
  createResponse<T, R>(responseClass: new () => T, sessionId: string, callback: (_obj: T) => Promise<R>, classes?: any): Promise<R>;
19
21
  getSessionsForUserId(userId: string): Promise<any[]>;
22
+ getSessions(): Promise<any[]>;
23
+ deleteSessionsForUserId(userId: string): Promise<void>;
24
+ deleteSessions(): Promise<void>;
20
25
  }
21
26
  export declare function getSessionData(sessionId: string, interfaceName?: string): Promise<Record<string, any> | undefined>;
22
- export declare function saveSessionData(sessionId: string, interfaceName?: string, sessionData?: string, connectionId?: string, userId?: string): Promise<string>;
27
+ export declare function saveSessionData(sessionId: string, interfaceName?: string, sessionData?: string, connectionId?: string, userId?: string, expirationMinutes?: number): Promise<string>;
23
28
  export declare const EndPointsLogging: {
24
29
  create: boolean;
25
30
  connect: boolean;
@@ -21,8 +21,12 @@ class ClassifyServerless {
21
21
  this.logLevel = {};
22
22
  this.classDefs = new Map();
23
23
  this.requests = new Map();
24
+ this.expirationMinutes = 60 * 24;
24
25
  this.log = msg => console.log(msg);
25
26
  }
27
+ setExpirationMinutes(minutes) {
28
+ this.expirationMinutes = minutes;
29
+ }
26
30
  setLogger(log) {
27
31
  this.log = log;
28
32
  }
@@ -54,7 +58,7 @@ class ClassifyServerless {
54
58
  const socketResult = yield getSessionData(sessionId, "");
55
59
  if (!socketResult) {
56
60
  sessionId = context.awsRequestId;
57
- yield saveSessionData(sessionId, undefined, undefined, undefined);
61
+ yield saveSessionData(sessionId, undefined, undefined, undefined, undefined, this.expirationMinutes);
58
62
  }
59
63
  const lambdaResponse = {
60
64
  data: process.env.IS_OFFLINE ? 'ws://localhost:3001' : `wss://${process.env.APIG_ENDPOINT}`,
@@ -106,7 +110,7 @@ class ClassifyServerless {
106
110
  }
107
111
  const updatedSessionData = (0, js_freeze_dry_1.serialize)(obj, classes);
108
112
  if (!result || updatedSessionData !== result.sessionData)
109
- sessionId = yield saveSessionData(sessionId, request.interfaceName, updatedSessionData, undefined, obj.__userId__);
113
+ sessionId = yield saveSessionData(sessionId, request.interfaceName, updatedSessionData, undefined, obj.__userId__, this.expirationMinutes);
110
114
  // Formulate response
111
115
  const lambdaResponse = {
112
116
  data: fnResponse,
@@ -174,7 +178,7 @@ class ClassifyServerless {
174
178
  catch (e) {
175
179
  if (expressServer.logLevel.exceptions)
176
180
  expressServer.log(e.message);
177
- throw e;
181
+ throw new Error(`Unable to send message via Websocket ${e.message}`);
178
182
  }
179
183
  });
180
184
  };
@@ -238,10 +242,10 @@ class ClassifyServerless {
238
242
  this.log(`creating response for ${interfaceName} with sessionId=${sessionId} connectionId= ${obj.__connectionId__} sessionData=${sessionData}`);
239
243
  const ret = yield callback(obj);
240
244
  const updatedSessionData = (0, js_freeze_dry_1.serialize)(obj, classes);
241
- if (updatedSessionData !== result.sessionData) {
245
+ if (updatedSessionData !== result.sessionData || Math.floor(Date.now() / 1000 / 60) !== result.expires / 60) {
242
246
  if (this.logLevel.calls)
243
247
  this.log(`saving session data for ${interfaceName} with sessionId=${sessionId} connectionId= ${obj.__connectionId__} sessionData=${updatedSessionData}`);
244
- yield saveSessionData(sessionId, interfaceName, updatedSessionData, undefined);
248
+ yield saveSessionData(sessionId, interfaceName, updatedSessionData, undefined, undefined, this.expirationMinutes);
245
249
  }
246
250
  return ret;
247
251
  });
@@ -263,8 +267,54 @@ class ClassifyServerless {
263
267
  return [];
264
268
  });
265
269
  }
270
+ getSessions() {
271
+ return __awaiter(this, void 0, void 0, function* () {
272
+ const data = yield ddbDocClient.scan({
273
+ TableName: `classifySessionStore.${process.env.DOMAIN}`,
274
+ ProjectionExpression: `sessionId`
275
+ });
276
+ return data.Items ? data.Items.map(i => i.sessionId) : [];
277
+ });
278
+ }
279
+ deleteSessionsForUserId(userId) {
280
+ return __awaiter(this, void 0, void 0, function* () {
281
+ if (userId) {
282
+ const data = yield ddbDocClient.query({
283
+ TableName: `classifySessionStore.${process.env.DOMAIN}`,
284
+ KeyConditionExpression: 'userId = :userId',
285
+ IndexName: 'userId',
286
+ ExpressionAttributeValues: {
287
+ ':userId': userId,
288
+ },
289
+ ProjectionExpression: `sessionId`
290
+ });
291
+ const keys = data.Items ? data.Items.map(i => i.sessionId) : [];
292
+ yield deleteSessionByKeys(keys);
293
+ }
294
+ });
295
+ }
296
+ deleteSessions() {
297
+ return __awaiter(this, void 0, void 0, function* () {
298
+ const data = yield ddbDocClient.scan({
299
+ TableName: `classifySessionStore.${process.env.DOMAIN}`,
300
+ ProjectionExpression: `sessionId`
301
+ });
302
+ const keys = data.Items ? data.Items.map(i => i.sessionId) : [];
303
+ yield deleteSessionByKeys(keys);
304
+ });
305
+ }
266
306
  }
267
307
  exports.ClassifyServerless = ClassifyServerless;
308
+ function deleteSessionByKeys(keys) {
309
+ return __awaiter(this, void 0, void 0, function* () {
310
+ for (let ix = 0; ix < keys.length; ++ix) {
311
+ yield ddbDocClient.delete({
312
+ TableName: `classifySessionStore.${process.env.DOMAIN}`,
313
+ Key: { sessionId: keys[ix] }
314
+ });
315
+ }
316
+ });
317
+ }
268
318
  function getSessionData(sessionId, interfaceName = "") {
269
319
  return __awaiter(this, void 0, void 0, function* () {
270
320
  if (sessionId) {
@@ -272,7 +322,7 @@ function getSessionData(sessionId, interfaceName = "") {
272
322
  TableName: `classifySessionStore.${process.env.DOMAIN}`,
273
323
  Key: { sessionId },
274
324
  ConsistentRead: true,
275
- ProjectionExpression: `interface_${interfaceName}, connectionId, userId, updated`
325
+ ProjectionExpression: `interface_${interfaceName}, connectionId, userId, updated, expires`
276
326
  });
277
327
  return data.Item;
278
328
  }
@@ -280,10 +330,16 @@ function getSessionData(sessionId, interfaceName = "") {
280
330
  });
281
331
  }
282
332
  exports.getSessionData = getSessionData;
283
- function saveSessionData(sessionId, interfaceName, sessionData, connectionId, userId) {
333
+ function saveSessionData(sessionId, interfaceName, sessionData, connectionId, userId, expirationMinutes) {
284
334
  return __awaiter(this, void 0, void 0, function* () {
285
335
  const updateExpressionComponents = ['updated = :time'];
286
336
  const expressionAttributeValues = { ':time': new Date().getTime() };
337
+ if (typeof expirationMinutes === 'number') {
338
+ const expires = new Date();
339
+ expires.setMinutes(expires.getMinutes() + expirationMinutes);
340
+ updateExpressionComponents.push('expires = :expires');
341
+ expressionAttributeValues[':expires'] = expires.getTime() / 1000;
342
+ }
287
343
  if (sessionData && interfaceName) {
288
344
  updateExpressionComponents.push(`interface_${interfaceName} = :data`);
289
345
  expressionAttributeValues[`:data`] = sessionData;
@@ -4,7 +4,9 @@ export declare class ClassifyServerless {
4
4
  logLevel: Partial<typeof EndPointsLogging>;
5
5
  classDefs: Map<any, ClassDef<any, any>>;
6
6
  requests: Map<any, any>;
7
+ expirationMinutes: number;
7
8
  log: (_message: string) => void;
9
+ setExpirationMinutes(minutes: number): void;
8
10
  setLogger(log: (_message: string) => void): void;
9
11
  setLogLevel(logLevel: Partial<typeof EndPointsLogging>): void;
10
12
  registerResponse<T>(responseClass: new () => T, authorizer?: (_endPoint: T, _method: string, _args: IArguments) => Promise<boolean>): void;
@@ -17,9 +19,12 @@ export declare class ClassifyServerless {
17
19
  createRequestForSession<T>(sessionId: string, requestClass: new () => T): Promise<T>;
18
20
  createResponse<T, R>(responseClass: new () => T, sessionId: string, callback: (_obj: T) => Promise<R>, classes?: any): Promise<R>;
19
21
  getSessionsForUserId(userId: string): Promise<any[]>;
22
+ getSessions(): Promise<any[]>;
23
+ deleteSessionsForUserId(userId: string): Promise<void>;
24
+ deleteSessions(): Promise<void>;
20
25
  }
21
26
  export declare function getSessionData(sessionId: string, interfaceName?: string): Promise<Record<string, any> | undefined>;
22
- export declare function saveSessionData(sessionId: string, interfaceName?: string, sessionData?: string, connectionId?: string, userId?: string): Promise<string>;
27
+ export declare function saveSessionData(sessionId: string, interfaceName?: string, sessionData?: string, connectionId?: string, userId?: string, expirationMinutes?: number): Promise<string>;
23
28
  export declare const EndPointsLogging: {
24
29
  create: boolean;
25
30
  connect: boolean;
@@ -18,8 +18,12 @@ export class ClassifyServerless {
18
18
  this.logLevel = {};
19
19
  this.classDefs = new Map();
20
20
  this.requests = new Map();
21
+ this.expirationMinutes = 60 * 24;
21
22
  this.log = msg => console.log(msg);
22
23
  }
24
+ setExpirationMinutes(minutes) {
25
+ this.expirationMinutes = minutes;
26
+ }
23
27
  setLogger(log) {
24
28
  this.log = log;
25
29
  }
@@ -51,7 +55,7 @@ export class ClassifyServerless {
51
55
  const socketResult = yield getSessionData(sessionId, "");
52
56
  if (!socketResult) {
53
57
  sessionId = context.awsRequestId;
54
- yield saveSessionData(sessionId, undefined, undefined, undefined);
58
+ yield saveSessionData(sessionId, undefined, undefined, undefined, undefined, this.expirationMinutes);
55
59
  }
56
60
  const lambdaResponse = {
57
61
  data: process.env.IS_OFFLINE ? 'ws://localhost:3001' : `wss://${process.env.APIG_ENDPOINT}`,
@@ -103,7 +107,7 @@ export class ClassifyServerless {
103
107
  }
104
108
  const updatedSessionData = serialize(obj, classes);
105
109
  if (!result || updatedSessionData !== result.sessionData)
106
- sessionId = yield saveSessionData(sessionId, request.interfaceName, updatedSessionData, undefined, obj.__userId__);
110
+ sessionId = yield saveSessionData(sessionId, request.interfaceName, updatedSessionData, undefined, obj.__userId__, this.expirationMinutes);
107
111
  // Formulate response
108
112
  const lambdaResponse = {
109
113
  data: fnResponse,
@@ -171,7 +175,7 @@ export class ClassifyServerless {
171
175
  catch (e) {
172
176
  if (expressServer.logLevel.exceptions)
173
177
  expressServer.log(e.message);
174
- throw e;
178
+ throw new Error(`Unable to send message via Websocket ${e.message}`);
175
179
  }
176
180
  });
177
181
  };
@@ -235,10 +239,10 @@ export class ClassifyServerless {
235
239
  this.log(`creating response for ${interfaceName} with sessionId=${sessionId} connectionId= ${obj.__connectionId__} sessionData=${sessionData}`);
236
240
  const ret = yield callback(obj);
237
241
  const updatedSessionData = serialize(obj, classes);
238
- if (updatedSessionData !== result.sessionData) {
242
+ if (updatedSessionData !== result.sessionData || Math.floor(Date.now() / 1000 / 60) !== result.expires / 60) {
239
243
  if (this.logLevel.calls)
240
244
  this.log(`saving session data for ${interfaceName} with sessionId=${sessionId} connectionId= ${obj.__connectionId__} sessionData=${updatedSessionData}`);
241
- yield saveSessionData(sessionId, interfaceName, updatedSessionData, undefined);
245
+ yield saveSessionData(sessionId, interfaceName, updatedSessionData, undefined, undefined, this.expirationMinutes);
242
246
  }
243
247
  return ret;
244
248
  });
@@ -260,6 +264,52 @@ export class ClassifyServerless {
260
264
  return [];
261
265
  });
262
266
  }
267
+ getSessions() {
268
+ return __awaiter(this, void 0, void 0, function* () {
269
+ const data = yield ddbDocClient.scan({
270
+ TableName: `classifySessionStore.${process.env.DOMAIN}`,
271
+ ProjectionExpression: `sessionId`
272
+ });
273
+ return data.Items ? data.Items.map(i => i.sessionId) : [];
274
+ });
275
+ }
276
+ deleteSessionsForUserId(userId) {
277
+ return __awaiter(this, void 0, void 0, function* () {
278
+ if (userId) {
279
+ const data = yield ddbDocClient.query({
280
+ TableName: `classifySessionStore.${process.env.DOMAIN}`,
281
+ KeyConditionExpression: 'userId = :userId',
282
+ IndexName: 'userId',
283
+ ExpressionAttributeValues: {
284
+ ':userId': userId,
285
+ },
286
+ ProjectionExpression: `sessionId`
287
+ });
288
+ const keys = data.Items ? data.Items.map(i => i.sessionId) : [];
289
+ yield deleteSessionByKeys(keys);
290
+ }
291
+ });
292
+ }
293
+ deleteSessions() {
294
+ return __awaiter(this, void 0, void 0, function* () {
295
+ const data = yield ddbDocClient.scan({
296
+ TableName: `classifySessionStore.${process.env.DOMAIN}`,
297
+ ProjectionExpression: `sessionId`
298
+ });
299
+ const keys = data.Items ? data.Items.map(i => i.sessionId) : [];
300
+ yield deleteSessionByKeys(keys);
301
+ });
302
+ }
303
+ }
304
+ function deleteSessionByKeys(keys) {
305
+ return __awaiter(this, void 0, void 0, function* () {
306
+ for (let ix = 0; ix < keys.length; ++ix) {
307
+ yield ddbDocClient.delete({
308
+ TableName: `classifySessionStore.${process.env.DOMAIN}`,
309
+ Key: { sessionId: keys[ix] }
310
+ });
311
+ }
312
+ });
263
313
  }
264
314
  export function getSessionData(sessionId, interfaceName = "") {
265
315
  return __awaiter(this, void 0, void 0, function* () {
@@ -268,17 +318,23 @@ export function getSessionData(sessionId, interfaceName = "") {
268
318
  TableName: `classifySessionStore.${process.env.DOMAIN}`,
269
319
  Key: { sessionId },
270
320
  ConsistentRead: true,
271
- ProjectionExpression: `interface_${interfaceName}, connectionId, userId, updated`
321
+ ProjectionExpression: `interface_${interfaceName}, connectionId, userId, updated, expires`
272
322
  });
273
323
  return data.Item;
274
324
  }
275
325
  return undefined;
276
326
  });
277
327
  }
278
- export function saveSessionData(sessionId, interfaceName, sessionData, connectionId, userId) {
328
+ export function saveSessionData(sessionId, interfaceName, sessionData, connectionId, userId, expirationMinutes) {
279
329
  return __awaiter(this, void 0, void 0, function* () {
280
330
  const updateExpressionComponents = ['updated = :time'];
281
331
  const expressionAttributeValues = { ':time': new Date().getTime() };
332
+ if (typeof expirationMinutes === 'number') {
333
+ const expires = new Date();
334
+ expires.setMinutes(expires.getMinutes() + expirationMinutes);
335
+ updateExpressionComponents.push('expires = :expires');
336
+ expressionAttributeValues[':expires'] = expires.getTime() / 1000;
337
+ }
282
338
  if (sessionData && interfaceName) {
283
339
  updateExpressionComponents.push(`interface_${interfaceName} = :data`);
284
340
  expressionAttributeValues[`:data`] = sessionData;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aws-classify-server",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "main": "./lib/cjs/index.js",
5
5
  "module": "./lib/esm/index.js",
6
6
  "types": "./lib/esm/index.d.ts",
@@ -21,4 +21,6 @@ Resources:
21
21
  - AttributeName: userId
22
22
  KeyType: HASH
23
23
  Projection:
24
- ProjectionType: KEYS_ONLY
24
+ ProjectionType: KEYS_ONLY
25
+ StreamSpecification:
26
+ StreamViewType: ${self:custom.SessionStreamViewType, 'NEW_IMAGE'}