@qelos/plugin-netlify-api 1.0.1 → 1.0.2
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 +22 -3
- package/functions/qelos-api-proxy.ts +29 -8
- package/index.js +24 -6
- package/manifest.yml +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,14 +4,29 @@ Netlify build plugin for Qelos frontend apps: proxies `/api/*` to your Qelos API
|
|
|
4
4
|
|
|
5
5
|
## Setup
|
|
6
6
|
|
|
7
|
-
In your site’s `netlify.toml
|
|
7
|
+
In your site’s `netlify.toml`, add the plugin next to your existing `[build]` / `[build.environment]` (same idea as a manual `[functions]` + `[[redirects]]` + `api-proxy.ts`, but without checking in the function or redirect yourself):
|
|
8
8
|
|
|
9
9
|
```toml
|
|
10
|
+
[build]
|
|
11
|
+
command = "npm run build"
|
|
12
|
+
publish = "dist"
|
|
13
|
+
|
|
14
|
+
[build.environment]
|
|
15
|
+
# Used by the injected proxy at runtime (and by your build if you read it in app config)
|
|
16
|
+
QELOS_API_IP = "http://159.203.152.168"
|
|
17
|
+
|
|
10
18
|
[[plugins]]
|
|
11
19
|
package = "@qelos/plugin-netlify-api"
|
|
12
20
|
```
|
|
13
21
|
|
|
14
|
-
|
|
22
|
+
Minimal variant (defaults API URL inside the plugin if you omit env):
|
|
23
|
+
|
|
24
|
+
```toml
|
|
25
|
+
[[plugins]]
|
|
26
|
+
package = "@qelos/plugin-netlify-api"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Optional: set the API URL (default `http://159.203.152.168`) and/or enable bypass-admin header:
|
|
15
30
|
|
|
16
31
|
```toml
|
|
17
32
|
[[plugins]]
|
|
@@ -19,9 +34,11 @@ Optional: set the API URL (default `http://159.203.152.168`):
|
|
|
19
34
|
|
|
20
35
|
[plugins.inputs]
|
|
21
36
|
api_url = "http://159.203.152.168"
|
|
37
|
+
bypass_admin = true
|
|
22
38
|
```
|
|
23
39
|
|
|
24
|
-
|
|
40
|
+
- **api_url** — Target for the `/api/*` proxy. You can also set **`QELOS_API_IP`** or **`API_HOST`** in `[build.environment]` or in the Netlify UI (same role as `API_HOST` in a hand-written `netlify/functions/api-proxy.ts`).
|
|
41
|
+
- **bypass_admin** — If `true`, the proxy adds the header `x-bypass-admin: true` to every request so that admin users are scoped as regular users. See root docs: `documentation/docs/plugins/api-proxy.md` and `documentation/docs/sdk/token_refresh.md`.
|
|
25
42
|
|
|
26
43
|
## What it does
|
|
27
44
|
|
|
@@ -30,3 +47,5 @@ Or set the `QELOS_API_IP` environment variable in the Netlify UI (build or runti
|
|
|
30
47
|
- **Function:** Injects a serverless function `qelos-api-proxy` that forwards requests to the host/port from `QELOS_API_IP` (supports a full URL like `http://159.203.152.168` or a hostname).
|
|
31
48
|
|
|
32
49
|
No need to add redirects or the function file to your repo; the plugin does it at build time.
|
|
50
|
+
|
|
51
|
+
**Parity with a manual Netlify function** (e.g. `[[redirects]]` → `/.netlify/functions/api-proxy` and a function using `process.env.API_HOST`): use this plugin instead of those entries; set `QELOS_API_IP` or `API_HOST` to the same value you used for `API_HOST`, and set `bypass_admin = true` under `[plugins.inputs]` if your old proxy always sent `x-bypass-admin: true`.
|
|
@@ -1,13 +1,31 @@
|
|
|
1
1
|
import http from "http";
|
|
2
|
+
import https from "https";
|
|
2
3
|
import type { Handler } from "@netlify/functions";
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
/** Same-origin proxy target; mirrors manual setups that use API_HOST (e.g. ai-words api-proxy). */
|
|
6
|
+
const raw =
|
|
7
|
+
process.env.QELOS_API_IP ?? process.env.API_HOST ?? "159.203.152.168";
|
|
8
|
+
|
|
9
|
+
let PROXY_HOST: string;
|
|
10
|
+
let PROXY_PORT: number;
|
|
11
|
+
let requestImpl: typeof http.request;
|
|
12
|
+
|
|
13
|
+
if (raw.startsWith("http://") || raw.startsWith("https://")) {
|
|
14
|
+
const u = new URL(raw);
|
|
15
|
+
PROXY_HOST = u.hostname;
|
|
16
|
+
PROXY_PORT = u.port
|
|
17
|
+
? parseInt(u.port, 10)
|
|
18
|
+
: u.protocol === "https:"
|
|
19
|
+
? 443
|
|
20
|
+
: 80;
|
|
21
|
+
requestImpl = u.protocol === "https:" ? https.request : http.request;
|
|
22
|
+
} else {
|
|
23
|
+
PROXY_HOST = raw;
|
|
24
|
+
PROXY_PORT = 80;
|
|
25
|
+
requestImpl = http.request;
|
|
26
|
+
}
|
|
27
|
+
const ADD_BYPASS_ADMIN_HEADER =
|
|
28
|
+
process.env.QELOS_BYPASS_ADMIN_HEADER === "true";
|
|
11
29
|
|
|
12
30
|
export const handler: Handler = (event) =>
|
|
13
31
|
new Promise((resolve) => {
|
|
@@ -17,6 +35,9 @@ export const handler: Handler = (event) =>
|
|
|
17
35
|
if (val) headers[key] = val;
|
|
18
36
|
}
|
|
19
37
|
headers["host"] = event.headers["host"] ?? PROXY_HOST;
|
|
38
|
+
if (ADD_BYPASS_ADMIN_HEADER) {
|
|
39
|
+
headers["x-bypass-admin"] = "true";
|
|
40
|
+
}
|
|
20
41
|
// Lambda buffers the body, so chunked encoding is not applicable
|
|
21
42
|
delete headers["transfer-encoding"];
|
|
22
43
|
|
|
@@ -28,7 +49,7 @@ export const handler: Handler = (event) =>
|
|
|
28
49
|
? Buffer.from(event.body, event.isBase64Encoded ? "base64" : "utf8")
|
|
29
50
|
: undefined;
|
|
30
51
|
|
|
31
|
-
const proxyReq =
|
|
52
|
+
const proxyReq = requestImpl(
|
|
32
53
|
{
|
|
33
54
|
hostname: PROXY_HOST,
|
|
34
55
|
port: PROXY_PORT,
|
package/index.js
CHANGED
|
@@ -1,31 +1,49 @@
|
|
|
1
|
-
const path = require(
|
|
1
|
+
const path = require('node:path');
|
|
2
2
|
|
|
3
|
-
const DEFAULT_API_URL =
|
|
3
|
+
const DEFAULT_API_URL = 'http://159.203.152.168';
|
|
4
4
|
|
|
5
5
|
module.exports = {
|
|
6
6
|
async onPreBuild({ netlifyConfig, utils, inputs }) {
|
|
7
|
-
const apiUrl =
|
|
7
|
+
const apiUrl =
|
|
8
|
+
inputs.api_url ?? process.env.QELOS_API_IP ?? DEFAULT_API_URL;
|
|
9
|
+
const bypassAdmin =
|
|
10
|
+
inputs.bypass_admin === true || inputs.bypass_admin === 'true';
|
|
8
11
|
|
|
9
12
|
// Ensure build.environment exists
|
|
10
13
|
if (!netlifyConfig.build.environment) {
|
|
11
14
|
netlifyConfig.build.environment = {};
|
|
12
15
|
}
|
|
13
16
|
netlifyConfig.build.environment.QELOS_API_IP = apiUrl;
|
|
17
|
+
if (bypassAdmin) {
|
|
18
|
+
netlifyConfig.build.environment.QELOS_BYPASS_ADMIN_HEADER = 'true';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!netlifyConfig.functions) {
|
|
22
|
+
// [functions]
|
|
23
|
+
// directory = "netlify/functions"
|
|
24
|
+
netlifyConfig.functions = { directory: 'netlify/functions' };
|
|
25
|
+
} else {
|
|
26
|
+
// should use this dir as path of the stored function
|
|
27
|
+
}
|
|
14
28
|
|
|
15
29
|
// Add redirect: /api/* -> Netlify function (proxy)
|
|
16
30
|
if (!netlifyConfig.redirects) {
|
|
17
31
|
netlifyConfig.redirects = [];
|
|
18
32
|
}
|
|
19
33
|
netlifyConfig.redirects.push({
|
|
20
|
-
from:
|
|
21
|
-
to:
|
|
34
|
+
from: '/api/*',
|
|
35
|
+
to: '/.netlify/functions/qelos-api-proxy',
|
|
22
36
|
status: 200,
|
|
23
37
|
force: true,
|
|
24
38
|
});
|
|
25
39
|
|
|
26
40
|
// Inject the proxy function (must run in onPreBuild so it's bundled)
|
|
27
41
|
const pluginRoot = __dirname;
|
|
28
|
-
const functionPath = path.join(
|
|
42
|
+
const functionPath = path.join(
|
|
43
|
+
pluginRoot,
|
|
44
|
+
'functions',
|
|
45
|
+
'qelos-api-proxy.ts',
|
|
46
|
+
);
|
|
29
47
|
await utils.functions.add(functionPath);
|
|
30
48
|
},
|
|
31
49
|
};
|
package/manifest.yml
CHANGED
|
@@ -4,3 +4,7 @@ inputs:
|
|
|
4
4
|
required: false
|
|
5
5
|
description: "Qelos API base URL (e.g. http://159.203.152.168). Used as QELOS_API_IP and for /api/* proxy."
|
|
6
6
|
default: "http://159.203.152.168"
|
|
7
|
+
- name: bypass_admin
|
|
8
|
+
required: false
|
|
9
|
+
description: "If true, the proxy adds header x-bypass-admin: true to every request (so admins are scoped as regular users)."
|
|
10
|
+
default: false
|