@plurnk/plurnk-schemes 3.2.2 → 3.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/SPEC.md +118 -681
- package/dist/ByteSource.d.ts +13 -0
- package/dist/ByteSource.d.ts.map +1 -1
- package/dist/ByteSource.js +62 -1
- package/dist/ByteSource.js.map +1 -1
- package/dist/Manifest.d.ts.map +1 -1
- package/dist/Manifest.js +12 -6
- package/dist/Manifest.js.map +1 -1
- package/dist/Matcher.d.ts.map +1 -1
- package/dist/Matcher.js +2 -3
- package/dist/Matcher.js.map +1 -1
- package/dist/MessageScheme.d.ts +6 -8
- package/dist/MessageScheme.d.ts.map +1 -1
- package/dist/MessageScheme.js +2 -2
- package/dist/MessageScheme.js.map +1 -1
- package/dist/MetadataOptions.d.ts +1 -2
- package/dist/MetadataOptions.d.ts.map +1 -1
- package/dist/MetadataOptions.js +5 -6
- package/dist/MetadataOptions.js.map +1 -1
- package/dist/MimetypeClassifier.d.ts +5 -0
- package/dist/MimetypeClassifier.d.ts.map +1 -1
- package/dist/MimetypeClassifier.js +33 -5
- package/dist/MimetypeClassifier.js.map +1 -1
- package/dist/OutputScheme.js +2 -2
- package/dist/OutputScheme.js.map +1 -1
- package/dist/PacketSections.d.ts +10 -1
- package/dist/PacketSections.d.ts.map +1 -1
- package/dist/PacketSections.js +12 -3
- package/dist/PacketSections.js.map +1 -1
- package/dist/ResourceNames.js +1 -1
- package/dist/ResourceNames.js.map +1 -1
- package/dist/Results.d.ts +3 -3
- package/dist/Results.d.ts.map +1 -1
- package/dist/Results.js +4 -8
- package/dist/Results.js.map +1 -1
- package/dist/SchemeDiscovery.d.ts.map +1 -1
- package/dist/SchemeDiscovery.js +11 -49
- package/dist/SchemeDiscovery.js.map +1 -1
- package/dist/Slicer.d.ts.map +1 -1
- package/dist/Slicer.js +22 -16
- package/dist/Slicer.js.map +1 -1
- package/dist/Summarize.js +2 -2
- package/dist/Summarize.js.map +1 -1
- package/dist/ctx.d.ts +3 -5
- package/dist/ctx.d.ts.map +1 -1
- package/dist/edit-receipt.d.ts +4 -0
- package/dist/edit-receipt.d.ts.map +1 -1
- package/dist/handler.d.ts +27 -4
- package/dist/handler.d.ts.map +1 -1
- package/dist/index.d.ts +7 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -11
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/dist/FileByteSource.d.ts +0 -9
- package/dist/FileByteSource.d.ts.map +0 -1
- package/dist/FileByteSource.js +0 -42
- package/dist/FileByteSource.js.map +0 -1
- package/dist/GeneratedByteSource.d.ts +0 -8
- package/dist/GeneratedByteSource.d.ts.map +0 -1
- package/dist/GeneratedByteSource.js +0 -21
- package/dist/GeneratedByteSource.js.map +0 -1
- package/dist/PathMimetype.d.ts +0 -6
- package/dist/PathMimetype.d.ts.map +0 -1
- package/dist/PathMimetype.js +0 -30
- package/dist/PathMimetype.js.map +0 -1
- package/dist/edit-statement.d.ts +0 -5
- package/dist/edit-statement.d.ts.map +0 -1
- package/dist/edit-statement.js +0 -2
- package/dist/edit-statement.js.map +0 -1
- package/dist/module-slice.d.ts +0 -22
- package/dist/module-slice.d.ts.map +0 -1
- package/dist/module-slice.js +0 -2
- package/dist/module-slice.js.map +0 -1
- package/dist/packet.d.ts +0 -10
- package/dist/packet.d.ts.map +0 -1
- package/dist/packet.js +0 -4
- package/dist/packet.js.map +0 -1
- package/dist/resource-tree.d.ts +0 -15
- package/dist/resource-tree.d.ts.map +0 -1
- package/dist/resource-tree.js +0 -2
- package/dist/resource-tree.js.map +0 -1
package/SPEC.md
CHANGED
|
@@ -1,153 +1,41 @@
|
|
|
1
|
-
# plurnk-schemes
|
|
1
|
+
# `@plurnk/plurnk-schemes` Specification
|
|
2
2
|
|
|
3
|
-
Contract for `@plurnk/plurnk-schemes-*` sibling packages
|
|
3
|
+
Contract for `@plurnk/plurnk-schemes-*` sibling packages, entry/channel handler dispatch, text/window slicing, and third-party scheme discovery.
|
|
4
4
|
|
|
5
|
-
## §manifest
|
|
5
|
+
## §manifest Scheme manifest
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
{
|
|
9
|
-
"name": "@plurnk/plurnk-schemes-<name>",
|
|
10
|
-
"plurnk": { "kind": "scheme", "name": "<scheme name>" }
|
|
11
|
-
}
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
Class-level manifest (static field on the default export):
|
|
15
|
-
|
|
16
|
-
```ts
|
|
17
|
-
import type { SchemeManifest } from "@plurnk/plurnk-schemes";
|
|
18
|
-
|
|
19
|
-
class Notes {
|
|
20
|
-
static manifest: SchemeManifest = {
|
|
21
|
-
name: "notes",
|
|
22
|
-
authority: "namespace",
|
|
23
|
-
channels: { body: "text/markdown", preview: "text/markdown" },
|
|
24
|
-
defaultChannel: "body",
|
|
25
|
-
category: "data",
|
|
26
|
-
writableBy: ["model", "client"],
|
|
27
|
-
volatile: false,
|
|
28
|
-
modelVisible: true,
|
|
29
|
-
textEditScopes: true,
|
|
30
|
-
traits: ["web"],
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
```
|
|
7
|
+
Every scheme package declares `plurnk: { "kind": "scheme", "name": "<scheme>" }` (or `plurnk.schemes: [{ name, export }]`) in `package.json` and exposes a static or instance `manifest: SchemeManifest` validated by `Manifest.of`:
|
|
34
8
|
|
|
35
9
|
| Field | Constraint |
|
|
36
10
|
|---|---|
|
|
37
|
-
| `name` | Matches `package.json#plurnk.name
|
|
38
|
-
|
|
|
39
|
-
| `channels` | `Record<channelName, mimetype>` for declared channel types. Channel names lowercase; an untyped default may coexist with typed siblings. |
|
|
40
|
-
| `defaultChannel` | Lowercase channel targeted when path has no `#fragment`.
|
|
41
|
-
| `category` | `"data"` (entry-bearing)
|
|
42
|
-
| `writableBy` | Subset of `["model", "client", "_plurnk"]`; empty declares a scheme no operation writes
|
|
11
|
+
| `name` | Matches `package.json#plurnk.name` (the addressing/routing URI prefix). |
|
|
12
|
+
| `authority?` | `"namespace"` (default — folds authored authority into pathname) or `"resource"` (preserves it as the entry authority). |
|
|
13
|
+
| `channels` | `Record<channelName, mimetype>` for declared channel types. Channel names are lowercase; an untyped default may coexist with typed siblings. |
|
|
14
|
+
| `defaultChannel` | Lowercase channel targeted when a path has no `#fragment`. Omission from `channels` means its type is determined per resource; empty string means no default. |
|
|
15
|
+
| `category` | `"data"` (entry-bearing), `"logging"` (`log://` rows), or `"control"` (owns no entries). |
|
|
16
|
+
| `writableBy` | Subset of `["model", "client", "_plurnk"]`; empty declares a scheme no operation writes (such as runtime output). Consumer returns `403` for outside-set writes. |
|
|
43
17
|
| `volatile` | Boolean. |
|
|
44
18
|
| `modelVisible` | Boolean. |
|
|
45
|
-
| `folderScopes?` | `true` declares that a trailing slash on FIND is a collection scope
|
|
46
|
-
| `lineAnchors?` | `true` publishes and accepts shared line anchors for stable textual representations without declaring EDIT support. |
|
|
47
|
-
| `textEditScopes?` | `true` declares the shared textual EDIT coordinate and collision contract
|
|
48
|
-
|
|
|
49
|
-
|
|
|
50
|
-
| `documentation?` |
|
|
51
|
-
|
|
|
52
|
-
| `storedScheme?` |
|
|
53
|
-
|
|
54
|
-
The manifest is closed: unknown top-level fields fail admission. Every entry
|
|
55
|
-
belongs to the operation's workspace. Resource coordinates and intrinsic
|
|
56
|
-
mutability are resolved through {§entry-address-resolution}.
|
|
57
|
-
|
|
58
|
-
{§manifest-metadata-modifier} is the scheme's explicit opt-in to
|
|
59
|
-
{§scheme-metadata-modifier}. Core never parses or moves metadata into the
|
|
60
|
-
target. Direct operation methods receive it on `statement.metadata`; exact
|
|
61
|
-
resource preparation receives the same ordered raw blocks on
|
|
62
|
-
`request.metadata`. A present modifier on any scheme that did not opt in is a
|
|
63
|
-
non-retryable `400 scheme-metadata-unsupported`, and the handler is not called.
|
|
64
|
-
|
|
65
|
-
The invoked handler owns this admission, not an address it consumes internally.
|
|
66
|
-
An execution delegates its blocks to the selected executor under {§executor-metadata};
|
|
67
|
-
its source acquisition is a separate READ without inherited execution metadata.
|
|
68
|
-
|
|
69
|
-
§service-metadata-keys **Two keys are the service's, withheld from every owner.**
|
|
70
|
-
`MetadataOptions.SERVICE_KEYS` names `env` and `lifetime`: the reader strips them from
|
|
71
|
-
every owner's `options` and surfaces them raw beside it, so no scheme or executor
|
|
72
|
-
interprets or refuses them and the service alone owns their shapes — the environment a
|
|
73
|
-
scope opens, and how long its live work may run. `pattern` is the language's, lifted
|
|
74
|
-
before the block reaches the reader ({§matcher-option}).
|
|
75
|
-
|
|
76
|
-
{§manifest-capability-traits} `traits` are closed manifest data, not a policy
|
|
77
|
-
channel. Names match `^[a-z][a-z0-9-]*$`, are unique, and carry through a
|
|
78
|
-
synthesized runtime-output scheme. A handler never interprets policy or a named
|
|
79
|
-
client mode. The consumer combines operation, access class, scheme, runtime,
|
|
80
|
-
tool, and these declared facts into its general capability descriptor; the
|
|
81
|
-
same decision governs dispatch and teaching visibility.
|
|
82
|
-
|
|
83
|
-
Proposal behavior is orthogonal to capabilities. A handler proposes by
|
|
84
|
-
returning 202; the consumer's proposal lifecycle routes it to the worker
|
|
85
|
-
owner's review unless the server disposition `PLURNK_SERVICE_PROPOSALS` accepts
|
|
86
|
-
or rejects it, with timeout as a lifecycle bound.
|
|
87
|
-
|
|
88
|
-
§manifest-self-doc **Discoverable scheme references.** `documentation` contains the scheme's operation contracts and examples. The consumer materializes it as **`worker:///_plurnk/plurnk/<name>.md`**: FIND projects its exact H2 `Summary`, and READ retrieves its body on demand. Reference availability follows the registered capabilities, not illustrative operations. `glyph` is client display metadata under {§manifest-client-display}, not self-documentation.
|
|
89
|
-
|
|
90
|
-
**Authoring convention — `docs/<name>.md`.** The contract field stays a plain `string`, but a sibling SHOULD keep the deep doc in a **`docs/<name>.md`** file at the package root rather than inline, and load it into the manifest at module init — e.g. `documentation: await readFile(new URL("../docs/<name>.md", import.meta.url), "utf-8")` (top-level await; `../` resolves identically from `src/` in test and `dist/` once built). Ship it by adding `docs/**/*` to `files`. This keeps prose out of the handler source and gives editors real Markdown; the consumer materializes it at `worker:///_plurnk/plurnk/<name>.md`. A missing file fails-hard at import (no silent empty doc).
|
|
91
|
-
|
|
92
|
-
## §2 Interface
|
|
93
|
-
|
|
94
|
-
§resource-publication-names **Published resources have names, not invented ordinals.**
|
|
95
|
-
`ResourceNames` allocates one URI-encoded component per resource: a supplied name
|
|
96
|
-
is preserved; no name produces eight hexadecimal characters. A repeated name
|
|
97
|
-
gets an eight-character hash suffix, never overwrites a sibling. Passing stable
|
|
98
|
-
identities in collection order reconstructs the same names. Allocation neither
|
|
99
|
-
creates entries nor changes their ownership or publication policy.
|
|
100
|
-
|
|
101
|
-
§scheme-source-bytes **Original bytes retain the full resource identity.**
|
|
102
|
-
`byteSource({authority, pathname}, ctx)` supplies a `ByteSource`: `size()` returns
|
|
103
|
-
the byte count or `null` for an absent source; `read(first, last)` returns the
|
|
104
|
-
one-based inclusive byte window. The context carries the invoking actor and
|
|
105
|
-
workspace. READ, FIND, transfers, and native model attachments
|
|
106
|
-
use this same source contract. Public `EntryData` also accepts `bytes` beside
|
|
107
|
-
an empty `content`; the consumer owns its storage encoding. Binary channels retain
|
|
108
|
-
those bytes exactly. Textual channels accept exact UTF-8 (including BOM and line
|
|
109
|
-
endings); invalid text bytes fail before replacing the stored resource.
|
|
110
|
-
|
|
111
|
-
An optional `nativePath()` identifies the original regular file, or `null` when
|
|
112
|
-
absent. It never creates a copy. The resource owner resolves it under the same
|
|
113
|
-
identity and admission as the byte source; only an admitted consumer may use
|
|
114
|
-
it. `FileByteSource` implements this for filesystem-backed schemes. Consumers
|
|
115
|
-
must not substitute the file for a selected derived channel. Native execution
|
|
116
|
-
preserves the file's name and surrounding filesystem; it grants no new
|
|
117
|
-
capability, changes no working directory, and performs no automatic copying.
|
|
118
|
-
|
|
119
|
-
§web-materialization-contract **Web materialization is a handler capability, not a package name.**
|
|
120
|
-
A handler may publish `webMaterializer`: `fetch(url, {signal})` acquires a checked
|
|
121
|
-
`WebFetchResult` (`null` for a dead source), `materialize(fetched, projection)` produces
|
|
122
|
-
the entry's `WebMaterializedResult`, and `materializedChannels(result, request?)` lays it
|
|
123
|
-
out as entry channels. The result and error shapes (`WebFetchResult`,
|
|
124
|
-
`WebMaterializedResult`, `WebMaterializationError`) are this framework's. The `https`
|
|
125
|
-
handler publishes it; the service's entry sink resolves it through the scheme registry and
|
|
126
|
-
names no extension package, so a compatible extension replaces it through the ordinary installation
|
|
127
|
-
and discovery path.
|
|
128
|
-
|
|
129
|
-
§scheme-operation-dispatch Sister scheme handlers implement op methods consumed by plurnk-service via
|
|
130
|
-
dispatch. The consumer owns READ for every `category: "data"` scheme and owns
|
|
131
|
-
exact-resource FIND over its canonical representation; no handler method can
|
|
132
|
-
replace either projection. Other absent operation methods return **501**. The
|
|
133
|
-
exported **`SchemeHandler`** interface gives operation methods their grammar
|
|
134
|
-
statement and `ctx`, including KILL's target, scope, metadata and aside. Bundled
|
|
135
|
-
adapters use the same interface; no positional pathname/scope overload exists.
|
|
136
|
-
Representation preparation receives a deliberately narrower request.
|
|
137
|
-
`editBatch` returns the typed `EditBatchResult`
|
|
138
|
-
specialization:
|
|
19
|
+
| `folderScopes?` | `true` declares that a trailing slash on `FIND` is a collection scope; absent/`false` treats `/` as ordinary resource syntax. |
|
|
20
|
+
| `lineAnchors?` | `true` publishes and accepts shared line anchors for stable textual representations without declaring `EDIT` support. |
|
|
21
|
+
| `textEditScopes?` | `true` declares the shared textual `EDIT` coordinate and collision contract ({§line-anchors}). Handlers receive numeric coordinates only and route standard entry mutation through `ctx.entries.operations.editBatch`. |
|
|
22
|
+
| `metadataModifier?` | `true` opts into `[metadata]` on resource operations ({§slot-order}). Absent/`false` rejects `[metadata]` at dispatch with non-retryable `400 scheme-metadata-unsupported`. |
|
|
23
|
+
| `traits?` | Unique lowercase capability facts matching `^[a-z][a-z0-9-]*$` (e.g. `web`, `interaction`) consumed by {§capability-admission}. |
|
|
24
|
+
| `documentation?` | Deep reference Markdown (loaded from `docs/<name>.md`) with an exact H2 `Summary`, materialized on demand at `plurnk:///<name>.md` (`FIND` projects H2 `Summary`; `READ` retrieves the body). |
|
|
25
|
+
| `glyph?` | Non-empty opaque client presentation glyph projected through {§mcp-server-definition}; never enters model teaching. |
|
|
26
|
+
| `storedScheme?` | Non-null string persisted to `entries.scheme` when different from `name` (defaults to `name`). |
|
|
139
27
|
|
|
140
|
-
|
|
141
|
-
|
|
28
|
+
- The manifest is closed: unknown top-level fields fail admission.
|
|
29
|
+
- **Reserved service metadata keys:** `MetadataOptions.SERVICE_KEYS` (`["lifetime"]`) are stripped from every owner's `options` and surfaced raw beside `options` so no scheme or executor interprets or refuses `lifetime` ({§exec-lifetime}).
|
|
30
|
+
|
|
31
|
+
## §scheme-operation-dispatch Handler interface and operation dispatch
|
|
142
32
|
|
|
33
|
+
```ts
|
|
143
34
|
export interface SchemeHandler {
|
|
144
35
|
ready?(): Promise<void>;
|
|
145
36
|
close?(): Promise<void>;
|
|
146
37
|
resolveEntryAddress?(target: ParsedPath, ctx: SchemeAddressCtx, access?: "read" | "write"): Promise<EntryAddress | SchemeResult | null>;
|
|
147
|
-
prepareRepresentation?(
|
|
148
|
-
request: RepresentationPreparationRequest,
|
|
149
|
-
ctx: SchemeCtx,
|
|
150
|
-
): Promise<RepresentationPreparationResult>;
|
|
38
|
+
prepareRepresentation?(request: RepresentationPreparationRequest, ctx: SchemeCtx): Promise<RepresentationPreparationResult>;
|
|
151
39
|
prepareFind?(statement: FindStatement, ctx: SchemeCtx): Promise<SchemeResult>;
|
|
152
40
|
find?(statement: FindStatement, ctx: SchemeCtx): Promise<SchemeResult>;
|
|
153
41
|
editBatch?(statements: readonly ResolvedEditStatement[], ctx: SchemeCtx): Promise<EditBatchResult>;
|
|
@@ -158,575 +46,124 @@ export interface SchemeHandler {
|
|
|
158
46
|
}
|
|
159
47
|
```
|
|
160
48
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
`
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
`ctx.
|
|
171
|
-
snapshot owner and lands with the consumer's compare-and-swap. Applying the
|
|
172
|
-
numeric coordinates independently would discard the declared collision
|
|
173
|
-
contract. Core-owned special resources enforce the equivalent invariant inside
|
|
174
|
-
their mutation adapter.
|
|
175
|
-
|
|
176
|
-
§read-preparation `prepareRepresentation?` is the optional, operation-neutral
|
|
177
|
-
acquisition seam for one exact resource. Core first resolves its canonical
|
|
178
|
-
authority and pathname, binds `ctx.entries`/channels/subscriptions to
|
|
179
|
-
that exact workspace coordinate, and removes the channel fragment. The request
|
|
180
|
-
is exactly `{ target, metadata, authority, pathname }`: the target remains pure
|
|
181
|
-
resource identity while `metadata` is the exact opaque modifier or `null`.
|
|
182
|
-
READ coordinates, FIND matchers, the selected channel, and operation intent are
|
|
183
|
-
structurally unavailable.
|
|
184
|
-
|
|
185
|
-
A stored scheme omits the hook. An acquired scheme writes its complete channel
|
|
186
|
-
topology through `ctx.entries` and returns `200` readiness. A live scheme first
|
|
187
|
-
seeds those same canonical channels, opens a subscription, and may return `102`
|
|
188
|
-
only while production remains live. Other statuses are exact terminal results.
|
|
189
|
-
Per-channel producer status belongs durably on that channel as
|
|
190
|
-
`producerResult`; no transient preparation result may carry content, channel
|
|
191
|
-
selection, or channel outcomes. Neither preparation nor producer results supply
|
|
192
|
-
the READ's `terminal` flag: core derives it from channel state under
|
|
193
|
-
{§stream-observation-result}. After `200`, core alone selects the authored
|
|
194
|
-
channel, applies tag/binary/text rules (including {§markerless-first-page}), and
|
|
195
|
-
composes that channel's producer evidence. Cold and warm reads therefore have
|
|
196
|
-
identical semantics.
|
|
197
|
-
|
|
198
|
-
FIND classifies the target after canonical address resolution; a resolved
|
|
199
|
-
collection remains broad when `folderScopes` is declared, even when the authored
|
|
200
|
-
path omitted its trailing slash. Exact FIND uses the same `prepareRepresentation?`
|
|
201
|
-
seam and then the standard entry query; the queried default channel's durable producer result composes
|
|
202
|
-
with that exact query just as it does with exact READ. `prepareFind?` is only
|
|
203
|
-
the optional broad-scope discovery seam
|
|
204
|
-
used before standard entry selection when no custom broad `find()` exists. A
|
|
205
|
-
custom `find()` may own genuinely different candidate enumeration, but never
|
|
206
|
-
exact-resource materialization or READ coordinates. Every standard query uses
|
|
207
|
-
the same canonical identity as `ctx.entries`; URL authority cannot disappear
|
|
208
|
-
between preparation and lookup.
|
|
209
|
-
|
|
210
|
-
An exact COPY/MOVE source also resolves and prepares through this seam before
|
|
211
|
-
core selects its canonical stored channel. COPY/MOVE retain their own source
|
|
212
|
-
scope algebra: an absent source scope means the complete channel and an explicit
|
|
213
|
-
scope preserves raw source separators. Neither distinction is exposed to the
|
|
214
|
-
producer. A live `102` leaves the composition unapplied; a ready representation
|
|
215
|
-
is selected from the same channels used by READ and exact FIND. A selected
|
|
216
|
-
channel's producer failure aborts before destination mutation; successful
|
|
217
|
-
non-`200` content remains eligible for transfer.
|
|
218
|
-
|
|
219
|
-
§entry-address-resolution `resolveEntryAddress?` defines canonical addresses for client and model operations. Core removes the channel fragment and target-slot escapes {§path-parentheses} before invocation; other identity components remain exact. The hook receives capability-free `SchemeAddressCtx` and returns only the resource coordinate. The optional access argument defaults to `read`; `write` checks intrinsic mutability before a mutation or proposal. Resolution is observational and has no effects.
|
|
49
|
+
| Seam / helper | Contract |
|
|
50
|
+
|---|---|
|
|
51
|
+
| Operation dispatch | Core owns `READ` for every `category: "data"` scheme and exact-resource `FIND` over its canonical representation; unimplemented optional methods return `501`. Log-targeted `KILL`, `WORK`, `FORK`, and native dispositions (`NOTE`, `WAIT`) are core-owned and never dispatch to scheme handlers. |
|
|
52
|
+
| `prepareRepresentation?(request, ctx)` | Operation-neutral acquisition seam for one exact resource (`{ target, metadata, authority, pathname }`, with no scope, matcher, or channel fragment). Writes canonical channels via `ctx.entries` and returns `200`, `102` while a live `StreamSubscription` remains active ({§exec-stream}), or an exact terminal result. Shared by exact `READ`, exact `FIND`, and exact `COPY`/`MOVE` sources. |
|
|
53
|
+
| `prepareFind?(statement, ctx)` | Broad-scope discovery seam invoked before standard entry selection when no custom `find()` is implemented. |
|
|
54
|
+
| `ResourceNames` | Allocates one URI-encoded component per published resource: preserves supplied names, generates 8-hex characters when unnamed, and appends an 8-hex hash suffix on collision without overwriting siblings. |
|
|
55
|
+
| `ByteSource` (`FileByteSource`, `GeneratedByteSource`) | Supplies `size()` (byte count or `null` when absent), 1-based inclusive `read(first, last)`, and optional `nativePath()` (original regular file path or `null`, never creating a copy). Binary channels preserve exact bytes; textual channels require valid UTF-8. |
|
|
56
|
+
| `webMaterializer` | Optional handler capability (`{ fetch, materialize, materializedChannels }` returning `WebFetchResult`, `WebMaterializedResult`, or `WebMaterializationError`) published by `https` and resolved through the scheme registry without hardcoding an extension package name. |
|
|
57
|
+
|
|
58
|
+
`resolveEntryAddress?(target, ctx, access)` receives capability-free `SchemeAddressCtx` and `access` (`"read"` default, or `"write"`). Core strips `#fragment` and {§path-syntax} target parentheses before invocation:
|
|
220
59
|
|
|
221
60
|
| Return | Meaning |
|
|
222
61
|
|---|---|
|
|
223
|
-
| Hook absent | Use the standard coordinate from {§manifest
|
|
62
|
+
| Hook absent | Use the standard coordinate from `manifest.authority` ({§manifest}). |
|
|
224
63
|
| `{ authority, pathname }` | Bind this exact resource in the operation's workspace. |
|
|
225
64
|
| Non-success `SchemeResult` | Preserve the expected address or mutability refusal exactly. |
|
|
226
65
|
| `null` | No resource at this selector. |
|
|
227
66
|
|
|
228
|
-
|
|
67
|
+
Handler lifecycle invariants for process-lived `SchemeHandler` instances:
|
|
229
68
|
|
|
230
|
-
|
|
69
|
+
| Concern | Contract |
|
|
70
|
+
|---|---|
|
|
71
|
+
| Readiness (`ready?`) | Runs after registration and before capability advertisement; establishes that advertised resources are usable. |
|
|
72
|
+
| Hook cardinality | Invoked once per unique handler object identity, even when multiple registered names share that object. |
|
|
73
|
+
| Operation context | `SchemeCtx` and capabilities extracted from it are operation-owned; only `StreamSubscription` from `subscriptions.open` is retainable. |
|
|
74
|
+
| Retained state & live ownership | Tenant- or address-selectable state keys every isolation coordinate; conflicting live acquisition fails explicitly without overwriting the existing owner. |
|
|
75
|
+
| Shutdown (`close?`) | Runs after in-flight scheme work drains and before backing stores close; the consumer awaits every unique handler close and aggregates failures. |
|
|
231
76
|
|
|
232
|
-
§
|
|
233
|
-
instance and may receive overlapping operation calls. Retained handler state is
|
|
234
|
-
ordinary; handlers must make concurrent access and semantic isolation explicit.
|
|
77
|
+
Regional mutation receipts (`ResolvedEditStatement`, `EditBatchResult`): Core resolves {§matcher-prefix-claims} line anchors and {§zero-width-column-one-insert} bodies before calling `editBatch`, so `ResolvedEditStatement.lineMarker` contains numbers only. Regional `editBatch` returns `EditBatchResult` carrying `EditBatchReceipt` (`revision`, `unit: "lines" | "codePoints"`, `before`, `after`, optional advisory `parseIssues: { before, after }`, {§op-shapes}):
|
|
235
78
|
|
|
236
|
-
|
|
|
237
|
-
|
|
238
|
-
|
|
|
239
|
-
|
|
|
240
|
-
| Operation context | `SchemeCtx` and capabilities extracted from it remain operation-owned under {§scheme-ctx-lifetime}; only the `StreamSubscription` returned by `subscriptions.open` is retainable. |
|
|
241
|
-
| Retained state | Tenant- or address-selectable state keys every semantic isolation coordinate. A global pool is valid only when it carries no cross-tenant session state. |
|
|
242
|
-
| Live ownership | An address-selectable live resource has one unambiguous owner. Conflicting acquisition fails explicitly; it never overwrites the existing owner. |
|
|
243
|
-
| Shutdown | After in-flight scheme work drains and before backing stores close, `close?()` releases partially or fully initialized handler resources. The consumer attempts and awaits every unique handler close, then aggregates every failure. |
|
|
79
|
+
| Batch outcome | Authored correlation | Landed effects |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| Applied as proposed (`AppliedEditBatchReceipt`) | `effects[N]` describes authored `EDIT` `N` (`requested`, `source`, `result`, `removed`, `inserted`, source-numbered `context`) | One truthful effect per authored `EDIT` |
|
|
82
|
+
| Resolver replaced proposed body (`ReviewerReplacementEditBatchReceipt`) | `disposition: "reviewer-replaced"`; `superseded[N]` retains authored marker `N` | One `replacement` effect describes the bytes that actually landed |
|
|
244
83
|
|
|
245
|
-
|
|
246
|
-
hook.
|
|
84
|
+
## §network-address Network address and media helpers
|
|
247
85
|
|
|
248
|
-
|
|
86
|
+
`NetworkAddress.from(target)` normalizes `http`, `https`, `ws`, and `wss` targets into `{ scheme, authority, pathname, url, hasCredentials }`, and `NetworkAddress.render({ scheme, authority, pathname })` reconstructs the model-facing address with {§path-syntax} target escaping:
|
|
249
87
|
|
|
250
|
-
|
|
251
|
-
|
|
88
|
+
| Component | Entry identity (`authority` / `pathname`) | Transport `url` | Plurnk channel |
|
|
89
|
+
|---|---|---|---|
|
|
90
|
+
| Scheme (`http`, `https`, `ws`, `wss`) | Exact addressed scheme | Yes | No |
|
|
91
|
+
| Host & non-default port | `<host>[:<port>]` in `authority` (WHATWG canonical host) | Yes | No |
|
|
92
|
+
| Path (`%28`/`%29` $\to$ `(` / `)`) & query | `<path>[?<query>]` in `pathname` (preserving order, duplicates, and empty `?`) | Yes | No |
|
|
93
|
+
| `#fragment` | No | No | Yes |
|
|
94
|
+
| Userinfo | Rejected (`hasCredentials: true`) | No | No |
|
|
252
95
|
|
|
253
|
-
|
|
254
|
-
handler methods. The engine composes their source and
|
|
255
|
-
destination resource selections over `ctx.entries` and uses `editBatch` for a
|
|
256
|
-
scoped destination or source mutation. This keeps channel selection, snapshot
|
|
257
|
-
ordering, cross-scheme failures, and proposal sequencing uniform for every data
|
|
258
|
-
scheme. Scheme hooks return their ordinary mutation result and, for a regional
|
|
259
|
-
`editBatch`, an `EditBatchResult` carrying its aggregate `EditBatchReceipt`:
|
|
96
|
+
Additional framework helpers:
|
|
260
97
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
readonly requested: string;
|
|
266
|
-
readonly source: string;
|
|
267
|
-
readonly result: string;
|
|
268
|
-
readonly removed: number;
|
|
269
|
-
readonly inserted: number;
|
|
270
|
-
readonly context: string;
|
|
271
|
-
}
|
|
98
|
+
- **`MimetypeClassifier` & `PathMimetype`:** `isBinary(mimetype)` (delegates to `@plurnk/plurnk-mimetypes`), `isHtml(mimetype)` (`text/html`, `application/xhtml+xml`), `isJson(mimetype)` (`application/json` and `+json`, excluding NDJSON), `normalizeAutoText(mimetype)` (`text/plain` / `null` / `undefined` $\to$ `TEXT_PRIMITIVE_MIMETYPE` `"text/markdown"`), and `isTransferCompatible(source, destination, sourceClassification?)` (permits verbatim `COPY`/`MOVE` between equal mimetypes or from any textual source into `text/plain` or `text/markdown`, {§mimetype-content}). `PathMimetype.resolve(pathname, defaultMimetype, mimetypes)` detects by extension and auto-normalizes `text/plain` to `text/markdown`.
|
|
99
|
+
- **Packet transformation (`PacketSections`):** A scheme implementing `transformSections(sections: PacketSectionDraft[])` may add, remove, or reorder `{ name, slot: "system" | "user" | "assistant", header: string | null, content }` drafts before core token measurement ({§packet-assembly}), validated before and after by `PacketSections.assertDrafts` (unique non-empty names).
|
|
100
|
+
- **Executor output schemes (`OutputScheme`, `Summarize`):** `OutputScheme.manifestFromRuntime(decl)` derives a read-only volatile data `SchemeManifest` from an executor `RuntimeDecl` (preserving `glyph` and `traits`); `Summarize.summarize(content, mimetype) -> OrientIndex` produces structural-only receipt indices.
|
|
101
|
+
- **Resource capture (`ctx.resources.capture`, `MessageAttachments`):** Acquires ordered snapshots (`{ name, mediaType, contentHash, target, bytes }`) without performing `SEND` or transferring ownership ({§op-methods-op-dispatch}).
|
|
272
102
|
|
|
273
|
-
|
|
274
|
-
readonly before: number;
|
|
275
|
-
readonly after: number;
|
|
276
|
-
}
|
|
103
|
+
`ctx.projection` delegates model-facing projection to the configured mimetype framework (`ProjectionInputLimitError` exports its bounded-input failure):
|
|
277
104
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
105
|
+
| Surface | Contract |
|
|
106
|
+
|---|---|
|
|
107
|
+
| `readable(content, mimetype)` | Project an acquired Unicode representation (`""` is present; only `null` denotes absence). |
|
|
108
|
+
| `binary(chunks, mimetype)` | Return bounded source `bytes`, nullable `readable: ProjectedText`, and `projectionIdentity`, consuming one async byte source under {§mimetype-binary-input}. |
|
|
109
|
+
| `identity(mimetype)` | Return opaque identity of configured projection behavior for cache and materialization freshness. |
|
|
110
|
+
| `isBinary(mimetype)` | Classify through the configured registry so installed handler declarations remain authoritative. |
|
|
111
|
+
| `parseIssues(content, mimetype)` | Return nonnegative parser-recovery count, or `undefined` when unavailable ({§mimetype-channel-selection}). |
|
|
112
|
+
| `ProjectedText` | Derived Unicode plus output mimetype, source mimetype, and opaque projection identity. |
|
|
286
113
|
|
|
287
|
-
|
|
288
|
-
readonly revision: string;
|
|
289
|
-
readonly unit: EditReceiptUnit;
|
|
290
|
-
readonly before: number;
|
|
291
|
-
readonly after: number;
|
|
292
|
-
readonly parseIssues?: ParseIssueTransition;
|
|
293
|
-
readonly disposition: "reviewer-replaced";
|
|
294
|
-
readonly superseded: readonly string[];
|
|
295
|
-
readonly replacement: EditEffectReceipt;
|
|
296
|
-
}
|
|
114
|
+
## §slicer-text-algebra Text, window, and pagination slicing
|
|
297
115
|
|
|
298
|
-
|
|
299
|
-
| AppliedEditBatchReceipt
|
|
300
|
-
| ReviewerReplacementEditBatchReceipt;
|
|
116
|
+
`Slicer` owns one coordinate algebra across textual lines, code-point regions, positional byte windows (`Slicer.window`), and ordered result pagination (`Slicer.page`):
|
|
301
117
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
118
|
+
| Scope | Meaning |
|
|
119
|
+
|---|---|
|
|
120
|
+
| `<N>` | Whole 1-based physical line, byte (`unit: "byte"`), or result item `N` |
|
|
121
|
+
| `<N,M>` | Inclusive 1-based range `N..M` (`M = -1` selects through the end) |
|
|
122
|
+
| `<SL,SC,EL,EC>` | Exact exclusive-end text region using 1-based Unicode code-point columns ({§text-region}) |
|
|
123
|
+
| `<0>` / `<-1>` | Single-position mutation anchors before the first / after the final line (`start: null` on `window()`) |
|
|
124
|
+
|
|
125
|
+
- **One-based ranges (`range-starts-at-one`):** A two-coordinate range starts at `1`. `<0,M>` is refused `416 range-not-satisfiable` by `lines()`, `linesRaw()`, `textReplacement()`, `lineMarkerEdit[Batch]()`, `window()`, and `page()` (even on empty content/results) and never clamped to `<1,M>`. As a shared `READ` projection tolerance, `<0,M>` (for positive safe integer `M` or `-1`) selects `<1,M>`, retains `[0,M]` as requested, and emits scope-normalization evidence.
|
|
126
|
+
- **3-coordinate lowering and end clamping:** `<startLine,startColumn,endLine>` lowers to `<startLine,startColumn,endLine,endCol>` with boundary-validated normalization evidence. Harmless end-bound overshoots clamp to EOF / final code point; start-bound overshoots and inverted ranges fail `416`.
|
|
127
|
+
- **`Slicer.wholeLineBody(content, marker, body)`:** Appends the content's line separator only for a non-empty body without a trailing newline at a zero-width column-1 region ({§zero-width-column-one-insert}).
|
|
128
|
+
- **Batch edits (`lineMarkerEditBatch`):** Validates all replacements against one snapshot; resolves identical twins, co-located insertions, and evidenced 1-line shared endpoints (recorded in `merges`); rejects any other overlap with `409 overlapping-edits` (`conflicts`, `cleanRegions`, `conflictingRegions`, `editCount`, `applied: 0`) and applies all or none.
|
|
129
|
+
- **Results and Matcher (`Results`, `Matcher`):** `Results.isErrorStatus(status)` is `status >= 400`; `Results.isEntry`, `isProposal`, and `isPassthrough` guard optional result shapes; `Results.assert`, `assertReadResult`, and `assertMatchEvidenceList` enforce RFC 9457 `ProblemDetails` on `400..599` and `{ locator?, region?, enclosingRegion?, matched? }` on matches. `Matcher.matchAgainstContent(body, content, mimetype, mimetypes, diagnostic?)` adapts `Mimetypes.query` (`200` matches, `204` empty, `400 invalid-expression` with bounded `diagnostic`, `415 unsupported-dialect`, `203` raw-text fallback with `reason`, {§matcher-dispatch}).
|
|
130
|
+
|
|
131
|
+
| Problem code | Status | Contract & pinned wording |
|
|
132
|
+
|---|---:|---|
|
|
133
|
+
| `range-not-satisfiable` | `416` | Range lies outside available extent (`Lines and columns count from 1.`, `An exact region names its earlier position first: <SL,SC,EL,EC>.`, `-1 is the only position counted from the end; lines run 1..N.`, `Choose positions within 1..N.`, or ``Range <0,end> starts at 0, which is not a line; lines are numbered from 1 and 0 is only the `<0>` prepend position. Recovery: `<L,M>` selects lines L through M; `<0>` prepends and `<-1>` appends without replacing anything.`` / `Range <0,end> starts at 0; <unit> positions are numbered from 1.`). Unsupported scope arity: `A scope requires one position or an inclusive two-position range.` |
|
|
134
|
+
| `overlapping-edits` | `409` | Two `EDIT` regions overlap, or a whole-resource replacement coexists with another `EDIT`. `Recovery: Submit the whole-resource replacement by itself.` |
|
|
135
|
+
| `invalid-expression` | `400` | `The <dialect> matcher expression is invalid. Recovery: Revise the matcher expression.` |
|
|
136
|
+
| `unsupported-dialect` | `415` | `The <dialect> matcher is not supported for <mimetype>. Recovery: Use a matcher supported by the resource mimetype.` |
|
|
137
|
+
| `metadata-invalid` | `400` | `[metadata] must be a JSON array.` or `[metadata] must be a JSON array of option objects; every element is an object.` |
|
|
138
|
+
| `metadata-unsupported` | `400` | `Message metadata accepts only attachments.` |
|
|
139
|
+
| `attachments-invalid` | `400` | `attachments must be an array of non-empty resource addresses.` |
|
|
306
140
|
|
|
307
|
-
|
|
308
|
-
| ------------------------------------ | ------------------------------------------------- | --------------------------------------------------------------------- |
|
|
309
|
-
| Applied as proposed | `effects[N]` describes authored EDIT `N` | One truthful effect per authored EDIT |
|
|
310
|
-
| Resolver replaced the proposed body | `superseded[N]` retains authored marker `N` | One `replacement` effect describes the bytes that actually landed |
|
|
311
|
-
|
|
312
|
-
`requested` retains the admitted scope. `source` and `result` are resolved
|
|
313
|
-
scope strings using {§text-scope-semantics}: `<line>`, `<first,last>`, or
|
|
314
|
-
`<startLine,startColumn,endLine,endColumn>`. Empty selections use an exact
|
|
315
|
-
zero-width region at the source insertion point or landed deletion join;
|
|
316
|
-
they never invent a line beyond an unterminated EOF. Producers resolve these
|
|
317
|
-
coordinates from the respective revision, not from another formatted receipt.
|
|
318
|
-
|
|
319
|
-
The replacement form is not a heuristic attribution. An arbitrary resolver
|
|
320
|
-
body supersedes every authored EDIT because its correspondence to those edits
|
|
321
|
-
cannot be known. The consumer projects the replacement once on the durable
|
|
322
|
-
proposal-owning row and projects each authored marker's superseded disposition
|
|
323
|
-
on its own row.
|
|
324
|
-
|
|
325
|
-
`context` is an ordered, source-numbered projection of the landed result. For a
|
|
326
|
-
consumer-selected count `C`, it contains up to `C` surrounding lines and the
|
|
327
|
-
first and last `C` landed lines at each result boundary. Overlapping windows
|
|
328
|
-
coalesce and coordinate jumps expose an omitted middle. A deletion instead
|
|
329
|
-
contains up to `C` lines on each side of its join.
|
|
330
|
-
|
|
331
|
-
The engine validates that receipt and owns the ordered COPY/MOVE resource
|
|
332
|
-
effects shown to consumers; extensions do not invent a second effect envelope.
|
|
333
|
-
`parseIssues`, when present, carries nonnegative parser-recovery counts for the
|
|
334
|
-
complete source and resulting revisions. It is omitted when both are clean or
|
|
335
|
-
either inspection is unavailable. The hint is advisory: inspection failure
|
|
336
|
-
does not reverse a landed mutation.
|
|
337
|
-
|
|
338
|
-
## §3 Helpers exported by this repo
|
|
339
|
-
|
|
340
|
-
### Types
|
|
341
|
-
|
|
342
|
-
- Manifest: `SchemeManifest`, `SchemeAuthority`, `EntryCoordinate`, and `WriterTier`.
|
|
343
|
-
- Mutation receipts: `EditBatchResult`, `EditBatchReceipt`, `EditReceipt`, `EditEffectReceipt`, `EditReceiptUnit`, and `ParseIssueTransition`.
|
|
344
|
-
- §scheme-packet-transform **Packet-section transformation.** A scheme may implement `transformSections(sections: PacketSectionDraft[]) → PacketSectionDraft[] | Promise<…>` to add, remove, or reorder sections before core measures the packet. The exact draft shape is `{ name; slot: "system"|"user"|"assistant"; header: string|null; content }`; no token measurement exists at this boundary. Core invokes implementations in registration order and applies `PacketSections.assertDrafts` to the initial list and every returned list. Names are non-empty and unique within the packet. Slots are message roles; their order determines the envelope ({§packet-wire-envelope}).
|
|
345
|
-
- Behavior contract: `SchemeHandler` (§2). Scheme-facing grammar types re-exported here so siblings pin only this package: `PlurnkStatement` + the per-op statement types (`ReadStatement`, `FindStatement`, `CopyStatement`, `MoveStatement`, `SendStatement`, `ExecStatement`, `WorkStatement`, `ForkStatement`, `KillStatement`, `ContinuationStatement`) and path types (`ParsedPath` = `LocalPath` | `UrlPath`). EDIT uses `ResolvedEditStatement` under {§resolved-edit-statement}.
|
|
346
|
-
- Target syntax: contracts-owned `PathSyntax` is re-exported for the shared exact-versus-path-glob classifier {§path-glob}.
|
|
347
|
-
- Discovery: `SchemeDiscovery` (behavior class) with `SchemeInfo` / `SchemeDiscoveryResult` / `DiscoverOptions` (§6).
|
|
348
|
-
- §executor-scheme-output Executor-scheme ("an executor is a scheme"): `OutputScheme.manifestFromRuntime(decl)` derives a read-only-output `SchemeManifest` from an executor's `RuntimeDecl` (zero scheme-authoring). Executor output is a canonical entry and therefore inherits core's exact READ projection under {§read-preparation}; no executor-specific READ helper exists. `Summarize.summarize(content, mimetype)` -> `OrientIndex` is the structural-only execution-receipt index (no content - universal-receipt containment). A per-tag executor-scheme supplies its manifest via instance `get manifest()` (§2 `SchemeHandler.manifest?`).
|
|
349
|
-
- Results: `SchemeResult` is the universal operation-result contract. Statuses below 400 carry no `problem`; statuses 400–599 require RFC 9457 `ProblemDetails`. `EntryResult`, `ProposalResult`, and `PassthroughResult` are optional conventional shapes, not engine routing discriminators. Guards inspect those optional shapes; proposal routing itself is engine-owned and follows status plus operation semantics.
|
|
350
|
-
- Standard `EntryFindResult` exposes only its paged `results`, complete `matchingPathCount` / `matchLocationCount`, `itemsWeightTotal` / `returnedItemsWeightTotal`, and typed range. `EntryCatalogChannel.weight` and `EntryCatalogScope.weight` are model-independent curation weights; model-facing JSON may project them under its own vocabulary. Each resource-mode `EntryCatalogItem` is a nonempty, default-first array of flat `EntryCatalogChannel` objects; a scope is the one-element `EntryCatalogScopeGroup`. Exact matcher mode returns flat `MatchEvidence` locations. Pagination is the materialization bound; no path-owning channel wrapper, hidden `matches`, `pathnames`, or overflow-only result collection exists.
|
|
351
|
-
- §scheme-catalog-parse-issues An `EntryCatalogChannel` may carry a positive `parseIssues` count when its exact content projection reported parser recovery sites. Zero and unavailable evidence are omitted. This is advisory metadata and never a validity gate or operation failure.
|
|
352
|
-
- Capability ctx (see §3.bis): `SchemeCtx`, `StreamSubscription`, and the domain capabilities. Entry authors additionally receive `EntryOperationCaps`, `EntryAddress`, and typed standard-operation results. `editBatch` receives the numeric splices of one operation for one canonical resource and channel; it validates against one snapshot and commits one revision or none ({§edit-batch}). Core calls it separately for each authored EDIT, in execution order.
|
|
353
|
-
|
|
354
|
-
Behavior ships as `export default class` (one class per file, static methods) — the ecosystem class paradigm. Type-only modules and the barrel are the only non-class files.
|
|
355
|
-
|
|
356
|
-
### §network-address Network address identity
|
|
357
|
-
|
|
358
|
-
`NetworkAddress.from(target)` is the single non-secret normalization path for
|
|
359
|
-
HTTP and WebSocket targets. It returns the exact addressed `scheme`, canonical
|
|
360
|
-
entry `authority` and `pathname`, a fragmentless and credential-free transport
|
|
361
|
-
`url`, and whether userinfo was present so the handler can reject it.
|
|
362
|
-
|
|
363
|
-
| Component | Entry identity | Transport URL | Plurnk channel |
|
|
364
|
-
|------------------|-----------------------------------------------------|---------------|----------------|
|
|
365
|
-
| Scheme | Exact `http`, `https`, `ws`, or `wss` | Yes | No |
|
|
366
|
-
| Host | Canonical WHATWG hostname | Yes | No |
|
|
367
|
-
| Port | Non-default port | Yes | No |
|
|
368
|
-
| Path | Canonical pathname | Yes | No |
|
|
369
|
-
| Query | Serialized order, duplicates, and explicit empty `?` | Yes | No |
|
|
370
|
-
| Fragment | No | No | Yes |
|
|
371
|
-
| Userinfo | No | No | No |
|
|
372
|
-
|
|
373
|
-
The canonical storage coordinate is authority `<host>[:<port>]` plus pathname
|
|
374
|
-
`<path>[?<query>]`, keyed together with workspace and the exact
|
|
375
|
-
addressed scheme. `NetworkAddress.render({ scheme, authority, pathname })` is
|
|
376
|
-
its model-facing inverse: it applies the Plurnk lexical target spelling
|
|
377
|
-
{§path-parentheses} after reconstructing the exact address. Transport URLs and
|
|
378
|
-
storage identity never carry that syntax layer. Routing aliases select a
|
|
379
|
-
handler; they do not collapse resource identity.
|
|
380
|
-
Scheme metadata is statement-level input under {§scheme-metadata-modifier}; it
|
|
381
|
-
is never a `NetworkAddress` component.
|
|
382
|
-
|
|
383
|
-
### §mimetype-classifier Mimetype classification — `MimetypeClassifier`
|
|
384
|
-
|
|
385
|
-
- `MimetypeClassifier.isBinary(mimetype)` — pure taxonomy for a registry-free boundary. Delegates to `classifyMimetype` from `@plurnk/plurnk-mimetypes`; a consumer with a configured `Mimetypes` service uses `Mimetypes.classify()` so installed handler declarations remain authoritative ({§mimetype-classification}).
|
|
386
|
-
- `MimetypeClassifier.isHtml(mimetype)` — recognizes the normalized web-projection family: `text/html` and `application/xhtml+xml`.
|
|
387
|
-
- `MimetypeClassifier.isJson(mimetype)` - `application/json` plus `+json` variants, used only by result summarization.
|
|
388
|
-
- `MimetypeClassifier.normalizeAutoText(mimetype)` — `text/plain` / null / undefined → `TEXT_PRIMITIVE_MIMETYPE` (`text/markdown`).
|
|
389
|
-
- §mimetype-verbatim-transfer `MimetypeClassifier.isTransferCompatible(source, destination, sourceClassification?)` permits verbatim COPY/MOVE between equal mimetypes, or from any textual source into `text/plain` or `text/markdown`. Unequal structured or binary destination types remain incompatible. Configured consumers supply the source's resolved `{ binary }` classification; registry-free callers use the shared taxonomy. Compatibility never converts content or changes either channel's declared type.
|
|
390
|
-
- `TEXT_PRIMITIVE_MIMETYPE` — `"text/markdown"` (named export from the same module).
|
|
391
|
-
|
|
392
|
-
### §scheme-projection Projection capability
|
|
393
|
-
|
|
394
|
-
§scheme-resource-capture `ctx.resources.capture(addresses)` acquires ordered
|
|
395
|
-
exact resource/channel snapshots through Core's shared source-selection path.
|
|
396
|
-
It returns bytes plus immutable receipt descriptors, or the acquisition failure
|
|
397
|
-
without delivering anything. It neither performs SEND nor transfers resource
|
|
398
|
-
ownership. `MessageAttachments` opts a message recipient into the common
|
|
399
|
-
metadata shape under {§send-resource-attachments}; other recipients retain
|
|
400
|
-
their own metadata vocabulary.
|
|
401
|
-
|
|
402
|
-
Acquisition schemes delegate model-facing projection to the consumer's one
|
|
403
|
-
configured mimetype framework. They neither instantiate readers nor discard source
|
|
404
|
-
bytes merely because no readable projection exists.
|
|
405
|
-
|
|
406
|
-
| Surface | Contract |
|
|
407
|
-
| --------------------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
408
|
-
| `readable(content, mimetype)` | Project an acquired Unicode representation. |
|
|
409
|
-
| `binary(chunks, mimetype)` | Return bounded source `bytes`, nullable `readable: ProjectedText`, and the configured `projectionIdentity`, even without a reader; consume one async byte source under {§mimetype-binary-input}. |
|
|
410
|
-
| `identity(mimetype)` | Return the opaque identity of configured projection behavior for cache and materialization freshness. |
|
|
411
|
-
| `isBinary(mimetype)` | Classify through the configured registry; installed handler declarations remain authoritative. |
|
|
412
|
-
| `parseIssues(content, mimetype)` | Return a nonnegative parser-recovery count, or omit unavailable evidence, under {§mimetype-parse-issues}. |
|
|
413
|
-
| `ProjectedText` | Derived Unicode plus its output mimetype, source mimetype, and opaque projection identity. |
|
|
414
|
-
|
|
415
|
-
A readable projection is present even when its `content` is `""`; only `null`
|
|
416
|
-
denotes absence. Consumers must not infer projection presence from content
|
|
417
|
-
length. Thrown readable, identity, and classification calls are execution
|
|
418
|
-
failures whose causes propagate; they must never be converted to `null`.
|
|
419
|
-
Parser-recovery inspection is deliberately non-gating: successful clean
|
|
420
|
-
inspection returns `0`; tooling failure or structural degradation surfaces a
|
|
421
|
-
Notice where available and returns `undefined`.
|
|
422
|
-
`ProjectionInputLimitError` is the projection boundary's exported name for the
|
|
423
|
-
configured mimetype framework's typed bounded-input failure.
|
|
424
|
-
|
|
425
|
-
### §slicer-window Positional windows without content - `Slicer.window`
|
|
426
|
-
|
|
427
|
-
`Slicer.window(marker, total, unit)` resolves a one- or two-coordinate marker against a
|
|
428
|
-
total alone, with the exact normalization, sentinels, extents, and 416 facts of `lines()`, for
|
|
429
|
-
a resource whose positions are not text lines in memory: the byte view of a binary
|
|
430
|
-
(`unit: "byte"`, {§read-bytes} in core). A sentinel selects nothing (`start: null`); a
|
|
431
|
-
region of four coordinates has no meaning over a window and is refused.
|
|
432
|
-
|
|
433
|
-
### §slicer-text-algebra Text-region slicing and replacement - `Slicer`
|
|
434
|
-
|
|
435
|
-
`Slicer` owns one text algebra for every textual mimetype:
|
|
141
|
+
## §capability-ctx Capability context and subscriptions
|
|
436
142
|
|
|
437
|
-
|
|
143
|
+
`SchemeCtx` is the operation-scoped capability surface (`{ workspaceId, sessionId, loopId, turnId, writer, signal, logEntryId? }`, {§execution-output-identity}) injected by the consumer:
|
|
144
|
+
|
|
145
|
+
| Capability | Contract |
|
|
438
146
|
|---|---|
|
|
439
|
-
|
|
|
440
|
-
|
|
|
441
|
-
|
|
|
442
|
-
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
§range-starts-at-one A two-coordinate range starts at 1. `<0>` is a single-position
|
|
450
|
-
prepend anchor, never a range start: `<0,M>` is refused 416 by `lines()`,
|
|
451
|
-
`linesRaw()`, `textReplacement()`, `lineMarkerEdit[Batch]()`, `window()` and
|
|
452
|
-
`page()`, on empty content and empty result sets too, and never clamped to
|
|
453
|
-
`<1,M>`. The refusal's detail states the zero start in the range's unit; its
|
|
454
|
-
`recovery` never rebuilds the refused range ({§diagnostic-observation}):
|
|
455
|
-
|
|
456
|
-
| Unit | `recovery` |
|
|
147
|
+
| `entries` & `channels` | Direct storage (`address`, `read`, `write`, `delete`, optional scheme-private `attributes`) and standard `operations` (`editBatch`, `find`, `send`), plus `channels` (`append`, `replace`, `setState`), bound by Core to the resolved workspace coordinate ({§scheme-surface}). |
|
|
148
|
+
| `notify`, `projection`, `resources`, `messages` | `notify.streamEvent` (between-turn client metadata signal), `projection`, `resources.capture`, and `messages`. |
|
|
149
|
+
| `interactions` | `request(ClientInteractionRequest, signal?) -> Promise<ClientInteractionResolution>` ({§provider-request-accounting}). |
|
|
150
|
+
| `subscriptions` | `open(pathname, handle)` returns the sole capability retainable after the handler call returns: `StreamSubscription` (`AbortSignal` + `notifyChunk(channel, chunk, mimetype?)` + `close(result, summary?, channelResults?)` that validates `ChannelProducerResult` overrides, settles channel states, unregisters the live handle, and wakes the session). |
|
|
151
|
+
| Proposals (`applyResolution`) | A side-effecting scheme proposes by returning `status: 202`; on acceptance, Core calls `applyResolution({ attrs, metadata, body }, ctx)` ({§log-wire-format}). Accepted `EDIT` proposals may return an aggregate `editReceipt` (using `reviewer-replaced` when the resolver replaced the body). |
|
|
152
|
+
|
|
153
|
+
## §resource-tree-scheme Module slice and resource trees
|
|
154
|
+
|
|
155
|
+
| Type / concern | Contract |
|
|
457
156
|
|---|---|
|
|
458
|
-
|
|
|
459
|
-
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
as the receipt's requested range, and returns scope-normalization evidence for
|
|
464
|
-
the ordinary non-striking warning. Text and byte views, including empty resources,
|
|
465
|
-
use the same rule. The strict algebra above remains unchanged for mutation,
|
|
466
|
-
removal, and transfer operands. Single-position sentinels, character regions,
|
|
467
|
-
and other invalid endpoints are not reinterpreted.
|
|
468
|
-
|
|
469
|
-
As an unadvertised ingestion tolerance, `Slicer` accepts
|
|
470
|
-
`<startLine,startColumn,endLine>` and immediately lowers it to the complete
|
|
471
|
-
four-coordinate region ending after the final code point of `endLine`.
|
|
472
|
-
Successful results carry schemes-owned, boundary-validated normalization
|
|
473
|
-
evidence containing both the authored and canonical coordinates. Producers do
|
|
474
|
-
not emit or proactively teach the tolerated form.
|
|
475
|
-
|
|
476
|
-
A harmless end-bound overshoot clamps rather than erroring: an oversized line
|
|
477
|
-
range ends at the final line, an exact end line beyond the content ends at EOF,
|
|
478
|
-
and an oversized end column ends at its line's final code point. Start-line and
|
|
479
|
-
start-column overshoots remain 416 errors.
|
|
480
|
-
|
|
481
|
-
- `Slicer.lines(content, marker)` returns the selected text, source
|
|
482
|
-
`startLine`, and complete resolved `region`; `Slicer.linesRaw` preserves
|
|
483
|
-
original newline separators for COPY/MOVE source transfer.
|
|
484
|
-
- `Slicer.textReplacement(content, marker, body)` lowers a line shorthand or
|
|
485
|
-
exact region to one `{start,end,body}` replacement against the source
|
|
486
|
-
snapshot.
|
|
487
|
-
- `Slicer.lineMarkerEdit` applies one replacement.
|
|
488
|
-
- `Slicer.lineMarkerEditBatch` validates all replacements against one snapshot,
|
|
489
|
-
resolves an identical twin, two insertions at one point, and an evidenced one-line shared
|
|
490
|
-
endpoint (reported in `merges`, receipts from `applied`), rejects every other overlap, and
|
|
491
|
-
applies all or none. An overlap Problem states the
|
|
492
|
-
failure once for the whole batch: every conflicting pair with its relation in
|
|
493
|
-
`conflicts`, the regions that conflict with nothing in `cleanRegions`, the
|
|
494
|
-
first pair in `conflictingRegions`, plus `editCount` and `applied: 0`. The
|
|
495
|
-
prose states counts and, for a shared endpoint, the line both regions claim,
|
|
496
|
-
its text and the two regions; it adds no second line-only representation.
|
|
497
|
-
- `Slicer.page(items, marker, options?)` is the separate ordered-result
|
|
498
|
-
pagination helper; it accepts only one or two integer positions and can name
|
|
499
|
-
an operation-owned range unit. An empty result set satisfies any well-formed
|
|
500
|
-
request as an empty page; only an inverted range fails.
|
|
501
|
-
- `Slicer.coversAvailable(range)` derives whether a successful range selected
|
|
502
|
-
the complete available extent; that fact is never serialized separately.
|
|
503
|
-
|
|
504
|
-
A successful line or pagination selection carries the contracts-owned
|
|
505
|
-
`RangeExtent` {§range-extent}; a 416 carries the same extent without
|
|
506
|
-
`returned`. Exact regions use `region` instead. An exact-region failure,
|
|
507
|
-
including a failed tolerated three-coordinate scope, carries
|
|
508
|
-
`requestedCoordinates` exactly as authored; an invalid-arity text scope does
|
|
509
|
-
likewise. Both carry `columnKind: "unicodeCodePoints"`.
|
|
510
|
-
|
|
511
|
-
### §path-extension-mimetype Path-extension mimetype — `PathMimetype`
|
|
512
|
-
|
|
513
|
-
- `PathMimetype.resolve(pathname, defaultMimetype, mimetypes)` — pathname extension → `Mimetypes.detect({ ext })`; falls back to `defaultMimetype` when no extension. text/plain auto-normalizes to text/markdown.
|
|
514
|
-
|
|
515
|
-
### Result families — `Results`
|
|
516
|
-
|
|
517
|
-
- `Results.isEntry` / `Results.isProposal` / `Results.isPassthrough` — guards for the optional conventional result shapes.
|
|
518
|
-
- `Results.isErrorStatus(status)` — `status >= 400`.
|
|
519
|
-
- `Results.problem(owner, code, status, detail, extensions?)` — build and validate RFC 9457 Problem Details with a stable `https://problems.plurnk.xyz/<owner>/<code>` type.
|
|
520
|
-
- `Results.failure(owner, code, status, detail, fields?, extensions?)` — build and validate a failed operation result.
|
|
521
|
-
- `Results.assert(result)` — validate the complete success/failure discrimination and reject malformed extension output.
|
|
522
|
-
- `Results.assertMatchEvidence(evidence)` / `assertMatchEvidenceList(evidence)` - enforce the exact `{ locator?, region?, enclosingRegion?, matched? }` shape and shared `TextRegion` contract.
|
|
523
|
-
- `Results.assertReadResult(result)` - validate the universal operation result plus any `region` and `matches` it exposes.
|
|
524
|
-
- `Results.attachInstance(result, uri)` — attach the durable occurrence URI to a failed result.
|
|
525
|
-
|
|
526
|
-
A handler owns its failure classification and explanation. A retained failure's
|
|
527
|
-
`instance` continues to identify its original occurrence; reading it does not create
|
|
528
|
-
a different failure. When absent, the daemon adds the committed log coordinate. A
|
|
529
|
-
malformed handler result is an extension contract violation and fails hard; the
|
|
530
|
-
consumer does not invent a fallback error or reinterpret arbitrary fields.
|
|
531
|
-
The same discrimination applies to every `SchemeCtx` capability result:
|
|
532
|
-
entries and channels never return a bare failure status.
|
|
533
|
-
|
|
534
|
-
### Matcher dispatch - `Matcher` {§matcher-dispatch}
|
|
535
|
-
|
|
536
|
-
- `Matcher.matchAgainstContent(body, content, mimetype, mimetypes, diagnostic?)` is the body-matcher adapter over `Mimetypes.query` (glob/regex/jsonpath/xpath). The optional projector supplies one bounded caught-parser `diagnostic` extension without transferring error-formatting policy into this package or splicing implementation text into Problem prose.
|
|
537
|
-
- A match returns status 200 and `matches: MatchEvidence[]`.
|
|
538
|
-
`MatchEvidence` is `{locator?, region?, enclosingRegion?, matched?}`. `locator` preserves a structural locator;
|
|
539
|
-
`matched` is the matched text itself, present for the regex and glob dialects so a match row
|
|
540
|
-
reads without a READ;
|
|
541
|
-
`region` is the exact selected source span; `enclosingRegion` is context when
|
|
542
|
-
the handler can locate only the containing text. Both are complete four-coordinate
|
|
543
|
-
`TextRegion` values. Context does not authorize exact-source mutation.
|
|
544
|
-
Each item must contain at least one of `locator`, `region`, or `enclosingRegion`; other fields violate
|
|
545
|
-
the shared evidence contract.
|
|
546
|
-
- The matcher is a boolean resource selector. It does not replace content with matched values or choose a retrieval window. FIND owns selection and pagination; exact READ owns text projection.
|
|
547
|
-
- Empty results return 204 with `matches: []`; `UnsupportedDialectError` maps to 415; `InvalidExpressionError` maps to 400 with the bounded native parser cause when one was projected; `QueryParseFailureError` maps to 203 with raw content, text/markdown, and `reason`.
|
|
548
|
-
- A multi-resource matcher omits candidates that return 415 when at least one candidate supports the dialect. If no candidate supports it, the matcher returns the first exact 415 Problem. An unreadable binary marker therefore cannot poison a repository-wide text search or masquerade as a match.
|
|
549
|
-
|
|
550
|
-
### §capability-ctx §3.bis Capability ctx — the stable trusted-extension surface
|
|
551
|
-
|
|
552
|
-
Scheme extensions are trusted in-process Node.js code. `SchemeCtx` is not a
|
|
553
|
-
sandbox or a security boundary; an installed extension already has the process's
|
|
554
|
-
authority. It is the stable semantic API that keeps extensions independent of
|
|
555
|
-
database schemas, prepared-statement names, and private service modules.
|
|
556
|
-
**Interfaces only**: this repo exports the contract and the consumer injects
|
|
557
|
-
its implementation.
|
|
558
|
-
|
|
559
|
-
`SchemeCtx` carries per-dispatch identity (`workspaceId`/`workerId`/`loopId`/`turnId`/`writer`/`signal`, and during proposal application `logEntryId`, the operation row being settled, so a scheme can keep what it did on that row, {§log-mutation-patch}) plus capability namespaces:
|
|
560
|
-
|
|
561
|
-
§scheme-ctx-workspace-environment `workspaceId` selects shared Functionality and admission policy; `workerId` attributes the operation and selects its journal. Core binds the addressed resource before supplying this context. Handlers must use that binding rather than reinterpret caller identity as resource ownership ({§runtime-resource-binding}).
|
|
562
|
-
|
|
563
|
-
- `entries` — direct storage over the scheme and authority already bound by core
|
|
564
|
-
(`address`/`read`/`write`/`delete`) plus `operations`, the standard PLURNK
|
|
565
|
-
`EDIT`/`FIND`/`SEND` implementations for entry-bearing schemes. READ selection
|
|
566
|
-
and model-facing projection belong to the consumer's universal dispatch
|
|
567
|
-
({§universal-read-composition}); `entries.read` returns stored channels, not
|
|
568
|
-
a projected READ receipt.
|
|
569
|
-
`address(pathname)` returns the bound resource's URI without fetching or
|
|
570
|
-
creating it. Links preserve the bound resource authority, never a
|
|
571
|
-
caller-relative namespace.
|
|
572
|
-
A write may omit channel state to select the `static` default; a successful
|
|
573
|
-
storage read always returns each channel's persisted lifecycle state.
|
|
574
|
-
Optional `attributes` are scheme-private durable metadata. They are scoped to
|
|
575
|
-
that entry, replaced only when explicitly written, and never projected into
|
|
576
|
-
model content, catalogs, or client entry data.
|
|
577
|
-
Standard operations are bound to the canonical workspace coordinate selected
|
|
578
|
-
before the handler receives this context. A handler may implement its own op method
|
|
579
|
-
instead. In particular, a handler with `find()` owns FIND; one without it
|
|
580
|
-
receives the standard stored-entry behavior.
|
|
581
|
-
- `channels` — content writes + state (`append`/`replace`/`setState`).
|
|
582
|
-
- `notify` — between-turn client signal (`streamEvent`, metadata-only); not model-facing. Wake delivery belongs to stream settlement, not notification.
|
|
583
|
-
- `projection` — the text and bounded-byte projection capability in {§scheme-projection}. Acquisition schemes own source representations; they do not instantiate or second-guess the readers. `null` means no readable projection.
|
|
584
|
-
- §scheme-interactions `interactions` — `request(ClientInteractionRequest, signal?)`
|
|
585
|
-
awaits the contracts-owned interaction and returns its
|
|
586
|
-
`ClientInteractionResolution` ({§client-interaction-wire}). Core binds the
|
|
587
|
-
current operation identity, persistence, client projection, and cancellation;
|
|
588
|
-
the scheme retains no callback, interaction identity, or private lifecycle.
|
|
589
|
-
An optional signal narrows, never replaces, the operation's cancellation scope.
|
|
590
|
-
- §scheme-subscriptions `subscriptions` — one streaming lifecycle:
|
|
591
|
-
|
|
592
|
-
| Surface | Lifetime | Contract |
|
|
593
|
-
| --------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------- |
|
|
594
|
-
| `open(pathname, handle)` | Operation | Bind durable and live identity, return the exact object, and route cancellation through its signal/handle. |
|
|
595
|
-
| Returned `StreamSubscription` | Retainable | `AbortSignal` plus fused chunk publication and terminal settlement; the only retainable capability. |
|
|
596
|
-
|
|
597
|
-
`notifyChunk` appends and emits one stream event. Its optional stateless
|
|
598
|
-
`mimetype` retypes the channel only when the stored type differs.
|
|
599
|
-
`close(result, summary?, channelResults?)` validates and persists the exact
|
|
600
|
-
universal `ChannelProducerResult`, settles every channel with an exact named
|
|
601
|
-
result override or that universal default, unregisters the live handle, and
|
|
602
|
-
wakes the worker. Channel state is derived from its settled result.
|
|
603
|
-
`summary` is presentation only; it never replaces or reconstructs the result.
|
|
604
|
-
An override names an existing channel and is itself an exact
|
|
605
|
-
`ChannelProducerResult`; invalid overrides fail before any settlement changes.
|
|
606
|
-
This permits one multi-channel producer to preserve successful evidence beside
|
|
607
|
-
an independently failed representation without inventing another settlement
|
|
608
|
-
path or reducing a result to a state label.
|
|
609
|
-
|
|
610
|
-
`EntryCoordinates.resolve(target, authority)` supplies the same canonical
|
|
611
|
-
coordinate Core binds ({§scheme-address}); handlers do not invent another
|
|
612
|
-
interpretation of namespace authorities.
|
|
613
|
-
|
|
614
|
-
The consumer passes exactly this public context to every handler. Bundled
|
|
615
|
-
adapters that also implement daemon-owned lifecycle behavior receive those
|
|
616
|
-
collaborators separately at construction or binding time; consumers must not
|
|
617
|
-
decorate `SchemeCtx` with database handles, registries, tokenizers, notifier
|
|
618
|
-
callbacks, or other private service state.
|
|
619
|
-
|
|
620
|
-
§scheme-ctx-lifetime `SchemeCtx` belongs to one operation call. A handler may
|
|
621
|
-
use it for the duration of that call, including asynchronous work awaited by
|
|
622
|
-
the call, but must not retain the context or any other extracted capability
|
|
623
|
-
after the handler returns. A streaming handler may retain only the exact
|
|
624
|
-
`StreamSubscription` returned by `subscriptions.open`; its bound methods carry
|
|
625
|
-
that subscription's identity without retaining the general context. Other
|
|
626
|
-
retained handler-owned resources follow {§handler-lifecycle}.
|
|
627
|
-
|
|
628
|
-
**Proposals are not a capability.** A side-effecting scheme proposes by *returning* a `ProposalResult` (status 202); the engine owns the resolution lifecycle. On acceptance it calls the handler's optional `applyResolution({ attrs, metadata, body }, ctx)` hook. `attrs` is the payload returned by the proposing operation, `metadata` is the exact statement-level scheme metadata retained only across the live proposal pause, and `body` is the resolver-approved body, when present. Metadata is never added to proposal attrs or client projection. The hook returns a `ProposalApplyResult`: a status below 400 completes the accept; a failure preserves the applying scheme's Problem Details as the proposal's final result.
|
|
629
|
-
|
|
630
|
-
§scheme-edit-proposal-receipt An accepted EDIT proposal may return its final
|
|
631
|
-
aggregate `editReceipt` alongside its per-row model-facing `result`. A resolver
|
|
632
|
-
replacement must use the reviewer-replaced form from
|
|
633
|
-
{§scheme-edit-batch-receipt}. Core consumes that aggregate as transient batch
|
|
634
|
-
coordination and COPY/MOVE composition input; it persists only per-row receipts
|
|
635
|
-
or ordered resource effects.
|
|
636
|
-
|
|
637
|
-
## §4 What's NOT in this repo
|
|
638
|
-
|
|
639
|
-
DB-coupled entry/channel machinery — CRUD + write-time tokenization, the
|
|
640
|
-
standard entry operations, channel writes, and subscription registry — lives
|
|
641
|
-
in the consumer. This package defines their stable interfaces and pure helpers
|
|
642
|
-
({§scheme-ctx-entries}).
|
|
643
|
-
|
|
644
|
-
## §5 Trusted extension contract
|
|
645
|
-
|
|
646
|
-
Installed schemes may legitimately own network connections, subprocesses,
|
|
647
|
-
caches, pools, or other host resources under {§handler-lifecycle}. These powers
|
|
648
|
-
are why installation is a trust decision and why contained interoperability
|
|
649
|
-
belongs in MCP rather than an in-process extension.
|
|
650
|
-
|
|
651
|
-
The supported compatibility boundary is `@plurnk/plurnk-schemes`. Extensions
|
|
652
|
-
should not import private service modules, depend on database layout, or call
|
|
653
|
-
prepared statements directly: those are unstable implementation details, not
|
|
654
|
-
additional extension capabilities. Use `SchemeCtx` or propose a new semantic
|
|
655
|
-
capability when the public surface cannot express a coherent extension.
|
|
656
|
-
|
|
657
|
-
## Module slice
|
|
658
|
-
|
|
659
|
-
§scheme-module-slice **A daemon module contributes to the scheme kind through types this package
|
|
660
|
-
owns.** They complete the module contract's slices ({§module-seam-slices}).
|
|
661
|
-
|
|
662
|
-
| Type | Contract |
|
|
663
|
-
| --- | --- |
|
|
664
|
-
| `SchemeRegistrationSeam` | `registerScheme(name, handler)` adds one process-wide addressable `SchemeHandler`; scheme readiness and model-facing capability publication remain the host's. |
|
|
665
|
-
| `ResourceTreeRegistrationSeam` | `registerResourceTreeScheme(name, source)` exposes named read-only resource trees through {§resource-tree-scheme}, without giving the module a storage interface. |
|
|
666
|
-
| `RuntimeSchemeFacet` | A scheme face over a module's own resources. It claims only its own path subtree and there is the scheme's whole live half: READ and FIND preparation, FIND, EDIT, SEND and KILL are its own wherever it implements them, and its `manifest` states what the executor's output contract does not — the resource authority, channels, default channel and `writableBy` that govern every claimed coordinate. Unclaimed coordinates keep the standard executor-output behavior. A runtime carries one on its registration ({§executor-module-slice}), and a Functionality family's manager may expose one ({§functionality-adapter}). |
|
|
667
|
-
|
|
668
|
-
§resource-tree-scheme **A tree supplies resources; the host supplies their entry projections.**
|
|
669
|
-
`ResourceTreeSource.trees(workspaceId)` returns the currently available trees keyed by URI
|
|
670
|
-
authority. Each tree lists relative resource paths and supplies a {§scheme-source-bytes}
|
|
671
|
-
`ByteSource` for a relative path. Listing is authoritative; a source's null size means absent.
|
|
672
|
-
The source owns containment and acquisition, including optional native-file identity.
|
|
157
|
+
| `SchemeRegistrationSeam` | `registerScheme(name, handler)` registers a process-wide `SchemeHandler` ({§module-seam-slices}). |
|
|
158
|
+
| `RuntimeSchemeFacet` | Claims a path subtree under an executor or Functionality scheme ({§executor-role}, {§functionality-adapter}) with its own `manifest` (`authority`, `channels`, `defaultChannel`, `writableBy`) and live `prepareRepresentation`, `prepareFind`, `find`, `editBatch`, `send`, and `kill` hooks while unclaimed coordinates keep standard executor-output behavior. |
|
|
159
|
+
| `ResourceTreeRegistrationSeam` | `registerResourceTreeScheme(name, source)` exposes read-only `ResourceTreeSource.trees(workspaceId)` keyed by URI authority (`name://authority/path`, resource authority, folder scopes, dynamic MIME `body` channel). |
|
|
160
|
+
| Tree publication & projection | Demand-loaded entries on `READ` and `COPY`; model/client writes are forbidden (`403`). The host detects MIME, applies the input bound, and runs the installed MIME projection while keeping original `ByteSource` bytes for byte views, transfers, and attachments. |
|
|
161
|
+
| Tree `FIND`, withdrawal & failures | `FIND` refreshes resources in the requested authority/path scope and evicts withdrawn authorities or absent paths (an exact missing `READ` never returns cached content). Optional `refusal(cause, address)` translates recognized source errors into failure results (`status >= 400`). |
|
|
673
162
|
|
|
674
|
-
|
|
675
|
-
| --- | --- |
|
|
676
|
-
| Addressing | `name://authority/path`; resource authority, ordinary folder scopes, a dynamic MIME `body` channel. READ and source transfers share exact-resource preparation. |
|
|
677
|
-
| Publication | Demand-loaded entries, not eagerly injected bodies. Model and client writes are forbidden; only the host writes projections. |
|
|
678
|
-
| Projection | The host detects MIME, applies the configured input bound, and uses the installed MIME projection. Original bytes remain the source of byte views, transfers and attachments. Refresh replaces obsolete projection metadata too. |
|
|
679
|
-
| FIND | The host refreshes resources in the requested path/authority scope, including descendants needed for shallow folder summaries, then performs ordinary pattern selection. |
|
|
680
|
-
| Withdrawal | FIND removes cached projections for withdrawn authorities and absent resources in its refreshed scope. An exact missing READ never returns cached content. Historical log receipts are unchanged. |
|
|
681
|
-
| Failures | Optional `refusal(cause, address)` translates recognized source failures into ordinary failure results (status ≥400); null preserves the host's missing-file result or propagates the original unexpected exception. Projection and persistence failures must not be recast as source failures. |
|
|
682
|
-
|
|
683
|
-
The module does not receive scopes, matchers, database handles, or entry lifecycle controls through
|
|
684
|
-
this source interface. A tree registration uses the ordinary scheme registry, with the same unique
|
|
685
|
-
name, readiness, capability and lifecycle rules as other schemes.
|
|
686
|
-
|
|
687
|
-
## §scheme-discovery §6 Discovery & registration (third-party)
|
|
688
|
-
|
|
689
|
-
A scheme handler is discovered and registered with **zero first-party involvement** — install it, it lights up. The contract:
|
|
690
|
-
|
|
691
|
-
- **Declare** the exact string `plurnk.kind: "scheme"` in `package.json` ({§extension-kind}). Then name the scheme(s) it owns in one of two forms: `plurnk.schemes: [{ name, export }, …]` (canonical — one entry per scheme, `export` naming the handler-class export) or `plurnk.name: "<scheme>"` (one-scheme shorthand for the `default` export). One package may own several names inside this kind; each name has exactly one owner.
|
|
692
|
-
- **`SchemeDiscovery` owns the scan (this package).** `SchemeDiscovery.discover({ cwd? })` walks *all* of `node_modules` — scoped (`@acme/foo`) and unscoped — and returns `{ schemes: {name, packageName, exportName?}[], packageAttributions, skipped }` for every package declaring `plurnk.kind === "scheme"`. Scope-agnostic, so a third party under their own scope is found with no first-party allow-list; two names claiming one prefix fail-hard (across packages or within one), as does a malformed `plurnk.schemes` (locality of error, not a silent skip). It returns **descriptors, not handlers** — contract-only, it never imports a scheme package; the consumer imports each `packageName` and registers `new mod[exportName ?? "default"]()`, applying in-tree precedence. The scan primitives — package enumeration, the `PLURNK_EXTENSIONS_TRUSTED_ONLY` trust gate, the deployment-root `node_modules` walk — are one implementation in `@plurnk/plurnk-meta`, shared by every kind's scanner; `SchemeDiscovery` adds only the scheme-descriptor shape on top.
|
|
693
|
-
- **Attribution is package-authored.** `packageAttributions` carries one canonical validated static tag list per admitted package; a loaded handler may additionally implement the shared runtime `attributions` function ({§extension-attribution}). The consumer owns no other attribution policy.
|
|
694
|
-
- **The framework stays contract-only.** `@plurnk/plurnk-schemes` does not depend on scheme extensions. The daemon declares its bundled extensions as direct dependencies, and additional scheme extensions are installed at the application root. Each declares the framework as a peer dependency using the repository's normal same-minor compatibility range; the framework itself is ignored by discovery because it has no `plurnk.kind`.
|
|
695
|
-
- **The default bundle is the daemon's own `dependencies`**, not an aggregator package. Installing `plurnk-core` surfaces the first-party schemes; any other leaf — first-party or third-party — is added by installing it, and scope-agnostic discovery lights it up identically. No bundle is ever a gate.
|
|
696
|
-
- **Trust.** The scanner enforces the shared predicate before attribution or scheme-field validation and returns withheld package names in `skipped`; the host owns presentation ({§extension-trust-boundary}).
|
|
697
|
-
|
|
698
|
-
## Message sources
|
|
699
|
-
|
|
700
|
-
§message-source-scheme Protocol modules register `MessageScheme` or compose its hooks into
|
|
701
|
-
their existing scheme. Core's `SchemeCtx.messages` materializes retained messages in that
|
|
702
|
-
scheme for ordinary READ/FIND/COPY and delivers exact-address SEND replies under
|
|
703
|
-
{§send-response-receipt}. The materialization is a derived representation, never the source
|
|
704
|
-
of message body or reply state. The protocol module owns URI identity; Core owns durable
|
|
705
|
-
admission and correlation. Message representations reject mutation while remaining SEND
|
|
706
|
-
recipients. Scratch entries and protocol artifacts retain their own existing write contracts.
|
|
707
|
-
|
|
708
|
-
§message-immutable An EDIT, COPY or MOVE onto, or KILL of, a message address is
|
|
709
|
-
refused 405 `message-immutable` with no `recovery` ({§diagnostic-observation}); its detail
|
|
710
|
-
names the address as an immutable received message:
|
|
711
|
-
`` `message://tester/bde40185` is a received message; it cannot be edited, moved or killed. ``
|
|
712
|
-
|
|
713
|
-
§problems-schemes **Selection and metadata Problems.** Every code minted here, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
|
|
714
|
-
|
|
715
|
-
| code | status | contract |
|
|
716
|
-
|---|---:|---|
|
|
717
|
-
| `range-not-satisfiable` | 416 | The range lies outside the available extent (a line before 1, past the end, or a column outside its line; a result page names the unit it pages). Recovery: Choose a range within the available extent. Some refusals state the extent or show the working form of the construct instead; none rebuilds the input into another scope ({§diagnostic-observation}): a result position outside its page the page's bound (`Choose positions within 1..3.`), a region holding a zero line or column the counting rule of {§text-scope-semantics} (`Lines and columns count from 1.`), an inverted region the form's order (`An exact region names its earlier position first: <SL,SC,EL,EC>.`), a `<-N,-1>` range the line extent (`-1 is the only position counted from the end; lines run 1..92.`), and a line range from 0 the line forms ({§range-starts-at-one}). |
|
|
718
|
-
| `overlapping-edits` | 409 | Two EDIT regions overlap, or a whole-resource replacement cannot coexist with another EDIT. Recovery: Submit the whole-resource replacement by itself. |
|
|
719
|
-
| `invalid-expression` | 400 | The *dialect* matcher expression is invalid. Recovery: Revise the matcher expression. |
|
|
720
|
-
| `unsupported-dialect` | 415 | The *dialect* matcher is not supported for *mimetype*. Recovery: Use a matcher supported by the resource mimetype. |
|
|
721
|
-
| `metadata-unsupported` | 400 | Message metadata accepts only attachments. |
|
|
722
|
-
| `attachments-invalid` | 400 | attachments must be an array of non-empty resource addresses. |
|
|
723
|
-
| `metadata-invalid` | 400 | [metadata] must be a JSON array of option objects; every element is an object. |
|
|
163
|
+
## §scheme-discovery Third-party discovery
|
|
724
164
|
|
|
725
|
-
§
|
|
165
|
+
`SchemeDiscovery.discover({ cwd? })` scans `node_modules` via `@plurnk/plurnk-meta` ({§extension-discovery}) for packages declaring `plurnk.kind === "scheme"` (`plurnk.schemes: [{ name, export }]` or `plurnk.name`), failing hard on duplicate scheme prefixes or malformed declarations and returning `{ schemes, packageAttributions, skipped }` descriptors without importing handler modules.
|
|
726
166
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
| [metadata] must be a JSON array. | a malformed JSON metadata modifier |
|
|
731
|
-
| [metadata] must be a JSON array of option objects; every element is an object. | a non-object element supplied to an object-only metadata owner |
|
|
732
|
-
| A scope requires one position or an inclusive two-position range. | a scope of unsupported arity |
|
|
167
|
+
## §message-source-scheme Message sources
|
|
168
|
+
|
|
169
|
+
Protocol modules register `MessageScheme` or compose its hooks so `SchemeCtx.messages` materializes retained inbound messages for `READ`, `FIND`, and `COPY` and routes exact-address `SEND` replies under {§message-completion}. Any `EDIT`, `COPY`/`MOVE` onto, or `KILL` of a message address is refused `405 message-immutable` with no `recovery` ({§diagnostic-observation}): `` `<address>` is a received message; it cannot be edited, moved or killed. ``
|