@abide/abide 0.117.2 → 0.119.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 +22 -0
- package/bin/abide.ts +74 -11
- package/docs/REGISTRY.md +18 -15
- package/docs/RULEBOOK.md +71 -10
- package/docs/abide.md +584 -274
- package/package.json +1 -1
- package/scaffold/AGENTS.md +1 -1
- package/scaffold/src/getGreeting.test.ts +2 -1
- package/scaffold/src/index.abide +5 -2
- package/scaffold/src/index.test.ts +2 -0
- package/scaffold/src/layout.abide +6 -6
- package/src/compiler/Lowering.ts +20 -2
- package/src/compiler/PositionTable.ts +1 -0
- package/src/compiler/Refusals.ts +1 -0
- package/src/compiler/TypeSession.ts +49 -13
- package/src/compiler/aliasedSymbol.ts +1 -1
- package/src/compiler/ambientReadsIn.ts +1 -0
- package/src/compiler/appLayout.ts +55 -3
- package/src/compiler/appMap.ts +15 -0
- package/src/compiler/argsDefaultsIn.ts +1 -0
- package/src/compiler/argsSchemaOf.ts +1 -0
- package/src/compiler/checkApp.ts +3 -1
- package/src/compiler/checkedShadow.ts +2 -1
- package/src/compiler/classifyRead.ts +1 -0
- package/src/compiler/classifyTemplate.ts +1 -0
- package/src/compiler/compileApp.ts +5 -3
- package/src/compiler/compiledEntry.ts +2 -1
- package/src/compiler/componentGraph.ts +1 -0
- package/src/compiler/declaredExports.ts +4 -2
- package/src/compiler/emitClient.ts +19 -14
- package/src/compiler/emitComponent.ts +1 -0
- package/src/compiler/emitSource.ts +2 -1
- package/src/compiler/formatAbide.ts +857 -0
- package/src/compiler/formatDiagnosis.ts +1 -0
- package/src/compiler/handlersUnder.ts +7 -3
- package/src/compiler/hookCalls.ts +1 -0
- package/src/compiler/lineOf.ts +17 -0
- package/src/compiler/matchersOf.ts +157 -0
- package/src/compiler/mountsOf.ts +5 -0
- package/src/compiler/paramFile.ts +125 -0
- package/src/compiler/parseAbide.ts +48 -28
- package/src/compiler/projectShadow.ts +11 -4
- package/src/compiler/reactiveOptions.ts +1 -0
- package/src/compiler/reactiveTypes.ts +2 -1
- package/src/compiler/readsIn.ts +3 -2
- package/src/compiler/renderMarkup.ts +3 -2
- package/src/compiler/resolverIn.ts +2 -0
- package/src/compiler/sameTemplate.ts +150 -0
- package/src/compiler/scaffold.ts +4 -11
- package/src/compiler/serveLanguage.ts +48 -21
- package/src/compiler/sharedModuleWrites.ts +2 -1
- package/src/compiler/sourceMapOf.ts +1 -0
- package/src/compiler/splitImports.ts +2 -0
- package/src/compiler/templateWarnings.ts +2 -2
- package/src/compiler/trackingWarnings.ts +1 -0
- package/src/compiler/writeDefaultProject.ts +5 -1
- package/src/server/BRIDGE_VERSION.ts +1 -1
- package/src/server/abideModules.ts +2 -0
- package/src/server/answerFailure.ts +1 -0
- package/src/server/answerRequest.ts +57 -19
- package/src/server/answerRpc.ts +6 -2
- package/src/server/answerSocket.ts +2 -1
- package/src/server/answerValue.ts +1 -0
- package/src/server/answerWorker.ts +1 -0
- package/src/server/appTree.ts +18 -9
- package/src/server/argsFor.ts +1 -0
- package/src/server/assistant.ts +2 -1
- package/src/server/banner.ts +2 -0
- package/src/server/bridgeRelay.ts +1 -0
- package/src/server/callerOf.ts +1 -0
- package/src/server/claudeApi.ts +1 -0
- package/src/server/claudeCode.ts +1 -0
- package/src/server/clientBundle.ts +1 -0
- package/src/server/coerceArgs.ts +1 -2
- package/src/server/commands.ts +9 -0
- package/src/server/compressAnswer.ts +2 -1
- package/src/server/config.ts +2 -0
- package/src/server/createApp.ts +4 -2
- package/src/server/crossingOrigin.ts +1 -0
- package/src/server/csp.ts +1 -0
- package/src/server/deferredBuilds.ts +1 -0
- package/src/server/derivedArgs.ts +1 -0
- package/src/server/devWorker.ts +2 -1
- package/src/server/faceOf.ts +2 -7
- package/src/server/generatedSurfaces.ts +79 -7
- package/src/server/hooks.ts +1 -0
- package/src/server/iconAccent.ts +1 -1
- package/src/server/installServer.ts +1 -0
- package/src/server/installSourceMaps.ts +1 -0
- package/src/server/launcherPage.ts +2 -2
- package/src/server/manifestOf.ts +1 -0
- package/src/server/muxUpgrade.ts +1 -0
- package/src/server/nativeMenu.ts +2 -0
- package/src/server/placement.ts +12 -2
- package/src/server/principal.ts +2 -1
- package/src/server/remote.ts +7 -2
- package/src/server/render.ts +3 -3
- package/src/server/renderComponent.ts +1 -0
- package/src/server/reportHealth.ts +1 -0
- package/src/server/requestScope.ts +3 -1
- package/src/server/runDesktop.ts +3 -2
- package/src/server/seedBuffer.ts +1 -0
- package/src/server/serveDev.ts +3 -2
- package/src/server/shell.ts +2 -0
- package/src/server/streamEvent.ts +1 -0
- package/src/server/surfaceOf.ts +6 -1
- package/src/server/testBuild.ts +1 -0
- package/src/server/testMount.ts +1 -0
- package/src/server/trace.ts +2 -0
- package/src/server/withAbideSources.ts +1 -0
- package/src/shared/Attributes.ts +12 -8
- package/src/shared/cookies.ts +1 -1
- package/src/shared/escapeText.ts +1 -1
- package/src/shared/filledPath.ts +16 -10
- package/src/shared/index.ts +1 -5
- package/src/shared/jsonSchema.ts +1 -3
- package/src/shared/matchRoute.ts +16 -4
- package/src/shared/menuBridge.ts +1 -2
- package/src/shared/outbox.ts +1 -1
- package/src/shared/reactive/Keyed.ts +2 -2
- package/src/shared/reactive/Reactive.ts +12 -16
- package/src/shared/reactive/index.ts +3 -4
- package/src/shared/reactive/isReactive.ts +1 -1
- package/src/shared/reactive/scoped.ts +2 -2
- package/src/shared/reactive/share.ts +1 -1
- package/src/shared/reactive/watch.ts +4 -4
- package/src/shared/refuse.ts +1 -1
- package/src/shared/routePattern.ts +66 -14
- package/src/shared/rpc.ts +8 -11
- package/src/shared/url.ts +24 -7
- package/src/shared/validateJson.ts +1 -1
- package/src/ui/ArmRegion.ts +1 -0
- package/src/ui/Level.ts +1 -0
- package/src/ui/List.ts +1 -0
- package/src/ui/RawRun.ts +1 -0
- package/src/ui/Router.ts +1 -0
- package/src/ui/TryRegion.ts +1 -0
- package/src/ui/adoptWalk.ts +2 -1
- package/src/ui/bindElement.ts +1 -0
- package/src/ui/bindFiles.ts +1 -0
- package/src/ui/bindGroup.ts +1 -0
- package/src/ui/bindProperty.ts +1 -0
- package/src/ui/bindSpread.ts +1 -0
- package/src/ui/index.ts +1 -6
- package/src/ui/outboxQueue.ts +1 -1
- package/src/ui/parseMarkup.ts +2 -1
- package/src/ui/reconcile.ts +2 -1
- package/src/ui/reconcileHead.ts +1 -0
- package/src/ui/regions.ts +2 -1
- package/src/ui/registerWorker.ts +1 -0
- package/src/ui/rows.ts +1 -0
- package/src/ui/setMarkup.ts +1 -0
- package/src/ui/setText.ts +1 -0
- package/src/ui/socketWire.ts +4 -3
- package/src/ui/wire.ts +2 -1
- /package/scaffold/src/{getGreeting.ts → getGreeting.handler.ts} +0 -0
|
@@ -23,6 +23,7 @@ import { PATCH_SINKS } from '#shared/reactive/PATCH_SINKS.ts'
|
|
|
23
23
|
import { unowned } from '#shared/reactive/watch.ts'
|
|
24
24
|
import { refuse } from '#shared/refuse.ts'
|
|
25
25
|
import { rpcRequest } from '#shared/rpcRequest.ts'
|
|
26
|
+
|
|
26
27
|
import { handlerKey, type Mounted } from './answerRpc.ts'
|
|
27
28
|
import { argsFor } from './argsFor.ts'
|
|
28
29
|
import { positiveSetting } from './config.ts'
|
|
@@ -32,8 +33,8 @@ import { sendOrClose } from './muxUpgrade.ts'
|
|
|
32
33
|
import {
|
|
33
34
|
heldByApp,
|
|
34
35
|
inOpenScope,
|
|
35
|
-
type RequestScope,
|
|
36
36
|
releaseScope,
|
|
37
|
+
type RequestScope,
|
|
37
38
|
scopeFor,
|
|
38
39
|
} from './requestScope.ts'
|
|
39
40
|
import { EVENT_STREAM_OPENER, streamEvent } from './streamEvent.ts'
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
} from '#shared/OFFLINE_CACHES.ts'
|
|
20
20
|
import { PRINCIPAL_HEADER } from '#shared/PRINCIPAL_HEADER.ts'
|
|
21
21
|
import { REACHED_MESSAGE } from '#shared/REACHED_MESSAGE.ts'
|
|
22
|
+
|
|
22
23
|
import type { Manifest } from './manifestOf.ts'
|
|
23
24
|
|
|
24
25
|
// What `framingOf` reads as a framed stream (16.32), and a binary's bytes (16.34), which may be one —
|
package/src/server/appTree.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// 23.14 — WHERE AN APP'S ADDRESSES ARE, read off the tree in one walk. A file directly in a directory
|
|
2
2
|
// below the root is an address — a page, a layout, an error page or a handler file — and nothing
|
|
3
|
-
// else is there but its tests (23.22); a fence is never one (23.15): `public` holds files answered as
|
|
3
|
+
// else is there but its tests and the param files its segments name (23.22, 23.24); a fence is never one (23.15): `public` holds files answered as
|
|
4
4
|
// authored at the path of the directories above it, and `lib` holds the rest, a server file among it
|
|
5
5
|
// (23.23). So listing a directory lists its routes.
|
|
6
6
|
//
|
|
@@ -13,17 +13,21 @@
|
|
|
13
13
|
// can drop them.
|
|
14
14
|
|
|
15
15
|
import { type Dirent, existsSync, readdirSync } from 'node:fs' // bun has no directory listing or sync existence check of its own
|
|
16
|
+
|
|
16
17
|
import type { Refusals } from '#compiler/Refusals.ts'
|
|
17
18
|
import { ABIDE_ADDRESS } from '#shared/ADDRESSES.ts'
|
|
18
19
|
import {
|
|
19
20
|
PUBLIC_DIRECTORY,
|
|
20
21
|
RESERVED_DIRECTORIES,
|
|
21
22
|
} from '#shared/RESERVED_DIRECTORIES.ts'
|
|
23
|
+
|
|
22
24
|
import {
|
|
23
25
|
DIRECTORY_FILES,
|
|
26
|
+
isBenchFile,
|
|
24
27
|
isDeclarationFile,
|
|
28
|
+
isHandlerFile,
|
|
29
|
+
isParamFile,
|
|
25
30
|
isServerFile,
|
|
26
|
-
isBenchFile,
|
|
27
31
|
isTestFile,
|
|
28
32
|
placeOf,
|
|
29
33
|
routeOf,
|
|
@@ -36,6 +40,8 @@ type AppFiles = {
|
|
|
36
40
|
abide: string[]
|
|
37
41
|
/** Every handler file, in path order. */
|
|
38
42
|
handlers: string[]
|
|
43
|
+
/** 23.24 — every param file directly in an address directory, in path order. */
|
|
44
|
+
params: string[]
|
|
39
45
|
/** Every module under a `lib` directory, in path order — read for 37.13. */
|
|
40
46
|
modules: string[]
|
|
41
47
|
/** Every file under a `public` directory, to the address it is answered at below the mount. */
|
|
@@ -52,6 +58,7 @@ export function appFiles(root: string, refusals: Refusals): AppFiles {
|
|
|
52
58
|
const files: AppFiles = {
|
|
53
59
|
abide: [],
|
|
54
60
|
handlers: [],
|
|
61
|
+
params: [],
|
|
55
62
|
modules: [],
|
|
56
63
|
published: new Map(),
|
|
57
64
|
}
|
|
@@ -61,6 +68,7 @@ export function appFiles(root: string, refusals: Refusals): AppFiles {
|
|
|
61
68
|
walk(root, '', undefined, files, refusals, packaged)
|
|
62
69
|
files.abide.sort()
|
|
63
70
|
files.handlers.sort()
|
|
71
|
+
files.params.sort()
|
|
64
72
|
files.modules.sort()
|
|
65
73
|
return files
|
|
66
74
|
}
|
|
@@ -126,13 +134,17 @@ function walk(
|
|
|
126
134
|
isDeclarationFile(path)
|
|
127
135
|
)
|
|
128
136
|
continue
|
|
129
|
-
if (
|
|
137
|
+
if (isParamFile(path)) {
|
|
138
|
+
files.params.push(path)
|
|
139
|
+
continue
|
|
140
|
+
}
|
|
141
|
+
if (!abide && !isHandlerFile(path)) {
|
|
130
142
|
if (packaged && relative === '' && !path.endsWith('.ts'))
|
|
131
143
|
continue
|
|
132
144
|
refusals.at(
|
|
133
145
|
path,
|
|
134
146
|
new Error(
|
|
135
|
-
`abide: ${path} is directly in an address directory, which holds pages, layouts, error pages, handler files, test files, bench files and declaration files alone. Move it into a lib directory, beside it or in any directory above it. RULEBOOK 23.22.`,
|
|
147
|
+
`abide: ${path} is directly in an address directory, which holds pages, layouts, error pages, handler files, param files, test files, bench files and declaration files alone. ${path.endsWith('.ts') ? 'Name a handler file <name>.handler.ts, or move anything else' : 'Move it'} into a lib directory, beside it or in any directory above it. RULEBOOK 23.22.`,
|
|
136
148
|
),
|
|
137
149
|
)
|
|
138
150
|
continue
|
|
@@ -211,8 +223,7 @@ export function holdsApp(root: string): boolean {
|
|
|
211
223
|
return !appSourcesUnder(root, '').next().done
|
|
212
224
|
}
|
|
213
225
|
|
|
214
|
-
// Every `.abide` under `directory`, and every handler file
|
|
215
|
-
// no server file (23.23).
|
|
226
|
+
// Every `.abide` under `directory`, and every handler file whose place is an address.
|
|
216
227
|
function* appSourcesUnder(
|
|
217
228
|
directory: string,
|
|
218
229
|
relative: string,
|
|
@@ -230,9 +241,7 @@ function* appSourcesUnder(
|
|
|
230
241
|
yield* appSourcesUnder(`${directory}/${entry.name}`, `${path}/`)
|
|
231
242
|
else if (
|
|
232
243
|
path.endsWith('.abide') ||
|
|
233
|
-
(
|
|
234
|
-
!isServerFile(path) &&
|
|
235
|
-
placeOf(path) === 'address')
|
|
244
|
+
(isHandlerFile(path) && placeOf(path) === 'address')
|
|
236
245
|
)
|
|
237
246
|
yield path
|
|
238
247
|
}
|
package/src/server/argsFor.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { DERIVED_ARGS } from '#shared/DERIVED_ARGS.ts'
|
|
6
6
|
import { normalized } from '#shared/reactive/argsContract.ts'
|
|
7
7
|
import { validationError } from '#shared/refuse.ts'
|
|
8
|
+
|
|
8
9
|
import type { Mounted } from './answerRpc.ts'
|
|
9
10
|
import { coerceArgs } from './coerceArgs.ts'
|
|
10
11
|
|
package/src/server/assistant.ts
CHANGED
|
@@ -12,8 +12,9 @@
|
|
|
12
12
|
|
|
13
13
|
import { namedLogger } from '#shared/log.ts'
|
|
14
14
|
import { refuse } from '#shared/refuse.ts'
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
import { type McpReply, McpSurface } from './generatedSurfaces.ts'
|
|
17
|
+
import { IMAGE_TYPES } from './IMAGE_TYPES.ts'
|
|
17
18
|
import { request, within } from './requestScope.ts'
|
|
18
19
|
|
|
19
20
|
/** A piece of a turn: words, or an image as base64 with its type. */
|
package/src/server/banner.ts
CHANGED
package/src/server/callerOf.ts
CHANGED
package/src/server/claudeApi.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { framedStream } from '#shared/framing.ts'
|
|
10
10
|
import { refuse } from '#shared/refuse.ts'
|
|
11
|
+
|
|
11
12
|
import { blocksOf, type Provider, textOf } from './assistant.ts'
|
|
12
13
|
|
|
13
14
|
/** A Messages API request body, less what abide writes, with the client's key and origin. */
|
package/src/server/claudeCode.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// long a browser may keep it.
|
|
8
8
|
|
|
9
9
|
import { CLIENT_ADDRESS } from '#shared/ADDRESSES.ts'
|
|
10
|
+
|
|
10
11
|
import { abideModules, type Compilation, tablePath } from './abideModules.ts'
|
|
11
12
|
import { appPlugins } from './appPlugins.ts'
|
|
12
13
|
import { CLIENT_ENTRY } from './CLIENT_BUILD.ts'
|
package/src/server/coerceArgs.ts
CHANGED
|
@@ -19,8 +19,7 @@ export type Document = {
|
|
|
19
19
|
/** The document a handler's `args` schema declares, or `undefined`. */
|
|
20
20
|
export function argsDocumentOf(handler: Gated<unknown>): Document | undefined {
|
|
21
21
|
const gate = gateOf(handler) as
|
|
22
|
-
|
|
23
|
-
| undefined
|
|
22
|
+
{ '~standard'?: { jsonSchema?: { input?: () => unknown } } } | undefined
|
|
24
23
|
const document = gate?.['~standard']?.jsonSchema?.input?.()
|
|
25
24
|
return document !== null && typeof document === 'object'
|
|
26
25
|
? (document as Document)
|
package/src/server/commands.ts
CHANGED
|
@@ -5,8 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
import { resolve } from 'node:path' // bun exposes no path helpers of its own
|
|
7
7
|
import { parseArgs } from 'node:util' // bun exposes no argv parser of its own yet
|
|
8
|
+
|
|
8
9
|
import { MCP_ADDRESS, OPENAPI_ADDRESS } from '#shared/ADDRESSES.ts'
|
|
9
10
|
import { IN_PROCESS_ORIGIN } from '#shared/IN_PROCESS_ORIGIN.ts'
|
|
11
|
+
|
|
10
12
|
import { banner } from './banner.ts'
|
|
11
13
|
import { type App, type AppHandle, enterApp } from './createApp.ts'
|
|
12
14
|
import { stopOnSignalOrFault } from './faultPolicy.ts'
|
|
@@ -32,6 +34,7 @@ type SourceCommands = Record<
|
|
|
32
34
|
| 'dev'
|
|
33
35
|
| 'build'
|
|
34
36
|
| 'check'
|
|
37
|
+
| 'format'
|
|
35
38
|
| 'routes'
|
|
36
39
|
| 'compile'
|
|
37
40
|
| 'bundle'
|
|
@@ -194,6 +197,11 @@ function commandsOf(host: Host): Row[] {
|
|
|
194
197
|
'type-check the templates and the TypeScript, on the line you wrote',
|
|
195
198
|
'check',
|
|
196
199
|
),
|
|
200
|
+
fromSource(
|
|
201
|
+
'format [--check] [dir…]',
|
|
202
|
+
'format every .abide — its code by bun fmt, its markup by its nesting',
|
|
203
|
+
'format',
|
|
204
|
+
),
|
|
197
205
|
fromSource(
|
|
198
206
|
'routes [--json]',
|
|
199
207
|
'every address the app answers, its file, and where each hook is filed',
|
|
@@ -288,6 +296,7 @@ function parseFlags(argv: string[]) {
|
|
|
288
296
|
target: { type: 'string' },
|
|
289
297
|
platforms: { type: 'string' },
|
|
290
298
|
json: { type: 'boolean' },
|
|
299
|
+
check: { type: 'boolean' },
|
|
291
300
|
help: { type: 'boolean', short: 'h' },
|
|
292
301
|
version: { type: 'boolean', short: 'v' },
|
|
293
302
|
},
|
|
@@ -10,9 +10,10 @@
|
|
|
10
10
|
// BUN'S GZIP parts from zlib's past ~130 KB, which only the off-loop lane reaches — so that lane takes
|
|
11
11
|
// zlib's, the loop keeps bun's, and the two make the same bytes.
|
|
12
12
|
import { brotliCompress, brotliCompressSync, constants, gzip } from 'node:zlib' // bun has no brotli, and no compression off the loop
|
|
13
|
+
|
|
13
14
|
import {
|
|
14
|
-
ENCODINGS,
|
|
15
15
|
type Encoding,
|
|
16
|
+
ENCODINGS,
|
|
16
17
|
negotiateEncoding,
|
|
17
18
|
} from './negotiateEncoding.ts'
|
|
18
19
|
|
package/src/server/config.ts
CHANGED
|
@@ -5,11 +5,13 @@
|
|
|
5
5
|
// and a throw out of `onConfig` is the value's standing error, which a read throws (27.1).
|
|
6
6
|
|
|
7
7
|
import { homedir } from 'node:os' // bun exposes no home directory of its own
|
|
8
|
+
|
|
8
9
|
import { isRecord } from '#shared/isRecord.ts'
|
|
9
10
|
import { numberFromText } from '#shared/numberFromText.ts'
|
|
10
11
|
import { reactive } from '#shared/reactive/index.ts'
|
|
11
12
|
import { validationError } from '#shared/refuse.ts'
|
|
12
13
|
import { runSchema } from '#shared/Schema.ts'
|
|
14
|
+
|
|
13
15
|
import { appDirectories } from './appDirectories.ts'
|
|
14
16
|
import { type Env, HOOKS, inOrder } from './hooks.ts'
|
|
15
17
|
import { withoutTrailingSlash } from './withoutTrailingSlash.ts'
|
package/src/server/createApp.ts
CHANGED
|
@@ -5,17 +5,19 @@
|
|
|
5
5
|
|
|
6
6
|
import { existsSync } from 'node:fs' // bun exposes no sync existence check of its own
|
|
7
7
|
import { resolve } from 'node:path' // bun exposes no path helpers of its own
|
|
8
|
+
|
|
8
9
|
import { FAILURE_STATUS_TEXT } from '#shared/FAILURE_STATUS_TEXT.ts'
|
|
9
10
|
import { framingOf } from '#shared/framing.ts'
|
|
10
11
|
import { IN_PROCESS_ORIGIN } from '#shared/IN_PROCESS_ORIGIN.ts'
|
|
11
|
-
import { LONGEST_DELAY } from '#shared/LONGEST_DELAY.ts'
|
|
12
12
|
import { namedLogger } from '#shared/log.ts'
|
|
13
|
+
import { LONGEST_DELAY } from '#shared/LONGEST_DELAY.ts'
|
|
13
14
|
import { compose } from '#shared/Middleware.ts'
|
|
14
15
|
import { MOUNT, unmounted } from '#shared/mount.ts'
|
|
15
16
|
import { PRINCIPAL_HEADER } from '#shared/PRINCIPAL_HEADER.ts'
|
|
16
17
|
import { RPC_SERVER } from '#shared/RPC_SERVER.ts'
|
|
18
|
+
|
|
17
19
|
import { servedTable } from './abideModules.ts'
|
|
18
|
-
import { type AppSources
|
|
20
|
+
import { answerRequest, type AppSources } from './answerRequest.ts'
|
|
19
21
|
import type { Mount } from './answerRpc.ts'
|
|
20
22
|
import { Mux, type MuxConnection } from './answerSocket.ts'
|
|
21
23
|
import { appDirectories } from './appDirectories.ts'
|
package/src/server/csp.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// rung writing a document's header — so the two agree, and an answer that is not a document mints none.
|
|
7
7
|
|
|
8
8
|
import type { Middleware } from '#shared/Middleware.ts'
|
|
9
|
+
|
|
9
10
|
import { randomToken } from './randomToken.ts'
|
|
10
11
|
import { EARLY_CALL_HASH } from './render.ts'
|
|
11
12
|
import { within } from './requestScope.ts'
|
|
@@ -3,6 +3,7 @@ import type { JsonValue } from '#shared/JsonValue.ts'
|
|
|
3
3
|
import type { Gated } from '#shared/reactive/argsContract.ts'
|
|
4
4
|
import type { HeldToAnnotation } from '#shared/rpc.ts'
|
|
5
5
|
import { validateJson } from '#shared/validateJson.ts'
|
|
6
|
+
|
|
6
7
|
import { argsDocumentOf } from './coerceArgs.ts'
|
|
7
8
|
|
|
8
9
|
/**
|
package/src/server/devWorker.ts
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
import { DEV_ADDRESS } from '#shared/ADDRESSES.ts'
|
|
22
22
|
import { escapeText } from '#shared/escapeText.ts'
|
|
23
|
+
|
|
23
24
|
import {
|
|
24
25
|
type Compilation,
|
|
25
26
|
serveCompilation,
|
|
@@ -34,7 +35,7 @@ import {
|
|
|
34
35
|
clientBundle,
|
|
35
36
|
type ServedFile,
|
|
36
37
|
} from './clientBundle.ts'
|
|
37
|
-
import { type BootedApp,
|
|
38
|
+
import { bootApp, type BootedApp, originUnder } from './createApp.ts'
|
|
38
39
|
import { keepServing } from './faultPolicy.ts'
|
|
39
40
|
import { type Manifest, NO_MANIFEST } from './manifestOf.ts'
|
|
40
41
|
import { admitsMux, muxSocketOptions } from './muxUpgrade.ts'
|
package/src/server/faceOf.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// specifier, an `onLoad` for a path), and this decides what the answer is.
|
|
5
5
|
|
|
6
6
|
import type { JsonValue } from '#shared/JsonValue.ts'
|
|
7
|
+
|
|
7
8
|
import { HANDLER_SUFFIX, SERVER_QUERY } from './MODULE_QUERIES.ts'
|
|
8
9
|
|
|
9
10
|
// A VIRTUAL FACE'S PATH: its file's, with a suffix that is not a query. Both registries key a module
|
|
@@ -38,13 +39,7 @@ export type Face = { path: string; namespace: string }
|
|
|
38
39
|
* module (`?server`), a `.abide` named bare, or a module that may be a handler file.
|
|
39
40
|
*/
|
|
40
41
|
export type Asked =
|
|
41
|
-
| '
|
|
42
|
-
| 'style'
|
|
43
|
-
| 'component'
|
|
44
|
-
| 'client'
|
|
45
|
-
| 'server'
|
|
46
|
-
| 'abide'
|
|
47
|
-
| 'handler'
|
|
42
|
+
'text' | 'style' | 'component' | 'client' | 'server' | 'abide' | 'handler'
|
|
48
43
|
|
|
49
44
|
/**
|
|
50
45
|
* One handler file, as `Compilation.handlers` holds it — and 19.9's schema its default's annotation
|
|
@@ -18,8 +18,9 @@ import { essenceOf } from '#shared/framing.ts'
|
|
|
18
18
|
import { namedLogger } from '#shared/log.ts'
|
|
19
19
|
import { mounted } from '#shared/mount.ts'
|
|
20
20
|
import { type Reactive, reactive } from '#shared/reactive/index.ts'
|
|
21
|
-
import { parseRoutePattern } from '#shared/routePattern.ts'
|
|
21
|
+
import { parseRoutePattern, type Segment } from '#shared/routePattern.ts'
|
|
22
22
|
import { argsInURL, rpcRequest } from '#shared/rpcRequest.ts'
|
|
23
|
+
|
|
23
24
|
import { answered } from './answerFailure.ts'
|
|
24
25
|
import { bodyWithin, type Mounted } from './answerRpc.ts'
|
|
25
26
|
import type { ToolAnswer, ToolDefinition } from './assistant.ts'
|
|
@@ -134,13 +135,22 @@ function openApiOf(handlers: Map<string, Mounted>): {
|
|
|
134
135
|
for (const segment of parseRoutePattern(each.address)) {
|
|
135
136
|
if (segment.kind === 'static') continue
|
|
136
137
|
inPath.add(segment.name)
|
|
138
|
+
const declared = schema?.properties?.[segment.name] ?? {
|
|
139
|
+
type: 'string',
|
|
140
|
+
}
|
|
141
|
+
// 20.23 — and what the segment takes, save a rest's: its value is the parts joined,
|
|
142
|
+
// which one part's pattern does not describe.
|
|
137
143
|
const parameter: Record<string, unknown> = {
|
|
138
144
|
name: segment.name,
|
|
139
145
|
in: 'path',
|
|
140
146
|
required: true,
|
|
141
|
-
schema:
|
|
142
|
-
|
|
143
|
-
|
|
147
|
+
schema:
|
|
148
|
+
segment.kind === 'rest'
|
|
149
|
+
? declared
|
|
150
|
+
: patterned(
|
|
151
|
+
declared,
|
|
152
|
+
patternOf(segment, each.matchers),
|
|
153
|
+
),
|
|
144
154
|
}
|
|
145
155
|
if (segment.kind === 'optional')
|
|
146
156
|
parameter.description = 'May be left out, with its segment.'
|
|
@@ -172,8 +182,11 @@ function openApiOf(handlers: Map<string, Mounted>): {
|
|
|
172
182
|
},
|
|
173
183
|
},
|
|
174
184
|
}
|
|
175
|
-
// OpenAPI spells a parameter `{id}` where a route spells it `[id]
|
|
176
|
-
const path = each.address.replace(
|
|
185
|
+
// OpenAPI spells a parameter `{id}` where a route spells it `[id]`, and names no matcher.
|
|
186
|
+
const path = each.address.replace(
|
|
187
|
+
/\[+(?:\.\.\.)?([^\]=]+)(?:=[^\]]*)?\]+/g,
|
|
188
|
+
'{$1}',
|
|
189
|
+
)
|
|
177
190
|
paths[path] ??= {}
|
|
178
191
|
;(paths[path] as Record<string, unknown>)[each.method.toLowerCase()] =
|
|
179
192
|
operation
|
|
@@ -291,7 +304,9 @@ export class McpSurface {
|
|
|
291
304
|
listing.push({
|
|
292
305
|
name: tool.name,
|
|
293
306
|
description: tool.description ?? '',
|
|
294
|
-
inputSchema: toolInput(
|
|
307
|
+
inputSchema: toolInput(
|
|
308
|
+
withPathPatterns(tool.schema, tool.address, tool.matchers),
|
|
309
|
+
),
|
|
295
310
|
// 20.14 — what the method promises: a `GET` is safe, and a `GET`, a `PUT` and a
|
|
296
311
|
// `DELETE` idempotent. Any other write may destroy, and nothing says it does not.
|
|
297
312
|
annotations: {
|
|
@@ -454,6 +469,63 @@ function logCall(
|
|
|
454
469
|
)
|
|
455
470
|
}
|
|
456
471
|
|
|
472
|
+
/** 20.23 — the anchored pattern a segment takes a part by: its matcher's, or 30.34's default. */
|
|
473
|
+
function patternOf(segment: Segment, matchers: Record<string, string>): string {
|
|
474
|
+
return segment.matcher === undefined
|
|
475
|
+
? PERIODLESS_PATTERN
|
|
476
|
+
: (matchers[segment.matcher] ?? PERIODLESS_PATTERN)
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const PERIODLESS_PATTERN = '^[^.]+$'
|
|
480
|
+
|
|
481
|
+
/** `declared` constrained to `pattern` too: beside a pattern it declares itself, not over it. */
|
|
482
|
+
function patterned(declared: unknown, pattern: string): unknown {
|
|
483
|
+
if (declared === null || typeof declared !== 'object') return { pattern }
|
|
484
|
+
return 'pattern' in declared
|
|
485
|
+
? { allOf: [declared, { pattern }] }
|
|
486
|
+
: { ...declared, pattern }
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* 20.23 — `schema` with each route parameter it declares constrained to what its segment takes, a
|
|
491
|
+
* rest's on each of its items; `schema` itself where the route has no parameter it declares.
|
|
492
|
+
*/
|
|
493
|
+
function withPathPatterns(
|
|
494
|
+
schema: unknown,
|
|
495
|
+
address: string,
|
|
496
|
+
matchers: Record<string, string>,
|
|
497
|
+
): unknown {
|
|
498
|
+
if (schema === null || typeof schema !== 'object') return schema
|
|
499
|
+
const properties = (schema as { properties?: Record<string, unknown> })
|
|
500
|
+
.properties
|
|
501
|
+
if (properties === undefined) return schema
|
|
502
|
+
const constrained: Record<string, unknown> = { ...properties }
|
|
503
|
+
let changed = false
|
|
504
|
+
for (const segment of parseRoutePattern(address)) {
|
|
505
|
+
if (segment.kind === 'static') continue
|
|
506
|
+
const declared = properties[segment.name]
|
|
507
|
+
if (declared === undefined) continue
|
|
508
|
+
const pattern = patternOf(segment, matchers)
|
|
509
|
+
constrained[segment.name] =
|
|
510
|
+
segment.kind === 'rest' &&
|
|
511
|
+
declared !== null &&
|
|
512
|
+
typeof declared === 'object' &&
|
|
513
|
+
'items' in declared
|
|
514
|
+
? {
|
|
515
|
+
...declared,
|
|
516
|
+
items: patterned(
|
|
517
|
+
(declared as { items: unknown }).items,
|
|
518
|
+
pattern,
|
|
519
|
+
),
|
|
520
|
+
}
|
|
521
|
+
: segment.kind === 'rest'
|
|
522
|
+
? declared
|
|
523
|
+
: patterned(declared, pattern)
|
|
524
|
+
changed = true
|
|
525
|
+
}
|
|
526
|
+
return changed ? { ...schema, properties: constrained } : schema
|
|
527
|
+
}
|
|
528
|
+
|
|
457
529
|
/**
|
|
458
530
|
* `schema` as a tool's `inputSchema`, its top-level `type` `object` whatever it declared there, or
|
|
459
531
|
* `undefined` where no value it admits is an object. 20.19, 20.20.
|
package/src/server/hooks.ts
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
type Segment,
|
|
22
22
|
} from '#shared/routePattern.ts'
|
|
23
23
|
import type { Schema } from '#shared/Schema.ts'
|
|
24
|
+
|
|
24
25
|
import { config } from './config.ts'
|
|
25
26
|
import type { LauncherOptions } from './launcherOptions.ts'
|
|
26
27
|
import { currentRequestScope } from './requestScope.ts'
|
package/src/server/iconAccent.ts
CHANGED
|
@@ -82,7 +82,7 @@ function decoded(
|
|
|
82
82
|
let channels = 0
|
|
83
83
|
const compressed: Uint8Array[] = []
|
|
84
84
|
let length = 0
|
|
85
|
-
for (let at = 8; at + 8 <= png.length;
|
|
85
|
+
for (let at = 8; at + 8 <= png.length;) {
|
|
86
86
|
const size = view.getUint32(at)
|
|
87
87
|
const type = String.fromCharCode(...png.subarray(at + 4, at + 8))
|
|
88
88
|
const body = png.subarray(at + 8, at + 8 + size)
|
|
@@ -14,6 +14,7 @@ import { MOUNT } from '#shared/mount.ts'
|
|
|
14
14
|
import { PRINCIPAL } from '#shared/principal.ts'
|
|
15
15
|
import { RPC_SERVER } from '#shared/RPC_SERVER.ts'
|
|
16
16
|
import { UNEXPECTED } from '#shared/UNEXPECTED.ts'
|
|
17
|
+
|
|
17
18
|
import { reachedInRender } from './answerRequest.ts'
|
|
18
19
|
import { environmentTimeout } from './answerRpc.ts'
|
|
19
20
|
import { broadcast, feedFromServed, swept } from './answerSocket.ts'
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// rebuild, and a test boots several apps in one process.
|
|
8
8
|
|
|
9
9
|
import { resolve } from 'node:path' // bun exposes no path helpers of its own
|
|
10
|
+
|
|
10
11
|
import { HANDLER_FACE } from './MODULE_QUERIES.ts'
|
|
11
12
|
import { decodeMappings, placeAt, type Segment } from './sourceMappings.ts'
|
|
12
13
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// asks something first, so a Start with no configuration to ask for has none and starts at once.
|
|
8
8
|
|
|
9
9
|
import { escapeAttribute, escapeText } from '#shared/escapeText.ts'
|
|
10
|
+
|
|
10
11
|
import type { ConfigField } from './configFields.ts'
|
|
11
12
|
import { inkOn } from './iconAccent.ts'
|
|
12
13
|
|
|
@@ -77,8 +78,7 @@ export function launcherPage(page: Launch): string {
|
|
|
77
78
|
// field shows them.
|
|
78
79
|
const failureLine = (
|
|
79
80
|
failure:
|
|
80
|
-
|
|
81
|
-
| undefined,
|
|
81
|
+
{ message: string; issues: Record<string, string[]> } | undefined,
|
|
82
82
|
): string => {
|
|
83
83
|
if (failure === undefined) return ''
|
|
84
84
|
let line = `<p class="failure" role="alert">${escapeText(failure.message)}</p>`
|
package/src/server/manifestOf.ts
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
// a preload of the same address is a second request line for bytes already on their way.
|
|
17
17
|
|
|
18
18
|
import { resolve } from 'node:path' // bun exposes no path helpers of its own
|
|
19
|
+
|
|
19
20
|
import { CLIENT_ENTRY } from './CLIENT_BUILD.ts'
|
|
20
21
|
import { VIRTUAL_DIRECTORY } from './VIRTUAL_DIRECTORY.ts'
|
|
21
22
|
|
package/src/server/muxUpgrade.ts
CHANGED
package/src/server/nativeMenu.ts
CHANGED
package/src/server/placement.ts
CHANGED
|
@@ -104,6 +104,16 @@ export function isServerFile(path: string): boolean {
|
|
|
104
104
|
|
|
105
105
|
const SERVER_FILE = /[^/]\.server\.[^./]+$/
|
|
106
106
|
|
|
107
|
+
/** 16.2 — whether `path` names a handler file, `<name>.handler.ts`, whose default export answers at its route. */
|
|
108
|
+
export function isHandlerFile(path: string): boolean {
|
|
109
|
+
return path.endsWith('.handler.ts')
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** 23.24 — whether `path` names a param file, `<NAME>.param.ts`, declaring the matcher `NAME`. */
|
|
113
|
+
export function isParamFile(path: string): boolean {
|
|
114
|
+
return path.endsWith('.param.ts')
|
|
115
|
+
}
|
|
116
|
+
|
|
107
117
|
/** Whether `path` names a test file, which is never an address nor a module the app runs. */
|
|
108
118
|
export function isTestFile(path: string): boolean {
|
|
109
119
|
return path.endsWith('.test.ts')
|
|
@@ -127,7 +137,7 @@ export function skipped(name: string): boolean {
|
|
|
127
137
|
/**
|
|
128
138
|
* The route a file answers at — its path below the root without its extension.
|
|
129
139
|
*
|
|
130
|
-
* 23.14 — `media/[id].abide` and `media/getGrid.ts` are `/media/[id]` and `/media/getGrid`; an
|
|
140
|
+
* 23.14 — `media/[id].abide` and `media/getGrid.handler.ts` are `/media/[id]` and `/media/getGrid`; an
|
|
131
141
|
* `index.abide`, a `layout.abide` and an `error.abide` are their directory's.
|
|
132
142
|
*/
|
|
133
143
|
export function routeOf(path: string): string {
|
|
@@ -138,7 +148,7 @@ export function routeOf(path: string): string {
|
|
|
138
148
|
return `/${parts.filter((part) => part !== '').join('/')}`
|
|
139
149
|
}
|
|
140
150
|
|
|
141
|
-
const EXTENSION = /\.(?:abide|ts)$/
|
|
151
|
+
const EXTENSION = /\.(?:abide|handler\.ts)$/
|
|
142
152
|
|
|
143
153
|
/** 23.14, 23.18 — the names whose route is their directory's, and so a route's wherever they stand. */
|
|
144
154
|
export const DIRECTORY_FILES = new Set([
|
package/src/server/principal.ts
CHANGED
|
@@ -9,14 +9,15 @@ import { cookies } from '#shared/cookies.ts'
|
|
|
9
9
|
import { isFailed } from '#shared/Failed.ts'
|
|
10
10
|
import { isRecord } from '#shared/isRecord.ts'
|
|
11
11
|
import { namedLogger } from '#shared/log.ts'
|
|
12
|
-
import { PRINCIPAL_HEADER } from '#shared/PRINCIPAL_HEADER.ts'
|
|
13
12
|
import {
|
|
14
13
|
type PRINCIPAL,
|
|
15
14
|
type Principal,
|
|
16
15
|
principalMembers,
|
|
17
16
|
} from '#shared/principal.ts'
|
|
17
|
+
import { PRINCIPAL_HEADER } from '#shared/PRINCIPAL_HEADER.ts'
|
|
18
18
|
import { refuse } from '#shared/refuse.ts'
|
|
19
19
|
import { declare } from '#shared/rpc.ts'
|
|
20
|
+
|
|
20
21
|
import { mountedOwn } from './answerRpc.ts'
|
|
21
22
|
import { signedInAt } from './bridgeRelay.ts'
|
|
22
23
|
import { callerOf, callerOrMint, mintCaller } from './callerOf.ts'
|