@yomotech/view-toolkit 0.0.78 → 0.0.80

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,105 @@ 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(
1056
+ // `GET /tenant-dbs -> ${response.status} ${this.stringifyErrorDetails(data)}`
1057
+ // );
1058
+ // }
1059
+ return data;
1060
+ }
1061
+ async parseJsonOrText(response) {
1062
+ const rawText = await response.text();
1063
+ if (!rawText)
1064
+ return null;
1065
+ try {
1066
+ return JSON.parse(rawText);
1067
+ }
1068
+ catch {
1069
+ return rawText;
1057
1070
  }
1058
- if (Array.isArray(result.data)) {
1059
- return result.data;
1071
+ }
1072
+ stringifyErrorDetails(data) {
1073
+ if (typeof data === 'string')
1074
+ return data;
1075
+ try {
1076
+ return JSON.stringify(data);
1060
1077
  }
1061
- if (result.data &&
1062
- Array.isArray(result.data.databases)) {
1063
- return result.data;
1078
+ catch {
1079
+ return 'Unknown error';
1064
1080
  }
1065
- throw new Error(`Invalid /tenant-dbs response: ` +
1066
- `${this.stringifyErrorDetails(result.data)}`);
1067
1081
  }
1068
1082
  async getFileContentFromCouchDb(couchDbName, filePath) {
1069
1083
  try {
1070
- const dbName = couchDbName?.trim().toLowerCase();
1084
+ const dbName = couchDbName?.toLowerCase();
1071
1085
  const docId = filePath?.trim();
1072
- if (!dbName) {
1073
- console.error('Missing CouchDB database name');
1074
- return null;
1075
- }
1076
1086
  if (!docId) {
1077
1087
  console.error('Missing file path');
1078
1088
  return null;
1079
1089
  }
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);
1090
+ const response = await fetch(this.getDocumentUrl(dbName, docId), {
1091
+ method: 'GET',
1092
+ headers: await this.getReadHeaders(),
1093
+ });
1094
+ const doc = await this.parseJsonOrText(response);
1095
+ if (!response.ok) {
1096
+ console.error(`Failed to fetch file "${docId}" from "${dbName}": ${response.status}`, doc);
1085
1097
  return null;
1086
1098
  }
1087
1099
  if (!doc?.data) {
1088
- console.error(`Document "${docId}" ` + `does not contain file data`);
1100
+ console.error(`Document "${docId}" does not contain file data`);
1089
1101
  return null;
1090
1102
  }
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);
1103
+ // do not decode images as utf8 text
1104
+ if (doc.type === 'media' ||
1105
+ doc.type === 'base64file' ||
1106
+ this.isBinaryMediaFile(doc.name || doc.path || docId, doc.contentType)) {
1094
1107
  return {
1095
1108
  type: doc.type || 'base64file',
1096
- mimeType,
1109
+ mimeType: this.getMimeType(doc.name || doc.path || docId, doc.contentType),
1097
1110
  base64: doc.data,
1098
- src: `data:${mimeType};base64,` + `${doc.data}`,
1111
+ src: `data:${this.getMimeType(doc.name || doc.path || docId, doc.contentType)};base64,${doc.data}`,
1099
1112
  name: doc.name,
1100
1113
  path: doc.path,
1101
1114
  metadata: doc.metadata || {},
1102
1115
  };
1103
1116
  }
1104
1117
  const decodedContent = this.fromBase64(doc.data);
1105
- if (this.isJsonFile(fileName, doc.contentType)) {
1118
+ if (this.isJsonFile(doc.name || doc.path || docId, doc.contentType)) {
1106
1119
  try {
1107
1120
  return JSON.parse(decodedContent);
1108
1121
  }
1109
1122
  catch (jsonError) {
1110
- console.error(`Failed to parse JSON ` +
1111
- `for file "${docId}"`, jsonError);
1123
+ console.error(`Failed to parse JSON for file "${docId}"`, jsonError);
1112
1124
  return decodedContent;
1113
1125
  }
1114
1126
  }
1115
1127
  return decodedContent;
1116
1128
  }
1117
1129
  catch (error) {
1118
- console.error(`Unexpected error while fetching ` +
1119
- `file "${filePath}" from ` +
1120
- `"${couchDbName}"`, error);
1130
+ console.error(`Unexpected error while fetching file "${filePath}" from "${couchDbName}"`, error);
1121
1131
  return null;
1122
1132
  }
1123
1133
  }
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) {
1264
- return null;
1265
- }
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
- }
1304
1134
  isBinaryMediaFile(fileNameOrPath, contentType) {
1305
1135
  const lower = (fileNameOrPath || '').toLowerCase();
1306
- const type = (contentType || '')
1307
- .toLowerCase()
1308
- .split(';')[0]
1309
- .trim();
1136
+ const type = contentType || '';
1310
1137
  return (type.startsWith('image/') ||
1311
1138
  type.startsWith('video/') ||
1312
1139
  type.startsWith('audio/') ||
@@ -1326,53 +1153,113 @@ class Couchdb {
1326
1153
  lower.endsWith('.pdf'));
1327
1154
  }
1328
1155
  getMimeType(fileNameOrPath, contentType) {
1329
- if (contentType &&
1330
- contentType.trim()) {
1331
- return contentType
1332
- .split(';')[0]
1333
- .trim();
1334
- }
1156
+ if (contentType)
1157
+ return contentType;
1335
1158
  const lower = (fileNameOrPath || '').toLowerCase();
1336
- if (lower.endsWith('.png')) {
1159
+ if (lower.endsWith('.png'))
1337
1160
  return 'image/png';
1338
- }
1339
- if (lower.endsWith('.jpg') ||
1340
- lower.endsWith('.jpeg')) {
1161
+ if (lower.endsWith('.jpg') || lower.endsWith('.jpeg'))
1341
1162
  return 'image/jpeg';
1342
- }
1343
- if (lower.endsWith('.ico')) {
1163
+ if (lower.endsWith('.ico'))
1344
1164
  return 'image/x-icon';
1345
- }
1346
- if (lower.endsWith('.svg')) {
1165
+ if (lower.endsWith('.svg'))
1347
1166
  return 'image/svg+xml';
1348
- }
1349
- if (lower.endsWith('.webp')) {
1167
+ if (lower.endsWith('.webp'))
1350
1168
  return 'image/webp';
1351
- }
1352
- if (lower.endsWith('.gif')) {
1169
+ if (lower.endsWith('.gif'))
1353
1170
  return 'image/gif';
1354
- }
1355
- if (lower.endsWith('.mp4')) {
1171
+ if (lower.endsWith('.mp4'))
1356
1172
  return 'video/mp4';
1357
- }
1358
- if (lower.endsWith('.webm')) {
1173
+ if (lower.endsWith('.webm'))
1359
1174
  return 'video/webm';
1360
- }
1361
- if (lower.endsWith('.mp3')) {
1175
+ if (lower.endsWith('.mp3'))
1362
1176
  return 'audio/mpeg';
1363
- }
1364
- if (lower.endsWith('.wav')) {
1177
+ if (lower.endsWith('.wav'))
1365
1178
  return 'audio/wav';
1366
- }
1367
- if (lower.endsWith('.m4a')) {
1179
+ if (lower.endsWith('.m4a'))
1368
1180
  return 'audio/mp4';
1369
- }
1370
- if (lower.endsWith('.pdf')) {
1181
+ if (lower.endsWith('.pdf'))
1371
1182
  return 'application/pdf';
1372
- }
1373
1183
  return 'application/octet-stream';
1374
1184
  }
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 });
1185
+ getImageMimeType(fileNameOrPath) {
1186
+ const lower = (fileNameOrPath || '').toLowerCase();
1187
+ if (lower.endsWith('.png'))
1188
+ return 'image/png';
1189
+ if (lower.endsWith('.jpg') || lower.endsWith('.jpeg'))
1190
+ return 'image/jpeg';
1191
+ if (lower.endsWith('.ico'))
1192
+ return 'image/x-icon';
1193
+ if (lower.endsWith('.svg'))
1194
+ return 'image/svg+xml';
1195
+ return 'image/png';
1196
+ }
1197
+ fromBase64(base64) {
1198
+ try {
1199
+ return decodeURIComponent(escape(atob(base64)));
1200
+ }
1201
+ catch {
1202
+ return atob(base64);
1203
+ }
1204
+ }
1205
+ isJsonFile(fileNameOrPath, contentType) {
1206
+ const lower = (fileNameOrPath || '').toLowerCase();
1207
+ return lower.endsWith('.json') || contentType === 'application/json';
1208
+ }
1209
+ getDocumentUrl(dbName, docId) {
1210
+ return `${this.getDbUrl(dbName)}/${encodeURIComponent(docId)}`;
1211
+ }
1212
+ getDbUrl(dbName) {
1213
+ return `${this.couchDbBaseUrl}/${dbName}`;
1214
+ }
1215
+ async getReadHeaders() {
1216
+ return {
1217
+ Accept: 'application/json',
1218
+ ...(await this.buildTenantHeaders()),
1219
+ };
1220
+ }
1221
+ async buildTenantHeaders() {
1222
+ const tenantKey = await this.utilityService.getStorage('tenantKey');
1223
+ const tenantName = await this.utilityService.getStorage('tenantName');
1224
+ const selectedTenant = await this.utilityService.getLocalStorage('selectedTenant');
1225
+ if (tenantKey) {
1226
+ if (typeof tenantKey !== 'string' || !tenantKey.trim()) {
1227
+ throw new Error('Missing tenantKey');
1228
+ }
1229
+ return {
1230
+ 'X-Tenant-Key': tenantKey.trim(),
1231
+ };
1232
+ }
1233
+ else {
1234
+ if (!tenantName && !selectedTenant) {
1235
+ throw new Error('Missing tenantName');
1236
+ }
1237
+ return {
1238
+ 'X-Tenant': tenantName ? tenantName.trim() : selectedTenant.trim(),
1239
+ };
1240
+ }
1241
+ }
1242
+ async getImageSrcFromCouchDb(couchDbName, filePath) {
1243
+ const dbName = couchDbName?.toLowerCase();
1244
+ const docId = filePath?.trim();
1245
+ if (!docId) {
1246
+ throw new Error('Missing file path');
1247
+ }
1248
+ const response = await fetch(this.getDocumentUrl(dbName, docId), {
1249
+ method: 'GET',
1250
+ headers: await this.getReadHeaders(),
1251
+ });
1252
+ const doc = await this.parseJsonOrText(response);
1253
+ if (!response.ok) {
1254
+ throw new Error(`Failed to fetch image "${docId}" from "${dbName}": ${response.status} ${this.stringifyErrorDetails(doc)}`);
1255
+ }
1256
+ if (!doc?.data) {
1257
+ throw new Error(`Document "${docId}" does not contain image data`);
1258
+ }
1259
+ const mimeType = doc.contentType || 'image/png';
1260
+ return `data:${mimeType};base64,${doc.data}`;
1261
+ }
1262
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: Couchdb, deps: [{ token: UtilityService }], target: i0.ɵɵFactoryTarget.Injectable });
1376
1263
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: Couchdb, providedIn: 'root' });
1377
1264
  }
1378
1265
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: Couchdb, decorators: [{
@@ -1380,7 +1267,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImpor
1380
1267
  args: [{
1381
1268
  providedIn: 'root',
1382
1269
  }]
1383
- }], ctorParameters: () => [{ type: UtilityService }, { type: i1.Platform }] });
1270
+ }], ctorParameters: () => [{ type: UtilityService }] });
1384
1271
 
1385
1272
  class ConfigService {
1386
1273
  couchdbService;