castle-token 0.1.0__tar.gz

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.
Files changed (41) hide show
  1. castle_token-0.1.0/.github/workflows/ci.yml +26 -0
  2. castle_token-0.1.0/.github/workflows/node-release.yml +234 -0
  3. castle_token-0.1.0/.github/workflows/node.yml +37 -0
  4. castle_token-0.1.0/.github/workflows/python-release.yml +179 -0
  5. castle_token-0.1.0/.github/workflows/python.yml +55 -0
  6. castle_token-0.1.0/.gitignore +27 -0
  7. castle_token-0.1.0/Cargo.lock +833 -0
  8. castle_token-0.1.0/Cargo.toml +35 -0
  9. castle_token-0.1.0/PKG-INFO +90 -0
  10. castle_token-0.1.0/README.md +171 -0
  11. castle_token-0.1.0/pyproject.toml +29 -0
  12. castle_token-0.1.0/python/Cargo.toml +23 -0
  13. castle_token-0.1.0/python/README.md +71 -0
  14. castle_token-0.1.0/python/castle_token/__init__.py +23 -0
  15. castle_token-0.1.0/python/castle_token/__init__.pyi +80 -0
  16. castle_token-0.1.0/python/castle_token/py.typed +0 -0
  17. castle_token-0.1.0/python/examples/mint_token.py +60 -0
  18. castle_token-0.1.0/python/src/lib.rs +234 -0
  19. castle_token-0.1.0/python/tests/test_smoke.py +58 -0
  20. castle_token-0.1.0/src/ce.rs +224 -0
  21. castle_token-0.1.0/src/codec.rs +68 -0
  22. castle_token-0.1.0/src/error.rs +57 -0
  23. castle_token-0.1.0/src/events.rs +166 -0
  24. castle_token-0.1.0/src/fingerprint/context.rs +400 -0
  25. castle_token-0.1.0/src/fingerprint/devices.json +363 -0
  26. castle_token-0.1.0/src/fingerprint/devices.rs +39 -0
  27. castle_token-0.1.0/src/fingerprint/encode.rs +186 -0
  28. castle_token-0.1.0/src/fingerprint/mod.rs +214 -0
  29. castle_token-0.1.0/src/fingerprint/parts/extra.rs +58 -0
  30. castle_token-0.1.0/src/fingerprint/parts/mod.rs +30 -0
  31. castle_token-0.1.0/src/fingerprint/parts/part0.rs +243 -0
  32. castle_token-0.1.0/src/fingerprint/parts/part4.rs +183 -0
  33. castle_token-0.1.0/src/fingerprint/parts/part7.rs +241 -0
  34. castle_token-0.1.0/src/lib.rs +19 -0
  35. castle_token-0.1.0/src/main.rs +80 -0
  36. castle_token-0.1.0/src/token/encoder.rs +133 -0
  37. castle_token-0.1.0/src/token/inner_payload.rs +32 -0
  38. castle_token-0.1.0/src/token/mod.rs +180 -0
  39. castle_token-0.1.0/src/token/time_token.rs +109 -0
  40. castle_token-0.1.0/src/xxtea.rs +144 -0
  41. castle_token-0.1.0/tests/decode_roundtrip.rs +90 -0
