superbee 0.4.3-pre.1 → 0.4.3-pre.3
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 +180 -10
- package/dist/publication.mjs +214 -12
- package/dist/superbee.mjs +427 -71
- 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.3" }, source: { commit: "11561dfb62d36f61149e2655e8bebeb08c4e7c9f", dirty: false }, artifact: { channel: "npm-package" }, compatibility_contracts: { skill: 1, hook: 1, mcp: 1 } };
|
|
48
48
|
}
|
|
49
49
|
});
|
|
50
50
|
|
|
@@ -4943,6 +4943,12 @@ async function probeSegment(port, candidate, rel, segment) {
|
|
|
4943
4943
|
function hasExact(listing, segment) {
|
|
4944
4944
|
return listing.some((entry) => entry.name === segment);
|
|
4945
4945
|
}
|
|
4946
|
+
function freshListings(port) {
|
|
4947
|
+
return async (dir) => {
|
|
4948
|
+
const listing = await port.entries(dir);
|
|
4949
|
+
return listing === null ? null : { has: (name) => hasExact(listing, name) };
|
|
4950
|
+
};
|
|
4951
|
+
}
|
|
4946
4952
|
async function walkExact(port, rootResolved, segments, rel) {
|
|
4947
4953
|
let parent = rootResolved;
|
|
4948
4954
|
for (let index2 = 0; index2 < segments.length; index2++) {
|
|
@@ -4973,14 +4979,14 @@ async function recordWalk(port, rootResolved, segments, rel) {
|
|
|
4973
4979
|
}
|
|
4974
4980
|
return recorded;
|
|
4975
4981
|
}
|
|
4976
|
-
async function confirmedWalk(port, rootResolved, segments, rel, recorded, handle) {
|
|
4982
|
+
async function confirmedWalk(port, rootResolved, segments, rel, recorded, handle, listings = freshListings(port)) {
|
|
4977
4983
|
let parent = rootResolved;
|
|
4978
4984
|
for (let index2 = 0; index2 < segments.length; index2++) {
|
|
4979
4985
|
const segment = segments[index2];
|
|
4980
4986
|
const candidate = path2.join(parent, segment);
|
|
4981
|
-
const listing = await
|
|
4987
|
+
const listing = await listings(parent);
|
|
4982
4988
|
if (listing === null) return "absent";
|
|
4983
|
-
const listed2 =
|
|
4989
|
+
const listed2 = listing.has(segment);
|
|
4984
4990
|
if (handle !== null && index2 === segments.length - 1) {
|
|
4985
4991
|
const verdict = classifyLeaf({ listed: listed2, probe: await probeSegment(port, candidate, rel, segment), handle });
|
|
4986
4992
|
if (verdict === "aliased") throw new FilesystemIdentityAliasError(rel, segment);
|
|
@@ -5000,13 +5006,15 @@ function countRestart(restarts, rel) {
|
|
|
5000
5006
|
return restarts + 1;
|
|
5001
5007
|
}
|
|
5002
5008
|
async function observeExact(port, root, rel, read) {
|
|
5009
|
+
return observeWith(port, path2.resolve(root), rel, read, freshListings(port));
|
|
5010
|
+
}
|
|
5011
|
+
async function observeWith(port, rootResolved, rel, read, listings, onExact) {
|
|
5003
5012
|
const segments = relSegments(rel);
|
|
5004
|
-
const rootResolved = path2.resolve(root);
|
|
5005
5013
|
const target3 = path2.join(rootResolved, ...segments);
|
|
5006
5014
|
for (let restarts = 0; ; ) {
|
|
5007
5015
|
const recorded = await recordWalk(port, rootResolved, segments, rel);
|
|
5008
5016
|
if (recorded === null) return { state: "absent" };
|
|
5009
|
-
const verified2 = await confirmedWalk(port, rootResolved, segments, rel, recorded, null);
|
|
5017
|
+
const verified2 = await confirmedWalk(port, rootResolved, segments, rel, recorded, null, listings);
|
|
5010
5018
|
if (verified2 === "absent") return { state: "absent" };
|
|
5011
5019
|
if (verified2 === "restart") {
|
|
5012
5020
|
restarts = countRestart(restarts, rel);
|
|
@@ -5028,11 +5036,14 @@ async function observeExact(port, root, rel, read) {
|
|
|
5028
5036
|
try {
|
|
5029
5037
|
value = await read(opened.handle, target3);
|
|
5030
5038
|
if (value === null) return { state: "absent" };
|
|
5031
|
-
verdict = await confirmedWalk(port, rootResolved, segments, rel, recorded, opened);
|
|
5039
|
+
verdict = await confirmedWalk(port, rootResolved, segments, rel, recorded, opened, listings);
|
|
5032
5040
|
} finally {
|
|
5033
5041
|
await port.close(opened.handle);
|
|
5034
5042
|
}
|
|
5035
|
-
if (verdict === "exact")
|
|
5043
|
+
if (verdict === "exact") {
|
|
5044
|
+
onExact?.(recorded, { dev: opened.dev, ino: opened.ino });
|
|
5045
|
+
return { state: "exact", value };
|
|
5046
|
+
}
|
|
5036
5047
|
if (verdict === "absent") return { state: "absent" };
|
|
5037
5048
|
restarts = countRestart(restarts, rel);
|
|
5038
5049
|
}
|
|
@@ -5051,6 +5062,99 @@ async function probeExact(port, root, rel) {
|
|
|
5051
5062
|
restarts = countRestart(restarts, rel);
|
|
5052
5063
|
}
|
|
5053
5064
|
}
|
|
5065
|
+
function witnessKey(witness) {
|
|
5066
|
+
return `${witness.dev}:${witness.ino}:${witness.mtimeNs}:${witness.ctimeNs}`;
|
|
5067
|
+
}
|
|
5068
|
+
function openObservationPass(port, root, now = Date.now) {
|
|
5069
|
+
const rootResolved = path2.resolve(root);
|
|
5070
|
+
const kept = /* @__PURE__ */ new Map();
|
|
5071
|
+
const reusedVerdicts = [];
|
|
5072
|
+
const fresh = freshListings(port);
|
|
5073
|
+
const witnessOf = port.directoryWitness?.bind(port);
|
|
5074
|
+
const settled = (witness) => {
|
|
5075
|
+
const nowNs = BigInt(Math.floor(now())) * 1000000n;
|
|
5076
|
+
const latest = witness.mtimeNs > witness.ctimeNs ? witness.mtimeNs : witness.ctimeNs;
|
|
5077
|
+
return nowNs - latest >= SETTLED_AFTER_NS;
|
|
5078
|
+
};
|
|
5079
|
+
const listingsFor = () => {
|
|
5080
|
+
let reused = false;
|
|
5081
|
+
if (witnessOf === void 0) return { source: fresh, reused: () => false };
|
|
5082
|
+
const source = async (dir) => {
|
|
5083
|
+
const keep = kept.get(dir);
|
|
5084
|
+
if (keep !== void 0) {
|
|
5085
|
+
const current = await witnessOf(dir);
|
|
5086
|
+
if (current !== null && witnessKey(current) === keep.witness) {
|
|
5087
|
+
reused = true;
|
|
5088
|
+
return keep.names;
|
|
5089
|
+
}
|
|
5090
|
+
kept.delete(dir);
|
|
5091
|
+
}
|
|
5092
|
+
const before = await witnessOf(dir);
|
|
5093
|
+
const listing = await port.entries(dir);
|
|
5094
|
+
if (listing === null) return null;
|
|
5095
|
+
const names = new Set(listing.map((entry) => entry.name));
|
|
5096
|
+
const after = await witnessOf(dir);
|
|
5097
|
+
if (before !== null && after !== null && witnessKey(before) === witnessKey(after) && settled(after)) {
|
|
5098
|
+
kept.set(dir, { witness: witnessKey(after), names });
|
|
5099
|
+
}
|
|
5100
|
+
return names;
|
|
5101
|
+
};
|
|
5102
|
+
return { source, reused: () => reused };
|
|
5103
|
+
};
|
|
5104
|
+
return {
|
|
5105
|
+
async observe(rel, read) {
|
|
5106
|
+
const listings = listingsFor();
|
|
5107
|
+
let exact;
|
|
5108
|
+
let observed;
|
|
5109
|
+
try {
|
|
5110
|
+
observed = await observeWith(port, rootResolved, rel, read, listings.source, (recorded, handle) => {
|
|
5111
|
+
exact = { rel, segments: relSegments(rel), recorded, handle };
|
|
5112
|
+
});
|
|
5113
|
+
} catch (error51) {
|
|
5114
|
+
if (!listings.reused()) throw error51;
|
|
5115
|
+
return observeExact(port, rootResolved, rel, read);
|
|
5116
|
+
}
|
|
5117
|
+
if (!listings.reused()) return observed;
|
|
5118
|
+
if (observed.state === "absent") return observeExact(port, rootResolved, rel, read);
|
|
5119
|
+
if (exact !== void 0) reusedVerdicts.push(exact);
|
|
5120
|
+
return observed;
|
|
5121
|
+
},
|
|
5122
|
+
async finish() {
|
|
5123
|
+
const retry = /* @__PURE__ */ new Set();
|
|
5124
|
+
const endListings = /* @__PURE__ */ new Map();
|
|
5125
|
+
const listedAtEnd = async (dir) => {
|
|
5126
|
+
if (!endListings.has(dir)) {
|
|
5127
|
+
const listing = await port.entries(dir);
|
|
5128
|
+
endListings.set(dir, listing === null ? null : new Set(listing.map((entry) => entry.name)));
|
|
5129
|
+
}
|
|
5130
|
+
return endListings.get(dir);
|
|
5131
|
+
};
|
|
5132
|
+
try {
|
|
5133
|
+
for (const verdict of reusedVerdicts) {
|
|
5134
|
+
if (!await holdsAtEnd(port, rootResolved, verdict, listedAtEnd)) retry.add(verdict.rel);
|
|
5135
|
+
}
|
|
5136
|
+
} finally {
|
|
5137
|
+
kept.clear();
|
|
5138
|
+
reusedVerdicts.length = 0;
|
|
5139
|
+
}
|
|
5140
|
+
return [...retry];
|
|
5141
|
+
}
|
|
5142
|
+
};
|
|
5143
|
+
}
|
|
5144
|
+
async function holdsAtEnd(port, rootResolved, verdict, listedAtEnd) {
|
|
5145
|
+
let parent = rootResolved;
|
|
5146
|
+
for (let index2 = 0; index2 < verdict.segments.length; index2++) {
|
|
5147
|
+
const segment = verdict.segments[index2];
|
|
5148
|
+
const listing = await listedAtEnd(parent);
|
|
5149
|
+
if (listing === null || !listing.has(segment)) return false;
|
|
5150
|
+
const candidate = path2.join(parent, segment);
|
|
5151
|
+
const probed = await port.probe(candidate);
|
|
5152
|
+
const expected = index2 === verdict.segments.length - 1 ? verdict.handle : verdict.recorded[index2];
|
|
5153
|
+
if (probed === null || probed.kind === "symlink" || !sameWitness(probed, expected)) return false;
|
|
5154
|
+
parent = candidate;
|
|
5155
|
+
}
|
|
5156
|
+
return true;
|
|
5157
|
+
}
|
|
5054
5158
|
function unsupportedLinkRoots(port) {
|
|
5055
5159
|
let roots = linkUnsupportedRoots.get(port);
|
|
5056
5160
|
if (!roots) {
|
|
@@ -5201,8 +5305,28 @@ function kindOf(stats) {
|
|
|
5201
5305
|
if (stats.isFile()) return "file";
|
|
5202
5306
|
return "other";
|
|
5203
5307
|
}
|
|
5308
|
+
function directoryWitnessTrusted(platform, filesystemType) {
|
|
5309
|
+
if (platform !== "linux") return true;
|
|
5310
|
+
return filesystemType !== null && LOCAL_LINUX_FILESYSTEMS.has(filesystemType);
|
|
5311
|
+
}
|
|
5312
|
+
function witnessTrust() {
|
|
5313
|
+
const devices = /* @__PURE__ */ new Map();
|
|
5314
|
+
return (dev, dir) => {
|
|
5315
|
+
if (process.platform !== "linux") return Promise.resolve(true);
|
|
5316
|
+
let trusted = devices.get(dev);
|
|
5317
|
+
if (trusted === void 0) {
|
|
5318
|
+
trusted = fs2.statfs(dir).then(
|
|
5319
|
+
(info) => directoryWitnessTrusted("linux", Number(info.type)),
|
|
5320
|
+
() => false
|
|
5321
|
+
);
|
|
5322
|
+
devices.set(dev, trusted);
|
|
5323
|
+
}
|
|
5324
|
+
return trusted;
|
|
5325
|
+
};
|
|
5326
|
+
}
|
|
5204
5327
|
function createNodeFilesystemIdentityPort(hostPolicy) {
|
|
5205
5328
|
const policy = captureFilesystemHostPolicy(hostPolicy);
|
|
5329
|
+
const witnessTrustedOn = witnessTrust();
|
|
5206
5330
|
return Object.freeze({
|
|
5207
5331
|
isTransientOpenError: policy.isTransientOpenError,
|
|
5208
5332
|
isReplacementConflict: policy.isReplacementConflict,
|
|
@@ -5225,6 +5349,17 @@ function createNodeFilesystemIdentityPort(hostPolicy) {
|
|
|
5225
5349
|
throw err;
|
|
5226
5350
|
}
|
|
5227
5351
|
},
|
|
5352
|
+
async directoryWitness(dir) {
|
|
5353
|
+
let stats;
|
|
5354
|
+
try {
|
|
5355
|
+
stats = await fs2.stat(dir, { bigint: true });
|
|
5356
|
+
} catch (err) {
|
|
5357
|
+
if (isAbsentPathError(err)) return null;
|
|
5358
|
+
throw err;
|
|
5359
|
+
}
|
|
5360
|
+
if (!await witnessTrustedOn(stats.dev, dir)) return null;
|
|
5361
|
+
return { dev: stats.dev, ino: stats.ino, mtimeNs: stats.mtimeNs, ctimeNs: stats.ctimeNs };
|
|
5362
|
+
},
|
|
5228
5363
|
async open(target3) {
|
|
5229
5364
|
const handle = await fs2.open(target3, "r");
|
|
5230
5365
|
try {
|
|
@@ -5279,7 +5414,7 @@ function createNodeFilesystemIdentityPort(hostPolicy) {
|
|
|
5279
5414
|
}
|
|
5280
5415
|
});
|
|
5281
5416
|
}
|
|
5282
|
-
var FilesystemSymlinkEntryError, FilesystemShapeMismatchError, ABSENT_PATH_CODES, MAX_RESTARTS, linkUnsupportedRoots, queues, ABSENT_FILE_CODES;
|
|
5417
|
+
var FilesystemSymlinkEntryError, FilesystemShapeMismatchError, ABSENT_PATH_CODES, MAX_RESTARTS, SETTLED_AFTER_NS, linkUnsupportedRoots, queues, ABSENT_FILE_CODES, LOCAL_LINUX_FILESYSTEMS;
|
|
5283
5418
|
var init_filesystem_identity = __esm({
|
|
5284
5419
|
"../core/src/filesystem-identity.ts"() {
|
|
5285
5420
|
"use strict";
|
|
@@ -5310,9 +5445,38 @@ var init_filesystem_identity = __esm({
|
|
|
5310
5445
|
};
|
|
5311
5446
|
ABSENT_PATH_CODES = /* @__PURE__ */ new Set(["ENOENT", "ENOTDIR"]);
|
|
5312
5447
|
MAX_RESTARTS = 3;
|
|
5448
|
+
SETTLED_AFTER_NS = 3000000000n;
|
|
5313
5449
|
linkUnsupportedRoots = /* @__PURE__ */ new WeakMap();
|
|
5314
5450
|
queues = /* @__PURE__ */ new Map();
|
|
5315
5451
|
ABSENT_FILE_CODES = /* @__PURE__ */ new Set(["ENOENT", "ENOTDIR", "EISDIR"]);
|
|
5452
|
+
LOCAL_LINUX_FILESYSTEMS = /* @__PURE__ */ new Set([
|
|
5453
|
+
61267,
|
|
5454
|
+
// ext2/3/4
|
|
5455
|
+
1481003842,
|
|
5456
|
+
// xfs
|
|
5457
|
+
2435016766,
|
|
5458
|
+
// btrfs
|
|
5459
|
+
16914836,
|
|
5460
|
+
// tmpfs
|
|
5461
|
+
2240043254,
|
|
5462
|
+
// ramfs
|
|
5463
|
+
2035054128,
|
|
5464
|
+
// overlayfs
|
|
5465
|
+
801189825,
|
|
5466
|
+
// zfs
|
|
5467
|
+
4076150800,
|
|
5468
|
+
// f2fs
|
|
5469
|
+
3393526350,
|
|
5470
|
+
// bcachefs
|
|
5471
|
+
19780,
|
|
5472
|
+
// vfat
|
|
5473
|
+
538032816,
|
|
5474
|
+
// exfat
|
|
5475
|
+
1936094318,
|
|
5476
|
+
// ntfs3
|
|
5477
|
+
18475
|
|
5478
|
+
// hfsplus
|
|
5479
|
+
]);
|
|
5316
5480
|
}
|
|
5317
5481
|
});
|
|
5318
5482
|
|
|
@@ -5627,10 +5791,11 @@ var init_backend = __esm({
|
|
|
5627
5791
|
return void 0;
|
|
5628
5792
|
}
|
|
5629
5793
|
}
|
|
5630
|
-
async #readWithEdition(id, edition) {
|
|
5794
|
+
async #readWithEdition(id, edition, pass) {
|
|
5631
5795
|
assertSafeConceptId(id);
|
|
5632
5796
|
const rel = pathFromConceptId(id);
|
|
5633
|
-
const
|
|
5797
|
+
const read = (handle) => readBytes(this.#port, handle);
|
|
5798
|
+
const observed = pass ? await pass.observe(rel, read) : await observeExact(this.#port, this.#root, rel, read);
|
|
5634
5799
|
if (observed.state === "absent") throw notFound(this.#root, rel);
|
|
5635
5800
|
const raw = observed.value.toString("utf8");
|
|
5636
5801
|
const { frontmatter, body } = parseMarkdown(raw, rel, { okfVersion: await edition() });
|
|
@@ -5645,7 +5810,12 @@ var init_backend = __esm({
|
|
|
5645
5810
|
}
|
|
5646
5811
|
let editionPromise;
|
|
5647
5812
|
const edition = () => editionPromise ??= this.#readEdition();
|
|
5648
|
-
|
|
5813
|
+
const pass = openObservationPass(this.#port, this.#root);
|
|
5814
|
+
for (const id of ids) out.push(await this.#readWithEdition(id, edition, pass));
|
|
5815
|
+
const retry = new Set(await pass.finish());
|
|
5816
|
+
for (let index2 = 0; index2 < ids.length; index2++) {
|
|
5817
|
+
if (retry.has(pathFromConceptId(ids[index2]))) out[index2] = await this.#readWithEdition(ids[index2], edition);
|
|
5818
|
+
}
|
|
5649
5819
|
return out;
|
|
5650
5820
|
}
|
|
5651
5821
|
async write(id, doc2, options = {}) {
|
|
@@ -22560,7 +22730,13 @@ async function discoverIssuer(fetchImpl, issuer) {
|
|
|
22560
22730
|
throw lastError instanceof CliError ? lastError : new CliError("RUNTIME", `could not read issuer metadata for ${issuer}`);
|
|
22561
22731
|
}
|
|
22562
22732
|
async function discoverHosted(fetchImpl, target3) {
|
|
22563
|
-
|
|
22733
|
+
let prm;
|
|
22734
|
+
try {
|
|
22735
|
+
prm = await fetchJson(fetchImpl, target3.metadataUrl, "protected-resource metadata");
|
|
22736
|
+
} catch (error51) {
|
|
22737
|
+
if (error51 instanceof CliError && error51.details?.status === 404) throw missingMetadataError(target3);
|
|
22738
|
+
throw error51;
|
|
22739
|
+
}
|
|
22564
22740
|
const resource = optionalString(prm.resource);
|
|
22565
22741
|
if (resource === void 0) {
|
|
22566
22742
|
throw new CliError("RUNTIME", `protected-resource metadata at ${target3.metadataUrl} has no resource`);
|
|
@@ -22604,13 +22780,93 @@ function resolveClientId(sources) {
|
|
|
22604
22780
|
details
|
|
22605
22781
|
});
|
|
22606
22782
|
}
|
|
22607
|
-
|
|
22783
|
+
function parentDomain(hostname5) {
|
|
22784
|
+
if (hostname5.startsWith("[") || IPV4.test(hostname5)) return null;
|
|
22785
|
+
const labels = hostname5.split(".");
|
|
22786
|
+
if (labels.length < 3 || labels.some((label) => label === "")) return null;
|
|
22787
|
+
return labels.slice(1).join(".");
|
|
22788
|
+
}
|
|
22789
|
+
function mayBeWorkspaceOrigin(target3) {
|
|
22790
|
+
const url2 = new URL(target3.origin);
|
|
22791
|
+
return url2.protocol === "https:" && url2.port === "" && target3.audience === `${target3.origin}${DEFAULT_RESOURCE_PATH}` && parentDomain(url2.hostname) !== null;
|
|
22792
|
+
}
|
|
22793
|
+
function trustedPointerTarget(origin, resource) {
|
|
22794
|
+
if (typeof resource !== "string" || resource.length > MAX_POINTER_RESOURCE_LENGTH || resource.includes("@")) return null;
|
|
22795
|
+
let from;
|
|
22796
|
+
let to;
|
|
22797
|
+
try {
|
|
22798
|
+
from = new URL(origin);
|
|
22799
|
+
to = new URL(resource);
|
|
22800
|
+
} catch {
|
|
22801
|
+
return null;
|
|
22802
|
+
}
|
|
22803
|
+
if (from.protocol !== "https:" || to.protocol !== "https:") return null;
|
|
22804
|
+
if (to.username || to.password || to.port !== "" || from.port !== "" || to.search || to.hash) return null;
|
|
22805
|
+
if (to.hostname === from.hostname) return null;
|
|
22806
|
+
const parent = parentDomain(from.hostname);
|
|
22807
|
+
if (parent === null || to.hostname !== `mcp.${parent}`) return null;
|
|
22808
|
+
try {
|
|
22809
|
+
return resolveHostedTarget(resource);
|
|
22810
|
+
} catch {
|
|
22811
|
+
return null;
|
|
22812
|
+
}
|
|
22813
|
+
}
|
|
22814
|
+
function missingMetadataError(target3) {
|
|
22815
|
+
const hostname5 = new URL(target3.origin).hostname;
|
|
22816
|
+
const parent = parentDomain(hostname5);
|
|
22817
|
+
const label = hostname5.split(".")[0];
|
|
22818
|
+
const suggestion = parent !== null && label !== "mcp" && isWorkspaceSlug(label) ? { host: `https://mcp.${parent}`, workspace: label } : null;
|
|
22819
|
+
return new CliError("RUNTIME", `protected-resource metadata at ${target3.metadataUrl} returned HTTP 404`, {
|
|
22820
|
+
details: {
|
|
22821
|
+
status: 404,
|
|
22822
|
+
reason: "no_protected_resource_metadata",
|
|
22823
|
+
host: target3.origin,
|
|
22824
|
+
...suggestion ? { suggested_host: suggestion.host, suggested_workspace: suggestion.workspace } : {}
|
|
22825
|
+
},
|
|
22826
|
+
help: suggestion ? `${target3.origin} may be a workspace address rather than the sign-in host; if so, re-run with --host ${commandToken(suggestion.host)} --workspace ${commandToken(suggestion.workspace)} (--workspace only where the command takes it)` : `${target3.origin} publishes no Superbee sign-in metadata; check the URL, or ask the host's operator which Superbee host to use`
|
|
22827
|
+
});
|
|
22828
|
+
}
|
|
22829
|
+
async function readWorkspacePointer(fetchImpl, target3) {
|
|
22830
|
+
let pointer;
|
|
22831
|
+
try {
|
|
22832
|
+
pointer = await fetchJson(fetchImpl, `${target3.origin}${WORKSPACE_POINTER_PATH}`, "workspace pointer");
|
|
22833
|
+
} catch {
|
|
22834
|
+
return null;
|
|
22835
|
+
}
|
|
22836
|
+
if (pointer.schema_version !== 1 || !isWorkspaceSlug(pointer.workspace_slug)) return null;
|
|
22837
|
+
if (pointer.workspace_slug !== new URL(target3.origin).hostname.split(".")[0]) return null;
|
|
22838
|
+
const gateway = trustedPointerTarget(target3.origin, pointer.resource);
|
|
22839
|
+
if (gateway === null) return null;
|
|
22840
|
+
return { target: gateway, workspaceSlug: pointer.workspace_slug, requestedOrigin: target3.origin };
|
|
22841
|
+
}
|
|
22842
|
+
async function followWorkspaceOrigin(fetchImpl, target3) {
|
|
22843
|
+
if (!mayBeWorkspaceOrigin(target3)) return null;
|
|
22844
|
+
let status2;
|
|
22845
|
+
try {
|
|
22846
|
+
const response = await fetchImpl(target3.metadataUrl, {
|
|
22847
|
+
headers: { accept: "application/json" },
|
|
22848
|
+
redirect: "error",
|
|
22849
|
+
signal: AbortSignal.timeout(HTTP_TIMEOUT_MS)
|
|
22850
|
+
});
|
|
22851
|
+
status2 = response.status;
|
|
22852
|
+
await response.body?.cancel().catch(() => void 0);
|
|
22853
|
+
} catch {
|
|
22854
|
+
return null;
|
|
22855
|
+
}
|
|
22856
|
+
if (status2 !== 404) return null;
|
|
22857
|
+
const followed = await readWorkspacePointer(fetchImpl, target3);
|
|
22858
|
+
if (followed === null) throw missingMetadataError(target3);
|
|
22859
|
+
return followed;
|
|
22860
|
+
}
|
|
22861
|
+
var DEFAULT_RESOURCE_PATH, PUBLISHED_CLIENT_ID_FIELD, BUILT_IN_CLIENT_IDS, REQUESTED_SCOPE, HTTP_TIMEOUT_MS, CLIENT_ID, MAX_METADATA_BYTES, WORKSPACE_POINTER_PATH, IPV4, MAX_POINTER_RESOURCE_LENGTH;
|
|
22608
22862
|
var init_discovery = __esm({
|
|
22609
22863
|
"../cli/src/hosted-auth/discovery.ts"() {
|
|
22610
22864
|
"use strict";
|
|
22611
22865
|
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
22612
22866
|
init_define_SUPERBEE_UPDATE_POLICY();
|
|
22613
22867
|
init_errors4();
|
|
22868
|
+
init_command_text();
|
|
22869
|
+
init_reference();
|
|
22614
22870
|
DEFAULT_RESOURCE_PATH = "/mcp";
|
|
22615
22871
|
PUBLISHED_CLIENT_ID_FIELD = "superbee_cli_client_id";
|
|
22616
22872
|
BUILT_IN_CLIENT_IDS = Object.freeze({});
|
|
@@ -22618,6 +22874,9 @@ var init_discovery = __esm({
|
|
|
22618
22874
|
HTTP_TIMEOUT_MS = 1e4;
|
|
22619
22875
|
CLIENT_ID = /^[\x21-\x7e]{1,256}$/;
|
|
22620
22876
|
MAX_METADATA_BYTES = 256 * 1024;
|
|
22877
|
+
WORKSPACE_POINTER_PATH = "/.well-known/superbee-workspace";
|
|
22878
|
+
IPV4 = /^\d{1,3}(?:\.\d{1,3}){3}$/;
|
|
22879
|
+
MAX_POINTER_RESOURCE_LENGTH = 2048;
|
|
22621
22880
|
}
|
|
22622
22881
|
});
|
|
22623
22882
|
|
|
@@ -22840,8 +23099,11 @@ __export(session_exports, {
|
|
|
22840
23099
|
readPending: () => readPending,
|
|
22841
23100
|
readSession: () => readSession,
|
|
22842
23101
|
requireHostedBundleHost: () => requireHostedBundleHost,
|
|
23102
|
+
resolveHostChoice: () => resolveHostChoice,
|
|
23103
|
+
resolveHostChoiceOrNull: () => resolveHostChoiceOrNull,
|
|
22843
23104
|
resolveHostSelection: () => resolveHostSelection,
|
|
22844
23105
|
resolveHostSelectionOrNull: () => resolveHostSelectionOrNull,
|
|
23106
|
+
resolveNamedHost: () => resolveNamedHost,
|
|
22845
23107
|
sessionAccount: () => sessionAccount,
|
|
22846
23108
|
sessionDirFor: () => sessionDirFor,
|
|
22847
23109
|
storeForNewSession: () => storeForNewSession,
|
|
@@ -22852,6 +23114,8 @@ __export(session_exports, {
|
|
|
22852
23114
|
waitForHostedSignIn: () => waitForHostedSignIn,
|
|
22853
23115
|
waitingSignIns: () => waitingSignIns,
|
|
22854
23116
|
withSessionLock: () => withSessionLock,
|
|
23117
|
+
workspaceForNamedHost: () => workspaceForNamedHost,
|
|
23118
|
+
workspaceOriginView: () => workspaceOriginView,
|
|
22855
23119
|
writeDefaultHost: () => writeDefaultHost
|
|
22856
23120
|
});
|
|
22857
23121
|
import { mkdir as mkdir2, readdir as readdir3, realpath as realpath2, stat as stat3, unlink as unlink5 } from "node:fs/promises";
|
|
@@ -22955,10 +23219,31 @@ function notSignedInError(env = {}) {
|
|
|
22955
23219
|
{ details: { status: "not_signed_in", reason: "no_host", sign_in_command: command }, help: command }
|
|
22956
23220
|
);
|
|
22957
23221
|
}
|
|
22958
|
-
async function requireHostedBundleHost(flag,
|
|
22959
|
-
|
|
22960
|
-
|
|
22961
|
-
|
|
23222
|
+
async function requireHostedBundleHost(flag, deps) {
|
|
23223
|
+
if (flag && deps.fetch !== null) return resolveNamedHost(flag, { home: deps.home, fetch: deps.fetch });
|
|
23224
|
+
const chosen = await hostedBundleHost(flag, deps.home);
|
|
23225
|
+
if (!chosen) throw notSignedInError(deps.env);
|
|
23226
|
+
return { target: resolveHostedTarget(chosen), workspaceSlug: null, requestedOrigin: null };
|
|
23227
|
+
}
|
|
23228
|
+
async function resolveNamedHost(host, deps) {
|
|
23229
|
+
const target3 = resolveHostedTarget(host);
|
|
23230
|
+
const plain = { target: target3, workspaceSlug: null, requestedOrigin: null };
|
|
23231
|
+
if (await readSession(deps.home, target3) || await readPending(deps.home, target3)) return plain;
|
|
23232
|
+
const followed = await followWorkspaceOrigin(deps.fetch, target3);
|
|
23233
|
+
if (!followed) return plain;
|
|
23234
|
+
return { target: followed.target, workspaceSlug: followed.workspaceSlug, requestedOrigin: followed.requestedOrigin };
|
|
23235
|
+
}
|
|
23236
|
+
function workspaceOriginView(named) {
|
|
23237
|
+
if (named.requestedOrigin === null || named.workspaceSlug === null) return {};
|
|
23238
|
+
return { host_from: "workspace-origin", requested_host: named.requestedOrigin, workspace_slug: named.workspaceSlug };
|
|
23239
|
+
}
|
|
23240
|
+
function workspaceForNamedHost(named, flag) {
|
|
23241
|
+
if (named.workspaceSlug === null) return flag;
|
|
23242
|
+
if (flag === void 0 || flag === named.workspaceSlug) return named.workspaceSlug;
|
|
23243
|
+
throw new CliError("USAGE", `--host ${commandToken(named.requestedOrigin ?? "")} is the address of workspace '${named.workspaceSlug}', but --workspace names '${flag}'`, {
|
|
23244
|
+
details: { reason: "workspace_conflict", host_workspace: named.workspaceSlug, workspace: flag },
|
|
23245
|
+
help: `drop --workspace to use '${named.workspaceSlug}', or pass the other workspace's own address (or its slug) instead`
|
|
23246
|
+
});
|
|
22962
23247
|
}
|
|
22963
23248
|
async function storedSessionHosts(home2) {
|
|
22964
23249
|
const root = hostedAuthRoot(home2);
|
|
@@ -23007,6 +23292,8 @@ function hostSourceText(source) {
|
|
|
23007
23292
|
switch (source) {
|
|
23008
23293
|
case "flag":
|
|
23009
23294
|
return "--host";
|
|
23295
|
+
case "workspace-origin":
|
|
23296
|
+
return "the gateway the workspace address in --host points to";
|
|
23010
23297
|
case "last-sign-in":
|
|
23011
23298
|
return "your last sign-in, the only host with a session";
|
|
23012
23299
|
case "only-session":
|
|
@@ -23015,11 +23302,14 @@ function hostSourceText(source) {
|
|
|
23015
23302
|
return "your last sign-in; no session for it now";
|
|
23016
23303
|
}
|
|
23017
23304
|
}
|
|
23018
|
-
async function hostedWriteHost(flag, home2, retry) {
|
|
23305
|
+
async function hostedWriteHost(flag, home2, retry, fetchImpl) {
|
|
23019
23306
|
if (flag !== void 0) {
|
|
23020
23307
|
if (flag.trim() === "") throw new CliError("USAGE", "--host is empty: name the hosted Superbee URL", { help: retry("<url>") });
|
|
23021
|
-
return { target: resolveHostedTarget(flag), source: "flag" };
|
|
23308
|
+
if (fetchImpl === null) return { target: resolveHostedTarget(flag), source: "flag", workspaceSlug: null, requestedOrigin: null };
|
|
23309
|
+
const named = await resolveNamedHost(flag, { home: home2, fetch: fetchImpl });
|
|
23310
|
+
return { ...named, source: named.requestedOrigin !== null ? "workspace-origin" : "flag" };
|
|
23022
23311
|
}
|
|
23312
|
+
const unnamed = { workspaceSlug: null, requestedOrigin: null };
|
|
23023
23313
|
const remembered = await readDefaultHost(home2);
|
|
23024
23314
|
const stored = await storedSessionHosts(home2);
|
|
23025
23315
|
const candidates = new Set(stored);
|
|
@@ -23043,22 +23333,30 @@ async function hostedWriteHost(flag, home2, retry) {
|
|
|
23043
23333
|
help: `re-run with --host set to the host you mean (one of: ${hosts.join(", ")}); the last sign-in is not used when sessions are held for more than one host or it has none`
|
|
23044
23334
|
});
|
|
23045
23335
|
}
|
|
23046
|
-
if (rememberedHost) return { target: resolveHostedTarget(rememberedHost), source: stored.length === 0 ? "last-sign-in-signed-out" : "last-sign-in" };
|
|
23047
|
-
if (stored.length === 1) return { target: resolveHostedTarget(stored[0]), source: "only-session" };
|
|
23336
|
+
if (rememberedHost) return { target: resolveHostedTarget(rememberedHost), source: stored.length === 0 ? "last-sign-in-signed-out" : "last-sign-in", ...unnamed };
|
|
23337
|
+
if (stored.length === 1) return { target: resolveHostedTarget(stored[0]), source: "only-session", ...unnamed };
|
|
23048
23338
|
return null;
|
|
23049
23339
|
}
|
|
23340
|
+
async function resolveHostChoiceOrNull(flag, deps) {
|
|
23341
|
+
const named = flag ?? (deps.env[HOST_ENV] || void 0);
|
|
23342
|
+
if (named !== void 0) return resolveNamedHost(named, deps);
|
|
23343
|
+
const remembered = await readDefaultHost(deps.home);
|
|
23344
|
+
return remembered ? { target: resolveHostedTarget(remembered), workspaceSlug: null, requestedOrigin: null } : null;
|
|
23345
|
+
}
|
|
23050
23346
|
async function resolveHostSelectionOrNull(flag, deps) {
|
|
23051
|
-
|
|
23052
|
-
return chosen ? resolveHostedTarget(chosen) : null;
|
|
23347
|
+
return (await resolveHostChoiceOrNull(flag, deps))?.target ?? null;
|
|
23053
23348
|
}
|
|
23054
|
-
async function
|
|
23055
|
-
const
|
|
23056
|
-
if (!
|
|
23349
|
+
async function resolveHostChoice(flag, deps) {
|
|
23350
|
+
const choice = await resolveHostChoiceOrNull(flag, deps);
|
|
23351
|
+
if (!choice) {
|
|
23057
23352
|
throw new CliError("USAGE", "no hosted Superbee host selected", {
|
|
23058
23353
|
help: `pass --host <url> (for example ${String(firstSignInCommand())}) or set ${HOST_ENV}`
|
|
23059
23354
|
});
|
|
23060
23355
|
}
|
|
23061
|
-
return
|
|
23356
|
+
return choice;
|
|
23357
|
+
}
|
|
23358
|
+
async function resolveHostSelection(flag, deps) {
|
|
23359
|
+
return (await resolveHostChoice(flag, deps)).target;
|
|
23062
23360
|
}
|
|
23063
23361
|
function directoryForAccount(home2) {
|
|
23064
23362
|
return (account) => sessionDirFor(home2, account);
|
|
@@ -26304,8 +26602,10 @@ function jsonPure(value) {
|
|
|
26304
26602
|
if (typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype) return Object.values(value).every(jsonPure);
|
|
26305
26603
|
return false;
|
|
26306
26604
|
}
|
|
26307
|
-
function wholeDocumentRequest(bundleId, intent, okfVersion) {
|
|
26605
|
+
function wholeDocumentRequest(bundleId, intent, okfVersion, options = {}) {
|
|
26308
26606
|
const operation = operationOf(intent);
|
|
26607
|
+
const importing = options.mode === "import";
|
|
26608
|
+
if (importing && operation !== "create") throw new WholeDocumentInputError(`'${intent.target}' is a ${operation}, and only a create may carry imported provenance`, "unsupported_operation");
|
|
26309
26609
|
if (operation === "delete") return { kind: "delete", operationId: OPERATION_IDS.delete, payload: { bundleId, documentId: intent.target, expectedVersion: intent.base } };
|
|
26310
26610
|
let parsed2;
|
|
26311
26611
|
try {
|
|
@@ -26314,11 +26614,17 @@ function wholeDocumentRequest(bundleId, intent, okfVersion) {
|
|
|
26314
26614
|
throw new WholeDocumentInputError(`'${intent.target}' does not parse: ${error51.message}`);
|
|
26315
26615
|
}
|
|
26316
26616
|
const frontmatter = {};
|
|
26617
|
+
const carried = [];
|
|
26618
|
+
const dropped = [];
|
|
26317
26619
|
for (const [key2, value] of Object.entries(parsed2.frontmatter)) {
|
|
26318
26620
|
if (!HOSTED_MANAGED_FIELDS.has(key2)) frontmatter[key2] = value;
|
|
26621
|
+
else if (importing && IMPORT_CARRIED_FIELDS.includes(key2)) {
|
|
26622
|
+
frontmatter[key2] = value;
|
|
26623
|
+
carried.push(key2);
|
|
26624
|
+
} else if (importing) dropped.push(key2);
|
|
26319
26625
|
}
|
|
26320
26626
|
if (!jsonPure(frontmatter)) throw new WholeDocumentInputError(`'${intent.target}' has frontmatter that is not plain JSON`);
|
|
26321
|
-
const keys = Object.keys(frontmatter);
|
|
26627
|
+
const keys = Object.keys(frontmatter).filter((key2) => !HOSTED_MANAGED_FIELDS.has(key2));
|
|
26322
26628
|
if (keys.length > FRONTMATTER_KEY_LIMIT) throw new WholeDocumentInputError(`'${intent.target}' has ${keys.length} frontmatter fields; at most ${FRONTMATTER_KEY_LIMIT} are accepted`);
|
|
26323
26629
|
if (typeof frontmatter.type !== "string" || frontmatter.type.trim() === "") throw new WholeDocumentInputError(`'${intent.target}' has no type`);
|
|
26324
26630
|
if (keys.some((key2) => UNSAFE_KEYS.has(key2))) throw new WholeDocumentInputError(`'${intent.target}' names a reserved object key in its frontmatter`);
|
|
@@ -26327,7 +26633,8 @@ function wholeDocumentRequest(bundleId, intent, okfVersion) {
|
|
|
26327
26633
|
kind: "create",
|
|
26328
26634
|
operationId: OPERATION_IDS.create,
|
|
26329
26635
|
payload: { bundleId, documentId: intent.target, expectAbsent: true, frontmatter, body: parsed2.body },
|
|
26330
|
-
...intent.recreates !== void 0 ? { recreates: intent.recreates } : {}
|
|
26636
|
+
...intent.recreates !== void 0 ? { recreates: intent.recreates } : {},
|
|
26637
|
+
...importing ? { provenance: { carried, dropped } } : {}
|
|
26331
26638
|
} : { kind: "replace", operationId: OPERATION_IDS.replace, payload: { ...common, expectedVersion: intent.base } };
|
|
26332
26639
|
}
|
|
26333
26640
|
function createWholeDocumentTransport(options) {
|
|
@@ -26497,7 +26804,7 @@ function createWholeDocumentTransport(options) {
|
|
|
26497
26804
|
}
|
|
26498
26805
|
};
|
|
26499
26806
|
}
|
|
26500
|
-
var HOSTED_MANAGED_FIELDS, FRONTMATTER_KEY_LIMIT, UNSAFE_KEYS, WHOLE_DOCUMENT_SETTLEMENT, WHOLE_DOCUMENT_BOUNDS, CURRENT_HOST_DOCUMENT_INPUT_BYTES, SYNC_WRITE_ROUTES, OPERATION_IDS, WHOLE_DOCUMENT_INTENT_KINDS, WholeDocumentInputError, UNKNOWN3, encoder2;
|
|
26807
|
+
var HOSTED_MANAGED_FIELDS, IMPORT_CARRIED_FIELDS, IMPORT_DROPPED_FIELDS, FRONTMATTER_KEY_LIMIT, UNSAFE_KEYS, WHOLE_DOCUMENT_SETTLEMENT, WHOLE_DOCUMENT_BOUNDS, CURRENT_HOST_DOCUMENT_INPUT_BYTES, SYNC_WRITE_ROUTES, OPERATION_IDS, WHOLE_DOCUMENT_INTENT_KINDS, WholeDocumentInputError, UNKNOWN3, encoder2;
|
|
26501
26808
|
var init_whole_document_transport = __esm({
|
|
26502
26809
|
"../core/src/hosted-transport/whole-document-transport.ts"() {
|
|
26503
26810
|
"use strict";
|
|
@@ -26510,6 +26817,8 @@ var init_whole_document_transport = __esm({
|
|
|
26510
26817
|
init_version_transport();
|
|
26511
26818
|
init_read_adapter();
|
|
26512
26819
|
HOSTED_MANAGED_FIELDS = /* @__PURE__ */ new Set(["actor", "superbee_updated_by", "generated", "verified", "timestamp", "okf_version"]);
|
|
26820
|
+
IMPORT_CARRIED_FIELDS = Object.freeze(["generated", "timestamp", "actor", "okf_version"]);
|
|
26821
|
+
IMPORT_DROPPED_FIELDS = Object.freeze([...HOSTED_MANAGED_FIELDS].filter((field) => !IMPORT_CARRIED_FIELDS.includes(field)));
|
|
26513
26822
|
FRONTMATTER_KEY_LIMIT = 32;
|
|
26514
26823
|
UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
26515
26824
|
WHOLE_DOCUMENT_SETTLEMENT = "recorded-only";
|
|
@@ -129253,11 +129562,13 @@ async function bundleRetire(argv2, partial2 = {}) {
|
|
|
129253
129562
|
if (!typed) {
|
|
129254
129563
|
throw new CliError("USAGE", `'${positionals[0]}' is not a hosted bundle id or <workspace>/<bundle-id>`, { help: `${cliInvocation()} bundle retire --help` });
|
|
129255
129564
|
}
|
|
129256
|
-
const
|
|
129565
|
+
const named = await requireHostedBundleHost(values.host, deps.auth);
|
|
129566
|
+
const target3 = named.target;
|
|
129567
|
+
const workspace = workspaceForNamedHost(named, values.workspace);
|
|
129257
129568
|
const host = commandToken(hostArgument(target3));
|
|
129258
|
-
const command = (reference2) => commandFragment`${cliInvocation()} bundle retire ${commandToken(reference2)} --host ${host}${
|
|
129569
|
+
const command = (reference2) => commandFragment`${cliInvocation()} bundle retire ${commandToken(reference2)} --host ${host}${workspace !== void 0 ? commandFragment` --workspace ${commandToken(workspace)}` : commandFragment``}`;
|
|
129259
129570
|
const resume2 = commandFragment`${command(hostedBundleReferenceText(typed))}${values.json ? commandFragment` --json` : commandFragment``}`;
|
|
129260
|
-
const account = await connectHostedAccount(target3, { ...
|
|
129571
|
+
const account = await connectHostedAccount(target3, { ...workspace !== void 0 ? { workspace } : {}, resume: resume2 }, { auth: deps.auth, ...deps.fetch ? { fetch: deps.fetch } : {} });
|
|
129261
129572
|
const resolved = resolveBundleReference(typed, account, target3, command).reference;
|
|
129262
129573
|
const client = resolved.slug === null ? account.client : account.client.within(resolved.slug);
|
|
129263
129574
|
const reference = hostedBundleReferenceText(resolved);
|
|
@@ -129627,7 +129938,7 @@ async function catalogInner(argv2, deps) {
|
|
|
129627
129938
|
}
|
|
129628
129939
|
async function listHosted(values, deps, home2, stdout) {
|
|
129629
129940
|
const auth = deps.auth ?? defaultHostedAuthDeps(home2);
|
|
129630
|
-
const target3 = await requireHostedBundleHost(values.host, auth
|
|
129941
|
+
const { target: target3 } = await requireHostedBundleHost(values.host, auth);
|
|
129631
129942
|
const host = hostArgument(target3);
|
|
129632
129943
|
const resume2 = commandFragment`${cliInvocation()} catalog list --hosted --host ${commandToken(host)}${values.json ? commandFragment` --json` : commandFragment``}`;
|
|
129633
129944
|
const { client, identity } = await connectHostedAccount(
|
|
@@ -130868,9 +131179,9 @@ async function setupHosted(argv2, partial2 = {}) {
|
|
|
130868
131179
|
return;
|
|
130869
131180
|
}
|
|
130870
131181
|
const mode = resolveMode(values);
|
|
130871
|
-
let
|
|
131182
|
+
let choice;
|
|
130872
131183
|
try {
|
|
130873
|
-
|
|
131184
|
+
choice = await resolveHostChoice(values.url, auth);
|
|
130874
131185
|
} catch (error51) {
|
|
130875
131186
|
if (error51 instanceof CliError && error51.code === "USAGE" && values.url === void 0) {
|
|
130876
131187
|
throw new CliError("USAGE", "no hosted Superbee URL: pass --url", { help: `${cliInvocation()} setup hosted --url <hosted-url>` });
|
|
@@ -130880,17 +131191,20 @@ async function setupHosted(argv2, partial2 = {}) {
|
|
|
130880
131191
|
}
|
|
130881
131192
|
throw error51;
|
|
130882
131193
|
}
|
|
131194
|
+
const target3 = choice.target;
|
|
131195
|
+
const requested = workspaceForNamedHost(choice, values.workspace);
|
|
130883
131196
|
const host = hostArgument(target3);
|
|
130884
|
-
const resume2 = commandFragment`${cliInvocation()} setup hosted --url ${commandToken(host)}${
|
|
131197
|
+
const resume2 = commandFragment`${cliInvocation()} setup hosted --url ${commandToken(host)}${requested !== void 0 ? commandFragment` --workspace ${commandToken(requested)}` : commandFragment``}${values.json ? commandFragment` --json` : commandFragment``}`;
|
|
130885
131198
|
const { identity, workspace: chosen } = await connectHostedAccount(
|
|
130886
131199
|
target3,
|
|
130887
|
-
{ workspace:
|
|
131200
|
+
{ workspace: requested, resume: resume2, otherWorkspace: `${cliInvocation()} setup hosted --url ${commandToken(host)} --workspace <id>` },
|
|
130888
131201
|
{ auth, ...partial2.fetch ? { fetch: partial2.fetch } : {} }
|
|
130889
131202
|
);
|
|
130890
131203
|
await writeDefaultHost(auth.home, host);
|
|
130891
131204
|
const workspaces = identity.tenantIds;
|
|
130892
131205
|
const base = {
|
|
130893
131206
|
host: target3.origin,
|
|
131207
|
+
...workspaceOriginView(choice),
|
|
130894
131208
|
signed_in: true,
|
|
130895
131209
|
principal: identity.principalId,
|
|
130896
131210
|
workspaces
|
|
@@ -131953,7 +132267,8 @@ async function login(argv2, partial2 = {}) {
|
|
|
131953
132267
|
const port = parsePort(values.port);
|
|
131954
132268
|
const clientIdFlag = values["client-id"] || void 0;
|
|
131955
132269
|
const auth = { ...deps.auth, env: { ...deps.auth.env, [ACCESS_TOKEN_ENV]: void 0 } };
|
|
131956
|
-
const
|
|
132270
|
+
const choice = await resolveHostChoice(values.host, auth);
|
|
132271
|
+
const target3 = choice.target;
|
|
131957
132272
|
const signIn = { ...clientIdFlag ? { clientIdFlag } : {} };
|
|
131958
132273
|
let token;
|
|
131959
132274
|
if (values.loopback && await readSession(auth.home, target3)) {
|
|
@@ -131993,6 +132308,7 @@ ${url2}
|
|
|
131993
132308
|
status: token.source === "sign-in" ? "signed_in" : "already_signed_in",
|
|
131994
132309
|
host: target3.origin,
|
|
131995
132310
|
audience: target3.audience,
|
|
132311
|
+
...workspaceOriginView(choice),
|
|
131996
132312
|
...session ? sessionView(session) : {},
|
|
131997
132313
|
...deps.auth.env[ACCESS_TOKEN_ENV] ? { env_override: `${ACCESS_TOKEN_ENV} is set and takes precedence for hosted commands` } : {},
|
|
131998
132314
|
help: [`${cliInvocation()} whoami --host ${commandToken(hostArgument(target3))}`]
|
|
@@ -132198,8 +132514,11 @@ and it completes sign-in. --wait polls instead, for at most --timeout seconds
|
|
|
132198
132514
|
--loopback signs in through a browser redirect to 127.0.0.1 (PKCE), waits at most --timeout
|
|
132199
132515
|
seconds, then falls back to device sign-in. The link is printed on stderr.
|
|
132200
132516
|
|
|
132201
|
-
The host is --host, then ${HOST_ENV}, then the host of the last sign-in.
|
|
132202
|
-
|
|
132517
|
+
The host is --host, then ${HOST_ENV}, then the host of the last sign-in. A workspace address
|
|
132518
|
+
(<workspace>.<domain>) with no metadata of its own is followed, through its
|
|
132519
|
+
/.well-known/superbee-workspace pointer, to the gateway it names under the same domain; the
|
|
132520
|
+
session is kept for that gateway (reported as host_from: workspace-origin). The issuer comes from
|
|
132521
|
+
the host's protected-resource metadata. The CLI client id comes from --client-id, then
|
|
132203
132522
|
${CLIENT_ID_ENV}, then the host's metadata. The refresh token is kept in the OS credential store
|
|
132204
132523
|
(macOS Keychain, Linux Secret Service); ${CREDENTIAL_STORE_ENV}=file opts in to a 0600 file
|
|
132205
132524
|
instead. ${ACCESS_TOKEN_ENV} (for CI) is used as given by hosted commands and is never stored.
|
|
@@ -132219,10 +132538,12 @@ Options:
|
|
|
132219
132538
|
Usage:
|
|
132220
132539
|
superbee whoami [--host <url>] [--json]
|
|
132221
132540
|
|
|
132222
|
-
|
|
132541
|
+
Read-only: reports the host, issuer, client, the signed-in subject from the token's
|
|
132223
132542
|
claims (not yet confirmed by the gateway), scopes, token expiry, where the refresh token is kept,
|
|
132224
132543
|
and any sign-in waiting on the person. Never prints a token. Not signed in is a successful result,
|
|
132225
132544
|
including on a first run with no host selected yet (it names the sign-in command).
|
|
132545
|
+
It reads local state only, except that a host with no stored session that turns out to be a
|
|
132546
|
+
workspace's browser address is resolved to its gateway first (its metadata and pointer requests).
|
|
132226
132547
|
|
|
132227
132548
|
Options:
|
|
132228
132549
|
--host <url> Hosted Superbee URL (default: ${HOST_ENV}, then the last sign-in)
|
|
@@ -132915,18 +133236,18 @@ async function release(folderArg, deps, mode) {
|
|
|
132915
133236
|
)
|
|
132916
133237
|
);
|
|
132917
133238
|
}
|
|
132918
|
-
async function checkoutHost(flag, folder, typed, values, home2, env) {
|
|
133239
|
+
async function checkoutHost(flag, folder, typed, values, home2, env, fetchImpl) {
|
|
132919
133240
|
if (flag === void 0) {
|
|
132920
133241
|
const real = await realpath11(folder).catch(() => null);
|
|
132921
133242
|
const bound = real ? await bindingForPath(home2, real).catch(() => null) : null;
|
|
132922
|
-
if (bound) return checkoutTarget(bound);
|
|
133243
|
+
if (bound) return { target: checkoutTarget(bound), workspace: values.workspace, origin: {} };
|
|
132923
133244
|
}
|
|
132924
133245
|
const retry = (host) => String(
|
|
132925
133246
|
commandFragment`${cliInvocation()} checkout ${commandToken(hostedBundleReferenceText(typed))} --host ${commandToken(host)} --dir ${commandToken(folder)}${values.workspace !== void 0 ? commandFragment` --workspace ${commandToken(values.workspace)}` : commandFragment``}${values.json ? commandFragment` --json` : commandFragment``}`
|
|
132926
133247
|
);
|
|
132927
|
-
const chosen = await hostedWriteHost(flag, home2, retry);
|
|
133248
|
+
const chosen = await hostedWriteHost(flag, home2, retry, fetchImpl);
|
|
132928
133249
|
if (!chosen) throw notSignedInError(env);
|
|
132929
|
-
return chosen.target;
|
|
133250
|
+
return { target: chosen.target, workspace: workspaceForNamedHost(chosen, values.workspace), origin: workspaceOriginView(chosen) };
|
|
132930
133251
|
}
|
|
132931
133252
|
async function checkout(argv2, partial2 = {}) {
|
|
132932
133253
|
const deps = checkoutDeps(partial2);
|
|
@@ -132975,16 +133296,16 @@ async function checkout(argv2, partial2 = {}) {
|
|
|
132975
133296
|
const bundleId = typed.bundleId;
|
|
132976
133297
|
const folder = path53.resolve(deps.cwd, values.dir ?? bundleId);
|
|
132977
133298
|
assertBundleOutsidePrivateState(folder, deps.auth.home);
|
|
132978
|
-
const target3 = await checkoutHost(values.host, folder, typed, values, deps.auth.home, deps.auth.env);
|
|
133299
|
+
const { target: target3, workspace: workspaceFlag2, origin: hostOrigin } = await checkoutHost(values.host, folder, typed, values, deps.auth.home, deps.auth.env, deps.auth.fetch);
|
|
132979
133300
|
const prefix = syncRoutePrefix(target3);
|
|
132980
|
-
const resume2 = commandFragment`${cliInvocation()} checkout ${commandToken(hostedBundleReferenceText(typed))} --host ${commandToken(hostArgument(target3))} --dir ${commandToken(folder)}${
|
|
133301
|
+
const resume2 = commandFragment`${cliInvocation()} checkout ${commandToken(hostedBundleReferenceText(typed))} --host ${commandToken(hostArgument(target3))} --dir ${commandToken(folder)}${workspaceFlag2 !== void 0 ? commandFragment` --workspace ${commandToken(workspaceFlag2)}` : commandFragment``}${values.json ? commandFragment` --json` : commandFragment``}`;
|
|
132981
133302
|
const found = await entryKind(folder);
|
|
132982
133303
|
if (found === "other") {
|
|
132983
133304
|
throw new CliError("ALREADY_EXISTS", `${folder} exists and is not a folder`, { help: "pass --dir <new folder>" });
|
|
132984
133305
|
}
|
|
132985
133306
|
if (found === "dir") {
|
|
132986
133307
|
const existing = await bindingForPath(deps.auth.home, await realpath11(folder));
|
|
132987
|
-
const sameWorkspace =
|
|
133308
|
+
const sameWorkspace = workspaceFlag2 === void 0 || workspaceFlag2 === existing?.workspace_slug || workspaceFlag2 === existing?.workspace;
|
|
132988
133309
|
const asked = typed.slug === null && sameWorkspace ? { slug: existing?.workspace_slug ?? null, bundleId } : typed;
|
|
132989
133310
|
if (existing && bindsBundle(existing, target3, asked)) {
|
|
132990
133311
|
deps.stdout(render({ checkout: "unchanged", ...bindingView(existing), help: nextSteps(existing.path) }, mode));
|
|
@@ -132998,7 +133319,7 @@ async function checkout(argv2, partial2 = {}) {
|
|
|
132998
133319
|
});
|
|
132999
133320
|
}
|
|
133000
133321
|
await assertStandaloneFolder(folder);
|
|
133001
|
-
const { identity, reader, listed: listed2, workspace, reference, definitionWrites, documentInputBytes } = await connectHostedBundle(typed, target3,
|
|
133322
|
+
const { identity, reader, listed: listed2, workspace, reference, definitionWrites, documentInputBytes } = await connectHostedBundle(typed, target3, workspaceFlag2, deps, resume2);
|
|
133002
133323
|
const canonical2 = await canonicalFolder(folder);
|
|
133003
133324
|
let createdFolder = false;
|
|
133004
133325
|
const placed = /* @__PURE__ */ new Map();
|
|
@@ -133104,6 +133425,7 @@ async function checkout(argv2, partial2 = {}) {
|
|
|
133104
133425
|
{
|
|
133105
133426
|
checkout: "created",
|
|
133106
133427
|
...bindingView(result3.binding),
|
|
133428
|
+
...hostOrigin,
|
|
133107
133429
|
catalog: cataloged,
|
|
133108
133430
|
documents: result3.documents,
|
|
133109
133431
|
root_index: result3.root,
|
|
@@ -134000,11 +134322,12 @@ async function exportCommand(argv2, partial2 = {}) {
|
|
|
134000
134322
|
}
|
|
134001
134323
|
let source;
|
|
134002
134324
|
if (reference) {
|
|
134325
|
+
const named2 = await requireHostedBundleHost(values.host, deps.auth);
|
|
134003
134326
|
source = {
|
|
134004
|
-
target:
|
|
134327
|
+
target: named2.target,
|
|
134005
134328
|
bundleId: reference.bundleId,
|
|
134006
134329
|
slug: reference.slug,
|
|
134007
|
-
workspace: values.workspace ?? null,
|
|
134330
|
+
workspace: workspaceForNamedHost(named2, values.workspace) ?? null,
|
|
134008
134331
|
binding: null
|
|
134009
134332
|
};
|
|
134010
134333
|
} else {
|
|
@@ -134430,7 +134753,10 @@ function gitVersions(board, id, rel, current, okfVersion, now, documentInputByte
|
|
|
134430
134753
|
label: `imported:git/${sha}`,
|
|
134431
134754
|
author: cleanAuthor(author ?? ""),
|
|
134432
134755
|
authoredAt: new Date(when).toISOString(),
|
|
134433
|
-
|
|
134756
|
+
// An imported version never asserts verification or host attribution, as a current document does not.
|
|
134757
|
+
frontmatter: Object.fromEntries(
|
|
134758
|
+
Object.entries(parsed2.frontmatter).filter(([key2]) => !IMPORT_DROPPED_FIELDS.includes(key2))
|
|
134759
|
+
),
|
|
134434
134760
|
body: parsed2.body ?? ""
|
|
134435
134761
|
});
|
|
134436
134762
|
}
|
|
@@ -134493,6 +134819,10 @@ async function planPublish(folder, options) {
|
|
|
134493
134819
|
const blockers = [];
|
|
134494
134820
|
const extras = {};
|
|
134495
134821
|
const documentFiles = [];
|
|
134822
|
+
const provenance2 = {
|
|
134823
|
+
carried: Object.fromEntries(IMPORT_CARRIED_FIELDS.map((field) => [field, 0])),
|
|
134824
|
+
dropped: Object.fromEntries(IMPORT_DROPPED_FIELDS.map((field) => [field, 0]))
|
|
134825
|
+
};
|
|
134496
134826
|
const entries = await walkAll(folder);
|
|
134497
134827
|
let rootIndex = null;
|
|
134498
134828
|
try {
|
|
@@ -134564,7 +134894,7 @@ async function planPublish(folder, options) {
|
|
|
134564
134894
|
}
|
|
134565
134895
|
let request3;
|
|
134566
134896
|
try {
|
|
134567
|
-
request3 = wholeDocumentRequest("publish", { kind: "document.write", target: id, base: null, content: utf83(bytes) }, okfVersion);
|
|
134897
|
+
request3 = wholeDocumentRequest("publish", { kind: "document.write", target: id, base: null, content: utf83(bytes) }, okfVersion, { mode: "import" });
|
|
134568
134898
|
} catch (error51) {
|
|
134569
134899
|
if (error51 instanceof WholeDocumentInputError) {
|
|
134570
134900
|
blockers.push({ path: entry.rel, reason: "not_sendable", message: error51.message });
|
|
@@ -134572,7 +134902,13 @@ async function planPublish(folder, options) {
|
|
|
134572
134902
|
}
|
|
134573
134903
|
throw error51;
|
|
134574
134904
|
}
|
|
134575
|
-
if (request3.kind
|
|
134905
|
+
if (request3.kind !== "create") throw new Error(`'${id}' became a ${request3.kind} request`);
|
|
134906
|
+
if (Buffer.byteLength(JSON.stringify(request3.payload.frontmatter)) > FRONTMATTER_JSON_BYTES) {
|
|
134907
|
+
blockers.push({ path: entry.rel, reason: "too_large", message: `'${id}' has more than the ${FRONTMATTER_JSON_BYTES / 1024} KiB of frontmatter the host stores, counting ${request3.provenance.carried.join(", ")}` });
|
|
134908
|
+
continue;
|
|
134909
|
+
}
|
|
134910
|
+
for (const field of request3.provenance.carried) provenance2.carried[field] = (provenance2.carried[field] ?? 0) + 1;
|
|
134911
|
+
for (const field of request3.provenance.dropped) provenance2.dropped[field] = (provenance2.dropped[field] ?? 0) + 1;
|
|
134576
134912
|
documents.push({ id, frontmatter: request3.payload.frontmatter, body: request3.payload.body ?? "" });
|
|
134577
134913
|
documentFiles.push({ id, rel: entry.rel, text: utf83(bytes) });
|
|
134578
134914
|
}
|
|
@@ -134619,7 +134955,7 @@ async function planPublish(folder, options) {
|
|
|
134619
134955
|
const draft = { documents, reserved, blobs: blobs2, history };
|
|
134620
134956
|
const sendPath = publishPath(draft);
|
|
134621
134957
|
if (sendPath.mode === "staged") blockers.push(...stagedBlockers(draft));
|
|
134622
|
-
return { documents, reserved, blobs: blobs2, history, path: sendPath, skipped, blockers, historyPlan, extras };
|
|
134958
|
+
return { documents, reserved, blobs: blobs2, history, path: sendPath, skipped, blockers, historyPlan, extras, provenance: provenance2 };
|
|
134623
134959
|
}
|
|
134624
134960
|
function publishPath(plan) {
|
|
134625
134961
|
const bounds = PUBLISH_BOUNDS;
|
|
@@ -135159,7 +135495,15 @@ function summary(plan) {
|
|
|
135159
135495
|
reserved_files: plan.reserved.length,
|
|
135160
135496
|
other_files: plan.blobs.length,
|
|
135161
135497
|
sent: plan.path.mode === "one-shot" ? "one request" : `staged: ${plan.path.why}; a list of everything, parts of about 1 MiB, each file, then commits until created (resumable)`,
|
|
135162
|
-
history: { mode: plan.historyPlan.mode, versions: plan.historyPlan.versions, ...plan.historyPlan.skipped > 0 ? { skipped: plan.historyPlan.skipped } : {}, note: plan.historyPlan.note }
|
|
135498
|
+
history: { mode: plan.historyPlan.mode, versions: plan.historyPlan.versions, ...plan.historyPlan.skipped > 0 ? { skipped: plan.historyPlan.skipped } : {}, note: plan.historyPlan.note },
|
|
135499
|
+
provenance: provenanceOf(plan)
|
|
135500
|
+
};
|
|
135501
|
+
}
|
|
135502
|
+
function provenanceOf(plan) {
|
|
135503
|
+
return {
|
|
135504
|
+
carried: plan.provenance.carried,
|
|
135505
|
+
dropped: plan.provenance.dropped,
|
|
135506
|
+
note: "provenance travels as each file states it (a claim, not a verification); verification events and the last-editor attribution stay in the folder, and the host attributes the creation to you"
|
|
135163
135507
|
};
|
|
135164
135508
|
}
|
|
135165
135509
|
function createRefusal(code3, message, context) {
|
|
@@ -135351,15 +135695,17 @@ async function publish(argv2, partial2 = {}) {
|
|
|
135351
135695
|
});
|
|
135352
135696
|
}
|
|
135353
135697
|
const withHistory = values["with-history"] === true;
|
|
135354
|
-
|
|
135698
|
+
let workspaceFlag2 = values.workspace;
|
|
135699
|
+
const yesCommandFor = (host) => commandFragment`${cliInvocation()} publish --to hosted${values.dir !== void 0 ? commandFragment` --dir ${commandToken(canonical2)}` : commandFragment``}${host !== null ? commandFragment` --host ${commandToken(host)}` : commandFragment``}${workspaceFlag2 !== void 0 ? commandFragment` --workspace ${commandToken(workspaceFlag2)}` : commandFragment``} --bundle-id ${commandToken(bundleId)}${values.name !== void 0 ? commandFragment` --name ${commandToken(name)}` : commandFragment``}${withHistory ? commandFragment` --with-history` : commandFragment``} --yes${values.json ? commandFragment` --json` : commandFragment``}`;
|
|
135355
135700
|
let chosen = null;
|
|
135356
135701
|
let ambiguous = null;
|
|
135357
135702
|
try {
|
|
135358
|
-
chosen = await hostedWriteHost(values.host, home2, (host) => String(yesCommandFor(host)));
|
|
135703
|
+
chosen = await hostedWriteHost(values.host, home2, (host) => String(yesCommandFor(host)), values.yes ? deps.auth.fetch : null);
|
|
135359
135704
|
} catch (error51) {
|
|
135360
135705
|
if (values.yes || !(error51 instanceof CliError) || error51.details?.reason !== "ambiguous_host") throw error51;
|
|
135361
135706
|
ambiguous = error51;
|
|
135362
135707
|
}
|
|
135708
|
+
if (chosen) workspaceFlag2 = workspaceForNamedHost(chosen, values.workspace);
|
|
135363
135709
|
const target3 = chosen?.target ?? null;
|
|
135364
135710
|
const planFor = (documentInputBytes) => planPublish(canonical2, withHistory ? { history: true, ...board ? { board } : {}, now: deps.auth.now(), documentInputBytes } : { history: false, documentInputBytes });
|
|
135365
135711
|
let plan = await planFor(CURRENT_HOST_DOCUMENT_INPUT_BYTES);
|
|
@@ -135430,7 +135776,7 @@ async function publish(argv2, partial2 = {}) {
|
|
|
135430
135776
|
const otherWorkspace = `${cliInvocation()} publish --to hosted --host ${commandToken(bindingHostArgument(target3))} --workspace <id> --bundle-id ${commandToken(bundleId)} --yes`;
|
|
135431
135777
|
const { client, identity, workspace } = await connectHostedAccount(
|
|
135432
135778
|
target3,
|
|
135433
|
-
{ workspace:
|
|
135779
|
+
{ workspace: workspaceFlag2, resume: yesCommand, otherWorkspace, deadlineMs: CREATE_DEADLINE_MS },
|
|
135434
135780
|
{ auth: deps.auth, ...deps.fetch ? { fetch: deps.fetch } : {} }
|
|
135435
135781
|
);
|
|
135436
135782
|
if (workspace === null) {
|
|
@@ -135466,7 +135812,8 @@ async function publish(argv2, partial2 = {}) {
|
|
|
135466
135812
|
documents: created.documents ?? plan.documents.length,
|
|
135467
135813
|
reserved_files: created.reserved ?? plan.reserved.length,
|
|
135468
135814
|
other_files: created.blobs ?? plan.blobs.length,
|
|
135469
|
-
history: created.history ?? { imported: plan.history.length, verified: false }
|
|
135815
|
+
history: created.history ?? { imported: plan.history.length, verified: false },
|
|
135816
|
+
provenance: { carried: plan.provenance.carried, dropped: plan.provenance.dropped }
|
|
135470
135817
|
},
|
|
135471
135818
|
folder: canonical2,
|
|
135472
135819
|
home: facts.home,
|
|
@@ -135560,7 +135907,8 @@ async function publish(argv2, partial2 = {}) {
|
|
|
135560
135907
|
documents: created.documents ?? plan.documents.length,
|
|
135561
135908
|
reserved_files: created.reserved ?? plan.reserved.length,
|
|
135562
135909
|
other_files: created.blobs ?? plan.blobs.length,
|
|
135563
|
-
history: created.history ?? { imported: plan.history.length, verified: false }
|
|
135910
|
+
history: created.history ?? { imported: plan.history.length, verified: false },
|
|
135911
|
+
provenance: { carried: plan.provenance.carried, dropped: plan.provenance.dropped }
|
|
135564
135912
|
},
|
|
135565
135913
|
folder: canonical2,
|
|
135566
135914
|
home: "hosted",
|
|
@@ -135629,6 +135977,10 @@ Without --yes, previews only, with no network: what travels (documents, reserved
|
|
|
135629
135977
|
files), what stays (dot-files, links), how it is sent, every bound the host enforces, the history
|
|
135630
135978
|
plan, and what will happen to the folder.
|
|
135631
135979
|
|
|
135980
|
+
Each document's provenance (generated, timestamp, actor, okf_version) travels as its file states
|
|
135981
|
+
it, a claim rather than a verification; verified and superbee_updated_by never travel. The
|
|
135982
|
+
preview and the receipt count both, per field.
|
|
135983
|
+
|
|
135632
135984
|
A bundle within one request's bounds (at most 1,000 documents, 100 other files of 1 MB each,
|
|
135633
135985
|
1,000 earlier versions, 1,500 objects in all, 3 MiB) is sent in one request. A larger one is sent
|
|
135634
135986
|
staged: a list of everything, then parts of about 1 MiB, then each file, then commits until the
|
|
@@ -135739,10 +136091,12 @@ async function accessList(argv2, deps) {
|
|
|
135739
136091
|
return;
|
|
135740
136092
|
}
|
|
135741
136093
|
const typed = typedReference(positionals[0]);
|
|
135742
|
-
const
|
|
136094
|
+
const named = await requireHostedBundleHost(values.host, deps.auth);
|
|
136095
|
+
const target3 = named.target;
|
|
136096
|
+
const workspace = workspaceForNamedHost(named, values.workspace);
|
|
135743
136097
|
const command = (reference) => commandFragment`${cliInvocation()} access list ${commandToken(reference)}${hostFlag(target3)}`;
|
|
135744
|
-
const resume2 = commandFragment`${command(hostedBundleReferenceText(typed))}${workspaceFlag(
|
|
135745
|
-
const reached = await reach(typed, target3,
|
|
136098
|
+
const resume2 = commandFragment`${command(hostedBundleReferenceText(typed))}${workspaceFlag(workspace)}${values.json ? commandFragment` --json` : commandFragment``}`;
|
|
136099
|
+
const reached = await reach(typed, target3, workspace, resume2, deps, command);
|
|
135746
136100
|
const answer2 = await postRoute({ client: reached.client, resume: resume2, reference: reached.reference }, "access-list", { bundleId: reached.bundleId });
|
|
135747
136101
|
if (!answer2.ok) throw accessRefusal(answer2.code, answer2.message, { reference: reached.reference, host: target3, again: resume2 });
|
|
135748
136102
|
const data = answer2.data;
|
|
@@ -135815,8 +136169,10 @@ async function accessChange(action, argv2, deps) {
|
|
|
135815
136169
|
throw usage2(wanted === void 0 ? "grant needs --level read or --level write" : `'${wanted}' is not a level: read or write`);
|
|
135816
136170
|
}
|
|
135817
136171
|
const mode = resolveMode(values);
|
|
135818
|
-
const
|
|
135819
|
-
const
|
|
136172
|
+
const named = await requireHostedBundleHost(values.host, { ...deps.auth, fetch: values.yes ? deps.auth.fetch : null });
|
|
136173
|
+
const target3 = named.target;
|
|
136174
|
+
const workspace = workspaceForNamedHost(named, values.workspace);
|
|
136175
|
+
const command = (reference) => commandFragment`${cliInvocation()} access ${commandToken(action)} ${commandToken(reference)} ${commandToken(person)}${action === "grant" ? commandFragment` --level ${commandToken(wanted)}` : commandFragment``}${hostFlag(target3)}${workspaceFlag(workspace)} --yes`;
|
|
135820
136176
|
const typedText = hostedBundleReferenceText(typed);
|
|
135821
136177
|
const yesCommand = commandFragment`${command(typedText)}${values.json ? commandFragment` --json` : commandFragment``}`;
|
|
135822
136178
|
if (!values.yes) {
|
|
@@ -135829,7 +136185,7 @@ async function accessChange(action, argv2, deps) {
|
|
|
135829
136185
|
person,
|
|
135830
136186
|
...action === "grant" ? { level: wanted } : {},
|
|
135831
136187
|
host: target3.origin,
|
|
135832
|
-
...
|
|
136188
|
+
...workspace !== void 0 ? { workspace } : {},
|
|
135833
136189
|
will: action === "grant" ? `give ${person} ${wanted} access to '${typedText}' (or change their level to ${wanted}); they must already be a member of the workspace (invite them from the Members page in the Superbee app first)` : `take ${person}'s access to '${typedText}' away; they stay a member of the workspace`,
|
|
135834
136190
|
needs: "a workspace admin, granting no more than your own level on the bundle",
|
|
135835
136191
|
network: "none (preview)",
|
|
@@ -135840,7 +136196,7 @@ async function accessChange(action, argv2, deps) {
|
|
|
135840
136196
|
);
|
|
135841
136197
|
return;
|
|
135842
136198
|
}
|
|
135843
|
-
const reached = await reach(typed, target3,
|
|
136199
|
+
const reached = await reach(typed, target3, workspace, yesCommand, deps, (reference) => command(reference));
|
|
135844
136200
|
const route = action === "grant" ? "access-grant" : "access-revoke";
|
|
135845
136201
|
const home2 = deps.auth.home;
|
|
135846
136202
|
const requestId2 = await accessRequestId(home2, target3.origin, reached.reference, person, action === "grant" ? `grant:${wanted}` : "revoke", deps.auth.now());
|