Web APIs

Andromeda provides implementations of standard web APIs to ensure compatibility with existing web code and standards. This includes event handling, text encoding, and other essential web platform features.

Overview

The Web APIs in Andromeda follow WHATWG specifications and provide a familiar programming model for developers coming from browser environments.

Event API

Event Class

The Event API provides a standard way to handle events, following the WHATWG HTML Living Standard for event handling.

Constructor

new Event(type: string, eventInitDict?: EventInit)

Creates a new Event object.

Parameters:

Properties

Methods

preventDefault(): void

Cancels the event's default action if it's cancelable.

const event = new Event("submit", { cancelable: true });
event.preventDefault();
console.log(event.defaultPrevented); // true
stopPropagation(): void

Stops the event from propagating further through the event flow.

const event = new Event("click", { bubbles: true });
event.stopPropagation();
// Event will not bubble to parent elements
stopImmediatePropagation(): void

Stops the event from propagating and prevents other listeners on the same element from being called.

element.addEventListener("click", (event) => {
  event.stopImmediatePropagation();
  // Other click listeners on this element won't be called
});

Event Usage Examples

Creating Custom Events

// Create a simple custom event
const customEvent = new Event("myCustomEvent");

// Create an event with options
const configurableEvent = new Event("userAction", {
  bubbles: true,
  cancelable: true,
});

// Check event properties
console.log(customEvent.type); // "myCustomEvent"
console.log(customEvent.bubbles); // false
console.log(configurableEvent.bubbles); // true

Event Handling Patterns

// Event listener function
function handleCustomEvent(event: Event) {
  console.log(`Received event: ${event.type}`);

  if (event.cancelable) {
    event.preventDefault();
    console.log("Default action prevented");
  }
}

// Create and dispatch custom event
const event = new Event("dataProcessed", {
  bubbles: false,
  cancelable: true,
});

// Simulate event handling
handleCustomEvent(event);

Event State Management

class EventProcessor {
  processEvent(event: Event): boolean {
    // Check if event is valid for processing
    if (!event.isTrusted) {
      console.warn("Untrusted event, skipping processing");
      return false;
    }

    // Process different event phases
    switch (event.eventPhase) {
      case Event.CAPTURING_PHASE:
        console.log("Event in capturing phase");
        break;
      case Event.AT_TARGET:
        console.log("Event at target");
        break;
      case Event.BUBBLING_PHASE:
        console.log("Event in bubbling phase");
        break;
    }

    return true;
  }
}

Text Encoding API

The Text Encoding API provides utilities for encoding and decoding text, implementing the WHATWG Encoding Standard.

TextEncoder

Encodes strings into UTF-8 byte sequences.

TextEncoder Constructor

new TextEncoder();

Creates a new TextEncoder instance. Always uses UTF-8 encoding.

TextEncoder Properties

TextEncoder Methods

encode(input?: string): Uint8Array

Encodes a string into a Uint8Array of UTF-8 bytes.

const encoder = new TextEncoder();

// Encode ASCII text
const ascii = encoder.encode("Hello, World!");
console.log(ascii); // Uint8Array with UTF-8 bytes

// Encode Unicode text
const unicode = encoder.encode("你好世界");
console.log(unicode); // Uint8Array with UTF-8 bytes for Chinese characters

// Empty string
const empty = encoder.encode("");
console.log(empty.length); // 0
encodeInto(source: string, destination: Uint8Array): TextEncoderEncodeIntoResult

Encodes a string into an existing Uint8Array buffer.

const encoder = new TextEncoder();
const buffer = new Uint8Array(50);

const result = encoder.encodeInto("Hello, 世界!", buffer);
console.log(result.read); // Number of characters read
console.log(result.written); // Number of bytes written

TextDecoder

Decodes byte sequences into strings using specified encoding.

TextDecoder Constructor

new TextDecoder(label?: string, options?: TextDecoderOptions)

Creates a new TextDecoder instance.

Parameters:

TextDecoder Properties

TextDecoder Methods

decode(input?: BufferSource, options?: TextDecodeOptions): string

Decodes a byte sequence into a string.

const decoder = new TextDecoder();

// Decode UTF-8 bytes
const bytes = new Uint8Array([72, 101, 108, 108, 111]); // "Hello"
const text = decoder.decode(bytes);
console.log(text); // "Hello"

// Streaming decode
const stream = { stream: true };
const partial1 = decoder.decode(bytes1, stream);
const partial2 = decoder.decode(bytes2, stream);
const final = decoder.decode(); // Finish stream

Text Encoding Examples

Basic Encoding/Decoding

const encoder = new TextEncoder();
const decoder = new TextDecoder();

// Round-trip encoding
const originalText = "Hello, 世界! 🌍";
const encoded = encoder.encode(originalText);
const decoded = decoder.decode(encoded);

console.log(originalText === decoded); // true
console.log(encoded.length); // Number of bytes (varies with Unicode)

Working with Different Text Types

const encoder = new TextEncoder();
const decoder = new TextDecoder();

