@k9o/core 1.0.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +7 -69
  2. package/README.md +225 -27
  3. package/dist/{chunk-OE2MMUIG.js → chunk-2NDFTHUB.js} +2 -2
  4. package/dist/chunk-2NDFTHUB.js.map +1 -0
  5. package/dist/{chunk-2VSTF5UU.js → chunk-LJZ45UA2.js} +1 -1
  6. package/dist/chunk-LJZ45UA2.js.map +1 -0
  7. package/dist/{chunk-FVWKL5UQ.js → chunk-O2ZTV6YN.js} +2 -2
  8. package/dist/chunk-O2ZTV6YN.js.map +1 -0
  9. package/dist/envelope.d.ts +9 -9
  10. package/dist/http.d.ts +4 -4
  11. package/dist/http.js +2 -2
  12. package/dist/index.d.ts +163 -183
  13. package/dist/index.js +43 -44
  14. package/dist/index.js.map +1 -1
  15. package/dist/kerror.d.ts +2 -2
  16. package/dist/kerror.js +1 -1
  17. package/dist/types.d.ts +4 -6
  18. package/dist/url-grammar.d.ts +6 -6
  19. package/dist/url-grammar.js +2 -2
  20. package/package.json +5 -4
  21. package/src/audit.ts +6 -6
  22. package/src/compute/llms.ts +16 -16
  23. package/src/data/from.ts +12 -12
  24. package/src/envelope.ts +9 -9
  25. package/src/extensions-bridge.ts +7 -9
  26. package/src/functions.ts +8 -8
  27. package/src/gate-bridge.ts +2 -2
  28. package/src/http.ts +4 -4
  29. package/src/index.ts +17 -27
  30. package/src/internal/sse.ts +2 -2
  31. package/src/kerror.ts +2 -2
  32. package/src/me.ts +7 -8
  33. package/src/metadata.ts +13 -20
  34. package/src/migrations.ts +12 -12
  35. package/src/org.ts +19 -19
  36. package/src/orgs.ts +5 -5
  37. package/src/policies.ts +2 -2
  38. package/src/projects.ts +5 -5
  39. package/src/realtime.ts +16 -16
  40. package/src/retry.ts +1 -1
  41. package/src/storage-buckets.ts +1 -1
  42. package/src/studio/dashboards.ts +13 -13
  43. package/src/studio/index.ts +2 -2
  44. package/src/studio/workflows.ts +21 -21
  45. package/src/types.ts +4 -6
  46. package/src/url-grammar.ts +6 -6
  47. package/dist/chunk-2VSTF5UU.js.map +0 -1
  48. package/dist/chunk-FVWKL5UQ.js.map +0 -1
  49. package/dist/chunk-OE2MMUIG.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,76 +1,14 @@
1
1
  # Changelog — @k9o/core
2
2
 
3
- ## Unreleased
3
+ ## 1.1.1 — 2026-10-25
4
4
 
5
- - NEW `client.storage.locations.{list, create, get, update, retire, test}` — storage locations over `/@<projectSlug>/storage/locations`: register your own object store once per project from a pre-created `credentialRef`, then link it to buckets and Datasets. Provider-specific ids (`accountId` and `parentAccessKeyId` for r2, `bucketId` for b2) go in `providerParams`. New types: `StorageLocation`, `CreateStorageLocationInput`, `UpdateStorageLocationInput`, `StorageLocationProviderParams` and friends.
6
- - REMOVED (breaking) `client.byos.{list, create, get}` and the types `ByosBinding`, `CreateByosBindingInput`, `ByosProvider`, `ByosCustodyMode`, `ByosPurpose`. The purpose-based `/@<projectSlug>/byos` routes are withdrawn and answer 404; a location has no purpose. The credential helpers in `@k9o/core/byos` are unchanged.
7
- - REMOVED `client.policies.deactivate()` — the emergency-deactivate verb is retired per ch06 §9.4.4; use the publish-lockdown pattern instead.
5
+ - Documentation links corrected: the documentation hub is https://docs.kilimanjaro.dev, with the website, platform API and console listed in a Links section. Package metadata points at the same places.
8
6
 
9
- ## v0.5.0 — 2026-05-25 (org-plane + operator-self namespaces)
7
+ ## 1.1.0 — 2026-10-25
10
8
 
11
- NEW `client.org.*` org-plane namespace + NEW `client.me.*` operator-self namespace.
9
+ - Documentation rewritten with runnable examples and expected output; internal cross-references removed from the published sources. No change to the public API.
10
+ - Error text for `update()` / `delete()` without an `id` filter no longer mentions a version or a roadmap.
12
11
 
13
- - `client.org.members.{list, invite, get, remove}` per ch02 §6 + ask 1
14
- - `client.org.groups.{list, create, get, delete}` per ch02 §6 + ask 2
15
- - `client.org.auditLog.{query, tail}` per ch05 §4.4 + 6-event org family per ch05 §4.2 + ask 3 (distinct from project-plane `client.audit`)
16
- - `client.org.gate.roles.{list, grant, get, revoke}` per ch02 §6.5 `_sys.org_role_grants` substrate + ask 4 (ORG_ADMIN / ORG_BILLING_ADMIN grants with soft-delete revocation)
17
- - `client.org.gate.idpProviders.{list, create, get, configure, delete}` per ch02 §6.5 + ask 7
18
- - `client.org.smtp.{get, set, test, unset}` per ch02 §6.6 + ask 5 (3-tier cascade platform→org→project; Kibo-enclave password sequestration; 5/hour test-email rate limit)
19
- - `client.org.get()` — read bound org (mirrors `client.orgs.current()` for namespace symmetry)
20
- - `client.me.profile.{get, update}` — operator profile per ch01 §5.4 `/me/*` cross-org canonical
21
- - `client.me.sessions.{list, revoke, revokeAll}` — operator session management
22
- - `client.me.apiTokens.{list, create, delete}` — personal scripting tokens (forward substrate)
23
- - `client.me.notifications.{list, markRead, markAllRead}` — operator-targeted notifications (forward substrate)
24
- - `client.me.auditLog.query()` — operator-self audit (actions performed BY this operator across orgs; distinct from project-plane + org-plane audit)
25
- - `client.me.dataExport.{request, status}` — personal data export per GDPR-style flows (forward substrate)
12
+ ## 1.0.0 — 2026-10-23
26
13
 
