@tak-ps/cloudtak 13.43.0 → 13.45.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.
@@ -23,7 +23,8 @@ export declare enum WorkerMessageType {
23
23
  Profile_Update = "cloudtak:profile:update",
24
24
  Sync_Start = "cloudtak:sync:start",
25
25
  Sync_Complete = "cloudtak:sync:complete",
26
- Sync_Update = "cloudtak:sync:update"
26
+ Sync_Update = "cloudtak:sync:update",
27
+ Iconset_Change = "cloudtak:iconset:change"
27
28
  }
28
29
  export type WorkerMessage = {
29
30
  type: WorkerMessageType;
@@ -1,11 +1,10 @@
1
1
  import { type DBIcon } from '../database.ts';
2
2
  export interface IconHydrateResult {
3
- /** Iconsets that were added or refreshed during the diff. */
4
- changed: string[];
3
+ added: string[];
4
+ /** Iconsets refetched because the remote `version`/`updated` differs. */
5
+ updated: string[];
5
6
  /** Iconsets that were removed locally because they no longer exist remotely. */
6
7
  removed: string[];
7
- /** True when the diff was skipped because the local cache was fresh. */
8
- skipped: boolean;
9
8
  }
10
9
  export default class Icon {
11
10
  static has(icon: string): Promise<boolean>;
@@ -20,24 +19,22 @@ export default class Icon {
20
19
  static list(iconsetUid: string): Promise<DBIcon[]>;
21
20
  /**
22
21
  * Diff the server iconset list against Dexie and refetch icons for any
23
- * iconsets that are new or whose `version`/`updated` differs.
24
- *
25
- * Behaviour:
26
- * - When Dexie already has data and was refreshed recently the call
27
- * returns immediately (`skipped: true`) and the diff runs in the
28
- * background; the next call will see the updated cache marker.
29
- * - When `force` is true the diff always runs inline.
22
+ * iconsets that are new or whose `version`/`updated` differs. Concurrent
23
+ * calls coalesce onto the in-flight diff.
30
24
  */
31
- static hydrate(opts: {
32
- token: string;
33
- force?: boolean;
34
- }): Promise<IconHydrateResult>;
25
+ static hydrate(): Promise<IconHydrateResult>;
35
26
  /**
36
27
  * Ensure a single iconset is present in Dexie. Returns true if Dexie was
37
28
  * actually updated so the caller can purge stale map images.
38
29
  */
39
- static addIconset(uid: string, opts: {
40
- token: string;
30
+ static addIconset(uid: string, opts?: {
41
31
  force?: boolean;
42
32
  }): Promise<boolean>;
33
+ /**
34
+ * Fetch a single `<iconsetUid>:<path>` icon directly from the API.
35
+ * Used as the network fallback when an icon isn't cached in Dexie yet
36
+ * (e.g. an overlay referencing an iconset that hasn't synced). Returns
37
+ * undefined when the icon can't be retrieved.
38
+ */
39
+ static fetchRemote(id: string): Promise<Blob | undefined>;
43
40
  }
@@ -1,22 +1,23 @@
1
1
  import type { Map as MapLibreMap } from 'maplibre-gl';
2
- import { type DBIconset } from '../../database.ts';
3
2
  export default class IconManager {
4
- private cache;
5
3
  private map;
6
- private loggedMissingImageIds;
4
+ private inflight;
7
5
  private loggedErrors;
8
- private inflightImage;
9
6
  private fallbackBitmap;
10
- private requestedIconsetImageIds;
7
+ /**
8
+ * Image ids registered with the generic fallback bitmap (or recolored
9
+ * from one) because the real icon couldn't be loaded at resolve time.
10
+ * These are retried once the owning iconset lands in Dexie.
11
+ */
12
+ private fallbackIds;
11
13
  constructor(map: MapLibreMap);
12
14
  private logWarnOnce;
13
15
  private logErrorOnce;
14
- static from(uid: string): Promise<DBIconset | undefined>;
15
16
  /**
16
- * MapLibre style sprite descriptor. The custom iconset spritesheets are no
17
- * longer loaded here; icons are served on demand from Dexie via
18
- * `onStyleImageMissing`. Only the small built-in `default` sprite is loaded
19
- * up-front because it provides the CoT-type fallbacks.
17
+ * MapLibre style sprite descriptor. Iconset icons are served on demand
18
+ * from Dexie via the missing style image resolver; only the small
19
+ * built-in `default` sprite is loaded up-front because it provides the
20
+ * CoT-type fallbacks.
20
21
  *
21
22
  * The default sprite itself is also served from the Dexie cache via the
22
23
  * `cloudtak-sprite://` protocol (see `registerSpriteProtocol`) so it
@@ -34,34 +35,41 @@ export default class IconManager {
34
35
  */
35
36
  static registerSpriteProtocol(): void;
36
37
  /**
37
- * Hydrate the local Dexie icon cache from the API.
38
+ * Missing style image resolver entry point. MapLibre awaits the returned
39
+ * promise before rendering the requesting tile, so the image must be
40
+ * registered by the time it settles.
38
41
  *
39
- * This method also handles main-thread concerns like purging stale MapLibre
40
- * images when the local Dexie cache changes.
42
+ * Must never reject: a rejected resolver promise fails the whole image
43
+ * batch for the tile, so failures are logged and the id is left
44
+ * unresolved (MapLibre then fires the legacy `styleimagemissing` event
45
+ * and renders the feature without an icon).
41
46
  */
42
- hydrate(opts?: {
43
- force?: boolean;
44
- }): Promise<void>;
47
+ resolve(id: string): Promise<void>;
48
+ private resolveImage;
45
49
  /**
46
- * Ensure a single iconset is present in Dexie. Used by overlays that
47
- * reference a specific iconset so it is available even if the user-wide
48
- * hydrate hasn't completed yet.
50
+ * Resolve an `<iconsetUid>:<path>` image id from Dexie, falling back to
51
+ * fetching the single icon from the API (for iconsets that haven't been
52
+ * hydrated locally) and finally to a generic point icon.
49
53
  */
50
- addIconset(uid: string, opts?: {
51
- force?: boolean;
52
- }): Promise<void>;
53
- removeIconset(uid: string): Promise<void>;
54
- deleteIconset(uid: string): Promise<void>;
55
- private applyHydrateResult;
56
- private purgeMapImagesForIconset;
57
- onStyleImageMissing(e: {
58
- id: string;
59
- }): Promise<void>;
54
+ private loadIconsetImage;
55
+ private addImage;
60
56
  /**
61
- * Resolve an `<iconsetUid>:<path>` image id from Dexie and register it with
62
- * MapLibre. Falls back to a generic point icon when the icon isn't cached.
57
+ * Remove all MapLibre images belonging to the given iconsets (including
58
+ * colored variants, whose ids share the `<uid>:` prefix). MapLibre
59
+ * re-requests removed images through the missing style image resolver
60
+ * the next time a feature needs them, so purging is all that's required
61
+ * to pick up refreshed Dexie content.
63
62
  */
64
- private loadIconsetImage;
63
+ purgeIconsets(uids: string[]): void;
64
+ /**
65
+ * Retry fallback placeholder images belonging to the given iconsets.
66
+ * Used when an iconset is cached in Dexie for the first time: icons that
67
+ * already resolved successfully (via the network fallback) are identical
68
+ * to the newly cached rows and are left untouched - only ids stuck on
69
+ * the generic fallback bitmap are dropped so they re-resolve.
70
+ */
71
+ purgeFallbacks(uids: string[]): void;
72
+ deleteIconset(uid: string): Promise<void>;
65
73
  /**
66
74
  * Decode an iconset blob into an `ImageBitmap`.
67
75
  *
@@ -80,18 +88,11 @@ export default class IconManager {
80
88
  * set explicitly before rasterizing.
81
89
  */
82
90
  private decodeSvgBlob;
83
- private reloadIconsetImages;
84
- private reloadRequestedIconsetImage;
85
- private removeRequestedImagesForIconset;
86
91
  private getFallbackBitmap;
87
92
  /**
88
- * Get or create a colored version of an icon
89
- */
90
- getColoredIcon(iconId: string, color: string): string;
91
- /**
92
- * Create a colored version of an icon and add it to the map
93
+ * Register a recolored copy of an already-registered base image.
93
94
  */
94
- private createColoredIcon;
95
+ private addColoredImage;
95
96
  /**
96
97
  * Replace white/light pixels with the target color
97
98
  */
@@ -52,6 +52,28 @@ export default class AtlasSync {
52
52
  event(event: SyncEvent): Promise<void>;
53
53
  destroy(): void;
54
54
  private runFullSync;
55
+ /**
56
+ * Hydrate the Dexie icon cache (iconset metadata, icon blobs and built-in
57
+ * sprites) from the API. All bulk icon hydration flows through here; the
58
+ * main thread only loads individual images into MapLibre on demand via
59
+ * the missing style image resolver (see stores/modules/icons.ts).
60
+ */
61
+ syncIcons(): Promise<void>;
62
+ /**
63
+ * Refresh a single iconset in Dexie. Used by the UI after mutating an
64
+ * iconset (icon create/update/delete) since the server does not yet
65
+ * broadcast iconset sync events.
66
+ */
67
+ syncIconset(uid: string): Promise<void>;
68
+ /**
69
+ * Tell the main thread how Dexie iconset content changed. `purge` lists
70
+ * iconsets whose icon blobs are actually different (version bump, removal
71
+ * or explicit mutation) so their MapLibre images must be dropped and
72
+ * re-resolved on demand. `added` lists iconsets cached for the first time
73
+ * - their content matches what the network fallback already served, so
74
+ * only fallback placeholder images need repair.
75
+ */
76
+ private notifyIconsetChange;
55
77
  private flush;
56
78
  private syncEvent;
57
79
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tak-ps/cloudtak",
3
3
  "type": "module",
4
- "version": "13.43.0",
4
+ "version": "13.45.0",
5
5
  "types": "dist/types/plugin.d.ts",
6
6
  "files": [
7
7
  "dist/types"
@@ -84,7 +84,7 @@
84
84
  "hls.js": "^1.6.5",
85
85
  "imask": "^6.0.0",
86
86
  "jsonata": "^2.0.4",
87
- "maplibre-gl": "v6.0.0-20",
87
+ "maplibre-gl": "v6.0.0-21",
88
88
  "milsymbol": "^3.0.2",
89
89
  "openapi-fetch": "^0.17.0",
90
90
  "phone": "^3.1.59",