@surph_ai/cli 0.0.37 → 0.0.38
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/board/deploy.js +40 -4
- package/package.json +1 -1
- package/scaffold/board/AGENTS.md +2 -2
- package/scaffold/board/README.md +21 -18
- package/scaffold/board/site/index.html +5 -7
- package/scaffold/index.js +3 -1
package/board/deploy.js
CHANGED
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
// 4. Unzip it on S3 into boards/<slug>/site/ (the board's pages and assets).
|
|
14
14
|
// 5. Upload board.json to boards/<slug>/board.json — last, so the live
|
|
15
15
|
// board's definition only changes once its site is up.
|
|
16
|
+
// 6. Clear the board's files from the CDN cache (CloudFront serves
|
|
17
|
+
// https://<slug>.surph-boards.com from boards/<slug>/site/), so the new
|
|
18
|
+
// version shows right away.
|
|
16
19
|
//
|
|
17
20
|
// Node's built-ins only (zlib for compression, fetch for the upload). Needs
|
|
18
21
|
// Node.js 20 or later.
|
|
@@ -28,6 +31,8 @@ const RPC_URL = 'https://rpc.surph.ai';
|
|
|
28
31
|
const SYNC_URL = 'https://e3lunom2hka3u6iiotrlzrcez40uwdnk.lambda-url.us-east-1.on.aws/';
|
|
29
32
|
// Also the board's host name (<slug>.surph-boards.com), so at most 63 characters.
|
|
30
33
|
const SLUG_RE = /^[a-z0-9][a-z0-9-]{0,62}$/;
|
|
34
|
+
// The CloudFront distribution in front of the boards (*.surph-boards.com).
|
|
35
|
+
const CLOUDFRONT_ID = 'E1AB54JQZBIU11';
|
|
31
36
|
const PLACEHOLDER_SLUG = 'my-board';
|
|
32
37
|
|
|
33
38
|
// The board's site: site/ in its folder (boards/<slug>/site/ when live).
|
|
@@ -184,6 +189,28 @@ const upload = async (uploadUrl, body, filetype, filename) => {
|
|
|
184
189
|
}
|
|
185
190
|
};
|
|
186
191
|
|
|
192
|
+
// Clear boards/<slug>/* from CloudFront's cache (the `invalidateCache`
|
|
193
|
+
// action, on the same Lambda as `sync`). The board is already published by
|
|
194
|
+
// now, so a failure is reported, not fatal: the old files expire on their own.
|
|
195
|
+
const invalidateCache = async (slug) => {
|
|
196
|
+
const path = `/boards/${slug}/*`;
|
|
197
|
+
try {
|
|
198
|
+
const res = await fetch(SYNC_URL, {
|
|
199
|
+
method: 'POST',
|
|
200
|
+
headers: { 'Content-Type': 'application/json', Accept: 'application/json', 'Turbo-Client': 'portal' },
|
|
201
|
+
body: JSON.stringify({ action: 'invalidateCache', args: { cloudfront: CLOUDFRONT_ID, path } }),
|
|
202
|
+
});
|
|
203
|
+
const text = await res.text().catch(() => '');
|
|
204
|
+
let json = null;
|
|
205
|
+
try { json = JSON.parse(text); } catch { /* not JSON */ }
|
|
206
|
+
const error = json?.error || json?.response?.error || json?.data?.error;
|
|
207
|
+
if (!res.ok || error) throw new Error(typeof error === 'string' ? error : (error?.message || text.slice(0, 300) || `HTTP ${res.status}`));
|
|
208
|
+
console.log(`Cleared the CDN cache: ${path} (https://${slug}.surph-boards.com shows the new version in a minute or two)`);
|
|
209
|
+
} catch (e) {
|
|
210
|
+
console.warn(`The board is published, but clearing the CDN cache (${path}) failed: ${e.message}. https://${slug}.surph-boards.com may show the old version for a while.`);
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
187
214
|
// Unzip boards/<slug>/site/site.zip on S3 into boards/<slug>/site/.
|
|
188
215
|
const unzipOnS3 = async (slug) => {
|
|
189
216
|
const res = await fetch(SYNC_URL, {
|
|
@@ -208,11 +235,19 @@ const main = async () => {
|
|
|
208
235
|
fail(`No board.json in ${ROOT}. Run this from the board's folder.`);
|
|
209
236
|
}
|
|
210
237
|
const slug = boardSlug();
|
|
211
|
-
|
|
212
|
-
|
|
238
|
+
// A board whose pages live on its own site (pages by `url`, the site in
|
|
239
|
+
// board.json's `origins`) has no site/ to publish: only board.json goes up.
|
|
240
|
+
const hasSite = fs.existsSync(SITE) && fs.statSync(SITE).isDirectory();
|
|
241
|
+
const files = hasSite ? siteFiles() : [];
|
|
242
|
+
if (!files.length) {
|
|
243
|
+
console.log(`No site/ files to publish${hasSite ? ' (site/ is empty)' : ''}: publishing board.json only.`);
|
|
244
|
+
console.log(`\nDeploying the board "${slug}"…`);
|
|
245
|
+
const boardUrl = await uploadUrlFor(slug, 'board.json', 'application/json');
|
|
246
|
+
await upload(boardUrl, fs.readFileSync(path.join(ROOT, 'board.json')), 'application/json', 'board.json');
|
|
247
|
+
console.log(`Uploaded: ${boardUrl.split('?')[0]}`);
|
|
248
|
+
await invalidateCache(slug);
|
|
249
|
+
return;
|
|
213
250
|
}
|
|
214
|
-
const files = siteFiles();
|
|
215
|
-
if (!files.length) fail('Nothing to deploy: site/ has no files.');
|
|
216
251
|
|
|
217
252
|
const zip = zipFiles(files);
|
|
218
253
|
fs.writeFileSync(path.join(ROOT, ZIP_NAME), zip);
|
|
@@ -231,6 +266,7 @@ const main = async () => {
|
|
|
231
266
|
const boardUrl = await uploadUrlFor(slug, 'board.json', 'application/json');
|
|
232
267
|
await upload(boardUrl, fs.readFileSync(path.join(ROOT, 'board.json')), 'application/json', 'board.json');
|
|
233
268
|
console.log(`Uploaded: ${boardUrl.split('?')[0]}`);
|
|
269
|
+
await invalidateCache(slug);
|
|
234
270
|
};
|
|
235
271
|
|
|
236
272
|
const MIN_NODE = 20;
|
package/package.json
CHANGED
package/scaffold/board/AGENTS.md
CHANGED
|
@@ -25,7 +25,7 @@ Previewing and publishing the board need **Node.js 20 or later**. The pages them
|
|
|
25
25
|
|
|
26
26
|
Keep them in step on a board that hasn't been published yet. The person won't think about the slug, so you do:
|
|
27
27
|
|
|
28
|
-
1. **Whenever you set or change the board's name on an unpublished board, set `slug` from it in the same edit:** lowercase, spaces and punctuation turned into single dashes (BreakLedger → `breakledger`, "DC Tech Events" → `dc-tech-events`). Tell the person the slug you chose, in a word: it's the board's address (`https://<slug>.surph-boards.com`).
|
|
28
|
+
1. **Whenever you set or change the board's name on an unpublished board, set `slug` from it in the same edit:** lowercase, spaces and punctuation turned into single dashes (BreakLedger → `breakledger`, "DC Tech Events" → `dc-tech-events`). Tell the person the slug you chose, in a word: it's the board's address (`https://<slug>.surph-boards.com`). Every page names the slug too, on its SDK tag (`<script data-board="<slug>" src="…/surph-board.js">`): change it there in the same edit, or the page stops speaking for the board.
|
|
29
29
|
2. **A new board's slug starts from its folder name** (`surph board break-ledger` → `break-ledger`). Older boards may still have the placeholder `my-board`: replace it as soon as the board has a name. `npm run deploy` refuses to publish with `my-board`.
|
|
30
30
|
3. **Check the slug is free before you settle on it:** `curl -s -o /dev/null -w "%{http_code}" https://surph.s3.us-east-1.amazonaws.com/boards/<slug>/board.json`. `200` means a board with that slug already exists. If this folder never published it, it's someone else's: pick another (add a short suffix, e.g. `breakledger-dk`) and say so. Anything else (403 or 404) means it's free.
|
|
31
31
|
4. **Is this board published?** Treat it as published if the person says so, or if you ran `npm run deploy` for it. If unsure, ask.
|
|
@@ -34,7 +34,7 @@ Keep them in step on a board that hasn't been published yet. The person won't th
|
|
|
34
34
|
## The working loop
|
|
35
35
|
|
|
36
36
|
1. **Preview:** run `npm run dev` from this folder and leave it running. It serves the board at `http://localhost:4180`: the pages in `site/` as its base (`/` is `site/index.html`), plus `/board.json` (nothing to install; it uses the Surph CLI through `npx`).
|
|
37
|
-
2. **See it in Surph:** ask the person to open Surph, go to **Settings → Developer**, turn on **Run Surph as a local board**, and keep the address `http://localhost:4180`. Surph reloads as this board.
|
|
37
|
+
2. **See it in Surph:** ask the person to open Surph, go to **Settings → Developer**, turn on **Run Surph as a local board**, and keep the address `http://localhost:4180`. Surph reloads as this board. Or, simpler: with `npm run dev` running, the person says "open http://localhost:4180" in Surph's chat, and the board joins the chat (its pages must load the SDK with `board: '<slug>'` and call `ready()`; see the README).
|
|
38
38
|
3. **Configure the board** (name, contexts, tools, instructions): the person can click the **DEV** label in Surph's canvas header to open the Local board panel, which saves `board.json` for you. You can also edit `board.json` directly; the README describes every field.
|
|
39
39
|
4. **Change pages:** the pages and their assets live in `site/` (`site/index.html`, `site/assets/…`). Edit them there and keep `board.json`'s `config.pages` in step (every page listed, `shows` written as plain facts, `ops` matching the page's `host.rpc` calls). The person reloads Surph to see the change.
|
|
40
40
|
5. **Publish:** `npm run deploy`. **Only when the person asks you to in this conversation.** It replaces the live board for everyone who uses it. Check the board in dev mode first, and check `slug` first (see above): not `my-board`, and either free or this board's own. Once deployed, the site is live at `https://<slug>.surph-boards.com/`.
|
package/scaffold/board/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Surph board
|
|
2
2
|
|
|
3
|
-
This project is a **Surph board**: a set of web pages that Surph shows in its **canvas**, the panel beside the Surph chat. Each page is a static HTML file. Surph loads it in an iframe and answers the page's requests for data. The page talks to Surph only through the Surph SDK (`surph-
|
|
3
|
+
This project is a **Surph board**: a set of web pages that Surph shows in its **canvas**, the panel beside the Surph chat. Each page is a static HTML file. Surph loads it in an iframe and answers the page's requests for data. The page talks to Surph only through the Surph board SDK (`surph-board.js`), which works over `postMessage`.
|
|
4
4
|
|
|
5
5
|
**If you're a coding agent, read this whole file before writing a page.** Surph answers only the operations listed in [Operations the host answers](#operations-the-host-answers), with exactly the payloads shown. A page that calls anything else gets an error, and a field not listed here doesn't exist.
|
|
6
6
|
|
|
@@ -96,6 +96,7 @@ Surph only shows pages that are registered with the board. The board itself is d
|
|
|
96
96
|
| `tools` | Slugs of Surph tools the board's chat can use. Optional. |
|
|
97
97
|
| `config.instructions` | Instructions from the board's owner for the board's chat: tone, behavior, what it helps with. On a board they take the place of each context's own instructions. |
|
|
98
98
|
| `config.pages` | The board's pages, one registry entry each (below). |
|
|
99
|
+
| `origins` | Optional. Other sites allowed to speak for this board, as origins (`["https://breakledger.com"]`), for pages hosted outside Surph that load the SDK with `board: '<slug>'`. The board's own `https://<slug>.surph-boards.com` is always allowed. List only sites you control: a listed site can speak as the board. |
|
|
99
100
|
| `config.icon` | Optional. The board's icon: a file in `site/`, by its path there (`apple-touch-icon.png`, `assets/img/icon.png`). Surph shows it beside the board's name: on each of the chat's replies ("@BreakLedger") and in the header. A small square image works best. |
|
|
100
101
|
|
|
101
102
|
A registry entry:
|
|
@@ -121,31 +122,31 @@ A registry entry:
|
|
|
121
122
|
|
|
122
123
|
## The SDK
|
|
123
124
|
|
|
124
|
-
Every page loads the SDK from this exact URL. Don't copy, bundle, edit or replace it.
|
|
125
|
+
Every page loads the SDK from this exact URL, with the board's slug on the tag. Don't copy, bundle, edit or replace it.
|
|
125
126
|
|
|
126
127
|
```html
|
|
127
|
-
<script src="https://surph.s3.us-east-1.amazonaws.com/admin/desktop/js/
|
|
128
|
+
<script data-board="my-board" src="https://surph.s3.us-east-1.amazonaws.com/admin/desktop/js/board-sdk/v1/surph-board.js"></script>
|
|
128
129
|
```
|
|
129
130
|
|
|
130
|
-
It defines one global, `
|
|
131
|
+
`data-board` is this board's slug (`board.json`'s `slug`). With it, the SDK connects to Surph and announces the board as it loads; there's nothing to call. Add `data-page="events"` to name the page (optional). It defines one global, `SurphBoard`, for the page's own scripts:
|
|
131
132
|
|
|
132
133
|
```js
|
|
133
|
-
const host =
|
|
134
|
-
|
|
135
|
-
onRefresh: function () { paint(); } // Surph's data changed: ask again and repaint
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
host.ready(); // Call once, after connect
|
|
134
|
+
const host = SurphBoard.host; // The page's connection to Surph
|
|
135
|
+
SurphBoard.onRefresh(paint); // Surph's data changed: ask again and repaint
|
|
139
136
|
host.rpc(op, args, { timeout }); // Ask Surph for something; returns a Promise
|
|
140
137
|
host.hosted; // true inside the Surph canvas, false when opened directly
|
|
141
138
|
```
|
|
142
139
|
|
|
140
|
+
Setting it up by hand instead (a tag without `data-board`) also works: `const host = SurphBoard.connect({ board: 'my-board', page: 'events', onRefresh: paint }); host.ready();`. Either way there's one connection per page: `SurphBoard.connect()` returns `SurphBoard.host` when it already exists, and `ready()` announces once.
|
|
141
|
+
|
|
143
142
|
- `rpc(op, args, extra)` sends `args` as an object (use `{}` when there are none). It resolves with the operation's result object.
|
|
144
143
|
- It rejects with:
|
|
145
144
|
- `Error('host timeout')`: no reply in time. The default wait is 15 seconds; pass `{ timeout: 800 }` on reads.
|
|
146
145
|
- `Error('not in a Surph host')`: the page isn't inside the canvas (`hosted` is false).
|
|
147
146
|
- `Error('<message>')`: Surph answered with an error, for example `Unknown op: …` for an operation it doesn't support.
|
|
148
|
-
-
|
|
147
|
+
- `data-board` (or `board` in `connect`) says which board the page speaks for. The SDK passes it to Surph when the page loads, which checks the page's site against the board's: the board's own `https://<slug>.surph-boards.com`, plus any listed in `board.json`'s `origins`. A page on any other site is shown as an ordinary web page.
|
|
148
|
+
- When the chat reads the page, the SDK answers with the page's visible text on its own; nothing to add.
|
|
149
|
+
- Pages written before the board SDK load `surph-wave.js` and call `SurphWave.connect({ pageSlug, board, onRefresh })`. They still work; use the board SDK's tag for new pages and when you touch an old one.
|
|
149
150
|
|
|
150
151
|
## Call pattern
|
|
151
152
|
|
|
@@ -155,10 +156,9 @@ Every page that reads data uses this loop. Keep its rules:
|
|
|
155
156
|
- paint only after a successful reply.
|
|
156
157
|
|
|
157
158
|
```js
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
});
|
|
159
|
+
// The page loads <script data-board="my-board" src="…/surph-board.js"></script> first.
|
|
160
|
+
const host = SurphBoard.host;
|
|
161
|
+
SurphBoard.onRefresh(paint);
|
|
162
162
|
|
|
163
163
|
let painting = false;
|
|
164
164
|
async function paint() {
|
|
@@ -176,7 +176,6 @@ async function paint() {
|
|
|
176
176
|
// got is the operation's result. Paint it here (see "Rules for pages").
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
-
host.ready();
|
|
180
179
|
paint();
|
|
181
180
|
```
|
|
182
181
|
|
|
@@ -424,6 +423,7 @@ A field marked "omitted" is missing from the object, not `null`. Every URL is `h
|
|
|
424
423
|
2. Keep it running while you work; the terminal shows a line each time Surph saves `board.json`.
|
|
425
424
|
3. Open `http://localhost:4180/` (your `site/index.html`) to check a page loads without console errors. It shows its empty layout there (`hosted` is false); real data only appears inside the Surph canvas.
|
|
426
425
|
4. **Run Surph as your board with dev mode.** Keep `npm run dev` running. In Surph, open **Settings → Developer**, turn on **Run Surph as a local board**, and keep the address `http://localhost:4180`. Surph reloads as the board `board.json` describes: its name and icon in the header, its contexts and instructions in the chat, and its pages in the canvas (it opens on your start page, the Pages menu lists your pages, and the chat's model sees their `shows` lines). The status under the address says what loaded, or why it couldn't read `board.json`; until it loads, Surph runs as usual. A **DEV** label in the canvas header shows your board is loaded. While it's on, anything the chat saves goes to your own space in Surph, not to a board's shared space.
|
|
426
|
+
- **Or chat with the board without dev mode:** with `npm run dev` running, say "open http://localhost:4180" in Surph's chat. When the page loads the SDK with `board: '<slug>'` and calls `ready()`, the board joins the chat from the `board.json` at that address (it's your own machine, so no live board is needed): the canvas header shows it, its description opens its part of the conversation, and its replies are signed with its name. Live, the same happens for pages on `https://<slug>.surph-boards.com` or a site in `origins`.
|
|
427
427
|
5. **Configure the board from Surph.** Click the **DEV** label to open the **Local board** panel: set the board's name, slug, description and icon (an image in `site/`), pick its contexts (yours, or public ones by search) and which one the chat starts with, pick its tools, and write its instructions. The panel also lists the pages and flags a missing `shows` line or an operation the host doesn't answer. **Save and reload** writes `board.json` through the dev server and reloads Surph as the updated board. Pages and any other fields are kept as they are in the file; edit pages in `board.json` itself.
|
|
428
428
|
6. Dev mode affects only your browser. Turn it off in the same place to get Surph's own pages back.
|
|
429
429
|
7. In Surph, keep your browser's DevTools open with **Network → Disable cache** checked, or the canvas may keep showing an older copy of a page after you change it. After editing `board.json` by hand, reload Surph so it reads the file again.
|
|
@@ -432,13 +432,16 @@ A field marked "omitted" is missing from the object, not `null`. Every URL is `h
|
|
|
432
432
|
|
|
433
433
|
`npm run deploy` (`npx @surph_ai/cli board-deploy`, from the Surph CLI) publishes the board to Surph. Run it from the board's folder. It needs Node.js 20 or later and nothing else installed. In order, it:
|
|
434
434
|
|
|
435
|
+
A board whose pages live on its own site (pages listed by `url`, the site in `origins`) can have no `site/` folder, or an empty one: the deploy then publishes `board.json` only.
|
|
436
|
+
|
|
435
437
|
1. **Reads the board's `slug`** from `board.json` (lowercase letters, digits and dashes). The slug names the board's place in Surph, so it must be this board's own, not the placeholder `my-board` and not another board's (see the `slug` field above); without a valid one it stops before doing anything.
|
|
436
438
|
2. **Zips the site** into `site.zip`: every file in `site/`, except dot-files (`.env`, `.DS_Store`) and `node_modules`. Nothing outside `site/` is included (`board.json` goes up on its own in step 5). It lists the files it zipped.
|
|
437
439
|
3. **Uploads `site.zip`** to the board's `site/` folder in Surph's storage, then deletes the local `site.zip`. If the upload fails, the zip is kept to look at.
|
|
438
440
|
4. **Unzips it there**, so the board's `site/` folder in Surph's storage holds the same files as your `site/`, where each page's `file` is found.
|
|
439
441
|
5. **Uploads `board.json`**, last, so the live board's definition only changes once its pages are up. If an earlier step fails, `board.json` isn't uploaded and the live board keeps its previous version.
|
|
442
|
+
6. **Clears the board's cached files** at `https://<slug>.surph-boards.com`, so the new version shows within a minute or two. If this step fails, the board is still published; it says so, and the old files may show for a while.
|
|
440
443
|
|
|
441
|
-
Each step prints what it did; a failure prints why and stops. After a deploy, the site is live at `https://<slug>.surph-boards.com/`, and Surph picks up the new `board.json` within about a minute.
|
|
444
|
+
Each step prints what it did; a failure prints why and stops. After a deploy, the site is live at `https://<slug>.surph-boards.com/`, and Surph picks up the new `board.json` within about a minute. The deploy clears the cached copies there, so a changed file shows within a minute or two; reload to check.
|
|
442
445
|
|
|
443
446
|
**For coding agents:**
|
|
444
447
|
- **Deploying publishes the board to everyone who uses it.** Don't run `npm run deploy` unless the person asks you to in this conversation. Check the board with dev mode first (see [Developing locally](#developing-locally)).
|
|
@@ -451,7 +454,7 @@ Each step prints what it did; a failure prints why and stops. After a deploy, th
|
|
|
451
454
|
- [ ] Reads use the call pattern: a timeout retries, other errors stop, nothing is cleared before a reply.
|
|
452
455
|
- [ ] Data from Surph is written with `textContent`; links and images use only `http(s)` values.
|
|
453
456
|
- [ ] Operations that act for the person run only from their click (a start page's `page.open` aside).
|
|
454
|
-
- [ ] The SDK `<script>` tag is the v1 URL above, unchanged.
|
|
457
|
+
- [ ] The SDK `<script>` tag is the v1 URL above, unchanged, and every page's SDK tag has `data-board="<slug>"` matching `board.json`'s `slug`.
|
|
455
458
|
- [ ] Every page (in `site/`) links `assets/css/site.css?v=<n>`; if `site.css` changed, `<n>` is bumped in every page.
|
|
456
459
|
- [ ] `board.json`'s `config.pages` lists every page: `name`, `file` (or `url`), `shows` written as facts, `ops` matching the file's `rpc` calls, and one `start` page.
|
|
457
460
|
- [ ] Opened at `http://localhost:4180/<page>`, every page loads without console errors.
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
<h2>How a page works in Surph</h2>
|
|
82
82
|
<ul class="facts">
|
|
83
83
|
<li><strong>It's a static HTML file.</strong> No build step or framework. Surph loads it in an iframe; you can host it anywhere on <code>https</code>.</li>
|
|
84
|
-
<li><strong>It talks to Surph through the SDK.</strong> The page loads <code>surph-
|
|
84
|
+
<li><strong>It talks to Surph through the SDK.</strong> The page loads <code>surph-board.js</code>, calls <code>SurphBoard.connect()</code>, then asks the host for data with <code>host.rpc(op, args)</code>: the board's recent items, the chat's context, the items the chat looked up, and more. The page never calls Surph's servers itself.</li>
|
|
85
85
|
<li><strong>The chat decides when to show it.</strong> Each page is registered with a <code>shows</code> line, plain facts about what it displays. The chat's model reads those and opens the page that fits what the person asked. A page can also take values in its address (<code>?ids=…</code>) that the chat fills in.</li>
|
|
86
86
|
<li><strong>It updates as the chat goes.</strong> When the host's data changes, it calls the page's <code>onRefresh</code>, and the page asks again and repaints.</li>
|
|
87
87
|
<li><strong>Opened directly, it still loads.</strong> Outside Surph, <code>host.hosted</code> is false and every call rejects, so the page shows its empty layout. That's what you see here when you run it locally.</li>
|
|
@@ -95,12 +95,11 @@
|
|
|
95
95
|
<li><strong>See them in Surph:</strong> open <strong>Settings → Developer</strong> and turn on dev mode for <code>http://localhost:4180</code>. The canvas then shows the board's pages, with real data.</li>
|
|
96
96
|
</ol>
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
<!-- data-board: this board's slug (board.json's "slug"). The SDK connects and announces the board as it loads. -->
|
|
99
|
+
<script data-board="my-board" src="https://surph.s3.us-east-1.amazonaws.com/admin/desktop/js/board-sdk/v1/surph-board.js"></script>
|
|
99
100
|
<script>
|
|
100
|
-
const host =
|
|
101
|
-
|
|
102
|
-
onRefresh: function () { paint(); }
|
|
103
|
-
});
|
|
101
|
+
const host = SurphBoard.host;
|
|
102
|
+
SurphBoard.onRefresh(paint);
|
|
104
103
|
|
|
105
104
|
const statusBox = document.getElementById('status');
|
|
106
105
|
const statusTitle = document.getElementById('status-title');
|
|
@@ -145,7 +144,6 @@
|
|
|
145
144
|
: 'board.get answered: this chat isn’t on a board, so it has no board items.');
|
|
146
145
|
}
|
|
147
146
|
|
|
148
|
-
host.ready();
|
|
149
147
|
paint();
|
|
150
148
|
</script>
|
|
151
149
|
</body>
|
package/scaffold/index.js
CHANGED
|
@@ -285,7 +285,9 @@ const scaffoldBoard = async (name) => {
|
|
|
285
285
|
// The board's pages and assets go in site/ (boards/<slug>/site/ when live).
|
|
286
286
|
shell.mkdir('-p', 'site/assets/css')
|
|
287
287
|
shell.mkdir('-p', 'site/assets/js')
|
|
288
|
-
|
|
288
|
+
// The starter page speaks for this board: its SDK tag names the slug.
|
|
289
|
+
const indexHtml = utils.readFile(path.join(__dirname, 'board/site/index.html'))
|
|
290
|
+
utils.write('site/index.html', indexHtml.replace('data-board="my-board"', `data-board="${boardJson.slug}"`))
|
|
289
291
|
shell.cp('-R', path.join(__dirname, `board/site/assets/css/site.css`), 'site/assets/css/site.css')
|
|
290
292
|
|
|
291
293
|
await progress.done()
|