@tak-ps/cloudtak 13.91.1 → 13.93.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,6 +1,6 @@
1
1
  import type { DBChatroom } from '../database.ts';
2
2
  import ChatroomChats from './chatroom-chats.ts';
3
- import { type Observable } from 'dexie';
3
+ import type { Observable } from 'dexie';
4
4
  import type { ProfileChatroomList, ProfileChatList } from '../types.ts';
5
5
  /**
6
6
  * High Level Wrapper around the Profile Chatroom API
@@ -1,4 +1,4 @@
1
- import { type Subscription } from 'dexie';
1
+ import type { Subscription } from 'dexie';
2
2
  import type { paths } from '@cloudtak/api-types';
3
3
  export type FullConfig = paths['/api/config']['get']['responses']['200']['content']['application/json'];
4
4
  export default class Config<K extends keyof FullConfig = keyof FullConfig> {
@@ -1,4 +1,4 @@
1
- import { type Observable } from 'dexie';
1
+ import type { Observable } from 'dexie';
2
2
  import type { Contact as TAKContact } from '../types.ts';
3
3
  import BaseInterface from './interface.ts';
4
4
  import type { BaseInterface_ListOptions, BaseInterface_FromOptions } from './interface.ts';
@@ -6,7 +6,7 @@
6
6
  * Note: it does not trigger re-rendering in the map stack, so it must be used
7
7
  * alongside cot.ts or atlas-database.ts to ensure re-rendering happens.
8
8
  */
9
- import { type Observable } from 'dexie';
9
+ import type { Observable } from 'dexie';
10
10
  import { type DBFeature } from '../database.ts';
11
11
  import type { paths } from '@cloudtak/api-types';
12
12
  import BaseInterface from './interface.ts';
@@ -1,4 +1,4 @@
1
- import { type Observable } from 'dexie';
1
+ import type { Observable } from 'dexie';
2
2
  import type { Group, GroupChannel } from '../types.ts';
3
3
  import BaseInterface from './interface.ts';
4
4
  import type { BaseInterface_ListOptions, BaseInterface_FromOptions } from './interface.ts';
@@ -1,4 +1,4 @@
1
- import { type Observable } from 'dexie';
1
+ import type { Observable } from 'dexie';
2
2
  import { type DBIconset } from '../database.ts';
3
3
  import type { paths } from '@cloudtak/api-types';
4
4
  import type { Iconset } from '../types.ts';
@@ -1,4 +1,4 @@
1
- import { type Observable } from 'dexie';
1
+ import type { Observable } from 'dexie';
2
2
  import { type DBKV } from '../database.ts';
3
3
  import BaseInterface from './interface.ts';
