anbaric-web 1.21.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/package.json +24 -0
- package/src/appInternalPath.ts +56 -0
- package/src/database.ts +12 -0
- package/src/index.ts +2 -0
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "anbaric-web",
|
|
3
|
+
"version": "1.21.0",
|
|
4
|
+
"description": "Shared platform web utilities: the app-proxy URL helpers and a safely-pooled Postgres client for plugin data functions",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "chris@anbaric.ai",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "src/index.ts",
|
|
9
|
+
"types": "src/index.ts",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "vitest run"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"pg": "^8.16.0"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/node": "^26.2.0",
|
|
18
|
+
"@types/pg": "^8.15.0",
|
|
19
|
+
"typescript": "^7.0.2"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"src"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/* The app-proxy URL convention, in one place. A Node app deployed under
|
|
2
|
+
/app/<name> is served with that prefix stripped, so an absolute-path URL it
|
|
3
|
+
emits - a sub-page like "/orders", a resource like "/styles.css", or an Await
|
|
4
|
+
resolveUrl like "/approve?job=1" - points at the platform root rather than the
|
|
5
|
+
app. These helpers map such a path back onto its app at /app/<name>/<path>.
|
|
6
|
+
|
|
7
|
+
The core conditional rewrite - appInternalPath - is shared by both uses: the
|
|
8
|
+
server's Referer-based link recovery derives the app name from the Referer,
|
|
9
|
+
while a plugin presenting an Await resolveUrl supplies it directly (the app is
|
|
10
|
+
known from the job's app_id). Keeping the rule here means both agree on what
|
|
11
|
+
"an app-internal absolute path" is and how it maps onto /app/<name>. */
|
|
12
|
+
|
|
13
|
+
const KNOWN_PREFIXES = ["/api", "/app"];
|
|
14
|
+
|
|
15
|
+
const isKnownPrefix = (pathname : string) : boolean =>
|
|
16
|
+
KNOWN_PREFIXES.some(prefix => pathname === prefix || pathname.startsWith(`${prefix}/`));
|
|
17
|
+
|
|
18
|
+
/* Places an absolute path onto the named app at /app/<appName>/<path>, or
|
|
19
|
+
returns undefined (leave the path untouched) when there is no app, the path
|
|
20
|
+
is not absolute (a relative or fully-qualified URL), or it is already under a
|
|
21
|
+
known platform prefix (/api, /app - including an already-correct /app/... ). */
|
|
22
|
+
const appInternalPath = (appName : string | undefined, pathname : string, search : string = "") : string | undefined => {
|
|
23
|
+
if (!appName) return undefined;
|
|
24
|
+
if (!pathname.startsWith("/")) return undefined;
|
|
25
|
+
if (isKnownPrefix(pathname)) return undefined;
|
|
26
|
+
return `/app/${appName}${pathname}${search}`;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/* The same rule for a whole URL string (path plus any query/hash), returning the
|
|
30
|
+
rewritten URL, or the original unchanged when it should be left alone. Use
|
|
31
|
+
this where a URL is presented rather than routed - e.g. an Await resolveUrl. */
|
|
32
|
+
const appInternalUrl = (appName : string | undefined, url : string) : string => {
|
|
33
|
+
const separator = url.search(/[?#]/);
|
|
34
|
+
const pathname = separator === -1 ? url : url.slice(0, separator);
|
|
35
|
+
const search = separator === -1 ? "" : url.slice(separator);
|
|
36
|
+
return appInternalPath(appName, pathname, search) ?? url;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const refererAppName = (referer : string | undefined) : string | undefined => {
|
|
40
|
+
if (!referer) return undefined;
|
|
41
|
+
|
|
42
|
+
let pathname : string;
|
|
43
|
+
try {
|
|
44
|
+
pathname = new URL(referer).pathname;
|
|
45
|
+
} catch {
|
|
46
|
+
pathname = referer;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const match = /^\/app\/([^/?#]+)(?:[/?#]|$)/.exec(pathname);
|
|
50
|
+
return match ? match[1] : undefined;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const appInternalRedirect = (pathname : string, search : string, referer : string | undefined) : string | undefined =>
|
|
54
|
+
appInternalPath(refererAppName(referer), pathname, search);
|
|
55
|
+
|
|
56
|
+
export { appInternalPath, appInternalUrl, appInternalRedirect, refererAppName };
|
package/src/database.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Pool } from "pg";
|
|
2
|
+
|
|
3
|
+
/* A single lazily-created connection pool to the platform database, shared
|
|
4
|
+
across every plugin data call in the process. Data functions run on the
|
|
5
|
+
server; in a plugin's browser bundle pg is stubbed and this is never reached.
|
|
6
|
+
Centralising it here means plugins never hand-roll their own Pool (and never
|
|
7
|
+
leak one per call). */
|
|
8
|
+
let pool : Pool | undefined;
|
|
9
|
+
|
|
10
|
+
const database = () : Pool => (pool ??= new Pool({ connectionString: process.env.ANBARIC_DATABASE_URL }));
|
|
11
|
+
|
|
12
|
+
export { database };
|
package/src/index.ts
ADDED