@seedgrid/fe-backup 2026.7.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/README.md +86 -0
- package/dist/backup.d.ts +47 -0
- package/dist/backup.d.ts.map +1 -0
- package/dist/backup.js +3 -0
- package/dist/export-status.d.ts +6 -0
- package/dist/export-status.d.ts.map +1 -0
- package/dist/export-status.js +28 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/messages.d.ts +308 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +202 -0
- package/dist/module.d.ts +3 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +23 -0
- package/dist/module.json +15 -0
- package/dist/paths.d.ts +9 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +11 -0
- package/dist/server/create-backup-server.d.ts +19 -0
- package/dist/server/create-backup-server.d.ts.map +1 -0
- package/dist/server/create-backup-server.js +19 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +2 -0
- package/package.json +43 -0
- package/scaffold/README.md +69 -0
- package/scaffold/src/app/api/backup/exports/[jobId]/download/route.ts +87 -0
- package/scaffold/src/app/backup/exports/(create)/new/page.test.tsx +182 -0
- package/scaffold/src/app/backup/exports/(create)/new/page.tsx +168 -0
- package/scaffold/src/app/backup/exports/(list)/page.test.tsx +166 -0
- package/scaffold/src/app/backup/exports/(list)/page.tsx +286 -0
- package/scaffold/src/modules/backup/components/ExportStatusBadge.test.tsx +75 -0
- package/scaffold/src/modules/backup/components/ExportStatusBadge.tsx +54 -0
- package/scaffold/src/modules/backup/config.ts +27 -0
- package/scaffold/src/modules/backup/index.ts +19 -0
- package/scaffold/src/modules/backup/services/backup-api.test.ts +122 -0
- package/scaffold/src/modules/backup/services/backup-api.ts +205 -0
- package/scaffold/src/modules/backup/services/backup-service.test.ts +125 -0
- package/scaffold/src/modules/backup/services/backup-service.ts +34 -0
- package/scaffold/src/modules/backup/types.ts +17 -0
- package/scaffold/src/modules/backup/useBackupAppShellSections.test.tsx +61 -0
- package/scaffold/src/modules/backup/useBackupAppShellSections.tsx +50 -0
package/dist/messages.js
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
// Mensagens do módulo backup/export. Promovido de
|
|
2
|
+
// seedgrid-cli/templates/modules/backup/src/modules/backup/messages.ts.hbs —
|
|
3
|
+
// era puro (zero import "@/...", zero handlebars real), mesmo critério do
|
|
4
|
+
// securityMessages do fe-security.
|
|
5
|
+
const en = {
|
|
6
|
+
"backup.common.module_name": "Exports",
|
|
7
|
+
"backup.common.loading": "Loading...",
|
|
8
|
+
"backup.common.actions": "Actions",
|
|
9
|
+
"backup.common.cancel": "Cancel",
|
|
10
|
+
"backup.common.confirm": "Confirm",
|
|
11
|
+
"backup.common.refresh": "Refresh",
|
|
12
|
+
"backup.common.server_connection_error": "Could not connect to the server",
|
|
13
|
+
"backup.exports.list.title": "Data Exports",
|
|
14
|
+
"backup.exports.list.description": "Create and manage tenant data export jobs.",
|
|
15
|
+
"backup.exports.list.new": "New export",
|
|
16
|
+
"backup.exports.list.empty": "No export jobs found.",
|
|
17
|
+
"backup.exports.list.column.job_id": "Job ID",
|
|
18
|
+
"backup.exports.list.column.format": "Format",
|
|
19
|
+
"backup.exports.list.column.scope": "Scope",
|
|
20
|
+
"backup.exports.list.column.status": "Status",
|
|
21
|
+
"backup.exports.list.column.progress": "Progress",
|
|
22
|
+
"backup.exports.list.column.created_at": "Created at",
|
|
23
|
+
"backup.exports.list.column.finished_at": "Finished at",
|
|
24
|
+
"backup.exports.list.column.size": "Size",
|
|
25
|
+
"backup.exports.list.action.download": "Download",
|
|
26
|
+
"backup.exports.list.action.delete": "Delete",
|
|
27
|
+
"backup.exports.list.action.cancel": "Cancel",
|
|
28
|
+
"backup.exports.list.load_error": "Could not load export jobs.",
|
|
29
|
+
"backup.exports.list.delete_title": "Delete export",
|
|
30
|
+
"backup.exports.list.delete_message": "Delete or cancel the selected export job?",
|
|
31
|
+
"backup.exports.list.delete_success": "Export job deleted successfully.",
|
|
32
|
+
"backup.exports.list.delete_error": "Could not delete the export job.",
|
|
33
|
+
"backup.exports.list.download_error": "Could not download the export file.",
|
|
34
|
+
"backup.exports.create.title": "New export",
|
|
35
|
+
"backup.exports.create.description": "Configure and start a new data export job.",
|
|
36
|
+
"backup.exports.create.format_label": "Export format",
|
|
37
|
+
"backup.exports.create.scope_label": "Export scope",
|
|
38
|
+
"backup.exports.create.attachments_label": "Include attachments",
|
|
39
|
+
"backup.exports.create.format_csv_zip": "CSV (Portability)",
|
|
40
|
+
"backup.exports.create.format_csv_zip_hint": "CSV files in ZIP. Best for migration, compliance (LGPD/GDPR), and BI tools.",
|
|
41
|
+
"backup.exports.create.format_sql_dump_zip": "SQL Dump (Technical Restore)",
|
|
42
|
+
"backup.exports.create.format_sql_dump_zip_hint": "SQL dump in ZIP. Best for disaster recovery and faithful restoration.",
|
|
43
|
+
"backup.exports.create.scope_domain": "Business data",
|
|
44
|
+
"backup.exports.create.scope_domain_hint": "Exports business entities only (recommended).",
|
|
45
|
+
"backup.exports.create.scope_raw": "Raw database tables",
|
|
46
|
+
"backup.exports.create.scope_raw_hint": "Exports all tables. For advanced users only.",
|
|
47
|
+
"backup.exports.create.scope_custom": "Custom selection",
|
|
48
|
+
"backup.exports.create.scope_custom_hint": "Select specific modules to export.",
|
|
49
|
+
"backup.exports.create.submit": "Start export",
|
|
50
|
+
"backup.exports.create.success": "Export job created successfully.",
|
|
51
|
+
"backup.exports.create.error": "Could not create the export job.",
|
|
52
|
+
"backup.exports.status.REQUESTED": "Requested",
|
|
53
|
+
"backup.exports.status.QUEUED": "Queued",
|
|
54
|
+
"backup.exports.status.RUNNING": "Running",
|
|
55
|
+
"backup.exports.status.DONE": "Ready",
|
|
56
|
+
"backup.exports.status.DONE_NOTIFIED": "Ready",
|
|
57
|
+
"backup.exports.status.FAILED": "Failed",
|
|
58
|
+
"backup.exports.status.EXPIRED": "Expired",
|
|
59
|
+
"backup.exports.status.CANCELLED": "Cancelled",
|
|
60
|
+
"backup.exports.format.CSV_ZIP": "CSV / ZIP",
|
|
61
|
+
"backup.exports.format.SQL_DUMP_ZIP": "SQL Dump / ZIP",
|
|
62
|
+
"backup.exports.scope.DOMAIN": "Business data",
|
|
63
|
+
"backup.exports.scope.RAW": "Raw tables",
|
|
64
|
+
"backup.exports.scope.CUSTOM": "Custom",
|
|
65
|
+
};
|
|
66
|
+
const ptBr = {
|
|
67
|
+
"backup.common.module_name": "Exportacoes",
|
|
68
|
+
"backup.common.loading": "Carregando...",
|
|
69
|
+
"backup.common.actions": "Acoes",
|
|
70
|
+
"backup.common.cancel": "Cancelar",
|
|
71
|
+
"backup.common.confirm": "Confirmar",
|
|
72
|
+
"backup.common.refresh": "Atualizar",
|
|
73
|
+
"backup.common.server_connection_error": "Erro ao conectar ao servidor",
|
|
74
|
+
"backup.exports.list.title": "Exportacoes de dados",
|
|
75
|
+
"backup.exports.list.description": "Crie e gerencie jobs de exportacao de dados do tenant.",
|
|
76
|
+
"backup.exports.list.new": "Nova exportacao",
|
|
77
|
+
"backup.exports.list.empty": "Nenhum job de exportacao encontrado.",
|
|
78
|
+
"backup.exports.list.column.job_id": "ID do job",
|
|
79
|
+
"backup.exports.list.column.format": "Formato",
|
|
80
|
+
"backup.exports.list.column.scope": "Escopo",
|
|
81
|
+
"backup.exports.list.column.status": "Status",
|
|
82
|
+
"backup.exports.list.column.progress": "Progresso",
|
|
83
|
+
"backup.exports.list.column.created_at": "Criado em",
|
|
84
|
+
"backup.exports.list.column.finished_at": "Finalizado em",
|
|
85
|
+
"backup.exports.list.column.size": "Tamanho",
|
|
86
|
+
"backup.exports.list.action.download": "Baixar",
|
|
87
|
+
"backup.exports.list.action.delete": "Excluir",
|
|
88
|
+
"backup.exports.list.action.cancel": "Cancelar",
|
|
89
|
+
"backup.exports.list.load_error": "Nao foi possivel carregar os jobs de exportacao.",
|
|
90
|
+
"backup.exports.list.delete_title": "Excluir exportacao",
|
|
91
|
+
"backup.exports.list.delete_message": "Excluir ou cancelar o job de exportacao selecionado?",
|
|
92
|
+
"backup.exports.list.delete_success": "Job de exportacao excluido com sucesso.",
|
|
93
|
+
"backup.exports.list.delete_error": "Nao foi possivel excluir o job de exportacao.",
|
|
94
|
+
"backup.exports.list.download_error": "Nao foi possivel baixar o arquivo de exportacao.",
|
|
95
|
+
"backup.exports.create.title": "Nova exportacao",
|
|
96
|
+
"backup.exports.create.description": "Configure e inicie um novo job de exportacao de dados.",
|
|
97
|
+
"backup.exports.create.format_label": "Formato de exportacao",
|
|
98
|
+
"backup.exports.create.scope_label": "Escopo de exportacao",
|
|
99
|
+
"backup.exports.create.attachments_label": "Incluir anexos",
|
|
100
|
+
"backup.exports.create.format_csv_zip": "CSV (Portabilidade)",
|
|
101
|
+
"backup.exports.create.format_csv_zip_hint": "Arquivos CSV em ZIP. Ideal para migracao, conformidade (LGPD/GDPR) e ferramentas de BI.",
|
|
102
|
+
"backup.exports.create.format_sql_dump_zip": "SQL Dump (Restauracao tecnica)",
|
|
103
|
+
"backup.exports.create.format_sql_dump_zip_hint": "Dump SQL em ZIP. Ideal para recuperacao de desastre e restauracao fiel.",
|
|
104
|
+
"backup.exports.create.scope_domain": "Dados de negocio",
|
|
105
|
+
"backup.exports.create.scope_domain_hint": "Exporta apenas entidades de negocio (recomendado).",
|
|
106
|
+
"backup.exports.create.scope_raw": "Tabelas brutas do banco",
|
|
107
|
+
"backup.exports.create.scope_raw_hint": "Exporta todas as tabelas. Somente para usuarios avancados.",
|
|
108
|
+
"backup.exports.create.scope_custom": "Selecao personalizada",
|
|
109
|
+
"backup.exports.create.scope_custom_hint": "Selecione modulos especificos para exportar.",
|
|
110
|
+
"backup.exports.create.submit": "Iniciar exportacao",
|
|
111
|
+
"backup.exports.create.success": "Job de exportacao criado com sucesso.",
|
|
112
|
+
"backup.exports.create.error": "Nao foi possivel criar o job de exportacao.",
|
|
113
|
+
"backup.exports.status.REQUESTED": "Solicitado",
|
|
114
|
+
"backup.exports.status.QUEUED": "Na fila",
|
|
115
|
+
"backup.exports.status.RUNNING": "Em andamento",
|
|
116
|
+
"backup.exports.status.DONE": "Pronto",
|
|
117
|
+
"backup.exports.status.DONE_NOTIFIED": "Pronto",
|
|
118
|
+
"backup.exports.status.FAILED": "Falhou",
|
|
119
|
+
"backup.exports.status.EXPIRED": "Expirado",
|
|
120
|
+
"backup.exports.status.CANCELLED": "Cancelado",
|
|
121
|
+
"backup.exports.format.CSV_ZIP": "CSV / ZIP",
|
|
122
|
+
"backup.exports.format.SQL_DUMP_ZIP": "SQL Dump / ZIP",
|
|
123
|
+
"backup.exports.scope.DOMAIN": "Dados de negocio",
|
|
124
|
+
"backup.exports.scope.RAW": "Tabelas brutas",
|
|
125
|
+
"backup.exports.scope.CUSTOM": "Personalizado",
|
|
126
|
+
};
|
|
127
|
+
const ptPt = {
|
|
128
|
+
"backup.exports.list.title": "Exportacoes de dados",
|
|
129
|
+
"backup.exports.list.new": "Nova exportacao",
|
|
130
|
+
"backup.exports.list.empty": "Nenhum job de exportacao encontrado.",
|
|
131
|
+
"backup.exports.list.action.download": "Transferir",
|
|
132
|
+
"backup.exports.create.submit": "Iniciar exportacao",
|
|
133
|
+
};
|
|
134
|
+
const es = {
|
|
135
|
+
"backup.common.module_name": "Exportaciones",
|
|
136
|
+
"backup.common.loading": "Cargando...",
|
|
137
|
+
"backup.common.actions": "Acciones",
|
|
138
|
+
"backup.common.cancel": "Cancelar",
|
|
139
|
+
"backup.common.confirm": "Confirmar",
|
|
140
|
+
"backup.common.server_connection_error": "Error al conectar con el servidor",
|
|
141
|
+
"backup.exports.list.title": "Exportaciones de datos",
|
|
142
|
+
"backup.exports.list.description": "Crea y gestiona jobs de exportacion de datos del tenant.",
|
|
143
|
+
"backup.exports.list.new": "Nueva exportacion",
|
|
144
|
+
"backup.exports.list.empty": "No se encontraron jobs de exportacion.",
|
|
145
|
+
"backup.exports.list.action.download": "Descargar",
|
|
146
|
+
"backup.exports.list.action.delete": "Eliminar",
|
|
147
|
+
"backup.exports.list.action.cancel": "Cancelar",
|
|
148
|
+
"backup.exports.list.delete_title": "Eliminar exportacion",
|
|
149
|
+
"backup.exports.list.delete_message": "Eliminar o cancelar el job de exportacion seleccionado?",
|
|
150
|
+
"backup.exports.list.delete_success": "Job de exportacion eliminado correctamente.",
|
|
151
|
+
"backup.exports.list.delete_error": "No se pudo eliminar el job de exportacion.",
|
|
152
|
+
"backup.exports.create.title": "Nueva exportacion",
|
|
153
|
+
"backup.exports.create.submit": "Iniciar exportacion",
|
|
154
|
+
"backup.exports.create.success": "Job de exportacion creado correctamente.",
|
|
155
|
+
"backup.exports.create.error": "No se pudo crear el job de exportacion.",
|
|
156
|
+
"backup.exports.status.REQUESTED": "Solicitado",
|
|
157
|
+
"backup.exports.status.QUEUED": "En cola",
|
|
158
|
+
"backup.exports.status.RUNNING": "En progreso",
|
|
159
|
+
"backup.exports.status.DONE": "Listo",
|
|
160
|
+
"backup.exports.status.DONE_NOTIFIED": "Listo",
|
|
161
|
+
"backup.exports.status.FAILED": "Fallido",
|
|
162
|
+
"backup.exports.status.EXPIRED": "Expirado",
|
|
163
|
+
"backup.exports.status.CANCELLED": "Cancelado",
|
|
164
|
+
};
|
|
165
|
+
const fr = {
|
|
166
|
+
"backup.common.module_name": "Exportations",
|
|
167
|
+
"backup.common.loading": "Chargement...",
|
|
168
|
+
"backup.common.actions": "Actions",
|
|
169
|
+
"backup.common.cancel": "Annuler",
|
|
170
|
+
"backup.common.confirm": "Confirmer",
|
|
171
|
+
"backup.common.server_connection_error": "Erreur de connexion au serveur",
|
|
172
|
+
"backup.exports.list.title": "Exportations de donnees",
|
|
173
|
+
"backup.exports.list.description": "Creez et gerez les jobs d exportation des donnees du tenant.",
|
|
174
|
+
"backup.exports.list.new": "Nouvelle exportation",
|
|
175
|
+
"backup.exports.list.empty": "Aucun job d exportation trouve.",
|
|
176
|
+
"backup.exports.list.action.download": "Telecharger",
|
|
177
|
+
"backup.exports.list.action.delete": "Supprimer",
|
|
178
|
+
"backup.exports.list.action.cancel": "Annuler",
|
|
179
|
+
"backup.exports.list.delete_title": "Supprimer l exportation",
|
|
180
|
+
"backup.exports.list.delete_message": "Supprimer ou annuler le job d exportation selectionne ?",
|
|
181
|
+
"backup.exports.list.delete_success": "Job d exportation supprime avec succes.",
|
|
182
|
+
"backup.exports.list.delete_error": "Impossible de supprimer le job d exportation.",
|
|
183
|
+
"backup.exports.create.title": "Nouvelle exportation",
|
|
184
|
+
"backup.exports.create.submit": "Demarrer l exportation",
|
|
185
|
+
"backup.exports.create.success": "Job d exportation cree avec succes.",
|
|
186
|
+
"backup.exports.create.error": "Impossible de creer le job d exportation.",
|
|
187
|
+
"backup.exports.status.REQUESTED": "Demande",
|
|
188
|
+
"backup.exports.status.QUEUED": "En attente",
|
|
189
|
+
"backup.exports.status.RUNNING": "En cours",
|
|
190
|
+
"backup.exports.status.DONE": "Pret",
|
|
191
|
+
"backup.exports.status.DONE_NOTIFIED": "Pret",
|
|
192
|
+
"backup.exports.status.FAILED": "Echoue",
|
|
193
|
+
"backup.exports.status.EXPIRED": "Expire",
|
|
194
|
+
"backup.exports.status.CANCELLED": "Annule",
|
|
195
|
+
};
|
|
196
|
+
export const backupMessages = {
|
|
197
|
+
en,
|
|
198
|
+
es: { ...en, ...es },
|
|
199
|
+
fr: { ...en, ...fr },
|
|
200
|
+
"pt-BR": { ...en, ...ptBr },
|
|
201
|
+
"pt-PT": { ...en, ...ptBr, ...ptPt },
|
|
202
|
+
};
|
package/dist/module.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAkBnE,eAAO,MAAM,MAAM,EAAE,yBAMpB,CAAC"}
|
package/dist/module.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Reference-adjacent implementation of the manifest read by the SeedGrid CLI
|
|
2
|
+
// (Rust). See seedgrid-cli/docs/adr/0004-module-manifest-contract.md.
|
|
3
|
+
//
|
|
4
|
+
// `messages` is filled in because `backupMessages` was a pure object (zero
|
|
5
|
+
// `@/...` import) in the old CLI template and got promoted to lib as-is —
|
|
6
|
+
// see scaffold/README.md.
|
|
7
|
+
//
|
|
8
|
+
// `navigation` uses the scaffold-local hook via `@/modules/backup` — the
|
|
9
|
+
// wiring is plain string substitution into the app-shell-navigation markers,
|
|
10
|
+
// so a scaffold alias is fine even though `useBackupAppShellSections`
|
|
11
|
+
// hardcodes a scaffold route and calls `@/modules/security`/`@/i18n`. Same
|
|
12
|
+
// mechanism as fe-security's `navigation`. Without it the CLI never wires the
|
|
13
|
+
// backup menu into the app shell.
|
|
14
|
+
//
|
|
15
|
+
// No `provider` here: unlike fe-subdomain-tenancy's `TenantProvider`, this
|
|
16
|
+
// module has no standalone React context to wrap the app with.
|
|
17
|
+
export const module = {
|
|
18
|
+
id: "backup",
|
|
19
|
+
requires: ["security"],
|
|
20
|
+
configKey: "backup",
|
|
21
|
+
navigation: { import: "useBackupAppShellSections", from: "@/modules/backup" },
|
|
22
|
+
messages: { import: "backupMessages", from: "@seedgrid/fe-backup" },
|
|
23
|
+
};
|
package/dist/module.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "backup",
|
|
3
|
+
"requires": [
|
|
4
|
+
"security"
|
|
5
|
+
],
|
|
6
|
+
"configKey": "backup",
|
|
7
|
+
"navigation": {
|
|
8
|
+
"import": "useBackupAppShellSections",
|
|
9
|
+
"from": "@/modules/backup"
|
|
10
|
+
},
|
|
11
|
+
"messages": {
|
|
12
|
+
"import": "backupMessages",
|
|
13
|
+
"from": "@seedgrid/fe-backup"
|
|
14
|
+
}
|
|
15
|
+
}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const BackupPaths: {
|
|
2
|
+
/** POST cria export · GET lista exports. */
|
|
3
|
+
readonly exports: "/exports";
|
|
4
|
+
/** GET status · DELETE remove. */
|
|
5
|
+
readonly byId: (jobId: string) => string;
|
|
6
|
+
/** GET download (application/zip). */
|
|
7
|
+
readonly download: (jobId: string) => string;
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,WAAW;IACtB,4CAA4C;;IAE5C,kCAAkC;2BACpB,MAAM;IACpB,sCAAsC;+BACpB,MAAM;CAChB,CAAC"}
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Paths do backup/export (espelho de RestControllerPath.java em seedgrid-quarkus-ext-backup).
|
|
2
|
+
// A extensão monta em /exports; o prefixo final depende de como o app inclui a extensão.
|
|
3
|
+
const seg = (value) => encodeURIComponent(value);
|
|
4
|
+
export const BackupPaths = {
|
|
5
|
+
/** POST cria export · GET lista exports. */
|
|
6
|
+
exports: "/exports",
|
|
7
|
+
/** GET status · DELETE remove. */
|
|
8
|
+
byId: (jobId) => `/exports/${seg(jobId)}`,
|
|
9
|
+
/** GET download (application/zip). */
|
|
10
|
+
download: (jobId) => `/exports/${seg(jobId)}/download`,
|
|
11
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { SecurityServer } from "@seedgrid/fe-security";
|
|
2
|
+
import type { ExportRequest, ExportResponse } from "../backup";
|
|
3
|
+
export interface BackupServer {
|
|
4
|
+
/** Cria um export job (POST /exports). */
|
|
5
|
+
createExport(req: ExportRequest): Promise<ExportResponse>;
|
|
6
|
+
/** Lista os export jobs (GET /exports). */
|
|
7
|
+
listExports(): Promise<ExportResponse[]>;
|
|
8
|
+
/** Status de um job — pra polling até DONE (GET /exports/{jobId}). */
|
|
9
|
+
getExportStatus(jobId: string): Promise<ExportResponse>;
|
|
10
|
+
/** Remove um job (DELETE /exports/{jobId}). */
|
|
11
|
+
deleteExport(jobId: string): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Baixa o zip (GET /exports/{jobId}/download). Devolve o Response CRU — o route
|
|
14
|
+
* handler do app faz o stream pro browser (apiFetchSecurity faria .json()).
|
|
15
|
+
*/
|
|
16
|
+
downloadExport(jobId: string): Promise<Response>;
|
|
17
|
+
}
|
|
18
|
+
export declare function createBackupServer(session: SecurityServer): BackupServer;
|
|
19
|
+
//# sourceMappingURL=create-backup-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-backup-server.d.ts","sourceRoot":"","sources":["../../src/server/create-backup-server.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE/D,MAAM,WAAW,YAAY;IAC3B,0CAA0C;IAC1C,YAAY,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC1D,2CAA2C;IAC3C,WAAW,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IACzC,sEAAsE;IACtE,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACxD,+CAA+C;IAC/C,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C;;;OAGG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAClD;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,YAAY,CAkBxE"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Helpers server-side de backup, sobre o motor de sessão do fe-security. SERVER-ONLY.
|
|
2
|
+
//
|
|
3
|
+
// const session = createSecurityServer({ ... });
|
|
4
|
+
// export const backup = createBackupServer(session);
|
|
5
|
+
import { BackupPaths } from "../paths";
|
|
6
|
+
export function createBackupServer(session) {
|
|
7
|
+
return {
|
|
8
|
+
createExport: (req) => session.apiFetchSecurity(BackupPaths.exports, {
|
|
9
|
+
method: "POST",
|
|
10
|
+
body: JSON.stringify(req),
|
|
11
|
+
}),
|
|
12
|
+
listExports: () => session.apiFetchSecurity(BackupPaths.exports),
|
|
13
|
+
getExportStatus: (jobId) => session.apiFetchSecurity(BackupPaths.byId(jobId)),
|
|
14
|
+
deleteExport: (jobId) => session.apiFetchSecurity(BackupPaths.byId(jobId), {
|
|
15
|
+
method: "DELETE",
|
|
16
|
+
}),
|
|
17
|
+
downloadExport: (jobId) => session.fetchWithSession(BackupPaths.download(jobId)),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,kBAAkB,EAClB,KAAK,YAAY,GAClB,MAAM,wBAAwB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@seedgrid/fe-backup",
|
|
3
|
+
"version": "2026.7.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/SeedGrid/seedgrid-fe-components.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/SeedGrid/seedgrid-fe-components",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/SeedGrid/seedgrid-fe-components/issues"
|
|
14
|
+
},
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"default": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./server": {
|
|
21
|
+
"types": "./dist/server/index.d.ts",
|
|
22
|
+
"default": "./dist/server/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"scaffold"
|
|
28
|
+
],
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"@seedgrid/fe-core": "*",
|
|
31
|
+
"@seedgrid/fe-security": "*"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@seedgrid/fe-core": "2026.7.1",
|
|
35
|
+
"@seedgrid/fe-security": "2026.7.2"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc -p tsconfig.json",
|
|
39
|
+
"postbuild": "node scripts/emit-module-manifest.mjs",
|
|
40
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
41
|
+
"test": "pnpm run build && node --test tests/module-manifest.test.mjs tests/export-status.test.mjs"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# `fe-backup` scaffold
|
|
2
|
+
|
|
3
|
+
Conteúdo copiado para dentro do app gerado pelo CLI (git do app, editável à
|
|
4
|
+
vontade — ver `seedgrid-cli/docs/adr/0004-module-manifest-contract.md`).
|
|
5
|
+
Extraído de `seedgrid-cli/templates/modules/backup/` (17 arquivos, todos sem
|
|
6
|
+
`{{...}}` real — nenhum ficou `.hbs`).
|
|
7
|
+
|
|
8
|
+
Mesmo critério lib vs scaffold do `fe-security`/`fe-subdomain-tenancy`:
|
|
9
|
+
import `@/...` real = scaffold; puro ou só-default-trivial = lib.
|
|
10
|
+
|
|
11
|
+
## Promovido pra `@seedgrid/fe-backup` (lib)
|
|
12
|
+
|
|
13
|
+
- `messages.ts` (`backupMessages`) — puro, zero import `@/...`.
|
|
14
|
+
- `export-status.ts` (`classifyExportStatus`, `isExportInProgress`,
|
|
15
|
+
`isExportDownloadable`, `ExportStatusGroup`) — puro, opera só sobre o
|
|
16
|
+
`ExportStatus` já em `backup.ts`.
|
|
17
|
+
|
|
18
|
+
## Corrigido: `BackupFormat`/`ArtifactInfo` (lib) estavam errados
|
|
19
|
+
|
|
20
|
+
Conferido contra o backend real
|
|
21
|
+
(`seedgrid-quarkus-ext-backup/runtime/.../domains/{BackupFormat,ExportScope,ExportStatus}.java`,
|
|
22
|
+
`dtos/ExportResponse.java`):
|
|
23
|
+
|
|
24
|
+
- `BackupFormat` em `backup.ts` tinha 8 valores fictícios
|
|
25
|
+
(`CSV`, `CSV_ZIP`, `ETL`, `GDPR`, `LGPD`, `SQL`, `SQL_DUMP_ZIP`, `ZIP`) — o
|
|
26
|
+
enum real só tem **2**: `CSV_ZIP`, `SQL_DUMP_ZIP`. Corrigido.
|
|
27
|
+
- `ArtifactInfo.id` era `string` — o DTO real (`ExportResponse.ArtifactInfo.id`)
|
|
28
|
+
é `Long` → `number`. Corrigido.
|
|
29
|
+
- `ExportScope` (`DOMAIN`/`RAW`/`CUSTOM`) e `ExportStatus` (8 valores) já
|
|
30
|
+
batiam certinho com o backend, não precisaram de ajuste.
|
|
31
|
+
|
|
32
|
+
Antes dessa correção, o scaffold (extraído dos templates do CLI, que sempre
|
|
33
|
+
usaram só os 2 formatos reais) tinha sua PRÓPRIA cópia local de
|
|
34
|
+
`BackupFormat`/`ArtifactInfo` porque divergia da lib. Depois da correção os
|
|
35
|
+
dois batem, então `scaffold/src/modules/backup/types.ts` virou um simples
|
|
36
|
+
reexport de `@seedgrid/fe-backup` (`ArtifactInfo`, `BackupFormat`,
|
|
37
|
+
`ExportRequest`, `ExportResponse`, `ExportScope`, `ExportStatus`) — nada
|
|
38
|
+
redeclarado.
|
|
39
|
+
|
|
40
|
+
## Ficou scaffold
|
|
41
|
+
|
|
42
|
+
- `app/backup/exports/(list)/page.tsx` (+ teste), `app/backup/exports/(create)/new/page.tsx`
|
|
43
|
+
(+ teste) — telas concretas.
|
|
44
|
+
- `app/api/backup/exports/[jobId]/download/route.ts` — route handler: por
|
|
45
|
+
natureza sempre scaffold (Next.js exige o arquivo num path físico
|
|
46
|
+
específico).
|
|
47
|
+
- `modules/backup/config.ts` — `backupConfig.apiBaseUrl`/`routes`/`polling`
|
|
48
|
+
são acoplados ao app (rotas concretas, polling interval).
|
|
49
|
+
- `modules/backup/services/{backup-api,backup-service}.ts` (+ testes) —
|
|
50
|
+
`backup-api.ts` usa `backupConfig.apiBaseUrl` (local) e `@/i18n` (1 chave
|
|
51
|
+
de fallback, mesmo padrão do `security-api.ts` do fe-security); `backup-service.ts`
|
|
52
|
+
depende de `backup-api.ts`, então segue a mesma cadeia pra scaffold.
|
|
53
|
+
- `modules/backup/components/ExportStatusBadge.tsx` (+ teste) — usa
|
|
54
|
+
`useI18n()` direto dentro do componente (chama `t(key)` internamente, ao
|
|
55
|
+
contrário do `StatusBadge` do fe-security que recebe `label` já traduzido
|
|
56
|
+
via prop). Daria pra decopiar do mesmo jeito, mas não foi feito nesta
|
|
57
|
+
passada — ver Follow-ups.
|
|
58
|
+
- `modules/backup/useBackupAppShellSections.tsx` (+ teste) — hardcoda rota
|
|
59
|
+
concreta (`backupConfig.routes.exports`) e usa `usePermission`/`@/i18n`.
|
|
60
|
+
|
|
61
|
+
## Follow-ups (fora do escopo desta extração)
|
|
62
|
+
|
|
63
|
+
- `ExportStatusBadge` poderia virar lib trocando `t(key)` interno por um
|
|
64
|
+
prop `label: string` (mesmo padrão do `StatusBadge` do fe-security) — não
|
|
65
|
+
fiz por tempo, mas é uma decoupling trivial se algum dia fizer falta.
|
|
66
|
+
- `backup-api.ts`/`backup-service.ts` têm o mesmo tipo de acoplamento que
|
|
67
|
+
`security-api.ts`/`security-service.ts` do fe-security (`apiBaseUrl` local
|
|
68
|
+
+ 1 chamada de tradução) — mesma ressalva: promover exigiria injeção de
|
|
69
|
+
config, redesenho deliberado, não mecânico.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// seedgrid:managed
|
|
2
|
+
|
|
3
|
+
import { type NextRequest, NextResponse } from "next/server";
|
|
4
|
+
|
|
5
|
+
import { appEnvironment } from "@/config/environment";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* GET /api/backup/exports/[jobId]/download
|
|
9
|
+
*
|
|
10
|
+
* Server-side proxy that forwards the download request to the backend
|
|
11
|
+
* with the user's authorization token from the session cookie.
|
|
12
|
+
* Returns the ZIP file stream directly to the browser.
|
|
13
|
+
*/
|
|
14
|
+
export async function GET(
|
|
15
|
+
request: NextRequest,
|
|
16
|
+
context: { params: Promise<{ jobId: string }> }
|
|
17
|
+
) {
|
|
18
|
+
const { jobId } = await context.params;
|
|
19
|
+
const decodedJobId = decodeURIComponent(jobId);
|
|
20
|
+
|
|
21
|
+
const authHeader = request.headers.get("authorization");
|
|
22
|
+
const cookieHeader = request.headers.get("cookie");
|
|
23
|
+
|
|
24
|
+
const backendUrl = `${appEnvironment.hosts.apiOrigin}/exports/${encodeURIComponent(decodedJobId)}/download`;
|
|
25
|
+
|
|
26
|
+
const headers: HeadersInit = {
|
|
27
|
+
Accept: "application/zip, application/octet-stream",
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
if (authHeader) {
|
|
31
|
+
headers["Authorization"] = authHeader;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (cookieHeader) {
|
|
35
|
+
headers["Cookie"] = cookieHeader;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
const upstream = await fetch(backendUrl, {
|
|
40
|
+
method: "GET",
|
|
41
|
+
headers,
|
|
42
|
+
cache: "no-store",
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if (!upstream.ok) {
|
|
46
|
+
if (upstream.status === 404) {
|
|
47
|
+
return NextResponse.json(
|
|
48
|
+
{ message: "Export not found or not ready" },
|
|
49
|
+
{ status: 404 }
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (upstream.status === 410) {
|
|
54
|
+
return NextResponse.json(
|
|
55
|
+
{ message: "Export expired or failed" },
|
|
56
|
+
{ status: 410 }
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return NextResponse.json(
|
|
61
|
+
{ message: "Failed to download export" },
|
|
62
|
+
{ status: upstream.status }
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const contentDisposition =
|
|
67
|
+
upstream.headers.get("Content-Disposition") ??
|
|
68
|
+
`attachment; filename="export-${decodedJobId}.zip"`;
|
|
69
|
+
|
|
70
|
+
const contentType =
|
|
71
|
+
upstream.headers.get("Content-Type") ?? "application/zip";
|
|
72
|
+
|
|
73
|
+
return new NextResponse(upstream.body, {
|
|
74
|
+
status: 200,
|
|
75
|
+
headers: {
|
|
76
|
+
"Content-Disposition": contentDisposition,
|
|
77
|
+
"Content-Type": contentType,
|
|
78
|
+
"Cache-Control": "no-store",
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
} catch {
|
|
82
|
+
return NextResponse.json(
|
|
83
|
+
{ message: "Could not reach the export service" },
|
|
84
|
+
{ status: 502 }
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|