# defineAssetSource

Keep authored asset names at call sites while a planner selects the optimized output.



<DemoPreview name="defineAssetSource" />

## Usage [#usage]

```ts
import { defineAssetSource } from '@joycostudio/xyz'

const asset = defineAssetSource({
  url: new URL('https://cdn.example.com/'),
  segments: { textures: 'textures', models: 'models' },
})

asset.textures('noise.png') // https://cdn.example.com/textures/noise.png
asset.models('scene.glb') // https://cdn.example.com/models/scene.glb
```

## API [#api]

### defineAssetSource [#defineassetsource]

```ts
defineAssetSource<const Segments extends Record<string, string> = Record<never, never>>(
  definition: AssetSourceDefinition<Segments>
): AssetSource<Segments>
```

Creates a callable URL resolver with typed builders for each configured segment. Absolute URLs pass through unchanged. Relative paths keep their query and hash suffixes, including when routed to a planned output.

| Argument               | Description                                                                                                                                                                                            |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `definition.url`       | Required `URL` for the CDN source root. Its pathname is also the prefix passed to the planner.                                                                                                         |
| `definition.planner?`  | Receives a source path without its query or hash. Return `{ ok: true, data: [{ output: 'path' }] }` to replace it. Unsuccessful results or results with zero or multiple outputs keep the source path. |
| `definition.segments?` | Map of names to path prefixes, exposed as methods on the resolver, such as `{ textures: 'textures' }`.                                                                                                 |
| `definition.optimize?` | Boolean or getter controlling planned outputs. Defaults to `true`; a getter is evaluated on each relative-path resolution.                                                                             |

```ts
const asset = defineAssetSource({
  url: new URL('https://cdn.example.com/assets/'),
  segments: { textures: 'textures' },
  optimize: true,
  planner: (input) => ({
    ok: true,
    data: [{ output: input.replace(/\.png$/, '.webp') }],
  }),
})

asset.textures('noise.png') // https://cdn.example.com/assets/textures/noise.webp
```

### asset [#asset]

```ts
asset(file: string): string
```

The returned resolver builds a URL from the configured root and optional planner.

| Argument | Description                                                                   |
| -------- | ----------------------------------------------------------------------------- |
| `file`   | An authored relative asset path or an absolute URL to pass through unchanged. |

```ts
asset('noise.png') // https://cdn.example.com/noise.png
```

### asset\[segment] [#assetsegment]

```ts
asset.textures(file: string): string
```

Each name in `definition.segments` becomes a method. It adds the configured prefix before resolving the URL; absolute URLs still pass through unchanged.

| Argument | Description                                             |
| -------- | ------------------------------------------------------- |
| `file`   | Asset path relative to the segment, or an absolute URL. |

```ts
asset.textures('noise.png') // https://cdn.example.com/textures/noise.png
```
