dsh-cool-theme 0.4.0 → 0.6.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.
@@ -1 +1 @@
1
- {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../../src/client/presets.ts"],"names":[],"mappings":"AAuCA,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmC0B,CAAA;AAE9C,+FAA+F;AAC/F,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,OAAO,GAAG,QAAQ,CAAA;AAEtD,eAAO,MAAM,aAAa,EAAE;IAAE,KAAK,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAK7D,CAAA"}
1
+ {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../../src/client/presets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAc,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAqCpE,gEAAgE;AAChE,MAAM,MAAM,SAAS,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,SAAS,CAAA;CAAE,CAAA;AAE5E;;;;;GAKG;AACH,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,eAAe,EAAE,SAAS,CAmCtD,CAAA;AAED,+FAA+F;AAC/F,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,OAAO,GAAG,QAAQ,CAAA;AAEtD;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,QAAQ,CAAwC,CAAA;AAE1F,eAAO,MAAM,aAAa,EAAE;IAAE,KAAK,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAQ7D,CAAA"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Browser half of the theme-file transport.
3
+ *
4
+ * The Host owns the files; this module is the only place that knows the wire
5
+ * shape, so the rest of the client keeps working with plain `SavedTheme`
6
+ * records. Every call is same-origin against the Host's own prefix route.
7
+ */
8
+ import type { ThemeDocument } from '../contract.js';
9
+ import { type CustomTheme, type SavedTheme } from './custom.js';
10
+ /** Repair one stored document against the preset its seeds derive from. */
11
+ export declare function documentToSaved(doc: ThemeDocument, fallbackFor: (base: string) => CustomTheme): SavedTheme;
12
+ /** The document payload for one entry; timestamps stay the Host's business. */
13
+ export declare function savedToDocument(entry: SavedTheme): Record<string, unknown>;
14
+ /**
15
+ * The Host answered as something other than this API — its route half is not
16
+ * mounted (the usual cause is a DSH process started before this plugin's host
17
+ * half existed). Distinguished from a write failure because only this one tells
18
+ * the user to restart, and the browser copy is still intact meanwhile.
19
+ */
20
+ export declare class ThemeApiUnavailableError extends Error {
21
+ }
22
+ /** Every stored theme, in the Host's creation-time order (oldest first). */
23
+ export declare function fetchThemes(fallbackFor: (base: string) => CustomTheme): Promise<SavedTheme[]>;
24
+ /** Insert or replace the given entries; resolves with what the Host stored. */
25
+ export declare function pushThemes(entries: SavedTheme[], fallbackFor: (base: string) => CustomTheme): Promise<SavedTheme[]>;
26
+ /** Remove one theme's directory. */
27
+ export declare function removeTheme(id: string): Promise<void>;
28
+ /**
29
+ * Download one theme as an archive. The response is the archive itself rather
30
+ * than JSON, so this is the one call that does not go through {@link callApi}.
31
+ */
32
+ export declare function exportTheme(id: string, name: string): Promise<void>;
33
+ /**
34
+ * Upload one archive. The Host validates it, names the theme and stores it, so
35
+ * a success means the roster already has the theme — the answer carries what to
36
+ * report, not what the client still has to write.
37
+ */
38
+ export declare function importTheme(file: File): Promise<{
39
+ id: string;
40
+ name: string;
41
+ }>;
42
+ /**
43
+ * The themes a browser saved before files became the store, minus those the
44
+ * Host already has.
45
+ *
46
+ * Ids are the join key: a theme another browser already migrated must not be
47
+ * written twice, while one this roster lacks would otherwise disappear from the
48
+ * UI. Callers adopt the result, then stop reading the browser copy.
49
+ */
50
+ export declare function legacyThemesToAdopt(legacy: SavedTheme[], hostThemes: SavedTheme[]): SavedTheme[];
51
+ //# sourceMappingURL=theme-files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-files.d.ts","sourceRoot":"","sources":["../../../src/client/theme-files.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,OAAO,KAAK,EAAc,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAC/D,OAAO,EAAmB,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAEhF,2EAA2E;AAC3E,wBAAgB,eAAe,CAC7B,GAAG,EAAE,aAAa,EAClB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,WAAW,GACzC,UAAU,CAQZ;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAS1E;AAMD;;;;;GAKG;AACH,qBAAa,wBAAyB,SAAQ,KAAK;CAAG;AA4DtD,4EAA4E;AAC5E,wBAAsB,WAAW,CAC/B,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,WAAW,GACzC,OAAO,CAAC,UAAU,EAAE,CAAC,CAEvB;AAED,+EAA+E;AAC/E,wBAAsB,UAAU,CAC9B,OAAO,EAAE,UAAU,EAAE,EACrB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,WAAW,GACzC,OAAO,CAAC,UAAU,EAAE,CAAC,CAMvB;AAED,oCAAoC;AACpC,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3D;AAWD;;;GAGG;AACH,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUzE;AAuCD;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAWnF;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,UAAU,EAAE,EACpB,UAAU,EAAE,UAAU,EAAE,GACvB,UAAU,EAAE,CAGd"}
@@ -1 +1 @@
1
- {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../src/client/theme.tsx"],"names":[],"mappings":"AAyCA,wBAAgB,aAAa,CAAC,GAAG,EAAE,GAAG,QAsQrC"}
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../src/client/theme.tsx"],"names":[],"mappings":"AA8MA,wBAAgB,aAAa,CAAC,GAAG,EAAE,GAAG,QAmhBrC"}
@@ -1,8 +1,21 @@
1
- import { type PresetId } from './presets.js';
1
+ import { type PresetId, type PresetDef } from './presets.js';
2
2
  export declare function buildBaseCss(): string;
3
- export declare function buildOverrides(id: PresetId): Record<string, {
3
+ /**
4
+ * Accepts either a preset id or an already-built `PresetDef` (what a custom
5
+ * theme produces). Both go through the identical merge, so a custom theme is
6
+ * not a special case anywhere downstream.
7
+ */
8
+ export declare function resolvePreset(src: PresetId | PresetDef): {
9
+ light: {
10
+ [x: string]: string;
11
+ };
12
+ dark: {
13
+ [x: string]: string;
14
+ };
15
+ } | null;
16
+ export declare function buildOverrides(src: PresetId | PresetDef): Record<string, {
4
17
  light: string;
5
18
  dark: string;
6
19
  }>;
7
- export declare function buildFullCssFallback(id: PresetId): string;
20
+ export declare function buildFullCssFallback(src: PresetId | PresetDef): string;
8
21
  //# sourceMappingURL=tokens.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../src/client/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAA;AAIrD,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAcD,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAI5F;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,QAAQ,GAAG,MAAM,CAQzD"}
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../src/client/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAA;AAItF,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,QAAQ,GAAG,SAAS;;;;;;;SAatD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAIzG;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAItE"}
@@ -3,4 +3,82 @@
3
3
  */
4
4
  export declare const THEME_STORAGE_KEY = "cool-theme-preset";
5
5
  export declare const THEME_STORAGE_KEY_LEGACY = "cooltea-theme-preset";
6
+ export declare const CUSTOM_PRESET_ID = "custom";
7
+ export declare const CUSTOM_THEME_STORAGE_KEY = "cool-theme-custom";
8
+ export declare const CUSTOM_LIST_STORAGE_KEY = "cool-theme-custom-list";
9
+ export declare const CUSTOM_ACTIVE_STORAGE_KEY = "cool-theme-custom-active";
10
+ export declare const CUSTOM_MIGRATED_STORAGE_KEY = "cool-theme-custom-migrated";
11
+ /**
12
+ * Documents are one directory each — `<root>/<id>/theme.json` — so a theme can
13
+ * later carry media beside its seeds without changing this contract.
14
+ */
15
+ export declare const THEME_FILE_VERSION = 1;
16
+ /** Media kind carried with a theme; the seed payload itself is `theme`. */
17
+ export type ThemeAssetKind = 'image' | 'video';
18
+ /** One media file stored under the theme's `assets/` directory. */
19
+ export type ThemeAsset = {
20
+ /** File name inside `assets/`; unique within the theme. */
21
+ name: string;
22
+ kind: ThemeAssetKind;
23
+ /** Content type the Host serves it back with. */
24
+ mime: string;
25
+ bytes: number;
26
+ };
27
+ /**
28
+ * One theme as it is stored and exchanged. `theme` stays opaque here: the
29
+ * Client owns the seed shape and repairs it against a preset on read, while the
30
+ * Host only ever moves the document in and out of a file.
31
+ */
32
+ export type ThemeDocument = {
33
+ v: number;
34
+ id: string;
35
+ name: string;
36
+ /** Id of the preset the seeds derive from. */
37
+ base: string;
38
+ theme: unknown;
39
+ assets: ThemeAsset[];
40
+ createdAt: string;
41
+ updatedAt: string;
42
+ };
43
+ /**
44
+ * The Host's theme-file API, all below one prefix route. Kept here so the two
45
+ * halves cannot drift on a path.
46
+ */
47
+ export declare const THEME_API_PREFIX = "/cool-theme/api";
48
+ export declare const THEME_API_PATH_THEMES = "/cool-theme/api/themes";
49
+ /**
50
+ * Share archive: one theme directory zipped. The document keeps the name it has
51
+ * on disk, so an archive is a copy of the directory rather than a new format,
52
+ * and media added later travels with it under {@link THEME_ARCHIVE_ASSETS_DIR}.
53
+ */
54
+ export declare const THEME_ARCHIVE_DOCUMENT = "theme.json";
55
+ export declare const THEME_ARCHIVE_ASSETS_DIR = "assets";
56
+ /** Content type of an exported archive, and the extension a name gets. */
57
+ export declare const THEME_ARCHIVE_MIME = "application/zip";
58
+ export declare const THEME_ARCHIVE_EXTENSION = ".zip";
59
+ /**
60
+ * Import bounds. A theme is a small JSON document, so anything past these caps
61
+ * is refused before it is parsed rather than after it has been held in memory.
62
+ */
63
+ export declare const THEME_ARCHIVE_MAX_BYTES: number;
64
+ export declare const THEME_ARCHIVE_MAX_ENTRIES = 256;
65
+ /** Cap on one uncompressed entry, so a zip bomb cannot expand without bound. */
66
+ export declare const THEME_ARCHIVE_MAX_ENTRY_BYTES: number;
67
+ /** Route segments below {@link THEME_API_PATH_THEMES}: `/<id>/export`, `/import`. */
68
+ export declare const THEME_API_SEGMENT_EXPORT = "export";
69
+ export declare const THEME_API_PATH_IMPORT = "/cool-theme/api/themes/import";
70
+ /**
71
+ * Name the Host suggests for a downloaded archive. The archive keeps the
72
+ * theme's name so a user can tell two exports apart, with the characters a
73
+ * filesystem refuses folded to spaces; the id is the fallback for a name that
74
+ * folds away to nothing.
75
+ */
76
+ export declare function archiveFileName(name: string, id: string): string;
77
+ /**
78
+ * `base`, else `${base} 2`, `${base} 3`, … An imported theme keeps the name it
79
+ * was shared under — that name is the point of the share — so a clash is
80
+ * resolved by numbering rather than by renaming the incoming theme. The Host
81
+ * owns this because it owns the roster the names have to be free in.
82
+ */
83
+ export declare function freeThemeName(base: string, taken: readonly string[]): string;
6
84
  //# sourceMappingURL=contract.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/contract.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,eAAO,MAAM,iBAAiB,sBAAsB,CAAA;AACpD,eAAO,MAAM,wBAAwB,yBAAyB,CAAA"}
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/contract.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,eAAO,MAAM,iBAAiB,sBAAsB,CAAA;AACpD,eAAO,MAAM,wBAAwB,yBAAyB,CAAA;AAG9D,eAAO,MAAM,gBAAgB,WAAW,CAAA;AAKxC,eAAO,MAAM,wBAAwB,sBAAsB,CAAA;AAG3D,eAAO,MAAM,uBAAuB,2BAA2B,CAAA;AAI/D,eAAO,MAAM,yBAAyB,6BAA6B,CAAA;AAInE,eAAO,MAAM,2BAA2B,+BAA+B,CAAA;AAMvE;;;GAGG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAA;AAEnC,2EAA2E;AAC3E,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,OAAO,CAAA;AAE9C,mEAAmE;AACnE,MAAM,MAAM,UAAU,GAAG;IACvB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,cAAc,CAAA;IACpB,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,CAAC,EAAE,MAAM,CAAA;IACT,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,UAAU,EAAE,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB,oBAAoB,CAAA;AACjD,eAAO,MAAM,qBAAqB,2BAA+B,CAAA;AAEjE;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,eAAe,CAAA;AAClD,eAAO,MAAM,wBAAwB,WAAW,CAAA;AAEhD,0EAA0E;AAC1E,eAAO,MAAM,kBAAkB,oBAAoB,CAAA;AACnD,eAAO,MAAM,uBAAuB,SAAS,CAAA;AAE7C;;;GAGG;AACH,eAAO,MAAM,uBAAuB,QAAkB,CAAA;AACtD,eAAO,MAAM,yBAAyB,MAAM,CAAA;AAC5C,gFAAgF;AAChF,eAAO,MAAM,6BAA6B,QAAkB,CAAA;AAE5D,qFAAqF;AACrF,eAAO,MAAM,wBAAwB,WAAW,CAAA;AAChD,eAAO,MAAM,qBAAqB,kCAAoC,CAAA;AAEtE;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAQhE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAQ5E"}
@@ -1,9 +1,12 @@
1
1
  /**
2
2
  * Host entry for dsh-cool-theme.
3
- * No host routes needed — theme is purely client-side (localStorage + overrideTokens).
4
- * Keep a minimal apply so the cordis patch has a mount point.
3
+ *
4
+ * Owns the theme files: the browser half cannot touch the filesystem, so every
5
+ * roster change travels over one same-origin prefix route below
6
+ * {@link THEME_API_PREFIX}. The route is the whole host surface — no service is
7
+ * provided, and nothing here interprets the theme payload beyond moving it.
5
8
  */
6
9
  export declare const name = "dsh-cool-theme";
7
10
  export declare const inject: string[];
8
- export declare function apply(_ctx: any): void;
11
+ export declare function apply(ctx: any): void;
9
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/host/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,IAAI,mBAAmB,CAAA;AAEpC,eAAO,MAAM,MAAM,EAAE,MAAM,EAAO,CAAA;AAElC,wBAAgB,KAAK,CAAC,IAAI,EAAE,GAAG,QAAI"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/host/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAkBH,eAAO,MAAM,IAAI,mBAAmB,CAAA;AAEpC,eAAO,MAAM,MAAM,UAAgB,CAAA;AAwKnC,wBAAgB,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CA0DpC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Theme files owned by the Host.
3
+ *
4
+ * One directory per theme below `$DSH_HOME/cool-theme/themes/<id>/`, holding the
5
+ * document at `theme.json` and — once themes carry media — the originals under
6
+ * `assets/`. Keeping a theme a self-contained directory is what makes the later
7
+ * export a copy of that directory rather than a reassembly of scattered rows.
8
+ */
9
+ import type { ThemeAsset, ThemeDocument } from '../contract.js';
10
+ export declare function isThemeId(value: unknown): value is string;
11
+ /**
12
+ * The harness home, resolved the way the rest of DSH resolves it: an explicit
13
+ * `DSH_HOME`, else `~/.dsh`.
14
+ */
15
+ export declare function harnessHome(): string;
16
+ /** Root of every stored theme. */
17
+ export declare function themesRoot(): string;
18
+ /** One theme's own directory. Callers must have validated `id`. */
19
+ export declare function themeDir(id: string): string;
20
+ /** Every stored theme, oldest by creation time first; unreadable directories are skipped. */
21
+ export declare function listThemes(): Promise<ThemeDocument[]>;
22
+ /**
23
+ * Insert or replace one document. `createdAt` is the caller's when the theme is
24
+ * new and the stored value when it already exists, so a later rename or edit
25
+ * cannot rewrite when the theme was made.
26
+ */
27
+ export declare function putTheme(input: {
28
+ id: string;
29
+ name: string;
30
+ base: string;
31
+ theme: unknown;
32
+ assets: ThemeAsset[];
33
+ }): Promise<ThemeDocument>;
34
+ /** Remove one theme directory. A missing directory is already the goal. */
35
+ export declare function deleteTheme(id: string): Promise<void>;
36
+ /**
37
+ * A fresh theme id. The same shape the client mints (`ct_` + time + noise), so
38
+ * an id never says which half created it, and `isThemeId` is the only rule both
39
+ * halves apply.
40
+ */
41
+ export declare function newThemeId(): string;
42
+ /** Absolute path of a theme's media directory; used once themes carry media. */
43
+ export declare function assetsDir(id: string): string;
44
+ //# sourceMappingURL=theme-files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-files.d.ts","sourceRoot":"","sources":["../../../src/host/theme-files.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAc/D,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEzD;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAGpC;AAED,kCAAkC;AAClC,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,mEAAmE;AACnE,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE3C;AAgED,6FAA6F;AAC7F,wBAAsB,UAAU,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAkB3D;AAED;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,KAAK,EAAE;IACpC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,UAAU,EAAE,CAAA;CACrB,GAAG,OAAO,CAAC,aAAa,CAAC,CAezB;AAED,2EAA2E;AAC3E,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3D;AAED;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,gFAAgF;AAChF,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE5C"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Theme sharing: packing one stored theme into an archive and reading one back.
3
+ *
4
+ * An archive is the theme directory itself — the same `theme.json` and `assets/`
5
+ * a theme occupies on disk — so sharing never invents a second format. The Host
6
+ * owns both halves because the browser can neither read the theme's files nor
7
+ * decompress an archive on its behalf.
8
+ *
9
+ * Reading is deliberately strict: an archive either validates as one of ours or
10
+ * is refused with a reason. Nothing half-valid is ever handed to the client to
11
+ * repair, because a foreign or damaged file must not be able to seed the roster.
12
+ */
13
+ import type { ThemeAsset, ThemeDocument } from '../contract.js';
14
+ /** The document as it is packed; the timestamps are the Host's own bookkeeping. */
15
+ type PackedDocument = Pick<ThemeDocument, 'id' | 'name' | 'base' | 'theme' | 'assets'>;
16
+ /** A share refused for a reason worth showing the user. */
17
+ export declare class ArchiveError extends Error {
18
+ }
19
+ /**
20
+ * Pack one theme directory. A theme with no media still gets an archive holding
21
+ * its document alone, so sharing a plain theme needs no second code path.
22
+ */
23
+ export declare function packTheme(id: string): Promise<{
24
+ fileName: string;
25
+ bytes: Buffer;
26
+ document: PackedDocument;
27
+ }>;
28
+ /** An archive's document, validated; anything else throws {@link ArchiveError}. */
29
+ export type UnpackedTheme = {
30
+ /** Created document, ready for the client to give a fresh id and name. */
31
+ document: PackedDocument;
32
+ /** Media carried beside the document, already bounds-checked. */
33
+ assets: {
34
+ name: string;
35
+ bytes: Buffer;
36
+ kind: ThemeAsset['kind'];
37
+ mime: string;
38
+ }[];
39
+ };
40
+ /**
41
+ * Read an archive back into a theme. Only the document and its media are
42
+ * accepted; every path is required to be exactly one of those two shapes, so a
43
+ * directory entry or a nested path is refused rather than normalised.
44
+ */
45
+ export declare function unpackTheme(archive: Buffer): UnpackedTheme;
46
+ export {};
47
+ //# sourceMappingURL=theme-share.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-share.d.ts","sourceRoot":"","sources":["../../../src/host/theme-share.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAWH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAI/D,mFAAmF;AACnF,KAAK,cAAc,GAAG,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC,CAAA;AAmBtF,2DAA2D;AAC3D,qBAAa,YAAa,SAAQ,KAAK;CAAG;AAE1C;;;GAGG;AACH,wBAAsB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IACnD,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,cAAc,CAAA;CACzB,CAAC,CAyCD;AAOD,mFAAmF;AACnF,MAAM,MAAM,aAAa,GAAG;IAC1B,0EAA0E;IAC1E,QAAQ,EAAE,cAAc,CAAA;IACxB,iEAAiE;IACjE,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAClF,CAAA;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CA+E1D"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * The little of ZIP that sharing a theme needs.
3
+ *
4
+ * A theme is one small JSON document plus whatever media sits beside it, so the
5
+ * archive format is worth exactly this much: a writer that emits stored/deflated
6
+ * entries with a central directory, and a reader that walks that directory back.
7
+ * Node owns the compression (`zlib.deflateRawSync` / `inflateRawSync`); the two
8
+ * checksums and the record layout are all that has to be written here, which
9
+ * keeps the plugin dependency-free.
10
+ *
11
+ * Deliberately unsupported, because nothing this plugin writes ever produces
12
+ * them: zip64, encrypted entries, multi-disk archives, and data descriptors.
13
+ */
14
+ export type ZipEntry = {
15
+ /** Path inside the archive, always with forward slashes. */
16
+ name: string;
17
+ data: Buffer;
18
+ };
19
+ /** How a read should select and bound the entries it inflates. */
20
+ export type ReadZipOptions = {
21
+ filter?: (name: string) => boolean;
22
+ /** Largest uncompressed entry to accept; a bigger one is a refusal, not a skip. */
23
+ maxEntryBytes?: number;
24
+ };
25
+ /** CRC-32 of one entry, as the archive records it. */
26
+ export declare function crc32(data: Buffer): number;
27
+ /**
28
+ * Pack entries into one archive. Directory entries are not emitted: every
29
+ * consumer this format targets infers them from the entry paths.
30
+ */
31
+ export declare function createZip(entries: ZipEntry[]): Buffer;
32
+ /**
33
+ * Entry bytes from one archive, with `filter` deciding which entries are worth
34
+ * inflating. Throws on anything this writer would not have produced, so a file
35
+ * that is not one of our archives fails as "unreadable" rather than as a
36
+ * half-parsed theme.
37
+ */
38
+ export declare function readZip(input: Buffer, options?: ReadZipOptions): ZipEntry[];
39
+ //# sourceMappingURL=zip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip.d.ts","sourceRoot":"","sources":["../../../src/host/zip.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAsBH,MAAM,MAAM,QAAQ,GAAG;IACrB,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,kEAAkE;AAClE,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAA;IAClC,mFAAmF;IACnF,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAcD,sDAAsD;AACtD,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM1C;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM,CAwErD;AAUD;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,QAAQ,EAAE,CA0D/E"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * The preset ids, in one place both halves can read.
3
+ *
4
+ * `presets.ts` carries the colour maps and is client-only; the Host needs the
5
+ * same id vocabulary to tell an archive that derives from a preset we ship from
6
+ * one that does not, so the names live here and that file checks itself against
7
+ * them.
8
+ */
9
+ export declare const PRESET_IDS: readonly ["aura", "ayu", "catppuccin", "catppuccin-frappe", "catppuccin-macchiato", "cobalt2", "cursor", "dracula", "dsh", "everforest", "flexoki", "github", "gruvbox", "kanagawa", "lucent-orng", "material", "matrix", "mercury", "monokai", "nightowl", "nord", "onedark", "opencode", "orng", "osaka-jade", "palenight", "rosepine", "solarized", "synthwave84", "system", "tokyonight", "vercel", "vesper", "zenburn"];
10
+ /** One shipped preset id. `native` is a storage alias, not a preset. */
11
+ export type BuiltinPresetId = (typeof PRESET_IDS)[number];
12
+ /**
13
+ * Whether a theme may name `base` and still be resolved here. `native` is the
14
+ * legacy alias for `dsh`, so a theme that carries it stays usable.
15
+ */
16
+ export declare function isKnownBase(value: string): boolean;
17
+ //# sourceMappingURL=presets-ids.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets-ids.d.ts","sourceRoot":"","sources":["../../src/presets-ids.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,eAAO,MAAM,UAAU,8ZAmCb,CAAA;AAEV,wEAAwE;AACxE,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAA;AAEzD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAElD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-cool-theme",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "A plugin for changing themes for DSH, with a number of popular default themes built in.",
5
5
  "type": "module",
6
6
  "license": "MIT",