@mediamonks/canopy-cli 0.7.12 → 0.7.13

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.
Files changed (119) hide show
  1. package/dist/{db-8Etjmzxh.mjs → db-DKnJQPm5.mjs} +2 -2
  2. package/dist/{deploy-B1WrPq5W.mjs → deploy-CnxJ4TE6.mjs} +2 -2
  3. package/dist/dev-BqLvttKc.mjs +2 -0
  4. package/dist/{dev-BnUYGQQm.mjs → dev-CyJT6EfQ.mjs} +4 -4
  5. package/dist/docs/ci.md +50 -0
  6. package/dist/docs/cli-create.md +46 -0
  7. package/dist/docs/cli-db.md +86 -0
  8. package/dist/docs/cli-delete.md +44 -0
  9. package/dist/docs/cli-deploy.md +58 -0
  10. package/dist/docs/cli-dev.md +82 -0
  11. package/dist/docs/cli-docs.md +47 -0
  12. package/dist/docs/cli-download.md +42 -0
  13. package/dist/docs/cli-egress.md +37 -0
  14. package/dist/docs/cli-feedback.md +75 -0
  15. package/dist/docs/cli-index.md +61 -0
  16. package/dist/docs/cli-init.md +46 -0
  17. package/dist/docs/cli-login.md +43 -0
  18. package/dist/docs/cli-logout.md +32 -0
  19. package/dist/docs/cli-logs.md +57 -0
  20. package/dist/docs/cli-open.md +41 -0
  21. package/dist/docs/cli-projects.md +43 -0
  22. package/dist/docs/cli-promote.md +44 -0
  23. package/dist/docs/cli-rollback.md +45 -0
  24. package/dist/docs/cli-skill.md +39 -0
  25. package/dist/docs/cli-staging.md +54 -0
  26. package/dist/docs/cli-token.md +47 -0
  27. package/dist/docs/cli-upgrade.md +43 -0
  28. package/dist/docs/cli-usage.md +43 -0
  29. package/dist/docs/cli-whoami.md +46 -0
  30. package/dist/docs/cli.md +86 -0
  31. package/dist/docs/data.md +85 -0
  32. package/dist/docs/deploy.md +81 -0
  33. package/dist/docs/dev.md +72 -0
  34. package/dist/docs/developers-agents-and-ai.md +95 -0
  35. package/dist/docs/developers-architecture.md +106 -0
  36. package/dist/docs/getting-started.md +108 -0
  37. package/dist/docs/index.json +336 -0
  38. package/dist/docs/infrastructure.md +406 -0
  39. package/dist/docs/migrations.md +183 -0
  40. package/dist/docs/overview-faq.md +105 -0
  41. package/dist/docs/overview-how-it-works.md +82 -0
  42. package/dist/docs/overview-use-cases.md +76 -0
  43. package/dist/docs/overview-what-is-canopy.md +75 -0
  44. package/dist/docs/platform-ai-usage.md +65 -0
  45. package/dist/docs/platform-client-access.md +54 -0
  46. package/dist/docs/platform-deploys-and-rollbacks.md +93 -0
  47. package/dist/docs/platform-egress.md +75 -0
  48. package/dist/docs/platform-feedback.md +114 -0
  49. package/dist/docs/platform-google.md +213 -0
  50. package/dist/docs/platform-members-and-access.md +71 -0
  51. package/dist/docs/platform-project-data.md +76 -0
  52. package/dist/docs/platform-schedules.md +90 -0
  53. package/dist/docs/platform-sites-and-profiles.md +61 -0
  54. package/dist/docs/porting-nextjs.md +233 -0
  55. package/dist/docs/sdk-ai.md +103 -0
  56. package/dist/docs/sdk-auth.md +57 -0
  57. package/dist/docs/sdk-database.md +126 -0
  58. package/dist/docs/sdk-files.md +82 -0
  59. package/dist/docs/sdk-services.md +58 -0
  60. package/dist/docs/sdk.md +126 -0
  61. package/dist/docs/staging.md +106 -0
  62. package/dist/docs/static-serving.md +323 -0
  63. package/dist/docs/troubleshooting.md +102 -0
  64. package/dist/{docs-DxB7NhZs.mjs → docs-BBMVxVta.mjs} +2 -2
  65. package/dist/{egress-CN_axsAN.mjs → egress-BFSwa8Uu.mjs} +1 -1
  66. package/dist/{feedback-B-GXUBPs.mjs → feedback-BMX_d4KZ.mjs} +2 -2
  67. package/dist/index.mjs +25 -24
  68. package/dist/{local-BGRd_FMZ.mjs → local-BQxsp-ZQ.mjs} +2 -2
  69. package/dist/{login-D7dI8D9N.mjs → login-BDTO3nVw.mjs} +1 -1
  70. package/dist/{logs-DNiZquki.mjs → logs-C53y2eAS.mjs} +1 -1
  71. package/dist/{migrations-C-5x6SYf.mjs → migrations-C6EcKD6a.mjs} +1 -1
  72. package/dist/{open-DRPp4QJg.mjs → open-C5x3tX6I.mjs} +1 -1
  73. package/dist/{package-CDLufecy.mjs → package-vJXq4RNN.mjs} +1 -1
  74. package/dist/{projects-C6JQjVqg.mjs → projects-MMbv7MmK.mjs} +1 -1
  75. package/dist/schedule-Cq9K0rnE.mjs +106 -0
  76. package/dist/skill/canopy/SKILL.md +160 -0
  77. package/dist/{skill-BOWfqwr2.mjs → skill-Zq9aIPKf.mjs} +2 -2
  78. package/dist/{staging-Bw1D_J8M.mjs → staging-D8G4amjO.mjs} +1 -1
  79. package/dist/templates/spa/.github/workflows/canopy-deploy.yml +34 -0
  80. package/dist/templates/spa/AGENTS.md +47 -0
  81. package/dist/templates/spa/README.md +14 -0
  82. package/dist/templates/spa/_gitignore +4 -0
  83. package/dist/templates/spa/canopy.json +5 -0
  84. package/dist/templates/spa/index.html +12 -0
  85. package/dist/templates/spa/package.json +21 -0
  86. package/dist/templates/spa/src/app.tsx +25 -0
  87. package/dist/templates/spa/src/canopy.ts +5 -0
  88. package/dist/templates/spa/src/main.tsx +10 -0
  89. package/dist/templates/spa/src/style.css +29 -0
  90. package/dist/templates/spa/tsconfig.json +16 -0
  91. package/dist/templates/spa/vite.config.ts +7 -0
  92. package/dist/templates/static/AGENTS.md +45 -0
  93. package/dist/templates/static/README.md +9 -0
  94. package/dist/templates/static/_gitignore +2 -0
  95. package/dist/templates/static/canopy.json +4 -0
  96. package/dist/templates/static/index.html +21 -0
  97. package/dist/templates/static/main.js +9 -0
  98. package/dist/templates/static/style.css +29 -0
  99. package/dist/templates/worker/.dev.vars.example +9 -0
  100. package/dist/templates/worker/.github/workflows/canopy-deploy.yml +34 -0
  101. package/dist/templates/worker/AGENTS.md +63 -0
  102. package/dist/templates/worker/README.md +17 -0
  103. package/dist/templates/worker/_gitignore +5 -0
  104. package/dist/templates/worker/canopy.json +6 -0
  105. package/dist/templates/worker/index.html +12 -0
  106. package/dist/templates/worker/package.json +22 -0
  107. package/dist/templates/worker/src/app.tsx +25 -0
  108. package/dist/templates/worker/src/canopy.ts +5 -0
  109. package/dist/templates/worker/src/main.tsx +10 -0
  110. package/dist/templates/worker/src/style.css +29 -0
  111. package/dist/templates/worker/tsconfig.json +16 -0
  112. package/dist/templates/worker/vite.config.ts +7 -0
  113. package/dist/templates/worker/worker/index.ts +52 -0
  114. package/dist/{token-D7zrIF8G.mjs → token-BUxgRJVA.mjs} +1 -1
  115. package/dist/{ui-2mrJcjYC.mjs → ui-B1Px5y7q.mjs} +17 -0
  116. package/dist/{upgrade-fhfrid_O.mjs → upgrade-ES8u8_Pn.mjs} +2 -2
  117. package/dist/{usage-CX1Izj_l.mjs → usage-DjNngyvy.mjs} +1 -1
  118. package/package.json +1 -1
  119. package/dist/dev-CySBxW7I.mjs +0 -2
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "jsx": "react-jsx",
8
+ "strict": true,
9
+ "noEmit": true,
10
+ "skipLibCheck": true,
11
+ "isolatedModules": true,
12
+ "allowImportingTsExtensions": true,
13
+ "noUncheckedIndexedAccess": true
14
+ },
15
+ "include": ["src", "vite.config.ts"]
16
+ }
@@ -0,0 +1,7 @@
1
+ import react from "@vitejs/plugin-react";
2
+ import { defineConfig } from "vite";
3
+
4
+ // `canopy dev` picks this config up and adds its own /_api proxy on top.
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ });
@@ -0,0 +1,45 @@
1
+ # {{name}} — a Canopy static app
2
+
3
+ A no-build web app on [Canopy](https://dashboard.thanarie.dev), Monks' managed
4
+ platform for internal projects. Everything is served behind company login;
5
+ there is no infrastructure to manage and none should be added.
6
+
7
+ ## Canopy skill
8
+
9
+ The full SDK reference (auth, db, blob, ai) and platform guardrails ship as an
10
+ agent skill, kept out of this scaffold so it stays current. Install it before
11
+ building features:
12
+
13
+ ```
14
+ npx skills add mediamonks/canopy
15
+ ```
16
+
17
+ If that fails the skill isn't published yet — the SDK surface is documented on
18
+ the [Canopy dashboard](https://dashboard.thanarie.dev).
19
+
20
+ ## Working on this project
21
+
22
+ - Plain html/css/js in this directory — no bundler, no install step. The
23
+ Canopy SDK is imported straight from the platform, so it always matches the
24
+ API version: `import { createCanopy } from "/_api/data/v1/sdk.js";`
25
+ - `canopy dev` — local dev server; its `/_api` proxies to the real platform.
26
+ That is LIVE project data: read freely, but take a `canopy db snapshot`
27
+ before risky data changes.
28
+ - `canopy dev --local [--pull]` — offline sandbox with local data instead;
29
+ writes never reach the platform. Prefer it for destructive experiments.
30
+ - `canopy deploy` — publish; live (behind company login) at
31
+ https://{{slug}}.thanarie.dev.
32
+ - Risky change (schema migration, backend rework)? `canopy deploy --staging`
33
+ first — a private copy with its own database cloned from live — verify, then
34
+ `canopy promote` ships the exact tested version. Never promote with failing
35
+ checks.
36
+
37
+ ## Boundaries
38
+
39
+ - Do not add auth — the platform authenticates every request before it
40
+ reaches this app.
41
+ - Do not store secrets anywhere in this project, and never call external APIs
42
+ that need them from the browser — all backend needs go through the Canopy
43
+ SDK (`canopy.auth`, `canopy.db`, `canopy.blob`, `canopy.ai`).
44
+ - Keep it a static site: no SSR, no custom servers, no databases outside
45
+ `canopy.db`.
@@ -0,0 +1,9 @@
1
+ # {{name}}
2
+
3
+ A [Canopy](https://dashboard.thanarie.dev) project. Live (behind company
4
+ login) at https://{{slug}}.thanarie.dev after the first `canopy deploy`.
5
+
6
+ - `canopy dev` — develop locally against the live platform (real data!)
7
+ - `canopy dev --local [--pull]` — offline sandbox with local data instead
8
+ - `canopy deploy` — publish the current directory
9
+ - `AGENTS.md` — project guardrails and skill setup for coding agents
@@ -0,0 +1,2 @@
1
+ .canopy/
2
+ .DS_Store
@@ -0,0 +1,4 @@
1
+ {
2
+ "slug": "{{slug}}",
3
+ "dist": "."
4
+ }
@@ -0,0 +1,21 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>{{name}}</title>
7
+ <link rel="stylesheet" href="./style.css" />
8
+ </head>
9
+ <body>
10
+ <main>
11
+ <h1>{{name}}</h1>
12
+ <p class="status" id="status">connecting to Canopy…</p>
13
+ <section id="app">
14
+ <p class="placeholder">
15
+ Start building — edit <code>main.js</code>, then run <code>canopy deploy</code>.
16
+ </p>
17
+ </section>
18
+ </main>
19
+ <script type="module" src="./main.js"></script>
20
+ </body>
21
+ </html>
@@ -0,0 +1,9 @@
1
+ // The Canopy SDK is served by the platform itself — nothing to install.
2
+ // Auth (auth), data (db), files (blob) and AI (ai) are all live — see
3
+ // AGENTS.md for how to get the full SDK reference.
4
+ import { createCanopy } from "/_api/data/v1/sdk.js";
5
+
6
+ const canopy = createCanopy();
7
+
8
+ const user = await canopy.auth.user();
9
+ document.getElementById("status").textContent = `signed in as ${user.email}`;
@@ -0,0 +1,29 @@
1
+ :root {
2
+ font-family: system-ui, sans-serif;
3
+ color-scheme: light dark;
4
+ }
5
+
6
+ body {
7
+ margin: 0;
8
+ display: grid;
9
+ place-items: center;
10
+ min-height: 100vh;
11
+ }
12
+
13
+ main {
14
+ max-width: 40rem;
15
+ padding: 2rem;
16
+ text-align: center;
17
+ }
18
+
19
+ .status {
20
+ font-size: 0.9rem;
21
+ opacity: 0.7;
22
+ }
23
+
24
+ .placeholder {
25
+ border: 1px dashed color-mix(in srgb, currentColor 30%, transparent);
26
+ border-radius: 8px;
27
+ padding: 1.5rem;
28
+ opacity: 0.6;
29
+ }
@@ -0,0 +1,9 @@
1
+ # Local worker secrets for `canopy dev` — copy to .dev.vars (gitignored).
2
+ #
3
+ # Dashboard secrets (Settings → Secrets) are never downloaded: the platform
4
+ # can't hand a stored value back, and live keys don't belong on a laptop. Set
5
+ # local stand-ins here; the worker reads them as c.env.NAME, exactly as it
6
+ # reads the dashboard's in production. `canopy dev` prints which dashboard
7
+ # secret names this file is missing.
8
+ #
9
+ # MY_API_KEY=local-test-key
@@ -0,0 +1,34 @@
1
+ # Deploy to Canopy on every push to main. GitHub's runners are the build
2
+ # farm — the platform owns no build infrastructure.
3
+ #
4
+ # Needs a CANOPY_DEPLOY_TOKEN repo secret: create a deploy token in the
5
+ # dashboard (project → Settings → Deploy tokens) or with `canopy token
6
+ # create`, then add it via `gh secret set CANOPY_DEPLOY_TOKEN` or the repo's
7
+ # Settings → Secrets. Until the secret is set, this workflow skips itself
8
+ # instead of failing the build.
9
+ name: Deploy to Canopy
10
+
11
+ on:
12
+ push:
13
+ branches: [main]
14
+
15
+ jobs:
16
+ deploy:
17
+ runs-on: ubuntu-latest
18
+ env:
19
+ CANOPY_DEPLOY_TOKEN: ${{ secrets.CANOPY_DEPLOY_TOKEN }}
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ - uses: actions/setup-node@v4
23
+ with:
24
+ node-version: 22
25
+ - name: Install dependencies
26
+ if: env.CANOPY_DEPLOY_TOKEN != ''
27
+ run: |
28
+ if [ -f package-lock.json ]; then npm ci; else npm install; fi
29
+ - name: Deploy
30
+ if: env.CANOPY_DEPLOY_TOKEN != ''
31
+ run: npm exec --yes @mediamonks/canopy-cli deploy
32
+ - name: Skipped (no deploy token)
33
+ if: env.CANOPY_DEPLOY_TOKEN == ''
34
+ run: echo "CANOPY_DEPLOY_TOKEN secret not set — skipping deploy."
@@ -0,0 +1,63 @@
1
+ # {{name}} — a Canopy React SPA with a backend Worker
2
+
3
+ A Vite + React single-page app plus a per-project backend Worker on
4
+ [Canopy](https://dashboard.thanarie.dev), Monks' managed platform for internal
5
+ projects. Everything is served behind company login; there is no
6
+ infrastructure to manage and none should be added.
7
+
8
+ ## Canopy skill
9
+
10
+ The full SDK reference (auth, db, blob, ai) and platform guardrails ship as an
11
+ agent skill, kept out of this scaffold so it stays current. Install it before
12
+ building features:
13
+
14
+ ```
15
+ npx skills add mediamonks/canopy
16
+ ```
17
+
18
+ If that fails the skill isn't published yet — the SDK surface is documented on
19
+ the [Canopy dashboard](https://dashboard.thanarie.dev).
20
+
21
+ ## Working on this project
22
+
23
+ - Frontend: a standard Vite + React + TypeScript app in `src/`; `npm install`
24
+ once, then develop with `canopy dev` (it runs Vite with this project's
25
+ `vite.config.ts` and proxies `/_api` to the platform).
26
+ - Backend: Hono-style handlers in `worker/index.ts`, serving `/api/*`, plus an
27
+ optional `scheduled(event, env)` for dashboard Schedules (switch on
28
+ `event.name`). It runs behind the Canopy gateway (HTTP requests arrive
29
+ authenticated) and reaches the platform through a service binding — same
30
+ SDK, same budgets and data isolation as the browser.
31
+ - `canopy dev` serves the worker as well: `/api/*` goes to
32
+ `worker/index.ts` with the same `env` it gets deployed, no build step. Tick a
33
+ schedule by hand with
34
+ `curl -X POST localhost:5173/__canopy/scheduled -d '{"name":"<schedule>"}'`.
35
+ - The SDK comes from npm (`@mediamonks/canopy`) — the browser's shared
36
+ instance lives in `src/canopy.ts`.
37
+ - `canopy dev` uses LIVE project data: read freely, but take a
38
+ `canopy db snapshot` before risky data changes.
39
+ - `canopy dev --local [--pull]` — offline sandbox with local data instead;
40
+ writes never reach the platform. Prefer it for destructive experiments.
41
+ - `canopy deploy` — builds (`npm run build`) and publishes; live (behind
42
+ company login) at https://{{slug}}.thanarie.dev.
43
+ - Defining your own tables (raw `sql()` / Drizzle)? Use the migrations flow —
44
+ `canopy docs migrations`. Never invent a `DATABASE_URL` (none exists):
45
+ generate migrations locally, and `canopy deploy` applies them.
46
+ - Risky change (schema migration, backend rework)? `canopy deploy --staging`
47
+ first — a private copy with its own database cloned from live — verify, then
48
+ `canopy promote` ships the exact tested version. Never promote with failing
49
+ checks.
50
+
51
+ ## Boundaries
52
+
53
+ - Do not add auth — the platform authenticates every request before it
54
+ reaches this app or the Worker.
55
+ - Do not store secrets in the repo or SPA. Set them in the Canopy dashboard
56
+ (Settings → Secrets); the Worker reads them as `c.env.SECRET_NAME`
57
+ (Workers-shaped bindings — not `process.env`). Locally, put stand-in values
58
+ in `.dev.vars` (gitignored, see `.dev.vars.example`) — dashboard values are
59
+ never downloaded, and `canopy dev` prints which names are still missing. Platform access still goes
60
+ through the Canopy SDK (`canopy.auth`, `canopy.db`, `canopy.blob`,
61
+ `canopy.ai`) in both the browser and the Worker.
62
+ - The Worker is the only backend: no SSR, no long-running processes, no
63
+ databases outside `canopy.db` / `c.env.DB`.
@@ -0,0 +1,17 @@
1
+ # {{name}}
2
+
3
+ A [Canopy](https://dashboard.thanarie.dev) project — Vite + React with a
4
+ backend Worker (`worker/`). Live (behind company login) at
5
+ https://{{slug}}.thanarie.dev after the first `canopy deploy`.
6
+
7
+ - `npm install` — once, then:
8
+ - `canopy dev` — develop locally against the live platform (real data!);
9
+ `/api/*` is served by `worker/index.ts`, everything else by the SPA
10
+ - `.dev.vars` — local values for the worker's secrets (copy
11
+ `.dev.vars.example`); dashboard secrets are never downloaded
12
+ - `canopy dev --local [--pull]` — offline sandbox with local data instead
13
+ - `canopy deploy` — build and publish the frontend and the `worker/` backend
14
+ - `AGENTS.md` — project guardrails and skill setup for coding agents
15
+
16
+ Push-to-main deploys are prepared in `.github/workflows/canopy-deploy.yml`
17
+ (needs a `CANOPY_DEPLOY_TOKEN` repo secret — see the workflow file).
@@ -0,0 +1,5 @@
1
+ node_modules/
2
+ dist/
3
+ .canopy/
4
+ .dev.vars
5
+ .DS_Store
@@ -0,0 +1,6 @@
1
+ {
2
+ "slug": "{{slug}}",
3
+ "build": "npm run build",
4
+ "dist": "dist",
5
+ "worker": "worker/index.ts"
6
+ }
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>{{name}}</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "{{slug}}",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "canopy dev",
7
+ "build": "tsc && vite build"
8
+ },
9
+ "dependencies": {
10
+ "@mediamonks/canopy": "^0.0.4",
11
+ "hono": "^4.8.0",
12
+ "react": "^19.1.0",
13
+ "react-dom": "^19.1.0"
14
+ },
15
+ "devDependencies": {
16
+ "@types/react": "^19.1.0",
17
+ "@types/react-dom": "^19.1.0",
18
+ "@vitejs/plugin-react": "^5.0.0",
19
+ "typescript": "^5.8.0",
20
+ "vite": "^7.0.0"
21
+ }
22
+ }
@@ -0,0 +1,25 @@
1
+ import { useEffect, useState } from "react";
2
+ import { canopy } from "./canopy.ts";
3
+
4
+ export function App() {
5
+ const [status, setStatus] = useState("connecting to Canopy…");
6
+
7
+ useEffect(() => {
8
+ canopy.auth
9
+ .user()
10
+ .then((user) => setStatus(`signed in as ${user.email}`))
11
+ .catch(() => setStatus("could not reach Canopy — is `canopy dev` running?"));
12
+ }, []);
13
+
14
+ return (
15
+ <main>
16
+ <h1>{"{{name}}"}</h1>
17
+ <p className="status">{status}</p>
18
+ <section>
19
+ <p className="placeholder">
20
+ Start building — edit <code>src/app.tsx</code>, then run <code>canopy deploy</code>.
21
+ </p>
22
+ </section>
23
+ </main>
24
+ );
25
+ }
@@ -0,0 +1,5 @@
1
+ // One SDK instance for the whole app. Auth (auth), data (db), files (blob)
2
+ // and AI (ai) are all live — see AGENTS.md for how to get the full reference.
3
+ import { createCanopy } from "@mediamonks/canopy";
4
+
5
+ export const canopy = createCanopy();
@@ -0,0 +1,10 @@
1
+ import { StrictMode } from "react";
2
+ import { createRoot } from "react-dom/client";
3
+ import { App } from "./app.tsx";
4
+ import "./style.css";
5
+
6
+ createRoot(document.getElementById("root") as HTMLElement).render(
7
+ <StrictMode>
8
+ <App />
9
+ </StrictMode>,
10
+ );
@@ -0,0 +1,29 @@
1
+ :root {
2
+ font-family: system-ui, sans-serif;
3
+ color-scheme: light dark;
4
+ }
5
+
6
+ body {
7
+ margin: 0;
8
+ display: grid;
9
+ place-items: center;
10
+ min-height: 100vh;
11
+ }
12
+
13
+ main {
14
+ max-width: 40rem;
15
+ padding: 2rem;
16
+ text-align: center;
17
+ }
18
+
19
+ .status {
20
+ font-size: 0.9rem;
21
+ opacity: 0.7;
22
+ }
23
+
24
+ .placeholder {
25
+ border: 1px dashed color-mix(in srgb, currentColor 30%, transparent);
26
+ border-radius: 8px;
27
+ padding: 1.5rem;
28
+ opacity: 0.6;
29
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "jsx": "react-jsx",
8
+ "strict": true,
9
+ "noEmit": true,
10
+ "skipLibCheck": true,
11
+ "isolatedModules": true,
12
+ "allowImportingTsExtensions": true,
13
+ "noUncheckedIndexedAccess": true
14
+ },
15
+ "include": ["src", "worker", "vite.config.ts"]
16
+ }
@@ -0,0 +1,7 @@
1
+ import react from "@vitejs/plugin-react";
2
+ import { defineConfig } from "vite";
3
+
4
+ // `canopy dev` picks this config up and adds its own /_api proxy on top.
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ });
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The project's own backend Worker (Hono-style handlers). It runs behind the
3
+ * Canopy gateway — every request is already authenticated — and reaches the
4
+ * platform (db/blob/ai) through the CANOPY service binding, so budgets and
5
+ * data isolation still apply.
6
+ *
7
+ * On GCP, `canopy deploy` bundles this file and rolls a per-project Cloud Run
8
+ * service (docs/05-gcp-plan.md G6). Routes under `/api/*` reach this Worker;
9
+ * everything else serves the SPA. Dashboard schedules call `scheduled()`
10
+ * (docs/07-schedules.md).
11
+ */
12
+
13
+ import { createCanopy } from "@mediamonks/canopy";
14
+ import { Hono } from "hono";
15
+
16
+ interface Env {
17
+ // Service binding to the platform API (canopy-api), scoped to this project.
18
+ CANOPY: { fetch: typeof fetch };
19
+ // Dashboard secrets (Settings → Secrets) land as Workers-shaped bindings:
20
+ // MY_API_KEY?: string;
21
+ }
22
+
23
+ interface ScheduledEvent {
24
+ name: string;
25
+ cron: string;
26
+ scheduledTime: number;
27
+ type: "scheduled";
28
+ }
29
+
30
+ const app = new Hono<{ Bindings: Env }>();
31
+
32
+ // Routes under /api/* reach this Worker; everything else serves the SPA.
33
+ app.get("/api/hello", async (c) => {
34
+ const canopy = createCanopy({ fetch: c.env.CANOPY.fetch.bind(c.env.CANOPY) });
35
+ const user = await canopy.auth.user();
36
+ return c.json({ message: `Hello from the backend, ${user.name}!` });
37
+ });
38
+
39
+ export default {
40
+ fetch: app.fetch.bind(app),
41
+
42
+ // Settings → Schedules: switch on event.name (not the cron string).
43
+ async scheduled(event: ScheduledEvent, _env: Env) {
44
+ switch (event.name) {
45
+ // case "daily-digest":
46
+ // await doWork(_env);
47
+ // break;
48
+ default:
49
+ console.warn("unhandled schedule", event.name);
50
+ }
51
+ },
52
+ };
@@ -1,5 +1,5 @@
1
1
  import { a as projectDirArgs, c as resolveProject, o as projectFlagArgs } from "./site-BUlQR117.mjs";
