@equinor/fusion-framework-module-services 0.1.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.
Files changed (88) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/esm/configurator.js +3 -0
  3. package/dist/esm/configurator.js.map +1 -0
  4. package/dist/esm/context/api-models.js +2 -0
  5. package/dist/esm/context/api-models.js.map +1 -0
  6. package/dist/esm/context/client.js +22 -0
  7. package/dist/esm/context/client.js.map +1 -0
  8. package/dist/esm/context/get/client.js +4 -0
  9. package/dist/esm/context/get/client.js.map +1 -0
  10. package/dist/esm/context/get/generate-endpoint.js +18 -0
  11. package/dist/esm/context/get/generate-endpoint.js.map +1 -0
  12. package/dist/esm/context/get/generate-parameters.js +7 -0
  13. package/dist/esm/context/get/generate-parameters.js.map +1 -0
  14. package/dist/esm/context/get/index.js +6 -0
  15. package/dist/esm/context/get/index.js.map +1 -0
  16. package/dist/esm/context/get/types.js +2 -0
  17. package/dist/esm/context/get/types.js.map +1 -0
  18. package/dist/esm/context/index.js +5 -0
  19. package/dist/esm/context/index.js.map +1 -0
  20. package/dist/esm/context/query/client.js +4 -0
  21. package/dist/esm/context/query/client.js.map +1 -0
  22. package/dist/esm/context/query/generate-endpoint.js +47 -0
  23. package/dist/esm/context/query/generate-endpoint.js.map +1 -0
  24. package/dist/esm/context/query/generate-parameters.js +7 -0
  25. package/dist/esm/context/query/generate-parameters.js.map +1 -0
  26. package/dist/esm/context/query/index.js +6 -0
  27. package/dist/esm/context/query/index.js.map +1 -0
  28. package/dist/esm/context/query/types.js +2 -0
  29. package/dist/esm/context/query/types.js.map +1 -0
  30. package/dist/esm/context/static.js +6 -0
  31. package/dist/esm/context/static.js.map +1 -0
  32. package/dist/esm/context/types.js +2 -0
  33. package/dist/esm/context/types.js.map +1 -0
  34. package/dist/esm/errors.js +7 -0
  35. package/dist/esm/errors.js.map +1 -0
  36. package/dist/esm/index.js +5 -0
  37. package/dist/esm/index.js.map +1 -0
  38. package/dist/esm/module.js +51 -0
  39. package/dist/esm/module.js.map +1 -0
  40. package/dist/esm/provider.js +30 -0
  41. package/dist/esm/provider.js.map +1 -0
  42. package/dist/esm/types.js +2 -0
  43. package/dist/esm/types.js.map +1 -0
  44. package/dist/tsconfig.tsbuildinfo +1 -0
  45. package/dist/types/configurator.d.ts +6 -0
  46. package/dist/types/context/api-models.d.ts +31 -0
  47. package/dist/types/context/client.d.ts +13 -0
  48. package/dist/types/context/get/client.d.ts +4 -0
  49. package/dist/types/context/get/generate-endpoint.d.ts +2 -0
  50. package/dist/types/context/get/generate-parameters.d.ts +4 -0
  51. package/dist/types/context/get/index.d.ts +5 -0
  52. package/dist/types/context/get/types.d.ts +19 -0
  53. package/dist/types/context/index.d.ts +4 -0
  54. package/dist/types/context/query/client.d.ts +4 -0
  55. package/dist/types/context/query/generate-endpoint.d.ts +3 -0
  56. package/dist/types/context/query/generate-parameters.d.ts +4 -0
  57. package/dist/types/context/query/index.d.ts +5 -0
  58. package/dist/types/context/query/types.d.ts +32 -0
  59. package/dist/types/context/static.d.ts +4 -0
  60. package/dist/types/context/types.d.ts +1 -0
  61. package/dist/types/errors.d.ts +4 -0
  62. package/dist/types/index.d.ts +5 -0
  63. package/dist/types/module.d.ts +20 -0
  64. package/dist/types/provider.d.ts +22 -0
  65. package/dist/types/types.d.ts +13 -0
  66. package/package.json +60 -0
  67. package/src/configurator.ts +8 -0
  68. package/src/context/api-models.ts +42 -0
  69. package/src/context/client.ts +49 -0
  70. package/src/context/get/client.ts +33 -0
  71. package/src/context/get/generate-endpoint.ts +25 -0
  72. package/src/context/get/generate-parameters.ts +23 -0
  73. package/src/context/get/index.ts +8 -0
  74. package/src/context/get/types.ts +52 -0
  75. package/src/context/index.ts +6 -0
  76. package/src/context/query/client.ts +35 -0
  77. package/src/context/query/generate-endpoint.ts +65 -0
  78. package/src/context/query/generate-parameters.ts +23 -0
  79. package/src/context/query/index.ts +8 -0
  80. package/src/context/query/types.ts +63 -0
  81. package/src/context/static.ts +6 -0
  82. package/src/context/types.ts +5 -0
  83. package/src/errors.ts +5 -0
  84. package/src/index.ts +6 -0
  85. package/src/module.ts +101 -0
  86. package/src/provider.ts +51 -0
  87. package/src/types.ts +41 -0
  88. package/tsconfig.json +38 -0
