@goodbones/browser 0.1.0-beta.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.
Files changed (88) hide show
  1. package/LICENSE +21 -0
  2. package/build/dts/index.d.ts +12 -0
  3. package/build/dts/index.d.ts.map +1 -0
  4. package/build/dts/main.d.ts +3 -0
  5. package/build/dts/main.d.ts.map +1 -0
  6. package/build/dts/model/atlas.d.ts +157 -0
  7. package/build/dts/model/atlas.d.ts.map +1 -0
  8. package/build/dts/model/campaigns.d.ts +141 -0
  9. package/build/dts/model/campaigns.d.ts.map +1 -0
  10. package/build/dts/server/collect.d.ts +16 -0
  11. package/build/dts/server/collect.d.ts.map +1 -0
  12. package/build/dts/server/compose.d.ts +13 -0
  13. package/build/dts/server/compose.d.ts.map +1 -0
  14. package/build/dts/server/export.d.ts +3 -0
  15. package/build/dts/server/export.d.ts.map +1 -0
  16. package/build/dts/server/handler.d.ts +6 -0
  17. package/build/dts/server/handler.d.ts.map +1 -0
  18. package/build/dts/server/serve.d.ts +15 -0
  19. package/build/dts/server/serve.d.ts.map +1 -0
  20. package/build/dts/server/site.d.ts +2 -0
  21. package/build/dts/server/site.d.ts.map +1 -0
  22. package/build/dts/server/source.d.ts +19 -0
  23. package/build/dts/server/source.d.ts.map +1 -0
  24. package/build/dts/server/vite-plugin.d.ts +8 -0
  25. package/build/dts/server/vite-plugin.d.ts.map +1 -0
  26. package/build/dts/server/watch.d.ts +10 -0
  27. package/build/dts/server/watch.d.ts.map +1 -0
  28. package/build/esm/index.js +14 -0
  29. package/build/esm/index.js.map +1 -0
  30. package/build/esm/main.js +134 -0
  31. package/build/esm/main.js.map +1 -0
  32. package/build/esm/model/atlas.js +431 -0
  33. package/build/esm/model/atlas.js.map +1 -0
  34. package/build/esm/model/campaigns.js +181 -0
  35. package/build/esm/model/campaigns.js.map +1 -0
  36. package/build/esm/server/collect.js +83 -0
  37. package/build/esm/server/collect.js.map +1 -0
  38. package/build/esm/server/compose.js +50 -0
  39. package/build/esm/server/compose.js.map +1 -0
  40. package/build/esm/server/export.js +19 -0
  41. package/build/esm/server/export.js.map +1 -0
  42. package/build/esm/server/handler.js +67 -0
  43. package/build/esm/server/handler.js.map +1 -0
  44. package/build/esm/server/serve.js +80 -0
  45. package/build/esm/server/serve.js.map +1 -0
  46. package/build/esm/server/site.js +6 -0
  47. package/build/esm/server/site.js.map +1 -0
  48. package/build/esm/server/source.js +67 -0
  49. package/build/esm/server/source.js.map +1 -0
  50. package/build/esm/server/vite-plugin.js +21 -0
  51. package/build/esm/server/vite-plugin.js.map +1 -0
  52. package/build/esm/server/watch.js +56 -0
  53. package/build/esm/server/watch.js.map +1 -0
  54. package/build/site/_astro/Browser.yxldcnQ3.js +3 -0
  55. package/build/site/_astro/client.Buyw3Q1S.js +9 -0
  56. package/build/site/_astro/index.DQrWs1cb.css +1 -0
  57. package/build/site/_astro/react.DJY1zw8Z.js +1 -0
  58. package/build/site/favicon.svg +1 -0
  59. package/build/site/index.html +8 -0
  60. package/package.json +78 -0
  61. package/src/app/components/Browser.tsx +153 -0
  62. package/src/app/components/architecture/ArchitectureBrowser.tsx +240 -0
  63. package/src/app/components/architecture/Detail.tsx +655 -0
  64. package/src/app/components/architecture/ManifestPane.tsx +178 -0
  65. package/src/app/components/architecture/Tree.tsx +205 -0
  66. package/src/app/components/architecture/rows.ts +181 -0
  67. package/src/app/components/architecture/selection.ts +6 -0
  68. package/src/app/components/campaigns/CampaignBrowser.tsx +146 -0
  69. package/src/app/components/campaigns/Detail.tsx +653 -0
  70. package/src/app/components/campaigns/Ladder.tsx +326 -0
  71. package/src/app/components/campaigns/pick.ts +7 -0
  72. package/src/app/components/lib/data.ts +132 -0
  73. package/src/app/pages/index.astro +34 -0
  74. package/src/app/public/favicon.svg +1 -0
  75. package/src/app/styles/theme.css +993 -0
  76. package/src/index.ts +37 -0
  77. package/src/main.ts +155 -0
  78. package/src/model/atlas.ts +751 -0
  79. package/src/model/campaigns.ts +376 -0
  80. package/src/server/collect.ts +132 -0
  81. package/src/server/compose.ts +79 -0
  82. package/src/server/export.ts +24 -0
  83. package/src/server/handler.ts +77 -0
  84. package/src/server/serve.ts +100 -0
  85. package/src/server/site.ts +6 -0
  86. package/src/server/source.ts +89 -0
  87. package/src/server/vite-plugin.ts +32 -0
  88. package/src/server/watch.ts +65 -0
