@vibes.diy/prompts 14.1.16 → 14.1.17

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/llms/backend.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export const backendConfig = {
2
2
  name: "backend",
3
3
  label: "backend-js",
4
- description: "server-side backend.js file: answer HTTP/webhook requests at the app's /_api URL, react to committed data changes, and run scheduled jobs — its writes go through the app's own access rules; sends a record on to another service through a Zapier Catch Hook when the person asks for Zapier",
4
+ description: "server-side backend.js file: answer HTTP/webhook requests at the app's /_api URL, react to committed data changes, and run scheduled jobs — its writes go through the app's own access rules; reads a web page, feed or API the person names and hands it to the page through /_api; sends a record on to another service through a Zapier Catch Hook when the person asks for Zapier",
5
5
  cues: ["zapier", "catch hook"],
6
6
  };
7
7
  //# sourceMappingURL=backend.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"backend.js","sourceRoot":"","sources":["../../jsr/llms/backend.ts"],"names":[],"mappings":"AAUA,MAAM,CAAC,MAAM,aAAa,GAAc;IACtC,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,YAAY;IACnB,WAAW,EACT,gSAAgS;IAMlS,IAAI,EAAE,CAAC,QAAQ,EAAE,YAAY,CAAC;CAC/B,CAAC"}
1
+ {"version":3,"file":"backend.js","sourceRoot":"","sources":["../../jsr/llms/backend.ts"],"names":[],"mappings":"AAUA,MAAM,CAAC,MAAM,aAAa,GAAc;IACtC,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,YAAY;IACnB,WAAW,EACT,uXAAuX;IAMzX,IAAI,EAAE,CAAC,QAAQ,EAAE,YAAY,CAAC;CAC/B,CAAC"}
package/llms/backend.md CHANGED
@@ -601,6 +601,81 @@ From `App.jsx`, call it with a relative fetch — no host needed:
601
601
  const res = await fetch("/_api/rsvp", { method: "POST", body: JSON.stringify({ name }) });
