Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c333bbce4e | |||
| 6001c2e3b8 |
@@ -2,11 +2,15 @@ APP_NAME=Glastree
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:aWz7908H9c7s+it9uMTwb6pyUrpddyMclcuN9Kzv7Ao=
|
||||
APP_DEBUG=true
|
||||
APP_URL=
|
||||
APP_URL=https://glastree.soon.it
|
||||
APP_PROTOCOL=https
|
||||
FORCE_HTTPS=true
|
||||
TRUSTED_PROXIES=*
|
||||
|
||||
GOOGLE_CLIENT_ID=980774223097-o5h7a6kepvg69te34fof2otn7ibi9uha.apps.googleusercontent.com
|
||||
GOOGLE_CLIENT_SECRET=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
|
||||
|
||||
|
||||
APP_LOCALE=it
|
||||
APP_FALLBACK_LOCALE=it
|
||||
APP_FAKER_LOCALE=it_IT
|
||||
|
||||
@@ -46,6 +46,3 @@ MAIL_FROM_ADDRESS="hello@example.com"
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
|
||||
VITE_APP_NAME="${APP_NAME}"
|
||||
GOOGLE_CLIENT_ID=
|
||||
GOOGLE_CLIENT_SECRET=
|
||||
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
# Fix: tabella `google_o_auth_connections` mancante
|
||||
|
||||
## Problema
|
||||
|
||||
Migration `2026_06_15_000001_create_google_oauth_connections_table.php` segnata come "Ran" (batch 39) ma tabella fisica inesistente sul database MySQL/MariaDB. Causa 500 su GET `/impostazioni`.
|
||||
|
||||
## Comandi (eseguire sul server `192.168.222.177`)
|
||||
|
||||
```bash
|
||||
# 1. Creare la tabella mancante con la stessa definizione della migration
|
||||
php artisan tinker --execute="
|
||||
Schema::create('google_o_auth_connections', function (\Illuminate\Database\Schema\Blueprint \$table) {
|
||||
\$table->id();
|
||||
\$table->string('service', 20)->unique();
|
||||
\$table->string('client_id', 255);
|
||||
\$table->text('client_secret');
|
||||
\$table->text('refresh_token');
|
||||
\$table->timestamps();
|
||||
});
|
||||
"
|
||||
|
||||
# 2. Pulire la cache delle viste (stale compiled view)
|
||||
php artisan view:clear
|
||||
|
||||
# 3. Verificare che la tabella esista
|
||||
php artisan tinker --execute="echo Schema::hasTable('google_o_auth_connections') ? 'OK' : 'ERRORE';"
|
||||
```
|
||||
@@ -1,144 +0,0 @@
|
||||
# 🚀 Deploy & Aggiornamento — Glastree
|
||||
|
||||
## Generare il Pacchetto (Server di Sviluppo)
|
||||
|
||||
```bash
|
||||
cd /var/www/html/glastree
|
||||
|
||||
# Installa dipendenze PHP production (esclude dev)
|
||||
composer install --no-dev --optimize-autoloader
|
||||
|
||||
# Build asset Vite (se node_modules/ presente)
|
||||
npm install && npm run build
|
||||
|
||||
# Genera archivio
|
||||
bash build-dist.sh
|
||||
```
|
||||
|
||||
L'archivio `glastree-YYYYMMDD_HHMM.tar.gz` viene creato nella directory corrente.
|
||||
|
||||
---
|
||||
|
||||
## 🆕 Installazione Fresca (Nuovo Server)
|
||||
|
||||
```bash
|
||||
# 1. Estrai archivio
|
||||
tar xzf glastree-YYYYMMDD_HHMM.tar.gz
|
||||
cd glastree
|
||||
|
||||
# 2. Crea directory necessarie
|
||||
mkdir -p storage/framework/cache/data \
|
||||
storage/framework/sessions \
|
||||
storage/framework/views \
|
||||
storage/logs \
|
||||
bootstrap/cache \
|
||||
storage/app/public \
|
||||
storage/app/public/logos \
|
||||
storage/app/public/documenti/eventi \
|
||||
storage/app/backups \
|
||||
storage/app/documenti \
|
||||
storage/app/private/avatars/gruppi
|
||||
|
||||
# 3. Permessi
|
||||
chmod -R 775 storage bootstrap/cache
|
||||
chown -R www-data:www-data storage bootstrap/cache
|
||||
|
||||
# 4. Crea .gitignore in storage/app/public (serve a Laravel)
|
||||
echo "*" > storage/app/public/.gitignore
|
||||
echo "!.gitignore" >> storage/app/public/.gitignore
|
||||
|
||||
# 5. Configura ambiente
|
||||
cp .env.example .env
|
||||
# Modifica manualmente: DB, APP_URL, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET
|
||||
php artisan key:generate
|
||||
|
||||
# 6. Pulisci cache e ricrea symlink
|
||||
rm -f public/storage
|
||||
ln -sf ../storage/app/public public/storage
|
||||
php artisan config:clear
|
||||
php artisan route:clear
|
||||
php artisan view:clear
|
||||
|
||||
# 7. Avvia installazione DB
|
||||
php install.php
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Aggiornamento (Server Esistente)
|
||||
|
||||
```bash
|
||||
# 1. BACKUP
|
||||
cp .env .env.backup.$(date +%Y%m%d_%H%M%S)
|
||||
mysqldump -u USER -p DBNAME > backup_$(date +%Y%m%d_%H%M%S).sql
|
||||
|
||||
# 2. Estrai archivio
|
||||
tar xzf glastree-YYYYMMDD_HHMM.tar.gz
|
||||
|
||||
# 3. Ripristina .env
|
||||
cp .env.backup.* .env
|
||||
|
||||
# 4. Aggiungi nuove variabili d'ambiente
|
||||
echo "GOOGLE_CLIENT_ID=" >> .env
|
||||
echo "GOOGLE_CLIENT_SECRET=" >> .env
|
||||
|
||||
# 5. Permessi
|
||||
chmod -R 775 storage bootstrap/cache
|
||||
chown -R www-data:www-data storage bootstrap/cache
|
||||
|
||||
# 6. Symlink storage
|
||||
rm -f public/storage
|
||||
ln -sf ../storage/app/public public/storage
|
||||
|
||||
# 7. Migration
|
||||
php artisan migrate --force
|
||||
|
||||
# 8. Pulisci cache
|
||||
php artisan config:clear
|
||||
php artisan route:clear
|
||||
php artisan view:clear
|
||||
|
||||
# 9. Asset Vite
|
||||
npm install && npm run build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 Contenuto dell'Archivio
|
||||
|
||||
| Include | Esclude |
|
||||
|---------|---------|
|
||||
| Sorgenti PHP (`app/`, `config/`, `routes/`, `resources/`) | `.git/`, `node_modules/`, `tests/` |
|
||||
| Vendor production | `.env`, `.env.example` |
|
||||
| Asset Vite compilati (`public/build/`) | `storage/app/public/`, `storage/app/private/` |
|
||||
| Migration e seeder | `storage/framework/cache/*`, `sessions/*`, `views/*` |
|
||||
| | `storage/logs/*`, `storage/debugbar/*` |
|
||||
| | `storage/app/backups/`, `storage/app/documenti/` |
|
||||
| | `MEMORY.md`, `AGENTS.md`, `build-dist.sh`, Docker files |
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Variabili d'Ambiente Richieste
|
||||
|
||||
```env
|
||||
APP_URL=https://tuodominio.it
|
||||
APP_SUBFOLDER=/app
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=glastree
|
||||
DB_USERNAME=glastree
|
||||
DB_PASSWORD=...
|
||||
|
||||
GOOGLE_CLIENT_ID=....
|
||||
GOOGLE_CLIENT_SECRET=....
|
||||
```
|
||||
|
||||
## 🌐 Google OAuth 2.0 — Post-Deploy
|
||||
|
||||
1. [Google Cloud Console](https://console.cloud.google.com/) → Abilita Gmail API, Drive API, Calendar API
|
||||
2. Credenziali → OAuth Client ID → Web Application
|
||||
3. Redirect URI: `https://tuodominio.it/app/auth/google/callback`
|
||||
4. Inserisci Client ID/Secret in `.env`
|
||||
5. **Impostazioni → Google Services** → Connetti Gmail, Drive, Calendar
|
||||
6. Per Gmail: **Impostazioni → Email → IMAP** → seleziona "OAuth 2.0"
|
||||
@@ -291,11 +291,8 @@ if (!empty($contatto['individuo_id'])) { create }
|
||||
```
|
||||
|
||||
## Prossimi Passi
|
||||
- [DONE] ... (existing items)
|
||||
- Verificare end-to-end su remote: tutte le nuove mass action, mailing list con contatti senza email, ricerca multi-tag
|
||||
- Test end-to-end OAuth con credenziali Google reali (configurare Google Cloud Console, registrare callback URI, ottenere refresh token)
|
||||
- Verificare EmailSetting::isOauth() integration in email sync flow
|
||||
- Verificare StorageRepositoryService::buildGoogleDrive() OAuth fallback con repos esistenti
|
||||
- Verificare GoogleCalendarSyncService::buildClient() OAuth fallback con connessioni esistenti
|
||||
- [DONE] Fix performance: spostata query `VistaReport::where(...)->get()` da `@php` nel partial `table-settings.blade.php` a tutti i 5 controller (prima veniva eseguita 1 query per ogni pagina load per ogni entity, anche senza mai aprire la modale)
|
||||
- [DONE] Rimosse vecchie modal legacy (`#saveVistaModal`, `#colonneModal`, `#vistaListModal`) da `individui` e `gruppi` — duplicate rispetto al nuovo modal unificato
|
||||
- [DONE] Rimosse vecchie funzioni JS (`saveVista()`, `toggleColumn()`, `showSaveVistaModal()`) da `individui` e `gruppi`
|
||||
@@ -383,102 +380,3 @@ if (!empty($contatto['individuo_id'])) { create }
|
||||
**Fix**:
|
||||
1. `VistaReportController@update` (linea 101-103): aggiunto `if ($request->expectsJson()) { return response()->json([...]); }` — così il fetch riceve JSON 200, non un redirect 302.
|
||||
2. Fetch headers in `table-settings.blade.php`: aggiunto `'Accept': 'application/json'` — necessario perché `expectsJson()` controlla l'header `Accept`, non `Content-Type`.
|
||||
|
||||
## 2026-06-15 — Centralized Google OAuth 2.0 System (Gmail, Drive, Calendar)
|
||||
|
||||
**Obiettivo**: Implementare autenticazione OAuth 2.0 centralizzata per Gmail (IMAP/SMTP), Google Drive e Google Calendar come alternativa opzionale all'auth con password, con revoca per-servizio.
|
||||
|
||||
### Files Creati
|
||||
- **Enum** `app/Enums/GoogleService.php` — 3 casi (Gmail, Drive, Calendar) con scope/label/icon/hexColor
|
||||
- **Migration 1** `2026_06_15_000001_create_google_oauth_connections_table.php` — tabella google_oauth_connections
|
||||
- **Migration 2** `2026_06_15_000002_add_auth_method_to_email_settings_table.php` — auth_method a email_settings
|
||||
- **Model** `app/Models/GoogleOAuthConnection.php` — encrypted field accessor/mutator
|
||||
- **Service** `app/Services/GoogleOAuthService.php` — full OAuth flow methods
|
||||
- **Controller** `app/Http/Controllers/GoogleOAuthController.php` — connect/callback/revoke/status
|
||||
- **Routes** in `routes/web.php` — 4 nuove route
|
||||
- **View** `resources/views/google-oauth/status.blade.php`
|
||||
|
||||
### Problemi Risolti
|
||||
1. Filesystem permission: directory 755 (www-data). Script PHP via Apache da storage/app/public/
|
||||
2. routes/web.php root:root 644 -> rename trick
|
||||
3. authorize() method conflict -> rinominato in connect()
|
||||
|
||||
### Architettura
|
||||
- Fallback pattern: Drive/Calendar provano OAuth centralizzata, poi config esistente
|
||||
- Per-service revoca: record separato per servizio (unique su service)
|
||||
- Single callback URI: /auth/google/callback, routing via state
|
||||
- Token encryption: AES-256-CBC + APP_KEY
|
||||
|
||||
### Completato
|
||||
1. ✅ **EmailSetting model** (`app/Models/EmailSetting.php`): `auth_method` in ``, `isOauth()` method, `getOAuthAccessToken()` via `GoogleOAuthService`, `getDecryptedPassword()` returns OAuth token when isOauth, `getDecryptedSmtpPassword()` same, `getImapClient()` returns null for OAuth, `testConnection()` has OAuth path via Webklex\PHPIMAP
|
||||
2. ✅ **EmailController** (`app/Http/Controllers/EmailController.php`): `syncEmails()` redirects to `syncEmailsViaOAuth()`, `connectImap()` redirects to `connectOAuthImap()`, `sendViaImap()` appends `auth_mode=xoauth2` to DSN, added `processWebklexMessage()` helper
|
||||
3. ✅ **StorageRepositoryService** (`app/Services/StorageRepositoryService.php`): `buildGoogleDrive()` tries `GoogleOAuthService::buildClient(GoogleService::Drive)` first, falls back to config. Same for `readGoogleDriveFile()` and `checkGoogleDriveApiStatus()`
|
||||
4. ✅ **GoogleCalendarSyncService** (`app/Services/GoogleCalendarSyncService.php`): `buildClient()` tries `GoogleOAuthService::buildClient(GoogleService::Calendar)` first, falls back to config
|
||||
5. ✅ **Tab Google Services** in `resources/views/impostazioni/index.blade.php` — nav tab + tab-pane with Connect/Revoke per service (Gmail, Drive, Calendar), status badges, alert linking to email tab. Added `auth_method` select in email IMAP tab
|
||||
6. ⏳ **Test end-to-end** — requires user to configure Google Cloud Console (OAuth consent screen, callback URI) and provide credentials
|
||||
|
||||
### Files Modified
|
||||
- `app/Models/EmailSetting.php` — OAuth-aware auth_method, decrypt overrides, IMAP client
|
||||
- `app/Http/Controllers/EmailController.php` — OAuth sync/send/connect paths
|
||||
- `app/Services/StorageRepositoryService.php` — Drive OAuth fallback
|
||||
- `app/Services/GoogleCalendarSyncService.php` — Calendar OAuth fallback
|
||||
- `resources/views/impostazioni/index.blade.php` — Google Services tab + auth_method select
|
||||
|
||||
### Bug Fix
|
||||
- **2026-06-15 — Variable interpolation in str_replace**: In `apply_all_mods.php`, the second argument to `str_replace()` used double quotes, causing PHP to interpolate $fileId, $service, $googleMimeType, $originalBasename as empty strings. Result: method signature `exportGoogleDriveDoc` lost all parameter variable names. Fixed by running a second script that used `preg_replace` to restore the signature. (file -> app/Services/StorageRepositoryService.php)
|
||||
|
||||
|
||||
### Pre-Production Review Fixes
|
||||
|
||||
**2026-06-15 — 4 criticità risolte prima del deploy**
|
||||
|
||||
| # | Problema | File | Fix |
|
||||
|---|----------|------|-----|
|
||||
| 1 | Credenziali Google vuote | `GoogleOAuthService.php:createClient()` | Sostituito `setAuthConfig([client_id:'']` con `setClientId(config(...))`, `setClientSecret(config(...))`, `setRedirectUri(...)`. Rimossi 4 import inutilizzati |
|
||||
| 2 | Route name errato | `google-oauth/status.blade.php:55` | `google.oauth.connect` → `google.oauth.authorize` |
|
||||
| 3 | Metodo inesistente `description()` | `google-oauth/status.blade.php:43` | Sostituito con `label() . ' - ' . scope()`. Layout cambiato da `layouts.app` a `layouts.adminlte` |
|
||||
| 4 | `auth_method` select mancante | `impostazioni/index.blade.php` | Inserito `<select name="auth_method">` all'inizio del card-body in `#email-imap` |
|
||||
| — | `GOOGLE_CLIENT_ID`/`GOOGLE_CLIENT_SECRET` mancanti | `config/services.php`, `.env.example` | Aggiunte sezione google in services.php con `env()`, variabili a `.env.example` |
|
||||
| — | Istruzioni aggiornamento mancanti | `build-dist.sh` | Aggiunta sezione "AGGIORNAMENTO (SERVER ESISTENTE)" con backup, migrate, env vars |
|
||||
|
||||
### Files Review Round
|
||||
- `app/Services/GoogleOAuthService.php` — createClient() legge da config, import puliti
|
||||
- `resources/views/google-oauth/status.blade.php` — route, description, layout fix
|
||||
- `resources/views/impostazioni/index.blade.php` — auth_method select
|
||||
- `config/services.php` — sezione google
|
||||
- `.env.example` — GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET
|
||||
- `build-dist.sh` — update instructions
|
||||
|
||||
|
||||
### 2026-06-15 — Cleanup: file inutilizzati, codice morto e import superflui
|
||||
|
||||
**File eliminati (7 backup .bak):**
|
||||
- `MEMORY.md.bak`, `EmailController.php.bak`, `web.php.bak`, `web.php.bak2`
|
||||
- `index.blade.php.bak` (141 KB), `build-dist.sh.bak`, `.env.example.bak`
|
||||
- Directory vuota `tests/Feature/Auth/`
|
||||
|
||||
**Metodi morti rimossi (3):**
|
||||
| Metodo | File | Motivo |
|
||||
|--------|------|--------|
|
||||
| `create()` | `DocumentoController.php` | Nessuna route registrata, view inesistente |
|
||||
| `index()` | `StorageRepositoryController.php` | Nessuna route GET, view inesistente |
|
||||
| `downloadMigrationScript()` | `BackupController.php` | Nessuna route, view inesistente |
|
||||
|
||||
**Import superflui rimossi (20):**
|
||||
- `EmailController.php`: `GoogleService`, `GoogleOAuthService`, `Crypt` (non usati direttamente, logica passa da `EmailSetting` model)
|
||||
- `BackupController.php`: `JsonResponse` (usato dal metodo rimosso)
|
||||
- `StorageRepositoryController.php`: `View` (usato dal metodo rimosso)
|
||||
- `GruppoMembroController.php`: `Individuo`, `Ruolo`
|
||||
- `HomeController.php`: `Notifica`
|
||||
- `ImpostazioniController.php`: `Crypt`
|
||||
- `AuthController.php`: `EmailSetting`, `Address`
|
||||
- `IndividuoController.php`: `Contatto`
|
||||
- `AppSetting.php`: `File`
|
||||
- `EmailAttachment.php`: `Storage`
|
||||
- `Evento.php`: `HasMany`
|
||||
- `ExportHelpPdf.php`: `Storage`
|
||||
- `BackupService.php`: `Notifica`, `Crypt`, `Storage`
|
||||
- `AuthServiceProvider.php`: `Route`
|
||||
|
||||
**Verifica:** Tutti i 14 file modificati passano `php -l`
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# Proxy Configuration — Glastree
|
||||
|
||||
## Nginx Proxy Manager (Custom Nginx Configuration)
|
||||
|
||||
Nella scheda **Advanced** del tuo proxy host:
|
||||
|
||||
```nginx
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header X-Forwarded-Port $server_port;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `.env` (App Laravel)
|
||||
|
||||
```env
|
||||
APP_URL=https://glastree.soon.it
|
||||
APP_PROTOCOL=https
|
||||
FORCE_HTTPS=true
|
||||
TRUSTED_PROXIES=*
|
||||
```
|
||||
|
||||
Dopo qualsiasi modifica:
|
||||
|
||||
```bash
|
||||
php artisan config:clear
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Google OAuth — Authorized Redirect URIs
|
||||
|
||||
```
|
||||
https://glastree.soon.it/auth/google/callback
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `bootstrap/app.php`
|
||||
|
||||
```php
|
||||
$middleware->trustProxies(at: '*');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Schema richieste
|
||||
|
||||
```
|
||||
Cliente (HTTPS)
|
||||
↓
|
||||
Nginx Proxy Manager (termina TLS, inoltra HTTP + X-Forwarded-Proto: https)
|
||||
↓
|
||||
App Laravel (vede richieste come HTTPS grazie a trustProxies(at:"*"))
|
||||
```
|
||||
@@ -7,6 +7,7 @@ namespace App\Console\Commands;
|
||||
use App\Models\AppSetting;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class ExportHelpPdf extends Command
|
||||
{
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum GoogleService: string
|
||||
{
|
||||
case Gmail = 'gmail';
|
||||
case Drive = 'drive';
|
||||
case Calendar = 'calendar';
|
||||
|
||||
public function scope(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Gmail => 'https://mail.google.com/',
|
||||
self::Drive => 'https://www.googleapis.com/auth/drive',
|
||||
self::Calendar => 'https://www.googleapis.com/auth/calendar',
|
||||
};
|
||||
}
|
||||
|
||||
public function label(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Gmail => 'Gmail (lettura e invio email)',
|
||||
self::Drive => 'Google Drive (file)',
|
||||
self::Calendar => 'Google Calendar (eventi)',
|
||||
};
|
||||
}
|
||||
|
||||
public function icon(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Gmail => 'fa-google',
|
||||
self::Drive => 'fa-google-drive',
|
||||
self::Calendar => 'fa-calendar-alt',
|
||||
};
|
||||
}
|
||||
|
||||
public function hexColor(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Gmail => '#EA4335',
|
||||
self::Drive => '#34A853',
|
||||
self::Calendar => '#4285F4',
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ namespace App\Http\Controllers\Admin;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\AppSetting;
|
||||
use App\Services\BackupService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
@@ -108,4 +109,10 @@ class BackupController extends Controller
|
||||
->with('success', 'Configurazione backup automatico salvata.');
|
||||
}
|
||||
|
||||
public function downloadMigrationScript(): JsonResponse
|
||||
{
|
||||
$script = view('admin.backup.migration-script')->render();
|
||||
|
||||
return response()->json(['script' => $script]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,14 @@ namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\ActivityLog;
|
||||
use App\Models\EmailSetting;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Symfony\Component\Mime\Address;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
|
||||
@@ -134,6 +134,16 @@ class DocumentoController extends Controller
|
||||
));
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
$this->authorizeWrite('documenti');
|
||||
$individui = Individuo::orderBy('cognome')->orderBy('nome')->get();
|
||||
$gruppi = Gruppo::orderBy('nome')->get();
|
||||
$eventi = Evento::orderBy('nome_evento')->get();
|
||||
$tipologie = TipologiaDocumento::attive();
|
||||
return view('documenti.create', compact('individui', 'gruppi', 'eventi', 'tipologie'));
|
||||
}
|
||||
|
||||
public function edit($documento)
|
||||
{
|
||||
$this->authorizeWrite('documenti');
|
||||
|
||||
@@ -12,6 +12,7 @@ use App\Models\Gruppo;
|
||||
use App\Models\Individuo;
|
||||
use App\Models\Documento;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
@@ -401,10 +402,6 @@ class EmailController extends Controller
|
||||
|
||||
$this->ensureFoldersExist();
|
||||
|
||||
if ($settings->isOauth()) {
|
||||
return $this->syncEmailsViaOAuth($settings);
|
||||
}
|
||||
|
||||
$mailbox = $this->connectImap($settings);
|
||||
|
||||
\Illuminate\Support\Facades\Log::info('IMAP connection established', ['host' => $settings->imap_host]);
|
||||
@@ -526,10 +523,6 @@ class EmailController extends Controller
|
||||
$encryption
|
||||
);
|
||||
|
||||
if ($settings->isOauth()) {
|
||||
$dsn .= '&auth_mode=xoauth2';
|
||||
}
|
||||
|
||||
try {
|
||||
$transport = \Symfony\Component\Mailer\Transport::fromDsn($dsn);
|
||||
$mailer = new \Symfony\Component\Mailer\Mailer($transport);
|
||||
@@ -650,10 +643,6 @@ class EmailController extends Controller
|
||||
throw new \Exception('Configurazione IMAP non valida');
|
||||
}
|
||||
|
||||
if ($settings->isOauth()) {
|
||||
return $this->connectOAuthImap($settings);
|
||||
}
|
||||
|
||||
$encryption = match ($settings->imap_encryption) {
|
||||
'ssl' => 'ssl',
|
||||
'tls' => 'tls',
|
||||
@@ -670,27 +659,6 @@ class EmailController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
private function connectOAuthImap($settings): \Webklex\PHPIMAP\Client
|
||||
{
|
||||
$token = $settings->getOAuthAccessToken();
|
||||
if (!$token) {
|
||||
throw new \Exception('Impossibile ottenere il token OAuth per IMAP');
|
||||
}
|
||||
|
||||
$client = new \Webklex\PHPIMAP\Client([
|
||||
'host' => $settings->imap_host,
|
||||
'port' => $settings->imap_port ?? 993,
|
||||
'encryption' => $settings->imap_encryption ?? 'ssl',
|
||||
'validate_cert' => false,
|
||||
'username' => $settings->imap_username,
|
||||
'password' => $token,
|
||||
'authentication' => 'oauth',
|
||||
]);
|
||||
$client->connect();
|
||||
|
||||
return $client;
|
||||
}
|
||||
|
||||
private function processImapMessage($imapMessage, $imapFolder)
|
||||
{
|
||||
$folderType = match ($imapFolder) {
|
||||
@@ -749,133 +717,6 @@ class EmailController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private function syncEmailsViaOAuth($settings): bool
|
||||
{
|
||||
$this->ensureFoldersExist();
|
||||
|
||||
$client = $this->connectOAuthImap($settings);
|
||||
|
||||
$folderMappings = [
|
||||
'INBOX' => 'inbox',
|
||||
'Sent' => 'sent',
|
||||
'[Gmail]/Sent Mail' => 'sent',
|
||||
'Sent Mail' => 'sent',
|
||||
'Drafts' => 'drafts',
|
||||
'[Gmail]/Drafts' => 'drafts',
|
||||
'Trash' => 'trash',
|
||||
'[Gmail]/Trash' => 'trash',
|
||||
];
|
||||
|
||||
$totalNew = 0;
|
||||
|
||||
foreach (array_keys($folderMappings) as $imapFolderName) {
|
||||
try {
|
||||
$folder = $client->getFolder($imapFolderName);
|
||||
if (!$folder) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$messages = $folder->messages()
|
||||
->setFetchFlags(true)
|
||||
->setFetchBody(true)
|
||||
->limit(100)
|
||||
->get();
|
||||
|
||||
foreach ($messages as $imapMessage) {
|
||||
$messageId = $imapMessage->getMessageId() ?? uniqid('msg_');
|
||||
$existing = EmailMessage::where('message_id', $messageId)->first();
|
||||
if ($existing) {
|
||||
continue;
|
||||
}
|
||||
$this->processWebklexMessage($imapMessage, $imapFolderName);
|
||||
$totalNew++;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
\Illuminate\Support\Facades\Log::error('Error processing OAuth IMAP folder', ['folder' => $imapFolderName, 'error' => $e->getMessage()]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$client->disconnect();
|
||||
\Illuminate\Support\Facades\Log::info('OAuth email sync completed', ['new' => $totalNew]);
|
||||
return true;
|
||||
}
|
||||
|
||||
private function processWebklexMessage($imapMessage, $imapFolder)
|
||||
{
|
||||
$folderType = match ($imapFolder) {
|
||||
'INBOX', 'inbox' => 'inbox',
|
||||
'Sent', 'sent', '[Gmail]/Sent Mail' => 'sent',
|
||||
'Drafts', 'drafts', '[Gmail]/Drafts' => 'drafts',
|
||||
'Trash', 'trash', '[Gmail]/Trash' => 'trash',
|
||||
'Archive', 'archive', '[Gmail]/All Mail' => 'archive',
|
||||
'Starred', 'starred', '[Gmail]/Starred' => 'starred',
|
||||
default => 'inbox',
|
||||
};
|
||||
|
||||
$folder = EmailFolder::where('type', $folderType)->first();
|
||||
if (!$folder) return;
|
||||
|
||||
$messageId = $imapMessage->getMessageId() ?? uniqid('msg_');
|
||||
$existing = EmailMessage::where('message_id', $messageId)->first();
|
||||
if ($existing) return;
|
||||
|
||||
$from = $imapMessage->getFrom();
|
||||
$to = $imapMessage->getTo();
|
||||
|
||||
$fromName = '';
|
||||
$fromEmail = '';
|
||||
if ($from && $from->first()) {
|
||||
$fromName = $from->first()->personal ?? '';
|
||||
$fromEmail = ($from->first()->mailbox ?? '') . '@' . ($from->first()->host ?? '');
|
||||
}
|
||||
|
||||
$toEmail = '';
|
||||
if ($to && $to->first()) {
|
||||
$toEmail = ($to->first()->mailbox ?? '') . '@' . ($to->first()->host ?? '');
|
||||
}
|
||||
|
||||
$message = EmailMessage::create([
|
||||
'email_folder_id' => $folder->id,
|
||||
'message_id' => $messageId,
|
||||
'subject' => mb_substr($imapMessage->getSubject() ?? '(senza oggetto)', 0, 255),
|
||||
'from_name' => mb_substr($fromName, 0, 255),
|
||||
'from_email' => mb_substr($fromEmail, 0, 255),
|
||||
'to_email' => mb_substr($toEmail, 0, 255),
|
||||
'body_text' => $imapMessage->getTextBody() ?? '',
|
||||
'body_html' => $imapMessage->getHTMLBody() ?? '',
|
||||
'is_read' => !($imapMessage->getFlags()['UNSEEN'] ?? false),
|
||||
'is_starred' => !empty($imapMessage->getFlags()['FLAGGED']),
|
||||
'is_sent' => $folderType === 'sent',
|
||||
'received_at' => $imapMessage->getDate() ?? now(),
|
||||
'imap_uid' => $imapMessage->getUid() ?? null,
|
||||
]);
|
||||
|
||||
$attachments = $imapMessage->getAttachments();
|
||||
if ($attachments && count($attachments) > 0) {
|
||||
foreach ($attachments as $attachment) {
|
||||
try {
|
||||
$filename = $attachment->getName() ?? 'attachment';
|
||||
$contents = $attachment->getContent();
|
||||
$path = 'email-attachments/' . \Illuminate\Support\Str::uuid() . '_' . $filename;
|
||||
\Illuminate\Support\Facades\Storage::put($path, $contents);
|
||||
|
||||
EmailAttachment::create([
|
||||
'email_message_id' => $message->id,
|
||||
'filename' => $filename,
|
||||
'mime_type' => $attachment->getMimeType() ?? 'application/octet-stream',
|
||||
'size' => strlen($contents),
|
||||
'file_path' => $path,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
\Illuminate\Support\Facades\Log::error('Error saving OAuth attachment', ['error' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function ensureFoldersExist()
|
||||
{
|
||||
$systemFolders = EmailFolder::getSystemFolders();
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Enums\GoogleService;
|
||||
use App\Services\GoogleOAuthService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class GoogleOAuthController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly GoogleOAuthService $oauthService,
|
||||
) {}
|
||||
|
||||
public function connect(GoogleService $service): RedirectResponse
|
||||
{
|
||||
$url = $this->oauthService->getAuthorizationUrl($service);
|
||||
return redirect()->away($url);
|
||||
}
|
||||
|
||||
public function callback(Request $request): RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'code' => 'required|string',
|
||||
'state' => 'required|string|in:' . implode(',', array_column(GoogleService::cases(), 'value')),
|
||||
]);
|
||||
|
||||
$service = GoogleService::from($request->state);
|
||||
|
||||
try {
|
||||
$this->oauthService->handleCallback($request->code, $service);
|
||||
return redirect()->route('impostazioni.index', ['#google-services'])
|
||||
->with('success', "Google {$service->label()} connected successfully.");
|
||||
} catch (\Exception $e) {
|
||||
return redirect()->route('impostazioni.index', ['#google-services'])
|
||||
->with('error', 'Google OAuth error: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function revoke(GoogleService $service): RedirectResponse
|
||||
{
|
||||
try {
|
||||
$this->oauthService->revoke($service);
|
||||
return redirect()->route('impostazioni.index', ['#google-services'])
|
||||
->with('success', "Google {$service->label()} revoked successfully.");
|
||||
} catch (\Exception $e) {
|
||||
return redirect()->route('impostazioni.index', ['#google-services'])
|
||||
->with('error', 'Revocation error: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function status(): View
|
||||
{
|
||||
$services = [];
|
||||
foreach (GoogleService::cases() as $service) {
|
||||
$services[] = [
|
||||
'service' => $service,
|
||||
'authorized' => $this->oauthService->isAuthorized($service),
|
||||
];
|
||||
}
|
||||
|
||||
return view('google-oauth.status', ['services' => $services]);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Gruppo;
|
||||
use App\Models\Individuo;
|
||||
use App\Models\Ruolo;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class GruppoMembroController extends Controller
|
||||
|
||||
@@ -10,6 +10,7 @@ use App\Models\Gruppo;
|
||||
use App\Models\Individuo;
|
||||
use App\Models\EmailMessage;
|
||||
use App\Models\MailingList;
|
||||
use App\Models\Notifica;
|
||||
use App\Services\BackupService;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ use App\Models\TipologiaDocumento;
|
||||
use App\Models\TipologiaEvento;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Individuo;
|
||||
use App\Models\Contatto;
|
||||
use App\Models\Documento;
|
||||
use App\Models\Gruppo;
|
||||
use App\Models\Comune;
|
||||
|
||||
@@ -10,6 +10,7 @@ use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\View\View;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
|
||||
class StorageRepositoryController extends Controller
|
||||
@@ -18,7 +19,20 @@ class StorageRepositoryController extends Controller
|
||||
private readonly StorageRepositoryService $repoService
|
||||
) {}
|
||||
|
||||
public function store(Request $request): RedirectResponse
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorizeWrite('settings');
|
||||
|
||||
$repositories = StorageRepository::orderBy('ordine')->get();
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json($repositories);
|
||||
}
|
||||
|
||||
return view('storage-repositories.index', compact('repositories'));
|
||||
}
|
||||
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$this->authorizeWrite('settings');
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class EmailAttachment extends Model
|
||||
{
|
||||
|
||||
@@ -4,8 +4,6 @@ namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use App\Enums\GoogleService;
|
||||
use App\Services\GoogleOAuthService;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
|
||||
class EmailSetting extends Model
|
||||
@@ -16,7 +14,7 @@ class EmailSetting extends Model
|
||||
'imap_host', 'imap_port', 'imap_encryption', 'imap_username', 'imap_password',
|
||||
'smtp_host', 'smtp_port', 'smtp_encryption', 'smtp_username', 'smtp_password',
|
||||
'email_address', 'email_name', 'reply_to', 'sync_interval_minutes',
|
||||
'last_sync_at', 'is_active', 'signature', 'signature_enabled', 'auth_method'
|
||||
'last_sync_at', 'is_active', 'signature', 'signature_enabled'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
@@ -43,9 +41,6 @@ class EmailSetting extends Model
|
||||
|
||||
public function getDecryptedPassword(): string
|
||||
{
|
||||
if ($this->isOauth()) {
|
||||
return $this->getOAuthAccessToken() ?? '';
|
||||
}
|
||||
if (empty($this->imap_password)) {
|
||||
return '';
|
||||
}
|
||||
@@ -58,9 +53,6 @@ class EmailSetting extends Model
|
||||
|
||||
public function getDecryptedSmtpPassword(): string
|
||||
{
|
||||
if ($this->isOauth()) {
|
||||
return $this->getOAuthAccessToken() ?? '';
|
||||
}
|
||||
if (empty($this->smtp_password)) {
|
||||
return $this->getDecryptedPassword();
|
||||
}
|
||||
@@ -71,26 +63,6 @@ class EmailSetting extends Model
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function isOauth(): bool
|
||||
{
|
||||
return $this->auth_method === 'oauth';
|
||||
}
|
||||
|
||||
public function getOAuthAccessToken(): ?string
|
||||
{
|
||||
if (!$this->isOauth()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
$oauth = app(GoogleOAuthService::class);
|
||||
return $oauth->getAccessToken(GoogleService::Gmail);
|
||||
} catch (\Exception $e) {
|
||||
\Illuminate\Support\Facades\Log::error('OAuth token refresh failed: ' . $e->getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSmtpConfig(): array
|
||||
{
|
||||
return [
|
||||
@@ -108,10 +80,6 @@ class EmailSetting extends Model
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->isOauth()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
$encryption = match ($this->imap_encryption) {
|
||||
'ssl' => 'ssl',
|
||||
@@ -135,10 +103,6 @@ class EmailSetting extends Model
|
||||
public function testConnection(): array
|
||||
{
|
||||
try {
|
||||
if ($this->isOauth()) {
|
||||
return $this->testOAuthImapConnection();
|
||||
}
|
||||
|
||||
$mailbox = $this->getImapClient();
|
||||
|
||||
if (!$mailbox) {
|
||||
@@ -161,32 +125,6 @@ class EmailSetting extends Model
|
||||
}
|
||||
}
|
||||
|
||||
private function testOAuthImapConnection(): array
|
||||
{
|
||||
try {
|
||||
$token = $this->getOAuthAccessToken();
|
||||
if (!$token) {
|
||||
return ['success' => false, 'message' => 'Impossibile ottenere il token OAuth. Verifica la connessione Google.'];
|
||||
}
|
||||
|
||||
$client = new \Webklex\PHPIMAP\Client([
|
||||
'host' => $this->imap_host,
|
||||
'port' => $this->imap_port ?? 993,
|
||||
'encryption' => $this->imap_encryption ?? 'ssl',
|
||||
'validate_cert' => false,
|
||||
'username' => $this->imap_username,
|
||||
'password' => $token,
|
||||
'authentication' => 'oauth',
|
||||
]);
|
||||
$client->connect();
|
||||
$client->disconnect();
|
||||
|
||||
return ['success' => true, 'message' => 'Connessione IMAP OAuth riuscita! Server: ' . $this->imap_host];
|
||||
} catch (\Exception $e) {
|
||||
return ['success' => false, 'message' => 'Errore connessione IMAP OAuth: ' . $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
public static function getActive()
|
||||
{
|
||||
return self::where('is_active', true)->first();
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Traits\HasTagsLight;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class Evento extends Model
|
||||
{
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\GoogleService;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
|
||||
class GoogleOAuthConnection extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'service',
|
||||
'client_id',
|
||||
'client_secret',
|
||||
'refresh_token',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'service' => GoogleService::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function getClientSecretAttribute(?string $value): ?string
|
||||
{
|
||||
return $value ? Crypt::decryptString($value) : null;
|
||||
}
|
||||
|
||||
public function setClientSecretAttribute(?string $value): void
|
||||
{
|
||||
$this->attributes['client_secret'] = $value ? Crypt::encryptString($value) : null;
|
||||
}
|
||||
|
||||
public function getRefreshTokenAttribute(?string $value): ?string
|
||||
{
|
||||
return $value ? Crypt::decryptString($value) : null;
|
||||
}
|
||||
|
||||
public function setRefreshTokenAttribute(?string $value): void
|
||||
{
|
||||
$this->attributes['refresh_token'] = $value ? Crypt::encryptString($value) : null;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace App\Providers;
|
||||
|
||||
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
|
||||
class AuthServiceProvider extends ServiceProvider
|
||||
|
||||
@@ -5,8 +5,11 @@ declare(strict_types=1);
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\AppSetting;
|
||||
use App\Models\Notifica;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use RuntimeException;
|
||||
use ZipArchive;
|
||||
|
||||
|
||||
@@ -4,9 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Enums\GoogleService;
|
||||
use App\Models\CalendarioConnessione;
|
||||
use App\Services\GoogleOAuthService;
|
||||
use App\Models\Evento;
|
||||
use Carbon\Carbon;
|
||||
use Google\Client as GoogleClient;
|
||||
@@ -329,16 +327,6 @@ class GoogleCalendarSyncService
|
||||
|
||||
private function buildClient(CalendarioConnessione $connessione): GoogleClient
|
||||
{
|
||||
try {
|
||||
$oauth = app(GoogleOAuthService::class);
|
||||
$connection = $oauth->getConnection(GoogleService::Calendar);
|
||||
if ($connection) {
|
||||
return $oauth->buildClient(GoogleService::Calendar);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
\Illuminate\Support\Facades\Log::warning('Central Calendar OAuth failed, falling back: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
$config = $connessione->getDecryptedConfig();
|
||||
|
||||
$client = new GoogleClient();
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Enums\GoogleService;
|
||||
use App\Models\GoogleOAuthConnection;
|
||||
use Google\Client;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class GoogleOAuthService
|
||||
{
|
||||
private const TOKEN_URI = 'https://oauth2.googleapis.com/token';
|
||||
|
||||
private static function getRedirectUri(): string
|
||||
{
|
||||
$subfolder = config('app.url');
|
||||
return rtrim($subfolder, '/') . '/auth/google/callback';
|
||||
}
|
||||
|
||||
public function getAuthorizationUrl(GoogleService $service): string
|
||||
{
|
||||
$client = $this->createClient($service);
|
||||
$client->setRedirectUri(self::getRedirectUri());
|
||||
$client->setState($service->value);
|
||||
$client->setAccessType('offline');
|
||||
$client->setPrompt('consent');
|
||||
$client->setIncludeGrantedScopes(true);
|
||||
|
||||
return $client->createAuthUrl();
|
||||
}
|
||||
|
||||
public function handleCallback(string $code, GoogleService $service): GoogleOAuthConnection
|
||||
{
|
||||
$client = $this->createClient($service);
|
||||
$client->setRedirectUri(self::getRedirectUri());
|
||||
|
||||
$token = $client->fetchAccessTokenWithAuthCode($code);
|
||||
|
||||
if (isset($token['error'])) {
|
||||
throw new \RuntimeException('Google OAuth error: ' . ($token['error_description'] ?? $token['error']));
|
||||
}
|
||||
|
||||
if (!isset($token['refresh_token'])) {
|
||||
throw new \RuntimeException('No refresh token returned. Ensure access_type=offline and prompt=consent are set.');
|
||||
}
|
||||
|
||||
$clientId = $client->getClientId();
|
||||
$clientSecret = $client->getClientSecret();
|
||||
|
||||
return GoogleOAuthConnection::updateOrCreate(
|
||||
['service' => $service->value],
|
||||
[
|
||||
'client_id' => $clientId,
|
||||
'client_secret' => $clientSecret,
|
||||
'refresh_token' => $token['refresh_token'],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function revoke(GoogleService $service): void
|
||||
{
|
||||
$connection = $this->getConnection($service);
|
||||
if (!$connection) {
|
||||
return;
|
||||
}
|
||||
|
||||
$client = $this->createClient($service);
|
||||
$client->revokeToken();
|
||||
$connection->delete();
|
||||
}
|
||||
|
||||
public function getAccessToken(GoogleService $service): ?string
|
||||
{
|
||||
$connection = $this->getConnection($service);
|
||||
if (!$connection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
$client = $this->createClient($service);
|
||||
$client->setAccessToken([
|
||||
'access_token' => '',
|
||||
'refresh_token' => $connection->refresh_token,
|
||||
'client_id' => $connection->client_id,
|
||||
'client_secret' => $connection->client_secret,
|
||||
]);
|
||||
|
||||
if ($client->isAccessTokenExpired()) {
|
||||
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
|
||||
$newToken = $client->getAccessToken();
|
||||
if (isset($newToken['refresh_token'])) {
|
||||
$connection->refresh_token = $newToken['refresh_token'];
|
||||
$connection->save();
|
||||
}
|
||||
}
|
||||
|
||||
$accessToken = $client->getAccessToken();
|
||||
return $accessToken['access_token'] ?? null;
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Google OAuth token refresh failed for ' . $service->value . ': ' . $e->getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function isAuthorized(GoogleService $service): bool
|
||||
{
|
||||
return $this->getConnection($service) !== null;
|
||||
}
|
||||
|
||||
public function getConnection(GoogleService $service): ?GoogleOAuthConnection
|
||||
{
|
||||
return GoogleOAuthConnection::where('service', $service->value)->first();
|
||||
}
|
||||
|
||||
public function buildClient(GoogleService $service): Client
|
||||
{
|
||||
$client = $this->createClient($service);
|
||||
$connection = $this->getConnection($service);
|
||||
|
||||
if ($connection) {
|
||||
$client->setAccessToken([
|
||||
'access_token' => '',
|
||||
'refresh_token' => $connection->refresh_token,
|
||||
'client_id' => $connection->client_id,
|
||||
'client_secret' => $connection->client_secret,
|
||||
]);
|
||||
|
||||
if ($client->isAccessTokenExpired()) {
|
||||
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
|
||||
}
|
||||
}
|
||||
|
||||
return $client;
|
||||
}
|
||||
|
||||
private function createClient(GoogleService $service): Client
|
||||
{
|
||||
$client = new Client();
|
||||
$client->setApplicationName(config('app.name'));
|
||||
$client->setScopes([$service->scope()]);
|
||||
$client->setClientId(config('services.google.client_id'));
|
||||
$client->setClientSecret(config('services.google.client_secret'));
|
||||
$client->setRedirectUri(self::getRedirectUri());
|
||||
|
||||
return $client;
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Enums\GoogleService;
|
||||
use App\Models\StorageRepository;
|
||||
use App\Services\GoogleOAuthService;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use League\Flysystem\Filesystem;
|
||||
@@ -71,20 +69,6 @@ class StorageRepositoryService
|
||||
private function checkGoogleDriveApiStatus(array $config): ?string
|
||||
{
|
||||
try {
|
||||
try {
|
||||
$oauth = app(GoogleOAuthService::class);
|
||||
$connection = $oauth->getConnection(GoogleService::Drive);
|
||||
if ($connection) {
|
||||
$client = $oauth->buildClient(GoogleService::Drive);
|
||||
$service = new \Google_Service_Drive($client);
|
||||
$rootId = $config['root_folder_id'] ?? 'root';
|
||||
$service->files->get($rootId, ['fields' => 'id']);
|
||||
return null;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// fall through to config-based auth
|
||||
}
|
||||
|
||||
$client = new \Google_Client();
|
||||
$client->setClientId($config['client_id']);
|
||||
$client->setClientSecret($config['client_secret']);
|
||||
@@ -260,18 +244,6 @@ class StorageRepositoryService
|
||||
{
|
||||
$config = $repo->getDecryptedConfig();
|
||||
|
||||
try {
|
||||
$oauth = app(GoogleOAuthService::class);
|
||||
$connection = $oauth->getConnection(GoogleService::Drive);
|
||||
if ($connection) {
|
||||
$client = $oauth->buildClient(GoogleService::Drive);
|
||||
$service = new \Google_Service_Drive($client);
|
||||
return $this->readGoogleDriveFileWithService($service, $config, $normalizedPath, $basename);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
\Illuminate\Support\Facades\Log::warning('Central Google Drive OAuth failed in readGoogleDriveFile, falling back: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
$client = new \Google_Client();
|
||||
$client->setClientId($config['client_id']);
|
||||
$client->setClientSecret($config['client_secret']);
|
||||
@@ -311,40 +283,6 @@ class StorageRepositoryService
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
private function readGoogleDriveFileWithService(\Google_Service_Drive $service, array $config, string $normalizedPath, string $basename): array
|
||||
{
|
||||
$rootFolderId = $config['root_folder_id'] ?? 'root';
|
||||
|
||||
$fileId = $this->findGoogleDriveFileId($service, $rootFolderId, $normalizedPath);
|
||||
$file = $service->files->get($fileId, ['fields' => 'id,name,mimeType,size']);
|
||||
|
||||
$mimeType = $file->getMimeType();
|
||||
|
||||
if ($mimeType && str_starts_with($mimeType, 'application/vnd.google-apps.')) {
|
||||
return $this->exportGoogleDriveDoc($service, $fileId, $mimeType, $basename);
|
||||
}
|
||||
|
||||
$response = $service->files->get($fileId, ['alt' => 'media']);
|
||||
$body = $response->getBody();
|
||||
$stream = $body instanceof \Psr\Http\Message\StreamInterface ? $body->detach() : null;
|
||||
|
||||
if (!$stream) {
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
fwrite($stream, (string) $body);
|
||||
rewind($stream);
|
||||
}
|
||||
|
||||
$fileSize = $file->getSize();
|
||||
|
||||
return [
|
||||
'stream' => $stream,
|
||||
'mimeType' => $mimeType,
|
||||
'basename' => $basename,
|
||||
'fileSize' => $fileSize !== null ? (int) $fileSize : null,
|
||||
];
|
||||
}
|
||||
|
||||
private function exportGoogleDriveDoc(\Google_Service_Drive $service, string $fileId, string $googleMimeType, string $originalBasename): array
|
||||
{
|
||||
$exportMap = [
|
||||
|
||||
Regular → Executable
-33
@@ -94,36 +94,3 @@ echo " php artisan view:clear"
|
||||
echo ""
|
||||
echo " # 6. Avvia installazione MySQL"
|
||||
echo " php install.php"
|
||||
|
||||
echo ""
|
||||
echo "=== AGGIORNAMENTO (SERVER ESISTENTE) ==="
|
||||
echo ""
|
||||
echo " 1. BACKUP:"
|
||||
echo " cp .env .env.backup.$(date +%Y%m%d_%H%M%S)"
|
||||
echo " mysqldump -u USER -p DBNAME > backup_$(date +%Y%m%d_%H%M%S).sql"
|
||||
echo ""
|
||||
echo " 2. Estrai archivio (sovrascrive):"
|
||||
echo " tar xzf ${ARCHIVE}"
|
||||
echo ""
|
||||
echo " 3. Ripristina .env e aggiungi nuove variabili:"
|
||||
echo " cp .env.backup.* .env"
|
||||
echo " # Aggiungi se mancanti:"
|
||||
echo ' echo "GOOGLE_CLIENT_ID=" >> .env'
|
||||
echo ' echo "GOOGLE_CLIENT_SECRET=" >> .env'
|
||||
echo ""
|
||||
echo " 4. Permessi:"
|
||||
echo ' chmod -R 775 storage bootstrap/cache'
|
||||
echo ' chown -R www-data:www-data storage bootstrap/cache'
|
||||
echo ""
|
||||
echo " 5. Ricrea symlink storage:"
|
||||
echo ' rm -f public/storage'
|
||||
echo ' ln -sf ../storage/app/public public/storage'
|
||||
echo ""
|
||||
echo " 6. Esegui migration DB:"
|
||||
echo " php artisan migrate --force"
|
||||
echo ""
|
||||
echo " 7. Pulisci cache e ricostruisci asset:"
|
||||
echo " php artisan config:clear"
|
||||
echo " php artisan route:clear"
|
||||
echo " php artisan view:clear"
|
||||
echo " # npm install && npm run build (se serve ricostruire Vite)"
|
||||
|
||||
@@ -35,9 +35,4 @@ return [
|
||||
],
|
||||
],
|
||||
|
||||
|
||||
'google' => [
|
||||
'client_id' => env('GOOGLE_CLIENT_ID'),
|
||||
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
|
||||
],
|
||||
];
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('google_oauth_connections', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('service', 20)->unique();
|
||||
$table->string('client_id', 255);
|
||||
$table->text('client_secret');
|
||||
$table->text('refresh_token');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('google_oauth_connections');
|
||||
}
|
||||
};
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('email_settings', function (Blueprint $table) {
|
||||
$table->string('auth_method', 20)->default('password');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('email_settings', function (Blueprint $table) {
|
||||
$table->dropColumn('auth_method');
|
||||
});
|
||||
}
|
||||
};
|
||||
+1
@@ -0,0 +1 @@
|
||||
../laravel-vite-plugin/bin/clean.js
|
||||
+1
@@ -0,0 +1 @@
|
||||
../concurrently/dist/bin/concurrently.js
|
||||
+1
@@ -0,0 +1 @@
|
||||
../concurrently/dist/bin/concurrently.js
|
||||
+1
@@ -0,0 +1 @@
|
||||
../jiti/lib/jiti-cli.mjs
|
||||
+1
@@ -0,0 +1 @@
|
||||
../nanoid/bin/nanoid.cjs
|
||||
+1
@@ -0,0 +1 @@
|
||||
../rolldown/bin/cli.mjs
|
||||
+1
@@ -0,0 +1 @@
|
||||
../tree-kill/cli.js
|
||||
+1
@@ -0,0 +1 @@
|
||||
../vite/bin/vite.js
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+66
@@ -0,0 +1,66 @@
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Instrument Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.bunny.net/instrument-sans/files/instrument-sans-latin-400-normal.woff2) format('woff2'), url(https://fonts.bunny.net/instrument-sans/files/instrument-sans-latin-400-normal.woff) format('woff');
|
||||
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Instrument Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.bunny.net/instrument-sans/files/instrument-sans-latin-ext-400-normal.woff2) format('woff2'), url(https://fonts.bunny.net/instrument-sans/files/instrument-sans-latin-ext-400-normal.woff) format('woff');
|
||||
unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Instrument Sans';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.bunny.net/instrument-sans/files/instrument-sans-latin-500-normal.woff2) format('woff2'), url(https://fonts.bunny.net/instrument-sans/files/instrument-sans-latin-500-normal.woff) format('woff');
|
||||
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Instrument Sans';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.bunny.net/instrument-sans/files/instrument-sans-latin-ext-500-normal.woff2) format('woff2'), url(https://fonts.bunny.net/instrument-sans/files/instrument-sans-latin-ext-500-normal.woff) format('woff');
|
||||
unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Instrument Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.bunny.net/instrument-sans/files/instrument-sans-latin-600-normal.woff2) format('woff2'), url(https://fonts.bunny.net/instrument-sans/files/instrument-sans-latin-600-normal.woff) format('woff');
|
||||
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Instrument Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-stretch: 100%;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.bunny.net/instrument-sans/files/instrument-sans-latin-ext-600-normal.woff2) format('woff2'), url(https://fonts.bunny.net/instrument-sans/files/instrument-sans-latin-ext-600-normal.woff) format('woff');
|
||||
unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
|
||||
}
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+929
@@ -0,0 +1,929 @@
|
||||
{
|
||||
"name": "glastree",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"node_modules/@emnapi/core": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
|
||||
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/wasi-threads": "1.2.1",
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/runtime": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
|
||||
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/wasi-threads": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
|
||||
"integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
"version": "0.3.13",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
||||
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.5.0",
|
||||
"@jridgewell/trace-mapping": "^0.3.24"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/remapping": {
|
||||
"version": "2.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
|
||||
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.24"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/resolve-uri": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
||||
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.31",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
|
||||
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "^3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/wasm-runtime": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz",
|
||||
"integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@tybys/wasm-util": "^0.10.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/Brooooooklyn"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emnapi/core": "^1.7.1",
|
||||
"@emnapi/runtime": "^1.7.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxc-project/types": {
|
||||
"version": "0.133.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz",
|
||||
"integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/Boshen"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz",
|
||||
"integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-x64-musl": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz",
|
||||
"integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/pluginutils": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
|
||||
"integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@tailwindcss/node": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.1.tgz",
|
||||
"integrity": "sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/remapping": "^2.3.5",
|
||||
"enhanced-resolve": "5.21.6",
|
||||
"jiti": "^2.7.0",
|
||||
"lightningcss": "1.32.0",
|
||||
"magic-string": "^0.30.21",
|
||||
"source-map-js": "^1.2.1",
|
||||
"tailwindcss": "4.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.1.tgz",
|
||||
"integrity": "sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@tailwindcss/oxide-android-arm64": "4.3.1",
|
||||
"@tailwindcss/oxide-darwin-arm64": "4.3.1",
|
||||
"@tailwindcss/oxide-darwin-x64": "4.3.1",
|
||||
"@tailwindcss/oxide-freebsd-x64": "4.3.1",
|
||||
"@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.1",
|
||||
"@tailwindcss/oxide-linux-arm64-gnu": "4.3.1",
|
||||
"@tailwindcss/oxide-linux-arm64-musl": "4.3.1",
|
||||
"@tailwindcss/oxide-linux-x64-gnu": "4.3.1",
|
||||
"@tailwindcss/oxide-linux-x64-musl": "4.3.1",
|
||||
"@tailwindcss/oxide-wasm32-wasi": "4.3.1",
|
||||
"@tailwindcss/oxide-win32-arm64-msvc": "4.3.1",
|
||||
"@tailwindcss/oxide-win32-x64-msvc": "4.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.1.tgz",
|
||||
"integrity": "sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-linux-x64-musl": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.1.tgz",
|
||||
"integrity": "sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/vite": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.1.tgz",
|
||||
"integrity": "sha512-hItDHuIIlEV61R+faXu66s1K36aTurO/Qw0e45Vskz57gXl9pWOT6eg3zmcEui6CZXddbN7zd41bwmvag4JGwQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@tailwindcss/node": "4.3.1",
|
||||
"@tailwindcss/oxide": "4.3.1",
|
||||
"tailwindcss": "4.3.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vite": "^5.2.0 || ^6 || ^7 || ^8"
|
||||
}
|
||||
},
|
||||
"node_modules/@tybys/wasm-util": {
|
||||
"version": "0.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
|
||||
"integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk/node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/concurrently": {
|
||||
"version": "9.2.1",
|
||||
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz",
|
||||
"integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chalk": "4.1.2",
|
||||
"rxjs": "7.8.2",
|
||||
"shell-quote": "1.8.3",
|
||||
"supports-color": "8.1.1",
|
||||
"tree-kill": "1.2.2",
|
||||
"yargs": "17.7.2"
|
||||
},
|
||||
"bin": {
|
||||
"conc": "dist/bin/concurrently.js",
|
||||
"concurrently": "dist/bin/concurrently.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.21.6",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz",
|
||||
"integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
"tapable": "^2.3.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
||||
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/fdir": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"picomatch": "^3 || ^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"picomatch": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "6.* || 8.* || >= 10.*"
|
||||
}
|
||||
},
|
||||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/jiti": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz",
|
||||
"integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"jiti": "lib/jiti-cli.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/laravel-vite-plugin": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-3.1.0.tgz",
|
||||
"integrity": "sha512-Fzocl+X4eQ9jOi0RwdphYRGkUbPJ3ky1pTAST5Ot18cS2gw6d2vldK2eCrlKDVjtibCjCx5qptYDlA0373n7qg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"picocolors": "^1.0.0",
|
||||
"tinyglobby": "^0.2.12",
|
||||
"vite-plugin-full-reload": "^1.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"clean-orphaned-assets": "bin/clean.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"fontaine": "^0.5.0",
|
||||
"vite": "^8.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"fontaine": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
|
||||
"integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"lightningcss-android-arm64": "1.32.0",
|
||||
"lightningcss-darwin-arm64": "1.32.0",
|
||||
"lightningcss-darwin-x64": "1.32.0",
|
||||
"lightningcss-freebsd-x64": "1.32.0",
|
||||
"lightningcss-linux-arm-gnueabihf": "1.32.0",
|
||||
"lightningcss-linux-arm64-gnu": "1.32.0",
|
||||
"lightningcss-linux-arm64-musl": "1.32.0",
|
||||
"lightningcss-linux-x64-gnu": "1.32.0",
|
||||
"lightningcss-linux-x64-musl": "1.32.0",
|
||||
"lightningcss-win32-arm64-msvc": "1.32.0",
|
||||
"lightningcss-win32-x64-msvc": "1.32.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-x64-gnu": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
|
||||
"integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-x64-musl": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
|
||||
"integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.21",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
||||
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.12",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
|
||||
"integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.15",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
|
||||
"integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
{
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.12",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rolldown": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz",
|
||||
"integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@oxc-project/types": "=0.133.0",
|
||||
"@rolldown/pluginutils": "^1.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"rolldown": "bin/cli.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rolldown/binding-android-arm64": "1.0.3",
|
||||
"@rolldown/binding-darwin-arm64": "1.0.3",
|
||||
"@rolldown/binding-darwin-x64": "1.0.3",
|
||||
"@rolldown/binding-freebsd-x64": "1.0.3",
|
||||
"@rolldown/binding-linux-arm-gnueabihf": "1.0.3",
|
||||
"@rolldown/binding-linux-arm64-gnu": "1.0.3",
|
||||
"@rolldown/binding-linux-arm64-musl": "1.0.3",
|
||||
"@rolldown/binding-linux-ppc64-gnu": "1.0.3",
|
||||
"@rolldown/binding-linux-s390x-gnu": "1.0.3",
|
||||
"@rolldown/binding-linux-x64-gnu": "1.0.3",
|
||||
"@rolldown/binding-linux-x64-musl": "1.0.3",
|
||||
"@rolldown/binding-openharmony-arm64": "1.0.3",
|
||||
"@rolldown/binding-wasm32-wasi": "1.0.3",
|
||||
"@rolldown/binding-win32-arm64-msvc": "1.0.3",
|
||||
"@rolldown/binding-win32-x64-msvc": "1.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/rxjs": {
|
||||
"version": "7.8.2",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
|
||||
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/shell-quote": {
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz",
|
||||
"integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
||||
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.1.tgz",
|
||||
"integrity": "sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/tapable": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
|
||||
"integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.17",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
|
||||
"integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fdir": "^6.5.0",
|
||||
"picomatch": "^4.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/SuperchupuDev"
|
||||
}
|
||||
},
|
||||
"node_modules/tree-kill": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
|
||||
"integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tree-kill": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "8.0.16",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz",
|
||||
"integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lightningcss": "^1.32.0",
|
||||
"picomatch": "^4.0.4",
|
||||
"postcss": "^8.5.15",
|
||||
"rolldown": "1.0.3",
|
||||
"tinyglobby": "^0.2.17"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/vitejs/vite?sponsor=1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": "^20.19.0 || >=22.12.0",
|
||||
"@vitejs/devtools": "^0.1.18",
|
||||
"esbuild": "^0.27.0 || ^0.28.0",
|
||||
"jiti": ">=1.21.0",
|
||||
"less": "^4.0.0",
|
||||
"sass": "^1.70.0",
|
||||
"sass-embedded": "^1.70.0",
|
||||
"stylus": ">=0.54.8",
|
||||
"sugarss": "^5.0.0",
|
||||
"terser": "^5.16.0",
|
||||
"tsx": "^4.8.1",
|
||||
"yaml": "^2.4.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
},
|
||||
"@vitejs/devtools": {
|
||||
"optional": true
|
||||
},
|
||||
"esbuild": {
|
||||
"optional": true
|
||||
},
|
||||
"jiti": {
|
||||
"optional": true
|
||||
},
|
||||
"less": {
|
||||
"optional": true
|
||||
},
|
||||
"sass": {
|
||||
"optional": true
|
||||
},
|
||||
"sass-embedded": {
|
||||
"optional": true
|
||||
},
|
||||
"stylus": {
|
||||
"optional": true
|
||||
},
|
||||
"sugarss": {
|
||||
"optional": true
|
||||
},
|
||||
"terser": {
|
||||
"optional": true
|
||||
},
|
||||
"tsx": {
|
||||
"optional": true
|
||||
},
|
||||
"yaml": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vite-plugin-full-reload": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/vite-plugin-full-reload/-/vite-plugin-full-reload-1.2.0.tgz",
|
||||
"integrity": "sha512-kz18NW79x0IHbxRSHm0jttP4zoO9P9gXh+n6UTwlNKnviTTEpOlum6oS9SmecrTtSr+muHEn5TUuC75UovQzcA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"picocolors": "^1.0.0",
|
||||
"picomatch": "^2.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/vite-plugin-full-reload/node_modules/picomatch": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
|
||||
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs-parser": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-present Toyobayashi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+1
@@ -0,0 +1 @@
|
||||
See [https://github.com/toyobayashi/emnapi](https://github.com/toyobayashi/emnapi)
|
||||
+7397
File diff suppressed because it is too large
Load Diff
+420
@@ -0,0 +1,420 @@
|
||||
/// <reference types="node" />
|
||||
|
||||
import type { Context } from '@emnapi/runtime';
|
||||
import type { ReferenceOwnership } from '@emnapi/runtime';
|
||||
import type { Worker as Worker_2 } from 'worker_threads';
|
||||
|
||||
/** @public */
|
||||
export declare type BaseCreateOptions = {
|
||||
filename?: string
|
||||
nodeBinding?: NodeBinding
|
||||
reuseWorker?: ThreadManagerOptionsMain['reuseWorker']
|
||||
asyncWorkPoolSize?: number
|
||||
waitThreadStart?: MainThreadBaseOptions['waitThreadStart']
|
||||
onCreateWorker?: (info: CreateWorkerInfo) => any
|
||||
print?: (str: string) => void
|
||||
printErr?: (str: string) => void
|
||||
postMessage?: (msg: any) => any
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface BaseOptions {
|
||||
wasi: WASIInstance;
|
||||
version?: 'preview1';
|
||||
wasm64?: boolean;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ChildThreadOptions extends BaseOptions {
|
||||
childThread: true;
|
||||
postMessage?: (data: any) => void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CleanupThreadPayload {
|
||||
tid: number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CommandInfo<T extends CommandType> {
|
||||
type: T;
|
||||
payload: CommandPayloadMap[T];
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CommandPayloadMap {
|
||||
load: LoadPayload;
|
||||
loaded: LoadedPayload;
|
||||
start: StartPayload;
|
||||
'cleanup-thread': CleanupThreadPayload;
|
||||
'terminate-all-threads': TerminateAllThreadsPayload;
|
||||
'spawn-thread': SpawnThreadPayload;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type CommandType = keyof CommandPayloadMap;
|
||||
|
||||
/** @public */
|
||||
export declare function createInstanceProxy(instance: WebAssembly.Instance, memory?: WebAssembly.Memory | (() => WebAssembly.Memory)): WebAssembly.Instance;
|
||||
|
||||
/** @public */
|
||||
export declare function createNapiModule (
|
||||
options: CreateOptions
|
||||
): NapiModule
|
||||
|
||||
/** @public */
|
||||
export declare type CreateOptions = BaseCreateOptions & ({
|
||||
context: Context
|
||||
childThread?: boolean
|
||||
} | {
|
||||
context?: Context
|
||||
childThread: true
|
||||
})
|
||||
|
||||
/** @public */
|
||||
export declare interface CreateWorkerInfo {
|
||||
type: 'thread' | 'async-work'
|
||||
name: string
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface InitOptions {
|
||||
instance: WebAssembly.Instance
|
||||
module: WebAssembly.Module
|
||||
memory?: WebAssembly.Memory
|
||||
table?: WebAssembly.Table
|
||||
}
|
||||
|
||||
export declare type InputType = string | URL | Response | BufferSource | WebAssembly.Module;
|
||||
|
||||
/** @public */
|
||||
export declare interface InstantiatedSource extends LoadedSource {
|
||||
napiModule: NapiModule;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare function instantiateNapiModule(
|
||||
/** Only support `BufferSource` or `WebAssembly.Module` on Node.js */
|
||||
wasmInput: InputType | Promise<InputType>, options: InstantiateOptions): Promise<InstantiatedSource>;
|
||||
|
||||
/** @public */
|
||||
export declare function instantiateNapiModuleSync(wasmInput: BufferSource | WebAssembly.Module, options: InstantiateOptions): InstantiatedSource;
|
||||
|
||||
/** @public */
|
||||
export declare type InstantiateOptions = CreateOptions & LoadOptions;
|
||||
|
||||
/** @public */
|
||||
export declare function isSharedArrayBuffer(value: any): value is SharedArrayBuffer;
|
||||
|
||||
/** @public */
|
||||
export declare function isTrapError(e: Error): e is WebAssembly.RuntimeError;
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadedPayload {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadedSource extends WebAssembly.WebAssemblyInstantiatedSource {
|
||||
usedInstance: WebAssembly.Instance;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare function loadNapiModule(napiModule: NapiModule,
|
||||
/** Only support `BufferSource` or `WebAssembly.Module` on Node.js */
|
||||
wasmInput: InputType | Promise<InputType>, options?: LoadOptions): Promise<LoadedSource>;
|
||||
|
||||
/** @public */
|
||||
export declare function loadNapiModuleSync(napiModule: NapiModule, wasmInput: BufferSource | WebAssembly.Module, options?: LoadOptions): LoadedSource;
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadOptions {
|
||||
wasi?: WASIInstance;
|
||||
overwriteImports?: (importObject: WebAssembly.Imports) => WebAssembly.Imports;
|
||||
beforeInit?: (source: WebAssembly.WebAssemblyInstantiatedSource) => void;
|
||||
getMemory?: (exports: WebAssembly.Exports) => WebAssembly.Memory;
|
||||
getTable?: (exports: WebAssembly.Exports) => WebAssembly.Table;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadPayload {
|
||||
wasmModule: WebAssembly.Module;
|
||||
wasmMemory: WebAssembly.Memory;
|
||||
sab?: Int32Array;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadBaseOptions extends BaseOptions {
|
||||
waitThreadStart?: boolean | number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type MainThreadOptions = MainThreadOptionsWithThreadManager | MainThreadOptionsCreateThreadManager;
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadOptionsCreateThreadManager extends MainThreadBaseOptions, ThreadManagerOptionsMain {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadOptionsWithThreadManager extends MainThreadBaseOptions {
|
||||
threadManager?: ThreadManager | (() => ThreadManager);
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MessageEventData<T extends CommandType> {
|
||||
__emnapi__: CommandInfo<T>;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class MessageHandler extends ThreadMessageHandler {
|
||||
napiModule: NapiModule | undefined;
|
||||
constructor(options: MessageHandlerOptions);
|
||||
instantiate(data: LoadPayload): InstantiatedSource | PromiseLike<InstantiatedSource>;
|
||||
handle(e: WorkerMessageEvent): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MessageHandlerOptions extends ThreadMessageHandlerOptions {
|
||||
onLoad: (data: LoadPayload) => InstantiatedSource | PromiseLike<InstantiatedSource>;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface NapiModule {
|
||||
imports: {
|
||||
env: any
|
||||
napi: any
|
||||
emnapi: any
|
||||
}
|
||||
exports: any
|
||||
loaded: boolean
|
||||
filename: string
|
||||
childThread: boolean
|
||||
emnapi: {
|
||||
syncMemory<T extends ArrayBuffer | ArrayBufferView> (
|
||||
js_to_wasm: boolean,
|
||||
arrayBufferOrView: T,
|
||||
offset?: number,
|
||||
len?: number
|
||||
): T
|
||||
getMemoryAddress (arrayBufferOrView: ArrayBuffer | ArrayBufferView): PointerInfo
|
||||
addSendListener (worker: any): boolean
|
||||
}
|
||||
|
||||
init (options: InitOptions): any
|
||||
initWorker (arg: number, func: [number, number]): void
|
||||
postMessage?: (msg: any) => any
|
||||
|
||||
waitThreadStart: boolean | number
|
||||
/* Excluded from this release type: PThread */}
|
||||
|
||||
/** @public */
|
||||
export declare interface NodeBinding {
|
||||
node: {
|
||||
emitAsyncInit: Function
|
||||
emitAsyncDestroy: Function
|
||||
makeCallback: Function
|
||||
}
|
||||
napi: {
|
||||
asyncInit: Function
|
||||
asyncDestroy: Function
|
||||
makeCallback: Function
|
||||
}
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface PointerInfo {
|
||||
address: number
|
||||
ownership: ReferenceOwnership
|
||||
runtimeAllocated: 0 | 1
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ReuseWorkerOptions {
|
||||
/**
|
||||
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size | PTHREAD_POOL_SIZE}
|
||||
*/
|
||||
size: number;
|
||||
/**
|
||||
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size-strict | PTHREAD_POOL_SIZE_STRICT}
|
||||
*/
|
||||
strict?: boolean;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface SpawnThreadPayload {
|
||||
startArg: number;
|
||||
errorOrTid: number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface StartPayload {
|
||||
tid: number;
|
||||
arg: number;
|
||||
sab?: Int32Array;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface StartResult {
|
||||
exitCode: number;
|
||||
instance: WebAssembly.Instance;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface TerminateAllThreadsPayload {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class ThreadManager {
|
||||
unusedWorkers: WorkerLike[];
|
||||
runningWorkers: WorkerLike[];
|
||||
pthreads: Record<number, WorkerLike>;
|
||||
get nextWorkerID(): number;
|
||||
wasmModule: WebAssembly.Module | null;
|
||||
wasmMemory: WebAssembly.Memory | null;
|
||||
private readonly messageEvents;
|
||||
private readonly _childThread;
|
||||
private readonly _onCreateWorker;
|
||||
private readonly _reuseWorker;
|
||||
private readonly _beforeLoad?;
|
||||
/* Excluded from this release type: printErr */
|
||||
threadSpawn?: ((startArg: number, errorOrTid?: number) => number);
|
||||
constructor(options: ThreadManagerOptions);
|
||||
init(): void;
|
||||
initMainThread(): void;
|
||||
private preparePool;
|
||||
shouldPreloadWorkers(): boolean;
|
||||
loadWasmModuleToAllWorkers(): Promise<WorkerLike[]>;
|
||||
preloadWorkers(): Promise<WorkerLike[]>;
|
||||
setup(wasmModule: WebAssembly.Module, wasmMemory: WebAssembly.Memory): void;
|
||||
markId(worker: WorkerLike): number;
|
||||
returnWorkerToPool(worker: WorkerLike): void;
|
||||
loadWasmModuleToWorker(worker: WorkerLike, sab?: Int32Array): Promise<WorkerLike>;
|
||||
allocateUnusedWorker(): WorkerLike;
|
||||
getNewWorker(sab?: Int32Array): WorkerLike | undefined;
|
||||
cleanThread(worker: WorkerLike, tid: number, force?: boolean): void;
|
||||
terminateWorker(worker: WorkerLike): void;
|
||||
terminateAllThreads(): void;
|
||||
addMessageEventListener(worker: WorkerLike, onMessage: (e: WorkerMessageEvent) => void): () => void;
|
||||
fireMessageEvent(worker: WorkerLike, e: WorkerMessageEvent): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type ThreadManagerOptions = ThreadManagerOptionsMain | ThreadManagerOptionsChild;
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsBase {
|
||||
printErr?: (message: string) => void;
|
||||
threadSpawn?: (startArg: number, errorOrTid?: number) => number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsChild extends ThreadManagerOptionsBase {
|
||||
childThread: true;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsMain extends ThreadManagerOptionsBase {
|
||||
beforeLoad?: (worker: WorkerLike) => any;
|
||||
reuseWorker?: boolean | number | ReuseWorkerOptions;
|
||||
onCreateWorker: WorkerFactory;
|
||||
childThread?: false;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class ThreadMessageHandler {
|
||||
protected instance: WebAssembly.Instance | undefined;
|
||||
private messagesBeforeLoad;
|
||||
protected postMessage: (message: any) => void;
|
||||
protected onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
protected onError: (error: Error, type: WorkerMessageType) => void;
|
||||
constructor(options?: ThreadMessageHandlerOptions);
|
||||
/** @virtual */
|
||||
instantiate(data: LoadPayload): WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
/** @virtual */
|
||||
handle(e: WorkerMessageEvent<MessageEventData<WorkerMessageType>>): void;
|
||||
private _load;
|
||||
private _start;
|
||||
protected _loaded(err: Error | null, source: WebAssembly.WebAssemblyInstantiatedSource | null, payload: LoadPayload): void;
|
||||
protected handleAfterLoad<E extends WorkerMessageEvent>(e: E, f: (e: E) => void): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadMessageHandlerOptions {
|
||||
onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
onError?: (error: Error, type: WorkerMessageType) => void;
|
||||
postMessage?: (message: any) => void;
|
||||
}
|
||||
|
||||
export declare const version: string;
|
||||
|
||||
/** @public */
|
||||
export declare interface WASIInstance {
|
||||
readonly wasiImport?: Record<string, any>;
|
||||
initialize(instance: object): void;
|
||||
start(instance: object): number;
|
||||
getImportObject?(): any;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class WASIThreads {
|
||||
PThread: ThreadManager | undefined;
|
||||
private wasmMemory;
|
||||
private wasmInstance;
|
||||
private readonly threadSpawn;
|
||||
readonly childThread: boolean;
|
||||
private readonly postMessage;
|
||||
readonly wasi: WASIInstance;
|
||||
constructor(options: WASIThreadsOptions);
|
||||
getImportObject(): {
|
||||
wasi: WASIThreadsImports;
|
||||
};
|
||||
setup(wasmInstance: WebAssembly.Instance, wasmModule: WebAssembly.Module, wasmMemory?: WebAssembly.Memory): void;
|
||||
preloadWorkers(): Promise<WorkerLike[]>;
|
||||
/**
|
||||
* It's ok to call this method to a WASI command module.
|
||||
*
|
||||
* in child thread, must call this method instead of {@link WASIThreads.start} even if it's a WASI command module
|
||||
*
|
||||
* @returns A proxied WebAssembly instance if in child thread, other wise the original instance
|
||||
*/
|
||||
initialize(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): WebAssembly.Instance;
|
||||
/**
|
||||
* Equivalent to calling {@link WASIThreads.initialize} and then calling {@link WASIInstance.start}
|
||||
* ```js
|
||||
* this.initialize(instance, module, memory)
|
||||
* this.wasi.start(instance)
|
||||
* ```
|
||||
*/
|
||||
start(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): StartResult;
|
||||
terminateAllThreads(): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface WASIThreadsImports {
|
||||
'thread-spawn': (startArg: number, errorOrTid?: number) => number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type WASIThreadsOptions = MainThreadOptions | ChildThreadOptions;
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerFactory = (ctx: {
|
||||
type: string;
|
||||
name: string;
|
||||
}) => WorkerLike;
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerLike = (Worker | Worker_2) & {
|
||||
whenLoaded?: Promise<WorkerLike>;
|
||||
loaded?: boolean;
|
||||
__emnapi_tid?: number;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export declare interface WorkerMessageEvent<T = any> {
|
||||
data: T;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerMessageType = 'load' | 'start';
|
||||
|
||||
export { }
|
||||
+1
File diff suppressed because one or more lines are too long
+420
@@ -0,0 +1,420 @@
|
||||
/// <reference types="node" />
|
||||
|
||||
import type { Context } from '@emnapi/runtime';
|
||||
import type { ReferenceOwnership } from '@emnapi/runtime';
|
||||
import type { Worker as Worker_2 } from 'worker_threads';
|
||||
|
||||
/** @public */
|
||||
export declare type BaseCreateOptions = {
|
||||
filename?: string
|
||||
nodeBinding?: NodeBinding
|
||||
reuseWorker?: ThreadManagerOptionsMain['reuseWorker']
|
||||
asyncWorkPoolSize?: number
|
||||
waitThreadStart?: MainThreadBaseOptions['waitThreadStart']
|
||||
onCreateWorker?: (info: CreateWorkerInfo) => any
|
||||
print?: (str: string) => void
|
||||
printErr?: (str: string) => void
|
||||
postMessage?: (msg: any) => any
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface BaseOptions {
|
||||
wasi: WASIInstance;
|
||||
version?: 'preview1';
|
||||
wasm64?: boolean;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ChildThreadOptions extends BaseOptions {
|
||||
childThread: true;
|
||||
postMessage?: (data: any) => void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CleanupThreadPayload {
|
||||
tid: number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CommandInfo<T extends CommandType> {
|
||||
type: T;
|
||||
payload: CommandPayloadMap[T];
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CommandPayloadMap {
|
||||
load: LoadPayload;
|
||||
loaded: LoadedPayload;
|
||||
start: StartPayload;
|
||||
'cleanup-thread': CleanupThreadPayload;
|
||||
'terminate-all-threads': TerminateAllThreadsPayload;
|
||||
'spawn-thread': SpawnThreadPayload;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type CommandType = keyof CommandPayloadMap;
|
||||
|
||||
/** @public */
|
||||
export declare function createInstanceProxy(instance: WebAssembly.Instance, memory?: WebAssembly.Memory | (() => WebAssembly.Memory)): WebAssembly.Instance;
|
||||
|
||||
/** @public */
|
||||
export declare function createNapiModule (
|
||||
options: CreateOptions
|
||||
): NapiModule
|
||||
|
||||
/** @public */
|
||||
export declare type CreateOptions = BaseCreateOptions & ({
|
||||
context: Context
|
||||
childThread?: boolean
|
||||
} | {
|
||||
context?: Context
|
||||
childThread: true
|
||||
})
|
||||
|
||||
/** @public */
|
||||
export declare interface CreateWorkerInfo {
|
||||
type: 'thread' | 'async-work'
|
||||
name: string
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface InitOptions {
|
||||
instance: WebAssembly.Instance
|
||||
module: WebAssembly.Module
|
||||
memory?: WebAssembly.Memory
|
||||
table?: WebAssembly.Table
|
||||
}
|
||||
|
||||
export declare type InputType = string | URL | Response | BufferSource | WebAssembly.Module;
|
||||
|
||||
/** @public */
|
||||
export declare interface InstantiatedSource extends LoadedSource {
|
||||
napiModule: NapiModule;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare function instantiateNapiModule(
|
||||
/** Only support `BufferSource` or `WebAssembly.Module` on Node.js */
|
||||
wasmInput: InputType | Promise<InputType>, options: InstantiateOptions): Promise<InstantiatedSource>;
|
||||
|
||||
/** @public */
|
||||
export declare function instantiateNapiModuleSync(wasmInput: BufferSource | WebAssembly.Module, options: InstantiateOptions): InstantiatedSource;
|
||||
|
||||
/** @public */
|
||||
export declare type InstantiateOptions = CreateOptions & LoadOptions;
|
||||
|
||||
/** @public */
|
||||
export declare function isSharedArrayBuffer(value: any): value is SharedArrayBuffer;
|
||||
|
||||
/** @public */
|
||||
export declare function isTrapError(e: Error): e is WebAssembly.RuntimeError;
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadedPayload {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadedSource extends WebAssembly.WebAssemblyInstantiatedSource {
|
||||
usedInstance: WebAssembly.Instance;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare function loadNapiModule(napiModule: NapiModule,
|
||||
/** Only support `BufferSource` or `WebAssembly.Module` on Node.js */
|
||||
wasmInput: InputType | Promise<InputType>, options?: LoadOptions): Promise<LoadedSource>;
|
||||
|
||||
/** @public */
|
||||
export declare function loadNapiModuleSync(napiModule: NapiModule, wasmInput: BufferSource | WebAssembly.Module, options?: LoadOptions): LoadedSource;
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadOptions {
|
||||
wasi?: WASIInstance;
|
||||
overwriteImports?: (importObject: WebAssembly.Imports) => WebAssembly.Imports;
|
||||
beforeInit?: (source: WebAssembly.WebAssemblyInstantiatedSource) => void;
|
||||
getMemory?: (exports: WebAssembly.Exports) => WebAssembly.Memory;
|
||||
getTable?: (exports: WebAssembly.Exports) => WebAssembly.Table;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadPayload {
|
||||
wasmModule: WebAssembly.Module;
|
||||
wasmMemory: WebAssembly.Memory;
|
||||
sab?: Int32Array;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadBaseOptions extends BaseOptions {
|
||||
waitThreadStart?: boolean | number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type MainThreadOptions = MainThreadOptionsWithThreadManager | MainThreadOptionsCreateThreadManager;
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadOptionsCreateThreadManager extends MainThreadBaseOptions, ThreadManagerOptionsMain {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadOptionsWithThreadManager extends MainThreadBaseOptions {
|
||||
threadManager?: ThreadManager | (() => ThreadManager);
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MessageEventData<T extends CommandType> {
|
||||
__emnapi__: CommandInfo<T>;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class MessageHandler extends ThreadMessageHandler {
|
||||
napiModule: NapiModule | undefined;
|
||||
constructor(options: MessageHandlerOptions);
|
||||
instantiate(data: LoadPayload): InstantiatedSource | PromiseLike<InstantiatedSource>;
|
||||
handle(e: WorkerMessageEvent): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MessageHandlerOptions extends ThreadMessageHandlerOptions {
|
||||
onLoad: (data: LoadPayload) => InstantiatedSource | PromiseLike<InstantiatedSource>;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface NapiModule {
|
||||
imports: {
|
||||
env: any
|
||||
napi: any
|
||||
emnapi: any
|
||||
}
|
||||
exports: any
|
||||
loaded: boolean
|
||||
filename: string
|
||||
childThread: boolean
|
||||
emnapi: {
|
||||
syncMemory<T extends ArrayBuffer | ArrayBufferView> (
|
||||
js_to_wasm: boolean,
|
||||
arrayBufferOrView: T,
|
||||
offset?: number,
|
||||
len?: number
|
||||
): T
|
||||
getMemoryAddress (arrayBufferOrView: ArrayBuffer | ArrayBufferView): PointerInfo
|
||||
addSendListener (worker: any): boolean
|
||||
}
|
||||
|
||||
init (options: InitOptions): any
|
||||
initWorker (arg: number, func: [number, number]): void
|
||||
postMessage?: (msg: any) => any
|
||||
|
||||
waitThreadStart: boolean | number
|
||||
/* Excluded from this release type: PThread */}
|
||||
|
||||
/** @public */
|
||||
export declare interface NodeBinding {
|
||||
node: {
|
||||
emitAsyncInit: Function
|
||||
emitAsyncDestroy: Function
|
||||
makeCallback: Function
|
||||
}
|
||||
napi: {
|
||||
asyncInit: Function
|
||||
asyncDestroy: Function
|
||||
makeCallback: Function
|
||||
}
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface PointerInfo {
|
||||
address: number
|
||||
ownership: ReferenceOwnership
|
||||
runtimeAllocated: 0 | 1
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ReuseWorkerOptions {
|
||||
/**
|
||||
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size | PTHREAD_POOL_SIZE}
|
||||
*/
|
||||
size: number;
|
||||
/**
|
||||
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size-strict | PTHREAD_POOL_SIZE_STRICT}
|
||||
*/
|
||||
strict?: boolean;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface SpawnThreadPayload {
|
||||
startArg: number;
|
||||
errorOrTid: number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface StartPayload {
|
||||
tid: number;
|
||||
arg: number;
|
||||
sab?: Int32Array;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface StartResult {
|
||||
exitCode: number;
|
||||
instance: WebAssembly.Instance;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface TerminateAllThreadsPayload {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class ThreadManager {
|
||||
unusedWorkers: WorkerLike[];
|
||||
runningWorkers: WorkerLike[];
|
||||
pthreads: Record<number, WorkerLike>;
|
||||
get nextWorkerID(): number;
|
||||
wasmModule: WebAssembly.Module | null;
|
||||
wasmMemory: WebAssembly.Memory | null;
|
||||
private readonly messageEvents;
|
||||
private readonly _childThread;
|
||||
private readonly _onCreateWorker;
|
||||
private readonly _reuseWorker;
|
||||
private readonly _beforeLoad?;
|
||||
/* Excluded from this release type: printErr */
|
||||
threadSpawn?: ((startArg: number, errorOrTid?: number) => number);
|
||||
constructor(options: ThreadManagerOptions);
|
||||
init(): void;
|
||||
initMainThread(): void;
|
||||
private preparePool;
|
||||
shouldPreloadWorkers(): boolean;
|
||||
loadWasmModuleToAllWorkers(): Promise<WorkerLike[]>;
|
||||
preloadWorkers(): Promise<WorkerLike[]>;
|
||||
setup(wasmModule: WebAssembly.Module, wasmMemory: WebAssembly.Memory): void;
|
||||
markId(worker: WorkerLike): number;
|
||||
returnWorkerToPool(worker: WorkerLike): void;
|
||||
loadWasmModuleToWorker(worker: WorkerLike, sab?: Int32Array): Promise<WorkerLike>;
|
||||
allocateUnusedWorker(): WorkerLike;
|
||||
getNewWorker(sab?: Int32Array): WorkerLike | undefined;
|
||||
cleanThread(worker: WorkerLike, tid: number, force?: boolean): void;
|
||||
terminateWorker(worker: WorkerLike): void;
|
||||
terminateAllThreads(): void;
|
||||
addMessageEventListener(worker: WorkerLike, onMessage: (e: WorkerMessageEvent) => void): () => void;
|
||||
fireMessageEvent(worker: WorkerLike, e: WorkerMessageEvent): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type ThreadManagerOptions = ThreadManagerOptionsMain | ThreadManagerOptionsChild;
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsBase {
|
||||
printErr?: (message: string) => void;
|
||||
threadSpawn?: (startArg: number, errorOrTid?: number) => number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsChild extends ThreadManagerOptionsBase {
|
||||
childThread: true;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsMain extends ThreadManagerOptionsBase {
|
||||
beforeLoad?: (worker: WorkerLike) => any;
|
||||
reuseWorker?: boolean | number | ReuseWorkerOptions;
|
||||
onCreateWorker: WorkerFactory;
|
||||
childThread?: false;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class ThreadMessageHandler {
|
||||
protected instance: WebAssembly.Instance | undefined;
|
||||
private messagesBeforeLoad;
|
||||
protected postMessage: (message: any) => void;
|
||||
protected onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
protected onError: (error: Error, type: WorkerMessageType) => void;
|
||||
constructor(options?: ThreadMessageHandlerOptions);
|
||||
/** @virtual */
|
||||
instantiate(data: LoadPayload): WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
/** @virtual */
|
||||
handle(e: WorkerMessageEvent<MessageEventData<WorkerMessageType>>): void;
|
||||
private _load;
|
||||
private _start;
|
||||
protected _loaded(err: Error | null, source: WebAssembly.WebAssemblyInstantiatedSource | null, payload: LoadPayload): void;
|
||||
protected handleAfterLoad<E extends WorkerMessageEvent>(e: E, f: (e: E) => void): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadMessageHandlerOptions {
|
||||
onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
onError?: (error: Error, type: WorkerMessageType) => void;
|
||||
postMessage?: (message: any) => void;
|
||||
}
|
||||
|
||||
export declare const version: string;
|
||||
|
||||
/** @public */
|
||||
export declare interface WASIInstance {
|
||||
readonly wasiImport?: Record<string, any>;
|
||||
initialize(instance: object): void;
|
||||
start(instance: object): number;
|
||||
getImportObject?(): any;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class WASIThreads {
|
||||
PThread: ThreadManager | undefined;
|
||||
private wasmMemory;
|
||||
private wasmInstance;
|
||||
private readonly threadSpawn;
|
||||
readonly childThread: boolean;
|
||||
private readonly postMessage;
|
||||
readonly wasi: WASIInstance;
|
||||
constructor(options: WASIThreadsOptions);
|
||||
getImportObject(): {
|
||||
wasi: WASIThreadsImports;
|
||||
};
|
||||
setup(wasmInstance: WebAssembly.Instance, wasmModule: WebAssembly.Module, wasmMemory?: WebAssembly.Memory): void;
|
||||
preloadWorkers(): Promise<WorkerLike[]>;
|
||||
/**
|
||||
* It's ok to call this method to a WASI command module.
|
||||
*
|
||||
* in child thread, must call this method instead of {@link WASIThreads.start} even if it's a WASI command module
|
||||
*
|
||||
* @returns A proxied WebAssembly instance if in child thread, other wise the original instance
|
||||
*/
|
||||
initialize(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): WebAssembly.Instance;
|
||||
/**
|
||||
* Equivalent to calling {@link WASIThreads.initialize} and then calling {@link WASIInstance.start}
|
||||
* ```js
|
||||
* this.initialize(instance, module, memory)
|
||||
* this.wasi.start(instance)
|
||||
* ```
|
||||
*/
|
||||
start(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): StartResult;
|
||||
terminateAllThreads(): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface WASIThreadsImports {
|
||||
'thread-spawn': (startArg: number, errorOrTid?: number) => number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type WASIThreadsOptions = MainThreadOptions | ChildThreadOptions;
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerFactory = (ctx: {
|
||||
type: string;
|
||||
name: string;
|
||||
}) => WorkerLike;
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerLike = (Worker | Worker_2) & {
|
||||
whenLoaded?: Promise<WorkerLike>;
|
||||
loaded?: boolean;
|
||||
__emnapi_tid?: number;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export declare interface WorkerMessageEvent<T = any> {
|
||||
data: T;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerMessageType = 'load' | 'start';
|
||||
|
||||
export { }
|
||||
+422
@@ -0,0 +1,422 @@
|
||||
/// <reference types="node" />
|
||||
|
||||
import type { Context } from '@emnapi/runtime';
|
||||
import type { ReferenceOwnership } from '@emnapi/runtime';
|
||||
import type { Worker as Worker_2 } from 'worker_threads';
|
||||
|
||||
/** @public */
|
||||
export declare type BaseCreateOptions = {
|
||||
filename?: string
|
||||
nodeBinding?: NodeBinding
|
||||
reuseWorker?: ThreadManagerOptionsMain['reuseWorker']
|
||||
asyncWorkPoolSize?: number
|
||||
waitThreadStart?: MainThreadBaseOptions['waitThreadStart']
|
||||
onCreateWorker?: (info: CreateWorkerInfo) => any
|
||||
print?: (str: string) => void
|
||||
printErr?: (str: string) => void
|
||||
postMessage?: (msg: any) => any
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface BaseOptions {
|
||||
wasi: WASIInstance;
|
||||
version?: 'preview1';
|
||||
wasm64?: boolean;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ChildThreadOptions extends BaseOptions {
|
||||
childThread: true;
|
||||
postMessage?: (data: any) => void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CleanupThreadPayload {
|
||||
tid: number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CommandInfo<T extends CommandType> {
|
||||
type: T;
|
||||
payload: CommandPayloadMap[T];
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CommandPayloadMap {
|
||||
load: LoadPayload;
|
||||
loaded: LoadedPayload;
|
||||
start: StartPayload;
|
||||
'cleanup-thread': CleanupThreadPayload;
|
||||
'terminate-all-threads': TerminateAllThreadsPayload;
|
||||
'spawn-thread': SpawnThreadPayload;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type CommandType = keyof CommandPayloadMap;
|
||||
|
||||
/** @public */
|
||||
export declare function createInstanceProxy(instance: WebAssembly.Instance, memory?: WebAssembly.Memory | (() => WebAssembly.Memory)): WebAssembly.Instance;
|
||||
|
||||
/** @public */
|
||||
export declare function createNapiModule (
|
||||
options: CreateOptions
|
||||
): NapiModule
|
||||
|
||||
/** @public */
|
||||
export declare type CreateOptions = BaseCreateOptions & ({
|
||||
context: Context
|
||||
childThread?: boolean
|
||||
} | {
|
||||
context?: Context
|
||||
childThread: true
|
||||
})
|
||||
|
||||
/** @public */
|
||||
export declare interface CreateWorkerInfo {
|
||||
type: 'thread' | 'async-work'
|
||||
name: string
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface InitOptions {
|
||||
instance: WebAssembly.Instance
|
||||
module: WebAssembly.Module
|
||||
memory?: WebAssembly.Memory
|
||||
table?: WebAssembly.Table
|
||||
}
|
||||
|
||||
export declare type InputType = string | URL | Response | BufferSource | WebAssembly.Module;
|
||||
|
||||
/** @public */
|
||||
export declare interface InstantiatedSource extends LoadedSource {
|
||||
napiModule: NapiModule;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare function instantiateNapiModule(
|
||||
/** Only support `BufferSource` or `WebAssembly.Module` on Node.js */
|
||||
wasmInput: InputType | Promise<InputType>, options: InstantiateOptions): Promise<InstantiatedSource>;
|
||||
|
||||
/** @public */
|
||||
export declare function instantiateNapiModuleSync(wasmInput: BufferSource | WebAssembly.Module, options: InstantiateOptions): InstantiatedSource;
|
||||
|
||||
/** @public */
|
||||
export declare type InstantiateOptions = CreateOptions & LoadOptions;
|
||||
|
||||
/** @public */
|
||||
export declare function isSharedArrayBuffer(value: any): value is SharedArrayBuffer;
|
||||
|
||||
/** @public */
|
||||
export declare function isTrapError(e: Error): e is WebAssembly.RuntimeError;
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadedPayload {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadedSource extends WebAssembly.WebAssemblyInstantiatedSource {
|
||||
usedInstance: WebAssembly.Instance;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare function loadNapiModule(napiModule: NapiModule,
|
||||
/** Only support `BufferSource` or `WebAssembly.Module` on Node.js */
|
||||
wasmInput: InputType | Promise<InputType>, options?: LoadOptions): Promise<LoadedSource>;
|
||||
|
||||
/** @public */
|
||||
export declare function loadNapiModuleSync(napiModule: NapiModule, wasmInput: BufferSource | WebAssembly.Module, options?: LoadOptions): LoadedSource;
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadOptions {
|
||||
wasi?: WASIInstance;
|
||||
overwriteImports?: (importObject: WebAssembly.Imports) => WebAssembly.Imports;
|
||||
beforeInit?: (source: WebAssembly.WebAssemblyInstantiatedSource) => void;
|
||||
getMemory?: (exports: WebAssembly.Exports) => WebAssembly.Memory;
|
||||
getTable?: (exports: WebAssembly.Exports) => WebAssembly.Table;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadPayload {
|
||||
wasmModule: WebAssembly.Module;
|
||||
wasmMemory: WebAssembly.Memory;
|
||||
sab?: Int32Array;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadBaseOptions extends BaseOptions {
|
||||
waitThreadStart?: boolean | number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type MainThreadOptions = MainThreadOptionsWithThreadManager | MainThreadOptionsCreateThreadManager;
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadOptionsCreateThreadManager extends MainThreadBaseOptions, ThreadManagerOptionsMain {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadOptionsWithThreadManager extends MainThreadBaseOptions {
|
||||
threadManager?: ThreadManager | (() => ThreadManager);
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MessageEventData<T extends CommandType> {
|
||||
__emnapi__: CommandInfo<T>;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class MessageHandler extends ThreadMessageHandler {
|
||||
napiModule: NapiModule | undefined;
|
||||
constructor(options: MessageHandlerOptions);
|
||||
instantiate(data: LoadPayload): InstantiatedSource | PromiseLike<InstantiatedSource>;
|
||||
handle(e: WorkerMessageEvent): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MessageHandlerOptions extends ThreadMessageHandlerOptions {
|
||||
onLoad: (data: LoadPayload) => InstantiatedSource | PromiseLike<InstantiatedSource>;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface NapiModule {
|
||||
imports: {
|
||||
env: any
|
||||
napi: any
|
||||
emnapi: any
|
||||
}
|
||||
exports: any
|
||||
loaded: boolean
|
||||
filename: string
|
||||
childThread: boolean
|
||||
emnapi: {
|
||||
syncMemory<T extends ArrayBuffer | ArrayBufferView> (
|
||||
js_to_wasm: boolean,
|
||||
arrayBufferOrView: T,
|
||||
offset?: number,
|
||||
len?: number
|
||||
): T
|
||||
getMemoryAddress (arrayBufferOrView: ArrayBuffer | ArrayBufferView): PointerInfo
|
||||
addSendListener (worker: any): boolean
|
||||
}
|
||||
|
||||
init (options: InitOptions): any
|
||||
initWorker (arg: number, func: [number, number]): void
|
||||
postMessage?: (msg: any) => any
|
||||
|
||||
waitThreadStart: boolean | number
|
||||
/* Excluded from this release type: PThread */}
|
||||
|
||||
/** @public */
|
||||
export declare interface NodeBinding {
|
||||
node: {
|
||||
emitAsyncInit: Function
|
||||
emitAsyncDestroy: Function
|
||||
makeCallback: Function
|
||||
}
|
||||
napi: {
|
||||
asyncInit: Function
|
||||
asyncDestroy: Function
|
||||
makeCallback: Function
|
||||
}
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface PointerInfo {
|
||||
address: number
|
||||
ownership: ReferenceOwnership
|
||||
runtimeAllocated: 0 | 1
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ReuseWorkerOptions {
|
||||
/**
|
||||
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size | PTHREAD_POOL_SIZE}
|
||||
*/
|
||||
size: number;
|
||||
/**
|
||||
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size-strict | PTHREAD_POOL_SIZE_STRICT}
|
||||
*/
|
||||
strict?: boolean;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface SpawnThreadPayload {
|
||||
startArg: number;
|
||||
errorOrTid: number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface StartPayload {
|
||||
tid: number;
|
||||
arg: number;
|
||||
sab?: Int32Array;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface StartResult {
|
||||
exitCode: number;
|
||||
instance: WebAssembly.Instance;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface TerminateAllThreadsPayload {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class ThreadManager {
|
||||
unusedWorkers: WorkerLike[];
|
||||
runningWorkers: WorkerLike[];
|
||||
pthreads: Record<number, WorkerLike>;
|
||||
get nextWorkerID(): number;
|
||||
wasmModule: WebAssembly.Module | null;
|
||||
wasmMemory: WebAssembly.Memory | null;
|
||||
private readonly messageEvents;
|
||||
private readonly _childThread;
|
||||
private readonly _onCreateWorker;
|
||||
private readonly _reuseWorker;
|
||||
private readonly _beforeLoad?;
|
||||
/* Excluded from this release type: printErr */
|
||||
threadSpawn?: ((startArg: number, errorOrTid?: number) => number);
|
||||
constructor(options: ThreadManagerOptions);
|
||||
init(): void;
|
||||
initMainThread(): void;
|
||||
private preparePool;
|
||||
shouldPreloadWorkers(): boolean;
|
||||
loadWasmModuleToAllWorkers(): Promise<WorkerLike[]>;
|
||||
preloadWorkers(): Promise<WorkerLike[]>;
|
||||
setup(wasmModule: WebAssembly.Module, wasmMemory: WebAssembly.Memory): void;
|
||||
markId(worker: WorkerLike): number;
|
||||
returnWorkerToPool(worker: WorkerLike): void;
|
||||
loadWasmModuleToWorker(worker: WorkerLike, sab?: Int32Array): Promise<WorkerLike>;
|
||||
allocateUnusedWorker(): WorkerLike;
|
||||
getNewWorker(sab?: Int32Array): WorkerLike | undefined;
|
||||
cleanThread(worker: WorkerLike, tid: number, force?: boolean): void;
|
||||
terminateWorker(worker: WorkerLike): void;
|
||||
terminateAllThreads(): void;
|
||||
addMessageEventListener(worker: WorkerLike, onMessage: (e: WorkerMessageEvent) => void): () => void;
|
||||
fireMessageEvent(worker: WorkerLike, e: WorkerMessageEvent): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type ThreadManagerOptions = ThreadManagerOptionsMain | ThreadManagerOptionsChild;
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsBase {
|
||||
printErr?: (message: string) => void;
|
||||
threadSpawn?: (startArg: number, errorOrTid?: number) => number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsChild extends ThreadManagerOptionsBase {
|
||||
childThread: true;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsMain extends ThreadManagerOptionsBase {
|
||||
beforeLoad?: (worker: WorkerLike) => any;
|
||||
reuseWorker?: boolean | number | ReuseWorkerOptions;
|
||||
onCreateWorker: WorkerFactory;
|
||||
childThread?: false;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class ThreadMessageHandler {
|
||||
protected instance: WebAssembly.Instance | undefined;
|
||||
private messagesBeforeLoad;
|
||||
protected postMessage: (message: any) => void;
|
||||
protected onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
protected onError: (error: Error, type: WorkerMessageType) => void;
|
||||
constructor(options?: ThreadMessageHandlerOptions);
|
||||
/** @virtual */
|
||||
instantiate(data: LoadPayload): WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
/** @virtual */
|
||||
handle(e: WorkerMessageEvent<MessageEventData<WorkerMessageType>>): void;
|
||||
private _load;
|
||||
private _start;
|
||||
protected _loaded(err: Error | null, source: WebAssembly.WebAssemblyInstantiatedSource | null, payload: LoadPayload): void;
|
||||
protected handleAfterLoad<E extends WorkerMessageEvent>(e: E, f: (e: E) => void): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadMessageHandlerOptions {
|
||||
onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
onError?: (error: Error, type: WorkerMessageType) => void;
|
||||
postMessage?: (message: any) => void;
|
||||
}
|
||||
|
||||
export declare const version: string;
|
||||
|
||||
/** @public */
|
||||
export declare interface WASIInstance {
|
||||
readonly wasiImport?: Record<string, any>;
|
||||
initialize(instance: object): void;
|
||||
start(instance: object): number;
|
||||
getImportObject?(): any;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class WASIThreads {
|
||||
PThread: ThreadManager | undefined;
|
||||
private wasmMemory;
|
||||
private wasmInstance;
|
||||
private readonly threadSpawn;
|
||||
readonly childThread: boolean;
|
||||
private readonly postMessage;
|
||||
readonly wasi: WASIInstance;
|
||||
constructor(options: WASIThreadsOptions);
|
||||
getImportObject(): {
|
||||
wasi: WASIThreadsImports;
|
||||
};
|
||||
setup(wasmInstance: WebAssembly.Instance, wasmModule: WebAssembly.Module, wasmMemory?: WebAssembly.Memory): void;
|
||||
preloadWorkers(): Promise<WorkerLike[]>;
|
||||
/**
|
||||
* It's ok to call this method to a WASI command module.
|
||||
*
|
||||
* in child thread, must call this method instead of {@link WASIThreads.start} even if it's a WASI command module
|
||||
*
|
||||
* @returns A proxied WebAssembly instance if in child thread, other wise the original instance
|
||||
*/
|
||||
initialize(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): WebAssembly.Instance;
|
||||
/**
|
||||
* Equivalent to calling {@link WASIThreads.initialize} and then calling {@link WASIInstance.start}
|
||||
* ```js
|
||||
* this.initialize(instance, module, memory)
|
||||
* this.wasi.start(instance)
|
||||
* ```
|
||||
*/
|
||||
start(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): StartResult;
|
||||
terminateAllThreads(): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface WASIThreadsImports {
|
||||
'thread-spawn': (startArg: number, errorOrTid?: number) => number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type WASIThreadsOptions = MainThreadOptions | ChildThreadOptions;
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerFactory = (ctx: {
|
||||
type: string;
|
||||
name: string;
|
||||
}) => WorkerLike;
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerLike = (Worker | Worker_2) & {
|
||||
whenLoaded?: Promise<WorkerLike>;
|
||||
loaded?: boolean;
|
||||
__emnapi_tid?: number;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export declare interface WorkerMessageEvent<T = any> {
|
||||
data: T;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerMessageType = 'load' | 'start';
|
||||
|
||||
export { }
|
||||
|
||||
export as namespace emnapiCore;
|
||||
+8228
File diff suppressed because it is too large
Load Diff
+9231
File diff suppressed because it is too large
Load Diff
+420
@@ -0,0 +1,420 @@
|
||||
/// <reference types="node" />
|
||||
|
||||
import type { Context } from '@emnapi/runtime';
|
||||
import type { ReferenceOwnership } from '@emnapi/runtime';
|
||||
import type { Worker as Worker_2 } from 'worker_threads';
|
||||
|
||||
/** @public */
|
||||
export declare type BaseCreateOptions = {
|
||||
filename?: string
|
||||
nodeBinding?: NodeBinding
|
||||
reuseWorker?: ThreadManagerOptionsMain['reuseWorker']
|
||||
asyncWorkPoolSize?: number
|
||||
waitThreadStart?: MainThreadBaseOptions['waitThreadStart']
|
||||
onCreateWorker?: (info: CreateWorkerInfo) => any
|
||||
print?: (str: string) => void
|
||||
printErr?: (str: string) => void
|
||||
postMessage?: (msg: any) => any
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface BaseOptions {
|
||||
wasi: WASIInstance;
|
||||
version?: 'preview1';
|
||||
wasm64?: boolean;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ChildThreadOptions extends BaseOptions {
|
||||
childThread: true;
|
||||
postMessage?: (data: any) => void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CleanupThreadPayload {
|
||||
tid: number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CommandInfo<T extends CommandType> {
|
||||
type: T;
|
||||
payload: CommandPayloadMap[T];
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CommandPayloadMap {
|
||||
load: LoadPayload;
|
||||
loaded: LoadedPayload;
|
||||
start: StartPayload;
|
||||
'cleanup-thread': CleanupThreadPayload;
|
||||
'terminate-all-threads': TerminateAllThreadsPayload;
|
||||
'spawn-thread': SpawnThreadPayload;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type CommandType = keyof CommandPayloadMap;
|
||||
|
||||
/** @public */
|
||||
export declare function createInstanceProxy(instance: WebAssembly.Instance, memory?: WebAssembly.Memory | (() => WebAssembly.Memory)): WebAssembly.Instance;
|
||||
|
||||
/** @public */
|
||||
export declare function createNapiModule (
|
||||
options: CreateOptions
|
||||
): NapiModule
|
||||
|
||||
/** @public */
|
||||
export declare type CreateOptions = BaseCreateOptions & ({
|
||||
context: Context
|
||||
childThread?: boolean
|
||||
} | {
|
||||
context?: Context
|
||||
childThread: true
|
||||
})
|
||||
|
||||
/** @public */
|
||||
export declare interface CreateWorkerInfo {
|
||||
type: 'thread' | 'async-work'
|
||||
name: string
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface InitOptions {
|
||||
instance: WebAssembly.Instance
|
||||
module: WebAssembly.Module
|
||||
memory?: WebAssembly.Memory
|
||||
table?: WebAssembly.Table
|
||||
}
|
||||
|
||||
export declare type InputType = string | URL | Response | BufferSource | WebAssembly.Module;
|
||||
|
||||
/** @public */
|
||||
export declare interface InstantiatedSource extends LoadedSource {
|
||||
napiModule: NapiModule;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare function instantiateNapiModule(
|
||||
/** Only support `BufferSource` or `WebAssembly.Module` on Node.js */
|
||||
wasmInput: InputType | Promise<InputType>, options: InstantiateOptions): Promise<InstantiatedSource>;
|
||||
|
||||
/** @public */
|
||||
export declare function instantiateNapiModuleSync(wasmInput: BufferSource | WebAssembly.Module, options: InstantiateOptions): InstantiatedSource;
|
||||
|
||||
/** @public */
|
||||
export declare type InstantiateOptions = CreateOptions & LoadOptions;
|
||||
|
||||
/** @public */
|
||||
export declare function isSharedArrayBuffer(value: any): value is SharedArrayBuffer;
|
||||
|
||||
/** @public */
|
||||
export declare function isTrapError(e: Error): e is WebAssembly.RuntimeError;
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadedPayload {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadedSource extends WebAssembly.WebAssemblyInstantiatedSource {
|
||||
usedInstance: WebAssembly.Instance;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare function loadNapiModule(napiModule: NapiModule,
|
||||
/** Only support `BufferSource` or `WebAssembly.Module` on Node.js */
|
||||
wasmInput: InputType | Promise<InputType>, options?: LoadOptions): Promise<LoadedSource>;
|
||||
|
||||
/** @public */
|
||||
export declare function loadNapiModuleSync(napiModule: NapiModule, wasmInput: BufferSource | WebAssembly.Module, options?: LoadOptions): LoadedSource;
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadOptions {
|
||||
wasi?: WASIInstance;
|
||||
overwriteImports?: (importObject: WebAssembly.Imports) => WebAssembly.Imports;
|
||||
beforeInit?: (source: WebAssembly.WebAssemblyInstantiatedSource) => void;
|
||||
getMemory?: (exports: WebAssembly.Exports) => WebAssembly.Memory;
|
||||
getTable?: (exports: WebAssembly.Exports) => WebAssembly.Table;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadPayload {
|
||||
wasmModule: WebAssembly.Module;
|
||||
wasmMemory: WebAssembly.Memory;
|
||||
sab?: Int32Array;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadBaseOptions extends BaseOptions {
|
||||
waitThreadStart?: boolean | number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type MainThreadOptions = MainThreadOptionsWithThreadManager | MainThreadOptionsCreateThreadManager;
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadOptionsCreateThreadManager extends MainThreadBaseOptions, ThreadManagerOptionsMain {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadOptionsWithThreadManager extends MainThreadBaseOptions {
|
||||
threadManager?: ThreadManager | (() => ThreadManager);
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MessageEventData<T extends CommandType> {
|
||||
__emnapi__: CommandInfo<T>;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class MessageHandler extends ThreadMessageHandler {
|
||||
napiModule: NapiModule | undefined;
|
||||
constructor(options: MessageHandlerOptions);
|
||||
instantiate(data: LoadPayload): InstantiatedSource | PromiseLike<InstantiatedSource>;
|
||||
handle(e: WorkerMessageEvent): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MessageHandlerOptions extends ThreadMessageHandlerOptions {
|
||||
onLoad: (data: LoadPayload) => InstantiatedSource | PromiseLike<InstantiatedSource>;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface NapiModule {
|
||||
imports: {
|
||||
env: any
|
||||
napi: any
|
||||
emnapi: any
|
||||
}
|
||||
exports: any
|
||||
loaded: boolean
|
||||
filename: string
|
||||
childThread: boolean
|
||||
emnapi: {
|
||||
syncMemory<T extends ArrayBuffer | ArrayBufferView> (
|
||||
js_to_wasm: boolean,
|
||||
arrayBufferOrView: T,
|
||||
offset?: number,
|
||||
len?: number
|
||||
): T
|
||||
getMemoryAddress (arrayBufferOrView: ArrayBuffer | ArrayBufferView): PointerInfo
|
||||
addSendListener (worker: any): boolean
|
||||
}
|
||||
|
||||
init (options: InitOptions): any
|
||||
initWorker (arg: number, func: [number, number]): void
|
||||
postMessage?: (msg: any) => any
|
||||
|
||||
waitThreadStart: boolean | number
|
||||
/* Excluded from this release type: PThread */}
|
||||
|
||||
/** @public */
|
||||
export declare interface NodeBinding {
|
||||
node: {
|
||||
emitAsyncInit: Function
|
||||
emitAsyncDestroy: Function
|
||||
makeCallback: Function
|
||||
}
|
||||
napi: {
|
||||
asyncInit: Function
|
||||
asyncDestroy: Function
|
||||
makeCallback: Function
|
||||
}
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface PointerInfo {
|
||||
address: number
|
||||
ownership: ReferenceOwnership
|
||||
runtimeAllocated: 0 | 1
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ReuseWorkerOptions {
|
||||
/**
|
||||
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size | PTHREAD_POOL_SIZE}
|
||||
*/
|
||||
size: number;
|
||||
/**
|
||||
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size-strict | PTHREAD_POOL_SIZE_STRICT}
|
||||
*/
|
||||
strict?: boolean;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface SpawnThreadPayload {
|
||||
startArg: number;
|
||||
errorOrTid: number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface StartPayload {
|
||||
tid: number;
|
||||
arg: number;
|
||||
sab?: Int32Array;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface StartResult {
|
||||
exitCode: number;
|
||||
instance: WebAssembly.Instance;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface TerminateAllThreadsPayload {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class ThreadManager {
|
||||
unusedWorkers: WorkerLike[];
|
||||
runningWorkers: WorkerLike[];
|
||||
pthreads: Record<number, WorkerLike>;
|
||||
get nextWorkerID(): number;
|
||||
wasmModule: WebAssembly.Module | null;
|
||||
wasmMemory: WebAssembly.Memory | null;
|
||||
private readonly messageEvents;
|
||||
private readonly _childThread;
|
||||
private readonly _onCreateWorker;
|
||||
private readonly _reuseWorker;
|
||||
private readonly _beforeLoad?;
|
||||
/* Excluded from this release type: printErr */
|
||||
threadSpawn?: ((startArg: number, errorOrTid?: number) => number);
|
||||
constructor(options: ThreadManagerOptions);
|
||||
init(): void;
|
||||
initMainThread(): void;
|
||||
private preparePool;
|
||||
shouldPreloadWorkers(): boolean;
|
||||
loadWasmModuleToAllWorkers(): Promise<WorkerLike[]>;
|
||||
preloadWorkers(): Promise<WorkerLike[]>;
|
||||
setup(wasmModule: WebAssembly.Module, wasmMemory: WebAssembly.Memory): void;
|
||||
markId(worker: WorkerLike): number;
|
||||
returnWorkerToPool(worker: WorkerLike): void;
|
||||
loadWasmModuleToWorker(worker: WorkerLike, sab?: Int32Array): Promise<WorkerLike>;
|
||||
allocateUnusedWorker(): WorkerLike;
|
||||
getNewWorker(sab?: Int32Array): WorkerLike | undefined;
|
||||
cleanThread(worker: WorkerLike, tid: number, force?: boolean): void;
|
||||
terminateWorker(worker: WorkerLike): void;
|
||||
terminateAllThreads(): void;
|
||||
addMessageEventListener(worker: WorkerLike, onMessage: (e: WorkerMessageEvent) => void): () => void;
|
||||
fireMessageEvent(worker: WorkerLike, e: WorkerMessageEvent): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type ThreadManagerOptions = ThreadManagerOptionsMain | ThreadManagerOptionsChild;
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsBase {
|
||||
printErr?: (message: string) => void;
|
||||
threadSpawn?: (startArg: number, errorOrTid?: number) => number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsChild extends ThreadManagerOptionsBase {
|
||||
childThread: true;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsMain extends ThreadManagerOptionsBase {
|
||||
beforeLoad?: (worker: WorkerLike) => any;
|
||||
reuseWorker?: boolean | number | ReuseWorkerOptions;
|
||||
onCreateWorker: WorkerFactory;
|
||||
childThread?: false;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class ThreadMessageHandler {
|
||||
protected instance: WebAssembly.Instance | undefined;
|
||||
private messagesBeforeLoad;
|
||||
protected postMessage: (message: any) => void;
|
||||
protected onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
protected onError: (error: Error, type: WorkerMessageType) => void;
|
||||
constructor(options?: ThreadMessageHandlerOptions);
|
||||
/** @virtual */
|
||||
instantiate(data: LoadPayload): WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
/** @virtual */
|
||||
handle(e: WorkerMessageEvent<MessageEventData<WorkerMessageType>>): void;
|
||||
private _load;
|
||||
private _start;
|
||||
protected _loaded(err: Error | null, source: WebAssembly.WebAssemblyInstantiatedSource | null, payload: LoadPayload): void;
|
||||
protected handleAfterLoad<E extends WorkerMessageEvent>(e: E, f: (e: E) => void): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadMessageHandlerOptions {
|
||||
onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
onError?: (error: Error, type: WorkerMessageType) => void;
|
||||
postMessage?: (message: any) => void;
|
||||
}
|
||||
|
||||
export declare const version: string;
|
||||
|
||||
/** @public */
|
||||
export declare interface WASIInstance {
|
||||
readonly wasiImport?: Record<string, any>;
|
||||
initialize(instance: object): void;
|
||||
start(instance: object): number;
|
||||
getImportObject?(): any;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class WASIThreads {
|
||||
PThread: ThreadManager | undefined;
|
||||
private wasmMemory;
|
||||
private wasmInstance;
|
||||
private readonly threadSpawn;
|
||||
readonly childThread: boolean;
|
||||
private readonly postMessage;
|
||||
readonly wasi: WASIInstance;
|
||||
constructor(options: WASIThreadsOptions);
|
||||
getImportObject(): {
|
||||
wasi: WASIThreadsImports;
|
||||
};
|
||||
setup(wasmInstance: WebAssembly.Instance, wasmModule: WebAssembly.Module, wasmMemory?: WebAssembly.Memory): void;
|
||||
preloadWorkers(): Promise<WorkerLike[]>;
|
||||
/**
|
||||
* It's ok to call this method to a WASI command module.
|
||||
*
|
||||
* in child thread, must call this method instead of {@link WASIThreads.start} even if it's a WASI command module
|
||||
*
|
||||
* @returns A proxied WebAssembly instance if in child thread, other wise the original instance
|
||||
*/
|
||||
initialize(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): WebAssembly.Instance;
|
||||
/**
|
||||
* Equivalent to calling {@link WASIThreads.initialize} and then calling {@link WASIInstance.start}
|
||||
* ```js
|
||||
* this.initialize(instance, module, memory)
|
||||
* this.wasi.start(instance)
|
||||
* ```
|
||||
*/
|
||||
start(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): StartResult;
|
||||
terminateAllThreads(): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface WASIThreadsImports {
|
||||
'thread-spawn': (startArg: number, errorOrTid?: number) => number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type WASIThreadsOptions = MainThreadOptions | ChildThreadOptions;
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerFactory = (ctx: {
|
||||
type: string;
|
||||
name: string;
|
||||
}) => WorkerLike;
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerLike = (Worker | Worker_2) & {
|
||||
whenLoaded?: Promise<WorkerLike>;
|
||||
loaded?: boolean;
|
||||
__emnapi_tid?: number;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export declare interface WorkerMessageEvent<T = any> {
|
||||
data: T;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerMessageType = 'load' | 'start';
|
||||
|
||||
export { }
|
||||
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+7386
File diff suppressed because it is too large
Load Diff
+5
@@ -0,0 +1,5 @@
|
||||
if (typeof process !== 'undefined' && process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./dist/emnapi-core.cjs.min.js')
|
||||
} else {
|
||||
module.exports = require('./dist/emnapi-core.cjs.js')
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "@emnapi/core",
|
||||
"version": "1.10.0",
|
||||
"description": "emnapi core",
|
||||
"main": "index.js",
|
||||
"module": "./dist/emnapi-core.esm-bundler.js",
|
||||
"types": "./dist/emnapi-core.d.ts",
|
||||
"sideEffects": false,
|
||||
"exports": {
|
||||
".": {
|
||||
"types": {
|
||||
"module": "./dist/emnapi-core.d.ts",
|
||||
"import": "./dist/emnapi-core.d.mts",
|
||||
"default": "./dist/emnapi-core.d.ts"
|
||||
},
|
||||
"module": "./dist/emnapi-core.esm-bundler.js",
|
||||
"import": "./dist/emnapi-core.mjs",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./dist/emnapi-core.cjs.min": {
|
||||
"types": "./dist/emnapi-core.d.ts",
|
||||
"default": "./dist/emnapi-core.cjs.min.js"
|
||||
},
|
||||
"./dist/emnapi-core.min.mjs": {
|
||||
"types": "./dist/emnapi-core.d.mts",
|
||||
"default": "./dist/emnapi-core.min.mjs"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@emnapi/wasi-threads": "1.2.1",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "node ./script/build.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/toyobayashi/emnapi.git"
|
||||
},
|
||||
"author": "toyobayashi",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/toyobayashi/emnapi/issues"
|
||||
},
|
||||
"homepage": "https://github.com/toyobayashi/emnapi#readme",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-present Toyobayashi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+1
@@ -0,0 +1 @@
|
||||
See [https://github.com/toyobayashi/emnapi](https://github.com/toyobayashi/emnapi)
|
||||
+1381
File diff suppressed because it is too large
Load Diff
+671
@@ -0,0 +1,671 @@
|
||||
export declare type Ptr = number | bigint
|
||||
|
||||
export declare interface IBuffer extends Uint8Array {}
|
||||
export declare interface BufferCtor {
|
||||
readonly prototype: IBuffer
|
||||
/** @deprecated */
|
||||
new (...args: any[]): IBuffer
|
||||
from: {
|
||||
(buffer: ArrayBufferLike): IBuffer
|
||||
(buffer: ArrayBufferLike, byteOffset: number, length: number): IBuffer
|
||||
}
|
||||
alloc: (size: number) => IBuffer
|
||||
isBuffer: (obj: unknown) => obj is IBuffer
|
||||
}
|
||||
|
||||
export declare const enum GlobalHandle {
|
||||
UNDEFINED = 1,
|
||||
NULL,
|
||||
FALSE,
|
||||
TRUE,
|
||||
GLOBAL
|
||||
}
|
||||
|
||||
export declare const enum Version {
|
||||
NODE_API_SUPPORTED_VERSION_MIN = 1,
|
||||
NODE_API_DEFAULT_MODULE_API_VERSION = 8,
|
||||
NODE_API_SUPPORTED_VERSION_MAX = 10,
|
||||
NAPI_VERSION_EXPERIMENTAL = 2147483647 // INT_MAX
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export declare type Pointer<T> = number
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export declare type PointerPointer<T> = number
|
||||
export declare type FunctionPointer<T extends (...args: any[]) => any> = Pointer<T>
|
||||
export declare type Const<T> = T
|
||||
|
||||
export declare type void_p = Pointer<void>
|
||||
export declare type void_pp = Pointer<void_p>
|
||||
export declare type bool = number
|
||||
export declare type char = number
|
||||
export declare type char_p = Pointer<char>
|
||||
export declare type unsigned_char = number
|
||||
export declare type const_char = Const<char>
|
||||
export declare type const_char_p = Pointer<const_char>
|
||||
export declare type char16_t_p = number
|
||||
export declare type const_char16_t_p = number
|
||||
|
||||
export declare type short = number
|
||||
export declare type unsigned_short = number
|
||||
export declare type int = number
|
||||
export declare type unsigned_int = number
|
||||
export declare type long = number
|
||||
export declare type unsigned_long = number
|
||||
export declare type long_long = bigint
|
||||
export declare type unsigned_long_long = bigint
|
||||
export declare type float = number
|
||||
export declare type double = number
|
||||
export declare type long_double = number
|
||||
export declare type size_t = number
|
||||
|
||||
export declare type int8_t = number
|
||||
export declare type uint8_t = number
|
||||
export declare type int16_t = number
|
||||
export declare type uint16_t = number
|
||||
export declare type int32_t = number
|
||||
export declare type uint32_t = number
|
||||
export declare type int64_t = bigint
|
||||
export declare type uint64_t = bigint
|
||||
export declare type napi_env = Pointer<unknown>
|
||||
|
||||
export declare type napi_value = Pointer<unknown>
|
||||
export declare type napi_ref = Pointer<unknown>
|
||||
export declare type napi_deferred = Pointer<unknown>
|
||||
export declare type napi_handle_scope = Pointer<unknown>
|
||||
export declare type napi_escapable_handle_scope = Pointer<unknown>
|
||||
|
||||
export declare type napi_addon_register_func = FunctionPointer<(env: napi_env, exports: napi_value) => napi_value>
|
||||
|
||||
export declare type napi_callback_info = Pointer<unknown>
|
||||
export declare type napi_callback = FunctionPointer<(env: napi_env, info: napi_callback_info) => napi_value>
|
||||
|
||||
export declare interface napi_extended_error_info {
|
||||
error_message: const_char_p
|
||||
engine_reserved: void_p
|
||||
engine_error_code: uint32_t
|
||||
error_code: napi_status
|
||||
}
|
||||
|
||||
export declare interface napi_property_descriptor {
|
||||
// One of utf8name or name should be NULL.
|
||||
utf8name: const_char_p
|
||||
name: napi_value
|
||||
|
||||
method: napi_callback
|
||||
getter: napi_callback
|
||||
setter: napi_callback
|
||||
value: napi_value
|
||||
/* napi_property_attributes */
|
||||
attributes: number
|
||||
data: void_p
|
||||
}
|
||||
|
||||
export declare type napi_finalize = FunctionPointer<(
|
||||
env: napi_env,
|
||||
finalize_data: void_p,
|
||||
finalize_hint: void_p
|
||||
) => void>
|
||||
|
||||
export declare interface node_module {
|
||||
nm_version: int32_t
|
||||
nm_flags: uint32_t
|
||||
nm_filename: Pointer<const_char>
|
||||
nm_register_func: napi_addon_register_func
|
||||
nm_modname: Pointer<const_char>
|
||||
nm_priv: Pointer<void>
|
||||
reserved: PointerPointer<void>
|
||||
}
|
||||
|
||||
export declare interface napi_node_version {
|
||||
major: uint32_t
|
||||
minor: uint32_t
|
||||
patch: uint32_t
|
||||
release: const_char_p
|
||||
}
|
||||
|
||||
export declare interface emnapi_emscripten_version {
|
||||
major: uint32_t
|
||||
minor: uint32_t
|
||||
patch: uint32_t
|
||||
}
|
||||
|
||||
export declare const enum napi_status {
|
||||
napi_ok,
|
||||
napi_invalid_arg,
|
||||
napi_object_expected,
|
||||
napi_string_expected,
|
||||
napi_name_expected,
|
||||
napi_function_expected,
|
||||
napi_number_expected,
|
||||
napi_boolean_expected,
|
||||
napi_array_expected,
|
||||
napi_generic_failure,
|
||||
napi_pending_exception,
|
||||
napi_cancelled,
|
||||
napi_escape_called_twice,
|
||||
napi_handle_scope_mismatch,
|
||||
napi_callback_scope_mismatch,
|
||||
napi_queue_full,
|
||||
napi_closing,
|
||||
napi_bigint_expected,
|
||||
napi_date_expected,
|
||||
napi_arraybuffer_expected,
|
||||
napi_detachable_arraybuffer_expected,
|
||||
napi_would_deadlock, // unused
|
||||
napi_no_external_buffers_allowed,
|
||||
napi_cannot_run_js
|
||||
}
|
||||
|
||||
export declare const enum napi_property_attributes {
|
||||
napi_default = 0,
|
||||
napi_writable = 1 << 0,
|
||||
napi_enumerable = 1 << 1,
|
||||
napi_configurable = 1 << 2,
|
||||
|
||||
// Used with napi_define_class to distinguish static properties
|
||||
// from instance properties. Ignored by napi_define_properties.
|
||||
napi_static = 1 << 10,
|
||||
|
||||
/// #ifdef NAPI_EXPERIMENTAL
|
||||
// Default for class methods.
|
||||
napi_default_method = napi_writable | napi_configurable,
|
||||
|
||||
// Default for object properties, like in JS obj[prop].
|
||||
napi_default_jsproperty = napi_writable | napi_enumerable | napi_configurable
|
||||
/// #endif // NAPI_EXPERIMENTAL
|
||||
}
|
||||
|
||||
export declare const enum napi_valuetype {
|
||||
napi_undefined,
|
||||
napi_null,
|
||||
napi_boolean,
|
||||
napi_number,
|
||||
napi_string,
|
||||
napi_symbol,
|
||||
napi_object,
|
||||
napi_function,
|
||||
napi_external,
|
||||
napi_bigint
|
||||
}
|
||||
|
||||
export declare const enum napi_typedarray_type {
|
||||
napi_int8_array,
|
||||
napi_uint8_array,
|
||||
napi_uint8_clamped_array,
|
||||
napi_int16_array,
|
||||
napi_uint16_array,
|
||||
napi_int32_array,
|
||||
napi_uint32_array,
|
||||
napi_float32_array,
|
||||
napi_float64_array,
|
||||
napi_bigint64_array,
|
||||
napi_biguint64_array,
|
||||
napi_float16_array,
|
||||
}
|
||||
|
||||
export declare const enum napi_key_collection_mode {
|
||||
napi_key_include_prototypes,
|
||||
napi_key_own_only
|
||||
}
|
||||
|
||||
export declare const enum napi_key_filter {
|
||||
napi_key_all_properties = 0,
|
||||
napi_key_writable = 1,
|
||||
napi_key_enumerable = 1 << 1,
|
||||
napi_key_configurable = 1 << 2,
|
||||
napi_key_skip_strings = 1 << 3,
|
||||
napi_key_skip_symbols = 1 << 4
|
||||
}
|
||||
|
||||
export declare const enum napi_key_conversion {
|
||||
napi_key_keep_numbers,
|
||||
napi_key_numbers_to_strings
|
||||
}
|
||||
|
||||
export declare const enum emnapi_memory_view_type {
|
||||
emnapi_int8_array,
|
||||
emnapi_uint8_array,
|
||||
emnapi_uint8_clamped_array,
|
||||
emnapi_int16_array,
|
||||
emnapi_uint16_array,
|
||||
emnapi_int32_array,
|
||||
emnapi_uint32_array,
|
||||
emnapi_float32_array,
|
||||
emnapi_float64_array,
|
||||
emnapi_bigint64_array,
|
||||
emnapi_biguint64_array,
|
||||
emnapi_float16_array,
|
||||
emnapi_data_view = -1,
|
||||
emnapi_buffer = -2
|
||||
}
|
||||
|
||||
export declare const enum napi_threadsafe_function_call_mode {
|
||||
napi_tsfn_nonblocking,
|
||||
napi_tsfn_blocking
|
||||
}
|
||||
|
||||
export declare const enum napi_threadsafe_function_release_mode {
|
||||
napi_tsfn_release,
|
||||
napi_tsfn_abort
|
||||
}
|
||||
export declare type CleanupHookCallbackFunction = number | ((arg: number) => void);
|
||||
|
||||
export declare class ConstHandle<S extends undefined | null | boolean | typeof globalThis> extends Handle<S> {
|
||||
constructor(id: number, value: S);
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class Context {
|
||||
private _isStopping;
|
||||
private _canCallIntoJs;
|
||||
private _suppressDestroy;
|
||||
envStore: Store<Env>;
|
||||
scopeStore: ScopeStore;
|
||||
refStore: Store<Reference>;
|
||||
deferredStore: Store<Deferred<any>>;
|
||||
handleStore: HandleStore;
|
||||
private readonly refCounter?;
|
||||
private readonly cleanupQueue;
|
||||
private readonly _externalMemory;
|
||||
feature: {
|
||||
supportReflect: boolean;
|
||||
supportFinalizer: boolean;
|
||||
supportWeakSymbol: boolean;
|
||||
supportBigInt: boolean;
|
||||
supportNewFunction: boolean;
|
||||
canSetFunctionName: boolean;
|
||||
setImmediate: (callback: () => void) => void;
|
||||
Buffer: BufferCtor | undefined;
|
||||
MessageChannel: {
|
||||
new (): MessageChannel;
|
||||
prototype: MessageChannel;
|
||||
} | undefined;
|
||||
};
|
||||
constructor(options?: ContextOptions);
|
||||
/**
|
||||
* Suppress the destroy on `beforeExit` event in Node.js.
|
||||
* Call this method if you want to keep the context and
|
||||
* all associated {@link Env | Env} alive,
|
||||
* this also means that cleanup hooks will not be called.
|
||||
* After call this method, you should call
|
||||
* {@link Context.destroy | `Context.prototype.destroy`} method manually.
|
||||
*/
|
||||
suppressDestroy(): void;
|
||||
getRuntimeVersions(): {
|
||||
version: string;
|
||||
NODE_API_SUPPORTED_VERSION_MAX: Version;
|
||||
NAPI_VERSION_EXPERIMENTAL: Version;
|
||||
NODE_API_DEFAULT_MODULE_API_VERSION: Version;
|
||||
};
|
||||
createNotSupportWeakRefError(api: string, message: string): NotSupportWeakRefError;
|
||||
createNotSupportBufferError(api: string, message: string): NotSupportBufferError;
|
||||
createReference(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership): Reference;
|
||||
createReferenceWithData(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): Reference;
|
||||
createReferenceWithFinalizer(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback?: napi_finalize, finalize_data?: void_p, finalize_hint?: void_p): Reference;
|
||||
createDeferred<T = any>(value: IDeferrdValue<T>): Deferred<T>;
|
||||
adjustAmountOfExternalAllocatedMemory(changeInBytes: number | bigint): bigint;
|
||||
createEnv(filename: string, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never, nodeBinding?: any): Env;
|
||||
createTrackedFinalizer(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
|
||||
getCurrentScope(): HandleScope | null;
|
||||
addToCurrentScope<V>(value: V): Handle<V>;
|
||||
openScope(envObject?: Env): HandleScope;
|
||||
closeScope(envObject?: Env, _scope?: HandleScope): void;
|
||||
ensureHandle<S>(value: S): Handle<S>;
|
||||
addCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
|
||||
removeCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
|
||||
runCleanup(): void;
|
||||
increaseWaitingRequestCounter(): void;
|
||||
decreaseWaitingRequestCounter(): void;
|
||||
setCanCallIntoJs(value: boolean): void;
|
||||
setStopping(value: boolean): void;
|
||||
canCallIntoJs(): boolean;
|
||||
/**
|
||||
* Destroy the context and call cleanup hooks.
|
||||
* Associated {@link Env | Env} will be destroyed.
|
||||
*/
|
||||
destroy(): void;
|
||||
}
|
||||
|
||||
export declare interface ContextOptions {
|
||||
onExternalMemoryChange?: (current: bigint, old: bigint, delta: bigint) => any;
|
||||
}
|
||||
|
||||
export declare function createContext(options?: ContextOptions): Context;
|
||||
|
||||
export declare class Deferred<T = any> implements IStoreValue {
|
||||
static create<T = any>(ctx: Context, value: IDeferrdValue<T>): Deferred;
|
||||
id: number;
|
||||
ctx: Context;
|
||||
value: IDeferrdValue<T>;
|
||||
constructor(ctx: Context, value: IDeferrdValue<T>);
|
||||
resolve(value: T): void;
|
||||
reject(reason?: any): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class EmnapiError extends Error {
|
||||
constructor(message?: string);
|
||||
}
|
||||
|
||||
export declare abstract class Env implements IStoreValue {
|
||||
readonly ctx: Context;
|
||||
moduleApiVersion: number;
|
||||
makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void;
|
||||
makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void;
|
||||
abort: (msg?: string) => never;
|
||||
id: number;
|
||||
openHandleScopes: number;
|
||||
instanceData: TrackedFinalizer | null;
|
||||
tryCatch: TryCatch;
|
||||
refs: number;
|
||||
reflist: RefTracker;
|
||||
finalizing_reflist: RefTracker;
|
||||
pendingFinalizers: RefTracker[];
|
||||
lastError: {
|
||||
errorCode: napi_status;
|
||||
engineErrorCode: number;
|
||||
engineReserved: Ptr;
|
||||
};
|
||||
inGcFinalizer: boolean;
|
||||
constructor(ctx: Context, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never);
|
||||
/** @virtual */
|
||||
canCallIntoJs(): boolean;
|
||||
terminatedOrTerminating(): boolean;
|
||||
ref(): void;
|
||||
unref(): void;
|
||||
ensureHandle<S>(value: S): Handle<S>;
|
||||
ensureHandleId(value: any): napi_value;
|
||||
clearLastError(): napi_status;
|
||||
setLastError(error_code: napi_status, engine_error_code?: uint32_t, engine_reserved?: void_p): napi_status;
|
||||
getReturnStatus(): napi_status;
|
||||
callIntoModule<T>(fn: (env: Env) => T, handleException?: (envObject: Env, value: any) => void): T;
|
||||
/** @virtual */
|
||||
abstract callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
|
||||
invokeFinalizerFromGC(finalizer: RefTracker): void;
|
||||
checkGCAccess(): void;
|
||||
/** @virtual */
|
||||
enqueueFinalizer(finalizer: RefTracker): void;
|
||||
/** @virtual */
|
||||
dequeueFinalizer(finalizer: RefTracker): void;
|
||||
/** @virtual */
|
||||
deleteMe(): void;
|
||||
dispose(): void;
|
||||
private readonly _bindingMap;
|
||||
initObjectBinding<S extends object>(value: S): IReferenceBinding;
|
||||
getObjectBinding<S extends object>(value: S): IReferenceBinding;
|
||||
setInstanceData(data: number, finalize_cb: number, finalize_hint: number): void;
|
||||
getInstanceData(): number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
declare interface External_2 extends Record<any, any> {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
declare const External_2: {
|
||||
new (value: number | bigint): External_2;
|
||||
prototype: null;
|
||||
};
|
||||
export { External_2 as External }
|
||||
|
||||
export declare class Finalizer {
|
||||
envObject: Env;
|
||||
private _finalizeCallback;
|
||||
private _finalizeData;
|
||||
private _finalizeHint;
|
||||
private _makeDynCall_vppp;
|
||||
constructor(envObject: Env, _finalizeCallback?: napi_finalize, _finalizeData?: void_p, _finalizeHint?: void_p);
|
||||
callback(): napi_finalize;
|
||||
data(): void_p;
|
||||
hint(): void_p;
|
||||
resetEnv(): void;
|
||||
resetFinalizer(): void;
|
||||
callFinalizer(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare function getDefaultContext(): Context;
|
||||
|
||||
/** @public */
|
||||
export declare function getExternalValue(external: External_2): number | bigint;
|
||||
|
||||
export declare class Handle<S> {
|
||||
id: number;
|
||||
value: S;
|
||||
constructor(id: number, value: S);
|
||||
data(): void_p;
|
||||
isNumber(): boolean;
|
||||
isBigInt(): boolean;
|
||||
isString(): boolean;
|
||||
isFunction(): boolean;
|
||||
isExternal(): boolean;
|
||||
isObject(): boolean;
|
||||
isArray(): boolean;
|
||||
isArrayBuffer(): boolean;
|
||||
isTypedArray(): boolean;
|
||||
isBuffer(BufferConstructor?: BufferCtor): boolean;
|
||||
isDataView(): boolean;
|
||||
isDate(): boolean;
|
||||
isPromise(): boolean;
|
||||
isBoolean(): boolean;
|
||||
isUndefined(): boolean;
|
||||
isSymbol(): boolean;
|
||||
isNull(): boolean;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class HandleScope {
|
||||
handleStore: HandleStore;
|
||||
id: number;
|
||||
parent: HandleScope | null;
|
||||
child: HandleScope | null;
|
||||
start: number;
|
||||
end: number;
|
||||
private _escapeCalled;
|
||||
callbackInfo: ICallbackInfo;
|
||||
constructor(handleStore: HandleStore, id: number, parentScope: HandleScope | null, start: number, end?: number);
|
||||
add<V>(value: V): Handle<V>;
|
||||
addExternal(data: void_p): Handle<object>;
|
||||
dispose(): void;
|
||||
escape(handle: number): Handle<any> | null;
|
||||
escapeCalled(): boolean;
|
||||
}
|
||||
|
||||
export declare class HandleStore {
|
||||
static UNDEFINED: ConstHandle<undefined>;
|
||||
static NULL: ConstHandle<null>;
|
||||
static FALSE: ConstHandle<false>;
|
||||
static TRUE: ConstHandle<true>;
|
||||
static GLOBAL: ConstHandle<typeof globalThis>;
|
||||
static MIN_ID: 6;
|
||||
private readonly _values;
|
||||
private _next;
|
||||
push<S>(value: S): Handle<S>;
|
||||
erase(start: number, end: number): void;
|
||||
get(id: Ptr): Handle<any> | undefined;
|
||||
swap(a: number, b: number): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare interface ICallbackInfo {
|
||||
thiz: any;
|
||||
data: void_p;
|
||||
args: ArrayLike<any>;
|
||||
fn: Function;
|
||||
}
|
||||
|
||||
export declare interface IDeferrdValue<T = any> {
|
||||
resolve: (value: T) => void;
|
||||
reject: (reason?: any) => void;
|
||||
}
|
||||
|
||||
export declare interface IReferenceBinding {
|
||||
wrapped: number;
|
||||
tag: Uint32Array | null;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare function isExternal(object: unknown): object is External_2;
|
||||
|
||||
export declare function isReferenceType(v: any): v is object;
|
||||
|
||||
export declare interface IStoreValue {
|
||||
id: number;
|
||||
dispose(): void;
|
||||
[x: string]: any;
|
||||
}
|
||||
|
||||
export declare const NAPI_VERSION_EXPERIMENTAL = Version.NAPI_VERSION_EXPERIMENTAL;
|
||||
|
||||
export declare const NODE_API_DEFAULT_MODULE_API_VERSION = Version.NODE_API_DEFAULT_MODULE_API_VERSION;
|
||||
|
||||
export declare const NODE_API_SUPPORTED_VERSION_MAX = Version.NODE_API_SUPPORTED_VERSION_MAX;
|
||||
|
||||
export declare const NODE_API_SUPPORTED_VERSION_MIN = Version.NODE_API_SUPPORTED_VERSION_MIN;
|
||||
|
||||
export declare class NodeEnv extends Env {
|
||||
filename: string;
|
||||
private readonly nodeBinding?;
|
||||
destructing: boolean;
|
||||
finalizationScheduled: boolean;
|
||||
constructor(ctx: Context, filename: string, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never, nodeBinding?: any);
|
||||
deleteMe(): void;
|
||||
canCallIntoJs(): boolean;
|
||||
triggerFatalException(err: any): void;
|
||||
callbackIntoModule<T>(enforceUncaughtExceptionPolicy: boolean, fn: (env: Env) => T): T;
|
||||
callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
|
||||
callFinalizerInternal(forceUncaught: int, cb: napi_finalize, data: void_p, hint: void_p): void;
|
||||
enqueueFinalizer(finalizer: RefTracker): void;
|
||||
drainFinalizerQueue(): void;
|
||||
}
|
||||
|
||||
export declare class NotSupportBufferError extends EmnapiError {
|
||||
constructor(api: string, message: string);
|
||||
}
|
||||
|
||||
export declare class NotSupportWeakRefError extends EmnapiError {
|
||||
constructor(api: string, message: string);
|
||||
}
|
||||
|
||||
export declare class Persistent<T> {
|
||||
private _ref;
|
||||
private _param;
|
||||
private _callback;
|
||||
private static readonly _registry;
|
||||
constructor(value: T);
|
||||
setWeak<P>(param: P, callback: (param: P) => void): void;
|
||||
clearWeak(): void;
|
||||
reset(): void;
|
||||
isEmpty(): boolean;
|
||||
deref(): T | undefined;
|
||||
}
|
||||
|
||||
export declare class Reference extends RefTracker implements IStoreValue {
|
||||
private static weakCallback;
|
||||
id: number;
|
||||
envObject: Env;
|
||||
private readonly canBeWeak;
|
||||
private _refcount;
|
||||
private readonly _ownership;
|
||||
persistent: Persistent<object>;
|
||||
static create(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, _unused1?: void_p, _unused2?: void_p, _unused3?: void_p): Reference;
|
||||
protected constructor(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership);
|
||||
ref(): number;
|
||||
unref(): number;
|
||||
get(envObject?: Env): napi_value;
|
||||
/** @virtual */
|
||||
resetFinalizer(): void;
|
||||
/** @virtual */
|
||||
data(): void_p;
|
||||
refcount(): number;
|
||||
ownership(): ReferenceOwnership;
|
||||
/** @virtual */
|
||||
protected callUserFinalizer(): void;
|
||||
/** @virtual */
|
||||
protected invokeFinalizerFromGC(): void;
|
||||
private _setWeak;
|
||||
finalize(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare enum ReferenceOwnership {
|
||||
kRuntime = 0,
|
||||
kUserland = 1
|
||||
}
|
||||
|
||||
export declare class ReferenceWithData extends Reference {
|
||||
private readonly _data;
|
||||
static create(envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): ReferenceWithData;
|
||||
private constructor();
|
||||
data(): void_p;
|
||||
}
|
||||
|
||||
export declare class ReferenceWithFinalizer extends Reference {
|
||||
private _finalizer;
|
||||
static create(envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): ReferenceWithFinalizer;
|
||||
private constructor();
|
||||
resetFinalizer(): void;
|
||||
data(): void_p;
|
||||
protected callUserFinalizer(): void;
|
||||
protected invokeFinalizerFromGC(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class RefTracker {
|
||||
/** @virtual */
|
||||
dispose(): void;
|
||||
/** @virtual */
|
||||
finalize(): void;
|
||||
private _next;
|
||||
private _prev;
|
||||
link(list: RefTracker): void;
|
||||
unlink(): void;
|
||||
static finalizeAll(list: RefTracker): void;
|
||||
}
|
||||
|
||||
export declare class ScopeStore {
|
||||
private readonly _rootScope;
|
||||
currentScope: HandleScope;
|
||||
private readonly _values;
|
||||
constructor();
|
||||
get(id: number): HandleScope | undefined;
|
||||
openScope(handleStore: HandleStore): HandleScope;
|
||||
closeScope(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class Store<V extends IStoreValue> {
|
||||
protected _values: Array<V | undefined>;
|
||||
private _freeList;
|
||||
private _size;
|
||||
constructor();
|
||||
add(value: V): void;
|
||||
get(id: Ptr): V | undefined;
|
||||
has(id: Ptr): boolean;
|
||||
remove(id: Ptr): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class TrackedFinalizer extends RefTracker {
|
||||
private _finalizer;
|
||||
static create(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
|
||||
private constructor();
|
||||
data(): void_p;
|
||||
dispose(): void;
|
||||
finalize(): void;
|
||||
}
|
||||
|
||||
export declare class TryCatch {
|
||||
private _exception;
|
||||
private _caught;
|
||||
isEmpty(): boolean;
|
||||
hasCaught(): boolean;
|
||||
exception(): any;
|
||||
setError(err: any): void;
|
||||
reset(): void;
|
||||
extractException(): any;
|
||||
}
|
||||
|
||||
export declare const version: string;
|
||||
|
||||
export { }
|
||||
+1
File diff suppressed because one or more lines are too long
+671
@@ -0,0 +1,671 @@
|
||||
export declare type Ptr = number | bigint
|
||||
|
||||
export declare interface IBuffer extends Uint8Array {}
|
||||
export declare interface BufferCtor {
|
||||
readonly prototype: IBuffer
|
||||
/** @deprecated */
|
||||
new (...args: any[]): IBuffer
|
||||
from: {
|
||||
(buffer: ArrayBufferLike): IBuffer
|
||||
(buffer: ArrayBufferLike, byteOffset: number, length: number): IBuffer
|
||||
}
|
||||
alloc: (size: number) => IBuffer
|
||||
isBuffer: (obj: unknown) => obj is IBuffer
|
||||
}
|
||||
|
||||
export declare const enum GlobalHandle {
|
||||
UNDEFINED = 1,
|
||||
NULL,
|
||||
FALSE,
|
||||
TRUE,
|
||||
GLOBAL
|
||||
}
|
||||
|
||||
export declare const enum Version {
|
||||
NODE_API_SUPPORTED_VERSION_MIN = 1,
|
||||
NODE_API_DEFAULT_MODULE_API_VERSION = 8,
|
||||
NODE_API_SUPPORTED_VERSION_MAX = 10,
|
||||
NAPI_VERSION_EXPERIMENTAL = 2147483647 // INT_MAX
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export declare type Pointer<T> = number
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export declare type PointerPointer<T> = number
|
||||
export declare type FunctionPointer<T extends (...args: any[]) => any> = Pointer<T>
|
||||
export declare type Const<T> = T
|
||||
|
||||
export declare type void_p = Pointer<void>
|
||||
export declare type void_pp = Pointer<void_p>
|
||||
export declare type bool = number
|
||||
export declare type char = number
|
||||
export declare type char_p = Pointer<char>
|
||||
export declare type unsigned_char = number
|
||||
export declare type const_char = Const<char>
|
||||
export declare type const_char_p = Pointer<const_char>
|
||||
export declare type char16_t_p = number
|
||||
export declare type const_char16_t_p = number
|
||||
|
||||
export declare type short = number
|
||||
export declare type unsigned_short = number
|
||||
export declare type int = number
|
||||
export declare type unsigned_int = number
|
||||
export declare type long = number
|
||||
export declare type unsigned_long = number
|
||||
export declare type long_long = bigint
|
||||
export declare type unsigned_long_long = bigint
|
||||
export declare type float = number
|
||||
export declare type double = number
|
||||
export declare type long_double = number
|
||||
export declare type size_t = number
|
||||
|
||||
export declare type int8_t = number
|
||||
export declare type uint8_t = number
|
||||
export declare type int16_t = number
|
||||
export declare type uint16_t = number
|
||||
export declare type int32_t = number
|
||||
export declare type uint32_t = number
|
||||
export declare type int64_t = bigint
|
||||
export declare type uint64_t = bigint
|
||||
export declare type napi_env = Pointer<unknown>
|
||||
|
||||
export declare type napi_value = Pointer<unknown>
|
||||
export declare type napi_ref = Pointer<unknown>
|
||||
export declare type napi_deferred = Pointer<unknown>
|
||||
export declare type napi_handle_scope = Pointer<unknown>
|
||||
export declare type napi_escapable_handle_scope = Pointer<unknown>
|
||||
|
||||
export declare type napi_addon_register_func = FunctionPointer<(env: napi_env, exports: napi_value) => napi_value>
|
||||
|
||||
export declare type napi_callback_info = Pointer<unknown>
|
||||
export declare type napi_callback = FunctionPointer<(env: napi_env, info: napi_callback_info) => napi_value>
|
||||
|
||||
export declare interface napi_extended_error_info {
|
||||
error_message: const_char_p
|
||||
engine_reserved: void_p
|
||||
engine_error_code: uint32_t
|
||||
error_code: napi_status
|
||||
}
|
||||
|
||||
export declare interface napi_property_descriptor {
|
||||
// One of utf8name or name should be NULL.
|
||||
utf8name: const_char_p
|
||||
name: napi_value
|
||||
|
||||
method: napi_callback
|
||||
getter: napi_callback
|
||||
setter: napi_callback
|
||||
value: napi_value
|
||||
/* napi_property_attributes */
|
||||
attributes: number
|
||||
data: void_p
|
||||
}
|
||||
|
||||
export declare type napi_finalize = FunctionPointer<(
|
||||
env: napi_env,
|
||||
finalize_data: void_p,
|
||||
finalize_hint: void_p
|
||||
) => void>
|
||||
|
||||
export declare interface node_module {
|
||||
nm_version: int32_t
|
||||
nm_flags: uint32_t
|
||||
nm_filename: Pointer<const_char>
|
||||
nm_register_func: napi_addon_register_func
|
||||
nm_modname: Pointer<const_char>
|
||||
nm_priv: Pointer<void>
|
||||
reserved: PointerPointer<void>
|
||||
}
|
||||
|
||||
export declare interface napi_node_version {
|
||||
major: uint32_t
|
||||
minor: uint32_t
|
||||
patch: uint32_t
|
||||
release: const_char_p
|
||||
}
|
||||
|
||||
export declare interface emnapi_emscripten_version {
|
||||
major: uint32_t
|
||||
minor: uint32_t
|
||||
patch: uint32_t
|
||||
}
|
||||
|
||||
export declare const enum napi_status {
|
||||
napi_ok,
|
||||
napi_invalid_arg,
|
||||
napi_object_expected,
|
||||
napi_string_expected,
|
||||
napi_name_expected,
|
||||
napi_function_expected,
|
||||
napi_number_expected,
|
||||
napi_boolean_expected,
|
||||
napi_array_expected,
|
||||
napi_generic_failure,
|
||||
napi_pending_exception,
|
||||
napi_cancelled,
|
||||
napi_escape_called_twice,
|
||||
napi_handle_scope_mismatch,
|
||||
napi_callback_scope_mismatch,
|
||||
napi_queue_full,
|
||||
napi_closing,
|
||||
napi_bigint_expected,
|
||||
napi_date_expected,
|
||||
napi_arraybuffer_expected,
|
||||
napi_detachable_arraybuffer_expected,
|
||||
napi_would_deadlock, // unused
|
||||
napi_no_external_buffers_allowed,
|
||||
napi_cannot_run_js
|
||||
}
|
||||
|
||||
export declare const enum napi_property_attributes {
|
||||
napi_default = 0,
|
||||
napi_writable = 1 << 0,
|
||||
napi_enumerable = 1 << 1,
|
||||
napi_configurable = 1 << 2,
|
||||
|
||||
// Used with napi_define_class to distinguish static properties
|
||||
// from instance properties. Ignored by napi_define_properties.
|
||||
napi_static = 1 << 10,
|
||||
|
||||
/// #ifdef NAPI_EXPERIMENTAL
|
||||
// Default for class methods.
|
||||
napi_default_method = napi_writable | napi_configurable,
|
||||
|
||||
// Default for object properties, like in JS obj[prop].
|
||||
napi_default_jsproperty = napi_writable | napi_enumerable | napi_configurable
|
||||
/// #endif // NAPI_EXPERIMENTAL
|
||||
}
|
||||
|
||||
export declare const enum napi_valuetype {
|
||||
napi_undefined,
|
||||
napi_null,
|
||||
napi_boolean,
|
||||
napi_number,
|
||||
napi_string,
|
||||
napi_symbol,
|
||||
napi_object,
|
||||
napi_function,
|
||||
napi_external,
|
||||
napi_bigint
|
||||
}
|
||||
|
||||
export declare const enum napi_typedarray_type {
|
||||
napi_int8_array,
|
||||
napi_uint8_array,
|
||||
napi_uint8_clamped_array,
|
||||
napi_int16_array,
|
||||
napi_uint16_array,
|
||||
napi_int32_array,
|
||||
napi_uint32_array,
|
||||
napi_float32_array,
|
||||
napi_float64_array,
|
||||
napi_bigint64_array,
|
||||
napi_biguint64_array,
|
||||
napi_float16_array,
|
||||
}
|
||||
|
||||
export declare const enum napi_key_collection_mode {
|
||||
napi_key_include_prototypes,
|
||||
napi_key_own_only
|
||||
}
|
||||
|
||||
export declare const enum napi_key_filter {
|
||||
napi_key_all_properties = 0,
|
||||
napi_key_writable = 1,
|
||||
napi_key_enumerable = 1 << 1,
|
||||
napi_key_configurable = 1 << 2,
|
||||
napi_key_skip_strings = 1 << 3,
|
||||
napi_key_skip_symbols = 1 << 4
|
||||
}
|
||||
|
||||
export declare const enum napi_key_conversion {
|
||||
napi_key_keep_numbers,
|
||||
napi_key_numbers_to_strings
|
||||
}
|
||||
|
||||
export declare const enum emnapi_memory_view_type {
|
||||
emnapi_int8_array,
|
||||
emnapi_uint8_array,
|
||||
emnapi_uint8_clamped_array,
|
||||
emnapi_int16_array,
|
||||
emnapi_uint16_array,
|
||||
emnapi_int32_array,
|
||||
emnapi_uint32_array,
|
||||
emnapi_float32_array,
|
||||
emnapi_float64_array,
|
||||
emnapi_bigint64_array,
|
||||
emnapi_biguint64_array,
|
||||
emnapi_float16_array,
|
||||
emnapi_data_view = -1,
|
||||
emnapi_buffer = -2
|
||||
}
|
||||
|
||||
export declare const enum napi_threadsafe_function_call_mode {
|
||||
napi_tsfn_nonblocking,
|
||||
napi_tsfn_blocking
|
||||
}
|
||||
|
||||
export declare const enum napi_threadsafe_function_release_mode {
|
||||
napi_tsfn_release,
|
||||
napi_tsfn_abort
|
||||
}
|
||||
export declare type CleanupHookCallbackFunction = number | ((arg: number) => void);
|
||||
|
||||
export declare class ConstHandle<S extends undefined | null | boolean | typeof globalThis> extends Handle<S> {
|
||||
constructor(id: number, value: S);
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class Context {
|
||||
private _isStopping;
|
||||
private _canCallIntoJs;
|
||||
private _suppressDestroy;
|
||||
envStore: Store<Env>;
|
||||
scopeStore: ScopeStore;
|
||||
refStore: Store<Reference>;
|
||||
deferredStore: Store<Deferred<any>>;
|
||||
handleStore: HandleStore;
|
||||
private readonly refCounter?;
|
||||
private readonly cleanupQueue;
|
||||
private readonly _externalMemory;
|
||||
feature: {
|
||||
supportReflect: boolean;
|
||||
supportFinalizer: boolean;
|
||||
supportWeakSymbol: boolean;
|
||||
supportBigInt: boolean;
|
||||
supportNewFunction: boolean;
|
||||
canSetFunctionName: boolean;
|
||||
setImmediate: (callback: () => void) => void;
|
||||
Buffer: BufferCtor | undefined;
|
||||
MessageChannel: {
|
||||
new (): MessageChannel;
|
||||
prototype: MessageChannel;
|
||||
} | undefined;
|
||||
};
|
||||
constructor(options?: ContextOptions);
|
||||
/**
|
||||
* Suppress the destroy on `beforeExit` event in Node.js.
|
||||
* Call this method if you want to keep the context and
|
||||
* all associated {@link Env | Env} alive,
|
||||
* this also means that cleanup hooks will not be called.
|
||||
* After call this method, you should call
|
||||
* {@link Context.destroy | `Context.prototype.destroy`} method manually.
|
||||
*/
|
||||
suppressDestroy(): void;
|
||||
getRuntimeVersions(): {
|
||||
version: string;
|
||||
NODE_API_SUPPORTED_VERSION_MAX: Version;
|
||||
NAPI_VERSION_EXPERIMENTAL: Version;
|
||||
NODE_API_DEFAULT_MODULE_API_VERSION: Version;
|
||||
};
|
||||
createNotSupportWeakRefError(api: string, message: string): NotSupportWeakRefError;
|
||||
createNotSupportBufferError(api: string, message: string): NotSupportBufferError;
|
||||
createReference(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership): Reference;
|
||||
createReferenceWithData(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): Reference;
|
||||
createReferenceWithFinalizer(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback?: napi_finalize, finalize_data?: void_p, finalize_hint?: void_p): Reference;
|
||||
createDeferred<T = any>(value: IDeferrdValue<T>): Deferred<T>;
|
||||
adjustAmountOfExternalAllocatedMemory(changeInBytes: number | bigint): bigint;
|
||||
createEnv(filename: string, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never, nodeBinding?: any): Env;
|
||||
createTrackedFinalizer(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
|
||||
getCurrentScope(): HandleScope | null;
|
||||
addToCurrentScope<V>(value: V): Handle<V>;
|
||||
openScope(envObject?: Env): HandleScope;
|
||||
closeScope(envObject?: Env, _scope?: HandleScope): void;
|
||||
ensureHandle<S>(value: S): Handle<S>;
|
||||
addCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
|
||||
removeCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
|
||||
runCleanup(): void;
|
||||
increaseWaitingRequestCounter(): void;
|
||||
decreaseWaitingRequestCounter(): void;
|
||||
setCanCallIntoJs(value: boolean): void;
|
||||
setStopping(value: boolean): void;
|
||||
canCallIntoJs(): boolean;
|
||||
/**
|
||||
* Destroy the context and call cleanup hooks.
|
||||
* Associated {@link Env | Env} will be destroyed.
|
||||
*/
|
||||
destroy(): void;
|
||||
}
|
||||
|
||||
export declare interface ContextOptions {
|
||||
onExternalMemoryChange?: (current: bigint, old: bigint, delta: bigint) => any;
|
||||
}
|
||||
|
||||
export declare function createContext(options?: ContextOptions): Context;
|
||||
|
||||
export declare class Deferred<T = any> implements IStoreValue {
|
||||
static create<T = any>(ctx: Context, value: IDeferrdValue<T>): Deferred;
|
||||
id: number;
|
||||
ctx: Context;
|
||||
value: IDeferrdValue<T>;
|
||||
constructor(ctx: Context, value: IDeferrdValue<T>);
|
||||
resolve(value: T): void;
|
||||
reject(reason?: any): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class EmnapiError extends Error {
|
||||
constructor(message?: string);
|
||||
}
|
||||
|
||||
export declare abstract class Env implements IStoreValue {
|
||||
readonly ctx: Context;
|
||||
moduleApiVersion: number;
|
||||
makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void;
|
||||
makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void;
|
||||
abort: (msg?: string) => never;
|
||||
id: number;
|
||||
openHandleScopes: number;
|
||||
instanceData: TrackedFinalizer | null;
|
||||
tryCatch: TryCatch;
|
||||
refs: number;
|
||||
reflist: RefTracker;
|
||||
finalizing_reflist: RefTracker;
|
||||
pendingFinalizers: RefTracker[];
|
||||
lastError: {
|
||||
errorCode: napi_status;
|
||||
engineErrorCode: number;
|
||||
engineReserved: Ptr;
|
||||
};
|
||||
inGcFinalizer: boolean;
|
||||
constructor(ctx: Context, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never);
|
||||
/** @virtual */
|
||||
canCallIntoJs(): boolean;
|
||||
terminatedOrTerminating(): boolean;
|
||||
ref(): void;
|
||||
unref(): void;
|
||||
ensureHandle<S>(value: S): Handle<S>;
|
||||
ensureHandleId(value: any): napi_value;
|
||||
clearLastError(): napi_status;
|
||||
setLastError(error_code: napi_status, engine_error_code?: uint32_t, engine_reserved?: void_p): napi_status;
|
||||
getReturnStatus(): napi_status;
|
||||
callIntoModule<T>(fn: (env: Env) => T, handleException?: (envObject: Env, value: any) => void): T;
|
||||
/** @virtual */
|
||||
abstract callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
|
||||
invokeFinalizerFromGC(finalizer: RefTracker): void;
|
||||
checkGCAccess(): void;
|
||||
/** @virtual */
|
||||
enqueueFinalizer(finalizer: RefTracker): void;
|
||||
/** @virtual */
|
||||
dequeueFinalizer(finalizer: RefTracker): void;
|
||||
/** @virtual */
|
||||
deleteMe(): void;
|
||||
dispose(): void;
|
||||
private readonly _bindingMap;
|
||||
initObjectBinding<S extends object>(value: S): IReferenceBinding;
|
||||
getObjectBinding<S extends object>(value: S): IReferenceBinding;
|
||||
setInstanceData(data: number, finalize_cb: number, finalize_hint: number): void;
|
||||
getInstanceData(): number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
declare interface External_2 extends Record<any, any> {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
declare const External_2: {
|
||||
new (value: number | bigint): External_2;
|
||||
prototype: null;
|
||||
};
|
||||
export { External_2 as External }
|
||||
|
||||
export declare class Finalizer {
|
||||
envObject: Env;
|
||||
private _finalizeCallback;
|
||||
private _finalizeData;
|
||||
private _finalizeHint;
|
||||
private _makeDynCall_vppp;
|
||||
constructor(envObject: Env, _finalizeCallback?: napi_finalize, _finalizeData?: void_p, _finalizeHint?: void_p);
|
||||
callback(): napi_finalize;
|
||||
data(): void_p;
|
||||
hint(): void_p;
|
||||
resetEnv(): void;
|
||||
resetFinalizer(): void;
|
||||
callFinalizer(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare function getDefaultContext(): Context;
|
||||
|
||||
/** @public */
|
||||
export declare function getExternalValue(external: External_2): number | bigint;
|
||||
|
||||
export declare class Handle<S> {
|
||||
id: number;
|
||||
value: S;
|
||||
constructor(id: number, value: S);
|
||||
data(): void_p;
|
||||
isNumber(): boolean;
|
||||
isBigInt(): boolean;
|
||||
isString(): boolean;
|
||||
isFunction(): boolean;
|
||||
isExternal(): boolean;
|
||||
isObject(): boolean;
|
||||
isArray(): boolean;
|
||||
isArrayBuffer(): boolean;
|
||||
isTypedArray(): boolean;
|
||||
isBuffer(BufferConstructor?: BufferCtor): boolean;
|
||||
isDataView(): boolean;
|
||||
isDate(): boolean;
|
||||
isPromise(): boolean;
|
||||
isBoolean(): boolean;
|
||||
isUndefined(): boolean;
|
||||
isSymbol(): boolean;
|
||||
isNull(): boolean;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class HandleScope {
|
||||
handleStore: HandleStore;
|
||||
id: number;
|
||||
parent: HandleScope | null;
|
||||
child: HandleScope | null;
|
||||
start: number;
|
||||
end: number;
|
||||
private _escapeCalled;
|
||||
callbackInfo: ICallbackInfo;
|
||||
constructor(handleStore: HandleStore, id: number, parentScope: HandleScope | null, start: number, end?: number);
|
||||
add<V>(value: V): Handle<V>;
|
||||
addExternal(data: void_p): Handle<object>;
|
||||
dispose(): void;
|
||||
escape(handle: number): Handle<any> | null;
|
||||
escapeCalled(): boolean;
|
||||
}
|
||||
|
||||
export declare class HandleStore {
|
||||
static UNDEFINED: ConstHandle<undefined>;
|
||||
static NULL: ConstHandle<null>;
|
||||
static FALSE: ConstHandle<false>;
|
||||
static TRUE: ConstHandle<true>;
|
||||
static GLOBAL: ConstHandle<typeof globalThis>;
|
||||
static MIN_ID: 6;
|
||||
private readonly _values;
|
||||
private _next;
|
||||
push<S>(value: S): Handle<S>;
|
||||
erase(start: number, end: number): void;
|
||||
get(id: Ptr): Handle<any> | undefined;
|
||||
swap(a: number, b: number): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare interface ICallbackInfo {
|
||||
thiz: any;
|
||||
data: void_p;
|
||||
args: ArrayLike<any>;
|
||||
fn: Function;
|
||||
}
|
||||
|
||||
export declare interface IDeferrdValue<T = any> {
|
||||
resolve: (value: T) => void;
|
||||
reject: (reason?: any) => void;
|
||||
}
|
||||
|
||||
export declare interface IReferenceBinding {
|
||||
wrapped: number;
|
||||
tag: Uint32Array | null;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare function isExternal(object: unknown): object is External_2;
|
||||
|
||||
export declare function isReferenceType(v: any): v is object;
|
||||
|
||||
export declare interface IStoreValue {
|
||||
id: number;
|
||||
dispose(): void;
|
||||
[x: string]: any;
|
||||
}
|
||||
|
||||
export declare const NAPI_VERSION_EXPERIMENTAL = Version.NAPI_VERSION_EXPERIMENTAL;
|
||||
|
||||
export declare const NODE_API_DEFAULT_MODULE_API_VERSION = Version.NODE_API_DEFAULT_MODULE_API_VERSION;
|
||||
|
||||
export declare const NODE_API_SUPPORTED_VERSION_MAX = Version.NODE_API_SUPPORTED_VERSION_MAX;
|
||||
|
||||
export declare const NODE_API_SUPPORTED_VERSION_MIN = Version.NODE_API_SUPPORTED_VERSION_MIN;
|
||||
|
||||
export declare class NodeEnv extends Env {
|
||||
filename: string;
|
||||
private readonly nodeBinding?;
|
||||
destructing: boolean;
|
||||
finalizationScheduled: boolean;
|
||||
constructor(ctx: Context, filename: string, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never, nodeBinding?: any);
|
||||
deleteMe(): void;
|
||||
canCallIntoJs(): boolean;
|
||||
triggerFatalException(err: any): void;
|
||||
callbackIntoModule<T>(enforceUncaughtExceptionPolicy: boolean, fn: (env: Env) => T): T;
|
||||
callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
|
||||
callFinalizerInternal(forceUncaught: int, cb: napi_finalize, data: void_p, hint: void_p): void;
|
||||
enqueueFinalizer(finalizer: RefTracker): void;
|
||||
drainFinalizerQueue(): void;
|
||||
}
|
||||
|
||||
export declare class NotSupportBufferError extends EmnapiError {
|
||||
constructor(api: string, message: string);
|
||||
}
|
||||
|
||||
export declare class NotSupportWeakRefError extends EmnapiError {
|
||||
constructor(api: string, message: string);
|
||||
}
|
||||
|
||||
export declare class Persistent<T> {
|
||||
private _ref;
|
||||
private _param;
|
||||
private _callback;
|
||||
private static readonly _registry;
|
||||
constructor(value: T);
|
||||
setWeak<P>(param: P, callback: (param: P) => void): void;
|
||||
clearWeak(): void;
|
||||
reset(): void;
|
||||
isEmpty(): boolean;
|
||||
deref(): T | undefined;
|
||||
}
|
||||
|
||||
export declare class Reference extends RefTracker implements IStoreValue {
|
||||
private static weakCallback;
|
||||
id: number;
|
||||
envObject: Env;
|
||||
private readonly canBeWeak;
|
||||
private _refcount;
|
||||
private readonly _ownership;
|
||||
persistent: Persistent<object>;
|
||||
static create(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, _unused1?: void_p, _unused2?: void_p, _unused3?: void_p): Reference;
|
||||
protected constructor(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership);
|
||||
ref(): number;
|
||||
unref(): number;
|
||||
get(envObject?: Env): napi_value;
|
||||
/** @virtual */
|
||||
resetFinalizer(): void;
|
||||
/** @virtual */
|
||||
data(): void_p;
|
||||
refcount(): number;
|
||||
ownership(): ReferenceOwnership;
|
||||
/** @virtual */
|
||||
protected callUserFinalizer(): void;
|
||||
/** @virtual */
|
||||
protected invokeFinalizerFromGC(): void;
|
||||
private _setWeak;
|
||||
finalize(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare enum ReferenceOwnership {
|
||||
kRuntime = 0,
|
||||
kUserland = 1
|
||||
}
|
||||
|
||||
export declare class ReferenceWithData extends Reference {
|
||||
private readonly _data;
|
||||
static create(envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): ReferenceWithData;
|
||||
private constructor();
|
||||
data(): void_p;
|
||||
}
|
||||
|
||||
export declare class ReferenceWithFinalizer extends Reference {
|
||||
private _finalizer;
|
||||
static create(envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): ReferenceWithFinalizer;
|
||||
private constructor();
|
||||
resetFinalizer(): void;
|
||||
data(): void_p;
|
||||
protected callUserFinalizer(): void;
|
||||
protected invokeFinalizerFromGC(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class RefTracker {
|
||||
/** @virtual */
|
||||
dispose(): void;
|
||||
/** @virtual */
|
||||
finalize(): void;
|
||||
private _next;
|
||||
private _prev;
|
||||
link(list: RefTracker): void;
|
||||
unlink(): void;
|
||||
static finalizeAll(list: RefTracker): void;
|
||||
}
|
||||
|
||||
export declare class ScopeStore {
|
||||
private readonly _rootScope;
|
||||
currentScope: HandleScope;
|
||||
private readonly _values;
|
||||
constructor();
|
||||
get(id: number): HandleScope | undefined;
|
||||
openScope(handleStore: HandleStore): HandleScope;
|
||||
closeScope(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class Store<V extends IStoreValue> {
|
||||
protected _values: Array<V | undefined>;
|
||||
private _freeList;
|
||||
private _size;
|
||||
constructor();
|
||||
add(value: V): void;
|
||||
get(id: Ptr): V | undefined;
|
||||
has(id: Ptr): boolean;
|
||||
remove(id: Ptr): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class TrackedFinalizer extends RefTracker {
|
||||
private _finalizer;
|
||||
static create(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
|
||||
private constructor();
|
||||
data(): void_p;
|
||||
dispose(): void;
|
||||
finalize(): void;
|
||||
}
|
||||
|
||||
export declare class TryCatch {
|
||||
private _exception;
|
||||
private _caught;
|
||||
isEmpty(): boolean;
|
||||
hasCaught(): boolean;
|
||||
exception(): any;
|
||||
setError(err: any): void;
|
||||
reset(): void;
|
||||
extractException(): any;
|
||||
}
|
||||
|
||||
export declare const version: string;
|
||||
|
||||
export { }
|
||||
+673
@@ -0,0 +1,673 @@
|
||||
export declare type Ptr = number | bigint
|
||||
|
||||
export declare interface IBuffer extends Uint8Array {}
|
||||
export declare interface BufferCtor {
|
||||
readonly prototype: IBuffer
|
||||
/** @deprecated */
|
||||
new (...args: any[]): IBuffer
|
||||
from: {
|
||||
(buffer: ArrayBufferLike): IBuffer
|
||||
(buffer: ArrayBufferLike, byteOffset: number, length: number): IBuffer
|
||||
}
|
||||
alloc: (size: number) => IBuffer
|
||||
isBuffer: (obj: unknown) => obj is IBuffer
|
||||
}
|
||||
|
||||
export declare const enum GlobalHandle {
|
||||
UNDEFINED = 1,
|
||||
NULL,
|
||||
FALSE,
|
||||
TRUE,
|
||||
GLOBAL
|
||||
}
|
||||
|
||||
export declare const enum Version {
|
||||
NODE_API_SUPPORTED_VERSION_MIN = 1,
|
||||
NODE_API_DEFAULT_MODULE_API_VERSION = 8,
|
||||
NODE_API_SUPPORTED_VERSION_MAX = 10,
|
||||
NAPI_VERSION_EXPERIMENTAL = 2147483647 // INT_MAX
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export declare type Pointer<T> = number
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export declare type PointerPointer<T> = number
|
||||
export declare type FunctionPointer<T extends (...args: any[]) => any> = Pointer<T>
|
||||
export declare type Const<T> = T
|
||||
|
||||
export declare type void_p = Pointer<void>
|
||||
export declare type void_pp = Pointer<void_p>
|
||||
export declare type bool = number
|
||||
export declare type char = number
|
||||
export declare type char_p = Pointer<char>
|
||||
export declare type unsigned_char = number
|
||||
export declare type const_char = Const<char>
|
||||
export declare type const_char_p = Pointer<const_char>
|
||||
export declare type char16_t_p = number
|
||||
export declare type const_char16_t_p = number
|
||||
|
||||
export declare type short = number
|
||||
export declare type unsigned_short = number
|
||||
export declare type int = number
|
||||
export declare type unsigned_int = number
|
||||
export declare type long = number
|
||||
export declare type unsigned_long = number
|
||||
export declare type long_long = bigint
|
||||
export declare type unsigned_long_long = bigint
|
||||
export declare type float = number
|
||||
export declare type double = number
|
||||
export declare type long_double = number
|
||||
export declare type size_t = number
|
||||
|
||||
export declare type int8_t = number
|
||||
export declare type uint8_t = number
|
||||
export declare type int16_t = number
|
||||
export declare type uint16_t = number
|
||||
export declare type int32_t = number
|
||||
export declare type uint32_t = number
|
||||
export declare type int64_t = bigint
|
||||
export declare type uint64_t = bigint
|
||||
export declare type napi_env = Pointer<unknown>
|
||||
|
||||
export declare type napi_value = Pointer<unknown>
|
||||
export declare type napi_ref = Pointer<unknown>
|
||||
export declare type napi_deferred = Pointer<unknown>
|
||||
export declare type napi_handle_scope = Pointer<unknown>
|
||||
export declare type napi_escapable_handle_scope = Pointer<unknown>
|
||||
|
||||
export declare type napi_addon_register_func = FunctionPointer<(env: napi_env, exports: napi_value) => napi_value>
|
||||
|
||||
export declare type napi_callback_info = Pointer<unknown>
|
||||
export declare type napi_callback = FunctionPointer<(env: napi_env, info: napi_callback_info) => napi_value>
|
||||
|
||||
export declare interface napi_extended_error_info {
|
||||
error_message: const_char_p
|
||||
engine_reserved: void_p
|
||||
engine_error_code: uint32_t
|
||||
error_code: napi_status
|
||||
}
|
||||
|
||||
export declare interface napi_property_descriptor {
|
||||
// One of utf8name or name should be NULL.
|
||||
utf8name: const_char_p
|
||||
name: napi_value
|
||||
|
||||
method: napi_callback
|
||||
getter: napi_callback
|
||||
setter: napi_callback
|
||||
value: napi_value
|
||||
/* napi_property_attributes */
|
||||
attributes: number
|
||||
data: void_p
|
||||
}
|
||||
|
||||
export declare type napi_finalize = FunctionPointer<(
|
||||
env: napi_env,
|
||||
finalize_data: void_p,
|
||||
finalize_hint: void_p
|
||||
) => void>
|
||||
|
||||
export declare interface node_module {
|
||||
nm_version: int32_t
|
||||
nm_flags: uint32_t
|
||||
nm_filename: Pointer<const_char>
|
||||
nm_register_func: napi_addon_register_func
|
||||
nm_modname: Pointer<const_char>
|
||||
nm_priv: Pointer<void>
|
||||
reserved: PointerPointer<void>
|
||||
}
|
||||
|
||||
export declare interface napi_node_version {
|
||||
major: uint32_t
|
||||
minor: uint32_t
|
||||
patch: uint32_t
|
||||
release: const_char_p
|
||||
}
|
||||
|
||||
export declare interface emnapi_emscripten_version {
|
||||
major: uint32_t
|
||||
minor: uint32_t
|
||||
patch: uint32_t
|
||||
}
|
||||
|
||||
export declare const enum napi_status {
|
||||
napi_ok,
|
||||
napi_invalid_arg,
|
||||
napi_object_expected,
|
||||
napi_string_expected,
|
||||
napi_name_expected,
|
||||
napi_function_expected,
|
||||
napi_number_expected,
|
||||
napi_boolean_expected,
|
||||
napi_array_expected,
|
||||
napi_generic_failure,
|
||||
napi_pending_exception,
|
||||
napi_cancelled,
|
||||
napi_escape_called_twice,
|
||||
napi_handle_scope_mismatch,
|
||||
napi_callback_scope_mismatch,
|
||||
napi_queue_full,
|
||||
napi_closing,
|
||||
napi_bigint_expected,
|
||||
napi_date_expected,
|
||||
napi_arraybuffer_expected,
|
||||
napi_detachable_arraybuffer_expected,
|
||||
napi_would_deadlock, // unused
|
||||
napi_no_external_buffers_allowed,
|
||||
napi_cannot_run_js
|
||||
}
|
||||
|
||||
export declare const enum napi_property_attributes {
|
||||
napi_default = 0,
|
||||
napi_writable = 1 << 0,
|
||||
napi_enumerable = 1 << 1,
|
||||
napi_configurable = 1 << 2,
|
||||
|
||||
// Used with napi_define_class to distinguish static properties
|
||||
// from instance properties. Ignored by napi_define_properties.
|
||||
napi_static = 1 << 10,
|
||||
|
||||
/// #ifdef NAPI_EXPERIMENTAL
|
||||
// Default for class methods.
|
||||
napi_default_method = napi_writable | napi_configurable,
|
||||
|
||||
// Default for object properties, like in JS obj[prop].
|
||||
napi_default_jsproperty = napi_writable | napi_enumerable | napi_configurable
|
||||
/// #endif // NAPI_EXPERIMENTAL
|
||||
}
|
||||
|
||||
export declare const enum napi_valuetype {
|
||||
napi_undefined,
|
||||
napi_null,
|
||||
napi_boolean,
|
||||
napi_number,
|
||||
napi_string,
|
||||
napi_symbol,
|
||||
napi_object,
|
||||
napi_function,
|
||||
napi_external,
|
||||
napi_bigint
|
||||
}
|
||||
|
||||
export declare const enum napi_typedarray_type {
|
||||
napi_int8_array,
|
||||
napi_uint8_array,
|
||||
napi_uint8_clamped_array,
|
||||
napi_int16_array,
|
||||
napi_uint16_array,
|
||||
napi_int32_array,
|
||||
napi_uint32_array,
|
||||
napi_float32_array,
|
||||
napi_float64_array,
|
||||
napi_bigint64_array,
|
||||
napi_biguint64_array,
|
||||
napi_float16_array,
|
||||
}
|
||||
|
||||
export declare const enum napi_key_collection_mode {
|
||||
napi_key_include_prototypes,
|
||||
napi_key_own_only
|
||||
}
|
||||
|
||||
export declare const enum napi_key_filter {
|
||||
napi_key_all_properties = 0,
|
||||
napi_key_writable = 1,
|
||||
napi_key_enumerable = 1 << 1,
|
||||
napi_key_configurable = 1 << 2,
|
||||
napi_key_skip_strings = 1 << 3,
|
||||
napi_key_skip_symbols = 1 << 4
|
||||
}
|
||||
|
||||
export declare const enum napi_key_conversion {
|
||||
napi_key_keep_numbers,
|
||||
napi_key_numbers_to_strings
|
||||
}
|
||||
|
||||
export declare const enum emnapi_memory_view_type {
|
||||
emnapi_int8_array,
|
||||
emnapi_uint8_array,
|
||||
emnapi_uint8_clamped_array,
|
||||
emnapi_int16_array,
|
||||
emnapi_uint16_array,
|
||||
emnapi_int32_array,
|
||||
emnapi_uint32_array,
|
||||
emnapi_float32_array,
|
||||
emnapi_float64_array,
|
||||
emnapi_bigint64_array,
|
||||
emnapi_biguint64_array,
|
||||
emnapi_float16_array,
|
||||
emnapi_data_view = -1,
|
||||
emnapi_buffer = -2
|
||||
}
|
||||
|
||||
export declare const enum napi_threadsafe_function_call_mode {
|
||||
napi_tsfn_nonblocking,
|
||||
napi_tsfn_blocking
|
||||
}
|
||||
|
||||
export declare const enum napi_threadsafe_function_release_mode {
|
||||
napi_tsfn_release,
|
||||
napi_tsfn_abort
|
||||
}
|
||||
export declare type CleanupHookCallbackFunction = number | ((arg: number) => void);
|
||||
|
||||
export declare class ConstHandle<S extends undefined | null | boolean | typeof globalThis> extends Handle<S> {
|
||||
constructor(id: number, value: S);
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class Context {
|
||||
private _isStopping;
|
||||
private _canCallIntoJs;
|
||||
private _suppressDestroy;
|
||||
envStore: Store<Env>;
|
||||
scopeStore: ScopeStore;
|
||||
refStore: Store<Reference>;
|
||||
deferredStore: Store<Deferred<any>>;
|
||||
handleStore: HandleStore;
|
||||
private readonly refCounter?;
|
||||
private readonly cleanupQueue;
|
||||
private readonly _externalMemory;
|
||||
feature: {
|
||||
supportReflect: boolean;
|
||||
supportFinalizer: boolean;
|
||||
supportWeakSymbol: boolean;
|
||||
supportBigInt: boolean;
|
||||
supportNewFunction: boolean;
|
||||
canSetFunctionName: boolean;
|
||||
setImmediate: (callback: () => void) => void;
|
||||
Buffer: BufferCtor | undefined;
|
||||
MessageChannel: {
|
||||
new (): MessageChannel;
|
||||
prototype: MessageChannel;
|
||||
} | undefined;
|
||||
};
|
||||
constructor(options?: ContextOptions);
|
||||
/**
|
||||
* Suppress the destroy on `beforeExit` event in Node.js.
|
||||
* Call this method if you want to keep the context and
|
||||
* all associated {@link Env | Env} alive,
|
||||
* this also means that cleanup hooks will not be called.
|
||||
* After call this method, you should call
|
||||
* {@link Context.destroy | `Context.prototype.destroy`} method manually.
|
||||
*/
|
||||
suppressDestroy(): void;
|
||||
getRuntimeVersions(): {
|
||||
version: string;
|
||||
NODE_API_SUPPORTED_VERSION_MAX: Version;
|
||||
NAPI_VERSION_EXPERIMENTAL: Version;
|
||||
NODE_API_DEFAULT_MODULE_API_VERSION: Version;
|
||||
};
|
||||
createNotSupportWeakRefError(api: string, message: string): NotSupportWeakRefError;
|
||||
createNotSupportBufferError(api: string, message: string): NotSupportBufferError;
|
||||
createReference(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership): Reference;
|
||||
createReferenceWithData(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): Reference;
|
||||
createReferenceWithFinalizer(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback?: napi_finalize, finalize_data?: void_p, finalize_hint?: void_p): Reference;
|
||||
createDeferred<T = any>(value: IDeferrdValue<T>): Deferred<T>;
|
||||
adjustAmountOfExternalAllocatedMemory(changeInBytes: number | bigint): bigint;
|
||||
createEnv(filename: string, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never, nodeBinding?: any): Env;
|
||||
createTrackedFinalizer(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
|
||||
getCurrentScope(): HandleScope | null;
|
||||
addToCurrentScope<V>(value: V): Handle<V>;
|
||||
openScope(envObject?: Env): HandleScope;
|
||||
closeScope(envObject?: Env, _scope?: HandleScope): void;
|
||||
ensureHandle<S>(value: S): Handle<S>;
|
||||
addCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
|
||||
removeCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
|
||||
runCleanup(): void;
|
||||
increaseWaitingRequestCounter(): void;
|
||||
decreaseWaitingRequestCounter(): void;
|
||||
setCanCallIntoJs(value: boolean): void;
|
||||
setStopping(value: boolean): void;
|
||||
canCallIntoJs(): boolean;
|
||||
/**
|
||||
* Destroy the context and call cleanup hooks.
|
||||
* Associated {@link Env | Env} will be destroyed.
|
||||
*/
|
||||
destroy(): void;
|
||||
}
|
||||
|
||||
export declare interface ContextOptions {
|
||||
onExternalMemoryChange?: (current: bigint, old: bigint, delta: bigint) => any;
|
||||
}
|
||||
|
||||
export declare function createContext(options?: ContextOptions): Context;
|
||||
|
||||
export declare class Deferred<T = any> implements IStoreValue {
|
||||
static create<T = any>(ctx: Context, value: IDeferrdValue<T>): Deferred;
|
||||
id: number;
|
||||
ctx: Context;
|
||||
value: IDeferrdValue<T>;
|
||||
constructor(ctx: Context, value: IDeferrdValue<T>);
|
||||
resolve(value: T): void;
|
||||
reject(reason?: any): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class EmnapiError extends Error {
|
||||
constructor(message?: string);
|
||||
}
|
||||
|
||||
export declare abstract class Env implements IStoreValue {
|
||||
readonly ctx: Context;
|
||||
moduleApiVersion: number;
|
||||
makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void;
|
||||
makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void;
|
||||
abort: (msg?: string) => never;
|
||||
id: number;
|
||||
openHandleScopes: number;
|
||||
instanceData: TrackedFinalizer | null;
|
||||
tryCatch: TryCatch;
|
||||
refs: number;
|
||||
reflist: RefTracker;
|
||||
finalizing_reflist: RefTracker;
|
||||
pendingFinalizers: RefTracker[];
|
||||
lastError: {
|
||||
errorCode: napi_status;
|
||||
engineErrorCode: number;
|
||||
engineReserved: Ptr;
|
||||
};
|
||||
inGcFinalizer: boolean;
|
||||
constructor(ctx: Context, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never);
|
||||
/** @virtual */
|
||||
canCallIntoJs(): boolean;
|
||||
terminatedOrTerminating(): boolean;
|
||||
ref(): void;
|
||||
unref(): void;
|
||||
ensureHandle<S>(value: S): Handle<S>;
|
||||
ensureHandleId(value: any): napi_value;
|
||||
clearLastError(): napi_status;
|
||||
setLastError(error_code: napi_status, engine_error_code?: uint32_t, engine_reserved?: void_p): napi_status;
|
||||
getReturnStatus(): napi_status;
|
||||
callIntoModule<T>(fn: (env: Env) => T, handleException?: (envObject: Env, value: any) => void): T;
|
||||
/** @virtual */
|
||||
abstract callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
|
||||
invokeFinalizerFromGC(finalizer: RefTracker): void;
|
||||
checkGCAccess(): void;
|
||||
/** @virtual */
|
||||
enqueueFinalizer(finalizer: RefTracker): void;
|
||||
/** @virtual */
|
||||
dequeueFinalizer(finalizer: RefTracker): void;
|
||||
/** @virtual */
|
||||
deleteMe(): void;
|
||||
dispose(): void;
|
||||
private readonly _bindingMap;
|
||||
initObjectBinding<S extends object>(value: S): IReferenceBinding;
|
||||
getObjectBinding<S extends object>(value: S): IReferenceBinding;
|
||||
setInstanceData(data: number, finalize_cb: number, finalize_hint: number): void;
|
||||
getInstanceData(): number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
declare interface External_2 extends Record<any, any> {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
declare const External_2: {
|
||||
new (value: number | bigint): External_2;
|
||||
prototype: null;
|
||||
};
|
||||
export { External_2 as External }
|
||||
|
||||
export declare class Finalizer {
|
||||
envObject: Env;
|
||||
private _finalizeCallback;
|
||||
private _finalizeData;
|
||||
private _finalizeHint;
|
||||
private _makeDynCall_vppp;
|
||||
constructor(envObject: Env, _finalizeCallback?: napi_finalize, _finalizeData?: void_p, _finalizeHint?: void_p);
|
||||
callback(): napi_finalize;
|
||||
data(): void_p;
|
||||
hint(): void_p;
|
||||
resetEnv(): void;
|
||||
resetFinalizer(): void;
|
||||
callFinalizer(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare function getDefaultContext(): Context;
|
||||
|
||||
/** @public */
|
||||
export declare function getExternalValue(external: External_2): number | bigint;
|
||||
|
||||
export declare class Handle<S> {
|
||||
id: number;
|
||||
value: S;
|
||||
constructor(id: number, value: S);
|
||||
data(): void_p;
|
||||
isNumber(): boolean;
|
||||
isBigInt(): boolean;
|
||||
isString(): boolean;
|
||||
isFunction(): boolean;
|
||||
isExternal(): boolean;
|
||||
isObject(): boolean;
|
||||
isArray(): boolean;
|
||||
isArrayBuffer(): boolean;
|
||||
isTypedArray(): boolean;
|
||||
isBuffer(BufferConstructor?: BufferCtor): boolean;
|
||||
isDataView(): boolean;
|
||||
isDate(): boolean;
|
||||
isPromise(): boolean;
|
||||
isBoolean(): boolean;
|
||||
isUndefined(): boolean;
|
||||
isSymbol(): boolean;
|
||||
isNull(): boolean;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class HandleScope {
|
||||
handleStore: HandleStore;
|
||||
id: number;
|
||||
parent: HandleScope | null;
|
||||
child: HandleScope | null;
|
||||
start: number;
|
||||
end: number;
|
||||
private _escapeCalled;
|
||||
callbackInfo: ICallbackInfo;
|
||||
constructor(handleStore: HandleStore, id: number, parentScope: HandleScope | null, start: number, end?: number);
|
||||
add<V>(value: V): Handle<V>;
|
||||
addExternal(data: void_p): Handle<object>;
|
||||
dispose(): void;
|
||||
escape(handle: number): Handle<any> | null;
|
||||
escapeCalled(): boolean;
|
||||
}
|
||||
|
||||
export declare class HandleStore {
|
||||
static UNDEFINED: ConstHandle<undefined>;
|
||||
static NULL: ConstHandle<null>;
|
||||
static FALSE: ConstHandle<false>;
|
||||
static TRUE: ConstHandle<true>;
|
||||
static GLOBAL: ConstHandle<typeof globalThis>;
|
||||
static MIN_ID: 6;
|
||||
private readonly _values;
|
||||
private _next;
|
||||
push<S>(value: S): Handle<S>;
|
||||
erase(start: number, end: number): void;
|
||||
get(id: Ptr): Handle<any> | undefined;
|
||||
swap(a: number, b: number): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare interface ICallbackInfo {
|
||||
thiz: any;
|
||||
data: void_p;
|
||||
args: ArrayLike<any>;
|
||||
fn: Function;
|
||||
}
|
||||
|
||||
export declare interface IDeferrdValue<T = any> {
|
||||
resolve: (value: T) => void;
|
||||
reject: (reason?: any) => void;
|
||||
}
|
||||
|
||||
export declare interface IReferenceBinding {
|
||||
wrapped: number;
|
||||
tag: Uint32Array | null;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare function isExternal(object: unknown): object is External_2;
|
||||
|
||||
export declare function isReferenceType(v: any): v is object;
|
||||
|
||||
export declare interface IStoreValue {
|
||||
id: number;
|
||||
dispose(): void;
|
||||
[x: string]: any;
|
||||
}
|
||||
|
||||
export declare const NAPI_VERSION_EXPERIMENTAL = Version.NAPI_VERSION_EXPERIMENTAL;
|
||||
|
||||
export declare const NODE_API_DEFAULT_MODULE_API_VERSION = Version.NODE_API_DEFAULT_MODULE_API_VERSION;
|
||||
|
||||
export declare const NODE_API_SUPPORTED_VERSION_MAX = Version.NODE_API_SUPPORTED_VERSION_MAX;
|
||||
|
||||
export declare const NODE_API_SUPPORTED_VERSION_MIN = Version.NODE_API_SUPPORTED_VERSION_MIN;
|
||||
|
||||
export declare class NodeEnv extends Env {
|
||||
filename: string;
|
||||
private readonly nodeBinding?;
|
||||
destructing: boolean;
|
||||
finalizationScheduled: boolean;
|
||||
constructor(ctx: Context, filename: string, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never, nodeBinding?: any);
|
||||
deleteMe(): void;
|
||||
canCallIntoJs(): boolean;
|
||||
triggerFatalException(err: any): void;
|
||||
callbackIntoModule<T>(enforceUncaughtExceptionPolicy: boolean, fn: (env: Env) => T): T;
|
||||
callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
|
||||
callFinalizerInternal(forceUncaught: int, cb: napi_finalize, data: void_p, hint: void_p): void;
|
||||
enqueueFinalizer(finalizer: RefTracker): void;
|
||||
drainFinalizerQueue(): void;
|
||||
}
|
||||
|
||||
export declare class NotSupportBufferError extends EmnapiError {
|
||||
constructor(api: string, message: string);
|
||||
}
|
||||
|
||||
export declare class NotSupportWeakRefError extends EmnapiError {
|
||||
constructor(api: string, message: string);
|
||||
}
|
||||
|
||||
export declare class Persistent<T> {
|
||||
private _ref;
|
||||
private _param;
|
||||
private _callback;
|
||||
private static readonly _registry;
|
||||
constructor(value: T);
|
||||
setWeak<P>(param: P, callback: (param: P) => void): void;
|
||||
clearWeak(): void;
|
||||
reset(): void;
|
||||
isEmpty(): boolean;
|
||||
deref(): T | undefined;
|
||||
}
|
||||
|
||||
export declare class Reference extends RefTracker implements IStoreValue {
|
||||
private static weakCallback;
|
||||
id: number;
|
||||
envObject: Env;
|
||||
private readonly canBeWeak;
|
||||
private _refcount;
|
||||
private readonly _ownership;
|
||||
persistent: Persistent<object>;
|
||||
static create(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, _unused1?: void_p, _unused2?: void_p, _unused3?: void_p): Reference;
|
||||
protected constructor(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership);
|
||||
ref(): number;
|
||||
unref(): number;
|
||||
get(envObject?: Env): napi_value;
|
||||
/** @virtual */
|
||||
resetFinalizer(): void;
|
||||
/** @virtual */
|
||||
data(): void_p;
|
||||
refcount(): number;
|
||||
ownership(): ReferenceOwnership;
|
||||
/** @virtual */
|
||||
protected callUserFinalizer(): void;
|
||||
/** @virtual */
|
||||
protected invokeFinalizerFromGC(): void;
|
||||
private _setWeak;
|
||||
finalize(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare enum ReferenceOwnership {
|
||||
kRuntime = 0,
|
||||
kUserland = 1
|
||||
}
|
||||
|
||||
export declare class ReferenceWithData extends Reference {
|
||||
private readonly _data;
|
||||
static create(envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): ReferenceWithData;
|
||||
private constructor();
|
||||
data(): void_p;
|
||||
}
|
||||
|
||||
export declare class ReferenceWithFinalizer extends Reference {
|
||||
private _finalizer;
|
||||
static create(envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): ReferenceWithFinalizer;
|
||||
private constructor();
|
||||
resetFinalizer(): void;
|
||||
data(): void_p;
|
||||
protected callUserFinalizer(): void;
|
||||
protected invokeFinalizerFromGC(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class RefTracker {
|
||||
/** @virtual */
|
||||
dispose(): void;
|
||||
/** @virtual */
|
||||
finalize(): void;
|
||||
private _next;
|
||||
private _prev;
|
||||
link(list: RefTracker): void;
|
||||
unlink(): void;
|
||||
static finalizeAll(list: RefTracker): void;
|
||||
}
|
||||
|
||||
export declare class ScopeStore {
|
||||
private readonly _rootScope;
|
||||
currentScope: HandleScope;
|
||||
private readonly _values;
|
||||
constructor();
|
||||
get(id: number): HandleScope | undefined;
|
||||
openScope(handleStore: HandleStore): HandleScope;
|
||||
closeScope(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class Store<V extends IStoreValue> {
|
||||
protected _values: Array<V | undefined>;
|
||||
private _freeList;
|
||||
private _size;
|
||||
constructor();
|
||||
add(value: V): void;
|
||||
get(id: Ptr): V | undefined;
|
||||
has(id: Ptr): boolean;
|
||||
remove(id: Ptr): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class TrackedFinalizer extends RefTracker {
|
||||
private _finalizer;
|
||||
static create(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
|
||||
private constructor();
|
||||
data(): void_p;
|
||||
dispose(): void;
|
||||
finalize(): void;
|
||||
}
|
||||
|
||||
export declare class TryCatch {
|
||||
private _exception;
|
||||
private _caught;
|
||||
isEmpty(): boolean;
|
||||
hasCaught(): boolean;
|
||||
exception(): any;
|
||||
setError(err: any): void;
|
||||
reset(): void;
|
||||
extractException(): any;
|
||||
}
|
||||
|
||||
export declare const version: string;
|
||||
|
||||
export { }
|
||||
|
||||
export as namespace emnapi;
|
||||
+1438
File diff suppressed because it is too large
Load Diff
+426
@@ -0,0 +1,426 @@
|
||||
declare namespace emnapi {
|
||||
|
||||
export type CleanupHookCallbackFunction = number | ((arg: number) => void);
|
||||
|
||||
export class ConstHandle<S extends undefined | null | boolean | typeof globalThis> extends Handle<S> {
|
||||
constructor(id: number, value: S);
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export class Context {
|
||||
private _isStopping;
|
||||
private _canCallIntoJs;
|
||||
private _suppressDestroy;
|
||||
envStore: Store<Env>;
|
||||
scopeStore: ScopeStore;
|
||||
refStore: Store<Reference>;
|
||||
deferredStore: Store<Deferred<any>>;
|
||||
handleStore: HandleStore;
|
||||
private readonly refCounter?;
|
||||
private readonly cleanupQueue;
|
||||
private readonly _externalMemory;
|
||||
feature: {
|
||||
supportReflect: boolean;
|
||||
supportFinalizer: boolean;
|
||||
supportWeakSymbol: boolean;
|
||||
supportBigInt: boolean;
|
||||
supportNewFunction: boolean;
|
||||
canSetFunctionName: boolean;
|
||||
setImmediate: (callback: () => void) => void;
|
||||
Buffer: BufferCtor | undefined;
|
||||
MessageChannel: {
|
||||
new (): MessageChannel;
|
||||
prototype: MessageChannel;
|
||||
} | undefined;
|
||||
};
|
||||
constructor(options?: ContextOptions);
|
||||
/**
|
||||
* Suppress the destroy on `beforeExit` event in Node.js.
|
||||
* Call this method if you want to keep the context and
|
||||
* all associated {@link Env | Env} alive,
|
||||
* this also means that cleanup hooks will not be called.
|
||||
* After call this method, you should call
|
||||
* {@link Context.destroy | `Context.prototype.destroy`} method manually.
|
||||
*/
|
||||
suppressDestroy(): void;
|
||||
getRuntimeVersions(): {
|
||||
version: string;
|
||||
NODE_API_SUPPORTED_VERSION_MAX: Version;
|
||||
NAPI_VERSION_EXPERIMENTAL: Version;
|
||||
NODE_API_DEFAULT_MODULE_API_VERSION: Version;
|
||||
};
|
||||
createNotSupportWeakRefError(api: string, message: string): NotSupportWeakRefError;
|
||||
createNotSupportBufferError(api: string, message: string): NotSupportBufferError;
|
||||
createReference(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership): Reference;
|
||||
createReferenceWithData(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): Reference;
|
||||
createReferenceWithFinalizer(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback?: napi_finalize, finalize_data?: void_p, finalize_hint?: void_p): Reference;
|
||||
createDeferred<T = any>(value: IDeferrdValue<T>): Deferred<T>;
|
||||
adjustAmountOfExternalAllocatedMemory(changeInBytes: number | bigint): bigint;
|
||||
createEnv(filename: string, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never, nodeBinding?: any): Env;
|
||||
createTrackedFinalizer(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
|
||||
getCurrentScope(): HandleScope | null;
|
||||
addToCurrentScope<V>(value: V): Handle<V>;
|
||||
openScope(envObject?: Env): HandleScope;
|
||||
closeScope(envObject?: Env, _scope?: HandleScope): void;
|
||||
ensureHandle<S>(value: S): Handle<S>;
|
||||
addCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
|
||||
removeCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
|
||||
runCleanup(): void;
|
||||
increaseWaitingRequestCounter(): void;
|
||||
decreaseWaitingRequestCounter(): void;
|
||||
setCanCallIntoJs(value: boolean): void;
|
||||
setStopping(value: boolean): void;
|
||||
canCallIntoJs(): boolean;
|
||||
/**
|
||||
* Destroy the context and call cleanup hooks.
|
||||
* Associated {@link Env | Env} will be destroyed.
|
||||
*/
|
||||
destroy(): void;
|
||||
}
|
||||
|
||||
export interface ContextOptions {
|
||||
onExternalMemoryChange?: (current: bigint, old: bigint, delta: bigint) => any;
|
||||
}
|
||||
|
||||
export function createContext(options?: ContextOptions): Context;
|
||||
|
||||
export class Deferred<T = any> implements IStoreValue {
|
||||
static create<T = any>(ctx: Context, value: IDeferrdValue<T>): Deferred;
|
||||
id: number;
|
||||
ctx: Context;
|
||||
value: IDeferrdValue<T>;
|
||||
constructor(ctx: Context, value: IDeferrdValue<T>);
|
||||
resolve(value: T): void;
|
||||
reject(reason?: any): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export class EmnapiError extends Error {
|
||||
constructor(message?: string);
|
||||
}
|
||||
|
||||
export abstract class Env implements IStoreValue {
|
||||
readonly ctx: Context;
|
||||
moduleApiVersion: number;
|
||||
makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void;
|
||||
makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void;
|
||||
abort: (msg?: string) => never;
|
||||
id: number;
|
||||
openHandleScopes: number;
|
||||
instanceData: TrackedFinalizer | null;
|
||||
tryCatch: TryCatch;
|
||||
refs: number;
|
||||
reflist: RefTracker;
|
||||
finalizing_reflist: RefTracker;
|
||||
pendingFinalizers: RefTracker[];
|
||||
lastError: {
|
||||
errorCode: napi_status;
|
||||
engineErrorCode: number;
|
||||
engineReserved: Ptr;
|
||||
};
|
||||
inGcFinalizer: boolean;
|
||||
constructor(ctx: Context, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never);
|
||||
/** @virtual */
|
||||
canCallIntoJs(): boolean;
|
||||
terminatedOrTerminating(): boolean;
|
||||
ref(): void;
|
||||
unref(): void;
|
||||
ensureHandle<S>(value: S): Handle<S>;
|
||||
ensureHandleId(value: any): napi_value;
|
||||
clearLastError(): napi_status;
|
||||
setLastError(error_code: napi_status, engine_error_code?: uint32_t, engine_reserved?: void_p): napi_status;
|
||||
getReturnStatus(): napi_status;
|
||||
callIntoModule<T>(fn: (env: Env) => T, handleException?: (envObject: Env, value: any) => void): T;
|
||||
/** @virtual */
|
||||
abstract callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
|
||||
invokeFinalizerFromGC(finalizer: RefTracker): void;
|
||||
checkGCAccess(): void;
|
||||
/** @virtual */
|
||||
enqueueFinalizer(finalizer: RefTracker): void;
|
||||
/** @virtual */
|
||||
dequeueFinalizer(finalizer: RefTracker): void;
|
||||
/** @virtual */
|
||||
deleteMe(): void;
|
||||
dispose(): void;
|
||||
private readonly _bindingMap;
|
||||
initObjectBinding<S extends object>(value: S): IReferenceBinding;
|
||||
getObjectBinding<S extends object>(value: S): IReferenceBinding;
|
||||
setInstanceData(data: number, finalize_cb: number, finalize_hint: number): void;
|
||||
getInstanceData(): number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
interface External_2 extends Record<any, any> {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
const External_2: {
|
||||
new (value: number | bigint): External_2;
|
||||
prototype: null;
|
||||
};
|
||||
export { External_2 as External }
|
||||
|
||||
export class Finalizer {
|
||||
envObject: Env;
|
||||
private _finalizeCallback;
|
||||
private _finalizeData;
|
||||
private _finalizeHint;
|
||||
private _makeDynCall_vppp;
|
||||
constructor(envObject: Env, _finalizeCallback?: napi_finalize, _finalizeData?: void_p, _finalizeHint?: void_p);
|
||||
callback(): napi_finalize;
|
||||
data(): void_p;
|
||||
hint(): void_p;
|
||||
resetEnv(): void;
|
||||
resetFinalizer(): void;
|
||||
callFinalizer(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export function getDefaultContext(): Context;
|
||||
|
||||
/** @public */
|
||||
export function getExternalValue(external: External_2): number | bigint;
|
||||
|
||||
export class Handle<S> {
|
||||
id: number;
|
||||
value: S;
|
||||
constructor(id: number, value: S);
|
||||
data(): void_p;
|
||||
isNumber(): boolean;
|
||||
isBigInt(): boolean;
|
||||
isString(): boolean;
|
||||
isFunction(): boolean;
|
||||
isExternal(): boolean;
|
||||
isObject(): boolean;
|
||||
isArray(): boolean;
|
||||
isArrayBuffer(): boolean;
|
||||
isTypedArray(): boolean;
|
||||
isBuffer(BufferConstructor?: BufferCtor): boolean;
|
||||
isDataView(): boolean;
|
||||
isDate(): boolean;
|
||||
isPromise(): boolean;
|
||||
isBoolean(): boolean;
|
||||
isUndefined(): boolean;
|
||||
isSymbol(): boolean;
|
||||
isNull(): boolean;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export class HandleScope {
|
||||
handleStore: HandleStore;
|
||||
id: number;
|
||||
parent: HandleScope | null;
|
||||
child: HandleScope | null;
|
||||
start: number;
|
||||
end: number;
|
||||
private _escapeCalled;
|
||||
callbackInfo: ICallbackInfo;
|
||||
constructor(handleStore: HandleStore, id: number, parentScope: HandleScope | null, start: number, end?: number);
|
||||
add<V>(value: V): Handle<V>;
|
||||
addExternal(data: void_p): Handle<object>;
|
||||
dispose(): void;
|
||||
escape(handle: number): Handle<any> | null;
|
||||
escapeCalled(): boolean;
|
||||
}
|
||||
|
||||
export class HandleStore {
|
||||
static UNDEFINED: ConstHandle<undefined>;
|
||||
static NULL: ConstHandle<null>;
|
||||
static FALSE: ConstHandle<false>;
|
||||
static TRUE: ConstHandle<true>;
|
||||
static GLOBAL: ConstHandle<typeof globalThis>;
|
||||
static MIN_ID: 6;
|
||||
private readonly _values;
|
||||
private _next;
|
||||
push<S>(value: S): Handle<S>;
|
||||
erase(start: number, end: number): void;
|
||||
get(id: Ptr): Handle<any> | undefined;
|
||||
swap(a: number, b: number): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export interface ICallbackInfo {
|
||||
thiz: any;
|
||||
data: void_p;
|
||||
args: ArrayLike<any>;
|
||||
fn: Function;
|
||||
}
|
||||
|
||||
export interface IDeferrdValue<T = any> {
|
||||
resolve: (value: T) => void;
|
||||
reject: (reason?: any) => void;
|
||||
}
|
||||
|
||||
export interface IReferenceBinding {
|
||||
wrapped: number;
|
||||
tag: Uint32Array | null;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export function isExternal(object: unknown): object is External_2;
|
||||
|
||||
export function isReferenceType(v: any): v is object;
|
||||
|
||||
export interface IStoreValue {
|
||||
id: number;
|
||||
dispose(): void;
|
||||
[x: string]: any;
|
||||
}
|
||||
|
||||
export const NAPI_VERSION_EXPERIMENTAL = Version.NAPI_VERSION_EXPERIMENTAL;
|
||||
|
||||
export const NODE_API_DEFAULT_MODULE_API_VERSION = Version.NODE_API_DEFAULT_MODULE_API_VERSION;
|
||||
|
||||
export const NODE_API_SUPPORTED_VERSION_MAX = Version.NODE_API_SUPPORTED_VERSION_MAX;
|
||||
|
||||
export const NODE_API_SUPPORTED_VERSION_MIN = Version.NODE_API_SUPPORTED_VERSION_MIN;
|
||||
|
||||
export class NodeEnv extends Env {
|
||||
filename: string;
|
||||
private readonly nodeBinding?;
|
||||
destructing: boolean;
|
||||
finalizationScheduled: boolean;
|
||||
constructor(ctx: Context, filename: string, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never, nodeBinding?: any);
|
||||
deleteMe(): void;
|
||||
canCallIntoJs(): boolean;
|
||||
triggerFatalException(err: any): void;
|
||||
callbackIntoModule<T>(enforceUncaughtExceptionPolicy: boolean, fn: (env: Env) => T): T;
|
||||
callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
|
||||
callFinalizerInternal(forceUncaught: int, cb: napi_finalize, data: void_p, hint: void_p): void;
|
||||
enqueueFinalizer(finalizer: RefTracker): void;
|
||||
drainFinalizerQueue(): void;
|
||||
}
|
||||
|
||||
export class NotSupportBufferError extends EmnapiError {
|
||||
constructor(api: string, message: string);
|
||||
}
|
||||
|
||||
export class NotSupportWeakRefError extends EmnapiError {
|
||||
constructor(api: string, message: string);
|
||||
}
|
||||
|
||||
export class Persistent<T> {
|
||||
private _ref;
|
||||
private _param;
|
||||
private _callback;
|
||||
private static readonly _registry;
|
||||
constructor(value: T);
|
||||
setWeak<P>(param: P, callback: (param: P) => void): void;
|
||||
clearWeak(): void;
|
||||
reset(): void;
|
||||
isEmpty(): boolean;
|
||||
deref(): T | undefined;
|
||||
}
|
||||
|
||||
export class Reference extends RefTracker implements IStoreValue {
|
||||
private static weakCallback;
|
||||
id: number;
|
||||
envObject: Env;
|
||||
private readonly canBeWeak;
|
||||
private _refcount;
|
||||
private readonly _ownership;
|
||||
persistent: Persistent<object>;
|
||||
static create(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, _unused1?: void_p, _unused2?: void_p, _unused3?: void_p): Reference;
|
||||
protected constructor(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership);
|
||||
ref(): number;
|
||||
unref(): number;
|
||||
get(envObject?: Env): napi_value;
|
||||
/** @virtual */
|
||||
resetFinalizer(): void;
|
||||
/** @virtual */
|
||||
data(): void_p;
|
||||
refcount(): number;
|
||||
ownership(): ReferenceOwnership;
|
||||
/** @virtual */
|
||||
protected callUserFinalizer(): void;
|
||||
/** @virtual */
|
||||
protected invokeFinalizerFromGC(): void;
|
||||
private _setWeak;
|
||||
finalize(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export enum ReferenceOwnership {
|
||||
kRuntime = 0,
|
||||
kUserland = 1
|
||||
}
|
||||
|
||||
export class ReferenceWithData extends Reference {
|
||||
private readonly _data;
|
||||
static create(envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): ReferenceWithData;
|
||||
private constructor();
|
||||
data(): void_p;
|
||||
}
|
||||
|
||||
export class ReferenceWithFinalizer extends Reference {
|
||||
private _finalizer;
|
||||
static create(envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): ReferenceWithFinalizer;
|
||||
private constructor();
|
||||
resetFinalizer(): void;
|
||||
data(): void_p;
|
||||
protected callUserFinalizer(): void;
|
||||
protected invokeFinalizerFromGC(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export class RefTracker {
|
||||
/** @virtual */
|
||||
dispose(): void;
|
||||
/** @virtual */
|
||||
finalize(): void;
|
||||
private _next;
|
||||
private _prev;
|
||||
link(list: RefTracker): void;
|
||||
unlink(): void;
|
||||
static finalizeAll(list: RefTracker): void;
|
||||
}
|
||||
|
||||
export class ScopeStore {
|
||||
private readonly _rootScope;
|
||||
currentScope: HandleScope;
|
||||
private readonly _values;
|
||||
constructor();
|
||||
get(id: number): HandleScope | undefined;
|
||||
openScope(handleStore: HandleStore): HandleScope;
|
||||
closeScope(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export class Store<V extends IStoreValue> {
|
||||
protected _values: Array<V | undefined>;
|
||||
private _freeList;
|
||||
private _size;
|
||||
constructor();
|
||||
add(value: V): void;
|
||||
get(id: Ptr): V | undefined;
|
||||
has(id: Ptr): boolean;
|
||||
remove(id: Ptr): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export class TrackedFinalizer extends RefTracker {
|
||||
private _finalizer;
|
||||
static create(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
|
||||
private constructor();
|
||||
data(): void_p;
|
||||
dispose(): void;
|
||||
finalize(): void;
|
||||
}
|
||||
|
||||
export class TryCatch {
|
||||
private _exception;
|
||||
private _caught;
|
||||
isEmpty(): boolean;
|
||||
hasCaught(): boolean;
|
||||
exception(): any;
|
||||
setError(err: any): void;
|
||||
reset(): void;
|
||||
extractException(): any;
|
||||
}
|
||||
|
||||
export const version: string;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
+1509
File diff suppressed because it is too large
Load Diff
+1510
File diff suppressed because it is too large
Load Diff
+671
@@ -0,0 +1,671 @@
|
||||
export declare type Ptr = number | bigint
|
||||
|
||||
export declare interface IBuffer extends Uint8Array {}
|
||||
export declare interface BufferCtor {
|
||||
readonly prototype: IBuffer
|
||||
/** @deprecated */
|
||||
new (...args: any[]): IBuffer
|
||||
from: {
|
||||
(buffer: ArrayBufferLike): IBuffer
|
||||
(buffer: ArrayBufferLike, byteOffset: number, length: number): IBuffer
|
||||
}
|
||||
alloc: (size: number) => IBuffer
|
||||
isBuffer: (obj: unknown) => obj is IBuffer
|
||||
}
|
||||
|
||||
export declare const enum GlobalHandle {
|
||||
UNDEFINED = 1,
|
||||
NULL,
|
||||
FALSE,
|
||||
TRUE,
|
||||
GLOBAL
|
||||
}
|
||||
|
||||
export declare const enum Version {
|
||||
NODE_API_SUPPORTED_VERSION_MIN = 1,
|
||||
NODE_API_DEFAULT_MODULE_API_VERSION = 8,
|
||||
NODE_API_SUPPORTED_VERSION_MAX = 10,
|
||||
NAPI_VERSION_EXPERIMENTAL = 2147483647 // INT_MAX
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export declare type Pointer<T> = number
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export declare type PointerPointer<T> = number
|
||||
export declare type FunctionPointer<T extends (...args: any[]) => any> = Pointer<T>
|
||||
export declare type Const<T> = T
|
||||
|
||||
export declare type void_p = Pointer<void>
|
||||
export declare type void_pp = Pointer<void_p>
|
||||
export declare type bool = number
|
||||
export declare type char = number
|
||||
export declare type char_p = Pointer<char>
|
||||
export declare type unsigned_char = number
|
||||
export declare type const_char = Const<char>
|
||||
export declare type const_char_p = Pointer<const_char>
|
||||
export declare type char16_t_p = number
|
||||
export declare type const_char16_t_p = number
|
||||
|
||||
export declare type short = number
|
||||
export declare type unsigned_short = number
|
||||
export declare type int = number
|
||||
export declare type unsigned_int = number
|
||||
export declare type long = number
|
||||
export declare type unsigned_long = number
|
||||
export declare type long_long = bigint
|
||||
export declare type unsigned_long_long = bigint
|
||||
export declare type float = number
|
||||
export declare type double = number
|
||||
export declare type long_double = number
|
||||
export declare type size_t = number
|
||||
|
||||
export declare type int8_t = number
|
||||
export declare type uint8_t = number
|
||||
export declare type int16_t = number
|
||||
export declare type uint16_t = number
|
||||
export declare type int32_t = number
|
||||
export declare type uint32_t = number
|
||||
export declare type int64_t = bigint
|
||||
export declare type uint64_t = bigint
|
||||
export declare type napi_env = Pointer<unknown>
|
||||
|
||||
export declare type napi_value = Pointer<unknown>
|
||||
export declare type napi_ref = Pointer<unknown>
|
||||
export declare type napi_deferred = Pointer<unknown>
|
||||
export declare type napi_handle_scope = Pointer<unknown>
|
||||
export declare type napi_escapable_handle_scope = Pointer<unknown>
|
||||
|
||||
export declare type napi_addon_register_func = FunctionPointer<(env: napi_env, exports: napi_value) => napi_value>
|
||||
|
||||
export declare type napi_callback_info = Pointer<unknown>
|
||||
export declare type napi_callback = FunctionPointer<(env: napi_env, info: napi_callback_info) => napi_value>
|
||||
|
||||
export declare interface napi_extended_error_info {
|
||||
error_message: const_char_p
|
||||
engine_reserved: void_p
|
||||
engine_error_code: uint32_t
|
||||
error_code: napi_status
|
||||
}
|
||||
|
||||
export declare interface napi_property_descriptor {
|
||||
// One of utf8name or name should be NULL.
|
||||
utf8name: const_char_p
|
||||
name: napi_value
|
||||
|
||||
method: napi_callback
|
||||
getter: napi_callback
|
||||
setter: napi_callback
|
||||
value: napi_value
|
||||
/* napi_property_attributes */
|
||||
attributes: number
|
||||
data: void_p
|
||||
}
|
||||
|
||||
export declare type napi_finalize = FunctionPointer<(
|
||||
env: napi_env,
|
||||
finalize_data: void_p,
|
||||
finalize_hint: void_p
|
||||
) => void>
|
||||
|
||||
export declare interface node_module {
|
||||
nm_version: int32_t
|
||||
nm_flags: uint32_t
|
||||
nm_filename: Pointer<const_char>
|
||||
nm_register_func: napi_addon_register_func
|
||||
nm_modname: Pointer<const_char>
|
||||
nm_priv: Pointer<void>
|
||||
reserved: PointerPointer<void>
|
||||
}
|
||||
|
||||
export declare interface napi_node_version {
|
||||
major: uint32_t
|
||||
minor: uint32_t
|
||||
patch: uint32_t
|
||||
release: const_char_p
|
||||
}
|
||||
|
||||
export declare interface emnapi_emscripten_version {
|
||||
major: uint32_t
|
||||
minor: uint32_t
|
||||
patch: uint32_t
|
||||
}
|
||||
|
||||
export declare const enum napi_status {
|
||||
napi_ok,
|
||||
napi_invalid_arg,
|
||||
napi_object_expected,
|
||||
napi_string_expected,
|
||||
napi_name_expected,
|
||||
napi_function_expected,
|
||||
napi_number_expected,
|
||||
napi_boolean_expected,
|
||||
napi_array_expected,
|
||||
napi_generic_failure,
|
||||
napi_pending_exception,
|
||||
napi_cancelled,
|
||||
napi_escape_called_twice,
|
||||
napi_handle_scope_mismatch,
|
||||
napi_callback_scope_mismatch,
|
||||
napi_queue_full,
|
||||
napi_closing,
|
||||
napi_bigint_expected,
|
||||
napi_date_expected,
|
||||
napi_arraybuffer_expected,
|
||||
napi_detachable_arraybuffer_expected,
|
||||
napi_would_deadlock, // unused
|
||||
napi_no_external_buffers_allowed,
|
||||
napi_cannot_run_js
|
||||
}
|
||||
|
||||
export declare const enum napi_property_attributes {
|
||||
napi_default = 0,
|
||||
napi_writable = 1 << 0,
|
||||
napi_enumerable = 1 << 1,
|
||||
napi_configurable = 1 << 2,
|
||||
|
||||
// Used with napi_define_class to distinguish static properties
|
||||
// from instance properties. Ignored by napi_define_properties.
|
||||
napi_static = 1 << 10,
|
||||
|
||||
/// #ifdef NAPI_EXPERIMENTAL
|
||||
// Default for class methods.
|
||||
napi_default_method = napi_writable | napi_configurable,
|
||||
|
||||
// Default for object properties, like in JS obj[prop].
|
||||
napi_default_jsproperty = napi_writable | napi_enumerable | napi_configurable
|
||||
/// #endif // NAPI_EXPERIMENTAL
|
||||
}
|
||||
|
||||
export declare const enum napi_valuetype {
|
||||
napi_undefined,
|
||||
napi_null,
|
||||
napi_boolean,
|
||||
napi_number,
|
||||
napi_string,
|
||||
napi_symbol,
|
||||
napi_object,
|
||||
napi_function,
|
||||
napi_external,
|
||||
napi_bigint
|
||||
}
|
||||
|
||||
export declare const enum napi_typedarray_type {
|
||||
napi_int8_array,
|
||||
napi_uint8_array,
|
||||
napi_uint8_clamped_array,
|
||||
napi_int16_array,
|
||||
napi_uint16_array,
|
||||
napi_int32_array,
|
||||
napi_uint32_array,
|
||||
napi_float32_array,
|
||||
napi_float64_array,
|
||||
napi_bigint64_array,
|
||||
napi_biguint64_array,
|
||||
napi_float16_array,
|
||||
}
|
||||
|
||||
export declare const enum napi_key_collection_mode {
|
||||
napi_key_include_prototypes,
|
||||
napi_key_own_only
|
||||
}
|
||||
|
||||
export declare const enum napi_key_filter {
|
||||
napi_key_all_properties = 0,
|
||||
napi_key_writable = 1,
|
||||
napi_key_enumerable = 1 << 1,
|
||||
napi_key_configurable = 1 << 2,
|
||||
napi_key_skip_strings = 1 << 3,
|
||||
napi_key_skip_symbols = 1 << 4
|
||||
}
|
||||
|
||||
export declare const enum napi_key_conversion {
|
||||
napi_key_keep_numbers,
|
||||
napi_key_numbers_to_strings
|
||||
}
|
||||
|
||||
export declare const enum emnapi_memory_view_type {
|
||||
emnapi_int8_array,
|
||||
emnapi_uint8_array,
|
||||
emnapi_uint8_clamped_array,
|
||||
emnapi_int16_array,
|
||||
emnapi_uint16_array,
|
||||
emnapi_int32_array,
|
||||
emnapi_uint32_array,
|
||||
emnapi_float32_array,
|
||||
emnapi_float64_array,
|
||||
emnapi_bigint64_array,
|
||||
emnapi_biguint64_array,
|
||||
emnapi_float16_array,
|
||||
emnapi_data_view = -1,
|
||||
emnapi_buffer = -2
|
||||
}
|
||||
|
||||
export declare const enum napi_threadsafe_function_call_mode {
|
||||
napi_tsfn_nonblocking,
|
||||
napi_tsfn_blocking
|
||||
}
|
||||
|
||||
export declare const enum napi_threadsafe_function_release_mode {
|
||||
napi_tsfn_release,
|
||||
napi_tsfn_abort
|
||||
}
|
||||
export declare type CleanupHookCallbackFunction = number | ((arg: number) => void);
|
||||
|
||||
export declare class ConstHandle<S extends undefined | null | boolean | typeof globalThis> extends Handle<S> {
|
||||
constructor(id: number, value: S);
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class Context {
|
||||
private _isStopping;
|
||||
private _canCallIntoJs;
|
||||
private _suppressDestroy;
|
||||
envStore: Store<Env>;
|
||||
scopeStore: ScopeStore;
|
||||
refStore: Store<Reference>;
|
||||
deferredStore: Store<Deferred<any>>;
|
||||
handleStore: HandleStore;
|
||||
private readonly refCounter?;
|
||||
private readonly cleanupQueue;
|
||||
private readonly _externalMemory;
|
||||
feature: {
|
||||
supportReflect: boolean;
|
||||
supportFinalizer: boolean;
|
||||
supportWeakSymbol: boolean;
|
||||
supportBigInt: boolean;
|
||||
supportNewFunction: boolean;
|
||||
canSetFunctionName: boolean;
|
||||
setImmediate: (callback: () => void) => void;
|
||||
Buffer: BufferCtor | undefined;
|
||||
MessageChannel: {
|
||||
new (): MessageChannel;
|
||||
prototype: MessageChannel;
|
||||
} | undefined;
|
||||
};
|
||||
constructor(options?: ContextOptions);
|
||||
/**
|
||||
* Suppress the destroy on `beforeExit` event in Node.js.
|
||||
* Call this method if you want to keep the context and
|
||||
* all associated {@link Env | Env} alive,
|
||||
* this also means that cleanup hooks will not be called.
|
||||
* After call this method, you should call
|
||||
* {@link Context.destroy | `Context.prototype.destroy`} method manually.
|
||||
*/
|
||||
suppressDestroy(): void;
|
||||
getRuntimeVersions(): {
|
||||
version: string;
|
||||
NODE_API_SUPPORTED_VERSION_MAX: Version;
|
||||
NAPI_VERSION_EXPERIMENTAL: Version;
|
||||
NODE_API_DEFAULT_MODULE_API_VERSION: Version;
|
||||
};
|
||||
createNotSupportWeakRefError(api: string, message: string): NotSupportWeakRefError;
|
||||
createNotSupportBufferError(api: string, message: string): NotSupportBufferError;
|
||||
createReference(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership): Reference;
|
||||
createReferenceWithData(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): Reference;
|
||||
createReferenceWithFinalizer(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback?: napi_finalize, finalize_data?: void_p, finalize_hint?: void_p): Reference;
|
||||
createDeferred<T = any>(value: IDeferrdValue<T>): Deferred<T>;
|
||||
adjustAmountOfExternalAllocatedMemory(changeInBytes: number | bigint): bigint;
|
||||
createEnv(filename: string, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never, nodeBinding?: any): Env;
|
||||
createTrackedFinalizer(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
|
||||
getCurrentScope(): HandleScope | null;
|
||||
addToCurrentScope<V>(value: V): Handle<V>;
|
||||
openScope(envObject?: Env): HandleScope;
|
||||
closeScope(envObject?: Env, _scope?: HandleScope): void;
|
||||
ensureHandle<S>(value: S): Handle<S>;
|
||||
addCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
|
||||
removeCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
|
||||
runCleanup(): void;
|
||||
increaseWaitingRequestCounter(): void;
|
||||
decreaseWaitingRequestCounter(): void;
|
||||
setCanCallIntoJs(value: boolean): void;
|
||||
setStopping(value: boolean): void;
|
||||
canCallIntoJs(): boolean;
|
||||
/**
|
||||
* Destroy the context and call cleanup hooks.
|
||||
* Associated {@link Env | Env} will be destroyed.
|
||||
*/
|
||||
destroy(): void;
|
||||
}
|
||||
|
||||
export declare interface ContextOptions {
|
||||
onExternalMemoryChange?: (current: bigint, old: bigint, delta: bigint) => any;
|
||||
}
|
||||
|
||||
export declare function createContext(options?: ContextOptions): Context;
|
||||
|
||||
export declare class Deferred<T = any> implements IStoreValue {
|
||||
static create<T = any>(ctx: Context, value: IDeferrdValue<T>): Deferred;
|
||||
id: number;
|
||||
ctx: Context;
|
||||
value: IDeferrdValue<T>;
|
||||
constructor(ctx: Context, value: IDeferrdValue<T>);
|
||||
resolve(value: T): void;
|
||||
reject(reason?: any): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class EmnapiError extends Error {
|
||||
constructor(message?: string);
|
||||
}
|
||||
|
||||
export declare abstract class Env implements IStoreValue {
|
||||
readonly ctx: Context;
|
||||
moduleApiVersion: number;
|
||||
makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void;
|
||||
makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void;
|
||||
abort: (msg?: string) => never;
|
||||
id: number;
|
||||
openHandleScopes: number;
|
||||
instanceData: TrackedFinalizer | null;
|
||||
tryCatch: TryCatch;
|
||||
refs: number;
|
||||
reflist: RefTracker;
|
||||
finalizing_reflist: RefTracker;
|
||||
pendingFinalizers: RefTracker[];
|
||||
lastError: {
|
||||
errorCode: napi_status;
|
||||
engineErrorCode: number;
|
||||
engineReserved: Ptr;
|
||||
};
|
||||
inGcFinalizer: boolean;
|
||||
constructor(ctx: Context, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never);
|
||||
/** @virtual */
|
||||
canCallIntoJs(): boolean;
|
||||
terminatedOrTerminating(): boolean;
|
||||
ref(): void;
|
||||
unref(): void;
|
||||
ensureHandle<S>(value: S): Handle<S>;
|
||||
ensureHandleId(value: any): napi_value;
|
||||
clearLastError(): napi_status;
|
||||
setLastError(error_code: napi_status, engine_error_code?: uint32_t, engine_reserved?: void_p): napi_status;
|
||||
getReturnStatus(): napi_status;
|
||||
callIntoModule<T>(fn: (env: Env) => T, handleException?: (envObject: Env, value: any) => void): T;
|
||||
/** @virtual */
|
||||
abstract callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
|
||||
invokeFinalizerFromGC(finalizer: RefTracker): void;
|
||||
checkGCAccess(): void;
|
||||
/** @virtual */
|
||||
enqueueFinalizer(finalizer: RefTracker): void;
|
||||
/** @virtual */
|
||||
dequeueFinalizer(finalizer: RefTracker): void;
|
||||
/** @virtual */
|
||||
deleteMe(): void;
|
||||
dispose(): void;
|
||||
private readonly _bindingMap;
|
||||
initObjectBinding<S extends object>(value: S): IReferenceBinding;
|
||||
getObjectBinding<S extends object>(value: S): IReferenceBinding;
|
||||
setInstanceData(data: number, finalize_cb: number, finalize_hint: number): void;
|
||||
getInstanceData(): number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
declare interface External_2 extends Record<any, any> {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
declare const External_2: {
|
||||
new (value: number | bigint): External_2;
|
||||
prototype: null;
|
||||
};
|
||||
export { External_2 as External }
|
||||
|
||||
export declare class Finalizer {
|
||||
envObject: Env;
|
||||
private _finalizeCallback;
|
||||
private _finalizeData;
|
||||
private _finalizeHint;
|
||||
private _makeDynCall_vppp;
|
||||
constructor(envObject: Env, _finalizeCallback?: napi_finalize, _finalizeData?: void_p, _finalizeHint?: void_p);
|
||||
callback(): napi_finalize;
|
||||
data(): void_p;
|
||||
hint(): void_p;
|
||||
resetEnv(): void;
|
||||
resetFinalizer(): void;
|
||||
callFinalizer(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare function getDefaultContext(): Context;
|
||||
|
||||
/** @public */
|
||||
export declare function getExternalValue(external: External_2): number | bigint;
|
||||
|
||||
export declare class Handle<S> {
|
||||
id: number;
|
||||
value: S;
|
||||
constructor(id: number, value: S);
|
||||
data(): void_p;
|
||||
isNumber(): boolean;
|
||||
isBigInt(): boolean;
|
||||
isString(): boolean;
|
||||
isFunction(): boolean;
|
||||
isExternal(): boolean;
|
||||
isObject(): boolean;
|
||||
isArray(): boolean;
|
||||
isArrayBuffer(): boolean;
|
||||
isTypedArray(): boolean;
|
||||
isBuffer(BufferConstructor?: BufferCtor): boolean;
|
||||
isDataView(): boolean;
|
||||
isDate(): boolean;
|
||||
isPromise(): boolean;
|
||||
isBoolean(): boolean;
|
||||
isUndefined(): boolean;
|
||||
isSymbol(): boolean;
|
||||
isNull(): boolean;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class HandleScope {
|
||||
handleStore: HandleStore;
|
||||
id: number;
|
||||
parent: HandleScope | null;
|
||||
child: HandleScope | null;
|
||||
start: number;
|
||||
end: number;
|
||||
private _escapeCalled;
|
||||
callbackInfo: ICallbackInfo;
|
||||
constructor(handleStore: HandleStore, id: number, parentScope: HandleScope | null, start: number, end?: number);
|
||||
add<V>(value: V): Handle<V>;
|
||||
addExternal(data: void_p): Handle<object>;
|
||||
dispose(): void;
|
||||
escape(handle: number): Handle<any> | null;
|
||||
escapeCalled(): boolean;
|
||||
}
|
||||
|
||||
export declare class HandleStore {
|
||||
static UNDEFINED: ConstHandle<undefined>;
|
||||
static NULL: ConstHandle<null>;
|
||||
static FALSE: ConstHandle<false>;
|
||||
static TRUE: ConstHandle<true>;
|
||||
static GLOBAL: ConstHandle<typeof globalThis>;
|
||||
static MIN_ID: 6;
|
||||
private readonly _values;
|
||||
private _next;
|
||||
push<S>(value: S): Handle<S>;
|
||||
erase(start: number, end: number): void;
|
||||
get(id: Ptr): Handle<any> | undefined;
|
||||
swap(a: number, b: number): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare interface ICallbackInfo {
|
||||
thiz: any;
|
||||
data: void_p;
|
||||
args: ArrayLike<any>;
|
||||
fn: Function;
|
||||
}
|
||||
|
||||
export declare interface IDeferrdValue<T = any> {
|
||||
resolve: (value: T) => void;
|
||||
reject: (reason?: any) => void;
|
||||
}
|
||||
|
||||
export declare interface IReferenceBinding {
|
||||
wrapped: number;
|
||||
tag: Uint32Array | null;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare function isExternal(object: unknown): object is External_2;
|
||||
|
||||
export declare function isReferenceType(v: any): v is object;
|
||||
|
||||
export declare interface IStoreValue {
|
||||
id: number;
|
||||
dispose(): void;
|
||||
[x: string]: any;
|
||||
}
|
||||
|
||||
export declare const NAPI_VERSION_EXPERIMENTAL = Version.NAPI_VERSION_EXPERIMENTAL;
|
||||
|
||||
export declare const NODE_API_DEFAULT_MODULE_API_VERSION = Version.NODE_API_DEFAULT_MODULE_API_VERSION;
|
||||
|
||||
export declare const NODE_API_SUPPORTED_VERSION_MAX = Version.NODE_API_SUPPORTED_VERSION_MAX;
|
||||
|
||||
export declare const NODE_API_SUPPORTED_VERSION_MIN = Version.NODE_API_SUPPORTED_VERSION_MIN;
|
||||
|
||||
export declare class NodeEnv extends Env {
|
||||
filename: string;
|
||||
private readonly nodeBinding?;
|
||||
destructing: boolean;
|
||||
finalizationScheduled: boolean;
|
||||
constructor(ctx: Context, filename: string, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never, nodeBinding?: any);
|
||||
deleteMe(): void;
|
||||
canCallIntoJs(): boolean;
|
||||
triggerFatalException(err: any): void;
|
||||
callbackIntoModule<T>(enforceUncaughtExceptionPolicy: boolean, fn: (env: Env) => T): T;
|
||||
callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
|
||||
callFinalizerInternal(forceUncaught: int, cb: napi_finalize, data: void_p, hint: void_p): void;
|
||||
enqueueFinalizer(finalizer: RefTracker): void;
|
||||
drainFinalizerQueue(): void;
|
||||
}
|
||||
|
||||
export declare class NotSupportBufferError extends EmnapiError {
|
||||
constructor(api: string, message: string);
|
||||
}
|
||||
|
||||
export declare class NotSupportWeakRefError extends EmnapiError {
|
||||
constructor(api: string, message: string);
|
||||
}
|
||||
|
||||
export declare class Persistent<T> {
|
||||
private _ref;
|
||||
private _param;
|
||||
private _callback;
|
||||
private static readonly _registry;
|
||||
constructor(value: T);
|
||||
setWeak<P>(param: P, callback: (param: P) => void): void;
|
||||
clearWeak(): void;
|
||||
reset(): void;
|
||||
isEmpty(): boolean;
|
||||
deref(): T | undefined;
|
||||
}
|
||||
|
||||
export declare class Reference extends RefTracker implements IStoreValue {
|
||||
private static weakCallback;
|
||||
id: number;
|
||||
envObject: Env;
|
||||
private readonly canBeWeak;
|
||||
private _refcount;
|
||||
private readonly _ownership;
|
||||
persistent: Persistent<object>;
|
||||
static create(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, _unused1?: void_p, _unused2?: void_p, _unused3?: void_p): Reference;
|
||||
protected constructor(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership);
|
||||
ref(): number;
|
||||
unref(): number;
|
||||
get(envObject?: Env): napi_value;
|
||||
/** @virtual */
|
||||
resetFinalizer(): void;
|
||||
/** @virtual */
|
||||
data(): void_p;
|
||||
refcount(): number;
|
||||
ownership(): ReferenceOwnership;
|
||||
/** @virtual */
|
||||
protected callUserFinalizer(): void;
|
||||
/** @virtual */
|
||||
protected invokeFinalizerFromGC(): void;
|
||||
private _setWeak;
|
||||
finalize(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare enum ReferenceOwnership {
|
||||
kRuntime = 0,
|
||||
kUserland = 1
|
||||
}
|
||||
|
||||
export declare class ReferenceWithData extends Reference {
|
||||
private readonly _data;
|
||||
static create(envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): ReferenceWithData;
|
||||
private constructor();
|
||||
data(): void_p;
|
||||
}
|
||||
|
||||
export declare class ReferenceWithFinalizer extends Reference {
|
||||
private _finalizer;
|
||||
static create(envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): ReferenceWithFinalizer;
|
||||
private constructor();
|
||||
resetFinalizer(): void;
|
||||
data(): void_p;
|
||||
protected callUserFinalizer(): void;
|
||||
protected invokeFinalizerFromGC(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class RefTracker {
|
||||
/** @virtual */
|
||||
dispose(): void;
|
||||
/** @virtual */
|
||||
finalize(): void;
|
||||
private _next;
|
||||
private _prev;
|
||||
link(list: RefTracker): void;
|
||||
unlink(): void;
|
||||
static finalizeAll(list: RefTracker): void;
|
||||
}
|
||||
|
||||
export declare class ScopeStore {
|
||||
private readonly _rootScope;
|
||||
currentScope: HandleScope;
|
||||
private readonly _values;
|
||||
constructor();
|
||||
get(id: number): HandleScope | undefined;
|
||||
openScope(handleStore: HandleStore): HandleScope;
|
||||
closeScope(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class Store<V extends IStoreValue> {
|
||||
protected _values: Array<V | undefined>;
|
||||
private _freeList;
|
||||
private _size;
|
||||
constructor();
|
||||
add(value: V): void;
|
||||
get(id: Ptr): V | undefined;
|
||||
has(id: Ptr): boolean;
|
||||
remove(id: Ptr): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export declare class TrackedFinalizer extends RefTracker {
|
||||
private _finalizer;
|
||||
static create(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
|
||||
private constructor();
|
||||
data(): void_p;
|
||||
dispose(): void;
|
||||
finalize(): void;
|
||||
}
|
||||
|
||||
export declare class TryCatch {
|
||||
private _exception;
|
||||
private _caught;
|
||||
isEmpty(): boolean;
|
||||
hasCaught(): boolean;
|
||||
exception(): any;
|
||||
setError(err: any): void;
|
||||
reset(): void;
|
||||
extractException(): any;
|
||||
}
|
||||
|
||||
export declare const version: string;
|
||||
|
||||
export { }
|
||||
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1350
File diff suppressed because it is too large
Load Diff
+5
@@ -0,0 +1,5 @@
|
||||
if (typeof process !== 'undefined' && process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./dist/emnapi.cjs.min.js')
|
||||
} else {
|
||||
module.exports = require('./dist/emnapi.cjs.js')
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "@emnapi/runtime",
|
||||
"version": "1.10.0",
|
||||
"description": "emnapi runtime",
|
||||
"main": "index.js",
|
||||
"module": "./dist/emnapi.esm-bundler.js",
|
||||
"types": "./dist/emnapi.d.ts",
|
||||
"sideEffects": false,
|
||||
"exports": {
|
||||
".": {
|
||||
"types": {
|
||||
"module": "./dist/emnapi.d.ts",
|
||||
"import": "./dist/emnapi.d.mts",
|
||||
"default": "./dist/emnapi.d.ts"
|
||||
},
|
||||
"module": "./dist/emnapi.esm-bundler.js",
|
||||
"import": "./dist/emnapi.mjs",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./dist/emnapi.cjs.min": {
|
||||
"types": "./dist/emnapi.d.ts",
|
||||
"default": "./dist/emnapi.cjs.min.js"
|
||||
},
|
||||
"./dist/emnapi.min.mjs": {
|
||||
"types": "./dist/emnapi.d.mts",
|
||||
"default": "./dist/emnapi.min.mjs"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "node ./script/build.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/toyobayashi/emnapi.git"
|
||||
},
|
||||
"author": "toyobayashi",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/toyobayashi/emnapi/issues"
|
||||
},
|
||||
"homepage": "https://github.com/toyobayashi/emnapi#readme",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-present Toyobayashi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
# @emnapi/wasi-threads
|
||||
|
||||
This package makes [wasi-threads proposal](https://github.com/WebAssembly/wasi-threads) based WASI modules work in Node.js and browser.
|
||||
|
||||
## Quick Start
|
||||
|
||||
`index.html`
|
||||
|
||||
```html
|
||||
<script src="./node_modules/@tybys/wasm-util/dist/wasm-util.js"></script>
|
||||
<script src="./node_modules/@emnapi/wasi-threads/dist/wasi-threads.js"></script>
|
||||
<script src="./index.js"></script>
|
||||
```
|
||||
|
||||
If your application will block browser main thread (for example `pthread_join`), please run it in worker instead.
|
||||
|
||||
```html
|
||||
<script>
|
||||
// pthread_join (Atomics.wait) cannot be called in browser main thread
|
||||
new Worker('./index.js')
|
||||
</script>
|
||||
```
|
||||
|
||||
`index.js`
|
||||
|
||||
```js
|
||||
const ENVIRONMENT_IS_NODE =
|
||||
typeof process === 'object' && process !== null &&
|
||||
typeof process.versions === 'object' && process.versions !== null &&
|
||||
typeof process.versions.node === 'string';
|
||||
|
||||
(function (main) {
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
main(require)
|
||||
} else {
|
||||
if (typeof importScripts === 'function') {
|
||||
importScripts('./node_modules/@tybys/wasm-util/dist/wasm-util.js')
|
||||
importScripts('./node_modules/@emnapi/wasi-threads/dist/wasi-threads.js')
|
||||
}
|
||||
const nodeWasi = { WASI: globalThis.wasmUtil.WASI }
|
||||
const nodeWorkerThreads = {
|
||||
Worker: globalThis.Worker
|
||||
}
|
||||
const _require = function (request) {
|
||||
if (request === 'node:wasi' || request === 'wasi') return nodeWasi
|
||||
if (request === 'node:worker_threads' || request === 'worker_threads') return nodeWorkerThreads
|
||||
if (request === '@emnapi/wasi-threads') return globalThis.wasiThreads
|
||||
throw new Error('Can not find module: ' + request)
|
||||
}
|
||||
main(_require)
|
||||
}
|
||||
})(async function (require) {
|
||||
const { WASI } = require('wasi')
|
||||
const { Worker } = require('worker_threads')
|
||||
const { WASIThreads } = require('@emnapi/wasi-threads')
|
||||
|
||||
const wasi = new WASI({
|
||||
version: 'preview1'
|
||||
})
|
||||
const wasiThreads = new WASIThreads({
|
||||
wasi,
|
||||
|
||||
/**
|
||||
* avoid Atomics.wait() deadlock during thread creation in browser
|
||||
* see https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size
|
||||
*/
|
||||
reuseWorker: ENVIRONMENT_IS_NODE
|
||||
? false
|
||||
: {
|
||||
size: 4 /** greater than actual needs (2) */,
|
||||
strict: true
|
||||
},
|
||||
|
||||
/**
|
||||
* Synchronous thread creation
|
||||
* pthread_create will not return until thread worker actually starts
|
||||
*/
|
||||
waitThreadStart: typeof window === 'undefined' ? 1000 : false,
|
||||
|
||||
onCreateWorker: () => {
|
||||
return new Worker('./worker.js', {
|
||||
execArgv: ['--experimental-wasi-unstable-preview1']
|
||||
})
|
||||
}
|
||||
})
|
||||
const memory = new WebAssembly.Memory({
|
||||
initial: 16777216 / 65536,
|
||||
maximum: 2147483648 / 65536,
|
||||
shared: true
|
||||
})
|
||||
let input
|
||||
const file = 'path/to/your/wasi-module.wasm'
|
||||
try {
|
||||
input = require('fs').readFileSync(require('path').join(__dirname, file))
|
||||
} catch (err) {
|
||||
const response = await fetch(file)
|
||||
input = await response.arrayBuffer()
|
||||
}
|
||||
let { module, instance } = await WebAssembly.instantiate(input, {
|
||||
env: { memory },
|
||||
wasi_snapshot_preview1: wasi.wasiImport,
|
||||
...wasiThreads.getImportObject()
|
||||
})
|
||||
|
||||
wasiThreads.setup(instance, module, memory)
|
||||
await wasiThreads.preloadWorkers()
|
||||
|
||||
if (typeof instance.exports._start === 'function') {
|
||||
return wasi.start(instance)
|
||||
} else {
|
||||
wasi.initialize(instance)
|
||||
// instance.exports.exported_wasm_function()
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
`worker.js`
|
||||
|
||||
```js
|
||||
(function (main) {
|
||||
const ENVIRONMENT_IS_NODE =
|
||||
typeof process === 'object' && process !== null &&
|
||||
typeof process.versions === 'object' && process.versions !== null &&
|
||||
typeof process.versions.node === 'string'
|
||||
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
const _require = function (request) {
|
||||
return require(request)
|
||||
}
|
||||
|
||||
const _init = function () {
|
||||
const nodeWorkerThreads = require('worker_threads')
|
||||
const parentPort = nodeWorkerThreads.parentPort
|
||||
|
||||
parentPort.on('message', (data) => {
|
||||
globalThis.onmessage({ data })
|
||||
})
|
||||
|
||||
Object.assign(globalThis, {
|
||||
self: globalThis,
|
||||
require,
|
||||
Worker: nodeWorkerThreads.Worker,
|
||||
importScripts: function (f) {
|
||||
(0, eval)(require('fs').readFileSync(f, 'utf8') + '//# sourceURL=' + f)
|
||||
},
|
||||
postMessage: function (msg) {
|
||||
parentPort.postMessage(msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
main(_require, _init)
|
||||
} else {
|
||||
importScripts('./node_modules/@tybys/wasm-util/dist/wasm-util.js')
|
||||
importScripts('./node_modules/@emnapi/wasi-threads/dist/wasi-threads.js')
|
||||
|
||||
const nodeWasi = { WASI: globalThis.wasmUtil.WASI }
|
||||
const _require = function (request) {
|
||||
if (request === '@emnapi/wasi-threads') return globalThis.wasiThreads
|
||||
if (request === 'node:wasi' || request === 'wasi') return nodeWasi
|
||||
throw new Error('Can not find module: ' + request)
|
||||
}
|
||||
const _init = function () {}
|
||||
main(_require, _init)
|
||||
}
|
||||
})(function main (require, init) {
|
||||
init()
|
||||
|
||||
const { WASI } = require('wasi')
|
||||
const { ThreadMessageHandler, WASIThreads } = require('@emnapi/wasi-threads')
|
||||
|
||||
const handler = new ThreadMessageHandler({
|
||||
async onLoad ({ wasmModule, wasmMemory }) {
|
||||
const wasi = new WASI({
|
||||
version: 'preview1'
|
||||
})
|
||||
|
||||
const wasiThreads = new WASIThreads({
|
||||
wasi,
|
||||
childThread: true
|
||||
})
|
||||
|
||||
const originalInstance = await WebAssembly.instantiate(wasmModule, {
|
||||
env: {
|
||||
memory: wasmMemory,
|
||||
},
|
||||
wasi_snapshot_preview1: wasi.wasiImport,
|
||||
...wasiThreads.getImportObject()
|
||||
})
|
||||
|
||||
// must call `initialize` instead of `start` in child thread
|
||||
const instance = wasiThreads.initialize(originalInstance, wasmModule, wasmMemory)
|
||||
|
||||
return { module: wasmModule, instance }
|
||||
}
|
||||
})
|
||||
|
||||
globalThis.onmessage = function (e) {
|
||||
handler.handle(e)
|
||||
// handle other messages
|
||||
}
|
||||
})
|
||||
```
|
||||
+894
@@ -0,0 +1,894 @@
|
||||
const _WebAssembly = typeof WebAssembly !== 'undefined'
|
||||
? WebAssembly
|
||||
: typeof WXWebAssembly !== 'undefined'
|
||||
? WXWebAssembly
|
||||
: undefined;
|
||||
const ENVIRONMENT_IS_NODE = typeof process === 'object' && process !== null &&
|
||||
typeof process.versions === 'object' && process.versions !== null &&
|
||||
typeof process.versions.node === 'string';
|
||||
function getPostMessage(options) {
|
||||
return typeof (options === null || options === void 0 ? void 0 : options.postMessage) === 'function'
|
||||
? options.postMessage
|
||||
: typeof postMessage === 'function'
|
||||
? postMessage
|
||||
: undefined;
|
||||
}
|
||||
function serizeErrorToBuffer(sab, code, error) {
|
||||
const i32array = new Int32Array(sab);
|
||||
Atomics.store(i32array, 0, code);
|
||||
if (code > 1 && error) {
|
||||
const name = error.name;
|
||||
const message = error.message;
|
||||
const stack = error.stack;
|
||||
const nameBuffer = new TextEncoder().encode(name);
|
||||
const messageBuffer = new TextEncoder().encode(message);
|
||||
const stackBuffer = new TextEncoder().encode(stack);
|
||||
Atomics.store(i32array, 1, nameBuffer.length);
|
||||
Atomics.store(i32array, 2, messageBuffer.length);
|
||||
Atomics.store(i32array, 3, stackBuffer.length);
|
||||
const buffer = new Uint8Array(sab);
|
||||
buffer.set(nameBuffer, 16);
|
||||
buffer.set(messageBuffer, 16 + nameBuffer.length);
|
||||
buffer.set(stackBuffer, 16 + nameBuffer.length + messageBuffer.length);
|
||||
}
|
||||
}
|
||||
function deserizeErrorFromBuffer(sab) {
|
||||
var _a, _b;
|
||||
const i32array = new Int32Array(sab);
|
||||
const status = Atomics.load(i32array, 0);
|
||||
if (status <= 1) {
|
||||
return null;
|
||||
}
|
||||
const nameLength = Atomics.load(i32array, 1);
|
||||
const messageLength = Atomics.load(i32array, 2);
|
||||
const stackLength = Atomics.load(i32array, 3);
|
||||
const buffer = new Uint8Array(sab);
|
||||
const nameBuffer = buffer.slice(16, 16 + nameLength);
|
||||
const messageBuffer = buffer.slice(16 + nameLength, 16 + nameLength + messageLength);
|
||||
const stackBuffer = buffer.slice(16 + nameLength + messageLength, 16 + nameLength + messageLength + stackLength);
|
||||
const name = new TextDecoder().decode(nameBuffer);
|
||||
const message = new TextDecoder().decode(messageBuffer);
|
||||
const stack = new TextDecoder().decode(stackBuffer);
|
||||
const ErrorConstructor = (_a = globalThis[name]) !== null && _a !== void 0 ? _a : (name === 'RuntimeError' ? ((_b = _WebAssembly.RuntimeError) !== null && _b !== void 0 ? _b : Error) : Error);
|
||||
const error = new ErrorConstructor(message);
|
||||
Object.defineProperty(error, 'stack', {
|
||||
value: stack,
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
return error;
|
||||
}
|
||||
function isSharedArrayBuffer(value) {
|
||||
return ((typeof SharedArrayBuffer === 'function' && value instanceof SharedArrayBuffer) ||
|
||||
(Object.prototype.toString.call(value) === '[object SharedArrayBuffer]'));
|
||||
}
|
||||
function isTrapError(e) {
|
||||
try {
|
||||
return e instanceof _WebAssembly.RuntimeError;
|
||||
}
|
||||
catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function createMessage(type, payload) {
|
||||
return {
|
||||
__emnapi__: {
|
||||
type,
|
||||
payload
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const WASI_THREADS_MAX_TID = 0x1FFFFFFF;
|
||||
function checkSharedWasmMemory(wasmMemory) {
|
||||
if (wasmMemory) {
|
||||
if (!isSharedArrayBuffer(wasmMemory.buffer)) {
|
||||
throw new Error('Multithread features require shared wasm memory. ' +
|
||||
'Try to compile with `-matomics -mbulk-memory` and use `--import-memory --shared-memory` during linking, ' +
|
||||
'then create WebAssembly.Memory with `shared: true` option');
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (typeof SharedArrayBuffer === 'undefined') {
|
||||
throw new Error('Current environment does not support SharedArrayBuffer, threads are not available!');
|
||||
}
|
||||
}
|
||||
}
|
||||
function getReuseWorker(value) {
|
||||
var _a;
|
||||
if (typeof value === 'boolean') {
|
||||
return value ? { size: 0, strict: false } : false;
|
||||
}
|
||||
if (typeof value === 'number') {
|
||||
if (!(value >= 0)) {
|
||||
throw new RangeError('reuseWorker: size must be a non-negative integer');
|
||||
}
|
||||
return { size: value, strict: false };
|
||||
}
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
const size = (_a = Number(value.size)) !== null && _a !== void 0 ? _a : 0;
|
||||
const strict = Boolean(value.strict);
|
||||
if (!(size > 0) && strict) {
|
||||
throw new RangeError('reuseWorker: size must be set to positive integer if strict is set to true');
|
||||
}
|
||||
return { size, strict };
|
||||
}
|
||||
let nextWorkerID = 0;
|
||||
class ThreadManager {
|
||||
get nextWorkerID() { return nextWorkerID; }
|
||||
constructor(options) {
|
||||
var _a;
|
||||
this.unusedWorkers = [];
|
||||
this.runningWorkers = [];
|
||||
this.pthreads = Object.create(null);
|
||||
this.wasmModule = null;
|
||||
this.wasmMemory = null;
|
||||
this.messageEvents = new WeakMap();
|
||||
if (!options) {
|
||||
throw new TypeError('ThreadManager(): options is not provided');
|
||||
}
|
||||
if ('childThread' in options) {
|
||||
this._childThread = Boolean(options.childThread);
|
||||
}
|
||||
else {
|
||||
this._childThread = false;
|
||||
}
|
||||
if (this._childThread) {
|
||||
this._onCreateWorker = undefined;
|
||||
this._reuseWorker = false;
|
||||
this._beforeLoad = undefined;
|
||||
}
|
||||
else {
|
||||
this._onCreateWorker = options.onCreateWorker;
|
||||
this._reuseWorker = getReuseWorker(options.reuseWorker);
|
||||
this._beforeLoad = options.beforeLoad;
|
||||
}
|
||||
this.printErr = (_a = options.printErr) !== null && _a !== void 0 ? _a : console.error.bind(console);
|
||||
this.threadSpawn = options.threadSpawn;
|
||||
}
|
||||
init() {
|
||||
if (!this._childThread) {
|
||||
this.initMainThread();
|
||||
}
|
||||
}
|
||||
initMainThread() {
|
||||
this.preparePool();
|
||||
}
|
||||
preparePool() {
|
||||
if (this._reuseWorker) {
|
||||
if (this._reuseWorker.size) {
|
||||
let pthreadPoolSize = this._reuseWorker.size;
|
||||
while (pthreadPoolSize--) {
|
||||
const worker = this.allocateUnusedWorker();
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
worker.once('message', () => { });
|
||||
worker.unref();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
shouldPreloadWorkers() {
|
||||
return !this._childThread && this._reuseWorker && this._reuseWorker.size > 0;
|
||||
}
|
||||
loadWasmModuleToAllWorkers() {
|
||||
const promises = Array(this.unusedWorkers.length);
|
||||
for (let i = 0; i < this.unusedWorkers.length; ++i) {
|
||||
const worker = this.unusedWorkers[i];
|
||||
if (ENVIRONMENT_IS_NODE)
|
||||
worker.ref();
|
||||
promises[i] = this.loadWasmModuleToWorker(worker).then((w) => {
|
||||
if (ENVIRONMENT_IS_NODE)
|
||||
worker.unref();
|
||||
return w;
|
||||
}, (e) => {
|
||||
if (ENVIRONMENT_IS_NODE)
|
||||
worker.unref();
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
return Promise.all(promises).catch((err) => {
|
||||
this.terminateAllThreads();
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
preloadWorkers() {
|
||||
if (this.shouldPreloadWorkers()) {
|
||||
return this.loadWasmModuleToAllWorkers();
|
||||
}
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
setup(wasmModule, wasmMemory) {
|
||||
this.wasmModule = wasmModule;
|
||||
this.wasmMemory = wasmMemory;
|
||||
}
|
||||
markId(worker) {
|
||||
if (worker.__emnapi_tid)
|
||||
return worker.__emnapi_tid;
|
||||
const tid = nextWorkerID + 43;
|
||||
nextWorkerID = (nextWorkerID + 1) % (WASI_THREADS_MAX_TID - 42);
|
||||
this.pthreads[tid] = worker;
|
||||
worker.__emnapi_tid = tid;
|
||||
return tid;
|
||||
}
|
||||
returnWorkerToPool(worker) {
|
||||
var tid = worker.__emnapi_tid;
|
||||
if (tid !== undefined) {
|
||||
delete this.pthreads[tid];
|
||||
}
|
||||
this.unusedWorkers.push(worker);
|
||||
this.runningWorkers.splice(this.runningWorkers.indexOf(worker), 1);
|
||||
delete worker.__emnapi_tid;
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
worker.unref();
|
||||
}
|
||||
}
|
||||
loadWasmModuleToWorker(worker, sab) {
|
||||
if (worker.whenLoaded)
|
||||
return worker.whenLoaded;
|
||||
const err = this.printErr;
|
||||
const beforeLoad = this._beforeLoad;
|
||||
const _this = this;
|
||||
worker.whenLoaded = new Promise((resolve, reject) => {
|
||||
const handleError = function (e) {
|
||||
let message = 'worker sent an error!';
|
||||
if (worker.__emnapi_tid !== undefined) {
|
||||
message = 'worker (tid = ' + worker.__emnapi_tid + ') sent an error!';
|
||||
}
|
||||
if ('message' in e) {
|
||||
err(message + ' ' + e.message);
|
||||
if (e.message.indexOf('RuntimeError') !== -1 || e.message.indexOf('unreachable') !== -1) {
|
||||
try {
|
||||
_this.terminateAllThreads();
|
||||
}
|
||||
catch (_) { }
|
||||
}
|
||||
}
|
||||
else {
|
||||
err(message);
|
||||
}
|
||||
reject(e);
|
||||
throw e;
|
||||
};
|
||||
const handleMessage = (data) => {
|
||||
if (data.__emnapi__) {
|
||||
const type = data.__emnapi__.type;
|
||||
const payload = data.__emnapi__.payload;
|
||||
if (type === 'loaded') {
|
||||
worker.loaded = true;
|
||||
if (ENVIRONMENT_IS_NODE && !worker.__emnapi_tid) {
|
||||
worker.unref();
|
||||
}
|
||||
resolve(worker);
|
||||
}
|
||||
else if (type === 'cleanup-thread') {
|
||||
if (payload.tid in this.pthreads) {
|
||||
this.cleanThread(worker, payload.tid);
|
||||
}
|
||||
}
|
||||
else if (type === 'spawn-thread') {
|
||||
this.threadSpawn(payload.startArg, payload.errorOrTid);
|
||||
}
|
||||
else if (type === 'terminate-all-threads') {
|
||||
this.terminateAllThreads();
|
||||
}
|
||||
}
|
||||
};
|
||||
worker.onmessage = (e) => {
|
||||
handleMessage(e.data);
|
||||
this.fireMessageEvent(worker, e);
|
||||
};
|
||||
worker.onerror = handleError;
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
worker.on('message', function (data) {
|
||||
var _a, _b;
|
||||
(_b = (_a = worker).onmessage) === null || _b === void 0 ? void 0 : _b.call(_a, {
|
||||
data
|
||||
});
|
||||
});
|
||||
worker.on('error', function (e) {
|
||||
var _a, _b;
|
||||
(_b = (_a = worker).onerror) === null || _b === void 0 ? void 0 : _b.call(_a, e);
|
||||
});
|
||||
worker.on('detachedExit', function () { });
|
||||
}
|
||||
if (typeof beforeLoad === 'function') {
|
||||
beforeLoad(worker);
|
||||
}
|
||||
try {
|
||||
worker.postMessage(createMessage('load', {
|
||||
wasmModule: this.wasmModule,
|
||||
wasmMemory: this.wasmMemory,
|
||||
sab
|
||||
}));
|
||||
}
|
||||
catch (err) {
|
||||
checkSharedWasmMemory(this.wasmMemory);
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
return worker.whenLoaded;
|
||||
}
|
||||
allocateUnusedWorker() {
|
||||
const _onCreateWorker = this._onCreateWorker;
|
||||
if (typeof _onCreateWorker !== 'function') {
|
||||
throw new TypeError('`options.onCreateWorker` is not provided');
|
||||
}
|
||||
const worker = _onCreateWorker({ type: 'thread', name: 'emnapi-pthread' });
|
||||
this.unusedWorkers.push(worker);
|
||||
return worker;
|
||||
}
|
||||
getNewWorker(sab) {
|
||||
if (this._reuseWorker) {
|
||||
if (this.unusedWorkers.length === 0) {
|
||||
if (this._reuseWorker.strict) {
|
||||
if (!ENVIRONMENT_IS_NODE) {
|
||||
const err = this.printErr;
|
||||
err('Tried to spawn a new thread, but the thread pool is exhausted.\n' +
|
||||
'This might result in a deadlock unless some threads eventually exit or the code explicitly breaks out to the event loop.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
const worker = this.allocateUnusedWorker();
|
||||
this.loadWasmModuleToWorker(worker, sab);
|
||||
}
|
||||
return this.unusedWorkers.pop();
|
||||
}
|
||||
const worker = this.allocateUnusedWorker();
|
||||
this.loadWasmModuleToWorker(worker, sab);
|
||||
return this.unusedWorkers.pop();
|
||||
}
|
||||
cleanThread(worker, tid, force) {
|
||||
if (!force && this._reuseWorker) {
|
||||
this.returnWorkerToPool(worker);
|
||||
}
|
||||
else {
|
||||
delete this.pthreads[tid];
|
||||
const index = this.runningWorkers.indexOf(worker);
|
||||
if (index !== -1) {
|
||||
this.runningWorkers.splice(index, 1);
|
||||
}
|
||||
this.terminateWorker(worker);
|
||||
delete worker.__emnapi_tid;
|
||||
}
|
||||
}
|
||||
terminateWorker(worker) {
|
||||
var _a;
|
||||
const tid = worker.__emnapi_tid;
|
||||
worker.terminate();
|
||||
(_a = this.messageEvents.get(worker)) === null || _a === void 0 ? void 0 : _a.clear();
|
||||
this.messageEvents.delete(worker);
|
||||
worker.onmessage = (e) => {
|
||||
if (e.data.__emnapi__) {
|
||||
const err = this.printErr;
|
||||
err('received "' + e.data.__emnapi__.type + '" command from terminated worker: ' + tid);
|
||||
}
|
||||
};
|
||||
}
|
||||
terminateAllThreads() {
|
||||
for (let i = 0; i < this.runningWorkers.length; ++i) {
|
||||
this.terminateWorker(this.runningWorkers[i]);
|
||||
}
|
||||
for (let i = 0; i < this.unusedWorkers.length; ++i) {
|
||||
this.terminateWorker(this.unusedWorkers[i]);
|
||||
}
|
||||
this.unusedWorkers = [];
|
||||
this.runningWorkers = [];
|
||||
this.pthreads = Object.create(null);
|
||||
this.preparePool();
|
||||
}
|
||||
addMessageEventListener(worker, onMessage) {
|
||||
let listeners = this.messageEvents.get(worker);
|
||||
if (!listeners) {
|
||||
listeners = new Set();
|
||||
this.messageEvents.set(worker, listeners);
|
||||
}
|
||||
listeners.add(onMessage);
|
||||
return () => {
|
||||
listeners === null || listeners === void 0 ? void 0 : listeners.delete(onMessage);
|
||||
};
|
||||
}
|
||||
fireMessageEvent(worker, e) {
|
||||
const listeners = this.messageEvents.get(worker);
|
||||
if (!listeners)
|
||||
return;
|
||||
const err = this.printErr;
|
||||
listeners.forEach((listener) => {
|
||||
try {
|
||||
listener(e);
|
||||
}
|
||||
catch (e) {
|
||||
err(e.stack);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const kIsProxy = Symbol('kIsProxy');
|
||||
function createInstanceProxy(instance, memory) {
|
||||
if (instance[kIsProxy])
|
||||
return instance;
|
||||
const originalExports = instance.exports;
|
||||
const createHandler = function (target) {
|
||||
const handlers = [
|
||||
'apply',
|
||||
'construct',
|
||||
'defineProperty',
|
||||
'deleteProperty',
|
||||
'get',
|
||||
'getOwnPropertyDescriptor',
|
||||
'getPrototypeOf',
|
||||
'has',
|
||||
'isExtensible',
|
||||
'ownKeys',
|
||||
'preventExtensions',
|
||||
'set',
|
||||
'setPrototypeOf'
|
||||
];
|
||||
const handler = {};
|
||||
for (let i = 0; i < handlers.length; i++) {
|
||||
const name = handlers[i];
|
||||
handler[name] = function () {
|
||||
const args = Array.prototype.slice.call(arguments, 1);
|
||||
args.unshift(target);
|
||||
return Reflect[name].apply(Reflect, args);
|
||||
};
|
||||
}
|
||||
return handler;
|
||||
};
|
||||
const handler = createHandler(originalExports);
|
||||
const _initialize = () => { };
|
||||
const _start = () => 0;
|
||||
handler.get = function (_target, p, receiver) {
|
||||
var _a;
|
||||
if (p === 'memory') {
|
||||
return (_a = (typeof memory === 'function' ? memory() : memory)) !== null && _a !== void 0 ? _a : Reflect.get(originalExports, p, receiver);
|
||||
}
|
||||
if (p === '_initialize') {
|
||||
return p in originalExports ? _initialize : undefined;
|
||||
}
|
||||
if (p === '_start') {
|
||||
return p in originalExports ? _start : undefined;
|
||||
}
|
||||
return Reflect.get(originalExports, p, receiver);
|
||||
};
|
||||
handler.has = function (_target, p) {
|
||||
if (p === 'memory')
|
||||
return true;
|
||||
return Reflect.has(originalExports, p);
|
||||
};
|
||||
const exportsProxy = new Proxy(Object.create(null), handler);
|
||||
return new Proxy(instance, {
|
||||
get(target, p, receiver) {
|
||||
if (p === 'exports') {
|
||||
return exportsProxy;
|
||||
}
|
||||
if (p === kIsProxy) {
|
||||
return true;
|
||||
}
|
||||
return Reflect.get(target, p, receiver);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const patchedWasiInstances = new WeakMap();
|
||||
class WASIThreads {
|
||||
constructor(options) {
|
||||
if (!options) {
|
||||
throw new TypeError('WASIThreads(): options is not provided');
|
||||
}
|
||||
if (!options.wasi) {
|
||||
throw new TypeError('WASIThreads(): options.wasi is not provided');
|
||||
}
|
||||
patchedWasiInstances.set(this, new WeakSet());
|
||||
const wasi = options.wasi;
|
||||
patchWasiInstance(this, wasi);
|
||||
this.wasi = wasi;
|
||||
if ('childThread' in options) {
|
||||
this.childThread = Boolean(options.childThread);
|
||||
}
|
||||
else {
|
||||
this.childThread = false;
|
||||
}
|
||||
this.PThread = undefined;
|
||||
if ('threadManager' in options) {
|
||||
if (typeof options.threadManager === 'function') {
|
||||
this.PThread = options.threadManager();
|
||||
}
|
||||
else {
|
||||
this.PThread = options.threadManager;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!this.childThread) {
|
||||
this.PThread = new ThreadManager(options);
|
||||
this.PThread.init();
|
||||
}
|
||||
}
|
||||
let waitThreadStart = false;
|
||||
if ('waitThreadStart' in options) {
|
||||
waitThreadStart = typeof options.waitThreadStart === 'number' ? options.waitThreadStart : Boolean(options.waitThreadStart);
|
||||
}
|
||||
const postMessage = getPostMessage(options);
|
||||
if (this.childThread && typeof postMessage !== 'function') {
|
||||
throw new TypeError('options.postMessage is not a function');
|
||||
}
|
||||
this.postMessage = postMessage;
|
||||
const wasm64 = Boolean(options.wasm64);
|
||||
const threadSpawn = (startArg, errorOrTid) => {
|
||||
var _a;
|
||||
const EAGAIN = 6;
|
||||
const isNewABI = errorOrTid !== undefined;
|
||||
try {
|
||||
checkSharedWasmMemory(this.wasmMemory);
|
||||
}
|
||||
catch (err) {
|
||||
(_a = this.PThread) === null || _a === void 0 ? void 0 : _a.printErr(err.stack);
|
||||
if (isNewABI) {
|
||||
const struct = new Int32Array(this.wasmMemory.buffer, errorOrTid, 2);
|
||||
Atomics.store(struct, 0, 1);
|
||||
Atomics.store(struct, 1, EAGAIN);
|
||||
Atomics.notify(struct, 1);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
if (!isNewABI) {
|
||||
const malloc = this.wasmInstance.exports.malloc;
|
||||
errorOrTid = wasm64 ? Number(malloc(BigInt(8))) : (malloc(8) >>> 0);
|
||||
if (!errorOrTid) {
|
||||
return -48;
|
||||
}
|
||||
}
|
||||
const _free = this.wasmInstance.exports.free;
|
||||
const free = wasm64 ? (ptr) => { _free(BigInt(ptr)); } : _free;
|
||||
const struct = new Int32Array(this.wasmMemory.buffer, errorOrTid, 2);
|
||||
Atomics.store(struct, 0, 0);
|
||||
Atomics.store(struct, 1, 0);
|
||||
if (this.childThread) {
|
||||
postMessage(createMessage('spawn-thread', {
|
||||
startArg,
|
||||
errorOrTid: errorOrTid
|
||||
}));
|
||||
Atomics.wait(struct, 1, 0);
|
||||
const isError = Atomics.load(struct, 0);
|
||||
const result = Atomics.load(struct, 1);
|
||||
if (isNewABI) {
|
||||
return isError;
|
||||
}
|
||||
free(errorOrTid);
|
||||
return isError ? -result : result;
|
||||
}
|
||||
const shouldWait = waitThreadStart || (waitThreadStart === 0);
|
||||
let sab;
|
||||
if (shouldWait) {
|
||||
sab = new Int32Array(new SharedArrayBuffer(16 + 8192));
|
||||
Atomics.store(sab, 0, 0);
|
||||
}
|
||||
let worker;
|
||||
let tid;
|
||||
const PThread = this.PThread;
|
||||
try {
|
||||
worker = PThread.getNewWorker(sab);
|
||||
if (!worker) {
|
||||
throw new Error('failed to get new worker');
|
||||
}
|
||||
tid = PThread.markId(worker);
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
worker.unref();
|
||||
}
|
||||
worker.postMessage(createMessage('start', {
|
||||
tid,
|
||||
arg: startArg,
|
||||
sab
|
||||
}));
|
||||
if (shouldWait) {
|
||||
if (typeof waitThreadStart === 'number') {
|
||||
const waitResult = Atomics.wait(sab, 0, 0, waitThreadStart);
|
||||
if (waitResult === 'timed-out') {
|
||||
try {
|
||||
PThread.cleanThread(worker, tid, true);
|
||||
}
|
||||
catch (_) { }
|
||||
throw new Error('Spawning thread timed out. Please check if the worker is created successfully and if message is handled properly in the worker.');
|
||||
}
|
||||
}
|
||||
else {
|
||||
Atomics.wait(sab, 0, 0);
|
||||
}
|
||||
const r = Atomics.load(sab, 0);
|
||||
if (r > 1) {
|
||||
try {
|
||||
PThread.cleanThread(worker, tid, true);
|
||||
}
|
||||
catch (_) { }
|
||||
throw deserizeErrorFromBuffer(sab.buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
Atomics.store(struct, 0, 1);
|
||||
Atomics.store(struct, 1, EAGAIN);
|
||||
Atomics.notify(struct, 1);
|
||||
PThread === null || PThread === void 0 ? void 0 : PThread.printErr(e.stack);
|
||||
if (isNewABI) {
|
||||
return 1;
|
||||
}
|
||||
free(errorOrTid);
|
||||
return -EAGAIN;
|
||||
}
|
||||
Atomics.store(struct, 0, 0);
|
||||
Atomics.store(struct, 1, tid);
|
||||
Atomics.notify(struct, 1);
|
||||
PThread.runningWorkers.push(worker);
|
||||
if (!shouldWait) {
|
||||
worker.whenLoaded.catch((err) => {
|
||||
delete worker.whenLoaded;
|
||||
PThread.cleanThread(worker, tid, true);
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
if (isNewABI) {
|
||||
return 0;
|
||||
}
|
||||
free(errorOrTid);
|
||||
return tid;
|
||||
};
|
||||
this.threadSpawn = threadSpawn;
|
||||
if (this.PThread) {
|
||||
this.PThread.threadSpawn = threadSpawn;
|
||||
}
|
||||
}
|
||||
getImportObject() {
|
||||
return {
|
||||
wasi: {
|
||||
'thread-spawn': this.threadSpawn
|
||||
}
|
||||
};
|
||||
}
|
||||
setup(wasmInstance, wasmModule, wasmMemory) {
|
||||
wasmMemory !== null && wasmMemory !== void 0 ? wasmMemory : (wasmMemory = wasmInstance.exports.memory);
|
||||
this.wasmInstance = wasmInstance;
|
||||
this.wasmMemory = wasmMemory;
|
||||
if (this.PThread) {
|
||||
this.PThread.setup(wasmModule, wasmMemory);
|
||||
}
|
||||
}
|
||||
preloadWorkers() {
|
||||
if (this.PThread) {
|
||||
return this.PThread.preloadWorkers();
|
||||
}
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
initialize(instance, module, memory) {
|
||||
const exports$1 = instance.exports;
|
||||
memory !== null && memory !== void 0 ? memory : (memory = exports$1.memory);
|
||||
if (this.childThread) {
|
||||
instance = createInstanceProxy(instance, memory);
|
||||
}
|
||||
this.setup(instance, module, memory);
|
||||
const wasi = this.wasi;
|
||||
if (('_start' in exports$1) && (typeof exports$1._start === 'function')) {
|
||||
if (this.childThread) {
|
||||
wasi.start(instance);
|
||||
try {
|
||||
const kStarted = getWasiSymbol(wasi, 'kStarted');
|
||||
wasi[kStarted] = false;
|
||||
}
|
||||
catch (_) { }
|
||||
}
|
||||
else {
|
||||
setupInstance(wasi, instance);
|
||||
}
|
||||
}
|
||||
else {
|
||||
wasi.initialize(instance);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
start(instance, module, memory) {
|
||||
const exports$1 = instance.exports;
|
||||
memory !== null && memory !== void 0 ? memory : (memory = exports$1.memory);
|
||||
if (this.childThread) {
|
||||
instance = createInstanceProxy(instance, memory);
|
||||
}
|
||||
this.setup(instance, module, memory);
|
||||
const exitCode = this.wasi.start(instance);
|
||||
return { exitCode, instance };
|
||||
}
|
||||
terminateAllThreads() {
|
||||
var _a;
|
||||
if (!this.childThread) {
|
||||
(_a = this.PThread) === null || _a === void 0 ? void 0 : _a.terminateAllThreads();
|
||||
}
|
||||
else {
|
||||
this.postMessage(createMessage('terminate-all-threads', {}));
|
||||
}
|
||||
}
|
||||
}
|
||||
function patchWasiInstance(wasiThreads, wasi) {
|
||||
const patched = patchedWasiInstances.get(wasiThreads);
|
||||
if (patched.has(wasi)) {
|
||||
return;
|
||||
}
|
||||
const _this = wasiThreads;
|
||||
const wasiImport = wasi.wasiImport;
|
||||
if (wasiImport) {
|
||||
const proc_exit = wasiImport.proc_exit;
|
||||
wasiImport.proc_exit = function (code) {
|
||||
_this.terminateAllThreads();
|
||||
return proc_exit.call(this, code);
|
||||
};
|
||||
}
|
||||
if (!_this.childThread) {
|
||||
const start = wasi.start;
|
||||
if (typeof start === 'function') {
|
||||
wasi.start = function (instance) {
|
||||
try {
|
||||
return start.call(this, instance);
|
||||
}
|
||||
catch (err) {
|
||||
if (isTrapError(err)) {
|
||||
_this.terminateAllThreads();
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
patched.add(wasi);
|
||||
}
|
||||
function getWasiSymbol(wasi, description) {
|
||||
const symbols = Object.getOwnPropertySymbols(wasi);
|
||||
const selectDescription = (description) => (s) => {
|
||||
if (s.description) {
|
||||
return s.description === description;
|
||||
}
|
||||
return s.toString() === `Symbol(${description})`;
|
||||
};
|
||||
if (Array.isArray(description)) {
|
||||
return description.map(d => symbols.filter(selectDescription(d))[0]);
|
||||
}
|
||||
return symbols.filter(selectDescription(description))[0];
|
||||
}
|
||||
function setupInstance(wasi, instance) {
|
||||
const [kInstance, kSetMemory] = getWasiSymbol(wasi, ['kInstance', 'kSetMemory']);
|
||||
wasi[kInstance] = instance;
|
||||
wasi[kSetMemory](instance.exports.memory);
|
||||
}
|
||||
|
||||
class ThreadMessageHandler {
|
||||
constructor(options) {
|
||||
const postMsg = getPostMessage(options);
|
||||
if (typeof postMsg !== 'function') {
|
||||
throw new TypeError('options.postMessage is not a function');
|
||||
}
|
||||
this.postMessage = postMsg;
|
||||
this.onLoad = options === null || options === void 0 ? void 0 : options.onLoad;
|
||||
this.onError = typeof (options === null || options === void 0 ? void 0 : options.onError) === 'function' ? options.onError : (_type, err) => { throw err; };
|
||||
this.instance = undefined;
|
||||
this.messagesBeforeLoad = [];
|
||||
}
|
||||
instantiate(data) {
|
||||
if (typeof this.onLoad === 'function') {
|
||||
return this.onLoad(data);
|
||||
}
|
||||
throw new Error('ThreadMessageHandler.prototype.instantiate is not implemented');
|
||||
}
|
||||
handle(e) {
|
||||
var _a;
|
||||
if ((_a = e === null || e === void 0 ? void 0 : e.data) === null || _a === void 0 ? void 0 : _a.__emnapi__) {
|
||||
const type = e.data.__emnapi__.type;
|
||||
const payload = e.data.__emnapi__.payload;
|
||||
try {
|
||||
if (type === 'load') {
|
||||
this._load(payload);
|
||||
}
|
||||
else if (type === 'start') {
|
||||
this.handleAfterLoad(e, () => {
|
||||
this._start(payload);
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
this.onError(err, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
_load(payload) {
|
||||
if (this.instance !== undefined)
|
||||
return;
|
||||
let source;
|
||||
try {
|
||||
source = this.instantiate(payload);
|
||||
}
|
||||
catch (err) {
|
||||
this._loaded(err, null, payload);
|
||||
return;
|
||||
}
|
||||
const then = source && 'then' in source ? source.then : undefined;
|
||||
if (typeof then === 'function') {
|
||||
then.call(source, (source) => { this._loaded(null, source, payload); }, (err) => { this._loaded(err, null, payload); });
|
||||
}
|
||||
else {
|
||||
this._loaded(null, source, payload);
|
||||
}
|
||||
}
|
||||
_start(payload) {
|
||||
const wasi_thread_start = this.instance.exports.wasi_thread_start;
|
||||
if (typeof wasi_thread_start !== 'function') {
|
||||
const err = new TypeError('wasi_thread_start is not exported');
|
||||
notifyPthreadCreateResult(payload.sab, 2, err);
|
||||
throw err;
|
||||
}
|
||||
const postMessage = this.postMessage;
|
||||
const tid = payload.tid;
|
||||
const startArg = payload.arg;
|
||||
notifyPthreadCreateResult(payload.sab, 1);
|
||||
try {
|
||||
wasi_thread_start(tid, startArg);
|
||||
}
|
||||
catch (err) {
|
||||
if (err !== 'unwind') {
|
||||
throw err;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
postMessage(createMessage('cleanup-thread', { tid }));
|
||||
}
|
||||
_loaded(err, source, payload) {
|
||||
if (err) {
|
||||
notifyPthreadCreateResult(payload.sab, 2, err);
|
||||
throw err;
|
||||
}
|
||||
if (source == null) {
|
||||
const err = new TypeError('onLoad should return an object');
|
||||
notifyPthreadCreateResult(payload.sab, 2, err);
|
||||
throw err;
|
||||
}
|
||||
const instance = source.instance;
|
||||
if (!instance) {
|
||||
const err = new TypeError('onLoad should return an object which includes "instance"');
|
||||
notifyPthreadCreateResult(payload.sab, 2, err);
|
||||
throw err;
|
||||
}
|
||||
this.instance = instance;
|
||||
const postMessage = this.postMessage;
|
||||
postMessage(createMessage('loaded', {}));
|
||||
const messages = this.messagesBeforeLoad;
|
||||
this.messagesBeforeLoad = [];
|
||||
for (let i = 0; i < messages.length; i++) {
|
||||
const data = messages[i];
|
||||
this.handle({ data });
|
||||
}
|
||||
}
|
||||
handleAfterLoad(e, f) {
|
||||
if (this.instance !== undefined) {
|
||||
f.call(this, e);
|
||||
}
|
||||
else {
|
||||
this.messagesBeforeLoad.push(e.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
function notifyPthreadCreateResult(sab, result, error) {
|
||||
if (sab) {
|
||||
serizeErrorToBuffer(sab.buffer, result, error);
|
||||
Atomics.notify(sab, 0);
|
||||
}
|
||||
}
|
||||
|
||||
exports.ThreadManager = ThreadManager;
|
||||
exports.ThreadMessageHandler = ThreadMessageHandler;
|
||||
exports.WASIThreads = WASIThreads;
|
||||
exports.createInstanceProxy = createInstanceProxy;
|
||||
exports.isSharedArrayBuffer = isSharedArrayBuffer;
|
||||
exports.isTrapError = isTrapError;
|
||||
+272
@@ -0,0 +1,272 @@
|
||||
/// <reference types="node" />
|
||||
|
||||
import type { Worker as Worker_2 } from 'worker_threads';
|
||||
|
||||
/** @public */
|
||||
export declare interface BaseOptions {
|
||||
wasi: WASIInstance;
|
||||
version?: 'preview1';
|
||||
wasm64?: boolean;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ChildThreadOptions extends BaseOptions {
|
||||
childThread: true;
|
||||
postMessage?: (data: any) => void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CleanupThreadPayload {
|
||||
tid: number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CommandInfo<T extends CommandType> {
|
||||
type: T;
|
||||
payload: CommandPayloadMap[T];
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CommandPayloadMap {
|
||||
load: LoadPayload;
|
||||
loaded: LoadedPayload;
|
||||
start: StartPayload;
|
||||
'cleanup-thread': CleanupThreadPayload;
|
||||
'terminate-all-threads': TerminateAllThreadsPayload;
|
||||
'spawn-thread': SpawnThreadPayload;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type CommandType = keyof CommandPayloadMap;
|
||||
|
||||
/** @public */
|
||||
export declare function createInstanceProxy(instance: WebAssembly.Instance, memory?: WebAssembly.Memory | (() => WebAssembly.Memory)): WebAssembly.Instance;
|
||||
|
||||
/** @public */
|
||||
export declare function isSharedArrayBuffer(value: any): value is SharedArrayBuffer;
|
||||
|
||||
/** @public */
|
||||
export declare function isTrapError(e: Error): e is WebAssembly.RuntimeError;
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadedPayload {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadPayload {
|
||||
wasmModule: WebAssembly.Module;
|
||||
wasmMemory: WebAssembly.Memory;
|
||||
sab?: Int32Array;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadBaseOptions extends BaseOptions {
|
||||
waitThreadStart?: boolean | number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type MainThreadOptions = MainThreadOptionsWithThreadManager | MainThreadOptionsCreateThreadManager;
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadOptionsCreateThreadManager extends MainThreadBaseOptions, ThreadManagerOptionsMain {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadOptionsWithThreadManager extends MainThreadBaseOptions {
|
||||
threadManager?: ThreadManager | (() => ThreadManager);
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MessageEventData<T extends CommandType> {
|
||||
__emnapi__: CommandInfo<T>;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ReuseWorkerOptions {
|
||||
/**
|
||||
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size | PTHREAD_POOL_SIZE}
|
||||
*/
|
||||
size: number;
|
||||
/**
|
||||
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size-strict | PTHREAD_POOL_SIZE_STRICT}
|
||||
*/
|
||||
strict?: boolean;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface SpawnThreadPayload {
|
||||
startArg: number;
|
||||
errorOrTid: number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface StartPayload {
|
||||
tid: number;
|
||||
arg: number;
|
||||
sab?: Int32Array;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface StartResult {
|
||||
exitCode: number;
|
||||
instance: WebAssembly.Instance;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface TerminateAllThreadsPayload {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class ThreadManager {
|
||||
unusedWorkers: WorkerLike[];
|
||||
runningWorkers: WorkerLike[];
|
||||
pthreads: Record<number, WorkerLike>;
|
||||
get nextWorkerID(): number;
|
||||
wasmModule: WebAssembly.Module | null;
|
||||
wasmMemory: WebAssembly.Memory | null;
|
||||
private readonly messageEvents;
|
||||
private readonly _childThread;
|
||||
private readonly _onCreateWorker;
|
||||
private readonly _reuseWorker;
|
||||
private readonly _beforeLoad?;
|
||||
/* Excluded from this release type: printErr */
|
||||
threadSpawn?: ((startArg: number, errorOrTid?: number) => number);
|
||||
constructor(options: ThreadManagerOptions);
|
||||
init(): void;
|
||||
initMainThread(): void;
|
||||
private preparePool;
|
||||
shouldPreloadWorkers(): boolean;
|
||||
loadWasmModuleToAllWorkers(): Promise<WorkerLike[]>;
|
||||
preloadWorkers(): Promise<WorkerLike[]>;
|
||||
setup(wasmModule: WebAssembly.Module, wasmMemory: WebAssembly.Memory): void;
|
||||
markId(worker: WorkerLike): number;
|
||||
returnWorkerToPool(worker: WorkerLike): void;
|
||||
loadWasmModuleToWorker(worker: WorkerLike, sab?: Int32Array): Promise<WorkerLike>;
|
||||
allocateUnusedWorker(): WorkerLike;
|
||||
getNewWorker(sab?: Int32Array): WorkerLike | undefined;
|
||||
cleanThread(worker: WorkerLike, tid: number, force?: boolean): void;
|
||||
terminateWorker(worker: WorkerLike): void;
|
||||
terminateAllThreads(): void;
|
||||
addMessageEventListener(worker: WorkerLike, onMessage: (e: WorkerMessageEvent) => void): () => void;
|
||||
fireMessageEvent(worker: WorkerLike, e: WorkerMessageEvent): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type ThreadManagerOptions = ThreadManagerOptionsMain | ThreadManagerOptionsChild;
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsBase {
|
||||
printErr?: (message: string) => void;
|
||||
threadSpawn?: (startArg: number, errorOrTid?: number) => number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsChild extends ThreadManagerOptionsBase {
|
||||
childThread: true;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsMain extends ThreadManagerOptionsBase {
|
||||
beforeLoad?: (worker: WorkerLike) => any;
|
||||
reuseWorker?: boolean | number | ReuseWorkerOptions;
|
||||
onCreateWorker: WorkerFactory;
|
||||
childThread?: false;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class ThreadMessageHandler {
|
||||
protected instance: WebAssembly.Instance | undefined;
|
||||
private messagesBeforeLoad;
|
||||
protected postMessage: (message: any) => void;
|
||||
protected onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
protected onError: (error: Error, type: WorkerMessageType) => void;
|
||||
constructor(options?: ThreadMessageHandlerOptions);
|
||||
/** @virtual */
|
||||
instantiate(data: LoadPayload): WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
/** @virtual */
|
||||
handle(e: WorkerMessageEvent<MessageEventData<WorkerMessageType>>): void;
|
||||
private _load;
|
||||
private _start;
|
||||
protected _loaded(err: Error | null, source: WebAssembly.WebAssemblyInstantiatedSource | null, payload: LoadPayload): void;
|
||||
protected handleAfterLoad<E extends WorkerMessageEvent>(e: E, f: (e: E) => void): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadMessageHandlerOptions {
|
||||
onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
onError?: (error: Error, type: WorkerMessageType) => void;
|
||||
postMessage?: (message: any) => void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface WASIInstance {
|
||||
readonly wasiImport?: Record<string, any>;
|
||||
initialize(instance: object): void;
|
||||
start(instance: object): number;
|
||||
getImportObject?(): any;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class WASIThreads {
|
||||
PThread: ThreadManager | undefined;
|
||||
private wasmMemory;
|
||||
private wasmInstance;
|
||||
private readonly threadSpawn;
|
||||
readonly childThread: boolean;
|
||||
private readonly postMessage;
|
||||
readonly wasi: WASIInstance;
|
||||
constructor(options: WASIThreadsOptions);
|
||||
getImportObject(): {
|
||||
wasi: WASIThreadsImports;
|
||||
};
|
||||
setup(wasmInstance: WebAssembly.Instance, wasmModule: WebAssembly.Module, wasmMemory?: WebAssembly.Memory): void;
|
||||
preloadWorkers(): Promise<WorkerLike[]>;
|
||||
/**
|
||||
* It's ok to call this method to a WASI command module.
|
||||
*
|
||||
* in child thread, must call this method instead of {@link WASIThreads.start} even if it's a WASI command module
|
||||
*
|
||||
* @returns A proxied WebAssembly instance if in child thread, other wise the original instance
|
||||
*/
|
||||
initialize(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): WebAssembly.Instance;
|
||||
/**
|
||||
* Equivalent to calling {@link WASIThreads.initialize} and then calling {@link WASIInstance.start}
|
||||
* ```js
|
||||
* this.initialize(instance, module, memory)
|
||||
* this.wasi.start(instance)
|
||||
* ```
|
||||
*/
|
||||
start(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): StartResult;
|
||||
terminateAllThreads(): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface WASIThreadsImports {
|
||||
'thread-spawn': (startArg: number, errorOrTid?: number) => number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type WASIThreadsOptions = MainThreadOptions | ChildThreadOptions;
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerFactory = (ctx: {
|
||||
type: string;
|
||||
name: string;
|
||||
}) => WorkerLike;
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerLike = (Worker | Worker_2) & {
|
||||
whenLoaded?: Promise<WorkerLike>;
|
||||
loaded?: boolean;
|
||||
__emnapi_tid?: number;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export declare interface WorkerMessageEvent<T = any> {
|
||||
data: T;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerMessageType = 'load' | 'start';
|
||||
|
||||
export { }
|
||||
+1
File diff suppressed because one or more lines are too long
+272
@@ -0,0 +1,272 @@
|
||||
/// <reference types="node" />
|
||||
|
||||
import type { Worker as Worker_2 } from 'worker_threads';
|
||||
|
||||
/** @public */
|
||||
export declare interface BaseOptions {
|
||||
wasi: WASIInstance;
|
||||
version?: 'preview1';
|
||||
wasm64?: boolean;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ChildThreadOptions extends BaseOptions {
|
||||
childThread: true;
|
||||
postMessage?: (data: any) => void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CleanupThreadPayload {
|
||||
tid: number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CommandInfo<T extends CommandType> {
|
||||
type: T;
|
||||
payload: CommandPayloadMap[T];
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CommandPayloadMap {
|
||||
load: LoadPayload;
|
||||
loaded: LoadedPayload;
|
||||
start: StartPayload;
|
||||
'cleanup-thread': CleanupThreadPayload;
|
||||
'terminate-all-threads': TerminateAllThreadsPayload;
|
||||
'spawn-thread': SpawnThreadPayload;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type CommandType = keyof CommandPayloadMap;
|
||||
|
||||
/** @public */
|
||||
export declare function createInstanceProxy(instance: WebAssembly.Instance, memory?: WebAssembly.Memory | (() => WebAssembly.Memory)): WebAssembly.Instance;
|
||||
|
||||
/** @public */
|
||||
export declare function isSharedArrayBuffer(value: any): value is SharedArrayBuffer;
|
||||
|
||||
/** @public */
|
||||
export declare function isTrapError(e: Error): e is WebAssembly.RuntimeError;
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadedPayload {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadPayload {
|
||||
wasmModule: WebAssembly.Module;
|
||||
wasmMemory: WebAssembly.Memory;
|
||||
sab?: Int32Array;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadBaseOptions extends BaseOptions {
|
||||
waitThreadStart?: boolean | number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type MainThreadOptions = MainThreadOptionsWithThreadManager | MainThreadOptionsCreateThreadManager;
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadOptionsCreateThreadManager extends MainThreadBaseOptions, ThreadManagerOptionsMain {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadOptionsWithThreadManager extends MainThreadBaseOptions {
|
||||
threadManager?: ThreadManager | (() => ThreadManager);
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MessageEventData<T extends CommandType> {
|
||||
__emnapi__: CommandInfo<T>;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ReuseWorkerOptions {
|
||||
/**
|
||||
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size | PTHREAD_POOL_SIZE}
|
||||
*/
|
||||
size: number;
|
||||
/**
|
||||
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size-strict | PTHREAD_POOL_SIZE_STRICT}
|
||||
*/
|
||||
strict?: boolean;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface SpawnThreadPayload {
|
||||
startArg: number;
|
||||
errorOrTid: number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface StartPayload {
|
||||
tid: number;
|
||||
arg: number;
|
||||
sab?: Int32Array;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface StartResult {
|
||||
exitCode: number;
|
||||
instance: WebAssembly.Instance;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface TerminateAllThreadsPayload {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class ThreadManager {
|
||||
unusedWorkers: WorkerLike[];
|
||||
runningWorkers: WorkerLike[];
|
||||
pthreads: Record<number, WorkerLike>;
|
||||
get nextWorkerID(): number;
|
||||
wasmModule: WebAssembly.Module | null;
|
||||
wasmMemory: WebAssembly.Memory | null;
|
||||
private readonly messageEvents;
|
||||
private readonly _childThread;
|
||||
private readonly _onCreateWorker;
|
||||
private readonly _reuseWorker;
|
||||
private readonly _beforeLoad?;
|
||||
/* Excluded from this release type: printErr */
|
||||
threadSpawn?: ((startArg: number, errorOrTid?: number) => number);
|
||||
constructor(options: ThreadManagerOptions);
|
||||
init(): void;
|
||||
initMainThread(): void;
|
||||
private preparePool;
|
||||
shouldPreloadWorkers(): boolean;
|
||||
loadWasmModuleToAllWorkers(): Promise<WorkerLike[]>;
|
||||
preloadWorkers(): Promise<WorkerLike[]>;
|
||||
setup(wasmModule: WebAssembly.Module, wasmMemory: WebAssembly.Memory): void;
|
||||
markId(worker: WorkerLike): number;
|
||||
returnWorkerToPool(worker: WorkerLike): void;
|
||||
loadWasmModuleToWorker(worker: WorkerLike, sab?: Int32Array): Promise<WorkerLike>;
|
||||
allocateUnusedWorker(): WorkerLike;
|
||||
getNewWorker(sab?: Int32Array): WorkerLike | undefined;
|
||||
cleanThread(worker: WorkerLike, tid: number, force?: boolean): void;
|
||||
terminateWorker(worker: WorkerLike): void;
|
||||
terminateAllThreads(): void;
|
||||
addMessageEventListener(worker: WorkerLike, onMessage: (e: WorkerMessageEvent) => void): () => void;
|
||||
fireMessageEvent(worker: WorkerLike, e: WorkerMessageEvent): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type ThreadManagerOptions = ThreadManagerOptionsMain | ThreadManagerOptionsChild;
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsBase {
|
||||
printErr?: (message: string) => void;
|
||||
threadSpawn?: (startArg: number, errorOrTid?: number) => number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsChild extends ThreadManagerOptionsBase {
|
||||
childThread: true;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsMain extends ThreadManagerOptionsBase {
|
||||
beforeLoad?: (worker: WorkerLike) => any;
|
||||
reuseWorker?: boolean | number | ReuseWorkerOptions;
|
||||
onCreateWorker: WorkerFactory;
|
||||
childThread?: false;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class ThreadMessageHandler {
|
||||
protected instance: WebAssembly.Instance | undefined;
|
||||
private messagesBeforeLoad;
|
||||
protected postMessage: (message: any) => void;
|
||||
protected onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
protected onError: (error: Error, type: WorkerMessageType) => void;
|
||||
constructor(options?: ThreadMessageHandlerOptions);
|
||||
/** @virtual */
|
||||
instantiate(data: LoadPayload): WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
/** @virtual */
|
||||
handle(e: WorkerMessageEvent<MessageEventData<WorkerMessageType>>): void;
|
||||
private _load;
|
||||
private _start;
|
||||
protected _loaded(err: Error | null, source: WebAssembly.WebAssemblyInstantiatedSource | null, payload: LoadPayload): void;
|
||||
protected handleAfterLoad<E extends WorkerMessageEvent>(e: E, f: (e: E) => void): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadMessageHandlerOptions {
|
||||
onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
onError?: (error: Error, type: WorkerMessageType) => void;
|
||||
postMessage?: (message: any) => void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface WASIInstance {
|
||||
readonly wasiImport?: Record<string, any>;
|
||||
initialize(instance: object): void;
|
||||
start(instance: object): number;
|
||||
getImportObject?(): any;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class WASIThreads {
|
||||
PThread: ThreadManager | undefined;
|
||||
private wasmMemory;
|
||||
private wasmInstance;
|
||||
private readonly threadSpawn;
|
||||
readonly childThread: boolean;
|
||||
private readonly postMessage;
|
||||
readonly wasi: WASIInstance;
|
||||
constructor(options: WASIThreadsOptions);
|
||||
getImportObject(): {
|
||||
wasi: WASIThreadsImports;
|
||||
};
|
||||
setup(wasmInstance: WebAssembly.Instance, wasmModule: WebAssembly.Module, wasmMemory?: WebAssembly.Memory): void;
|
||||
preloadWorkers(): Promise<WorkerLike[]>;
|
||||
/**
|
||||
* It's ok to call this method to a WASI command module.
|
||||
*
|
||||
* in child thread, must call this method instead of {@link WASIThreads.start} even if it's a WASI command module
|
||||
*
|
||||
* @returns A proxied WebAssembly instance if in child thread, other wise the original instance
|
||||
*/
|
||||
initialize(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): WebAssembly.Instance;
|
||||
/**
|
||||
* Equivalent to calling {@link WASIThreads.initialize} and then calling {@link WASIInstance.start}
|
||||
* ```js
|
||||
* this.initialize(instance, module, memory)
|
||||
* this.wasi.start(instance)
|
||||
* ```
|
||||
*/
|
||||
start(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): StartResult;
|
||||
terminateAllThreads(): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface WASIThreadsImports {
|
||||
'thread-spawn': (startArg: number, errorOrTid?: number) => number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type WASIThreadsOptions = MainThreadOptions | ChildThreadOptions;
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerFactory = (ctx: {
|
||||
type: string;
|
||||
name: string;
|
||||
}) => WorkerLike;
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerLike = (Worker | Worker_2) & {
|
||||
whenLoaded?: Promise<WorkerLike>;
|
||||
loaded?: boolean;
|
||||
__emnapi_tid?: number;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export declare interface WorkerMessageEvent<T = any> {
|
||||
data: T;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerMessageType = 'load' | 'start';
|
||||
|
||||
export { }
|
||||
+274
@@ -0,0 +1,274 @@
|
||||
/// <reference types="node" />
|
||||
|
||||
import type { Worker as Worker_2 } from 'worker_threads';
|
||||
|
||||
/** @public */
|
||||
export declare interface BaseOptions {
|
||||
wasi: WASIInstance;
|
||||
version?: 'preview1';
|
||||
wasm64?: boolean;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ChildThreadOptions extends BaseOptions {
|
||||
childThread: true;
|
||||
postMessage?: (data: any) => void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CleanupThreadPayload {
|
||||
tid: number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CommandInfo<T extends CommandType> {
|
||||
type: T;
|
||||
payload: CommandPayloadMap[T];
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CommandPayloadMap {
|
||||
load: LoadPayload;
|
||||
loaded: LoadedPayload;
|
||||
start: StartPayload;
|
||||
'cleanup-thread': CleanupThreadPayload;
|
||||
'terminate-all-threads': TerminateAllThreadsPayload;
|
||||
'spawn-thread': SpawnThreadPayload;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type CommandType = keyof CommandPayloadMap;
|
||||
|
||||
/** @public */
|
||||
export declare function createInstanceProxy(instance: WebAssembly.Instance, memory?: WebAssembly.Memory | (() => WebAssembly.Memory)): WebAssembly.Instance;
|
||||
|
||||
/** @public */
|
||||
export declare function isSharedArrayBuffer(value: any): value is SharedArrayBuffer;
|
||||
|
||||
/** @public */
|
||||
export declare function isTrapError(e: Error): e is WebAssembly.RuntimeError;
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadedPayload {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadPayload {
|
||||
wasmModule: WebAssembly.Module;
|
||||
wasmMemory: WebAssembly.Memory;
|
||||
sab?: Int32Array;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadBaseOptions extends BaseOptions {
|
||||
waitThreadStart?: boolean | number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type MainThreadOptions = MainThreadOptionsWithThreadManager | MainThreadOptionsCreateThreadManager;
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadOptionsCreateThreadManager extends MainThreadBaseOptions, ThreadManagerOptionsMain {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadOptionsWithThreadManager extends MainThreadBaseOptions {
|
||||
threadManager?: ThreadManager | (() => ThreadManager);
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MessageEventData<T extends CommandType> {
|
||||
__emnapi__: CommandInfo<T>;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ReuseWorkerOptions {
|
||||
/**
|
||||
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size | PTHREAD_POOL_SIZE}
|
||||
*/
|
||||
size: number;
|
||||
/**
|
||||
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size-strict | PTHREAD_POOL_SIZE_STRICT}
|
||||
*/
|
||||
strict?: boolean;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface SpawnThreadPayload {
|
||||
startArg: number;
|
||||
errorOrTid: number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface StartPayload {
|
||||
tid: number;
|
||||
arg: number;
|
||||
sab?: Int32Array;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface StartResult {
|
||||
exitCode: number;
|
||||
instance: WebAssembly.Instance;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface TerminateAllThreadsPayload {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class ThreadManager {
|
||||
unusedWorkers: WorkerLike[];
|
||||
runningWorkers: WorkerLike[];
|
||||
pthreads: Record<number, WorkerLike>;
|
||||
get nextWorkerID(): number;
|
||||
wasmModule: WebAssembly.Module | null;
|
||||
wasmMemory: WebAssembly.Memory | null;
|
||||
private readonly messageEvents;
|
||||
private readonly _childThread;
|
||||
private readonly _onCreateWorker;
|
||||
private readonly _reuseWorker;
|
||||
private readonly _beforeLoad?;
|
||||
/* Excluded from this release type: printErr */
|
||||
threadSpawn?: ((startArg: number, errorOrTid?: number) => number);
|
||||
constructor(options: ThreadManagerOptions);
|
||||
init(): void;
|
||||
initMainThread(): void;
|
||||
private preparePool;
|
||||
shouldPreloadWorkers(): boolean;
|
||||
loadWasmModuleToAllWorkers(): Promise<WorkerLike[]>;
|
||||
preloadWorkers(): Promise<WorkerLike[]>;
|
||||
setup(wasmModule: WebAssembly.Module, wasmMemory: WebAssembly.Memory): void;
|
||||
markId(worker: WorkerLike): number;
|
||||
returnWorkerToPool(worker: WorkerLike): void;
|
||||
loadWasmModuleToWorker(worker: WorkerLike, sab?: Int32Array): Promise<WorkerLike>;
|
||||
allocateUnusedWorker(): WorkerLike;
|
||||
getNewWorker(sab?: Int32Array): WorkerLike | undefined;
|
||||
cleanThread(worker: WorkerLike, tid: number, force?: boolean): void;
|
||||
terminateWorker(worker: WorkerLike): void;
|
||||
terminateAllThreads(): void;
|
||||
addMessageEventListener(worker: WorkerLike, onMessage: (e: WorkerMessageEvent) => void): () => void;
|
||||
fireMessageEvent(worker: WorkerLike, e: WorkerMessageEvent): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type ThreadManagerOptions = ThreadManagerOptionsMain | ThreadManagerOptionsChild;
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsBase {
|
||||
printErr?: (message: string) => void;
|
||||
threadSpawn?: (startArg: number, errorOrTid?: number) => number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsChild extends ThreadManagerOptionsBase {
|
||||
childThread: true;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsMain extends ThreadManagerOptionsBase {
|
||||
beforeLoad?: (worker: WorkerLike) => any;
|
||||
reuseWorker?: boolean | number | ReuseWorkerOptions;
|
||||
onCreateWorker: WorkerFactory;
|
||||
childThread?: false;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class ThreadMessageHandler {
|
||||
protected instance: WebAssembly.Instance | undefined;
|
||||
private messagesBeforeLoad;
|
||||
protected postMessage: (message: any) => void;
|
||||
protected onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
protected onError: (error: Error, type: WorkerMessageType) => void;
|
||||
constructor(options?: ThreadMessageHandlerOptions);
|
||||
/** @virtual */
|
||||
instantiate(data: LoadPayload): WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
/** @virtual */
|
||||
handle(e: WorkerMessageEvent<MessageEventData<WorkerMessageType>>): void;
|
||||
private _load;
|
||||
private _start;
|
||||
protected _loaded(err: Error | null, source: WebAssembly.WebAssemblyInstantiatedSource | null, payload: LoadPayload): void;
|
||||
protected handleAfterLoad<E extends WorkerMessageEvent>(e: E, f: (e: E) => void): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadMessageHandlerOptions {
|
||||
onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
onError?: (error: Error, type: WorkerMessageType) => void;
|
||||
postMessage?: (message: any) => void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface WASIInstance {
|
||||
readonly wasiImport?: Record<string, any>;
|
||||
initialize(instance: object): void;
|
||||
start(instance: object): number;
|
||||
getImportObject?(): any;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class WASIThreads {
|
||||
PThread: ThreadManager | undefined;
|
||||
private wasmMemory;
|
||||
private wasmInstance;
|
||||
private readonly threadSpawn;
|
||||
readonly childThread: boolean;
|
||||
private readonly postMessage;
|
||||
readonly wasi: WASIInstance;
|
||||
constructor(options: WASIThreadsOptions);
|
||||
getImportObject(): {
|
||||
wasi: WASIThreadsImports;
|
||||
};
|
||||
setup(wasmInstance: WebAssembly.Instance, wasmModule: WebAssembly.Module, wasmMemory?: WebAssembly.Memory): void;
|
||||
preloadWorkers(): Promise<WorkerLike[]>;
|
||||
/**
|
||||
* It's ok to call this method to a WASI command module.
|
||||
*
|
||||
* in child thread, must call this method instead of {@link WASIThreads.start} even if it's a WASI command module
|
||||
*
|
||||
* @returns A proxied WebAssembly instance if in child thread, other wise the original instance
|
||||
*/
|
||||
initialize(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): WebAssembly.Instance;
|
||||
/**
|
||||
* Equivalent to calling {@link WASIThreads.initialize} and then calling {@link WASIInstance.start}
|
||||
* ```js
|
||||
* this.initialize(instance, module, memory)
|
||||
* this.wasi.start(instance)
|
||||
* ```
|
||||
*/
|
||||
start(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): StartResult;
|
||||
terminateAllThreads(): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface WASIThreadsImports {
|
||||
'thread-spawn': (startArg: number, errorOrTid?: number) => number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type WASIThreadsOptions = MainThreadOptions | ChildThreadOptions;
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerFactory = (ctx: {
|
||||
type: string;
|
||||
name: string;
|
||||
}) => WorkerLike;
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerLike = (Worker | Worker_2) & {
|
||||
whenLoaded?: Promise<WorkerLike>;
|
||||
loaded?: boolean;
|
||||
__emnapi_tid?: number;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export declare interface WorkerMessageEvent<T = any> {
|
||||
data: T;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerMessageType = 'load' | 'start';
|
||||
|
||||
export { }
|
||||
|
||||
export as namespace wasiThreads;
|
||||
+942
@@ -0,0 +1,942 @@
|
||||
var _WebAssembly = typeof WebAssembly !== 'undefined'
|
||||
? WebAssembly
|
||||
: typeof WXWebAssembly !== 'undefined'
|
||||
? WXWebAssembly
|
||||
: undefined;
|
||||
var ENVIRONMENT_IS_NODE = typeof process === 'object' && process !== null &&
|
||||
typeof process.versions === 'object' && process.versions !== null &&
|
||||
typeof process.versions.node === 'string';
|
||||
function getPostMessage(options) {
|
||||
return typeof (options === null || options === void 0 ? void 0 : options.postMessage) === 'function'
|
||||
? options.postMessage
|
||||
: typeof postMessage === 'function'
|
||||
? postMessage
|
||||
: undefined;
|
||||
}
|
||||
function serizeErrorToBuffer(sab, code, error) {
|
||||
var i32array = new Int32Array(sab);
|
||||
Atomics.store(i32array, 0, code);
|
||||
if (code > 1 && error) {
|
||||
var name_1 = error.name;
|
||||
var message = error.message;
|
||||
var stack = error.stack;
|
||||
var nameBuffer = new TextEncoder().encode(name_1);
|
||||
var messageBuffer = new TextEncoder().encode(message);
|
||||
var stackBuffer = new TextEncoder().encode(stack);
|
||||
Atomics.store(i32array, 1, nameBuffer.length);
|
||||
Atomics.store(i32array, 2, messageBuffer.length);
|
||||
Atomics.store(i32array, 3, stackBuffer.length);
|
||||
var buffer = new Uint8Array(sab);
|
||||
buffer.set(nameBuffer, 16);
|
||||
buffer.set(messageBuffer, 16 + nameBuffer.length);
|
||||
buffer.set(stackBuffer, 16 + nameBuffer.length + messageBuffer.length);
|
||||
}
|
||||
}
|
||||
function deserizeErrorFromBuffer(sab) {
|
||||
var _a, _b;
|
||||
var i32array = new Int32Array(sab);
|
||||
var status = Atomics.load(i32array, 0);
|
||||
if (status <= 1) {
|
||||
return null;
|
||||
}
|
||||
var nameLength = Atomics.load(i32array, 1);
|
||||
var messageLength = Atomics.load(i32array, 2);
|
||||
var stackLength = Atomics.load(i32array, 3);
|
||||
var buffer = new Uint8Array(sab);
|
||||
var nameBuffer = buffer.slice(16, 16 + nameLength);
|
||||
var messageBuffer = buffer.slice(16 + nameLength, 16 + nameLength + messageLength);
|
||||
var stackBuffer = buffer.slice(16 + nameLength + messageLength, 16 + nameLength + messageLength + stackLength);
|
||||
var name = new TextDecoder().decode(nameBuffer);
|
||||
var message = new TextDecoder().decode(messageBuffer);
|
||||
var stack = new TextDecoder().decode(stackBuffer);
|
||||
var ErrorConstructor = (_a = globalThis[name]) !== null && _a !== void 0 ? _a : (name === 'RuntimeError' ? ((_b = _WebAssembly.RuntimeError) !== null && _b !== void 0 ? _b : Error) : Error);
|
||||
var error = new ErrorConstructor(message);
|
||||
Object.defineProperty(error, 'stack', {
|
||||
value: stack,
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
return error;
|
||||
}
|
||||
/** @public */
|
||||
function isSharedArrayBuffer(value) {
|
||||
return ((typeof SharedArrayBuffer === 'function' && value instanceof SharedArrayBuffer) ||
|
||||
(Object.prototype.toString.call(value) === '[object SharedArrayBuffer]'));
|
||||
}
|
||||
/** @public */
|
||||
function isTrapError(e) {
|
||||
try {
|
||||
return e instanceof _WebAssembly.RuntimeError;
|
||||
}
|
||||
catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function createMessage(type, payload) {
|
||||
return {
|
||||
__emnapi__: {
|
||||
type: type,
|
||||
payload: payload
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var WASI_THREADS_MAX_TID = 0x1FFFFFFF;
|
||||
function checkSharedWasmMemory(wasmMemory) {
|
||||
if (wasmMemory) {
|
||||
if (!isSharedArrayBuffer(wasmMemory.buffer)) {
|
||||
throw new Error('Multithread features require shared wasm memory. ' +
|
||||
'Try to compile with `-matomics -mbulk-memory` and use `--import-memory --shared-memory` during linking, ' +
|
||||
'then create WebAssembly.Memory with `shared: true` option');
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (typeof SharedArrayBuffer === 'undefined') {
|
||||
throw new Error('Current environment does not support SharedArrayBuffer, threads are not available!');
|
||||
}
|
||||
}
|
||||
}
|
||||
function getReuseWorker(value) {
|
||||
var _a;
|
||||
if (typeof value === 'boolean') {
|
||||
return value ? { size: 0, strict: false } : false;
|
||||
}
|
||||
if (typeof value === 'number') {
|
||||
if (!(value >= 0)) {
|
||||
throw new RangeError('reuseWorker: size must be a non-negative integer');
|
||||
}
|
||||
return { size: value, strict: false };
|
||||
}
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
var size = (_a = Number(value.size)) !== null && _a !== void 0 ? _a : 0;
|
||||
var strict = Boolean(value.strict);
|
||||
if (!(size > 0) && strict) {
|
||||
throw new RangeError('reuseWorker: size must be set to positive integer if strict is set to true');
|
||||
}
|
||||
return { size: size, strict: strict };
|
||||
}
|
||||
var nextWorkerID = 0;
|
||||
/** @public */
|
||||
var ThreadManager = /*#__PURE__*/ (function () {
|
||||
function ThreadManager(options) {
|
||||
var _a;
|
||||
this.unusedWorkers = [];
|
||||
this.runningWorkers = [];
|
||||
this.pthreads = Object.create(null);
|
||||
this.wasmModule = null;
|
||||
this.wasmMemory = null;
|
||||
this.messageEvents = new WeakMap();
|
||||
if (!options) {
|
||||
throw new TypeError('ThreadManager(): options is not provided');
|
||||
}
|
||||
if ('childThread' in options) {
|
||||
this._childThread = Boolean(options.childThread);
|
||||
}
|
||||
else {
|
||||
this._childThread = false;
|
||||
}
|
||||
if (this._childThread) {
|
||||
this._onCreateWorker = undefined;
|
||||
this._reuseWorker = false;
|
||||
this._beforeLoad = undefined;
|
||||
}
|
||||
else {
|
||||
this._onCreateWorker = options.onCreateWorker;
|
||||
this._reuseWorker = getReuseWorker(options.reuseWorker);
|
||||
this._beforeLoad = options.beforeLoad;
|
||||
}
|
||||
this.printErr = (_a = options.printErr) !== null && _a !== void 0 ? _a : console.error.bind(console);
|
||||
this.threadSpawn = options.threadSpawn;
|
||||
}
|
||||
Object.defineProperty(ThreadManager.prototype, "nextWorkerID", {
|
||||
get: function () { return nextWorkerID; },
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
ThreadManager.prototype.init = function () {
|
||||
if (!this._childThread) {
|
||||
this.initMainThread();
|
||||
}
|
||||
};
|
||||
ThreadManager.prototype.initMainThread = function () {
|
||||
this.preparePool();
|
||||
};
|
||||
ThreadManager.prototype.preparePool = function () {
|
||||
if (this._reuseWorker) {
|
||||
if (this._reuseWorker.size) {
|
||||
var pthreadPoolSize = this._reuseWorker.size;
|
||||
while (pthreadPoolSize--) {
|
||||
var worker = this.allocateUnusedWorker();
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
// https://github.com/nodejs/node/issues/53036
|
||||
worker.once('message', function () { });
|
||||
worker.unref();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
ThreadManager.prototype.shouldPreloadWorkers = function () {
|
||||
return !this._childThread && this._reuseWorker && this._reuseWorker.size > 0;
|
||||
};
|
||||
ThreadManager.prototype.loadWasmModuleToAllWorkers = function () {
|
||||
var _this_1 = this;
|
||||
var promises = Array(this.unusedWorkers.length);
|
||||
var _loop_1 = function (i) {
|
||||
var worker = this_1.unusedWorkers[i];
|
||||
if (ENVIRONMENT_IS_NODE)
|
||||
worker.ref();
|
||||
promises[i] = this_1.loadWasmModuleToWorker(worker).then(function (w) {
|
||||
if (ENVIRONMENT_IS_NODE)
|
||||
worker.unref();
|
||||
return w;
|
||||
}, function (e) {
|
||||
if (ENVIRONMENT_IS_NODE)
|
||||
worker.unref();
|
||||
throw e;
|
||||
});
|
||||
};
|
||||
var this_1 = this;
|
||||
for (var i = 0; i < this.unusedWorkers.length; ++i) {
|
||||
_loop_1(i);
|
||||
}
|
||||
return Promise.all(promises).catch(function (err) {
|
||||
_this_1.terminateAllThreads();
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
ThreadManager.prototype.preloadWorkers = function () {
|
||||
if (this.shouldPreloadWorkers()) {
|
||||
return this.loadWasmModuleToAllWorkers();
|
||||
}
|
||||
return Promise.resolve([]);
|
||||
};
|
||||
ThreadManager.prototype.setup = function (wasmModule, wasmMemory) {
|
||||
this.wasmModule = wasmModule;
|
||||
this.wasmMemory = wasmMemory;
|
||||
};
|
||||
ThreadManager.prototype.markId = function (worker) {
|
||||
if (worker.__emnapi_tid)
|
||||
return worker.__emnapi_tid;
|
||||
var tid = nextWorkerID + 43;
|
||||
nextWorkerID = (nextWorkerID + 1) % (WASI_THREADS_MAX_TID - 42);
|
||||
this.pthreads[tid] = worker;
|
||||
worker.__emnapi_tid = tid;
|
||||
return tid;
|
||||
};
|
||||
ThreadManager.prototype.returnWorkerToPool = function (worker) {
|
||||
var tid = worker.__emnapi_tid;
|
||||
if (tid !== undefined) {
|
||||
delete this.pthreads[tid];
|
||||
}
|
||||
this.unusedWorkers.push(worker);
|
||||
this.runningWorkers.splice(this.runningWorkers.indexOf(worker), 1);
|
||||
delete worker.__emnapi_tid;
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
worker.unref();
|
||||
}
|
||||
};
|
||||
ThreadManager.prototype.loadWasmModuleToWorker = function (worker, sab) {
|
||||
var _this_1 = this;
|
||||
if (worker.whenLoaded)
|
||||
return worker.whenLoaded;
|
||||
var err = this.printErr;
|
||||
var beforeLoad = this._beforeLoad;
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
var _this = this;
|
||||
worker.whenLoaded = new Promise(function (resolve, reject) {
|
||||
var handleError = function (e) {
|
||||
var message = 'worker sent an error!';
|
||||
if (worker.__emnapi_tid !== undefined) {
|
||||
message = 'worker (tid = ' + worker.__emnapi_tid + ') sent an error!';
|
||||
}
|
||||
if ('message' in e) {
|
||||
err(message + ' ' + e.message);
|
||||
if (e.message.indexOf('RuntimeError') !== -1 || e.message.indexOf('unreachable') !== -1) {
|
||||
try {
|
||||
_this.terminateAllThreads();
|
||||
}
|
||||
catch (_) { }
|
||||
}
|
||||
}
|
||||
else {
|
||||
err(message);
|
||||
}
|
||||
reject(e);
|
||||
throw e;
|
||||
};
|
||||
var handleMessage = function (data) {
|
||||
if (data.__emnapi__) {
|
||||
var type = data.__emnapi__.type;
|
||||
var payload = data.__emnapi__.payload;
|
||||
if (type === 'loaded') {
|
||||
worker.loaded = true;
|
||||
if (ENVIRONMENT_IS_NODE && !worker.__emnapi_tid) {
|
||||
worker.unref();
|
||||
}
|
||||
resolve(worker);
|
||||
// if (payload.err) {
|
||||
// err('failed to load in child thread: ' + (payload.err.message || payload.err))
|
||||
// }
|
||||
}
|
||||
else if (type === 'cleanup-thread') {
|
||||
if (payload.tid in _this_1.pthreads) {
|
||||
_this_1.cleanThread(worker, payload.tid);
|
||||
}
|
||||
}
|
||||
else if (type === 'spawn-thread') {
|
||||
_this_1.threadSpawn(payload.startArg, payload.errorOrTid);
|
||||
}
|
||||
else if (type === 'terminate-all-threads') {
|
||||
_this_1.terminateAllThreads();
|
||||
}
|
||||
}
|
||||
};
|
||||
worker.onmessage = function (e) {
|
||||
handleMessage(e.data);
|
||||
_this_1.fireMessageEvent(worker, e);
|
||||
};
|
||||
worker.onerror = handleError;
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
worker.on('message', function (data) {
|
||||
var _a, _b;
|
||||
(_b = (_a = worker).onmessage) === null || _b === void 0 ? void 0 : _b.call(_a, {
|
||||
data: data
|
||||
});
|
||||
});
|
||||
worker.on('error', function (e) {
|
||||
var _a, _b;
|
||||
(_b = (_a = worker).onerror) === null || _b === void 0 ? void 0 : _b.call(_a, e);
|
||||
});
|
||||
worker.on('detachedExit', function () { });
|
||||
}
|
||||
if (typeof beforeLoad === 'function') {
|
||||
beforeLoad(worker);
|
||||
}
|
||||
try {
|
||||
worker.postMessage(createMessage('load', {
|
||||
wasmModule: _this_1.wasmModule,
|
||||
wasmMemory: _this_1.wasmMemory,
|
||||
sab: sab
|
||||
}));
|
||||
}
|
||||
catch (err) {
|
||||
checkSharedWasmMemory(_this_1.wasmMemory);
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
return worker.whenLoaded;
|
||||
};
|
||||
ThreadManager.prototype.allocateUnusedWorker = function () {
|
||||
var _onCreateWorker = this._onCreateWorker;
|
||||
if (typeof _onCreateWorker !== 'function') {
|
||||
throw new TypeError('`options.onCreateWorker` is not provided');
|
||||
}
|
||||
var worker = _onCreateWorker({ type: 'thread', name: 'emnapi-pthread' });
|
||||
this.unusedWorkers.push(worker);
|
||||
return worker;
|
||||
};
|
||||
ThreadManager.prototype.getNewWorker = function (sab) {
|
||||
if (this._reuseWorker) {
|
||||
if (this.unusedWorkers.length === 0) {
|
||||
if (this._reuseWorker.strict) {
|
||||
if (!ENVIRONMENT_IS_NODE) {
|
||||
var err = this.printErr;
|
||||
err('Tried to spawn a new thread, but the thread pool is exhausted.\n' +
|
||||
'This might result in a deadlock unless some threads eventually exit or the code explicitly breaks out to the event loop.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
var worker_1 = this.allocateUnusedWorker();
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.loadWasmModuleToWorker(worker_1, sab);
|
||||
}
|
||||
return this.unusedWorkers.pop();
|
||||
}
|
||||
var worker = this.allocateUnusedWorker();
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.loadWasmModuleToWorker(worker, sab);
|
||||
return this.unusedWorkers.pop();
|
||||
};
|
||||
ThreadManager.prototype.cleanThread = function (worker, tid, force) {
|
||||
if (!force && this._reuseWorker) {
|
||||
this.returnWorkerToPool(worker);
|
||||
}
|
||||
else {
|
||||
delete this.pthreads[tid];
|
||||
var index = this.runningWorkers.indexOf(worker);
|
||||
if (index !== -1) {
|
||||
this.runningWorkers.splice(index, 1);
|
||||
}
|
||||
this.terminateWorker(worker);
|
||||
delete worker.__emnapi_tid;
|
||||
}
|
||||
};
|
||||
ThreadManager.prototype.terminateWorker = function (worker) {
|
||||
var _this_1 = this;
|
||||
var _a;
|
||||
var tid = worker.__emnapi_tid;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
worker.terminate();
|
||||
(_a = this.messageEvents.get(worker)) === null || _a === void 0 ? void 0 : _a.clear();
|
||||
this.messageEvents.delete(worker);
|
||||
worker.onmessage = function (e) {
|
||||
if (e.data.__emnapi__) {
|
||||
var err = _this_1.printErr;
|
||||
err('received "' + e.data.__emnapi__.type + '" command from terminated worker: ' + tid);
|
||||
}
|
||||
};
|
||||
};
|
||||
ThreadManager.prototype.terminateAllThreads = function () {
|
||||
for (var i = 0; i < this.runningWorkers.length; ++i) {
|
||||
this.terminateWorker(this.runningWorkers[i]);
|
||||
}
|
||||
for (var i = 0; i < this.unusedWorkers.length; ++i) {
|
||||
this.terminateWorker(this.unusedWorkers[i]);
|
||||
}
|
||||
this.unusedWorkers = [];
|
||||
this.runningWorkers = [];
|
||||
this.pthreads = Object.create(null);
|
||||
this.preparePool();
|
||||
};
|
||||
ThreadManager.prototype.addMessageEventListener = function (worker, onMessage) {
|
||||
var listeners = this.messageEvents.get(worker);
|
||||
if (!listeners) {
|
||||
listeners = new Set();
|
||||
this.messageEvents.set(worker, listeners);
|
||||
}
|
||||
listeners.add(onMessage);
|
||||
return function () {
|
||||
listeners === null || listeners === void 0 ? void 0 : listeners.delete(onMessage);
|
||||
};
|
||||
};
|
||||
ThreadManager.prototype.fireMessageEvent = function (worker, e) {
|
||||
var listeners = this.messageEvents.get(worker);
|
||||
if (!listeners)
|
||||
return;
|
||||
var err = this.printErr;
|
||||
listeners.forEach(function (listener) {
|
||||
try {
|
||||
listener(e);
|
||||
}
|
||||
catch (e) {
|
||||
err(e.stack);
|
||||
}
|
||||
});
|
||||
};
|
||||
return ThreadManager;
|
||||
}());
|
||||
|
||||
var kIsProxy = Symbol('kIsProxy');
|
||||
/** @public */
|
||||
function createInstanceProxy(instance, memory) {
|
||||
if (instance[kIsProxy])
|
||||
return instance;
|
||||
// https://github.com/nodejs/help/issues/4102
|
||||
var originalExports = instance.exports;
|
||||
var createHandler = function (target) {
|
||||
var handlers = [
|
||||
'apply',
|
||||
'construct',
|
||||
'defineProperty',
|
||||
'deleteProperty',
|
||||
'get',
|
||||
'getOwnPropertyDescriptor',
|
||||
'getPrototypeOf',
|
||||
'has',
|
||||
'isExtensible',
|
||||
'ownKeys',
|
||||
'preventExtensions',
|
||||
'set',
|
||||
'setPrototypeOf'
|
||||
];
|
||||
var handler = {};
|
||||
var _loop_1 = function (i) {
|
||||
var name_1 = handlers[i];
|
||||
handler[name_1] = function () {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
args.unshift(target);
|
||||
return Reflect[name_1].apply(Reflect, args);
|
||||
};
|
||||
};
|
||||
for (var i = 0; i < handlers.length; i++) {
|
||||
_loop_1(i);
|
||||
}
|
||||
return handler;
|
||||
};
|
||||
var handler = createHandler(originalExports);
|
||||
var _initialize = function () { };
|
||||
var _start = function () { return 0; };
|
||||
handler.get = function (_target, p, receiver) {
|
||||
var _a;
|
||||
if (p === 'memory') {
|
||||
return (_a = (typeof memory === 'function' ? memory() : memory)) !== null && _a !== void 0 ? _a : Reflect.get(originalExports, p, receiver);
|
||||
}
|
||||
if (p === '_initialize') {
|
||||
return p in originalExports ? _initialize : undefined;
|
||||
}
|
||||
if (p === '_start') {
|
||||
return p in originalExports ? _start : undefined;
|
||||
}
|
||||
return Reflect.get(originalExports, p, receiver);
|
||||
};
|
||||
handler.has = function (_target, p) {
|
||||
if (p === 'memory')
|
||||
return true;
|
||||
return Reflect.has(originalExports, p);
|
||||
};
|
||||
var exportsProxy = new Proxy(Object.create(null), handler);
|
||||
return new Proxy(instance, {
|
||||
get: function (target, p, receiver) {
|
||||
if (p === 'exports') {
|
||||
return exportsProxy;
|
||||
}
|
||||
if (p === kIsProxy) {
|
||||
return true;
|
||||
}
|
||||
return Reflect.get(target, p, receiver);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var patchedWasiInstances = new WeakMap();
|
||||
/** @public */
|
||||
var WASIThreads = /*#__PURE__*/ (function () {
|
||||
function WASIThreads(options) {
|
||||
var _this_1 = this;
|
||||
if (!options) {
|
||||
throw new TypeError('WASIThreads(): options is not provided');
|
||||
}
|
||||
if (!options.wasi) {
|
||||
throw new TypeError('WASIThreads(): options.wasi is not provided');
|
||||
}
|
||||
patchedWasiInstances.set(this, new WeakSet());
|
||||
var wasi = options.wasi;
|
||||
patchWasiInstance(this, wasi);
|
||||
this.wasi = wasi;
|
||||
if ('childThread' in options) {
|
||||
this.childThread = Boolean(options.childThread);
|
||||
}
|
||||
else {
|
||||
this.childThread = false;
|
||||
}
|
||||
this.PThread = undefined;
|
||||
if ('threadManager' in options) {
|
||||
if (typeof options.threadManager === 'function') {
|
||||
this.PThread = options.threadManager();
|
||||
}
|
||||
else {
|
||||
this.PThread = options.threadManager;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!this.childThread) {
|
||||
this.PThread = new ThreadManager(options);
|
||||
this.PThread.init();
|
||||
}
|
||||
}
|
||||
var waitThreadStart = false;
|
||||
if ('waitThreadStart' in options) {
|
||||
waitThreadStart = typeof options.waitThreadStart === 'number' ? options.waitThreadStart : Boolean(options.waitThreadStart);
|
||||
}
|
||||
var postMessage = getPostMessage(options);
|
||||
if (this.childThread && typeof postMessage !== 'function') {
|
||||
throw new TypeError('options.postMessage is not a function');
|
||||
}
|
||||
this.postMessage = postMessage;
|
||||
var wasm64 = Boolean(options.wasm64);
|
||||
var threadSpawn = function (startArg, errorOrTid) {
|
||||
var _a;
|
||||
var EAGAIN = 6;
|
||||
var isNewABI = errorOrTid !== undefined;
|
||||
try {
|
||||
checkSharedWasmMemory(_this_1.wasmMemory);
|
||||
}
|
||||
catch (err) {
|
||||
(_a = _this_1.PThread) === null || _a === void 0 ? void 0 : _a.printErr(err.stack);
|
||||
if (isNewABI) {
|
||||
var struct_1 = new Int32Array(_this_1.wasmMemory.buffer, errorOrTid, 2);
|
||||
Atomics.store(struct_1, 0, 1);
|
||||
Atomics.store(struct_1, 1, EAGAIN);
|
||||
Atomics.notify(struct_1, 1);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
if (!isNewABI) {
|
||||
var malloc = _this_1.wasmInstance.exports.malloc;
|
||||
errorOrTid = wasm64 ? Number(malloc(BigInt(8))) : (malloc(8) >>> 0);
|
||||
if (!errorOrTid) {
|
||||
return -48; /* ENOMEM */
|
||||
}
|
||||
}
|
||||
var _free = _this_1.wasmInstance.exports.free;
|
||||
var free = wasm64 ? function (ptr) { _free(BigInt(ptr)); } : _free;
|
||||
var struct = new Int32Array(_this_1.wasmMemory.buffer, errorOrTid, 2);
|
||||
Atomics.store(struct, 0, 0);
|
||||
Atomics.store(struct, 1, 0);
|
||||
if (_this_1.childThread) {
|
||||
postMessage(createMessage('spawn-thread', {
|
||||
startArg: startArg,
|
||||
errorOrTid: errorOrTid
|
||||
}));
|
||||
Atomics.wait(struct, 1, 0);
|
||||
var isError = Atomics.load(struct, 0);
|
||||
var result = Atomics.load(struct, 1);
|
||||
if (isNewABI) {
|
||||
return isError;
|
||||
}
|
||||
free(errorOrTid);
|
||||
return isError ? -result : result;
|
||||
}
|
||||
var shouldWait = waitThreadStart || (waitThreadStart === 0);
|
||||
var sab;
|
||||
if (shouldWait) {
|
||||
sab = new Int32Array(new SharedArrayBuffer(16 + 8192));
|
||||
Atomics.store(sab, 0, 0);
|
||||
}
|
||||
var worker;
|
||||
var tid;
|
||||
var PThread = _this_1.PThread;
|
||||
try {
|
||||
worker = PThread.getNewWorker(sab);
|
||||
if (!worker) {
|
||||
throw new Error('failed to get new worker');
|
||||
}
|
||||
tid = PThread.markId(worker);
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
worker.unref();
|
||||
}
|
||||
worker.postMessage(createMessage('start', {
|
||||
tid: tid,
|
||||
arg: startArg,
|
||||
sab: sab
|
||||
}));
|
||||
if (shouldWait) {
|
||||
if (typeof waitThreadStart === 'number') {
|
||||
var waitResult = Atomics.wait(sab, 0, 0, waitThreadStart);
|
||||
if (waitResult === 'timed-out') {
|
||||
try {
|
||||
PThread.cleanThread(worker, tid, true);
|
||||
}
|
||||
catch (_) { }
|
||||
throw new Error('Spawning thread timed out. Please check if the worker is created successfully and if message is handled properly in the worker.');
|
||||
}
|
||||
}
|
||||
else {
|
||||
Atomics.wait(sab, 0, 0);
|
||||
}
|
||||
var r = Atomics.load(sab, 0);
|
||||
if (r > 1) {
|
||||
try {
|
||||
PThread.cleanThread(worker, tid, true);
|
||||
}
|
||||
catch (_) { }
|
||||
throw deserizeErrorFromBuffer(sab.buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
Atomics.store(struct, 0, 1);
|
||||
Atomics.store(struct, 1, EAGAIN);
|
||||
Atomics.notify(struct, 1);
|
||||
PThread === null || PThread === void 0 ? void 0 : PThread.printErr(e.stack);
|
||||
if (isNewABI) {
|
||||
return 1;
|
||||
}
|
||||
free(errorOrTid);
|
||||
return -EAGAIN;
|
||||
}
|
||||
Atomics.store(struct, 0, 0);
|
||||
Atomics.store(struct, 1, tid);
|
||||
Atomics.notify(struct, 1);
|
||||
PThread.runningWorkers.push(worker);
|
||||
if (!shouldWait) {
|
||||
worker.whenLoaded.catch(function (err) {
|
||||
delete worker.whenLoaded;
|
||||
PThread.cleanThread(worker, tid, true);
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
if (isNewABI) {
|
||||
return 0;
|
||||
}
|
||||
free(errorOrTid);
|
||||
return tid;
|
||||
};
|
||||
this.threadSpawn = threadSpawn;
|
||||
if (this.PThread) {
|
||||
this.PThread.threadSpawn = threadSpawn;
|
||||
}
|
||||
}
|
||||
WASIThreads.prototype.getImportObject = function () {
|
||||
return {
|
||||
wasi: {
|
||||
'thread-spawn': this.threadSpawn
|
||||
}
|
||||
};
|
||||
};
|
||||
WASIThreads.prototype.setup = function (wasmInstance, wasmModule, wasmMemory) {
|
||||
wasmMemory !== null && wasmMemory !== void 0 ? wasmMemory : (wasmMemory = wasmInstance.exports.memory);
|
||||
this.wasmInstance = wasmInstance;
|
||||
this.wasmMemory = wasmMemory;
|
||||
if (this.PThread) {
|
||||
this.PThread.setup(wasmModule, wasmMemory);
|
||||
}
|
||||
};
|
||||
WASIThreads.prototype.preloadWorkers = function () {
|
||||
if (this.PThread) {
|
||||
return this.PThread.preloadWorkers();
|
||||
}
|
||||
return Promise.resolve([]);
|
||||
};
|
||||
/**
|
||||
* It's ok to call this method to a WASI command module.
|
||||
*
|
||||
* in child thread, must call this method instead of {@link WASIThreads.start} even if it's a WASI command module
|
||||
*
|
||||
* @returns A proxied WebAssembly instance if in child thread, other wise the original instance
|
||||
*/
|
||||
WASIThreads.prototype.initialize = function (instance, module, memory) {
|
||||
var exports$1 = instance.exports;
|
||||
memory !== null && memory !== void 0 ? memory : (memory = exports$1.memory);
|
||||
if (this.childThread) {
|
||||
instance = createInstanceProxy(instance, memory);
|
||||
}
|
||||
this.setup(instance, module, memory);
|
||||
var wasi = this.wasi;
|
||||
if (('_start' in exports$1) && (typeof exports$1._start === 'function')) {
|
||||
if (this.childThread) {
|
||||
wasi.start(instance);
|
||||
try {
|
||||
var kStarted = getWasiSymbol(wasi, 'kStarted');
|
||||
wasi[kStarted] = false;
|
||||
}
|
||||
catch (_) { }
|
||||
}
|
||||
else {
|
||||
setupInstance(wasi, instance);
|
||||
}
|
||||
}
|
||||
else {
|
||||
wasi.initialize(instance);
|
||||
}
|
||||
return instance;
|
||||
};
|
||||
/**
|
||||
* Equivalent to calling {@link WASIThreads.initialize} and then calling {@link WASIInstance.start}
|
||||
* ```js
|
||||
* this.initialize(instance, module, memory)
|
||||
* this.wasi.start(instance)
|
||||
* ```
|
||||
*/
|
||||
WASIThreads.prototype.start = function (instance, module, memory) {
|
||||
var exports$1 = instance.exports;
|
||||
memory !== null && memory !== void 0 ? memory : (memory = exports$1.memory);
|
||||
if (this.childThread) {
|
||||
instance = createInstanceProxy(instance, memory);
|
||||
}
|
||||
this.setup(instance, module, memory);
|
||||
var exitCode = this.wasi.start(instance);
|
||||
return { exitCode: exitCode, instance: instance };
|
||||
};
|
||||
WASIThreads.prototype.terminateAllThreads = function () {
|
||||
var _a;
|
||||
if (!this.childThread) {
|
||||
(_a = this.PThread) === null || _a === void 0 ? void 0 : _a.terminateAllThreads();
|
||||
}
|
||||
else {
|
||||
this.postMessage(createMessage('terminate-all-threads', {}));
|
||||
}
|
||||
};
|
||||
return WASIThreads;
|
||||
}());
|
||||
function patchWasiInstance(wasiThreads, wasi) {
|
||||
var patched = patchedWasiInstances.get(wasiThreads);
|
||||
if (patched.has(wasi)) {
|
||||
return;
|
||||
}
|
||||
var _this = wasiThreads;
|
||||
var wasiImport = wasi.wasiImport;
|
||||
if (wasiImport) {
|
||||
var proc_exit_1 = wasiImport.proc_exit;
|
||||
wasiImport.proc_exit = function (code) {
|
||||
_this.terminateAllThreads();
|
||||
return proc_exit_1.call(this, code);
|
||||
};
|
||||
}
|
||||
if (!_this.childThread) {
|
||||
var start_1 = wasi.start;
|
||||
if (typeof start_1 === 'function') {
|
||||
wasi.start = function (instance) {
|
||||
try {
|
||||
return start_1.call(this, instance);
|
||||
}
|
||||
catch (err) {
|
||||
if (isTrapError(err)) {
|
||||
_this.terminateAllThreads();
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
patched.add(wasi);
|
||||
}
|
||||
function getWasiSymbol(wasi, description) {
|
||||
var symbols = Object.getOwnPropertySymbols(wasi);
|
||||
var selectDescription = function (description) { return function (s) {
|
||||
if (s.description) {
|
||||
return s.description === description;
|
||||
}
|
||||
return s.toString() === "Symbol(".concat(description, ")");
|
||||
}; };
|
||||
if (Array.isArray(description)) {
|
||||
return description.map(function (d) { return symbols.filter(selectDescription(d))[0]; });
|
||||
}
|
||||
return symbols.filter(selectDescription(description))[0];
|
||||
}
|
||||
function setupInstance(wasi, instance) {
|
||||
var _a = getWasiSymbol(wasi, ['kInstance', 'kSetMemory']), kInstance = _a[0], kSetMemory = _a[1];
|
||||
wasi[kInstance] = instance;
|
||||
wasi[kSetMemory](instance.exports.memory);
|
||||
}
|
||||
|
||||
/** @public */
|
||||
var ThreadMessageHandler = /*#__PURE__*/ (function () {
|
||||
function ThreadMessageHandler(options) {
|
||||
var postMsg = getPostMessage(options);
|
||||
if (typeof postMsg !== 'function') {
|
||||
throw new TypeError('options.postMessage is not a function');
|
||||
}
|
||||
this.postMessage = postMsg;
|
||||
this.onLoad = options === null || options === void 0 ? void 0 : options.onLoad;
|
||||
this.onError = typeof (options === null || options === void 0 ? void 0 : options.onError) === 'function' ? options.onError : function (_type, err) { throw err; };
|
||||
this.instance = undefined;
|
||||
// this.module = undefined
|
||||
this.messagesBeforeLoad = [];
|
||||
}
|
||||
/** @virtual */
|
||||
ThreadMessageHandler.prototype.instantiate = function (data) {
|
||||
if (typeof this.onLoad === 'function') {
|
||||
return this.onLoad(data);
|
||||
}
|
||||
throw new Error('ThreadMessageHandler.prototype.instantiate is not implemented');
|
||||
};
|
||||
/** @virtual */
|
||||
ThreadMessageHandler.prototype.handle = function (e) {
|
||||
var _this = this;
|
||||
var _a;
|
||||
if ((_a = e === null || e === void 0 ? void 0 : e.data) === null || _a === void 0 ? void 0 : _a.__emnapi__) {
|
||||
var type = e.data.__emnapi__.type;
|
||||
var payload_1 = e.data.__emnapi__.payload;
|
||||
try {
|
||||
if (type === 'load') {
|
||||
this._load(payload_1);
|
||||
}
|
||||
else if (type === 'start') {
|
||||
this.handleAfterLoad(e, function () {
|
||||
_this._start(payload_1);
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
this.onError(err, type);
|
||||
}
|
||||
}
|
||||
};
|
||||
ThreadMessageHandler.prototype._load = function (payload) {
|
||||
var _this = this;
|
||||
if (this.instance !== undefined)
|
||||
return;
|
||||
var source;
|
||||
try {
|
||||
source = this.instantiate(payload);
|
||||
}
|
||||
catch (err) {
|
||||
this._loaded(err, null, payload);
|
||||
return;
|
||||
}
|
||||
var then = source && 'then' in source ? source.then : undefined;
|
||||
if (typeof then === 'function') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
then.call(source, function (source) { _this._loaded(null, source, payload); }, function (err) { _this._loaded(err, null, payload); });
|
||||
}
|
||||
else {
|
||||
this._loaded(null, source, payload);
|
||||
}
|
||||
};
|
||||
ThreadMessageHandler.prototype._start = function (payload) {
|
||||
var wasi_thread_start = this.instance.exports.wasi_thread_start;
|
||||
if (typeof wasi_thread_start !== 'function') {
|
||||
var err = new TypeError('wasi_thread_start is not exported');
|
||||
notifyPthreadCreateResult(payload.sab, 2, err);
|
||||
throw err;
|
||||
}
|
||||
var postMessage = this.postMessage;
|
||||
var tid = payload.tid;
|
||||
var startArg = payload.arg;
|
||||
notifyPthreadCreateResult(payload.sab, 1);
|
||||
try {
|
||||
wasi_thread_start(tid, startArg);
|
||||
}
|
||||
catch (err) {
|
||||
if (err !== 'unwind') {
|
||||
throw err;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
postMessage(createMessage('cleanup-thread', { tid: tid }));
|
||||
};
|
||||
ThreadMessageHandler.prototype._loaded = function (err, source, payload) {
|
||||
if (err) {
|
||||
notifyPthreadCreateResult(payload.sab, 2, err);
|
||||
throw err;
|
||||
}
|
||||
if (source == null) {
|
||||
var err_1 = new TypeError('onLoad should return an object');
|
||||
notifyPthreadCreateResult(payload.sab, 2, err_1);
|
||||
throw err_1;
|
||||
}
|
||||
var instance = source.instance;
|
||||
if (!instance) {
|
||||
var err_2 = new TypeError('onLoad should return an object which includes "instance"');
|
||||
notifyPthreadCreateResult(payload.sab, 2, err_2);
|
||||
throw err_2;
|
||||
}
|
||||
this.instance = instance;
|
||||
var postMessage = this.postMessage;
|
||||
postMessage(createMessage('loaded', {}));
|
||||
var messages = this.messagesBeforeLoad;
|
||||
this.messagesBeforeLoad = [];
|
||||
for (var i = 0; i < messages.length; i++) {
|
||||
var data = messages[i];
|
||||
this.handle({ data: data });
|
||||
}
|
||||
};
|
||||
ThreadMessageHandler.prototype.handleAfterLoad = function (e, f) {
|
||||
if (this.instance !== undefined) {
|
||||
f.call(this, e);
|
||||
}
|
||||
else {
|
||||
this.messagesBeforeLoad.push(e.data);
|
||||
}
|
||||
};
|
||||
return ThreadMessageHandler;
|
||||
}());
|
||||
function notifyPthreadCreateResult(sab, result, error) {
|
||||
if (sab) {
|
||||
serizeErrorToBuffer(sab.buffer, result, error);
|
||||
Atomics.notify(sab, 0);
|
||||
}
|
||||
}
|
||||
|
||||
export { ThreadManager, ThreadMessageHandler, WASIThreads, createInstanceProxy, isSharedArrayBuffer, isTrapError };
|
||||
+954
@@ -0,0 +1,954 @@
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
||||
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.wasiThreads = {}));
|
||||
})(this, (function (exports) {
|
||||
var _WebAssembly = typeof WebAssembly !== 'undefined'
|
||||
? WebAssembly
|
||||
: typeof WXWebAssembly !== 'undefined'
|
||||
? WXWebAssembly
|
||||
: undefined;
|
||||
var ENVIRONMENT_IS_NODE = typeof process === 'object' && process !== null &&
|
||||
typeof process.versions === 'object' && process.versions !== null &&
|
||||
typeof process.versions.node === 'string';
|
||||
function getPostMessage(options) {
|
||||
return typeof (options === null || options === void 0 ? void 0 : options.postMessage) === 'function'
|
||||
? options.postMessage
|
||||
: typeof postMessage === 'function'
|
||||
? postMessage
|
||||
: undefined;
|
||||
}
|
||||
function serizeErrorToBuffer(sab, code, error) {
|
||||
var i32array = new Int32Array(sab);
|
||||
Atomics.store(i32array, 0, code);
|
||||
if (code > 1 && error) {
|
||||
var name_1 = error.name;
|
||||
var message = error.message;
|
||||
var stack = error.stack;
|
||||
var nameBuffer = new TextEncoder().encode(name_1);
|
||||
var messageBuffer = new TextEncoder().encode(message);
|
||||
var stackBuffer = new TextEncoder().encode(stack);
|
||||
Atomics.store(i32array, 1, nameBuffer.length);
|
||||
Atomics.store(i32array, 2, messageBuffer.length);
|
||||
Atomics.store(i32array, 3, stackBuffer.length);
|
||||
var buffer = new Uint8Array(sab);
|
||||
buffer.set(nameBuffer, 16);
|
||||
buffer.set(messageBuffer, 16 + nameBuffer.length);
|
||||
buffer.set(stackBuffer, 16 + nameBuffer.length + messageBuffer.length);
|
||||
}
|
||||
}
|
||||
function deserizeErrorFromBuffer(sab) {
|
||||
var _a, _b;
|
||||
var i32array = new Int32Array(sab);
|
||||
var status = Atomics.load(i32array, 0);
|
||||
if (status <= 1) {
|
||||
return null;
|
||||
}
|
||||
var nameLength = Atomics.load(i32array, 1);
|
||||
var messageLength = Atomics.load(i32array, 2);
|
||||
var stackLength = Atomics.load(i32array, 3);
|
||||
var buffer = new Uint8Array(sab);
|
||||
var nameBuffer = buffer.slice(16, 16 + nameLength);
|
||||
var messageBuffer = buffer.slice(16 + nameLength, 16 + nameLength + messageLength);
|
||||
var stackBuffer = buffer.slice(16 + nameLength + messageLength, 16 + nameLength + messageLength + stackLength);
|
||||
var name = new TextDecoder().decode(nameBuffer);
|
||||
var message = new TextDecoder().decode(messageBuffer);
|
||||
var stack = new TextDecoder().decode(stackBuffer);
|
||||
var ErrorConstructor = (_a = globalThis[name]) !== null && _a !== void 0 ? _a : (name === 'RuntimeError' ? ((_b = _WebAssembly.RuntimeError) !== null && _b !== void 0 ? _b : Error) : Error);
|
||||
var error = new ErrorConstructor(message);
|
||||
Object.defineProperty(error, 'stack', {
|
||||
value: stack,
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
return error;
|
||||
}
|
||||
/** @public */
|
||||
function isSharedArrayBuffer(value) {
|
||||
return ((typeof SharedArrayBuffer === 'function' && value instanceof SharedArrayBuffer) ||
|
||||
(Object.prototype.toString.call(value) === '[object SharedArrayBuffer]'));
|
||||
}
|
||||
/** @public */
|
||||
function isTrapError(e) {
|
||||
try {
|
||||
return e instanceof _WebAssembly.RuntimeError;
|
||||
}
|
||||
catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function createMessage(type, payload) {
|
||||
return {
|
||||
__emnapi__: {
|
||||
type: type,
|
||||
payload: payload
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var WASI_THREADS_MAX_TID = 0x1FFFFFFF;
|
||||
function checkSharedWasmMemory(wasmMemory) {
|
||||
if (wasmMemory) {
|
||||
if (!isSharedArrayBuffer(wasmMemory.buffer)) {
|
||||
throw new Error('Multithread features require shared wasm memory. ' +
|
||||
'Try to compile with `-matomics -mbulk-memory` and use `--import-memory --shared-memory` during linking, ' +
|
||||
'then create WebAssembly.Memory with `shared: true` option');
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (typeof SharedArrayBuffer === 'undefined') {
|
||||
throw new Error('Current environment does not support SharedArrayBuffer, threads are not available!');
|
||||
}
|
||||
}
|
||||
}
|
||||
function getReuseWorker(value) {
|
||||
var _a;
|
||||
if (typeof value === 'boolean') {
|
||||
return value ? { size: 0, strict: false } : false;
|
||||
}
|
||||
if (typeof value === 'number') {
|
||||
if (!(value >= 0)) {
|
||||
throw new RangeError('reuseWorker: size must be a non-negative integer');
|
||||
}
|
||||
return { size: value, strict: false };
|
||||
}
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
var size = (_a = Number(value.size)) !== null && _a !== void 0 ? _a : 0;
|
||||
var strict = Boolean(value.strict);
|
||||
if (!(size > 0) && strict) {
|
||||
throw new RangeError('reuseWorker: size must be set to positive integer if strict is set to true');
|
||||
}
|
||||
return { size: size, strict: strict };
|
||||
}
|
||||
var nextWorkerID = 0;
|
||||
/** @public */
|
||||
var ThreadManager = /*#__PURE__*/ (function () {
|
||||
function ThreadManager(options) {
|
||||
var _a;
|
||||
this.unusedWorkers = [];
|
||||
this.runningWorkers = [];
|
||||
this.pthreads = Object.create(null);
|
||||
this.wasmModule = null;
|
||||
this.wasmMemory = null;
|
||||
this.messageEvents = new WeakMap();
|
||||
if (!options) {
|
||||
throw new TypeError('ThreadManager(): options is not provided');
|
||||
}
|
||||
if ('childThread' in options) {
|
||||
this._childThread = Boolean(options.childThread);
|
||||
}
|
||||
else {
|
||||
this._childThread = false;
|
||||
}
|
||||
if (this._childThread) {
|
||||
this._onCreateWorker = undefined;
|
||||
this._reuseWorker = false;
|
||||
this._beforeLoad = undefined;
|
||||
}
|
||||
else {
|
||||
this._onCreateWorker = options.onCreateWorker;
|
||||
this._reuseWorker = getReuseWorker(options.reuseWorker);
|
||||
this._beforeLoad = options.beforeLoad;
|
||||
}
|
||||
this.printErr = (_a = options.printErr) !== null && _a !== void 0 ? _a : console.error.bind(console);
|
||||
this.threadSpawn = options.threadSpawn;
|
||||
}
|
||||
Object.defineProperty(ThreadManager.prototype, "nextWorkerID", {
|
||||
get: function () { return nextWorkerID; },
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
ThreadManager.prototype.init = function () {
|
||||
if (!this._childThread) {
|
||||
this.initMainThread();
|
||||
}
|
||||
};
|
||||
ThreadManager.prototype.initMainThread = function () {
|
||||
this.preparePool();
|
||||
};
|
||||
ThreadManager.prototype.preparePool = function () {
|
||||
if (this._reuseWorker) {
|
||||
if (this._reuseWorker.size) {
|
||||
var pthreadPoolSize = this._reuseWorker.size;
|
||||
while (pthreadPoolSize--) {
|
||||
var worker = this.allocateUnusedWorker();
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
// https://github.com/nodejs/node/issues/53036
|
||||
worker.once('message', function () { });
|
||||
worker.unref();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
ThreadManager.prototype.shouldPreloadWorkers = function () {
|
||||
return !this._childThread && this._reuseWorker && this._reuseWorker.size > 0;
|
||||
};
|
||||
ThreadManager.prototype.loadWasmModuleToAllWorkers = function () {
|
||||
var _this_1 = this;
|
||||
var promises = Array(this.unusedWorkers.length);
|
||||
var _loop_1 = function (i) {
|
||||
var worker = this_1.unusedWorkers[i];
|
||||
if (ENVIRONMENT_IS_NODE)
|
||||
worker.ref();
|
||||
promises[i] = this_1.loadWasmModuleToWorker(worker).then(function (w) {
|
||||
if (ENVIRONMENT_IS_NODE)
|
||||
worker.unref();
|
||||
return w;
|
||||
}, function (e) {
|
||||
if (ENVIRONMENT_IS_NODE)
|
||||
worker.unref();
|
||||
throw e;
|
||||
});
|
||||
};
|
||||
var this_1 = this;
|
||||
for (var i = 0; i < this.unusedWorkers.length; ++i) {
|
||||
_loop_1(i);
|
||||
}
|
||||
return Promise.all(promises).catch(function (err) {
|
||||
_this_1.terminateAllThreads();
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
ThreadManager.prototype.preloadWorkers = function () {
|
||||
if (this.shouldPreloadWorkers()) {
|
||||
return this.loadWasmModuleToAllWorkers();
|
||||
}
|
||||
return Promise.resolve([]);
|
||||
};
|
||||
ThreadManager.prototype.setup = function (wasmModule, wasmMemory) {
|
||||
this.wasmModule = wasmModule;
|
||||
this.wasmMemory = wasmMemory;
|
||||
};
|
||||
ThreadManager.prototype.markId = function (worker) {
|
||||
if (worker.__emnapi_tid)
|
||||
return worker.__emnapi_tid;
|
||||
var tid = nextWorkerID + 43;
|
||||
nextWorkerID = (nextWorkerID + 1) % (WASI_THREADS_MAX_TID - 42);
|
||||
this.pthreads[tid] = worker;
|
||||
worker.__emnapi_tid = tid;
|
||||
return tid;
|
||||
};
|
||||
ThreadManager.prototype.returnWorkerToPool = function (worker) {
|
||||
var tid = worker.__emnapi_tid;
|
||||
if (tid !== undefined) {
|
||||
delete this.pthreads[tid];
|
||||
}
|
||||
this.unusedWorkers.push(worker);
|
||||
this.runningWorkers.splice(this.runningWorkers.indexOf(worker), 1);
|
||||
delete worker.__emnapi_tid;
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
worker.unref();
|
||||
}
|
||||
};
|
||||
ThreadManager.prototype.loadWasmModuleToWorker = function (worker, sab) {
|
||||
var _this_1 = this;
|
||||
if (worker.whenLoaded)
|
||||
return worker.whenLoaded;
|
||||
var err = this.printErr;
|
||||
var beforeLoad = this._beforeLoad;
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
var _this = this;
|
||||
worker.whenLoaded = new Promise(function (resolve, reject) {
|
||||
var handleError = function (e) {
|
||||
var message = 'worker sent an error!';
|
||||
if (worker.__emnapi_tid !== undefined) {
|
||||
message = 'worker (tid = ' + worker.__emnapi_tid + ') sent an error!';
|
||||
}
|
||||
if ('message' in e) {
|
||||
err(message + ' ' + e.message);
|
||||
if (e.message.indexOf('RuntimeError') !== -1 || e.message.indexOf('unreachable') !== -1) {
|
||||
try {
|
||||
_this.terminateAllThreads();
|
||||
}
|
||||
catch (_) { }
|
||||
}
|
||||
}
|
||||
else {
|
||||
err(message);
|
||||
}
|
||||
reject(e);
|
||||
throw e;
|
||||
};
|
||||
var handleMessage = function (data) {
|
||||
if (data.__emnapi__) {
|
||||
var type = data.__emnapi__.type;
|
||||
var payload = data.__emnapi__.payload;
|
||||
if (type === 'loaded') {
|
||||
worker.loaded = true;
|
||||
if (ENVIRONMENT_IS_NODE && !worker.__emnapi_tid) {
|
||||
worker.unref();
|
||||
}
|
||||
resolve(worker);
|
||||
// if (payload.err) {
|
||||
// err('failed to load in child thread: ' + (payload.err.message || payload.err))
|
||||
// }
|
||||
}
|
||||
else if (type === 'cleanup-thread') {
|
||||
if (payload.tid in _this_1.pthreads) {
|
||||
_this_1.cleanThread(worker, payload.tid);
|
||||
}
|
||||
}
|
||||
else if (type === 'spawn-thread') {
|
||||
_this_1.threadSpawn(payload.startArg, payload.errorOrTid);
|
||||
}
|
||||
else if (type === 'terminate-all-threads') {
|
||||
_this_1.terminateAllThreads();
|
||||
}
|
||||
}
|
||||
};
|
||||
worker.onmessage = function (e) {
|
||||
handleMessage(e.data);
|
||||
_this_1.fireMessageEvent(worker, e);
|
||||
};
|
||||
worker.onerror = handleError;
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
worker.on('message', function (data) {
|
||||
var _a, _b;
|
||||
(_b = (_a = worker).onmessage) === null || _b === void 0 ? void 0 : _b.call(_a, {
|
||||
data: data
|
||||
});
|
||||
});
|
||||
worker.on('error', function (e) {
|
||||
var _a, _b;
|
||||
(_b = (_a = worker).onerror) === null || _b === void 0 ? void 0 : _b.call(_a, e);
|
||||
});
|
||||
worker.on('detachedExit', function () { });
|
||||
}
|
||||
if (typeof beforeLoad === 'function') {
|
||||
beforeLoad(worker);
|
||||
}
|
||||
try {
|
||||
worker.postMessage(createMessage('load', {
|
||||
wasmModule: _this_1.wasmModule,
|
||||
wasmMemory: _this_1.wasmMemory,
|
||||
sab: sab
|
||||
}));
|
||||
}
|
||||
catch (err) {
|
||||
checkSharedWasmMemory(_this_1.wasmMemory);
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
return worker.whenLoaded;
|
||||
};
|
||||
ThreadManager.prototype.allocateUnusedWorker = function () {
|
||||
var _onCreateWorker = this._onCreateWorker;
|
||||
if (typeof _onCreateWorker !== 'function') {
|
||||
throw new TypeError('`options.onCreateWorker` is not provided');
|
||||
}
|
||||
var worker = _onCreateWorker({ type: 'thread', name: 'emnapi-pthread' });
|
||||
this.unusedWorkers.push(worker);
|
||||
return worker;
|
||||
};
|
||||
ThreadManager.prototype.getNewWorker = function (sab) {
|
||||
if (this._reuseWorker) {
|
||||
if (this.unusedWorkers.length === 0) {
|
||||
if (this._reuseWorker.strict) {
|
||||
if (!ENVIRONMENT_IS_NODE) {
|
||||
var err = this.printErr;
|
||||
err('Tried to spawn a new thread, but the thread pool is exhausted.\n' +
|
||||
'This might result in a deadlock unless some threads eventually exit or the code explicitly breaks out to the event loop.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
var worker_1 = this.allocateUnusedWorker();
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.loadWasmModuleToWorker(worker_1, sab);
|
||||
}
|
||||
return this.unusedWorkers.pop();
|
||||
}
|
||||
var worker = this.allocateUnusedWorker();
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.loadWasmModuleToWorker(worker, sab);
|
||||
return this.unusedWorkers.pop();
|
||||
};
|
||||
ThreadManager.prototype.cleanThread = function (worker, tid, force) {
|
||||
if (!force && this._reuseWorker) {
|
||||
this.returnWorkerToPool(worker);
|
||||
}
|
||||
else {
|
||||
delete this.pthreads[tid];
|
||||
var index = this.runningWorkers.indexOf(worker);
|
||||
if (index !== -1) {
|
||||
this.runningWorkers.splice(index, 1);
|
||||
}
|
||||
this.terminateWorker(worker);
|
||||
delete worker.__emnapi_tid;
|
||||
}
|
||||
};
|
||||
ThreadManager.prototype.terminateWorker = function (worker) {
|
||||
var _this_1 = this;
|
||||
var _a;
|
||||
var tid = worker.__emnapi_tid;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
worker.terminate();
|
||||
(_a = this.messageEvents.get(worker)) === null || _a === void 0 ? void 0 : _a.clear();
|
||||
this.messageEvents.delete(worker);
|
||||
worker.onmessage = function (e) {
|
||||
if (e.data.__emnapi__) {
|
||||
var err = _this_1.printErr;
|
||||
err('received "' + e.data.__emnapi__.type + '" command from terminated worker: ' + tid);
|
||||
}
|
||||
};
|
||||
};
|
||||
ThreadManager.prototype.terminateAllThreads = function () {
|
||||
for (var i = 0; i < this.runningWorkers.length; ++i) {
|
||||
this.terminateWorker(this.runningWorkers[i]);
|
||||
}
|
||||
for (var i = 0; i < this.unusedWorkers.length; ++i) {
|
||||
this.terminateWorker(this.unusedWorkers[i]);
|
||||
}
|
||||
this.unusedWorkers = [];
|
||||
this.runningWorkers = [];
|
||||
this.pthreads = Object.create(null);
|
||||
this.preparePool();
|
||||
};
|
||||
ThreadManager.prototype.addMessageEventListener = function (worker, onMessage) {
|
||||
var listeners = this.messageEvents.get(worker);
|
||||
if (!listeners) {
|
||||
listeners = new Set();
|
||||
this.messageEvents.set(worker, listeners);
|
||||
}
|
||||
listeners.add(onMessage);
|
||||
return function () {
|
||||
listeners === null || listeners === void 0 ? void 0 : listeners.delete(onMessage);
|
||||
};
|
||||
};
|
||||
ThreadManager.prototype.fireMessageEvent = function (worker, e) {
|
||||
var listeners = this.messageEvents.get(worker);
|
||||
if (!listeners)
|
||||
return;
|
||||
var err = this.printErr;
|
||||
listeners.forEach(function (listener) {
|
||||
try {
|
||||
listener(e);
|
||||
}
|
||||
catch (e) {
|
||||
err(e.stack);
|
||||
}
|
||||
});
|
||||
};
|
||||
return ThreadManager;
|
||||
}());
|
||||
|
||||
var kIsProxy = Symbol('kIsProxy');
|
||||
/** @public */
|
||||
function createInstanceProxy(instance, memory) {
|
||||
if (instance[kIsProxy])
|
||||
return instance;
|
||||
// https://github.com/nodejs/help/issues/4102
|
||||
var originalExports = instance.exports;
|
||||
var createHandler = function (target) {
|
||||
var handlers = [
|
||||
'apply',
|
||||
'construct',
|
||||
'defineProperty',
|
||||
'deleteProperty',
|
||||
'get',
|
||||
'getOwnPropertyDescriptor',
|
||||
'getPrototypeOf',
|
||||
'has',
|
||||
'isExtensible',
|
||||
'ownKeys',
|
||||
'preventExtensions',
|
||||
'set',
|
||||
'setPrototypeOf'
|
||||
];
|
||||
var handler = {};
|
||||
var _loop_1 = function (i) {
|
||||
var name_1 = handlers[i];
|
||||
handler[name_1] = function () {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
args.unshift(target);
|
||||
return Reflect[name_1].apply(Reflect, args);
|
||||
};
|
||||
};
|
||||
for (var i = 0; i < handlers.length; i++) {
|
||||
_loop_1(i);
|
||||
}
|
||||
return handler;
|
||||
};
|
||||
var handler = createHandler(originalExports);
|
||||
var _initialize = function () { };
|
||||
var _start = function () { return 0; };
|
||||
handler.get = function (_target, p, receiver) {
|
||||
var _a;
|
||||
if (p === 'memory') {
|
||||
return (_a = (typeof memory === 'function' ? memory() : memory)) !== null && _a !== void 0 ? _a : Reflect.get(originalExports, p, receiver);
|
||||
}
|
||||
if (p === '_initialize') {
|
||||
return p in originalExports ? _initialize : undefined;
|
||||
}
|
||||
if (p === '_start') {
|
||||
return p in originalExports ? _start : undefined;
|
||||
}
|
||||
return Reflect.get(originalExports, p, receiver);
|
||||
};
|
||||
handler.has = function (_target, p) {
|
||||
if (p === 'memory')
|
||||
return true;
|
||||
return Reflect.has(originalExports, p);
|
||||
};
|
||||
var exportsProxy = new Proxy(Object.create(null), handler);
|
||||
return new Proxy(instance, {
|
||||
get: function (target, p, receiver) {
|
||||
if (p === 'exports') {
|
||||
return exportsProxy;
|
||||
}
|
||||
if (p === kIsProxy) {
|
||||
return true;
|
||||
}
|
||||
return Reflect.get(target, p, receiver);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var patchedWasiInstances = new WeakMap();
|
||||
/** @public */
|
||||
var WASIThreads = /*#__PURE__*/ (function () {
|
||||
function WASIThreads(options) {
|
||||
var _this_1 = this;
|
||||
if (!options) {
|
||||
throw new TypeError('WASIThreads(): options is not provided');
|
||||
}
|
||||
if (!options.wasi) {
|
||||
throw new TypeError('WASIThreads(): options.wasi is not provided');
|
||||
}
|
||||
patchedWasiInstances.set(this, new WeakSet());
|
||||
var wasi = options.wasi;
|
||||
patchWasiInstance(this, wasi);
|
||||
this.wasi = wasi;
|
||||
if ('childThread' in options) {
|
||||
this.childThread = Boolean(options.childThread);
|
||||
}
|
||||
else {
|
||||
this.childThread = false;
|
||||
}
|
||||
this.PThread = undefined;
|
||||
if ('threadManager' in options) {
|
||||
if (typeof options.threadManager === 'function') {
|
||||
this.PThread = options.threadManager();
|
||||
}
|
||||
else {
|
||||
this.PThread = options.threadManager;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!this.childThread) {
|
||||
this.PThread = new ThreadManager(options);
|
||||
this.PThread.init();
|
||||
}
|
||||
}
|
||||
var waitThreadStart = false;
|
||||
if ('waitThreadStart' in options) {
|
||||
waitThreadStart = typeof options.waitThreadStart === 'number' ? options.waitThreadStart : Boolean(options.waitThreadStart);
|
||||
}
|
||||
var postMessage = getPostMessage(options);
|
||||
if (this.childThread && typeof postMessage !== 'function') {
|
||||
throw new TypeError('options.postMessage is not a function');
|
||||
}
|
||||
this.postMessage = postMessage;
|
||||
var wasm64 = Boolean(options.wasm64);
|
||||
var threadSpawn = function (startArg, errorOrTid) {
|
||||
var _a;
|
||||
var EAGAIN = 6;
|
||||
var isNewABI = errorOrTid !== undefined;
|
||||
try {
|
||||
checkSharedWasmMemory(_this_1.wasmMemory);
|
||||
}
|
||||
catch (err) {
|
||||
(_a = _this_1.PThread) === null || _a === void 0 ? void 0 : _a.printErr(err.stack);
|
||||
if (isNewABI) {
|
||||
var struct_1 = new Int32Array(_this_1.wasmMemory.buffer, errorOrTid, 2);
|
||||
Atomics.store(struct_1, 0, 1);
|
||||
Atomics.store(struct_1, 1, EAGAIN);
|
||||
Atomics.notify(struct_1, 1);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
if (!isNewABI) {
|
||||
var malloc = _this_1.wasmInstance.exports.malloc;
|
||||
errorOrTid = wasm64 ? Number(malloc(BigInt(8))) : (malloc(8) >>> 0);
|
||||
if (!errorOrTid) {
|
||||
return -48; /* ENOMEM */
|
||||
}
|
||||
}
|
||||
var _free = _this_1.wasmInstance.exports.free;
|
||||
var free = wasm64 ? function (ptr) { _free(BigInt(ptr)); } : _free;
|
||||
var struct = new Int32Array(_this_1.wasmMemory.buffer, errorOrTid, 2);
|
||||
Atomics.store(struct, 0, 0);
|
||||
Atomics.store(struct, 1, 0);
|
||||
if (_this_1.childThread) {
|
||||
postMessage(createMessage('spawn-thread', {
|
||||
startArg: startArg,
|
||||
errorOrTid: errorOrTid
|
||||
}));
|
||||
Atomics.wait(struct, 1, 0);
|
||||
var isError = Atomics.load(struct, 0);
|
||||
var result = Atomics.load(struct, 1);
|
||||
if (isNewABI) {
|
||||
return isError;
|
||||
}
|
||||
free(errorOrTid);
|
||||
return isError ? -result : result;
|
||||
}
|
||||
var shouldWait = waitThreadStart || (waitThreadStart === 0);
|
||||
var sab;
|
||||
if (shouldWait) {
|
||||
sab = new Int32Array(new SharedArrayBuffer(16 + 8192));
|
||||
Atomics.store(sab, 0, 0);
|
||||
}
|
||||
var worker;
|
||||
var tid;
|
||||
var PThread = _this_1.PThread;
|
||||
try {
|
||||
worker = PThread.getNewWorker(sab);
|
||||
if (!worker) {
|
||||
throw new Error('failed to get new worker');
|
||||
}
|
||||
tid = PThread.markId(worker);
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
worker.unref();
|
||||
}
|
||||
worker.postMessage(createMessage('start', {
|
||||
tid: tid,
|
||||
arg: startArg,
|
||||
sab: sab
|
||||
}));
|
||||
if (shouldWait) {
|
||||
if (typeof waitThreadStart === 'number') {
|
||||
var waitResult = Atomics.wait(sab, 0, 0, waitThreadStart);
|
||||
if (waitResult === 'timed-out') {
|
||||
try {
|
||||
PThread.cleanThread(worker, tid, true);
|
||||
}
|
||||
catch (_) { }
|
||||
throw new Error('Spawning thread timed out. Please check if the worker is created successfully and if message is handled properly in the worker.');
|
||||
}
|
||||
}
|
||||
else {
|
||||
Atomics.wait(sab, 0, 0);
|
||||
}
|
||||
var r = Atomics.load(sab, 0);
|
||||
if (r > 1) {
|
||||
try {
|
||||
PThread.cleanThread(worker, tid, true);
|
||||
}
|
||||
catch (_) { }
|
||||
throw deserizeErrorFromBuffer(sab.buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
Atomics.store(struct, 0, 1);
|
||||
Atomics.store(struct, 1, EAGAIN);
|
||||
Atomics.notify(struct, 1);
|
||||
PThread === null || PThread === void 0 ? void 0 : PThread.printErr(e.stack);
|
||||
if (isNewABI) {
|
||||
return 1;
|
||||
}
|
||||
free(errorOrTid);
|
||||
return -EAGAIN;
|
||||
}
|
||||
Atomics.store(struct, 0, 0);
|
||||
Atomics.store(struct, 1, tid);
|
||||
Atomics.notify(struct, 1);
|
||||
PThread.runningWorkers.push(worker);
|
||||
if (!shouldWait) {
|
||||
worker.whenLoaded.catch(function (err) {
|
||||
delete worker.whenLoaded;
|
||||
PThread.cleanThread(worker, tid, true);
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
if (isNewABI) {
|
||||
return 0;
|
||||
}
|
||||
free(errorOrTid);
|
||||
return tid;
|
||||
};
|
||||
this.threadSpawn = threadSpawn;
|
||||
if (this.PThread) {
|
||||
this.PThread.threadSpawn = threadSpawn;
|
||||
}
|
||||
}
|
||||
WASIThreads.prototype.getImportObject = function () {
|
||||
return {
|
||||
wasi: {
|
||||
'thread-spawn': this.threadSpawn
|
||||
}
|
||||
};
|
||||
};
|
||||
WASIThreads.prototype.setup = function (wasmInstance, wasmModule, wasmMemory) {
|
||||
wasmMemory !== null && wasmMemory !== void 0 ? wasmMemory : (wasmMemory = wasmInstance.exports.memory);
|
||||
this.wasmInstance = wasmInstance;
|
||||
this.wasmMemory = wasmMemory;
|
||||
if (this.PThread) {
|
||||
this.PThread.setup(wasmModule, wasmMemory);
|
||||
}
|
||||
};
|
||||
WASIThreads.prototype.preloadWorkers = function () {
|
||||
if (this.PThread) {
|
||||
return this.PThread.preloadWorkers();
|
||||
}
|
||||
return Promise.resolve([]);
|
||||
};
|
||||
/**
|
||||
* It's ok to call this method to a WASI command module.
|
||||
*
|
||||
* in child thread, must call this method instead of {@link WASIThreads.start} even if it's a WASI command module
|
||||
*
|
||||
* @returns A proxied WebAssembly instance if in child thread, other wise the original instance
|
||||
*/
|
||||
WASIThreads.prototype.initialize = function (instance, module, memory) {
|
||||
var exports$1 = instance.exports;
|
||||
memory !== null && memory !== void 0 ? memory : (memory = exports$1.memory);
|
||||
if (this.childThread) {
|
||||
instance = createInstanceProxy(instance, memory);
|
||||
}
|
||||
this.setup(instance, module, memory);
|
||||
var wasi = this.wasi;
|
||||
if (('_start' in exports$1) && (typeof exports$1._start === 'function')) {
|
||||
if (this.childThread) {
|
||||
wasi.start(instance);
|
||||
try {
|
||||
var kStarted = getWasiSymbol(wasi, 'kStarted');
|
||||
wasi[kStarted] = false;
|
||||
}
|
||||
catch (_) { }
|
||||
}
|
||||
else {
|
||||
setupInstance(wasi, instance);
|
||||
}
|
||||
}
|
||||
else {
|
||||
wasi.initialize(instance);
|
||||
}
|
||||
return instance;
|
||||
};
|
||||
/**
|
||||
* Equivalent to calling {@link WASIThreads.initialize} and then calling {@link WASIInstance.start}
|
||||
* ```js
|
||||
* this.initialize(instance, module, memory)
|
||||
* this.wasi.start(instance)
|
||||
* ```
|
||||
*/
|
||||
WASIThreads.prototype.start = function (instance, module, memory) {
|
||||
var exports$1 = instance.exports;
|
||||
memory !== null && memory !== void 0 ? memory : (memory = exports$1.memory);
|
||||
if (this.childThread) {
|
||||
instance = createInstanceProxy(instance, memory);
|
||||
}
|
||||
this.setup(instance, module, memory);
|
||||
var exitCode = this.wasi.start(instance);
|
||||
return { exitCode: exitCode, instance: instance };
|
||||
};
|
||||
WASIThreads.prototype.terminateAllThreads = function () {
|
||||
var _a;
|
||||
if (!this.childThread) {
|
||||
(_a = this.PThread) === null || _a === void 0 ? void 0 : _a.terminateAllThreads();
|
||||
}
|
||||
else {
|
||||
this.postMessage(createMessage('terminate-all-threads', {}));
|
||||
}
|
||||
};
|
||||
return WASIThreads;
|
||||
}());
|
||||
function patchWasiInstance(wasiThreads, wasi) {
|
||||
var patched = patchedWasiInstances.get(wasiThreads);
|
||||
if (patched.has(wasi)) {
|
||||
return;
|
||||
}
|
||||
var _this = wasiThreads;
|
||||
var wasiImport = wasi.wasiImport;
|
||||
if (wasiImport) {
|
||||
var proc_exit_1 = wasiImport.proc_exit;
|
||||
wasiImport.proc_exit = function (code) {
|
||||
_this.terminateAllThreads();
|
||||
return proc_exit_1.call(this, code);
|
||||
};
|
||||
}
|
||||
if (!_this.childThread) {
|
||||
var start_1 = wasi.start;
|
||||
if (typeof start_1 === 'function') {
|
||||
wasi.start = function (instance) {
|
||||
try {
|
||||
return start_1.call(this, instance);
|
||||
}
|
||||
catch (err) {
|
||||
if (isTrapError(err)) {
|
||||
_this.terminateAllThreads();
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
patched.add(wasi);
|
||||
}
|
||||
function getWasiSymbol(wasi, description) {
|
||||
var symbols = Object.getOwnPropertySymbols(wasi);
|
||||
var selectDescription = function (description) { return function (s) {
|
||||
if (s.description) {
|
||||
return s.description === description;
|
||||
}
|
||||
return s.toString() === "Symbol(".concat(description, ")");
|
||||
}; };
|
||||
if (Array.isArray(description)) {
|
||||
return description.map(function (d) { return symbols.filter(selectDescription(d))[0]; });
|
||||
}
|
||||
return symbols.filter(selectDescription(description))[0];
|
||||
}
|
||||
function setupInstance(wasi, instance) {
|
||||
var _a = getWasiSymbol(wasi, ['kInstance', 'kSetMemory']), kInstance = _a[0], kSetMemory = _a[1];
|
||||
wasi[kInstance] = instance;
|
||||
wasi[kSetMemory](instance.exports.memory);
|
||||
}
|
||||
|
||||
/** @public */
|
||||
var ThreadMessageHandler = /*#__PURE__*/ (function () {
|
||||
function ThreadMessageHandler(options) {
|
||||
var postMsg = getPostMessage(options);
|
||||
if (typeof postMsg !== 'function') {
|
||||
throw new TypeError('options.postMessage is not a function');
|
||||
}
|
||||
this.postMessage = postMsg;
|
||||
this.onLoad = options === null || options === void 0 ? void 0 : options.onLoad;
|
||||
this.onError = typeof (options === null || options === void 0 ? void 0 : options.onError) === 'function' ? options.onError : function (_type, err) { throw err; };
|
||||
this.instance = undefined;
|
||||
// this.module = undefined
|
||||
this.messagesBeforeLoad = [];
|
||||
}
|
||||
/** @virtual */
|
||||
ThreadMessageHandler.prototype.instantiate = function (data) {
|
||||
if (typeof this.onLoad === 'function') {
|
||||
return this.onLoad(data);
|
||||
}
|
||||
throw new Error('ThreadMessageHandler.prototype.instantiate is not implemented');
|
||||
};
|
||||
/** @virtual */
|
||||
ThreadMessageHandler.prototype.handle = function (e) {
|
||||
var _this = this;
|
||||
var _a;
|
||||
if ((_a = e === null || e === void 0 ? void 0 : e.data) === null || _a === void 0 ? void 0 : _a.__emnapi__) {
|
||||
var type = e.data.__emnapi__.type;
|
||||
var payload_1 = e.data.__emnapi__.payload;
|
||||
try {
|
||||
if (type === 'load') {
|
||||
this._load(payload_1);
|
||||
}
|
||||
else if (type === 'start') {
|
||||
this.handleAfterLoad(e, function () {
|
||||
_this._start(payload_1);
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
this.onError(err, type);
|
||||
}
|
||||
}
|
||||
};
|
||||
ThreadMessageHandler.prototype._load = function (payload) {
|
||||
var _this = this;
|
||||
if (this.instance !== undefined)
|
||||
return;
|
||||
var source;
|
||||
try {
|
||||
source = this.instantiate(payload);
|
||||
}
|
||||
catch (err) {
|
||||
this._loaded(err, null, payload);
|
||||
return;
|
||||
}
|
||||
var then = source && 'then' in source ? source.then : undefined;
|
||||
if (typeof then === 'function') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
then.call(source, function (source) { _this._loaded(null, source, payload); }, function (err) { _this._loaded(err, null, payload); });
|
||||
}
|
||||
else {
|
||||
this._loaded(null, source, payload);
|
||||
}
|
||||
};
|
||||
ThreadMessageHandler.prototype._start = function (payload) {
|
||||
var wasi_thread_start = this.instance.exports.wasi_thread_start;
|
||||
if (typeof wasi_thread_start !== 'function') {
|
||||
var err = new TypeError('wasi_thread_start is not exported');
|
||||
notifyPthreadCreateResult(payload.sab, 2, err);
|
||||
throw err;
|
||||
}
|
||||
var postMessage = this.postMessage;
|
||||
var tid = payload.tid;
|
||||
var startArg = payload.arg;
|
||||
notifyPthreadCreateResult(payload.sab, 1);
|
||||
try {
|
||||
wasi_thread_start(tid, startArg);
|
||||
}
|
||||
catch (err) {
|
||||
if (err !== 'unwind') {
|
||||
throw err;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
postMessage(createMessage('cleanup-thread', { tid: tid }));
|
||||
};
|
||||
ThreadMessageHandler.prototype._loaded = function (err, source, payload) {
|
||||
if (err) {
|
||||
notifyPthreadCreateResult(payload.sab, 2, err);
|
||||
throw err;
|
||||
}
|
||||
if (source == null) {
|
||||
var err_1 = new TypeError('onLoad should return an object');
|
||||
notifyPthreadCreateResult(payload.sab, 2, err_1);
|
||||
throw err_1;
|
||||
}
|
||||
var instance = source.instance;
|
||||
if (!instance) {
|
||||
var err_2 = new TypeError('onLoad should return an object which includes "instance"');
|
||||
notifyPthreadCreateResult(payload.sab, 2, err_2);
|
||||
throw err_2;
|
||||
}
|
||||
this.instance = instance;
|
||||
var postMessage = this.postMessage;
|
||||
postMessage(createMessage('loaded', {}));
|
||||
var messages = this.messagesBeforeLoad;
|
||||
this.messagesBeforeLoad = [];
|
||||
for (var i = 0; i < messages.length; i++) {
|
||||
var data = messages[i];
|
||||
this.handle({ data: data });
|
||||
}
|
||||
};
|
||||
ThreadMessageHandler.prototype.handleAfterLoad = function (e, f) {
|
||||
if (this.instance !== undefined) {
|
||||
f.call(this, e);
|
||||
}
|
||||
else {
|
||||
this.messagesBeforeLoad.push(e.data);
|
||||
}
|
||||
};
|
||||
return ThreadMessageHandler;
|
||||
}());
|
||||
function notifyPthreadCreateResult(sab, result, error) {
|
||||
if (sab) {
|
||||
serizeErrorToBuffer(sab.buffer, result, error);
|
||||
Atomics.notify(sab, 0);
|
||||
}
|
||||
}
|
||||
|
||||
exports.ThreadManager = ThreadManager;
|
||||
exports.ThreadMessageHandler = ThreadMessageHandler;
|
||||
exports.WASIThreads = WASIThreads;
|
||||
exports.createInstanceProxy = createInstanceProxy;
|
||||
exports.isSharedArrayBuffer = isSharedArrayBuffer;
|
||||
exports.isTrapError = isTrapError;
|
||||
|
||||
}));
|
||||
+272
@@ -0,0 +1,272 @@
|
||||
/// <reference types="node" />
|
||||
|
||||
import type { Worker as Worker_2 } from 'worker_threads';
|
||||
|
||||
/** @public */
|
||||
export declare interface BaseOptions {
|
||||
wasi: WASIInstance;
|
||||
version?: 'preview1';
|
||||
wasm64?: boolean;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ChildThreadOptions extends BaseOptions {
|
||||
childThread: true;
|
||||
postMessage?: (data: any) => void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CleanupThreadPayload {
|
||||
tid: number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CommandInfo<T extends CommandType> {
|
||||
type: T;
|
||||
payload: CommandPayloadMap[T];
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface CommandPayloadMap {
|
||||
load: LoadPayload;
|
||||
loaded: LoadedPayload;
|
||||
start: StartPayload;
|
||||
'cleanup-thread': CleanupThreadPayload;
|
||||
'terminate-all-threads': TerminateAllThreadsPayload;
|
||||
'spawn-thread': SpawnThreadPayload;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type CommandType = keyof CommandPayloadMap;
|
||||
|
||||
/** @public */
|
||||
export declare function createInstanceProxy(instance: WebAssembly.Instance, memory?: WebAssembly.Memory | (() => WebAssembly.Memory)): WebAssembly.Instance;
|
||||
|
||||
/** @public */
|
||||
export declare function isSharedArrayBuffer(value: any): value is SharedArrayBuffer;
|
||||
|
||||
/** @public */
|
||||
export declare function isTrapError(e: Error): e is WebAssembly.RuntimeError;
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadedPayload {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface LoadPayload {
|
||||
wasmModule: WebAssembly.Module;
|
||||
wasmMemory: WebAssembly.Memory;
|
||||
sab?: Int32Array;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadBaseOptions extends BaseOptions {
|
||||
waitThreadStart?: boolean | number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type MainThreadOptions = MainThreadOptionsWithThreadManager | MainThreadOptionsCreateThreadManager;
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadOptionsCreateThreadManager extends MainThreadBaseOptions, ThreadManagerOptionsMain {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MainThreadOptionsWithThreadManager extends MainThreadBaseOptions {
|
||||
threadManager?: ThreadManager | (() => ThreadManager);
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface MessageEventData<T extends CommandType> {
|
||||
__emnapi__: CommandInfo<T>;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ReuseWorkerOptions {
|
||||
/**
|
||||
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size | PTHREAD_POOL_SIZE}
|
||||
*/
|
||||
size: number;
|
||||
/**
|
||||
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size-strict | PTHREAD_POOL_SIZE_STRICT}
|
||||
*/
|
||||
strict?: boolean;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface SpawnThreadPayload {
|
||||
startArg: number;
|
||||
errorOrTid: number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface StartPayload {
|
||||
tid: number;
|
||||
arg: number;
|
||||
sab?: Int32Array;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface StartResult {
|
||||
exitCode: number;
|
||||
instance: WebAssembly.Instance;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface TerminateAllThreadsPayload {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class ThreadManager {
|
||||
unusedWorkers: WorkerLike[];
|
||||
runningWorkers: WorkerLike[];
|
||||
pthreads: Record<number, WorkerLike>;
|
||||
get nextWorkerID(): number;
|
||||
wasmModule: WebAssembly.Module | null;
|
||||
wasmMemory: WebAssembly.Memory | null;
|
||||
private readonly messageEvents;
|
||||
private readonly _childThread;
|
||||
private readonly _onCreateWorker;
|
||||
private readonly _reuseWorker;
|
||||
private readonly _beforeLoad?;
|
||||
/* Excluded from this release type: printErr */
|
||||
threadSpawn?: ((startArg: number, errorOrTid?: number) => number);
|
||||
constructor(options: ThreadManagerOptions);
|
||||
init(): void;
|
||||
initMainThread(): void;
|
||||
private preparePool;
|
||||
shouldPreloadWorkers(): boolean;
|
||||
loadWasmModuleToAllWorkers(): Promise<WorkerLike[]>;
|
||||
preloadWorkers(): Promise<WorkerLike[]>;
|
||||
setup(wasmModule: WebAssembly.Module, wasmMemory: WebAssembly.Memory): void;
|
||||
markId(worker: WorkerLike): number;
|
||||
returnWorkerToPool(worker: WorkerLike): void;
|
||||
loadWasmModuleToWorker(worker: WorkerLike, sab?: Int32Array): Promise<WorkerLike>;
|
||||
allocateUnusedWorker(): WorkerLike;
|
||||
getNewWorker(sab?: Int32Array): WorkerLike | undefined;
|
||||
cleanThread(worker: WorkerLike, tid: number, force?: boolean): void;
|
||||
terminateWorker(worker: WorkerLike): void;
|
||||
terminateAllThreads(): void;
|
||||
addMessageEventListener(worker: WorkerLike, onMessage: (e: WorkerMessageEvent) => void): () => void;
|
||||
fireMessageEvent(worker: WorkerLike, e: WorkerMessageEvent): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type ThreadManagerOptions = ThreadManagerOptionsMain | ThreadManagerOptionsChild;
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsBase {
|
||||
printErr?: (message: string) => void;
|
||||
threadSpawn?: (startArg: number, errorOrTid?: number) => number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsChild extends ThreadManagerOptionsBase {
|
||||
childThread: true;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadManagerOptionsMain extends ThreadManagerOptionsBase {
|
||||
beforeLoad?: (worker: WorkerLike) => any;
|
||||
reuseWorker?: boolean | number | ReuseWorkerOptions;
|
||||
onCreateWorker: WorkerFactory;
|
||||
childThread?: false;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class ThreadMessageHandler {
|
||||
protected instance: WebAssembly.Instance | undefined;
|
||||
private messagesBeforeLoad;
|
||||
protected postMessage: (message: any) => void;
|
||||
protected onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
protected onError: (error: Error, type: WorkerMessageType) => void;
|
||||
constructor(options?: ThreadMessageHandlerOptions);
|
||||
/** @virtual */
|
||||
instantiate(data: LoadPayload): WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
/** @virtual */
|
||||
handle(e: WorkerMessageEvent<MessageEventData<WorkerMessageType>>): void;
|
||||
private _load;
|
||||
private _start;
|
||||
protected _loaded(err: Error | null, source: WebAssembly.WebAssemblyInstantiatedSource | null, payload: LoadPayload): void;
|
||||
protected handleAfterLoad<E extends WorkerMessageEvent>(e: E, f: (e: E) => void): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface ThreadMessageHandlerOptions {
|
||||
onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
|
||||
onError?: (error: Error, type: WorkerMessageType) => void;
|
||||
postMessage?: (message: any) => void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface WASIInstance {
|
||||
readonly wasiImport?: Record<string, any>;
|
||||
initialize(instance: object): void;
|
||||
start(instance: object): number;
|
||||
getImportObject?(): any;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare class WASIThreads {
|
||||
PThread: ThreadManager | undefined;
|
||||
private wasmMemory;
|
||||
private wasmInstance;
|
||||
private readonly threadSpawn;
|
||||
readonly childThread: boolean;
|
||||
private readonly postMessage;
|
||||
readonly wasi: WASIInstance;
|
||||
constructor(options: WASIThreadsOptions);
|
||||
getImportObject(): {
|
||||
wasi: WASIThreadsImports;
|
||||
};
|
||||
setup(wasmInstance: WebAssembly.Instance, wasmModule: WebAssembly.Module, wasmMemory?: WebAssembly.Memory): void;
|
||||
preloadWorkers(): Promise<WorkerLike[]>;
|
||||
/**
|
||||
* It's ok to call this method to a WASI command module.
|
||||
*
|
||||
* in child thread, must call this method instead of {@link WASIThreads.start} even if it's a WASI command module
|
||||
*
|
||||
* @returns A proxied WebAssembly instance if in child thread, other wise the original instance
|
||||
*/
|
||||
initialize(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): WebAssembly.Instance;
|
||||
/**
|
||||
* Equivalent to calling {@link WASIThreads.initialize} and then calling {@link WASIInstance.start}
|
||||
* ```js
|
||||
* this.initialize(instance, module, memory)
|
||||
* this.wasi.start(instance)
|
||||
* ```
|
||||
*/
|
||||
start(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): StartResult;
|
||||
terminateAllThreads(): void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface WASIThreadsImports {
|
||||
'thread-spawn': (startArg: number, errorOrTid?: number) => number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type WASIThreadsOptions = MainThreadOptions | ChildThreadOptions;
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerFactory = (ctx: {
|
||||
type: string;
|
||||
name: string;
|
||||
}) => WorkerLike;
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerLike = (Worker | Worker_2) & {
|
||||
whenLoaded?: Promise<WorkerLike>;
|
||||
loaded?: boolean;
|
||||
__emnapi_tid?: number;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export declare interface WorkerMessageEvent<T = any> {
|
||||
data: T;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare type WorkerMessageType = 'load' | 'start';
|
||||
|
||||
export { }
|
||||
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+889
@@ -0,0 +1,889 @@
|
||||
const _WebAssembly = typeof WebAssembly !== 'undefined'
|
||||
? WebAssembly
|
||||
: typeof WXWebAssembly !== 'undefined'
|
||||
? WXWebAssembly
|
||||
: undefined;
|
||||
const ENVIRONMENT_IS_NODE = typeof process === 'object' && process !== null &&
|
||||
typeof process.versions === 'object' && process.versions !== null &&
|
||||
typeof process.versions.node === 'string';
|
||||
function getPostMessage(options) {
|
||||
return typeof (options === null || options === void 0 ? void 0 : options.postMessage) === 'function'
|
||||
? options.postMessage
|
||||
: typeof postMessage === 'function'
|
||||
? postMessage
|
||||
: undefined;
|
||||
}
|
||||
function serizeErrorToBuffer(sab, code, error) {
|
||||
const i32array = new Int32Array(sab);
|
||||
Atomics.store(i32array, 0, code);
|
||||
if (code > 1 && error) {
|
||||
const name = error.name;
|
||||
const message = error.message;
|
||||
const stack = error.stack;
|
||||
const nameBuffer = new TextEncoder().encode(name);
|
||||
const messageBuffer = new TextEncoder().encode(message);
|
||||
const stackBuffer = new TextEncoder().encode(stack);
|
||||
Atomics.store(i32array, 1, nameBuffer.length);
|
||||
Atomics.store(i32array, 2, messageBuffer.length);
|
||||
Atomics.store(i32array, 3, stackBuffer.length);
|
||||
const buffer = new Uint8Array(sab);
|
||||
buffer.set(nameBuffer, 16);
|
||||
buffer.set(messageBuffer, 16 + nameBuffer.length);
|
||||
buffer.set(stackBuffer, 16 + nameBuffer.length + messageBuffer.length);
|
||||
}
|
||||
}
|
||||
function deserizeErrorFromBuffer(sab) {
|
||||
var _a, _b;
|
||||
const i32array = new Int32Array(sab);
|
||||
const status = Atomics.load(i32array, 0);
|
||||
if (status <= 1) {
|
||||
return null;
|
||||
}
|
||||
const nameLength = Atomics.load(i32array, 1);
|
||||
const messageLength = Atomics.load(i32array, 2);
|
||||
const stackLength = Atomics.load(i32array, 3);
|
||||
const buffer = new Uint8Array(sab);
|
||||
const nameBuffer = buffer.slice(16, 16 + nameLength);
|
||||
const messageBuffer = buffer.slice(16 + nameLength, 16 + nameLength + messageLength);
|
||||
const stackBuffer = buffer.slice(16 + nameLength + messageLength, 16 + nameLength + messageLength + stackLength);
|
||||
const name = new TextDecoder().decode(nameBuffer);
|
||||
const message = new TextDecoder().decode(messageBuffer);
|
||||
const stack = new TextDecoder().decode(stackBuffer);
|
||||
const ErrorConstructor = (_a = globalThis[name]) !== null && _a !== void 0 ? _a : (name === 'RuntimeError' ? ((_b = _WebAssembly.RuntimeError) !== null && _b !== void 0 ? _b : Error) : Error);
|
||||
const error = new ErrorConstructor(message);
|
||||
Object.defineProperty(error, 'stack', {
|
||||
value: stack,
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
return error;
|
||||
}
|
||||
function isSharedArrayBuffer(value) {
|
||||
return ((typeof SharedArrayBuffer === 'function' && value instanceof SharedArrayBuffer) ||
|
||||
(Object.prototype.toString.call(value) === '[object SharedArrayBuffer]'));
|
||||
}
|
||||
function isTrapError(e) {
|
||||
try {
|
||||
return e instanceof _WebAssembly.RuntimeError;
|
||||
}
|
||||
catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function createMessage(type, payload) {
|
||||
return {
|
||||
__emnapi__: {
|
||||
type,
|
||||
payload
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const WASI_THREADS_MAX_TID = 0x1FFFFFFF;
|
||||
function checkSharedWasmMemory(wasmMemory) {
|
||||
if (wasmMemory) {
|
||||
if (!isSharedArrayBuffer(wasmMemory.buffer)) {
|
||||
throw new Error('Multithread features require shared wasm memory. ' +
|
||||
'Try to compile with `-matomics -mbulk-memory` and use `--import-memory --shared-memory` during linking, ' +
|
||||
'then create WebAssembly.Memory with `shared: true` option');
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (typeof SharedArrayBuffer === 'undefined') {
|
||||
throw new Error('Current environment does not support SharedArrayBuffer, threads are not available!');
|
||||
}
|
||||
}
|
||||
}
|
||||
function getReuseWorker(value) {
|
||||
var _a;
|
||||
if (typeof value === 'boolean') {
|
||||
return value ? { size: 0, strict: false } : false;
|
||||
}
|
||||
if (typeof value === 'number') {
|
||||
if (!(value >= 0)) {
|
||||
throw new RangeError('reuseWorker: size must be a non-negative integer');
|
||||
}
|
||||
return { size: value, strict: false };
|
||||
}
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
const size = (_a = Number(value.size)) !== null && _a !== void 0 ? _a : 0;
|
||||
const strict = Boolean(value.strict);
|
||||
if (!(size > 0) && strict) {
|
||||
throw new RangeError('reuseWorker: size must be set to positive integer if strict is set to true');
|
||||
}
|
||||
return { size, strict };
|
||||
}
|
||||
let nextWorkerID = 0;
|
||||
class ThreadManager {
|
||||
get nextWorkerID() { return nextWorkerID; }
|
||||
constructor(options) {
|
||||
var _a;
|
||||
this.unusedWorkers = [];
|
||||
this.runningWorkers = [];
|
||||
this.pthreads = Object.create(null);
|
||||
this.wasmModule = null;
|
||||
this.wasmMemory = null;
|
||||
this.messageEvents = new WeakMap();
|
||||
if (!options) {
|
||||
throw new TypeError('ThreadManager(): options is not provided');
|
||||
}
|
||||
if ('childThread' in options) {
|
||||
this._childThread = Boolean(options.childThread);
|
||||
}
|
||||
else {
|
||||
this._childThread = false;
|
||||
}
|
||||
if (this._childThread) {
|
||||
this._onCreateWorker = undefined;
|
||||
this._reuseWorker = false;
|
||||
this._beforeLoad = undefined;
|
||||
}
|
||||
else {
|
||||
this._onCreateWorker = options.onCreateWorker;
|
||||
this._reuseWorker = getReuseWorker(options.reuseWorker);
|
||||
this._beforeLoad = options.beforeLoad;
|
||||
}
|
||||
this.printErr = (_a = options.printErr) !== null && _a !== void 0 ? _a : console.error.bind(console);
|
||||
this.threadSpawn = options.threadSpawn;
|
||||
}
|
||||
init() {
|
||||
if (!this._childThread) {
|
||||
this.initMainThread();
|
||||
}
|
||||
}
|
||||
initMainThread() {
|
||||
this.preparePool();
|
||||
}
|
||||
preparePool() {
|
||||
if (this._reuseWorker) {
|
||||
if (this._reuseWorker.size) {
|
||||
let pthreadPoolSize = this._reuseWorker.size;
|
||||
while (pthreadPoolSize--) {
|
||||
const worker = this.allocateUnusedWorker();
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
worker.once('message', () => { });
|
||||
worker.unref();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
shouldPreloadWorkers() {
|
||||
return !this._childThread && this._reuseWorker && this._reuseWorker.size > 0;
|
||||
}
|
||||
loadWasmModuleToAllWorkers() {
|
||||
const promises = Array(this.unusedWorkers.length);
|
||||
for (let i = 0; i < this.unusedWorkers.length; ++i) {
|
||||
const worker = this.unusedWorkers[i];
|
||||
if (ENVIRONMENT_IS_NODE)
|
||||
worker.ref();
|
||||
promises[i] = this.loadWasmModuleToWorker(worker).then((w) => {
|
||||
if (ENVIRONMENT_IS_NODE)
|
||||
worker.unref();
|
||||
return w;
|
||||
}, (e) => {
|
||||
if (ENVIRONMENT_IS_NODE)
|
||||
worker.unref();
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
return Promise.all(promises).catch((err) => {
|
||||
this.terminateAllThreads();
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
preloadWorkers() {
|
||||
if (this.shouldPreloadWorkers()) {
|
||||
return this.loadWasmModuleToAllWorkers();
|
||||
}
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
setup(wasmModule, wasmMemory) {
|
||||
this.wasmModule = wasmModule;
|
||||
this.wasmMemory = wasmMemory;
|
||||
}
|
||||
markId(worker) {
|
||||
if (worker.__emnapi_tid)
|
||||
return worker.__emnapi_tid;
|
||||
const tid = nextWorkerID + 43;
|
||||
nextWorkerID = (nextWorkerID + 1) % (WASI_THREADS_MAX_TID - 42);
|
||||
this.pthreads[tid] = worker;
|
||||
worker.__emnapi_tid = tid;
|
||||
return tid;
|
||||
}
|
||||
returnWorkerToPool(worker) {
|
||||
var tid = worker.__emnapi_tid;
|
||||
if (tid !== undefined) {
|
||||
delete this.pthreads[tid];
|
||||
}
|
||||
this.unusedWorkers.push(worker);
|
||||
this.runningWorkers.splice(this.runningWorkers.indexOf(worker), 1);
|
||||
delete worker.__emnapi_tid;
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
worker.unref();
|
||||
}
|
||||
}
|
||||
loadWasmModuleToWorker(worker, sab) {
|
||||
if (worker.whenLoaded)
|
||||
return worker.whenLoaded;
|
||||
const err = this.printErr;
|
||||
const beforeLoad = this._beforeLoad;
|
||||
const _this = this;
|
||||
worker.whenLoaded = new Promise((resolve, reject) => {
|
||||
const handleError = function (e) {
|
||||
let message = 'worker sent an error!';
|
||||
if (worker.__emnapi_tid !== undefined) {
|
||||
message = 'worker (tid = ' + worker.__emnapi_tid + ') sent an error!';
|
||||
}
|
||||
if ('message' in e) {
|
||||
err(message + ' ' + e.message);
|
||||
if (e.message.indexOf('RuntimeError') !== -1 || e.message.indexOf('unreachable') !== -1) {
|
||||
try {
|
||||
_this.terminateAllThreads();
|
||||
}
|
||||
catch (_) { }
|
||||
}
|
||||
}
|
||||
else {
|
||||
err(message);
|
||||
}
|
||||
reject(e);
|
||||
throw e;
|
||||
};
|
||||
const handleMessage = (data) => {
|
||||
if (data.__emnapi__) {
|
||||
const type = data.__emnapi__.type;
|
||||
const payload = data.__emnapi__.payload;
|
||||
if (type === 'loaded') {
|
||||
worker.loaded = true;
|
||||
if (ENVIRONMENT_IS_NODE && !worker.__emnapi_tid) {
|
||||
worker.unref();
|
||||
}
|
||||
resolve(worker);
|
||||
}
|
||||
else if (type === 'cleanup-thread') {
|
||||
if (payload.tid in this.pthreads) {
|
||||
this.cleanThread(worker, payload.tid);
|
||||
}
|
||||
}
|
||||
else if (type === 'spawn-thread') {
|
||||
this.threadSpawn(payload.startArg, payload.errorOrTid);
|
||||
}
|
||||
else if (type === 'terminate-all-threads') {
|
||||
this.terminateAllThreads();
|
||||
}
|
||||
}
|
||||
};
|
||||
worker.onmessage = (e) => {
|
||||
handleMessage(e.data);
|
||||
this.fireMessageEvent(worker, e);
|
||||
};
|
||||
worker.onerror = handleError;
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
worker.on('message', function (data) {
|
||||
var _a, _b;
|
||||
(_b = (_a = worker).onmessage) === null || _b === void 0 ? void 0 : _b.call(_a, {
|
||||
data
|
||||
});
|
||||
});
|
||||
worker.on('error', function (e) {
|
||||
var _a, _b;
|
||||
(_b = (_a = worker).onerror) === null || _b === void 0 ? void 0 : _b.call(_a, e);
|
||||
});
|
||||
worker.on('detachedExit', function () { });
|
||||
}
|
||||
if (typeof beforeLoad === 'function') {
|
||||
beforeLoad(worker);
|
||||
}
|
||||
try {
|
||||
worker.postMessage(createMessage('load', {
|
||||
wasmModule: this.wasmModule,
|
||||
wasmMemory: this.wasmMemory,
|
||||
sab
|
||||
}));
|
||||
}
|
||||
catch (err) {
|
||||
checkSharedWasmMemory(this.wasmMemory);
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
return worker.whenLoaded;
|
||||
}
|
||||
allocateUnusedWorker() {
|
||||
const _onCreateWorker = this._onCreateWorker;
|
||||
if (typeof _onCreateWorker !== 'function') {
|
||||
throw new TypeError('`options.onCreateWorker` is not provided');
|
||||
}
|
||||
const worker = _onCreateWorker({ type: 'thread', name: 'emnapi-pthread' });
|
||||
this.unusedWorkers.push(worker);
|
||||
return worker;
|
||||
}
|
||||
getNewWorker(sab) {
|
||||
if (this._reuseWorker) {
|
||||
if (this.unusedWorkers.length === 0) {
|
||||
if (this._reuseWorker.strict) {
|
||||
if (!ENVIRONMENT_IS_NODE) {
|
||||
const err = this.printErr;
|
||||
err('Tried to spawn a new thread, but the thread pool is exhausted.\n' +
|
||||
'This might result in a deadlock unless some threads eventually exit or the code explicitly breaks out to the event loop.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
const worker = this.allocateUnusedWorker();
|
||||
this.loadWasmModuleToWorker(worker, sab);
|
||||
}
|
||||
return this.unusedWorkers.pop();
|
||||
}
|
||||
const worker = this.allocateUnusedWorker();
|
||||
this.loadWasmModuleToWorker(worker, sab);
|
||||
return this.unusedWorkers.pop();
|
||||
}
|
||||
cleanThread(worker, tid, force) {
|
||||
if (!force && this._reuseWorker) {
|
||||
this.returnWorkerToPool(worker);
|
||||
}
|
||||
else {
|
||||
delete this.pthreads[tid];
|
||||
const index = this.runningWorkers.indexOf(worker);
|
||||
if (index !== -1) {
|
||||
this.runningWorkers.splice(index, 1);
|
||||
}
|
||||
this.terminateWorker(worker);
|
||||
delete worker.__emnapi_tid;
|
||||
}
|
||||
}
|
||||
terminateWorker(worker) {
|
||||
var _a;
|
||||
const tid = worker.__emnapi_tid;
|
||||
worker.terminate();
|
||||
(_a = this.messageEvents.get(worker)) === null || _a === void 0 ? void 0 : _a.clear();
|
||||
this.messageEvents.delete(worker);
|
||||
worker.onmessage = (e) => {
|
||||
if (e.data.__emnapi__) {
|
||||
const err = this.printErr;
|
||||
err('received "' + e.data.__emnapi__.type + '" command from terminated worker: ' + tid);
|
||||
}
|
||||
};
|
||||
}
|
||||
terminateAllThreads() {
|
||||
for (let i = 0; i < this.runningWorkers.length; ++i) {
|
||||
this.terminateWorker(this.runningWorkers[i]);
|
||||
}
|
||||
for (let i = 0; i < this.unusedWorkers.length; ++i) {
|
||||
this.terminateWorker(this.unusedWorkers[i]);
|
||||
}
|
||||
this.unusedWorkers = [];
|
||||
this.runningWorkers = [];
|
||||
this.pthreads = Object.create(null);
|
||||
this.preparePool();
|
||||
}
|
||||
addMessageEventListener(worker, onMessage) {
|
||||
let listeners = this.messageEvents.get(worker);
|
||||
if (!listeners) {
|
||||
listeners = new Set();
|
||||
this.messageEvents.set(worker, listeners);
|
||||
}
|
||||
listeners.add(onMessage);
|
||||
return () => {
|
||||
listeners === null || listeners === void 0 ? void 0 : listeners.delete(onMessage);
|
||||
};
|
||||
}
|
||||
fireMessageEvent(worker, e) {
|
||||
const listeners = this.messageEvents.get(worker);
|
||||
if (!listeners)
|
||||
return;
|
||||
const err = this.printErr;
|
||||
listeners.forEach((listener) => {
|
||||
try {
|
||||
listener(e);
|
||||
}
|
||||
catch (e) {
|
||||
err(e.stack);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const kIsProxy = Symbol('kIsProxy');
|
||||
function createInstanceProxy(instance, memory) {
|
||||
if (instance[kIsProxy])
|
||||
return instance;
|
||||
const originalExports = instance.exports;
|
||||
const createHandler = function (target) {
|
||||
const handlers = [
|
||||
'apply',
|
||||
'construct',
|
||||
'defineProperty',
|
||||
'deleteProperty',
|
||||
'get',
|
||||
'getOwnPropertyDescriptor',
|
||||
'getPrototypeOf',
|
||||
'has',
|
||||
'isExtensible',
|
||||
'ownKeys',
|
||||
'preventExtensions',
|
||||
'set',
|
||||
'setPrototypeOf'
|
||||
];
|
||||
const handler = {};
|
||||
for (let i = 0; i < handlers.length; i++) {
|
||||
const name = handlers[i];
|
||||
handler[name] = function () {
|
||||
const args = Array.prototype.slice.call(arguments, 1);
|
||||
args.unshift(target);
|
||||
return Reflect[name].apply(Reflect, args);
|
||||
};
|
||||
}
|
||||
return handler;
|
||||
};
|
||||
const handler = createHandler(originalExports);
|
||||
const _initialize = () => { };
|
||||
const _start = () => 0;
|
||||
handler.get = function (_target, p, receiver) {
|
||||
var _a;
|
||||
if (p === 'memory') {
|
||||
return (_a = (typeof memory === 'function' ? memory() : memory)) !== null && _a !== void 0 ? _a : Reflect.get(originalExports, p, receiver);
|
||||
}
|
||||
if (p === '_initialize') {
|
||||
return p in originalExports ? _initialize : undefined;
|
||||
}
|
||||
if (p === '_start') {
|
||||
return p in originalExports ? _start : undefined;
|
||||
}
|
||||
return Reflect.get(originalExports, p, receiver);
|
||||
};
|
||||
handler.has = function (_target, p) {
|
||||
if (p === 'memory')
|
||||
return true;
|
||||
return Reflect.has(originalExports, p);
|
||||
};
|
||||
const exportsProxy = new Proxy(Object.create(null), handler);
|
||||
return new Proxy(instance, {
|
||||
get(target, p, receiver) {
|
||||
if (p === 'exports') {
|
||||
return exportsProxy;
|
||||
}
|
||||
if (p === kIsProxy) {
|
||||
return true;
|
||||
}
|
||||
return Reflect.get(target, p, receiver);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const patchedWasiInstances = new WeakMap();
|
||||
class WASIThreads {
|
||||
constructor(options) {
|
||||
if (!options) {
|
||||
throw new TypeError('WASIThreads(): options is not provided');
|
||||
}
|
||||
if (!options.wasi) {
|
||||
throw new TypeError('WASIThreads(): options.wasi is not provided');
|
||||
}
|
||||
patchedWasiInstances.set(this, new WeakSet());
|
||||
const wasi = options.wasi;
|
||||
patchWasiInstance(this, wasi);
|
||||
this.wasi = wasi;
|
||||
if ('childThread' in options) {
|
||||
this.childThread = Boolean(options.childThread);
|
||||
}
|
||||
else {
|
||||
this.childThread = false;
|
||||
}
|
||||
this.PThread = undefined;
|
||||
if ('threadManager' in options) {
|
||||
if (typeof options.threadManager === 'function') {
|
||||
this.PThread = options.threadManager();
|
||||
}
|
||||
else {
|
||||
this.PThread = options.threadManager;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!this.childThread) {
|
||||
this.PThread = new ThreadManager(options);
|
||||
this.PThread.init();
|
||||
}
|
||||
}
|
||||
let waitThreadStart = false;
|
||||
if ('waitThreadStart' in options) {
|
||||
waitThreadStart = typeof options.waitThreadStart === 'number' ? options.waitThreadStart : Boolean(options.waitThreadStart);
|
||||
}
|
||||
const postMessage = getPostMessage(options);
|
||||
if (this.childThread && typeof postMessage !== 'function') {
|
||||
throw new TypeError('options.postMessage is not a function');
|
||||
}
|
||||
this.postMessage = postMessage;
|
||||
const wasm64 = Boolean(options.wasm64);
|
||||
const threadSpawn = (startArg, errorOrTid) => {
|
||||
var _a;
|
||||
const EAGAIN = 6;
|
||||
const isNewABI = errorOrTid !== undefined;
|
||||
try {
|
||||
checkSharedWasmMemory(this.wasmMemory);
|
||||
}
|
||||
catch (err) {
|
||||
(_a = this.PThread) === null || _a === void 0 ? void 0 : _a.printErr(err.stack);
|
||||
if (isNewABI) {
|
||||
const struct = new Int32Array(this.wasmMemory.buffer, errorOrTid, 2);
|
||||
Atomics.store(struct, 0, 1);
|
||||
Atomics.store(struct, 1, EAGAIN);
|
||||
Atomics.notify(struct, 1);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
if (!isNewABI) {
|
||||
const malloc = this.wasmInstance.exports.malloc;
|
||||
errorOrTid = wasm64 ? Number(malloc(BigInt(8))) : (malloc(8) >>> 0);
|
||||
if (!errorOrTid) {
|
||||
return -48;
|
||||
}
|
||||
}
|
||||
const _free = this.wasmInstance.exports.free;
|
||||
const free = wasm64 ? (ptr) => { _free(BigInt(ptr)); } : _free;
|
||||
const struct = new Int32Array(this.wasmMemory.buffer, errorOrTid, 2);
|
||||
Atomics.store(struct, 0, 0);
|
||||
Atomics.store(struct, 1, 0);
|
||||
if (this.childThread) {
|
||||
postMessage(createMessage('spawn-thread', {
|
||||
startArg,
|
||||
errorOrTid: errorOrTid
|
||||
}));
|
||||
Atomics.wait(struct, 1, 0);
|
||||
const isError = Atomics.load(struct, 0);
|
||||
const result = Atomics.load(struct, 1);
|
||||
if (isNewABI) {
|
||||
return isError;
|
||||
}
|
||||
free(errorOrTid);
|
||||
return isError ? -result : result;
|
||||
}
|
||||
const shouldWait = waitThreadStart || (waitThreadStart === 0);
|
||||
let sab;
|
||||
if (shouldWait) {
|
||||
sab = new Int32Array(new SharedArrayBuffer(16 + 8192));
|
||||
Atomics.store(sab, 0, 0);
|
||||
}
|
||||
let worker;
|
||||
let tid;
|
||||
const PThread = this.PThread;
|
||||
try {
|
||||
worker = PThread.getNewWorker(sab);
|
||||
if (!worker) {
|
||||
throw new Error('failed to get new worker');
|
||||
}
|
||||
tid = PThread.markId(worker);
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
worker.unref();
|
||||
}
|
||||
worker.postMessage(createMessage('start', {
|
||||
tid,
|
||||
arg: startArg,
|
||||
sab
|
||||
}));
|
||||
if (shouldWait) {
|
||||
if (typeof waitThreadStart === 'number') {
|
||||
const waitResult = Atomics.wait(sab, 0, 0, waitThreadStart);
|
||||
if (waitResult === 'timed-out') {
|
||||
try {
|
||||
PThread.cleanThread(worker, tid, true);
|
||||
}
|
||||
catch (_) { }
|
||||
throw new Error('Spawning thread timed out. Please check if the worker is created successfully and if message is handled properly in the worker.');
|
||||
}
|
||||
}
|
||||
else {
|
||||
Atomics.wait(sab, 0, 0);
|
||||
}
|
||||
const r = Atomics.load(sab, 0);
|
||||
if (r > 1) {
|
||||
try {
|
||||
PThread.cleanThread(worker, tid, true);
|
||||
}
|
||||
catch (_) { }
|
||||
throw deserizeErrorFromBuffer(sab.buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
Atomics.store(struct, 0, 1);
|
||||
Atomics.store(struct, 1, EAGAIN);
|
||||
Atomics.notify(struct, 1);
|
||||
PThread === null || PThread === void 0 ? void 0 : PThread.printErr(e.stack);
|
||||
if (isNewABI) {
|
||||
return 1;
|
||||
}
|
||||
free(errorOrTid);
|
||||
return -EAGAIN;
|
||||
}
|
||||
Atomics.store(struct, 0, 0);
|
||||
Atomics.store(struct, 1, tid);
|
||||
Atomics.notify(struct, 1);
|
||||
PThread.runningWorkers.push(worker);
|
||||
if (!shouldWait) {
|
||||
worker.whenLoaded.catch((err) => {
|
||||
delete worker.whenLoaded;
|
||||
PThread.cleanThread(worker, tid, true);
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
if (isNewABI) {
|
||||
return 0;
|
||||
}
|
||||
free(errorOrTid);
|
||||
return tid;
|
||||
};
|
||||
this.threadSpawn = threadSpawn;
|
||||
if (this.PThread) {
|
||||
this.PThread.threadSpawn = threadSpawn;
|
||||
}
|
||||
}
|
||||
getImportObject() {
|
||||
return {
|
||||
wasi: {
|
||||
'thread-spawn': this.threadSpawn
|
||||
}
|
||||
};
|
||||
}
|
||||
setup(wasmInstance, wasmModule, wasmMemory) {
|
||||
wasmMemory !== null && wasmMemory !== void 0 ? wasmMemory : (wasmMemory = wasmInstance.exports.memory);
|
||||
this.wasmInstance = wasmInstance;
|
||||
this.wasmMemory = wasmMemory;
|
||||
if (this.PThread) {
|
||||
this.PThread.setup(wasmModule, wasmMemory);
|
||||
}
|
||||
}
|
||||
preloadWorkers() {
|
||||
if (this.PThread) {
|
||||
return this.PThread.preloadWorkers();
|
||||
}
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
initialize(instance, module, memory) {
|
||||
const exports$1 = instance.exports;
|
||||
memory !== null && memory !== void 0 ? memory : (memory = exports$1.memory);
|
||||
if (this.childThread) {
|
||||
instance = createInstanceProxy(instance, memory);
|
||||
}
|
||||
this.setup(instance, module, memory);
|
||||
const wasi = this.wasi;
|
||||
if (('_start' in exports$1) && (typeof exports$1._start === 'function')) {
|
||||
if (this.childThread) {
|
||||
wasi.start(instance);
|
||||
try {
|
||||
const kStarted = getWasiSymbol(wasi, 'kStarted');
|
||||
wasi[kStarted] = false;
|
||||
}
|
||||
catch (_) { }
|
||||
}
|
||||
else {
|
||||
setupInstance(wasi, instance);
|
||||
}
|
||||
}
|
||||
else {
|
||||
wasi.initialize(instance);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
start(instance, module, memory) {
|
||||
const exports$1 = instance.exports;
|
||||
memory !== null && memory !== void 0 ? memory : (memory = exports$1.memory);
|
||||
if (this.childThread) {
|
||||
instance = createInstanceProxy(instance, memory);
|
||||
}
|
||||
this.setup(instance, module, memory);
|
||||
const exitCode = this.wasi.start(instance);
|
||||
return { exitCode, instance };
|
||||
}
|
||||
terminateAllThreads() {
|
||||
var _a;
|
||||
if (!this.childThread) {
|
||||
(_a = this.PThread) === null || _a === void 0 ? void 0 : _a.terminateAllThreads();
|
||||
}
|
||||
else {
|
||||
this.postMessage(createMessage('terminate-all-threads', {}));
|
||||
}
|
||||
}
|
||||
}
|
||||
function patchWasiInstance(wasiThreads, wasi) {
|
||||
const patched = patchedWasiInstances.get(wasiThreads);
|
||||
if (patched.has(wasi)) {
|
||||
return;
|
||||
}
|
||||
const _this = wasiThreads;
|
||||
const wasiImport = wasi.wasiImport;
|
||||
if (wasiImport) {
|
||||
const proc_exit = wasiImport.proc_exit;
|
||||
wasiImport.proc_exit = function (code) {
|
||||
_this.terminateAllThreads();
|
||||
return proc_exit.call(this, code);
|
||||
};
|
||||
}
|
||||
if (!_this.childThread) {
|
||||
const start = wasi.start;
|
||||
if (typeof start === 'function') {
|
||||
wasi.start = function (instance) {
|
||||
try {
|
||||
return start.call(this, instance);
|
||||
}
|
||||
catch (err) {
|
||||
if (isTrapError(err)) {
|
||||
_this.terminateAllThreads();
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
patched.add(wasi);
|
||||
}
|
||||
function getWasiSymbol(wasi, description) {
|
||||
const symbols = Object.getOwnPropertySymbols(wasi);
|
||||
const selectDescription = (description) => (s) => {
|
||||
if (s.description) {
|
||||
return s.description === description;
|
||||
}
|
||||
return s.toString() === `Symbol(${description})`;
|
||||
};
|
||||
if (Array.isArray(description)) {
|
||||
return description.map(d => symbols.filter(selectDescription(d))[0]);
|
||||
}
|
||||
return symbols.filter(selectDescription(description))[0];
|
||||
}
|
||||
function setupInstance(wasi, instance) {
|
||||
const [kInstance, kSetMemory] = getWasiSymbol(wasi, ['kInstance', 'kSetMemory']);
|
||||
wasi[kInstance] = instance;
|
||||
wasi[kSetMemory](instance.exports.memory);
|
||||
}
|
||||
|
||||
class ThreadMessageHandler {
|
||||
constructor(options) {
|
||||
const postMsg = getPostMessage(options);
|
||||
if (typeof postMsg !== 'function') {
|
||||
throw new TypeError('options.postMessage is not a function');
|
||||
}
|
||||
this.postMessage = postMsg;
|
||||
this.onLoad = options === null || options === void 0 ? void 0 : options.onLoad;
|
||||
this.onError = typeof (options === null || options === void 0 ? void 0 : options.onError) === 'function' ? options.onError : (_type, err) => { throw err; };
|
||||
this.instance = undefined;
|
||||
this.messagesBeforeLoad = [];
|
||||
}
|
||||
instantiate(data) {
|
||||
if (typeof this.onLoad === 'function') {
|
||||
return this.onLoad(data);
|
||||
}
|
||||
throw new Error('ThreadMessageHandler.prototype.instantiate is not implemented');
|
||||
}
|
||||
handle(e) {
|
||||
var _a;
|
||||
if ((_a = e === null || e === void 0 ? void 0 : e.data) === null || _a === void 0 ? void 0 : _a.__emnapi__) {
|
||||
const type = e.data.__emnapi__.type;
|
||||
const payload = e.data.__emnapi__.payload;
|
||||
try {
|
||||
if (type === 'load') {
|
||||
this._load(payload);
|
||||
}
|
||||
else if (type === 'start') {
|
||||
this.handleAfterLoad(e, () => {
|
||||
this._start(payload);
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
this.onError(err, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
_load(payload) {
|
||||
if (this.instance !== undefined)
|
||||
return;
|
||||
let source;
|
||||
try {
|
||||
source = this.instantiate(payload);
|
||||
}
|
||||
catch (err) {
|
||||
this._loaded(err, null, payload);
|
||||
return;
|
||||
}
|
||||
const then = source && 'then' in source ? source.then : undefined;
|
||||
if (typeof then === 'function') {
|
||||
then.call(source, (source) => { this._loaded(null, source, payload); }, (err) => { this._loaded(err, null, payload); });
|
||||
}
|
||||
else {
|
||||
this._loaded(null, source, payload);
|
||||
}
|
||||
}
|
||||
_start(payload) {
|
||||
const wasi_thread_start = this.instance.exports.wasi_thread_start;
|
||||
if (typeof wasi_thread_start !== 'function') {
|
||||
const err = new TypeError('wasi_thread_start is not exported');
|
||||
notifyPthreadCreateResult(payload.sab, 2, err);
|
||||
throw err;
|
||||
}
|
||||
const postMessage = this.postMessage;
|
||||
const tid = payload.tid;
|
||||
const startArg = payload.arg;
|
||||
notifyPthreadCreateResult(payload.sab, 1);
|
||||
try {
|
||||
wasi_thread_start(tid, startArg);
|
||||
}
|
||||
catch (err) {
|
||||
if (err !== 'unwind') {
|
||||
throw err;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
postMessage(createMessage('cleanup-thread', { tid }));
|
||||
}
|
||||
_loaded(err, source, payload) {
|
||||
if (err) {
|
||||
notifyPthreadCreateResult(payload.sab, 2, err);
|
||||
throw err;
|
||||
}
|
||||
if (source == null) {
|
||||
const err = new TypeError('onLoad should return an object');
|
||||
notifyPthreadCreateResult(payload.sab, 2, err);
|
||||
throw err;
|
||||
}
|
||||
const instance = source.instance;
|
||||
if (!instance) {
|
||||
const err = new TypeError('onLoad should return an object which includes "instance"');
|
||||
notifyPthreadCreateResult(payload.sab, 2, err);
|
||||
throw err;
|
||||
}
|
||||
this.instance = instance;
|
||||
const postMessage = this.postMessage;
|
||||
postMessage(createMessage('loaded', {}));
|
||||
const messages = this.messagesBeforeLoad;
|
||||
this.messagesBeforeLoad = [];
|
||||
for (let i = 0; i < messages.length; i++) {
|
||||
const data = messages[i];
|
||||
this.handle({ data });
|
||||
}
|
||||
}
|
||||
handleAfterLoad(e, f) {
|
||||
if (this.instance !== undefined) {
|
||||
f.call(this, e);
|
||||
}
|
||||
else {
|
||||
this.messagesBeforeLoad.push(e.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
function notifyPthreadCreateResult(sab, result, error) {
|
||||
if (sab) {
|
||||
serizeErrorToBuffer(sab.buffer, result, error);
|
||||
Atomics.notify(sab, 0);
|
||||
}
|
||||
}
|
||||
|
||||
export { ThreadManager, ThreadMessageHandler, WASIThreads, createInstanceProxy, isSharedArrayBuffer, isTrapError };
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
if (typeof process !== 'undefined' && process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./dist/wasi-threads.cjs.min.js')
|
||||
} else {
|
||||
module.exports = require('./dist/wasi-threads.cjs.js')
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user