4
4
  export default class KV extends BaseInterface {
@@ -1,5 +1,5 @@
1
1
  import { NotificationType } from '../database.ts';
2
- import { type Observable } from 'dexie';
2
+ import type { Observable } from 'dexie';
3
3
  import type { DBNotification } from '../database.ts';
4
4
  import BaseInterface from './interface.ts';
5
5
  import type { BaseInterface_FromOptions } from './interface.ts';
@@ -1,4 +1,4 @@
1
- import { type Observable } from 'dexie';
1
+ import type { Observable } from 'dexie';
2
2
  import { type DBOverlay } from '../database.ts';
3
3
  import type { paths } from '@cloudtak/api-types';
4
4
  import BaseInterface from './interface.ts';
@@ -35,6 +35,31 @@ export default class OverlayManager extends BaseInterface {
35
35
  static appendLoaded(...overlays: Overlay[]): void;
36
36
  static createLoaded(body: Parameters<typeof Overlay.create>[0], opts?: Overlay_CreateLoadedOptions): Promise<Overlay>;
37
37
  static reorderLoaded(orderedIds: number[], movedId: string | number): Promise<void>;
38
+ /**
39
+ * Basemaps are pinned to the bottom of the stack and internal overlays
40
+ * (e.g. "Map Features") to the top - their `pos` is a sentinel and is
41
+ * never driven by drag order
42
+ */
43
+ static isPinned(overlay: {
44
+ mode: string;
45
+ _internal?: boolean;
46
+ }): boolean;
47
+ /**
48
+ * Stack comparator (bottom first) - pinned placement is decided from the
49
+ * overlay itself so a stale or corrupted `pos` cannot misplace it
50
+ */
51
+ static compareStack(this: void, a: {
52
+ mode: string;
53
+ pos: number;
54
+ name: string;
55
+ _internal?: boolean;
56
+ }, b: {
57
+ mode: string;
58
+ pos: number;
59
+ name: string;
60
+ _internal?: boolean;
61
+ }): number;
62
+ private static stackRank;
38
63
  /**
39
64
  * Move every loaded overlay's map layers so their stacking matches the
40
65
  * `loaded` order (index 0 at the bottom)
@@ -1,4 +1,4 @@
1
- import { type Observable } from 'dexie';
1
+ import type { Observable } from 'dexie';
2
2
  import { type DBProfileFile } from '../database.ts';
3
3
  import BaseInterface from './interface.ts';
4
4
  import type { BaseInterface_ListOptions } from './interface.ts';
@@ -1,5 +1,5 @@
1
1
  import type { Profile } from '../types.ts';
2
- import { type Subscription } from 'dexie';
2
+ import type { Subscription } from 'dexie';
3
3
  export default class ProfileConfig<K extends keyof Profile = keyof Profile> {
4
4
  key: K;
5
5
  value: Profile[K];
@@ -1,4 +1,4 @@
1
- import { type Observable } from 'dexie';
1
+ import type { Observable } from 'dexie';
2
2
  import type { Server, Server_Update } from '../types.ts';
3
3
  export default class ServerManager {
4
4
  static live(): Observable<Server | undefined>;
@@ -1,5 +1,5 @@
1
1
  import type { DBSubscriptionChat } from '../database.ts';
2
- import { type Observable } from 'dexie';
2
+ import type { Observable } from 'dexie';
3
3
  import type Atlas from '../workers/atlas.ts';
4
4
  import type { Remote } from 'comlink';
5
5
  /**
@@ -1,3 +1,4 @@
1
+ import type { DBSubscriptionFeature } from '../database.ts';
1
2
  import COT from './cot.ts';
2
3
  import Subscription from './subscription.ts';
3
4
  import type Atlas from '../workers/atlas.ts';
@@ -17,21 +18,30 @@ export default class SubscriptionFeature {
17
18
  list(opts?: {
18
19
  refresh?: boolean;
19
20
  }): Promise<Array<Feature>>;
21
+ /**
22
+ * Local changes that have not been confirmed by the server, including tombstones
23
+ */
24
+ pending(): Promise<Array<DBSubscriptionFeature>>;
25
+ /**
26
+ * The unconfirmed local change to a single feature, if there is one
27
+ */
28
+ pendingFrom(uid: string): Promise<DBSubscriptionFeature | undefined>;
20
29
  collection(raw?: boolean): Promise<FeatureCollection>;
21
30
  bounds(): Promise<BBox>;
22
31
  from(uid: string): Promise<Feature | undefined>;
23
32
  /**
24
33
  * Upsert a feature into the mission.
25
- * This will udpate the feature in the local DB, submit it to the TAK Server and
26
- * mark the subscription as dirty for a re-render
34
+ * This will update the feature in the local DB, mark the subscription as dirty for a re-render
35
+ * and submit it to the TAK Server in the background, leaving it unsynced until confirmed
27
36
  *
28
- * @param opts.skipNetwork - If true, the feature will not be updated on the server - IE in response to a Mission Change event
37
+ * @param opts.skipNetwork - If true, the feature came from the server - IE in response to a Mission Change event
29
38
  */
30
39
  update(atlas: Atlas, cot: COT, opts?: {
31
40
  skipNetwork?: boolean;
32
41
  }): Promise<void>;
33
42
  /**
34
43
  * Delete a feature from the mission.
44
+ * A local delete leaves a tombstone until the TAK Server confirms it
35
45
  *
36
46
  * @param atlas - The Atlas instance
37
47
  * @param uid - The unique ID of the feature to delete
@@ -41,4 +51,17 @@ export default class SubscriptionFeature {
41
51
  delete(atlas: Atlas, uid: string, opts?: {
42
52
  skipNetwork?: boolean;
43
53
  }): Promise<void>;
54
+ /**
55
+ * Submit unconfirmed local changes to the TAK Server, never rejecting - failures are
56
+ * recorded on the rows. Concurrent calls for a mission share a single in-flight push
57
+ *
58
+ * @returns true if every pending change was confirmed
59
+ */
60
+ push(): Promise<boolean>;
61
+ private flush;
62
+ /**
63
+ * Mark rows as synced unless they were changed again while the request was in flight
64
+ */
65
+ private confirm;
66
+ private failed;
44
67
  }
@@ -2,6 +2,8 @@ import type Subscription from '../../../base/subscription.ts';
2
2
  type __VLS_Props = {
3
3
  /** The Mission Subscription the CoT originates from */
4
4
  subscription: Subscription;
5
+ /** The UID of the CoT being viewed */
6
+ uid: string;
5
7
  };
6
8
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
7
9
  declare const _default: typeof __VLS_export;
@@ -9,6 +9,11 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
9
9
  type: NumberConstructor;
10
10
  default: number;
11
11
  };
