vde-open 0.1.9 → 0.1.11

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.
@@ -1,6 +1,6 @@
1
- import { C as roleAllowed, N as __commonJSMin, P as __toESM, S as isValidLogicalPath, _ as classifyLink, b as encodeLogicalPath, d as analyzeDocument, g as assetTypeOf, u as ParseLimitError, v as classifyReference, x as hasHiddenSegment, y as dirnameOfLogicalPath } from "./html-static-BDV6MgA7.js";
2
- import { $ as literal, A as successEnvelope, B as readParamsSchema, C as VdeError, D as ExitCode, E as isVdeError, F as htmlModeChangeParamsSchema, G as sha256Schema, H as reorderParamsSchema, I as htmlModeSchema, J as watchRuleSchema, K as sourceKindSchema, L as linkOpenParamsSchema, M as closeParamsSchema, N as documentFormatSchema, P as documentIdSchema, Q as boolean, R as listParamsSchema, S as validateAnswers, U as revisionSchema, V as renderGrantParamsSchema, W as searchParamsSchema, X as _enum, Y as LIMITS, Z as array, _ as feedbackWaitParamsSchema, a as uniqueTokens, at as canonicalJson, b as submissionSchema, c as feedbackAckParamsSchema, d as feedbackDraftParamsSchema, et as number, f as feedbackForgetParamsSchema, g as feedbackSubmitParamsSchema, h as feedbackStatusSchema, i as codePointLength, it as ZodError, j as assetRecordSchema, k as errorEnvelope, l as feedbackCancelParamsSchema, m as feedbackListParamsSchema, n as batchesOf, nt as strictObject, o as answersSchema, p as feedbackIdParamsSchema, q as sourceStateSchema, r as partsOf, rt as string, s as cancellationSchema, tt as record, u as feedbackCreateParamsSchema, v as questionnaireSchema, w as exitCodeForError, x as utf8Length, y as requestIdSchema, z as openParamsSchema } from "./search-index-B7DqaWh6.js";
3
- import { n as scanReferences, r as extractTitle } from "./render-BX3arVZj.js";
1
+ import { C as roleAllowed, N as __commonJSMin, P as __toESM, S as isValidLogicalPath, _ as classifyLink, b as encodeLogicalPath, d as analyzeDocument, g as assetTypeOf, u as ParseLimitError, v as classifyReference, x as hasHiddenSegment, y as dirnameOfLogicalPath } from "./html-static-C_wwQAJx.js";
2
+ import { $ as literal, A as successEnvelope, B as readParamsSchema, C as VdeError, D as ExitCode, E as isVdeError, F as htmlModeChangeParamsSchema, G as sha256Schema, H as reorderParamsSchema, I as htmlModeSchema, J as watchRuleSchema, K as sourceKindSchema, L as linkOpenParamsSchema, M as closeParamsSchema, N as documentFormatSchema, P as documentIdSchema, Q as boolean, R as listParamsSchema, S as validateAnswers, U as revisionSchema, V as renderGrantParamsSchema, W as searchParamsSchema, X as _enum, Y as LIMITS, Z as array, _ as feedbackWaitParamsSchema, a as uniqueTokens, at as canonicalJson, b as submissionSchema, c as feedbackAckParamsSchema, d as feedbackDraftParamsSchema, et as number, f as feedbackForgetParamsSchema, g as feedbackSubmitParamsSchema, h as feedbackStatusSchema, i as codePointLength, it as ZodError, j as assetRecordSchema, k as errorEnvelope, l as feedbackCancelParamsSchema, m as feedbackListParamsSchema, n as batchesOf, nt as strictObject, o as answersSchema, p as feedbackIdParamsSchema, q as sourceStateSchema, r as partsOf, rt as string, s as cancellationSchema, tt as record, u as feedbackCreateParamsSchema, v as questionnaireSchema, w as exitCodeForError, x as utf8Length, y as requestIdSchema, z as openParamsSchema } from "./search-index-BoGly_y4.js";
3
+ import { n as scanReferences, r as extractTitle } from "./render-BJa4uW0H.js";
4
4
  import { n as measureHeap, t as collectGarbage } from "./heap-C3qHm7SE.js";
5
5
  import { accessSync, constants, existsSync, stat, statSync, unwatchFile, watch, watchFile } from "node:fs";
6
6
  import { appendFile, chmod, link, lstat, mkdir, mkdtemp, open, readFile, readdir, readlink, realpath, rename, rm, rmdir, stat as stat$1, writeFile } from "node:fs/promises";
@@ -154,7 +154,7 @@ function parseStrictJson(text) {
154
154
  }
155
155
  //#endregion
156
156
  //#region package.json
157
- var version = "0.1.9";
157
+ var version = "0.1.11";
158
158
  //#endregion
159
159
  //#region src/documents/cursor.ts
160
160
  function invalidCursor(reason) {
@@ -283,7 +283,7 @@ function decodeSource(bytes, label) {
283
283
  throw invalid(label, "invalid-utf8");
284
284
  }
285
285
  }
