@aamini/lib 0.0.1

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/dist/env.d.mts ADDED
@@ -0,0 +1,7 @@
1
+ import { ZodTypeAny, z } from "zod";
2
+
3
+ //#region src/env.d.ts
4
+ declare function createEnv<T extends ZodTypeAny>(schema: T): z.infer<T>;
5
+ //#endregion
6
+ export { createEnv };
7
+ //# sourceMappingURL=env.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.mts","names":[],"sources":["../src/env.ts"],"mappings":";;;iBAGgB,SAAA,WAAoB,UAAA,CAAA,CAAY,MAAA,EAAQ,CAAA,GAAI,CAAA,CAAE,KAAA,CAAM,CAAA"}
package/dist/env.mjs ADDED
@@ -0,0 +1,27 @@
1
+ import { config } from "dotenv";
2
+ //#region src/env.ts
3
+ function createEnv(schema) {
4
+ const rawEnvironmentName = process.env.RAILWAY_ENVIRONMENT_NAME ?? process.env.NODE_ENV ?? "development";
5
+ const environmentName = /(?:^|-)pr-\d+$/.test(rawEnvironmentName) ? "staging" : rawEnvironmentName;
6
+ const fileEnvironment = {};
7
+ config({
8
+ path: [
9
+ `.env.${environmentName}`,
10
+ ".env",
11
+ `.env.${environmentName}.local`,
12
+ ".env.local"
13
+ ],
14
+ quiet: true,
15
+ override: true,
16
+ processEnv: fileEnvironment
17
+ });
18
+ for (const [key, value] of Object.entries(fileEnvironment)) process.env[key] ??= value;
19
+ return schema.parse({
20
+ ...process.env,
21
+ ...fileEnvironment
22
+ });
23
+ }
24
+ //#endregion
25
+ export { createEnv };
26
+
27
+ //# sourceMappingURL=env.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.mjs","names":[],"sources":["../src/env.ts"],"sourcesContent":["import { config } from 'dotenv'\nimport type { ZodTypeAny, z } from 'zod'\n\nexport function createEnv<T extends ZodTypeAny>(schema: T): z.infer<T> {\n\tconst rawEnvironmentName =\n\t\tprocess.env.RAILWAY_ENVIRONMENT_NAME ??\n\t\tprocess.env.NODE_ENV ??\n\t\t'development'\n\tconst environmentName = /(?:^|-)pr-\\d+$/.test(rawEnvironmentName)\n\t\t? 'staging'\n\t\t: rawEnvironmentName\n\tconst fileEnvironment: Record<string, string> = {}\n\n\tconfig({\n\t\tpath: [\n\t\t\t`.env.${environmentName}`,\n\t\t\t'.env',\n\t\t\t`.env.${environmentName}.local`,\n\t\t\t'.env.local',\n\t\t],\n\t\tquiet: true,\n\t\toverride: true,\n\t\tprocessEnv: fileEnvironment,\n\t})\n\n\tfor (const [key, value] of Object.entries(fileEnvironment)) {\n\t\tprocess.env[key] ??= value\n\t}\n\n\treturn schema.parse({ ...process.env, ...fileEnvironment })\n}\n"],"mappings":";;AAGA,SAAgB,UAAgC,QAAuB;CACtE,MAAM,qBACL,QAAQ,IAAI,4BACZ,QAAQ,IAAI,YACZ;CACD,MAAM,kBAAkB,iBAAiB,KAAK,mBAAmB,GAC9D,YACA;CACH,MAAM,kBAA0C,EAAE;CAElD,OAAO;EACN,MAAM;GACL,QAAQ;GACR;GACA,QAAQ,gBAAgB;GACxB;GACA;EACD,OAAO;EACP,UAAU;EACV,YAAY;EACZ,CAAC;CAEF,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,gBAAgB,EACzD,QAAQ,IAAI,SAAS;CAGtB,OAAO,OAAO,MAAM;EAAE,GAAG,QAAQ;EAAK,GAAG;EAAiB,CAAC"}
@@ -0,0 +1,10 @@
1
+ //#region src/posthog-proxy.d.ts
2
+ type PostHogProxyOptions = {
3
+ publicPathPrefix: string;
4
+ upstreamOrigin: string;
5
+ upstreamPathPrefix?: string;
6
+ };
7
+ declare function createPostHogProxyRequestHandler(options: PostHogProxyOptions): (request: Request) => Promise<Response>;
8
+ //#endregion
9
+ export { createPostHogProxyRequestHandler };
10
+ //# sourceMappingURL=posthog-proxy.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"posthog-proxy.d.mts","names":[],"sources":["../src/posthog-proxy.ts"],"mappings":";KAAK,mBAAA;EACJ,gBAAA;EACA,cAAA;EACA,kBAAA;AAAA;AAAA,iBAce,gCAAA,CAAiC,OAAA,EAAS,mBAAA,IACf,OAAA,EAAS,OAAA,KAAO,OAAA,CAAA,QAAA"}
@@ -0,0 +1,58 @@
1
+ //#region src/posthog-proxy.ts
2
+ const HOP_BY_HOP_HEADERS = new Set([
3
+ "connection",
4
+ "keep-alive",
5
+ "proxy-authenticate",
6
+ "proxy-authorization",
7
+ "te",
8
+ "trailer",
9
+ "transfer-encoding",
10
+ "upgrade"
11
+ ]);
12
+ function createPostHogProxyRequestHandler(options) {
13
+ return async function proxyPostHogRequest(request) {
14
+ const requestUrl = new URL(request.url);
15
+ const upstreamPath = requestUrl.pathname.startsWith(options.publicPathPrefix) ? requestUrl.pathname.slice(options.publicPathPrefix.length) : "";
16
+ const upstreamUrl = new URL(buildUpstreamPath(options, upstreamPath) + requestUrl.search, trimTrailingSlash(options.upstreamOrigin) + "/");
17
+ const headers = new Headers(request.headers);
18
+ const connectionHeader = headers.get("connection");
19
+ for (const header of HOP_BY_HOP_HEADERS) headers.delete(header);
20
+ if (connectionHeader) for (const token of connectionHeader.split(",")) {
21
+ const header = token.trim().toLowerCase();
22
+ if (header) headers.delete(header);
23
+ }
24
+ headers.delete("host");
25
+ const requestInit = {
26
+ method: request.method,
27
+ headers,
28
+ redirect: "follow"
29
+ };
30
+ if (request.method !== "GET" && request.method !== "HEAD") requestInit.body = await request.arrayBuffer();
31
+ const upstreamResponse = await fetch(upstreamUrl, requestInit);
32
+ return new Response(upstreamResponse.body, {
33
+ status: upstreamResponse.status,
34
+ statusText: upstreamResponse.statusText,
35
+ headers: upstreamResponse.headers
36
+ });
37
+ };
38
+ }
39
+ function buildUpstreamPath(options, upstreamPath) {
40
+ const prefix = trimSlashes(options.upstreamPathPrefix ?? "");
41
+ const path = trimLeadingSlash(upstreamPath);
42
+ if (!prefix) return path;
43
+ if (!path) return prefix;
44
+ return `${prefix}/${path}`;
45
+ }
46
+ function trimLeadingSlash(value) {
47
+ return value.replace(/^\/+/, "");
48
+ }
49
+ function trimSlashes(value) {
50
+ return value.replace(/^\/+|\/+$/g, "");
51
+ }
52
+ function trimTrailingSlash(value) {
53
+ return value.replace(/\/+$/, "");
54
+ }
55
+ //#endregion
56
+ export { createPostHogProxyRequestHandler };
57
+
58
+ //# sourceMappingURL=posthog-proxy.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"posthog-proxy.mjs","names":[],"sources":["../src/posthog-proxy.ts"],"sourcesContent":["type PostHogProxyOptions = {\n\tpublicPathPrefix: string\n\tupstreamOrigin: string\n\tupstreamPathPrefix?: string\n}\n\nconst HOP_BY_HOP_HEADERS = new Set([\n\t'connection',\n\t'keep-alive',\n\t'proxy-authenticate',\n\t'proxy-authorization',\n\t'te',\n\t'trailer',\n\t'transfer-encoding',\n\t'upgrade',\n])\n\nexport function createPostHogProxyRequestHandler(options: PostHogProxyOptions) {\n\treturn async function proxyPostHogRequest(request: Request) {\n\t\tconst requestUrl = new URL(request.url)\n\t\tconst upstreamPath = requestUrl.pathname.startsWith(\n\t\t\toptions.publicPathPrefix,\n\t\t)\n\t\t\t? requestUrl.pathname.slice(options.publicPathPrefix.length)\n\t\t\t: ''\n\t\tconst upstreamUrl = new URL(\n\t\t\tbuildUpstreamPath(options, upstreamPath) + requestUrl.search,\n\t\t\ttrimTrailingSlash(options.upstreamOrigin) + '/',\n\t\t)\n\t\tconst headers = new Headers(request.headers)\n\t\tconst connectionHeader = headers.get('connection')\n\n\t\t// Strip hop-by-hop headers before proxying: RFC 9110 §7.6.\n\t\t// https://www.rfc-editor.org/rfc/rfc9110.html#name-connection-specific-header\n\t\tfor (const header of HOP_BY_HOP_HEADERS) {\n\t\t\theaders.delete(header)\n\t\t}\n\n\t\tif (connectionHeader) {\n\t\t\tfor (const token of connectionHeader.split(',')) {\n\t\t\t\tconst header = token.trim().toLowerCase()\n\t\t\t\tif (header) {\n\t\t\t\t\theaders.delete(header)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\theaders.delete('host')\n\n\t\tconst requestInit: RequestInit = {\n\t\t\tmethod: request.method,\n\t\t\theaders,\n\t\t\tredirect: 'follow',\n\t\t}\n\n\t\tif (request.method !== 'GET' && request.method !== 'HEAD') {\n\t\t\trequestInit.body = await request.arrayBuffer()\n\t\t}\n\n\t\tconst upstreamResponse = await fetch(upstreamUrl, requestInit)\n\n\t\treturn new Response(upstreamResponse.body, {\n\t\t\tstatus: upstreamResponse.status,\n\t\t\tstatusText: upstreamResponse.statusText,\n\t\t\theaders: upstreamResponse.headers,\n\t\t})\n\t}\n}\n\nfunction buildUpstreamPath(options: PostHogProxyOptions, upstreamPath: string) {\n\tconst prefix = trimSlashes(options.upstreamPathPrefix ?? '')\n\tconst path = trimLeadingSlash(upstreamPath)\n\n\tif (!prefix) {\n\t\treturn path\n\t}\n\n\tif (!path) {\n\t\treturn prefix\n\t}\n\n\treturn `${prefix}/${path}`\n}\n\nfunction trimLeadingSlash(value: string) {\n\treturn value.replace(/^\\/+/, '')\n}\n\nfunction trimSlashes(value: string) {\n\treturn value.replace(/^\\/+|\\/+$/g, '')\n}\n\nfunction trimTrailingSlash(value: string) {\n\treturn value.replace(/\\/+$/, '')\n}\n"],"mappings":";AAMA,MAAM,qBAAqB,IAAI,IAAI;CAClC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,CAAC;AAEF,SAAgB,iCAAiC,SAA8B;CAC9E,OAAO,eAAe,oBAAoB,SAAkB;EAC3D,MAAM,aAAa,IAAI,IAAI,QAAQ,IAAI;EACvC,MAAM,eAAe,WAAW,SAAS,WACxC,QAAQ,iBACR,GACE,WAAW,SAAS,MAAM,QAAQ,iBAAiB,OAAO,GAC1D;EACH,MAAM,cAAc,IAAI,IACvB,kBAAkB,SAAS,aAAa,GAAG,WAAW,QACtD,kBAAkB,QAAQ,eAAe,GAAG,IAC5C;EACD,MAAM,UAAU,IAAI,QAAQ,QAAQ,QAAQ;EAC5C,MAAM,mBAAmB,QAAQ,IAAI,aAAa;EAIlD,KAAK,MAAM,UAAU,oBACpB,QAAQ,OAAO,OAAO;EAGvB,IAAI,kBACH,KAAK,MAAM,SAAS,iBAAiB,MAAM,IAAI,EAAE;GAChD,MAAM,SAAS,MAAM,MAAM,CAAC,aAAa;GACzC,IAAI,QACH,QAAQ,OAAO,OAAO;;EAKzB,QAAQ,OAAO,OAAO;EAEtB,MAAM,cAA2B;GAChC,QAAQ,QAAQ;GAChB;GACA,UAAU;GACV;EAED,IAAI,QAAQ,WAAW,SAAS,QAAQ,WAAW,QAClD,YAAY,OAAO,MAAM,QAAQ,aAAa;EAG/C,MAAM,mBAAmB,MAAM,MAAM,aAAa,YAAY;EAE9D,OAAO,IAAI,SAAS,iBAAiB,MAAM;GAC1C,QAAQ,iBAAiB;GACzB,YAAY,iBAAiB;GAC7B,SAAS,iBAAiB;GAC1B,CAAC;;;AAIJ,SAAS,kBAAkB,SAA8B,cAAsB;CAC9E,MAAM,SAAS,YAAY,QAAQ,sBAAsB,GAAG;CAC5D,MAAM,OAAO,iBAAiB,aAAa;CAE3C,IAAI,CAAC,QACJ,OAAO;CAGR,IAAI,CAAC,MACJ,OAAO;CAGR,OAAO,GAAG,OAAO,GAAG;;AAGrB,SAAS,iBAAiB,OAAe;CACxC,OAAO,MAAM,QAAQ,QAAQ,GAAG;;AAGjC,SAAS,YAAY,OAAe;CACnC,OAAO,MAAM,QAAQ,cAAc,GAAG;;AAGvC,SAAS,kBAAkB,OAAe;CACzC,OAAO,MAAM,QAAQ,QAAQ,GAAG"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@aamini/lib",
3
+ "version": "0.0.1",
4
+ "private": false,
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/aamini-stack/projects.git",
9
+ "directory": "packages/lib"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/aamini-stack/projects/issues"
13
+ },
14
+ "homepage": "https://github.com/aamini-stack/projects/tree/main/packages/lib#readme",
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "src"
21
+ ],
22
+ "exports": {
23
+ "./env": {
24
+ "types": "./dist/env.d.mts",
25
+ "import": "./dist/env.mjs",
26
+ "default": "./dist/env.mjs"
27
+ },
28
+ "./posthog-proxy": {
29
+ "types": "./dist/posthog-proxy.d.mts",
30
+ "import": "./dist/posthog-proxy.mjs",
31
+ "default": "./dist/posthog-proxy.mjs"
32
+ }
33
+ },
34
+ "scripts": {
35
+ "pack": "vp pack",
36
+ "prepublishOnly": "vp pack",
37
+ "check": "vp check"
38
+ },
39
+ "dependencies": {
40
+ "dotenv": "^17.4.2",
41
+ "zod": "^4.3.6"
42
+ },
43
+ "devDependencies": {
44
+ "@aamini/config": "workspace:*",
45
+ "typescript": "6.0.2"
46
+ }
47
+ }
package/src/env.ts ADDED
@@ -0,0 +1,31 @@
1
+ import { config } from 'dotenv'
2
+ import type { ZodTypeAny, z } from 'zod'
3
+
4
+ export function createEnv<T extends ZodTypeAny>(schema: T): z.infer<T> {
5
+ const rawEnvironmentName =
6
+ process.env.RAILWAY_ENVIRONMENT_NAME ??
7
+ process.env.NODE_ENV ??
8
+ 'development'
9
+ const environmentName = /(?:^|-)pr-\d+$/.test(rawEnvironmentName)
10
+ ? 'staging'
11
+ : rawEnvironmentName
12
+ const fileEnvironment: Record<string, string> = {}
13
+
14
+ config({
15
+ path: [
16
+ `.env.${environmentName}`,
17
+ '.env',
18
+ `.env.${environmentName}.local`,
19
+ '.env.local',
20
+ ],
21
+ quiet: true,
22
+ override: true,
23
+ processEnv: fileEnvironment,
24
+ })
25
+
26
+ for (const [key, value] of Object.entries(fileEnvironment)) {
27
+ process.env[key] ??= value
28
+ }
29
+
30
+ return schema.parse({ ...process.env, ...fileEnvironment })
31
+ }
@@ -0,0 +1,95 @@
1
+ type PostHogProxyOptions = {
2
+ publicPathPrefix: string
3
+ upstreamOrigin: string
4
+ upstreamPathPrefix?: string
5
+ }
6
+
7
+ const HOP_BY_HOP_HEADERS = new Set([
8
+ 'connection',
9
+ 'keep-alive',
10
+ 'proxy-authenticate',
11
+ 'proxy-authorization',
12
+ 'te',
13
+ 'trailer',
14
+ 'transfer-encoding',
15
+ 'upgrade',
16
+ ])
17
+
18
+ export function createPostHogProxyRequestHandler(options: PostHogProxyOptions) {
19
+ return async function proxyPostHogRequest(request: Request) {
20
+ const requestUrl = new URL(request.url)
21
+ const upstreamPath = requestUrl.pathname.startsWith(
22
+ options.publicPathPrefix,
23
+ )
24
+ ? requestUrl.pathname.slice(options.publicPathPrefix.length)
25
+ : ''
26
+ const upstreamUrl = new URL(
27
+ buildUpstreamPath(options, upstreamPath) + requestUrl.search,
28
+ trimTrailingSlash(options.upstreamOrigin) + '/',
29
+ )
30
+ const headers = new Headers(request.headers)
31
+ const connectionHeader = headers.get('connection')
32
+
33
+ // Strip hop-by-hop headers before proxying: RFC 9110 §7.6.
34
+ // https://www.rfc-editor.org/rfc/rfc9110.html#name-connection-specific-header
35
+ for (const header of HOP_BY_HOP_HEADERS) {
36
+ headers.delete(header)
37
+ }
38
+
39
+ if (connectionHeader) {
40
+ for (const token of connectionHeader.split(',')) {
41
+ const header = token.trim().toLowerCase()
42
+ if (header) {
43
+ headers.delete(header)
44
+ }
45
+ }
46
+ }
47
+
48
+ headers.delete('host')
49
+
50
+ const requestInit: RequestInit = {
51
+ method: request.method,
52
+ headers,
53
+ redirect: 'follow',
54
+ }
55
+
56
+ if (request.method !== 'GET' && request.method !== 'HEAD') {
57
+ requestInit.body = await request.arrayBuffer()
58
+ }
59
+
60
+ const upstreamResponse = await fetch(upstreamUrl, requestInit)
61
+
62
+ return new Response(upstreamResponse.body, {
63
+ status: upstreamResponse.status,
64
+ statusText: upstreamResponse.statusText,
65
+ headers: upstreamResponse.headers,
66
+ })
67
+ }
68
+ }
69
+
70
+ function buildUpstreamPath(options: PostHogProxyOptions, upstreamPath: string) {
71
+ const prefix = trimSlashes(options.upstreamPathPrefix ?? '')
72
+ const path = trimLeadingSlash(upstreamPath)
73
+
74
+ if (!prefix) {
75
+ return path
76
+ }
77
+
78
+ if (!path) {
79
+ return prefix
80
+ }
81
+
82
+ return `${prefix}/${path}`
83
+ }
84
+
85
+ function trimLeadingSlash(value: string) {
86
+ return value.replace(/^\/+/, '')
87
+ }
88
+
89
+ function trimSlashes(value: string) {
90
+ return value.replace(/^\/+|\/+$/g, '')
91
+ }
92
+
93
+ function trimTrailingSlash(value: string) {
94
+ return value.replace(/\/+$/, '')
95
+ }