diff --git a/packages/backend/test/e2e/fetch-resource.ts b/packages/backend/test/e2e/fetch-resource.ts index 9643c45d1a0bade81c2b7584ae5851e2de4a92dd..78ca8b43ba2a4163fd9d7885a8b3e7860ae02c41 100644 --- a/packages/backend/test/e2e/fetch-resource.ts +++ b/packages/backend/test/e2e/fetch-resource.ts @@ -1,7 +1,8 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { startServer, signup, post, api, simpleGet } from '../utils.js'; +import { startServer, channel, clip, cookie, galleryPost, signup, page, play, post, simpleGet, uploadFile } from '../utils.js'; +import type { SimpleGetResponse } from '../utils.js'; import type { INestApplicationContext } from '@nestjs/common'; // Request Accept @@ -15,189 +16,446 @@ const AP = 'application/activity+json; charset=utf-8'; const HTML = 'text/html; charset=utf-8'; const JSON_UTF8 = 'application/json; charset=utf-8'; -describe('Fetch resource', () => { +describe('Webリソース', () => { let app: INestApplicationContext; let alice: any; + let aliceUploadedFile: any; let alicesPost: any; + let alicePage: any; + let alicePlay: any; + let aliceClip: any; + let aliceGalleryPost: any; + let aliceChannel: any; + + type Request = { + path: string, + accept?: string, + cookie?: string, + }; + const ok = async (param: Request & { + type?: string, + }):Promise<SimpleGetResponse> => { + const { path, accept, cookie, type } = param; + const res = await simpleGet(path, accept, cookie); + assert.strictEqual(res.status, 200); + assert.strictEqual(res.type, type ?? HTML); + return res; + }; + + const notOk = async (param: Request & { + status?: number, + code?: string, + }): Promise<SimpleGetResponse> => { + const { path, accept, cookie, status, code } = param; + const res = await simpleGet(path, accept, cookie); + assert.notStrictEqual(res.status, 200); + if (status != null) { + assert.strictEqual(res.status, status); + } + if (code != null) { + assert.strictEqual(res.body.error.code, code); + } + return res; + }; + + const notFound = async (param: Request): Promise<SimpleGetResponse> => { + return await notOk({ + ...param, + status: 404, + }); + }; + + const metaTag = (res: SimpleGetResponse, key: string, superkey = 'name'): string => { + return res.body.window.document.querySelector('meta[' + superkey + '="' + key + '"]')?.content; + }; beforeAll(async () => { app = await startServer(); alice = await signup({ username: 'alice' }); + aliceUploadedFile = await uploadFile(alice); alicesPost = await post(alice, { text: 'test', }); + alicePage = await page(alice, {}); + alicePlay = await play(alice, {}); + aliceClip = await clip(alice, {}); + aliceGalleryPost = await galleryPost(alice, { + fileIds: [aliceUploadedFile.body.id], + }); + aliceChannel = await channel(alice, {}); }, 1000 * 60 * 2); afterAll(async () => { await app.close(); }); - describe('Common', () => { - test('meta', async () => { - const res = await api('/meta', { - }); + describe.each([ + { path: '/', type: HTML }, + { path: '/docs/ja-JP/about', type: HTML }, // "指定ã•ã‚ŒãŸURLã«è©²å½“ã™ã‚‹ãƒšãƒ¼ã‚¸ã¯ã‚ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚" + // fastify-static gives charset=UTF-8 instead of utf-8 and that's okay + { path: '/api-doc', type: 'text/html; charset=UTF-8' }, + { path: '/api.json', type: JSON_UTF8 }, + { path: '/api-console', type: HTML }, + { path: '/_info_card_', type: HTML }, + { path: '/bios', type: HTML }, + { path: '/cli', type: HTML }, + { path: '/flush', type: HTML }, + { path: '/robots.txt', type: 'text/plain; charset=UTF-8' }, + { path: '/favicon.ico', type: 'image/vnd.microsoft.icon' }, + { path: '/opensearch.xml', type: 'application/opensearchdescription+xml' }, + { path: '/apple-touch-icon.png', type: 'image/png' }, + { path: '/twemoji/2764.svg', type: 'image/svg+xml' }, + { path: '/twemoji/2764-fe0f-200d-1f525.svg', type: 'image/svg+xml' }, + { path: '/twemoji-badge/2764.png', type: 'image/png' }, + { path: '/twemoji-badge/2764-fe0f-200d-1f525.png', type: 'image/png' }, + { path: '/fluent-emoji/2764.png', type: 'image/png' }, + { path: '/fluent-emoji/2764-fe0f-200d-1f525.png', type: 'image/png' }, + ])('$path', (p) => { + test('ãŒGETã§ãる。', async () => await ok({ ...p })); + + // 注æ„: WebページãŒ200ã§å–å¾—ã§ãã¦ã‚‚ã€å®Ÿéš›ã®HTMLãŒæ£ã—ã表示ã§ãã‚‹ã¨ã¯é™ã‚‰ãªã„ + // 例ãˆã°ã€ /@xxx/pages/yyy ã«å˜åœ¨ã—ãªã„IDを渡ã—ãŸå ´åˆã€HTTPレスãƒãƒ³ã‚¹ã§ã¯ã‚¨ãƒ©ãƒ¼ã‚’区別ã§ããªã„ + // ã“ã†ã„ã£ãŸã‚¢ã‚µãƒ¼ã‚·ãƒ§ãƒ³ã¯ãƒ•ãƒãƒ³ãƒˆã‚¨ãƒ³ãƒ‰E2Eã‚„API Endpointã®ãƒ†ã‚¹ãƒˆã§æ‹…ä¿ã™ã‚‹ã€‚ + }); - assert.strictEqual(res.status, 200); - }); + describe.each([ + { path: '/twemoji/2764.png' }, + { path: '/twemoji/2764-fe0f-200d-1f525.png' }, + { path: '/twemoji-badge/2764.svg' }, + { path: '/twemoji-badge/2764-fe0f-200d-1f525.svg' }, + { path: '/fluent-emoji/2764.svg' }, + { path: '/fluent-emoji/2764-fe0f-200d-1f525.svg' }, + ])('$path', ({ path }) => { + test('ã¯GETã§ããªã„。', async () => await notFound({ path })); + }); - test('GET root', async () => { - const res = await simpleGet('/'); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, HTML); - }); + describe.each([ + { ext: 'rss', type: 'application/rss+xml; charset=utf-8' }, + { ext: 'atom', type: 'application/atom+xml; charset=utf-8' }, + { ext: 'json', type: 'application/json; charset=utf-8' }, + ])('/@:username.$ext', ({ ext, type }) => { + const path = (username: string): string => `/@${username}.${ext}`; + + test('ãŒGETã§ãる。', async () => await ok({ + path: path(alice.username), + type, + })); + + test('ã¯å˜åœ¨ã—ãªã„ユーザーã¯GETã§ããªã„。', async () => await notOk({ + path: path('nonexisting'), + status: 404, + })); + }); - test('GET docs', async () => { - const res = await simpleGet('/docs/ja-JP/about'); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, HTML); - }); + describe.each([{ path: '/api/foo' }])('$path', ({ path }) => { + test('ã¯GETã§ããªã„。', async () => await notOk({ + path, + status: 404, + code: 'UNKNOWN_API_ENDPOINT', + })); + }); - test('GET api-doc', async () => { - const res = await simpleGet('/api-doc'); - assert.strictEqual(res.status, 200); - // fastify-static gives charset=UTF-8 instead of utf-8 and that's okay - assert.strictEqual(res.type?.toLowerCase(), HTML); - }); + describe.each([{ path: '/queue' }])('$path', ({ path }) => { + test('ã¯adminã§ãªã‘ã‚Œã°GETã§ããªã„。', async () => await notOk({ + path, + status: 500, // FIXME? 403ã§ã¯ãªã„。 + })); + + test('ã¯adminãªã‚‰GETã§ãる。', async () => await ok({ + path, + cookie: cookie(alice), + })); + }); - test('GET api.json', async () => { - const res = await simpleGet('/api.json'); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, JSON_UTF8); - }); + describe.each([{ path: '/streaming' }])('$path', ({ path }) => { + test('ã¯GETã§ããªã„。', async () => await notOk({ + path, + status: 503, + })); + }); - test('GET api/foo (å˜åœ¨ã—ãªã„)', async () => { - const res = await simpleGet('/api/foo'); - assert.strictEqual(res.status, 404); - assert.strictEqual(res.body.error.code, 'UNKNOWN_API_ENDPOINT'); + describe('/@:username', () => { + const path = (username: string): string => `/@${username}`; + + describe.each([ + { accept: PREFER_HTML }, + { accept: UNSPECIFIED }, + ])('(Acceptヘッダ: $accept)', ({ accept }) => { + test('ã¯HTMLã¨ã—ã¦GETã§ãる。', async () => { + const res = await ok({ + path: path(alice.username), + accept, + type: HTML, + }); + assert.strictEqual(metaTag(res, 'misskey:user-username'), alice.username); + assert.strictEqual(metaTag(res, 'misskey:user-id'), alice.id); + + // TODO ogã‚¿ã‚°ã®æ¤œè¨¼ + // TODO profile.noCrawleã®æ¤œè¨¼ + // TODO twitter:creatorã®æ¤œè¨¼ + // TODO <link rel="me" ...>ã®æ¤œè¨¼ + }); + test('ã¯HTMLã¨ã—ã¦GETã§ãる。(å˜åœ¨ã—ãªã„IDã§ã‚‚。)', async () => await ok({ + path: path('xxxxxxxxxx'), + type: HTML, + })); }); - test('GET api-console (client page)', async () => { - const res = await simpleGet('/api-console'); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, HTML); + describe.each([ + { accept: ONLY_AP }, + { accept: PREFER_AP }, + ])('(Acceptヘッダ: $accept)', ({ accept }) => { + test('ã¯ActivityPubã¨ã—ã¦GETã§ãる。', async () => { + const res = await ok({ + path: path(alice.username), + accept, + type: AP, + }); + assert.strictEqual(res.body.type, 'Person'); + }); + + test('ã¯å˜åœ¨ã—ãªã„IDã®ã¨ãActivityPubã¨ã—ã¦GETã§ããªã„。', async () => await notFound({ + path: path('xxxxxxxxxx'), + accept, + })); }); + }); - test('GET favicon.ico', async () => { - const res = await simpleGet('/favicon.ico'); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, 'image/vnd.microsoft.icon'); + describe.each([ + // 実際ã®ãƒãƒ³ãƒ‰ãƒ«ã¯ãƒ•ãƒãƒ³ãƒˆã‚¨ãƒ³ãƒ‰(index.vue)ã§è¡Œã‚れる + { sub: 'home' }, + { sub: 'notes' }, + { sub: 'activity' }, + { sub: 'achievements' }, + { sub: 'reactions' }, + { sub: 'clips' }, + { sub: 'pages' }, + { sub: 'gallery' }, + ])('/@:username/$sub', ({ sub }) => { + const path = (username: string): string => `/@${username}/${sub}`; + + test('ã¯HTMLã¨ã—ã¦GETã§ãる。', async () => { + const res = await ok({ + path: path(alice.username), + }); + assert.strictEqual(metaTag(res, 'misskey:user-username'), alice.username); + assert.strictEqual(metaTag(res, 'misskey:user-id'), alice.id); }); + }); + + describe('/@:user/pages/:page', () => { + const path = (username: string, pagename: string): string => `/@${username}/pages/${pagename}`; - test('GET apple-touch-icon.png', async () => { - const res = await simpleGet('/apple-touch-icon.png'); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, 'image/png'); + test('ã¯HTMLã¨ã—ã¦GETã§ãる。', async () => { + const res = await ok({ + path: path(alice.username, alicePage.name), + }); + assert.strictEqual(metaTag(res, 'misskey:user-username'), alice.username); + assert.strictEqual(metaTag(res, 'misskey:user-id'), alice.id); + assert.strictEqual(metaTag(res, 'misskey:page-id'), alicePage.id); + + // TODO ogã‚¿ã‚°ã®æ¤œè¨¼ + // TODO profile.noCrawleã®æ¤œè¨¼ + // TODO twitter:creatorã®æ¤œè¨¼ }); + + test('ã¯GETã§ãる。(å˜åœ¨ã—ãªã„IDã§ã‚‚。)', async () => await ok({ + path: path(alice.username, 'xxxxxxxxxx'), + })); + }); - test('GET twemoji svg', async () => { - const res = await simpleGet('/twemoji/2764.svg'); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, 'image/svg+xml'); + describe('/users/:id', () => { + const path = (id: string): string => `/users/${id}`; + + describe.each([ + { accept: PREFER_HTML }, + { accept: UNSPECIFIED }, + ])('(Acceptヘッダ: $accept)', ({ accept }) => { + test('ã¯/@:usernameã«ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆã™ã‚‹', async () => { + const res = await simpleGet(path(alice.id), accept); + assert.strictEqual(res.status, 302); + assert.strictEqual(res.location, `/@${alice.username}`); + }); + + test('ã¯å˜åœ¨ã—ãªã„ユーザーã¯GETã§ããªã„。', async () => await notFound({ + path: path('xxxxxxxx'), + })); }); - test('GET twemoji svg with hyphen', async () => { - const res = await simpleGet('/twemoji/2764-fe0f-200d-1f525.svg'); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, 'image/svg+xml'); + describe.each([ + { accept: ONLY_AP }, + { accept: PREFER_AP }, + ])('(Acceptヘッダ: $accept)', ({ accept }) => { + test('ã¯ActivityPubã¨ã—ã¦GETã§ãる。', async () => { + const res = await ok({ + path: path(alice.id), + accept, + type: AP, + }); + assert.strictEqual(res.body.type, 'Person'); + }); + + test('ã¯å˜åœ¨ã—ãªã„IDã®ã¨ãActivityPubã¨ã—ã¦GETã§ããªã„。', async () => await notOk({ + path: path('xxxxxxxx'), + accept, + status: 404, + })); }); }); + + describe('/users/inbox', () => { + test('ãŒGETã§ãる。(POST専用ã ã‘ã©4xx/5xxã«ãªã‚‰ãšHTMLãŒè¿”ã£ã¦ãã‚‹)', async () => await ok({ + path: '/inbox', + })); - describe('/@:username', () => { - test('Only AP => AP', async () => { - const res = await simpleGet(`/@${alice.username}`, ONLY_AP); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, AP); - }); + // test.todo('POSTã§ãる?'); + }); - test('Prefer AP => AP', async () => { - const res = await simpleGet(`/@${alice.username}`, PREFER_AP); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, AP); - }); + describe('/users/:id/inbox', () => { + const path = (id: string): string => `/users/${id}/inbox`; - test('Prefer HTML => HTML', async () => { - const res = await simpleGet(`/@${alice.username}`, PREFER_HTML); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, HTML); - }); + test('ãŒGETã§ãる。(POST専用ã ã‘ã©4xx/5xxã«ãªã‚‰ãšHTMLãŒè¿”ã£ã¦ãã‚‹)', async () => await ok({ + path: path(alice.id), + })); - test('Unspecified => HTML', async () => { - const res = await simpleGet(`/@${alice.username}`, UNSPECIFIED); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, HTML); - }); + // test.todo('POSTã§ãる?'); }); - describe('/users/:id', () => { - test('Only AP => AP', async () => { - const res = await simpleGet(`/users/${alice.id}`, ONLY_AP); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, AP); - }); + describe('/users/:id/outbox', () => { + const path = (id: string): string => `/users/${id}/outbox`; - test('Prefer AP => AP', async () => { - const res = await simpleGet(`/users/${alice.id}`, PREFER_AP); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, AP); + test('ãŒGETã§ãる。', async () => { + const res = await ok({ + path: path(alice.id), + type: AP, + }); + assert.strictEqual(res.body.type, 'OrderedCollection'); }); + }); + + describe('/notes/:id', () => { + const path = (noteId: string): string => `/notes/${noteId}`; + + describe.each([ + { accept: PREFER_HTML }, + { accept: UNSPECIFIED }, + ])('(Acceptヘッダ: $accept)', ({ accept }) => { + test('ã¯HTMLã¨ã—ã¦GETã§ãる。', async () => { + const res = await ok({ + path: path(alicesPost.id), + accept, + type: HTML, + }); + assert.strictEqual(metaTag(res, 'misskey:user-username'), alice.username); + assert.strictEqual(metaTag(res, 'misskey:user-id'), alice.id); + assert.strictEqual(metaTag(res, 'misskey:note-id'), alicesPost.id); + + // TODO ogã‚¿ã‚°ã®æ¤œè¨¼ + // TODO profile.noCrawleã®æ¤œè¨¼ + // TODO twitter:creatorã®æ¤œè¨¼ + }); - test('Prefer HTML => Redirect to /@:username', async () => { - const res = await simpleGet(`/users/${alice.id}`, PREFER_HTML); - assert.strictEqual(res.status, 302); - assert.strictEqual(res.location, `/@${alice.username}`); + test('ã¯HTMLã¨ã—ã¦GETã§ãる。(å˜åœ¨ã—ãªã„IDã§ã‚‚。)', async () => await ok({ + path: path('xxxxxxxxxx'), + })); }); - test('Undecided => HTML', async () => { - const res = await simpleGet(`/users/${alice.id}`, UNSPECIFIED); - assert.strictEqual(res.status, 302); - assert.strictEqual(res.location, `/@${alice.username}`); + describe.each([ + { accept: ONLY_AP }, + { accept: PREFER_AP }, + ])('(Acceptヘッダ: $accept)', ({ accept }) => { + test('ã¯ActivityPubã¨ã—ã¦GETã§ãる。', async () => { + const res = await ok({ + path: path(alicesPost.id), + accept, + type: AP, + }); + assert.strictEqual(res.body.type, 'Note'); + }); + + test('ã¯å˜åœ¨ã—ãªã„IDã®ã¨ãActivityPubã¨ã—ã¦GETã§ããªã„。', async () => await notFound({ + path: path('xxxxxxxxxx'), + accept, + })); }); }); + + describe('/play/:id', () => { + const path = (playid: string): string => `/play/${playid}`; - describe('/notes/:id', () => { - test('Only AP => AP', async () => { - const res = await simpleGet(`/notes/${alicesPost.id}`, ONLY_AP); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, AP); + test('ãŒGETã§ãる。', async () => { + const res = await ok({ + path: path(alicePlay.id), + }); + assert.strictEqual(metaTag(res, 'misskey:user-username'), alice.username); + assert.strictEqual(metaTag(res, 'misskey:user-id'), alice.id); + assert.strictEqual(metaTag(res, 'misskey:flash-id'), alicePlay.id); + + // TODO ogã‚¿ã‚°ã®æ¤œè¨¼ + // TODO profile.noCrawleã®æ¤œè¨¼ + // TODO twitter:creatorã®æ¤œè¨¼ }); - test('Prefer AP => AP', async () => { - const res = await simpleGet(`/notes/${alicesPost.id}`, PREFER_AP); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, AP); - }); + test('ãŒGETã§ãる。(å˜åœ¨ã—ãªã„IDã§ã‚‚。)', async () => await ok({ + path: path('xxxxxxxxxx'), + })); + }); + + describe('/clips/:clip', () => { + const path = (clip: string): string => `/clips/${clip}`; - test('Prefer HTML => HTML', async () => { - const res = await simpleGet(`/notes/${alicesPost.id}`, PREFER_HTML); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, HTML); - }); + test('ãŒGETã§ãる。', async () => { + const res = await ok({ + path: path(aliceClip.id), + }); + assert.strictEqual(metaTag(res, 'misskey:user-username'), alice.username); + assert.strictEqual(metaTag(res, 'misskey:user-id'), alice.id); + assert.strictEqual(metaTag(res, 'misskey:clip-id'), aliceClip.id); - test('Unspecified => HTML', async () => { - const res = await simpleGet(`/notes/${alicesPost.id}`, UNSPECIFIED); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, HTML); + // TODO ogã‚¿ã‚°ã®æ¤œè¨¼ + // TODO profile.noCrawleã®æ¤œè¨¼ }); + + test('ãŒGETã§ãる。(å˜åœ¨ã—ãªã„IDã§ã‚‚。)', async () => await ok({ + path: path('xxxxxxxxxx'), + })); }); - describe('Feeds', () => { - test('RSS', async () => { - const res = await simpleGet(`/@${alice.username}.rss`, UNSPECIFIED); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, 'application/rss+xml; charset=utf-8'); - }); + describe('/gallery/:post', () => { + const path = (post: string): string => `/gallery/${post}`; + + test('ãŒGETã§ãる。', async () => { + const res = await ok({ + path: path(aliceGalleryPost.id), + }); + assert.strictEqual(metaTag(res, 'misskey:user-username'), alice.username); + assert.strictEqual(metaTag(res, 'misskey:user-id'), alice.id); - test('ATOM', async () => { - const res = await simpleGet(`/@${alice.username}.atom`, UNSPECIFIED); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, 'application/atom+xml; charset=utf-8'); + // FIXME: misskey:gallery-post-idã¿ãŸã„ãªmetaã‚¿ã‚°ã®è¨å®šãŒãªã„ + // TODO profile.noCrawleã®æ¤œè¨¼ + // TODO twitter:creatorã®æ¤œè¨¼ }); + + test('ãŒGETã§ãる。(å˜åœ¨ã—ãªã„IDã§ã‚‚。)', async () => await ok({ + path: path('xxxxxxxxxx'), + })); + }); + + describe('/channels/:channel', () => { + const path = (channel: string): string => `/channels/${channel}`; + + test('ã¯GETã§ãる。', async () => { + const res = await ok({ + path: path(aliceChannel.id), + }); - test('JSON', async () => { - const res = await simpleGet(`/@${alice.username}.json`, UNSPECIFIED); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.type, 'application/json; charset=utf-8'); + // FIXME: misskey関連ã®metaã‚¿ã‚°ã®è¨å®šãŒãªã„ + // TODO ogã‚¿ã‚°ã®æ¤œè¨¼ }); + + test('ãŒGETã§ãる。(å˜åœ¨ã—ãªã„IDã§ã‚‚。)', async () => await ok({ + path: path('xxxxxxxxxx'), + })); }); }); diff --git a/packages/backend/test/utils.ts b/packages/backend/test/utils.ts index d1a5d6d9497e40c048a15ff9b82a970291b50c5c..4d52c2f06284e4c2031bc78c3dde20c5d96990c3 100644 --- a/packages/backend/test/utils.ts +++ b/packages/backend/test/utils.ts @@ -3,6 +3,7 @@ import { isAbsolute, basename } from 'node:path'; import WebSocket from 'ws'; import fetch, { Blob, File, RequestInit } from 'node-fetch'; import { DataSource } from 'typeorm'; +import { JSDOM } from 'jsdom'; import { entities } from '../src/postgres.js'; import { loadConfig } from '../src/config.js'; import type * as misskey from 'misskey-js'; @@ -12,6 +13,10 @@ export { server as startServer } from '@/boot/common.js'; const config = loadConfig(); export const port = config.port; +export const cookie = (me: any): string => { + return `token=${me.token};`; +}; + export const api = async (endpoint: string, params: any, me?: any) => { const normalized = endpoint.replace(/^\//, ''); return await request(`api/${normalized}`, params, me); @@ -71,6 +76,71 @@ export const react = async (user: any, note: any, reaction: string): Promise<any }, user); }; +export const page = async (user: any, page: any = {}): Promise<any> => { + const res = await api('pages/create', { + alignCenter: false, + content: [ + { + id: '2be9a64b-5ada-43a3-85f3-ec3429551ded', + text: 'Hello World!', + type: 'text', + }, + ], + eyeCatchingImageId: null, + font: 'sans-serif', + hideTitleWhenPinned: false, + name: '1678594845072', + script: '', + summary: null, + title: '', + variables: [], + ...page, + }, user); + return res.body; +}; + +export const play = async (user: any, play: any = {}): Promise<any> => { + const res = await api('flash/create', { + permissions: [], + script: 'test', + summary: '', + title: 'test', + ...play, + }, user); + return res.body; +}; + +export const clip = async (user: any, clip: any = {}): Promise<any> => { + const res = await api('clips/create', { + description: null, + isPublic: true, + name: 'test', + ...clip, + }, user); + return res.body; +}; + +export const galleryPost = async (user: any, channel: any = {}): Promise<any> => { + const res = await api('gallery/posts/create', { + description: null, + fileIds: [], + isSensitive: false, + title: 'test', + ...channel, + }, user); + return res.body; +}; + +export const channel = async (user: any, channel: any = {}): Promise<any> => { + const res = await api('channels/create', { + bannerId: null, + description: null, + name: 'test', + ...channel, + }, user); + return res.body; +}; + interface UploadOptions { /** Optional, absolute path or relative from ./resources/ */ path?: string | URL; @@ -196,10 +266,17 @@ export const waitFire = async (user: any, channel: string, trgr: () => any, cond }); }; -export const simpleGet = async (path: string, accept = '*/*'): Promise<{ status: number, body: any, type: string | null, location: string | null }> => { +export type SimpleGetResponse = { + status: number, + body: any | JSDOM | null, + type: string | null, + location: string | null +}; +export const simpleGet = async (path: string, accept = '*/*', cookie: any = undefined): Promise<SimpleGetResponse> => { const res = await relativeFetch(path, { headers: { Accept: accept, + Cookie: cookie, }, redirect: 'manual', }); @@ -208,10 +285,14 @@ export const simpleGet = async (path: string, accept = '*/*'): Promise<{ status: 'application/json; charset=utf-8', 'application/activity+json; charset=utf-8', ]; + const htmlTypes = [ + 'text/html; charset=utf-8', + ]; - const body = jsonTypes.includes(res.headers.get('content-type') ?? '') - ? await res.json() - : null; + const body = + jsonTypes.includes(res.headers.get('content-type') ?? '') ? await res.json() : + htmlTypes.includes(res.headers.get('content-type') ?? '') ? new JSDOM(await res.text()) : + null; return { status: res.status,