@webpieces/http-routing 0.4.583 → 0.4.585

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/http-routing",
3
- "version": "0.4.583",
3
+ "version": "0.4.585",
4
4
  "description": "Decorator-based routing with auto-wiring for WebPieces",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -22,9 +22,9 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "@inversifyjs/binding-decorators": "1.1.5",
25
- "@webpieces/core-context": "0.4.583",
26
- "@webpieces/core-util": "0.4.583",
27
- "@webpieces/gcp-identity": "0.4.583",
25
+ "@webpieces/core-context": "0.4.585",
26
+ "@webpieces/core-util": "0.4.585",
27
+ "@webpieces/gcp-identity": "0.4.585",
28
28
  "inversify": "7.10.4",
29
29
  "jsonwebtoken": "9.0.2",
30
30
  "minimatch": "10.0.1"
@@ -16,7 +16,7 @@ export declare class SharedSecrets {
16
16
  }
17
17
  /**
18
18
  * AuthValues - what {@link JwtHook.parseJwt} returns: the authenticated user's id + roles (used
19
- * by the framework to stamp a principal and enforce @AuthJwt(...roles)) plus any extra context
19
+ * by the framework to stamp a principal and enforce @AuthJwt({roles: [...]})) plus any extra context
20
20
  * entries the app wants set (orgId, tenant, ...). The framework sets `entries` into RequestContext
21
21
  * via {@link RequestContext.putHeader}. Data-only structure (a class, per the guidelines).
22
22
  */
