├── .github └── workflows │ ├── deploy.yaml │ └── lint.yaml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .spectral.yaml ├── .vscode └── extensions.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── assets ├── shiftpsh-blog.png ├── solvedac-ud-compact.png └── solvedac-ud-full.png ├── favicon.svg ├── index.html ├── package.json ├── patches ├── @typespec__openapi3@0.54.0-dev.11.patch └── serve-reload-replace@4.0.3.patch ├── pnpm-lock.yaml ├── scripts ├── build.js └── git-hooks │ └── pre-commit ├── src ├── auth.tsp ├── extensions.tsp ├── main.tsp ├── models │ ├── ArenaTier.tsp │ ├── Background.tsp │ ├── BackgroundAuthor.tsp │ ├── BackgroundCategory.tsp │ ├── Badge.tsp │ ├── BadgeCategory.tsp │ ├── BadgeTier.tsp │ ├── Class.tsp │ ├── CoinShopProduct.tsp │ ├── Emoticon.tsp │ ├── Item.tsp │ ├── Language.tsp │ ├── Organization.tsp │ ├── OrganizationType.tsp │ ├── PaginatedList.tsp │ ├── Post.tsp │ ├── Problem.tsp │ ├── ProblemLevel.tsp │ ├── ProblemTag.tsp │ ├── ProblemTagAlias.tsp │ ├── ProblemTagNameTranslated.tsp │ ├── ProblemTitleTranslated.tsp │ ├── Ranked.tsp │ ├── RivalUser.tsp │ ├── SiteStatistics.tsp │ ├── SocialUser.tsp │ ├── SolveTier.tsp │ ├── User.tsp │ ├── UserAdditionalInfo.tsp │ └── _barrel.tsp └── operations │ ├── _barrel.tsp │ ├── account │ ├── _barrel.tsp │ ├── redeem.tsp │ ├── update_settings.tsp │ └── verify_credentials.tsp │ ├── background │ ├── _barrel.tsp │ └── show.tsp │ ├── badge │ ├── _barrel.tsp │ └── show.tsp │ ├── coins │ ├── _barrel.tsp │ ├── exchange_rate.tsp │ └── shop │ │ ├── _barrel.tsp │ │ └── list.tsp │ ├── organization │ ├── _barrel.tsp │ └── show.tsp │ ├── post │ ├── _barrel.tsp │ └── show.tsp │ ├── problem │ ├── _barrel.tsp │ ├── class.tsp │ ├── level.tsp │ ├── lookup.tsp │ └── show.tsp │ ├── ranking │ ├── _barrel.tsp │ ├── arena_in_organization.tsp │ ├── class.tsp │ ├── contribution.tsp │ ├── in_organization.tsp │ ├── organization.tsp │ ├── reverse_rival.tsp │ ├── rival.tsp │ ├── streak.tsp │ └── tier.tsp │ ├── search │ ├── _barrel.tsp │ ├── problem.tsp │ ├── suggestion.tsp │ ├── tag.tsp │ └── user.tsp │ ├── site │ ├── _barrel.tsp │ └── stats.tsp │ ├── tag │ ├── _barrel.tsp │ ├── list.tsp │ └── show.tsp │ └── user │ ├── _barrel.tsp │ ├── additional_info.tsp │ ├── class_stats.tsp │ ├── contribution_stats.tsp │ ├── organizations.tsp │ ├── problem_stats.tsp │ ├── problem_tag_stats.tsp │ ├── show.tsp │ └── top_100.tsp ├── tspconfig.yaml └── vendors └── @stoplight └── elements ├── web-components.min.js └── web-components.min.js.LICENSE.txt /.github/workflows/deploy.yaml: -------------------------------------------------------------------------------- 1 | name: Deploy 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | permissions: 9 | contents: read 10 | pages: write 11 | id-token: write 12 | 13 | concurrency: 14 | group: 'pages' 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | lint: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v4 22 | - uses: pnpm/action-setup@v3 23 | with: 24 | version: 8 25 | - uses: actions/setup-node@v4 26 | with: 27 | cache: pnpm 28 | - run: pnpm i 29 | - run: pnpm build 30 | - uses: stoplightio/spectral-action@v0.8.10 31 | with: 32 | file_glob: 'tsp-output/*.yaml' 33 | page-deployment: 34 | needs: [lint] 35 | runs-on: ubuntu-latest 36 | steps: 37 | - uses: actions/checkout@v4 38 | - uses: pnpm/action-setup@v3 39 | with: 40 | version: 8 41 | - uses: actions/setup-node@v4 42 | with: 43 | cache: pnpm 44 | - run: pnpm i 45 | - run: pnpm build 46 | - name: Setup Pages 47 | uses: actions/configure-pages@v5 48 | - name: Upload artifact 49 | uses: actions/upload-pages-artifact@v3 50 | with: 51 | path: build/unofficial-documentation 52 | - name: Deploy to GitHub Pages 53 | id: deployment 54 | uses: actions/deploy-pages@v4 55 | library-deployment: 56 | needs: [page-deployment] 57 | runs-on: ubuntu-latest 58 | strategy: 59 | matrix: 60 | repo: 61 | - 'solvedac/api.ts' 62 | - 'solvedac/api.rs' 63 | steps: 64 | - name: Invoke Workflow 65 | uses: benc-uk/workflow-dispatch@v1 66 | with: 67 | workflow: Follow Up 68 | token: ${{ secrets.WORKFLOW_DISPATCH }} 69 | repo: ${{ matrix.repo }} 70 | inputs: | 71 | { 72 | "run-id": "${{ github.run_id }}" 73 | } 74 | -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | lint: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: pnpm/action-setup@v3 14 | with: 15 | version: 8 16 | - uses: actions/setup-node@v4 17 | with: 18 | cache: pnpm 19 | - run: pnpm i 20 | - run: pnpm build 21 | - uses: stoplightio/spectral-action@v0.8.10 22 | with: 23 | file_glob: 'tsp-output/*.yaml' 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | tsp-output/ 3 | build/ 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Temp 2 | src/**/*.yaml 3 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "plugins": [ 4 | "@typespec/prettier-plugin-typespec" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.spectral.yaml: -------------------------------------------------------------------------------- 1 | extends: spectral:oas 2 | rules: 3 | oas3-unused-component: hint 4 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "redhat.vscode-yaml", 4 | "42crunch.vscode-openapi", 5 | "typespec.typespec-vscode" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ![banner](assets/solvedac-ud-compact.png) 4 | 5 | 저장소에 기여할 때, GitHub 이슈를 통해 변경점에 관해 토론해주세요. 이후, Pull Request를 만들어주시면 감사하겠습니다. 6 | 7 | ## 문서 작성 방법 8 | 9 | API를 문서화하기 위해서는 paths/나 schemas/ 아래 파일을 수정·추가하면 됩니다. 문서 안에서 말투는 기본적으로 하십시오체를 사용하며, `paths` 내부 `summary`는 -하기로 끝냅니다. 내용을 작성할 때에는 간결하고 알아듣기 쉽게 작성하도록 합니다. 10 | 11 | ### 개발 서버 가동 12 | 13 | 프로젝트 루트 폴더 속 정적 파일을 HTTP로 제공하면 됩니다. 그 방법은 여러가지가 있을 수 있으나, 여기서는 다음 방법만 설명하도록 합니다. 14 | 15 | #### (npm/yarn) servor 이용 16 | 17 | 1. serve를 설치하세요. 18 | 19 | ```sh 20 | npm install -g servor 21 | yarn global add servor 22 | ``` 23 | 24 | 2. 프로젝트 루트 폴더에서 다음 명령어를 실행하세요. 25 | 26 | ```sh 27 | servor --reload 28 | ``` 29 | 30 | ## Pull Request 절차 31 | 32 | - 한 명 이상의 개발자가 합병되기에 합당한지 평가합니다. 33 | - PR이 합병되기에 합당하다면 버전 수정을 요구하는 코멘트가 달립니다. 버전 포맷은 `(solved.ac API 버전).(현재 년도).(현재 월)+b(해당 달 수정 횟수)`입니다. 알맞게 수정해주세요. 34 | 35 | ## 행동 강령 36 | 37 | 모든 기여자들이 환영, 존중받는다고 느낄 수 있도록, 기본적인 행동 강령을 정하고자 합니다. 다만, 너무나 많은 규칙은 외우기 힘들기 때문에 다음 규칙 하나를 중심으로 행동하기로 합니다. 38 | 39 | > 인간으로서, 기본적으로 지켜야 할 예의을 지키기 40 | 41 | 물론, 위 문장이 모호하고 때때로 다르게 해석할 수도 있습니다. 따라서, 특히 다음과 같은 사항을 지켜야 함을 추가로 안내하고자 합니다. 42 | 43 | - 열린 마음으로 다른 이들을 받아들이기 44 | - 정중한 어투로 대화하기 45 | - 다른 사람들을 존중하기 46 | - 남을 비난하거나 욕하지 않기 47 | 48 | 이 외에는 서로 상처받지 않게, 조율할 수 있으면 좋겠습니다. 감사합니다. 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @solvedac/unofficial-documentation 2 | 3 | ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/solvedac/unofficial-documentation/lint.yaml?branch=main&label=documentation+validity+check&style=for-the-badge) 4 | 5 | [![banner](assets/solvedac-ud-full.png)](https://solvedac.github.io/unofficial-documentation) 6 | 7 | > [접속하기](https://solvedac.github.io/unofficial-documentation) 8 | 9 | 이 프로젝트는 [solved.ac](https://solved.ac/) API를 문서화하는 커뮤니티 프로젝트입니다. 이 저장소는 원작자의 요청에 따라 언제든 지워질 수 있으며, 현재 API와 일치하지 않을 수도 있는 점 양해 부탁드립니다. 10 | 11 | solved.ac 서비스는 shiftpsh가 기획·개발·디자인·운영하는 프로젝트로, 이 저장소와는 solved.ac의 API를 문서화해둔 것 이외에는 아무런 관련이 없습니다. 12 | 13 | **주의**: (2023/03/08~) CORS 문제로 인해 API는 사이트 내에서 호출할 수 없으므로 별도 도구를 이용해주십시오. ([#51](https://github.com/solvedac/unofficial-documentation/issues/51)) 14 | 15 | ## 기여하기 16 | 17 | [CONTRIBUTING.md](CONTRIBUTING.md)를 참조해주세요. 18 | 19 | ### shiftpsh 님의 시간을 아낍시다 20 | 21 | ![shiftpsh blog](assets/shiftpsh-blog.png) 22 | 23 | - [solved.ac 화이트리스트 관련 입장 (5/8)](https://blog.shift.moe/2020/05/08/solved-ac-%ed%99%94%ec%9d%b4%ed%8a%b8%eb%a6%ac%ec%8a%a4%ed%8a%b8-%ea%b4%80%eb%a0%a8-%ec%9e%85%ec%9e%a5-5-8/), 2020/05/08, Shifted 24 | -------------------------------------------------------------------------------- /assets/shiftpsh-blog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solvedac/unofficial-documentation/ffe7b0470474fbc27482c75d7934db01d3b0a6aa/assets/shiftpsh-blog.png -------------------------------------------------------------------------------- /assets/solvedac-ud-compact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solvedac/unofficial-documentation/ffe7b0470474fbc27482c75d7934db01d3b0a6aa/assets/solvedac-ud-compact.png -------------------------------------------------------------------------------- /assets/solvedac-ud-full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solvedac/unofficial-documentation/ffe7b0470474fbc27482c75d7934db01d3b0a6aa/assets/solvedac-ud-full.png -------------------------------------------------------------------------------- /favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | Artboard 1 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | @solvedac/unofficial-documentation 11 | 12 | 16 | 17 | 21 | 25 | 26 | 27 | 28 | 32 | 36 | 37 | 38 | 39 | 40 | 44 | 49 | 263 | 264 | 265 | 277 | 286 | 469 | 470 | 523 | 524 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@solvedac/unofficial-documentation", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "scripts": { 6 | "dev": "concurrently npm:watch npm:serve", 7 | "build": "node ./scripts/build.js", 8 | "watch": "nodemon --exec pnpm build -e tsp", 9 | "serve": "srr --port=8481 --ignore=node_modules/ --proxy=https://solved.ac/api/v3 --root=build/", 10 | "format": "prettier -w src", 11 | "lint:format": "prettier -c src", 12 | "prepare": "git config core.hooksPath ./scripts/git-hooks" 13 | }, 14 | "dependencies": { 15 | "@typespec/best-practices": "^0.46.0-dev.0", 16 | "@typespec/compiler": "0.54.0-dev.21", 17 | "@typespec/http": "0.54.0-dev.7", 18 | "@typespec/openapi": "0.54.0-dev.3", 19 | "@typespec/openapi3": "0.54.0-dev.11", 20 | "@typespec/prettier-plugin-typespec": "0.54.0-dev.2", 21 | "@typespec/rest": "0.54.0-dev.2", 22 | "@typespec/versioning": "0.54.0-dev.4", 23 | "concurrently": "^8.2.2", 24 | "deepmerge": "^4.3.1", 25 | "nodemon": "^3.1.0", 26 | "prettier": "^3.2.5", 27 | "serve-reload-replace": "^4.0.3", 28 | "yaml": "^2.4.0", 29 | "zx": "^7.2.3" 30 | }, 31 | "private": true, 32 | "pnpm": { 33 | "patchedDependencies": { 34 | "serve-reload-replace@4.0.3": "patches/serve-reload-replace@4.0.3.patch", 35 | "@typespec/openapi3@0.54.0-dev.11": "patches/@typespec__openapi3@0.54.0-dev.11.patch" 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /patches/@typespec__openapi3@0.54.0-dev.11.patch: -------------------------------------------------------------------------------- 1 | diff --git a/dist/src/schema-emitter.js b/dist/src/schema-emitter.js 2 | index 377d1afa8874b64aa99fbeb6e309875c0ff24458..7207ecabe07e4fb04462ba7ca3bad0f6f0bdaa6b 100644 3 | --- a/dist/src/schema-emitter.js 4 | +++ b/dist/src/schema-emitter.js 5 | @@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function ( 6 | return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); 7 | }; 8 | var _OpenAPI3SchemaEmitter_instances, _OpenAPI3SchemaEmitter_metadataInfo, _OpenAPI3SchemaEmitter_visibilityUsage, _OpenAPI3SchemaEmitter_options, _OpenAPI3SchemaEmitter_applyExternalDocs, _OpenAPI3SchemaEmitter_typeNameOptions, _OpenAPI3SchemaEmitter_getVisibilityContext, _OpenAPI3SchemaEmitter_getContentType, _OpenAPI3SchemaEmitter_requiredModelProperties, _OpenAPI3SchemaEmitter_isBytesKeptRaw, _OpenAPI3SchemaEmitter_enumSchema, _OpenAPI3SchemaEmitter_unionSchema, _OpenAPI3SchemaEmitter_getDiscriminatorMapping, _OpenAPI3SchemaEmitter_attachExtensions, _OpenAPI3SchemaEmitter_getSchemaForScalar, _OpenAPI3SchemaEmitter_getSchemaForStdScalars, _OpenAPI3SchemaEmitter_applyConstraints, _OpenAPI3SchemaEmitter_inlineType, _OpenAPI3SchemaEmitter_createDeclaration, _OpenAPI3SchemaEmitter_isStdType, _OpenAPI3SchemaEmitter_applyEncoding, _OpenAPI3SchemaEmitter_mergeFormatAndEncoding; 9 | -import { compilerAssert, getDeprecated, getDiscriminatedUnion, getDiscriminator, getDoc, getEncode, getFormat, getKnownValues, getMaxItems, getMaxLength, getMaxValue, getMaxValueExclusive, getMinItems, getMinLength, getMinValue, getMinValueExclusive, getNamespaceFullName, getPattern, getSummary, getTypeName, ignoreDiagnostics, isArrayModelType, isNeverType, isNullType, isSecret, isTemplateDeclaration, resolveEncodedName, stringTemplateToString, } from "@typespec/compiler"; 10 | +import { SyntaxKind, compilerAssert, getDeprecated, getDiscriminatedUnion, getDiscriminator, getDoc, getEncode, getFormat, getKnownValues, getMaxItems, getMaxLength, getMaxValue, getMaxValueExclusive, getMinItems, getMinLength, getMinValue, getMinValueExclusive, getNamespaceFullName, getPattern, getSourceLocation, getSummary, getTypeName, ignoreDiagnostics, isArrayModelType, isNeverType, isNullType, isSecret, isTemplateDeclaration, resolveEncodedName, stringTemplateToString, } from "@typespec/compiler"; 11 | import { ArrayBuilder, ObjectBuilder, Placeholder, TypeEmitter, } from "@typespec/compiler/emitter-framework"; 12 | import { Visibility, getVisibilitySuffix } from "@typespec/http"; 13 | import { checkDuplicateTypeName, getExtensions, getExternalDocs, getOpenAPITypeName, isReadonlyProperty, shouldInline, } from "@typespec/openapi"; 14 | @@ -603,6 +603,19 @@ _OpenAPI3SchemaEmitter_metadataInfo = new WeakMap(), _OpenAPI3SchemaEmitter_visi 15 | if (!__classPrivateFieldGet(this, _OpenAPI3SchemaEmitter_instances, "m", _OpenAPI3SchemaEmitter_isStdType).call(this, type) || type.name !== "url") { 16 | applyConstraint(getFormat, "format"); 17 | } 18 | + const examples = []; 19 | + for (const doc of type.node?.docs ?? []) { 20 | + for (const dTag of doc.tags) { 21 | + if (dTag.kind === SyntaxKind.DocUnknownTag && dTag.tagName.sv === "example") { 22 | + examples.push(extractExample(dTag)); 23 | + } 24 | + } 25 | + } 26 | + if (examples.length === 1) { 27 | + schema.example = examples[0].content; 28 | + } else if (examples.length > 1) { 29 | + schema.examples = Object.fromEntries(examples.map((example, i) => [example.title ?? i, example.content])); 30 | + } 31 | applyConstraint(getDoc, "description"); 32 | applyConstraint(getSummary, "title"); 33 | applyConstraint((p, t) => (getDeprecated(p, t) !== undefined ? true : undefined), "deprecated"); 34 | @@ -680,6 +693,54 @@ _OpenAPI3SchemaEmitter_metadataInfo = new WeakMap(), _OpenAPI3SchemaEmitter_visi 35 | return encodeAsFormat !== null && encodeAsFormat !== void 0 ? encodeAsFormat : encoding; 36 | } 37 | }; 38 | +function checkIfTagHasDocOnSameLine(tag) { 39 | + const start = tag.content[0]?.pos; 40 | + const end = tag.content[0]?.end; 41 | + const file = getSourceLocation(tag.content[0]).file; 42 | + 43 | + let hasFirstLine = false; 44 | + for (let i = start; i < end; i++) { 45 | + const ch = file.text[i]; 46 | + if (ch === "\n") { 47 | + break; 48 | + } 49 | + // Todo reuse compiler whitespace logic or have a way to get this info from the parser. 50 | + if (ch !== " ") { 51 | + hasFirstLine = true; 52 | + } 53 | + } 54 | + return hasFirstLine; 55 | + } 56 | +function extractExample(tag) { 57 | + const content = getDocContent(tag.content); 58 | + const hasInfoOnFirstLine = checkIfTagHasDocOnSameLine(tag); 59 | + try { 60 | + if (hasInfoOnFirstLine) { 61 | + const [title, ...contents] = content.split("\n"); 62 | + if (contents.length > 0) { 63 | + return { title, content: JSON.parse(contents.join("\n").replace(/^(```|`)|(`|```)$/g, '')) }; 64 | + } else { 65 | + return { content: JSON.parse(content.replace(/^(```|`)|(`|```)$/g, '')) }; 66 | + } 67 | + } else { 68 | + return { content: JSON.parse(content.replace(/^(```|`)|(`|```)$/g, '')) }; 69 | + } 70 | + } catch (e) { 71 | + console.error(`Error: ${e?.message}\n${content} is not a valid json.`); 72 | + return `ERROR: ${e?.message}`; 73 | + } 74 | +} 75 | +function getDocContent(content) { 76 | + const docs = []; 77 | + for (const node of content) { 78 | + compilerAssert( 79 | + node.kind === SyntaxKind.DocText, 80 | + "No other doc content node kinds exist yet. Update this code appropriately when more are added." 81 | + ); 82 | + docs.push(node.text); 83 | + } 84 | + return docs.join("").replace(/\\\n/g, ""); 85 | +} 86 | function isLiteralType(type) { 87 | return type.kind === "Boolean" || type.kind === "String" || type.kind === "Number"; 88 | } 89 | -------------------------------------------------------------------------------- /patches/serve-reload-replace@4.0.3.patch: -------------------------------------------------------------------------------- 1 | diff --git a/lib/bin.js b/lib/bin.js 2 | index 8628ed0638e271935f9298e2eb0f3e9ba286990b..aa98d191e9f7b50f999da0bcb955a3853565e894 100755 3 | --- a/lib/bin.js 4 | +++ b/lib/bin.js 5 | @@ -12,11 +12,15 @@ const options = { 6 | '--index': String, 7 | '--port': String, 8 | '--root': String, 9 | + '--ignore': String, 10 | + '--proxy': String, 11 | '--verbose': Boolean 12 | } 13 | 14 | const usage = `Usage: srr [options] 15 | ${chalk.yellow('--root')} Path to serve & watch default: $PWD 16 | + ${chalk.yellow('--ignore')} Regex filter to ignore files from being watched default: null 17 | + ${chalk.yellow('--proxy')} WHat url should the proxy point to default: null 18 | ${chalk.yellow('--client')} Path to custom EventSource client default: built-in 19 | ${chalk.yellow('--address')} Specify network interface to use default: 0.0.0.0 20 | ${chalk.yellow('--port')} Specify a port to use default: 8080 21 | @@ -34,4 +38,4 @@ if (args.help) { 22 | 23 | const server = new SRR(args) 24 | 25 | -server.start() 26 | +server.start(args) 27 | diff --git a/lib/client.js b/lib/client.js 28 | index 7deb3eca3c97ce67e6fb28e1f0e7f25aa1506796..4646aa9c7c3529392de2ae178153769dbcf3e0c7 100644 29 | --- a/lib/client.js 30 | +++ b/lib/client.js 31 | @@ -9,3 +9,8 @@ sse.addEventListener('error', event => { 32 | }) 33 | 34 | // TODO: track resources on page 35 | + 36 | +const originalFetch = globalThis.fetch; 37 | +globalThis.fetch = function proxiedFetch(url, ...args) { 38 | + return originalFetch(PROXY_HOST && url.startsWith(PROXY_HOST) ? url.replace(PROXY_HOST, 'proxy') : url, ...args); 39 | +} 40 | diff --git a/lib/handler.js b/lib/handler.js 41 | index 9c49dcdfa10772985ae3ac8230c75a6b2a72ad13..2b082beec37037ebd8d948194a7cccac8ffee622 100644 42 | --- a/lib/handler.js 43 | +++ b/lib/handler.js 44 | @@ -8,7 +8,7 @@ const headerFormat = headers => { 45 | return Object.keys(headers).map(() => '%s:gray: %s:dim').join(' ') 46 | } 47 | 48 | -module.exports = function ({ client, clients, root, index, verbose }) { 49 | +module.exports = function ({ client, clients, root, index, verbose, proxy }) { 50 | return async (request, response) => { 51 | // set headers object 52 | response.headers = {} 53 | @@ -50,16 +50,31 @@ module.exports = function ({ client, clients, root, index, verbose }) { 54 | return 55 | } 56 | 57 | + if (proxy && request.url.startsWith('/proxy')) { 58 | + const path = request.url.substring('/proxy'.length) || '/'; 59 | + const fetchResp = await fetch(proxy + path, { 60 | + method: request.method, 61 | + headers: request.headers, 62 | + }); 63 | + response.writeHead(fetchResp.status, { 64 | + ...Object.fromEntries(fetchResp.headers), 65 | + 'content-encoding': '', 66 | + }); 67 | + response.end(Buffer.from(await fetchResp.arrayBuffer())); 68 | + log('%dot:green %s:white %s:magenta ↦ %s:white %s:dim (proxied)', request.method, request.url, response.statusCode, response.statusMessage) 69 | + return; 70 | + } 71 | + 72 | try { 73 | if (request.url === '/__client') { 74 | try { 75 | const path = client ? urlToPath(root, `/${client}`) : urlToPath(__dirname, '/client.js') 76 | - const script = await readFile(path) 77 | + const script = await readFile(path, { encoding: 'utf8' }) 78 | response.writeHead(200, { 79 | 'content-type': 'text/javascript', 80 | 'cache-control': 'no-store' 81 | }) 82 | - response.end(script) 83 | + response.end(script.replace(/PROXY_HOST/g, proxy ? JSON.stringify(proxy) : 'null')) 84 | return 85 | } catch (err) { 86 | const error = new Error(`Error Loading Client: ${err.message}`) 87 | diff --git a/lib/server.js b/lib/server.js 88 | index 50590f6c1e4f83481a310c2b253e707ed808b3f2..9701856ccc00dbb90639d36b63f591322b2e1f19 100644 89 | --- a/lib/server.js 90 | +++ b/lib/server.js 91 | @@ -15,7 +15,7 @@ class SRR { 92 | #clients = {} 93 | #instance = null 94 | 95 | - constructor ({ verbose = false, root = process.cwd(), index = 'index.html', client } = {}) { 96 | + constructor ({ verbose = false, root = process.cwd(), index = 'index.html', client, ignore, proxy } = {}) { 97 | this.#instance = new Server() 98 | this.#options = { verbose, root, index, client } 99 | 100 | @@ -25,7 +25,7 @@ class SRR { 101 | const cwd = expandTilde(root) 102 | const watcher = watch('.', { cwd, ignoreInitial: true }) 103 | 104 | - watcher.on('all', sse(this.#clients)) 105 | + watcher.on('all', sse(this.#clients, ignore)) 106 | 107 | /* istanbul ignore next */ 108 | watcher.on('ready', () => log('%dot:green Watching files in %s:yellow', cwd)) 109 | @@ -35,7 +35,7 @@ class SRR { 110 | this.exit() 111 | }) 112 | 113 | - this.#instance.on('listening', () => log('%dot:green Listening on %s:yellow %d:red', this.#instance.address().address, this.#instance.address().port)) 114 | + this.#instance.on('listening', () => log('%dot:green Listening on http://%s:yellow:%d:red/unofficial-documentation', this.#instance.address().address, this.#instance.address().port)) 115 | this.#instance.on('close', async () => { 116 | log('%dot:red Server Stopped') 117 | 118 | @@ -44,7 +44,7 @@ class SRR { 119 | }) 120 | 121 | // main handler 122 | - this.#instance.on('request', request({ client, clients: this.#clients, root, index, verbose })) 123 | + this.#instance.on('request', request({ client, clients: this.#clients, root, index, verbose, proxy })) 124 | } 125 | 126 | start ({ address = '0.0.0.0', port = 8080 } = {}) { 127 | diff --git a/lib/sse.js b/lib/sse.js 128 | index 029b922088eab603d1bb4ff3e0759204ded3197f..dd2d5e5c723a6e202fdd1a97dd7df0b966f80b3d 100644 129 | --- a/lib/sse.js 130 | +++ b/lib/sse.js 131 | @@ -1,7 +1,9 @@ 132 | const { log } = require('./log') 133 | 134 | -module.exports = function (clients, passThrough = false) { 135 | +module.exports = function (clients, ignore, passThrough = false) { 136 | + ignore = typeof ignore === 'string' ? new RegExp(ignore) : null; 137 | return (event, path) => { 138 | + if (ignore && ignore.test(path)) return; 139 | log('%dot:yellow %s:dim %s:blue', event, path) 140 | 141 | Object.values(clients).forEach(response => { 142 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | patchedDependencies: 8 | '@typespec/openapi3@0.54.0-dev.11': 9 | hash: q2a7ywvkbbdrx7o6zfnuzklmdm 10 | path: patches/@typespec__openapi3@0.54.0-dev.11.patch 11 | serve-reload-replace@4.0.3: 12 | hash: bajuoovynzaplahtsvu3xnzwpa 13 | path: patches/serve-reload-replace@4.0.3.patch 14 | 15 | importers: 16 | 17 | .: 18 | dependencies: 19 | '@typespec/best-practices': 20 | specifier: ^0.46.0-dev.0 21 | version: 0.46.0-dev.0(@typespec/compiler@0.54.0-dev.21) 22 | '@typespec/compiler': 23 | specifier: 0.54.0-dev.21 24 | version: 0.54.0-dev.21 25 | '@typespec/http': 26 | specifier: 0.54.0-dev.7 27 | version: 0.54.0-dev.7(@typespec/compiler@0.54.0-dev.21) 28 | '@typespec/openapi': 29 | specifier: 0.54.0-dev.3 30 | version: 0.54.0-dev.3(@typespec/compiler@0.54.0-dev.21)(@typespec/http@0.54.0-dev.7(@typespec/compiler@0.54.0-dev.21)) 31 | '@typespec/openapi3': 32 | specifier: 0.54.0-dev.11 33 | version: 0.54.0-dev.11(patch_hash=q2a7ywvkbbdrx7o6zfnuzklmdm)(@typespec/compiler@0.54.0-dev.21)(@typespec/http@0.54.0-dev.7(@typespec/compiler@0.54.0-dev.21))(@typespec/openapi@0.54.0-dev.3(@typespec/compiler@0.54.0-dev.21)(@typespec/http@0.54.0-dev.7(@typespec/compiler@0.54.0-dev.21)))(@typespec/versioning@0.54.0-dev.4(@typespec/compiler@0.54.0-dev.21)) 34 | '@typespec/prettier-plugin-typespec': 35 | specifier: 0.54.0-dev.2 36 | version: 0.54.0-dev.2 37 | '@typespec/rest': 38 | specifier: 0.54.0-dev.2 39 | version: 0.54.0-dev.2(@typespec/compiler@0.54.0-dev.21)(@typespec/http@0.54.0-dev.7(@typespec/compiler@0.54.0-dev.21)) 40 | '@typespec/versioning': 41 | specifier: 0.54.0-dev.4 42 | version: 0.54.0-dev.4(@typespec/compiler@0.54.0-dev.21) 43 | concurrently: 44 | specifier: ^8.2.2 45 | version: 8.2.2 46 | deepmerge: 47 | specifier: ^4.3.1 48 | version: 4.3.1 49 | nodemon: 50 | specifier: ^3.1.0 51 | version: 3.1.0 52 | prettier: 53 | specifier: ^3.2.5 54 | version: 3.2.5 55 | serve-reload-replace: 56 | specifier: ^4.0.3 57 | version: 4.0.3(patch_hash=bajuoovynzaplahtsvu3xnzwpa) 58 | yaml: 59 | specifier: ^2.4.0 60 | version: 2.4.0 61 | zx: 62 | specifier: ^7.2.3 63 | version: 7.2.3 64 | 65 | packages: 66 | 67 | '@babel/code-frame@7.23.5': 68 | resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} 69 | engines: {node: '>=6.9.0'} 70 | 71 | '@babel/helper-validator-identifier@7.22.20': 72 | resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} 73 | engines: {node: '>=6.9.0'} 74 | 75 | '@babel/highlight@7.23.4': 76 | resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} 77 | engines: {node: '>=6.9.0'} 78 | 79 | '@babel/runtime@7.24.0': 80 | resolution: {integrity: sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==} 81 | engines: {node: '>=6.9.0'} 82 | 83 | '@nodelib/fs.scandir@2.1.5': 84 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 85 | engines: {node: '>= 8'} 86 | 87 | '@nodelib/fs.stat@2.0.5': 88 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 89 | engines: {node: '>= 8'} 90 | 91 | '@nodelib/fs.walk@1.2.8': 92 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 93 | engines: {node: '>= 8'} 94 | 95 | '@sindresorhus/merge-streams@2.3.0': 96 | resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} 97 | engines: {node: '>=18'} 98 | 99 | '@types/fs-extra@11.0.4': 100 | resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} 101 | 102 | '@types/jsonfile@6.1.4': 103 | resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} 104 | 105 | '@types/minimist@1.2.5': 106 | resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} 107 | 108 | '@types/node@18.19.22': 109 | resolution: {integrity: sha512-p3pDIfuMg/aXBmhkyanPshdfJuX5c5+bQjYLIikPLXAUycEogij/c50n/C+8XOA5L93cU4ZRXtn+dNQGi0IZqQ==} 110 | 111 | '@types/ps-tree@1.1.6': 112 | resolution: {integrity: sha512-PtrlVaOaI44/3pl3cvnlK+GxOM3re2526TJvPvh7W+keHIXdV4TE0ylpPBAcvFQCbGitaTXwL9u+RF7qtVeazQ==} 113 | 114 | '@types/which@3.0.3': 115 | resolution: {integrity: sha512-2C1+XoY0huExTbs8MQv1DuS5FS86+SEjdM9F/+GS61gg5Hqbtj8ZiDSx8MfWcyei907fIPbfPGCOrNUTnVHY1g==} 116 | 117 | '@typespec/best-practices@0.46.0-dev.0': 118 | resolution: {integrity: sha512-jgmHisamuyskmkuQcWdsyVuow7DGlVlX1LFAnwUvd9tZQgYe62tlad+4EvpfacklFvCKyLdrS8oAEEESBfpy1g==} 119 | engines: {node: '>=18.0.0'} 120 | peerDependencies: 121 | '@typespec/compiler': ~0.52.0 || >=0.53.0-dev <0.53.0 122 | 123 | '@typespec/compiler@0.54.0-dev.21': 124 | resolution: {integrity: sha512-yfWdCVH630NMgQdi1QHviRKgIs3TU4xyLbWmg3I2+Q7eV5aZJ07TLw+7cSEW2YN6g2CRQSStWJz3VPv3ffcL2Q==} 125 | engines: {node: '>=18.0.0'} 126 | hasBin: true 127 | 128 | '@typespec/http@0.54.0-dev.7': 129 | resolution: {integrity: sha512-fMYjfrAE9y6cwjZmI/ju9E08RhpksASDTT3KR003fLfpNDNVmllnWEHSDAsurWsDFNUI1GgVO1gtP2MSrhPaWw==} 130 | engines: {node: '>=18.0.0'} 131 | peerDependencies: 132 | '@typespec/compiler': ~0.53.1 || >=0.54.0-dev <0.54.0 133 | 134 | '@typespec/openapi3@0.54.0-dev.11': 135 | resolution: {integrity: sha512-aOf/QYkt61O5c+YZd4hTCZsyTuKdJNZN7yuOMCwAePIhwQlNExi5E9GZCX1D5YT5dUgkXnQDFDUPVTEwLo9HFA==} 136 | engines: {node: '>=18.0.0'} 137 | peerDependencies: 138 | '@typespec/compiler': ~0.53.1 || >=0.54.0-dev <0.54.0 139 | '@typespec/http': ~0.53.0 || >=0.54.0-dev <0.54.0 140 | '@typespec/openapi': ~0.53.0 || >=0.54.0-dev <0.54.0 141 | '@typespec/versioning': ~0.53.0 || >=0.54.0-dev <0.54.0 142 | 143 | '@typespec/openapi@0.54.0-dev.3': 144 | resolution: {integrity: sha512-qohPsbCM1DNn+npOR4LIvXBwMrnPxiCGX8LTOqPpwFjy8G2DJZV4W4Ouo5pZ1vebzS+7lGYxXUpAFvGkfV+ASA==} 145 | engines: {node: '>=18.0.0'} 146 | peerDependencies: 147 | '@typespec/compiler': ~0.53.1 || >=0.54.0-dev <0.54.0 148 | '@typespec/http': ~0.53.0 || >=0.54.0-dev <0.54.0 149 | 150 | '@typespec/prettier-plugin-typespec@0.54.0-dev.2': 151 | resolution: {integrity: sha512-KoRgBJhFYvOCgXPZ+LNkTVwtmmG8EsN2bBCt8PSZPQtdlmT4IcIeaLY4wZ9Tvv1uJXDZ+snFDzl1GXDvFq1ZEg==} 152 | 153 | '@typespec/rest@0.54.0-dev.2': 154 | resolution: {integrity: sha512-Sk5omA7a2WmfmpRgHXSbC8uX/eozdmueW2TcfDv/+uFNS+xZN/EeJbOKwks/ir5wkWWUTJ8b1AZ5twnjMFQdTg==} 155 | engines: {node: '>=18.0.0'} 156 | peerDependencies: 157 | '@typespec/compiler': ~0.53.1 || >=0.54.0-dev <0.54.0 158 | '@typespec/http': ~0.53.0 || >=0.54.0-dev <0.54.0 159 | 160 | '@typespec/versioning@0.54.0-dev.4': 161 | resolution: {integrity: sha512-jpZ9emHt5lIHWK2wv+qztmeJ7tvsYANPWmcurl/VLQS7jJVs6WJ75HxT3fUMSkZ4oCb8AvHMlcg6EHN3dyRngA==} 162 | engines: {node: '>=18.0.0'} 163 | peerDependencies: 164 | '@typespec/compiler': ~0.53.1 || >=0.54.0-dev <0.54.0 165 | 166 | abbrev@1.1.1: 167 | resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} 168 | 169 | ajv@8.12.0: 170 | resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} 171 | 172 | ansi-regex@2.1.1: 173 | resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} 174 | engines: {node: '>=0.10.0'} 175 | 176 | ansi-regex@5.0.1: 177 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 178 | engines: {node: '>=8'} 179 | 180 | ansi-styles@2.2.1: 181 | resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==} 182 | engines: {node: '>=0.10.0'} 183 | 184 | ansi-styles@3.2.1: 185 | resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} 186 | engines: {node: '>=4'} 187 | 188 | ansi-styles@4.3.0: 189 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 190 | engines: {node: '>=8'} 191 | 192 | anymatch@3.1.3: 193 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} 194 | engines: {node: '>= 8'} 195 | 196 | balanced-match@1.0.2: 197 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 198 | 199 | binary-extensions@2.2.0: 200 | resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} 201 | engines: {node: '>=8'} 202 | 203 | brace-expansion@1.1.11: 204 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 205 | 206 | braces@3.0.2: 207 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} 208 | engines: {node: '>=8'} 209 | 210 | chalk@1.1.3: 211 | resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==} 212 | engines: {node: '>=0.10.0'} 213 | 214 | chalk@2.4.2: 215 | resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} 216 | engines: {node: '>=4'} 217 | 218 | chalk@4.1.2: 219 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 220 | engines: {node: '>=10'} 221 | 222 | chalk@5.3.0: 223 | resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} 224 | engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} 225 | 226 | change-case@5.4.3: 227 | resolution: {integrity: sha512-4cdyvorTy/lViZlVzw2O8/hHCLUuHqp4KpSSP3DlauhFCf3LdnfF+p5s0EAhjKsU7bqrMzu7iQArYfoPiHO2nw==} 228 | 229 | chokidar@3.6.0: 230 | resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} 231 | engines: {node: '>= 8.10.0'} 232 | 233 | cliui@8.0.1: 234 | resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} 235 | engines: {node: '>=12'} 236 | 237 | color-convert@1.9.3: 238 | resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} 239 | 240 | color-convert@2.0.1: 241 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 242 | engines: {node: '>=7.0.0'} 243 | 244 | color-name@1.1.3: 245 | resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} 246 | 247 | color-name@1.1.4: 248 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 249 | 250 | concat-map@0.0.1: 251 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 252 | 253 | concurrently@8.2.2: 254 | resolution: {integrity: sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==} 255 | engines: {node: ^14.13.0 || >=16.0.0} 256 | hasBin: true 257 | 258 | data-uri-to-buffer@4.0.1: 259 | resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} 260 | engines: {node: '>= 12'} 261 | 262 | date-fns@2.30.0: 263 | resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} 264 | engines: {node: '>=0.11'} 265 | 266 | dateformat@2.2.0: 267 | resolution: {integrity: sha512-GODcnWq3YGoTnygPfi02ygEiRxqUxpJwuRHjdhJYuxpcZmDq4rjBiXYmbCCzStxo176ixfLT6i4NPwQooRySnw==} 268 | 269 | debug-log@1.0.1: 270 | resolution: {integrity: sha512-gV/pe1YIaKNgLYnd1g9VNW80tcb7oV5qvNUxG7NM8rbDpnl6RGunzlAtlGSb0wEs3nesu2vHNiX9TSsZ+Y+RjA==} 271 | engines: {node: '>=0.10.0'} 272 | 273 | debug@4.3.4: 274 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} 275 | engines: {node: '>=6.0'} 276 | peerDependencies: 277 | supports-color: '*' 278 | peerDependenciesMeta: 279 | supports-color: 280 | optional: true 281 | 282 | deepmerge@4.3.1: 283 | resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} 284 | engines: {node: '>=0.10.0'} 285 | 286 | dir-glob@3.0.1: 287 | resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} 288 | engines: {node: '>=8'} 289 | 290 | duplexer@0.1.2: 291 | resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} 292 | 293 | emoji-regex@8.0.0: 294 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 295 | 296 | escalade@3.1.2: 297 | resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} 298 | engines: {node: '>=6'} 299 | 300 | escape-string-regexp@1.0.5: 301 | resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} 302 | engines: {node: '>=0.8.0'} 303 | 304 | event-stream@3.3.4: 305 | resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} 306 | 307 | extend@3.0.2: 308 | resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} 309 | 310 | fast-deep-equal@3.1.3: 311 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 312 | 313 | fast-glob@3.3.2: 314 | resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} 315 | engines: {node: '>=8.6.0'} 316 | 317 | fastq@1.17.1: 318 | resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} 319 | 320 | fetch-blob@3.2.0: 321 | resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} 322 | engines: {node: ^12.20 || >= 14.13} 323 | 324 | fill-range@7.0.1: 325 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} 326 | engines: {node: '>=8'} 327 | 328 | formdata-polyfill@4.0.10: 329 | resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} 330 | engines: {node: '>=12.20.0'} 331 | 332 | from@0.1.7: 333 | resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} 334 | 335 | fs-extra@11.2.0: 336 | resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} 337 | engines: {node: '>=14.14'} 338 | 339 | fsevents@2.3.3: 340 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 341 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 342 | os: [darwin] 343 | 344 | furmat@1.0.0: 345 | resolution: {integrity: sha512-BHLCIQ0Vn8ehHbGch/jQrsl5hRXaupEmzwr22OMiO/O9EVYGCdVRjn9t8y8//Ltx4ZYHh5ifa9uG9gQwCvy72A==} 346 | engines: {node: '>=4'} 347 | 348 | fx@31.0.0: 349 | resolution: {integrity: sha512-OoeYSPKqNKmfnH4s+rGYI0c8OZmqqOOXsUtqy0YyHqQQoQSDiDs3m3M9uXKx5OQR+jDx7/FhYqpO3kl/As/xgg==} 350 | hasBin: true 351 | 352 | get-caller-file@2.0.5: 353 | resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} 354 | engines: {node: 6.* || 8.* || >= 10.*} 355 | 356 | glob-parent@5.1.2: 357 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 358 | engines: {node: '>= 6'} 359 | 360 | globby@13.2.2: 361 | resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==} 362 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 363 | 364 | globby@14.0.1: 365 | resolution: {integrity: sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==} 366 | engines: {node: '>=18'} 367 | 368 | graceful-fs@4.2.11: 369 | resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} 370 | 371 | has-ansi@2.0.0: 372 | resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==} 373 | engines: {node: '>=0.10.0'} 374 | 375 | has-flag@3.0.0: 376 | resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} 377 | engines: {node: '>=4'} 378 | 379 | has-flag@4.0.0: 380 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 381 | engines: {node: '>=8'} 382 | 383 | ignore-by-default@1.0.1: 384 | resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==} 385 | 386 | ignore@5.3.1: 387 | resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} 388 | engines: {node: '>= 4'} 389 | 390 | is-binary-path@2.1.0: 391 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 392 | engines: {node: '>=8'} 393 | 394 | is-extglob@2.1.1: 395 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 396 | engines: {node: '>=0.10.0'} 397 | 398 | is-fullwidth-code-point@3.0.0: 399 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 400 | engines: {node: '>=8'} 401 | 402 | is-glob@4.0.3: 403 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 404 | engines: {node: '>=0.10.0'} 405 | 406 | is-number@7.0.0: 407 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 408 | engines: {node: '>=0.12.0'} 409 | 410 | isexe@2.0.0: 411 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 412 | 413 | js-tokens@4.0.0: 414 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 415 | 416 | json-schema-traverse@1.0.0: 417 | resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} 418 | 419 | jsonfile@6.1.0: 420 | resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} 421 | 422 | kleur@3.0.3: 423 | resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} 424 | engines: {node: '>=6'} 425 | 426 | lodash@4.17.21: 427 | resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} 428 | 429 | lru-cache@6.0.0: 430 | resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} 431 | engines: {node: '>=10'} 432 | 433 | map-stream@0.1.0: 434 | resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} 435 | 436 | merge2@1.4.1: 437 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 438 | engines: {node: '>= 8'} 439 | 440 | micromatch@4.0.5: 441 | resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} 442 | engines: {node: '>=8.6'} 443 | 444 | minimatch@3.1.2: 445 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 446 | 447 | minimist@1.2.8: 448 | resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} 449 | 450 | ms@2.1.2: 451 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 452 | 453 | mustache@4.2.0: 454 | resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} 455 | hasBin: true 456 | 457 | node-domexception@1.0.0: 458 | resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} 459 | engines: {node: '>=10.5.0'} 460 | 461 | node-fetch@3.3.1: 462 | resolution: {integrity: sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow==} 463 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 464 | 465 | nodemon@3.1.0: 466 | resolution: {integrity: sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==} 467 | engines: {node: '>=10'} 468 | hasBin: true 469 | 470 | nopt@1.0.10: 471 | resolution: {integrity: sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==} 472 | hasBin: true 473 | 474 | normalize-path@3.0.0: 475 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 476 | engines: {node: '>=0.10.0'} 477 | 478 | oh-my-log@5.0.1: 479 | resolution: {integrity: sha512-M8zXpmsmI0RMOEZMVCjNEH5nNr9npmt14cgjkD1uh3iLSIpXpluQjoVwPv83HSGvNb8/edb5NhjyNMMTs1qLgA==} 480 | engines: {node: '>=4'} 481 | 482 | path-type@4.0.0: 483 | resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} 484 | engines: {node: '>=8'} 485 | 486 | path-type@5.0.0: 487 | resolution: {integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==} 488 | engines: {node: '>=12'} 489 | 490 | pause-stream@0.0.11: 491 | resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} 492 | 493 | picocolors@1.0.0: 494 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} 495 | 496 | picomatch@2.3.1: 497 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 498 | engines: {node: '>=8.6'} 499 | 500 | prettier@3.2.5: 501 | resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} 502 | engines: {node: '>=14'} 503 | hasBin: true 504 | 505 | prompts@2.4.2: 506 | resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} 507 | engines: {node: '>= 6'} 508 | 509 | ps-tree@1.2.0: 510 | resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==} 511 | engines: {node: '>= 0.10'} 512 | hasBin: true 513 | 514 | pstree.remy@1.1.8: 515 | resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} 516 | 517 | punycode@2.3.1: 518 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 519 | engines: {node: '>=6'} 520 | 521 | queue-microtask@1.2.3: 522 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 523 | 524 | readdirp@3.6.0: 525 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 526 | engines: {node: '>=8.10.0'} 527 | 528 | regenerator-runtime@0.14.1: 529 | resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} 530 | 531 | require-directory@2.1.1: 532 | resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} 533 | engines: {node: '>=0.10.0'} 534 | 535 | require-from-string@2.0.2: 536 | resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} 537 | engines: {node: '>=0.10.0'} 538 | 539 | reusify@1.0.4: 540 | resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} 541 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 542 | 543 | run-parallel@1.2.0: 544 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 545 | 546 | rxjs@7.8.1: 547 | resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} 548 | 549 | semver@7.6.0: 550 | resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} 551 | engines: {node: '>=10'} 552 | hasBin: true 553 | 554 | serve-reload-replace@4.0.3: 555 | resolution: {integrity: sha512-j1+tpVu/bxmeuhXXUOzeaHeYCSJTiHFIWwBcHl+gBpRAJncG+9hngXgjjrs2gH8iPzMLqSjhSMcpRXjHzLEIJA==} 556 | engines: {node: '>=14'} 557 | hasBin: true 558 | 559 | shell-quote@1.8.1: 560 | resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} 561 | 562 | simple-update-notifier@2.0.0: 563 | resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} 564 | engines: {node: '>=10'} 565 | 566 | sisteransi@1.0.5: 567 | resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} 568 | 569 | slash@4.0.0: 570 | resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} 571 | engines: {node: '>=12'} 572 | 573 | slash@5.1.0: 574 | resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} 575 | engines: {node: '>=14.16'} 576 | 577 | spawn-command@0.0.2: 578 | resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==} 579 | 580 | split@0.3.3: 581 | resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==} 582 | 583 | stream-combiner@0.0.4: 584 | resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==} 585 | 586 | string-width@4.2.3: 587 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 588 | engines: {node: '>=8'} 589 | 590 | strip-ansi@3.0.1: 591 | resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} 592 | engines: {node: '>=0.10.0'} 593 | 594 | strip-ansi@6.0.1: 595 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 596 | engines: {node: '>=8'} 597 | 598 | supports-color@2.0.0: 599 | resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==} 600 | engines: {node: '>=0.8.0'} 601 | 602 | supports-color@5.5.0: 603 | resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} 604 | engines: {node: '>=4'} 605 | 606 | supports-color@7.2.0: 607 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 608 | engines: {node: '>=8'} 609 | 610 | supports-color@8.1.1: 611 | resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} 612 | engines: {node: '>=10'} 613 | 614 | through@2.3.8: 615 | resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} 616 | 617 | to-regex-range@5.0.1: 618 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 619 | engines: {node: '>=8.0'} 620 | 621 | touch@3.1.0: 622 | resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==} 623 | hasBin: true 624 | 625 | tree-kill@1.2.2: 626 | resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} 627 | hasBin: true 628 | 629 | tslib@2.6.2: 630 | resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} 631 | 632 | undefsafe@2.0.5: 633 | resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} 634 | 635 | undici-types@5.26.5: 636 | resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} 637 | 638 | unicorn-magic@0.1.0: 639 | resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} 640 | engines: {node: '>=18'} 641 | 642 | universalify@2.0.1: 643 | resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} 644 | engines: {node: '>= 10.0.0'} 645 | 646 | uri-js@4.4.1: 647 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 648 | 649 | vscode-jsonrpc@8.2.0: 650 | resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} 651 | engines: {node: '>=14.0.0'} 652 | 653 | vscode-languageserver-protocol@3.17.5: 654 | resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} 655 | 656 | vscode-languageserver-textdocument@1.0.11: 657 | resolution: {integrity: sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==} 658 | 659 | vscode-languageserver-types@3.17.5: 660 | resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} 661 | 662 | vscode-languageserver@9.0.1: 663 | resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} 664 | hasBin: true 665 | 666 | web-streams-polyfill@3.3.3: 667 | resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} 668 | engines: {node: '>= 8'} 669 | 670 | webpod@0.0.2: 671 | resolution: {integrity: sha512-cSwwQIeg8v4i3p4ajHhwgR7N6VyxAf+KYSSsY6Pd3aETE+xEU4vbitz7qQkB0I321xnhDdgtxuiSfk5r/FVtjg==} 672 | hasBin: true 673 | 674 | which@3.0.1: 675 | resolution: {integrity: sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==} 676 | engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} 677 | hasBin: true 678 | 679 | wrap-ansi@7.0.0: 680 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 681 | engines: {node: '>=10'} 682 | 683 | y18n@5.0.8: 684 | resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} 685 | engines: {node: '>=10'} 686 | 687 | yallist@4.0.0: 688 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} 689 | 690 | yaml@2.3.4: 691 | resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==} 692 | engines: {node: '>= 14'} 693 | 694 | yaml@2.4.0: 695 | resolution: {integrity: sha512-j9iR8g+/t0lArF4V6NE/QCfT+CO7iLqrXAHZbJdo+LfjqP1vR8Fg5bSiaq6Q2lOD1AUEVrEVIgABvBFYojJVYQ==} 696 | engines: {node: '>= 14'} 697 | hasBin: true 698 | 699 | yargs-parser@21.1.1: 700 | resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} 701 | engines: {node: '>=12'} 702 | 703 | yargs@17.7.2: 704 | resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} 705 | engines: {node: '>=12'} 706 | 707 | zx@7.2.3: 708 | resolution: {integrity: sha512-QODu38nLlYXg/B/Gw7ZKiZrvPkEsjPN3LQ5JFXM7h0JvwhEdPNNl+4Ao1y4+o3CLNiDUNcwzQYZ4/Ko7kKzCMA==} 709 | engines: {node: '>= 16.0.0'} 710 | hasBin: true 711 | 712 | snapshots: 713 | 714 | '@babel/code-frame@7.23.5': 715 | dependencies: 716 | '@babel/highlight': 7.23.4 717 | chalk: 2.4.2 718 | 719 | '@babel/helper-validator-identifier@7.22.20': {} 720 | 721 | '@babel/highlight@7.23.4': 722 | dependencies: 723 | '@babel/helper-validator-identifier': 7.22.20 724 | chalk: 2.4.2 725 | js-tokens: 4.0.0 726 | 727 | '@babel/runtime@7.24.0': 728 | dependencies: 729 | regenerator-runtime: 0.14.1 730 | 731 | '@nodelib/fs.scandir@2.1.5': 732 | dependencies: 733 | '@nodelib/fs.stat': 2.0.5 734 | run-parallel: 1.2.0 735 | 736 | '@nodelib/fs.stat@2.0.5': {} 737 | 738 | '@nodelib/fs.walk@1.2.8': 739 | dependencies: 740 | '@nodelib/fs.scandir': 2.1.5 741 | fastq: 1.17.1 742 | 743 | '@sindresorhus/merge-streams@2.3.0': {} 744 | 745 | '@types/fs-extra@11.0.4': 746 | dependencies: 747 | '@types/jsonfile': 6.1.4 748 | '@types/node': 18.19.22 749 | 750 | '@types/jsonfile@6.1.4': 751 | dependencies: 752 | '@types/node': 18.19.22 753 | 754 | '@types/minimist@1.2.5': {} 755 | 756 | '@types/node@18.19.22': 757 | dependencies: 758 | undici-types: 5.26.5 759 | 760 | '@types/ps-tree@1.1.6': {} 761 | 762 | '@types/which@3.0.3': {} 763 | 764 | '@typespec/best-practices@0.46.0-dev.0(@typespec/compiler@0.54.0-dev.21)': 765 | dependencies: 766 | '@typespec/compiler': 0.54.0-dev.21 767 | 768 | '@typespec/compiler@0.54.0-dev.21': 769 | dependencies: 770 | '@babel/code-frame': 7.23.5 771 | ajv: 8.12.0 772 | change-case: 5.4.3 773 | globby: 14.0.1 774 | mustache: 4.2.0 775 | picocolors: 1.0.0 776 | prettier: 3.2.5 777 | prompts: 2.4.2 778 | semver: 7.6.0 779 | vscode-languageserver: 9.0.1 780 | vscode-languageserver-textdocument: 1.0.11 781 | yaml: 2.3.4 782 | yargs: 17.7.2 783 | 784 | '@typespec/http@0.54.0-dev.7(@typespec/compiler@0.54.0-dev.21)': 785 | dependencies: 786 | '@typespec/compiler': 0.54.0-dev.21 787 | 788 | '@typespec/openapi3@0.54.0-dev.11(patch_hash=q2a7ywvkbbdrx7o6zfnuzklmdm)(@typespec/compiler@0.54.0-dev.21)(@typespec/http@0.54.0-dev.7(@typespec/compiler@0.54.0-dev.21))(@typespec/openapi@0.54.0-dev.3(@typespec/compiler@0.54.0-dev.21)(@typespec/http@0.54.0-dev.7(@typespec/compiler@0.54.0-dev.21)))(@typespec/versioning@0.54.0-dev.4(@typespec/compiler@0.54.0-dev.21))': 789 | dependencies: 790 | '@typespec/compiler': 0.54.0-dev.21 791 | '@typespec/http': 0.54.0-dev.7(@typespec/compiler@0.54.0-dev.21) 792 | '@typespec/openapi': 0.54.0-dev.3(@typespec/compiler@0.54.0-dev.21)(@typespec/http@0.54.0-dev.7(@typespec/compiler@0.54.0-dev.21)) 793 | '@typespec/versioning': 0.54.0-dev.4(@typespec/compiler@0.54.0-dev.21) 794 | yaml: 2.3.4 795 | 796 | '@typespec/openapi@0.54.0-dev.3(@typespec/compiler@0.54.0-dev.21)(@typespec/http@0.54.0-dev.7(@typespec/compiler@0.54.0-dev.21))': 797 | dependencies: 798 | '@typespec/compiler': 0.54.0-dev.21 799 | '@typespec/http': 0.54.0-dev.7(@typespec/compiler@0.54.0-dev.21) 800 | 801 | '@typespec/prettier-plugin-typespec@0.54.0-dev.2': 802 | dependencies: 803 | prettier: 3.2.5 804 | 805 | '@typespec/rest@0.54.0-dev.2(@typespec/compiler@0.54.0-dev.21)(@typespec/http@0.54.0-dev.7(@typespec/compiler@0.54.0-dev.21))': 806 | dependencies: 807 | '@typespec/compiler': 0.54.0-dev.21 808 | '@typespec/http': 0.54.0-dev.7(@typespec/compiler@0.54.0-dev.21) 809 | 810 | '@typespec/versioning@0.54.0-dev.4(@typespec/compiler@0.54.0-dev.21)': 811 | dependencies: 812 | '@typespec/compiler': 0.54.0-dev.21 813 | 814 | abbrev@1.1.1: {} 815 | 816 | ajv@8.12.0: 817 | dependencies: 818 | fast-deep-equal: 3.1.3 819 | json-schema-traverse: 1.0.0 820 | require-from-string: 2.0.2 821 | uri-js: 4.4.1 822 | 823 | ansi-regex@2.1.1: {} 824 | 825 | ansi-regex@5.0.1: {} 826 | 827 | ansi-styles@2.2.1: {} 828 | 829 | ansi-styles@3.2.1: 830 | dependencies: 831 | color-convert: 1.9.3 832 | 833 | ansi-styles@4.3.0: 834 | dependencies: 835 | color-convert: 2.0.1 836 | 837 | anymatch@3.1.3: 838 | dependencies: 839 | normalize-path: 3.0.0 840 | picomatch: 2.3.1 841 | 842 | balanced-match@1.0.2: {} 843 | 844 | binary-extensions@2.2.0: {} 845 | 846 | brace-expansion@1.1.11: 847 | dependencies: 848 | balanced-match: 1.0.2 849 | concat-map: 0.0.1 850 | 851 | braces@3.0.2: 852 | dependencies: 853 | fill-range: 7.0.1 854 | 855 | chalk@1.1.3: 856 | dependencies: 857 | ansi-styles: 2.2.1 858 | escape-string-regexp: 1.0.5 859 | has-ansi: 2.0.0 860 | strip-ansi: 3.0.1 861 | supports-color: 2.0.0 862 | 863 | chalk@2.4.2: 864 | dependencies: 865 | ansi-styles: 3.2.1 866 | escape-string-regexp: 1.0.5 867 | supports-color: 5.5.0 868 | 869 | chalk@4.1.2: 870 | dependencies: 871 | ansi-styles: 4.3.0 872 | supports-color: 7.2.0 873 | 874 | chalk@5.3.0: {} 875 | 876 | change-case@5.4.3: {} 877 | 878 | chokidar@3.6.0: 879 | dependencies: 880 | anymatch: 3.1.3 881 | braces: 3.0.2 882 | glob-parent: 5.1.2 883 | is-binary-path: 2.1.0 884 | is-glob: 4.0.3 885 | normalize-path: 3.0.0 886 | readdirp: 3.6.0 887 | optionalDependencies: 888 | fsevents: 2.3.3 889 | 890 | cliui@8.0.1: 891 | dependencies: 892 | string-width: 4.2.3 893 | strip-ansi: 6.0.1 894 | wrap-ansi: 7.0.0 895 | 896 | color-convert@1.9.3: 897 | dependencies: 898 | color-name: 1.1.3 899 | 900 | color-convert@2.0.1: 901 | dependencies: 902 | color-name: 1.1.4 903 | 904 | color-name@1.1.3: {} 905 | 906 | color-name@1.1.4: {} 907 | 908 | concat-map@0.0.1: {} 909 | 910 | concurrently@8.2.2: 911 | dependencies: 912 | chalk: 4.1.2 913 | date-fns: 2.30.0 914 | lodash: 4.17.21 915 | rxjs: 7.8.1 916 | shell-quote: 1.8.1 917 | spawn-command: 0.0.2 918 | supports-color: 8.1.1 919 | tree-kill: 1.2.2 920 | yargs: 17.7.2 921 | 922 | data-uri-to-buffer@4.0.1: {} 923 | 924 | date-fns@2.30.0: 925 | dependencies: 926 | '@babel/runtime': 7.24.0 927 | 928 | dateformat@2.2.0: {} 929 | 930 | debug-log@1.0.1: {} 931 | 932 | debug@4.3.4(supports-color@5.5.0): 933 | dependencies: 934 | ms: 2.1.2 935 | optionalDependencies: 936 | supports-color: 5.5.0 937 | 938 | deepmerge@4.3.1: {} 939 | 940 | dir-glob@3.0.1: 941 | dependencies: 942 | path-type: 4.0.0 943 | 944 | duplexer@0.1.2: {} 945 | 946 | emoji-regex@8.0.0: {} 947 | 948 | escalade@3.1.2: {} 949 | 950 | escape-string-regexp@1.0.5: {} 951 | 952 | event-stream@3.3.4: 953 | dependencies: 954 | duplexer: 0.1.2 955 | from: 0.1.7 956 | map-stream: 0.1.0 957 | pause-stream: 0.0.11 958 | split: 0.3.3 959 | stream-combiner: 0.0.4 960 | through: 2.3.8 961 | 962 | extend@3.0.2: {} 963 | 964 | fast-deep-equal@3.1.3: {} 965 | 966 | fast-glob@3.3.2: 967 | dependencies: 968 | '@nodelib/fs.stat': 2.0.5 969 | '@nodelib/fs.walk': 1.2.8 970 | glob-parent: 5.1.2 971 | merge2: 1.4.1 972 | micromatch: 4.0.5 973 | 974 | fastq@1.17.1: 975 | dependencies: 976 | reusify: 1.0.4 977 | 978 | fetch-blob@3.2.0: 979 | dependencies: 980 | node-domexception: 1.0.0 981 | web-streams-polyfill: 3.3.3 982 | 983 | fill-range@7.0.1: 984 | dependencies: 985 | to-regex-range: 5.0.1 986 | 987 | formdata-polyfill@4.0.10: 988 | dependencies: 989 | fetch-blob: 3.2.0 990 | 991 | from@0.1.7: {} 992 | 993 | fs-extra@11.2.0: 994 | dependencies: 995 | graceful-fs: 4.2.11 996 | jsonfile: 6.1.0 997 | universalify: 2.0.1 998 | 999 | fsevents@2.3.3: 1000 | optional: true 1001 | 1002 | furmat@1.0.0: 1003 | dependencies: 1004 | chalk: 1.1.3 1005 | 1006 | fx@31.0.0: {} 1007 | 1008 | get-caller-file@2.0.5: {} 1009 | 1010 | glob-parent@5.1.2: 1011 | dependencies: 1012 | is-glob: 4.0.3 1013 | 1014 | globby@13.2.2: 1015 | dependencies: 1016 | dir-glob: 3.0.1 1017 | fast-glob: 3.3.2 1018 | ignore: 5.3.1 1019 | merge2: 1.4.1 1020 | slash: 4.0.0 1021 | 1022 | globby@14.0.1: 1023 | dependencies: 1024 | '@sindresorhus/merge-streams': 2.3.0 1025 | fast-glob: 3.3.2 1026 | ignore: 5.3.1 1027 | path-type: 5.0.0 1028 | slash: 5.1.0 1029 | unicorn-magic: 0.1.0 1030 | 1031 | graceful-fs@4.2.11: {} 1032 | 1033 | has-ansi@2.0.0: 1034 | dependencies: 1035 | ansi-regex: 2.1.1 1036 | 1037 | has-flag@3.0.0: {} 1038 | 1039 | has-flag@4.0.0: {} 1040 | 1041 | ignore-by-default@1.0.1: {} 1042 | 1043 | ignore@5.3.1: {} 1044 | 1045 | is-binary-path@2.1.0: 1046 | dependencies: 1047 | binary-extensions: 2.2.0 1048 | 1049 | is-extglob@2.1.1: {} 1050 | 1051 | is-fullwidth-code-point@3.0.0: {} 1052 | 1053 | is-glob@4.0.3: 1054 | dependencies: 1055 | is-extglob: 2.1.1 1056 | 1057 | is-number@7.0.0: {} 1058 | 1059 | isexe@2.0.0: {} 1060 | 1061 | js-tokens@4.0.0: {} 1062 | 1063 | json-schema-traverse@1.0.0: {} 1064 | 1065 | jsonfile@6.1.0: 1066 | dependencies: 1067 | universalify: 2.0.1 1068 | optionalDependencies: 1069 | graceful-fs: 4.2.11 1070 | 1071 | kleur@3.0.3: {} 1072 | 1073 | lodash@4.17.21: {} 1074 | 1075 | lru-cache@6.0.0: 1076 | dependencies: 1077 | yallist: 4.0.0 1078 | 1079 | map-stream@0.1.0: {} 1080 | 1081 | merge2@1.4.1: {} 1082 | 1083 | micromatch@4.0.5: 1084 | dependencies: 1085 | braces: 3.0.2 1086 | picomatch: 2.3.1 1087 | 1088 | minimatch@3.1.2: 1089 | dependencies: 1090 | brace-expansion: 1.1.11 1091 | 1092 | minimist@1.2.8: {} 1093 | 1094 | ms@2.1.2: {} 1095 | 1096 | mustache@4.2.0: {} 1097 | 1098 | node-domexception@1.0.0: {} 1099 | 1100 | node-fetch@3.3.1: 1101 | dependencies: 1102 | data-uri-to-buffer: 4.0.1 1103 | fetch-blob: 3.2.0 1104 | formdata-polyfill: 4.0.10 1105 | 1106 | nodemon@3.1.0: 1107 | dependencies: 1108 | chokidar: 3.6.0 1109 | debug: 4.3.4(supports-color@5.5.0) 1110 | ignore-by-default: 1.0.1 1111 | minimatch: 3.1.2 1112 | pstree.remy: 1.1.8 1113 | semver: 7.6.0 1114 | simple-update-notifier: 2.0.0 1115 | supports-color: 5.5.0 1116 | touch: 3.1.0 1117 | undefsafe: 2.0.5 1118 | 1119 | nopt@1.0.10: 1120 | dependencies: 1121 | abbrev: 1.1.1 1122 | 1123 | normalize-path@3.0.0: {} 1124 | 1125 | oh-my-log@5.0.1: 1126 | dependencies: 1127 | chalk: 1.1.3 1128 | dateformat: 2.2.0 1129 | debug-log: 1.0.1 1130 | extend: 3.0.2 1131 | furmat: 1.0.0 1132 | 1133 | path-type@4.0.0: {} 1134 | 1135 | path-type@5.0.0: {} 1136 | 1137 | pause-stream@0.0.11: 1138 | dependencies: 1139 | through: 2.3.8 1140 | 1141 | picocolors@1.0.0: {} 1142 | 1143 | picomatch@2.3.1: {} 1144 | 1145 | prettier@3.2.5: {} 1146 | 1147 | prompts@2.4.2: 1148 | dependencies: 1149 | kleur: 3.0.3 1150 | sisteransi: 1.0.5 1151 | 1152 | ps-tree@1.2.0: 1153 | dependencies: 1154 | event-stream: 3.3.4 1155 | 1156 | pstree.remy@1.1.8: {} 1157 | 1158 | punycode@2.3.1: {} 1159 | 1160 | queue-microtask@1.2.3: {} 1161 | 1162 | readdirp@3.6.0: 1163 | dependencies: 1164 | picomatch: 2.3.1 1165 | 1166 | regenerator-runtime@0.14.1: {} 1167 | 1168 | require-directory@2.1.1: {} 1169 | 1170 | require-from-string@2.0.2: {} 1171 | 1172 | reusify@1.0.4: {} 1173 | 1174 | run-parallel@1.2.0: 1175 | dependencies: 1176 | queue-microtask: 1.2.3 1177 | 1178 | rxjs@7.8.1: 1179 | dependencies: 1180 | tslib: 2.6.2 1181 | 1182 | semver@7.6.0: 1183 | dependencies: 1184 | lru-cache: 6.0.0 1185 | 1186 | serve-reload-replace@4.0.3(patch_hash=bajuoovynzaplahtsvu3xnzwpa): 1187 | dependencies: 1188 | chalk: 4.1.2 1189 | chokidar: 3.6.0 1190 | oh-my-log: 5.0.1 1191 | 1192 | shell-quote@1.8.1: {} 1193 | 1194 | simple-update-notifier@2.0.0: 1195 | dependencies: 1196 | semver: 7.6.0 1197 | 1198 | sisteransi@1.0.5: {} 1199 | 1200 | slash@4.0.0: {} 1201 | 1202 | slash@5.1.0: {} 1203 | 1204 | spawn-command@0.0.2: {} 1205 | 1206 | split@0.3.3: 1207 | dependencies: 1208 | through: 2.3.8 1209 | 1210 | stream-combiner@0.0.4: 1211 | dependencies: 1212 | duplexer: 0.1.2 1213 | 1214 | string-width@4.2.3: 1215 | dependencies: 1216 | emoji-regex: 8.0.0 1217 | is-fullwidth-code-point: 3.0.0 1218 | strip-ansi: 6.0.1 1219 | 1220 | strip-ansi@3.0.1: 1221 | dependencies: 1222 | ansi-regex: 2.1.1 1223 | 1224 | strip-ansi@6.0.1: 1225 | dependencies: 1226 | ansi-regex: 5.0.1 1227 | 1228 | supports-color@2.0.0: {} 1229 | 1230 | supports-color@5.5.0: 1231 | dependencies: 1232 | has-flag: 3.0.0 1233 | 1234 | supports-color@7.2.0: 1235 | dependencies: 1236 | has-flag: 4.0.0 1237 | 1238 | supports-color@8.1.1: 1239 | dependencies: 1240 | has-flag: 4.0.0 1241 | 1242 | through@2.3.8: {} 1243 | 1244 | to-regex-range@5.0.1: 1245 | dependencies: 1246 | is-number: 7.0.0 1247 | 1248 | touch@3.1.0: 1249 | dependencies: 1250 | nopt: 1.0.10 1251 | 1252 | tree-kill@1.2.2: {} 1253 | 1254 | tslib@2.6.2: {} 1255 | 1256 | undefsafe@2.0.5: {} 1257 | 1258 | undici-types@5.26.5: {} 1259 | 1260 | unicorn-magic@0.1.0: {} 1261 | 1262 | universalify@2.0.1: {} 1263 | 1264 | uri-js@4.4.1: 1265 | dependencies: 1266 | punycode: 2.3.1 1267 | 1268 | vscode-jsonrpc@8.2.0: {} 1269 | 1270 | vscode-languageserver-protocol@3.17.5: 1271 | dependencies: 1272 | vscode-jsonrpc: 8.2.0 1273 | vscode-languageserver-types: 3.17.5 1274 | 1275 | vscode-languageserver-textdocument@1.0.11: {} 1276 | 1277 | vscode-languageserver-types@3.17.5: {} 1278 | 1279 | vscode-languageserver@9.0.1: 1280 | dependencies: 1281 | vscode-languageserver-protocol: 3.17.5 1282 | 1283 | web-streams-polyfill@3.3.3: {} 1284 | 1285 | webpod@0.0.2: {} 1286 | 1287 | which@3.0.1: 1288 | dependencies: 1289 | isexe: 2.0.0 1290 | 1291 | wrap-ansi@7.0.0: 1292 | dependencies: 1293 | ansi-styles: 4.3.0 1294 | string-width: 4.2.3 1295 | strip-ansi: 6.0.1 1296 | 1297 | y18n@5.0.8: {} 1298 | 1299 | yallist@4.0.0: {} 1300 | 1301 | yaml@2.3.4: {} 1302 | 1303 | yaml@2.4.0: {} 1304 | 1305 | yargs-parser@21.1.1: {} 1306 | 1307 | yargs@17.7.2: 1308 | dependencies: 1309 | cliui: 8.0.1 1310 | escalade: 3.1.2 1311 | get-caller-file: 2.0.5 1312 | require-directory: 2.1.1 1313 | string-width: 4.2.3 1314 | y18n: 5.0.8 1315 | yargs-parser: 21.1.1 1316 | 1317 | zx@7.2.3: 1318 | dependencies: 1319 | '@types/fs-extra': 11.0.4 1320 | '@types/minimist': 1.2.5 1321 | '@types/node': 18.19.22 1322 | '@types/ps-tree': 1.1.6 1323 | '@types/which': 3.0.3 1324 | chalk: 5.3.0 1325 | fs-extra: 11.2.0 1326 | fx: 31.0.0 1327 | globby: 13.2.2 1328 | minimist: 1.2.8 1329 | node-fetch: 3.3.1 1330 | ps-tree: 1.2.0 1331 | webpod: 0.0.2 1332 | which: 3.0.1 1333 | yaml: 2.4.0 1334 | -------------------------------------------------------------------------------- /scripts/build.js: -------------------------------------------------------------------------------- 1 | import { $ } from 'zx'; 2 | 3 | await $`tsp compile src`; 4 | await $`rm -rf build`; 5 | await $`mkdir build`; 6 | await $`mkdir build/unofficial-documentation`; 7 | await $`cp favicon.svg build/unofficial-documentation`; 8 | await $`cp index.html build/unofficial-documentation`; 9 | await $`cp -r tsp-output build/unofficial-documentation`; 10 | await $`cp -r vendors build/unofficial-documentation`; 11 | await $`cp -r assets build/unofficial-documentation`; 12 | await $`echo '' >build/index.html`; 13 | 14 | const branch = await $`git branch --show-current`.quiet(); 15 | if (branch.stdout.trim() != 'main') { 16 | const hash = (await $`git rev-parse --short HEAD`.quiet()).toString().trim(); 17 | const version = `${hash}`; 18 | 19 | $.quote = (s) => s; 20 | await $`sed -E "s/version:.+/version: \\"${version}\\"/" -i "build/unofficial-documentation/tsp-output/@typespec/openapi3/openapi.yaml"`; 21 | } 22 | -------------------------------------------------------------------------------- /scripts/git-hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | pnpm run lint:format 3 | -------------------------------------------------------------------------------- /src/auth.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | 3 | /** 4 | * JWT 규격의 solved.ac 사용자 접근 토큰을 Cookie로 넘깁니다. 5 | */ 6 | model TokenAuth is ApiKeyAuth; 7 | 8 | namespace SolvedAC { 9 | /** 10 | * `solvedacToken`이 올바르지 않은 경우입니다. 11 | */ 12 | @error 13 | model Unauthorized { 14 | @statusCode status: 401; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/extensions.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | alias XInternal = "x-internal"; 4 | scalar Color extends string; 5 | alias TODO = unknown; 6 | -------------------------------------------------------------------------------- /src/main.tsp: -------------------------------------------------------------------------------- 1 | import "@typespec/http"; 2 | import "@typespec/rest"; 3 | import "@typespec/openapi"; 4 | import "@typespec/openapi3"; 5 | import "@typespec/versioning"; 6 | 7 | import "./operations/_barrel.tsp"; 8 | import "./models/_barrel.tsp"; 9 | import "./extensions.tsp"; 10 | 11 | using TypeSpec.Http; 12 | using TypeSpec.OpenAPI; 13 | using TypeSpec.Versioning; 14 | 15 | @service({ 16 | title: "@solvedac/unofficial-documentation", 17 | }) 18 | @server("https://solved.ac/api/v3", "") 19 | @info({ 20 | version: "3.2024.03+b1", 21 | description: """ 22 | 이 프로젝트는 [solved.ac](https://solved.ac/) API를 문서화하는 커뮤니티 프로젝트입니다. 23 | 24 | 이 저장소는 원작자의 요청에 따라 언제든 지워질 수 있으며, 현재 API와 일치하지 않을 수도 있는 점 양해 부탁드립니다. 25 | 26 | 27 | 28 | solved.ac 서비스는 shiftpsh가 기획·개발·디자인·운영하는 프로젝트로, 29 | 이 저장소와는 solved.ac의 API를 문서화해둔 것 이외에는 아무런 관련이 없습니다. 30 | 31 | 32 | 33 | [GitHub에서 보기](https://github.com/solvedac/unofficial-documentation) 34 | 35 | 36 | **주의**: (2023/03/08~) CORS 문제로 인해 API는 사이트 내에서 호출할 수 없으므로 별도 도구를 이용해주십시오. ([#51](https://github.com/solvedac/unofficial-documentation/issues/51))
37 | **참고**: 본 저장소를 내려받고, `pnpm dev`를 실행하시면 로컬 개발 서버를 프록시로 삼아 CORS를 무시할 수 있습니다. 38 | 39 | 40 | ![@solvedac/unofficial-documentation banner](/unofficial-documentation/assets/solvedac-ud-compact.png) 41 | """, 42 | contact: { 43 | name: "RanolP", 44 | email: "me@ranolp.dev", 45 | }, 46 | }) 47 | namespace SolvedAC; 48 | -------------------------------------------------------------------------------- /src/models/ArenaTier.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * Unrated를 0, 5 | * C를 1, 6 | * ..., 7 | * SSS+을 12, 8 | * X를 13으로 표현하는 아레나 티어입니다. 9 | * 자세한 값 정보는 표1. 아레나 레이팅 표를 펼쳐 참고하십시오. 10 | * 11 | *
12 | * 13 | * 표1. 아레나 레이팅 표 14 | * 15 | * 16 | * | 수치 | 이름 | 요구 레이팅 | 17 | * | ---: | :---------------------------------------------------------------------------------------------- | ---------------------------------------------: | 18 | * | 0 | Unrated | - | 19 | * | 1 | C | 1 | 20 | * | 2 | C+ | 400 | 21 | * | 3 | B | 800 | 22 | * | 4 | B+ | 1000 | 23 | * | 5 | A | 1200 | 24 | * | 6 | A+ | 1400 | 25 | * | 7 | S | 1600 | 26 | * | 8 | S+ | 1800 | 27 | * | 9 | SS | 2000 | 28 | * | 10 | SS+ | 2200 | 29 | * | 11 | SSS | 2400 | 30 | * | 12 | SSS+ | 2600 | 31 | * | 13 | X | 3000 | 32 | * 33 | *
34 | */ 35 | enum ArenaTier { 36 | Unknown: 0, 37 | C: 1, 38 | CPlus: 2, 39 | B: 3, 40 | BPlus: 4, 41 | A: 5, 42 | APlus: 6, 43 | S: 7, 44 | SPlus: 8, 45 | SS: 9, 46 | SSPlus: 10, 47 | SSS: 11, 48 | SSSPlus: 12, 49 | X: 13, 50 | } 51 | -------------------------------------------------------------------------------- /src/models/Background.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * 사용자가 획득할 수 있는 배경입니다. 5 | */ 6 | model Background { 7 | /** 8 | * 배경의 고유 ID입니다. 9 | * 10 | * @example "boardgame_7" 11 | */ 12 | backgroundId: string; 13 | 14 | /** 15 | * 배경 사진으로 가는 하이퍼링크입니다. 16 | * 17 | * @example "https://static.solved.ac/profile_bg/boardgame/chess.png" 18 | */ 19 | backgroundImageUrl: url; 20 | 21 | /** 22 | * 일러스트 배경 보기가 꺼져있을 때 보여줄 수 있는 대안 배경 사진으로 가는 하이퍼링크입니다. 23 | * 일러스트를 포함하지 않은 배경이거나, 배경 제작자가 따로 준비하지 않은 경우 `null` 값일 수 있습니다. 24 | * 25 | * @example "https://static.solved.ac/profile_bg/boardgame/chess_fallback.png" 26 | */ 27 | fallbackBackgroundImageUrl?: url | null; 28 | 29 | /** 30 | * 움직이는 배경이 켜져있을 때 보여줄 수 있는 배경 영상으로 가는 하이퍼링크입니다. 31 | * 배경 제작자가 따로 준비하지 않은 경우 `null` 값일 수 있습니다. 32 | * 33 | * @example "https://static.solved.ac/profile_bg/boardgame/chess.mp4" 34 | */ 35 | backgroundVideoUrl?: url | null; 36 | 37 | /** 38 | * 배경을 획득한 사용자 수입니다. 39 | * 40 | * @example 105 41 | */ 42 | unlockedUserCount: uint64; 43 | 44 | /** 45 | * 배경의 표시 이름입니다. 46 | * 47 | * @example "분석의 예술" 48 | */ 49 | displayName: string; 50 | 51 | /** 52 | * 배경의 설명입니다. 53 | * 54 | * @example 55 | * "나쁜 오프닝 뒤에는 미들게임이라는 희망이 있고, \ 56 | * 나쁜 미들게임 뒤에는 엔드게임이라는 희망이 있다. \ 57 | * 하지만 엔드게임에 들어갔다면 진실과 마주해야 한다." 58 | */ 59 | displayDescription: string; 60 | 61 | /** 62 | * 배경을 얻는 조건입니다. 63 | * 조건이 숨겨진 경우, 해당 값이 내려오지 않습니다. 64 | * 65 | * @example "보드게임컵에 출전해 7문제 이상 해결" 66 | */ 67 | conditions?: string | null; 68 | 69 | /** 70 | * 배경 획득 조건이 숨겨져 있는지 여부입니다. 71 | * 72 | * @example false 73 | */ 74 | hiddenConditions: boolean; 75 | 76 | /** 77 | * 일러스트 배경인지 여부입니다. 78 | * 79 | * @example true 80 | */ 81 | isIllust: boolean; 82 | 83 | /** 84 | * 배경 획득 유형 분류입니다. 85 | * 86 | * @example "contest" 87 | */ 88 | backgroundCategory: BackgroundCategory; 89 | 90 | /** 91 | * solved.ac 회사가 권리를 보유하는지 여부입니다. 92 | * @example true 93 | */ 94 | solvedCompanyRights: boolean; 95 | 96 | /** 97 | * 배경을 작업한 작가 목록입니다. 빈 배열일 수 있습니다. 98 | * 99 | * @example 100 | * [ 101 | * { 102 | * "authorId": "havana723", 103 | * "role": "Illustration", 104 | * "authorUrl": null, 105 | * "handle": "havana723", 106 | * "twitter": null, 107 | * "instagram": null, 108 | * "displayName": "havana723" 109 | * }, 110 | * { 111 | * "authorId": "shiftpsh", 112 | * "role": "Graphic art / Animations", 113 | * "authorUrl": "https://shiftpsh.com", 114 | * "handle": "shiftpsh", 115 | * "twitter": "shiftpsh", 116 | * "instagram": "shiftpsh", 117 | * "displayName": "shiftpsh" 118 | * } 119 | * ] 120 | */ 121 | authors: BackgroundAuthor[]; 122 | } 123 | -------------------------------------------------------------------------------- /src/models/BackgroundAuthor.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * 배경을 작업한 작가입니다. 5 | */ 6 | model BackgroundAuthor { 7 | /** 8 | * 작가 고유 ID입니다. 9 | * 10 | * @example "havana723" 11 | */ 12 | authorId: string; 13 | 14 | /** 15 | * 수행한 역할입니다. 16 | * 17 | * @example "Illustration" 18 | */ 19 | role: string; 20 | 21 | /** 22 | * 작가 홈페이지로 가는 하이퍼링크입니다. 23 | * 24 | * @example null 25 | */ 26 | authorUrl?: url | null; 27 | 28 | /** 29 | * 작가의 solved.ac 핸들입니다. 30 | * 31 | * @example "havana723" 32 | */ 33 | handle?: string | null; 34 | 35 | /** 36 | * 작가의 Twitter ID입니다. 37 | * 38 | * @example null 39 | */ 40 | twitter?: string | null; 41 | 42 | /** 43 | * 작가의 인스타그램 ID입니다. 44 | * 45 | * @example null 46 | */ 47 | instagram?: string | null; 48 | 49 | /** 50 | * 작가의 표시 이름입니다. 51 | * 52 | * @example "havana723" 53 | */ 54 | displayName: string; 55 | } 56 | -------------------------------------------------------------------------------- /src/models/BackgroundCategory.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * 배경 획득 유형 분류입니다. 5 | * 6 | * @example "contest" 7 | */ 8 | enum BackgroundCategory { 9 | /** 10 | * 이벤트 미션 수행으로 획득 11 | */ 12 | Event: "event", 13 | 14 | /** 15 | * 아레나 참여 후 조건 만족으로 획득 16 | */ 17 | Arena: "arena", 18 | 19 | /** 20 | * 업적 달성으로 획득 21 | */ 22 | Achievement: "achievement", 23 | 24 | /** 25 | * 시즌 변경을 함께해 획득 26 | */ 27 | Season: "season", 28 | 29 | /** 30 | * 대회 참여 후 조건 만족으로 획득 31 | */ 32 | Contest: "contest", 33 | } 34 | -------------------------------------------------------------------------------- /src/models/Badge.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.OpenAPI; 2 | 3 | namespace SolvedAC; 4 | 5 | /** 6 | * 사용자가 획득할 수 있는 뱃지입니다. 7 | */ 8 | model Badge { 9 | /** 10 | * 뱃지의 고유 ID입니다. 11 | * @example "anniversary_1st" 12 | */ 13 | badgeId: string; 14 | 15 | /** 16 | * 뱃지 사진으로 가는 하이퍼링크입니다. 17 | * @example "https://static.solved.ac/profile_badge/anniversary_1st.png" 18 | */ 19 | badgeImageUrl: url; 20 | 21 | /** 22 | * 뱃지가 표시되는 이름입니다. 23 | * @example "1솔브" 24 | */ 25 | displayName: string; 26 | 27 | /** 28 | * 뱃지의 설명입니다. 29 | * @example "solved.ac의 1주년과 함께했다" 30 | */ 31 | displayDescription: string; 32 | 33 | /** 34 | * 뱃지를 획득한 사용자 수입니다. 35 | * @example 5000 36 | */ 37 | unlockedUserCount: uint64; 38 | 39 | /** 40 | * @example "gold" 41 | */ 42 | badgeTier: BadgeTier; 43 | 44 | /** 45 | * @example "season" 46 | */ 47 | badgeCategory: BadgeCategory; 48 | 49 | /** 50 | * solved.ac 회사가 권리를 보유하는지 여부입니다. 51 | * @example true 52 | */ 53 | solvedCompanyRights: boolean; 54 | 55 | /** 56 | * 뱃지가 만들어진 시각입니다. 57 | * @example "2021-06-05T15:00:00.000Z" 58 | */ 59 | createdAt: offsetDateTime; 60 | } 61 | -------------------------------------------------------------------------------- /src/models/BadgeCategory.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * 뱃지 획득 유형 분류입니다. 5 | * @example "season" 6 | */ 7 | enum BadgeCategory { 8 | /** 9 | * 업적 달성으로 획득 10 | */ 11 | Achievement: "achievement", 12 | 13 | /** 14 | * 시즌 변경을 함께해 획득 15 | */ 16 | Season: "season", 17 | 18 | /** 19 | * 이벤트 미션 수행으로 획득 20 | */ 21 | Event: "event", 22 | 23 | /** 24 | * 대회 참여 후 조건 만족으로 획득 25 | */ 26 | Contest: "contest", 27 | } 28 | -------------------------------------------------------------------------------- /src/models/BadgeTier.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * 뱃지의 등급입니다. 5 | * @example "bronze" 6 | */ 7 | enum BadgeTier { 8 | Bronze: "bronze", 9 | Silver: "silver", 10 | Gold: "gold", 11 | Master: "master", 12 | } 13 | -------------------------------------------------------------------------------- /src/models/Class.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * [솔브드 CLASS](https://solved.ac/class)입니다. 5 | */ 6 | alias Class = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10; 7 | -------------------------------------------------------------------------------- /src/models/CoinShopProduct.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.OpenAPI; 2 | 3 | namespace SolvedAC; 4 | 5 | /** 6 | * 코인샵에서 판매하고 있는 상품입니다. 7 | */ 8 | model CoinShopProduct { 9 | /** 10 | * 재고(Stock Keeping Unit) ID입니다. 11 | * @example 1 12 | */ 13 | skuId: uint32; 14 | 15 | item: Item; 16 | 17 | /** 18 | * 1회 구매 시 획득하는 아이템 개수입니다. 19 | * @example 1 20 | */ 21 | units: uint32; 22 | 23 | /** 24 | * 가격입니다. 25 | * 코인의 경우 나누기 100을 해야 표시 가격이 됩니다. 26 | * @example 99 27 | */ 28 | price: uint32; 29 | 30 | /** 31 | * 가격 단위입니다. 32 | * @example "coins" 33 | */ 34 | priceUnit: "coins" | "stardusts"; 35 | 36 | /** 37 | * 아이템 사용 시간 제한 여부입니다. 38 | * @example false 39 | */ 40 | itemUseTimeLimited: boolean; 41 | 42 | /** 43 | * 아이템 구매 기간 제한 여부입니다. 44 | * @example false 45 | */ 46 | itemSellTimeLimited: boolean; 47 | } 48 | -------------------------------------------------------------------------------- /src/models/Emoticon.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.OpenAPI; 2 | 3 | namespace SolvedAC; 4 | 5 | /** 6 | * 난이도 투표 등에 사용할 수 있는 이모티콘입니다. 7 | */ 8 | model Emoticon { 9 | /** 10 | * 고유 식별자입니다. 11 | * @example "hanbyeol-01" 12 | */ 13 | emoticonId: string; 14 | 15 | /** 16 | * 사진으로 가는 하이퍼링크입니다. 17 | * @example "https://static.solved.ac/emoticons/fool.png" 18 | */ 19 | emoticonUrl: url; 20 | 21 | /** 22 | * 한국어 이름입니다. 23 | * @example "난 바보야" 24 | */ 25 | displayName: string; 26 | } 27 | -------------------------------------------------------------------------------- /src/models/Item.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * 사용자가 사용할 수 있는 아이템입니다. 5 | */ 6 | model Item { 7 | /** 8 | * ID입니다. 9 | * @example "streak-freeze" 10 | */ 11 | itemId: string; 12 | 13 | /** 14 | * 아이템 사진으로 가는 하이퍼링크입니다. 15 | * @example "https://static.solved.ac/item/freeze-small-simple.svg" 16 | */ 17 | itemImageUrl: url; 18 | 19 | /** 20 | * 최대 소유 가능 개수입니다. 21 | * 사람에 따라 다를 수 있습니다. 22 | * @example 2 23 | */ 24 | inventoryMaxUnits: uint32; 25 | 26 | /** 27 | * 사용 가능 여부입니다. 28 | * @example true 29 | */ 30 | usable: boolean; 31 | 32 | /** 33 | * 국제화된 이름입니다. 34 | * @example "스트릭 프리즈" 35 | */ 36 | displayName: string; 37 | 38 | /** 39 | * 국제화된 설명입니다. 40 | * @example "미리 장착해 두면 어제 문제 푸는 걸 잊었더라도 스트릭이 깨지지 않습니다. 단, 스트릭 길이가 늘어나지는 않습니다.\n인벤토리에서 장착해서 사용할 수 있습니다." 41 | */ 42 | displayDescription: string; 43 | } 44 | -------------------------------------------------------------------------------- /src/models/Language.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * solved.ac에서 지원하는 사용자 언어입니다 5 | */ 6 | enum Language { 7 | /** 8 | * 한국어 9 | */ 10 | Korean: "ko", 11 | 12 | /** 13 | * English 14 | */ 15 | English: "en", 16 | 17 | /** 18 | * 日本語 19 | */ 20 | Japanese: "ja", 21 | } 22 | -------------------------------------------------------------------------------- /src/models/Organization.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * solved.ac에 등록한 단체입니다. 5 | */ 6 | model Organization { 7 | /** 8 | * ID입니다. 9 | * @example 394 10 | */ 11 | organizationId: uint64; 12 | 13 | /** 14 | * 이름입니다. 15 | * @example "KAIST" 16 | */ 17 | name: string; 18 | 19 | /** 20 | * 유형입니다. 21 | * @example "university" 22 | */ 23 | type: OrganizationType; 24 | 25 | /** 26 | * 문제풀이 레이팅입니다. 27 | * @example 3332 28 | */ 29 | rating: uint32; 30 | 31 | /** 32 | * 속한 사용자 수입니다. 33 | * @example 627 34 | */ 35 | userCount: uint64; 36 | 37 | /** 38 | * 난이도 기여 수입니다. 39 | * @example 29838 40 | */ 41 | voteCount: uint64; 42 | 43 | /** 44 | * 푼 문제 수입니다. 45 | * @example 21708 46 | */ 47 | solvedCount: uint64; 48 | 49 | /** 50 | * 상징 색입니다. 51 | * @example "#000000" 52 | */ 53 | color: Color; 54 | } 55 | -------------------------------------------------------------------------------- /src/models/OrganizationType.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * 단체 유형입니다. 5 | */ 6 | enum OrganizationType { 7 | /** 8 | * 대학교 9 | */ 10 | University: "university", 11 | 12 | /** 13 | * 회사 14 | */ 15 | Company: "company", 16 | 17 | /** 18 | * 커뮤니티 19 | */ 20 | Community: "community", 21 | 22 | /** 23 | * 고등학교 24 | */ 25 | HighSchool: "high_school", 26 | 27 | /** 28 | * 중학교 29 | */ 30 | MiddleSchool: "middle_school", 31 | 32 | /** 33 | * 초등학교 34 | */ 35 | ElementarySchool: "elementary_school", 36 | 37 | /** 38 | * 기타 39 | */ 40 | Others: "undefined", 41 | } 42 | -------------------------------------------------------------------------------- /src/models/PaginatedList.tsp: -------------------------------------------------------------------------------- 1 | /** 2 | * 페이지네이션 가능한 쿼리의 응답 결과입니다. 3 | */ 4 | model PaginatedList { 5 | /** 6 | * 전체 원소 수입니다. 7 | * 8 | * @example 1 9 | */ 10 | count: uint64; 11 | 12 | /** 13 | * 현재 페이지의 원소 목록입니다. 14 | */ 15 | items: T[]; 16 | } 17 | -------------------------------------------------------------------------------- /src/models/Post.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * solved.ac의 게시글입니다. 5 | */ 6 | model Post { 7 | /** 8 | * 게시글의 아이디입니다. 9 | * @example "rules_v1" 10 | */ 11 | postId: string; 12 | 13 | /** 14 | * 게시글의 제목입니다. 15 | * @example "solved.ac 이용 규칙 – v1" 16 | */ 17 | title: string; 18 | 19 | /** 20 | * 게시글의 내용입니다. 21 | * @example "이 규칙은 2020년 3월 1일부터 유효합니다.\n\n## 1\\. 난이도 기여\n\n난이도 기여는 난이도 기여 가이드라인을 기반으로 자신이 해당 문제를 해결하고 느낀 난이도를 솔직하게 표현해야 합니다. 다음과 같은 난이도 기여는 운영진 판단 하에 임의로 삭제될 수 있습니다.\n\n**a**. 특정 문제에 다른 이용자 대부분이 납득하기 힘든 난이도를 매긴 경우\n\n* 예: 1000번 문제에 Ruby I을 기여, 8481번 문제에 Bronze V를 기여\n* 2020년 이전 기여 중 Platinum과 Silver를 헷갈린 기여는 예외로 합니다.\n* 이와 같은 기여를 자신의 티어를 올릴 목적으로 한 경우, 기여가 삭제되는 것은 물론 해당 문제에 대한 경험치가 영구적으로 반영되지 않게 될 수 있습니다.\n\n**b**. 특정 문제를 해결하는 것과 관련이 없거나 도움이 전혀 되지 않는 태그를 단 경우\n* 예: 1003번 문제에 tag:dijkstra를 닮\n* 난이도 기여 전체를 삭제하는 대신, 해당 태그만 삭제될 수도 있습니다.\n* 문제와 관련 없는 태그를 납득하기 힘들 정도로 많이 달았다면 이용자에게 혼란을 주기 위함이라고 판단될 수 있습니다.\n\n**c**. 난이도 기여 경험치를 얻기 위한 목적으로, 자동화 스크립트 등을 사용해 자신이 푼 문제에 난이도를 일괄적으로 매기는 경우\n\n**d**. 경험치를 얻기 위한 목적으로, 정상적이지 않은 방법으로 난이도 기여를 한 경우\n* 정상적이지 않은 방법으로 난이도 기여가 가능함을 발견한 경우 shift@solved.ac로 즉시 신고 바랍니다. 프로필에 뱃지를 달아 드립니다.\n\n**e**. 동일인이 다중 계정을 사용해 한 문제에 1건 초과의 기여를 남긴 경우\n\n## 2. 난이도 기여 의견\n\n난이도 기여 의견은 문제 출제자들과 다른 기여자들, 그리고 문제를 푸는 사람들에 대한 존중을 바탕으로 작성되어야 합니다. 다음과 같은 의견은 운영진 판단 하에 임의로 삭제될 수 있습니다.\n\n**a**. 인종, 성, 성적 지향, 지역, 종교, 교육 수준, 생활 수준 등에 기반해 혐오적인 내용을 담고 있는 경우\n\n**b**. 출제자, 다른 기여자, 또는 문제를 푸는 사람들에 대한 비하적인 내용을 담고 있는 경우\n\n**c**. 욕설을 담고 있는 경우\n\n**d**. 문제 혹은 문제 해결과 관련이 없는 내용을 적은 경우\n\n## 3. 소스 코드 윤리\n\n다음과 같은 행위를 한 경우 운영진 판단 하에 사용 제재를 가할 수 있습니다.\n\n**a**. 경험치를 올릴 목적으로 다른 사람의 소스 코드를 그대로 혹은 수정을 가해 제출하는 행위\n\n## 4. 이벤트 참가\n\n동일인이 다중 계정을 사용해 이벤트 등에 참가할 경우 보상 획득을 임의로 제한할 수 있습니다.\n\n## 5. 아레나\n\n**a**. 아레나 참가 중에는 다른 참가자와 문제에 대해 의논하면 안 됩니다.\n\n**b**. 아레나는 1인당 한 개의 계정으로만 참가할 수 있습니다. 단, 다음의 예외를 허용합니다.\n- 이전에 다른 계정으로 아레나에 참가한 적 있을 경우, 이전 계정을 더 이상 사용하지 않으려는 경우에만 새 계정으로 참가할 수 있습니다.\n\n**c**. 동시에 두 개 이상의 다중 계정으로 아레나에 참가하면 안 됩니다.\n\n**d**. 아레나 참가 중 제출한 소스 코드는 대회 시작 시점 이전에 작성한 것이어도 괜찮습니다. 단, 제출한 코드는 제3자의 저작권 등의 권리를 침해하지 않아야 합니다.\n\n**e**. Open Contest 아레나 등, 앞서 또는 동시에 같은 문제들을 포함하여 개최된 대회가 있는 경우, 해당 대회의 참가자는 아레나에 참가하면 안 됩니다.\n\n**f**. 아레나에 참가하고자 하는 경우 대회 시작 5분 전까지 등록을 마쳐야 합니다.\n\n## 제재\n위의 사항을 위반해 기여가 삭제된 경우, 위반 행위의 심각성을 따져 추가적인 제재가 가해질 수 있습니다.\n\n* **1.c.**, **1.d.**\n - 난이도 기여 영구 제한 및 사이트 이용 제한.\n* **1.e.**\n - (해당하는 다중 계정에 대해) 난이도 기여 영구 제한.\n* **2.a.**, **2.b.**, **2.c.**\n - 난이도 기여 30일 제한. 최근 365일간 3회 이상 반복되었을 경우 난이도 기여 영구 제한.\n* **1.a.**, **1.b.**, **2.d.**\n - 악의가 있다고 판단될 경우, 난이도 기여 7일 제한 및 해당 문제에 대해 난이도 기여 영구 제한. 최근 365일간 5회 이상 반복되었을 경우 난이도 기여 영구 제한.\n* **3.a.**\n - 해당 계정의 경험치, 레이팅, CLASS를 영구히 0으로 설정.\n - 레이팅을 0으로 설정하는 기간 동안 이벤트 등에 참가하더라도 보상을 부여하지 않으며, 순위 집계 시 해당 유저를 제외함.\n* **5.a.**, **5.b.**, **5.c.**, **5.d.**, **5.e.**\n - 해당 계정의 아레나 레이팅을 영구히 0으로 설정.\n\n추가로, 운영진 판단 하에 규칙을 위반한 해당 사용자의 기여를 전부 삭제하거나 사이트 이용을 영구 제한할 수 있습니다." 22 | */ 23 | content: string; 24 | 25 | /** 26 | * 게시글이 작성된 언어입니다. 27 | */ 28 | language: string; 29 | 30 | /** 31 | * 게시글 내용의 타입입니다. 32 | */ 33 | type: string; 34 | } 35 | -------------------------------------------------------------------------------- /src/models/Problem.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * 문제 정보입니다. 5 | */ 6 | model Problem { 7 | /** 8 | * 백준 문제 번호로, 문제마다 고유합니다. 9 | * 10 | * @example 13705 11 | */ 12 | problemId: uint64; 13 | 14 | /** 15 | * 한국어 문제 제목입니다. 16 | * HTML 엔티티나 LaTeX 수식을 포함할 수 있습니다. 17 | * 18 | * @example "Ax+Bsin(x)=C" 19 | */ 20 | titleKo: string; 21 | 22 | /** 23 | * 언어별 문제 제목 목록입니다. 24 | * 25 | * @example 26 | * [{ 27 | * "language": "ko", 28 | * "languageDisplayName": "ko", 29 | * "title": "Ax+Bsin(x)=C", 30 | * "isOriginal": true 31 | * }] 32 | */ 33 | titles: ProblemTitleTranslated[]; 34 | 35 | /** 36 | * 채점 가능 여부입니다. 37 | * 38 | * @example true 39 | */ 40 | isSolvable: boolean; 41 | 42 | /** 43 | * 부분 점수/서브태스크 문제 여부입니다. 44 | * 45 | * @example false 46 | */ 47 | isPartial: boolean; 48 | 49 | /** 50 | * 맞은 사람 수입니다. 51 | * 52 | * @example 560 53 | */ 54 | acceptedUserCount: uint64; 55 | 56 | level: ProblemLevel; 57 | 58 | /** 59 | * 난이도 기여자 수입니다. 60 | * 61 | * @example 163 62 | */ 63 | votedUserCount: uint64; 64 | 65 | /** 66 | * 새싹 문제 여부입니다. 67 | * 68 | * @example false 69 | */ 70 | sprout: boolean; 71 | 72 | /** 73 | * 레이팅을 주지 않는지 여부입니다. 74 | * 75 | * @example false 76 | */ 77 | givesNoRating: boolean; 78 | 79 | /** 80 | * 난이도 기여 제한 여부입니다. 81 | * 82 | * @example false 83 | */ 84 | isLevelLocked: boolean; 85 | 86 | /** 87 | * 평균 시도 횟수입니다. 88 | * 89 | * @example 24.5393 90 | */ 91 | averageTries: float64; 92 | 93 | /** 94 | * 공식 문제 여부입니다. 95 | * 번외 문제 등은 비공식 문제로 분류됩니다. 96 | * 97 | * @example true 98 | */ 99 | official: boolean; 100 | 101 | /** 102 | * 태그 목록입니다. 103 | * 104 | * @example 105 | * [ 106 | * { 107 | * "key": "arbitrary_precision", 108 | * "isMeta": false, 109 | * "bojTagId": 117, 110 | * "problemCount": 241, 111 | * "displayNames": [ 112 | * { 113 | * "language": "ko", 114 | * "name": "임의 정밀도 / 큰 수 연산", 115 | * "short": "임의 정밀도 / 큰 수 연산" 116 | * }, 117 | * { 118 | * "language": "en", 119 | * "name": "arbitrary precision / big integers", 120 | * "short": "arbitrary precision / big integers" 121 | * }, 122 | * { 123 | * "language": "ja", 124 | * "name": "高精度または大きな数の演算", 125 | * "short": "高精度または大きな数の演算" 126 | * } 127 | * ], 128 | * "aliases": [ 129 | * { "alias": "빅인티저" }, 130 | * { "alias": "빅데시멀" }, 131 | * { "alias": "biginteger" }, 132 | * { "alias": "bigdecimal" } 133 | * ] 134 | * }, 135 | * { 136 | * "key": "binary_search", 137 | * "isMeta": false, 138 | * "bojTagId": 12, 139 | * "problemCount": 1137, 140 | * "displayNames": [ 141 | * { 142 | * "language": "ko", 143 | * "name": "이분 탐색", 144 | * "short": "이분 탐색" 145 | * }, 146 | * { 147 | * "language": "en", 148 | * "name": "binary search", 149 | * "short": "binary search" 150 | * }, 151 | * { 152 | * "language": "ja", 153 | * "name": "二分探索", 154 | * "short": "二分探索" 155 | * } 156 | * ], 157 | * "aliases": [ 158 | * { "alias": "이분탐색" }, 159 | * { "alias": "이진탐색" } 160 | * ] 161 | * }, 162 | * { 163 | * "key": "math", 164 | * "isMeta": false, 165 | * "bojTagId": 124, 166 | * "problemCount": 6007, 167 | * "displayNames": [ 168 | * { 169 | * "language": "ko", 170 | * "name": "수학", 171 | * "short": "수학" 172 | * }, 173 | * { 174 | * "language": "en", 175 | * "name": "mathematics", 176 | * "short": "math" 177 | * }, 178 | * { 179 | * "language": "ja", 180 | * "name": "数学", 181 | * "short": "数学" 182 | * } 183 | * ], 184 | * "aliases": [] 185 | * }, 186 | * { 187 | * "key": "numerical_analysis", 188 | * "isMeta": false, 189 | * "bojTagId": 122, 190 | * "problemCount": 17, 191 | * "displayNames": [ 192 | * { 193 | * "language": "ko", 194 | * "name": "수치해석", 195 | * "short": "수치해석" 196 | * }, 197 | * { 198 | * "language": "en", 199 | * "name": "numerical analysis", 200 | * "short": "numerical analysis" 201 | * }, 202 | * { 203 | * "language": "ja", 204 | * "name": "数値解析", 205 | * "short": "数値解析" 206 | * } 207 | * ], 208 | * "aliases": [ 209 | * { "alias": "수학" } 210 | * ] 211 | * } 212 | * ] 213 | */ 214 | tags: ProblemTag[]; 215 | 216 | metadata: unknown; 217 | } 218 | -------------------------------------------------------------------------------- /src/models/ProblemLevel.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * Unrated / Not Ratable를 0, 5 | * Bronze V를 1, 6 | * Bronze IV를 2, 7 | * ..., 8 | * Ruby II을 29, 9 | * Ruby I를 30으로 표현하는 문제 난이도입니다. 10 | * 자세한 값 정보는 표1. 문제 난이도 표를 펼쳐 참고하십시오. 11 | * 12 | *
13 | * 14 | * 표1. 문제 난이도 표 15 | * 16 | * 17 | * | 수치 | 이름 | 18 | * | ---: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 19 | * | 0 | Unrated / Not Ratable | 20 | * | 1 | Bronze V | 21 | * | 2 | Bronze IV | 22 | * | 3 | Bronze III | 23 | * | 4 | Bronze II | 24 | * | 5 | Bronze I | 25 | * | 6 | Silver V | 26 | * | 7 | Silver IV | 27 | * | 8 | Silver III | 28 | * | 9 | Silver II | 29 | * | 10 | Silver I | 30 | * | 11 | Gold V | 31 | * | 12 | Gold IV | 32 | * | 13 | Gold III | 33 | * | 14 | Gold II | 34 | * | 15 | Gold I | 35 | * | 16 | Platinum V | 36 | * | 17 | Platinum IV | 37 | * | 18 | Platinum III | 38 | * | 19 | Platinum II | 39 | * | 20 | Platinum I | 40 | * | 21 | Diamond V | 41 | * | 22 | Diamond IV | 42 | * | 23 | Diamond III | 43 | * | 24 | Diamond II | 44 | * | 25 | Diamond I | 45 | * | 26 | Ruby V | 46 | * | 27 | Ruby IV | 47 | * | 28 | Ruby III | 48 | * | 29 | Ruby II | 49 | * | 30 | Ruby I | 50 | * 51 | *
52 | */ 53 | enum ProblemLevel { 54 | Zero: 0, 55 | Bronze5: 1, 56 | Bronze4: 2, 57 | Bronze3: 3, 58 | Bronze2: 4, 59 | Bronze1: 5, 60 | Silver5: 6, 61 | Silver4: 7, 62 | Silver3: 8, 63 | Silver2: 9, 64 | Silver1: 10, 65 | Gold5: 11, 66 | Gold4: 12, 67 | Gold3: 13, 68 | Gold2: 14, 69 | Gold1: 15, 70 | Platinum5: 16, 71 | Platinum4: 17, 72 | Platinum3: 18, 73 | Platinum2: 19, 74 | Platinum1: 20, 75 | Diamond5: 21, 76 | Diamond4: 22, 77 | Diamond3: 23, 78 | Diamond2: 24, 79 | Diamond1: 25, 80 | Ruby5: 26, 81 | Ruby4: 27, 82 | Ruby3: 28, 83 | Ruby2: 29, 84 | Ruby1: 30, 85 | } 86 | -------------------------------------------------------------------------------- /src/models/ProblemTag.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | model ProblemTag { 4 | /** 5 | * solved.ac에서 쓰는 태그 ID입니다. 6 | * 7 | * @example "arbitrary_precision" 8 | */ 9 | key: string; 10 | 11 | /** 12 | * @TODO 의미 파악하기 13 | * 14 | * @example false 15 | */ 16 | isMeta: boolean; 17 | 18 | /** 19 | * 백준 온라인 저지에서 쓰는 태그 ID입니다. 20 | * 21 | * @example 117 22 | */ 23 | bojTagId: uint64; 24 | 25 | /** 26 | * 태그가 붙은 문제 수입니다. 27 | * 28 | * @example 241 29 | */ 30 | problemCount: uint64; 31 | 32 | /** 33 | * 언어별 태그 이름 목록입니다. 34 | */ 35 | displayNames: ProblemTagNameTranslated[]; 36 | 37 | /** 38 | * 별명 목록입니다. 빈 배열일 수 있습니다. 39 | */ 40 | aliases: ProblemTagAlias[]; 41 | } 42 | -------------------------------------------------------------------------------- /src/models/ProblemTagAlias.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * 태그의 별칭을 나타냅니다. 5 | */ 6 | model ProblemTagAlias { 7 | /** 8 | * 별칭입니다 9 | */ 10 | `alias`: string; 11 | } 12 | -------------------------------------------------------------------------------- /src/models/ProblemTagNameTranslated.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | model ProblemTagNameTranslated { 4 | /** 5 | * 태그 이름이 작성된 언어입니다. 6 | * 7 | * @example "ko" 8 | */ 9 | language: Language; 10 | 11 | /** 12 | * 이름입니다. 13 | * 14 | * @example "임의 정밀도 / 큰 수 연산" 15 | */ 16 | name: string; 17 | 18 | /** 19 | * 짧은 이름입니다. 20 | * 따로 없을 경우 `name`과 같은 값입니다. 21 | * 22 | * @example "임의 정밀도 / 큰 수 연산" 23 | */ 24 | short: string; 25 | } 26 | -------------------------------------------------------------------------------- /src/models/ProblemTitleTranslated.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * 언어별 문제 제목입니다. 5 | */ 6 | model ProblemTitleTranslated { 7 | /** 8 | * 문제 제목이 작성된 언어입니다. 9 | * 10 | * @example "ko" 11 | */ 12 | language: Language; 13 | 14 | /** 15 | * 문제 제목이 작성된 언어의 이름입니다. 16 | * 17 | * @example "ko" 18 | */ 19 | languageDisplayName: string; 20 | 21 | /** 22 | * 문제 제목입니다. 23 | * 24 | * @example "Ax+Bsin(x)=C" 25 | */ 26 | title: string; 27 | 28 | /** 29 | * 원본과 동일한지 여부입니다. 30 | * 31 | * @example true 32 | */ 33 | isOriginal: boolean; 34 | } 35 | -------------------------------------------------------------------------------- /src/models/Ranked.tsp: -------------------------------------------------------------------------------- 1 | /** 2 | * 페이지네이션 가능한 쿼리의 응답 결과입니다. 3 | */ 4 | model Ranked { 5 | ...T; 6 | 7 | /** 8 | * 순위입니다. 9 | * 10 | * @example 1 11 | */ 12 | rank: uint64; 13 | } 14 | -------------------------------------------------------------------------------- /src/models/RivalUser.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | model RivalUser extends User { 4 | /** 5 | * 라이벌 여부입니다. 6 | * 7 | * @example false 8 | */ 9 | isRival: boolean; 10 | 11 | /** 12 | * 역라이벌 여부입니다. 13 | * 14 | * @example false 15 | */ 16 | isReverseRival: boolean; 17 | } 18 | -------------------------------------------------------------------------------- /src/models/SiteStatistics.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * solved.ac 사이트의 통계 정보입니다. 5 | */ 6 | model SiteStatistics { 7 | /** 8 | * 여태까지 색인된 백준 문제 수입니다. 9 | * 10 | * @example 29799 11 | */ 12 | problemCount: uint64; 13 | 14 | /** 15 | * 여태까지 난이도가 기여된 백준 문제 수입니다. 16 | * 17 | * @example 22252 18 | */ 19 | problemVotedCount: uint64; 20 | 21 | /** 22 | * 여태까지 등록한 사용자 수입니다. 23 | * 24 | * @example 127880 25 | */ 26 | userCount: uint64; 27 | 28 | /** 29 | * 여태까지 난이도에 기여한 사용자 수입니다 30 | * 31 | * @example 3657 32 | */ 33 | contributorCount: uint64; 34 | 35 | /** 36 | * 여태까지 이루어진 난이도 기여의 수입니다. 37 | * 38 | * @example 409333 39 | */ 40 | contributionCount: uint64; 41 | } 42 | -------------------------------------------------------------------------------- /src/models/SocialUser.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * solved.ac 사용자 정보입니다. 5 | */ 6 | model SocialUser extends RivalUser { 7 | /** 8 | * 로그인한 사용자가 해당 사용자를 차단했는지 여부입니다. 9 | * 10 | * @example false 11 | */ 12 | blocked: boolean; 13 | 14 | /** 15 | * 로그인한 사용자가 해당 사용자에게 차단당했는지 여부입니다. 16 | * 17 | * @example false 18 | */ 19 | reverseBlocked: boolean; 20 | } 21 | -------------------------------------------------------------------------------- /src/models/SolveTier.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * Unrated를 0, 5 | * Bronze V를 1, 6 | * ..., 7 | * Ruby I을 30, 8 | * Master를 31로 표현하는 문제해결 티어입니다. 9 | * 자세한 값 정보는 표1. 문제 풀이 레이팅 표를 펼쳐 참고하십시오. 10 | * 11 | *
12 | * 13 | * 표1. 문제 풀이 레이팅 표 14 | * 15 | * 16 | * | 수치 | 이름 | 요구 레이팅 | 17 | * | ---: | :------------------------------------------------------------------------------------------------------ | --------------------------------------------------: | 18 | * | 0 | Unrated | 0 | 19 | * | 1 | Bronze V | 30 | 20 | * | 2 | Bronze IV | 60 | 21 | * | 3 | Bronze III | 90 | 22 | * | 4 | Bronze II | 120 | 23 | * | 5 | Bronze I | 150 | 24 | * | 6 | Silver V | 200 | 25 | * | 7 | Silver IV | 300 | 26 | * | 8 | Silver III | 400 | 27 | * | 9 | Silver II | 500 | 28 | * | 10 | Silver I | 650 | 29 | * | 11 | Gold V | 800 | 30 | * | 12 | Gold IV | 950 | 31 | * | 13 | Gold III | 1100 | 32 | * | 14 | Gold II | 1250 | 33 | * | 15 | Gold I | 1400 | 34 | * | 16 | Platinum V | 1600 | 35 | * | 17 | Platinum IV | 1750 | 36 | * | 18 | Platinum III | 1900 | 37 | * | 19 | Platinum II | 2000 | 38 | * | 20 | Platinum I | 2100 | 39 | * | 21 | Diamond V | 2200 | 40 | * | 22 | Diamond IV | 2300 | 41 | * | 23 | Diamond III | 2400 | 42 | * | 24 | Diamond II | 2500 | 43 | * | 25 | Diamond I | 2600 | 44 | * | 26 | Ruby V | 2700 | 45 | * | 27 | Ruby IV | 2800 | 46 | * | 28 | Ruby III | 2850 | 47 | * | 29 | Ruby II | 2900 | 48 | * | 30 | Ruby I | 2950 | 49 | * | 31 | Master | 3000 | 50 | * 51 | *
52 | */ 53 | enum SolveTier { 54 | Unrated: 0, 55 | Bronze5: 1, 56 | Bronze4: 2, 57 | Bronze3: 3, 58 | Bronze2: 4, 59 | Bronze1: 5, 60 | Silver5: 6, 61 | Silver4: 7, 62 | Silver3: 8, 63 | Silver2: 9, 64 | Silver1: 10, 65 | Gold5: 11, 66 | Gold4: 12, 67 | Gold3: 13, 68 | Gold2: 14, 69 | Gold1: 15, 70 | Platinum5: 16, 71 | Platinum4: 17, 72 | Platinum3: 18, 73 | Platinum2: 19, 74 | Platinum1: 20, 75 | Diamond5: 21, 76 | Diamond4: 22, 77 | Diamond3: 23, 78 | Diamond2: 24, 79 | Diamond1: 25, 80 | Ruby5: 26, 81 | Ruby4: 27, 82 | Ruby3: 28, 83 | Ruby2: 29, 84 | Ruby1: 30, 85 | Master: 31, 86 | } 87 | -------------------------------------------------------------------------------- /src/models/User.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * solved.ac 사용자 정보입니다. 5 | */ 6 | @withVisibility("full") 7 | model User { 8 | /** 9 | * 사용자명입니다. 10 | * 11 | * @example "shiftpsh" 12 | */ 13 | @visibility("brief", "full") 14 | handle: string; 15 | 16 | /** 17 | * 자기소개입니다. 18 | * 19 | * @example "🧡 이곳의 개발자입니다." 20 | */ 21 | @visibility("brief", "full") 22 | bio: string; 23 | 24 | /** 25 | * 장착 중인 뱃지 ID입니다. 26 | * 27 | * @example "ghudegy2022-1" 28 | */ 29 | @visibility("brief", "full") 30 | badgeId?: string | null; 31 | 32 | /** 33 | * 장착 중인 배경 ID입니다. 34 | * 35 | * @example "event240203" 36 | */ 37 | @visibility("brief", "full") 38 | backgroundId: string; 39 | 40 | /** 41 | * 프로필 사진으로 가는 하이퍼링크입니다. 42 | * 43 | * @example "https://static.solved.ac/uploads/profile/shiftpsh-picture-1693244003120.png" 44 | */ 45 | @visibility("brief", "full") 46 | profileImageUrl?: url | null; 47 | 48 | /** 49 | * 푼 문제 수입니다. 50 | * 51 | * @example 3474 52 | */ 53 | @visibility("brief", "full") 54 | solvedCount: uint64; 55 | 56 | /** 57 | * 난이도 기여 수입니다. 58 | * 59 | * @example 1528 60 | */ 61 | @visibility("brief", "full") 62 | voteCount: uint64; 63 | 64 | /** 65 | * 취득한 CLASS입니다. 66 | * 취득한 CLASS가 없다면 0으로 표현합니다. 67 | * 68 | * @example 8 69 | */ 70 | @visibility("brief", "full") 71 | class: 0 | Class; 72 | 73 | /** 74 | * CLASS 완성도에 따른 장식입니다. 75 | * 장식 없음 (`"none"`), 76 | * 은장+ (`"silver"`), 77 | * 금장++ (`"gold"`)이 있습니다. 78 | * 79 | * @example "none" 80 | */ 81 | @visibility("brief", "full") 82 | classDecoration: "none" | "silver" | "gold"; 83 | 84 | /** 85 | * 라이벌 수입니다. 86 | * 87 | * @example 57 88 | */ 89 | @visibility("brief", "full") 90 | rivalCount: uint64; 91 | 92 | /** 93 | * 역라이벌 수입니다. 94 | * 95 | * @example 139 96 | */ 97 | @visibility("brief", "full") 98 | reverseRivalCount: uint64; 99 | 100 | /** 101 | * @example 26 102 | */ 103 | @visibility("brief", "full") 104 | tier: SolveTier; 105 | 106 | /** 107 | * 문제풀이 레이팅입니다 108 | * 109 | * @example 2724 110 | */ 111 | @visibility("brief", "full") 112 | rating: uint32; 113 | 114 | /** 115 | * 상위 100 문제 난이도 합으로 얻은 레이팅입니다. 116 | * 117 | * @example 2294 118 | */ 119 | @visibility("brief", "full") 120 | ratingByProblemsSum: uint32; 121 | 122 | /** 123 | * 취득한 CLASS에 따라 얻은 레이팅입니다. 124 | * 125 | * @example 230 126 | */ 127 | @visibility("brief", "full") 128 | ratingByClass: uint32; 129 | 130 | /** 131 | * 푼 문제 수로 얻은 레이팅입니다. 132 | * 133 | * @example 175 134 | */ 135 | @visibility("brief", "full") 136 | ratingBySolvedCount: uint32; 137 | 138 | /** 139 | * 문제 난이도에 기여한 횟수로 받은 레이팅입니다. 140 | * 141 | * @example 25 142 | */ 143 | @visibility("brief", "full") 144 | ratingByVoteCount: uint32; 145 | 146 | /** 147 | * 현재 아레나 티어입니다. 148 | * 149 | * @example 0 150 | */ 151 | @visibility("brief", "full") 152 | arenaTier: ArenaTier; 153 | 154 | /** 155 | * 현재 아레나 레이팅입니다. 156 | * 157 | * @example 0 158 | */ 159 | @visibility("brief", "full") 160 | arenaRating: uint32; 161 | 162 | /** 163 | * 역대 받은 아레나 티어 중 최고점일 때의 아레나 티어입니다. 164 | * 165 | * @example 0 166 | */ 167 | @visibility("brief", "full") 168 | arenaMaxTier: ArenaTier; 169 | 170 | /** 171 | * 역대 받은 아레나 레이팅 중 최고점일 때의 아레나 레이팅입니다. 172 | * 173 | * @example 0 174 | */ 175 | @visibility("brief", "full") 176 | arenaMaxRating: uint32; 177 | 178 | /** 179 | * 참여한 아레나 라운드 수입니다. 180 | * 181 | * @example 0 182 | */ 183 | @visibility("brief", "full") 184 | arenaCompetedRoundCount: uint64; 185 | 186 | /** 187 | * 유지한 최대 스트릭의 길이입니다. (일 단위) 188 | * 189 | * @example 366 190 | */ 191 | @visibility("brief", "full") 192 | maxStreak: uint64; 193 | 194 | /** 195 | * 보유 중인 코인에 100을 곱한 값입니다. 196 | * 만약, 실제로 보유한 코인이 0.15라면 15로 기록됩니다. 197 | * 198 | * @example 1063 199 | */ 200 | @visibility("brief", "full") 201 | coins: uint64; 202 | 203 | /** 204 | * 보유 중인 별가루 양입니다. 205 | * 206 | * @example 273583 207 | */ 208 | @visibility("brief", "full") 209 | stardusts: uint64; 210 | 211 | /** 212 | * 가입 시각입니다. 213 | * 일부 계정에 대해 2021년 6월 19일 0시 (UTC)로 백필된 흔적이 있습니다. 214 | * 215 | * @example "2021-06-19T00:00:00.000Z" 216 | */ 217 | @visibility("brief", "full") 218 | joinedAt: offsetDateTime; 219 | 220 | /** 221 | * 정지 종료 시각입니다. 222 | * 정지 이력이 없을 경우 Unix Timestamp 0 값을 포매팅한 문자열입니다. 223 | * 224 | * @example "1970-01-01T00:00:00.000Z" 225 | */ 226 | @visibility("brief", "full") 227 | bannedUntil: offsetDateTime; 228 | 229 | /** 230 | * [솔브드 서포터](https://solved.ac/support) 종료 시각입니다. 231 | * 활성화 이력이 없을 경우 Unix Timestamp 0 값을 포매팅한 문자열입니다. 232 | * 233 | * @example "2099-12-31T14:59:59.000Z" 234 | */ 235 | @visibility("brief", "full") 236 | proUntil: offsetDateTime; 237 | 238 | /** 239 | * 순위입니다. 240 | * 이 값은 요청하는 엔드포인트의 정렬 기준에 따라 다를 수 있습니다. 241 | * 예) /ranking/* 엔드포인트에서는 해당 랭킹의 순위, /show 엔드포인트에서는 문제풀이 레이팅 순위 242 | * 243 | * @example 130 244 | */ 245 | @visibility("full") 246 | rank: uint64; 247 | } 248 | -------------------------------------------------------------------------------- /src/models/UserAdditionalInfo.tsp: -------------------------------------------------------------------------------- 1 | namespace SolvedAC; 2 | 3 | /** 4 | * solved.ac 사용자 부가 정보입니다. 5 | */ 6 | model UserAdditionalInfo { 7 | /** 8 | * 사용자의 국가/지역 코드입니다. 9 | * 10 | * @example "kr" 11 | */ 12 | countryCode: string; 13 | 14 | /** 15 | * 사용자의 성별입니다. 16 | * - 0: 선택 안 함 17 | * - 1: 남성 18 | * - 2: 여성 19 | * - 9: 기타 20 | * 21 | * @example 0 22 | */ 23 | gender: uint64; 24 | 25 | /** 26 | * 사용자를 영어로 표기할 때 사용하는 대명사입니다. 27 | * 28 | * @example "he/him" 29 | */ 30 | pronouns: string; 31 | 32 | /** 33 | * 사용자의 생년입니다. 34 | * 35 | * @example 1998 36 | */ 37 | birthYear: uint64; 38 | 39 | /** 40 | * 사용자의 생월입니다. 41 | * 42 | * @example 8 43 | */ 44 | birthMonth: uint64; 45 | 46 | /** 47 | * 사용자의 생일입니다. 48 | * 49 | * @example 6 50 | */ 51 | birthDay: uint64; 52 | 53 | /** 54 | * 사용자의 영어 이름입니다. 55 | * 56 | * @example "Suhyun Park" 57 | */ 58 | name: string; 59 | 60 | /** 61 | * 사용자의 모국어 이름입니다. 62 | * 63 | * @example "박수현" 64 | */ 65 | nameNative: string; 66 | } 67 | -------------------------------------------------------------------------------- /src/models/_barrel.tsp: -------------------------------------------------------------------------------- 1 | import "./SolveTier.tsp"; 2 | import "./Badge.tsp"; 3 | import "./BadgeTier.tsp"; 4 | import "./BadgeCategory.tsp"; 5 | import "./Background.tsp"; 6 | import "./BackgroundCategory.tsp"; 7 | import "./BackgroundAuthor.tsp"; 8 | import "./Language.tsp"; 9 | import "./SiteStatistics.tsp"; 10 | import "./Problem.tsp"; 11 | import "./ProblemLevel.tsp"; 12 | import "./ProblemTitleTranslated.tsp"; 13 | import "./ProblemTagNameTranslated.tsp"; 14 | import "./ProblemTagAlias.tsp"; 15 | import "./ProblemTag.tsp"; 16 | import "./PaginatedList.tsp"; 17 | import "./User.tsp"; 18 | import "./RivalUser.tsp"; 19 | import "./SocialUser.tsp"; 20 | import "./ArenaTier.tsp"; 21 | import "./Class.tsp"; 22 | import "./CoinShopProduct.tsp"; 23 | import "./Item.tsp"; 24 | import "./Organization.tsp"; 25 | import "./OrganizationType.tsp"; 26 | import "./Ranked.tsp"; 27 | import "./Emoticon.tsp"; 28 | import "./UserAdditionalInfo.tsp"; 29 | import "./Post.tsp"; 30 | -------------------------------------------------------------------------------- /src/operations/_barrel.tsp: -------------------------------------------------------------------------------- 1 | import "./account/_barrel.tsp"; 2 | import "./background/_barrel.tsp"; 3 | import "./badge/_barrel.tsp"; 4 | import "./coins/_barrel.tsp"; 5 | import "./organization/_barrel.tsp"; 6 | import "./post/_barrel.tsp"; 7 | import "./problem/_barrel.tsp"; 8 | import "./ranking/_barrel.tsp"; 9 | import "./search/_barrel.tsp"; 10 | import "./site/_barrel.tsp"; 11 | import "./tag/_barrel.tsp"; 12 | import "./user/_barrel.tsp"; 13 | -------------------------------------------------------------------------------- /src/operations/account/_barrel.tsp: -------------------------------------------------------------------------------- 1 | import "./redeem.tsp"; 2 | import "./update_settings.tsp"; 3 | import "./verify_credentials.tsp"; 4 | -------------------------------------------------------------------------------- /src/operations/account/redeem.tsp: -------------------------------------------------------------------------------- 1 | /** 2 | * @TODO: 반환에 성공한 경우 문서화하기 3 | */ 4 | using TypeSpec.Http; 5 | using TypeSpec.OpenAPI; 6 | 7 | namespace SolvedAC; 8 | /** 9 | * 리딤 코드와 배지, 배경 등을 교환합니다. 10 | * 11 | * **주의**: 로그인이 필요한 API는 사이트 내에서 호출할 수 없으므로 별도 도구를 이용해주십시오. 12 | */ 13 | @summary("코드 교환하기") 14 | @tag("account") 15 | @useAuth(TokenAuth) 16 | @post 17 | @route("/account/redeem") 18 | op redeemCode( 19 | /** 20 | * 응답을 받을 언어입니다. 21 | */ 22 | @header 23 | `x-solvedac-language`?: Language, 24 | 25 | /** 26 | * 리딤 코드입니다. 27 | * @example "R33D3MC0D3" 28 | */ 29 | code: string, 30 | ): Unauthorized | RedeemCode.NotFound; 31 | 32 | namespace RedeemCode { 33 | /** 34 | * 리딤 코드가 올바르지 않은 경우입니다. 35 | */ 36 | @error 37 | @extension(XInternal, true) 38 | model NotFound { 39 | @statusCode status: 404; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/operations/account/update_settings.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | /** 6 | * 계정의 설정을 변경합니다. 7 | * 8 | * **주의**: 로그인이 필요한 API는 사이트 내에서 호출할 수 없으므로 별도 도구를 이용해주십시오. 9 | */ 10 | @summary("계정 설정 변경하기") 11 | @tag("account") 12 | @useAuth(TokenAuth) 13 | @patch 14 | @route("/account/update_settings") 15 | op updateAccountSettings( 16 | /** 17 | * 응답을 받을 언어입니다. 18 | */ 19 | @header 20 | `x-solvedac-language`?: Language, 21 | 22 | /** 23 | * 업데이트할 설정의 이름입니다. 24 | * @example "twitterPostOnClassIncrease" 25 | */ 26 | key: string, 27 | 28 | /** 29 | * 업데이트할 설정의 새로운 값입니다. 30 | * @example true 31 | */ 32 | value: unknown, 33 | ): UpdateAccountSettings.Ok | Unauthorized; 34 | 35 | namespace UpdateAccountSettings { 36 | /** 37 | * 서버가 반환에 성공한 경우입니다. 38 | */ 39 | @extension(XInternal, true) 40 | model Ok { 41 | @statusCode status: 204; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/operations/account/verify_credentials.tsp: -------------------------------------------------------------------------------- 1 | /** 2 | * @TODO: 반환에 성공한 경우 문서화하기 3 | */ 4 | using TypeSpec.Http; 5 | using TypeSpec.OpenAPI; 6 | 7 | namespace SolvedAC; 8 | /** 9 | * 현재 로그인한 계정 정보를 가져옵니다. 10 | * 11 | * **주의**: 로그인이 필요한 API는 사이트 내에서 호출할 수 없으므로 별도 도구를 이용해주십시오. 12 | */ 13 | @summary("로그인 정보 가져오기") 14 | @tag("account") 15 | @useAuth(TokenAuth) 16 | @get 17 | @route("/account/verify_credentials") 18 | op verifyAccountCredentials( 19 | /** 20 | * 응답을 받을 언어입니다. 21 | */ 22 | @header 23 | `x-solvedac-language`?: Language, 24 | ): Unauthorized | VerifyCredentials.Ok; 25 | 26 | namespace VerifyCredentials { 27 | /** 28 | * 크레데션 관련 본인 정보 29 | */ 30 | @extension(XInternal, true) 31 | model Ok { 32 | @statusCode status: 200; 33 | @body body: Credential; 34 | } 35 | 36 | @extension(XInternal, true) 37 | model Credential { 38 | user: UserWithSettings; 39 | aggredOn: Agreements; 40 | 41 | /** 42 | * 보유할 수 있는 모든 이모티콘에 대해 이모티콘 정보에 덧붙여 보유 여부를 함께 담은 목록입니다. 43 | * 44 | * @example 45 | * [ 46 | * { 47 | * "emoticonId": "hanbyeol-01", "emoticonUrl": "https://static.solved.ac/emoticons/fool.png", 48 | * "displayName": "난 바보야", "unlocked": true 49 | * }, 50 | * { 51 | * "emoticonId": "hanbyeol-02", "emoticonUrl": "https://static.solved.ac/emoticons/lgtm.png", 52 | * "displayName": "LGTM", "unlocked": false 53 | * }, 54 | * { 55 | * "emoticonId": "hanbyeol-03", "emoticonUrl": "https://static.solved.ac/emoticons/real.png", 56 | * "displayName": "ㄹㅇㅋㅋ", "unlocked": true 57 | * }, 58 | * { 59 | * "emoticonId": "hanbyeol-04", "emoticonUrl": "https://static.solved.ac/emoticons/why-work.png", 60 | * "displayName": "이게 왜 됨?", "unlocked": true 61 | * }, 62 | * { 63 | * "emoticonId": "hanbyeol-05", "emoticonUrl": "https://static.solved.ac/emoticons/i-wont-do.png", 64 | * "displayName": "응, 안 해", "unlocked": true 65 | * }, 66 | * { 67 | * "emoticonId": "hanbyeol-06", "emoticonUrl": "https://static.solved.ac/emoticons/overclock.png", 68 | * "displayName": "두뇌풀가동!", "unlocked": true 69 | * }, 70 | * { 71 | * "emoticonId": "hanbyeol-07", "emoticonUrl": "https://static.solved.ac/emoticons/hello-world.png", 72 | * "displayName": "Hello, World!", "unlocked": true 73 | * }, 74 | * { 75 | * "emoticonId": "hanbyeol-08", "emoticonUrl": "https://static.solved.ac/emoticons/i-hate-math.png", 76 | * "displayName": "수학시러!", "unlocked": true 77 | * }, 78 | * { 79 | * "emoticonId": "hanbyeol-09", "emoticonUrl": "https://static.solved.ac/emoticons/am-i-screwed.png", 80 | * "displayName": "망?했네?", "unlocked": true 81 | * }, 82 | * { 83 | * "emoticonId": "hanbyeol-10", "emoticonUrl": "https://static.solved.ac/emoticons/dont-decieve.png", 84 | * "displayName": "기만ㄴㄴ", "unlocked": true 85 | * }, 86 | * { 87 | * "emoticonId": "hanbyeol-11", "emoticonUrl": "https://static.solved.ac/emoticons/i-hate-coding.png", 88 | * "displayName": "코딩시러!", "unlocked": true 89 | * }, 90 | * { 91 | * "emoticonId": "hanbyeol-12", "emoticonUrl": "https://static.solved.ac/emoticons/thinking-face.png", 92 | * "displayName": "흠터레스팅", "unlocked": true 93 | * }, 94 | * { 95 | * "emoticonId": "hanbyeol-13", "emoticonUrl": "https://static.solved.ac/emoticons/why-dont-work.png", 96 | * "displayName": "이게 왜 안 됨?", "unlocked": true 97 | * }, 98 | * { 99 | * "emoticonId": "hanbyeol-14", "emoticonUrl": "https://static.solved.ac/emoticons/well-programmed.png", 100 | * "displayName": "잘짰네ㅎ", "unlocked": true 101 | * }, 102 | * { 103 | * "emoticonId": "hanbyeol-15", "emoticonUrl": "https://static.solved.ac/emoticons/please-dont-explode.png", 104 | * "displayName": "터지면 안대...", "unlocked": true 105 | * }, 106 | * { 107 | * "emoticonId": "hanbyeol-16", "emoticonUrl": "https://static.solved.ac/emoticons/nooo.png", 108 | * "displayName": "으에에~", "unlocked": false 109 | * } 110 | * ] 111 | */ 112 | emoticons: EmoticonUnlockStatus[]; 113 | 114 | bookmarks: TODO; 115 | 116 | /** 117 | * 받은 알림 수입니다. 118 | * @example 0 119 | */ 120 | notificationCount: uint32; 121 | 122 | /** 123 | * 마지막으로 솔브드 상태가 변한 시각입니다. 124 | * @example "2024-03-17T19:24:42.000Z" 125 | */ 126 | lastSolvedStateChangedAt: offsetDateTime; 127 | } 128 | 129 | /** 130 | * 사용자 동의 여부입니다. 131 | */ 132 | model Agreements { 133 | /** 134 | * 동의한 약관 버전입니다. 135 | * @example "tos_v1" 136 | */ 137 | tos: string; 138 | 139 | /** 140 | * 동의한 개인정보 처리방침 버전입니다. 141 | * @example "privacy_v2" 142 | */ 143 | privacy: string; 144 | } 145 | 146 | @extension(XInternal, true) 147 | model EmoticonUnlockStatus extends Emoticon { 148 | /** 149 | * 해금 여부입니다. 150 | * @example true 151 | */ 152 | unlocked: boolean; 153 | } 154 | 155 | @extension(XInternal, true) 156 | @withVisibility("brief") 157 | model UserWithSettings extends User { 158 | /** 159 | * 설정입니다. 160 | */ 161 | settings: UserSettings; 162 | 163 | /** 164 | * 사용 중인 이메일 주소입니다. 165 | * 166 | * @example `"me@shiftpsh.com"` 167 | */ 168 | email: string; 169 | } 170 | 171 | model UserSettings { 172 | twitterPostOnProblemSolve: "true"; 173 | screenTheme: "default"; 174 | twitterPostHandle: "true"; 175 | twitterPostOnRatingIncrease: "true"; 176 | twitterPostOnTierIncrease: "true"; 177 | twitterPostOnClassIncrease: "true"; 178 | pro_hideAds: "true"; 179 | siteLanguage: "ko"; 180 | showIllustBackground: "true"; 181 | showMovieBackground: "true"; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /src/operations/background/_barrel.tsp: -------------------------------------------------------------------------------- 1 | import "./show.tsp"; 2 | -------------------------------------------------------------------------------- /src/operations/background/show.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 배경 정보를 가져옵니다. 8 | * 9 | * @return 10 | * 요청한 배경 ID에 알맞은 배경 정보를 반환합니다. 11 | */ 12 | @summary("배경 정보 가져오기") 13 | @tag("background") 14 | @get 15 | @route("/background/show") 16 | op getBackground( 17 | /** 18 | * 응답을 받을 언어입니다. 19 | */ 20 | @header 21 | `x-solvedac-language`?: Language, 22 | 23 | @query backgroundId: string, 24 | ): GetBackground.Ok; 25 | 26 | namespace GetBackground { 27 | @extension(XInternal, true) 28 | model Ok { 29 | @statusCode status: 200; 30 | @body background: Background; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/operations/badge/_barrel.tsp: -------------------------------------------------------------------------------- 1 | import "./show.tsp"; 2 | -------------------------------------------------------------------------------- /src/operations/badge/show.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 뱃지의 정보를 가져옵니다. 8 | * 9 | * @returns 10 | * 요청한 ID에 알맞은 뱃지 데이터를 반환합니다. 11 | */ 12 | @summary("뱃지 정보 가져오기") 13 | @tag("badge") 14 | @get 15 | @route("/badge/show") 16 | op getBadge( 17 | /** 18 | * 응답을 받을 언어입니다. 19 | */ 20 | @header 21 | `x-solvedac-language`?: Language, 22 | 23 | /** 24 | * 뱃지 ID 25 | */ 26 | @query 27 | badgeId: string, 28 | ): GetBadge.Ok; 29 | 30 | namespace GetBadge { 31 | @extension(XInternal, true) 32 | model Ok { 33 | @statusCode status: 200; 34 | @body badge: Badge; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/operations/coins/_barrel.tsp: -------------------------------------------------------------------------------- 1 | import "./exchange_rate.tsp"; 2 | import "./shop/_barrel.tsp"; 3 | -------------------------------------------------------------------------------- /src/operations/coins/exchange_rate.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 코인 → 별조각 환율을 가져옵니다. 8 | * 9 | * @return 10 | * 환율을 가져옵니다. 11 | */ 12 | @summary("코인 → 별조각 환율 가져오기") 13 | @tag("coins") 14 | @get 15 | @route("/coins/exchange_rate") 16 | op getCoinStardustExchangeRate(): GetCoinStardustExchangeRate.Ok; 17 | 18 | namespace GetCoinStardustExchangeRate { 19 | @extension(XInternal, true) 20 | model Ok { 21 | @statusCode status: 200; 22 | @body data: ExchangeRate; 23 | } 24 | 25 | @extension(XInternal, true) 26 | model ExchangeRate { 27 | /** 28 | * 1 코인을 별조각으로 바꾸는 환율입니다. 29 | * 별조각을 코인으로 환전할 때에는 수수료가 1%(소수점은 내림) 붙습니다. 30 | * @example 1498 31 | */ 32 | rate: uint64; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/operations/coins/shop/_barrel.tsp: -------------------------------------------------------------------------------- 1 | import "./list.tsp"; 2 | -------------------------------------------------------------------------------- /src/operations/coins/shop/list.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 코인샵에서 팔고 있는 상품 목록을 가져옵니다. 8 | * 9 | * @return 10 | * 상품 목록을 가져옵니다. 11 | */ 12 | @summary("코인샵 상품 목록 가져오기") 13 | @tag("coins") 14 | @get 15 | @route("/coins/shop/list") 16 | op getCoinShopProducts( 17 | /** 18 | * 응답을 받을 언어입니다. 19 | */ 20 | @header 21 | `x-solvedac-language`?: Language, 22 | ): GetCoinShopProducts.Ok; 23 | 24 | namespace GetCoinShopProducts { 25 | @extension(XInternal, true) 26 | model Ok { 27 | @statusCode status: 200; 28 | @body data: CoinShopProduct[]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/operations/organization/_barrel.tsp: -------------------------------------------------------------------------------- 1 | import "./show.tsp"; 2 | -------------------------------------------------------------------------------- /src/operations/organization/show.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 해당 ID의 단체 정보를 가져옵니다. 8 | * 9 | * @return 10 | * 단체 정보를 가져옵니다. 11 | */ 12 | @summary("단체 ID로 단체 정보 가져오기") 13 | @tag("organization") 14 | @get 15 | @route("/organization/show") 16 | op getOrganizationById( 17 | /** 18 | * 요청할 단체의 ID 19 | */ 20 | @query 21 | organizationId: string, 22 | ): GetOrganizationById.Ok; 23 | 24 | namespace GetOrganizationById { 25 | @extension(XInternal, true) 26 | model Ok { 27 | @statusCode status: 200; 28 | @body organization: Organization; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/operations/post/_barrel.tsp: -------------------------------------------------------------------------------- 1 | import "./show.tsp"; 2 | -------------------------------------------------------------------------------- /src/operations/post/show.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 해당 제목의 게시글을 가져옵니다. 8 | * 9 | * @return 10 | * 게시글을 가져옵니다. 11 | */ 12 | @summary("게시글 제목으로 게시글 가져오기") 13 | @tag("post") 14 | @get 15 | @route("/post/show") 16 | op getPostById( 17 | /** 18 | * 응답을 받을 언어입니다. 19 | */ 20 | @header 21 | `x-solvedac-language`?: Language, 22 | 23 | /** 24 | * 요청할 게시글의 제목 25 | */ 26 | @query 27 | postId: string, 28 | ): GetPostById.Ok; 29 | 30 | namespace GetPostById { 31 | @extension(XInternal, true) 32 | model Ok { 33 | @statusCode status: 200; 34 | @body post: Post; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/operations/problem/_barrel.tsp: -------------------------------------------------------------------------------- 1 | import "./show.tsp"; 2 | import "./lookup.tsp"; 3 | import "./level.tsp"; 4 | import "./class.tsp"; 5 | -------------------------------------------------------------------------------- /src/operations/problem/class.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * CLASS별 문제 수를 가져옵니다. 8 | * 9 | * @return 10 | * CLASS별 문제 수 11 | */ 12 | @summary("CLASS별 문제 수 가져오기") 13 | @tag("problem") 14 | @get 15 | @route("/problem/class") 16 | op getClassesProblemCount( 17 | /** 18 | * 응답을 받을 언어입니다. 19 | */ 20 | @header 21 | `x-solvedac-language`?: Language, 22 | ): GetClassesProblemCount.Ok; 23 | 24 | namespace GetClassesProblemCount { 25 | /** 26 | * @example 27 | * [ 28 | * { "class": 1, "total": 36, "essentials": 16, "criteria": 16 }, 29 | * { "class": 2, "total": 40, "essentials": 20, "criteria": 16 }, 30 | * { "class": 3, "total": 48, "essentials": 20, "criteria": 20 }, 31 | * { "class": 4, "total": 48, "essentials": 24, "criteria": 20 }, 32 | * { "class": 5, "total": 48, "essentials": 24, "criteria": 20 }, 33 | * { "class": 6, "total": 48, "essentials": 24, "criteria": 20 }, 34 | * { "class": 7, "total": 48, "essentials": 24, "criteria": 20 }, 35 | * { "class": 8, "total": 48, "essentials": 24, "criteria": 20 }, 36 | * { "class": 9, "total": 48, "essentials": 24, "criteria": 20 }, 37 | * { "class": 10, "total": 48, "essentials": 24, "criteria": 20 } 38 | * ] 39 | */ 40 | @extension(XInternal, true) 41 | model Ok { 42 | @statusCode status: 200; 43 | @body items: ClassEntry[]; 44 | } 45 | 46 | @extension(XInternal, true) 47 | model ClassEntry { 48 | /** 49 | * 클래스 숫자입니다. 50 | */ 51 | class: Class; 52 | 53 | /** 54 | * 총 문제 수입니다. 55 | */ 56 | total: uint32; 57 | 58 | /** 59 | * 에센셜 문제 수입니다. 60 | */ 61 | essentials: uint32; 62 | 63 | /** 64 | * 취득에 필요한 문제 수입니다. 65 | */ 66 | criteria: uint32; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/operations/problem/level.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 난이도별 문제 수를 가져옵니다. 8 | * 9 | * @return 10 | * 난이도별 문제 수 11 | */ 12 | @summary("난이도별 문제 수 가져오기") 13 | @tag("problem") 14 | @get 15 | @route("/problem/level") 16 | op getProblemsCountGroupByLevel( 17 | /** 18 | * 응답을 받을 언어입니다. 19 | */ 20 | @header 21 | `x-solvedac-language`?: Language, 22 | ): GetProblemsCountGroupByLevel.Ok; 23 | 24 | namespace GetProblemsCountGroupByLevel { 25 | /** 26 | * @example 27 | * [ 28 | * { "level": 0, "count": 7159 }, 29 | * { "level": 1, "count": 154 }, 30 | * { "level": 2, "count": 271 }, 31 | * { "level": 3, "count": 696 }, 32 | * { "level": 4, "count": 893 }, 33 | * { "level": 5, "count": 782 }, 34 | * { "level": 6, "count": 771 }, 35 | * { "level": 7, "count": 828 }, 36 | * { "level": 8, "count": 914 }, 37 | * { "level": 9, "count": 959 }, 38 | * { "level": 10, "count": 1021 }, 39 | * { "level": 11, "count": 973 }, 40 | * { "level": 12, "count": 1386 }, 41 | * { "level": 13, "count": 1291 }, 42 | * { "level": 14, "count": 1126 }, 43 | * { "level": 15, "count": 1023 }, 44 | * { "level": 16, "count": 1178 }, 45 | * { "level": 17, "count": 1121 }, 46 | * { "level": 18, "count": 1165 }, 47 | * { "level": 19, "count": 1126 }, 48 | * { "level": 20, "count": 891 }, 49 | * { "level": 21, "count": 904 }, 50 | * { "level": 22, "count": 850 }, 51 | * { "level": 23, "count": 602 }, 52 | * { "level": 24, "count": 440 }, 53 | * { "level": 25, "count": 352 }, 54 | * { "level": 26, "count": 281 }, 55 | * { "level": 27, "count": 149 }, 56 | * { "level": 28, "count": 93 }, 57 | * { "level": 29, "count": 32 }, 58 | * { "level": 30, "count": 28 } 59 | * ] 60 | */ 61 | @extension(XInternal, true) 62 | model Ok { 63 | @statusCode status: 200; 64 | @body items: LevelEntry[]; 65 | } 66 | 67 | @extension(XInternal, true) 68 | model LevelEntry { 69 | level: ProblemLevel; 70 | 71 | /** 72 | * 문제 수입니다. 73 | */ 74 | count: uint64; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/operations/problem/lookup.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 요청한 번호 목록 각각의 백준 문제에 해당하는 solved.ac 문제 정보를 목록으로 가져옵니다. 8 | * 9 | * @return 10 | * solved.ac 문제 정보 여러개를 가져옵니다. 11 | */ 12 | @summary("백준 문제 번호 목록으로 문제 가져오기") 13 | @tag("problem") 14 | @get 15 | @route("/problem/lookup") 16 | op getProblemsByIdList( 17 | /** 18 | * 응답을 받을 언어입니다. 19 | */ 20 | @header 21 | `x-solvedac-language`?: Language, 22 | 23 | /** 24 | * 요청할 백준 문제 번호 목록 25 | * 쉼표로 구분해 넣습니다 26 | */ 27 | @query({ 28 | format: "csv", 29 | }) 30 | problemIds: uint64[], 31 | ): GetProblemsByIdList.Ok; 32 | 33 | namespace GetProblemsByIdList { 34 | @extension(XInternal, true) 35 | model Ok { 36 | @statusCode status: 200; 37 | @body data: PaginatedList; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/operations/problem/show.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 요청한 번호의 백준 문제에 해당하는 solved.ac 문제 정보를 가져옵니다. 8 | * 9 | * @return 10 | * solved.ac 문제 정보 1개를 가져옵니다. 11 | */ 12 | @summary("백준 문제 번호로 문제 가져오기") 13 | @tag("problem") 14 | @get 15 | @route("/problem/show") 16 | op getProblemById( 17 | /** 18 | * 응답을 받을 언어입니다. 19 | */ 20 | @header 21 | `x-solvedac-language`?: Language, 22 | 23 | /** 24 | * 요청할 백준 문제 번호 25 | */ 26 | @query 27 | problemId: uint64, 28 | ): GetProblemById.Ok; 29 | 30 | namespace GetProblemById { 31 | @extension(XInternal, true) 32 | model Ok { 33 | @statusCode status: 200; 34 | @body problem: Problem; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/operations/ranking/_barrel.tsp: -------------------------------------------------------------------------------- 1 | import "./contribution.tsp"; 2 | import "./class.tsp"; 3 | import "./streak.tsp"; 4 | import "./reverse_rival.tsp"; 5 | import "./rival.tsp"; 6 | import "./tier.tsp"; 7 | import "./organization.tsp"; 8 | import "./in_organization.tsp"; 9 | import "./arena_in_organization.tsp"; 10 | -------------------------------------------------------------------------------- /src/operations/ranking/arena_in_organization.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 해당 단체에 속한 사용자 중에서 아레나 레이팅이 높은 사용자가 먼저 오도록 정렬한 목록을 가져옵니다. 8 | * 9 | * @return 10 | * 페이지네이션 가능한 사용자 목록을 반환합니다. 11 | */ 12 | @summary("아레나 레이팅 순 단체 내 랭킹 가져오기") 13 | @tag("ranking") 14 | @get 15 | @route("/ranking/arena_in_organization") 16 | op getRankingByArenaRatingInOrganization( 17 | /** 18 | * 단체 ID 19 | */ 20 | @query 21 | organizationId: uint32, 22 | 23 | /** 24 | * 페이지 25 | */ 26 | @query 27 | page?: uint32, 28 | ): GetRankingByArenaRatingInOrganization.Ok; 29 | 30 | namespace GetRankingByArenaRatingInOrganization { 31 | @extension(XInternal, true) 32 | model Ok { 33 | @statusCode status: 200; 34 | @body data: PaginatedList; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/operations/ranking/class.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * CLASS가 높은 사용자가 먼저 오도록 정렬한 사용자 목록을 가져옵니다. 8 | * 9 | * @return 10 | * 페이지네이션 가능한 사용자 목록을 반환합니다. 11 | */ 12 | @summary("CLASS 순 사용자 랭킹 가져오기") 13 | @tag("ranking") 14 | @useAuth(TokenAuth) 15 | @get 16 | @route("/ranking/class") 17 | op getRankingByClass( 18 | /** 19 | * 응답을 받을 언어입니다. 20 | */ 21 | @header 22 | `x-solvedac-language`?: Language, 23 | 24 | /** 25 | * 페이지 26 | */ 27 | @query 28 | page?: uint32, 29 | ): GetRankingByClass.Ok; 30 | 31 | namespace GetRankingByClass { 32 | @extension(XInternal, true) 33 | model Ok { 34 | @statusCode status: 200; 35 | @body data: PaginatedList; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/operations/ranking/contribution.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 기여 횟수가 높은 사용자가 먼저 오도록 정렬한 사용자 목록을 가져옵니다. 8 | * 9 | * @return 10 | * 페이지네이션 가능한 사용자 목록을 반환합니다. 11 | */ 12 | @summary("기여 순 사용자 랭킹 가져오기") 13 | @tag("ranking") 14 | @useAuth(TokenAuth) 15 | @get 16 | @route("/ranking/contribution") 17 | op getRankingByContribution( 18 | /** 19 | * 응답을 받을 언어입니다. 20 | */ 21 | @header 22 | `x-solvedac-language`?: Language, 23 | 24 | /** 25 | * 페이지 26 | */ 27 | @query 28 | page?: uint32, 29 | ): GetRankingByContribution.Ok; 30 | 31 | namespace GetRankingByContribution { 32 | @extension(XInternal, true) 33 | model Ok { 34 | @statusCode status: 200; 35 | @body data: PaginatedList; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/operations/ranking/in_organization.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 해당 단체에 속한 사용자 중에서 문제풀이 레이팅이 높은 사용자가 먼저 오도록 정렬한 목록을 가져옵니다. 8 | * 9 | * @return 10 | * 페이지네이션 가능한 사용자 목록을 반환합니다. 11 | */ 12 | @summary("문제풀이 레이팅 순 단체 내 랭킹 가져오기") 13 | @tag("ranking") 14 | @get 15 | @route("/ranking/in_organization") 16 | op getRankingByACRatingInOrganization( 17 | /** 18 | * 단체 ID 19 | */ 20 | @query 21 | organizationId: uint32, 22 | 23 | /** 24 | * 페이지 25 | */ 26 | @query 27 | page?: uint32, 28 | ): GetRankingByACRatingInOrganization.Ok; 29 | 30 | namespace GetRankingByACRatingInOrganization { 31 | @extension(XInternal, true) 32 | model Ok { 33 | @statusCode status: 200; 34 | @body data: PaginatedList; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/operations/ranking/organization.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 역라이벌인 사용자 중에서 문제풀이 레이팅이 높은 단체가 먼저 오도록 정렬한 목록을 가져옵니다. 8 | * 9 | * @return 10 | * 페이지네이션 가능한 사용자 목록을 반환합니다. 11 | */ 12 | @summary("문제풀이 레이팅 순 단체 랭킹 가져오기") 13 | @tag("ranking") 14 | @get 15 | @route("/ranking/organization") 16 | op getOrganizationRankingByACRating( 17 | /** 18 | * 단체 유형. 지정하지 않을 경우 전체입니다. 19 | */ 20 | @query 21 | type?: OrganizationType, 22 | 23 | /** 24 | * 페이지 25 | */ 26 | @query 27 | page?: uint32, 28 | ): GetOrganizationRankingByACRating.Ok; 29 | 30 | namespace GetOrganizationRankingByACRating { 31 | @extension(XInternal, true) 32 | model Ok { 33 | @statusCode status: 200; 34 | @body data: PaginatedList>; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/operations/ranking/reverse_rival.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 역라이벌인 사용자 중에서 문제풀이 레이팅이 높은 사용자가 먼저 오도록 정렬한 목록을 가져옵니다. 8 | * 9 | * @return 10 | * 페이지네이션 가능한 사용자 목록을 반환합니다. 11 | */ 12 | @summary("문제풀이 레이팅 순 역라이벌 랭킹 가져오기") 13 | @tag("ranking") 14 | @useAuth(TokenAuth) 15 | @get 16 | @route("/ranking/reverse_rival") 17 | op getReverseRivalRankingByACRating( 18 | /** 19 | * 응답을 받을 언어입니다. 20 | */ 21 | @header 22 | `x-solvedac-language`?: Language, 23 | 24 | /** 25 | * 페이지 26 | */ 27 | @query 28 | page?: uint32, 29 | ): GetReverseRivalRankingByACRating.Ok | Unauthorized; 30 | 31 | namespace GetReverseRivalRankingByACRating { 32 | @extension(XInternal, true) 33 | model Ok { 34 | @statusCode status: 200; 35 | @body data: PaginatedList; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/operations/ranking/rival.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 라이벌인 사용자 중에서 문제풀이 레이팅이 높은 사용자가 먼저 오도록 정렬한 목록을 가져옵니다. 8 | * 9 | * @return 10 | * 페이지네이션 가능한 사용자 목록을 반환합니다. 11 | */ 12 | @summary("문제풀이 레이팅 순 라이벌 랭킹 가져오기") 13 | @tag("ranking") 14 | @useAuth(TokenAuth) 15 | @get 16 | @route("/ranking/rival") 17 | op getRivalRankingByACRating( 18 | /** 19 | * 응답을 받을 언어입니다. 20 | */ 21 | @header 22 | `x-solvedac-language`?: Language, 23 | 24 | /** 25 | * 페이지 26 | */ 27 | @query 28 | page?: uint32, 29 | ): GetRivalRankingByACRating.Ok | Unauthorized; 30 | 31 | namespace GetRivalRankingByACRating { 32 | @extension(XInternal, true) 33 | model Ok { 34 | @statusCode status: 200; 35 | @body data: PaginatedList; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/operations/ranking/streak.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 치장 스트릭 유지일이 높은 사용자가 먼저 오도록 정렬한 사용자 목록을 가져옵니다. 8 | * 9 | * @return 10 | * 페이지네이션 가능한 사용자 목록을 반환합니다. 11 | */ 12 | @summary("최장 스트릭 순 사용자 랭킹 가져오기") 13 | @tag("ranking") 14 | @useAuth(TokenAuth) 15 | @get 16 | @route("/ranking/streak") 17 | op getRankingByMaxStreak( 18 | /** 19 | * 응답을 받을 언어입니다. 20 | */ 21 | @header 22 | `x-solvedac-language`?: Language, 23 | 24 | /** 25 | * 페이지 26 | */ 27 | @query 28 | page?: uint32, 29 | ): GetRankingByMaxStreak.Ok; 30 | 31 | namespace GetRankingByMaxStreak { 32 | @extension(XInternal, true) 33 | model Ok { 34 | @statusCode status: 200; 35 | @body data: PaginatedList; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/operations/ranking/tier.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 문제풀이 레이팅이 높은 사용자가 먼저 오도록 정렬한 사용자 목록을 가져옵니다. 8 | * 9 | * @return 10 | * 페이지네이션 가능한 사용자 목록을 반환합니다. 11 | */ 12 | @summary("문제풀이 레이팅 순 사용자 랭킹 가져오기") 13 | @tag("ranking") 14 | @useAuth(TokenAuth) 15 | @get 16 | @route("/ranking/tier") 17 | op getRankingBySolveACRating( 18 | /** 19 | * 응답을 받을 언어입니다. 20 | */ 21 | @header 22 | `x-solvedac-language`?: Language, 23 | 24 | /** 25 | * 페이지 26 | */ 27 | @query 28 | page?: uint32, 29 | ): GetRankingBySolveTier.Ok; 30 | 31 | namespace GetRankingBySolveTier { 32 | @extension(XInternal, true) 33 | model Ok { 34 | @statusCode status: 200; 35 | @body data: PaginatedList; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/operations/search/_barrel.tsp: -------------------------------------------------------------------------------- 1 | import "./problem.tsp"; 2 | import "./tag.tsp"; 3 | import "./user.tsp"; 4 | import "./suggestion.tsp"; 5 | -------------------------------------------------------------------------------- /src/operations/search/problem.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 주어진 쿼리에 따라 문제를 검색합니다. 8 | * 9 | * @return 10 | * 페이지네이션 가능한 문제 목록을 반환합니다. 11 | */ 12 | @summary("문제 검색하기") 13 | @tag("search") 14 | @get 15 | @route("/search/problem") 16 | op searchProblem( 17 | /** 18 | * 응답을 받을 언어입니다. 19 | */ 20 | @header 21 | `x-solvedac-language`?: Language, 22 | 23 | /** 24 | * 쿼리 문자열 25 | */ 26 | @query 27 | query: string, 28 | 29 | /** 30 | * 검색 결과 정렬 방향 31 | * 32 | *
33 | * 열거형 값 설명 34 | * 35 | * | 값 | 설명 | 36 | * | :--- | :---------------------- | 37 | * | asc | 오름차순 (작은 것 먼저) | 38 | * | desc | 내림차순 (큰 것 먼저) | 39 | *
40 | */ 41 | @query 42 | direction: SearchProblem.QueryDirection, 43 | 44 | /** 45 | * 페이지 46 | */ 47 | @query 48 | page?: uint32, 49 | 50 | /** 51 | * 검색 결과 정렬 기준 52 | * 53 | *
54 | * 열거형 값 설명 55 | * 56 | * | 값 | 설명 | 57 | * | :---------- | :------------- | 58 | * | id | 백준 문제 번호 | 59 | * | level | 문제 수준 | 60 | * | title | 문제 제목 | 61 | * | solved | 푼 사람 수 | 62 | * | average_try | 평균 시도 | 63 | * | random | 랜덤 | 64 | *
65 | */ 66 | @query 67 | sort: SearchProblem.QuerySort, 68 | ): SearchProblem.Ok; 69 | 70 | namespace SearchProblem { 71 | /** 72 | * 검색 결과 정렬 방향 73 | */ 74 | @extension(XInternal, true) 75 | enum QueryDirection { 76 | Ascend: "asc", 77 | Descend: "desc", 78 | } 79 | 80 | /** 81 | * 검색 결과 정렬 기준 82 | */ 83 | @extension(XInternal, true) 84 | enum QuerySort { 85 | BojId: "id", 86 | Level: "level", 87 | Title: "title", 88 | SolvedCount: "solved", 89 | AverageTry: "average_try", 90 | Random: "random", 91 | } 92 | 93 | @extension(XInternal, true) 94 | model Ok { 95 | @statusCode status: 200; 96 | @body data: PaginatedList; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/operations/search/suggestion.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 주어진 쿼리에 따라 검색할 때 도움이 되도록 자동 완성 및 상위 검색 결과를 반환합니다. 8 | * 자동 완성 결과는 언어에 의존적입니다. 9 | * 10 | * @return 11 | * 자동 완성 및 상위 검색 결과를 반환합니다. 12 | */ 13 | @summary("검색 자동완성 구하기") 14 | @tag("search") 15 | @get 16 | @route("/search/suggestion") 17 | op getSearchAutoCompletions( 18 | /** 19 | * 응답을 받을 언어입니다. 20 | */ 21 | @header 22 | `x-solvedac-language`?: Language, 23 | 24 | /** 25 | * 쿼리 문자열 26 | */ 27 | @query 28 | query: string, 29 | ): GetSearchAutoCompletions.Ok; 30 | 31 | namespace GetSearchAutoCompletions { 32 | @extension(XInternal, true) 33 | model Ok { 34 | @statusCode status: 200; 35 | @body data: Suggestion; 36 | } 37 | 38 | @extension(XInternal, true) 39 | model Suggestion { 40 | autocomplete: AutoCompleteEntry[]; 41 | problems: BriefProblemEntry[]; 42 | 43 | /** 44 | * 검색 결과로 나올 총 문제 수입니다 45 | * 46 | * @example 12548 47 | */ 48 | problemCount: uint64; 49 | 50 | tags: BriefProblemTagEntry[]; 51 | 52 | /** 53 | * 검색 결과로 나올 총 태그 수입니다. 54 | * 55 | * @example 134 56 | */ 57 | tagCount: uint64; 58 | 59 | users: UserEntry[]; 60 | 61 | /** 62 | * 검색 결과로 나올 총 사용자 수입니다. 63 | * 64 | * @example 15015 65 | */ 66 | userCount: uint64; 67 | } 68 | 69 | @extension(XInternal, true) 70 | model AutoCompleteEntryBase { 71 | /** 72 | * 자동 완성 제목입니다. 73 | * 만약 href이 없을 경우 누르면 해당 값으로 자동 완성합니다. 74 | */ 75 | caption: string; 76 | 77 | /** 78 | * 자동 완성 요소의 설명입니다. 79 | */ 80 | description: string; 81 | } 82 | 83 | /** 84 | * 고급 검색 관련 자동 완성입니다. 85 | * 86 | * @example { "caption": "s#", "description": "푼 사람 수" } 87 | */ 88 | @extension(XInternal, true) 89 | model AutoCompleteEntry { 90 | ...AutoCompleteEntryBase; 91 | } 92 | 93 | /** 94 | * 요악한 문제 정보입니다. 95 | * 96 | * @example 97 | * { 98 | * "id": 1014, 99 | * "title": "컨닝", 100 | * "level": 17, 101 | * "solved": 2143, 102 | * "caption": "컨닝", 103 | * "description": "#1014", 104 | * "href": "https://www.acmicpc.net/problem/1014" 105 | * } 106 | */ 107 | @extension(XInternal, true) 108 | model BriefProblemEntry { 109 | /** 110 | * 문제 ID입니다. 111 | * 112 | * @example 1763 113 | */ 114 | id: uint64; 115 | 116 | /** 117 | * 문제 제목입니다. 118 | * 119 | * @example "트리 색칠" 120 | */ 121 | title: string; 122 | 123 | /** 124 | * @example 24 125 | */ 126 | level: ProblemLevel; 127 | 128 | /** 129 | * 푼 사람 수입니다. 130 | * 131 | * @example 160 132 | */ 133 | solved: uint64; 134 | 135 | ...AutoCompleteEntryBase; 136 | } 137 | 138 | /** 139 | * 요약한 태그 정보입니다. 140 | * 141 | * @example 142 | * { 143 | * "key": "math", 144 | * "name": "수학", 145 | * "problemCount": 6078, 146 | * "caption": "tag:math", 147 | * "description": "6078문제", 148 | * "href": "/problems/tags/math" 149 | * } 150 | */ 151 | @extension(XInternal, true) 152 | model BriefProblemTagEntry { 153 | /** 154 | * solved.ac에서 쓰는 태그 ID입니다. 155 | * @example "math" 156 | */ 157 | key: string; 158 | 159 | /** 160 | * 태그 이름입니다. 161 | * 사용자 언어에 따라 번역되지 않습니다. 162 | * 163 | * @example "mathematics" 164 | */ 165 | name: string; 166 | 167 | /** 168 | * 태그가 붙은 문제 수입니다. 169 | * 170 | * @example 6078 171 | */ 172 | problemCount: uint64; 173 | 174 | ...AutoCompleteEntryBase; 175 | } 176 | 177 | /** 178 | * 사용자 정보입니다. 179 | */ 180 | @extension(XInternal, true) 181 | @withVisibility("brief") 182 | model UserEntry is User; 183 | } 184 | -------------------------------------------------------------------------------- /src/operations/search/tag.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 주어진 쿼리에 따라 문제 태그를 검색합니다. 8 | * 9 | * @return 10 | * 페이지네이션 가능한 문제 목록을 반환합니다. 11 | */ 12 | @summary("문제 태그 검색하기") 13 | @tag("search") 14 | @get 15 | @route("/search/tag") 16 | op searchProblemTag( 17 | /** 18 | * 응답을 받을 언어입니다. 19 | */ 20 | @header 21 | `x-solvedac-language`?: Language, 22 | 23 | /** 24 | * 쿼리 문자열 25 | */ 26 | @query 27 | query: string, 28 | 29 | /** 30 | * 페이지 31 | */ 32 | @query 33 | page?: uint32, 34 | ): SearchTag.Ok; 35 | 36 | namespace SearchTag { 37 | @extension(XInternal, true) 38 | model Ok { 39 | @statusCode status: 200; 40 | @body data: PaginatedList; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/operations/search/user.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 주어진 쿼리에 따라 사용자를 검색합니다. 8 | * 9 | * @return 10 | * 페이지네이션 가능한 문제 목록을 반환합니다. 11 | */ 12 | @summary("사용자 검색하기") 13 | @tag("search") 14 | @get 15 | @route("/search/user") 16 | op searchUser( 17 | /** 18 | * 응답을 받을 언어입니다. 19 | */ 20 | @header 21 | `x-solvedac-language`?: Language, 22 | 23 | /** 24 | * 쿼리 문자열 25 | */ 26 | @query 27 | query: string, 28 | 29 | /** 30 | * 페이지 31 | */ 32 | @query 33 | page?: uint32, 34 | ): SearchUser.Ok; 35 | 36 | namespace SearchUser { 37 | @extension(XInternal, true) 38 | model Ok { 39 | @statusCode status: 200; 40 | @body data: PaginatedList; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/operations/site/_barrel.tsp: -------------------------------------------------------------------------------- 1 | import "./stats.tsp"; 2 | -------------------------------------------------------------------------------- /src/operations/site/stats.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * solved.ac 통계를 가져옵니다. 8 | * 9 | * @return 10 | * solved.ac 사이트 통계 정보 11 | */ 12 | @summary("solved.ac 통계 가져오기") 13 | @tag("other") 14 | @get 15 | @route("/site/stats") 16 | op getSiteStatistics(): GetSiteStatistics.Ok; 17 | 18 | namespace GetSiteStatistics { 19 | @extension(XInternal, true) 20 | model Ok { 21 | @statusCode status: 200; 22 | @body stats: SiteStatistics; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/operations/tag/_barrel.tsp: -------------------------------------------------------------------------------- 1 | import "./list.tsp"; 2 | import "./show.tsp"; 3 | -------------------------------------------------------------------------------- /src/operations/tag/list.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 태그 목록을 가져옵니다. 8 | * 9 | * @return 10 | * 태그 목록을 가져옵니다. 11 | */ 12 | @summary("태그 목록 가져오기") 13 | @tag("tag") 14 | @get 15 | @route("/tag/list") 16 | op getTagList( 17 | /** 18 | * 페이지 19 | */ 20 | @query 21 | page?: uint32, 22 | ): GetTagList.Ok; 23 | 24 | namespace GetTagList { 25 | @extension(XInternal, true) 26 | model Ok { 27 | @statusCode status: 200; 28 | @body data: PaginatedList; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/operations/tag/show.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 태그 ID로 태그 정보를 가져옵니다. 8 | * 9 | * @return 10 | * 태그 정보를 가져옵니다. 11 | */ 12 | @summary("태그 ID로 태그 정보 가져오기") 13 | @tag("tag") 14 | @get 15 | @route("/tag/show") 16 | op getTagByKey( 17 | /** 18 | * 태그 ID 19 | */ 20 | @query 21 | key: string, 22 | ): GetTagByKey.Ok; 23 | 24 | namespace GetTagByKey { 25 | @extension(XInternal, true) 26 | model Ok { 27 | @statusCode status: 200; 28 | @body tag: ProblemTag; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/operations/user/_barrel.tsp: -------------------------------------------------------------------------------- 1 | import "./show.tsp"; 2 | import "./top_100.tsp"; 3 | import "./organizations.tsp"; 4 | import "./problem_stats.tsp"; 5 | import "./additional_info.tsp"; 6 | import "./class_stats.tsp"; 7 | import "./contribution_stats.tsp"; 8 | import "./problem_tag_stats.tsp"; 9 | -------------------------------------------------------------------------------- /src/operations/user/additional_info.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 해당 핸들을 가진 사용자의 부가 정보를 가져옵니다. 8 | * 9 | * @return 10 | * 사용자 부가 정보를 가져옵니다 11 | */ 12 | @summary("사용자 핸들로 부가 정보 가져오기") 13 | @tag("user") 14 | @get 15 | @route("/user/additional_info") 16 | op getUserAdditionalInfo( 17 | /** 18 | * 요청할 사용자명 19 | */ 20 | @query 21 | handle: string, 22 | ): GetUserAdditionalInfo.Ok; 23 | 24 | namespace GetUserAdditionalInfo { 25 | @extension(XInternal, true) 26 | model Ok { 27 | @statusCode status: 200; 28 | @body userAdditionalInfo: UserAdditionalInfo; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/operations/user/class_stats.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 해당 핸들의 사용자가 푼 문제 수를 클래스별로 나누어 가져옵니다. 8 | * 9 | * @return 10 | * 클래스별 푼 문제 수가 담긴 목록 11 | */ 12 | @summary("클래스별로 사용자가 푼 문제 수 가져오기") 13 | @tag("user") 14 | @get 15 | @route("/user/class_stats") 16 | op getUserClassStats( 17 | /** 18 | * 요청할 사용자명 19 | */ 20 | @query 21 | handle: string, 22 | ): GetUserClassStats.Ok; 23 | 24 | namespace GetUserClassStats { 25 | /** 26 | * @example 27 | * [ 28 | * { 29 | * "total": 36, 30 | * "totalSolved": 36, 31 | * "essentials": 16, 32 | * "essentialSolved": 16, 33 | * "class": 1, 34 | * "decoration": "gold" 35 | * }, 36 | * { 37 | * "total": 40, 38 | * "totalSolved": 40, 39 | * "essentials": 20, 40 | * "essentialSolved": 20, 41 | * "class": 2, 42 | * "decoration": "gold" 43 | * }, 44 | * { 45 | * "total": 48, 46 | * "totalSolved": 48, 47 | * "essentials": 20, 48 | * "essentialSolved": 20, 49 | * "class": 3, 50 | * "decoration": "gold" 51 | * }, 52 | * { 53 | * "total": 48, 54 | * "totalSolved": 40, 55 | * "essentials": 24, 56 | * "essentialSolved": 22, 57 | * "class": 4, 58 | * "decoration": "none" 59 | * }, 60 | * { 61 | * "total": 48, 62 | * "totalSolved": 26, 63 | * "essentials": 24, 64 | * "essentialSolved": 13, 65 | * "class": 5, 66 | * "decoration": "none" 67 | * }, 68 | * { 69 | * "total": 48, 70 | * "totalSolved": 24, 71 | * "essentials": 24, 72 | * "essentialSolved": 8, 73 | * "class": 6, 74 | * "decoration": "none" 75 | * }, 76 | * { 77 | * "total": 48, 78 | * "totalSolved": 13, 79 | * "essentials": 24, 80 | * "essentialSolved": 7, 81 | * "class": 7, 82 | * "decoration": null 83 | * }, 84 | * { 85 | * "total": 48, 86 | * "totalSolved": 1, 87 | * "essentials": 24, 88 | * "essentialSolved": 1, 89 | * "class": 8, 90 | * "decoration": null 91 | * }, 92 | * { 93 | * "total": 48, 94 | * "totalSolved": 0, 95 | * "essentials": 24, 96 | * "essentialSolved": 0, 97 | * "class": 9, 98 | * "decoration": null 99 | * }, 100 | * { 101 | * "total": 48, 102 | * "totalSolved": 0, 103 | * "essentials": 24, 104 | * "essentialSolved": 0, 105 | * "class": 10, 106 | * "decoration": null 107 | * } 108 | * ] 109 | */ 110 | @extension(XInternal, true) 111 | model Ok { 112 | @statusCode status: 200; 113 | @body data: Array; 114 | } 115 | 116 | @extension(XInternal, true) 117 | model ClassStat { 118 | /** 119 | * 클래스 번호입니다. 120 | * @example 1 121 | */ 122 | class: Class; 123 | 124 | /** 125 | * solved.ac에 등록된 해당 클래스의 문제 수입니다. 126 | * @example 36 127 | */ 128 | total: uint64; 129 | 130 | /** 131 | * 사용자가 푼 클래스 문제 수입니다. 132 | * @example 36 133 | */ 134 | totalSolved: uint64; 135 | 136 | /** 137 | * solved.ac에 등록된 해당 클래스의 에센셜 문제 수입니다. 138 | * @example 16 139 | */ 140 | essentials: uint64; 141 | 142 | /** 143 | * 사용자가 푼 클래스 에센셜 문제 수입니다. 144 | * @example 16 145 | */ 146 | essentialSolved: uint64; 147 | 148 | /** 149 | * 사용자가 획득한 클래스 치장입니다. 150 | * @example "gold" 151 | */ 152 | decoration: string; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/operations/user/contribution_stats.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 해당 핸들의 사용자가 기여한 문제 수를 문제 수준별로 나누어 가져옵니다. 8 | * 9 | * @return 10 | * 문제 수준별 기여한 문제 수가 담긴 목록 11 | */ 12 | @summary("문제 수준별로 사용자가 기여한 문제 수 가져오기") 13 | @tag("user") 14 | @get 15 | @route("/user/contribution_stats") 16 | op getUserContributionStats( 17 | /** 18 | * 요청할 사용자명 19 | */ 20 | @query 21 | handle: string, 22 | ): GetUserContributionStats.Ok; 23 | 24 | namespace GetUserContributionStats { 25 | /** 26 | * @example 27 | *{ 28 | *[ 29 | * { 30 | * "total": 7071, 31 | * "solved": 11, 32 | * "solvedStandards": 9, 33 | * "contributed": 0 34 | * }, 35 | * { 36 | * "total": 308, 37 | * "solved": 154, 38 | * "solvedStandards": 49, 39 | * "contributed": 79 40 | * }, 41 | * { 42 | * "total": 568, 43 | * "solved": 284, 44 | * "solvedStandards": 13, 45 | * "contributed": 205 46 | * }, 47 | * { 48 | * "total": 1370, 49 | * "solved": 664, 50 | * "solvedStandards": 12, 51 | * "contributed": 584 52 | * }, 53 | * { 54 | * "total": 1403, 55 | * "solved": 497, 56 | * "solvedStandards": 17, 57 | * "contributed": 344 58 | * }, 59 | * { 60 | * "total": 1011, 61 | * "solved": 220, 62 | * "solvedStandards": 2, 63 | * "contributed": 144 64 | * }, 65 | * { 66 | * "total": 1009, 67 | * "solved": 213, 68 | * "solvedStandards": 2, 69 | * "contributed": 8 70 | * }, 71 | * { 72 | * "total": 1008, 73 | * "solved": 153, 74 | * "solvedStandards": 1, 75 | * "contributed": 2 76 | * }, 77 | * { 78 | * "total": 1011, 79 | * "solved": 115, 80 | * "solvedStandards": 11, 81 | * "contributed": 2 82 | * }, 83 | * { 84 | * "total": 1077, 85 | * "solved": 118, 86 | * "solvedStandards": 11, 87 | * "contributed": 1 88 | * }, 89 | * { 90 | * "total": 1167, 91 | * "solved": 97, 92 | * "solvedStandards": 3, 93 | * "contributed": 2 94 | * }, 95 | * { 96 | * "total": 1052, 97 | * "solved": 97, 98 | * "solvedStandards": 5, 99 | * "contributed": 2 100 | * }, 101 | * { 102 | * "total": 1532, 103 | * "solved": 85, 104 | * "solvedStandards": 2, 105 | * "contributed": 8 106 | * }, 107 | * { 108 | * "total": 1387, 109 | * "solved": 50, 110 | * "solvedStandards": 1, 111 | * "contributed": 8 112 | * }, 113 | * { 114 | * "total": 1197, 115 | * "solved": 44, 116 | * "solvedStandards": 0, 117 | * "contributed": 11 118 | * }, 119 | * { 120 | * "total": 1106, 121 | * "solved": 55, 122 | * "solvedStandards": 12, 123 | * "contributed": 18 124 | * }, 125 | * { 126 | * "total": 1287, 127 | * "solved": 94, 128 | * "solvedStandards": 2, 129 | * "contributed": 12 130 | * }, 131 | * { 132 | * "total": 1226, 133 | * "solved": 66, 134 | * "solvedStandards": 2, 135 | * "contributed": 6 136 | * }, 137 | * { 138 | * "total": 1243, 139 | * "solved": 53, 140 | * "solvedStandards": 0, 141 | * "contributed": 4 142 | * }, 143 | * { 144 | * "total": 1181, 145 | * "solved": 22, 146 | * "solvedStandards": 0, 147 | * "contributed": 0 148 | * }, 149 | * { 150 | * "total": 896, 151 | * "solved": 9, 152 | * "solvedStandards": 2, 153 | * "contributed": 2 154 | * }, 155 | * { 156 | * "total": 941, 157 | * "solved": 6, 158 | * "solvedStandards": 0, 159 | * "contributed": 1 160 | * }, 161 | * { 162 | * "total": 880, 163 | * "solved": 5, 164 | * "solvedStandards": 0, 165 | * "contributed": 0 166 | * }, 167 | * { 168 | * "total": 618, 169 | * "solved": 0, 170 | * "solvedStandards": 0, 171 | * "contributed": 0 172 | * }, 173 | * { 174 | * "total": 452, 175 | * "solved": 0, 176 | * "solvedStandards": 0, 177 | * "contributed": 0 178 | * }, 179 | * { 180 | * "total": 355, 181 | * "solved": 0, 182 | * "solvedStandards": 0, 183 | * "contributed": 0 184 | * }, 185 | * { 186 | * "total": 285, 187 | * "solved": 0, 188 | * "solvedStandards": 0, 189 | * "contributed": 0 190 | * }, 191 | * { 192 | * "total": 150, 193 | * "solved": 0, 194 | * "solvedStandards": 0, 195 | * "contributed": 0 196 | * }, 197 | * { 198 | * "total": 92, 199 | * "solved": 0, 200 | * "solvedStandards": 0, 201 | * "contributed": 0 202 | * }, 203 | * { 204 | * "total": 34, 205 | * "solved": 0, 206 | * "solvedStandards": 0, 207 | * "contributed": 0 208 | * }, 209 | * { 210 | * "total": 28, 211 | * "solved": 0, 212 | * "solvedStandards": 0, 213 | * "contributed": 0 214 | * } 215 | *] 216 | *} 217 | */ 218 | @extension(XInternal, true) 219 | model Ok { 220 | @statusCode status: 200; 221 | @body data: Array; 222 | } 223 | 224 | @extension(XInternal, true) 225 | model ContributionStat { 226 | /** 227 | * solved.ac에 등록된 해당 수준 문제 수입니다. 228 | * @example 0 229 | */ 230 | total: uint64; 231 | 232 | /** 233 | * 사용자가 푼 문제 수입니다. 234 | */ 235 | solved: uint64; 236 | 237 | /** 238 | * 사용자가 푼 표준 문제 수입니다. 239 | */ 240 | solvedStandards: uint64; 241 | 242 | /** 243 | * 사용자가 기여한 문제 수입니다. 244 | */ 245 | contributed: uint64; 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /src/operations/user/organizations.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 해당 핸들의 사용자 정보를 가져옵니다. 8 | * 만약 요청자가 로그인 중이라면 라이벌 여부도 가져옵니다. 9 | * 로그인 중이 아니라면 라이벌 등 로그인해야 알 수 있는 정보는 기본값 처리됩니다. 10 | * 11 | * @return 12 | * 사용자 정보를 가져옵니다 13 | */ 14 | @summary("사용자 핸들로 단체 가져오기") 15 | @tag("user") 16 | @get 17 | @route("/user/organizations") 18 | op getUserOrganizations( 19 | /** 20 | * 요청할 사용자명 21 | */ 22 | @query 23 | handle: string, 24 | ): GetUserOrganizations.Ok; 25 | 26 | namespace GetUserOrganizations { 27 | @extension(XInternal, true) 28 | model Ok { 29 | @statusCode status: 200; 30 | @body data: Array; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/operations/user/problem_stats.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 해당 핸들의 사용자가 푼 문제 수를 문제 수준별로 나누어 가져옵니다. 8 | * 9 | * @return 10 | * 문제 수준별 푼 문제 수가 담긴 목록 11 | */ 12 | @summary("문제 수준별로 사용자가 푼 문제 수 가져오기") 13 | @tag("user") 14 | @get 15 | @route("/user/problem_stats") 16 | op getUserProblemStats( 17 | /** 18 | * 요청할 사용자명 19 | */ 20 | @query 21 | handle: string, 22 | ): GetUserProblemStats.Ok; 23 | 24 | namespace GetUserProblemStats { 25 | /** 26 | * @example 27 | * [ 28 | * { "level": 0, "solved": 33, "tried": 3, "partial": 2, "total": 7078 }, 29 | * { "level": 1, "solved": 108, "tried": 0, "partial": 0, "total": 154 }, 30 | * { "level": 2, "solved": 155, "tried": 0, "partial": 0, "total": 283 }, 31 | * { "level": 3, "solved": 341, "tried": 0, "partial": 0, "total": 703 }, 32 | * { "level": 4, "solved": 365, "tried": 0, "partial": 0, "total": 902 }, 33 | * { "level": 5, "solved": 227, "tried": 0, "partial": 0, "total": 783 }, 34 | * { "level": 6, "solved": 193, "tried": 0, "partial": 0, "total": 783 }, 35 | * { "level": 7, "solved": 183, "tried": 0, "partial": 0, "total": 847 }, 36 | * { "level": 8, "solved": 180, "tried": 0, "partial": 0, "total": 892 }, 37 | * { "level": 9, "solved": 165, "tried": 0, "partial": 0, "total": 972 }, 38 | * { "level": 10, "solved": 154, "tried": 0, "partial": 0, "total": 1051 }, 39 | * { "level": 11, "solved": 186, "tried": 1, "partial": 0, "total": 940 }, 40 | * { "level": 12, "solved": 196, "tried": 0, "partial": 0, "total": 1431 }, 41 | * { "level": 13, "solved": 154, "tried": 3, "partial": 0, "total": 1318 }, 42 | * { "level": 14, "solved": 131, "tried": 3, "partial": 0, "total": 1145 }, 43 | * { "level": 15, "solved": 104, "tried": 3, "partial": 0, "total": 1041 }, 44 | * { "level": 16, "solved": 120, "tried": 2, "partial": 0, "total": 1185 }, 45 | * { "level": 17, "solved": 110, "tried": 6, "partial": 0, "total": 1147 }, 46 | * { "level": 18, "solved": 98, "tried": 6, "partial": 1, "total": 1181 }, 47 | * { "level": 19, "solved": 83, "tried": 4, "partial": 0, "total": 1147 }, 48 | * { "level": 20, "solved": 64, "tried": 5, "partial": 0, "total": 891 }, 49 | * { "level": 21, "solved": 52, "tried": 3, "partial": 0, "total": 930 }, 50 | * { "level": 22, "solved": 32, "tried": 6, "partial": 1, "total": 871 }, 51 | * { "level": 23, "solved": 23, "tried": 2, "partial": 1, "total": 615 }, 52 | * { "level": 24, "solved": 13, "tried": 1, "partial": 0, "total": 450 }, 53 | * { "level": 25, "solved": 7, "tried": 1, "partial": 0, "total": 356 }, 54 | * { "level": 26, "solved": 4, "tried": 0, "partial": 0, "total": 283 }, 55 | * { "level": 27, "solved": 1, "tried": 0, "partial": 0, "total": 150 }, 56 | * { "level": 28, "solved": 1, "tried": 0, "partial": 1, "total": 92 }, 57 | * { "level": 29, "solved": 1, "tried": 0, "partial": 0, "total": 34 }, 58 | * { "level": 30, "solved": 2, "tried": 0, "partial": 0, "total": 28 } 59 | * ] 60 | */ 61 | @extension(XInternal, true) 62 | model Ok { 63 | @statusCode status: 200; 64 | @body data: Array; 65 | } 66 | 67 | @extension(XInternal, true) 68 | model ProblemStat { 69 | level: ProblemLevel; 70 | 71 | /** 72 | * solved.ac에 등록된 해당 수준 문제 수입니다. 73 | * @example 0 74 | */ 75 | total: uint64; 76 | 77 | /** 78 | * 사용자가 푼 문제 수입니다. 79 | */ 80 | solved: uint64; 81 | 82 | /** 83 | * 사용자가 부분 성공한 문제 수입니다. 84 | */ 85 | partial: uint64; 86 | 87 | /** 88 | * 사용자가 시도해 본 문제 수입니다. 89 | */ 90 | tried: uint64; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/operations/user/problem_tag_stats.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 해당 핸들의 사용자가 푼 문제 수를 태그별로 나누어 가져옵니다. 8 | * 9 | * @return 10 | * 태그별 푼 문제 수가 담긴 목록 11 | */ 12 | @summary("태그별로 사용자가 푼 문제 수 가져오기") 13 | @tag("user") 14 | @get 15 | @route("/user/problem_tag_stats") 16 | op getUserProblemTagStats( 17 | /** 18 | * 요청할 사용자명 19 | */ 20 | @query 21 | handle: string, 22 | ): GetUserProblemTagStats.Ok; 23 | 24 | namespace GetUserProblemTagStats { 25 | @extension(XInternal, true) 26 | model Ok { 27 | @statusCode status: 200; 28 | @body data: PaginatedList; 29 | } 30 | 31 | @extension(XInternal, true) 32 | model ProblemTagStat { 33 | tag: ProblemTag; 34 | 35 | /** 36 | * solved.ac에 등록된 해당 태그 문제 수입니다. 37 | * @example 0 38 | */ 39 | total: uint64; 40 | 41 | /** 42 | * 사용자가 푼 문제 수입니다. 43 | */ 44 | solved: uint64; 45 | 46 | /** 47 | * 사용자가 부분 성공한 문제 수입니다. 48 | */ 49 | partial: uint64; 50 | 51 | /** 52 | * 사용자가 시도해 본 문제 수입니다. 53 | */ 54 | tried: uint64; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/operations/user/show.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 해당 핸들의 사용자 정보를 가져옵니다. 8 | * 만약 요청자가 로그인 중이라면 라이벌 여부도 가져옵니다. 9 | * 로그인 중이 아니라면 라이벌 등 로그인해야 알 수 있는 정보는 기본값 처리됩니다. 10 | * 11 | * @return 12 | * 사용자 정보를 가져옵니다 13 | */ 14 | @summary("사용자 핸들로 정보 가져오기") 15 | @tag("user") 16 | @useAuth(TokenAuth) 17 | @get 18 | @route("/user/show") 19 | op getUserByHandle( 20 | /** 21 | * 응답을 받을 언어입니다. 22 | */ 23 | @header 24 | `x-solvedac-language`?: Language, 25 | 26 | /** 27 | * 요청할 사용자명 28 | */ 29 | @query 30 | handle: string, 31 | ): GetUserByHandle.Ok; 32 | 33 | namespace GetUserByHandle { 34 | @extension(XInternal, true) 35 | model Ok { 36 | @statusCode status: 200; 37 | @body user: SocialUser; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/operations/user/top_100.tsp: -------------------------------------------------------------------------------- 1 | using TypeSpec.Http; 2 | using TypeSpec.OpenAPI; 3 | 4 | namespace SolvedAC; 5 | 6 | /** 7 | * 사용자가 푼 문제 중 문제 수준이 높은 상위 100 문제를 가져옵니다 8 | * 9 | * @return 10 | * 상위 100 문제 목록 11 | */ 12 | @summary("상위 100 문제 가져오기") 13 | @tag("user") 14 | @get 15 | @route("/user/top_100") 16 | op getUserTop100( 17 | /** 18 | * 응답을 받을 언어입니다. 19 | */ 20 | @header 21 | `x-solvedac-language`?: Language, 22 | 23 | /** 24 | * 요청할 사용자명 25 | */ 26 | @query 27 | handle: string, 28 | ): GetUserTop100.Ok; 29 | 30 | namespace GetUserTop100 { 31 | @extension(XInternal, true) 32 | model Ok { 33 | @statusCode status: 200; 34 | @body data: PaginatedList; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tspconfig.yaml: -------------------------------------------------------------------------------- 1 | linter: 2 | extends: 3 | - "@typespec/best-practices/recommended" 4 | imports: 5 | - "./auth.tsp" 6 | emit: 7 | - "@typespec/openapi3" 8 | options: 9 | "@typespec/openapi3": 10 | output-file: openapi.yaml 11 | -------------------------------------------------------------------------------- /vendors/@stoplight/elements/web-components.min.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* 2 | object-assign 3 | (c) Sindre Sorhus 4 | @license MIT 5 | */ 6 | 7 | /*! 8 | Copyright (c) 2017 Jed Watson. 9 | Licensed under the MIT License (MIT), see 10 | http://jedwatson.github.io/classnames 11 | */ 12 | 13 | /*! 14 | Copyright (c) 2018 Jed Watson. 15 | Licensed under the MIT License (MIT), see 16 | http://jedwatson.github.io/classnames 17 | */ 18 | 19 | /*! 20 | * Determine if an object is a Buffer 21 | * 22 | * @author Feross Aboukhadijeh 23 | * @license MIT 24 | */ 25 | 26 | /*! 27 | * EventEmitter v5.2.9 - git.io/ee 28 | * Unlicense - http://unlicense.org/ 29 | * Oliver Caldwell - https://oli.me.uk/ 30 | * @preserve 31 | */ 32 | 33 | /*! 34 | * Font Awesome Free 6.1.1 by @fontawesome - https://fontawesome.com 35 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 36 | * Copyright 2022 Fonticons, Inc. 37 | */ 38 | 39 | /*! 40 | * The buffer module from node.js, for the browser. 41 | * 42 | * @author Feross Aboukhadijeh 43 | * @license MIT 44 | */ 45 | 46 | /*! 47 | * URI.js - Mutating URLs 48 | * 49 | * Version: 1.19.11 50 | * 51 | * Author: Rodney Rehm 52 | * Web: http://medialize.github.io/URI.js/ 53 | * 54 | * Licensed under 55 | * MIT License http://www.opensource.org/licenses/mit-license 56 | * 57 | */ 58 | 59 | /*! 60 | * URI.js - Mutating URLs 61 | * IPv6 Support 62 | * 63 | * Version: 1.19.11 64 | * 65 | * Author: Rodney Rehm 66 | * Web: http://medialize.github.io/URI.js/ 67 | * 68 | * Licensed under 69 | * MIT License http://www.opensource.org/licenses/mit-license 70 | * 71 | */ 72 | 73 | /*! 74 | * URI.js - Mutating URLs 75 | * Second Level Domain (SLD) Support 76 | * 77 | * Version: 1.19.11 78 | * 79 | * Author: Rodney Rehm 80 | * Web: http://medialize.github.io/URI.js/ 81 | * 82 | * Licensed under 83 | * MIT License http://www.opensource.org/licenses/mit-license 84 | * 85 | */ 86 | 87 | /*! 88 | * repeat-string 89 | * 90 | * Copyright (c) 2014-2015, Jon Schlinkert. 91 | * Licensed under the MIT License. 92 | */ 93 | 94 | /*! ***************************************************************************** 95 | Copyright (c) Microsoft Corporation. 96 | 97 | Permission to use, copy, modify, and/or distribute this software for any 98 | purpose with or without fee is hereby granted. 99 | 100 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 101 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 102 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 103 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 104 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 105 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 106 | PERFORMANCE OF THIS SOFTWARE. 107 | ***************************************************************************** */ 108 | 109 | /*! https://mths.be/punycode v1.3.2 by @mathias */ 110 | 111 | /*! https://mths.be/punycode v1.4.0 by @mathias */ 112 | 113 | /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */ 114 | 115 | /** 116 | * @license 117 | * Lodash 118 | * Copyright OpenJS Foundation and other contributors 119 | * Released under MIT license 120 | * Based on Underscore.js 1.8.3 121 | * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 122 | */ 123 | 124 | /** @license React v0.19.1 125 | * scheduler.production.min.js 126 | * 127 | * Copyright (c) Facebook, Inc. and its affiliates. 128 | * 129 | * This source code is licensed under the MIT license found in the 130 | * LICENSE file in the root directory of this source tree. 131 | */ 132 | 133 | /** @license React v16.13.1 134 | * react-is.production.min.js 135 | * 136 | * Copyright (c) Facebook, Inc. and its affiliates. 137 | * 138 | * This source code is licensed under the MIT license found in the 139 | * LICENSE file in the root directory of this source tree. 140 | */ 141 | 142 | /** @license React v16.14.0 143 | * react-dom.production.min.js 144 | * 145 | * Copyright (c) Facebook, Inc. and its affiliates. 146 | * 147 | * This source code is licensed under the MIT license found in the 148 | * LICENSE file in the root directory of this source tree. 149 | */ 150 | 151 | /** @license React v16.14.0 152 | * react-jsx-runtime.production.min.js 153 | * 154 | * Copyright (c) Facebook, Inc. and its affiliates. 155 | * 156 | * This source code is licensed under the MIT license found in the 157 | * LICENSE file in the root directory of this source tree. 158 | */ 159 | 160 | /** @license React v16.14.0 161 | * react.production.min.js 162 | * 163 | * Copyright (c) Facebook, Inc. and its affiliates. 164 | * 165 | * This source code is licensed under the MIT license found in the 166 | * LICENSE file in the root directory of this source tree. 167 | */ 168 | --------------------------------------------------------------------------------