# Quick Start

Getting a Worker reading and writing through these adapters, from nothing.

## 1. Declare the environment

Extend the package's contract with whatever your Worker adds of its own:

```ts
// src/types/Env.ts
import type { CloudflareEnv } from '@bayudwiyansatria/cloudflare'

export interface Env extends CloudflareEnv {
  LOG_LEVEL?: string
}
```

`CloudflareEnv` carries the bindings — `KV`, `DB`, `BUCKET`, `QUEUE` and the rest — every one of them optional, because
a library cannot know which resources you provisioned.

## 2. Register the configuration surface

The kernel holds the runtime-neutral settings; this package contributes the binding-backed half. The application joins
them:

```ts
// src/config/index.ts
import { configure, systemDefaults } from '@bayudwiyansatria/core'
import { cloudflareDefaults } from '@bayudwiyansatria/cloudflare'

export const defaults = {
  ...systemDefaults,
  ...cloudflareDefaults,
  logging: { ...systemDefaults.logging, ...cloudflareDefaults.logging }
}

export const overrides = {
  kv: { expirationTtl: 60 },
  logging: { service: 'example-worker' }
}

configure(defaults, overrides)
```

The halves are almost disjoint — the kernel owns `security`, this package owns the binding-backed modules — so a flat
spread carries all of those across untouched. `logging` is the one key both declare: the kernel sets the level, and this
package narrows which context fields reach the line (see [`cloudflareDefaults.logging`](../reference/observability.md)).
Spreading alone would drop one whole block for the other, and a bundler that folds the two spreads into a single object
literal reports the collision as a `Duplicate key "logging"` warning on every `wrangler dev` and `wrangler deploy`.
Merging that one module by hand settles both: this package's narrower values win key by key, the kernel's survive
wherever they are not restated, and the literal names `logging` once.

Overrides apply **per field**, so naming `expirationTtl` keeps the default `binding` of `KV`.

### Where to call `configure()`

Put it in the configuration module itself, as above, and have anything that reads configuration at startup import that
module:

```ts
// src/app.ts
import '@/config' // must come first — see below

import { Hono } from 'hono'
```

ES imports are hoisted, so a `configure()` call written in your entry file runs _after_ every module it imports has
already initialised. That matters because registering routes is startup work by nature: `SecurityMiddleware.apply` needs
the protected pattern at the moment it registers, not per request. Putting the call in `config/` and naming that
dependency makes the module graph enforce the order, since a module is always fully evaluated before its importers.

Get this wrong and the Worker throws `ConfigurationError` on startup, with a message naming both likely causes.

## 3. Use a capability

```ts
// src/services/ArticleService.ts
import { Service } from '@bayudwiyansatria/core'
import { D1Service, KVService } from '@bayudwiyansatria/cloudflare'

import type { Env } from '@/types/Env'

const cache = new KVService()
const db = new D1Service()

export class ArticleService extends Service {
  public async get(env: Env, id: number) {
    const article = await cache.remember(env, `article:${id}`, () =>
      db.first(env, 'SELECT * FROM articles WHERE id = ?', id)
    )

    return article ? this.ok('article found', article) : this.fail('article not found')
  }
}
```

Accessors are created once at module scope and reused across requests. That is safe because an accessor holds the
binding's _name_, not the binding — the binding itself is read off the `env` passed to each call.

### Degradation is part of the contract

A Worker deployed without a KV namespace still serves. `cache.remember` returns the loaded value, `cache.get` reads as a
miss, and writes are dropped — so an unprovisioned cache makes the Worker slower, never broken. Each capability
documents whether it degrades or throws, and `isAvailable(env)` reports the truth if you need to branch.

## 4. Add the middleware (optional)

```ts
// src/app.ts
import { logToAnalytics, SecurityMiddleware } from '@bayudwiyansatria/cloudflare/middlewares'

const app = new Hono()

app.use('*', logToAnalytics) // first, so rejected requests are still observed
new SecurityMiddleware().apply(app)
```

Order is load-bearing. `SecurityMiddleware` short-circuits a rejected request, so registering the logger ahead of it is
what keeps a `401` in both the logstream and the metrics. The other way round it leaves no trace at all.

## 5. Wire the bindings

Nothing above names a binding, because the configuration layer does:

```jsonc
// wrangler.json
{
  "kv_namespaces": [{ "binding": "KV", "id": "…" }],
  "d1_databases": [{ "binding": "DB", "database_id": "…" }],
  "analytics_engine_datasets": [{ "binding": "TELEMETRY", "dataset": "telemetry" }]
}
```

Those `binding` values match `cloudflareDefaults`. To use different names, override them rather than renaming anything
in code:

```ts
configure(defaults, { kv: { binding: 'SESSIONS' }, d1: { binding: 'ARTICLES_DB' } })
```

## Verify locally

In this library repository, run `npm test` and `npm run build`. In a consuming Worker, start the Cloudflare development
runtime with `npx wrangler dev` and call a route that uses the configured capability. A startup `ConfigurationError`
means step 2 is incomplete.

## Next

- [Bindings](../reference/bindings.md) — all eighteen accessors and their `wrangler.json` wiring
- [Directory Structure](../reference/directory-structure.md) — the layers and the boundary between them