package/src/AuthConfig.js CHANGED
@@ -22,7 +22,7 @@ class SharedSecrets {
22
22
  exports.SharedSecrets = SharedSecrets;
23
23
  /**
24
24
  * AuthValues - what {@link JwtHook.parseJwt} returns: the authenticated user's id + roles (used
25
- * by the framework to stamp a principal and enforce @AuthJwt(...roles)) plus any extra context
25
+ * by the framework to stamp a principal and enforce @AuthJwt({roles: [...]})) plus any extra context
26
26
  * entries the app wants set (orgId, tenant, ...). The framework sets `entries` into RequestContext
27
27
  * via {@link RequestContext.putHeader}. Data-only structure (a class, per the guidelines).
28
28
  */
@@ -1 +1 @@
1
- {"version":3,"file":"AuthConfig.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/AuthConfig.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;GASG;AACH,MAAa,aAAa;IAEF;IACA;IAFpB,YACoB,OAAe,EACf,OAAe;QADf,YAAO,GAAP,OAAO,CAAQ;QACf,YAAO,GAAP,OAAO,CAAQ;IAChC,CAAC;CACP;AALD,sCAKC;AAED;;;;;GAKG;AACH,MAAa,UAAU;IAEC;IACA;IACA;IAEA;IALpB,YACoB,MAAc,EACd,QAAkB,EAAE,EACpB,UAA0B,EAAE;IAC5C,wGAAwG;IACxF,SAAkC,EAAE;QAJpC,WAAM,GAAN,MAAM,CAAQ;QACd,UAAK,GAAL,KAAK,CAAe;QACpB,YAAO,GAAP,OAAO,CAAqB;QAE5B,WAAM,GAAN,MAAM,CAA8B;IACrD,CAAC;CACP;AARD,gCAQC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAa,UAAU;IACnB,wGAAwG;IAC/F,aAAa,CAAgC;IAEtD,YAAY,gBAA+C,EAAE;QACzD,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IACvC,CAAC;CACJ;AAPD,gCAOC;AAED;;;;GAIG;AACH,mNAAmN;AACtM,QAAA,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC","sourcesContent":["import { ContextTuple } from '@webpieces/core-util';\n\n/**\n * SharedSecrets - the accepted values for ONE `@AuthSharedSecret(name)`. BOTH secret1 AND secret2\n * are accepted — this is what makes zero-downtime ROTATION possible:\n *\n * to rotate: shift secret2 → secret1, and put the NEW secret in secret2. Callers cut over from\n * the old value to the new during the window; once every caller sends the new one, the stale\n * value falls out on the next shift. At all times EITHER key works, so no request is dropped.\n *\n * Data-only structure (a class, per the guidelines). Leave secret2 empty for a single secret.\n */\nexport class SharedSecrets {\n constructor(\n public readonly secret1: string,\n public readonly secret2: string,\n ) {}\n}\n\n/**\n * AuthValues - what {@link JwtHook.parseJwt} returns: the authenticated user's id + roles (used\n * by the framework to stamp a principal and enforce @AuthJwt(...roles)) plus any extra context\n * entries the app wants set (orgId, tenant, ...). The framework sets `entries` into RequestContext\n * via {@link RequestContext.putHeader}. Data-only structure (a class, per the guidelines).\n */\nexport class AuthValues {\n constructor(\n public readonly userId: string,\n public readonly roles: string[] = [],\n public readonly entries: ContextTuple[] = [],\n // webpieces-disable no-any-unknown -- raw JWT claims for app-defined authorization (inOrg, tenant, ...)\n public readonly claims: Record<string, unknown> = {},\n ) {}\n}\n\n/**\n * AuthConfig - the app-provided SHARED-SECRET state the framework {@link AuthFilter} reads to\n * enforce `@AuthSharedSecret(name)` endpoints. It holds ONLY the accepted secret values (STATE) —\n * there is no verification code here. The verification MECHANISMS are separate optional hooks the\n * app binds when it needs them:\n *\n * - user JWT → bind a {@link JwtHook} (parseJwt + authorizeJwt).\n * - OIDC → bind an {@link OidcHook} to override the framework's default verifier; a server that\n * binds nothing still verifies Google OIDC via the built-in {@link DefaultOidcVerifier}.\n *\n * So a zero-wiring server accepts service-to-service OIDC out of the box, and an app only binds the\n * pieces it actually uses. This class is injected `@optional` into AuthFilter (rebindable in tests);\n * when unbound, shared-secret endpoints simply have no accepted secret and fail fast (401).\n */\nexport class AuthConfig {\n /** Accepted shared-secret values keyed by `@AuthSharedSecret(name)`. DEFAULT empty — pass to enable. */\n readonly sharedSecrets: Record<string, SharedSecrets>;\n\n constructor(sharedSecrets: Record<string, SharedSecrets> = {}) {\n this.sharedSecrets = sharedSecrets;\n }\n}\n\n/**\n * DI identifier for the optional {@link AuthConfig} binding. It is a Symbol (not the class) so the app\n * container's inversify autobind never auto-constructs this token, keeping `@optional() @inject(AUTH_CONFIG)`\n * correct — undefined when unbound. The AuthConfig class stays the TYPE and the impl base.\n */\n// webpieces-disable no-symbol-di-tokens -- optional DI token: must be a Symbol so the app container's autobind never auto-constructs this token, keeping @optional() @inject(...) correct (undefined when unbound)\nexport const AUTH_CONFIG = Symbol.for('AuthConfig');\n"]}
1
+ {"version":3,"file":"AuthConfig.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/AuthConfig.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;GASG;AACH,MAAa,aAAa;IAEF;IACA;IAFpB,YACoB,OAAe,EACf,OAAe;QADf,YAAO,GAAP,OAAO,CAAQ;QACf,YAAO,GAAP,OAAO,CAAQ;IAChC,CAAC;CACP;AALD,sCAKC;AAED;;;;;GAKG;AACH,MAAa,UAAU;IAEC;IACA;IACA;IAEA;IALpB,YACoB,MAAc,EACd,QAAkB,EAAE,EACpB,UAA0B,EAAE;IAC5C,wGAAwG;IACxF,SAAkC,EAAE;QAJpC,WAAM,GAAN,MAAM,CAAQ;QACd,UAAK,GAAL,KAAK,CAAe;QACpB,YAAO,GAAP,OAAO,CAAqB;QAE5B,WAAM,GAAN,MAAM,CAA8B;IACrD,CAAC;CACP;AARD,gCAQC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAa,UAAU;IACnB,wGAAwG;IAC/F,aAAa,CAAgC;IAEtD,YAAY,gBAA+C,EAAE;QACzD,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IACvC,CAAC;CACJ;AAPD,gCAOC;AAED;;;;GAIG;AACH,mNAAmN;AACtM,QAAA,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC","sourcesContent":["import { ContextTuple } from '@webpieces/core-util';\n\n/**\n * SharedSecrets - the accepted values for ONE `@AuthSharedSecret(name)`. BOTH secret1 AND secret2\n * are accepted — this is what makes zero-downtime ROTATION possible:\n *\n * to rotate: shift secret2 → secret1, and put the NEW secret in secret2. Callers cut over from\n * the old value to the new during the window; once every caller sends the new one, the stale\n * value falls out on the next shift. At all times EITHER key works, so no request is dropped.\n *\n * Data-only structure (a class, per the guidelines). Leave secret2 empty for a single secret.\n */\nexport class SharedSecrets {\n constructor(\n public readonly secret1: string,\n public readonly secret2: string,\n ) {}\n}\n\n/**\n * AuthValues - what {@link JwtHook.parseJwt} returns: the authenticated user's id + roles (used\n * by the framework to stamp a principal and enforce @AuthJwt({roles: [...]})) plus any extra context\n * entries the app wants set (orgId, tenant, ...). The framework sets `entries` into RequestContext\n * via {@link RequestContext.putHeader}. Data-only structure (a class, per the guidelines).\n */\nexport class AuthValues {\n constructor(\n public readonly userId: string,\n public readonly roles: string[] = [],\n public readonly entries: ContextTuple[] = [],\n // webpieces-disable no-any-unknown -- raw JWT claims for app-defined authorization (inOrg, tenant, ...)\n public readonly claims: Record<string, unknown> = {},\n ) {}\n}\n\n/**\n * AuthConfig - the app-provided SHARED-SECRET state the framework {@link AuthFilter} reads to\n * enforce `@AuthSharedSecret(name)` endpoints. It holds ONLY the accepted secret values (STATE) —\n * there is no verification code here. The verification MECHANISMS are separate optional hooks the\n * app binds when it needs them:\n *\n * - user JWT → bind a {@link JwtHook} (parseJwt + authorizeJwt).\n * - OIDC → bind an {@link OidcHook} to override the framework's default verifier; a server that\n * binds nothing still verifies Google OIDC via the built-in {@link DefaultOidcVerifier}.\n *\n * So a zero-wiring server accepts service-to-service OIDC out of the box, and an app only binds the\n * pieces it actually uses. This class is injected `@optional` into AuthFilter (rebindable in tests);\n * when unbound, shared-secret endpoints simply have no accepted secret and fail fast (401).\n */\nexport class AuthConfig {\n /** Accepted shared-secret values keyed by `@AuthSharedSecret(name)`. DEFAULT empty — pass to enable. */\n readonly sharedSecrets: Record<string, SharedSecrets>;\n\n constructor(sharedSecrets: Record<string, SharedSecrets> = {}) {\n this.sharedSecrets = sharedSecrets;\n }\n}\n\n/**\n * DI identifier for the optional {@link AuthConfig} binding. It is a Symbol (not the class) so the app\n * container's inversify autobind never auto-constructs this token, keeping `@optional() @inject(AUTH_CONFIG)`\n * correct — undefined when unbound. The AuthConfig class stays the TYPE and the impl base.\n */\n// webpieces-disable no-symbol-di-tokens -- optional DI token: must be a Symbol so the app container's autobind never auto-constructs this token, keeping @optional() @inject(...) correct (undefined when unbound)\nexport const AUTH_CONFIG = Symbol.for('AuthConfig');\n"]}
@@ -3,23 +3,24 @@ import { AuthValues } from './AuthConfig';
3
3
  /**
4
4
  * JwtHook - the OPTIONAL user-JWT mechanism. Its DI token is the {@link JWT_HOOK} Symbol injected via
5
5
  * `@inject(JWT_HOOK)` (a Symbol, because the app container uses autobind; rebindable in tests). Bind one
6
- * to turn on `@AuthJwt(...)` endpoints. When NO JwtHook is bound, the framework
6
+ * to turn on `@AuthJwt({...})` endpoints. When NO JwtHook is bound, the framework
7
7
  * {@link AuthFilter} treats every jwt endpoint as "not enabled" and fails fast (401) — there is no
8
8
  * default JWT verification because it needs an app secret + payload shape the framework can't guess.
9
9
  *
10
10
  * - `parseJwt` — AUTHENTICATION: decode/verify a user JWT into {@link AuthValues}, or throw. The
11
11
  * app owns the strategy (HS256 secret, RS256 + JWKS, a provider SDK, ...).
12
12
  * - `authorizeJwt` — AUTHORIZATION: check the authenticated user against the endpoint's
13
- * {@link JwtRequirement}. The DEFAULT enforces `roles` (any-of; empty = any
14
- * authenticated user); override for app-defined requirements carried by
15
- * `@Auth({...})` e.g. `if (requirement['inOrg'] && !values.claims['orgId']) ...`.
13
+ * {@link JwtRequirement}. The DEFAULT enforces the roles any-of; override for
14
+ * app-defined requirements carried by the SAME decorator, e.g.
15
+ * `@AuthJwt({allRolesAllowed: true, inOrg: true})`
16
+ * `if (requirement['inOrg'] && !values.claims['orgId']) ...`.
16
17
  */
17
18
  export declare abstract class JwtHook {
18
19
  /** Parse a user JWT (kind:'jwt') — AUTHENTICATION only. Return who the user is, or throw. */
19
20
  abstract parseJwt(token: string): AuthValues;
20
21
  /**
21
- * DEFAULT authorization: enforce `roles` (any-of; empty = any authenticated user). Override to
22
- * enforce app-defined requirements. Throw HttpForbiddenError to deny; return to allow.
22
+ * DEFAULT authorization: enforce the endpoint's roles (any-of). Override to enforce app-defined
23
+ * requirements. Throw HttpForbiddenError to deny; return to allow.
23
24
  */
24
25
  authorizeJwt(values: AuthValues, requirement: JwtRequirement): void;
25
26
  }
package/src/AuthHooks.js CHANGED
@@ -5,24 +5,27 @@ const core_util_1 = require("@webpieces/core-util");
5
5
  /**
6
6
  * JwtHook - the OPTIONAL user-JWT mechanism. Its DI token is the {@link JWT_HOOK} Symbol injected via
7
7
  * `@inject(JWT_HOOK)` (a Symbol, because the app container uses autobind; rebindable in tests). Bind one
8
- * to turn on `@AuthJwt(...)` endpoints. When NO JwtHook is bound, the framework
8
+ * to turn on `@AuthJwt({...})` endpoints. When NO JwtHook is bound, the framework
9
9
  * {@link AuthFilter} treats every jwt endpoint as "not enabled" and fails fast (401) — there is no
10
10
  * default JWT verification because it needs an app secret + payload shape the framework can't guess.
11
11
  *
12
12
  * - `parseJwt` — AUTHENTICATION: decode/verify a user JWT into {@link AuthValues}, or throw. The
13
13
  * app owns the strategy (HS256 secret, RS256 + JWKS, a provider SDK, ...).
14
14
  * - `authorizeJwt` — AUTHORIZATION: check the authenticated user against the endpoint's
15
- * {@link JwtRequirement}. The DEFAULT enforces `roles` (any-of; empty = any
16
- * authenticated user); override for app-defined requirements carried by
17
- * `@Auth({...})` e.g. `if (requirement['inOrg'] && !values.claims['orgId']) ...`.
15
+ * {@link JwtRequirement}. The DEFAULT enforces the roles any-of; override for
16
+ * app-defined requirements carried by the SAME decorator, e.g.
17
+ * `@AuthJwt({allRolesAllowed: true, inOrg: true})`
18
+ * `if (requirement['inOrg'] && !values.claims['orgId']) ...`.
18
19
  */
19
20
  class JwtHook {
20
21
  /**
21
- * DEFAULT authorization: enforce `roles` (any-of; empty = any authenticated user). Override to
22
- * enforce app-defined requirements. Throw HttpForbiddenError to deny; return to allow.
22
+ * DEFAULT authorization: enforce the endpoint's roles (any-of). Override to enforce app-defined
23
+ * requirements. Throw HttpForbiddenError to deny; return to allow.
23
24
  */
24
25
  authorizeJwt(values, requirement) {
25
- const roles = requirement.roles ?? [];
26
+ // rolesRequired is the ONE reader of the JwtRoles union: [] means the endpoint typed
27
+ // `allRolesAllowed: true`, never "the field was missing" — that state no longer compiles.
28
+ const roles = (0, core_util_1.rolesRequired)(requirement);
26
29
  if (roles.length > 0 && !roles.some((role) => values.roles.includes(role))) {
27
30
  throw new core_util_1.HttpForbiddenError(`Endpoint requires one of roles: ${roles.join(', ')}`);
28
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AuthHooks.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/AuthHooks.ts"],"names":[],"mappings":";;;AAAA,oDAA0E;AAG1E;;;;;;;;;;;;;GAaG;AACH,MAAsB,OAAO;IAIzB;;;OAGG;IACH,YAAY,CAAC,MAAkB,EAAE,WAA2B;QACxD,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE,CAAC;QACtC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YACjF,MAAM,IAAI,8BAAkB,CAAC,mCAAmC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxF,CAAC;IACL,CAAC;CACJ;AAdD,0BAcC;AAED;;;;GAIG;AACH,mNAAmN;AACtM,QAAA,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAE9C;;;;;;;;;GASG;AACH,MAAsB,QAAQ;CAE7B;AAFD,4BAEC;AAED;;;;GAIG;AACH,mNAAmN;AACtM,QAAA,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC","sourcesContent":["import { JwtRequirement, HttpForbiddenError } from '@webpieces/core-util';\nimport { AuthValues } from './AuthConfig';\n\n/**\n * JwtHook - the OPTIONAL user-JWT mechanism. Its DI token is the {@link JWT_HOOK} Symbol injected via\n * `@inject(JWT_HOOK)` (a Symbol, because the app container uses autobind; rebindable in tests). Bind one\n * to turn on `@AuthJwt(...)` endpoints. When NO JwtHook is bound, the framework\n * {@link AuthFilter} treats every jwt endpoint as \"not enabled\" and fails fast (401) — there is no\n * default JWT verification because it needs an app secret + payload shape the framework can't guess.\n *\n * - `parseJwt` — AUTHENTICATION: decode/verify a user JWT into {@link AuthValues}, or throw. The\n * app owns the strategy (HS256 secret, RS256 + JWKS, a provider SDK, ...).\n * - `authorizeJwt` — AUTHORIZATION: check the authenticated user against the endpoint's\n * {@link JwtRequirement}. The DEFAULT enforces `roles` (any-of; empty = any\n * authenticated user); override for app-defined requirements carried by\n * `@Auth({...})` e.g. `if (requirement['inOrg'] && !values.claims['orgId']) ...`.\n */\nexport abstract class JwtHook {\n /** Parse a user JWT (kind:'jwt') — AUTHENTICATION only. Return who the user is, or throw. */\n abstract parseJwt(token: string): AuthValues;\n\n /**\n * DEFAULT authorization: enforce `roles` (any-of; empty = any authenticated user). Override to\n * enforce app-defined requirements. Throw HttpForbiddenError to deny; return to allow.\n */\n authorizeJwt(values: AuthValues, requirement: JwtRequirement): void {\n const roles = requirement.roles ?? [];\n if (roles.length > 0 && !roles.some((role: string) => values.roles.includes(role))) {\n throw new HttpForbiddenError(`Endpoint requires one of roles: ${roles.join(', ')}`);\n }\n }\n}\n\n/**\n * DI identifier for the optional {@link JwtHook} binding. It is a Symbol (not the class) so the app\n * container's inversify autobind never auto-constructs this token, keeping `@optional() @inject(JWT_HOOK)`\n * correct — undefined when unbound. The JwtHook class stays the TYPE and the impl base.\n */\n// webpieces-disable no-symbol-di-tokens -- optional DI token: must be a Symbol so the app container's autobind never auto-constructs this token, keeping @optional() @inject(...) correct (undefined when unbound)\nexport const JWT_HOOK = Symbol.for('JwtHook');\n\n/**\n * OidcHook - the OPTIONAL override for Google OIDC service-to-service verification. Its DI token is the\n * {@link OIDC_HOOK} Symbol injected via `@inject(OIDC_HOOK)` (a Symbol, because the app container uses\n * autobind; rebindable in tests). Bind one ONLY to customize the caller policy — e.g. an app that reads an\n * `ALLOWED_OIDC_CALLERS` env var at its composition root and enforces that allow-list. When NO\n * OidcHook is bound, the framework {@link AuthFilter} runs the built-in {@link DefaultOidcVerifier}\n * directly, so a server that wires nothing still verifies Google OIDC against its `@AuthOidc(...callers)`\n * (else trusts the edge — any Google-signed caller). `verifyOidc` verifies the token against `callers`;\n * throw on failure.\n */\nexport abstract class OidcHook {\n abstract verifyOidc(token: string, callers: string[]): Promise<void>;\n}\n\n/**\n * DI identifier for the optional {@link OidcHook} binding. It is a Symbol (not the class) so the app\n * container's inversify autobind never auto-constructs this token, keeping `@optional() @inject(OIDC_HOOK)`\n * correct — undefined when unbound. The OidcHook class stays the TYPE and the impl base.\n */\n// webpieces-disable no-symbol-di-tokens -- optional DI token: must be a Symbol so the app container's autobind never auto-constructs this token, keeping @optional() @inject(...) correct (undefined when unbound)\nexport const OIDC_HOOK = Symbol.for('OidcHook');\n"]}
1
+ {"version":3,"file":"AuthHooks.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/AuthHooks.ts"],"names":[],"mappings":";;;AAAA,oDAAyF;AAGzF;;;;;;;;;;;;;;GAcG;AACH,MAAsB,OAAO;IAIzB;;;OAGG;IACH,YAAY,CAAC,MAAkB,EAAE,WAA2B;QACxD,qFAAqF;QACrF,0FAA0F;QAC1F,MAAM,KAAK,GAAG,IAAA,yBAAa,EAAC,WAAW,CAAC,CAAC;QACzC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YACjF,MAAM,IAAI,8BAAkB,CAAC,mCAAmC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxF,CAAC;IACL,CAAC;CACJ;AAhBD,0BAgBC;AAED;;;;GAIG;AACH,mNAAmN;AACtM,QAAA,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAE9C;;;;;;;;;GASG;AACH,MAAsB,QAAQ;CAE7B;AAFD,4BAEC;AAED;;;;GAIG;AACH,mNAAmN;AACtM,QAAA,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC","sourcesContent":["import { JwtRequirement, rolesRequired, HttpForbiddenError } from '@webpieces/core-util';\nimport { AuthValues } from './AuthConfig';\n\n/**\n * JwtHook - the OPTIONAL user-JWT mechanism. Its DI token is the {@link JWT_HOOK} Symbol injected via\n * `@inject(JWT_HOOK)` (a Symbol, because the app container uses autobind; rebindable in tests). Bind one\n * to turn on `@AuthJwt({...})` endpoints. When NO JwtHook is bound, the framework\n * {@link AuthFilter} treats every jwt endpoint as \"not enabled\" and fails fast (401) — there is no\n * default JWT verification because it needs an app secret + payload shape the framework can't guess.\n *\n * - `parseJwt` — AUTHENTICATION: decode/verify a user JWT into {@link AuthValues}, or throw. The\n * app owns the strategy (HS256 secret, RS256 + JWKS, a provider SDK, ...).\n * - `authorizeJwt` — AUTHORIZATION: check the authenticated user against the endpoint's\n * {@link JwtRequirement}. The DEFAULT enforces the roles any-of; override for\n * app-defined requirements carried by the SAME decorator, e.g.\n * `@AuthJwt({allRolesAllowed: true, inOrg: true})` →\n * `if (requirement['inOrg'] && !values.claims['orgId']) ...`.\n */\nexport abstract class JwtHook {\n /** Parse a user JWT (kind:'jwt') — AUTHENTICATION only. Return who the user is, or throw. */\n abstract parseJwt(token: string): AuthValues;\n\n /**\n * DEFAULT authorization: enforce the endpoint's roles (any-of). Override to enforce app-defined\n * requirements. Throw HttpForbiddenError to deny; return to allow.\n */\n authorizeJwt(values: AuthValues, requirement: JwtRequirement): void {\n // rolesRequired is the ONE reader of the JwtRoles union: [] means the endpoint typed\n // `allRolesAllowed: true`, never \"the field was missing\" — that state no longer compiles.\n const roles = rolesRequired(requirement);\n if (roles.length > 0 && !roles.some((role: string) => values.roles.includes(role))) {\n throw new HttpForbiddenError(`Endpoint requires one of roles: ${roles.join(', ')}`);\n }\n }\n}\n\n/**\n * DI identifier for the optional {@link JwtHook} binding. It is a Symbol (not the class) so the app\n * container's inversify autobind never auto-constructs this token, keeping `@optional() @inject(JWT_HOOK)`\n * correct — undefined when unbound. The JwtHook class stays the TYPE and the impl base.\n */\n// webpieces-disable no-symbol-di-tokens -- optional DI token: must be a Symbol so the app container's autobind never auto-constructs this token, keeping @optional() @inject(...) correct (undefined when unbound)\nexport const JWT_HOOK = Symbol.for('JwtHook');\n\n/**\n * OidcHook - the OPTIONAL override for Google OIDC service-to-service verification. Its DI token is the\n * {@link OIDC_HOOK} Symbol injected via `@inject(OIDC_HOOK)` (a Symbol, because the app container uses\n * autobind; rebindable in tests). Bind one ONLY to customize the caller policy — e.g. an app that reads an\n * `ALLOWED_OIDC_CALLERS` env var at its composition root and enforces that allow-list. When NO\n * OidcHook is bound, the framework {@link AuthFilter} runs the built-in {@link DefaultOidcVerifier}\n * directly, so a server that wires nothing still verifies Google OIDC against its `@AuthOidc(...callers)`\n * (else trusts the edge — any Google-signed caller). `verifyOidc` verifies the token against `callers`;\n * throw on failure.\n */\nexport abstract class OidcHook {\n abstract verifyOidc(token: string, callers: string[]): Promise<void>;\n}\n\n/**\n * DI identifier for the optional {@link OidcHook} binding. It is a Symbol (not the class) so the app\n * container's inversify autobind never auto-constructs this token, keeping `@optional() @inject(OIDC_HOOK)`\n * correct — undefined when unbound. The OidcHook class stays the TYPE and the impl base.\n */\n// webpieces-disable no-symbol-di-tokens -- optional DI token: must be a Symbol so the app container's autobind never auto-constructs this token, keeping @optional() @inject(...) correct (undefined when unbound)\nexport const OIDC_HOOK = Symbol.for('OidcHook');\n"]}
package/src/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { ApiPath, Endpoint, Public, AuthJwt, AuthJwtAllRolesAllowed, AuthOidc, AuthSharedSecret, Rpc, PubSub, Queue, getApiPath, getEndpoints, getEndpointOptions, isFormPost, isApiPath, getAuthMeta, getAuthMode, assertEveryEndpointHasAuthMode, getApiKind, assertApiKind, assertPubSubConventions, getQueueName, AuthMeta, RouteMetadata, METADATA_KEYS, ValidateImplementation, DocumentDesign, isDocumentDesign, } from '@webpieces/core-util';
1
+ export { ApiPath, Endpoint, Public, AuthJwt, rolesRequired, AuthOidc, AuthSharedSecret, Rpc, PubSub, Queue, getApiPath, getEndpoints, getEndpointOptions, isFormPost, isApiPath, getAuthMeta, getAuthMode, assertEveryEndpointHasAuthMode, getApiKind, assertApiKind, assertPubSubConventions, getQueueName, AuthMeta, RouteMetadata, METADATA_KEYS, ValidateImplementation, DocumentDesign, isDocumentDesign, } from '@webpieces/core-util';
2
2
  export type { AuthMode, ApiKind, EndpointOptions } from '@webpieces/core-util';
3
3
  export { SourceFile, ROUTING_METADATA_KEYS, } from './decorators';
4
4
  export { provideSingletonDefaultForApi } from '@webpieces/core-context';
package/src/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.JwtHook = exports.SharedSecrets = exports.AuthValues = exports.AUTH_CONFIG = exports.AuthConfig = exports.ApiClient = exports.FilterMatcher = exports.LogApiFilter = exports.RouteHandler = exports.MethodMeta = exports.FilterChain = exports.WpResponse = exports.Filter = exports.HttpRequest = exports.FilterDefinition = exports.RouteDefinition = exports.ApiRoutingFactory = exports.buildFrameworkModule = exports.provideFrameworkSingletonDefaultForApi = exports.provideFrameworkSingleton = exports.provideSingletonDefaultForApi = exports.ROUTING_METADATA_KEYS = exports.SourceFile = exports.isDocumentDesign = exports.DocumentDesign = exports.METADATA_KEYS = exports.RouteMetadata = exports.AuthMeta = exports.getQueueName = exports.assertPubSubConventions = exports.assertApiKind = exports.getApiKind = exports.assertEveryEndpointHasAuthMode = exports.getAuthMode = exports.getAuthMeta = exports.isApiPath = exports.isFormPost = exports.getEndpointOptions = exports.getEndpoints = exports.getApiPath = exports.Queue = exports.PubSub = exports.Rpc = exports.AuthSharedSecret = exports.AuthOidc = exports.AuthJwtAllRolesAllowed = exports.AuthJwt = exports.Public = exports.Endpoint = exports.ApiPath = void 0;
3
+ exports.JwtHook = exports.SharedSecrets = exports.AuthValues = exports.AUTH_CONFIG = exports.AuthConfig = exports.ApiClient = exports.FilterMatcher = exports.LogApiFilter = exports.RouteHandler = exports.MethodMeta = exports.FilterChain = exports.WpResponse = exports.Filter = exports.HttpRequest = exports.FilterDefinition = exports.RouteDefinition = exports.ApiRoutingFactory = exports.buildFrameworkModule = exports.provideFrameworkSingletonDefaultForApi = exports.provideFrameworkSingleton = exports.provideSingletonDefaultForApi = exports.ROUTING_METADATA_KEYS = exports.SourceFile = exports.isDocumentDesign = exports.DocumentDesign = exports.METADATA_KEYS = exports.RouteMetadata = exports.AuthMeta = exports.getQueueName = exports.assertPubSubConventions = exports.assertApiKind = exports.getApiKind = exports.assertEveryEndpointHasAuthMode = exports.getAuthMode = exports.getAuthMeta = exports.isApiPath = exports.isFormPost = exports.getEndpointOptions = exports.getEndpoints = exports.getApiPath = exports.Queue = exports.PubSub = exports.Rpc = exports.AuthSharedSecret = exports.AuthOidc = exports.rolesRequired = exports.AuthJwt = exports.Public = exports.Endpoint = exports.ApiPath = void 0;
4
4
  exports.WEBPIECES_CONFIG_TOKEN = exports.WebpiecesConfig = exports.RuntimeSetupOptions = exports.setupRuntime = exports.WebpiecesRouterFactory = exports.WebpiecesRouter = exports.DefaultJwtHook = exports.DefaultOidcVerifier = exports.OIDC_HOOK = exports.OidcHook = exports.JWT_HOOK = void 0;
5
5
  // Re-export API decorators from core-util for convenience
6
6
  var core_util_1 = require("@webpieces/core-util");
@@ -8,7 +8,7 @@ Object.defineProperty(exports, "ApiPath", { enumerable: true, get: function () {
8
8
  Object.defineProperty(exports, "Endpoint", { enumerable: true, get: function () { return core_util_1.Endpoint; } });
9
9
  Object.defineProperty(exports, "Public", { enumerable: true, get: function () { return core_util_1.Public; } });
10
10
  Object.defineProperty(exports, "AuthJwt", { enumerable: true, get: function () { return core_util_1.AuthJwt; } });
11
- Object.defineProperty(exports, "AuthJwtAllRolesAllowed", { enumerable: true, get: function () { return core_util_1.AuthJwtAllRolesAllowed; } });
11
+ Object.defineProperty(exports, "rolesRequired", { enumerable: true, get: function () { return core_util_1.rolesRequired; } });
12
12
  Object.defineProperty(exports, "AuthOidc", { enumerable: true, get: function () { return core_util_1.AuthOidc; } });
13
13
  Object.defineProperty(exports, "AuthSharedSecret", { enumerable: true, get: function () { return core_util_1.AuthSharedSecret; } });
14
14
  Object.defineProperty(exports, "Rpc", { enumerable: true, get: function () { return core_util_1.Rpc; } });
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/index.ts"],"names":[],"mappings":";;;;AAAA,0DAA0D;AAC1D,kDA+B8B;AA9B1B,oGAAA,OAAO,OAAA;AACP,qGAAA,QAAQ,OAAA;AACR,mGAAA,MAAM,OAAA;AACN,oGAAA,OAAO,OAAA;AACP,mHAAA,sBAAsB,OAAA;AACtB,qGAAA,QAAQ,OAAA;AACR,6GAAA,gBAAgB,OAAA;AAChB,gGAAA,GAAG,OAAA;AACH,mGAAA,MAAM,OAAA;AACN,kGAAA,KAAK,OAAA;AACL,uGAAA,UAAU,OAAA;AACV,yGAAA,YAAY,OAAA;AACZ,+GAAA,kBAAkB,OAAA;AAClB,uGAAA,UAAU,OAAA;AACV,sGAAA,SAAS,OAAA;AACT,wGAAA,WAAW,OAAA;AACX,wGAAA,WAAW,OAAA;AACX,2HAAA,8BAA8B,OAAA;AAC9B,uGAAA,UAAU,OAAA;AACV,0GAAA,aAAa,OAAA;AACb,oHAAA,uBAAuB,OAAA;AACvB,yGAAA,YAAY,OAAA;AACZ,qGAAA,QAAQ,OAAA;AACR,0GAAA,aAAa,OAAA;AACb,0GAAA,aAAa,OAAA;AAEb,2EAA2E;AAC3E,oCAAoC;AACpC,2GAAA,cAAc,OAAA;AACd,6GAAA,gBAAgB,OAAA;AAIpB,+CAA+C;AAC/C,2CAGsB;AAFlB,wGAAA,UAAU,OAAA;AACV,mHAAA,qBAAqB,OAAA;AAGzB,iFAAiF;AACjF,wDAAwE;AAA/D,6HAAA,6BAA6B,OAAA;AACtC,gGAAgG;AAChG,wDAIiC;AAH7B,yHAAA,yBAAyB,OAAA;AACzB,sIAAA,sCAAsC,OAAA;AACtC,oHAAA,oBAAoB,OAAA;AAGxB,yDAAmE;AAA1D,sHAAA,iBAAiB,OAAA;AAE1B,qBAAqB;AACrB,2CAKsB;AAFlB,6GAAA,eAAe,OAAA;AACf,8GAAA,gBAAgB,OAAA;AAGpB,sFAAsF;AACtF,+FAA+F;AAC/F,wDAAsD;AAA7C,2GAAA,WAAW,OAAA;AAEpB,qFAAqF;AACrF,mCAAuD;AAA9C,gGAAA,MAAM,OAAA;AAAE,oGAAA,UAAU,OAAA;AAC3B,6CAA4C;AAAnC,0GAAA,WAAW,OAAA;AACpB,2CAA0C;AAAjC,wGAAA,UAAU,OAAA;AACnB,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AAErB,wFAAwF;AACxF,0FAA0F;AAC1F,uDAAsD;AAA7C,4GAAA,YAAY,OAAA;AAErB,oFAAoF;AACpF,sFAAsF;AAEtF,kBAAkB;AAClB,iDAA4D;AAAnD,8GAAA,aAAa,OAAA;AAOtB,yCAAwD;AAA/C,sGAAA,SAAS,OAAA;AAElB,mFAAmF;AACnF,iEAAiE;AACjE,oFAAoF;AACpF,4FAA4F;AAC5F,2CAAkF;AAAzE,wGAAA,UAAU,OAAA;AAAE,yGAAA,WAAW,OAAA;AAAE,wGAAA,UAAU,OAAA;AAAE,2GAAA,aAAa,OAAA;AAC3D,yCAAqE;AAA5D,oGAAA,OAAO,OAAA;AAAE,qGAAA,QAAQ,OAAA;AAAE,qGAAA,QAAQ,OAAA;AAAE,sGAAA,SAAS,OAAA;AAC/C,6DAA4D;AAAnD,0HAAA,mBAAmB,OAAA;AAC5B,0FAA0F;AAC1F,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AAEvB,kEAAkE;AAElE,0FAA0F;AAC1F,qDAAoG;AAA3F,kHAAA,eAAe,OAAA;AAAE,yHAAA,sBAAsB,OAAA;AAEhD,8FAA8F;AAC9F,kGAAkG;AAClG,+CAAmE;AAA1D,4GAAA,YAAY,OAAA;AAAE,mHAAA,mBAAmB,OAAA;AAE1C,uBAAuB;AACvB,qDAA4E;AAAnE,kHAAA,eAAe,OAAA;AAAE,yHAAA,sBAAsB,OAAA","sourcesContent":["// Re-export API decorators from core-util for convenience\nexport {\n ApiPath,\n Endpoint,\n Public,\n AuthJwt,\n AuthJwtAllRolesAllowed,\n AuthOidc,\n AuthSharedSecret,\n Rpc,\n PubSub,\n Queue,\n getApiPath,\n getEndpoints,\n getEndpointOptions,\n isFormPost,\n isApiPath,\n getAuthMeta,\n getAuthMode,\n assertEveryEndpointHasAuthMode,\n getApiKind,\n assertApiKind,\n assertPubSubConventions,\n getQueueName,\n AuthMeta,\n RouteMetadata,\n METADATA_KEYS,\n ValidateImplementation,\n // @DocumentDesign moved to core-util (design-root marker, browser + Node);\n // re-exported here for back-compat.\n DocumentDesign,\n isDocumentDesign,\n} from '@webpieces/core-util';\nexport type { AuthMode, ApiKind, EndpointOptions } from '@webpieces/core-util';\n\n// Server-side routing decorators and utilities\nexport {\n SourceFile,\n ROUTING_METADATA_KEYS,\n} from './decorators';\n\n// DI provider decorators moved to core-context; re-exported here for back-compat\nexport { provideSingletonDefaultForApi } from '@webpieces/core-context';\n// Framework-only DI registry (packages/** framework classes use these; see frameworkProvide.ts)\nexport {\n provideFrameworkSingleton,\n provideFrameworkSingletonDefaultForApi,\n buildFrameworkModule,\n} from '@webpieces/core-context';\n\nexport { ApiRoutingFactory, ClassType } from './ApiRoutingFactory';\n\n// Core routing types\nexport {\n Routes,\n RouteBuilder,\n RouteDefinition,\n FilterDefinition,\n} from './WebAppMeta';\n\n// The transport-neutral request type (defined in core-context; this is http-routing's\n// public request — a transport adapter builds one and the chain reads it from RequestContext).\nexport { HttpRequest } from '@webpieces/core-context';\n\n// Filter-chain primitives (absorbed from the former @webpieces/http-filters package)\nexport { Filter, WpResponse, Service } from './Filter';\nexport { FilterChain } from './FilterChain';\nexport { MethodMeta } from './MethodMeta';\nexport { RouteHandler } from './RouteHandler';\n\n// LogApiFilter: the fixed OUTERMOST framework filter (auto-installed at 1,000,000 above\n// AuthFilter). Exported for reference/testing only — apps must NOT install it themselves.\nexport { LogApiFilter } from './filters/LogApiFilter';\n\n// RouteBuilderImpl (the route table + chain composer) is now INTERNAL — it is never\n// handed to upper layers. The express layer consumes ApiFactory.apiClients() instead.\n\n// Filter matching\nexport { FilterMatcher, HttpFilter } from './FilterMatcher';\n\n// The app's server-surface declaration: DI binding modules + route groups + headers.\nexport { AppModules, RouteModule } from './AppModules';\n\n// The public API-surface abstraction: declare routes/filters, get them back as ApiClient[].\nexport { ApiFactory } from './ApiFactory';\nexport { ApiClient, ApiClientProxy } from './ApiClient';\n\n// Auth: the app-provided, container-bound pieces the framework AuthFilter injects.\n// - AuthConfig: shared-secret STATE (@AuthSharedSecret values).\n// - JwtHook / OidcHook: OPTIONAL verification mechanisms (bind only what you use).\n// - DefaultOidcVerifier: the built-in Google OIDC verifier used when no OidcHook is bound.\nexport { AuthConfig, AUTH_CONFIG, AuthValues, SharedSecrets } from './AuthConfig';\nexport { JwtHook, JWT_HOOK, OidcHook, OIDC_HOOK } from './AuthHooks';\nexport { DefaultOidcVerifier } from './DefaultOidcVerifier';\n// DefaultJwtHook: batteries-included HS256 JwtHook — `new DefaultJwtHook(secret)` and go.\nexport { DefaultJwtHook } from './DefaultJwtHook';\n\n// Above-boundary context setup shared by every transport adapter.\n\n// Node-only router (the express-free heart: container + filter chain + in-process client)\nexport { WebpiecesRouter, WebpiecesRouterFactory, WebpiecesRouterOptions } from './WebpiecesRouter';\n\n// The ONE transport-free startup sequence (headers → logging → router → routes) → ApiFactory.\n// Reusable by any company/app and any framework adapter; a company wraps it with its own headers.\nexport { setupRuntime, RuntimeSetupOptions } from './setupRuntime';\n\n// Server configuration\nexport { WebpiecesConfig, WEBPIECES_CONFIG_TOKEN } from './WebpiecesConfig';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/index.ts"],"names":[],"mappings":";;;;AAAA,0DAA0D;AAC1D,kDA+B8B;AA9B1B,oGAAA,OAAO,OAAA;AACP,qGAAA,QAAQ,OAAA;AACR,mGAAA,MAAM,OAAA;AACN,oGAAA,OAAO,OAAA;AACP,0GAAA,aAAa,OAAA;AACb,qGAAA,QAAQ,OAAA;AACR,6GAAA,gBAAgB,OAAA;AAChB,gGAAA,GAAG,OAAA;AACH,mGAAA,MAAM,OAAA;AACN,kGAAA,KAAK,OAAA;AACL,uGAAA,UAAU,OAAA;AACV,yGAAA,YAAY,OAAA;AACZ,+GAAA,kBAAkB,OAAA;AAClB,uGAAA,UAAU,OAAA;AACV,sGAAA,SAAS,OAAA;AACT,wGAAA,WAAW,OAAA;AACX,wGAAA,WAAW,OAAA;AACX,2HAAA,8BAA8B,OAAA;AAC9B,uGAAA,UAAU,OAAA;AACV,0GAAA,aAAa,OAAA;AACb,oHAAA,uBAAuB,OAAA;AACvB,yGAAA,YAAY,OAAA;AACZ,qGAAA,QAAQ,OAAA;AACR,0GAAA,aAAa,OAAA;AACb,0GAAA,aAAa,OAAA;AAEb,2EAA2E;AAC3E,oCAAoC;AACpC,2GAAA,cAAc,OAAA;AACd,6GAAA,gBAAgB,OAAA;AAIpB,+CAA+C;AAC/C,2CAGsB;AAFlB,wGAAA,UAAU,OAAA;AACV,mHAAA,qBAAqB,OAAA;AAGzB,iFAAiF;AACjF,wDAAwE;AAA/D,6HAAA,6BAA6B,OAAA;AACtC,gGAAgG;AAChG,wDAIiC;AAH7B,yHAAA,yBAAyB,OAAA;AACzB,sIAAA,sCAAsC,OAAA;AACtC,oHAAA,oBAAoB,OAAA;AAGxB,yDAAmE;AAA1D,sHAAA,iBAAiB,OAAA;AAE1B,qBAAqB;AACrB,2CAKsB;AAFlB,6GAAA,eAAe,OAAA;AACf,8GAAA,gBAAgB,OAAA;AAGpB,sFAAsF;AACtF,+FAA+F;AAC/F,wDAAsD;AAA7C,2GAAA,WAAW,OAAA;AAEpB,qFAAqF;AACrF,mCAAuD;AAA9C,gGAAA,MAAM,OAAA;AAAE,oGAAA,UAAU,OAAA;AAC3B,6CAA4C;AAAnC,0GAAA,WAAW,OAAA;AACpB,2CAA0C;AAAjC,wGAAA,UAAU,OAAA;AACnB,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AAErB,wFAAwF;AACxF,0FAA0F;AAC1F,uDAAsD;AAA7C,4GAAA,YAAY,OAAA;AAErB,oFAAoF;AACpF,sFAAsF;AAEtF,kBAAkB;AAClB,iDAA4D;AAAnD,8GAAA,aAAa,OAAA;AAOtB,yCAAwD;AAA/C,sGAAA,SAAS,OAAA;AAElB,mFAAmF;AACnF,iEAAiE;AACjE,oFAAoF;AACpF,4FAA4F;AAC5F,2CAAkF;AAAzE,wGAAA,UAAU,OAAA;AAAE,yGAAA,WAAW,OAAA;AAAE,wGAAA,UAAU,OAAA;AAAE,2GAAA,aAAa,OAAA;AAC3D,yCAAqE;AAA5D,oGAAA,OAAO,OAAA;AAAE,qGAAA,QAAQ,OAAA;AAAE,qGAAA,QAAQ,OAAA;AAAE,sGAAA,SAAS,OAAA;AAC/C,6DAA4D;AAAnD,0HAAA,mBAAmB,OAAA;AAC5B,0FAA0F;AAC1F,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AAEvB,kEAAkE;AAElE,0FAA0F;AAC1F,qDAAoG;AAA3F,kHAAA,eAAe,OAAA;AAAE,yHAAA,sBAAsB,OAAA;AAEhD,8FAA8F;AAC9F,kGAAkG;AAClG,+CAAmE;AAA1D,4GAAA,YAAY,OAAA;AAAE,mHAAA,mBAAmB,OAAA;AAE1C,uBAAuB;AACvB,qDAA4E;AAAnE,kHAAA,eAAe,OAAA;AAAE,yHAAA,sBAAsB,OAAA","sourcesContent":["// Re-export API decorators from core-util for convenience\nexport {\n ApiPath,\n Endpoint,\n Public,\n AuthJwt,\n rolesRequired,\n AuthOidc,\n AuthSharedSecret,\n Rpc,\n PubSub,\n Queue,\n getApiPath,\n getEndpoints,\n getEndpointOptions,\n isFormPost,\n isApiPath,\n getAuthMeta,\n getAuthMode,\n assertEveryEndpointHasAuthMode,\n getApiKind,\n assertApiKind,\n assertPubSubConventions,\n getQueueName,\n AuthMeta,\n RouteMetadata,\n METADATA_KEYS,\n ValidateImplementation,\n // @DocumentDesign moved to core-util (design-root marker, browser + Node);\n // re-exported here for back-compat.\n DocumentDesign,\n isDocumentDesign,\n} from '@webpieces/core-util';\nexport type { AuthMode, ApiKind, EndpointOptions } from '@webpieces/core-util';\n\n// Server-side routing decorators and utilities\nexport {\n SourceFile,\n ROUTING_METADATA_KEYS,\n} from './decorators';\n\n// DI provider decorators moved to core-context; re-exported here for back-compat\nexport { provideSingletonDefaultForApi } from '@webpieces/core-context';\n// Framework-only DI registry (packages/** framework classes use these; see frameworkProvide.ts)\nexport {\n provideFrameworkSingleton,\n provideFrameworkSingletonDefaultForApi,\n buildFrameworkModule,\n} from '@webpieces/core-context';\n\nexport { ApiRoutingFactory, ClassType } from './ApiRoutingFactory';\n\n// Core routing types\nexport {\n Routes,\n RouteBuilder,\n RouteDefinition,\n FilterDefinition,\n} from './WebAppMeta';\n\n// The transport-neutral request type (defined in core-context; this is http-routing's\n// public request — a transport adapter builds one and the chain reads it from RequestContext).\nexport { HttpRequest } from '@webpieces/core-context';\n\n// Filter-chain primitives (absorbed from the former @webpieces/http-filters package)\nexport { Filter, WpResponse, Service } from './Filter';\nexport { FilterChain } from './FilterChain';\nexport { MethodMeta } from './MethodMeta';\nexport { RouteHandler } from './RouteHandler';\n\n// LogApiFilter: the fixed OUTERMOST framework filter (auto-installed at 1,000,000 above\n// AuthFilter). Exported for reference/testing only — apps must NOT install it themselves.\nexport { LogApiFilter } from './filters/LogApiFilter';\n\n// RouteBuilderImpl (the route table + chain composer) is now INTERNAL — it is never\n// handed to upper layers. The express layer consumes ApiFactory.apiClients() instead.\n\n// Filter matching\nexport { FilterMatcher, HttpFilter } from './FilterMatcher';\n\n// The app's server-surface declaration: DI binding modules + route groups + headers.\nexport { AppModules, RouteModule } from './AppModules';\n\n// The public API-surface abstraction: declare routes/filters, get them back as ApiClient[].\nexport { ApiFactory } from './ApiFactory';\nexport { ApiClient, ApiClientProxy } from './ApiClient';\n\n// Auth: the app-provided, container-bound pieces the framework AuthFilter injects.\n// - AuthConfig: shared-secret STATE (@AuthSharedSecret values).\n// - JwtHook / OidcHook: OPTIONAL verification mechanisms (bind only what you use).\n// - DefaultOidcVerifier: the built-in Google OIDC verifier used when no OidcHook is bound.\nexport { AuthConfig, AUTH_CONFIG, AuthValues, SharedSecrets } from './AuthConfig';\nexport { JwtHook, JWT_HOOK, OidcHook, OIDC_HOOK } from './AuthHooks';\nexport { DefaultOidcVerifier } from './DefaultOidcVerifier';\n// DefaultJwtHook: batteries-included HS256 JwtHook — `new DefaultJwtHook(secret)` and go.\nexport { DefaultJwtHook } from './DefaultJwtHook';\n\n// Above-boundary context setup shared by every transport adapter.\n\n// Node-only router (the express-free heart: container + filter chain + in-process client)\nexport { WebpiecesRouter, WebpiecesRouterFactory, WebpiecesRouterOptions } from './WebpiecesRouter';\n\n// The ONE transport-free startup sequence (headers → logging → router → routes) → ApiFactory.\n// Reusable by any company/app and any framework adapter; a company wraps it with its own headers.\nexport { setupRuntime, RuntimeSetupOptions } from './setupRuntime';\n\n// Server configuration\nexport { WebpiecesConfig, WEBPIECES_CONFIG_TOKEN } from './WebpiecesConfig';\n"]}