2
- import { c as apiRequest, n as reportErrors } from "./ui-2mrJcjYC.mjs";
2
+ import { c as apiRequest, n as reportErrors } from "./ui-B1Px5y7q.mjs";
3
3
  import { defineCommand } from "citty";
4
4
  const tokenCommand = defineCommand({
5
5
  meta: {
@@ -114,6 +114,22 @@ const ERROR_COPY = {
114
114
  why: "the report already has the maximum number of screenshots",
115
115
  fix: "Remove one from the report on the dashboard before attaching another."
116
116
  },
117
+ invalid_name: {
118
+ why: "the schedule name is not a valid format",
119
+ fix: "Use lowercase letters, digits and hyphens, starting with a letter (e.g. refresh-feeds)."
120
+ },
121
+ invalid_cron: {
122
+ why: "the cron expression is not a valid five-field cron",
123
+ fix: "Use five space-separated fields, quoted — minute hour day month weekday (e.g. \"0 5 * * *\")."
124
+ },
125
+ too_many_schedules: {
126
+ why: "the project is at its schedule limit",
127
+ fix: "Remove a schedule you no longer need (`canopy schedule list` / `canopy schedule remove`)."
128
+ },
129
+ scheduler_sync_failed: {
130
+ why: "the schedule was saved but syncing it to the platform scheduler failed",
131
+ fix: "Retry the same command — it re-syncs the saved schedule."
132
+ },
117
133
  worker_egress_sync_failed: {
118
134
  why: "the list was saved but redeploying the running worker with it failed",
119
135
  fix: "Retry, or redeploy the project (`canopy deploy`) to apply the new allowlist."
@@ -221,6 +237,7 @@ async function apiRequest(method, path, body, rawContentType, headers) {
221
237
  body: body === void 0 ? void 0 : isForm ? body : rawContentType !== void 0 ? body : JSON.stringify(body)
222
238
  });
223
239
  if (!response.ok) return fail(response, isDeployToken, method, path);
240
+ if (response.status === 204) return void 0;
224
241
  return await response.json();
225
242
  }
226
243
  /**
@@ -1,5 +1,5 @@
1
1
  import { t as PACKAGE_NAME } from "./version-check-CcsA1QjI.mjs";
2
- import { n as reportErrors } from "./ui-2mrJcjYC.mjs";
2
+ import { n as reportErrors } from "./ui-B1Px5y7q.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-BOWfqwr2.mjs");
115
+ const { skillInstalled } = await import("./skill-Zq9aIPKf.mjs");
116
116
  const refreshSkill = skillInstalled(process.cwd());
117
117
  console.log(`Upgrading via ${command}: ${command} ${cmd.join(" ")}`);
118
118
  await run(command, cmd);
@@ -1,5 +1,5 @@
1
1
  import { c as resolveProject, o as projectFlagArgs } from "./site-BUlQR117.mjs";
2
- import { c as apiRequest, n as reportErrors, u as withContext } from "./ui-2mrJcjYC.mjs";
2
+ import { c as apiRequest, n as reportErrors, u as withContext } from "./ui-B1Px5y7q.mjs";
3
3
  import { defineCommand } from "citty";
4
4
  //#region src/usage.ts
5
5
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mediamonks/canopy-cli",
3
- "version": "0.7.12",
3
+ "version": "0.7.13",
4
4
  "description": "Canopy CLI — create, develop and deploy Canopy projects.",
5
5
  "bin": {
6
6
  "canopy": "./dist/index.mjs"
@@ -1,2 +0,0 @@
1
- import { t as devCommand } from "./dev-BnUYGQQm.mjs";
2
- export { devCommand };