jiren 1.0.6 → 1.0.9
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/components/client.ts +9 -11
- package/components/native.ts +179 -61
- package/components/runtime.ts +17 -0
- package/dist/components/native.d.ts +16 -99
- package/dist/components/runtime.d.ts +7 -0
- package/package.json +6 -4
package/components/client.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { lib } from "./native";
|
|
1
|
+
import { lib, readCString } from "./native";
|
|
3
2
|
import type {
|
|
4
3
|
RequestOptions,
|
|
5
4
|
GetRequestOptions,
|
|
@@ -7,8 +6,10 @@ import type {
|
|
|
7
6
|
HttpResponse,
|
|
8
7
|
} from "../types";
|
|
9
8
|
|
|
9
|
+
// Runtime-agnostic pointer type
|
|
10
|
+
type Pointer = any;
|
|
10
11
|
export class JirenClient {
|
|
11
|
-
private ptr:
|
|
12
|
+
private ptr: unknown | null;
|
|
12
13
|
|
|
13
14
|
constructor() {
|
|
14
15
|
this.ptr = lib.symbols.zclient_new();
|
|
@@ -21,7 +22,7 @@ export class JirenClient {
|
|
|
21
22
|
*/
|
|
22
23
|
public close(): void {
|
|
23
24
|
if (this.ptr) {
|
|
24
|
-
lib.symbols.zclient_free(this.ptr);
|
|
25
|
+
lib.symbols.zclient_free(this.ptr as Pointer);
|
|
25
26
|
this.ptr = null;
|
|
26
27
|
}
|
|
27
28
|
}
|
|
@@ -59,7 +60,7 @@ export class JirenClient {
|
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
const respPtr = lib.symbols.zclient_request(
|
|
62
|
-
this.ptr,
|
|
63
|
+
this.ptr as Pointer,
|
|
63
64
|
methodBuffer,
|
|
64
65
|
urlBuffer,
|
|
65
66
|
headersBuffer,
|
|
@@ -132,7 +133,7 @@ export class JirenClient {
|
|
|
132
133
|
|
|
133
134
|
for (const url of urls) {
|
|
134
135
|
const urlBuffer = Buffer.from(url + "\0");
|
|
135
|
-
lib.symbols.zclient_prefetch(this.ptr, urlBuffer);
|
|
136
|
+
lib.symbols.zclient_prefetch(this.ptr as Pointer, urlBuffer);
|
|
136
137
|
}
|
|
137
138
|
}
|
|
138
139
|
|
|
@@ -151,15 +152,12 @@ export class JirenClient {
|
|
|
151
152
|
|
|
152
153
|
let bodyString = "";
|
|
153
154
|
if (bodyLen > 0 && bodyPtr) {
|
|
154
|
-
|
|
155
|
-
// Since we know the length, we can be more precise, but CString assumes null-terminated
|
|
156
|
-
// for now we trust it is null terminated from Zig
|
|
157
|
-
bodyString = new CString(bodyPtr).toString();
|
|
155
|
+
bodyString = readCString(bodyPtr);
|
|
158
156
|
}
|
|
159
157
|
|
|
160
158
|
const headers: Record<string, string> = {};
|
|
161
159
|
if (headersLen > 0 && headersPtr) {
|
|
162
|
-
const headersStr =
|
|
160
|
+
const headersStr = readCString(headersPtr);
|
|
163
161
|
const lines = headersStr.split("\r\n");
|
|
164
162
|
for (const line of lines) {
|
|
165
163
|
if (!line) continue;
|
package/components/native.ts
CHANGED
|
@@ -1,64 +1,182 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { join } from "path";
|
|
1
|
+
import { isBun } from "./runtime";
|
|
2
|
+
import { join, dirname } from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
3
4
|
|
|
4
|
-
//
|
|
5
|
-
|
|
5
|
+
// Helper to get library path
|
|
6
|
+
function getLibPath(): string {
|
|
7
|
+
if (isBun) {
|
|
8
|
+
// @ts-ignore - Bun-specific
|
|
9
|
+
const { suffix } = await import("bun:ffi");
|
|
10
|
+
return join(import.meta.dir, `../lib/libhttpclient.${suffix}`);
|
|
11
|
+
} else {
|
|
12
|
+
// Node.js
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
const __dirname = dirname(__filename);
|
|
15
|
+
const platform = process.platform;
|
|
16
|
+
const ext =
|
|
17
|
+
platform === "darwin" ? "dylib" : platform === "win32" ? "dll" : "so";
|
|
18
|
+
return join(__dirname, `../lib/libhttpclient.${ext}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
6
21
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
returns: FFIType.u16,
|
|
31
|
-
},
|
|
32
|
-
zclient_response_body: {
|
|
33
|
-
args: [FFIType.ptr],
|
|
34
|
-
returns: FFIType.ptr,
|
|
35
|
-
},
|
|
36
|
-
zclient_response_body_len: {
|
|
37
|
-
args: [FFIType.ptr],
|
|
38
|
-
returns: FFIType.u64,
|
|
39
|
-
},
|
|
40
|
-
zclient_response_headers: {
|
|
41
|
-
args: [FFIType.ptr],
|
|
42
|
-
returns: FFIType.ptr,
|
|
43
|
-
},
|
|
44
|
-
zclient_response_headers_len: {
|
|
45
|
-
args: [FFIType.ptr],
|
|
46
|
-
returns: FFIType.u64,
|
|
47
|
-
},
|
|
48
|
-
zclient_response_free: {
|
|
49
|
-
args: [FFIType.ptr],
|
|
50
|
-
returns: FFIType.void,
|
|
51
|
-
},
|
|
52
|
-
zclient_request: {
|
|
53
|
-
args: [
|
|
54
|
-
FFIType.ptr, // client
|
|
55
|
-
FFIType.cstring, // method
|
|
56
|
-
FFIType.cstring, // url
|
|
57
|
-
FFIType.cstring, // headers (nullable)
|
|
58
|
-
FFIType.cstring, // body (nullable)
|
|
59
|
-
],
|
|
60
|
-
returns: FFIType.ptr,
|
|
61
|
-
},
|
|
62
|
-
} as const;
|
|
22
|
+
// Type definitions for our FFI symbols
|
|
23
|
+
export type NativeLib = {
|
|
24
|
+
symbols: {
|
|
25
|
+
zclient_new: () => any;
|
|
26
|
+
zclient_free: (ptr: any) => void;
|
|
27
|
+
zclient_get: (client: any, url: any) => any;
|
|
28
|
+
zclient_post: (client: any, url: any, body: any) => any;
|
|
29
|
+
zclient_prefetch: (client: any, url: any) => void;
|
|
30
|
+
zclient_response_status: (resp: any) => number;
|
|
31
|
+
zclient_response_body: (resp: any) => any;
|
|
32
|
+
zclient_response_body_len: (resp: any) => bigint | number;
|
|
33
|
+
zclient_response_headers: (resp: any) => any;
|
|
34
|
+
zclient_response_headers_len: (resp: any) => bigint | number;
|
|
35
|
+
zclient_response_free: (resp: any) => void;
|
|
36
|
+
zclient_request: (
|
|
37
|
+
client: any,
|
|
38
|
+
method: any,
|
|
39
|
+
url: any,
|
|
40
|
+
headers: any,
|
|
41
|
+
body: any
|
|
42
|
+
) => any;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
63
45
|
|
|
64
|
-
|
|
46
|
+
// Load the appropriate FFI library
|
|
47
|
+
async function loadLibrary(): Promise<NativeLib> {
|
|
48
|
+
const libPath = getLibPath();
|
|
49
|
+
|
|
50
|
+
if (isBun) {
|
|
51
|
+
// Use Bun FFI
|
|
52
|
+
const { dlopen, FFIType } = await import("bun:ffi");
|
|
53
|
+
|
|
54
|
+
const ffiDef = {
|
|
55
|
+
zclient_new: { args: [], returns: FFIType.ptr },
|
|
56
|
+
zclient_free: { args: [FFIType.ptr], returns: FFIType.void },
|
|
57
|
+
zclient_get: {
|
|
58
|
+
args: [FFIType.ptr, FFIType.cstring],
|
|
59
|
+
returns: FFIType.ptr,
|
|
60
|
+
},
|
|
61
|
+
zclient_post: {
|
|
62
|
+
args: [FFIType.ptr, FFIType.cstring, FFIType.cstring],
|
|
63
|
+
returns: FFIType.ptr,
|
|
64
|
+
},
|
|
65
|
+
zclient_prefetch: {
|
|
66
|
+
args: [FFIType.ptr, FFIType.cstring],
|
|
67
|
+
returns: FFIType.void,
|
|
68
|
+
},
|
|
69
|
+
zclient_response_status: { args: [FFIType.ptr], returns: FFIType.u16 },
|
|
70
|
+
zclient_response_body: { args: [FFIType.ptr], returns: FFIType.ptr },
|
|
71
|
+
zclient_response_body_len: { args: [FFIType.ptr], returns: FFIType.u64 },
|
|
72
|
+
zclient_response_headers: { args: [FFIType.ptr], returns: FFIType.ptr },
|
|
73
|
+
zclient_response_headers_len: {
|
|
74
|
+
args: [FFIType.ptr],
|
|
75
|
+
returns: FFIType.u64,
|
|
76
|
+
},
|
|
77
|
+
zclient_response_free: { args: [FFIType.ptr], returns: FFIType.void },
|
|
78
|
+
zclient_request: {
|
|
79
|
+
args: [
|
|
80
|
+
FFIType.ptr,
|
|
81
|
+
FFIType.cstring,
|
|
82
|
+
FFIType.cstring,
|
|
83
|
+
FFIType.cstring,
|
|
84
|
+
FFIType.cstring,
|
|
85
|
+
],
|
|
86
|
+
returns: FFIType.ptr,
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
return dlopen(libPath, ffiDef) as NativeLib;
|
|
91
|
+
} else {
|
|
92
|
+
// Use koffi for Node.js
|
|
93
|
+
const koffi = await import("koffi");
|
|
94
|
+
|
|
95
|
+
const nativeLib = koffi.load(libPath);
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
symbols: {
|
|
99
|
+
zclient_new: nativeLib.func("zclient_new", "void*", []),
|
|
100
|
+
zclient_free: nativeLib.func("zclient_free", "void", ["void*"]),
|
|
101
|
+
zclient_get: nativeLib.func("zclient_get", "void*", ["void*", "str"]),
|
|
102
|
+
zclient_post: nativeLib.func("zclient_post", "void*", [
|
|
103
|
+
"void*",
|
|
104
|
+
"str",
|
|
105
|
+
"str",
|
|
106
|
+
]),
|
|
107
|
+
zclient_prefetch: nativeLib.func("zclient_prefetch", "void", [
|
|
108
|
+
"void*",
|
|
109
|
+
"str",
|
|
110
|
+
]),
|
|
111
|
+
zclient_response_status: nativeLib.func(
|
|
112
|
+
"zclient_response_status",
|
|
113
|
+
"uint16",
|
|
114
|
+
["void*"]
|
|
115
|
+
),
|
|
116
|
+
zclient_response_body: nativeLib.func(
|
|
117
|
+
"zclient_response_body",
|
|
118
|
+
"void*",
|
|
119
|
+
["void*"]
|
|
120
|
+
),
|
|
121
|
+
zclient_response_body_len: nativeLib.func(
|
|
122
|
+
"zclient_response_body_len",
|
|
123
|
+
"uint64",
|
|
124
|
+
["void*"]
|
|
125
|
+
),
|
|
126
|
+
zclient_response_headers: nativeLib.func(
|
|
127
|
+
"zclient_response_headers",
|
|
128
|
+
"void*",
|
|
129
|
+
["void*"]
|
|
130
|
+
),
|
|
131
|
+
zclient_response_headers_len: nativeLib.func(
|
|
132
|
+
"zclient_response_headers_len",
|
|
133
|
+
"uint64",
|
|
134
|
+
["void*"]
|
|
135
|
+
),
|
|
136
|
+
zclient_response_free: nativeLib.func("zclient_response_free", "void", [
|
|
137
|
+
"void*",
|
|
138
|
+
]),
|
|
139
|
+
zclient_request: nativeLib.func("zclient_request", "void*", [
|
|
140
|
+
"void*",
|
|
141
|
+
"str",
|
|
142
|
+
"str",
|
|
143
|
+
"str",
|
|
144
|
+
"str",
|
|
145
|
+
]),
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Export the loaded library (initialized on first import)
|
|
152
|
+
export const lib: NativeLib = await loadLibrary();
|
|
153
|
+
|
|
154
|
+
// Helper to read C string from pointer (runtime-agnostic)
|
|
155
|
+
export function readCString(ptr: any): string {
|
|
156
|
+
if (!ptr) return "";
|
|
157
|
+
|
|
158
|
+
if (isBun) {
|
|
159
|
+
// For Bun, we need to dynamically get CString
|
|
160
|
+
// Use a simple approach: read bytes until null terminator
|
|
161
|
+
const view = new DataView(new ArrayBuffer(0));
|
|
162
|
+
try {
|
|
163
|
+
// In Bun, pointers can be read as buffers
|
|
164
|
+
// @ts-ignore - Bun specific
|
|
165
|
+
const buf = Buffer.from(ptr as any);
|
|
166
|
+
const nullIdx = buf.indexOf(0);
|
|
167
|
+
return buf.toString("utf8", 0, nullIdx >= 0 ? nullIdx : undefined);
|
|
168
|
+
} catch {
|
|
169
|
+
// Fallback: try to read as string directly
|
|
170
|
+
return String(ptr);
|
|
171
|
+
}
|
|
172
|
+
} else {
|
|
173
|
+
// Node.js with koffi
|
|
174
|
+
try {
|
|
175
|
+
const koffi = require("koffi");
|
|
176
|
+
return koffi.decode(ptr, "string");
|
|
177
|
+
} catch (e) {
|
|
178
|
+
console.error("Failed to decode C string:", e);
|
|
179
|
+
return "";
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime detection utility for Jiren
|
|
3
|
+
* Detects whether we're running in Bun or Node.js
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const isBun = typeof Bun !== "undefined";
|
|
7
|
+
export const isNode =
|
|
8
|
+
!isBun &&
|
|
9
|
+
typeof process !== "undefined" &&
|
|
10
|
+
process.versions &&
|
|
11
|
+
process.versions.node;
|
|
12
|
+
|
|
13
|
+
export function getRuntime(): "bun" | "node" | "unknown" {
|
|
14
|
+
if (isBun) return "bun";
|
|
15
|
+
if (isNode) return "node";
|
|
16
|
+
return "unknown";
|
|
17
|
+
}
|
|
@@ -1,101 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
readonly zclient_post: {
|
|
16
|
-
readonly args: readonly [FFIType.ptr, FFIType.cstring, FFIType.cstring];
|
|
17
|
-
readonly returns: FFIType.ptr;
|
|
18
|
-
};
|
|
19
|
-
readonly zclient_prefetch: {
|
|
20
|
-
readonly args: readonly [FFIType.ptr, FFIType.cstring];
|
|
21
|
-
readonly returns: FFIType.void;
|
|
22
|
-
};
|
|
23
|
-
readonly zclient_response_status: {
|
|
24
|
-
readonly args: readonly [FFIType.ptr];
|
|
25
|
-
readonly returns: FFIType.uint16_t;
|
|
26
|
-
};
|
|
27
|
-
readonly zclient_response_body: {
|
|
28
|
-
readonly args: readonly [FFIType.ptr];
|
|
29
|
-
readonly returns: FFIType.ptr;
|
|
30
|
-
};
|
|
31
|
-
readonly zclient_response_body_len: {
|
|
32
|
-
readonly args: readonly [FFIType.ptr];
|
|
33
|
-
readonly returns: FFIType.uint64_t;
|
|
34
|
-
};
|
|
35
|
-
readonly zclient_response_headers: {
|
|
36
|
-
readonly args: readonly [FFIType.ptr];
|
|
37
|
-
readonly returns: FFIType.ptr;
|
|
38
|
-
};
|
|
39
|
-
readonly zclient_response_headers_len: {
|
|
40
|
-
readonly args: readonly [FFIType.ptr];
|
|
41
|
-
readonly returns: FFIType.uint64_t;
|
|
42
|
-
};
|
|
43
|
-
readonly zclient_response_free: {
|
|
44
|
-
readonly args: readonly [FFIType.ptr];
|
|
45
|
-
readonly returns: FFIType.void;
|
|
46
|
-
};
|
|
47
|
-
readonly zclient_request: {
|
|
48
|
-
readonly args: readonly [FFIType.ptr, FFIType.cstring, FFIType.cstring, FFIType.cstring, FFIType.cstring];
|
|
49
|
-
readonly returns: FFIType.ptr;
|
|
1
|
+
export type NativeLib = {
|
|
2
|
+
symbols: {
|
|
3
|
+
zclient_new: () => any;
|
|
4
|
+
zclient_free: (ptr: any) => void;
|
|
5
|
+
zclient_get: (client: any, url: any) => any;
|
|
6
|
+
zclient_post: (client: any, url: any, body: any) => any;
|
|
7
|
+
zclient_prefetch: (client: any, url: any) => void;
|
|
8
|
+
zclient_response_status: (resp: any) => number;
|
|
9
|
+
zclient_response_body: (resp: any) => any;
|
|
10
|
+
zclient_response_body_len: (resp: any) => bigint | number;
|
|
11
|
+
zclient_response_headers: (resp: any) => any;
|
|
12
|
+
zclient_response_headers_len: (resp: any) => bigint | number;
|
|
13
|
+
zclient_response_free: (resp: any) => void;
|
|
14
|
+
zclient_request: (client: any, method: any, url: any, headers: any, body: any) => any;
|
|
50
15
|
};
|
|
51
16
|
};
|
|
52
|
-
export declare const lib:
|
|
53
|
-
|
|
54
|
-
readonly args: readonly [];
|
|
55
|
-
readonly returns: FFIType.ptr;
|
|
56
|
-
};
|
|
57
|
-
readonly zclient_free: {
|
|
58
|
-
readonly args: readonly [FFIType.ptr];
|
|
59
|
-
readonly returns: FFIType.void;
|
|
60
|
-
};
|
|
61
|
-
readonly zclient_get: {
|
|
62
|
-
readonly args: readonly [FFIType.ptr, FFIType.cstring];
|
|
63
|
-
readonly returns: FFIType.ptr;
|
|
64
|
-
};
|
|
65
|
-
readonly zclient_post: {
|
|
66
|
-
readonly args: readonly [FFIType.ptr, FFIType.cstring, FFIType.cstring];
|
|
67
|
-
readonly returns: FFIType.ptr;
|
|
68
|
-
};
|
|
69
|
-
readonly zclient_prefetch: {
|
|
70
|
-
readonly args: readonly [FFIType.ptr, FFIType.cstring];
|
|
71
|
-
readonly returns: FFIType.void;
|
|
72
|
-
};
|
|
73
|
-
readonly zclient_response_status: {
|
|
74
|
-
readonly args: readonly [FFIType.ptr];
|
|
75
|
-
readonly returns: FFIType.uint16_t;
|
|
76
|
-
};
|
|
77
|
-
readonly zclient_response_body: {
|
|
78
|
-
readonly args: readonly [FFIType.ptr];
|
|
79
|
-
readonly returns: FFIType.ptr;
|
|
80
|
-
};
|
|
81
|
-
readonly zclient_response_body_len: {
|
|
82
|
-
readonly args: readonly [FFIType.ptr];
|
|
83
|
-
readonly returns: FFIType.uint64_t;
|
|
84
|
-
};
|
|
85
|
-
readonly zclient_response_headers: {
|
|
86
|
-
readonly args: readonly [FFIType.ptr];
|
|
87
|
-
readonly returns: FFIType.ptr;
|
|
88
|
-
};
|
|
89
|
-
readonly zclient_response_headers_len: {
|
|
90
|
-
readonly args: readonly [FFIType.ptr];
|
|
91
|
-
readonly returns: FFIType.uint64_t;
|
|
92
|
-
};
|
|
93
|
-
readonly zclient_response_free: {
|
|
94
|
-
readonly args: readonly [FFIType.ptr];
|
|
95
|
-
readonly returns: FFIType.void;
|
|
96
|
-
};
|
|
97
|
-
readonly zclient_request: {
|
|
98
|
-
readonly args: readonly [FFIType.ptr, FFIType.cstring, FFIType.cstring, FFIType.cstring, FFIType.cstring];
|
|
99
|
-
readonly returns: FFIType.ptr;
|
|
100
|
-
};
|
|
101
|
-
}>;
|
|
17
|
+
export declare const lib: NativeLib;
|
|
18
|
+
export declare function readCString(ptr: any): string;
|
package/package.json
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jiren",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"author": "",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"module": "index.ts",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
-
"dependencies": {
|
|
9
|
-
|
|
8
|
+
"dependencies": {},
|
|
9
|
+
"optionalDependencies": {
|
|
10
|
+
"koffi": "^2.9.0"
|
|
10
11
|
},
|
|
11
12
|
"devDependencies": {
|
|
12
|
-
"typescript": "^5"
|
|
13
|
+
"typescript": "^5",
|
|
14
|
+
"@types/bun": "^1.3.4"
|
|
13
15
|
},
|
|
14
16
|
"peerDependencies": {
|
|
15
17
|
"typescript": "^5"
|