@things-factory/figure-service 10.1.3 โ 10.1.6
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/coverage/clover.xml +6 -0
- package/coverage/coverage-final.json +1 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +101 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov.info +0 -0
- package/dist-server/index.d.ts +2 -0
- package/dist-server/index.js +13 -0
- package/dist-server/index.js.map +1 -1
- package/dist-server/routers/figure-thumbnail-router.d.ts +24 -0
- package/dist-server/routers/figure-thumbnail-router.js +93 -0
- package/dist-server/routers/figure-thumbnail-router.js.map +1 -0
- package/dist-server/routes.d.ts +1 -0
- package/dist-server/routes.js +21 -0
- package/dist-server/routes.js.map +1 -0
- package/dist-server/service/figure/event-subscriber.d.ts +21 -0
- package/dist-server/service/figure/event-subscriber.js +51 -0
- package/dist-server/service/figure/event-subscriber.js.map +1 -0
- package/dist-server/service/figure/figure-gate.d.ts +55 -0
- package/dist-server/service/figure/figure-gate.js +64 -0
- package/dist-server/service/figure/figure-gate.js.map +1 -0
- package/dist-server/service/figure/figure-history.d.ts +43 -0
- package/dist-server/service/figure/figure-history.js +155 -0
- package/dist-server/service/figure/figure-history.js.map +1 -0
- package/dist-server/service/figure/figure-mutation.d.ts +45 -0
- package/dist-server/service/figure/figure-mutation.js +174 -1
- package/dist-server/service/figure/figure-mutation.js.map +1 -1
- package/dist-server/service/figure/figure-query.d.ts +24 -1
- package/dist-server/service/figure/figure-query.js +75 -0
- package/dist-server/service/figure/figure-query.js.map +1 -1
- package/dist-server/service/figure/figure-tools.d.ts +10 -0
- package/dist-server/service/figure/figure-tools.js +304 -0
- package/dist-server/service/figure/figure-tools.js.map +1 -0
- package/dist-server/service/figure/figure-type.d.ts +25 -1
- package/dist-server/service/figure/figure-type.js +58 -5
- package/dist-server/service/figure/figure-type.js.map +1 -1
- package/dist-server/service/figure/figure.d.ts +9 -0
- package/dist-server/service/figure/figure.js +15 -3
- package/dist-server/service/figure/figure.js.map +1 -1
- package/dist-server/service/figure/index.d.ts +4 -1
- package/dist-server/service/figure/index.js +5 -2
- package/dist-server/service/figure/index.js.map +1 -1
- package/dist-server/service/index.d.ts +6 -2
- package/dist-server/service/index.js +17 -2
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -0
- package/package.json +9 -6
- package/server/index.ts +13 -0
- package/server/routers/figure-thumbnail-router.ts +110 -0
- package/server/routes.ts +24 -0
- package/server/service/figure/event-subscriber.ts +49 -0
- package/server/service/figure/figure-gate.ts +119 -0
- package/server/service/figure/figure-history.ts +130 -0
- package/server/service/figure/figure-mutation.ts +180 -1
- package/server/service/figure/figure-propose.test.ts +136 -4
- package/server/service/figure/figure-query.ts +63 -1
- package/server/service/figure/figure-tools.test.ts +284 -0
- package/server/service/figure/figure-tools.ts +320 -0
- package/server/service/figure/figure-type.ts +49 -2
- package/server/service/figure/figure.ts +15 -3
- package/server/service/figure/index.ts +4 -1
- package/server/service/index.ts +23 -2
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
var addSorting = (function() {
|
|
3
|
+
'use strict';
|
|
4
|
+
var cols,
|
|
5
|
+
currentSort = {
|
|
6
|
+
index: 0,
|
|
7
|
+
desc: false
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// returns the summary table element
|
|
11
|
+
function getTable() {
|
|
12
|
+
return document.querySelector('.coverage-summary');
|
|
13
|
+
}
|
|
14
|
+
// returns the thead element of the summary table
|
|
15
|
+
function getTableHeader() {
|
|
16
|
+
return getTable().querySelector('thead tr');
|
|
17
|
+
}
|
|
18
|
+
// returns the tbody element of the summary table
|
|
19
|
+
function getTableBody() {
|
|
20
|
+
return getTable().querySelector('tbody');
|
|
21
|
+
}
|
|
22
|
+
// returns the th element for nth column
|
|
23
|
+
function getNthColumn(n) {
|
|
24
|
+
return getTableHeader().querySelectorAll('th')[n];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function onFilterInput() {
|
|
28
|
+
const searchValue = document.getElementById('fileSearch').value;
|
|
29
|
+
const rows = document.getElementsByTagName('tbody')[0].children;
|
|
30
|
+
|
|
31
|
+
// Try to create a RegExp from the searchValue. If it fails (invalid regex),
|
|
32
|
+
// it will be treated as a plain text search
|
|
33
|
+
let searchRegex;
|
|
34
|
+
try {
|
|
35
|
+
searchRegex = new RegExp(searchValue, 'i'); // 'i' for case-insensitive
|
|
36
|
+
} catch (error) {
|
|
37
|
+
searchRegex = null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
for (let i = 0; i < rows.length; i++) {
|
|
41
|
+
const row = rows[i];
|
|
42
|
+
let isMatch = false;
|
|
43
|
+
|
|
44
|
+
if (searchRegex) {
|
|
45
|
+
// If a valid regex was created, use it for matching
|
|
46
|
+
isMatch = searchRegex.test(row.textContent);
|
|
47
|
+
} else {
|
|
48
|
+
// Otherwise, fall back to the original plain text search
|
|
49
|
+
isMatch = row.textContent
|
|
50
|
+
.toLowerCase()
|
|
51
|
+
.includes(searchValue.toLowerCase());
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
row.style.display = isMatch ? '' : 'none';
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// loads the search box
|
|
59
|
+
function addSearchBox() {
|
|
60
|
+
var template = document.getElementById('filterTemplate');
|
|
61
|
+
var templateClone = template.content.cloneNode(true);
|
|
62
|
+
templateClone.getElementById('fileSearch').oninput = onFilterInput;
|
|
63
|
+
template.parentElement.appendChild(templateClone);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// loads all columns
|
|
67
|
+
function loadColumns() {
|
|
68
|
+
var colNodes = getTableHeader().querySelectorAll('th'),
|
|
69
|
+
colNode,
|
|
70
|
+
cols = [],
|
|
71
|
+
col,
|
|
72
|
+
i;
|
|
73
|
+
|
|
74
|
+
for (i = 0; i < colNodes.length; i += 1) {
|
|
75
|
+
colNode = colNodes[i];
|
|
76
|
+
col = {
|
|
77
|
+
key: colNode.getAttribute('data-col'),
|
|
78
|
+
sortable: !colNode.getAttribute('data-nosort'),
|
|
79
|
+
type: colNode.getAttribute('data-type') || 'string'
|
|
80
|
+
};
|
|
81
|
+
cols.push(col);
|
|
82
|
+
if (col.sortable) {
|
|
83
|
+
col.defaultDescSort = col.type === 'number';
|
|
84
|
+
colNode.innerHTML =
|
|
85
|
+
colNode.innerHTML + '<span class="sorter"></span>';
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return cols;
|
|
89
|
+
}
|
|
90
|
+
// attaches a data attribute to every tr element with an object
|
|
91
|
+
// of data values keyed by column name
|
|
92
|
+
function loadRowData(tableRow) {
|
|
93
|
+
var tableCols = tableRow.querySelectorAll('td'),
|
|
94
|
+
colNode,
|
|
95
|
+
col,
|
|
96
|
+
data = {},
|
|
97
|
+
i,
|
|
98
|
+
val;
|
|
99
|
+
for (i = 0; i < tableCols.length; i += 1) {
|
|
100
|
+
colNode = tableCols[i];
|
|
101
|
+
col = cols[i];
|
|
102
|
+
val = colNode.getAttribute('data-value');
|
|
103
|
+
if (col.type === 'number') {
|
|
104
|
+
val = Number(val);
|
|
105
|
+
}
|
|
106
|
+
data[col.key] = val;
|
|
107
|
+
}
|
|
108
|
+
return data;
|
|
109
|
+
}
|
|
110
|
+
// loads all row data
|
|
111
|
+
function loadData() {
|
|
112
|
+
var rows = getTableBody().querySelectorAll('tr'),
|
|
113
|
+
i;
|
|
114
|
+
|
|
115
|
+
for (i = 0; i < rows.length; i += 1) {
|
|
116
|
+
rows[i].data = loadRowData(rows[i]);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// sorts the table using the data for the ith column
|
|
120
|
+
function sortByIndex(index, desc) {
|
|
121
|
+
var key = cols[index].key,
|
|
122
|
+
sorter = function(a, b) {
|
|
123
|
+
a = a.data[key];
|
|
124
|
+
b = b.data[key];
|
|
125
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
126
|
+
},
|
|
127
|
+
finalSorter = sorter,
|
|
128
|
+
tableBody = document.querySelector('.coverage-summary tbody'),
|
|
129
|
+
rowNodes = tableBody.querySelectorAll('tr'),
|
|
130
|
+
rows = [],
|
|
131
|
+
i;
|
|
132
|
+
|
|
133
|
+
if (desc) {
|
|
134
|
+
finalSorter = function(a, b) {
|
|
135
|
+
return -1 * sorter(a, b);
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
for (i = 0; i < rowNodes.length; i += 1) {
|
|
140
|
+
rows.push(rowNodes[i]);
|
|
141
|
+
tableBody.removeChild(rowNodes[i]);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
rows.sort(finalSorter);
|
|
145
|
+
|
|
146
|
+
for (i = 0; i < rows.length; i += 1) {
|
|
147
|
+
tableBody.appendChild(rows[i]);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// removes sort indicators for current column being sorted
|
|
151
|
+
function removeSortIndicators() {
|
|
152
|
+
var col = getNthColumn(currentSort.index),
|
|
153
|
+
cls = col.className;
|
|
154
|
+
|
|
155
|
+
cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, '');
|
|
156
|
+
col.className = cls;
|
|
157
|
+
}
|
|
158
|
+
// adds sort indicators for current column being sorted
|
|
159
|
+
function addSortIndicators() {
|
|
160
|
+
getNthColumn(currentSort.index).className += currentSort.desc
|
|
161
|
+
? ' sorted-desc'
|
|
162
|
+
: ' sorted';
|
|
163
|
+
}
|
|
164
|
+
// adds event listeners for all sorter widgets
|
|
165
|
+
function enableUI() {
|
|
166
|
+
var i,
|
|
167
|
+
el,
|
|
168
|
+
ithSorter = function ithSorter(i) {
|
|
169
|
+
var col = cols[i];
|
|
170
|
+
|
|
171
|
+
return function() {
|
|
172
|
+
var desc = col.defaultDescSort;
|
|
173
|
+
|
|
174
|
+
if (currentSort.index === i) {
|
|
175
|
+
desc = !currentSort.desc;
|
|
176
|
+
}
|
|
177
|
+
sortByIndex(i, desc);
|
|
178
|
+
removeSortIndicators();
|
|
179
|
+
currentSort.index = i;
|
|
180
|
+
currentSort.desc = desc;
|
|
181
|
+
addSortIndicators();
|
|
182
|
+
};
|
|
183
|
+
};
|
|
184
|
+
for (i = 0; i < cols.length; i += 1) {
|
|
185
|
+
if (cols[i].sortable) {
|
|
186
|
+
// add the click event handler on the th so users
|
|
187
|
+
// dont have to click on those tiny arrows
|
|
188
|
+
el = getNthColumn(i).querySelector('.sorter').parentElement;
|
|
189
|
+
if (el.addEventListener) {
|
|
190
|
+
el.addEventListener('click', ithSorter(i));
|
|
191
|
+
} else {
|
|
192
|
+
el.attachEvent('onclick', ithSorter(i));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// adds sorting functionality to the UI
|
|
198
|
+
return function() {
|
|
199
|
+
if (!getTable()) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
cols = loadColumns();
|
|
203
|
+
loadData();
|
|
204
|
+
addSearchBox();
|
|
205
|
+
addSortIndicators();
|
|
206
|
+
enableUI();
|
|
207
|
+
};
|
|
208
|
+
})();
|
|
209
|
+
|
|
210
|
+
window.addEventListener('load', addSorting);
|
|
File without changes
|
package/dist-server/index.d.ts
CHANGED
package/dist-server/index.js
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerFigureToolCategories = void 0;
|
|
3
4
|
const tslib_1 = require("tslib");
|
|
5
|
+
require("./routes.js");
|
|
6
|
+
/*
|
|
7
|
+
* ์ ์ ๋๊ตฌ๋ฅผ ์ด์์คํดํธ ๋ ์ง์คํธ๋ฆฌ์ ๋ฑ๋กํ๋ค.
|
|
8
|
+
*
|
|
9
|
+
* ์ด ํจํค์ง๊ฐ ์ ์ฌ๋๋ฉด ๋ํ๋ฉด(๋ํฌ)์ด ์ ์ ์ค์ธ Figure ์ ์ ๋ณธยท๋น์ฉยท๋ฐํ ํ์ ์ ์ฝ๊ณ ํ๋ณด๋ฅผ
|
|
10
|
+
* ์์ฒญํ ์ ์๋ค. ๋ฅ๋ ฅ์ ๋ณต์ ํ์ง ์๊ณ figure-service ๊ฐ ์ด๋ฏธ ๊ฐ์ง ์ง์
์ ์ ํฌ์ํ๋ค โ
|
|
11
|
+
* ๋
ธ์ถ ๋ฒ์๋ ๋ํ๋ฉด์ด `toolCategories` ๋ก ๊ณ ๋ฅธ๋ค(twin-ai ยท board-import ์ ๊ฐ์ ๋ฐฉ์).
|
|
12
|
+
*/
|
|
13
|
+
const figure_tools_js_1 = require("./service/figure/figure-tools.js");
|
|
14
|
+
(0, figure_tools_js_1.registerFigureToolCategories)();
|
|
4
15
|
tslib_1.__exportStar(require("./service/index.js"), exports);
|
|
5
16
|
tslib_1.__exportStar(require("./migrations/index.js"), exports);
|
|
17
|
+
var figure_tools_js_2 = require("./service/figure/figure-tools.js");
|
|
18
|
+
Object.defineProperty(exports, "registerFigureToolCategories", { enumerable: true, get: function () { return figure_tools_js_2.registerFigureToolCategories; } });
|
|
6
19
|
//# sourceMappingURL=index.js.map
|
package/dist-server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;;AAAA,uBAAoB;AAEpB;;;;;;GAMG;AACH,sEAA+E;AAC/E,IAAA,8CAA4B,GAAE,CAAA;AAE9B,6DAAkC;AAClC,gEAAqC;AACrC,oEAA+E;AAAtE,+HAAA,4BAA4B,OAAA","sourcesContent":["import './routes.js'\n\n/*\n * ์ ์ ๋๊ตฌ๋ฅผ ์ด์์คํดํธ ๋ ์ง์คํธ๋ฆฌ์ ๋ฑ๋กํ๋ค.\n *\n * ์ด ํจํค์ง๊ฐ ์ ์ฌ๋๋ฉด ๋ํ๋ฉด(๋ํฌ)์ด ์ ์ ์ค์ธ Figure ์ ์ ๋ณธยท๋น์ฉยท๋ฐํ ํ์ ์ ์ฝ๊ณ ํ๋ณด๋ฅผ\n * ์์ฒญํ ์ ์๋ค. ๋ฅ๋ ฅ์ ๋ณต์ ํ์ง ์๊ณ figure-service ๊ฐ ์ด๋ฏธ ๊ฐ์ง ์ง์
์ ์ ํฌ์ํ๋ค โ\n * ๋
ธ์ถ ๋ฒ์๋ ๋ํ๋ฉด์ด `toolCategories` ๋ก ๊ณ ๋ฅธ๋ค(twin-ai ยท board-import ์ ๊ฐ์ ๋ฐฉ์).\n */\nimport { registerFigureToolCategories } from './service/figure/figure-tools.js'\nregisterFigureToolCategories()\n\nexport * from './service/index.js'\nexport * from './migrations/index.js'\nexport { registerFigureToolCategories } from './service/figure/figure-tools.js'\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ์ธ๋ค์ผ์ **๊ทธ๋ฆผ์ผ๋ก** ๋ด๋ณด๋ด๋ ๊ธธ.
|
|
3
|
+
*
|
|
4
|
+
* ## ์ ํ์ํ๊ฐ
|
|
5
|
+
*
|
|
6
|
+
* ์ธ๋ค์ผ์ base64 ๋ฌธ์์ด๋ก ์นธ์ ๋ค์ด ์๋ค(`Board.thumbnail` ๊ณผ ๊ฐ์ ๋ฐฉ์). ๊ทธ๊ฒ์ ๋ชฉ๋ก ์ง์๊ฐ
|
|
7
|
+
* ํจ๊ป ์ค์ด ์ค๋ฉด ์นดํ๋ก๊ทธ๋ฅผ ์ด ๋๋ง๋ค ๊ทธ๋ฆผ ์ ๋ถ๊ฐ JSON ์์ ๋ด๊ฒจ ๋ค์ ์จ๋ค โ data URL ์
|
|
8
|
+
* ๋ธ๋ผ์ฐ์ ๊ฐ ์บ์ํ ์ ์๋ค. [ํ์ธํจ] ํ๋ณธ 14๊ฐ์ 227KB, ํ ์ฅ ์ต๋ 20KB.
|
|
9
|
+
*
|
|
10
|
+
* ๊ทธ๋ฆผ์ผ๋ก ๋ด๋ณด๋ด๋ฉด ๋ธ๋ผ์ฐ์ ๊ฐ ์บ์ํ๊ณ , ๋ถ๋ฅด๋ ์ชฝ์ด `?v=thumbnailUpdatedAt` ์ ๋ถ์ด๋ฏ๋ก ๊ทธ๋ฆผ์ด
|
|
11
|
+
* ๋ค์ ๋ง๋ค์ด์ง ๊ฒ๋ง ๋ค์ ๋ฐ๋๋ค. ๋ชฉ๋ก ์ง์์์๋ `thumbnail` ์ ์์ ๊ณ ๋ฅด์ง ์๋๋ค.
|
|
12
|
+
*
|
|
13
|
+
* ## board ๋ฅผ ๋ฒ ๋ผ๋ฉด์ ๊ณ ์น ๊ฒ ์
|
|
14
|
+
*
|
|
15
|
+
* `standalone-board-service-router` ์ `/thumbnail/:id` ๊ฐ ๋ณธ์ด์ง๋ง ๊ทธ๋๋ก ๋๋ฉด ์ ๋๋ ๊ฒ๋ค์ด ์๋ค.
|
|
16
|
+
*
|
|
17
|
+
* 1. **๊ธธ ์ด๋ฆ์ด ๊ฒน์น๋ค.** ์ด ์ฑ์ board ๋ ํจ๊ป ์ฃ๋๋ค(๋ฉ๋ด๊ฐ board-ui ๋ฅผ ๋์ด์จ๋ค).
|
|
18
|
+
* `/thumbnail/:id` ๋ก ๋๋ฉด ๋จผ์ ๋ฑ๋ก๋ ์ชฝ์ด ์ด๊ธฐ๊ณ , ๋จ์ ํ์์ id ๋ฅผ ์ฐพ์ 404 ๋ฅผ ๋ธ๋ค.
|
|
19
|
+
* 2. **ํ ์ ์ฒด๋ฅผ ์ฝ๋๋ค.** board ๋ `findOneBy` ๋ก ํ์ ๋ค ์ฝ๋๋ค. figure ํ์๋ ์ ๋ณธ(`source`)์ด
|
|
20
|
+
* ๋ถ์ด ์์ด, ๊ทธ๋ฆผ ํ ์ฅ์ ์ ๋ณธ๊น์ง ์ฝ๊ฒ ๋๋ค. ํ์ํ ์นธ๋ง ๊ณ ๋ฅธ๋ค.
|
|
21
|
+
* 3. **png ๋ก ๋ชป ๋ฐ๋๋ค.** figure ์ธ๋ค์ผ์ webp ๋ค(๋ชจ๋ธ๋ฌ๊ฐ ๊ทธ๋ ๊ฒ ๋ง๋ ๋ค). data URL ์ด ์ค์ค๋ก
|
|
22
|
+
* ๋งํ๋ ํ์์ ์ด๋ค โ ๋ชป ๋ฐ์ผ๋ฉด ๋ธ๋ผ์ฐ์ ๊ฐ ํ์ฅ์์ ๋ค๋ฅธ ๋ฐ์ดํธ๋ฅผ ๋ฐ๋๋ค.
|
|
23
|
+
*/
|
|
24
|
+
export declare const figureThumbnailRouter: any;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.figureThumbnailRouter = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const koa_router_1 = tslib_1.__importDefault(require("koa-router"));
|
|
6
|
+
const typeorm_1 = require("typeorm");
|
|
7
|
+
const auth_base_1 = require("@things-factory/auth-base");
|
|
8
|
+
const shell_1 = require("@things-factory/shell");
|
|
9
|
+
const figure_js_1 = require("../service/figure/figure.js");
|
|
10
|
+
/**
|
|
11
|
+
* ์ธ๋ค์ผ์ **๊ทธ๋ฆผ์ผ๋ก** ๋ด๋ณด๋ด๋ ๊ธธ.
|
|
12
|
+
*
|
|
13
|
+
* ## ์ ํ์ํ๊ฐ
|
|
14
|
+
*
|
|
15
|
+
* ์ธ๋ค์ผ์ base64 ๋ฌธ์์ด๋ก ์นธ์ ๋ค์ด ์๋ค(`Board.thumbnail` ๊ณผ ๊ฐ์ ๋ฐฉ์). ๊ทธ๊ฒ์ ๋ชฉ๋ก ์ง์๊ฐ
|
|
16
|
+
* ํจ๊ป ์ค์ด ์ค๋ฉด ์นดํ๋ก๊ทธ๋ฅผ ์ด ๋๋ง๋ค ๊ทธ๋ฆผ ์ ๋ถ๊ฐ JSON ์์ ๋ด๊ฒจ ๋ค์ ์จ๋ค โ data URL ์
|
|
17
|
+
* ๋ธ๋ผ์ฐ์ ๊ฐ ์บ์ํ ์ ์๋ค. [ํ์ธํจ] ํ๋ณธ 14๊ฐ์ 227KB, ํ ์ฅ ์ต๋ 20KB.
|
|
18
|
+
*
|
|
19
|
+
* ๊ทธ๋ฆผ์ผ๋ก ๋ด๋ณด๋ด๋ฉด ๋ธ๋ผ์ฐ์ ๊ฐ ์บ์ํ๊ณ , ๋ถ๋ฅด๋ ์ชฝ์ด `?v=thumbnailUpdatedAt` ์ ๋ถ์ด๋ฏ๋ก ๊ทธ๋ฆผ์ด
|
|
20
|
+
* ๋ค์ ๋ง๋ค์ด์ง ๊ฒ๋ง ๋ค์ ๋ฐ๋๋ค. ๋ชฉ๋ก ์ง์์์๋ `thumbnail` ์ ์์ ๊ณ ๋ฅด์ง ์๋๋ค.
|
|
21
|
+
*
|
|
22
|
+
* ## board ๋ฅผ ๋ฒ ๋ผ๋ฉด์ ๊ณ ์น ๊ฒ ์
|
|
23
|
+
*
|
|
24
|
+
* `standalone-board-service-router` ์ `/thumbnail/:id` ๊ฐ ๋ณธ์ด์ง๋ง ๊ทธ๋๋ก ๋๋ฉด ์ ๋๋ ๊ฒ๋ค์ด ์๋ค.
|
|
25
|
+
*
|
|
26
|
+
* 1. **๊ธธ ์ด๋ฆ์ด ๊ฒน์น๋ค.** ์ด ์ฑ์ board ๋ ํจ๊ป ์ฃ๋๋ค(๋ฉ๋ด๊ฐ board-ui ๋ฅผ ๋์ด์จ๋ค).
|
|
27
|
+
* `/thumbnail/:id` ๋ก ๋๋ฉด ๋จผ์ ๋ฑ๋ก๋ ์ชฝ์ด ์ด๊ธฐ๊ณ , ๋จ์ ํ์์ id ๋ฅผ ์ฐพ์ 404 ๋ฅผ ๋ธ๋ค.
|
|
28
|
+
* 2. **ํ ์ ์ฒด๋ฅผ ์ฝ๋๋ค.** board ๋ `findOneBy` ๋ก ํ์ ๋ค ์ฝ๋๋ค. figure ํ์๋ ์ ๋ณธ(`source`)์ด
|
|
29
|
+
* ๋ถ์ด ์์ด, ๊ทธ๋ฆผ ํ ์ฅ์ ์ ๋ณธ๊น์ง ์ฝ๊ฒ ๋๋ค. ํ์ํ ์นธ๋ง ๊ณ ๋ฅธ๋ค.
|
|
30
|
+
* 3. **png ๋ก ๋ชป ๋ฐ๋๋ค.** figure ์ธ๋ค์ผ์ webp ๋ค(๋ชจ๋ธ๋ฌ๊ฐ ๊ทธ๋ ๊ฒ ๋ง๋ ๋ค). data URL ์ด ์ค์ค๋ก
|
|
31
|
+
* ๋งํ๋ ํ์์ ์ด๋ค โ ๋ชป ๋ฐ์ผ๋ฉด ๋ธ๋ผ์ฐ์ ๊ฐ ํ์ฅ์์ ๋ค๋ฅธ ๋ฐ์ดํธ๋ฅผ ๋ฐ๋๋ค.
|
|
32
|
+
*/
|
|
33
|
+
exports.figureThumbnailRouter = new koa_router_1.default();
|
|
34
|
+
/** `data:image/webp;base64,....` โ ํ์๊ณผ ๋ฐ์ดํธ. ์๋๋ฉด undefined. */
|
|
35
|
+
function decodeDataUrl(dataUrl) {
|
|
36
|
+
const matched = /^data:([^;,]+);base64,(.*)$/s.exec(dataUrl);
|
|
37
|
+
if (!matched) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
return { type: matched[1], buffer: Buffer.from(matched[2], 'base64') };
|
|
41
|
+
}
|
|
42
|
+
exports.figureThumbnailRouter.get('/figure-thumbnail/:id', async (context, next) => {
|
|
43
|
+
const { domain, user, unsafeIP, prohibitedPrivileges } = context.state;
|
|
44
|
+
/*
|
|
45
|
+
**์ง์์ ๊ฐ์ ๋ฌธ์ ์ด๋ค.**
|
|
46
|
+
|
|
47
|
+
`User.hasPrivilege('query','figure',โฆ)` ๋ง ๋ณด๋ฉด ์ ๋๋ค โ figure ์ง์๋
|
|
48
|
+
`@privilege(category: "figure", privilege: "query", domainOwnerGranted: true)` ๋ก ์ ์ธ๋์ด ์๊ณ ,
|
|
49
|
+
๋๋ฉ์ธ ์์ ์๋ `figure:query` ๊ถํ ์ค์ด ์์ด๋ ํต๊ณผํ๋ค. ๊ทธ ํ์ฉ์ ์ฌ๊ธฐ์ ๋นผ๋ฉด ๋ชฉ๋ก์ ๋ณด์ด๋๋ฐ
|
|
50
|
+
๊ทธ๋ฆผ๋ง 403 ์ด ๋์ด, ํ๋ฉด์ ใ๊ทธ๋ฆผ์ด ์์ง ์๋คใ๊ณ ๊ฑฐ์ง๋งํ๋ค. [ํ์ธํจ] ์ค์ ๋ก ์นด๋ 14์ฅ์ด ์ ๋ถ
|
|
51
|
+
403 ์ด์๋ค.
|
|
52
|
+
|
|
53
|
+
์กฐ๊ฑด์ ์์ผ๋ก ๋ค์ ์ ์ง ์๊ณ ์ง์์๊ฐ ์ฐ๋ ํจ์๋ฅผ ๊ทธ๋๋ก ์ด๋ค. ์ ์ธ์ด ๋ฐ๋๋ฉด ์ฌ๊ธฐ๋ ํจ๊ป ๋ฐ๋๋ค.
|
|
54
|
+
*/
|
|
55
|
+
const allowed = await (0, auth_base_1.checkPermission)({ category: 'figure', privilege: 'query', owner: true }, user, domain, unsafeIP, prohibitedPrivileges);
|
|
56
|
+
if (!allowed) {
|
|
57
|
+
context.status = 403;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const { id } = context.params;
|
|
61
|
+
/*
|
|
62
|
+
์ฝ๊ธฐ๋ ๋ถ๋ชจ ๋๋ฉ์ธ๊น์ง ๋ณธ๋ค โ `figure` ์ง์์ ๊ฐ์ ๋ฒ์๋ค. ๋ฌผ๋ ค๋ฐ์ ํ์์ ๋ชฉ๋ก์๋ ๋ณด์ฌ ์ฃผ๊ณ
|
|
63
|
+
๊ทธ๋ฆผ๋ง 404 ๋ฅผ ๋ด๋ฉด, ํ๋ฉด์ ใ๊ทธ๋ฆผ์ด ์์ง ์๋คใ๊ณ ๊ฑฐ์ง๋งํ๊ฒ ๋๋ค.
|
|
64
|
+
*/
|
|
65
|
+
const found = await (0, shell_1.getRepository)(figure_js_1.Figure).findOne({
|
|
66
|
+
where: { domain: { id: (0, typeorm_1.In)([domain.id, domain.parentId].filter(Boolean)) }, id },
|
|
67
|
+
select: { id: true, thumbnail: true, thumbnailUpdatedAt: true }
|
|
68
|
+
});
|
|
69
|
+
const decoded = found?.thumbnail ? decodeDataUrl(found.thumbnail) : undefined;
|
|
70
|
+
if (!decoded) {
|
|
71
|
+
context.status = 404;
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
/*
|
|
75
|
+
**๊ฐ์ธ ์บ์๋ง ํ๋ฝํ๋ค.** ์ด ๊ทธ๋ฆผ์ ๊ถํ์ ๋ณธ ๋ค์ ๋ด์ฃผ๋ ๊ฒ์ด๋ฏ๋ก ๊ณต์ฉ ์บ์(ํ๋ก์)์ ๋จ์ผ๋ฉด
|
|
76
|
+
์ ๋๋ค. ๋ถ๋ฅด๋ ์ชฝ์ด `?v=` ๋ก ํ์ ๊ฐ๋ฆฌ๋ฏ๋ก ์ค๋ ๋์ด๋ ๋ก์ ๊ทธ๋ฆผ์ด ๋จ์ง ์๊ณ , `v` ์์ด ๋ถ๋ฅธ
|
|
77
|
+
๊ฒฝ์ฐ๋ฅผ ์ํด ์๊ฐ์ ํจ๊ป ์ค์ด ๋ค์ ๋ฌผ์ด๋ณผ ์ ์๊ฒ ํ๋ค.
|
|
78
|
+
*/
|
|
79
|
+
const stamp = found.thumbnailUpdatedAt;
|
|
80
|
+
context.type = decoded.type;
|
|
81
|
+
context.set('Cache-Control', 'private, max-age=31536000');
|
|
82
|
+
if (stamp) {
|
|
83
|
+
context.set('Last-Modified', new Date(stamp).toUTCString());
|
|
84
|
+
context.set('ETag', `"${new Date(stamp).getTime()}"`);
|
|
85
|
+
/* ๋ธ๋ผ์ฐ์ ๊ฐ ๊ฐ์ง ๊ฒ์ด ์์ง ๊ทธ๊ฒ์ด๋ฉด ๋ฐ์ดํธ๋ฅผ ๋ณด๋ด์ง ์๋๋ค. */
|
|
86
|
+
if (context.fresh) {
|
|
87
|
+
context.status = 304;
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
context.body = decoded.buffer;
|
|
92
|
+
});
|
|
93
|
+
//# sourceMappingURL=figure-thumbnail-router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"figure-thumbnail-router.js","sourceRoot":"","sources":["../../server/routers/figure-thumbnail-router.ts"],"names":[],"mappings":";;;;AAAA,oEAA+B;AAC/B,qCAA4B;AAE5B,yDAA2D;AAC3D,iDAAqD;AAErD,2DAAoD;AAEpD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACU,QAAA,qBAAqB,GAAG,IAAI,oBAAM,EAAE,CAAA;AAEjD,8DAA8D;AAC9D,SAAS,aAAa,CAAC,OAAe;IACpC,MAAM,OAAO,GAAG,8BAA8B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC5D,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAA;AACxE,CAAC;AAED,6BAAqB,CAAC,GAAG,CAAC,uBAAuB,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;IACzE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,oBAAoB,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IAEtE;;;;;;;;;;MAUE;IACF,MAAM,OAAO,GAAG,MAAM,IAAA,2BAAe,EACnC,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EACvD,IAAI,EACJ,MAAM,EACN,QAAQ,EACR,oBAAoB,CACrB,CAAA;IAED,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,GAAG,GAAG,CAAA;QACpB,OAAM;IACR,CAAC;IAED,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAA;IAE7B;;;MAGE;IACF,MAAM,KAAK,GAAG,MAAM,IAAA,qBAAa,EAAC,kBAAM,CAAC,CAAC,OAAO,CAAC;QAChD,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAA,YAAE,EAAC,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE;QAC/E,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE;KAChE,CAAC,CAAA;IAEF,MAAM,OAAO,GAAG,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAE7E,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,GAAG,GAAG,CAAA;QACpB,OAAM;IACR,CAAC;IAED;;;;MAIE;IACF,MAAM,KAAK,GAAG,KAAM,CAAC,kBAAkB,CAAA;IAEvC,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAA;IAC3B,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,2BAA2B,CAAC,CAAA;IACzD,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,CAAA;QAC3D,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;QAErD,uCAAuC;QACvC,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAClB,OAAO,CAAC,MAAM,GAAG,GAAG,CAAA;YACpB,OAAM;QACR,CAAC;IACH,CAAC;IAED,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,MAAM,CAAA;AAC/B,CAAC,CAAC,CAAA","sourcesContent":["import Router from 'koa-router'\nimport { In } from 'typeorm'\n\nimport { checkPermission } from '@things-factory/auth-base'\nimport { getRepository } from '@things-factory/shell'\n\nimport { Figure } from '../service/figure/figure.js'\n\n/**\n * ์ธ๋ค์ผ์ **๊ทธ๋ฆผ์ผ๋ก** ๋ด๋ณด๋ด๋ ๊ธธ.\n *\n * ## ์ ํ์ํ๊ฐ\n *\n * ์ธ๋ค์ผ์ base64 ๋ฌธ์์ด๋ก ์นธ์ ๋ค์ด ์๋ค(`Board.thumbnail` ๊ณผ ๊ฐ์ ๋ฐฉ์). ๊ทธ๊ฒ์ ๋ชฉ๋ก ์ง์๊ฐ\n * ํจ๊ป ์ค์ด ์ค๋ฉด ์นดํ๋ก๊ทธ๋ฅผ ์ด ๋๋ง๋ค ๊ทธ๋ฆผ ์ ๋ถ๊ฐ JSON ์์ ๋ด๊ฒจ ๋ค์ ์จ๋ค โ data URL ์\n * ๋ธ๋ผ์ฐ์ ๊ฐ ์บ์ํ ์ ์๋ค. [ํ์ธํจ] ํ๋ณธ 14๊ฐ์ 227KB, ํ ์ฅ ์ต๋ 20KB.\n *\n * ๊ทธ๋ฆผ์ผ๋ก ๋ด๋ณด๋ด๋ฉด ๋ธ๋ผ์ฐ์ ๊ฐ ์บ์ํ๊ณ , ๋ถ๋ฅด๋ ์ชฝ์ด `?v=thumbnailUpdatedAt` ์ ๋ถ์ด๋ฏ๋ก ๊ทธ๋ฆผ์ด\n * ๋ค์ ๋ง๋ค์ด์ง ๊ฒ๋ง ๋ค์ ๋ฐ๋๋ค. ๋ชฉ๋ก ์ง์์์๋ `thumbnail` ์ ์์ ๊ณ ๋ฅด์ง ์๋๋ค.\n *\n * ## board ๋ฅผ ๋ฒ ๋ผ๋ฉด์ ๊ณ ์น ๊ฒ ์
\n *\n * `standalone-board-service-router` ์ `/thumbnail/:id` ๊ฐ ๋ณธ์ด์ง๋ง ๊ทธ๋๋ก ๋๋ฉด ์ ๋๋ ๊ฒ๋ค์ด ์๋ค.\n *\n * 1. **๊ธธ ์ด๋ฆ์ด ๊ฒน์น๋ค.** ์ด ์ฑ์ board ๋ ํจ๊ป ์ฃ๋๋ค(๋ฉ๋ด๊ฐ board-ui ๋ฅผ ๋์ด์จ๋ค).\n * `/thumbnail/:id` ๋ก ๋๋ฉด ๋จผ์ ๋ฑ๋ก๋ ์ชฝ์ด ์ด๊ธฐ๊ณ , ๋จ์ ํ์์ id ๋ฅผ ์ฐพ์ 404 ๋ฅผ ๋ธ๋ค.\n * 2. **ํ ์ ์ฒด๋ฅผ ์ฝ๋๋ค.** board ๋ `findOneBy` ๋ก ํ์ ๋ค ์ฝ๋๋ค. figure ํ์๋ ์ ๋ณธ(`source`)์ด\n * ๋ถ์ด ์์ด, ๊ทธ๋ฆผ ํ ์ฅ์ ์ ๋ณธ๊น์ง ์ฝ๊ฒ ๋๋ค. ํ์ํ ์นธ๋ง ๊ณ ๋ฅธ๋ค.\n * 3. **png ๋ก ๋ชป ๋ฐ๋๋ค.** figure ์ธ๋ค์ผ์ webp ๋ค(๋ชจ๋ธ๋ฌ๊ฐ ๊ทธ๋ ๊ฒ ๋ง๋ ๋ค). data URL ์ด ์ค์ค๋ก\n * ๋งํ๋ ํ์์ ์ด๋ค โ ๋ชป ๋ฐ์ผ๋ฉด ๋ธ๋ผ์ฐ์ ๊ฐ ํ์ฅ์์ ๋ค๋ฅธ ๋ฐ์ดํธ๋ฅผ ๋ฐ๋๋ค.\n */\nexport const figureThumbnailRouter = new Router()\n\n/** `data:image/webp;base64,....` โ ํ์๊ณผ ๋ฐ์ดํธ. ์๋๋ฉด undefined. */\nfunction decodeDataUrl(dataUrl: string): { type: string; buffer: Buffer } | undefined {\n const matched = /^data:([^;,]+);base64,(.*)$/s.exec(dataUrl)\n if (!matched) {\n return undefined\n }\n\n return { type: matched[1], buffer: Buffer.from(matched[2], 'base64') }\n}\n\nfigureThumbnailRouter.get('/figure-thumbnail/:id', async (context, next) => {\n const { domain, user, unsafeIP, prohibitedPrivileges } = context.state\n\n /*\n **์ง์์ ๊ฐ์ ๋ฌธ์ ์ด๋ค.**\n\n `User.hasPrivilege('query','figure',โฆ)` ๋ง ๋ณด๋ฉด ์ ๋๋ค โ figure ์ง์๋\n `@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)` ๋ก ์ ์ธ๋์ด ์๊ณ ,\n ๋๋ฉ์ธ ์์ ์๋ `figure:query` ๊ถํ ์ค์ด ์์ด๋ ํต๊ณผํ๋ค. ๊ทธ ํ์ฉ์ ์ฌ๊ธฐ์ ๋นผ๋ฉด ๋ชฉ๋ก์ ๋ณด์ด๋๋ฐ\n ๊ทธ๋ฆผ๋ง 403 ์ด ๋์ด, ํ๋ฉด์ ใ๊ทธ๋ฆผ์ด ์์ง ์๋คใ๊ณ ๊ฑฐ์ง๋งํ๋ค. [ํ์ธํจ] ์ค์ ๋ก ์นด๋ 14์ฅ์ด ์ ๋ถ\n 403 ์ด์๋ค.\n\n ์กฐ๊ฑด์ ์์ผ๋ก ๋ค์ ์ ์ง ์๊ณ ์ง์์๊ฐ ์ฐ๋ ํจ์๋ฅผ ๊ทธ๋๋ก ์ด๋ค. ์ ์ธ์ด ๋ฐ๋๋ฉด ์ฌ๊ธฐ๋ ํจ๊ป ๋ฐ๋๋ค.\n */\n const allowed = await checkPermission(\n { category: 'figure', privilege: 'query', owner: true },\n user,\n domain,\n unsafeIP,\n prohibitedPrivileges\n )\n\n if (!allowed) {\n context.status = 403\n return\n }\n\n const { id } = context.params\n\n /*\n ์ฝ๊ธฐ๋ ๋ถ๋ชจ ๋๋ฉ์ธ๊น์ง ๋ณธ๋ค โ `figure` ์ง์์ ๊ฐ์ ๋ฒ์๋ค. ๋ฌผ๋ ค๋ฐ์ ํ์์ ๋ชฉ๋ก์๋ ๋ณด์ฌ ์ฃผ๊ณ \n ๊ทธ๋ฆผ๋ง 404 ๋ฅผ ๋ด๋ฉด, ํ๋ฉด์ ใ๊ทธ๋ฆผ์ด ์์ง ์๋คใ๊ณ ๊ฑฐ์ง๋งํ๊ฒ ๋๋ค.\n */\n const found = await getRepository(Figure).findOne({\n where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id },\n select: { id: true, thumbnail: true, thumbnailUpdatedAt: true }\n })\n\n const decoded = found?.thumbnail ? decodeDataUrl(found.thumbnail) : undefined\n\n if (!decoded) {\n context.status = 404\n return\n }\n\n /*\n **๊ฐ์ธ ์บ์๋ง ํ๋ฝํ๋ค.** ์ด ๊ทธ๋ฆผ์ ๊ถํ์ ๋ณธ ๋ค์ ๋ด์ฃผ๋ ๊ฒ์ด๋ฏ๋ก ๊ณต์ฉ ์บ์(ํ๋ก์)์ ๋จ์ผ๋ฉด\n ์ ๋๋ค. ๋ถ๋ฅด๋ ์ชฝ์ด `?v=` ๋ก ํ์ ๊ฐ๋ฆฌ๋ฏ๋ก ์ค๋ ๋์ด๋ ๋ก์ ๊ทธ๋ฆผ์ด ๋จ์ง ์๊ณ , `v` ์์ด ๋ถ๋ฅธ\n ๊ฒฝ์ฐ๋ฅผ ์ํด ์๊ฐ์ ํจ๊ป ์ค์ด ๋ค์ ๋ฌผ์ด๋ณผ ์ ์๊ฒ ํ๋ค.\n */\n const stamp = found!.thumbnailUpdatedAt\n\n context.type = decoded.type\n context.set('Cache-Control', 'private, max-age=31536000')\n if (stamp) {\n context.set('Last-Modified', new Date(stamp).toUTCString())\n context.set('ETag', `\"${new Date(stamp).getTime()}\"`)\n\n /* ๋ธ๋ผ์ฐ์ ๊ฐ ๊ฐ์ง ๊ฒ์ด ์์ง ๊ทธ๊ฒ์ด๋ฉด ๋ฐ์ดํธ๋ฅผ ๋ณด๋ด์ง ์๋๋ค. */\n if (context.fresh) {\n context.status = 304\n return\n }\n }\n\n context.body = decoded.buffer\n})\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const env_1 = require("@things-factory/env");
|
|
4
|
+
const shell_1 = require("@things-factory/shell");
|
|
5
|
+
const figure_thumbnail_router_js_1 = require("./routers/figure-thumbnail-router.js");
|
|
6
|
+
/**
|
|
7
|
+
* ๋๋ฉ์ธ ๊ฒฝ๋ก๊ฐ ์ฃผ์์ ๋ค์ด๊ฐ๋ ๋ฐฐ์น์ธ๊ฐ.
|
|
8
|
+
*
|
|
9
|
+
* `subdomain` ์ค์ ์ด ์์ผ๋ฉด ๋๋ฉ์ธ์ ํธ์คํธ ์ด๋ฆ์ผ๋ก ๊ฐ๋ฆฌ๋ฏ๋ก ๊ฒฝ๋ก์ ๋๋ฉ์ธ์ด ์๋ค. ์์ผ๋ฉด
|
|
10
|
+
* `/domain/{subdomain}/...` ๋ก ๊ฐ๋ฆฐ๋ค โ board-service ๊ฐ ๊ฐ์ ํ๋จ์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ํ๋ค.
|
|
11
|
+
*/
|
|
12
|
+
const isPathBaseDomain = !env_1.config.get('subdomain');
|
|
13
|
+
process.on('bootstrap-module-domain-private-route', (app, domainPrivateRouter) => {
|
|
14
|
+
if (isPathBaseDomain) {
|
|
15
|
+
domainPrivateRouter.use(`/${(0, shell_1.getRoutePrefixForDomainType)()}/:domain`, figure_thumbnail_router_js_1.figureThumbnailRouter.routes(), figure_thumbnail_router_js_1.figureThumbnailRouter.allowedMethods());
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
domainPrivateRouter.use('', figure_thumbnail_router_js_1.figureThumbnailRouter.routes(), figure_thumbnail_router_js_1.figureThumbnailRouter.allowedMethods());
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../server/routes.ts"],"names":[],"mappings":";;AAAA,6CAA4C;AAC5C,iDAAmE;AAEnE,qFAA4E;AAE5E;;;;;GAKG;AACH,MAAM,gBAAgB,GAAG,CAAC,YAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;AAEjD,OAAO,CAAC,EAAE,CAAC,uCAA8C,EAAE,CAAC,GAAG,EAAE,mBAAmB,EAAE,EAAE;IACtF,IAAI,gBAAgB,EAAE,CAAC;QACrB,mBAAmB,CAAC,GAAG,CACrB,IAAI,IAAA,mCAA2B,GAAE,UAAU,EAC3C,kDAAqB,CAAC,MAAM,EAAE,EAC9B,kDAAqB,CAAC,cAAc,EAAE,CACvC,CAAA;IACH,CAAC;SAAM,CAAC;QACN,mBAAmB,CAAC,GAAG,CAAC,EAAE,EAAE,kDAAqB,CAAC,MAAM,EAAE,EAAE,kDAAqB,CAAC,cAAc,EAAE,CAAC,CAAA;IACrG,CAAC;AACH,CAAC,CAAC,CAAA","sourcesContent":["import { config } from '@things-factory/env'\nimport { getRoutePrefixForDomainType } from '@things-factory/shell'\n\nimport { figureThumbnailRouter } from './routers/figure-thumbnail-router.js'\n\n/**\n * ๋๋ฉ์ธ ๊ฒฝ๋ก๊ฐ ์ฃผ์์ ๋ค์ด๊ฐ๋ ๋ฐฐ์น์ธ๊ฐ.\n *\n * `subdomain` ์ค์ ์ด ์์ผ๋ฉด ๋๋ฉ์ธ์ ํธ์คํธ ์ด๋ฆ์ผ๋ก ๊ฐ๋ฆฌ๋ฏ๋ก ๊ฒฝ๋ก์ ๋๋ฉ์ธ์ด ์๋ค. ์์ผ๋ฉด\n * `/domain/{subdomain}/...` ๋ก ๊ฐ๋ฆฐ๋ค โ board-service ๊ฐ ๊ฐ์ ํ๋จ์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ํ๋ค.\n */\nconst isPathBaseDomain = !config.get('subdomain')\n\nprocess.on('bootstrap-module-domain-private-route' as any, (app, domainPrivateRouter) => {\n if (isPathBaseDomain) {\n domainPrivateRouter.use(\n `/${getRoutePrefixForDomainType()}/:domain`,\n figureThumbnailRouter.routes(),\n figureThumbnailRouter.allowedMethods()\n )\n } else {\n domainPrivateRouter.use('', figureThumbnailRouter.routes(), figureThumbnailRouter.allowedMethods())\n }\n})\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { HistoryEntitySubscriber } from '@operato/typeorm-history';
|
|
2
|
+
import { Figure } from './figure.js';
|
|
3
|
+
import { FigureHistory } from './figure-history.js';
|
|
4
|
+
/**
|
|
5
|
+
* ํ๋ณธ์ ๋จ๊ธด๋ค โ **๋ฐํ๋ ์ ์ฅ์๋ง.**
|
|
6
|
+
*
|
|
7
|
+
* `@operato/typeorm-history` ๋ ์๋ ๋ชจ๋ ์ ์ฅ์ ๋ฒ ๋๋ค. ๊ทธ๋ฐ๋ฐ ๋ํ์ ์ ์ ์ค์ ์์ญ ๋ฒ ์ ์ฅ๋๊ณ ,
|
|
8
|
+
* ๊ทธ ์ ๋ถ๋ฅผ ๋จ๊ธฐ๋ฉด ํ๋ณธ ๋ชฉ๋ก์ด ใ๋ด๊ฐ ์ค๋ ๋ช ๋ฒ ๋๋ ๋ใ๊ฐ ๋๋ค. ์ฌ๋์ด ํ์ด๋ผ๊ณ ๋ถ๋ฅด๋ ๊ฒ์
|
|
9
|
+
* **๋ฐํํ ๊ฒ**์ด๋ฏ๋ก ๊ทธ๋๋ง ๋ฒ ๋๋ค. board ๊ฐ ๊ฐ์ ๊ท์น์ผ๋ก ๋๋ค(`board-service` ์ ๊ฐ์ ์ด๋ฆ ํ์ผ).
|
|
10
|
+
*
|
|
11
|
+
* ๋ฐํ ๋ฉ๋ชจ๋ Figure ์ ์นธ์ด ์๋๋ค. `releaseFigure` ๊ฐ ์ ์ฅํ ์ํฐํฐ์ `__releaseComment` ๋ก ์น์ด
|
|
12
|
+
* ๋๋ฉด ์ฌ๊ธฐ์ ํ๋ณธ์ `comment` ๋ก ์ฎ๊ธด๋ค โ ๋ฉ๋ชจ๋ ๊ทธ ํ์ ๊ฒ์ด์ง ๋ํ์ ๊ฒ์ด ์๋๋ค.
|
|
13
|
+
*/
|
|
14
|
+
export declare class FigureHistoryEntitySubscriber extends HistoryEntitySubscriber<Figure, FigureHistory> {
|
|
15
|
+
get entity(): typeof Figure;
|
|
16
|
+
get historyEntity(): typeof FigureHistory;
|
|
17
|
+
beforeInsertHistory(history: FigureHistory, entity: Figure): FigureHistory;
|
|
18
|
+
beforeUpdateHistory(history: FigureHistory, entity: Figure): FigureHistory;
|
|
19
|
+
afterInsert(event: any): Promise<void>;
|
|
20
|
+
afterUpdate(event: any): Promise<void>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FigureHistoryEntitySubscriber = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const typeorm_1 = require("typeorm");
|
|
6
|
+
const typeorm_history_1 = require("@operato/typeorm-history");
|
|
7
|
+
const figure_js_1 = require("./figure.js");
|
|
8
|
+
const figure_history_js_1 = require("./figure-history.js");
|
|
9
|
+
/**
|
|
10
|
+
* ํ๋ณธ์ ๋จ๊ธด๋ค โ **๋ฐํ๋ ์ ์ฅ์๋ง.**
|
|
11
|
+
*
|
|
12
|
+
* `@operato/typeorm-history` ๋ ์๋ ๋ชจ๋ ์ ์ฅ์ ๋ฒ ๋๋ค. ๊ทธ๋ฐ๋ฐ ๋ํ์ ์ ์ ์ค์ ์์ญ ๋ฒ ์ ์ฅ๋๊ณ ,
|
|
13
|
+
* ๊ทธ ์ ๋ถ๋ฅผ ๋จ๊ธฐ๋ฉด ํ๋ณธ ๋ชฉ๋ก์ด ใ๋ด๊ฐ ์ค๋ ๋ช ๋ฒ ๋๋ ๋ใ๊ฐ ๋๋ค. ์ฌ๋์ด ํ์ด๋ผ๊ณ ๋ถ๋ฅด๋ ๊ฒ์
|
|
14
|
+
* **๋ฐํํ ๊ฒ**์ด๋ฏ๋ก ๊ทธ๋๋ง ๋ฒ ๋๋ค. board ๊ฐ ๊ฐ์ ๊ท์น์ผ๋ก ๋๋ค(`board-service` ์ ๊ฐ์ ์ด๋ฆ ํ์ผ).
|
|
15
|
+
*
|
|
16
|
+
* ๋ฐํ ๋ฉ๋ชจ๋ Figure ์ ์นธ์ด ์๋๋ค. `releaseFigure` ๊ฐ ์ ์ฅํ ์ํฐํฐ์ `__releaseComment` ๋ก ์น์ด
|
|
17
|
+
* ๋๋ฉด ์ฌ๊ธฐ์ ํ๋ณธ์ `comment` ๋ก ์ฎ๊ธด๋ค โ ๋ฉ๋ชจ๋ ๊ทธ ํ์ ๊ฒ์ด์ง ๋ํ์ ๊ฒ์ด ์๋๋ค.
|
|
18
|
+
*/
|
|
19
|
+
let FigureHistoryEntitySubscriber = class FigureHistoryEntitySubscriber extends typeorm_history_1.HistoryEntitySubscriber {
|
|
20
|
+
get entity() {
|
|
21
|
+
return figure_js_1.Figure;
|
|
22
|
+
}
|
|
23
|
+
get historyEntity() {
|
|
24
|
+
return figure_history_js_1.FigureHistory;
|
|
25
|
+
}
|
|
26
|
+
beforeInsertHistory(history, entity) {
|
|
27
|
+
;
|
|
28
|
+
history.comment = entity.__releaseComment ?? null;
|
|
29
|
+
return history;
|
|
30
|
+
}
|
|
31
|
+
beforeUpdateHistory(history, entity) {
|
|
32
|
+
;
|
|
33
|
+
history.comment = entity.__releaseComment ?? null;
|
|
34
|
+
return history;
|
|
35
|
+
}
|
|
36
|
+
async afterInsert(event) {
|
|
37
|
+
if (event.entity?.state == 'released') {
|
|
38
|
+
await super.afterInsert(event);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async afterUpdate(event) {
|
|
42
|
+
if (event.entity?.state == 'released') {
|
|
43
|
+
await super.afterUpdate(event);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
exports.FigureHistoryEntitySubscriber = FigureHistoryEntitySubscriber;
|
|
48
|
+
exports.FigureHistoryEntitySubscriber = FigureHistoryEntitySubscriber = tslib_1.__decorate([
|
|
49
|
+
(0, typeorm_1.EventSubscriber)()
|
|
50
|
+
], FigureHistoryEntitySubscriber);
|
|
51
|
+
//# sourceMappingURL=event-subscriber.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-subscriber.js","sourceRoot":"","sources":["../../../server/service/figure/event-subscriber.ts"],"names":[],"mappings":";;;;AAAA,qCAAyC;AAEzC,8DAAkE;AAElE,2CAAoC;AACpC,2DAAmD;AAEnD;;;;;;;;;GASG;AAEI,IAAM,6BAA6B,GAAnC,MAAM,6BAA8B,SAAQ,yCAA8C;IAC/F,IAAW,MAAM;QACf,OAAO,kBAAM,CAAA;IACf,CAAC;IAED,IAAW,aAAa;QACtB,OAAO,iCAAa,CAAA;IACtB,CAAC;IAEM,mBAAmB,CAAC,OAAsB,EAAE,MAAc;QAC/D,CAAC;QAAC,OAAe,CAAC,OAAO,GAAI,MAAc,CAAC,gBAAgB,IAAI,IAAI,CAAA;QACpE,OAAO,OAAO,CAAA;IAChB,CAAC;IAEM,mBAAmB,CAAC,OAAsB,EAAE,MAAc;QAC/D,CAAC;QAAC,OAAe,CAAC,OAAO,GAAI,MAAc,CAAC,gBAAgB,IAAI,IAAI,CAAA;QACpE,OAAO,OAAO,CAAA;IAChB,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,KAAU;QACjC,IAAI,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,UAAU,EAAE,CAAC;YACtC,MAAM,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;QAChC,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,KAAU;QACjC,IAAI,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,UAAU,EAAE,CAAC;YACtC,MAAM,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;QAChC,CAAC;IACH,CAAC;CACF,CAAA;AA9BY,sEAA6B;wCAA7B,6BAA6B;IADzC,IAAA,yBAAe,GAAE;GACL,6BAA6B,CA8BzC","sourcesContent":["import { EventSubscriber } from 'typeorm'\n\nimport { HistoryEntitySubscriber } from '@operato/typeorm-history'\n\nimport { Figure } from './figure.js'\nimport { FigureHistory } from './figure-history.js'\n\n/**\n * ํ๋ณธ์ ๋จ๊ธด๋ค โ **๋ฐํ๋ ์ ์ฅ์๋ง.**\n *\n * `@operato/typeorm-history` ๋ ์๋ ๋ชจ๋ ์ ์ฅ์ ๋ฒ ๋๋ค. ๊ทธ๋ฐ๋ฐ ๋ํ์ ์ ์ ์ค์ ์์ญ ๋ฒ ์ ์ฅ๋๊ณ ,\n * ๊ทธ ์ ๋ถ๋ฅผ ๋จ๊ธฐ๋ฉด ํ๋ณธ ๋ชฉ๋ก์ด ใ๋ด๊ฐ ์ค๋ ๋ช ๋ฒ ๋๋ ๋ใ๊ฐ ๋๋ค. ์ฌ๋์ด ํ์ด๋ผ๊ณ ๋ถ๋ฅด๋ ๊ฒ์\n * **๋ฐํํ ๊ฒ**์ด๋ฏ๋ก ๊ทธ๋๋ง ๋ฒ ๋๋ค. board ๊ฐ ๊ฐ์ ๊ท์น์ผ๋ก ๋๋ค(`board-service` ์ ๊ฐ์ ์ด๋ฆ ํ์ผ).\n *\n * ๋ฐํ ๋ฉ๋ชจ๋ Figure ์ ์นธ์ด ์๋๋ค. `releaseFigure` ๊ฐ ์ ์ฅํ ์ํฐํฐ์ `__releaseComment` ๋ก ์น์ด\n * ๋๋ฉด ์ฌ๊ธฐ์ ํ๋ณธ์ `comment` ๋ก ์ฎ๊ธด๋ค โ ๋ฉ๋ชจ๋ ๊ทธ ํ์ ๊ฒ์ด์ง ๋ํ์ ๊ฒ์ด ์๋๋ค.\n */\n@EventSubscriber()\nexport class FigureHistoryEntitySubscriber extends HistoryEntitySubscriber<Figure, FigureHistory> {\n public get entity() {\n return Figure\n }\n\n public get historyEntity() {\n return FigureHistory\n }\n\n public beforeInsertHistory(history: FigureHistory, entity: Figure): FigureHistory {\n ;(history as any).comment = (entity as any).__releaseComment ?? null\n return history\n }\n\n public beforeUpdateHistory(history: FigureHistory, entity: Figure): FigureHistory {\n ;(history as any).comment = (entity as any).__releaseComment ?? null\n return history\n }\n\n public async afterInsert(event: any): Promise<void> {\n if (event.entity?.state == 'released') {\n await super.afterInsert(event)\n }\n }\n\n public async afterUpdate(event: any): Promise<void> {\n if (event.entity?.state == 'released') {\n await super.afterUpdate(event)\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ๋ฐํํด๋ ๋๋ โ **์๋ฒ๊ฐ ํ์ ํ๋ค.**
|
|
3
|
+
*
|
|
4
|
+
* ## ์ ์๋ฒ์ธ๊ฐ
|
|
5
|
+
*
|
|
6
|
+
* ์ด ๊ฒ์ฌ๋ ๋ธ๋ผ์ฐ์ ํ๋ค์ค์๋ง ์์๋ค(`test/browser/check-figure-scaling.mjs`). ์ฌ๋์ด ๋๋ฆด ๋๋ง
|
|
7
|
+
* ๋์๊ณ , ๋ฐํ ๊ฒฝ๋ก์๋ ์๋ฌด ๊ฒ์ฌ๋ ์์๋ค โ ํ์๋ง ๋ง์ผ๋ฉด ๋ฌด์์ด๋ ๋ฐํ๋์๋ค. ๋ฐํ์ ์๋น์ฒ์๊ฒ
|
|
8
|
+
* ํ๋ ์ฝ์์ด๋ฏ๋ก, ๊ทธ ์ฝ์์ ์งํฌ ์ ์๋์ง๋ ์ฝ์ํ๋ ์๋ฆฌ๊ฐ ์ฌ์ผ ํ๋ค.
|
|
9
|
+
*
|
|
10
|
+
* ## ๋ฌด์์ ๋ง๊ณ ๋ฌด์์ ์๋ฆฌ๋
|
|
11
|
+
*
|
|
12
|
+
* ํ์ ์ `figure-model` ์ `gate.ts` ๊ฐ ์ด๋ฏธ ๋ฌธ์๋ก ์ ํด ๋์๋ค. ์ฌ๊ธฐ์ ์๋ก ์ ํ์ง ์๋๋ค.
|
|
13
|
+
*
|
|
14
|
+
* sizing-splits ํฌ๊ธฐ๋ฅผ ๋ฐ๊พธ๋ฉด ์กฐ๊ฐ์ด ๊ฐ๋ผ์ง๋ค **๋ง๋๋ค**
|
|
15
|
+
* sizing-loose 1๋ฐฐ์์ ์ด๋ฏธ ์ฌ๋ฌ ์กฐ๊ฐ์ด๋ค ์๋ฆฐ๋ค
|
|
16
|
+
* violations ํ์์ด ๊ถํ์ง ์๋ ๊ฒ ์๋ฆฐ๋ค (์ ์ฅ ๋ ์ด๋ฏธ ๋ณด์ฌ ์ค ๊ฒ๋ค)
|
|
17
|
+
*
|
|
18
|
+
* ๊ฐ๋ผ์ง์ ๋ง๋ ์ด์ ๋ ์ฌ๋ ๋์ ใ๋ถ์์ก๋คใ๋ก ๋ณด์ด๊ธฐ ๋๋ฌธ์ด๋ค โ ์๊ทธ๋ํ์๋ฅผ 3๋ฐฐ๋ก ์ธ์ฐ๋ ๋จํ๊ฐ
|
|
19
|
+
* ๊ธฐ๋ฅ ์ ๊ณต์ค์ ๋ด๋ ๊ทธ๊ฒ์ด๊ณ , ์ต์ปค ๊ท์น์ด ์๊ธด ์ด์ ๋ค. ์๋น์ฒ๊ฐ ํ์์ ๋๋ ค ์ฐ๋ ๊ฒ์ ๋ง์ ์
|
|
20
|
+
* ์์ผ๋(๊ทธ๊ฒ์ด ์ด ํ์์ ๊ฐ์ด๋ค), ๋๋ ค๋ ๊ฒฌ๋๋์ง๋ฅผ ๋ฐํ ์ ์ ๋ณธ๋ค.
|
|
21
|
+
*
|
|
22
|
+
* ## ์ฌ ๋ณธ ๊ฐ
|
|
23
|
+
*
|
|
24
|
+
* [ํ์ธํจ] 2026-09-09 ยท ํ๋ณธ 15๊ฐ(์๋ 14 + ์ ์ 1)
|
|
25
|
+
* ํ์ ์ค๋ฅ 0 ยท 1๋ฐฐ ๋ถ๋ฆฌ 0 ยท **๊ฐ๋ผ์ง 1**(MIXER, zยทy-z ์กฐํฉ) ยท ์กฐ์ฉํจ 14
|
|
26
|
+
*
|
|
27
|
+
* ๊ฒ์ดํธ๊ฐ ๋ฒฝ์ด ์๋๋ผ๋ ๋ป์ด๋ค. ์ด๋ท์ ๊ทธ๋๋ก ๋ฐํ๋๊ณ , ํ๋๋ ๊ณ ์น ๊ฒ์ด ์๋ค.
|
|
28
|
+
*/
|
|
29
|
+
/** ๊ฒ์ดํธ๊ฐ ๋ธ ํ ๊ฐ์ง. `blocking` ์ด ์ฐธ์ด๋ฉด ๋ฐํ์ด ์ ๋๋ค. */
|
|
30
|
+
export interface GateFinding {
|
|
31
|
+
code: string;
|
|
32
|
+
message: string;
|
|
33
|
+
/**
|
|
34
|
+
* **์ ๊ทธ๊ฒ์ด ๋ฌธ์ ์ธ๊ฐ.** ์ฐ ๊ฒ๋ง ๋ณด์ฌ ์ฃผ๋ฉด ์ฝ๋ ์ฌ๋์ด ใ๊ทธ๋์?ใ์์ ๋ฉ์ถ๋ค โ ํ๋ฉด์
|
|
35
|
+
* ใ1 ์กฐ๊ฐ์ด 2 ์กฐ๊ฐ์ผ๋ก ๊ฐ๋ผ์ง๋คใ๋ง ๋ด์ ๋ ์ค์ ๋ก ๊ทธ๋ฌ๋ค.
|
|
36
|
+
*/
|
|
37
|
+
why?: string;
|
|
38
|
+
/** **๋ฌด์์ ๋ฐ๊พธ๋ฉด ๋๋.** ๋ถํ ์ด๋ฆ๊ณผ ๊ฐ์ผ๋ก. ํ์์ด ๋ง๋ ๋ฌธ์ฅ์ ๊ทธ๋๋ก ์ฎ๊ธด๋ค. */
|
|
39
|
+
how?: string;
|
|
40
|
+
/** ์ด๋๋ฅผ ๊ฐ๋ฆฌํค๋ โ ๊ฐ๋ผ์ง์ ๊ฐ๋ผ์ง ๋ถํ ์ด๋ฆ๋ค, ํ์ ์๋ฐ์ ์ ๋ณธ ์์ ๊ฒฝ๋ก. */
|
|
41
|
+
at?: string;
|
|
42
|
+
blocking: boolean;
|
|
43
|
+
}
|
|
44
|
+
export interface Inspection {
|
|
45
|
+
findings: GateFinding[];
|
|
46
|
+
/** ๋ง๋ ๊ฒ์ด ํ๋๋ผ๋ ์๋. ํ๋ฉด์ด ์ด๊ฒ์ผ๋ก ๋จ์ถ๋ฅผ ์ ๊ทผ๋ค. */
|
|
47
|
+
blocked: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* ์ ๋ณธ ํ๋๋ฅผ ํ์ ํ๋ค.
|
|
51
|
+
*
|
|
52
|
+
* ์ ๋ณธ์ด ์๊ฑฐ๋(์์ง ์ ์ฅ ์ ) JSON ์ด ์๋๋ฉด **๋ง๋๋ค** โ ๋ฐํํ ๋์์ด ์๋ ๊ฒ์ด๋ค. ๊ทธ ๊ฒฝ์ฐ๋ฅผ
|
|
53
|
+
* ์กฐ์ฉํ ํต๊ณผ์ํค๋ฉด ๋น ๊ฒ์ด ๋ฐํ๋๋ค.
|
|
54
|
+
*/
|
|
55
|
+
export declare function inspectSource(sourceJson?: string | null): Inspection;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.inspectSource = inspectSource;
|
|
4
|
+
const figure_model_1 = require("@hatiolab/figure-model");
|
|
5
|
+
/**
|
|
6
|
+
* ์ ๋ณธ ํ๋๋ฅผ ํ์ ํ๋ค.
|
|
7
|
+
*
|
|
8
|
+
* ์ ๋ณธ์ด ์๊ฑฐ๋(์์ง ์ ์ฅ ์ ) JSON ์ด ์๋๋ฉด **๋ง๋๋ค** โ ๋ฐํํ ๋์์ด ์๋ ๊ฒ์ด๋ค. ๊ทธ ๊ฒฝ์ฐ๋ฅผ
|
|
9
|
+
* ์กฐ์ฉํ ํต๊ณผ์ํค๋ฉด ๋น ๊ฒ์ด ๋ฐํ๋๋ค.
|
|
10
|
+
*/
|
|
11
|
+
function inspectSource(sourceJson) {
|
|
12
|
+
if (!sourceJson) {
|
|
13
|
+
return {
|
|
14
|
+
blocked: true,
|
|
15
|
+
findings: [
|
|
16
|
+
{
|
|
17
|
+
code: 'no-source',
|
|
18
|
+
message: '์ ์ฅ๋ ์ ๋ณธ์ด ์๋ค. ์ ์ฅํ๋ฉด ๋ฐํํ ์ ์๋ค',
|
|
19
|
+
blocking: true
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
let parsed;
|
|
25
|
+
try {
|
|
26
|
+
parsed = JSON.parse(sourceJson);
|
|
27
|
+
}
|
|
28
|
+
catch (e) {
|
|
29
|
+
return {
|
|
30
|
+
blocked: true,
|
|
31
|
+
findings: [{ code: 'source-not-json', message: `์ ๋ณธ์ด JSON ์ด ์๋๋ค: ${e.message}`, blocking: true }]
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const result = (0, figure_model_1.validate)(parsed);
|
|
35
|
+
const findings = [];
|
|
36
|
+
/*
|
|
37
|
+
ํ์ ์ค๋ฅ๋ **์ ์ฅ์ ํต๊ณผํ ์ ์๋ค**(`parseSource` ๊ฐ ๊ฑฐ์ ํ๋ค). ๊ทธ๋๋ ์ฌ๊ธฐ์ ๋ค์ ๋ณด๋ ์ด์ ๋,
|
|
38
|
+
์ด ํ์ ์ด ์ ์ฅ ๊ฒฝ๋ก์ ๋
๋ฆฝ์ด์ด์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค โ ์ ์ ๋ณธ์ด ๋จ์ ์๊ฑฐ๋ ํ์์ด ์ํด์ง ๋ค๋ผ๋ฉด
|
|
39
|
+
์ ์ฅ ๋๋ ๋ง์๋ ๊ฒ์ด ์ง๊ธ์ ํ๋ฆด ์ ์๋ค. ๊ทธ๋ ๋ฐํ์ด ํต๊ณผํ๋ฉด ์ ๋๋ค.
|
|
40
|
+
*/
|
|
41
|
+
for (const error of result.errors) {
|
|
42
|
+
findings.push({ code: error.code, message: error.message, at: error.path, blocking: true });
|
|
43
|
+
}
|
|
44
|
+
for (const violation of result.violations) {
|
|
45
|
+
findings.push({ code: violation.code, message: violation.message, blocking: false });
|
|
46
|
+
}
|
|
47
|
+
if (result.errors.length === 0) {
|
|
48
|
+
const report = (0, figure_model_1.sizingReport)((0, figure_model_1.compile)(parsed));
|
|
49
|
+
for (const finding of report.findings) {
|
|
50
|
+
findings.push({
|
|
51
|
+
code: finding.code,
|
|
52
|
+
message: finding.message,
|
|
53
|
+
/* ์ยท์ด๋ป๊ฒ๋ ํ์์ด ์์ ํ๋ค. ์๋ฒ๊ฐ ๋ค์ ์ฐ๋ฉด ๋ ๋ฒ์ด ๋๊ณ ๊ณง ์ด๊ธ๋๋ค. */
|
|
54
|
+
why: finding.why,
|
|
55
|
+
how: finding.how,
|
|
56
|
+
/* ์ซ์๊ฐ ์๋๋ผ ์๋ฆฌ๋ฅผ ๋งํ๋ค โ ์ด๋ ๋ถํ๋ค์ด ๊ฐ๋ผ์ ธ ๋์๋. */
|
|
57
|
+
at: finding.clumps.map(clump => [...clump].sort().join('+')).join(' | ') || undefined,
|
|
58
|
+
blocking: finding.code === 'sizing-splits'
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return { findings, blocked: findings.some(finding => finding.blocking) };
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=figure-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"figure-gate.js","sourceRoot":"","sources":["../../../server/service/figure/figure-gate.ts"],"names":[],"mappings":";;AA4DA,sCA0DC;AAtHD,yDAAwE;AAsDxE;;;;;GAKG;AACH,SAAgB,aAAa,CAAC,UAA0B;IACtD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO;YACL,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,WAAW;oBACjB,OAAO,EAAE,2BAA2B;oBACpC,QAAQ,EAAE,IAAI;iBACf;aACF;SACF,CAAA;IACH,CAAC;IAED,IAAI,MAAe,CAAA;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;IACjC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO;YACL,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,mBAAoB,CAAW,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;SAC5G,CAAA;IACH,CAAC;IAED,MAAM,MAAM,GAAG,IAAA,uBAAQ,EAAC,MAAM,CAAC,CAAA;IAC/B,MAAM,QAAQ,GAAkB,EAAE,CAAA;IAElC;;;;MAIE;IACF,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7F,CAAC;IAED,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QAC1C,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;IACtF,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,IAAA,2BAAY,EAAC,IAAA,sBAAO,EAAC,MAAsB,CAAC,CAAC,CAAA;QAE5D,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACtC,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,gDAAgD;gBAChD,GAAG,EAAE,OAAO,CAAC,GAAG;gBAChB,GAAG,EAAE,OAAO,CAAC,GAAG;gBAChB,wCAAwC;gBACxC,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,SAAS;gBACrF,QAAQ,EAAE,OAAO,CAAC,IAAI,KAAK,eAAe;aAC3C,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAA;AAC1E,CAAC","sourcesContent":["import { compile, sizingReport, validate } from '@hatiolab/figure-model'\nimport type { FigureSource } from '@hatiolab/figure-model'\n\n/**\n * ๋ฐํํด๋ ๋๋ โ **์๋ฒ๊ฐ ํ์ ํ๋ค.**\n *\n * ## ์ ์๋ฒ์ธ๊ฐ\n *\n * ์ด ๊ฒ์ฌ๋ ๋ธ๋ผ์ฐ์ ํ๋ค์ค์๋ง ์์๋ค(`test/browser/check-figure-scaling.mjs`). ์ฌ๋์ด ๋๋ฆด ๋๋ง\n * ๋์๊ณ , ๋ฐํ ๊ฒฝ๋ก์๋ ์๋ฌด ๊ฒ์ฌ๋ ์์๋ค โ ํ์๋ง ๋ง์ผ๋ฉด ๋ฌด์์ด๋ ๋ฐํ๋์๋ค. ๋ฐํ์ ์๋น์ฒ์๊ฒ\n * ํ๋ ์ฝ์์ด๋ฏ๋ก, ๊ทธ ์ฝ์์ ์งํฌ ์ ์๋์ง๋ ์ฝ์ํ๋ ์๋ฆฌ๊ฐ ์ฌ์ผ ํ๋ค.\n *\n * ## ๋ฌด์์ ๋ง๊ณ ๋ฌด์์ ์๋ฆฌ๋\n *\n * ํ์ ์ `figure-model` ์ `gate.ts` ๊ฐ ์ด๋ฏธ ๋ฌธ์๋ก ์ ํด ๋์๋ค. ์ฌ๊ธฐ์ ์๋ก ์ ํ์ง ์๋๋ค.\n *\n * sizing-splits ํฌ๊ธฐ๋ฅผ ๋ฐ๊พธ๋ฉด ์กฐ๊ฐ์ด ๊ฐ๋ผ์ง๋ค **๋ง๋๋ค**\n * sizing-loose 1๋ฐฐ์์ ์ด๋ฏธ ์ฌ๋ฌ ์กฐ๊ฐ์ด๋ค ์๋ฆฐ๋ค\n * violations ํ์์ด ๊ถํ์ง ์๋ ๊ฒ ์๋ฆฐ๋ค (์ ์ฅ ๋ ์ด๋ฏธ ๋ณด์ฌ ์ค ๊ฒ๋ค)\n *\n * ๊ฐ๋ผ์ง์ ๋ง๋ ์ด์ ๋ ์ฌ๋ ๋์ ใ๋ถ์์ก๋คใ๋ก ๋ณด์ด๊ธฐ ๋๋ฌธ์ด๋ค โ ์๊ทธ๋ํ์๋ฅผ 3๋ฐฐ๋ก ์ธ์ฐ๋ ๋จํ๊ฐ\n * ๊ธฐ๋ฅ ์ ๊ณต์ค์ ๋ด๋ ๊ทธ๊ฒ์ด๊ณ , ์ต์ปค ๊ท์น์ด ์๊ธด ์ด์ ๋ค. ์๋น์ฒ๊ฐ ํ์์ ๋๋ ค ์ฐ๋ ๊ฒ์ ๋ง์ ์\n * ์์ผ๋(๊ทธ๊ฒ์ด ์ด ํ์์ ๊ฐ์ด๋ค), ๋๋ ค๋ ๊ฒฌ๋๋์ง๋ฅผ ๋ฐํ ์ ์ ๋ณธ๋ค.\n *\n * ## ์ฌ ๋ณธ ๊ฐ\n *\n * [ํ์ธํจ] 2026-09-09 ยท ํ๋ณธ 15๊ฐ(์๋ 14 + ์ ์ 1)\n * ํ์ ์ค๋ฅ 0 ยท 1๋ฐฐ ๋ถ๋ฆฌ 0 ยท **๊ฐ๋ผ์ง 1**(MIXER, zยทy-z ์กฐํฉ) ยท ์กฐ์ฉํจ 14\n *\n * ๊ฒ์ดํธ๊ฐ ๋ฒฝ์ด ์๋๋ผ๋ ๋ป์ด๋ค. ์ด๋ท์ ๊ทธ๋๋ก ๋ฐํ๋๊ณ , ํ๋๋ ๊ณ ์น ๊ฒ์ด ์๋ค.\n */\n\n/** ๊ฒ์ดํธ๊ฐ ๋ธ ํ ๊ฐ์ง. `blocking` ์ด ์ฐธ์ด๋ฉด ๋ฐํ์ด ์ ๋๋ค. */\nexport interface GateFinding {\n code: string\n message: string\n /**\n * **์ ๊ทธ๊ฒ์ด ๋ฌธ์ ์ธ๊ฐ.** ์ฐ ๊ฒ๋ง ๋ณด์ฌ ์ฃผ๋ฉด ์ฝ๋ ์ฌ๋์ด ใ๊ทธ๋์?ใ์์ ๋ฉ์ถ๋ค โ ํ๋ฉด์\n * ใ1 ์กฐ๊ฐ์ด 2 ์กฐ๊ฐ์ผ๋ก ๊ฐ๋ผ์ง๋คใ๋ง ๋ด์ ๋ ์ค์ ๋ก ๊ทธ๋ฌ๋ค.\n */\n why?: string\n /** **๋ฌด์์ ๋ฐ๊พธ๋ฉด ๋๋.** ๋ถํ ์ด๋ฆ๊ณผ ๊ฐ์ผ๋ก. ํ์์ด ๋ง๋ ๋ฌธ์ฅ์ ๊ทธ๋๋ก ์ฎ๊ธด๋ค. */\n how?: string\n /** ์ด๋๋ฅผ ๊ฐ๋ฆฌํค๋ โ ๊ฐ๋ผ์ง์ ๊ฐ๋ผ์ง ๋ถํ ์ด๋ฆ๋ค, ํ์ ์๋ฐ์ ์ ๋ณธ ์์ ๊ฒฝ๋ก. */\n at?: string\n blocking: boolean\n}\n\nexport interface Inspection {\n findings: GateFinding[]\n /** ๋ง๋ ๊ฒ์ด ํ๋๋ผ๋ ์๋. ํ๋ฉด์ด ์ด๊ฒ์ผ๋ก ๋จ์ถ๋ฅผ ์ ๊ทผ๋ค. */\n blocked: boolean\n}\n\n/**\n * ์ ๋ณธ ํ๋๋ฅผ ํ์ ํ๋ค.\n *\n * ์ ๋ณธ์ด ์๊ฑฐ๋(์์ง ์ ์ฅ ์ ) JSON ์ด ์๋๋ฉด **๋ง๋๋ค** โ ๋ฐํํ ๋์์ด ์๋ ๊ฒ์ด๋ค. ๊ทธ ๊ฒฝ์ฐ๋ฅผ\n * ์กฐ์ฉํ ํต๊ณผ์ํค๋ฉด ๋น ๊ฒ์ด ๋ฐํ๋๋ค.\n */\nexport function inspectSource(sourceJson?: string | null): Inspection {\n if (!sourceJson) {\n return {\n blocked: true,\n findings: [\n {\n code: 'no-source',\n message: '์ ์ฅ๋ ์ ๋ณธ์ด ์๋ค. ์ ์ฅํ๋ฉด ๋ฐํํ ์ ์๋ค',\n blocking: true\n }\n ]\n }\n }\n\n let parsed: unknown\n try {\n parsed = JSON.parse(sourceJson)\n } catch (e) {\n return {\n blocked: true,\n findings: [{ code: 'source-not-json', message: `์ ๋ณธ์ด JSON ์ด ์๋๋ค: ${(e as Error).message}`, blocking: true }]\n }\n }\n\n const result = validate(parsed)\n const findings: GateFinding[] = []\n\n /*\n ํ์ ์ค๋ฅ๋ **์ ์ฅ์ ํต๊ณผํ ์ ์๋ค**(`parseSource` ๊ฐ ๊ฑฐ์ ํ๋ค). ๊ทธ๋๋ ์ฌ๊ธฐ์ ๋ค์ ๋ณด๋ ์ด์ ๋,\n ์ด ํ์ ์ด ์ ์ฅ ๊ฒฝ๋ก์ ๋
๋ฆฝ์ด์ด์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค โ ์ ์ ๋ณธ์ด ๋จ์ ์๊ฑฐ๋ ํ์์ด ์ํด์ง ๋ค๋ผ๋ฉด\n ์ ์ฅ ๋๋ ๋ง์๋ ๊ฒ์ด ์ง๊ธ์ ํ๋ฆด ์ ์๋ค. ๊ทธ๋ ๋ฐํ์ด ํต๊ณผํ๋ฉด ์ ๋๋ค.\n */\n for (const error of result.errors) {\n findings.push({ code: error.code, message: error.message, at: error.path, blocking: true })\n }\n\n for (const violation of result.violations) {\n findings.push({ code: violation.code, message: violation.message, blocking: false })\n }\n\n if (result.errors.length === 0) {\n const report = sizingReport(compile(parsed as FigureSource))\n\n for (const finding of report.findings) {\n findings.push({\n code: finding.code,\n message: finding.message,\n /* ์ยท์ด๋ป๊ฒ๋ ํ์์ด ์์ ํ๋ค. ์๋ฒ๊ฐ ๋ค์ ์ฐ๋ฉด ๋ ๋ฒ์ด ๋๊ณ ๊ณง ์ด๊ธ๋๋ค. */\n why: finding.why,\n how: finding.how,\n /* ์ซ์๊ฐ ์๋๋ผ ์๋ฆฌ๋ฅผ ๋งํ๋ค โ ์ด๋ ๋ถํ๋ค์ด ๊ฐ๋ผ์ ธ ๋์๋. */\n at: finding.clumps.map(clump => [...clump].sort().join('+')).join(' | ') || undefined,\n blocking: finding.code === 'sizing-splits'\n })\n }\n }\n\n return { findings, blocked: findings.some(finding => finding.blocking) }\n}\n"]}
|