@ya-accelerators/web-backend-framework 0.0.100 → 0.0.102
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/@types/express.d.ts +0 -4
- package/dist/connector/google-auth/index.js +0 -30
- package/dist/connector/google-auth/index.js.map +1 -1
- package/dist/constants.d.ts +9 -0
- package/dist/constants.js +73 -4
- package/dist/constants.js.map +1 -1
- package/dist/context/audit/index.js.map +1 -1
- package/dist/context/request/index.js +0 -15
- package/dist/context/request/index.js.map +1 -1
- package/dist/coordination/lock/index.d.ts +0 -8
- package/dist/coordination/lock/index.js +0 -29
- package/dist/coordination/lock/index.js.map +1 -1
- package/dist/coordination/rate-limit/index.d.ts +0 -5
- package/dist/coordination/rate-limit/index.js +0 -23
- package/dist/coordination/rate-limit/index.js.map +1 -1
- package/dist/coordination/throttle/index.d.ts +0 -13
- package/dist/coordination/throttle/index.js +0 -13
- package/dist/coordination/throttle/index.js.map +1 -1
- package/dist/env.d.ts +1 -1
- package/dist/env.js +5 -15
- package/dist/env.js.map +1 -1
- package/dist/internal/federation/index.d.ts +1 -1
- package/dist/internal/federation/index.js +0 -20
- package/dist/internal/federation/index.js.map +1 -1
- package/dist/logger/index.js +0 -18
- package/dist/logger/index.js.map +1 -1
- package/dist/repository/prisma/index.js +5 -7
- package/dist/repository/prisma/index.js.map +1 -1
- package/dist/repository/prisma/lifecycle.js +1 -28
- package/dist/repository/prisma/lifecycle.js.map +1 -1
- package/dist/repository/prisma/rds-log-record.d.ts +10 -0
- package/dist/repository/prisma/rds-log-record.js +20 -0
- package/dist/repository/prisma/rds-log-record.js.map +1 -0
- package/dist/repository/redis/index.js +0 -4
- package/dist/repository/redis/index.js.map +1 -1
- package/dist/repository/s3/index.js +1 -25
- package/dist/repository/s3/index.js.map +1 -1
- package/dist/server/express/index.js +20 -52
- package/dist/server/express/index.js.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/trpc/declaration/index.d.ts +38 -0
- package/dist/server/trpc/declaration/index.js +2 -0
- package/dist/server/trpc/declaration/index.js.map +1 -0
- package/dist/server/trpc/index.d.ts +10 -9
- package/dist/server/trpc/index.js +12 -28
- package/dist/server/trpc/index.js.map +1 -1
- package/dist/server/trpc/schema/index.js +0 -10
- package/dist/server/trpc/schema/index.js.map +1 -1
- package/dist/server/uploads/index.js +12 -12
- package/dist/server/uploads/index.js.map +1 -1
- package/dist/util/index.js +87 -96
- package/dist/util/index.js.map +1 -1
- package/package.json +13 -9
package/@types/express.d.ts
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
// Captures the raw request body for handlers that need to verify a signature
|
|
2
|
-
// against the original bytes (e.g. Stripe webhooks) — the parsed `req.body`
|
|
3
|
-
// would not survive signature verification because JSON.stringify is not
|
|
4
|
-
// guaranteed to reproduce the exact byte sequence the sender signed.
|
|
5
1
|
declare global {
|
|
6
2
|
namespace Express {
|
|
7
3
|
interface Request {
|
|
@@ -1,24 +1,11 @@
|
|
|
1
1
|
import { runWithRequestHeaders } from '../../context/request/index.js';
|
|
2
2
|
import { awsSecurityCredentialsSupplier, impersonatedClient, parseWifConfig } from '../../internal/federation/index.js';
|
|
3
3
|
import { logger } from '../../logger/index.js';
|
|
4
|
-
// AWS → Google Workload Identity Federation auth primitives. All three federate the running AWS identity
|
|
5
|
-
// into a Google Workload Identity Pool and impersonate the configured service account; they differ only in
|
|
6
|
-
// the token they mint. The framework owns all `google-auth-library` usage — consumers pass their own base64
|
|
7
|
-
// WIF cred config (holds no credential — points at the pool / provider / SA, read from the consumer's own
|
|
8
|
-
// env proxy) and never import `google-auth-library` themselves. `google-auth-library` is dynamically
|
|
9
|
-
// imported so a service that never calls Google does not load it. AWS credentials resolve through the AWS
|
|
10
|
-
// SDK chain via the shared Fargate-safe supplier (`internal/federation`), so federation works on ECS
|
|
11
|
-
// Fargate (task-role creds at the container credential endpoint), which the library's built-in AWS source
|
|
12
|
-
// (env → IMDS only) does not reach; `AWS_REGION` supplies the signature region.
|
|
13
4
|
const ID_TOKEN_TTL_SEC = 3600;
|
|
14
5
|
const REFRESH_SKEW_MS = 5 * 60 * 1000;
|
|
15
|
-
// Access-token auth for calling any Google Cloud API (Vertex AI / Gemini, Storage, …). The consumer hands
|
|
16
|
-
// authClient() to whichever Google SDK it uses (e.g. @google/genai `googleAuthOptions`), or reads bearer()
|
|
17
|
-
// directly. SA impersonation is performed by the AwsClient itself via service_account_impersonation_url.
|
|
18
6
|
export const googleCloudAuth = (wifConfigBase64) => {
|
|
19
7
|
let client;
|
|
20
8
|
let inflight;
|
|
21
|
-
// Built once per instance and reused — the client owns access-token acquisition, caching, and refresh.
|
|
22
9
|
const authClient = async () => {
|
|
23
10
|
if (client !== undefined) {
|
|
24
11
|
return client;
|
|
@@ -26,10 +13,6 @@ export const googleCloudAuth = (wifConfigBase64) => {
|
|
|
26
13
|
if (inflight === undefined) {
|
|
27
14
|
inflight = (async () => {
|
|
28
15
|
const { AwsClient } = await import('google-auth-library');
|
|
29
|
-
// Construct AwsClient directly (not ExternalAccountClient.fromJSON, whose client-type selection
|
|
30
|
-
// reads only credential_source and ignores aws_security_credentials_supplier, yielding a throwing
|
|
31
|
-
// IdentityPoolClient). credential_source is cleared because AwsClient rejects both a credential
|
|
32
|
-
// source and a supplier at once; the built-in IMDS source is dropped in favour of the supplier.
|
|
33
16
|
return new AwsClient({
|
|
34
17
|
...parseWifConfig(wifConfigBase64, 'googleCloudAuth'),
|
|
35
18
|
credential_source: undefined,
|
|
@@ -57,9 +40,6 @@ export const googleCloudAuth = (wifConfigBase64) => {
|
|
|
57
40
|
},
|
|
58
41
|
};
|
|
59
42
|
};
|
|
60
|
-
// Audience-bound OIDC id_token auth for service-to-service calls (e.g. a fork's service calling the
|
|
61
|
-
// central corporate-service). Mints a Google-signed id_token whose `aud` is the passed audience, which the
|
|
62
|
-
// callee verifies against Google's JWKS. The token is cached and refreshed REFRESH_SKEW_MS before expiry.
|
|
63
43
|
// `forHost` (host[:port]) host-binds the Bearer that `withAuth` forwards: it is attached only to a fetch
|
|
64
44
|
// whose target host matches, so an unrelated outbound fetch inside the closure never receives the credential.
|
|
65
45
|
export const googleIdTokenAuth = (wifConfigBase64, audience, forHost) => {
|
|
@@ -77,8 +57,6 @@ export const googleIdTokenAuth = (wifConfigBase64, audience, forHost) => {
|
|
|
77
57
|
logger.error('google-auth', { op: 'id-token', error: e });
|
|
78
58
|
throw e;
|
|
79
59
|
}),
|
|
80
|
-
// Google id_tokens are valid for ID_TOKEN_TTL_SEC; bearer() refreshes REFRESH_SKEW_MS earlier. The
|
|
81
|
-
// sub-second offset between the mint await and this stamp is immaterial against the 5-min skew.
|
|
82
60
|
expiresAt: (Math.floor(Date.now() / 1000) + ID_TOKEN_TTL_SEC) * 1000,
|
|
83
61
|
};
|
|
84
62
|
};
|
|
@@ -96,17 +74,9 @@ export const googleIdTokenAuth = (wifConfigBase64, audience, forHost) => {
|
|
|
96
74
|
};
|
|
97
75
|
return {
|
|
98
76
|
bearer,
|
|
99
|
-
// Run fn with the minted Bearer forwarded on outbound fetch (the in-mesh credential-propagation
|
|
100
|
-
// allow path, e.g. a consumer's per-env corporate-service dist client reaching corporate-service).
|
|
101
|
-
// When `forHost` is set the Bearer is bound to that host, so it never rides an unrelated outbound fetch.
|
|
102
77
|
withAuth: async (fn) => runWithRequestHeaders({ authorization: await bearer() }, fn, forHost === undefined ? undefined : { forHost }),
|
|
103
78
|
};
|
|
104
79
|
};
|
|
105
|
-
// Impersonated access-token auth for arbitrary target scopes — what googleCloudAuth's fixed cloud-platform
|
|
106
|
-
// scope does not cover (Cloud Identity / Directory admin / IAM provisioning, e.g. corporate-service's own
|
|
107
|
-
// server-side Google operations). Mints per call (no cache — callers cache the downstream result where it
|
|
108
|
-
// matters) and returns the impersonated SA's email alongside the token for follow-up IAM Credentials calls
|
|
109
|
-
// (e.g. a domain-wide-delegation signJwt). `label` prefixes error messages with the calling module's name.
|
|
110
80
|
export const googleImpersonatedAuth = (wifConfigBase64, { label, lifetime, targetScopes }) => ({
|
|
111
81
|
accessToken: async () => {
|
|
112
82
|
const { impersonated, serviceAccountEmail } = await impersonatedClient({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/connector/google-auth/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAA;AACtE,OAAO,EAAE,8BAA8B,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAA;AACvH,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAA;AAE9C,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/connector/google-auth/index.ts"],"names":[],"mappings":"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"}
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
1
|
export declare const constants: {
|
|
2
2
|
OAUTH_DEV_REDIRECTOR_URL: string;
|
|
3
|
+
UPLOADS_PREFIX: string;
|
|
4
|
+
UPLOADS_EXPIRE_DAYS: number;
|
|
5
|
+
UPLOAD_FILENAME_MAX_LENGTH: number;
|
|
6
|
+
UPLOAD_CONTENT_TYPE_MAX_LENGTH: number;
|
|
7
|
+
UPLOAD_STORED_CONTENT_TYPE: string;
|
|
8
|
+
PII_ALLOWED_AWS_REGIONS: readonly ['eu-north-1', 'eu-west-1', 'eu-west-3', 'eu-central-1', 'eu-south-1', 'eu-south-2'];
|
|
9
|
+
SANITIZE_KEYWORDS: readonly ['authorization', 'proxy-authorization', 'cookie', 'set-cookie', 'x-api-key', 'apikey', 'api_key', 'api-key', 'token', 'secret', 'password', 'passwd', 'signature', 'private', 'session', 'jwt', 'bearer', 'email', 'fullname', 'isikukood', 'dateofbirth', 'phone', 'wage', 'screenedname', 'familyname', 'givenname', 'middlename', 'holdername', 'namekana', 'nickname', 'fax', 'workplaceaddress', 'complainantcontact', 'affiliatedorganization', 'nationalid', 'zipcode', 'taxnumber', 'corporateid', 'useragent', 'hostcountry', 'residencycountry', 'jobtitle', 'department', 'authenticationkey'];
|
|
10
|
+
SANITIZE_EXACT_KEYS: readonly ['ip'];
|
|
11
|
+
SANITIZE_EXACT_KEYS_EXCEPT_ERRORS: readonly ['name'];
|
|
3
12
|
};
|
package/dist/constants.js
CHANGED
|
@@ -1,8 +1,77 @@
|
|
|
1
1
|
export const constants = {
|
|
2
|
-
// Shared OAuth dev redirector (see `docker.md § Shared OAuth dev redirector`). In dev, provider OAuth
|
|
3
|
-
// `redirect_uri` points here because providers reject `http://*.orb.local`; the redirector 302s the browser
|
|
4
|
-
// back to the app's local return URL carried in `state`. One shared AWS-hosted instance for every product ×
|
|
5
|
-
// engineer, entity-invariant — a code constant, not env. Only used when DEPLOY_ENV === 'dev'.
|
|
6
2
|
OAUTH_DEV_REDIRECTOR_URL: 'https://jbilvarnjxcewv7spngtoaowia0krqmu.lambda-url.eu-north-1.on.aws/',
|
|
3
|
+
UPLOADS_PREFIX: '_uploads/',
|
|
4
|
+
UPLOADS_EXPIRE_DAYS: 1,
|
|
5
|
+
UPLOAD_FILENAME_MAX_LENGTH: 255,
|
|
6
|
+
UPLOAD_CONTENT_TYPE_MAX_LENGTH: 255,
|
|
7
|
+
UPLOAD_STORED_CONTENT_TYPE: 'application/octet-stream',
|
|
8
|
+
// The AWS regions inside the EU / EEA, which is where every resource processing or storing personal data is
|
|
9
|
+
// provisioned (infra.md § 9, GDPR Art. 44-49). Removing an entry closes a region every consumer's S3 / SES /
|
|
10
|
+
// STS clients may bind; an entry outside the EEA takes a documented Art. 46 transfer mechanism, recorded in
|
|
11
|
+
// the Sub-processors page, before it is added.
|
|
12
|
+
PII_ALLOWED_AWS_REGIONS: [
|
|
13
|
+
'eu-north-1',
|
|
14
|
+
'eu-west-1',
|
|
15
|
+
'eu-west-3',
|
|
16
|
+
'eu-central-1',
|
|
17
|
+
'eu-south-1',
|
|
18
|
+
'eu-south-2',
|
|
19
|
+
],
|
|
20
|
+
// The keys `Util.sanitize` redacts by substring match. Every entry must stay low-false-positive: a
|
|
21
|
+
// substring here masks any key containing it, so a generic word would gut incident investigation. Bare
|
|
22
|
+
// 'name' (a direct identifier, db-schema.md) belongs in SANITIZE_EXACT_KEYS_EXCEPT_ERRORS instead — a
|
|
23
|
+
// substring entry would mask serviceName / fileName / ….
|
|
24
|
+
SANITIZE_KEYWORDS: [
|
|
25
|
+
'authorization',
|
|
26
|
+
'proxy-authorization',
|
|
27
|
+
'cookie',
|
|
28
|
+
'set-cookie',
|
|
29
|
+
'x-api-key',
|
|
30
|
+
'apikey',
|
|
31
|
+
'api_key',
|
|
32
|
+
'api-key',
|
|
33
|
+
'token',
|
|
34
|
+
'secret',
|
|
35
|
+
'password',
|
|
36
|
+
'passwd',
|
|
37
|
+
'signature',
|
|
38
|
+
'private',
|
|
39
|
+
'session',
|
|
40
|
+
'jwt',
|
|
41
|
+
'bearer',
|
|
42
|
+
'email',
|
|
43
|
+
'fullname',
|
|
44
|
+
'isikukood',
|
|
45
|
+
'dateofbirth',
|
|
46
|
+
'phone',
|
|
47
|
+
'wage',
|
|
48
|
+
'screenedname',
|
|
49
|
+
'familyname',
|
|
50
|
+
'givenname',
|
|
51
|
+
'middlename',
|
|
52
|
+
'holdername',
|
|
53
|
+
'namekana',
|
|
54
|
+
'nickname',
|
|
55
|
+
'fax',
|
|
56
|
+
'workplaceaddress',
|
|
57
|
+
'complainantcontact',
|
|
58
|
+
'affiliatedorganization',
|
|
59
|
+
'nationalid',
|
|
60
|
+
'zipcode',
|
|
61
|
+
'taxnumber',
|
|
62
|
+
'corporateid',
|
|
63
|
+
'useragent',
|
|
64
|
+
'hostcountry',
|
|
65
|
+
'residencycountry',
|
|
66
|
+
'jobtitle',
|
|
67
|
+
'department',
|
|
68
|
+
'authenticationkey',
|
|
69
|
+
],
|
|
70
|
+
// Exact-match-only PII keys. A substring entry would be catastrophic here — 'ip' matches recipient /
|
|
71
|
+
// description / zip / script — so these are compared whole.
|
|
72
|
+
SANITIZE_EXACT_KEYS: ['ip'],
|
|
73
|
+
// Exact-match PII keys that an object produced from an Error is exempt from: its `name` is the error
|
|
74
|
+
// class, not a person's.
|
|
75
|
+
SANITIZE_EXACT_KEYS_EXCEPT_ERRORS: ['name'],
|
|
7
76
|
};
|
|
8
77
|
//# sourceMappingURL=constants.js.map
|
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,wBAAwB,EAAE,wEAAwE;IAClG,cAAc,EAAE,WAAW;IAC3B,mBAAmB,EAAE,CAAC;IACtB,0BAA0B,EAAE,GAAG;IAC/B,8BAA8B,EAAE,GAAG;IACnC,0BAA0B,EAAE,0BAA0B;IAEtD,4GAA4G;IAC5G,6GAA6G;IAC7G,4GAA4G;IAC5G,+CAA+C;IAC/C,uBAAuB,EAAE;QACvB,YAAY;QACZ,WAAW;QACX,WAAW;QACX,cAAc;QACd,YAAY;QACZ,YAAY;KACJ;IAEV,mGAAmG;IACnG,uGAAuG;IACvG,sGAAsG;IACtG,yDAAyD;IACzD,iBAAiB,EAAE;QACjB,eAAe;QACf,qBAAqB;QACrB,QAAQ;QACR,YAAY;QACZ,WAAW;QACX,QAAQ;QACR,SAAS;QACT,SAAS;QACT,OAAO;QACP,QAAQ;QACR,UAAU;QACV,QAAQ;QACR,WAAW;QACX,SAAS;QACT,SAAS;QACT,KAAK;QACL,QAAQ;QACR,OAAO;QACP,UAAU;QACV,WAAW;QACX,aAAa;QACb,OAAO;QACP,MAAM;QACN,cAAc;QACd,YAAY;QACZ,WAAW;QACX,YAAY;QACZ,YAAY;QACZ,UAAU;QACV,UAAU;QACV,KAAK;QACL,kBAAkB;QAClB,oBAAoB;QACpB,wBAAwB;QACxB,YAAY;QACZ,SAAS;QACT,WAAW;QACX,aAAa;QACb,WAAW;QACX,aAAa;QACb,kBAAkB;QAClB,UAAU;QACV,YAAY;QACZ,mBAAmB;KACX;IAEV,qGAAqG;IACrG,4DAA4D;IAC5D,mBAAmB,EAAE,CAAC,IAAI,CAAU;IAEpC,qGAAqG;IACrG,yBAAyB;IACzB,iCAAiC,EAAE,CAAC,MAAM,CAAU;CACrD,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/context/audit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/context/audit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAY/C,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,iBAAiB,EAAgB,CAAA;AAExE,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,EAAE,CAAC,mBAAmB,CAAC,QAAQ,EAAE,CAAA;AAE1E,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAI,IAA+C,EAAE,EAAoB,EAAE,EAAE;IAC5G,MAAM,MAAM,GAAG,mBAAmB,CAAC,QAAQ,EAAE,CAAA;IAC7C,OAAO,mBAAmB,CAAC,GAAG,CAC5B;QACE,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,QAAQ,EAAE,MAAM,EAAE,QAAQ,IAAI,KAAK;KACpC,EACD,EAAE,CACH,CAAA;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAI,IAAyB,EAAE,EAAoB,EAAE,EAAE,CACtF,mBAAmB,CAAC,GAAG,CACrB;IACE,MAAM,EAAE,IAAI,CAAC,MAAM;IACnB,QAAQ,EAAE,IAAI;CACf,EACD,EAAE,CACH,CAAA"}
|
|
@@ -1,19 +1,4 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from 'async_hooks';
|
|
2
|
-
// Request-scoped context shared across middleware boundaries (request id, header
|
|
3
|
-
// forwarding, current request path for log records). Lives in its own module so the
|
|
4
|
-
// logger can read it without depending on `server/express` (which already depends on the
|
|
5
|
-
// logger). The path is overridden by the tRPC procedure middleware so log records
|
|
6
|
-
// emitted inside a procedure carry the procedure path rather than the bare `/trpc`
|
|
7
|
-
// from Express.
|
|
8
|
-
//
|
|
9
|
-
// `headers` are the auto-captured inbound request headers; only tracing headers are
|
|
10
|
-
// auto-forwarded to outbound `fetch` (see `server/express` § AUTO_FORWARD_ALLOW_LIST) —
|
|
11
|
-
// everything else (credentials, client-context quasi-identifiers, content negotiation) is
|
|
12
|
-
// withheld by default. `forwardHeaderScopes` are headers set explicitly via
|
|
13
|
-
// `runWithRequestHeaders` — an intentional, audited in-mesh propagation path. Each scope may
|
|
14
|
-
// be host-bound (`forHost`) so a forwarded credential is only ever attached to a request whose
|
|
15
|
-
// target host matches, and `nonForwardableHeaders` is the per-app additional deny-set carried
|
|
16
|
-
// from `createApp` so the module-global patched `fetch` reads the right app's config.
|
|
17
2
|
export const requestContextStorage = new AsyncLocalStorage();
|
|
18
3
|
export const getCurrentRequestPath = () => requestContextStorage.getStore()?.path;
|
|
19
4
|
// Attach `headers` to every outbound `fetch` within `fn`. Pass `forHost` to bind them to a single
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/context/request/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAE/C,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/context/request/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,14 +7,6 @@ export declare const lock: {
|
|
|
7
7
|
key: string;
|
|
8
8
|
token: string;
|
|
9
9
|
}) => Promise<void>;
|
|
10
|
-
/**
|
|
11
|
-
* Run `fn` while holding the lock. Returns `{ acquired: false }` without
|
|
12
|
-
* invoking `fn` if the lock could not be acquired. Always releases the lock,
|
|
13
|
-
* even when `fn` throws.
|
|
14
|
-
*
|
|
15
|
-
* The discriminated return lets callers tell "lock not acquired" from "fn
|
|
16
|
-
* ran and returned undefined" — a plain `T | undefined` would collide.
|
|
17
|
-
*/
|
|
18
10
|
withLock: <T>({ key, ttlSec }: {
|
|
19
11
|
key: string;
|
|
20
12
|
ttlSec: number;
|
|
@@ -1,24 +1,6 @@
|
|
|
1
1
|
import { Script } from '@valkey/valkey-glide';
|
|
2
2
|
import { redis } from '../../repository/redis/index.js';
|
|
3
3
|
import { Util } from '../../util/index.js';
|
|
4
|
-
/**
|
|
5
|
-
* Distributed mutex built on Redis SET NX + check-and-delete.
|
|
6
|
-
*
|
|
7
|
-
* Use to serialize work that must not run concurrently across processes —
|
|
8
|
-
* payout execution, batch jobs, anything where two concurrent runs would
|
|
9
|
-
* double-spend or corrupt state.
|
|
10
|
-
*
|
|
11
|
-
* `acquire` returns a unique token on success (null when the lock is held).
|
|
12
|
-
* `release` only deletes the key when the stored token still matches, so a
|
|
13
|
-
* TTL-expired-then-reacquired lock is never deleted by the original holder.
|
|
14
|
-
*
|
|
15
|
-
* Redis errors propagate as throws — callers decide whether to fail-closed
|
|
16
|
-
* via `.catch(() => null)` (acquire) or surface the failure.
|
|
17
|
-
*
|
|
18
|
-
* Note: even with the token check, a critical section that overruns `ttlSec`
|
|
19
|
-
* no longer holds the lock; another worker can enter while `fn` is still
|
|
20
|
-
* running. Pick `ttlSec` larger than the worst-case body duration.
|
|
21
|
-
*/
|
|
22
4
|
const RELEASE_SCRIPT = new Script(`
|
|
23
5
|
if redis.call("GET", KEYS[1]) == ARGV[1] then
|
|
24
6
|
return redis.call("DEL", KEYS[1])
|
|
@@ -35,14 +17,6 @@ export const lock = {
|
|
|
35
17
|
release: async ({ key, token }) => {
|
|
36
18
|
await redis.invokeScript(RELEASE_SCRIPT, { keys: [key], args: [token] });
|
|
37
19
|
},
|
|
38
|
-
/**
|
|
39
|
-
* Run `fn` while holding the lock. Returns `{ acquired: false }` without
|
|
40
|
-
* invoking `fn` if the lock could not be acquired. Always releases the lock,
|
|
41
|
-
* even when `fn` throws.
|
|
42
|
-
*
|
|
43
|
-
* The discriminated return lets callers tell "lock not acquired" from "fn
|
|
44
|
-
* ran and returned undefined" — a plain `T | undefined` would collide.
|
|
45
|
-
*/
|
|
46
20
|
withLock: async ({ key, ttlSec }, fn) => {
|
|
47
21
|
const token = await lock.acquire({ key, ttlSec });
|
|
48
22
|
if (token === null) {
|
|
@@ -52,9 +26,6 @@ export const lock = {
|
|
|
52
26
|
return { acquired: true, value: await fn() };
|
|
53
27
|
}
|
|
54
28
|
finally {
|
|
55
|
-
// Swallow release failures so a Redis blip in cleanup doesn't mask
|
|
56
|
-
// `fn`'s original exception. The framework-level redis.invokeScript
|
|
57
|
-
// already logs the failure, and the lock TTL guarantees recovery.
|
|
58
29
|
await lock.release({ key, token }).catch(() => undefined);
|
|
59
30
|
}
|
|
60
31
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/coordination/lock/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAE7C,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAA;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAE1C
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/coordination/lock/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAE7C,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAA;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAE1C,MAAM,cAAc,GAAG,IAAI,MAAM,CAAC;;;;;;CAMjC,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,EAAmC,EAAE,EAAE;QAClE,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,EAAE,CAAA;QAC/B,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;QAChD,OAAO,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA;IAClC,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,KAAK,EAAkC,EAAE,EAAE;QAChE,MAAM,KAAK,CAAC,YAAY,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IAC1E,CAAC;IACD,QAAQ,EAAE,KAAK,EAAK,EAAE,GAAG,EAAE,MAAM,EAAmC,EAAE,EAAoB,EAAE,EAAE;QAC5F,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAA;QACjD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;QAC5B,CAAC;QACD,IAAI,CAAC;YACH,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAA;QAC9C,CAAC;gBAAS,CAAC;YACT,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;QAC3D,CAAC;IACH,CAAC;CACF,CAAA"}
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
export declare const rateLimit: {
|
|
2
|
-
/**
|
|
3
|
-
* Increment the counter for `key` and decide whether the current attempt is
|
|
4
|
-
* allowed. Returns the post-increment count and how many attempts remain in
|
|
5
|
-
* the current window.
|
|
6
|
-
*/
|
|
7
2
|
attempt: ({ key, max, windowSec }: {
|
|
8
3
|
key: string;
|
|
9
4
|
max: number;
|
|
@@ -1,35 +1,12 @@
|
|
|
1
1
|
import { Script } from '@valkey/valkey-glide';
|
|
2
2
|
import { redis } from '../../repository/redis/index.js';
|
|
3
|
-
/**
|
|
4
|
-
* Fixed-window rate limiter built on a single atomic Lua script
|
|
5
|
-
* (INCR + EXPIRE on the first hit of a window).
|
|
6
|
-
*
|
|
7
|
-
* Use to cap the number of attempts against a key inside a rolling window —
|
|
8
|
-
* unauthenticated endpoints (password reset, signup, OTP request, etc.) that
|
|
9
|
-
* would otherwise be abusable by brute-force or spam.
|
|
10
|
-
*
|
|
11
|
-
* The INCR and EXPIRE run inside a Lua script, so the key is guaranteed to
|
|
12
|
-
* have a TTL whenever its value > 0 — an interrupt between the two ops is
|
|
13
|
-
* impossible.
|
|
14
|
-
*
|
|
15
|
-
* Redis errors propagate as throws — callers decide whether to fail-closed
|
|
16
|
-
* via `.catch(...)` or surface the failure.
|
|
17
|
-
*/
|
|
18
3
|
const ATTEMPT_SCRIPT = new Script(`
|
|
19
4
|
local n = redis.call("INCR", KEYS[1])
|
|
20
5
|
if n == 1 then redis.call("EXPIRE", KEYS[1], ARGV[1]) end
|
|
21
6
|
return n
|
|
22
7
|
`);
|
|
23
8
|
export const rateLimit = {
|
|
24
|
-
/**
|
|
25
|
-
* Increment the counter for `key` and decide whether the current attempt is
|
|
26
|
-
* allowed. Returns the post-increment count and how many attempts remain in
|
|
27
|
-
* the current window.
|
|
28
|
-
*/
|
|
29
9
|
attempt: async ({ key, max, windowSec }) => {
|
|
30
|
-
// A non-integer windowSec makes the Lua EXPIRE fail after the INCR (no rollback) — the key persists
|
|
31
|
-
// with no TTL, permanently denying the caller; windowSec: 0 makes EXPIRE delete the key, permanently
|
|
32
|
-
// allowing it. Reject both before running the script.
|
|
33
10
|
if (!Number.isInteger(windowSec) || windowSec <= 0) {
|
|
34
11
|
throw new Error(`rateLimit: windowSec must be a positive integer (got ${windowSec})`);
|
|
35
12
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/coordination/rate-limit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAE7C,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAA;AAEvD
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/coordination/rate-limit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAE7C,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAA;AAEvD,MAAM,cAAc,GAAG,IAAI,MAAM,CAAC;;;;CAIjC,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAmD,EAAE,EAAE;QAC1F,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;YACnD,MAAM,IAAI,KAAK,CAAC,wDAAwD,SAAS,GAAG,CAAC,CAAA;QACvF,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,KAAK,CAAC,YAAY,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAC1G,OAAO;YACL,OAAO,EAAE,KAAK,IAAI,GAAG;YACrB,KAAK;YACL,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,KAAK,CAAC;SACpC,CAAA;IACH,CAAC;CACF,CAAA"}
|
|
@@ -1,16 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* At-most-once-per-window throttle built on Redis SET NX.
|
|
3
|
-
*
|
|
4
|
-
* Use when an action should run at most once per `windowSec` — sanctions
|
|
5
|
-
* evaluation that should not re-fire on every call-log ingest, single-use
|
|
6
|
-
* token claims that must succeed exactly once across concurrent attempts.
|
|
7
|
-
*
|
|
8
|
-
* Unlike `lock`, there is no explicit release: the slot opens again only
|
|
9
|
-
* when the TTL expires.
|
|
10
|
-
*
|
|
11
|
-
* Redis errors propagate as throws — callers decide whether to fail-closed
|
|
12
|
-
* via `.catch(() => false)` or surface the failure.
|
|
13
|
-
*/
|
|
14
1
|
export declare const throttle: {
|
|
15
2
|
tryAcquire: ({ key, windowSec }: {
|
|
16
3
|
key: string;
|
|
@@ -1,17 +1,4 @@
|
|
|
1
1
|
import { redis } from '../../repository/redis/index.js';
|
|
2
|
-
/**
|
|
3
|
-
* At-most-once-per-window throttle built on Redis SET NX.
|
|
4
|
-
*
|
|
5
|
-
* Use when an action should run at most once per `windowSec` — sanctions
|
|
6
|
-
* evaluation that should not re-fire on every call-log ingest, single-use
|
|
7
|
-
* token claims that must succeed exactly once across concurrent attempts.
|
|
8
|
-
*
|
|
9
|
-
* Unlike `lock`, there is no explicit release: the slot opens again only
|
|
10
|
-
* when the TTL expires.
|
|
11
|
-
*
|
|
12
|
-
* Redis errors propagate as throws — callers decide whether to fail-closed
|
|
13
|
-
* via `.catch(() => false)` or surface the failure.
|
|
14
|
-
*/
|
|
15
2
|
export const throttle = {
|
|
16
3
|
tryAcquire: async ({ key, windowSec }) => {
|
|
17
4
|
const ok = await redis.setNx(key, '1', windowSec);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/coordination/throttle/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAA;AAEvD
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/coordination/throttle/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAA;AAEvD,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,UAAU,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,SAAS,EAAsC,EAAE,EAAE;QAC3E,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,CAAC,CAAA;QACjD,OAAO,EAAE,IAAI,IAAI,CAAA;IACnB,CAAC;CACF,CAAA"}
|
package/dist/env.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const defaultEnv: {
|
|
2
|
-
AWS_REGION:
|
|
2
|
+
AWS_REGION: "eu-central-1" | "eu-north-1" | "eu-south-1" | "eu-south-2" | "eu-west-1" | "eu-west-3";
|
|
3
3
|
NODE_ENV: "development" | "production";
|
|
4
4
|
DEPLOY_ENV: "dev" | "prd" | "stg";
|
|
5
5
|
LOG_LEVEL?: "debug" | "error" | "info" | "warn" | undefined;
|
package/dist/env.js
CHANGED
|
@@ -1,31 +1,25 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { constants } from './constants.js';
|
|
2
3
|
import { Util } from './util/index.js';
|
|
3
4
|
export const defaultEnv = Util.createEnvProxy(z.object({
|
|
4
|
-
|
|
5
|
-
AWS_REGION: z.string().min(1),
|
|
6
|
-
// ---- Common
|
|
5
|
+
AWS_REGION: z.enum(constants.PII_ALLOWED_AWS_REGIONS),
|
|
7
6
|
NODE_ENV: z.enum(['development', 'production']),
|
|
8
7
|
DEPLOY_ENV: z.enum(['dev', 'stg', 'prd']),
|
|
9
|
-
LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).optional(),
|
|
10
|
-
// ---- Infra
|
|
8
|
+
LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).optional(),
|
|
11
9
|
DATABASE_HOST: z.string().min(1),
|
|
12
10
|
DATABASE_PORT: z.string().min(1).transform(Number),
|
|
13
11
|
DATABASE_RO_HOST: z.string().min(1),
|
|
14
12
|
DATABASE_RO_PORT: z.string().min(1).transform(Number),
|
|
15
13
|
DATABASE_USER: z.string().min(1),
|
|
16
14
|
DATABASE_PASSWORD: z.string().min(1),
|
|
17
|
-
DATABASE_NAME: z.string().min(1).optional(),
|
|
15
|
+
DATABASE_NAME: z.string().min(1).optional(),
|
|
18
16
|
REDIS_CLUSTER: z.string().transform((val) => val === 'true'),
|
|
19
17
|
REDIS_HOST: z.string().min(1),
|
|
20
18
|
REDIS_PORT: z.string().min(1).transform(Number),
|
|
21
|
-
LOCAL_S3_ENDPOINT: z.url().optional(),
|
|
19
|
+
LOCAL_S3_ENDPOINT: z.url().optional(),
|
|
22
20
|
STORAGE_BUCKET: z.string().min(1),
|
|
23
|
-
// ---- Package
|
|
24
21
|
SERVICE: z.string().min(1),
|
|
25
22
|
PORT: z.string().min(1).transform(Number),
|
|
26
|
-
// Comma-separated list of allowed origins (a single origin stays a one-element list). Each entry is
|
|
27
|
-
// trimmed and URL-validated, so a malformed / empty entry fails at startup instead of silently
|
|
28
|
-
// widening or narrowing the allow-list.
|
|
29
23
|
CORS_ORIGIN: z
|
|
30
24
|
.string()
|
|
31
25
|
.min(1)
|
|
@@ -33,13 +27,10 @@ export const defaultEnv = Util.createEnvProxy(z.object({
|
|
|
33
27
|
.pipe(z.array(z.url()).min(1)),
|
|
34
28
|
BASE_URL: z.url(),
|
|
35
29
|
}), () => ({
|
|
36
|
-
// ---- AWS
|
|
37
30
|
AWS_REGION: process.env.AWS_REGION,
|
|
38
|
-
// ---- Common
|
|
39
31
|
NODE_ENV: process.env.NODE_ENV,
|
|
40
32
|
DEPLOY_ENV: process.env.DEPLOY_ENV,
|
|
41
33
|
LOG_LEVEL: process.env.LOG_LEVEL,
|
|
42
|
-
// ---- Infra
|
|
43
34
|
DATABASE_HOST: process.env.DATABASE_HOST,
|
|
44
35
|
DATABASE_PORT: process.env.DATABASE_PORT,
|
|
45
36
|
DATABASE_RO_HOST: process.env.DATABASE_RO_HOST,
|
|
@@ -52,7 +43,6 @@ export const defaultEnv = Util.createEnvProxy(z.object({
|
|
|
52
43
|
REDIS_PORT: process.env.REDIS_PORT,
|
|
53
44
|
LOCAL_S3_ENDPOINT: process.env.LOCAL_S3_ENDPOINT,
|
|
54
45
|
STORAGE_BUCKET: process.env.STORAGE_BUCKET,
|
|
55
|
-
// ---- Package
|
|
56
46
|
SERVICE: process.env.SERVICE,
|
|
57
47
|
PORT: process.env.PORT,
|
|
58
48
|
CORS_ORIGIN: process.env.CORS_ORIGIN,
|
package/dist/env.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAEtC,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,CAC3C,CAAC,CAAC,MAAM,CAAC;IACP,
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AwsClientOptions } from 'google-auth-library';
|
|
2
2
|
export declare const awsSecurityCredentialsSupplier: {
|
|
3
|
-
getAwsRegion: () => Promise<
|
|
3
|
+
getAwsRegion: () => Promise<"eu-central-1" | "eu-north-1" | "eu-south-1" | "eu-south-2" | "eu-west-1" | "eu-west-3">;
|
|
4
4
|
getAwsSecurityCredentials: () => Promise<{
|
|
5
5
|
accessKeyId: string;
|
|
6
6
|
secretAccessKey: string;
|
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
import { defaultEnv } from '../../env.js';
|
|
2
|
-
// Shared AWS → Google Workload Identity Federation plumbing. All consumers federate the running AWS
|
|
3
|
-
// identity into a Google Workload Identity Pool and impersonate a service account: googleIdTokenAuth
|
|
4
|
-
// mints an audience-bound OIDC id_token, googleCloudAuth a cloud-platform access token, and
|
|
5
|
-
// googleImpersonatedAuth an access token for arbitrary target scopes. What they share lives here — the
|
|
6
|
-
// AWS credential supplier, the cred-config parse, and the Impersonated-client builder.
|
|
7
|
-
//
|
|
8
|
-
// The AWS identity is resolved through the AWS SDK credential chain (env / ECS container credential
|
|
9
|
-
// endpoint / EC2 IMDS, rotation-aware) rather than google-auth-library's built-in AWS source, which
|
|
10
|
-
// reads only env vars → EC2 IMDS and therefore fails on ECS Fargate, where task-role credentials
|
|
11
|
-
// live at the container credential endpoint instead of IMDS. The chain is exposed to
|
|
12
|
-
// google-auth-library via the custom aws_security_credentials_supplier below.
|
|
13
2
|
let awsCredentialProvider;
|
|
14
3
|
// An AwsSecurityCredentialsSupplier backed by the AWS SDK defaultProvider (the credential provider is
|
|
15
4
|
// dynamically imported and memoized so a service that never federates does not load it).
|
|
@@ -21,9 +10,6 @@ export const awsSecurityCredentialsSupplier = {
|
|
|
21
10
|
return { accessKeyId: c.accessKeyId, secretAccessKey: c.secretAccessKey, token: c.sessionToken };
|
|
22
11
|
},
|
|
23
12
|
};
|
|
24
|
-
// Parse the base64 WIF cred config (points at the pool / provider / SA; holds no credential). Both
|
|
25
|
-
// consumers require service account impersonation, so the presence check lives here and the return
|
|
26
|
-
// type narrows the field to non-optional for the caller.
|
|
27
13
|
export const parseWifConfig = (base64, label) => {
|
|
28
14
|
const config = JSON.parse(Buffer.from(base64, 'base64').toString('utf8'));
|
|
29
15
|
const { service_account_impersonation_url } = config;
|
|
@@ -32,12 +18,6 @@ export const parseWifConfig = (base64, label) => {
|
|
|
32
18
|
}
|
|
33
19
|
return { ...config, service_account_impersonation_url };
|
|
34
20
|
};
|
|
35
|
-
// Build the Impersonated client the token mints run through: parse the WIF config, derive the target SA
|
|
36
|
-
// email from its impersonation URL, and wrap the federation-only AwsClient (impersonation URL + built-in
|
|
37
|
-
// IMDS source stripped in favour of the supplier — AwsClient rejects a credential source and a supplier at
|
|
38
|
-
// once) in an Impersonated for the requested lifetime / target scopes. Impersonation itself runs via
|
|
39
|
-
// generateAccessToken / generateIdToken, for which the federated principal holds
|
|
40
|
-
// roles/iam.serviceAccountTokenCreator on the SA.
|
|
41
21
|
export const impersonatedClient = async ({ wifConfigBase64, label, lifetime, targetScopes, }) => {
|
|
42
22
|
const { AwsClient, Impersonated } = await import('google-auth-library');
|
|
43
23
|
const config = parseWifConfig(wifConfigBase64, label);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/internal/federation/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/internal/federation/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC,IAAI,qBAES,CAAA;AAEb,sGAAsG;AACtG,yFAAyF;AACzF,MAAM,CAAC,MAAM,8BAA8B,GAAG;IAC5C,YAAY,EAAE,KAAK,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU;IAC/C,yBAAyB,EAAE,KAAK,IAAI,EAAE;QACpC,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,mCAAmC,CAAC,CAAA;QAC7E,MAAM,CAAC,GAAG,MAAM,CAAC,qBAAqB,KAAK,eAAe,EAAE,CAAC,EAAE,CAAA;QAC/D,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,eAAe,EAAE,CAAC,CAAC,eAAe,EAAE,KAAK,EAAE,CAAC,CAAC,YAAY,EAAE,CAAA;IAClG,CAAC;CACF,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,MAAc,EACd,KAAa,EACqD,EAAE;IACpE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAqB,CAAA;IAC7F,MAAM,EAAE,iCAAiC,EAAE,GAAG,MAAM,CAAA;IACpD,IAAI,iCAAiC,KAAK,SAAS,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,wDAAwD,CAAC,CAAA;IACnF,CAAC;IACD,OAAO,EAAE,GAAG,MAAM,EAAE,iCAAiC,EAAE,CAAA;AACzD,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,EAAE,EACvC,eAAe,EACf,KAAK,EACL,QAAQ,EACR,YAAY,GAMb,EAAE,EAAE;IACH,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAA;IACvE,MAAM,MAAM,GAAG,cAAc,CAAC,eAAe,EAAE,KAAK,CAAC,CAAA;IACrD,MAAM,mBAAmB,GAAG,MAAM,CAAC,iCAAiC,CAAC,KAAK,CAAC,4BAA4B,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAC7G,IAAI,mBAAmB,KAAK,SAAS,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,uDAAuD,CAAC,CAAA;IAClF,CAAC;IACD,OAAO;QACL,YAAY,EAAE,IAAI,YAAY,CAAC;YAC7B,YAAY,EAAE,IAAI,SAAS,CAAC;gBAC1B,GAAG,MAAM;gBACT,iCAAiC,EAAE,SAAS;gBAC5C,iBAAiB,EAAE,SAAS;gBAC5B,iCAAiC,EAAE,8BAA8B;aAClE,CAAC;YACF,eAAe,EAAE,mBAAmB;YACpC,QAAQ;YACR,YAAY;SACb,CAAC;QACF,mBAAmB;KACpB,CAAA;AACH,CAAC,CAAA"}
|
package/dist/logger/index.js
CHANGED
|
@@ -3,31 +3,13 @@ import { getCurrentRequestPath } from '../context/request/index.js';
|
|
|
3
3
|
import { defaultEnv } from '../env.js';
|
|
4
4
|
import { Util } from '../util/index.js';
|
|
5
5
|
const LEVEL_ORDER = { debug: 10, info: 20, warn: 30, error: 40 };
|
|
6
|
-
// LOG_LEVEL overrides per package's .env.<env>; otherwise the threshold defaults by
|
|
7
|
-
// DEPLOY_ENV: dev=debug (full local trace), stg=info (drop high-volume debug), prd=warn
|
|
8
|
-
// (only warnings and errors). LOG_LEVEL is the escape hatch when you need to temporarily
|
|
9
|
-
// raise visibility — e.g. enable debug in prd for an incident, or info in stg for a
|
|
10
|
-
// repro session.
|
|
11
6
|
const DEFAULT_BY_DEPLOY_ENV = { dev: 'debug', stg: 'info', prd: 'warn' };
|
|
12
|
-
// Cap each sanitized string so one oversized value (a base64 blob, a giant payload) cannot blow past
|
|
13
|
-
// the CloudWatch 256 KB per-event limit. Applied per string / line, well under the whole-record ceiling.
|
|
14
7
|
const MAX_LOG_STRING_LENGTH = 8192;
|
|
15
8
|
const emit = (level, tag, payload) => {
|
|
16
9
|
if (LEVEL_ORDER[level] < LEVEL_ORDER[defaultEnv.LOG_LEVEL ?? DEFAULT_BY_DEPLOY_ENV[defaultEnv.DEPLOY_ENV]]) {
|
|
17
10
|
return;
|
|
18
11
|
}
|
|
19
|
-
// Guard the whole sanitize+format+write: a payload with a throwing getter or non-serializable value
|
|
20
|
-
// must not make `logger.error` throw — it runs inside the uncaughtException handler and tRPC onError,
|
|
21
|
-
// where a throw is fatal. On failure, degrade to a minimal single-line record (sanctioned console use,
|
|
22
|
-
// last-resort logger).
|
|
23
12
|
try {
|
|
24
|
-
// dev (local, human-read) prints via util.inspect so string values render literally — no
|
|
25
|
-
// JSON quote/newline escaping (`\"`, `\n`) and no depth truncation (`[Object]`). stg/prd
|
|
26
|
-
// (ECS → CloudWatch, machine-parsed) print single-line JSON so each entry maps to one
|
|
27
|
-
// CloudWatch record and the escaping is the correct, parseable wire form.
|
|
28
|
-
// `path` is auto-injected from the AsyncLocalStorage request context (Express request
|
|
29
|
-
// path, overridden to the tRPC procedure path inside `baseProcedure`). The caller can
|
|
30
|
-
// still pass `path` in `payload` to override — payload spreads last.
|
|
31
13
|
const autoPath = getCurrentRequestPath();
|
|
32
14
|
const record = Util.sanitize({
|
|
33
15
|
level,
|
package/dist/logger/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/logger/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAA;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAEvC,MAAM,WAAW,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAW,CAAA;AAGzE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/logger/index.ts"],"names":[],"mappings":"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"}
|