27
- 27 new tests pass / 0 fail covering URL composition across all org-plane + me-plane methods. Total @k9o/core suite: 124 / 0 across 8 test files.
28
-
29
- ## v0.4.0 — 2026-05-25 (checkpoint D — retry + backoff)
30
-
31
- - HTTP client now retries transient failures per `retryConfig: { maxRetries, backoff: "exponential" | "linear" | "none", initialDelayMs, maxDelayMs }`
32
- - `createClient({ retryConfig: ... })` threads the config into the bound HTTP layer
33
- - Retryable: transport failures (`K9O_UPSTREAM_UNAVAILABLE`); HTTP 502/503/504; HTTP 429 (rate-limit)
34
- - Non-retryable: other 4xx (caller error); other 5xx (gateway-side bug; surface immediately); non-KError thrown values
35
- - Idempotency gate: only GET / HEAD / OPTIONS / DELETE are retried. POST / PATCH / PUT are never retried automatically — callers can opt in via `idempotencyKey` header per ch01 §10.2 when they assert idempotency (future sub-cycle integrates the header-driven path)
36
- - Backoff: exponential default (initialDelayMs * 2^attempt, capped, ±25% jitter); linear available; none for tight loops; defaults 100ms initial / 5000ms cap / 3 retries
37
- - 19 new tests covering isRetryable predicate + computeDelay backoff variants + withRetry orchestration + end-to-end HTTP retry integration. Total @k9o/core suite: 97 pass / 0 fail.
38
-
39
- ## v0.3.0 — 2026-05-25 (checkpoint C — pillar composition: `client.gate` + `client.extensions`)
40
-
41
- - `client.gate` composed from `@k9o/gate` via gate-bridge — shares baseUrl + projectSlug; mode defaults to `native`; partnerToken inherits from apiKey. Throws `K9O_MISSING_PROJECT_CONTEXT` when accessed without projectSlug bound.
42
- - `client.extensions` composed from `@k9o/extensions` — `client.extensions.extension(slug)` factory returning typed Trailblazer/Anchor/Keystone class extension bindings per ch13 §8.1.
43
- - `@k9o/gate` + `@k9o/extensions` added as workspace dependencies.
44
- - 6 new composition tests pass: gate namespace exposed when projectSlug bound; gate throws K9O_MISSING_PROJECT_CONTEXT without it; gate routes against same baseUrl + projectSlug as K9oClient; extensions.extension factory + paperless + cairn binding types resolve.
45
- - KError ↔ GateError alignment is still open. Until then both error types are shape-compatible; caller code narrowing on `.code` works against either.
46
- - Total @k9o/core suite: 78 pass / 0 fail across 6 test files.
47
-
48
- ## v0.2.0 — 2026-05-25 (checkpoint B — migrations + functions + policies + audit + orgs)
49
-
50
- 5 new namespaces wired to gateway routes:
51
-
52
- - `client.migrations` — apply / list / get / queue / listPending / applyPending / rejectPending / deletePending per ch04 §2 + gateway `routes/migrations.ts` (8 methods)
53
- - `client.functions` — deploy / list / get / delete / invoke per ch07 + gateway `routes/{functions,invoke}.ts` (5 methods)
54
- - `client.policies` — current / list / create / validate / get / update / delete / publish / deactivate per ch06 §9 + gateway `routes/policies.ts` (9 methods)
55
- - `client.audit` — query / tail per ch05 §4 + gateway `routes/audit-log.ts` (2 methods)
56
- - `client.orgs` — list / get / restore / current per ch02 + gateway `routes/orgs-crud.ts` (4 methods)
57
-
58
- 20 new unit tests pass / 0 fail (covers URL composition + HTTP method + body shape + query string serialisation across all 5 namespaces). Total @k9o/core suite: 72 pass.
59
-
60
- Forward sub-cycles: pillar composition (client.gate + client.extensions re-exports), retry/backoff in HTTP client, subscription/streaming, kibo namespace (composes with future @k9o/kibo).
61
-
62
- ## v0.1.0 — 2026-05-25 (first-pass scaffold)
63
-
64
- NEW package. Surfaces shipped:
65
-
66
- - `createClient(options)` factory with baseUrl validation
67
- - HTTP client (`request`) with envelope unwrap on 2xx + `KError` rehydration on non-2xx + bearer/project/org header injection + transport failure mapping per ch01 §1 + §2
68
- - `KError` class + `KErrorWire` type + `kerrorFromWire` rehydration per ch01 §2 + ch11
69
- - Envelope + meta accessor types (`Envelope<T>` / `MetaCursor` / `MetaSubscription` / `MetaIdempotency` / `MetaWarning` / `MetaCost` / `MetaTiming` / `MetaContext` / `PaginatedEnvelope<T>`) per ch01 §1 + ch13 §5
70
- - URL grammar v2.5.68 helpers: `validateBaseUrl` (rejects path/scheme/query/fragment per ch13 §7.2 → `K9O_INVALID_BASE_URL`), `validateSlug`, `projectPath` (member-plane `/@<slug>/...`), `orgPath`, `platformPath` per ch01 §5.4
71
- - Data-plane DSL `client.from(collection)` with chainable filter builder (eq / neq / gt / gte / lt / lte / in / notIn / like / ilike / is / filter), pagination (limit / cursor), counting (count: none / exact / estimated), and terminal verbs (select / insert / update / delete) per ch04 §3 + §6.4; `update` + `delete` require `.eq('id', '...')` filter (row-mass updates deferred)
72
- - Project lifecycle (`client.projects.list / create / get / update`) per ch02
73
-
74
- 52 unit tests pass / 0 fail across 4 test files; tsc clean strict.
75
-
76
- Forward sub-cycles add: `client.migrations`, `client.functions`, `client.policies`, `client.audit`, `client.orgs`, `client.gate` (composition), `client.kibo` (composition), `client.extensions` (composition), retry/backoff per ch13 §7.1, subscription/streaming per ch04 §8.
14
+ First public release. See the README for the full API overview.
package/README.md CHANGED
@@ -1,61 +1,259 @@
1
1
  # @k9o/core
2
2
 
3
- Kilimanjaro platform SDK for TypeScript / JavaScript.
3
+ The Kilimanjaro platform SDK for TypeScript and JavaScript. One client for your data, projects, functions, audit log and more.
4
4
 
5
- `createClient` + data-plane DSL + project lifecycle + cross-cutting `KError` + meta accessor sugar. Composes with `@k9o/gate` (auth pillar) and `@k9o/extensions` (extension consumption pillar).
5
+ ## Contents
6
6
 
