@abloatai/ablo 0.11.0 → 0.11.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.
@@ -1,11 +1,16 @@
1
1
  # Quickstart
2
2
 
3
- Build with Ablo on **your own database**. You declare a small Ablo schema for the
4
- models humans and agents edit together, hand the client your Postgres
5
- `DATABASE_URL`, and coordinate every write through `ablo.<model>`. Your database
6
- is the system of record Ablo never hosts your data. It is the transaction
7
- layer on top: it registers your connection, commits every write there behind
8
- row-level security, and fans the confirmed rows out to every connected client.
3
+ Build with Ablo on **the Postgres you already have**. You declare a small Ablo
4
+ schema for the models humans and agents edit together, hand the client your
5
+ Postgres `DATABASE_URL` (passed explicitly), and coordinate every write through
6
+ `ablo.<model>`. In production, your database is the system of record. Ablo is the
7
+ transaction layer on top: it registers your connection, commits every write there
8
+ behind row-level security, and fans the confirmed rows out to every connected
9
+ client.
10
+
11
+ > No database yet? The hosted **sandbox** can host rows in Ablo's test plane —
12
+ > pass an `apiKey` only and omit `databaseUrl`, like Stripe test mode — so you can
13
+ > try Ablo before pointing it at your Postgres.
9
14
 
10
15
  ## 1. Install and initialize
11
16
 
@@ -25,10 +30,12 @@ instead:
25
30
  export ABLO_API_KEY=sk_test_...
26
31
  ```
27
32
 
28
- Every SDK and CLI call needs a key. Test and live keys work like Stripe's
29
- except both point at databases *you* own: `sk_test_*` for your dev database,
30
- `sk_live_*` for production. There is no keyless mode; the public `/sandbox` page
31
- is a hosted demo, not your app.
33
+ Every SDK and CLI call needs a key. Test and live keys work like Stripe's:
34
+ `sk_test_*` for the sandbox, `sk_live_*` for production. In production a key
35
+ points at the database *you* own; in the sandbox you can skip the database
36
+ entirely and let Ablo's test plane host the rows (apiKey only). There is no
37
+ keyless mode — a key is always required. (The public `/sandbox` page is a
38
+ separate hosted demo, not your app.)
32
39
 
33
40
  ## 2. Your Ablo schema (init scaffolded it)
34
41
 
@@ -51,18 +58,24 @@ export const schema = defineSchema({
51
58
  ```
52
59
 
53
60
 
54
- Register the schema once (init scaffolds this `ablo.d.ts`), and every type
55
- is one parameter away — no `typeof schema` re-stating, anywhere:
61
+ The schema is registered once (init scaffolds `ablo/register.ts` for you), and
62
+ every type is one parameter away — no `typeof schema` re-stating, anywhere:
56
63
 
57
64
  ```ts
58
- // ablo.d.ts — once per project
59
- import type { schema } from './ablo/schema';
65
+ // ablo/register.ts — scaffolded by `npx ablo init`, sits beside ablo/schema.ts
66
+ import type { schema } from './schema';
60
67
  declare module '@abloatai/ablo' {
61
68
  interface Register { Schema: typeof schema }
62
69
  }
63
70
  export {};
64
71
  ```
65
72
 
