@somewhere-tech/cli 0.37.8 → 0.37.10

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.
@@ -1,13 +1,13 @@
1
1
  export const BUNDLED_SKILLS_PACK = {
2
2
  "schema": 1,
3
3
  "name": "somewhere-skills",
4
- "version": "1+46ccaa5adb17",
5
- "sha256": "46ccaa5adb176861262dd34f446fb2e4c0b3d900ce4fc72a895ee14d002e4467",
4
+ "version": "1+3394a026e6f8",
5
+ "sha256": "3394a026e6f8d3d4553af8b97605ad40f8e035d769e33bbf23fb4fd5263f61d1",
6
6
  "files": [
7
7
  {
8
8
  "path": "deploy-verify-loop/SKILL.md",
9
- "sha256": "e90d0f4861b160ccde0fb9e7179cfbac2fb0c9ad2696323c1d11a086cca2a4f7",
10
- "content": "---\nname: deploy-verify-loop\ndescription: After every change: deploy the raw source, check the live app, and read logs or errors before guessing at a fix.\n---\n\n# Deploy, verify, read the failure\n\n## The loop\n\n```bash\nsomewhere typecheck\nsomewhere deploy\n```\n\nDon't bundle the source yourself; the platform runs the frontend build.\n\n```bash\nsomewhere deploy-check --run /api/hello -X POST -d '{\"name\":\"Ada\"}'\n```\n\n| Step | Command | What it tells you |\n|---|---|---|\n| Verify | `somewhere verify [--flow flow.json]` | Runs the live app at desktop and phone sizes: named steps, console/network health, both screenshots. |\n| Inspect | `somewhere browser [target]` | One page: screenshot, snapshot, DOM, network, or an evaluated expression. |\n| Diagnose | `somewhere logs --tail 10`, `somewhere errors` | Recent function output, then failures split into refused and exception. `errors` needs a claimed project and a signed-in account. |\n\n## A flow for verify --flow\n\n```json\n{ \"actions\": [{ \"fill\": \"#title\", \"value\": \"Verify entry\" }, { \"fill\": \"#from_email\", \"value\": \"v@example.com\" },\n { \"click\": \"#send\" }, { \"expect\": { \"selector\": \"#status\", \"text\": \"Received\" } }], \"viewports\": [\"desktop\", \"mobile\"] }\n```\n\n`passed` requires successful steps and request expectations, no page errors, and no unexpected failed requests. It can be false even when every step succeeded.\n\n## Failure 1: the live site still shows the old version\n\nBrowser or CDN cache. Hard-reload (Cmd-Shift-R), or check with `curl -sI https://{subdomain}.somewhere.site`.\n\n## Failure 2: a route fails\n\nShow recent failures with a `kind` column: **refused** for a 4xx your own handler returned on purpose, **exception** for an uncaught throw or a 5xx.\n\nThe `stack` field is the single most useful field for debugging — it tells you the exact file + line in your code where the throw originated.\n\n| `somewhere rollback [project]` | `-y, --yes`, `--json` | Select the previous retained production release. |\n\nSources (`somewhere docs <topic>`): browser, cli, common-mistakes, getting-started, recipe-signed-in-app, troubleshooting.\n"
9
+ "sha256": "a00ce22447da1c70678de35f696cc81f976fbb0b56d832fa55edf2802fd8271e",
10
+ "content": "---\nname: deploy-verify-loop\ndescription: After every change: deploy the raw source, check the live app, and read logs or errors before guessing at a fix.\n---\n\n# Deploy, verify, read the failure\n\n## The loop\n\n```bash\nsomewhere typecheck\nsomewhere deploy\n```\n\nDon't bundle the source yourself; the platform runs the frontend build.\n\n```bash\nsomewhere deploy-check --run /api/hello -X POST -d '{\"name\":\"Ada\"}'\n```\n\n| Step | Command | What it tells you |\n|---|---|---|\n| Verify | `somewhere verify [--flow flow.json]` | Runs the live app at desktop and phone sizes: named steps, console/network health, both screenshots. |\n| Inspect | `somewhere browser [target]` | One page: screenshot, snapshot, DOM, network, or an evaluated expression. |\n| Diagnose | `somewhere logs --tail 10`, `somewhere errors` | Recent function output, then failures split into refused and exception. `errors` also works on a temporary project. |\n\n## A flow for verify --flow\n\n```json\n{ \"actions\": [{ \"fill\": \"#title\", \"value\": \"Verify entry\" }, { \"fill\": \"#from_email\", \"value\": \"v@example.com\" },\n { \"click\": \"#send\" }, { \"expect\": { \"selector\": \"#status\", \"text\": \"Received\" } }], \"viewports\": [\"desktop\", \"mobile\"] }\n```\n\n`passed` requires successful steps and request expectations, no page errors, and no unexpected failed requests. It can be false even when every step succeeded.\n\n## Failure 1: the live site still shows the old version\n\nBrowser or CDN cache. Hard-reload (Cmd-Shift-R), or check with `curl -sI https://{subdomain}.somewhere.site`.\n\n## Failure 2: a route fails\n\nShow recent failures with a `kind` column: **refused** for a 4xx your own handler returned on purpose, **exception** for an uncaught throw or a 5xx.\n\nThe `stack` field is the single most useful field for debugging — it tells you the exact file + line in your code where the throw originated.\n\n| `somewhere rollback [project]` | `-y, --yes`, `--json` | Select the previous retained production release. |\n\nSources (`somewhere docs <topic>`): browser, cli, common-mistakes, getting-started, recipe-signed-in-app, troubleshooting.\n"
11
11
  },
12
12
  {
13
13
  "path": "schema-changes/SKILL.md",
@@ -26,13 +26,13 @@ export const BUNDLED_SKILLS_PACK = {
26
26
  },
27
27
  {
28
28
  "path": "realtime-and-background/SKILL.md",
29
- "sha256": "ffa18344dae04bb1cefb78d5b8bb0a3911fcea553f8db1aa6179935a4573bd8c",
30
- "content": "---\nname: realtime-and-background\ndescription: When the page must update without a reload, users need audio/video, or work must run outside one request.\n---\n\n# Live views, call rooms, jobs, queues, cron\n\n## Live view: the page updates when rows change\n\n`sw.db.live(name, sw.db.from(...))` is the live path a signed-in browser can subscribe to.\n\n```ts\n// api/open-notes.ts — the declaration and the SELECT stay server-side\nexport default async function (_req, sw) {\n return Response.json(await sw.db.live('notes.open', sw.db.from('notes', {\n where: { done: false },\n columns: ['id', 'title', 'done', 'created_at'],\n order: [['created_at', 'desc'], ['id', 'asc']],\n limit: 20,\n })))\n}\n\n// browser — the loader re-calls the function, never the database\nimport { watchLive } from '/__sw/live/client.js'\n\nconst stop = watchLive(\n () => fetch('/api/open-notes', { credentials: 'include' }).then(r => r.json()),\n (rows) => render(rows),\n)\n```\n\n## Call room: audio and video\n\nBuild video calling, screen sharing, or live audio rooms.\n\n## Job: slow work with a status\n\nQueue work that shouldn't block a user request. Make handlers idempotent — they may run more than once.\n\n```ts\nconst job = await sw.jobs.create({\n handler: '/api/jobs/summarize-notes',\n idempotency_key: `summary:${user.id}:${operationId}`,\n // user_id comes from the verified session, so the handler can trust it.\n payload: { summary_id: `${user.id}:${operationId}`, user_id: user.id },\n});\n```\n\n```ts\nif (!(await sw.jobs.verifyInvocation(req))) {\n return Response.json({ error: 'forbidden' }, { status: 403 })\n}\n```\n\n## Queue: fire and forget\n\nFor fire-and-forget tasks where you don't need to inspect status later. Use sw.jobs if you DO need to look up the result.\n\n## Cron: on a schedule\n\nSchedules run on Builder and higher. The finest granularity is one minute: a 5-field expression has no seconds field.\n\n```js\ncron_create({\n project_id: \"my-app\",\n schedule: \"0 9 * * *\", // 5-field cron expression\n timezone: \"America/Los_Angeles\", // optional; defaults to UTC\n handler: \"/api/jobs/daily-digest\",\n payload: { segment: \"daily\" } // optional\n})\n```\n\n```bash\nsomewhere cron run cleanup --project <project> --wait # run once now and wait for the result (id or name)\n```\n\n## Failure 1: REALTIME_RETIRED (410) or CHANNEL_FORBIDDEN (403)\n\nCaller-named channels are retired. This is not a configuration problem and there is no flag to turn them on.\n\n## Failure 2: CRON_SCHEDULE_TOO_FREQUENT\n\nA schedule tighter than `min_interval_minutes` is refused when you create or edit it, with `CRON_SCHEDULE_TOO_FREQUENT` naming both intervals.\n\nSources (`somewhere docs <topic>`): calls, cron, live, sw.jobs, sw.queue, troubleshooting.\n"
29
+ "sha256": "762f0082f694ca5a0e6ae11b133d89da8c25e46729697be346fbc19c6e212d31",
30
+ "content": "---\nname: realtime-and-background\ndescription: When the page must update without a reload, users need audio/video, or work must run outside one request.\n---\n\n# Live views, call rooms, jobs, queues, cron\n\n## Live view: the page updates when rows change\n\n`sw.db.live(name, sw.db.from(...))` is the live path a signed-in browser can subscribe to.\n\n```ts\n// api/open-notes.ts — the declaration and the SELECT stay server-side\nexport default async function (_req, sw) {\n return Response.json(await sw.db.live('notes.open', sw.db.from('notes', {\n where: { done: false },\n columns: ['id', 'title', 'done', 'created_at'],\n order: [['created_at', 'desc'], ['id', 'asc']],\n limit: 20,\n })))\n}\n```\n\n## Call room: audio and video\n\nBuild video calling, screen sharing, or live audio rooms.\n\n## Job: slow work with a status\n\nQueue work that shouldn't block a user request. Make handlers idempotent — they may run more than once.\n\n```ts\nconst job = await sw.jobs.create({\n handler: '/api/jobs/summarize-notes',\n idempotency_key: `summary:${user.id}:${operationId}`,\n // user_id comes from the verified session, so the handler can trust it.\n payload: { summary_id: `${user.id}:${operationId}`, user_id: user.id },\n});\n```\n\n```ts\nif (!(await sw.jobs.verifyInvocation(request))) {\n return Response.json({ error: 'forbidden' }, { status: 403 });\n}\n```\n\n## Queue: fire and forget\n\nFor fire-and-forget tasks where you don't need to inspect status later. Use sw.jobs if you DO need to look up the result.\n\n## Cron: on a schedule\n\nSchedules run on every plan. The finest granularity is one minute: a 5-field expression has no seconds field.\n\n```js\ncron_create({\n project_id: \"my-app\",\n schedule: \"0 9 * * *\", // 5-field cron expression\n timezone: \"America/Los_Angeles\", // optional; defaults to UTC\n handler: \"/api/jobs/daily-digest\",\n payload: { segment: \"daily\" } // optional\n})\n```\n\n```bash\nsomewhere cron run cleanup --project <project> --wait # run once now and wait for the result (id or name)\n```\n\n## Failure 1: REALTIME_RETIRED (410) or CHANNEL_FORBIDDEN (403)\n\nCaller-named channels are retired. This is not a configuration problem and there is no flag to turn them on.\n\n## Failure 2: CRON_SCHEDULE_TOO_FREQUENT\n\nA schedule tighter than `min_interval_minutes` is refused when you create or edit it, with `CRON_SCHEDULE_TOO_FREQUENT` naming both intervals.\n\nSources (`somewhere docs <topic>`): calls, cron, live, sw.jobs, sw.queue, troubleshooting.\n"
31
31
  },
32
32
  {
33
33
  "path": "email-and-test-inbox/SKILL.md",
34
- "sha256": "9ede7a39ed5a65dfd06d8f05ffdf0388102536eb3aa36d4157addfdfd897fc6f",
35
- "content": "---\nname: email-and-test-inbox\ndescription: When the app sends email, or you need to test sign-up, magic-link, or reset mail without a real mailbox.\n---\n\n# Send email and read the test inbox\n\n## Send\n\n```ts\nawait sw.email.send({\n to: 'alice@example.com',\n subject: 'Your order shipped',\n html: '<p>Tracking: ABC123</p>',\n reply_to: 'support@yourapp.com' // optional\n})\n```\n\nIt can only email people registered with this project (including pending magic-link sign-ins) or the project's owner. For auth emails (password reset, verification, welcome), the platform sends them automatically — you don't call sw.email for those. Read the current per-tier caps from /v1/pricing instead of copying them into project policy or application code.\n\n## Test inbox\n\nAddresses `<anything>@<project-subdomain>.test.somewhere.site` never reach a real mailbox. Read it with `somewhere email test-inbox <address>` (or `sw.email.inbox(address)`) → `{ address, messages: [{ id, to, subject, text, html, magic_link, created_at }] }`.\n\n## Failure 1: MANAGED_SENDER_RECIPIENT_NOT_A_USER\n\nOther recipients return `MANAGED_SENDER_RECIPIENT_NOT_A_USER`; verify your own sender domain for outreach.\n\n## Failure 2: gating on status 'sent'\n\nDo not gate follow-up work on `status === 'sent'` alone: a captured test send and a replay of a delivered message are both successful sends.\n\nSources (`somewhere docs <topic>`): sw.email.\n"
34
+ "sha256": "440d7f08e21be5d23d9218944b1e80bd4050134b6a8dba36bc789646a5ad1908",
35
+ "content": "---\nname: email-and-test-inbox\ndescription: When the app sends email, or you need to test sign-up, magic-link, or reset mail without a real mailbox.\n---\n\n# Send email and read the test inbox\n\n## Send\n\n```ts\n// api/_lib/order-email.ts — call it from a handler that already checked who\n// receives this; the address comes from your saved order, never the request.\nexport function sendOrderShipped(\n sw: SomewhereRuntimeContext,\n order: { id: string; email: string; trackingNumber: string },\n): Promise<SomewhereEmailSendResult> {\n return sw.email.send({\n to: order.email,\n subject: 'Your order shipped',\n text: `Tracking: ${order.trackingNumber}`, // or html, or both\n reply_to: 'support@yourapp.com', // optional\n idempotency_key: `order-shipped:${order.id}`,\n });\n}\n```\n\nIt can only email people registered with this project (including pending magic-link sign-ins) or the project's owner.\n\n## Test inbox\n\nAddresses `<anything>@<project-subdomain>.test.somewhere.site` never reach a real mailbox. Read it with `somewhere email test-inbox <address>` (or `sw.email.inbox(address)`) → `{ address, messages: [{ id, to, subject, text, html, magic_link, created_at }] }`.\n\n## Failure 1: MANAGED_SENDER_RECIPIENT_NOT_A_USER\n\nOther recipients return `MANAGED_SENDER_RECIPIENT_NOT_A_USER`; verify your own sender domain for outreach.\n\n## Failure 2: gating on status 'sent'\n\nDo not gate follow-up work on `status === 'sent'` alone: a captured test send and a replay of a delivered message are both successful sends.\n\nSources (`somewhere docs <topic>`): sw.email.\n"
36
36
  }
37
37
  ]
38
38
  };
@@ -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,8oEAA8oE;SAC1pE;QACD;YACE,MAAM,EAAE,yBAAyB;YACjC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,ggEAAggE;SAC5gE;QACD;YACE,MAAM,EAAE,wBAAwB;YAChC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,mkEAAmkE;SAC/kE;QACD;YACE,MAAM,EAAE,0BAA0B;YAClC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,gwDAAgwD;SAC5wD;QACD;YACE,MAAM,EAAE,kCAAkC;YAC1C,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,myFAAmyF;SAC/yF;QACD;YACE,MAAM,EAAE,+BAA+B;YACvC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,+5CAA+5C;SAC36C;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,goEAAgoE;SAC5oE;QACD;YACE,MAAM,EAAE,yBAAyB;YACjC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,ggEAAggE;SAC5gE;QACD;YACE,MAAM,EAAE,wBAAwB;YAChC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,mkEAAmkE;SAC/kE;QACD;YACE,MAAM,EAAE,0BAA0B;YAClC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,gwDAAgwD;SAC5wD;QACD;YACE,MAAM,EAAE,kCAAkC;YAC1C,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,6hFAA6hF;SACziF;QACD;YACE,MAAM,EAAE,+BAA+B;YACvC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,8kDAA8kD;SAC1lD;KACF;CACF,CAAC"}
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@somewhere-tech/cli",
3
- "version": "0.37.8",
3
+ "version": "0.37.10",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@somewhere-tech/cli",
9
- "version": "0.37.8",
9
+ "version": "0.37.10",
10
10
  "bundleDependencies": [
11
11
  "@modelcontextprotocol/sdk",
12
12
  "chokidar",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@somewhere-tech/cli",
3
- "version": "0.37.8",
3
+ "version": "0.37.10",
4
4
  "description": "CLI for somewhere.tech — auth, projects, deploy, pull, promote, db, logs, env, MCP bridge.",
5
5
  "keywords": [
6
6
  "somewhere",
@@ -1,18 +1,20 @@
1
1
  {
2
2
  "esbuild": "0.24.0",
3
3
  "source_files": {
4
- "worker/containers/compile/declared-data-contract.cjs": "49db952d33eee0b41583c541abe304a91dbe22207f0309cc480e32a1c9484df5",
5
- "worker/containers/compile/runtime-types.cjs": "0c90ca3404de59f976a74bdaeecef0365888f62b4e0178aad5ad8f4d3b717f6c",
6
- "worker/containers/compile/schema-types.cjs": "2872a80845d0ea1ba806dc98da6b578a19331a94ad4d5c5e66d114b034f8e5fe",
4
+ "worker/containers/compile/declared-data-contract.cjs": "f8a4d1353773f34881aaffbe7ad74aa1eb1458628f2da46cda961e6dd352eb40",
5
+ "worker/containers/compile/runtime-types.cjs": "2ea89ebdf25073a70b69c76cbe78502d8a29f6e89b55323c8bc84ed6651c94eb",
6
+ "worker/containers/compile/schema-types.cjs": "f31099146c91e38e0b526ea4b59b33d4d83f7cdafe79f9805769df850e101848",
7
7
  "worker/containers/compile/typed-data.cjs": "57b458e16a373e42d48a0e527317fcdf609299ae368eb539a8b582b9a47abb15",
8
- "worker/containers/compile/typed-files.cjs": "af198ef42ea3d68df31ade5b146ead89414e5200f144de4268ca9713c382716c",
9
- "worker/src/utils/authority/scope-enforcement.ts": "617d166a0f802dcc6e1cb096b094e7661d0465ea8600c9699aefbe1f865050bc",
8
+ "worker/containers/compile/typed-files.cjs": "0e17085a38d2c40f84849ebdd5c892a838b9d18d6a5111c0b224f4d389872e90",
9
+ "worker/src/utils/authority/scope-enforcement.ts": "77133d3026c26a7a842952221f54703916322dbccb7d744c98e3f69dec56e5f0",
10
+ "worker/src/utils/db-schema-deploy/bigint-text.ts": "ef3f581daeecb234d2c1e288bc09495a6facd7b0354b300134918f6c0cf10cc2",
10
11
  "worker/src/utils/db-schema-deploy/client-contract-source.ts": "92b9fc756f88b9c26159b6e1785bd2229b788bfc1f62af13aed1bc66c277ff14",
11
- "worker/src/utils/db-schema-deploy/client-permissions.ts": "05b1d68afae151569abfa16b452834a96b3c0a2bf4b04f63d322f05548827222",
12
+ "worker/src/utils/db-schema-deploy/client-permissions.ts": "1ec99e9b5e9c575460253f8d4a656228919aca6da09d43065e2b34bcbb633b0c",
12
13
  "worker/src/utils/db-schema-deploy/extract-schema-files.ts": "5923d30040251b3ec4481d38f3f4ddbbd4889129d77bb08843d9dd7992467a0a",
13
14
  "worker/src/utils/db-schema-deploy/extract-schema-relations.ts": "3984683d3227e964845836079476687a7295e6907b525ef21b9eebc488825bf8",
14
- "worker/src/utils/db-schema-deploy/extract-schema-ts.ts": "8280f5c197f83ccb08398b3d45576e1fbd3132b73b52bc4dc643995288fbc94d",
15
+ "worker/src/utils/db-schema-deploy/extract-schema-ts.ts": "405a8d9da80cdb3dbc2dfc93a70e0ed475a93393c14214c9f288b7c58ffd402b",
16
+ "worker/src/utils/db-schema-deploy/schema-constants.ts": "07e648748409207fa4b97367b8942463c047a0bb0e27a36f16f696f90f2b550d",
15
17
  "worker/src/utils/db-schema-deploy/schema-ownership.ts": "e6c811a87bc657707be3518dfe547c6d97718ac073108b126eb7f791c9c08202"
16
18
  },
17
- "sha256": "e3a3bff525d0b6cf1066edaee7307223300ab07441a512b785dabfac2ec31e25"
19
+ "sha256": "786df868aee907143e2b3e9c0497792c5d8eb9bf7d2582860db7ad0107eaba40"
18
20
  }