@superbee/core 0.2.0-pre.11 → 0.2.0-pre.13
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/dist/cross-bundle.d.ts +135 -0
- package/dist/cross-bundle.d.ts.map +1 -0
- package/dist/cross-bundle.js +186 -0
- package/dist/cross-bundle.js.map +1 -0
- package/dist/dependencies.d.ts +94 -0
- package/dist/dependencies.d.ts.map +1 -0
- package/dist/dependencies.js +180 -0
- package/dist/dependencies.js.map +1 -0
- package/dist/engine.d.ts +7 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +7 -1
- package/dist/engine.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/links.d.ts +20 -2
- package/dist/links.d.ts.map +1 -1
- package/dist/links.js +208 -4
- package/dist/links.js.map +1 -1
- package/dist/qualified-links.d.ts +67 -0
- package/dist/qualified-links.d.ts.map +1 -0
- package/dist/qualified-links.js +117 -0
- package/dist/qualified-links.js.map +1 -0
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +13 -1
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-bundle link resolution: the resolver interface every backend implements, and the local
|
|
3
|
+
* resolver over explicitly bound {@link StorageBackend}s.
|
|
4
|
+
*
|
|
5
|
+
* Resolution is always explicit. A resolver reads only the copies it was constructed with; nothing
|
|
6
|
+
* is fetched or discovered. Browser-safe: bindings are backends, never filesystem paths, and pin
|
|
7
|
+
* checks are injected (the CLI probes git; core never spawns a process).
|
|
8
|
+
*/
|
|
9
|
+
import type { DependencyMap, DependencyProblemCode } from "./dependencies.js";
|
|
10
|
+
import { type QualifiedLink, type QualifiedRef } from "./qualified-links.js";
|
|
11
|
+
import type { ConceptId, OkfDocument, StorageBackend, Version } from "./types.js";
|
|
12
|
+
/**
|
|
13
|
+
* Why a link did not resolve. An unresolved link is still a valid link.
|
|
14
|
+
* - `bundle_unavailable`: no copy is bound, or the bound copy is not the declared bundle.
|
|
15
|
+
* - `pin_mismatch`: the bound copy is not at the pinned version.
|
|
16
|
+
* - `target_missing`: the document is not in the bound copy.
|
|
17
|
+
* - `not_authorized`: the reader may not read the target bundle.
|
|
18
|
+
* - `unknown_alias`: the alias is not declared in `docs/dependencies`.
|
|
19
|
+
* - `invalid_ref`: the href is malformed.
|
|
20
|
+
*/
|
|
21
|
+
export type UnresolvedReason = "bundle_unavailable" | "pin_mismatch" | "target_missing" | "not_authorized" | "unknown_alias" | "invalid_ref";
|
|
22
|
+
export declare const UNRESOLVED_REASONS: readonly UnresolvedReason[];
|
|
23
|
+
/**
|
|
24
|
+
* The reasons that are the referring document's fault (fix the link or the target). The others
|
|
25
|
+
* (`bundle_unavailable`, `pin_mismatch`, `not_authorized`) describe the reader's environment or
|
|
26
|
+
* access, and a check must not blame the document for them.
|
|
27
|
+
*/
|
|
28
|
+
export declare const RECORD_REASONS: readonly UnresolvedReason[];
|
|
29
|
+
export declare function isRecordReason(reason: UnresolvedReason): boolean;
|
|
30
|
+
/** The one detail every `not_authorized` result carries, so it says nothing about the target. */
|
|
31
|
+
export declare const NOT_AUTHORIZED_DETAIL = "the reader is not authorized to read this bundle";
|
|
32
|
+
export type Resolution = {
|
|
33
|
+
state: "resolved";
|
|
34
|
+
ref: QualifiedRef;
|
|
35
|
+
bundle_id: string;
|
|
36
|
+
/** A backend-defined revision of the bound copy, when it has one. The local resolver sets none. */
|
|
37
|
+
revision?: string;
|
|
38
|
+
document: OkfDocument;
|
|
39
|
+
version: Version;
|
|
40
|
+
} | {
|
|
41
|
+
state: "unresolved";
|
|
42
|
+
/** Null when the ref itself is malformed. */
|
|
43
|
+
ref: QualifiedRef | null;
|
|
44
|
+
href: string;
|
|
45
|
+
reason: UnresolvedReason;
|
|
46
|
+
/** Only ever the id from the reader's own declaration. */
|
|
47
|
+
bundle_id?: string;
|
|
48
|
+
detail: string;
|
|
49
|
+
};
|
|
50
|
+
/** A link into a target document from a bundle the reader may read. */
|
|
51
|
+
export interface CrossBacklink {
|
|
52
|
+
from: {
|
|
53
|
+
bundle_id: string;
|
|
54
|
+
id: ConceptId;
|
|
55
|
+
};
|
|
56
|
+
text: string;
|
|
57
|
+
href: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Resolves `okf://` refs for ONE reader.
|
|
61
|
+
*
|
|
62
|
+
* Authorization invariants, binding on every implementation (local, hosted, any future one):
|
|
63
|
+
*
|
|
64
|
+
* 1. A resolver is built for one reader. Grants are a constructor concern, never a method
|
|
65
|
+
* parameter.
|
|
66
|
+
* 2. The grant check comes first. For a reader without a grant on the target bundle, the answer is
|
|
67
|
+
* `not_authorized` before any "bundle not found", "document not found" or `pin_mismatch`, and
|
|
68
|
+
* before any revision or version is disclosed.
|
|
69
|
+
* 3. `not_authorized` results for a present target and for a missing target are deep-equal, with
|
|
70
|
+
* the fixed detail {@link NOT_AUTHORIZED_DETAIL}. Their `bundle_id` comes only from the
|
|
71
|
+
* reader's own declaration.
|
|
72
|
+
* 4. `backlinks()` returns only hits in readable bundles, and never names or counts the others.
|
|
73
|
+
*
|
|
74
|
+
* The local resolver reads only copies the reader bound explicitly, so it never answers
|
|
75
|
+
* `not_authorized`.
|
|
76
|
+
*/
|
|
77
|
+
export interface BundleResolver {
|
|
78
|
+
/** `"local"` here; `"hosted"` later. */
|
|
79
|
+
readonly kind: string;
|
|
80
|
+
readonly dependencies: DependencyMap;
|
|
81
|
+
/** Batched and positional: `result[i]` answers `refs[i]`. */
|
|
82
|
+
resolve(refs: readonly QualifiedRef[]): Promise<Resolution[]>;
|
|
83
|
+
backlinks(target: {
|
|
84
|
+
bundle_id: string;
|
|
85
|
+
id: ConceptId;
|
|
86
|
+
}, options?: {
|
|
87
|
+
text?: string;
|
|
88
|
+
}): Promise<CrossBacklink[]>;
|
|
89
|
+
}
|
|
90
|
+
export interface CommitPin {
|
|
91
|
+
kind: "commit";
|
|
92
|
+
value: string;
|
|
93
|
+
}
|
|
94
|
+
/** Whether a bound copy is at a commit pin. Injected by the caller (the CLI checks the bundle's git subtree). */
|
|
95
|
+
export type PinCheck = (pin: CommitPin) => Promise<{
|
|
96
|
+
ok: true;
|
|
97
|
+
} | {
|
|
98
|
+
ok: false;
|
|
99
|
+
detail: string;
|
|
100
|
+
}>;
|
|
101
|
+
export interface BundleBinding {
|
|
102
|
+
backend: StorageBackend;
|
|
103
|
+
/** How the caller named the copy (a path or catalog label), for messages. */
|
|
104
|
+
label: string;
|
|
105
|
+
/** The bound copy's own portable id. Absent or different from the declaration: `bundle_unavailable`. */
|
|
106
|
+
identity?: string;
|
|
107
|
+
/** Required to satisfy a commit pin; without it a pinned dependency is `pin_mismatch`. */
|
|
108
|
+
pin?: PinCheck;
|
|
109
|
+
}
|
|
110
|
+
export interface LocalResolverOptions {
|
|
111
|
+
dependencies: DependencyMap;
|
|
112
|
+
/** `ParsedDependencies.rejected`: declared aliases whose entry was dropped, for the detail. */
|
|
113
|
+
rejected?: ReadonlyMap<string, DependencyProblemCode>;
|
|
114
|
+
bindings: ReadonlyMap<string, BundleBinding>;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The local resolver: each alias reads through the backend the caller bound to it. One
|
|
118
|
+
* delete-tolerant batch read per alias per `resolve` call. When a batch names a missing target,
|
|
119
|
+
* a backend whose `readMany` fails on the absent id (as the shipped backends do) costs one extra
|
|
120
|
+
* `read()` per id in that alias's batch, through `readManyExisting`'s per-id fallback.
|
|
121
|
+
*
|
|
122
|
+
* `backlinks()` always returns `[]`: a local reader has no index of who links into a bundle, and
|
|
123
|
+
* scanning other bound copies for inbound links is deferred until something needs it.
|
|
124
|
+
*/
|
|
125
|
+
export declare function createLocalResolver(options: LocalResolverOptions): BundleResolver;
|
|
126
|
+
export interface QualifiedLinkResolution {
|
|
127
|
+
link: QualifiedLink;
|
|
128
|
+
resolution: Resolution;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Resolve parsed links (from {@link parseQualifiedLinks}) in one `resolve` call. A malformed href
|
|
132
|
+
* is `invalid_ref` here without reaching the resolver, and carries the parser's detail.
|
|
133
|
+
*/
|
|
134
|
+
export declare function resolveQualifiedLinks(resolver: BundleResolver, links: readonly QualifiedLink[]): Promise<QualifiedLinkResolution[]>;
|
|
135
|
+
//# sourceMappingURL=cross-bundle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross-bundle.d.ts","sourceRoot":"","sources":["../src/cross-bundle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-bundle link resolution: the resolver interface every backend implements, and the local
|
|
3
|
+
* resolver over explicitly bound {@link StorageBackend}s.
|
|
4
|
+
*
|
|
5
|
+
* Resolution is always explicit. A resolver reads only the copies it was constructed with; nothing
|
|
6
|
+
* is fetched or discovered. Browser-safe: bindings are backends, never filesystem paths, and pin
|
|
7
|
+
* checks are injected (the CLI probes git; core never spawns a process).
|
|
8
|
+
*/
|
|
9
|
+
import { readManyExisting } from "./engine.js";
|
|
10
|
+
import { InvalidInputError } from "./errors.js";
|
|
11
|
+
import { qualifiedHref } from "./qualified-links.js";
|
|
12
|
+
export const UNRESOLVED_REASONS = Object.freeze([
|
|
13
|
+
"bundle_unavailable",
|
|
14
|
+
"pin_mismatch",
|
|
15
|
+
"target_missing",
|
|
16
|
+
"not_authorized",
|
|
17
|
+
"unknown_alias",
|
|
18
|
+
"invalid_ref",
|
|
19
|
+
]);
|
|
20
|
+
/**
|
|
21
|
+
* The reasons that are the referring document's fault (fix the link or the target). The others
|
|
22
|
+
* (`bundle_unavailable`, `pin_mismatch`, `not_authorized`) describe the reader's environment or
|
|
23
|
+
* access, and a check must not blame the document for them.
|
|
24
|
+
*/
|
|
25
|
+
export const RECORD_REASONS = Object.freeze([
|
|
26
|
+
"target_missing",
|
|
27
|
+
"unknown_alias",
|
|
28
|
+
"invalid_ref",
|
|
29
|
+
]);
|
|
30
|
+
export function isRecordReason(reason) {
|
|
31
|
+
return RECORD_REASONS.includes(reason);
|
|
32
|
+
}
|
|
33
|
+
/** The one detail every `not_authorized` result carries, so it says nothing about the target. */
|
|
34
|
+
export const NOT_AUTHORIZED_DETAIL = "the reader is not authorized to read this bundle";
|
|
35
|
+
function hrefOf(ref) {
|
|
36
|
+
try {
|
|
37
|
+
return { href: qualifiedHref(ref), valid: true };
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (error instanceof InvalidInputError)
|
|
41
|
+
return { href: `okf://${ref.alias}/${ref.id}.md`, valid: false };
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function errorDetail(error) {
|
|
46
|
+
return error instanceof Error ? error.message : String(error);
|
|
47
|
+
}
|
|
48
|
+
/** The per-alias verdict before any document is read: null when the copy may be read. */
|
|
49
|
+
async function bindingVerdict(entry, binding) {
|
|
50
|
+
if (!binding)
|
|
51
|
+
return { reason: "bundle_unavailable", detail: `no copy of '${entry.bundle_id}' is bound for alias '${entry.alias}'` };
|
|
52
|
+
if (binding.identity === undefined) {
|
|
53
|
+
return { reason: "bundle_unavailable", detail: `${binding.label} declares no bundle_id; expected '${entry.bundle_id}'` };
|
|
54
|
+
}
|
|
55
|
+
if (binding.identity !== entry.bundle_id) {
|
|
56
|
+
return { reason: "bundle_unavailable", detail: `${binding.label} is '${binding.identity}', not '${entry.bundle_id}'` };
|
|
57
|
+
}
|
|
58
|
+
const pin = entry.pin;
|
|
59
|
+
if (!pin)
|
|
60
|
+
return null;
|
|
61
|
+
if (pin.kind === "digest")
|
|
62
|
+
return { reason: "pin_mismatch", detail: "digest pins are verified by a hosted resolver" };
|
|
63
|
+
if (!binding.pin)
|
|
64
|
+
return { reason: "pin_mismatch", detail: `no pin check is available for ${binding.label}` };
|
|
65
|
+
try {
|
|
66
|
+
const verdict = await binding.pin({ kind: "commit", value: pin.value });
|
|
67
|
+
return verdict.ok ? null : { reason: "pin_mismatch", detail: verdict.detail };
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
return { reason: "pin_mismatch", detail: `pin check failed: ${errorDetail(error)}` };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The local resolver: each alias reads through the backend the caller bound to it. One
|
|
75
|
+
* delete-tolerant batch read per alias per `resolve` call. When a batch names a missing target,
|
|
76
|
+
* a backend whose `readMany` fails on the absent id (as the shipped backends do) costs one extra
|
|
77
|
+
* `read()` per id in that alias's batch, through `readManyExisting`'s per-id fallback.
|
|
78
|
+
*
|
|
79
|
+
* `backlinks()` always returns `[]`: a local reader has no index of who links into a bundle, and
|
|
80
|
+
* scanning other bound copies for inbound links is deferred until something needs it.
|
|
81
|
+
*/
|
|
82
|
+
export function createLocalResolver(options) {
|
|
83
|
+
const { dependencies, bindings, rejected } = options;
|
|
84
|
+
return {
|
|
85
|
+
kind: "local",
|
|
86
|
+
dependencies,
|
|
87
|
+
async resolve(refs) {
|
|
88
|
+
const out = new Array(refs.length);
|
|
89
|
+
const unresolved = (i, ref, href, reason, detail, bundleId) => {
|
|
90
|
+
const row = { state: "unresolved", ref, href, reason, detail };
|
|
91
|
+
if (bundleId !== undefined)
|
|
92
|
+
row.bundle_id = bundleId;
|
|
93
|
+
out[i] = row;
|
|
94
|
+
};
|
|
95
|
+
// alias -> indexes of the refs that reached the read stage
|
|
96
|
+
const pending = new Map();
|
|
97
|
+
const verdicts = new Map();
|
|
98
|
+
const hrefs = [];
|
|
99
|
+
for (let i = 0; i < refs.length; i++) {
|
|
100
|
+
const ref = refs[i];
|
|
101
|
+
const { href, valid } = hrefOf(ref);
|
|
102
|
+
hrefs[i] = href;
|
|
103
|
+
if (!valid) {
|
|
104
|
+
unresolved(i, null, href, "invalid_ref", "not a valid cross-bundle target");
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const entry = dependencies.get(ref.alias);
|
|
108
|
+
if (!entry) {
|
|
109
|
+
const code = rejected?.get(ref.alias);
|
|
110
|
+
unresolved(i, ref, href, "unknown_alias", code === undefined
|
|
111
|
+
? `alias '${ref.alias}' is not declared in docs/dependencies`
|
|
112
|
+
: `alias '${ref.alias}' is declared but rejected (${code})`);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (!verdicts.has(ref.alias))
|
|
116
|
+
verdicts.set(ref.alias, bindingVerdict(entry, bindings.get(ref.alias)));
|
|
117
|
+
const indexes = pending.get(ref.alias) ?? [];
|
|
118
|
+
indexes.push(i);
|
|
119
|
+
pending.set(ref.alias, indexes);
|
|
120
|
+
}
|
|
121
|
+
for (const [alias, indexes] of pending) {
|
|
122
|
+
const entry = dependencies.get(alias);
|
|
123
|
+
const verdict = await verdicts.get(alias);
|
|
124
|
+
if (verdict) {
|
|
125
|
+
for (const i of indexes)
|
|
126
|
+
unresolved(i, refs[i], hrefs[i], verdict.reason, verdict.detail, entry.bundle_id);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const binding = bindings.get(alias);
|
|
130
|
+
const ids = [...new Set(indexes.map((i) => refs[i].id))];
|
|
131
|
+
const malformed = new Map();
|
|
132
|
+
let found;
|
|
133
|
+
try {
|
|
134
|
+
const results = await readManyExisting(binding.backend, ids, (skip) => malformed.set(skip.id, skip.reason));
|
|
135
|
+
found = new Map(results.map((result) => [result.doc.id, result]));
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
const detail = `${binding.label} could not be read: ${errorDetail(error)}`;
|
|
139
|
+
for (const i of indexes)
|
|
140
|
+
unresolved(i, refs[i], hrefs[i], "bundle_unavailable", detail, entry.bundle_id);
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
for (const i of indexes) {
|
|
144
|
+
const ref = refs[i];
|
|
145
|
+
const hit = found.get(ref.id);
|
|
146
|
+
if (hit) {
|
|
147
|
+
out[i] = { state: "resolved", ref, bundle_id: entry.bundle_id, document: hit.doc, version: hit.version };
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
const why = malformed.get(ref.id);
|
|
151
|
+
const detail = why === undefined
|
|
152
|
+
? `'${ref.id}' is not in ${binding.label}`
|
|
153
|
+
: `'${ref.id}' in ${binding.label} is malformed: ${why}`;
|
|
154
|
+
unresolved(i, ref, hrefs[i], "target_missing", detail, entry.bundle_id);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return out;
|
|
159
|
+
},
|
|
160
|
+
async backlinks() {
|
|
161
|
+
return [];
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Resolve parsed links (from {@link parseQualifiedLinks}) in one `resolve` call. A malformed href
|
|
167
|
+
* is `invalid_ref` here without reaching the resolver, and carries the parser's detail.
|
|
168
|
+
*/
|
|
169
|
+
export async function resolveQualifiedLinks(resolver, links) {
|
|
170
|
+
const refs = [];
|
|
171
|
+
for (const link of links)
|
|
172
|
+
if (link.ref)
|
|
173
|
+
refs.push(link.ref);
|
|
174
|
+
const resolved = await resolver.resolve(refs);
|
|
175
|
+
let next = 0;
|
|
176
|
+
return links.map((link) => {
|
|
177
|
+
if (!link.ref) {
|
|
178
|
+
return {
|
|
179
|
+
link,
|
|
180
|
+
resolution: { state: "unresolved", ref: null, href: link.href, reason: "invalid_ref", detail: link.detail ?? "malformed cross-bundle link" },
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
return { link, resolution: resolved[next++] };
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=cross-bundle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross-bundle.js","sourceRoot":"","sources":["../src/cross-bundle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundle identity and the `docs/dependencies` declaration.
|
|
3
|
+
*
|
|
4
|
+
* A bundle names the other bundles it links into in ONE committed document, `docs/dependencies`
|
|
5
|
+
* (type `Bundle Dependencies`). Each entry maps a local alias (the `<alias>` in
|
|
6
|
+
* `okf://<alias>/<path>.md`) to the target's portable `bundle_id`, plus optional `source`, `pin`
|
|
7
|
+
* and `path`. A target confirms its own identity with `bundle_id` in its `docs/bundle` document.
|
|
8
|
+
*
|
|
9
|
+
* Pure and browser-safe: no `node:*` import, no I/O. Consumers read the documents through their
|
|
10
|
+
* own backend and hand them here.
|
|
11
|
+
*/
|
|
12
|
+
import type { OkfDocument } from "./types.js";
|
|
13
|
+
/** True when `id` is a portable bundle id (the hosted bundle-id grammar). */
|
|
14
|
+
export declare function isHostedBundleId(id: string): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* The well-known concept id carrying a bundle's explicit display name and portable id. NOT the
|
|
17
|
+
* bundle-root `index.md` — OKF §3.1 reserves that file's frontmatter solely for `okf_version`, so
|
|
18
|
+
* the name needs its own small doc.
|
|
19
|
+
*/
|
|
20
|
+
export declare const BUNDLE_NAME_DOC_ID = "docs/bundle";
|
|
21
|
+
/**
|
|
22
|
+
* The ownership marker: `docs/bundle` speaks for the bundle ONLY when it carries exactly this
|
|
23
|
+
* `type`. A `docs/bundle` doc of any other type is an ordinary document and is ignored, so an
|
|
24
|
+
* unrelated pre-existing doc is never appropriated as the bundle's name or id.
|
|
25
|
+
*/
|
|
26
|
+
export declare const BUNDLE_NAME_DOC_TYPE = "Bundle Name";
|
|
27
|
+
/**
|
|
28
|
+
* The bundle's self-declared portable id: `bundle_id` in `docs/bundle` under the marker type, when
|
|
29
|
+
* it satisfies {@link isHostedBundleId}. Anything else (absent doc, other type, missing or
|
|
30
|
+
* malformed id) is `undefined`; the caller decides what a bundle without a declared id means.
|
|
31
|
+
*/
|
|
32
|
+
export declare function declaredBundleId(doc: OkfDocument | null | undefined): string | undefined;
|
|
33
|
+
export declare const DEPENDENCIES_DOC_ID = "docs/dependencies";
|
|
34
|
+
export declare const DEPENDENCIES_DOC_TYPE = "Bundle Dependencies";
|
|
35
|
+
/** The alias grammar shared by `okf://<alias>/…` hrefs, dependency keys and qualified Kind targets. */
|
|
36
|
+
export declare const BUNDLE_ALIAS: RegExp;
|
|
37
|
+
export declare function isBundleAlias(alias: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* A dependency pin. Hex is lower-case only; an upper-case pin is rejected (`DEP_PIN`) rather than
|
|
40
|
+
* folded, so the declaration is the exact string git and a host compare. A `commit` pin (7-40 hex) is checked by an injected `PinCheck` against the
|
|
41
|
+
* bound copy's subtree. A `digest` pin (`sha256:<64 hex>`) parses, but only a hosted resolver can
|
|
42
|
+
* verify it; a local resolver fails it closed.
|
|
43
|
+
*/
|
|
44
|
+
export type DependencyPin = {
|
|
45
|
+
kind: "commit";
|
|
46
|
+
value: string;
|
|
47
|
+
} | {
|
|
48
|
+
kind: "digest";
|
|
49
|
+
value: string;
|
|
50
|
+
};
|
|
51
|
+
export interface DependencyEntry {
|
|
52
|
+
alias: string;
|
|
53
|
+
bundle_id: string;
|
|
54
|
+
/** Where to get the bundle (git URL or `hosted:<host>/<bundle_id>`). Informational only. */
|
|
55
|
+
source?: string;
|
|
56
|
+
pin?: DependencyPin;
|
|
57
|
+
/** Relative to the declaring bundle's root; used only by an explicit `--with-deps`. */
|
|
58
|
+
path?: string;
|
|
59
|
+
}
|
|
60
|
+
/** Alias -> entry. A Map, so an alias such as `constructor` can never hit an inherited property. */
|
|
61
|
+
export type DependencyMap = ReadonlyMap<string, DependencyEntry>;
|
|
62
|
+
export type DependencyProblemCode = "DEP_TYPE" | "DEP_SHAPE" | "DEP_ALIAS" | "DEP_BUNDLE_ID" | "DEP_PIN" | "DEP_PATH_ABSOLUTE" | "DEP_DUPLICATE_BUNDLE" | "DEP_SELF" | "DEP_UNKNOWN_KEY" | "DEP_RESERVED_KEY";
|
|
63
|
+
export interface DependencyProblem {
|
|
64
|
+
code: DependencyProblemCode;
|
|
65
|
+
alias?: string;
|
|
66
|
+
detail: string;
|
|
67
|
+
}
|
|
68
|
+
export interface ParsedDependencies {
|
|
69
|
+
dependencies: DependencyMap;
|
|
70
|
+
problems: DependencyProblem[];
|
|
71
|
+
/**
|
|
72
|
+
* Aliases that are declared but whose entry was dropped, with the code that dropped it, so a
|
|
73
|
+
* link under one can say "declared but rejected" instead of "not declared".
|
|
74
|
+
*/
|
|
75
|
+
rejected: ReadonlyMap<string, DependencyProblemCode>;
|
|
76
|
+
}
|
|
77
|
+
export interface ParseDependenciesOptions {
|
|
78
|
+
/** The declaring bundle's own id; an entry naming it is `DEP_SELF`. */
|
|
79
|
+
selfBundleId?: string;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Absolute under POSIX or win32 rules, or carrying a backslash. Pure string checks (no
|
|
83
|
+
* `node:path`) so the verdict is the same on every host: `/x`, `\x`, `\\server\share`, `C:\x`,
|
|
84
|
+
* `C:/x` and the drive-relative `C:x` are all refused.
|
|
85
|
+
*/
|
|
86
|
+
export declare function isNonPortableDependencyPath(value: string): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Parse `docs/dependencies`. Never throws: every defect is a problem, and an entry whose alias,
|
|
89
|
+
* `bundle_id` or `pin` is unusable is dropped (fail closed: a link under it reads as
|
|
90
|
+
* `unknown_alias`, never as resolved against the wrong copy). An unusable `source` or `path` drops
|
|
91
|
+
* only that field. Unknown and reserved keys are reported and the entry is kept.
|
|
92
|
+
*/
|
|
93
|
+
export declare function parseDependencies(doc: OkfDocument | null | undefined, options?: ParseDependenciesOptions): ParsedDependencies;
|
|
94
|
+
//# sourceMappingURL=dependencies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependencies.d.ts","sourceRoot":"","sources":["../src/dependencies.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAY9C,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,gBAAgB,CAAC;AAEhD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,gBAAgB,CAAC;AAElD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAMxF;AAID,eAAO,MAAM,mBAAmB,sBAAsB,CAAC;AACvD,eAAO,MAAM,qBAAqB,wBAAwB,CAAC;AAE3D,uGAAuG;AACvG,eAAO,MAAM,YAAY,QAA2B,CAAC;AAErD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,4FAA4F;IAC5F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,uFAAuF;IACvF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,oGAAoG;AACpG,MAAM,MAAM,aAAa,GAAG,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAEjE,MAAM,MAAM,qBAAqB,GAC7B,UAAU,GACV,WAAW,GACX,WAAW,GACX,eAAe,GACf,SAAS,GACT,mBAAmB,GACnB,sBAAsB,GACtB,UAAU,GACV,iBAAiB,GACjB,kBAAkB,CAAC;AAEvB,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,qBAAqB,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,aAAa,CAAC;IAC5B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B;;;OAGG;IACH,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,wBAAwB;IACvC,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAaD;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAElE;AASD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,EACnC,OAAO,GAAE,wBAA6B,GACrC,kBAAkB,CAyFpB"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundle identity and the `docs/dependencies` declaration.
|
|
3
|
+
*
|
|
4
|
+
* A bundle names the other bundles it links into in ONE committed document, `docs/dependencies`
|
|
5
|
+
* (type `Bundle Dependencies`). Each entry maps a local alias (the `<alias>` in
|
|
6
|
+
* `okf://<alias>/<path>.md`) to the target's portable `bundle_id`, plus optional `source`, `pin`
|
|
7
|
+
* and `path`. A target confirms its own identity with `bundle_id` in its `docs/bundle` document.
|
|
8
|
+
*
|
|
9
|
+
* Pure and browser-safe: no `node:*` import, no I/O. Consumers read the documents through their
|
|
10
|
+
* own backend and hand them here.
|
|
11
|
+
*/
|
|
12
|
+
// ── Bundle identity ─────────────────────────────────────────────────────────
|
|
13
|
+
// A portable bundle id: lower-case letters and digits joined by `.`, `_` or `-`, starting with a
|
|
14
|
+
// letter, at most 128 characters. The one rule hosted `checkout`, `export` and `publish` accept an
|
|
15
|
+
// id by, and the one a printed `checkout <id>` command is emitted for: an id it rejects (one
|
|
16
|
+
// starting with `-` would read as an option) never appears in a command.
|
|
17
|
+
const BUNDLE_ID = /^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$/;
|
|
18
|
+
const BUNDLE_ID_MAX_LENGTH = 128;
|
|
19
|
+
/** True when `id` is a portable bundle id (the hosted bundle-id grammar). */
|
|
20
|
+
export function isHostedBundleId(id) {
|
|
21
|
+
return id.length <= BUNDLE_ID_MAX_LENGTH && BUNDLE_ID.test(id);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The well-known concept id carrying a bundle's explicit display name and portable id. NOT the
|
|
25
|
+
* bundle-root `index.md` — OKF §3.1 reserves that file's frontmatter solely for `okf_version`, so
|
|
26
|
+
* the name needs its own small doc.
|
|
27
|
+
*/
|
|
28
|
+
export const BUNDLE_NAME_DOC_ID = "docs/bundle";
|
|
29
|
+
/**
|
|
30
|
+
* The ownership marker: `docs/bundle` speaks for the bundle ONLY when it carries exactly this
|
|
31
|
+
* `type`. A `docs/bundle` doc of any other type is an ordinary document and is ignored, so an
|
|
32
|
+
* unrelated pre-existing doc is never appropriated as the bundle's name or id.
|
|
33
|
+
*/
|
|
34
|
+
export const BUNDLE_NAME_DOC_TYPE = "Bundle Name";
|
|
35
|
+
/**
|
|
36
|
+
* The bundle's self-declared portable id: `bundle_id` in `docs/bundle` under the marker type, when
|
|
37
|
+
* it satisfies {@link isHostedBundleId}. Anything else (absent doc, other type, missing or
|
|
38
|
+
* malformed id) is `undefined`; the caller decides what a bundle without a declared id means.
|
|
39
|
+
*/
|
|
40
|
+
export function declaredBundleId(doc) {
|
|
41
|
+
if (!doc || doc.id !== BUNDLE_NAME_DOC_ID)
|
|
42
|
+
return undefined;
|
|
43
|
+
const type = doc.frontmatter.type;
|
|
44
|
+
if (typeof type !== "string" || type.trim() !== BUNDLE_NAME_DOC_TYPE)
|
|
45
|
+
return undefined;
|
|
46
|
+
const id = doc.frontmatter.bundle_id;
|
|
47
|
+
return typeof id === "string" && isHostedBundleId(id) ? id : undefined;
|
|
48
|
+
}
|
|
49
|
+
// ── docs/dependencies ───────────────────────────────────────────────────────
|
|
50
|
+
export const DEPENDENCIES_DOC_ID = "docs/dependencies";
|
|
51
|
+
export const DEPENDENCIES_DOC_TYPE = "Bundle Dependencies";
|
|
52
|
+
/** The alias grammar shared by `okf://<alias>/…` hrefs, dependency keys and qualified Kind targets. */
|
|
53
|
+
export const BUNDLE_ALIAS = /^[a-z][a-z0-9-]{0,62}$/;
|
|
54
|
+
export function isBundleAlias(alias) {
|
|
55
|
+
return BUNDLE_ALIAS.test(alias);
|
|
56
|
+
}
|
|
57
|
+
const KNOWN_KEYS = new Set(["bundle_id", "source", "pin", "path"]);
|
|
58
|
+
/** Reserved for recipe dependencies, which will reuse this declaration. */
|
|
59
|
+
const RESERVED_KEYS = new Set(["use", "version", "channel"]);
|
|
60
|
+
const COMMIT_PIN = /^[0-9a-f]{7,40}$/;
|
|
61
|
+
const DIGEST_PIN = /^sha256:[0-9a-f]{64}$/;
|
|
62
|
+
function isRecord(value) {
|
|
63
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Absolute under POSIX or win32 rules, or carrying a backslash. Pure string checks (no
|
|
67
|
+
* `node:path`) so the verdict is the same on every host: `/x`, `\x`, `\\server\share`, `C:\x`,
|
|
68
|
+
* `C:/x` and the drive-relative `C:x` are all refused.
|
|
69
|
+
*/
|
|
70
|
+
export function isNonPortableDependencyPath(value) {
|
|
71
|
+
return value.startsWith("/") || value.includes("\\") || /^[A-Za-z]:/.test(value);
|
|
72
|
+
}
|
|
73
|
+
function parsePin(value) {
|
|
74
|
+
if (typeof value !== "string")
|
|
75
|
+
return null;
|
|
76
|
+
if (COMMIT_PIN.test(value))
|
|
77
|
+
return { kind: "commit", value };
|
|
78
|
+
if (DIGEST_PIN.test(value))
|
|
79
|
+
return { kind: "digest", value };
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Parse `docs/dependencies`. Never throws: every defect is a problem, and an entry whose alias,
|
|
84
|
+
* `bundle_id` or `pin` is unusable is dropped (fail closed: a link under it reads as
|
|
85
|
+
* `unknown_alias`, never as resolved against the wrong copy). An unusable `source` or `path` drops
|
|
86
|
+
* only that field. Unknown and reserved keys are reported and the entry is kept.
|
|
87
|
+
*/
|
|
88
|
+
export function parseDependencies(doc, options = {}) {
|
|
89
|
+
const dependencies = new Map();
|
|
90
|
+
const problems = [];
|
|
91
|
+
const rejected = new Map();
|
|
92
|
+
const result = () => ({ dependencies, problems, rejected });
|
|
93
|
+
const reject = (alias, code, detail) => {
|
|
94
|
+
problems.push({ code, alias, detail });
|
|
95
|
+
rejected.set(alias, code);
|
|
96
|
+
};
|
|
97
|
+
if (!doc)
|
|
98
|
+
return result();
|
|
99
|
+
const type = doc.frontmatter.type;
|
|
100
|
+
if (typeof type !== "string" || type.trim() !== DEPENDENCIES_DOC_TYPE) {
|
|
101
|
+
problems.push({ code: "DEP_TYPE", detail: `type must be '${DEPENDENCIES_DOC_TYPE}'` });
|
|
102
|
+
return result();
|
|
103
|
+
}
|
|
104
|
+
const declared = doc.frontmatter.dependencies;
|
|
105
|
+
if (declared === undefined || declared === null)
|
|
106
|
+
return result();
|
|
107
|
+
if (!isRecord(declared)) {
|
|
108
|
+
problems.push({ code: "DEP_SHAPE", detail: "dependencies must be a mapping of alias to entry" });
|
|
109
|
+
return result();
|
|
110
|
+
}
|
|
111
|
+
const aliasByBundle = new Map();
|
|
112
|
+
for (const [alias, raw] of Object.entries(declared)) {
|
|
113
|
+
if (!isBundleAlias(alias)) {
|
|
114
|
+
problems.push({ code: "DEP_ALIAS", alias, detail: "alias must match ^[a-z][a-z0-9-]{0,62}$" });
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (!isRecord(raw)) {
|
|
118
|
+
reject(alias, "DEP_SHAPE", "entry must be a mapping");
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const bundleId = raw.bundle_id;
|
|
122
|
+
if (typeof bundleId !== "string" || !isHostedBundleId(bundleId)) {
|
|
123
|
+
reject(alias, "DEP_BUNDLE_ID", "bundle_id is required and must be a portable bundle id");
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
let pin;
|
|
127
|
+
if (raw.pin !== undefined) {
|
|
128
|
+
const parsed = parsePin(raw.pin);
|
|
129
|
+
if (parsed === null) {
|
|
130
|
+
// A YAML scalar such as 1234567 or 3e45678 arrives as a number, so the hint says to quote.
|
|
131
|
+
reject(alias, "DEP_PIN", "pin must be a quoted commit (7-40 lower-case hex) or sha256:<64 lower-case hex>");
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
pin = parsed;
|
|
135
|
+
}
|
|
136
|
+
if (options.selfBundleId !== undefined && bundleId === options.selfBundleId) {
|
|
137
|
+
reject(alias, "DEP_SELF", `bundle_id '${bundleId}' is this bundle`);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
const earlier = aliasByBundle.get(bundleId);
|
|
141
|
+
if (earlier !== undefined) {
|
|
142
|
+
reject(alias, "DEP_DUPLICATE_BUNDLE", `bundle_id '${bundleId}' is already declared as '${earlier}'`);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const entry = { alias, bundle_id: bundleId };
|
|
146
|
+
if (raw.source !== undefined) {
|
|
147
|
+
if (typeof raw.source === "string" && raw.source.trim() !== "")
|
|
148
|
+
entry.source = raw.source;
|
|
149
|
+
else
|
|
150
|
+
problems.push({ code: "DEP_SHAPE", alias, detail: "source must be a non-empty string" });
|
|
151
|
+
}
|
|
152
|
+
if (pin)
|
|
153
|
+
entry.pin = pin;
|
|
154
|
+
if (raw.path !== undefined) {
|
|
155
|
+
if (typeof raw.path !== "string" || raw.path.trim() === "") {
|
|
156
|
+
problems.push({ code: "DEP_SHAPE", alias, detail: "path must be a non-empty string" });
|
|
157
|
+
}
|
|
158
|
+
else if (isNonPortableDependencyPath(raw.path)) {
|
|
159
|
+
problems.push({ code: "DEP_PATH_ABSOLUTE", alias, detail: "path must be relative to this bundle's root, with '/' separators" });
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
entry.path = raw.path;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
for (const key of Object.keys(raw)) {
|
|
166
|
+
if (KNOWN_KEYS.has(key))
|
|
167
|
+
continue;
|
|
168
|
+
if (RESERVED_KEYS.has(key)) {
|
|
169
|
+
problems.push({ code: "DEP_RESERVED_KEY", alias, detail: `'${key}' is reserved for recipe dependencies` });
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
problems.push({ code: "DEP_UNKNOWN_KEY", alias, detail: `unknown key '${key}'` });
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
aliasByBundle.set(bundleId, alias);
|
|
176
|
+
dependencies.set(alias, entry);
|
|
177
|
+
}
|
|
178
|
+
return result();
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=dependencies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependencies.js","sourceRoot":"","sources":["../src/dependencies.ts"],"names":[],"mappings":"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"}
|
package/dist/engine.d.ts
CHANGED
|
@@ -36,6 +36,13 @@ export declare function readDoc(backend: StorageBackend, id: ConceptId): Promise
|
|
|
36
36
|
export declare function existsDoc(backend: StorageBackend, id: ConceptId): Promise<boolean>;
|
|
37
37
|
export declare function docVersions(backend: StorageBackend, id: ConceptId): Promise<VersionInfo[]>;
|
|
38
38
|
export declare function deleteDoc(backend: StorageBackend, id: ConceptId, options?: DeleteOptions): Promise<boolean>;
|
|
39
|
+
/**
|
|
40
|
+
* Delete-tolerant batch read: one `readMany`, falling back to per-id reads only when the batch
|
|
41
|
+
* fails because an id vanished (or, with `onMalformed`, because one document is malformed).
|
|
42
|
+
* Absent ids are simply missing from the result. Shared by the scan path and the cross-bundle
|
|
43
|
+
* resolver, which issues one call per bound alias.
|
|
44
|
+
*/
|
|
45
|
+
export declare function readManyExisting(backend: StorageBackend, ids: ConceptId[], onMalformed?: (skip: SkippedDoc) => void): Promise<ReadResult[]>;
|
|
39
46
|
export declare function query(backend: StorageBackend, filter?: QueryFilter, options?: QueryOptions): Promise<OkfDocument[]>;
|
|
40
47
|
export declare const list: typeof query;
|
|
41
48
|
export declare function queryHeads(backend: StorageBackend, filter?: QueryFilter, options?: QueryOptions): Promise<HeadResult[]>;
|