superbee 0.4.3-pre.19 → 0.4.3-pre.20
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/publication-bridge.mjs +96 -96
- package/dist/publication.mjs +96 -96
- package/dist/superbee.mjs +766 -611
- package/package.json +1 -1
package/dist/superbee.mjs
CHANGED
|
@@ -44,7 +44,7 @@ var __toESM = (mod, isNodeMode, target3) => (target3 = mod != null ? __create(__
|
|
|
44
44
|
var define_SUPERBEE_BUILD_IDENTITY_default;
|
|
45
45
|
var init_define_SUPERBEE_BUILD_IDENTITY = __esm({
|
|
46
46
|
"<define:__SUPERBEE_BUILD_IDENTITY__>"() {
|
|
47
|
-
define_SUPERBEE_BUILD_IDENTITY_default = { schema: "superbee.build-identity.v1", package: { name: "superbee", version: "0.4.3-pre.
|
|
47
|
+
define_SUPERBEE_BUILD_IDENTITY_default = { schema: "superbee.build-identity.v1", package: { name: "superbee", version: "0.4.3-pre.20" }, source: { commit: "72beac1bac6d129a9e7792f1a5d5067d5220cf62", dirty: false }, artifact: { channel: "npm-package" }, compatibility_contracts: { skill: 1, hook: 1, mcp: 1 } };
|
|
48
48
|
}
|
|
49
49
|
});
|
|
50
50
|
|
|
@@ -3103,23 +3103,6 @@ var init_frontmatter = __esm({
|
|
|
3103
3103
|
}
|
|
3104
3104
|
});
|
|
3105
3105
|
|
|
3106
|
-
// ../core/src/meaningful-change-time.ts
|
|
3107
|
-
function meaningfulChangeTimeField(frontmatter) {
|
|
3108
|
-
const generated = frontmatter.generated;
|
|
3109
|
-
if (generated !== null && typeof generated === "object" && !Array.isArray(generated) && generated.at !== void 0) return "generated.at";
|
|
3110
|
-
return "timestamp";
|
|
3111
|
-
}
|
|
3112
|
-
function meaningfulChangeTimeValue(frontmatter) {
|
|
3113
|
-
return meaningfulChangeTimeField(frontmatter) === "generated.at" ? frontmatter.generated.at : frontmatter.timestamp;
|
|
3114
|
-
}
|
|
3115
|
-
var init_meaningful_change_time = __esm({
|
|
3116
|
-
"../core/src/meaningful-change-time.ts"() {
|
|
3117
|
-
"use strict";
|
|
3118
|
-
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
3119
|
-
init_define_SUPERBEE_UPDATE_POLICY();
|
|
3120
|
-
}
|
|
3121
|
-
});
|
|
3122
|
-
|
|
3123
3106
|
// ../core/src/errors.ts
|
|
3124
3107
|
var InvalidInputError, OkfActorError, FilesystemIdentityAliasError, ConcurrentReplacementError;
|
|
3125
3108
|
var init_errors = __esm({
|
|
@@ -3167,6 +3150,576 @@ var init_errors = __esm({
|
|
|
3167
3150
|
}
|
|
3168
3151
|
});
|
|
3169
3152
|
|
|
3153
|
+
// ../core/src/paths.ts
|
|
3154
|
+
function compareStorageKeys(a, b) {
|
|
3155
|
+
const primary = a.localeCompare(b);
|
|
3156
|
+
if (primary !== 0 || a === b) return primary;
|
|
3157
|
+
const left = Array.from(a, (character) => character.codePointAt(0));
|
|
3158
|
+
const right = Array.from(b, (character) => character.codePointAt(0));
|
|
3159
|
+
for (let i = 0; i < Math.min(left.length, right.length); i++) {
|
|
3160
|
+
if (left[i] !== right[i]) return left[i] - right[i];
|
|
3161
|
+
}
|
|
3162
|
+
return left.length - right.length;
|
|
3163
|
+
}
|
|
3164
|
+
function assertPortablePath(value, label) {
|
|
3165
|
+
if (/[\u0000-\u001f\u007f]/u.test(value) || /^[a-z]:/i.test(value)) {
|
|
3166
|
+
throw new InvalidInputError(`${label} must not contain controls or start with a drive prefix.`);
|
|
3167
|
+
}
|
|
3168
|
+
if (value.includes("\\") || value.split("/").some((segment) => segment === "" || segment === "." || segment === "..")) {
|
|
3169
|
+
throw new InvalidInputError(`${label} must be canonical and bundle-relative.`);
|
|
3170
|
+
}
|
|
3171
|
+
}
|
|
3172
|
+
function assertSafeReservedFilename(name) {
|
|
3173
|
+
if (!RESERVED_FILENAMES.includes(name)) {
|
|
3174
|
+
throw new InvalidInputError("Reserved filename must be index.md or log.md.");
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
function toPosix(p2) {
|
|
3178
|
+
return p2.replace(/\\/g, "/").replace(/\/{2,}/g, "/");
|
|
3179
|
+
}
|
|
3180
|
+
function isReservedFile(relPath) {
|
|
3181
|
+
const base = toPosix(relPath).split("/").pop() ?? "";
|
|
3182
|
+
return RESERVED_FILENAMES.includes(base);
|
|
3183
|
+
}
|
|
3184
|
+
function conceptIdFromPath(relPath) {
|
|
3185
|
+
const norm = toPosix(relPath).replace(/^\.?\//, "").split("/").filter((segment) => segment !== ".").join("/");
|
|
3186
|
+
return norm.endsWith(".md") ? norm.slice(0, -3) : norm;
|
|
3187
|
+
}
|
|
3188
|
+
function pathFromConceptId(id) {
|
|
3189
|
+
assertSafeConceptId(id);
|
|
3190
|
+
return `${id}.md`;
|
|
3191
|
+
}
|
|
3192
|
+
function assertSafeConceptId(id) {
|
|
3193
|
+
if (typeof id !== "string" || id.trim() === "") {
|
|
3194
|
+
throw new InvalidInputError("Concept id must be a non-empty string.");
|
|
3195
|
+
}
|
|
3196
|
+
assertPortablePath(id, "Concept id");
|
|
3197
|
+
const segments = id.split("/");
|
|
3198
|
+
if (segments.slice(0, -1).some((seg) => seg.toLowerCase().endsWith(".md"))) {
|
|
3199
|
+
throw new InvalidInputError(
|
|
3200
|
+
`Concept id must not contain a non-final segment ending in '.md': '${id}' (it collides with a concept file at that path).`
|
|
3201
|
+
);
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
function nonCanonicalDocumentId(id) {
|
|
3205
|
+
const segments = id.split("/");
|
|
3206
|
+
if (segments.some((segment) => segment !== segment.trim())) return "segment_whitespace";
|
|
3207
|
+
if (segments.some((segment) => FORMAT_AT_EDGE.test(segment) || FORMAT_INSIDE.test(segment))) return "format_character";
|
|
3208
|
+
if (id !== id.normalize("NFC")) return "not_nfc";
|
|
3209
|
+
return null;
|
|
3210
|
+
}
|
|
3211
|
+
function assertSafeBlobKey(key4) {
|
|
3212
|
+
if (typeof key4 !== "string" || key4.trim() === "") {
|
|
3213
|
+
throw new InvalidInputError("Blob key must be a non-empty string.");
|
|
3214
|
+
}
|
|
3215
|
+
assertPortablePath(key4, "Blob key");
|
|
3216
|
+
const segments = key4.split("/");
|
|
3217
|
+
if (segments.some((seg) => seg.startsWith("."))) {
|
|
3218
|
+
throw new InvalidInputError(`Blob key must not contain dot-prefixed segments: '${key4}'.`);
|
|
3219
|
+
}
|
|
3220
|
+
if (segments.some((seg) => seg.toLowerCase().endsWith(".md"))) {
|
|
3221
|
+
throw new InvalidInputError(
|
|
3222
|
+
`Blob key '${key4}' has a path segment ending in '.md' (checked case-insensitively, at any depth), which collides with the concept-document namespace \u2014 write it as a doc instead.`
|
|
3223
|
+
);
|
|
3224
|
+
}
|
|
3225
|
+
}
|
|
3226
|
+
function assertSafeReservedDir(dir) {
|
|
3227
|
+
if (typeof dir !== "string") {
|
|
3228
|
+
throw new InvalidInputError("Reserved-file directory must be a string.");
|
|
3229
|
+
}
|
|
3230
|
+
if (dir !== "") assertPortablePath(dir, "Reserved-file directory");
|
|
3231
|
+
}
|
|
3232
|
+
var RESERVED_FILENAMES, FORMAT_AT_EDGE, FORMAT_INSIDE;
|
|
3233
|
+
var init_paths = __esm({
|
|
3234
|
+
"../core/src/paths.ts"() {
|
|
3235
|
+
"use strict";
|
|
3236
|
+
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
3237
|
+
init_define_SUPERBEE_UPDATE_POLICY();
|
|
3238
|
+
init_errors();
|
|
3239
|
+
RESERVED_FILENAMES = ["index.md", "log.md"];
|
|
3240
|
+
FORMAT_AT_EDGE = new RegExp("^\\p{Cf}|\\p{Cf}$", "u");
|
|
3241
|
+
FORMAT_INSIDE = new RegExp("(?![\\u200c\\u200d])\\p{Cf}", "u");
|
|
3242
|
+
}
|
|
3243
|
+
});
|
|
3244
|
+
|
|
3245
|
+
// ../core/src/links.ts
|
|
3246
|
+
function normalizeSegments(segments) {
|
|
3247
|
+
const out = [];
|
|
3248
|
+
for (const segment of segments) {
|
|
3249
|
+
if (segment === "" || segment === ".") continue;
|
|
3250
|
+
if (segment === ".." && out.length > 0 && out[out.length - 1] !== "..") {
|
|
3251
|
+
out.pop();
|
|
3252
|
+
continue;
|
|
3253
|
+
}
|
|
3254
|
+
out.push(segment);
|
|
3255
|
+
}
|
|
3256
|
+
return out;
|
|
3257
|
+
}
|
|
3258
|
+
function joinPosix(base, rel) {
|
|
3259
|
+
return normalizeSegments([...base.split("/"), ...rel.split("/")]).join("/");
|
|
3260
|
+
}
|
|
3261
|
+
function relativePosix(from, to) {
|
|
3262
|
+
const fromSegments = normalizeSegments(from.split("/"));
|
|
3263
|
+
const toSegments = normalizeSegments(to.split("/"));
|
|
3264
|
+
let common = 0;
|
|
3265
|
+
while (common < fromSegments.length && common < toSegments.length && fromSegments[common] === toSegments[common]) {
|
|
3266
|
+
common++;
|
|
3267
|
+
}
|
|
3268
|
+
const ups = fromSegments.length - common;
|
|
3269
|
+
return [...Array(ups).fill(".."), ...toSegments.slice(common)].join("/");
|
|
3270
|
+
}
|
|
3271
|
+
function isExternalHref(href) {
|
|
3272
|
+
const h2 = href.trim();
|
|
3273
|
+
return /^[a-z][a-z0-9+.-]*:\/\//i.test(h2) || h2.startsWith("mailto:") || h2.startsWith("#");
|
|
3274
|
+
}
|
|
3275
|
+
function extractMarkdownLinks(source2, options = {}) {
|
|
3276
|
+
const body = options.skipCode ? maskMarkdownCode(source2) : source2;
|
|
3277
|
+
const out = [];
|
|
3278
|
+
let textOpen = -1;
|
|
3279
|
+
let afterClose;
|
|
3280
|
+
let hrefFirst;
|
|
3281
|
+
let hrefRest;
|
|
3282
|
+
for (let cursor = 0; cursor < body.length; cursor++) {
|
|
3283
|
+
const char = body[cursor];
|
|
3284
|
+
if (hrefRest) {
|
|
3285
|
+
if (char === ")") {
|
|
3286
|
+
if (hrefRest.open === 0 || body[hrefRest.open - 1] !== "!") {
|
|
3287
|
+
out.push({
|
|
3288
|
+
text: source2.slice(hrefRest.open + 1, hrefRest.close),
|
|
3289
|
+
href: source2.slice(hrefRest.hrefStart, cursor)
|
|
3290
|
+
});
|
|
3291
|
+
}
|
|
3292
|
+
textOpen = -1;
|
|
3293
|
+
afterClose = void 0;
|
|
3294
|
+
hrefFirst = void 0;
|
|
3295
|
+
hrefRest = void 0;
|
|
3296
|
+
continue;
|
|
3297
|
+
}
|
|
3298
|
+
if (char.trim() === "") hrefRest = void 0;
|
|
3299
|
+
}
|
|
3300
|
+
if (hrefFirst) {
|
|
3301
|
+
if (char !== ")" && char.trim() !== "" && !hrefRest) {
|
|
3302
|
+
hrefRest = hrefFirst;
|
|
3303
|
+
}
|
|
3304
|
+
hrefFirst = void 0;
|
|
3305
|
+
}
|
|
3306
|
+
if (afterClose) {
|
|
3307
|
+
if (char === "(") {
|
|
3308
|
+
hrefFirst = { ...afterClose, hrefStart: cursor + 1 };
|
|
3309
|
+
}
|
|
3310
|
+
afterClose = void 0;
|
|
3311
|
+
}
|
|
3312
|
+
if (textOpen >= 0 && char === "]") {
|
|
3313
|
+
afterClose = { open: textOpen, close: cursor };
|
|
3314
|
+
textOpen = -1;
|
|
3315
|
+
}
|
|
3316
|
+
if (char === "[" && textOpen < 0) textOpen = cursor;
|
|
3317
|
+
}
|
|
3318
|
+
return out;
|
|
3319
|
+
}
|
|
3320
|
+
function leadingIndent(line2, from, startColumn) {
|
|
3321
|
+
let columns = 0;
|
|
3322
|
+
let index2 = from;
|
|
3323
|
+
while (index2 < line2.length) {
|
|
3324
|
+
const char = line2[index2];
|
|
3325
|
+
if (char === " ") columns += 1;
|
|
3326
|
+
else if (char === " ") columns += 4 - (startColumn + columns) % 4;
|
|
3327
|
+
else break;
|
|
3328
|
+
index2++;
|
|
3329
|
+
}
|
|
3330
|
+
return { columns, chars: index2 - from };
|
|
3331
|
+
}
|
|
3332
|
+
function maskMarkdownCode(body) {
|
|
3333
|
+
const out = body.split("");
|
|
3334
|
+
const blank = (from, to) => {
|
|
3335
|
+
for (let index2 = from; index2 < to; index2++) if (out[index2] !== "\n" && out[index2] !== "\r") out[index2] = " ";
|
|
3336
|
+
};
|
|
3337
|
+
const lists = [];
|
|
3338
|
+
let fence = null;
|
|
3339
|
+
let inParagraph = false;
|
|
3340
|
+
let segmentStart = -1;
|
|
3341
|
+
const closeSegment = (end) => {
|
|
3342
|
+
if (segmentStart >= 0) maskCodeSpans(body, segmentStart, end, blank);
|
|
3343
|
+
segmentStart = -1;
|
|
3344
|
+
};
|
|
3345
|
+
let lineStart = 0;
|
|
3346
|
+
while (lineStart <= body.length) {
|
|
3347
|
+
const newline = body.indexOf("\n", lineStart);
|
|
3348
|
+
const lineEnd = newline < 0 ? body.length : newline;
|
|
3349
|
+
const line2 = body.slice(lineStart, lineEnd);
|
|
3350
|
+
let contentAt = 0;
|
|
3351
|
+
let quotes = 0;
|
|
3352
|
+
for (let match = /^ {0,3}> ?/.exec(line2); match; match = /^ {0,3}> ?/.exec(line2.slice(contentAt))) {
|
|
3353
|
+
if (fence && quotes >= fence.quotes) break;
|
|
3354
|
+
contentAt += match[0].length;
|
|
3355
|
+
quotes++;
|
|
3356
|
+
}
|
|
3357
|
+
const { columns: indent2, chars } = leadingIndent(line2, contentAt, contentAt);
|
|
3358
|
+
const rest = line2.slice(contentAt + chars).replace(/\r$/, "");
|
|
3359
|
+
const isBlank = rest.trim() === "";
|
|
3360
|
+
if (fence && (quotes < fence.quotes || !isBlank && indent2 < fence.container)) fence = null;
|
|
3361
|
+
if (fence) {
|
|
3362
|
+
const close = indent2 - fence.container <= 3 ? FENCE_OPEN.exec(rest) : null;
|
|
3363
|
+
if (close && close[1][0] === fence.char && close[1].length >= fence.length && close[2].trim() === "") fence = null;
|
|
3364
|
+
blank(lineStart, lineEnd);
|
|
3365
|
+
} else if (isBlank) {
|
|
3366
|
+
closeSegment(lineStart);
|
|
3367
|
+
inParagraph = false;
|
|
3368
|
+
} else {
|
|
3369
|
+
if (!inParagraph) while (lists.length > 0 && lists[lists.length - 1] > indent2) lists.pop();
|
|
3370
|
+
let container = lists.length > 0 ? lists[lists.length - 1] : 0;
|
|
3371
|
+
let relative3 = indent2 - container;
|
|
3372
|
+
let text5 = rest;
|
|
3373
|
+
let textAt = lineStart + contentAt + chars;
|
|
3374
|
+
const marker = relative3 <= 3 && !THEMATIC_BREAK.test(text5) ? LIST_MARKER.exec(text5) : null;
|
|
3375
|
+
if (marker) {
|
|
3376
|
+
closeSegment(lineStart);
|
|
3377
|
+
const markerEnd = indent2 + marker[1].length;
|
|
3378
|
+
const spacing = leadingIndent(marker[2], 0, contentAt + markerEnd).columns;
|
|
3379
|
+
const wide = marker[2] === "" || spacing >= 5;
|
|
3380
|
+
lists.push(markerEnd + (wide ? 1 : spacing));
|
|
3381
|
+
container = lists[lists.length - 1];
|
|
3382
|
+
text5 = text5.slice(marker[1].length + (wide ? 0 : marker[2].length));
|
|
3383
|
+
textAt += marker[1].length + (wide ? 0 : marker[2].length);
|
|
3384
|
+
relative3 = wide ? Math.max(spacing - 1, 0) : 0;
|
|
3385
|
+
inParagraph = false;
|
|
3386
|
+
}
|
|
3387
|
+
const open5 = relative3 <= 3 ? FENCE_OPEN.exec(text5) : null;
|
|
3388
|
+
if (open5 && !(open5[1][0] === "`" && open5[2].includes("`"))) {
|
|
3389
|
+
closeSegment(lineStart);
|
|
3390
|
+
fence = { char: open5[1][0], length: open5[1].length, container, quotes };
|
|
3391
|
+
blank(textAt, lineEnd);
|
|
3392
|
+
inParagraph = false;
|
|
3393
|
+
} else if (!inParagraph && relative3 >= 4) {
|
|
3394
|
+
closeSegment(lineStart);
|
|
3395
|
+
blank(textAt, lineEnd);
|
|
3396
|
+
} else if (ATX_HEADING.test(text5) || THEMATIC_BREAK.test(text5)) {
|
|
3397
|
+
closeSegment(lineStart);
|
|
3398
|
+
maskCodeSpans(body, textAt, lineEnd, blank);
|
|
3399
|
+
inParagraph = false;
|
|
3400
|
+
} else {
|
|
3401
|
+
if (segmentStart < 0) segmentStart = textAt;
|
|
3402
|
+
inParagraph = text5.trim() !== "";
|
|
3403
|
+
}
|
|
3404
|
+
}
|
|
3405
|
+
if (newline < 0) break;
|
|
3406
|
+
lineStart = newline + 1;
|
|
3407
|
+
}
|
|
3408
|
+
closeSegment(body.length);
|
|
3409
|
+
return out.join("");
|
|
3410
|
+
}
|
|
3411
|
+
function maskCodeSpans(body, from, to, blank) {
|
|
3412
|
+
const runs = [];
|
|
3413
|
+
for (let index2 = from; index2 < to; ) {
|
|
3414
|
+
if (body[index2] !== "`") {
|
|
3415
|
+
index2++;
|
|
3416
|
+
continue;
|
|
3417
|
+
}
|
|
3418
|
+
let end = index2;
|
|
3419
|
+
while (end < to && body[end] === "`") end++;
|
|
3420
|
+
runs.push({ at: index2, length: end - index2 });
|
|
3421
|
+
index2 = end;
|
|
3422
|
+
}
|
|
3423
|
+
const byLength = /* @__PURE__ */ new Map();
|
|
3424
|
+
runs.forEach((run, position2) => {
|
|
3425
|
+
const list6 = byLength.get(run.length);
|
|
3426
|
+
if (list6) list6.push(position2);
|
|
3427
|
+
else byLength.set(run.length, [position2]);
|
|
3428
|
+
});
|
|
3429
|
+
const next = /* @__PURE__ */ new Map();
|
|
3430
|
+
const nextRun = (length, after) => {
|
|
3431
|
+
const list6 = byLength.get(length);
|
|
3432
|
+
if (!list6) return -1;
|
|
3433
|
+
let cursor = next.get(length) ?? 0;
|
|
3434
|
+
while (cursor < list6.length && list6[cursor] <= after) cursor++;
|
|
3435
|
+
next.set(length, cursor);
|
|
3436
|
+
return cursor < list6.length ? list6[cursor] : -1;
|
|
3437
|
+
};
|
|
3438
|
+
let escapeScan = from;
|
|
3439
|
+
let escaped = false;
|
|
3440
|
+
for (let position2 = 0; position2 < runs.length; position2++) {
|
|
3441
|
+
let { at, length } = runs[position2];
|
|
3442
|
+
for (; escapeScan < at; escapeScan++) escaped = body[escapeScan] === "\\" ? !escaped : false;
|
|
3443
|
+
if (escaped) {
|
|
3444
|
+
at += 1;
|
|
3445
|
+
length -= 1;
|
|
3446
|
+
escaped = false;
|
|
3447
|
+
if (length === 0) continue;
|
|
3448
|
+
const list6 = byLength.get(length);
|
|
3449
|
+
if (!list6) continue;
|
|
3450
|
+
}
|
|
3451
|
+
const closer = nextRun(length, position2);
|
|
3452
|
+
if (closer < 0) continue;
|
|
3453
|
+
const close = runs[closer];
|
|
3454
|
+
blank(at, close.at + close.length);
|
|
3455
|
+
position2 = closer;
|
|
3456
|
+
escapeScan = close.at + close.length;
|
|
3457
|
+
escaped = false;
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3460
|
+
function resolveConceptId(fromId, href) {
|
|
3461
|
+
const target3 = (href.split("#")[0] ?? "").split("?")[0]?.trim() ?? "";
|
|
3462
|
+
if (target3 === "" || isExternalHref(target3)) return null;
|
|
3463
|
+
if (!target3.endsWith(".md")) return null;
|
|
3464
|
+
let resolved;
|
|
3465
|
+
if (target3.startsWith("/")) {
|
|
3466
|
+
resolved = target3.slice(1);
|
|
3467
|
+
} else {
|
|
3468
|
+
const slash = fromId.lastIndexOf("/");
|
|
3469
|
+
const fromDir = slash >= 0 ? fromId.slice(0, slash) : "";
|
|
3470
|
+
resolved = joinPosix(fromDir, target3);
|
|
3471
|
+
}
|
|
3472
|
+
resolved = resolved.replace(/^(\.\.\/)+/, "");
|
|
3473
|
+
if (isReservedFile(resolved)) return null;
|
|
3474
|
+
const id = resolved.replace(/\.md$/, "");
|
|
3475
|
+
try {
|
|
3476
|
+
assertSafeConceptId(id);
|
|
3477
|
+
return id;
|
|
3478
|
+
} catch (error51) {
|
|
3479
|
+
if (error51 instanceof InvalidInputError) return null;
|
|
3480
|
+
throw error51;
|
|
3481
|
+
}
|
|
3482
|
+
}
|
|
3483
|
+
function relativeHref(fromId, target3) {
|
|
3484
|
+
const t = target3.trim();
|
|
3485
|
+
if (isExternalHref(t)) return t;
|
|
3486
|
+
assertSafeConceptId(fromId);
|
|
3487
|
+
assertSafeConceptId(t);
|
|
3488
|
+
const targetId = t;
|
|
3489
|
+
const slash = fromId.lastIndexOf("/");
|
|
3490
|
+
const fromDir = slash >= 0 ? fromId.slice(0, slash) : "";
|
|
3491
|
+
return relativePosix(fromDir, `${targetId}.md`);
|
|
3492
|
+
}
|
|
3493
|
+
function parseLinksFromDoc(doc2) {
|
|
3494
|
+
const links = [];
|
|
3495
|
+
for (const raw of extractMarkdownLinks(doc2.body)) {
|
|
3496
|
+
const to = resolveConceptId(doc2.id, raw.href);
|
|
3497
|
+
if (to === null) continue;
|
|
3498
|
+
links.push({ from: doc2.id, to, text: raw.text, href: raw.href });
|
|
3499
|
+
}
|
|
3500
|
+
return links;
|
|
3501
|
+
}
|
|
3502
|
+
var FENCE_OPEN, LIST_MARKER, THEMATIC_BREAK, ATX_HEADING;
|
|
3503
|
+
var init_links = __esm({
|
|
3504
|
+
"../core/src/links.ts"() {
|
|
3505
|
+
"use strict";
|
|
3506
|
+
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
3507
|
+
init_define_SUPERBEE_UPDATE_POLICY();
|
|
3508
|
+
init_paths();
|
|
3509
|
+
init_errors();
|
|
3510
|
+
FENCE_OPEN = /^(`{3,}|~{3,})(.*)$/;
|
|
3511
|
+
LIST_MARKER = /^([-+*]|\d{1,9}[.)])([ \t]+|$)/;
|
|
3512
|
+
THEMATIC_BREAK = /^(?:(?:\*[ \t]*){3,}|(?:-[ \t]*){3,}|(?:_[ \t]*){3,})$/;
|
|
3513
|
+
ATX_HEADING = /^#{1,6}(?:[ \t]|$)/;
|
|
3514
|
+
}
|
|
3515
|
+
});
|
|
3516
|
+
|
|
3517
|
+
// ../core/src/body-replace-guards.ts
|
|
3518
|
+
function previewTruncationNotice(omitted) {
|
|
3519
|
+
return `${BODY_PREVIEW_TRUNCATION_MARKER} ${omitted} more character(s) are NOT shown`;
|
|
3520
|
+
}
|
|
3521
|
+
function attachBodyPreview(rec, body, fullBodyHelp) {
|
|
3522
|
+
if (body.length <= BODY_PREVIEW_LIMIT) {
|
|
3523
|
+
rec.body = body;
|
|
3524
|
+
return;
|
|
3525
|
+
}
|
|
3526
|
+
const omitted = body.length - BODY_PREVIEW_LIMIT;
|
|
3527
|
+
rec[BODY_PREVIEW_KEY] = `${body.slice(0, BODY_PREVIEW_LIMIT)}
|
|
3528
|
+
|
|
3529
|
+
${previewTruncationNotice(omitted)} \u2014 this value is a preview, not the document body; use this record's help to read the complete body before rewriting it.`;
|
|
3530
|
+
rec.body_truncated = true;
|
|
3531
|
+
rec.body_chars = body.length;
|
|
3532
|
+
rec.help = [...fullBodyHelp];
|
|
3533
|
+
}
|
|
3534
|
+
function matchesPreviewSlice(candidate, preview4) {
|
|
3535
|
+
if (candidate === preview4) return true;
|
|
3536
|
+
const trimmed = preview4.trimEnd();
|
|
3537
|
+
return trimmed !== "" && candidate.trimEnd() === trimmed;
|
|
3538
|
+
}
|
|
3539
|
+
function firstForeignNotice(storedBody, nextBody) {
|
|
3540
|
+
const preservesStoredBody = nextBody.includes(storedBody.trimEnd());
|
|
3541
|
+
const every = new RegExp(BODY_PREVIEW_TRUNCATION_SIGNATURE.source, `${BODY_PREVIEW_TRUNCATION_SIGNATURE.flags}g`);
|
|
3542
|
+
for (const match of nextBody.matchAll(every)) {
|
|
3543
|
+
if (!(preservesStoredBody && storedBody.includes(match[0]))) return match[0];
|
|
3544
|
+
}
|
|
3545
|
+
return void 0;
|
|
3546
|
+
}
|
|
3547
|
+
function isSameStoredBody(nextBody, existingBody) {
|
|
3548
|
+
return normalizeDocumentBodyForStorage(nextBody) === normalizeDocumentBodyForStorage(existingBody);
|
|
3549
|
+
}
|
|
3550
|
+
function bodyPreviewFinding(existing, nextBody) {
|
|
3551
|
+
if (isSameStoredBody(nextBody, existing.body)) return;
|
|
3552
|
+
const notice = firstForeignNotice(existing.body, nextBody);
|
|
3553
|
+
if (notice !== void 0) return { reason: "preview_marker", marker: BODY_PREVIEW_TRUNCATION_MARKER, notice };
|
|
3554
|
+
if (existing.body.length > BODY_PREVIEW_LIMIT && matchesPreviewSlice(nextBody, existing.body.slice(0, BODY_PREVIEW_LIMIT))) {
|
|
3555
|
+
return { reason: "stored_body_preview", preview_limit: BODY_PREVIEW_LIMIT, supplied_body_chars: nextBody.length, stored_body_chars: existing.body.length };
|
|
3556
|
+
}
|
|
3557
|
+
}
|
|
3558
|
+
function captureBodyReplacePosture(value) {
|
|
3559
|
+
if (value === void 0) return;
|
|
3560
|
+
if (value === null || typeof value !== "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) {
|
|
3561
|
+
throw new InvalidInputError("bodyReplace must be an object with boolean acceptTruncatedBody and/or replaceLinks fields.");
|
|
3562
|
+
}
|
|
3563
|
+
const captured = {};
|
|
3564
|
+
for (const key4 of Reflect.ownKeys(value)) {
|
|
3565
|
+
if (key4 !== "acceptTruncatedBody" && key4 !== "replaceLinks") throw new InvalidInputError("Unknown bodyReplace field.");
|
|
3566
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key4);
|
|
3567
|
+
if (!("value" in descriptor) || typeof descriptor.value !== "boolean") throw new InvalidInputError(`bodyReplace.${key4} must be a boolean.`);
|
|
3568
|
+
captured[key4] = descriptor.value;
|
|
3569
|
+
}
|
|
3570
|
+
return captured;
|
|
3571
|
+
}
|
|
3572
|
+
function computeDroppedLinks(existingLinks, nextLinks, mode = "target") {
|
|
3573
|
+
const nextByTarget = /* @__PURE__ */ new Map();
|
|
3574
|
+
for (const l of nextLinks) {
|
|
3575
|
+
const key4 = mode === "exact-edge" ? JSON.stringify([l.from, l.to]) : l.to;
|
|
3576
|
+
const bucket = nextByTarget.get(key4);
|
|
3577
|
+
if (bucket) bucket.push(l);
|
|
3578
|
+
else nextByTarget.set(key4, [l]);
|
|
3579
|
+
}
|
|
3580
|
+
const existingByTarget = /* @__PURE__ */ new Map();
|
|
3581
|
+
for (const l of existingLinks) {
|
|
3582
|
+
const key4 = mode === "exact-edge" ? JSON.stringify([l.from, l.to]) : l.to;
|
|
3583
|
+
const bucket = existingByTarget.get(key4);
|
|
3584
|
+
if (bucket) bucket.push(l);
|
|
3585
|
+
else existingByTarget.set(key4, [l]);
|
|
3586
|
+
}
|
|
3587
|
+
const dropped = [];
|
|
3588
|
+
for (const [target3, oldOccurrences] of existingByTarget) {
|
|
3589
|
+
const available = [...nextByTarget.get(target3) ?? []];
|
|
3590
|
+
const unmatchedExact = [];
|
|
3591
|
+
for (const old of oldOccurrences) {
|
|
3592
|
+
const idx = available.findIndex((n) => n.text === old.text);
|
|
3593
|
+
if (idx >= 0) available.splice(idx, 1);
|
|
3594
|
+
else unmatchedExact.push(old);
|
|
3595
|
+
}
|
|
3596
|
+
for (const old of unmatchedExact) {
|
|
3597
|
+
if (mode === "target" && available.length > 0) available.shift();
|
|
3598
|
+
else dropped.push(old);
|
|
3599
|
+
}
|
|
3600
|
+
}
|
|
3601
|
+
return dropped;
|
|
3602
|
+
}
|
|
3603
|
+
function droppedLinks(_bundle, existing, nextBody) {
|
|
3604
|
+
return computeDroppedLinks(parseLinksFromDoc(existing), parseLinksFromDoc({ ...existing, body: nextBody }));
|
|
3605
|
+
}
|
|
3606
|
+
function guardTruncatedBodyPreview(existing, nextBody, acceptTruncatedBody) {
|
|
3607
|
+
if (acceptTruncatedBody) return;
|
|
3608
|
+
const finding = bodyPreviewFinding(existing, nextBody);
|
|
3609
|
+
if (finding) throw new BodyReplaceError(existing.id, finding, BODY_PREVIEW_TRUNCATION_SIGNATURE.test(existing.body));
|
|
3610
|
+
}
|
|
3611
|
+
function guardDroppedLinks(bundle, existing, nextBody, replaceLinks) {
|
|
3612
|
+
if (replaceLinks || isSameStoredBody(nextBody, existing.body)) return;
|
|
3613
|
+
const dropped = droppedLinks(bundle, existing, nextBody);
|
|
3614
|
+
if (dropped.length) throw new BodyReplaceError(existing.id, { reason: "dropped_links", dropped_links: dropped });
|
|
3615
|
+
}
|
|
3616
|
+
function guardBodyReplace(bundle, existing, nextBody, posture) {
|
|
3617
|
+
if (isSameStoredBody(nextBody, existing.body)) return;
|
|
3618
|
+
guardTruncatedBodyPreview(existing, nextBody, Boolean(posture?.acceptTruncatedBody));
|
|
3619
|
+
guardDroppedLinks(bundle, existing, nextBody, Boolean(posture?.replaceLinks));
|
|
3620
|
+
}
|
|
3621
|
+
function assertTypedListPatch(kind2, storageField) {
|
|
3622
|
+
const types = kind2.fields.types ?? {};
|
|
3623
|
+
const type = Object.hasOwn(types, storageField) ? types[storageField] : void 0;
|
|
3624
|
+
if (type === "string-list" || type === "https-url-list") throw new TypedListPatchError(storageField, type);
|
|
3625
|
+
}
|
|
3626
|
+
var BODY_PREVIEW_LIMIT, BODY_PREVIEW_TRUNCATION_MARKER, BODY_PREVIEW_TRUNCATION_SIGNATURE, BODY_PREVIEW_KEY, BODY_PREVIEW_RESERVED_KEYS, BodyReplaceError, TypedListPatchError;
|
|
3627
|
+
var init_body_replace_guards = __esm({
|
|
3628
|
+
"../core/src/body-replace-guards.ts"() {
|
|
3629
|
+
"use strict";
|
|
3630
|
+
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
3631
|
+
init_define_SUPERBEE_UPDATE_POLICY();
|
|
3632
|
+
init_frontmatter();
|
|
3633
|
+
init_links();
|
|
3634
|
+
init_errors();
|
|
3635
|
+
BODY_PREVIEW_LIMIT = 1e3;
|
|
3636
|
+
BODY_PREVIEW_TRUNCATION_MARKER = "[superbee:body-preview-truncated]";
|
|
3637
|
+
BODY_PREVIEW_TRUNCATION_SIGNATURE = /\[superbee:body-preview-truncated\]\s+\d+\s+more\s+characters?\(?s?\)?\s+are\s+NOT\s+shown/i;
|
|
3638
|
+
BODY_PREVIEW_KEY = "body_preview";
|
|
3639
|
+
BODY_PREVIEW_RESERVED_KEYS = [
|
|
3640
|
+
"body",
|
|
3641
|
+
BODY_PREVIEW_KEY,
|
|
3642
|
+
"body_truncated",
|
|
3643
|
+
"body_chars",
|
|
3644
|
+
"help"
|
|
3645
|
+
];
|
|
3646
|
+
BodyReplaceError = class extends InvalidInputError {
|
|
3647
|
+
id;
|
|
3648
|
+
finding;
|
|
3649
|
+
storedCarriesNotice;
|
|
3650
|
+
constructor(id, finding, storedCarriesNotice = false) {
|
|
3651
|
+
super(`Body replacement of '${id}' refused: ${finding.reason}.`);
|
|
3652
|
+
this.name = "BodyReplaceError";
|
|
3653
|
+
this.id = id;
|
|
3654
|
+
this.finding = finding;
|
|
3655
|
+
this.storedCarriesNotice = storedCarriesNotice;
|
|
3656
|
+
}
|
|
3657
|
+
};
|
|
3658
|
+
TypedListPatchError = class extends InvalidInputError {
|
|
3659
|
+
field;
|
|
3660
|
+
fieldType;
|
|
3661
|
+
constructor(field, fieldType) {
|
|
3662
|
+
super(`'${field}' is a ${fieldType} field; use an explicit whole-list replacement.`);
|
|
3663
|
+
this.name = "TypedListPatchError";
|
|
3664
|
+
this.field = field;
|
|
3665
|
+
this.fieldType = fieldType;
|
|
3666
|
+
}
|
|
3667
|
+
};
|
|
3668
|
+
}
|
|
3669
|
+
});
|
|
3670
|
+
|
|
3671
|
+
// ../core/src/version-transport.ts
|
|
3672
|
+
function isContentVersion(value) {
|
|
3673
|
+
return typeof value === "string" && /^sha256:[0-9a-f]{64}$/.test(value);
|
|
3674
|
+
}
|
|
3675
|
+
function stripETagWrapper(raw) {
|
|
3676
|
+
let value = raw.trim();
|
|
3677
|
+
if (value.startsWith("W/")) value = value.slice(2);
|
|
3678
|
+
if (value.length >= 2 && value.startsWith('"') && value.endsWith('"')) {
|
|
3679
|
+
value = value.slice(1, -1);
|
|
3680
|
+
}
|
|
3681
|
+
return value;
|
|
3682
|
+
}
|
|
3683
|
+
var VersionConflict;
|
|
3684
|
+
var init_version_transport = __esm({
|
|
3685
|
+
"../core/src/version-transport.ts"() {
|
|
3686
|
+
"use strict";
|
|
3687
|
+
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
3688
|
+
init_define_SUPERBEE_UPDATE_POLICY();
|
|
3689
|
+
VersionConflict = class extends Error {
|
|
3690
|
+
name = "VersionConflict";
|
|
3691
|
+
id;
|
|
3692
|
+
expected;
|
|
3693
|
+
actual;
|
|
3694
|
+
constructor(id, expected, actual) {
|
|
3695
|
+
super(
|
|
3696
|
+
`version conflict on '${id}': expected ${expected ?? "absent"}, found ${actual ?? "none"} (the document changed since you read it \u2014 re-read and retry)`
|
|
3697
|
+
);
|
|
3698
|
+
this.id = id;
|
|
3699
|
+
this.expected = expected;
|
|
3700
|
+
this.actual = actual;
|
|
3701
|
+
}
|
|
3702
|
+
};
|
|
3703
|
+
}
|
|
3704
|
+
});
|
|
3705
|
+
|
|
3706
|
+
// ../core/src/meaningful-change-time.ts
|
|
3707
|
+
function meaningfulChangeTimeField(frontmatter) {
|
|
3708
|
+
const generated = frontmatter.generated;
|
|
3709
|
+
if (generated !== null && typeof generated === "object" && !Array.isArray(generated) && generated.at !== void 0) return "generated.at";
|
|
3710
|
+
return "timestamp";
|
|
3711
|
+
}
|
|
3712
|
+
function meaningfulChangeTimeValue(frontmatter) {
|
|
3713
|
+
return meaningfulChangeTimeField(frontmatter) === "generated.at" ? frontmatter.generated.at : frontmatter.timestamp;
|
|
3714
|
+
}
|
|
3715
|
+
var init_meaningful_change_time = __esm({
|
|
3716
|
+
"../core/src/meaningful-change-time.ts"() {
|
|
3717
|
+
"use strict";
|
|
3718
|
+
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
3719
|
+
init_define_SUPERBEE_UPDATE_POLICY();
|
|
3720
|
+
}
|
|
3721
|
+
});
|
|
3722
|
+
|
|
3170
3723
|
// ../core/src/okf-actor.ts
|
|
3171
3724
|
function isOkfActor(value) {
|
|
3172
3725
|
if (typeof value !== "string" || value.trim() !== value || value.length === 0 || /\s/.test(value)) {
|
|
@@ -3786,370 +4339,6 @@ var init_document_write_policy = __esm({
|
|
|
3786
4339
|
}
|
|
3787
4340
|
});
|
|
3788
4341
|
|
|
3789
|
-
// ../core/src/paths.ts
|
|
3790
|
-
function compareStorageKeys(a, b) {
|
|
3791
|
-
const primary = a.localeCompare(b);
|
|
3792
|
-
if (primary !== 0 || a === b) return primary;
|
|
3793
|
-
const left = Array.from(a, (character) => character.codePointAt(0));
|
|
3794
|
-
const right = Array.from(b, (character) => character.codePointAt(0));
|
|
3795
|
-
for (let i = 0; i < Math.min(left.length, right.length); i++) {
|
|
3796
|
-
if (left[i] !== right[i]) return left[i] - right[i];
|
|
3797
|
-
}
|
|
3798
|
-
return left.length - right.length;
|
|
3799
|
-
}
|
|
3800
|
-
function assertPortablePath(value, label) {
|
|
3801
|
-
if (/[\u0000-\u001f\u007f]/u.test(value) || /^[a-z]:/i.test(value)) {
|
|
3802
|
-
throw new InvalidInputError(`${label} must not contain controls or start with a drive prefix.`);
|
|
3803
|
-
}
|
|
3804
|
-
if (value.includes("\\") || value.split("/").some((segment) => segment === "" || segment === "." || segment === "..")) {
|
|
3805
|
-
throw new InvalidInputError(`${label} must be canonical and bundle-relative.`);
|
|
3806
|
-
}
|
|
3807
|
-
}
|
|
3808
|
-
function assertSafeReservedFilename(name) {
|
|
3809
|
-
if (!RESERVED_FILENAMES.includes(name)) {
|
|
3810
|
-
throw new InvalidInputError("Reserved filename must be index.md or log.md.");
|
|
3811
|
-
}
|
|
3812
|
-
}
|
|
3813
|
-
function toPosix(p2) {
|
|
3814
|
-
return p2.replace(/\\/g, "/").replace(/\/{2,}/g, "/");
|
|
3815
|
-
}
|
|
3816
|
-
function isReservedFile(relPath) {
|
|
3817
|
-
const base = toPosix(relPath).split("/").pop() ?? "";
|
|
3818
|
-
return RESERVED_FILENAMES.includes(base);
|
|
3819
|
-
}
|
|
3820
|
-
function conceptIdFromPath(relPath) {
|
|
3821
|
-
const norm = toPosix(relPath).replace(/^\.?\//, "").split("/").filter((segment) => segment !== ".").join("/");
|
|
3822
|
-
return norm.endsWith(".md") ? norm.slice(0, -3) : norm;
|
|
3823
|
-
}
|
|
3824
|
-
function pathFromConceptId(id) {
|
|
3825
|
-
assertSafeConceptId(id);
|
|
3826
|
-
return `${id}.md`;
|
|
3827
|
-
}
|
|
3828
|
-
function assertSafeConceptId(id) {
|
|
3829
|
-
if (typeof id !== "string" || id.trim() === "") {
|
|
3830
|
-
throw new InvalidInputError("Concept id must be a non-empty string.");
|
|
3831
|
-
}
|
|
3832
|
-
assertPortablePath(id, "Concept id");
|
|
3833
|
-
const segments = id.split("/");
|
|
3834
|
-
if (segments.slice(0, -1).some((seg) => seg.toLowerCase().endsWith(".md"))) {
|
|
3835
|
-
throw new InvalidInputError(
|
|
3836
|
-
`Concept id must not contain a non-final segment ending in '.md': '${id}' (it collides with a concept file at that path).`
|
|
3837
|
-
);
|
|
3838
|
-
}
|
|
3839
|
-
}
|
|
3840
|
-
function nonCanonicalDocumentId(id) {
|
|
3841
|
-
const segments = id.split("/");
|
|
3842
|
-
if (segments.some((segment) => segment !== segment.trim())) return "segment_whitespace";
|
|
3843
|
-
if (segments.some((segment) => FORMAT_AT_EDGE.test(segment) || FORMAT_INSIDE.test(segment))) return "format_character";
|
|
3844
|
-
if (id !== id.normalize("NFC")) return "not_nfc";
|
|
3845
|
-
return null;
|
|
3846
|
-
}
|
|
3847
|
-
function assertSafeBlobKey(key4) {
|
|
3848
|
-
if (typeof key4 !== "string" || key4.trim() === "") {
|
|
3849
|
-
throw new InvalidInputError("Blob key must be a non-empty string.");
|
|
3850
|
-
}
|
|
3851
|
-
assertPortablePath(key4, "Blob key");
|
|
3852
|
-
const segments = key4.split("/");
|
|
3853
|
-
if (segments.some((seg) => seg.startsWith("."))) {
|
|
3854
|
-
throw new InvalidInputError(`Blob key must not contain dot-prefixed segments: '${key4}'.`);
|
|
3855
|
-
}
|
|
3856
|
-
if (segments.some((seg) => seg.toLowerCase().endsWith(".md"))) {
|
|
3857
|
-
throw new InvalidInputError(
|
|
3858
|
-
`Blob key '${key4}' has a path segment ending in '.md' (checked case-insensitively, at any depth), which collides with the concept-document namespace \u2014 write it as a doc instead.`
|
|
3859
|
-
);
|
|
3860
|
-
}
|
|
3861
|
-
}
|
|
3862
|
-
function assertSafeReservedDir(dir) {
|
|
3863
|
-
if (typeof dir !== "string") {
|
|
3864
|
-
throw new InvalidInputError("Reserved-file directory must be a string.");
|
|
3865
|
-
}
|
|
3866
|
-
if (dir !== "") assertPortablePath(dir, "Reserved-file directory");
|
|
3867
|
-
}
|
|
3868
|
-
var RESERVED_FILENAMES, FORMAT_AT_EDGE, FORMAT_INSIDE;
|
|
3869
|
-
var init_paths = __esm({
|
|
3870
|
-
"../core/src/paths.ts"() {
|
|
3871
|
-
"use strict";
|
|
3872
|
-
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
3873
|
-
init_define_SUPERBEE_UPDATE_POLICY();
|
|
3874
|
-
init_errors();
|
|
3875
|
-
RESERVED_FILENAMES = ["index.md", "log.md"];
|
|
3876
|
-
FORMAT_AT_EDGE = new RegExp("^\\p{Cf}|\\p{Cf}$", "u");
|
|
3877
|
-
FORMAT_INSIDE = new RegExp("(?![\\u200c\\u200d])\\p{Cf}", "u");
|
|
3878
|
-
}
|
|
3879
|
-
});
|
|
3880
|
-
|
|
3881
|
-
// ../core/src/links.ts
|
|
3882
|
-
function normalizeSegments(segments) {
|
|
3883
|
-
const out = [];
|
|
3884
|
-
for (const segment of segments) {
|
|
3885
|
-
if (segment === "" || segment === ".") continue;
|
|
3886
|
-
if (segment === ".." && out.length > 0 && out[out.length - 1] !== "..") {
|
|
3887
|
-
out.pop();
|
|
3888
|
-
continue;
|
|
3889
|
-
}
|
|
3890
|
-
out.push(segment);
|
|
3891
|
-
}
|
|
3892
|
-
return out;
|
|
3893
|
-
}
|
|
3894
|
-
function joinPosix(base, rel) {
|
|
3895
|
-
return normalizeSegments([...base.split("/"), ...rel.split("/")]).join("/");
|
|
3896
|
-
}
|
|
3897
|
-
function relativePosix(from, to) {
|
|
3898
|
-
const fromSegments = normalizeSegments(from.split("/"));
|
|
3899
|
-
const toSegments = normalizeSegments(to.split("/"));
|
|
3900
|
-
let common = 0;
|
|
3901
|
-
while (common < fromSegments.length && common < toSegments.length && fromSegments[common] === toSegments[common]) {
|
|
3902
|
-
common++;
|
|
3903
|
-
}
|
|
3904
|
-
const ups = fromSegments.length - common;
|
|
3905
|
-
return [...Array(ups).fill(".."), ...toSegments.slice(common)].join("/");
|
|
3906
|
-
}
|
|
3907
|
-
function isExternalHref(href) {
|
|
3908
|
-
const h2 = href.trim();
|
|
3909
|
-
return /^[a-z][a-z0-9+.-]*:\/\//i.test(h2) || h2.startsWith("mailto:") || h2.startsWith("#");
|
|
3910
|
-
}
|
|
3911
|
-
function extractMarkdownLinks(source2, options = {}) {
|
|
3912
|
-
const body = options.skipCode ? maskMarkdownCode(source2) : source2;
|
|
3913
|
-
const out = [];
|
|
3914
|
-
let textOpen = -1;
|
|
3915
|
-
let afterClose;
|
|
3916
|
-
let hrefFirst;
|
|
3917
|
-
let hrefRest;
|
|
3918
|
-
for (let cursor = 0; cursor < body.length; cursor++) {
|
|
3919
|
-
const char = body[cursor];
|
|
3920
|
-
if (hrefRest) {
|
|
3921
|
-
if (char === ")") {
|
|
3922
|
-
if (hrefRest.open === 0 || body[hrefRest.open - 1] !== "!") {
|
|
3923
|
-
out.push({
|
|
3924
|
-
text: source2.slice(hrefRest.open + 1, hrefRest.close),
|
|
3925
|
-
href: source2.slice(hrefRest.hrefStart, cursor)
|
|
3926
|
-
});
|
|
3927
|
-
}
|
|
3928
|
-
textOpen = -1;
|
|
3929
|
-
afterClose = void 0;
|
|
3930
|
-
hrefFirst = void 0;
|
|
3931
|
-
hrefRest = void 0;
|
|
3932
|
-
continue;
|
|
3933
|
-
}
|
|
3934
|
-
if (char.trim() === "") hrefRest = void 0;
|
|
3935
|
-
}
|
|
3936
|
-
if (hrefFirst) {
|
|
3937
|
-
if (char !== ")" && char.trim() !== "" && !hrefRest) {
|
|
3938
|
-
hrefRest = hrefFirst;
|
|
3939
|
-
}
|
|
3940
|
-
hrefFirst = void 0;
|
|
3941
|
-
}
|
|
3942
|
-
if (afterClose) {
|
|
3943
|
-
if (char === "(") {
|
|
3944
|
-
hrefFirst = { ...afterClose, hrefStart: cursor + 1 };
|
|
3945
|
-
}
|
|
3946
|
-
afterClose = void 0;
|
|
3947
|
-
}
|
|
3948
|
-
if (textOpen >= 0 && char === "]") {
|
|
3949
|
-
afterClose = { open: textOpen, close: cursor };
|
|
3950
|
-
textOpen = -1;
|
|
3951
|
-
}
|
|
3952
|
-
if (char === "[" && textOpen < 0) textOpen = cursor;
|
|
3953
|
-
}
|
|
3954
|
-
return out;
|
|
3955
|
-
}
|
|
3956
|
-
function leadingIndent(line2, from, startColumn) {
|
|
3957
|
-
let columns = 0;
|
|
3958
|
-
let index2 = from;
|
|
3959
|
-
while (index2 < line2.length) {
|
|
3960
|
-
const char = line2[index2];
|
|
3961
|
-
if (char === " ") columns += 1;
|
|
3962
|
-
else if (char === " ") columns += 4 - (startColumn + columns) % 4;
|
|
3963
|
-
else break;
|
|
3964
|
-
index2++;
|
|
3965
|
-
}
|
|
3966
|
-
return { columns, chars: index2 - from };
|
|
3967
|
-
}
|
|
3968
|
-
function maskMarkdownCode(body) {
|
|
3969
|
-
const out = body.split("");
|
|
3970
|
-
const blank = (from, to) => {
|
|
3971
|
-
for (let index2 = from; index2 < to; index2++) if (out[index2] !== "\n" && out[index2] !== "\r") out[index2] = " ";
|
|
3972
|
-
};
|
|
3973
|
-
const lists = [];
|
|
3974
|
-
let fence = null;
|
|
3975
|
-
let inParagraph = false;
|
|
3976
|
-
let segmentStart = -1;
|
|
3977
|
-
const closeSegment = (end) => {
|
|
3978
|
-
if (segmentStart >= 0) maskCodeSpans(body, segmentStart, end, blank);
|
|
3979
|
-
segmentStart = -1;
|
|
3980
|
-
};
|
|
3981
|
-
let lineStart = 0;
|
|
3982
|
-
while (lineStart <= body.length) {
|
|
3983
|
-
const newline = body.indexOf("\n", lineStart);
|
|
3984
|
-
const lineEnd = newline < 0 ? body.length : newline;
|
|
3985
|
-
const line2 = body.slice(lineStart, lineEnd);
|
|
3986
|
-
let contentAt = 0;
|
|
3987
|
-
let quotes = 0;
|
|
3988
|
-
for (let match = /^ {0,3}> ?/.exec(line2); match; match = /^ {0,3}> ?/.exec(line2.slice(contentAt))) {
|
|
3989
|
-
if (fence && quotes >= fence.quotes) break;
|
|
3990
|
-
contentAt += match[0].length;
|
|
3991
|
-
quotes++;
|
|
3992
|
-
}
|
|
3993
|
-
const { columns: indent2, chars } = leadingIndent(line2, contentAt, contentAt);
|
|
3994
|
-
const rest = line2.slice(contentAt + chars).replace(/\r$/, "");
|
|
3995
|
-
const isBlank = rest.trim() === "";
|
|
3996
|
-
if (fence && (quotes < fence.quotes || !isBlank && indent2 < fence.container)) fence = null;
|
|
3997
|
-
if (fence) {
|
|
3998
|
-
const close = indent2 - fence.container <= 3 ? FENCE_OPEN.exec(rest) : null;
|
|
3999
|
-
if (close && close[1][0] === fence.char && close[1].length >= fence.length && close[2].trim() === "") fence = null;
|
|
4000
|
-
blank(lineStart, lineEnd);
|
|
4001
|
-
} else if (isBlank) {
|
|
4002
|
-
closeSegment(lineStart);
|
|
4003
|
-
inParagraph = false;
|
|
4004
|
-
} else {
|
|
4005
|
-
if (!inParagraph) while (lists.length > 0 && lists[lists.length - 1] > indent2) lists.pop();
|
|
4006
|
-
let container = lists.length > 0 ? lists[lists.length - 1] : 0;
|
|
4007
|
-
let relative3 = indent2 - container;
|
|
4008
|
-
let text5 = rest;
|
|
4009
|
-
let textAt = lineStart + contentAt + chars;
|
|
4010
|
-
const marker = relative3 <= 3 && !THEMATIC_BREAK.test(text5) ? LIST_MARKER.exec(text5) : null;
|
|
4011
|
-
if (marker) {
|
|
4012
|
-
closeSegment(lineStart);
|
|
4013
|
-
const markerEnd = indent2 + marker[1].length;
|
|
4014
|
-
const spacing = leadingIndent(marker[2], 0, contentAt + markerEnd).columns;
|
|
4015
|
-
const wide = marker[2] === "" || spacing >= 5;
|
|
4016
|
-
lists.push(markerEnd + (wide ? 1 : spacing));
|
|
4017
|
-
container = lists[lists.length - 1];
|
|
4018
|
-
text5 = text5.slice(marker[1].length + (wide ? 0 : marker[2].length));
|
|
4019
|
-
textAt += marker[1].length + (wide ? 0 : marker[2].length);
|
|
4020
|
-
relative3 = wide ? Math.max(spacing - 1, 0) : 0;
|
|
4021
|
-
inParagraph = false;
|
|
4022
|
-
}
|
|
4023
|
-
const open5 = relative3 <= 3 ? FENCE_OPEN.exec(text5) : null;
|
|
4024
|
-
if (open5 && !(open5[1][0] === "`" && open5[2].includes("`"))) {
|
|
4025
|
-
closeSegment(lineStart);
|
|
4026
|
-
fence = { char: open5[1][0], length: open5[1].length, container, quotes };
|
|
4027
|
-
blank(textAt, lineEnd);
|
|
4028
|
-
inParagraph = false;
|
|
4029
|
-
} else if (!inParagraph && relative3 >= 4) {
|
|
4030
|
-
closeSegment(lineStart);
|
|
4031
|
-
blank(textAt, lineEnd);
|
|
4032
|
-
} else if (ATX_HEADING.test(text5) || THEMATIC_BREAK.test(text5)) {
|
|
4033
|
-
closeSegment(lineStart);
|
|
4034
|
-
maskCodeSpans(body, textAt, lineEnd, blank);
|
|
4035
|
-
inParagraph = false;
|
|
4036
|
-
} else {
|
|
4037
|
-
if (segmentStart < 0) segmentStart = textAt;
|
|
4038
|
-
inParagraph = text5.trim() !== "";
|
|
4039
|
-
}
|
|
4040
|
-
}
|
|
4041
|
-
if (newline < 0) break;
|
|
4042
|
-
lineStart = newline + 1;
|
|
4043
|
-
}
|
|
4044
|
-
closeSegment(body.length);
|
|
4045
|
-
return out.join("");
|
|
4046
|
-
}
|
|
4047
|
-
function maskCodeSpans(body, from, to, blank) {
|
|
4048
|
-
const runs = [];
|
|
4049
|
-
for (let index2 = from; index2 < to; ) {
|
|
4050
|
-
if (body[index2] !== "`") {
|
|
4051
|
-
index2++;
|
|
4052
|
-
continue;
|
|
4053
|
-
}
|
|
4054
|
-
let end = index2;
|
|
4055
|
-
while (end < to && body[end] === "`") end++;
|
|
4056
|
-
runs.push({ at: index2, length: end - index2 });
|
|
4057
|
-
index2 = end;
|
|
4058
|
-
}
|
|
4059
|
-
const byLength = /* @__PURE__ */ new Map();
|
|
4060
|
-
runs.forEach((run, position2) => {
|
|
4061
|
-
const list6 = byLength.get(run.length);
|
|
4062
|
-
if (list6) list6.push(position2);
|
|
4063
|
-
else byLength.set(run.length, [position2]);
|
|
4064
|
-
});
|
|
4065
|
-
const next = /* @__PURE__ */ new Map();
|
|
4066
|
-
const nextRun = (length, after) => {
|
|
4067
|
-
const list6 = byLength.get(length);
|
|
4068
|
-
if (!list6) return -1;
|
|
4069
|
-
let cursor = next.get(length) ?? 0;
|
|
4070
|
-
while (cursor < list6.length && list6[cursor] <= after) cursor++;
|
|
4071
|
-
next.set(length, cursor);
|
|
4072
|
-
return cursor < list6.length ? list6[cursor] : -1;
|
|
4073
|
-
};
|
|
4074
|
-
let escapeScan = from;
|
|
4075
|
-
let escaped = false;
|
|
4076
|
-
for (let position2 = 0; position2 < runs.length; position2++) {
|
|
4077
|
-
let { at, length } = runs[position2];
|
|
4078
|
-
for (; escapeScan < at; escapeScan++) escaped = body[escapeScan] === "\\" ? !escaped : false;
|
|
4079
|
-
if (escaped) {
|
|
4080
|
-
at += 1;
|
|
4081
|
-
length -= 1;
|
|
4082
|
-
escaped = false;
|
|
4083
|
-
if (length === 0) continue;
|
|
4084
|
-
const list6 = byLength.get(length);
|
|
4085
|
-
if (!list6) continue;
|
|
4086
|
-
}
|
|
4087
|
-
const closer = nextRun(length, position2);
|
|
4088
|
-
if (closer < 0) continue;
|
|
4089
|
-
const close = runs[closer];
|
|
4090
|
-
blank(at, close.at + close.length);
|
|
4091
|
-
position2 = closer;
|
|
4092
|
-
escapeScan = close.at + close.length;
|
|
4093
|
-
escaped = false;
|
|
4094
|
-
}
|
|
4095
|
-
}
|
|
4096
|
-
function resolveConceptId(fromId, href) {
|
|
4097
|
-
const target3 = (href.split("#")[0] ?? "").split("?")[0]?.trim() ?? "";
|
|
4098
|
-
if (target3 === "" || isExternalHref(target3)) return null;
|
|
4099
|
-
if (!target3.endsWith(".md")) return null;
|
|
4100
|
-
let resolved;
|
|
4101
|
-
if (target3.startsWith("/")) {
|
|
4102
|
-
resolved = target3.slice(1);
|
|
4103
|
-
} else {
|
|
4104
|
-
const slash = fromId.lastIndexOf("/");
|
|
4105
|
-
const fromDir = slash >= 0 ? fromId.slice(0, slash) : "";
|
|
4106
|
-
resolved = joinPosix(fromDir, target3);
|
|
4107
|
-
}
|
|
4108
|
-
resolved = resolved.replace(/^(\.\.\/)+/, "");
|
|
4109
|
-
if (isReservedFile(resolved)) return null;
|
|
4110
|
-
const id = resolved.replace(/\.md$/, "");
|
|
4111
|
-
try {
|
|
4112
|
-
assertSafeConceptId(id);
|
|
4113
|
-
return id;
|
|
4114
|
-
} catch (error51) {
|
|
4115
|
-
if (error51 instanceof InvalidInputError) return null;
|
|
4116
|
-
throw error51;
|
|
4117
|
-
}
|
|
4118
|
-
}
|
|
4119
|
-
function relativeHref(fromId, target3) {
|
|
4120
|
-
const t = target3.trim();
|
|
4121
|
-
if (isExternalHref(t)) return t;
|
|
4122
|
-
assertSafeConceptId(fromId);
|
|
4123
|
-
assertSafeConceptId(t);
|
|
4124
|
-
const targetId = t;
|
|
4125
|
-
const slash = fromId.lastIndexOf("/");
|
|
4126
|
-
const fromDir = slash >= 0 ? fromId.slice(0, slash) : "";
|
|
4127
|
-
return relativePosix(fromDir, `${targetId}.md`);
|
|
4128
|
-
}
|
|
4129
|
-
function parseLinksFromDoc(doc2) {
|
|
4130
|
-
const links = [];
|
|
4131
|
-
for (const raw of extractMarkdownLinks(doc2.body)) {
|
|
4132
|
-
const to = resolveConceptId(doc2.id, raw.href);
|
|
4133
|
-
if (to === null) continue;
|
|
4134
|
-
links.push({ from: doc2.id, to, text: raw.text, href: raw.href });
|
|
4135
|
-
}
|
|
4136
|
-
return links;
|
|
4137
|
-
}
|
|
4138
|
-
var FENCE_OPEN, LIST_MARKER, THEMATIC_BREAK, ATX_HEADING;
|
|
4139
|
-
var init_links = __esm({
|
|
4140
|
-
"../core/src/links.ts"() {
|
|
4141
|
-
"use strict";
|
|
4142
|
-
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
4143
|
-
init_define_SUPERBEE_UPDATE_POLICY();
|
|
4144
|
-
init_paths();
|
|
4145
|
-
init_errors();
|
|
4146
|
-
FENCE_OPEN = /^(`{3,}|~{3,})(.*)$/;
|
|
4147
|
-
LIST_MARKER = /^([-+*]|\d{1,9}[.)])([ \t]+|$)/;
|
|
4148
|
-
THEMATIC_BREAK = /^(?:(?:\*[ \t]*){3,}|(?:-[ \t]*){3,}|(?:_[ \t]*){3,})$/;
|
|
4149
|
-
ATX_HEADING = /^#{1,6}(?:[ \t]|$)/;
|
|
4150
|
-
}
|
|
4151
|
-
});
|
|
4152
|
-
|
|
4153
4342
|
// ../core/src/portable-frontmatter.ts
|
|
4154
4343
|
function parseLeadingFrontmatter(raw, context2) {
|
|
4155
4344
|
const split = splitLeadingFrontmatter(raw, context2);
|
|
@@ -4410,11 +4599,34 @@ async function listBlobs(backend, prefix) {
|
|
|
4410
4599
|
async function deleteBlob(backend, key4, options) {
|
|
4411
4600
|
return backend.deleteBlob(key4, options);
|
|
4412
4601
|
}
|
|
4602
|
+
async function writeDocVersionedGuarded(backend, doc2, options = {}) {
|
|
4603
|
+
const candidate = structuredClone(doc2);
|
|
4604
|
+
assertWritableConceptDocument(candidate);
|
|
4605
|
+
const posture = captureBodyReplacePosture(options.bodyReplace);
|
|
4606
|
+
const captured = { ...options, ...posture === void 0 ? {} : { bodyReplace: posture } };
|
|
4607
|
+
let existing;
|
|
4608
|
+
try {
|
|
4609
|
+
existing = await backend.read(candidate.id);
|
|
4610
|
+
} catch (error51) {
|
|
4611
|
+
if (error51?.code !== "ENOENT") throw error51;
|
|
4612
|
+
}
|
|
4613
|
+
const observed = existing?.version ?? null;
|
|
4614
|
+
if (captured.expectedVersion !== void 0 && captured.expectedVersion !== observed) {
|
|
4615
|
+
throw new VersionConflict(candidate.id, captured.expectedVersion, observed);
|
|
4616
|
+
}
|
|
4617
|
+
if ((posture?.replaceLinks || posture?.acceptTruncatedBody) && captured.expectedVersion === void 0) {
|
|
4618
|
+
throw new InvalidInputError("bodyReplace overrides require an explicit expected version (If-Match or If-None-Match: *).");
|
|
4619
|
+
}
|
|
4620
|
+
if (existing) guardBodyReplace({ root: "", backend }, existing.doc, candidate.body, posture);
|
|
4621
|
+
return writeDocVersioned(backend, candidate, { ...captured, expectedVersion: observed });
|
|
4622
|
+
}
|
|
4413
4623
|
var init_engine = __esm({
|
|
4414
4624
|
"../core/src/engine.ts"() {
|
|
4415
4625
|
"use strict";
|
|
4416
4626
|
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
4417
4627
|
init_define_SUPERBEE_UPDATE_POLICY();
|
|
4628
|
+
init_body_replace_guards();
|
|
4629
|
+
init_version_transport();
|
|
4418
4630
|
init_document_write_policy();
|
|
4419
4631
|
init_errors();
|
|
4420
4632
|
init_frontmatter_contract();
|
|
@@ -4422,6 +4634,7 @@ var init_engine = __esm({
|
|
|
4422
4634
|
init_paths();
|
|
4423
4635
|
init_portable_frontmatter();
|
|
4424
4636
|
init_query_filter();
|
|
4637
|
+
init_body_replace_guards();
|
|
4425
4638
|
}
|
|
4426
4639
|
});
|
|
4427
4640
|
|
|
@@ -5846,41 +6059,6 @@ var init_sha256 = __esm({
|
|
|
5846
6059
|
}
|
|
5847
6060
|
});
|
|
5848
6061
|
|
|
5849
|
-
// ../core/src/version-transport.ts
|
|
5850
|
-
function isContentVersion(value) {
|
|
5851
|
-
return typeof value === "string" && /^sha256:[0-9a-f]{64}$/.test(value);
|
|
5852
|
-
}
|
|
5853
|
-
function stripETagWrapper(raw) {
|
|
5854
|
-
let value = raw.trim();
|
|
5855
|
-
if (value.startsWith("W/")) value = value.slice(2);
|
|
5856
|
-
if (value.length >= 2 && value.startsWith('"') && value.endsWith('"')) {
|
|
5857
|
-
value = value.slice(1, -1);
|
|
5858
|
-
}
|
|
5859
|
-
return value;
|
|
5860
|
-
}
|
|
5861
|
-
var VersionConflict;
|
|
5862
|
-
var init_version_transport = __esm({
|
|
5863
|
-
"../core/src/version-transport.ts"() {
|
|
5864
|
-
"use strict";
|
|
5865
|
-
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
5866
|
-
init_define_SUPERBEE_UPDATE_POLICY();
|
|
5867
|
-
VersionConflict = class extends Error {
|
|
5868
|
-
name = "VersionConflict";
|
|
5869
|
-
id;
|
|
5870
|
-
expected;
|
|
5871
|
-
actual;
|
|
5872
|
-
constructor(id, expected, actual) {
|
|
5873
|
-
super(
|
|
5874
|
-
`version conflict on '${id}': expected ${expected ?? "absent"}, found ${actual ?? "none"} (the document changed since you read it \u2014 re-read and retry)`
|
|
5875
|
-
);
|
|
5876
|
-
this.id = id;
|
|
5877
|
-
this.expected = expected;
|
|
5878
|
-
this.actual = actual;
|
|
5879
|
-
}
|
|
5880
|
-
};
|
|
5881
|
-
}
|
|
5882
|
-
});
|
|
5883
|
-
|
|
5884
6062
|
// ../core/src/versioning.ts
|
|
5885
6063
|
function sha256Hex(input) {
|
|
5886
6064
|
return sha256HexOfUtf8(input);
|
|
@@ -8677,6 +8855,7 @@ function assertJournalGuard(expected, current) {
|
|
|
8677
8855
|
if (!equalJournalValue(a, b)) throw new JournalGuardConflict(a.target);
|
|
8678
8856
|
}
|
|
8679
8857
|
function captureIntentUpdate(patch, options) {
|
|
8858
|
+
if (Object.hasOwn(patch, "bodyReplace")) throw new JournalGuardConflict("bodyReplace");
|
|
8680
8859
|
const guard = captureJournalGuardOption(options);
|
|
8681
8860
|
if (guard !== void 0) captureJournalValue({ patch, options });
|
|
8682
8861
|
if (options.document && guard === void 0) throw new JournalGuardConflict(options.document.id);
|
|
@@ -8747,7 +8926,17 @@ function captureJournalDeleteOptions(target3, options) {
|
|
|
8747
8926
|
}
|
|
8748
8927
|
return captured;
|
|
8749
8928
|
}
|
|
8929
|
+
function captureNewDocumentIntent(intent) {
|
|
8930
|
+
const captured = captureJournalValue(intent);
|
|
8931
|
+
const posture = captureBodyReplacePosture(captured.bodyReplace);
|
|
8932
|
+
if (posture !== void 0) {
|
|
8933
|
+
if (captured.kind !== "document.write") throw new JournalGuardConflict(captured.target);
|
|
8934
|
+
return { ...captured, bodyReplace: posture };
|
|
8935
|
+
}
|
|
8936
|
+
return captured;
|
|
8937
|
+
}
|
|
8750
8938
|
function assertDeletionIntent(target3, options) {
|
|
8939
|
+
if (options.intent && Object.hasOwn(options.intent, "bodyReplace")) throw new JournalSnapshotConflict(target3);
|
|
8751
8940
|
if (options.intent === void 0 && options.supersede === void 0) return;
|
|
8752
8941
|
if (options.guard !== void 0 || options.intent !== void 0 && (options.intent.kind !== DOCUMENT_DELETE_KIND || options.intent.target !== target3)) {
|
|
8753
8942
|
throw new JournalSnapshotConflict(target3);
|
|
@@ -8782,6 +8971,7 @@ var init_journaled_backend = __esm({
|
|
|
8782
8971
|
"use strict";
|
|
8783
8972
|
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
8784
8973
|
init_define_SUPERBEE_UPDATE_POLICY();
|
|
8974
|
+
init_body_replace_guards();
|
|
8785
8975
|
init_paths();
|
|
8786
8976
|
init_versioning();
|
|
8787
8977
|
DOCUMENT_DELETE_KIND = "document.delete";
|
|
@@ -8906,8 +9096,8 @@ function captureRemoteFrontmatter(frontmatter) {
|
|
|
8906
9096
|
};
|
|
8907
9097
|
return visit3(frontmatter, "frontmatter", 0);
|
|
8908
9098
|
}
|
|
8909
|
-
function encodeRemoteDocument(frontmatter, body) {
|
|
8910
|
-
const payload = Object.assign(/* @__PURE__ */ Object.create(null), { frontmatter: captureRemoteFrontmatter(frontmatter), body });
|
|
9099
|
+
function encodeRemoteDocument(frontmatter, body, bodyReplace) {
|
|
9100
|
+
const payload = Object.assign(/* @__PURE__ */ Object.create(null), { frontmatter: captureRemoteFrontmatter(frontmatter), body, ...bodyReplace === void 0 ? {} : { bodyReplace: captureBodyReplacePosture(bodyReplace) } });
|
|
8911
9101
|
return JSON.stringify(payload);
|
|
8912
9102
|
}
|
|
8913
9103
|
var RemoteDocumentValueError;
|
|
@@ -8916,6 +9106,7 @@ var init_remote_document_codec = __esm({
|
|
|
8916
9106
|
"use strict";
|
|
8917
9107
|
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
8918
9108
|
init_define_SUPERBEE_UPDATE_POLICY();
|
|
9109
|
+
init_body_replace_guards();
|
|
8919
9110
|
init_errors();
|
|
8920
9111
|
RemoteDocumentValueError = class extends InvalidInputError {
|
|
8921
9112
|
path;
|
|
@@ -9501,7 +9692,7 @@ var init_remote_backend = __esm({
|
|
|
9501
9692
|
if (options.expectedVersion === null) headers["If-None-Match"] = "*";
|
|
9502
9693
|
else if (options.expectedVersion !== void 0) headers["If-Match"] = options.expectedVersion;
|
|
9503
9694
|
if (options.actor) headers["X-Actor"] = options.actor;
|
|
9504
|
-
const body = encodeRemoteDocument(doc2.frontmatter, doc2.body ?? "");
|
|
9695
|
+
const body = encodeRemoteDocument(doc2.frontmatter, doc2.body ?? "", options.bodyReplace);
|
|
9505
9696
|
let minted = false;
|
|
9506
9697
|
if (options.requestId !== void 0) {
|
|
9507
9698
|
assertRequestIdentity(options.requestId);
|
|
@@ -9874,7 +10065,11 @@ function buildTransport(remote, options) {
|
|
|
9874
10065
|
return { kind: "refused", code: "USAGE", message: `remote operation transport: unsupported intent kind '${intent.kind}'`, executed: false };
|
|
9875
10066
|
}
|
|
9876
10067
|
let parsed2;
|
|
10068
|
+
let posture;
|
|
9877
10069
|
try {
|
|
10070
|
+
const descriptor = Object.getOwnPropertyDescriptor(intent, "bodyReplace");
|
|
10071
|
+
if (descriptor && !("value" in descriptor)) throw new Error("bodyReplace must be an explicit data field.");
|
|
10072
|
+
posture = captureBodyReplacePosture(descriptor?.value);
|
|
9878
10073
|
parsed2 = parseMarkdown(intent.content, pathFromConceptId(intent.target));
|
|
9879
10074
|
} catch (error51) {
|
|
9880
10075
|
return { kind: "refused", code: "USAGE", message: error51 instanceof Error ? error51.message : String(error51), executed: false };
|
|
@@ -9883,6 +10078,7 @@ function buildTransport(remote, options) {
|
|
|
9883
10078
|
const writeOptions = {
|
|
9884
10079
|
expectedVersion: intent.base,
|
|
9885
10080
|
requestId: intent.requestId,
|
|
10081
|
+
...posture === void 0 ? {} : { bodyReplace: posture },
|
|
9886
10082
|
...options.actor === void 0 ? {} : { actor: options.actor }
|
|
9887
10083
|
};
|
|
9888
10084
|
try {
|
|
@@ -9910,6 +10106,7 @@ var init_remote_operations = __esm({
|
|
|
9910
10106
|
"use strict";
|
|
9911
10107
|
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
9912
10108
|
init_define_SUPERBEE_UPDATE_POLICY();
|
|
10109
|
+
init_body_replace_guards();
|
|
9913
10110
|
init_frontmatter();
|
|
9914
10111
|
init_paths();
|
|
9915
10112
|
init_remote_backend();
|
|
@@ -9973,146 +10170,6 @@ var init_mutation = __esm({
|
|
|
9973
10170
|
}
|
|
9974
10171
|
});
|
|
9975
10172
|
|
|
9976
|
-
// ../core/src/body-replace-guards.ts
|
|
9977
|
-
function previewTruncationNotice(omitted) {
|
|
9978
|
-
return `${BODY_PREVIEW_TRUNCATION_MARKER} ${omitted} more character(s) are NOT shown`;
|
|
9979
|
-
}
|
|
9980
|
-
function attachBodyPreview(rec, body, fullBodyHelp) {
|
|
9981
|
-
if (body.length <= BODY_PREVIEW_LIMIT) {
|
|
9982
|
-
rec.body = body;
|
|
9983
|
-
return;
|
|
9984
|
-
}
|
|
9985
|
-
const omitted = body.length - BODY_PREVIEW_LIMIT;
|
|
9986
|
-
rec[BODY_PREVIEW_KEY] = `${body.slice(0, BODY_PREVIEW_LIMIT)}
|
|
9987
|
-
|
|
9988
|
-
${previewTruncationNotice(omitted)} \u2014 this value is a preview, not the document body; use this record's help to read the complete body before rewriting it.`;
|
|
9989
|
-
rec.body_truncated = true;
|
|
9990
|
-
rec.body_chars = body.length;
|
|
9991
|
-
rec.help = [...fullBodyHelp];
|
|
9992
|
-
}
|
|
9993
|
-
function matchesPreviewSlice(candidate, preview4) {
|
|
9994
|
-
if (candidate === preview4) return true;
|
|
9995
|
-
const trimmed = preview4.trimEnd();
|
|
9996
|
-
return trimmed !== "" && candidate.trimEnd() === trimmed;
|
|
9997
|
-
}
|
|
9998
|
-
function firstForeignNotice(storedBody, nextBody) {
|
|
9999
|
-
const preservesStoredBody = nextBody.includes(storedBody.trimEnd());
|
|
10000
|
-
const every = new RegExp(BODY_PREVIEW_TRUNCATION_SIGNATURE.source, `${BODY_PREVIEW_TRUNCATION_SIGNATURE.flags}g`);
|
|
10001
|
-
for (const match of nextBody.matchAll(every)) {
|
|
10002
|
-
if (!(preservesStoredBody && storedBody.includes(match[0]))) return match[0];
|
|
10003
|
-
}
|
|
10004
|
-
return void 0;
|
|
10005
|
-
}
|
|
10006
|
-
function isSameStoredBody(nextBody, existingBody) {
|
|
10007
|
-
return normalizeDocumentBodyForStorage(nextBody) === normalizeDocumentBodyForStorage(existingBody);
|
|
10008
|
-
}
|
|
10009
|
-
function bodyPreviewFinding(existing, nextBody) {
|
|
10010
|
-
if (isSameStoredBody(nextBody, existing.body)) return;
|
|
10011
|
-
const notice = firstForeignNotice(existing.body, nextBody);
|
|
10012
|
-
if (notice !== void 0) return { reason: "preview_marker", marker: BODY_PREVIEW_TRUNCATION_MARKER, notice };
|
|
10013
|
-
if (existing.body.length > BODY_PREVIEW_LIMIT && matchesPreviewSlice(nextBody, existing.body.slice(0, BODY_PREVIEW_LIMIT))) {
|
|
10014
|
-
return { reason: "stored_body_preview", preview_limit: BODY_PREVIEW_LIMIT, supplied_body_chars: nextBody.length, stored_body_chars: existing.body.length };
|
|
10015
|
-
}
|
|
10016
|
-
}
|
|
10017
|
-
function computeDroppedLinks(existingLinks, nextLinks, mode = "target") {
|
|
10018
|
-
const nextByTarget = /* @__PURE__ */ new Map();
|
|
10019
|
-
for (const l of nextLinks) {
|
|
10020
|
-
const key4 = mode === "exact-edge" ? JSON.stringify([l.from, l.to]) : l.to;
|
|
10021
|
-
const bucket = nextByTarget.get(key4);
|
|
10022
|
-
if (bucket) bucket.push(l);
|
|
10023
|
-
else nextByTarget.set(key4, [l]);
|
|
10024
|
-
}
|
|
10025
|
-
const existingByTarget = /* @__PURE__ */ new Map();
|
|
10026
|
-
for (const l of existingLinks) {
|
|
10027
|
-
const key4 = mode === "exact-edge" ? JSON.stringify([l.from, l.to]) : l.to;
|
|
10028
|
-
const bucket = existingByTarget.get(key4);
|
|
10029
|
-
if (bucket) bucket.push(l);
|
|
10030
|
-
else existingByTarget.set(key4, [l]);
|
|
10031
|
-
}
|
|
10032
|
-
const dropped = [];
|
|
10033
|
-
for (const [target3, oldOccurrences] of existingByTarget) {
|
|
10034
|
-
const available = [...nextByTarget.get(target3) ?? []];
|
|
10035
|
-
const unmatchedExact = [];
|
|
10036
|
-
for (const old of oldOccurrences) {
|
|
10037
|
-
const idx = available.findIndex((n) => n.text === old.text);
|
|
10038
|
-
if (idx >= 0) available.splice(idx, 1);
|
|
10039
|
-
else unmatchedExact.push(old);
|
|
10040
|
-
}
|
|
10041
|
-
for (const old of unmatchedExact) {
|
|
10042
|
-
if (mode === "target" && available.length > 0) available.shift();
|
|
10043
|
-
else dropped.push(old);
|
|
10044
|
-
}
|
|
10045
|
-
}
|
|
10046
|
-
return dropped;
|
|
10047
|
-
}
|
|
10048
|
-
function droppedLinks(_bundle, existing, nextBody) {
|
|
10049
|
-
return computeDroppedLinks(parseLinksFromDoc(existing), parseLinksFromDoc({ ...existing, body: nextBody }));
|
|
10050
|
-
}
|
|
10051
|
-
function guardTruncatedBodyPreview(existing, nextBody, acceptTruncatedBody) {
|
|
10052
|
-
if (acceptTruncatedBody) return;
|
|
10053
|
-
const finding = bodyPreviewFinding(existing, nextBody);
|
|
10054
|
-
if (finding) throw new BodyReplaceError(existing.id, finding, BODY_PREVIEW_TRUNCATION_SIGNATURE.test(existing.body));
|
|
10055
|
-
}
|
|
10056
|
-
function guardDroppedLinks(bundle, existing, nextBody, replaceLinks) {
|
|
10057
|
-
if (replaceLinks || isSameStoredBody(nextBody, existing.body)) return;
|
|
10058
|
-
const dropped = droppedLinks(bundle, existing, nextBody);
|
|
10059
|
-
if (dropped.length) throw new BodyReplaceError(existing.id, { reason: "dropped_links", dropped_links: dropped });
|
|
10060
|
-
}
|
|
10061
|
-
function guardBodyReplace(bundle, existing, nextBody, posture) {
|
|
10062
|
-
if (isSameStoredBody(nextBody, existing.body)) return;
|
|
10063
|
-
guardTruncatedBodyPreview(existing, nextBody, Boolean(posture?.acceptTruncatedBody));
|
|
10064
|
-
guardDroppedLinks(bundle, existing, nextBody, Boolean(posture?.replaceLinks));
|
|
10065
|
-
}
|
|
10066
|
-
function assertTypedListPatch(kind2, storageField) {
|
|
10067
|
-
const types = kind2.fields.types ?? {};
|
|
10068
|
-
const type = Object.hasOwn(types, storageField) ? types[storageField] : void 0;
|
|
10069
|
-
if (type === "string-list" || type === "https-url-list") throw new TypedListPatchError(storageField, type);
|
|
10070
|
-
}
|
|
10071
|
-
var BODY_PREVIEW_LIMIT, BODY_PREVIEW_TRUNCATION_MARKER, BODY_PREVIEW_TRUNCATION_SIGNATURE, BODY_PREVIEW_KEY, BODY_PREVIEW_RESERVED_KEYS, BodyReplaceError, TypedListPatchError;
|
|
10072
|
-
var init_body_replace_guards = __esm({
|
|
10073
|
-
"../core/src/body-replace-guards.ts"() {
|
|
10074
|
-
"use strict";
|
|
10075
|
-
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
10076
|
-
init_define_SUPERBEE_UPDATE_POLICY();
|
|
10077
|
-
init_frontmatter();
|
|
10078
|
-
init_links();
|
|
10079
|
-
init_errors();
|
|
10080
|
-
BODY_PREVIEW_LIMIT = 1e3;
|
|
10081
|
-
BODY_PREVIEW_TRUNCATION_MARKER = "[superbee:body-preview-truncated]";
|
|
10082
|
-
BODY_PREVIEW_TRUNCATION_SIGNATURE = /\[superbee:body-preview-truncated\]\s+\d+\s+more\s+characters?\(?s?\)?\s+are\s+NOT\s+shown/i;
|
|
10083
|
-
BODY_PREVIEW_KEY = "body_preview";
|
|
10084
|
-
BODY_PREVIEW_RESERVED_KEYS = [
|
|
10085
|
-
"body",
|
|
10086
|
-
BODY_PREVIEW_KEY,
|
|
10087
|
-
"body_truncated",
|
|
10088
|
-
"body_chars",
|
|
10089
|
-
"help"
|
|
10090
|
-
];
|
|
10091
|
-
BodyReplaceError = class extends InvalidInputError {
|
|
10092
|
-
id;
|
|
10093
|
-
finding;
|
|
10094
|
-
storedCarriesNotice;
|
|
10095
|
-
constructor(id, finding, storedCarriesNotice = false) {
|
|
10096
|
-
super(`Body replacement of '${id}' refused: ${finding.reason}.`);
|
|
10097
|
-
this.name = "BodyReplaceError";
|
|
10098
|
-
this.id = id;
|
|
10099
|
-
this.finding = finding;
|
|
10100
|
-
this.storedCarriesNotice = storedCarriesNotice;
|
|
10101
|
-
}
|
|
10102
|
-
};
|
|
10103
|
-
TypedListPatchError = class extends InvalidInputError {
|
|
10104
|
-
field;
|
|
10105
|
-
fieldType;
|
|
10106
|
-
constructor(field, fieldType) {
|
|
10107
|
-
super(`'${field}' is a ${fieldType} field; use an explicit whole-list replacement.`);
|
|
10108
|
-
this.name = "TypedListPatchError";
|
|
10109
|
-
this.field = field;
|
|
10110
|
-
this.fieldType = fieldType;
|
|
10111
|
-
}
|
|
10112
|
-
};
|
|
10113
|
-
}
|
|
10114
|
-
});
|
|
10115
|
-
|
|
10116
10173
|
// ../core/src/managed-document-metadata.ts
|
|
10117
10174
|
function isManagedDocumentMetadataField(field) {
|
|
10118
10175
|
return MANAGED_DOCUMENT_METADATA_FIELDS.has(field);
|
|
@@ -11921,7 +11978,8 @@ async function mutateDocument(opts) {
|
|
|
11921
11978
|
const { warnings } = validateCandidate(opts.id, candidate, opts.registry, opts.strict, okfVersion, decisionNow);
|
|
11922
11979
|
const { doc: doc2, version: version4 } = await writeDocVersionedForEdition2(opts.bundle, { id: opts.id, ...candidate }, okfVersion, {
|
|
11923
11980
|
expectedVersion: null,
|
|
11924
|
-
actor: opts.actor
|
|
11981
|
+
actor: opts.actor,
|
|
11982
|
+
bodyReplace: opts.bodyReplace
|
|
11925
11983
|
});
|
|
11926
11984
|
return { doc: doc2, changed: true, version: version4, warnings };
|
|
11927
11985
|
}
|
|
@@ -11994,7 +12052,8 @@ async function mutateDocument(opts) {
|
|
|
11994
12052
|
write: async (next, expectedVersion) => {
|
|
11995
12053
|
const written = await writeDocVersionedForEdition2(opts.bundle, next, okfVersion, {
|
|
11996
12054
|
expectedVersion,
|
|
11997
|
-
actor: opts.actor
|
|
12055
|
+
actor: opts.actor,
|
|
12056
|
+
bodyReplace: opts.bodyReplace
|
|
11998
12057
|
});
|
|
11999
12058
|
savedDoc2 = written.doc;
|
|
12000
12059
|
return written.version;
|
|
@@ -12036,7 +12095,8 @@ async function mutateDocument(opts) {
|
|
|
12036
12095
|
write: async (next, expectedVersion) => {
|
|
12037
12096
|
const written = await writeDocVersionedForEdition2(opts.bundle, next, okfVersion, {
|
|
12038
12097
|
expectedVersion: hardCas ? opts.expectedVersion : expectedVersion,
|
|
12039
|
-
actor: opts.actor
|
|
12098
|
+
actor: opts.actor,
|
|
12099
|
+
bodyReplace: opts.bodyReplace
|
|
12040
12100
|
});
|
|
12041
12101
|
savedDoc = written.doc;
|
|
12042
12102
|
return written.version;
|
|
@@ -29050,7 +29110,7 @@ var init_source_profiles = __esm({
|
|
|
29050
29110
|
};
|
|
29051
29111
|
}
|
|
29052
29112
|
});
|
|
29053
|
-
SOURCE_PLUGIN_CORE_VERSION = "0.2.0-pre.
|
|
29113
|
+
SOURCE_PLUGIN_CORE_VERSION = "0.2.0-pre.30";
|
|
29054
29114
|
SOURCE_PROFILES = Object.freeze([restJsonProfile].map((profile) => Object.freeze({ id: profile.id, version: profile.version, kind: profile.kind })));
|
|
29055
29115
|
}
|
|
29056
29116
|
});
|
|
@@ -39277,6 +39337,7 @@ var init_indexeddb_backend = __esm({
|
|
|
39277
39337
|
"use strict";
|
|
39278
39338
|
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
39279
39339
|
init_define_SUPERBEE_UPDATE_POLICY();
|
|
39340
|
+
init_journaled_backend();
|
|
39280
39341
|
init_content_type();
|
|
39281
39342
|
init_frontmatter();
|
|
39282
39343
|
init_mutation_attribution();
|
|
@@ -39728,6 +39789,7 @@ var init_indexeddb_backend = __esm({
|
|
|
39728
39789
|
}
|
|
39729
39790
|
assertSafeConceptId(id);
|
|
39730
39791
|
assertJournalResolutionOptions(id, options);
|
|
39792
|
+
if (options.intent) options = { ...options, intent: captureNewDocumentIntent(options.intent) };
|
|
39731
39793
|
const raw = stringifyDoc(doc2.frontmatter, doc2.body ?? "");
|
|
39732
39794
|
const version4 = versionOfBytes(raw);
|
|
39733
39795
|
if (snapshotGuard && (doc2.id !== id || options.intent && options.intent.target !== id)) throw new JournalGuardConflict(id);
|
|
@@ -40590,6 +40652,14 @@ async function bootstrap(remote, local, options = {}) {
|
|
|
40590
40652
|
await backend.writeMeta(BOOTSTRAP_KEY, marker);
|
|
40591
40653
|
return marker;
|
|
40592
40654
|
}
|
|
40655
|
+
function composedBodyReplace(...postures) {
|
|
40656
|
+
const declarations = postures.map(captureBodyReplacePosture).filter((row5) => row5 !== void 0);
|
|
40657
|
+
if (!declarations.length) return;
|
|
40658
|
+
return {
|
|
40659
|
+
replaceLinks: declarations.some((row5) => row5.replaceLinks === true),
|
|
40660
|
+
acceptTruncatedBody: declarations.some((row5) => row5.acceptTruncatedBody === true)
|
|
40661
|
+
};
|
|
40662
|
+
}
|
|
40593
40663
|
function supersedingIntent(kind2, superseded, now) {
|
|
40594
40664
|
const deleting = kind2 === DOCUMENT_DELETE_KIND;
|
|
40595
40665
|
if (deleting && superseded.base === null) return void 0;
|
|
@@ -40600,6 +40670,7 @@ function supersedingIntent(kind2, superseded, now) {
|
|
|
40600
40670
|
base: superseded.base,
|
|
40601
40671
|
baseContent: superseded.baseContent,
|
|
40602
40672
|
createdAt: now,
|
|
40673
|
+
...!deleting && superseded.kind === "document.write" && superseded.bodyReplace !== void 0 ? { bodyReplace: composedBodyReplace(superseded.bodyReplace) } : {},
|
|
40603
40674
|
...superseded.after !== void 0 ? { after: superseded.after } : {},
|
|
40604
40675
|
...!deleting && superseded.recreates !== void 0 && superseded.base === null ? { recreates: superseded.recreates } : {}
|
|
40605
40676
|
};
|
|
@@ -40656,8 +40727,11 @@ function chainedBase(intent) {
|
|
|
40656
40727
|
function journalingBackend(backend, id, recorded) {
|
|
40657
40728
|
const write = async (target3, doc2, options = {}) => {
|
|
40658
40729
|
if (target3 !== id) throw new Error(`commitLocal for '${id}' cannot write '${target3}'`);
|
|
40730
|
+
const declaredPosture = captureBodyReplacePosture(options.bodyReplace);
|
|
40659
40731
|
for (let attempt = 0; ; attempt++) {
|
|
40660
40732
|
const composed = await composeIntent(backend, id, (/* @__PURE__ */ new Date()).toISOString());
|
|
40733
|
+
const posture = composedBodyReplace(composed.intent.bodyReplace, declaredPosture);
|
|
40734
|
+
if (posture !== void 0) composed.intent = { ...composed.intent, bodyReplace: posture };
|
|
40661
40735
|
try {
|
|
40662
40736
|
const written = await backend.writeJournaled(id, doc2, { ...options, ...composed });
|
|
40663
40737
|
recorded.intent = written.intent;
|
|
@@ -40887,6 +40961,7 @@ async function resolveConflict(local, remote, reviewed, choice, options = {}) {
|
|
|
40887
40961
|
base: shared.base.version,
|
|
40888
40962
|
baseContent: shared.base.content,
|
|
40889
40963
|
createdAt: resolvedAt,
|
|
40964
|
+
bodyReplace: { replaceLinks: true },
|
|
40890
40965
|
...recreates !== void 0 ? { recreates } : {}
|
|
40891
40966
|
};
|
|
40892
40967
|
let written;
|
|
@@ -41208,7 +41283,11 @@ async function foldRefusedChain(backend, listed2) {
|
|
|
41208
41283
|
if (chain.length !== 2 || !head2 || !successor || !isContentRefusal(head2) || successor.requestId !== listed2.requestId || successor.state !== "pending" || successor.attempts !== 0 || successor.after !== head2.requestId) return null;
|
|
41209
41284
|
const deleting = successor.kind === DOCUMENT_DELETE_KIND;
|
|
41210
41285
|
if (deleting ? snapshot4.document !== null : !snapshot4.document || successor.local !== snapshot4.document.version || successor.content !== snapshot4.raw) return null;
|
|
41211
|
-
|
|
41286
|
+
let intent = supersedingIntent(deleting ? DOCUMENT_DELETE_KIND : "document.write", head2, (/* @__PURE__ */ new Date()).toISOString());
|
|
41287
|
+
if (!deleting && intent) {
|
|
41288
|
+
const posture = composedBodyReplace(intent.bodyReplace, successor.bodyReplace);
|
|
41289
|
+
if (posture !== void 0) intent = { ...intent, bodyReplace: posture };
|
|
41290
|
+
}
|
|
41212
41291
|
const resolveIntents = { expected: chain };
|
|
41213
41292
|
try {
|
|
41214
41293
|
if (deleting) {
|
|
@@ -41538,6 +41617,7 @@ var init_local_bundle = __esm({
|
|
|
41538
41617
|
"use strict";
|
|
41539
41618
|
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
41540
41619
|
init_define_SUPERBEE_UPDATE_POLICY();
|
|
41620
|
+
init_engine();
|
|
41541
41621
|
init_document_codec();
|
|
41542
41622
|
init_governed_body_write();
|
|
41543
41623
|
init_verification();
|
|
@@ -41838,6 +41918,13 @@ function validateIntentChanges(changes, format2, file2) {
|
|
|
41838
41918
|
for (const change of changes) {
|
|
41839
41919
|
if (change.family !== "intent" || change.value === null) continue;
|
|
41840
41920
|
const row5 = change.value;
|
|
41921
|
+
if (!("recordFamily" in row5) && row5.bodyReplace !== void 0) {
|
|
41922
|
+
try {
|
|
41923
|
+
captureNewDocumentIntent(row5);
|
|
41924
|
+
} catch {
|
|
41925
|
+
throw new FileJournalCorruptError(file2, "invalid document edit intent");
|
|
41926
|
+
}
|
|
41927
|
+
}
|
|
41841
41928
|
if ("recordFamily" in row5) {
|
|
41842
41929
|
if (row5.recordFamily !== "blob" || format2 < 2) throw new FileJournalCorruptError(file2, "blob intent is not allowed in this format");
|
|
41843
41930
|
if (blobIntentFormat(row5) > format2) throw new FileJournalCorruptError(file2, "blob not-dispatched evidence is not allowed in this format");
|
|
@@ -41958,6 +42045,7 @@ var init_file_journaled_backend = __esm({
|
|
|
41958
42045
|
"use strict";
|
|
41959
42046
|
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
41960
42047
|
init_define_SUPERBEE_UPDATE_POLICY();
|
|
42048
|
+
init_journaled_backend();
|
|
41961
42049
|
init_blob_contract();
|
|
41962
42050
|
init_blob_journal();
|
|
41963
42051
|
init_content_type();
|
|
@@ -42423,6 +42511,7 @@ var init_file_journaled_backend = __esm({
|
|
|
42423
42511
|
}
|
|
42424
42512
|
assertSafeConceptId(id);
|
|
42425
42513
|
assertJournalResolutionOptions(id, options);
|
|
42514
|
+
if (options.intent) options = { ...options, intent: captureNewDocumentIntent(options.intent) };
|
|
42426
42515
|
if (snapshotGuard && (doc2.id !== id || options.intent && options.intent.target !== id)) throw new JournalGuardConflict(id);
|
|
42427
42516
|
const raw = stringifyDoc(doc2.frontmatter, doc2.body ?? "");
|
|
42428
42517
|
const version4 = versionOfBytes(raw);
|
|
@@ -93267,6 +93356,9 @@ function errorFromCaught(err) {
|
|
|
93267
93356
|
if (err instanceof RemoteDocumentValueError) {
|
|
93268
93357
|
return errorResponse(500, "RUNTIME", err.message);
|
|
93269
93358
|
}
|
|
93359
|
+
if (err instanceof BodyReplaceError) {
|
|
93360
|
+
return errorResponse(400, "USAGE", err.message, { id: err.id, ...err.finding });
|
|
93361
|
+
}
|
|
93270
93362
|
if (err instanceof InvalidInputError) {
|
|
93271
93363
|
return errorResponse(400, "USAGE", err.message);
|
|
93272
93364
|
}
|
|
@@ -93544,7 +93636,9 @@ function buildRouter(options) {
|
|
|
93544
93636
|
return errorResponse(400, "USAGE", "request body field body must be a string when present");
|
|
93545
93637
|
}
|
|
93546
93638
|
const writeOptions = writeOptionsFromRequest(req, attribution);
|
|
93547
|
-
const
|
|
93639
|
+
const posture = captureBodyReplacePosture(payload.bodyReplace);
|
|
93640
|
+
if (posture !== void 0) writeOptions.bodyReplace = posture;
|
|
93641
|
+
const result3 = await writeDocVersionedGuarded(
|
|
93548
93642
|
backend,
|
|
93549
93643
|
{ id, frontmatter: payload.frontmatter, body: payload.body ?? "" },
|
|
93550
93644
|
writeOptions
|
|
@@ -152473,20 +152567,35 @@ async function localBundle(dir, cwd = process.cwd(), home2 = homedir49()) {
|
|
|
152473
152567
|
if (process.platform !== "darwin" && process.platform !== "linux") throw refuse("unsupported_supervision_platform");
|
|
152474
152568
|
return target3.canonicalRoot;
|
|
152475
152569
|
}
|
|
152476
|
-
|
|
152477
|
-
|
|
152570
|
+
function toolSelections(values, home2) {
|
|
152571
|
+
const selections = {};
|
|
152572
|
+
for (const [handle, value] of Object.entries(values)) {
|
|
152573
|
+
if (!key3.test(handle)) throw refuse("tool_handle");
|
|
152574
|
+
let selected2;
|
|
152575
|
+
if (typeof value === "string") selected2 = { path: value, versionFlag: "--version" };
|
|
152576
|
+
else {
|
|
152577
|
+
if (!record16(value) || Object.keys(value).length !== 2 || !Object.hasOwn(value, "path") || !Object.hasOwn(value, "versionFlag") || typeof value.path !== "string" || value.versionFlag !== "--version" && value.versionFlag !== "-version") throw refuse("tool_selection");
|
|
152578
|
+
selected2 = { path: value.path, versionFlag: value.versionFlag };
|
|
152579
|
+
}
|
|
152580
|
+
if (!path64.isAbsolute(selected2.path)) throw refuse("absolute_tool_required");
|
|
152581
|
+
assertPathOutsidePrivateState(selected2.path, home2);
|
|
152582
|
+
selections[handle] = selected2;
|
|
152583
|
+
}
|
|
152584
|
+
return selections;
|
|
152585
|
+
}
|
|
152586
|
+
async function toolIdentity({ path: file2, versionFlag }) {
|
|
152478
152587
|
const resolved = await realpath15(file2);
|
|
152479
152588
|
const bytes = await localFileBytes(resolved, 256 * 1024 * 1024);
|
|
152480
152589
|
const magic = bytes.subarray(0, 4).toString("hex");
|
|
152481
152590
|
const native = process.platform === "linux" ? magic === "7f454c46" : ["feedface", "cefaedfe", "feedfacf", "cffaedfe", "cafebabe", "bebafeca", "cafebabf", "bfbafeca"].includes(magic);
|
|
152482
152591
|
if (!native) throw refuse("native_tool_binary_required");
|
|
152483
|
-
const version4 = await probeToolVersion(resolved);
|
|
152592
|
+
const version4 = await probeToolVersion(resolved, versionFlag);
|
|
152484
152593
|
if (await realpath15(resolved) !== resolved || hash2(await localFileBytes(resolved, 256 * 1024 * 1024)) !== hash2(bytes)) throw refuse("tool_changed_rebind_required");
|
|
152485
|
-
return { path: resolved, sha256: hash2(bytes), version: version4 };
|
|
152594
|
+
return { path: resolved, sha256: hash2(bytes), version: version4, versionFlag };
|
|
152486
152595
|
}
|
|
152487
|
-
async function probeToolVersion(file2) {
|
|
152596
|
+
async function probeToolVersion(file2, versionFlag) {
|
|
152488
152597
|
return new Promise((resolve2, reject) => {
|
|
152489
|
-
const child = spawn5(file2, [
|
|
152598
|
+
const child = spawn5(file2, [versionFlag], { detached: true, env: { PATH: "/usr/bin:/bin" }, stdio: ["ignore", "pipe", "pipe"] });
|
|
152490
152599
|
let settled = false, stdout = "", bytes = 0, failureReason;
|
|
152491
152600
|
const finish = async (reason) => {
|
|
152492
152601
|
failureReason ??= reason;
|
|
@@ -152523,6 +152632,7 @@ async function bindLocalOperation(operation, bundle, config2, accept, home2 = ho
|
|
|
152523
152632
|
if (!record16(config2) || !record16(config2.resources) || !record16(config2.tools) || !Object.hasOwn(LOCAL_OPERATION_PROFILES, config2.profile)) throw refuse("binding_config");
|
|
152524
152633
|
const profile = LOCAL_OPERATION_PROFILES[config2.profile];
|
|
152525
152634
|
if (Object.keys(config2.resources).length === 0 || Object.keys(config2.resources).length > profile.files || Object.keys(config2.tools).length > 8) throw refuse("binding_count");
|
|
152635
|
+
const selectedTools = toolSelections(config2.tools, home2);
|
|
152526
152636
|
const resources = {}, tools = {}, expectedInputs = {};
|
|
152527
152637
|
let total = 0;
|
|
152528
152638
|
for (const [role, value] of Object.entries(config2.resources)) {
|
|
@@ -152534,39 +152644,71 @@ async function bindLocalOperation(operation, bundle, config2, accept, home2 = ho
|
|
|
152534
152644
|
resources[role] = { path: selected2, logicalRef: value.logicalRef };
|
|
152535
152645
|
expectedInputs[role] = hash2(bytes);
|
|
152536
152646
|
}
|
|
152537
|
-
for (const [handle,
|
|
152538
|
-
if (typeof file2 !== "string") throw refuse("tool_selection");
|
|
152539
|
-
if (!key3.test(handle)) throw refuse("tool_handle");
|
|
152540
|
-
assertPathOutsidePrivateState(file2, home2);
|
|
152541
|
-
tools[handle] = await toolIdentity(file2);
|
|
152542
|
-
}
|
|
152647
|
+
for (const [handle, selected2] of Object.entries(selectedTools)) tools[handle] = await toolIdentity(selected2);
|
|
152543
152648
|
const outputRoot = await ordinaryDirectory(config2.outputRoot, home2, bundle), rootStatus = await lstat13(outputRoot);
|
|
152544
152649
|
const binding2 = { v: 1, bundle, operation, pluginDigest: selection.digest, generation: selection.generation, capability: selection.capability, resources, tools, outputRoot, outputRootIdentity: { dev: rootStatus.dev, ino: rootStatus.ino }, profile: config2.profile };
|
|
152545
152650
|
const digest4 = hash2(canonicalJson3(binding2));
|
|
152546
|
-
if (accept === void 0) return { status: "preview", digest: digest4, operation, profile: config2.profile, expectedInputs, resources: Object.keys(resources), tools:
|
|
152651
|
+
if (accept === void 0) return { status: "preview", digest: digest4, operation, profile: config2.profile, expectedInputs, resources: Object.keys(resources), tools: toolEvidence(tools), effects: ["trusted code with ambient authority; no OS sandbox", "copies selected inputs; creates private local files; consumes compute", "supported adapter makes no network requests; network is not sandboxed", "HTML export is separate from Artifact publication"], next: `superbee op bind ${commandToken(operation)} --local --resources-file <same-file> --accept ${commandToken(digest4)} --dir <same-bundle>` };
|
|
152547
152652
|
if (accept !== digest4) throw refuse("binding_acceptance_changed");
|
|
152548
152653
|
const id = randomUUID9();
|
|
152549
152654
|
await writeUserStateFileAtomic0600(home2, path64.join(canonicalUserStateDir(home2), "local-operation-bindings"), `${id}.json`, JSON.stringify(binding2));
|
|
152550
152655
|
return { status: "bound", binding: id, digest: digest4, operation, expectedInputs, next: `superbee op run ${commandToken(operation)} --local --binding ${commandToken(id)} --input-file <run-input.json> --dir <same-bundle>` };
|
|
152551
152656
|
}
|
|
152552
|
-
|
|
152553
|
-
|
|
152554
|
-
|
|
152555
|
-
|
|
152556
|
-
|
|
152557
|
-
|
|
152558
|
-
|
|
152559
|
-
|
|
152560
|
-
|
|
152561
|
-
|
|
152562
|
-
}
|
|
152563
|
-
|
|
152564
|
-
|
|
152657
|
+
function outputFailure(phase, error51) {
|
|
152658
|
+
return { phase, errno: error51 instanceof OutputScanError ? error51.errno : "unknown", syscall: error51 instanceof OutputScanError ? error51.syscall : "unknown" };
|
|
152659
|
+
}
|
|
152660
|
+
async function outputBudget(directory, maximumBytes, maximumFiles, live = false, io = outputBudgetIo) {
|
|
152661
|
+
for (let attempt = 1; ; attempt++) {
|
|
152662
|
+
let bytes = 0, count6 = 0;
|
|
152663
|
+
const scan3 = async (dir) => {
|
|
152664
|
+
let entries;
|
|
152665
|
+
try {
|
|
152666
|
+
entries = await io.readdir(dir);
|
|
152667
|
+
} catch (error51) {
|
|
152668
|
+
throw new OutputScanError(error51, dir !== directory);
|
|
152669
|
+
}
|
|
152670
|
+
for (const entry of entries) {
|
|
152671
|
+
if (++count6 > maximumFiles * 2) return false;
|
|
152672
|
+
const file2 = path64.join(dir, entry.name);
|
|
152673
|
+
let status2;
|
|
152674
|
+
try {
|
|
152675
|
+
status2 = await io.lstat(file2);
|
|
152676
|
+
} catch (error51) {
|
|
152677
|
+
throw new OutputScanError(error51, true);
|
|
152678
|
+
}
|
|
152679
|
+
if (status2.isSymbolicLink() || !status2.isFile() && !status2.isDirectory()) return false;
|
|
152680
|
+
if (status2.isDirectory()) {
|
|
152681
|
+
if (!await scan3(file2)) return false;
|
|
152682
|
+
} else {
|
|
152683
|
+
bytes += status2.size;
|
|
152684
|
+
if (bytes > maximumBytes) return false;
|
|
152685
|
+
}
|
|
152565
152686
|
}
|
|
152687
|
+
return true;
|
|
152688
|
+
};
|
|
152689
|
+
try {
|
|
152690
|
+
return await scan3(directory);
|
|
152691
|
+
} catch (error51) {
|
|
152692
|
+
if (live && attempt < 3 && error51 instanceof OutputScanError && error51.vanishedDescendant) continue;
|
|
152693
|
+
throw error51;
|
|
152566
152694
|
}
|
|
152567
|
-
|
|
152695
|
+
}
|
|
152696
|
+
}
|
|
152697
|
+
function startOutputBudgetPoll(directory, maximumBytes, maximumFiles, report, scan3 = outputBudget) {
|
|
152698
|
+
let pending, stopped = false;
|
|
152699
|
+
const timer = setInterval(() => {
|
|
152700
|
+
if (stopped || pending) return;
|
|
152701
|
+
pending = scan3(directory, maximumBytes, maximumFiles, true).then((ok4) => {
|
|
152702
|
+
if (!ok4) report("output_limit");
|
|
152703
|
+
}).catch((error51) => report("output_validation", error51)).finally(() => {
|
|
152704
|
+
pending = void 0;
|
|
152705
|
+
});
|
|
152706
|
+
}, 50);
|
|
152707
|
+
return async () => {
|
|
152708
|
+
stopped = true;
|
|
152709
|
+
clearInterval(timer);
|
|
152710
|
+
await pending;
|
|
152568
152711
|
};
|
|
152569
|
-
return scan3(directory);
|
|
152570
152712
|
}
|
|
152571
152713
|
async function groupPresent(pid) {
|
|
152572
152714
|
try {
|
|
@@ -152635,7 +152777,7 @@ async function runLocalOperation(operation, bundle, bindingId, input, options =
|
|
|
152635
152777
|
resources[role] = { path: captured, logicalRef: resource.logicalRef, sha256: sha2562 };
|
|
152636
152778
|
inputs.push({ role, logicalRef: resource.logicalRef, sha256: sha2562, bytes: bytes.length });
|
|
152637
152779
|
}
|
|
152638
|
-
const manifest2 = { version: 1, invocationId: id, operation, implementationId: selection.capability.implementationId, plugin: { digest: selection.digest, generation: selection.generation, assets: selection.assets }, inputs, settingsDigest: hash2(canonicalJson3(input.settings)), tools:
|
|
152780
|
+
const manifest2 = { version: 1, invocationId: id, operation, implementationId: selection.capability.implementationId, plugin: { digest: selection.digest, generation: selection.generation, assets: selection.assets }, inputs, settingsDigest: hash2(canonicalJson3(input.settings)), tools: toolEvidence(binding2.tools), profile: binding2.profile, platform: { os: process.platform, arch: process.arch, node: process.version }, startedAt: (/* @__PURE__ */ new Date()).toISOString(), status: "interrupted_unconfirmed", reason: "parent_outcome_unknown", outputs: [], publication: "not_attempted" };
|
|
152639
152781
|
const manifestPath = path64.join(workspace, "manifest.json");
|
|
152640
152782
|
await writeFile3(manifestPath, JSON.stringify(manifest2, null, 2), { mode: 384, flag: "wx" });
|
|
152641
152783
|
const maximumOutputBytes = Math.min(selection.capability.maximumOutputBytes ?? DEFAULT_MAXIMUM_OUTPUT_BYTES, DEFAULT_MAXIMUM_OUTPUT_BYTES);
|
|
@@ -152658,16 +152800,10 @@ async function runLocalOperation(operation, bundle, bindingId, input, options =
|
|
|
152658
152800
|
};
|
|
152659
152801
|
child.stdout.on("data", capture2);
|
|
152660
152802
|
child.stderr.on("data", capture2);
|
|
152661
|
-
|
|
152662
|
-
|
|
152663
|
-
|
|
152664
|
-
|
|
152665
|
-
void outputBudget(outputDirectory, profile.outputBytes, profile.files).then((ok4) => {
|
|
152666
|
-
if (!ok4) terminate("output_limit");
|
|
152667
|
-
}).catch(() => terminate("output_validation")).finally(() => {
|
|
152668
|
-
checking = false;
|
|
152669
|
-
});
|
|
152670
|
-
}, 50);
|
|
152803
|
+
const stopBudget = startOutputBudgetPoll(outputDirectory, profile.outputBytes, profile.files, (why, error51) => {
|
|
152804
|
+
manifest2.outputValidationFailure ??= outputFailure("live", error51);
|
|
152805
|
+
terminate(why);
|
|
152806
|
+
});
|
|
152671
152807
|
const deadline = setTimeout(() => terminate("deadline"), profile.deadlineMs);
|
|
152672
152808
|
const abort = () => terminate("cancelled");
|
|
152673
152809
|
options.signal?.addEventListener("abort", abort, { once: true });
|
|
@@ -152712,9 +152848,10 @@ async function runLocalOperation(operation, bundle, bindingId, input, options =
|
|
|
152712
152848
|
child.send({ type: "initialize", entryPath: selection.entryPath, capabilityName: selection.capability.name, maximumOutputBytes, protocolBytes: DEFAULT_MAXIMUM_OUTPUT_BYTES, tools: binding2.tools, resources, profile, invocation: { id, outputDirectory, assetDirectory: selection.rootPath, profile: binding2.profile }, input: input.settings });
|
|
152713
152849
|
});
|
|
152714
152850
|
clearTimeout(deadline);
|
|
152715
|
-
|
|
152851
|
+
const budgetStopped = stopBudget();
|
|
152716
152852
|
options.signal?.removeEventListener("abort", abort);
|
|
152717
152853
|
const stopped = child.pid !== void 0 ? await stopGroup(child.pid, profile.graceMs) : closed;
|
|
152854
|
+
await budgetStopped;
|
|
152718
152855
|
for (const [tool, identity] of Object.entries(binding2.tools)) {
|
|
152719
152856
|
try {
|
|
152720
152857
|
if (await realpath15(identity.path) !== identity.path || hash2(await localFileBytes(identity.path, 256 * 1024 * 1024)) !== identity.sha256) throw Error();
|
|
@@ -152748,9 +152885,10 @@ async function runLocalOperation(operation, bundle, bindingId, input, options =
|
|
|
152748
152885
|
for (const entry of all2) if (entry.isFile() && !seen.has(path64.relative(outputDirectory, path64.join(entry.parentPath, entry.name)))) throw refuse("undeclared_output");
|
|
152749
152886
|
manifest2.settings = result3.settings ?? input.settings;
|
|
152750
152887
|
manifest2.partialOutputState = "validated";
|
|
152751
|
-
} catch {
|
|
152888
|
+
} catch (error51) {
|
|
152752
152889
|
manifest2.status = "failed";
|
|
152753
152890
|
manifest2.reason = "output_validation";
|
|
152891
|
+
manifest2.outputValidationFailure = outputFailure("final", error51);
|
|
152754
152892
|
manifest2.outputs = [];
|
|
152755
152893
|
}
|
|
152756
152894
|
}
|
|
@@ -152777,7 +152915,7 @@ async function runLocalOperation(operation, bundle, bindingId, input, options =
|
|
|
152777
152915
|
await writeFile3(manifestPath, JSON.stringify(manifest2, null, 2), { mode: 384 });
|
|
152778
152916
|
return { invocationId: id, status: manifest2.status, reason: manifest2.reason, manifest: manifestPath, outputs: manifest2.outputs, export: manifest2.export === void 0 ? void 0 : { ...manifest2.export, ...exportPath ? { path: exportPath } : {} }, publication: "not_attempted" };
|
|
152779
152917
|
}
|
|
152780
|
-
var LOCAL_OPERATION_PROFILES, record16, hash2, refuse, key3, within;
|
|
152918
|
+
var LOCAL_OPERATION_PROFILES, record16, hash2, refuse, key3, within, toolEvidence, outputBudgetIo, OutputScanError;
|
|
152781
152919
|
var init_local_operation = __esm({
|
|
152782
152920
|
"../cli/src/local-operation.ts"() {
|
|
152783
152921
|
"use strict";
|
|
@@ -152805,6 +152943,20 @@ var init_local_operation = __esm({
|
|
|
152805
152943
|
const rel = path64.relative(root, target3);
|
|
152806
152944
|
return rel !== "" && !rel.startsWith(`..${path64.sep}`) && rel !== ".." && !path64.isAbsolute(rel);
|
|
152807
152945
|
};
|
|
152946
|
+
toolEvidence = (tools) => Object.fromEntries(Object.entries(tools).map(([name, t]) => [name, { sha256: t.sha256, version: t.version, versionFlag: t.versionFlag ?? "--version" }]));
|
|
152947
|
+
outputBudgetIo = { readdir: (directory) => readdir10(directory, { withFileTypes: true }), lstat: (file2) => lstat13(file2) };
|
|
152948
|
+
OutputScanError = class extends Error {
|
|
152949
|
+
errno;
|
|
152950
|
+
syscall;
|
|
152951
|
+
vanishedDescendant;
|
|
152952
|
+
constructor(error51, descendant) {
|
|
152953
|
+
super("output_scan_failed");
|
|
152954
|
+
const value = error51;
|
|
152955
|
+
this.errno = typeof value?.code === "string" && /^E[A-Z0-9]{1,30}$/.test(value.code) ? value.code : "unknown";
|
|
152956
|
+
this.syscall = value?.syscall === "lstat" || value?.syscall === "scandir" ? value.syscall : "unknown";
|
|
152957
|
+
this.vanishedDescendant = descendant && this.errno === "ENOENT";
|
|
152958
|
+
}
|
|
152959
|
+
};
|
|
152808
152960
|
}
|
|
152809
152961
|
});
|
|
152810
152962
|
|
|
@@ -153176,15 +153328,18 @@ exports one validated HTML into the selected ordinary output root without publis
|
|
|
153176
153328
|
Trusted code has ambient local authority; process supervision is not an OS sandbox.
|
|
153177
153329
|
|
|
153178
153330
|
Local binding resources JSON contains resources (role -> {path, logicalRef}), tools (handle ->
|
|
153179
|
-
absolute executable path), outputRoot (existing ordinary directory outside the bundle/private
|
|
153331
|
+
absolute executable path or exact {path, versionFlag}), outputRoot (existing ordinary directory outside the bundle/private
|
|
153180
153332
|
state), and profile (synthetic-v1: 16 MiB inputs/32 MiB outputs/30 seconds, or comparison-v1:
|
|
153181
153333
|
128 MiB inputs/128 MiB outputs/120 seconds). Inputs are finite individual regular files; adapters
|
|
153182
153334
|
must refuse unclosed dependencies. Preview returns expectedInputs hashes. Run input JSON contains
|
|
153183
153335
|
{expectedInputs: {role: "sha256:..."}, settings: {...}}. Confirm new hashes for changed inputs.
|
|
153184
153336
|
Tool paths resolve to native physical binaries; executable scripts/wrappers are refused.
|
|
153185
153337
|
Symlink launcher/virtual-environment semantics are not
|
|
153186
|
-
preserved. Use a copied interpreter when needed.
|
|
153187
|
-
|
|
153338
|
+
preserved. Use a copied interpreter when needed. String tool paths probe with --version; explicit
|
|
153339
|
+
versionFlag accepts only --version or -version. All selections are validated before any probe;
|
|
153340
|
+
there is no flag fallback or arbitrary probe argv. Bind pins executable bytes, version output
|
|
153341
|
+
and the selected flag, not arbitrary installed libraries or OS dependencies. Existing stored
|
|
153342
|
+
bindings without a flag retain --version in new run evidence; earlier receipts are unchanged. These profiles are not qualified private-pilot
|
|
153188
153343
|
limits or CPU/RAM/disk isolation.
|
|
153189
153344
|
|
|
153190
153345
|
Without --local, a local or Git bundle has no host operations: op list answers none, and op run is refused
|