@kaikybrofc/omnizap-system 2.1.8
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/.env.example +534 -0
- package/LICENSE +21 -0
- package/README.md +431 -0
- package/RELEASE-v2.1.2.md +83 -0
- package/app/config/adminIdentity.js +87 -0
- package/app/config/baileysConfig.js +693 -0
- package/app/config/groupUtils.js +388 -0
- package/app/connection/socketController.js +992 -0
- package/app/controllers/messageController.js +354 -0
- package/app/modules/adminModule/groupCommandHandlers.js +1294 -0
- package/app/modules/adminModule/groupEventHandlers.js +355 -0
- package/app/modules/aiModule/catCommand.js +1006 -0
- package/app/modules/broadcastModule/noticeCommand.js +416 -0
- package/app/modules/gameModule/diceCommand.js +67 -0
- package/app/modules/menuModule/common.js +311 -0
- package/app/modules/menuModule/menus.js +59 -0
- package/app/modules/playModule/playCommand.js +1615 -0
- package/app/modules/quoteModule/quoteCommand.js +851 -0
- package/app/modules/rpgPokemonModule/rpgBattleCanvasRenderer.js +786 -0
- package/app/modules/rpgPokemonModule/rpgBattleService.js +2082 -0
- package/app/modules/rpgPokemonModule/rpgBattleService.test.js +760 -0
- package/app/modules/rpgPokemonModule/rpgEvolutionUtils.js +22 -0
- package/app/modules/rpgPokemonModule/rpgPokemonCommand.js +172 -0
- package/app/modules/rpgPokemonModule/rpgPokemonDomain.js +192 -0
- package/app/modules/rpgPokemonModule/rpgPokemonDomain.test.js +93 -0
- package/app/modules/rpgPokemonModule/rpgPokemonEvolution.test.js +46 -0
- package/app/modules/rpgPokemonModule/rpgPokemonMessages.js +746 -0
- package/app/modules/rpgPokemonModule/rpgPokemonRepository.js +1859 -0
- package/app/modules/rpgPokemonModule/rpgPokemonService.js +6738 -0
- package/app/modules/rpgPokemonModule/rpgProfileCanvasRenderer.js +354 -0
- package/app/modules/statsModule/globalRankingCommand.js +65 -0
- package/app/modules/statsModule/noMessageCommand.js +288 -0
- package/app/modules/statsModule/rankingCommand.js +60 -0
- package/app/modules/statsModule/rankingCommon.js +889 -0
- package/app/modules/stickerModule/addStickerMetadata.js +239 -0
- package/app/modules/stickerModule/convertToWebp.js +390 -0
- package/app/modules/stickerModule/stickerCommand.js +454 -0
- package/app/modules/stickerModule/stickerConvertCommand.js +156 -0
- package/app/modules/stickerModule/stickerTextCommand.js +657 -0
- package/app/modules/stickerPackModule/autoPackCollectorRuntime.js +20 -0
- package/app/modules/stickerPackModule/autoPackCollectorService.js +284 -0
- package/app/modules/stickerPackModule/semanticReclassificationEngine.js +466 -0
- package/app/modules/stickerPackModule/semanticReclassificationEngine.test.js +88 -0
- package/app/modules/stickerPackModule/semanticThemeClusterService.js +571 -0
- package/app/modules/stickerPackModule/stickerAssetClassificationRepository.js +449 -0
- package/app/modules/stickerPackModule/stickerAssetRepository.js +400 -0
- package/app/modules/stickerPackModule/stickerAssetReprocessQueueRepository.js +180 -0
- package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +4078 -0
- package/app/modules/stickerPackModule/stickerClassificationBackgroundRuntime.js +598 -0
- package/app/modules/stickerPackModule/stickerClassificationService.js +588 -0
- package/app/modules/stickerPackModule/stickerMarketplaceDriftService.js +102 -0
- package/app/modules/stickerPackModule/stickerPackCatalogHttp.js +7506 -0
- package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +1095 -0
- package/app/modules/stickerPackModule/stickerPackEngagementRepository.js +108 -0
- package/app/modules/stickerPackModule/stickerPackErrors.js +30 -0
- package/app/modules/stickerPackModule/stickerPackInteractionEventRepository.js +110 -0
- package/app/modules/stickerPackModule/stickerPackItemRepository.js +440 -0
- package/app/modules/stickerPackModule/stickerPackMarketplaceService.js +337 -0
- package/app/modules/stickerPackModule/stickerPackMessageService.js +296 -0
- package/app/modules/stickerPackModule/stickerPackRepository.js +442 -0
- package/app/modules/stickerPackModule/stickerPackService.js +788 -0
- package/app/modules/stickerPackModule/stickerPackServiceRuntime.js +51 -0
- package/app/modules/stickerPackModule/stickerPackUtils.js +97 -0
- package/app/modules/stickerPackModule/stickerStorageService.js +507 -0
- package/app/modules/stickerPackModule/stickerWorkerPipelineRuntime.js +233 -0
- package/app/modules/stickerPackModule/stickerWorkerTaskQueueRepository.js +205 -0
- package/app/modules/systemMetricsModule/pingCommand.js +421 -0
- package/app/modules/tiktokModule/tiktokCommand.js +798 -0
- package/app/modules/userModule/userCommand.js +1217 -0
- package/app/modules/waifuPicsModule/waifuPicsCommand.js +177 -0
- package/app/observability/metrics.js +734 -0
- package/app/services/captchaService.js +492 -0
- package/app/services/dbWriteQueue.js +572 -0
- package/app/services/groupMetadataService.js +279 -0
- package/app/services/lidMapService.js +663 -0
- package/app/services/messagePersistenceService.js +56 -0
- package/app/services/newsBroadcastService.js +351 -0
- package/app/services/pokeApiService.js +398 -0
- package/app/services/queueUtils.js +57 -0
- package/app/services/socketState.js +7 -0
- package/app/store/aiPromptStore.js +38 -0
- package/app/store/groupConfigStore.js +58 -0
- package/app/store/premiumUserStore.js +36 -0
- package/app/utils/antiLink/antiLinkModule.js +804 -0
- package/app/utils/http/getImageBufferModule.js +18 -0
- package/app/utils/json/jsonSanitizer.js +113 -0
- package/app/utils/json/jsonSanitizer.test.js +40 -0
- package/app/utils/logger/loggerModule.js +262 -0
- package/app/utils/systemMetrics/systemMetricsModule.js +91 -0
- package/database/index.js +2052 -0
- package/database/init.js +516 -0
- package/database/migrations/20260203_0001_sticker_packs.sql +54 -0
- package/database/migrations/20260210_0003_rpg_pokemon.sql +58 -0
- package/database/migrations/20260210_0004_rpg_shiny_biome.sql +9 -0
- package/database/migrations/20260210_0005_rpg_missions.sql +14 -0
- package/database/migrations/20260210_0006_rpg_world_pokedex_traits.sql +27 -0
- package/database/migrations/20260210_0007_rpg_raid_pvp.sql +56 -0
- package/database/migrations/20260210_0008_rpg_social_system.sql +195 -0
- package/database/migrations/20260211_0009_rpg_social_xp.sql +36 -0
- package/database/migrations/20260222_0010_remove_message_xp.sql +2 -0
- package/database/migrations/20260226_0011_sticker_asset_classification.sql +17 -0
- package/database/migrations/20260226_0012_sticker_pack_engagement.sql +16 -0
- package/database/migrations/20260226_0013_sticker_marketplace_intelligence.sql +19 -0
- package/database/migrations/20260226_0014_sticker_pack_publish_flow.sql +30 -0
- package/database/migrations/20260226_0014_sticker_worker_queues.sql +42 -0
- package/database/migrations/20260226_0015_sticker_auto_pack_curation_integrity.sql +18 -0
- package/database/migrations/20260226_0016_sticker_web_google_auth_persistence.sql +34 -0
- package/database/migrations/20260226_0017_sticker_web_admin_ban.sql +22 -0
- package/database/migrations/20260226_0018_sticker_web_admin_moderator.sql +18 -0
- package/database/migrations/20260227_0019_sticker_classification_v2_signals.sql +12 -0
- package/database/migrations/20260227_0020_semantic_theme_clusters.sql +35 -0
- package/docker-compose.yml +103 -0
- package/ecosystem.prod.config.cjs +35 -0
- package/eslint.config.js +61 -0
- package/index.js +437 -0
- package/ml/clip_classifier/Dockerfile +16 -0
- package/ml/clip_classifier/README.md +120 -0
- package/ml/clip_classifier/adaptive_scoring.py +40 -0
- package/ml/clip_classifier/classifier.py +654 -0
- package/ml/clip_classifier/embedding_store.py +481 -0
- package/ml/clip_classifier/env_loader.py +15 -0
- package/ml/clip_classifier/llm_label_expander.py +144 -0
- package/ml/clip_classifier/main.py +213 -0
- package/ml/clip_classifier/requirements.txt +10 -0
- package/ml/clip_classifier/similarity_engine.py +74 -0
- package/observability/alert-rules.yml +60 -0
- package/observability/grafana/dashboards/omnizap-mysql.json +136 -0
- package/observability/grafana/dashboards/omnizap-overview.json +170 -0
- package/observability/grafana/provisioning/dashboards/dashboards.yml +11 -0
- package/observability/grafana/provisioning/datasources/datasources.yml +15 -0
- package/observability/loki-config.yml +38 -0
- package/observability/mysql-exporter.cnf +5 -0
- package/observability/mysql-setup.sql +46 -0
- package/observability/prometheus.yml +32 -0
- package/observability/promtail-config.yml +84 -0
- package/package.json +109 -0
- package/public/api-docs/index.html +144 -0
- package/public/css/github-project-panel.css +297 -0
- package/public/css/stickers-admin.css +1272 -0
- package/public/css/styles.css +671 -0
- package/public/index.html +1311 -0
- package/public/js/apps/apiDocsApp.js +310 -0
- package/public/js/apps/createPackApp.js +2069 -0
- package/public/js/apps/homeApp.js +396 -0
- package/public/js/apps/stickersAdminApp.js +1744 -0
- package/public/js/apps/stickersApp.js +4830 -0
- package/public/js/catalog.js +1019 -0
- package/public/js/github-panel/components/CommitList.js +34 -0
- package/public/js/github-panel/components/ErrorState.js +16 -0
- package/public/js/github-panel/components/GithubProjectPanel.js +106 -0
- package/public/js/github-panel/components/ReleaseList.js +38 -0
- package/public/js/github-panel/components/SkeletonPanel.js +22 -0
- package/public/js/github-panel/components/StatCard.js +15 -0
- package/public/js/github-panel/index.js +15 -0
- package/public/js/github-panel/useGithubRepoData.js +154 -0
- package/public/js/github-panel/vendor/react.js +11 -0
- package/public/js/runtime/react-runtime.js +19 -0
- package/public/licenca/index.html +106 -0
- package/public/stickers/admin/index.html +23 -0
- package/public/stickers/create/index.html +47 -0
- package/public/stickers/index.html +48 -0
- package/public/termos-de-uso/index.html +125 -0
- package/scripts/cache-bust.mjs +107 -0
- package/scripts/deploy.sh +458 -0
- package/scripts/github-deploy-notify.mjs +174 -0
- package/scripts/release.sh +129 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { React, memo } from '../vendor/react.js';
|
|
2
|
+
|
|
3
|
+
const h = React.createElement;
|
|
4
|
+
|
|
5
|
+
function CommitListComponent({ items, formatDate }) {
|
|
6
|
+
if (!Array.isArray(items) || items.length === 0) {
|
|
7
|
+
return h('div', { className: 'ghp-empty' }, 'Nenhum commit recente encontrado.');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return h(
|
|
11
|
+
'ul',
|
|
12
|
+
{ className: 'ghp-list', 'aria-label': 'Lista de commits recentes' },
|
|
13
|
+
...items.map((commit, index) =>
|
|
14
|
+
h(
|
|
15
|
+
'li',
|
|
16
|
+
{ key: (commit.sha || 'commit') + String(index), className: 'ghp-list-item' },
|
|
17
|
+
h(
|
|
18
|
+
'a',
|
|
19
|
+
{
|
|
20
|
+
href: commit.html_url || '#',
|
|
21
|
+
target: '_blank',
|
|
22
|
+
rel: 'noreferrer noopener',
|
|
23
|
+
className: 'ghp-list-link',
|
|
24
|
+
'aria-label': `Abrir commit ${commit.sha || ''} no GitHub`,
|
|
25
|
+
},
|
|
26
|
+
`${commit.sha || '---'} - ${commit.message || 'Sem mensagem'}`,
|
|
27
|
+
),
|
|
28
|
+
h('p', { className: 'ghp-list-meta' }, `${commit.author || 'autor desconhecido'} · ${formatDate(commit.date)}`),
|
|
29
|
+
),
|
|
30
|
+
),
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const CommitList = memo(CommitListComponent);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { React, memo } from '../vendor/react.js';
|
|
2
|
+
|
|
3
|
+
const h = React.createElement;
|
|
4
|
+
|
|
5
|
+
function ErrorStateComponent({ message, onRetry, isRateLimited }) {
|
|
6
|
+
return h(
|
|
7
|
+
'section',
|
|
8
|
+
{ className: 'ghp-error', role: 'alert' },
|
|
9
|
+
h('h3', null, 'Não foi possível carregar os dados do GitHub'),
|
|
10
|
+
h('p', null, message || 'Tente novamente em alguns instantes.'),
|
|
11
|
+
isRateLimited ? h('p', { className: 'ghp-rate-limit' }, 'Limite de requisições do GitHub atingido. Tente novamente em breve.') : null,
|
|
12
|
+
h('button', { type: 'button', className: 'ghp-retry', onClick: onRetry }, 'Tentar novamente'),
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const ErrorState = memo(ErrorStateComponent);
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { React, useMemo, useCallback } from '../vendor/react.js';
|
|
2
|
+
import { useGithubRepoData } from '../useGithubRepoData.js';
|
|
3
|
+
import { StatCard } from './StatCard.js';
|
|
4
|
+
import { CommitList } from './CommitList.js';
|
|
5
|
+
import { ReleaseList } from './ReleaseList.js';
|
|
6
|
+
import { SkeletonPanel } from './SkeletonPanel.js';
|
|
7
|
+
import { ErrorState } from './ErrorState.js';
|
|
8
|
+
|
|
9
|
+
const h = React.createElement;
|
|
10
|
+
|
|
11
|
+
const fmtDate = (value) => {
|
|
12
|
+
const time = Date.parse(String(value || ''));
|
|
13
|
+
if (!Number.isFinite(time)) return 'n/d';
|
|
14
|
+
return new Intl.DateTimeFormat('pt-BR', {
|
|
15
|
+
day: '2-digit',
|
|
16
|
+
month: '2-digit',
|
|
17
|
+
year: 'numeric',
|
|
18
|
+
hour: '2-digit',
|
|
19
|
+
minute: '2-digit',
|
|
20
|
+
}).format(new Date(time));
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const toInt = (value) => {
|
|
24
|
+
const parsed = Number(value);
|
|
25
|
+
return Number.isFinite(parsed) ? Math.round(parsed) : 0;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export function GithubProjectPanel({ owner, repo, endpoint }) {
|
|
29
|
+
const { data, loading, error, lastUpdatedAt, refresh } = useGithubRepoData({ owner, repo, endpoint });
|
|
30
|
+
|
|
31
|
+
const statCards = useMemo(() => {
|
|
32
|
+
if (!data) return [];
|
|
33
|
+
|
|
34
|
+
const languages = Array.isArray(data.languages) ? data.languages.map((entry) => entry.name).join(', ') : '';
|
|
35
|
+
|
|
36
|
+
return [
|
|
37
|
+
{ label: 'Repositório', value: data.repository || `${owner}/${repo}`, detail: data.description || 'Sem descrição.', iconClass: 'fa-brands fa-github' },
|
|
38
|
+
{ label: 'Stars', value: String(toInt(data.stars)), detail: 'Popularidade do projeto', iconClass: 'fa-solid fa-star' },
|
|
39
|
+
{ label: 'Forks', value: String(toInt(data.forks)), detail: 'Repositórios derivados', iconClass: 'fa-solid fa-code-fork' },
|
|
40
|
+
{ label: 'Issues abertas', value: String(toInt(data.open_issues)), detail: 'Demandas em aberto', iconClass: 'fa-solid fa-circle-exclamation' },
|
|
41
|
+
{ label: 'PRs abertos', value: String(toInt(data.open_prs)), detail: 'Mudanças em revisão', iconClass: 'fa-solid fa-code-pull-request' },
|
|
42
|
+
{ label: 'Linguagem principal', value: data.language || 'n/d', detail: languages || 'Sem linguagens mapeadas', iconClass: 'fa-solid fa-code' },
|
|
43
|
+
{ label: 'Licença', value: data.license || 'n/d', detail: 'Modelo de uso do projeto', iconClass: 'fa-solid fa-scale-balanced' },
|
|
44
|
+
{ label: 'Branch padrão', value: data.default_branch || 'n/d', detail: 'Base principal de desenvolvimento', iconClass: 'fa-solid fa-code-branch' },
|
|
45
|
+
{ label: 'Último push', value: fmtDate(data.pushed_at), detail: 'Atualização mais recente no repositório', iconClass: 'fa-solid fa-upload' },
|
|
46
|
+
{
|
|
47
|
+
label: 'Última release',
|
|
48
|
+
value: data.latest_release?.tag || data.latest_release?.name || 'Sem release',
|
|
49
|
+
detail: data.latest_release?.published_at ? fmtDate(data.latest_release.published_at) : 'Sem data de publicação',
|
|
50
|
+
iconClass: 'fa-solid fa-tag',
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
}, [data, owner, repo]);
|
|
54
|
+
|
|
55
|
+
const handleRetry = useCallback(() => {
|
|
56
|
+
refresh();
|
|
57
|
+
}, [refresh]);
|
|
58
|
+
|
|
59
|
+
if (loading && !data) {
|
|
60
|
+
return h(SkeletonPanel);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (error && !data) {
|
|
64
|
+
return h(ErrorState, {
|
|
65
|
+
message: error.message,
|
|
66
|
+
isRateLimited: Boolean(error.rateLimited),
|
|
67
|
+
onRetry: handleRetry,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return h(
|
|
72
|
+
'section',
|
|
73
|
+
{ className: 'ghp-panel' },
|
|
74
|
+
h(
|
|
75
|
+
'header',
|
|
76
|
+
{ className: 'ghp-header' },
|
|
77
|
+
h('h3', { className: 'ghp-title' }, 'Projeto no GitHub'),
|
|
78
|
+
h(
|
|
79
|
+
'div',
|
|
80
|
+
{ className: 'ghp-header-actions' },
|
|
81
|
+
h('span', { className: 'ghp-updated' }, `Atualizado: ${fmtDate(lastUpdatedAt)}`),
|
|
82
|
+
h(
|
|
83
|
+
'a',
|
|
84
|
+
{
|
|
85
|
+
href: data?.html_url || `https://github.com/${owner}/${repo}`,
|
|
86
|
+
target: '_blank',
|
|
87
|
+
rel: 'noreferrer noopener',
|
|
88
|
+
className: 'ghp-repo-link',
|
|
89
|
+
'aria-label': 'Abrir repositório no GitHub',
|
|
90
|
+
},
|
|
91
|
+
'Abrir repositório',
|
|
92
|
+
),
|
|
93
|
+
),
|
|
94
|
+
),
|
|
95
|
+
error
|
|
96
|
+
? h('p', { className: 'ghp-inline-warning', role: 'status' }, error.rateLimited ? 'Limite da API do GitHub atingido; exibindo cache local.' : 'Exibindo último snapshot disponível.')
|
|
97
|
+
: null,
|
|
98
|
+
h('div', { className: 'ghp-stat-grid' }, ...statCards.map((card) => h(StatCard, { key: card.label, ...card }))),
|
|
99
|
+
h(
|
|
100
|
+
'div',
|
|
101
|
+
{ className: 'ghp-list-grid' },
|
|
102
|
+
h('section', { className: 'ghp-list-card' }, h('h4', { className: 'ghp-list-title' }, 'Últimos Commits'), h(CommitList, { items: data?.latest_commits || [], formatDate: fmtDate })),
|
|
103
|
+
h('section', { className: 'ghp-list-card' }, h('h4', { className: 'ghp-list-title' }, 'Últimas Releases'), h(ReleaseList, { items: data?.latest_releases || [], formatDate: fmtDate })),
|
|
104
|
+
),
|
|
105
|
+
);
|
|
106
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { React, memo } from '../vendor/react.js';
|
|
2
|
+
|
|
3
|
+
const h = React.createElement;
|
|
4
|
+
|
|
5
|
+
function ReleaseListComponent({ items, formatDate }) {
|
|
6
|
+
if (!Array.isArray(items) || items.length === 0) {
|
|
7
|
+
return h('div', { className: 'ghp-empty' }, 'Nenhuma release publicada ainda.');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return h(
|
|
11
|
+
'ul',
|
|
12
|
+
{ className: 'ghp-list', 'aria-label': 'Lista de releases recentes' },
|
|
13
|
+
...items.map((release, index) => {
|
|
14
|
+
const flags = [release.prerelease ? 'pre-release' : '', release.draft ? 'draft' : ''].filter(Boolean).join(', ');
|
|
15
|
+
const releaseName = release.tag || release.name || 'release';
|
|
16
|
+
const label = flags ? `${releaseName} (${flags})` : releaseName;
|
|
17
|
+
|
|
18
|
+
return h(
|
|
19
|
+
'li',
|
|
20
|
+
{ key: label + String(index), className: 'ghp-list-item' },
|
|
21
|
+
h(
|
|
22
|
+
'a',
|
|
23
|
+
{
|
|
24
|
+
href: release.html_url || '#',
|
|
25
|
+
target: '_blank',
|
|
26
|
+
rel: 'noreferrer noopener',
|
|
27
|
+
className: 'ghp-list-link',
|
|
28
|
+
'aria-label': `Abrir release ${releaseName} no GitHub`,
|
|
29
|
+
},
|
|
30
|
+
label,
|
|
31
|
+
),
|
|
32
|
+
h('p', { className: 'ghp-list-meta' }, formatDate(release.published_at)),
|
|
33
|
+
);
|
|
34
|
+
}),
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const ReleaseList = memo(ReleaseListComponent);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { React, memo } from '../vendor/react.js';
|
|
2
|
+
|
|
3
|
+
const h = React.createElement;
|
|
4
|
+
|
|
5
|
+
function SkeletonPanelComponent() {
|
|
6
|
+
const statNodes = Array.from({ length: 10 }).map((_, index) => h('div', { key: `s-${index}`, className: 'ghp-skeleton-card' }));
|
|
7
|
+
const listNodes = Array.from({ length: 4 }).map((_, index) => h('li', { key: `l-${index}`, className: 'ghp-skeleton-line' }));
|
|
8
|
+
|
|
9
|
+
return h(
|
|
10
|
+
'section',
|
|
11
|
+
{ className: 'ghp-panel', 'aria-busy': 'true', 'aria-live': 'polite' },
|
|
12
|
+
h('div', { className: 'ghp-stat-grid' }, ...statNodes),
|
|
13
|
+
h(
|
|
14
|
+
'div',
|
|
15
|
+
{ className: 'ghp-list-grid' },
|
|
16
|
+
h('div', { className: 'ghp-list-card' }, h('div', { className: 'ghp-skeleton-title' }), h('ul', { className: 'ghp-list' }, ...listNodes)),
|
|
17
|
+
h('div', { className: 'ghp-list-card' }, h('div', { className: 'ghp-skeleton-title' }), h('ul', { className: 'ghp-list' }, ...listNodes)),
|
|
18
|
+
),
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const SkeletonPanel = memo(SkeletonPanelComponent);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { React, memo } from '../vendor/react.js';
|
|
2
|
+
|
|
3
|
+
const h = React.createElement;
|
|
4
|
+
|
|
5
|
+
function StatCardComponent({ label, value, detail, iconClass }) {
|
|
6
|
+
return h(
|
|
7
|
+
'article',
|
|
8
|
+
{ className: 'ghp-stat-card' },
|
|
9
|
+
h('header', { className: 'ghp-stat-head' }, h('span', { className: 'ghp-stat-label' }, label), iconClass ? h('i', { className: iconClass, 'aria-hidden': 'true' }) : null),
|
|
10
|
+
h('p', { className: 'ghp-stat-value' }, value),
|
|
11
|
+
h('p', { className: 'ghp-stat-detail', title: detail || '' }, detail || ' '),
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const StatCard = memo(StatCardComponent);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { React, createRoot } from './vendor/react.js';
|
|
2
|
+
import { GithubProjectPanel } from './components/GithubProjectPanel.js';
|
|
3
|
+
|
|
4
|
+
const h = React.createElement;
|
|
5
|
+
|
|
6
|
+
const rootEl = document.getElementById('github-project-panel-root');
|
|
7
|
+
|
|
8
|
+
if (rootEl) {
|
|
9
|
+
const owner = rootEl.dataset.owner || 'kaikybrofc';
|
|
10
|
+
const repo = rootEl.dataset.repo || 'omnizap-system';
|
|
11
|
+
const endpoint = rootEl.dataset.endpoint || '/api/sticker-packs/project-summary';
|
|
12
|
+
|
|
13
|
+
const root = createRoot(rootEl);
|
|
14
|
+
root.render(h(GithubProjectPanel, { owner, repo, endpoint }));
|
|
15
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from './vendor/react.js';
|
|
2
|
+
|
|
3
|
+
const CACHE_PREFIX = 'omnizap:github-summary:';
|
|
4
|
+
const DEFAULT_TTL_MS = 5 * 60 * 1000;
|
|
5
|
+
const RETRY_DELAY_MS = 900;
|
|
6
|
+
|
|
7
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
8
|
+
|
|
9
|
+
const toErrorObject = (error, statusCode = null, rateLimited = false) => ({
|
|
10
|
+
message: error?.message || 'Falha ao carregar dados do projeto.',
|
|
11
|
+
statusCode,
|
|
12
|
+
rateLimited,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export function useGithubRepoData({ owner, repo, endpoint = '/api/sticker-packs/project-summary', ttlMs = DEFAULT_TTL_MS }) {
|
|
16
|
+
const cacheKey = CACHE_PREFIX + String(owner || '') + '/' + String(repo || '');
|
|
17
|
+
const abortRef = useRef(null);
|
|
18
|
+
|
|
19
|
+
const [state, setState] = useState({
|
|
20
|
+
data: null,
|
|
21
|
+
loading: true,
|
|
22
|
+
error: null,
|
|
23
|
+
lastUpdatedAt: null,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const readCache = useCallback(() => {
|
|
27
|
+
try {
|
|
28
|
+
const raw = sessionStorage.getItem(cacheKey);
|
|
29
|
+
if (!raw) return null;
|
|
30
|
+
const parsed = JSON.parse(raw);
|
|
31
|
+
if (!parsed?.data || !parsed?.storedAt) return null;
|
|
32
|
+
return parsed;
|
|
33
|
+
} catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}, [cacheKey]);
|
|
37
|
+
|
|
38
|
+
const writeCache = useCallback(
|
|
39
|
+
(data) => {
|
|
40
|
+
try {
|
|
41
|
+
sessionStorage.setItem(
|
|
42
|
+
cacheKey,
|
|
43
|
+
JSON.stringify({
|
|
44
|
+
data,
|
|
45
|
+
storedAt: Date.now(),
|
|
46
|
+
}),
|
|
47
|
+
);
|
|
48
|
+
} catch {
|
|
49
|
+
// noop
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
[cacheKey],
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const fetchWithRetry = useCallback(async () => {
|
|
56
|
+
const doFetch = async () => {
|
|
57
|
+
if (abortRef.current) {
|
|
58
|
+
abortRef.current.abort();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const controller = new AbortController();
|
|
62
|
+
abortRef.current = controller;
|
|
63
|
+
|
|
64
|
+
const response = await fetch(endpoint, { signal: controller.signal });
|
|
65
|
+
const payload = await response.json().catch(() => ({}));
|
|
66
|
+
|
|
67
|
+
if (!response.ok) {
|
|
68
|
+
const error = new Error(payload?.error || 'Falha ao carregar dados do projeto.');
|
|
69
|
+
error.statusCode = response.status;
|
|
70
|
+
error.rateLimited = response.status === 429;
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return payload?.data || null;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
return await doFetch();
|
|
79
|
+
} catch (error) {
|
|
80
|
+
if (error?.name === 'AbortError') throw error;
|
|
81
|
+
const status = Number(error?.statusCode) || 0;
|
|
82
|
+
const retryable = status === 429 || status >= 500 || status === 0;
|
|
83
|
+
if (!retryable) throw error;
|
|
84
|
+
await sleep(RETRY_DELAY_MS);
|
|
85
|
+
return doFetch();
|
|
86
|
+
}
|
|
87
|
+
}, [endpoint]);
|
|
88
|
+
|
|
89
|
+
const refresh = useCallback(
|
|
90
|
+
async ({ silent = false } = {}) => {
|
|
91
|
+
if (!silent) {
|
|
92
|
+
setState((prev) => ({ ...prev, loading: true, error: null }));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
const data = await fetchWithRetry();
|
|
97
|
+
if (!data) {
|
|
98
|
+
throw new Error('Resposta vazia da API.');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
writeCache(data);
|
|
102
|
+
setState({
|
|
103
|
+
data,
|
|
104
|
+
loading: false,
|
|
105
|
+
error: null,
|
|
106
|
+
lastUpdatedAt: Date.now(),
|
|
107
|
+
});
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (error?.name === 'AbortError') return;
|
|
110
|
+
setState((prev) => ({
|
|
111
|
+
...prev,
|
|
112
|
+
loading: false,
|
|
113
|
+
error: toErrorObject(error, error?.statusCode || null, Boolean(error?.rateLimited)),
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
[fetchWithRetry, writeCache],
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
const cached = readCache();
|
|
122
|
+
const now = Date.now();
|
|
123
|
+
|
|
124
|
+
if (cached?.data) {
|
|
125
|
+
setState({
|
|
126
|
+
data: cached.data,
|
|
127
|
+
loading: false,
|
|
128
|
+
error: null,
|
|
129
|
+
lastUpdatedAt: Number(cached.storedAt) || now,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const isExpired = now - Number(cached.storedAt || 0) > ttlMs;
|
|
133
|
+
if (isExpired) {
|
|
134
|
+
refresh({ silent: true });
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
refresh();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return () => {
|
|
141
|
+
if (abortRef.current) {
|
|
142
|
+
abortRef.current.abort();
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}, [readCache, refresh, ttlMs]);
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
data: state.data,
|
|
149
|
+
loading: state.loading,
|
|
150
|
+
error: state.error,
|
|
151
|
+
lastUpdatedAt: state.lastUpdatedAt,
|
|
152
|
+
refresh,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { setup } from 'https://esm.sh/twind@0.16.19';
|
|
2
|
+
import { observe } from 'https://esm.sh/twind@0.16.19/observe';
|
|
3
|
+
|
|
4
|
+
if (typeof document !== 'undefined' && !window.__omnizapTwindReady) {
|
|
5
|
+
setup({ preflight: false });
|
|
6
|
+
observe(document.documentElement);
|
|
7
|
+
window.__omnizapTwindReady = true;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
default as React,
|
|
12
|
+
useEffect,
|
|
13
|
+
useMemo,
|
|
14
|
+
useRef,
|
|
15
|
+
useState,
|
|
16
|
+
memo,
|
|
17
|
+
} from 'https://esm.sh/react@18.3.1';
|
|
18
|
+
|
|
19
|
+
export { createRoot } from 'https://esm.sh/react-dom@18.3.1/client';
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="pt-BR">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>Licença | OmniZap System</title>
|
|
7
|
+
<meta name="description" content="Informações de licença do OmniZap System (MIT License)." />
|
|
8
|
+
<meta name="robots" content="index, follow" />
|
|
9
|
+
<link rel="canonical" href="https://omnizap.shop/licenca/" />
|
|
10
|
+
<link rel="icon" type="image/jpeg" href="https://iili.io/FC3FABe.jpg" />
|
|
11
|
+
<link rel="apple-touch-icon" href="https://iili.io/FC3FABe.jpg" />
|
|
12
|
+
<style>
|
|
13
|
+
:root {
|
|
14
|
+
--bg: #0b1020;
|
|
15
|
+
--bg-2: #121a2f;
|
|
16
|
+
--line: #2a3b60;
|
|
17
|
+
--text: #e6edf7;
|
|
18
|
+
--muted: #9fb0cc;
|
|
19
|
+
--card: #141e36cc;
|
|
20
|
+
}
|
|
21
|
+
* { box-sizing: border-box; }
|
|
22
|
+
body {
|
|
23
|
+
margin: 0;
|
|
24
|
+
font-family: "Manrope", system-ui, -apple-system, sans-serif;
|
|
25
|
+
color: var(--text);
|
|
26
|
+
background:
|
|
27
|
+
radial-gradient(58rem 24rem at -8% -12%, #22c55e26, transparent 60%),
|
|
28
|
+
radial-gradient(58rem 24rem at 112% -10%, #38bdf822, transparent 58%),
|
|
29
|
+
linear-gradient(165deg, var(--bg), var(--bg-2));
|
|
30
|
+
}
|
|
31
|
+
.wrap { width: min(960px, 92vw); margin: 0 auto; padding: 24px 0 42px; }
|
|
32
|
+
.top {
|
|
33
|
+
display: flex;
|
|
34
|
+
gap: 10px;
|
|
35
|
+
flex-wrap: wrap;
|
|
36
|
+
margin-bottom: 16px;
|
|
37
|
+
}
|
|
38
|
+
.top a {
|
|
39
|
+
color: var(--text);
|
|
40
|
+
text-decoration: none;
|
|
41
|
+
border: 1px solid var(--line);
|
|
42
|
+
border-radius: 10px;
|
|
43
|
+
padding: 8px 12px;
|
|
44
|
+
background: #111a2d;
|
|
45
|
+
}
|
|
46
|
+
.card {
|
|
47
|
+
border: 1px solid var(--line);
|
|
48
|
+
border-radius: 14px;
|
|
49
|
+
background: var(--card);
|
|
50
|
+
padding: 18px;
|
|
51
|
+
margin-bottom: 12px;
|
|
52
|
+
}
|
|
53
|
+
h1, h2 { margin: 0 0 10px; }
|
|
54
|
+
h1 { font-size: clamp(28px, 4.2vw, 38px); }
|
|
55
|
+
p { color: var(--muted); line-height: 1.6; margin: 0 0 10px; }
|
|
56
|
+
pre {
|
|
57
|
+
margin: 0;
|
|
58
|
+
white-space: pre-wrap;
|
|
59
|
+
line-height: 1.5;
|
|
60
|
+
color: #d6e4fa;
|
|
61
|
+
border: 1px solid #314669;
|
|
62
|
+
border-radius: 12px;
|
|
63
|
+
background: #0f1729;
|
|
64
|
+
padding: 14px;
|
|
65
|
+
overflow: auto;
|
|
66
|
+
}
|
|
67
|
+
</style>
|
|
68
|
+
</head>
|
|
69
|
+
<body>
|
|
70
|
+
<main class="wrap">
|
|
71
|
+
<nav class="top" aria-label="Navegação">
|
|
72
|
+
<a href="/">Início</a>
|
|
73
|
+
<a href="/stickers/">Stickers</a>
|
|
74
|
+
<a href="/api-docs/">API</a>
|
|
75
|
+
<a href="/termos-de-uso/">Termos de Uso</a>
|
|
76
|
+
</nav>
|
|
77
|
+
|
|
78
|
+
<section class="card">
|
|
79
|
+
<h1>Licença</h1>
|
|
80
|
+
<p>Este projeto é distribuído sob a licença MIT. Abaixo está o texto da licença usada no repositório.</p>
|
|
81
|
+
<p>Copyright (c) 2025 Kaiky Brito</p>
|
|
82
|
+
</section>
|
|
83
|
+
|
|
84
|
+
<section class="card">
|
|
85
|
+
<h2>MIT License (texto original)</h2>
|
|
86
|
+
<pre>Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
87
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
88
|
+
in the Software without restriction, including without limitation the rights
|
|
89
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
90
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
91
|
+
furnished to do so, subject to the following conditions:
|
|
92
|
+
|
|
93
|
+
The above copyright notice and this permission notice shall be included in all
|
|
94
|
+
copies or substantial portions of the Software.
|
|
95
|
+
|
|
96
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
97
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
98
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
99
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
100
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
101
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
102
|
+
SOFTWARE.</pre>
|
|
103
|
+
</section>
|
|
104
|
+
</main>
|
|
105
|
+
</body>
|
|
106
|
+
</html>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="pt-BR">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>OmniZap | Painel Admin</title>
|
|
7
|
+
<meta name="robots" content="noindex, nofollow" />
|
|
8
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
9
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
10
|
+
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
|
|
11
|
+
<link rel="stylesheet" href="/css/stickers-admin.css?v=20260226-admin-saas-redesign-v1" />
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<div
|
|
15
|
+
id="stickers-admin-root"
|
|
16
|
+
data-api-base-path="/api/sticker-packs"
|
|
17
|
+
data-web-path="/stickers"
|
|
18
|
+
data-admin-web-path="/stickers/admin"
|
|
19
|
+
></div>
|
|
20
|
+
|
|
21
|
+
<script type="module" src="/js/apps/stickersAdminApp.js?v=20260226-admin-moderators-v1"></script>
|
|
22
|
+
</body>
|
|
23
|
+
</html>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="pt-BR">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>OmniZap | Criar novo Pack</title>
|
|
7
|
+
<meta name="description" content="Crie um novo pack com fluxo visual passo a passo. Adicione stickers, escolha capa e publique no catálogo OmniZap." />
|
|
8
|
+
<meta name="robots" content="noindex, nofollow" />
|
|
9
|
+
<link rel="icon" type="image/jpeg" href="https://iili.io/FC3FABe.jpg" />
|
|
10
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
11
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
12
|
+
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=Sora:wght@500;600;700;800&display=swap" rel="stylesheet" />
|
|
13
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
14
|
+
<script>
|
|
15
|
+
tailwind.config = {
|
|
16
|
+
theme: {
|
|
17
|
+
extend: {
|
|
18
|
+
fontFamily: {
|
|
19
|
+
sans: ['Manrope', 'ui-sans-serif', 'system-ui'],
|
|
20
|
+
display: ['Sora', 'ui-sans-serif', 'system-ui']
|
|
21
|
+
},
|
|
22
|
+
colors: {
|
|
23
|
+
base: '#090d14',
|
|
24
|
+
panel: '#111722',
|
|
25
|
+
panelSoft: '#151f2d',
|
|
26
|
+
line: '#243042',
|
|
27
|
+
accent: '#2dd4bf',
|
|
28
|
+
accent2: '#34d399',
|
|
29
|
+
},
|
|
30
|
+
boxShadow: {
|
|
31
|
+
panel: '0 20px 40px rgba(0,0,0,.35)'
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
</script>
|
|
37
|
+
</head>
|
|
38
|
+
<body class="bg-base text-slate-100 min-h-screen">
|
|
39
|
+
<div
|
|
40
|
+
id="create-pack-react-root"
|
|
41
|
+
data-api-base-path="/api/sticker-packs"
|
|
42
|
+
data-web-path="/stickers"
|
|
43
|
+
></div>
|
|
44
|
+
|
|
45
|
+
<script type="module" src="/js/apps/createPackApp.js?v=20260226-create-pack-cta-open-created-pack1"></script>
|
|
46
|
+
</body>
|
|
47
|
+
</html>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="pt-BR">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>OmniZap Sticker Catalog</title>
|
|
7
|
+
<meta name="description" content="Catálogo de stickers e packs OmniZap em estilo app." />
|
|
8
|
+
<meta name="robots" content="index, follow" />
|
|
9
|
+
<link rel="canonical" href="https://omnizap.shop/stickers/" />
|
|
10
|
+
<link rel="icon" type="image/jpeg" href="https://iili.io/FC3FABe.jpg" />
|
|
11
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
12
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
13
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
|
|
14
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
15
|
+
<script>
|
|
16
|
+
tailwind.config = {
|
|
17
|
+
theme: {
|
|
18
|
+
extend: {
|
|
19
|
+
fontFamily: {
|
|
20
|
+
sans: ['Inter', 'ui-sans-serif', 'system-ui', 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji']
|
|
21
|
+
},
|
|
22
|
+
colors: {
|
|
23
|
+
slateApp: '#0f172a',
|
|
24
|
+
slateCard: '#111827',
|
|
25
|
+
borderApp: '#22304a',
|
|
26
|
+
accent: '#22c55e'
|
|
27
|
+
},
|
|
28
|
+
boxShadow: {
|
|
29
|
+
soft: '0 8px 24px rgba(2, 6, 23, 0.22)'
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
</script>
|
|
35
|
+
</head>
|
|
36
|
+
<body class="bg-slateApp text-slate-100 font-sans min-h-screen">
|
|
37
|
+
<div id="stickers-react-root"
|
|
38
|
+
data-web-path="/stickers"
|
|
39
|
+
data-api-base-path="/api/sticker-packs"
|
|
40
|
+
data-orphan-api-path="/api/sticker-packs/orphan-stickers"
|
|
41
|
+
data-default-limit="24"
|
|
42
|
+
data-default-orphan-limit="24"
|
|
43
|
+
data-initial-pack-key=""
|
|
44
|
+
></div>
|
|
45
|
+
|
|
46
|
+
<script type="module" src="/js/apps/stickersApp.js?v=20260227-ui-hotfix-v5"></script>
|
|
47
|
+
</body>
|
|
48
|
+
</html>
|