@yomotech/view-toolkit 0.0.78 → 0.0.79

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.
@@ -6,7 +6,7 @@ import * as i3 from '@angular/forms';
6
6
  import { FormsModule } from '@angular/forms';
7
7
  import * as i1$1 from '@angular/common/http';
8
8
  import { HttpHeaders, HttpParams } from '@angular/common/http';
9
- import { Capacitor, CapacitorHttp } from '@capacitor/core';
9
+ import { CapacitorHttp, Capacitor } from '@capacitor/core';
10
10
  import * as i11 from 'ng-zorro-antd/icon';
11
11
  import { NzIconModule } from 'ng-zorro-antd/icon';
12
12
  import * as i13 from 'ng-zorro-antd/button';
@@ -1035,278 +1035,103 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImpor
1035
1035
 
1036
1036
  class Couchdb {
1037
1037
  utilityService;
1038
- platform;
1039
- remoteCouchDbBaseUrl = 'https://couchdb.yomotech.de';
1040
- webProxyBaseUrl = '/couchdb-api';
1041
- constructor(utilityService, platform) {
1038
+ couchDbBaseUrl = 'https://couchdb.yomotech.de';
1039
+ constructor(utilityService) {
1042
1040
  this.utilityService = utilityService;
1043
- this.platform = platform;
1044
1041
  }
1045
1042
  async getTenantDatabases(tenantKey) {
1046
- const normalizedTenantKey = tenantKey?.trim();
1047
- if (!normalizedTenantKey) {
1043
+ if (!tenantKey || !tenantKey.trim()) {
1048
1044
  throw new Error('Missing tenantKey');
1049
1045
  }
1050
- const result = await this.sendGetRequest('/tenant-dbs', {
1051
- Accept: 'application/json',
1052
- 'X-Tenant-Key': normalizedTenantKey,
1046
+ const response = await fetch(`https://couchdb.yomotech.de/tenant-dbs`, {
1047
+ method: 'GET',
1048
+ headers: {
1049
+ Accept: 'application/json',
1050
+ 'X-Tenant-Key': tenantKey.trim(),
1051
+ },
1053
1052
  });
1054
- if (!result.ok) {
1055
- throw new Error(`GET /tenant-dbs -> ${result.status} ` +
1056
- `${this.stringifyErrorDetails(result.data)}`);
1053
+ const data = await this.parseJsonOrText(response);
1054
+ if (!response.ok) {
1055
+ throw new Error(`GET /tenant-dbs -> ${response.status} ${this.stringifyErrorDetails(data)}`);
1056
+ }
1057
+ return data;
1058
+ }
1059
+ async parseJsonOrText(response) {
1060
+ const rawText = await response.text();
1061
+ if (!rawText)
1062
+ return null;
1063
+ try {
1064
+ return JSON.parse(rawText);
1065
+ }
1066
+ catch {
1067
+ return rawText;
1057
1068
  }
1058
- if (Array.isArray(result.data)) {
1059
- return result.data;
1069
+ }
1070
+ stringifyErrorDetails(data) {
1071
+ if (typeof data === 'string')
1072
+ return data;
1073
+ try {
1074
+ return JSON.stringify(data);
1060
1075
  }
1061
- if (result.data &&
1062
- Array.isArray(result.data.databases)) {
1063
- return result.data;
1076
+ catch {
1077
+ return 'Unknown error';
1064
1078
  }
1065
- throw new Error(`Invalid /tenant-dbs response: ` +
1066
- `${this.stringifyErrorDetails(result.data)}`);
1067
1079
  }
1068
1080
  async getFileContentFromCouchDb(couchDbName, filePath) {
1069
1081
  try {
1070
- const dbName = couchDbName?.trim().toLowerCase();
1082
+ const dbName = couchDbName?.toLowerCase();
1071
1083
  const docId = filePath?.trim();
1072
- if (!dbName) {
1073
- console.error('Missing CouchDB database name');
1074
- return null;
1075
- }
1076
1084
  if (!docId) {
1077
1085
  console.error('Missing file path');
1078
1086
  return null;
1079
1087
  }
1080
- const path = this.getDocumentPath(dbName, docId);
1081
- const result = await this.sendGetRequest(path, await this.getReadHeaders());
1082
- const doc = result.data;
1083
- if (!result.ok) {
1084
- console.error(`Failed to fetch file "${docId}" ` + `from "${dbName}": ` + `${result.status}`, doc);
1088
+ const response = await fetch(this.getDocumentUrl(dbName, docId), {
1089
+ method: 'GET',
1090
+ headers: await this.getReadHeaders(),
1091
+ });
1092
+ const doc = await this.parseJsonOrText(response);
1093
+ if (!response.ok) {
1094
+ console.error(`Failed to fetch file "${docId}" from "${dbName}": ${response.status}`, doc);
1085
1095
  return null;
1086
1096
  }
1087
1097
  if (!doc?.data) {
1088
- console.error(`Document "${docId}" ` + `does not contain file data`);
1098
+ console.error(`Document "${docId}" does not contain file data`);
1089
1099
  return null;
1090
1100
  }
1091
- const fileName = doc.name || doc.path || docId;
1092
- if (doc.type === 'media' || doc.type === 'base64file' || this.isBinaryMediaFile(fileName, doc.contentType)) {
1093
- const mimeType = this.getMimeType(fileName, doc.contentType);
1101
+ // do not decode images as utf8 text
1102
+ if (doc.type === 'media' ||
1103
+ doc.type === 'base64file' ||
1104
+ this.isBinaryMediaFile(doc.name || doc.path || docId, doc.contentType)) {
1094
1105
  return {
1095
1106
  type: doc.type || 'base64file',
1096
- mimeType,
1107
+ mimeType: this.getMimeType(doc.name || doc.path || docId, doc.contentType),
1097
1108
  base64: doc.data,
1098
- src: `data:${mimeType};base64,` + `${doc.data}`,
1109
+ src: `data:${this.getMimeType(doc.name || doc.path || docId, doc.contentType)};base64,${doc.data}`,
1099
1110
  name: doc.name,
1100
1111
  path: doc.path,
1101
1112
  metadata: doc.metadata || {},
1102
1113
  };
1103
1114
  }
1104
1115
  const decodedContent = this.fromBase64(doc.data);
1105
- if (this.isJsonFile(fileName, doc.contentType)) {
1116
+ if (this.isJsonFile(doc.name || doc.path || docId, doc.contentType)) {
1106
1117
  try {
1107
1118
  return JSON.parse(decodedContent);
1108
1119
  }
1109
1120
  catch (jsonError) {
1110
- console.error(`Failed to parse JSON ` +
1111
- `for file "${docId}"`, jsonError);
1121
+ console.error(`Failed to parse JSON for file "${docId}"`, jsonError);
1112
1122
  return decodedContent;
1113
1123
  }
1114
1124
  }
1115
1125
  return decodedContent;
1116
1126
  }
1117
1127
  catch (error) {
1118
- console.error(`Unexpected error while fetching ` +
1119
- `file "${filePath}" from ` +
1120
- `"${couchDbName}"`, error);
1121
- return null;
1122
- }
1123
- }
1124
- async getImageSrcFromCouchDb(couchDbName, filePath) {
1125
- const dbName = couchDbName?.trim().toLowerCase();
1126
- const docId = filePath?.trim();
1127
- if (!dbName) {
1128
- throw new Error('Missing CouchDB database name');
1129
- }
1130
- if (!docId) {
1131
- throw new Error('Missing file path');
1132
- }
1133
- const path = this.getDocumentPath(dbName, docId);
1134
- const result = await this.sendGetRequest(path, await this.getReadHeaders());
1135
- const doc = result.data;
1136
- if (!result.ok) {
1137
- throw new Error(`Failed to fetch image ` +
1138
- `"${docId}" from "${dbName}": ` +
1139
- `${result.status} ` +
1140
- `${this.stringifyErrorDetails(doc)}`);
1141
- }
1142
- if (!doc?.data) {
1143
- throw new Error(`Document "${docId}" ` +
1144
- `does not contain image data`);
1145
- }
1146
- const mimeType = this.getMimeType(doc.name ||
1147
- doc.path ||
1148
- docId, doc.contentType);
1149
- return (`data:${mimeType};base64,` +
1150
- `${doc.data}`);
1151
- }
1152
- async sendGetRequest(path, headers) {
1153
- const normalizedPath = path.startsWith('/')
1154
- ? path
1155
- : `/${path}`;
1156
- if (Capacitor.isNativePlatform()) {
1157
- return this.sendNativeGetRequest(normalizedPath, headers);
1158
- }
1159
- return this.sendWebGetRequest(normalizedPath, headers);
1160
- }
1161
- async sendNativeGetRequest(path, headers) {
1162
- const url = `${this.remoteCouchDbBaseUrl}${path}`;
1163
- try {
1164
- const response = await CapacitorHttp.get({
1165
- url,
1166
- headers,
1167
- connectTimeout: 15000,
1168
- readTimeout: 30000,
1169
- });
1170
- const data = this.normalizeNativeResponseData(response.data);
1171
- return {
1172
- ok: response.status >= 200 &&
1173
- response.status < 300,
1174
- status: response.status,
1175
- data: data,
1176
- };
1177
- }
1178
- catch (error) {
1179
- console.log('[CouchDB][Native] Request failed:', error);
1180
- return {
1181
- ok: false,
1182
- status: this.extractNativeErrorStatus(error),
1183
- data: this.extractNativeErrorData(error),
1184
- };
1185
- }
1186
- }
1187
- async sendWebGetRequest(path, headers) {
1188
- const url = `${this.webProxyBaseUrl}${path}`;
1189
- try {
1190
- const response = await fetch(url, { method: 'GET', cache: 'no-store', headers, });
1191
- const data = await this.parseJsonOrText(response);
1192
- return { ok: response.ok, status: response.status, data: data };
1193
- }
1194
- catch (error) {
1195
- console.error('[CouchDB][Web] Request failed:', error);
1196
- return { ok: false, status: 0, data: error, };
1197
- }
1198
- }
1199
- normalizeNativeResponseData(data) {
1200
- if (typeof data !== 'string') {
1201
- return data;
1202
- }
1203
- if (!data.trim()) {
1204
- return null;
1205
- }
1206
- try {
1207
- return JSON.parse(data);
1208
- }
1209
- catch {
1210
- return data;
1211
- }
1212
- }
1213
- extractNativeErrorStatus(error) {
1214
- const status = error?.status ??
1215
- error?.response?.status ??
1216
- error?.data?.status;
1217
- return Number.isFinite(Number(status))
1218
- ? Number(status)
1219
- : 0;
1220
- }
1221
- extractNativeErrorData(error) {
1222
- return (error?.data ??
1223
- error?.response?.data ??
1224
- error?.message ??
1225
- error);
1226
- }
1227
- getDocumentPath(dbName, docId) {
1228
- const encodedDbName = encodeURIComponent(dbName.trim().toLowerCase());
1229
- const encodedDocId = encodeURIComponent(docId.trim());
1230
- return (`/${encodedDbName}/` + `${encodedDocId}`);
1231
- }
1232
- async getReadHeaders() {
1233
- return {
1234
- Accept: 'application/json',
1235
- ...(await this.buildTenantHeaders()),
1236
- };
1237
- }
1238
- async buildTenantHeaders() {
1239
- let tenantKey = "";
1240
- let tenantName = "";
1241
- if (this.platform.ANDROID || this.platform.IOS) {
1242
- tenantKey = await this.utilityService.getLocalStorage('tenantKey');
1243
- tenantName = await this.utilityService.getLocalStorage('tenantName');
1244
- }
1245
- else {
1246
- tenantKey = await this.utilityService.getStorage('tenantKey');
1247
- tenantName = await this.utilityService.getStorage('tenantName');
1248
- }
1249
- const selectedTenant = await this.utilityService.getLocalStorage('selectedTenant');
1250
- if (typeof tenantKey === 'string' && tenantKey.trim()) {
1251
- return { 'X-Tenant-Key': tenantKey.trim() };
1252
- }
1253
- const normalizedTenantName = typeof tenantName === 'string' ? tenantName.trim() : '';
1254
- const normalizedSelectedTenant = typeof selectedTenant === 'string' ? selectedTenant.trim() : '';
1255
- const tenant = normalizedTenantName || normalizedSelectedTenant;
1256
- if (!tenant) {
1257
- throw new Error('Missing tenantKey, tenantName, ' + 'or selectedTenant');
1258
- }
1259
- return { 'X-Tenant': tenant, };
1260
- }
1261
- async parseJsonOrText(response) {
1262
- const rawText = await response.text();
1263
- if (!rawText) {
1128
+ console.error(`Unexpected error while fetching file "${filePath}" from "${couchDbName}"`, error);
1264
1129
  return null;
1265
1130
  }
1266
- try {
1267
- return JSON.parse(rawText);
1268
- }
1269
- catch {
1270
- return rawText;
1271
- }
1272
- }
1273
- stringifyErrorDetails(data) {
1274
- if (typeof data === 'string') {
1275
- return data;
1276
- }
1277
- try {
1278
- return JSON.stringify(data);
1279
- }
1280
- catch {
1281
- return 'Unknown error';
1282
- }
1283
- }
1284
- fromBase64(base64) {
1285
- try {
1286
- const binaryString = atob(base64);
1287
- const bytes = Uint8Array.from(binaryString, character => character.charCodeAt(0));
1288
- return new TextDecoder('utf-8').decode(bytes);
1289
- }
1290
- catch {
1291
- return atob(base64);
1292
- }
1293
- }
1294
- isJsonFile(fileNameOrPath, contentType) {
1295
- const lower = (fileNameOrPath || '').toLowerCase();
1296
- const normalizedContentType = (contentType || '')
1297
- .toLowerCase()
1298
- .split(';')[0]
1299
- .trim();
1300
- return (lower.endsWith('.json') ||
1301
- normalizedContentType ===
1302
- 'application/json');
1303
1131
  }
1304
1132
  isBinaryMediaFile(fileNameOrPath, contentType) {
1305
1133
  const lower = (fileNameOrPath || '').toLowerCase();
1306
- const type = (contentType || '')
1307
- .toLowerCase()
1308
- .split(';')[0]
1309
- .trim();
1134
+ const type = contentType || '';
1310
1135
  return (type.startsWith('image/') ||
1311
1136
  type.startsWith('video/') ||
1312
1137
  type.startsWith('audio/') ||
@@ -1326,53 +1151,113 @@ class Couchdb {
1326
1151
  lower.endsWith('.pdf'));
1327
1152
  }
1328
1153
  getMimeType(fileNameOrPath, contentType) {
1329
- if (contentType &&
1330
- contentType.trim()) {
1331
- return contentType
1332
- .split(';')[0]
1333
- .trim();
1334
- }
1154
+ if (contentType)
1155
+ return contentType;
1335
1156
  const lower = (fileNameOrPath || '').toLowerCase();
1336
- if (lower.endsWith('.png')) {
1157
+ if (lower.endsWith('.png'))
1337
1158
  return 'image/png';
1338
- }
1339
- if (lower.endsWith('.jpg') ||
1340
- lower.endsWith('.jpeg')) {
1159
+ if (lower.endsWith('.jpg') || lower.endsWith('.jpeg'))
1341
1160
  return 'image/jpeg';
1342
- }
1343
- if (lower.endsWith('.ico')) {
1161
+ if (lower.endsWith('.ico'))
1344
1162
  return 'image/x-icon';
1345
- }
1346
- if (lower.endsWith('.svg')) {
1163
+ if (lower.endsWith('.svg'))
1347
1164
  return 'image/svg+xml';
1348
- }
1349
- if (lower.endsWith('.webp')) {
1165
+ if (lower.endsWith('.webp'))
1350
1166
  return 'image/webp';
1351
- }
1352
- if (lower.endsWith('.gif')) {
1167
+ if (lower.endsWith('.gif'))
1353
1168
  return 'image/gif';
1354
- }
1355
- if (lower.endsWith('.mp4')) {
1169
+ if (lower.endsWith('.mp4'))
1356
1170
  return 'video/mp4';
1357
- }
1358
- if (lower.endsWith('.webm')) {
1171
+ if (lower.endsWith('.webm'))
1359
1172
  return 'video/webm';
1360
- }
1361
- if (lower.endsWith('.mp3')) {
1173
+ if (lower.endsWith('.mp3'))
1362
1174
  return 'audio/mpeg';
1363
- }
1364
- if (lower.endsWith('.wav')) {
1175
+ if (lower.endsWith('.wav'))
1365
1176
  return 'audio/wav';
1366
- }
1367
- if (lower.endsWith('.m4a')) {
1177
+ if (lower.endsWith('.m4a'))
1368
1178
  return 'audio/mp4';
1369
- }
1370
- if (lower.endsWith('.pdf')) {
1179
+ if (lower.endsWith('.pdf'))
1371
1180
  return 'application/pdf';
1372
- }
1373
1181
  return 'application/octet-stream';
1374
1182
  }
1375
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: Couchdb, deps: [{ token: UtilityService }, { token: i1.Platform }], target: i0.ɵɵFactoryTarget.Injectable });
1183
+ getImageMimeType(fileNameOrPath) {
1184
+ const lower = (fileNameOrPath || '').toLowerCase();
1185
+ if (lower.endsWith('.png'))
1186
+ return 'image/png';
1187
+ if (lower.endsWith('.jpg') || lower.endsWith('.jpeg'))
1188
+ return 'image/jpeg';
1189
+ if (lower.endsWith('.ico'))
1190
+ return 'image/x-icon';
1191
+ if (lower.endsWith('.svg'))
1192
+ return 'image/svg+xml';
1193
+ return 'image/png';
1194
+ }
1195
+ fromBase64(base64) {
1196
+ try {
1197
+ return decodeURIComponent(escape(atob(base64)));
1198
+ }
1199
+ catch {
1200
+ return atob(base64);
1201
+ }
1202
+ }
1203
+ isJsonFile(fileNameOrPath, contentType) {
1204
+ const lower = (fileNameOrPath || '').toLowerCase();
1205
+ return lower.endsWith('.json') || contentType === 'application/json';
1206
+ }
1207
+ getDocumentUrl(dbName, docId) {
1208
+ return `${this.getDbUrl(dbName)}/${encodeURIComponent(docId)}`;
1209
+ }
1210
+ getDbUrl(dbName) {
1211
+ return `${this.couchDbBaseUrl}/${dbName}`;
1212
+ }
1213
+ async getReadHeaders() {
1214
+ return {
1215
+ Accept: 'application/json',
1216
+ ...(await this.buildTenantHeaders()),
1217
+ };
1218
+ }
1219
+ async buildTenantHeaders() {
1220
+ const tenantKey = await this.utilityService.getStorage('tenantKey');
1221
+ const tenantName = await this.utilityService.getStorage('tenantName');
1222
+ const selectedTenant = await this.utilityService.getLocalStorage('selectedTenant');
1223
+ if (tenantKey) {
1224
+ if (typeof tenantKey !== 'string' || !tenantKey.trim()) {
1225
+ throw new Error('Missing tenantKey');
1226
+ }
1227
+ return {
1228
+ 'X-Tenant-Key': tenantKey.trim(),
1229
+ };
1230
+ }
1231
+ else {
1232
+ if (!tenantName && !selectedTenant) {
1233
+ throw new Error('Missing tenantName');
1234
+ }
1235
+ return {
1236
+ 'X-Tenant': tenantName ? tenantName.trim() : selectedTenant.trim(),
1237
+ };
1238
+ }
1239
+ }
1240
+ async getImageSrcFromCouchDb(couchDbName, filePath) {
1241
+ const dbName = couchDbName?.toLowerCase();
1242
+ const docId = filePath?.trim();
1243
+ if (!docId) {
1244
+ throw new Error('Missing file path');
1245
+ }
1246
+ const response = await fetch(this.getDocumentUrl(dbName, docId), {
1247
+ method: 'GET',
1248
+ headers: await this.getReadHeaders(),
1249
+ });
1250
+ const doc = await this.parseJsonOrText(response);
1251
+ if (!response.ok) {
1252
+ throw new Error(`Failed to fetch image "${docId}" from "${dbName}": ${response.status} ${this.stringifyErrorDetails(doc)}`);
1253
+ }
1254
+ if (!doc?.data) {
1255
+ throw new Error(`Document "${docId}" does not contain image data`);
1256
+ }
1257
+ const mimeType = doc.contentType || 'image/png';
1258
+ return `data:${mimeType};base64,${doc.data}`;
1259
+ }
1260
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: Couchdb, deps: [{ token: UtilityService }], target: i0.ɵɵFactoryTarget.Injectable });
1376
1261
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: Couchdb, providedIn: 'root' });
1377
1262
  }
1378
1263
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: Couchdb, decorators: [{
@@ -1380,7 +1265,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImpor
1380
1265
  args: [{
1381
1266
  providedIn: 'root',
1382
1267
  }]
1383
- }], ctorParameters: () => [{ type: UtilityService }, { type: i1.Platform }] });
1268
+ }], ctorParameters: () => [{ type: UtilityService }] });
1384
1269
 
1385
1270
  class ConfigService {
1386
1271
  couchdbService;