@webpieces/gcp-identity 0.3.371 → 0.3.373

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
@@ -6,7 +6,8 @@ tests) every call falls back to a deterministic localhost value so no GCP is nee
6
6
 
7
7
  - `getProjectId()` / `getNumericProjectId()` / `getRegion()` — cached metadata lookups
8
8
  - `getServiceName()` — logical name from `K_SERVICE` (strips a `tf-` prefix), else `'local'`
9
- - `getSelfCloudRunUrl()` / `getCloudRunUrl(name)` deterministic Cloud Run URLs
9
+ - `getSelfCloudRunUrl()` this service's own base URL
10
+ - `resolveServiceUrl(svcName)` — the base URL to call svcName: a `ClientRegistry` override wins, else the Cloud Run URL is derived on GCP, else (off-GCP, unregistered) it throws
10
11
  - `getRuntimeServiceAccountEmail()` — the SA this process runs as
11
12
  - `mintIdToken(audience)` — Google-signed OIDC ID token (a `dev-oidc.*` token off-GCP)
12
13
  - `verifyOidcFromCallers(idToken, callers)` — verify + allow-list the caller SA
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/gcp-identity",
3
- "version": "0.3.371",
3
+ "version": "0.3.373",
4
4
  "description": "GCP runtime identity: project/region metadata, Cloud Run URLs, OIDC mint/verify",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -23,8 +23,8 @@
23
23
  "access": "public"
24
24
  },
25
25
  "dependencies": {
26
- "@webpieces/core-context": "0.3.371",
27
- "@webpieces/core-util": "0.3.371",
26
+ "@webpieces/core-context": "0.3.373",
27
+ "@webpieces/core-util": "0.3.373",
28
28
  "google-auth-library": "9.15.1",
29
29
  "gcp-metadata": "6.1.1",
30
30
  "inversify": "7.10.4",
package/src/index.d.ts CHANGED
@@ -9,5 +9,5 @@
9
9
  * via an app-bound AuthConfig) and the RPC + Cloud Tasks clients.
10
10
  */
11
11
  export { isOnGcp } from './metadata';
12
- export { getServiceName, getProjectId, getRegion, getRuntimeServiceAccountEmail, getSelfCloudRunUrl, getCloudRunUrl, resolveTargetUrl, LOCAL_SERVICE_ACCOUNT_EMAIL, } from './urls';
12
+ export { getServiceName, getProjectId, getRegion, getRuntimeServiceAccountEmail, getSelfCloudRunUrl, resolveServiceUrl, LOCAL_SERVICE_ACCOUNT_EMAIL, } from './urls';
13
13
  export { GcpOidc, OidcVerifyResult } from './oidc';
package/src/index.js CHANGED
@@ -10,7 +10,7 @@
10
10
  * via an app-bound AuthConfig) and the RPC + Cloud Tasks clients.
11
11
  */
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.OidcVerifyResult = exports.GcpOidc = exports.LOCAL_SERVICE_ACCOUNT_EMAIL = exports.resolveTargetUrl = exports.getCloudRunUrl = exports.getSelfCloudRunUrl = exports.getRuntimeServiceAccountEmail = exports.getRegion = exports.getProjectId = exports.getServiceName = exports.isOnGcp = void 0;
13
+ exports.OidcVerifyResult = exports.GcpOidc = exports.LOCAL_SERVICE_ACCOUNT_EMAIL = exports.resolveServiceUrl = exports.getSelfCloudRunUrl = exports.getRuntimeServiceAccountEmail = exports.getRegion = exports.getProjectId = exports.getServiceName = exports.isOnGcp = void 0;
14
14
  var metadata_1 = require("./metadata");
15
15
  Object.defineProperty(exports, "isOnGcp", { enumerable: true, get: function () { return metadata_1.isOnGcp; } });
16
16
  var urls_1 = require("./urls");
