@webpieces/core-util 0.4.921 → 0.4.923

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/core-util",
3
- "version": "0.4.921",
3
+ "version": "0.4.923",
4
4
  "description": "Utility functions for WebPieces - works in browser and Node.js",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -18,12 +18,15 @@ import { ApiKeyCredential, AuthMode } from './auth-mode';
18
18
  * with no security block, which is precisely the silent failure the argument exists to remove, so
19
19
  * `[]` is a compile error rather than a runtime throw (shim shape #4).
20
20
  * 3. {@link ApiKeyCredential} makes the two OpenAPI schemes MUTUALLY exclusive: a header credential
21
- * must carry its header name, and a bearer credential must NOT — its location IS `Authorization`,
22
- * so a `name` beside it would be a lie a generator has to guess about.
21
+ * must carry the ContextKey whose `httpHeader` it rides under, and a bearer credential must NOT —
22
+ * its location IS `Authorization`, so a key beside it would be a lie a generator has to guess about.
23
23
  * 4. The ONE-ARGUMENT `@apiKey('regime')` form is GONE. It could declare a key regime while
24
24
  * saying nothing about where the credential rides, which is the whole defect; per the
25
25
  * no-backwards-compatibility rule there is no overload and no optional second parameter left
26
26
  * behind, and this directive is what proves it.
27
+ * 5. The header-name STRING spelling `{ in: 'header', name: 'x-api-key' }` is GONE (#1249). A header
28
+ * is defined ONCE, as a ContextKey, and named by that key everywhere; a string here was a second
29
+ * copy a rename leaves silently stale.
27
30
  *
28
31
  * The EXHAUSTIVENESS half needs no directive: `apiKeyIsCoveredExhaustively` below returns on every
29
32
  * branch with no `default`, so dropping the `apikey` case makes tsc fail with TS7030 (not all code
@@ -31,6 +34,8 @@ import { ApiKeyCredential, AuthMode } from './auth-mode';
31
34
  * `DestinationTrust.forAuthMode` rely on, asserted here where it cannot be edited away by accident.
32
35
  */
33
36
  export declare class AuthApiKeyCompileAssertions {
37
+ private static readonly API_KEY;
38
+ private static readonly ORG_ID;
34
39
  /** The one legitimate spelling must keep compiling; asserted by the ABSENCE of an error. */
35
40
  legitimate(): AuthMode;
36
41
  /** The bearer branch, likewise asserted by the ABSENCE of an error. */
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AuthApiKeyCompileAssertions = void 0;
4
+ const ContextKey_1 = require("../ContextKey");
4
5
  const auth_mode_1 = require("./auth-mode");
5
6
  const decorators_1 = require("./decorators");
6
7
  /**
@@ -22,12 +23,15 @@ const decorators_1 = require("./decorators");
22
23
  * with no security block, which is precisely the silent failure the argument exists to remove, so
23
24
  * `[]` is a compile error rather than a runtime throw (shim shape #4).
24
25
  * 3. {@link ApiKeyCredential} makes the two OpenAPI schemes MUTUALLY exclusive: a header credential
25
- * must carry its header name, and a bearer credential must NOT — its location IS `Authorization`,
26
- * so a `name` beside it would be a lie a generator has to guess about.
26
+ * must carry the ContextKey whose `httpHeader` it rides under, and a bearer credential must NOT —
27
+ * its location IS `Authorization`, so a key beside it would be a lie a generator has to guess about.
27
28
  * 4. The ONE-ARGUMENT `@apiKey('regime')` form is GONE. It could declare a key regime while
28
29
  * saying nothing about where the credential rides, which is the whole defect; per the
29
30
  * no-backwards-compatibility rule there is no overload and no optional second parameter left
30
31
  * behind, and this directive is what proves it.
32
+ * 5. The header-name STRING spelling `{ in: 'header', name: 'x-api-key' }` is GONE (#1249). A header
33
+ * is defined ONCE, as a ContextKey, and named by that key everywhere; a string here was a second
34
+ * copy a rename leaves silently stale.
31
35
  *
32
36
  * The EXHAUSTIVENESS half needs no directive: `apiKeyIsCoveredExhaustively` below returns on every
33
37
  * branch with no `default`, so dropping the `apikey` case makes tsc fail with TS7030 (not all code
@@ -35,6 +39,8 @@ const decorators_1 = require("./decorators");
35
39
  * `DestinationTrust.forAuthMode` rely on, asserted here where it cannot be edited away by accident.
36
40
  */
37
41
  class AuthApiKeyCompileAssertions {
42
+ static API_KEY = ContextKey_1.ContextKey.untrusted('apiKey', 'x-api-key', true);
43
+ static ORG_ID = ContextKey_1.ContextKey.untrusted('organizationId', 'x-organization-id');
38
44
  /** The one legitimate spelling must keep compiling; asserted by the ABSENCE of an error. */
39
45
  legitimate() {
40
46
  const mode = {
@@ -43,10 +49,10 @@ class AuthApiKeyCompileAssertions {
43
49
  credentials: [
44
50
  {
45
51
  in: 'header',
46
- name: 'x-api-key',
52
+ key: AuthApiKeyCompileAssertions.API_KEY,
47
53
  description: 'The key issued to your integration.',
48
54
  },
49
- { in: 'header', name: 'x-organization-id' },
55
+ { in: 'header', key: AuthApiKeyCompileAssertions.ORG_ID },
50
56
  ],
51
57
  };
52
58
  return mode;
@@ -61,14 +67,14 @@ class AuthApiKeyCompileAssertions {
61
67
  }
62
68
  /** apiKey takes regime and credentials; WpAuth wraps the descriptor in a nonempty list. */
63
69
  legitimateDecorator() {
64
- return (0, decorators_1.WpAuth)([(0, auth_mode_1.apiKey)('onetablet-partner', [{ in: 'header', name: 'x-api-key' }])]);
70
+ return (0, decorators_1.WpAuth)([(0, auth_mode_1.apiKey)('onetablet-partner', [{ in: 'header', key: AuthApiKeyCompileAssertions.API_KEY }])]);
65
71
  }
66
72
  /** Every one of these must be UNWRITABLE. A directive going unused here fails the build. */
67
73
  rejected() {
68
74
  // @ts-expect-error `regime` is REQUIRED — it selects which key regime, so it cannot be omitted
69
75
  const noRegime = {
70
76
  kind: 'apikey',
71
- credentials: [{ in: 'header', name: 'x-api-key' }],
77
+ credentials: [{ in: 'header', key: AuthApiKeyCompileAssertions.API_KEY }],
72
78
  };
73
79
  void noRegime;
74
80
  // @ts-expect-error `credentials` is REQUIRED — a regime that declares no location is the defect
@@ -81,17 +87,23 @@ class AuthApiKeyCompileAssertions {
81
87
  // @ts-expect-error the discriminant is 'apikey'; 'api-key' is not a member of the union
82
88
  kind: 'api-key',
83
89
  regime: 'onetablet-partner',
84
- credentials: [{ in: 'header', name: 'x-api-key' }],
90
+ credentials: [{ in: 'header', key: AuthApiKeyCompileAssertions.API_KEY }],
85
91
  };
86
92
  void misspelled;
87
- // @ts-expect-error bearer's location IS `Authorization`; a header name beside it is a lie
88
- const bearerWithName = { in: 'bearer', name: 'x-api-key' };
89
- void bearerWithName;
90
- // @ts-expect-error a header credential with no header name cannot become a securityScheme
91
- const headerWithNoName = { in: 'header' };
92
- void headerWithNoName;
93
+ // @ts-expect-error bearer's location IS `Authorization`; a ContextKey beside it is a lie
94
+ const bearerWithKey = { in: 'bearer', key: AuthApiKeyCompileAssertions.API_KEY };
95
+ void bearerWithKey;
96
+ // @ts-expect-error a header credential with no ContextKey cannot become a securityScheme
97
+ const headerWithNoKey = { in: 'header' };
98
+ void headerWithNoKey;
99
+ // @ts-expect-error the header-name STRING spelling is deleted — name the ContextKey: `key: MyKeys.API_KEY`
100
+ const headerNameString = { in: 'header', name: 'x-api-key' };
101
+ void headerNameString;
102
+ // @ts-expect-error `key` is a ContextKey, never the header name itself
103
+ const keyAsString = { in: 'header', key: 'x-api-key' };
104
+ void keyAsString;
93
105
  // @ts-expect-error 'query' is not reachable — the framework declares only these two locations
94
- const unknownLocation = { in: 'query', name: 'api_key' };
106
+ const unknownLocation = { in: 'query', key: AuthApiKeyCompileAssertions.API_KEY };
95
107
  void unknownLocation;
96
108
  }
97
109
  /** The apiKey descriptor requires an explicit credential list; no one-argument form exists. */
@@ -1 +1 @@
1
- {"version":3,"file":"WpAuthApiKeyCompileAssertions.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/WpAuthApiKeyCompileAssertions.ts"],"names":[],"mappings":"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","sourcesContent":["import { apiKey, ApiKeyCredential, AuthMode } from './auth-mode';\nimport { WpAuth } from './decorators';\n\n/**\n * COMPILE-TIME assertions for the `apikey` member of the {@link AuthMode} union and for the\n * {@link apiKey} descriptor and {@link WpAuth} signature. Each `@ts-expect-error` below FAILS THE BUILD (TS2578, \"unused\n * '@ts-expect-error' directive\") if the line it guards ever starts compiling.\n *\n * WHY THIS IS NOT A `.spec.ts` FILE — same reason as its sibling `AuthJwtCompileAssertions.ts`:\n * tsconfig.lib.json EXCLUDES specs and vitest strips types with esbuild, so a `@ts-expect-error` in a\n * spec is inert and the suite passes whether or not the guarded line really errors.\n *\n * WHAT IT PINS.\n *\n * 1. The union member is `{ kind: 'apikey'; regime: string; credentials: [...] }` and nothing looser.\n * `regime` is the lookup key selecting WHICH key regime a route belongs to, so a mode with no\n * regime — or spelled `api-key`, which is what a reader guesses from the decorator — must not\n * type-check its way into a switch that would then silently miss it.\n * 2. `credentials` is NON-EMPTY. A regime that names no credential generates a published document\n * with no security block, which is precisely the silent failure the argument exists to remove, so\n * `[]` is a compile error rather than a runtime throw (shim shape #4).\n * 3. {@link ApiKeyCredential} makes the two OpenAPI schemes MUTUALLY exclusive: a header credential\n * must carry its header name, and a bearer credential must NOT — its location IS `Authorization`,\n * so a `name` beside it would be a lie a generator has to guess about.\n * 4. The ONE-ARGUMENT `@apiKey('regime')` form is GONE. It could declare a key regime while\n * saying nothing about where the credential rides, which is the whole defect; per the\n * no-backwards-compatibility rule there is no overload and no optional second parameter left\n * behind, and this directive is what proves it.\n *\n * The EXHAUSTIVENESS half needs no directive: `apiKeyIsCoveredExhaustively` below returns on every\n * branch with no `default`, so dropping the `apikey` case makes tsc fail with TS7030 (not all code\n * paths return a value). That is the same property `AuthFilter.verifiesCaller` and\n * `DestinationTrust.forAuthMode` rely on, asserted here where it cannot be edited away by accident.\n */\nexport class AuthApiKeyCompileAssertions {\n /** The one legitimate spelling must keep compiling; asserted by the ABSENCE of an error. */\n legitimate(): AuthMode {\n const mode: AuthMode = {\n kind: 'apikey',\n regime: 'onetablet-partner',\n credentials: [\n {\n in: 'header',\n name: 'x-api-key',\n description: 'The key issued to your integration.',\n },\n { in: 'header', name: 'x-organization-id' },\n ],\n };\n return mode;\n }\n\n /** The bearer branch, likewise asserted by the ABSENCE of an error. */\n legitimateBearer(): ApiKeyCredential {\n const credential: ApiKeyCredential = {\n in: 'bearer',\n description: 'Send the key as a bearer token.',\n };\n return credential;\n }\n\n /** apiKey takes regime and credentials; WpAuth wraps the descriptor in a nonempty list. */\n legitimateDecorator(): MethodDecorator {\n return WpAuth([apiKey('onetablet-partner', [{ in: 'header', name: 'x-api-key' }])]);\n }\n\n /** Every one of these must be UNWRITABLE. A directive going unused here fails the build. */\n rejected(): void {\n // @ts-expect-error `regime` is REQUIRED — it selects which key regime, so it cannot be omitted\n const noRegime: AuthMode = {\n kind: 'apikey',\n credentials: [{ in: 'header', name: 'x-api-key' }],\n };\n void noRegime;\n // @ts-expect-error `credentials` is REQUIRED — a regime that declares no location is the defect\n const noCredentials: AuthMode = { kind: 'apikey', regime: 'onetablet-partner' };\n void noCredentials;\n // @ts-expect-error EMPTY is not a widening — it would emit a document with no security block\n const empty: AuthMode = { kind: 'apikey', regime: 'onetablet-partner', credentials: [] };\n void empty;\n const misspelled: AuthMode = {\n // @ts-expect-error the discriminant is 'apikey'; 'api-key' is not a member of the union\n kind: 'api-key',\n regime: 'onetablet-partner',\n credentials: [{ in: 'header', name: 'x-api-key' }],\n };\n void misspelled;\n // @ts-expect-error bearer's location IS `Authorization`; a header name beside it is a lie\n const bearerWithName: ApiKeyCredential = { in: 'bearer', name: 'x-api-key' };\n void bearerWithName;\n // @ts-expect-error a header credential with no header name cannot become a securityScheme\n const headerWithNoName: ApiKeyCredential = { in: 'header' };\n void headerWithNoName;\n // @ts-expect-error 'query' is not reachable — the framework declares only these two locations\n const unknownLocation: ApiKeyCredential = { in: 'query', name: 'api_key' };\n void unknownLocation;\n }\n\n /** The apiKey descriptor requires an explicit credential list; no one-argument form exists. */\n oneArgumentFormIsGone(): void {\n // @ts-expect-error apiKey requires regime and credentials\n const legacy = apiKey('onetablet-partner');\n void legacy;\n }\n\n /**\n * Exhaustiveness, stated as code: NO `default`, a return on every branch. Deleting the `apikey`\n * case turns this into TS7030 — the compile error that forces a DECISION about a new mode's trust\n * posture rather than letting it land on one by accident.\n */\n apiKeyIsCoveredExhaustively(mode: AuthMode): string {\n switch (mode.kind) {\n case 'public':\n return 'public';\n case 'jwt':\n return 'jwt';\n case 'oidc':\n return 'oidc';\n case 'shared-secret':\n return 'shared-secret';\n case 'webhook':\n return 'webhook';\n case 'apikey':\n return 'apikey';\n }\n }\n}\n"]}
1
+ {"version":3,"file":"WpAuthApiKeyCompileAssertions.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/WpAuthApiKeyCompileAssertions.ts"],"names":[],"mappings":"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","sourcesContent":["import { ContextKey } from '../ContextKey';\nimport { apiKey, ApiKeyCredential, AuthMode } from './auth-mode';\nimport { WpAuth } from './decorators';\n\n/**\n * COMPILE-TIME assertions for the `apikey` member of the {@link AuthMode} union and for the\n * {@link apiKey} descriptor and {@link WpAuth} signature. Each `@ts-expect-error` below FAILS THE BUILD (TS2578, \"unused\n * '@ts-expect-error' directive\") if the line it guards ever starts compiling.\n *\n * WHY THIS IS NOT A `.spec.ts` FILE — same reason as its sibling `AuthJwtCompileAssertions.ts`:\n * tsconfig.lib.json EXCLUDES specs and vitest strips types with esbuild, so a `@ts-expect-error` in a\n * spec is inert and the suite passes whether or not the guarded line really errors.\n *\n * WHAT IT PINS.\n *\n * 1. The union member is `{ kind: 'apikey'; regime: string; credentials: [...] }` and nothing looser.\n * `regime` is the lookup key selecting WHICH key regime a route belongs to, so a mode with no\n * regime — or spelled `api-key`, which is what a reader guesses from the decorator — must not\n * type-check its way into a switch that would then silently miss it.\n * 2. `credentials` is NON-EMPTY. A regime that names no credential generates a published document\n * with no security block, which is precisely the silent failure the argument exists to remove, so\n * `[]` is a compile error rather than a runtime throw (shim shape #4).\n * 3. {@link ApiKeyCredential} makes the two OpenAPI schemes MUTUALLY exclusive: a header credential\n * must carry the ContextKey whose `httpHeader` it rides under, and a bearer credential must NOT —\n * its location IS `Authorization`, so a key beside it would be a lie a generator has to guess about.\n * 4. The ONE-ARGUMENT `@apiKey('regime')` form is GONE. It could declare a key regime while\n * saying nothing about where the credential rides, which is the whole defect; per the\n * no-backwards-compatibility rule there is no overload and no optional second parameter left\n * behind, and this directive is what proves it.\n * 5. The header-name STRING spelling `{ in: 'header', name: 'x-api-key' }` is GONE (#1249). A header\n * is defined ONCE, as a ContextKey, and named by that key everywhere; a string here was a second\n * copy a rename leaves silently stale.\n *\n * The EXHAUSTIVENESS half needs no directive: `apiKeyIsCoveredExhaustively` below returns on every\n * branch with no `default`, so dropping the `apikey` case makes tsc fail with TS7030 (not all code\n * paths return a value). That is the same property `AuthFilter.verifiesCaller` and\n * `DestinationTrust.forAuthMode` rely on, asserted here where it cannot be edited away by accident.\n */\nexport class AuthApiKeyCompileAssertions {\n private static readonly API_KEY = ContextKey.untrusted<string>('apiKey', 'x-api-key', true);\n private static readonly ORG_ID = ContextKey.untrusted<string>('organizationId', 'x-organization-id');\n\n /** The one legitimate spelling must keep compiling; asserted by the ABSENCE of an error. */\n legitimate(): AuthMode {\n const mode: AuthMode = {\n kind: 'apikey',\n regime: 'onetablet-partner',\n credentials: [\n {\n in: 'header',\n key: AuthApiKeyCompileAssertions.API_KEY,\n description: 'The key issued to your integration.',\n },\n { in: 'header', key: AuthApiKeyCompileAssertions.ORG_ID },\n ],\n };\n return mode;\n }\n\n /** The bearer branch, likewise asserted by the ABSENCE of an error. */\n legitimateBearer(): ApiKeyCredential {\n const credential: ApiKeyCredential = {\n in: 'bearer',\n description: 'Send the key as a bearer token.',\n };\n return credential;\n }\n\n /** apiKey takes regime and credentials; WpAuth wraps the descriptor in a nonempty list. */\n legitimateDecorator(): MethodDecorator {\n return WpAuth([apiKey('onetablet-partner', [{ in: 'header', key: AuthApiKeyCompileAssertions.API_KEY }])]);\n }\n\n /** Every one of these must be UNWRITABLE. A directive going unused here fails the build. */\n rejected(): void {\n // @ts-expect-error `regime` is REQUIRED — it selects which key regime, so it cannot be omitted\n const noRegime: AuthMode = {\n kind: 'apikey',\n credentials: [{ in: 'header', key: AuthApiKeyCompileAssertions.API_KEY }],\n };\n void noRegime;\n // @ts-expect-error `credentials` is REQUIRED — a regime that declares no location is the defect\n const noCredentials: AuthMode = { kind: 'apikey', regime: 'onetablet-partner' };\n void noCredentials;\n // @ts-expect-error EMPTY is not a widening — it would emit a document with no security block\n const empty: AuthMode = { kind: 'apikey', regime: 'onetablet-partner', credentials: [] };\n void empty;\n const misspelled: AuthMode = {\n // @ts-expect-error the discriminant is 'apikey'; 'api-key' is not a member of the union\n kind: 'api-key',\n regime: 'onetablet-partner',\n credentials: [{ in: 'header', key: AuthApiKeyCompileAssertions.API_KEY }],\n };\n void misspelled;\n // @ts-expect-error bearer's location IS `Authorization`; a ContextKey beside it is a lie\n const bearerWithKey: ApiKeyCredential = { in: 'bearer', key: AuthApiKeyCompileAssertions.API_KEY };\n void bearerWithKey;\n // @ts-expect-error a header credential with no ContextKey cannot become a securityScheme\n const headerWithNoKey: ApiKeyCredential = { in: 'header' };\n void headerWithNoKey;\n // @ts-expect-error the header-name STRING spelling is deleted — name the ContextKey: `key: MyKeys.API_KEY`\n const headerNameString: ApiKeyCredential = { in: 'header', name: 'x-api-key' };\n void headerNameString;\n // @ts-expect-error `key` is a ContextKey, never the header name itself\n const keyAsString: ApiKeyCredential = { in: 'header', key: 'x-api-key' };\n void keyAsString;\n // @ts-expect-error 'query' is not reachable — the framework declares only these two locations\n const unknownLocation: ApiKeyCredential = { in: 'query', key: AuthApiKeyCompileAssertions.API_KEY };\n void unknownLocation;\n }\n\n /** The apiKey descriptor requires an explicit credential list; no one-argument form exists. */\n oneArgumentFormIsGone(): void {\n // @ts-expect-error apiKey requires regime and credentials\n const legacy = apiKey('onetablet-partner');\n void legacy;\n }\n\n /**\n * Exhaustiveness, stated as code: NO `default`, a return on every branch. Deleting the `apikey`\n * case turns this into TS7030 — the compile error that forces a DECISION about a new mode's trust\n * posture rather than letting it land on one by accident.\n */\n apiKeyIsCoveredExhaustively(mode: AuthMode): string {\n switch (mode.kind) {\n case 'public':\n return 'public';\n case 'jwt':\n return 'jwt';\n case 'oidc':\n return 'oidc';\n case 'shared-secret':\n return 'shared-secret';\n case 'webhook':\n return 'webhook';\n case 'apikey':\n return 'apikey';\n }\n }\n}\n"]}
@@ -1,10 +1,22 @@
1
+ import type { AnyContextKey } from '../ContextKey';
2
+ /**
3
+ * WHERE one api-key credential rides.
4
+ *
5
+ * A header credential names the {@link AnyContextKey ContextKey} that carries it — NEVER a header-name
6
+ * string. The key's `httpHeader` is the wire name, so the ONE definition of each header (the
7
+ * ContextKey) is reused on every surface: `RequestContext` put/get, the client/server header
8
+ * transfer, this declaration, and the published OpenAPI document. A string here was a second copy a
9
+ * rename left stale (#1249). The key MUST declare an `httpHeader` — {@link AuthDeclaration} refuses
10
+ * one that does not, and the OpenAPI generator reads the header name off the key's
11
+ * `ContextKey.trusted(...)` / `ContextKey.untrusted(...)` definition.
12
+ */
1
13
  export type ApiKeyCredential = {
2
14
  in: 'header';
3
- name: string;
15
+ key: AnyContextKey;
4
16
  description?: string;
5
17
  } | {
6
18
  in: 'bearer';
7
- name?: never;
19
+ key?: never;
8
20
  description?: string;
9
21
  };
10
22
  export type ApiKeyCredentials = readonly [ApiKeyCredential, ...ApiKeyCredential[]];
@@ -39,6 +51,14 @@ export declare class AuthMeta {
39
51
  export declare class AuthDeclaration {
40
52
  static validate(meta: AuthMeta): void;
41
53
  private static validateMethod;
54
+ /**
55
+ * A header credential's key must be a ContextKey that rides the wire. `httpHeader` is optional on
56
+ * ContextKey itself (most keys never leave the process), and the factories' explicit value-type
57
+ * argument (`ContextKey.untrusted<string>(...)`) stops TypeScript inferring whether one was
58
+ * passed, so the type cannot say "a key WITH a header". It is checked once, when the contract is
59
+ * decorated, and the OpenAPI generator refuses the same key statically.
60
+ */
61
+ private static requireHeaderKey;
42
62
  private static requireText;
43
63
  }
44
64
  export declare function jwt(): AuthMethod;
@@ -75,8 +75,8 @@ class AuthDeclaration {
75
75
  throw new Error('apiKey(...) requires a nonempty credentials tuple.');
76
76
  for (const credential of method.credentials) {
77
77
  if (credential.in === 'header')
78
- this.requireText(credential.name, 'apiKey header');
79
- else if (credential.in !== 'bearer' || Object.hasOwn(credential, 'name'))
78
+ this.requireHeaderKey(credential.key);
79
+ else if (credential.in !== 'bearer' || Object.hasOwn(credential, 'key'))
80
80
  throw new Error('Invalid API-key credential location.');
81
81
  }
82
82
  break;
@@ -87,6 +87,22 @@ class AuthDeclaration {
87
87
  throw new Error(`Auth method rejects '${key}'; operation policy belongs in @WpAuthorization.`);
88
88
  }
89
89
  }
90
+ /**
91
+ * A header credential's key must be a ContextKey that rides the wire. `httpHeader` is optional on
92
+ * ContextKey itself (most keys never leave the process), and the factories' explicit value-type
93
+ * argument (`ContextKey.untrusted<string>(...)`) stops TypeScript inferring whether one was
94
+ * passed, so the type cannot say "a key WITH a header". It is checked once, when the contract is
95
+ * decorated, and the OpenAPI generator refuses the same key statically.
96
+ */
97
+ // webpieces-disable no-function-outside-class -- stateless contract validation or scope metadata reader used before DI registration
98
+ static requireHeaderKey(key) {
99
+ if (!key || typeof key !== 'object' || typeof key.name !== 'string') {
100
+ throw new Error("apiKey header credential requires `key`: the ContextKey carrying it, e.g. { in: 'header', key: MyKeys.API_KEY }.");
101
+ }
102
+ if (typeof key.httpHeader !== 'string' || !key.httpHeader.trim()) {
103
+ throw new Error(`apiKey header credential key '${key.name}' declares no httpHeader; define it with ContextKey.trusted(name, provenance, '<header>') or ContextKey.untrusted(name, '<header>').`);
104
+ }
105
+ }
90
106
  // webpieces-disable no-function-outside-class -- stateless contract validation or scope metadata reader used before DI registration
91
107
  static requireText(value, label) {
92
108
  if (typeof value !== 'string' || !value.trim())
@@ -1 +1 @@
1
- {"version":3,"file":"auth-mode.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/auth-mode.ts"],"names":[],"mappings":"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","sourcesContent":["export type ApiKeyCredential =\n | { in: 'header'; name: string; description?: string }\n | { in: 'bearer'; name?: never; description?: string };\n\nexport type ApiKeyCredentials = readonly [ApiKeyCredential, ...ApiKeyCredential[]];\n\n/** One concrete mechanism; user policy belongs exclusively to WpAuthorization. */\nexport type AuthMethod =\n | { kind: 'jwt' }\n | { kind: 'oidc'; callers: readonly string[] }\n | { kind: 'shared-secret'; secretKey: string }\n | { kind: 'webhook'; name: string }\n | { kind: 'apikey'; regime: string; credentials: ApiKeyCredentials };\n\nexport type AuthMethods = readonly [AuthMethod, ...AuthMethod[]];\nexport type AuthMode = AuthMethod | { kind: 'public' };\n\n/** Alternatives remain unresolved until a concrete mechanism is chosen for this hop. */\nexport class AuthMeta {\n readonly methods: readonly [AuthMode, ...AuthMode[]];\n\n constructor(\n methods: readonly [AuthMode, ...AuthMode[]],\n public readonly publicReason: string | undefined,\n ) {\n this.methods = methods;\n AuthDeclaration.validate(this);\n this.methods = Object.freeze(methods.map((method: AuthMode) => AuthMeta.snapshot(method))) as readonly [AuthMode, ...AuthMode[]];\n Object.freeze(this);\n }\n\n // webpieces-disable no-function-outside-class -- stateless contract validation or scope metadata reader used before DI registration\n private static snapshot(method: AuthMode): AuthMode {\n switch (method.kind) {\n case 'oidc': return Object.freeze({ ...method, callers: Object.freeze([...method.callers]) });\n case 'apikey': return Object.freeze({ ...method, credentials: Object.freeze(method.credentials.map((credential: ApiKeyCredential) => Object.freeze({ ...credential }))) as ApiKeyCredentials });\n default: return Object.freeze({ ...method });\n }\n }\n}\n\nexport class AuthDeclaration {\n // webpieces-disable no-function-outside-class -- stateless contract validation or scope metadata reader used before DI registration\n static validate(meta: AuthMeta): void {\n if (!Array.isArray(meta.methods) || meta.methods.length === 0) throw new Error('@WpAuth requires a nonempty methods tuple.');\n const kinds = new Set<string>();\n for (const method of meta.methods) {\n if (!method || typeof method !== 'object' || kinds.has(method.kind)) throw new Error('@WpAuth rejects duplicate or invalid credential methods.');\n kinds.add(method.kind);\n this.validateMethod(method);\n }\n if (kinds.has('public')) {\n if (meta.methods.length !== 1 || typeof meta.publicReason !== 'string' || !meta.publicReason.trim()) {\n throw new Error('Public auth must be declared separately with @WpAuthPublic(reason).');\n }\n } else if (meta.publicReason !== undefined) throw new Error('Protected @WpAuth rejects public reasons.');\n }\n\n // webpieces-disable no-function-outside-class -- stateless contract validation or scope metadata reader used before DI registration\n private static validateMethod(method: AuthMode): void {\n let keys: readonly string[];\n switch (method.kind) {\n case 'jwt':\n case 'public': keys = ['kind']; break;\n case 'oidc':\n keys = ['kind', 'callers'];\n if (!Array.isArray(method.callers) || !method.callers.every((caller: string) => typeof caller === 'string' && caller.trim().length > 0)) throw new Error('oidc(...) requires valid caller names.');\n break;\n case 'shared-secret':\n keys = ['kind', 'secretKey'];\n this.requireText(method.secretKey, 'sharedSecret'); break;\n case 'webhook':\n keys = ['kind', 'name'];\n this.requireText(method.name, 'webhook'); break;\n case 'apikey':\n keys = ['kind', 'regime', 'credentials'];\n this.requireText(method.regime, 'apiKey');\n if (!Array.isArray(method.credentials) || !method.credentials.length) throw new Error('apiKey(...) requires a nonempty credentials tuple.');\n for (const credential of method.credentials) {\n if (credential.in === 'header') this.requireText(credential.name, 'apiKey header');\n else if (credential.in !== 'bearer' || Object.hasOwn(credential, 'name')) throw new Error('Invalid API-key credential location.');\n }\n break;\n default: throw new Error('Unknown @WpAuth method; use jwt/oidc/sharedSecret/webhook/apiKey descriptors.');\n }\n for (const key of Object.keys(method)) {\n if (!keys.includes(key)) throw new Error(`Auth method rejects '${key}'; operation policy belongs in @WpAuthorization.`);\n }\n }\n\n // webpieces-disable no-function-outside-class -- stateless contract validation or scope metadata reader used before DI registration\n private static requireText(value: string, label: string): void {\n if (typeof value !== 'string' || !value.trim()) throw new Error(`${label} requires a nonempty name.`);\n }\n}\n\n// webpieces-disable no-function-outside-class -- canonical credential descriptor factory\nexport function jwt(): AuthMethod { return { kind: 'jwt' }; }\n// webpieces-disable no-function-outside-class -- canonical credential descriptor factory\nexport function oidc(...callers: string[]): AuthMethod { return { kind: 'oidc', callers }; }\n// webpieces-disable no-function-outside-class -- canonical credential descriptor factory\nexport function sharedSecret(secretKey: string): AuthMethod { return { kind: 'shared-secret', secretKey }; }\n// webpieces-disable no-function-outside-class -- canonical credential descriptor factory\nexport function webhook(name: string): AuthMethod { return { kind: 'webhook', name }; }\n// webpieces-disable no-function-outside-class -- canonical credential descriptor factory\nexport function apiKey(regime: string, credentials: ApiKeyCredentials): AuthMethod { return { kind: 'apikey', regime, credentials }; }\n"]}
1
+ {"version":3,"file":"auth-mode.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/auth-mode.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AnyContextKey } from '../ContextKey';\n\n/**\n * WHERE one api-key credential rides.\n *\n * A header credential names the {@link AnyContextKey ContextKey} that carries it — NEVER a header-name\n * string. The key's `httpHeader` is the wire name, so the ONE definition of each header (the\n * ContextKey) is reused on every surface: `RequestContext` put/get, the client/server header\n * transfer, this declaration, and the published OpenAPI document. A string here was a second copy a\n * rename left stale (#1249). The key MUST declare an `httpHeader` — {@link AuthDeclaration} refuses\n * one that does not, and the OpenAPI generator reads the header name off the key's\n * `ContextKey.trusted(...)` / `ContextKey.untrusted(...)` definition.\n */\nexport type ApiKeyCredential =\n | { in: 'header'; key: AnyContextKey; description?: string }\n | { in: 'bearer'; key?: never; description?: string };\n\nexport type ApiKeyCredentials = readonly [ApiKeyCredential, ...ApiKeyCredential[]];\n\n/** One concrete mechanism; user policy belongs exclusively to WpAuthorization. */\nexport type AuthMethod =\n | { kind: 'jwt' }\n | { kind: 'oidc'; callers: readonly string[] }\n | { kind: 'shared-secret'; secretKey: string }\n | { kind: 'webhook'; name: string }\n | { kind: 'apikey'; regime: string; credentials: ApiKeyCredentials };\n\nexport type AuthMethods = readonly [AuthMethod, ...AuthMethod[]];\nexport type AuthMode = AuthMethod | { kind: 'public' };\n\n/** Alternatives remain unresolved until a concrete mechanism is chosen for this hop. */\nexport class AuthMeta {\n readonly methods: readonly [AuthMode, ...AuthMode[]];\n\n constructor(\n methods: readonly [AuthMode, ...AuthMode[]],\n public readonly publicReason: string | undefined,\n ) {\n this.methods = methods;\n AuthDeclaration.validate(this);\n this.methods = Object.freeze(methods.map((method: AuthMode) => AuthMeta.snapshot(method))) as readonly [AuthMode, ...AuthMode[]];\n Object.freeze(this);\n }\n\n // webpieces-disable no-function-outside-class -- stateless contract validation or scope metadata reader used before DI registration\n private static snapshot(method: AuthMode): AuthMode {\n switch (method.kind) {\n case 'oidc': return Object.freeze({ ...method, callers: Object.freeze([...method.callers]) });\n case 'apikey': return Object.freeze({ ...method, credentials: Object.freeze(method.credentials.map((credential: ApiKeyCredential) => Object.freeze({ ...credential }))) as ApiKeyCredentials });\n default: return Object.freeze({ ...method });\n }\n }\n}\n\nexport class AuthDeclaration {\n // webpieces-disable no-function-outside-class -- stateless contract validation or scope metadata reader used before DI registration\n static validate(meta: AuthMeta): void {\n if (!Array.isArray(meta.methods) || meta.methods.length === 0) throw new Error('@WpAuth requires a nonempty methods tuple.');\n const kinds = new Set<string>();\n for (const method of meta.methods) {\n if (!method || typeof method !== 'object' || kinds.has(method.kind)) throw new Error('@WpAuth rejects duplicate or invalid credential methods.');\n kinds.add(method.kind);\n this.validateMethod(method);\n }\n if (kinds.has('public')) {\n if (meta.methods.length !== 1 || typeof meta.publicReason !== 'string' || !meta.publicReason.trim()) {\n throw new Error('Public auth must be declared separately with @WpAuthPublic(reason).');\n }\n } else if (meta.publicReason !== undefined) throw new Error('Protected @WpAuth rejects public reasons.');\n }\n\n // webpieces-disable no-function-outside-class -- stateless contract validation or scope metadata reader used before DI registration\n private static validateMethod(method: AuthMode): void {\n let keys: readonly string[];\n switch (method.kind) {\n case 'jwt':\n case 'public': keys = ['kind']; break;\n case 'oidc':\n keys = ['kind', 'callers'];\n if (!Array.isArray(method.callers) || !method.callers.every((caller: string) => typeof caller === 'string' && caller.trim().length > 0)) throw new Error('oidc(...) requires valid caller names.');\n break;\n case 'shared-secret':\n keys = ['kind', 'secretKey'];\n this.requireText(method.secretKey, 'sharedSecret'); break;\n case 'webhook':\n keys = ['kind', 'name'];\n this.requireText(method.name, 'webhook'); break;\n case 'apikey':\n keys = ['kind', 'regime', 'credentials'];\n this.requireText(method.regime, 'apiKey');\n if (!Array.isArray(method.credentials) || !method.credentials.length) throw new Error('apiKey(...) requires a nonempty credentials tuple.');\n for (const credential of method.credentials) {\n if (credential.in === 'header') this.requireHeaderKey(credential.key);\n else if (credential.in !== 'bearer' || Object.hasOwn(credential, 'key')) throw new Error('Invalid API-key credential location.');\n }\n break;\n default: throw new Error('Unknown @WpAuth method; use jwt/oidc/sharedSecret/webhook/apiKey descriptors.');\n }\n for (const key of Object.keys(method)) {\n if (!keys.includes(key)) throw new Error(`Auth method rejects '${key}'; operation policy belongs in @WpAuthorization.`);\n }\n }\n\n /**\n * A header credential's key must be a ContextKey that rides the wire. `httpHeader` is optional on\n * ContextKey itself (most keys never leave the process), and the factories' explicit value-type\n * argument (`ContextKey.untrusted<string>(...)`) stops TypeScript inferring whether one was\n * passed, so the type cannot say \"a key WITH a header\". It is checked once, when the contract is\n * decorated, and the OpenAPI generator refuses the same key statically.\n */\n // webpieces-disable no-function-outside-class -- stateless contract validation or scope metadata reader used before DI registration\n private static requireHeaderKey(key: AnyContextKey | undefined): void {\n if (!key || typeof key !== 'object' || typeof key.name !== 'string') {\n throw new Error(\"apiKey header credential requires `key`: the ContextKey carrying it, e.g. { in: 'header', key: MyKeys.API_KEY }.\");\n }\n if (typeof key.httpHeader !== 'string' || !key.httpHeader.trim()) {\n throw new Error(`apiKey header credential key '${key.name}' declares no httpHeader; define it with ContextKey.trusted(name, provenance, '<header>') or ContextKey.untrusted(name, '<header>').`);\n }\n }\n\n // webpieces-disable no-function-outside-class -- stateless contract validation or scope metadata reader used before DI registration\n private static requireText(value: string, label: string): void {\n if (typeof value !== 'string' || !value.trim()) throw new Error(`${label} requires a nonempty name.`);\n }\n}\n\n// webpieces-disable no-function-outside-class -- canonical credential descriptor factory\nexport function jwt(): AuthMethod { return { kind: 'jwt' }; }\n// webpieces-disable no-function-outside-class -- canonical credential descriptor factory\nexport function oidc(...callers: string[]): AuthMethod { return { kind: 'oidc', callers }; }\n// webpieces-disable no-function-outside-class -- canonical credential descriptor factory\nexport function sharedSecret(secretKey: string): AuthMethod { return { kind: 'shared-secret', secretKey }; }\n// webpieces-disable no-function-outside-class -- canonical credential descriptor factory\nexport function webhook(name: string): AuthMethod { return { kind: 'webhook', name }; }\n// webpieces-disable no-function-outside-class -- canonical credential descriptor factory\nexport function apiKey(regime: string, credentials: ApiKeyCredentials): AuthMethod { return { kind: 'apikey', regime, credentials }; }\n"]}
@@ -392,7 +392,7 @@ function getAuthMeta(apiClass, methodName) {
392
392
  * the caller hits becomes the API they believe exists. It leads with the ROLE-GATED member on purpose —
393
393
  * the first thing offered should not be the widest grant.
394
394
  */
395
- exports.MISSING_AUTH_DECORATOR_FIX = "Declare @WpAuth([jwt(), oidc(...callers), sharedSecret(key), webhook(name), apiKey('regime', [{in: 'header', name: 'x-api-key'}])]) " +
395
+ exports.MISSING_AUTH_DECORATOR_FIX = "Declare @WpAuth([jwt(), oidc(...callers), sharedSecret(key), webhook(name), apiKey('regime', [{in: 'header', key: MyKeys.API_KEY}])]) " +
396
396
  "or @WpAuthPublic('reason'), and exactly one @WpAuthorization on every endpoint. Add @WpLocalOnly() separately when locality is required.";
397
397
  /**
398
398
  * Fail-fast at wiring time if any endpoint lacks an auth mode. Both the server
@@ -1 +1 @@
1
- {"version":3,"file":"decorators.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/decorators.ts"],"names":[],"mappings":"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","sourcesContent":["import 'reflect-metadata';\nimport { MaskSpec, MaskMode } from './LogFieldMask';\nimport {\n DEFAULT_CALLER_KIND,\n ENDPOINT_CALLER_KEY,\n ExternalCaller,\n getEndpointCaller,\n} from './external-caller';\n// The TYPE layer these decorators attach — split out for file size only (see auth-mode.ts).\nimport { AuthMeta, AuthMethods, AuthMode } from './auth-mode';\nimport {\n EndpointOperation,\n EndpointOptions,\n ExternalEndpointOptions,\n READ,\n WRITE_IDEMPOTENT,\n WRITE,\n} from './HttpEndpointOptions';\nimport { GET, HttpMethod, POST } from './HttpContract';\nimport { AuthorizationDeclaration, AuthorizationType, AUTHORIZATION_METHODS_KEY, getAuthorization } from './authorization';\nimport { HTTP_PARAMETERS_METADATA_KEY } from './http-parameter-decorators';\n\nexport type { EndpointOptions, ExternalEndpointOptions } from './HttpEndpointOptions';\nexport type { EndpointOperation } from './HttpEndpointOptions';\nexport { READ, WRITE_IDEMPOTENT, WRITE } from './HttpEndpointOptions';\nexport type { HttpMethod } from './HttpContract';\nexport { GET, POST } from './HttpContract';\nexport { PathParam, QueryParam, getHttpParameterDeclarations } from './http-parameter-decorators';\n\n/**\n * Metadata keys for storing API routing information.\n * These keys are used by both server-side (routing) and client-side (client generation).\n */\nexport const METADATA_KEYS = {\n API_PATH: 'webpieces:api-path',\n ENDPOINTS: 'webpieces:endpoints',\n AUTH_META: 'webpieces:auth-meta',\n /** Method names carrying one of the canonical authorization decorators. */\n AUTH_METHODS: 'webpieces:auth-methods',\n /** 'rpc' (default, sync request/response) vs 'pubsub' (fire-and-forget cloud task). */\n API_KIND: 'webpieces:api-kind',\n /** Per-method Cloud Tasks queue-name override (set via @Queue). */\n QUEUE_OVERRIDE: 'webpieces:queue-override',\n /** Per-method @Endpoint options (e.g. formPost), parallel to ENDPOINTS. */\n ENDPOINT_OPTIONS: 'webpieces:endpoint-options',\n /** Per-method required HTTP method, parallel to ENDPOINTS. */\n ENDPOINT_HTTP_METHOD: 'webpieces:endpoint-http-method',\n /** Per-method required read/write semantics, parallel to ENDPOINTS. */\n ENDPOINT_OPERATION: 'webpieces:endpoint-operation',\n /** Per-method @Endpoint trigger kind (rpc | cloudtasks | cron | external), parallel to ENDPOINTS. */\n ENDPOINT_KIND: 'webpieces:endpoint-kind',\n /** Per-method declared external CALLER (only for kind 'external'), parallel to ENDPOINTS. */\n ENDPOINT_CALLER: ENDPOINT_CALLER_KEY,\n /** Per-method @MaskLog spec (which DTO fields the LogApiCall path masks). */\n MASK_LOG: 'webpieces:mask-log',\n /** Per-method opt-in metadata for publishing an RPC endpoint as an MCP tool. */\n MCP_TOOLS: 'webpieces:mcp-tools',\n /** Per-method PERMANENT exclusion from MCP, with the reason — see @InvalidEndpointForMcp. */\n MCP_INVALID: 'webpieces:mcp-invalid',\n /** Per-method request/response event metadata for a typed streaming endpoint. */\n STREAM_ENDPOINTS: 'webpieces:stream-endpoints',\n /** Per-method MCP-user authorization, intentionally separate from HTTP hop auth. */\n LOCAL_ONLY: 'webpieces:local-only',\n /** Per-method explicit path/query parameter declarations, keyed by parameter index. */\n HTTP_PARAMETERS: HTTP_PARAMETERS_METADATA_KEY,\n};\n\n/** Nominal backing keeps raw string literals out of endpoint declarations. */\nenum EndpointKindValue {\n RPC = 'rpc',\n CLOUDTASKS = 'cloudtasks',\n CRON = 'cron',\n EXTERNAL = 'external',\n}\n\n/** Short, statically importable decorator arguments. */\nexport const RPC = EndpointKindValue.RPC;\nexport const CLOUDTASKS = EndpointKindValue.CLOUDTASKS;\nexport const CRON = EndpointKindValue.CRON;\nexport const EXTERNAL = EndpointKindValue.EXTERNAL;\n\n/** Runtime trigger/delivery owner used by validation, architecture, and infrastructure tooling. */\nexport type EndpointKind = typeof RPC | typeof CLOUDTASKS | typeof CRON | typeof EXTERNAL;\n\n/** Class decorator that sets the shared base path for all endpoints. */\nexport function ApiPath(basePath: string): ClassDecorator {\n return (target: Function) => {\n if (Reflect.hasMetadata('webpieces:ipc-api-id', target)) {\n throw new Error(\n `Class ${target.name || 'Unknown'} cannot combine @ApiPath with @WpInternal.`,\n );\n }\n Reflect.defineMetadata(METADATA_KEYS.API_PATH, basePath, target);\n\n // Initialize endpoints map if not exists\n if (!Reflect.hasMetadata(METADATA_KEYS.ENDPOINTS, target)) {\n Reflect.defineMetadata(METADATA_KEYS.ENDPOINTS, {}, target);\n }\n };\n}\n\n/**\n * Registers `@Endpoint(POST, path, WRITE, RPC)`. Method, operation, and trigger are required enum\n * values. Operation is independent of the HTTP verb. EXTERNAL additionally requires `calledBy`.\n * Each classification rides a parallel metadata map while ENDPOINTS remains method-name -> path.\n */\n// webpieces-disable no-function-outside-class -- decorator factory; decorators are inherently module-scope\nexport function Endpoint(\n httpMethod: HttpMethod,\n path: string,\n operation: EndpointOperation,\n kind: typeof EXTERNAL,\n options: ExternalEndpointOptions,\n): MethodDecorator;\n// webpieces-disable no-function-outside-class -- decorator factory; decorators are inherently module-scope\nexport function Endpoint(\n httpMethod: HttpMethod,\n path: string,\n operation: EndpointOperation,\n kind: Exclude<EndpointKind, typeof EXTERNAL>,\n options?: EndpointOptions,\n): MethodDecorator;\n// webpieces-disable no-function-outside-class -- decorator factory; decorators are inherently module-scope\nexport function Endpoint(\n httpMethod: HttpMethod,\n path: string,\n operation: EndpointOperation,\n kind: EndpointKind,\n options: EndpointOptions = {},\n): MethodDecorator {\n validateEndpointClassification(httpMethod, operation, kind);\n // webpieces-disable no-any-unknown -- reflect-metadata decorator API requires any\n return (target: any, propertyKey: string | symbol, _descriptor: PropertyDescriptor) => {\n const metadataTarget = typeof target === 'function' ? target : target.constructor;\n recordEndpointMetadata(\n metadataTarget,\n propertyKey as string,\n httpMethod,\n path,\n operation,\n kind,\n options,\n );\n };\n}\n\n// webpieces-disable no-function-outside-class -- runtime validation backs up nominal TS enums\nfunction validateEndpointClassification(\n httpMethod: HttpMethod,\n operation: EndpointOperation,\n kind: EndpointKind,\n): void {\n if (!isHttpMethod(httpMethod)) {\n throw new Error(\n `@Endpoint httpMethod must be GET or POST, received '${String(httpMethod)}'.`,\n );\n }\n if (!isEndpointOperation(operation)) {\n throw new Error(\n `@Endpoint operation must be READ, WRITE_IDEMPOTENT, or WRITE, received '${String(operation)}'.`,\n );\n }\n if (!isEndpointKind(kind)) {\n throw new Error(\n `@Endpoint trigger must be RPC, CLOUDTASKS, CRON, or EXTERNAL, received '${String(kind)}'.`,\n );\n }\n}\n\n// webpieces-disable no-function-outside-class -- one metadata write shared by the decorator overloads\nfunction recordEndpointMetadata(\n metadataTarget: Function,\n propertyKey: string,\n httpMethod: HttpMethod,\n path: string,\n operation: EndpointOperation,\n kind: EndpointKind,\n options: EndpointOptions,\n): void {\n const endpoints: Record<string, string> =\n Reflect.getMetadata(METADATA_KEYS.ENDPOINTS, metadataTarget) || {};\n\n endpoints[propertyKey] = path;\n\n Reflect.defineMetadata(METADATA_KEYS.ENDPOINTS, endpoints, metadataTarget);\n\n const methods: Record<string, HttpMethod> =\n Reflect.getMetadata(METADATA_KEYS.ENDPOINT_HTTP_METHOD, metadataTarget) || {};\n methods[propertyKey] = httpMethod;\n Reflect.defineMetadata(METADATA_KEYS.ENDPOINT_HTTP_METHOD, methods, metadataTarget);\n\n const operations: Record<string, EndpointOperation> =\n Reflect.getMetadata(METADATA_KEYS.ENDPOINT_OPERATION, metadataTarget) || {};\n operations[propertyKey] = operation;\n Reflect.defineMetadata(METADATA_KEYS.ENDPOINT_OPERATION, operations, metadataTarget);\n\n const kinds: Record<string, EndpointKind> =\n Reflect.getMetadata(METADATA_KEYS.ENDPOINT_KIND, metadataTarget) || {};\n kinds[propertyKey] = kind;\n Reflect.defineMetadata(METADATA_KEYS.ENDPOINT_KIND, kinds, metadataTarget);\n\n const opts: Record<string, EndpointOptions> =\n Reflect.getMetadata(METADATA_KEYS.ENDPOINT_OPTIONS, metadataTarget) || {};\n opts[propertyKey] = options;\n Reflect.defineMetadata(METADATA_KEYS.ENDPOINT_OPTIONS, opts, metadataTarget);\n\n const declared = options as ExternalEndpointOptions;\n if (\n kind !== EXTERNAL ||\n typeof declared.calledBy !== 'string' ||\n declared.calledBy === ''\n )\n return;\n const callers: Record<string, ExternalCaller> =\n Reflect.getMetadata(METADATA_KEYS.ENDPOINT_CALLER, metadataTarget) || {};\n callers[propertyKey] = new ExternalCaller(\n declared.callerKind ?? DEFAULT_CALLER_KIND,\n declared.calledBy,\n );\n Reflect.defineMetadata(METADATA_KEYS.ENDPOINT_CALLER, callers, metadataTarget);\n}\n\n/** Declares request/response DTO field names that API logging must mask at any depth. */\n// webpieces-disable no-function-outside-class -- decorator factory; decorators are inherently module-scope\nexport function MaskLog(fields: Record<string, MaskMode>): MethodDecorator {\n const spec = new MaskSpec(fields);\n // webpieces-disable no-any-unknown -- reflect-metadata decorator API requires any\n return (target: any, propertyKey: string | symbol, _descriptor: PropertyDescriptor) => {\n const metadataTarget = typeof target === 'function' ? target : target.constructor;\n const specs: Record<string, MaskSpec> =\n Reflect.getMetadata(METADATA_KEYS.MASK_LOG, metadataTarget) || {};\n specs[propertyKey as string] = spec;\n Reflect.defineMetadata(METADATA_KEYS.MASK_LOG, specs, metadataTarget);\n };\n}\n\n/**\n * The @MaskLog spec for one method, or undefined if the method declared none (the common case — the\n * caller then logs the DTO verbatim on the plain JSON.stringify fast path).\n */\n// webpieces-disable no-function-outside-class -- reflect-metadata reader, sibling of getEndpointOptions\nexport function getMaskSpec(apiClass: Function, methodName: string): MaskSpec | undefined {\n const specs: Record<string, MaskSpec> =\n Reflect.getMetadata(METADATA_KEYS.MASK_LOG, apiClass) || {};\n return specs[methodName];\n}\n\n/**\n * Shared implementation for every auth decorator. Authorization is deliberately\n * method-only: a class-level default is too easy to miss when reviewing one endpoint.\n */\n// webpieces-disable no-function-outside-class -- decorator factory; decorators are inherently module-scope\nfunction defineAuthMetadata(authMeta: AuthMeta): MethodDecorator {\n\n // webpieces-disable no-any-unknown -- reflect-metadata decorator API requires any\n return (target: any, propertyKey?: string | symbol, _descriptor?: PropertyDescriptor) => {\n if (propertyKey === undefined) {\n throw new Error(\n 'Authorization decorators are method-only; annotate every @Endpoint explicitly.',\n );\n }\n const metadataTarget = typeof target === 'function' ? target : target.constructor;\n if (Reflect.hasMetadata('webpieces:ipc-api-id', metadataTarget)) {\n throw new Error(\n `Internal API ${metadataTarget.name || 'Unknown'} cannot use HTTP authorization decorators.`,\n );\n }\n validateNoConflictingDecorators(metadataTarget, propertyKey as string);\n Reflect.defineMetadata(METADATA_KEYS.AUTH_META, authMeta, metadataTarget, propertyKey);\n const methods = new Set<string>(\n Reflect.getMetadata(METADATA_KEYS.AUTH_METHODS, metadataTarget) || [],\n );\n methods.add(propertyKey as string);\n Reflect.defineMetadata(METADATA_KEYS.AUTH_METHODS, [...methods], metadataTarget);\n };\n}\n\n/**\n * @WpAuthPublic(reason) - endpoint intentionally requires no authentication.\n * The non-empty reason makes anonymous exposure an explicit review decision.\n */\n// webpieces-disable no-function-outside-class -- decorator factory; decorators are inherently module-scope\nexport function WpAuthPublic(reason: string): MethodDecorator {\n if (typeof reason !== 'string' || reason.trim() === '') {\n throw new Error(\n '@WpAuthPublic requires a non-empty reason explaining why anonymous access is required.',\n );\n }\n return defineAuthMetadata(new AuthMeta([{ kind: 'public' }], reason));\n}\n\n/** Protected network ingress: authenticate one declared credential, then authorize independently. */\n// webpieces-disable no-function-outside-class -- canonical method decorator factory\nexport function WpAuth(methods: AuthMethods): MethodDecorator {\n return defineAuthMetadata(new AuthMeta(methods, undefined));\n}\n\n/** Locality is independent of authentication and cannot prove a user or machine identity. */\n// webpieces-disable no-function-outside-class -- canonical method decorator factory\nexport function WpLocalOnly(): MethodDecorator {\n return (target: object, methodName: string | symbol) => {\n if (methodName === undefined) throw new Error('@WpLocalOnly is method-only.');\n Reflect.defineMetadata(METADATA_KEYS.LOCAL_ONLY, true, target.constructor, methodName);\n };\n}\n\n// webpieces-disable no-function-outside-class -- canonical metadata reader\nexport function isLocalOnly(apiClass: Function, methodName: string): boolean {\n return Reflect.getMetadata(METADATA_KEYS.LOCAL_ONLY, apiClass, methodName) === true;\n}\n\n// ============================================================\n// Helper functions\n// ============================================================\n\n/**\n * Get the base path from @ApiPath decorator.\n */\nexport function getApiPath(apiClass: Function): string | undefined {\n return Reflect.getMetadata(METADATA_KEYS.API_PATH, apiClass);\n}\n\n/**\n * Get all endpoints from @Endpoint decorators.\n * Returns a record of methodName -> endpoint path.\n */\nexport function getEndpoints(apiClass: Function): Record<string, string> | undefined {\n return Reflect.getMetadata(METADATA_KEYS.ENDPOINTS, apiClass);\n}\n\n/**\n * Every method's declared trigger kind, as `methodName -> kind`. Parallel to {@link getEndpoints}.\n * Empty for a class carrying no @Endpoint at all.\n */\n// webpieces-disable no-function-outside-class -- reflect-metadata reader, sibling of getEndpoints\nexport function getEndpointKinds(apiClass: Function): Record<string, EndpointKind> {\n return Reflect.getMetadata(METADATA_KEYS.ENDPOINT_KIND, apiClass) || {};\n}\n\n/**\n * What triggers ONE method, or undefined when the method carries no @Endpoint.\n *\n * Defaults to nothing rather than to 'rpc': `kind` is a required argument, so a missing entry means\n * \"this is not an endpoint\", never \"an endpoint that forgot to say\". Silently defaulting here would\n * put an undeclared cron or webhook back into the graph as a normal rpc call — the exact blindness\n * the required argument exists to remove.\n */\n// webpieces-disable no-function-outside-class -- reflect-metadata reader, sibling of getEndpoints\nexport function getEndpointKind(apiClass: Function, methodName: string): EndpointKind | undefined {\n return getEndpointKinds(apiClass)[methodName];\n}\n\n/** The required HTTP method for one endpoint. */\n// webpieces-disable no-function-outside-class -- reflect-metadata reader, sibling of getEndpointKind\nexport function getEndpointHttpMethod(apiClass: Function, methodName: string): HttpMethod {\n const methods: Record<string, HttpMethod> =\n Reflect.getMetadata(METADATA_KEYS.ENDPOINT_HTTP_METHOD, apiClass) || {};\n const method = methods[methodName];\n if (!isHttpMethod(method)) {\n throw new Error(\n `@Endpoint ${apiClass.name || 'Unknown'}.${methodName} must declare GET or POST.`,\n );\n }\n return method;\n}\n\n/**\n * Get the @Endpoint options for one method (empty object if the method had no options).\n */\n// webpieces-disable no-function-outside-class -- reflect-metadata reader, sibling of getEndpoints\nexport function getEndpointOptions(apiClass: Function, methodName: string): EndpointOptions {\n const opts: Record<string, EndpointOptions> =\n Reflect.getMetadata(METADATA_KEYS.ENDPOINT_OPTIONS, apiClass) || {};\n const options = opts[methodName];\n if (!options && getEndpoints(apiClass)?.[methodName] === undefined) {\n // Preserve the historical helper behavior for a method that is not an endpoint at all.\n return {} as EndpointOptions;\n }\n return options ?? {};\n}\n\n/** Read one endpoint's required side-effect semantics. */\n// webpieces-disable no-function-outside-class -- reflect-metadata reader, sibling of getEndpointOptions\nexport function getEndpointOperation(apiClass: Function, methodName: string): EndpointOperation {\n const operations: Record<string, EndpointOperation> =\n Reflect.getMetadata(METADATA_KEYS.ENDPOINT_OPERATION, apiClass) || {};\n const operation = operations[methodName];\n if (!isEndpointOperation(operation)) {\n throw new Error(\n `@Endpoint ${apiClass.name || 'Unknown'}.${methodName} must declare READ, ` +\n 'WRITE_IDEMPOTENT, or WRITE.',\n );\n }\n return operation;\n}\n\n// webpieces-disable no-function-outside-class -- runtime backstop for JavaScript and `as any` callers; webpieces-disable no-any-unknown -- untrusted runtime value is narrowed to an endpoint operation\nfunction isEndpointOperation(value: unknown): value is EndpointOperation {\n return (\n value === READ ||\n value === WRITE_IDEMPOTENT ||\n value === WRITE\n );\n}\n\n// webpieces-disable no-function-outside-class -- runtime backstop for JavaScript and `as any` callers; webpieces-disable no-any-unknown -- untrusted runtime value is narrowed to an HTTP method\nfunction isHttpMethod(value: unknown): value is HttpMethod {\n return value === GET || value === POST;\n}\n\n// webpieces-disable no-function-outside-class -- runtime backstop for JavaScript and `as any` callers; webpieces-disable no-any-unknown -- untrusted runtime value is narrowed to an endpoint kind\nfunction isEndpointKind(value: unknown): value is EndpointKind {\n return (\n value === RPC ||\n value === CLOUDTASKS ||\n value === CRON ||\n value === EXTERNAL\n );\n}\n\n/**\n * Fail-fast at wiring time when an `external` endpoint declared no caller. The {@link Endpoint}\n * overloads already make that a COMPILE error; this is the backstop for the ways TS is bypassed —\n * a JS caller, an `as any` options object, a hand-rolled Reflect.defineMetadata.\n * @throws Error naming the first external endpoint with no `calledBy`.\n */\n// webpieces-disable no-function-outside-class -- wiring-time assert, sibling of assertEveryEndpointHasAuthMode\nexport function assertEveryExternalEndpointDeclaresCaller(apiClass: Function): void {\n const kinds = getEndpointKinds(apiClass);\n for (const methodName of Object.keys(kinds)) {\n if (\n kinds[methodName] !== 'external' ||\n getEndpointCaller(apiClass, methodName) !== undefined\n )\n continue;\n throw new Error(\n `External endpoint '${methodName}' in ${apiClass.name || 'Unknown'} declares no caller. Say WHO ` +\n `posts to it: @Endpoint(POST, path, WRITE, EXTERNAL, { calledBy: '<vendor>' }) — the runtime architecture ` +\n `graph cannot name an inbound caller it was never told about.`,\n );\n }\n}\n\n/**\n * True when the method's @Endpoint declared `{ formPost: true }` — its body is\n * application/x-www-form-urlencoded (flat), not JSON.\n */\n// webpieces-disable no-function-outside-class -- reflect-metadata reader, sibling of getEndpoints\nexport function isFormPost(apiClass: Function, methodName: string): boolean {\n return getEndpointOptions(apiClass, methodName).formPost === true;\n}\n\n/**\n * True when the method's @Endpoint declared `{ rawBody: true }` — the transport must retain the\n * verbatim bytes + absolute url for an {@link WebhookAuthCallback} hook to verify.\n */\n// webpieces-disable no-function-outside-class -- reflect-metadata reader, sibling of isFormPost\nexport function isRawBody(apiClass: Function, methodName: string): boolean {\n return getEndpointOptions(apiClass, methodName).rawBody === true;\n}\n\n/**\n * Fail-fast at wiring time when an `webhook(...)` endpoint did not ask the transport to keep the\n * bytes it is supposed to verify. A hook with nothing to verify is a MISCONFIGURATION, and it must\n * surface at startup, naming the fix — not as a 401 in production on exactly the traffic the endpoint\n * exists for.\n *\n * This pairing is a runtime assert rather than a type because the two halves live on DIFFERENT\n * decorators (`webhook(...)` and `@Endpoint`), and no union over one decorator's argument can say\n * anything about the other's.\n *\n * @throws Error naming the first `webhook(...)` endpoint missing `{ rawBody: true }`.\n */\n// webpieces-disable no-function-outside-class -- wiring-time assert, sibling of assertEveryEndpointHasAuthMode\nexport function assertEveryWebhookEndpointRetainsRawBody(apiClass: Function): void {\n const endpoints = getEndpoints(apiClass) || {};\n for (const methodName of Object.keys(endpoints)) {\n if (\n !getAuthMeta(apiClass, methodName)?.methods.some((method: AuthMode) => method.kind === 'webhook') ||\n isRawBody(apiClass, methodName)\n )\n continue;\n throw new Error(\n `Endpoint '${methodName}' in ${apiClass.name || 'Unknown'} is webhook(...) but its @Endpoint ` +\n `does not declare { rawBody: true }. A webhook hook verifies a signature over the bytes and ` +\n `the url the SENDER transmitted, and without that option the transport parses the body and ` +\n `throws them away — leaving the hook nothing to check.`,\n );\n }\n}\n\n/**\n * Check if a class has @ApiPath decorator.\n */\nexport function isApiPath(apiClass: Function): boolean {\n return Reflect.hasMetadata(METADATA_KEYS.API_PATH, apiClass);\n}\n\n/**\n * Get method-level auth metadata. Class-level authorization is forbidden.\n */\n// webpieces-disable no-function-outside-class -- reflect-metadata reader paired with the decorator API\nexport function getAuthMeta(apiClass: Function, methodName: string): AuthMeta | undefined {\n return Reflect.getMetadata(METADATA_KEYS.AUTH_META, apiClass, methodName);\n}\n\n/**\n * The ONE prescription for \"this endpoint declares no auth\", shared by the two places that raise it\n * (here and http-routing's ApiRoutingFactory) because they had drifted into teaching different menus.\n * A message teaching an incomplete API is the same defect as an API with two spellings: whichever menu\n * the caller hits becomes the API they believe exists. It leads with the ROLE-GATED member on purpose —\n * the first thing offered should not be the widest grant.\n */\nexport const MISSING_AUTH_DECORATOR_FIX =\n \"Declare @WpAuth([jwt(), oidc(...callers), sharedSecret(key), webhook(name), apiKey('regime', [{in: 'header', name: 'x-api-key'}])]) \" +\n \"or @WpAuthPublic('reason'), and exactly one @WpAuthorization on every endpoint. Add @WpLocalOnly() separately when locality is required.\";\n\n/**\n * Fail-fast at wiring time if any endpoint lacks an auth mode. Both the server\n * (ApiRoutingFactory) and the task/rpc clients call this so a missing auth\n * decorator is a startup error, never a silent open endpoint.\n * @throws Error naming the first endpoint with no auth decorator, via {@link MISSING_AUTH_DECORATOR_FIX}.\n */\nexport function assertEveryEndpointHasAuthMode(apiClass: Function): void {\n const apiName = apiClass.name || 'Unknown';\n const endpoints = getEndpoints(apiClass) || {};\n for (const methodName of Object.keys(endpoints)) {\n if (!getAuthMeta(apiClass, methodName)) {\n throw new Error(\n `Endpoint '${methodName}' in ${apiName} has no auth decorator. ` +\n MISSING_AUTH_DECORATOR_FIX,\n );\n }\n const policy = getAuthorization(apiClass, methodName);\n if (!policy) throw new Error(`Endpoint '${methodName}' in ${apiName} requires @WpAuthorization.`);\n AuthorizationDeclaration.validate(policy);\n const auth = getAuthMeta(apiClass, methodName)!;\n const isPublic = auth.methods.some((method: AuthMode) => method.kind === 'public');\n if (isPublic !== (policy.authType === AuthorizationType.ANONYMOUS)) {\n throw new Error(`Endpoint '${methodName}' must pair public authentication with ANONYMOUS authorization, or protected authentication with protected/CUSTOM authorization.`);\n }\n }\n const policyMethods: string[] = Reflect.getMetadata(AUTHORIZATION_METHODS_KEY, apiClass) ?? [];\n for (const methodName of policyMethods) {\n if (!(methodName in endpoints)) throw new Error(`Orphan @WpAuthorization on ${apiName}.${methodName}; declare @Endpoint.`);\n }\n}\n\n/**\n * Validate that a class/method doesn't have conflicting auth decorators.\n * @throws Error if multiple auth decorators are found on the same target.\n */\n// webpieces-disable no-function-outside-class -- shared decorator metadata validation\nexport function validateNoConflictingDecorators(\n apiClass: Function,\n methodName: string | undefined,\n): void {\n const existing = methodName\n ? Reflect.getMetadata(METADATA_KEYS.AUTH_META, apiClass, methodName)\n : Reflect.getMetadata(METADATA_KEYS.AUTH_META, apiClass);\n\n if (existing) {\n const targetName = apiClass.name || 'Unknown';\n const location = methodName\n ? `method '${methodName}' of ${targetName}`\n : `class ${targetName}`;\n throw new Error(\n `Conflicting auth decorator on ${location}. ` +\n `Exactly one @WpAuth([...]) or @WpAuthPublic('reason') is allowed per endpoint.`,\n );\n }\n}\n"]}
1
+ {"version":3,"file":"decorators.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/decorators.ts"],"names":[],"mappings":"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","sourcesContent":["import 'reflect-metadata';\nimport { MaskSpec, MaskMode } from './LogFieldMask';\nimport {\n DEFAULT_CALLER_KIND,\n ENDPOINT_CALLER_KEY,\n ExternalCaller,\n getEndpointCaller,\n} from './external-caller';\n// The TYPE layer these decorators attach — split out for file size only (see auth-mode.ts).\nimport { AuthMeta, AuthMethods, AuthMode } from './auth-mode';\nimport {\n EndpointOperation,\n EndpointOptions,\n ExternalEndpointOptions,\n READ,\n WRITE_IDEMPOTENT,\n WRITE,\n} from './HttpEndpointOptions';\nimport { GET, HttpMethod, POST } from './HttpContract';\nimport { AuthorizationDeclaration, AuthorizationType, AUTHORIZATION_METHODS_KEY, getAuthorization } from './authorization';\nimport { HTTP_PARAMETERS_METADATA_KEY } from './http-parameter-decorators';\n\nexport type { EndpointOptions, ExternalEndpointOptions } from './HttpEndpointOptions';\nexport type { EndpointOperation } from './HttpEndpointOptions';\nexport { READ, WRITE_IDEMPOTENT, WRITE } from './HttpEndpointOptions';\nexport type { HttpMethod } from './HttpContract';\nexport { GET, POST } from './HttpContract';\nexport { PathParam, QueryParam, getHttpParameterDeclarations } from './http-parameter-decorators';\n\n/**\n * Metadata keys for storing API routing information.\n * These keys are used by both server-side (routing) and client-side (client generation).\n */\nexport const METADATA_KEYS = {\n API_PATH: 'webpieces:api-path',\n ENDPOINTS: 'webpieces:endpoints',\n AUTH_META: 'webpieces:auth-meta',\n /** Method names carrying one of the canonical authorization decorators. */\n AUTH_METHODS: 'webpieces:auth-methods',\n /** 'rpc' (default, sync request/response) vs 'pubsub' (fire-and-forget cloud task). */\n API_KIND: 'webpieces:api-kind',\n /** Per-method Cloud Tasks queue-name override (set via @Queue). */\n QUEUE_OVERRIDE: 'webpieces:queue-override',\n /** Per-method @Endpoint options (e.g. formPost), parallel to ENDPOINTS. */\n ENDPOINT_OPTIONS: 'webpieces:endpoint-options',\n /** Per-method required HTTP method, parallel to ENDPOINTS. */\n ENDPOINT_HTTP_METHOD: 'webpieces:endpoint-http-method',\n /** Per-method required read/write semantics, parallel to ENDPOINTS. */\n ENDPOINT_OPERATION: 'webpieces:endpoint-operation',\n /** Per-method @Endpoint trigger kind (rpc | cloudtasks | cron | external), parallel to ENDPOINTS. */\n ENDPOINT_KIND: 'webpieces:endpoint-kind',\n /** Per-method declared external CALLER (only for kind 'external'), parallel to ENDPOINTS. */\n ENDPOINT_CALLER: ENDPOINT_CALLER_KEY,\n /** Per-method @MaskLog spec (which DTO fields the LogApiCall path masks). */\n MASK_LOG: 'webpieces:mask-log',\n /** Per-method opt-in metadata for publishing an RPC endpoint as an MCP tool. */\n MCP_TOOLS: 'webpieces:mcp-tools',\n /** Per-method PERMANENT exclusion from MCP, with the reason — see @InvalidEndpointForMcp. */\n MCP_INVALID: 'webpieces:mcp-invalid',\n /** Per-method request/response event metadata for a typed streaming endpoint. */\n STREAM_ENDPOINTS: 'webpieces:stream-endpoints',\n /** Per-method MCP-user authorization, intentionally separate from HTTP hop auth. */\n LOCAL_ONLY: 'webpieces:local-only',\n /** Per-method explicit path/query parameter declarations, keyed by parameter index. */\n HTTP_PARAMETERS: HTTP_PARAMETERS_METADATA_KEY,\n};\n\n/** Nominal backing keeps raw string literals out of endpoint declarations. */\nenum EndpointKindValue {\n RPC = 'rpc',\n CLOUDTASKS = 'cloudtasks',\n CRON = 'cron',\n EXTERNAL = 'external',\n}\n\n/** Short, statically importable decorator arguments. */\nexport const RPC = EndpointKindValue.RPC;\nexport const CLOUDTASKS = EndpointKindValue.CLOUDTASKS;\nexport const CRON = EndpointKindValue.CRON;\nexport const EXTERNAL = EndpointKindValue.EXTERNAL;\n\n/** Runtime trigger/delivery owner used by validation, architecture, and infrastructure tooling. */\nexport type EndpointKind = typeof RPC | typeof CLOUDTASKS | typeof CRON | typeof EXTERNAL;\n\n/** Class decorator that sets the shared base path for all endpoints. */\nexport function ApiPath(basePath: string): ClassDecorator {\n return (target: Function) => {\n if (Reflect.hasMetadata('webpieces:ipc-api-id', target)) {\n throw new Error(\n `Class ${target.name || 'Unknown'} cannot combine @ApiPath with @WpInternal.`,\n );\n }\n Reflect.defineMetadata(METADATA_KEYS.API_PATH, basePath, target);\n\n // Initialize endpoints map if not exists\n if (!Reflect.hasMetadata(METADATA_KEYS.ENDPOINTS, target)) {\n Reflect.defineMetadata(METADATA_KEYS.ENDPOINTS, {}, target);\n }\n };\n}\n\n/**\n * Registers `@Endpoint(POST, path, WRITE, RPC)`. Method, operation, and trigger are required enum\n * values. Operation is independent of the HTTP verb. EXTERNAL additionally requires `calledBy`.\n * Each classification rides a parallel metadata map while ENDPOINTS remains method-name -> path.\n */\n// webpieces-disable no-function-outside-class -- decorator factory; decorators are inherently module-scope\nexport function Endpoint(\n httpMethod: HttpMethod,\n path: string,\n operation: EndpointOperation,\n kind: typeof EXTERNAL,\n options: ExternalEndpointOptions,\n): MethodDecorator;\n// webpieces-disable no-function-outside-class -- decorator factory; decorators are inherently module-scope\nexport function Endpoint(\n httpMethod: HttpMethod,\n path: string,\n operation: EndpointOperation,\n kind: Exclude<EndpointKind, typeof EXTERNAL>,\n options?: EndpointOptions,\n): MethodDecorator;\n// webpieces-disable no-function-outside-class -- decorator factory; decorators are inherently module-scope\nexport function Endpoint(\n httpMethod: HttpMethod,\n path: string,\n operation: EndpointOperation,\n kind: EndpointKind,\n options: EndpointOptions = {},\n): MethodDecorator {\n validateEndpointClassification(httpMethod, operation, kind);\n // webpieces-disable no-any-unknown -- reflect-metadata decorator API requires any\n return (target: any, propertyKey: string | symbol, _descriptor: PropertyDescriptor) => {\n const metadataTarget = typeof target === 'function' ? target : target.constructor;\n recordEndpointMetadata(\n metadataTarget,\n propertyKey as string,\n httpMethod,\n path,\n operation,\n kind,\n options,\n );\n };\n}\n\n// webpieces-disable no-function-outside-class -- runtime validation backs up nominal TS enums\nfunction validateEndpointClassification(\n httpMethod: HttpMethod,\n operation: EndpointOperation,\n kind: EndpointKind,\n): void {\n if (!isHttpMethod(httpMethod)) {\n throw new Error(\n `@Endpoint httpMethod must be GET or POST, received '${String(httpMethod)}'.`,\n );\n }\n if (!isEndpointOperation(operation)) {\n throw new Error(\n `@Endpoint operation must be READ, WRITE_IDEMPOTENT, or WRITE, received '${String(operation)}'.`,\n );\n }\n if (!isEndpointKind(kind)) {\n throw new Error(\n `@Endpoint trigger must be RPC, CLOUDTASKS, CRON, or EXTERNAL, received '${String(kind)}'.`,\n );\n }\n}\n\n// webpieces-disable no-function-outside-class -- one metadata write shared by the decorator overloads\nfunction recordEndpointMetadata(\n metadataTarget: Function,\n propertyKey: string,\n httpMethod: HttpMethod,\n path: string,\n operation: EndpointOperation,\n kind: EndpointKind,\n options: EndpointOptions,\n): void {\n const endpoints: Record<string, string> =\n Reflect.getMetadata(METADATA_KEYS.ENDPOINTS, metadataTarget) || {};\n\n endpoints[propertyKey] = path;\n\n Reflect.defineMetadata(METADATA_KEYS.ENDPOINTS, endpoints, metadataTarget);\n\n const methods: Record<string, HttpMethod> =\n Reflect.getMetadata(METADATA_KEYS.ENDPOINT_HTTP_METHOD, metadataTarget) || {};\n methods[propertyKey] = httpMethod;\n Reflect.defineMetadata(METADATA_KEYS.ENDPOINT_HTTP_METHOD, methods, metadataTarget);\n\n const operations: Record<string, EndpointOperation> =\n Reflect.getMetadata(METADATA_KEYS.ENDPOINT_OPERATION, metadataTarget) || {};\n operations[propertyKey] = operation;\n Reflect.defineMetadata(METADATA_KEYS.ENDPOINT_OPERATION, operations, metadataTarget);\n\n const kinds: Record<string, EndpointKind> =\n Reflect.getMetadata(METADATA_KEYS.ENDPOINT_KIND, metadataTarget) || {};\n kinds[propertyKey] = kind;\n Reflect.defineMetadata(METADATA_KEYS.ENDPOINT_KIND, kinds, metadataTarget);\n\n const opts: Record<string, EndpointOptions> =\n Reflect.getMetadata(METADATA_KEYS.ENDPOINT_OPTIONS, metadataTarget) || {};\n opts[propertyKey] = options;\n Reflect.defineMetadata(METADATA_KEYS.ENDPOINT_OPTIONS, opts, metadataTarget);\n\n const declared = options as ExternalEndpointOptions;\n if (\n kind !== EXTERNAL ||\n typeof declared.calledBy !== 'string' ||\n declared.calledBy === ''\n )\n return;\n const callers: Record<string, ExternalCaller> =\n Reflect.getMetadata(METADATA_KEYS.ENDPOINT_CALLER, metadataTarget) || {};\n callers[propertyKey] = new ExternalCaller(\n declared.callerKind ?? DEFAULT_CALLER_KIND,\n declared.calledBy,\n );\n Reflect.defineMetadata(METADATA_KEYS.ENDPOINT_CALLER, callers, metadataTarget);\n}\n\n/** Declares request/response DTO field names that API logging must mask at any depth. */\n// webpieces-disable no-function-outside-class -- decorator factory; decorators are inherently module-scope\nexport function MaskLog(fields: Record<string, MaskMode>): MethodDecorator {\n const spec = new MaskSpec(fields);\n // webpieces-disable no-any-unknown -- reflect-metadata decorator API requires any\n return (target: any, propertyKey: string | symbol, _descriptor: PropertyDescriptor) => {\n const metadataTarget = typeof target === 'function' ? target : target.constructor;\n const specs: Record<string, MaskSpec> =\n Reflect.getMetadata(METADATA_KEYS.MASK_LOG, metadataTarget) || {};\n specs[propertyKey as string] = spec;\n Reflect.defineMetadata(METADATA_KEYS.MASK_LOG, specs, metadataTarget);\n };\n}\n\n/**\n * The @MaskLog spec for one method, or undefined if the method declared none (the common case — the\n * caller then logs the DTO verbatim on the plain JSON.stringify fast path).\n */\n// webpieces-disable no-function-outside-class -- reflect-metadata reader, sibling of getEndpointOptions\nexport function getMaskSpec(apiClass: Function, methodName: string): MaskSpec | undefined {\n const specs: Record<string, MaskSpec> =\n Reflect.getMetadata(METADATA_KEYS.MASK_LOG, apiClass) || {};\n return specs[methodName];\n}\n\n/**\n * Shared implementation for every auth decorator. Authorization is deliberately\n * method-only: a class-level default is too easy to miss when reviewing one endpoint.\n */\n// webpieces-disable no-function-outside-class -- decorator factory; decorators are inherently module-scope\nfunction defineAuthMetadata(authMeta: AuthMeta): MethodDecorator {\n\n // webpieces-disable no-any-unknown -- reflect-metadata decorator API requires any\n return (target: any, propertyKey?: string | symbol, _descriptor?: PropertyDescriptor) => {\n if (propertyKey === undefined) {\n throw new Error(\n 'Authorization decorators are method-only; annotate every @Endpoint explicitly.',\n );\n }\n const metadataTarget = typeof target === 'function' ? target : target.constructor;\n if (Reflect.hasMetadata('webpieces:ipc-api-id', metadataTarget)) {\n throw new Error(\n `Internal API ${metadataTarget.name || 'Unknown'} cannot use HTTP authorization decorators.`,\n );\n }\n validateNoConflictingDecorators(metadataTarget, propertyKey as string);\n Reflect.defineMetadata(METADATA_KEYS.AUTH_META, authMeta, metadataTarget, propertyKey);\n const methods = new Set<string>(\n Reflect.getMetadata(METADATA_KEYS.AUTH_METHODS, metadataTarget) || [],\n );\n methods.add(propertyKey as string);\n Reflect.defineMetadata(METADATA_KEYS.AUTH_METHODS, [...methods], metadataTarget);\n };\n}\n\n/**\n * @WpAuthPublic(reason) - endpoint intentionally requires no authentication.\n * The non-empty reason makes anonymous exposure an explicit review decision.\n */\n// webpieces-disable no-function-outside-class -- decorator factory; decorators are inherently module-scope\nexport function WpAuthPublic(reason: string): MethodDecorator {\n if (typeof reason !== 'string' || reason.trim() === '') {\n throw new Error(\n '@WpAuthPublic requires a non-empty reason explaining why anonymous access is required.',\n );\n }\n return defineAuthMetadata(new AuthMeta([{ kind: 'public' }], reason));\n}\n\n/** Protected network ingress: authenticate one declared credential, then authorize independently. */\n// webpieces-disable no-function-outside-class -- canonical method decorator factory\nexport function WpAuth(methods: AuthMethods): MethodDecorator {\n return defineAuthMetadata(new AuthMeta(methods, undefined));\n}\n\n/** Locality is independent of authentication and cannot prove a user or machine identity. */\n// webpieces-disable no-function-outside-class -- canonical method decorator factory\nexport function WpLocalOnly(): MethodDecorator {\n return (target: object, methodName: string | symbol) => {\n if (methodName === undefined) throw new Error('@WpLocalOnly is method-only.');\n Reflect.defineMetadata(METADATA_KEYS.LOCAL_ONLY, true, target.constructor, methodName);\n };\n}\n\n// webpieces-disable no-function-outside-class -- canonical metadata reader\nexport function isLocalOnly(apiClass: Function, methodName: string): boolean {\n return Reflect.getMetadata(METADATA_KEYS.LOCAL_ONLY, apiClass, methodName) === true;\n}\n\n// ============================================================\n// Helper functions\n// ============================================================\n\n/**\n * Get the base path from @ApiPath decorator.\n */\nexport function getApiPath(apiClass: Function): string | undefined {\n return Reflect.getMetadata(METADATA_KEYS.API_PATH, apiClass);\n}\n\n/**\n * Get all endpoints from @Endpoint decorators.\n * Returns a record of methodName -> endpoint path.\n */\nexport function getEndpoints(apiClass: Function): Record<string, string> | undefined {\n return Reflect.getMetadata(METADATA_KEYS.ENDPOINTS, apiClass);\n}\n\n/**\n * Every method's declared trigger kind, as `methodName -> kind`. Parallel to {@link getEndpoints}.\n * Empty for a class carrying no @Endpoint at all.\n */\n// webpieces-disable no-function-outside-class -- reflect-metadata reader, sibling of getEndpoints\nexport function getEndpointKinds(apiClass: Function): Record<string, EndpointKind> {\n return Reflect.getMetadata(METADATA_KEYS.ENDPOINT_KIND, apiClass) || {};\n}\n\n/**\n * What triggers ONE method, or undefined when the method carries no @Endpoint.\n *\n * Defaults to nothing rather than to 'rpc': `kind` is a required argument, so a missing entry means\n * \"this is not an endpoint\", never \"an endpoint that forgot to say\". Silently defaulting here would\n * put an undeclared cron or webhook back into the graph as a normal rpc call — the exact blindness\n * the required argument exists to remove.\n */\n// webpieces-disable no-function-outside-class -- reflect-metadata reader, sibling of getEndpoints\nexport function getEndpointKind(apiClass: Function, methodName: string): EndpointKind | undefined {\n return getEndpointKinds(apiClass)[methodName];\n}\n\n/** The required HTTP method for one endpoint. */\n// webpieces-disable no-function-outside-class -- reflect-metadata reader, sibling of getEndpointKind\nexport function getEndpointHttpMethod(apiClass: Function, methodName: string): HttpMethod {\n const methods: Record<string, HttpMethod> =\n Reflect.getMetadata(METADATA_KEYS.ENDPOINT_HTTP_METHOD, apiClass) || {};\n const method = methods[methodName];\n if (!isHttpMethod(method)) {\n throw new Error(\n `@Endpoint ${apiClass.name || 'Unknown'}.${methodName} must declare GET or POST.`,\n );\n }\n return method;\n}\n\n/**\n * Get the @Endpoint options for one method (empty object if the method had no options).\n */\n// webpieces-disable no-function-outside-class -- reflect-metadata reader, sibling of getEndpoints\nexport function getEndpointOptions(apiClass: Function, methodName: string): EndpointOptions {\n const opts: Record<string, EndpointOptions> =\n Reflect.getMetadata(METADATA_KEYS.ENDPOINT_OPTIONS, apiClass) || {};\n const options = opts[methodName];\n if (!options && getEndpoints(apiClass)?.[methodName] === undefined) {\n // Preserve the historical helper behavior for a method that is not an endpoint at all.\n return {} as EndpointOptions;\n }\n return options ?? {};\n}\n\n/** Read one endpoint's required side-effect semantics. */\n// webpieces-disable no-function-outside-class -- reflect-metadata reader, sibling of getEndpointOptions\nexport function getEndpointOperation(apiClass: Function, methodName: string): EndpointOperation {\n const operations: Record<string, EndpointOperation> =\n Reflect.getMetadata(METADATA_KEYS.ENDPOINT_OPERATION, apiClass) || {};\n const operation = operations[methodName];\n if (!isEndpointOperation(operation)) {\n throw new Error(\n `@Endpoint ${apiClass.name || 'Unknown'}.${methodName} must declare READ, ` +\n 'WRITE_IDEMPOTENT, or WRITE.',\n );\n }\n return operation;\n}\n\n// webpieces-disable no-function-outside-class -- runtime backstop for JavaScript and `as any` callers; webpieces-disable no-any-unknown -- untrusted runtime value is narrowed to an endpoint operation\nfunction isEndpointOperation(value: unknown): value is EndpointOperation {\n return (\n value === READ ||\n value === WRITE_IDEMPOTENT ||\n value === WRITE\n );\n}\n\n// webpieces-disable no-function-outside-class -- runtime backstop for JavaScript and `as any` callers; webpieces-disable no-any-unknown -- untrusted runtime value is narrowed to an HTTP method\nfunction isHttpMethod(value: unknown): value is HttpMethod {\n return value === GET || value === POST;\n}\n\n// webpieces-disable no-function-outside-class -- runtime backstop for JavaScript and `as any` callers; webpieces-disable no-any-unknown -- untrusted runtime value is narrowed to an endpoint kind\nfunction isEndpointKind(value: unknown): value is EndpointKind {\n return (\n value === RPC ||\n value === CLOUDTASKS ||\n value === CRON ||\n value === EXTERNAL\n );\n}\n\n/**\n * Fail-fast at wiring time when an `external` endpoint declared no caller. The {@link Endpoint}\n * overloads already make that a COMPILE error; this is the backstop for the ways TS is bypassed —\n * a JS caller, an `as any` options object, a hand-rolled Reflect.defineMetadata.\n * @throws Error naming the first external endpoint with no `calledBy`.\n */\n// webpieces-disable no-function-outside-class -- wiring-time assert, sibling of assertEveryEndpointHasAuthMode\nexport function assertEveryExternalEndpointDeclaresCaller(apiClass: Function): void {\n const kinds = getEndpointKinds(apiClass);\n for (const methodName of Object.keys(kinds)) {\n if (\n kinds[methodName] !== 'external' ||\n getEndpointCaller(apiClass, methodName) !== undefined\n )\n continue;\n throw new Error(\n `External endpoint '${methodName}' in ${apiClass.name || 'Unknown'} declares no caller. Say WHO ` +\n `posts to it: @Endpoint(POST, path, WRITE, EXTERNAL, { calledBy: '<vendor>' }) — the runtime architecture ` +\n `graph cannot name an inbound caller it was never told about.`,\n );\n }\n}\n\n/**\n * True when the method's @Endpoint declared `{ formPost: true }` — its body is\n * application/x-www-form-urlencoded (flat), not JSON.\n */\n// webpieces-disable no-function-outside-class -- reflect-metadata reader, sibling of getEndpoints\nexport function isFormPost(apiClass: Function, methodName: string): boolean {\n return getEndpointOptions(apiClass, methodName).formPost === true;\n}\n\n/**\n * True when the method's @Endpoint declared `{ rawBody: true }` — the transport must retain the\n * verbatim bytes + absolute url for an {@link WebhookAuthCallback} hook to verify.\n */\n// webpieces-disable no-function-outside-class -- reflect-metadata reader, sibling of isFormPost\nexport function isRawBody(apiClass: Function, methodName: string): boolean {\n return getEndpointOptions(apiClass, methodName).rawBody === true;\n}\n\n/**\n * Fail-fast at wiring time when an `webhook(...)` endpoint did not ask the transport to keep the\n * bytes it is supposed to verify. A hook with nothing to verify is a MISCONFIGURATION, and it must\n * surface at startup, naming the fix — not as a 401 in production on exactly the traffic the endpoint\n * exists for.\n *\n * This pairing is a runtime assert rather than a type because the two halves live on DIFFERENT\n * decorators (`webhook(...)` and `@Endpoint`), and no union over one decorator's argument can say\n * anything about the other's.\n *\n * @throws Error naming the first `webhook(...)` endpoint missing `{ rawBody: true }`.\n */\n// webpieces-disable no-function-outside-class -- wiring-time assert, sibling of assertEveryEndpointHasAuthMode\nexport function assertEveryWebhookEndpointRetainsRawBody(apiClass: Function): void {\n const endpoints = getEndpoints(apiClass) || {};\n for (const methodName of Object.keys(endpoints)) {\n if (\n !getAuthMeta(apiClass, methodName)?.methods.some((method: AuthMode) => method.kind === 'webhook') ||\n isRawBody(apiClass, methodName)\n )\n continue;\n throw new Error(\n `Endpoint '${methodName}' in ${apiClass.name || 'Unknown'} is webhook(...) but its @Endpoint ` +\n `does not declare { rawBody: true }. A webhook hook verifies a signature over the bytes and ` +\n `the url the SENDER transmitted, and without that option the transport parses the body and ` +\n `throws them away — leaving the hook nothing to check.`,\n );\n }\n}\n\n/**\n * Check if a class has @ApiPath decorator.\n */\nexport function isApiPath(apiClass: Function): boolean {\n return Reflect.hasMetadata(METADATA_KEYS.API_PATH, apiClass);\n}\n\n/**\n * Get method-level auth metadata. Class-level authorization is forbidden.\n */\n// webpieces-disable no-function-outside-class -- reflect-metadata reader paired with the decorator API\nexport function getAuthMeta(apiClass: Function, methodName: string): AuthMeta | undefined {\n return Reflect.getMetadata(METADATA_KEYS.AUTH_META, apiClass, methodName);\n}\n\n/**\n * The ONE prescription for \"this endpoint declares no auth\", shared by the two places that raise it\n * (here and http-routing's ApiRoutingFactory) because they had drifted into teaching different menus.\n * A message teaching an incomplete API is the same defect as an API with two spellings: whichever menu\n * the caller hits becomes the API they believe exists. It leads with the ROLE-GATED member on purpose —\n * the first thing offered should not be the widest grant.\n */\nexport const MISSING_AUTH_DECORATOR_FIX =\n \"Declare @WpAuth([jwt(), oidc(...callers), sharedSecret(key), webhook(name), apiKey('regime', [{in: 'header', key: MyKeys.API_KEY}])]) \" +\n \"or @WpAuthPublic('reason'), and exactly one @WpAuthorization on every endpoint. Add @WpLocalOnly() separately when locality is required.\";\n\n/**\n * Fail-fast at wiring time if any endpoint lacks an auth mode. Both the server\n * (ApiRoutingFactory) and the task/rpc clients call this so a missing auth\n * decorator is a startup error, never a silent open endpoint.\n * @throws Error naming the first endpoint with no auth decorator, via {@link MISSING_AUTH_DECORATOR_FIX}.\n */\nexport function assertEveryEndpointHasAuthMode(apiClass: Function): void {\n const apiName = apiClass.name || 'Unknown';\n const endpoints = getEndpoints(apiClass) || {};\n for (const methodName of Object.keys(endpoints)) {\n if (!getAuthMeta(apiClass, methodName)) {\n throw new Error(\n `Endpoint '${methodName}' in ${apiName} has no auth decorator. ` +\n MISSING_AUTH_DECORATOR_FIX,\n );\n }\n const policy = getAuthorization(apiClass, methodName);\n if (!policy) throw new Error(`Endpoint '${methodName}' in ${apiName} requires @WpAuthorization.`);\n AuthorizationDeclaration.validate(policy);\n const auth = getAuthMeta(apiClass, methodName)!;\n const isPublic = auth.methods.some((method: AuthMode) => method.kind === 'public');\n if (isPublic !== (policy.authType === AuthorizationType.ANONYMOUS)) {\n throw new Error(`Endpoint '${methodName}' must pair public authentication with ANONYMOUS authorization, or protected authentication with protected/CUSTOM authorization.`);\n }\n }\n const policyMethods: string[] = Reflect.getMetadata(AUTHORIZATION_METHODS_KEY, apiClass) ?? [];\n for (const methodName of policyMethods) {\n if (!(methodName in endpoints)) throw new Error(`Orphan @WpAuthorization on ${apiName}.${methodName}; declare @Endpoint.`);\n }\n}\n\n/**\n * Validate that a class/method doesn't have conflicting auth decorators.\n * @throws Error if multiple auth decorators are found on the same target.\n */\n// webpieces-disable no-function-outside-class -- shared decorator metadata validation\nexport function validateNoConflictingDecorators(\n apiClass: Function,\n methodName: string | undefined,\n): void {\n const existing = methodName\n ? Reflect.getMetadata(METADATA_KEYS.AUTH_META, apiClass, methodName)\n : Reflect.getMetadata(METADATA_KEYS.AUTH_META, apiClass);\n\n if (existing) {\n const targetName = apiClass.name || 'Unknown';\n const location = methodName\n ? `method '${methodName}' of ${targetName}`\n : `class ${targetName}`;\n throw new Error(\n `Conflicting auth decorator on ${location}. ` +\n `Exactly one @WpAuth([...]) or @WpAuthPublic('reason') is allowed per endpoint.`,\n );\n }\n}\n"]}