7
- ## Status
7
+ - [Links](#links)
8
+ - [Install](#install)
9
+ - [Quick start](#quick-start)
10
+ - [Authentication and project context](#authentication-and-project-context)
11
+ - [Running queries](#running-queries)
12
+ - [Handling errors](#handling-errors)
13
+ - [Regional hosts](#regional-hosts)
14
+ - [Appendix](#appendix)
8
15
 
9
- v0.1.0 — first-pass scaffold. Surfaces shipped:
16
+ ## Links
10
17
 
11
- - `createClient(options)` — factory + baseUrl validation per ch13 §7
12
- - `client.from(collection)` — data-plane DSL: `.select()` / `.insert()` / `.update()` / `.delete()` with filter chain (eq / neq / gt / gte / lt / lte / in / notIn / like / ilike / is / filter) + pagination (limit / cursor / count) per ch04 §3 + §6.4
13
- - `client.projects` — list / create / get / update per ch02
14
- - `KError` — closed-taxonomy error class + `kerrorFromWire` rehydration per ch01 §2
15
- - URL grammar v2.5.68 — `validateBaseUrl` / `validateSlug` / `projectPath` / `orgPath` / `platformPath` per ch01 §5.4
16
-
17
- Forward sub-cycles add: `client.migrations`, `client.functions`, `client.policies`, `client.audit`, `client.orgs`, `client.gate` (composition with `@k9o/gate`), `client.kibo` (composition with future `@k9o/kibo`), `client.extensions` (composition with `@k9o/extensions`), retry/backoff, subscription/streaming.
18
+ - Website: <https://kilimanjaro.dev>
19
+ - Documentation / Developer Hub: <https://docs.kilimanjaro.dev>
20
+ - Platform API: <https://api.k9o.io>
21
+ - Platform Console: <https://console.k9o.io>
18
22
 
19
23
  ## Install
20
24
 
25
+ ```bash
26
+ npm install @k9o/core
27
+ ```
28
+
21
29
  ```bash
22
30
  bun add @k9o/core
23
31
  ```
24
32
 
33
+ ```bash
34
+ pnpm add @k9o/core
35
+ ```
36
+
37
+ Requires Node.js 18+, Bun 1.1+ or a browser with a global `fetch`. TypeScript 5.6+ is optional. See [Requirements](#requirements).
38
+
25
39
  ## Quick start
26
40
 
27
- ```typescript
28
- import { createClient, KError } from "@k9o/core";
41
+ The examples on this page use a `tasks` collection with a `title` and a `done` field.
42
+
43
+ ```ts
44
+ import { createClient } from "@k9o/core";
29
45
 
30
46
  const client = createClient({
31
- baseUrl: "https://acme.api.k9o.io",
32
47
  apiKey: process.env.K9O_API_KEY,
33
48
  orgSlug: "acme",
34
49
  projectSlug: "member-portal",
35
50
  });
36
51
 
52
+ type Task = { id: string; title: string; done: boolean };
53
+
54
+ const created = await client.from("tasks").insert<Task>({ title: "Write the README", done: false });
55
+ const task = created.data;
56
+
57
+ console.log(task.title);
58
+ ```
59
+
60
+ ```text
61
+ Write the README
62
+ ```
63
+
64
+ Every method resolves to `{ data, meta }`. `data` is the typed result and `meta` holds response metadata.
65
+
66
+ ## Authentication and project context
67
+
68
+ Three options select who you are and where you work. See [Client options](#client-options) for the full list.
69
+
70
+ | Option | What it does |
71
+ | --- | --- |
72
+ | `apiKey` | Bearer token sent on every request. |
73
+ | `orgSlug` | Selects your organization. |
74
+ | `projectSlug` | Selects the project. Required by project-scoped calls. |
75
+
76
+ - On the default host, pass `orgSlug` and leave `baseUrl` out.
77
+ - On a self-hosted or custom host, pass `baseUrl` and leave `orgSlug` out.
78
+
79
+ ```ts
80
+ const client = createClient({
81
+ baseUrl: "https://acme.example.com",
82
+ apiKey: process.env.K9O_API_KEY,
83
+ projectSlug: "member-portal",
84
+ });
85
+ ```
86
+
87
+ To retry transient failures, add `retryConfig`. See [Retry settings](#retry-settings).
88
+
89
+ ## Running queries
90
+
91
+ `client.from(collection)` reads and writes records. Chain filters and paging, then await the result.
92
+
93
+ ```ts
94
+ const response = await client.from("tasks").select<Task>().eq("done", false).limit(10);
95
+
96
+ for (const openTask of response.data) {
97
+ console.log(openTask.title);
98
+ }
99
+ ```
100
+
101
+ Update or delete one record by id:
102
+
103
+ ```ts
104
+ const updated = await client.from("tasks").update<Task>({ done: true }).eq("id", task.id);
105
+
106
+ console.log(updated.data.done);
107
+ ```
108
+
109
+ ```text
110
+ true
111
+ ```
112
+
113
+ - `update` and `delete` need an `eq("id", ...)` filter. They never change many rows at once.
114
+ - See [Data methods](#data-methods) for filters and paging.
115
+ - Other namespaces such as projects, migrations and audit are listed in [Methods by namespace](#methods-by-namespace).
116
+
117
+ ## Handling errors
118
+
119
+ Every method throws `KError` when a request fails or the SDK rejects your input. Switch on `code`.
120
+
121
+ ```ts
122
+ import { KError } from "@k9o/core";
123
+
37
124
  try {
38
- const { data, meta } = await client.from("posts").select().limit(10);
39
- console.log(data);
40
- console.log("next cursor:", (meta as { cursor?: { next: string | null } }).cursor?.next);
41
- } catch (e) {
42
- if (e instanceof KError && e.code === "K9O_TIER_CAP_HIT") {
43
- console.warn(e.message, e.recommendation);
125
+ await client.from("tasks").insert<Task>({ title: "One more task", done: false });
126
+ } catch (error) {
127
+ if (error instanceof KError && error.code === "K9O_TIER_CAP_HIT") {
128
+ console.warn(error.message, error.recommendation);
44
129
  } else {
45
- throw e;
130
+ throw error;
46
131
  }
47
132
  }
48
133
  ```
49
134
 
50
- ## Architecture
135
+ - `KError` also carries `context`, `status` and `requestId`. See [Error fields](#error-fields).
136
+ - The gateway can send many codes. See [Error codes](#error-codes) for the ones the SDK raises itself.
137
+
138
+ ## Regional hosts
139
+
140
+ - On an organization host such as `https://acme.api.k9o.io`, the client sends one `HEAD` request first.
141
+ - The request carries no credentials. It finds the regional host for your organization.
142
+ - All later requests go to that host. The answer is cached for the life of the client.
143
+ - Any other `baseUrl` is used as given. If the lookup fails, the configured host is used.
144
+
145
+ ## Appendix
146
+
147
+ ### Requirements
148
+
149
+ | Requirement | Version |
150
+ | --- | --- |
151
+ | Node.js | 18 or newer |
152
+ | Bun | 1.1 or newer |
153
+ | TypeScript (optional) | 5.6 or newer |
154
+ | Browser | Any with a global `fetch` |
155
+
156
+ ### Client options
157
+
158
+ | Option | What it does |
159
+ | --- | --- |
160
+ | `apiKey` | Bearer token sent on every request. |
161
+ | `orgSlug` | Selects your organization. On the default host it builds `https://<orgSlug>.api.k9o.io`. |
162
+ | `projectSlug` | Selects the project. Required by project-scoped calls. |
163
+ | `baseUrl` | Gateway host, no path. Defaults to `https://api.k9o.io`. |
164
+ | `fetch` | Custom `fetch` implementation. |
165
+ | `defaultHeaders` | Headers added to every request. |
166
+ | `retryConfig` | Retry policy. See [Retry settings](#retry-settings). |
167
+
168
+ - A `baseUrl` with a path, query or fragment throws `K9O_INVALID_BASE_URL`.
169
+ - Slugs use 2 to 63 lowercase letters, digits and hyphens. They start with a letter and do not end with a hyphen.
170
+
171
+ ### Retry settings
172
+
173
+ | Field | Meaning |
174
+ | --- | --- |
175
+ | `maxRetries` | How many times to retry. |
176
+ | `backoff` | `"exponential"`, `"linear"` or `"none"`. |
177
+ | `initialDelayMs` | First delay. Optional. |
178
+ | `maxDelayMs` | Delay cap. Optional. |
179
+
180
+ - Only GET, HEAD, OPTIONS and DELETE are retried.
181
+ - Retries happen on network failure and on HTTP 429, 502, 503 and 504.
182
+
183
+ ### Methods by namespace
184
+
185
+ | Namespace | Methods |
186
+ | --- | --- |
187
+ | `client.from(collection)` | See [Data methods](#data-methods). |
188
+ | `client.projects` | `list`, `create`, `get`, `update` |
189
+ | `client.migrations` | `apply`, `list`, `get`, `queue`, `listPending`, `applyPending`, `rejectPending`, `deletePending` |
190
+ | `client.functions` | `deploy`, `list`, `get`, `delete` |
191
+ | `client.audit` | `query`, `tail` (needs `projectSlug`) |
192
+ | `client.policies` | Policy bundle lifecycle |
193
+ | `client.storage` | Storage locations and buckets |
194
+ | `client.metadata` | Metadata queries across surfaces |
195
+ | `client.orgs` | `list`, `get`, `restore`, `current` |
196
+ | `client.org` | Members, groups, SMTP settings, audit log, identity providers |
197
+ | `client.me` | Your profile, sessions, API tokens, notifications |
198
+ | `client.studio` | `workflows` and `dashboards` |
199
+ | `client.compute.llms` | `list`, `read`, `invoke` |
200
+ | `client.ai` | `embed` |
201
+ | `client.realtime` | `subscribe`, `replay` |
202
+ | `client.gate` | End-user sign-in from `@k9o/gate` (needs `projectSlug`) |
203
+ | `client.kibo` | Vault and key operations from `@k9o/kibo` |
204
+ | `client.extensions` | `extension(slug)` from `@k9o/extensions` |
205
+
206
+ ### Data methods
207
+
208
+ | Method | What it does |
209
+ | --- | --- |
210
+ | `select<T>()` | Starts a query. Await it to get the rows. |
211
+ | `insert<T>(record)` | Creates one record. |
212
+ | `update<T>(patch)` | Updates one record by id. |
213
+ | `delete<T>()` | Deletes one record by id. |
214
+ | `eq`, `neq` | Equal, not equal. |
215
+ | `gt`, `gte`, `lt`, `lte` | Comparisons. |
216
+ | `in`, `notIn` | Value is in, or not in, a list. |
217
+ | `like`, `ilike` | Pattern match, case-sensitive or not. |
218
+ | `is` | Compare with `"null"`, `"true"` or `"false"`. |
219
+ | `filter(column, op, value)` | Generic form of the filters above. |
220
+ | `limit(n)` | Maximum rows to return. |
221
+ | `cursor(token)` | Continue from a cursor. |
222
+ | `count(mode)` | `"none"`, `"exact"` or `"estimated"`. |
223
+
224
+ Filters combine with AND.
225
+
226
+ ### Error fields
227
+
228
+ | Field | Meaning |
229
+ | --- | --- |
230
+ | `code` | Stable string such as `K9O_PROJECT_NOT_FOUND`. Switch on this. |
231
+ | `message` | Human-readable explanation. |
232
+ | `context` | Read-only per-code details. |
233
+ | `recommendation` | Suggested next step, or `null`. |
234
+ | `status` | HTTP status, or `null` if no request was sent. |
235
+ | `requestId` | Gateway trace id for support, or `null`. |
236
+
237
+ ### Error codes
238
+
239
+ The gateway can send other codes. The SDK passes them through unchanged.
51
240
 
52
- `@k9o/core` is the umbrella TypeScript factory that:
241
+ | Code | When |
242
+ | --- | --- |
243
+ | `K9O_INVALID_BASE_URL` | `baseUrl` is not a plain http or https host. |
244
+ | `K9O_INVALID_FIELD_VALUE` | An argument or slug failed validation. |
245
+ | `K9O_INVALID_FILTER` | A realtime subscription filter was malformed. |
246
+ | `K9O_MISSING_PROJECT_CONTEXT` | A project-scoped call was made without `projectSlug`. |
247
+ | `K9O_UPSTREAM_UNAVAILABLE` | The gateway could not be reached. |
248
+ | `K9O_INTERNAL_ERROR` | No `fetch` is available, or the response was unexpected. |
53
249
 
54
- - Constructs the `K9oClient` with cross-cutting HTTP, KError, and URL grammar
55
- - Hosts pillars that don't have their own dedicated package (data-plane, projects, migrations, functions, policies, audit, orgs)
56
- - Composes pillar packages (`@k9o/gate`, `@k9o/extensions`, future `@k9o/kibo`) under namespaces on the client
250
+ ### Related packages
57
251
 
58
- Customers may import pillar packages directly when they only need one slice — `@k9o/gate` standalone for Auth0-parity deployments, `@k9o/extensions` standalone for extension-only consumption — or import `@k9o/core` for the full platform surface.
252
+ | Package | What it does |
253
+ | --- | --- |
254
+ | `@k9o/gate` | End-user sign-up, sign-in, sessions and JWT verification. |
255
+ | `@k9o/extensions` | Typed bindings for platform extensions. |
256
+ | `@k9o/kibo` | Vault and key operations. |
59
257
 
60
258
  ## License
61
259
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  KError
3
- } from "./chunk-2VSTF5UU.js";
3
+ } from "./chunk-LJZ45UA2.js";
4
4
 
5
5
  // src/url-grammar.ts
6
6
  function validateBaseUrl(baseUrl) {
@@ -90,4 +90,4 @@ export {
90
90
  orgPath,
91
91
  platformPath
92
92
  };
93
- //# sourceMappingURL=chunk-OE2MMUIG.js.map
93
+ //# sourceMappingURL=chunk-2NDFTHUB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/url-grammar.ts"],"sourcesContent":["/**\n * URL grammar.\n *\n * Canonical URL shapes:\n * - Member-plane (project-scoped): `<orgSlug>.api.k9o.io/@<projectSlug>/<sub-resource>/...`\n * - Org-plane (org-scoped): `<orgSlug>.api.k9o.io/<resource>/...`\n * - Platform-plane (cross-org): `api.k9o.io/discovery/...` + `api.k9o.io/auth/...` etc.\n *\n * The `baseUrl` passed to `createClient` is the gateway host root —\n * scheme + host (+ optional port). Path-bearing baseUrls\n * are rejected with `K9O_INVALID_BASE_URL`.\n *\n * The SDK constructs URLs by composing `baseUrl + path-from-builder`.\n * Per-resource SDK methods use the builders below to assemble their\n * `path` argument before handing to the HTTP client.\n */\n\nimport { KError } from \"./kerror.ts\";\n\n/**\n * Validate a `baseUrl`. Returns the normalised form\n * (trailing-slash stripped) on success; throws `K9O_INVALID_BASE_URL`\n * on any violation.\n *\n * Accepted shapes:\n * - `https://api.k9o.io`\n * - `https://acme.api.k9o.io`\n * - `http://localhost:8080`\n * - `https://api.k9o.io:443`\n *\n * Rejected shapes:\n * - path segments (`https://api.k9o.io/v2`)\n * - missing scheme (`api.k9o.io`)\n * - non-http(s) scheme (`wss://api.k9o.io`)\n * - query / fragment (`https://api.k9o.io?x=1`)\n */\nexport function validateBaseUrl(baseUrl: string): string {\n let parsed: URL;\n try {\n parsed = new URL(baseUrl);\n } catch {\n throw new KError({\n code: \"K9O_INVALID_BASE_URL\",\n message: `baseUrl \"${baseUrl}\" is not a valid URL`,\n context: { baseUrl },\n recommendation: \"Pass a scheme + host like `https://api.k9o.io` or `https://<orgSlug>.api.k9o.io`\",\n status: null,\n });\n }\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n throw new KError({\n code: \"K9O_INVALID_BASE_URL\",\n message: `baseUrl \"${baseUrl}\" uses unsupported scheme \"${parsed.protocol}\"; expected http: or https:`,\n context: { baseUrl, scheme: parsed.protocol },\n recommendation: \"Use http:// or https://. WebSocket subscriptions are wired internally over SSE on the same host.\",\n status: null,\n });\n }\n if (parsed.pathname !== \"/\" && parsed.pathname !== \"\") {\n throw new KError({\n code: \"K9O_INVALID_BASE_URL\",\n message: `baseUrl \"${baseUrl}\" must not contain a path segment; got \"${parsed.pathname}\"`,\n context: { baseUrl, path: parsed.pathname },\n recommendation: \"Strip the path segment — pass host only. URL paths are composed by the SDK.\",\n status: null,\n });\n }\n if (parsed.search.length > 0 || parsed.hash.length > 0) {\n throw new KError({\n code: \"K9O_INVALID_BASE_URL\",\n message: `baseUrl \"${baseUrl}\" must not contain query or fragment`,\n context: { baseUrl, query: parsed.search, fragment: parsed.hash },\n recommendation: \"Pass host only.\",\n status: null,\n });\n }\n // Normalise — strip trailing slash so concatenation is predictable.\n const normalised = `${parsed.protocol}//${parsed.host}`;\n return normalised;\n}\n\n/**\n * The bare platform apex hosts org-subdomain derivation applies to. `api.k9o.io`\n * (production) and `api-staging.k9o.io` (staging) share the same\n * `<orgSlug>.<apex>` wire-routing scheme — confirmed live (conformance,\n * `k9o login` examples, staging demo configs all address orgs this way on\n * both). A THIRD apex here needs the same confirmation before joining this\n * set — never inferred from a hostname merely looking apex-shaped.\n */\nconst K9O_ORG_DERIVABLE_APEXES = new Set([\"api.k9o.io\", \"api-staging.k9o.io\"]);\n\n/**\n * Resolve the effective baseUrl. `baseUrl` is\n * OPTIONAL — it defaults to the platform apex `https://api.k9o.io`. When the\n * (validated) host is a bare apex in `K9O_ORG_DERIVABLE_APEXES` and `orgSlug`\n * is supplied, the SDK composes the canonical org-subdomain wire root\n * `https://<orgSlug>.<apex>`. An explicit `<orgSlug>` subdomain, a\n * self-hosted / Sovereign host, or a dev host (anything not in that set)\n * passes through unchanged — `orgSlug` is intentionally NOT validated or\n * composed onto a non-apex host (fixed 2026-08-30: this used to silently\n * ignore `orgSlug` for `api-staging.k9o.io` too, not just genuine\n * self-hosted/custom hosts, since only the literal production apex string\n * was checked).\n */\nexport function resolveBaseUrl(baseUrl: string | undefined, orgSlug?: string): string {\n const validated = validateBaseUrl(baseUrl ?? \"https://api.k9o.io\");\n const parsed = new URL(validated);\n if (K9O_ORG_DERIVABLE_APEXES.has(parsed.hostname) && orgSlug) {\n validateSlug(orgSlug, \"org\");\n return `${parsed.protocol}//${orgSlug}.${parsed.hostname}`;\n }\n return validated;\n}\n\n/**\n * Slug format validator:\n * `[a-z][a-z0-9-]{1,62}` and must not end with `-`.\n */\nconst SLUG_RE = /^[a-z][a-z0-9-]{1,62}$/;\n\nexport function validateSlug(slug: string, kind: \"org\" | \"project\"): void {\n if (!SLUG_RE.test(slug) || slug.endsWith(\"-\")) {\n throw new KError({\n code: \"K9O_INVALID_FIELD_VALUE\",\n message: `${kind}Slug \"${slug}\" does not match required format ^[a-z][a-z0-9-]{1,62}$ (must not end with '-')`,\n context: { slug, kind },\n recommendation: `Pass a slug matching the format — lowercase letters / digits / hyphens; 2-63 chars; starts with a letter; does not end with hyphen.`,\n status: null,\n });\n }\n}\n\n/**\n * Build a project-scoped (member-plane) URL path per the URL grammar\n * E.g. `projectPath('member-portal', 'collections/posts/documents')`\n * → `/@member-portal/collections/posts/documents`.\n *\n * The caller is responsible for normalising sub-resource components\n * (URL-encoding goes through the caller's path construction; this\n * helper handles only the prefix + slug shape).\n */\nexport function projectPath(projectSlug: string, subResource: string): string {\n validateSlug(projectSlug, \"project\");\n const cleaned = subResource.startsWith(\"/\") ? subResource.slice(1) : subResource;\n return `/@${projectSlug}/${cleaned}`;\n}\n\n/**\n * Build an org-plane path. E.g. `orgPath('org')` → `/org`,\n * `orgPath('projects')` → `/projects`.\n */\nexport function orgPath(resource: string): string {\n const cleaned = resource.startsWith(\"/\") ? resource.slice(1) : resource;\n return `/${cleaned}`;\n}\n\n/**\n * Build a platform-plane path (cross-org). E.g.\n * `platformPath('discovery/projects')` → `/discovery/projects`,\n * `platformPath('auth/sign-in')` → `/auth/sign-in`.\n *\n * Composes with the platform baseUrl (`https://api.k9o.io`) — not the\n * org-subdomain baseUrl.\n */\nexport function platformPath(resource: string): string {\n const cleaned = resource.startsWith(\"/\") ? resource.slice(1) : resource;\n return `/${cleaned}`;\n}\n"],"mappings":";;;;;AAoCO,SAAS,gBAAgB,SAAyB;AACvD,MAAI;AACJ,MAAI;AACF,aAAS,IAAI,IAAI,OAAO;AAAA,EAC1B,QAAQ;AACN,UAAM,IAAI,OAAO;AAAA,MACf,MAAM;AAAA,MACN,SAAS,YAAY,OAAO;AAAA,MAC5B,SAAS,EAAE,QAAQ;AAAA,MACnB,gBAAgB;AAAA,MAChB,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AACA,MAAI,OAAO,aAAa,WAAW,OAAO,aAAa,UAAU;AAC/D,UAAM,IAAI,OAAO;AAAA,MACf,MAAM;AAAA,MACN,SAAS,YAAY,OAAO,8BAA8B,OAAO,QAAQ;AAAA,MACzE,SAAS,EAAE,SAAS,QAAQ,OAAO,SAAS;AAAA,MAC5C,gBAAgB;AAAA,MAChB,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AACA,MAAI,OAAO,aAAa,OAAO,OAAO,aAAa,IAAI;AACrD,UAAM,IAAI,OAAO;AAAA,MACf,MAAM;AAAA,MACN,SAAS,YAAY,OAAO,2CAA2C,OAAO,QAAQ;AAAA,MACtF,SAAS,EAAE,SAAS,MAAM,OAAO,SAAS;AAAA,MAC1C,gBAAgB;AAAA,MAChB,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AACA,MAAI,OAAO,OAAO,SAAS,KAAK,OAAO,KAAK,SAAS,GAAG;AACtD,UAAM,IAAI,OAAO;AAAA,MACf,MAAM;AAAA,MACN,SAAS,YAAY,OAAO;AAAA,MAC5B,SAAS,EAAE,SAAS,OAAO,OAAO,QAAQ,UAAU,OAAO,KAAK;AAAA,MAChE,gBAAgB;AAAA,MAChB,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAEA,QAAM,aAAa,GAAG,OAAO,QAAQ,KAAK,OAAO,IAAI;AACrD,SAAO;AACT;AAUA,IAAM,2BAA2B,oBAAI,IAAI,CAAC,cAAc,oBAAoB,CAAC;AAetE,SAAS,eAAe,SAA6B,SAA0B;AACpF,QAAM,YAAY,gBAAgB,WAAW,oBAAoB;AACjE,QAAM,SAAS,IAAI,IAAI,SAAS;AAChC,MAAI,yBAAyB,IAAI,OAAO,QAAQ,KAAK,SAAS;AAC5D,iBAAa,SAAS,KAAK;AAC3B,WAAO,GAAG,OAAO,QAAQ,KAAK,OAAO,IAAI,OAAO,QAAQ;AAAA,EAC1D;AACA,SAAO;AACT;AAMA,IAAM,UAAU;AAET,SAAS,aAAa,MAAc,MAA+B;AACxE,MAAI,CAAC,QAAQ,KAAK,IAAI,KAAK,KAAK,SAAS,GAAG,GAAG;AAC7C,UAAM,IAAI,OAAO;AAAA,MACf,MAAM;AAAA,MACN,SAAS,GAAG,IAAI,SAAS,IAAI;AAAA,MAC7B,SAAS,EAAE,MAAM,KAAK;AAAA,MACtB,gBAAgB;AAAA,MAChB,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AACF;AAWO,SAAS,YAAY,aAAqB,aAA6B;AAC5E,eAAa,aAAa,SAAS;AACnC,QAAM,UAAU,YAAY,WAAW,GAAG,IAAI,YAAY,MAAM,CAAC,IAAI;AACrE,SAAO,KAAK,WAAW,IAAI,OAAO;AACpC;AAMO,SAAS,QAAQ,UAA0B;AAChD,QAAM,UAAU,SAAS,WAAW,GAAG,IAAI,SAAS,MAAM,CAAC,IAAI;AAC/D,SAAO,IAAI,OAAO;AACpB;AAUO,SAAS,aAAa,UAA0B;AACrD,QAAM,UAAU,SAAS,WAAW,GAAG,IAAI,SAAS,MAAM,CAAC,IAAI;AAC/D,SAAO,IAAI,OAAO;AACpB;","names":[]}
@@ -30,4 +30,4 @@ export {
30
30
  KError,
31
31
  kerrorFromWire
32
32
  };
33
- //# sourceMappingURL=chunk-2VSTF5UU.js.map
33
+ //# sourceMappingURL=chunk-LJZ45UA2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/kerror.ts"],"sourcesContent":["/**\n * `KError` — the closed-taxonomy error class returned by every `@k9o/core`\n * surface on non-2xx gateway responses or SDK-side validation failures.\n *\n * TypeScript / JavaScript throw on error; the per-language SDKs deliver this same payload\n * via their idiomatic mechanism (Go tuple-return; Rust Result; Python\n * raise; etc.) without changing the field shape.\n *\n * Fields:\n * - `code` — closed-taxonomy string (e.g. `K9O_TIER_CAP_HIT`,\n * `K9O_PROJECT_NOT_FOUND`); unknown codes pass through\n * with `code` preserved + `INTERNAL_ERROR` family\n * classification recorded in `context.originalCode`.\n * - `message` — human-readable explanation.\n * - `context` — structured per-code payload (immutable; frozen).\n * - `recommendation` — actionable next step (may be null when the\n * gateway didn't return one).\n * - `status` — HTTP status the gateway returned (or null for\n * SDK-side construct-time errors like\n * `K9O_INVALID_BASE_URL`).\n * - `requestId` — gateway-emitted trace ID for downstream correlation.\n *\n * Standalone `@k9o/gate` ships its own `GateError` for the Auth0-parity\n * deployment shape; when `@k9o/gate` is composed inside `@k9o/core`,\n * `GateError` semantics align with `KError extends KError` (alignment still open).\n * Until then `KError` is the canonical error type returned by `@k9o/core` surfaces; `GateError` thrown by\n * `@k9o/gate`-delegated surfaces remain `KError`-shape-compatible\n * (both expose the same `code` / `message` / `context` / `recommendation`\n * fields) so caller code that narrows on `code` works against either.\n */\n\n/**\n * Wire-shape sentinel matching the gateway's `KError` JSON payload. The HTTP client recognises this on non-2xx responses\n * and rehydrates it into a `KError` instance.\n */\nexport type KErrorWire = {\n code: string;\n message: string;\n context?: Record<string, unknown>;\n recommendation?: string | null;\n requestId?: string;\n};\n\n/**\n * The customer-facing error type. Every `@k9o/core` surface throws this\n * on non-2xx upstream responses, transport failures, or SDK-side\n * validation failures.\n */\nexport class KError extends Error {\n readonly code: string;\n readonly context: Readonly<Record<string, unknown>>;\n readonly recommendation: string | null;\n readonly status: number | null;\n readonly requestId: string | null;\n\n constructor(init: {\n code: string;\n message: string;\n context?: Record<string, unknown>;\n recommendation?: string | null;\n status?: number | null;\n requestId?: string | null;\n }) {\n super(init.message);\n this.name = \"KError\";\n this.code = init.code;\n this.context = Object.freeze({ ...(init.context ?? {}) });\n this.recommendation = init.recommendation ?? null;\n this.status = init.status ?? null;\n this.requestId = init.requestId ?? null;\n }\n}\n\n/**\n * Rehydrate a wire `KError` payload into a typed `KError` instance.\n * Unlike `@k9o/gate.gateErrorFromWire`, `@k9o/core` does not maintain\n * a hand-curated allow-list of known codes — the gateway's KError\n * code-space is open-ended and curated centrally; the SDK\n * preserves whatever code the gateway sends. Code-narrowing in caller\n * code uses string-literal comparison against the well-known codes\n * (e.g. `if (e.code === 'K9O_TIER_CAP_HIT')`).\n */\nexport function kerrorFromWire(wire: KErrorWire, status: number): KError {\n return new KError({\n code: wire.code,\n message: wire.message,\n context: wire.context ?? {},\n recommendation: wire.recommendation ?? null,\n status,\n requestId: wire.requestId ?? null,\n });\n}\n"],"mappings":";AAgDO,IAAM,SAAN,cAAqB,MAAM;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,MAOT;AACD,UAAM,KAAK,OAAO;AAClB,SAAK,OAAO;AACZ,SAAK,OAAO,KAAK;AACjB,SAAK,UAAU,OAAO,OAAO,EAAE,GAAI,KAAK,WAAW,CAAC,EAAG,CAAC;AACxD,SAAK,iBAAiB,KAAK,kBAAkB;AAC7C,SAAK,SAAS,KAAK,UAAU;AAC7B,SAAK,YAAY,KAAK,aAAa;AAAA,EACrC;AACF;AAWO,SAAS,eAAe,MAAkB,QAAwB;AACvE,SAAO,IAAI,OAAO;AAAA,IAChB,MAAM,KAAK;AAAA,IACX,SAAS,KAAK;AAAA,IACd,SAAS,KAAK,WAAW,CAAC;AAAA,IAC1B,gBAAgB,KAAK,kBAAkB;AAAA,IACvC;AAAA,IACA,WAAW,KAAK,aAAa;AAAA,EAC/B,CAAC;AACH;","names":[]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  KError,
3
3
  kerrorFromWire
4
- } from "./chunk-2VSTF5UU.js";
4
+ } from "./chunk-LJZ45UA2.js";
5
5
 
6
6
  // src/retry.ts
7
7
  var RETRYABLE_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "OPTIONS", "DELETE"]);
@@ -231,4 +231,4 @@ export {
231
231
  requestOnce,
232
232
  requestStream
233
233
  };
234
- //# sourceMappingURL=chunk-FVWKL5UQ.js.map
234
+ //# sourceMappingURL=chunk-O2ZTV6YN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/retry.ts","../src/region.ts","../src/http.ts"],"sourcesContent":["/**\n * Retry + backoff for the HTTP client.\n *\n * Configured via `retryConfig: { maxRetries, backoff }`. Retries are\n * scoped to transient failures only — never retry on KError-carrying\n * non-2xx responses (those are semantic; the caller must handle them).\n *\n * Retryable conditions (transient; safe to retry idempotently):\n * - Transport error (`K9O_UPSTREAM_UNAVAILABLE` from `request()`) — network down,\n * DNS fail, connection refused, etc.\n * - HTTP 502 / 503 / 504 (gateway-up but downstream unavailable)\n * - HTTP 429 with `Retry-After` header (rate-limit; backoff by header value)\n *\n * Non-retryable (semantic; caller must handle):\n * - HTTP 4xx other than 429 (caller bug; retry won't help)\n * - HTTP 5xx other than 502/503/504 (gateway-side bug; surface immediately)\n * - KError on success-shape (rare; malformed envelope)\n *\n * Retry method discipline: only GET / HEAD / OPTIONS / DELETE are\n * retried by default — these are RFC-7231 idempotent. POST / PATCH /\n * PUT are NOT retried (caller can opt in via `idempotencyKey` header\n * when they assert idempotency).\n *\n * Backoff:\n * - `exponential` (default) — `initialDelayMs * 2^attempt`, capped at maxDelayMs; jittered ±25%\n * - `linear` — `initialDelayMs * (attempt + 1)`, capped at maxDelayMs; jittered ±25%\n * - `none` — no delay between attempts\n */\n\nimport { KError } from \"./kerror.ts\";\nimport type { RetryConfig } from \"./types.ts\";\n\nconst RETRYABLE_METHODS = new Set([\"GET\", \"HEAD\", \"OPTIONS\", \"DELETE\"]);\nconst RETRYABLE_STATUS = new Set([502, 503, 504]);\n\nexport const DEFAULT_RETRY_CONFIG: Required<RetryConfig> = {\n maxRetries: 3,\n backoff: \"exponential\",\n initialDelayMs: 100,\n maxDelayMs: 5000,\n};\n\n/**\n * Decide if a thrown error is retryable.\n * Only KError instances are inspected; other thrown values propagate\n * (programmer error / unrecoverable state).\n */\nexport function isRetryable(error: unknown, method: string): boolean {\n if (!RETRYABLE_METHODS.has(method.toUpperCase())) return false;\n if (!(error instanceof KError)) return false;\n if (error.code === \"K9O_UPSTREAM_UNAVAILABLE\") return true;\n if (error.status !== null && RETRYABLE_STATUS.has(error.status)) return true;\n if (error.status === 429) return true; // rate-limit; respect Retry-After if surfaced in context\n return false;\n}\n\n/**\n * Compute the backoff delay for a given attempt index (0-based).\n */\nexport function computeDelay(config: Required<RetryConfig>, attempt: number): number {\n let base: number;\n if (config.backoff === \"none\") return 0;\n if (config.backoff === \"linear\") base = config.initialDelayMs * (attempt + 1);\n else base = config.initialDelayMs * Math.pow(2, attempt);\n const capped = Math.min(base, config.maxDelayMs);\n // ±25% jitter\n const jitter = capped * 0.25 * (Math.random() * 2 - 1);\n return Math.max(0, Math.floor(capped + jitter));\n}\n\n/**\n * Sleep helper. Pulled out so tests can stub it via injection.\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Execute a function with retry. The function is called up to\n * `maxRetries + 1` times; non-retryable failures throw immediately.\n *\n * @param fn - The function to execute (typically the HTTP request)\n * @param method - HTTP method (used to gate retry per RETRYABLE_METHODS)\n * @param config - Retry config; defaults applied if partial\n * @param sleepImpl - Sleep implementation (tests inject a no-op or fast variant)\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n method: string,\n config: RetryConfig | undefined,\n sleepImpl: (ms: number) => Promise<void> = sleep,\n): Promise<T> {\n const c: Required<RetryConfig> = {\n ...DEFAULT_RETRY_CONFIG,\n ...(config ?? {}),\n };\n let lastError: unknown;\n for (let attempt = 0; attempt <= c.maxRetries; attempt++) {\n try {\n return await fn();\n } catch (e) {\n lastError = e;\n if (attempt === c.maxRetries) break;\n if (!isRetryable(e, method)) break;\n const delay = computeDelay(c, attempt);\n if (delay > 0) await sleepImpl(delay);\n }\n }\n throw lastError;\n}\n","/**\n * Regional host resolution lives in `@k9o/gate` (which `@k9o/core` composes), so the Gate client and the core client\n * share one implementation of the probe and of the `Location` validation. See `packages/gate/src/region.ts`.\n */\nexport { resolveRegionalOrigin, regionalOriginFromLocation, type RegionConfig } from \"@k9o/gate\";\n","/**\n * HTTP client abstraction for `@k9o/core`.\n *\n * Lifted + generalised from `@k9o/gate/client.ts` (the auth-pillar SDK's\n * proven pattern). This client is per-instance — `createClient` constructs\n * one bound to its config; per-call options merge into the bound defaults.\n *\n * Responsibilities:\n * - URL construction against bound `baseUrl` + per-call `path` + query\n * - Envelope unwrap on 2xx (rejects malformed envelopes as INTERNAL_ERROR)\n * - KError rehydration on non-2xx\n * - Bearer token injection (from per-call override OR bound default)\n * - Project context header (`x-k9o-project-slug`) injection when bound\n * - Retry with exponential backoff per RetryConfig (see retry.ts) — not available\n * yet; requests are currently a single attempt\n *\n * The client is intentionally minimal — per-resource SDK methods compose\n * the path + body + bearer themselves and hand to `request()`. This keeps\n * the HTTP layer dumb and the per-resource logic auditable.\n */\n\nimport { KError, kerrorFromWire, type KErrorWire } from \"./kerror.ts\";\nimport type { Envelope } from \"./envelope.ts\";\nimport { withRetry } from \"./retry.ts\";\nimport type { RetryConfig } from \"./types.ts\";\nimport { resolveRegionalOrigin } from \"./region.ts\";\n\n/**\n * Per-instance HTTP client config. Constructed by `createClient`; passed\n * to `request()` per call.\n */\nexport type HttpClientConfig = {\n /** Normalised baseUrl (scheme + host); set via createClient. */\n baseUrl: string;\n /** Default bearer token (per-call override wins). */\n apiKey?: string | undefined;\n /** Active project slug — injected as `x-k9o-project-slug` header on every request. */\n projectSlug?: string | undefined;\n /** Active org slug — injected as `x-k9o-org-slug` header on every request. */\n orgSlug?: string | undefined;\n /** Custom fetch impl (defaults to globalThis.fetch); use for tests + non-standard runtimes. */\n fetch?: typeof globalThis.fetch | undefined;\n /** Default headers merged into every request. */\n defaultHeaders?: Record<string, string> | undefined;\n /** Retry config; idempotent methods only (GET/HEAD/OPTIONS/DELETE) — applied when transport fails or upstream returns 502/503/504/429. */\n retryConfig?: RetryConfig | undefined;\n};\n\n/**\n * Per-call request options.\n */\nexport type RequestInit = {\n method: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n path: string;\n body?: unknown;\n /** Per-call bearer override (wins over config.apiKey). */\n bearerToken?: string | undefined;\n /** Per-call additional headers (merged with config.defaultHeaders + auth). */\n headers?: Record<string, string> | undefined;\n /** Per-call query params. */\n query?: Record<string, string | number | boolean | undefined> | undefined;\n};\n\n/**\n * Issue a request against the gateway. Returns the unwrapped Envelope\n * on 2xx; throws KError on non-2xx, transport failures, or malformed\n * responses.\n */\nexport async function request<T>(\n config: HttpClientConfig,\n init: RequestInit,\n): Promise<Envelope<T>> {\n return withRetry(() => requestOnce<T>(config, init), init.method, config.retryConfig);\n}\n\n/**\n * Single-attempt request implementation. `request` wraps this in\n * retry-with-backoff per `config.retryConfig`. Exported for tests that\n * want to bypass retry semantics.\n */\nexport async function requestOnce<T>(\n config: HttpClientConfig,\n init: RequestInit,\n): Promise<Envelope<T>> {\n const fetchImpl = config.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== \"function\") {\n throw new KError({\n code: \"K9O_INTERNAL_ERROR\",\n message:\n \"No fetch implementation available — pass {fetch} in createClient options for runtimes without a global fetch\",\n context: {},\n recommendation: \"Use Node 18+, Bun 1.1+, or a modern browser; otherwise supply a fetch polyfill via the fetch option.\",\n });\n }\n\n const url = buildUrl(await resolveRegionalOrigin(config), init.path, init.query);\n const headers: Record<string, string> = {\n accept: \"application/json\",\n ...(config.defaultHeaders ?? {}),\n ...(config.projectSlug ? { \"x-k9o-project-slug\": config.projectSlug } : {}),\n ...(config.orgSlug ? { \"x-k9o-org-slug\": config.orgSlug } : {}),\n ...(init.headers ?? {}),\n };\n const bearer = init.bearerToken ?? config.apiKey;\n if (typeof bearer === \"string\" && bearer.length > 0) {\n headers[\"authorization\"] = `Bearer ${bearer}`;\n }\n const requestInit: Record<string, unknown> = {\n method: init.method,\n headers,\n };\n if (init.body !== undefined) {\n if (typeof FormData !== \"undefined\" && init.body instanceof FormData) {\n // Multipart: the runtime sets the content type (with its boundary); never JSON-encode it.\n requestInit[\"body\"] = init.body;\n } else {\n headers[\"content-type\"] = \"application/json\";\n requestInit[\"body\"] = JSON.stringify(init.body);\n }\n }\n\n let response: Response;\n try {\n response = await fetchImpl(url, requestInit as Parameters<typeof fetchImpl>[1]);\n } catch (e) {\n throw new KError({\n code: \"K9O_UPSTREAM_UNAVAILABLE\",\n message: `Network error reaching ${url}: ${e instanceof Error ? e.message : String(e)}`,\n context: { url },\n recommendation: \"Check connectivity to the gateway; retry with backoff if transient.\",\n });\n }\n\n // 204 No Content — synthesize an empty envelope (some DELETE / PUT endpoints).\n if (response.status === 204) {\n return { data: undefined as unknown as T, meta: {} };\n }\n\n let parsed: unknown;\n try {\n parsed = await response.json();\n } catch (e) {\n throw new KError({\n code: \"K9O_INTERNAL_ERROR\",\n message: `Failed to parse JSON response from ${url}: ${e instanceof Error ? e.message : String(e)}`,\n context: { url, status: response.status },\n status: response.status,\n });\n }\n\n if (response.status >= 200 && response.status < 300) {\n if (!isEnvelope<T>(parsed)) {\n throw new KError({\n code: \"K9O_INTERNAL_ERROR\",\n message: `Malformed envelope from ${url}: expected {data, meta}`,\n context: { url, status: response.status },\n status: response.status,\n });\n }\n return parsed;\n }\n\n if (isKErrorWire(parsed)) {\n throw kerrorFromWire(parsed, response.status);\n }\n throw new KError({\n code: \"K9O_INTERNAL_ERROR\",\n message: `Upstream returned ${response.status} with non-KError body`,\n context: { url, status: response.status, body: parsed },\n status: response.status,\n });\n}\n\n/**\n * Open a streaming request against the gateway. Returns the raw\n * `Response` on 2xx (caller consumes `response.body` as an SSE / chunked\n * stream); throws `KError` on non-2xx, transport failures, or a missing\n * body. Used by streaming surfaces — `client.compute.llms.invokeStream`\n * + `client.realtime.subscribe` SSE transport.\n *\n * Unlike `request()`, this does NOT unwrap the JSON envelope or apply\n * retry — streaming responses are consumed incrementally and retry on a\n * half-consumed stream is unsafe.\n */\nexport async function requestStream(\n config: HttpClientConfig,\n init: RequestInit & { accept?: string },\n): Promise<Response> {\n const fetchImpl = config.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== \"function\") {\n throw new KError({\n code: \"K9O_INTERNAL_ERROR\",\n message: \"No fetch implementation available — pass {fetch} in createClient options\",\n context: {},\n recommendation: \"Use Node 18+, Bun 1.1+, or a modern browser; otherwise supply a fetch polyfill via the fetch option.\",\n });\n }\n\n const url = buildUrl(await resolveRegionalOrigin(config), init.path, init.query);\n const headers: Record<string, string> = {\n accept: init.accept ?? \"text/event-stream\",\n ...(config.defaultHeaders ?? {}),\n ...(config.projectSlug ? { \"x-k9o-project-slug\": config.projectSlug } : {}),\n ...(config.orgSlug ? { \"x-k9o-org-slug\": config.orgSlug } : {}),\n ...(init.headers ?? {}),\n };\n const bearer = init.bearerToken ?? config.apiKey;\n if (typeof bearer === \"string\" && bearer.length > 0) {\n headers[\"authorization\"] = `Bearer ${bearer}`;\n }\n const requestInit: Record<string, unknown> = { method: init.method, headers };\n if (init.body !== undefined) {\n headers[\"content-type\"] = \"application/json\";\n requestInit[\"body\"] = JSON.stringify(init.body);\n }\n\n let response: Response;\n try {\n response = await fetchImpl(url, requestInit as Parameters<typeof fetchImpl>[1]);\n } catch (e) {\n throw new KError({\n code: \"K9O_UPSTREAM_UNAVAILABLE\",\n message: `Network error reaching ${url}: ${e instanceof Error ? e.message : String(e)}`,\n context: { url },\n recommendation: \"Check connectivity to the gateway; retry with backoff if transient.\",\n });\n }\n\n if (response.status < 200 || response.status >= 300) {\n let parsed: unknown = null;\n try {\n parsed = await response.json();\n } catch {\n /* non-JSON error body */\n }\n if (isKErrorWire(parsed)) throw kerrorFromWire(parsed, response.status);\n throw new KError({\n code: \"K9O_INTERNAL_ERROR\",\n message: `Upstream returned ${response.status} opening stream`,\n context: { url, status: response.status, body: parsed },\n status: response.status,\n });\n }\n\n if (response.body === null) {\n throw new KError({\n code: \"K9O_INTERNAL_ERROR\",\n message: `Stream response from ${url} has no body`,\n context: { url, status: response.status },\n status: response.status,\n });\n }\n\n return response;\n}\n\nfunction buildUrl(\n baseUrl: string,\n path: string,\n query: RequestInit[\"query\"],\n): string {\n const trimmedBase = baseUrl.endsWith(\"/\") ? baseUrl.slice(0, -1) : baseUrl;\n const trimmedPath = path.startsWith(\"/\") ? path : `/${path}`;\n let url = `${trimmedBase}${trimmedPath}`;\n if (query !== undefined) {\n const params = new URLSearchParams();\n for (const [k, v] of Object.entries(query)) {\n if (v !== undefined) params.set(k, String(v));\n }\n const qs = params.toString();\n if (qs.length > 0) url += `?${qs}`;\n }\n return url;\n}\n\nfunction isEnvelope<T>(value: unknown): value is Envelope<T> {\n if (value === null || typeof value !== \"object\") return false;\n const v = value as { data?: unknown; meta?: unknown };\n return \"data\" in v && \"meta\" in v && typeof v.meta === \"object\" && v.meta !== null;\n}\n\nfunction isKErrorWire(value: unknown): value is KErrorWire {\n if (value === null || typeof value !== \"object\") return false;\n const v = value as { code?: unknown; message?: unknown };\n return typeof v.code === \"string\" && typeof v.message === \"string\";\n}\n"],"mappings":"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","names":[]}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Standard ch01 §1 envelope + meta namespace types.
2
+ * Standard envelope + meta namespace types.
3
3
  *
4
4
  * The `meta` namespace surfaces structured per-namespace
5
5
  * accessors (cursor / subscription / idempotency / warnings / cost /
@@ -22,7 +22,7 @@ type Envelope<T> = {
22
22
  meta: Record<string, unknown>;
23
23
  };
24
24
  /**
25
- * Cursor pagination accessor per ch01 §6.4. `next` is the opaque cursor
25
+ * Cursor pagination accessor. `next` is the opaque cursor
26
26
  * for the next page (null when no more); `totalCount` populated only
27
27
  * when the caller passes `?count=exact` (otherwise undefined).
28
28
  */
@@ -31,7 +31,7 @@ type MetaCursor = {
31
31
  totalCount?: number;
32
32
  };
33
33
  /**
34
- * Subscription delivery metadata per ch04 §8. `isInitial` is true on
34
+ * Subscription delivery metadata. `isInitial` is true on
35
35
  * the first batch of an initial-load subscription; false on subsequent
36
36
  * live deltas.
37
37
  */
@@ -39,7 +39,7 @@ type MetaSubscription = {
39
39
  isInitial: boolean;
40
40
  };
41
41
  /**
42
- * Idempotency replay metadata per ch01 §10.2. `replayed` is true when
42
+ * Idempotency replay metadata. `replayed` is true when
43
43
  * the gateway recognised a previously-seen idempotency key and returned
44
44
  * the original response.
45
45
  */
@@ -47,7 +47,7 @@ type MetaIdempotency = {
47
47
  replayed: boolean;
48
48
  };
49
49
  /**
50
- * Non-fatal warning shape per ch01 §1.3. Surfaced on responses where
50
+ * Non-fatal warning shape. Surfaced on responses where
51
51
  * the operation succeeded but the caller should know about caveats
52
52
  * (e.g. tier-approaching-cap; deprecated field used).
53
53
  */
@@ -56,8 +56,8 @@ type MetaWarning = {
56
56
  message: string;
57
57
  };
58
58
  /**
59
- * Cost metadata per ch10 — per-dimension consumption attribution.
60
- * Field names per ch10 cost dimensions (waypoints, storageGbHours, egress,
59
+ * Cost metadata — per-dimension consumption attribution.
60
+ * Field names (waypoints, storageGbHours, egress,
61
61
  * apiCalls, vaultOps, etc.). Dimensions are sparsely populated and values
62
62
  * may be scalars (e.g. `waypoints: 3`) or structured objects (e.g.
63
63
  * `egress: { gb, zone }`, `vaultOps: { encrypt, decrypt, ... }`), so the
@@ -66,14 +66,14 @@ type MetaWarning = {
66
66
  */
67
67
  type MetaCost = Record<string, unknown>;
68
68
  /**
69
- * Timing metadata per ch01 §1.3. `totalMs` is the gateway-side wall-clock
69
+ * Timing metadata. `totalMs` is the gateway-side wall-clock
70
70
  * for the request.
71
71
  */
72
72
  type MetaTiming = {
73
73
  totalMs: number;
74
74
  };
75
75
  /**
76
- * Request-correlation metadata per ch01 §1.3. `requestId` is the
76
+ * Request-correlation metadata. `requestId` is the
77
77
  * gateway-emitted trace ID; surface in error reports for support.
78
78
  */
79
79
  type MetaContext = {
package/dist/http.d.ts CHANGED
@@ -14,8 +14,8 @@ import { RetryConfig } from './types.js';
14
14
  * - KError rehydration on non-2xx
15
15
  * - Bearer token injection (from per-call override OR bound default)
16
16
  * - Project context header (`x-k9o-project-slug`) injection when bound
17
- * - Retry with exponential backoff per RetryConfig (see retry.ts) — TBD
18
- * in next sub-cycle; v0.1.0 ships single-attempt
17
+ * - Retry with exponential backoff per RetryConfig (see retry.ts) — not available
18
+ * yet; requests are currently a single attempt
19
19
  *
20
20
  * The client is intentionally minimal — per-resource SDK methods compose
21
21
  * the path + body + bearer themselves and hand to `request()`. This keeps
@@ -39,7 +39,7 @@ type HttpClientConfig = {
39
39
  fetch?: typeof globalThis.fetch | undefined;
40
40
  /** Default headers merged into every request. */
41
41
  defaultHeaders?: Record<string, string> | undefined;
42
- /** Retry config per ch13 §7.1; idempotent methods only (GET/HEAD/OPTIONS/DELETE) — applied when transport fails or upstream returns 502/503/504/429. */
42
+ /** Retry config; idempotent methods only (GET/HEAD/OPTIONS/DELETE) — applied when transport fails or upstream returns 502/503/504/429. */
43
43
  retryConfig?: RetryConfig | undefined;
44
44
  };
45
45
  /**
@@ -73,7 +73,7 @@ declare function requestOnce<T>(config: HttpClientConfig, init: RequestInit): Pr
73
73
  * `Response` on 2xx (caller consumes `response.body` as an SSE / chunked
74
74
  * stream); throws `KError` on non-2xx, transport failures, or a missing
75
75
  * body. Used by streaming surfaces — `client.compute.llms.invokeStream`
76
- * (ch07 §10.2) + `client.realtime.subscribe` SSE transport (ch07 §11.3).
76
+ * + `client.realtime.subscribe` SSE transport.
77
77
  *
78
78
  * Unlike `request()`, this does NOT unwrap the JSON envelope or apply
79
79
  * retry — streaming responses are consumed incrementally and retry on a
package/dist/http.js CHANGED
@@ -2,8 +2,8 @@ import {
2
2
  request,
3
3
  requestOnce,
4
4
  requestStream
5
- } from "./chunk-FVWKL5UQ.js";
6
- import "./chunk-2VSTF5UU.js";
5
+ } from "./chunk-O2ZTV6YN.js";
6
+ import "./chunk-LJZ45UA2.js";
7
7
  export {
8
8
  request,
9
9
  requestOnce,