@jokerized/decksmith 0.1.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.
Files changed (78) hide show
  1. package/README.md +794 -0
  2. package/dist/cli.js +8906 -0
  3. package/dist/deck-runtime.js +55 -0
  4. package/dist/index.js +8590 -0
  5. package/dist/mcp.js +7809 -0
  6. package/dist/server/errors.js +73 -0
  7. package/dist/server/http.js +504 -0
  8. package/dist/server/main.js +91 -0
  9. package/dist/server/options.js +198 -0
  10. package/dist/server/pipeline.js +356 -0
  11. package/dist/server/queue.js +195 -0
  12. package/dist/server/ui.js +1614 -0
  13. package/dist/server/upload.js +232 -0
  14. package/dist/types/cli.d.ts +1 -0
  15. package/dist/types/deck/runtime.d.ts +59 -0
  16. package/dist/types/deck/subtitles.d.ts +101 -0
  17. package/dist/types/emit/archetypes/annotated-figure.d.ts +103 -0
  18. package/dist/types/emit/archetypes/bar-compare.d.ts +30 -0
  19. package/dist/types/emit/archetypes/callout.d.ts +7 -0
  20. package/dist/types/emit/archetypes/claim-figure.d.ts +9 -0
  21. package/dist/types/emit/archetypes/data-table.d.ts +21 -0
  22. package/dist/types/emit/archetypes/equation-walk.d.ts +2 -0
  23. package/dist/types/emit/archetypes/grid.d.ts +16 -0
  24. package/dist/types/emit/archetypes/index.d.ts +19 -0
  25. package/dist/types/emit/archetypes/line-chart.d.ts +22 -0
  26. package/dist/types/emit/archetypes/pipeline.d.ts +81 -0
  27. package/dist/types/emit/archetypes/split-compare.d.ts +2 -0
  28. package/dist/types/emit/archetypes/stack.d.ts +93 -0
  29. package/dist/types/emit/archetypes/title.d.ts +188 -0
  30. package/dist/types/emit/camera.d.ts +397 -0
  31. package/dist/types/emit/composition.d.ts +191 -0
  32. package/dist/types/emit/island.d.ts +19 -0
  33. package/dist/types/emit/kit.d.ts +256 -0
  34. package/dist/types/emit/svg.d.ts +177 -0
  35. package/dist/types/emit/theme.d.ts +65 -0
  36. package/dist/types/emit/themes/index.d.ts +40 -0
  37. package/dist/types/emit/themes/ink.d.ts +12 -0
  38. package/dist/types/emit/themes/mono.d.ts +20 -0
  39. package/dist/types/emit/themes/paper.d.ts +18 -0
  40. package/dist/types/index.d.ts +200 -0
  41. package/dist/types/mcp/main.d.ts +2 -0
  42. package/dist/types/mcp/prereqs.d.ts +22 -0
  43. package/dist/types/mcp/tools.d.ts +212 -0
  44. package/dist/types/narrate/narrate.d.ts +87 -0
  45. package/dist/types/narrate/tts.d.ts +134 -0
  46. package/dist/types/narrate/voices.d.ts +29 -0
  47. package/dist/types/pack/media.d.ts +61 -0
  48. package/dist/types/pack/pack.d.ts +16 -0
  49. package/dist/types/plan/codex.d.ts +24 -0
  50. package/dist/types/plan/duration.d.ts +394 -0
  51. package/dist/types/plan/prompt.d.ts +47 -0
  52. package/dist/types/plan/refs.d.ts +22 -0
  53. package/dist/types/plan/select.d.ts +116 -0
  54. package/dist/types/prefs.d.ts +43 -0
  55. package/dist/types/render/captions.d.ts +108 -0
  56. package/dist/types/render/ffmpeg.d.ts +129 -0
  57. package/dist/types/render/render.d.ts +123 -0
  58. package/dist/types/render/timing.d.ts +290 -0
  59. package/dist/types/server/errors.d.ts +11 -0
  60. package/dist/types/server/http.d.ts +57 -0
  61. package/dist/types/server/main.d.ts +1 -0
  62. package/dist/types/server/options.d.ts +90 -0
  63. package/dist/types/server/pipeline.d.ts +21 -0
  64. package/dist/types/server/queue.d.ts +105 -0
  65. package/dist/types/server/ui.d.ts +9 -0
  66. package/dist/types/server/upload.d.ts +107 -0
  67. package/dist/types/source/assets.d.ts +11 -0
  68. package/dist/types/source/fonts.d.ts +15 -0
  69. package/dist/types/source/markdown.d.ts +8 -0
  70. package/dist/types/types.d.ts +1992 -0
  71. package/dist/types/verify/budget.d.ts +41 -0
  72. package/dist/types/verify/check.d.ts +78 -0
  73. package/dist/types/verify/drift.d.ts +158 -0
  74. package/dist/types/verify/fidelity.d.ts +247 -0
  75. package/dist/types/verify/index.d.ts +207 -0
  76. package/dist/types/verify/overprint.d.ts +133 -0
  77. package/dist/types/verify/typefloor.d.ts +50 -0
  78. package/package.json +84 -0