// ASCII text
const ascii = "Simple ASCII text";
const asciiBytes = encoder.encode(ascii);
console.log(`ASCII: ${ascii.length} chars → ${asciiBytes.length} bytes`);

// Unicode text (2-byte characters)
const latin = "Café résumé naïve";
const latinBytes = encoder.encode(latin);
console.log(`Latin: ${latin.length} chars → ${latinBytes.length} bytes`);

// Unicode text (3-byte characters)
const chinese = "你好世界";
const chineseBytes = encoder.encode(chinese);
console.log(`Chinese: ${chinese.length} chars → ${chineseBytes.length} bytes`);

// Emoji (4-byte characters)
const emoji = "🌍🚀⭐";
const emojiBytes = encoder.encode(emoji);
console.log(`Emoji: ${emoji.length} chars → ${emojiBytes.length} bytes`);

Streaming Text Processing

const decoder = new TextDecoder();

function processTextStream(chunks: Uint8Array[]): string {
  let result = "";

  // Process all chunks except the last with streaming
  for (let i = 0; i < chunks.length - 1; i++) {
    result += decoder.decode(chunks[i], { stream: true });
  }

  // Process final chunk without streaming
  if (chunks.length > 0) {
    result += decoder.decode(chunks[chunks.length - 1]);
  }

  return result;
}

// Example usage with chunked data
const textData = "This is a long text that might be received in chunks";
const encoded = new TextEncoder().encode(textData);

// Split into chunks
const chunk1 = encoded.slice(0, 10);
const chunk2 = encoded.slice(10, 20);
const chunk3 = encoded.slice(20);

const reconstructed = processTextStream([chunk1, chunk2, chunk3]);
console.log(textData === reconstructed); // true

Error Handling

// Fatal mode - throws on invalid sequences
const fatalDecoder = new TextDecoder("utf-8", { fatal: true });

try {
  // Invalid UTF-8 sequence
  const invalidBytes = new Uint8Array([0xFF, 0xFE, 0xFD]);
  const result = fatalDecoder.decode(invalidBytes);
} catch (error) {
  console.error("Decoding failed:", error.message);
}

// Non-fatal mode - replaces invalid sequences
const tolerantDecoder = new TextDecoder("utf-8", { fatal: false });
const invalidBytes = new Uint8Array([0xFF, 0xFE, 0xFD]);
const result = tolerantDecoder.decode(invalidBytes);
console.log(result); // Contains replacement characters

Performance Optimization

// Reuse encoder/decoder instances
const globalEncoder = new TextEncoder();
const globalDecoder = new TextDecoder();

function efficientTextProcessing(texts: string[]): Uint8Array[] {
  // Reuse the same encoder instance
  return texts.map((text) => globalEncoder.encode(text));
}

// Pre-allocate buffers for encodeInto
const encoder = new TextEncoder();
const buffer = new Uint8Array(1024); // Reusable buffer

function encodeWithBuffer(text: string): Uint8Array {
  const result = encoder.encodeInto(text, buffer);
  return buffer.slice(0, result.written);
}

Validation and Testing

Text Encoding Validation

function validateTextEncoding(): boolean {
  const encoder = new TextEncoder();
  const decoder = new TextDecoder();

  // Test cases
  const testCases = [
    "Hello, World!", // ASCII
    "Café résumé", // Latin-1 supplement
    "你好世界", // CJK
    "🌍🚀⭐", // Emoji
    "", // Empty string
    "\0\x01\x02", // Control characters
  ];

  for (const testCase of testCases) {
    const encoded = encoder.encode(testCase);
    const decoded = decoder.decode(encoded);

    if (testCase !== decoded) {
      console.error(`Failed for: "${testCase}"`);
      return false;
    }
  }

  console.log("✓ All text encoding tests passed");
  return true;
}

// Run validation
validateTextEncoding();

Event System Testing

function testEventSystem(): boolean {
  // Test basic event creation
  const event1 = new Event("test");
  if (event1.type !== "test" || event1.bubbles !== false) {
    return false;
  }

  // Test event with options
  const event2 = new Event("custom", { bubbles: true, cancelable: true });
  if (!event2.bubbles || !event2.cancelable) {
    return false;
  }

  // Test preventDefault
  event2.preventDefault();
  if (!event2.defaultPrevented) {
    return false;
  }

  console.log("✓ All event tests passed");
  return true;
}

// Run validation
testEventSystem();

Browser Compatibility

Andromeda's Web APIs are designed to be compatible with standard browser implementations:

Best Practices

Text Encoding

  1. Reuse Instances: Create encoder/decoder instances once and reuse them
  2. Handle Errors: Use fatal mode when data integrity is critical
  3. Stream Processing: Use streaming for large text data
  4. Buffer Management: Pre-allocate buffers for better performance

Events

  1. Use Standard Types: Use well-known event types when possible
  2. Configure Appropriately: Set bubbles and cancelable based on needs
  3. Handle Errors: Check event state before processing
  4. Performance: Avoid creating excessive event objects