@aivorynet/slaide 1.0.0
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/CHANGELOG.md +26 -0
- package/LICENSE +201 -0
- package/README.md +87 -0
- package/bin/slaide.js +25 -0
- package/dist/assets.d.ts +10 -0
- package/dist/assets.js +54 -0
- package/dist/assets.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +433 -0
- package/dist/cli.js.map +1 -0
- package/dist/compare/index.d.ts +24 -0
- package/dist/compare/index.js +246 -0
- package/dist/compare/index.js.map +1 -0
- package/dist/compare/ssim.d.ts +2 -0
- package/dist/compare/ssim.js +46 -0
- package/dist/compare/ssim.js.map +1 -0
- package/dist/compiler/chrome.d.ts +7 -0
- package/dist/compiler/chrome.js +94 -0
- package/dist/compiler/chrome.js.map +1 -0
- package/dist/compiler/compile.d.ts +2 -0
- package/dist/compiler/compile.js +432 -0
- package/dist/compiler/compile.js.map +1 -0
- package/dist/compiler/markdown.d.ts +26 -0
- package/dist/compiler/markdown.js +439 -0
- package/dist/compiler/markdown.js.map +1 -0
- package/dist/compiler/tokens.d.ts +13 -0
- package/dist/compiler/tokens.js +127 -0
- package/dist/compiler/tokens.js.map +1 -0
- package/dist/container.d.ts +47 -0
- package/dist/container.js +309 -0
- package/dist/container.js.map +1 -0
- package/dist/engine-entry.d.ts +1 -0
- package/dist/engine-entry.js +71 -0
- package/dist/engine-entry.js.map +1 -0
- package/dist/export-keynote/keynote.d.ts +10 -0
- package/dist/export-keynote/keynote.js +58 -0
- package/dist/export-keynote/keynote.js.map +1 -0
- package/dist/export-pptx/embed-fonts.d.ts +5 -0
- package/dist/export-pptx/embed-fonts.js +159 -0
- package/dist/export-pptx/embed-fonts.js.map +1 -0
- package/dist/export-pptx/inject-anim.d.ts +28 -0
- package/dist/export-pptx/inject-anim.js +150 -0
- package/dist/export-pptx/inject-anim.js.map +1 -0
- package/dist/export-pptx/pptx.d.ts +10 -0
- package/dist/export-pptx/pptx.js +425 -0
- package/dist/export-pptx/pptx.js.map +1 -0
- package/dist/export-pptx/transitions.d.ts +16 -0
- package/dist/export-pptx/transitions.js +82 -0
- package/dist/export-pptx/transitions.js.map +1 -0
- package/dist/import/emit.d.ts +5 -0
- package/dist/import/emit.js +274 -0
- package/dist/import/emit.js.map +1 -0
- package/dist/import/index.d.ts +21 -0
- package/dist/import/index.js +192 -0
- package/dist/import/index.js.map +1 -0
- package/dist/import/pptx.d.ts +117 -0
- package/dist/import/pptx.js +1043 -0
- package/dist/import/pptx.js.map +1 -0
- package/dist/import/raster-com.d.ts +27 -0
- package/dist/import/raster-com.js +113 -0
- package/dist/import/raster-com.js.map +1 -0
- package/dist/import/raster-extension.d.ts +35 -0
- package/dist/import/raster-extension.js +27 -0
- package/dist/import/raster-extension.js.map +1 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.js +174 -0
- package/dist/index.js.map +1 -0
- package/dist/install/detect.d.ts +17 -0
- package/dist/install/detect.js +82 -0
- package/dist/install/detect.js.map +1 -0
- package/dist/install/index.d.ts +20 -0
- package/dist/install/index.js +126 -0
- package/dist/install/index.js.map +1 -0
- package/dist/install/registry.d.ts +33 -0
- package/dist/install/registry.js +169 -0
- package/dist/install/registry.js.map +1 -0
- package/dist/install/skills.d.ts +17 -0
- package/dist/install/skills.js +72 -0
- package/dist/install/skills.js.map +1 -0
- package/dist/master-io.d.ts +7 -0
- package/dist/master-io.js +55 -0
- package/dist/master-io.js.map +1 -0
- package/dist/mcp/server.d.ts +3 -0
- package/dist/mcp/server.js +114 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/optimize/export-optimize.d.ts +21 -0
- package/dist/optimize/export-optimize.js +167 -0
- package/dist/optimize/export-optimize.js.map +1 -0
- package/dist/parser/frontmatter.d.ts +8 -0
- package/dist/parser/frontmatter.js +45 -0
- package/dist/parser/frontmatter.js.map +1 -0
- package/dist/parser/parse.d.ts +2 -0
- package/dist/parser/parse.js +184 -0
- package/dist/parser/parse.js.map +1 -0
- package/dist/render/anim.d.ts +50 -0
- package/dist/render/anim.js +213 -0
- package/dist/render/anim.js.map +1 -0
- package/dist/render/charts.d.ts +3 -0
- package/dist/render/charts.js +171 -0
- package/dist/render/charts.js.map +1 -0
- package/dist/render/css.d.ts +3 -0
- package/dist/render/css.js +183 -0
- package/dist/render/css.js.map +1 -0
- package/dist/render/echarts-lib.generated.d.ts +1 -0
- package/dist/render/echarts-lib.generated.js +7 -0
- package/dist/render/echarts-lib.generated.js.map +1 -0
- package/dist/render/html.d.ts +5 -0
- package/dist/render/html.js +186 -0
- package/dist/render/html.js.map +1 -0
- package/dist/render/inject.d.ts +12 -0
- package/dist/render/inject.js +19 -0
- package/dist/render/inject.js.map +1 -0
- package/dist/render/mermaid-lib.generated.d.ts +1 -0
- package/dist/render/mermaid-lib.generated.js +7 -0
- package/dist/render/mermaid-lib.generated.js.map +1 -0
- package/dist/render/runtime.d.ts +1 -0
- package/dist/render/runtime.js +393 -0
- package/dist/render/runtime.js.map +1 -0
- package/dist/render-pdf/pdf.d.ts +9 -0
- package/dist/render-pdf/pdf.js +53 -0
- package/dist/render-pdf/pdf.js.map +1 -0
- package/dist/render-png/montage.d.ts +14 -0
- package/dist/render-png/montage.js +75 -0
- package/dist/render-png/montage.js.map +1 -0
- package/dist/render-png/shoot.d.ts +25 -0
- package/dist/render-png/shoot.js +79 -0
- package/dist/render-png/shoot.js.map +1 -0
- package/dist/scaffold.d.ts +9 -0
- package/dist/scaffold.js +36 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/types.d.ts +212 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/dist/util.d.ts +6 -0
- package/dist/util.js +28 -0
- package/dist/util.js.map +1 -0
- package/package.json +66 -0
- package/skills/slaide/SKILL.md +64 -0
- package/skills/slaide/agents/openai.yaml +12 -0
- package/skills/slaide/examples/branded-deck.slaide +198 -0
- package/skills/slaide/examples/branded-theme.slaide.yaml +187 -0
- package/skills/slaide/examples/sample.slaide +98 -0
- package/skills/slaide/reference.md +177 -0
- package/skills/slaide/themes.md +171 -0
- package/themes/aurora.slaide.yaml +136 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export declare const SLAIDEC_FORMAT = "slaidec/1";
|
|
2
|
+
export interface OpenedDeck {
|
|
3
|
+
/** Absolute path to a real, on-disk `.slaide` file to read. */
|
|
4
|
+
deckFile: string;
|
|
5
|
+
/** Directory the deck's master/assets resolve against. */
|
|
6
|
+
deckDir: string;
|
|
7
|
+
/** Set only when the input was a `.slaidec`; carries info needed to write edits back. */
|
|
8
|
+
container: {
|
|
9
|
+
path: string;
|
|
10
|
+
extractDir: string;
|
|
11
|
+
} | null;
|
|
12
|
+
}
|
|
13
|
+
/** Is this path a `.slaidec` container — by extension, or by ZIP magic (PK\x03\x04)? */
|
|
14
|
+
export declare function isSlaidec(path: string): boolean;
|
|
15
|
+
export interface PackResult {
|
|
16
|
+
out: string;
|
|
17
|
+
bytes: number;
|
|
18
|
+
files: number;
|
|
19
|
+
entryDeck: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Build a `.slaidec` from a deck file OR a working folder.
|
|
23
|
+
* - folder input: zip its files as-is (everything is already self-relative).
|
|
24
|
+
* - deck-file input: curate deck + resolved master + sibling assets/.
|
|
25
|
+
*/
|
|
26
|
+
export declare function packDeck(input: string, outPath: string, opts?: {
|
|
27
|
+
force?: boolean;
|
|
28
|
+
image?: import('./optimize/export-optimize.js').ImageOpts;
|
|
29
|
+
}): Promise<PackResult>;
|
|
30
|
+
export interface UnpackResult {
|
|
31
|
+
outDir: string;
|
|
32
|
+
files: number;
|
|
33
|
+
entryDeck: string;
|
|
34
|
+
}
|
|
35
|
+
/** Extract a `.slaidec` to a folder (the editable working form). */
|
|
36
|
+
export declare function unpackDeck(slaidecPath: string, outDir: string, opts?: {
|
|
37
|
+
force?: boolean;
|
|
38
|
+
}): Promise<UnpackResult>;
|
|
39
|
+
/** Re-zip a (possibly edited) extraction back into its `.slaidec` (used after viewer edits). */
|
|
40
|
+
export declare function repackContainer(extractDir: string, slaidecPath: string): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Resolve any deck input — a `.slaide` file, a working folder, or a `.slaidec` —
|
|
43
|
+
* to a real on-disk deck file + its directory. `.slaidec` inputs are extracted to a
|
|
44
|
+
* content-addressed cache under the temp dir (reused until the file changes), so the
|
|
45
|
+
* rest of the pipeline reads ordinary files with zero special-casing.
|
|
46
|
+
*/
|
|
47
|
+
export declare function openDeck(input: string): Promise<OpenedDeck>;
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
// Copyright 2026 AIVory, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// @slaide/container — the `.slaidec` file variant: a ZIP that bundles a deck +
|
|
4
|
+
// its master + all referenced assets into ONE shareable, compressed file.
|
|
5
|
+
//
|
|
6
|
+
// This is purely an *alternative* distribution form. The normal working form —
|
|
7
|
+
// a folder with `deck.slaide` + `master.slaide.yaml` + `assets/` — is untouched
|
|
8
|
+
// and stays the editable source of truth. A `.slaidec` is just that folder zipped:
|
|
9
|
+
// the deck text inside keeps its ordinary grammar (`master: ./master.slaide.yaml`,
|
|
10
|
+
// `assets/...`), so once extracted it renders through the unchanged pipeline with
|
|
11
|
+
// no special-casing.
|
|
12
|
+
//
|
|
13
|
+
// slaide pack <deck|folder> → one .slaidec
|
|
14
|
+
// slaide unpack <.slaidec> → the folder back
|
|
15
|
+
// every read command (build/render/view/export/validate/…) opens a .slaidec
|
|
16
|
+
// transparently via openDeck().
|
|
17
|
+
import JSZip from 'jszip';
|
|
18
|
+
import { createHash } from 'node:crypto';
|
|
19
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync, statSync, readdirSync, rmSync, } from 'node:fs';
|
|
20
|
+
import { dirname, resolve, join, basename, relative, sep } from 'node:path';
|
|
21
|
+
import { fileURLToPath } from 'node:url';
|
|
22
|
+
import { tmpdir } from 'node:os';
|
|
23
|
+
import yaml from 'js-yaml';
|
|
24
|
+
export const SLAIDEC_FORMAT = 'slaidec/1';
|
|
25
|
+
// Already-compressed payloads: STORE them (deflate would waste CPU and can grow them).
|
|
26
|
+
const STORE_EXT = new Set([
|
|
27
|
+
'.png', '.jpg', '.jpeg', '.webp', '.gif', '.avif',
|
|
28
|
+
'.mp4', '.webm', '.mov', '.m4v', '.ogv',
|
|
29
|
+
'.mp3', '.ogg', '.m4a', '.aac', '.wav',
|
|
30
|
+
'.woff', '.woff2', '.zip', '.slaidec',
|
|
31
|
+
]);
|
|
32
|
+
// A fixed timestamp so re-packing identical content yields byte-identical archives
|
|
33
|
+
// (stable in git, idempotent `pack`). ZIP's epoch floor is 1980-01-01.
|
|
34
|
+
const FIXED_DATE = new Date(Date.UTC(1980, 0, 1, 0, 0, 0));
|
|
35
|
+
function extOf(p) {
|
|
36
|
+
const b = basename(p);
|
|
37
|
+
const i = b.lastIndexOf('.');
|
|
38
|
+
return i < 0 ? '' : b.slice(i).toLowerCase();
|
|
39
|
+
}
|
|
40
|
+
/** Is this path a `.slaidec` container — by extension, or by ZIP magic (PK\x03\x04)? */
|
|
41
|
+
export function isSlaidec(path) {
|
|
42
|
+
if (extOf(path) === '.slaidec')
|
|
43
|
+
return true;
|
|
44
|
+
if (extOf(path) === '.slaide')
|
|
45
|
+
return false; // the text form is never a container
|
|
46
|
+
try {
|
|
47
|
+
if (!statSync(path).isFile())
|
|
48
|
+
return false;
|
|
49
|
+
const fd = readFileSync(path);
|
|
50
|
+
return fd.length >= 4 && fd[0] === 0x50 && fd[1] === 0x4b && fd[2] === 0x03 && fd[3] === 0x04;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** All files under `dir`, as archive-relative POSIX paths (sorted), skipping junk. */
|
|
57
|
+
function walkFiles(dir) {
|
|
58
|
+
const out = [];
|
|
59
|
+
const skip = new Set(['.git', 'node_modules', '.DS_Store', 'Thumbs.db']);
|
|
60
|
+
const recur = (d) => {
|
|
61
|
+
for (const ent of readdirSync(d, { withFileTypes: true })) {
|
|
62
|
+
if (skip.has(ent.name))
|
|
63
|
+
continue;
|
|
64
|
+
const abs = join(d, ent.name);
|
|
65
|
+
if (ent.isDirectory())
|
|
66
|
+
recur(abs);
|
|
67
|
+
else if (ent.isFile() && extOf(abs) !== '.slaidec')
|
|
68
|
+
out.push(abs); // never nest a container
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
recur(dir);
|
|
72
|
+
return out.map((a) => relative(dir, a).split(sep).join('/')).sort();
|
|
73
|
+
}
|
|
74
|
+
/** Find the entry deck inside a folder: the manifest's `deck`, else the single root `.slaide`. */
|
|
75
|
+
function findEntryDeck(dir) {
|
|
76
|
+
const manifestPath = join(dir, 'slaidec.json');
|
|
77
|
+
if (existsSync(manifestPath)) {
|
|
78
|
+
try {
|
|
79
|
+
const m = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
80
|
+
if (m && typeof m.deck === 'string' && existsSync(join(dir, m.deck)))
|
|
81
|
+
return m.deck;
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
/* fall through to convention */
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const roots = readdirSync(dir).filter((f) => f.endsWith('.slaide') && statSync(join(dir, f)).isFile());
|
|
88
|
+
if (roots.length === 1)
|
|
89
|
+
return roots[0];
|
|
90
|
+
if (roots.length === 0)
|
|
91
|
+
throw new Error(`No .slaide deck found in ${dir}`);
|
|
92
|
+
throw new Error(`Multiple .slaide decks in ${dir} (${roots.join(', ')}); add a slaidec.json naming the entry "deck".`);
|
|
93
|
+
}
|
|
94
|
+
/** Build a deterministic ZIP from an archive-path → bytes map. */
|
|
95
|
+
async function zipEntries(entries) {
|
|
96
|
+
const zip = new JSZip();
|
|
97
|
+
for (const path of [...entries.keys()].sort()) {
|
|
98
|
+
const data = entries.get(path);
|
|
99
|
+
const store = STORE_EXT.has(extOf(path));
|
|
100
|
+
zip.file(path, data, {
|
|
101
|
+
date: FIXED_DATE,
|
|
102
|
+
compression: store ? 'STORE' : 'DEFLATE',
|
|
103
|
+
compressionOptions: store ? undefined : { level: 9 },
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
// platform DOS (default) keeps output stable across OSes.
|
|
107
|
+
return zip.generateAsync({ type: 'nodebuffer', platform: 'DOS' });
|
|
108
|
+
}
|
|
109
|
+
/** Resolve the master a deck references, mirroring core resolveMasterPath (with bundled default). */
|
|
110
|
+
function resolveDeckMaster(deckPath) {
|
|
111
|
+
const src = readFileSync(deckPath, 'utf8');
|
|
112
|
+
const head = readHeadmatter(src);
|
|
113
|
+
const ref = typeof head.master === 'string' ? head.master : null;
|
|
114
|
+
const deckDir = dirname(resolve(deckPath));
|
|
115
|
+
if (ref) {
|
|
116
|
+
const abs = resolve(deckDir, ref);
|
|
117
|
+
return { masterPath: abs, ref };
|
|
118
|
+
}
|
|
119
|
+
// No master: ref → the bundled default theme (themes/aurora.slaide.yaml at repo root).
|
|
120
|
+
const def = resolve(dirname(fileURLToPath(import.meta.url)), '../themes/aurora.slaide.yaml');
|
|
121
|
+
return { masterPath: def, ref: null };
|
|
122
|
+
}
|
|
123
|
+
/** Cheap headmatter read (first `---`…`---` block) without importing the full parser. */
|
|
124
|
+
function readHeadmatter(src) {
|
|
125
|
+
const lines = src.split(/\r?\n/);
|
|
126
|
+
if (lines[0]?.trim() !== '---')
|
|
127
|
+
return {};
|
|
128
|
+
const end = lines.slice(1).findIndex((l) => l.trim() === '---');
|
|
129
|
+
if (end < 0)
|
|
130
|
+
return {};
|
|
131
|
+
try {
|
|
132
|
+
const obj = yaml.load(lines.slice(1, end + 1).join('\n'));
|
|
133
|
+
return obj && typeof obj === 'object' && !Array.isArray(obj) ? obj : {};
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return {};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/** Curate the entries for packing a single deck FILE: deck + resolved master + sibling assets/. */
|
|
140
|
+
function stageDeckFile(deckPath) {
|
|
141
|
+
const entries = new Map();
|
|
142
|
+
const deckDir = dirname(resolve(deckPath));
|
|
143
|
+
const deckName = basename(deckPath);
|
|
144
|
+
let deckText = readFileSync(deckPath, 'utf8');
|
|
145
|
+
const { masterPath, ref } = resolveDeckMaster(deckPath);
|
|
146
|
+
if (!existsSync(masterPath)) {
|
|
147
|
+
throw new Error(`pack: master not found (${ref ?? 'bundled default'}) for ${deckName}`);
|
|
148
|
+
}
|
|
149
|
+
const masterInsideDeckDir = resolve(masterPath).startsWith(resolve(deckDir) + sep);
|
|
150
|
+
let masterArchivePath;
|
|
151
|
+
if (ref && masterInsideDeckDir) {
|
|
152
|
+
// Keep the deck's existing relative reference verbatim.
|
|
153
|
+
masterArchivePath = relative(deckDir, resolve(masterPath)).split(sep).join('/');
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
// Master lives outside the deck folder (or is the bundled default): copy it to the
|
|
157
|
+
// root and point the deck at it. Rewrite only the `master:` headmatter line.
|
|
158
|
+
masterArchivePath = 'master.slaide.yaml';
|
|
159
|
+
deckText = rewriteMasterRef(deckText, './master.slaide.yaml');
|
|
160
|
+
}
|
|
161
|
+
entries.set(masterArchivePath, readFileSync(masterPath));
|
|
162
|
+
entries.set(deckName, Buffer.from(deckText, 'utf8'));
|
|
163
|
+
// Sibling assets/ folder (the standard layout) travels along.
|
|
164
|
+
const assetsDir = join(deckDir, 'assets');
|
|
165
|
+
if (existsSync(assetsDir) && statSync(assetsDir).isDirectory()) {
|
|
166
|
+
for (const rel of walkFiles(assetsDir)) {
|
|
167
|
+
entries.set('assets/' + rel, readFileSync(join(assetsDir, rel)));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return { entries, entryName: deckName };
|
|
171
|
+
}
|
|
172
|
+
/** Replace the value of the top-level `master:` headmatter key (within the first `---` block). */
|
|
173
|
+
function rewriteMasterRef(src, newRef) {
|
|
174
|
+
const lines = src.split(/\r?\n/);
|
|
175
|
+
if (lines[0]?.trim() !== '---')
|
|
176
|
+
return src;
|
|
177
|
+
for (let i = 1; i < lines.length; i++) {
|
|
178
|
+
if (lines[i].trim() === '---')
|
|
179
|
+
break; // end of headmatter
|
|
180
|
+
if (/^master\s*:/.test(lines[i])) {
|
|
181
|
+
lines[i] = `master: ${newRef}`;
|
|
182
|
+
return lines.join('\n');
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return src;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Build a `.slaidec` from a deck file OR a working folder.
|
|
189
|
+
* - folder input: zip its files as-is (everything is already self-relative).
|
|
190
|
+
* - deck-file input: curate deck + resolved master + sibling assets/.
|
|
191
|
+
*/
|
|
192
|
+
export async function packDeck(input, outPath, opts = {}) {
|
|
193
|
+
const abs = resolve(input);
|
|
194
|
+
if (!existsSync(abs))
|
|
195
|
+
throw new Error(`pack: input not found: ${input}`);
|
|
196
|
+
if (existsSync(outPath) && !opts.force)
|
|
197
|
+
throw new Error(`pack: ${outPath} exists (use --force)`);
|
|
198
|
+
let entries;
|
|
199
|
+
let entryName;
|
|
200
|
+
if (statSync(abs).isDirectory()) {
|
|
201
|
+
entries = new Map();
|
|
202
|
+
for (const rel of walkFiles(abs)) {
|
|
203
|
+
if (rel === 'slaidec.json')
|
|
204
|
+
continue; // regenerated below
|
|
205
|
+
entries.set(rel, readFileSync(join(abs, rel)));
|
|
206
|
+
}
|
|
207
|
+
entryName = findEntryDeck(abs);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
({ entries, entryName } = stageDeckFile(abs));
|
|
211
|
+
}
|
|
212
|
+
const manifest = { format: SLAIDEC_FORMAT, deck: entryName };
|
|
213
|
+
entries.set('slaidec.json', Buffer.from(JSON.stringify(manifest, null, 2) + '\n', 'utf8'));
|
|
214
|
+
// Optional: downscale/recompress raster assets (format-preserving, so refs stay valid).
|
|
215
|
+
if (opts.image) {
|
|
216
|
+
const { optimizeImageBuffers } = await import('./optimize/export-optimize.js');
|
|
217
|
+
const imgs = [...entries].filter(([n]) => /\.(png|jpe?g|webp)$/i.test(n)).map(([name, buf]) => ({ name, buf }));
|
|
218
|
+
if (imgs.length) {
|
|
219
|
+
const optimized = await optimizeImageBuffers(imgs, opts.image);
|
|
220
|
+
for (const [name, buf] of optimized)
|
|
221
|
+
entries.set(name, buf);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const buf = await zipEntries(entries);
|
|
225
|
+
mkdirSync(dirname(resolve(outPath)), { recursive: true });
|
|
226
|
+
writeFileSync(outPath, buf);
|
|
227
|
+
return { out: outPath, bytes: buf.length, files: entries.size, entryDeck: entryName };
|
|
228
|
+
}
|
|
229
|
+
/** Extract a `.slaidec` to a folder (the editable working form). */
|
|
230
|
+
export async function unpackDeck(slaidecPath, outDir, opts = {}) {
|
|
231
|
+
if (!existsSync(slaidecPath))
|
|
232
|
+
throw new Error(`unpack: file not found: ${slaidecPath}`);
|
|
233
|
+
if (existsSync(outDir) && readdirSync(outDir).length > 0 && !opts.force) {
|
|
234
|
+
throw new Error(`unpack: ${outDir} is not empty (use --force)`);
|
|
235
|
+
}
|
|
236
|
+
const files = await extractTo(slaidecPath, outDir);
|
|
237
|
+
return { outDir, files: files.length, entryDeck: findEntryDeck(outDir) };
|
|
238
|
+
}
|
|
239
|
+
/** Re-zip a (possibly edited) extraction back into its `.slaidec` (used after viewer edits). */
|
|
240
|
+
export async function repackContainer(extractDir, slaidecPath) {
|
|
241
|
+
await packDeck(extractDir, slaidecPath, { force: true });
|
|
242
|
+
}
|
|
243
|
+
/** Low-level: extract every entry of a `.slaidec` into `dir`. Returns written archive paths. */
|
|
244
|
+
async function extractTo(slaidecPath, dir) {
|
|
245
|
+
let zip;
|
|
246
|
+
try {
|
|
247
|
+
zip = await JSZip.loadAsync(readFileSync(slaidecPath));
|
|
248
|
+
}
|
|
249
|
+
catch (e) {
|
|
250
|
+
throw new Error(`Not a valid .slaidec (corrupt or not a ZIP): ${slaidecPath} — ${e.message}`);
|
|
251
|
+
}
|
|
252
|
+
mkdirSync(dir, { recursive: true });
|
|
253
|
+
const written = [];
|
|
254
|
+
for (const [name, entry] of Object.entries(zip.files)) {
|
|
255
|
+
if (entry.dir)
|
|
256
|
+
continue;
|
|
257
|
+
const dest = join(dir, name);
|
|
258
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
259
|
+
writeFileSync(dest, await entry.async('nodebuffer'));
|
|
260
|
+
written.push(name);
|
|
261
|
+
}
|
|
262
|
+
if (!written.length)
|
|
263
|
+
throw new Error(`Empty .slaidec (no entries): ${slaidecPath}`);
|
|
264
|
+
return written;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Resolve any deck input — a `.slaide` file, a working folder, or a `.slaidec` —
|
|
268
|
+
* to a real on-disk deck file + its directory. `.slaidec` inputs are extracted to a
|
|
269
|
+
* content-addressed cache under the temp dir (reused until the file changes), so the
|
|
270
|
+
* rest of the pipeline reads ordinary files with zero special-casing.
|
|
271
|
+
*/
|
|
272
|
+
export async function openDeck(input) {
|
|
273
|
+
const abs = resolve(input);
|
|
274
|
+
if (!existsSync(abs))
|
|
275
|
+
throw new Error(`Deck not found: ${input}`);
|
|
276
|
+
// Directory: the uncompressed working folder.
|
|
277
|
+
if (statSync(abs).isDirectory()) {
|
|
278
|
+
const entry = findEntryDeck(abs);
|
|
279
|
+
return { deckFile: join(abs, entry), deckDir: abs, container: null };
|
|
280
|
+
}
|
|
281
|
+
// Plain `.slaide` (or any non-container file): use it directly — today's behavior.
|
|
282
|
+
if (!isSlaidec(abs)) {
|
|
283
|
+
return { deckFile: abs, deckDir: dirname(abs), container: null };
|
|
284
|
+
}
|
|
285
|
+
// `.slaidec` container: extract to a single cache dir per file (keyed by path), and
|
|
286
|
+
// re-extract whenever the file changes (mtime+size marker stored alongside the dir).
|
|
287
|
+
// Reusing ONE dir per source keeps temp bounded across repeated in-place edits — each
|
|
288
|
+
// edit repacks and bumps the file's mtime, which simply invalidates this same dir.
|
|
289
|
+
const st = statSync(abs);
|
|
290
|
+
const key = createHash('sha1').update(abs).digest('hex').slice(0, 16);
|
|
291
|
+
const extractDir = join(tmpdir(), 'slaide-slaidec', key);
|
|
292
|
+
const markerPath = extractDir + '.src'; // sibling, so it never lands inside the repacked archive
|
|
293
|
+
const marker = `${st.mtimeMs}:${st.size}`;
|
|
294
|
+
let reuse = false;
|
|
295
|
+
try {
|
|
296
|
+
reuse = existsSync(extractDir) && existsSync(join(extractDir, 'slaidec.json')) && readFileSync(markerPath, 'utf8') === marker;
|
|
297
|
+
}
|
|
298
|
+
catch {
|
|
299
|
+
reuse = false;
|
|
300
|
+
}
|
|
301
|
+
if (!reuse) {
|
|
302
|
+
rmSync(extractDir, { recursive: true, force: true });
|
|
303
|
+
await extractTo(abs, extractDir);
|
|
304
|
+
writeFileSync(markerPath, marker, 'utf8');
|
|
305
|
+
}
|
|
306
|
+
const entry = findEntryDeck(extractDir);
|
|
307
|
+
return { deckFile: join(extractDir, entry), deckDir: extractDir, container: { path: abs, extractDir } };
|
|
308
|
+
}
|
|
309
|
+
//# sourceMappingURL=container.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container.js","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Copyright 2026 AIVory, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// Lean engine entry for the native viewer. Only `render` + `export-html` so the
|
|
4
|
+
// `bun build --compile` bundle stays small (no Playwright/MCP). PDF export is done
|
|
5
|
+
// by the viewer's own webview (WebView2 PrintToPdf); this never needs a browser.
|
|
6
|
+
import { writeFileSync } from 'node:fs';
|
|
7
|
+
import { renderFileHtml, openDeck, packDeck, isSlaidec } from './index.js';
|
|
8
|
+
const args = process.argv.slice(2);
|
|
9
|
+
const cmd = args[0];
|
|
10
|
+
const has = (n) => args.includes(n);
|
|
11
|
+
const flag = (n) => {
|
|
12
|
+
const i = args.indexOf(n);
|
|
13
|
+
return i >= 0 ? args[i + 1] : undefined;
|
|
14
|
+
};
|
|
15
|
+
const positional = (n) => args.filter((a) => !a.startsWith('--'))[n];
|
|
16
|
+
async function main() {
|
|
17
|
+
if (cmd === 'render') {
|
|
18
|
+
const deck = positional(1);
|
|
19
|
+
if (!deck) {
|
|
20
|
+
process.stderr.write('render needs a deck path\n');
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
const { deckFile } = await openDeck(deck);
|
|
24
|
+
const mode = has('--print') ? 'print' : 'web';
|
|
25
|
+
const { html, ir } = renderFileHtml(deckFile, { mode, inline: true });
|
|
26
|
+
if (has('--meta')) {
|
|
27
|
+
process.stderr.write(JSON.stringify({ title: ir.meta.title, author: ir.meta.author, slides: ir.slides.length, canvas: ir.canvas, warnings: ir.warnings }) + '\n');
|
|
28
|
+
}
|
|
29
|
+
process.stdout.write(html);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (cmd === 'pack') {
|
|
33
|
+
// Bundle the open deck (+ master + assets) into one shareable .slaidec.
|
|
34
|
+
const deck = positional(1);
|
|
35
|
+
const out = flag('--out');
|
|
36
|
+
if (!deck || !out) {
|
|
37
|
+
process.stderr.write('pack needs <deck> --out <file.slaidec>\n');
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
if (isSlaidec(deck)) {
|
|
41
|
+
// Re-export an already-packed deck: pack the extracted working copy.
|
|
42
|
+
const { container } = await openDeck(deck);
|
|
43
|
+
await packDeck(container ? container.extractDir : deck, out, { force: true });
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
await packDeck(deck, out, { force: true });
|
|
47
|
+
}
|
|
48
|
+
process.stdout.write(out);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (cmd === 'export-html') {
|
|
52
|
+
const deck = positional(1);
|
|
53
|
+
const out = flag('--out');
|
|
54
|
+
if (!deck || !out) {
|
|
55
|
+
process.stderr.write('export-html needs <deck> --out <file>\n');
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
const { deckFile } = await openDeck(deck);
|
|
59
|
+
const { html } = renderFileHtml(deckFile, { mode: 'web', inline: true });
|
|
60
|
+
writeFileSync(out, html, 'utf8');
|
|
61
|
+
process.stdout.write(out);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
process.stderr.write('slaide-engine: usage: render <deck> [--print] [--meta] | export-html <deck> --out <file> | pack <deck> --out <file.slaidec>\n');
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
main().catch((e) => {
|
|
68
|
+
process.stderr.write('slaide-engine: ' + e.message + '\n');
|
|
69
|
+
process.exit(1);
|
|
70
|
+
});
|
|
71
|
+
//# sourceMappingURL=engine-entry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine-entry.js","sourceRoot":"","sources":["../src/engine-entry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface KeynoteOptions {
|
|
2
|
+
out: string;
|
|
3
|
+
}
|
|
4
|
+
/** True only on macOS with Keynote installed (the one path that can write native .key). */
|
|
5
|
+
export declare function keynoteAvailable(): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Export a deck to native Keynote (.key). macOS + Keynote only; throws a clear, actionable
|
|
8
|
+
* error elsewhere so callers can fall back to --pptx.
|
|
9
|
+
*/
|
|
10
|
+
export declare function exportKeynote(deckPath: string, opts: KeynoteOptions, injected?: import('playwright').Browser): Promise<string>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Copyright 2026 AIVory, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// @slaide/export-keynote: slaide deck to native Apple Keynote (.key).
|
|
4
|
+
//
|
|
5
|
+
// There is no cross-platform writer for the proprietary Keynote (.iwa) format, so a real
|
|
6
|
+
// .key is produced only on macOS by driving Keynote.app: we export an editable .pptx (the
|
|
7
|
+
// same high-fidelity pipeline as `--pptx`), then have Keynote open it and save it as native
|
|
8
|
+
// Keynote. On every other platform .key is unavailable; the caller should surface that and
|
|
9
|
+
// offer --pptx instead (PowerPoint files open in Keynote).
|
|
10
|
+
import { spawnSync } from 'node:child_process';
|
|
11
|
+
import { mkdtempSync, rmSync } from 'node:fs';
|
|
12
|
+
import { tmpdir } from 'node:os';
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
import { exportPptx } from '../export-pptx/pptx.js';
|
|
15
|
+
/** True only on macOS with Keynote installed (the one path that can write native .key). */
|
|
16
|
+
export function keynoteAvailable() {
|
|
17
|
+
if (process.platform !== 'darwin')
|
|
18
|
+
return false;
|
|
19
|
+
const r = spawnSync('osascript', ['-e', 'exists application "Keynote"'], { encoding: 'utf8' });
|
|
20
|
+
return r.status === 0 && /true/i.test(r.stdout || '');
|
|
21
|
+
}
|
|
22
|
+
// AppleScript: open the .pptx in Keynote, save it to the .key path (native format), close it.
|
|
23
|
+
const CONVERT = `on run argv
|
|
24
|
+
set inFile to POSIX file (item 1 of argv)
|
|
25
|
+
set outPath to (item 2 of argv)
|
|
26
|
+
tell application "Keynote"
|
|
27
|
+
set theDoc to open inFile
|
|
28
|
+
save theDoc in (POSIX file outPath)
|
|
29
|
+
close theDoc saving no
|
|
30
|
+
end tell
|
|
31
|
+
end run`;
|
|
32
|
+
function convertPptxToKeynote(pptxPath, keyPath) {
|
|
33
|
+
const r = spawnSync('osascript', ['-e', CONVERT, pptxPath, keyPath], { encoding: 'utf8' });
|
|
34
|
+
if (r.status !== 0) {
|
|
35
|
+
throw new Error('Keynote conversion failed: ' + (r.stderr || r.error?.message || 'unknown error').trim());
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Export a deck to native Keynote (.key). macOS + Keynote only; throws a clear, actionable
|
|
40
|
+
* error elsewhere so callers can fall back to --pptx.
|
|
41
|
+
*/
|
|
42
|
+
export async function exportKeynote(deckPath, opts, injected) {
|
|
43
|
+
if (!keynoteAvailable()) {
|
|
44
|
+
throw new Error('Keynote (.key) export is available on macOS with Keynote installed. ' +
|
|
45
|
+
'Export to PowerPoint instead (--pptx); the .pptx opens in Keynote.');
|
|
46
|
+
}
|
|
47
|
+
const work = mkdtempSync(join(tmpdir(), 'slaide-keynote-'));
|
|
48
|
+
try {
|
|
49
|
+
const pptx = join(work, 'deck.pptx');
|
|
50
|
+
await exportPptx(deckPath, { out: pptx }, injected);
|
|
51
|
+
convertPptxToKeynote(pptx, opts.out);
|
|
52
|
+
return opts.out;
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
rmSync(work, { recursive: true, force: true });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=keynote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keynote.js","sourceRoot":"","sources":["../../src/export-keynote/keynote.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,sCAAsC;AACtC,sEAAsE;AACtE,EAAE;AACF,yFAAyF;AACzF,0FAA0F;AAC1F,4FAA4F;AAC5F,2FAA2F;AAC3F,2DAA2D;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAMpD,2FAA2F;AAC3F,MAAM,UAAU,gBAAgB;IAC9B,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAChD,MAAM,CAAC,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,8BAA8B,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/F,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;AACxD,CAAC;AAED,8FAA8F;AAC9F,MAAM,OAAO,GAAG;;;;;;;;QAQR,CAAC;AAET,SAAS,oBAAoB,CAAC,QAAgB,EAAE,OAAe;IAC7D,MAAM,CAAC,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3F,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,6BAA6B,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,EAAE,OAAO,IAAI,eAAe,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC5G,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,QAAgB,EAChB,IAAoB,EACpB,QAAuC;IAEvC,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,sEAAsE;YACpE,oEAAoE,CACvE,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC5D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QACrC,MAAM,UAAU,CAAC,QAAQ,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,QAAQ,CAAC,CAAC;QACpD,oBAAoB,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC,GAAG,CAAC;IAClB,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embed the fonts referenced by `fontImports` (Google Fonts CSS URLs) into a pptx buffer.
|
|
3
|
+
* Returns the buffer unchanged when there's nothing to embed or any fetch fails.
|
|
4
|
+
*/
|
|
5
|
+
export declare function embedFonts(pptxBuf: Buffer, fontImports: string[]): Promise<Buffer>;
|