@aspan-corporation/ac-shared 1.2.35 → 1.2.37
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/lib/lambda/index.js +5 -1
- package/lib/services/sts.d.ts +7 -2
- package/lib/services/sts.js +42 -1
- package/lib/utils/diary.d.ts +8 -0
- package/lib/utils/diary.js +12 -3
- package/package.json +6 -3
package/lib/lambda/index.js
CHANGED
|
@@ -14,7 +14,11 @@ export { MetricUnit } from "@aws-lambda-powertools/metrics";
|
|
|
14
14
|
export const tracer = new Tracer();
|
|
15
15
|
export const metrics = new Metrics({ namespace: "aspan-corporation" });
|
|
16
16
|
export const withMiddlewares = (handler) => middy(handler)
|
|
17
|
-
|
|
17
|
+
// logEvent is deliberately false: several handlers are fronted by API
|
|
18
|
+
// Gateway, whose proxy event carries the caller's `Authorization` header
|
|
19
|
+
// (a live Cognito token). Logging the full event would persist those
|
|
20
|
+
// tokens to CloudWatch. Handlers log the specific fields they need.
|
|
21
|
+
.use(injectLambdaContext(logger, { logEvent: false }))
|
|
18
22
|
.use(captureLambdaHandler(tracer))
|
|
19
23
|
.use(logMetrics(metrics, { captureColdStartMetric: true }))
|
|
20
24
|
.use({
|
package/lib/services/sts.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { Logger } from "@aws-lambda-powertools/logger";
|
|
2
|
-
import { AssumeRoleCommandInput, STSClient } from "@aws-sdk/client-sts";
|
|
2
|
+
import { AssumeRoleCommandInput, AssumeRoleCommandOutput, STSClient } from "@aws-sdk/client-sts";
|
|
3
|
+
/**
|
|
4
|
+
* Clear the module-scoped assume-role credential cache. Intended for tests
|
|
5
|
+
* only, so each case starts from a known state.
|
|
6
|
+
*/
|
|
7
|
+
export declare const clearAssumeRoleCache: () => void;
|
|
3
8
|
export declare class STSService {
|
|
4
9
|
logger: Logger;
|
|
5
10
|
client: STSClient;
|
|
@@ -9,6 +14,6 @@ export declare class STSService {
|
|
|
9
14
|
client?: STSClient;
|
|
10
15
|
});
|
|
11
16
|
getCallerIdentity(): Promise<import("@aws-sdk/client-sts").GetCallerIdentityCommandOutput>;
|
|
12
|
-
assumeRole(assumeRoleCommandInput: AssumeRoleCommandInput): Promise<
|
|
17
|
+
assumeRole(assumeRoleCommandInput: AssumeRoleCommandInput): Promise<AssumeRoleCommandOutput>;
|
|
13
18
|
}
|
|
14
19
|
export type { AssumeRoleCommandInput, AssumeRoleCommandOutput } from "@aws-sdk/client-sts";
|
package/lib/services/sts.js
CHANGED
|
@@ -1,6 +1,34 @@
|
|
|
1
1
|
import { Logger } from "@aws-lambda-powertools/logger";
|
|
2
2
|
import { AssumeRoleCommand, GetCallerIdentityCommand, STSClient } from "@aws-sdk/client-sts";
|
|
3
3
|
import assert from "node:assert/strict";
|
|
4
|
+
// Module-scoped cache of assumed-role credentials, shared across every
|
|
5
|
+
// STSService instance in the same execution environment. Lambda handlers
|
|
6
|
+
// construct a fresh STSService per invocation (usually in a middy `before`
|
|
7
|
+
// hook), so an instance-level cache would never hit. Keying at module scope
|
|
8
|
+
// means a warm container assumes the role once and reuses the credentials
|
|
9
|
+
// until they are close to expiry, removing an STS round-trip (~50-150ms) from
|
|
10
|
+
// every invocation.
|
|
11
|
+
const REFRESH_BUFFER_MS = 5 * 60 * 1000;
|
|
12
|
+
const credentialCache = new Map();
|
|
13
|
+
const cacheKey = (input) => [
|
|
14
|
+
input.RoleArn,
|
|
15
|
+
input.RoleSessionName,
|
|
16
|
+
input.ExternalId ?? "",
|
|
17
|
+
input.DurationSeconds ?? "",
|
|
18
|
+
input.SerialNumber ?? ""
|
|
19
|
+
].join("|");
|
|
20
|
+
const isFresh = (output) => {
|
|
21
|
+
const expiration = output.Credentials?.Expiration;
|
|
22
|
+
return (expiration instanceof Date &&
|
|
23
|
+
expiration.getTime() - REFRESH_BUFFER_MS > Date.now());
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Clear the module-scoped assume-role credential cache. Intended for tests
|
|
27
|
+
* only, so each case starts from a known state.
|
|
28
|
+
*/
|
|
29
|
+
export const clearAssumeRoleCache = () => {
|
|
30
|
+
credentialCache.clear();
|
|
31
|
+
};
|
|
4
32
|
export class STSService {
|
|
5
33
|
logger;
|
|
6
34
|
client;
|
|
@@ -27,7 +55,20 @@ export class STSService {
|
|
|
27
55
|
return await this.client.send(new GetCallerIdentityCommand({}));
|
|
28
56
|
}
|
|
29
57
|
async assumeRole(assumeRoleCommandInput) {
|
|
58
|
+
const key = cacheKey(assumeRoleCommandInput);
|
|
59
|
+
const cached = credentialCache.get(key);
|
|
60
|
+
if (cached && isFresh(cached)) {
|
|
61
|
+
this.logger.debug("assumeRole cache hit", {
|
|
62
|
+
roleArn: assumeRoleCommandInput.RoleArn
|
|
63
|
+
});
|
|
64
|
+
return cached;
|
|
65
|
+
}
|
|
30
66
|
this.logger.debug("assumeRole", { assumeRoleCommandInput });
|
|
31
|
-
|
|
67
|
+
const output = await this.client.send(new AssumeRoleCommand(assumeRoleCommandInput));
|
|
68
|
+
// Only cache credentials that carry an expiry we can reason about.
|
|
69
|
+
if (output.Credentials?.Expiration) {
|
|
70
|
+
credentialCache.set(key, output);
|
|
71
|
+
}
|
|
72
|
+
return output;
|
|
32
73
|
}
|
|
33
74
|
}
|
package/lib/utils/diary.d.ts
CHANGED
|
@@ -49,6 +49,14 @@ export declare const parseDiaryKeyDate: (key: string) => {
|
|
|
49
49
|
* words. Strips markdown syntax (code fences, image/link targets, formatting),
|
|
50
50
|
* drops stop-words and tokens shorter than 2 chars, and caps the result at
|
|
51
51
|
* `MAX_TEXT_TOKENS` to bound the meta-item size. No stemming (exact-word match).
|
|
52
|
+
*
|
|
53
|
+
* Word boundaries and lowercasing are Unicode-aware: tokens are split on any
|
|
54
|
+
* run of characters that are neither a Unicode letter (`\p{L}`) nor number
|
|
55
|
+
* (`\p{N}`), so non-Latin scripts (e.g. Cyrillic) survive as searchable words
|
|
56
|
+
* rather than being discarded. `toLowerCase()` is likewise Unicode-aware; we
|
|
57
|
+
* deliberately avoid `toLocaleLowerCase()` so tokenisation is deterministic and
|
|
58
|
+
* independent of the host locale (the indexer lambda and the browser that
|
|
59
|
+
* builds search queries must produce identical tokens).
|
|
52
60
|
*/
|
|
53
61
|
export declare const tokenizeText: (markdown: string) => string[];
|
|
54
62
|
/** Plain-text preview: strip markdown, collapse whitespace, truncate. */
|
package/lib/utils/diary.js
CHANGED
|
@@ -91,6 +91,14 @@ const STOP_WORDS = new Set([
|
|
|
91
91
|
* words. Strips markdown syntax (code fences, image/link targets, formatting),
|
|
92
92
|
* drops stop-words and tokens shorter than 2 chars, and caps the result at
|
|
93
93
|
* `MAX_TEXT_TOKENS` to bound the meta-item size. No stemming (exact-word match).
|
|
94
|
+
*
|
|
95
|
+
* Word boundaries and lowercasing are Unicode-aware: tokens are split on any
|
|
96
|
+
* run of characters that are neither a Unicode letter (`\p{L}`) nor number
|
|
97
|
+
* (`\p{N}`), so non-Latin scripts (e.g. Cyrillic) survive as searchable words
|
|
98
|
+
* rather than being discarded. `toLowerCase()` is likewise Unicode-aware; we
|
|
99
|
+
* deliberately avoid `toLocaleLowerCase()` so tokenisation is deterministic and
|
|
100
|
+
* independent of the host locale (the indexer lambda and the browser that
|
|
101
|
+
* builds search queries must produce identical tokens).
|
|
94
102
|
*/
|
|
95
103
|
export const tokenizeText = (markdown) => {
|
|
96
104
|
if (!markdown)
|
|
@@ -109,11 +117,12 @@ export const tokenizeText = (markdown) => {
|
|
|
109
117
|
// leftover markdown punctuation
|
|
110
118
|
.replace(/[#>*_~\-]+/g, " ");
|
|
111
119
|
const seen = new Set();
|
|
112
|
-
for (const raw of stripped.toLowerCase().split(/[
|
|
120
|
+
for (const raw of stripped.toLowerCase().split(/[^\p{L}\p{N}]+/u)) {
|
|
113
121
|
if (raw.length < 2)
|
|
114
122
|
continue;
|
|
115
|
-
// Drop pure
|
|
116
|
-
|
|
123
|
+
// Drop pure-number tokens (dates/counts add noise) in any script; keep
|
|
124
|
+
// alphanumerics like "v2".
|
|
125
|
+
if (/^\p{N}+$/u.test(raw))
|
|
117
126
|
continue;
|
|
118
127
|
if (STOP_WORDS.has(raw))
|
|
119
128
|
continue;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aspan-corporation/ac-shared",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.37",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"exports": {
|
|
@@ -36,12 +36,15 @@
|
|
|
36
36
|
"clean": "rm -rf lib",
|
|
37
37
|
"build": "npm run clean && npm run build:code && npm run build:types",
|
|
38
38
|
"build:code": "tsc --declaration false --emitDeclarationOnly false",
|
|
39
|
-
"build:types": "tsc --emitDeclarationOnly --declaration"
|
|
39
|
+
"build:types": "tsc --emitDeclarationOnly --declaration",
|
|
40
|
+
"test": "vitest run",
|
|
41
|
+
"test:watch": "vitest"
|
|
40
42
|
},
|
|
41
43
|
"devDependencies": {
|
|
42
44
|
"@types/aws-lambda": "^8.10.137",
|
|
43
45
|
"@types/node": "^20.12.5",
|
|
44
|
-
"typescript": "^5.4.4"
|
|
46
|
+
"typescript": "^5.4.4",
|
|
47
|
+
"vitest": "^4.1.9"
|
|
45
48
|
},
|
|
46
49
|
"dependencies": {
|
|
47
50
|
"@aws-lambda-powertools/batch": "^2.30.2",
|