@abide/abide 0.100.0 → 0.102.0
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/CHANGELOG.md +31 -0
- package/bin/abide.ts +227 -163
- package/docs/REGISTRY.md +726 -0
- package/docs/RULEBOOK.md +2753 -0
- package/docs/abide.md +12878 -0
- package/package.json +10 -3
- package/scaffold/AGENTS.md +31 -0
- package/scaffold/CLAUDE.md +1 -0
- package/scaffold/src/layout.abide +18 -0
- package/src/compiler/Lowering.ts +78 -9
- package/src/compiler/ShadowMap.ts +2 -2
- package/src/compiler/TypeSession.ts +262 -67
- package/src/compiler/argsSchemaOf.ts +1 -1
- package/src/compiler/checkApp.ts +43 -15
- package/src/compiler/checkedShadow.ts +39 -5
- package/src/compiler/classifyRead.ts +6 -4
- package/src/compiler/classifyTemplate.ts +1 -1
- package/src/compiler/compileApp.ts +433 -193
- package/src/compiler/compiledEntry.ts +43 -39
- package/src/compiler/componentGraph.ts +58 -71
- package/src/compiler/declaredExports.ts +24 -7
- package/src/compiler/emitClient.ts +141 -71
- package/src/compiler/emitComponent.ts +37 -8
- package/src/compiler/emitSource.ts +106 -13
- package/src/compiler/handlersUnder.ts +106 -56
- package/src/compiler/index.ts +7 -0
- package/src/compiler/mountsOf.ts +138 -0
- package/src/compiler/nearest.ts +14 -0
- package/src/compiler/parseAbide.ts +157 -20
- package/src/compiler/projectShadow.ts +213 -7
- package/src/compiler/reactiveTypes.ts +20 -7
- package/src/compiler/readSources.ts +15 -2
- package/src/compiler/readsIn.ts +61 -7
- package/src/compiler/renderMarkup.ts +3 -3
- package/src/compiler/scaffold.ts +30 -11
- package/src/compiler/serveLanguage.ts +125 -34
- package/src/compiler/sourceMapOf.ts +193 -0
- package/src/compiler/splitImports.ts +205 -83
- package/src/compiler/syncTypes.ts +32 -0
- package/src/compiler/tokenize.ts +14 -0
- package/src/compiler/writeDefaultProject.ts +1 -1
- package/src/compiler/writeTypes.ts +82 -0
- package/src/server/CLIENT_BUILD.ts +11 -13
- package/src/server/DEFAULT_PORT.ts +1 -1
- package/src/server/LAUNCHER_FILES.ts +9 -0
- package/src/server/MODULE_QUERIES.ts +18 -0
- package/src/server/TABLES.ts +7 -0
- package/src/server/VIRTUAL_DIRECTORY.ts +4 -5
- package/src/server/abideModules.ts +391 -0
- package/src/server/answerFailure.ts +16 -6
- package/src/server/answerRequest.ts +235 -106
- package/src/server/answerRpc.ts +124 -39
- package/src/server/answerSocket.ts +141 -48
- package/src/server/answerValue.ts +22 -9
- package/src/server/appDirectories.ts +1 -1
- package/src/server/appPlugins.ts +1 -1
- package/src/server/appTree.ts +179 -0
- package/src/server/argsFor.ts +2 -2
- package/src/server/assistant.ts +2 -2
- package/src/server/bridgeRelay.ts +6 -8
- package/src/server/claudeCode.ts +0 -6
- package/src/server/clientBuildOptions.ts +8 -3
- package/src/server/coerceArgs.ts +1 -1
- package/src/server/commands.ts +37 -37
- package/src/server/componentModules.d.ts +3 -1
- package/src/server/compressAnswer.ts +48 -14
- package/src/server/config.ts +25 -29
- package/src/server/configFields.ts +31 -25
- package/src/server/createApp.ts +59 -73
- package/src/server/devWorker.ts +144 -183
- package/src/server/executableName.ts +4 -0
- package/src/server/fenceServer.ts +37 -35
- package/src/server/generatedSurfaces.ts +99 -66
- package/src/server/hooks.ts +124 -52
- package/src/server/iconAccent.ts +191 -0
- package/src/server/index.ts +11 -7
- package/src/server/installSourceMaps.ts +88 -0
- package/src/server/launcherOptions.ts +34 -31
- package/src/server/launcherPage.ts +107 -64
- package/src/server/manifestOf.ts +16 -13
- package/src/server/namesUnder.ts +2 -2
- package/src/server/nativeMenu.ts +5 -5
- package/src/server/negotiateEncoding.ts +1 -1
- package/src/server/principal.ts +10 -5
- package/src/server/realOrAsGiven.ts +10 -0
- package/src/server/refuseAddressCollision.ts +21 -14
- package/src/server/remote.ts +49 -52
- package/src/server/render.ts +65 -94
- package/src/server/renderComponent.ts +5 -0
- package/src/server/reportHealth.ts +2 -2
- package/src/server/requestScope.ts +12 -1
- package/src/server/runBuild.ts +24 -0
- package/src/server/runCompiled.ts +5 -5
- package/src/server/runDesktop.ts +52 -27
- package/src/server/serveBuild.ts +43 -52
- package/src/server/serveDev.ts +81 -39
- package/src/server/shell.ts +7 -22
- package/src/server/sourceMappings.ts +139 -0
- package/src/server/surfaceOf.ts +18 -3
- package/src/server/testBuild.ts +1 -19
- package/src/server/withAbideSources.ts +117 -0
- package/src/shared/ADDRESSES.ts +7 -18
- package/src/shared/APP_META.ts +7 -0
- package/src/shared/CopyOptions.ts +1 -1
- package/src/shared/DEBUG_META.ts +1 -1
- package/src/shared/GLOBAL_GETS.ts +9 -3
- package/src/shared/RESERVED_DIRECTORIES.ts +15 -0
- package/src/shared/RPC_SERVER.ts +2 -2
- package/src/shared/cookies.ts +2 -2
- package/src/shared/csp.ts +1 -1
- package/src/shared/escapeText.ts +1 -1
- package/src/shared/filledPath.ts +85 -0
- package/src/shared/framing.ts +79 -6
- package/src/shared/headKeyOf.ts +2 -0
- package/src/shared/index.ts +1 -1
- package/src/shared/log.ts +27 -13
- package/src/shared/matchRoute.ts +23 -4
- package/src/shared/menuItem.ts +3 -3
- package/src/shared/reactive/Cursor.ts +3 -9
- package/src/shared/reactive/Keyed.ts +4 -3
- package/src/shared/reactive/NotLanded.ts +1 -1
- package/src/shared/reactive/Reactive.ts +81 -60
- package/src/shared/reactive/argsContract.ts +4 -4
- package/src/shared/reactive/canonicalKey.ts +4 -4
- package/src/shared/reactive/chunksOfStream.ts +6 -0
- package/src/shared/reactive/index.ts +1 -1
- package/src/shared/reactive/recordWrites.ts +103 -5
- package/src/shared/reactive/structural.ts +1 -1
- package/src/shared/reactive/tracking.ts +155 -21
- package/src/shared/reactive/watch.ts +10 -6
- package/src/shared/refuse.ts +1 -1
- package/src/shared/routePattern.ts +82 -46
- package/src/shared/rpc.ts +47 -13
- package/src/shared/rpcRequest.ts +27 -3
- package/src/shared/url.ts +4 -44
- package/src/shared/writePath.ts +1 -1
- package/src/ui/LAYER_NAMES.ts +1 -1
- package/src/ui/List.ts +3 -3
- package/src/ui/MOUNTING_LEVEL.ts +18 -0
- package/src/ui/Mismatch.ts +1 -1
- package/src/ui/RawRun.ts +1 -1
- package/src/ui/Router.ts +38 -31
- package/src/ui/Scope.ts +1 -1
- package/src/ui/TryRegion.ts +2 -2
- package/src/ui/applyHead.ts +33 -0
- package/src/ui/index.ts +1 -1
- package/src/ui/menuBridge.ts +1 -1
- package/src/ui/moveNode.ts +1 -1
- package/src/ui/reconcile.ts +2 -2
- package/src/ui/reportMenu.ts +2 -2
- package/src/ui/routing.ts +2 -2
- package/src/ui/setAttribute.ts +1 -1
- package/src/ui/setText.ts +1 -1
- package/src/ui/socketWire.ts +9 -7
- package/src/ui/wire.ts +1 -1
- package/scaffold/src/server/app.ts +0 -6
- package/scaffold/src/shared/.gitkeep +0 -0
- package/scaffold/src/ui/app.html +0 -8
- package/src/server/componentImports.ts +0 -56
- /package/scaffold/src/{ui/pages/page.abide → page.abide} +0 -0
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import { AsyncLocalStorage } from 'node:async_hooks' // bun implements AsyncLocalStorage and has no context-carrying api of its own
|
|
13
13
|
import { Cookies } from '#shared/cookies.ts'
|
|
14
|
+
import type { Params } from '#shared/matchRoute.ts'
|
|
14
15
|
import type { Principal } from '#shared/principal.ts'
|
|
15
16
|
import { SCOPING, type Scope } from '#shared/reactive/scoping.ts'
|
|
16
17
|
import type { RpcRequest } from '#shared/rpcRequest.ts'
|
|
@@ -51,6 +52,14 @@ export type RequestScope = Scope & {
|
|
|
51
52
|
trace: { id: string; span: string; flags: string } | undefined
|
|
52
53
|
/** `undefined` where the scope was opened without one — 42.8's scope, which 22.1 throws in. */
|
|
53
54
|
request: Request | undefined
|
|
55
|
+
/**
|
|
56
|
+
* The route the request matched, once routing has run: the file route whose hooks answer it.
|
|
57
|
+
*
|
|
58
|
+
* 37.5 — which `onError` hooks an error in this request reaches.
|
|
59
|
+
*/
|
|
60
|
+
route: string | undefined
|
|
61
|
+
/** What that route matched in the address, for the answer its rungs reach (16.14). */
|
|
62
|
+
params: Params | undefined
|
|
54
63
|
/**
|
|
55
64
|
* The app that opened this scope: the `App.fetch` `RPC_SERVER.raw` answers through, and its MCP
|
|
56
65
|
* surface.
|
|
@@ -158,6 +167,8 @@ export function scopeFor(
|
|
|
158
167
|
principal: undefined,
|
|
159
168
|
applied: false,
|
|
160
169
|
request: given,
|
|
170
|
+
route: undefined,
|
|
171
|
+
params: undefined,
|
|
161
172
|
received,
|
|
162
173
|
app,
|
|
163
174
|
response: { status: 200, headers: new Headers() },
|
|
@@ -376,7 +387,7 @@ export function handlerTook(rpc: object, duration: number): void {
|
|
|
376
387
|
/**
|
|
377
388
|
* Adds `duration` to the time spent in rungs.
|
|
378
389
|
*
|
|
379
|
-
* 21.20 — or takes it back out where it was the
|
|
390
|
+
* 21.20 — or takes it back out where it was the center's.
|
|
380
391
|
*/
|
|
381
392
|
export function rungsTook(duration: number): void {
|
|
382
393
|
const timing = STORAGE.getStore()?.timing
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// The CLI, spawned rather than imported: the compiler is not reachable from the server seam.
|
|
2
|
+
const ABIDE_BIN = Bun.fileURLToPath(
|
|
3
|
+
new URL('../../bin/abide.ts', import.meta.url),
|
|
4
|
+
)
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `abide build` of the app under `root` into `out`, run as the CLI.
|
|
8
|
+
*
|
|
9
|
+
* SPAWNED RATHER THAN IMPORTED: the compiler is not reachable from the server seam.
|
|
10
|
+
*/
|
|
11
|
+
export async function runBuild(root: string, out: string): Promise<void> {
|
|
12
|
+
const child = Bun.spawn(
|
|
13
|
+
[process.execPath, ABIDE_BIN, 'build', '--root', root, '--out', out],
|
|
14
|
+
{ stdout: 'ignore', stderr: 'pipe' },
|
|
15
|
+
)
|
|
16
|
+
const [exitCode, said] = await Promise.all([
|
|
17
|
+
child.exited,
|
|
18
|
+
new Response(child.stderr).text(),
|
|
19
|
+
])
|
|
20
|
+
if (exitCode !== 0)
|
|
21
|
+
throw new Error(
|
|
22
|
+
`abide: could not build the app under ${root}.\n${said}`,
|
|
23
|
+
)
|
|
24
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// 38.
|
|
1
|
+
// 38.50 — A COMPILED APP'S COMMAND LINE: `abide`'s list (`commands.ts`), over the app the executable
|
|
2
2
|
// holds rather than one on disk, and spoken under the name it was started by — a `--platforms` build
|
|
3
3
|
// is `ledger-linux-x64`, and that is what a reader types.
|
|
4
4
|
|
|
@@ -9,11 +9,11 @@ import { type BuildParts, builtSources, serveApp } from './serveBuild.ts'
|
|
|
9
9
|
export async function runCompiled(
|
|
10
10
|
origin: AppOrigin,
|
|
11
11
|
parts: BuildParts,
|
|
12
|
-
// 38.
|
|
13
|
-
// and the app's
|
|
12
|
+
// 38.56 — every specifier a script `run` may import out of the executable: abide's own entries
|
|
13
|
+
// and the app's `.abide` modules, each to the module it holds.
|
|
14
14
|
specifiers: Record<string, () => Promise<Record<string, unknown>>>,
|
|
15
15
|
): Promise<void> {
|
|
16
|
-
// REGISTERED AT START AND LOADED ON FIRST IMPORT:
|
|
16
|
+
// REGISTERED AT START AND LOADED ON FIRST IMPORT: an app module a script never names never
|
|
17
17
|
// runs its top level, as it would not under `abide run`.
|
|
18
18
|
Bun.plugin({
|
|
19
19
|
name: 'abide:compiled-specifiers',
|
|
@@ -30,7 +30,7 @@ export async function runCompiled(
|
|
|
30
30
|
handlers: async () => parts.handlers,
|
|
31
31
|
appPackage: () => origin.package,
|
|
32
32
|
boot: () => bootApp(origin, () => builtSources(parts)),
|
|
33
|
-
// 38.
|
|
33
|
+
// 38.49.
|
|
34
34
|
serve: ({ values: { port } }) =>
|
|
35
35
|
serveApp(
|
|
36
36
|
origin,
|
package/src/server/runDesktop.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// 38.
|
|
1
|
+
// 38.70 — WHAT `abide bundle` WRITES, STARTED WITH NO COMMAND: a window on the app. Given a command
|
|
2
2
|
// it is the executable `abide compile` writes (`runCompiled`), so a terminal still reaches every one.
|
|
3
3
|
//
|
|
4
4
|
// ONE PROCESS. The app, the launcher's own page and the window share it: AppKit's events are drained
|
|
@@ -25,18 +25,19 @@ import {
|
|
|
25
25
|
import { APP_PACKAGE, configuredMount, dataDirectory } from './config.ts'
|
|
26
26
|
import { configFields } from './configFields.ts'
|
|
27
27
|
import { type App, type AppOrigin, bootApp } from './createApp.ts'
|
|
28
|
+
import { executableName } from './executableName.ts'
|
|
28
29
|
import { reportUnexpected } from './hooks.ts'
|
|
29
30
|
import { installServer } from './installServer.ts'
|
|
30
|
-
import
|
|
31
|
+
import { launcherOf } from './launcherOptions.ts'
|
|
31
32
|
import { type Launch, launcherPage } from './launcherPage.ts'
|
|
32
33
|
import { installMenu, menuBar, type NativeItem } from './nativeMenu.ts'
|
|
33
34
|
import { randomToken } from './randomToken.ts'
|
|
34
|
-
import { type Component,
|
|
35
|
+
import { type Component, renderDocument } from './render.ts'
|
|
35
36
|
import { LISTENING } from './requestScope.ts'
|
|
36
37
|
import { runCompiled } from './runCompiled.ts'
|
|
37
38
|
import { type BuildParts, builtSources } from './serveBuild.ts'
|
|
38
39
|
|
|
39
|
-
/** What the launcher did last, and what its forms held, kept across launches. 38.
|
|
40
|
+
/** What the launcher did last, and what its forms held, kept across launches. 38.73. */
|
|
40
41
|
type Remembered = {
|
|
41
42
|
last: { start: Record<string, string> } | { connect: string } | null
|
|
42
43
|
values: Record<string, string>
|
|
@@ -50,15 +51,22 @@ type Failure = {
|
|
|
50
51
|
issues: Record<string, string[]>
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
/** What `abide bundle` read
|
|
54
|
+
/** What `abide bundle` read of the launcher's files, carried in the executable. */
|
|
54
55
|
export type Desktop = {
|
|
55
|
-
|
|
56
|
-
/** 38.83 — `src/bundle/launch.abide`, where the app has one. */
|
|
56
|
+
/** 38.80 — `src/launcher.abide`, where the app has one: its `launcher`, and its page. */
|
|
57
57
|
launch:
|
|
58
|
-
| (() => Promise<{
|
|
58
|
+
| (() => Promise<{
|
|
59
|
+
default: (props: Launch) => Component
|
|
60
|
+
launcher?: unknown
|
|
61
|
+
}>)
|
|
59
62
|
| undefined
|
|
60
|
-
/**
|
|
61
|
-
|
|
63
|
+
/** 38.82 — whether that file has markup of its own, which then stands in for the built-in page. */
|
|
64
|
+
custom: boolean
|
|
65
|
+
/** The document the launch page renders into, its stylesheet already in its head (38.84). */
|
|
66
|
+
document: string
|
|
67
|
+
/** 38.101 — the app's icon as a data URL, and the accent taken from it. */
|
|
68
|
+
icon: string | undefined
|
|
69
|
+
accent: string | undefined
|
|
62
70
|
}
|
|
63
71
|
|
|
64
72
|
const LOOPBACK = '127.0.0.1'
|
|
@@ -79,14 +87,24 @@ export async function runDesktop(
|
|
|
79
87
|
async function launch(
|
|
80
88
|
origin: AppOrigin,
|
|
81
89
|
load: () => ReturnType<typeof builtSources>,
|
|
82
|
-
{
|
|
90
|
+
{ launch: launchModule, custom, document, icon, accent }: Desktop,
|
|
83
91
|
): Promise<void> {
|
|
84
92
|
installServer()
|
|
85
93
|
APP_PACKAGE.current = origin.package
|
|
86
94
|
// 37.1 — imported for what it files, so the start form reads `onConfig`.
|
|
87
95
|
await origin.hooks?.()
|
|
88
|
-
|
|
89
|
-
|
|
96
|
+
// 34.32 — the `launcher` export, read off its module as the app launches. 38.85 — one that fails
|
|
97
|
+
// to load leaves the built-in page, with its defaults.
|
|
98
|
+
const launcherModule = await launchModule?.().catch((thrown: unknown) => {
|
|
99
|
+
reportUnexpected(thrown)
|
|
100
|
+
return undefined
|
|
101
|
+
})
|
|
102
|
+
const options = launcherOf(launcherModule?.launcher)
|
|
103
|
+
// 38.81 — a `launcher` the checker would have refused, written where nothing checked it.
|
|
104
|
+
if (typeof options === 'string')
|
|
105
|
+
throw new Error(`abide: ${options}. RULEBOOK 38.81.`)
|
|
106
|
+
const launchPage = custom ? launcherModule : undefined
|
|
107
|
+
const appName = executableName(origin.package.name)
|
|
90
108
|
const directory = dataDirectory(origin.package.name ?? 'app')
|
|
91
109
|
const stateFile = `${directory}/desktop.json`
|
|
92
110
|
const remembered: Remembered = {
|
|
@@ -149,21 +167,24 @@ async function launch(
|
|
|
149
167
|
)
|
|
150
168
|
return connected === undefined ? onwards() : page('connect')
|
|
151
169
|
}
|
|
170
|
+
// The Connect… menu item asks for the page with its connect form open.
|
|
152
171
|
return page(
|
|
153
172
|
url.searchParams.get('focus') === 'connect'
|
|
154
173
|
? 'connect'
|
|
155
|
-
:
|
|
174
|
+
: undefined,
|
|
156
175
|
)
|
|
157
176
|
},
|
|
158
177
|
})
|
|
159
178
|
const base = `${launcher.url.origin}/${token}/`
|
|
160
|
-
// 38.
|
|
179
|
+
// 38.71 — the answer to a start or a connect that took: the app the window now shows.
|
|
161
180
|
const onwards = (): Response =>
|
|
162
181
|
new Response(null, {
|
|
163
182
|
status: 303,
|
|
164
183
|
headers: { location: current?.url ?? base },
|
|
165
184
|
})
|
|
166
|
-
const page = async (
|
|
185
|
+
const page = async (
|
|
186
|
+
focus: 'start' | 'connect' | undefined,
|
|
187
|
+
): Promise<Response> => {
|
|
167
188
|
const shown = failure
|
|
168
189
|
failure = undefined
|
|
169
190
|
const props: Launch = {
|
|
@@ -173,17 +194,21 @@ async function launch(
|
|
|
173
194
|
fields: configFields(derived()),
|
|
174
195
|
url: remembered.url,
|
|
175
196
|
failure: shown,
|
|
176
|
-
focus:
|
|
197
|
+
focus:
|
|
198
|
+
shown?.form ??
|
|
199
|
+
(focus === 'connect' && options.connect ? focus : undefined),
|
|
200
|
+
icon,
|
|
201
|
+
accent,
|
|
177
202
|
}
|
|
178
203
|
const headers = { 'content-type': 'text/html; charset=utf-8' }
|
|
179
204
|
if (launchPage !== undefined)
|
|
180
205
|
try {
|
|
181
206
|
return new Response(
|
|
182
|
-
await
|
|
207
|
+
await renderDocument(launchPage.default(props), document),
|
|
183
208
|
{ headers },
|
|
184
209
|
)
|
|
185
210
|
} catch (thrown) {
|
|
186
|
-
// 38.
|
|
211
|
+
// 38.85 — the built-in page stands in for one that failed.
|
|
187
212
|
reportUnexpected(thrown)
|
|
188
213
|
}
|
|
189
214
|
return new Response(launcherPage(props), { headers })
|
|
@@ -196,7 +221,7 @@ async function launch(
|
|
|
196
221
|
await leaving.app.stop().catch(reportUnexpected)
|
|
197
222
|
}
|
|
198
223
|
|
|
199
|
-
// 38.
|
|
224
|
+
// 38.72 — the form's values are the environment the app is booted under, so 27.8 coerces them
|
|
200
225
|
// and 27.7's schema refuses them as it would any other.
|
|
201
226
|
async function start(
|
|
202
227
|
values: Record<string, string>,
|
|
@@ -215,7 +240,7 @@ async function launch(
|
|
|
215
240
|
}
|
|
216
241
|
try {
|
|
217
242
|
await app
|
|
218
|
-
// 38.
|
|
243
|
+
// 38.75.
|
|
219
244
|
.listen({ hostname: LOOPBACK, port: remembered.port })
|
|
220
245
|
// The port the last launch served on, so the app's origin — and its storage with
|
|
221
246
|
// it — is the one it had; any free one where that is taken.
|
|
@@ -296,7 +321,7 @@ async function launch(
|
|
|
296
321
|
types: 'Q@:@',
|
|
297
322
|
args: [FFIType.ptr],
|
|
298
323
|
returns: FFIType.u64,
|
|
299
|
-
// NSTerminateCancel: 38.
|
|
324
|
+
// NSTerminateCancel: 38.76 — the app is stopped first, and the process ends after.
|
|
300
325
|
run: () => {
|
|
301
326
|
quit()
|
|
302
327
|
return 0
|
|
@@ -382,20 +407,20 @@ async function launch(
|
|
|
382
407
|
),
|
|
383
408
|
null,
|
|
384
409
|
)
|
|
385
|
-
// 38.
|
|
410
|
+
// 38.88 — THE MENU BAR IS THE PAGE'S: the defaults until the page the window loads tells it
|
|
386
411
|
// what its route exports, and again after every navigation it makes.
|
|
387
412
|
const showMenu = (told: NativeItem[]): void =>
|
|
388
413
|
installMenu(menuBar(appName, options.connect, told), (item) => {
|
|
389
414
|
if (item.role === 'connect')
|
|
390
415
|
return navigate(`${base}?focus=connect`)
|
|
391
|
-
// 38.
|
|
416
|
+
// 38.74.
|
|
392
417
|
if (item.role === 'disconnect') {
|
|
393
418
|
remembered.last = null
|
|
394
419
|
void remember()
|
|
395
420
|
return void disconnect().then(() => navigate(base))
|
|
396
421
|
}
|
|
397
422
|
if (item.role === 'reload') return void send(view, 'reload')
|
|
398
|
-
// 38.
|
|
423
|
+
// 38.90, 38.91 — the page that numbered the item does what it means.
|
|
399
424
|
if (item.id !== undefined)
|
|
400
425
|
send(
|
|
401
426
|
view,
|
|
@@ -433,7 +458,7 @@ async function launch(
|
|
|
433
458
|
nsString('abideMenu'),
|
|
434
459
|
)
|
|
435
460
|
const navigate = (address: string): void => {
|
|
436
|
-
// 38.
|
|
461
|
+
// 38.92.
|
|
437
462
|
showMenu([])
|
|
438
463
|
send(
|
|
439
464
|
view,
|
|
@@ -485,7 +510,7 @@ async function launch(
|
|
|
485
510
|
send(window, 'setTitle:', nsString(title))
|
|
486
511
|
}, DRAIN_MILLISECONDS)
|
|
487
512
|
|
|
488
|
-
// 38.
|
|
513
|
+
// 38.73 — WHAT IT DID LAST, done again.
|
|
489
514
|
const last = remembered.last
|
|
490
515
|
if (options.start && last !== null && 'start' in last)
|
|
491
516
|
await start(last.start)
|
package/src/server/serveBuild.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// 38.6 and 38.
|
|
1
|
+
// 38.6 and 38.10 — `abide start` and a compiled app: the built app, over http. The request path is
|
|
2
2
|
// `answerRequest`'s, shared with `abide dev`; what this module is, is the SUPPLIER — where each part
|
|
3
3
|
// comes from when the parts are what `abide build` produced.
|
|
4
4
|
//
|
|
@@ -8,19 +8,22 @@
|
|
|
8
8
|
|
|
9
9
|
import { CLIENT_ADDRESS } from '#shared/ADDRESSES.ts'
|
|
10
10
|
import {
|
|
11
|
+
type Compilation,
|
|
12
|
+
serveCompilation,
|
|
13
|
+
servedTable,
|
|
14
|
+
} from './abideModules.ts'
|
|
15
|
+
import {
|
|
16
|
+
type AppSources,
|
|
11
17
|
appSources,
|
|
12
|
-
type LoadedSources,
|
|
13
|
-
type ServerTable,
|
|
14
18
|
type SourceParts,
|
|
15
19
|
} from './answerRequest.ts'
|
|
16
|
-
import type { Mount } from './answerRpc.ts'
|
|
17
20
|
import {
|
|
18
21
|
CLIENT_DIRECTORY,
|
|
22
|
+
COMPILATION,
|
|
19
23
|
ENCODING_SUFFIX,
|
|
20
24
|
MANIFEST,
|
|
21
25
|
PUBLIC_DIRECTORY,
|
|
22
26
|
} from './CLIENT_BUILD.ts'
|
|
23
|
-
import { componentImports } from './componentImports.ts'
|
|
24
27
|
import { type App, type AppOrigin, bootApp } from './createApp.ts'
|
|
25
28
|
import { stopOnSignalOrFault } from './faultPolicy.ts'
|
|
26
29
|
import type { Manifest } from './manifestOf.ts'
|
|
@@ -30,13 +33,13 @@ import {
|
|
|
30
33
|
type Encoding,
|
|
31
34
|
negotiateEncoding,
|
|
32
35
|
} from './negotiateEncoding.ts'
|
|
33
|
-
import {
|
|
36
|
+
import { runBuild } from './runBuild.ts'
|
|
34
37
|
|
|
35
38
|
/**
|
|
36
39
|
* What `abide build` produced, as the parts an `App` is booted over.
|
|
37
40
|
*
|
|
38
41
|
* Read off disk by `abide start` (`loadBuild`), and out of the executable itself by a compiled app
|
|
39
|
-
* (38.
|
|
42
|
+
* (38.10). ONE SHAPE, so the two are answered by one path and differ only in where a byte is read
|
|
40
43
|
* from — a file is a PATH in both, and `Bun.file` reads the executable's own the same way it reads
|
|
41
44
|
* the disk's.
|
|
42
45
|
*/
|
|
@@ -53,7 +56,7 @@ export type BuildParts = Omit<SourceParts, 'client' | 'explained'> & {
|
|
|
53
56
|
*/
|
|
54
57
|
export async function serveApp(
|
|
55
58
|
origin: AppOrigin,
|
|
56
|
-
load: () => Promise<
|
|
59
|
+
load: () => Promise<AppSources>,
|
|
57
60
|
port: number | undefined,
|
|
58
61
|
): Promise<App> {
|
|
59
62
|
const app = await bootApp(origin, load)
|
|
@@ -64,63 +67,51 @@ export async function serveApp(
|
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
/**
|
|
67
|
-
*
|
|
70
|
+
* Serves the compilation `abide build` kept in `out` to this process's imports; `false` where there
|
|
71
|
+
* is none, because the app under `root` holds nothing to build.
|
|
68
72
|
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
73
|
+
* 38.6 — what `abide start` boots: no compiler is loaded, and every `.abide` the app imports is
|
|
74
|
+
* answered out of what the build compiled. 38.100 — AN APP NOBODY BUILT IS BUILT, by `build`, rather
|
|
75
|
+
* than refused, so every caller boots the same way whether or not a build came first. The CLI passes
|
|
76
|
+
* its own build, in-process; anything else spawns it.
|
|
71
77
|
*/
|
|
72
|
-
export function
|
|
78
|
+
export async function serveBuild(
|
|
73
79
|
root: string,
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const rpc = (await import(
|
|
83
|
-
Bun.pathToFileURL(`${directory}/rpc.ts`).href
|
|
84
|
-
)) as {
|
|
85
|
-
handlers: Mount[]
|
|
80
|
+
out: string,
|
|
81
|
+
build: (root: string, out: string) => Promise<unknown> = runBuild,
|
|
82
|
+
): Promise<boolean> {
|
|
83
|
+
const path = `${out}/${COMPILATION}`
|
|
84
|
+
if (!(await Bun.file(path).exists())) {
|
|
85
|
+
await build(root, out)
|
|
86
|
+
// A FRESH HANDLE: one taken before the build wrote the file reads it as empty.
|
|
87
|
+
if (!(await Bun.file(path).exists())) return false
|
|
86
88
|
}
|
|
87
|
-
|
|
89
|
+
serveCompilation(root, (await Bun.file(path).json()) as Compilation)
|
|
90
|
+
return true
|
|
88
91
|
}
|
|
89
92
|
|
|
90
|
-
/**
|
|
93
|
+
/**
|
|
94
|
+
* What `abide build` left on disk, as the sources an `App` is booted over — its compilation served
|
|
95
|
+
* already (`serveBuild`).
|
|
96
|
+
*/
|
|
91
97
|
export async function loadBuild(options: {
|
|
92
98
|
/**
|
|
93
|
-
* The app's source root — the directory
|
|
94
|
-
* shell is resolved against.
|
|
99
|
+
* The app's source root — the directory its pages sit under.
|
|
95
100
|
*/
|
|
96
101
|
root: string
|
|
97
102
|
/** Where `abide build` put its output. */
|
|
98
103
|
out: string
|
|
99
|
-
}): Promise<
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
// independent of each other.
|
|
106
|
-
//
|
|
107
|
-
// THE SHELL IS READ ONCE, at boot. `render`'s own note prices the per-render read at 98% of the
|
|
108
|
-
// op and leaves the caching to whatever server got written; this is that server. The manifest
|
|
109
|
-
// names the stylesheet only where the bundler collected one, so an app that imports none links
|
|
110
|
-
// none.
|
|
111
|
-
const [table, handlers, shell, manifest] = await Promise.all([
|
|
112
|
-
import(
|
|
113
|
-
Bun.pathToFileURL(`${options.out}/server.ts`).href
|
|
114
|
-
) as Promise<ServerTable>,
|
|
115
|
-
handlersIn(options.out),
|
|
116
|
-
shellUnder(options.root),
|
|
104
|
+
}): Promise<AppSources> {
|
|
105
|
+
// THE BOOT READS OVERLAP: the tables and the manifest are independent of each other. The
|
|
106
|
+
// manifest names the stylesheet only where the bundler collected one, so an app that imports
|
|
107
|
+
// none links none.
|
|
108
|
+
const [table, manifest] = await Promise.all([
|
|
109
|
+
servedTable(options.root),
|
|
117
110
|
Bun.file(`${options.out}/${MANIFEST}`).json() as Promise<Manifest>,
|
|
118
111
|
])
|
|
119
112
|
return builtSources({
|
|
120
113
|
table,
|
|
121
|
-
handlers,
|
|
122
|
-
handlerModule: sourceModuleLoader(options.root, options.out),
|
|
123
|
-
shell,
|
|
114
|
+
handlers: table.handlers,
|
|
124
115
|
manifest,
|
|
125
116
|
client: pathsUnder(`${options.out}/${CLIENT_DIRECTORY}`),
|
|
126
117
|
published: pathsUnder(`${options.out}/${PUBLIC_DIRECTORY}`),
|
|
@@ -136,9 +127,9 @@ export function pathsUnder(directory: string): Map<string, string> {
|
|
|
136
127
|
}
|
|
137
128
|
|
|
138
129
|
/** The sources an `App` is booted over, out of the parts `abide build` produced. */
|
|
139
|
-
export function builtSources(parts: BuildParts): Promise<
|
|
130
|
+
export function builtSources(parts: BuildParts): Promise<AppSources> {
|
|
140
131
|
// THE BUNDLE, ENUMERATED RATHER THAN RESOLVED. A request names a file in this set or it names
|
|
141
|
-
// nothing — there is no path to
|
|
132
|
+
// nothing — there is no path to normalize, so `..` is not a case that has to be got right,
|
|
142
133
|
// and what is servable is exactly what the build produced.
|
|
143
134
|
//
|
|
144
135
|
// THE PRECOMPRESSED COPIES ARE NOT ADDRESSES OF THEIR OWN. They are the same file in another
|
|
@@ -173,7 +164,7 @@ export function builtSources(parts: BuildParts): Promise<LoadedSources> {
|
|
|
173
164
|
'content-type': type,
|
|
174
165
|
vary: 'accept-encoding',
|
|
175
166
|
}
|
|
176
|
-
// 38.
|
|
167
|
+
// 38.29 — the precompressed copy where the request takes its encoding.
|
|
177
168
|
const encoding = negotiateEncoding(
|
|
178
169
|
request.headers.get('accept-encoding'),
|
|
179
170
|
encodings,
|