@digitraffic/common 2023.5.10-1 → 2023.5.25-1

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.
@@ -12,7 +12,7 @@ import { IModel } from "aws-cdk-lib/aws-apigateway/lib/model";
12
12
  * If fileName is set, then Content-Disposition-header will be set to use it
13
13
  * If timestamp is set, then ETag & Last-Modified headers will be set
14
14
  */
15
- export declare const RESPONSE_DEFAULT_LAMBDA = "#set($inputRoot = $input.path('$'))\n#if ($inputRoot.status != 200)\n#set ($context.responseOverride.status = $inputRoot.status)\n#set ($context.responseOverride.header.Content-Type = 'text/plain')\n#end\n#set ($context.responseOverride.header.Access-Control-Allow-Origin = '*')\n#if (\"$!inputRoot.timestamp\" != \"\")\n#set ($context.responseOverride.header.ETag = $inputRoot.timestamp)\n#set ($context.responseOverride.header.Last-Modified = $inputRoot.timestamp)\n#end\n#if (\"$!inputRoot.fileName\" != \"\")\n#set ($disposition = 'attachment; filename=\"FN\"')\n#set ($context.responseOverride.header.Content-Disposition = $disposition.replaceAll('FN', $inputRoot.fileName))\n#end\n$util.base64Decode($inputRoot.body)";
15
+ export declare const RESPONSE_DEFAULT_LAMBDA = "#set($inputRoot = $input.path('$'))\n#if ($inputRoot.status != 200)\n#set ($context.responseOverride.status = $inputRoot.status)\n#set ($context.responseOverride.header.Content-Type = 'text/plain')\n#end\n#set ($context.responseOverride.header.Access-Control-Allow-Origin = '*')\n#if (\"$!inputRoot.timestamp\" != \"\")\n#set ($context.responseOverride.header.Last-Modified = $inputRoot.timestamp)\n#end\n#if (\"$!inputRoot.etag\" != \"\")\n#set ($context.responseOverride.header.ETag = $inputRoot.etag)\n#end\n#if (\"$!inputRoot.fileName\" != \"\")\n#set ($disposition = 'attachment; filename=\"FN\"')\n#set ($context.responseOverride.header.Content-Disposition = $disposition.replaceAll('FN', $inputRoot.fileName))\n#end\n$util.base64Decode($inputRoot.body)";
16
16
  /**
17
17
  * Use this for deprecated integrations.
18
18
  * Will add HTTP headers Deprecation and Sunset to response.
@@ -22,9 +22,11 @@ exports.RESPONSE_DEFAULT_LAMBDA = `#set($inputRoot = $input.path('$'))
22
22
  #end
23
23
  #set ($context.responseOverride.header.Access-Control-Allow-Origin = '*')
24
24
  #if ("$!inputRoot.timestamp" != "")
25
- #set ($context.responseOverride.header.ETag = $inputRoot.timestamp)
26
25
  #set ($context.responseOverride.header.Last-Modified = $inputRoot.timestamp)
27
26
  #end
27
+ #if ("$!inputRoot.etag" != "")
28
+ #set ($context.responseOverride.header.ETag = $inputRoot.etag)
29
+ #end
28
30
  #if ("$!inputRoot.fileName" != "")
29
31
  #set ($disposition = 'attachment; filename="FN"')
30
32
  #set ($context.responseOverride.header.Content-Disposition = $disposition.replaceAll('FN', $inputRoot.fileName))
@@ -3,6 +3,7 @@ export declare class LambdaResponse {
3
3
  readonly body: string;
4
4
  readonly fileName?: string;
5
5
  readonly timestamp?: string;
6
+ readonly etag: string;
6
7
  constructor(status: number, body: string, fileName?: string, timestamp?: Date);
7
8
  withTimestamp(timestamp: Date): LambdaResponse;
8
9
  /**
@@ -1,12 +1,17 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.LambdaResponse = void 0;
7
+ const etag_1 = __importDefault(require("etag"));
4
8
  class LambdaResponse {
5
9
  constructor(status, body, fileName, timestamp) {
6
10
  this.status = status;
7
11
  this.body = body;
8
12
  this.fileName = fileName;
9
13
  this.timestamp = timestamp?.toUTCString();
14
+ this.etag = (0, etag_1.default)(body); // create strong etag by default
10
15
  }
11
16
  withTimestamp(timestamp) {
12
17
  return new LambdaResponse(this.status, this.body, this.fileName, timestamp);
@@ -2,11 +2,19 @@ import { DTDatabase, DTTransaction } from "./database";
2
2
  export interface CachedValue<T> {
3
3
  content: T;
4
4
  last_updated: Date;
5
+ modified: Date;
5
6
  }
6
7
  export declare enum JSON_CACHE_KEY {
7
8
  NAUTICAL_WARNINGS_ACTIVE = "nautical-warnings-active",
8
9
  NAUTICAL_WARNINGS_ARCHIVED = "nautical-warnings-archived"
9
10
  }
10
- export declare function updateCachedJson<T>(db: DTDatabase | DTTransaction, cacheKey: JSON_CACHE_KEY, value: T): Promise<null>;
11
- export declare function getJsonFromCache<T>(db: DTDatabase | DTTransaction, cacheKey: JSON_CACHE_KEY): Promise<T | null>;
12
- export declare function getFromCache<T>(db: DTDatabase | DTTransaction, cacheKey: JSON_CACHE_KEY): Promise<CachedValue<T> | null>;
11
+ /**
12
+ *
13
+ * @param db
14
+ * @param cacheKey
15
+ * @param value
16
+ * @param lastUpdated time when data was created or updated
17
+ */
18
+ export declare function updateCachedJson<T>(db: DTDatabase | DTTransaction, cacheKey: JSON_CACHE_KEY, value: T, lastUpdated: Date): Promise<void>;
19
+ export declare function getJsonFromCache<T>(db: DTDatabase | DTTransaction, cacheKey: JSON_CACHE_KEY): Promise<T | undefined>;
20
+ export declare function getFromCache<T>(db: DTDatabase | DTTransaction, cacheKey: JSON_CACHE_KEY): Promise<CachedValue<T> | undefined>;
@@ -2,37 +2,45 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getFromCache = exports.getJsonFromCache = exports.updateCachedJson = exports.JSON_CACHE_KEY = void 0;
4
4
  const pg_promise_1 = require("pg-promise");
