pynect 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +478 -2
- package/SECURITY.md +34 -0
- package/binding.gyp +60 -0
- package/dist/cli/codegen.d.ts +3 -0
- package/dist/cli/codegen.d.ts.map +1 -0
- package/dist/cli/codegen.js +543 -0
- package/dist/cli/codegen.js.map +1 -0
- package/dist/cli/sync.d.ts +3 -0
- package/dist/cli/sync.d.ts.map +1 -0
- package/dist/cli/sync.js +48 -0
- package/dist/cli/sync.js.map +1 -0
- package/dist/config/project.d.ts +57 -0
- package/dist/config/project.d.ts.map +1 -0
- package/dist/config/project.js +176 -0
- package/dist/config/project.js.map +1 -0
- package/dist/core/IsolatedWorker.d.ts +39 -0
- package/dist/core/IsolatedWorker.d.ts.map +1 -0
- package/dist/core/IsolatedWorker.js +178 -0
- package/dist/core/IsolatedWorker.js.map +1 -0
- package/dist/core/PyCallable.d.ts +67 -0
- package/dist/core/PyCallable.d.ts.map +1 -0
- package/dist/core/PyCallable.js +104 -0
- package/dist/core/PyCallable.js.map +1 -0
- package/dist/core/PyContext.d.ts +76 -0
- package/dist/core/PyContext.d.ts.map +1 -0
- package/dist/core/PyContext.js +239 -0
- package/dist/core/PyContext.js.map +1 -0
- package/dist/core/PyIterator.d.ts +84 -0
- package/dist/core/PyIterator.d.ts.map +1 -0
- package/dist/core/PyIterator.js +243 -0
- package/dist/core/PyIterator.js.map +1 -0
- package/dist/core/PyModule.d.ts +53 -0
- package/dist/core/PyModule.d.ts.map +1 -0
- package/dist/core/PyModule.js +162 -0
- package/dist/core/PyModule.js.map +1 -0
- package/dist/core/PyProxy.d.ts +75 -0
- package/dist/core/PyProxy.d.ts.map +1 -0
- package/dist/core/PyProxy.js +563 -0
- package/dist/core/PyProxy.js.map +1 -0
- package/dist/core/PyRuntime.d.ts +112 -0
- package/dist/core/PyRuntime.d.ts.map +1 -0
- package/dist/core/PyRuntime.js +546 -0
- package/dist/core/PyRuntime.js.map +1 -0
- package/dist/env/PackageInstaller.d.ts +232 -0
- package/dist/env/PackageInstaller.d.ts.map +1 -0
- package/dist/env/PackageInstaller.js +628 -0
- package/dist/env/PackageInstaller.js.map +1 -0
- package/dist/env/ProjectEnvironment.d.ts +63 -0
- package/dist/env/ProjectEnvironment.d.ts.map +1 -0
- package/dist/env/ProjectEnvironment.js +379 -0
- package/dist/env/ProjectEnvironment.js.map +1 -0
- package/dist/env/PyfigAdapter.d.ts +32 -0
- package/dist/env/PyfigAdapter.d.ts.map +1 -0
- package/dist/env/PyfigAdapter.js +10 -0
- package/dist/env/PyfigAdapter.js.map +1 -0
- package/dist/env/PythonDetector.d.ts +48 -0
- package/dist/env/PythonDetector.d.ts.map +1 -0
- package/dist/env/PythonDetector.js +182 -0
- package/dist/env/PythonDetector.js.map +1 -0
- package/dist/env/PythonProvisioner.d.ts +16 -0
- package/dist/env/PythonProvisioner.d.ts.map +1 -0
- package/dist/env/PythonProvisioner.js +42 -0
- package/dist/env/PythonProvisioner.js.map +1 -0
- package/dist/env/VenvManager.d.ts +55 -0
- package/dist/env/VenvManager.d.ts.map +1 -0
- package/dist/env/VenvManager.js +153 -0
- package/dist/env/VenvManager.js.map +1 -0
- package/dist/env/executables.d.ts +3 -0
- package/dist/env/executables.d.ts.map +1 -0
- package/dist/env/executables.js +14 -0
- package/dist/env/executables.js.map +1 -0
- package/dist/index.d.ts +182 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +393 -0
- package/dist/index.js.map +1 -0
- package/dist/native/NativeAddonLoader.d.ts +11 -0
- package/dist/native/NativeAddonLoader.d.ts.map +1 -0
- package/dist/native/NativeAddonLoader.js +75 -0
- package/dist/native/NativeAddonLoader.js.map +1 -0
- package/dist/plugins/Plugin.interface.d.ts +41 -0
- package/dist/plugins/Plugin.interface.d.ts.map +1 -0
- package/dist/plugins/Plugin.interface.js +12 -0
- package/dist/plugins/Plugin.interface.js.map +1 -0
- package/dist/plugins/PluginManager.d.ts +26 -0
- package/dist/plugins/PluginManager.d.ts.map +1 -0
- package/dist/plugins/PluginManager.js +174 -0
- package/dist/plugins/PluginManager.js.map +1 -0
- package/dist/plugins/builtin/NumpyPlugin.d.ts +17 -0
- package/dist/plugins/builtin/NumpyPlugin.d.ts.map +1 -0
- package/dist/plugins/builtin/NumpyPlugin.js +41 -0
- package/dist/plugins/builtin/NumpyPlugin.js.map +1 -0
- package/dist/plugins/builtin/PandasPlugin.d.ts +19 -0
- package/dist/plugins/builtin/PandasPlugin.d.ts.map +1 -0
- package/dist/plugins/builtin/PandasPlugin.js +57 -0
- package/dist/plugins/builtin/PandasPlugin.js.map +1 -0
- package/dist/plugins/builtin/TorchPlugin.d.ts +23 -0
- package/dist/plugins/builtin/TorchPlugin.d.ts.map +1 -0
- package/dist/plugins/builtin/TorchPlugin.js +50 -0
- package/dist/plugins/builtin/TorchPlugin.js.map +1 -0
- package/dist/plugins/index.d.ts +7 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +12 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/serialization/DataFrameBridge.d.ts +141 -0
- package/dist/serialization/DataFrameBridge.d.ts.map +1 -0
- package/dist/serialization/DataFrameBridge.js +355 -0
- package/dist/serialization/DataFrameBridge.js.map +1 -0
- package/dist/serialization/MsgPackSerializer.d.ts +45 -0
- package/dist/serialization/MsgPackSerializer.d.ts.map +1 -0
- package/dist/serialization/MsgPackSerializer.js +242 -0
- package/dist/serialization/MsgPackSerializer.js.map +1 -0
- package/dist/serialization/NumpyBridge.d.ts +96 -0
- package/dist/serialization/NumpyBridge.d.ts.map +1 -0
- package/dist/serialization/NumpyBridge.js +323 -0
- package/dist/serialization/NumpyBridge.js.map +1 -0
- package/dist/serialization/Serializer.d.ts +78 -0
- package/dist/serialization/Serializer.d.ts.map +1 -0
- package/dist/serialization/Serializer.js +281 -0
- package/dist/serialization/Serializer.js.map +1 -0
- package/dist/types/addon.d.ts +131 -0
- package/dist/types/addon.d.ts.map +1 -0
- package/dist/types/addon.js +32 -0
- package/dist/types/addon.js.map +1 -0
- package/dist/types/config.d.ts +233 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +60 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +12 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/python.d.ts +235 -0
- package/dist/types/python.d.ts.map +1 -0
- package/dist/types/python.js +7 -0
- package/dist/types/python.js.map +1 -0
- package/dist/utils/ErrorTranslator.d.ts +83 -0
- package/dist/utils/ErrorTranslator.d.ts.map +1 -0
- package/dist/utils/ErrorTranslator.js +210 -0
- package/dist/utils/ErrorTranslator.js.map +1 -0
- package/dist/utils/Locking.d.ts +3 -0
- package/dist/utils/Locking.d.ts.map +1 -0
- package/dist/utils/Locking.js +10 -0
- package/dist/utils/Locking.js.map +1 -0
- package/dist/utils/Logger.d.ts +27 -0
- package/dist/utils/Logger.d.ts.map +1 -0
- package/dist/utils/Logger.js +115 -0
- package/dist/utils/Logger.js.map +1 -0
- package/dist/utils/MemoryMonitor.d.ts +43 -0
- package/dist/utils/MemoryMonitor.d.ts.map +1 -0
- package/dist/utils/MemoryMonitor.js +143 -0
- package/dist/utils/MemoryMonitor.js.map +1 -0
- package/package.json +114 -4
- package/python/ast_inspector.py +248 -0
- package/python/error_handler.py +432 -0
- package/python/isolated_worker.py +94 -0
- package/python/pynect_dispatcher.py +382 -0
- package/python/pynect_runtime.py +574 -0
- package/python/serializer.py +373 -0
- package/python/type_inspector.py +315 -0
- package/scripts/build-native.js +50 -0
- package/scripts/cli.js +21 -0
- package/scripts/ensure-native.js +85 -0
- package/scripts/postinstall.js +40 -0
- package/scripts/pyfig.js +113 -0
- package/scripts/python-provisioner.js +23 -0
- package/scripts/smoke-python-boundary.js +103 -0
- package/src/native/NativeAddonLoader.ts +98 -0
- package/src/native/gil_guard.cpp +25 -0
- package/src/native/gil_guard.h +174 -0
- package/src/native/pynect_addon.cpp +942 -0
- package/src/native/python_bridge.cpp +904 -0
- package/src/native/python_bridge.h +263 -0
- package/src/native/thread_pool.cpp +375 -0
- package/src/native/thread_pool.h +185 -0
- package/src/native/type_converter.cpp +906 -0
- package/src/native/type_converter.h +271 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Reggie Bowser and NodePyX contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,479 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Pynect
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Pynect lets Node.js and Bun call Python modules in-process with generated TypeScript declarations and optional Python-side Pydantic validation. Python type hints remain the source of truth, so projects do not need a separately maintained controller interface or TypeScript validation schema.
|
|
4
|
+
|
|
5
|
+
Python remains responsible for normalization and validation. If Pydantic 1 or 2 is importable, annotated arguments and return values are validated automatically. Pydantic is optional; Pynect does not install it.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
bun add --trust pynect
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Declare application Python dependencies. Pynect's trusted postinstall creates the uv project and synchronizes the locked environment:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"pynect": {
|
|
18
|
+
"schemaVersion": 1,
|
|
19
|
+
"requiresPython": ">=3.11,<3.13",
|
|
20
|
+
"requirements": ["pydantic>=2,<3"]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
When lifecycle scripts are disabled or Pynect is not trusted, run `bunx --bun pynect sync` explicitly.
|
|
26
|
+
|
|
27
|
+
Current Bun releases and Node.js 22 or newer are supported. Bun-only systems do not need a `node` executable. A preinstalled Python or uv is also unnecessary: Pynect uses Pyfig to create `<project-root>/.venv`, installing its pinned uv and a managed GIL-enabled Python 3.12 when no compatible embeddable CPython exists. When a matching prebuilt addon is unavailable, the first `init()` or `importModule()` compiles it with the active JavaScript runtime from `process.execPath`; a C++ toolchain is still required for that fallback.
|
|
28
|
+
|
|
29
|
+
## Quick start
|
|
30
|
+
|
|
31
|
+
Add a typed Python module such as `calculator.py`:
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
def add(left: int, right: int) -> int:
|
|
35
|
+
return left + right
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Generate declarations for the project. With no module arguments, Pynect discovers Python files under conventional `src` or `python` source roots, falling back to the current directory. Public members are included by default; private modules, private members, and files ending in `_example.py` are skipped:
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
bunx --bun pynect codegen
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`bunx --bun` makes Bun execute the package binary itself, so codegen does not require a separate Node.js installation.
|
|
45
|
+
|
|
46
|
+
Code generation uses [Pacwich](https://github.com/smorsic/pacwich) to resolve the current package or monorepo workspace. By default it also adds the generated declarations to `tsconfig.json`, adds a `codegen` package script when one does not exist, and ignores the generated metadata directory in `.gitignore`.
|
|
47
|
+
|
|
48
|
+
Use the generated module type directly:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { importModule } from 'pynect';
|
|
52
|
+
|
|
53
|
+
const calculator = await importModule('calculator');
|
|
54
|
+
console.log(await calculator.add(2, 3));
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`importModule()` initializes the shared runtime with defaults on first use and the runtime shuts down automatically when the process finishes. Call `init(config)` first only when custom runtime settings are needed. Call `shutdown()` explicitly only when the application needs to release Python before process exit.
|
|
58
|
+
|
|
59
|
+
## Add Pydantic validation
|
|
60
|
+
|
|
61
|
+
For Python-side normalization and validation, use Pydantic models in a module such as `users.py`:
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from pydantic import BaseModel
|
|
65
|
+
|
|
66
|
+
class UserInput(BaseModel):
|
|
67
|
+
name: str
|
|
68
|
+
age: int
|
|
69
|
+
|
|
70
|
+
class UserResult(BaseModel):
|
|
71
|
+
id: int
|
|
72
|
+
name: str
|
|
73
|
+
|
|
74
|
+
def create_user(data: UserInput) -> UserResult:
|
|
75
|
+
return UserResult(id=1, name=data.name)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Regenerate the project declarations:
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
bunx --bun pynect codegen
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Then restrict the dispatcher to fully typed members in that module:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { init, importModule } from 'pynect';
|
|
88
|
+
|
|
89
|
+
await init({
|
|
90
|
+
dispatcher: {
|
|
91
|
+
include: ['users.*'],
|
|
92
|
+
typedOnly: true,
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const users = await importModule('users');
|
|
97
|
+
const user = await users.create_user({ name: 'Alice', age: 30 });
|
|
98
|
+
console.log(user.name);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
When Pydantic is installed in the selected Python environment, the input object becomes a `UserInput` before the function runs. The returned `UserResult` is validated and converted to JSON-compatible Python values before it crosses back to JavaScript. Without Pydantic, the annotated Python call still works but Pydantic validation is skipped.
|
|
102
|
+
|
|
103
|
+
## Why Pynect
|
|
104
|
+
|
|
105
|
+
Pynect and [PyBridge](https://github.com/marcj/pybridge) connect TypeScript and Python with different execution models. Pynect may be a better fit when you want:
|
|
106
|
+
|
|
107
|
+
- CPython embedded in the Node.js or Bun process instead of a Python subprocess connected over standard input and output.
|
|
108
|
+
- TypeScript declarations generated by inspecting Python modules instead of a separately maintained TypeScript controller interface.
|
|
109
|
+
- Direct proxy access to Python modules, classes, objects, and functions.
|
|
110
|
+
- Optional Pydantic 1 or 2 validation and normalization in Python, including Python-defined validators and serializers.
|
|
111
|
+
- Include, exclude, type-hint, and export policies enforced at the dispatcher boundary.
|
|
112
|
+
- Automatic embeddable-Python discovery with a checksum-verified uv fallback when Python is unavailable or lacks development headers.
|
|
113
|
+
|
|
114
|
+
PyBridge may be a better fit when every call must be process-isolated, or when RxJS generator streaming or Deepkit runtime serialization and reflection matter more than direct in-process access.
|
|
115
|
+
|
|
116
|
+
The main tradeoff is isolation versus integration. Normal Pynect proxy calls avoid subprocess transport and duplicate controller definitions, while its optional JSON-only worker provides hard termination for selected calls. Installation still requires a local C++ build toolchain until prebuilt binaries are available.
|
|
117
|
+
|
|
118
|
+
## Python and native build
|
|
119
|
+
|
|
120
|
+
The package loads a matching local N-API addon first. Its build manifest must name the exact interpreter selected by Pyfig; a stale addon built for another Python is rebuilt. If no matching addon works, Pynect lazily builds one against the selected interpreter. The builder is launched with `process.execPath`, so Bun launches Bun and Node.js launches Node.js instead of assuming a `node` command exists. The same approach works with another Node-compatible runtime when it implements the child-process and N-API behavior Pynect needs.
|
|
121
|
+
|
|
122
|
+
```mermaid
|
|
123
|
+
graph TD;
|
|
124
|
+
A[First runtime initialization] --> B[Pyfig selects repository Python];
|
|
125
|
+
B --> C{Exact Python addon loads};
|
|
126
|
+
C -->|Yes| G[Initialize embedded CPython];
|
|
127
|
+
C -->|No| D[Launch builder with process execPath];
|
|
128
|
+
D --> E[Build against selected Python headers and library];
|
|
129
|
+
E --> F[Load newly built addon];
|
|
130
|
+
F --> G;
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Pynect requires Python 3.10 or newer, `Python.h`, a linkable CPython library, and the standard GIL-enabled ABI. It rejects a runtime-only or free-threaded installation instead of compiling against unrelated `python3-config` output. When no compatible interpreter exists, Pyfig downloads the pinned uv archive from Astral's GitHub release, verifies its SHA-256 checksum, and installs managed Python 3.12.
|
|
134
|
+
|
|
135
|
+
Builds, the embedded runtime, codegen, isolated workers, `pipSpawn`, and `uv pip` all use the same repository-root `.venv` interpreter. `virtualenv.path` is deprecated; when provided for compatibility, it must resolve to that root `.venv`.
|
|
136
|
+
|
|
137
|
+
## Locked application environment
|
|
138
|
+
|
|
139
|
+
One application owns one `.venv` and one `pynect.lock`. Reusable npm packages contribute requirements and exposed modules through their `package.json` without installing anything themselves:
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"name": "@acme/name-generator",
|
|
144
|
+
"dependencies": {
|
|
145
|
+
"pynect": "^0.2.0"
|
|
146
|
+
},
|
|
147
|
+
"pynect": {
|
|
148
|
+
"schemaVersion": 1,
|
|
149
|
+
"requiresPython": ">=3.11,<3.13",
|
|
150
|
+
"requirements": ["name-generator>=1,<2"],
|
|
151
|
+
"modules": {
|
|
152
|
+
"generator": {
|
|
153
|
+
"import": "name_generator",
|
|
154
|
+
"include": ["generate_name"]
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
`pynect sync` walks the installed npm dependency graph and writes one minimal generated uv project at `.pynect/pyproject.toml`. uv performs dependency resolution, writes its native universal lock, and exactly synchronizes the root `.venv`; Pynect copies that native lock to the configured `pynect.lock` path for check-in. uv's shared cache avoids repeated downloads across environments. Pynect records the manifest hash, lock hash, Python ABI, platform, and contributing packages in `.venv/.pynect-state.json`.
|
|
162
|
+
|
|
163
|
+
Pynect does not implement a Python package resolver. Conflicts and platform-specific selections are handled by uv, while Pynect adds the npm packages that contributed each top-level requirement to failure output. Dependency manifests may declare only `schemaVersion`, `requiresPython`, `requirements`, and `modules`; Python selection, installation policy, lockfile placement, indexes, and credentials remain application-owned.
|
|
164
|
+
|
|
165
|
+
The root application may resolve a known conflict explicitly without changing a dependency package:
|
|
166
|
+
|
|
167
|
+
```json
|
|
168
|
+
{
|
|
169
|
+
"pynect": {
|
|
170
|
+
"overrides": {
|
|
171
|
+
"image-lib": ">=2,<3"
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Overrides are emitted as uv's native `tool.uv.override-dependencies` configuration and included in the manifest fingerprint. Configure private indexes with uv's application environment variables such as `UV_DEFAULT_INDEX`; keep credentials outside `package.json`.
|
|
178
|
+
|
|
179
|
+
Exposed module ids are namespaced by npm package name:
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
import { importModule } from 'pynect';
|
|
183
|
+
|
|
184
|
+
const generator = await importModule('@acme/name-generator:generator');
|
|
185
|
+
console.log(await generator.generate_name());
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
The aggregated `modules.include` patterns are enforced by the runtime dispatcher. When `include` is omitted, that manifest exposes the module's public callables; application dispatcher includes are additive, and excludes always win.
|
|
189
|
+
|
|
190
|
+
Normal runtime startup validates the lock and environment state without network access. Applications that want development-time repair may opt in with `"autoSync": "if-missing"`; the default is `"never"`. Production and CI should use an explicit frozen sync:
|
|
191
|
+
|
|
192
|
+
```sh
|
|
193
|
+
bunx --bun pynect sync --frozen
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Pynect's postinstall runs the same sync automatically when a reachable npm package contributes a `pynect` manifest. Set `PYNECT_SKIP_POSTINSTALL=1` to opt out. npm users can also use `--ignore-scripts`; Bun users must explicitly trust `pynect` because Bun blocks dependency lifecycle scripts by default:
|
|
197
|
+
|
|
198
|
+
```json
|
|
199
|
+
{
|
|
200
|
+
"trustedDependencies": ["pynect"]
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
An application may always keep installation side-effect free and run `pynect sync` explicitly instead.
|
|
205
|
+
|
|
206
|
+
Configuration precedence is API or CLI, environment, root `package.json`, then default:
|
|
207
|
+
|
|
208
|
+
| package.json / API | Environment | CLI | Default |
|
|
209
|
+
| --- | --- | --- | --- |
|
|
210
|
+
| `python` | `PYNECT_PYTHON` | `--python` | auto-detect |
|
|
211
|
+
| `requiresPython` | `PYNECT_REQUIRES_PYTHON` | `--requires-python` | `>=3.10.0 <4.0.0` |
|
|
212
|
+
| `managedPython` | `PYNECT_MANAGED_PYTHON` | `--managed-python` | `3.12` |
|
|
213
|
+
| `uvVersion` | `PYNECT_UV_VERSION` | `--uv-version` | Pyfig's pinned release |
|
|
214
|
+
| `installPython` | `PYNECT_INSTALL_PYTHON` | `--install-python` | `true` |
|
|
215
|
+
| `installUv` | `PYNECT_INSTALL_UV` | `--install-uv` | `true` |
|
|
216
|
+
| `createVirtualEnvironment` | `PYNECT_CREATE_VIRTUAL_ENVIRONMENT` | `--create-virtual-environment` | `true` |
|
|
217
|
+
| `autoSync` | `PYNECT_AUTO_SYNC` | n/a | `never` |
|
|
218
|
+
| `lockfile` | `PYNECT_LOCKFILE` | `--lockfile` | `pynect.lock` |
|
|
219
|
+
|
|
220
|
+
`--offline` prohibits network access. `--frozen` passes uv's `--locked` check and refuses to rewrite an outdated lock. The deprecated `PYNECT_AUTO_INSTALL` and runtime `autoInstallPython` names remain compatibility aliases; new configuration should use the names above. Runtime `virtualenv.autoInstall` is no longer supported because independent startup installs cannot resolve the complete npm dependency graph safely.
|
|
221
|
+
|
|
222
|
+
Pynect uses [loqkit](https://www.npmjs.com/package/loqkit) for JavaScript critical sections. Project sync and native builds use its default layered memory, worker-thread, and cross-process file locks. Runtime lifecycle and Python garbage collection use memory-scoped locks because those resources belong to one JavaScript process. Pynect does not maintain separate promise, module, inspection, or proxy memo caches; new memoized getters should use loqkit's `memoize` primitive.
|
|
223
|
+
|
|
224
|
+
Pyfig's managed-tool provisioning uses its own check-lock-check sections:
|
|
225
|
+
|
|
226
|
+
1. Check for an existing tool.
|
|
227
|
+
2. Acquire a cross-process file lock.
|
|
228
|
+
3. Check again.
|
|
229
|
+
4. Install only if it is still absent.
|
|
230
|
+
|
|
231
|
+
A C++ build toolchain is still required. On Windows, install Visual Studio Build Tools with the Desktop development with C++ workload. Set `PYNECT_AUTO_INSTALL=0` to prohibit managed Python downloads while still allowing `.venv` creation from a compatible setup-python or system interpreter. Set `PYNECT_INSTALL_UV=0` to prohibit uv installation, `PYNECT_CREATE_VIRTUAL_ENVIRONMENT=0` to require an existing root `.venv`, or `PYNECT_PYTHON` to check a specific interpreter first.
|
|
232
|
+
|
|
233
|
+
## Codegen selection
|
|
234
|
+
|
|
235
|
+
The simplest form discovers project modules and generates every public member:
|
|
236
|
+
|
|
237
|
+
```sh
|
|
238
|
+
bunx --bun pynect codegen
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Pass module names when you only want specific modules:
|
|
242
|
+
|
|
243
|
+
```sh
|
|
244
|
+
bunx --bun pynect codegen users billing
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Add repeatable include and exclude patterns when a project needs a narrower surface. Supplying `--include` restricts output to matching members. Supplying `--typed` restricts output to fully typed members. `--exclude` always excludes. Patterns match leaf or qualified names:
|
|
248
|
+
|
|
249
|
+
```sh
|
|
250
|
+
bunx --bun pynect codegen users billing \
|
|
251
|
+
--include 'users.*' \
|
|
252
|
+
--include 'billing.Invoice*' \
|
|
253
|
+
--exclude '*internal*' \
|
|
254
|
+
--typed
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
For reusable settings, put the same options in `pynect.config.json`:
|
|
258
|
+
|
|
259
|
+
```json
|
|
260
|
+
{
|
|
261
|
+
"src": ["./python"],
|
|
262
|
+
"outDir": "./generated",
|
|
263
|
+
"include": ["users.*", "billing.Invoice*"],
|
|
264
|
+
"exclude": ["*internal*"],
|
|
265
|
+
"typed": true,
|
|
266
|
+
"configure": true
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
The CLI uses Commander. Configuration precedence is CLI, environment, JSON config, then defaults. Set `"configure": false` or pass `--no-configure` to prevent edits to `tsconfig.json`, `package.json`, and `.gitignore`. Use `--tsconfig` when the workspace uses a nonstandard config filename.
|
|
271
|
+
|
|
272
|
+
Automatic discovery skips directories, packages, and modules whose names begin with `_`, common environment and build directories, and files ending in `_example.py`. The same private-package rule applies to explicitly requested module paths. Use repeatable `--src` options when Python lives somewhere else:
|
|
273
|
+
|
|
274
|
+
```sh
|
|
275
|
+
bunx --bun pynect codegen --src ./backend --src ./shared-python
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Local source files are parsed with Python's AST and are not imported during generation. Explicit installed modules that cannot be resolved under a configured source root use live inspection so packages such as NumPy and pandas can still expose their runtime API.
|
|
279
|
+
|
|
280
|
+
Use centralized overrides for opaque extension types or legacy untyped functions:
|
|
281
|
+
|
|
282
|
+
```json
|
|
283
|
+
{
|
|
284
|
+
"typeOverrides": {
|
|
285
|
+
"UUID": "string",
|
|
286
|
+
"Decimal": "number"
|
|
287
|
+
},
|
|
288
|
+
"signatureOverrides": {
|
|
289
|
+
"legacy.lookup": "(userId: string): Promise<User>",
|
|
290
|
+
"legacy.Client.fetch": "(limit?: number): Promise<User[]>"
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Type overrides map a Python annotation name wherever it appears. Signature overrides are keyed by the fully qualified function or method name and replace its generated TypeScript call signature.
|
|
296
|
+
|
|
297
|
+
Other commands:
|
|
298
|
+
|
|
299
|
+
```sh
|
|
300
|
+
bunx pynect codegen --list
|
|
301
|
+
bunx pynect codegen --all
|
|
302
|
+
bunx pynect codegen --clear
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
`--all` means all modules tracked in generated metadata. Within each requested module, the default is all public members. Use `--exported` to require the `@export` marker or `--typed` to require complete parameter and return type hints.
|
|
306
|
+
|
|
307
|
+
## Raw module imports
|
|
308
|
+
|
|
309
|
+
Generated declarations are the normal application workflow. For exploration, third-party packages, or Python modules that do not need generated types, import a module directly:
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
import { importModule } from 'pynect';
|
|
313
|
+
|
|
314
|
+
const math = await importModule('math');
|
|
315
|
+
console.log(await math.sqrt(9));
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Raw imports return a dynamic Python proxy. Run codegen when the module should provide TypeScript inference in application code.
|
|
319
|
+
|
|
320
|
+
## Runtime policy
|
|
321
|
+
|
|
322
|
+
```ts
|
|
323
|
+
await init({
|
|
324
|
+
autoShutdown: true,
|
|
325
|
+
dispatcher: {
|
|
326
|
+
include: ['my_app.*'],
|
|
327
|
+
exclude: ['*.admin.*', '*._*'],
|
|
328
|
+
typedOnly: true,
|
|
329
|
+
exportedOnly: false,
|
|
330
|
+
validation: 'auto', // auto, required, or off
|
|
331
|
+
},
|
|
332
|
+
allowUnsafeCode: false,
|
|
333
|
+
allowPackageInstall: false,
|
|
334
|
+
includeTracebacks: false,
|
|
335
|
+
});
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
`autoShutdown` defaults to `true` for both the embedded runtime and the optional isolated worker. Set it to `false` only when the host owns lifecycle and will call `shutdown()` explicitly.
|
|
339
|
+
|
|
340
|
+
Defaults are intentionally conservative around dangerous bridge features:
|
|
341
|
+
|
|
342
|
+
- Raw `eval`, `exec`, file execution, contexts, and native-addon access are disabled.
|
|
343
|
+
- Runtime package installation is disabled.
|
|
344
|
+
- Python tracebacks are hidden.
|
|
345
|
+
- Private callables and modules are rejected.
|
|
346
|
+
- Excludes override includes and decorators.
|
|
347
|
+
- Pydantic validation is automatic only when Pydantic is already importable.
|
|
348
|
+
|
|
349
|
+
Every normal proxy function, method, and constructor call passes through this policy and validation dispatcher.
|
|
350
|
+
`typedOnly` and `exportedOnly` are independent: enabling both requires every callable to be explicitly exported and fully typed.
|
|
351
|
+
|
|
352
|
+
The worker pool defaults to the larger of four workers or the host's available CPU count. This improves queue scheduling; the CPython GIL still prevents CPU-bound Python bytecode from running in parallel within one interpreter.
|
|
353
|
+
|
|
354
|
+
## Cancellation and timeouts
|
|
355
|
+
|
|
356
|
+
`callTimeout` limits time waiting in the native queue. `executionTimeout` separately cancels asynchronous Python execution:
|
|
357
|
+
|
|
358
|
+
```ts
|
|
359
|
+
await init({
|
|
360
|
+
callTimeout: 2_000,
|
|
361
|
+
executionTimeout: 10_000,
|
|
362
|
+
});
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
Every generated function and method includes a typed `withOptions()` call:
|
|
366
|
+
|
|
367
|
+
```ts
|
|
368
|
+
import { importModule } from 'pynect';
|
|
369
|
+
|
|
370
|
+
const jobs = await importModule('jobs');
|
|
371
|
+
const controller = new AbortController();
|
|
372
|
+
|
|
373
|
+
setTimeout(() => controller.abort(), 1_000);
|
|
374
|
+
await jobs.run_job.withOptions(
|
|
375
|
+
{ signal: controller.signal, executionTimeout: 5_000 },
|
|
376
|
+
{ id: 42 },
|
|
377
|
+
);
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
`withOptions` is a property on the callable, so it does not consume a sibling module name such as `run_jobWithOptions`. If a Python callable itself defines a `withOptions` attribute, use the exported `PYNECT_WITH_OPTIONS` symbol for the bridge operation:
|
|
381
|
+
|
|
382
|
+
```ts
|
|
383
|
+
import { PYNECT_WITH_OPTIONS } from 'pynect';
|
|
384
|
+
|
|
385
|
+
await jobs.run_job[PYNECT_WITH_OPTIONS](
|
|
386
|
+
{ executionTimeout: 5_000 },
|
|
387
|
+
{ id: 42 },
|
|
388
|
+
);
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
Queued calls are removed before execution when possible. Running async functions are cancelled on the persistent asyncio loop. Arbitrary synchronous CPython code cannot be interrupted safely inside the Node.js process.
|
|
392
|
+
|
|
393
|
+
## Isolated calls
|
|
394
|
+
|
|
395
|
+
Enable the optional worker when a call needs a hard timeout or when an ordinary Python interpreter crash should be contained outside the Node.js process:
|
|
396
|
+
|
|
397
|
+
```ts
|
|
398
|
+
import { callIsolated, init, shutdown } from 'pynect';
|
|
399
|
+
|
|
400
|
+
await init({
|
|
401
|
+
isolation: {
|
|
402
|
+
enabled: true,
|
|
403
|
+
timeout: 30_000,
|
|
404
|
+
},
|
|
405
|
+
dispatcher: {
|
|
406
|
+
include: ['jobs.*'],
|
|
407
|
+
},
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
try {
|
|
411
|
+
const result = await callIsolated(
|
|
412
|
+
'jobs',
|
|
413
|
+
'run_job',
|
|
414
|
+
[{ id: 42 }],
|
|
415
|
+
{ timeout: 5_000 },
|
|
416
|
+
);
|
|
417
|
+
console.log(result);
|
|
418
|
+
} finally {
|
|
419
|
+
await shutdown();
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
Isolated calls use a lazy persistent Python child process and JSON-compatible arguments and results. Calls through that worker are serialized. A timeout or abort terminates it, rejects its outstanding calls, and lets the next call start a fresh worker. The child process still has the operating-system permissions of the current user; use an OS sandbox or container for hostile code.
|
|
424
|
+
|
|
425
|
+
## Pydantic modes
|
|
426
|
+
|
|
427
|
+
- `auto`: validate every supported argument and return annotation when Pydantic 1 or 2 is available; otherwise preserve Python behavior. This is the default for all normal callable dispatches.
|
|
428
|
+
- `required`: reject calls when Pydantic is missing or cannot build a validator for an annotation.
|
|
429
|
+
- `off`: never ask Pydantic to validate.
|
|
430
|
+
|
|
431
|
+
Pydantic models, aliases, defaults, nested models, enums, dates, UUIDs, and standard annotated containers use Pydantic's own validation and serialization behavior. Custom validators and serializers run in Python; Pynect does not attempt to reproduce them in TypeScript.
|
|
432
|
+
|
|
433
|
+
Pydantic cannot infer a validation target for an unannotated value, and some extension callables do not expose an inspectable signature. Those calls still pass through the dispatcher and its access policy, but their untyped values retain normal Python behavior.
|
|
434
|
+
|
|
435
|
+
## Current limits
|
|
436
|
+
|
|
437
|
+
- Normal proxy calls are in-process. A native Python crash can terminate Node or Bun; use `callIsolated()` where a process boundary is required.
|
|
438
|
+
- In-process execution timeouts and aborts are cooperative for async functions. Hard termination of synchronous code requires `callIsolated()`.
|
|
439
|
+
- Async Python uses one persistent asyncio loop. CPU-bound work still needs Python multiprocessing or native extensions that release the GIL.
|
|
440
|
+
- Local modules use safe AST inspection, but codegen for explicitly requested installed packages imports those packages and may run their import-time code.
|
|
441
|
+
- The isolated worker is not an operating-system sandbox and supports only JSON-compatible calls, not Python object proxies.
|
|
442
|
+
- GitHub Actions builds Python 3.12 native artifacts for Linux, macOS, and Windows on x64 and ARM64. Those artifacts are not yet attached to releases or downloaded during package installation.
|
|
443
|
+
|
|
444
|
+
See [SECURITY.md](./SECURITY.md) before exposing imports or call patterns to untrusted input.
|
|
445
|
+
|
|
446
|
+
## Development
|
|
447
|
+
|
|
448
|
+
```sh
|
|
449
|
+
bun install --frozen-lockfile
|
|
450
|
+
bun run verify
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
`verify` type-checks, rebuilds the addon, and runs the shared-interpreter smoke test. `scripts/docker-zero-python.sh` is the clean-container reproduction: it starts from the official Bun image, asserts that Node.js, Python, and uv are absent, installs the registry-published Pyfig dependency plus only the C++ toolchain, then verifies Pyfig bootstrap, lazy native compilation through Bun, and the full Pynect native boundary. The separate `Native binaries` workflow runs for native or Python-boundary changes and can also be started manually.
|
|
454
|
+
|
|
455
|
+
### Publishing
|
|
456
|
+
|
|
457
|
+
Local publishing uses the package-scoped npm token at `~/.secrets/npm/pynect-publish-token`. The file contains only the raw token and must never be copied into the repository, an npm command-line argument, or a log. The token is limited to `pynect`, has package read/write access, has no organization access, bypasses publish-time 2FA, and expires January 30, 2027.
|
|
458
|
+
|
|
459
|
+
Load the token only into the current PowerShell process, verify the npm identity, and publish from a clean `main` branch:
|
|
460
|
+
|
|
461
|
+
```powershell
|
|
462
|
+
$tokenPath = Join-Path $env:USERPROFILE '.secrets\npm\pynect-publish-token'
|
|
463
|
+
$env:NPM_TOKEN = (Get-Content -Raw -LiteralPath $tokenPath).Trim()
|
|
464
|
+
|
|
465
|
+
try {
|
|
466
|
+
npm whoami --registry=https://registry.npmjs.org/
|
|
467
|
+
npm publish
|
|
468
|
+
} finally {
|
|
469
|
+
Remove-Item Env:NPM_TOKEN -ErrorAction SilentlyContinue
|
|
470
|
+
}
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
npm plans to remove direct publishing with bypass-2FA granular tokens in January 2027. Replace this local flow with trusted publishing before that cutoff; until then, rotate the token at the same secret path without changing repository files.
|
|
474
|
+
|
|
475
|
+
## Project history
|
|
476
|
+
|
|
477
|
+
Pynect builds on [NodePyX](https://github.com/Brah-Timo/nodepyx) and retains its Git history and contributor attribution. Its public API, dispatcher policy, optional Pydantic integration, Python provisioning, codegen, and Windows build path have been revised for this project.
|
|
478
|
+
|
|
479
|
+
MIT licensed.
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Security
|
|
2
|
+
|
|
3
|
+
Pynect embeds Python in the JavaScript process. Treat every imported module and callable as trusted code with the permissions of that process.
|
|
4
|
+
|
|
5
|
+
## Safe defaults
|
|
6
|
+
|
|
7
|
+
- Raw Python code execution and native-addon access require `allowUnsafeCode: true`.
|
|
8
|
+
- Package installation requires `allowPackageInstall: true`.
|
|
9
|
+
- Tracebacks are hidden unless `includeTracebacks: true`.
|
|
10
|
+
- Dispatcher include, exclude, type-hint, and export policies are enforced inside the native call path.
|
|
11
|
+
- Dependency manifests cannot select indexes, credentials, interpreters, or installation policy.
|
|
12
|
+
- Postinstall synchronization runs only when lifecycle scripts are enabled (and, with Bun, Pynect is trusted); set `PYNECT_SKIP_POSTINSTALL=1` or disable lifecycle scripts to require explicit synchronization.
|
|
13
|
+
- Normal runtime startup validates the checked lock and environment fingerprint without installing packages.
|
|
14
|
+
- Local codegen discovery uses AST parsing and does not execute application modules.
|
|
15
|
+
- Private module and callable names are rejected; explicit excludes always win.
|
|
16
|
+
- Python package specifications and module identifiers are validated before subprocess use.
|
|
17
|
+
- Pyfig pins uv, downloads only Astral's GitHub release archive, and verifies its SHA-256 checksum before extraction.
|
|
18
|
+
- Pynect project sync and native builds use loqkit's layered memory, worker-thread, and cross-process file locks; process-owned runtime and garbage-collection sections use its memory lock.
|
|
19
|
+
- Pyfig and uv retain ownership of their package and managed-tool synchronization.
|
|
20
|
+
- uv owns Python dependency resolution and exact environment synchronization through the generated non-package `pyproject.toml`; Pynect does not implement a parallel resolver.
|
|
21
|
+
|
|
22
|
+
## Deployment guidance
|
|
23
|
+
|
|
24
|
+
Use a narrow dispatcher include list, run under a low-privilege operating-system account, and keep `allowUnsafeCode` and `allowPackageInstall` disabled for applications that process untrusted input. Do not let request data select module names, attribute paths, package specifications, Python code, or filesystem paths.
|
|
25
|
+
|
|
26
|
+
Pydantic validates data shapes; it is not a sandbox. Validators and serializers are Python code and must be trusted.
|
|
27
|
+
|
|
28
|
+
`callIsolated()` protects the Node.js process from a worker crash and allows hard termination on timeout. It does not reduce filesystem, network, environment, or operating-system permissions. Run hostile code in a separately secured account, container, virtual machine, or platform sandbox.
|
|
29
|
+
|
|
30
|
+
Codegen for explicitly requested installed modules uses runtime inspection and imports the package. Only inspect third-party packages you trust.
|
|
31
|
+
|
|
32
|
+
## Reporting
|
|
33
|
+
|
|
34
|
+
Report vulnerabilities privately to the repository owner before opening a public issue. Include the affected commit, platform, Python version, JavaScript runtime and version, and a minimal reproduction without secrets.
|
package/binding.gyp
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"targets": [{
|
|
3
|
+
"target_name": "pynect_addon",
|
|
4
|
+
"sources": [
|
|
5
|
+
"src/native/pynect_addon.cpp",
|
|
6
|
+
"src/native/python_bridge.cpp",
|
|
7
|
+
"src/native/type_converter.cpp",
|
|
8
|
+
"src/native/thread_pool.cpp",
|
|
9
|
+
"src/native/gil_guard.cpp"
|
|
10
|
+
],
|
|
11
|
+
"include_dirs": [
|
|
12
|
+
"<!@(node -p \"require('node-addon-api').include\")",
|
|
13
|
+
"<!(node -p \"process.env.PYNECT_PYTHON_INCLUDE_DIR || (() => { throw new Error('PYNECT_PYTHON_INCLUDE_DIR is required') })()\")"
|
|
14
|
+
],
|
|
15
|
+
"libraries": [
|
|
16
|
+
"<!(node -p \"process.env.PYNECT_PYTHON_LIBRARY || (() => { throw new Error('PYNECT_PYTHON_LIBRARY is required') })()\")"
|
|
17
|
+
],
|
|
18
|
+
"cflags_cc": [
|
|
19
|
+
"-std=c++17",
|
|
20
|
+
"-O2",
|
|
21
|
+
"-Wall",
|
|
22
|
+
"-Wextra",
|
|
23
|
+
"-Wno-unused-parameter"
|
|
24
|
+
],
|
|
25
|
+
"cflags!": ["-fno-exceptions"],
|
|
26
|
+
"cflags_cc!": ["-fno-exceptions"],
|
|
27
|
+
"defines": [
|
|
28
|
+
"NAPI_CPP_EXCEPTIONS",
|
|
29
|
+
"NAPI_VERSION=8",
|
|
30
|
+
"PY_SSIZE_T_CLEAN"
|
|
31
|
+
],
|
|
32
|
+
"conditions": [
|
|
33
|
+
["OS=='linux'", {
|
|
34
|
+
"cflags_cc": ["-fvisibility=hidden"],
|
|
35
|
+
"libraries": ["-ldl"],
|
|
36
|
+
"ldflags": [
|
|
37
|
+
"-Wl,-rpath,<!(node -p \"process.env.PYNECT_PYTHON_LIBRARY_DIR || (() => { throw new Error('PYNECT_PYTHON_LIBRARY_DIR is required') })()\")"
|
|
38
|
+
]
|
|
39
|
+
}],
|
|
40
|
+
["OS=='mac'", {
|
|
41
|
+
"xcode_settings": {
|
|
42
|
+
"MACOSX_DEPLOYMENT_TARGET": "11.0",
|
|
43
|
+
"OTHER_CFLAGS": ["-std=c++17", "-stdlib=libc++"],
|
|
44
|
+
"LD_RUNPATH_SEARCH_PATHS": [
|
|
45
|
+
"<!(node -p \"process.env.PYNECT_PYTHON_LIBRARY_DIR || (() => { throw new Error('PYNECT_PYTHON_LIBRARY_DIR is required') })()\")"
|
|
46
|
+
],
|
|
47
|
+
"GCC_ENABLE_CPP_EXCEPTIONS": "YES"
|
|
48
|
+
}
|
|
49
|
+
}],
|
|
50
|
+
["OS=='win'", {
|
|
51
|
+
"msvs_settings": {
|
|
52
|
+
"VCCLCompilerTool": {
|
|
53
|
+
"ExceptionHandling": 1,
|
|
54
|
+
"AdditionalOptions": ["/std:c++17"]
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}]
|
|
58
|
+
]
|
|
59
|
+
}]
|
|
60
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../src/cli/codegen.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AA6G5C,wBAAgB,oBAAoB,CAAC,IAAI,SAAY,GAAG,OAAO,CAwB9D"}
|