@blotout/qinto-cli 0.1.11 → 0.1.13
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 +95 -0
- package/dist/index.js +4156 -3496
- package/dist/index.js.map +1 -1
- package/dist/worker-artifact/main/index.js +318 -174
- package/dist/worker-artifact/version.json +4 -4
- package/dist/worker-artifact/wfp/index.js +17 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -223,6 +223,10 @@ callee's page, exactly as a site manager does on a deployed site.
|
|
|
223
223
|
An app folder added or removed while `dev` is running is not picked up — it says so and asks for a restart. A save inside a
|
|
224
224
|
mounted app rebuilds that app alone.
|
|
225
225
|
|
|
226
|
+
Declared `server.schedules` fire on their own while `dev` runs — at the cron's minute, in UTC, with `scheduledTime` set to that
|
|
227
|
+
instant, exactly as the deployed sweep dispatches them. Each schedule on the app's console page also has a **Run now** button,
|
|
228
|
+
so you never wait for the window.
|
|
229
|
+
|
|
226
230
|
Three surfaces, one per side of the product:
|
|
227
231
|
|
|
228
232
|
- **The console** is the platform's side. A team and the site `dev.localhost` are seeded for you; every mounted app is listed
|
|
@@ -259,10 +263,101 @@ are namespaced by its slug, so two apps declaring a `d1` called `ledger` get a d
|
|
|
259
263
|
| `--worker-port <port>` | Port the local site worker listens on (default `4310`). |
|
|
260
264
|
| `--ui-port <port>` | Port the app panels are served from (default `4302`). |
|
|
261
265
|
| `--reset` | Discard this directory's local installs, variables, secrets and stored data first. |
|
|
266
|
+
| `--tunnel` | Expose the site worker on a fresh `trycloudflare.com` hostname, so a vendor webhook can reach its endpoints. |
|
|
267
|
+
| `--tunnel-name <name>` | Expose it through this named Cloudflare Tunnel instead, for a hostname that survives a restart. |
|
|
262
268
|
| `--no-input` | Disable all interactive prompts, mounting every app found. |
|
|
263
269
|
|
|
264
270
|
All four listeners bind `127.0.0.1` only.
|
|
265
271
|
|
|
272
|
+
**Reaching your endpoints from outside — `--tunnel`.** A vendor webhook cannot call `127.0.0.1`, so `--tunnel` opens a
|
|
273
|
+
Cloudflare Tunnel to the site worker and prints the public origin; the console's Endpoints card then leads with the URL to
|
|
274
|
+
register with the vendor and keeps the loopback one beside it for `curl`.
|
|
275
|
+
|
|
276
|
+
```
|
|
277
|
+
Anyone who has this URL can:
|
|
278
|
+
· call your app’s ungated endpoints
|
|
279
|
+
· make your app code run against real vendor APIs, with your dev variables and secrets
|
|
280
|
+
· reach whatever the site worker passes through
|
|
281
|
+
|
|
282
|
+
Restrict it with Cloudflare Access on a named tunnel (--tunnel-name) if that matters here.
|
|
283
|
+
|
|
284
|
+
Opening a Cloudflare Tunnel to the site worker — this usually takes 20-40 seconds.
|
|
285
|
+
· downloading cloudflared 2026.8.3…
|
|
286
|
+
· starting cloudflared…
|
|
287
|
+
· connecting to the Cloudflare edge…
|
|
288
|
+
· publishing odd-mule-hits-yet.trycloudflare.com in DNS…
|
|
289
|
+
|
|
290
|
+
Site worker http://127.0.0.1:4310
|
|
291
|
+
Public site https://odd-mule-hits-yet.trycloudflare.com
|
|
292
|
+
! anyone holding this URL reaches your dev site worker
|
|
293
|
+
|
|
294
|
+
My App (my-app) — installed and active on the seeded site
|
|
295
|
+
POST https://odd-mule-hits-yet.trycloudflare.com/app/my-app/hook
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
`cloudflared` is downloaded and cached on first use, unless you already have one on `PATH` or at `CLOUDFLARED_PATH`.
|
|
299
|
+
|
|
300
|
+
**The tunnel closes after an hour.** It is a public door onto your machine, and an `app dev` left running overnight would hold it
|
|
301
|
+
open until you noticed. `dev` says how long is left every ten minutes; press `a` then Enter to add an hour, up to three hours from
|
|
302
|
+
now. When it closes, the public URL stops being advertised and the loopback one carries on.
|
|
303
|
+
|
|
304
|
+
**A hostname that survives a restart — `--tunnel-name <name>`.** A quick tunnel is free and needs no account, but its hostname is
|
|
305
|
+
new on every run, so a vendor has to be told the new one each time. A named tunnel keeps one hostname. `dev` reads it from **your
|
|
306
|
+
own Cloudflare account**, never from anything Qinto holds.
|
|
307
|
+
|
|
308
|
+
In the Cloudflare dashboard, create a tunnel and give it a **public hostname pointing at `http://127.0.0.1:4310`** — the port
|
|
309
|
+
`--worker-port` sets. Then run `qinto app dev --tunnel-name <name>`. The first time, `dev` asks for the two things it needs and
|
|
310
|
+
tells you how to make them:
|
|
311
|
+
|
|
312
|
+
```
|
|
313
|
+
A named tunnel is read from your own Cloudflare account, and qinto has no credentials for it yet.
|
|
314
|
+
|
|
315
|
+
1. Open https://dash.cloudflare.com/profile/api-tokens
|
|
316
|
+
2. Select Create Token, then Create Custom Token.
|
|
317
|
+
3. Under Permissions, add one row: Account > Cloudflare Tunnel > Edit
|
|
318
|
+
That is the only permission qinto needs. Do not add more.
|
|
319
|
+
4. Under Account Resources, select the account that holds the tunnel.
|
|
320
|
+
5. Create the token and copy it — Cloudflare shows it once.
|
|
321
|
+
|
|
322
|
+
Your account ID is the last part of the dashboard URL:
|
|
323
|
+
https://dash.cloudflare.com/<account-id>
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
They are saved in **`~/.qinto/cloudflare.json`**, readable only by you, and every later run uses them without asking. They are
|
|
327
|
+
written only **after Cloudflare accepts them**, so a mistyped token is asked for again rather than stored and reported as a tunnel
|
|
328
|
+
fault. Delete that file to enter different ones. `CLOUDFLARE_ACCOUNT_ID` and `CLOUDFLARE_API_TOKEN` in the environment override the
|
|
329
|
+
saved pair and overwrite nothing — that is how CI, or a second account, runs. Set **both or neither**: one on its own is refused
|
|
330
|
+
rather than paired with a credential from somewhere else. `--no-input`, and a run with no terminal, say what to set instead of
|
|
331
|
+
prompting.
|
|
332
|
+
|
|
333
|
+
`dev` looks the tunnel up by name and runs it on the token it fetched. cloudflared reads ingress rules top to bottom and stops at
|
|
334
|
+
the first match, so the rule that decides a hostname is often not the rule naming it — an earlier catch-all, wildcard, or
|
|
335
|
+
same-hostname rule takes the request first. A hostname is advertised only when **every rule that can take it points at your worker
|
|
336
|
+
port, ending in one that carries no path**. A rule with a `path` takes some requests and leaves the rest to the rules below it, and
|
|
337
|
+
that path is a regex `dev` cannot evaluate, so one pointing elsewhere is refused rather than guessed at — it may be the rule that
|
|
338
|
+
takes your `/app/...` URLs. Wildcards are never offered: `https://*.example.com` is not something a vendor can call, though it still
|
|
339
|
+
decides the hostnames it covers. Every advertised hostname is then checked in DNS, not just the first. A tunnel that routes nothing
|
|
340
|
+
usable is refused, and the message lists its rules in the order cloudflared reads them. A tunnel created locally
|
|
341
|
+
with `cloudflared tunnel create` has no configuration in the dashboard, so it lands in the same message — configure it there
|
|
342
|
+
instead. `CLOUDFLARE_*` and `TUNNEL_*` are both kept out of cloudflared's own environment: it is given the tunnel token and
|
|
343
|
+
nothing else, so a stray variable cannot redirect the tunnel and your account token is never handed to a process with no use for
|
|
344
|
+
it.
|
|
345
|
+
|
|
346
|
+
**Your own cloudflared setup is left alone, and not used.** `dev` runs cloudflared against a config file of its own, because an
|
|
347
|
+
existing `~/.cloudflared/config.yml` would otherwise win: its `ingress` rules override the `--url` `dev` passes, and the tunnel
|
|
348
|
+
would answer that config's catch-all — a 404 on every webhook — instead of the site worker.
|
|
349
|
+
|
|
350
|
+
**Why it takes 20-40 seconds.** `dev` names each thing it is waiting for, and the wait is deliberate. A fresh
|
|
351
|
+
`trycloudflare.com` hostname is minted about five seconds before DNS publishes it, and `trycloudflare.com` tells resolvers to
|
|
352
|
+
remember a miss for **1800 seconds** — so one lookup a moment too early makes the hostname fail for the next half hour, for you
|
|
353
|
+
and for the vendor you gave it to. `dev` therefore waits for cloudflared to register a connection, then asks the zone's own
|
|
354
|
+
nameservers whether the name exists yet. Those answer from zone data, so the wait itself leaves nothing behind in any cache your
|
|
355
|
+
browser, `curl` or the vendor will read. By the time the URL is printed it works on the first request. The tunnel closes when
|
|
356
|
+
`dev` does.
|
|
357
|
+
|
|
358
|
+
**Only the site worker is exposed** — the same worker, and the same code, that faces the internet on a deployed site. The console
|
|
359
|
+
is never tunneled: it installs apps and shows your variables, and it answers a loopback `Host` and nothing else.
|
|
360
|
+
|
|
266
361
|
Two things behave differently from a deployed site, and `dev` says so rather than letting you discover them:
|
|
267
362
|
|
|
268
363
|
- **`ai`, `vectorize`, and a `hyperdrive` with no local database URL are not bound.** Each needs a Cloudflare account or a
|