@trypattern/sdk 0.1.14 → 0.1.16

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 CHANGED
@@ -117,7 +117,7 @@ email, phone, address, notes, status }` with `status` `requested`, `accepted`, `
117
117
  shows the live photos without storing them. With
118
118
  `pages` (`definePages(tables, { '/': head, '/items/:itemId': { head, paths } })` in
119
119
  `server/pages.ts`) it renders the `<head>` of public pages: each `head` reads tables anyone may
120
- read (`rows`, `row`, `photoUrl`) and returns `{ title, description, image, hero, jsonLd, data }`
120
+ read (`rows`, `row`, `photoUrl`), and `appTitle()` gives the site's name as the owner set it, and returns `{ title, description, image, hero, jsonLd, data }`
121
121
  (or `null` for a 404). The Worker puts the title, description, canonical link, `og:*` (the image
122
122
  at 1200×630 with `fit=cover`), `twitter:card`, JSON-LD, a preload of the `hero` with `Image`'s
123
123
  srcset, and `data` as `<script type="application/json" id="pattern-data">` into the built
package/dist/cli/app.js CHANGED
@@ -310,7 +310,7 @@ and restore sign in the same way when they need to, so this is rarely run on its
310
310
  summary: 'Download a site from onpattern.app and install it, ready for app start',
311
311
  details: `app pull acmeflower
312
312
  Downloads the source of the site's latest live version into this folder when it is empty, or into
313
- ./<name> otherwise, writes pattern.json, installs, and runs app setup. Never needs git; when the
313
+ ./<name> otherwise (./<name>-2 and on when that folder already has files), writes pattern.json, installs, and runs app setup. Never needs git; when the
314
314
  Command Line Tools are installed it also makes a first commit. Signs in first if needed (see app login).
315
315
  --code <setup code> signs in with the one-time setup code from onpattern.app instead of the browser.`,
316
316
  run: (argument, options) => {
@@ -252,7 +252,12 @@ function isInsideHome(path) {
252
252
  function folderFor(name, cwd) {
253
253
  if (isInsideHome(cwd) && cwd !== homedir() && isEmptyFolder(cwd))
254
254
  return cwd;
255
- return join(isInsideHome(cwd) ? cwd : homedir(), name);
255
+ const base = join(isInsideHome(cwd) ? cwd : homedir(), name);
256
+ for (let number = 1;; number += 1) {
257
+ const folder = number === 1 ? base : `${base}-${number}`;
258
+ if (!existsSync(folder) || isEmptyFolder(folder))
259
+ return folder;
260
+ }
256
261
  }
257
262
  async function hasPnpm(io, cwd) {
258
263
  return (await io.run('pnpm', ['--version'], cwd)).code === 0;
@@ -285,13 +290,6 @@ export async function pull(io, name, cwd, setupCode) {
285
290
  }
286
291
  sayHost(io);
287
292
  const target = folderFor(name, cwd);
288
- if (target !== cwd && existsSync(target) && !isEmptyFolder(target)) {
289
- return {
290
- code: 1,
291
- data: { error: 'folder not empty', folder: target },
292
- text: `✗ ${target} already has files in it. Pull into an empty folder.`
293
- };
294
- }
295
293
  try {
296
294
  if (setupCode !== undefined)
297
295
  await useSetupCode(io, setupCode);
@@ -348,7 +346,7 @@ export async function pull(io, name, cwd, setupCode) {
348
346
  await io.run('git', ['add', '-A'], target);
349
347
  await io.run('git', ['commit', '-q', '-m', `Version ${result.number} from onpattern.app`], target);
350
348
  }
351
- const next = result.isStarter
349
+ const next = result.isStarter || result.app.pulledAt === null
352
350
  ? firstChange(result.title, result.app.url, target)
353
351
  : `cd into ${target}, read AGENTS.md, then ./app start`;
354
352
  return {
@@ -14,6 +14,7 @@ export type PageRequest<Group extends Tables> = {
14
14
  rows: <Name extends ReadableName<Group>>(table: Name) => Promise<readonly Row<Group[Name]>[]>;
15
15
  row: <Name extends ReadableName<Group>>(table: Name, id: string) => Promise<Row<Group[Name]> | undefined>;
16
16
  photoUrl: (image: MediaImage) => string;
17
+ appTitle: () => Promise<string>;
17
18
  };
18
19
  export type PageHero = {
19
20
  image: MediaImage;
@@ -49,6 +50,7 @@ type AnyRequest = {
49
50
  rows: (table: string) => Promise<readonly unknown[]>;
50
51
  row: (table: string, id: string) => Promise<unknown>;
51
52
  photoUrl: (image: MediaImage) => string;
53
+ appTitle: () => Promise<string>;
52
54
  };
53
55
  type PageRoute = {
54
56
  pattern: string;
@@ -71,6 +71,7 @@ function readableTable(pages, name) {
71
71
  function requestFor(c, pages, params) {
72
72
  const url = new URL(c.req.url);
73
73
  const read = new Map();
74
+ let title;
74
75
  return {
75
76
  url,
76
77
  params,
@@ -81,7 +82,11 @@ function requestFor(c, pages, params) {
81
82
  return found;
82
83
  },
83
84
  row: (name, id) => readRow(c.env.DB, readableTable(pages, name), id),
84
- photoUrl: (image) => `${url.origin}${mediaPath(image.key)}`
85
+ photoUrl: (image) => `${url.origin}${mediaPath(image.key)}`,
86
+ appTitle: () => {
87
+ title ??= readTitle(c.env.DB);
88
+ return title;
89
+ }
85
90
  };
86
91
  }
87
92
  function escapeHtml(text) {
@@ -217,7 +222,7 @@ export async function renderPage(c, pages, route, params) {
217
222
  try {
218
223
  head = await route.head(request);
219
224
  if (head !== null) {
220
- tags = headTags(pages, request.url, await readTitle(c.env.DB), head);
225
+ tags = headTags(pages, request.url, await request.appTitle(), head);
221
226
  }
222
227
  }
223
228
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trypattern/sdk",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",