@@ -0,0 +1,181 @@
1
+ import { campaignsOf, isDefinedPhase, ledgerKeyOf, LEGACY_SECTOR, snapshotCampaignsOf, } from "@goodbones/campaigns";
2
+ const dirnameOf = (file) => {
3
+ const at = file.lastIndexOf("/");
4
+ return at === -1 ? "" : file.slice(0, at);
5
+ };
6
+ const positionAt = (locate, manifestPath, path) => {
7
+ const found = locate?.(path);
8
+ if (found === null || found === undefined)
9
+ return null;
10
+ const directory = dirnameOf(manifestPath);
11
+ const file = found.file === undefined
12
+ ? manifestPath
13
+ : directory === ""
14
+ ? found.file
15
+ : `${directory}/${found.file}`;
16
+ return { file, line: found.line, column: found.column };
17
+ };
18
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
19
+ const stringAt = (value, ...keys) => {
20
+ let cursor = value;
21
+ for (const key of keys) {
22
+ if (!isRecord(cursor))
23
+ return null;
24
+ cursor = cursor[key];
25
+ }
26
+ return typeof cursor === "string" ? cursor : null;
27
+ };
28
+ const DAY = 24 * 60 * 60 * 1000;
29
+ export const campaignViewOf = (input) => {
30
+ const { policy } = input;
31
+ const state = campaignsOf(policy);
32
+ const snapshots = snapshotCampaignsOf(policy, input.evaluations);
33
+ const position = (path) => positionAt(input.locate, input.manifestPath, path);
34
+ const campaigns = input.evaluations.map((evaluation, index) => {
35
+ const { rule } = evaluation;
36
+ const report = input.reports[index];
37
+ const snapshot = snapshots[index];
38
+ if (report === undefined || snapshot === undefined) {
39
+ throw new Error(`campaign ${rule.id} was evaluated without a report`);
40
+ }
41
+ const scalar = new Set(rule.objectives.filter((one) => one.measure !== null).map((one) => one.id));
42
+ const objectives = rule.objectives.map((objective, j) => {
43
+ const own = report.objectives[j];
44
+ const summary = snapshot.objectives[j];
45
+ const ledger = state.ledgers.get(ledgerKeyOf(rule.id, objective.id));
46
+ const sectors = (own?.sectors ?? []).map((sector) => {
47
+ const held = ledger?.sectors[sector.sector];
48
+ return {
49
+ sector: sector.sector,
50
+ count: sector.count,
51
+ holdouts: held?.holdouts ?? [],
52
+ new: sector.new,
53
+ stale: sector.stale,
54
+ drifted: sector.drifted,
55
+ unrecorded: sector.unrecorded,
56
+ initial: held?.initial ?? null,
57
+ cleared: held?.cleared ?? null,
58
+ closed: held?.closed ?? null,
59
+ lastCleared: held?.lastCleared ?? null,
60
+ measure: sector.measure ?? null,
61
+ };
62
+ });
63
+ return {
64
+ id: objective.id,
65
+ message: objective.message,
66
+ why: objective.why,
67
+ holdout: objective.measure !== null ? "measure" : (objective.holdout ?? "match"),
68
+ phase: summary?.phase ?? null,
69
+ position: position(["campaigns", rule.id, "objectives", objective.id]),
70
+ count: summary?.count ?? own?.count ?? 0,
71
+ initial: summary?.initial ?? 0,
72
+ allowed: summary?.allowed ?? 0,
73
+ cleared: summary?.cleared ?? 0,
74
+ closed: summary?.closed ?? 0,
75
+ progress: summary?.progress ?? 0,
76
+ lastCleared: summary?.lastCleared ?? null,
77
+ concessions: summary?.concessions ?? 0,
78
+ complete: summary?.complete ?? false,
79
+ ledgered: summary?.ledgered ?? false,
80
+ measure: own?.measure === undefined
81
+ ? null
82
+ : {
83
+ direction: own.measure.direction,
84
+ value: own.measure.value,
85
+ recorded: own.measure.recorded,
86
+ target: own.measure.target,
87
+ tolerance: own.measure.tolerance,
88
+ },
89
+ sectors,
90
+ };
91
+ });
92
+ const phases = rule.phases.map((phase, i) => ({
93
+ id: phase.id,
94
+ index: i,
95
+ defined: isDefinedPhase(phase),
96
+ intent: phase.intent ?? null,
97
+ attested: phase.attested,
98
+ objectives: [...phase.objectives],
99
+ sectors: snapshot.phases[i]?.sectors ?? 0,
100
+ concessions: phase.concessions.length,
101
+ position: position(["campaigns", rule.id, "phases", i]),
102
+ }));
103
+ const hitsOf = (sector) => evaluation.hits
104
+ .filter((hit) => hit.sector === sector)
105
+ .map((hit) => ({
106
+ objective: hit.objective,
107
+ file: hit.violation.file,
108
+ subject: hit.violation.subject,
109
+ line: hit.range === undefined ? null : hit.range.start.line + 1,
110
+ entry: hit.entry,
111
+ message: hit.violation.message,
112
+ }))
113
+ .sort((a, b) => {
114
+ const byFile = a.file.localeCompare(b.file);
115
+ return byFile !== 0 ? byFile : a.entry.localeCompare(b.entry);
116
+ });
117
+ const sectors = [...evaluation.sectors.values()].map((sectorState) => {
118
+ const record = state.sectorRecords.get(ledgerKeyOf(rule.id, sectorState.name));
119
+ const summary = snapshot.sectors.find((one) => one.name === sectorState.name);
120
+ const residueTotal = Object.entries(sectorState.residue)
121
+ .filter(([id]) => !scalar.has(id))
122
+ .reduce((sum, [, n]) => sum + n, 0);
123
+ const scalarOpen = Object.entries(sectorState.counts).some(([id, n]) => scalar.has(id) && n > 0);
124
+ return {
125
+ name: sectorState.name,
126
+ legacy: sectorState.name === LEGACY_SECTOR,
127
+ phase: sectorState.phase,
128
+ phaseId: rule.phases[sectorState.phase]?.id ?? null,
129
+ done: rule.phases.length === 0
130
+ ? residueTotal === 0 && !scalarOpen
131
+ : sectorState.phase >= rule.phases.length,
132
+ reached: record?.reached ?? null,
133
+ since: record?.since ?? null,
134
+ roots: sectorState.sector.roots,
135
+ marker: sectorState.sector.marker,
136
+ files: [...sectorState.sector.files].sort(),
137
+ residue: sectorState.residue,
138
+ counts: sectorState.counts,
139
+ values: sectorState.values,
140
+ stalled: summary?.stalled ?? false,
141
+ attested: record?.attested ?? [],
142
+ notes: record?.notes ?? [],
143
+ hits: hitsOf(sectorState.name),
144
+ };
145
+ });
146
+ return {
147
+ id: rule.id,
148
+ title: rule.title,
149
+ why: rule.why,
150
+ how: stringAt(input.manifest, "campaigns", rule.id, "how"),
151
+ owner: rule.owner,
152
+ scope: rule.scope.map((one) => one.source),
153
+ perimeter: rule.perimeter?.kind ?? null,
154
+ staleAfterDays: rule.staleAfter === null ? null : Math.round(rule.staleAfter / DAY),
155
+ onComplete: rule.onComplete,
156
+ position: position(["campaigns", rule.id]),
157
+ count: snapshot.count,
158
+ progress: snapshot.progress,
159
+ stalled: report.stalled,
160
+ complete: report.complete,
161
+ ledgered: snapshot.ledgered,
162
+ missingLedger: report.missingLedger,
163
+ arithmetic: report.arithmetic,
164
+ phases,
165
+ objectives,
166
+ sectors,
167
+ legacy: snapshot.legacy,
168
+ drift: report.drift,
169
+ plan: report.plan,
170
+ };
171
+ });
172
+ return {
173
+ version: 1,
174
+ name: input.name,
175
+ generatedAt: new Date(input.now).toISOString(),
176
+ ledgerDir: state.ledgerDir,
177
+ campaigns,
178
+ nudge: input.nudge,
179
+ };
180
+ };
181
+ //# sourceMappingURL=campaigns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"campaigns.js","sourceRoot":"","sources":["../../../src/model/campaigns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ import { readFileSync } from "node:fs";
2
+ import * as path from "node:path";
3
+ import { campaignReportsOf, campaignsOf, evaluateCampaigns, nudgeOf, readDiff, reportSpecsOf, widenedExtensions, } from "@goodbones/campaigns";
4
+ import { listSourceFiles } from "@goodbones/core";
5
+ import { buildAtlas } from "../model/atlas.js";
6
+ import { campaignViewOf } from "../model/campaigns.js";
7
+ import { loadPolicyFromFile } from "./compose.js";
8
+ const toPosix = (file) => file.split(path.sep).join("/");
9
+ export const collect = async (options) => {
10
+ const loaded = await loadPolicyFromFile(options.repoRoot, options.configFilename);
11
+ return collectWith(loaded, options);
12
+ };
13
+ export const collectWith = async (loaded, options) => {
14
+ const { policy } = loaded;
15
+ const name = path.basename(options.repoRoot);
16
+ const manifestPath = toPosix(path.relative(options.repoRoot, loaded.configPath));
17
+ // Every `report` a campaign names is read now, before any file asks.
18
+ await Promise.all(reportSpecsOf(campaignsOf(policy).campaignRules).map((spec) => campaignsOf(policy).reports.read?.(spec)));
19
+ const walked = listSourceFiles(options.repoRoot, options.roots, policy.languages, widenedExtensions(policy));
20
+ const known = new Set(policy.languages.flatMap((one) => one.extensions));
21
+ const files = walked.filter((file) => known.has(path.extname(file)));
22
+ const texts = new Map();
23
+ const textOf = (file) => {
24
+ const cached = texts.get(file);
25
+ if (cached !== undefined)
26
+ return cached;
27
+ const text = readFileSync(path.join(options.repoRoot, file), "utf8");
28
+ texts.set(file, text);
29
+ return text;
30
+ };
31
+ const parsed = new Map();
32
+ const factsOf = (file) => {
33
+ const cached = parsed.get(file);
34
+ if (cached !== undefined)
35
+ return cached;
36
+ const facts = policy.extractor.factsOf(file, textOf(file));
37
+ parsed.set(file, facts);
38
+ return facts;
39
+ };
40
+ const atlas = buildAtlas({
41
+ policy,
42
+ name,
43
+ roots: options.roots,
44
+ files,
45
+ factsOf,
46
+ locate: loaded.locate,
47
+ manifestPath,
48
+ manifestFiles: loaded.files.map((file) => ({
49
+ path: toPosix(path.relative(options.repoRoot, file)),
50
+ text: readFileSync(file, "utf8"),
51
+ })),
52
+ now: policy.now,
53
+ });
54
+ const evaluations = evaluateCampaigns(policy, options.roots, walked, { textOf, factsOf });
55
+ const reports = campaignReportsOf(policy, evaluations);
56
+ const nudge = options.nudge === false ? null : nudgeFor(loaded, evaluations);
57
+ const campaigns = campaignViewOf({
58
+ policy,
59
+ name,
60
+ evaluations,
61
+ reports,
62
+ manifest: loaded.manifest,
63
+ locate: loaded.locate,
64
+ manifestPath,
65
+ nudge,
66
+ now: policy.now,
67
+ });
68
+ return { atlas, campaigns };
69
+ };
70
+ // The nudge for the working tree against HEAD, or nothing where git does
71
+ // not answer — a repository with no commits, or none at all.
72
+ const nudgeFor = (loaded, evaluations) => {
73
+ if (campaignsOf(loaded.policy).campaignRules.length === 0)
74
+ return null;
75
+ try {
76
+ const diff = readDiff(loaded.policy.repoRoot, null);
77
+ return nudgeOf(loaded.policy, evaluations, diff, null, null, null);
78
+ }
79
+ catch {
80
+ return null;
81
+ }
82
+ };
83
+ //# sourceMappingURL=collect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collect.js","sourceRoot":"","sources":["../../../src/server/collect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import * as path from "node:path";
2
+ import { astGrepMatcher } from "@goodbones/ast-grep";
3
+ import { campaignsExtension, loadCampaignFunctions, makeReportSourceLive, } from "@goodbones/campaigns";
4
+ import { findManifestFile, loadPolicy, makeFileSystemLive, readManifestFile, } from "@goodbones/core";
5
+ import { typescriptLanguage } from "@goodbones/typescript";
6
+ import * as Result from "effect/Result";
7
+ // This host's composition root: the same three lines the CLI and the plugin
8
+ // each have, on purpose — the three hosts share the core and never each
9
+ // other. Nothing below this file names TypeScript or ast-grep.
10
+ export const hostLanguages = () => [
11
+ typescriptLanguage({ syntax: astGrepMatcher() }),
12
+ ];
13
+ export const hostNow = () => {
14
+ const pinned = process.env.ARCHITECTURE_NOW;
15
+ if (pinned === undefined || pinned === "")
16
+ return Date.now();
17
+ const parsed = /^\d+$/.test(pinned) ? Number(pinned) : Date.parse(pinned);
18
+ if (Number.isNaN(parsed)) {
19
+ throw new Error(`ARCHITECTURE_NOW is ${JSON.stringify(pinned)}, which is not a date.`);
20
+ }
21
+ return parsed;
22
+ };
23
+ export const manifestPathOf = (repoRoot, configFilename) => configFilename === undefined
24
+ ? findManifestFile(repoRoot)
25
+ : path.resolve(repoRoot, configFilename);
26
+ export const loadPolicyFromFile = async (repoRoot, configFilename) => {
27
+ const configPath = manifestPathOf(repoRoot, configFilename);
28
+ const read = await readManifestFile(configPath);
29
+ const { functions, manifest } = await loadCampaignFunctions(configPath, read.manifest);
30
+ const loaded = loadPolicy({
31
+ repoRoot,
32
+ configPath,
33
+ manifest,
34
+ locate: read.locate,
35
+ languages: hostLanguages(),
36
+ fileSystem: makeFileSystemLive(repoRoot),
37
+ extensions: [campaignsExtension({ functions, reports: makeReportSourceLive(repoRoot) })],
38
+ now: hostNow(),
39
+ });
40
+ if (Result.isFailure(loaded))
41
+ throw loaded.failure;
42
+ return {
43
+ policy: loaded.success,
44
+ manifest: read.manifest,
45
+ locate: read.locate,
46
+ configPath,
47
+ files: read.files,
48
+ };
49
+ };
50
+ //# sourceMappingURL=compose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose.js","sourceRoot":"","sources":["../../../src/server/compose.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,gBAAgB,EAGhB,UAAU,EACV,kBAAkB,EAElB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,4EAA4E;AAC5E,wEAAwE;AACxE,+DAA+D;AAE/D,MAAM,CAAC,MAAM,aAAa,GAAG,GAA4B,EAAE,CAAC;IAC1D,kBAAkB,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,CAAC;CACjD,CAAC;AAEF,MAAM,CAAC,MAAM,OAAO,GAAG,GAAW,EAAE;IAClC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC5C,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7D,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1E,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC;IACzF,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,QAAgB,EAAE,cAAuB,EAAU,EAAE,CAClF,cAAc,KAAK,SAAS;IAC1B,CAAC,CAAC,gBAAgB,CAAC,QAAQ,CAAC;IAC5B,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;AAY7C,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,EACrC,QAAgB,EAChB,cAAuB,EACE,EAAE;IAC3B,MAAM,UAAU,GAAG,cAAc,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;IAC5D,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAChD,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,MAAM,qBAAqB,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvF,MAAM,MAAM,GAAG,UAAU,CAAC;QACxB,QAAQ;QACR,UAAU;QACV,QAAQ;QACR,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,SAAS,EAAE,aAAa,EAAE;QAC1B,UAAU,EAAE,kBAAkB,CAAC,QAAQ,CAAC;QACxC,UAAU,EAAE,CAAC,kBAAkB,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,oBAAoB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACxF,GAAG,EAAE,OAAO,EAAE;KACf,CAAC,CAAC;IACH,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;QAAE,MAAM,MAAM,CAAC,OAAO,CAAC;IACnD,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,OAAO;QACtB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,UAAU;QACV,KAAK,EAAE,IAAI,CAAC,KAAK;KAClB,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { cpSync, mkdirSync, writeFileSync } from "node:fs";
2
+ import * as path from "node:path";
3
+ // A static export: the page as built, with the two models written where the
4
+ // page fetches them. Serve the folder from the root of a host; the page
5
+ // finds no feed there and says it is a snapshot.
6
+ export const exportSite = (siteDir, out, collected) => {
7
+ mkdirSync(out, { recursive: true });
8
+ cpSync(siteDir, out, { recursive: true });
9
+ const data = path.join(out, "__goodbones");
10
+ mkdirSync(data, { recursive: true });
11
+ writeFileSync(path.join(data, "atlas.json"), JSON.stringify(collected.atlas));
12
+ writeFileSync(path.join(data, "campaigns.json"), JSON.stringify(collected.campaigns));
13
+ writeFileSync(path.join(data, "status.json"), JSON.stringify({
14
+ name: collected.atlas.name,
15
+ generatedAt: collected.atlas.generatedAt,
16
+ live: false,
17
+ }));
18
+ };
19
+ //# sourceMappingURL=export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../../../src/server/export.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAIlC,4EAA4E;AAC5E,wEAAwE;AACxE,iDAAiD;AACjD,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,OAAe,EAAE,GAAW,EAAE,SAAoB,EAAQ,EAAE;IACrF,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IAC3C,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9E,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,gBAAgB,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC;IACtF,aAAa,CACX,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,EAC9B,IAAI,CAAC,SAAS,CAAC;QACb,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,IAAI;QAC1B,WAAW,EAAE,SAAS,CAAC,KAAK,CAAC,WAAW;QACxC,IAAI,EAAE,KAAK;KACZ,CAAC,CACH,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,67 @@
1
+ // The routes the page reads, mounted under `/__goodbones/` by the bin's
2
+ // server and by the Vite plugin alike, so the page is the same in both:
3
+ //
4
+ // atlas.json the Architecture Browser's model
5
+ // campaigns.json the Campaign Browser's model
6
+ // status.json the repository's name and whether the feed is live
7
+ // events server-sent events: `changed` when the repository does
8
+ //
9
+ // A static export writes the first three as files and has no feed.
10
+ export const PREFIX = "/__goodbones/";
11
+ const HEARTBEAT_MS = 25_000;
12
+ const json = (response, status, body) => {
13
+ response.statusCode = status;
14
+ response.setHeader("content-type", "application/json; charset=utf-8");
15
+ response.setHeader("cache-control", "no-store");
16
+ response.end(JSON.stringify(body));
17
+ };
18
+ const messageOf = (cause) => typeof cause === "object" && cause !== null && "message" in cause
19
+ ? String(cause.message)
20
+ : String(cause);
21
+ export const makeHandler = (source) => {
22
+ return async (request, response) => {
23
+ const url = new URL(request.url ?? "/", "http://localhost");
24
+ if (!url.pathname.startsWith(PREFIX))
25
+ return false;
26
+ const route = url.pathname.slice(PREFIX.length);
27
+ if (route === "events") {
28
+ response.statusCode = 200;
29
+ response.setHeader("content-type", "text/event-stream");
30
+ response.setHeader("cache-control", "no-store");
31
+ response.setHeader("connection", "keep-alive");
32
+ response.write(`event: hello\ndata: ${JSON.stringify({ live: source.live })}\n\n`);
33
+ const unsubscribe = source.subscribe((change) => {
34
+ response.write(`event: changed\ndata: ${JSON.stringify(change)}\n\n`);
35
+ });
36
+ const heartbeat = setInterval(() => response.write(": keep-alive\n\n"), HEARTBEAT_MS);
37
+ request.on("close", () => {
38
+ clearInterval(heartbeat);
39
+ unsubscribe();
40
+ });
41
+ return true;
42
+ }
43
+ if (route === "atlas.json" || route === "campaigns.json" || route === "status.json") {
44
+ try {
45
+ const collected = await source.current();
46
+ if (route === "atlas.json")
47
+ json(response, 200, collected.atlas);
48
+ else if (route === "campaigns.json")
49
+ json(response, 200, collected.campaigns);
50
+ else {
51
+ json(response, 200, {
52
+ name: collected.atlas.name,
53
+ generatedAt: collected.atlas.generatedAt,
54
+ live: source.live,
55
+ });
56
+ }
57
+ }
58
+ catch (cause) {
59
+ json(response, 500, { error: messageOf(cause) });
60
+ }
61
+ return true;
62
+ }
63
+ json(response, 404, { error: `no such route: ${url.pathname}` });
64
+ return true;
65
+ };
66
+ };
67
+ //# sourceMappingURL=handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/server/handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ import { createReadStream, existsSync, statSync } from "node:fs";
2
+ import { createServer } from "node:http";
3
+ import * as path from "node:path";
4
+ // The bin's server: the prebuilt page from `build/site`, and the handler's
5
+ // routes in front of it. No framework — the page is static files and the
6
+ // data is four routes.
7
+ const TYPES = {
8
+ ".html": "text/html; charset=utf-8",
9
+ ".js": "text/javascript; charset=utf-8",
10
+ ".mjs": "text/javascript; charset=utf-8",
11
+ ".css": "text/css; charset=utf-8",
12
+ ".json": "application/json; charset=utf-8",
13
+ ".svg": "image/svg+xml",
14
+ ".png": "image/png",
15
+ ".ico": "image/x-icon",
16
+ ".woff": "font/woff",
17
+ ".woff2": "font/woff2",
18
+ ".txt": "text/plain; charset=utf-8",
19
+ ".map": "application/json; charset=utf-8",
20
+ };
21
+ // A path inside the site directory, or nothing for one that escapes it.
22
+ const fileFor = (siteDir, pathname) => {
23
+ const decoded = decodeURIComponent(pathname);
24
+ const wanted = decoded.endsWith("/") ? `${decoded}index.html` : decoded;
25
+ const resolved = path.resolve(siteDir, `.${wanted}`);
26
+ if (!resolved.startsWith(siteDir))
27
+ return null;
28
+ if (existsSync(resolved) && statSync(resolved).isFile())
29
+ return resolved;
30
+ // `/architecture` for `architecture.html`, as the build's `format: file`
31
+ // emits pages.
32
+ const asPage = `${resolved}.html`;
33
+ if (existsSync(asPage) && statSync(asPage).isFile())
34
+ return asPage;
35
+ return null;
36
+ };
37
+ export const serve = (options) => new Promise((resolve, reject) => {
38
+ const siteDir = path.resolve(options.siteDir);
39
+ const server = createServer((request, response) => {
40
+ options
41
+ .handler(request, response)
42
+ .then((handled) => {
43
+ if (handled)
44
+ return;
45
+ const url = new URL(request.url ?? "/", "http://localhost");
46
+ const file = fileFor(siteDir, url.pathname);
47
+ if (file === null) {
48
+ response.statusCode = 404;
49
+ response.setHeader("content-type", "text/plain; charset=utf-8");
50
+ response.end("not found");
51
+ return;
52
+ }
53
+ response.statusCode = 200;
54
+ response.setHeader("content-type", TYPES[path.extname(file)] ?? "application/octet-stream");
55
+ response.setHeader("cache-control", "no-cache");
56
+ createReadStream(file).pipe(response);
57
+ })
58
+ .catch((cause) => {
59
+ response.statusCode = 500;
60
+ response.setHeader("content-type", "text/plain; charset=utf-8");
61
+ response.end(String(cause));
62
+ });
63
+ });
64
+ server.once("error", reject);
65
+ server.listen(options.port, options.host, () => {
66
+ const address = server.address();
67
+ const host = options.host === "0.0.0.0" || options.host === "::" ? "localhost" : options.host;
68
+ resolve({
69
+ server,
70
+ url: `http://${host}:${String(address.port)}/`,
71
+ close: () => new Promise((done) => {
72
+ server.closeAllConnections();
73
+ server.close(() => {
74
+ done();
75
+ });
76
+ }),
77
+ });
78
+ });
79
+ });
80
+ //# sourceMappingURL=serve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve.js","sourceRoot":"","sources":["../../../src/server/serve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import * as path from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ // Where `astro build` put the page: `build/site`, beside this module's
4
+ // `build/esm`. The bin serves it; a static export copies it.
5
+ export const SITE_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../site");
6
+ //# sourceMappingURL=site.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site.js","sourceRoot":"","sources":["../../../src/server/site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,uEAAuE;AACvE,6DAA6D;AAC7D,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC"}
@@ -0,0 +1,67 @@
1
+ import { collect } from "./collect.js";
2
+ import { watchRepository } from "./watch.js";
3
+ export const makeSource = (options) => {
4
+ const listeners = new Set();
5
+ let cached = null;
6
+ const compute = options.compute ?? (() => collect(options));
7
+ const current = () => {
8
+ if (cached === null) {
9
+ const started = compute();
10
+ cached = started;
11
+ // A failed computation is not kept: the next request tries again,
12
+ // after the author has fixed the manifest.
13
+ started.catch(() => {
14
+ if (cached === started)
15
+ cached = null;
16
+ });
17
+ }
18
+ return cached;
19
+ };
20
+ const invalidate = (files) => {
21
+ cached = null;
22
+ const change = { files, at: new Date().toISOString() };
23
+ for (const listener of listeners)
24
+ listener(change);
25
+ };
26
+ let stopWatching = null;
27
+ if (options.watch === true) {
28
+ // The extensions and the ledger directory come from the policy, once it
29
+ // has loaded; until then every change under the roots counts.
30
+ stopWatching = watchRepository({
31
+ repoRoot: options.repoRoot,
32
+ extensions: [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"],
33
+ ledgerDir: ".architecture-campaigns",
34
+ debounceMs: options.debounceMs,
35
+ onChange: invalidate,
36
+ });
37
+ void current()
38
+ .then((collected) => {
39
+ stopWatching?.();
40
+ stopWatching = watchRepository({
41
+ repoRoot: options.repoRoot,
42
+ extensions: [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"],
43
+ ledgerDir: collected.campaigns.ledgerDir,
44
+ debounceMs: options.debounceMs,
45
+ onChange: invalidate,
46
+ });
47
+ })
48
+ .catch(() => {
49
+ // Keep the first watcher: the manifest that failed to load is one of
50
+ // the files it watches, and its fix is the next change.
51
+ });
52
+ }
53
+ return {
54
+ current,
55
+ subscribe: (listener) => {
56
+ listeners.add(listener);
57
+ return () => listeners.delete(listener);
58
+ },
59
+ invalidate,
60
+ live: options.watch === true,
61
+ close: () => {
62
+ stopWatching?.();
63
+ listeners.clear();
64
+ },
65
+ };
66
+ };
67
+ //# sourceMappingURL=source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.js","sourceRoot":"","sources":["../../../src/server/source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAuC,MAAM,cAAc,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAsB7C,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,OAAsB,EAAU,EAAE;IAC3D,MAAM,SAAS,GAAG,IAAI,GAAG,EAA4B,CAAC;IACtD,IAAI,MAAM,GAA8B,IAAI,CAAC;IAC7C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IAE5D,MAAM,OAAO,GAAG,GAAuB,EAAE;QACvC,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,OAAO,GAAG,OAAO,EAAE,CAAC;YAC1B,MAAM,GAAG,OAAO,CAAC;YACjB,kEAAkE;YAClE,2CAA2C;YAC3C,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE;gBACjB,IAAI,MAAM,KAAK,OAAO;oBAAE,MAAM,GAAG,IAAI,CAAC;YACxC,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;IAEF,MAAM,UAAU,GAAG,CAAC,KAA4B,EAAQ,EAAE;QACxD,MAAM,GAAG,IAAI,CAAC;QACd,MAAM,MAAM,GAAW,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;QAC/D,KAAK,MAAM,QAAQ,IAAI,SAAS;YAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACrD,CAAC,CAAC;IAEF,IAAI,YAAY,GAAwB,IAAI,CAAC;IAC7C,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QAC3B,wEAAwE;QACxE,8DAA8D;QAC9D,YAAY,GAAG,eAAe,CAAC;YAC7B,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;YAC1E,SAAS,EAAE,yBAAyB;YACpC,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,QAAQ,EAAE,UAAU;SACrB,CAAC,CAAC;QACH,KAAK,OAAO,EAAE;aACX,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE;YAClB,YAAY,EAAE,EAAE,CAAC;YACjB,YAAY,GAAG,eAAe,CAAC;gBAC7B,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;gBAC1E,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC,SAAS;gBACxC,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,QAAQ,EAAE,UAAU;aACrB,CAAC,CAAC;QACL,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE;YACV,qEAAqE;YACrE,wDAAwD;QAC1D,CAAC,CAAC,CAAC;IACP,CAAC;IAED,OAAO;QACL,OAAO;QACP,SAAS,EAAE,CAAC,QAAQ,EAAE,EAAE;YACtB,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACxB,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC1C,CAAC;QACD,UAAU;QACV,IAAI,EAAE,OAAO,CAAC,KAAK,KAAK,IAAI;QAC5B,KAAK,EAAE,GAAG,EAAE;YACV,YAAY,EAAE,EAAE,CAAC;YACjB,SAAS,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC;KACF,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { makeHandler } from "./handler.js";
2
+ import { makeSource } from "./source.js";
3
+ export const goodbonesBrowser = (options) => ({
4
+ name: "goodbones-browser",
5
+ configureServer(server) {
6
+ const source = makeSource({ ...options, watch: true });
7
+ const handle = makeHandler(source);
8
+ server.middlewares.use((request, response, next) => {
9
+ handle(request, response)
10
+ .then((handled) => {
11
+ if (!handled)
12
+ next();
13
+ })
14
+ .catch(next);
15
+ });
16
+ server.httpServer?.once("close", () => {
17
+ source.close();
18
+ });
19
+ },
20
+ });
21
+ //# sourceMappingURL=vite-plugin.js.map