ugly-app 0.1.917 → 0.1.920
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.
- package/README.md +76 -60
- package/dist/cli/publish/orchestrator.d.ts.map +1 -1
- package/dist/cli/publish/orchestrator.js +15 -1
- package/dist/cli/publish/orchestrator.js.map +1 -1
- package/dist/cli/publish/providers/cloudflare.d.ts +15 -4
- package/dist/cli/publish/providers/cloudflare.d.ts.map +1 -1
- package/dist/cli/publish/providers/cloudflare.js +56 -14
- package/dist/cli/publish/providers/cloudflare.js.map +1 -1
- package/dist/cli/uglyappConfig.d.ts +28 -0
- package/dist/cli/uglyappConfig.d.ts.map +1 -1
- package/dist/cli/uglyappConfig.js.map +1 -1
- package/dist/cli/version.d.ts +1 -1
- package/dist/cli/version.js +1 -1
- package/dist/client/Logger.d.ts +4 -0
- package/dist/client/Logger.d.ts.map +1 -1
- package/dist/client/Logger.js +33 -0
- package/dist/client/Logger.js.map +1 -1
- package/dist/client/createSocket.d.ts.map +1 -1
- package/dist/client/createSocket.js +62 -9
- package/dist/client/createSocket.js.map +1 -1
- package/dist/inspect/host-bundle.js +8 -8
- package/dist/server/Socket.d.ts.map +1 -1
- package/dist/server/Socket.js +4 -1
- package/dist/server/Socket.js.map +1 -1
- package/dist/server/adapter/workers/createWorkersApp.d.ts.map +1 -1
- package/dist/server/adapter/workers/createWorkersApp.js +5 -1
- package/dist/server/adapter/workers/createWorkersApp.js.map +1 -1
- package/dist/server/adapter/workers/wrapWithAssets.d.ts.map +1 -1
- package/dist/server/adapter/workers/wrapWithAssets.js +40 -0
- package/dist/server/adapter/workers/wrapWithAssets.js.map +1 -1
- package/dist/shared/ProxyOps.d.ts +14 -0
- package/dist/shared/ProxyOps.d.ts.map +1 -1
- package/dist/shared/ProxyOps.js +9 -0
- package/dist/shared/ProxyOps.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/publish/orchestrator.ts +15 -0
- package/src/cli/publish/providers/cloudflare.ts +80 -22
- package/src/cli/publish/providers/queueConsumer.test.ts +115 -0
- package/src/cli/uglyappConfig.ts +29 -0
- package/src/cli/version.ts +1 -1
- package/src/client/Logger.ts +35 -0
- package/src/client/createSocket.ts +64 -8
- package/src/client/opaqueScriptError.test.ts +35 -0
- package/src/server/Socket.ts +4 -1
- package/src/server/adapter/workers/createWorkersApp.ts +5 -1
- package/src/server/adapter/workers/wrapWithAssets.ts +45 -0
- package/src/shared/ProxyOps.ts +9 -0
package/README.md
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
# ugly-app
|
|
2
2
|
|
|
3
|
-
A full-stack TypeScript framework for shipping production web apps. Scaffold
|
|
4
|
-
`npx ugly-app init my-app` and get an opinionated
|
|
5
|
-
stack with type-safe RPC over WebSocket and HTTP, real-time
|
|
6
|
-
built-in auth, AI generation, storage, workers, and a CLI for every
|
|
3
|
+
A full-stack TypeScript framework for shipping production web apps. Scaffold
|
|
4
|
+
with `npx ugly-app init my-app` and get an opinionated Node + React + Postgres
|
|
5
|
+
stack with type-safe RPC over WebSocket and HTTP, real-time doc subscriptions,
|
|
6
|
+
built-in auth, AI generation, storage, workers, cron, and a CLI for every
|
|
7
|
+
workflow.
|
|
7
8
|
|
|
8
|
-
ugly-app is designed to run against [ugly.bot](https://ugly.bot), which
|
|
9
|
-
auth, infra (
|
|
10
|
-
keys, and deployment. Your app talks to all of it
|
|
11
|
-
tunnel and its `UGLY_BOT_TOKEN`.
|
|
9
|
+
ugly-app is designed to run against [ugly.bot](https://ugly.bot), which
|
|
10
|
+
provides auth, infra (Postgres, Qdrant, NATS, S3-compatible object storage),
|
|
11
|
+
AI provider keys, push, email, and deployment. Your app talks to all of it
|
|
12
|
+
through the project's dev tunnel and its `UGLY_BOT_TOKEN`.
|
|
12
13
|
|
|
13
14
|
## What's included
|
|
14
15
|
|
|
15
|
-
- **Server** — Express + WebSocket with
|
|
16
|
+
- **Server** — Express + WebSocket with typed RPC and Zod validation.
|
|
16
17
|
- **Client** — React 19 + Vite with typed routing, lazy pages, animated transitions, and a router-owned popup layer.
|
|
17
|
-
- **Database** — `TypedDB` over
|
|
18
|
+
- **Database** — `TypedDB` over Postgres (JSONB) or Cloudflare D1, with full-text and vector search.
|
|
18
19
|
- **Auth** — HttpOnly cookies + JWT. ugly.bot OAuth by default; magic-link / Google in `mode: 'self'`.
|
|
19
20
|
- **AI** — Text, JSON, image, embeddings, web search — proxied through ugly.bot.
|
|
20
21
|
- **Realtime** — NATS pub/sub and doc change subscriptions (`trackDoc` / `trackDocs`).
|
|
21
22
|
- **Storage** — S3-compatible buckets with presigned uploads.
|
|
22
|
-
- **Workers & cron** — `setWorkers()` registers named async tasks with optional Zod
|
|
23
|
+
- **Workers & cron** — `setWorkers()` registers named async tasks with optional Zod schemas and cron schedules.
|
|
23
24
|
- **Two-adapter deploy** — Same source runs on Node (Express) or Cloudflare Workers (Hono + Durable Objects).
|
|
24
25
|
- **CLI** — `ugly-app` commands for dev, build, deploy, migrations, logs, AI, and auth.
|
|
25
26
|
|
|
@@ -37,12 +38,13 @@ wired up.
|
|
|
37
38
|
|
|
38
39
|
---
|
|
39
40
|
|
|
40
|
-
## Server — `createApp()`
|
|
41
|
+
## Server — `createApp()`
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
Single server entry point. Returns an `App` that owns Express, the WebSocket
|
|
44
|
+
server, the typed DB, and the RPC dispatcher.
|
|
44
45
|
|
|
45
46
|
```ts
|
|
47
|
+
// server/index.ts
|
|
46
48
|
import {
|
|
47
49
|
createApp,
|
|
48
50
|
type AppConfigurator,
|
|
@@ -53,17 +55,29 @@ import type { WorkerHandlers } from 'ugly-app/shared';
|
|
|
53
55
|
import { messages, requests } from '../shared/api';
|
|
54
56
|
import { collections } from '../shared/collections';
|
|
55
57
|
import { cronTasks } from '../shared/cron';
|
|
58
|
+
import { experiments } from '../shared/experiments';
|
|
56
59
|
import { pages } from '../shared/pages';
|
|
60
|
+
import { stringsDef } from '../shared/strings';
|
|
61
|
+
import en from '../shared/lang/en';
|
|
62
|
+
import es from '../shared/lang/es';
|
|
57
63
|
|
|
58
64
|
const cronHandlers: WorkerHandlers<typeof cronTasks> = { /* … */ };
|
|
59
65
|
|
|
60
66
|
const app = createApp(
|
|
61
|
-
{ requests, messages },
|
|
67
|
+
{ requests, messages },
|
|
62
68
|
{ /* handlers */ } satisfies RequestHandlers<typeof requests>,
|
|
63
69
|
collections,
|
|
64
70
|
(configurator: AppConfigurator) => {
|
|
65
71
|
configurator.setPages({ pages });
|
|
72
|
+
configurator.setExperiments(experiments);
|
|
73
|
+
configurator.setStrings({
|
|
74
|
+
defaultLang: stringsDef.defaultLang,
|
|
75
|
+
langs: stringsDef.langs,
|
|
76
|
+
criticalKeys: stringsDef.criticalKeys,
|
|
77
|
+
getTable: (lang) => ({ en, es } as Record<string, unknown>)[lang] ?? en,
|
|
78
|
+
});
|
|
66
79
|
configurator.setWorkers(cronTasks, cronHandlers);
|
|
80
|
+
configurator.setOnEmail(async (inbound: InboundEmail) => { /* … */ });
|
|
67
81
|
},
|
|
68
82
|
);
|
|
69
83
|
|
|
@@ -97,16 +111,17 @@ call `configurator.setPages()` still work — they just get the loose
|
|
|
97
111
|
| `start(port?)` | Start the server (default 3000; templates use 4321). |
|
|
98
112
|
| `db` | The `TypedDB<Map>` (map inferred from your collections + framework built-ins). |
|
|
99
113
|
| `httpServer` | The underlying Node `http.Server`. |
|
|
100
|
-
| `wss` | The main `WebSocketServer` (path set
|
|
101
|
-
| `dispatch(name, input, userId)` | Invoke
|
|
114
|
+
| `wss` | The main `WebSocketServer` (path set via `setWsPath`, default `/rpc`). |
|
|
115
|
+
| `dispatch(name, input, userId)` | Invoke a registered RPC handler programmatically (inherited from `AppRouter`). |
|
|
102
116
|
| `registerRoutes(fn)` | Mount additional Express routes after creation. |
|
|
103
|
-
| `pushSend(input)` | Send a push whose click-through target is a route from this app's `pages
|
|
117
|
+
| `pushSend(input)` | Send a push whose click-through target is a route from this app's `pages`. `page` and `query` are type-checked when the registry carries `pages`; the framework mints a `https://ugly.bot/l/<code>` short link so the click-through is always absolute and dock-app-routable. |
|
|
104
118
|
|
|
105
|
-
Framework services start automatically inside `app.start()`: schema drift
|
|
106
|
-
NATS connection + KV buckets, data-proxy connection, event-counter
|
|
107
|
-
cleanup for log tables, console/error capture, and ugly.bot log
|
|
108
|
-
Postgres, NATS, storage, and AI clients are loaded **lazily** — a
|
|
109
|
-
`DATABASE_URL` / `NATS_URL` / `R2_BUCKET` doesn't pay their
|
|
119
|
+
Framework services start automatically inside `app.start()`: schema drift
|
|
120
|
+
check, NATS connection + KV buckets, data-proxy connection, event-counter
|
|
121
|
+
flush, TTL cleanup for log tables, console/error capture, and ugly.bot log
|
|
122
|
+
forwarding. Postgres, NATS, storage, and AI clients are loaded **lazily** — a
|
|
123
|
+
host without `DATABASE_URL` / `NATS_URL` / `R2_BUCKET` doesn't pay their
|
|
124
|
+
startup cost.
|
|
110
125
|
|
|
111
126
|
### `AppConfigurator`
|
|
112
127
|
|
|
@@ -115,7 +130,7 @@ Every method is optional; `setPages` is what mounts the SPA.
|
|
|
115
130
|
| Method | Description |
|
|
116
131
|
|--------|-------------|
|
|
117
132
|
| `setPages({ pages, renderPage?, clientDistPath? })` | Mount the SPA. Dev runs Vite in middleware mode; prod serves `clientDistPath` (default `dist/client`). Provide `renderPage(routeName, params) => Promise<string>` to SSR any `ssr: true` pages. |
|
|
118
|
-
| `setUserHelper(helper)` |
|
|
133
|
+
| `setUserHelper(helper)` | A `UserHelper<UserBase>` the framework uses to look up / create users on WebSocket auth. Falls back to a minimal shim if unset. |
|
|
119
134
|
| `setOnUserCreate(handler)` | `(userId, { email?, phone? }, db) => Promise<void>` — called on first login; create the user record. |
|
|
120
135
|
| `setAuth(provider)` | Replace the default auth provider (`verify(code)`, `authUrl(origin)`, optional `registerRoutes`). |
|
|
121
136
|
| `setOnSocketMessage(handler)` | Single raw-WebSocket handler. `(ws, userId, msg) => boolean` — return `true` to consume, `false` to fall through. **Replaces** any previously registered handler. |
|
|
@@ -123,7 +138,7 @@ Every method is optional; `setPages` is what mounts the SPA.
|
|
|
123
138
|
| `setWsPath(path)` | Override the WebSocket path (default `/rpc`). |
|
|
124
139
|
| `setOnWsAuth(handler)` | `(ws, userId, req) => void` — fires after a socket session authenticates. |
|
|
125
140
|
| `setOnAfterStart(handler)` | `(db) => Promise<void>` — called once after data-proxy + NATS are ready. |
|
|
126
|
-
| `setOnMinuteTick(fn)` / `setOnHourlyTick(fn)` | Framework-managed periodic callbacks.
|
|
141
|
+
| `setOnMinuteTick(fn)` / `setOnHourlyTick(fn)` | Framework-managed periodic callbacks. Fire only when `CLOCK_ENABLED=true`. |
|
|
127
142
|
| `setHealthHandler(fn)` | Override the default `GET /health`. |
|
|
128
143
|
| `setExperiments(experiments)` | Register `Experiment` definitions for `initSession` / `captureEvent` bucketing. |
|
|
129
144
|
| `setIsAdmin(fn)` | `(userId, db) => boolean \| Promise<boolean>` — gate for admin-only framework requests. Defaults to matching `MAINTAIN_BOT_USER_ID`. |
|
|
@@ -131,7 +146,7 @@ Every method is optional; `setPages` is what mounts the SPA.
|
|
|
131
146
|
| `setOnEmail(handler)` | Handle inbound emails routed to `{domain}@ugly.bot` (delivered as internal HTTP). |
|
|
132
147
|
| `setCronTasks(tasks, handlers)` | **Deprecated.** Legacy cron-only registry — prefer `setWorkers()`. |
|
|
133
148
|
| `setWorkers(workers, handlers)` | Register named async tasks with optional Zod input schema and cron schedule. Powers `GET /_workers/manifest`, `POST /_workers/run`, and the cron orchestrator. Scheduled workers are mirrored into the cron registry automatically. |
|
|
134
|
-
| `setStrings(config)` | Localization config — framework injects language + critical strings into SSR HTML. |
|
|
149
|
+
| `setStrings(config)` | Localization config — the framework injects language + critical strings into SSR HTML. |
|
|
135
150
|
| `registerRoutes(fn)` | Mount custom Express routes. |
|
|
136
151
|
| `setWorkerQueue(queue)` | Register a `WorkerQueue` with `start()` / `stop()` for lifecycle management. |
|
|
137
152
|
|
|
@@ -142,10 +157,10 @@ captured imports (`app.db`, `storage`, `pgQuery`, `uglyBotRequest`, etc.).
|
|
|
142
157
|
|
|
143
158
|
```ts
|
|
144
159
|
// req() — public, userId may be null
|
|
145
|
-
getPublicData: async (userId: string | null, input) => { … }
|
|
160
|
+
getPublicData: async (userId: string | null, input) => { /* … */ }
|
|
146
161
|
|
|
147
162
|
// authReq() — authenticated, framework returns 401 if no/invalid token
|
|
148
|
-
getMe: async (userId: string, input) => { … }
|
|
163
|
+
getMe: async (userId: string, input) => { /* … */ }
|
|
149
164
|
```
|
|
150
165
|
|
|
151
166
|
### Built-in framework requests
|
|
@@ -193,7 +208,7 @@ export const requests = defineRequests({
|
|
|
193
208
|
output: z.object({ userId: z.string(), email: z.string().optional() }),
|
|
194
209
|
}),
|
|
195
210
|
|
|
196
|
-
//
|
|
211
|
+
// Per-endpoint rate limiting — enforced before the handler runs
|
|
197
212
|
submitFeedback: authReq({
|
|
198
213
|
input: z.object({ type: z.enum(['bug', 'design', 'feature']), message: z.string() }),
|
|
199
214
|
output: z.object({ id: z.string() }),
|
|
@@ -202,9 +217,9 @@ export const requests = defineRequests({
|
|
|
202
217
|
});
|
|
203
218
|
```
|
|
204
219
|
|
|
205
|
-
Every request is reachable as **both** `socket.request(name, input)`
|
|
206
|
-
and `POST /api/:name { input }` (HTTP). `z` is re-exported from
|
|
207
|
-
convenience.
|
|
220
|
+
Every request is reachable as **both** `socket.request(name, input)`
|
|
221
|
+
(WebSocket) and `POST /api/:name { input }` (HTTP). `z` is re-exported from
|
|
222
|
+
Zod for convenience.
|
|
208
223
|
|
|
209
224
|
### Collections (`shared/collections.ts`)
|
|
210
225
|
|
|
@@ -233,26 +248,26 @@ export const collections = defineCollections({
|
|
|
233
248
|
});
|
|
234
249
|
```
|
|
235
250
|
|
|
236
|
-
|
|
237
|
-
-
|
|
238
|
-
- `cache` — `true` / `false`
|
|
251
|
+
**`CollectionMeta`:**
|
|
252
|
+
- `db` — **required.** `neon` (Postgres) or `d1` (Cloudflare D1 / SQLite). Both handles are exported from `ugly-app/shared`. Omitting it is a compile error and runtime throw. A `d1` collection may also declare `search` (SQLite FTS5) and/or `vector` (Cloudflare Vectorize).
|
|
253
|
+
- `cache` — `true` / `false` / `{ ttlMs }`. When enabled, `getDoc` / `getByIds` read from an LRU cache; writes invalidate it.
|
|
239
254
|
- `trackable` — enables real-time `trackDoc` / `trackDocs` via change-stream NATS notifications.
|
|
240
255
|
- `public` — allow unauthenticated client reads.
|
|
241
256
|
- `cascadeFrom` — parent collection: when the parent doc is deleted, docs in this collection are cascade-deleted.
|
|
242
257
|
- `trackKeys?` — fields usable as NATS routing keys for scoped `trackDocs` subscriptions.
|
|
243
|
-
- `getter?(ids)` — batch resolver for collections
|
|
258
|
+
- `getter?(ids)` — batch resolver for collections with no local table (framework pattern; e.g. `userPublic` resolves via ugly.bot).
|
|
244
259
|
- `skipReadValidation?` — opt out of per-row zod validation on reads for very hot collections. Writes are always validated. Global kill-switch: `UGLY_DB_VALIDATE_READS=0`.
|
|
245
260
|
- `search?: { fields, language? }` — full-text index over the named JSONB paths (Neon: Postgres FTS; D1: SQLite FTS5, ranked by bm25).
|
|
246
|
-
- `vector?: { dimensions, metric?, filterable? }` — ANN index.
|
|
261
|
+
- `vector?: { dimensions, metric?, filterable? }` — ANN index. Vector supplied out-of-band at write time (`setDoc(c, doc, { vec })`) — never stored in the doc JSON. Query with `getDocs(c, filter, { near })`.
|
|
247
262
|
|
|
248
263
|
All documents extend `DBObject`: `{ _id, version, created, updated }`. Use
|
|
249
|
-
`dbDefaults()` to stamp `version` / `created` / `updated` on inserts.
|
|
250
|
-
generate `_id` with `nanoid()`** — never `crypto.randomUUID()`,
|
|
251
|
-
`Math.random()` (see `CLAUDE.md`).
|
|
264
|
+
`dbDefaults()` to stamp `version` / `created` / `updated` on inserts.
|
|
265
|
+
**Always generate `_id` with `nanoid()`** — never `crypto.randomUUID()`,
|
|
266
|
+
`Date.now()`, or `Math.random()` (see `CLAUDE.md`).
|
|
252
267
|
|
|
253
|
-
After schema changes, run `npm run db:schema-gen` then `npm run db:migrate`.
|
|
254
|
-
app refuses to start when drift is detected (set `SCHEMA_CHECK_SKIP=true`
|
|
255
|
-
as a last resort).
|
|
268
|
+
After schema changes, run `npm run db:schema-gen` then `npm run db:migrate`.
|
|
269
|
+
The app refuses to start when drift is detected (set `SCHEMA_CHECK_SKIP=true`
|
|
270
|
+
only as a last resort).
|
|
256
271
|
|
|
257
272
|
---
|
|
258
273
|
|
|
@@ -276,9 +291,10 @@ export type AppPages = typeof pages;
|
|
|
276
291
|
```
|
|
277
292
|
|
|
278
293
|
`definePage<Params>(options?)` returns a `PageDef<Params>` — a runtime object
|
|
279
|
-
carrying `PageMeta` plus a phantom `_params` used only for TypeScript
|
|
294
|
+
carrying `PageMeta` plus a phantom `_params` used only for TypeScript
|
|
295
|
+
inference.
|
|
280
296
|
|
|
281
|
-
Options (all optional):
|
|
297
|
+
**Options** (all optional):
|
|
282
298
|
|
|
283
299
|
- `auth` (default `true`) — protected route. When `isAuthenticated()` returns false on this route, the router synchronously renders the framework's `<AuthRoot>` in place of the page (dispatches on `window.__UGLY_APP_AUTH_MODE__`: Mode A → `<LoginPopup>`, Mode B → `<MagicLinkForm>` plus optional Google button). Apps cannot override this fallback — the framework owns the login UX so no route can accidentally ship as auth-required with no way to log in.
|
|
284
300
|
- `ssr` (default `false`) — server-render the page for SEO. `{ auth: true, ssr: true }` is silently dropped to `ssr: false` with a warning: the SSR document is served from a shared edge cache and must not depend on the viewer.
|
|
@@ -310,7 +326,7 @@ export const {
|
|
|
310
326
|
|
|
311
327
|
**Config:**
|
|
312
328
|
- `pages` (required) — the `PageRegistry` from `shared/pages.ts`.
|
|
313
|
-
- `allPages?` — the lazy route → element map (`PageMap<Pages>`). Prefer registering
|
|
329
|
+
- `allPages?` — the lazy route → element map (`PageMap<Pages>`). Prefer registering via `setAllPages()` from the browser entry when the app also server-renders — the Worker bundle has no code splitting, so a static import inlines every page (and its deps) into `worker.js`.
|
|
314
330
|
- `ssrPages?` — `Partial<{ [K]: ComponentType<Params> }>` of statically-imported components for `ssr: true` routes. Used by both the Worker's `renderToString` and the client's first hydration render so the initial paint resolves synchronously and never mismatches the server output.
|
|
315
331
|
|
|
316
332
|
**`createRouter` returns:**
|
|
@@ -347,8 +363,8 @@ export const allPages = {
|
|
|
347
363
|
- **`lazyPage(factory)`** — lazy-imports a default-exported `React.ComponentType<Params>`. The page receives route params as props.
|
|
348
364
|
- **`lazyPageLoader(factory)`** — lazy-imports an async loader `(params) => Promise<ReactElement>`. Use when a route needs data fetching before render. The loader file is the chunk boundary, so it can statically import its page component.
|
|
349
365
|
|
|
350
|
-
Both wrappers recover from stale-deploy chunk 404s ("Failed to fetch
|
|
351
|
-
imported module"): on the first failure they trigger a single
|
|
366
|
+
Both wrappers recover from stale-deploy chunk 404s ("Failed to fetch
|
|
367
|
+
dynamically imported module"): on the first failure they trigger a single
|
|
352
368
|
`window.location.reload()` (guarded by `sessionStorage` so a genuinely broken
|
|
353
369
|
chunk can't loop) to fetch the fresh `index.html` with new chunk hashes.
|
|
354
370
|
|
|
@@ -387,8 +403,8 @@ match a registered route.
|
|
|
387
403
|
### Popups — `openPopup()`
|
|
388
404
|
|
|
389
405
|
`useRouter().openPopup()` is the canonical modal / sheet / menu API. The
|
|
390
|
-
router owns the popup layer, drives a spring animation
|
|
391
|
-
|
|
406
|
+
router owns the popup layer, drives a spring animation, and stacks popups
|
|
407
|
+
z-index-correctly above every page.
|
|
392
408
|
|
|
393
409
|
```tsx
|
|
394
410
|
const { openPopup } = useRouter();
|
|
@@ -449,7 +465,7 @@ bootstrapApp({
|
|
|
449
465
|
});
|
|
450
466
|
```
|
|
451
467
|
|
|
452
|
-
|
|
468
|
+
**`BootstrapAppOptions`:**
|
|
453
469
|
|
|
454
470
|
| Field | Description |
|
|
455
471
|
|-------|-------------|
|
|
@@ -504,12 +520,11 @@ const {
|
|
|
504
520
|
```
|
|
505
521
|
|
|
506
522
|
`useApp<TAsyncOptions>()` is generic in the async-options type so apps can
|
|
507
|
-
pass a custom option through to a custom `loadingOverlay` element
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
returns
|
|
511
|
-
|
|
512
|
-
prop, and finally to identity.
|
|
523
|
+
pass a custom option through to a custom `loadingOverlay` element. `AppProvider`
|
|
524
|
+
`cloneElement`s the overlay with `{ label, asyncOptions }` while `runAsync` is
|
|
525
|
+
pending. `useAppOptional()` returns `null` outside the provider; `useLocalizer()`
|
|
526
|
+
returns a localizer that prefers `<StringsProvider>` data, falls back to the
|
|
527
|
+
`AppProvider` `localizer` prop, and finally to identity.
|
|
513
528
|
|
|
514
529
|
Two popup APIs coexist: `useRouter().openPopup()` (spring-animated,
|
|
515
530
|
dismissible, mode-aware — the default choice) and `useApp().showPopup()` (a
|
|
@@ -575,7 +590,7 @@ Any GET request with `?token=<JWT>` will, if the token verifies, set the
|
|
|
575
590
|
cookie and 302-redirect to the same URL without the token parameter — useful
|
|
576
591
|
for embedding any page in an iframe.
|
|
577
592
|
|
|
578
|
-
### Built-in routes
|
|
593
|
+
### Built-in auth routes
|
|
579
594
|
|
|
580
595
|
| Endpoint | Description |
|
|
581
596
|
|----------|-------------|
|
|
@@ -597,7 +612,7 @@ configurator.setAuth({
|
|
|
597
612
|
});
|
|
598
613
|
```
|
|
599
614
|
|
|
600
|
-
### Server-side helpers
|
|
615
|
+
### Server-side auth helpers
|
|
601
616
|
|
|
602
617
|
- `verifyToken(token)` — verifies a token against ugly.bot and returns the `userId`.
|
|
603
618
|
- `getRequestUser(req)` — synchronous decode of the per-project `UGLY_PROJECT_TOKEN` cookie set by ugly.bot's wake-on-traffic gate. Returns `{ userId } | null` without a network round-trip; safe as the primary auth check in deployed-app handlers.
|
|
@@ -927,7 +942,7 @@ requests automatically tag events with the user's branch assignments.
|
|
|
927
942
|
|
|
928
943
|
---
|
|
929
944
|
|
|
930
|
-
## Built-in endpoints
|
|
945
|
+
## Built-in HTTP endpoints
|
|
931
946
|
|
|
932
947
|
| Endpoint | Description |
|
|
933
948
|
|----------|-------------|
|
|
@@ -955,6 +970,7 @@ requests automatically tag events with the user's branch assignments.
|
|
|
955
970
|
| `ugly-app/shared` | Cross-tier: `defineRequests`, `defineCollections`, `definePage`, `defineWorkers`, Zod, experiments, time constants. |
|
|
956
971
|
| `ugly-app/client` | React: `bootstrapApp`, `createRouter`, `lazyPage`, `AppProvider`, components, animations, audio, AI helpers. |
|
|
957
972
|
| `ugly-app/server/adapter/workers` | Cloudflare Workers entry (Hono router + Durable Objects + Neon HTTP driver + R2). |
|
|
973
|
+
| `ugly-app/server/ssr` | SSR renderer used by the Workers adapter. |
|
|
958
974
|
| `ugly-app/conversation/{shared,server,client,engine}` | AI chat sessions with persisted history. |
|
|
959
975
|
| `ugly-app/collab/{server,client}` | Yjs-based collaborative editing. |
|
|
960
976
|
| `ugly-app/markdown/{shared,client}` | Markdown rendering + editor. |
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../../src/cli/publish/orchestrator.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../../src/cli/publish/orchestrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -2248,7 +2248,21 @@ export async function runPublish(input) {
|
|
|
2248
2248
|
// Register Cron Triggers + attach the queue consumer now that the
|
|
2249
2249
|
// script exists (both reference the deployed worker by name).
|
|
2250
2250
|
if (queueId) {
|
|
2251
|
-
|
|
2251
|
+
const queueCfg = readUglyAppConfig(input.projectPath)?.queue;
|
|
2252
|
+
await cloudflare.ensureQueueConsumer(cloudflareToken, state.cloudflare.accountId, queueId, input.appName, {
|
|
2253
|
+
...(queueCfg?.maxConcurrency !== undefined
|
|
2254
|
+
? { maxConcurrency: queueCfg.maxConcurrency }
|
|
2255
|
+
: {}),
|
|
2256
|
+
...(queueCfg?.batchSize !== undefined
|
|
2257
|
+
? { batchSize: queueCfg.batchSize }
|
|
2258
|
+
: {}),
|
|
2259
|
+
...(queueCfg?.maxRetries !== undefined
|
|
2260
|
+
? { maxRetries: queueCfg.maxRetries }
|
|
2261
|
+
: {}),
|
|
2262
|
+
...(queueCfg?.maxWaitTimeMs !== undefined
|
|
2263
|
+
? { maxWaitTimeMs: queueCfg.maxWaitTimeMs }
|
|
2264
|
+
: {}),
|
|
2265
|
+
});
|
|
2252
2266
|
}
|
|
2253
2267
|
// Always PUT schedules (empty array clears stale triggers).
|
|
2254
2268
|
await cloudflare.putCronTriggers(cloudflareToken, state.cloudflare.accountId, input.appName, cronSchedules);
|