73
+ It's a regular `.ts` module, not a hand-authored `.d.ts`. The top-level
74
+ `import type { schema }` makes the `declare module` block *merge* into (augment)
75
+ the SDK's `Register` interface instead of colliding with it — the same shape
76
+ [TanStack Router uses in `src/router.tsx`](https://tanstack.com/router/latest/docs/framework/react/guide/type-safety). Any `.ts` file in your
77
+ `tsconfig` `include` works; it never needs to be imported.
78
+
66
79
  ```ts
67
80
  import type { Model } from '@abloatai/ablo/schema';
68
81
 
@@ -73,6 +86,12 @@ type WeatherReport = Model<'weatherReports'>; // fully typed from YOUR schema
73
86
  TanStack-Router pattern: declare the source of truth once, everything
74
87
  infers from it.)
75
88
 
89
+ When you need to name the client type — to pass it to a function or store it in
90
+ a context — **infer it from the value**: `type Sync = typeof sync`. That's the
91
+ same idiom as tRPC's `typeof appRouter` and Drizzle's `typeof db`; it resolves
92
+ the typed overload at the call site. Avoid `ReturnType<typeof Ablo>`, which
93
+ collapses to the untyped client.
94
+
76
95
  ## 3. Point Ablo at your database
77
96
 
78
97
  The client takes your schema, your key, and your `DATABASE_URL`. On first
@@ -93,10 +112,14 @@ import { schema } from './schema';
93
112
  export const ablo = Ablo({
94
113
  schema,
95
114
  apiKey: process.env.ABLO_API_KEY,
96
- databaseUrl: process.env.DATABASE_URL, // your Postgres — rows live here, never with Ablo
115
+ databaseUrl: process.env.DATABASE_URL, // your Postgres, passed explicitly — rows live here
97
116
  });
98
117
  ```
99
118
 
119
+ `databaseUrl` is not auto-read from the environment — you pass it explicitly
120
+ (as above). If a `DATABASE_URL` is set for another tool, `Ablo()` ignores it
121
+ unless you wire it in like this.
122
+
100
123
  Use a dedicated **non-superuser role** for the connection — Ablo enforces
101
124
  tenant isolation with row-level security, so the server rejects superuser or
102
125
  `BYPASSRLS` roles outright (`database_role_cannot_enforce_rls`).
@@ -127,29 +150,34 @@ built from an ORM adapter instead — same product, same writes, see
127
150
  [Connect Your Database](./data-sources.md). In that setup, omit `databaseUrl`
128
151
  from `Ablo(...)`.
129
152
 
130
- ## 4. Push Ablo provisions your tables for you
153
+ ## 4. Push the schema, then map it to tables
131
154
 
132
155
  ```bash
133
156
  npx ablo push # checks your DATABASE_URL role, pushes the schema (sandbox),
134
- # provisions your synced-model tables (with row-level
135
- # security) IN YOUR database, and writes ABLO_API_KEY to
136
- # .env.local. Add --watch to re-push on every save.
157
+ # and writes ABLO_API_KEY to .env.local. Add --watch to
158
+ # re-push on every save.
137
159
  ```
138
160
 
139
- Nothing runs locally there is no dev server to start. Your app talks to
140
- Ablo's hosted API with the sandbox key; the rows land in your database.
141
-
142
- There is no separate migration step: the push provisions your synced-model
143
- tables in the registered database server-side — your other tables are left
144
- untouched. (`npx ablo migrate` still exists for the signed Data Source
145
- endpoint mode, where Ablo never touches your database and DDL must run from
146
- your side.)
147
-
148
- `ablo push` uploads the schema *definition*
149
- model names, fields, types. That metadata is the only thing Ablo keeps; the
150
- rows stay in your database. Skipping the push makes every write to a new or
151
- changed model fail with `server_execute_unknown_model` that error literally
152
- means "run `npx ablo push`."
161
+ `ablo push` uploads the schema *definition* model names, fields, types. That
162
+ metadata is what tells Ablo which models to coordinate. Skipping it makes every
163
+ write to a new or changed model fail with `server_execute_unknown_model` — that
164
+ error literally means "run `npx ablo push`."
165
+
166
+ Now Ablo needs real Postgres tables behind those models. Two ways, depending on
167
+ who owns the tables:
168
+
169
+ - **Adopt existing tables (the common case).** Most teams already have the
170
+ tables created by Prisma, Drizzle, or hand-written migrations. Run
171
+ `npx ablo pull` to import their shape into your schema, or `npx ablo check`
172
+ to verify your schema and the live tables agree. Keep managing the tables
173
+ with your own migration tool; Ablo just syncs the subset of models you
174
+ declared.
175
+ - **Let Ablo provision them.** If Ablo should own the tables, `npx ablo migrate`
176
+ creates your synced-model tables (with row-level security) in the registered
177
+ database. Your other tables are left untouched.
178
+
179
+ Nothing runs locally — there is no dev server to start. Your app talks to Ablo's
180
+ hosted API with the sandbox key; the rows land in your database.
153
181
 
154
182
  ## 5. Write through the model
155
183
 
package/docs/react.md CHANGED
@@ -178,6 +178,52 @@ imperative work after an event or effect.
178
178
 
179
179
  See [API reference](/docs/api) for the full options surface.
180
180
 
181
+ ## useClaim — named-claim dispatcher
182
+
183
+ `useClaim` (renamed from `useIntent` in 0.11.0) is typed sugar for invoking a
184
+ *named* claim from your own coordination vocabulary — distinct from the
185
+ row-level `ablo.<model>.claim({ id })` resource claim. Use it when you want to
186
+ broadcast a semantic claim like "I'm editing this layer" or "the agent is
187
+ generating here" and let your transport turn it into a network effect.
188
+
189
+ Declare the vocabulary once via module augmentation on the `Register` interface
190
+ (the `Claims` key — previously `Intents`):
191
+
192
+ ```ts
193
+ declare module '@abloatai/ablo' {
194
+ interface Register {
195
+ Claims: {
196
+ editLayer: { slideId: string; layerId: string };
197
+ generateWithAI: { entityId: string; tool: string };
198
+ };
199
+ }
200
+ }
201
+ ```
202
+
203
+ Then `useClaim('editLayer')` returns a function whose sole argument is the
204
+ `editLayer` shape — purely compile-time narrowing, no runtime checks:
205
+
206
+ ```tsx
207
+ 'use client';
208
+
209
+ import { useClaim } from '@abloatai/ablo/react';
210
+
211
+ export function LayerToolbar({ slideId, layerId }: { slideId: string; layerId: string }) {
212
+ const claimEditLayer = useClaim('editLayer');
213
+
214
+ return (
215
+ <button onClick={() => claimEditLayer({ slideId, layerId })}>
216
+ Edit layer
217
+ </button>
218
+ );
219
+ }
220
+ ```
221
+
222
+ The hook is pure sugar: the actual network effect lives in the `beginClaim`
223
+ function wired into the provider (bound to your transport). If no `beginClaim`
224
+ is wired, the returned invoker throws `AbloValidationError` with code
225
+ `claim_not_wired`.
226
+
181
227
  ## Next.js
182
228
 
183
229
  The Next.js [App Router landing](/nextjs) walks through Server Components
package/llms-full.txt CHANGED
@@ -19,7 +19,7 @@ Public imports:
19
19
  - `@abloatai/ablo/react` — React provider and hooks.
20
20
  - `@abloatai/ablo/testing` — test harnesses and mocks.
21
21
 
22
- TYPES: have the project register its schema ONCE via declaration merging (init scaffolds `ablo.d.ts`): `declare module '@abloatai/ablo' { interface Register { Schema: typeof schema } }`. Then model types are one parameter: `type Task = Model<'tasks'>` (import type { Model } from '@abloatai/ablo/schema'). Do NOT teach `InferModel` (deprecated) or the two-param `Model<typeof schema,'tasks'>` unless multiple schemas exist. Never hand-write model interfaces — derive from the schema.
22
+ TYPES: the project registers its schema ONCE via declaration merging — `npx ablo init` scaffolds `ablo/register.ts` (a regular `.ts` module beside schema.ts, NOT a hand-authored `.d.ts`): `import type { schema } from './schema'; declare module '@abloatai/ablo' { interface Register { Schema: typeof schema } }`. The top-level `import type` makes `declare module` MERGE (augment) the SDK's Register interface rather than collide — same shape TanStack Router uses in src/router.tsx; any `.ts` file in tsconfig include works, never imported. Then model types are one parameter: `type Task = Model<'tasks'>` (import type { Model } from '@abloatai/ablo/schema'). Do NOT teach `InferModel` (deprecated) or the two-param `Model<typeof schema,'tasks'>` unless multiple schemas exist. Never hand-write model interfaces — derive from the schema. To NAME the client type (function param, context value), infer from the value: `type Sync = typeof sync` — same idiom as tRPC `typeof appRouter` / Drizzle `typeof db`; it resolves the typed overload at the call site. Do NOT use `ReturnType<typeof Ablo>` (collapses to the untyped last overload) and do NOT import a bespoke client-type generic — there is none.
23
23
 
24
24
 
25
25
  Do not teach `/api`, `/agent`, `/ai-sdk`, `/core`, `/realtime`, or `internal/*` as public imports. The Data Source surface — `/source`, `/source/next`, `/source/drizzle`, `/source/kysely`, `/source/conformance` — IS public (it's how a customer-owned database is wired).
@@ -145,9 +145,21 @@ This applies to any API-backed app: Python, Rails, Go, or Node. The backend keep
145
145
  its service layer and DB credentials. Ablo gets a Data Source endpoint and uses
146
146
  `ABLO_API_KEY`, not a database URL.
147
147
 
148
- When the user DOES use the connection-string path (`Ablo({ databaseUrl })` /
149
- `DATABASE_URL` at init): the role must be NON-superuser and NON-BYPASSRLS
150
- Ablo enforces row-level security and rejects owner roles with
148
+ The connection-string path is the PRIMARY one: pass `databaseUrl` explicitly to
149
+ `Ablo({ databaseUrl })`. It is NOT auto-read from the environment a
150
+ `DATABASE_URL` set for another tool (Prisma, Drizzle, docker-compose) is ignored
151
+ unless you pass `databaseUrl`. The typical user ALREADY has a Postgres (often
152
+ Prisma-managed for auth/audit/log tables that are NOT in the Ablo schema); Ablo
153
+ syncs a SUBSET of models against it. Most users do NOT run `ablo migrate` — they
154
+ ADOPT existing tables with `npx ablo pull` / `npx ablo check`, or keep managing
155
+ tables with their own migration tool. Run `npx ablo migrate` only when Ablo
156
+ should OWN the tables. NOTE: Ablo's CLOUD connects to your Postgres over the
157
+ NETWORK, so a localhost / private-range DB is unreachable and rejected — for a
158
+ local dev DB, expose a signed Data Source endpoint (your app proxies to it) or
159
+ use the hosted sandbox (no DB needed).
160
+
161
+ When the user DOES use the connection-string path: the role must be NON-superuser
162
+ and NON-BYPASSRLS — Ablo enforces row-level security and rejects owner roles with
151
163
  `database_role_cannot_enforce_rls`. Neon's and Supabase's default dashboard
152
164
  strings use the database OWNER (e.g. `neondb_owner`) and ARE rejected. EASIEST: have the user run `npx ablo migrate` — it detects the unsafe role and creates the scoped one automatically from their machine (owner credential never reaches Ablo; new DATABASE_URL written to the env file). Manual alternative — create a scoped role first (`CREATE ROLE ablo_app LOGIN PASSWORD '...'
153
165
  NOSUPERUSER NOBYPASSRLS; GRANT CREATE, CONNECT ON DATABASE <db> TO ablo_app;
@@ -162,9 +174,11 @@ The options that matter: `schema` and `apiKey`. Everything else
162
174
  breaks the connection. It exists only for self-hosted/proxy setups the human
163
175
  explicitly asks for.
164
176
 
165
- There is intentionally no `databaseURL` option on `Ablo(...)`. Application and
166
- agent code use `ABLO_API_KEY`. Customer-owned app databases stay private behind
167
- a signed Data Source endpoint.
177
+ `databaseUrl` is an OPTIONAL, server-only option on `Ablo(...)`. It is NOT
178
+ auto-read from the environment pass it EXPLICITLY to register your Postgres
179
+ directly (the primary connection-string path). Omit it when you expose a signed
180
+ Data Source endpoint (so customer-owned app databases stay private), or when
181
+ trying Ablo against the hosted sandbox (apiKey only, no database).
168
182
 
169
183
  Important per-write options: `wait`, `readAt`, `onStale`,
170
184
  `idempotencyKey`, and `timeout`.
@@ -187,7 +201,10 @@ There are two sandbox surfaces:
187
201
  be pasted into Claude Code or Codex to wire one real model through Ablo.
188
202
  - Authenticated org sandboxes are real test environments. The default sandbox is
189
203
  the Stripe-style sandbox for an org. It has an isolated sync group prefix,
190
- can mint `sk_test_*` keys, and can be reset without touching live state.
204
+ can mint `sk_test_*` keys, and can be reset without touching live state. The
205
+ sandbox CAN host rows in Ablo's test plane, so you can try Ablo with NO
206
+ database — `apiKey` only, no `databaseUrl` — like Stripe test mode. (In
207
+ production, your own Postgres is the system of record.)
191
208
 
192
209
  Additional org sandboxes can start blank or copy live configuration. Keep
193
210
  customer production traffic on `sk_live_*`; use `sk_test_*` for app setup, Data
package/llms.txt CHANGED
@@ -8,7 +8,7 @@ Use AI SDK for the agent loop. Use Ablo when agent reads and writes must persist
8
8
 
9
9
  ## Start here
10
10
 
11
- First action when integrating into an app: run `npx ablo init --yes --framework <nextjs|vite|remix|vanilla> --storage datasource`. Agents have no TTY — `--yes` is REQUIRED or it HANGS. It scaffolds `ablo/schema.ts`, the client, the Data Source endpoint, and (for Next.js) the browser provider + session route, all on the current API. Edit the generated files rather than hand-writing from this doc.
11
+ First action when integrating into an app: run `npx ablo init --yes --framework <nextjs|vite|remix|vanilla>`. Agents have no TTY — `--yes` is REQUIRED or it HANGS. The default `--storage direct` (connection string) scaffolds `ablo/schema.ts`, the client, and (for Next.js) the browser provider + session route; pass `--storage endpoint` instead when database credentials must stay inside the app — that variant scaffolds a signed Data Source endpoint. All on the current API. Edit the generated files rather than hand-writing from this doc.
12
12
 
13
13
  Second: make sure a key exists — WITHOUT printing it. The key is a secret; it must never appear in your output, your reasoning, or a file you echo (it would live in the conversation history forever). Check PRESENCE only: `[ -n "$ABLO_API_KEY" ] && echo set` and `grep -cq '^ABLO_API_KEY=' .env.local && echo wired` — never `cat .env.local`, never `echo $ABLO_API_KEY`. If neither check passes, ask the HUMAN to run `npx ablo login` once — it opens a browser and saves a `sk_test_` key locally; an agent must NOT run it. You never copy the key by hand: the next step writes it into `.env.local` (and gitignores it) for you.
14
14
 
@@ -24,7 +24,7 @@ Each app gets its own PROJECT inside the org — its own schema, its own sandbox
24
24
  import Ablo from '@abloatai/ablo';
25
25
  import { defineSchema, model, z } from '@abloatai/ablo/schema';
26
26
 
27
- TYPES: have the project register its schema ONCE via declaration merging (init scaffolds `ablo.d.ts`): `declare module '@abloatai/ablo' { interface Register { Schema: typeof schema } }`. Then model types are one parameter: `type Task = Model<'tasks'>` (import type { Model } from '@abloatai/ablo/schema'). Do NOT teach `InferModel` (deprecated) or the two-param `Model<typeof schema,'tasks'>` unless multiple schemas exist. Never hand-write model interfaces — derive from the schema.
27
+ TYPES: the project registers its schema ONCE via declaration merging — `npx ablo init` scaffolds `ablo/register.ts` (a regular `.ts` module beside schema.ts, NOT a hand-authored `.d.ts`): `import type { schema } from './schema'; declare module '@abloatai/ablo' { interface Register { Schema: typeof schema } }`. The top-level `import type` makes `declare module` MERGE (augment) the SDK's Register interface rather than collide — same shape TanStack Router uses in src/router.tsx; any `.ts` file in tsconfig include works, never imported. Then model types are one parameter: `type Task = Model<'tasks'>` (import type { Model } from '@abloatai/ablo/schema'). Do NOT teach `InferModel` (deprecated) or the two-param `Model<typeof schema,'tasks'>` unless multiple schemas exist. Never hand-write model interfaces — derive from the schema. To NAME the client type (function param, context value), infer from the value: `type Sync = typeof sync` — same idiom as tRPC `typeof appRouter` / Drizzle `typeof db`; it resolves the typed overload at the call site. Do NOT use `ReturnType<typeof Ablo>` (collapses to the untyped last overload) and do NOT import a bespoke client-type generic — there is none.
28
28
 
29
29
 
30
30
  const schema = defineSchema({
@@ -123,9 +123,9 @@ A schema is model fields and relations. Advanced schema helpers such as `mutable
123
123
 
124
124
  ## Storage Boundary
125
125
 
126
- Do not add `databaseURL` to `Ablo(...)`. Application and agent code use `ABLO_API_KEY`.
126
+ `databaseUrl` is an OPTIONAL, server-only constructor option on `Ablo(...)`. It is NOT auto-read from the environment — pass it EXPLICITLY to register your Postgres directly. Omit it when you expose a signed Data Source endpoint, or when trying Ablo against the hosted sandbox (apiKey only). A `DATABASE_URL` set for another tool (Prisma, Drizzle, docker-compose) is ignored unless you pass `databaseUrl` explicitly.
127
127
 
128
- Every schema model is backed by a database, and the default is YOUR OWN. Keep your rows in your Postgres and expose a Data Source endpoint that hands Ablo an ORM `adapter` (Drizzle is the default; Prisma and Kysely are also supported) — it owns the transaction, exactly-once idempotency, and outbox in ONE pass (no hand-written `commit`/`events`). Your `DATABASE_URL` lives in your app, never in `Ablo(...)`; run `npx ablo migrate` to provision the synced-model tables in your DB.
128
+ In production, every schema model is backed by YOUR OWN database. The PRIMARY path is the connection string: pass `databaseUrl` (most users already have a Postgres — often Prisma- or Drizzle-managed for auth/audit/log tables that are NOT in the Ablo schema; Ablo syncs a SUBSET of models against it). Most users do NOT run `ablo migrate` — they ADOPT existing tables with `npx ablo pull` / `npx ablo check`, or keep managing tables with their own migration tool. Run `npx ablo migrate` only when Ablo should OWN the tables (it provisions the synced-model tables in your DB). The alternative to the connection string is a signed Data Source endpoint that hands Ablo an ORM `adapter` (Drizzle is the default; Prisma and Kysely are also supported) — it owns the transaction, exactly-once idempotency, and outbox in ONE pass (no hand-written `commit`/`events`); use it when database credentials must never leave your infrastructure (or for a local/private-range DB, which Ablo's cloud cannot reach over the network).
129
129
 
130
130
  GOTCHA the user WILL hit: `DATABASE_URL` must use a NON-superuser, NON-BYPASSRLS role (Ablo enforces row-level security; owner roles are rejected with `database_role_cannot_enforce_rls`). Neon's and Supabase's default dashboard connection strings use the database OWNER (e.g. `neondb_owner`) and are rejected. EASIEST: `npx ablo migrate` detects the unsafe role and creates the scoped one automatically from the user's machine (owner credential never reaches Ablo; new DATABASE_URL written to the env file). Manual alternative — create a scoped role first: `CREATE ROLE ablo_app LOGIN PASSWORD '...' NOSUPERUSER NOBYPASSRLS; GRANT CREATE, CONNECT ON DATABASE <db> TO ablo_app; GRANT CREATE, USAGE ON SCHEMA public TO ablo_app;` — then swap user/password into the same host/db string.
131
131
 
@@ -145,7 +145,7 @@ export const { POST } = dataSourceNext({
145
145
  });
146
146
  ```
147
147
 
148
- `npx ablo init` defaults to this — it scaffolds the endpoint and the `DATABASE_URL` for you (see CLI below). Your app database credentials stay private — Ablo only calls the endpoint.
148
+ `npx ablo init` defaults to `--storage direct` (the connection-string path — it scaffolds the client carrying `databaseUrl` and the `DATABASE_URL` env entry; see CLI below). Pass `--storage endpoint` to scaffold the signed Data Source endpoint above instead, when app database credentials must stay private — Ablo only calls the endpoint.
149
149
 
150
150
  ## Sandboxes
151
151
 
@@ -156,9 +156,11 @@ when an agent is asked to "make Ablo work" in an existing app.
156
156
 
157
157
  Authenticated org sandboxes are real test environments. Treat the default
158
158
  sandbox like Stripe test mode: it has an isolated sync group prefix and mints
159
- `sk_test_*` keys. Extra sandboxes can start blank or copy live configuration.
160
- Resetting a sandbox creates a clean future stream without touching live data.
161
- Use `sk_live_*` only for production.
159
+ `sk_test_*` keys. The sandbox CAN host rows in Ablo's test plane, so you can try
160
+ Ablo with NO database `apiKey` only, no `databaseUrl`. (In production, your own
161
+ Postgres is the system of record.) Extra sandboxes can start blank or copy live
162
+ configuration. Resetting a sandbox creates a clean future stream without
163
+ touching live data. Use `sk_live_*` only for production.
162
164
 
163
165
  For coding agents, the sandbox success path is: pick one shared model,
164
166
  declare schema, create the Ablo client, replace one direct mutation with a typed
@@ -185,7 +187,7 @@ Do not teach `/api`, `/agent`, `/ai-sdk`, `/core`, `/realtime`, or internal subp
185
187
 
186
188
  `ablo init` and other prompts need a TTY; an agent/CI run has none and will HANG. Always:
187
189
 
188
- - `npx ablo init --yes` (flags: `--framework`, `--auth`, `--storage`, `--no-agent`, `--no-pull`, `--no-install`, `--no-login`). Generates `ablo/schema.ts` + the `ablo/data-source.ts` endpoint above.
190
+ - `npx ablo init --yes` (flags: `--framework`, `--auth`, `--storage direct|endpoint` (default `direct`), `--no-agent`, `--no-pull`, `--no-install`, `--no-login`). Generates `ablo/schema.ts` + the client; `--storage direct` (default) wires `databaseUrl`, `--storage endpoint` scaffolds the `ablo/data-source.ts` endpoint above instead.
189
191
  - Key: see "Start here" — env → `.env.local` → ask the human to `npx ablo login`; never run `login` yourself, never copy keys by hand (`ablo push` writes `.env.local`).
190
192
  - Adopt an existing DB: `npx ablo pull prisma [path]` / `npx ablo pull drizzle <module>`.
191
193
  - `npx ablo push --no-watch` pushes the schema (sandbox) AND writes `ABLO_API_KEY` to `.env.local` (default watches forever); `npx ablo logs --no-follow` (default tails forever); `npx ablo mode sandbox|production` (always pass the arg). `npx ablo push`/`status`/`pull`/`check`/`generate` are one-shot.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abloatai/ablo",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
4
4
  "description": "The Collaboration Layer For AI Agents",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",