@aglyn/shared-util-http 1.0.0-beta.143 → 1.0.0-beta.145

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.
Files changed (2) hide show
  1. package/README.md +53 -2
  2. package/package.json +7 -2
package/README.md CHANGED
@@ -1,3 +1,54 @@
1
- # shared-util-http
1
+ # @aglyn/shared-util-http
2
2
 
3
- This library was generated with [Nx](https://nx.dev).
3
+ Small HTTP helpers for Fetch API and Next.js request handlers: CORS, request headers, an ID-token cookie, same-origin redirect checks, URL scheme allowlists, and an authenticated `fetch`. It is mainly a dependency of the larger Aglyn packages (`@aglyn/aglyn`, the plugins, the tenant runtime) and is usable on its own.
4
+
5
+ > Beta. Published from the Aglyn monorepo under the `beta` dist-tag; APIs can change between beta releases.
6
+
7
+ ## Install
8
+
9
+ npm install @aglyn/shared-util-http@beta
10
+
11
+ Peer dependency: `next` (`16.3.3`), optional. You need it when you use the helpers that take Next.js objects (`NextRequest`, `NextResponse`, `NextApiRequest`), such as the cookie helpers. The subpath modules below use only web standards.
12
+
13
+ ## What's in it
14
+
15
+ From the package root:
16
+
17
+ - CORS: `corsHandleResponse(req, res, options?)` and `corsBuildResponseHandler(options?)`, which curries a reusable configuration. Deny-by-default: with no `origin` option the response is returned untouched. `credentials` is never paired with a `*` origin. Preflight `OPTIONS` requests are answered for you unless `preflightContinue` is set. Lower-level pieces: `getOriginHeaders`, `getOriginHeadersFromRequest`, `getAllowedHeaders`, `isOriginAllowed`.
18
+ - `getRequestHeader(request, name)` - reads a header from either a Fetch `Request` or a `NextApiRequest`.
19
+ - `getAbsoluteUrl(path, request?)` - builds an absolute URL from the `host` header (server) or `window.location` (browser).
20
+ - `cookieGetUserIdToken(request)` / `cookieSetUserIdToken(request, response, token, options?)` - read and write the user ID-token cookie, `httpOnly` by default.
21
+ - Types: `CorsOptions`, `StaticOrigin`, `OriginFn`.
22
+
23
+ By subpath only (not re-exported from the root):
24
+
25
+ - `@aglyn/shared-util-http/safe-redirect` - `isSameOriginPath(candidate)` and `safeSameOriginPath(candidate, fallback = '/')`. Instead of pattern-matching the string, they resolve it with the URL parser against a probe origin and accept it only if the origin is unchanged, which catches `//host`, `/\host`, and tab or newline tricks alike.
26
+ - `@aglyn/shared-util-http/safe-url-scheme` - `hasSafeLinkScheme(value)` (`http`, `https`, `mailto`, `tel`, `sms`, or no scheme) and `hasSafeMediaScheme(value)` (`http`, `https`, or no scheme). They check the scheme only; you still have to escape the value into the attribute afterwards.
27
+ - `@aglyn/shared-util-http/authorized-token` - `resolveIdToken(user, options?)`, `authorizedFetch(user, input, init?, options?)`, `describeCallFailure(error, fallback)`, `AuthorizationUnavailableError`, `ID_TOKEN_TIMEOUT_MS`. `user` is anything with a `getIdToken()` method. The token wait has a deadline, and when no token can be had `authorizedFetch` sends nothing and resolves to a `401`-shaped response carrying the reason.
28
+
29
+ ## Usage
30
+
31
+ ```ts
32
+ import { corsBuildResponseHandler } from '@aglyn/shared-util-http'
33
+ import { safeSameOriginPath } from '@aglyn/shared-util-http/safe-redirect'
34
+
35
+ const cors = corsBuildResponseHandler({
36
+ origin: ['https://app.example.com'],
37
+ credentials: true,
38
+ })
39
+
40
+ export async function GET(req: Request) {
41
+ return cors(req, Response.json({ ok: true }))
42
+ }
43
+
44
+ // Anything that would leave the origin becomes '/'.
45
+ const next = safeSameOriginPath(new URL(location.href).searchParams.get('next'))
46
+ ```
47
+
48
+ ## How it fits
49
+
50
+ A `shared` package: generic, with no knowledge of Aglyn's model. Shared packages may only import other shared packages; this one depends on `@aglyn/shared-data-enums` (HTTP status codes and the cookie key). `@aglyn/shared-util-next`, `@aglyn/shared-util-rest-api`, `@aglyn/shared-util-email`, `@aglyn/aglyn`, the tenant runtime packages and most plugins depend on it.
51
+
52
+ ## License
53
+
54
+ Apache-2.0. Source: https://github.com/aglyn/aglyn/tree/main/libs/shared/util/http
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglyn/shared-util-http",
3
- "version": "1.0.0-beta.143",
3
+ "version": "1.0.0-beta.145",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://aglyn.com",
6
6
  "repository": {
@@ -25,12 +25,17 @@
25
25
  "./package.json": "./package.json"
26
26
  },
27
27
  "dependencies": {
28
- "@aglyn/shared-data-enums": "1.0.0-beta.143",
28
+ "@aglyn/shared-data-enums": "1.0.0-beta.145",
29
29
  "@swc/helpers": "0.5.23"
30
30
  },
31
31
  "peerDependencies": {
32
32
  "next": "16.3.3"
33
33
  },
34
+ "peerDependenciesMeta": {
35
+ "next": {
36
+ "optional": true
37
+ }
38
+ },
34
39
  "sideEffects": false,
35
40
  "types": "./src/index.d.ts",
36
41
  "module": "./src/index.js",