@lenne.tech/ng-base 0.0.9 → 0.2.1

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.
@@ -4,8 +4,10 @@ import { HttpLink } from 'apollo-angular/http';
4
4
  import * as i0 from '@angular/core';
5
5
  import { InjectionToken, Injectable, Inject, Directive, ElementRef, Input, Output, HostBinding, HostListener, Pipe, NgModule } from '@angular/core';
6
6
  import { BehaviorSubject, Observable, of, throwError } from 'rxjs';
7
- import { ApolloLink } from '@apollo/client/core';
7
+ import { ApolloLink, split, concat } from '@apollo/client/core';
8
8
  import { InMemoryCache } from '@apollo/client/cache';
9
+ import { WebSocketLink } from '@apollo/client/link/ws';
10
+ import { getMainDefinition } from '@apollo/client/utilities';
9
11
  import * as i1$2 from '@angular/platform-browser';
10
12
  import { DomSanitizer, Title, Meta } from '@angular/platform-browser';
11
13
  import * as i1$1 from '@angular/router';
@@ -208,7 +210,8 @@ AuthService.ctorParameters = () => [
208
210
  * Factory for apollo-angular options
209
211
  */
210
212
  function apolloOptionsFactory(baseModuleConfig, httpLink, authService) {
211
- const link = httpLink.create({
213
+ const links = [];
214
+ const http = httpLink.create({
212
215
  uri: baseModuleConfig.apiUrl,
213
216
  });
214
217
  const authMiddleware = new ApolloLink((operation, forward) => {
@@ -222,8 +225,44 @@ function apolloOptionsFactory(baseModuleConfig, httpLink, authService) {
222
225
  }
223
226
  return forward(operation);
224
227
  });
228
+ if (baseModuleConfig.wsUrl) {
229
+ let wsClient;
230
+ if (localStorage) {
231
+ const token = authService.token || null;
232
+ wsClient = new WebSocketLink({
233
+ uri: baseModuleConfig.wsUrl,
234
+ options: {
235
+ reconnect: true,
236
+ connectionParams: {
237
+ authToken: token,
238
+ },
239
+ },
240
+ });
241
+ }
242
+ else {
243
+ wsClient = new WebSocketLink({
244
+ uri: baseModuleConfig.wsUrl,
245
+ options: {
246
+ reconnect: true,
247
+ },
248
+ });
249
+ }
250
+ // using the ability to split links, you can send data to each link
251
+ // depending on what kind of operation is being sent
252
+ links.push(split(
253
+ // split based on operation type
254
+ ({ query }) => {
255
+ // @ts-ignore
256
+ const { kind, operation } = getMainDefinition(query);
257
+ return kind === 'OperationDefinition' && operation === 'subscription';
258
+ }, wsClient, concat(authMiddleware, http)));
259
+ }
260
+ else {
261
+ links.push(http);
262
+ links.push(authMiddleware);
263
+ }
225
264
  return {
226
- link: ApolloLink.from([authMiddleware, link]),
265
+ link: ApolloLink.from(links),
227
266
  cache: new InMemoryCache(),
228
267
  defaultOptions: {
229
268
  query: {
@@ -566,7 +605,7 @@ const elements = [
566
605
  ResizableDirective,
567
606
  // Pipes
568
607
  EllipsesPipe,
569
- SafeHtmlPipe
608
+ SafeHtmlPipe,
570
609
  ];
571
610
  /**
572
611
  * Base module
@@ -577,27 +616,36 @@ class BaseModule {
577
616
  */
578
617
  static forRoot(baseModuleConfig = {}) {
579
618
  // Default config
580
- const config = Object.assign({ apiUrl: 'localhost:300', authGuardRedirectUrl: '/auth', version: null, prefix: null, scrollDetectionOffset: 200, scrollOffset: 100, storageType: 'local' }, baseModuleConfig);
619
+ const config = Object.assign({ apiUrl: 'localhost:3000', authGuardRedirectUrl: '/auth', logging: false, version: null, prefix: null, scrollDetectionOffset: 200, scrollOffset: 100, storageType: 'local' }, baseModuleConfig);
620
+ // Prepare providers
621
+ const providers = [
622
+ {
623
+ provide: BASE_MODULE_CONFIG,
624
+ useValue: baseModuleConfig,
625
+ },
626
+ ];
627
+ // Add apollo features if API URL is set
628
+ if (baseModuleConfig.apiUrl) {
629
+ providers.push({
630
+ provide: APOLLO_OPTIONS,
631
+ useFactory: apolloOptionsFactory,
632
+ deps: [BASE_MODULE_CONFIG, HttpLink, AuthService],
633
+ });
634
+ }
635
+ else if (config.logging) {
636
+ console.log('apiUrl is missing, ApolloLink is not initialized');
637
+ }
638
+ // Return root module
581
639
  return {
582
640
  ngModule: BaseModule,
583
- providers: [
584
- {
585
- provide: BASE_MODULE_CONFIG,
586
- useValue: baseModuleConfig
587
- },
588
- {
589
- provide: APOLLO_OPTIONS,
590
- useFactory: apolloOptionsFactory,
591
- deps: [BASE_MODULE_CONFIG, HttpLink, AuthService],
592
- }
593
- ]
641
+ providers,
594
642
  };
595
643
  }
596
644
  }
597
645
  BaseModule.decorators = [
598
646
  { type: NgModule, args: [{
599
647
  declarations: elements,
600
- exports: elements
648
+ exports: elements,
601
649
  },] }
602
650
  ];
603
651
 
@@ -1527,13 +1575,29 @@ class GraphQLService {
1527
1575
  const documentNode = fields
1528
1576
  ? gql(config.type + '{\n' + graphql + args + fields + '\n}')
1529
1577
  : gql(config.type + '{\n' + graphql + args + '\n}');
1578
+ // Log
1579
+ if (config.log) {
1580
+ console.log({ documentNode });
1581
+ }
1530
1582
  const request = {};
1531
1583
  request[config.type] = documentNode;
1532
1584
  // Log
1533
1585
  if (config.log) {
1534
1586
  console.log({ request });
1535
1587
  }
1536
- const func = config.type === GraphQLRequestType.MUTATION ? 'mutate' : config.type;
1588
+ let func;
1589
+ if (config.type === GraphQLRequestType.MUTATION) {
1590
+ func = 'mutate';
1591
+ request[config.type] = documentNode;
1592
+ }
1593
+ else if (config.type === GraphQLRequestType.SUBSCRIPTION) {
1594
+ func = 'subscribe';
1595
+ request.query = documentNode;
1596
+ }
1597
+ else {
1598
+ func = config.type;
1599
+ request[config.type] = documentNode;
1600
+ }
1537
1601
  this.apollo[func](request).subscribe((result) => {
1538
1602
  var _a;
1539
1603
  const data = ((_a = result === null || result === void 0 ? void 0 : result.data) === null || _a === void 0 ? void 0 : _a[graphql]) !== undefined ? result.data[graphql] : result;
@@ -1551,8 +1615,10 @@ class GraphQLService {
1551
1615
  else {
1552
1616
  subscriber.next(config.model.map(data));
1553
1617
  }
1554
- // Done
1555
- subscriber.complete();
1618
+ if (config.type !== GraphQLRequestType.SUBSCRIPTION) {
1619
+ // Done
1620
+ subscriber.complete();
1621
+ }
1556
1622
  }, (error) => {
1557
1623
  subscriber.error(error);
1558
1624
  subscriber.complete();
@@ -1563,14 +1629,23 @@ class GraphQLService {
1563
1629
  /**
1564
1630
  * Get fields / args from IGraphQLTypeCollection
1565
1631
  */
1566
- graphQLTypeCollectionToStringArray(collection, current = '', result = []) {
1632
+ graphQLTypeCollectionToStringArray(collection, current = '', result = [], cacheNode = []) {
1567
1633
  if (collection) {
1568
1634
  if (collection instanceof GraphQLType) {
1569
1635
  result.push(current);
1570
1636
  }
1571
1637
  else {
1638
+ if (current === null || current === void 0 ? void 0 : current.includes('.')) {
1639
+ cacheNode.push(current.split('.')[1]);
1640
+ }
1641
+ else if (current) {
1642
+ cacheNode.push(current);
1643
+ }
1572
1644
  for (const key of Object.keys(collection)) {
1573
- this.graphQLTypeCollectionToStringArray(collection[key], current ? current + '.' + key : key, result);
1645
+ if (current === key || cacheNode.includes(key)) {
1646
+ continue;
1647
+ }
1648
+ this.graphQLTypeCollectionToStringArray(collection[key], current ? current + '.' + key : key, result, cacheNode);
1574
1649
  }
1575
1650
  }
1576
1651
  }
@@ -1580,13 +1655,13 @@ class GraphQLService {
1580
1655
  * Prepare arguments for GraphQL request
1581
1656
  */
1582
1657
  prepareArguments(args, options = {}) {
1583
- // Config
1658
+ // Init config variables
1584
1659
  const { allowed, level, parent, schemaArgs, usedArgs } = Object.assign({ allowed: null, level: 1, parent: '', schemaArgs: [], usedArgs: [] }, options);
1585
1660
  // Check args
1586
- if (!args) {
1661
+ if (args === undefined || args === null) {
1587
1662
  return { argsString: '', schemaArgs, usedArgs };
1588
1663
  }
1589
- // Process args
1664
+ // Init args
1590
1665
  const result = [];
1591
1666
  // Process array
1592
1667
  if (Array.isArray(args)) {
@@ -1599,6 +1674,7 @@ class GraphQLService {
1599
1674
  }
1600
1675
  key = allowedKeys === null || allowedKeys === void 0 ? void 0 : allowedKeys.shift();
1601
1676
  }
1677
+ // Process value
1602
1678
  result.push(this.prepareArguments(item, {
1603
1679
  allowed: key ? allowed[key] : null,
1604
1680
  level: level + 1,
@@ -1607,10 +1683,13 @@ class GraphQLService {
1607
1683
  usedArgs,
1608
1684
  }).argsString);
1609
1685
  }
1686
+ // Encapsulation of the array result
1610
1687
  if (result.length) {
1688
+ // Complete result, encapsulated via round brackets
1611
1689
  if (level === 1) {
1612
1690
  return { argsString: '(' + result.join(', ') + ')', schemaArgs, usedArgs };
1613
1691
  }
1692
+ // Deeper result part, encapsulated via square brackets
1614
1693
  else {
1615
1694
  return { argsString: '[' + result.join(', ') + ']', schemaArgs, usedArgs };
1616
1695
  }
@@ -1618,62 +1697,92 @@ class GraphQLService {
1618
1697
  }
1619
1698
  // Process object
1620
1699
  else if (typeof args === 'object') {
1700
+ // Check object is empty
1701
+ if (args && Object.keys(args).length === 0 && Object.getPrototypeOf(args) === Object.prototype) {
1702
+ return { argsString: '{}', schemaArgs, usedArgs };
1703
+ }
1704
+ // Process all object entries
1621
1705
  for (const [key, value] of Object.entries(args)) {
1706
+ // Init data for current entry
1622
1707
  const currentKey = parent + key;
1623
1708
  schemaArgs.push(currentKey);
1709
+ // If the allowed key handling is enabled and the current key is not included in the list of allowed keys,
1710
+ // the current key will be skipped
1624
1711
  if (allowed && !allowed[key]) {
1625
1712
  continue;
1626
1713
  }
1627
- if (value !== undefined && value !== null) {
1628
- usedArgs.push(currentKey);
1629
- if (value instanceof GraphQLEnum) {
1630
- result.push(key + ':' + value.value);
1631
- continue;
1714
+ // Skip value if not exists
1715
+ if (value === undefined && value === null) {
1716
+ continue;
1717
+ }
1718
+ // Add current key to metadata
1719
+ usedArgs.push(currentKey);
1720
+ // Process GraphQLEnum
1721
+ if (value instanceof GraphQLEnum) {
1722
+ result.push(key + ':' + value.value);
1723
+ continue;
1724
+ }
1725
+ // Process array
1726
+ else if (Array.isArray(value)) {
1727
+ result.push(key +
1728
+ ': [' +
1729
+ value.map((item) => this.prepareArguments(item, {
1730
+ allowed: allowed[key],
1731
+ level: level + 1,
1732
+ parent: currentKey + '.',
1733
+ schemaArgs,
1734
+ usedArgs,
1735
+ }).argsString) +
1736
+ ']');
1737
+ continue;
1738
+ }
1739
+ // Prepare additional result string
1740
+ let additionalResult = key + ': ';
1741
+ // Value is a date object
1742
+ if (typeof value === 'object' && Object.prototype.toString.call(value) === '[object Date]') {
1743
+ additionalResult += `"""${value.toString()}"""`;
1744
+ }
1745
+ // Value is a string
1746
+ else if (typeof value === 'string') {
1747
+ // Enum (doesn't need quotation marks)
1748
+ if (allowed[key].isEnum) {
1749
+ additionalResult += value;
1632
1750
  }
1633
- if (Array.isArray(value)) {
1634
- result.push(key +
1635
- ': [' +
1636
- value.map((item) => this.prepareArguments(item, {
1637
- allowed: allowed[key],
1638
- level: level + 1,
1639
- parent: currentKey + '.',
1640
- schemaArgs,
1641
- usedArgs,
1642
- }).argsString) +
1643
- ']');
1644
- continue;
1751
+ // String
1752
+ else {
1753
+ additionalResult += `"""${value.replace(/"/g, '\\"')}"""`;
1645
1754
  }
1646
- result.push(key +
1647
- ': ' +
1648
- (typeof value === 'string' ||
1649
- typeof value === 'boolean' ||
1650
- Object.prototype.toString.call(value) === '[object Date]'
1651
- ? allowed[key].isEnum
1652
- ? value
1653
- : typeof value === 'string'
1654
- ? `"""${value.replace(/"/g, '\\"')}"""`
1655
- : Object.prototype.toString.call(value) === '[object Date]'
1656
- ? `"""${value.toString()}"""`
1657
- : value
1658
- : this.prepareArguments(value, {
1659
- allowed: allowed[key],
1660
- level: level + 1,
1661
- parent: currentKey + '.',
1662
- schemaArgs,
1663
- usedArgs,
1664
- }).argsString));
1665
1755
  }
1756
+ // Value is a simple boolean or a number
1757
+ else if (typeof value === 'boolean' || typeof value === 'number') {
1758
+ additionalResult += value;
1759
+ }
1760
+ // Others
1761
+ else {
1762
+ additionalResult += this.prepareArguments(value, {
1763
+ allowed: allowed[key],
1764
+ level: level + 1,
1765
+ parent: currentKey + '.',
1766
+ schemaArgs,
1767
+ usedArgs,
1768
+ }).argsString;
1769
+ }
1770
+ // Push deeper part into result array
1771
+ result.push(additionalResult);
1666
1772
  }
1773
+ // Encapsulation of the object result
1667
1774
  if (result.length) {
1775
+ // Complete result, encapsulated via round brackets
1668
1776
  if (level === 1) {
1669
1777
  return { argsString: '(' + result.join(', ') + ')', schemaArgs, usedArgs };
1670
1778
  }
1779
+ // Deeper result part, encapsulated via curly brackets
1671
1780
  else {
1672
1781
  return { argsString: '{' + result.join(', ') + '}', schemaArgs, usedArgs };
1673
1782
  }
1674
1783
  }
1675
1784
  }
1676
- // Others
1785
+ // Prepare and process other / unknown values as JSON
1677
1786
  else {
1678
1787
  return { argsString: JSON.stringify(args), schemaArgs, usedArgs };
1679
1788
  }
@@ -1830,7 +1939,9 @@ class GraphQLPlusService extends GraphQLService {
1830
1939
  }
1831
1940
  subscriber.next(response);
1832
1941
  this.handleLoader('stop', options);
1833
- subscriber.complete();
1942
+ if (options.type !== GraphQLRequestType.SUBSCRIPTION) {
1943
+ subscriber.complete();
1944
+ }
1834
1945
  }, (error) => {
1835
1946
  if (!options.ignoreErrors) {
1836
1947
  this.handleError(error, options.excludedErrors);