602
602
  ```
603
603
 
604
+ ### Reading a page the person names — the `/_api` proxy
605
+
606
+ A page the person names is read in `backend.js` and handed to the app through `/_api`. A browser
607
+ reaches its own app and the hosts that publish CORS headers, so an ordinary web page — somebody's
608
+ homepage, a blog post, a competitor's landing page — is readable from a handler and from nowhere
609
+ else. This is the shape for every "scan this site", "check this URL", "summarize this page" ask:
610
+ the handler takes the address, reads it with `ctx.fetch`, strips the markup to text, and answers
611
+ with what it measured. Repeat reads of the same address come back from the read cache (about five
612
+ minutes), so a person re-scanning a site pays for one read.
613
+
614
+ The handler settles the address before reading it. The platform reads `https:` hosts, so an
615
+ address typed without a scheme, or with `http:`, is normalized to `https:` and anything else comes
616
+ back as a stated refusal rather than a thrown handler — a refusal the app can show is worth more
617
+ than a policy error the app has to guess at.
618
+
619
+ `ok` means TEXT CAME BACK. A 200 that strips to nothing — a page that renders itself in the
620
+ browser, a consent wall, a host answering with an empty body — is a read that produced no page, so
621
+ it answers `ok: false` with a reason. That is what makes `page.ok` a sound thing for the app to
622
+ branch on: a score or a summary is only ever computed from text the handler actually returned.
623
+
624
+ backend.js
625
+
626
+ ```js
627
+ export async function fetch(request, ctx) {
628
+ const url = new URL(request.url);
629
+ if (url.pathname === "/page") {
630
+ const typed = (url.searchParams.get("url") ?? "").trim();
631
+ let parsed;
632
+ try {
633
+ parsed = new URL(/^[a-z]+:/i.test(typed) ? typed : `https://${typed}`);
634
+ } catch {
635
+ return Response.json({ ok: false, reason: "that does not look like a web address" }, { status: 400 });
636
+ }
637
+ // The platform reads https hosts, so http is normalized rather than refused.
638
+ if (parsed.protocol === "http:") parsed.protocol = "https:";
639
+ if (parsed.protocol !== "https:") {
640
+ return Response.json({ ok: false, reason: "only web pages can be read" }, { status: 400 });
641
+ }
642
+ const res = await ctx.fetch(parsed.href, { headers: { accept: "text/html" } });
643
+ const html = await res.text();
644
+ // Script and style bodies first — their contents are not page text — then the tags themselves.
645
+ const text = html
646
+ .replace(/<(script|style)\b[^>]*>[\s\S]*?<\/\1>/gi, " ")
647
+ .replace(/<[^>]+>/g, " ")
648
+ .replace(/\s+/g, " ")
649
+ .trim()
650
+ .slice(0, 20000);
651
+ // A page that came back with no readable text is a read that produced no page.
652
+ if (res.ok === false || text.length === 0) {
653
+ const reason = res.ok ? "that page returned nothing we could read" : `that page answered ${res.status}`;
654
+ return Response.json({ ok: false, status: res.status, reason });
655
+ }
656
+ const title = /<title[^>]*>([\s\S]*?)<\/title>/i.exec(html)?.[1]?.trim() ?? "";
657
+ return Response.json({ ok: true, status: res.status, title, text });
658
+ }
659
+ return new Response("not found", { status: 404 });
660
+ }
661
+ ```
662
+
663
+ From `App.jsx`, the page asks the handler for the address it was given:
664
+
665
+ ```js
666
+ const res = await fetch(`/_api/page?url=${encodeURIComponent(url)}`);
667
+ const page = await res.json();
668
+ if (page.ok === false) {
669
+ setResult({ read: false, reason: page.reason });
670
+ return; // nothing is scored, summarized or graded from a page that was not read
671
+ }
672
+ setResult({ read: true, ...(await scorePage(page.title, page.text)) });
673
+ ```
674
+
675
+ The refusal lands where the result would have gone — "we could not read that page: it returned
676
+ nothing we could read" — so the person sees the read fail instead of a number computed from
677
+ nothing.
678
+
604
679
  ## onChange — react to committed writes
605
680
 
606
681
  **When the request says a record is kept on the server, or that the server reacts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibes.diy/prompts",
3
- "version": "14.1.16",
3
+ "version": "14.1.17",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "exports": {
@@ -34,9 +34,9 @@
34
34
  "license": "Apache-2.0",
35
35
  "dependencies": {
36
36
  "@adviser/cement": "~0.5.34",
37
- "@vibes.diy/call-ai-v2": "14.1.16",
38
- "@vibes.diy/identity": "14.1.16",
39
- "@vibes.diy/use-vibes-types": "14.1.16",
37
+ "@vibes.diy/call-ai-v2": "14.1.17",
38
+ "@vibes.diy/identity": "14.1.17",
39
+ "@vibes.diy/use-vibes-types": "14.1.17",
40
40
  "arktype": "~2.2.3",
41
41
  "json-schema-faker": "~0.6.3"
42
42
  },
@@ -188,6 +188,10 @@ When someone reports that their app won't open ("App not available", a blank scr
188
188
 
189
189
  Static assets. Files the maker added in the Files tab (or pushed with the CLI) are part of the app and are listed in the context as `assets:`. Reference them by absolute path from the app root — `<img src="/logo.png" alt="…">`, `<audio src="/intro.mp3">`, `fetch("/data.csv")` — never by an external URL and never by inlining bytes. If the maker asks for an image the app does not have, say which file to add rather than inventing a path.
190
190
 
191
+ ### Reading a page the person names
192
+
193
+ When an app works on the contents of a URL the person types — scanning it, checking it, scoring it, summarizing it — that address is read server-side: a `backend.js` `fetch` handler reads it with `ctx.fetch` and the page asks `/_api/…` for the text, because a page in a browser reaches its own app and the hosts that invite it. If that read comes back empty or fails, the app says so where the result goes, before anything worked out without it appears.
194
+
191
195
  ## End every turn with one improvement question
192
196
 
193
197
  After your code edits, end your response with exactly ONE short improvement question and 2–4 multiple-choice options.
@@ -190,6 +190,10 @@ When someone reports that their app won't open ("App not available", a blank scr
190
190
 
191
191
  Static assets. Files the maker added in the Files tab (or pushed with the CLI) are part of the app and are listed in the context as `assets:`. Reference them by absolute path from the app root — `<img src="/logo.png" alt="…">`, `<audio src="/intro.mp3">`, `fetch("/data.csv")` — never by an external URL and never by inlining bytes. If the maker asks for an image the app does not have, say which file to add rather than inventing a path.
192
192
 
193
+ ### Reading a page the person names
194
+
195
+ When an app works on the contents of a URL the person types — scanning it, checking it, scoring it, summarizing it — that address is read server-side: a `backend.js` `fetch` handler reads it with `ctx.fetch` and the page asks `/_api/…` for the text, because a page in a browser reaches its own app and the hosts that invite it. If that read comes back empty or fails, the app says so where the result goes, before anything worked out without it appears.
196
+
193
197
  ## End every turn with one improvement question
194
198
 
195
199
  After your code edits, end your response with exactly ONE short improvement question and 2–4 multiple-choice options.
package/system-prompt.md CHANGED
@@ -752,6 +752,10 @@ When someone reports that their app won't open ("App not available", a blank scr
752
752
 
753
753
  Static assets. Files the maker added in the Files tab (or pushed with the CLI) are part of the app and are listed in the context as `assets:`. Reference them by absolute path from the app root — `<img src="/logo.png" alt="…">`, `<audio src="/intro.mp3">`, `fetch("/data.csv")` — never by an external URL and never by inlining bytes. If the maker asks for an image the app does not have, say which file to add rather than inventing a path.
754
754
 
755
+ ### Reading a page the person names
756
+
757
+ When an app works on the contents of a URL the person types — scanning it, checking it, scoring it, summarizing it — that address is read server-side: a `backend.js` `fetch` handler reads it with `ctx.fetch` and the page asks `/_api/…` for the text, because a page in a browser reaches its own app and the hosts that invite it. If that read comes back empty or fails, the app says so where the result goes, before anything worked out without it appears.
758
+
755
759
  ## End every turn with one improvement question
756
760
 
757
761
  After your code edits, end your response with exactly ONE short improvement question and 2–4 multiple-choice options.