@@ -0,0 +1,65 @@
1
+ import buildOdataQuery from 'odata-query';
2
+
3
+ import { UnsupportedApiVersion } from '@equinor/fusion-framework-module-services/errors';
4
+
5
+ import { ApiVersion } from '@equinor/fusion-framework-module-services/context';
6
+
7
+ import type {
8
+ QueryContextArgs,
9
+ QueryContextOdataFilter,
10
+ QueryContextOdataParameters,
11
+ } from './types';
12
+
13
+ const buildOdataFilter = (filterObj: QueryContextOdataFilter) => {
14
+ return Object.keys(filterObj).reduce((acc, key) => {
15
+ switch (key) {
16
+ case 'type':
17
+ return filterObj[key]?.length ? { ...acc, [key]: { in: filterObj[key] } } : acc;
18
+ default:
19
+ return { ...acc, [key]: filterObj[key as keyof typeof filterObj] };
20
+ }
21
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
+ }, {} as any);
23
+ };
24
+
25
+ const buildOdataObject = (parameters: QueryContextOdataParameters) => {
26
+ return Object.keys(parameters).reduce((acc, key) => {
27
+ switch (key) {
28
+ case 'filter':
29
+ return {
30
+ ...acc,
31
+ [key]: buildOdataFilter(parameters['filter'] as QueryContextOdataFilter),
32
+ };
33
+ default:
34
+ return { ...acc, [key]: parameters[key as keyof typeof parameters] };
35
+ }
36
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
37
+ }, {} as any);
38
+ };
39
+
40
+ const createSearchParameters = (args: string | QueryContextOdataParameters) => {
41
+ return typeof args === 'string' ? args : buildOdataQuery(buildOdataObject(args));
42
+ };
43
+
44
+ export const generateEndpoint = <TVersion extends string = keyof typeof ApiVersion>(
45
+ version: TVersion,
46
+ args: QueryContextArgs<TVersion>
47
+ ) => {
48
+ const apiVersion = ApiVersion[version as keyof typeof ApiVersion] ?? version;
49
+ switch (apiVersion) {
50
+ case ApiVersion.v2:
51
+ throw new UnsupportedApiVersion(version);
52
+ case ApiVersion.v1:
53
+ default: {
54
+ const { query, includeDeleted } = args as QueryContextArgs<'v1'>;
55
+ const params = new URLSearchParams(createSearchParameters(query));
56
+ params.append('api-version', apiVersion);
57
+ if (includeDeleted) {
58
+ params.append('includeDeleted', 'true');
59
+ }
60
+ return `/contexts/?${String(params)}`;
61
+ }
62
+ }
63
+ };
64
+
65
+ export default generateEndpoint;
@@ -0,0 +1,23 @@
1
+ import { ClientRequestInit, IHttpClient } from '@equinor/fusion-framework-module-http/client';
2
+
3
+ import { ApiVersion } from '@equinor/fusion-framework-module-services/context';
4
+
5
+ import { generateEndpoint } from './generate-endpoint';
6
+
7
+ import type { QueryContextArgs, ApiClientArguments } from './types';
8
+
9
+ /** Function for generating parameter for querying context service */
10
+ export const generateParameters = <
11
+ TResult,
12
+ TVersion extends string = keyof typeof ApiVersion,
13
+ TClient extends IHttpClient = IHttpClient
14
+ >(
15
+ version: TVersion,
16
+ args: QueryContextArgs<TVersion>,
17
+ init?: ClientRequestInit<TClient, TResult>
18
+ ): ApiClientArguments<TClient, TResult> => {
19
+ const path = generateEndpoint(version, args);
20
+ return [path, init];
21
+ };
22
+
23
+ export default generateParameters;
@@ -0,0 +1,8 @@
1
+ export { ApiVersion, ApiContextEntity } from '@equinor/fusion-framework-module-services/context';
2
+
3
+ export { generateEndpoint } from './generate-endpoint';
4
+ export { generateParameters } from './generate-parameters';
5
+
6
+ export * from './types';
7
+
8
+ export { queryContext, default } from './client';
@@ -0,0 +1,63 @@
1
+ import { IHttpClient, ClientRequestInit } from '@equinor/fusion-framework-module-http/client';
2
+
3
+ import {
4
+ ApiVersion,
5
+ ApiContextEntity,
6
+ ClientMethod,
7
+ } from '@equinor/fusion-framework-module-services/context';
8
+
9
+ export {
10
+ ApiClientArguments,
11
+ ClientMethod,
12
+ } from '@equinor/fusion-framework-module-services/context';
13
+
14
+ export type QueryContextOdataFilter = {
15
+ type?: string[];
16
+ externalId?: string;
17
+ };
18
+
19
+ export type QueryContextOdataParameters = {
20
+ search?: string;
21
+ filter?: QueryContextOdataFilter;
22
+ };
23
+
24
+ type QueryContextArgs_v1 = {
25
+ query: string | QueryContextOdataParameters;
26
+ includeDeleted?: boolean;
27
+ };
28
+
29
+ type QueryContextArgs_v2 = QueryContextArgs_v1;
30
+
31
+ type SearchContextArgTypes = {
32
+ [ApiVersion.v1]: QueryContextArgs_v1;
33
+ [ApiVersion.v2]: QueryContextArgs_v2;
34
+ };
35
+
36
+ export type QueryContextArgs<T> = T extends keyof typeof ApiVersion
37
+ ? SearchContextArgTypes[typeof ApiVersion[T]]
38
+ : { query: { search: string } };
39
+
40
+ type QueryContextResponseTypes = {
41
+ [ApiVersion.v1]: Array<ApiContextEntity<ApiVersion.v1>>;
42
+ [ApiVersion.v2]: Array<ApiContextEntity<ApiVersion.v2>>;
43
+ };
44
+
45
+ export type QueryContextResponse<T> = T extends keyof typeof ApiVersion
46
+ ? QueryContextResponseTypes[typeof ApiVersion[T]]
47
+ : unknown;
48
+
49
+ export type QueryContextFn<
50
+ TVersion extends string = keyof typeof ApiVersion,
51
+ TMethod extends keyof ClientMethod<unknown> = keyof ClientMethod<unknown>,
52
+ TClient extends IHttpClient = IHttpClient,
53
+ TResult = QueryContextResponse<TVersion>
54
+ > = (
55
+ args: QueryContextArgs<TVersion>,
56
+ init?: ClientRequestInit<TClient, TResult>
57
+ ) => QueryContextResult<TVersion, TMethod, TResult>;
58
+
59
+ export type QueryContextResult<
60
+ TVersion extends string = keyof typeof ApiVersion,
61
+ TMethod extends keyof ClientMethod<unknown> = keyof ClientMethod<unknown>,
62
+ TResult = QueryContextResponse<TVersion>
63
+ > = ClientMethod<TResult>[TMethod];
@@ -0,0 +1,6 @@
1
+ /** index of api versions of context service */
2
+ export enum ApiVersion {
3
+ 'v1' = '1.0',
4
+ /** not in use atm */
5
+ 'v2' = '2.0',
6
+ }
@@ -0,0 +1,5 @@
1
+ export {
2
+ ClientMethodType,
3
+ ClientMethod,
4
+ ApiClientArguments,
5
+ } from '@equinor/fusion-framework-module-services';
package/src/errors.ts ADDED
@@ -0,0 +1,5 @@
1
+ export class UnsupportedApiVersion extends Error {
2
+ constructor(public readonly version: string | number, cause?: unknown) {
3
+ super(`unsupported version ${version}`, { cause });
4
+ }
5
+ }
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ export * from './types';
2
+ export type { ServicesModule, ServicesModuleKey } from './module';
3
+
4
+ export { ApiConfigurator, IApiConfigurator } from './configurator';
5
+ export { ApiProvider, IApiProvider, Service } from './provider';
6
+ export { default, module, enableServices, configureServices } from './module';
package/src/module.ts ADDED
@@ -0,0 +1,101 @@
1
+ import type {
2
+ IModuleConfigurator,
3
+ IModulesConfigurator,
4
+ Module,
5
+ } from '@equinor/fusion-framework-module';
6
+ import type { HttpModule, IHttpClientProvider } from '@equinor/fusion-framework-module-http';
7
+ import type {
8
+ ServiceDiscoveryModule,
9
+ ServiceDiscoveryProvider,
10
+ } from '@equinor/fusion-framework-module-service-discovery';
11
+
12
+ import { IApiConfigurator, ApiConfigurator } from './configurator';
13
+ import { IApiProvider, ApiProvider } from './provider';
14
+
15
+ import type { ApiClientFactory } from './types';
16
+
17
+ export type ServicesModuleKey = 'services';
18
+
19
+ export const moduleKey: ServicesModuleKey = 'services';
20
+
21
+ export type ServicesModule = Module<
22
+ ServicesModuleKey,
23
+ IApiProvider,
24
+ IApiConfigurator,
25
+ [HttpModule, ServiceDiscoveryModule]
26
+ >;
27
+
28
+ /**
29
+ * Method to trying to resolve method for creating an IHttpClient
30
+ */
31
+ const createDefaultClient =
32
+ (http: IHttpClientProvider, serviceDiscovery?: ServiceDiscoveryProvider): ApiClientFactory =>
33
+ async (name: string) => {
34
+ if (http.hasClient(name)) {
35
+ return http.createClient(name);
36
+ }
37
+ if (serviceDiscovery) {
38
+ return serviceDiscovery.createClient(name);
39
+ }
40
+ throw Error(`failed to create http client for service ${name}`);
41
+ };
42
+
43
+ /**
44
+ * Configure http-client
45
+ */
46
+ export const module: ServicesModule = {
47
+ name: moduleKey,
48
+ configure: () => new ApiConfigurator(),
49
+ initialize: async ({ ref, config, requireInstance, hasModule }) => {
50
+ /** we can not create this callback within the configuration, since it might require other modules. */
51
+ if (!config.createClient) {
52
+ const http = await requireInstance('http');
53
+ const serviceDiscovery: ServiceDiscoveryProvider | undefined = hasModule(
54
+ 'serviceDiscovery'
55
+ )
56
+ ? /** if the module is within module, await creation */
57
+ await requireInstance('serviceDiscovery')
58
+ : /** try to load parent service discovery provider */
59
+ ref?.serviceDiscovery;
60
+
61
+ config.createClient = createDefaultClient(http, serviceDiscovery);
62
+ }
63
+ if (!config.createClient) {
64
+ throw Error('missing configuration for creating API client');
65
+ }
66
+ return new ApiProvider(config as Required<IApiConfigurator>);
67
+ },
68
+ };
69
+
70
+ /**
71
+ * Method for enabling the Service module
72
+ * @param config - configuration object
73
+ */
74
+ export const enableServices = (config: IModulesConfigurator): void => {
75
+ config.addConfig({ module });
76
+ };
77
+
78
+ /**
79
+ * @example
80
+ * ```ts
81
+ * config.addConfig(x => x.createClient(...));
82
+ * ```
83
+ * @param configure - Callback for configuring the module
84
+ * @returns Configuration object
85
+ */
86
+ export const configureServices = (
87
+ configure: (configurator: IApiConfigurator) => void
88
+ ): IModuleConfigurator<ServicesModule> => {
89
+ return {
90
+ module,
91
+ configure,
92
+ };
93
+ };
94
+
95
+ declare module '@equinor/fusion-framework-module' {
96
+ interface Modules {
97
+ services: ServicesModule;
98
+ }
99
+ }
100
+
101
+ export default module;
@@ -0,0 +1,51 @@
1
+ import { IHttpClient } from '@equinor/fusion-framework-module-http';
2
+ import { ClientMethod } from './types';
3
+
4
+ import { ApiClientFactory } from './types';
5
+ import { ContextApiClient } from './context';
6
+
7
+ export enum Service {
8
+ Context = 'context',
9
+ }
10
+
11
+ type ApiServices<TMethod extends keyof ClientMethod, TClient extends IHttpClient> = {
12
+ [Service.Context]: ContextApiClient<TMethod, TClient>;
13
+ };
14
+
15
+ export interface IApiProvider<TClient extends IHttpClient = IHttpClient> {
16
+ /**
17
+ * @param name - Name of the service to use
18
+ * @param version - Version of the service to use
19
+ */
20
+ createApiClient<TService extends Service, TMethod extends keyof ClientMethod>(
21
+ name: TService,
22
+ version: TMethod
23
+ ): Promise<ApiServices<TMethod, TClient>[TService]>;
24
+ }
25
+
26
+
27
+ type ApiProviderCtorArgs<TClient extends IHttpClient = IHttpClient> = {
28
+ /** method for creating IHttpClients for api clients */
29
+ createClient: ApiClientFactory<TClient>;
30
+ };
31
+
32
+ export class ApiProvider<TClient extends IHttpClient = IHttpClient>
33
+ implements IApiProvider<TClient>
34
+ {
35
+ protected _createClientFn: ApiClientFactory<TClient>;
36
+ constructor({ createClient }: ApiProviderCtorArgs<TClient>) {
37
+ this._createClientFn = createClient;
38
+ }
39
+
40
+ public async createApiClient<TService extends Service, TMethod extends keyof ClientMethod>(
41
+ name: TService,
42
+ method: TMethod
43
+ ): Promise<ApiServices<TMethod, TClient>[TService]> {
44
+ const httpClient = await this._createClientFn(name);
45
+ switch (name) {
46
+ case Service.Context:
47
+ return new ContextApiClient(httpClient, method);
48
+ }
49
+ throw Error(`could not create api client for [${name}]`);
50
+ }
51
+ }
package/src/types.ts ADDED
@@ -0,0 +1,41 @@
1
+ import {
2
+ ClientRequestInit,
3
+ IHttpClient,
4
+ FetchResponse,
5
+ StreamResponse,
6
+ } from '@equinor/fusion-framework-module-http/client';
7
+
8
+ export type ApiClientFactory<TClient extends IHttpClient = IHttpClient> = (
9
+ name: string
10
+ ) => Promise<TClient>;
11
+
12
+ export type ApiClientArguments<TClient extends IHttpClient, TResult = unknown> = [
13
+ path: string,
14
+ init?: ClientRequestInit<TClient, TResult>
15
+ ];
16
+
17
+ /**
18
+ * Execute methods on the IHttpClient
19
+ */
20
+ export type ClientMethod<T = unknown> = {
21
+ /**
22
+ * Fetch data async
23
+ * NOTE: data needs to be extracted from the response
24
+ */
25
+ fetch: Promise<FetchResponse<T>>;
26
+ /**
27
+ * Fetch JSON data from a service
28
+ */
29
+ json: Promise<T>;
30
+ /**
31
+ * Fetch data as an observable
32
+ * NOTE: data needs to be extracted from the response
33
+ */
34
+ fetch$: StreamResponse<FetchResponse<T>>;
35
+ /**
36
+ * Fetch JSON data from a service as observable
37
+ */
38
+ json$: StreamResponse<T>;
39
+ };
40
+
41
+ export type ClientMethodType = keyof ClientMethod;
package/tsconfig.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist/esm",
5
+ "rootDir": "src",
6
+ "declarationDir": "./dist/types",
7
+ "baseUrl": "src",
8
+ "paths": {
9
+ "@equinor/fusion-framework-module-services": [
10
+ "."
11
+ ],
12
+ "@equinor/fusion-framework-module-services/*": [
13
+ "./*"
14
+ ]
15
+ }
16
+ },
17
+ "references": [
18
+ {
19
+ "path": "../observable"
20
+ },
21
+ {
22
+ "path": "../module"
23
+ },
24
+ {
25
+ "path": "../module-http"
26
+ },
27
+ {
28
+ "path": "../module-service-discovery"
29
+ }
30
+ ],
31
+ "include": [
32
+ "src/**/*",
33
+ ],
34
+ "exclude": [
35
+ "node_modules",
36
+ "lib"
37
+ ]
38
+ }