@somewhere-cloud/cli 0.38.0 → 0.38.1

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.
@@ -4,39 +4,35 @@ import { SKILLS_DIR, skillNames } from './skills-pack.js';
4
4
  // docs lint byte-compares this value when SOMEWHERE_CLI_REPO points here.
5
5
  export const AGENT_WORKFLOW = `## Getting started — build, deploy, verify
6
6
 
7
- \`somewhere init --name <slug>\` creates a React + TypeScript app; no login needed.
8
- Default: sign-in UI. Minimal: SDK and auth route. Bare: neither. \`init --catalog --json\` lists \`--features\` modules.
9
- \`npx @somewhere-cloud/cli deploy\` publishes a temporary app and prints its live
10
- URL, claim URL and expiry. Login is needed for account-owned operations,
11
- the email test inbox and cron. On a hosted VM, \`somewhere login\` uses browser approval and keeps you signed in.
7
+ \`somewhere init --name <slug>\` writes React + TypeScript. Signed out: local only;
8
+ signed in: also creates and links a project.
9
+ Default: sign-in UI; minimal: SDK/auth route; bare: neither. \`init --catalog --json\`: modules.
10
+ \`npx @somewhere-cloud/cli deploy\` publishes raw source: signed out, a temporary URL, claim URL
11
+ and expiry; linked, your account project. On a hosted VM, \`somewhere login\` uses browser approval and keeps you signed in.
12
+ Account operations, test inbox and cron need login.
12
13
  Start auth/data/cron with \`somewhere docs recipe-signed-in-app --full\`.
13
14
 
14
15
  After edits: \`somewhere typecheck\` and focused local/browser tests. Publish:
15
16
  1. \`somewhere deploy\` (do not build first). Deploy
16
- checks compilation, schema and secrets, refusing a blank page
17
- before going live; \`somewhere deploy-check\` runs them without publishing
17
+ checks compilation, schema and secrets; \`somewhere deploy-check\` runs them without publishing
18
18
  (diagnosis, review, \`--run /api/x\`).
19
- 2. Run \`somewhere verify\` once on the final deployed journey (or
20
- \`--flow flow.json\`); rerun after fixes. Sign test users up
19
+ 2. Run \`somewhere verify\` on the final journey (\`--flow flow.json\`); rerun after fixes. Sign test users up
21
20
  in-app at \`*.test.somewhere.site\`; more: \`actors\` + \`journey\` (\`somewhere docs browser\`).
22
- 3. \`somewhere browser\` inspects a page; \`somewhere logs --tail 10\`, then
23
- \`somewhere errors\`: read the failure first.
21
+ 3. Inspect: \`somewhere browser\`; diagnose: \`somewhere logs --tail 10\`, \`somewhere errors\`.
24
22
  4. Test mail: \`somewhere email test-inbox <addr>\` includes \`verification_code\`.
25
23
  Don't retest sign-in or \`sw.db.from\` scoping; test each table's scope, auth before \`sw.db.server\`/raw SQL, bad input and journeys.
26
24
 
27
- Routes: \`index.html\` loads \`src/main.tsx\`; every extensionless path with no file
28
- (\`/signin\`) serves \`index.html\`, so one app routes by \`location.pathname\`.
25
+ Routes: \`index.html\` loads \`src/main.tsx\`; unmatched extensionless paths
26
+ (\`/signin\`) serve it. Route the app by \`location.pathname\`.
29
27
  \`api/notes/[id].ts\` is \`/api/notes/:id\`; \`_\`-prefixed names are import-only
30
- helpers. Avoid names differing only in letter case (\`SignIn.tsx\`, \`signin.tsx\`).
28
+ helpers. Avoid names differing only in case.
31
29
 
32
30
  With auth enabled, \`api/auth/[...path].ts\` is
33
31
  \`export { somewhereAuth as default } from '@somewhere-cloud/sdk/server'\`; pages
34
- use \`createSomewhereAuth()\` from \`@somewhere-cloud/sdk/auth\` (no SDK:
35
- \`docs({ topic: 'auth-client' })\`). \`auth.signUp({ email, password,
32
+ use \`createSomewhereAuth()\` from \`@somewhere-cloud/sdk/auth\` (client and React hooks:
33
+ \`somewhere docs auth-client --section react-auth-state\`). \`auth.signUp({ email, password,
36
34
  displayName? })\` / \`auth.signIn({ email, password })\` return the user or throw
37
- with the message. Gate pages on \`auth.getState().status\` (React:
38
- \`useAuthState()\`) as the auth starter's \`src/App.tsx\` does. Sign-up signs the user
39
- in with \`email_verified: false\`; unverified users can sign in and pass
35
+ with the message. Gate on \`auth.getState().status\` (React: \`useAuthState()\`). Sign-up sets \`email_verified: false\`; unverified users pass
40
36
  \`auth: 'required'\`. \`sw.auth.requireUser(req)\` returns \`{ id, email,
41
37
  role, email_verified, … }\` or throws 401 \`AUTH_REQUIRED\`;
42
38
  \`sw.auth.fromRequest(req)\` returns it or \`null\`.
@@ -47,10 +43,13 @@ async ({ body, user, params }, sw) => value })\`; set \`auth\` (\`'required'\`,
47
43
  function (req, sw)\` returning a \`Response\`. Params: \`params.id\` there,
48
44
  \`sw.params.id\` bare; \`somewhere typecheck\` types bare handlers too.
49
45
 
50
- Data: declare tables in \`db/schema.ts\`; pages use \`somewhere:data\`
46
+ Data: \`id()\` is a random text key; use \`text()\` for references to it.
47
+ Declare tables in \`db/schema.ts\`; pages use \`somewhere:data\`
51
48
  (\`data.notes.list()\`, \`.create()\`, \`.update(id, …)\`) without API files.
52
49
  Use \`owner()\` for personal rows, \`group()\` for invited teams, \`appRole()\`
53
50
  for app-wide roles, \`anyOf()\` for owner or a role, \`allOf()\` for members-only rows.
51
+ Booking/help desk: \`somewhere docs sw.db --section provider-or-booker-and-owner-or-staff-recipes\`.
52
+ Keep fitting scopes when an exceptional write needs \`sw.db.server.tx\`.
54
53
  \`shared()\` gives signed-in reads and creator-only writes. \`client\` sets browser
55
54
  columns; \`publicRead: { where }\` admits visitors. Public-profile enquiries use
56
55
  \`client.intake\` (\`somewhere docs declared-data\`). Keep scopes and grants;
@@ -68,8 +67,7 @@ await sw.db.server.insert('entries', { user_id: profile.user_id, owner_email: pr
68
67
  title: title.trim(), from_email, created_ms: Date.now() });
69
68
  \`\`\`
70
69
 
71
- The owner comes from that lookup, never the body; the sender is not the
72
- owner. Rate limits and the alert are in \`somewhere docs recipe-signed-in-app\`.
70
+ Use the looked-up owner, never the body. Rate limits/alerts: \`recipe-signed-in-app\`.
73
71
  Use \`serverOnly()\` only when every operation needs a function's own access check.
74
72
  Structured queries: \`sw.db.from\` / \`insert\` / \`update\` / \`remove\` return \`{ data: rows[], count,
75
73
  changes }\`; \`where: { a: 1, b: { in: ids }, c: { gte: 2 }, d: null }\` (one
@@ -1 +1 @@
1
- {"version":3,"file":"init-agent-guide.js","sourceRoot":"","sources":["../../src/lib/init-agent-guide.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE1D,2EAA2E;AAC3E,0EAA0E;AAC1E,MAAM,CAAC,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8E7B,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,aAAa,UAAU,QAAQ;MACzD,UAAU,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;MACvE,oJAAoJ,CAAC;AAEzJ,MAAM,CAAC,MAAM,cAAc,GAAG,uCAAuC,cAAc,KAAK,cAAc,IAAI,CAAC;AAC3G,MAAM,CAAC,MAAM,cAAc,GAAG,4CAA4C,CAAC"}
1
+ {"version":3,"file":"init-agent-guide.js","sourceRoot":"","sources":["../../src/lib/init-agent-guide.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE1D,2EAA2E;AAC3E,0EAA0E;AAC1E,MAAM,CAAC,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4E7B,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,aAAa,UAAU,QAAQ;MACzD,UAAU,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;MACvE,oJAAoJ,CAAC;AAEzJ,MAAM,CAAC,MAAM,cAAc,GAAG,uCAAuC,cAAc,KAAK,cAAc,IAAI,CAAC;AAC3G,MAAM,CAAC,MAAM,cAAc,GAAG,4CAA4C,CAAC"}
@@ -127,11 +127,17 @@ the greeting message; add caller authorization before serving private data.
127
127
  The SDK and \`api/auth/[...path].ts\` are included; add your sign-in UI or use
128
128
  \`somewhere init --template auth\` for the complete sign-in screens.
129
129
 
130
- When replacing the greeting, remove its page/service files and mark its
131
- already-deployed table with \`greetings: removedTable()\` in the schema (import
132
- \`removedTable\` from \`somewhere/db\`). A deploy retires it with the normal
133
- 30-day retention; deleting the declaration alone is refused. Remove an unused
134
- \`types/app.ts\` too. A missing optional include directory is harmless.
130
+ When replacing the greeting, remove its page/service files. If this table has
131
+ never been deployed, delete its schema declaration. If it has been deployed,
132
+ use \`greetings: removedTable()\` (import \`removedTable\` from \`somewhere/db\`);
133
+ the deploy retires it with 30-day retention, even if it is empty. Remove an
134
+ unused \`types/app.ts\` too. A missing optional include directory is harmless.
135
+
136
+ The greeting's \`serverOnly()\` scope demonstrates a trusted public endpoint;
137
+ it is not the default for your app's data. Choose fitting declared access
138
+ before the first deploy: \`owner()\` for personal rows, \`group()\` for teams,
139
+ and \`anyOf()\` for combined access. Read \`somewhere docs sw.db --section
140
+ provider-or-booker-and-owner-or-staff-recipes\` for booking and help-desk rules.
135
141
 
136
142
  \`\`\`sh
137
143
  somewhere typecheck
@@ -1 +1 @@
1
- {"version":3,"file":"init-green-template.js","sourceRoot":"","sources":["../../src/lib/init-green-template.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvE,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;CAqBpB,CAAC;AAEF,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;CAchB,CAAC;AAEF,MAAM,SAAS,GAAG;;;CAGjB,CAAC;AAEF,MAAM,MAAM,GAAG;;;;;;;;;;CAUd,CAAC;AAEF,MAAM,GAAG,GAAG;;;;;;;;CAQX,CAAC;AAEF,MAAM,OAAO,GAAG;;;;;;;CAOf,CAAC;AAEF,MAAM,GAAG,GAAG;;;;;;;;;;;;;;;;;;;;;;;CAuBX,CAAC;AAEF,MAAM,IAAI,GAAG;;;;;;;;;;CAUZ,CAAC;AAEF,MAAM,MAAM,GAAG;;;;;;;;;;;;;;CAcd,CAAC;AAEF,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;CAwBd,CAAC;AAEF,MAAM,UAAU,mBAAmB;IACjC,OAAO;QACL,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,yJAAyJ,EAAE;QAC1L,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE;QAC9C,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE;QAC9C,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE;QACtC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,YAAY,EAAE;QAC/C,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,EAAE;QAC5C;YACE,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE,oUAAoU;SAC9U;QACD,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,GAAG,EAAE;QACrC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE;QACvC,EAAE,IAAI,EAAE,0BAA0B,EAAE,OAAO,EAAE,OAAO,EAAE;QACtD,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE;QAC3C,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,GAAG,EAAE;QACzC,EAAE,IAAI,EAAE,uBAAuB,EAAE,OAAO,EAAE,2EAA2E,EAAE;QACvH,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE;QACzC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE;KAC7C,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"init-green-template.js","sourceRoot":"","sources":["../../src/lib/init-green-template.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvE,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;CAqBpB,CAAC;AAEF,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;CAchB,CAAC;AAEF,MAAM,SAAS,GAAG;;;CAGjB,CAAC;AAEF,MAAM,MAAM,GAAG;;;;;;;;;;CAUd,CAAC;AAEF,MAAM,GAAG,GAAG;;;;;;;;CAQX,CAAC;AAEF,MAAM,OAAO,GAAG;;;;;;;CAOf,CAAC;AAEF,MAAM,GAAG,GAAG;;;;;;;;;;;;;;;;;;;;;;;CAuBX,CAAC;AAEF,MAAM,IAAI,GAAG;;;;;;;;;;CAUZ,CAAC;AAEF,MAAM,MAAM,GAAG;;;;;;;;;;;;;;CAcd,CAAC;AAEF,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8Bd,CAAC;AAEF,MAAM,UAAU,mBAAmB;IACjC,OAAO;QACL,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,yJAAyJ,EAAE;QAC1L,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE;QAC9C,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE;QAC9C,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE;QACtC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,YAAY,EAAE;QAC/C,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,EAAE;QAC5C;YACE,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE,oUAAoU;SAC9U;QACD,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,GAAG,EAAE;QACrC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE;QACvC,EAAE,IAAI,EAAE,0BAA0B,EAAE,OAAO,EAAE,OAAO,EAAE;QACtD,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE;QAC3C,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,GAAG,EAAE;QACzC,EAAE,IAAI,EAAE,uBAAuB,EAAE,OAAO,EAAE,2EAA2E,EAAE;QACvH,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE;QACzC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE;KAC7C,CAAC;AACJ,CAAC"}
@@ -1,8 +1,8 @@
1
1
  export const BUNDLED_SKILLS_PACK = {
2
2
  "schema": 1,
3
3
  "name": "somewhere-skills",
4
- "version": "1+99a80fef6c66",
5
- "sha256": "99a80fef6c661de10a31aceeed4c1c908fc4a4a7705207dc7f6ceeac5a20299b",
4
+ "version": "1+a9b0d6a4b518",
5
+ "sha256": "a9b0d6a4b5185d8088357c156a7b5b222ebbbd31639113120818998488bcef50",
6
6
  "files": [
7
7
  {
8
8
  "path": "deploy-verify-loop/SKILL.md",
@@ -11,13 +11,13 @@ export const BUNDLED_SKILLS_PACK = {
11
11
  },
12
12
  {
13
13
  "path": "schema-changes/SKILL.md",
14
- "sha256": "bb6cacd237c2706bd5477b72d5979fbb971b9c0584ca43968bfa56a97259b079",
15
- "content": "---\nname: schema-changes\ndescription: Before adding, changing, or removing a table or column in db/schema.ts.\n---\n\n# Change the database schema safely\n\n## The file is the contract\n\nThe default `somewhere init` starter has no `db/schema.ts`: create it at the project root, or start with `somewhere init --features private-data`, which includes one.\n\n```ts\n// db/schema.ts\nimport { id, owner, schema, table, text, timestamp } from 'somewhere/db';\n\nexport default schema({\n notes: table(\n {\n id: id(),\n title: text(),\n body: text({ default: '' }),\n created_at: timestamp({ default: 'now' }),\n },\n {\n scope: owner(),\n client: {\n read: ['id', 'title', 'body', 'created_at'],\n create: ['title', 'body'],\n update: ['title', 'body'],\n delete: true,\n },\n },\n ),\n});\n```\n\nA table without a `client` block can't be reached from the browser at all.\n\nDeclare a file collection in `db/schema.ts`: who may upload, read, replace and delete its files.\n\n| `somewhere typecheck [dir]` | `--json`, `--deploy`, `--watch`, `--hook <host>` | Run `tsc --noEmit` over the project. `--deploy`: the deploy's narrower reference check, no `tsconfig.json` needed. `--watch` re-checks on save; never deploys. `--hook` is what `somewhere hooks install` runs. It regenerates `__somewhere_data.d.ts` and `__somewhere_files.d.ts` from `db/schema.ts`; CLI 0.37.47+ starters `.gitignore` them. |\n\n## What a deploy does with it\n\n- **Additive changes apply**: a new table, a new nullable-or-defaulted column, a new index, a new unique group. Unchanged schema is a no-op.\n- **Unmarked removals and shape changes refuse** with `409 SCHEMA_DEPLOY_REFUSED` and a message naming the change.\n- **Removing a table** is `old_table: removedTable()`.\n- once the new version is live it retires the table and keeps its data for 30 days.\n- a production deploy or a promotion that would remove or rename a column is refused before anything changes, so a running release never loses a column it uses. Keep the column declared and leave its data in place.\n\n## Failure: raw SQL refused after the schema file deploys\n\nOn an older shared database, ordinary `sw.db.query` / `sw.db.batch` fail before transport with `MANAGED_RAW_SQL_REQUIRES_SERVER_AUTHORITY`, including in job, queue, and cron handlers; with a separate SQL database they run there and never see declared tables. Fix: write with `sw.db.insert` / `sw.db.update` / `sw.db.remove` (the table needs a declared intent)\n\nSources (`somewhere docs <topic>`): cli, declared-data, declared-files, getting-started, sw.db, troubleshooting.\n"
14
+ "sha256": "1b215b59474cec396c53c1fdbc3432b5b3a21f3fa8909580f1d18c640e0f746f",
15
+ "content": "---\nname: schema-changes\ndescription: Before adding, changing, or removing a table or column in db/schema.ts.\n---\n\n# Change the database schema safely\n\n## The file is the contract\n\nThe default `somewhere init` starter has no `db/schema.ts`: create it at the project root, or start with `somewhere init --features private-data`, which includes one.\n\n```ts\n// db/schema.ts\nimport { id, owner, schema, table, text, timestamp } from 'somewhere/db';\n\nexport default schema({\n notes: table(\n {\n id: id(),\n title: text(),\n body: text({ default: '' }),\n created_at: timestamp({ default: 'now' }),\n },\n {\n scope: owner(),\n client: {\n read: ['id', 'title', 'body', 'created_at'],\n create: ['title', 'body'],\n update: ['title', 'body'],\n delete: true,\n },\n },\n ),\n});\n```\n\nA table without a `client` block can't be reached from the browser at all.\n\nBefore the first deploy, delete an unused starter table declaration outright: there is no deployed table to retire. After a table has been deployed, use `removedTable()` as described above, including when the table is empty.\n\nDeclare a file collection in `db/schema.ts`: who may upload, read, replace and delete its files.\n\nRun `somewhere typecheck` before deploying schema changes.\n\n## What a deploy does with it\n\n- **Additive changes apply**: a new table, a new nullable-or-defaulted column, a new index, a new unique group. Unchanged schema is a no-op.\n- **Unmarked removals and shape changes refuse** with `409 SCHEMA_DEPLOY_REFUSED` and a message naming the change.\n- **Removing a table** is `old_table: removedTable()`.\n- once the new version is live it retires the table and keeps its data for 30 days.\n- a production deploy or a promotion that would remove or rename a column is refused before anything changes, so a running release never loses a column it uses. Keep the column declared and leave its data in place.\n\n## Failure: raw SQL refused after the schema file deploys\n\nOn an older shared database, ordinary `sw.db.query` / `sw.db.batch` fail before transport with `MANAGED_RAW_SQL_REQUIRES_SERVER_AUTHORITY`, including in job, queue, and cron handlers; with a separate SQL database they run there and never see declared tables. Fix: write with `sw.db.insert` / `sw.db.update` / `sw.db.remove` (the table needs a declared intent)\n\nSources (`somewhere docs <topic>`): declared-data, declared-files, getting-started, sw.db, troubleshooting.\n"
16
16
  },
