@obsidiane/meridiane 2.0.10 → 2.0.12
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.
- package/README.md +19 -2
- package/cli.js +21 -37
- package/package.json +13 -6
- package/src/README.md +9 -0
- package/{tools/app → src/application}/bridge-workflow.js +29 -23
- package/src/application/generate-bridge.js +50 -0
- package/{tools/app → src/application}/run-build.js +1 -1
- package/{tools/app → src/application}/run-dev.js +30 -36
- package/{tools/app → src/application}/run-generate.js +3 -3
- package/{tools → src}/domain/bridge-options.js +8 -21
- package/src/domain/list-values.js +6 -0
- package/src/generators/bridge/write-bridge-files.js +100 -0
- package/src/generators/models/interface-schema.js +116 -0
- package/src/generators/models/model-selection.js +148 -0
- package/src/generators/models/oas-contract.js +170 -0
- package/{tools/generator → src/generators}/models/oas-schema-name.js +6 -15
- package/src/generators/models/openapi-to-models.js +136 -0
- package/{tools/generator → src/generators}/models/schema-utils.js +27 -3
- package/src/generators/models/templates/type-alias.hbs +2 -0
- package/src/generators/models/type-expression.js +65 -0
- package/src/generators/models/type-resolver.js +240 -0
- package/src/generators/models/utils.js +89 -0
- package/src/generators/models/write-model-files.js +55 -0
- package/src/infrastructure/dev-project.js +48 -0
- package/{tools/infra → src/infrastructure}/exec.js +3 -2
- package/src/infrastructure/local-package-install.js +104 -0
- package/src/infrastructure/spec-loader.js +65 -0
- package/templates/{_lib_template → angular-bridge}/README.md +9 -0
- package/templates/angular-bridge/src/lib/bridge/rest/api-platform.adapter.ts +82 -0
- package/templates/angular-bridge/src/lib/bridge/rest/http-request.options.ts +30 -0
- package/templates/{_lib_template → angular-bridge}/src/lib/bridge/rest/query-builder.ts +10 -10
- package/templates/angular-bridge/src/lib/bridge/sse/mercure-connections.ts +255 -0
- package/templates/angular-bridge/src/lib/bridge/sse/mercure-payload.ts +82 -0
- package/templates/angular-bridge/src/lib/bridge/sse/mercure-url.builder.ts +39 -0
- package/templates/angular-bridge/src/lib/bridge/sse/mercure.adapter.ts +358 -0
- package/templates/{_lib_template → angular-bridge}/src/lib/bridge/sse/ref-count-topic.registry.ts +3 -12
- package/templates/angular-bridge/src/lib/bridge/sse/subscription-claims.ts +76 -0
- package/templates/angular-bridge/src/lib/bridge-options.ts +59 -0
- package/templates/{_lib_template → angular-bridge}/src/lib/facades/bridge.facade.ts +50 -51
- package/templates/{_lib_template → angular-bridge}/src/lib/facades/facade.factory.ts +0 -1
- package/templates/angular-bridge/src/lib/facades/facade.interface.ts +13 -0
- package/templates/{_lib_template → angular-bridge}/src/lib/facades/resource.facade.ts +24 -31
- package/templates/angular-bridge/src/lib/interceptors/bearer-auth.interceptor.ts +33 -0
- package/templates/angular-bridge/src/lib/interceptors/bridge-defaults.interceptor.ts +65 -0
- package/templates/angular-bridge/src/lib/interceptors/content-type.interceptor.ts +37 -0
- package/templates/angular-bridge/src/lib/interceptors/scoped.interceptor.ts +9 -0
- package/templates/angular-bridge/src/lib/interceptors/singleflight.interceptor.ts +46 -0
- package/templates/{_lib_template → angular-bridge}/src/lib/ports/realtime.port.ts +6 -2
- package/templates/{_lib_template → angular-bridge}/src/lib/ports/resource-repository.port.ts +7 -7
- package/templates/angular-bridge/src/lib/provide-bridge.ts +98 -0
- package/templates/angular-bridge/src/lib/utils/iri.ts +6 -0
- package/templates/angular-bridge/src/lib/utils/request-url.ts +31 -0
- package/templates/{_lib_template → angular-bridge}/src/public-api.ts +2 -0
- package/templates/{_lib_template → angular-bridge}/tsconfig.lib.json +13 -2
- package/templates/_lib_template/src/lib/bridge/rest/api-platform.adapter.ts +0 -84
- package/templates/_lib_template/src/lib/bridge/rest/http-request.options.ts +0 -21
- package/templates/_lib_template/src/lib/bridge/sse/mercure-url.builder.ts +0 -17
- package/templates/_lib_template/src/lib/bridge/sse/mercure.adapter.ts +0 -806
- package/templates/_lib_template/src/lib/facades/facade.interface.ts +0 -31
- package/templates/_lib_template/src/lib/interceptors/bridge-defaults.interceptor.ts +0 -53
- package/templates/_lib_template/src/lib/interceptors/content-type.interceptor.ts +0 -49
- package/templates/_lib_template/src/lib/interceptors/singleflight.interceptor.ts +0 -55
- package/templates/_lib_template/src/lib/provide-bridge.ts +0 -186
- package/tools/build.js +0 -1
- package/tools/dev.js +0 -1
- package/tools/domain/paths.js +0 -10
- package/tools/generate.js +0 -1
- package/tools/generator/models/oas-contract.js +0 -159
- package/tools/generator/models/openapi-to-models.js +0 -240
- package/tools/generator/models/type-resolver.js +0 -107
- package/tools/generator/models/utils.js +0 -62
- package/tools/infra/dev-support.js +0 -189
- package/tools/infra/generate/bridge.js +0 -212
- package/tools/infra/spec-loader.js +0 -59
- package/tools/infra/standalone-workspace.js +0 -162
- /package/{tools → src}/domain/lib-name.js +0 -0
- /package/{tools/generator → src/generators}/models/handlebars.js +0 -0
- /package/{tools/generator → src/generators}/models/templates/index.hbs +0 -0
- /package/{tools/generator → src/generators}/models/templates/model.hbs +0 -0
- /package/{tools/infra → src/infrastructure}/json.js +0 -0
- /package/{tools/infra → src/infrastructure}/logger.js +0 -0
- /package/templates/{_lib_template → angular-bridge}/ng-package.json +0 -0
- /package/templates/{_lib_template → angular-bridge}/package.json +0 -0
- /package/templates/{_lib_template → angular-bridge}/src/lib/bridge/sse/eventsource-wrapper.ts +0 -0
- /package/templates/{_lib_template → angular-bridge}/src/lib/bridge/sse/mercure-topic.mapper.ts +0 -0
- /package/templates/{_lib_template → angular-bridge}/src/lib/bridge.types.ts +0 -0
- /package/templates/{_lib_template → angular-bridge}/src/lib/interceptors/bridge-debug.interceptor.ts +0 -0
- /package/templates/{_lib_template → angular-bridge}/src/lib/tokens.ts +0 -0
- /package/templates/{_lib_template → angular-bridge}/src/lib/utils/url.ts +0 -0
- /package/templates/{_lib_template → angular-bridge}/src/models/index.ts +0 -0
- /package/templates/{_lib_template → angular-bridge}/tsconfig.lib.prod.json +0 -0
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import {Iri} from '../ports/resource-repository.port';
|
|
2
|
+
|
|
3
|
+
export function toIriList(input: Iri | Iri[]): string[] {
|
|
4
|
+
const values = Array.isArray(input) ? input : [input];
|
|
5
|
+
return values.filter((value): value is string => typeof value === 'string' && value.length > 0);
|
|
6
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
type UrlKind = 'absolute' | 'protocol-relative' | 'relative';
|
|
2
|
+
|
|
3
|
+
/** Returns whether a request belongs to the configured API origin and path. */
|
|
4
|
+
export function isRequestWithinBaseUrl(requestUrl: string, baseUrl: string): boolean {
|
|
5
|
+
try {
|
|
6
|
+
const kind = classifyUrl(baseUrl);
|
|
7
|
+
if (kind !== classifyUrl(requestUrl)) return false;
|
|
8
|
+
|
|
9
|
+
const protocol = kind === 'absolute' && baseUrl.toLowerCase().startsWith('http://') ? 'http:' : 'https:';
|
|
10
|
+
const comparisonOrigin = `${protocol}//bridge.invalid`;
|
|
11
|
+
const base = new URL(baseUrl, `${comparisonOrigin}/`);
|
|
12
|
+
const request = new URL(requestUrl, `${comparisonOrigin}/`);
|
|
13
|
+
|
|
14
|
+
if (base.origin !== request.origin) return false;
|
|
15
|
+
|
|
16
|
+
const basePath = trimTrailingSlash(base.pathname);
|
|
17
|
+
return basePath === '/' || request.pathname === basePath || request.pathname.startsWith(`${basePath}/`);
|
|
18
|
+
} catch {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function classifyUrl(url: string): UrlKind {
|
|
24
|
+
if (/^https?:\/\//i.test(url)) return 'absolute';
|
|
25
|
+
if (url.startsWith('//')) return 'protocol-relative';
|
|
26
|
+
return 'relative';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function trimTrailingSlash(pathname: string): string {
|
|
30
|
+
return pathname === '/' ? pathname : pathname.replace(/\/+$/, '') || '/';
|
|
31
|
+
}
|
|
@@ -3,6 +3,8 @@ export * from './lib/bridge.types';
|
|
|
3
3
|
export * from './lib/facades/facade.factory';
|
|
4
4
|
export * from './lib/facades/bridge.facade';
|
|
5
5
|
export * from './lib/facades/resource.facade';
|
|
6
|
+
export * from './lib/facades/facade.interface';
|
|
7
|
+
export * from './lib/ports/realtime.port';
|
|
6
8
|
export * from './lib/ports/resource-repository.port';
|
|
7
9
|
export * from './lib/utils/url';
|
|
8
10
|
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
|
2
2
|
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
|
3
3
|
{
|
|
4
|
-
"extends": "../../tsconfig.json",
|
|
5
4
|
"compilerOptions": {
|
|
5
|
+
"target": "ES2022",
|
|
6
|
+
"module": "ES2022",
|
|
7
|
+
"moduleResolution": "bundler",
|
|
8
|
+
"lib": ["ES2022", "DOM"],
|
|
9
|
+
"strict": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"experimentalDecorators": true,
|
|
12
|
+
"importHelpers": true,
|
|
6
13
|
"outDir": "../../out-tsc/lib",
|
|
7
14
|
"declaration": true,
|
|
8
15
|
"declarationMap": true,
|
|
@@ -14,5 +21,9 @@
|
|
|
14
21
|
],
|
|
15
22
|
"exclude": [
|
|
16
23
|
"**/*.spec.ts"
|
|
17
|
-
]
|
|
24
|
+
],
|
|
25
|
+
"angularCompilerOptions": {
|
|
26
|
+
"compilationMode": "partial",
|
|
27
|
+
"strictTemplates": true
|
|
28
|
+
}
|
|
18
29
|
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import {HttpClient} from '@angular/common/http';
|
|
2
|
-
import {Observable} from 'rxjs';
|
|
3
|
-
import {toHttpParams} from './query-builder';
|
|
4
|
-
import {buildHttpRequestOptions} from './http-request.options';
|
|
5
|
-
import {
|
|
6
|
-
Collection,
|
|
7
|
-
HttpCallOptions,
|
|
8
|
-
HttpRequestConfig,
|
|
9
|
-
Iri,
|
|
10
|
-
IriRequired,
|
|
11
|
-
Item,
|
|
12
|
-
AnyQuery,
|
|
13
|
-
ResourceRepository,
|
|
14
|
-
} from '../../ports/resource-repository.port';
|
|
15
|
-
import {resolveUrl} from '../../utils/url';
|
|
16
|
-
|
|
17
|
-
export class ApiPlatformRestRepository<T extends Item> implements ResourceRepository<T> {
|
|
18
|
-
constructor(
|
|
19
|
-
private readonly http: HttpClient,
|
|
20
|
-
private readonly apiBase: string,
|
|
21
|
-
private readonly resourcePath: Iri,
|
|
22
|
-
private readonly httpWithCredentialsDefault: boolean,
|
|
23
|
-
) {
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
getCollection$(query?: AnyQuery, opts?: HttpCallOptions): Observable<Collection<T>> {
|
|
27
|
-
const params = toHttpParams(query);
|
|
28
|
-
return this.http.get<Collection<T>>(this.resolveUrl(this.resourcePath), {
|
|
29
|
-
params,
|
|
30
|
-
headers: opts?.headers,
|
|
31
|
-
withCredentials: opts?.withCredentials ?? this.httpWithCredentialsDefault,
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
get$(iri: IriRequired, opts?: HttpCallOptions): Observable<T> {
|
|
36
|
-
return this.http.get<T>(this.resolveUrl(iri), {
|
|
37
|
-
headers: opts?.headers,
|
|
38
|
-
withCredentials: opts?.withCredentials ?? this.httpWithCredentialsDefault,
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
post$(payload: Partial<T>, opts?: HttpCallOptions): Observable<T> {
|
|
43
|
-
return this.http.post<T>(this.resolveUrl(this.resourcePath), payload, {
|
|
44
|
-
headers: opts?.headers,
|
|
45
|
-
withCredentials: opts?.withCredentials ?? this.httpWithCredentialsDefault,
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
patch$(iri: IriRequired, changes: Partial<T>, opts?: HttpCallOptions): Observable<T> {
|
|
50
|
-
return this.http.patch<T>(this.resolveUrl(iri), changes, {
|
|
51
|
-
headers: opts?.headers,
|
|
52
|
-
withCredentials: opts?.withCredentials ?? this.httpWithCredentialsDefault,
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
put$(iri: IriRequired, payload: Partial<T>, opts?: HttpCallOptions): Observable<T> {
|
|
57
|
-
return this.http.put<T>(this.resolveUrl(iri), payload, {
|
|
58
|
-
headers: opts?.headers,
|
|
59
|
-
withCredentials: opts?.withCredentials ?? this.httpWithCredentialsDefault,
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
delete$(iri: IriRequired, opts?: HttpCallOptions): Observable<void> {
|
|
64
|
-
return this.http.delete<void>(this.resolveUrl(iri), {
|
|
65
|
-
headers: opts?.headers,
|
|
66
|
-
withCredentials: opts?.withCredentials ?? this.httpWithCredentialsDefault,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
request$<R = unknown, B = unknown>(req: HttpRequestConfig<B>): Observable<R> {
|
|
71
|
-
// Low-level escape hatch for non-standard endpoints (custom controllers, uploads, etc.).
|
|
72
|
-
const {method, url} = req;
|
|
73
|
-
|
|
74
|
-
const targetUrl = this.resolveUrl(url ?? this.resourcePath);
|
|
75
|
-
const mergedOptions = buildHttpRequestOptions(req, {withCredentialsDefault: this.httpWithCredentialsDefault});
|
|
76
|
-
return this.http.request<R>(method, targetUrl, mergedOptions as {observe: 'body'});
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
private resolveUrl(path?: Iri): string {
|
|
80
|
-
const effectivePath = path ?? this.resourcePath;
|
|
81
|
-
if (!effectivePath) throw new Error('ApiPlatformRestRepository: missing url and resourcePath');
|
|
82
|
-
return resolveUrl(this.apiBase, effectivePath);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import {HttpRequestConfig} from '../../ports/resource-repository.port';
|
|
2
|
-
import {toHttpParams} from './query-builder';
|
|
3
|
-
|
|
4
|
-
export function buildHttpRequestOptions(
|
|
5
|
-
req: HttpRequestConfig,
|
|
6
|
-
{withCredentialsDefault}: {withCredentialsDefault: boolean}
|
|
7
|
-
): Record<string, unknown> {
|
|
8
|
-
const {query, body, headers, responseType, withCredentials, options = {}} = req;
|
|
9
|
-
const mergedOptions: Record<string, unknown> = {...options};
|
|
10
|
-
|
|
11
|
-
if (headers) mergedOptions['headers'] = headers;
|
|
12
|
-
if (query) mergedOptions['params'] = toHttpParams(query);
|
|
13
|
-
if (body !== undefined) mergedOptions['body'] = body;
|
|
14
|
-
|
|
15
|
-
mergedOptions['responseType'] = (responseType ?? (mergedOptions['responseType'] as any) ?? 'json') as any;
|
|
16
|
-
mergedOptions['withCredentials'] =
|
|
17
|
-
withCredentials ?? (mergedOptions['withCredentials'] as any) ?? withCredentialsDefault;
|
|
18
|
-
mergedOptions['observe'] = 'body';
|
|
19
|
-
|
|
20
|
-
return mergedOptions;
|
|
21
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export class MercureUrlBuilder {
|
|
2
|
-
/**
|
|
3
|
-
* Builds the Mercure hub URL with one `topic=` parameter per topic.
|
|
4
|
-
* The adapter is responsible for canonicalising topics beforehand.
|
|
5
|
-
*/
|
|
6
|
-
build(hubUrl: string, topics: ReadonlySet<string>, lastEventId?: string): string {
|
|
7
|
-
const url = new URL(hubUrl);
|
|
8
|
-
if (lastEventId) {
|
|
9
|
-
url.searchParams.set('lastEventID', lastEventId);
|
|
10
|
-
}
|
|
11
|
-
url.searchParams.delete('topic');
|
|
12
|
-
for (const topic of topics) {
|
|
13
|
-
url.searchParams.append('topic', topic);
|
|
14
|
-
}
|
|
15
|
-
return url.toString();
|
|
16
|
-
}
|
|
17
|
-
}
|