npm package: @mandarin3d/slicing-sdk
Description: SDK for interacting with Mandarin3D slicing API
Author: Mandarin3D
Latest version: 1.0.1

# Mandarin3D Slicing SDK

A TypeScript SDK for interacting with the Mandarin3D slicing API. This package provides a simple interface for submitting 3D models for slicing and monitoring the slicing process, with built-in support for both production and development environments.

## Features

- 🚀 Easy integration with Next.js and React applications
- 🔄 Real-time status updates via WebSocket in development mode
- 🎯 Type-safe API with full TypeScript support
- 🛠 Built-in React hooks for easy state management
- 🧪 Development mode with local callback support
- 📡 Automatic polling in production mode

## Installation

```bash
npm install @mandarin3d/slicing-sdk
# or
yarn add @mandarin3d/slicing-sdk
# or
pnpm add @mandarin3d/slicing-sdk
```

## Quick Start

### Basic Usage in Next.js

```typescript
import { M3DSlicingClient } from '@mandarin3d/slicing-sdk';

// Create a client instance
const client = new M3DSlicingClient({
  apiKey: process.env.NEXT_PUBLIC_M3D_API_KEY!,
  mode: process.env.NODE_ENV === 'development' ? 'development' : 'production'
});

// Submit a slicing job
const response = await client.submitSlicingJob({
  stl_file_link: 'https://example.com/model.stl'
});

console.log('Job submitted:', response.job_id);
```

### Using the React Hook

```typescript
import { useSlicingJob } from '@mandarin3d/slicing-sdk';

function SlicingComponent() {
  const { submitJob, status, isLoading, error } = useSlicingJob({
    client,
    onComplete: (status) => {
      console.log('Slicing completed!', status);
    }
  });

  const handleSubmit = async () => {
    await submitJob({
      stl_file_link: 'https://example.com/model.stl'
    });
  };

  return (
    <div>
      <button onClick={handleSubmit} disabled={isLoading}>
        Start Slicing
      </button>
      {status && (
        <div>
          <p>Status: {status.status}</p>
          <p>Message: {status.message}</p>
          {status.slicing_info && (
            <div>
              <p>Volume: {status.slicing_info.volume}mm³</p>
              <p>Size: {status.slicing_info.size_x}x{status.slicing_info.size_y}x{status.slicing_info.size_z}mm</p>
            </div>
          )}
        </div>
      )}
    </div>
  );
}
```

### Complete Next.js Example

```typescript
// pages/slicing.tsx
import { useState } from 'react';
import { M3DSlicingClient, useSlicingJob } from '@mandarin3d/slicing-sdk';
import { FaUpload, FaSpinner, FaCheck, FaTimes } from 'react-icons/fa';

// Initialize the client
const client = new M3DSlicingClient({
  apiKey: process.env.NEXT_PUBLIC_M3D_API_KEY!,
  mode: process.env.NODE_ENV === 'development' ? 'development' : 'production',
  devPort: 3001 // Optional, defaults to 3001
});

export default function SlicingPage() {
  const [fileUrl, setFileUrl] = useState('');
  
  const { submitJob, status, isLoading, error } = useSlicingJob({
    client,
    onComplete: (status) => {
      if (status.status === 'completed') {
        // Handle completion
      }
    }
  });

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!fileUrl) return;
    
    try {
      await submitJob({
        stl_file_link: fileUrl
      });
    } catch (err) {
      console.error('Failed to submit job:', err);
    }
  };

  return (
    <div className="max-w-2xl mx-auto p-6">
      <h1 className="text-3xl font-bold mb-6">3D Model Slicer</h1>
      
      <form onSubmit={handleSubmit} className="space-y-4">
        <div>
          <label className="block text-sm font-medium mb-2">
            STL File URL
          </label>
          <input
            type="url"
            value={fileUrl}
            onChange={(e) => setFileUrl(e.target.value)}
            className="w-full px-4 py-2 border rounded"
            placeholder="https://example.com/model.stl"
            required
          />
        </div>
        
        <button
          type="submit"
          disabled={isLoading}
          className="flex items-center justify-center w-full px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 disabled:opacity-50"
        >
          {isLoading ? (
            <><FaSpinner className="animate-spin mr-2" /> Processing...</>
          ) : (
            <><FaUpload className="mr-2" /> Submit for Slicing</>
          )}
        </button>
      </form>

      {error && (
        <div className="mt-4 p-4 bg-red-50 text-red-700 rounded">
          <div className="flex items-center">
            <FaTimes className="mr-2" />
            {error.message}
          </div>
        </div>
      )}

      {status && (
        <div className="mt-6 p-4 border rounded">
          <h2 className="text-xl font-semibold mb-4">Slicing Status</h2>
          
          <div className="space-y-2">
            <div className="flex items-center">
              <span className="font-medium mr-2">Status:</span>
              <span className={status.status === 'completed' ? 'text-green-600' : 'text-blue-600'}>
                {status.status === 'completed' && <FaCheck className="inline mr-1" />}
                {status.status}
              </span>
            </div>
            
            <div>
              <span className="font-medium mr-2">Message:</span>
              {status.message}
            </div>

            {status.slicing_info && (
              <div className="mt-4 space-y-2">
                <h3 className="text-lg font-medium">Model Information</h3>
                <div className="grid grid-cols-2 gap-4">
                  <div>
                    <span className="font-medium">Volume:</span>
                    <span className="ml-2">{status.slicing_info.volume}mm³</span>
                  </div>
                  <div>
                    <span className="font-medium">Dimensions:</span>
                    <span className="ml-2">
                      {status.slicing_info.size_x}x{status.slicing_info.size_y}x{status.slicing_info.size_z}mm
                    </span>
                  </div>
                  {status.slicing_info.gcode_info && (
                    <>
                      <div>
                        <span className="font-medium">Print Time:</span>
                        <span className="ml-2">{status.slicing_info.gcode_info.print_time}</span>
                      </div>
                      <div>
                        <span className="font-medium">Layer Count:</span>
                        <span className="ml-2">{status.slicing_info.gcode_info.layer_count}</span>
                      </div>
                    </>
                  )}
                </div>
              </div>
            )}
          </div>
        </div>
      )}
    </div>
  );
}
```