17
17
  {
18
18
  "path": "sign-in-setup/SKILL.md",
19
- "sha256": "f8d0099c91d7740e868807ed56355cfe3f4d9d8205ca8417a8a9645fed05a6ee",
20
- "content": "---\nname: sign-in-setup\ndescription: When the app needs users to sign up, sign in, or sign out.\n---\n\n# Set up sign-in\n\n## Server: one route file\n\n`login` / `signup` are developer-key-gated (the browser can't call them), so one server route mediates them and sets the session cookies.\n\n```ts\n// api/auth/[...path].ts\nexport { somewhereAuth as default } from '@somewhere-cloud/sdk/server';\n```\n\nIt serves `POST /signup`, `/login`, `/logout`, `/magic-link`, `/magic-link/verify`, `GET /me`, and the Google/GitHub/Discord `GET /<provider>-url` + `POST /<provider>` code exchange.\n\n## Page: the SDK client\n\n```bash\nnpm i @somewhere-cloud/sdk\n```\n\n```ts\n// src/auth.ts — page code\nimport { createSomewhereAuth } from '@somewhere-cloud/sdk/auth'\n\nexport const auth = createSomewhereAuth()\n\n// Call from your sign-up form; throws AuthError with the message on failure.\nexport async function signUp(email: string, password: string) {\n await auth.signUp({ email, password }) // or auth.signIn({ email, password })\n return auth.getUser() // the signed-in user, or null\n}\nexport async function signOut() {\n await auth.signOut();\n if (auth.getState().signOutUnconfirmed) {\n throw new Error('Sign-out could not be confirmed. Please try again.');\n }\n // Only navigate or reload after confirmed logout.\n}\n```\n\nAwait `signOut()` in the click handler before navigating or reloading. While it is pending, keep the current screen or show a disabled signing-out state. Do not use the appearance of a signed-out form as proof that the server session has ended. After awaiting, check `auth.getState().signOutUnconfirmed`; show a retry message when true. `signOut()` can settle without confirming server logout.\n\nCalls to your own `api/*` functions just send `credentials: 'include'`.\n\nDon't write `getCookie()` / token-parsing helpers → `sw.auth.fromRequest(req)` reads cookie + Bearer header and returns the validated user (or null) in one call.\n\nMail to `<name>@<project>.test.somewhere.site` is read with `somewhere email test-inbox <address>`.\n\n## Failure 1: sign-in errors\n\nexpected failures (wrong password, duplicate email, weak password) come back as structured 4xx with the real message, never an opaque 500.\n\n## Failure 2: AUTH_REQUIRED from an owner() table\n\nThe table is user-owned, so the platform scopes it to a principal, and this request had none: there is no signed-in user, and this table does not declare `owner({ visitors: true })`, which is the declaration that accepts a stable anonymous visitor identity.\n\nSources (`somewhere docs <topic>`): auth-client, common-mistakes, recipe-signed-in-app, sdk, troubleshooting.\n"
19
+ "sha256": "6b729ec43cf5572321ba4cd7ff4eccb28c35ebacb925d22ef1b8fb0eca4c5093",
20
+ "content": "---\nname: sign-in-setup\ndescription: When the app needs users to sign up, sign in, or sign out.\n---\n\n# Set up sign-in\n\n## Server: one route file\n\n`login` / `signup` are developer-key-gated (the browser can't call them), so one server route mediates them and sets the session cookies.\n\n```ts\n// api/auth/[...path].ts\nexport { somewhereAuth as default } from '@somewhere-cloud/sdk/server';\n```\n\nIt serves `POST /signup`, `/login`, `/logout`, `/magic-link`, `/magic-link/verify`, `GET /me`, and the Google/GitHub/Discord `GET /<provider>-url` + `POST /<provider>` code exchange.\n\n## Client and React state reference\n\nRead `docs({ topic: 'auth-client', section: 'react-auth-state' })` for the SDK's React state contract. Extend the starter's existing provider and auth client.\n\n## Page: the SDK client\n\n```bash\nnpm i @somewhere-cloud/sdk\n```\n\n```ts\n// src/auth.ts — page code\nimport { createSomewhereAuth } from '@somewhere-cloud/sdk/auth'\n\nexport const auth = createSomewhereAuth()\n\n// Call from your sign-up form; throws AuthError with the message on failure.\nexport async function signUp(email: string, password: string) {\n await auth.signUp({ email, password }) // or auth.signIn({ email, password })\n return auth.getUser() // the signed-in user, or null\n}\nexport async function signOut() {\n await auth.signOut();\n if (auth.getState().signOutUnconfirmed) {\n throw new Error('Sign-out could not be confirmed. Please try again.');\n }\n // Only navigate or reload after confirmed logout.\n}\n```\n\nAwait `signOut()` in the click handler before navigating or reloading. While it is pending, keep the current screen or show a disabled signing-out state. Do not use the appearance of a signed-out form as proof that the server session has ended. After awaiting, check `auth.getState().signOutUnconfirmed`; show a retry message when true. `signOut()` can settle without confirming server logout.\n\nCalls to your own `api/*` functions just send `credentials: 'include'`.\n\nDon't write `getCookie()` / token-parsing helpers → `sw.auth.fromRequest(req)` reads cookie + Bearer header and returns the validated user (or null) in one call.\n\nMail to `<name>@<project>.test.somewhere.site` is read with `somewhere email test-inbox <address>`.\n\n## Failure 1: sign-in errors\n\nexpected failures (wrong password, duplicate email, weak password) come back as structured 4xx with the real message, never an opaque 500.\n\n## Failure 2: AUTH_REQUIRED from an owner() table\n\nThe table is user-owned, so the platform scopes it to a principal, and this request had none: there is no signed-in user, and this table does not declare `owner({ visitors: true })`, which is the declaration that accepts a stable anonymous visitor identity.\n\nSources (`somewhere docs <topic>`): auth-client, common-mistakes, recipe-signed-in-app, sdk, troubleshooting.\n"
21
21
  },
