@chibitek/chibi 0.1.175 → 0.1.177

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.
Files changed (66) hide show
  1. package/dist/assets/{abnfDiagram-O67JEVCF-CjXTIXBz.js → abnfDiagram-O67JEVCF-D66KKLXq.js} +1 -1
  2. package/dist/assets/{arc-1QgG2iO9.js → arc-Chl6g0yq.js} +1 -1
  3. package/dist/assets/{architectureDiagram-NJMV4G6O-CzCo4hRJ.js → architectureDiagram-NJMV4G6O-ChT8017v.js} +1 -1
  4. package/dist/assets/{blockDiagram-BEXU5L5S-DhrHIUjL.js → blockDiagram-BEXU5L5S-DSOAtPXh.js} +1 -1
  5. package/dist/assets/{c4Diagram-YGBWAQC7-gOjFoY7Z.js → c4Diagram-YGBWAQC7-CAyzcis4.js} +1 -1
  6. package/dist/assets/channel-DGEfaLnD.js +1 -0
  7. package/dist/assets/{chunk-2Q5K7J3B-B9bsMZTt.js → chunk-2Q5K7J3B-DG7zWvl1.js} +1 -1
  8. package/dist/assets/{chunk-3FUC2YCW-D6qIOfLe.js → chunk-3FUC2YCW-CNQ37WCV.js} +2 -2
  9. package/dist/assets/{chunk-5VM5RSS4-DCixOiOi.js → chunk-5VM5RSS4-Dvv3U9Ci.js} +1 -1
  10. package/dist/assets/{chunk-GTNCS2PH-Bh52Az-G.js → chunk-GTNCS2PH-DyQrY0Ij.js} +1 -1
  11. package/dist/assets/{chunk-GWA4HPMP-Dbs4EZ88.js → chunk-GWA4HPMP-BLgrTe-Y.js} +1 -1
  12. package/dist/assets/{chunk-JWPE2WC7-jReoeHz2.js → chunk-JWPE2WC7-Bi7RU6mT.js} +1 -1
  13. package/dist/assets/{chunk-NETBCI7D-CF3H0lZo.js → chunk-NETBCI7D-bBBVBfAd.js} +1 -1
  14. package/dist/assets/{chunk-WEXAMYUT-DetCJmJX.js → chunk-WEXAMYUT-CE_h60fU.js} +1 -1
  15. package/dist/assets/{chunk-XXDRQBXY-CigsN-8U.js → chunk-XXDRQBXY-f6P9rCRq.js} +1 -1
  16. package/dist/assets/{classDiagram-v2-NBCMYWYE-D8ZcMUWM.js → classDiagram-v2-NBCMYWYE-6Uq3JzmJ.js} +1 -1
  17. package/dist/assets/{cose-bilkent-JH36ORCC-BnqFoYIa.js → cose-bilkent-JH36ORCC-BxvkL31E.js} +1 -1
  18. package/dist/assets/{cynefin-OW5HDTMX-DWSSGPqP.js → cynefin-OW5HDTMX-Dlcwlw2F.js} +1 -1
  19. package/dist/assets/{cynefinDiagram-VND7K2PF-Doo-ZQ5E.js → cynefinDiagram-VND7K2PF-D3NOeWUy.js} +1 -1
  20. package/dist/assets/{dagre-6A5THRUB-Bje_N-ue.js → dagre-6A5THRUB-IGmT7nsP.js} +1 -1
  21. package/dist/assets/{diagram-22UHCM2B-osEfxfGj.js → diagram-22UHCM2B-D0K8tG3k.js} +1 -1
  22. package/dist/assets/{diagram-3UASUU5V-D0ybINw1.js → diagram-3UASUU5V-CSkDkOvw.js} +1 -1
  23. package/dist/assets/{diagram-ATOU4E4O-DwS59waF.js → diagram-ATOU4E4O-CX5EXBJ_.js} +1 -1
  24. package/dist/assets/{diagram-CDSNMT55-stDTabsA.js → diagram-CDSNMT55-D0FQ7x1J.js} +1 -1
  25. package/dist/assets/{diagram-MLGK6HIB-COdtBBj4.js → diagram-MLGK6HIB-BymN_w7h.js} +1 -1
  26. package/dist/assets/{diagram-MPIPVDR6-S32r0-4f.js → diagram-MPIPVDR6-ugKqp8yy.js} +1 -1
  27. package/dist/assets/{ebnfDiagram-ZINNZB2B-CZxbMOzV.js → ebnfDiagram-ZINNZB2B-DROFb0r3.js} +1 -1
  28. package/dist/assets/{elk-276RUBZZ-PzYOam0u.js → elk-276RUBZZ-CNVCU2l7.js} +1 -1
  29. package/dist/assets/{erDiagram-OPXOYQCR-D0HBOTqF.js → erDiagram-OPXOYQCR-BQj5bZ7y.js} +1 -1
  30. package/dist/assets/{flowDiagram-KWPJA3E3-1d8rftXL.js → flowDiagram-KWPJA3E3-C3cBXKRL.js} +1 -1
  31. package/dist/assets/{ganttDiagram-FUAMR5RP-CWn83VOd.js → ganttDiagram-FUAMR5RP-CdNdC_Vp.js} +1 -1
  32. package/dist/assets/{gitGraphDiagram-X574FWY7-CkLyRxvr.js → gitGraphDiagram-X574FWY7-v_LM9fGO.js} +1 -1
  33. package/dist/assets/{index-BcBNl1Sc.js → index-UICHeO5x.js} +4 -4
  34. package/dist/assets/{index-DfdDXEfq.js → index-fnHp_1ly.js} +1 -1
  35. package/dist/assets/{infoDiagram-VRGFBTTK-BmAsjOaa.js → infoDiagram-VRGFBTTK-0fzWO21Z.js} +1 -1
  36. package/dist/assets/{ishikawaDiagram-OU5B5YK6-B9d57hp_.js → ishikawaDiagram-OU5B5YK6-BmqyKWCK.js} +1 -1
  37. package/dist/assets/{journeyDiagram-ZHPQQLJL-II3Kse3X.js → journeyDiagram-ZHPQQLJL-BSihTjOI.js} +1 -1
  38. package/dist/assets/{kanban-definition-PNTS6WVX-DtovCoCx.js → kanban-definition-PNTS6WVX-LAP03jiI.js} +1 -1
  39. package/dist/assets/{linear-BnH8vI1-.js → linear-BoSfZT4X.js} +1 -1
  40. package/dist/assets/{mermaid.core-BExpGmRM.js → mermaid.core-KciMRs_R.js} +5 -5
  41. package/dist/assets/{mindmap-definition-NLK3R4M7-CSGJyaor.js → mindmap-definition-NLK3R4M7-CEGLBEfc.js} +1 -1
  42. package/dist/assets/{pegDiagram-GJSIUBJH-BFgKWA7i.js → pegDiagram-GJSIUBJH-DLwMHvoR.js} +1 -1
  43. package/dist/assets/{pieDiagram-5QR66LMP-Dl3FAvDB.js → pieDiagram-5QR66LMP-DHnlu96s.js} +1 -1
  44. package/dist/assets/{quadrantDiagram-O4NWA36T-DafRWmMB.js → quadrantDiagram-O4NWA36T-C_aIseXA.js} +1 -1
  45. package/dist/assets/{railroadDiagram-XR7U4H2S-CHJ7SyyJ.js → railroadDiagram-XR7U4H2S-DOXDQ14n.js} +1 -1
  46. package/dist/assets/{requirementDiagram-PLB6GJNP-DJzpaN8z.js → requirementDiagram-PLB6GJNP-C49u1hle.js} +1 -1
  47. package/dist/assets/{sankeyDiagram-IPEJSGJF-BKqi0qaK.js → sankeyDiagram-IPEJSGJF-TO8i3aYk.js} +1 -1
  48. package/dist/assets/{sequenceDiagram-PO4LG4MO-Bdc2LKBx.js → sequenceDiagram-PO4LG4MO-CqByM3om.js} +1 -1
  49. package/dist/assets/{sizeCapture-INFHLROL-CIuw2Jav.js → sizeCapture-INFHLROL-BVsTiKjg.js} +1 -1
  50. package/dist/assets/{stateDiagram-v2-GCMORJYK-CocMnCmt.js → stateDiagram-v2-GCMORJYK-0AUlHnV-.js} +1 -1
  51. package/dist/assets/{swimlanes-2SLR337P-D7Kw4SfT.js → swimlanes-2SLR337P-D_wUrvq4.js} +1 -1
  52. package/dist/assets/swimlanesDiagram-TC7HE7FX-HihkzjzX.js +8 -0
  53. package/dist/assets/{timeline-definition-EJHVYXUP-DEXnhdui.js → timeline-definition-EJHVYXUP-qf2wxQef.js} +1 -1
  54. package/dist/assets/{usecaseDiagram-POWQR4AR-CJTa0bWM.js → usecaseDiagram-POWQR4AR-Blqc8FjE.js} +1 -1
  55. package/dist/assets/{vennDiagram-UO4OBE2U-CKphfio6.js → vennDiagram-UO4OBE2U-Df3HJl0f.js} +1 -1
  56. package/dist/assets/{wardleyDiagram-VNRHLVJA-COQ5I4oG.js → wardleyDiagram-VNRHLVJA-B-QhMirM.js} +1 -1
  57. package/dist/assets/{xychartDiagram-PMCCYNJV-BqlgNUIm.js → xychartDiagram-PMCCYNJV-DsZdyUlm.js} +1 -1
  58. package/dist/index.html +1 -1
  59. package/dist-server/index.js +29 -14
  60. package/dist-server/server/attachment-mimes.js +31 -7
  61. package/dist-server/server/attachments.js +16 -20
  62. package/dist-server/server/harness-import/history.js +1 -1
  63. package/dist-server/src/lib/composer-attachments.js +5 -6
  64. package/package.json +1 -1
  65. package/dist/assets/channel-DB0DMkPD.js +0 -1
  66. package/dist/assets/swimlanesDiagram-TC7HE7FX-Bq7WUTaZ.js +0 -8
