@bendyline/squisq 1.5.2 → 2.0.1
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/README.md +63 -10
- package/dist/{Doc-BBVGq1_9.d.ts → Doc-ylqWKDc_.d.ts} +248 -37
- package/dist/{ImageEditDoc-FuyGtt6o.d.ts → ImageEditDoc-D828IXJ1.d.ts} +1 -1
- package/dist/annotationCoercion-Dr_DY9Hx.d.ts +86 -0
- package/dist/{chunk-T5UK6YOB.js → chunk-2PWOO4ZE.js} +60 -17
- package/dist/chunk-2PWOO4ZE.js.map +1 -0
- package/dist/{chunk-VWUFZ6ZG.js → chunk-3E5F2XMR.js} +2 -29
- package/dist/chunk-3E5F2XMR.js.map +1 -0
- package/dist/chunk-4X3JQXNM.js +35 -0
- package/dist/chunk-4X3JQXNM.js.map +1 -0
- package/dist/{chunk-P3K7NLHF.js → chunk-5DKBFXPY.js} +31 -121
- package/dist/chunk-5DKBFXPY.js.map +1 -0
- package/dist/{chunk-DLXZMS5K.js → chunk-5J4HKRJF.js} +51 -3
- package/dist/chunk-5J4HKRJF.js.map +1 -0
- package/dist/chunk-5UYI3RJB.js +2503 -0
- package/dist/chunk-5UYI3RJB.js.map +1 -0
- package/dist/{chunk-BEQODJWV.js → chunk-66QO7XFB.js} +11 -291
- package/dist/chunk-66QO7XFB.js.map +1 -0
- package/dist/{chunk-HWVFJAAH.js → chunk-AMIR72JP.js} +28 -10
- package/dist/chunk-AMIR72JP.js.map +1 -0
- package/dist/chunk-CY2R2VPR.js +884 -0
- package/dist/chunk-CY2R2VPR.js.map +1 -0
- package/dist/chunk-FVJUUTEM.js +74 -0
- package/dist/chunk-FVJUUTEM.js.map +1 -0
- package/dist/{chunk-Q3ROPT5H.js → chunk-GZY66SDN.js} +1 -1
- package/dist/{chunk-Q3ROPT5H.js.map → chunk-GZY66SDN.js.map} +1 -1
- package/dist/chunk-JOQYPRDZ.js +127 -0
- package/dist/chunk-JOQYPRDZ.js.map +1 -0
- package/dist/{chunk-A4O7GIWE.js → chunk-MMPBOUK7.js} +10 -73
- package/dist/chunk-MMPBOUK7.js.map +1 -0
- package/dist/{chunk-LDQ2HJIX.js → chunk-PXLVXTLW.js} +252 -54
- package/dist/chunk-PXLVXTLW.js.map +1 -0
- package/dist/{chunk-TQWLI6S2.js → chunk-Q7LROV2H.js} +4 -2
- package/dist/{chunk-TQWLI6S2.js.map → chunk-Q7LROV2H.js.map} +1 -1
- package/dist/{chunk-GPLTCSXO.js → chunk-R2GC6RLD.js} +7 -7
- package/dist/chunk-R2GC6RLD.js.map +1 -0
- package/dist/chunk-R2YZTCLO.js +292 -0
- package/dist/chunk-R2YZTCLO.js.map +1 -0
- package/dist/chunk-S7A5D7ZJ.js +174 -0
- package/dist/chunk-S7A5D7ZJ.js.map +1 -0
- package/dist/chunk-TFJVXUHH.js +2358 -0
- package/dist/chunk-TFJVXUHH.js.map +1 -0
- package/dist/{chunk-LTN6I7QW.js → chunk-TUWMK62B.js} +55 -4
- package/dist/chunk-TUWMK62B.js.map +1 -0
- package/dist/{chunk-IMSCRLLV.js → chunk-VR7UPJ7C.js} +35 -25
- package/dist/chunk-VR7UPJ7C.js.map +1 -0
- package/dist/{chunk-KKNUBQ6Y.js → chunk-W4O2TX5I.js} +157 -92
- package/dist/chunk-W4O2TX5I.js.map +1 -0
- package/dist/{chunk-5TYS5V3G.js → chunk-X6DUONGT.js} +4204 -3560
- package/dist/chunk-X6DUONGT.js.map +1 -0
- package/dist/doc/index.d.ts +2334 -5
- package/dist/doc/index.js +127 -33
- package/dist/generate/index.d.ts +7 -2
- package/dist/generate/index.js +1 -1
- package/dist/imageEdit/index.d.ts +9 -6
- package/dist/imageEdit/index.js +3 -3
- package/dist/index.d.ts +12 -10
- package/dist/index.js +246 -80
- package/dist/jsonForm/index.d.ts +7 -3
- package/dist/jsonForm/index.js +9 -4
- package/dist/markdown/index.d.ts +6 -70
- package/dist/markdown/index.js +13 -9
- package/dist/narration/index.d.ts +618 -0
- package/dist/narration/index.js +82 -0
- package/dist/recommend/index.d.ts +15 -1
- package/dist/recommend/index.js +2 -2
- package/dist/schemas/index.d.ts +28 -6
- package/dist/schemas/index.js +15 -13
- package/dist/spatial/index.d.ts +0 -1
- package/dist/spatial/index.js +1 -1
- package/dist/storage/index.js +1 -1
- package/dist/{themeLibrary-CehcJhzz.d.ts → themeLibrary-RjVgLpUi.d.ts} +10 -11
- package/dist/timing/index.js +5 -3
- package/dist/transform/index.d.ts +35 -24
- package/dist/transform/index.js +9 -10
- package/dist/{types-DlAZ7MW4.d.ts → types-BwMPl2CB.d.ts} +1 -1
- package/dist/{types-D98li1gV.d.ts → types-C4kiRn_k.d.ts} +3 -1
- package/dist/versions/index.d.ts +2 -1
- package/dist/versions/index.js +2 -2
- package/package.json +6 -6
- package/src/__tests__/applyNarrationTiming.test.ts +190 -0
- package/src/__tests__/applyRenderStyle.test.ts +3 -3
- package/src/__tests__/asciiDiagramBattle.test.ts +246 -0
- package/src/__tests__/asciiDiagramDetect.test.ts +162 -0
- package/src/__tests__/asciiDiagramMapping.test.ts +38 -0
- package/src/__tests__/asciiDiagramParse.test.ts +233 -0
- package/src/__tests__/asciiDiagramPipeline.test.ts +273 -0
- package/src/__tests__/asciiDiagramRender.test.ts +162 -0
- package/src/__tests__/asciiDiagramRepair.test.ts +84 -0
- package/src/__tests__/asciiTimelineDetect.test.ts +157 -0
- package/src/__tests__/asciiTimelineParse.test.ts +205 -0
- package/src/__tests__/asciiTimelinePipeline.test.ts +349 -0
- package/src/__tests__/asciiTimelineRender.test.ts +376 -0
- package/src/__tests__/attrTokens.test.ts +5 -0
- package/src/__tests__/contentContainer.test.ts +43 -0
- package/src/__tests__/customTemplatesFrontmatter.test.ts +0 -15
- package/src/__tests__/customThemesFrontmatter.test.ts +1 -0
- package/src/__tests__/dataTable.test.ts +25 -15
- package/src/__tests__/diagramBlock.test.ts +3 -3
- package/src/__tests__/diagramText.test.ts +26 -0
- package/src/__tests__/docToMarkdownMedia.test.ts +83 -0
- package/src/__tests__/drawingBlock.test.ts +3 -3
- package/src/__tests__/fixtures/asciiDiagramBattle.ts +512 -0
- package/src/__tests__/fixtures/asciiDiagrams.ts +287 -0
- package/src/__tests__/fixtures/asciiTimelines.ts +35 -0
- package/src/__tests__/fixtures/treeviewFixtures.ts +243 -0
- package/src/__tests__/getLayers.test.ts +32 -18
- package/src/__tests__/getLayersFallback.test.ts +8 -8
- package/src/__tests__/imageEditVersions.test.ts +2 -0
- package/src/__tests__/jsonForm.pointer.test.ts +47 -1
- package/src/__tests__/layoutBlock.test.ts +3 -3
- package/src/__tests__/majorApiTypes.test.ts +18 -0
- package/src/__tests__/markdown.test.ts +54 -4
- package/src/__tests__/markdownSanitize.test.ts +7 -5
- package/src/__tests__/matchFontFamily.test.ts +114 -0
- package/src/__tests__/materializeBlockLayers.test.ts +135 -0
- package/src/__tests__/materializeTestUtils.ts +17 -0
- package/src/__tests__/narrationAlign.test.ts +150 -0
- package/src/__tests__/narrationFeatures.test.ts +71 -0
- package/src/__tests__/narrationNuclei.test.ts +45 -0
- package/src/__tests__/narrationPacing.test.ts +189 -0
- package/src/__tests__/narrationScript.test.ts +149 -0
- package/src/__tests__/narrationSessionRepro.test.ts +62 -0
- package/src/__tests__/narrationSidecar.test.ts +88 -0
- package/src/__tests__/narrationSyllables.test.ts +65 -0
- package/src/__tests__/narrationTestSignals.ts +167 -0
- package/src/__tests__/narrationVad.test.ts +66 -0
- package/src/__tests__/resolveDocTheme.test.ts +16 -2
- package/src/__tests__/rootExports.test.ts +18 -0
- package/src/__tests__/scopedContentContainer.test.ts +20 -0
- package/src/__tests__/shapeGeometry.test.ts +12 -0
- package/src/__tests__/templateAnnotationParse.test.ts +10 -0
- package/src/__tests__/templateInputs.test.ts +69 -0
- package/src/__tests__/templateMetadata.test.ts +2 -1
- package/src/__tests__/templates.test.ts +143 -17
- package/src/__tests__/themeCompile.test.ts +49 -22
- package/src/__tests__/transformProvenance.test.ts +160 -0
- package/src/__tests__/transformV2.test.ts +40 -14
- package/src/__tests__/treeviewBattle.test.ts +76 -0
- package/src/__tests__/treeviewDetect.test.ts +168 -0
- package/src/__tests__/treeviewParse.test.ts +118 -0
- package/src/__tests__/treeviewPipeline.test.ts +183 -0
- package/src/__tests__/treeviewRender.test.ts +91 -0
- package/src/__tests__/versions.test.ts +44 -0
- package/src/doc/applyNarrationTiming.ts +244 -0
- package/src/doc/asciiDiagram/chars.ts +210 -0
- package/src/doc/asciiDiagram/detect.ts +175 -0
- package/src/doc/asciiDiagram/index.ts +38 -0
- package/src/doc/asciiDiagram/mapping.ts +225 -0
- package/src/doc/asciiDiagram/parse.ts +1095 -0
- package/src/doc/asciiDiagram/render.ts +963 -0
- package/src/doc/asciiDiagram/repair.ts +400 -0
- package/src/doc/asciiDiagram/types.ts +65 -0
- package/src/doc/asciiTimeline/detect.ts +138 -0
- package/src/doc/asciiTimeline/index.ts +26 -0
- package/src/doc/asciiTimeline/mapping.ts +43 -0
- package/src/doc/asciiTimeline/parse.ts +870 -0
- package/src/doc/asciiTimeline/render.ts +427 -0
- package/src/doc/asciiTimeline/types.ts +73 -0
- package/src/doc/asciiTimeline/wrappedFlow.ts +427 -0
- package/src/doc/audioMapping.ts +60 -46
- package/src/doc/customTemplatesFrontmatter.ts +0 -41
- package/src/doc/docToMarkdown.ts +70 -2
- package/src/doc/index.ts +76 -4
- package/src/doc/markdownToDoc.ts +138 -2
- package/src/doc/materializeBlockLayers.ts +304 -0
- package/src/doc/mediaAnnotations.ts +20 -0
- package/src/doc/resolveDocTheme.ts +8 -7
- package/src/doc/templateInputs.ts +185 -2
- package/src/doc/templates/__tests__/customTemplateRegistry.test.ts +22 -8
- package/src/doc/templates/__tests__/listBlock.test.ts +64 -0
- package/src/doc/templates/diagramBlock.ts +237 -38
- package/src/doc/templates/fallbackBlock.ts +1 -1
- package/src/doc/templates/index.ts +134 -279
- package/src/doc/templates/inputDescriptors.ts +20 -1
- package/src/doc/templates/listBlock.ts +88 -30
- package/src/doc/templates/metadata.ts +10 -0
- package/src/doc/templates/persistentLayers.ts +12 -126
- package/src/doc/templates/registry.ts +88 -0
- package/src/doc/templates/templateNames.ts +22 -0
- package/src/doc/templates/timelineBlock.ts +613 -0
- package/src/doc/templates/treeBlock.ts +131 -0
- package/src/doc/treeview/chars.ts +72 -0
- package/src/doc/treeview/detect.ts +145 -0
- package/src/doc/treeview/index.ts +30 -0
- package/src/doc/treeview/mapping.ts +95 -0
- package/src/doc/treeview/parse.ts +201 -0
- package/src/doc/treeview/render.ts +41 -0
- package/src/doc/treeview/types.ts +43 -0
- package/src/doc/utils/applyRenderStyle.ts +2 -9
- package/src/doc/utils/diagramText.ts +78 -0
- package/src/doc/utils/shapeGeometry.ts +67 -5
- package/src/doc/validate.ts +1 -1
- package/src/generate/templateMapper.ts +7 -0
- package/src/imageEdit/export.ts +6 -5
- package/src/imageEdit/versionPaths.ts +13 -26
- package/src/imageEdit/versions.ts +21 -100
- package/src/index.ts +1 -0
- package/src/internal/immutable.ts +58 -0
- package/src/jsonForm/index.ts +9 -1
- package/src/jsonForm/pointer.ts +68 -23
- package/src/markdown/attrTokens.ts +7 -5
- package/src/markdown/index.ts +1 -0
- package/src/markdown/stringify.ts +4 -9
- package/src/markdown/utils.ts +36 -14
- package/src/narration/align.ts +514 -0
- package/src/narration/features.ts +231 -0
- package/src/narration/index.ts +86 -0
- package/src/narration/nuclei.ts +118 -0
- package/src/narration/pacing.ts +211 -0
- package/src/narration/script.ts +239 -0
- package/src/narration/session.ts +100 -0
- package/src/narration/sidecar.ts +187 -0
- package/src/narration/syllables.ts +85 -0
- package/src/narration/trace.ts +50 -0
- package/src/narration/types.ts +299 -0
- package/src/narration/vad.ts +131 -0
- package/src/recommend/numberHighlight.ts +25 -0
- package/src/recommend/templates.ts +108 -12
- package/src/schemas/BlockTemplates.ts +156 -7
- package/src/schemas/Doc.ts +72 -9
- package/src/schemas/Media.ts +12 -2
- package/src/schemas/Theme.ts +45 -25
- package/src/schemas/Viewport.ts +2 -2
- package/src/schemas/fontStacks.ts +79 -0
- package/src/schemas/themeCompile.ts +15 -0
- package/src/schemas/themeConstants.ts +2 -0
- package/src/schemas/themeLibrary.ts +25 -19
- package/src/schemas/themeValidator.ts +1 -1
- package/src/schemas/themes/gezellig.json +1 -1
- package/src/spatial/Geohash.ts +0 -3
- package/src/storage/ContentContainer.ts +17 -9
- package/src/storage/ScopedContentContainer.ts +45 -15
- package/src/transform/applyTransform.ts +5 -5
- package/src/transform/index.ts +3 -1
- package/src/transform/registry.ts +169 -49
- package/src/transform/templateSelector.ts +21 -2
- package/src/transform/timingAllocator.ts +152 -21
- package/src/transform/types.ts +14 -1
- package/src/versions/gitignore.ts +34 -0
- package/src/versions/index.ts +2 -0
- package/src/versions/operations.ts +18 -104
- package/src/versions/paths.ts +13 -28
- package/src/versions/snapshotStore.ts +202 -0
- package/src/versions/types.ts +3 -1
- package/dist/chunk-5TYS5V3G.js.map +0 -1
- package/dist/chunk-A4O7GIWE.js.map +0 -1
- package/dist/chunk-BEQODJWV.js.map +0 -1
- package/dist/chunk-DLXZMS5K.js.map +0 -1
- package/dist/chunk-GPLTCSXO.js.map +0 -1
- package/dist/chunk-HWVFJAAH.js.map +0 -1
- package/dist/chunk-IMSCRLLV.js.map +0 -1
- package/dist/chunk-JELIRVDP.js +0 -24
- package/dist/chunk-JELIRVDP.js.map +0 -1
- package/dist/chunk-KKNUBQ6Y.js.map +0 -1
- package/dist/chunk-LDQ2HJIX.js.map +0 -1
- package/dist/chunk-LTN6I7QW.js.map +0 -1
- package/dist/chunk-P3K7NLHF.js.map +0 -1
- package/dist/chunk-T5UK6YOB.js.map +0 -1
- package/dist/chunk-UY7KGQ5R.js +0 -192
- package/dist/chunk-UY7KGQ5R.js.map +0 -1
- package/dist/chunk-VLJJHDAC.js +0 -218
- package/dist/chunk-VLJJHDAC.js.map +0 -1
- package/dist/chunk-VWUFZ6ZG.js.map +0 -1
- package/dist/story/index.d.ts +0 -1801
- package/dist/story/index.js +0 -279
- package/src/doc/getLayers.ts +0 -195
- /package/dist/{story → narration}/index.js.map +0 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal storage engine shared by document and image-editor histories.
|
|
3
|
+
* Public APIs keep their domain-specific names and result reasons; this module
|
|
4
|
+
* owns the mechanics that must behave identically across both histories.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { ContentContainer } from '../storage/ContentContainer.js';
|
|
8
|
+
import { ensureVersionsGitIgnored } from './gitignore.js';
|
|
9
|
+
import { formatVersionTimestamp, parseVersionTimestamp } from './timestamp.js';
|
|
10
|
+
import type { CoalesceOptions, PrunePolicy, Version } from './types.js';
|
|
11
|
+
|
|
12
|
+
const decoder = new TextDecoder();
|
|
13
|
+
const encoder = new TextEncoder();
|
|
14
|
+
|
|
15
|
+
export interface SnapshotPathStrategy {
|
|
16
|
+
readonly prefix: string;
|
|
17
|
+
readonly extension: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface SaveTextSnapshotOptions {
|
|
21
|
+
content: string;
|
|
22
|
+
basename: string;
|
|
23
|
+
mimeType: string;
|
|
24
|
+
now?: Date;
|
|
25
|
+
force?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface SaveTextSnapshotResult {
|
|
29
|
+
saved: boolean;
|
|
30
|
+
version: Version | null;
|
|
31
|
+
reason: 'saved' | 'unchanged';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function buildSnapshotPath(
|
|
35
|
+
strategy: SnapshotPathStrategy,
|
|
36
|
+
basename: string,
|
|
37
|
+
date: Date,
|
|
38
|
+
collision = 0,
|
|
39
|
+
): string {
|
|
40
|
+
const stamp = formatVersionTimestamp(date);
|
|
41
|
+
const suffix = collision > 0 ? `-${collision + 1}` : '';
|
|
42
|
+
return `${strategy.prefix}${basename}.${stamp}${suffix}.${strategy.extension}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function parseSnapshotPath(
|
|
46
|
+
strategy: SnapshotPathStrategy,
|
|
47
|
+
path: string,
|
|
48
|
+
): { basename: string; timestamp: Date; collision: number } | null {
|
|
49
|
+
if (!path.startsWith(strategy.prefix)) return null;
|
|
50
|
+
const extension = `.${strategy.extension}`;
|
|
51
|
+
const rest = path.slice(strategy.prefix.length);
|
|
52
|
+
if (!rest.endsWith(extension)) return null;
|
|
53
|
+
const stem = rest.slice(0, -extension.length);
|
|
54
|
+
const lastDot = stem.lastIndexOf('.');
|
|
55
|
+
if (lastDot <= 0) return null;
|
|
56
|
+
|
|
57
|
+
const basename = stem.slice(0, lastDot);
|
|
58
|
+
const tail = stem.slice(lastDot + 1);
|
|
59
|
+
const dash = tail.indexOf('-');
|
|
60
|
+
let stamp = tail;
|
|
61
|
+
let collision = 0;
|
|
62
|
+
if (dash >= 0) {
|
|
63
|
+
stamp = tail.slice(0, dash);
|
|
64
|
+
const suffix = Number(tail.slice(dash + 1));
|
|
65
|
+
if (!Number.isInteger(suffix) || suffix < 2) return null;
|
|
66
|
+
collision = suffix - 1;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const timestamp = parseVersionTimestamp(stamp);
|
|
70
|
+
return timestamp ? { basename, timestamp, collision } : null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function listSnapshots(
|
|
74
|
+
container: ContentContainer,
|
|
75
|
+
strategy: SnapshotPathStrategy,
|
|
76
|
+
basename?: string,
|
|
77
|
+
): Promise<Version[]> {
|
|
78
|
+
const entries = await container.listFiles(strategy.prefix);
|
|
79
|
+
const versions: Version[] = [];
|
|
80
|
+
for (const entry of entries) {
|
|
81
|
+
const parsed = parseSnapshotPath(strategy, entry.path);
|
|
82
|
+
if (!parsed || (basename !== undefined && parsed.basename !== basename)) continue;
|
|
83
|
+
versions.push({
|
|
84
|
+
path: entry.path,
|
|
85
|
+
basename: parsed.basename,
|
|
86
|
+
timestamp: parsed.timestamp,
|
|
87
|
+
size: entry.size,
|
|
88
|
+
collision: parsed.collision,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
versions.sort((a, b) => {
|
|
93
|
+
const timestampDelta = b.timestamp.getTime() - a.timestamp.getTime();
|
|
94
|
+
return timestampDelta || b.collision - a.collision;
|
|
95
|
+
});
|
|
96
|
+
return versions;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export async function readTextSnapshot(
|
|
100
|
+
container: ContentContainer,
|
|
101
|
+
version: Version | string,
|
|
102
|
+
): Promise<string | null> {
|
|
103
|
+
const path = typeof version === 'string' ? version : version.path;
|
|
104
|
+
const data = await container.readFile(path);
|
|
105
|
+
return data ? decoder.decode(data) : null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export async function saveTextSnapshot(
|
|
109
|
+
container: ContentContainer,
|
|
110
|
+
strategy: SnapshotPathStrategy,
|
|
111
|
+
options: SaveTextSnapshotOptions,
|
|
112
|
+
): Promise<SaveTextSnapshotResult> {
|
|
113
|
+
const versions = await listSnapshots(container, strategy, options.basename);
|
|
114
|
+
if (!options.force && versions.length > 0) {
|
|
115
|
+
const existing = await readTextSnapshot(container, versions[0]!);
|
|
116
|
+
if (existing === options.content) {
|
|
117
|
+
// Backfill containers written before history owned its ignore rule.
|
|
118
|
+
await ensureVersionsGitIgnored(container);
|
|
119
|
+
return { saved: false, version: null, reason: 'unchanged' };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const now = options.now ?? new Date();
|
|
124
|
+
let collision = 0;
|
|
125
|
+
let path = buildSnapshotPath(strategy, options.basename, now, collision);
|
|
126
|
+
while (await container.exists(path)) {
|
|
127
|
+
collision += 1;
|
|
128
|
+
path = buildSnapshotPath(strategy, options.basename, now, collision);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const data = encoder.encode(options.content);
|
|
132
|
+
await ensureVersionsGitIgnored(container);
|
|
133
|
+
await container.writeFile(path, data, options.mimeType);
|
|
134
|
+
return {
|
|
135
|
+
saved: true,
|
|
136
|
+
version: {
|
|
137
|
+
path,
|
|
138
|
+
basename: options.basename,
|
|
139
|
+
timestamp: now,
|
|
140
|
+
size: data.byteLength,
|
|
141
|
+
collision,
|
|
142
|
+
},
|
|
143
|
+
reason: 'saved',
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export async function pruneSnapshots(
|
|
148
|
+
container: ContentContainer,
|
|
149
|
+
strategy: SnapshotPathStrategy,
|
|
150
|
+
policy: PrunePolicy,
|
|
151
|
+
basename?: string,
|
|
152
|
+
): Promise<Version[]> {
|
|
153
|
+
const versions = await listSnapshots(container, strategy, basename);
|
|
154
|
+
let toDelete: Version[];
|
|
155
|
+
|
|
156
|
+
if (policy.type === 'keep-last-n') {
|
|
157
|
+
toDelete = versions.slice(Math.max(0, Math.floor(policy.n)));
|
|
158
|
+
} else if (policy.type === 'older-than') {
|
|
159
|
+
const cutoff = policy.date.getTime();
|
|
160
|
+
toDelete = versions.filter((version) => version.timestamp.getTime() < cutoff);
|
|
161
|
+
} else {
|
|
162
|
+
toDelete = versions.filter((version) => !policy.keep(version, versions));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
await removeSnapshots(container, toDelete);
|
|
166
|
+
return toDelete;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export async function coalesceSnapshots(
|
|
170
|
+
container: ContentContainer,
|
|
171
|
+
strategy: SnapshotPathStrategy,
|
|
172
|
+
options: CoalesceOptions = {},
|
|
173
|
+
basename?: string,
|
|
174
|
+
): Promise<Version[]> {
|
|
175
|
+
const windowMs = options.windowMs ?? 60_000;
|
|
176
|
+
const versions = await listSnapshots(container, strategy, basename);
|
|
177
|
+
const toDelete: Version[] = [];
|
|
178
|
+
|
|
179
|
+
// Compare against the last kept snapshot. Pairwise comparison against a
|
|
180
|
+
// deleted neighbor would chain through a dense run and over-prune it.
|
|
181
|
+
if (versions.length > 0) {
|
|
182
|
+
let anchor = versions[0]!;
|
|
183
|
+
for (let index = 1; index < versions.length; index++) {
|
|
184
|
+
const candidate = versions[index]!;
|
|
185
|
+
if (anchor.timestamp.getTime() - candidate.timestamp.getTime() <= windowMs) {
|
|
186
|
+
toDelete.push(candidate);
|
|
187
|
+
} else {
|
|
188
|
+
anchor = candidate;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
await removeSnapshots(container, toDelete);
|
|
194
|
+
return toDelete;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async function removeSnapshots(
|
|
198
|
+
container: ContentContainer,
|
|
199
|
+
versions: readonly Version[],
|
|
200
|
+
): Promise<void> {
|
|
201
|
+
for (const version of versions) await container.removeFile(version.path);
|
|
202
|
+
}
|
package/src/versions/types.ts
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
* the document inside the same {@link ContentContainer}. They live under
|
|
6
6
|
* `.versions/<docBasename>.<sortableTimestamp>.md`. The container is the
|
|
7
7
|
* unit of persistence — when the host serializes the container to a ZIP,
|
|
8
|
-
* a real folder, or anywhere else, the version snapshots ride along.
|
|
8
|
+
* a real folder, or anywhere else, the version snapshots ride along. When
|
|
9
|
+
* snapshots are retained, a container-root `.gitignore` rule excludes the
|
|
10
|
+
* `.versions/` folder from Git.
|
|
9
11
|
*/
|
|
10
12
|
|
|
11
13
|
/**
|