286
- async function readSourceFile(path) {
286
+ async function readSourceFile(path, format = "markdown") {
287
287
  let canonicalPath;
288
288
  try {
289
289
  canonicalPath = await realpath(path);
@@ -317,7 +317,7 @@ async function readSourceFile(path) {
317
317
  return {
318
318
  canonicalPath,
319
319
  bytes,
320
- text: decodeSource(bytes, path),
320
+ text: format === "image" ? "" : decodeSource(bytes, path),
321
321
  signature: statSignature(after)
322
322
  };
323
323
  } finally {
@@ -3387,7 +3387,10 @@ const FORMAT_BY_EXTENSION = /* @__PURE__ */ new Map([
3387
3387
  [".htm", "html"]
3388
3388
  ]);
3389
3389
  function formatOfPath(path) {
3390
- return FORMAT_BY_EXTENSION.get(extname(path).toLowerCase()) ?? null;
3390
+ const document = FORMAT_BY_EXTENSION.get(extname(path).toLowerCase());
3391
+ if (document) return document;
3392
+ const asset = assetTypeOf(path);
3393
+ return asset?.role === "image" || asset?.role === "svg" ? "image" : null;
3391
3394
  }
3392
3395
  function compareText(a, b) {
3393
3396
  return a < b ? -1 : a > b ? 1 : 0;
@@ -4086,6 +4089,7 @@ const ANALYSIS_CACHE_BYTES = 33554432;
4086
4089
  const MISSING_RETRY_MS = 1e3;
4087
4090
  const MISSING_RETRY_INTERVAL_MS = 100;
4088
4091
  function profileOf(format) {
4092
+ if (format === "image") return "image-v1";
4089
4093
  return format === "markdown" ? MARKDOWN_PARSER_PROFILE : HTML_STATIC_PARSER_PROFILE;
4090
4094
  }
4091
4095
  function toSummary(record, order, searchState = "excluded", pendingRequestIds = [], interactiveAllowed = false, repository = null) {
@@ -4290,6 +4294,20 @@ var DocumentService = class {
4290
4294
  });
4291
4295
  documentLogicalPath = fromRoot.split(sep).join("/");
4292
4296
  }
4297
+ if (source.format === "image") {
4298
+ const type = assetTypeOf(documentLogicalPath);
4299
+ if (type?.role !== "image" && type?.role !== "svg") throw new VdeError("E_UNSUPPORTED_FORMAT", "The file extension is not an image format.");
4300
+ if (extraAssets.length > 0) throw new VdeError("E_INVALID_ARGUMENT", "--asset is not available for standalone images.");
4301
+ return {
4302
+ ...source,
4303
+ assetsRoot,
4304
+ extraAssets: [],
4305
+ documentLogicalPath,
4306
+ assets: [],
4307
+ trackedFiles: [],
4308
+ assetScanFailed: false
4309
+ };
4310
+ }
4293
4311
  let assetScanFailed = false;
4294
4312
  const manifest = await buildManifest({
4295
4313
  format: source.format,
@@ -4598,7 +4616,7 @@ var DocumentService = class {
4598
4616
  for (const [canonicalPath, { candidate, format }] of resolved.unique) {
4599
4617
  let loaded;
4600
4618
  try {
4601
- loaded = await this.#readSource(candidate.absolutePath);
4619
+ loaded = await this.#readSource(candidate.absolutePath, format);
4602
4620
  } catch (error) {
4603
4621
  if (!(error instanceof VdeError)) throw error;
4604
4622
  problems.push({
@@ -4699,7 +4717,7 @@ var DocumentService = class {
4699
4717
  sha256
4700
4718
  }))
4701
4719
  });
4702
- const title = options.title ?? extractTitle(item.text, item.format) ?? item.fallbackTitle;
4720
+ const title = options.title ?? (item.format === "image" ? null : extractTitle(item.text, item.format)) ?? item.fallbackTitle;
4703
4721
  const revisionRecord = {
4704
4722
  revision,
4705
4723
  format: item.format,
@@ -4869,6 +4887,10 @@ var DocumentService = class {
4869
4887
  sectionId = payload["sectionId"];
4870
4888
  }
4871
4889
  const entry = this.#requireRevision(record, revision);
4890
+ if (entry.format === "image") throw new VdeError("E_UNSUPPORTED_FORMAT", "Images have no text source, outline, or sections.", {
4891
+ documentId: record.documentId,
4892
+ format: "image"
4893
+ });
4872
4894
  if (mode === "outline") return this.#readOutline(record, entry, params.maxBytes, offset ?? 0);
4873
4895
  if (mode === "section") return this.#readSection(record, entry, sectionId ?? "", params.maxBytes, offset ?? 0);
4874
4896
  const source = await this.#store.readBlob(entry.sourceSha256);
@@ -5245,7 +5267,12 @@ var DocumentService = class {
5245
5267
  let failure = "error";
5246
5268
  const deadline = Date.now() + MISSING_RETRY_MS;
5247
5269
  for (;;) try {
5248
- loaded = await this.#readSource(canonicalPath);
5270
+ const format = this.#store.payload.documents[documentId]?.format;
5271
+ if (format === void 0) return {
5272
+ changed: false,
5273
+ signature: null
5274
+ };
5275
+ loaded = await this.#readSource(canonicalPath, format);
5249
5276
  break;
5250
5277
  } catch (error) {
5251
5278
  if (!(error instanceof VdeError)) throw error;
@@ -5362,7 +5389,7 @@ var DocumentService = class {
5362
5389
  if (isOpenPath(before, path) || rule.suppressedPaths.includes(path)) continue;
5363
5390
  let loaded;
5364
5391
  try {
5365
- loaded = await this.#readSource(path);
5392
+ loaded = await this.#readSource(path, format);
5366
5393
  } catch (error) {
5367
5394
  if (error instanceof VdeError) continue;
5368
5395
  throw error;
@@ -5825,6 +5852,7 @@ function createPdfService(options) {
5825
5852
  const run = async (documentId, revision, signal) => {
5826
5853
  const started = Date.now();
5827
5854
  const { record, entry } = documents.describeRevision(documentId, revision);
5855
+ if (entry.format === "image") throw new VdeError("E_UNSUPPORTED_FORMAT", "PDF export is available for Markdown and HTML.");
5828
5856
  const source = (await store.readBlob(entry.sourceSha256)).toString("utf8");
5829
5857
  const slot = randomBytes(16).toString("hex");
5830
5858
  let assets = entry.assets.filter((asset) => asset.role === "image" || asset.role === "svg");
@@ -6900,12 +6928,9 @@ function decodeUtf8(bytes) {
6900
6928
  }
6901
6929
  }
6902
6930
  function createRenderService(options) {
6903
- const { store, documents, sessions, parse } = options;
6931
+ const { store, documents, parse } = options;
6904
6932
  const grants = /* @__PURE__ */ new Map();
6905
6933
  const snapshots = /* @__PURE__ */ new Map();
6906
- sessions.onAnyRevoke((sessionId) => {
6907
- for (const [key, grant] of grants) if (grant.sessionId === sessionId) grants.delete(key);
6908
- });
6909
6934
  const snapshotOf = async (documentId, revision, mode = "static", withSdk = false) => {
6910
6935
  const { record, entry } = documents.describeRevision(documentId, revision);
6911
6936
  const cacheKey = `${entry.revision}\n${entry.documentLogicalPath}\n${mode}\n${String(withSdk)}`;
@@ -6919,6 +6944,28 @@ function createRenderService(options) {
6919
6944
  snapshot: cached
6920
6945
  };
6921
6946
  }
6947
+ if (entry.format === "image") {
6948
+ const type = assetTypeOf(entry.documentLogicalPath);
6949
+ if (type?.role !== "image" && type?.role !== "svg") throw new VdeError("E_UNSUPPORTED_FORMAT", "The file extension is not an image format.");
6950
+ return {
6951
+ record,
6952
+ entry,
6953
+ snapshot: {
6954
+ format: "image",
6955
+ documentLogicalPath: entry.documentLogicalPath,
6956
+ hasDocument: true,
6957
+ files: /* @__PURE__ */ new Map([[entry.documentLogicalPath, {
6958
+ kind: "blob",
6959
+ sha256: entry.sourceSha256,
6960
+ ...type
6961
+ }]]),
6962
+ assets: [],
6963
+ links: [],
6964
+ diagnostics: [],
6965
+ headingTargets: []
6966
+ }
6967
+ };
6968
+ }
6922
6969
  const source = (await store.readBlob(entry.sourceSha256)).toString("utf8");
6923
6970
  const stylesheets = [];
6924
6971
  for (const asset of entry.assets) {
@@ -7004,14 +7051,13 @@ function createRenderService(options) {
7004
7051
  const liveGrant = (key) => {
7005
7052
  const grant = grants.get(key);
7006
7053
  if (!grant) return null;
7007
- const record = documents.state.documents[grant.documentId];
7008
- if (!sessions.isActiveId(grant.sessionId) || !record?.isOpen || documents.openEpoch(grant.documentId) !== grant.openEpoch || grant.mode === "interactive" && documents.interactiveGeneration(grant.documentId) !== grant.permission) {
7054
+ if (!documents.state.documents[grant.documentId]?.isOpen || documents.openEpoch(grant.documentId) !== grant.openEpoch || grant.mode === "interactive" && documents.interactiveGeneration(grant.documentId) !== grant.permission) {
7009
7055
  grants.delete(key);
7010
7056
  return null;
7011
7057
  }
7012
7058
  return grant;
7013
7059
  };
7014
- const issue = async (sessionId, params, context) => {
7060
+ const issue = async (params, context) => {
7015
7061
  const interactive = params.mode === "interactive";
7016
7062
  const permissionOf = () => {
7017
7063
  if (!interactive) return null;
@@ -7054,7 +7100,6 @@ function createRenderService(options) {
7054
7100
  }
7055
7101
  const key = randomBytes(32).toString("base64url");
7056
7102
  grants.set(key, {
7057
- sessionId,
7058
7103
  documentId: record.documentId,
7059
7104
  openEpoch,
7060
7105
  revision: entry.revision,
@@ -7064,8 +7109,11 @@ function createRenderService(options) {
7064
7109
  bridge,
7065
7110
  missing: /* @__PURE__ */ new Set()
7066
7111
  });
7067
- const owned = [...grants].filter(([, grant]) => grant.sessionId === sessionId);
7068
- for (const [oldKey] of owned.slice(0, Math.max(0, owned.length - LIMITS.renderGrantsPerSession))) grants.delete(oldKey);
7112
+ while (grants.size > LIMITS.renderGrants) {
7113
+ const oldest = grants.keys().next().value;
7114
+ if (oldest === void 0) break;
7115
+ grants.delete(oldest);
7116
+ }
7069
7117
  const filesBaseUrl = `${options.previewOrigin()}/r/${key}/files/`;
7070
7118
  return {
7071
7119
  grant: key,
@@ -7100,14 +7148,14 @@ function createRenderService(options) {
7100
7148
  snapshots: snapshots.size
7101
7149
  };
7102
7150
  },
7103
- async createGrant(sessionId, rawParams, context) {
7151
+ async createGrant(rawParams, context) {
7104
7152
  const params = renderGrantParamsSchema.parse(rawParams);
7105
- return issue(sessionId, {
7153
+ return issue({
7106
7154
  ...params,
7107
7155
  requestId: null
7108
7156
  }, context);
7109
7157
  },
7110
- async createGrantForRequest(sessionId, requestId, context) {
7158
+ async createGrantForRequest(requestId, context) {
7111
7159
  const request = Object.hasOwn(store.payload.feedbackRequests, requestId) ? store.payload.feedbackRequests[requestId] : void 0;
7112
7160
  if (!request) throw new VdeError("E_REQUEST_NOT_FOUND", "The question was not found.", { requestId });
7113
7161
  if (request.status !== "pending") throw new VdeError("E_REQUEST_NOT_PENDING", "The question is not pending.", {
@@ -7115,16 +7163,16 @@ function createRenderService(options) {
7115
7163
  status: request.status
7116
7164
  });
7117
7165
  const interactive = request.renderMode === "interactive" && documents.interactiveAllowed(request.documentId);
7118
- return issue(sessionId, {
7166
+ return issue({
7119
7167
  documentId: request.documentId,
7120
7168
  revision: request.revision,
7121
7169
  mode: interactive ? "interactive" : "static",
7122
7170
  requestId: interactive ? request.requestId : null
7123
7171
  }, context);
7124
7172
  },
7125
- bridgeOf(sessionId, key) {
7173
+ bridgeOf(key) {
7126
7174
  const grant = liveGrant(key);
7127
- if (!grant?.bridge || grant.sessionId !== sessionId) return null;
7175
+ if (!grant?.bridge) return null;
7128
7176
  if (store.payload.feedbackRequests[grant.bridge.requestId]?.status !== "pending") return null;
7129
7177
  return {
7130
7178
  requestId: grant.bridge.requestId,
@@ -7132,9 +7180,9 @@ function createRenderService(options) {
7132
7180
  revision: grant.revision
7133
7181
  };
7134
7182
  },
7135
- release(sessionId, keys) {
7183
+ release(keys) {
7136
7184
  let released = 0;
7137
- for (const key of keys) if (grants.get(key)?.sessionId === sessionId && grants.delete(key)) released += 1;
7185
+ for (const key of keys) if (grants.delete(key)) released += 1;
7138
7186
  return released;
7139
7187
  },
7140
7188
  async resolve(key, logicalPath) {
@@ -7162,9 +7210,9 @@ function createRenderService(options) {
7162
7210
  mode: grant.mode
7163
7211
  };
7164
7212
  },
7165
- missingOf(sessionId, key) {
7213
+ missingOf(key) {
7166
7214
  const grant = liveGrant(key);
7167
- if (!grant || grant.sessionId !== sessionId) return [];
7215
+ if (!grant) return [];
7168
7216
  return [...grant.missing];
7169
7217
  },
7170
7218
  pruneClosed() {
@@ -7471,7 +7519,7 @@ function createSearchService(options) {
7471
7519
  if (indexed.get(documentId) === attempt) indexed.delete(documentId);
7472
7520
  };
7473
7521
  try {
7474
- const text = (await store.readBlob(entry.sourceSha256)).toString("utf8");
7522
+ const text = entry.format === "image" ? "" : (await store.readBlob(entry.sourceSha256)).toString("utf8");
7475
7523
  const { sections } = await analyzeOnce(entry.format, text);
7476
7524
  if (!current()) {
7477
7525
  await giveUp(false);
@@ -11016,7 +11064,7 @@ function createEventQueue(options) {
11016
11064
  if (pending === 0) progressAt = now();
11017
11065
  pending += 1;
11018
11066
  writes = writes.then(() => {
11019
- if (stopped || !options.beforeWrite()) return void 0;
11067
+ if (stopped) return void 0;
11020
11068
  return write();
11021
11069
  }).then(() => {
11022
11070
  progressAt = now();
@@ -11216,27 +11264,9 @@ async function startManagementServer(deps, options = {}) {
11216
11264
  if (Number(c.req.header("content-length") ?? "0") > 0 && !(c.req.header("content-type") ?? "").startsWith("application/json")) return fail(c, new VdeError("E_INVALID_ARGUMENT", "The body must be sent as JSON."));
11217
11265
  }
11218
11266
  if (deps.isStopping()) return fail(c, new VdeError("E_DAEMON_STOPPING", "The daemon is stopping."));
11219
- if (c.req.path === `${API_PREFIX}/sessions/bootstrap` && method === "POST") return next();
11220
- const authorization = c.req.header("authorization") ?? "";
11221
- const token = authorization.startsWith("Bearer ") ? authorization.slice(7) : "";
11222
- if (token === "" || !deps.sessions.authenticate(token)) return fail(c, new VdeError("E_UNAUTHORIZED", "Authentication is required. Open again from the CLI."));
11223
- c.set("token", token);
11224
11267
  return next();
11225
11268
  });
11226
11269
  const api = new Hono();
11227
- api.post("/sessions/bootstrap", async (c) => {
11228
- const body = strictObject({ ticket: string().min(1).max(256) }).parse(await c.req.json());
11229
- const token = deps.sessions.exchange(body.ticket);
11230
- if (!token) return fail(c, new VdeError("E_UNAUTHORIZED", "This URL has already been used or has expired."));
11231
- return c.json(successEnvelope({
11232
- token,
11233
- idleTimeoutSeconds: LIMITS.sessionIdleMs / 1e3
11234
- }, { command: "sessions.bootstrap" }));
11235
- });
11236
- api.delete("/session", (c) => {
11237
- deps.sessions.revoke(c.get("token"));
11238
- return c.json(successEnvelope({ revoked: true }, { command: "session.delete" }));
11239
- });
11240
11270
  api.get("/status", (c) => {
11241
11271
  const state = deps.documents.state;
11242
11272
  const status = {
@@ -11322,28 +11352,27 @@ async function startManagementServer(deps, options = {}) {
11322
11352
  });
11323
11353
  api.post("/feedback/:id/render-grants", async (c) => {
11324
11354
  const requestId = requestIdSchema.parse(c.req.param("id"));
11325
- const result = await deps.render.createGrantForRequest(deps.sessions.idOf(c.get("token")), requestId, { origin: c.req.header("origin") ?? origin });
11355
+ const result = await deps.render.createGrantForRequest(requestId, { origin: c.req.header("origin") ?? origin });
11326
11356
  return c.json(successEnvelope(result, {
11327
11357
  command: "feedback.render-grant",
11328
11358
  catalogVersion: deps.documents.state.catalogVersion
11329
11359
  }));
11330
11360
  });
11331
- const bridgeOf = (token, grant) => {
11332
- const found = typeof grant === "string" ? deps.render.bridgeOf(deps.sessions.idOf(token), grant) : null;
11361
+ const bridgeOf = (grant) => {
11362
+ const found = typeof grant === "string" ? deps.render.bridgeOf(grant) : null;
11333
11363
  if (!found) throw new VdeError("E_RENDER_GRANT_INVALID", "The render grant has expired, so draft answers from the HTML are not accepted.");
11334
11364
  return found;
11335
11365
  };
11336
11366
  api.post("/render-grants/bridge/ready", async (c) => {
11337
11367
  const body = strictObject({ grant: string().min(1).max(128) }).parse(await c.req.json());
11338
- const { requestId } = bridgeOf(c.get("token"), body.grant);
11368
+ const { requestId } = bridgeOf(body.grant);
11339
11369
  return ok(c, "render-grants.bridge-ready", deps.feedback.getForUi(requestId));
11340
11370
  });
11341
11371
  api.put("/render-grants/bridge/draft", async (c) => {
11342
11372
  const { grant, ...draft } = parseAnswersBody(await c.req.text());
11343
- const token = c.get("token");
11344
- const { requestId } = bridgeOf(token, grant);
11373
+ const { requestId } = bridgeOf(grant);
11345
11374
  return ok(c, "render-grants.bridge-draft", await deps.feedback.updateDraft(requestId, draft, { authorize: () => {
11346
- if (bridgeOf(token, grant).requestId !== requestId) throw new VdeError("E_RENDER_GRANT_INVALID", "The render grant has changed.");
11375
+ if (bridgeOf(grant).requestId !== requestId) throw new VdeError("E_RENDER_GRANT_INVALID", "The render grant has changed.");
11347
11376
  } }));
11348
11377
  });
11349
11378
  api.post("/feedback/:id/submit", async (c) => ok(c, "feedback.submit", await deps.feedback.submit(requestIdSchema.parse(c.req.param("id")), await c.req.json())));
@@ -11356,7 +11385,7 @@ async function startManagementServer(deps, options = {}) {
11356
11385
  revision: string().optional(),
11357
11386
  mode: string().optional()
11358
11387
  }).parse(await c.req.json());
11359
- const result = await deps.render.createGrant(deps.sessions.idOf(c.get("token")), {
11388
+ const result = await deps.render.createGrant({
11360
11389
  documentId: c.req.param("id"),
11361
11390
  ...body
11362
11391
  }, { origin: c.req.header("origin") ?? origin });
@@ -11367,7 +11396,7 @@ async function startManagementServer(deps, options = {}) {
11367
11396
  });
11368
11397
  api.post("/render-grants/missing", async (c) => {
11369
11398
  const body = strictObject({ grant: string().min(1).max(128) }).parse(await c.req.json());
11370
- const missing = deps.render.missingOf(deps.sessions.idOf(c.get("token")), body.grant);
11399
+ const missing = deps.render.missingOf(body.grant);
11371
11400
  return c.json(successEnvelope({ missing }, { command: "render-grants.missing" }));
11372
11401
  });
11373
11402
  api.post("/documents/:id/html-mode", async (c) => {
@@ -11379,7 +11408,7 @@ async function startManagementServer(deps, options = {}) {
11379
11408
  });
11380
11409
  api.post("/render-grants/release", async (c) => {
11381
11410
  const body = strictObject({ grants: array(string().min(1).max(128)).max(256) }).parse(await c.req.json());
11382
- const released = deps.render.release(deps.sessions.idOf(c.get("token")), body.grants);
11411
+ const released = deps.render.release(body.grants);
11383
11412
  return c.json(successEnvelope({ released }, { command: "render-grants.release" }));
11384
11413
  });
11385
11414
  api.post("/documents/:id/links/:linkId/open", async (c) => {
@@ -11408,7 +11437,6 @@ async function startManagementServer(deps, options = {}) {
11408
11437
  closed = true;
11409
11438
  wake();
11410
11439
  };
11411
- const token = c.get("token");
11412
11440
  const queue = createEventQueue({
11413
11441
  writeEvent: (event) => stream.writeSSE({
11414
11442
  event: event.type,
@@ -11416,11 +11444,6 @@ async function startManagementServer(deps, options = {}) {
11416
11444
  data: JSON.stringify(event)
11417
11445
  }),
11418
11446
  writeHeartbeat: () => stream.write(": heartbeat\n\n"),
11419
- beforeWrite: () => {
11420
- if (deps.sessions.isActive(token)) return true;
11421
- drop();
11422
- return false;
11423
- },
11424
11447
  onError: finish
11425
11448
  });
11426
11449
  const drop = () => {
@@ -11431,7 +11454,6 @@ async function startManagementServer(deps, options = {}) {
11431
11454
  };
11432
11455
  streams.set(finish, queue);
11433
11456
  stream.onAbort(finish);
11434
- const stopWatchingSession = deps.sessions.onRevoke(token, drop);
11435
11457
  const send = (event) => {
11436
11458
  if (!closed) queue.send(event);
11437
11459
  };
@@ -11443,10 +11465,6 @@ async function startManagementServer(deps, options = {}) {
11443
11465
  });
11444
11466
  const unsubscribe = deps.events.subscribe(send);
11445
11467
  const heartbeat = setInterval(() => {
11446
- if (!deps.sessions.isActive(token)) {
11447
- drop();
11448
- return;
11449
- }
11450
11468
  if (queue.stalledFor() >= (deps.stallMs ?? LIMITS.sseStallMs)) {
11451
11469
  drop();
11452
11470
  return;
@@ -11457,7 +11475,6 @@ async function startManagementServer(deps, options = {}) {
11457
11475
  await done;
11458
11476
  } finally {
11459
11477
  clearInterval(heartbeat);
11460
- stopWatchingSession();
11461
11478
  unsubscribe();
11462
11479
  await queue.settled();
11463
11480
  streams.delete(finish);
@@ -11864,99 +11881,6 @@ async function startIpcServer(options) {
11864
11881
  };
11865
11882
  }
11866
11883
  //#endregion
11867
- //#region src/server/session-service.ts
11868
- function digest(secret) {
11869
- return createHash("sha256").update(secret).digest("hex");
11870
- }
11871
- function newSecret() {
11872
- return randomBytes(32).toString("base64url");
11873
- }
11874
- function createSessionService(now = Date.now) {
11875
- const tickets = /* @__PURE__ */ new Map();
11876
- const sessions = /* @__PURE__ */ new Map();
11877
- const revokeListeners = /* @__PURE__ */ new Map();
11878
- const anyRevokeListeners = /* @__PURE__ */ new Set();
11879
- const drop = (key) => {
11880
- if (!sessions.delete(key)) return;
11881
- const listeners = revokeListeners.get(key);
11882
- revokeListeners.delete(key);
11883
- if (listeners) for (const listener of listeners) listener();
11884
- for (const listener of anyRevokeListeners) listener(key);
11885
- };
11886
- const isActiveKey = (key) => {
11887
- const lastUsedAt = sessions.get(key);
11888
- if (lastUsedAt === void 0) return false;
11889
- if (lastUsedAt + LIMITS.sessionIdleMs < now()) {
11890
- drop(key);
11891
- return false;
11892
- }
11893
- return true;
11894
- };
11895
- const sweep = () => {
11896
- const current = now();
11897
- for (const [key, expiresAt] of tickets) if (expiresAt < current) tickets.delete(key);
11898
- for (const [key, lastUsedAt] of sessions) if (lastUsedAt + LIMITS.sessionIdleMs < current) drop(key);
11899
- };
11900
- return {
11901
- retainedCounts() {
11902
- let listeners = 0;
11903
- for (const set of revokeListeners.values()) listeners += set.size;
11904
- return {
11905
- tickets: tickets.size,
11906
- sessions: sessions.size,
11907
- revokeListeners: listeners,
11908
- anyRevokeListeners: anyRevokeListeners.size
11909
- };
11910
- },
11911
- createBootstrapTicket() {
11912
- sweep();
11913
- const ticket = newSecret();
11914
- tickets.set(digest(ticket), now() + LIMITS.bootstrapTicketTtlMs);
11915
- return ticket;
11916
- },
11917
- exchange(ticket) {
11918
- sweep();
11919
- const key = digest(ticket);
11920
- const expiresAt = tickets.get(key);
11921
- tickets.delete(key);
11922
- if (expiresAt === void 0 || expiresAt < now()) return null;
11923
- const token = newSecret();
11924
- sessions.set(digest(token), now());
11925
- return token;
11926
- },
11927
- authenticate(token) {
11928
- const key = digest(token);
11929
- const lastUsedAt = sessions.get(key);
11930
- if (lastUsedAt === void 0) return false;
11931
- if (lastUsedAt + LIMITS.sessionIdleMs < now()) {
11932
- drop(key);
11933
- return false;
11934
- }
11935
- sessions.set(key, now());
11936
- return true;
11937
- },
11938
- isActive: (token) => isActiveKey(digest(token)),
11939
- idOf: digest,
11940
- isActiveId: isActiveKey,
11941
- onAnyRevoke(listener) {
11942
- anyRevokeListeners.add(listener);
11943
- },
11944
- revoke(token) {
11945
- drop(digest(token));
11946
- },
11947
- onRevoke(token, listener) {
11948
- const key = digest(token);
11949
- const listeners = revokeListeners.get(key) ?? /* @__PURE__ */ new Set();
11950
- revokeListeners.set(key, listeners);
11951
- listeners.add(listener);
11952
- return () => {
11953
- listeners.delete(listener);
11954
- if (listeners.size === 0 && revokeListeners.get(key) === listeners) revokeListeners.delete(key);
11955
- };
11956
- }
11957
- };
11958
- }
11959
- //#endregion
11960
11884
  //#region ../../node_modules/.pnpm/readdirp@5.1.1/node_modules/readdirp/index.js
11961
11885
  const EntryTypes = {
11962
11886
  FILE_TYPE: "files",
@@ -14342,7 +14266,6 @@ async function startDaemon(options) {
14342
14266
  emit
14343
14267
  });
14344
14268
  const answering = feedback;
14345
- const sessions = createSessionService();
14346
14269
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
14347
14270
  const devOrigin = isSourceRun ? environment.env["VDE_OPEN_DEV_UI_ORIGIN"] ?? null : null;
14348
14271
  let managementOrigin = null;
@@ -14350,7 +14273,6 @@ async function startDaemon(options) {
14350
14273
  const render = createRenderService({
14351
14274
  store: openedStore,
14352
14275
  documents,
14353
- sessions,
14354
14276
  parse: parser,
14355
14277
  previewOrigin: () => previewOrigin,
14356
14278
  onMissing: (documentId) => emit({
@@ -14379,7 +14301,6 @@ async function startDaemon(options) {
14379
14301
  daemonId,
14380
14302
  version,
14381
14303
  documents,
14382
- sessions,
14383
14304
  events,
14384
14305
  render,
14385
14306
  search: searching,
@@ -14441,8 +14362,7 @@ async function startDaemon(options) {
14441
14362
  documents: documents.retainedCounts(),
14442
14363
  search: search?.retainedCounts() ?? {},
14443
14364
  render: render.retainedCounts(),
14444
- feedback: answering.retainedCounts(),
14445
- sessions: sessions.retainedCounts()
14365
+ feedback: answering.retainedCounts()
14446
14366
  },
14447
14367
  workers,
14448
14368
  activeResources,
@@ -14486,11 +14406,7 @@ async function startDaemon(options) {
14486
14406
  const result = await documents.removeWatchRule(params);
14487
14407
  watching.sync();
14488
14408
  return result;
14489
- },
14490
- "ui.bootstrap": () => ({ data: {
14491
- bootstrapUrl: `${uiUrl}#bootstrap=${sessions.createBootstrapTicket()}`,
14492
- uiUrl
14493
- } })
14409
+ }
14494
14410
  };
14495
14411
  ipc = await startIpcServer({
14496
14412
  socketPath: location.socketPath,
@@ -1,4 +1,4 @@
1
- import { A as escapeAttr, D as defaultTreeAdapter, E as serialize, M as footnoteReferenceId, O as NS, T as parseFragment, c as renderedLinkOf, h as parseMarkdownDocument, i as transformStaticHtml, j as escapeHtml$2, k as parseMarkdown, l as MARKDOWN_PARSE_OPTIONS, n as resolveAssetUrl, o as transformCss, s as localImagePath, t as DiagnosticLog, w as parse, y as dirnameOfLogicalPath } from "./html-static-BDV6MgA7.js";
1
+ import { A as escapeAttr, D as defaultTreeAdapter, E as serialize, M as footnoteReferenceId, O as NS, T as parseFragment, c as renderedLinkOf, h as parseMarkdownDocument, i as transformStaticHtml, j as escapeHtml$2, k as parseMarkdown, l as MARKDOWN_PARSE_OPTIONS, n as resolveAssetUrl, o as transformCss, s as localImagePath, t as DiagnosticLog, w as parse, y as dirnameOfLogicalPath } from "./html-static-C_wwQAJx.js";
2
2
  //#region ../../node_modules/.pnpm/@tanstack+markdown@1.0.0_react@19.3.0/node_modules/@tanstack/markdown/dist/html.js
3
3
  function renderHtml(input, options = {}) {
4
4
  return (typeof input === "string" ? parseMarkdown(input, options) : input).children.map((node) => renderBlock(node, options)).join("\n");
@@ -1,4 +1,4 @@
1
- import { _ as classifyLink, a as scanCssReferences, f as assertWithinLimits, i as transformStaticHtml, k as parseMarkdown, l as MARKDOWN_PARSE_OPTIONS, m as markdownUrlTransform, n as resolveAssetUrl, o as transformCss, p as inlineText$1, r as scanHtmlReferences, t as DiagnosticLog, w as parse, y as dirnameOfLogicalPath } from "./html-static-BDV6MgA7.js";
1
+ import { _ as classifyLink, a as scanCssReferences, f as assertWithinLimits, i as transformStaticHtml, k as parseMarkdown, l as MARKDOWN_PARSE_OPTIONS, m as markdownUrlTransform, n as resolveAssetUrl, o as transformCss, p as inlineText$1, r as scanHtmlReferences, t as DiagnosticLog, w as parse, y as dirnameOfLogicalPath } from "./html-static-C_wwQAJx.js";
2
2
  //#region ../../packages/document/src/title.ts
3
3
  const TITLE_SCAN_CHARS = 65536;
4
4
  const MAX_TITLE_LENGTH = 160;
@@ -5601,8 +5601,6 @@ const LIMITS = {
5601
5601
  printRenderTimeoutMs: 1e4,
5602
5602
  pdfExportTimeoutMs: 6e4,
5603
5603
  watchDebounceMs: 200,
5604
- bootstrapTicketTtlMs: 6e4,
5605
- sessionIdleMs: 432e5,
5606
5604
  sseHeartbeatMs: 15e3,
5607
5605
  ssePendingEvents: 256,
5608
5606
  sseStallMs: 6e4,
@@ -5610,7 +5608,7 @@ const LIMITS = {
5610
5608
  documentAssetBytes: 100 * MiB,
5611
5609
  documentAssets: 500,
5612
5610
  cssReferenceDepth: 8,
5613
- renderGrantsPerSession: 64,
5611
+ renderGrants: 64,
5614
5612
  searchLimitDefault: 5,
5615
5613
  searchLimitMax: 50,
5616
5614
  searchQueryCodePoints: 512,
@@ -5634,7 +5632,11 @@ const LIMITS = {
5634
5632
  const documentIdSchema = string().regex(/^doc_[0-9a-f-]{36}$/);
5635
5633
  const revisionSchema = string().regex(/^rev_[0-9a-f]{64}$/);
5636
5634
  const sha256Schema = string().regex(/^[0-9a-f]{64}$/);
5637
- const documentFormatSchema = _enum(["markdown", "html"]);
5635
+ const documentFormatSchema = _enum([
5636
+ "markdown",
5637
+ "html",
5638
+ "image"
5639
+ ]);
5638
5640
  const sourceKindSchema = _enum([
5639
5641
  "file",
5640
5642
  "stdin",
@@ -5876,14 +5878,6 @@ strictObject({
5876
5878
  openDocuments: number().int().nonnegative(),
5877
5879
  previewOrigin: string()
5878
5880
  });
5879
- strictObject({
5880
- bootstrapUrl: string(),
5881
- uiUrl: string()
5882
- });
5883
- strictObject({
5884
- token: string(),
5885
- idleTimeoutSeconds: number().int().positive()
5886
- });
5887
5881
  const renderGrantParamsSchema = strictObject({
5888
5882
  documentId: documentIdSchema,
5889
5883
  revision: revisionSchema.optional(),
@@ -5974,7 +5968,11 @@ const searchHitSchema = strictObject({
5974
5968
  ]),
5975
5969
  score: number(),
5976
5970
  sourceRange: sourceRangeSchema.nullable(),
5977
- extraction: _enum(["markdown", "static-html"])
5971
+ extraction: _enum([
5972
+ "markdown",
5973
+ "static-html",
5974
+ "image"
5975
+ ])
5978
5976
  });
5979
5977
  strictObject({
5980
5978
  query: string(),
@@ -8862,7 +8860,7 @@ var SearchIndex = class {
8862
8860
  matchKind: kind,
8863
8861
  score: Math.round(score * 1e3) / 1e3,
8864
8862
  sourceRange: null,
8865
- extraction: meta.format === "markdown" ? "markdown" : "static-html"
8863
+ extraction: meta.format === "image" ? "image" : meta.format === "markdown" ? "markdown" : "static-html"
8866
8864
  });
8867
8865
  }
8868
8866
  return hits;