@authhero/proxy 0.4.5 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -10
- package/dist/proxy.cjs +1 -1
- package/dist/proxy.d.ts +56 -3
- package/dist/proxy.mjs +72 -25
- package/dist/tsconfig.types.tsbuildinfo +1 -1
- package/dist/types/app.d.ts +2 -1
- package/dist/types/constants.d.ts +7 -0
- package/dist/types/data-plane/cache-adapter-cache.d.ts +39 -0
- package/dist/types/data-plane/cache-api-cache.d.ts +5 -0
- package/dist/types/http-adapter/index.d.ts +1 -0
- package/dist/types/index.d.ts +3 -0
- package/package.json +1 -1
package/dist/proxy.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ProxyRoute, ProxyRoutesAdapter, RouteMatch, HandlerConfig } from '@authhero/adapter-interfaces';
|
|
1
|
+
import { ProxyRoute, ProxyRoutesAdapter, CacheAdapter, RouteMatch, HandlerConfig } from '@authhero/adapter-interfaces';
|
|
2
2
|
export { HandlerConfig, ListProxyRoutesParams, ListProxyRoutesResult, ProxyRoute, ProxyRouteInsert, ProxyRouteUpdate, ProxyRoutesAdapter, RouteMatch, handlerConfigSchema, matchSchema, proxyRouteInsertSchema, proxyRouteSchema, proxyRouteUpdateSchema } from '@authhero/adapter-interfaces';
|
|
3
3
|
import { MiddlewareHandler, Hono, Context } from 'hono';
|
|
4
4
|
import { z } from '@hono/zod-openapi';
|
|
@@ -57,6 +57,7 @@ interface ProxyAppOptions {
|
|
|
57
57
|
data: ProxyDataAdapter;
|
|
58
58
|
cacheTtlMs?: number;
|
|
59
59
|
cache?: HostCacheOptions;
|
|
60
|
+
resolver?: HostResolverCache;
|
|
60
61
|
registry?: HandlerRegistry;
|
|
61
62
|
bindings?: Record<string, unknown>;
|
|
62
63
|
}
|
|
@@ -89,10 +90,53 @@ interface CacheApiHostCacheOptions {
|
|
|
89
90
|
* Invalidation is the caller's responsibility — typically the control plane
|
|
90
91
|
* issues `cache.delete(syntheticKey(...))` on every proxy_route mutation,
|
|
91
92
|
* and each colo's cache expires on its own TTL otherwise.
|
|
93
|
+
*
|
|
94
|
+
* @deprecated Prefer `createCacheAdapterHostCache` with `createCloudflareCache`
|
|
95
|
+
* from `@authhero/cloudflare-adapter`. The adapter-based wrapper supports
|
|
96
|
+
* stale-while-revalidate and works with any `CacheAdapter` (Cloudflare,
|
|
97
|
+
* Redis, in-memory, …).
|
|
92
98
|
*/
|
|
93
99
|
declare function createCacheApiHostCache(options: CacheApiHostCacheOptions): HostResolverCache;
|
|
94
100
|
declare function buildCacheApiKey(namespace: string, host: string): Request;
|
|
95
101
|
|
|
102
|
+
interface CacheAdapterHostCacheOptions {
|
|
103
|
+
upstream: HostResolverCache;
|
|
104
|
+
cache: CacheAdapter;
|
|
105
|
+
freshTtlMs: number;
|
|
106
|
+
staleTtlMs?: number;
|
|
107
|
+
negativeTtlMs?: number;
|
|
108
|
+
keyPrefix?: string;
|
|
109
|
+
waitUntil?: (promise: Promise<unknown>) => void;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Wraps an upstream `HostResolverCache` with a generic `CacheAdapter` layer.
|
|
113
|
+
* Adds stale-while-revalidate semantics on top of any cache implementation
|
|
114
|
+
* — Cloudflare Cache API (via `CloudflareCache` from `@authhero/cloudflare-adapter`),
|
|
115
|
+
* Redis, in-memory, or anything else satisfying the `CacheAdapter` interface.
|
|
116
|
+
*
|
|
117
|
+
* Typical use on Cloudflare Workers:
|
|
118
|
+
*
|
|
119
|
+
* ```ts
|
|
120
|
+
* import { createCloudflareCache } from "@authhero/cloudflare-adapter";
|
|
121
|
+
* import { createCacheAdapterHostCache, createInMemoryHostCache } from "@authhero/proxy";
|
|
122
|
+
*
|
|
123
|
+
* const cache = createCloudflareCache({ cacheName: "authhero-proxy-hosts" });
|
|
124
|
+
* const resolver = createCacheAdapterHostCache({
|
|
125
|
+
* upstream: createInMemoryHostCache(data, { freshTtlMs: 60_000 }),
|
|
126
|
+
* cache,
|
|
127
|
+
* freshTtlMs: 60 * 60_000, // 1 hour fresh
|
|
128
|
+
* staleTtlMs: 23 * 60 * 60_000, // SWR for 23 more hours (24h total)
|
|
129
|
+
* waitUntil: (p) => ctx.waitUntil(p),
|
|
130
|
+
* });
|
|
131
|
+
* ```
|
|
132
|
+
*
|
|
133
|
+
* Invalidation is the caller's responsibility — when a host's routes change,
|
|
134
|
+
* call `cache.delete(buildCacheAdapterKey(keyPrefix, host))` from the control
|
|
135
|
+
* plane. Otherwise entries expire on their own TTL.
|
|
136
|
+
*/
|
|
137
|
+
declare function createCacheAdapterHostCache(options: CacheAdapterHostCacheOptions): HostResolverCache;
|
|
138
|
+
declare function buildCacheAdapterKey(keyPrefix: string, host: string): string;
|
|
139
|
+
|
|
96
140
|
declare const corsHandler: HandlerDefinition<{
|
|
97
141
|
origins?: string[] | undefined;
|
|
98
142
|
allow_credentials?: boolean | undefined;
|
|
@@ -232,6 +276,7 @@ interface HttpProxyAdapterOptions {
|
|
|
232
276
|
clientId: string;
|
|
233
277
|
clientSecret: string;
|
|
234
278
|
audience?: string;
|
|
279
|
+
scope?: string;
|
|
235
280
|
resolveHostPath?: string;
|
|
236
281
|
tokenRefreshSkewSeconds?: number;
|
|
237
282
|
timeoutMs?: number;
|
|
@@ -249,5 +294,13 @@ interface HttpProxyAdapterOptions {
|
|
|
249
294
|
*/
|
|
250
295
|
declare function createHttpProxyAdapter(options: HttpProxyAdapterOptions): ProxyDataAdapter;
|
|
251
296
|
|
|
252
|
-
|
|
253
|
-
|
|
297
|
+
/**
|
|
298
|
+
* Scope a control-plane bearer token must carry to call
|
|
299
|
+
* `GET /api/v2/proxy/control-plane/hosts/:host` or `POST /sync`. The data
|
|
300
|
+
* plane requests it when minting tokens; the control plane requires it when
|
|
301
|
+
* verifying them.
|
|
302
|
+
*/
|
|
303
|
+
declare const PROXY_RESOLVE_HOST_SCOPE = "proxy:resolve_host";
|
|
304
|
+
|
|
305
|
+
export { HandlerRegistry, PROXY_RESOLVE_HOST_SCOPE, basicAuthHandler, buildCacheAdapterKey, buildCacheApiKey, buildMatchFilter, cacheHandler, compileHostApp, corsHandler, createCacheAdapterHostCache, createCacheApiHostCache, createHttpProxyAdapter, createInMemoryHostCache, createProxyApp, createProxyDataPlaneHandler, createProxyDataPlaneRouter, createStaticProxyAdapter, defineHandler, dispatchNamespaceHandler, forwardedHeadersHandler, headersHandler, httpHandler, httpRoute, matchesAnyHost, matchesHost, redirectHandler, registerBuiltinHandlers, rewriteCookiesHandler, rewriteLocationHandler, serviceBindingHandler, sortRoutes, staticHandler };
|
|
306
|
+
export type { CacheAdapterHostCacheOptions, CacheApiHostCacheOptions, HandlerBuildContext, HandlerDefinition, HostCacheOptions, HostResolverCache, HttpProxyAdapterOptions, ProxyAppOptions, ProxyDataAdapter, ProxyDataPlaneOptions, ResolvedHost, StaticHostConfig, StaticProxyAdapterOptions, StaticRouteInput };
|
package/dist/proxy.mjs
CHANGED
|
@@ -3009,6 +3009,7 @@ function Tr(e) {
|
|
|
3009
3009
|
data: e.data,
|
|
3010
3010
|
cacheTtlMs: e.cacheTtlMs,
|
|
3011
3011
|
cache: e.cache,
|
|
3012
|
+
resolver: e.resolver,
|
|
3012
3013
|
registry: e.registry,
|
|
3013
3014
|
bindings: e.bindings
|
|
3014
3015
|
})), n;
|
|
@@ -3041,11 +3042,53 @@ function Or(e, t) {
|
|
|
3041
3042
|
return Q(e, t);
|
|
3042
3043
|
}
|
|
3043
3044
|
//#endregion
|
|
3045
|
+
//#region src/data-plane/cache-adapter-cache.ts
|
|
3046
|
+
function kr(e) {
|
|
3047
|
+
let { upstream: t, cache: n, freshTtlMs: r, staleTtlMs: i = 0, negativeTtlMs: a = r, keyPrefix: o = "authhero-proxy-host", waitUntil: s } = e, c = /* @__PURE__ */ new Map();
|
|
3048
|
+
function l(e) {
|
|
3049
|
+
return `${o}:${e.toLowerCase()}`;
|
|
3050
|
+
}
|
|
3051
|
+
async function u(e) {
|
|
3052
|
+
let o = c.get(e);
|
|
3053
|
+
if (o) return o;
|
|
3054
|
+
let s = (async () => {
|
|
3055
|
+
try {
|
|
3056
|
+
let o = await t.resolveHost(e), s = Date.now(), c = o === null ? a : r, u = o === null ? 0 : i, d = {
|
|
3057
|
+
value: o,
|
|
3058
|
+
freshUntilMs: s + c,
|
|
3059
|
+
staleUntilMs: s + c + u
|
|
3060
|
+
}, f = Math.max(1, Math.ceil((c + u) / 1e3));
|
|
3061
|
+
return await n.set(l(e), d, f), o;
|
|
3062
|
+
} finally {
|
|
3063
|
+
c.delete(e);
|
|
3064
|
+
}
|
|
3065
|
+
})();
|
|
3066
|
+
return c.set(e, s), s;
|
|
3067
|
+
}
|
|
3068
|
+
return { async resolveHost(e) {
|
|
3069
|
+
let t = l(e), r = await n.get(t), i = Date.now();
|
|
3070
|
+
if (r && typeof r.freshUntilMs == "number") {
|
|
3071
|
+
if (r.freshUntilMs > i) return r.value;
|
|
3072
|
+
if (r.staleUntilMs > i) {
|
|
3073
|
+
if (!c.has(e)) {
|
|
3074
|
+
let t = u(e).catch(() => void 0);
|
|
3075
|
+
s && s(t);
|
|
3076
|
+
}
|
|
3077
|
+
return r.value;
|
|
3078
|
+
}
|
|
3079
|
+
}
|
|
3080
|
+
return u(e);
|
|
3081
|
+
} };
|
|
3082
|
+
}
|
|
3083
|
+
function Ar(e, t) {
|
|
3084
|
+
return `${e}:${t.toLowerCase()}`;
|
|
3085
|
+
}
|
|
3086
|
+
//#endregion
|
|
3044
3087
|
//#region src/static/index.ts
|
|
3045
3088
|
function $() {
|
|
3046
3089
|
throw Error("Static proxy adapter is read-only; configure routes at init time");
|
|
3047
3090
|
}
|
|
3048
|
-
function
|
|
3091
|
+
function jr(e, t, n, r, i, a) {
|
|
3049
3092
|
return {
|
|
3050
3093
|
id: e.id ?? `${n}:${t}`,
|
|
3051
3094
|
tenant_id: r,
|
|
@@ -3060,10 +3103,10 @@ function kr(e, t, n, r, i, a) {
|
|
|
3060
3103
|
updated_at: e.updated_at ?? a
|
|
3061
3104
|
};
|
|
3062
3105
|
}
|
|
3063
|
-
function
|
|
3106
|
+
function Mr(e) {
|
|
3064
3107
|
let t = (/* @__PURE__ */ new Date()).toISOString(), n = e.defaultTenantId ?? "static", r = /* @__PURE__ */ new Map();
|
|
3065
3108
|
for (let [i, a] of Object.entries(e.hosts)) {
|
|
3066
|
-
let e = i.toLowerCase(), o = Array.isArray(a) ? { routes: a } : a, s = o.tenant_id ?? n, c = o.custom_domain_id ?? e, l = o.routes.map((n, r) =>
|
|
3109
|
+
let e = i.toLowerCase(), o = Array.isArray(a) ? { routes: a } : a, s = o.tenant_id ?? n, c = o.custom_domain_id ?? e, l = o.routes.map((n, r) => jr(n, r, e, s, c, t)).sort((e, t) => e.priority - t.priority);
|
|
3067
3110
|
r.set(e, {
|
|
3068
3111
|
tenant_id: s,
|
|
3069
3112
|
custom_domain_id: c,
|
|
@@ -3107,7 +3150,7 @@ function Ar(e) {
|
|
|
3107
3150
|
}
|
|
3108
3151
|
};
|
|
3109
3152
|
}
|
|
3110
|
-
function
|
|
3153
|
+
function Nr(e, t = {}) {
|
|
3111
3154
|
return {
|
|
3112
3155
|
priority: t.priority,
|
|
3113
3156
|
match: { path: t.path ?? "/*" },
|
|
@@ -3121,8 +3164,11 @@ function jr(e, t = {}) {
|
|
|
3121
3164
|
};
|
|
3122
3165
|
}
|
|
3123
3166
|
//#endregion
|
|
3167
|
+
//#region src/constants.ts
|
|
3168
|
+
var Pr = "proxy:resolve_host";
|
|
3169
|
+
//#endregion
|
|
3124
3170
|
//#region src/http-adapter/index.ts
|
|
3125
|
-
function
|
|
3171
|
+
function Fr() {
|
|
3126
3172
|
let e = () => {
|
|
3127
3173
|
throw Error("HTTP proxy adapter does not expose write access to proxy_routes; mutate via the control-plane management API");
|
|
3128
3174
|
};
|
|
@@ -3144,41 +3190,42 @@ function Mr() {
|
|
|
3144
3190
|
}
|
|
3145
3191
|
};
|
|
3146
3192
|
}
|
|
3147
|
-
function
|
|
3148
|
-
let t = e.fetch ?? fetch, n = e.baseUrl.replace(/\/+$/, ""), r = e.resolveHostPath ?? "/api/v2/proxy/control-plane/hosts/", i = e.audience ?? `${n}/api/v2/`, a = e.tokenRefreshSkewSeconds ?? 60,
|
|
3149
|
-
function
|
|
3150
|
-
let t = new AbortController(), n = setTimeout(() => t.abort(),
|
|
3193
|
+
function Ir(e) {
|
|
3194
|
+
let t = e.fetch ?? fetch, n = e.baseUrl.replace(/\/+$/, ""), r = e.resolveHostPath ?? "/api/v2/proxy/control-plane/hosts/", i = e.audience ?? `${n}/api/v2/`, a = e.scope ?? "proxy:resolve_host", o = e.tokenRefreshSkewSeconds ?? 60, s = e.timeoutMs ?? 5e3;
|
|
3195
|
+
function c(e) {
|
|
3196
|
+
let t = new AbortController(), n = setTimeout(() => t.abort(), s);
|
|
3151
3197
|
return e(t.signal).finally(() => clearTimeout(n));
|
|
3152
3198
|
}
|
|
3153
|
-
let
|
|
3154
|
-
async function
|
|
3155
|
-
let r = await
|
|
3199
|
+
let l = null, u = null;
|
|
3200
|
+
async function d() {
|
|
3201
|
+
let r = await c((r) => t(`${n}/oauth/token`, {
|
|
3156
3202
|
method: "POST",
|
|
3157
3203
|
headers: { "content-type": "application/json" },
|
|
3158
3204
|
body: JSON.stringify({
|
|
3159
3205
|
grant_type: "client_credentials",
|
|
3160
3206
|
client_id: e.clientId,
|
|
3161
3207
|
client_secret: e.clientSecret,
|
|
3162
|
-
audience: i
|
|
3208
|
+
audience: i,
|
|
3209
|
+
scope: a
|
|
3163
3210
|
}),
|
|
3164
3211
|
signal: r
|
|
3165
3212
|
}));
|
|
3166
3213
|
if (!r.ok) throw Error(`Proxy adapter token request failed: ${r.status} ${await r.text().catch(() => "")}`);
|
|
3167
|
-
let
|
|
3168
|
-
return
|
|
3169
|
-
value:
|
|
3170
|
-
expires_at: Date.now() + (
|
|
3171
|
-
},
|
|
3214
|
+
let s = await r.json(), u = s.expires_in ?? 3600;
|
|
3215
|
+
return l = {
|
|
3216
|
+
value: s.access_token,
|
|
3217
|
+
expires_at: Date.now() + (u - o) * 1e3
|
|
3218
|
+
}, s.access_token;
|
|
3172
3219
|
}
|
|
3173
|
-
async function
|
|
3174
|
-
return
|
|
3175
|
-
|
|
3176
|
-
}),
|
|
3220
|
+
async function f() {
|
|
3221
|
+
return l && l.expires_at > Date.now() ? l.value : u || (u = d().finally(() => {
|
|
3222
|
+
u = null;
|
|
3223
|
+
}), u);
|
|
3177
3224
|
}
|
|
3178
3225
|
return {
|
|
3179
|
-
proxyRoutes:
|
|
3226
|
+
proxyRoutes: Fr(),
|
|
3180
3227
|
async resolveHost(e) {
|
|
3181
|
-
let i = await
|
|
3228
|
+
let i = await f(), a = `${n}${r}${encodeURIComponent(e.toLowerCase())}`, o = await c((e) => t(a, {
|
|
3182
3229
|
headers: { authorization: `Bearer ${i}` },
|
|
3183
3230
|
signal: e
|
|
3184
3231
|
}));
|
|
@@ -3189,4 +3236,4 @@ function Nr(e) {
|
|
|
3189
3236
|
};
|
|
3190
3237
|
}
|
|
3191
3238
|
//#endregion
|
|
3192
|
-
export { z as HandlerRegistry, Wn as basicAuthHandler, Or as buildCacheApiKey, yr as buildMatchFilter, Kn as cacheHandler, xr as compileHostApp, Vn as corsHandler, Dr as createCacheApiHostCache,
|
|
3239
|
+
export { z as HandlerRegistry, Pr as PROXY_RESOLVE_HOST_SCOPE, Wn as basicAuthHandler, Ar as buildCacheAdapterKey, Or as buildCacheApiKey, yr as buildMatchFilter, Kn as cacheHandler, xr as compileHostApp, Vn as corsHandler, kr as createCacheAdapterHostCache, Dr as createCacheApiHostCache, Ir as createHttpProxyAdapter, R as createInMemoryHostCache, Tr as createProxyApp, Z as createProxyDataPlaneHandler, wr as createProxyDataPlaneRouter, Mr as createStaticProxyAdapter, B as defineHandler, fr as dispatchNamespaceHandler, qn as forwardedHeadersHandler, P as handlerConfigSchema, Gn as headersHandler, ar as httpHandler, Nr as httpRoute, N as matchSchema, vr as matchesAnyHost, _r as matchesHost, F as proxyRouteInsertSchema, mn as proxyRouteSchema, hn as proxyRouteUpdateSchema, pr as redirectHandler, hr as registerBuiltinHandlers, Zn as rewriteCookiesHandler, Qn as rewriteLocationHandler, cr as serviceBindingHandler, gr as sortRoutes, mr as staticHandler };
|