Compare commits

...

2 Commits

Author SHA1 Message Date
inext c333bbce4e cancellazione modifiche dopo step before oauth 2026-06-16 21:43:24 +02:00
inext 6001c2e3b8 Revert OAuth2.0 2026-06-16 21:35:10 +02:00
5803 changed files with 677870 additions and 1143 deletions
+5 -1
View File
@@ -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
-3
View File
@@ -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
View File
@@ -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';"
```
-144
View File
@@ -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"
+1 -103
View File
@@ -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`
Executable
+59
View File
@@ -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:"*"))
```
+1
View File
@@ -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
{
-48
View File
@@ -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');
+1 -160
View File
@@ -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
+1
View File
@@ -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');
+1
View File
@@ -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;
+1
View File
@@ -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
{
+1 -63
View File
@@ -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();
+1
View File
@@ -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
{
-46
View File
@@ -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;
}
}
+1
View File
@@ -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
+3
View File
@@ -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();
-150
View File
@@ -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;
}
}
-62
View File
@@ -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
View File
@@ -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)"
-5
View File
@@ -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
View File
@@ -0,0 +1 @@
../laravel-vite-plugin/bin/clean.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../concurrently/dist/bin/concurrently.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../concurrently/dist/bin/concurrently.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../jiti/lib/jiti-cli.mjs
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../nanoid/bin/nanoid.cjs
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../rolldown/bin/cli.mjs
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../tree-kill/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../vite/bin/vite.js
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+66
View File
@@ -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;
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+929
View File
@@ -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
View File
@@ -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
View File
@@ -0,0 +1 @@
See [https://github.com/toyobayashi/emnapi](https://github.com/toyobayashi/emnapi)
+7397
View File
File diff suppressed because it is too large Load Diff
+420
View File
@@ -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 { }
File diff suppressed because one or more lines are too long
+420
View File
@@ -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
View File
@@ -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;
File diff suppressed because it is too large Load Diff
+9231
View File
File diff suppressed because it is too large Load Diff
+420
View File
@@ -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 { }
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+7386
View File
File diff suppressed because it is too large Load Diff
+5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -0,0 +1 @@
See [https://github.com/toyobayashi/emnapi](https://github.com/toyobayashi/emnapi)
+1381
View File
File diff suppressed because it is too large Load Diff
+671
View File
@@ -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 { }
File diff suppressed because one or more lines are too long
+671
View File
@@ -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
View File
@@ -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;
File diff suppressed because it is too large Load Diff
+426
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+1510
View File
File diff suppressed because it is too large Load Diff
+671
View File
@@ -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 { }
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1350
View File
File diff suppressed because it is too large Load Diff
+5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 { }
File diff suppressed because one or more lines are too long
+272
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 { }
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+889
View File
@@ -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
View File
@@ -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