@@ -6,7 +6,7 @@ import { createReadStream, linkSync, mkdirSync, readFileSync, readdirSync, statS
6
6
  import { link, open, unlink } from "node:fs/promises";
7
7
  import { join, extname } from "node:path";
8
8
  import { DATA_DIR } from "./config.js";
9
- import { FILE_MIMES, IMAGE_MIMES, extensionForFileMime, extensionForMime, normalizedMime } from "./attachment-mimes.js";
9
+ import { FILE_MIMES, IMAGE_MIMES, OTHER_FILE_EXTENSION, extensionForFileMime, extensionForMime, fileMime } from "./attachment-mimes.js";
10
10
  export { extensionForFileMime, extensionForMime };
11
11
  export const ATTACHMENTS_DIR = join(DATA_DIR, "attachments");
12
12
  /** The spec's ceiling: a screenshot bigger than this is rejected before it
@@ -255,12 +255,13 @@ async function withUploadLock(uploadId, operation) {
255
255
  uploadLocks.delete(uploadId);
256
256
  }
257
257
  }
258
- /** Every committed attachment name is `${uuid}${extension}` for one of these
259
- * fixed extensions — saveFile/saveImage never write any other suffix — so
260
- * whether a given upload ID is already committed, and under which content
261
- * type, can be answered with a handful of direct stats instead of a scan
262
- * over every file in the directory. */
263
- const KNOWN_ATTACHMENT_EXTENSIONS = Array.from(new Set([...Object.values(IMAGE_MIMES), ...Object.values(FILE_MIMES)]));
258
+ /** Committed attachment names are `${uuid}${extension}`, mostly for one of
259
+ * these fixed extensions, so whether a given upload ID is already committed,
260
+ * and under which content type, can be answered with a handful of direct
261
+ * stats instead of a scan over every file in the directory.
262
+ * ponytail: a file of another type keeps its own extension, so reusing one
263
+ * upload ID across two such extensions is not caught; a prefix scan would. */
264
+ const KNOWN_ATTACHMENT_EXTENSIONS = Array.from(new Set([...Object.values(IMAGE_MIMES), ...Object.values(FILE_MIMES), OTHER_FILE_EXTENSION]));
264
265
  /** Missing or unreadable candidates count as absent here; the atomic link
265
266
  * still detects a collision if a file exists when an upload commits. */
266
267
  function statSizeIfFile(path) {
@@ -297,14 +298,12 @@ async function digestFile(path) {
297
298
  function statusError(status, message) {
298
299
  return Object.assign(new Error(message), { status });
299
300
  }
300
- /** Strip platform-reserved characters and replace any sender-provided
301
- * extension with the canonical one for the accepted mime. Separators and
302
- * encoded separators are rejected rather than massaged so traversal attempts
303
- * remain visible as bad requests. */
301
+ /** Strip platform-reserved characters. A known mime replaces any
302
+ * sender-provided extension with its canonical one; any other type keeps the
303
+ * sender's name as written. Separators and encoded separators are rejected
304
+ * rather than massaged so traversal attempts remain visible as bad requests. */
304
305
  export function sanitizeSharedFileName(name, mime) {
305
- const extension = extensionForFileMime(mime);
306
- if (!extension)
307
- throw statusError(400, "content-type must be a supported document or audio type");
306
+ const extension = FILE_MIMES[fileMime(mime) ?? ""] ?? "";
308
307
  const normalized = name.normalize("NFKC").trim();
309
308
  if (!normalized)
310
309
  throw statusError(400, "name is required");
@@ -314,7 +313,7 @@ export function sanitizeSharedFileName(name, mime) {
314
313
  throw statusError(400, "name must be a filename, not a path");
315
314
  }
316
315
  const dot = normalized.lastIndexOf(".");
317
- const withoutExtension = dot > 0 ? normalized.slice(0, dot) : normalized;
316
+ const withoutExtension = extension && dot > 0 ? normalized.slice(0, dot) : normalized;
318
317
  const safeCharacters = Array.from(withoutExtension, (character) => {
319
318
  const code = character.charCodeAt(0);
320
319
  return code <= 31 || code === 127 || "<>:\"|?*".includes(character) ? "_" : character;
@@ -333,12 +332,9 @@ export function sanitizeSharedFileName(name, mime) {
333
332
  * the request in memory. A failed, empty, or oversized upload leaves no
334
333
  * partial file behind. */
335
334
  export async function saveFile(chunks, originalName, mime, options = {}) {
336
- const normalized = normalizedMime(mime);
337
- if (!normalized || !extensionForFileMime(normalized)) {
338
- throw statusError(400, "content-type must be a supported document or audio type");
339
- }
335
+ const normalized = fileMime(mime) ?? "application/octet-stream";
340
336
  const name = sanitizeSharedFileName(originalName, normalized);
341
- const extension = extensionForFileMime(normalized);
337
+ const extension = extensionForFileMime(normalized, name);
342
338
  const uploadId = validateAttachmentUploadId(options.uploadId);
343
339
  const expectedBytes = options.expectedBytes;
344
340
  if (expectedBytes !== undefined && (!Number.isSafeInteger(expectedBytes) || expectedBytes < 0)) {
@@ -173,7 +173,7 @@ export function uploadIdFor(key) {
173
173
  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-5${hex.slice(13, 16)}-${variant}${hex.slice(17, 20)}-${hex.slice(20, 32)}`;
174
174
  }
175
175
  /** The extension Atomic's store gives this file, for the already-saved check. */
176
- export const storedExtension = (file) => file.mime ? (file.image ? extensionForMime(file.mime) : extensionForFileMime(file.mime)) : null;
176
+ export const storedExtension = (file) => file.mime ? (file.image ? extensionForMime(file.mime) : extensionForFileMime(file.mime, file.name)) : null;
177
177
  export function formatBytes(bytes) {
178
178
  if (bytes < 1024)
179
179
  return `${bytes} B`;
@@ -72,6 +72,7 @@ const DOCUMENT_MIMES = {
72
72
  txt: "text/plain",
73
73
  md: "text/markdown",
74
74
  markdown: "text/markdown",
75
+ html: "text/html", htm: "text/html",
75
76
  csv: "text/csv",
76
77
  tsv: "text/tab-separated-values",
77
78
  json: "application/json",
@@ -271,16 +272,14 @@ export async function imageAttachmentFromFile(file, optimistic) {
271
272
  ...(optimistic?.previewUrl ? { previewUrl: optimistic.previewUrl } : {}),
272
273
  };
273
274
  }
274
- /** Copy a supported document or audio file into the private attachment store. The prompt
275
- * then carries the same durable path for the local agent and paired phones,
276
- * instead of exposing an arbitrary Finder path to the companion route. */
275
+ /** Copy any file into the private attachment store. The prompt then carries the same durable
276
+ * path for the local agent and paired phones, instead of an arbitrary Finder path. */
277
277
  export async function fileAttachmentFromFile(file) {
278
278
  const declared = file.type.split(";", 1)[0].trim().toLowerCase();
279
279
  const extension = file.name.split(".").at(-1)?.toLowerCase() ?? "";
280
280
  const mime = documentMime(file) ??
281
- (ACCEPTED_AUDIO_MIMES.has(declared) ? declared : AUDIO_MIMES_BY_EXTENSION[extension]);
282
- if (!mime)
283
- return null;
281
+ (ACCEPTED_AUDIO_MIMES.has(declared) ? declared : AUDIO_MIMES_BY_EXTENSION[extension]) ??
282
+ (/^[\w.+-]+\/[\w.+-]+$/.test(declared) ? declared : "application/octet-stream");
284
283
  if (file.size > FILE_MAX_BYTES) {
285
284
  throw Object.assign(new Error(`${file.name} exceeds 25 MB`), { status: 413 });
286
285
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chibitek/chibi",
3
- "version": "0.1.175",
3
+ "version": "0.1.177",
4
4
  "description": "Atomic by Chibitek: run your AI team's server anywhere and pair your devices to it",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -1 +0,0 @@
1
- import{U as a,C as n}from"./mermaid.core-BExpGmRM.js";const t=(r,o)=>a.lang.round(n.parse(r)[o]);export{t as c};
@@ -1,8 +0,0 @@
1
- import{c as r,s as e}from"./flowDiagram-KWPJA3E3-1d8rftXL.js";import{_ as a}from"./mermaid.core-BExpGmRM.js";import"./chunk-5VM5RSS4-DCixOiOi.js";import"./chunk-XXDRQBXY-CigsN-8U.js";import"./chunk-WEXAMYUT-DetCJmJX.js";import"./chunk-GWA4HPMP-Dbs4EZ88.js";import"./channel-DB0DMkPD.js";import"./index-BcBNl1Sc.js";var o=a(t=>`${e(t)}
2
- .swimlane.cluster:not([data-color-id]) rect {
3
- stroke: ${t.clusterBorder} !important;
4
- }
5
- [data-look="neo"].cluster rect {
6
- filter: none;
7
- }
8
- `,"getStyles"),s=o,u=r({styles:s});export{u as diagram};