22
22
  {
23
23
  "path": "troubleshooting/SKILL.md",
@@ -1 +1 @@
1
- {"version":3,"file":"skills-pack.generated.js","sourceRoot":"","sources":["../../src/lib/skills-pack.generated.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,MAAM,mBAAmB,GAAe;IAC7C,QAAQ,EAAE,CAAC;IACX,MAAM,EAAE,kBAAkB;IAC1B,SAAS,EAAE,gBAAgB;IAC3B,QAAQ,EAAE,kEAAkE;IAC5E,OAAO,EAAE;QACP;YACE,MAAM,EAAE,6BAA6B;YACrC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,mnEAAmnE;SAC/nE;QACD;YACE,MAAM,EAAE,yBAAyB;YACjC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,6mFAA6mF;SACznF;QACD;YACE,MAAM,EAAE,wBAAwB;YAChC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,ypFAAypF;SACrqF;QACD;YACE,MAAM,EAAE,0BAA0B;YAClC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,s2DAAs2D;SACl3D;QACD;YACE,MAAM,EAAE,kCAAkC;YAC1C,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,uvEAAuvE;SACnwE;QACD;YACE,MAAM,EAAE,+BAA+B;YACvC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,k3DAAk3D;SAC93D;QACD;YACE,MAAM,EAAE,iBAAiB;YACzB,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,65FAA65F;SACz6F;KACF;CACF,CAAC"}
1
+ {"version":3,"file":"skills-pack.generated.js","sourceRoot":"","sources":["../../src/lib/skills-pack.generated.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,MAAM,mBAAmB,GAAe;IAC7C,QAAQ,EAAE,CAAC;IACX,MAAM,EAAE,kBAAkB;IAC1B,SAAS,EAAE,gBAAgB;IAC3B,QAAQ,EAAE,kEAAkE;IAC5E,OAAO,EAAE;QACP;YACE,MAAM,EAAE,6BAA6B;YACrC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,mnEAAmnE;SAC/nE;QACD;YACE,MAAM,EAAE,yBAAyB;YACjC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,g+EAAg+E;SAC5+E;QACD;YACE,MAAM,EAAE,wBAAwB;YAChC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,k2FAAk2F;SAC92F;QACD;YACE,MAAM,EAAE,0BAA0B;YAClC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,s2DAAs2D;SACl3D;QACD;YACE,MAAM,EAAE,kCAAkC;YAC1C,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,uvEAAuvE;SACnwE;QACD;YACE,MAAM,EAAE,+BAA+B;YACvC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,k3DAAk3D;SAC93D;QACD;YACE,MAAM,EAAE,iBAAiB;YACzB,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,65FAA65F;SACz6F;KACF;CACF,CAAC"}
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@somewhere-cloud/cli",
3
- "version": "0.38.0",
3
+ "version": "0.38.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@somewhere-cloud/cli",
9
- "version": "0.38.0",
9
+ "version": "0.38.1",
10
10
  "bundleDependencies": [
11
11
  "@modelcontextprotocol/sdk",
12
12
  "chokidar",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@somewhere-cloud/cli",
3
- "version": "0.38.0",
3
+ "version": "0.38.1",
4
4
  "description": "CLI for somewhere.cloud — auth, projects, deploy, pull, promote, db, logs, env, MCP bridge.",
5
5
  "keywords": [
6
6
  "somewhere",