@augurworks/augur 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CANVAS.md +858 -0
- package/INSTALL.md +603 -0
- package/LICENSE +27 -0
- package/README.md +150 -0
- package/TRADEMARKS.md +72 -0
- package/agents/README.md +65 -0
- package/agents/canon-extract.md +117 -0
- package/agents/canon.md +151 -0
- package/agents/canvas.md +88 -0
- package/agents/currency.md +74 -0
- package/agents/drafts.md +92 -0
- package/agents/identity.md +148 -0
- package/agents/prototype-contract.md +69 -0
- package/agents/publishing.md +324 -0
- package/agents/review-feedback.md +76 -0
- package/agents/space-json.md +132 -0
- package/agents/ui-skill.md +101 -0
- package/agents/working-marks.md +86 -0
- package/brand/augur-eye.svg +3 -0
- package/brand/augur-icon.svg +41 -0
- package/brand/augur-mark.svg +5 -0
- package/brand/lentianova-bulky.otf +0 -0
- package/brand/lentianova-median.otf +0 -0
- package/brand/lentianova.woff2 +0 -0
- package/build.js +8409 -0
- package/changelog.md +133 -0
- package/fonts/inter-latin-wght-normal.woff2 +0 -0
- package/package.json +57 -0
- package/pitis/PETS.md +121 -0
- package/pitis/README.md +117 -0
- package/pitis/index.html +266 -0
- package/pitis/piti.build.js +81 -0
- package/pitis/piti.js +929 -0
- package/pitis/roast-agent.md +185 -0
- package/realtime/src/index.js +119 -0
- package/realtime/wrangler.example.toml +44 -0
- package/scripts/adopt.mjs +106 -0
- package/scripts/board-snapshot.mjs +197 -0
- package/scripts/build-seed-pack.mjs +33 -0
- package/scripts/bundle-rekey.mjs +112 -0
- package/scripts/bundle-tenancy-rehearsal.mjs +781 -0
- package/scripts/canon-extract.mjs +578 -0
- package/scripts/canon.mjs +599 -0
- package/scripts/canvas-screen.mjs +333 -0
- package/scripts/check-local.mjs +136 -0
- package/scripts/clawd-art.mjs +75 -0
- package/scripts/clawd-canvas.mjs +741 -0
- package/scripts/cli.mjs +100 -0
- package/scripts/clone.mjs +422 -0
- package/scripts/close.mjs +30 -0
- package/scripts/connect.mjs +103 -0
- package/scripts/deploy.mjs +157 -0
- package/scripts/dev.mjs +54 -0
- package/scripts/doc-lint.mjs +143 -0
- package/scripts/export.mjs +300 -0
- package/scripts/fork.mjs +64 -0
- package/scripts/freeze.mjs +74 -0
- package/scripts/frontdoor-parity.mjs +180 -0
- package/scripts/hook.mjs +67 -0
- package/scripts/identity-rekey.mjs +112 -0
- package/scripts/init.mjs +122 -0
- package/scripts/land.mjs +40 -0
- package/scripts/lib/adapters.mjs +156 -0
- package/scripts/lib/board-snapshot.mjs +511 -0
- package/scripts/lib/draft.mjs +385 -0
- package/scripts/lib/graduate.mjs +276 -0
- package/scripts/lib/instance.mjs +74 -0
- package/scripts/lib/marks.mjs +107 -0
- package/scripts/lib/materialize.mjs +138 -0
- package/scripts/lib/merge3.mjs +124 -0
- package/scripts/lib/offline-posture.mjs +120 -0
- package/scripts/lib/offline-respawn.mjs +18 -0
- package/scripts/lib/offline-wrangler.mjs +78 -0
- package/scripts/lib/publish-compose.mjs +12 -0
- package/scripts/lib/publish-conflict.mjs +78 -0
- package/scripts/lib/publish-evidence.mjs +144 -0
- package/scripts/lib/refine-compare.mjs +140 -0
- package/scripts/lib/refine-ledger.mjs +150 -0
- package/scripts/lib/refine-png.mjs +149 -0
- package/scripts/lib/seed-pack-build.mjs +141 -0
- package/scripts/lib/state-compare.mjs +68 -0
- package/scripts/lib/store.mjs +122 -0
- package/scripts/login.mjs +84 -0
- package/scripts/mark.mjs +112 -0
- package/scripts/migrate-board-keys.mjs +164 -0
- package/scripts/migrate.mjs +265 -0
- package/scripts/no-foreign-vocabulary.mjs +216 -0
- package/scripts/no-product-names.mjs +157 -0
- package/scripts/no-tenant-globals.mjs +1134 -0
- package/scripts/offline.mjs +247 -0
- package/scripts/og.mjs +170 -0
- package/scripts/one-tenant-resolver.mjs +146 -0
- package/scripts/open.mjs +63 -0
- package/scripts/publish.mjs +1041 -0
- package/scripts/read.mjs +31 -0
- package/scripts/refine.mjs +455 -0
- package/scripts/release-drift.mjs +138 -0
- package/scripts/restore.mjs +322 -0
- package/scripts/review.mjs +125 -0
- package/scripts/save.mjs +21 -0
- package/scripts/shell-lint.mjs +189 -0
- package/scripts/ship.mjs +460 -0
- package/scripts/shoot.mjs +264 -0
- package/scripts/smoke-invite.mjs +113 -0
- package/scripts/state-inventory.mjs +223 -0
- package/scripts/status.mjs +177 -0
- package/scripts/sync.mjs +27 -0
- package/scripts/tenant-do-rehearsal.mjs +1314 -0
- package/scripts/ui-copy-lint.mjs +202 -0
- package/scripts/watch.mjs +32 -0
- package/scripts/wrangler-preflight.mjs +246 -0
- package/seed/CANON.md +43 -0
- package/seed/README.md +119 -0
- package/seed/prototype-status.json +9 -0
- package/seed/registry.json +88 -0
- package/seed/skills/starter-ui/SKILL.md +52 -0
- package/seed/skills/starter-ui/skill.json +11 -0
- package/seed/skills/starter-ui/starter-tokens.css +73 -0
- package/seed/skills/starter-ui/starter-ui.css +318 -0
- package/seed/skills/starter-ui/starter-ui.js +50 -0
- package/seed/space.json +5 -0
- package/seed/start-here/prototypes/connect-your-terminal/index.html +428 -0
- package/seed/start-here/prototypes/connect-your-terminal/preview.webp +0 -0
- package/seed/start-here/prototypes/sample-with-comments/index.html +172 -0
- package/seed/start-here/prototypes/sample-with-comments/preview.webp +0 -0
- package/seed/start-here/prototypes/set-up-your-design-system/index.html +353 -0
- package/seed/start-here/prototypes/set-up-your-design-system/preview.webp +0 -0
- package/seed/threads.json +52 -0
- package/seed/worked-examples/prototypes/field-readings/index.html +273 -0
- package/seed/worked-examples/prototypes/field-readings/preview.webp +0 -0
- package/seed/worked-examples/prototypes/slide-deck/index.html +214 -0
- package/seed/worked-examples/prototypes/slide-deck/preview.webp +0 -0
- package/seed/worked-examples/prototypes/specimen-viewer/index.html +203 -0
- package/seed/worked-examples/prototypes/specimen-viewer/preview.webp +0 -0
- package/src/_worker.js +12668 -0
- package/src/board-key.mjs +57 -0
- package/src/board-room.mjs +881 -0
- package/src/bundle-keys.mjs +138 -0
- package/src/canon/collect-in-browser.js +215 -0
- package/src/canon/emit.mjs +232 -0
- package/src/canon/observe.mjs +260 -0
- package/src/canon/schema.mjs +451 -0
- package/src/canvas/DSEG-LICENSE.txt +95 -0
- package/src/canvas/DSEG7Classic-Bold.woff2 +0 -0
- package/src/canvas/canvas.css +885 -0
- package/src/canvas/canvas.js +5780 -0
- package/src/canvas/capture.js +485 -0
- package/src/chrome/appchrome.mjs +568 -0
- package/src/currency.mjs +203 -0
- package/src/delete-confirmation.mjs +254 -0
- package/src/drafts/drafts.js +326 -0
- package/src/entry.js +58 -0
- package/src/galleries.mjs +400 -0
- package/src/health-cron.mjs +173 -0
- package/src/identity.json +1 -0
- package/src/kv-codec.mjs +135 -0
- package/src/kv-identity.mjs +259 -0
- package/src/mail.mjs +599 -0
- package/src/provenance.mjs +74 -0
- package/src/publish-compose.mjs +363 -0
- package/src/publish-fork.mjs +221 -0
- package/src/publish-units.mjs +44 -0
- package/src/purge.mjs +81 -0
- package/src/review/COMMENTING-UX.md +306 -0
- package/src/review/cat.png +0 -0
- package/src/review/comment-cursor.svg +7 -0
- package/src/review/comments.js +1738 -0
- package/src/room-ticket.mjs +96 -0
- package/src/roster-chip.mjs +32 -0
- package/src/seed-pack.mjs +261 -0
- package/src/state-inventory.mjs +249 -0
- package/src/sw-logic.mjs +48 -0
- package/src/tenant-cache.mjs +141 -0
- package/src/tenant-context.mjs +386 -0
- package/src/tenant-do.js +2940 -0
- package/src/tenant-host.mjs +144 -0
- package/src/tenant-quotas.mjs +140 -0
- package/src/unit-core.mjs +103 -0
- package/src/unit-object.mjs +338 -0
- package/templates/README.md +67 -0
- package/templates/shell/deploy.yml +145 -0
- package/templates/shell/engine-bump.yml +142 -0
- package/templates/shell/health.yml +233 -0
- package/templates/shell/kv-backup.yml +201 -0
- package/templates/shell/roster-update.yml +110 -0
- package/templates/shell/space-preflight.yml +35 -0
- package/templates/shell/space-rebake.yml +79 -0
- package/templates/shell/store-backup.yml +152 -0
- package/templates/shell/wrangler.example.toml +266 -0
- package/templates/space/publish.yml +91 -0
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/* Augur — the draft bar (drafts that land, docs/drafts-that-land.md §5).
|
|
2
|
+
*
|
|
3
|
+
* Served at /__drafts/drafts.js and appended by the worker to a unit's HTML for signed-in
|
|
4
|
+
* members (withDraftUi in src/_worker.js), which also leaves the boot data in
|
|
5
|
+
* window.__augurDraft = { unit, draft, me: { id, role } }.
|
|
6
|
+
*
|
|
7
|
+
* On MAIN the bar lists the unit's open drafts (or shows nothing) and reloads the tab when
|
|
8
|
+
* a landing happens. On a DRAFT ADDRESS it names whose draft this is and when it last
|
|
9
|
+
* saved, offers Land and Discard to editors, and reloads on every save. History opens a
|
|
10
|
+
* panel of landings with Restore. Everything shown comes from /__unit/*, never from the
|
|
11
|
+
* page; the socket at /__unit/socket says WHEN to ask again. No chrome dependency, no
|
|
12
|
+
* external request, and nothing here is a lock: the bar refuses nobody.
|
|
13
|
+
*/
|
|
14
|
+
(function () {
|
|
15
|
+
if (window.top !== window.self) return; // gallery previews and embeds carry no bar
|
|
16
|
+
var boot = window.__augurDraft;
|
|
17
|
+
if (!boot || !boot.unit) return;
|
|
18
|
+
var UNIT = boot.unit, DRAFT = boot.draft || null, ME = boot.me || {};
|
|
19
|
+
var canWrite = ME.role !== "viewer";
|
|
20
|
+
var unitQ = "unit=" + encodeURIComponent(UNIT);
|
|
21
|
+
var state = { card: null, drafts: [] };
|
|
22
|
+
|
|
23
|
+
// ── talking to the unit ──────────────────────────────────────────────────────
|
|
24
|
+
function api(verb, body, extraQuery) {
|
|
25
|
+
var opts = { credentials: "same-origin", headers: { Accept: "application/json" } };
|
|
26
|
+
var url = "/__unit/" + verb;
|
|
27
|
+
if (body) {
|
|
28
|
+
opts.method = "POST";
|
|
29
|
+
opts.headers["Content-Type"] = "application/json";
|
|
30
|
+
body.unit = UNIT;
|
|
31
|
+
opts.body = JSON.stringify(body);
|
|
32
|
+
} else {
|
|
33
|
+
url += "?" + unitQ + (extraQuery || "");
|
|
34
|
+
}
|
|
35
|
+
return fetch(url, opts).then(function (r) {
|
|
36
|
+
return r.json().catch(function () { return {}; }).then(function (j) { j.__status = r.status; return j; });
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ── small helpers ────────────────────────────────────────────────────────────
|
|
41
|
+
function el(tag, cls, text) {
|
|
42
|
+
var e = document.createElement(tag);
|
|
43
|
+
if (cls) e.className = cls;
|
|
44
|
+
if (text != null) e.textContent = text;
|
|
45
|
+
return e;
|
|
46
|
+
}
|
|
47
|
+
function ago(iso, verb) {
|
|
48
|
+
var ms = Date.now() - Date.parse(iso || "");
|
|
49
|
+
if (!(ms >= 0)) return "";
|
|
50
|
+
var m = Math.round(ms / 60000);
|
|
51
|
+
if (m < 1) return verb + " just now";
|
|
52
|
+
if (m < 60) return verb + " " + m + " min ago";
|
|
53
|
+
var h = Math.round(m / 60);
|
|
54
|
+
if (h < 48) return verb + " " + h + " h ago";
|
|
55
|
+
return verb + " " + new Date(iso).toLocaleDateString();
|
|
56
|
+
}
|
|
57
|
+
function face(p) {
|
|
58
|
+
var f = el("span", "augur-draft__face", (p.initials || "?").slice(0, 2));
|
|
59
|
+
if (p.color) f.style.backgroundColor = p.color;
|
|
60
|
+
var id = p.owner || p.by;
|
|
61
|
+
if (id) f.setAttribute("data-person", id);
|
|
62
|
+
return f;
|
|
63
|
+
}
|
|
64
|
+
function label(p) { return (p.name || "Someone") + (p.session ? " · " + p.session : ""); }
|
|
65
|
+
function go(href) { location.href = href; }
|
|
66
|
+
|
|
67
|
+
// Photos, laid over the initials once /__people answers. Initials stand if it does not.
|
|
68
|
+
function faces(root) {
|
|
69
|
+
var els = root.querySelectorAll("[data-person]"), ids = [], byId = {};
|
|
70
|
+
for (var i = 0; i < els.length; i++) {
|
|
71
|
+
var id = els[i].getAttribute("data-person");
|
|
72
|
+
if (!id) continue;
|
|
73
|
+
(byId[id] = byId[id] || []).push(els[i]);
|
|
74
|
+
if (ids.indexOf(id) < 0) ids.push(id);
|
|
75
|
+
}
|
|
76
|
+
if (!ids.length) return;
|
|
77
|
+
fetch("/__people?ids=" + encodeURIComponent(ids.slice(0, 50).join(",")), { credentials: "same-origin" })
|
|
78
|
+
.then(function (r) { return r.ok ? r.json() : null; })
|
|
79
|
+
.then(function (d) {
|
|
80
|
+
if (!d || !d.people) return;
|
|
81
|
+
d.people.forEach(function (p) {
|
|
82
|
+
if (!p.avatar) return;
|
|
83
|
+
(byId[p.id] || []).forEach(function (e) {
|
|
84
|
+
e.style.backgroundImage = "url('" + p.avatar + "')";
|
|
85
|
+
e.style.backgroundSize = "cover";
|
|
86
|
+
e.textContent = "";
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
})
|
|
90
|
+
.catch(function () { /* initials stand */ });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ── styles, once ─────────────────────────────────────────────────────────────
|
|
94
|
+
var CSS = [
|
|
95
|
+
".augur-draftbar{position:fixed;left:12px;bottom:12px;z-index:2147483000;display:flex;align-items:center;gap:8px;",
|
|
96
|
+
"padding:6px 10px 6px 6px;border-radius:999px;background:#101828;color:#fff;box-shadow:0 8px 24px -8px rgba(16,24,40,.6);",
|
|
97
|
+
"font:600 12.5px/1.2 system-ui,-apple-system,Segoe UI,sans-serif;letter-spacing:-.005em;max-width:min(92vw,560px)}",
|
|
98
|
+
".augur-draftbar[hidden],.augur-draft__list[hidden],.augur-draft__panel[hidden],.augur-draft__note[hidden]{display:none}",
|
|
99
|
+
".augur-draftbar a{color:inherit;text-decoration:none}",
|
|
100
|
+
".augur-draft__face{flex:none;width:22px;height:22px;border-radius:50%;display:inline-grid;place-items:center;",
|
|
101
|
+
"font-size:9px;font-weight:700;color:#fff;background:#4f46e5;background-position:center}",
|
|
102
|
+
".augur-draft__text{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}",
|
|
103
|
+
".augur-draft__dim{opacity:.7;font-weight:500}",
|
|
104
|
+
".augur-draftbar button{font:inherit;border:0;border-radius:999px;padding:5px 10px;cursor:pointer;color:#101828;background:#fff}",
|
|
105
|
+
".augur-draftbar button.is-quiet{background:transparent;color:#fff;opacity:.85}",
|
|
106
|
+
".augur-draftbar button:disabled{opacity:.5;cursor:default}",
|
|
107
|
+
".augur-draft__list{position:fixed;left:12px;bottom:56px;z-index:2147483000;display:flex;flex-direction:column;gap:6px}",
|
|
108
|
+
".augur-draft__row{display:flex;align-items:center;gap:8px;padding:6px 10px 6px 6px;border-radius:999px;background:#101828;color:#fff;text-decoration:none;",
|
|
109
|
+
"font:600 12.5px/1.2 system-ui,-apple-system,Segoe UI,sans-serif;box-shadow:0 8px 24px -8px rgba(16,24,40,.6)}",
|
|
110
|
+
".augur-draft__row.is-idle{opacity:.75}",
|
|
111
|
+
".augur-draft__panel{position:fixed;left:12px;bottom:56px;z-index:2147483001;width:min(92vw,420px);max-height:60vh;overflow:auto;",
|
|
112
|
+
"background:#fff;color:#101828;border-radius:14px;box-shadow:0 20px 48px -16px rgba(16,24,40,.55),0 2px 8px rgba(16,24,40,.12);",
|
|
113
|
+
"font:500 13px/1.35 system-ui,-apple-system,Segoe UI,sans-serif;padding:8px}",
|
|
114
|
+
".augur-draft__panel h2{margin:4px 8px 8px;font-size:12px;letter-spacing:.04em;text-transform:uppercase;color:#667085}",
|
|
115
|
+
".augur-draft__landing{display:grid;grid-template-columns:22px 1fr auto;gap:8px;align-items:center;padding:8px;border-radius:10px}",
|
|
116
|
+
".augur-draft__landing:hover{background:#f2f4f7}",
|
|
117
|
+
".augur-draft__landing small{display:block;color:#667085;font-weight:500}",
|
|
118
|
+
".augur-draft__landing button{font:inherit;font-size:12px;border:1px solid #d0d5dd;background:#fff;border-radius:999px;padding:4px 10px;cursor:pointer}",
|
|
119
|
+
".augur-draft__note{position:fixed;left:12px;bottom:56px;z-index:2147483001;max-width:min(92vw,420px);padding:10px 12px;border-radius:12px;",
|
|
120
|
+
"background:#fff;color:#101828;box-shadow:0 12px 32px -12px rgba(16,24,40,.5);font:500 13px/1.35 system-ui,-apple-system,Segoe UI,sans-serif}",
|
|
121
|
+
].join("");
|
|
122
|
+
var style = el("style"); style.textContent = CSS; document.head.appendChild(style);
|
|
123
|
+
|
|
124
|
+
// ── the bar itself ───────────────────────────────────────────────────────────
|
|
125
|
+
var bar = el("div", "augur-draftbar"); bar.hidden = true;
|
|
126
|
+
var list = el("div", "augur-draft__list"); list.hidden = true;
|
|
127
|
+
var panel = el("div", "augur-draft__panel"); panel.hidden = true;
|
|
128
|
+
var noteBox = el("div", "augur-draft__note"); noteBox.hidden = true;
|
|
129
|
+
document.body.appendChild(bar); document.body.appendChild(list);
|
|
130
|
+
document.body.appendChild(panel); document.body.appendChild(noteBox);
|
|
131
|
+
|
|
132
|
+
var noteTimer = null;
|
|
133
|
+
function note(text) {
|
|
134
|
+
noteBox.textContent = text; noteBox.hidden = false;
|
|
135
|
+
clearTimeout(noteTimer);
|
|
136
|
+
noteTimer = setTimeout(function () { noteBox.hidden = true; }, 6000);
|
|
137
|
+
}
|
|
138
|
+
function clear(node) { while (node.firstChild) node.removeChild(node.firstChild); }
|
|
139
|
+
function button(text, cls, onClick) {
|
|
140
|
+
var b = el("button", cls, text); b.type = "button"; b.addEventListener("click", onClick); return b;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function renderMain(drafts) {
|
|
144
|
+
clear(bar); clear(list);
|
|
145
|
+
state.drafts = drafts || [];
|
|
146
|
+
if (!state.drafts.length) { bar.hidden = true; list.hidden = true; return; }
|
|
147
|
+
var n = state.drafts.length;
|
|
148
|
+
bar.appendChild(el("span", "augur-draft__text", n === 1 ? "1 draft open" : n + " drafts open"));
|
|
149
|
+
bar.appendChild(button(list.hidden ? "Show" : "Hide", "is-quiet", function () {
|
|
150
|
+
list.hidden = !list.hidden; this.textContent = list.hidden ? "Show" : "Hide";
|
|
151
|
+
}));
|
|
152
|
+
bar.appendChild(button("History", "is-quiet", history));
|
|
153
|
+
state.drafts.forEach(function (d) {
|
|
154
|
+
var row = el("a", "augur-draft__row" + (d.active ? "" : " is-idle"));
|
|
155
|
+
row.href = UNIT + "@" + d.id + "/";
|
|
156
|
+
row.appendChild(face(d));
|
|
157
|
+
row.appendChild(el("span", "augur-draft__text", label(d)));
|
|
158
|
+
row.appendChild(el("span", "augur-draft__dim", ago(d.lastSaveAt || d.openedAt, d.lastSaveAt ? "saved" : "opened")));
|
|
159
|
+
list.appendChild(row);
|
|
160
|
+
});
|
|
161
|
+
bar.hidden = false;
|
|
162
|
+
faces(list);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function renderDraft(card) {
|
|
166
|
+
clear(bar); list.hidden = true;
|
|
167
|
+
state.card = card;
|
|
168
|
+
bar.appendChild(face(card));
|
|
169
|
+
bar.appendChild(el("span", "augur-draft__text", label(card)));
|
|
170
|
+
bar.appendChild(el("span", "augur-draft__dim", card.closedAt
|
|
171
|
+
? "landed"
|
|
172
|
+
: ago(card.lastSaveAt || card.openedAt, card.lastSaveAt ? "saved" : "opened")));
|
|
173
|
+
if (canWrite && !card.closedAt) {
|
|
174
|
+
bar.appendChild(button("Land", "", land));
|
|
175
|
+
bar.appendChild(button("Discard", "is-quiet", discard));
|
|
176
|
+
}
|
|
177
|
+
bar.appendChild(button("History", "is-quiet", history));
|
|
178
|
+
var main = el("a", "augur-draft__dim", "Main"); main.href = UNIT; bar.appendChild(main);
|
|
179
|
+
bar.hidden = false;
|
|
180
|
+
faces(bar);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ── the verbs ────────────────────────────────────────────────────────────────
|
|
184
|
+
var busy = false;
|
|
185
|
+
function land() {
|
|
186
|
+
if (busy || !state.card) return;
|
|
187
|
+
busy = true;
|
|
188
|
+
api("land", { draftId: DRAFT, baseRevision: state.card.baseRevision, note: "" }).then(function (r) {
|
|
189
|
+
busy = false;
|
|
190
|
+
if (r.ok) { go(UNIT); return; }
|
|
191
|
+
if (r.__status === 409 && r.error === "main-moved") {
|
|
192
|
+
var n = (r.changed || []).length + (r.removed || []).length;
|
|
193
|
+
note("Main has moved since this draft began (" + n + (n === 1 ? " file" : " files") + "). Sync the draft and land again.");
|
|
194
|
+
} else if (r.__status === 409 && r.error === "landing-in-progress") {
|
|
195
|
+
note("Another landing is in progress on this prototype. Try again in a moment.");
|
|
196
|
+
} else if (r.__status === 409 && r.error === "would-unpublish") {
|
|
197
|
+
note("This draft has no files, so landing it would take the prototype down. Nothing was changed.");
|
|
198
|
+
} else if (r.__status === 403) {
|
|
199
|
+
note(r.message || "This account cannot land drafts.");
|
|
200
|
+
} else {
|
|
201
|
+
note("The landing was refused: " + (r.error || r.__status) + ".");
|
|
202
|
+
}
|
|
203
|
+
}).catch(function () { busy = false; note("The landing could not be sent. Check the connection and try again."); });
|
|
204
|
+
}
|
|
205
|
+
function discard() {
|
|
206
|
+
if (busy) return;
|
|
207
|
+
if (!confirm("Discard this draft? Every save it holds is gone for good; the prototype's real URL is untouched.")) return;
|
|
208
|
+
busy = true;
|
|
209
|
+
api("discard", { draftId: DRAFT }).then(function (r) {
|
|
210
|
+
busy = false;
|
|
211
|
+
if (r.closed) { go(UNIT); return; }
|
|
212
|
+
note(r.message || "The draft could not be discarded: " + (r.error || r.__status) + ".");
|
|
213
|
+
}).catch(function () { busy = false; note("The discard could not be sent."); });
|
|
214
|
+
}
|
|
215
|
+
function history() {
|
|
216
|
+
if (!panel.hidden) { panel.hidden = true; return; }
|
|
217
|
+
api("history").then(function (h) {
|
|
218
|
+
clear(panel);
|
|
219
|
+
if (h.__status !== 200) { note("History is not available right now."); return; }
|
|
220
|
+
panel.appendChild(el("h2", null, "Landings"));
|
|
221
|
+
(h.landings || []).forEach(function (l) {
|
|
222
|
+
var row = el("div", "augur-draft__landing");
|
|
223
|
+
row.appendChild(face(l));
|
|
224
|
+
var text = el("div");
|
|
225
|
+
var who = l.by === "live" ? "Adopted from the live site" : label(l);
|
|
226
|
+
text.appendChild(el("div", null, "#" + l.revision + " · " + who));
|
|
227
|
+
var meta = (l.note ? l.note + " · " : "") + ago(l.at, "landed")
|
|
228
|
+
+ (l.restoredFrom ? " · restored from #" + l.restoredFrom : "")
|
|
229
|
+
+ " · " + l.files + (l.files === 1 ? " file" : " files");
|
|
230
|
+
text.appendChild(el("small", null, meta));
|
|
231
|
+
row.appendChild(text);
|
|
232
|
+
if (canWrite && l.revision !== h.revision) {
|
|
233
|
+
row.appendChild(button("Restore", "", function () { restore(l.revision); }));
|
|
234
|
+
} else {
|
|
235
|
+
row.appendChild(el("span", "augur-draft__dim", l.revision === h.revision ? "current" : ""));
|
|
236
|
+
}
|
|
237
|
+
panel.appendChild(row);
|
|
238
|
+
});
|
|
239
|
+
panel.hidden = false;
|
|
240
|
+
faces(panel);
|
|
241
|
+
}).catch(function () { note("History could not be loaded."); });
|
|
242
|
+
}
|
|
243
|
+
function restore(revision) {
|
|
244
|
+
if (busy) return;
|
|
245
|
+
if (!confirm("Land revision #" + revision + " as a new landing? Nothing is rewritten; history keeps every step.")) return;
|
|
246
|
+
busy = true;
|
|
247
|
+
api("restore", { revision: revision, note: "restored revision " + revision }).then(function (r) {
|
|
248
|
+
busy = false;
|
|
249
|
+
if (r.ok) { panel.hidden = true; reloadMain(); return; }
|
|
250
|
+
note("The restore was refused: " + (r.error || r.__status) + ".");
|
|
251
|
+
}).catch(function () { busy = false; note("The restore could not be sent."); });
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// ── reloading, past the service worker ───────────────────────────────────────
|
|
255
|
+
// Main pages are served stale-while-revalidate by the service worker, so a plain reload
|
|
256
|
+
// after a landing would paint the previous landing first. Ask the worker to drop this
|
|
257
|
+
// URL, wait for its answer (or half a second), then reload — after the moment the
|
|
258
|
+
// engine's own manifest cache needs to notice the landing on every isolate.
|
|
259
|
+
function evict(url) {
|
|
260
|
+
return new Promise(function (resolve) {
|
|
261
|
+
var sw = navigator.serviceWorker && navigator.serviceWorker.controller;
|
|
262
|
+
if (!sw) { resolve(); return; }
|
|
263
|
+
var done = false, finish = function () { if (!done) { done = true; resolve(); } };
|
|
264
|
+
try {
|
|
265
|
+
var ch = new MessageChannel();
|
|
266
|
+
ch.port1.onmessage = finish;
|
|
267
|
+
sw.postMessage({ t: "evict", url: url }, [ch.port2]);
|
|
268
|
+
} catch (e) { finish(); }
|
|
269
|
+
setTimeout(finish, 500);
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
function reloadMain() {
|
|
273
|
+
evict(location.href).then(function () { setTimeout(function () { location.reload(); }, 1500); });
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// ── the socket ───────────────────────────────────────────────────────────────
|
|
277
|
+
var tries = 0, pingTimer = null;
|
|
278
|
+
function connect() {
|
|
279
|
+
var proto = location.protocol === "https:" ? "wss://" : "ws://";
|
|
280
|
+
var ws;
|
|
281
|
+
try { ws = new WebSocket(proto + location.host + "/__unit/socket?" + unitQ + (DRAFT ? "&draft=" + DRAFT : "")); }
|
|
282
|
+
catch (e) { return; }
|
|
283
|
+
ws.onopen = function () {
|
|
284
|
+
tries = 0;
|
|
285
|
+
clearInterval(pingTimer);
|
|
286
|
+
pingTimer = setInterval(function () { try { ws.send("ping"); } catch (e) { /* closing */ } }, 25000);
|
|
287
|
+
};
|
|
288
|
+
ws.onmessage = function (ev) {
|
|
289
|
+
var m; try { m = JSON.parse(ev.data); } catch (e) { return; }
|
|
290
|
+
if (!m || !m.t) return;
|
|
291
|
+
if (DRAFT) {
|
|
292
|
+
if (m.draftId !== DRAFT) { refresh(); return; }
|
|
293
|
+
if (m.t === "save") location.reload();
|
|
294
|
+
else if (m.t === "land" || m.t === "discard") go(UNIT);
|
|
295
|
+
} else {
|
|
296
|
+
if (m.t === "land") reloadMain();
|
|
297
|
+
else refresh();
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
ws.onclose = function () {
|
|
301
|
+
clearInterval(pingTimer);
|
|
302
|
+
if (tries >= 6) return; // a minute of trying is enough; the next visit connects again
|
|
303
|
+
var wait = Math.min(30000, 1000 * Math.pow(2, tries++));
|
|
304
|
+
setTimeout(connect, wait);
|
|
305
|
+
};
|
|
306
|
+
ws.onerror = function () { try { ws.close(); } catch (e) { /* already closed */ } };
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// ── first paint ──────────────────────────────────────────────────────────────
|
|
310
|
+
function refresh() {
|
|
311
|
+
if (DRAFT) {
|
|
312
|
+
api("draft", null, "&draft=" + DRAFT).then(function (card) {
|
|
313
|
+
if (card.__status !== 200) { bar.hidden = true; return; }
|
|
314
|
+
renderDraft(card);
|
|
315
|
+
}).catch(function () { /* the bar simply does not appear */ });
|
|
316
|
+
} else {
|
|
317
|
+
api("presence").then(function (p) {
|
|
318
|
+
if (p.__status !== 200) { bar.hidden = true; return; }
|
|
319
|
+
renderMain(p.drafts);
|
|
320
|
+
}).catch(function () { /* same */ });
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
refresh();
|
|
324
|
+
connect();
|
|
325
|
+
document.addEventListener("visibilitychange", function () { if (!document.hidden) refresh(); });
|
|
326
|
+
})();
|
package/src/entry.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The DEPLOY ENTRY. `wrangler deploy` bundles from here; nothing else imports it.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS FILE EXISTS AT ALL, given it is four lines of code. Two deploy models have to
|
|
5
|
+
* coexist for as long as the instances take to migrate:
|
|
6
|
+
*
|
|
7
|
+
* Pages build.js copies src/_worker.js VERBATIM into dist/_worker.js and Cloudflare
|
|
8
|
+
* runs that copy. There is no bundler, so that file can only import modules
|
|
9
|
+
* that build.js also copies next to it in dist/.
|
|
10
|
+
* Workers wrangler's `main` points HERE, in the source tree, and esbuild inlines the
|
|
11
|
+
* whole import graph into one script. dist/ is only the asset directory.
|
|
12
|
+
*
|
|
13
|
+
* So the two front doors read DIFFERENT files, and this is the one only Workers reads.
|
|
14
|
+
* That is what makes it the place for everything a Worker can declare and Pages cannot:
|
|
15
|
+
* a Durable Object class export (Pages Advanced Mode cannot define one at all, which is
|
|
16
|
+
* why the canvas rooms are a second worker today), a `scheduled` handler (the cron that
|
|
17
|
+
* removes the last reason an instance needs GitHub Actions to operate), a `queue`
|
|
18
|
+
* consumer. Each of those is one line here.
|
|
19
|
+
*
|
|
20
|
+
* THE ONE RULE, and it is not a style preference:
|
|
21
|
+
*
|
|
22
|
+
* NO REQUEST LOGIC IN THIS FILE. EVER.
|
|
23
|
+
*
|
|
24
|
+
* Anything written here runs on Workers instances and does not exist on Pages instances.
|
|
25
|
+
* A gate check, a header, a redirect added here would be live on one instance and absent
|
|
26
|
+
* on its neighbour, and every test in this repo drives src/_worker.js, so the suite would
|
|
27
|
+
* be green either way. test/worker-entry.test.mjs enforces it by reading this source, so
|
|
28
|
+
* the rule is checked rather than described.
|
|
29
|
+
*
|
|
30
|
+
* WHY NOT THE THREE-FILE SPLIT the plan item recommended: it assumed a single 3049-line
|
|
31
|
+
* file with zero imports. That is no longer true. src/_worker.js already imports five
|
|
32
|
+
* leaf modules (chrome/appchrome.mjs, tenant-context.mjs, tenant-cache.mjs, mail.mjs,
|
|
33
|
+
* kv-codec.mjs), none of which imports anything of its own, so the module graph the
|
|
34
|
+
* bundler needs already exists. Carving request logic out of _worker.js would be a
|
|
35
|
+
* refactor with no deploy-model reason behind it, and it would have to be done twice —
|
|
36
|
+
* once for each front door — for as long as both exist.
|
|
37
|
+
*/
|
|
38
|
+
import worker from "./_worker.js";
|
|
39
|
+
|
|
40
|
+
// The canvas rooms. `wrangler deploy` resolves a [[durable_objects.bindings]] class_name
|
|
41
|
+
// against THIS file's exports, so a Durable Object the engine worker is to hold has to be
|
|
42
|
+
// named here — which is the reason this file exists at all.
|
|
43
|
+
//
|
|
44
|
+
// Exporting it costs a Pages instance nothing: Pages reads src/_worker.js, never this
|
|
45
|
+
// file. And it costs a Worker instance nothing either until its wrangler.toml declares
|
|
46
|
+
// the binding and the migration, so this can land ahead of any instance being ready for it.
|
|
47
|
+
export { BoardRoom } from "./board-room.mjs";
|
|
48
|
+
|
|
49
|
+
// One workspace's mutable state, in storage that belongs to that workspace and to no
|
|
50
|
+
// other. Same deal as above: named here so wrangler can resolve the class, inert on every
|
|
51
|
+
// instance until one declares the binding and the migration.
|
|
52
|
+
export { TenantStore } from "./tenant-do.js";
|
|
53
|
+
|
|
54
|
+
// One unit's drafts, landings and lease — see docs/drafts-that-land.md. Named here for the
|
|
55
|
+
// same reason as the two above: inert until a wrangler.toml binds it as UNITS.
|
|
56
|
+
export { UnitObject } from "./unit-object.mjs";
|
|
57
|
+
|
|
58
|
+
export default worker;
|