@trypattern/sdk 0.1.1 → 0.1.3

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.
@@ -85,7 +85,8 @@ export class HttpSessionApi {
85
85
  });
86
86
  }
87
87
  startGoogleSignIn() {
88
- location.assign('/api/auth/google');
88
+ const next = `${location.pathname}${location.search}`;
89
+ location.assign(`/api/auth/google?next=${encodeURIComponent(next)}`);
89
90
  }
90
91
  onSignedOut(listener) {
91
92
  this.#signedOutListeners.add(listener);
@@ -1,5 +1,5 @@
1
1
  import { spawnSync } from 'node:child_process';
2
- import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
2
+ import { chmodSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
3
3
  import { homedir, hostname, userInfo } from 'node:os';
4
4
  import { basename, dirname, extname, join, matchesGlob, relative } from 'node:path';
5
5
  import { z } from 'zod';
@@ -14,6 +14,9 @@ const POLL_MS = 2000;
14
14
  const LOGIN_WAIT_MS = 120_000;
15
15
  const PUBLISH_WAIT_MS = 300_000;
16
16
  const SESSION_COOKIE = 'pattern_session';
17
+ const LAUNCHER = 'app';
18
+ const STARTER_WORKSPACE = 'pnpm-workspace.yaml';
19
+ const STARTER_BUILD_SETTINGS = 'allowBuilds:\n esbuild: false\n workerd: false\n';
17
20
  const IGNORED_IN_EMPTY_FOLDER = new Set(['.DS_Store', '.claude']);
18
21
  const MIME_TYPES = {
19
22
  '.html': 'text/html',
@@ -222,6 +225,15 @@ export async function login(io) {
222
225
  function isEmptyFolder(path) {
223
226
  return readdirSync(path).every((entry) => IGNORED_IN_EMPTY_FOLDER.has(entry));
224
227
  }
228
+ function isInsideHome(path) {
229
+ const fromHome = relative(homedir(), path);
230
+ return !fromHome.startsWith('..') && !fromHome.startsWith('/');
231
+ }
232
+ function folderFor(name, cwd) {
233
+ if (isInsideHome(cwd) && cwd !== homedir() && isEmptyFolder(cwd))
234
+ return cwd;
235
+ return join(isInsideHome(cwd) ? cwd : homedir(), name);
236
+ }
225
237
  function commandLineToolsReady() {
226
238
  return spawnSync('xcode-select', ['-p'], { stdio: 'ignore' }).status === 0;
227
239
  }
@@ -233,7 +245,7 @@ export async function pull(io, name, cwd) {
233
245
  text: '✗ Which site? app pull sundayparty'
234
246
  };
235
247
  }
236
- const target = isEmptyFolder(cwd) ? cwd : join(cwd, name);
248
+ const target = folderFor(name, cwd);
237
249
  if (target !== cwd && existsSync(target) && !isEmptyFolder(target)) {
238
250
  return {
239
251
  code: 1,
@@ -269,6 +281,8 @@ export async function pull(io, name, cwd) {
269
281
  writeFileSync(destination, Buffer.from(await value.arrayBuffer()));
270
282
  files += 1;
271
283
  }
284
+ if (existsSync(join(target, LAUNCHER)))
285
+ chmodSync(join(target, LAUNCHER), 0o755);
272
286
  writeFileSync(join(target, PROJECT_FILE), `${JSON.stringify({ name, title: result.title }, null, 2)}\n`);
273
287
  io.say(`✓ Downloaded ${files} files of version ${result.number}`);
274
288
  const install = await io.run('pnpm', ['install'], target);
@@ -284,11 +298,11 @@ export async function pull(io, name, cwd) {
284
298
  await io.run('git', ['add', '-A'], target);
285
299
  await io.run('git', ['commit', '-q', '-m', `Version ${result.number} from onpattern.app`], target);
286
300
  }
287
- const moved = target === cwd ? '' : `\n folder ${target} (open this folder in Claude)`;
301
+ const moved = `\n folder ${target}`;
288
302
  return {
289
303
  code: 0,
290
304
  data: { name, folder: target, version: result.number, files },
291
- text: `✓ ${result.title} is on this computer${moved}\n next read AGENTS.md, then app start`
305
+ text: `✓ ${result.title} is on this computer${moved}\n next cd into that folder, read AGENTS.md, then ./app start`
292
306
  };
293
307
  }
294
308
  catch (error) {
@@ -368,6 +382,9 @@ function uploadForm(root, io, isStarter) {
368
382
  form.append(`${UPLOAD.migrations}${file}`, fileBlob(join(migrations, file)), file);
369
383
  }
370
384
  const sources = sourceFiles(root);
385
+ if (isStarter && !sources.includes(STARTER_WORKSPACE)) {
386
+ form.append(`${UPLOAD.source}${STARTER_WORKSPACE}`, new Blob([STARTER_BUILD_SETTINGS], { type: 'text/yaml' }), STARTER_WORKSPACE);
387
+ }
371
388
  for (const path of sources) {
372
389
  const full = join(root, path);
373
390
  const contents = isStarter && path === 'package.json'
@@ -29,7 +29,10 @@ function randomToken() {
29
29
  .replaceAll('=', '');
30
30
  }
31
31
  function safePath(path) {
32
- return path !== undefined && path.startsWith('/') && !path.startsWith('//')
32
+ return path !== undefined &&
33
+ path.startsWith('/') &&
34
+ !path.startsWith('//') &&
35
+ !path.includes('\\')
33
36
  ? path
34
37
  : '/';
35
38
  }
package/dist/vite/vite.js CHANGED
@@ -11,6 +11,35 @@ import { localWorker } from "./localWorker.js";
11
11
  import { readProjectFile } from "./projectFile.js";
12
12
  import { rootAlias } from "./rootAlias.js";
13
13
  const DEV_SERVER_PORT = 5173;
14
+ const BROWSER_DEPENDENCIES = [
15
+ 'react',
16
+ 'react/jsx-runtime',
17
+ 'react/jsx-dev-runtime',
18
+ 'react-dom',
19
+ 'react-dom/client',
20
+ 'react-router',
21
+ 'react-router/dom',
22
+ 'zod',
23
+ '@stylexjs/stylex',
24
+ ...[
25
+ 'avatar',
26
+ 'button',
27
+ 'context-menu',
28
+ 'dialog',
29
+ 'field',
30
+ 'menu',
31
+ 'radio-group',
32
+ 'radio',
33
+ 'select',
34
+ 'separator',
35
+ 'switch',
36
+ 'tooltip'
37
+ ].map((part) => `@base-ui/react/${part}`)
38
+ ];
39
+ const sdkCompiledByStyleXButItsDependenciesPrebundled = {
40
+ exclude: ['@trypattern/sdk'],
41
+ include: BROWSER_DEPENDENCIES.map((dependency) => `@trypattern/sdk > ${dependency}`)
42
+ };
14
43
  const VISUAL_FLOW_TIMEOUT_MS = 30_000;
15
44
  const CSS_LAYERS_BEFORE_STYLEX = ['reset'];
16
45
  const browsersWithNativeLightDark = {
@@ -58,7 +87,7 @@ export function pattern({ tables, admins, seed = {}, world = {} }) {
58
87
  designFile()
59
88
  ],
60
89
  clearScreen: false,
61
- optimizeDeps: { exclude: ['@trypattern/sdk'] },
90
+ optimizeDeps: sdkCompiledByStyleXButItsDependenciesPrebundled,
62
91
  build: {
63
92
  cssTarget: ['chrome123', 'firefox120', 'safari17.5']
64
93
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trypattern/sdk",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",