## API Reference

### M3DSlicingClient

The main client class for interacting with the Mandarin3D slicing API.

#### Configuration

```typescript
interface SlicingConfig {
  apiKey: string;                 // Your Mandarin3D API key
  baseUrl?: string;              // Optional custom API URL
  mode?: 'development' | 'production'; // Default: 'production'
  devPort?: number;              // Dev server port (default: 3001)
  onJobUpdate?: (status: JobStatus) => void; // Global status handler
}
```

#### Methods

- `submitSlicingJob(request: SlicingRequest): Promise<SlicingResponse>`
- `getJobStatus(jobId: string): Promise<JobStatus>`
- `onJobUpdate(jobId: string, callback: JobStatusCallback): JobStatusSubscription`
- `destroy(): void`

### useSlicingJob Hook

A React hook for managing slicing jobs in your components.

```typescript
const {
  submitJob,    // Function to submit a new job
  status,       // Current job status
  isLoading,    // Loading state
  error         // Error state
} = useSlicingJob({
  client: M3DSlicingClient,
  onComplete?: (status: JobStatus) => void,
  onError?: (error: Error) => void
});
```

## Development Mode

The SDK includes a development mode that makes local development easier:

1. Runs a local WebSocket server for real-time updates
2. Handles callbacks locally without needing public URLs
3. No polling required - uses WebSocket for instant updates

To enable development mode:

```typescript
const client = new M3DSlicingClient({
  apiKey: process.env.NEXT_PUBLIC_M3D_API_KEY!,
  mode: 'development',
  devPort: 3001 // Optional
});
```

## Types

### JobStatus

```typescript
interface JobStatus {
  status: 'initialized' | 'downloading' | 'processing' | 'completed' | 'failed';
  message: string;
  job_id: string;
  created_at?: string;
  updated_at: string;
  slicing_info?: {
    volume: number;
    size_x: number;
    size_y: number;
    size_z: number;
    gcode_info?: {
      filament_mm?: string;
      filament_cm3?: string;
      filament_g?: string;
      filament_cost?: string;
      layer_count?: string;
      print_time?: string;
    };
  };
}
```

## Best Practices

1. Always clean up resources:
```typescript
useEffect(() => {
  return () => client.destroy();
}, []);
```

2. Handle errors appropriately:
```typescript
try {
  await submitJob(request);
} catch (error) {
  // Handle error
}
```

3. Use TypeScript for better type safety and autocompletion.

4. In development mode, ensure the port (default: 3001) is available.

## License

MIT

## Support

For support, please contact support@mandarin3d.com or visit our [documentation](https://docs.mandarin3d.com).