@@ -0,0 +1,26 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ env:
10
+ CARGO_TERM_COLOR: always
11
+
12
+ jobs:
13
+ test:
14
+ name: fmt + clippy + test
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v7
18
+ - uses: dtolnay/rust-toolchain@stable
19
+ with:
20
+ components: rustfmt, clippy
21
+ - uses: Swatinem/rust-cache@v2
22
+ - run: cargo fmt --all --check
23
+ # Scope clippy/test to the core crate so this Rust-only job never builds
24
+ # the PyO3 cdylib (which needs a Python interpreter) — see python.yml.
25
+ - run: cargo clippy -p castle-token --all-targets -- -D warnings
26
+ - run: cargo test -p castle-token
@@ -0,0 +1,234 @@
1
+ name: Node release
2
+
3
+ # Cross-arch prebuilt-binary pipeline for the `castle-token` npm package.
4
+ #
5
+ # Triggered by a `vX.Y.Z` tag: builds the addon for every target in
6
+ # node/package.json `napi.targets`, runs the binaries on real OS/arch matrices,
7
+ # then publishes the main package + the per-platform `optionalDependencies`
8
+ # packages so `npm i castle-token` pulls a prebuilt .node with no Rust toolchain.
9
+ #
10
+ # `workflow_dispatch` runs build + test only (no publish) for dry-runs.
11
+ #
12
+ # Release process:
13
+ # 1. set the SAME version in node/package.json `version` AND all 8
14
+ # `optionalDependencies` entries — they must match exactly. (`napi version`
15
+ # updates the npm/<platform>/ packages but NOT the root optionalDependencies,
16
+ # so bump those by hand or with a script.)
17
+ # 2. commit, then `git tag vX.Y.Z && git push origin vX.Y.Z`.
18
+ # Requires a repo secret `NPM_TOKEN` that is an npm **Automation** token — a
19
+ # classic/granular token fails publish with EOTP when the account has 2FA. The
20
+ # publish job fail-fasts if the tag/version disagree or npm auth is missing.
21
+
22
+ on:
23
+ push:
24
+ tags:
25
+ - 'v*.*.*'
26
+ workflow_dispatch:
27
+
28
+ env:
29
+ CARGO_TERM_COLOR: always
30
+ APP_NAME: castle-token
31
+ DEBUG: napi:*
32
+
33
+ defaults:
34
+ run:
35
+ working-directory: node
36
+
37
+ jobs:
38
+ build:
39
+ name: build ${{ matrix.settings.target }}
40
+ runs-on: ${{ matrix.settings.host }}
41
+ strategy:
42
+ fail-fast: false
43
+ matrix:
44
+ settings:
45
+ - host: ubuntu-latest
46
+ target: x86_64-unknown-linux-gnu
47
+ build: npm run build -- --target x86_64-unknown-linux-gnu --use-napi-cross
48
+ - host: ubuntu-latest
49
+ target: x86_64-unknown-linux-musl
50
+ build: npm run build -- --target x86_64-unknown-linux-musl -x
51
+ - host: ubuntu-latest
52
+ target: aarch64-unknown-linux-gnu
53
+ build: npm run build -- --target aarch64-unknown-linux-gnu --use-napi-cross
54
+ - host: ubuntu-latest
55
+ target: aarch64-unknown-linux-musl
56
+ build: npm run build -- --target aarch64-unknown-linux-musl -x
57
+ - host: macos-latest
58
+ target: x86_64-apple-darwin
59
+ build: npm run build -- --target x86_64-apple-darwin
60
+ - host: macos-latest
61
+ target: aarch64-apple-darwin
62
+ build: npm run build -- --target aarch64-apple-darwin
63
+ - host: windows-latest
64
+ target: x86_64-pc-windows-msvc
65
+ build: npm run build -- --target x86_64-pc-windows-msvc
66
+ - host: windows-latest
67
+ target: aarch64-pc-windows-msvc
68
+ build: npm run build -- --target aarch64-pc-windows-msvc
69
+ steps:
70
+ - uses: actions/checkout@v7
71
+ - uses: actions/setup-node@v6
72
+ with:
73
+ node-version: 24
74
+ cache: npm
75
+ cache-dependency-path: node/package-lock.json
76
+ - uses: dtolnay/rust-toolchain@stable
77
+ with:
78
+ targets: ${{ matrix.settings.target }}
79
+ - uses: Swatinem/rust-cache@v2
80
+ with:
81
+ workspaces: ". -> target"
82
+ key: ${{ matrix.settings.target }}
83
+ # musl targets cross-compile via cargo-zigbuild (`-x`); gnu targets use the
84
+ # napi cross-toolchain (`--use-napi-cross`), which the CLI fetches itself.
85
+ - uses: mlugg/setup-zig@v2
86
+ if: ${{ contains(matrix.settings.target, 'musl') }}
87
+ with:
88
+ version: 0.14.1
89
+ - uses: taiki-e/install-action@v2
90
+ if: ${{ contains(matrix.settings.target, 'musl') }}
91
+ with:
92
+ tool: cargo-zigbuild
93
+ - run: npm ci
94
+ - name: Build
95
+ run: ${{ matrix.settings.build }}
96
+ shell: bash
97
+ - uses: actions/upload-artifact@v7
98
+ with:
99
+ name: bindings-${{ matrix.settings.target }}
100
+ # path is repo-root-relative (not working-directory); the wildcard's
101
+ # common ancestor (node/) is stripped, so the artifact holds the bare
102
+ # castle-token.<target>.node, which the test job's `path: node` places
103
+ # back at node/ for the local-first loader.
104
+ path: node/${{ env.APP_NAME }}.*.node
105
+ if-no-files-found: error
106
+
107
+ test-macos-windows:
108
+ name: test ${{ matrix.settings.target }} - node@${{ matrix.node }}
109
+ needs: build
110
+ runs-on: ${{ matrix.settings.host }}
111
+ strategy:
112
+ fail-fast: false
113
+ matrix:
114
+ settings:
115
+ - host: macos-latest
116
+ target: aarch64-apple-darwin
117
+ architecture: arm64
118
+ - host: macos-latest
119
+ target: x86_64-apple-darwin
120
+ architecture: x64
121
+ - host: windows-latest
122
+ target: x86_64-pc-windows-msvc
123
+ architecture: x64
124
+ - host: windows-11-arm
125
+ target: aarch64-pc-windows-msvc
126
+ architecture: arm64
127
+ node: ['22', '24']
128
+ steps:
129
+ - uses: actions/checkout@v7
130
+ - uses: actions/setup-node@v6
131
+ with:
132
+ node-version: ${{ matrix.node }}
133
+ architecture: ${{ matrix.settings.architecture }}
134
+ - uses: actions/download-artifact@v8
135
+ with:
136
+ name: bindings-${{ matrix.settings.target }}
137
+ path: node
138
+ - run: node --test
139
+
140
+ test-linux:
141
+ name: test ${{ matrix.target }} - node@${{ matrix.node }}
142
+ needs: build
143
+ runs-on: ${{ contains(matrix.target, 'aarch64') && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
144
+ strategy:
145
+ fail-fast: false
146
+ matrix:
147
+ target:
148
+ - x86_64-unknown-linux-gnu
149
+ - x86_64-unknown-linux-musl
150
+ - aarch64-unknown-linux-gnu
151
+ - aarch64-unknown-linux-musl
152
+ node: ['22', '24']
153
+ steps:
154
+ - uses: actions/checkout@v7
155
+ - uses: actions/download-artifact@v8
156
+ with:
157
+ name: bindings-${{ matrix.target }}
158
+ path: node
159
+ # gnu binaries run on the host's Node directly; musl ones run in an Alpine
160
+ # container. arm64 targets use the native ubuntu-24.04-arm runner (no QEMU).
161
+ - name: Test (gnu, native)
162
+ if: ${{ !contains(matrix.target, 'musl') }}
163
+ uses: actions/setup-node@v6
164
+ with:
165
+ node-version: ${{ matrix.node }}
166
+ - name: Test (gnu, native)
167
+ if: ${{ !contains(matrix.target, 'musl') }}
168
+ run: node --test
169
+ - name: Test (musl, Alpine container)
170
+ if: ${{ contains(matrix.target, 'musl') }}
171
+ uses: addnab/docker-run-action@v3
172
+ with:
173
+ image: node:${{ matrix.node }}-alpine
174
+ options: -v ${{ github.workspace }}:/work -w /work/node
175
+ run: node --test
176
+
177
+ publish:
178
+ name: publish to npm
179
+ runs-on: ubuntu-latest
180
+ needs:
181
+ - test-macos-windows
182
+ - test-linux
183
+ if: ${{ startsWith(github.ref, 'refs/tags/v') }}
184
+ permissions:
185
+ contents: write # napi prepublish creates a GitHub release + uploads .node assets
186
+ id-token: write # npm provenance
187
+ env:
188
+ # job-level so the version guard, `npm whoami`, the root publish, and the
189
+ # per-platform publishes napi prepublish spawns all see the token.
190
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
191
+ steps:
192
+ - uses: actions/checkout@v7
193
+ - uses: actions/setup-node@v6
194
+ with:
195
+ node-version: 24
196
+ cache: npm
197
+ cache-dependency-path: node/package-lock.json
198
+ registry-url: https://registry.npmjs.org
199
+ - run: npm ci
200
+ - name: Verify tag matches package + optionalDependencies versions
201
+ run: |
202
+ PKG=$(node -p "require('./package.json').version")
203
+ if [ "$GITHUB_REF" != "refs/tags/v$PKG" ]; then
204
+ echo "::error::tag $GITHUB_REF does not match package.json v$PKG"; exit 1
205
+ fi
206
+ node -e "const p=require('./package.json');const bad=Object.entries(p.optionalDependencies).filter(([,v])=>v!==p.version);if(bad.length){console.error('optionalDependencies out of sync with '+p.version+':',bad);process.exit(1)}"
207
+ shell: bash
208
+ - name: Verify npm auth (must be an automation token)
209
+ run: npm whoami
210
+ - name: Recreate per-platform npm package dirs
211
+ run: npx napi create-npm-dirs
212
+ - uses: actions/download-artifact@v8
213
+ with:
214
+ path: node/artifacts
215
+ - name: Move .node files into npm/<platform>/
216
+ run: npm run artifacts # napi artifacts --output-dir artifacts
217
+ - name: Assert every platform binary is present (1 per target)
218
+ run: |
219
+ count=$(ls npm/*/${{ env.APP_NAME }}.*.node | wc -l)
220
+ echo "found $count platform binaries"
221
+ test "$count" -eq 8 || { echo "::error::expected 8 platform binaries, found $count"; exit 1; }
222
+ shell: bash
223
+ - name: List packages
224
+ run: ls -R npm
225
+ shell: bash
226
+ - name: Publish
227
+ # `npm publish` runs prepublishOnly (`napi prepublish -t npm`), which
228
+ # publishes each per-platform package + a GitHub release, then publishes
229
+ # the main package.
230
+ run: |
231
+ npm config set provenance true
232
+ npm publish --access public
233
+ env:
234
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,37 @@
1
+ name: Node
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ env:
10
+ CARGO_TERM_COLOR: always
11
+
12
+ defaults:
13
+ run:
14
+ working-directory: node
15
+
16
+ jobs:
17
+ test:
18
+ name: build + test (${{ matrix.os }})
19
+ runs-on: ${{ matrix.os }}
20
+ strategy:
21
+ fail-fast: false
22
+ matrix:
23
+ os: [ubuntu-latest, macos-latest, windows-latest]
24
+ steps:
25
+ - uses: actions/checkout@v7
26
+ - uses: actions/setup-node@v6
27
+ with:
28
+ node-version: 20
29
+ - uses: dtolnay/rust-toolchain@stable
30
+ - uses: Swatinem/rust-cache@v2
31
+ with:
32
+ workspaces: ". -> target"
33
+ # `napi build` compiles the addon and regenerates index.js / index.d.ts;
34
+ # `node --test` then loads the freshly built .node and runs the smoke tests.
35
+ - run: npm install
36
+ - run: npm run build
37
+ - run: npm test
@@ -0,0 +1,179 @@
1
+ name: Python release
2
+
3
+ # Build wheels + sdist for the `castle-token` Python package (PyO3 / maturin) and
4
+ # publish to PyPI via Trusted Publishing (OIDC — no stored token).
5
+ #
6
+ # `abi3-py39` means ONE wheel per platform/arch covers every CPython >= 3.9, so
7
+ # there is no per-Python-version matrix.
8
+ #
9
+ # Triggered by a `vX.Y.Z` tag (shared with the npm release — bump all package
10
+ # versions together). `workflow_dispatch` builds the wheels WITHOUT publishing.
11
+ #
12
+ # One-time PyPI setup (Trusted Publishing), at
13
+ # https://pypi.org/manage/account/publishing/ — add a "pending publisher":
14
+ # PyPI project name: castle-token
15
+ # Owner: 0x640480
16
+ # Repository: castle-rs
17
+ # Workflow name: python-release.yml
18
+ # Environment: pypi
19
+ # The wheel version comes from python/Cargo.toml `[package] version` (pyproject
20
+ # declares `dynamic = ["version"]`); keep it in sync with the tag.
21
+
22
+ on:
23
+ push:
24
+ tags:
25
+ - 'v*.*.*'
26
+ workflow_dispatch:
27
+
28
+ permissions:
29
+ contents: read
30
+
31
+ env:
32
+ MATURIN_ARGS: --release --out dist --manifest-path python/Cargo.toml
33
+
34
+ jobs:
35
+ linux:
36
+ name: wheel manylinux-${{ matrix.target }}
37
+ runs-on: ubuntu-latest
38
+ strategy:
39
+ fail-fast: false
40
+ matrix:
41
+ target: [x86_64, aarch64]
42
+ steps:
43
+ - uses: actions/checkout@v7
44
+ - uses: actions/setup-python@v6
45
+ with:
46
+ python-version: '3.x'
47
+ - name: Build wheel
48
+ uses: PyO3/maturin-action@v1
49
+ with:
50
+ target: ${{ matrix.target }}
51
+ args: ${{ env.MATURIN_ARGS }}
52
+ manylinux: auto
53
+ sccache: 'true'
54
+ - uses: actions/upload-artifact@v7
55
+ with:
56
+ name: wheels-manylinux-${{ matrix.target }}
57
+ path: dist
58
+
59
+ musllinux:
60
+ name: wheel musllinux-${{ matrix.target }}
61
+ runs-on: ubuntu-latest
62
+ strategy:
63
+ fail-fast: false
64
+ matrix:
65
+ target: [x86_64, aarch64]
66
+ steps:
67
+ - uses: actions/checkout@v7
68
+ - uses: actions/setup-python@v6
69
+ with:
70
+ python-version: '3.x'
71
+ - name: Build wheel
72
+ uses: PyO3/maturin-action@v1
73
+ with:
74
+ target: ${{ matrix.target }}
75
+ args: ${{ env.MATURIN_ARGS }}
76
+ manylinux: musllinux_1_2
77
+ sccache: 'true'
78
+ - uses: actions/upload-artifact@v7
79
+ with:
80
+ name: wheels-musllinux-${{ matrix.target }}
81
+ path: dist
82
+
83
+ macos:
84
+ name: wheel macos-${{ matrix.target }}
85
+ runs-on: ${{ matrix.runner }}
86
+ strategy:
87
+ fail-fast: false
88
+ matrix:
89
+ include:
90
+ - runner: macos-15-intel
91
+ target: x86_64
92
+ - runner: macos-latest
93
+ target: aarch64
94
+ steps:
95
+ - uses: actions/checkout@v7
96
+ - uses: actions/setup-python@v6
97
+ with:
98
+ python-version: '3.x'
99
+ - name: Build wheel
100
+ uses: PyO3/maturin-action@v1
101
+ with:
102
+ target: ${{ matrix.target }}
103
+ args: ${{ env.MATURIN_ARGS }}
104
+ sccache: 'true'
105
+ - uses: actions/upload-artifact@v7
106
+ with:
107
+ name: wheels-macos-${{ matrix.target }}
108
+ path: dist
109
+
110
+ windows:
111
+ name: wheel windows-x64
112
+ runs-on: windows-latest
113
+ steps:
114
+ - uses: actions/checkout@v7
115
+ - uses: actions/setup-python@v6
116
+ with:
117
+ python-version: '3.x'
118
+ architecture: x64
119
+ - name: Build wheel
120
+ uses: PyO3/maturin-action@v1
121
+ with:
122
+ target: x64
123
+ args: ${{ env.MATURIN_ARGS }}
124
+ sccache: 'true'
125
+ - uses: actions/upload-artifact@v7
126
+ with:
127
+ name: wheels-windows-x64
128
+ path: dist
129
+
130
+ sdist:
131
+ name: sdist
132
+ runs-on: ubuntu-latest
133
+ steps:
134
+ - uses: actions/checkout@v7
135
+ - name: Build sdist
136
+ uses: PyO3/maturin-action@v1
137
+ with:
138
+ command: sdist
139
+ args: --out dist --manifest-path python/Cargo.toml
140
+ - uses: actions/upload-artifact@v7
141
+ with:
142
+ name: wheels-sdist
143
+ path: dist
144
+
145
+ publish:
146
+ name: Publish to PyPI
147
+ runs-on: ubuntu-latest
148
+ needs: [linux, musllinux, macos, windows, sdist]
149
+ if: ${{ startsWith(github.ref, 'refs/tags/v') }}
150
+ environment:
151
+ name: pypi
152
+ url: https://pypi.org/p/castle-token
153
+ permissions:
154
+ id-token: write # OIDC for Trusted Publishing
155
+ attestations: write # PEP 740 attestations
156
+ contents: read
157
+ steps:
158
+ - uses: actions/checkout@v7
159
+ - name: Verify tag matches python/Cargo.toml version
160
+ # the wheel version is `dynamic` (maturin reads python/Cargo.toml); guard
161
+ # against a tag that disagrees, which would publish a stale version.
162
+ run: |
163
+ VER=$(python3 -c "import tomllib;print(tomllib.load(open('python/Cargo.toml','rb'))['package']['version'])")
164
+ if [ "$GITHUB_REF" != "refs/tags/v$VER" ]; then
165
+ echo "::error::tag $GITHUB_REF does not match python/Cargo.toml v$VER"; exit 1
166
+ fi
167
+ shell: bash
168
+ - uses: actions/download-artifact@v8
169
+ with:
170
+ # merge every wheels-* artifact into a single flat dist/ directory
171
+ pattern: wheels-*
172
+ path: dist
173
+ merge-multiple: true
174
+ - name: List distributions
175
+ run: ls -R dist
176
+ - name: Publish
177
+ uses: pypa/gh-action-pypi-publish@release/v1
178
+ with:
179
+ packages-dir: dist
@@ -0,0 +1,55 @@
1
+ name: Python
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ env:
10
+ CARGO_TERM_COLOR: always
11
+
12
+ jobs:
13
+ test:
14
+ name: build + pytest (${{ matrix.os }})
15
+ runs-on: ${{ matrix.os }}
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ os: [ubuntu-latest, macos-latest, windows-latest]
20
+ defaults:
21
+ run:
22
+ working-directory: python
23
+ steps:
24
+ - uses: actions/checkout@v7
25
+ - uses: actions/setup-python@v6
26
+ with:
27
+ python-version: "3.x"
28
+ - uses: dtolnay/rust-toolchain@stable
29
+ - uses: Swatinem/rust-cache@v2
30
+ with:
31
+ workspaces: ". -> target"
32
+ # `pip install .` drives the maturin build backend (builds + installs the
33
+ # abi3 wheel into the CI interpreter), then run the smoke tests.
34
+ - run: python -m pip install --upgrade pip
35
+ - run: pip install . pytest
36
+ - run: pytest tests -q
37
+
38
+ wheels:
39
+ name: build wheels (${{ matrix.os }})
40
+ runs-on: ${{ matrix.os }}
41
+ strategy:
42
+ fail-fast: false
43
+ matrix:
44
+ os: [ubuntu-latest, macos-latest, windows-latest]
45
+ steps:
46
+ - uses: actions/checkout@v7
47
+ - uses: PyO3/maturin-action@v1
48
+ with:
49
+ command: build
50
+ args: --release --out dist --manifest-path python/Cargo.toml
51
+ manylinux: auto
52
+ - uses: actions/upload-artifact@v7
53
+ with:
54
+ name: wheels-${{ matrix.os }}
55
+ path: dist
@@ -0,0 +1,27 @@
1
+ # Build artifacts
2
+ /target
3
+
4
+ # rustfmt backups
5
+ **/*.rs.bk
6
+ .env
7
+ .mcp.json
8
+
9
+ # Large browser captures the wire format was reverse-engineered from
10
+ *.har
11
+
12
+ # Reverse-engineering artifact (downloaded Castle bundle)
13
+ /bundle.js
14
+
15
+ # Python binding build artifacts
16
+ __pycache__/
17
+ *.pyc
18
+ .pytest_cache/
19
+ *.so
20
+ dist/
21
+ *.egg-info/
22
+ .venv/
23
+
24
+ # Node binding build artifacts (the per-platform .node is built, not committed;
25
+ # the generated index.js / index.d.ts loader + types ARE committed)
26
+ node_modules/
27
+ *.node