tantee-nuxt-commons 0.0.174 → 0.0.175

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.
@@ -2,10 +2,11 @@
2
2
  import { VAutocomplete } from 'vuetify/components/VAutocomplete'
3
3
  import { defineModel, withDefaults } from 'vue'
4
4
  import { useLookupList, type LookupProps } from '../../composables/lookupList'
5
+ import { useLocalStorageModel, type PersistSlimProps } from '../../composables/localStorageModel'
5
6
 
6
7
  interface Props extends /* @vue-ignore */ InstanceType<typeof VAutocomplete['$props']> {}
7
8
 
8
- const props = withDefaults(defineProps<Props & LookupProps>(), {
9
+ const props = withDefaults(defineProps<Props & LookupProps & PersistSlimProps>(), {
9
10
  fuzzy: false,
10
11
  showCode: false,
11
12
  cache: false,
@@ -22,6 +23,8 @@ const emit = defineEmits<{
22
23
 
23
24
  const selectedItems = defineModel<any>()
24
25
 
26
+ useLocalStorageModel(selectedItems,props)
27
+
25
28
  const {
26
29
  searchData,
27
30
  computedItems,
@@ -2,10 +2,11 @@
2
2
  import { VCombobox } from 'vuetify/components/VCombobox'
3
3
  import { defineModel, withDefaults } from 'vue'
4
4
  import { useLookupList, type LookupProps } from '../../composables/lookupList'
5
+ import { useLocalStorageModel, type PersistSlimProps } from '../../composables/localStorageModel'
5
6
 
6
7
  interface Props extends /* @vue-ignore */ InstanceType<typeof VCombobox['$props']> {}
7
8
 
8
- const props = withDefaults(defineProps<Props & LookupProps>(), {
9
+ const props = withDefaults(defineProps<Props & LookupProps & PersistSlimProps>(), {
9
10
  fuzzy: false,
10
11
  showCode: false,
11
12
  cache: false,
@@ -22,6 +23,8 @@ const emit = defineEmits<{
22
23
 
23
24
  const selectedItems = defineModel<any>()
24
25
 
26
+ useLocalStorageModel(selectedItems,props)
27
+
25
28
  const {
26
29
  searchData,
27
30
  computedItems,
@@ -2,10 +2,11 @@
2
2
  import { VCombobox } from 'vuetify/components/VCombobox'
3
3
  import { defineModel, withDefaults } from 'vue'
4
4
  import { useLookupList, type StaticLookupProps } from '../../composables/lookupList'
5
+ import { useLocalStorageModel, type PersistSlimProps } from '../../composables/localStorageModel'
5
6
 
6
7
  interface Props extends /* @vue-ignore */ InstanceType<typeof VCombobox['$props']> {}
7
8
 
8
- const props = withDefaults(defineProps<Props & StaticLookupProps>(), {
9
+ const props = withDefaults(defineProps<Props & StaticLookupProps & PersistSlimProps>(), {
9
10
  fuzzy: false,
10
11
  showCode: false,
11
12
  cache: false,
@@ -17,6 +18,8 @@ const emit = defineEmits<{
17
18
 
18
19
  const selectedItems = defineModel<any>()
19
20
 
21
+ useLocalStorageModel(selectedItems,props)
22
+
20
23
  const {
21
24
  computedItems,
22
25
  computedFilterKeys,
@@ -2,9 +2,9 @@ import type { UseFetchOptions } from 'nuxt/app';
2
2
  import type { SearchParameters } from 'ofetch';
3
3
  export declare function useApi(): {
4
4
  urlBuilder: (url: string | string[]) => string;
5
- get: (url: string | string[], body?: Record<string, any> | [], params?: SearchParameters, options?: UseFetchOptions<unknown>, cache?: boolean | number) => Promise<unknown>;
6
- getPromise: (url: string | string[], body?: Record<string, any> | [], params?: SearchParameters, options?: UseFetchOptions<unknown>, cache?: boolean | number) => Promise<unknown>;
7
- post: (url: string | string[], body?: Record<string, any> | [], params?: SearchParameters, options?: UseFetchOptions<unknown>, cache?: boolean | number) => Promise<unknown>;
8
- postPromise: (url: string | string[], body?: Record<string, any> | [], params?: SearchParameters, options?: UseFetchOptions<unknown>, cache?: boolean | number) => Promise<unknown>;
5
+ get: <T>(url: string | string[], body?: Record<string, any> | [], params?: SearchParameters, options?: UseFetchOptions<unknown>, cache?: boolean | number) => Promise<T>;
6
+ getPromise: <T>(url: string | string[], body?: Record<string, any> | [], params?: SearchParameters, options?: UseFetchOptions<unknown>, cache?: boolean | number) => Promise<T>;
7
+ post: <T>(url: string | string[], body?: Record<string, any> | [], params?: SearchParameters, options?: UseFetchOptions<unknown>, cache?: boolean | number) => Promise<T>;
8
+ postPromise: <T>(url: string | string[], body?: Record<string, any> | [], params?: SearchParameters, options?: UseFetchOptions<unknown>, cache?: boolean | number) => Promise<T>;
9
9
  hashKey: (data: any) => Promise<string>;
10
10
  };
@@ -1,29 +1,33 @@
1
1
  import { ofetch } from "ofetch";
2
2
  import { trimEnd, trimStart } from "lodash-es";
3
- import ls from "localstorage-ttl";
3
+ import ls from "localstorage-slim";
4
4
  import { stableStringify } from "../utils/object.js";
5
5
  import { sha256 } from "../utils/hash.js";
6
6
  import { useAuthentication, useRuntimeConfig } from "#imports";
7
7
  export function useApi() {
8
8
  const config = useRuntimeConfig();
9
+ const CACHE_PREFIX = "api-cache-";
9
10
  function urlBuilder(url) {
10
11
  let returnUrl;
11
12
  if (Array.isArray(url)) {
12
- if (url[0].toLowerCase() == "agent") url[0] = config?.public.WS_AGENT || config?.public.WS_DEVICE;
13
+ if (url[0].toLowerCase() === "agent") {
14
+ url[0] = config?.public.WS_AGENT || config?.public.WS_DEVICE;
15
+ }
13
16
  returnUrl = url.join("/");
14
17
  } else {
15
18
  returnUrl = url;
16
19
  }
17
20
  if (returnUrl.startsWith("http://") || returnUrl.startsWith("https://")) return returnUrl;
18
- else return trimEnd(config?.public.WS_API, "/") + "/" + trimStart(returnUrl, "/");
21
+ return trimEnd(config?.public.WS_API, "/") + "/" + trimStart(returnUrl, "/");
19
22
  }
20
23
  function optionBuilder(method, body, params, options = {}) {
21
24
  const headers = {
22
25
  "Content-Type": "application/json",
23
- "Accept": "application/json"
26
+ Accept: "application/json"
24
27
  };
25
28
  const { token } = useAuthentication().keycloak || {};
26
29
  if (token) {
30
+ ;
27
31
  headers["Authorization"] = `Bearer ${token}`;
28
32
  }
29
33
  const baseOptions = {
@@ -58,27 +62,35 @@ export function useApi() {
58
62
  const jsonString = stableStringify(data);
59
63
  return sha256(jsonString);
60
64
  }
61
- async function ofetchWithCache(url, method, body, params, options, cache) {
62
- const keyData = { url: urlBuilder(url), method, body, params, options };
63
- let ttl = 0;
64
- if (cache) {
65
- if (typeof cache === "boolean") ttl = 5 * 60 * 1e3;
66
- else {
67
- ttl = +cache * 60 * 1e3;
68
- }
65
+ function computeTtlSecond(cache) {
66
+ if (!cache) return 0;
67
+ if (typeof cache === "boolean") return 5 * 60;
68
+ let ttlNum = Math.max(0, Number(cache));
69
+ return ttlNum > 60 ? ttlNum : ttlNum * 60;
70
+ }
71
+ function safeGetCache(key) {
72
+ try {
73
+ const v = ls.get(key);
74
+ return v ?? null;
75
+ } catch {
76
+ return null;
69
77
  }
78
+ }
79
+ async function ofetchWithCache(url, method, body, params, options, cache) {
80
+ const builtUrl = urlBuilder(url);
81
+ const ttl = computeTtlSecond(cache);
70
82
  if (ttl === 0) {
71
- return ofetch(urlBuilder(url), optionBuilder(method, body, params, options));
83
+ return ofetch(builtUrl, optionBuilder(method, body, params, options));
72
84
  }
73
- const key = "api-cache-" + await hashKey(keyData);
74
- const cached = ls.get(key);
75
- if (cached) {
76
- return Promise.resolve(cached);
85
+ const keyData = { url: builtUrl, method, body, params, headers: options?.headers };
86
+ const key = CACHE_PREFIX + await hashKey(keyData);
87
+ const cached = safeGetCache(key);
88
+ if (cached !== null) {
89
+ return cached;
77
90
  }
78
- return ofetch(urlBuilder(url), optionBuilder(method, body, params, options)).then((result) => {
79
- ls.set(key, result, ttl);
80
- return result;
81
- });
91
+ const result = await ofetch(builtUrl, optionBuilder(method, body, params, options));
92
+ ls.set(key, result, { ttl });
93
+ return result;
82
94
  }
83
95
  return { urlBuilder, get, getPromise, post, postPromise, hashKey };
84
96
  }
@@ -0,0 +1,15 @@
1
+ /** JSON-serializable config object (backend: Map<String, Object>) */
2
+ export type ClientConfig = Record<string, any>;
3
+ export interface ClientConfigOptions {
4
+ storageKey?: string;
5
+ }
6
+ export interface ClientConfigService {
7
+ get(): ClientConfig | null;
8
+ set(cfg: ClientConfig): void;
9
+ clear(): void;
10
+ /** GraphQL-first, localStorage fallback */
11
+ load(): Promise<ClientConfig | null>;
12
+ /** BLANK method stub: implement GraphQL retrieval */
13
+ fetchFromGraphql(): Promise<ClientConfig>;
14
+ }
15
+ export declare function createClientConfigService(opts?: ClientConfigOptions): ClientConfigService;
@@ -0,0 +1,79 @@
1
+ import ls from "localstorage-slim";
2
+ import { Thumbmark } from "@thumbmarkjs/thumbmarkjs";
3
+ import { useGraphQlOperation } from "./graphqlOperation.js";
4
+ import { useHostAgent } from "./hostAgent.js";
5
+ function isPlainObject(v) {
6
+ return v !== null && typeof v === "object" && !Array.isArray(v);
7
+ }
8
+ function readConfig(storageKey) {
9
+ try {
10
+ const v = ls.get(storageKey);
11
+ if (!v || !isPlainObject(v)) return null;
12
+ return v;
13
+ } catch {
14
+ return null;
15
+ }
16
+ }
17
+ function writeConfig(storageKey, cfg) {
18
+ ls.set(storageKey, cfg);
19
+ }
20
+ function clearConfig(storageKey) {
21
+ ls.remove(storageKey);
22
+ }
23
+ export function createClientConfigService(opts = {}) {
24
+ const storageKey = opts.storageKey ?? "client_config";
25
+ const thumbmarkInstance = new Thumbmark();
26
+ return {
27
+ get() {
28
+ return readConfig(storageKey);
29
+ },
30
+ set(cfg) {
31
+ if (!isPlainObject(cfg)) {
32
+ throw new Error("ClientConfig must be a JSON-serializable object.");
33
+ }
34
+ JSON.stringify(cfg);
35
+ writeConfig(storageKey, cfg);
36
+ },
37
+ clear() {
38
+ clearConfig(storageKey);
39
+ },
40
+ async load() {
41
+ try {
42
+ const cfg = await this.fetchFromGraphql();
43
+ this.set(cfg);
44
+ return cfg;
45
+ } catch {
46
+ return this.get();
47
+ }
48
+ },
49
+ async fetchFromGraphql() {
50
+ const thumbmark = await thumbmarkInstance.get();
51
+ let computerName = thumbmark.thumbmark;
52
+ try {
53
+ const machineInfo = await useHostAgent().getMachineInfo();
54
+ if (machineInfo?.computerName) {
55
+ computerName = machineInfo.computerName;
56
+ }
57
+ } catch (err) {
58
+ console.warn("[client-config] getMachineInfo() failed, fallback to fingerprint:", err);
59
+ }
60
+ try {
61
+ const result = await useGraphQlOperation(
62
+ "Query",
63
+ "clientConfigByComputerNameAndFingerprint",
64
+ ["*"],
65
+ {
66
+ computerName,
67
+ fingerprint: thumbmark.thumbmark
68
+ },
69
+ false
70
+ );
71
+ if (!result || !result.configuration) return {};
72
+ return result.configuration;
73
+ } catch (err) {
74
+ console.warn("[client-config] fetching config failed:", err);
75
+ return {};
76
+ }
77
+ }
78
+ };
79
+ }
@@ -0,0 +1,260 @@
1
+ /**
2
+ * =========================
3
+ * Enums (STRING enums)
4
+ * =========================
5
+ */
6
+ export type Driver = 'Wia' | 'Twain' | 'Sane' | 'Escl';
7
+ export type PaperSource = 'Auto' | 'Flatbed' | 'Feeder' | 'Duplex';
8
+ export type BitDepth = 'Color' | 'Grayscale' | 'BlackAndWhite';
9
+ export type PrintDataType = 'Pdf' | 'Image' | 'Text' | 'Html' | 'Office';
10
+ export declare const DRIVER: {
11
+ readonly Wia: "Wia";
12
+ readonly Twain: "Twain";
13
+ readonly Sane: "Sane";
14
+ readonly Escl: "Escl";
15
+ };
16
+ export declare const PAPER_SOURCE: {
17
+ readonly Auto: "Auto";
18
+ readonly Flatbed: "Flatbed";
19
+ readonly Feeder: "Feeder";
20
+ readonly Duplex: "Duplex";
21
+ };
22
+ export declare const BIT_DEPTH: {
23
+ readonly Color: "Color";
24
+ readonly Grayscale: "Grayscale";
25
+ readonly BlackAndWhite: "BlackAndWhite";
26
+ };
27
+ export declare const PRINT_DATA_TYPE: {
28
+ readonly Pdf: "Pdf";
29
+ readonly Image: "Image";
30
+ readonly Text: "Text";
31
+ readonly Html: "Html";
32
+ readonly Office: "Office";
33
+ };
34
+ /**
35
+ * =========================
36
+ * REST DTOs
37
+ * =========================
38
+ */
39
+ export interface HostSettings {
40
+ printerA4?: string | null;
41
+ printerA5?: string | null;
42
+ defaultScanner?: string | null;
43
+ dpi?: number;
44
+ colorMode?: string | null;
45
+ pageSize?: string | null;
46
+ duplex?: boolean;
47
+ chromiumExecutablePath?: string | null;
48
+ }
49
+ export interface PrintRequest {
50
+ printData: string;
51
+ dataType: PrintDataType;
52
+ paperSize?: string | null;
53
+ printerName?: string | null;
54
+ copies?: number;
55
+ fileName?: string | null;
56
+ }
57
+ export interface PrintAcceptedResponse {
58
+ status: 'queued' | string;
59
+ printerName: string;
60
+ /** server returns DataType as string (effective.DataType.ToString()) */
61
+ DataType: PrintDataType | string;
62
+ paperSize?: string | null;
63
+ copies: number;
64
+ }
65
+ export interface ScanRequest {
66
+ deviceName?: string | null;
67
+ driver?: Driver | null;
68
+ paperSource?: PaperSource;
69
+ pageSize?: string | null;
70
+ dpi: number;
71
+ bitDepth?: BitDepth;
72
+ quality?: number;
73
+ maxQuality?: boolean;
74
+ autoDeskew?: boolean;
75
+ excludeBlankPages?: boolean;
76
+ brightness?: number;
77
+ contrast?: number;
78
+ }
79
+ export interface ScanResult {
80
+ base64String: string;
81
+ }
82
+ export interface ProblemDetails {
83
+ type?: string | null;
84
+ title?: string | null;
85
+ status?: number | null;
86
+ detail?: string | null;
87
+ instance?: string | null;
88
+ [k: string]: any;
89
+ }
90
+ export type DeviceNameList = string[];
91
+ export type LogFileList = string[];
92
+ /**
93
+ * =========================
94
+ * IDCardController result types
95
+ * =========================
96
+ */
97
+ export type JsonMeta = unknown;
98
+ export interface PatientRegisterInput {
99
+ citizenId?: string | null;
100
+ citizenIdVerified: boolean;
101
+ dob?: string | null;
102
+ dobPrecision?: 'yearMonthDay' | 'yearMonth' | 'year' | string;
103
+ gender?: string | null;
104
+ meta?: JsonMeta | null;
105
+ }
106
+ export interface PatientNameRegisterInput {
107
+ nameType: string;
108
+ prefix?: string | null;
109
+ firstName: string;
110
+ middleName?: string | null;
111
+ lastName?: string | null;
112
+ suffix?: string | null;
113
+ }
114
+ export interface PatientAddressRegisterInput {
115
+ mrn?: string | null;
116
+ addressType: string;
117
+ text: string;
118
+ place?: string | null;
119
+ villageNo?: string | null;
120
+ alleyWay?: string | null;
121
+ alley?: string | null;
122
+ street?: string | null;
123
+ subDistrictCode?: string | null;
124
+ districtCode?: string | null;
125
+ provinceCode?: string | null;
126
+ }
127
+ export interface PatientPhotoRegisterInput {
128
+ photoSource?: string | null;
129
+ base64String: string;
130
+ }
131
+ export interface PatientRegisterPayload {
132
+ patient: PatientRegisterInput;
133
+ patientNames?: PatientNameRegisterInput[] | null;
134
+ patientAddresses?: PatientAddressRegisterInput[] | null;
135
+ patientPhotos?: PatientPhotoRegisterInput[] | null;
136
+ }
137
+ export interface CitizenIdResult {
138
+ CitizenId?: string | null;
139
+ }
140
+ export interface MachineInfo {
141
+ computerName: string;
142
+ userName: string;
143
+ ipAddresses: string[];
144
+ softwareVersion: string;
145
+ }
146
+ /**
147
+ * =========================
148
+ * WS protocol types (exported for useHostAgentWs)
149
+ * =========================
150
+ */
151
+ export type IdCardWsClientMessage = {
152
+ action: 'subscribe';
153
+ reader?: string | null;
154
+ withPhoto?: boolean;
155
+ } | {
156
+ action: 'ping';
157
+ } | {
158
+ action: 'switchReader';
159
+ reader?: string | null;
160
+ } | {
161
+ action: 'unsubscribe';
162
+ } | {
163
+ action: string;
164
+ [k: string]: any;
165
+ };
166
+ export type IdCardWsServerMessage = {
167
+ type: 'monitor.subscribed';
168
+ ok: boolean;
169
+ reader?: string | null;
170
+ withPhoto?: boolean;
171
+ } | {
172
+ type: 'monitor.started';
173
+ reader?: string | null;
174
+ } | {
175
+ type: 'monitor.switchAck';
176
+ ok: boolean;
177
+ reader?: string | null;
178
+ } | {
179
+ type: 'monitor.switched';
180
+ reader?: string | null;
181
+ } | {
182
+ type: 'monitor.unsubscribed';
183
+ ok: boolean;
184
+ } | {
185
+ type: 'pong';
186
+ ts?: string;
187
+ } | {
188
+ type: 'card.inserted';
189
+ payload: PatientRegisterPayload;
190
+ } | {
191
+ type: 'card.removed';
192
+ } | {
193
+ type: 'card.error';
194
+ message?: string;
195
+ } | {
196
+ type: 'error';
197
+ code?: string;
198
+ message?: string;
199
+ } | {
200
+ type: string;
201
+ [k: string]: any;
202
+ };
203
+ export type IdCardWsEvent = {
204
+ type: 'open';
205
+ } | {
206
+ type: 'close';
207
+ code?: number;
208
+ reason?: string;
209
+ } | {
210
+ type: 'error';
211
+ error?: any;
212
+ } | {
213
+ type: 'message';
214
+ data: IdCardWsServerMessage;
215
+ raw: MessageEvent;
216
+ };
217
+ /**
218
+ * =========================
219
+ * Main REST composable (no WS, no lifecycle hooks)
220
+ * =========================
221
+ */
222
+ export declare function useHostAgent(): {
223
+ DRIVER: {
224
+ readonly Wia: "Wia";
225
+ readonly Twain: "Twain";
226
+ readonly Sane: "Sane";
227
+ readonly Escl: "Escl";
228
+ };
229
+ PAPER_SOURCE: {
230
+ readonly Auto: "Auto";
231
+ readonly Flatbed: "Flatbed";
232
+ readonly Feeder: "Feeder";
233
+ readonly Duplex: "Duplex";
234
+ };
235
+ BIT_DEPTH: {
236
+ readonly Color: "Color";
237
+ readonly Grayscale: "Grayscale";
238
+ readonly BlackAndWhite: "BlackAndWhite";
239
+ };
240
+ PRINT_DATA_TYPE: {
241
+ readonly Pdf: "Pdf";
242
+ readonly Image: "Image";
243
+ readonly Text: "Text";
244
+ readonly Html: "Html";
245
+ readonly Office: "Office";
246
+ };
247
+ getSettings: (cache?: boolean | number) => Promise<HostSettings>;
248
+ updateSettings: (settings: HostSettings) => Promise<HostSettings>;
249
+ getPrinters: (cache?: boolean | number) => Promise<DeviceNameList>;
250
+ getScanners: (cache?: boolean | number) => Promise<DeviceNameList>;
251
+ getIdCardInfo: (reader?: string) => Promise<PatientRegisterPayload>;
252
+ getIdCardInfoAndPhoto: (reader?: string) => Promise<PatientRegisterPayload>;
253
+ getCitizenId: (reader?: string) => Promise<CitizenIdResult>;
254
+ getMachineInfo: () => Promise<MachineInfo>;
255
+ print: (req: PrintRequest) => Promise<PrintAcceptedResponse>;
256
+ scan: (req: ScanRequest) => Promise<ScanResult[]>;
257
+ getLogFiles: (cache?: boolean | number) => Promise<LogFileList>;
258
+ tailLog: (file: string, lines?: number) => Promise<unknown>;
259
+ isProblemDetails: (x: any) => x is ProblemDetails;
260
+ };
@@ -0,0 +1,74 @@
1
+ import { useApi } from "./api.js";
2
+ export const DRIVER = { Wia: "Wia", Twain: "Twain", Sane: "Sane", Escl: "Escl" };
3
+ export const PAPER_SOURCE = { Auto: "Auto", Flatbed: "Flatbed", Feeder: "Feeder", Duplex: "Duplex" };
4
+ export const BIT_DEPTH = { Color: "Color", Grayscale: "Grayscale", BlackAndWhite: "BlackAndWhite" };
5
+ export const PRINT_DATA_TYPE = { Pdf: "Pdf", Image: "Image", Text: "Text", Html: "Html", Office: "Office" };
6
+ export function useHostAgent() {
7
+ const api = useApi();
8
+ const base = ["agent"];
9
+ function getSettings(cache = false) {
10
+ return api.getPromise([...base, "api/settings"], void 0, void 0, void 0, cache);
11
+ }
12
+ function updateSettings(settings) {
13
+ return api.postPromise([...base, "api/settings"], settings);
14
+ }
15
+ function getPrinters(cache = false) {
16
+ return api.getPromise([...base, "api/devices/printers"], void 0, void 0, void 0, cache);
17
+ }
18
+ function getScanners(cache = false) {
19
+ return api.getPromise([...base, "api/devices/scanners"], void 0, void 0, void 0, cache);
20
+ }
21
+ function getIdCardInfo(reader) {
22
+ return api.getPromise([...base, "idcard/info"], void 0, reader ? { reader } : void 0);
23
+ }
24
+ function getIdCardInfoAndPhoto(reader) {
25
+ return api.getPromise(
26
+ [...base, "idcard/infoAndPhoto"],
27
+ void 0,
28
+ reader ? { reader } : void 0
29
+ );
30
+ }
31
+ function getCitizenId(reader) {
32
+ return api.getPromise([...base, "idcard/citizenId"], void 0, reader ? { reader } : void 0);
33
+ }
34
+ function getMachineInfo() {
35
+ return api.getPromise([...base, "machine/info"]);
36
+ }
37
+ function print(req) {
38
+ return api.postPromise([...base, "print"], req);
39
+ }
40
+ function scan(req) {
41
+ return api.postPromise([...base, "scan"], req);
42
+ }
43
+ function getLogFiles(cache = false) {
44
+ return api.getPromise([...base, "api/logs/files"], void 0, void 0, void 0, cache);
45
+ }
46
+ function tailLog(file, lines = 500) {
47
+ return api.getPromise([...base, "api/logs/tail"], void 0, { file, lines });
48
+ }
49
+ function isProblemDetails(x) {
50
+ return !!x && typeof x === "object" && ("title" in x || "status" in x || "detail" in x);
51
+ }
52
+ return {
53
+ // enums/constants
54
+ DRIVER,
55
+ PAPER_SOURCE,
56
+ BIT_DEPTH,
57
+ PRINT_DATA_TYPE,
58
+ // REST
59
+ getSettings,
60
+ updateSettings,
61
+ getPrinters,
62
+ getScanners,
63
+ getIdCardInfo,
64
+ getIdCardInfoAndPhoto,
65
+ getCitizenId,
66
+ getMachineInfo,
67
+ print,
68
+ scan,
69
+ getLogFiles,
70
+ tailLog,
71
+ // util
72
+ isProblemDetails
73
+ };
74
+ }