@mediamonks/canopy-cli 0.7.25 → 0.7.26
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/dist/{db-jmYaum8F.mjs → db-DVMwCLlU.mjs} +2 -2
- package/dist/{deploy-CYKiBnrg.mjs → deploy-CTMcwHhI.mjs} +2 -2
- package/dist/dev-BOvMCaML.mjs +2 -0
- package/dist/{dev-BanjQNiD.mjs → dev-BvjbJcse.mjs} +4 -4
- package/dist/docs/cli-dev.md +1 -1
- package/dist/docs/cli-secrets.md +45 -0
- package/dist/docs/dev.md +3 -3
- package/dist/docs/index.json +5 -0
- package/dist/docs/platform-google.md +15 -8
- package/dist/docs/porting-nextjs.md +19 -19
- package/dist/{docs-xRbVshXp.mjs → docs-x3hMtUzT.mjs} +2 -2
- package/dist/{egress-BjN-7vil.mjs → egress-Cn-P46O3.mjs} +1 -1
- package/dist/{feedback-CGjOAHON.mjs → feedback-C9m3dNkJ.mjs} +2 -2
- package/dist/index.mjs +26 -25
- package/dist/{local-DvzG4XUB.mjs → local-laAZEDVJ.mjs} +2 -2
- package/dist/{login-COZ7Xcm0.mjs → login-C4MDP5NM.mjs} +1 -1
- package/dist/{logs-B_YoflCq.mjs → logs-CfDINw7U.mjs} +1 -1
- package/dist/{migrations-Btzr9_q7.mjs → migrations-B9fXxMDj.mjs} +1 -1
- package/dist/{open-D2hH933K.mjs → open-rS1ARzOy.mjs} +1 -1
- package/dist/{package-vZ0xH49Y.mjs → package-CBso2611.mjs} +1 -1
- package/dist/{projects-CLs6MEF7.mjs → projects-Dmm_976k.mjs} +1 -1
- package/dist/{schedule-B8zA8WlG.mjs → schedule-Buu71RWQ.mjs} +1 -1
- package/dist/secrets-BD3DaTih.mjs +121 -0
- package/dist/{skill-PoaZrCNy.mjs → skill-DmVlZXgv.mjs} +2 -2
- package/dist/{staging-pZpdZuj_.mjs → staging-CKEoDnac.mjs} +1 -1
- package/dist/templates/worker/.dev.vars.example +1 -1
- package/dist/templates/worker/AGENTS.md +1 -1
- package/dist/templates/worker/worker/index.ts +1 -1
- package/dist/{token-BKwGa10J.mjs → token-Dp2CoIYj.mjs} +1 -1
- package/dist/{ui-CUNkis89.mjs → ui-DR-siu2S.mjs} +52 -5
- package/dist/{upgrade-DjrNZ-B4.mjs → upgrade-C7u8pxeV.mjs} +2 -2
- package/dist/{usage-UmzU6sGp.mjs → usage-81JSiWIx.mjs} +1 -1
- package/package.json +1 -1
- package/dist/dev-BAcZi226.mjs +0 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { c as resolveProject, o as projectFlagArgs } from "./site-DM2J10CB.mjs";
|
|
2
|
-
import { a as unwrap, d as withContext, i as requireTty, l as apiRequest, r as reportErrors, s as apiDataRequest } from "./ui-
|
|
3
|
-
import { n as migrateProject, r as readMigrationFiles, t as describeMigrateResult } from "./migrations-
|
|
2
|
+
import { a as unwrap, d as withContext, i as requireTty, l as apiRequest, r as reportErrors, s as apiDataRequest } from "./ui-DR-siu2S.mjs";
|
|
3
|
+
import { n as migrateProject, r as readMigrationFiles, t as describeMigrateResult } from "./migrations-B9fXxMDj.mjs";
|
|
4
4
|
import { defineCommand } from "citty";
|
|
5
5
|
import { readFileSync, writeFileSync } from "node:fs";
|
|
6
6
|
import * as p from "@clack/prompts";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as projectDirArgs, c as resolveProject, l as stagingUrl, n as siteConfig, o as projectFlagArgs, s as projectUrl, u as tryReadCanopyJson } from "./site-DM2J10CB.mjs";
|
|
2
|
-
import { a as unwrap, c as apiDownload, d as withContext, l as apiRequest, r as reportErrors, s as apiDataRequest, t as formatDateTime } from "./ui-
|
|
3
|
-
import { n as migrateProject, r as readMigrationFiles, t as describeMigrateResult } from "./migrations-
|
|
2
|
+
import { a as unwrap, c as apiDownload, d as withContext, l as apiRequest, r as reportErrors, s as apiDataRequest, t as formatDateTime } from "./ui-DR-siu2S.mjs";
|
|
3
|
+
import { n as migrateProject, r as readMigrationFiles, t as describeMigrateResult } from "./migrations-B9fXxMDj.mjs";
|
|
4
4
|
import { defineCommand } from "citty";
|
|
5
5
|
import { mkdtempSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { tmpdir } from "node:os";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as projectDirArgs, c as resolveProject, i as projectDialect, n as siteConfig, u as tryReadCanopyJson } from "./site-DM2J10CB.mjs";
|
|
2
|
-
import { d as withContext, l as apiRequest, o as ApiError, r as reportErrors, t as formatDateTime } from "./ui-
|
|
3
|
-
import { r as readMigrationFiles } from "./migrations-
|
|
2
|
+
import { d as withContext, l as apiRequest, o as ApiError, r as reportErrors, t as formatDateTime } from "./ui-DR-siu2S.mjs";
|
|
3
|
+
import { r as readMigrationFiles } from "./migrations-B9fXxMDj.mjs";
|
|
4
4
|
import { n as stampWorkerHeaders } from "./src-CwSKZwNK.mjs";
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
import { defineCommand } from "citty";
|
|
@@ -176,7 +176,7 @@ async function devRemote(flags, slug) {
|
|
|
176
176
|
async function devLocal(flags, slug) {
|
|
177
177
|
let dump;
|
|
178
178
|
if (flags.pull) {
|
|
179
|
-
const { fetchProjectDump } = await import("./local-
|
|
179
|
+
const { fetchProjectDump } = await import("./local-laAZEDVJ.mjs");
|
|
180
180
|
console.log(`Pulling a fresh export of ${slug}${flags.staging ? " [staging]" : ""}…`);
|
|
181
181
|
dump = await fetchProjectDump(slug, flags.staging ? "staging" : "live");
|
|
182
182
|
}
|
|
@@ -191,7 +191,7 @@ async function devLocal(flags, slug) {
|
|
|
191
191
|
const reason = err instanceof ApiError ? err.explain().why : String(err);
|
|
192
192
|
console.log(`Note: ai/services will be unavailable — could not reach the platform (${reason}).`);
|
|
193
193
|
}
|
|
194
|
-
const { createSandbox } = await import("./local-
|
|
194
|
+
const { createSandbox } = await import("./local-laAZEDVJ.mjs");
|
|
195
195
|
const sandbox = await createSandbox({
|
|
196
196
|
slug,
|
|
197
197
|
persistDir: join(flags.dir, ".canopy", "local"),
|
package/dist/docs/cli-dev.md
CHANGED
|
@@ -47,7 +47,7 @@ To tick a schedule by hand, post its name to the same path the platform uses:
|
|
|
47
47
|
curl -X POST localhost:5173/__canopy/scheduled -d '{"name":"nightly-digest"}'
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
**Worker secrets.** Secrets you set in the dashboard are never downloaded — the platform can't hand a stored value back, and your laptop is not where a live API key belongs. Put local values in a `.dev.vars` file next to `canopy.json` instead:
|
|
50
|
+
**Worker secrets.** Secrets you set in the dashboard or with [`canopy secrets set`](https://docs.canopy.website/cli/secrets) are never downloaded — the platform can't hand a stored value back, and your laptop is not where a live API key belongs. Put local values in a `.dev.vars` file next to `canopy.json` instead:
|
|
51
51
|
|
|
52
52
|
```
|
|
53
53
|
STRIPE_KEY=sk_test_local
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: canopy secrets
|
|
3
|
+
description: Set, list, and remove the project's worker secrets from the terminal.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
`canopy secrets` manages the secrets your backend worker reads as `c.env.NAME`
|
|
7
|
+
— API keys, signing secrets, anything the browser must never see. It does the
|
|
8
|
+
same job as the dashboard's Secrets panel, so a first deploy can be scripted
|
|
9
|
+
end to end: create the project, allow its hosts, set its secrets, deploy.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
canopy secrets list
|
|
15
|
+
printf %s "$STRIPE_SECRET" | canopy secrets set STRIPE_SECRET
|
|
16
|
+
canopy secrets set STRIPE_SECRET --from-env STRIPE_SECRET
|
|
17
|
+
canopy secrets set STRIPE_SECRET # hidden prompt in a terminal
|
|
18
|
+
canopy secrets remove STRIPE_SECRET
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Arguments & flags
|
|
22
|
+
|
|
23
|
+
All subcommands resolve the project the usual way — `canopy.json` in the
|
|
24
|
+
target directory, or `--project <slug>` to override — and honor the global
|
|
25
|
+
`--profile <site>` / `CANOPY_PROFILE`.
|
|
26
|
+
|
|
27
|
+
- `list` — print the secret names and when each was last set. Values are
|
|
28
|
+
never shown.
|
|
29
|
+
- `set <name>` — store a value. Names are `UPPER_SNAKE_CASE`, up to 64
|
|
30
|
+
characters. The value comes from **stdin** when piped (one trailing newline
|
|
31
|
+
is trimmed, so `echo` works too), from `--from-env <VAR>` to read an
|
|
32
|
+
environment variable, or from a hidden prompt when you run it in a terminal.
|
|
33
|
+
There is deliberately no `--value` flag: a value on the command line would
|
|
34
|
+
end up in shell history and process lists.
|
|
35
|
+
- `remove <name>` — delete a secret. The worker stops seeing it right away.
|
|
36
|
+
|
|
37
|
+
## How it works
|
|
38
|
+
|
|
39
|
+
Secrets live on the platform, encrypted, per project. Setting or removing one
|
|
40
|
+
re-rolls the running worker immediately — no deploy needed. The live and
|
|
41
|
+
staging channels share one set of secrets, like the egress allowlist. Values
|
|
42
|
+
travel one way: once stored they can't be read back by anyone, including
|
|
43
|
+
`canopy dev`, which is why local development uses a `.dev.vars` file with
|
|
44
|
+
stand-in values (see [`canopy dev`](https://docs.canopy.website/cli/dev)). A project holds at most 64
|
|
45
|
+
secrets of up to 8 KiB each.
|
package/dist/docs/dev.md
CHANGED
|
@@ -53,9 +53,9 @@ Projects with a `worker` entry in `canopy.json` get their backend locally too:
|
|
|
53
53
|
production (`env.CANOPY`, `env.DB`, `env.BLOB`, `env.USER`). Edit and refresh —
|
|
54
54
|
there's no build step.
|
|
55
55
|
|
|
56
|
-
Secrets are the one thing that doesn't come from the
|
|
57
|
-
|
|
58
|
-
`canopy.json`:
|
|
56
|
+
Secrets are the one thing that doesn't come from the platform. Stored values
|
|
57
|
+
(set in the dashboard or with `canopy secrets set`) are never downloadable, so
|
|
58
|
+
put local ones in a `.dev.vars` file next to `canopy.json`:
|
|
59
59
|
|
|
60
60
|
```
|
|
61
61
|
STRIPE_KEY=sk_test_local
|
package/dist/docs/index.json
CHANGED
|
@@ -251,6 +251,11 @@
|
|
|
251
251
|
"title": "canopy egress",
|
|
252
252
|
"summary": "Manage which outbound hosts the project's backend worker may fetch."
|
|
253
253
|
},
|
|
254
|
+
{
|
|
255
|
+
"slug": "cli-secrets",
|
|
256
|
+
"title": "canopy secrets",
|
|
257
|
+
"summary": "Set, list, and remove the project's worker secrets from the terminal."
|
|
258
|
+
},
|
|
254
259
|
{
|
|
255
260
|
"slug": "cli-schedule",
|
|
256
261
|
"title": "canopy schedule",
|
|
@@ -97,6 +97,12 @@ so is a write using a reading-only permission.
|
|
|
97
97
|
|
|
98
98
|
Drive is deliberately limited to files your project created or that someone
|
|
99
99
|
explicitly opened with it — connecting Drive does not expose a whole Drive.
|
|
100
|
+
The one exception is **Copy files it is given**: hand your project the id of a
|
|
101
|
+
file the account can open (a template deck, say) and it may copy that one file.
|
|
102
|
+
The copy is a file your project made, so with _Files this project makes_ it can
|
|
103
|
+
open and change the copy from then on — the original is never touched. It cannot
|
|
104
|
+
list, search or read anything else. Because Google has no copy-only permission,
|
|
105
|
+
this one counts as wider access and needs a Canopy admin to unlock it.
|
|
100
106
|
|
|
101
107
|
### Wider permissions
|
|
102
108
|
|
|
@@ -145,14 +151,15 @@ reading-only permission is refused before it reaches Google.
|
|
|
145
151
|
|
|
146
152
|
**Drive**
|
|
147
153
|
|
|
148
|
-
| Permission | What it allows
|
|
149
|
-
| --------------------------------------------- |
|
|
150
|
-
| Files this project makes | Create files, and reopen the ones this project made or someone picked for it.
|
|
151
|
-
| Its own config folder | A hidden folder only this project can see. Invisible in the account's Drive.
|
|
152
|
-
|
|
|
153
|
-
|
|
|
154
|
-
| Read
|
|
155
|
-
|
|
|
154
|
+
| Permission | What it allows |
|
|
155
|
+
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
156
|
+
| Files this project makes | Create files, and reopen the ones this project made or someone picked for it. |
|
|
157
|
+
| Its own config folder | A hidden folder only this project can see. Invisible in the account's Drive. |
|
|
158
|
+
| Copy files it is given **(wider access)** | Copy a file the account can open, by id, into a file this project owns. Cannot list, read or change anything else. |
|
|
159
|
+
| Recordings and transcripts **(wider access)** | Read the recordings and transcripts Meet saved to Drive. |
|
|
160
|
+
| Read the whole Drive _(under consideration)_ | Read and download every file the account can see. |
|
|
161
|
+
| Read all file names _(under consideration)_ | Names and metadata of every file the account can see, without contents. |
|
|
162
|
+
| Full Drive access _(under consideration)_ | Read, change and delete every file the account can see. |
|
|
156
163
|
|
|
157
164
|
**Gmail**
|
|
158
165
|
|
|
@@ -62,24 +62,24 @@ together as a single version, with rollback.
|
|
|
62
62
|
List everything in the app that runs on the server. Each item lands in one of
|
|
63
63
|
three buckets:
|
|
64
64
|
|
|
65
|
-
| Next.js feature | Where it goes on Canopy
|
|
66
|
-
| ----------------------------------------------- |
|
|
67
|
-
| Pages, layouts, client components | Static build (unchanged in spirit)
|
|
68
|
-
| Server components fetching data at request time | Client-side fetching, or a worker endpoint
|
|
69
|
-
| Route handlers (`app/api/*/route.ts`) | Worker endpoints under `/api/*`
|
|
70
|
-
| Server actions | Explicit worker endpoints, called with `fetch` from the client
|
|
71
|
-
| Middleware | Usually deleted (auth is platform-provided); anything else moves into the worker
|
|
72
|
-
| NextAuth / auth middleware | Deleted — use `canopy.auth.user()` (client) or `env.USER` (worker)
|
|
73
|
-
| Database (Prisma, Postgres, …) | `canopy.db` — per-project database, document API + SQL escape hatch
|
|
74
|
-
| File uploads (S3, …) | `canopy.blob` — per-project file storage with signed downloads
|
|
75
|
-
| AI SDK / OpenAI client | `canopy.ai.chat()`, or point the Vercel AI SDK at `canopy.ai.endpoint()`
|
|
76
|
-
| `NEXT_PUBLIC_*` env vars | Build-time env vars in your CI — the platform doesn't inject build config
|
|
77
|
-
| Server-side env vars / secrets | Project secrets (dashboard Settings) — injected into the worker's `env`
|
|
78
|
-
| Cron (`vercel.json` crons) | [Schedules](https://docs.canopy.website/platform/schedules) — delivered to the worker's `scheduled()`
|
|
79
|
-
| ISR / `revalidate` / caching | Dropped — at internal-tool scale, fetch fresh or cache in the client
|
|
80
|
-
| `next/image` optimization | Plain `<img>`, or optimize at build time
|
|
81
|
-
| Custom domain | Not available — projects live at `<slug>.canopy.<domain>` behind sign-in
|
|
82
|
-
| Queues / background jobs | Not supported — restructure around request/response plus schedules
|
|
65
|
+
| Next.js feature | Where it goes on Canopy |
|
|
66
|
+
| ----------------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
67
|
+
| Pages, layouts, client components | Static build (unchanged in spirit) |
|
|
68
|
+
| Server components fetching data at request time | Client-side fetching, or a worker endpoint |
|
|
69
|
+
| Route handlers (`app/api/*/route.ts`) | Worker endpoints under `/api/*` |
|
|
70
|
+
| Server actions | Explicit worker endpoints, called with `fetch` from the client |
|
|
71
|
+
| Middleware | Usually deleted (auth is platform-provided); anything else moves into the worker |
|
|
72
|
+
| NextAuth / auth middleware | Deleted — use `canopy.auth.user()` (client) or `env.USER` (worker) |
|
|
73
|
+
| Database (Prisma, Postgres, …) | `canopy.db` — per-project database, document API + SQL escape hatch |
|
|
74
|
+
| File uploads (S3, …) | `canopy.blob` — per-project file storage with signed downloads |
|
|
75
|
+
| AI SDK / OpenAI client | `canopy.ai.chat()`, or point the Vercel AI SDK at `canopy.ai.endpoint()` |
|
|
76
|
+
| `NEXT_PUBLIC_*` env vars | Build-time env vars in your CI — the platform doesn't inject build config |
|
|
77
|
+
| Server-side env vars / secrets | Project secrets (`canopy secrets set` or dashboard Settings) — injected into the worker's `env` |
|
|
78
|
+
| Cron (`vercel.json` crons) | [Schedules](https://docs.canopy.website/platform/schedules) — delivered to the worker's `scheduled()` |
|
|
79
|
+
| ISR / `revalidate` / caching | Dropped — at internal-tool scale, fetch fresh or cache in the client |
|
|
80
|
+
| `next/image` optimization | Plain `<img>`, or optimize at build time |
|
|
81
|
+
| Custom domain | Not available — projects live at `<slug>.canopy.<domain>` behind sign-in |
|
|
82
|
+
| Queues / background jobs | Not supported — restructure around request/response plus schedules |
|
|
83
83
|
|
|
84
84
|
If the last two rows are deal-breakers, stop here: see
|
|
85
85
|
[When not to port](#when-not-to-port).
|
|
@@ -253,6 +253,6 @@ past greenhouse size (see [Use cases](https://docs.canopy.website/overview/use-c
|
|
|
253
253
|
- [ ] Worker: route handlers + server actions → `/api/*` endpoints in `worker/index.ts`
|
|
254
254
|
- [ ] Data: ORM → `canopy.db`; uploads → `canopy.blob`; AI clients → `canopy.ai`
|
|
255
255
|
- [ ] Delete NextAuth/middleware; read identity from `canopy.auth.user()` / `env.USER`
|
|
256
|
-
- [ ] Secrets
|
|
256
|
+
- [ ] Secrets via `canopy secrets set` (or dashboard Settings); `NEXT_PUBLIC_*` into your CI build
|
|
257
257
|
- [ ] Crons into Settings → Schedules, handled in `scheduled()`
|
|
258
258
|
- [ ] `canopy.json` with `build`, `dist`, `worker` — then `canopy deploy`
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { t as version } from "./package-
|
|
1
|
+
import { t as version } from "./package-CBso2611.mjs";
|
|
2
2
|
import { n as siteConfig } from "./site-DM2J10CB.mjs";
|
|
3
3
|
import { i as latestKnownVersion, r as compareSemver } from "./version-check-CcsA1QjI.mjs";
|
|
4
|
-
import { r as reportErrors } from "./ui-
|
|
4
|
+
import { r as reportErrors } from "./ui-DR-siu2S.mjs";
|
|
5
5
|
import { defineCommand } from "citty";
|
|
6
6
|
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { homedir } from "node:os";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as projectDirArgs, c as resolveProject } from "./site-DM2J10CB.mjs";
|
|
2
|
-
import { a as unwrap, d as withContext, i as requireTty, l as apiRequest, r as reportErrors, t as formatDateTime } from "./ui-
|
|
2
|
+
import { a as unwrap, d as withContext, i as requireTty, l as apiRequest, r as reportErrors, t as formatDateTime } from "./ui-DR-siu2S.mjs";
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
import * as p from "@clack/prompts";
|
|
5
5
|
//#region src/egress.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { t as version } from "./package-
|
|
1
|
+
import { t as version } from "./package-CBso2611.mjs";
|
|
2
2
|
import { a as projectDirArgs, c as resolveProject, d as tryResolveProject, n as siteConfig, u as tryReadCanopyJson } from "./site-DM2J10CB.mjs";
|
|
3
|
-
import { c as apiDownload, l as apiRequest, r as reportErrors, t as formatDateTime, u as apiUpload } from "./ui-
|
|
3
|
+
import { c as apiDownload, l as apiRequest, r as reportErrors, t as formatDateTime, u as apiUpload } from "./ui-DR-siu2S.mjs";
|
|
4
4
|
import { defineCommand } from "citty";
|
|
5
5
|
import { basename, extname, join } from "node:path";
|
|
6
6
|
import { readFile, writeFile } from "node:fs/promises";
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as version } from "./package-
|
|
2
|
+
import { t as version } from "./package-CBso2611.mjs";
|
|
3
3
|
import { r as siteHeaderLine, t as setInvocationProfile } from "./site-DM2J10CB.mjs";
|
|
4
4
|
import { a as notifyOfUpdate, o as runRefresh } from "./version-check-CcsA1QjI.mjs";
|
|
5
5
|
import { defineCommand, runMain } from "citty";
|
|
@@ -60,30 +60,31 @@ const main = defineCommand({
|
|
|
60
60
|
description: "canopy — create and deploy vibecoded projects"
|
|
61
61
|
},
|
|
62
62
|
subCommands: {
|
|
63
|
-
login: () => import("./login-
|
|
64
|
-
whoami: () => import("./login-
|
|
65
|
-
logout: () => import("./login-
|
|
66
|
-
create: () => import("./projects-
|
|
67
|
-
init: () => import("./projects-
|
|
68
|
-
projects: () => import("./projects-
|
|
69
|
-
delete: () => import("./projects-
|
|
70
|
-
dev: () => import("./dev-
|
|
71
|
-
deploy: () => import("./deploy-
|
|
72
|
-
promote: () => import("./deploy-
|
|
73
|
-
staging: () => import("./staging-
|
|
74
|
-
rollback: () => import("./deploy-
|
|
75
|
-
download: () => import("./deploy-
|
|
76
|
-
token: () => import("./token-
|
|
77
|
-
egress: () => import("./egress-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
63
|
+
login: () => import("./login-C4MDP5NM.mjs").then((m) => m.loginCommand),
|
|
64
|
+
whoami: () => import("./login-C4MDP5NM.mjs").then((m) => m.whoamiCommand),
|
|
65
|
+
logout: () => import("./login-C4MDP5NM.mjs").then((m) => m.logoutCommand),
|
|
66
|
+
create: () => import("./projects-Dmm_976k.mjs").then((m) => m.createCommand),
|
|
67
|
+
init: () => import("./projects-Dmm_976k.mjs").then((m) => m.initCommand),
|
|
68
|
+
projects: () => import("./projects-Dmm_976k.mjs").then((m) => m.projectsCommand),
|
|
69
|
+
delete: () => import("./projects-Dmm_976k.mjs").then((m) => m.deleteCommand),
|
|
70
|
+
dev: () => import("./dev-BOvMCaML.mjs").then((m) => m.devCommand),
|
|
71
|
+
deploy: () => import("./deploy-CTMcwHhI.mjs").then((m) => m.deployCommand),
|
|
72
|
+
promote: () => import("./deploy-CTMcwHhI.mjs").then((m) => m.promoteCommand),
|
|
73
|
+
staging: () => import("./staging-CKEoDnac.mjs").then((m) => m.stagingCommand),
|
|
74
|
+
rollback: () => import("./deploy-CTMcwHhI.mjs").then((m) => m.rollbackCommand),
|
|
75
|
+
download: () => import("./deploy-CTMcwHhI.mjs").then((m) => m.downloadCommand),
|
|
76
|
+
token: () => import("./token-Dp2CoIYj.mjs").then((m) => m.tokenCommand),
|
|
77
|
+
egress: () => import("./egress-Cn-P46O3.mjs").then((m) => m.egressCommand),
|
|
78
|
+
secrets: () => import("./secrets-BD3DaTih.mjs").then((m) => m.secretsCommand),
|
|
79
|
+
schedule: () => import("./schedule-Buu71RWQ.mjs").then((m) => m.scheduleCommand),
|
|
80
|
+
feedback: () => import("./feedback-C9m3dNkJ.mjs").then((m) => m.feedbackCommand),
|
|
81
|
+
db: () => import("./db-DVMwCLlU.mjs").then((m) => m.dbCommand),
|
|
82
|
+
usage: () => import("./usage-81JSiWIx.mjs").then((m) => m.usageCommand),
|
|
83
|
+
open: () => import("./open-rS1ARzOy.mjs").then((m) => m.openCommand),
|
|
84
|
+
docs: () => import("./docs-x3hMtUzT.mjs").then((m) => m.docsCommand),
|
|
85
|
+
skill: () => import("./skill-DmVlZXgv.mjs").then((m) => m.skillCommand),
|
|
86
|
+
upgrade: () => import("./upgrade-C7u8pxeV.mjs").then((m) => m.upgradeCommand),
|
|
87
|
+
logs: () => import("./logs-CfDINw7U.mjs").then((m) => m.logsCommand)
|
|
87
88
|
}
|
|
88
89
|
});
|
|
89
90
|
if (process.argv[2] !== "upgrade") notifyOfUpdate(version);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { s as apiDataRequest } from "./ui-
|
|
1
|
+
import { s as apiDataRequest } from "./ui-DR-siu2S.mjs";
|
|
2
2
|
import { a as blobRouter, i as META_COLUMNS, r as dbRouter } from "./src-CwSKZwNK.mjs";
|
|
3
|
-
import { r as rewriteApiPath } from "./dev-
|
|
3
|
+
import { r as rewriteApiPath } from "./dev-BvjbJcse.mjs";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { dirname, join, relative, sep } from "node:path";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { _ as writeConfigFile, f as clearAllProfileTokens, g as upsertProfileAuth, h as setActiveProfile, m as readConfigFile, n as siteConfig, p as listBakedProfiles, v as getBakedProfile, y as isProfileId } from "./site-DM2J10CB.mjs";
|
|
2
|
-
import { n as openBrowser, r as reportErrors } from "./ui-
|
|
2
|
+
import { n as openBrowser, r as reportErrors } from "./ui-DR-siu2S.mjs";
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
import { hostname } from "node:os";
|
|
5
5
|
import * as p from "@clack/prompts";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as resolveProject, o as projectFlagArgs } from "./site-DM2J10CB.mjs";
|
|
2
|
-
import { d as withContext, l as apiRequest, r as reportErrors } from "./ui-
|
|
2
|
+
import { d as withContext, l as apiRequest, r as reportErrors } from "./ui-DR-siu2S.mjs";
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
//#region src/logs.ts
|
|
5
5
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { u as tryReadCanopyJson } from "./site-DM2J10CB.mjs";
|
|
2
|
-
import { s as apiDataRequest } from "./ui-
|
|
2
|
+
import { s as apiDataRequest } from "./ui-DR-siu2S.mjs";
|
|
3
3
|
import { readFileSync, readdirSync } from "node:fs";
|
|
4
4
|
import { join, resolve } from "node:path";
|
|
5
5
|
//#region src/migrations.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as projectDirArgs, c as resolveProject, l as stagingUrl, s as projectUrl } from "./site-DM2J10CB.mjs";
|
|
2
|
-
import { n as openBrowser, r as reportErrors } from "./ui-
|
|
2
|
+
import { n as openBrowser, r as reportErrors } from "./ui-DR-siu2S.mjs";
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
//#region src/open.ts
|
|
5
5
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as siteConfig, s as projectUrl, u as tryReadCanopyJson } from "./site-DM2J10CB.mjs";
|
|
2
|
-
import { a as unwrap, i as requireTty, l as apiRequest, r as reportErrors } from "./ui-
|
|
2
|
+
import { a as unwrap, i as requireTty, l as apiRequest, r as reportErrors } from "./ui-DR-siu2S.mjs";
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { join, relative, resolve, sep } from "node:path";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as resolveProject, o as projectFlagArgs } from "./site-DM2J10CB.mjs";
|
|
2
|
-
import { d as withContext, l as apiRequest, r as reportErrors, t as formatDateTime } from "./ui-
|
|
2
|
+
import { d as withContext, l as apiRequest, r as reportErrors, t as formatDateTime } from "./ui-DR-siu2S.mjs";
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
//#region src/schedule.ts
|
|
5
5
|
/**
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { a as projectDirArgs, c as resolveProject } from "./site-DM2J10CB.mjs";
|
|
2
|
+
import { a as unwrap, d as withContext, l as apiRequest, r as reportErrors, t as formatDateTime } from "./ui-DR-siu2S.mjs";
|
|
3
|
+
import { defineCommand } from "citty";
|
|
4
|
+
import * as p from "@clack/prompts";
|
|
5
|
+
//#region src/secrets.ts
|
|
6
|
+
/**
|
|
7
|
+
* canopy secrets — manage the project's worker secrets from the terminal so a
|
|
8
|
+
* first deploy can be scripted end to end (create → egress → secrets → deploy).
|
|
9
|
+
* Values travel one way: set via stdin or an environment variable (never a
|
|
10
|
+
* flag, so nothing lands in shell history), listed by name only, and never
|
|
11
|
+
* echoed or downloaded — the same rule the dashboard follows. Secrets are
|
|
12
|
+
* shared by the live and staging channels (docs/14 §4.6).
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* A piped value usually ends in the newline `echo` or a heredoc appends; a
|
|
16
|
+
* secret never legitimately does. Strip exactly one trailing line break and
|
|
17
|
+
* leave everything else verbatim (leading/inner whitespace may be meaningful).
|
|
18
|
+
*/
|
|
19
|
+
function normalizeSecretValue(raw) {
|
|
20
|
+
return raw.replace(/\r?\n$/, "");
|
|
21
|
+
}
|
|
22
|
+
async function readStdin() {
|
|
23
|
+
const chunks = [];
|
|
24
|
+
for await (const chunk of process.stdin) chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
25
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
26
|
+
}
|
|
27
|
+
/** Resolve the value: --from-env, then piped stdin, then a hidden prompt on a TTY. */
|
|
28
|
+
async function resolveValue(name, fromEnv) {
|
|
29
|
+
if (fromEnv !== void 0) {
|
|
30
|
+
const value = process.env[fromEnv];
|
|
31
|
+
if (value === void 0) throw new Error(`environment variable ${fromEnv} is not set (nothing to store for ${name}).`);
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
if (!process.stdin.isTTY) return normalizeSecretValue(await readStdin());
|
|
35
|
+
return unwrap(await p.password({
|
|
36
|
+
message: `Value for ${name} (input is hidden)`,
|
|
37
|
+
validate: (v) => v ? void 0 : "A secret value cannot be empty."
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
const secretsCommand = defineCommand({
|
|
41
|
+
meta: {
|
|
42
|
+
name: "secrets",
|
|
43
|
+
description: "Manage the project's worker secrets (set / list / remove — values never shown)"
|
|
44
|
+
},
|
|
45
|
+
subCommands: {
|
|
46
|
+
list: defineCommand({
|
|
47
|
+
meta: {
|
|
48
|
+
name: "list",
|
|
49
|
+
description: "List the project's secret names (values are never shown)"
|
|
50
|
+
},
|
|
51
|
+
args: { ...projectDirArgs },
|
|
52
|
+
run: reportErrors("secrets list", async ({ args }) => {
|
|
53
|
+
const { slug } = resolveProject(args);
|
|
54
|
+
const { secrets } = await apiRequest("GET", `/projects/${slug}/secrets`);
|
|
55
|
+
if (secrets.length === 0) {
|
|
56
|
+
console.log(`No secrets set for ${slug} — add one with \`canopy secrets set NAME\`.`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const width = Math.max(...secrets.map((s) => s.key.length));
|
|
60
|
+
for (const s of secrets) console.log(`${s.key.padEnd(width)} updated ${formatDateTime(s.updated_at)}`);
|
|
61
|
+
})
|
|
62
|
+
}),
|
|
63
|
+
set: defineCommand({
|
|
64
|
+
meta: {
|
|
65
|
+
name: "set",
|
|
66
|
+
description: "Set a secret — value from stdin (`printf %s \"$V\" | canopy secrets set NAME`), --from-env, or a hidden prompt"
|
|
67
|
+
},
|
|
68
|
+
args: {
|
|
69
|
+
name: {
|
|
70
|
+
type: "positional",
|
|
71
|
+
description: "Secret name (UPPER_SNAKE_CASE, e.g. STRIPE_SECRET)",
|
|
72
|
+
required: true
|
|
73
|
+
},
|
|
74
|
+
"from-env": {
|
|
75
|
+
type: "string",
|
|
76
|
+
description: "Read the value from this environment variable instead of stdin"
|
|
77
|
+
},
|
|
78
|
+
...projectDirArgs
|
|
79
|
+
},
|
|
80
|
+
run: reportErrors("secrets set", async ({ args }) => {
|
|
81
|
+
const { slug } = resolveProject(args);
|
|
82
|
+
const name = args.name.trim();
|
|
83
|
+
const value = await resolveValue(name, args["from-env"]);
|
|
84
|
+
if (value.length === 0) {
|
|
85
|
+
console.error(`No value provided for ${name} — pipe it on stdin or pass --from-env VAR.`);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
await withContext(apiRequest("PUT", `/projects/${slug}/secrets/${name}`, { value }), {
|
|
89
|
+
action: `set secret ${name} on ${slug}`,
|
|
90
|
+
fixes: { not_supported_on_target: "This site has no worker runtime, so secrets have nowhere to go — set them on a site that runs workers (e.g. `--profile main`)." }
|
|
91
|
+
});
|
|
92
|
+
console.log(`Set ${name} for ${slug} — running workers pick it up now.`);
|
|
93
|
+
})
|
|
94
|
+
}),
|
|
95
|
+
remove: defineCommand({
|
|
96
|
+
meta: {
|
|
97
|
+
name: "remove",
|
|
98
|
+
description: "Remove a secret"
|
|
99
|
+
},
|
|
100
|
+
args: {
|
|
101
|
+
name: {
|
|
102
|
+
type: "positional",
|
|
103
|
+
description: "Secret name (as shown by `list`)",
|
|
104
|
+
required: true
|
|
105
|
+
},
|
|
106
|
+
...projectDirArgs
|
|
107
|
+
},
|
|
108
|
+
run: reportErrors("secrets remove", async ({ args }) => {
|
|
109
|
+
const { slug } = resolveProject(args);
|
|
110
|
+
const name = args.name.trim();
|
|
111
|
+
await withContext(apiRequest("DELETE", `/projects/${slug}/secrets/${name}`), {
|
|
112
|
+
action: `remove secret ${name} from ${slug}`,
|
|
113
|
+
fixes: { not_found: `${name} is not set on ${slug} (see \`canopy secrets list\`), or your account can't access the project.` }
|
|
114
|
+
});
|
|
115
|
+
console.log(`Removed ${name} from ${slug} — running workers no longer see it.`);
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
//#endregion
|
|
121
|
+
export { secretsCommand };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as version } from "./package-
|
|
2
|
-
import { r as reportErrors } from "./ui-
|
|
1
|
+
import { t as version } from "./package-CBso2611.mjs";
|
|
2
|
+
import { r as reportErrors } from "./ui-DR-siu2S.mjs";
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
import { cpSync, existsSync, mkdirSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { homedir } from "node:os";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as resolveProject, l as stagingUrl, o as projectFlagArgs, s as projectUrl } from "./site-DM2J10CB.mjs";
|
|
2
|
-
import { a as unwrap, d as withContext, i as requireTty, l as apiRequest, r as reportErrors, t as formatDateTime } from "./ui-
|
|
2
|
+
import { a as unwrap, d as withContext, i as requireTty, l as apiRequest, r as reportErrors, t as formatDateTime } from "./ui-DR-siu2S.mjs";
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
import * as p from "@clack/prompts";
|
|
5
5
|
//#region src/staging.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Local worker secrets for `canopy dev` — copy to .dev.vars (gitignored).
|
|
2
2
|
#
|
|
3
|
-
#
|
|
3
|
+
# Project secrets (`canopy secrets set NAME` or Settings → Secrets) are never downloaded: the platform
|
|
4
4
|
# can't hand a stored value back, and live keys don't belong on a laptop. Set
|
|
5
5
|
# local stand-ins here; the worker reads them as c.env.NAME, exactly as it
|
|
6
6
|
# reads the dashboard's in production. `canopy dev` prints which dashboard
|
|
@@ -56,7 +56,7 @@ the [Canopy dashboard](https://dashboard.thanarie.dev).
|
|
|
56
56
|
- Do not add auth — the platform authenticates every request before it
|
|
57
57
|
reaches this app or the Worker.
|
|
58
58
|
- Do not store secrets in the repo or SPA. Set them in the Canopy dashboard
|
|
59
|
-
(Settings → Secrets); the Worker reads them as `c.env.SECRET_NAME`
|
|
59
|
+
(`canopy secrets set NAME`, or Settings → Secrets); the Worker reads them as `c.env.SECRET_NAME`
|
|
60
60
|
(Workers-shaped bindings — not `process.env`). Locally, put stand-in values
|
|
61
61
|
in `.dev.vars` (gitignored, see `.dev.vars.example`) — dashboard values are
|
|
62
62
|
never downloaded, and `canopy dev` prints which names are still missing. Platform access still goes
|
|
@@ -25,7 +25,7 @@ interface Env {
|
|
|
25
25
|
// DB — this project's database: `dialect` plus
|
|
26
26
|
// `query(text, params) => { rows, rowCount }`
|
|
27
27
|
// BLOB — this project's files: `get` / `put` / `list` / `delete`
|
|
28
|
-
//
|
|
28
|
+
// Project secrets (`canopy secrets set` / Settings → Secrets) land as Workers-shaped bindings:
|
|
29
29
|
// MY_API_KEY?: string;
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as projectDirArgs, c as resolveProject, o as projectFlagArgs } from "./site-DM2J10CB.mjs";
|
|
2
|
-
import { l as apiRequest, r as reportErrors, t as formatDateTime } from "./ui-
|
|
2
|
+
import { l as apiRequest, r as reportErrors, t as formatDateTime } from "./ui-DR-siu2S.mjs";
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
const tokenCommand = defineCommand({
|
|
5
5
|
meta: {
|
|
@@ -137,6 +137,26 @@ const ERROR_COPY = {
|
|
|
137
137
|
worker_egress_sync_failed: {
|
|
138
138
|
why: "the list was saved but redeploying the running worker with it failed",
|
|
139
139
|
fix: "Retry, or redeploy the project (`canopy deploy`) to apply the new allowlist."
|
|
140
|
+
},
|
|
141
|
+
invalid_key: {
|
|
142
|
+
why: "secret names must be UPPER_SNAKE_CASE (a letter, then letters/digits/underscores, at most 64 chars)",
|
|
143
|
+
fix: "Rename it, e.g. STRIPE_SECRET."
|
|
144
|
+
},
|
|
145
|
+
reserved_key: {
|
|
146
|
+
why: "that name is reserved for the platform runtime",
|
|
147
|
+
fix: "Pick a name that isn't a Canopy or runtime binding."
|
|
148
|
+
},
|
|
149
|
+
value_too_large: {
|
|
150
|
+
why: "a secret value is limited to 8 KiB",
|
|
151
|
+
fix: "Store a reference (an id or a shorter key) and fetch the large payload from your worker instead."
|
|
152
|
+
},
|
|
153
|
+
too_many_secrets: {
|
|
154
|
+
why: "the project already holds the maximum number of secrets (64)",
|
|
155
|
+
fix: "Remove one you no longer need (`canopy secrets remove NAME`) first."
|
|
156
|
+
},
|
|
157
|
+
worker_secret_sync_failed: {
|
|
158
|
+
why: "the secret was saved but redeploying the running worker with it failed",
|
|
159
|
+
fix: "Retry, or redeploy the project (`canopy deploy`) to apply it."
|
|
140
160
|
}
|
|
141
161
|
};
|
|
142
162
|
/** Generic explanation for a status code when we have no per-code copy. */
|
|
@@ -154,21 +174,40 @@ function statusFix(status) {
|
|
|
154
174
|
if (status >= 500) return "This is usually temporary — wait a moment and try again.";
|
|
155
175
|
return "Re-check the command arguments and try again.";
|
|
156
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* One trace per CLI invocation (docs/42-observability.md §3.7): every request
|
|
179
|
+
* this process makes carries the same W3C traceparent, so the platform's logs
|
|
180
|
+
* for a `canopy deploy` line up under one id. The api echoes it back as
|
|
181
|
+
* `x-canopy-request-id`, which failures print for the user to quote.
|
|
182
|
+
*/
|
|
183
|
+
const TRACE_ID = randomHex(16);
|
|
184
|
+
function randomHex(bytes) {
|
|
185
|
+
const buf = new Uint8Array(bytes);
|
|
186
|
+
crypto.getRandomValues(buf);
|
|
187
|
+
let out = "";
|
|
188
|
+
for (const b of buf) out += b.toString(16).padStart(2, "0");
|
|
189
|
+
return out;
|
|
190
|
+
}
|
|
191
|
+
function traceHeaders() {
|
|
192
|
+
return { traceparent: `00-${TRACE_ID}-${randomHex(8)}-01` };
|
|
193
|
+
}
|
|
157
194
|
var ApiError = class extends Error {
|
|
158
195
|
status;
|
|
159
196
|
code;
|
|
160
197
|
method;
|
|
161
198
|
path;
|
|
162
199
|
detail;
|
|
200
|
+
requestId;
|
|
163
201
|
/** Command-specific copy, layered on by `withContext` (or `fail` for 401s). */
|
|
164
202
|
context;
|
|
165
|
-
constructor(status, code, method, path, detail) {
|
|
203
|
+
constructor(status, code, method, path, detail, requestId) {
|
|
166
204
|
super(detail ? `${code}: ${detail}` : code);
|
|
167
205
|
this.status = status;
|
|
168
206
|
this.code = code;
|
|
169
207
|
this.method = method;
|
|
170
208
|
this.path = path;
|
|
171
209
|
this.detail = detail;
|
|
210
|
+
this.requestId = requestId;
|
|
172
211
|
this.name = "ApiError";
|
|
173
212
|
}
|
|
174
213
|
/**
|
|
@@ -179,10 +218,12 @@ var ApiError = class extends Error {
|
|
|
179
218
|
const copy = ERROR_COPY[this.code];
|
|
180
219
|
const headline = this.context?.action ? `could not ${this.context.action}` : `${this.method} ${this.path} failed`;
|
|
181
220
|
const detail = this.detail ? `: ${this.detail}` : "";
|
|
221
|
+
const why = `${this.status} ${this.code}${detail} — ${copy?.why ?? statusWhy(this.status)}`;
|
|
222
|
+
const fix = this.context?.fixes?.[this.code] ?? copy?.fix ?? statusFix(this.status);
|
|
182
223
|
return {
|
|
183
224
|
headline,
|
|
184
|
-
why: `${
|
|
185
|
-
fix
|
|
225
|
+
why: this.requestId ? `${why} (request id ${this.requestId})` : why,
|
|
226
|
+
fix
|
|
186
227
|
};
|
|
187
228
|
}
|
|
188
229
|
};
|
|
@@ -221,7 +262,7 @@ function credentials() {
|
|
|
221
262
|
async function fail(response, isDeployToken, method, path) {
|
|
222
263
|
const payload = await response.json().catch(() => ({}));
|
|
223
264
|
const code = payload.error ?? (response.status === 401 ? "unauthenticated" : `http_${response.status}`);
|
|
224
|
-
const err = new ApiError(response.status, code, method, path, payload.detail);
|
|
265
|
+
const err = new ApiError(response.status, code, method, path, payload.detail, response.headers.get("x-canopy-request-id") ?? void 0);
|
|
225
266
|
if (response.status === 401) err.context = {
|
|
226
267
|
action: "authenticate with Canopy",
|
|
227
268
|
fixes: { [code]: isDeployToken ? "The deploy token was rejected — it may have been revoked. Create a new one in the dashboard (Settings → Deploy tokens) or with `canopy token create`." : "Your session has expired — run `canopy login` again." }
|
|
@@ -234,6 +275,7 @@ async function apiRequest(method, path, body, rawContentType, headers) {
|
|
|
234
275
|
const response = await fetch(`${apiUrl}/control/v1${path}`, {
|
|
235
276
|
method,
|
|
236
277
|
headers: {
|
|
278
|
+
...traceHeaders(),
|
|
237
279
|
authorization: `Bearer ${token}`,
|
|
238
280
|
...body === void 0 || isForm ? {} : { "content-type": rawContentType ?? "application/json" },
|
|
239
281
|
...headers
|
|
@@ -253,6 +295,7 @@ async function apiUpload(path, bytes, contentType) {
|
|
|
253
295
|
const response = await fetch(`${apiUrl}/control/v1${path}`, {
|
|
254
296
|
method: "POST",
|
|
255
297
|
headers: {
|
|
298
|
+
...traceHeaders(),
|
|
256
299
|
authorization: `Bearer ${token}`,
|
|
257
300
|
"content-type": contentType
|
|
258
301
|
},
|
|
@@ -264,7 +307,10 @@ async function apiUpload(path, bytes, contentType) {
|
|
|
264
307
|
/** Authenticated GET returning raw bytes (e.g. a deploy zip). */
|
|
265
308
|
async function apiDownload(path) {
|
|
266
309
|
const { apiUrl, token, isDeployToken } = credentials();
|
|
267
|
-
const response = await fetch(`${apiUrl}/control/v1${path}`, { headers: {
|
|
310
|
+
const response = await fetch(`${apiUrl}/control/v1${path}`, { headers: {
|
|
311
|
+
...traceHeaders(),
|
|
312
|
+
authorization: `Bearer ${token}`
|
|
313
|
+
} });
|
|
268
314
|
if (!response.ok) return fail(response, isDeployToken, "GET", path);
|
|
269
315
|
return Buffer.from(await response.arrayBuffer());
|
|
270
316
|
}
|
|
@@ -278,6 +324,7 @@ async function apiDataRequest(method, path, projectSlug, body, rawContentType, c
|
|
|
278
324
|
const response = await fetch(`${apiUrl}/data/v1${path}`, {
|
|
279
325
|
method,
|
|
280
326
|
headers: {
|
|
327
|
+
...traceHeaders(),
|
|
281
328
|
authorization: `Bearer ${token}`,
|
|
282
329
|
"x-canopy-project": projectSlug,
|
|
283
330
|
...channel === "staging" ? { "x-canopy-channel": "staging" } : {},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as PACKAGE_NAME } from "./version-check-CcsA1QjI.mjs";
|
|
2
|
-
import { r as reportErrors } from "./ui-
|
|
2
|
+
import { r as reportErrors } from "./ui-DR-siu2S.mjs";
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
@@ -112,7 +112,7 @@ const upgradeCommand = defineCommand({
|
|
|
112
112
|
const spec = `${PACKAGE_NAME}@${args.version ?? "latest"}`;
|
|
113
113
|
const command = pmCommand(pm);
|
|
114
114
|
const cmd = installArgs(pm, spec);
|
|
115
|
-
const { skillInstalled } = await import("./skill-
|
|
115
|
+
const { skillInstalled } = await import("./skill-DmVlZXgv.mjs");
|
|
116
116
|
const { homedir } = await import("node:os");
|
|
117
117
|
const refreshGlobal = skillInstalled(homedir());
|
|
118
118
|
const refreshRepo = process.cwd() !== homedir() && skillInstalled(process.cwd());
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as resolveProject, o as projectFlagArgs } from "./site-DM2J10CB.mjs";
|
|
2
|
-
import { d as withContext, l as apiRequest, r as reportErrors } from "./ui-
|
|
2
|
+
import { d as withContext, l as apiRequest, r as reportErrors } from "./ui-DR-siu2S.mjs";
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
//#region src/usage.ts
|
|
5
5
|
/**
|
package/package.json
CHANGED
package/dist/dev-BAcZi226.mjs
DELETED