jiren 1.0.10 → 1.0.11

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.
@@ -0,0 +1,140 @@
1
+ import { lib, readCString } from "./native";
2
+ export class JirenClient {
3
+ ptr;
4
+ constructor() {
5
+ this.ptr = lib.symbols.zclient_new();
6
+ if (!this.ptr)
7
+ throw new Error("Failed to create native client instance");
8
+ }
9
+ /**
10
+ * Free the native client resources.
11
+ * Must be called when the client is no longer needed.
12
+ */
13
+ close() {
14
+ if (this.ptr) {
15
+ lib.symbols.zclient_free(this.ptr);
16
+ this.ptr = null;
17
+ }
18
+ }
19
+ /**
20
+ * Perform a HTTP request.
21
+ * @param url - The URL to request
22
+ * @param options - Request options (method, headers, body)
23
+ * @returns Response object
24
+ */
25
+ request(url, options = {}) {
26
+ if (!this.ptr)
27
+ throw new Error("Client is closed");
28
+ const method = options.method || "GET";
29
+ const methodBuffer = Buffer.from(method + "\0");
30
+ const urlBuffer = Buffer.from(url + "\0");
31
+ let headersBuffer = null;
32
+ if (options.headers) {
33
+ const headerStr = Object.entries(options.headers)
34
+ .map(([k, v]) => `${k.toLowerCase()}: ${v}`)
35
+ .join("\r\n");
36
+ if (headerStr.length > 0) {
37
+ headersBuffer = Buffer.from(headerStr + "\0");
38
+ }
39
+ }
40
+ let bodyBuffer = null;
41
+ if (options.body) {
42
+ const bodyStr = typeof options.body === "string"
43
+ ? options.body
44
+ : JSON.stringify(options.body);
45
+ bodyBuffer = Buffer.from(bodyStr + "\0");
46
+ }
47
+ const respPtr = lib.symbols.zclient_request(this.ptr, methodBuffer, urlBuffer, headersBuffer, bodyBuffer);
48
+ const response = this.parseResponse(respPtr);
49
+ // Handle Redirects
50
+ if (options.maxRedirects &&
51
+ options.maxRedirects > 0 &&
52
+ response.status >= 300 &&
53
+ response.status < 400 &&
54
+ response.headers &&
55
+ response.headers["location"]) {
56
+ const location = response.headers["location"];
57
+ const newUrl = new URL(location, url).toString(); // Resolve relative URLs
58
+ const newOptions = { ...options, maxRedirects: options.maxRedirects - 1 };
59
+ return this.request(newUrl, newOptions);
60
+ }
61
+ return response;
62
+ }
63
+ get(url, options = {}) {
64
+ return this.request(url, { ...options, method: "GET" });
65
+ }
66
+ post(url, body, options = {}) {
67
+ return this.request(url, { ...options, method: "POST", body });
68
+ }
69
+ put(url, body, options = {}) {
70
+ return this.request(url, { ...options, method: "PUT", body });
71
+ }
72
+ delete(url, options = {}) {
73
+ return this.request(url, { ...options, method: "DELETE" });
74
+ }
75
+ patch(url, body, options = {}) {
76
+ return this.request(url, { ...options, method: "PATCH", body });
77
+ }
78
+ head(url, options = {}) {
79
+ return this.request(url, { ...options, method: "HEAD" });
80
+ }
81
+ /**
82
+ * Prefetch URLs to warm up connections (resolve DNS & Handshake).
83
+ * @param urls - List of URLs to prefetch
84
+ */
85
+ prefetch(urls) {
86
+ if (!this.ptr)
87
+ throw new Error("Client is closed");
88
+ for (const url of urls) {
89
+ const urlBuffer = Buffer.from(url + "\0");
90
+ lib.symbols.zclient_prefetch(this.ptr, urlBuffer);
91
+ }
92
+ }
93
+ parseResponse(respPtr) {
94
+ if (!respPtr)
95
+ throw new Error("Native request failed (returned null pointer)");
96
+ try {
97
+ const status = lib.symbols.zclient_response_status(respPtr);
98
+ const bodyLen = Number(lib.symbols.zclient_response_body_len(respPtr));
99
+ const bodyPtr = lib.symbols.zclient_response_body(respPtr);
100
+ const headersLen = Number(lib.symbols.zclient_response_headers_len(respPtr));
101
+ const headersPtr = lib.symbols.zclient_response_headers(respPtr);
102
+ let bodyString = "";
103
+ if (bodyLen > 0 && bodyPtr) {
104
+ bodyString = readCString(bodyPtr);
105
+ }
106
+ const headers = {};
107
+ if (headersLen > 0 && headersPtr) {
108
+ const headersStr = readCString(headersPtr);
109
+ const lines = headersStr.split("\r\n");
110
+ for (const line of lines) {
111
+ if (!line)
112
+ continue;
113
+ const colonIdx = line.indexOf(":");
114
+ if (colonIdx !== -1) {
115
+ const key = line.substring(0, colonIdx).trim().toLowerCase();
116
+ const val = line.substring(colonIdx + 1).trim();
117
+ headers[key] = val;
118
+ }
119
+ }
120
+ }
121
+ return {
122
+ status,
123
+ body: bodyString,
124
+ headers,
125
+ get ok() {
126
+ return status >= 200 && status < 300;
127
+ },
128
+ text: async () => bodyString,
129
+ json: () => {
130
+ if (!bodyString)
131
+ return null;
132
+ return JSON.parse(bodyString);
133
+ },
134
+ };
135
+ }
136
+ finally {
137
+ lib.symbols.zclient_response_free(respPtr);
138
+ }
139
+ }
140
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * flous - Ultra-fast HTTP/HTTPS client powered by native Zig
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ // Main client
7
+ export { JirenClient } from "./client";
8
+ // Remove broken exports
@@ -0,0 +1,132 @@
1
+ import { isBun } from "./runtime";
2
+ import { join, dirname } from "path";
3
+ import { fileURLToPath } from "url";
4
+ // Helper to get library path
5
+ function getLibPath() {
6
+ const platform = process.platform;
7
+ const ext = platform === "darwin" ? "dylib" : platform === "win32" ? "dll" : "so";
8
+ if (isBun) {
9
+ // @ts-ignore - Bun-specific
10
+ return join(import.meta.dir, `../lib/libhttpclient.${ext}`);
11
+ }
12
+ else {
13
+ // Node.js
14
+ const __filename = fileURLToPath(import.meta.url);
15
+ const __dirname = dirname(__filename);
16
+ return join(__dirname, `../lib/libhttpclient.${ext}`);
17
+ }
18
+ }
19
+ // Load the appropriate FFI library
20
+ async function loadLibrary() {
21
+ const libPath = getLibPath();
22
+ if (isBun) {
23
+ // Use Bun FFI
24
+ const { dlopen, FFIType } = await import("bun:ffi");
25
+ const ffiDef = {
26
+ zclient_new: { args: [], returns: FFIType.ptr },
27
+ zclient_free: { args: [FFIType.ptr], returns: FFIType.void },
28
+ zclient_get: {
29
+ args: [FFIType.ptr, FFIType.cstring],
30
+ returns: FFIType.ptr,
31
+ },
32
+ zclient_post: {
33
+ args: [FFIType.ptr, FFIType.cstring, FFIType.cstring],
34
+ returns: FFIType.ptr,
35
+ },
36
+ zclient_prefetch: {
37
+ args: [FFIType.ptr, FFIType.cstring],
38
+ returns: FFIType.void,
39
+ },
40
+ zclient_response_status: { args: [FFIType.ptr], returns: FFIType.u16 },
41
+ zclient_response_body: { args: [FFIType.ptr], returns: FFIType.ptr },
42
+ zclient_response_body_len: { args: [FFIType.ptr], returns: FFIType.u64 },
43
+ zclient_response_headers: { args: [FFIType.ptr], returns: FFIType.ptr },
44
+ zclient_response_headers_len: {
45
+ args: [FFIType.ptr],
46
+ returns: FFIType.u64,
47
+ },
48
+ zclient_response_free: { args: [FFIType.ptr], returns: FFIType.void },
49
+ zclient_request: {
50
+ args: [
51
+ FFIType.ptr,
52
+ FFIType.cstring,
53
+ FFIType.cstring,
54
+ FFIType.cstring,
55
+ FFIType.cstring,
56
+ ],
57
+ returns: FFIType.ptr,
58
+ },
59
+ };
60
+ return dlopen(libPath, ffiDef);
61
+ }
62
+ else {
63
+ // Use koffi for Node.js
64
+ const koffi = await import("koffi");
65
+ const nativeLib = koffi.load(libPath);
66
+ return {
67
+ symbols: {
68
+ zclient_new: nativeLib.func("zclient_new", "void*", []),
69
+ zclient_free: nativeLib.func("zclient_free", "void", ["void*"]),
70
+ zclient_get: nativeLib.func("zclient_get", "void*", ["void*", "str"]),
71
+ zclient_post: nativeLib.func("zclient_post", "void*", [
72
+ "void*",
73
+ "str",
74
+ "str",
75
+ ]),
76
+ zclient_prefetch: nativeLib.func("zclient_prefetch", "void", [
77
+ "void*",
78
+ "str",
79
+ ]),
80
+ zclient_response_status: nativeLib.func("zclient_response_status", "uint16", ["void*"]),
81
+ zclient_response_body: nativeLib.func("zclient_response_body", "void*", ["void*"]),
82
+ zclient_response_body_len: nativeLib.func("zclient_response_body_len", "uint64", ["void*"]),
83
+ zclient_response_headers: nativeLib.func("zclient_response_headers", "void*", ["void*"]),
84
+ zclient_response_headers_len: nativeLib.func("zclient_response_headers_len", "uint64", ["void*"]),
85
+ zclient_response_free: nativeLib.func("zclient_response_free", "void", [
86
+ "void*",
87
+ ]),
88
+ zclient_request: nativeLib.func("zclient_request", "void*", [
89
+ "void*",
90
+ "str",
91
+ "str",
92
+ "str",
93
+ "str",
94
+ ]),
95
+ },
96
+ };
97
+ }
98
+ }
99
+ // Export the loaded library (initialized on first import)
100
+ export const lib = await loadLibrary();
101
+ // Helper to read C string from pointer (runtime-agnostic)
102
+ export function readCString(ptr) {
103
+ if (!ptr)
104
+ return "";
105
+ if (isBun) {
106
+ // For Bun, we need to dynamically get CString
107
+ // Use a simple approach: read bytes until null terminator
108
+ const view = new DataView(new ArrayBuffer(0));
109
+ try {
110
+ // In Bun, pointers can be read as buffers
111
+ // @ts-ignore - Bun specific
112
+ const buf = Buffer.from(ptr);
113
+ const nullIdx = buf.indexOf(0);
114
+ return buf.toString("utf8", 0, nullIdx >= 0 ? nullIdx : undefined);
115
+ }
116
+ catch {
117
+ // Fallback: try to read as string directly
118
+ return String(ptr);
119
+ }
120
+ }
121
+ else {
122
+ // Node.js with koffi
123
+ try {
124
+ const koffi = require("koffi");
125
+ return koffi.decode(ptr, "string");
126
+ }
127
+ catch (e) {
128
+ console.error("Failed to decode C string:", e);
129
+ return "";
130
+ }
131
+ }
132
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Runtime detection utility for Jiren
3
+ * Detects whether we're running in Bun or Node.js
4
+ */
5
+ export const isBun = typeof Bun !== "undefined";
6
+ export const isNode = !isBun &&
7
+ typeof process !== "undefined" &&
8
+ process.versions &&
9
+ process.versions.node;
10
+ export function getRuntime() {
11
+ if (isBun)
12
+ return "bun";
13
+ if (isNode)
14
+ return "node";
15
+ return "unknown";
16
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * pow - Ultra-fast HTTP/HTTPS client powered by native Zigr than any other HTTP/HTTPS client
3
+ */
4
+ export {};
@@ -21,9 +21,7 @@
21
21
  *
22
22
  * @packageDocumentation
23
23
  */
24
-
25
24
  // Main client
26
25
  export { JirenClient } from "./components";
27
-
28
26
  // Types
29
27
  export * from "./types";
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "jiren",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
4
4
  "author": "",
5
- "main": "index.ts",
6
- "module": "index.ts",
7
- "types": "dist/index.d.ts",
5
+ "main": "index.js",
6
+ "module": "index.js",
7
+ "types": "index.d.ts",
8
8
  "dependencies": {},
9
9
  "optionalDependencies": {
10
10
  "koffi": "^2.9.0"
@@ -18,9 +18,9 @@
18
18
  },
19
19
  "description": "Jiren is a high-performance HTTP/HTTPS client, Faster than any other HTTP/HTTPS client.",
20
20
  "files": [
21
- "index.ts",
21
+ "index.js",
22
+ "index.d.ts",
22
23
  "types",
23
- "dist",
24
24
  "lib",
25
25
  "components"
26
26
  ],
@@ -40,7 +40,8 @@
40
40
  "scripts": {
41
41
  "build": "tsc",
42
42
  "build:zig": "cd .. && zig build --release=fast",
43
- "test": "bun run examples/basic.ts"
43
+ "test": "bun run examples/basic.ts",
44
+ "prepublishOnly": "npm run build"
44
45
  },
45
46
  "engines": {
46
47
  "node": ">=18.0.0",
package/types/index.js ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * jiren - Ultra-fast HTTP/HTTPS Client Types
3
+ * 56% faster than llhttp
4
+ */
5
+ export {};
package/dist/test.d.ts DELETED
@@ -1 +0,0 @@
1
- export {};
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes