fix(packaging): workaround yauzl/Node 26 hang + fix API bootstrap contract

Packaging was silently hanging forever because yauzl 2.10.0 read streams
emit no data events under Node 26, causing extract-zip to block indefinitely
inside @electron/packager 20. Fix: postinstall script patches
@electron/packager/dist/unzip.js to use bsdtar (libarchive) instead.
bsdtar was chosen over 7z because 7z refuses chained symlinks in macOS
.app framework bundles. Both package:linux and package:mac now produce
correct output.

Also corrects the V3 API bootstrap contract in api_client.ts:
- SearchQuery body was wrapped in an extra {search_query: ...} layer — removed
- x-no-account-id header standardised to 'bypass'
- Redundant x-no-account-id removed from file download headers
- Smoke test rewritten to validate the real two-step bootstrap path

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-05-11 16:48:15 -04:00
parent 36aed19169
commit bab08cd8a7
14 changed files with 797 additions and 1741 deletions

View File

@@ -1,55 +1,90 @@
import requests
import json
def test_device_lookup():
device_id = 'dbgMWS3KEHE'
api_key = 'INSdG85ANwsEIru3nUttMw'
base_url = 'https://dev-api.oneskyit.com'
endpoint = f'{base_url}/v3/crud/event_device/{device_id}'
headers = {
def test_bootstrap(device_id, api_key, base_url='https://dev-api.oneskyit.com'):
"""
Replicates the two-step bootstrap sequence in api_client.ts:
Step 1: GET event_device → extract account_id + app_base_url (fqdn)
Step 2: POST site_domain/search → returns the correct site context
"""
print(f'\n=== Bootstrap test ===')
print(f'Device: {device_id}')
print(f'Base URL: {base_url}')
# --- Step 1: Get Device Config ---
device_url = f'{base_url}/v3/crud/event_device/{device_id}'
headers_step1 = {
'Content-Type': 'application/json',
'x-aether-api-key': api_key,
'x-no-account-id': 'Nothing to See Here',
'Content-Type': 'application/json'
}
params = {
'view': 'enriched'
'x-no-account-id': 'bypass',
}
print(f'Testing lookup for device: {device_id}')
print(f'Endpoint: {endpoint}')
print(f'\n-- Step 1: GET {device_url}')
try:
response = requests.get(endpoint, headers=headers, params=params)
print(f'Status Code: {response.status_code}')
if response.status_code == 200:
data = response.json()
device_data = data.get('data', {})
print('Returned Fields (Key Values):')
important_fields = [
'account_id_random',
'app_base_url',
'code',
'name',
'event_id_random',
'event_location_id_random',
'local_file_cache_path',
'host_file_temp_path',
'recording_path',
'cfg_json'
]
for field in important_fields:
val = device_data.get(field, 'MISSING')
print(f' {field}: {val}')
else:
print(f'Error Response: {response.text}')
r1 = requests.get(device_url, headers=headers_step1)
print(f' Status: {r1.status_code}')
if r1.status_code != 200:
print(f' Error: {r1.text}')
return
device_data = r1.json().get('data', {})
important_fields = [
'account_id', 'app_base_url', 'code', 'name',
'event_id', 'event_location_id',
'local_file_cache_path', 'host_file_temp_path', 'recording_path',
]
for field in important_fields:
print(f' {field}: {device_data.get(field, "MISSING")}')
account_id = device_data.get('account_id') or device_data.get('account_id_random')
fqdn = device_data.get('app_base_url', 'native-demo.oneskyit.com')
except Exception as e:
print(f'Request failed: {e}')
print(f' Request failed: {e}')
return
# --- Step 2: Get Site Context ---
search_url = f'{base_url}/v3/crud/site_domain/search?limit=1'
headers_step2 = {
'Content-Type': 'application/json',
'x-aether-api-key': api_key,
'x-account-id': account_id or '',
}
body = {
'and': [{'field': 'fqdn', 'op': 'eq', 'value': fqdn}]
}
print(f'\n-- Step 2: POST {search_url}')
print(f' Searching for fqdn: {fqdn}')
try:
r2 = requests.post(search_url, headers=headers_step2, json=body)
print(f' Status: {r2.status_code}')
if r2.status_code != 200:
print(f' Error: {r2.text}')
return
results = r2.json().get('data', [])
print(f' Results returned: {len(results)}')
if results:
sd = results[0]
print(f' fqdn: {sd.get("fqdn")}')
print(f' account_id: {sd.get("account_id")}')
print(f' site_id: {sd.get("site_id")}')
if sd.get('account_id') != account_id:
print(f' WARNING: site_domain account_id does not match device account_id!')
else:
print(f' OK: account_id matches device.')
else:
print(f' WARNING: No site_domain found for fqdn "{fqdn}"')
except Exception as e:
print(f' Request failed: {e}')
if __name__ == '__main__':
test_device_lookup()
# Dev device (dev-api)
test_bootstrap(
device_id='dbgMWS3KEHE',
api_key='INSdG85ANwsEIru3nUttMw',
base_url='https://dev-api.oneskyit.com',
)