12
+ /** Overlay a red exclamation mark on the lower right corner of the icon */
13
+ error: {
14
+ type: BooleanConstructor;
15
+ default: boolean;
16
+ };
12
17
  }>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
13
18
  feature: {
14
19
  type: ObjectConstructor;
@@ -18,6 +23,12 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
18
23
  type: NumberConstructor;
19
24
  default: number;
20
25
  };
26
+ /** Overlay a red exclamation mark on the lower right corner of the icon */
27
+ error: {
28
+ type: BooleanConstructor;
29
+ default: boolean;
30
+ };
21
31
  }>> & Readonly<{}>, {
22
32
  size: number;
33
+ error: boolean;
23
34
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -27,6 +27,10 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
27
27
  type: BooleanConstructor;
28
28
  default: boolean;
29
29
  };
30
+ error: {
31
+ type: BooleanConstructor;
32
+ default: boolean;
33
+ };
30
34
  hover: {
31
35
  type: BooleanConstructor;
32
36
  default: boolean;
@@ -66,6 +70,10 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
66
70
  type: BooleanConstructor;
67
71
  default: boolean;
68
72
  };
73
+ error: {
74
+ type: BooleanConstructor;
75
+ default: boolean;
76
+ };
69
77
  hover: {
70
78
  type: BooleanConstructor;
71
79
  default: boolean;
@@ -77,6 +85,7 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
77
85
  }>> & Readonly<{
78
86
  onDelete?: ((...args: any[]) => any) | undefined;
79
87
  }>, {
88
+ error: boolean;
80
89
  select: boolean;
81
90
  compact: boolean;
82
91
  hover: boolean;
@@ -0,0 +1,11 @@
1
+ type __VLS_Props = {
2
+ /** The last error encountered submitting the change to the server */
3
+ error?: string;
4
+ /** The change is currently being submitted to the server */
5
+ loading?: boolean;
6
+ /** Append a hint to the tooltip that clicking the badge retries the sync */
7
+ retry?: boolean;
8
+ };
9
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
10
+ declare const _default: typeof __VLS_export;
11
+ export default _default;
@@ -20,15 +20,15 @@ declare const __VLS_export: import("vue").DefineComponent<Props, {
20
20
  refresh: typeof refresh;
21
21
  upload: typeof upload;
22
22
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
23
- cancel: () => any;
24
23
  error: (response: Error) => any;
24
+ cancel: () => any;
25
25
  done: (response: unknown) => any;
26
26
  staged: (response: {
27
27
  name: string;
28
28
  }) => any;
29
29
  }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
30
- onCancel?: (() => any) | undefined;
31
30
  onError?: ((response: Error) => any) | undefined;
31
+ onCancel?: (() => any) | undefined;
32
32
  onDone?: ((response: unknown) => any) | undefined;
33
33
  onStaged?: ((response: {
34
34
  name: string;
@@ -1,4 +1,4 @@
1
- import Dexie, { type EntityTable } from 'dexie';
1
+ import Dexie, { type EntityTable, type Observable } from 'dexie';
2
2
  import type { Feature, GroupChannel, Mission, MissionRole, MissionChange, MissionLayer, MissionLog, Contact, Server, ProfileFile, ProfileOverlayList } from './types.ts';
3
3
  export interface DBIcon {
4
4
  /** Maplibre image id, e.g. "<iconsetUid>:<icon-path-without-extension>" */
@@ -119,6 +119,12 @@ export interface DBSubscriptionFeature {
119
119
  mission: string;
120
120
  properties: Feature["properties"];
121
121
  geometry: Feature["geometry"];
122
+ /** False while a local change has not been confirmed by the server */
123
+ synced: boolean;
124
+ /** Tombstone for a local delete that has not been confirmed by the server */
125
+ deleted: boolean;
126
+ attempts: number;
127
+ error?: string;
122
128
  }
123
129
  export interface DBSubscriptionLayer {
124
130
  uid: string;
@@ -250,6 +256,13 @@ export declare class DatabaseUnavailableError extends Error {
250
256
  constructor(message: string);
251
257
  }
252
258
  export declare function isDatabaseSuspended(): boolean;
259
+ export declare function isDatabaseSuspendedError(err: unknown): boolean;
260
+ /**
261
+ * Dexie liveQuery that survives suspension. Any other rejection ends the
262
+ * subscription for good; Dexie discards an AbortError and keeps listening,
263
+ * and resumeDatabase() re-runs what was skipped.
264
+ */
265
+ export declare function liveQuery<T>(querier: () => T | Promise<T>): Observable<T>;
253
266
  /**
254
267
  * Reject every IndexedDB transaction synchronously, before an
255
268
  * IDBTransaction is opened, so nothing is ever in flight while the app is
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tak-ps/cloudtak",
3
3
  "type": "module",
4
- "version": "13.91.1",
4
+ "version": "13.93.0",
5
5
  "types": "dist/types/plugin.d.ts",
6
6
  "files": [
7
7
  "dist/types"
@@ -71,9 +71,9 @@
71
71
  "@turf/meta": "^7.2.0",
72
72
  "@turf/nearest-point-on-line": "^7.3.4",
73
73
  "@turf/point-on-feature": "^7.0.0",
74
- "@unhead/vue": "^2.1.17",
74
+ "@unhead/vue": "^3.4.1",
75
75
  "@ver0/deep-equal": "^2.0.1",
76
- "@vueuse/core": "^14.0.0",
76
+ "@vueuse/core": "^15.0.0",
77
77
  "autosize": "^6.0.1",
78
78
  "chart.js": "^4.5.1",
79
79
  "comlink": "^4.4.2",
@@ -119,9 +119,10 @@
119
119
  "@vitest/ui": "^5.0.0",
120
120
  "@vue/devtools-api": "^8.1.5",
121
121
  "@vue/test-utils": "^2.4.6",
122
- "@vueuse/rxjs": "^14.1.0",
122
+ "@vueuse/rxjs": "^15.0.0",
123
123
  "eslint": "^10.0.0",
124
124
  "eslint-plugin-vue": "^10.0.0",
125
+ "fake-indexeddb": "^6.2.5",
125
126
  "globals": "^17.3.0",
126
127
  "happy-dom": "^20.0.0",
127
128
  "jsdom": "^30.0.0",