commit
1229a8a92e
14 changed files with 1248 additions and 0 deletions
@ -0,0 +1,13 @@ |
|||||||
|
# Notion |
||||||
|
NOTION_API_KEY=secret_xxx |
||||||
|
NOTION_DATABASE_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx |
||||||
|
NOTION_PROP_STATUS=상태 |
||||||
|
NOTION_PROP_PROGRESS=진행률 |
||||||
|
NOTION_STATUS_DONE=완료 |
||||||
|
|
||||||
|
# Gitea |
||||||
|
GITEA_WEBHOOK_SECRET=your-secret |
||||||
|
|
||||||
|
# Server |
||||||
|
PORT=3000 |
||||||
|
LOG_LEVEL=info |
||||||
@ -0,0 +1,12 @@ |
|||||||
|
FROM node:20-alpine |
||||||
|
|
||||||
|
WORKDIR /app |
||||||
|
|
||||||
|
COPY package.json package-lock.json* ./ |
||||||
|
RUN npm ci --omit=dev |
||||||
|
|
||||||
|
COPY src/ ./src/ |
||||||
|
|
||||||
|
EXPOSE 3000 |
||||||
|
|
||||||
|
CMD ["node", "src/index.js"] |
||||||
@ -0,0 +1,11 @@ |
|||||||
|
name: gitea-notion-bridge |
||||||
|
|
||||||
|
services: |
||||||
|
bridge: |
||||||
|
build: . |
||||||
|
container_name: gitea-notion-bridge |
||||||
|
ports: |
||||||
|
- "3800:3000" |
||||||
|
env_file: |
||||||
|
- .env |
||||||
|
restart: always |
||||||
@ -0,0 +1,16 @@ |
|||||||
|
{ |
||||||
|
"name": "gitea-notion-bridge", |
||||||
|
"version": "1.0.0", |
||||||
|
"description": "Gitea webhook → Notion DB 상태 자동 업데이트 중계 서버", |
||||||
|
"main": "src/index.js", |
||||||
|
"scripts": { |
||||||
|
"start": "node src/index.js", |
||||||
|
"dev": "node --watch src/index.js" |
||||||
|
}, |
||||||
|
"dependencies": { |
||||||
|
"@notionhq/client": "^2.2.15", |
||||||
|
"express": "^4.21.0", |
||||||
|
"pino": "^9.4.0", |
||||||
|
"pino-pretty": "^11.2.0" |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,947 @@ |
|||||||
|
lockfileVersion: '9.0' |
||||||
|
|
||||||
|
settings: |
||||||
|
autoInstallPeers: true |
||||||
|
excludeLinksFromLockfile: false |
||||||
|
|
||||||
|
importers: |
||||||
|
|
||||||
|
.: |
||||||
|
dependencies: |
||||||
|
'@notionhq/client': |
||||||
|
specifier: ^2.2.15 |
||||||
|
version: 2.3.0 |
||||||
|
express: |
||||||
|
specifier: ^4.21.0 |
||||||
|
version: 4.22.1 |
||||||
|
pino: |
||||||
|
specifier: ^9.4.0 |
||||||
|
version: 9.14.0 |
||||||
|
pino-pretty: |
||||||
|
specifier: ^11.2.0 |
||||||
|
version: 11.3.0 |
||||||
|
|
||||||
|
packages: |
||||||
|
|
||||||
|
'@notionhq/client@2.3.0': |
||||||
|
resolution: {integrity: sha512-l7WqTCpQqC+HibkB9chghONQTYcxNQT0/rOJemBfmuKQRTu2vuV8B3yA395iKaUdDo7HI+0KvQaz9687Xskzkw==} |
||||||
|
engines: {node: '>=12'} |
||||||
|
|
||||||
|
'@pinojs/redact@0.4.0': |
||||||
|
resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} |
||||||
|
|
||||||
|
'@types/node-fetch@2.6.13': |
||||||
|
resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} |
||||||
|
|
||||||
|
'@types/node@25.5.0': |
||||||
|
resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} |
||||||
|
|
||||||
|
abort-controller@3.0.0: |
||||||
|
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} |
||||||
|
engines: {node: '>=6.5'} |
||||||
|
|
||||||
|
accepts@1.3.8: |
||||||
|
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} |
||||||
|
engines: {node: '>= 0.6'} |
||||||
|
|
||||||
|
array-flatten@1.1.1: |
||||||
|
resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} |
||||||
|
|
||||||
|
asynckit@0.4.0: |
||||||
|
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} |
||||||
|
|
||||||
|
atomic-sleep@1.0.0: |
||||||
|
resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} |
||||||
|
engines: {node: '>=8.0.0'} |
||||||
|
|
||||||
|
base64-js@1.5.1: |
||||||
|
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} |
||||||
|
|
||||||
|
body-parser@1.20.4: |
||||||
|
resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==} |
||||||
|
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} |
||||||
|
|
||||||
|
buffer@6.0.3: |
||||||
|
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} |
||||||
|
|
||||||
|
bytes@3.1.2: |
||||||
|
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} |
||||||
|
engines: {node: '>= 0.8'} |
||||||
|
|
||||||
|
call-bind-apply-helpers@1.0.2: |
||||||
|
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} |
||||||
|
engines: {node: '>= 0.4'} |
||||||
|
|
||||||
|
call-bound@1.0.4: |
||||||
|
resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} |
||||||
|
engines: {node: '>= 0.4'} |
||||||
|
|
||||||
|
colorette@2.0.20: |
||||||
|
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} |
||||||
|
|
||||||
|
combined-stream@1.0.8: |
||||||
|
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} |
||||||
|
engines: {node: '>= 0.8'} |
||||||
|
|
||||||
|
content-disposition@0.5.4: |
||||||
|
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} |
||||||
|
engines: {node: '>= 0.6'} |
||||||
|
|
||||||
|
content-type@1.0.5: |
||||||
|
resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} |
||||||
|
engines: {node: '>= 0.6'} |
||||||
|
|
||||||
|
cookie-signature@1.0.7: |
||||||
|
resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==} |
||||||
|
|
||||||
|
cookie@0.7.2: |
||||||
|
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} |
||||||
|
engines: {node: '>= 0.6'} |
||||||
|
|
||||||
|
dateformat@4.6.3: |
||||||
|
resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} |
||||||
|
|
||||||
|
debug@2.6.9: |
||||||
|
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} |
||||||
|
peerDependencies: |
||||||
|
supports-color: '*' |
||||||
|
peerDependenciesMeta: |
||||||
|
supports-color: |
||||||
|
optional: true |
||||||
|
|
||||||
|
delayed-stream@1.0.0: |
||||||
|
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} |
||||||
|
engines: {node: '>=0.4.0'} |
||||||
|
|
||||||
|
depd@2.0.0: |
||||||
|
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} |
||||||
|
engines: {node: '>= 0.8'} |
||||||
|
|
||||||
|
destroy@1.2.0: |
||||||
|
resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} |
||||||
|
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} |
||||||
|
|
||||||
|
dunder-proto@1.0.1: |
||||||
|
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} |
||||||
|
engines: {node: '>= 0.4'} |
||||||
|
|
||||||
|
ee-first@1.1.1: |
||||||
|
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} |
||||||
|
|
||||||
|
encodeurl@2.0.0: |
||||||
|
resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} |
||||||
|
engines: {node: '>= 0.8'} |
||||||
|
|
||||||
|
end-of-stream@1.4.5: |
||||||
|
resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} |
||||||
|
|
||||||
|
es-define-property@1.0.1: |
||||||
|
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} |
||||||
|
engines: {node: '>= 0.4'} |
||||||
|
|
||||||
|
es-errors@1.3.0: |
||||||
|
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} |
||||||
|
engines: {node: '>= 0.4'} |
||||||
|
|
||||||
|
es-object-atoms@1.1.1: |
||||||
|
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} |
||||||
|
engines: {node: '>= 0.4'} |
||||||
|
|
||||||
|
es-set-tostringtag@2.1.0: |
||||||
|
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} |
||||||
|
engines: {node: '>= 0.4'} |
||||||
|
|
||||||
|
escape-html@1.0.3: |
||||||
|
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} |
||||||
|
|
||||||
|
etag@1.8.1: |
||||||
|
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} |
||||||
|
engines: {node: '>= 0.6'} |
||||||
|
|
||||||
|
event-target-shim@5.0.1: |
||||||
|
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} |
||||||
|
engines: {node: '>=6'} |
||||||
|
|
||||||
|
events@3.3.0: |
||||||
|
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} |
||||||
|
engines: {node: '>=0.8.x'} |
||||||
|
|
||||||
|
express@4.22.1: |
||||||
|
resolution: {integrity: sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==} |
||||||
|
engines: {node: '>= 0.10.0'} |
||||||
|
|
||||||
|
fast-copy@3.0.2: |
||||||
|
resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==} |
||||||
|
|
||||||
|
fast-safe-stringify@2.1.1: |
||||||
|
resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} |
||||||
|
|
||||||
|
finalhandler@1.3.2: |
||||||
|
resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} |
||||||
|
engines: {node: '>= 0.8'} |
||||||
|
|
||||||
|
form-data@4.0.5: |
||||||
|
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} |
||||||
|
engines: {node: '>= 6'} |
||||||
|
|
||||||
|
forwarded@0.2.0: |
||||||
|
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} |
||||||
|
engines: {node: '>= 0.6'} |
||||||
|
|
||||||
|
fresh@0.5.2: |
||||||
|
resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} |
||||||
|
engines: {node: '>= 0.6'} |
||||||
|
|
||||||
|
function-bind@1.1.2: |
||||||
|
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} |
||||||
|
|
||||||
|
get-intrinsic@1.3.0: |
||||||
|
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} |
||||||
|
engines: {node: '>= 0.4'} |
||||||
|
|
||||||
|
get-proto@1.0.1: |
||||||
|
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} |
||||||
|
engines: {node: '>= 0.4'} |
||||||
|
|
||||||
|
gopd@1.2.0: |
||||||
|
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} |
||||||
|
engines: {node: '>= 0.4'} |
||||||
|
|
||||||
|
has-symbols@1.1.0: |
||||||
|
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} |
||||||
|
engines: {node: '>= 0.4'} |
||||||
|
|
||||||
|
has-tostringtag@1.0.2: |
||||||
|
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} |
||||||
|
engines: {node: '>= 0.4'} |
||||||
|
|
||||||
|
hasown@2.0.2: |
||||||
|
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} |
||||||
|
engines: {node: '>= 0.4'} |
||||||
|
|
||||||
|
help-me@5.0.0: |
||||||
|
resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} |
||||||
|
|
||||||
|
http-errors@2.0.1: |
||||||
|
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} |
||||||
|
engines: {node: '>= 0.8'} |
||||||
|
|
||||||
|
iconv-lite@0.4.24: |
||||||
|
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} |
||||||
|
engines: {node: '>=0.10.0'} |
||||||
|
|
||||||
|
ieee754@1.2.1: |
||||||
|
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} |
||||||
|
|
||||||
|
inherits@2.0.4: |
||||||
|
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} |
||||||
|
|
||||||
|
ipaddr.js@1.9.1: |
||||||
|
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} |
||||||
|
engines: {node: '>= 0.10'} |
||||||
|
|
||||||
|
joycon@3.1.1: |
||||||
|
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} |
||||||
|
engines: {node: '>=10'} |
||||||
|
|
||||||
|
math-intrinsics@1.1.0: |
||||||
|
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} |
||||||
|
engines: {node: '>= 0.4'} |
||||||
|
|
||||||
|
media-typer@0.3.0: |
||||||
|
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} |
||||||
|
engines: {node: '>= 0.6'} |
||||||
|
|
||||||
|
merge-descriptors@1.0.3: |
||||||
|
resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} |
||||||
|
|
||||||
|
methods@1.1.2: |
||||||
|
resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} |
||||||
|
engines: {node: '>= 0.6'} |
||||||
|
|
||||||
|
mime-db@1.52.0: |
||||||
|
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} |
||||||
|
engines: {node: '>= 0.6'} |
||||||
|
|
||||||
|
mime-types@2.1.35: |
||||||
|
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} |
||||||
|
engines: {node: '>= 0.6'} |
||||||
|
|
||||||
|
mime@1.6.0: |
||||||
|
resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} |
||||||
|
engines: {node: '>=4'} |
||||||
|
hasBin: true |
||||||
|
|
||||||
|
minimist@1.2.8: |
||||||
|
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} |
||||||
|
|
||||||
|
ms@2.0.0: |
||||||
|
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} |
||||||
|
|
||||||
|
ms@2.1.3: |
||||||
|
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} |
||||||
|
|
||||||
|
negotiator@0.6.3: |
||||||
|
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} |
||||||
|
engines: {node: '>= 0.6'} |
||||||
|
|
||||||
|
node-fetch@2.7.0: |
||||||
|
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} |
||||||
|
engines: {node: 4.x || >=6.0.0} |
||||||
|
peerDependencies: |
||||||
|
encoding: ^0.1.0 |
||||||
|
peerDependenciesMeta: |
||||||
|
encoding: |
||||||
|
optional: true |
||||||
|
|
||||||
|
object-inspect@1.13.4: |
||||||
|
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} |
||||||
|
engines: {node: '>= 0.4'} |
||||||
|
|
||||||
|
on-exit-leak-free@2.1.2: |
||||||
|
resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} |
||||||
|
engines: {node: '>=14.0.0'} |
||||||
|
|
||||||
|
on-finished@2.4.1: |
||||||
|
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} |
||||||
|
engines: {node: '>= 0.8'} |
||||||
|
|
||||||
|
once@1.4.0: |
||||||
|
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} |
||||||
|
|
||||||
|
parseurl@1.3.3: |
||||||
|
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} |
||||||
|
engines: {node: '>= 0.8'} |
||||||
|
|
||||||
|
path-to-regexp@0.1.13: |
||||||
|
resolution: {integrity: sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==} |
||||||
|
|
||||||
|
pino-abstract-transport@2.0.0: |
||||||
|
resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} |
||||||
|
|
||||||
|
pino-pretty@11.3.0: |
||||||
|
resolution: {integrity: sha512-oXwn7ICywaZPHmu3epHGU2oJX4nPmKvHvB/bwrJHlGcbEWaVcotkpyVHMKLKmiVryWYByNp0jpgAcXpFJDXJzA==} |
||||||
|
hasBin: true |
||||||
|
|
||||||
|
pino-std-serializers@7.1.0: |
||||||
|
resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} |
||||||
|
|
||||||
|
pino@9.14.0: |
||||||
|
resolution: {integrity: sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==} |
||||||
|
hasBin: true |
||||||
|
|
||||||
|
process-warning@5.0.0: |
||||||
|
resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} |
||||||
|
|
||||||
|
process@0.11.10: |
||||||
|
resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} |
||||||
|
engines: {node: '>= 0.6.0'} |
||||||
|
|
||||||
|
proxy-addr@2.0.7: |
||||||
|
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} |
||||||
|
engines: {node: '>= 0.10'} |
||||||
|
|
||||||
|
pump@3.0.4: |
||||||
|
resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} |
||||||
|
|
||||||
|
qs@6.14.2: |
||||||
|
resolution: {integrity: sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==} |
||||||
|
engines: {node: '>=0.6'} |
||||||
|
|
||||||
|
quick-format-unescaped@4.0.4: |
||||||
|
resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} |
||||||
|
|
||||||
|
range-parser@1.2.1: |
||||||
|
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} |
||||||
|
engines: {node: '>= 0.6'} |
||||||
|
|
||||||
|
raw-body@2.5.3: |
||||||
|
resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} |
||||||
|
engines: {node: '>= 0.8'} |
||||||
|
|
||||||
|
readable-stream@4.7.0: |
||||||
|
resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} |
||||||
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} |
||||||
|
|
||||||
|
real-require@0.2.0: |
||||||
|
resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} |
||||||
|
engines: {node: '>= 12.13.0'} |
||||||
|
|
||||||
|
safe-buffer@5.2.1: |
||||||
|
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} |
||||||
|
|
||||||
|
safe-stable-stringify@2.5.0: |
||||||
|
resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} |
||||||
|
engines: {node: '>=10'} |
||||||
|
|
||||||
|
safer-buffer@2.1.2: |
||||||
|
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} |
||||||
|
|
||||||
|
secure-json-parse@2.7.0: |
||||||
|
resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} |
||||||
|
|
||||||
|
send@0.19.2: |
||||||
|
resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} |
||||||
|
engines: {node: '>= 0.8.0'} |
||||||
|
|
||||||
|
serve-static@1.16.3: |
||||||
|
resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} |
||||||
|
engines: {node: '>= 0.8.0'} |
||||||
|
|
||||||
|
setprototypeof@1.2.0: |
||||||
|
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} |
||||||
|
|
||||||
|
side-channel-list@1.0.0: |
||||||
|
resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} |
||||||
|
engines: {node: '>= 0.4'} |
||||||
|
|
||||||
|
side-channel-map@1.0.1: |
||||||
|
resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} |
||||||
|
engines: {node: '>= 0.4'} |
||||||
|
|
||||||
|
side-channel-weakmap@1.0.2: |
||||||
|
resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} |
||||||
|
engines: {node: '>= 0.4'} |
||||||
|
|
||||||
|
side-channel@1.1.0: |
||||||
|
resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} |
||||||
|
engines: {node: '>= 0.4'} |
||||||
|
|
||||||
|
sonic-boom@4.2.1: |
||||||
|
resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} |
||||||
|
|
||||||
|
split2@4.2.0: |
||||||
|
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} |
||||||
|
engines: {node: '>= 10.x'} |
||||||
|
|
||||||
|
statuses@2.0.2: |
||||||
|
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} |
||||||
|
engines: {node: '>= 0.8'} |
||||||
|
|
||||||
|
string_decoder@1.3.0: |
||||||
|
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} |
||||||
|
|
||||||
|
strip-json-comments@3.1.1: |
||||||
|
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} |
||||||
|
engines: {node: '>=8'} |
||||||
|
|
||||||
|
thread-stream@3.1.0: |
||||||
|
resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} |
||||||
|
|
||||||
|
toidentifier@1.0.1: |
||||||
|
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} |
||||||
|
engines: {node: '>=0.6'} |
||||||
|
|
||||||
|
tr46@0.0.3: |
||||||
|
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} |
||||||
|
|
||||||
|
type-is@1.6.18: |
||||||
|
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} |
||||||
|
engines: {node: '>= 0.6'} |
||||||
|
|
||||||
|
undici-types@7.18.2: |
||||||
|
resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} |
||||||
|
|
||||||
|
unpipe@1.0.0: |
||||||
|
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} |
||||||
|
engines: {node: '>= 0.8'} |
||||||
|
|
||||||
|
utils-merge@1.0.1: |
||||||
|
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} |
||||||
|
engines: {node: '>= 0.4.0'} |
||||||
|
|
||||||
|
vary@1.1.2: |
||||||
|
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} |
||||||
|
engines: {node: '>= 0.8'} |
||||||
|
|
||||||
|
webidl-conversions@3.0.1: |
||||||
|
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} |
||||||
|
|
||||||
|
whatwg-url@5.0.0: |
||||||
|
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} |
||||||
|
|
||||||
|
wrappy@1.0.2: |
||||||
|
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} |
||||||
|
|
||||||
|
snapshots: |
||||||
|
|
||||||
|
'@notionhq/client@2.3.0': |
||||||
|
dependencies: |
||||||
|
'@types/node-fetch': 2.6.13 |
||||||
|
node-fetch: 2.7.0 |
||||||
|
transitivePeerDependencies: |
||||||
|
- encoding |
||||||
|
|
||||||
|
'@pinojs/redact@0.4.0': {} |
||||||
|
|
||||||
|
'@types/node-fetch@2.6.13': |
||||||
|
dependencies: |
||||||
|
'@types/node': 25.5.0 |
||||||
|
form-data: 4.0.5 |
||||||
|
|
||||||
|
'@types/node@25.5.0': |
||||||
|
dependencies: |
||||||
|
undici-types: 7.18.2 |
||||||
|
|
||||||
|
abort-controller@3.0.0: |
||||||
|
dependencies: |
||||||
|
event-target-shim: 5.0.1 |
||||||
|
|
||||||
|
accepts@1.3.8: |
||||||
|
dependencies: |
||||||
|
mime-types: 2.1.35 |
||||||
|
negotiator: 0.6.3 |
||||||
|
|
||||||
|
array-flatten@1.1.1: {} |
||||||
|
|
||||||
|
asynckit@0.4.0: {} |
||||||
|
|
||||||
|
atomic-sleep@1.0.0: {} |
||||||
|
|
||||||
|
base64-js@1.5.1: {} |
||||||
|
|
||||||
|
body-parser@1.20.4: |
||||||
|
dependencies: |
||||||
|
bytes: 3.1.2 |
||||||
|
content-type: 1.0.5 |
||||||
|
debug: 2.6.9 |
||||||
|
depd: 2.0.0 |
||||||
|
destroy: 1.2.0 |
||||||
|
http-errors: 2.0.1 |
||||||
|
iconv-lite: 0.4.24 |
||||||
|
on-finished: 2.4.1 |
||||||
|
qs: 6.14.2 |
||||||
|
raw-body: 2.5.3 |
||||||
|
type-is: 1.6.18 |
||||||
|
unpipe: 1.0.0 |
||||||
|
transitivePeerDependencies: |
||||||
|
- supports-color |
||||||
|
|
||||||
|
buffer@6.0.3: |
||||||
|
dependencies: |
||||||
|
base64-js: 1.5.1 |
||||||
|
ieee754: 1.2.1 |
||||||
|
|
||||||
|
bytes@3.1.2: {} |
||||||
|
|
||||||
|
call-bind-apply-helpers@1.0.2: |
||||||
|
dependencies: |
||||||
|
es-errors: 1.3.0 |
||||||
|
function-bind: 1.1.2 |
||||||
|
|
||||||
|
call-bound@1.0.4: |
||||||
|
dependencies: |
||||||
|
call-bind-apply-helpers: 1.0.2 |
||||||
|
get-intrinsic: 1.3.0 |
||||||
|
|
||||||
|
colorette@2.0.20: {} |
||||||
|
|
||||||
|
combined-stream@1.0.8: |
||||||
|
dependencies: |
||||||
|
delayed-stream: 1.0.0 |
||||||
|
|
||||||
|
content-disposition@0.5.4: |
||||||
|
dependencies: |
||||||
|
safe-buffer: 5.2.1 |
||||||
|
|
||||||
|
content-type@1.0.5: {} |
||||||
|
|
||||||
|
cookie-signature@1.0.7: {} |
||||||
|
|
||||||
|
cookie@0.7.2: {} |
||||||
|
|
||||||
|
dateformat@4.6.3: {} |
||||||
|
|
||||||
|
debug@2.6.9: |
||||||
|
dependencies: |
||||||
|
ms: 2.0.0 |
||||||
|
|
||||||
|
delayed-stream@1.0.0: {} |
||||||
|
|
||||||
|
depd@2.0.0: {} |
||||||
|
|
||||||
|
destroy@1.2.0: {} |
||||||
|
|
||||||
|
dunder-proto@1.0.1: |
||||||
|
dependencies: |
||||||
|
call-bind-apply-helpers: 1.0.2 |
||||||
|
es-errors: 1.3.0 |
||||||
|
gopd: 1.2.0 |
||||||
|
|
||||||
|
ee-first@1.1.1: {} |
||||||
|
|
||||||
|
encodeurl@2.0.0: {} |
||||||
|
|
||||||
|
end-of-stream@1.4.5: |
||||||
|
dependencies: |
||||||
|
once: 1.4.0 |
||||||
|
|
||||||
|
es-define-property@1.0.1: {} |
||||||
|
|
||||||
|
es-errors@1.3.0: {} |
||||||
|
|
||||||
|
es-object-atoms@1.1.1: |
||||||
|
dependencies: |
||||||
|
es-errors: 1.3.0 |
||||||
|
|
||||||
|
es-set-tostringtag@2.1.0: |
||||||
|
dependencies: |
||||||
|
es-errors: 1.3.0 |
||||||
|
get-intrinsic: 1.3.0 |
||||||
|
has-tostringtag: 1.0.2 |
||||||
|
hasown: 2.0.2 |
||||||
|
|
||||||
|
escape-html@1.0.3: {} |
||||||
|
|
||||||
|
etag@1.8.1: {} |
||||||
|
|
||||||
|
event-target-shim@5.0.1: {} |
||||||
|
|
||||||
|
events@3.3.0: {} |
||||||
|
|
||||||
|
express@4.22.1: |
||||||
|
dependencies: |
||||||
|
accepts: 1.3.8 |
||||||
|
array-flatten: 1.1.1 |
||||||
|
body-parser: 1.20.4 |
||||||
|
content-disposition: 0.5.4 |
||||||
|
content-type: 1.0.5 |
||||||
|
cookie: 0.7.2 |
||||||
|
cookie-signature: 1.0.7 |
||||||
|
debug: 2.6.9 |
||||||
|
depd: 2.0.0 |
||||||
|
encodeurl: 2.0.0 |
||||||
|
escape-html: 1.0.3 |
||||||
|
etag: 1.8.1 |
||||||
|
finalhandler: 1.3.2 |
||||||
|
fresh: 0.5.2 |
||||||
|
http-errors: 2.0.1 |
||||||
|
merge-descriptors: 1.0.3 |
||||||
|
methods: 1.1.2 |
||||||
|
on-finished: 2.4.1 |
||||||
|
parseurl: 1.3.3 |
||||||
|
path-to-regexp: 0.1.13 |
||||||
|
proxy-addr: 2.0.7 |
||||||
|
qs: 6.14.2 |
||||||
|
range-parser: 1.2.1 |
||||||
|
safe-buffer: 5.2.1 |
||||||
|
send: 0.19.2 |
||||||
|
serve-static: 1.16.3 |
||||||
|
setprototypeof: 1.2.0 |
||||||
|
statuses: 2.0.2 |
||||||
|
type-is: 1.6.18 |
||||||
|
utils-merge: 1.0.1 |
||||||
|
vary: 1.1.2 |
||||||
|
transitivePeerDependencies: |
||||||
|
- supports-color |
||||||
|
|
||||||
|
fast-copy@3.0.2: {} |
||||||
|
|
||||||
|
fast-safe-stringify@2.1.1: {} |
||||||
|
|
||||||
|
finalhandler@1.3.2: |
||||||
|
dependencies: |
||||||
|
debug: 2.6.9 |
||||||
|
encodeurl: 2.0.0 |
||||||
|
escape-html: 1.0.3 |
||||||
|
on-finished: 2.4.1 |
||||||
|
parseurl: 1.3.3 |
||||||
|
statuses: 2.0.2 |
||||||
|
unpipe: 1.0.0 |
||||||
|
transitivePeerDependencies: |
||||||
|
- supports-color |
||||||
|
|
||||||
|
form-data@4.0.5: |
||||||
|
dependencies: |
||||||
|
asynckit: 0.4.0 |
||||||
|
combined-stream: 1.0.8 |
||||||
|
es-set-tostringtag: 2.1.0 |
||||||
|
hasown: 2.0.2 |
||||||
|
mime-types: 2.1.35 |
||||||
|
|
||||||
|
forwarded@0.2.0: {} |
||||||
|
|
||||||
|
fresh@0.5.2: {} |
||||||
|
|
||||||
|
function-bind@1.1.2: {} |
||||||
|
|
||||||
|
get-intrinsic@1.3.0: |
||||||
|
dependencies: |
||||||
|
call-bind-apply-helpers: 1.0.2 |
||||||
|
es-define-property: 1.0.1 |
||||||
|
es-errors: 1.3.0 |
||||||
|
es-object-atoms: 1.1.1 |
||||||
|
function-bind: 1.1.2 |
||||||
|
get-proto: 1.0.1 |
||||||
|
gopd: 1.2.0 |
||||||
|
has-symbols: 1.1.0 |
||||||
|
hasown: 2.0.2 |
||||||
|
math-intrinsics: 1.1.0 |
||||||
|
|
||||||
|
get-proto@1.0.1: |
||||||
|
dependencies: |
||||||
|
dunder-proto: 1.0.1 |
||||||
|
es-object-atoms: 1.1.1 |
||||||
|
|
||||||
|
gopd@1.2.0: {} |
||||||
|
|
||||||
|
has-symbols@1.1.0: {} |
||||||
|
|
||||||
|
has-tostringtag@1.0.2: |
||||||
|
dependencies: |
||||||
|
has-symbols: 1.1.0 |
||||||
|
|
||||||
|
hasown@2.0.2: |
||||||
|
dependencies: |
||||||
|
function-bind: 1.1.2 |
||||||
|
|
||||||
|
help-me@5.0.0: {} |
||||||
|
|
||||||
|
http-errors@2.0.1: |
||||||
|
dependencies: |
||||||
|
depd: 2.0.0 |
||||||
|
inherits: 2.0.4 |
||||||
|
setprototypeof: 1.2.0 |
||||||
|
statuses: 2.0.2 |
||||||
|
toidentifier: 1.0.1 |
||||||
|
|
||||||
|
iconv-lite@0.4.24: |
||||||
|
dependencies: |
||||||
|
safer-buffer: 2.1.2 |
||||||
|
|
||||||
|
ieee754@1.2.1: {} |
||||||
|
|
||||||
|
inherits@2.0.4: {} |
||||||
|
|
||||||
|
ipaddr.js@1.9.1: {} |
||||||
|
|
||||||
|
joycon@3.1.1: {} |
||||||
|
|
||||||
|
math-intrinsics@1.1.0: {} |
||||||
|
|
||||||
|
media-typer@0.3.0: {} |
||||||
|
|
||||||
|
merge-descriptors@1.0.3: {} |
||||||
|
|
||||||
|
methods@1.1.2: {} |
||||||
|
|
||||||
|
mime-db@1.52.0: {} |
||||||
|
|
||||||
|
mime-types@2.1.35: |
||||||
|
dependencies: |
||||||
|
mime-db: 1.52.0 |
||||||
|
|
||||||
|
mime@1.6.0: {} |
||||||
|
|
||||||
|
minimist@1.2.8: {} |
||||||
|
|
||||||
|
ms@2.0.0: {} |
||||||
|
|
||||||
|
ms@2.1.3: {} |
||||||
|
|
||||||
|
negotiator@0.6.3: {} |
||||||
|
|
||||||
|
node-fetch@2.7.0: |
||||||
|
dependencies: |
||||||
|
whatwg-url: 5.0.0 |
||||||
|
|
||||||
|
object-inspect@1.13.4: {} |
||||||
|
|
||||||
|
on-exit-leak-free@2.1.2: {} |
||||||
|
|
||||||
|
on-finished@2.4.1: |
||||||
|
dependencies: |
||||||
|
ee-first: 1.1.1 |
||||||
|
|
||||||
|
once@1.4.0: |
||||||
|
dependencies: |
||||||
|
wrappy: 1.0.2 |
||||||
|
|
||||||
|
parseurl@1.3.3: {} |
||||||
|
|
||||||
|
path-to-regexp@0.1.13: {} |
||||||
|
|
||||||
|
pino-abstract-transport@2.0.0: |
||||||
|
dependencies: |
||||||
|
split2: 4.2.0 |
||||||
|
|
||||||
|
pino-pretty@11.3.0: |
||||||
|
dependencies: |
||||||
|
colorette: 2.0.20 |
||||||
|
dateformat: 4.6.3 |
||||||
|
fast-copy: 3.0.2 |
||||||
|
fast-safe-stringify: 2.1.1 |
||||||
|
help-me: 5.0.0 |
||||||
|
joycon: 3.1.1 |
||||||
|
minimist: 1.2.8 |
||||||
|
on-exit-leak-free: 2.1.2 |
||||||
|
pino-abstract-transport: 2.0.0 |
||||||
|
pump: 3.0.4 |
||||||
|
readable-stream: 4.7.0 |
||||||
|
secure-json-parse: 2.7.0 |
||||||
|
sonic-boom: 4.2.1 |
||||||
|
strip-json-comments: 3.1.1 |
||||||
|
|
||||||
|
pino-std-serializers@7.1.0: {} |
||||||
|
|
||||||
|
pino@9.14.0: |
||||||
|
dependencies: |
||||||
|
'@pinojs/redact': 0.4.0 |
||||||
|
atomic-sleep: 1.0.0 |
||||||
|
on-exit-leak-free: 2.1.2 |
||||||
|
pino-abstract-transport: 2.0.0 |
||||||
|
pino-std-serializers: 7.1.0 |
||||||
|
process-warning: 5.0.0 |
||||||
|
quick-format-unescaped: 4.0.4 |
||||||
|
real-require: 0.2.0 |
||||||
|
safe-stable-stringify: 2.5.0 |
||||||
|
sonic-boom: 4.2.1 |
||||||
|
thread-stream: 3.1.0 |
||||||
|
|
||||||
|
process-warning@5.0.0: {} |
||||||
|
|
||||||
|
process@0.11.10: {} |
||||||
|
|
||||||
|
proxy-addr@2.0.7: |
||||||
|
dependencies: |
||||||
|
forwarded: 0.2.0 |
||||||
|
ipaddr.js: 1.9.1 |
||||||
|
|
||||||
|
pump@3.0.4: |
||||||
|
dependencies: |
||||||
|
end-of-stream: 1.4.5 |
||||||
|
once: 1.4.0 |
||||||
|
|
||||||
|
qs@6.14.2: |
||||||
|
dependencies: |
||||||
|
side-channel: 1.1.0 |
||||||
|
|
||||||
|
quick-format-unescaped@4.0.4: {} |
||||||
|
|
||||||
|
range-parser@1.2.1: {} |
||||||
|
|
||||||
|
raw-body@2.5.3: |
||||||
|
dependencies: |
||||||
|
bytes: 3.1.2 |
||||||
|
http-errors: 2.0.1 |
||||||
|
iconv-lite: 0.4.24 |
||||||
|
unpipe: 1.0.0 |
||||||
|
|
||||||
|
readable-stream@4.7.0: |
||||||
|
dependencies: |
||||||
|
abort-controller: 3.0.0 |
||||||
|
buffer: 6.0.3 |
||||||
|
events: 3.3.0 |
||||||
|
process: 0.11.10 |
||||||
|
string_decoder: 1.3.0 |
||||||
|
|
||||||
|
real-require@0.2.0: {} |
||||||
|
|
||||||
|
safe-buffer@5.2.1: {} |
||||||
|
|
||||||
|
safe-stable-stringify@2.5.0: {} |
||||||
|
|
||||||
|
safer-buffer@2.1.2: {} |
||||||
|
|
||||||
|
secure-json-parse@2.7.0: {} |
||||||
|
|
||||||
|
send@0.19.2: |
||||||
|
dependencies: |
||||||
|
debug: 2.6.9 |
||||||
|
depd: 2.0.0 |
||||||
|
destroy: 1.2.0 |
||||||
|
encodeurl: 2.0.0 |
||||||
|
escape-html: 1.0.3 |
||||||
|
etag: 1.8.1 |
||||||
|
fresh: 0.5.2 |
||||||
|
http-errors: 2.0.1 |
||||||
|
mime: 1.6.0 |
||||||
|
ms: 2.1.3 |
||||||
|
on-finished: 2.4.1 |
||||||
|
range-parser: 1.2.1 |
||||||
|
statuses: 2.0.2 |
||||||
|
transitivePeerDependencies: |
||||||
|
- supports-color |
||||||
|
|
||||||
|
serve-static@1.16.3: |
||||||
|
dependencies: |
||||||
|
encodeurl: 2.0.0 |
||||||
|
escape-html: 1.0.3 |
||||||
|
parseurl: 1.3.3 |
||||||
|
send: 0.19.2 |
||||||
|
transitivePeerDependencies: |
||||||
|
- supports-color |
||||||
|
|
||||||
|
setprototypeof@1.2.0: {} |
||||||
|
|
||||||
|
side-channel-list@1.0.0: |
||||||
|
dependencies: |
||||||
|
es-errors: 1.3.0 |
||||||
|
object-inspect: 1.13.4 |
||||||
|
|
||||||
|
side-channel-map@1.0.1: |
||||||
|
dependencies: |
||||||
|
call-bound: 1.0.4 |
||||||
|
es-errors: 1.3.0 |
||||||
|
get-intrinsic: 1.3.0 |
||||||
|
object-inspect: 1.13.4 |
||||||
|
|
||||||
|
side-channel-weakmap@1.0.2: |
||||||
|
dependencies: |
||||||
|
call-bound: 1.0.4 |
||||||
|
es-errors: 1.3.0 |
||||||
|
get-intrinsic: 1.3.0 |
||||||
|
object-inspect: 1.13.4 |
||||||
|
side-channel-map: 1.0.1 |
||||||
|
|
||||||
|
side-channel@1.1.0: |
||||||
|
dependencies: |
||||||
|
es-errors: 1.3.0 |
||||||
|
object-inspect: 1.13.4 |
||||||
|
side-channel-list: 1.0.0 |
||||||
|
side-channel-map: 1.0.1 |
||||||
|
side-channel-weakmap: 1.0.2 |
||||||
|
|
||||||
|
sonic-boom@4.2.1: |
||||||
|
dependencies: |
||||||
|
atomic-sleep: 1.0.0 |
||||||
|
|
||||||
|
split2@4.2.0: {} |
||||||
|
|
||||||
|
statuses@2.0.2: {} |
||||||
|
|
||||||
|
string_decoder@1.3.0: |
||||||
|
dependencies: |
||||||
|
safe-buffer: 5.2.1 |
||||||
|
|
||||||
|
strip-json-comments@3.1.1: {} |
||||||
|
|
||||||
|
thread-stream@3.1.0: |
||||||
|
dependencies: |
||||||
|
real-require: 0.2.0 |
||||||
|
|
||||||
|
toidentifier@1.0.1: {} |
||||||
|
|
||||||
|
tr46@0.0.3: {} |
||||||
|
|
||||||
|
type-is@1.6.18: |
||||||
|
dependencies: |
||||||
|
media-typer: 0.3.0 |
||||||
|
mime-types: 2.1.35 |
||||||
|
|
||||||
|
undici-types@7.18.2: {} |
||||||
|
|
||||||
|
unpipe@1.0.0: {} |
||||||
|
|
||||||
|
utils-merge@1.0.1: {} |
||||||
|
|
||||||
|
vary@1.1.2: {} |
||||||
|
|
||||||
|
webidl-conversions@3.0.1: {} |
||||||
|
|
||||||
|
whatwg-url@5.0.0: |
||||||
|
dependencies: |
||||||
|
tr46: 0.0.3 |
||||||
|
webidl-conversions: 3.0.1 |
||||||
|
|
||||||
|
wrappy@1.0.2: {} |
||||||
@ -0,0 +1,24 @@ |
|||||||
|
const required = [ |
||||||
|
'NOTION_API_KEY', |
||||||
|
'NOTION_DATABASE_ID', |
||||||
|
'GITEA_WEBHOOK_SECRET', |
||||||
|
]; |
||||||
|
|
||||||
|
for (const key of required) { |
||||||
|
if (!process.env[key]) { |
||||||
|
console.error(`Missing required env: ${key}`); |
||||||
|
process.exit(1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
notionApiKey: process.env.NOTION_API_KEY, |
||||||
|
notionDatabaseId: process.env.NOTION_DATABASE_ID, |
||||||
|
notionPropStatus: process.env.NOTION_PROP_STATUS || '상태', |
||||||
|
notionPropProgress: process.env.NOTION_PROP_PROGRESS || '진행률', |
||||||
|
notionStatusDone: process.env.NOTION_STATUS_DONE || '완료', |
||||||
|
refPattern: null, // 서버 시작 시 Notion DB에서 자동 설정
|
||||||
|
giteaWebhookSecret: process.env.GITEA_WEBHOOK_SECRET, |
||||||
|
port: parseInt(process.env.PORT, 10) || 3000, |
||||||
|
logLevel: process.env.LOG_LEVEL || 'info', |
||||||
|
}; |
||||||
@ -0,0 +1,37 @@ |
|||||||
|
const express = require('express'); |
||||||
|
const config = require('./config'); |
||||||
|
const logger = require('./utils/logger'); |
||||||
|
const { loadRefPrefix } = require('./services/notion'); |
||||||
|
const webhookRouter = require('./routes/webhook'); |
||||||
|
|
||||||
|
const app = express(); |
||||||
|
|
||||||
|
// rawBody 보존 (서명 검증용)
|
||||||
|
app.use( |
||||||
|
express.json({ |
||||||
|
verify: (req, _res, buf) => { |
||||||
|
req.rawBody = buf.toString(); |
||||||
|
}, |
||||||
|
}) |
||||||
|
); |
||||||
|
|
||||||
|
// 라우트
|
||||||
|
app.get('/health', (_req, res) => res.json({ status: 'ok' })); |
||||||
|
app.use(webhookRouter); |
||||||
|
|
||||||
|
async function start() { |
||||||
|
// Notion DB에서 접두사 자동 감지
|
||||||
|
config.refPattern = await loadRefPrefix(); |
||||||
|
|
||||||
|
app.listen(config.port, () => { |
||||||
|
logger.info( |
||||||
|
{ port: config.port, prefix: config.refPattern }, |
||||||
|
'중계 서버 시작' |
||||||
|
); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
start().catch((err) => { |
||||||
|
logger.fatal(err, '서버 시작 실패'); |
||||||
|
process.exit(1); |
||||||
|
}); |
||||||
@ -0,0 +1,66 @@ |
|||||||
|
const { Router } = require('express'); |
||||||
|
const { verifySignature } = require('../utils/verify'); |
||||||
|
const { extractReferences } = require('../services/parser'); |
||||||
|
const { findPageByTaskId, markComplete } = require('../services/notion'); |
||||||
|
const logger = require('../utils/logger'); |
||||||
|
|
||||||
|
const router = Router(); |
||||||
|
|
||||||
|
router.post('/webhook', async (req, res) => { |
||||||
|
// 서명 검증
|
||||||
|
const signature = req.headers['x-gitea-signature']; |
||||||
|
if (!verifySignature(req.rawBody, signature)) { |
||||||
|
logger.warn('서명 검증 실패'); |
||||||
|
return res.status(401).json({ error: 'Invalid signature' }); |
||||||
|
} |
||||||
|
|
||||||
|
const event = req.headers['x-gitea-event']; |
||||||
|
const body = req.body; |
||||||
|
let refs = []; |
||||||
|
|
||||||
|
// 이벤트 타입별 참조 추출
|
||||||
|
if (event === 'push') { |
||||||
|
for (const commit of body.commits || []) { |
||||||
|
refs.push(...extractReferences(commit.message)); |
||||||
|
} |
||||||
|
} else if (event === 'pull_request') { |
||||||
|
const pr = body.pull_request || {}; |
||||||
|
refs.push(...extractReferences(pr.title)); |
||||||
|
refs.push(...extractReferences(pr.body)); |
||||||
|
} else { |
||||||
|
logger.info({ event }, '처리하지 않는 이벤트'); |
||||||
|
return res.json({ skipped: true, event }); |
||||||
|
} |
||||||
|
|
||||||
|
// 중복 제거
|
||||||
|
refs = [...new Set(refs)]; |
||||||
|
|
||||||
|
if (refs.length === 0) { |
||||||
|
logger.info('참조된 태스크 ID 없음'); |
||||||
|
return res.json({ processed: 0 }); |
||||||
|
} |
||||||
|
|
||||||
|
logger.info({ refs }, '참조 추출 완료'); |
||||||
|
|
||||||
|
// 참조별 Notion 업데이트
|
||||||
|
const results = []; |
||||||
|
for (const taskId of refs) { |
||||||
|
try { |
||||||
|
const pageId = await findPageByTaskId(taskId); |
||||||
|
if (!pageId) { |
||||||
|
logger.warn({ taskId }, 'Notion 페이지를 찾을 수 없음'); |
||||||
|
results.push({ taskId, status: 'not_found' }); |
||||||
|
continue; |
||||||
|
} |
||||||
|
await markComplete(pageId); |
||||||
|
results.push({ taskId, status: 'updated' }); |
||||||
|
} catch (err) { |
||||||
|
logger.error({ taskId, err: err.message }, 'Notion 업데이트 실패'); |
||||||
|
results.push({ taskId, status: 'error', error: err.message }); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
res.json({ processed: refs.length, results }); |
||||||
|
}); |
||||||
|
|
||||||
|
module.exports = router; |
||||||
@ -0,0 +1,52 @@ |
|||||||
|
const { Client } = require('@notionhq/client'); |
||||||
|
const config = require('../config'); |
||||||
|
const logger = require('../utils/logger'); |
||||||
|
|
||||||
|
const notion = new Client({ auth: config.notionApiKey }); |
||||||
|
|
||||||
|
async function loadRefPrefix() { |
||||||
|
const db = await notion.databases.retrieve({ |
||||||
|
database_id: config.notionDatabaseId, |
||||||
|
}); |
||||||
|
|
||||||
|
for (const [name, prop] of Object.entries(db.properties)) { |
||||||
|
if (prop.type === 'unique_id') { |
||||||
|
const prefix = prop.unique_id.prefix; |
||||||
|
logger.info({ property: name, prefix }, 'Notion DB 접두사 감지'); |
||||||
|
return prefix; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
throw new Error('Notion DB에서 Unique ID 속성을 찾을 수 없습니다'); |
||||||
|
} |
||||||
|
|
||||||
|
async function findPageByTaskId(taskId) { |
||||||
|
const response = await notion.databases.query({ |
||||||
|
database_id: config.notionDatabaseId, |
||||||
|
filter: { |
||||||
|
property: 'ID', |
||||||
|
unique_id: { equals: taskId }, |
||||||
|
}, |
||||||
|
}); |
||||||
|
|
||||||
|
if (response.results.length === 0) return null; |
||||||
|
return response.results[0].id; |
||||||
|
} |
||||||
|
|
||||||
|
async function markComplete(pageId) { |
||||||
|
await notion.pages.update({ |
||||||
|
page_id: pageId, |
||||||
|
properties: { |
||||||
|
[config.notionPropStatus]: { |
||||||
|
select: { name: config.notionStatusDone }, |
||||||
|
}, |
||||||
|
[config.notionPropProgress]: { |
||||||
|
number: 100, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}); |
||||||
|
|
||||||
|
logger.info({ pageId }, 'Notion 페이지 업데이트 완료'); |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { loadRefPrefix, findPageByTaskId, markComplete }; |
||||||
@ -0,0 +1,17 @@ |
|||||||
|
const config = require('../config'); |
||||||
|
|
||||||
|
function extractReferences(text) { |
||||||
|
if (!text) return []; |
||||||
|
|
||||||
|
const regex = new RegExp(`${config.refPattern}-(\\d+)`, 'g'); |
||||||
|
const ids = new Set(); |
||||||
|
let match; |
||||||
|
|
||||||
|
while ((match = regex.exec(text)) !== null) { |
||||||
|
ids.add(parseInt(match[1], 10)); |
||||||
|
} |
||||||
|
|
||||||
|
return [...ids]; |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { extractReferences }; |
||||||
@ -0,0 +1,25 @@ |
|||||||
|
const path = require('path'); |
||||||
|
const pino = require('pino'); |
||||||
|
const config = require('../config'); |
||||||
|
|
||||||
|
const logDir = path.join(__dirname, '../../logs'); |
||||||
|
|
||||||
|
module.exports = pino({ |
||||||
|
level: config.logLevel, |
||||||
|
transport: { |
||||||
|
targets: [ |
||||||
|
// 콘솔 출력
|
||||||
|
{ |
||||||
|
target: 'pino-pretty', |
||||||
|
options: { colorize: true }, |
||||||
|
level: config.logLevel, |
||||||
|
}, |
||||||
|
// 파일 출력 (logs/app.log)
|
||||||
|
{ |
||||||
|
target: 'pino/file', |
||||||
|
options: { destination: path.join(logDir, 'app.log'), mkdir: true }, |
||||||
|
level: config.logLevel, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
}); |
||||||
@ -0,0 +1,20 @@ |
|||||||
|
const crypto = require('crypto'); |
||||||
|
const config = require('../config'); |
||||||
|
|
||||||
|
function verifySignature(payload, signature) { |
||||||
|
if (!signature) return false; |
||||||
|
|
||||||
|
const expected = crypto |
||||||
|
.createHmac('sha256', config.giteaWebhookSecret) |
||||||
|
.update(payload) |
||||||
|
.digest('hex'); |
||||||
|
|
||||||
|
const sig = Buffer.from(signature, 'hex'); |
||||||
|
const exp = Buffer.from(expected, 'hex'); |
||||||
|
|
||||||
|
if (sig.length !== exp.length) return false; |
||||||
|
|
||||||
|
return crypto.timingSafeEqual(sig, exp); |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { verifySignature }; |
||||||
Loading…
Reference in new issue