5
- const SQL_UPDATE_CACHE_VALUE = `insert into cached_json(cache_id, content, last_updated)
6
- values ($1, $2, now())
7
- on conflict(cache_id) do
8
- update set content = $2, last_updated = now()`;
9
- const SQL_GET_CACHE_VALUE = `select content, last_updated from cached_json
10
- where cache_id = $1`;
11
5
  const PS_UPDATE_CACHE_VALUE = new pg_promise_1.PreparedStatement({
12
6
  name: "update-cache-value",
13
- text: SQL_UPDATE_CACHE_VALUE,
7
+ text: `insert into cached_json(cache_id, content, last_updated)
8
+ values ($1, $2, $3)
9
+ on conflict(cache_id) do
10
+ update set content = $2, last_updated = $3`,
14
11
  });
15
12
  const PS_GET_CACHE_VALUE = new pg_promise_1.PreparedStatement({
16
13
  name: "get-cache-value",
17
- text: SQL_GET_CACHE_VALUE,
14
+ text: "select content, last_updated, modified from cached_json where cache_id = $1",
18
15
  });
19
16
  var JSON_CACHE_KEY;
20
17
  (function (JSON_CACHE_KEY) {
21
18
  JSON_CACHE_KEY["NAUTICAL_WARNINGS_ACTIVE"] = "nautical-warnings-active";
22
19
  JSON_CACHE_KEY["NAUTICAL_WARNINGS_ARCHIVED"] = "nautical-warnings-archived";
23
20
  })(JSON_CACHE_KEY = exports.JSON_CACHE_KEY || (exports.JSON_CACHE_KEY = {}));