@@ -19,8 +19,7 @@ Object.defineProperty(exports, "getProjectId", { enumerable: true, get: function
19
19
  Object.defineProperty(exports, "getRegion", { enumerable: true, get: function () { return urls_1.getRegion; } });
20
20
  Object.defineProperty(exports, "getRuntimeServiceAccountEmail", { enumerable: true, get: function () { return urls_1.getRuntimeServiceAccountEmail; } });
21
21
  Object.defineProperty(exports, "getSelfCloudRunUrl", { enumerable: true, get: function () { return urls_1.getSelfCloudRunUrl; } });
22
- Object.defineProperty(exports, "getCloudRunUrl", { enumerable: true, get: function () { return urls_1.getCloudRunUrl; } });
23
- Object.defineProperty(exports, "resolveTargetUrl", { enumerable: true, get: function () { return urls_1.resolveTargetUrl; } });
22
+ Object.defineProperty(exports, "resolveServiceUrl", { enumerable: true, get: function () { return urls_1.resolveServiceUrl; } });
24
23
  Object.defineProperty(exports, "LOCAL_SERVICE_ACCOUNT_EMAIL", { enumerable: true, get: function () { return urls_1.LOCAL_SERVICE_ACCOUNT_EMAIL; } });
25
24
  var oidc_1 = require("./oidc");
26
25
  Object.defineProperty(exports, "GcpOidc", { enumerable: true, get: function () { return oidc_1.GcpOidc; } });
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/cloud/gcp-identity/src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;AAEH,uCAAqC;AAA5B,mGAAA,OAAO,OAAA;AAChB,+BASgB;AARZ,sGAAA,cAAc,OAAA;AACd,oGAAA,YAAY,OAAA;AACZ,iGAAA,SAAS,OAAA;AACT,qHAAA,6BAA6B,OAAA;AAC7B,0GAAA,kBAAkB,OAAA;AAClB,sGAAA,cAAc,OAAA;AACd,wGAAA,gBAAgB,OAAA;AAChB,mHAAA,2BAA2B,OAAA;AAE/B,+BAAmD;AAA1C,+FAAA,OAAO,OAAA;AAAE,wGAAA,gBAAgB,OAAA","sourcesContent":["/**\n * @webpieces/gcp-identity\n *\n * GCP runtime identity (Node-only). Metadata, Cloud Run URLs, and OIDC mint/verify,\n * all read from the metadata server / ADC at runtime with deterministic localhost\n * fallbacks off-GCP so local dev and tests never touch GCP.\n *\n * Underpins the @AuthOidc service-to-service auth mode (enforced by the framework AuthFilter\n * via an app-bound AuthConfig) and the RPC + Cloud Tasks clients.\n */\n\nexport { isOnGcp } from './metadata';\nexport {\n getServiceName,\n getProjectId,\n getRegion,\n getRuntimeServiceAccountEmail,\n getSelfCloudRunUrl,\n getCloudRunUrl,\n resolveTargetUrl,\n LOCAL_SERVICE_ACCOUNT_EMAIL,\n} from './urls';\nexport { GcpOidc, OidcVerifyResult } from './oidc';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/cloud/gcp-identity/src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;AAEH,uCAAqC;AAA5B,mGAAA,OAAO,OAAA;AAChB,+BAQgB;AAPZ,sGAAA,cAAc,OAAA;AACd,oGAAA,YAAY,OAAA;AACZ,iGAAA,SAAS,OAAA;AACT,qHAAA,6BAA6B,OAAA;AAC7B,0GAAA,kBAAkB,OAAA;AAClB,yGAAA,iBAAiB,OAAA;AACjB,mHAAA,2BAA2B,OAAA;AAE/B,+BAAmD;AAA1C,+FAAA,OAAO,OAAA;AAAE,wGAAA,gBAAgB,OAAA","sourcesContent":["/**\n * @webpieces/gcp-identity\n *\n * GCP runtime identity (Node-only). Metadata, Cloud Run URLs, and OIDC mint/verify,\n * all read from the metadata server / ADC at runtime with deterministic localhost\n * fallbacks off-GCP so local dev and tests never touch GCP.\n *\n * Underpins the @AuthOidc service-to-service auth mode (enforced by the framework AuthFilter\n * via an app-bound AuthConfig) and the RPC + Cloud Tasks clients.\n */\n\nexport { isOnGcp } from './metadata';\nexport {\n getServiceName,\n getProjectId,\n getRegion,\n getRuntimeServiceAccountEmail,\n getSelfCloudRunUrl,\n resolveServiceUrl,\n LOCAL_SERVICE_ACCOUNT_EMAIL,\n} from './urls';\nexport { GcpOidc, OidcVerifyResult } from './oidc';\n"]}
package/src/metadata.d.ts CHANGED
@@ -1,4 +1,8 @@
1
- /** True when running on GCP (Cloud Run / GCE) with a reachable metadata server. */
1
+ /**
2
+ * True when running on GCP Cloud Run. Gated on `K_SERVICE` (set by Cloud Run) so local dev does NO
3
+ * metadata network probe. For non-Cloud-Run GCP (GCE / Cloud Functions, which don't set `K_SERVICE`),
4
+ * set `METADATA_SERVER_DETECTION=assume-present` to force on-GCP behavior.
5
+ */
2
6
  export declare function isOnGcp(): Promise<boolean>;
3
7
  /** GCP project id (e.g. 'my-project'). Only call when isOnGcp() is true. */
4
8
  export declare function readProjectId(): Promise<string>;
package/src/metadata.js CHANGED
@@ -12,16 +12,27 @@ const gcpMetadata = tslib_1.__importStar(require("gcp-metadata"));
12
12
  * process (the metadata server is stable for the life of the instance). Off-GCP
13
13
  * `isOnGcp()` is false and the callers fall back to localhost values, so nothing
14
14
  * here is ever reached in local dev / tests.
15
+ *
16
+ * `isOnGcp()` is decided from the `K_SERVICE` env var (which Cloud Run always sets),
17
+ * NOT a metadata network probe — so local dev never blocks on the ~3s
18
+ * `gcpMetadata.isAvailable()` timeout. Every caller (project id, region, Cloud Run URL
19
+ * resolution, OIDC minting, Cloud Tasks) short-circuits through this one gate.
15
20
  */
16
21
  let cachedOnGcp;
17
22
  let cachedProjectId;
18
23
  let cachedNumericProjectId;
19
24
  let cachedRegion;
20
25
  let cachedSaEmail;
21
- /** True when running on GCP (Cloud Run / GCE) with a reachable metadata server. */
26
+ /**
27
+ * True when running on GCP Cloud Run. Gated on `K_SERVICE` (set by Cloud Run) so local dev does NO
28
+ * metadata network probe. For non-Cloud-Run GCP (GCE / Cloud Functions, which don't set `K_SERVICE`),
29
+ * set `METADATA_SERVER_DETECTION=assume-present` to force on-GCP behavior.
30
+ */
22
31
  function isOnGcp() {
23
32
  if (!cachedOnGcp) {
24
- cachedOnGcp = gcpMetadata.isAvailable();
33
+ const onGcp = process.env['K_SERVICE'] !== undefined ||
34
+ process.env['METADATA_SERVER_DETECTION'] === 'assume-present';
35
+ cachedOnGcp = Promise.resolve(onGcp);
25
36
  }
26
37
  return cachedOnGcp;
27
38
  }
@@ -1 +1 @@
1
- {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../../../packages/cloud/gcp-identity/src/metadata.ts"],"names":[],"mappings":";;AAgBA,0BAKC;AAUD,sCAKC;AAGD,oDAKC;AAGD,gCAQC;AAGD,wEAKC;;AA/DD,kEAA4C;AAE5C;;;;;GAKG;AAEH,IAAI,WAAyC,CAAC;AAC9C,IAAI,eAA4C,CAAC;AACjD,IAAI,sBAAmD,CAAC;AACxD,IAAI,YAAyC,CAAC;AAC9C,IAAI,aAA0C,CAAC;AAE/C,mFAAmF;AACnF,SAAgB,OAAO;IACnB,IAAI,CAAC,WAAW,EAAE,CAAC;QACf,WAAW,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC;IAC5C,CAAC;IACD,OAAO,WAAW,CAAC;AACvB,CAAC;AAED,oFAAoF;AACpF,wEAAwE;AACxE,iGAAiG;AACjG,SAAS,QAAQ,CAAC,KAAc;IAC5B,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACzB,CAAC;AAED,4EAA4E;AAC5E,SAAgB,aAAa;IACzB,IAAI,CAAC,eAAe,EAAE,CAAC;QACnB,eAAe,GAAG,WAAW,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,eAAe,CAAC;AAC3B,CAAC;AAED,yDAAyD;AACzD,SAAgB,oBAAoB;IAChC,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAC1B,sBAAsB,GAAG,WAAW,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtF,CAAC;IACD,OAAO,sBAAsB,CAAC;AAClC,CAAC;AAED,4FAA4F;AAC5F,SAAgB,UAAU;IACtB,IAAI,CAAC,YAAY,EAAE,CAAC;QAChB,YAAY,GAAG,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,GAAW,EAAE,EAAE;YAC9E,MAAM,GAAG,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;YACjC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QACnD,CAAC,CAAC,CAAC;IACP,CAAC;IACD,OAAO,YAAY,CAAC;AACxB,CAAC;AAED,sDAAsD;AACtD,SAAgB,8BAA8B;IAC1C,IAAI,CAAC,aAAa,EAAE,CAAC;QACjB,aAAa,GAAG,WAAW,CAAC,QAAQ,CAAC,gCAAgC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC1F,CAAC;IACD,OAAO,aAAa,CAAC;AACzB,CAAC","sourcesContent":["import * as gcpMetadata from 'gcp-metadata';\n\n/**\n * Cached reads of the GCP metadata server. Every value is fetched at most once per\n * process (the metadata server is stable for the life of the instance). Off-GCP\n * `isOnGcp()` is false and the callers fall back to localhost values, so nothing\n * here is ever reached in local dev / tests.\n */\n\nlet cachedOnGcp: Promise<boolean> | undefined;\nlet cachedProjectId: Promise<string> | undefined;\nlet cachedNumericProjectId: Promise<string> | undefined;\nlet cachedRegion: Promise<string> | undefined;\nlet cachedSaEmail: Promise<string> | undefined;\n\n/** True when running on GCP (Cloud Run / GCE) with a reachable metadata server. */\nexport function isOnGcp(): Promise<boolean> {\n if (!cachedOnGcp) {\n cachedOnGcp = gcpMetadata.isAvailable();\n }\n return cachedOnGcp;\n}\n\n// gcp-metadata returns loosely-typed values; coerce every metadata read to a string\n// through this one helper so the rest of the file stays strongly typed.\n// webpieces-disable no-any-unknown -- single coercion point for gcp-metadata's loose return type\nfunction asString(value: unknown): string {\n return String(value);\n}\n\n/** GCP project id (e.g. 'my-project'). Only call when isOnGcp() is true. */\nexport function readProjectId(): Promise<string> {\n if (!cachedProjectId) {\n cachedProjectId = gcpMetadata.project('project-id').then(asString);\n }\n return cachedProjectId;\n}\n\n/** Numeric project id (used to build Cloud Run URLs). */\nexport function readNumericProjectId(): Promise<string> {\n if (!cachedNumericProjectId) {\n cachedNumericProjectId = gcpMetadata.project('numeric-project-id').then(asString);\n }\n return cachedNumericProjectId;\n}\n\n/** Cloud Run region (e.g. 'us-central1'), parsed from 'projects/<num>/regions/<region>'. */\nexport function readRegion(): Promise<string> {\n if (!cachedRegion) {\n cachedRegion = gcpMetadata.instance('region').then(asString).then((raw: string) => {\n const idx = raw.lastIndexOf('/');\n return idx >= 0 ? raw.substring(idx + 1) : raw;\n });\n }\n return cachedRegion;\n}\n\n/** The service-account email this process runs as. */\nexport function readRuntimeServiceAccountEmail(): Promise<string> {\n if (!cachedSaEmail) {\n cachedSaEmail = gcpMetadata.instance('service-accounts/default/email').then(asString);\n }\n return cachedSaEmail;\n}\n"]}
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../../../packages/cloud/gcp-identity/src/metadata.ts"],"names":[],"mappings":";;AAyBA,0BAQC;AAUD,sCAKC;AAGD,oDAKC;AAGD,gCAQC;AAGD,wEAKC;;AA3ED,kEAA4C;AAE5C;;;;;;;;;;GAUG;AAEH,IAAI,WAAyC,CAAC;AAC9C,IAAI,eAA4C,CAAC;AACjD,IAAI,sBAAmD,CAAC;AACxD,IAAI,YAAyC,CAAC;AAC9C,IAAI,aAA0C,CAAC;AAE/C;;;;GAIG;AACH,SAAgB,OAAO;IACnB,IAAI,CAAC,WAAW,EAAE,CAAC;QACf,MAAM,KAAK,GACP,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,SAAS;YACtC,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,KAAK,gBAAgB,CAAC;QAClE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,WAAW,CAAC;AACvB,CAAC;AAED,oFAAoF;AACpF,wEAAwE;AACxE,iGAAiG;AACjG,SAAS,QAAQ,CAAC,KAAc;IAC5B,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACzB,CAAC;AAED,4EAA4E;AAC5E,SAAgB,aAAa;IACzB,IAAI,CAAC,eAAe,EAAE,CAAC;QACnB,eAAe,GAAG,WAAW,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,eAAe,CAAC;AAC3B,CAAC;AAED,yDAAyD;AACzD,SAAgB,oBAAoB;IAChC,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAC1B,sBAAsB,GAAG,WAAW,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtF,CAAC;IACD,OAAO,sBAAsB,CAAC;AAClC,CAAC;AAED,4FAA4F;AAC5F,SAAgB,UAAU;IACtB,IAAI,CAAC,YAAY,EAAE,CAAC;QAChB,YAAY,GAAG,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,GAAW,EAAE,EAAE;YAC9E,MAAM,GAAG,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;YACjC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QACnD,CAAC,CAAC,CAAC;IACP,CAAC;IACD,OAAO,YAAY,CAAC;AACxB,CAAC;AAED,sDAAsD;AACtD,SAAgB,8BAA8B;IAC1C,IAAI,CAAC,aAAa,EAAE,CAAC;QACjB,aAAa,GAAG,WAAW,CAAC,QAAQ,CAAC,gCAAgC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC1F,CAAC;IACD,OAAO,aAAa,CAAC;AACzB,CAAC","sourcesContent":["import * as gcpMetadata from 'gcp-metadata';\n\n/**\n * Cached reads of the GCP metadata server. Every value is fetched at most once per\n * process (the metadata server is stable for the life of the instance). Off-GCP\n * `isOnGcp()` is false and the callers fall back to localhost values, so nothing\n * here is ever reached in local dev / tests.\n *\n * `isOnGcp()` is decided from the `K_SERVICE` env var (which Cloud Run always sets),\n * NOT a metadata network probe — so local dev never blocks on the ~3s\n * `gcpMetadata.isAvailable()` timeout. Every caller (project id, region, Cloud Run URL\n * resolution, OIDC minting, Cloud Tasks) short-circuits through this one gate.\n */\n\nlet cachedOnGcp: Promise<boolean> | undefined;\nlet cachedProjectId: Promise<string> | undefined;\nlet cachedNumericProjectId: Promise<string> | undefined;\nlet cachedRegion: Promise<string> | undefined;\nlet cachedSaEmail: Promise<string> | undefined;\n\n/**\n * True when running on GCP Cloud Run. Gated on `K_SERVICE` (set by Cloud Run) so local dev does NO\n * metadata network probe. For non-Cloud-Run GCP (GCE / Cloud Functions, which don't set `K_SERVICE`),\n * set `METADATA_SERVER_DETECTION=assume-present` to force on-GCP behavior.\n */\nexport function isOnGcp(): Promise<boolean> {\n if (!cachedOnGcp) {\n const onGcp =\n process.env['K_SERVICE'] !== undefined ||\n process.env['METADATA_SERVER_DETECTION'] === 'assume-present';\n cachedOnGcp = Promise.resolve(onGcp);\n }\n return cachedOnGcp;\n}\n\n// gcp-metadata returns loosely-typed values; coerce every metadata read to a string\n// through this one helper so the rest of the file stays strongly typed.\n// webpieces-disable no-any-unknown -- single coercion point for gcp-metadata's loose return type\nfunction asString(value: unknown): string {\n return String(value);\n}\n\n/** GCP project id (e.g. 'my-project'). Only call when isOnGcp() is true. */\nexport function readProjectId(): Promise<string> {\n if (!cachedProjectId) {\n cachedProjectId = gcpMetadata.project('project-id').then(asString);\n }\n return cachedProjectId;\n}\n\n/** Numeric project id (used to build Cloud Run URLs). */\nexport function readNumericProjectId(): Promise<string> {\n if (!cachedNumericProjectId) {\n cachedNumericProjectId = gcpMetadata.project('numeric-project-id').then(asString);\n }\n return cachedNumericProjectId;\n}\n\n/** Cloud Run region (e.g. 'us-central1'), parsed from 'projects/<num>/regions/<region>'. */\nexport function readRegion(): Promise<string> {\n if (!cachedRegion) {\n cachedRegion = gcpMetadata.instance('region').then(asString).then((raw: string) => {\n const idx = raw.lastIndexOf('/');\n return idx >= 0 ? raw.substring(idx + 1) : raw;\n });\n }\n return cachedRegion;\n}\n\n/** The service-account email this process runs as. */\nexport function readRuntimeServiceAccountEmail(): Promise<string> {\n if (!cachedSaEmail) {\n cachedSaEmail = gcpMetadata.instance('service-accounts/default/email').then(asString);\n }\n return cachedSaEmail;\n}\n"]}
package/src/urls.d.ts CHANGED
@@ -17,22 +17,18 @@ export declare function getRuntimeServiceAccountEmail(): Promise<string>;
17
17
  */
18
18
  export declare function getSelfCloudRunUrl(): Promise<string>;
19
19
  /**
20
- * Deterministic base URL for another Cloud Run service in the same project/region.
21
- * Off-GCP returns a non-routable placeholder (in-memory task/rpc dispatch never
22
- * actually fetches it during tests); a real local multi-service run can override
23
- * via the CLOUD_RUN_URL_<UPPER_SNAKE_NAME> env var.
24
- */
25
- export declare function getCloudRunUrl(serviceName: string): Promise<string>;
26
- /**
27
- * Resolve the base URL a client should call.
20
+ * Resolve the base URL a client should call for `svcName`. The ONE resolver every RPC / Cloud Tasks
21
+ * client uses. Precedence:
28
22
  *
29
- * We lookup your service in the same project, same region, and form the url from the container
30
- * information unless you pass in a targetUrl, so you do not have to maintain targetUrls. This
31
- * works across your demo, qa, prod environments as long as each environment is in its own
32
- * projectId, which is typical.
23
+ * 1. A {@link ClientRegistry} override wins this is how you reach anything the derivation cannot
24
+ * describe: a localhost port, another region, another project, a non-Cloud-Run host. Each
25
+ * environment populates the registry from its own per-env config.
26
+ * 2. Otherwise, on GCP the URL is DERIVED from the Cloud Run service name + project + region
27
+ * (via {@link isOnGcp}) — same project, same region, zero maintenance across demo/qa/prod.
28
+ * 3. Otherwise (off-GCP and unregistered) it THROWS — a missing mapping is a setup bug, not a
29
+ * silent mis-route.
33
30
  *
34
- * Supply `targetUrl` only to reach somewhere that lookup cannot describe another region,
35
- * another project, or a non-Cloud-Run host. It wins over `svcName`, which is then used purely
36
- * as the logging name.
31
+ * So clients carry ONLY a `svcName`; there is no per-client `targetUrl` (a client is built once but a
32
+ * URL is per-environment that belongs in the registry, not on the client).
37
33
  */
38
- export declare function resolveTargetUrl(svcName: string, targetUrl?: string): Promise<string>;
34
+ export declare function resolveServiceUrl(svcName: string): Promise<string>;
package/src/urls.js CHANGED
@@ -6,8 +6,8 @@ exports.getProjectId = getProjectId;
6
6
  exports.getRegion = getRegion;
7
7
  exports.getRuntimeServiceAccountEmail = getRuntimeServiceAccountEmail;
8
8
  exports.getSelfCloudRunUrl = getSelfCloudRunUrl;
9
- exports.getCloudRunUrl = getCloudRunUrl;
10
- exports.resolveTargetUrl = resolveTargetUrl;
9
+ exports.resolveServiceUrl = resolveServiceUrl;
10
+ const core_util_1 = require("@webpieces/core-util");
11
11
  const metadata_1 = require("./metadata");
12
12
  /** Local fallback SA email used off-GCP so 'self' caller checks are deterministic. */
13
13
  exports.LOCAL_SERVICE_ACCOUNT_EMAIL = 'local@localhost.invalid';
@@ -58,43 +58,32 @@ async function getSelfCloudRunUrl() {
58
58
  return `https://${kService}-${numericProjectId}.${region}.run.app`;
59
59
  }
60
60
  /**
61
- * Deterministic base URL for another Cloud Run service in the same project/region.
62
- * Off-GCP returns a non-routable placeholder (in-memory task/rpc dispatch never
63
- * actually fetches it during tests); a real local multi-service run can override
64
- * via the CLOUD_RUN_URL_<UPPER_SNAKE_NAME> env var.
61
+ * Resolve the base URL a client should call for `svcName`. The ONE resolver every RPC / Cloud Tasks
62
+ * client uses. Precedence:
63
+ *
64
+ * 1. A {@link ClientRegistry} override wins — this is how you reach anything the derivation cannot
65
+ * describe: a localhost port, another region, another project, a non-Cloud-Run host. Each
66
+ * environment populates the registry from its own per-env config.
67
+ * 2. Otherwise, on GCP the URL is DERIVED from the Cloud Run service name + project + region
68
+ * (via {@link isOnGcp}) — same project, same region, zero maintenance across demo/qa/prod.
69
+ * 3. Otherwise (off-GCP and unregistered) it THROWS — a missing mapping is a setup bug, not a
70
+ * silent mis-route.
71
+ *
72
+ * So clients carry ONLY a `svcName`; there is no per-client `targetUrl` (a client is built once but a
73
+ * URL is per-environment — that belongs in the registry, not on the client).
65
74
  */
66
- async function getCloudRunUrl(serviceName) {
67
- const override = process.env[`CLOUD_RUN_URL_${toEnvKey(serviceName)}`];
75
+ // webpieces-disable no-function-outside-class -- pure GCP url helper; every sibling in this module is a free function
76
+ async function resolveServiceUrl(svcName) {
77
+ const override = core_util_1.ClientRegistry.tryLookup(svcName);
68
78
  if (override) {
69
79
  return override;
70
80
  }
71
81
  if (!(await (0, metadata_1.isOnGcp)())) {
72
- return `http://${serviceName}.localhost.invalid`;
82
+ throw new Error(`No URL for service "${svcName}". On GCP it is derived from the Cloud Run service name; ` +
83
+ `off-GCP register it: ClientRegistry.addMapping(svcName, port) or addUrlMapping(svcName, url).`);
73
84
  }
74
85
  const numericProjectId = await (0, metadata_1.readNumericProjectId)();
75
86
  const region = await (0, metadata_1.readRegion)();
76
- return `https://${serviceName}-${numericProjectId}.${region}.run.app`;
77
- }
78
- /**
79
- * Resolve the base URL a client should call.
80
- *
81
- * We lookup your service in the same project, same region, and form the url from the container
82
- * information unless you pass in a targetUrl, so you do not have to maintain targetUrls. This
83
- * works across your demo, qa, prod environments as long as each environment is in its own
84
- * projectId, which is typical.
85
- *
86
- * Supply `targetUrl` only to reach somewhere that lookup cannot describe — another region,
87
- * another project, or a non-Cloud-Run host. It wins over `svcName`, which is then used purely
88
- * as the logging name.
89
- */
90
- // webpieces-disable no-function-outside-class -- pure GCP url helper; every sibling in this module is a free function
91
- async function resolveTargetUrl(svcName, targetUrl) {
92
- if (targetUrl) {
93
- return targetUrl;
94
- }
95
- return getCloudRunUrl(svcName);
96
- }
97
- function toEnvKey(serviceName) {
98
- return serviceName.toUpperCase().replace(/[^A-Z0-9]+/g, '_');
87
+ return `https://${svcName}-${numericProjectId}.${region}.run.app`;
99
88
  }
100
89
  //# sourceMappingURL=urls.js.map
package/src/urls.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"urls.js","sourceRoot":"","sources":["../../../../../packages/cloud/gcp-identity/src/urls.ts"],"names":[],"mappings":"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","sourcesContent":["import { isOnGcp, readNumericProjectId, readRegion, readProjectId, readRuntimeServiceAccountEmail } from './metadata';\n\n/** Local fallback SA email used off-GCP so 'self' caller checks are deterministic. */\nexport const LOCAL_SERVICE_ACCOUNT_EMAIL = 'local@localhost.invalid';\n\n/**\n * Logical service name from K_SERVICE (Cloud Run sets this), stripping a leading\n * 'tf-' Terraform prefix. Off-GCP returns 'local'. Synchronous — env only.\n */\nexport function getServiceName(): string {\n const kService = process.env['K_SERVICE'];\n if (!kService) {\n return 'local';\n }\n return kService.startsWith('tf-') ? kService.substring('tf-'.length) : kService;\n}\n\n/** GCP project id, or 'local-project' off-GCP. */\nexport async function getProjectId(): Promise<string> {\n if (!(await isOnGcp())) {\n return 'local-project';\n }\n return readProjectId();\n}\n\n/** Cloud Run region, or 'local' off-GCP. */\nexport async function getRegion(): Promise<string> {\n if (!(await isOnGcp())) {\n return 'local';\n }\n return readRegion();\n}\n\n/** The runtime SA email, or the local placeholder off-GCP. */\nexport async function getRuntimeServiceAccountEmail(): Promise<string> {\n if (!(await isOnGcp())) {\n return LOCAL_SERVICE_ACCOUNT_EMAIL;\n }\n return readRuntimeServiceAccountEmail();\n}\n\n/**\n * This service's own base URL (its Cloud Tasks self-enqueue target / public base).\n * Off-GCP → http://localhost:<PORT>.\n */\nexport async function getSelfCloudRunUrl(): Promise<string> {\n const kService = process.env['K_SERVICE'];\n if (!(await isOnGcp()) || !kService) {\n const port = process.env['PORT'] ?? '8080';\n return `http://localhost:${port}`;\n }\n const numericProjectId = await readNumericProjectId();\n const region = await readRegion();\n return `https://${kService}-${numericProjectId}.${region}.run.app`;\n}\n\n/**\n * Deterministic base URL for another Cloud Run service in the same project/region.\n * Off-GCP returns a non-routable placeholder (in-memory task/rpc dispatch never\n * actually fetches it during tests); a real local multi-service run can override\n * via the CLOUD_RUN_URL_<UPPER_SNAKE_NAME> env var.\n */\nexport async function getCloudRunUrl(serviceName: string): Promise<string> {\n const override = process.env[`CLOUD_RUN_URL_${toEnvKey(serviceName)}`];\n if (override) {\n return override;\n }\n if (!(await isOnGcp())) {\n return `http://${serviceName}.localhost.invalid`;\n }\n const numericProjectId = await readNumericProjectId();\n const region = await readRegion();\n return `https://${serviceName}-${numericProjectId}.${region}.run.app`;\n}\n\n/**\n * Resolve the base URL a client should call.\n *\n * We lookup your service in the same project, same region, and form the url from the container\n * information unless you pass in a targetUrl, so you do not have to maintain targetUrls. This\n * works across your demo, qa, prod environments as long as each environment is in its own\n * projectId, which is typical.\n *\n * Supply `targetUrl` only to reach somewhere that lookup cannot describe another region,\n * another project, or a non-Cloud-Run host. It wins over `svcName`, which is then used purely\n * as the logging name.\n */\n// webpieces-disable no-function-outside-class -- pure GCP url helper; every sibling in this module is a free function\nexport async function resolveTargetUrl(svcName: string, targetUrl?: string): Promise<string> {\n if (targetUrl) {\n return targetUrl;\n }\n return getCloudRunUrl(svcName);\n}\n\nfunction toEnvKey(serviceName: string): string {\n return serviceName.toUpperCase().replace(/[^A-Z0-9]+/g, '_');\n}\n"]}
1
+ {"version":3,"file":"urls.js","sourceRoot":"","sources":["../../../../../packages/cloud/gcp-identity/src/urls.ts"],"names":[],"mappings":";;;AAUA,wCAMC;AAGD,oCAKC;AAGD,8BAKC;AAGD,sEAKC;AAMD,gDASC;AAkBD,8CAcC;AAvFD,oDAAsD;AACtD,yCAAsH;AAEtH,sFAAsF;AACzE,QAAA,2BAA2B,GAAG,yBAAyB,CAAC;AAErE;;;GAGG;AACH,SAAgB,cAAc;IAC1B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC1C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACZ,OAAO,OAAO,CAAC;IACnB,CAAC;IACD,OAAO,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AACpF,CAAC;AAED,kDAAkD;AAC3C,KAAK,UAAU,YAAY;IAC9B,IAAI,CAAC,CAAC,MAAM,IAAA,kBAAO,GAAE,CAAC,EAAE,CAAC;QACrB,OAAO,eAAe,CAAC;IAC3B,CAAC;IACD,OAAO,IAAA,wBAAa,GAAE,CAAC;AAC3B,CAAC;AAED,4CAA4C;AACrC,KAAK,UAAU,SAAS;IAC3B,IAAI,CAAC,CAAC,MAAM,IAAA,kBAAO,GAAE,CAAC,EAAE,CAAC;QACrB,OAAO,OAAO,CAAC;IACnB,CAAC;IACD,OAAO,IAAA,qBAAU,GAAE,CAAC;AACxB,CAAC;AAED,8DAA8D;AACvD,KAAK,UAAU,6BAA6B;IAC/C,IAAI,CAAC,CAAC,MAAM,IAAA,kBAAO,GAAE,CAAC,EAAE,CAAC;QACrB,OAAO,mCAA2B,CAAC;IACvC,CAAC;IACD,OAAO,IAAA,yCAA8B,GAAE,CAAC;AAC5C,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,kBAAkB;IACpC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC1C,IAAI,CAAC,CAAC,MAAM,IAAA,kBAAO,GAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC;QAC3C,OAAO,oBAAoB,IAAI,EAAE,CAAC;IACtC,CAAC;IACD,MAAM,gBAAgB,GAAG,MAAM,IAAA,+BAAoB,GAAE,CAAC;IACtD,MAAM,MAAM,GAAG,MAAM,IAAA,qBAAU,GAAE,CAAC;IAClC,OAAO,WAAW,QAAQ,IAAI,gBAAgB,IAAI,MAAM,UAAU,CAAC;AACvE,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,sHAAsH;AAC/G,KAAK,UAAU,iBAAiB,CAAC,OAAe;IACnD,MAAM,QAAQ,GAAG,0BAAc,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACnD,IAAI,QAAQ,EAAE,CAAC;QACX,OAAO,QAAQ,CAAC;IACpB,CAAC;IACD,IAAI,CAAC,CAAC,MAAM,IAAA,kBAAO,GAAE,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CACX,uBAAuB,OAAO,2DAA2D;YACzF,+FAA+F,CAClG,CAAC;IACN,CAAC;IACD,MAAM,gBAAgB,GAAG,MAAM,IAAA,+BAAoB,GAAE,CAAC;IACtD,MAAM,MAAM,GAAG,MAAM,IAAA,qBAAU,GAAE,CAAC;IAClC,OAAO,WAAW,OAAO,IAAI,gBAAgB,IAAI,MAAM,UAAU,CAAC;AACtE,CAAC","sourcesContent":["import { ClientRegistry } from '@webpieces/core-util';\nimport { isOnGcp, readNumericProjectId, readRegion, readProjectId, readRuntimeServiceAccountEmail } from './metadata';\n\n/** Local fallback SA email used off-GCP so 'self' caller checks are deterministic. */\nexport const LOCAL_SERVICE_ACCOUNT_EMAIL = 'local@localhost.invalid';\n\n/**\n * Logical service name from K_SERVICE (Cloud Run sets this), stripping a leading\n * 'tf-' Terraform prefix. Off-GCP returns 'local'. Synchronous — env only.\n */\nexport function getServiceName(): string {\n const kService = process.env['K_SERVICE'];\n if (!kService) {\n return 'local';\n }\n return kService.startsWith('tf-') ? kService.substring('tf-'.length) : kService;\n}\n\n/** GCP project id, or 'local-project' off-GCP. */\nexport async function getProjectId(): Promise<string> {\n if (!(await isOnGcp())) {\n return 'local-project';\n }\n return readProjectId();\n}\n\n/** Cloud Run region, or 'local' off-GCP. */\nexport async function getRegion(): Promise<string> {\n if (!(await isOnGcp())) {\n return 'local';\n }\n return readRegion();\n}\n\n/** The runtime SA email, or the local placeholder off-GCP. */\nexport async function getRuntimeServiceAccountEmail(): Promise<string> {\n if (!(await isOnGcp())) {\n return LOCAL_SERVICE_ACCOUNT_EMAIL;\n }\n return readRuntimeServiceAccountEmail();\n}\n\n/**\n * This service's own base URL (its Cloud Tasks self-enqueue target / public base).\n * Off-GCP → http://localhost:<PORT>.\n */\nexport async function getSelfCloudRunUrl(): Promise<string> {\n const kService = process.env['K_SERVICE'];\n if (!(await isOnGcp()) || !kService) {\n const port = process.env['PORT'] ?? '8080';\n return `http://localhost:${port}`;\n }\n const numericProjectId = await readNumericProjectId();\n const region = await readRegion();\n return `https://${kService}-${numericProjectId}.${region}.run.app`;\n}\n\n/**\n * Resolve the base URL a client should call for `svcName`. The ONE resolver every RPC / Cloud Tasks\n * client uses. Precedence:\n *\n * 1. A {@link ClientRegistry} override wins this is how you reach anything the derivation cannot\n * describe: a localhost port, another region, another project, a non-Cloud-Run host. Each\n * environment populates the registry from its own per-env config.\n * 2. Otherwise, on GCP the URL is DERIVED from the Cloud Run service name + project + region\n * (via {@link isOnGcp}) same project, same region, zero maintenance across demo/qa/prod.\n * 3. Otherwise (off-GCP and unregistered) it THROWS a missing mapping is a setup bug, not a\n * silent mis-route.\n *\n * So clients carry ONLY a `svcName`; there is no per-client `targetUrl` (a client is built once but a\n * URL is per-environment that belongs in the registry, not on the client).\n */\n// webpieces-disable no-function-outside-class -- pure GCP url helper; every sibling in this module is a free function\nexport async function resolveServiceUrl(svcName: string): Promise<string> {\n const override = ClientRegistry.tryLookup(svcName);\n if (override) {\n return override;\n }\n if (!(await isOnGcp())) {\n throw new Error(\n `No URL for service \"${svcName}\". On GCP it is derived from the Cloud Run service name; ` +\n `off-GCP register it: ClientRegistry.addMapping(svcName, port) or addUrlMapping(svcName, url).`,\n );\n }\n const numericProjectId = await readNumericProjectId();\n const region = await readRegion();\n return `https://${svcName}-${numericProjectId}.${region}.run.app`;\n}\n"]}