@@ -0,0 +1,195 @@
1
+ import { explain } from "./errors.js";
2
+ class QueueFullError extends Error {
3
+ hint;
4
+ status = 503;
5
+ constructor(max) {
6
+ super(`The queue is full \u2014 ${max} ${max === 1 ? "job is" : "jobs are"} already waiting.`);
7
+ this.name = "QueueFullError";
8
+ this.hint = "Decks are made one at a time because a render is minutes of CPU and RAM. Try again in a few minutes.";
9
+ }
10
+ }
11
+ class Queue {
12
+ #jobs = /* @__PURE__ */ new Map();
13
+ #waiting = [];
14
+ #watchers = /* @__PURE__ */ new Map();
15
+ #maxQueued;
16
+ #ttlMs;
17
+ #maxLog;
18
+ #now;
19
+ #onExpire;
20
+ #running;
21
+ constructor(opts = {}) {
22
+ this.#maxQueued = opts.maxQueued ?? 8;
23
+ this.#ttlMs = opts.ttlMs ?? 2 * 60 * 6e4;
24
+ this.#maxLog = opts.maxLog ?? 400;
25
+ this.#now = opts.now ?? Date.now;
26
+ this.#onExpire = opts.onExpire ?? (() => {
27
+ });
28
+ }
29
+ get depth() {
30
+ return this.#waiting.length;
31
+ }
32
+ get running() {
33
+ return this.#running;
34
+ }
35
+ /**
36
+ * Take a job, or refuse. Refusing is the point: an unbounded queue on a
37
+ * one-at-a-time worker is a promise the server cannot keep, and a caller told
38
+ * "position 400" has been lied to more politely than one told "full".
39
+ */
40
+ submit(input) {
41
+ if (this.#waiting.length >= this.#maxQueued) throw new QueueFullError(this.#maxQueued);
42
+ const job = {
43
+ id: input.id,
44
+ dir: input.dir,
45
+ state: "queued",
46
+ steps: input.stages.map((name) => ({ name, state: "pending" })),
47
+ log: [],
48
+ dropped: 0,
49
+ createdAt: this.#now(),
50
+ run: input.run
51
+ };
52
+ this.#jobs.set(job.id, job);
53
+ this.#waiting.push(job.id);
54
+ const ahead = this.#waiting.length - 1 + (this.#running ? 1 : 0);
55
+ this.#note(
56
+ job,
57
+ this.#waiting.length === 1 && !this.#running ? "queued" : `queued behind ${ahead} ${ahead === 1 ? "job" : "jobs"}`
58
+ );
59
+ for (const id of this.#waiting) this.#emit(id);
60
+ void this.#pump();
61
+ return this.view(job.id);
62
+ }
63
+ view(id) {
64
+ const job = this.#jobs.get(id);
65
+ if (!job) return void 0;
66
+ const at = this.#waiting.indexOf(id);
67
+ return {
68
+ id: job.id,
69
+ state: job.state,
70
+ ...job.stage ? { stage: job.stage } : {},
71
+ steps: job.steps.map((s) => ({ ...s })),
72
+ log: job.dropped ? [`\u2026 ${job.dropped} earlier line(s) dropped`, ...job.log] : [...job.log],
73
+ ...job.error ? { error: job.error } : {},
74
+ ...job.result ? { result: job.result } : {},
75
+ ...at >= 0 ? { queuePosition: at + 1 } : {},
76
+ createdAt: job.createdAt,
77
+ ms: (job.endedAt ?? this.#now()) - job.createdAt
78
+ };
79
+ }
80
+ /** Subscribe to changes for one job. Returns the unsubscribe. */
81
+ watch(id, fn) {
82
+ const set = this.#watchers.get(id) ?? /* @__PURE__ */ new Set();
83
+ set.add(fn);
84
+ this.#watchers.set(id, set);
85
+ return () => {
86
+ set.delete(fn);
87
+ if (set.size === 0) this.#watchers.delete(id);
88
+ };
89
+ }
90
+ /**
91
+ * Drop every job whose time is up and report their ids, so the caller can
92
+ * delete the directories. A running job is never swept, however old — the TTL
93
+ * measures how long an ANSWER is kept, not how long work may take.
94
+ */
95
+ sweep() {
96
+ const cutoff = this.#now() - this.#ttlMs;
97
+ const expired = [];
98
+ for (const job of [...this.#jobs.values()]) {
99
+ if (job.state === "running" || job.state === "queued") continue;
100
+ if ((job.endedAt ?? job.createdAt) > cutoff) continue;
101
+ this.#jobs.delete(job.id);
102
+ this.#watchers.delete(job.id);
103
+ expired.push(job.id);
104
+ this.#onExpire(job.id, job.dir);
105
+ }
106
+ return expired;
107
+ }
108
+ /* ---------------------------------------------------------------- internals */
109
+ async #pump() {
110
+ if (this.#running) return;
111
+ const id = this.#waiting.shift();
112
+ if (!id) return;
113
+ const job = this.#jobs.get(id);
114
+ if (!job) return void this.#pump();
115
+ this.#running = id;
116
+ job.state = "running";
117
+ this.#note(job, "running");
118
+ for (const other of this.#waiting) this.#emit(other);
119
+ try {
120
+ job.result = await job.run(this.#handle(job));
121
+ job.state = "done";
122
+ job.stage = void 0;
123
+ this.#note(job, "done");
124
+ } catch (err) {
125
+ job.state = "error";
126
+ job.error = explain(err);
127
+ const active = job.steps.find((s) => s.state === "running");
128
+ if (active) {
129
+ active.state = "error";
130
+ active.ms = this.#now() - (active.startedAt ?? this.#now());
131
+ }
132
+ this.#note(job, `error: ${job.error.message}`);
133
+ } finally {
134
+ job.endedAt = this.#now();
135
+ this.#running = void 0;
136
+ this.#emit(job.id);
137
+ void this.#pump();
138
+ }
139
+ }
140
+ #handle(job) {
141
+ return {
142
+ id: job.id,
143
+ dir: job.dir,
144
+ begin: (stage, detail) => {
145
+ job.stage = stage;
146
+ const step = this.#step(job, stage);
147
+ step.state = "running";
148
+ step.startedAt = this.#now();
149
+ if (detail) step.detail = detail;
150
+ this.#note(job, `${stage}: started`);
151
+ },
152
+ done: (stage, detail) => {
153
+ const step = this.#step(job, stage);
154
+ step.state = "done";
155
+ step.ms = this.#now() - (step.startedAt ?? this.#now());
156
+ if (detail) step.detail = detail;
157
+ this.#emit(job.id);
158
+ },
159
+ skip: (stage, why) => {
160
+ const step = this.#step(job, stage);
161
+ step.state = "skipped";
162
+ step.detail = why;
163
+ this.#emit(job.id);
164
+ },
165
+ log: (line) => this.#note(job, line)
166
+ };
167
+ }
168
+ /** A stage the caller did not declare still gets a row rather than vanishing. */
169
+ #step(job, stage) {
170
+ const found = job.steps.find((s) => s.name === stage);
171
+ if (found) return found;
172
+ const added = { name: stage, state: "pending" };
173
+ job.steps.push(added);
174
+ return added;
175
+ }
176
+ #note(job, line) {
177
+ job.log.push(line);
178
+ if (job.log.length > this.#maxLog) {
179
+ job.dropped += job.log.length - this.#maxLog;
180
+ job.log.splice(0, job.log.length - this.#maxLog);
181
+ }
182
+ this.#emit(job.id);
183
+ }
184
+ #emit(id) {
185
+ const watchers = this.#watchers.get(id);
186
+ if (!watchers?.size) return;
187
+ const view = this.view(id);
188
+ if (!view) return;
189
+ for (const fn of watchers) fn(view);
190
+ }
191
+ }
192
+ export {
193
+ Queue,
194
+ QueueFullError
195
+ };