24
- function updateCachedJson(db, cacheKey, value) {
25
- return db.none(PS_UPDATE_CACHE_VALUE, [cacheKey, value]);
21
+ /**
22
+ *
23
+ * @param db
24
+ * @param cacheKey
25
+ * @param value
26
+ * @param lastUpdated time when data was created or updated
27
+ */
28
+ async function updateCachedJson(db, cacheKey, value, lastUpdated) {
29
+ await db.none(PS_UPDATE_CACHE_VALUE, [cacheKey, value, lastUpdated]);
26
30
  }
27
31
  exports.updateCachedJson = updateCachedJson;
28
32
  function getJsonFromCache(db, cacheKey) {
29
33
  return db
30
34
  .oneOrNone(PS_GET_CACHE_VALUE, [cacheKey])
31
- .then((value) => value?.content ?? null);
35
+ .then((value) => value?.content ?? undefined);
32
36
  }
33
37
  exports.getJsonFromCache = getJsonFromCache;
34
- function getFromCache(db, cacheKey) {
35
- return db.oneOrNone(PS_GET_CACHE_VALUE, [cacheKey]);
38
+ async function getFromCache(db, cacheKey) {
39
+ return db
40
+ .oneOrNone(PS_GET_CACHE_VALUE, [cacheKey])
41
+ .then((result) => {
42
+ return result ?? undefined;
43
+ });
36
44
  }
37
45
  exports.getFromCache = getFromCache;
38
46
  //# sourceMappingURL=cached.js.map
@@ -1,3 +1,6 @@
1
+ /**
2
+ * Constant for the 1970-01-01T00:00:00Z epoch Date.
3
+ */
1
4
  export declare const EPOCH: Date;
2
5
  /**
3
6
  * Counts difference in milliseconds between dates.
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.dateFromIsoString = exports.countDiffInSeconds = exports.countDiffMs = exports.EPOCH = void 0;
4
+ /**
5
+ * Constant for the 1970-01-01T00:00:00Z epoch Date.
6
+ */
4
7
  exports.EPOCH = new Date(Date.UTC(1970, 0, 1));
5
8
  /**
6
9
  * Counts difference in milliseconds between dates.
@@ -26,10 +29,13 @@ exports.countDiffInSeconds = countDiffInSeconds;
26
29
  */
27
30
  function dateFromIsoString(isoString) {
28
31
  const parsed = new Date(isoString);
29
- if (!(parsed instanceof Date) || isNaN(parsed.getTime())) {
30
- throw new Error(`Invalid ISO-DATE -string: ${isoString}`);
32
+ if (!isValidDate(parsed)) {
33
+ throw new Error(`Could not parse iso date-time string: "${isoString}" to date`);
31
34
  }
32
35
  return parsed;
33
36
  }
34
37
  exports.dateFromIsoString = dateFromIsoString;
38
+ function isValidDate(d) {
39
+ return d instanceof Date && !isNaN(d.getTime());
40
+ }
35
41
  //# sourceMappingURL=date-utils.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digitraffic/common",
3
- "version": "2023.5.10-1",
3
+ "version": "2023.5.25-1",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
@@ -24,6 +24,7 @@
24
24
  "axios": "^1.2.6",
25
25
  "change-case": "^4.1.2",
26
26
  "constructs": "^10.2.17",
27
+ "etag": "^1.8.1",
27
28
  "geojson-validation": "^1.0.2",
28
29
  "moment": "^2.29.4",
29
30
  "node-ttl": "^0.2.0",
@@ -34,6 +35,7 @@
34
35
  "@aws-cdk/aws-synthetics-alpha": "2.78.0-alpha.0",
35
36
  "@types/aws-lambda": "~8.10.115",
36
37
  "@types/geojson": "^7946.0.10",
38
+ "@types/etag": "^1.8.1",
37
39
  "@types/jest": "^29.5.1",
38
40
  "@types/lodash": "^4.14.194",
39
41
  "@types/node": "18.15.13",
@@ -27,9 +27,11 @@ export const RESPONSE_DEFAULT_LAMBDA = `#set($inputRoot = $input.path('$'))
27
27
  #end
28
28
  #set ($context.responseOverride.header.Access-Control-Allow-Origin = '*')
29
29
  #if ("$!inputRoot.timestamp" != "")
30
- #set ($context.responseOverride.header.ETag = $inputRoot.timestamp)
31
30
  #set ($context.responseOverride.header.Last-Modified = $inputRoot.timestamp)
32
31
  #end
32
+ #if ("$!inputRoot.etag" != "")
33
+ #set ($context.responseOverride.header.ETag = $inputRoot.etag)
34
+ #end
33
35
  #if ("$!inputRoot.fileName" != "")
34
36
  #set ($disposition = 'attachment; filename="FN"')
35
37
  #set ($context.responseOverride.header.Content-Disposition = $disposition.replaceAll('FN', $inputRoot.fileName))
@@ -1,8 +1,11 @@
1
+ import etag from "etag";
2
+
1
3
  export class LambdaResponse {
2
4
  readonly status: number;
3
5
  readonly body: string;
4
6
  readonly fileName?: string;
5
7
  readonly timestamp?: string;
8
+ readonly etag: string;
6
9
 
7
10
  constructor(
8
11
  status: number,
@@ -14,6 +17,7 @@ export class LambdaResponse {
14
17
  this.body = body;
15
18
  this.fileName = fileName;
16
19
  this.timestamp = timestamp?.toUTCString();
20
+ this.etag = etag(body); // create strong etag by default
17
21
  }
18
22
 
19
23
  withTimestamp(timestamp: Date) {
@@ -4,24 +4,20 @@ import { DTDatabase, DTTransaction } from "./database";
4
4
  export interface CachedValue<T> {
5
5
  content: T;
6
6
  last_updated: Date;
7
+ modified: Date;
7
8
  }
8
9
 
9
- const SQL_UPDATE_CACHE_VALUE = `insert into cached_json(cache_id, content, last_updated)
10
- values ($1, $2, now())
11
- on conflict(cache_id) do
12
- update set content = $2, last_updated = now()`;
13
-
14
- const SQL_GET_CACHE_VALUE = `select content, last_updated from cached_json
15
- where cache_id = $1`;
16
-
17
10
  const PS_UPDATE_CACHE_VALUE = new PreparedStatement({
18
11
  name: "update-cache-value",
19
- text: SQL_UPDATE_CACHE_VALUE,
12
+ text: `insert into cached_json(cache_id, content, last_updated)
13
+ values ($1, $2, $3)
14
+ on conflict(cache_id) do
15
+ update set content = $2, last_updated = $3`,
20
16
  });
21
17
 
22
18
  const PS_GET_CACHE_VALUE = new PreparedStatement({
23
19
  name: "get-cache-value",
24
- text: SQL_GET_CACHE_VALUE,
20
+ text: "select content, last_updated, modified from cached_json where cache_id = $1",
25
21
  });
26
22
 
27
23
  export enum JSON_CACHE_KEY {
@@ -29,26 +25,38 @@ export enum JSON_CACHE_KEY {
29
25
  NAUTICAL_WARNINGS_ARCHIVED = "nautical-warnings-archived",
30
26
  }
31
27
 
32
- export function updateCachedJson<T>(
28
+ /**
29
+ *
30
+ * @param db
31
+ * @param cacheKey
32
+ * @param value
33
+ * @param lastUpdated time when data was created or updated
34
+ */
35
+ export async function updateCachedJson<T>(
33
36
  db: DTDatabase | DTTransaction,
34
37
  cacheKey: JSON_CACHE_KEY,
35
- value: T
36
- ): Promise<null> {
37
- return db.none(PS_UPDATE_CACHE_VALUE, [cacheKey, value]);
38
+ value: T,
39
+ lastUpdated: Date
40
+ ): Promise<void> {
41
+ await db.none(PS_UPDATE_CACHE_VALUE, [cacheKey, value, lastUpdated]);
38
42
  }
39
43
 
40
44
  export function getJsonFromCache<T>(
41
45
  db: DTDatabase | DTTransaction,
42
46
  cacheKey: JSON_CACHE_KEY
43
- ): Promise<T | null> {
47
+ ): Promise<T | undefined> {
44
48
  return db
45
49
  .oneOrNone<CachedValue<T>>(PS_GET_CACHE_VALUE, [cacheKey])
46
- .then((value) => value?.content ?? null);
50
+ .then((value) => value?.content ?? undefined);
47
51
  }
48
52
 
49
- export function getFromCache<T>(
53
+ export async function getFromCache<T>(
50
54
  db: DTDatabase | DTTransaction,
51
55
  cacheKey: JSON_CACHE_KEY
52
- ): Promise<CachedValue<T> | null> {
53
- return db.oneOrNone<CachedValue<T>>(PS_GET_CACHE_VALUE, [cacheKey]);
56
+ ): Promise<CachedValue<T> | undefined> {
57
+ return db
58
+ .oneOrNone<CachedValue<T>>(PS_GET_CACHE_VALUE, [cacheKey])
59
+ .then((result) => {
60
+ return result ?? undefined;
61
+ });
54
62
  }
@@ -1,4 +1,8 @@
1
+ /**
2
+ * Constant for the 1970-01-01T00:00:00Z epoch Date.
3
+ */
1
4
  export const EPOCH = new Date(Date.UTC(1970, 0, 1));
5
+
2
6
  /**
3
7
  * Counts difference in milliseconds between dates.
4
8
  * @param start
@@ -23,8 +27,14 @@ export function countDiffInSeconds(start: Date, end: Date): number {
23
27
  */
24
28
  export function dateFromIsoString(isoString: string): Date {
25
29
  const parsed = new Date(isoString);
26
- if (!(parsed instanceof Date) || isNaN(parsed.getTime())) {
27
- throw new Error(`Invalid ISO-DATE -string: ${isoString}`);
30
+ if (!isValidDate(parsed)) {
31
+ throw new Error(
32
+ `Could not parse iso date-time string: "${isoString}" to date`
33
+ );
28
34
  }
29
35
  return parsed;
30
36
  }
37
+
38
+ function isValidDate(d: any) {
39
+ return d instanceof Date && !isNaN(d.getTime());
40
+ }