@trismegisto/spine 2.0.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.
- package/LICENSE +56 -0
- package/README.md +207 -0
- package/fesm2022/trismegisto-spine-audit.mjs +1299 -0
- package/fesm2022/trismegisto-spine-audit.mjs.map +1 -0
- package/fesm2022/trismegisto-spine-auto-service-auto-service-audit.component-CCiz-q8o.mjs +37 -0
- package/fesm2022/trismegisto-spine-auto-service-auto-service-audit.component-CCiz-q8o.mjs.map +1 -0
- package/fesm2022/trismegisto-spine-auto-service-auto-service-client-picker.component-Z0wCANF6.mjs +51 -0
- package/fesm2022/trismegisto-spine-auto-service-auto-service-client-picker.component-Z0wCANF6.mjs.map +1 -0
- package/fesm2022/trismegisto-spine-auto-service-auto-service-client.component-BYkUOwWL.mjs +595 -0
- package/fesm2022/trismegisto-spine-auto-service-auto-service-client.component-BYkUOwWL.mjs.map +1 -0
- package/fesm2022/trismegisto-spine-auto-service-auto-service-groups.component-CqIVe2LU.mjs +357 -0
- package/fesm2022/trismegisto-spine-auto-service-auto-service-groups.component-CqIVe2LU.mjs.map +1 -0
- package/fesm2022/trismegisto-spine-auto-service-auto-service.component-B5tyJ2zY.mjs +477 -0
- package/fesm2022/trismegisto-spine-auto-service-auto-service.component-B5tyJ2zY.mjs.map +1 -0
- package/fesm2022/trismegisto-spine-auto-service-home.component-vl3BPFnk.mjs +238 -0
- package/fesm2022/trismegisto-spine-auto-service-home.component-vl3BPFnk.mjs.map +1 -0
- package/fesm2022/trismegisto-spine-auto-service.mjs +154 -0
- package/fesm2022/trismegisto-spine-auto-service.mjs.map +1 -0
- package/fesm2022/trismegisto-spine-graphql.mjs +347 -0
- package/fesm2022/trismegisto-spine-graphql.mjs.map +1 -0
- package/fesm2022/trismegisto-spine-layout.mjs +2848 -0
- package/fesm2022/trismegisto-spine-layout.mjs.map +1 -0
- package/fesm2022/trismegisto-spine-modal.mjs +141 -0
- package/fesm2022/trismegisto-spine-modal.mjs.map +1 -0
- package/fesm2022/trismegisto-spine-notification.mjs +122 -0
- package/fesm2022/trismegisto-spine-notification.mjs.map +1 -0
- package/fesm2022/trismegisto-spine-routing.mjs +398 -0
- package/fesm2022/trismegisto-spine-routing.mjs.map +1 -0
- package/fesm2022/trismegisto-spine-shell.mjs +409 -0
- package/fesm2022/trismegisto-spine-shell.mjs.map +1 -0
- package/fesm2022/trismegisto-spine-side-panel.mjs +142 -0
- package/fesm2022/trismegisto-spine-side-panel.mjs.map +1 -0
- package/fesm2022/trismegisto-spine.mjs +2574 -0
- package/fesm2022/trismegisto-spine.mjs.map +1 -0
- package/package.json +94 -0
- package/types/trismegisto-spine-audit.d.ts +948 -0
- package/types/trismegisto-spine-audit.d.ts.map +1 -0
- package/types/trismegisto-spine-auto-service.d.ts +110 -0
- package/types/trismegisto-spine-auto-service.d.ts.map +1 -0
- package/types/trismegisto-spine-graphql.d.ts +72 -0
- package/types/trismegisto-spine-graphql.d.ts.map +1 -0
- package/types/trismegisto-spine-layout.d.ts +1054 -0
- package/types/trismegisto-spine-layout.d.ts.map +1 -0
- package/types/trismegisto-spine-modal.d.ts +68 -0
- package/types/trismegisto-spine-modal.d.ts.map +1 -0
- package/types/trismegisto-spine-notification.d.ts +62 -0
- package/types/trismegisto-spine-notification.d.ts.map +1 -0
- package/types/trismegisto-spine-routing.d.ts +205 -0
- package/types/trismegisto-spine-routing.d.ts.map +1 -0
- package/types/trismegisto-spine-shell.d.ts +143 -0
- package/types/trismegisto-spine-shell.d.ts.map +1 -0
- package/types/trismegisto-spine-side-panel.d.ts +66 -0
- package/types/trismegisto-spine-side-panel.d.ts.map +1 -0
- package/types/trismegisto-spine.d.ts +1161 -0
- package/types/trismegisto-spine.d.ts.map +1 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { InjectionToken, makeEnvironmentProviders, Inject, Injectable } from '@angular/core';
|
|
3
|
+
import { COMPONENT_ROUTES } from '@trismegisto/spine/routing';
|
|
4
|
+
import { SPINE_ADMIN_API } from '@trismegisto/spine';
|
|
5
|
+
import * as i1 from '@angular/common/http';
|
|
6
|
+
import { HttpHeaders, HttpParams } from '@angular/common/http';
|
|
7
|
+
import { firstValueFrom } from 'rxjs';
|
|
8
|
+
import * as i2 from '@orfeu/angular/core';
|
|
9
|
+
|
|
10
|
+
const AUTO_SERVICE_CONFIG = new InjectionToken('AUTO_SERVICE_CONFIG');
|
|
11
|
+
// router_id dos 3 roteadores (páginas) do template "auto-service" (web.template_router,
|
|
12
|
+
// ver apps/argos/database/data/web/template_router.json) -- valores literais e
|
|
13
|
+
// estáveis (mesma convenção do resto do seed: UUID fixo, nunca gerado em runtime). É
|
|
14
|
+
// contra ISSO que o ComponentDistributorService casa via source_template_router_id
|
|
15
|
+
// (não o router_id materializado de cada client, que varia): qualquer client
|
|
16
|
+
// vinculado ao template "auto-service" resolve os 3 automaticamente, sem precisar
|
|
17
|
+
// declarar nada no próprio features.routes.ts. As 3 páginas vivem dentro de um menu
|
|
18
|
+
// "Administração" no template -- o menu em si nunca precisa de componente (nunca é
|
|
19
|
+
// page_id de nenhum router).
|
|
20
|
+
const AUTO_SERVICE_GROUPS_TEMPLATE_ROUTER_ID = 'ad100001-0000-4000-8000-000000000001';
|
|
21
|
+
const AUTO_SERVICE_APPS_TEMPLATE_ROUTER_ID = 'ad100002-0000-4000-8000-000000000001';
|
|
22
|
+
const AUTO_SERVICE_CLIENT_TEMPLATE_ROUTER_ID = 'ad100003-0000-4000-8000-000000000001';
|
|
23
|
+
// Auditoria: 4ª página do menu "Administração", ao lado de Grupos/Aplicações. O componente já fica
|
|
24
|
+
// ligado a este id; a entrada no menu aparece quando o template "auto-service" do banco ganhar o router
|
|
25
|
+
// (mesmos guards da página de Aplicações). Até lá a tela também abre pela aba "Auditoria" da própria
|
|
26
|
+
// página de Aplicações -- mesma autorização, por construção.
|
|
27
|
+
const AUTO_SERVICE_AUDIT_TEMPLATE_ROUTER_ID = 'ad100004-0000-4000-8000-000000000001';
|
|
28
|
+
// Início ("home", página de topo e pública do mesmo template). Todo client clonado do
|
|
29
|
+
// template ganha a própria linha em web.router com source_template_router_id apontando pra cá.
|
|
30
|
+
const AUTO_SERVICE_HOME_TEMPLATE_ROUTER_ID = '6a9a13db-f31b-494e-b51c-79af0ac28b60';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* As 5 telas do auto-serviço, carregadas sob demanda. Cada `import()` relativo vira um chunk próprio no
|
|
34
|
+
* FESM publicado (`trismegisto-spine-auto-service-<tela>-<hash>.mjs`), que o bundler do app mantém fora
|
|
35
|
+
* do carregamento inicial. Não exporte as telas no `public-api.ts` (ver o comentário lá).
|
|
36
|
+
*/
|
|
37
|
+
const AUTO_SERVICE_SCREENS = {
|
|
38
|
+
home: () => import('./trismegisto-spine-auto-service-home.component-vl3BPFnk.mjs').then(m => m.HomeComponent),
|
|
39
|
+
groups: () => import('./trismegisto-spine-auto-service-auto-service-groups.component-CqIVe2LU.mjs').then(m => m.AutoServiceGroupsComponent),
|
|
40
|
+
apps: () => import('./trismegisto-spine-auto-service-auto-service.component-B5tyJ2zY.mjs').then(m => m.AutoServiceComponent),
|
|
41
|
+
client: () => import('./trismegisto-spine-auto-service-auto-service-client.component-BYkUOwWL.mjs').then(m => m.AutoServiceClientComponent),
|
|
42
|
+
audit: () => import('./trismegisto-spine-auto-service-auto-service-audit.component-CCiz-q8o.mjs').then(m => m.AutoServiceAuditComponent),
|
|
43
|
+
};
|
|
44
|
+
// Cada app consumidora chama isso uma vez no bootstrap (mesmo padrão do
|
|
45
|
+
// provideAuth do @orfeu/angular) informando só a URL do argos-admin-server --
|
|
46
|
+
// o resto vem pronto: rotas/serviço (@trismegisto/spine/auto-service) E a própria
|
|
47
|
+
// ligação com os itens de menu, registrada aqui via source_template_router_id (não
|
|
48
|
+
// route_id -- esse varia por client, ver ComponentDistributorService). O app não
|
|
49
|
+
// precisa (e não deve) declarar nada em features.routes.ts pra isso funcionar; basta
|
|
50
|
+
// o client dele estar vinculado ao template "auto-service" (auth.clients.template_id).
|
|
51
|
+
// 5 páginas (Início + Grupos/Aplicações/Cliente/Auditoria) -- o ComponentDistributorService
|
|
52
|
+
// já suporta N entradas, cada uma casando pelo seu próprio source_template_router_id.
|
|
53
|
+
function provideAutoService(config) {
|
|
54
|
+
const componentRoutes = [
|
|
55
|
+
{ source_template_router_id: AUTO_SERVICE_HOME_TEMPLATE_ROUTER_ID, load: AUTO_SERVICE_SCREENS.home },
|
|
56
|
+
{ source_template_router_id: AUTO_SERVICE_GROUPS_TEMPLATE_ROUTER_ID, load: AUTO_SERVICE_SCREENS.groups },
|
|
57
|
+
{ source_template_router_id: AUTO_SERVICE_APPS_TEMPLATE_ROUTER_ID, load: AUTO_SERVICE_SCREENS.apps },
|
|
58
|
+
{ source_template_router_id: AUTO_SERVICE_CLIENT_TEMPLATE_ROUTER_ID, load: AUTO_SERVICE_SCREENS.client },
|
|
59
|
+
{ source_template_router_id: AUTO_SERVICE_AUDIT_TEMPLATE_ROUTER_ID, load: AUTO_SERVICE_SCREENS.audit },
|
|
60
|
+
];
|
|
61
|
+
return makeEnvironmentProviders([
|
|
62
|
+
{ provide: AUTO_SERVICE_CONFIG, useValue: config },
|
|
63
|
+
// Mesma URL, exposta também para o painel de configurações (tokens de aplicação em /me).
|
|
64
|
+
{ provide: SPINE_ADMIN_API, useValue: config.adminApi },
|
|
65
|
+
{ provide: COMPONENT_ROUTES, useValue: componentRoutes, multi: true },
|
|
66
|
+
]);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
class AutoServiceService {
|
|
70
|
+
get baseUrl() {
|
|
71
|
+
return `${this.config.adminApi}/auto-service`;
|
|
72
|
+
}
|
|
73
|
+
get headers() {
|
|
74
|
+
const token = this.auth.getToken();
|
|
75
|
+
return new HttpHeaders({ 'x-access-token': token ?? '' });
|
|
76
|
+
}
|
|
77
|
+
constructor(http, auth, config) {
|
|
78
|
+
this.http = http;
|
|
79
|
+
this.auth = auth;
|
|
80
|
+
this.config = config;
|
|
81
|
+
}
|
|
82
|
+
// Descoberta
|
|
83
|
+
getMyClients() { return firstValueFrom(this.http.get(`${this.baseUrl}`, { headers: this.headers })); }
|
|
84
|
+
// Routes
|
|
85
|
+
getWebRoutes(clientId) { return firstValueFrom(this.http.get(`${this.baseUrl}/${clientId}/routes`, { headers: this.headers })); }
|
|
86
|
+
createWebRoute(clientId, body) { return firstValueFrom(this.http.post(`${this.baseUrl}/${clientId}/routes`, body, { headers: this.headers })); }
|
|
87
|
+
updateWebRoute(clientId, id, body) { return firstValueFrom(this.http.put(`${this.baseUrl}/${clientId}/routes/${id}`, body, { headers: this.headers })); }
|
|
88
|
+
deleteWebRoute(clientId, id) { return firstValueFrom(this.http.delete(`${this.baseUrl}/${clientId}/routes/${id}`, { headers: this.headers })); }
|
|
89
|
+
// Routers
|
|
90
|
+
getRouters(clientId) { return firstValueFrom(this.http.get(`${this.baseUrl}/${clientId}/routers`, { headers: this.headers })); }
|
|
91
|
+
createRouter(clientId, body) { return firstValueFrom(this.http.post(`${this.baseUrl}/${clientId}/routers`, body, { headers: this.headers })); }
|
|
92
|
+
updateRouter(clientId, id, body) { return firstValueFrom(this.http.put(`${this.baseUrl}/${clientId}/routers/${id}`, body, { headers: this.headers })); }
|
|
93
|
+
deleteRouter(clientId, id) { return firstValueFrom(this.http.delete(`${this.baseUrl}/${clientId}/routers/${id}`, { headers: this.headers })); }
|
|
94
|
+
// Groups
|
|
95
|
+
getGroups(clientId) { return firstValueFrom(this.http.get(`${this.baseUrl}/${clientId}/groups`, { headers: this.headers })); }
|
|
96
|
+
getGroupMembers(clientId, groupId) { return firstValueFrom(this.http.get(`${this.baseUrl}/${clientId}/groups/${groupId}/members`, { headers: this.headers })); }
|
|
97
|
+
addGroupMember(clientId, groupId, userId, role) { return firstValueFrom(this.http.post(`${this.baseUrl}/${clientId}/groups/${groupId}/members`, { user_id: userId, role }, { headers: this.headers })); }
|
|
98
|
+
updateGroupMemberRole(clientId, groupId, userId, role) { return firstValueFrom(this.http.put(`${this.baseUrl}/${clientId}/groups/${groupId}/members/${userId}`, { role }, { headers: this.headers })); }
|
|
99
|
+
removeGroupMember(clientId, groupId, userId) { return firstValueFrom(this.http.delete(`${this.baseUrl}/${clientId}/groups/${groupId}/members/${userId}`, { headers: this.headers })); }
|
|
100
|
+
// Users (só leitura -- popular a busca de "adicionar membro" na aba Grupos, escopada pelo realm do próprio client)
|
|
101
|
+
searchUsers(clientId, opts = {}) {
|
|
102
|
+
let params = new HttpParams();
|
|
103
|
+
if (opts.search)
|
|
104
|
+
params = params.set('search', opts.search);
|
|
105
|
+
if (opts.limit)
|
|
106
|
+
params = params.set('limit', String(opts.limit));
|
|
107
|
+
return firstValueFrom(this.http.get(`${this.baseUrl}/${clientId}/users`, { headers: this.headers, params }));
|
|
108
|
+
}
|
|
109
|
+
// Access
|
|
110
|
+
getAccess(clientId) { return firstValueFrom(this.http.get(`${this.baseUrl}/${clientId}/access`, { headers: this.headers })); }
|
|
111
|
+
createAccess(clientId, groupId) { return firstValueFrom(this.http.post(`${this.baseUrl}/${clientId}/access`, { group_id: groupId }, { headers: this.headers })); }
|
|
112
|
+
deleteAccess(clientId, accessId) { return firstValueFrom(this.http.delete(`${this.baseUrl}/${clientId}/access/${accessId}`, { headers: this.headers })); }
|
|
113
|
+
getGuards(clientId, accessId) { return firstValueFrom(this.http.get(`${this.baseUrl}/${clientId}/access/${accessId}/guards`, { headers: this.headers })); }
|
|
114
|
+
addGuard(clientId, accessId, routerId) { return firstValueFrom(this.http.post(`${this.baseUrl}/${clientId}/access/${accessId}/guards`, { router_id: routerId }, { headers: this.headers })); }
|
|
115
|
+
removeGuard(clientId, accessId, guardId) { return firstValueFrom(this.http.delete(`${this.baseUrl}/${clientId}/access/${accessId}/guards/${guardId}`, { headers: this.headers })); }
|
|
116
|
+
// Apps (aplicações client_credentials no Project deste client)
|
|
117
|
+
getApps(clientId) { return firstValueFrom(this.http.get(`${this.baseUrl}/${clientId}/apps`, { headers: this.headers })); }
|
|
118
|
+
createApp(clientId, body) { return firstValueFrom(this.http.post(`${this.baseUrl}/${clientId}/apps`, body, { headers: this.headers })); }
|
|
119
|
+
updateApp(clientId, appId, body) { return firstValueFrom(this.http.put(`${this.baseUrl}/${clientId}/apps/${appId}`, body, { headers: this.headers })); }
|
|
120
|
+
deleteApp(clientId, appId) { return firstValueFrom(this.http.delete(`${this.baseUrl}/${clientId}/apps/${appId}`, { headers: this.headers })); }
|
|
121
|
+
getAppOperations(clientId, appId) { return firstValueFrom(this.http.get(`${this.baseUrl}/${clientId}/apps/${appId}/operations`, { headers: this.headers })); }
|
|
122
|
+
// Consumers (grupo ↔ aplicação)
|
|
123
|
+
getAppConsumers(clientId, appId) { return firstValueFrom(this.http.get(`${this.baseUrl}/${clientId}/apps/${appId}/consumers`, { headers: this.headers })); }
|
|
124
|
+
createAppConsumer(clientId, appId, groupId) { return firstValueFrom(this.http.post(`${this.baseUrl}/${clientId}/apps/${appId}/consumers`, { group_id: groupId }, { headers: this.headers })); }
|
|
125
|
+
deleteAppConsumer(clientId, consumerId) { return firstValueFrom(this.http.delete(`${this.baseUrl}/${clientId}/apps/consumers/${consumerId}`, { headers: this.headers })); }
|
|
126
|
+
// Permissions (consumer ↔ operação)
|
|
127
|
+
getAppPermissions(clientId, consumerId) { return firstValueFrom(this.http.get(`${this.baseUrl}/${clientId}/apps/consumers/${consumerId}/permissions`, { headers: this.headers })); }
|
|
128
|
+
addAppPermission(clientId, consumerId, operationId) { return firstValueFrom(this.http.post(`${this.baseUrl}/${clientId}/apps/consumers/${consumerId}/permissions`, { operation_id: operationId }, { headers: this.headers })); }
|
|
129
|
+
removeAppPermission(clientId, consumerId, permissionId) { return firstValueFrom(this.http.delete(`${this.baseUrl}/${clientId}/apps/consumers/${consumerId}/permissions/${permissionId}`, { headers: this.headers })); }
|
|
130
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: AutoServiceService, deps: [{ token: i1.HttpClient }, { token: i2.AuthorizationService }, { token: AUTO_SERVICE_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
131
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: AutoServiceService, providedIn: 'root' }); }
|
|
132
|
+
}
|
|
133
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: AutoServiceService, decorators: [{
|
|
134
|
+
type: Injectable,
|
|
135
|
+
args: [{ providedIn: 'root' }]
|
|
136
|
+
}], ctorParameters: () => [{ type: i1.HttpClient }, { type: i2.AuthorizationService }, { type: undefined, decorators: [{
|
|
137
|
+
type: Inject,
|
|
138
|
+
args: [AUTO_SERVICE_CONFIG]
|
|
139
|
+
}] }] });
|
|
140
|
+
|
|
141
|
+
// A auditoria (tipos, serviço e a tela) mora em `@trismegisto/spine/audit` — NÃO reexporte daqui: um
|
|
142
|
+
// `export` estático puxaria a tela para o arquivo deste ponto de entrada (ver abaixo e check-lazy).
|
|
143
|
+
// As telas (Início, Grupos, Aplicações, Cliente) e as peças delas NÃO são exportadas daqui de propósito:
|
|
144
|
+
// ficam só atrás dos `import()` de `AUTO_SERVICE_SCREENS`. Qualquer `export` estático de um componente
|
|
145
|
+
// delas faz o rollup do ng-packagr juntar a tela no FESM do ponto de entrada e trocar o `import()` por
|
|
146
|
+
// `Promise.resolve()` — e a tela (data-grid, combobox, drawer...) vai para o bundle inicial de todo app
|
|
147
|
+
// (bug da 0.9.9). `scripts/check-lazy.mjs` (no `npm run build`) falha se isso voltar.
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Generated bundle index. Do not edit.
|
|
151
|
+
*/
|
|
152
|
+
|
|
153
|
+
export { AUTO_SERVICE_APPS_TEMPLATE_ROUTER_ID, AUTO_SERVICE_AUDIT_TEMPLATE_ROUTER_ID, AUTO_SERVICE_CLIENT_TEMPLATE_ROUTER_ID, AUTO_SERVICE_CONFIG, AUTO_SERVICE_GROUPS_TEMPLATE_ROUTER_ID, AUTO_SERVICE_HOME_TEMPLATE_ROUTER_ID, AUTO_SERVICE_SCREENS, AutoServiceService, provideAutoService };
|
|
154
|
+
//# sourceMappingURL=trismegisto-spine-auto-service.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trismegisto-spine-auto-service.mjs","sources":["../../../projects/ui/auto-service/src/auto-service.tokens.ts","../../../projects/ui/auto-service/src/provide-auto-service.ts","../../../projects/ui/auto-service/src/auto-service.service.ts","../../../projects/ui/auto-service/src/public-api.ts","../../../projects/ui/auto-service/src/trismegisto-spine-auto-service.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\n\nexport interface AutoServiceConfig {\n // Base URL do argos-admin-server (o mesmo backend central que atende\n // /admin/*) -- /auto-service/* já existe lá, escopado por client_id, servindo\n // qualquer aplicação que instale este pacote, não só o argos-admin.\n adminApi: string;\n}\n\nexport const AUTO_SERVICE_CONFIG = new InjectionToken<AutoServiceConfig>('AUTO_SERVICE_CONFIG');\n\n// router_id dos 3 roteadores (páginas) do template \"auto-service\" (web.template_router,\n// ver apps/argos/database/data/web/template_router.json) -- valores literais e\n// estáveis (mesma convenção do resto do seed: UUID fixo, nunca gerado em runtime). É\n// contra ISSO que o ComponentDistributorService casa via source_template_router_id\n// (não o router_id materializado de cada client, que varia): qualquer client\n// vinculado ao template \"auto-service\" resolve os 3 automaticamente, sem precisar\n// declarar nada no próprio features.routes.ts. As 3 páginas vivem dentro de um menu\n// \"Administração\" no template -- o menu em si nunca precisa de componente (nunca é\n// page_id de nenhum router).\nexport const AUTO_SERVICE_GROUPS_TEMPLATE_ROUTER_ID = 'ad100001-0000-4000-8000-000000000001';\nexport const AUTO_SERVICE_APPS_TEMPLATE_ROUTER_ID = 'ad100002-0000-4000-8000-000000000001';\nexport const AUTO_SERVICE_CLIENT_TEMPLATE_ROUTER_ID = 'ad100003-0000-4000-8000-000000000001';\n// Auditoria: 4ª página do menu \"Administração\", ao lado de Grupos/Aplicações. O componente já fica\n// ligado a este id; a entrada no menu aparece quando o template \"auto-service\" do banco ganhar o router\n// (mesmos guards da página de Aplicações). Até lá a tela também abre pela aba \"Auditoria\" da própria\n// página de Aplicações -- mesma autorização, por construção.\nexport const AUTO_SERVICE_AUDIT_TEMPLATE_ROUTER_ID = 'ad100004-0000-4000-8000-000000000001';\n// Início (\"home\", página de topo e pública do mesmo template). Todo client clonado do\n// template ganha a própria linha em web.router com source_template_router_id apontando pra cá.\nexport const AUTO_SERVICE_HOME_TEMPLATE_ROUTER_ID = '6a9a13db-f31b-494e-b51c-79af0ac28b60';\n","import { EnvironmentProviders, Type, makeEnvironmentProviders } from '@angular/core';\nimport { COMPONENT_ROUTES, ComponentRoute } from '@trismegisto/spine/routing';\nimport { SPINE_ADMIN_API } from '@trismegisto/spine';\nimport {\n AUTO_SERVICE_CONFIG, AutoServiceConfig,\n AUTO_SERVICE_GROUPS_TEMPLATE_ROUTER_ID, AUTO_SERVICE_APPS_TEMPLATE_ROUTER_ID, AUTO_SERVICE_CLIENT_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_HOME_TEMPLATE_ROUTER_ID, AUTO_SERVICE_AUDIT_TEMPLATE_ROUTER_ID,\n} from './auto-service.tokens';\n\n/**\n * As 5 telas do auto-serviço, carregadas sob demanda. Cada `import()` relativo vira um chunk próprio no\n * FESM publicado (`trismegisto-spine-auto-service-<tela>-<hash>.mjs`), que o bundler do app mantém fora\n * do carregamento inicial. Não exporte as telas no `public-api.ts` (ver o comentário lá).\n */\nexport const AUTO_SERVICE_SCREENS: Readonly<Record<'home' | 'groups' | 'apps' | 'client' | 'audit', () => Promise<Type<unknown>>>> = {\n home: () => import('./home/home.component').then(m => m.HomeComponent),\n groups: () => import('./groups/auto-service-groups.component').then(m => m.AutoServiceGroupsComponent),\n apps: () => import('./auto-service.component').then(m => m.AutoServiceComponent),\n client: () => import('./auto-service-client.component').then(m => m.AutoServiceClientComponent),\n audit: () => import('./audit/auto-service-audit.component').then(m => m.AutoServiceAuditComponent),\n};\n\n// Cada app consumidora chama isso uma vez no bootstrap (mesmo padrão do\n// provideAuth do @orfeu/angular) informando só a URL do argos-admin-server --\n// o resto vem pronto: rotas/serviço (@trismegisto/spine/auto-service) E a própria\n// ligação com os itens de menu, registrada aqui via source_template_router_id (não\n// route_id -- esse varia por client, ver ComponentDistributorService). O app não\n// precisa (e não deve) declarar nada em features.routes.ts pra isso funcionar; basta\n// o client dele estar vinculado ao template \"auto-service\" (auth.clients.template_id).\n// 5 páginas (Início + Grupos/Aplicações/Cliente/Auditoria) -- o ComponentDistributorService\n// já suporta N entradas, cada uma casando pelo seu próprio source_template_router_id.\nexport function provideAutoService(config: AutoServiceConfig): EnvironmentProviders {\n const componentRoutes: ComponentRoute[] = [\n { source_template_router_id: AUTO_SERVICE_HOME_TEMPLATE_ROUTER_ID, load: AUTO_SERVICE_SCREENS.home },\n { source_template_router_id: AUTO_SERVICE_GROUPS_TEMPLATE_ROUTER_ID, load: AUTO_SERVICE_SCREENS.groups },\n { source_template_router_id: AUTO_SERVICE_APPS_TEMPLATE_ROUTER_ID, load: AUTO_SERVICE_SCREENS.apps },\n { source_template_router_id: AUTO_SERVICE_CLIENT_TEMPLATE_ROUTER_ID, load: AUTO_SERVICE_SCREENS.client },\n { source_template_router_id: AUTO_SERVICE_AUDIT_TEMPLATE_ROUTER_ID, load: AUTO_SERVICE_SCREENS.audit },\n ];\n\n return makeEnvironmentProviders([\n { provide: AUTO_SERVICE_CONFIG, useValue: config },\n // Mesma URL, exposta também para o painel de configurações (tokens de aplicação em /me).\n { provide: SPINE_ADMIN_API, useValue: config.adminApi },\n { provide: COMPONENT_ROUTES, useValue: componentRoutes, multi: true },\n ]);\n}\n","import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';\nimport { Inject, Injectable } from '@angular/core';\nimport { firstValueFrom } from 'rxjs';\nimport { AuthorizationService } from '@orfeu/angular/core';\nimport { AUTO_SERVICE_CONFIG, AutoServiceConfig } from './auto-service.tokens';\n\n@Injectable({ providedIn: 'root' })\nexport class AutoServiceService {\n\n private get baseUrl() {\n return `${this.config.adminApi}/auto-service`;\n }\n\n private get headers(): HttpHeaders {\n const token = this.auth.getToken();\n return new HttpHeaders({ 'x-access-token': token ?? '' });\n }\n\n constructor(\n private http: HttpClient,\n private auth: AuthorizationService,\n @Inject(AUTO_SERVICE_CONFIG) private config: AutoServiceConfig,\n ) {}\n\n // Descoberta\n getMyClients() { return firstValueFrom(this.http.get<{ clients: any[] }>(`${this.baseUrl}`, { headers: this.headers })); }\n\n // Routes\n getWebRoutes(clientId: string) { return firstValueFrom(this.http.get<{ routes: any[] }>(`${this.baseUrl}/${clientId}/routes`, { headers: this.headers })); }\n createWebRoute(clientId: string, body: any) { return firstValueFrom(this.http.post<any>(`${this.baseUrl}/${clientId}/routes`, body, { headers: this.headers })); }\n updateWebRoute(clientId: string, id: string, body: any) { return firstValueFrom(this.http.put<any>(`${this.baseUrl}/${clientId}/routes/${id}`, body, { headers: this.headers })); }\n deleteWebRoute(clientId: string, id: string) { return firstValueFrom(this.http.delete<any>(`${this.baseUrl}/${clientId}/routes/${id}`, { headers: this.headers })); }\n\n // Routers\n getRouters(clientId: string) { return firstValueFrom(this.http.get<{ routers: any[] }>(`${this.baseUrl}/${clientId}/routers`, { headers: this.headers })); }\n createRouter(clientId: string, body: any) { return firstValueFrom(this.http.post<any>(`${this.baseUrl}/${clientId}/routers`, body, { headers: this.headers })); }\n updateRouter(clientId: string, id: string, body: any) { return firstValueFrom(this.http.put<any>(`${this.baseUrl}/${clientId}/routers/${id}`, body, { headers: this.headers })); }\n deleteRouter(clientId: string, id: string) { return firstValueFrom(this.http.delete<any>(`${this.baseUrl}/${clientId}/routers/${id}`, { headers: this.headers })); }\n\n // Groups\n getGroups(clientId: string) { return firstValueFrom(this.http.get<{ groups: any[] }>(`${this.baseUrl}/${clientId}/groups`, { headers: this.headers })); }\n getGroupMembers(clientId: string, groupId: string) { return firstValueFrom(this.http.get<{ members: any[] }>(`${this.baseUrl}/${clientId}/groups/${groupId}/members`, { headers: this.headers })); }\n addGroupMember(clientId: string, groupId: string, userId: string, role: string | null) { return firstValueFrom(this.http.post<any>(`${this.baseUrl}/${clientId}/groups/${groupId}/members`, { user_id: userId, role }, { headers: this.headers })); }\n updateGroupMemberRole(clientId: string, groupId: string, userId: string, role: string | null) { return firstValueFrom(this.http.put<any>(`${this.baseUrl}/${clientId}/groups/${groupId}/members/${userId}`, { role }, { headers: this.headers })); }\n removeGroupMember(clientId: string, groupId: string, userId: string) { return firstValueFrom(this.http.delete<any>(`${this.baseUrl}/${clientId}/groups/${groupId}/members/${userId}`, { headers: this.headers })); }\n\n // Users (só leitura -- popular a busca de \"adicionar membro\" na aba Grupos, escopada pelo realm do próprio client)\n searchUsers(clientId: string, opts: { search?: string; limit?: number } = {}) {\n let params = new HttpParams();\n if (opts.search) params = params.set('search', opts.search);\n if (opts.limit) params = params.set('limit', String(opts.limit));\n return firstValueFrom(this.http.get<{ users: any[] }>(`${this.baseUrl}/${clientId}/users`, { headers: this.headers, params }));\n }\n\n // Access\n getAccess(clientId: string) { return firstValueFrom(this.http.get<{ access: any[] }>(`${this.baseUrl}/${clientId}/access`, { headers: this.headers })); }\n createAccess(clientId: string, groupId: string) { return firstValueFrom(this.http.post<any>(`${this.baseUrl}/${clientId}/access`, { group_id: groupId }, { headers: this.headers })); }\n deleteAccess(clientId: string, accessId: string) { return firstValueFrom(this.http.delete<any>(`${this.baseUrl}/${clientId}/access/${accessId}`, { headers: this.headers })); }\n getGuards(clientId: string, accessId: string) { return firstValueFrom(this.http.get<{ guards: any[] }>(`${this.baseUrl}/${clientId}/access/${accessId}/guards`, { headers: this.headers })); }\n addGuard(clientId: string, accessId: string, routerId: string) { return firstValueFrom(this.http.post<any>(`${this.baseUrl}/${clientId}/access/${accessId}/guards`, { router_id: routerId }, { headers: this.headers })); }\n removeGuard(clientId: string, accessId: string, guardId: string) { return firstValueFrom(this.http.delete<any>(`${this.baseUrl}/${clientId}/access/${accessId}/guards/${guardId}`, { headers: this.headers })); }\n\n // Apps (aplicações client_credentials no Project deste client)\n getApps(clientId: string) { return firstValueFrom(this.http.get<{ apps: any[] }>(`${this.baseUrl}/${clientId}/apps`, { headers: this.headers })); }\n createApp(clientId: string, body: { name: string; allowed_grants?: string[] }) { return firstValueFrom(this.http.post<{ id: string; name: string; secret: string }>(`${this.baseUrl}/${clientId}/apps`, body, { headers: this.headers })); }\n updateApp(clientId: string, appId: string, body: any) { return firstValueFrom(this.http.put<any>(`${this.baseUrl}/${clientId}/apps/${appId}`, body, { headers: this.headers })); }\n deleteApp(clientId: string, appId: string) { return firstValueFrom(this.http.delete<any>(`${this.baseUrl}/${clientId}/apps/${appId}`, { headers: this.headers })); }\n getAppOperations(clientId: string, appId: string) { return firstValueFrom(this.http.get<{ operations: any[] }>(`${this.baseUrl}/${clientId}/apps/${appId}/operations`, { headers: this.headers })); }\n\n // Consumers (grupo ↔ aplicação)\n getAppConsumers(clientId: string, appId: string) { return firstValueFrom(this.http.get<{ consumers: any[] }>(`${this.baseUrl}/${clientId}/apps/${appId}/consumers`, { headers: this.headers })); }\n createAppConsumer(clientId: string, appId: string, groupId: string) { return firstValueFrom(this.http.post<any>(`${this.baseUrl}/${clientId}/apps/${appId}/consumers`, { group_id: groupId }, { headers: this.headers })); }\n deleteAppConsumer(clientId: string, consumerId: string) { return firstValueFrom(this.http.delete<any>(`${this.baseUrl}/${clientId}/apps/consumers/${consumerId}`, { headers: this.headers })); }\n\n // Permissions (consumer ↔ operação)\n getAppPermissions(clientId: string, consumerId: string) { return firstValueFrom(this.http.get<{ permissions: any[] }>(`${this.baseUrl}/${clientId}/apps/consumers/${consumerId}/permissions`, { headers: this.headers })); }\n addAppPermission(clientId: string, consumerId: string, operationId: string) { return firstValueFrom(this.http.post<any>(`${this.baseUrl}/${clientId}/apps/consumers/${consumerId}/permissions`, { operation_id: operationId }, { headers: this.headers })); }\n removeAppPermission(clientId: string, consumerId: string, permissionId: string) { return firstValueFrom(this.http.delete<any>(`${this.baseUrl}/${clientId}/apps/consumers/${consumerId}/permissions/${permissionId}`, { headers: this.headers })); }\n // Auditoria: ver `SpineAuditService` (`@trismegisto/spine/audit`), o mesmo nos escopos admin e client.\n}\n","export * from './auto-service.tokens';\nexport * from './provide-auto-service';\nexport * from './auto-service.service';\nexport type { AutoServiceClient } from './client-picker/auto-service-client-picker.component';\n// A auditoria (tipos, serviço e a tela) mora em `@trismegisto/spine/audit` — NÃO reexporte daqui: um\n// `export` estático puxaria a tela para o arquivo deste ponto de entrada (ver abaixo e check-lazy).\n// As telas (Início, Grupos, Aplicações, Cliente) e as peças delas NÃO são exportadas daqui de propósito:\n// ficam só atrás dos `import()` de `AUTO_SERVICE_SCREENS`. Qualquer `export` estático de um componente\n// delas faz o rollup do ng-packagr juntar a tela no FESM do ponto de entrada e trocar o `import()` por\n// `Promise.resolve()` — e a tela (data-grid, combobox, drawer...) vai para o bundle inicial de todo app\n// (bug da 0.9.9). `scripts/check-lazy.mjs` (no `npm run build`) falha se isso voltar.\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import { currentSpineMessages, SPINE_MESSAGES, SPINE_CONFIG } from '@trismegisto/spine';
|
|
2
|
+
import { inject, PLATFORM_ID, DestroyRef, DOCUMENT } from '@angular/core';
|
|
3
|
+
import { Apollo, provideNamedApollo } from 'apollo-angular';
|
|
4
|
+
import { map, filter, firstValueFrom, Subject, tap } from 'rxjs';
|
|
5
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
6
|
+
import { HttpHeaders } from '@angular/common/http';
|
|
7
|
+
import { ApolloLink, InMemoryCache, CombinedGraphQLErrors } from '@apollo/client';
|
|
8
|
+
import { ErrorLink } from '@apollo/client/link/error';
|
|
9
|
+
import { GraphQLWsLink } from '@apollo/client/link/subscriptions';
|
|
10
|
+
import { HttpBatchLink } from 'apollo-angular/http';
|
|
11
|
+
import { OperationTypeNode } from 'graphql';
|
|
12
|
+
import { createClient } from 'graphql-ws';
|
|
13
|
+
import { AuthorizationService } from '@orfeu/angular/core';
|
|
14
|
+
import { NotificationService, AlertType } from '@trismegisto/spine/notification';
|
|
15
|
+
import { LoggerService } from '@trismegisto/spine/routing';
|
|
16
|
+
|
|
17
|
+
/** Business failure carried by an envelope. `status` is kept exactly as the backend sent it. */
|
|
18
|
+
class GraphqlEnvelopeError extends Error {
|
|
19
|
+
constructor(status, message) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.name = 'GraphqlEnvelopeError';
|
|
22
|
+
this.status = status;
|
|
23
|
+
// Keeps `instanceof` working when the output is down-levelled.
|
|
24
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const FAILURE_WORDS = new Set(['error', 'failed', 'failure', 'fail']);
|
|
28
|
+
function isEnvelopeOk(status) {
|
|
29
|
+
if (status === null || status === undefined)
|
|
30
|
+
return true;
|
|
31
|
+
if (typeof status === 'number')
|
|
32
|
+
return status >= 200 && status < 300;
|
|
33
|
+
if (typeof status !== 'string')
|
|
34
|
+
return true;
|
|
35
|
+
// Numeric text is deliberately not parsed: only the failure words count as failure.
|
|
36
|
+
return !FAILURE_WORDS.has(status.trim().toLowerCase());
|
|
37
|
+
}
|
|
38
|
+
/** Returns `data` of an ok envelope; throws `GraphqlEnvelopeError` for a missing or failed one. */
|
|
39
|
+
function unwrap(envelope) {
|
|
40
|
+
if (envelope === null || envelope === undefined) {
|
|
41
|
+
throw new GraphqlEnvelopeError(null, currentSpineMessages().graphql.noResponse);
|
|
42
|
+
}
|
|
43
|
+
if (!isEnvelopeOk(envelope.status)) {
|
|
44
|
+
throw new GraphqlEnvelopeError(envelope.status, envelope.message || currentSpineMessages().graphql.failed);
|
|
45
|
+
}
|
|
46
|
+
return envelope.data;
|
|
47
|
+
}
|
|
48
|
+
function objectFields(data) {
|
|
49
|
+
if (!data || typeof data !== 'object')
|
|
50
|
+
return [];
|
|
51
|
+
return Object.entries(data).filter((entry) => typeof entry[1] === 'object' && entry[1] !== null);
|
|
52
|
+
}
|
|
53
|
+
const hasStatus = (value) => 'status' in value && value['status'] !== null && value['status'] !== undefined;
|
|
54
|
+
/** First-level envelopes found in an operation's `data` (fields that carry both `status` and `message`). */
|
|
55
|
+
function envelopesOf(data) {
|
|
56
|
+
return objectFields(data)
|
|
57
|
+
.filter(([, value]) => 'message' in value && hasStatus(value))
|
|
58
|
+
.map(([field, value]) => {
|
|
59
|
+
const status = value['status'];
|
|
60
|
+
return { field, status, message: value['message'] ?? '', ok: isEnvelopeOk(status) };
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/** First-level fields whose status is a failure; `message` is optional here. */
|
|
64
|
+
function failedEnvelopes(data, fallbackMessage = currentSpineMessages().graphql.serviceFailure) {
|
|
65
|
+
return objectFields(data)
|
|
66
|
+
.filter(([, value]) => hasStatus(value) && !isEnvelopeOk(value['status']))
|
|
67
|
+
.map(([field, value]) => ({
|
|
68
|
+
field,
|
|
69
|
+
status: value['status'],
|
|
70
|
+
message: value['message'] || fallbackMessage,
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const contextOf = (options) => options?.silenceEnvelope ? { ...options.context, silenceEnvelope: true } : options?.context;
|
|
75
|
+
const required = (data) => {
|
|
76
|
+
if (data === null || data === undefined)
|
|
77
|
+
throw new GraphqlEnvelopeError(null, currentSpineMessages().graphql.noResponse);
|
|
78
|
+
return data;
|
|
79
|
+
};
|
|
80
|
+
/** O `GraphqlClient` do backend `namedClient` (`environment.graphql.<chave>.namedClient`). Chamar em contexto de injeção. */
|
|
81
|
+
function injectGraphqlClient(namedClient) {
|
|
82
|
+
const apollo = inject(Apollo);
|
|
83
|
+
const client = () => apollo.use(namedClient);
|
|
84
|
+
// Os genéricos do apollo-angular não casam 1:1 com os do TypedDocumentNode (variáveis opcionais):
|
|
85
|
+
// o tipo público acima é o contrato; aqui dentro o cast é deliberado.
|
|
86
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
87
|
+
return {
|
|
88
|
+
async query(document, variables, options) {
|
|
89
|
+
const result = await firstValueFrom(client().query({ query: document, variables, context: contextOf(options) }));
|
|
90
|
+
return required(result.data);
|
|
91
|
+
},
|
|
92
|
+
async mutate(document, variables, options) {
|
|
93
|
+
const result = await firstValueFrom(client().mutate({ mutation: document, variables, context: contextOf(options) }));
|
|
94
|
+
return required(result.data);
|
|
95
|
+
},
|
|
96
|
+
subscribe(document, variables) {
|
|
97
|
+
return client().subscribe({ query: document, variables }).pipe(map((result) => result.data), filter((data) => data !== null && data !== undefined));
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
/* eslint-enable @typescript-eslint/no-explicit-any */
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Emits the `namedClient` whose socket came back after a drop (never on the first connection). */
|
|
104
|
+
const wsReconnected$ = new Subject();
|
|
105
|
+
const TOKEN_HEADER = 'x-access-token';
|
|
106
|
+
const AUTH_CODES = new Set([401, 4401, 4403]);
|
|
107
|
+
const AUTH_RESET_WINDOW_MS = 5_000;
|
|
108
|
+
const STALE_TAB_MS = 60_000;
|
|
109
|
+
// Well under the ~60 s idle cut most reverse proxies apply.
|
|
110
|
+
const PING_EVERY_MS = 20_000;
|
|
111
|
+
const RETRY_BASE_MS = 1_000;
|
|
112
|
+
const RETRY_CAP_MS = 30_000;
|
|
113
|
+
const TOAST_OK_SECONDS = 4;
|
|
114
|
+
const TOAST_FAIL_SECONDS = 8;
|
|
115
|
+
// graphql-ws gives up on some close codes no matter what `shouldRetry` says; reporting them as this
|
|
116
|
+
// "try again later" code keeps the socket coming back.
|
|
117
|
+
const RETRYABLE_CLOSE = 1013;
|
|
118
|
+
function provideGraphql(options) {
|
|
119
|
+
return provideNamedApollo(() => buildClients(options));
|
|
120
|
+
}
|
|
121
|
+
function buildClients(options) {
|
|
122
|
+
const auth = inject(AuthorizationService);
|
|
123
|
+
const messages = inject(SPINE_MESSAGES);
|
|
124
|
+
const batchLink = inject(HttpBatchLink);
|
|
125
|
+
const notifications = inject(NotificationService, { optional: true });
|
|
126
|
+
const logger = inject(LoggerService, { optional: true });
|
|
127
|
+
const config = inject(SPINE_CONFIG, { optional: true });
|
|
128
|
+
const browser = isPlatformBrowser(inject(PLATFORM_ID));
|
|
129
|
+
const sockets = [];
|
|
130
|
+
const dropAllSockets = () => {
|
|
131
|
+
for (const socket of sockets) {
|
|
132
|
+
try {
|
|
133
|
+
socket.terminate();
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// already dead: nothing to do
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
let lastAuthReset = -Infinity;
|
|
141
|
+
const authErrorLink = new ErrorLink(({ error }) => {
|
|
142
|
+
if (!carriesAuthCode(error))
|
|
143
|
+
return;
|
|
144
|
+
const now = Date.now();
|
|
145
|
+
if (now - lastAuthReset < AUTH_RESET_WINDOW_MS)
|
|
146
|
+
return;
|
|
147
|
+
lastAuthReset = now;
|
|
148
|
+
dropAllSockets();
|
|
149
|
+
});
|
|
150
|
+
const tokenLink = new ApolloLink((operation, forward) => {
|
|
151
|
+
const token = auth.getToken();
|
|
152
|
+
if (token) {
|
|
153
|
+
operation.setContext(({ headers }) => ({
|
|
154
|
+
headers: toHttpHeaders(headers).set(TOKEN_HEADER, token),
|
|
155
|
+
}));
|
|
156
|
+
}
|
|
157
|
+
return forward(operation);
|
|
158
|
+
});
|
|
159
|
+
const toastLink = notifications ? envelopeToastLink(notifications, messages) : null;
|
|
160
|
+
const socketParams = () => {
|
|
161
|
+
const token = auth.getToken();
|
|
162
|
+
if (!token)
|
|
163
|
+
return {};
|
|
164
|
+
const params = { [TOKEN_HEADER]: token, headers: { [TOKEN_HEADER]: token } };
|
|
165
|
+
const routeId = logger?.routeId;
|
|
166
|
+
if (routeId)
|
|
167
|
+
params['routeId'] = routeId;
|
|
168
|
+
if (config?.clientId)
|
|
169
|
+
params['clientId'] = config.clientId;
|
|
170
|
+
return params;
|
|
171
|
+
};
|
|
172
|
+
const named = {};
|
|
173
|
+
for (const endpoint of Object.values(options.endpoints)) {
|
|
174
|
+
const httpLink = ApolloLink.concat(tokenLink, batchLink.create({ uri: endpoint.http }));
|
|
175
|
+
let transport = httpLink;
|
|
176
|
+
if (browser && endpoint.ws) {
|
|
177
|
+
const socket = openSocket(endpoint, socketParams);
|
|
178
|
+
sockets.push(socket);
|
|
179
|
+
transport = ApolloLink.split((operation) => operation.operationType === OperationTypeNode.SUBSCRIPTION, new GraphQLWsLink(socket), httpLink);
|
|
180
|
+
}
|
|
181
|
+
named[endpoint.namedClient] = {
|
|
182
|
+
link: ApolloLink.from(toastLink ? [authErrorLink, toastLink, transport] : [authErrorLink, transport]),
|
|
183
|
+
cache: new InMemoryCache(),
|
|
184
|
+
defaultOptions: {
|
|
185
|
+
query: { fetchPolicy: 'no-cache' },
|
|
186
|
+
watchQuery: { fetchPolicy: 'no-cache' },
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
const destroyRef = inject(DestroyRef);
|
|
191
|
+
if (browser && sockets.length) {
|
|
192
|
+
const doc = inject(DOCUMENT);
|
|
193
|
+
let hiddenAt = null;
|
|
194
|
+
const onVisibility = () => {
|
|
195
|
+
if (doc.visibilityState === 'hidden') {
|
|
196
|
+
hiddenAt = Date.now();
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (doc.visibilityState !== 'visible' || hiddenAt === null)
|
|
200
|
+
return;
|
|
201
|
+
const away = Date.now() - hiddenAt;
|
|
202
|
+
hiddenAt = null;
|
|
203
|
+
if (away >= STALE_TAB_MS)
|
|
204
|
+
dropAllSockets();
|
|
205
|
+
};
|
|
206
|
+
doc.addEventListener('visibilitychange', onVisibility);
|
|
207
|
+
destroyRef.onDestroy(() => doc.removeEventListener('visibilitychange', onVisibility));
|
|
208
|
+
}
|
|
209
|
+
destroyRef.onDestroy(() => {
|
|
210
|
+
for (const socket of sockets) {
|
|
211
|
+
Promise.resolve()
|
|
212
|
+
.then(() => socket.dispose())
|
|
213
|
+
.catch(() => undefined);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
return named;
|
|
217
|
+
}
|
|
218
|
+
function openSocket(endpoint, connectionParams) {
|
|
219
|
+
let everConnected = false;
|
|
220
|
+
return createClient({
|
|
221
|
+
url: endpoint.ws,
|
|
222
|
+
connectionParams,
|
|
223
|
+
keepAlive: PING_EVERY_MS,
|
|
224
|
+
retryAttempts: Infinity,
|
|
225
|
+
shouldRetry: () => true,
|
|
226
|
+
retryWait: backoff,
|
|
227
|
+
webSocketImpl: forgivingSocket(globalThis.WebSocket),
|
|
228
|
+
on: {
|
|
229
|
+
connected: (_socket, _payload, wasRetry) => {
|
|
230
|
+
if (wasRetry && everConnected)
|
|
231
|
+
wsReconnected$.next(endpoint.namedClient);
|
|
232
|
+
everConnected = true;
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
/** Exponential wait with "equal jitter": half fixed, half random, capped. */
|
|
238
|
+
function backoff(attempt) {
|
|
239
|
+
const ceiling = Math.min(RETRY_CAP_MS, RETRY_BASE_MS * 2 ** attempt);
|
|
240
|
+
const wait = ceiling / 2 + Math.random() * (ceiling / 2);
|
|
241
|
+
return new Promise((resolve) => setTimeout(resolve, wait));
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Thin wrapper around the platform WebSocket that reports every abnormal close as retryable, so the
|
|
245
|
+
* client keeps reconnecting even after closes graphql-ws would otherwise treat as final.
|
|
246
|
+
*/
|
|
247
|
+
function forgivingSocket(Native) {
|
|
248
|
+
class ForgivingSocket {
|
|
249
|
+
static { this.CONNECTING = 0; }
|
|
250
|
+
static { this.OPEN = 1; }
|
|
251
|
+
static { this.CLOSING = 2; }
|
|
252
|
+
static { this.CLOSED = 3; }
|
|
253
|
+
constructor(url, protocols) {
|
|
254
|
+
this.inner = new Native(url, protocols);
|
|
255
|
+
}
|
|
256
|
+
get readyState() {
|
|
257
|
+
return this.inner.readyState;
|
|
258
|
+
}
|
|
259
|
+
get protocol() {
|
|
260
|
+
return this.inner.protocol;
|
|
261
|
+
}
|
|
262
|
+
set onopen(handler) {
|
|
263
|
+
this.inner.onopen = handler;
|
|
264
|
+
}
|
|
265
|
+
set onmessage(handler) {
|
|
266
|
+
this.inner.onmessage = handler;
|
|
267
|
+
}
|
|
268
|
+
set onerror(handler) {
|
|
269
|
+
this.inner.onerror = handler;
|
|
270
|
+
}
|
|
271
|
+
set onclose(handler) {
|
|
272
|
+
this.inner.onclose = handler
|
|
273
|
+
? (event) => handler({
|
|
274
|
+
code: event.code === 1000 ? 1000 : RETRYABLE_CLOSE,
|
|
275
|
+
reason: event.reason,
|
|
276
|
+
wasClean: event.wasClean,
|
|
277
|
+
})
|
|
278
|
+
: null;
|
|
279
|
+
}
|
|
280
|
+
send(data) {
|
|
281
|
+
this.inner.send(data);
|
|
282
|
+
}
|
|
283
|
+
close(code, reason) {
|
|
284
|
+
this.inner.close(code, reason);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return ForgivingSocket;
|
|
288
|
+
}
|
|
289
|
+
function toHttpHeaders(headers) {
|
|
290
|
+
if (headers instanceof HttpHeaders)
|
|
291
|
+
return headers;
|
|
292
|
+
return new HttpHeaders(headers ?? {});
|
|
293
|
+
}
|
|
294
|
+
function codeOf(source) {
|
|
295
|
+
if (!source || typeof source !== 'object')
|
|
296
|
+
return null;
|
|
297
|
+
const record = source;
|
|
298
|
+
for (const key of ['code', 'status', 'statusCode']) {
|
|
299
|
+
const value = record[key];
|
|
300
|
+
if (value !== undefined && value !== null && value !== '') {
|
|
301
|
+
const code = Number(value);
|
|
302
|
+
if (Number.isFinite(code))
|
|
303
|
+
return code;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
function carriesAuthCode(error) {
|
|
309
|
+
const codes = CombinedGraphQLErrors.is(error)
|
|
310
|
+
? error.errors.map((entry) => codeOf(entry.extensions))
|
|
311
|
+
: [codeOf(error)];
|
|
312
|
+
return codes.some((code) => code !== null && AUTH_CODES.has(code));
|
|
313
|
+
}
|
|
314
|
+
function envelopeToastLink(notifications, messages) {
|
|
315
|
+
return new ApolloLink((operation, forward) => {
|
|
316
|
+
const kind = operation.operationType;
|
|
317
|
+
if (kind === OperationTypeNode.SUBSCRIPTION || operation.getContext()['silenceEnvelope'] === true) {
|
|
318
|
+
return forward(operation);
|
|
319
|
+
}
|
|
320
|
+
const isMutation = kind === OperationTypeNode.MUTATION;
|
|
321
|
+
return forward(operation).pipe(tap((result) => {
|
|
322
|
+
for (const envelope of envelopesOf(result.data)) {
|
|
323
|
+
if (envelope.ok ? !isMutation || !envelope.message : !isMutation && String(envelope.status) === '404') {
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
const numeric = Number(envelope.status);
|
|
327
|
+
notifications.addNotification({
|
|
328
|
+
timer: envelope.ok ? TOAST_OK_SECONDS : TOAST_FAIL_SECONDS,
|
|
329
|
+
hermesAlertType: Number.isFinite(numeric)
|
|
330
|
+
? notifications.resolveAlertType(numeric)
|
|
331
|
+
: envelope.ok
|
|
332
|
+
? AlertType.SUCCESS
|
|
333
|
+
: AlertType.DANGER,
|
|
334
|
+
message: envelope.message || (envelope.ok ? messages.graphql.done : messages.graphql.failed),
|
|
335
|
+
hermesAlertClosable: true,
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
}));
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Generated bundle index. Do not edit.
|
|
344
|
+
*/
|
|
345
|
+
|
|
346
|
+
export { GraphqlEnvelopeError, envelopesOf, failedEnvelopes, injectGraphqlClient, isEnvelopeOk, provideGraphql, unwrap, wsReconnected$ };
|
|
347
|
+
//# sourceMappingURL=trismegisto-spine-graphql.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trismegisto-spine-graphql.mjs","sources":["../../../projects/ui/graphql/src/envelope.ts","../../../projects/ui/graphql/src/graphql-client.ts","../../../projects/ui/graphql/src/provide-graphql.ts","../../../projects/ui/graphql/src/trismegisto-spine-graphql.ts"],"sourcesContent":["import { currentSpineMessages } from '@trismegisto/spine';\n\n/** Shape every root query/mutation field returns on the platform: business status travels in the payload. */\nexport interface GraphqlEnvelope<T> {\n readonly status?: number | string | null;\n readonly message?: string | null;\n readonly data?: T | null;\n}\n\n/** Business failure carried by an envelope. `status` is kept exactly as the backend sent it. */\nexport class GraphqlEnvelopeError extends Error {\n readonly status: number | string | null | undefined;\n\n constructor(status: number | string | null | undefined, message: string) {\n super(message);\n this.name = 'GraphqlEnvelopeError';\n this.status = status;\n // Keeps `instanceof` working when the output is down-levelled.\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nconst FAILURE_WORDS = new Set(['error', 'failed', 'failure', 'fail']);\n\nexport function isEnvelopeOk(status: GraphqlEnvelope<unknown>['status']): boolean {\n if (status === null || status === undefined) return true;\n if (typeof status === 'number') return status >= 200 && status < 300;\n if (typeof status !== 'string') return true;\n // Numeric text is deliberately not parsed: only the failure words count as failure.\n return !FAILURE_WORDS.has(status.trim().toLowerCase());\n}\n\n/** Returns `data` of an ok envelope; throws `GraphqlEnvelopeError` for a missing or failed one. */\nexport function unwrap<T>(envelope: GraphqlEnvelope<T> | null | undefined): T {\n if (envelope === null || envelope === undefined) {\n throw new GraphqlEnvelopeError(null, currentSpineMessages().graphql.noResponse);\n }\n if (!isEnvelopeOk(envelope.status)) {\n throw new GraphqlEnvelopeError(envelope.status, envelope.message || currentSpineMessages().graphql.failed);\n }\n return envelope.data as T;\n}\n\ntype Fields = [string, Record<string, unknown>][];\n\nfunction objectFields(data: unknown): Fields {\n if (!data || typeof data !== 'object') return [];\n return Object.entries(data as Record<string, unknown>).filter(\n (entry): entry is [string, Record<string, unknown>] => typeof entry[1] === 'object' && entry[1] !== null,\n );\n}\n\nconst hasStatus = (value: Record<string, unknown>): boolean =>\n 'status' in value && value['status'] !== null && value['status'] !== undefined;\n\n/** First-level envelopes found in an operation's `data` (fields that carry both `status` and `message`). */\nexport function envelopesOf(data: unknown): { field: string; status: number | string; message: string; ok: boolean }[] {\n return objectFields(data)\n .filter(([, value]) => 'message' in value && hasStatus(value))\n .map(([field, value]) => {\n const status = value['status'] as number | string;\n return { field, status, message: (value['message'] as string | null) ?? '', ok: isEnvelopeOk(status) };\n });\n}\n\n/** First-level fields whose status is a failure; `message` is optional here. */\nexport function failedEnvelopes(\n data: unknown,\n fallbackMessage: string = currentSpineMessages().graphql.serviceFailure,\n): { field: string; status: unknown; message: string }[] {\n return objectFields(data)\n .filter(([, value]) => hasStatus(value) && !isEnvelopeOk(value['status'] as GraphqlEnvelope<unknown>['status']))\n .map(([field, value]) => ({\n field,\n status: value['status'],\n message: (value['message'] as string | null | undefined) || fallbackMessage,\n }));\n}\n","import { inject } from '@angular/core';\nimport type { DefaultContext, OperationVariables, TypedDocumentNode } from '@apollo/client/core';\nimport { Apollo } from 'apollo-angular';\nimport { Observable, filter, firstValueFrom, map } from 'rxjs';\n\nimport { currentSpineMessages } from '@trismegisto/spine';\nimport { GraphqlEnvelopeError } from './envelope';\n\n/** Opções de uma chamada. `silenceEnvelope`: a tela trata a falha sozinha, sem o toast automático. */\nexport interface GraphqlCallOptions {\n readonly silenceEnvelope?: boolean;\n readonly context?: DefaultContext;\n}\n\n/**\n * Cliente GraphQL de UM backend do app, tipado pelo documento gerado no codegen\n * (`TypedDocumentNode`): o retorno é o `data` da operação, sem `<any>`. Junto com o `unwrap` do\n * envelope, é o caminho padrão dos serviços de domínio:\n *\n * private readonly gql = injectGraphqlClient('kalliope');\n * async listTeams() { return unwrap((await this.gql.query(ListTeamsDocument)).teams); }\n *\n * Erro de transporte/GraphQL (`errors[]`) rejeita a Promise (o `errorPolicy` é o padrão `none`);\n * resposta sem `data` também. Falha de NEGÓCIO vem no envelope e quem decide é o `unwrap`.\n */\nexport interface GraphqlClient {\n query<T, V extends OperationVariables = OperationVariables>(\n document: TypedDocumentNode<T, V>, variables?: V, options?: GraphqlCallOptions): Promise<T>;\n mutate<T, V extends OperationVariables = OperationVariables>(\n document: TypedDocumentNode<T, V>, variables?: V, options?: GraphqlCallOptions): Promise<T>;\n /** Eventos da subscription (sem envelope: evento não é resposta). Mensagem sem `data` é ignorada. */\n subscribe<T, V extends OperationVariables = OperationVariables>(\n document: TypedDocumentNode<T, V>, variables?: V): Observable<T>;\n}\n\nconst contextOf = (options?: GraphqlCallOptions): DefaultContext | undefined =>\n options?.silenceEnvelope ? { ...options.context, silenceEnvelope: true } : options?.context;\n\nconst required = <T>(data: T | null | undefined): T => {\n if (data === null || data === undefined) throw new GraphqlEnvelopeError(null, currentSpineMessages().graphql.noResponse);\n return data;\n};\n\n/** O `GraphqlClient` do backend `namedClient` (`environment.graphql.<chave>.namedClient`). Chamar em contexto de injeção. */\nexport function injectGraphqlClient(namedClient: string): GraphqlClient {\n const apollo = inject(Apollo);\n const client = () => apollo.use(namedClient);\n // Os genéricos do apollo-angular não casam 1:1 com os do TypedDocumentNode (variáveis opcionais):\n // o tipo público acima é o contrato; aqui dentro o cast é deliberado.\n /* eslint-disable @typescript-eslint/no-explicit-any */\n return {\n async query(document: any, variables?: any, options?: GraphqlCallOptions) {\n const result = await firstValueFrom(client().query<any, any>({ query: document, variables, context: contextOf(options) }));\n return required(result.data);\n },\n async mutate(document: any, variables?: any, options?: GraphqlCallOptions) {\n const result = await firstValueFrom(client().mutate<any, any>({ mutation: document, variables, context: contextOf(options) }));\n return required(result.data);\n },\n subscribe(document: any, variables?: any) {\n return client().subscribe<any, any>({ query: document, variables }).pipe(\n map((result) => result.data),\n filter((data) => data !== null && data !== undefined),\n );\n },\n } as GraphqlClient;\n /* eslint-enable @typescript-eslint/no-explicit-any */\n}\n","import { DOCUMENT, DestroyRef, PLATFORM_ID, Provider, inject } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { HttpHeaders } from '@angular/common/http';\nimport { ApolloLink, CombinedGraphQLErrors, InMemoryCache } from '@apollo/client';\nimport { ErrorLink } from '@apollo/client/link/error';\nimport { GraphQLWsLink } from '@apollo/client/link/subscriptions';\nimport { NamedOptions, provideNamedApollo } from 'apollo-angular';\nimport { HttpBatchLink } from 'apollo-angular/http';\nimport { OperationTypeNode } from 'graphql';\nimport { Client, createClient } from 'graphql-ws';\nimport { Subject, tap } from 'rxjs';\n\nimport { AuthorizationService } from '@orfeu/angular/core';\nimport { SPINE_CONFIG, SPINE_MESSAGES, SpineMessages } from '@trismegisto/spine';\nimport { AlertType, NotificationService } from '@trismegisto/spine/notification';\nimport { LoggerService } from '@trismegisto/spine/routing';\n\nimport { envelopesOf } from './envelope';\n\nexport interface GraphqlEndpoint {\n // Mutable on purpose: the runtime environment rewrites `http`/`ws` before bootstrap.\n namedClient: string;\n http: string;\n ws?: string;\n}\n\nexport interface GraphqlOptions {\n readonly endpoints: Readonly<Record<string, GraphqlEndpoint>>;\n}\n\n/** Emits the `namedClient` whose socket came back after a drop (never on the first connection). */\nexport const wsReconnected$ = new Subject<string>();\n\nconst TOKEN_HEADER = 'x-access-token';\nconst AUTH_CODES = new Set([401, 4401, 4403]);\nconst AUTH_RESET_WINDOW_MS = 5_000;\nconst STALE_TAB_MS = 60_000;\n// Well under the ~60 s idle cut most reverse proxies apply.\nconst PING_EVERY_MS = 20_000;\nconst RETRY_BASE_MS = 1_000;\nconst RETRY_CAP_MS = 30_000;\nconst TOAST_OK_SECONDS = 4;\nconst TOAST_FAIL_SECONDS = 8;\n// graphql-ws gives up on some close codes no matter what `shouldRetry` says; reporting them as this\n// \"try again later\" code keeps the socket coming back.\nconst RETRYABLE_CLOSE = 1013;\n\ntype InitPayload = Record<string, unknown>;\n\nexport function provideGraphql(options: GraphqlOptions): Provider {\n return provideNamedApollo(() => buildClients(options));\n}\n\nfunction buildClients(options: GraphqlOptions): NamedOptions {\n const auth = inject(AuthorizationService);\n const messages = inject(SPINE_MESSAGES);\n const batchLink = inject(HttpBatchLink);\n const notifications = inject(NotificationService, { optional: true });\n const logger = inject(LoggerService, { optional: true });\n const config = inject(SPINE_CONFIG, { optional: true });\n const browser = isPlatformBrowser(inject(PLATFORM_ID));\n\n const sockets: Client[] = [];\n const dropAllSockets = () => {\n for (const socket of sockets) {\n try {\n socket.terminate();\n } catch {\n // already dead: nothing to do\n }\n }\n };\n\n let lastAuthReset = -Infinity;\n const authErrorLink = new ErrorLink(({ error }) => {\n if (!carriesAuthCode(error)) return;\n const now = Date.now();\n if (now - lastAuthReset < AUTH_RESET_WINDOW_MS) return;\n lastAuthReset = now;\n dropAllSockets();\n });\n\n const tokenLink = new ApolloLink((operation, forward) => {\n const token = auth.getToken();\n if (token) {\n operation.setContext(({ headers }: { headers?: HttpHeaders | Record<string, string> }) => ({\n headers: toHttpHeaders(headers).set(TOKEN_HEADER, token),\n }));\n }\n return forward(operation);\n });\n\n const toastLink = notifications ? envelopeToastLink(notifications, messages) : null;\n\n const socketParams = (): InitPayload => {\n const token = auth.getToken();\n if (!token) return {};\n const params: InitPayload = { [TOKEN_HEADER]: token, headers: { [TOKEN_HEADER]: token } };\n const routeId = logger?.routeId;\n if (routeId) params['routeId'] = routeId;\n if (config?.clientId) params['clientId'] = config.clientId;\n return params;\n };\n\n const named: NamedOptions = {};\n for (const endpoint of Object.values(options.endpoints)) {\n const httpLink = ApolloLink.concat(tokenLink, batchLink.create({ uri: endpoint.http }));\n let transport: ApolloLink = httpLink;\n\n if (browser && endpoint.ws) {\n const socket = openSocket(endpoint, socketParams);\n sockets.push(socket);\n transport = ApolloLink.split(\n (operation) => operation.operationType === OperationTypeNode.SUBSCRIPTION,\n new GraphQLWsLink(socket),\n httpLink,\n );\n }\n\n named[endpoint.namedClient] = {\n link: ApolloLink.from(toastLink ? [authErrorLink, toastLink, transport] : [authErrorLink, transport]),\n cache: new InMemoryCache(),\n defaultOptions: {\n query: { fetchPolicy: 'no-cache' },\n watchQuery: { fetchPolicy: 'no-cache' },\n },\n };\n }\n\n const destroyRef = inject(DestroyRef);\n if (browser && sockets.length) {\n const doc = inject(DOCUMENT);\n let hiddenAt: number | null = null;\n const onVisibility = () => {\n if (doc.visibilityState === 'hidden') {\n hiddenAt = Date.now();\n return;\n }\n if (doc.visibilityState !== 'visible' || hiddenAt === null) return;\n const away = Date.now() - hiddenAt;\n hiddenAt = null;\n if (away >= STALE_TAB_MS) dropAllSockets();\n };\n doc.addEventListener('visibilitychange', onVisibility);\n destroyRef.onDestroy(() => doc.removeEventListener('visibilitychange', onVisibility));\n }\n destroyRef.onDestroy(() => {\n for (const socket of sockets) {\n Promise.resolve()\n .then(() => socket.dispose())\n .catch(() => undefined);\n }\n });\n\n return named;\n}\n\nfunction openSocket(endpoint: GraphqlEndpoint, connectionParams: () => InitPayload): Client {\n let everConnected = false;\n return createClient({\n url: endpoint.ws!,\n connectionParams,\n keepAlive: PING_EVERY_MS,\n retryAttempts: Infinity,\n shouldRetry: () => true,\n retryWait: backoff,\n webSocketImpl: forgivingSocket(globalThis.WebSocket),\n on: {\n connected: (_socket, _payload, wasRetry) => {\n if (wasRetry && everConnected) wsReconnected$.next(endpoint.namedClient);\n everConnected = true;\n },\n },\n });\n}\n\n/** Exponential wait with \"equal jitter\": half fixed, half random, capped. */\nfunction backoff(attempt: number): Promise<void> {\n const ceiling = Math.min(RETRY_CAP_MS, RETRY_BASE_MS * 2 ** attempt);\n const wait = ceiling / 2 + Math.random() * (ceiling / 2);\n return new Promise((resolve) => setTimeout(resolve, wait));\n}\n\n/**\n * Thin wrapper around the platform WebSocket that reports every abnormal close as retryable, so the\n * client keeps reconnecting even after closes graphql-ws would otherwise treat as final.\n */\nfunction forgivingSocket(Native: typeof WebSocket): typeof WebSocket {\n class ForgivingSocket {\n static readonly CONNECTING = 0;\n static readonly OPEN = 1;\n static readonly CLOSING = 2;\n static readonly CLOSED = 3;\n\n private readonly inner: WebSocket;\n\n constructor(url: string | URL, protocols?: string | string[]) {\n this.inner = new Native(url, protocols);\n }\n\n get readyState(): number {\n return this.inner.readyState;\n }\n\n get protocol(): string {\n return this.inner.protocol;\n }\n\n set onopen(handler: WebSocket['onopen']) {\n this.inner.onopen = handler;\n }\n\n set onmessage(handler: WebSocket['onmessage']) {\n this.inner.onmessage = handler;\n }\n\n set onerror(handler: WebSocket['onerror']) {\n this.inner.onerror = handler;\n }\n\n set onclose(handler: ((event: CloseEvent) => void) | null) {\n this.inner.onclose = handler\n ? (event: CloseEvent) =>\n handler({\n code: event.code === 1000 ? 1000 : RETRYABLE_CLOSE,\n reason: event.reason,\n wasClean: event.wasClean,\n } as CloseEvent)\n : null;\n }\n\n send(data: string): void {\n this.inner.send(data);\n }\n\n close(code?: number, reason?: string): void {\n this.inner.close(code, reason);\n }\n }\n return ForgivingSocket as unknown as typeof WebSocket;\n}\n\nfunction toHttpHeaders(headers: HttpHeaders | Record<string, string> | undefined): HttpHeaders {\n if (headers instanceof HttpHeaders) return headers;\n return new HttpHeaders(headers ?? {});\n}\n\nfunction codeOf(source: unknown): number | null {\n if (!source || typeof source !== 'object') return null;\n const record = source as Record<string, unknown>;\n for (const key of ['code', 'status', 'statusCode']) {\n const value = record[key];\n if (value !== undefined && value !== null && value !== '') {\n const code = Number(value);\n if (Number.isFinite(code)) return code;\n }\n }\n return null;\n}\n\nfunction carriesAuthCode(error: unknown): boolean {\n const codes = CombinedGraphQLErrors.is(error)\n ? error.errors.map((entry) => codeOf(entry.extensions))\n : [codeOf(error)];\n return codes.some((code) => code !== null && AUTH_CODES.has(code));\n}\n\nfunction envelopeToastLink(notifications: NotificationService, messages: SpineMessages): ApolloLink {\n return new ApolloLink((operation, forward) => {\n const kind = operation.operationType;\n if (kind === OperationTypeNode.SUBSCRIPTION || operation.getContext()['silenceEnvelope'] === true) {\n return forward(operation);\n }\n const isMutation = kind === OperationTypeNode.MUTATION;\n return forward(operation).pipe(\n tap((result) => {\n for (const envelope of envelopesOf(result.data)) {\n if (envelope.ok ? !isMutation || !envelope.message : !isMutation && String(envelope.status) === '404') {\n continue;\n }\n const numeric = Number(envelope.status);\n notifications.addNotification({\n timer: envelope.ok ? TOAST_OK_SECONDS : TOAST_FAIL_SECONDS,\n hermesAlertType: Number.isFinite(numeric)\n ? notifications.resolveAlertType(numeric)\n : envelope.ok\n ? AlertType.SUCCESS\n : AlertType.DANGER,\n message: envelope.message || (envelope.ok ? messages.graphql.done : messages.graphql.failed),\n hermesAlertClosable: true,\n });\n }\n }),\n );\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|