diff --git a/.env.example b/.env.example index 989eb7b7c..f7a190317 100644 --- a/.env.example +++ b/.env.example @@ -105,6 +105,7 @@ MATTERS_PASSPHRASES_SECRET= MATTERS_SPAM_DETECTION_API_URL= MATTERS_SHORT_CONTENT_SPAM_DETECTION_API_URL= MATTERS_COMMENT_SPAM_DETECTION_API_URL= +MATTERS_MOMENT_SPAM_DETECTION_API_URL= MATTERS_COMMENT_SPAM_AUTO_COLLAPSE=false MATTERS_AWS_SPAM_SAMPLE_QUEUE_URL= MATTERS_SPAM_SAMPLE_HASH_SALT= diff --git a/AGENTS.md b/AGENTS.md index 4deb14ce8..e7d84c489 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,11 +1,59 @@ ---- -description: -globs: -alwaysApply: true ---- -You are an expect in Typescript, Graphql and Web development using express.js, and use best practices to write clean and maintainable code. - -- Obey documentations mentioned by [README.md](mdc:README.md). -- *Must* read [Database-Modification.md](mdc:docs/Database-Modification.md) first for any database schema migration (create or alter tables). -- Prefer using methods in services over adding new code. -- Add or update tests according to [Unittest.md](mdc:docs/Unittest.md) for each changes. \ No newline at end of file +## Basic +a. Never speculate. Investigate and confirm the facts before writing any code. +b. Related Matters repositories for reference are at https://github.com/orgs/thematters/repositories +c. If a requirement is ambiguous, or the existing architecture cannot solve the problem elegantly, ask the + developer first instead of modifying core low-level modules on your own. + + +## Development +a. TypeScript is the primary language. +b. Prefer arrow functions. Avoid TypeScript generic type parameters where a concrete type works. +c. Do not write an if-else on a single line. +d. Write comments in English and only on the important parts. Keep them short and clear; avoid over-commenting. +e. After every change, re-run lint and format to keep quality and style consistent. +f. After every change, add or update the relevant test cases and run the tests to make sure they pass. +g. Install non-essential packages as devDependencies, such as lint, format, build, test and tooling + packages like eslint and codecov; keep runtime dependencies minimal. + + +## Error handling +a. Always throw the named error classes defined in common/errors, such as ForbiddenError, UserNotFoundError, + EmailInvalidError. +b. Do not throw strings or a generic Error. Add a new class only when none fits, to keep error codes consistent. +c. When an error occurs, besides throwing from common/errors, log it with the logger. + + +## Data access +a. Do not write knex or raw SQL directly in a resolver; access data through the services in context.dataSources. +b. Load list fields via the matching DataLoader to avoid N+1; never query row by row inside a loop. +c. Wrap multi-write operations that need atomicity in an atomService transaction. + + +## Pagination +a. Return connection fields with connectionFromArray, connectionFromPromisedArray and cursorToIndex, + following the Relay cursor spec. +b. Annotate connection fields with @complexity(multipliers input.first) to bound query complexity and + avoid over-fetching. + + +## Constants and async +a. Use the constants in common/enums for roles, states and types, such as USER_ROLE, USER_STATE and + NODE_TYPES; do not use magic strings. +b. Offload heavy tasks such as sending email, on-chain calls and notifications to the queue; do not await + them synchronously inside a resolver. + + +## Security +a. Never hardcode passwords, API keys or any sensitive information in the code. + + +## Git +a. General feature development and fixes + a1. Branch off the develop branch and make changes on that branch. + a2. Before git push, sync with develop so conflicts are found and resolved first. + a3. When conflicts appear, do not revert on your own even if you are sure the revert is safe; ask the + developer first. +b. Hotfix + b1. If the change is based on the master branch, cherry-pick it onto the develop branch. +c. Commit message + c1. Follow Conventional Commits, such as feat:, fix: and docs:. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..43c994c2d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/codegen.json b/codegen.json index 15b60470d..59f534b4d 100644 --- a/codegen.json +++ b/codegen.json @@ -74,9 +74,14 @@ "Appreciation": "./appreciation.js#Appreciation", "OAuthClient": "./user.js#OAuthClientDB", "Report": "./report.js#Report", + "SpamRing": "./spamRing.js#SpamRing", + "SpamRingMember": "./spamRing.js#SpamRingMember", + "SpamRingEvent": "./spamRing.js#SpamRingEvent", + "SpamRingSignals": "./spamRing.js#SpamRingSignals", "IcymiTopic": "./misc.js#MattersChoiceTopic", "Moment": "./moment.js#Moment", "MomentFeedApplication": "./moment.js#MomentFeedUser", + "Quote": "./quote.js#Quote", "Writing": "./index.js#Writing", "Campaign": "./campaign.js#Campaign", "CampaignOSS": "./campaign.js#Campaign", diff --git a/db/migrations/20260611100000_create_quote_table.js b/db/migrations/20260611100000_create_quote_table.js new file mode 100644 index 000000000..0e0adc29b --- /dev/null +++ b/db/migrations/20260611100000_create_quote_table.js @@ -0,0 +1,34 @@ +import { baseDown } from '../utils.js' + +const table = 'quote' + +const indexName = `${table}_user_id_article_id_content_unique` + +export const up = async (knex) => { + await knex('entity_type').insert({ table }) + await knex.schema.createTable(table, (t) => { + t.bigIncrements('id').primary() + t.text('content').notNullable() + t.bigInteger('article_id').unsigned().notNullable() + t.bigInteger('campaign_id').unsigned().notNullable() + t.bigInteger('user_id').unsigned().notNullable() + t.enu('state', ['active', 'archived', 'banned']).notNullable() + t.timestamp('created_at').defaultTo(knex.fn.now()) + t.timestamp('updated_at').defaultTo(knex.fn.now()) + + t.foreign('article_id').references('id').inTable('article') + t.foreign('campaign_id').references('id').inTable('campaign') + t.foreign('user_id').references('id').inTable('user') + + t.index('campaign_id') + t.index('article_id') + t.index(['user_id', 'created_at']) + }) + + // create a partial unique index to dedupe active quotes + await knex.raw( + `CREATE UNIQUE INDEX ${indexName} ON ${table} ("user_id", "article_id", "content") WHERE state = 'active'` + ) +} + +export const down = baseDown(table) diff --git a/db/migrations/20260612000000_alter_comment_type_add_campaign_discussion.js b/db/migrations/20260612000000_alter_comment_type_add_campaign_discussion.js new file mode 100644 index 000000000..831c32bd7 --- /dev/null +++ b/db/migrations/20260612000000_alter_comment_type_add_campaign_discussion.js @@ -0,0 +1,26 @@ +import { alterEnumString } from '../utils.js' + +const table = 'comment' + +export const up = async (knex) => { + await knex.raw( + alterEnumString(table, 'type', [ + 'article', + 'circle_discussion', + 'circle_broadcast', + 'moment', + 'campaign_discussion', + ]) + ) +} + +export const down = async (knex) => { + await knex.raw( + alterEnumString(table, 'type', [ + 'article', + 'circle_discussion', + 'circle_broadcast', + 'moment', + ]) + ) +} diff --git a/db/migrations/20260617000000_alter_campaign_to_add_enable_quote_wall.js b/db/migrations/20260617000000_alter_campaign_to_add_enable_quote_wall.js new file mode 100644 index 000000000..c51137bca --- /dev/null +++ b/db/migrations/20260617000000_alter_campaign_to_add_enable_quote_wall.js @@ -0,0 +1,16 @@ +const table = 'campaign' + +export const up = async (knex) => { + await knex.schema.alterTable(table, (t) => { + // whether this campaign exposes a quote wall (post-to-wall affordance). + // opt-in: defaults to false; 七日書 campaigns are enabled via data backfill + // and, going forward, via the OSS campaign editor toggle. + t.boolean('enable_quote_wall').notNullable().defaultTo(false) + }) +} + +export const down = async (knex) => { + await knex.schema.alterTable(table, (t) => { + t.dropColumn('enable_quote_wall') + }) +} diff --git a/db/migrations/20260617000100_backfill_enable_quote_wall_seven_day_book.js b/db/migrations/20260617000100_backfill_enable_quote_wall_seven_day_book.js new file mode 100644 index 000000000..fe4007b04 --- /dev/null +++ b/db/migrations/20260617000100_backfill_enable_quote_wall_seven_day_book.js @@ -0,0 +1,17 @@ +const table = 'campaign' + +// One-time backfill: enable the quote wall for existing 七日書 campaigns. +// The name match is used here ONCE (at migration time) only; from now on the +// flag is data-driven (toggled in the OSS campaign editor), so renaming a +// campaign no longer affects quote-wall eligibility. +export const up = async (knex) => { + await knex(table).where('name', 'like', '%七日書%').update({ + enable_quote_wall: true, + }) +} + +export const down = async (knex) => { + await knex(table).where('name', 'like', '%七日書%').update({ + enable_quote_wall: false, + }) +} diff --git a/db/migrations/20260617000200_alter_campaign_enable_quote_wall_default_on.js b/db/migrations/20260617000200_alter_campaign_enable_quote_wall_default_on.js new file mode 100644 index 000000000..9e492c61e --- /dev/null +++ b/db/migrations/20260617000200_alter_campaign_enable_quote_wall_default_on.js @@ -0,0 +1,20 @@ +const table = 'campaign' + +// Interim decision: open the quote wall for every campaign by default, instead +// of the original 七日書-only opt-in. The per-campaign `enable_quote_wall` flag +// is kept (as a future hook for the OSS toggle / 七日書-only restriction); we +// only flip its default to true and enable it on all existing campaigns. +export const up = async (knex) => { + await knex.schema.alterTable(table, (t) => { + t.boolean('enable_quote_wall').notNullable().defaultTo(true).alter() + }) + await knex(table).update({ enable_quote_wall: true }) +} + +export const down = async (knex) => { + // revert the default; existing per-campaign values are left as-is (the prior + // mixed state cannot be reconstructed) + await knex.schema.alterTable(table, (t) => { + t.boolean('enable_quote_wall').notNullable().defaultTo(false).alter() + }) +} diff --git a/db/migrations/20260620000000_create_spam_ring_table.js b/db/migrations/20260620000000_create_spam_ring_table.js new file mode 100644 index 000000000..614a3180e --- /dev/null +++ b/db/migrations/20260620000000_create_spam_ring_table.js @@ -0,0 +1,41 @@ +const table = 'spam_ring' + +export const up = async (knex) => { + await knex('entity_type').insert({ table }) + + await knex.schema.createTable(table, (t) => { + t.bigIncrements('id').primary() + t.uuid('uuid').notNullable().unique() + // 模板/家族指紋:偵測 job 端的歸群 key,同一 ring 跨次匯入用它做 idempotent upsert + t.text('fingerprint').notNullable().unique() + t.enu('status', ['pending', 'frozen', 'dismissed', 'restored']) + .notNullable() + .defaultTo('pending') + // app 層訊號摘要(nearDupRingSize/entityRingSize/botUsernameRatio/topEntity/sampleCodes/sampleBrands/contentModelMax) + t.jsonb('signals').notNullable().defaultTo('{}') + t.integer('n_articles').notNullable().defaultTo(0) + t.integer('n_authors').notNullable().defaultTo(0) + t.decimal('new_account_ratio', 5, 4) + t.decimal('score', 8, 4) + t.enu('severity', ['low', 'medium', 'high', 'critical']) + t.timestamp('detected_at').notNullable().defaultTo(knex.fn.now()) + t.timestamp('first_seen_at') + t.timestamp('last_seen_at') + t.timestamp('frozen_at') + t.bigInteger('frozen_by').unsigned() + t.text('note') + t.timestamp('created_at').defaultTo(knex.fn.now()) + t.timestamp('updated_at').defaultTo(knex.fn.now()) + + t.foreign('frozen_by').references('id').inTable('user') + t.index(['status', 'score']) + t.index(['status', 'detected_at']) + t.index(['status', 'n_authors']) + t.index(['detected_at']) + }) +} + +export const down = async (knex) => { + await knex('entity_type').where({ table }).del() + await knex.schema.dropTable(table) +} diff --git a/db/migrations/20260620001000_create_spam_ring_member_table.js b/db/migrations/20260620001000_create_spam_ring_member_table.js new file mode 100644 index 000000000..9c7789457 --- /dev/null +++ b/db/migrations/20260620001000_create_spam_ring_member_table.js @@ -0,0 +1,34 @@ +const table = 'spam_ring_member' + +export const up = async (knex) => { + await knex('entity_type').insert({ table }) + + await knex.schema.createTable(table, (t) => { + t.bigIncrements('id').primary() + t.uuid('uuid').notNullable().unique() + t.bigInteger('ring_id').unsigned().notNullable() + t.bigInteger('user_id').unsigned().notNullable() + t.enu('status', ['pending', 'frozen', 'skipped', 'restored']) + .notNullable() + .defaultTo('pending') + // 可逆性關鍵:unfreeze 只解除「本 ring 凍結造成的」封禁,不動其他原因已封的帳號 + t.boolean('banned_by_this_ring').notNullable().defaultTo(false) + t.text('skip_reason') + // 凍結當下捕捉的帳號狀態(稽核/還原參考) + t.enu('pre_freeze_state', ['active', 'banned', 'archived', 'frozen']) + t.jsonb('evidence').notNullable().defaultTo('{}') + t.timestamp('created_at').defaultTo(knex.fn.now()) + t.timestamp('updated_at').defaultTo(knex.fn.now()) + + t.foreign('ring_id').references('id').inTable('spam_ring') + t.foreign('user_id').references('id').inTable('user') + t.unique(['ring_id', 'user_id']) + t.index(['ring_id', 'status']) + t.index(['user_id']) + }) +} + +export const down = async (knex) => { + await knex('entity_type').where({ table }).del() + await knex.schema.dropTable(table) +} diff --git a/db/migrations/20260620002000_create_spam_ring_event_table.js b/db/migrations/20260620002000_create_spam_ring_event_table.js new file mode 100644 index 000000000..824a74210 --- /dev/null +++ b/db/migrations/20260620002000_create_spam_ring_event_table.js @@ -0,0 +1,37 @@ +const table = 'spam_ring_event' + +export const up = async (knex) => { + await knex('entity_type').insert({ table }) + + await knex.schema.createTable(table, (t) => { + t.bigIncrements('id').primary() + t.uuid('uuid').notNullable().unique() + t.bigInteger('ring_id').unsigned().notNullable() + t.bigInteger('member_id').unsigned() + // nullable:機器偵測(detected)事件無管理員,actor_id 留空 + t.bigInteger('actor_id').unsigned() + t.enu('action', [ + 'detected', + 'frozen', + 'unfrozen', + 'dismissed', + 'member_banned', + 'member_skipped', + 'member_restored', + ]).notNullable() + t.jsonb('detail').notNullable().defaultTo('{}') + t.timestamp('created_at').defaultTo(knex.fn.now()) + + t.foreign('ring_id').references('id').inTable('spam_ring') + t.foreign('member_id').references('id').inTable('spam_ring_member') + t.foreign('actor_id').references('id').inTable('user') + t.index(['ring_id', 'created_at']) + t.index(['actor_id', 'created_at']) + t.index(['action', 'created_at']) + }) +} + +export const down = async (knex) => { + await knex('entity_type').where({ table }).del() + await knex.schema.dropTable(table) +} diff --git a/schema.graphql b/schema.graphql index 08d59966e..1deb3a3f3 100644 --- a/schema.graphql +++ b/schema.graphql @@ -277,6 +277,24 @@ type Mutation { """Archive multiple users from OSS with per-user results.""" archiveUsers(input: ArchiveUsersInput!): ArchiveUsersResult! + """ + Freeze a spam ring: permanently (but reversibly) ban all member accounts. OSS. + """ + freezeSpamRing(input: FreezeSpamRingInput!): FreezeSpamRingResult! + + """ + Reverse a spam ring freeze: unban only the members this ring banned. OSS. + """ + unfreezeSpamRing(input: UnfreezeSpamRingInput!): UnfreezeSpamRingResult! + + """Mark a spam ring as a false positive (feeds training as ham). OSS.""" + dismissSpamRing(input: DismissSpamRingInput!): SpamRing! + + """ + Upsert spam ring candidates from the detection job (admin service principal). OSS. + """ + upsertSpamRingCandidates(input: UpsertSpamRingCandidatesInput!): UpsertSpamRingCandidatesResult! + """Update state of a user, used in OSS.""" updateUserRole(input: UpdateUserRoleInput!): User! @@ -321,6 +339,14 @@ type Mutation { unlikeMoment(input: UnlikeMomentInput!): Moment! applyMomentFeed: User! updateMomentFeedApplicationState(input: UpdateMomentFeedApplicationStateInput!): User! + + """Post a quote (selected from an article) onto the campaign quote wall.""" + putQuote(input: PutQuoteInput!): Quote! + + """ + Retract a quote from the wall (poster, source article author, or admin). + """ + deleteQuote(input: DeleteQuoteInput!): Boolean! putTopicChannel(input: PutTopicChannelInput!): TopicChannel! putCurationChannel(input: PutCurationChannelInput!): CurationChannel! putTagChannel(input: PutTagChannelInput!): Tag! @@ -960,6 +986,9 @@ enum ArticlesSort { mostComments mostDonations mostReadTime + + """Order by spam score from high to low (only scored articles)""" + mostSpam } input CampaignInput { @@ -997,6 +1026,9 @@ input PutWritingChallengeInput { managers: [ID!] showOther: Boolean showAd: Boolean + + """enable the quote wall (post-to-wall) for this campaign""" + enableQuoteWall: Boolean } input ApplyCampaignInput { @@ -1073,13 +1105,28 @@ type WritingChallenge implements Node & Campaign & Channel { state: CampaignState! participants(input: CampaignParticipantsInput!): CampaignParticipantConnection! articles(input: CampaignArticlesInput!): CampaignArticleConnection! + + """Comments made by campaign participants (public to read).""" + discussion(input: CommentsInput!): CommentConnection! + + """Discussion (include replies) count of this campaign.""" + discussionCount: Int! application: CampaignApplication featuredDescription(input: TranslationArgs): String! organizers: [User!]! isManager: Boolean! showOther: Boolean! showAd: Boolean! + + """whether this campaign exposes a quote wall (post-to-wall affordance)""" + enableQuoteWall: Boolean! oss: CampaignOSS! + + """Quotes on this campaign's quote wall (public).""" + quotes(input: QuotesInput!): QuoteConnection! + + """Quote count of this campaign's quote wall.""" + quoteCount: Int! } type CampaignOSS { @@ -1724,6 +1771,7 @@ input CommentInput { articleId: ID circleId: ID momentId: ID + campaignId: ID } input CommentCommentsInput { @@ -1914,6 +1962,7 @@ enum CommentType { circleDiscussion circleBroadcast moment + campaignDiscussion } """ @@ -2415,8 +2464,8 @@ type TranslatedAnnouncement { type OSS { users(input: ConnectionArgs!): UserConnection! - comments(input: ConnectionArgs!): CommentConnection! - moments(input: ConnectionArgs!): MomentConnection! + comments(input: OSSCommentsInput!): CommentConnection! + moments(input: OSSMomentsInput!): MomentConnection! articles(input: OSSArticlesInput!): ArticleConnection! tags(input: TagsInput!): TagConnection! oauthClients(input: ConnectionArgs!): OAuthClientConnection! @@ -2425,6 +2474,7 @@ type OSS { badgedUsers(input: BadgedUsersInput!): UserConnection! restrictedUsers(input: ConnectionArgs!): UserConnection! reports(input: OSSReportsInput!): ReportConnection! + spamRings(input: OSSSpamRingsInput!): SpamRingConnection! icymiTopics(input: ConnectionArgs!): IcymiTopicConnection! topicChannelFeedbacks(input: TopicChannelFeedbacksInput!): TopicChannelFeedbackConnection! momentFeedUsers(input: MomentFeedUsersInput!): UserConnection! @@ -2546,6 +2596,138 @@ input OSSReportsFilter { source: ReportSource } +""" +A spam ring: a cluster of accounts posting the same templated abuse, +surfaced by the account-layer ring detector (軸一 D). +""" +type SpamRing implements Node { + id: ID! + + """模板/家族指紋(偵測 job 的歸群 key)""" + fingerprint: String! + status: SpamRingStatus! + signals: SpamRingSignals! + nArticles: Int! + nAuthors: Int! + newAccountRatio: Float + score: Float + severity: SpamRingSeverity + detectedAt: DateTime! + firstSeenAt: DateTime + lastSeenAt: DateTime + frozenAt: DateTime + frozenBy: User + note: String + + """群內成員帳號(可分頁)""" + members(input: ConnectionArgs!): SpamRingMemberConnection! + + """列表渲染用的少量樣本,免分頁""" + memberSample(limit: Int): [User!]! + events: [SpamRingEvent!]! +} + +type SpamRingSignals { + nearDupRingSize: Int + entityRingSize: Int + botUsernameRatio: Float + topEntity: String + sampleCodes: [String!] + sampleBrands: [String!] + contentModelMax: Float +} + +type SpamRingMember { + id: ID! + user: User! + status: SpamRingMemberStatus! + + """是否由本 ring 的凍結造成封禁(解凍時只還原此類)""" + bannedByThisRing: Boolean! + skipReason: String + createdAt: DateTime! +} + +type SpamRingEvent { + id: ID! + action: SpamRingEventAction! + actor: User + + """JSON 字串""" + detail: String + createdAt: DateTime! +} + +enum SpamRingStatus { + pending + frozen + dismissed + restored +} + +enum SpamRingMemberStatus { + pending + frozen + skipped + restored +} + +enum SpamRingSeverity { + low + medium + high + critical +} + +enum SpamRingEventAction { + detected + frozen + unfrozen + dismissed + member_banned + member_skipped + member_restored +} + +type SpamRingConnection implements Connection { + totalCount: Int! + pageInfo: PageInfo! + edges: [SpamRingEdge!] +} + +type SpamRingEdge { + cursor: String! + node: SpamRing! +} + +type SpamRingMemberConnection implements Connection { + totalCount: Int! + pageInfo: PageInfo! + edges: [SpamRingMemberEdge!] +} + +type SpamRingMemberEdge { + cursor: String! + node: SpamRingMember! +} + +enum SpamRingsSort { + score + detectedAt + nAuthors +} + +input OSSSpamRingsInput { + after: String + first: Int + sort: SpamRingsSort = score + filter: OSSSpamRingsFilter +} + +input OSSSpamRingsFilter { + status: SpamRingStatus +} + input NodeInput { id: ID! } @@ -3006,6 +3188,32 @@ input OSSArticlesFilterInput { searchKey: String } +"""Sort options shared by OSS comment/moment lists for spam triage.""" +enum OSSContentSpamSort { + newest + + """Order by spam score from high to low (only scored items)""" + mostSpam +} + +input OSSSpamDatetimeFilterInput { + datetimeRange: DatetimeRangeInput +} + +input OSSCommentsInput { + after: String + first: Int + sort: OSSContentSpamSort = newest + filter: OSSSpamDatetimeFilterInput +} + +input OSSMomentsInput { + after: String + first: Int + sort: OSSContentSpamSort = newest + filter: OSSSpamDatetimeFilterInput +} + enum CacheControlScope { PUBLIC PRIVATE @@ -3612,6 +3820,81 @@ type ArchiveUserFailure { message: String! } +input FreezeSpamRingInput { + id: ID! + remark: String +} + +type FreezeSpamRingResult { + ring: SpamRing! + frozen: [User!]! + + """ + Members not banned (old account, high karma, already banned, archived…) — for manual review. + """ + skipped: [SpamRingSkip!]! +} + +input UnfreezeSpamRingInput { + id: ID! +} + +type UnfreezeSpamRingResult { + ring: SpamRing! + unbanned: [User!]! + skipped: [SpamRingSkip!]! +} + +type SpamRingSkip { + user: User! + reason: String! +} + +input DismissSpamRingInput { + id: ID! + note: String +} + +input UpsertSpamRingCandidatesInput { + candidates: [SpamRingCandidateInput!]! +} + +input SpamRingCandidateInput { + fingerprint: String! + + """Raw DB user ids (the detection job reads them from the replica).""" + memberUserIds: [String!] + memberUserNames: [String!] + signals: SpamRingSignalsInput! + nArticles: Int! + nAuthors: Int! + newAccountRatio: Float + score: Float + severity: SpamRingSeverity + firstSeenAt: DateTime + lastSeenAt: DateTime + + """JSON string: map of user id -> evidence.""" + memberEvidence: String +} + +input SpamRingSignalsInput { + nearDupRingSize: Int + entityRingSize: Int + botUsernameRatio: Float + topEntity: String + sampleCodes: [String!] + sampleBrands: [String!] + contentModelMax: Float +} + +type UpsertSpamRingCandidatesResult { + created: Int! + updated: Int! + skipped: Int! + rings: [SpamRing!]! +} + input UpdateUserRoleInput { id: ID! role: UserRole! @@ -3855,6 +4138,11 @@ input SocialLoginInput { """used in register""" language: UserLanguage referralCode: String + + """ + Google OIDC redirect_uri for OSS SSO. When set, must be allowlisted; login is restricted to existing admin accounts and no new account is created. + """ + redirectUri: String } input Oauth1CredentialInput { @@ -4443,6 +4731,46 @@ enum MomentFeedUserReviewedBy { seed } +input PutQuoteInput { + articleId: ID! + content: String! +} + +input DeleteQuoteInput { + id: ID! +} + +input QuotesInput { + first: Int + after: String + + """ + random sampling for wall display; refetch to shuffle. when true, after is ignored + """ + random: Boolean +} + +type Quote { + id: ID! + content: String! + article: Article! + + """the user who posted this quote onto the wall""" + poster: User! + createdAt: DateTime! +} + +type QuoteConnection implements Connection { + totalCount: Int! + pageInfo: PageInfo! + edges: [QuoteEdge!] +} + +type QuoteEdge { + cursor: String! + node: Quote! +} + interface Channel { id: ID! shortHash: String! diff --git a/src/common/enums/index.ts b/src/common/enums/index.ts index d2ea1a554..3999a6724 100644 --- a/src/common/enums/index.ts +++ b/src/common/enums/index.ts @@ -29,6 +29,7 @@ export * from './appreciation.js' export * from './metrics.js' export * from './badges.js' export * from './moment.js' +export * from './quote.js' export * from './campaign.js' export * from './channel.js' export * from './feedback.js' @@ -60,6 +61,7 @@ export const COMMENT_TYPE = { circleDiscussion: 'circle_discussion', circleBroadcast: 'circle_broadcast', moment: 'moment', + campaignDiscussion: 'campaign_discussion', } as const export const COMMENT_TYPES_REVERSED = Object.fromEntries( @@ -168,6 +170,7 @@ export enum NODE_TYPES { Collection = 'Collection', Report = 'Report', Moment = 'Moment', + Quote = 'Quote', Campaign = 'Campaign', CampaignStage = 'CampaignStage', TopicChannel = 'TopicChannel', @@ -181,6 +184,9 @@ export enum NODE_TYPES { Announcement = 'Announcement', CryptoWallet = 'CryptoWallet', CryptoWalletNFTAsset = 'NFTAsset', + SpamRing = 'SpamRing', + SpamRingMember = 'SpamRingMember', + SpamRingEvent = 'SpamRingEvent', // Unions & Interfaces Node = 'Node', @@ -251,6 +257,9 @@ export const MAX_ARTICLE_CONTENT_REVISION_LENGTH = 50 export const MAX_ARTICLE_COMMENT_LENGTH = 1200 +// campaign discussion comment length cap (matches moment / 短動態 = 240) +export const MAX_CAMPAIGN_COMMENT_LENGTH = 240 + export const MAX_PINNED_WORKS_LIMIT = 3 export const LATEST_WORKS_NUM = 4 diff --git a/src/common/enums/quote.ts b/src/common/enums/quote.ts new file mode 100644 index 000000000..f1734a20c --- /dev/null +++ b/src/common/enums/quote.ts @@ -0,0 +1,12 @@ +export const QUOTE_STATE = { + active: 'active', + archived: 'archived', + banned: 'banned', +} as const + +// a quote is a "one-glance" excerpt; longer text is a paragraph, not a quote +export const MAX_QUOTE_LENGTH = 80 + +// anti-abuse caps (product-decided defaults, tunable) +export const QUOTE_DAILY_LIMIT = 5 +export const QUOTE_PER_ARTICLE_LIMIT = 2 diff --git a/src/common/enums/user.ts b/src/common/enums/user.ts index b7d1a33ca..9e19c5549 100644 --- a/src/common/enums/user.ts +++ b/src/common/enums/user.ts @@ -8,6 +8,7 @@ export const USER_STATE = { export const USER_BAN_REMARK = { payoutReversedByAdmin: 'payout reversed by admin', paymentHighRisk: 'payment high risk', + spamRing: 'spam ring', } as const export const AUTHOR_TYPE = { diff --git a/src/common/environment.ts b/src/common/environment.ts index fbc14c4a4..59af45655 100644 --- a/src/common/environment.ts +++ b/src/common/environment.ts @@ -177,6 +177,14 @@ export const environment = { googleClientId: process.env.MATTERS_GOOGLE_CLIENT_ID || '', googleClientSecret: process.env.MATTERS_GOOGLE_CLIENT_SECRET || '', googleRedirectUri: process.env.MATTERS_GOOGLE_REDIRECT_URI || '', + // Allowlisted redirect_uri values for OSS Google SSO (comma-separated), e.g. + // "https://oss.matters.icu/callback/google,https://oss.matters.town/callback/google". + // Reuses the same Google OAuth client; the OSS callback URIs must also be + // registered on that client in Google Cloud Console. + ossGoogleRedirectUris: (process.env.MATTERS_OSS_GOOGLE_REDIRECT_URIS || '') + .split(',') + .map((uri) => uri.trim()) + .filter(Boolean), threadsClientId: process.env.MATTERS_THREADS_CLIENT_ID || '', threadsClientSecret: process.env.MATTERS_THREADS_CLIENT_SECRET || '', threadsRedirectUri: process.env.MATTERS_THREADS_REDIRECT_URI || '', @@ -189,6 +197,11 @@ export const environment = { process.env.MATTERS_SHORT_CONTENT_SPAM_DETECTION_API_URL || '', commentSpamDetectionApiUrl: process.env.MATTERS_COMMENT_SPAM_DETECTION_API_URL || '', + // Dedicated moment spam model (label-fix retrain; fixes the shared short-content + // model's ~90% false-kill on Chinese moments). Falls back to the short-content + // model when unset, so this is a zero-downtime opt-in via env. + momentSpamDetectionApiUrl: + process.env.MATTERS_MOMENT_SPAM_DETECTION_API_URL || '', // When true, a comment whose spam score reaches the system spam threshold is // auto-collapsed (folded but still expandable in-thread — "不刪除,只是不再被 // 看見"). Default off so scoring stays observe-only until ops opts in. @@ -273,7 +286,7 @@ export const environment = { 10 ), hottestMomentsDecayDays: parseInt( - process.env.MATTERS_HOTTEST_MOMENTS_DECAY_DAYS || '5', + process.env.MATTERS_HOTTEST_MOMENTS_DECAY_DAYS || '1', 10 ), hottestMomentsLikeWeight: parseFloat( diff --git a/src/common/utils/__test__/spamRingMigration.test.ts b/src/common/utils/__test__/spamRingMigration.test.ts new file mode 100644 index 000000000..9ca3a4c3a --- /dev/null +++ b/src/common/utils/__test__/spamRingMigration.test.ts @@ -0,0 +1,160 @@ +import { pathToFileURL } from 'url' + +type Migration = { + up: (knex: any) => Promise + down: (knex: any) => Promise +} + +const migrationUrl = (file: string) => + pathToFileURL(`${process.cwd()}/db/migrations/${file}`).href + +const createTableBuilder = (calls: string[]) => { + const builder: any = new Proxy( + {}, + { + get: (_, prop: string) => { + if (prop === 'foreign') { + return (column: string) => { + calls.push(`foreign:${column}`) + return builder + } + } + if (['references', 'inTable', 'notNullable', 'unique'].includes(prop)) { + return () => builder + } + return (...args: any[]) => { + calls.push(`${prop}:${args[0] ?? ''}`) + return builder + } + }, + } + ) + return builder +} + +const createKnex = () => { + const entityTypeInserts: Array> = [] + const entityTypeDeletes: Array> = [] + const tableCalls: string[] = [] + const droppedTables: string[] = [] + + const knex: any = (_table: string) => ({ + insert: async (data: Record) => { + entityTypeInserts.push(data) + }, + where: (query: Record) => ({ + del: async () => { + entityTypeDeletes.push(query) + }, + }), + }) + + knex.fn = { now: () => new Date('2026-06-20T00:00:00.000Z') } + knex.schema = { + createTable: async (table: string, callback: (b: any) => void) => { + tableCalls.push(`create:${table}`) + callback(createTableBuilder(tableCalls)) + }, + dropTable: async (table: string) => { + droppedTables.push(table) + }, + } + + return { knex, entityTypeInserts, entityTypeDeletes, tableCalls, droppedTables } +} + +describe('spam ring migrations', () => { + test('spam_ring: creates table, registers entity_type, key columns + indexes', async () => { + const { up } = (await import( + migrationUrl('20260620000000_create_spam_ring_table.js') + )) as Migration + const { knex, entityTypeInserts, tableCalls } = createKnex() + + await up(knex) + + expect(entityTypeInserts).toEqual([{ table: 'spam_ring' }]) + expect(tableCalls).toEqual( + expect.arrayContaining([ + 'create:spam_ring', + 'bigIncrements:id', + 'uuid:uuid', + 'text:fingerprint', + 'enu:status', + 'jsonb:signals', + 'integer:n_articles', + 'integer:n_authors', + 'decimal:new_account_ratio', + 'decimal:score', + 'enu:severity', + 'timestamp:detected_at', + 'bigInteger:frozen_by', + 'foreign:frozen_by', + 'index:status,score', + ]) + ) + }) + + test('spam_ring_member: includes banned_by_this_ring + unique(ring,user)', async () => { + const { up } = (await import( + migrationUrl('20260620001000_create_spam_ring_member_table.js') + )) as Migration + const { knex, entityTypeInserts, tableCalls } = createKnex() + + await up(knex) + + expect(entityTypeInserts).toEqual([{ table: 'spam_ring_member' }]) + expect(tableCalls).toEqual( + expect.arrayContaining([ + 'create:spam_ring_member', + 'bigInteger:ring_id', + 'bigInteger:user_id', + 'enu:status', + 'boolean:banned_by_this_ring', + 'enu:pre_freeze_state', + 'jsonb:evidence', + 'foreign:ring_id', + 'foreign:user_id', + 'index:ring_id,status', + ]) + ) + }) + + test('spam_ring_event: audit table with action enum + actor/member fks', async () => { + const { up } = (await import( + migrationUrl('20260620002000_create_spam_ring_event_table.js') + )) as Migration + const { knex, entityTypeInserts, tableCalls } = createKnex() + + await up(knex) + + expect(entityTypeInserts).toEqual([{ table: 'spam_ring_event' }]) + expect(tableCalls).toEqual( + expect.arrayContaining([ + 'create:spam_ring_event', + 'bigInteger:ring_id', + 'bigInteger:member_id', + 'bigInteger:actor_id', + 'enu:action', + 'jsonb:detail', + 'foreign:ring_id', + 'foreign:member_id', + 'foreign:actor_id', + 'index:ring_id,created_at', + ]) + ) + }) + + test('rollback drops tables and removes entity_type rows', async () => { + for (const file of [ + '20260620000000_create_spam_ring_table.js', + '20260620001000_create_spam_ring_member_table.js', + '20260620002000_create_spam_ring_event_table.js', + ]) { + const { down } = (await import(migrationUrl(file))) as Migration + const { knex, entityTypeDeletes, droppedTables } = createKnex() + await down(knex) + expect(entityTypeDeletes.length).toBe(1) + expect(droppedTables.length).toBe(1) + } + }) +}) diff --git a/src/common/utils/__test__/spamRingResolvers.test.ts b/src/common/utils/__test__/spamRingResolvers.test.ts new file mode 100644 index 000000000..97647eeff --- /dev/null +++ b/src/common/utils/__test__/spamRingResolvers.test.ts @@ -0,0 +1,337 @@ +import { jest } from '@jest/globals' + +import { NODE_TYPES } from '#common/enums/index.js' +import { toGlobalId } from '#common/utils/index.js' +import dismissSpamRing from '#mutations/user/dismissSpamRing.js' +import freezeSpamRing from '#mutations/user/freezeSpamRing.js' +import unfreezeSpamRing from '#mutations/user/unfreezeSpamRing.js' +import upsertSpamRingCandidates from '#mutations/user/upsertSpamRingCandidates.js' + +const connectionFromQuery = jest.fn(async () => ({ + edges: [], + totalCount: 0, + pageInfo: { + startCursor: '', + endCursor: '', + hasPreviousPage: false, + hasNextPage: false, + }, +})) + +jest.unstable_mockModule('#common/utils/connections.js', () => ({ + connectionFromQuery, +})) + +const { spamRings } = await import('#queries/system/oss/spamRings.js') +const { SpamRing, SpamRingMember, SpamRingEvent } = await import( + '#queries/system/spamRing/index.js' +) + +const ringGlobalId = (id: string) => + toGlobalId({ type: NODE_TYPES.SpamRing, id }) + +const makeContext = (viewer: any = { id: '9' }) => { + const userService = { __sentinel: 'userService' } + return { + viewer, + dataSources: { + userService, + spamRingService: { + freezeRing: jest.fn(async () => ({ ring: {}, frozen: [], skipped: [] })), + unfreezeRing: jest.fn(async () => ({ ring: {}, unbanned: [], skipped: [] })), + dismissRing: jest.fn(async () => ({ id: '1' })), + upsertCandidates: jest.fn(async () => ({ + created: 1, + updated: 0, + skipped: 0, + rings: [], + })), + }, + }, + } as any +} + +describe('spam ring mutation resolvers', () => { + beforeEach(() => { + connectionFromQuery.mockClear() + }) + + test('freezeSpamRing decodes global id and forwards viewer + userService', async () => { + const ctx = makeContext() + await (freezeSpamRing as any)( + null, + { input: { id: ringGlobalId('1'), remark: 'r' } }, + ctx + ) + expect(ctx.dataSources.spamRingService.freezeRing).toHaveBeenCalledWith({ + ringId: '1', + actorId: '9', + remark: 'r', + userService: ctx.dataSources.userService, + }) + }) + + test('unfreezeSpamRing forwards ringId + userService', async () => { + const ctx = makeContext() + await (unfreezeSpamRing as any)( + null, + { input: { id: ringGlobalId('7') } }, + ctx + ) + expect(ctx.dataSources.spamRingService.unfreezeRing).toHaveBeenCalledWith({ + ringId: '7', + actorId: '9', + userService: ctx.dataSources.userService, + }) + }) + + test('dismissSpamRing forwards note', async () => { + const ctx = makeContext() + await (dismissSpamRing as any)( + null, + { input: { id: ringGlobalId('3'), note: 'fp' } }, + ctx + ) + expect(ctx.dataSources.spamRingService.dismissRing).toHaveBeenCalledWith({ + ringId: '3', + actorId: '9', + note: 'fp', + }) + }) + + test('freezeSpamRing rejects when viewer has no id', async () => { + await expect( + (freezeSpamRing as any)( + null, + { input: { id: ringGlobalId('1') } }, + makeContext({}) + ) + ).rejects.toThrow('viewer has no id') + }) + + test('unfreezeSpamRing rejects when viewer has no id', async () => { + await expect( + (unfreezeSpamRing as any)( + null, + { input: { id: ringGlobalId('1') } }, + makeContext({}) + ) + ).rejects.toThrow('viewer has no id') + }) + + test('dismissSpamRing rejects when viewer has no id', async () => { + await expect( + (dismissSpamRing as any)( + null, + { input: { id: ringGlobalId('1') } }, + makeContext({}) + ) + ).rejects.toThrow('viewer has no id') + }) + + test('upsertSpamRingCandidates parses evidence JSON and coerces nulls', async () => { + const ctx = makeContext() + await (upsertSpamRingCandidates as any)( + null, + { + input: { + candidates: [ + { + fingerprint: 'fp1', + memberUserIds: ['u1', 'u2'], + memberUserNames: null, + signals: { nearDupRingSize: 2 }, + nArticles: 5, + nAuthors: 2, + newAccountRatio: null, + score: 0.9, + severity: null, + firstSeenAt: null, + lastSeenAt: null, + memberEvidence: JSON.stringify({ u1: { a: 1 } }), + }, + ], + }, + }, + ctx + ) + const arg = ( + ctx.dataSources.spamRingService.upsertCandidates as any + ).mock.calls[0][0] + expect(arg[0].fingerprint).toBe('fp1') + expect(arg[0].memberUserIds).toEqual(['u1', 'u2']) + expect(arg[0].memberUserNames).toBeUndefined() + expect(arg[0].newAccountRatio).toBeUndefined() + expect(arg[0].memberEvidence).toEqual({ u1: { a: 1 } }) + }) +}) + +describe('spam ring query resolvers', () => { + beforeEach(() => { + connectionFromQuery.mockClear() + }) + + test('oss.spamRings forwards status filter and nAuthors sorting', async () => { + const query = { __query: 'spam-ring-query' } + const ctx = { + dataSources: { + spamRingService: { + findRings: jest.fn(() => query), + }, + }, + } as any + const input = { + first: 20, + sort: 'nAuthors', + filter: { status: 'pending' }, + } + + await (spamRings as any)(null, { input }, ctx) + + expect(ctx.dataSources.spamRingService.findRings).toHaveBeenCalledWith({ + status: 'pending', + }) + expect(connectionFromQuery).toHaveBeenCalledWith({ + query, + args: input, + orderBy: { column: 'nAuthors', order: 'desc' }, + }) + }) + + test('oss.spamRings defaults to score sorting and no status filter', async () => { + const query = { __query: 'score-query' } + const ctx = { + dataSources: { + spamRingService: { + findRings: jest.fn(() => query), + }, + }, + } as any + + await (spamRings as any)(null, { input: { first: 10 } }, ctx) + + expect(ctx.dataSources.spamRingService.findRings).toHaveBeenCalledWith({ + status: undefined, + }) + expect(connectionFromQuery).toHaveBeenCalledWith({ + query, + args: { first: 10 }, + orderBy: { column: 'score', order: 'desc' }, + }) + }) + + test('oss.spamRings supports detectedAt sorting', async () => { + const query = { __query: 'detected-query' } + const ctx = { + dataSources: { + spamRingService: { + findRings: jest.fn(() => query), + }, + }, + } as any + + await (spamRings as any)(null, { input: { sort: 'detectedAt' } }, ctx) + + expect(connectionFromQuery).toHaveBeenCalledWith({ + query, + args: { sort: 'detectedAt' }, + orderBy: { column: 'detectedAt', order: 'desc' }, + }) + }) +}) + +describe('SpamRing type resolvers', () => { + test('resolves ids, frozenBy, members, samples, and events', async () => { + const frozenBy = { id: 'u9' } + const sampleUser = { id: 'u1' } + const members = [ + { id: 'm1', userId: 'u1' }, + { id: 'm2', userId: 'missing' }, + ] + const events = [{ id: 'e1', ringId: 'r1' }] + const ctx = { + dataSources: { + atomService: { + userIdLoader: { + load: jest.fn(async (id: string) => { + if (id === 'u9') return frozenBy + if (id === 'u1') return sampleUser + return null + }), + }, + }, + spamRingService: { + findMembersAndCount: jest.fn(async () => [members, 2]), + findMembers: jest.fn(async () => members), + findEvents: jest.fn(async () => events), + }, + }, + } as any + + expect((SpamRing.id as any)({ id: 'r1' })).toBe(ringGlobalId('r1')) + await expect( + (SpamRing.frozenBy as any)({ frozenBy: 'u9' }, null, ctx) + ).resolves.toBe(frozenBy) + expect((SpamRing.frozenBy as any)({ frozenBy: null }, null, ctx)).toBeNull() + + const memberConnection = await (SpamRing.members as any)( + { id: 'r1' }, + { input: { first: 1 } }, + ctx + ) + expect(ctx.dataSources.spamRingService.findMembersAndCount).toHaveBeenCalledWith( + 'r1', + { take: 1, skip: 0 } + ) + expect(memberConnection.totalCount).toBe(2) + expect(memberConnection.edges.map((edge: any) => edge.node.id)).toEqual([ + 'm1', + 'm2', + ]) + + await expect( + (SpamRing.memberSample as any)({ id: 'r1' }, { limit: 3 }, ctx) + ).resolves.toEqual([sampleUser]) + expect(ctx.dataSources.spamRingService.findMembers).toHaveBeenCalledWith( + 'r1', + 3 + ) + + await expect( + (SpamRing.events as any)({ id: 'r1' }, null, ctx) + ).resolves.toBe(events) + }) + + test('resolves member and event fields', async () => { + const actor = { id: 'u9' } + const user = { id: 'u1' } + const ctx = { + dataSources: { + atomService: { + userIdLoader: { + load: jest.fn(async (id: string) => (id === 'u9' ? actor : user)), + }, + }, + }, + } as any + + expect((SpamRingMember.id as any)({ id: 'm1' })).toBe( + toGlobalId({ type: NODE_TYPES.SpamRingMember, id: 'm1' }) + ) + await expect( + (SpamRingMember.user as any)({ userId: 'u1' }, null, ctx) + ).resolves.toBe(user) + + expect((SpamRingEvent.id as any)({ id: 'e1' })).toBe( + toGlobalId({ type: NODE_TYPES.SpamRingEvent, id: 'e1' }) + ) + await expect( + (SpamRingEvent.actor as any)({ actorId: 'u9' }, null, ctx) + ).resolves.toBe(actor) + expect((SpamRingEvent.actor as any)({ actorId: null }, null, ctx)).toBeNull() + expect((SpamRingEvent.detail as any)({ detail: { reason: 'fp' } })).toBe( + JSON.stringify({ reason: 'fp' }) + ) + expect((SpamRingEvent.detail as any)({ detail: null })).toBeNull() + }) +}) diff --git a/src/connectors/__test__/commentService.test.ts b/src/connectors/__test__/commentService.test.ts index 7fc228319..0ef2a3d33 100644 --- a/src/connectors/__test__/commentService.test.ts +++ b/src/connectors/__test__/commentService.test.ts @@ -940,6 +940,8 @@ describe('spam telegram alert (notify-only tiering)', () => { reason: 'spam_auto', dedupeKey: `comment:${comment.id}`, }) + // carries an OSS deep-link for one-click moderation + expect(sent[0].ossUrl).toContain('/comments?id=') }) test('emits Tier C (spam_review) for high-score benign-looking content', async () => { diff --git a/src/connectors/__test__/spamRingService.test.ts b/src/connectors/__test__/spamRingService.test.ts new file mode 100644 index 000000000..0e060b501 --- /dev/null +++ b/src/connectors/__test__/spamRingService.test.ts @@ -0,0 +1,445 @@ +import { jest } from '@jest/globals' + +import { USER_STATE, USER_BAN_REMARK } from '#common/enums/index.js' +import { SpamRingService } from '#connectors/spamRingService.js' + +const DAY = 86400000 + +// mock knex builder:chainable + thenable,依 table 回傳設定好的資料並記錄變更 +const makeConnections = ({ + ring, + members = [], +}: { + ring: any + members?: any[] +}) => { + const rec = { + memberUpdates: [] as any[], + ringUpdates: [] as any[], + eventInserts: [] as any[], + } + const builder = (table: string) => { + const ctx: any = { table, where: {} } + const b: any = { + where: (w: any) => { + Object.assign(ctx.where, w) + return b + }, + orderBy: () => b, + modify: (fn?: any) => { + if (fn) fn(b) + return b + }, + count: () => b, + clone: () => b, + offset: () => b, + limit: () => b, + first: async () => { + if (ctx.table === 'spam_ring') return ring + return undefined + }, + update: (data: any) => { + if (ctx.table === 'spam_ring_member') { + rec.memberUpdates.push({ where: { ...ctx.where }, data }) + } + if (ctx.table === 'spam_ring') { + rec.ringUpdates.push(data) + } + return { + returning: async () => [{ ...ring, ...data }], + then: (resolve: any) => resolve(1), + } + }, + insert: async (rows: any) => { + if (ctx.table === 'spam_ring_event') { + rec.eventInserts.push(...(Array.isArray(rows) ? rows : [rows])) + } + }, + // awaiting the builder directly (findMembers): resolve member rows + then: (resolve: any) => + resolve(ctx.table === 'spam_ring_member' ? members : []), + } + return b + } + const knex = (t: string) => builder(t) + const connections: any = { + knex, + knexRO: knex, + knexSearch: knex, + redis: {}, + objectCacheRedis: {}, + } + return { connections, rec } +} + +const makeUserService = (users: Record) => ({ + banUser: jest.fn(async (id: string) => ({ ...users[id], state: USER_STATE.banned })), + unbanUser: jest.fn(async (id: string) => ({ ...users[id], state: USER_STATE.active })), + findScore: jest.fn(async (_id: string) => 0), +}) + +const makeService = (connections: any, users: Record) => { + const service = new SpamRingService(connections) + ;(service as any).models = { + userIdLoader: { load: async (id: string) => users[id] ?? null }, + } + return service +} + +describe('SpamRingService.freezeRing', () => { + test('bans eligible members, skips old / already-banned, freezes ring', async () => { + const ring = { id: '1', status: 'pending' } + const members = [ + { id: 'm1', userId: 'u1', status: 'pending', bannedByThisRing: false }, + { id: 'm2', userId: 'u2', status: 'pending', bannedByThisRing: false }, + { id: 'm3', userId: 'u3', status: 'pending', bannedByThisRing: false }, + ] + const users: Record = { + u1: { id: 'u1', state: USER_STATE.active, createdAt: new Date(Date.now() - DAY) }, + u2: { id: 'u2', state: USER_STATE.active, createdAt: new Date(Date.now() - 100 * DAY) }, + u3: { id: 'u3', state: USER_STATE.banned, createdAt: new Date(Date.now() - DAY) }, + } + const { connections, rec } = makeConnections({ ring, members }) + const service = makeService(connections, users) + const userService = makeUserService(users) + + const result = await service.freezeRing({ + ringId: '1', + actorId: '9', + userService: userService as any, + }) + + // only u1 banned (u2 old account, u3 already banned) + expect(userService.banUser).toHaveBeenCalledTimes(1) + expect(userService.banUser).toHaveBeenCalledWith('u1', { + remark: USER_BAN_REMARK.spamRing, + }) + expect(result.frozen.map((u: any) => u.id)).toEqual(['u1']) + expect(result.skipped.map((s: any) => s.user.id).sort()).toEqual(['u2', 'u3']) + const u2skip = result.skipped.find((s: any) => s.user.id === 'u2') + expect(u2skip?.reason).toMatch(/old account/) + // ring marked frozen + expect(rec.ringUpdates.at(-1)).toMatchObject({ status: 'frozen', frozenBy: '9' }) + // events include the member ban + ring frozen + a skip + const actions = rec.eventInserts.map((e) => e.action) + expect(actions).toEqual( + expect.arrayContaining(['member_banned', 'member_skipped', 'frozen']) + ) + }) + + test('refuses to freeze a dismissed ring', async () => { + const { connections } = makeConnections({ ring: { id: '1', status: 'dismissed' } }) + const service = makeService(connections, {}) + await expect( + service.freezeRing({ ringId: '1', actorId: '9', userService: makeUserService({}) as any }) + ).rejects.toThrow('dismissed') + }) +}) + +describe('SpamRingService.unfreezeRing', () => { + test('unbans only members this ring banned; leaves others; restores ring', async () => { + const ring = { id: '1', status: 'frozen' } + const members = [ + { id: 'm1', userId: 'u1', status: 'frozen', bannedByThisRing: true }, + { id: 'm2', userId: 'u2', status: 'skipped', bannedByThisRing: false }, + { id: 'm3', userId: 'u3', status: 'frozen', bannedByThisRing: true }, + ] + const users: Record = { + u1: { id: 'u1', state: USER_STATE.banned }, + u2: { id: 'u2', state: USER_STATE.banned }, // banned by something else + u3: { id: 'u3', state: USER_STATE.archived }, // state changed since freeze + } + const { connections } = makeConnections({ ring, members }) + const service = makeService(connections, users) + const userService = makeUserService(users) + + const result = await service.unfreezeRing({ + ringId: '1', + actorId: '9', + userService: userService as any, + }) + + // only u1 unbanned (u2 not banned-by-this-ring → untouched; u3 archived → skipped) + expect(userService.unbanUser).toHaveBeenCalledTimes(1) + expect(userService.unbanUser).toHaveBeenCalledWith('u1', USER_STATE.active) + expect(result.unbanned.map((u: any) => u.id)).toEqual(['u1']) + expect(result.skipped.map((s: any) => s.user.id)).toEqual(['u3']) + }) + + test('refuses to unfreeze a ring that is not frozen', async () => { + const { connections } = makeConnections({ ring: { id: '1', status: 'pending' } }) + const service = makeService(connections, {}) + await expect( + service.unfreezeRing({ ringId: '1', actorId: '9', userService: makeUserService({}) as any }) + ).rejects.toThrow('not frozen') + }) +}) + +describe('SpamRingService.dismissRing', () => { + test('marks ring dismissed and writes an event', async () => { + const { connections, rec } = makeConnections({ ring: { id: '1', status: 'pending' } }) + const service = makeService(connections, {}) + await service.dismissRing({ ringId: '1', actorId: '9', note: 'false positive' }) + expect(rec.ringUpdates.at(-1)).toMatchObject({ status: 'dismissed', note: 'false positive' }) + expect(rec.eventInserts.map((e) => e.action)).toContain('dismissed') + }) +}) + +const makeImportConnections = ({ + rings = [], + members = [], + users = [], +}: { + rings?: any[] + members?: any[] + users?: any[] +}) => { + const rec = { + whereCalls: [] as any[], + offsets: [] as number[], + limits: [] as number[], + orderByCalls: [] as any[], + ringInserts: [] as any[], + ringUpdates: [] as any[], + memberInserts: [] as any[], + eventInserts: [] as any[], + whereInCalls: [] as any[], + } + + const rowsFor = (table: string, where: Record) => { + if (table === 'spam_ring') { + return rings.filter((r) => + Object.entries(where).every(([key, value]) => r[key] === value) + ) + } + if (table === 'spam_ring_member') { + return members.filter((m) => + Object.entries(where).every(([key, value]) => m[key] === value) + ) + } + return [] + } + + const builder = (table: string) => { + const ctx: any = { table, where: {}, whereIn: null, offset: undefined, limit: undefined } + const b: any = { + where: (w: any) => { + Object.assign(ctx.where, w) + rec.whereCalls.push({ table, where: { ...w } }) + return b + }, + whereIn: (column: string, values: any[]) => { + ctx.whereIn = { column, values } + rec.whereInCalls.push({ table, column, values }) + return b + }, + select: () => b, + orderBy: (...args: any[]) => { + rec.orderByCalls.push({ table, args }) + return b + }, + modify: (fn?: any) => { + if (fn) fn(b) + return b + }, + count: () => { + ctx.count = true + return b + }, + first: async () => { + if (ctx.count) { + return { count: String(rowsFor(table, ctx.where).length) } + } + return rowsFor(table, ctx.where)[0] + }, + offset: (value: number) => { + ctx.offset = value + rec.offsets.push(value) + return b + }, + limit: (value: number) => { + ctx.limit = value + rec.limits.push(value) + return b + }, + insert: (rows: any) => { + const inserted = Array.isArray(rows) ? rows : [rows] + if (table === 'spam_ring') { + const created = inserted.map((row, index) => ({ + id: row.id ?? String(rings.length + index + 1), + ...row, + })) + rings.push(...created) + rec.ringInserts.push(...created) + return { returning: async () => created } + } + if (table === 'spam_ring_member') { + members.push(...inserted) + rec.memberInserts.push(...inserted) + } + if (table === 'spam_ring_event') { + rec.eventInserts.push(...inserted) + } + return b + }, + update: (data: any) => { + if (table === 'spam_ring') { + const ring = rowsFor(table, ctx.where)[0] + Object.assign(ring, data) + rec.ringUpdates.push({ where: { ...ctx.where }, data }) + return { returning: async () => [ring] } + } + return { returning: async () => [] } + }, + then: (resolve: any) => { + if (table === 'user' && ctx.whereIn) { + return resolve( + users.filter((u) => ctx.whereIn.values.includes(u[ctx.whereIn.column])) + ) + } + const rows = rowsFor(table, ctx.where) + const start = ctx.offset ?? 0 + const end = ctx.limit === undefined ? undefined : start + ctx.limit + return resolve(rows.slice(start, end)) + }, + } + return b + } + + const knex = (table: string) => builder(table) + return { + connections: { + knex, + knexRO: knex, + knexSearch: knex, + redis: {}, + objectCacheRedis: {}, + } as any, + rec, + rings, + members, + } +} + +describe('SpamRingService query helpers', () => { + test('findRings and member queries apply filters and pagination', async () => { + const { connections, rec } = makeImportConnections({ + rings: [{ id: 'r1', status: 'pending' }], + members: [ + { id: 'm1', ringId: 'r1', userId: 'u1' }, + { id: 'm2', ringId: 'r1', userId: 'u2' }, + ], + }) + const service = new SpamRingService(connections) + + await (service.findRings({ status: 'pending' }) as any) + await service.findMembersAndCount('r1', { take: 1, skip: 1 }) + await service.findMembers('r1', 5) + await service.findEvents('r1') + + expect(rec.whereCalls).toEqual( + expect.arrayContaining([ + { table: 'spam_ring', where: { status: 'pending' } }, + { table: 'spam_ring_member', where: { ringId: 'r1' } }, + { table: 'spam_ring_event', where: { ringId: 'r1' } }, + ]) + ) + expect(rec.offsets).toContain(1) + expect(rec.limits).toEqual(expect.arrayContaining([1, 5])) + expect(rec.orderByCalls).toEqual( + expect.arrayContaining([ + { table: 'spam_ring_member', args: ['id', 'asc'] }, + { table: 'spam_ring_event', args: ['createdAt', 'desc'] }, + ]) + ) + }) +}) + +describe('SpamRingService.upsertCandidates', () => { + test('creates a new ring, resolves unique ids, inserts new members and event', async () => { + const { connections, rec, members } = makeImportConnections({ + users: [ + { id: 'u1', userName: 'alice' }, + { id: 'u2', userName: 'bob' }, + ], + }) + const service = new SpamRingService(connections) + + const result = await service.upsertCandidates([ + { + fingerprint: 'fp-new', + memberUserIds: ['u1', 'u1', 'u2'], + signals: { nearDupRingSize: 2 }, + nArticles: 3, + nAuthors: 2, + score: 0.91, + memberEvidence: { u1: { articleIds: ['a1'] } }, + }, + ]) + + expect(result.created).toBe(1) + expect(result.updated).toBe(0) + expect(rec.ringInserts[0]).toMatchObject({ + fingerprint: 'fp-new', + status: 'pending', + nArticles: 3, + nAuthors: 2, + score: 0.91, + }) + expect(members.map((m) => m.userId)).toEqual(['u1', 'u2']) + expect(rec.memberInserts[0].evidence).toBe( + JSON.stringify({ articleIds: ['a1'] }) + ) + expect(rec.eventInserts.map((e) => e.action)).toContain('detected') + }) + + test('updates pending rings, resolves usernames, and skips locked decisions', async () => { + const { connections, rec, members } = makeImportConnections({ + rings: [ + { id: 'r1', fingerprint: 'fp-existing', status: 'pending' }, + { id: 'r2', fingerprint: 'fp-frozen', status: 'frozen' }, + ], + members: [{ id: 'm1', ringId: 'r1', userId: 'u1' }], + users: [ + { id: 'u1', userName: 'alice' }, + { id: 'u3', userName: 'charlie' }, + ], + }) + const service = new SpamRingService(connections) + + const result = await service.upsertCandidates([ + { + fingerprint: 'fp-existing', + memberUserNames: ['alice', 'charlie', 'charlie'], + signals: { topEntity: 'brand:test' }, + nArticles: 8, + nAuthors: 2, + newAccountRatio: 0.5, + }, + { + fingerprint: 'fp-frozen', + memberUserIds: ['u9'], + }, + ]) + + expect(result.created).toBe(0) + expect(result.updated).toBe(1) + expect(result.skipped).toBe(1) + expect(rec.ringUpdates[0]).toMatchObject({ + where: { id: 'r1' }, + data: { + signals: JSON.stringify({ topEntity: 'brand:test' }), + nArticles: 8, + nAuthors: 2, + newAccountRatio: 0.5, + }, + }) + expect(rec.whereInCalls[0]).toMatchObject({ + table: 'user', + column: 'userName', + values: ['alice', 'charlie', 'charlie'], + }) + expect(members.map((m) => m.userId).sort()).toEqual(['u1', 'u3']) + expect(rec.memberInserts).toHaveLength(1) + }) +}) diff --git a/src/connectors/__test__/userService.test.ts b/src/connectors/__test__/userService.test.ts index 28a0ee2e9..3d5ee4bb4 100644 --- a/src/connectors/__test__/userService.test.ts +++ b/src/connectors/__test__/userService.test.ts @@ -1,5 +1,10 @@ import type { Connections } from '#definitions/index.js' +import { jest } from '@jest/globals' +import axios from 'axios' +import jwt from 'jsonwebtoken' + +import { environment } from '#common/environment.js' import { CACHE_PREFIX, APPRECIATION_PURPOSE, @@ -1225,3 +1230,40 @@ describe('addBookmarkCountColumn', () => { expect(article3Result.bookmarkCount).toBe('0') }) }) + +describe('fetchGoogleUserInfo', () => { + test('exchanges the code with the given redirectUri (OSS SSO)', async () => { + const nonce = 'test-nonce' + const redirectUri = 'https://oss.matters.icu/callback/google' + const idToken = jwt.sign( + { + aud: environment.googleClientId, + nonce, + sub: 'google-sub-1', + email: 'oss-sso@gmail.com', + email_verified: true, + }, + 'test-secret' + ) + const spy = jest + // eslint-disable-next-line @typescript-eslint/no-explicit-any + .spyOn(axios as any, 'post') + // eslint-disable-next-line @typescript-eslint/no-explicit-any + .mockResolvedValueOnce({ data: { id_token: idToken } } as any) + + const info = await userService.fetchGoogleUserInfo( + 'auth-code', + nonce, + redirectUri + ) + + expect(info.email).toBe('oss-sso@gmail.com') + expect(info.emailVerified).toBe(true) + expect(spy).toHaveBeenCalledWith( + 'https://oauth2.googleapis.com/token', + expect.objectContaining({ redirect_uri: redirectUri }), + expect.anything() + ) + spy.mockRestore() + }) +}) diff --git a/src/connectors/atomService.ts b/src/connectors/atomService.ts index 4510cb027..cfd38c025 100644 --- a/src/connectors/atomService.ts +++ b/src/connectors/atomService.ts @@ -647,6 +647,7 @@ const UPATEABLE_TABLES = [ 'collection', 'matters_choice_topic', 'moment', + 'quote', 'moment_asset', 'moment_article', 'moment_tag', diff --git a/src/connectors/campaignService.ts b/src/connectors/campaignService.ts index 34fed97c2..31e3fea9e 100644 --- a/src/connectors/campaignService.ts +++ b/src/connectors/campaignService.ts @@ -70,6 +70,7 @@ export class CampaignService { exclusive, showOther, showAd, + enableQuoteWall, }: { name: string description?: string @@ -85,6 +86,7 @@ export class CampaignService { exclusive?: boolean showOther?: boolean showAd?: boolean + enableQuoteWall?: boolean }) => this.models.create({ table: 'campaign', @@ -109,6 +111,7 @@ export class CampaignService { exclusive: exclusive ?? false, showOther, showAd, + enableQuoteWall, }, }) @@ -226,6 +229,12 @@ export class CampaignService { where: { userId, campaignId }, }) + // whether the user has successfully applied to (i.e. participates in) the campaign + public isParticipant = async (campaignId: string, userId: string) => { + const application = await this.getApplication(campaignId, userId) + return application?.state === CAMPAIGN_USER_STATE.succeeded + } + public findAndCountAll = async ( { skip, take }: { skip: number; take: number }, { diff --git a/src/connectors/commentService.ts b/src/connectors/commentService.ts index 9b2c069eb..2287666ff 100644 --- a/src/connectors/commentService.ts +++ b/src/connectors/commentService.ts @@ -1,5 +1,6 @@ import type { Article, + Campaign, Circle, Comment, CommunityWatchAction, @@ -22,6 +23,7 @@ import { USER_ACTION, USER_FEATURE_FLAG_TYPE, NOTICE_TYPE, + NODE_TYPES, } from '#common/enums/index.js' import { environment } from '#common/environment.js' import { @@ -31,9 +33,11 @@ import { UserInputError, } from '#common/errors.js' import { enqueueReportAlert } from '#common/notifications/reportAlert.js' +import { toGlobalId } from '#common/utils/index.js' import { v4 } from 'uuid' import { BaseService } from './baseService.js' +import { CampaignService } from './campaignService.js' import { classifyContentTier, nearDuplicate, @@ -89,6 +93,9 @@ export class CommentService extends BaseService { super('comment', connections) } + // Query builder for the OSS comment list (sortable / filterable). + public findComments = () => this.knexRO(this.table).select('*') + public findActiveCommunityWatchAction = async ( commentId: string ): Promise => { @@ -656,25 +663,31 @@ export class CommentService extends BaseService { // check target let article: Article let circle: Circle | undefined = undefined - let targetAuthorId: string + let campaign: Campaign | undefined = undefined + let targetAuthorId: string | undefined if (comment.type === COMMENT_TYPE.article) { article = await this.models.articleIdLoader.load(comment.targetId) targetAuthorId = article.authorId } else if (comment.type === COMMENT_TYPE.moment) { const moment = await this.models.momentIdLoader.load(comment.targetId) targetAuthorId = moment.authorId + } else if (comment.type === COMMENT_TYPE.campaignDiscussion) { + // campaign discussion has no single target author + campaign = await this.models.campaignIdLoader.load(comment.targetId) } else { circle = await this.models.circleIdLoader.load(comment.targetId) targetAuthorId = circle.owner } - const userService = new UserService(this.connections) - const isBlocked = await userService.blocked({ - userId: targetAuthorId, - targetId: user.id, - }) - if (isBlocked) { - throw new ForbiddenError('blocked user has no permission') + if (targetAuthorId) { + const userService = new UserService(this.connections) + const isBlocked = await userService.blocked({ + userId: targetAuthorId, + targetId: user.id, + }) + if (isBlocked) { + throw new ForbiddenError('blocked user has no permission') + } } // check permission @@ -692,6 +705,24 @@ export class CommentService extends BaseService { } } + if (campaign) { + const campaignService = new CampaignService(this.connections) + const isParticipant = await campaignService.isParticipant( + campaign.id, + user.id + ) + const isOrganizer = + campaign.creatorId === user.id || + (campaign.organizerIds ?? []).includes(user.id) || + (campaign.managerIds ?? []).includes(user.id) + + if (!isParticipant && !isOrganizer) { + throw new ForbiddenError( + 'only campaign participants have the permission' + ) + } + } + // check is voted before const voted = await this.findVotesByUserId({ userId: user.id, @@ -1008,6 +1039,7 @@ export class CommentService extends BaseService { const author = await this.models.userIdLoader.load(comment.authorId) const snippet = stripHtml(content).slice(0, 80) + const globalId = toGlobalId({ type: NODE_TYPES.Comment, id }) await enqueueReportAlert({ source: 'spam_detection', dedupeKey: `comment:${id}`, @@ -1015,6 +1047,9 @@ export class CommentService extends BaseService { 2 )}):${snippet}`, reason: TIER_REASON[tier], + ossUrl: `${environment.ossSiteDomain}/comments?id=${encodeURIComponent( + globalId + )}`, }) } diff --git a/src/connectors/index.ts b/src/connectors/index.ts index 25599a575..0bcc1a467 100644 --- a/src/connectors/index.ts +++ b/src/connectors/index.ts @@ -40,3 +40,4 @@ export * from './dailySummaryEmailService.js' export * from './badgeService.js' export * from './archiveUserService.js' export * from './ga4Service.js' +export * from './spamRingService.js' diff --git a/src/connectors/momentService.ts b/src/connectors/momentService.ts index 7ef20aa4d..2186e7e54 100644 --- a/src/connectors/momentService.ts +++ b/src/connectors/momentService.ts @@ -461,8 +461,11 @@ export class MomentService { id: string content: string }) => { + // Prefer the dedicated moment model; fall back to the shared short-content + // model when MATTERS_MOMENT_SPAM_DETECTION_API_URL is unset (zero-downtime). const detector = new SpamDetector( - environment.shortContentSpamDetectionApiUrl + environment.momentSpamDetectionApiUrl || + environment.shortContentSpamDetectionApiUrl ) const score = await detector.detect(content) diff --git a/src/connectors/spamRingService.ts b/src/connectors/spamRingService.ts new file mode 100644 index 000000000..fce4a857b --- /dev/null +++ b/src/connectors/spamRingService.ts @@ -0,0 +1,495 @@ +import type { + Connections, + SpamRing, + SpamRingMember, + SpamRingEvent, + SpamRingSignals, + SpamRingStatus, + SpamRingSeverity, + SpamRingEventAction, + User, +} from '#definitions/index.js' +import type { UserService } from './userService.js' +import type { Knex } from 'knex' + +import { USER_STATE, USER_BAN_REMARK } from '#common/enums/index.js' +import { UserInputError } from '#common/errors.js' +import { v4 } from 'uuid' + +import { BaseService } from './baseService.js' + +// 老帳號豁免護欄(roadmap 軸一 D 硬性):超過任一門檻的帳號不自動凍結,改列人工複查。 +// 模組級常數,便於與信任安全負責人統一調參。 +export const SPAM_RING_GUARDRAIL_MAX_AGE_DAYS = 30 +export const SPAM_RING_GUARDRAIL_MAX_SCORE = 5 + +const DAY_MS = 86400000 + +export interface SpamRingCandidate { + fingerprint: string + // 內部合約:偵測 job(讀 replica)直接帶原始 DB user id;亦可改帶 userName 由 server 解析 + memberUserIds?: string[] | null + memberUserNames?: string[] | null + signals?: SpamRingSignals | null + nArticles?: number | null + nAuthors?: number | null + newAccountRatio?: number | null + score?: number | null + severity?: SpamRingSeverity | null + firstSeenAt?: Date | string | null + lastSeenAt?: Date | string | null + memberEvidence?: Record | null +} + +interface RingEventInput { + ringId: string + memberId?: string | null + actorId?: string | null + action: SpamRingEventAction + detail?: Record +} + +export class SpamRingService extends BaseService { + public constructor(connections: Connections) { + super('spam_ring', connections) + } + + // --- 查詢 --- + public findRings = ({ + status, + }: { + status?: SpamRingStatus + }): Knex.QueryBuilder => { + const query = this.knexRO('spam_ring') + if (status) { + query.where({ status }) + } + return query + } + + public findRingById = (id: string): Promise => + this.knexRO('spam_ring').where({ id }).first() + + public findRingByFingerprint = ( + fingerprint: string + ): Promise => + this.knexRO('spam_ring').where({ fingerprint }).first() + + public findMembersAndCount = async ( + ringId: string, + { take, skip }: { take?: number; skip?: number } = {} + ): Promise<[SpamRingMember[], number]> => { + const countResult = await this.knexRO('spam_ring_member') + .where({ ringId }) + .count() + .first() + const totalCount = parseInt((countResult?.count as string) || '0', 10) + const members = await this.knexRO('spam_ring_member') + .where({ ringId }) + .orderBy('id', 'asc') + .modify((b: Knex.QueryBuilder) => { + if (skip !== undefined && Number.isFinite(skip)) { + b.offset(skip) + } + if (take !== undefined && Number.isFinite(take)) { + b.limit(take) + } + }) + return [members, totalCount] + } + + public findMembers = ( + ringId: string, + limit?: number + ): Promise => { + const query = this.knexRO('spam_ring_member') + .where({ ringId }) + .orderBy('id', 'asc') + if (limit !== undefined) { + query.limit(limit) + } + return query + } + + public findEvents = (ringId: string): Promise => + this.knexRO('spam_ring_event') + .where({ ringId }) + .orderBy('createdAt', 'desc') + + // --- 偵測 job 匯入(idempotent;不覆寫已凍結/已駁回的決策)--- + public upsertCandidates = async ( + candidates: SpamRingCandidate[] + ): Promise<{ + created: number + updated: number + skipped: number + rings: SpamRing[] + }> => { + let created = 0 + let updated = 0 + let skipped = 0 + const rings: SpamRing[] = [] + + for (const c of candidates) { + const existing = await this.findRingByFingerprint(c.fingerprint) + if ( + existing && + (existing.status === 'frozen' || existing.status === 'dismissed') + ) { + // 決策已鎖定,不動 + skipped += 1 + rings.push(existing) + continue + } + + const now = new Date() + let ring: SpamRing + if (existing) { + ;[ring] = await this.knex('spam_ring') + .where({ id: existing.id }) + .update({ + signals: JSON.stringify(c.signals ?? {}), + nArticles: c.nArticles ?? 0, + nAuthors: c.nAuthors ?? 0, + newAccountRatio: c.newAccountRatio ?? null, + score: c.score ?? null, + severity: c.severity ?? null, + firstSeenAt: c.firstSeenAt ?? null, + lastSeenAt: c.lastSeenAt ?? null, + detectedAt: now, + updatedAt: now, + }) + .returning('*') + updated += 1 + } else { + ;[ring] = await this.knex('spam_ring') + .insert({ + uuid: v4(), + fingerprint: c.fingerprint, + status: 'pending', + signals: JSON.stringify(c.signals ?? {}), + nArticles: c.nArticles ?? 0, + nAuthors: c.nAuthors ?? 0, + newAccountRatio: c.newAccountRatio ?? null, + score: c.score ?? null, + severity: c.severity ?? null, + detectedAt: now, + firstSeenAt: c.firstSeenAt ?? null, + lastSeenAt: c.lastSeenAt ?? null, + }) + .returning('*') + created += 1 + await this.insertEvents([ + { + ringId: ring.id, + action: 'detected', + detail: { source: 'job', nAuthors: c.nAuthors ?? 0 }, + }, + ]) + } + + const userIds = await this.resolveMemberIds(c) + await this.upsertMembers(ring.id, userIds, c.memberEvidence ?? null) + rings.push(ring) + } + + return { created, updated, skipped, rings } + } + + // --- 一鍵凍結(永久但可逆的封禁)--- + public freezeRing = async ({ + ringId, + actorId, + remark, + userService, + }: { + ringId: string + actorId: string + remark?: string | null + userService: UserService + }): Promise<{ + ring: SpamRing + frozen: User[] + skipped: Array<{ user: User; reason: string }> + }> => { + const ring = await this.findRingById(ringId) + if (!ring) { + throw new UserInputError('spam ring not found') + } + if (ring.status === 'dismissed') { + throw new UserInputError('cannot freeze a dismissed ring') + } + + const members = await this.findMembers(ringId) + const frozen: User[] = [] + const skipped: Array<{ user: User; reason: string }> = [] + + for (const member of members) { + const user = (await this.models.userIdLoader.load( + member.userId + )) as User | null + + if (!user) { + await this.updateMember(member.id, { + status: 'skipped', + skipReason: 'user not found', + }) + continue + } + // 本 ring 已凍結過此人 → idempotent,略過 + if (member.status === 'frozen' && member.bannedByThisRing) { + frozen.push(user) + continue + } + if (user.state === USER_STATE.archived) { + await this.skipMember(member.id, user, 'archived', actorId, ringId) + skipped.push({ user, reason: 'archived' }) + continue + } + if (user.state === USER_STATE.banned) { + await this.skipMember(member.id, user, 'already banned', actorId, ringId) + skipped.push({ user, reason: 'already banned' }) + continue + } + + // 老帳號 / 高 karma 豁免(硬性護欄) + const ageDays = (Date.now() - new Date(user.createdAt).getTime()) / DAY_MS + const score = await userService.findScore(user.id) + if ( + ageDays > SPAM_RING_GUARDRAIL_MAX_AGE_DAYS || + score > SPAM_RING_GUARDRAIL_MAX_SCORE + ) { + const reason = + ageDays > SPAM_RING_GUARDRAIL_MAX_AGE_DAYS + ? `old account (age ${Math.floor( + ageDays + )}d > ${SPAM_RING_GUARDRAIL_MAX_AGE_DAYS}d)` + : `high karma (score ${score} > ${SPAM_RING_GUARDRAIL_MAX_SCORE})` + await this.skipMember(member.id, user, reason, actorId, ringId) + skipped.push({ user, reason }) + continue + } + + // 永久但可逆封禁:省略 banDays → 不寫 punish_record、無到期;仍發 user_banned 申訴通知 + const banned = (await userService.banUser(user.id, { + remark: USER_BAN_REMARK.spamRing, + })) as User + await this.updateMember(member.id, { + status: 'frozen', + bannedByThisRing: true, + preFreezeState: user.state, + skipReason: null, + }) + await this.insertEvents([ + { ringId, memberId: member.id, actorId, action: 'member_banned' }, + ]) + frozen.push(banned) + } + + const now = new Date() + const [updatedRing] = await this.knex('spam_ring') + .where({ id: ringId }) + .update({ + status: 'frozen', + frozenAt: now, + frozenBy: actorId, + updatedAt: now, + }) + .returning('*') + await this.insertEvents([ + { + ringId, + actorId, + action: 'frozen', + detail: { + remark: remark ?? null, + frozen: frozen.length, + skipped: skipped.length, + }, + }, + ]) + + return { ring: updatedRing, frozen, skipped } + } + + // --- 解除凍結(只還原「本 ring 凍結造成的」封禁)--- + public unfreezeRing = async ({ + ringId, + actorId, + userService, + }: { + ringId: string + actorId: string + userService: UserService + }): Promise<{ + ring: SpamRing + unbanned: User[] + skipped: Array<{ user: User; reason: string }> + }> => { + const ring = await this.findRingById(ringId) + if (!ring) { + throw new UserInputError('spam ring not found') + } + if (ring.status !== 'frozen') { + throw new UserInputError('spam ring is not frozen') + } + + const members = await this.findMembers(ringId) + const unbanned: User[] = [] + const skipped: Array<{ user: User; reason: string }> = [] + + for (const member of members) { + if (!member.bannedByThisRing) { + continue + } + const user = (await this.models.userIdLoader.load( + member.userId + )) as User | null + if (!user) { + continue + } + // freeze 後狀態已變(例如被封存)→ 不復活,僅記錄 + if (user.state !== USER_STATE.banned) { + const reason = `state changed to ${user.state}` + await this.updateMember(member.id, { status: 'skipped', skipReason: reason }) + skipped.push({ user, reason }) + continue + } + const restored = (await userService.unbanUser( + user.id, + USER_STATE.active + )) as User + await this.updateMember(member.id, { + status: 'restored', + bannedByThisRing: false, + }) + await this.insertEvents([ + { ringId, memberId: member.id, actorId, action: 'member_restored' }, + ]) + unbanned.push(restored) + } + + const now = new Date() + const [updatedRing] = await this.knex('spam_ring') + .where({ id: ringId }) + .update({ status: 'restored', updatedAt: now }) + .returning('*') + await this.insertEvents([ + { ringId, actorId, action: 'unfrozen', detail: { unbanned: unbanned.length } }, + ]) + + return { ring: updatedRing, unbanned, skipped } + } + + // --- 標記誤判(餵 L1 訓練當 hard-negative ham)--- + public dismissRing = async ({ + ringId, + actorId, + note, + }: { + ringId: string + actorId: string + note?: string | null + }): Promise => { + const ring = await this.findRingById(ringId) + if (!ring) { + throw new UserInputError('spam ring not found') + } + const now = new Date() + const [updatedRing] = await this.knex('spam_ring') + .where({ id: ringId }) + .update({ status: 'dismissed', note: note ?? null, updatedAt: now }) + .returning('*') + await this.insertEvents([ + { ringId, actorId, action: 'dismissed', detail: { note: note ?? null } }, + ]) + return updatedRing + } + + // --- 私有輔助 --- + private resolveMemberIds = async ( + c: SpamRingCandidate + ): Promise => { + if (c.memberUserIds && c.memberUserIds.length > 0) { + return Array.from(new Set(c.memberUserIds.map((id) => String(id)))) + } + if (c.memberUserNames && c.memberUserNames.length > 0) { + const rows = await this.knexRO('user') + .whereIn('userName', c.memberUserNames) + .select('id') + return Array.from(new Set(rows.map((r: { id: string }) => String(r.id)))) + } + return [] + } + + private upsertMembers = async ( + ringId: string, + userIds: string[], + evidence: Record | null + ): Promise => { + for (const userId of userIds) { + const existing = await this.knexRO('spam_ring_member') + .where({ ringId, userId }) + .first() + if (existing) { + // 不擾動已存在 member(含已 frozen/skipped/restored) + continue + } + await this.knex('spam_ring_member').insert({ + uuid: v4(), + ringId, + userId, + status: 'pending', + bannedByThisRing: false, + evidence: JSON.stringify((evidence && evidence[userId]) || {}), + }) + } + } + + private updateMember = async ( + id: string, + patch: Partial<{ + status: string + bannedByThisRing: boolean + skipReason: string | null + preFreezeState: string + }> + ): Promise => { + await this.knex('spam_ring_member') + .where({ id }) + .update({ ...patch, updatedAt: new Date() }) + } + + private skipMember = async ( + memberId: string, + user: User, + reason: string, + actorId: string, + ringId: string + ): Promise => { + await this.updateMember(memberId, { + status: 'skipped', + skipReason: reason, + bannedByThisRing: false, + preFreezeState: user.state, + }) + await this.insertEvents([ + { ringId, memberId, actorId, action: 'member_skipped', detail: { reason } }, + ]) + } + + private insertEvents = async (events: RingEventInput[]): Promise => { + const now = new Date() + await this.knex('spam_ring_event').insert( + events.map((e) => ({ + uuid: v4(), + ringId: e.ringId, + memberId: e.memberId ?? null, + actorId: e.actorId ?? null, + action: e.action, + detail: JSON.stringify(e.detail ?? {}), + createdAt: now, + })) + ) + } +} diff --git a/src/connectors/userService.ts b/src/connectors/userService.ts index 6b1dafacc..9cf728824 100644 --- a/src/connectors/userService.ts +++ b/src/connectors/userService.ts @@ -2682,9 +2682,13 @@ export class UserService extends BaseService { */ public fetchGoogleUserInfo = async ( authorizationCode: string, - nonce: string + nonce: string, + redirectUri?: string ) => { - const { id_token } = await this.exchangeGoogleToken(authorizationCode) + const { id_token } = await this.exchangeGoogleToken( + authorizationCode, + redirectUri + ) // eslint-disable-next-line @typescript-eslint/no-explicit-any const data = jwt.decode(id_token) as any if (data.aud !== environment.googleClientId) { @@ -2701,14 +2705,18 @@ export class UserService extends BaseService { } private exchangeGoogleToken = async ( - authorizationCode: string + authorizationCode: string, + redirectUri?: string ): Promise<{ access_token: string; id_token: string }> => { const url = 'https://oauth2.googleapis.com/token' const data = { code: authorizationCode, client_id: environment.googleClientId, client_secret: environment.googleClientSecret, - redirect_uri: environment.googleRedirectUri, + // For OSS SSO the redirect_uri must match the one used in the authorization + // request; callers pass an allowlisted OSS callback. Falls back to the + // default (matters-web) redirect_uri otherwise. + redirect_uri: redirectUri || environment.googleRedirectUri, grant_type: 'authorization_code', } const headers = { diff --git a/src/definitions/campaign.d.ts b/src/definitions/campaign.d.ts index dc3353643..6022811ac 100644 --- a/src/definitions/campaign.d.ts +++ b/src/definitions/campaign.d.ts @@ -25,6 +25,7 @@ export interface Campaign { updatedAt: Date showOther: boolean showAd: boolean + enableQuoteWall: boolean } export interface CampaignStage { diff --git a/src/definitions/index.d.ts b/src/definitions/index.d.ts index 3658993fb..aac54366c 100644 --- a/src/definitions/index.d.ts +++ b/src/definitions/index.d.ts @@ -22,6 +22,7 @@ import type { SearchService, PublicationService, FederationExportService, + SpamRingService, } from '#connectors/index.js' import type { RevisionQueue, @@ -126,7 +127,13 @@ import type { PayoutAccount, Transaction, } from './payment.js' +import type { Quote } from './quote.js' import type { Report } from './report.js' +import type { + SpamRing, + SpamRingMember, + SpamRingEvent, +} from './spamRing.js' import type { Tag, TagTranslation, UserTagsOrder } from './tag.js' import type { Translation } from './translation.js' import type { @@ -168,10 +175,12 @@ export * from './payment.js' export * from './appreciation.js' export * from './asset.js' export * from './report.js' +export * from './spamRing.js' export * from './wallet.js' export * from './misc.js' export * from './schema.js' export * from './moment.js' +export * from './quote.js' export * from './campaign.js' export * from './translation.js' export * from './channel.js' @@ -216,6 +225,7 @@ export interface DataSources { channelService: ChannelService searchService: SearchService federationExportService: FederationExportService + spamRingService: SpamRingService likecoin: LikeCoin exchangeRate: ExchangeRate connections: Connections @@ -279,6 +289,9 @@ export interface TableTypeMap { comment: Comment community_watch_action: CommunityWatchAction community_watch_review_event: CommunityWatchReviewEvent + spam_ring: SpamRing + spam_ring_member: SpamRingMember + spam_ring_event: SpamRingEvent crypto_wallet: CryptoWallet crypto_wallet_signature: CryptoWalletSignature customer: Customer @@ -287,6 +300,7 @@ export interface TableTypeMap { featured_comment_materialized: FeaturedCommentMaterialized feature_flag: FeatureFlag moment: Moment + quote: Quote moment_asset: MomentAsset moment_article: MomentArticle moment_tag: MomentTag diff --git a/src/definitions/quote.d.ts b/src/definitions/quote.d.ts new file mode 100644 index 000000000..8e531d4a0 --- /dev/null +++ b/src/definitions/quote.d.ts @@ -0,0 +1,13 @@ +import type { QUOTE_STATE } from '#common/enums/index.js' +import type { ValueOf } from './generic.js' + +export interface Quote { + id: string + content: string + articleId: string + campaignId: string + userId: string + state: ValueOf + createdAt: Date + updatedAt: Date +} diff --git a/src/definitions/schema.d.ts b/src/definitions/schema.d.ts index b7436698d..a12da2e7e 100644 --- a/src/definitions/schema.d.ts +++ b/src/definitions/schema.d.ts @@ -1,205 +1,170 @@ -import { - GraphQLResolveInfo, - GraphQLScalarType, - GraphQLScalarTypeConfig, -} from 'graphql' -import { - User as UserModel, - OAuthClientDB as OAuthClientDBModel, -} from './user.js' -import { ETHWallet as ETHWalletModel } from './wallet.js' -import { Tag as TagModel } from './tag.js' -import { Collection as CollectionModel } from './collection.js' -import { Comment as CommentModel } from './comment.js' -import { CommunityWatchAction as CommunityWatchActionModel } from './communityWatch.js' -import { - Article as ArticleModel, - ArticleVersion as ArticleVersionModel, -} from './article.js' -import { Draft as DraftModel } from './draft.js' -import { - Circle as CircleModel, - CircleInvitation as CircleInvitationModel, - CircleMember as CircleMemberModel, -} from './circle.js' -import { - CirclePrice as CirclePriceModel, - Transaction as TransactionModel, - Writing as WritingModel, - Context, -} from './index.js' -import { PayoutAccount as PayoutAccountModel } from './payment.js' -import { Asset as AssetModel } from './asset.js' -import { NoticeItem as NoticeItemModel } from './notification.js' -import { Appreciation as AppreciationModel } from './appreciation.js' -import { Report as ReportModel } from './report.js' -import { MattersChoiceTopic as MattersChoiceTopicModel } from './misc.js' -import { - Moment as MomentModel, - MomentFeedUser as MomentFeedUserModel, -} from './moment.js' -import { - Campaign as CampaignModel, - CampaignStage as CampaignStageModel, -} from './campaign.js' -import { - TopicChannel as TopicChannelModel, - CurationChannel as CurationChannelModel, -} from './channel.js' -import { Announcement as AnnouncementModel } from './announcement.js' -import { TopicChannelFeedback as TopicChannelFeedbackModel } from './feedback.js' +import { GraphQLResolveInfo, GraphQLScalarType, GraphQLScalarTypeConfig } from 'graphql'; +import { User as UserModel, OAuthClientDB as OAuthClientDBModel } from './user.js'; +import { ETHWallet as ETHWalletModel } from './wallet.js'; +import { Tag as TagModel } from './tag.js'; +import { Collection as CollectionModel } from './collection.js'; +import { Comment as CommentModel } from './comment.js'; +import { CommunityWatchAction as CommunityWatchActionModel } from './communityWatch.js'; +import { Article as ArticleModel, ArticleVersion as ArticleVersionModel } from './article.js'; +import { Draft as DraftModel } from './draft.js'; +import { Circle as CircleModel, CircleInvitation as CircleInvitationModel, CircleMember as CircleMemberModel } from './circle.js'; +import { CirclePrice as CirclePriceModel, Transaction as TransactionModel, Writing as WritingModel, Context } from './index.js'; +import { PayoutAccount as PayoutAccountModel } from './payment.js'; +import { Asset as AssetModel } from './asset.js'; +import { NoticeItem as NoticeItemModel } from './notification.js'; +import { Appreciation as AppreciationModel } from './appreciation.js'; +import { Report as ReportModel } from './report.js'; +import { SpamRing as SpamRingModel, SpamRingMember as SpamRingMemberModel, SpamRingEvent as SpamRingEventModel, SpamRingSignals as SpamRingSignalsModel } from './spamRing.js'; +import { MattersChoiceTopic as MattersChoiceTopicModel } from './misc.js'; +import { Moment as MomentModel, MomentFeedUser as MomentFeedUserModel } from './moment.js'; +import { Quote as QuoteModel } from './quote.js'; +import { Campaign as CampaignModel, CampaignStage as CampaignStageModel } from './campaign.js'; +import { TopicChannel as TopicChannelModel, CurationChannel as CurationChannelModel } from './channel.js'; +import { Announcement as AnnouncementModel } from './announcement.js'; +import { TopicChannelFeedback as TopicChannelFeedbackModel } from './feedback.js'; import { GlobalId } from './nominal.js' -export type Maybe = T | null -export type InputMaybe = T | undefined -export type Exact = { - [K in keyof T]: T[K] -} -export type MakeOptional = Omit & { - [SubKey in K]?: Maybe -} -export type MakeMaybe = Omit & { - [SubKey in K]: Maybe -} -export type MakeEmpty< - T extends { [key: string]: unknown }, - K extends keyof T -> = { [_ in K]?: never } -export type Incremental = - | T - | { - [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never - } -export type Omit = Pick> -export type RequireFields = Omit & { - [P in K]-?: NonNullable -} +export type Maybe = T | null; +export type InputMaybe = T | undefined; +export type Exact = { [K in keyof T]: T[K] }; +export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; +export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; +export type MakeEmpty = { [_ in K]?: never }; +export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; +export type Omit = Pick>; +export type RequireFields = Omit & { [P in K]-?: NonNullable }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { - ID: { input: GlobalId; output: GlobalId } - String: { input: string; output: string } - Boolean: { input: boolean; output: boolean } - Int: { input: number; output: number } - Float: { input: number; output: number } - DateTime: { input: any; output: any } - Upload: { input: any; output: any } -} + ID: { input: GlobalId; output: GlobalId; } + String: { input: string; output: string; } + Boolean: { input: boolean; output: boolean; } + Int: { input: number; output: number; } + Float: { input: number; output: number; } + DateTime: { input: any; output: any; } + Upload: { input: any; output: any; } +}; export type GQLAdStatus = { - __typename?: 'AdStatus' + __typename?: 'AdStatus'; /** Whether this article is labeled as ad by human, null for not labeled yet. */ - isAd?: Maybe -} + isAd?: Maybe; +}; export type GQLAddCollectionsArticlesInput = { - articles: Array - collections: Array -} + articles: Array; + collections: Array; +}; export type GQLAddCreditInput = { - amount: Scalars['Float']['input'] -} + amount: Scalars['Float']['input']; +}; export type GQLAddCreditResult = { - __typename?: 'AddCreditResult' + __typename?: 'AddCreditResult'; /** The client secret of this PaymentIntent. */ - client_secret: Scalars['String']['output'] - transaction: GQLTransaction -} + client_secret: Scalars['String']['output']; + transaction: GQLTransaction; +}; export type GQLAddCurationChannelArticlesInput = { - articles: Array - channel: Scalars['ID']['input'] -} + articles: Array; + channel: Scalars['ID']['input']; +}; export type GQLAnnouncement = { - __typename?: 'Announcement' - channels: Array - content?: Maybe - cover?: Maybe - createdAt: Scalars['DateTime']['output'] - expiredAt?: Maybe - id: Scalars['ID']['output'] - link?: Maybe - order: Scalars['Int']['output'] - title?: Maybe + __typename?: 'Announcement'; + channels: Array; + content?: Maybe; + cover?: Maybe; + createdAt: Scalars['DateTime']['output']; + expiredAt?: Maybe; + id: Scalars['ID']['output']; + link?: Maybe; + order: Scalars['Int']['output']; + title?: Maybe; /** @deprecated Use title, content, link with TranslationArgs instead */ - translations?: Maybe> - type: GQLAnnouncementType - updatedAt: Scalars['DateTime']['output'] - visible: Scalars['Boolean']['output'] -} + translations?: Maybe>; + type: GQLAnnouncementType; + updatedAt: Scalars['DateTime']['output']; + visible: Scalars['Boolean']['output']; +}; + export type GQLAnnouncementContentArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; + export type GQLAnnouncementLinkArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; + export type GQLAnnouncementTitleArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; export type GQLAnnouncementChannel = { - __typename?: 'AnnouncementChannel' - channel: GQLChannel - order: Scalars['Int']['output'] - visible: Scalars['Boolean']['output'] -} + __typename?: 'AnnouncementChannel'; + channel: GQLChannel; + order: Scalars['Int']['output']; + visible: Scalars['Boolean']['output']; +}; export type GQLAnnouncementChannelInput = { - channel: Scalars['ID']['input'] - order: Scalars['Int']['input'] - visible: Scalars['Boolean']['input'] -} + channel: Scalars['ID']['input']; + order: Scalars['Int']['input']; + visible: Scalars['Boolean']['input']; +}; -export type GQLAnnouncementType = 'community' | 'product' | 'seminar' +export type GQLAnnouncementType = + | 'community' + | 'product' + | 'seminar'; export type GQLAnnouncementsInput = { - channel?: InputMaybe - id?: InputMaybe - visible?: InputMaybe -} + channel?: InputMaybe; + id?: InputMaybe; + visible?: InputMaybe; +}; export type GQLApplyCampaignInput = { - id: Scalars['ID']['input'] -} + id: Scalars['ID']['input']; +}; export type GQLAppreciateArticleInput = { - amount: Scalars['Int']['input'] - id: Scalars['ID']['input'] - superLike?: InputMaybe - token?: InputMaybe -} + amount: Scalars['Int']['input']; + id: Scalars['ID']['input']; + superLike?: InputMaybe; + token?: InputMaybe; +}; export type GQLAppreciation = { - __typename?: 'Appreciation' - amount: Scalars['Int']['output'] - content: Scalars['String']['output'] + __typename?: 'Appreciation'; + amount: Scalars['Int']['output']; + content: Scalars['String']['output']; /** Timestamp of appreciation. */ - createdAt: Scalars['DateTime']['output'] - purpose: GQLAppreciationPurpose + createdAt: Scalars['DateTime']['output']; + purpose: GQLAppreciationPurpose; /** Recipient of appreciation. */ - recipient: GQLUser + recipient: GQLUser; /** Sender of appreciation. */ - sender?: Maybe + sender?: Maybe; /** Object that appreciation is meant for. */ - target?: Maybe -} + target?: Maybe; +}; export type GQLAppreciationConnection = GQLConnection & { - __typename?: 'AppreciationConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'AppreciationConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLAppreciationEdge = { - __typename?: 'AppreciationEdge' - cursor: Scalars['String']['output'] - node: GQLAppreciation -} + __typename?: 'AppreciationEdge'; + cursor: Scalars['String']['output']; + node: GQLAppreciation; +}; export type GQLAppreciationPurpose = | 'appreciate' @@ -209,411 +174,427 @@ export type GQLAppreciationPurpose = | 'invitationAccepted' | 'joinByInvitation' | 'joinByTask' - | 'systemSubsidy' + | 'systemSubsidy'; export type GQLArchiveUserFailure = { - __typename?: 'ArchiveUserFailure' - id: Scalars['ID']['output'] - message: Scalars['String']['output'] -} + __typename?: 'ArchiveUserFailure'; + id: Scalars['ID']['output']; + message: Scalars['String']['output']; +}; export type GQLArchiveUsersInput = { - ids: Array - password: Scalars['String']['input'] -} + ids: Array; + password: Scalars['String']['input']; +}; export type GQLArchiveUsersResult = { - __typename?: 'ArchiveUsersResult' - archived: Array - skipped: Array -} + __typename?: 'ArchiveUsersResult'; + archived: Array; + skipped: Array; +}; /** * This type contains metadata, content, hash and related data of an article. If you * want information about article's comments. Please check Comment type. */ -export type GQLArticle = GQLNode & - GQLPinnableWork & { - __typename?: 'Article' - /** Access related fields on circle */ - access: GQLArticleAccess - /** Number represents how many times per user can appreciate this article. */ - appreciateLeft: Scalars['Int']['output'] - /** Limit the nuhmber of appreciate per user. */ - appreciateLimit: Scalars['Int']['output'] - /** Appreciations history of this article. */ - appreciationsReceived: GQLAppreciationConnection - /** Total number of appreciations recieved of this article. */ - appreciationsReceivedTotal: Scalars['Int']['output'] - /** List of assets are belonged to this article (Only the author can access currently). */ - assets: Array - /** Author of this article. */ - author: GQLUser - /** Available translation languages. */ - availableTranslations?: Maybe> - /** The number of users who bookmarked this article. */ - bookmarkCount: Scalars['Int']['output'] - bookmarked: Scalars['Boolean']['output'] - /** Associated campaigns */ - campaigns: Array - /** Whether readers can comment */ - canComment: Scalars['Boolean']['output'] - /** This value determines if current viewer can SuperLike or not. */ - canSuperLike: Scalars['Boolean']['output'] - /** Classifications status */ - classification: GQLArticleClassification - /** - * List of articles added into this article's connections. - * @deprecated Use connections instead - */ - collection: GQLArticleConnection - /** Collections of this article. */ - collections: GQLCollectionConnection - /** The counting number of comments. */ - commentCount: Scalars['Int']['output'] - /** List of comments of this article. */ - comments: GQLCommentConnection - /** List of articles which added this article into their connections. */ - connectedBy: GQLArticleConnection - connections: GQLArticleConnection - /** Content (HTML) of this article. */ - content: Scalars['String']['output'] - /** Different foramts of content. */ - contents: GQLArticleContents - /** Article cover's link, set by author */ - cover?: Maybe - /** Time of this article was created. */ - createdAt: Scalars['DateTime']['output'] - /** IPFS hash of this article. */ - dataHash: Scalars['String']['output'] - /** Cover link that is displayed on the article page */ - displayCover?: Maybe - /** Whether current viewer has donated to this article */ - donated: Scalars['Boolean']['output'] - /** Total number of donation recieved of this article. */ - donationCount: Scalars['Int']['output'] - /** Donations of this article, grouped by sender */ - donations: GQLArticleDonationConnection - /** List of featured comments of this article. */ - featuredComments: GQLCommentConnection - /** Computed federation export eligibility for this article. */ - federationEligibility: GQLArticleFederationEligibility - /** Article-level federation setting override. */ - federationSetting?: Maybe - /** This value determines if current viewer has appreciated or not. */ - hasAppreciate: Scalars['Boolean']['output'] - /** Unique ID of this article */ - id: Scalars['ID']['output'] - /** Whether the first line of paragraph should be indented */ - indentFirstLine: Scalars['Boolean']['output'] - /** The iscnId if published to ISCN */ - iscnId?: Maybe - /** Original language of content */ - language?: Maybe - /** License Type */ - license: GQLArticleLicenseType - /** Media hash, composed of cid encoding, of this article. */ - mediaHash: Scalars['String']['output'] - /** Whether this article is noindex */ - noindex: Scalars['Boolean']['output'] - oss: GQLArticleOss - /** The number determines how many comments can be set as pinned comment. */ - pinCommentLeft: Scalars['Int']['output'] - /** The number determines how many pinned comments can be set. */ - pinCommentLimit: Scalars['Int']['output'] - /** This value determines if this article is an author selected article or not. */ - pinned: Scalars['Boolean']['output'] - /** List of pinned comments. */ - pinnedComments?: Maybe> - /** Cumulative reading time in seconds */ - readTime: Scalars['Float']['output'] - /** Total number of readers of this article. */ - readerCount: Scalars['Int']['output'] - /** Related articles to this article. */ - relatedArticles: GQLArticleConnection - /** Donation-related articles to this article. */ - relatedDonationArticles: GQLArticleConnection - remark?: Maybe - /** Creator message after support */ - replyToDonator?: Maybe - /** Creator message asking for support */ - requestForDonation?: Maybe - /** The counting number of this article. */ - responseCount: Scalars['Int']['output'] - /** List of responses of a article. */ - responses: GQLResponseConnection - /** Time of this article was revised. */ - revisedAt?: Maybe - /** Revision Count */ - revisionCount: Scalars['Int']['output'] - /** Whether content is marked as sensitive by admin */ - sensitiveByAdmin: Scalars['Boolean']['output'] - /** whether content is marked as sensitive by author */ - sensitiveByAuthor: Scalars['Boolean']['output'] - /** Short hash for shorter url addressing */ - shortHash: Scalars['String']['output'] - /** Slugified article title. */ - slug: Scalars['String']['output'] - /** State of this article. */ - state: GQLArticleState - /** - * This value determines if current Viewer has bookmarked of not. - * @deprecated Use bookmarked instead - */ - subscribed: Scalars['Boolean']['output'] - /** A short summary for this article. */ - summary: Scalars['String']['output'] - /** This value determines if the summary is customized or not. */ - summaryCustomized: Scalars['Boolean']['output'] - /** Tags attached to this article. */ - tags?: Maybe> - /** Article title. */ - title: Scalars['String']['output'] - /** Transactions history of this article. */ - transactionsReceivedBy: GQLUserConnection - /** Translation of article title and content. */ - translation?: Maybe - /** History versions */ - versions: GQLArticleVersionsConnection - /** Word count of this article. */ - wordCount?: Maybe - } +export type GQLArticle = GQLNode & GQLPinnableWork & { + __typename?: 'Article'; + /** Access related fields on circle */ + access: GQLArticleAccess; + /** Number represents how many times per user can appreciate this article. */ + appreciateLeft: Scalars['Int']['output']; + /** Limit the nuhmber of appreciate per user. */ + appreciateLimit: Scalars['Int']['output']; + /** Appreciations history of this article. */ + appreciationsReceived: GQLAppreciationConnection; + /** Total number of appreciations recieved of this article. */ + appreciationsReceivedTotal: Scalars['Int']['output']; + /** List of assets are belonged to this article (Only the author can access currently). */ + assets: Array; + /** Author of this article. */ + author: GQLUser; + /** Available translation languages. */ + availableTranslations?: Maybe>; + /** The number of users who bookmarked this article. */ + bookmarkCount: Scalars['Int']['output']; + bookmarked: Scalars['Boolean']['output']; + /** Associated campaigns */ + campaigns: Array; + /** Whether readers can comment */ + canComment: Scalars['Boolean']['output']; + /** This value determines if current viewer can SuperLike or not. */ + canSuperLike: Scalars['Boolean']['output']; + /** Classifications status */ + classification: GQLArticleClassification; + /** + * List of articles added into this article's connections. + * @deprecated Use connections instead + */ + collection: GQLArticleConnection; + /** Collections of this article. */ + collections: GQLCollectionConnection; + /** The counting number of comments. */ + commentCount: Scalars['Int']['output']; + /** List of comments of this article. */ + comments: GQLCommentConnection; + /** List of articles which added this article into their connections. */ + connectedBy: GQLArticleConnection; + connections: GQLArticleConnection; + /** Content (HTML) of this article. */ + content: Scalars['String']['output']; + /** Different foramts of content. */ + contents: GQLArticleContents; + /** Article cover's link, set by author */ + cover?: Maybe; + /** Time of this article was created. */ + createdAt: Scalars['DateTime']['output']; + /** IPFS hash of this article. */ + dataHash: Scalars['String']['output']; + /** Cover link that is displayed on the article page */ + displayCover?: Maybe; + /** Whether current viewer has donated to this article */ + donated: Scalars['Boolean']['output']; + /** Total number of donation recieved of this article. */ + donationCount: Scalars['Int']['output']; + /** Donations of this article, grouped by sender */ + donations: GQLArticleDonationConnection; + /** List of featured comments of this article. */ + featuredComments: GQLCommentConnection; + /** Computed federation export eligibility for this article. */ + federationEligibility: GQLArticleFederationEligibility; + /** Article-level federation setting override. */ + federationSetting?: Maybe; + /** This value determines if current viewer has appreciated or not. */ + hasAppreciate: Scalars['Boolean']['output']; + /** Unique ID of this article */ + id: Scalars['ID']['output']; + /** Whether the first line of paragraph should be indented */ + indentFirstLine: Scalars['Boolean']['output']; + /** The iscnId if published to ISCN */ + iscnId?: Maybe; + /** Original language of content */ + language?: Maybe; + /** License Type */ + license: GQLArticleLicenseType; + /** Media hash, composed of cid encoding, of this article. */ + mediaHash: Scalars['String']['output']; + /** Whether this article is noindex */ + noindex: Scalars['Boolean']['output']; + oss: GQLArticleOss; + /** The number determines how many comments can be set as pinned comment. */ + pinCommentLeft: Scalars['Int']['output']; + /** The number determines how many pinned comments can be set. */ + pinCommentLimit: Scalars['Int']['output']; + /** This value determines if this article is an author selected article or not. */ + pinned: Scalars['Boolean']['output']; + /** List of pinned comments. */ + pinnedComments?: Maybe>; + /** Cumulative reading time in seconds */ + readTime: Scalars['Float']['output']; + /** Total number of readers of this article. */ + readerCount: Scalars['Int']['output']; + /** Related articles to this article. */ + relatedArticles: GQLArticleConnection; + /** Donation-related articles to this article. */ + relatedDonationArticles: GQLArticleConnection; + remark?: Maybe; + /** Creator message after support */ + replyToDonator?: Maybe; + /** Creator message asking for support */ + requestForDonation?: Maybe; + /** The counting number of this article. */ + responseCount: Scalars['Int']['output']; + /** List of responses of a article. */ + responses: GQLResponseConnection; + /** Time of this article was revised. */ + revisedAt?: Maybe; + /** Revision Count */ + revisionCount: Scalars['Int']['output']; + /** Whether content is marked as sensitive by admin */ + sensitiveByAdmin: Scalars['Boolean']['output']; + /** whether content is marked as sensitive by author */ + sensitiveByAuthor: Scalars['Boolean']['output']; + /** Short hash for shorter url addressing */ + shortHash: Scalars['String']['output']; + /** Slugified article title. */ + slug: Scalars['String']['output']; + /** State of this article. */ + state: GQLArticleState; + /** + * This value determines if current Viewer has bookmarked of not. + * @deprecated Use bookmarked instead + */ + subscribed: Scalars['Boolean']['output']; + /** A short summary for this article. */ + summary: Scalars['String']['output']; + /** This value determines if the summary is customized or not. */ + summaryCustomized: Scalars['Boolean']['output']; + /** Tags attached to this article. */ + tags?: Maybe>; + /** Article title. */ + title: Scalars['String']['output']; + /** Transactions history of this article. */ + transactionsReceivedBy: GQLUserConnection; + /** Translation of article title and content. */ + translation?: Maybe; + /** History versions */ + versions: GQLArticleVersionsConnection; + /** Word count of this article. */ + wordCount?: Maybe; +}; + /** * This type contains metadata, content, hash and related data of an article. If you * want information about article's comments. Please check Comment type. */ export type GQLArticleAppreciationsReceivedArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + /** * This type contains metadata, content, hash and related data of an article. If you * want information about article's comments. Please check Comment type. */ export type GQLArticleCollectionArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + /** * This type contains metadata, content, hash and related data of an article. If you * want information about article's comments. Please check Comment type. */ export type GQLArticleCollectionsArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + /** * This type contains metadata, content, hash and related data of an article. If you * want information about article's comments. Please check Comment type. */ export type GQLArticleCommentsArgs = { - input: GQLCommentsInput -} + input: GQLCommentsInput; +}; + /** * This type contains metadata, content, hash and related data of an article. If you * want information about article's comments. Please check Comment type. */ export type GQLArticleConnectedByArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + /** * This type contains metadata, content, hash and related data of an article. If you * want information about article's comments. Please check Comment type. */ export type GQLArticleConnectionsArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + /** * This type contains metadata, content, hash and related data of an article. If you * want information about article's comments. Please check Comment type. */ export type GQLArticleDonationsArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + /** * This type contains metadata, content, hash and related data of an article. If you * want information about article's comments. Please check Comment type. */ export type GQLArticleFeaturedCommentsArgs = { - input: GQLFeaturedCommentsInput -} + input: GQLFeaturedCommentsInput; +}; + /** * This type contains metadata, content, hash and related data of an article. If you * want information about article's comments. Please check Comment type. */ export type GQLArticleRelatedArticlesArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + /** * This type contains metadata, content, hash and related data of an article. If you * want information about article's comments. Please check Comment type. */ export type GQLArticleRelatedDonationArticlesArgs = { - input: GQLRelatedDonationArticlesInput -} + input: GQLRelatedDonationArticlesInput; +}; + /** * This type contains metadata, content, hash and related data of an article. If you * want information about article's comments. Please check Comment type. */ export type GQLArticleResponsesArgs = { - input: GQLResponsesInput -} + input: GQLResponsesInput; +}; + /** * This type contains metadata, content, hash and related data of an article. If you * want information about article's comments. Please check Comment type. */ export type GQLArticleTransactionsReceivedByArgs = { - input: GQLTransactionsReceivedByArgs -} + input: GQLTransactionsReceivedByArgs; +}; + /** * This type contains metadata, content, hash and related data of an article. If you * want information about article's comments. Please check Comment type. */ export type GQLArticleTranslationArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; + /** * This type contains metadata, content, hash and related data of an article. If you * want information about article's comments. Please check Comment type. */ export type GQLArticleVersionsArgs = { - input: GQLArticleVersionsInput -} + input: GQLArticleVersionsInput; +}; export type GQLArticleAccess = { - __typename?: 'ArticleAccess' - circle?: Maybe - secret?: Maybe - type: GQLArticleAccessType -} + __typename?: 'ArticleAccess'; + circle?: Maybe; + secret?: Maybe; + type: GQLArticleAccessType; +}; /** Enums for types of article access */ -export type GQLArticleAccessType = 'paywall' | 'public' +export type GQLArticleAccessType = + | 'paywall' + | 'public'; export type GQLArticleArticleNotice = GQLNotice & { - __typename?: 'ArticleArticleNotice' + __typename?: 'ArticleArticleNotice'; /** List of notice actors. */ - actors?: Maybe> - article: GQLArticle + actors?: Maybe>; + article: GQLArticle; /** Time of this notice was created. */ - createdAt: Scalars['DateTime']['output'] + createdAt: Scalars['DateTime']['output']; /** Unique ID of this notice. */ - id: Scalars['ID']['output'] - target: GQLArticle - type: GQLArticleArticleNoticeType + id: Scalars['ID']['output']; + target: GQLArticle; + type: GQLArticleArticleNoticeType; /** The value determines if the notice is unread or not. */ - unread: Scalars['Boolean']['output'] -} + unread: Scalars['Boolean']['output']; +}; -export type GQLArticleArticleNoticeType = 'ArticleNewCollected' +export type GQLArticleArticleNoticeType = + | 'ArticleNewCollected'; export type GQLArticleCampaign = { - __typename?: 'ArticleCampaign' - campaign: GQLCampaign - stage?: Maybe -} + __typename?: 'ArticleCampaign'; + campaign: GQLCampaign; + stage?: Maybe; +}; export type GQLArticleCampaignInput = { - campaign: Scalars['ID']['input'] - stage?: InputMaybe -} + campaign: Scalars['ID']['input']; + stage?: InputMaybe; +}; export type GQLArticleClassification = { - __typename?: 'ArticleClassification' - topicChannel: GQLTopicChannelClassification -} + __typename?: 'ArticleClassification'; + topicChannel: GQLTopicChannelClassification; +}; export type GQLArticleConnection = GQLConnection & { - __typename?: 'ArticleConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'ArticleConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLArticleContents = { - __typename?: 'ArticleContents' + __typename?: 'ArticleContents'; /** HTML content of this article. */ - html: Scalars['String']['output'] + html: Scalars['String']['output']; /** Markdown content of this article. */ - markdown: Scalars['String']['output'] -} + markdown: Scalars['String']['output']; +}; export type GQLArticleDonation = { - __typename?: 'ArticleDonation' - id: Scalars['ID']['output'] - sender?: Maybe -} + __typename?: 'ArticleDonation'; + id: Scalars['ID']['output']; + sender?: Maybe; +}; export type GQLArticleDonationConnection = { - __typename?: 'ArticleDonationConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'ArticleDonationConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLArticleDonationEdge = { - __typename?: 'ArticleDonationEdge' - cursor: Scalars['String']['output'] - node: GQLArticleDonation -} + __typename?: 'ArticleDonationEdge'; + cursor: Scalars['String']['output']; + node: GQLArticleDonation; +}; export type GQLArticleEdge = { - __typename?: 'ArticleEdge' - cursor: Scalars['String']['output'] - node: GQLArticle -} + __typename?: 'ArticleEdge'; + cursor: Scalars['String']['output']; + node: GQLArticle; +}; export type GQLArticleFederationEligibility = { - __typename?: 'ArticleFederationEligibility' - effectiveArticleSetting: GQLFederationArticleSettingState - eligible: Scalars['Boolean']['output'] - reason: GQLFederationExportDecisionReason -} + __typename?: 'ArticleFederationEligibility'; + effectiveArticleSetting: GQLFederationArticleSettingState; + eligible: Scalars['Boolean']['output']; + reason: GQLFederationExportDecisionReason; +}; export type GQLArticleFederationSetting = { - __typename?: 'ArticleFederationSetting' - articleId: Scalars['ID']['output'] - state: GQLFederationArticleSettingState - updatedBy?: Maybe -} + __typename?: 'ArticleFederationSetting'; + articleId: Scalars['ID']['output']; + state: GQLFederationArticleSettingState; + updatedBy?: Maybe; +}; export type GQLArticleInput = { - mediaHash?: InputMaybe - shortHash?: InputMaybe -} + mediaHash?: InputMaybe; + shortHash?: InputMaybe; +}; /** Enums for types of article license */ export type GQLArticleLicenseType = | 'arr' | 'cc_0' | 'cc_by_nc_nd_2' - | 'cc_by_nc_nd_4' + | 'cc_by_nc_nd_4'; export type GQLArticleNotice = GQLNotice & { - __typename?: 'ArticleNotice' + __typename?: 'ArticleNotice'; /** List of notice actors. */ - actors?: Maybe> + actors?: Maybe>; /** Time of this notice was created. */ - createdAt: Scalars['DateTime']['output'] - entities: Array + createdAt: Scalars['DateTime']['output']; + entities: Array; /** Unique ID of this notice. */ - id: Scalars['ID']['output'] - target: GQLArticle - type: GQLArticleNoticeType + id: Scalars['ID']['output']; + target: GQLArticle; + type: GQLArticleNoticeType; /** The value determines if the notice is unread or not. */ - unread: Scalars['Boolean']['output'] -} + unread: Scalars['Boolean']['output']; +}; export type GQLArticleNoticeType = | 'ArticleMentionedYou' @@ -624,103 +605,107 @@ export type GQLArticleNoticeType = | 'RevisedArticleNotPublished' | 'RevisedArticlePublished' | 'ScheduledArticlePublished' - | 'TopicChannelFeedbackAccepted' + | 'TopicChannelFeedbackAccepted'; export type GQLArticleOss = { - __typename?: 'ArticleOSS' - adStatus: GQLAdStatus - boost: Scalars['Float']['output'] - inRecommendHottest: Scalars['Boolean']['output'] - inRecommendIcymi: Scalars['Boolean']['output'] - inRecommendNewest: Scalars['Boolean']['output'] - inSearch: Scalars['Boolean']['output'] - pinHistory: Array> - score: Scalars['Float']['output'] - spamStatus: GQLSpamStatus + __typename?: 'ArticleOSS'; + adStatus: GQLAdStatus; + boost: Scalars['Float']['output']; + inRecommendHottest: Scalars['Boolean']['output']; + inRecommendIcymi: Scalars['Boolean']['output']; + inRecommendNewest: Scalars['Boolean']['output']; + inSearch: Scalars['Boolean']['output']; + pinHistory: Array>; + score: Scalars['Float']['output']; + spamStatus: GQLSpamStatus; /** @deprecated Use classification.topicChannel.channels instead */ - topicChannels?: Maybe> -} + topicChannels?: Maybe>; +}; export type GQLArticleRecommendationActivity = { - __typename?: 'ArticleRecommendationActivity' + __typename?: 'ArticleRecommendationActivity'; /** Recommended articles */ - nodes?: Maybe> + nodes?: Maybe>; /** The source type of recommendation */ - source?: Maybe -} + source?: Maybe; +}; export type GQLArticleRecommendationActivitySource = | 'ReadArticlesTags' - | 'UserDonation' + | 'UserDonation'; /** Enums for an article state. */ -export type GQLArticleState = 'active' | 'archived' | 'banned' +export type GQLArticleState = + | 'active' + | 'archived' + | 'banned'; export type GQLArticleTopicChannel = { - __typename?: 'ArticleTopicChannel' + __typename?: 'ArticleTopicChannel'; /** Whether this article is filtered out by anti-flood in this channel */ - antiFlooded: Scalars['Boolean']['output'] - channel: GQLTopicChannel + antiFlooded: Scalars['Boolean']['output']; + channel: GQLTopicChannel; /** Datetime when this article is classified */ - classicfiedAt: Scalars['DateTime']['output'] + classicfiedAt: Scalars['DateTime']['output']; /** Whether this article channel is enabled */ - enabled: Scalars['Boolean']['output'] + enabled: Scalars['Boolean']['output']; /** Whether this article is labeled by human, null for not labeled yet. */ - isLabeled: Scalars['Boolean']['output'] + isLabeled: Scalars['Boolean']['output']; /** Whether this article is pinned */ - pinned: Scalars['Boolean']['output'] + pinned: Scalars['Boolean']['output']; /** Confident score by machine */ - score?: Maybe -} + score?: Maybe; +}; export type GQLArticleTranslation = { - __typename?: 'ArticleTranslation' - content?: Maybe - language?: Maybe - model?: Maybe - summary?: Maybe - title?: Maybe -} + __typename?: 'ArticleTranslation'; + content?: Maybe; + language?: Maybe; + model?: Maybe; + summary?: Maybe; + title?: Maybe; +}; export type GQLArticleTranslationInput = { - language: GQLUserLanguage - model?: InputMaybe -} + language: GQLUserLanguage; + model?: InputMaybe; +}; export type GQLArticleVersion = GQLNode & { - __typename?: 'ArticleVersion' - contents: GQLArticleContents - createdAt: Scalars['DateTime']['output'] - dataHash?: Maybe - description?: Maybe - id: Scalars['ID']['output'] - mediaHash?: Maybe - summary: Scalars['String']['output'] - title: Scalars['String']['output'] - translation?: Maybe -} + __typename?: 'ArticleVersion'; + contents: GQLArticleContents; + createdAt: Scalars['DateTime']['output']; + dataHash?: Maybe; + description?: Maybe; + id: Scalars['ID']['output']; + mediaHash?: Maybe; + summary: Scalars['String']['output']; + title: Scalars['String']['output']; + translation?: Maybe; +}; + export type GQLArticleVersionTranslationArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; export type GQLArticleVersionEdge = { - __typename?: 'ArticleVersionEdge' - cursor: Scalars['String']['output'] - node: GQLArticleVersion -} + __typename?: 'ArticleVersionEdge'; + cursor: Scalars['String']['output']; + node: GQLArticleVersion; +}; export type GQLArticleVersionsConnection = GQLConnection & { - __typename?: 'ArticleVersionsConnection' - edges: Array> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'ArticleVersionsConnection'; + edges: Array>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLArticleVersionsInput = { - after?: InputMaybe - first?: InputMaybe -} + after?: InputMaybe; + first?: InputMaybe; +}; export type GQLArticlesSort = | 'mostAppreciations' @@ -728,22 +713,24 @@ export type GQLArticlesSort = | 'mostComments' | 'mostDonations' | 'mostReadTime' - | 'newest' + /** Order by spam score from high to low (only scored articles) */ + | 'mostSpam' + | 'newest'; /** This type contains type, link and related data of an asset. */ export type GQLAsset = { - __typename?: 'Asset' + __typename?: 'Asset'; /** Time of this asset was created. */ - createdAt: Scalars['DateTime']['output'] - draft?: Maybe + createdAt: Scalars['DateTime']['output']; + draft?: Maybe; /** Unique ID of this Asset. */ - id: Scalars['ID']['output'] + id: Scalars['ID']['output']; /** Link of this asset. */ - path: Scalars['String']['output'] + path: Scalars['String']['output']; /** Types of this asset. */ - type: GQLAssetType - uploadURL?: Maybe -} + type: GQLAssetType; + uploadURL?: Maybe; +}; /** Enums for asset types. */ export type GQLAssetType = @@ -759,24 +746,31 @@ export type GQLAssetType = | 'moment' | 'oauthClientAvatar' | 'profileCover' - | 'tagCover' + | 'tagCover'; export type GQLAuthResult = { - __typename?: 'AuthResult' - auth: Scalars['Boolean']['output'] - token?: Maybe - type: GQLAuthResultType - user?: Maybe -} - -export type GQLAuthResultType = 'LinkAccount' | 'Login' | 'Signup' - -export type GQLAuthorsType = 'active' | 'appreciated' | 'default' | 'trendy' + __typename?: 'AuthResult'; + auth: Scalars['Boolean']['output']; + token?: Maybe; + type: GQLAuthResultType; + user?: Maybe; +}; + +export type GQLAuthResultType = + | 'LinkAccount' + | 'Login' + | 'Signup'; + +export type GQLAuthorsType = + | 'active' + | 'appreciated' + | 'default' + | 'trendy'; export type GQLBadge = { - __typename?: 'Badge' - type: GQLBadgeType -} + __typename?: 'Badge'; + type: GQLBadgeType; +}; export type GQLBadgeType = | 'architect' @@ -788,424 +782,451 @@ export type GQLBadgeType = | 'nomad2' | 'nomad3' | 'nomad4' - | 'seed' + | 'seed'; export type GQLBadgedUsersInput = { - after?: InputMaybe - first?: InputMaybe - type?: InputMaybe -} + after?: InputMaybe; + first?: InputMaybe; + type?: InputMaybe; +}; export type GQLBalance = { - __typename?: 'Balance' - HKD: Scalars['Float']['output'] -} + __typename?: 'Balance'; + HKD: Scalars['Float']['output']; +}; export type GQLBanCampaignArticlesInput = { - articles: Array - campaign: Scalars['ID']['input'] -} + articles: Array; + campaign: Scalars['ID']['input']; +}; export type GQLBlockchainTransaction = { - __typename?: 'BlockchainTransaction' - chain: GQLChain - txHash: Scalars['String']['output'] -} + __typename?: 'BlockchainTransaction'; + chain: GQLChain; + txHash: Scalars['String']['output']; +}; export type GQLBlockedSearchKeyword = { - __typename?: 'BlockedSearchKeyword' + __typename?: 'BlockedSearchKeyword'; /** Time of this search keyword was created. */ - createdAt: Scalars['DateTime']['output'] + createdAt: Scalars['DateTime']['output']; /** Unique ID of bloked search keyword. */ - id: Scalars['ID']['output'] + id: Scalars['ID']['output']; /** Types of this search keyword. */ - searchKey: Scalars['String']['output'] -} + searchKey: Scalars['String']['output']; +}; -export type GQLBoostTypes = 'Article' | 'Campaign' | 'Tag' | 'User' +export type GQLBoostTypes = + | 'Article' + | 'Campaign' + | 'Tag' + | 'User'; -export type GQLCacheControlScope = 'PRIVATE' | 'PUBLIC' +export type GQLCacheControlScope = + | 'PRIVATE' + | 'PUBLIC'; export type GQLCampaign = { - id: Scalars['ID']['output'] - name: Scalars['String']['output'] - shortHash: Scalars['String']['output'] - state: GQLCampaignState -} + id: Scalars['ID']['output']; + name: Scalars['String']['output']; + shortHash: Scalars['String']['output']; + state: GQLCampaignState; +}; export type GQLCampaignApplication = { - __typename?: 'CampaignApplication' - createdAt: Scalars['DateTime']['output'] - state: GQLCampaignApplicationState -} + __typename?: 'CampaignApplication'; + createdAt: Scalars['DateTime']['output']; + state: GQLCampaignApplicationState; +}; -export type GQLCampaignApplicationState = 'pending' | 'rejected' | 'succeeded' +export type GQLCampaignApplicationState = + | 'pending' + | 'rejected' + | 'succeeded'; export type GQLCampaignArticleConnection = GQLConnection & { - __typename?: 'CampaignArticleConnection' - edges: Array - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'CampaignArticleConnection'; + edges: Array; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLCampaignArticleEdge = { - __typename?: 'CampaignArticleEdge' - announcement: Scalars['Boolean']['output'] - cursor: Scalars['String']['output'] - featured: Scalars['Boolean']['output'] - node: GQLArticle -} + __typename?: 'CampaignArticleEdge'; + announcement: Scalars['Boolean']['output']; + cursor: Scalars['String']['output']; + featured: Scalars['Boolean']['output']; + node: GQLArticle; +}; export type GQLCampaignArticleNotice = GQLNotice & { - __typename?: 'CampaignArticleNotice' + __typename?: 'CampaignArticleNotice'; /** List of notice actors. */ - actors?: Maybe> - article: GQLArticle + actors?: Maybe>; + article: GQLArticle; /** Time of this notice was created. */ - createdAt: Scalars['DateTime']['output'] + createdAt: Scalars['DateTime']['output']; /** Unique ID of this notice. */ - id: Scalars['ID']['output'] - target: GQLCampaign - type: GQLCampaignArticleNoticeType + id: Scalars['ID']['output']; + target: GQLCampaign; + type: GQLCampaignArticleNoticeType; /** The value determines if the notice is unread or not. */ - unread: Scalars['Boolean']['output'] -} + unread: Scalars['Boolean']['output']; +}; -export type GQLCampaignArticleNoticeType = 'CampaignArticleFeatured' +export type GQLCampaignArticleNoticeType = + | 'CampaignArticleFeatured'; export type GQLCampaignArticlesFilter = { - featured?: InputMaybe - stage?: InputMaybe -} + featured?: InputMaybe; + stage?: InputMaybe; +}; export type GQLCampaignArticlesInput = { - after?: InputMaybe - filter?: InputMaybe - first?: InputMaybe -} + after?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; +}; export type GQLCampaignConnection = GQLConnection & { - __typename?: 'CampaignConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'CampaignConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLCampaignEdge = { - __typename?: 'CampaignEdge' - cursor: Scalars['String']['output'] - node: GQLCampaign -} + __typename?: 'CampaignEdge'; + cursor: Scalars['String']['output']; + node: GQLCampaign; +}; export type GQLCampaignInput = { - shortHash: Scalars['String']['input'] -} + shortHash: Scalars['String']['input']; +}; export type GQLCampaignOss = { - __typename?: 'CampaignOSS' - boost: Scalars['Float']['output'] - exclusive: Scalars['Boolean']['output'] - managers: Array -} + __typename?: 'CampaignOSS'; + boost: Scalars['Float']['output']; + exclusive: Scalars['Boolean']['output']; + managers: Array; +}; export type GQLCampaignParticipantConnection = GQLConnection & { - __typename?: 'CampaignParticipantConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'CampaignParticipantConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLCampaignParticipantEdge = { - __typename?: 'CampaignParticipantEdge' - application?: Maybe - cursor: Scalars['String']['output'] - node: GQLUser -} + __typename?: 'CampaignParticipantEdge'; + application?: Maybe; + cursor: Scalars['String']['output']; + node: GQLUser; +}; export type GQLCampaignParticipantsInput = { - after?: InputMaybe - first?: InputMaybe + after?: InputMaybe; + first?: InputMaybe; /** return all state participants */ - oss?: InputMaybe -} + oss?: InputMaybe; +}; export type GQLCampaignStage = { - __typename?: 'CampaignStage' - description: Scalars['String']['output'] - id: Scalars['ID']['output'] - name: Scalars['String']['output'] - period?: Maybe -} + __typename?: 'CampaignStage'; + description: Scalars['String']['output']; + id: Scalars['ID']['output']; + name: Scalars['String']['output']; + period?: Maybe; +}; + export type GQLCampaignStageDescriptionArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; + export type GQLCampaignStageNameArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; export type GQLCampaignStageInput = { - description?: InputMaybe> - name: Array - period?: InputMaybe -} + description?: InputMaybe>; + name: Array; + period?: InputMaybe; +}; -export type GQLCampaignState = 'active' | 'archived' | 'finished' | 'pending' +export type GQLCampaignState = + | 'active' + | 'archived' + | 'finished' + | 'pending'; export type GQLCampaignsFilter = { - excludes?: InputMaybe> - sort?: InputMaybe - state?: InputMaybe -} + excludes?: InputMaybe>; + sort?: InputMaybe; + state?: InputMaybe; +}; -export type GQLCampaignsFilterSort = 'writingPeriod' +export type GQLCampaignsFilterSort = + | 'writingPeriod'; -export type GQLCampaignsFilterState = 'active' | 'finished' +export type GQLCampaignsFilterState = + | 'active' + | 'finished'; export type GQLCampaignsInput = { - after?: InputMaybe - filter?: InputMaybe - first?: InputMaybe + after?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; /** return pending and archived campaigns */ - oss?: InputMaybe -} + oss?: InputMaybe; +}; -export type GQLChain = 'Optimism' | 'Polygon' +export type GQLChain = + | 'Optimism' + | 'Polygon'; export type GQLChannel = { - id: Scalars['ID']['output'] - navbarTitle: Scalars['String']['output'] - shortHash: Scalars['String']['output'] -} + id: Scalars['ID']['output']; + navbarTitle: Scalars['String']['output']; + shortHash: Scalars['String']['output']; +}; + export type GQLChannelNavbarTitleArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; export type GQLChannelArticleConnection = GQLConnection & { - __typename?: 'ChannelArticleConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'ChannelArticleConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLChannelArticleEdge = { - __typename?: 'ChannelArticleEdge' - cursor: Scalars['String']['output'] - node: GQLArticle - pinned: Scalars['Boolean']['output'] -} + __typename?: 'ChannelArticleEdge'; + cursor: Scalars['String']['output']; + node: GQLArticle; + pinned: Scalars['Boolean']['output']; +}; export type GQLChannelArticlesFilter = { - datetimeRange?: InputMaybe - searchKey?: InputMaybe -} + datetimeRange?: InputMaybe; + searchKey?: InputMaybe; +}; export type GQLChannelArticlesInput = { - after?: InputMaybe - filter?: InputMaybe - first?: InputMaybe - oss?: InputMaybe - sort?: InputMaybe -} + after?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + oss?: InputMaybe; + sort?: InputMaybe; +}; export type GQLChannelInput = { - shortHash: Scalars['String']['input'] -} + shortHash: Scalars['String']['input']; +}; export type GQLChannelsInput = { /** return all channels if true, only active channels by default */ - oss?: InputMaybe -} + oss?: InputMaybe; +}; export type GQLCircle = GQLNode & { - __typename?: 'Circle' + __typename?: 'Circle'; /** Analytics dashboard. */ - analytics: GQLCircleAnalytics + analytics: GQLCircleAnalytics; /** * Circle avatar's link. * @deprecated No longer in use */ - avatar?: Maybe + avatar?: Maybe; /** Comments broadcasted by Circle owner. */ - broadcast: GQLCommentConnection + broadcast: GQLCommentConnection; /** * Circle cover's link. * @deprecated No longer in use */ - cover?: Maybe + cover?: Maybe; /** * Created time. * @deprecated No longer in use */ - createdAt: Scalars['DateTime']['output'] + createdAt: Scalars['DateTime']['output']; /** A short description of this Circle. */ - description?: Maybe + description?: Maybe; /** Comments made by Circle member. */ - discussion: GQLCommentConnection + discussion: GQLCommentConnection; /** Discussion (include replies) count of this circle. */ - discussionCount: Scalars['Int']['output'] + discussionCount: Scalars['Int']['output']; /** Discussion (exclude replies) count of this circle. */ - discussionThreadCount: Scalars['Int']['output'] + discussionThreadCount: Scalars['Int']['output']; /** * Human readable name of this Circle. * @deprecated No longer in use */ - displayName: Scalars['String']['output'] + displayName: Scalars['String']['output']; /** * List of Circle follower. * @deprecated No longer in use */ - followers: GQLUserConnection + followers: GQLUserConnection; /** Unique ID. */ - id: Scalars['ID']['output'] + id: Scalars['ID']['output']; /** Invitation used by current viewer. */ - invitedBy?: Maybe + invitedBy?: Maybe; /** Invitations belonged to this Circle. */ - invites: GQLInvites + invites: GQLInvites; /** * This value determines if current viewer is following Circle or not. * @deprecated No longer in use */ - isFollower: Scalars['Boolean']['output'] + isFollower: Scalars['Boolean']['output']; /** * This value determines if current viewer is Member or not. * @deprecated No longer in use */ - isMember: Scalars['Boolean']['output'] + isMember: Scalars['Boolean']['output']; /** * List of Circle member. * @deprecated No longer in use */ - members: GQLMemberConnection + members: GQLMemberConnection; /** * Slugified name of this Circle. * @deprecated No longer in use */ - name: Scalars['String']['output'] + name: Scalars['String']['output']; /** Circle owner. */ - owner: GQLUser + owner: GQLUser; /** Pinned comments broadcasted by Circle owner. */ - pinnedBroadcast?: Maybe> + pinnedBroadcast?: Maybe>; /** Prices offered by this Circle. */ - prices?: Maybe> + prices?: Maybe>; /** * State of this Circle. * @deprecated No longer in use */ - state: GQLCircleState + state: GQLCircleState; /** * Updated time. * @deprecated No longer in use */ - updatedAt: Scalars['DateTime']['output'] + updatedAt: Scalars['DateTime']['output']; /** * List of works belong to this Circle. * @deprecated No longer in use */ - works: GQLArticleConnection -} + works: GQLArticleConnection; +}; + export type GQLCircleBroadcastArgs = { - input: GQLCommentsInput -} + input: GQLCommentsInput; +}; + export type GQLCircleDiscussionArgs = { - input: GQLCommentsInput -} + input: GQLCommentsInput; +}; + export type GQLCircleFollowersArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLCircleMembersArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLCircleWorksArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; export type GQLCircleAnalytics = { - __typename?: 'CircleAnalytics' - content: GQLCircleContentAnalytics - follower: GQLCircleFollowerAnalytics - income: GQLCircleIncomeAnalytics - subscriber: GQLCircleSubscriberAnalytics -} + __typename?: 'CircleAnalytics'; + content: GQLCircleContentAnalytics; + follower: GQLCircleFollowerAnalytics; + income: GQLCircleIncomeAnalytics; + subscriber: GQLCircleSubscriberAnalytics; +}; export type GQLCircleConnection = GQLConnection & { - __typename?: 'CircleConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'CircleConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLCircleContentAnalytics = { - __typename?: 'CircleContentAnalytics' - paywall?: Maybe> - public?: Maybe> -} + __typename?: 'CircleContentAnalytics'; + paywall?: Maybe>; + public?: Maybe>; +}; export type GQLCircleContentAnalyticsDatum = { - __typename?: 'CircleContentAnalyticsDatum' - node: GQLArticle - readCount: Scalars['Int']['output'] -} + __typename?: 'CircleContentAnalyticsDatum'; + node: GQLArticle; + readCount: Scalars['Int']['output']; +}; export type GQLCircleEdge = { - __typename?: 'CircleEdge' - cursor: Scalars['String']['output'] - node: GQLCircle -} + __typename?: 'CircleEdge'; + cursor: Scalars['String']['output']; + node: GQLCircle; +}; export type GQLCircleFollowerAnalytics = { - __typename?: 'CircleFollowerAnalytics' + __typename?: 'CircleFollowerAnalytics'; /** current follower count */ - current: Scalars['Int']['output'] + current: Scalars['Int']['output']; /** the percentage of follower count in reader count of circle articles */ - followerPercentage: Scalars['Float']['output'] + followerPercentage: Scalars['Float']['output']; /** subscriber count history of last 4 months */ - history: Array -} + history: Array; +}; export type GQLCircleIncomeAnalytics = { - __typename?: 'CircleIncomeAnalytics' + __typename?: 'CircleIncomeAnalytics'; /** income history of last 4 months */ - history: Array + history: Array; /** income of next month */ - nextMonth: Scalars['Float']['output'] + nextMonth: Scalars['Float']['output']; /** income of this month */ - thisMonth: Scalars['Float']['output'] + thisMonth: Scalars['Float']['output']; /** total income of all time */ - total: Scalars['Float']['output'] -} + total: Scalars['Float']['output']; +}; export type GQLCircleInput = { /** Slugified name of a Circle. */ - name: Scalars['String']['input'] -} + name: Scalars['String']['input']; +}; export type GQLCircleNotice = GQLNotice & { - __typename?: 'CircleNotice' + __typename?: 'CircleNotice'; /** List of notice actors. */ - actors?: Maybe> + actors?: Maybe>; /** Optional discussion/broadcast comments for bundled notices */ - comments?: Maybe> + comments?: Maybe>; /** Time of this notice was created. */ - createdAt: Scalars['DateTime']['output'] + createdAt: Scalars['DateTime']['output']; /** Unique ID of this notice. */ - id: Scalars['ID']['output'] + id: Scalars['ID']['output']; /** Optional mention comments for bundled notices */ - mentions?: Maybe> + mentions?: Maybe>; /** Optional discussion/broadcast replies for bundled notices */ - replies?: Maybe> - target: GQLCircle - type: GQLCircleNoticeType + replies?: Maybe>; + target: GQLCircle; + type: GQLCircleNoticeType; /** The value determines if the notice is unread or not. */ - unread: Scalars['Boolean']['output'] -} + unread: Scalars['Boolean']['output']; +}; export type GQLCircleNoticeType = | 'CircleInvitation' @@ -1213,129 +1234,133 @@ export type GQLCircleNoticeType = | 'CircleNewDiscussionComments' | 'CircleNewFollower' | 'CircleNewSubscriber' - | 'CircleNewUnsubscriber' + | 'CircleNewUnsubscriber'; export type GQLCircleRecommendationActivity = { - __typename?: 'CircleRecommendationActivity' + __typename?: 'CircleRecommendationActivity'; /** Recommended circles */ - nodes?: Maybe> + nodes?: Maybe>; /** The source type of recommendation */ - source?: Maybe -} + source?: Maybe; +}; -export type GQLCircleRecommendationActivitySource = 'UserSubscription' +export type GQLCircleRecommendationActivitySource = + | 'UserSubscription'; -export type GQLCircleState = 'active' | 'archived' +export type GQLCircleState = + | 'active' + | 'archived'; export type GQLCircleSubscriberAnalytics = { - __typename?: 'CircleSubscriberAnalytics' + __typename?: 'CircleSubscriberAnalytics'; /** current invitee count */ - currentInvitee: Scalars['Int']['output'] + currentInvitee: Scalars['Int']['output']; /** current subscriber count */ - currentSubscriber: Scalars['Int']['output'] + currentSubscriber: Scalars['Int']['output']; /** invitee count history of last 4 months */ - inviteeHistory: Array + inviteeHistory: Array; /** subscriber count history of last 4 months */ - subscriberHistory: Array -} + subscriberHistory: Array; +}; export type GQLClaimLogbooksInput = { - ethAddress: Scalars['String']['input'] + ethAddress: Scalars['String']['input']; /** nonce from generateSigningMessage */ - nonce: Scalars['String']['input'] + nonce: Scalars['String']['input']; /** sign'ed by wallet */ - signature: Scalars['String']['input'] + signature: Scalars['String']['input']; /** the message being sign'ed, including nonce */ - signedMessage: Scalars['String']['input'] -} + signedMessage: Scalars['String']['input']; +}; export type GQLClaimLogbooksResult = { - __typename?: 'ClaimLogbooksResult' - ids?: Maybe> - txHash: Scalars['String']['output'] -} + __typename?: 'ClaimLogbooksResult'; + ids?: Maybe>; + txHash: Scalars['String']['output']; +}; export type GQLClaimPersonhoodBadgeInput = { - certChainProof: Scalars['String']['input'] - certChainType?: InputMaybe - handoffToken: Scalars['String']['input'] - userSigProof: Scalars['String']['input'] -} + certChainProof: Scalars['String']['input']; + certChainType?: InputMaybe; + handoffToken: Scalars['String']['input']; + userSigProof: Scalars['String']['input']; +}; export type GQLClassifyArticlesChannelsInput = { - ids: Array -} + ids: Array; +}; export type GQLClearCommunityWatchOriginalContentInput = { - note?: InputMaybe - uuid: Scalars['ID']['input'] -} + note?: InputMaybe; + uuid: Scalars['ID']['input']; +}; export type GQLClearReadHistoryInput = { - id?: InputMaybe -} + id?: InputMaybe; +}; + +export type GQLCollection = GQLNode & GQLPinnableWork & { + __typename?: 'Collection'; + articles: GQLArticleConnection; + author: GQLUser; + /** Check if the collection contains the article */ + contains: Scalars['Boolean']['output']; + cover?: Maybe; + description?: Maybe; + id: Scalars['ID']['output']; + likeCount: Scalars['Int']['output']; + /** whether current user has liked it */ + liked: Scalars['Boolean']['output']; + pinned: Scalars['Boolean']['output']; + title: Scalars['String']['output']; + updatedAt: Scalars['DateTime']['output']; +}; -export type GQLCollection = GQLNode & - GQLPinnableWork & { - __typename?: 'Collection' - articles: GQLArticleConnection - author: GQLUser - /** Check if the collection contains the article */ - contains: Scalars['Boolean']['output'] - cover?: Maybe - description?: Maybe - id: Scalars['ID']['output'] - likeCount: Scalars['Int']['output'] - /** whether current user has liked it */ - liked: Scalars['Boolean']['output'] - pinned: Scalars['Boolean']['output'] - title: Scalars['String']['output'] - updatedAt: Scalars['DateTime']['output'] - } export type GQLCollectionArticlesArgs = { - input: GQLCollectionArticlesInput -} + input: GQLCollectionArticlesInput; +}; + export type GQLCollectionContainsArgs = { - input: GQLNodeInput -} + input: GQLNodeInput; +}; export type GQLCollectionArticlesInput = { - after?: InputMaybe - before?: InputMaybe - first?: InputMaybe - includeAfter?: Scalars['Boolean']['input'] - includeBefore?: Scalars['Boolean']['input'] - last?: InputMaybe - reversed?: Scalars['Boolean']['input'] -} + after?: InputMaybe; + before?: InputMaybe; + first?: InputMaybe; + includeAfter?: Scalars['Boolean']['input']; + includeBefore?: Scalars['Boolean']['input']; + last?: InputMaybe; + reversed?: Scalars['Boolean']['input']; +}; export type GQLCollectionConnection = GQLConnection & { - __typename?: 'CollectionConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'CollectionConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLCollectionEdge = { - __typename?: 'CollectionEdge' - cursor: Scalars['String']['output'] - node: GQLCollection -} + __typename?: 'CollectionEdge'; + cursor: Scalars['String']['output']; + node: GQLCollection; +}; export type GQLCollectionNotice = GQLNotice & { - __typename?: 'CollectionNotice' + __typename?: 'CollectionNotice'; /** List of notice actors. */ - actors?: Maybe> + actors?: Maybe>; /** Time of this notice was created. */ - createdAt: Scalars['DateTime']['output'] + createdAt: Scalars['DateTime']['output']; /** Unique ID of this notice. */ - id: Scalars['ID']['output'] - target: GQLCollection + id: Scalars['ID']['output']; + target: GQLCollection; /** The value determines if the notice is unread or not. */ - unread: Scalars['Boolean']['output'] -} + unread: Scalars['Boolean']['output']; +}; export type GQLColor = | 'brown' @@ -1345,115 +1370,118 @@ export type GQLColor = | 'pink' | 'purple' | 'red' - | 'yellow' + | 'yellow'; /** This type contains content, author, descendant comments and related data of a comment. */ export type GQLComment = GQLNode & { - __typename?: 'Comment' + __typename?: 'Comment'; /** Author of this comment. */ - author: GQLUser + author: GQLUser; /** Descendant comments of this comment. */ - comments: GQLCommentConnection + comments: GQLCommentConnection; /** Community Watch audit action when this comment was removed by Community Watch. */ - communityWatchAction?: Maybe + communityWatchAction?: Maybe; /** Content of this comment. */ - content?: Maybe + content?: Maybe; /** Time of this comment was created. */ - createdAt: Scalars['DateTime']['output'] + createdAt: Scalars['DateTime']['output']; /** * The counting number of downvotes. * @deprecated No longer in use in querying */ - downvotes: Scalars['Int']['output'] + downvotes: Scalars['Int']['output']; /** This value determines this comment is from article donator or not. */ - fromDonator: Scalars['Boolean']['output'] + fromDonator: Scalars['Boolean']['output']; /** Unique ID of this comment. */ - id: Scalars['ID']['output'] + id: Scalars['ID']['output']; /** The value determines current user's vote. */ - myVote?: Maybe + myVote?: Maybe; /** Current comment belongs to which Node. */ - node: GQLNode + node: GQLNode; /** Parent comment of this comment. */ - parentComment?: Maybe + parentComment?: Maybe; /** This value determines this comment is pinned or not. */ - pinned: Scalars['Boolean']['output'] - remark?: Maybe + pinned: Scalars['Boolean']['output']; + remark?: Maybe; /** A Comment that this comment replied to. */ - replyTo?: Maybe - spamStatus: GQLSpamStatus + replyTo?: Maybe; + spamStatus: GQLSpamStatus; /** State of this comment. */ - state: GQLCommentState - type: GQLCommentType + state: GQLCommentState; + type: GQLCommentType; /** The counting number of upvotes. */ - upvotes: Scalars['Int']['output'] -} + upvotes: Scalars['Int']['output']; +}; + /** This type contains content, author, descendant comments and related data of a comment. */ export type GQLCommentCommentsArgs = { - input: GQLCommentCommentsInput -} + input: GQLCommentCommentsInput; +}; export type GQLCommentCommentNotice = GQLNotice & { - __typename?: 'CommentCommentNotice' + __typename?: 'CommentCommentNotice'; /** List of notice actors. */ - actors?: Maybe> - comment: GQLComment + actors?: Maybe>; + comment: GQLComment; /** Time of this notice was created. */ - createdAt: Scalars['DateTime']['output'] + createdAt: Scalars['DateTime']['output']; /** Unique ID of this notice. */ - id: Scalars['ID']['output'] - target: GQLComment - type: GQLCommentCommentNoticeType + id: Scalars['ID']['output']; + target: GQLComment; + type: GQLCommentCommentNoticeType; /** The value determines if the notice is unread or not. */ - unread: Scalars['Boolean']['output'] -} + unread: Scalars['Boolean']['output']; +}; -export type GQLCommentCommentNoticeType = 'CommentNewReply' +export type GQLCommentCommentNoticeType = + | 'CommentNewReply'; export type GQLCommentCommentsInput = { - after?: InputMaybe - author?: InputMaybe - first?: InputMaybe - sort?: InputMaybe -} + after?: InputMaybe; + author?: InputMaybe; + first?: InputMaybe; + sort?: InputMaybe; +}; export type GQLCommentConnection = GQLConnection & { - __typename?: 'CommentConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'CommentConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLCommentEdge = { - __typename?: 'CommentEdge' - cursor: Scalars['String']['output'] - node: GQLComment -} + __typename?: 'CommentEdge'; + cursor: Scalars['String']['output']; + node: GQLComment; +}; export type GQLCommentInput = { - articleId?: InputMaybe - circleId?: InputMaybe - content: Scalars['String']['input'] - mentions?: InputMaybe> - momentId?: InputMaybe - parentId?: InputMaybe - replyTo?: InputMaybe - type: GQLCommentType -} + articleId?: InputMaybe; + campaignId?: InputMaybe; + circleId?: InputMaybe; + content: Scalars['String']['input']; + mentions?: InputMaybe>; + momentId?: InputMaybe; + parentId?: InputMaybe; + replyTo?: InputMaybe; + type: GQLCommentType; +}; export type GQLCommentNotice = GQLNotice & { - __typename?: 'CommentNotice' + __typename?: 'CommentNotice'; /** List of notice actors. */ - actors?: Maybe> + actors?: Maybe>; /** Time of this notice was created. */ - createdAt: Scalars['DateTime']['output'] + createdAt: Scalars['DateTime']['output']; /** Unique ID of this notice. */ - id: Scalars['ID']['output'] - target: GQLComment - type: GQLCommentNoticeType + id: Scalars['ID']['output']; + target: GQLComment; + type: GQLCommentNoticeType; /** The value determines if the notice is unread or not. */ - unread: Scalars['Boolean']['output'] -} + unread: Scalars['Boolean']['output']; +}; export type GQLCommentNoticeType = | 'ArticleNewComment' @@ -1462,376 +1490,411 @@ export type GQLCommentNoticeType = | 'CommentMentionedYou' | 'CommentPinned' | 'MomentNewComment' - | 'SubscribedArticleNewComment' + | 'SubscribedArticleNewComment'; /** Enums for sorting comments by time. */ -export type GQLCommentSort = 'newest' | 'oldest' +export type GQLCommentSort = + | 'newest' + | 'oldest'; /** Enums for comment state. */ -export type GQLCommentState = 'active' | 'archived' | 'banned' | 'collapsed' +export type GQLCommentState = + | 'active' + | 'archived' + | 'banned' + | 'collapsed'; export type GQLCommentType = | 'article' + | 'campaignDiscussion' | 'circleBroadcast' | 'circleDiscussion' - | 'moment' + | 'moment'; export type GQLCommentsFilter = { - author?: InputMaybe - parentComment?: InputMaybe - state?: InputMaybe -} + author?: InputMaybe; + parentComment?: InputMaybe; + state?: InputMaybe; +}; export type GQLCommentsInput = { - after?: InputMaybe - before?: InputMaybe - filter?: InputMaybe - first?: InputMaybe - includeAfter?: InputMaybe - includeBefore?: InputMaybe - sort?: InputMaybe -} + after?: InputMaybe; + before?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + includeAfter?: InputMaybe; + includeBefore?: InputMaybe; + sort?: InputMaybe; +}; export type GQLCommunityWatchAction = { - __typename?: 'CommunityWatchAction' - actionState: GQLCommunityWatchActionState - actorDisplayName: Scalars['String']['output'] - appealState: GQLCommunityWatchAppealState - commentId: Scalars['ID']['output'] - contentCleared: Scalars['Boolean']['output'] + __typename?: 'CommunityWatchAction'; + actionState: GQLCommunityWatchActionState; + actorDisplayName: Scalars['String']['output']; + appealState: GQLCommunityWatchAppealState; + commentId: Scalars['ID']['output']; + contentCleared: Scalars['Boolean']['output']; /** SHA-256 hash of normalized original content for OSS clustering without re-spreading spam text. */ - contentHash?: Maybe - createdAt: Scalars['DateTime']['output'] - originalContent?: Maybe - reason: GQLCommunityWatchRemoveCommentReason + contentHash?: Maybe; + createdAt: Scalars['DateTime']['output']; + originalContent?: Maybe; + reason: GQLCommunityWatchRemoveCommentReason; /** Whether this Community Watch action also created the normal user report flow for staff review. */ - reportSynced: Scalars['Boolean']['output'] - reviewState: GQLCommunityWatchReviewState - sourceId: Scalars['ID']['output'] - sourceTitle: Scalars['String']['output'] - sourceType: GQLCommunityWatchActionSourceType + reportSynced: Scalars['Boolean']['output']; + reviewState: GQLCommunityWatchReviewState; + sourceId: Scalars['ID']['output']; + sourceTitle: Scalars['String']['output']; + sourceType: GQLCommunityWatchActionSourceType; /** Public Matters URL for the removed comment when the source still has a public route. */ - sourceUrl?: Maybe + sourceUrl?: Maybe; /** Public identifier used by the Community Watch transparency page. */ - uuid: Scalars['ID']['output'] -} + uuid: Scalars['ID']['output']; +}; export type GQLCommunityWatchActionConnection = GQLConnection & { - __typename?: 'CommunityWatchActionConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'CommunityWatchActionConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLCommunityWatchActionEdge = { - __typename?: 'CommunityWatchActionEdge' - cursor: Scalars['String']['output'] - node: GQLCommunityWatchAction -} + __typename?: 'CommunityWatchActionEdge'; + cursor: Scalars['String']['output']; + node: GQLCommunityWatchAction; +}; export type GQLCommunityWatchActionInput = { - uuid: Scalars['ID']['input'] -} + uuid: Scalars['ID']['input']; +}; -export type GQLCommunityWatchActionSourceType = 'article' | 'moment' +export type GQLCommunityWatchActionSourceType = + | 'article' + | 'moment'; -export type GQLCommunityWatchActionState = 'active' | 'restored' | 'voided' +export type GQLCommunityWatchActionState = + | 'active' + | 'restored' + | 'voided'; export type GQLCommunityWatchActionsInput = { - actionState?: InputMaybe - after?: InputMaybe - appealState?: InputMaybe - first?: InputMaybe - reason?: InputMaybe - reviewState?: InputMaybe -} - -export type GQLCommunityWatchAppealState = 'none' | 'received' | 'resolved' + actionState?: InputMaybe; + after?: InputMaybe; + appealState?: InputMaybe; + first?: InputMaybe; + reason?: InputMaybe; + reviewState?: InputMaybe; +}; + +export type GQLCommunityWatchAppealState = + | 'none' + | 'received' + | 'resolved'; export type GQLCommunityWatchRemoveCommentInput = { - id: Scalars['ID']['input'] - reason: GQLCommunityWatchRemoveCommentReason -} + id: Scalars['ID']['input']; + reason: GQLCommunityWatchRemoveCommentReason; +}; -export type GQLCommunityWatchRemoveCommentReason = 'porn_ad' | 'spam_ad' +export type GQLCommunityWatchRemoveCommentReason = + | 'porn_ad' + | 'spam_ad'; export type GQLCommunityWatchReviewState = | 'pending' | 'reason_adjusted' | 'reversed' - | 'upheld' + | 'upheld'; export type GQLConfirmVerificationCodeInput = { - code: Scalars['String']['input'] - email: Scalars['String']['input'] - type: GQLVerificationCodeType -} + code: Scalars['String']['input']; + email: Scalars['String']['input']; + type: GQLVerificationCodeType; +}; export type GQLConnectStripeAccountInput = { - country: GQLStripeAccountCountry -} + country: GQLStripeAccountCountry; +}; export type GQLConnectStripeAccountResult = { - __typename?: 'ConnectStripeAccountResult' - redirectUrl: Scalars['String']['output'] -} + __typename?: 'ConnectStripeAccountResult'; + redirectUrl: Scalars['String']['output']; +}; export type GQLConnection = { - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLConnectionArgs = { - after?: InputMaybe - filter?: InputMaybe - first?: InputMaybe - oss?: InputMaybe -} + after?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + oss?: InputMaybe; +}; export type GQLCreatePersonhoodHandoffInput = { - challenge: Scalars['String']['input'] - challengeExpiresAt?: InputMaybe -} + challenge: Scalars['String']['input']; + challengeExpiresAt?: InputMaybe; +}; export type GQLCryptoWallet = { - __typename?: 'CryptoWallet' - address: Scalars['String']['output'] + __typename?: 'CryptoWallet'; + address: Scalars['String']['output']; /** does this address own any Travelogger NFTs? this value is cached at most 1day, and refreshed at next `nfts` query */ - hasNFTs: Scalars['Boolean']['output'] - id: Scalars['ID']['output'] + hasNFTs: Scalars['Boolean']['output']; + id: Scalars['ID']['output']; /** NFT assets owned by this wallet address */ - nfts?: Maybe> -} + nfts?: Maybe>; +}; export type GQLCryptoWalletSignaturePurpose = | 'airdrop' | 'connect' | 'login' - | 'signup' - -export type GQLCurationChannel = GQLChannel & - GQLNode & { - __typename?: 'CurationChannel' - /** both activePeriod and state determine if the channel is active */ - activePeriod: GQLDatetimeRange - articles: GQLChannelArticleConnection - color: GQLColor - id: Scalars['ID']['output'] - name: Scalars['String']['output'] - navbarTitle: Scalars['String']['output'] - note?: Maybe - pinAmount: Scalars['Int']['output'] - shortHash: Scalars['String']['output'] - showRecommendation: Scalars['Boolean']['output'] - state: GQLCurationChannelState - } + | 'signup'; + +export type GQLCurationChannel = GQLChannel & GQLNode & { + __typename?: 'CurationChannel'; + /** both activePeriod and state determine if the channel is active */ + activePeriod: GQLDatetimeRange; + articles: GQLChannelArticleConnection; + color: GQLColor; + id: Scalars['ID']['output']; + name: Scalars['String']['output']; + navbarTitle: Scalars['String']['output']; + note?: Maybe; + pinAmount: Scalars['Int']['output']; + shortHash: Scalars['String']['output']; + showRecommendation: Scalars['Boolean']['output']; + state: GQLCurationChannelState; +}; + export type GQLCurationChannelArticlesArgs = { - input: GQLChannelArticlesInput -} + input: GQLChannelArticlesInput; +}; + export type GQLCurationChannelNameArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; + export type GQLCurationChannelNavbarTitleArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; + export type GQLCurationChannelNoteArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; -export type GQLCurationChannelState = 'archived' | 'editing' | 'published' +export type GQLCurationChannelState = + | 'archived' + | 'editing' + | 'published'; export type GQLDatetimeRange = { - __typename?: 'DatetimeRange' - end?: Maybe - start: Scalars['DateTime']['output'] -} + __typename?: 'DatetimeRange'; + end?: Maybe; + start: Scalars['DateTime']['output']; +}; export type GQLDatetimeRangeInput = { - end?: InputMaybe - start: Scalars['DateTime']['input'] -} + end?: InputMaybe; + start: Scalars['DateTime']['input']; +}; export type GQLDeleteAnnouncementsInput = { - ids?: InputMaybe> -} + ids?: InputMaybe>; +}; export type GQLDeleteCollectionArticlesInput = { - articles: Array - collection: Scalars['ID']['input'] -} + articles: Array; + collection: Scalars['ID']['input']; +}; export type GQLDeleteCollectionsInput = { - ids: Array -} + ids: Array; +}; export type GQLDeleteCommentInput = { - id: Scalars['ID']['input'] -} + id: Scalars['ID']['input']; +}; export type GQLDeleteCurationChannelArticlesInput = { - articles: Array - channel: Scalars['ID']['input'] -} + articles: Array; + channel: Scalars['ID']['input']; +}; export type GQLDeleteDraftInput = { - id: Scalars['ID']['input'] -} + id: Scalars['ID']['input']; +}; export type GQLDeleteMomentInput = { - id: Scalars['ID']['input'] -} + id: Scalars['ID']['input']; +}; + +export type GQLDeleteQuoteInput = { + id: Scalars['ID']['input']; +}; export type GQLDeleteTagsInput = { - ids: Array -} + ids: Array; +}; export type GQLDirectImageUploadInput = { - draft?: InputMaybe - entityId?: InputMaybe - entityType: GQLEntityType - mime?: InputMaybe - type: GQLAssetType - url?: InputMaybe -} + draft?: InputMaybe; + entityId?: InputMaybe; + entityType: GQLEntityType; + mime?: InputMaybe; + type: GQLAssetType; + url?: InputMaybe; +}; + +export type GQLDismissSpamRingInput = { + id: Scalars['ID']['input']; + note?: InputMaybe; +}; -export type GQLDonator = GQLCryptoWallet | GQLUser +export type GQLDonator = GQLCryptoWallet | GQLUser; /** This type contains content, collections, assets and related data of a draft. */ export type GQLDraft = GQLNode & { - __typename?: 'Draft' + __typename?: 'Draft'; /** Access related fields on circle */ - access: GQLDraftAccess + access: GQLDraftAccess; /** Published article */ - article?: Maybe + article?: Maybe; /** List of assets are belonged to this draft. */ - assets: Array + assets: Array; /** Associated campaigns */ - campaigns: Array + campaigns: Array; /** Whether readers can comment */ - canComment: Scalars['Boolean']['output'] + canComment: Scalars['Boolean']['output']; /** @deprecated Use connections instead */ - collection: GQLArticleConnection + collection: GQLArticleConnection; /** Collections of this draft. */ - collections: GQLCollectionConnection + collections: GQLCollectionConnection; /** Connection articles of this draft. */ - connections: GQLArticleConnection + connections: GQLArticleConnection; /** Content (HTML) of this draft. */ - content?: Maybe + content?: Maybe; /** Draft's cover link. */ - cover?: Maybe + cover?: Maybe; /** Time of this draft was created. */ - createdAt: Scalars['DateTime']['output'] + createdAt: Scalars['DateTime']['output']; /** Unique ID of this draft. */ - id: Scalars['ID']['output'] + id: Scalars['ID']['output']; /** Whether the first line of paragraph should be indented */ - indentFirstLine: Scalars['Boolean']['output'] + indentFirstLine: Scalars['Boolean']['output']; /** Whether publish to ISCN */ - iscnPublish?: Maybe + iscnPublish?: Maybe; /** License Type */ - license: GQLArticleLicenseType + license: GQLArticleLicenseType; /** Media hash, composed of cid encoding, of this draft. */ - mediaHash?: Maybe + mediaHash?: Maybe; /** Scheduled publish date of the article. */ - publishAt?: Maybe + publishAt?: Maybe; /** State of draft during publihsing. */ - publishState: GQLPublishState + publishState: GQLPublishState; /** Creator message after support */ - replyToDonator?: Maybe + replyToDonator?: Maybe; /** Creator message asking for support */ - requestForDonation?: Maybe + requestForDonation?: Maybe; /** Whether content is marked as sensitive by author */ - sensitiveByAuthor: Scalars['Boolean']['output'] + sensitiveByAuthor: Scalars['Boolean']['output']; /** Slugified draft title. */ - slug: Scalars['String']['output'] + slug: Scalars['String']['output']; /** Summary of this draft. */ - summary?: Maybe + summary?: Maybe; /** This value determines if the summary is customized or not. */ - summaryCustomized: Scalars['Boolean']['output'] + summaryCustomized: Scalars['Boolean']['output']; /** Tags are attached to this draft. */ - tags?: Maybe> + tags?: Maybe>; /** Draft title. */ - title?: Maybe + title?: Maybe; /** Last time of this draft was upadted. */ - updatedAt: Scalars['DateTime']['output'] + updatedAt: Scalars['DateTime']['output']; /** The counting number of words in this draft. */ - wordCount: Scalars['Int']['output'] -} + wordCount: Scalars['Int']['output']; +}; + /** This type contains content, collections, assets and related data of a draft. */ export type GQLDraftCollectionArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + /** This type contains content, collections, assets and related data of a draft. */ export type GQLDraftCollectionsArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + /** This type contains content, collections, assets and related data of a draft. */ export type GQLDraftConnectionsArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; export type GQLDraftAccess = { - __typename?: 'DraftAccess' - circle?: Maybe - type: GQLArticleAccessType -} + __typename?: 'DraftAccess'; + circle?: Maybe; + type: GQLArticleAccessType; +}; export type GQLDraftConnection = GQLConnection & { - __typename?: 'DraftConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'DraftConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLDraftEdge = { - __typename?: 'DraftEdge' - cursor: Scalars['String']['output'] - node: GQLDraft -} + __typename?: 'DraftEdge'; + cursor: Scalars['String']['output']; + node: GQLDraft; +}; export type GQLEditArticleInput = { - accessType?: InputMaybe + accessType?: InputMaybe; /** which campaigns to attach */ - campaigns?: InputMaybe> + campaigns?: InputMaybe>; /** whether readers can comment */ - canComment?: InputMaybe - circle?: InputMaybe + canComment?: InputMaybe; + circle?: InputMaybe; /** Deprecated, use connections instead */ - collection?: InputMaybe> - collections?: InputMaybe> - connections?: InputMaybe> - content?: InputMaybe - cover?: InputMaybe + collection?: InputMaybe>; + collections?: InputMaybe>; + connections?: InputMaybe>; + content?: InputMaybe; + cover?: InputMaybe; /** revision description */ - description?: InputMaybe - id: Scalars['ID']['input'] - indentFirstLine?: InputMaybe + description?: InputMaybe; + id: Scalars['ID']['input']; + indentFirstLine?: InputMaybe; /** whether publish to ISCN */ - iscnPublish?: InputMaybe - license?: InputMaybe - pinned?: InputMaybe - replyToDonator?: InputMaybe - requestForDonation?: InputMaybe - sensitive?: InputMaybe - state?: InputMaybe - summary?: InputMaybe - tags?: InputMaybe> - title?: InputMaybe -} + iscnPublish?: InputMaybe; + license?: InputMaybe; + pinned?: InputMaybe; + replyToDonator?: InputMaybe; + requestForDonation?: InputMaybe; + sensitive?: InputMaybe; + state?: InputMaybe; + summary?: InputMaybe; + tags?: InputMaybe>; + title?: InputMaybe; +}; export type GQLEmailLoginInput = { - email: Scalars['String']['input'] + email: Scalars['String']['input']; /** used in register */ - language?: InputMaybe - passwordOrCode: Scalars['String']['input'] - referralCode?: InputMaybe -} + language?: InputMaybe; + passwordOrCode: Scalars['String']['input']; + referralCode?: InputMaybe; +}; export type GQLEntityType = | 'announcement' @@ -1842,30 +1905,34 @@ export type GQLEntityType = | 'draft' | 'moment' | 'tag' - | 'user' + | 'user'; export type GQLExchangeRate = { - __typename?: 'ExchangeRate' - from: GQLTransactionCurrency - rate: Scalars['Float']['output'] - to: GQLQuoteCurrency + __typename?: 'ExchangeRate'; + from: GQLTransactionCurrency; + rate: Scalars['Float']['output']; + to: GQLQuoteCurrency; /** Last updated time from currency convertor APIs */ - updatedAt: Scalars['DateTime']['output'] -} + updatedAt: Scalars['DateTime']['output']; +}; export type GQLExchangeRatesInput = { - from?: InputMaybe - to?: InputMaybe -} + from?: InputMaybe; + to?: InputMaybe; +}; export type GQLFeature = { - __typename?: 'Feature' - enabled: Scalars['Boolean']['output'] - name: GQLFeatureName - value?: Maybe -} - -export type GQLFeatureFlag = 'admin' | 'off' | 'on' | 'seeding' + __typename?: 'Feature'; + enabled: Scalars['Boolean']['output']; + name: GQLFeatureName; + value?: Maybe; +}; + +export type GQLFeatureFlag = + | 'admin' + | 'off' + | 'on' + | 'seeding'; export type GQLFeatureName = | 'add_credit' @@ -1878,1143 +1945,1335 @@ export type GQLFeatureName = | 'payout' | 'spam_detection' | 'tag_adoption' - | 'verify_appreciate' + | 'verify_appreciate'; export type GQLFeaturedCommentsInput = { - after?: InputMaybe - first?: InputMaybe - sort?: InputMaybe -} + after?: InputMaybe; + first?: InputMaybe; + sort?: InputMaybe; +}; export type GQLFeaturedTagsInput = { /** tagIds */ - ids: Array -} + ids: Array; +}; export type GQLFederationArticleSettingState = | 'disabled' | 'enabled' - | 'inherit' + | 'inherit'; -export type GQLFederationAuthorSettingState = 'disabled' | 'enabled' +export type GQLFederationAuthorSettingState = + | 'disabled' + | 'enabled'; export type GQLFederationExportDecisionReason = | 'article_disabled' | 'article_not_public' | 'author_not_opted_in' - | 'eligible' + | 'eligible'; export type GQLFilterInput = { - inRangeEnd?: InputMaybe - inRangeStart?: InputMaybe + inRangeEnd?: InputMaybe; + inRangeStart?: InputMaybe; /** Used in User Articles filter, by tags or by time range, or both */ - tagIds?: InputMaybe> -} + tagIds?: InputMaybe>; +}; export type GQLFollowing = { - __typename?: 'Following' - circles: GQLCircleConnection - users: GQLUserConnection -} + __typename?: 'Following'; + circles: GQLCircleConnection; + users: GQLUserConnection; +}; + export type GQLFollowingCirclesArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLFollowingUsersArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; -export type GQLFollowingActivity = - | GQLArticleRecommendationActivity - | GQLCircleRecommendationActivity - | GQLUserAddArticleTagActivity - | GQLUserBroadcastCircleActivity - | GQLUserCreateCircleActivity - | GQLUserPostMomentActivity - | GQLUserPublishArticleActivity - | GQLUserRecommendationActivity +export type GQLFollowingActivity = GQLArticleRecommendationActivity | GQLCircleRecommendationActivity | GQLUserAddArticleTagActivity | GQLUserBroadcastCircleActivity | GQLUserCreateCircleActivity | GQLUserPostMomentActivity | GQLUserPublishArticleActivity | GQLUserRecommendationActivity; export type GQLFollowingActivityConnection = GQLConnection & { - __typename?: 'FollowingActivityConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'FollowingActivityConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLFollowingActivityEdge = { - __typename?: 'FollowingActivityEdge' - cursor: Scalars['String']['output'] - node: GQLFollowingActivity -} + __typename?: 'FollowingActivityEdge'; + cursor: Scalars['String']['output']; + node: GQLFollowingActivity; +}; + +export type GQLFreezeSpamRingInput = { + id: Scalars['ID']['input']; + remark?: InputMaybe; +}; + +export type GQLFreezeSpamRingResult = { + __typename?: 'FreezeSpamRingResult'; + frozen: Array; + ring: GQLSpamRing; + /** Members not banned (old account, high karma, already banned, archived…) — for manual review. */ + skipped: Array; +}; export type GQLFrequentSearchInput = { - first?: InputMaybe - key?: InputMaybe -} + first?: InputMaybe; + key?: InputMaybe; +}; export type GQLGenerateSigningMessageInput = { - address: Scalars['String']['input'] - purpose?: InputMaybe -} + address: Scalars['String']['input']; + purpose?: InputMaybe; +}; -export type GQLGrantType = 'authorization_code' | 'refresh_token' +export type GQLGrantType = + | 'authorization_code' + | 'refresh_token'; export type GQLIcymiTopic = GQLNode & { - __typename?: 'IcymiTopic' - archivedAt?: Maybe - articles: Array - id: Scalars['ID']['output'] - note?: Maybe - pinAmount: Scalars['Int']['output'] - publishedAt?: Maybe - state: GQLIcymiTopicState - title: Scalars['String']['output'] -} + __typename?: 'IcymiTopic'; + archivedAt?: Maybe; + articles: Array; + id: Scalars['ID']['output']; + note?: Maybe; + pinAmount: Scalars['Int']['output']; + publishedAt?: Maybe; + state: GQLIcymiTopicState; + title: Scalars['String']['output']; +}; + export type GQLIcymiTopicNoteArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; + export type GQLIcymiTopicTitleArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; export type GQLIcymiTopicConnection = GQLConnection & { - __typename?: 'IcymiTopicConnection' - edges: Array - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'IcymiTopicConnection'; + edges: Array; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLIcymiTopicEdge = { - __typename?: 'IcymiTopicEdge' - cursor: Scalars['String']['output'] - node: GQLIcymiTopic -} + __typename?: 'IcymiTopicEdge'; + cursor: Scalars['String']['output']; + node: GQLIcymiTopic; +}; -export type GQLIcymiTopicState = 'archived' | 'editing' | 'published' +export type GQLIcymiTopicState = + | 'archived' + | 'editing' + | 'published'; export type GQLIdentityInput = { - id?: InputMaybe - shortHash?: InputMaybe -} + id?: InputMaybe; + shortHash?: InputMaybe; +}; export type GQLInvitation = { - __typename?: 'Invitation' + __typename?: 'Invitation'; /** Accepted time. */ - acceptedAt?: Maybe + acceptedAt?: Maybe; /** Invitation of current Circle. */ - circle: GQLCircle + circle: GQLCircle; /** Created time. */ - createdAt: Scalars['DateTime']['output'] + createdAt: Scalars['DateTime']['output']; /** Free period of this invitation. */ - freePeriod: Scalars['Int']['output'] + freePeriod: Scalars['Int']['output']; /** Unique ID. */ - id: Scalars['ID']['output'] + id: Scalars['ID']['output']; /** Target person of this invitation. */ - invitee: GQLInvitee + invitee: GQLInvitee; /** Creator of this invitation. */ - inviter: GQLUser + inviter: GQLUser; /** Sent time. */ - sentAt: Scalars['DateTime']['output'] + sentAt: Scalars['DateTime']['output']; /** Determine it's specific state. */ - state: GQLInvitationState -} + state: GQLInvitationState; +}; export type GQLInvitationConnection = GQLConnection & { - __typename?: 'InvitationConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'InvitationConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLInvitationEdge = { - __typename?: 'InvitationEdge' - cursor: Scalars['String']['output'] - node: GQLInvitation -} + __typename?: 'InvitationEdge'; + cursor: Scalars['String']['output']; + node: GQLInvitation; +}; export type GQLInvitationState = | 'accepted' | 'pending' | 'transfer_failed' - | 'transfer_succeeded' + | 'transfer_succeeded'; export type GQLInviteCircleInput = { - circleId: Scalars['ID']['input'] - freePeriod: Scalars['Int']['input'] - invitees: Array -} + circleId: Scalars['ID']['input']; + freePeriod: Scalars['Int']['input']; + invitees: Array; +}; export type GQLInviteCircleInvitee = { - email?: InputMaybe - id?: InputMaybe -} + email?: InputMaybe; + id?: InputMaybe; +}; -export type GQLInvitee = GQLPerson | GQLUser +export type GQLInvitee = GQLPerson | GQLUser; export type GQLInvites = { - __typename?: 'Invites' + __typename?: 'Invites'; /** Accepted invitation list */ - accepted: GQLInvitationConnection + accepted: GQLInvitationConnection; /** Pending invitation list */ - pending: GQLInvitationConnection -} + pending: GQLInvitationConnection; +}; + export type GQLInvitesAcceptedArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLInvitesPendingArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; export type GQLKeywordInput = { - keyword: Scalars['String']['input'] -} + keyword: Scalars['String']['input']; +}; export type GQLKeywordsInput = { - keywords?: InputMaybe> -} + keywords?: InputMaybe>; +}; export type GQLLikeCollectionInput = { - id: Scalars['ID']['input'] -} + id: Scalars['ID']['input']; +}; export type GQLLikeMomentInput = { - id: Scalars['ID']['input'] -} + id: Scalars['ID']['input']; +}; export type GQLLiker = { - __typename?: 'Liker' + __typename?: 'Liker'; /** Whether liker is a civic liker */ - civicLiker: Scalars['Boolean']['output'] + civicLiker: Scalars['Boolean']['output']; /** Liker ID of LikeCoin */ - likerId?: Maybe + likerId?: Maybe; /** Total LIKE left in wallet. */ - total: Scalars['Float']['output'] -} + total: Scalars['Float']['output']; +}; export type GQLLogRecordInput = { - type: GQLLogRecordTypes -} + type: GQLLogRecordTypes; +}; export type GQLLogRecordTypes = | 'ReadFolloweeArticles' | 'ReadFollowingFeed' - | 'ReadResponseInfoPopUp' + | 'ReadResponseInfoPopUp'; export type GQLMember = { - __typename?: 'Member' + __typename?: 'Member'; /** Price chosen by user when joining a Circle. */ - price: GQLPrice + price: GQLPrice; /** User who join to a Circle. */ - user: GQLUser -} + user: GQLUser; +}; export type GQLMemberConnection = GQLConnection & { - __typename?: 'MemberConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'MemberConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLMemberEdge = { - __typename?: 'MemberEdge' - cursor: Scalars['String']['output'] - node: GQLMember -} + __typename?: 'MemberEdge'; + cursor: Scalars['String']['output']; + node: GQLMember; +}; export type GQLMergeTagsInput = { - content: Scalars['String']['input'] - ids: Array -} + content: Scalars['String']['input']; + ids: Array; +}; export type GQLMigrationInput = { - files: Array> - type?: InputMaybe -} + files: Array>; + type?: InputMaybe; +}; -export type GQLMigrationType = 'medium' +export type GQLMigrationType = + | 'medium'; export type GQLMoment = GQLNode & { - __typename?: 'Moment' - adStatus: GQLAdStatus - articles: Array - assets: Array - author: GQLUser - commentCount: Scalars['Int']['output'] - commentedFollowees: Array - comments: GQLCommentConnection - content?: Maybe - createdAt: Scalars['DateTime']['output'] - id: Scalars['ID']['output'] - likeCount: Scalars['Int']['output'] + __typename?: 'Moment'; + adStatus: GQLAdStatus; + articles: Array; + assets: Array; + author: GQLUser; + commentCount: Scalars['Int']['output']; + commentedFollowees: Array; + comments: GQLCommentConnection; + content?: Maybe; + createdAt: Scalars['DateTime']['output']; + id: Scalars['ID']['output']; + likeCount: Scalars['Int']['output']; /** whether current user has liked it */ - liked: Scalars['Boolean']['output'] - shortHash: Scalars['String']['output'] - spamStatus: GQLSpamStatus - state: GQLMomentState - tags: Array> -} + liked: Scalars['Boolean']['output']; + shortHash: Scalars['String']['output']; + spamStatus: GQLSpamStatus; + state: GQLMomentState; + tags: Array>; +}; + export type GQLMomentCommentsArgs = { - input: GQLCommentsInput -} + input: GQLCommentsInput; +}; export type GQLMomentConnection = GQLConnection & { - __typename?: 'MomentConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'MomentConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLMomentEdge = { - __typename?: 'MomentEdge' - cursor: Scalars['String']['output'] - node: GQLMoment -} + __typename?: 'MomentEdge'; + cursor: Scalars['String']['output']; + node: GQLMoment; +}; export type GQLMomentFeedApplication = { - __typename?: 'MomentFeedApplication' - createdAt: Scalars['DateTime']['output'] - reviewedBy?: Maybe - reviewer?: Maybe - state: GQLMomentFeedUserState - updatedAt: Scalars['DateTime']['output'] -} - -export type GQLMomentFeedUserReviewedBy = 'admin' | 'seed' | 'system' + __typename?: 'MomentFeedApplication'; + createdAt: Scalars['DateTime']['output']; + reviewedBy?: Maybe; + reviewer?: Maybe; + state: GQLMomentFeedUserState; + updatedAt: Scalars['DateTime']['output']; +}; + +export type GQLMomentFeedUserReviewedBy = + | 'admin' + | 'seed' + | 'system'; export type GQLMomentFeedUserState = | 'approved' | 'pending' | 'rejected' - | 'revoked' + | 'revoked'; export type GQLMomentFeedUsersInput = { - after?: InputMaybe - first?: InputMaybe - states?: InputMaybe> - userName?: InputMaybe -} + after?: InputMaybe; + first?: InputMaybe; + states?: InputMaybe>; + userName?: InputMaybe; +}; export type GQLMomentInput = { - shortHash: Scalars['String']['input'] -} + shortHash: Scalars['String']['input']; +}; export type GQLMomentNotice = GQLNotice & { - __typename?: 'MomentNotice' + __typename?: 'MomentNotice'; /** List of notice actors. */ - actors?: Maybe> + actors?: Maybe>; /** Time of this notice was created. */ - createdAt: Scalars['DateTime']['output'] + createdAt: Scalars['DateTime']['output']; /** Unique ID of this notice. */ - id: Scalars['ID']['output'] - target: GQLMoment - type: GQLMomentNoticeType + id: Scalars['ID']['output']; + target: GQLMoment; + type: GQLMomentNoticeType; /** The value determines if the notice is unread or not. */ - unread: Scalars['Boolean']['output'] -} + unread: Scalars['Boolean']['output']; +}; -export type GQLMomentNoticeType = 'MomentLiked' | 'MomentMentionedYou' +export type GQLMomentNoticeType = + | 'MomentLiked' + | 'MomentMentionedYou'; -export type GQLMomentState = 'active' | 'archived' +export type GQLMomentState = + | 'active' + | 'archived'; export type GQLMonthlyDatum = { - __typename?: 'MonthlyDatum' - date: Scalars['DateTime']['output'] - value: Scalars['Float']['output'] -} + __typename?: 'MonthlyDatum'; + date: Scalars['DateTime']['output']; + value: Scalars['Float']['output']; +}; export type GQLMutation = { - __typename?: 'Mutation' + __typename?: 'Mutation'; /** Add blocked search keyword to blocked_search_word db */ - addBlockedSearchKeyword: GQLBlockedSearchKeyword + addBlockedSearchKeyword: GQLBlockedSearchKeyword; /** Add articles to the begining of the collections. */ - addCollectionsArticles: Array + addCollectionsArticles: Array; /** Add Credit to User Wallet */ - addCredit: GQLAddCreditResult - addCurationChannelArticles: GQLCurationChannel + addCredit: GQLAddCreditResult; + addCurationChannelArticles: GQLCurationChannel; /** Add a social login to current user. */ - addSocialLogin: GQLUser + addSocialLogin: GQLUser; /** Add a wallet login to current user. */ - addWalletLogin: GQLUser - applyCampaign: GQLCampaign - applyMomentFeed: GQLUser + addWalletLogin: GQLUser; + applyCampaign: GQLCampaign; + applyMomentFeed: GQLUser; /** Appreciate an article. */ - appreciateArticle: GQLArticle + appreciateArticle: GQLArticle; /** Archive multiple users from OSS with per-user results. */ - archiveUsers: GQLArchiveUsersResult - banCampaignArticles: GQLCampaign + archiveUsers: GQLArchiveUsersResult; + banCampaignArticles: GQLCampaign; /** Let Traveloggers owner claims a Logbook, returns transaction hash */ - claimLogbooks: GQLClaimLogbooksResult + claimLogbooks: GQLClaimLogbooksResult; /** Claim the carbon based badge with a verified zkID personhood proof. */ - claimPersonhoodBadge: GQLUser - classifyArticlesChannels: Scalars['Boolean']['output'] + claimPersonhoodBadge: GQLUser; + classifyArticlesChannels: Scalars['Boolean']['output']; /** Clear stored original content for a Community Watch action as staff. */ - clearCommunityWatchOriginalContent: GQLCommunityWatchAction + clearCommunityWatchOriginalContent: GQLCommunityWatchAction; /** Clear read history for user. */ - clearReadHistory: GQLUser + clearReadHistory: GQLUser; /** Clear search history for user. */ - clearSearchHistory?: Maybe + clearSearchHistory?: Maybe; /** Remove a spam comment as a Community Watch member. */ - communityWatchRemoveComment: GQLComment + communityWatchRemoveComment: GQLComment; /** Confirm verification code from email. */ - confirmVerificationCode: Scalars['ID']['output'] + confirmVerificationCode: Scalars['ID']['output']; /** Create Stripe Connect account for Payout */ - connectStripeAccount: GQLConnectStripeAccountResult + connectStripeAccount: GQLConnectStripeAccountResult; /** Create a short-lived token that binds a verifier challenge to the current viewer. */ - createPersonhoodHandoff: GQLPersonhoodHandoff - deleteAnnouncements: Scalars['Boolean']['output'] + createPersonhoodHandoff: GQLPersonhoodHandoff; + deleteAnnouncements: Scalars['Boolean']['output']; /** Delete blocked search keywords from search_history db */ - deleteBlockedSearchKeywords?: Maybe + deleteBlockedSearchKeywords?: Maybe; /** Remove articles from the collection. */ - deleteCollectionArticles: GQLCollection - deleteCollections: Scalars['Boolean']['output'] + deleteCollectionArticles: GQLCollection; + deleteCollections: Scalars['Boolean']['output']; /** Remove a comment. */ - deleteComment: GQLComment - deleteCurationChannelArticles: GQLCurationChannel + deleteComment: GQLComment; + deleteCurationChannelArticles: GQLCurationChannel; /** Remove a draft. */ - deleteDraft?: Maybe - deleteMoment: GQLMoment - deleteTags?: Maybe - directImageUpload: GQLAsset + deleteDraft?: Maybe; + deleteMoment: GQLMoment; + /** Retract a quote from the wall (poster, source article author, or admin). */ + deleteQuote: Scalars['Boolean']['output']; + deleteTags?: Maybe; + directImageUpload: GQLAsset; + /** Mark a spam ring as a false positive (feeds training as ham). OSS. */ + dismissSpamRing: GQLSpamRing; /** Edit an article. */ - editArticle: GQLArticle + editArticle: GQLArticle; /** Login user. */ - emailLogin: GQLAuthResult + emailLogin: GQLAuthResult; + /** Freeze a spam ring: permanently (but reversibly) ban all member accounts. OSS. */ + freezeSpamRing: GQLFreezeSpamRingResult; /** Get signing message. */ - generateSigningMessage: GQLSigningMessageResult + generateSigningMessage: GQLSigningMessageResult; /** Invite others to join circle */ - invite?: Maybe> - likeCollection: GQLCollection - likeMoment: GQLMoment + invite?: Maybe>; + likeCollection: GQLCollection; + likeMoment: GQLMoment; /** Add specific user behavior record. */ - logRecord?: Maybe + logRecord?: Maybe; /** Mark all received notices as read. */ - markAllNoticesAsRead?: Maybe - mergeTags: GQLTag + markAllNoticesAsRead?: Maybe; + mergeTags: GQLTag; /** Migrate articles from other service provider. */ - migration?: Maybe + migration?: Maybe; /** Pay to another user or article */ - payTo: GQLPayToResult + payTo: GQLPayToResult; /** Payout to user */ - payout: GQLTransaction + payout: GQLTransaction; /** Pin a comment. */ - pinComment: GQLComment + pinComment: GQLComment; /** Publish an article onto IPFS. */ - publishArticle: GQLDraft - putAnnouncement: GQLAnnouncement - putArticleFederationSetting: GQLArticleFederationSetting + publishArticle: GQLDraft; + putAnnouncement: GQLAnnouncement; + putArticleFederationSetting: GQLArticleFederationSetting; /** Create or update a Circle. */ - putCircle: GQLCircle + putCircle: GQLCircle; /** * Add or remove Circle's articles * @deprecated No longer in use */ - putCircleArticles: GQLCircle - putCollection: GQLCollection + putCircleArticles: GQLCircle; + putCollection: GQLCollection; /** Publish or update a comment. */ - putComment: GQLComment - putCurationChannel: GQLCurationChannel + putComment: GQLComment; + putCurationChannel: GQLCurationChannel; /** Create or update a draft. */ - putDraft: GQLDraft + putDraft: GQLDraft; /** update tags for showing on profile page */ - putFeaturedTags?: Maybe> - putIcymiTopic?: Maybe - putMoment: GQLMoment + putFeaturedTags?: Maybe>; + putIcymiTopic?: Maybe; + putMoment: GQLMoment; /** Create or Update an OAuth Client, used in OSS. */ - putOAuthClient?: Maybe - putRemark?: Maybe - putRestrictedUsers: Array - putSkippedListItem?: Maybe> - putTagChannel: GQLTag - putTopicChannel: GQLTopicChannel - putUserFeatureFlags: Array - putUserFederationSetting: GQLUserFederationSetting - putWritingChallenge: GQLWritingChallenge + putOAuthClient?: Maybe; + /** Post a quote (selected from an article) onto the campaign quote wall. */ + putQuote: GQLQuote; + putRemark?: Maybe; + putRestrictedUsers: Array; + putSkippedListItem?: Maybe>; + putTagChannel: GQLTag; + putTopicChannel: GQLTopicChannel; + putUserFeatureFlags: Array; + putUserFederationSetting: GQLUserFederationSetting; + putWritingChallenge: GQLWritingChallenge; /** Read an article. */ - readArticle: GQLArticle + readArticle: GQLArticle; /** Remove a social login from current user. */ - removeSocialLogin: GQLUser + removeSocialLogin: GQLUser; /** Remove a wallet login from current user. */ - removeWalletLogin: GQLUser - renameTag: GQLTag - reorderChannels: Scalars['Boolean']['output'] + removeWalletLogin: GQLUser; + renameTag: GQLTag; + reorderChannels: Scalars['Boolean']['output']; /** Reorder articles in the collection. */ - reorderCollectionArticles: GQLCollection + reorderCollectionArticles: GQLCollection; /** Reset Liker ID */ - resetLikerId: GQLUser + resetLikerId: GQLUser; /** Reset user or payment password. */ - resetPassword?: Maybe + resetPassword?: Maybe; /** Restore a comment removed by Community Watch as staff. */ - restoreCommunityWatchComment: GQLCommunityWatchAction - reviewTopicChannelFeedback: GQLTopicChannelFeedback - sendCampaignAnnouncement?: Maybe + restoreCommunityWatchComment: GQLCommunityWatchAction; + reviewTopicChannelFeedback: GQLTopicChannelFeedback; + sendCampaignAnnouncement?: Maybe; /** Send verification code for email. */ - sendVerificationCode?: Maybe - setAdStatus: GQLArticle + sendVerificationCode?: Maybe; + setAdStatus: GQLArticle; /** Set current author's Fediverse federation preference for an article. */ - setArticleFederationSetting: GQLArticleFederationSetting - setArticleTopicChannels: GQLArticle - setBoost: GQLNode + setArticleFederationSetting: GQLArticleFederationSetting; + setArticleTopicChannels: GQLArticle; + setBoost: GQLNode; /** Set user currency preference. */ - setCurrency: GQLUser + setCurrency: GQLUser; /** Set user email. */ - setEmail: GQLUser - setFeature: GQLFeature + setEmail: GQLUser; + setFeature: GQLFeature; /** Set user email login password. */ - setPassword: GQLUser - setSpamStatus: GQLWriting + setPassword: GQLUser; + setSpamStatus: GQLWriting; /** Set user name. */ - setUserName: GQLUser + setUserName: GQLUser; /** Set current viewer's Fediverse federation preference. */ - setViewerFederationSetting: GQLUserFederationSetting - setWritingAdStatus: GQLWriting + setViewerFederationSetting: GQLUserFederationSetting; + setWritingAdStatus: GQLWriting; /** Upload a single file. */ - singleFileUpload: GQLAsset + singleFileUpload: GQLAsset; /** Login/Signup via social accounts. */ - socialLogin: GQLAuthResult + socialLogin: GQLAuthResult; /** Submit inappropriate content report */ - submitReport: GQLReport + submitReport: GQLReport; /** Feedback on topic channel classification */ - submitTopicChannelFeedback: GQLTopicChannelFeedback + submitTopicChannelFeedback: GQLTopicChannelFeedback; /** Subscribe a Circle. */ - subscribeCircle: GQLSubscribeCircleResult - toggleArticleRecommend: GQLArticle + subscribeCircle: GQLSubscribeCircleResult; + toggleArticleRecommend: GQLArticle; /** Block or Unblock a given user. */ - toggleBlockUser: GQLUser - toggleBookmarkArticle: GQLArticle - toggleBookmarkTag: GQLTag + toggleBlockUser: GQLUser; + toggleBookmarkArticle: GQLArticle; + toggleBookmarkTag: GQLTag; /** * Follow or unfollow a Circle. * @deprecated No longer in use */ - toggleFollowCircle: GQLCircle + toggleFollowCircle: GQLCircle; /** * Bookmark or unbookmark tag. * @deprecated Use toggleBookmarkTag instead */ - toggleFollowTag: GQLTag + toggleFollowTag: GQLTag; /** Follow or Unfollow current user. */ - toggleFollowUser: GQLUser - togglePinChannelArticles: Array + toggleFollowUser: GQLUser; + togglePinChannelArticles: Array; /** Pin or Unpin a comment. */ - togglePinComment: GQLComment - toggleSeedingUsers: Array> + togglePinComment: GQLComment; + toggleSeedingUsers: Array>; /** * Bookmark or unbookmark article * @deprecated Use toggleBookmarkArticle instead */ - toggleSubscribeArticle: GQLArticle - toggleUsersBadge: Array> - toggleWritingChallengeFeaturedArticles: GQLCampaign - unbindLikerId: GQLUser - unlikeCollection: GQLCollection - unlikeMoment: GQLMoment + toggleSubscribeArticle: GQLArticle; + toggleUsersBadge: Array>; + toggleWritingChallengeFeaturedArticles: GQLCampaign; + unbindLikerId: GQLUser; + /** Reverse a spam ring freeze: unban only the members this ring banned. OSS. */ + unfreezeSpamRing: GQLUnfreezeSpamRingResult; + unlikeCollection: GQLCollection; + unlikeMoment: GQLMoment; /** Unpin a comment. */ - unpinComment: GQLComment + unpinComment: GQLComment; /** Unsubscribe a Circle. */ - unsubscribeCircle: GQLCircle + unsubscribeCircle: GQLCircle; /** Unvote a comment. */ - unvoteComment: GQLComment - updateArticleSensitive: GQLArticle - updateArticleState: GQLArticle - updateCampaignApplicationState: GQLCampaign + unvoteComment: GQLComment; + updateArticleSensitive: GQLArticle; + updateArticleState: GQLArticle; + updateCampaignApplicationState: GQLCampaign; /** Update a comments' state. */ - updateCommentsState: Array + updateCommentsState: Array; /** Update Community Watch appeal, review, or reason as staff. */ - updateCommunityWatchActionState: GQLCommunityWatchAction - updateMomentFeedApplicationState: GQLUser + updateCommunityWatchActionState: GQLCommunityWatchAction; + updateMomentFeedApplicationState: GQLUser; /** Update user notification settings. */ - updateNotificationSetting: GQLUser + updateNotificationSetting: GQLUser; /** Update referralCode of a user, used in OSS. */ - updateUserExtra: GQLUser + updateUserExtra: GQLUser; /** Update user information. */ - updateUserInfo: GQLUser + updateUserInfo: GQLUser; /** Update state of a user, used in OSS. */ - updateUserRole: GQLUser + updateUserRole: GQLUser; /** Update state of a user, used in OSS. */ - updateUserState?: Maybe> + updateUserState?: Maybe>; + /** Upsert spam ring candidates from the detection job (admin service principal). OSS. */ + upsertSpamRingCandidates: GQLUpsertSpamRingCandidatesResult; /** Logout user. */ - userLogout: Scalars['Boolean']['output'] + userLogout: Scalars['Boolean']['output']; /** Verify user email. */ - verifyEmail: GQLAuthResult + verifyEmail: GQLAuthResult; /** Upvote or downvote a comment. */ - voteComment: GQLComment + voteComment: GQLComment; /** Login/Signup via a wallet. */ - walletLogin: GQLAuthResult + walletLogin: GQLAuthResult; /** Withdraw locked ERC20/native token from donation vault */ - withdrawLockedTokens: GQLWithdrawLockedTokensResult -} + withdrawLockedTokens: GQLWithdrawLockedTokensResult; +}; + export type GQLMutationAddBlockedSearchKeywordArgs = { - input: GQLKeywordInput -} + input: GQLKeywordInput; +}; + export type GQLMutationAddCollectionsArticlesArgs = { - input: GQLAddCollectionsArticlesInput -} + input: GQLAddCollectionsArticlesInput; +}; + export type GQLMutationAddCreditArgs = { - input: GQLAddCreditInput -} + input: GQLAddCreditInput; +}; + export type GQLMutationAddCurationChannelArticlesArgs = { - input: GQLAddCurationChannelArticlesInput -} + input: GQLAddCurationChannelArticlesInput; +}; + export type GQLMutationAddSocialLoginArgs = { - input: GQLSocialLoginInput -} + input: GQLSocialLoginInput; +}; + export type GQLMutationAddWalletLoginArgs = { - input: GQLWalletLoginInput -} + input: GQLWalletLoginInput; +}; + export type GQLMutationApplyCampaignArgs = { - input: GQLApplyCampaignInput -} + input: GQLApplyCampaignInput; +}; + export type GQLMutationAppreciateArticleArgs = { - input: GQLAppreciateArticleInput -} + input: GQLAppreciateArticleInput; +}; + export type GQLMutationArchiveUsersArgs = { - input: GQLArchiveUsersInput -} + input: GQLArchiveUsersInput; +}; + export type GQLMutationBanCampaignArticlesArgs = { - input: GQLBanCampaignArticlesInput -} + input: GQLBanCampaignArticlesInput; +}; + export type GQLMutationClaimLogbooksArgs = { - input: GQLClaimLogbooksInput -} + input: GQLClaimLogbooksInput; +}; + export type GQLMutationClaimPersonhoodBadgeArgs = { - input: GQLClaimPersonhoodBadgeInput -} + input: GQLClaimPersonhoodBadgeInput; +}; + export type GQLMutationClassifyArticlesChannelsArgs = { - input: GQLClassifyArticlesChannelsInput -} + input: GQLClassifyArticlesChannelsInput; +}; + export type GQLMutationClearCommunityWatchOriginalContentArgs = { - input: GQLClearCommunityWatchOriginalContentInput -} + input: GQLClearCommunityWatchOriginalContentInput; +}; + export type GQLMutationClearReadHistoryArgs = { - input: GQLClearReadHistoryInput -} + input: GQLClearReadHistoryInput; +}; + export type GQLMutationCommunityWatchRemoveCommentArgs = { - input: GQLCommunityWatchRemoveCommentInput -} + input: GQLCommunityWatchRemoveCommentInput; +}; + export type GQLMutationConfirmVerificationCodeArgs = { - input: GQLConfirmVerificationCodeInput -} + input: GQLConfirmVerificationCodeInput; +}; + export type GQLMutationConnectStripeAccountArgs = { - input: GQLConnectStripeAccountInput -} + input: GQLConnectStripeAccountInput; +}; + export type GQLMutationCreatePersonhoodHandoffArgs = { - input: GQLCreatePersonhoodHandoffInput -} + input: GQLCreatePersonhoodHandoffInput; +}; + export type GQLMutationDeleteAnnouncementsArgs = { - input: GQLDeleteAnnouncementsInput -} + input: GQLDeleteAnnouncementsInput; +}; + export type GQLMutationDeleteBlockedSearchKeywordsArgs = { - input: GQLKeywordsInput -} + input: GQLKeywordsInput; +}; + export type GQLMutationDeleteCollectionArticlesArgs = { - input: GQLDeleteCollectionArticlesInput -} + input: GQLDeleteCollectionArticlesInput; +}; + export type GQLMutationDeleteCollectionsArgs = { - input: GQLDeleteCollectionsInput -} + input: GQLDeleteCollectionsInput; +}; + export type GQLMutationDeleteCommentArgs = { - input: GQLDeleteCommentInput -} + input: GQLDeleteCommentInput; +}; + export type GQLMutationDeleteCurationChannelArticlesArgs = { - input: GQLDeleteCurationChannelArticlesInput -} + input: GQLDeleteCurationChannelArticlesInput; +}; + export type GQLMutationDeleteDraftArgs = { - input: GQLDeleteDraftInput -} + input: GQLDeleteDraftInput; +}; + export type GQLMutationDeleteMomentArgs = { - input: GQLDeleteMomentInput -} + input: GQLDeleteMomentInput; +}; + + +export type GQLMutationDeleteQuoteArgs = { + input: GQLDeleteQuoteInput; +}; + export type GQLMutationDeleteTagsArgs = { - input: GQLDeleteTagsInput -} + input: GQLDeleteTagsInput; +}; + export type GQLMutationDirectImageUploadArgs = { - input: GQLDirectImageUploadInput -} + input: GQLDirectImageUploadInput; +}; + + +export type GQLMutationDismissSpamRingArgs = { + input: GQLDismissSpamRingInput; +}; + export type GQLMutationEditArticleArgs = { - input: GQLEditArticleInput -} + input: GQLEditArticleInput; +}; + export type GQLMutationEmailLoginArgs = { - input: GQLEmailLoginInput -} + input: GQLEmailLoginInput; +}; + + +export type GQLMutationFreezeSpamRingArgs = { + input: GQLFreezeSpamRingInput; +}; + export type GQLMutationGenerateSigningMessageArgs = { - input: GQLGenerateSigningMessageInput -} + input: GQLGenerateSigningMessageInput; +}; + export type GQLMutationInviteArgs = { - input: GQLInviteCircleInput -} + input: GQLInviteCircleInput; +}; + export type GQLMutationLikeCollectionArgs = { - input: GQLLikeCollectionInput -} + input: GQLLikeCollectionInput; +}; + export type GQLMutationLikeMomentArgs = { - input: GQLLikeMomentInput -} + input: GQLLikeMomentInput; +}; + export type GQLMutationLogRecordArgs = { - input: GQLLogRecordInput -} + input: GQLLogRecordInput; +}; + export type GQLMutationMergeTagsArgs = { - input: GQLMergeTagsInput -} + input: GQLMergeTagsInput; +}; + export type GQLMutationMigrationArgs = { - input: GQLMigrationInput -} + input: GQLMigrationInput; +}; + export type GQLMutationPayToArgs = { - input: GQLPayToInput -} + input: GQLPayToInput; +}; + export type GQLMutationPayoutArgs = { - input: GQLPayoutInput -} + input: GQLPayoutInput; +}; + export type GQLMutationPinCommentArgs = { - input: GQLPinCommentInput -} + input: GQLPinCommentInput; +}; + export type GQLMutationPublishArticleArgs = { - input: GQLPublishArticleInput -} + input: GQLPublishArticleInput; +}; + export type GQLMutationPutAnnouncementArgs = { - input: GQLPutAnnouncementInput -} + input: GQLPutAnnouncementInput; +}; + export type GQLMutationPutArticleFederationSettingArgs = { - input: GQLPutArticleFederationSettingInput -} + input: GQLPutArticleFederationSettingInput; +}; + export type GQLMutationPutCircleArgs = { - input: GQLPutCircleInput -} + input: GQLPutCircleInput; +}; + export type GQLMutationPutCircleArticlesArgs = { - input: GQLPutCircleArticlesInput -} + input: GQLPutCircleArticlesInput; +}; + export type GQLMutationPutCollectionArgs = { - input: GQLPutCollectionInput -} + input: GQLPutCollectionInput; +}; + export type GQLMutationPutCommentArgs = { - input: GQLPutCommentInput -} + input: GQLPutCommentInput; +}; + export type GQLMutationPutCurationChannelArgs = { - input: GQLPutCurationChannelInput -} + input: GQLPutCurationChannelInput; +}; + export type GQLMutationPutDraftArgs = { - input: GQLPutDraftInput -} + input: GQLPutDraftInput; +}; + export type GQLMutationPutFeaturedTagsArgs = { - input: GQLFeaturedTagsInput -} + input: GQLFeaturedTagsInput; +}; + export type GQLMutationPutIcymiTopicArgs = { - input: GQLPutIcymiTopicInput -} + input: GQLPutIcymiTopicInput; +}; + export type GQLMutationPutMomentArgs = { - input: GQLPutMomentInput -} + input: GQLPutMomentInput; +}; + export type GQLMutationPutOAuthClientArgs = { - input: GQLPutOAuthClientInput -} + input: GQLPutOAuthClientInput; +}; + + +export type GQLMutationPutQuoteArgs = { + input: GQLPutQuoteInput; +}; + export type GQLMutationPutRemarkArgs = { - input: GQLPutRemarkInput -} + input: GQLPutRemarkInput; +}; + export type GQLMutationPutRestrictedUsersArgs = { - input: GQLPutRestrictedUsersInput -} + input: GQLPutRestrictedUsersInput; +}; + export type GQLMutationPutSkippedListItemArgs = { - input: GQLPutSkippedListItemInput -} + input: GQLPutSkippedListItemInput; +}; + export type GQLMutationPutTagChannelArgs = { - input: GQLPutTagChannelInput -} + input: GQLPutTagChannelInput; +}; + export type GQLMutationPutTopicChannelArgs = { - input: GQLPutTopicChannelInput -} + input: GQLPutTopicChannelInput; +}; + export type GQLMutationPutUserFeatureFlagsArgs = { - input: GQLPutUserFeatureFlagsInput -} + input: GQLPutUserFeatureFlagsInput; +}; + export type GQLMutationPutUserFederationSettingArgs = { - input: GQLPutUserFederationSettingInput -} + input: GQLPutUserFederationSettingInput; +}; + export type GQLMutationPutWritingChallengeArgs = { - input: GQLPutWritingChallengeInput -} + input: GQLPutWritingChallengeInput; +}; + export type GQLMutationReadArticleArgs = { - input: GQLReadArticleInput -} + input: GQLReadArticleInput; +}; + export type GQLMutationRemoveSocialLoginArgs = { - input: GQLRemoveSocialLoginInput -} + input: GQLRemoveSocialLoginInput; +}; + export type GQLMutationRenameTagArgs = { - input: GQLRenameTagInput -} + input: GQLRenameTagInput; +}; + export type GQLMutationReorderChannelsArgs = { - input: GQLReorderChannelsInput -} + input: GQLReorderChannelsInput; +}; + export type GQLMutationReorderCollectionArticlesArgs = { - input: GQLReorderCollectionArticlesInput -} + input: GQLReorderCollectionArticlesInput; +}; + export type GQLMutationResetLikerIdArgs = { - input: GQLResetLikerIdInput -} + input: GQLResetLikerIdInput; +}; + export type GQLMutationResetPasswordArgs = { - input: GQLResetPasswordInput -} + input: GQLResetPasswordInput; +}; + export type GQLMutationRestoreCommunityWatchCommentArgs = { - input: GQLRestoreCommunityWatchCommentInput -} + input: GQLRestoreCommunityWatchCommentInput; +}; + export type GQLMutationReviewTopicChannelFeedbackArgs = { - input: GQLReviewTopicChannelFeedbackInput -} + input: GQLReviewTopicChannelFeedbackInput; +}; + export type GQLMutationSendCampaignAnnouncementArgs = { - input: GQLSendCampaignAnnouncementInput -} + input: GQLSendCampaignAnnouncementInput; +}; + export type GQLMutationSendVerificationCodeArgs = { - input: GQLSendVerificationCodeInput -} + input: GQLSendVerificationCodeInput; +}; + export type GQLMutationSetAdStatusArgs = { - input: GQLSetAdStatusInput -} + input: GQLSetAdStatusInput; +}; + export type GQLMutationSetArticleFederationSettingArgs = { - input: GQLSetArticleFederationSettingInput -} + input: GQLSetArticleFederationSettingInput; +}; + export type GQLMutationSetArticleTopicChannelsArgs = { - input: GQLSetArticleTopicChannelsInput -} + input: GQLSetArticleTopicChannelsInput; +}; + export type GQLMutationSetBoostArgs = { - input: GQLSetBoostInput -} + input: GQLSetBoostInput; +}; + export type GQLMutationSetCurrencyArgs = { - input: GQLSetCurrencyInput -} + input: GQLSetCurrencyInput; +}; + export type GQLMutationSetEmailArgs = { - input: GQLSetEmailInput -} + input: GQLSetEmailInput; +}; + export type GQLMutationSetFeatureArgs = { - input: GQLSetFeatureInput -} + input: GQLSetFeatureInput; +}; + export type GQLMutationSetPasswordArgs = { - input: GQLSetPasswordInput -} + input: GQLSetPasswordInput; +}; + export type GQLMutationSetSpamStatusArgs = { - input: GQLSetSpamStatusInput -} + input: GQLSetSpamStatusInput; +}; + export type GQLMutationSetUserNameArgs = { - input: GQLSetUserNameInput -} + input: GQLSetUserNameInput; +}; + export type GQLMutationSetViewerFederationSettingArgs = { - input: GQLSetViewerFederationSettingInput -} + input: GQLSetViewerFederationSettingInput; +}; + export type GQLMutationSetWritingAdStatusArgs = { - input: GQLSetAdStatusInput -} + input: GQLSetAdStatusInput; +}; + export type GQLMutationSingleFileUploadArgs = { - input: GQLSingleFileUploadInput -} + input: GQLSingleFileUploadInput; +}; + export type GQLMutationSocialLoginArgs = { - input: GQLSocialLoginInput -} + input: GQLSocialLoginInput; +}; + export type GQLMutationSubmitReportArgs = { - input: GQLSubmitReportInput -} + input: GQLSubmitReportInput; +}; + export type GQLMutationSubmitTopicChannelFeedbackArgs = { - input: GQLSubmitTopicChannelFeedbackInput -} + input: GQLSubmitTopicChannelFeedbackInput; +}; + export type GQLMutationSubscribeCircleArgs = { - input: GQLSubscribeCircleInput -} + input: GQLSubscribeCircleInput; +}; + export type GQLMutationToggleArticleRecommendArgs = { - input: GQLToggleRecommendInput -} + input: GQLToggleRecommendInput; +}; + export type GQLMutationToggleBlockUserArgs = { - input: GQLToggleItemInput -} + input: GQLToggleItemInput; +}; + export type GQLMutationToggleBookmarkArticleArgs = { - input: GQLToggleItemInput -} + input: GQLToggleItemInput; +}; + export type GQLMutationToggleBookmarkTagArgs = { - input: GQLToggleItemInput -} + input: GQLToggleItemInput; +}; + export type GQLMutationToggleFollowCircleArgs = { - input: GQLToggleItemInput -} + input: GQLToggleItemInput; +}; + export type GQLMutationToggleFollowTagArgs = { - input: GQLToggleItemInput -} + input: GQLToggleItemInput; +}; + export type GQLMutationToggleFollowUserArgs = { - input: GQLToggleItemInput -} + input: GQLToggleItemInput; +}; + export type GQLMutationTogglePinChannelArticlesArgs = { - input: GQLTogglePinChannelArticlesInput -} + input: GQLTogglePinChannelArticlesInput; +}; + export type GQLMutationTogglePinCommentArgs = { - input: GQLToggleItemInput -} + input: GQLToggleItemInput; +}; + export type GQLMutationToggleSeedingUsersArgs = { - input: GQLToggleSeedingUsersInput -} + input: GQLToggleSeedingUsersInput; +}; + export type GQLMutationToggleSubscribeArticleArgs = { - input: GQLToggleItemInput -} + input: GQLToggleItemInput; +}; + export type GQLMutationToggleUsersBadgeArgs = { - input: GQLToggleUsersBadgeInput -} + input: GQLToggleUsersBadgeInput; +}; + export type GQLMutationToggleWritingChallengeFeaturedArticlesArgs = { - input: GQLToggleWritingChallengeFeaturedArticlesInput -} + input: GQLToggleWritingChallengeFeaturedArticlesInput; +}; + export type GQLMutationUnbindLikerIdArgs = { - input: GQLUnbindLikerIdInput -} + input: GQLUnbindLikerIdInput; +}; + + +export type GQLMutationUnfreezeSpamRingArgs = { + input: GQLUnfreezeSpamRingInput; +}; + export type GQLMutationUnlikeCollectionArgs = { - input: GQLUnlikeCollectionInput -} + input: GQLUnlikeCollectionInput; +}; + export type GQLMutationUnlikeMomentArgs = { - input: GQLUnlikeMomentInput -} + input: GQLUnlikeMomentInput; +}; + export type GQLMutationUnpinCommentArgs = { - input: GQLUnpinCommentInput -} + input: GQLUnpinCommentInput; +}; + export type GQLMutationUnsubscribeCircleArgs = { - input: GQLUnsubscribeCircleInput -} + input: GQLUnsubscribeCircleInput; +}; + export type GQLMutationUnvoteCommentArgs = { - input: GQLUnvoteCommentInput -} + input: GQLUnvoteCommentInput; +}; + export type GQLMutationUpdateArticleSensitiveArgs = { - input: GQLUpdateArticleSensitiveInput -} + input: GQLUpdateArticleSensitiveInput; +}; + export type GQLMutationUpdateArticleStateArgs = { - input: GQLUpdateArticleStateInput -} + input: GQLUpdateArticleStateInput; +}; + export type GQLMutationUpdateCampaignApplicationStateArgs = { - input: GQLUpdateCampaignApplicationStateInput -} + input: GQLUpdateCampaignApplicationStateInput; +}; + export type GQLMutationUpdateCommentsStateArgs = { - input: GQLUpdateCommentsStateInput -} + input: GQLUpdateCommentsStateInput; +}; + export type GQLMutationUpdateCommunityWatchActionStateArgs = { - input: GQLUpdateCommunityWatchActionStateInput -} + input: GQLUpdateCommunityWatchActionStateInput; +}; + export type GQLMutationUpdateMomentFeedApplicationStateArgs = { - input: GQLUpdateMomentFeedApplicationStateInput -} + input: GQLUpdateMomentFeedApplicationStateInput; +}; + export type GQLMutationUpdateNotificationSettingArgs = { - input: GQLUpdateNotificationSettingInput -} + input: GQLUpdateNotificationSettingInput; +}; + export type GQLMutationUpdateUserExtraArgs = { - input: GQLUpdateUserExtraInput -} + input: GQLUpdateUserExtraInput; +}; + export type GQLMutationUpdateUserInfoArgs = { - input: GQLUpdateUserInfoInput -} + input: GQLUpdateUserInfoInput; +}; + export type GQLMutationUpdateUserRoleArgs = { - input: GQLUpdateUserRoleInput -} + input: GQLUpdateUserRoleInput; +}; + export type GQLMutationUpdateUserStateArgs = { - input: GQLUpdateUserStateInput -} + input: GQLUpdateUserStateInput; +}; + + +export type GQLMutationUpsertSpamRingCandidatesArgs = { + input: GQLUpsertSpamRingCandidatesInput; +}; + export type GQLMutationVerifyEmailArgs = { - input: GQLVerifyEmailInput -} + input: GQLVerifyEmailInput; +}; + export type GQLMutationVoteCommentArgs = { - input: GQLVoteCommentInput -} + input: GQLVoteCommentInput; +}; + export type GQLMutationWalletLoginArgs = { - input: GQLWalletLoginInput -} + input: GQLWalletLoginInput; +}; /** NFT Asset */ export type GQLNftAsset = { - __typename?: 'NFTAsset' - collectionName: Scalars['String']['output'] + __typename?: 'NFTAsset'; + collectionName: Scalars['String']['output']; /** imageOriginalUrl: String! */ - contractAddress: Scalars['String']['output'] - description?: Maybe - id: Scalars['ID']['output'] - imagePreviewUrl?: Maybe - imageUrl: Scalars['String']['output'] - name: Scalars['String']['output'] -} + contractAddress: Scalars['String']['output']; + description?: Maybe; + id: Scalars['ID']['output']; + imagePreviewUrl?: Maybe; + imageUrl: Scalars['String']['output']; + name: Scalars['String']['output']; +}; export type GQLNode = { - id: Scalars['ID']['output'] -} + id: Scalars['ID']['output']; +}; export type GQLNodeInput = { - id: Scalars['ID']['input'] -} + id: Scalars['ID']['input']; +}; export type GQLNodesInput = { - ids: Array -} + ids: Array; +}; /** This interface contains common fields of a notice. */ export type GQLNotice = { /** Time of this notice was created. */ - createdAt: Scalars['DateTime']['output'] + createdAt: Scalars['DateTime']['output']; /** Unique ID of this notice. */ - id: Scalars['ID']['output'] + id: Scalars['ID']['output']; /** The value determines if the notice is unread or not. */ - unread: Scalars['Boolean']['output'] -} + unread: Scalars['Boolean']['output']; +}; export type GQLNoticeConnection = GQLConnection & { - __typename?: 'NoticeConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'NoticeConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLNoticeEdge = { - __typename?: 'NoticeEdge' - cursor: Scalars['String']['output'] - node: GQLNotice -} + __typename?: 'NoticeEdge'; + cursor: Scalars['String']['output']; + node: GQLNotice; +}; export type GQLNotificationSetting = { - __typename?: 'NotificationSetting' - articleNewAppreciation: Scalars['Boolean']['output'] - articleNewCollected: Scalars['Boolean']['output'] - articleNewComment: Scalars['Boolean']['output'] - articleNewSubscription: Scalars['Boolean']['output'] - circleMemberNewBroadcastReply: Scalars['Boolean']['output'] - circleMemberNewDiscussion: Scalars['Boolean']['output'] - circleMemberNewDiscussionReply: Scalars['Boolean']['output'] - circleNewFollower: Scalars['Boolean']['output'] + __typename?: 'NotificationSetting'; + articleNewAppreciation: Scalars['Boolean']['output']; + articleNewCollected: Scalars['Boolean']['output']; + articleNewComment: Scalars['Boolean']['output']; + articleNewSubscription: Scalars['Boolean']['output']; + circleMemberNewBroadcastReply: Scalars['Boolean']['output']; + circleMemberNewDiscussion: Scalars['Boolean']['output']; + circleMemberNewDiscussionReply: Scalars['Boolean']['output']; + circleNewFollower: Scalars['Boolean']['output']; /** for circle owners */ - circleNewSubscriber: Scalars['Boolean']['output'] - circleNewUnsubscriber: Scalars['Boolean']['output'] - email: Scalars['Boolean']['output'] + circleNewSubscriber: Scalars['Boolean']['output']; + circleNewUnsubscriber: Scalars['Boolean']['output']; + email: Scalars['Boolean']['output']; /** for circle members & followers */ - inCircleNewArticle: Scalars['Boolean']['output'] - inCircleNewBroadcast: Scalars['Boolean']['output'] - inCircleNewBroadcastReply: Scalars['Boolean']['output'] - inCircleNewDiscussion: Scalars['Boolean']['output'] - inCircleNewDiscussionReply: Scalars['Boolean']['output'] - mention: Scalars['Boolean']['output'] - newComment: Scalars['Boolean']['output'] - newLike: Scalars['Boolean']['output'] - userNewFollower: Scalars['Boolean']['output'] -} + inCircleNewArticle: Scalars['Boolean']['output']; + inCircleNewBroadcast: Scalars['Boolean']['output']; + inCircleNewBroadcastReply: Scalars['Boolean']['output']; + inCircleNewDiscussion: Scalars['Boolean']['output']; + inCircleNewDiscussionReply: Scalars['Boolean']['output']; + mention: Scalars['Boolean']['output']; + newComment: Scalars['Boolean']['output']; + newLike: Scalars['Boolean']['output']; + userNewFollower: Scalars['Boolean']['output']; +}; export type GQLNotificationSettingType = | 'articleNewAppreciation' @@ -3040,713 +3299,846 @@ export type GQLNotificationSettingType = | 'mention' | 'newComment' | 'newLike' - | 'userNewFollower' + | 'userNewFollower'; export type GQLOAuthClient = { - __typename?: 'OAuthClient' + __typename?: 'OAuthClient'; /** URL for oauth client's avatar. */ - avatar?: Maybe + avatar?: Maybe; /** Creation Date */ - createdAt: Scalars['DateTime']['output'] + createdAt: Scalars['DateTime']['output']; /** App Description */ - description?: Maybe + description?: Maybe; /** Grant Types */ - grantTypes?: Maybe> + grantTypes?: Maybe>; /** Unique Client ID of this OAuth Client. */ - id: Scalars['ID']['output'] + id: Scalars['ID']['output']; /** App name */ - name: Scalars['String']['output'] + name: Scalars['String']['output']; /** Redirect URIs */ - redirectURIs?: Maybe> + redirectURIs?: Maybe>; /** Scopes */ - scope?: Maybe> + scope?: Maybe>; /** Client secret */ - secret: Scalars['String']['output'] + secret: Scalars['String']['output']; /** Linked Developer Account */ - user?: Maybe + user?: Maybe; /** URL for oauth client's official website */ - website?: Maybe -} + website?: Maybe; +}; export type GQLOAuthClientConnection = GQLConnection & { - __typename?: 'OAuthClientConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'OAuthClientConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLOAuthClientEdge = { - __typename?: 'OAuthClientEdge' - cursor: Scalars['String']['output'] - node: GQLOAuthClient -} + __typename?: 'OAuthClientEdge'; + cursor: Scalars['String']['output']; + node: GQLOAuthClient; +}; export type GQLOAuthClientInput = { - id: Scalars['ID']['input'] -} + id: Scalars['ID']['input']; +}; export type GQLOss = { - __typename?: 'OSS' - articles: GQLArticleConnection - badgedUsers: GQLUserConnection - comments: GQLCommentConnection - icymiTopics: GQLIcymiTopicConnection - momentFeedUsers: GQLUserConnection - moments: GQLMomentConnection - oauthClients: GQLOAuthClientConnection - reports: GQLReportConnection - restrictedUsers: GQLUserConnection - seedingUsers: GQLUserConnection - skippedListItems: GQLSkippedListItemsConnection - tags: GQLTagConnection - topicChannelFeedbacks: GQLTopicChannelFeedbackConnection - users: GQLUserConnection -} + __typename?: 'OSS'; + articles: GQLArticleConnection; + badgedUsers: GQLUserConnection; + comments: GQLCommentConnection; + icymiTopics: GQLIcymiTopicConnection; + momentFeedUsers: GQLUserConnection; + moments: GQLMomentConnection; + oauthClients: GQLOAuthClientConnection; + reports: GQLReportConnection; + restrictedUsers: GQLUserConnection; + seedingUsers: GQLUserConnection; + skippedListItems: GQLSkippedListItemsConnection; + spamRings: GQLSpamRingConnection; + tags: GQLTagConnection; + topicChannelFeedbacks: GQLTopicChannelFeedbackConnection; + users: GQLUserConnection; +}; + export type GQLOssArticlesArgs = { - input: GQLOssArticlesInput -} + input: GQLOssArticlesInput; +}; + export type GQLOssBadgedUsersArgs = { - input: GQLBadgedUsersInput -} + input: GQLBadgedUsersInput; +}; + export type GQLOssCommentsArgs = { - input: GQLConnectionArgs -} + input: GQLOssCommentsInput; +}; + export type GQLOssIcymiTopicsArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLOssMomentFeedUsersArgs = { - input: GQLMomentFeedUsersInput -} + input: GQLMomentFeedUsersInput; +}; + export type GQLOssMomentsArgs = { - input: GQLConnectionArgs -} + input: GQLOssMomentsInput; +}; + export type GQLOssOauthClientsArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLOssReportsArgs = { - input: GQLOssReportsInput -} + input: GQLOssReportsInput; +}; + export type GQLOssRestrictedUsersArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLOssSeedingUsersArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLOssSkippedListItemsArgs = { - input: GQLSkippedListItemsInput -} + input: GQLSkippedListItemsInput; +}; + + +export type GQLOssSpamRingsArgs = { + input: GQLOssSpamRingsInput; +}; + export type GQLOssTagsArgs = { - input: GQLTagsInput -} + input: GQLTagsInput; +}; + export type GQLOssTopicChannelFeedbacksArgs = { - input: GQLTopicChannelFeedbacksInput -} + input: GQLTopicChannelFeedbacksInput; +}; + export type GQLOssUsersArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; export type GQLOssArticlesFilterInput = { - datetimeRange?: InputMaybe - isSpam?: InputMaybe - searchKey?: InputMaybe -} + datetimeRange?: InputMaybe; + isSpam?: InputMaybe; + searchKey?: InputMaybe; +}; export type GQLOssArticlesInput = { - after?: InputMaybe - filter?: InputMaybe - first?: InputMaybe - sort?: InputMaybe -} + after?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + sort?: InputMaybe; +}; + +export type GQLOssCommentsInput = { + after?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + sort?: InputMaybe; +}; + +/** Sort options shared by OSS comment/moment lists for spam triage. */ +export type GQLOssContentSpamSort = + /** Order by spam score from high to low (only scored items) */ + | 'mostSpam' + | 'newest'; + +export type GQLOssMomentsInput = { + after?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + sort?: InputMaybe; +}; export type GQLOssReportsFilter = { - source?: InputMaybe -} + source?: InputMaybe; +}; export type GQLOssReportsInput = { - after?: InputMaybe - filter?: InputMaybe - first?: InputMaybe -} + after?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; +}; + +export type GQLOssSpamDatetimeFilterInput = { + datetimeRange?: InputMaybe; +}; + +export type GQLOssSpamRingsFilter = { + status?: InputMaybe; +}; + +export type GQLOssSpamRingsInput = { + after?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + sort?: InputMaybe; +}; export type GQLOauth1CredentialInput = { - oauthToken: Scalars['String']['input'] - oauthVerifier: Scalars['String']['input'] -} + oauthToken: Scalars['String']['input']; + oauthVerifier: Scalars['String']['input']; +}; /** This type contains system-wise info and settings. */ export type GQLOfficial = { - __typename?: 'Official' + __typename?: 'Official'; /** Announcements */ - announcements?: Maybe> + announcements?: Maybe>; /** Feature flag */ - features: Array -} + features: Array; +}; + /** This type contains system-wise info and settings. */ export type GQLOfficialAnnouncementsArgs = { - input: GQLAnnouncementsInput -} + input: GQLAnnouncementsInput; +}; /** The notice type contains info about official announcement. */ export type GQLOfficialAnnouncementNotice = GQLNotice & { - __typename?: 'OfficialAnnouncementNotice' + __typename?: 'OfficialAnnouncementNotice'; /** Time of this notice was created. */ - createdAt: Scalars['DateTime']['output'] + createdAt: Scalars['DateTime']['output']; /** Unique ID of this notice. */ - id: Scalars['ID']['output'] + id: Scalars['ID']['output']; /** The link to a specific page if provided. */ - link?: Maybe + link?: Maybe; /** The message content. */ - message: Scalars['String']['output'] + message: Scalars['String']['output']; /** The value determines if the notice is unread or not. */ - unread: Scalars['Boolean']['output'] -} + unread: Scalars['Boolean']['output']; +}; export type GQLPageInfo = { - __typename?: 'PageInfo' - endCursor?: Maybe - hasNextPage: Scalars['Boolean']['output'] - hasPreviousPage: Scalars['Boolean']['output'] - startCursor?: Maybe -} + __typename?: 'PageInfo'; + endCursor?: Maybe; + hasNextPage: Scalars['Boolean']['output']; + hasPreviousPage: Scalars['Boolean']['output']; + startCursor?: Maybe; +}; export type GQLPayToInput = { - amount: Scalars['Float']['input'] + amount: Scalars['Float']['input']; /** for ERC20/native token payment */ - chain?: InputMaybe - currency: GQLTransactionCurrency - id?: InputMaybe + chain?: InputMaybe; + currency: GQLTransactionCurrency; + id?: InputMaybe; /** for HKD payment */ - password?: InputMaybe - purpose: GQLTransactionPurpose - recipientId: Scalars['ID']['input'] - targetId?: InputMaybe - txHash?: InputMaybe -} + password?: InputMaybe; + purpose: GQLTransactionPurpose; + recipientId: Scalars['ID']['input']; + targetId?: InputMaybe; + txHash?: InputMaybe; +}; export type GQLPayToResult = { - __typename?: 'PayToResult' + __typename?: 'PayToResult'; /** Only available when paying with LIKE. */ - redirectUrl?: Maybe - transaction: GQLTransaction -} + redirectUrl?: Maybe; + transaction: GQLTransaction; +}; export type GQLPayoutInput = { - amount: Scalars['Float']['input'] - password: Scalars['String']['input'] -} + amount: Scalars['Float']['input']; + password: Scalars['String']['input']; +}; export type GQLPerson = { - __typename?: 'Person' - email: Scalars['String']['output'] -} + __typename?: 'Person'; + email: Scalars['String']['output']; +}; export type GQLPersonhoodHandoff = { - __typename?: 'PersonhoodHandoff' - expiresAt: Scalars['DateTime']['output'] - token: Scalars['String']['output'] -} + __typename?: 'PersonhoodHandoff'; + expiresAt: Scalars['DateTime']['output']; + token: Scalars['String']['output']; +}; export type GQLPinCommentInput = { - id: Scalars['ID']['input'] -} + id: Scalars['ID']['input']; +}; export type GQLPinHistory = { - __typename?: 'PinHistory' + __typename?: 'PinHistory'; /** Which feed (IcymiTopic / Channel) the article was pinned */ - feed: GQLNode - pinnedAt: Scalars['DateTime']['output'] -} + feed: GQLNode; + pinnedAt: Scalars['DateTime']['output']; +}; export type GQLPinnableWork = { - cover?: Maybe - id: Scalars['ID']['output'] - pinned: Scalars['Boolean']['output'] - title: Scalars['String']['output'] -} + cover?: Maybe; + id: Scalars['ID']['output']; + pinned: Scalars['Boolean']['output']; + title: Scalars['String']['output']; +}; export type GQLPrice = { - __typename?: 'Price' + __typename?: 'Price'; /** Amount of Price. */ - amount: Scalars['Float']['output'] + amount: Scalars['Float']['output']; /** Current Price belongs to whcih Circle. */ - circle: GQLCircle + circle: GQLCircle; /** * Created time. * @deprecated No longer in use */ - createdAt: Scalars['DateTime']['output'] + createdAt: Scalars['DateTime']['output']; /** Currency of Price. */ - currency: GQLTransactionCurrency + currency: GQLTransactionCurrency; /** Unique ID. */ - id: Scalars['ID']['output'] + id: Scalars['ID']['output']; /** State of Price. */ - state: GQLPriceState + state: GQLPriceState; /** * Updated time. * @deprecated No longer in use */ - updatedAt: Scalars['DateTime']['output'] -} + updatedAt: Scalars['DateTime']['output']; +}; -export type GQLPriceState = 'active' | 'archived' +export type GQLPriceState = + | 'active' + | 'archived'; export type GQLPublishArticleInput = { - id: Scalars['ID']['input'] + id: Scalars['ID']['input']; /** whether publish to ISCN */ - iscnPublish?: InputMaybe + iscnPublish?: InputMaybe; /** Scheduled publish date of the article. */ - publishAt?: InputMaybe -} + publishAt?: InputMaybe; +}; /** Enums for publishing state. */ -export type GQLPublishState = 'error' | 'pending' | 'published' | 'unpublished' +export type GQLPublishState = + | 'error' + | 'pending' + | 'published' + | 'unpublished'; export type GQLPutAnnouncementInput = { - channels?: InputMaybe> - content?: InputMaybe> - cover?: InputMaybe - expiredAt?: InputMaybe - id?: InputMaybe - link?: InputMaybe> - order?: InputMaybe - title?: InputMaybe> - type?: InputMaybe - visible?: InputMaybe -} + channels?: InputMaybe>; + content?: InputMaybe>; + cover?: InputMaybe; + expiredAt?: InputMaybe; + id?: InputMaybe; + link?: InputMaybe>; + order?: InputMaybe; + title?: InputMaybe>; + type?: InputMaybe; + visible?: InputMaybe; +}; export type GQLPutArticleFederationSettingInput = { - id: Scalars['ID']['input'] - state: GQLFederationArticleSettingState -} + id: Scalars['ID']['input']; + state: GQLFederationArticleSettingState; +}; export type GQLPutCircleArticlesInput = { /** Access Type, `public` or `paywall` only. */ - accessType: GQLArticleAccessType + accessType: GQLArticleAccessType; /** Article Ids */ - articles?: InputMaybe> + articles?: InputMaybe>; /** Circle ID */ - id: Scalars['ID']['input'] - license?: InputMaybe + id: Scalars['ID']['input']; + license?: InputMaybe; /** Action Type */ - type: GQLPutCircleArticlesType -} + type: GQLPutCircleArticlesType; +}; -export type GQLPutCircleArticlesType = 'add' | 'remove' +export type GQLPutCircleArticlesType = + | 'add' + | 'remove'; export type GQLPutCircleInput = { /** Circle's subscription fee. */ - amount?: InputMaybe + amount?: InputMaybe; /** Unique ID of a Circle's avatar. */ - avatar?: InputMaybe + avatar?: InputMaybe; /** Unique ID of a Circle's cover. */ - cover?: InputMaybe + cover?: InputMaybe; /** A short description of this Circle. */ - description?: InputMaybe + description?: InputMaybe; /** Human readable name of this Circle. */ - displayName?: InputMaybe + displayName?: InputMaybe; /** Unique ID. */ - id?: InputMaybe + id?: InputMaybe; /** Slugified name of a Circle. */ - name?: InputMaybe -} + name?: InputMaybe; +}; export type GQLPutCollectionInput = { - cover?: InputMaybe - description?: InputMaybe - id?: InputMaybe - pinned?: InputMaybe - title?: InputMaybe -} + cover?: InputMaybe; + description?: InputMaybe; + id?: InputMaybe; + pinned?: InputMaybe; + title?: InputMaybe; +}; export type GQLPutCommentInput = { - comment: GQLCommentInput - id?: InputMaybe -} + comment: GQLCommentInput; + id?: InputMaybe; +}; export type GQLPutCurationChannelInput = { - activePeriod?: InputMaybe - color?: InputMaybe - id?: InputMaybe - name?: InputMaybe> - navbarTitle?: InputMaybe> - note?: InputMaybe> - pinAmount?: InputMaybe - showRecommendation?: InputMaybe - state?: InputMaybe -} + activePeriod?: InputMaybe; + color?: InputMaybe; + id?: InputMaybe; + name?: InputMaybe>; + navbarTitle?: InputMaybe>; + note?: InputMaybe>; + pinAmount?: InputMaybe; + showRecommendation?: InputMaybe; + state?: InputMaybe; +}; export type GQLPutDraftInput = { - accessType?: InputMaybe + accessType?: InputMaybe; /** Which campaigns to attach */ - campaigns?: InputMaybe> + campaigns?: InputMaybe>; /** Whether readers can comment */ - canComment?: InputMaybe - circle?: InputMaybe + canComment?: InputMaybe; + circle?: InputMaybe; /** Deprecated, use connections instead */ - collection?: InputMaybe>> + collection?: InputMaybe>>; /** Add article to these collections when published */ - collections?: InputMaybe> - connections?: InputMaybe> - content?: InputMaybe - cover?: InputMaybe - id?: InputMaybe - indentFirstLine?: InputMaybe + collections?: InputMaybe>; + connections?: InputMaybe>; + content?: InputMaybe; + cover?: InputMaybe; + id?: InputMaybe; + indentFirstLine?: InputMaybe; /** Whether publish to ISCN */ - iscnPublish?: InputMaybe + iscnPublish?: InputMaybe; /** Last known update timestamp for version conflict detection */ - lastUpdatedAt?: InputMaybe - license?: InputMaybe - replyToDonator?: InputMaybe - requestForDonation?: InputMaybe - sensitive?: InputMaybe - summary?: InputMaybe - tags?: InputMaybe> - title?: InputMaybe -} + lastUpdatedAt?: InputMaybe; + license?: InputMaybe; + replyToDonator?: InputMaybe; + requestForDonation?: InputMaybe; + sensitive?: InputMaybe; + summary?: InputMaybe; + tags?: InputMaybe>; + title?: InputMaybe; +}; export type GQLPutIcymiTopicInput = { - articles?: InputMaybe> - id?: InputMaybe - note?: InputMaybe> - pinAmount?: InputMaybe - state?: InputMaybe - title?: InputMaybe> -} + articles?: InputMaybe>; + id?: InputMaybe; + note?: InputMaybe>; + pinAmount?: InputMaybe; + state?: InputMaybe; + title?: InputMaybe>; +}; export type GQLPutMomentInput = { - articles?: InputMaybe> - assets?: InputMaybe> - content: Scalars['String']['input'] - tags?: InputMaybe> -} + articles?: InputMaybe>; + assets?: InputMaybe>; + content: Scalars['String']['input']; + tags?: InputMaybe>; +}; export type GQLPutOAuthClientInput = { - avatar?: InputMaybe - description?: InputMaybe - grantTypes?: InputMaybe> - id?: InputMaybe - name?: InputMaybe - redirectURIs?: InputMaybe> - scope?: InputMaybe> - secret?: InputMaybe - user?: InputMaybe - website?: InputMaybe -} + avatar?: InputMaybe; + description?: InputMaybe; + grantTypes?: InputMaybe>; + id?: InputMaybe; + name?: InputMaybe; + redirectURIs?: InputMaybe>; + scope?: InputMaybe>; + secret?: InputMaybe; + user?: InputMaybe; + website?: InputMaybe; +}; + +export type GQLPutQuoteInput = { + articleId: Scalars['ID']['input']; + content: Scalars['String']['input']; +}; export type GQLPutRemarkInput = { - id: Scalars['ID']['input'] - remark: Scalars['String']['input'] - type: GQLRemarkTypes -} + id: Scalars['ID']['input']; + remark: Scalars['String']['input']; + type: GQLRemarkTypes; +}; export type GQLPutRestrictedUsersInput = { - ids: Array - restrictions: Array -} + ids: Array; + restrictions: Array; +}; export type GQLPutSkippedListItemInput = { - archived?: InputMaybe - id?: InputMaybe - type?: InputMaybe - value?: InputMaybe -} + archived?: InputMaybe; + id?: InputMaybe; + type?: InputMaybe; + value?: InputMaybe; +}; export type GQLPutTagChannelInput = { - enabled?: InputMaybe - id: Scalars['ID']['input'] - navbarTitle?: InputMaybe> -} + enabled?: InputMaybe; + id: Scalars['ID']['input']; + navbarTitle?: InputMaybe>; +}; export type GQLPutTopicChannelInput = { - enabled?: InputMaybe - id?: InputMaybe - name?: InputMaybe> - navbarTitle?: InputMaybe> - note?: InputMaybe> - providerId?: InputMaybe - subChannels?: InputMaybe> -} + enabled?: InputMaybe; + id?: InputMaybe; + name?: InputMaybe>; + navbarTitle?: InputMaybe>; + note?: InputMaybe>; + providerId?: InputMaybe; + subChannels?: InputMaybe>; +}; export type GQLPutUserFeatureFlagsInput = { - flags: Array - ids: Array -} + flags: Array; + ids: Array; +}; export type GQLPutUserFederationSettingInput = { - id: Scalars['ID']['input'] - state: GQLFederationAuthorSettingState -} + id: Scalars['ID']['input']; + state: GQLFederationAuthorSettingState; +}; export type GQLPutWritingChallengeInput = { - announcements?: InputMaybe> - applicationPeriod?: InputMaybe - channelEnabled?: InputMaybe - cover?: InputMaybe - description?: InputMaybe> + announcements?: InputMaybe>; + applicationPeriod?: InputMaybe; + channelEnabled?: InputMaybe; + cover?: InputMaybe; + description?: InputMaybe>; + /** enable the quote wall (post-to-wall) for this campaign */ + enableQuoteWall?: InputMaybe; /** exclude articles of this campaign in topic channels and newest */ - exclusive?: InputMaybe - featuredDescription?: InputMaybe> - id?: InputMaybe - link?: InputMaybe - managers?: InputMaybe> - name?: InputMaybe> - navbarTitle?: InputMaybe> - newStages?: InputMaybe> - organizers?: InputMaybe> - showAd?: InputMaybe - showOther?: InputMaybe - stages?: InputMaybe> - state?: InputMaybe - writingPeriod?: InputMaybe -} + exclusive?: InputMaybe; + featuredDescription?: InputMaybe>; + id?: InputMaybe; + link?: InputMaybe; + managers?: InputMaybe>; + name?: InputMaybe>; + navbarTitle?: InputMaybe>; + newStages?: InputMaybe>; + organizers?: InputMaybe>; + showAd?: InputMaybe; + showOther?: InputMaybe; + stages?: InputMaybe>; + state?: InputMaybe; + writingPeriod?: InputMaybe; +}; export type GQLQuery = { - __typename?: 'Query' - article?: Maybe - campaign?: Maybe - campaignOrganizers: GQLUserConnection - campaigns: GQLCampaignConnection - channel?: Maybe - channels: Array - circle?: Maybe + __typename?: 'Query'; + article?: Maybe; + campaign?: Maybe; + campaignOrganizers: GQLUserConnection; + campaigns: GQLCampaignConnection; + channel?: Maybe; + channels: Array; + circle?: Maybe; /** One public Community Watch audit record. */ - communityWatchAction?: Maybe + communityWatchAction?: Maybe; /** Recent public Community Watch audit records. */ - communityWatchActions: GQLCommunityWatchActionConnection - exchangeRates?: Maybe> - frequentSearch?: Maybe> - moment?: Maybe - node?: Maybe - nodes?: Maybe> - oauthClient?: Maybe - oauthRequestToken?: Maybe - official: GQLOfficial - oss: GQLOss - search: GQLSearchResultConnection - user?: Maybe - viewer?: Maybe -} + communityWatchActions: GQLCommunityWatchActionConnection; + exchangeRates?: Maybe>; + frequentSearch?: Maybe>; + moment?: Maybe; + node?: Maybe; + nodes?: Maybe>; + oauthClient?: Maybe; + oauthRequestToken?: Maybe; + official: GQLOfficial; + oss: GQLOss; + search: GQLSearchResultConnection; + user?: Maybe; + viewer?: Maybe; +}; + export type GQLQueryArticleArgs = { - input: GQLArticleInput -} + input: GQLArticleInput; +}; + export type GQLQueryCampaignArgs = { - input: GQLCampaignInput -} + input: GQLCampaignInput; +}; + export type GQLQueryCampaignOrganizersArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLQueryCampaignsArgs = { - input: GQLCampaignsInput -} + input: GQLCampaignsInput; +}; + export type GQLQueryChannelArgs = { - input: GQLChannelInput -} + input: GQLChannelInput; +}; + export type GQLQueryChannelsArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; + export type GQLQueryCircleArgs = { - input: GQLCircleInput -} + input: GQLCircleInput; +}; + export type GQLQueryCommunityWatchActionArgs = { - input: GQLCommunityWatchActionInput -} + input: GQLCommunityWatchActionInput; +}; + export type GQLQueryCommunityWatchActionsArgs = { - input: GQLCommunityWatchActionsInput -} + input: GQLCommunityWatchActionsInput; +}; + export type GQLQueryExchangeRatesArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; + export type GQLQueryFrequentSearchArgs = { - input: GQLFrequentSearchInput -} + input: GQLFrequentSearchInput; +}; + export type GQLQueryMomentArgs = { - input: GQLMomentInput -} + input: GQLMomentInput; +}; + export type GQLQueryNodeArgs = { - input: GQLNodeInput -} + input: GQLNodeInput; +}; + export type GQLQueryNodesArgs = { - input: GQLNodesInput -} + input: GQLNodesInput; +}; + export type GQLQueryOauthClientArgs = { - input: GQLOAuthClientInput -} + input: GQLOAuthClientInput; +}; + export type GQLQuerySearchArgs = { - input: GQLSearchInput -} + input: GQLSearchInput; +}; -export type GQLQueryUserArgs = { - input: GQLUserInput -} -export type GQLQuoteCurrency = 'HKD' | 'TWD' | 'USD' +export type GQLQueryUserArgs = { + input: GQLUserInput; +}; + +export type GQLQuote = { + __typename?: 'Quote'; + article: GQLArticle; + content: Scalars['String']['output']; + createdAt: Scalars['DateTime']['output']; + id: Scalars['ID']['output']; + /** the user who posted this quote onto the wall */ + poster: GQLUser; +}; + +export type GQLQuoteConnection = GQLConnection & { + __typename?: 'QuoteConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; + +export type GQLQuoteCurrency = + | 'HKD' + | 'TWD' + | 'USD'; + +export type GQLQuoteEdge = { + __typename?: 'QuoteEdge'; + cursor: Scalars['String']['output']; + node: GQLQuote; +}; + +export type GQLQuotesInput = { + after?: InputMaybe; + first?: InputMaybe; + /** random sampling for wall display; refetch to shuffle. when true, after is ignored */ + random?: InputMaybe; +}; export type GQLReadArticleInput = { - id: Scalars['ID']['input'] -} + id: Scalars['ID']['input']; +}; export type GQLReadHistory = { - __typename?: 'ReadHistory' - article: GQLArticle - readAt: Scalars['DateTime']['output'] -} + __typename?: 'ReadHistory'; + article: GQLArticle; + readAt: Scalars['DateTime']['output']; +}; export type GQLReadHistoryConnection = GQLConnection & { - __typename?: 'ReadHistoryConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'ReadHistoryConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLReadHistoryEdge = { - __typename?: 'ReadHistoryEdge' - cursor: Scalars['String']['output'] - node: GQLReadHistory -} + __typename?: 'ReadHistoryEdge'; + cursor: Scalars['String']['output']; + node: GQLReadHistory; +}; export type GQLRecentSearchConnection = GQLConnection & { - __typename?: 'RecentSearchConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'RecentSearchConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLRecentSearchEdge = { - __typename?: 'RecentSearchEdge' - cursor: Scalars['String']['output'] - node: Scalars['String']['output'] -} + __typename?: 'RecentSearchEdge'; + cursor: Scalars['String']['output']; + node: Scalars['String']['output']; +}; export type GQLRecommendFilterInput = { - channel?: InputMaybe + channel?: InputMaybe; /** filter out followed users */ - followed?: InputMaybe + followed?: InputMaybe; /** index of list, min: 0, max: 49 */ - random?: InputMaybe -} + random?: InputMaybe; +}; export type GQLRecommendInput = { - after?: InputMaybe - filter?: InputMaybe - first?: InputMaybe - newAlgo?: InputMaybe - oss?: InputMaybe -} + after?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + newAlgo?: InputMaybe; + oss?: InputMaybe; +}; /** Enums for types of recommend articles. */ -export type GQLRecommendTypes = 'hottest' | 'icymi' | 'newest' | 'search' +export type GQLRecommendTypes = + | 'hottest' + | 'icymi' + | 'newest' + | 'search'; export type GQLRecommendation = { - __typename?: 'Recommendation' + __typename?: 'Recommendation'; /** Global user list, sort by activities in recent 6 month. */ - authors: GQLUserConnection + authors: GQLUserConnection; /** Activities based on user's following, sort by creation time. */ - following: GQLFollowingActivityConnection + following: GQLFollowingActivityConnection; /** Global articles sort by latest activity time. */ - hottest: GQLArticleConnection - hottestMoments: GQLMomentConnection + hottest: GQLArticleConnection; + hottestMoments: GQLMomentConnection; /** 'In case you missed it' recommendation. */ - icymi: GQLArticleConnection + icymi: GQLArticleConnection; /** 'In case you missed it' topic. */ - icymiTopic?: Maybe + icymiTopic?: Maybe; /** Global articles sort by publish time. */ - newest: GQLArticleConnection + newest: GQLArticleConnection; /** Global tag list, sort by activities in recent 14 days. */ - tags: GQLTagConnection -} + tags: GQLTagConnection; +}; + export type GQLRecommendationAuthorsArgs = { - input: GQLRecommendInput -} + input: GQLRecommendInput; +}; + export type GQLRecommendationFollowingArgs = { - input: GQLRecommendationFollowingInput -} + input: GQLRecommendationFollowingInput; +}; + export type GQLRecommendationHottestArgs = { - input: GQLRecommendInput -} + input: GQLRecommendInput; +}; + export type GQLRecommendationHottestMomentsArgs = { - input: GQLRecommendInput -} + input: GQLRecommendInput; +}; + export type GQLRecommendationIcymiArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLRecommendationNewestArgs = { - input: GQLRecommendationNewestInput -} + input: GQLRecommendationNewestInput; +}; + export type GQLRecommendationTagsArgs = { - input: GQLRecommendInput -} + input: GQLRecommendInput; +}; export type GQLRecommendationFollowingFilterInput = { - type?: InputMaybe -} + type?: InputMaybe; +}; -export type GQLRecommendationFollowingFilterType = 'article' +export type GQLRecommendationFollowingFilterType = + | 'article'; export type GQLRecommendationFollowingInput = { - after?: InputMaybe - filter?: InputMaybe - first?: InputMaybe -} + after?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; +}; export type GQLRecommendationNewestInput = { - after?: InputMaybe - excludeChannelArticles?: InputMaybe - filter?: InputMaybe - first?: InputMaybe - oss?: InputMaybe -} + after?: InputMaybe; + excludeChannelArticles?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + oss?: InputMaybe; +}; export type GQLRefreshIpnsFeedInput = { /** refresh how many recent articles, default to 50 */ - numArticles?: InputMaybe - userName: Scalars['String']['input'] -} + numArticles?: InputMaybe; + userName: Scalars['String']['input']; +}; export type GQLRelatedDonationArticlesInput = { - after?: InputMaybe - first?: InputMaybe - oss?: InputMaybe + after?: InputMaybe; + first?: InputMaybe; + oss?: InputMaybe; /** index of article list, min: 0, max: 49 */ - random?: InputMaybe -} + random?: InputMaybe; +}; export type GQLRemarkTypes = | 'Article' @@ -3754,57 +4146,57 @@ export type GQLRemarkTypes = | 'Feedback' | 'Report' | 'Tag' - | 'User' + | 'User'; export type GQLRemoveSocialLoginInput = { - type: GQLSocialAccountType -} + type: GQLSocialAccountType; +}; export type GQLRenameTagInput = { - content: Scalars['String']['input'] - id: Scalars['ID']['input'] -} + content: Scalars['String']['input']; + id: Scalars['ID']['input']; +}; export type GQLReorderChannelsInput = { - ids: Array -} + ids: Array; +}; export type GQLReorderCollectionArticlesInput = { - collection: Scalars['ID']['input'] - moves: Array -} + collection: Scalars['ID']['input']; + moves: Array; +}; export type GQLReorderMoveInput = { - item: Scalars['ID']['input'] + item: Scalars['ID']['input']; /** The new position move to. To move item to the beginning of the list, set to 0. To the end of the list, set to the length of the list - 1. */ - newPosition: Scalars['Int']['input'] -} + newPosition: Scalars['Int']['input']; +}; export type GQLReport = GQLNode & { - __typename?: 'Report' + __typename?: 'Report'; /** The audit record when this report originates from a community watch action. */ - communityWatchAction?: Maybe - createdAt: Scalars['DateTime']['output'] - id: Scalars['ID']['output'] - reason: GQLReportReason - reporter: GQLUser + communityWatchAction?: Maybe; + createdAt: Scalars['DateTime']['output']; + id: Scalars['ID']['output']; + reason: GQLReportReason; + reporter: GQLUser; /** Whether this record originates from a direct in-site report or a community watch action. */ - source: GQLReportSource - target: GQLNode -} + source: GQLReportSource; + target: GQLNode; +}; export type GQLReportConnection = GQLConnection & { - __typename?: 'ReportConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'ReportConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLReportEdge = { - __typename?: 'ReportEdge' - cursor: Scalars['String']['output'] - node: GQLReport -} + __typename?: 'ReportEdge'; + cursor: Scalars['String']['output']; + node: GQLReport; +}; export type GQLReportReason = /** Pornographic/adult advertising flagged by a community watch member. */ @@ -3815,274 +4207,466 @@ export type GQLReportReason = | 'illegal_advertising' | 'other' | 'pornography_involving_minors' - | 'tort' + | 'tort'; export type GQLReportSource = /** Created automatically when a community watch member removes a comment. */ | 'community_watch' /** Submitted directly via the in-site report form. */ - | 'direct' + | 'direct'; export type GQLResetLikerIdInput = { - id: Scalars['ID']['input'] -} + id: Scalars['ID']['input']; +}; export type GQLResetPasswordInput = { - codeId: Scalars['ID']['input'] - password: Scalars['String']['input'] - type?: InputMaybe -} + codeId: Scalars['ID']['input']; + password: Scalars['String']['input']; + type?: InputMaybe; +}; -export type GQLResetPasswordType = 'account' | 'payment' +export type GQLResetPasswordType = + | 'account' + | 'payment'; -export type GQLResponse = GQLArticle | GQLComment +export type GQLResponse = GQLArticle | GQLComment; export type GQLResponseConnection = GQLConnection & { - __typename?: 'ResponseConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'ResponseConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLResponseEdge = { - __typename?: 'ResponseEdge' - cursor: Scalars['String']['output'] - node: GQLResponse -} + __typename?: 'ResponseEdge'; + cursor: Scalars['String']['output']; + node: GQLResponse; +}; /** Enums for sorting responses. */ -export type GQLResponseSort = 'newest' | 'oldest' +export type GQLResponseSort = + | 'newest' + | 'oldest'; export type GQLResponsesInput = { - after?: InputMaybe - articleOnly?: InputMaybe - before?: InputMaybe - first?: InputMaybe - includeAfter?: InputMaybe - includeBefore?: InputMaybe - sort?: InputMaybe -} + after?: InputMaybe; + articleOnly?: InputMaybe; + before?: InputMaybe; + first?: InputMaybe; + includeAfter?: InputMaybe; + includeBefore?: InputMaybe; + sort?: InputMaybe; +}; export type GQLRestoreCommunityWatchCommentInput = { - note?: InputMaybe - uuid: Scalars['ID']['input'] -} + note?: InputMaybe; + uuid: Scalars['ID']['input']; +}; export type GQLReviewTopicChannelFeedbackInput = { - action: GQLTopicChannelFeedbackAction - feedback: Scalars['ID']['input'] -} + action: GQLTopicChannelFeedbackAction; + feedback: Scalars['ID']['input']; +}; /** Enums for user roles. */ -export type GQLRole = 'admin' | 'user' | 'vistor' +export type GQLRole = + | 'admin' + | 'user' + | 'vistor'; -export type GQLSearchApiVersion = 'v20230301' | 'v20230601' +export type GQLSearchApiVersion = + | 'v20230301' + | 'v20230601'; -export type GQLSearchExclude = 'blocked' +export type GQLSearchExclude = + | 'blocked'; export type GQLSearchFilter = { - authorId?: InputMaybe -} + authorId?: InputMaybe; +}; export type GQLSearchInput = { - after?: InputMaybe + after?: InputMaybe; /** specific condition for rule data out */ - exclude?: InputMaybe + exclude?: InputMaybe; /** extra query filter for searching */ - filter?: InputMaybe - first?: InputMaybe + filter?: InputMaybe; + first?: InputMaybe; /** should include tags used by author */ - includeAuthorTags?: InputMaybe + includeAuthorTags?: InputMaybe; /** search keyword */ - key: Scalars['String']['input'] - oss?: InputMaybe - quicksearch?: InputMaybe + key: Scalars['String']['input']; + oss?: InputMaybe; + quicksearch?: InputMaybe; /** whether this search operation should be recorded in search history */ - record?: InputMaybe + record?: InputMaybe; /** types of search target */ - type: GQLSearchTypes -} + type: GQLSearchTypes; +}; export type GQLSearchResultConnection = GQLConnection & { - __typename?: 'SearchResultConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'SearchResultConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLSearchResultEdge = { - __typename?: 'SearchResultEdge' - cursor: Scalars['String']['output'] - node: GQLNode -} + __typename?: 'SearchResultEdge'; + cursor: Scalars['String']['output']; + node: GQLNode; +}; -export type GQLSearchTypes = 'Article' | 'Tag' | 'User' +export type GQLSearchTypes = + | 'Article' + | 'Tag' + | 'User'; export type GQLSendCampaignAnnouncementInput = { - announcement: Array - campaign: Scalars['ID']['input'] - link: Scalars['String']['input'] - password: Scalars['String']['input'] -} + announcement: Array; + campaign: Scalars['ID']['input']; + link: Scalars['String']['input']; + password: Scalars['String']['input']; +}; export type GQLSendVerificationCodeInput = { - email: Scalars['String']['input'] + email: Scalars['String']['input']; /** email content language */ - language?: InputMaybe + language?: InputMaybe; /** * Redirect URL embedded in the verification email, * use code instead if not provided. */ - redirectUrl?: InputMaybe - token?: InputMaybe - type: GQLVerificationCodeType -} + redirectUrl?: InputMaybe; + token?: InputMaybe; + type: GQLVerificationCodeType; +}; export type GQLSetAdStatusInput = { - id: Scalars['ID']['input'] - isAd: Scalars['Boolean']['input'] -} + id: Scalars['ID']['input']; + isAd: Scalars['Boolean']['input']; +}; export type GQLSetArticleFederationSettingInput = { - id: Scalars['ID']['input'] - state: GQLFederationArticleSettingState -} + id: Scalars['ID']['input']; + state: GQLFederationArticleSettingState; +}; export type GQLSetArticleTopicChannelsInput = { - channels: Array - id: Scalars['ID']['input'] -} + channels: Array; + id: Scalars['ID']['input']; +}; export type GQLSetBoostInput = { - boost: Scalars['Float']['input'] - id: Scalars['ID']['input'] - type: GQLBoostTypes -} + boost: Scalars['Float']['input']; + id: Scalars['ID']['input']; + type: GQLBoostTypes; +}; export type GQLSetCurrencyInput = { - currency?: InputMaybe -} + currency?: InputMaybe; +}; export type GQLSetEmailInput = { - email: Scalars['String']['input'] -} + email: Scalars['String']['input']; +}; export type GQLSetFeatureInput = { - flag: GQLFeatureFlag - name: GQLFeatureName - value?: InputMaybe -} + flag: GQLFeatureFlag; + name: GQLFeatureName; + value?: InputMaybe; +}; export type GQLSetPasswordInput = { - password: Scalars['String']['input'] -} + password: Scalars['String']['input']; +}; export type GQLSetSpamStatusInput = { - id: Scalars['ID']['input'] - isSpam: Scalars['Boolean']['input'] -} + id: Scalars['ID']['input']; + isSpam: Scalars['Boolean']['input']; +}; export type GQLSetUserNameInput = { - userName: Scalars['String']['input'] -} + userName: Scalars['String']['input']; +}; export type GQLSetViewerFederationSettingInput = { - state: GQLFederationAuthorSettingState -} + state: GQLFederationAuthorSettingState; +}; export type GQLSigningMessagePurpose = | 'airdrop' | 'claimLogbook' | 'connect' | 'login' - | 'signup' + | 'signup'; export type GQLSigningMessageResult = { - __typename?: 'SigningMessageResult' - createdAt: Scalars['DateTime']['output'] - expiredAt: Scalars['DateTime']['output'] - nonce: Scalars['String']['output'] - purpose: GQLSigningMessagePurpose - signingMessage: Scalars['String']['output'] -} + __typename?: 'SigningMessageResult'; + createdAt: Scalars['DateTime']['output']; + expiredAt: Scalars['DateTime']['output']; + nonce: Scalars['String']['output']; + purpose: GQLSigningMessagePurpose; + signingMessage: Scalars['String']['output']; +}; export type GQLSingleFileUploadInput = { - draft?: InputMaybe - entityId?: InputMaybe - entityType: GQLEntityType - file?: InputMaybe - type: GQLAssetType - url?: InputMaybe -} + draft?: InputMaybe; + entityId?: InputMaybe; + entityType: GQLEntityType; + file?: InputMaybe; + type: GQLAssetType; + url?: InputMaybe; +}; export type GQLSkippedListItem = { - __typename?: 'SkippedListItem' - archived: Scalars['Boolean']['output'] - createdAt: Scalars['DateTime']['output'] - id: Scalars['ID']['output'] - type: GQLSkippedListItemType - updatedAt: Scalars['DateTime']['output'] - uuid: Scalars['ID']['output'] - value: Scalars['String']['output'] -} + __typename?: 'SkippedListItem'; + archived: Scalars['Boolean']['output']; + createdAt: Scalars['DateTime']['output']; + id: Scalars['ID']['output']; + type: GQLSkippedListItemType; + updatedAt: Scalars['DateTime']['output']; + uuid: Scalars['ID']['output']; + value: Scalars['String']['output']; +}; export type GQLSkippedListItemEdge = { - __typename?: 'SkippedListItemEdge' - cursor: Scalars['String']['output'] - node?: Maybe -} + __typename?: 'SkippedListItemEdge'; + cursor: Scalars['String']['output']; + node?: Maybe; +}; -export type GQLSkippedListItemType = 'agent_hash' | 'domain' | 'email' +export type GQLSkippedListItemType = + | 'agent_hash' + | 'domain' + | 'email'; export type GQLSkippedListItemsConnection = GQLConnection & { - __typename?: 'SkippedListItemsConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'SkippedListItemsConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLSkippedListItemsInput = { - after?: InputMaybe - first?: InputMaybe - type?: InputMaybe -} + after?: InputMaybe; + first?: InputMaybe; + type?: InputMaybe; +}; export type GQLSocialAccount = { - __typename?: 'SocialAccount' - email?: Maybe - type: GQLSocialAccountType - userName?: Maybe -} - -export type GQLSocialAccountType = 'Facebook' | 'Google' | 'Threads' | 'Twitter' + __typename?: 'SocialAccount'; + email?: Maybe; + type: GQLSocialAccountType; + userName?: Maybe; +}; + +export type GQLSocialAccountType = + | 'Facebook' + | 'Google' + | 'Threads' + | 'Twitter'; export type GQLSocialLoginInput = { - authorizationCode?: InputMaybe + authorizationCode?: InputMaybe; /** OAuth2 PKCE code_verifier for Facebook and Twitter */ - codeVerifier?: InputMaybe + codeVerifier?: InputMaybe; /** used in register */ - language?: InputMaybe + language?: InputMaybe; /** OIDC nonce for Google */ - nonce?: InputMaybe + nonce?: InputMaybe; /** oauth token/verifier in OAuth1.0a for Twitter */ - oauth1Credential?: InputMaybe - referralCode?: InputMaybe - type: GQLSocialAccountType -} + oauth1Credential?: InputMaybe; + /** Google OIDC redirect_uri for OSS SSO. When set, must be allowlisted; login is restricted to existing admin accounts and no new account is created. */ + redirectUri?: InputMaybe; + referralCode?: InputMaybe; + type: GQLSocialAccountType; +}; + +/** + * A spam ring: a cluster of accounts posting the same templated abuse, + * surfaced by the account-layer ring detector (軸一 D). + */ +export type GQLSpamRing = GQLNode & { + __typename?: 'SpamRing'; + detectedAt: Scalars['DateTime']['output']; + events: Array; + /** 模板/家族指紋(偵測 job 的歸群 key) */ + fingerprint: Scalars['String']['output']; + firstSeenAt?: Maybe; + frozenAt?: Maybe; + frozenBy?: Maybe; + id: Scalars['ID']['output']; + lastSeenAt?: Maybe; + /** 列表渲染用的少量樣本,免分頁 */ + memberSample: Array; + /** 群內成員帳號(可分頁) */ + members: GQLSpamRingMemberConnection; + nArticles: Scalars['Int']['output']; + nAuthors: Scalars['Int']['output']; + newAccountRatio?: Maybe; + note?: Maybe; + score?: Maybe; + severity?: Maybe; + signals: GQLSpamRingSignals; + status: GQLSpamRingStatus; +}; + + +/** + * A spam ring: a cluster of accounts posting the same templated abuse, + * surfaced by the account-layer ring detector (軸一 D). + */ +export type GQLSpamRingMemberSampleArgs = { + limit?: InputMaybe; +}; + + +/** + * A spam ring: a cluster of accounts posting the same templated abuse, + * surfaced by the account-layer ring detector (軸一 D). + */ +export type GQLSpamRingMembersArgs = { + input: GQLConnectionArgs; +}; + +export type GQLSpamRingCandidateInput = { + fingerprint: Scalars['String']['input']; + firstSeenAt?: InputMaybe; + lastSeenAt?: InputMaybe; + /** JSON string: map of user id -> evidence. */ + memberEvidence?: InputMaybe; + /** Raw DB user ids (the detection job reads them from the replica). */ + memberUserIds?: InputMaybe>; + memberUserNames?: InputMaybe>; + nArticles: Scalars['Int']['input']; + nAuthors: Scalars['Int']['input']; + newAccountRatio?: InputMaybe; + score?: InputMaybe; + severity?: InputMaybe; + signals: GQLSpamRingSignalsInput; +}; + +export type GQLSpamRingConnection = GQLConnection & { + __typename?: 'SpamRingConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; + +export type GQLSpamRingEdge = { + __typename?: 'SpamRingEdge'; + cursor: Scalars['String']['output']; + node: GQLSpamRing; +}; + +export type GQLSpamRingEvent = { + __typename?: 'SpamRingEvent'; + action: GQLSpamRingEventAction; + actor?: Maybe; + createdAt: Scalars['DateTime']['output']; + /** JSON 字串 */ + detail?: Maybe; + id: Scalars['ID']['output']; +}; + +export type GQLSpamRingEventAction = + | 'detected' + | 'dismissed' + | 'frozen' + | 'member_banned' + | 'member_restored' + | 'member_skipped' + | 'unfrozen'; + +export type GQLSpamRingMember = { + __typename?: 'SpamRingMember'; + /** 是否由本 ring 的凍結造成封禁(解凍時只還原此類) */ + bannedByThisRing: Scalars['Boolean']['output']; + createdAt: Scalars['DateTime']['output']; + id: Scalars['ID']['output']; + skipReason?: Maybe; + status: GQLSpamRingMemberStatus; + user: GQLUser; +}; + +export type GQLSpamRingMemberConnection = GQLConnection & { + __typename?: 'SpamRingMemberConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; + +export type GQLSpamRingMemberEdge = { + __typename?: 'SpamRingMemberEdge'; + cursor: Scalars['String']['output']; + node: GQLSpamRingMember; +}; + +export type GQLSpamRingMemberStatus = + | 'frozen' + | 'pending' + | 'restored' + | 'skipped'; + +export type GQLSpamRingSeverity = + | 'critical' + | 'high' + | 'low' + | 'medium'; + +export type GQLSpamRingSignals = { + __typename?: 'SpamRingSignals'; + botUsernameRatio?: Maybe; + contentModelMax?: Maybe; + entityRingSize?: Maybe; + nearDupRingSize?: Maybe; + sampleBrands?: Maybe>; + sampleCodes?: Maybe>; + topEntity?: Maybe; +}; + +export type GQLSpamRingSignalsInput = { + botUsernameRatio?: InputMaybe; + contentModelMax?: InputMaybe; + entityRingSize?: InputMaybe; + nearDupRingSize?: InputMaybe; + sampleBrands?: InputMaybe>; + sampleCodes?: InputMaybe>; + topEntity?: InputMaybe; +}; + +export type GQLSpamRingSkip = { + __typename?: 'SpamRingSkip'; + reason: Scalars['String']['output']; + user: GQLUser; +}; + +export type GQLSpamRingStatus = + | 'dismissed' + | 'frozen' + | 'pending' + | 'restored'; + +export type GQLSpamRingsSort = + | 'detectedAt' + | 'nAuthors' + | 'score'; export type GQLSpamStatus = { - __typename?: 'SpamStatus' + __typename?: 'SpamStatus'; /** Whether this work is labeled as spam by human, null for not labeled yet. */ - isSpam?: Maybe + isSpam?: Maybe; /** Spam confident score by machine, null for not checked yet. */ - score?: Maybe -} + score?: Maybe; +}; export type GQLStripeAccount = { - __typename?: 'StripeAccount' - id: Scalars['ID']['output'] - loginUrl: Scalars['String']['output'] -} + __typename?: 'StripeAccount'; + id: Scalars['ID']['output']; + loginUrl: Scalars['String']['output']; +}; export type GQLStripeAccountCountry = | 'Australia' @@ -4116,354 +4700,373 @@ export type GQLStripeAccountCountry = | 'Spain' | 'Sweden' | 'UnitedKingdom' - | 'UnitedStates' + | 'UnitedStates'; export type GQLSubmitReportInput = { - reason: GQLReportReason - targetId: Scalars['ID']['input'] -} + reason: GQLReportReason; + targetId: Scalars['ID']['input']; +}; export type GQLSubmitTopicChannelFeedbackInput = { - article: Scalars['ID']['input'] - channels?: InputMaybe> - type: GQLTopicChannelFeedbackType -} + article: Scalars['ID']['input']; + channels?: InputMaybe>; + type: GQLTopicChannelFeedbackType; +}; export type GQLSubscribeCircleInput = { /** Unique ID. */ - id: Scalars['ID']['input'] + id: Scalars['ID']['input']; /** Wallet password. */ - password?: InputMaybe -} + password?: InputMaybe; +}; export type GQLSubscribeCircleResult = { - __typename?: 'SubscribeCircleResult' - circle: GQLCircle + __typename?: 'SubscribeCircleResult'; + circle: GQLCircle; /** client secret for SetupIntent. */ - client_secret?: Maybe -} + client_secret?: Maybe; +}; /** This type contains content, count and related data of an article tag. */ -export type GQLTag = GQLChannel & - GQLNode & { - __typename?: 'Tag' - /** List of articles were attached with this tag. */ - articles: GQLChannelArticleConnection - /** Whether this tag is enabled as a channel */ - channelEnabled: Scalars['Boolean']['output'] - /** Content of this tag. */ - content: Scalars['String']['output'] - /** Time of this tag was created. */ - createdAt: Scalars['DateTime']['output'] - deleted: Scalars['Boolean']['output'] - /** Unique id of this tag. */ - id: Scalars['ID']['output'] - /** This value determines if current viewer is following or not. */ - isFollower?: Maybe - /** Navbar title for this tag channel */ - navbarTitle: Scalars['String']['output'] - /** Counts of this tag. */ - numArticles: Scalars['Int']['output'] - numAuthors: Scalars['Int']['output'] - numMoments: Scalars['Int']['output'] - oss: GQLTagOss - /** Tags recommended based on relations to current tag. */ - recommended: GQLTagConnection - /** Authors recommended based on relations to current tag. */ - recommendedAuthors: GQLUserConnection - remark?: Maybe - /** Short hash for shorter url addressing */ - shortHash: Scalars['String']['output'] - /** Articles and moments were attached with this tag. */ - writings: GQLTagWritingConnection - } +export type GQLTag = GQLChannel & GQLNode & { + __typename?: 'Tag'; + /** List of articles were attached with this tag. */ + articles: GQLChannelArticleConnection; + /** Whether this tag is enabled as a channel */ + channelEnabled: Scalars['Boolean']['output']; + /** Content of this tag. */ + content: Scalars['String']['output']; + /** Time of this tag was created. */ + createdAt: Scalars['DateTime']['output']; + deleted: Scalars['Boolean']['output']; + /** Unique id of this tag. */ + id: Scalars['ID']['output']; + /** This value determines if current viewer is following or not. */ + isFollower?: Maybe; + /** Navbar title for this tag channel */ + navbarTitle: Scalars['String']['output']; + /** Counts of this tag. */ + numArticles: Scalars['Int']['output']; + numAuthors: Scalars['Int']['output']; + numMoments: Scalars['Int']['output']; + oss: GQLTagOss; + /** Tags recommended based on relations to current tag. */ + recommended: GQLTagConnection; + /** Authors recommended based on relations to current tag. */ + recommendedAuthors: GQLUserConnection; + remark?: Maybe; + /** Short hash for shorter url addressing */ + shortHash: Scalars['String']['output']; + /** Articles and moments were attached with this tag. */ + writings: GQLTagWritingConnection; +}; + /** This type contains content, count and related data of an article tag. */ export type GQLTagArticlesArgs = { - input: GQLTagArticlesInput -} + input: GQLTagArticlesInput; +}; + /** This type contains content, count and related data of an article tag. */ export type GQLTagNavbarTitleArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; + /** This type contains content, count and related data of an article tag. */ export type GQLTagRecommendedArgs = { - input: GQLRecommendInput -} + input: GQLRecommendInput; +}; + /** This type contains content, count and related data of an article tag. */ export type GQLTagRecommendedAuthorsArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + /** This type contains content, count and related data of an article tag. */ export type GQLTagWritingsArgs = { - input: GQLWritingInput -} + input: GQLWritingInput; +}; export type GQLTagArticlesInput = { - after?: InputMaybe - first?: InputMaybe - oss?: InputMaybe - sortBy?: InputMaybe -} + after?: InputMaybe; + first?: InputMaybe; + oss?: InputMaybe; + sortBy?: InputMaybe; +}; -export type GQLTagArticlesSortBy = 'byCreatedAtDesc' | 'byHottestDesc' +export type GQLTagArticlesSortBy = + | 'byCreatedAtDesc' + | 'byHottestDesc'; export type GQLTagConnection = GQLConnection & { - __typename?: 'TagConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'TagConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLTagEdge = { - __typename?: 'TagEdge' - cursor: Scalars['String']['output'] - node: GQLTag -} + __typename?: 'TagEdge'; + cursor: Scalars['String']['output']; + node: GQLTag; +}; export type GQLTagOss = { - __typename?: 'TagOSS' - boost: Scalars['Float']['output'] - score: Scalars['Float']['output'] -} + __typename?: 'TagOSS'; + boost: Scalars['Float']['output']; + score: Scalars['Float']['output']; +}; export type GQLTagWritingConnection = GQLConnection & { - __typename?: 'TagWritingConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'TagWritingConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLTagWritingEdge = { - __typename?: 'TagWritingEdge' - cursor: Scalars['String']['output'] - node: GQLWriting - pinned: Scalars['Boolean']['output'] -} + __typename?: 'TagWritingEdge'; + cursor: Scalars['String']['output']; + node: GQLWriting; + pinned: Scalars['Boolean']['output']; +}; export type GQLTagsInput = { - after?: InputMaybe - first?: InputMaybe - sort?: InputMaybe -} + after?: InputMaybe; + first?: InputMaybe; + sort?: InputMaybe; +}; /** Enums for sorting tags. */ -export type GQLTagsSort = 'hottest' | 'newest' | 'oldest' +export type GQLTagsSort = + | 'hottest' + | 'newest' + | 'oldest'; export type GQLToggleCircleMemberInput = { /** Toggle value. */ - enabled: Scalars['Boolean']['input'] + enabled: Scalars['Boolean']['input']; /** Unique ID. */ - id: Scalars['ID']['input'] + id: Scalars['ID']['input']; /** Unique ID of target user. */ - targetId: Scalars['ID']['input'] -} + targetId: Scalars['ID']['input']; +}; /** Common input to toggle single item for `toggleXXX` mutations */ export type GQLToggleItemInput = { - enabled?: InputMaybe - id: Scalars['ID']['input'] -} + enabled?: InputMaybe; + id: Scalars['ID']['input']; +}; export type GQLTogglePinChannelArticlesInput = { - articles: Array + articles: Array; /** id of TopicChannel or CurationChannel */ - channels: Array - pinned: Scalars['Boolean']['input'] -} + channels: Array; + pinned: Scalars['Boolean']['input']; +}; export type GQLToggleRecommendInput = { - enabled: Scalars['Boolean']['input'] - id: Scalars['ID']['input'] - type?: InputMaybe -} + enabled: Scalars['Boolean']['input']; + id: Scalars['ID']['input']; + type?: InputMaybe; +}; export type GQLToggleSeedingUsersInput = { - enabled: Scalars['Boolean']['input'] - ids?: InputMaybe> -} + enabled: Scalars['Boolean']['input']; + ids?: InputMaybe>; +}; export type GQLToggleUsersBadgeInput = { - enabled: Scalars['Boolean']['input'] - ids: Array - type: GQLBadgeType -} + enabled: Scalars['Boolean']['input']; + ids: Array; + type: GQLBadgeType; +}; export type GQLToggleWritingChallengeFeaturedArticlesInput = { - articles: Array - campaign: Scalars['ID']['input'] - enabled: Scalars['Boolean']['input'] -} + articles: Array; + campaign: Scalars['ID']['input']; + enabled: Scalars['Boolean']['input']; +}; export type GQLTopDonatorConnection = GQLConnection & { - __typename?: 'TopDonatorConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'TopDonatorConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLTopDonatorEdge = { - __typename?: 'TopDonatorEdge' - cursor: Scalars['String']['output'] - donationCount: Scalars['Int']['output'] - node: GQLDonator -} + __typename?: 'TopDonatorEdge'; + cursor: Scalars['String']['output']; + donationCount: Scalars['Int']['output']; + node: GQLDonator; +}; export type GQLTopDonatorFilter = { - inRangeEnd?: InputMaybe - inRangeStart?: InputMaybe -} + inRangeEnd?: InputMaybe; + inRangeStart?: InputMaybe; +}; export type GQLTopDonatorInput = { - after?: InputMaybe - filter?: InputMaybe - first?: InputMaybe -} + after?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; +}; + +export type GQLTopicChannel = GQLChannel & GQLNode & { + __typename?: 'TopicChannel'; + articles: GQLChannelArticleConnection; + enabled: Scalars['Boolean']['output']; + id: Scalars['ID']['output']; + name: Scalars['String']['output']; + navbarTitle: Scalars['String']['output']; + note?: Maybe; + parent?: Maybe; + providerId?: Maybe; + shortHash: Scalars['String']['output']; +}; -export type GQLTopicChannel = GQLChannel & - GQLNode & { - __typename?: 'TopicChannel' - articles: GQLChannelArticleConnection - enabled: Scalars['Boolean']['output'] - id: Scalars['ID']['output'] - name: Scalars['String']['output'] - navbarTitle: Scalars['String']['output'] - note?: Maybe - parent?: Maybe - providerId?: Maybe - shortHash: Scalars['String']['output'] - } export type GQLTopicChannelArticlesArgs = { - input: GQLChannelArticlesInput -} + input: GQLChannelArticlesInput; +}; + export type GQLTopicChannelNameArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; + export type GQLTopicChannelNavbarTitleArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; + export type GQLTopicChannelNoteArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; export type GQLTopicChannelClassification = { - __typename?: 'TopicChannelClassification' + __typename?: 'TopicChannelClassification'; /** Which channels this article is in, null for not classified, empty for not in any channel */ - channels?: Maybe> + channels?: Maybe>; /** whether user enable channel classification */ - enabled: Scalars['Boolean']['output'] + enabled: Scalars['Boolean']['output']; /** Feedback from author */ - feedback?: Maybe -} + feedback?: Maybe; +}; export type GQLTopicChannelFeedback = { - __typename?: 'TopicChannelFeedback' - article: GQLArticle + __typename?: 'TopicChannelFeedback'; + article: GQLArticle; /** Which channels author want to be in, empty for no channels */ - channels?: Maybe> - createdAt: Scalars['DateTime']['output'] - id: Scalars['ID']['output'] - state?: Maybe - type: GQLTopicChannelFeedbackType -} + channels?: Maybe>; + createdAt: Scalars['DateTime']['output']; + id: Scalars['ID']['output']; + state?: Maybe; + type: GQLTopicChannelFeedbackType; +}; -export type GQLTopicChannelFeedbackAction = 'accept' | 'reject' +export type GQLTopicChannelFeedbackAction = + | 'accept' + | 'reject'; export type GQLTopicChannelFeedbackConnection = GQLConnection & { - __typename?: 'TopicChannelFeedbackConnection' - edges: Array - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'TopicChannelFeedbackConnection'; + edges: Array; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLTopicChannelFeedbackEdge = { - __typename?: 'TopicChannelFeedbackEdge' - cursor: Scalars['String']['output'] - node: GQLTopicChannelFeedback -} + __typename?: 'TopicChannelFeedbackEdge'; + cursor: Scalars['String']['output']; + node: GQLTopicChannelFeedback; +}; export type GQLTopicChannelFeedbackState = | 'accepted' | 'pending' | 'rejected' - | 'resolved' + | 'resolved'; -export type GQLTopicChannelFeedbackType = 'negative' | 'positive' +export type GQLTopicChannelFeedbackType = + | 'negative' + | 'positive'; export type GQLTopicChannelFeedbacksFilterInput = { - spam?: InputMaybe - state?: InputMaybe - type?: InputMaybe -} + spam?: InputMaybe; + state?: InputMaybe; + type?: InputMaybe; +}; export type GQLTopicChannelFeedbacksInput = { - after?: InputMaybe - filter?: InputMaybe - first: Scalars['Int']['input'] -} + after?: InputMaybe; + filter?: InputMaybe; + first: Scalars['Int']['input']; +}; export type GQLTransaction = { - __typename?: 'Transaction' - amount: Scalars['Float']['output'] + __typename?: 'Transaction'; + amount: Scalars['Float']['output']; /** blockchain transaction info of ERC20/native token payment transaction */ - blockchainTx?: Maybe + blockchainTx?: Maybe; /** Timestamp of transaction. */ - createdAt: Scalars['DateTime']['output'] - currency: GQLTransactionCurrency - fee: Scalars['Float']['output'] - id: Scalars['ID']['output'] + createdAt: Scalars['DateTime']['output']; + currency: GQLTransactionCurrency; + fee: Scalars['Float']['output']; + id: Scalars['ID']['output']; /** Message for end user, including reason of failure. */ - message?: Maybe - purpose: GQLTransactionPurpose + message?: Maybe; + purpose: GQLTransactionPurpose; /** Recipient of transaction. */ - recipient?: Maybe + recipient?: Maybe; /** Sender of transaction. */ - sender?: Maybe - state: GQLTransactionState + sender?: Maybe; + state: GQLTransactionState; /** Related target article or transaction. */ - target?: Maybe -} + target?: Maybe; +}; export type GQLTransactionConnection = GQLConnection & { - __typename?: 'TransactionConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'TransactionConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; -export type GQLTransactionCurrency = 'HKD' | 'LIKE' | 'USDT' +export type GQLTransactionCurrency = + | 'HKD' + | 'LIKE' + | 'USDT'; export type GQLTransactionEdge = { - __typename?: 'TransactionEdge' - cursor: Scalars['String']['output'] - node: GQLTransaction -} + __typename?: 'TransactionEdge'; + cursor: Scalars['String']['output']; + node: GQLTransaction; +}; export type GQLTransactionNotice = GQLNotice & { - __typename?: 'TransactionNotice' + __typename?: 'TransactionNotice'; /** List of notice actors. */ - actors?: Maybe> + actors?: Maybe>; /** Time of this notice was created. */ - createdAt: Scalars['DateTime']['output'] + createdAt: Scalars['DateTime']['output']; /** Unique ID of this notice. */ - id: Scalars['ID']['output'] - target: GQLTransaction - type: GQLTransactionNoticeType + id: Scalars['ID']['output']; + target: GQLTransaction; + type: GQLTransactionNoticeType; /** The value determines if the notice is unread or not. */ - unread: Scalars['Boolean']['output'] -} + unread: Scalars['Boolean']['output']; +}; export type GQLTransactionNoticeType = | 'PaymentReceivedDonation' - | 'WithdrewLockedTokens' + | 'WithdrewLockedTokens'; export type GQLTransactionPurpose = | 'addCredit' @@ -4473,7744 +5076,4112 @@ export type GQLTransactionPurpose = | 'payout' | 'payoutReversal' | 'refund' - | 'subscriptionSplit' + | 'subscriptionSplit'; export type GQLTransactionState = | 'canceled' | 'failed' | 'pending' - | 'succeeded' + | 'succeeded'; -export type GQLTransactionTarget = GQLArticle | GQLCircle | GQLTransaction +export type GQLTransactionTarget = GQLArticle | GQLCircle | GQLTransaction; export type GQLTransactionsArgs = { - after?: InputMaybe - filter?: InputMaybe - first?: InputMaybe + after?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; /** deprecated, use TransactionsFilter.id instead. */ - id?: InputMaybe + id?: InputMaybe; /** deprecated, use TransactionsFilter.states instead. */ - states?: InputMaybe> -} + states?: InputMaybe>; +}; export type GQLTransactionsFilter = { - currency?: InputMaybe - id?: InputMaybe - purpose?: InputMaybe - states?: InputMaybe> -} + currency?: InputMaybe; + id?: InputMaybe; + purpose?: InputMaybe; + states?: InputMaybe>; +}; export type GQLTransactionsReceivedByArgs = { - after?: InputMaybe - first?: InputMaybe - purpose: GQLTransactionPurpose - senderId?: InputMaybe -} + after?: InputMaybe; + first?: InputMaybe; + purpose: GQLTransactionPurpose; + senderId?: InputMaybe; +}; export type GQLTranslatedAnnouncement = { - __typename?: 'TranslatedAnnouncement' - content?: Maybe - cover?: Maybe - language: GQLUserLanguage - link?: Maybe - title?: Maybe -} + __typename?: 'TranslatedAnnouncement'; + content?: Maybe; + cover?: Maybe; + language: GQLUserLanguage; + link?: Maybe; + title?: Maybe; +}; export type GQLTranslationArgs = { - language: GQLUserLanguage -} + language: GQLUserLanguage; +}; export type GQLTranslationInput = { - language: GQLUserLanguage - text: Scalars['String']['input'] -} + language: GQLUserLanguage; + text: Scalars['String']['input']; +}; export type GQLTranslationModel = | 'google_gemini_2_0_flash' | 'google_gemini_2_5_flash' | 'google_translation_v2' - | 'opencc' + | 'opencc'; export type GQLUnbindLikerIdInput = { - id: Scalars['ID']['input'] - likerId: Scalars['String']['input'] -} + id: Scalars['ID']['input']; + likerId: Scalars['String']['input']; +}; + +export type GQLUnfreezeSpamRingInput = { + id: Scalars['ID']['input']; +}; + +export type GQLUnfreezeSpamRingResult = { + __typename?: 'UnfreezeSpamRingResult'; + ring: GQLSpamRing; + skipped: Array; + unbanned: Array; +}; export type GQLUnlikeCollectionInput = { - id: Scalars['ID']['input'] -} + id: Scalars['ID']['input']; +}; export type GQLUnlikeMomentInput = { - id: Scalars['ID']['input'] -} + id: Scalars['ID']['input']; +}; export type GQLUnpinCommentInput = { - id: Scalars['ID']['input'] -} + id: Scalars['ID']['input']; +}; export type GQLUnsubscribeCircleInput = { /** Unique ID. */ - id: Scalars['ID']['input'] -} + id: Scalars['ID']['input']; +}; export type GQLUnvoteCommentInput = { - id: Scalars['ID']['input'] -} + id: Scalars['ID']['input']; +}; export type GQLUpdateArticleSensitiveInput = { - id: Scalars['ID']['input'] - sensitive: Scalars['Boolean']['input'] -} + id: Scalars['ID']['input']; + sensitive: Scalars['Boolean']['input']; +}; export type GQLUpdateArticleStateInput = { - id: Scalars['ID']['input'] - state: GQLArticleState -} + id: Scalars['ID']['input']; + state: GQLArticleState; +}; export type GQLUpdateCampaignApplicationStateInput = { - campaign: Scalars['ID']['input'] - state: GQLCampaignApplicationState - user: Scalars['ID']['input'] -} + campaign: Scalars['ID']['input']; + state: GQLCampaignApplicationState; + user: Scalars['ID']['input']; +}; export type GQLUpdateCommentsStateInput = { - ids: Array - state: GQLCommentState -} + ids: Array; + state: GQLCommentState; +}; export type GQLUpdateCommunityWatchActionStateInput = { - appealState?: InputMaybe - note?: InputMaybe - reason?: InputMaybe - reviewState?: InputMaybe - uuid: Scalars['ID']['input'] -} + appealState?: InputMaybe; + note?: InputMaybe; + reason?: InputMaybe; + reviewState?: InputMaybe; + uuid: Scalars['ID']['input']; +}; export type GQLUpdateMomentFeedApplicationStateInput = { - id: Scalars['ID']['input'] - state: GQLMomentFeedUserState -} + id: Scalars['ID']['input']; + state: GQLMomentFeedUserState; +}; export type GQLUpdateNotificationSettingInput = { - enabled: Scalars['Boolean']['input'] - type: GQLNotificationSettingType -} + enabled: Scalars['Boolean']['input']; + type: GQLNotificationSettingType; +}; export type GQLUpdateUserExtraInput = { - id: Scalars['ID']['input'] - referralCode?: InputMaybe -} + id: Scalars['ID']['input']; + referralCode?: InputMaybe; +}; export type GQLUpdateUserInfoInput = { - agreeOn?: InputMaybe - avatar?: InputMaybe - description?: InputMaybe - displayName?: InputMaybe - language?: InputMaybe - paymentPassword?: InputMaybe - paymentPointer?: InputMaybe - profileCover?: InputMaybe - referralCode?: InputMaybe -} + agreeOn?: InputMaybe; + avatar?: InputMaybe; + description?: InputMaybe; + displayName?: InputMaybe; + language?: InputMaybe; + paymentPassword?: InputMaybe; + paymentPointer?: InputMaybe; + profileCover?: InputMaybe; + referralCode?: InputMaybe; +}; export type GQLUpdateUserRoleInput = { - id: Scalars['ID']['input'] - role: GQLUserRole -} + id: Scalars['ID']['input']; + role: GQLUserRole; +}; export type GQLUpdateUserStateInput = { - banDays?: InputMaybe - emails?: InputMaybe> - id?: InputMaybe - password?: InputMaybe - state: GQLUserState -} + banDays?: InputMaybe; + emails?: InputMaybe>; + id?: InputMaybe; + password?: InputMaybe; + state: GQLUserState; +}; + +export type GQLUpsertSpamRingCandidatesInput = { + candidates: Array; +}; + +export type GQLUpsertSpamRingCandidatesResult = { + __typename?: 'UpsertSpamRingCandidatesResult'; + created: Scalars['Int']['output']; + rings: Array; + skipped: Scalars['Int']['output']; + updated: Scalars['Int']['output']; +}; export type GQLUser = GQLNode & { - __typename?: 'User' + __typename?: 'User'; /** Record of user activity, only accessable by current user. */ - activity: GQLUserActivity + activity: GQLUserActivity; /** user data analytics, only accessable by current user. */ - analytics: GQLUserAnalytics + analytics: GQLUserAnalytics; /** Articles authored by current user. */ - articles: GQLArticleConnection + articles: GQLArticleConnection; /** URL for user avatar. */ - avatar?: Maybe + avatar?: Maybe; /** Users that blocked by current user. */ - blockList: GQLUserConnection + blockList: GQLUserConnection; /** Artilces current user bookmarked. */ - bookmarkedArticles: GQLArticleConnection + bookmarkedArticles: GQLArticleConnection; /** Tags current user bookmarked. */ - bookmarkedTags: GQLTagConnection + bookmarkedTags: GQLTagConnection; /** active applied campaigns */ - campaigns: GQLCampaignConnection + campaigns: GQLCampaignConnection; /** collections authored by current user. */ - collections: GQLCollectionConnection + collections: GQLCollectionConnection; /** Articles current user commented on */ - commentedArticles: GQLArticleConnection + commentedArticles: GQLArticleConnection; /** Display name on user profile, can be duplicated. */ - displayName?: Maybe + displayName?: Maybe; /** Drafts authored by current user. */ - drafts: GQLDraftConnection + drafts: GQLDraftConnection; /** Public-safe feature eligibility for current viewer. */ - features: GQLUserFeatures + features: GQLUserFeatures; /** User-level federation opt-in setting. */ - federationSetting?: Maybe + federationSetting?: Maybe; /** Followers of this user. */ - followers: GQLUserConnection + followers: GQLUserConnection; /** Following contents of this user. */ - following: GQLFollowing + following: GQLFollowing; /** Global id of an user. */ - id: Scalars['ID']['output'] + id: Scalars['ID']['output']; /** User information. */ - info: GQLUserInfo + info: GQLUserInfo; /** Whether current user is blocked by viewer. */ - isBlocked: Scalars['Boolean']['output'] + isBlocked: Scalars['Boolean']['output']; /** Whether current user is blocking viewer. */ - isBlocking: Scalars['Boolean']['output'] + isBlocking: Scalars['Boolean']['output']; /** Whether viewer is following current user. */ - isFollowee: Scalars['Boolean']['output'] + isFollowee: Scalars['Boolean']['output']; /** Whether current user is following viewer. */ - isFollower: Scalars['Boolean']['output'] - isMomentFeedApplied: Scalars['Boolean']['output'] + isFollower: Scalars['Boolean']['output']; + isMomentFeedApplied: Scalars['Boolean']['output']; /** user latest articles or collections */ - latestWorks: Array + latestWorks: Array; /** Liker info of current user */ - liker: GQLLiker + liker: GQLLiker; /** LikerID of LikeCoin, being used by LikeCoin OAuth */ - likerId?: Maybe - notices: GQLNoticeConnection - oss: GQLUserOss + likerId?: Maybe; + notices: GQLNoticeConnection; + oss: GQLUserOss; /** Circles belong to current user. */ - ownCircles?: Maybe> + ownCircles?: Maybe>; /** Payment pointer that resolves to Open Payments endpoints */ - paymentPointer?: Maybe + paymentPointer?: Maybe; /** user pinned articles or collections */ - pinnedWorks: Array + pinnedWorks: Array; /** Recommendations for current user. */ - recommendation: GQLRecommendation - remark?: Maybe + recommendation: GQLRecommendation; + remark?: Maybe; /** User settings. */ - settings: GQLUserSettings + settings: GQLUserSettings; /** Status of current user. */ - status?: Maybe + status?: Maybe; /** Circles whiches user has subscribed. */ - subscribedCircles: GQLCircleConnection + subscribedCircles: GQLCircleConnection; /** Tags by usage order of current user. */ - tags: GQLTagConnection + tags: GQLTagConnection; /** Global unique user name of a user. */ - userName?: Maybe + userName?: Maybe; /** User Wallet */ - wallet: GQLWallet + wallet: GQLWallet; /** Articles and moments authored by current user. */ - writings: GQLWritingConnection -} + writings: GQLWritingConnection; +}; + export type GQLUserArticlesArgs = { - input: GQLUserArticlesInput -} + input: GQLUserArticlesInput; +}; + export type GQLUserBlockListArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLUserBookmarkedArticlesArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLUserBookmarkedTagsArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLUserCampaignsArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLUserCollectionsArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLUserCommentedArticlesArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLUserDraftsArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLUserFollowersArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLUserNoticesArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLUserSubscribedCirclesArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLUserTagsArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLUserWritingsArgs = { - input: GQLWritingInput -} + input: GQLWritingInput; +}; export type GQLUserActivity = { - __typename?: 'UserActivity' + __typename?: 'UserActivity'; /** Appreciations current user received. */ - appreciationsReceived: GQLAppreciationConnection + appreciationsReceived: GQLAppreciationConnection; /** Total number of appreciation current user received. */ - appreciationsReceivedTotal: Scalars['Int']['output'] + appreciationsReceivedTotal: Scalars['Int']['output']; /** Appreciations current user gave. */ - appreciationsSent: GQLAppreciationConnection + appreciationsSent: GQLAppreciationConnection; /** Total number of appreciation current user gave. */ - appreciationsSentTotal: Scalars['Int']['output'] + appreciationsSentTotal: Scalars['Int']['output']; /** User reading history. */ - history: GQLReadHistoryConnection + history: GQLReadHistoryConnection; /** User search history. */ - recentSearches: GQLRecentSearchConnection -} + recentSearches: GQLRecentSearchConnection; +}; + export type GQLUserActivityAppreciationsReceivedArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLUserActivityAppreciationsSentArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLUserActivityHistoryArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; + export type GQLUserActivityRecentSearchesArgs = { - input: GQLConnectionArgs -} + input: GQLConnectionArgs; +}; export type GQLUserAddArticleTagActivity = { - __typename?: 'UserAddArticleTagActivity' - actor: GQLUser - createdAt: Scalars['DateTime']['output'] + __typename?: 'UserAddArticleTagActivity'; + actor: GQLUser; + createdAt: Scalars['DateTime']['output']; /** Article added to tag */ - node: GQLArticle + node: GQLArticle; /** Tag added by article */ - target: GQLTag -} + target: GQLTag; +}; export type GQLUserAnalytics = { - __typename?: 'UserAnalytics' + __typename?: 'UserAnalytics'; /** Top donators of current user. */ - topDonators: GQLTopDonatorConnection -} + topDonators: GQLTopDonatorConnection; +}; + export type GQLUserAnalyticsTopDonatorsArgs = { - input: GQLTopDonatorInput -} + input: GQLTopDonatorInput; +}; export type GQLUserArticlesFilter = { - state?: InputMaybe -} + state?: InputMaybe; +}; export type GQLUserArticlesInput = { - after?: InputMaybe - filter?: InputMaybe - first?: InputMaybe - sort?: InputMaybe -} + after?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + sort?: InputMaybe; +}; export type GQLUserArticlesSort = | 'mostAppreciations' | 'mostComments' | 'mostDonations' | 'mostReaders' - | 'newest' + | 'newest'; export type GQLUserBroadcastCircleActivity = { - __typename?: 'UserBroadcastCircleActivity' - actor: GQLUser - createdAt: Scalars['DateTime']['output'] + __typename?: 'UserBroadcastCircleActivity'; + actor: GQLUser; + createdAt: Scalars['DateTime']['output']; /** Comment broadcast by actor */ - node: GQLComment + node: GQLComment; /** Circle that comment belongs to */ - target: GQLCircle -} + target: GQLCircle; +}; export type GQLUserConnection = GQLConnection & { - __typename?: 'UserConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'UserConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLUserCreateCircleActivity = { - __typename?: 'UserCreateCircleActivity' - actor: GQLUser - createdAt: Scalars['DateTime']['output'] + __typename?: 'UserCreateCircleActivity'; + actor: GQLUser; + createdAt: Scalars['DateTime']['output']; /** Circle created by actor */ - node: GQLCircle -} + node: GQLCircle; +}; export type GQLUserEdge = { - __typename?: 'UserEdge' - cursor: Scalars['String']['output'] - node: GQLUser -} + __typename?: 'UserEdge'; + cursor: Scalars['String']['output']; + node: GQLUser; +}; export type GQLUserFeatureFlag = { - __typename?: 'UserFeatureFlag' - createdAt: Scalars['DateTime']['output'] - type: GQLUserFeatureFlagType -} + __typename?: 'UserFeatureFlag'; + createdAt: Scalars['DateTime']['output']; + type: GQLUserFeatureFlagType; +}; export type GQLUserFeatureFlagType = | 'bypassSpamDetection' | 'communityWatch' | 'fediverseBeta' | 'readSpamStatus' - | 'unlimitedArticleFetch' + | 'unlimitedArticleFetch'; export type GQLUserFeatures = { - __typename?: 'UserFeatures' + __typename?: 'UserFeatures'; /** Whether current viewer can use Community Watch controls. */ - communityWatch: Scalars['Boolean']['output'] + communityWatch: Scalars['Boolean']['output']; /** Whether current viewer can access Fediverse beta controls. */ - fediverseBeta: Scalars['Boolean']['output'] -} + fediverseBeta: Scalars['Boolean']['output']; +}; export type GQLUserFederationSetting = { - __typename?: 'UserFederationSetting' - state: GQLFederationAuthorSettingState - updatedBy?: Maybe - userId: Scalars['ID']['output'] -} + __typename?: 'UserFederationSetting'; + state: GQLFederationAuthorSettingState; + updatedBy?: Maybe; + userId: Scalars['ID']['output']; +}; -export type GQLUserGroup = 'a' | 'b' +export type GQLUserGroup = + | 'a' + | 'b'; export type GQLUserInfo = { - __typename?: 'UserInfo' + __typename?: 'UserInfo'; /** Timestamp of user agreement. */ - agreeOn?: Maybe + agreeOn?: Maybe; /** User badges. */ - badges?: Maybe> + badges?: Maybe>; /** Timestamp of registration. */ - createdAt?: Maybe + createdAt?: Maybe; /** Connected wallet. */ - cryptoWallet?: Maybe + cryptoWallet?: Maybe; /** User desciption. */ - description?: Maybe + description?: Maybe; /** User email. */ - email?: Maybe + email?: Maybe; /** Weather user email is verified. */ - emailVerified: Scalars['Boolean']['output'] + emailVerified: Scalars['Boolean']['output']; /** Login address */ - ethAddress?: Maybe + ethAddress?: Maybe; /** saved tags for showing on profile page, API allows up to 100, front-end lock'ed at lower limit */ - featuredTags?: Maybe> + featuredTags?: Maybe>; /** Type of group. */ - group: GQLUserGroup + group: GQLUserGroup; /** the ipnsKey (`ipfs.io/ipns//...`) for feed.json / rss.xml / index */ - ipnsKey?: Maybe - isWalletAuth: Scalars['Boolean']['output'] + ipnsKey?: Maybe; + isWalletAuth: Scalars['Boolean']['output']; /** Cover of profile page. */ - profileCover?: Maybe + profileCover?: Maybe; /** User connected social accounts. */ - socialAccounts: Array + socialAccounts: Array; /** Is user name editable. */ - userNameEditable: Scalars['Boolean']['output'] -} + userNameEditable: Scalars['Boolean']['output']; +}; export type GQLUserInfoFields = | 'agreeOn' | 'avatar' | 'description' | 'displayName' - | 'email' + | 'email'; export type GQLUserInput = { - ethAddress?: InputMaybe - userName?: InputMaybe + ethAddress?: InputMaybe; + userName?: InputMaybe; /** used for case insensitive username search */ - userNameCaseIgnore?: InputMaybe -} + userNameCaseIgnore?: InputMaybe; +}; -export type GQLUserLanguage = 'en' | 'zh_hans' | 'zh_hant' +export type GQLUserLanguage = + | 'en' + | 'zh_hans' + | 'zh_hant'; export type GQLUserNotice = GQLNotice & { - __typename?: 'UserNotice' + __typename?: 'UserNotice'; /** List of notice actors. */ - actors?: Maybe> + actors?: Maybe>; /** Time of this notice was created. */ - createdAt: Scalars['DateTime']['output'] + createdAt: Scalars['DateTime']['output']; /** Unique ID of this notice. */ - id: Scalars['ID']['output'] - target: GQLUser - type: GQLUserNoticeType + id: Scalars['ID']['output']; + target: GQLUser; + type: GQLUserNoticeType; /** The value determines if the notice is unread or not. */ - unread: Scalars['Boolean']['output'] -} + unread: Scalars['Boolean']['output']; +}; -export type GQLUserNoticeType = 'MomentFeedApproved' | 'UserNewFollower' +export type GQLUserNoticeType = + | 'MomentFeedApproved' + | 'UserNewFollower'; export type GQLUserOss = { - __typename?: 'UserOSS' - boost: Scalars['Float']['output'] - featureFlags: Array - momentFeedApplication?: Maybe - restrictions: Array - score: Scalars['Float']['output'] -} + __typename?: 'UserOSS'; + boost: Scalars['Float']['output']; + featureFlags: Array; + momentFeedApplication?: Maybe; + restrictions: Array; + score: Scalars['Float']['output']; +}; export type GQLUserPostMomentActivity = { - __typename?: 'UserPostMomentActivity' - actor: GQLUser - createdAt: Scalars['DateTime']['output'] + __typename?: 'UserPostMomentActivity'; + actor: GQLUser; + createdAt: Scalars['DateTime']['output']; /** Another 3 moments posted by actor */ - more: Array + more: Array; /** Moment posted by actor */ - node: GQLMoment -} + node: GQLMoment; +}; export type GQLUserPublishArticleActivity = { - __typename?: 'UserPublishArticleActivity' - actor: GQLUser - createdAt: Scalars['DateTime']['output'] + __typename?: 'UserPublishArticleActivity'; + actor: GQLUser; + createdAt: Scalars['DateTime']['output']; /** Article published by actor */ - node: GQLArticle -} + node: GQLArticle; +}; export type GQLUserRecommendationActivity = { - __typename?: 'UserRecommendationActivity' + __typename?: 'UserRecommendationActivity'; /** Recommended users */ - nodes?: Maybe> + nodes?: Maybe>; /** The source type of recommendation */ - source?: Maybe -} + source?: Maybe; +}; -export type GQLUserRecommendationActivitySource = 'UserFollowing' +export type GQLUserRecommendationActivitySource = + | 'UserFollowing'; export type GQLUserRestriction = { - __typename?: 'UserRestriction' - createdAt: Scalars['DateTime']['output'] - type: GQLUserRestrictionType -} + __typename?: 'UserRestriction'; + createdAt: Scalars['DateTime']['output']; + type: GQLUserRestrictionType; +}; -export type GQLUserRestrictionType = 'articleHottest' | 'articleNewest' +export type GQLUserRestrictionType = + | 'articleHottest' + | 'articleNewest'; -export type GQLUserRole = 'admin' | 'user' +export type GQLUserRole = + | 'admin' + | 'user'; export type GQLUserSettings = { - __typename?: 'UserSettings' + __typename?: 'UserSettings'; /** User currency preference. */ - currency: GQLQuoteCurrency + currency: GQLQuoteCurrency; /** User language setting. */ - language: GQLUserLanguage + language: GQLUserLanguage; /** Notification settings. */ - notification?: Maybe -} + notification?: Maybe; +}; -export type GQLUserState = 'active' | 'archived' | 'banned' | 'frozen' +export type GQLUserState = + | 'active' + | 'archived' + | 'banned' + | 'frozen'; export type GQLUserStatus = { - __typename?: 'UserStatus' + __typename?: 'UserStatus'; /** Number of articles published by user */ - articleCount: Scalars['Int']['output'] + articleCount: Scalars['Int']['output']; /** Number of chances for the user to change email in a nature day. Reset in UTC+8 0:00 */ - changeEmailTimesLeft: Scalars['Int']['output'] + changeEmailTimesLeft: Scalars['Int']['output']; /** Number of comments posted by user. */ - commentCount: Scalars['Int']['output'] + commentCount: Scalars['Int']['output']; /** Number of articles donated by user */ - donatedArticleCount: Scalars['Int']['output'] + donatedArticleCount: Scalars['Int']['output']; /** Weather login password is set for email login. */ - hasEmailLoginPassword: Scalars['Boolean']['output'] + hasEmailLoginPassword: Scalars['Boolean']['output']; /** Whether user already set payment password. */ - hasPaymentPassword: Scalars['Boolean']['output'] + hasPaymentPassword: Scalars['Boolean']['output']; /** Number of moments posted by user */ - momentCount: Scalars['Int']['output'] + momentCount: Scalars['Int']['output']; /** Number of times of donations received by user */ - receivedDonationCount: Scalars['Int']['output'] + receivedDonationCount: Scalars['Int']['output']; /** User role and access level. */ - role: GQLUserRole + role: GQLUserRole; /** User state. */ - state: GQLUserState + state: GQLUserState; /** Number of referred user registration count (in Digital Nomad Campaign). */ - totalReferredCount: Scalars['Int']['output'] + totalReferredCount: Scalars['Int']['output']; /** Number of total written words. */ - totalWordCount: Scalars['Int']['output'] + totalWordCount: Scalars['Int']['output']; /** Whether there are unread activities from following. */ - unreadFollowing: Scalars['Boolean']['output'] + unreadFollowing: Scalars['Boolean']['output']; /** Number of unread notices. */ - unreadNoticeCount: Scalars['Int']['output'] -} + unreadNoticeCount: Scalars['Int']['output']; +}; export type GQLVerificationCodeType = | 'email_otp' | 'email_verify' | 'payment_password_reset' - | 'register' + | 'register'; export type GQLVerifyEmailInput = { - code: Scalars['String']['input'] - email: Scalars['String']['input'] -} + code: Scalars['String']['input']; + email: Scalars['String']['input']; +}; /** Enums for vote types. */ -export type GQLVote = 'down' | 'up' +export type GQLVote = + | 'down' + | 'up'; export type GQLVoteCommentInput = { - id: Scalars['ID']['input'] - vote: GQLVote -} + id: Scalars['ID']['input']; + vote: GQLVote; +}; export type GQLWallet = { - __typename?: 'Wallet' - balance: GQLBalance + __typename?: 'Wallet'; + balance: GQLBalance; /** The last four digits of the card. */ - cardLast4?: Maybe + cardLast4?: Maybe; /** URL of Stripe Dashboard to manage subscription invoice and payment method */ - customerPortal?: Maybe + customerPortal?: Maybe; /** Account of Stripe Connect to manage payout */ - stripeAccount?: Maybe - transactions: GQLTransactionConnection -} + stripeAccount?: Maybe; + transactions: GQLTransactionConnection; +}; + export type GQLWalletTransactionsArgs = { - input: GQLTransactionsArgs -} + input: GQLTransactionsArgs; +}; export type GQLWalletLoginInput = { - ethAddress: Scalars['String']['input'] + ethAddress: Scalars['String']['input']; /** used in register */ - language?: InputMaybe + language?: InputMaybe; /** nonce from generateSigningMessage */ - nonce: Scalars['String']['input'] - referralCode?: InputMaybe + nonce: Scalars['String']['input']; + referralCode?: InputMaybe; /** sign'ed by wallet */ - signature: Scalars['String']['input'] + signature: Scalars['String']['input']; /** the message being sign'ed, including nonce */ - signedMessage: Scalars['String']['input'] -} + signedMessage: Scalars['String']['input']; +}; export type GQLWithdrawLockedTokensResult = { - __typename?: 'WithdrawLockedTokensResult' - transaction: GQLTransaction -} + __typename?: 'WithdrawLockedTokensResult'; + transaction: GQLTransaction; +}; + +export type GQLWriting = GQLArticle | GQLComment | GQLMoment; + +export type GQLWritingChallenge = GQLCampaign & GQLChannel & GQLNode & { + __typename?: 'WritingChallenge'; + announcements: Array; + application?: Maybe; + applicationPeriod?: Maybe; + articles: GQLCampaignArticleConnection; + channelEnabled: Scalars['Boolean']['output']; + cover?: Maybe; + description?: Maybe; + /** Comments made by campaign participants (public to read). */ + discussion: GQLCommentConnection; + /** Discussion (include replies) count of this campaign. */ + discussionCount: Scalars['Int']['output']; + /** whether this campaign exposes a quote wall (post-to-wall affordance) */ + enableQuoteWall: Scalars['Boolean']['output']; + featuredDescription: Scalars['String']['output']; + id: Scalars['ID']['output']; + isManager: Scalars['Boolean']['output']; + link: Scalars['String']['output']; + name: Scalars['String']['output']; + navbarTitle: Scalars['String']['output']; + organizers: Array; + oss: GQLCampaignOss; + participants: GQLCampaignParticipantConnection; + /** Quote count of this campaign's quote wall. */ + quoteCount: Scalars['Int']['output']; + /** Quotes on this campaign's quote wall (public). */ + quotes: GQLQuoteConnection; + shortHash: Scalars['String']['output']; + showAd: Scalars['Boolean']['output']; + showOther: Scalars['Boolean']['output']; + stages: Array; + state: GQLCampaignState; + writingPeriod?: Maybe; +}; -export type GQLWriting = GQLArticle | GQLComment | GQLMoment - -export type GQLWritingChallenge = GQLCampaign & - GQLChannel & - GQLNode & { - __typename?: 'WritingChallenge' - announcements: Array - application?: Maybe - applicationPeriod?: Maybe - articles: GQLCampaignArticleConnection - channelEnabled: Scalars['Boolean']['output'] - cover?: Maybe - description?: Maybe - featuredDescription: Scalars['String']['output'] - id: Scalars['ID']['output'] - isManager: Scalars['Boolean']['output'] - link: Scalars['String']['output'] - name: Scalars['String']['output'] - navbarTitle: Scalars['String']['output'] - organizers: Array - oss: GQLCampaignOss - participants: GQLCampaignParticipantConnection - shortHash: Scalars['String']['output'] - showAd: Scalars['Boolean']['output'] - showOther: Scalars['Boolean']['output'] - stages: Array - state: GQLCampaignState - writingPeriod?: Maybe - } export type GQLWritingChallengeArticlesArgs = { - input: GQLCampaignArticlesInput -} + input: GQLCampaignArticlesInput; +}; + export type GQLWritingChallengeDescriptionArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; + + +export type GQLWritingChallengeDiscussionArgs = { + input: GQLCommentsInput; +}; + export type GQLWritingChallengeFeaturedDescriptionArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; + export type GQLWritingChallengeNameArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; + export type GQLWritingChallengeNavbarTitleArgs = { - input?: InputMaybe -} + input?: InputMaybe; +}; + export type GQLWritingChallengeParticipantsArgs = { - input: GQLCampaignParticipantsInput -} + input: GQLCampaignParticipantsInput; +}; + + +export type GQLWritingChallengeQuotesArgs = { + input: GQLQuotesInput; +}; export type GQLWritingConnection = GQLConnection & { - __typename?: 'WritingConnection' - edges?: Maybe> - pageInfo: GQLPageInfo - totalCount: Scalars['Int']['output'] -} + __typename?: 'WritingConnection'; + edges?: Maybe>; + pageInfo: GQLPageInfo; + totalCount: Scalars['Int']['output']; +}; export type GQLWritingEdge = { - __typename?: 'WritingEdge' - cursor: Scalars['String']['output'] - node: GQLWriting -} + __typename?: 'WritingEdge'; + cursor: Scalars['String']['output']; + node: GQLWriting; +}; export type GQLWritingInput = { - after?: InputMaybe - first?: InputMaybe -} + after?: InputMaybe; + first?: InputMaybe; +}; -export type WithIndex = TObject & Record -export type ResolversObject = WithIndex +export type WithIndex = TObject & Record; +export type ResolversObject = WithIndex; -export type ResolverTypeWrapper = Promise | T +export type ResolverTypeWrapper = Promise | T; -export type Resolver< - TResult, - TParent = {}, - TContext = {}, - TArgs = {} -> = ResolverFn +export type Resolver = ResolverFn; export type ResolverFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo -) => Promise | TResult +) => Promise | TResult; export type SubscriptionSubscribeFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo -) => AsyncIterable | Promise> +) => AsyncIterable | Promise>; export type SubscriptionResolveFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo -) => TResult | Promise - -export interface SubscriptionSubscriberObject< - TResult, - TKey extends string, - TParent, - TContext, - TArgs -> { - subscribe: SubscriptionSubscribeFn< - { [key in TKey]: TResult }, - TParent, - TContext, - TArgs - > - resolve?: SubscriptionResolveFn< - TResult, - { [key in TKey]: TResult }, - TContext, - TArgs - > +) => TResult | Promise; + +export interface SubscriptionSubscriberObject { + subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>; + resolve?: SubscriptionResolveFn; } export interface SubscriptionResolverObject { - subscribe: SubscriptionSubscribeFn - resolve: SubscriptionResolveFn + subscribe: SubscriptionSubscribeFn; + resolve: SubscriptionResolveFn; } -export type SubscriptionObject< - TResult, - TKey extends string, - TParent, - TContext, - TArgs -> = +export type SubscriptionObject = | SubscriptionSubscriberObject - | SubscriptionResolverObject - -export type SubscriptionResolver< - TResult, - TKey extends string, - TParent = {}, - TContext = {}, - TArgs = {} -> = - | (( - ...args: any[] - ) => SubscriptionObject) - | SubscriptionObject + | SubscriptionResolverObject; + +export type SubscriptionResolver = + | ((...args: any[]) => SubscriptionObject) + | SubscriptionObject; export type TypeResolveFn = ( parent: TParent, context: TContext, info: GraphQLResolveInfo -) => Maybe | Promise> +) => Maybe | Promise>; -export type IsTypeOfResolverFn = ( - obj: T, - context: TContext, - info: GraphQLResolveInfo -) => boolean | Promise +export type IsTypeOfResolverFn = (obj: T, context: TContext, info: GraphQLResolveInfo) => boolean | Promise; -export type NextResolverFn = () => Promise +export type NextResolverFn = () => Promise; -export type DirectiveResolverFn< - TResult = {}, - TParent = {}, - TContext = {}, - TArgs = {} -> = ( +export type DirectiveResolverFn = ( next: NextResolverFn, parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo -) => TResult | Promise +) => TResult | Promise; /** Mapping of union types */ -export type GQLResolversUnionTypes<_RefType extends Record> = - ResolversObject<{ - Donator: ETHWalletModel | UserModel - FollowingActivity: - | (Omit & { - nodes?: Maybe> - }) - | (Omit & { - nodes?: Maybe> - }) - | (Omit & { - actor: _RefType['User'] - node: _RefType['Article'] - target: _RefType['Tag'] - }) - | (Omit & { - actor: _RefType['User'] - node: _RefType['Comment'] - target: _RefType['Circle'] - }) - | (Omit & { - actor: _RefType['User'] - node: _RefType['Circle'] - }) - | (Omit & { - actor: _RefType['User'] - more: Array<_RefType['Moment']> - node: _RefType['Moment'] - }) - | (Omit & { - actor: _RefType['User'] - node: _RefType['Article'] - }) - | (Omit & { - nodes?: Maybe> - }) - Invitee: GQLPerson | UserModel - Response: ArticleModel | CommentModel - TransactionTarget: ArticleModel | CircleModel | TransactionModel - Writing: ArticleModel | CommentModel | MomentModel - }> +export type GQLResolversUnionTypes<_RefType extends Record> = ResolversObject<{ + Donator: ( ETHWalletModel ) | ( UserModel ); + FollowingActivity: ( Omit & { nodes?: Maybe> } ) | ( Omit & { nodes?: Maybe> } ) | ( Omit & { actor: _RefType['User'], node: _RefType['Article'], target: _RefType['Tag'] } ) | ( Omit & { actor: _RefType['User'], node: _RefType['Comment'], target: _RefType['Circle'] } ) | ( Omit & { actor: _RefType['User'], node: _RefType['Circle'] } ) | ( Omit & { actor: _RefType['User'], more: Array<_RefType['Moment']>, node: _RefType['Moment'] } ) | ( Omit & { actor: _RefType['User'], node: _RefType['Article'] } ) | ( Omit & { nodes?: Maybe> } ); + Invitee: ( GQLPerson ) | ( UserModel ); + Response: ( ArticleModel ) | ( CommentModel ); + TransactionTarget: ( ArticleModel ) | ( CircleModel ) | ( TransactionModel ); + Writing: ( ArticleModel ) | ( CommentModel ) | ( MomentModel ); +}>; /** Mapping of interface types */ -export type GQLResolversInterfaceTypes< - _RefType extends Record -> = ResolversObject<{ - Campaign: CampaignModel - Channel: CurationChannelModel | TagModel | TopicChannelModel | CampaignModel - Connection: - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges: Array> - }) - | (Omit & { - edges: Array<_RefType['CampaignArticleEdge']> - }) - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges: Array<_RefType['IcymiTopicEdge']> - }) - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges?: Maybe> - }) - | GQLRecentSearchConnection - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges?: Maybe> - }) - | GQLSkippedListItemsConnection - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges: Array<_RefType['TopicChannelFeedbackEdge']> - }) - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges?: Maybe> - }) - | (Omit & { - edges?: Maybe> - }) - Node: - | ArticleModel - | ArticleVersionModel - | CircleModel - | CollectionModel - | CommentModel - | CurationChannelModel - | DraftModel - | MattersChoiceTopicModel - | MomentModel - | ReportModel - | TagModel - | TopicChannelModel - | UserModel - | CampaignModel - Notice: - | NoticeItemModel - | NoticeItemModel - | NoticeItemModel - | NoticeItemModel - | NoticeItemModel - | NoticeItemModel - | NoticeItemModel - | NoticeItemModel - | NoticeItemModel - | NoticeItemModel - | NoticeItemModel - PinnableWork: ArticleModel | CollectionModel -}> +export type GQLResolversInterfaceTypes<_RefType extends Record> = ResolversObject<{ + Campaign: ( CampaignModel ); + Channel: ( CurationChannelModel ) | ( TagModel ) | ( TopicChannelModel ) | ( CampaignModel ); + Connection: ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges: Array> } ) | ( Omit & { edges: Array<_RefType['CampaignArticleEdge']> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges: Array<_RefType['IcymiTopicEdge']> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( GQLRecentSearchConnection ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( GQLSkippedListItemsConnection ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges: Array<_RefType['TopicChannelFeedbackEdge']> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ) | ( Omit & { edges?: Maybe> } ); + Node: ( ArticleModel ) | ( ArticleVersionModel ) | ( CircleModel ) | ( CollectionModel ) | ( CommentModel ) | ( CurationChannelModel ) | ( DraftModel ) | ( MattersChoiceTopicModel ) | ( MomentModel ) | ( ReportModel ) | ( SpamRingModel ) | ( TagModel ) | ( TopicChannelModel ) | ( UserModel ) | ( CampaignModel ); + Notice: ( NoticeItemModel ) | ( NoticeItemModel ) | ( NoticeItemModel ) | ( NoticeItemModel ) | ( NoticeItemModel ) | ( NoticeItemModel ) | ( NoticeItemModel ) | ( NoticeItemModel ) | ( NoticeItemModel ) | ( NoticeItemModel ) | ( NoticeItemModel ); + PinnableWork: ( ArticleModel ) | ( CollectionModel ); +}>; /** Mapping between all available schema types and the resolvers types */ export type GQLResolversTypes = ResolversObject<{ - AdStatus: ResolverTypeWrapper - AddCollectionsArticlesInput: GQLAddCollectionsArticlesInput - AddCreditInput: GQLAddCreditInput - AddCreditResult: ResolverTypeWrapper< - Omit & { - transaction: GQLResolversTypes['Transaction'] - } - > - AddCurationChannelArticlesInput: GQLAddCurationChannelArticlesInput - Announcement: ResolverTypeWrapper - AnnouncementChannel: ResolverTypeWrapper< - Omit & { - channel: GQLResolversTypes['Channel'] - } - > - AnnouncementChannelInput: GQLAnnouncementChannelInput - AnnouncementType: GQLAnnouncementType - AnnouncementsInput: GQLAnnouncementsInput - ApplyCampaignInput: GQLApplyCampaignInput - AppreciateArticleInput: GQLAppreciateArticleInput - Appreciation: ResolverTypeWrapper - AppreciationConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - AppreciationEdge: ResolverTypeWrapper< - Omit & { - node: GQLResolversTypes['Appreciation'] - } - > - AppreciationPurpose: GQLAppreciationPurpose - ArchiveUserFailure: ResolverTypeWrapper - ArchiveUsersInput: GQLArchiveUsersInput - ArchiveUsersResult: ResolverTypeWrapper< - Omit & { - archived: Array - } - > - Article: ResolverTypeWrapper - ArticleAccess: ResolverTypeWrapper - ArticleAccessType: GQLArticleAccessType - ArticleArticleNotice: ResolverTypeWrapper - ArticleArticleNoticeType: GQLArticleArticleNoticeType - ArticleCampaign: ResolverTypeWrapper< - Omit & { - campaign: GQLResolversTypes['Campaign'] - stage?: Maybe - } - > - ArticleCampaignInput: GQLArticleCampaignInput - ArticleClassification: ResolverTypeWrapper - ArticleConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - ArticleContents: ResolverTypeWrapper - ArticleDonation: ResolverTypeWrapper< - Omit & { - sender?: Maybe - } - > - ArticleDonationConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - ArticleDonationEdge: ResolverTypeWrapper< - Omit & { - node: GQLResolversTypes['ArticleDonation'] - } - > - ArticleEdge: ResolverTypeWrapper< - Omit & { node: GQLResolversTypes['Article'] } - > - ArticleFederationEligibility: ResolverTypeWrapper - ArticleFederationSetting: ResolverTypeWrapper - ArticleInput: GQLArticleInput - ArticleLicenseType: GQLArticleLicenseType - ArticleNotice: ResolverTypeWrapper - ArticleNoticeType: GQLArticleNoticeType - ArticleOSS: ResolverTypeWrapper - ArticleRecommendationActivity: ResolverTypeWrapper< - Omit & { - nodes?: Maybe> - } - > - ArticleRecommendationActivitySource: GQLArticleRecommendationActivitySource - ArticleState: GQLArticleState - ArticleTopicChannel: ResolverTypeWrapper< - Omit & { - channel: GQLResolversTypes['TopicChannel'] - } - > - ArticleTranslation: ResolverTypeWrapper - ArticleTranslationInput: GQLArticleTranslationInput - ArticleVersion: ResolverTypeWrapper - ArticleVersionEdge: ResolverTypeWrapper< - Omit & { - node: GQLResolversTypes['ArticleVersion'] - } - > - ArticleVersionsConnection: ResolverTypeWrapper< - Omit & { - edges: Array> - } - > - ArticleVersionsInput: GQLArticleVersionsInput - ArticlesSort: GQLArticlesSort - Asset: ResolverTypeWrapper - AssetType: GQLAssetType - AuthResult: ResolverTypeWrapper< - Omit & { user?: Maybe } - > - AuthResultType: GQLAuthResultType - AuthorsType: GQLAuthorsType - Badge: ResolverTypeWrapper - BadgeType: GQLBadgeType - BadgedUsersInput: GQLBadgedUsersInput - Balance: ResolverTypeWrapper - BanCampaignArticlesInput: GQLBanCampaignArticlesInput - BlockchainTransaction: ResolverTypeWrapper - BlockedSearchKeyword: ResolverTypeWrapper - Boolean: ResolverTypeWrapper - BoostTypes: GQLBoostTypes - CacheControlScope: GQLCacheControlScope - Campaign: ResolverTypeWrapper - CampaignApplication: ResolverTypeWrapper - CampaignApplicationState: GQLCampaignApplicationState - CampaignArticleConnection: ResolverTypeWrapper< - Omit & { - edges: Array - } - > - CampaignArticleEdge: ResolverTypeWrapper< - Omit & { - node: GQLResolversTypes['Article'] - } - > - CampaignArticleNotice: ResolverTypeWrapper - CampaignArticleNoticeType: GQLCampaignArticleNoticeType - CampaignArticlesFilter: GQLCampaignArticlesFilter - CampaignArticlesInput: GQLCampaignArticlesInput - CampaignConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - CampaignEdge: ResolverTypeWrapper< - Omit & { node: GQLResolversTypes['Campaign'] } - > - CampaignInput: GQLCampaignInput - CampaignOSS: ResolverTypeWrapper - CampaignParticipantConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - CampaignParticipantEdge: ResolverTypeWrapper< - Omit & { - application?: Maybe - node: GQLResolversTypes['User'] - } - > - CampaignParticipantsInput: GQLCampaignParticipantsInput - CampaignStage: ResolverTypeWrapper - CampaignStageInput: GQLCampaignStageInput - CampaignState: GQLCampaignState - CampaignsFilter: GQLCampaignsFilter - CampaignsFilterSort: GQLCampaignsFilterSort - CampaignsFilterState: GQLCampaignsFilterState - CampaignsInput: GQLCampaignsInput - Chain: GQLChain - Channel: ResolverTypeWrapper< - GQLResolversInterfaceTypes['Channel'] - > - ChannelArticleConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - ChannelArticleEdge: ResolverTypeWrapper< - Omit & { node: GQLResolversTypes['Article'] } - > - ChannelArticlesFilter: GQLChannelArticlesFilter - ChannelArticlesInput: GQLChannelArticlesInput - ChannelInput: GQLChannelInput - ChannelsInput: GQLChannelsInput - Circle: ResolverTypeWrapper - CircleAnalytics: ResolverTypeWrapper - CircleConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - CircleContentAnalytics: ResolverTypeWrapper - CircleContentAnalyticsDatum: ResolverTypeWrapper< - Omit & { - node: GQLResolversTypes['Article'] - } - > - CircleEdge: ResolverTypeWrapper< - Omit & { node: GQLResolversTypes['Circle'] } - > - CircleFollowerAnalytics: ResolverTypeWrapper - CircleIncomeAnalytics: ResolverTypeWrapper - CircleInput: GQLCircleInput - CircleNotice: ResolverTypeWrapper - CircleNoticeType: GQLCircleNoticeType - CircleRecommendationActivity: ResolverTypeWrapper< - Omit & { - nodes?: Maybe> - } - > - CircleRecommendationActivitySource: GQLCircleRecommendationActivitySource - CircleState: GQLCircleState - CircleSubscriberAnalytics: ResolverTypeWrapper - ClaimLogbooksInput: GQLClaimLogbooksInput - ClaimLogbooksResult: ResolverTypeWrapper - ClaimPersonhoodBadgeInput: GQLClaimPersonhoodBadgeInput - ClassifyArticlesChannelsInput: GQLClassifyArticlesChannelsInput - ClearCommunityWatchOriginalContentInput: GQLClearCommunityWatchOriginalContentInput - ClearReadHistoryInput: GQLClearReadHistoryInput - Collection: ResolverTypeWrapper - CollectionArticlesInput: GQLCollectionArticlesInput - CollectionConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - CollectionEdge: ResolverTypeWrapper< - Omit & { node: GQLResolversTypes['Collection'] } - > - CollectionNotice: ResolverTypeWrapper - Color: GQLColor - Comment: ResolverTypeWrapper - CommentCommentNotice: ResolverTypeWrapper - CommentCommentNoticeType: GQLCommentCommentNoticeType - CommentCommentsInput: GQLCommentCommentsInput - CommentConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - CommentEdge: ResolverTypeWrapper< - Omit & { node: GQLResolversTypes['Comment'] } - > - CommentInput: GQLCommentInput - CommentNotice: ResolverTypeWrapper - CommentNoticeType: GQLCommentNoticeType - CommentSort: GQLCommentSort - CommentState: GQLCommentState - CommentType: GQLCommentType - CommentsFilter: GQLCommentsFilter - CommentsInput: GQLCommentsInput - CommunityWatchAction: ResolverTypeWrapper - CommunityWatchActionConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - CommunityWatchActionEdge: ResolverTypeWrapper< - Omit & { - node: GQLResolversTypes['CommunityWatchAction'] - } - > - CommunityWatchActionInput: GQLCommunityWatchActionInput - CommunityWatchActionSourceType: GQLCommunityWatchActionSourceType - CommunityWatchActionState: GQLCommunityWatchActionState - CommunityWatchActionsInput: GQLCommunityWatchActionsInput - CommunityWatchAppealState: GQLCommunityWatchAppealState - CommunityWatchRemoveCommentInput: GQLCommunityWatchRemoveCommentInput - CommunityWatchRemoveCommentReason: GQLCommunityWatchRemoveCommentReason - CommunityWatchReviewState: GQLCommunityWatchReviewState - ConfirmVerificationCodeInput: GQLConfirmVerificationCodeInput - ConnectStripeAccountInput: GQLConnectStripeAccountInput - ConnectStripeAccountResult: ResolverTypeWrapper - Connection: ResolverTypeWrapper< - GQLResolversInterfaceTypes['Connection'] - > - ConnectionArgs: GQLConnectionArgs - CreatePersonhoodHandoffInput: GQLCreatePersonhoodHandoffInput - CryptoWallet: ResolverTypeWrapper - CryptoWalletSignaturePurpose: GQLCryptoWalletSignaturePurpose - CurationChannel: ResolverTypeWrapper - CurationChannelState: GQLCurationChannelState - DateTime: ResolverTypeWrapper - DatetimeRange: ResolverTypeWrapper - DatetimeRangeInput: GQLDatetimeRangeInput - DeleteAnnouncementsInput: GQLDeleteAnnouncementsInput - DeleteCollectionArticlesInput: GQLDeleteCollectionArticlesInput - DeleteCollectionsInput: GQLDeleteCollectionsInput - DeleteCommentInput: GQLDeleteCommentInput - DeleteCurationChannelArticlesInput: GQLDeleteCurationChannelArticlesInput - DeleteDraftInput: GQLDeleteDraftInput - DeleteMomentInput: GQLDeleteMomentInput - DeleteTagsInput: GQLDeleteTagsInput - DirectImageUploadInput: GQLDirectImageUploadInput - Donator: ResolverTypeWrapper< - GQLResolversUnionTypes['Donator'] - > - Draft: ResolverTypeWrapper - DraftAccess: ResolverTypeWrapper - DraftConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - DraftEdge: ResolverTypeWrapper< - Omit & { node: GQLResolversTypes['Draft'] } - > - EditArticleInput: GQLEditArticleInput - EmailLoginInput: GQLEmailLoginInput - EntityType: GQLEntityType - ExchangeRate: ResolverTypeWrapper - ExchangeRatesInput: GQLExchangeRatesInput - Feature: ResolverTypeWrapper - FeatureFlag: GQLFeatureFlag - FeatureName: GQLFeatureName - FeaturedCommentsInput: GQLFeaturedCommentsInput - FeaturedTagsInput: GQLFeaturedTagsInput - FederationArticleSettingState: GQLFederationArticleSettingState - FederationAuthorSettingState: GQLFederationAuthorSettingState - FederationExportDecisionReason: GQLFederationExportDecisionReason - FilterInput: GQLFilterInput - Float: ResolverTypeWrapper - Following: ResolverTypeWrapper - FollowingActivity: ResolverTypeWrapper< - GQLResolversUnionTypes['FollowingActivity'] - > - FollowingActivityConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - FollowingActivityEdge: ResolverTypeWrapper< - Omit & { - node: GQLResolversTypes['FollowingActivity'] - } - > - FrequentSearchInput: GQLFrequentSearchInput - GenerateSigningMessageInput: GQLGenerateSigningMessageInput - GrantType: GQLGrantType - ID: ResolverTypeWrapper - IcymiTopic: ResolverTypeWrapper - IcymiTopicConnection: ResolverTypeWrapper< - Omit & { - edges: Array - } - > - IcymiTopicEdge: ResolverTypeWrapper< - Omit & { node: GQLResolversTypes['IcymiTopic'] } - > - IcymiTopicState: GQLIcymiTopicState - IdentityInput: GQLIdentityInput - Int: ResolverTypeWrapper - Invitation: ResolverTypeWrapper - InvitationConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - InvitationEdge: ResolverTypeWrapper< - Omit & { node: GQLResolversTypes['Invitation'] } - > - InvitationState: GQLInvitationState - InviteCircleInput: GQLInviteCircleInput - InviteCircleInvitee: GQLInviteCircleInvitee - Invitee: ResolverTypeWrapper< - GQLResolversUnionTypes['Invitee'] - > - Invites: ResolverTypeWrapper - KeywordInput: GQLKeywordInput - KeywordsInput: GQLKeywordsInput - LikeCollectionInput: GQLLikeCollectionInput - LikeMomentInput: GQLLikeMomentInput - Liker: ResolverTypeWrapper - LogRecordInput: GQLLogRecordInput - LogRecordTypes: GQLLogRecordTypes - Member: ResolverTypeWrapper - MemberConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - MemberEdge: ResolverTypeWrapper< - Omit & { node: GQLResolversTypes['Member'] } - > - MergeTagsInput: GQLMergeTagsInput - MigrationInput: GQLMigrationInput - MigrationType: GQLMigrationType - Moment: ResolverTypeWrapper - MomentConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - MomentEdge: ResolverTypeWrapper< - Omit & { node: GQLResolversTypes['Moment'] } - > - MomentFeedApplication: ResolverTypeWrapper - MomentFeedUserReviewedBy: GQLMomentFeedUserReviewedBy - MomentFeedUserState: GQLMomentFeedUserState - MomentFeedUsersInput: GQLMomentFeedUsersInput - MomentInput: GQLMomentInput - MomentNotice: ResolverTypeWrapper - MomentNoticeType: GQLMomentNoticeType - MomentState: GQLMomentState - MonthlyDatum: ResolverTypeWrapper - Mutation: ResolverTypeWrapper<{}> - NFTAsset: ResolverTypeWrapper - Node: ResolverTypeWrapper< - GQLResolversInterfaceTypes['Node'] - > - NodeInput: GQLNodeInput - NodesInput: GQLNodesInput - Notice: ResolverTypeWrapper - NoticeConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - NoticeEdge: ResolverTypeWrapper< - Omit & { node: GQLResolversTypes['Notice'] } - > - NotificationSetting: ResolverTypeWrapper - NotificationSettingType: GQLNotificationSettingType - OAuthClient: ResolverTypeWrapper - OAuthClientConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - OAuthClientEdge: ResolverTypeWrapper< - Omit & { - node: GQLResolversTypes['OAuthClient'] - } - > - OAuthClientInput: GQLOAuthClientInput - OSS: ResolverTypeWrapper< - Omit< - GQLOss, - | 'articles' - | 'badgedUsers' - | 'comments' - | 'icymiTopics' - | 'momentFeedUsers' - | 'moments' - | 'oauthClients' - | 'reports' - | 'restrictedUsers' - | 'seedingUsers' - | 'tags' - | 'topicChannelFeedbacks' - | 'users' - > & { - articles: GQLResolversTypes['ArticleConnection'] - badgedUsers: GQLResolversTypes['UserConnection'] - comments: GQLResolversTypes['CommentConnection'] - icymiTopics: GQLResolversTypes['IcymiTopicConnection'] - momentFeedUsers: GQLResolversTypes['UserConnection'] - moments: GQLResolversTypes['MomentConnection'] - oauthClients: GQLResolversTypes['OAuthClientConnection'] - reports: GQLResolversTypes['ReportConnection'] - restrictedUsers: GQLResolversTypes['UserConnection'] - seedingUsers: GQLResolversTypes['UserConnection'] - tags: GQLResolversTypes['TagConnection'] - topicChannelFeedbacks: GQLResolversTypes['TopicChannelFeedbackConnection'] - users: GQLResolversTypes['UserConnection'] - } - > - OSSArticlesFilterInput: GQLOssArticlesFilterInput - OSSArticlesInput: GQLOssArticlesInput - OSSReportsFilter: GQLOssReportsFilter - OSSReportsInput: GQLOssReportsInput - Oauth1CredentialInput: GQLOauth1CredentialInput - Official: ResolverTypeWrapper< - Omit & { - announcements?: Maybe> - } - > - OfficialAnnouncementNotice: ResolverTypeWrapper - PageInfo: ResolverTypeWrapper - PayToInput: GQLPayToInput - PayToResult: ResolverTypeWrapper< - Omit & { - transaction: GQLResolversTypes['Transaction'] - } - > - PayoutInput: GQLPayoutInput - Person: ResolverTypeWrapper - PersonhoodHandoff: ResolverTypeWrapper - PinCommentInput: GQLPinCommentInput - PinHistory: ResolverTypeWrapper< - Omit & { feed: GQLResolversTypes['Node'] } - > - PinnableWork: ResolverTypeWrapper< - GQLResolversInterfaceTypes['PinnableWork'] - > - Price: ResolverTypeWrapper - PriceState: GQLPriceState - PublishArticleInput: GQLPublishArticleInput - PublishState: GQLPublishState - PutAnnouncementInput: GQLPutAnnouncementInput - PutArticleFederationSettingInput: GQLPutArticleFederationSettingInput - PutCircleArticlesInput: GQLPutCircleArticlesInput - PutCircleArticlesType: GQLPutCircleArticlesType - PutCircleInput: GQLPutCircleInput - PutCollectionInput: GQLPutCollectionInput - PutCommentInput: GQLPutCommentInput - PutCurationChannelInput: GQLPutCurationChannelInput - PutDraftInput: GQLPutDraftInput - PutIcymiTopicInput: GQLPutIcymiTopicInput - PutMomentInput: GQLPutMomentInput - PutOAuthClientInput: GQLPutOAuthClientInput - PutRemarkInput: GQLPutRemarkInput - PutRestrictedUsersInput: GQLPutRestrictedUsersInput - PutSkippedListItemInput: GQLPutSkippedListItemInput - PutTagChannelInput: GQLPutTagChannelInput - PutTopicChannelInput: GQLPutTopicChannelInput - PutUserFeatureFlagsInput: GQLPutUserFeatureFlagsInput - PutUserFederationSettingInput: GQLPutUserFederationSettingInput - PutWritingChallengeInput: GQLPutWritingChallengeInput - Query: ResolverTypeWrapper<{}> - QuoteCurrency: GQLQuoteCurrency - ReadArticleInput: GQLReadArticleInput - ReadHistory: ResolverTypeWrapper< - Omit & { article: GQLResolversTypes['Article'] } - > - ReadHistoryConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - ReadHistoryEdge: ResolverTypeWrapper< - Omit & { - node: GQLResolversTypes['ReadHistory'] - } - > - RecentSearchConnection: ResolverTypeWrapper - RecentSearchEdge: ResolverTypeWrapper - RecommendFilterInput: GQLRecommendFilterInput - RecommendInput: GQLRecommendInput - RecommendTypes: GQLRecommendTypes - Recommendation: ResolverTypeWrapper - RecommendationFollowingFilterInput: GQLRecommendationFollowingFilterInput - RecommendationFollowingFilterType: GQLRecommendationFollowingFilterType - RecommendationFollowingInput: GQLRecommendationFollowingInput - RecommendationNewestInput: GQLRecommendationNewestInput - RefreshIPNSFeedInput: GQLRefreshIpnsFeedInput - RelatedDonationArticlesInput: GQLRelatedDonationArticlesInput - RemarkTypes: GQLRemarkTypes - RemoveSocialLoginInput: GQLRemoveSocialLoginInput - RenameTagInput: GQLRenameTagInput - ReorderChannelsInput: GQLReorderChannelsInput - ReorderCollectionArticlesInput: GQLReorderCollectionArticlesInput - ReorderMoveInput: GQLReorderMoveInput - Report: ResolverTypeWrapper - ReportConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - ReportEdge: ResolverTypeWrapper< - Omit & { node: GQLResolversTypes['Report'] } - > - ReportReason: GQLReportReason - ReportSource: GQLReportSource - ResetLikerIdInput: GQLResetLikerIdInput - ResetPasswordInput: GQLResetPasswordInput - ResetPasswordType: GQLResetPasswordType - Response: ResolverTypeWrapper< - GQLResolversUnionTypes['Response'] - > - ResponseConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - ResponseEdge: ResolverTypeWrapper< - Omit & { node: GQLResolversTypes['Response'] } - > - ResponseSort: GQLResponseSort - ResponsesInput: GQLResponsesInput - RestoreCommunityWatchCommentInput: GQLRestoreCommunityWatchCommentInput - ReviewTopicChannelFeedbackInput: GQLReviewTopicChannelFeedbackInput - Role: GQLRole - SearchAPIVersion: GQLSearchApiVersion - SearchExclude: GQLSearchExclude - SearchFilter: GQLSearchFilter - SearchInput: GQLSearchInput - SearchResultConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - SearchResultEdge: ResolverTypeWrapper< - Omit & { node: GQLResolversTypes['Node'] } - > - SearchTypes: GQLSearchTypes - SendCampaignAnnouncementInput: GQLSendCampaignAnnouncementInput - SendVerificationCodeInput: GQLSendVerificationCodeInput - SetAdStatusInput: GQLSetAdStatusInput - SetArticleFederationSettingInput: GQLSetArticleFederationSettingInput - SetArticleTopicChannelsInput: GQLSetArticleTopicChannelsInput - SetBoostInput: GQLSetBoostInput - SetCurrencyInput: GQLSetCurrencyInput - SetEmailInput: GQLSetEmailInput - SetFeatureInput: GQLSetFeatureInput - SetPasswordInput: GQLSetPasswordInput - SetSpamStatusInput: GQLSetSpamStatusInput - SetUserNameInput: GQLSetUserNameInput - SetViewerFederationSettingInput: GQLSetViewerFederationSettingInput - SigningMessagePurpose: GQLSigningMessagePurpose - SigningMessageResult: ResolverTypeWrapper - SingleFileUploadInput: GQLSingleFileUploadInput - SkippedListItem: ResolverTypeWrapper - SkippedListItemEdge: ResolverTypeWrapper - SkippedListItemType: GQLSkippedListItemType - SkippedListItemsConnection: ResolverTypeWrapper - SkippedListItemsInput: GQLSkippedListItemsInput - SocialAccount: ResolverTypeWrapper - SocialAccountType: GQLSocialAccountType - SocialLoginInput: GQLSocialLoginInput - SpamStatus: ResolverTypeWrapper - String: ResolverTypeWrapper - StripeAccount: ResolverTypeWrapper - StripeAccountCountry: GQLStripeAccountCountry - SubmitReportInput: GQLSubmitReportInput - SubmitTopicChannelFeedbackInput: GQLSubmitTopicChannelFeedbackInput - SubscribeCircleInput: GQLSubscribeCircleInput - SubscribeCircleResult: ResolverTypeWrapper< - Omit & { - circle: GQLResolversTypes['Circle'] - } - > - Tag: ResolverTypeWrapper - TagArticlesInput: GQLTagArticlesInput - TagArticlesSortBy: GQLTagArticlesSortBy - TagConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - TagEdge: ResolverTypeWrapper< - Omit & { node: GQLResolversTypes['Tag'] } - > - TagOSS: ResolverTypeWrapper - TagWritingConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - TagWritingEdge: ResolverTypeWrapper< - Omit & { node: GQLResolversTypes['Writing'] } - > - TagsInput: GQLTagsInput - TagsSort: GQLTagsSort - ToggleCircleMemberInput: GQLToggleCircleMemberInput - ToggleItemInput: GQLToggleItemInput - TogglePinChannelArticlesInput: GQLTogglePinChannelArticlesInput - ToggleRecommendInput: GQLToggleRecommendInput - ToggleSeedingUsersInput: GQLToggleSeedingUsersInput - ToggleUsersBadgeInput: GQLToggleUsersBadgeInput - ToggleWritingChallengeFeaturedArticlesInput: GQLToggleWritingChallengeFeaturedArticlesInput - TopDonatorConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - TopDonatorEdge: ResolverTypeWrapper< - Omit & { node: GQLResolversTypes['Donator'] } - > - TopDonatorFilter: GQLTopDonatorFilter - TopDonatorInput: GQLTopDonatorInput - TopicChannel: ResolverTypeWrapper - TopicChannelClassification: ResolverTypeWrapper - TopicChannelFeedback: ResolverTypeWrapper - TopicChannelFeedbackAction: GQLTopicChannelFeedbackAction - TopicChannelFeedbackConnection: ResolverTypeWrapper< - Omit & { - edges: Array - } - > - TopicChannelFeedbackEdge: ResolverTypeWrapper< - Omit & { - node: GQLResolversTypes['TopicChannelFeedback'] - } - > - TopicChannelFeedbackState: GQLTopicChannelFeedbackState - TopicChannelFeedbackType: GQLTopicChannelFeedbackType - TopicChannelFeedbacksFilterInput: GQLTopicChannelFeedbacksFilterInput - TopicChannelFeedbacksInput: GQLTopicChannelFeedbacksInput - Transaction: ResolverTypeWrapper - TransactionConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - TransactionCurrency: GQLTransactionCurrency - TransactionEdge: ResolverTypeWrapper< - Omit & { - node: GQLResolversTypes['Transaction'] - } - > - TransactionNotice: ResolverTypeWrapper - TransactionNoticeType: GQLTransactionNoticeType - TransactionPurpose: GQLTransactionPurpose - TransactionState: GQLTransactionState - TransactionTarget: ResolverTypeWrapper< - GQLResolversUnionTypes['TransactionTarget'] - > - TransactionsArgs: GQLTransactionsArgs - TransactionsFilter: GQLTransactionsFilter - TransactionsReceivedByArgs: GQLTransactionsReceivedByArgs - TranslatedAnnouncement: ResolverTypeWrapper - TranslationArgs: GQLTranslationArgs - TranslationInput: GQLTranslationInput - TranslationModel: GQLTranslationModel - UnbindLikerIdInput: GQLUnbindLikerIdInput - UnlikeCollectionInput: GQLUnlikeCollectionInput - UnlikeMomentInput: GQLUnlikeMomentInput - UnpinCommentInput: GQLUnpinCommentInput - UnsubscribeCircleInput: GQLUnsubscribeCircleInput - UnvoteCommentInput: GQLUnvoteCommentInput - UpdateArticleSensitiveInput: GQLUpdateArticleSensitiveInput - UpdateArticleStateInput: GQLUpdateArticleStateInput - UpdateCampaignApplicationStateInput: GQLUpdateCampaignApplicationStateInput - UpdateCommentsStateInput: GQLUpdateCommentsStateInput - UpdateCommunityWatchActionStateInput: GQLUpdateCommunityWatchActionStateInput - UpdateMomentFeedApplicationStateInput: GQLUpdateMomentFeedApplicationStateInput - UpdateNotificationSettingInput: GQLUpdateNotificationSettingInput - UpdateUserExtraInput: GQLUpdateUserExtraInput - UpdateUserInfoInput: GQLUpdateUserInfoInput - UpdateUserRoleInput: GQLUpdateUserRoleInput - UpdateUserStateInput: GQLUpdateUserStateInput - Upload: ResolverTypeWrapper - User: ResolverTypeWrapper - UserActivity: ResolverTypeWrapper - UserAddArticleTagActivity: ResolverTypeWrapper< - Omit & { - actor: GQLResolversTypes['User'] - node: GQLResolversTypes['Article'] - target: GQLResolversTypes['Tag'] - } - > - UserAnalytics: ResolverTypeWrapper - UserArticlesFilter: GQLUserArticlesFilter - UserArticlesInput: GQLUserArticlesInput - UserArticlesSort: GQLUserArticlesSort - UserBroadcastCircleActivity: ResolverTypeWrapper< - Omit & { - actor: GQLResolversTypes['User'] - node: GQLResolversTypes['Comment'] - target: GQLResolversTypes['Circle'] - } - > - UserConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - UserCreateCircleActivity: ResolverTypeWrapper< - Omit & { - actor: GQLResolversTypes['User'] - node: GQLResolversTypes['Circle'] - } - > - UserEdge: ResolverTypeWrapper< - Omit & { node: GQLResolversTypes['User'] } - > - UserFeatureFlag: ResolverTypeWrapper - UserFeatureFlagType: GQLUserFeatureFlagType - UserFeatures: ResolverTypeWrapper - UserFederationSetting: ResolverTypeWrapper - UserGroup: GQLUserGroup - UserInfo: ResolverTypeWrapper - UserInfoFields: GQLUserInfoFields - UserInput: GQLUserInput - UserLanguage: GQLUserLanguage - UserNotice: ResolverTypeWrapper - UserNoticeType: GQLUserNoticeType - UserOSS: ResolverTypeWrapper - UserPostMomentActivity: ResolverTypeWrapper< - Omit & { - actor: GQLResolversTypes['User'] - more: Array - node: GQLResolversTypes['Moment'] - } - > - UserPublishArticleActivity: ResolverTypeWrapper< - Omit & { - actor: GQLResolversTypes['User'] - node: GQLResolversTypes['Article'] - } - > - UserRecommendationActivity: ResolverTypeWrapper< - Omit & { - nodes?: Maybe> - } - > - UserRecommendationActivitySource: GQLUserRecommendationActivitySource - UserRestriction: ResolverTypeWrapper - UserRestrictionType: GQLUserRestrictionType - UserRole: GQLUserRole - UserSettings: ResolverTypeWrapper - UserState: GQLUserState - UserStatus: ResolverTypeWrapper - VerificationCodeType: GQLVerificationCodeType - VerifyEmailInput: GQLVerifyEmailInput - Vote: GQLVote - VoteCommentInput: GQLVoteCommentInput - Wallet: ResolverTypeWrapper - WalletLoginInput: GQLWalletLoginInput - WithdrawLockedTokensResult: ResolverTypeWrapper< - Omit & { - transaction: GQLResolversTypes['Transaction'] - } - > - Writing: ResolverTypeWrapper - WritingChallenge: ResolverTypeWrapper - WritingConnection: ResolverTypeWrapper< - Omit & { - edges?: Maybe> - } - > - WritingEdge: ResolverTypeWrapper< - Omit & { node: GQLResolversTypes['Writing'] } - > - WritingInput: GQLWritingInput -}> + AdStatus: ResolverTypeWrapper; + AddCollectionsArticlesInput: GQLAddCollectionsArticlesInput; + AddCreditInput: GQLAddCreditInput; + AddCreditResult: ResolverTypeWrapper & { transaction: GQLResolversTypes['Transaction'] }>; + AddCurationChannelArticlesInput: GQLAddCurationChannelArticlesInput; + Announcement: ResolverTypeWrapper; + AnnouncementChannel: ResolverTypeWrapper & { channel: GQLResolversTypes['Channel'] }>; + AnnouncementChannelInput: GQLAnnouncementChannelInput; + AnnouncementType: GQLAnnouncementType; + AnnouncementsInput: GQLAnnouncementsInput; + ApplyCampaignInput: GQLApplyCampaignInput; + AppreciateArticleInput: GQLAppreciateArticleInput; + Appreciation: ResolverTypeWrapper; + AppreciationConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + AppreciationEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Appreciation'] }>; + AppreciationPurpose: GQLAppreciationPurpose; + ArchiveUserFailure: ResolverTypeWrapper; + ArchiveUsersInput: GQLArchiveUsersInput; + ArchiveUsersResult: ResolverTypeWrapper & { archived: Array }>; + Article: ResolverTypeWrapper; + ArticleAccess: ResolverTypeWrapper; + ArticleAccessType: GQLArticleAccessType; + ArticleArticleNotice: ResolverTypeWrapper; + ArticleArticleNoticeType: GQLArticleArticleNoticeType; + ArticleCampaign: ResolverTypeWrapper & { campaign: GQLResolversTypes['Campaign'], stage?: Maybe }>; + ArticleCampaignInput: GQLArticleCampaignInput; + ArticleClassification: ResolverTypeWrapper; + ArticleConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + ArticleContents: ResolverTypeWrapper; + ArticleDonation: ResolverTypeWrapper & { sender?: Maybe }>; + ArticleDonationConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + ArticleDonationEdge: ResolverTypeWrapper & { node: GQLResolversTypes['ArticleDonation'] }>; + ArticleEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Article'] }>; + ArticleFederationEligibility: ResolverTypeWrapper; + ArticleFederationSetting: ResolverTypeWrapper; + ArticleInput: GQLArticleInput; + ArticleLicenseType: GQLArticleLicenseType; + ArticleNotice: ResolverTypeWrapper; + ArticleNoticeType: GQLArticleNoticeType; + ArticleOSS: ResolverTypeWrapper; + ArticleRecommendationActivity: ResolverTypeWrapper & { nodes?: Maybe> }>; + ArticleRecommendationActivitySource: GQLArticleRecommendationActivitySource; + ArticleState: GQLArticleState; + ArticleTopicChannel: ResolverTypeWrapper & { channel: GQLResolversTypes['TopicChannel'] }>; + ArticleTranslation: ResolverTypeWrapper; + ArticleTranslationInput: GQLArticleTranslationInput; + ArticleVersion: ResolverTypeWrapper; + ArticleVersionEdge: ResolverTypeWrapper & { node: GQLResolversTypes['ArticleVersion'] }>; + ArticleVersionsConnection: ResolverTypeWrapper & { edges: Array> }>; + ArticleVersionsInput: GQLArticleVersionsInput; + ArticlesSort: GQLArticlesSort; + Asset: ResolverTypeWrapper; + AssetType: GQLAssetType; + AuthResult: ResolverTypeWrapper & { user?: Maybe }>; + AuthResultType: GQLAuthResultType; + AuthorsType: GQLAuthorsType; + Badge: ResolverTypeWrapper; + BadgeType: GQLBadgeType; + BadgedUsersInput: GQLBadgedUsersInput; + Balance: ResolverTypeWrapper; + BanCampaignArticlesInput: GQLBanCampaignArticlesInput; + BlockchainTransaction: ResolverTypeWrapper; + BlockedSearchKeyword: ResolverTypeWrapper; + Boolean: ResolverTypeWrapper; + BoostTypes: GQLBoostTypes; + CacheControlScope: GQLCacheControlScope; + Campaign: ResolverTypeWrapper; + CampaignApplication: ResolverTypeWrapper; + CampaignApplicationState: GQLCampaignApplicationState; + CampaignArticleConnection: ResolverTypeWrapper & { edges: Array }>; + CampaignArticleEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Article'] }>; + CampaignArticleNotice: ResolverTypeWrapper; + CampaignArticleNoticeType: GQLCampaignArticleNoticeType; + CampaignArticlesFilter: GQLCampaignArticlesFilter; + CampaignArticlesInput: GQLCampaignArticlesInput; + CampaignConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + CampaignEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Campaign'] }>; + CampaignInput: GQLCampaignInput; + CampaignOSS: ResolverTypeWrapper; + CampaignParticipantConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + CampaignParticipantEdge: ResolverTypeWrapper & { application?: Maybe, node: GQLResolversTypes['User'] }>; + CampaignParticipantsInput: GQLCampaignParticipantsInput; + CampaignStage: ResolverTypeWrapper; + CampaignStageInput: GQLCampaignStageInput; + CampaignState: GQLCampaignState; + CampaignsFilter: GQLCampaignsFilter; + CampaignsFilterSort: GQLCampaignsFilterSort; + CampaignsFilterState: GQLCampaignsFilterState; + CampaignsInput: GQLCampaignsInput; + Chain: GQLChain; + Channel: ResolverTypeWrapper['Channel']>; + ChannelArticleConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + ChannelArticleEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Article'] }>; + ChannelArticlesFilter: GQLChannelArticlesFilter; + ChannelArticlesInput: GQLChannelArticlesInput; + ChannelInput: GQLChannelInput; + ChannelsInput: GQLChannelsInput; + Circle: ResolverTypeWrapper; + CircleAnalytics: ResolverTypeWrapper; + CircleConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + CircleContentAnalytics: ResolverTypeWrapper; + CircleContentAnalyticsDatum: ResolverTypeWrapper & { node: GQLResolversTypes['Article'] }>; + CircleEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Circle'] }>; + CircleFollowerAnalytics: ResolverTypeWrapper; + CircleIncomeAnalytics: ResolverTypeWrapper; + CircleInput: GQLCircleInput; + CircleNotice: ResolverTypeWrapper; + CircleNoticeType: GQLCircleNoticeType; + CircleRecommendationActivity: ResolverTypeWrapper & { nodes?: Maybe> }>; + CircleRecommendationActivitySource: GQLCircleRecommendationActivitySource; + CircleState: GQLCircleState; + CircleSubscriberAnalytics: ResolverTypeWrapper; + ClaimLogbooksInput: GQLClaimLogbooksInput; + ClaimLogbooksResult: ResolverTypeWrapper; + ClaimPersonhoodBadgeInput: GQLClaimPersonhoodBadgeInput; + ClassifyArticlesChannelsInput: GQLClassifyArticlesChannelsInput; + ClearCommunityWatchOriginalContentInput: GQLClearCommunityWatchOriginalContentInput; + ClearReadHistoryInput: GQLClearReadHistoryInput; + Collection: ResolverTypeWrapper; + CollectionArticlesInput: GQLCollectionArticlesInput; + CollectionConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + CollectionEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Collection'] }>; + CollectionNotice: ResolverTypeWrapper; + Color: GQLColor; + Comment: ResolverTypeWrapper; + CommentCommentNotice: ResolverTypeWrapper; + CommentCommentNoticeType: GQLCommentCommentNoticeType; + CommentCommentsInput: GQLCommentCommentsInput; + CommentConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + CommentEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Comment'] }>; + CommentInput: GQLCommentInput; + CommentNotice: ResolverTypeWrapper; + CommentNoticeType: GQLCommentNoticeType; + CommentSort: GQLCommentSort; + CommentState: GQLCommentState; + CommentType: GQLCommentType; + CommentsFilter: GQLCommentsFilter; + CommentsInput: GQLCommentsInput; + CommunityWatchAction: ResolverTypeWrapper; + CommunityWatchActionConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + CommunityWatchActionEdge: ResolverTypeWrapper & { node: GQLResolversTypes['CommunityWatchAction'] }>; + CommunityWatchActionInput: GQLCommunityWatchActionInput; + CommunityWatchActionSourceType: GQLCommunityWatchActionSourceType; + CommunityWatchActionState: GQLCommunityWatchActionState; + CommunityWatchActionsInput: GQLCommunityWatchActionsInput; + CommunityWatchAppealState: GQLCommunityWatchAppealState; + CommunityWatchRemoveCommentInput: GQLCommunityWatchRemoveCommentInput; + CommunityWatchRemoveCommentReason: GQLCommunityWatchRemoveCommentReason; + CommunityWatchReviewState: GQLCommunityWatchReviewState; + ConfirmVerificationCodeInput: GQLConfirmVerificationCodeInput; + ConnectStripeAccountInput: GQLConnectStripeAccountInput; + ConnectStripeAccountResult: ResolverTypeWrapper; + Connection: ResolverTypeWrapper['Connection']>; + ConnectionArgs: GQLConnectionArgs; + CreatePersonhoodHandoffInput: GQLCreatePersonhoodHandoffInput; + CryptoWallet: ResolverTypeWrapper; + CryptoWalletSignaturePurpose: GQLCryptoWalletSignaturePurpose; + CurationChannel: ResolverTypeWrapper; + CurationChannelState: GQLCurationChannelState; + DateTime: ResolverTypeWrapper; + DatetimeRange: ResolverTypeWrapper; + DatetimeRangeInput: GQLDatetimeRangeInput; + DeleteAnnouncementsInput: GQLDeleteAnnouncementsInput; + DeleteCollectionArticlesInput: GQLDeleteCollectionArticlesInput; + DeleteCollectionsInput: GQLDeleteCollectionsInput; + DeleteCommentInput: GQLDeleteCommentInput; + DeleteCurationChannelArticlesInput: GQLDeleteCurationChannelArticlesInput; + DeleteDraftInput: GQLDeleteDraftInput; + DeleteMomentInput: GQLDeleteMomentInput; + DeleteQuoteInput: GQLDeleteQuoteInput; + DeleteTagsInput: GQLDeleteTagsInput; + DirectImageUploadInput: GQLDirectImageUploadInput; + DismissSpamRingInput: GQLDismissSpamRingInput; + Donator: ResolverTypeWrapper['Donator']>; + Draft: ResolverTypeWrapper; + DraftAccess: ResolverTypeWrapper; + DraftConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + DraftEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Draft'] }>; + EditArticleInput: GQLEditArticleInput; + EmailLoginInput: GQLEmailLoginInput; + EntityType: GQLEntityType; + ExchangeRate: ResolverTypeWrapper; + ExchangeRatesInput: GQLExchangeRatesInput; + Feature: ResolverTypeWrapper; + FeatureFlag: GQLFeatureFlag; + FeatureName: GQLFeatureName; + FeaturedCommentsInput: GQLFeaturedCommentsInput; + FeaturedTagsInput: GQLFeaturedTagsInput; + FederationArticleSettingState: GQLFederationArticleSettingState; + FederationAuthorSettingState: GQLFederationAuthorSettingState; + FederationExportDecisionReason: GQLFederationExportDecisionReason; + FilterInput: GQLFilterInput; + Float: ResolverTypeWrapper; + Following: ResolverTypeWrapper; + FollowingActivity: ResolverTypeWrapper['FollowingActivity']>; + FollowingActivityConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + FollowingActivityEdge: ResolverTypeWrapper & { node: GQLResolversTypes['FollowingActivity'] }>; + FreezeSpamRingInput: GQLFreezeSpamRingInput; + FreezeSpamRingResult: ResolverTypeWrapper & { frozen: Array, ring: GQLResolversTypes['SpamRing'], skipped: Array }>; + FrequentSearchInput: GQLFrequentSearchInput; + GenerateSigningMessageInput: GQLGenerateSigningMessageInput; + GrantType: GQLGrantType; + ID: ResolverTypeWrapper; + IcymiTopic: ResolverTypeWrapper; + IcymiTopicConnection: ResolverTypeWrapper & { edges: Array }>; + IcymiTopicEdge: ResolverTypeWrapper & { node: GQLResolversTypes['IcymiTopic'] }>; + IcymiTopicState: GQLIcymiTopicState; + IdentityInput: GQLIdentityInput; + Int: ResolverTypeWrapper; + Invitation: ResolverTypeWrapper; + InvitationConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + InvitationEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Invitation'] }>; + InvitationState: GQLInvitationState; + InviteCircleInput: GQLInviteCircleInput; + InviteCircleInvitee: GQLInviteCircleInvitee; + Invitee: ResolverTypeWrapper['Invitee']>; + Invites: ResolverTypeWrapper; + KeywordInput: GQLKeywordInput; + KeywordsInput: GQLKeywordsInput; + LikeCollectionInput: GQLLikeCollectionInput; + LikeMomentInput: GQLLikeMomentInput; + Liker: ResolverTypeWrapper; + LogRecordInput: GQLLogRecordInput; + LogRecordTypes: GQLLogRecordTypes; + Member: ResolverTypeWrapper; + MemberConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + MemberEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Member'] }>; + MergeTagsInput: GQLMergeTagsInput; + MigrationInput: GQLMigrationInput; + MigrationType: GQLMigrationType; + Moment: ResolverTypeWrapper; + MomentConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + MomentEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Moment'] }>; + MomentFeedApplication: ResolverTypeWrapper; + MomentFeedUserReviewedBy: GQLMomentFeedUserReviewedBy; + MomentFeedUserState: GQLMomentFeedUserState; + MomentFeedUsersInput: GQLMomentFeedUsersInput; + MomentInput: GQLMomentInput; + MomentNotice: ResolverTypeWrapper; + MomentNoticeType: GQLMomentNoticeType; + MomentState: GQLMomentState; + MonthlyDatum: ResolverTypeWrapper; + Mutation: ResolverTypeWrapper<{}>; + NFTAsset: ResolverTypeWrapper; + Node: ResolverTypeWrapper['Node']>; + NodeInput: GQLNodeInput; + NodesInput: GQLNodesInput; + Notice: ResolverTypeWrapper; + NoticeConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + NoticeEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Notice'] }>; + NotificationSetting: ResolverTypeWrapper; + NotificationSettingType: GQLNotificationSettingType; + OAuthClient: ResolverTypeWrapper; + OAuthClientConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + OAuthClientEdge: ResolverTypeWrapper & { node: GQLResolversTypes['OAuthClient'] }>; + OAuthClientInput: GQLOAuthClientInput; + OSS: ResolverTypeWrapper & { articles: GQLResolversTypes['ArticleConnection'], badgedUsers: GQLResolversTypes['UserConnection'], comments: GQLResolversTypes['CommentConnection'], icymiTopics: GQLResolversTypes['IcymiTopicConnection'], momentFeedUsers: GQLResolversTypes['UserConnection'], moments: GQLResolversTypes['MomentConnection'], oauthClients: GQLResolversTypes['OAuthClientConnection'], reports: GQLResolversTypes['ReportConnection'], restrictedUsers: GQLResolversTypes['UserConnection'], seedingUsers: GQLResolversTypes['UserConnection'], spamRings: GQLResolversTypes['SpamRingConnection'], tags: GQLResolversTypes['TagConnection'], topicChannelFeedbacks: GQLResolversTypes['TopicChannelFeedbackConnection'], users: GQLResolversTypes['UserConnection'] }>; + OSSArticlesFilterInput: GQLOssArticlesFilterInput; + OSSArticlesInput: GQLOssArticlesInput; + OSSCommentsInput: GQLOssCommentsInput; + OSSContentSpamSort: GQLOssContentSpamSort; + OSSMomentsInput: GQLOssMomentsInput; + OSSReportsFilter: GQLOssReportsFilter; + OSSReportsInput: GQLOssReportsInput; + OSSSpamDatetimeFilterInput: GQLOssSpamDatetimeFilterInput; + OSSSpamRingsFilter: GQLOssSpamRingsFilter; + OSSSpamRingsInput: GQLOssSpamRingsInput; + Oauth1CredentialInput: GQLOauth1CredentialInput; + Official: ResolverTypeWrapper & { announcements?: Maybe> }>; + OfficialAnnouncementNotice: ResolverTypeWrapper; + PageInfo: ResolverTypeWrapper; + PayToInput: GQLPayToInput; + PayToResult: ResolverTypeWrapper & { transaction: GQLResolversTypes['Transaction'] }>; + PayoutInput: GQLPayoutInput; + Person: ResolverTypeWrapper; + PersonhoodHandoff: ResolverTypeWrapper; + PinCommentInput: GQLPinCommentInput; + PinHistory: ResolverTypeWrapper & { feed: GQLResolversTypes['Node'] }>; + PinnableWork: ResolverTypeWrapper['PinnableWork']>; + Price: ResolverTypeWrapper; + PriceState: GQLPriceState; + PublishArticleInput: GQLPublishArticleInput; + PublishState: GQLPublishState; + PutAnnouncementInput: GQLPutAnnouncementInput; + PutArticleFederationSettingInput: GQLPutArticleFederationSettingInput; + PutCircleArticlesInput: GQLPutCircleArticlesInput; + PutCircleArticlesType: GQLPutCircleArticlesType; + PutCircleInput: GQLPutCircleInput; + PutCollectionInput: GQLPutCollectionInput; + PutCommentInput: GQLPutCommentInput; + PutCurationChannelInput: GQLPutCurationChannelInput; + PutDraftInput: GQLPutDraftInput; + PutIcymiTopicInput: GQLPutIcymiTopicInput; + PutMomentInput: GQLPutMomentInput; + PutOAuthClientInput: GQLPutOAuthClientInput; + PutQuoteInput: GQLPutQuoteInput; + PutRemarkInput: GQLPutRemarkInput; + PutRestrictedUsersInput: GQLPutRestrictedUsersInput; + PutSkippedListItemInput: GQLPutSkippedListItemInput; + PutTagChannelInput: GQLPutTagChannelInput; + PutTopicChannelInput: GQLPutTopicChannelInput; + PutUserFeatureFlagsInput: GQLPutUserFeatureFlagsInput; + PutUserFederationSettingInput: GQLPutUserFederationSettingInput; + PutWritingChallengeInput: GQLPutWritingChallengeInput; + Query: ResolverTypeWrapper<{}>; + Quote: ResolverTypeWrapper; + QuoteConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + QuoteCurrency: GQLQuoteCurrency; + QuoteEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Quote'] }>; + QuotesInput: GQLQuotesInput; + ReadArticleInput: GQLReadArticleInput; + ReadHistory: ResolverTypeWrapper & { article: GQLResolversTypes['Article'] }>; + ReadHistoryConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + ReadHistoryEdge: ResolverTypeWrapper & { node: GQLResolversTypes['ReadHistory'] }>; + RecentSearchConnection: ResolverTypeWrapper; + RecentSearchEdge: ResolverTypeWrapper; + RecommendFilterInput: GQLRecommendFilterInput; + RecommendInput: GQLRecommendInput; + RecommendTypes: GQLRecommendTypes; + Recommendation: ResolverTypeWrapper; + RecommendationFollowingFilterInput: GQLRecommendationFollowingFilterInput; + RecommendationFollowingFilterType: GQLRecommendationFollowingFilterType; + RecommendationFollowingInput: GQLRecommendationFollowingInput; + RecommendationNewestInput: GQLRecommendationNewestInput; + RefreshIPNSFeedInput: GQLRefreshIpnsFeedInput; + RelatedDonationArticlesInput: GQLRelatedDonationArticlesInput; + RemarkTypes: GQLRemarkTypes; + RemoveSocialLoginInput: GQLRemoveSocialLoginInput; + RenameTagInput: GQLRenameTagInput; + ReorderChannelsInput: GQLReorderChannelsInput; + ReorderCollectionArticlesInput: GQLReorderCollectionArticlesInput; + ReorderMoveInput: GQLReorderMoveInput; + Report: ResolverTypeWrapper; + ReportConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + ReportEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Report'] }>; + ReportReason: GQLReportReason; + ReportSource: GQLReportSource; + ResetLikerIdInput: GQLResetLikerIdInput; + ResetPasswordInput: GQLResetPasswordInput; + ResetPasswordType: GQLResetPasswordType; + Response: ResolverTypeWrapper['Response']>; + ResponseConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + ResponseEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Response'] }>; + ResponseSort: GQLResponseSort; + ResponsesInput: GQLResponsesInput; + RestoreCommunityWatchCommentInput: GQLRestoreCommunityWatchCommentInput; + ReviewTopicChannelFeedbackInput: GQLReviewTopicChannelFeedbackInput; + Role: GQLRole; + SearchAPIVersion: GQLSearchApiVersion; + SearchExclude: GQLSearchExclude; + SearchFilter: GQLSearchFilter; + SearchInput: GQLSearchInput; + SearchResultConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + SearchResultEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Node'] }>; + SearchTypes: GQLSearchTypes; + SendCampaignAnnouncementInput: GQLSendCampaignAnnouncementInput; + SendVerificationCodeInput: GQLSendVerificationCodeInput; + SetAdStatusInput: GQLSetAdStatusInput; + SetArticleFederationSettingInput: GQLSetArticleFederationSettingInput; + SetArticleTopicChannelsInput: GQLSetArticleTopicChannelsInput; + SetBoostInput: GQLSetBoostInput; + SetCurrencyInput: GQLSetCurrencyInput; + SetEmailInput: GQLSetEmailInput; + SetFeatureInput: GQLSetFeatureInput; + SetPasswordInput: GQLSetPasswordInput; + SetSpamStatusInput: GQLSetSpamStatusInput; + SetUserNameInput: GQLSetUserNameInput; + SetViewerFederationSettingInput: GQLSetViewerFederationSettingInput; + SigningMessagePurpose: GQLSigningMessagePurpose; + SigningMessageResult: ResolverTypeWrapper; + SingleFileUploadInput: GQLSingleFileUploadInput; + SkippedListItem: ResolverTypeWrapper; + SkippedListItemEdge: ResolverTypeWrapper; + SkippedListItemType: GQLSkippedListItemType; + SkippedListItemsConnection: ResolverTypeWrapper; + SkippedListItemsInput: GQLSkippedListItemsInput; + SocialAccount: ResolverTypeWrapper; + SocialAccountType: GQLSocialAccountType; + SocialLoginInput: GQLSocialLoginInput; + SpamRing: ResolverTypeWrapper; + SpamRingCandidateInput: GQLSpamRingCandidateInput; + SpamRingConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + SpamRingEdge: ResolverTypeWrapper & { node: GQLResolversTypes['SpamRing'] }>; + SpamRingEvent: ResolverTypeWrapper; + SpamRingEventAction: GQLSpamRingEventAction; + SpamRingMember: ResolverTypeWrapper; + SpamRingMemberConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + SpamRingMemberEdge: ResolverTypeWrapper & { node: GQLResolversTypes['SpamRingMember'] }>; + SpamRingMemberStatus: GQLSpamRingMemberStatus; + SpamRingSeverity: GQLSpamRingSeverity; + SpamRingSignals: ResolverTypeWrapper; + SpamRingSignalsInput: GQLSpamRingSignalsInput; + SpamRingSkip: ResolverTypeWrapper & { user: GQLResolversTypes['User'] }>; + SpamRingStatus: GQLSpamRingStatus; + SpamRingsSort: GQLSpamRingsSort; + SpamStatus: ResolverTypeWrapper; + String: ResolverTypeWrapper; + StripeAccount: ResolverTypeWrapper; + StripeAccountCountry: GQLStripeAccountCountry; + SubmitReportInput: GQLSubmitReportInput; + SubmitTopicChannelFeedbackInput: GQLSubmitTopicChannelFeedbackInput; + SubscribeCircleInput: GQLSubscribeCircleInput; + SubscribeCircleResult: ResolverTypeWrapper & { circle: GQLResolversTypes['Circle'] }>; + Tag: ResolverTypeWrapper; + TagArticlesInput: GQLTagArticlesInput; + TagArticlesSortBy: GQLTagArticlesSortBy; + TagConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + TagEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Tag'] }>; + TagOSS: ResolverTypeWrapper; + TagWritingConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + TagWritingEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Writing'] }>; + TagsInput: GQLTagsInput; + TagsSort: GQLTagsSort; + ToggleCircleMemberInput: GQLToggleCircleMemberInput; + ToggleItemInput: GQLToggleItemInput; + TogglePinChannelArticlesInput: GQLTogglePinChannelArticlesInput; + ToggleRecommendInput: GQLToggleRecommendInput; + ToggleSeedingUsersInput: GQLToggleSeedingUsersInput; + ToggleUsersBadgeInput: GQLToggleUsersBadgeInput; + ToggleWritingChallengeFeaturedArticlesInput: GQLToggleWritingChallengeFeaturedArticlesInput; + TopDonatorConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + TopDonatorEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Donator'] }>; + TopDonatorFilter: GQLTopDonatorFilter; + TopDonatorInput: GQLTopDonatorInput; + TopicChannel: ResolverTypeWrapper; + TopicChannelClassification: ResolverTypeWrapper; + TopicChannelFeedback: ResolverTypeWrapper; + TopicChannelFeedbackAction: GQLTopicChannelFeedbackAction; + TopicChannelFeedbackConnection: ResolverTypeWrapper & { edges: Array }>; + TopicChannelFeedbackEdge: ResolverTypeWrapper & { node: GQLResolversTypes['TopicChannelFeedback'] }>; + TopicChannelFeedbackState: GQLTopicChannelFeedbackState; + TopicChannelFeedbackType: GQLTopicChannelFeedbackType; + TopicChannelFeedbacksFilterInput: GQLTopicChannelFeedbacksFilterInput; + TopicChannelFeedbacksInput: GQLTopicChannelFeedbacksInput; + Transaction: ResolverTypeWrapper; + TransactionConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + TransactionCurrency: GQLTransactionCurrency; + TransactionEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Transaction'] }>; + TransactionNotice: ResolverTypeWrapper; + TransactionNoticeType: GQLTransactionNoticeType; + TransactionPurpose: GQLTransactionPurpose; + TransactionState: GQLTransactionState; + TransactionTarget: ResolverTypeWrapper['TransactionTarget']>; + TransactionsArgs: GQLTransactionsArgs; + TransactionsFilter: GQLTransactionsFilter; + TransactionsReceivedByArgs: GQLTransactionsReceivedByArgs; + TranslatedAnnouncement: ResolverTypeWrapper; + TranslationArgs: GQLTranslationArgs; + TranslationInput: GQLTranslationInput; + TranslationModel: GQLTranslationModel; + UnbindLikerIdInput: GQLUnbindLikerIdInput; + UnfreezeSpamRingInput: GQLUnfreezeSpamRingInput; + UnfreezeSpamRingResult: ResolverTypeWrapper & { ring: GQLResolversTypes['SpamRing'], skipped: Array, unbanned: Array }>; + UnlikeCollectionInput: GQLUnlikeCollectionInput; + UnlikeMomentInput: GQLUnlikeMomentInput; + UnpinCommentInput: GQLUnpinCommentInput; + UnsubscribeCircleInput: GQLUnsubscribeCircleInput; + UnvoteCommentInput: GQLUnvoteCommentInput; + UpdateArticleSensitiveInput: GQLUpdateArticleSensitiveInput; + UpdateArticleStateInput: GQLUpdateArticleStateInput; + UpdateCampaignApplicationStateInput: GQLUpdateCampaignApplicationStateInput; + UpdateCommentsStateInput: GQLUpdateCommentsStateInput; + UpdateCommunityWatchActionStateInput: GQLUpdateCommunityWatchActionStateInput; + UpdateMomentFeedApplicationStateInput: GQLUpdateMomentFeedApplicationStateInput; + UpdateNotificationSettingInput: GQLUpdateNotificationSettingInput; + UpdateUserExtraInput: GQLUpdateUserExtraInput; + UpdateUserInfoInput: GQLUpdateUserInfoInput; + UpdateUserRoleInput: GQLUpdateUserRoleInput; + UpdateUserStateInput: GQLUpdateUserStateInput; + Upload: ResolverTypeWrapper; + UpsertSpamRingCandidatesInput: GQLUpsertSpamRingCandidatesInput; + UpsertSpamRingCandidatesResult: ResolverTypeWrapper & { rings: Array }>; + User: ResolverTypeWrapper; + UserActivity: ResolverTypeWrapper; + UserAddArticleTagActivity: ResolverTypeWrapper & { actor: GQLResolversTypes['User'], node: GQLResolversTypes['Article'], target: GQLResolversTypes['Tag'] }>; + UserAnalytics: ResolverTypeWrapper; + UserArticlesFilter: GQLUserArticlesFilter; + UserArticlesInput: GQLUserArticlesInput; + UserArticlesSort: GQLUserArticlesSort; + UserBroadcastCircleActivity: ResolverTypeWrapper & { actor: GQLResolversTypes['User'], node: GQLResolversTypes['Comment'], target: GQLResolversTypes['Circle'] }>; + UserConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + UserCreateCircleActivity: ResolverTypeWrapper & { actor: GQLResolversTypes['User'], node: GQLResolversTypes['Circle'] }>; + UserEdge: ResolverTypeWrapper & { node: GQLResolversTypes['User'] }>; + UserFeatureFlag: ResolverTypeWrapper; + UserFeatureFlagType: GQLUserFeatureFlagType; + UserFeatures: ResolverTypeWrapper; + UserFederationSetting: ResolverTypeWrapper; + UserGroup: GQLUserGroup; + UserInfo: ResolverTypeWrapper; + UserInfoFields: GQLUserInfoFields; + UserInput: GQLUserInput; + UserLanguage: GQLUserLanguage; + UserNotice: ResolverTypeWrapper; + UserNoticeType: GQLUserNoticeType; + UserOSS: ResolverTypeWrapper; + UserPostMomentActivity: ResolverTypeWrapper & { actor: GQLResolversTypes['User'], more: Array, node: GQLResolversTypes['Moment'] }>; + UserPublishArticleActivity: ResolverTypeWrapper & { actor: GQLResolversTypes['User'], node: GQLResolversTypes['Article'] }>; + UserRecommendationActivity: ResolverTypeWrapper & { nodes?: Maybe> }>; + UserRecommendationActivitySource: GQLUserRecommendationActivitySource; + UserRestriction: ResolverTypeWrapper; + UserRestrictionType: GQLUserRestrictionType; + UserRole: GQLUserRole; + UserSettings: ResolverTypeWrapper; + UserState: GQLUserState; + UserStatus: ResolverTypeWrapper; + VerificationCodeType: GQLVerificationCodeType; + VerifyEmailInput: GQLVerifyEmailInput; + Vote: GQLVote; + VoteCommentInput: GQLVoteCommentInput; + Wallet: ResolverTypeWrapper; + WalletLoginInput: GQLWalletLoginInput; + WithdrawLockedTokensResult: ResolverTypeWrapper & { transaction: GQLResolversTypes['Transaction'] }>; + Writing: ResolverTypeWrapper; + WritingChallenge: ResolverTypeWrapper; + WritingConnection: ResolverTypeWrapper & { edges?: Maybe> }>; + WritingEdge: ResolverTypeWrapper & { node: GQLResolversTypes['Writing'] }>; + WritingInput: GQLWritingInput; +}>; /** Mapping between all available schema types and the resolvers parents */ export type GQLResolversParentTypes = ResolversObject<{ - AdStatus: GQLAdStatus - AddCollectionsArticlesInput: GQLAddCollectionsArticlesInput - AddCreditInput: GQLAddCreditInput - AddCreditResult: Omit & { - transaction: GQLResolversParentTypes['Transaction'] - } - AddCurationChannelArticlesInput: GQLAddCurationChannelArticlesInput - Announcement: AnnouncementModel - AnnouncementChannel: Omit & { - channel: GQLResolversParentTypes['Channel'] - } - AnnouncementChannelInput: GQLAnnouncementChannelInput - AnnouncementsInput: GQLAnnouncementsInput - ApplyCampaignInput: GQLApplyCampaignInput - AppreciateArticleInput: GQLAppreciateArticleInput - Appreciation: AppreciationModel - AppreciationConnection: Omit & { - edges?: Maybe> - } - AppreciationEdge: Omit & { - node: GQLResolversParentTypes['Appreciation'] - } - ArchiveUserFailure: GQLArchiveUserFailure - ArchiveUsersInput: GQLArchiveUsersInput - ArchiveUsersResult: Omit & { - archived: Array - } - Article: ArticleModel - ArticleAccess: ArticleModel - ArticleArticleNotice: NoticeItemModel - ArticleCampaign: Omit & { - campaign: GQLResolversParentTypes['Campaign'] - stage?: Maybe - } - ArticleCampaignInput: GQLArticleCampaignInput - ArticleClassification: ArticleModel - ArticleConnection: Omit & { - edges?: Maybe> - } - ArticleContents: ArticleVersionModel - ArticleDonation: Omit & { - sender?: Maybe - } - ArticleDonationConnection: Omit & { - edges?: Maybe> - } - ArticleDonationEdge: Omit & { - node: GQLResolversParentTypes['ArticleDonation'] - } - ArticleEdge: Omit & { - node: GQLResolversParentTypes['Article'] - } - ArticleFederationEligibility: GQLArticleFederationEligibility - ArticleFederationSetting: GQLArticleFederationSetting - ArticleInput: GQLArticleInput - ArticleNotice: NoticeItemModel - ArticleOSS: ArticleModel - ArticleRecommendationActivity: Omit< - GQLArticleRecommendationActivity, - 'nodes' - > & { nodes?: Maybe> } - ArticleTopicChannel: Omit & { - channel: GQLResolversParentTypes['TopicChannel'] - } - ArticleTranslation: GQLArticleTranslation - ArticleTranslationInput: GQLArticleTranslationInput - ArticleVersion: ArticleVersionModel - ArticleVersionEdge: Omit & { - node: GQLResolversParentTypes['ArticleVersion'] - } - ArticleVersionsConnection: Omit & { - edges: Array> - } - ArticleVersionsInput: GQLArticleVersionsInput - Asset: AssetModel - AuthResult: Omit & { - user?: Maybe - } - Badge: GQLBadge - BadgedUsersInput: GQLBadgedUsersInput - Balance: GQLBalance - BanCampaignArticlesInput: GQLBanCampaignArticlesInput - BlockchainTransaction: GQLBlockchainTransaction - BlockedSearchKeyword: GQLBlockedSearchKeyword - Boolean: Scalars['Boolean']['output'] - Campaign: CampaignModel - CampaignApplication: GQLCampaignApplication - CampaignArticleConnection: Omit & { - edges: Array - } - CampaignArticleEdge: Omit & { - node: GQLResolversParentTypes['Article'] - } - CampaignArticleNotice: NoticeItemModel - CampaignArticlesFilter: GQLCampaignArticlesFilter - CampaignArticlesInput: GQLCampaignArticlesInput - CampaignConnection: Omit & { - edges?: Maybe> - } - CampaignEdge: Omit & { - node: GQLResolversParentTypes['Campaign'] - } - CampaignInput: GQLCampaignInput - CampaignOSS: CampaignModel - CampaignParticipantConnection: Omit< - GQLCampaignParticipantConnection, - 'edges' - > & { - edges?: Maybe> - } - CampaignParticipantEdge: Omit< - GQLCampaignParticipantEdge, - 'application' | 'node' - > & { - application?: Maybe - node: GQLResolversParentTypes['User'] - } - CampaignParticipantsInput: GQLCampaignParticipantsInput - CampaignStage: CampaignStageModel - CampaignStageInput: GQLCampaignStageInput - CampaignsFilter: GQLCampaignsFilter - CampaignsInput: GQLCampaignsInput - Channel: GQLResolversInterfaceTypes['Channel'] - ChannelArticleConnection: Omit & { - edges?: Maybe> - } - ChannelArticleEdge: Omit & { - node: GQLResolversParentTypes['Article'] - } - ChannelArticlesFilter: GQLChannelArticlesFilter - ChannelArticlesInput: GQLChannelArticlesInput - ChannelInput: GQLChannelInput - ChannelsInput: GQLChannelsInput - Circle: CircleModel - CircleAnalytics: CircleModel - CircleConnection: Omit & { - edges?: Maybe> - } - CircleContentAnalytics: CircleModel - CircleContentAnalyticsDatum: Omit & { - node: GQLResolversParentTypes['Article'] - } - CircleEdge: Omit & { - node: GQLResolversParentTypes['Circle'] - } - CircleFollowerAnalytics: CircleModel - CircleIncomeAnalytics: CircleModel - CircleInput: GQLCircleInput - CircleNotice: NoticeItemModel - CircleRecommendationActivity: Omit< - GQLCircleRecommendationActivity, - 'nodes' - > & { nodes?: Maybe> } - CircleSubscriberAnalytics: CircleModel - ClaimLogbooksInput: GQLClaimLogbooksInput - ClaimLogbooksResult: GQLClaimLogbooksResult - ClaimPersonhoodBadgeInput: GQLClaimPersonhoodBadgeInput - ClassifyArticlesChannelsInput: GQLClassifyArticlesChannelsInput - ClearCommunityWatchOriginalContentInput: GQLClearCommunityWatchOriginalContentInput - ClearReadHistoryInput: GQLClearReadHistoryInput - Collection: CollectionModel - CollectionArticlesInput: GQLCollectionArticlesInput - CollectionConnection: Omit & { - edges?: Maybe> - } - CollectionEdge: Omit & { - node: GQLResolversParentTypes['Collection'] - } - CollectionNotice: NoticeItemModel - Comment: CommentModel - CommentCommentNotice: NoticeItemModel - CommentCommentsInput: GQLCommentCommentsInput - CommentConnection: Omit & { - edges?: Maybe> - } - CommentEdge: Omit & { - node: GQLResolversParentTypes['Comment'] - } - CommentInput: GQLCommentInput - CommentNotice: NoticeItemModel - CommentsFilter: GQLCommentsFilter - CommentsInput: GQLCommentsInput - CommunityWatchAction: CommunityWatchActionModel - CommunityWatchActionConnection: Omit< - GQLCommunityWatchActionConnection, - 'edges' - > & { - edges?: Maybe> - } - CommunityWatchActionEdge: Omit & { - node: GQLResolversParentTypes['CommunityWatchAction'] - } - CommunityWatchActionInput: GQLCommunityWatchActionInput - CommunityWatchActionsInput: GQLCommunityWatchActionsInput - CommunityWatchRemoveCommentInput: GQLCommunityWatchRemoveCommentInput - ConfirmVerificationCodeInput: GQLConfirmVerificationCodeInput - ConnectStripeAccountInput: GQLConnectStripeAccountInput - ConnectStripeAccountResult: GQLConnectStripeAccountResult - Connection: GQLResolversInterfaceTypes['Connection'] - ConnectionArgs: GQLConnectionArgs - CreatePersonhoodHandoffInput: GQLCreatePersonhoodHandoffInput - CryptoWallet: ETHWalletModel - CurationChannel: CurationChannelModel - DateTime: Scalars['DateTime']['output'] - DatetimeRange: GQLDatetimeRange - DatetimeRangeInput: GQLDatetimeRangeInput - DeleteAnnouncementsInput: GQLDeleteAnnouncementsInput - DeleteCollectionArticlesInput: GQLDeleteCollectionArticlesInput - DeleteCollectionsInput: GQLDeleteCollectionsInput - DeleteCommentInput: GQLDeleteCommentInput - DeleteCurationChannelArticlesInput: GQLDeleteCurationChannelArticlesInput - DeleteDraftInput: GQLDeleteDraftInput - DeleteMomentInput: GQLDeleteMomentInput - DeleteTagsInput: GQLDeleteTagsInput - DirectImageUploadInput: GQLDirectImageUploadInput - Donator: GQLResolversUnionTypes['Donator'] - Draft: DraftModel - DraftAccess: DraftModel - DraftConnection: Omit & { - edges?: Maybe> - } - DraftEdge: Omit & { - node: GQLResolversParentTypes['Draft'] - } - EditArticleInput: GQLEditArticleInput - EmailLoginInput: GQLEmailLoginInput - ExchangeRate: GQLExchangeRate - ExchangeRatesInput: GQLExchangeRatesInput - Feature: GQLFeature - FeaturedCommentsInput: GQLFeaturedCommentsInput - FeaturedTagsInput: GQLFeaturedTagsInput - FilterInput: GQLFilterInput - Float: Scalars['Float']['output'] - Following: UserModel - FollowingActivity: GQLResolversUnionTypes['FollowingActivity'] - FollowingActivityConnection: Omit & { - edges?: Maybe> - } - FollowingActivityEdge: Omit & { - node: GQLResolversParentTypes['FollowingActivity'] - } - FrequentSearchInput: GQLFrequentSearchInput - GenerateSigningMessageInput: GQLGenerateSigningMessageInput - ID: Scalars['ID']['output'] - IcymiTopic: MattersChoiceTopicModel - IcymiTopicConnection: Omit & { - edges: Array - } - IcymiTopicEdge: Omit & { - node: GQLResolversParentTypes['IcymiTopic'] - } - IdentityInput: GQLIdentityInput - Int: Scalars['Int']['output'] - Invitation: CircleInvitationModel - InvitationConnection: Omit & { - edges?: Maybe> - } - InvitationEdge: Omit & { - node: GQLResolversParentTypes['Invitation'] - } - InviteCircleInput: GQLInviteCircleInput - InviteCircleInvitee: GQLInviteCircleInvitee - Invitee: GQLResolversUnionTypes['Invitee'] - Invites: CircleModel - KeywordInput: GQLKeywordInput - KeywordsInput: GQLKeywordsInput - LikeCollectionInput: GQLLikeCollectionInput - LikeMomentInput: GQLLikeMomentInput - Liker: UserModel - LogRecordInput: GQLLogRecordInput - Member: CircleMemberModel - MemberConnection: Omit & { - edges?: Maybe> - } - MemberEdge: Omit & { - node: GQLResolversParentTypes['Member'] - } - MergeTagsInput: GQLMergeTagsInput - MigrationInput: GQLMigrationInput - Moment: MomentModel - MomentConnection: Omit & { - edges?: Maybe> - } - MomentEdge: Omit & { - node: GQLResolversParentTypes['Moment'] - } - MomentFeedApplication: MomentFeedUserModel - MomentFeedUsersInput: GQLMomentFeedUsersInput - MomentInput: GQLMomentInput - MomentNotice: NoticeItemModel - MonthlyDatum: GQLMonthlyDatum - Mutation: {} - NFTAsset: GQLNftAsset - Node: GQLResolversInterfaceTypes['Node'] - NodeInput: GQLNodeInput - NodesInput: GQLNodesInput - Notice: NoticeItemModel - NoticeConnection: Omit & { - edges?: Maybe> - } - NoticeEdge: Omit & { - node: GQLResolversParentTypes['Notice'] - } - NotificationSetting: GQLNotificationSetting - OAuthClient: OAuthClientDBModel - OAuthClientConnection: Omit & { - edges?: Maybe> - } - OAuthClientEdge: Omit & { - node: GQLResolversParentTypes['OAuthClient'] - } - OAuthClientInput: GQLOAuthClientInput - OSS: Omit< - GQLOss, - | 'articles' - | 'badgedUsers' - | 'comments' - | 'icymiTopics' - | 'momentFeedUsers' - | 'moments' - | 'oauthClients' - | 'reports' - | 'restrictedUsers' - | 'seedingUsers' - | 'tags' - | 'topicChannelFeedbacks' - | 'users' - > & { - articles: GQLResolversParentTypes['ArticleConnection'] - badgedUsers: GQLResolversParentTypes['UserConnection'] - comments: GQLResolversParentTypes['CommentConnection'] - icymiTopics: GQLResolversParentTypes['IcymiTopicConnection'] - momentFeedUsers: GQLResolversParentTypes['UserConnection'] - moments: GQLResolversParentTypes['MomentConnection'] - oauthClients: GQLResolversParentTypes['OAuthClientConnection'] - reports: GQLResolversParentTypes['ReportConnection'] - restrictedUsers: GQLResolversParentTypes['UserConnection'] - seedingUsers: GQLResolversParentTypes['UserConnection'] - tags: GQLResolversParentTypes['TagConnection'] - topicChannelFeedbacks: GQLResolversParentTypes['TopicChannelFeedbackConnection'] - users: GQLResolversParentTypes['UserConnection'] - } - OSSArticlesFilterInput: GQLOssArticlesFilterInput - OSSArticlesInput: GQLOssArticlesInput - OSSReportsFilter: GQLOssReportsFilter - OSSReportsInput: GQLOssReportsInput - Oauth1CredentialInput: GQLOauth1CredentialInput - Official: Omit & { - announcements?: Maybe> - } - OfficialAnnouncementNotice: NoticeItemModel - PageInfo: GQLPageInfo - PayToInput: GQLPayToInput - PayToResult: Omit & { - transaction: GQLResolversParentTypes['Transaction'] - } - PayoutInput: GQLPayoutInput - Person: GQLPerson - PersonhoodHandoff: GQLPersonhoodHandoff - PinCommentInput: GQLPinCommentInput - PinHistory: Omit & { - feed: GQLResolversParentTypes['Node'] - } - PinnableWork: GQLResolversInterfaceTypes['PinnableWork'] - Price: CirclePriceModel - PublishArticleInput: GQLPublishArticleInput - PutAnnouncementInput: GQLPutAnnouncementInput - PutArticleFederationSettingInput: GQLPutArticleFederationSettingInput - PutCircleArticlesInput: GQLPutCircleArticlesInput - PutCircleInput: GQLPutCircleInput - PutCollectionInput: GQLPutCollectionInput - PutCommentInput: GQLPutCommentInput - PutCurationChannelInput: GQLPutCurationChannelInput - PutDraftInput: GQLPutDraftInput - PutIcymiTopicInput: GQLPutIcymiTopicInput - PutMomentInput: GQLPutMomentInput - PutOAuthClientInput: GQLPutOAuthClientInput - PutRemarkInput: GQLPutRemarkInput - PutRestrictedUsersInput: GQLPutRestrictedUsersInput - PutSkippedListItemInput: GQLPutSkippedListItemInput - PutTagChannelInput: GQLPutTagChannelInput - PutTopicChannelInput: GQLPutTopicChannelInput - PutUserFeatureFlagsInput: GQLPutUserFeatureFlagsInput - PutUserFederationSettingInput: GQLPutUserFederationSettingInput - PutWritingChallengeInput: GQLPutWritingChallengeInput - Query: {} - ReadArticleInput: GQLReadArticleInput - ReadHistory: Omit & { - article: GQLResolversParentTypes['Article'] - } - ReadHistoryConnection: Omit & { - edges?: Maybe> - } - ReadHistoryEdge: Omit & { - node: GQLResolversParentTypes['ReadHistory'] - } - RecentSearchConnection: GQLRecentSearchConnection - RecentSearchEdge: GQLRecentSearchEdge - RecommendFilterInput: GQLRecommendFilterInput - RecommendInput: GQLRecommendInput - Recommendation: UserModel - RecommendationFollowingFilterInput: GQLRecommendationFollowingFilterInput - RecommendationFollowingInput: GQLRecommendationFollowingInput - RecommendationNewestInput: GQLRecommendationNewestInput - RefreshIPNSFeedInput: GQLRefreshIpnsFeedInput - RelatedDonationArticlesInput: GQLRelatedDonationArticlesInput - RemoveSocialLoginInput: GQLRemoveSocialLoginInput - RenameTagInput: GQLRenameTagInput - ReorderChannelsInput: GQLReorderChannelsInput - ReorderCollectionArticlesInput: GQLReorderCollectionArticlesInput - ReorderMoveInput: GQLReorderMoveInput - Report: ReportModel - ReportConnection: Omit & { - edges?: Maybe> - } - ReportEdge: Omit & { - node: GQLResolversParentTypes['Report'] - } - ResetLikerIdInput: GQLResetLikerIdInput - ResetPasswordInput: GQLResetPasswordInput - Response: GQLResolversUnionTypes['Response'] - ResponseConnection: Omit & { - edges?: Maybe> - } - ResponseEdge: Omit & { - node: GQLResolversParentTypes['Response'] - } - ResponsesInput: GQLResponsesInput - RestoreCommunityWatchCommentInput: GQLRestoreCommunityWatchCommentInput - ReviewTopicChannelFeedbackInput: GQLReviewTopicChannelFeedbackInput - SearchFilter: GQLSearchFilter - SearchInput: GQLSearchInput - SearchResultConnection: Omit & { - edges?: Maybe> - } - SearchResultEdge: Omit & { - node: GQLResolversParentTypes['Node'] - } - SendCampaignAnnouncementInput: GQLSendCampaignAnnouncementInput - SendVerificationCodeInput: GQLSendVerificationCodeInput - SetAdStatusInput: GQLSetAdStatusInput - SetArticleFederationSettingInput: GQLSetArticleFederationSettingInput - SetArticleTopicChannelsInput: GQLSetArticleTopicChannelsInput - SetBoostInput: GQLSetBoostInput - SetCurrencyInput: GQLSetCurrencyInput - SetEmailInput: GQLSetEmailInput - SetFeatureInput: GQLSetFeatureInput - SetPasswordInput: GQLSetPasswordInput - SetSpamStatusInput: GQLSetSpamStatusInput - SetUserNameInput: GQLSetUserNameInput - SetViewerFederationSettingInput: GQLSetViewerFederationSettingInput - SigningMessageResult: GQLSigningMessageResult - SingleFileUploadInput: GQLSingleFileUploadInput - SkippedListItem: GQLSkippedListItem - SkippedListItemEdge: GQLSkippedListItemEdge - SkippedListItemsConnection: GQLSkippedListItemsConnection - SkippedListItemsInput: GQLSkippedListItemsInput - SocialAccount: GQLSocialAccount - SocialLoginInput: GQLSocialLoginInput - SpamStatus: GQLSpamStatus - String: Scalars['String']['output'] - StripeAccount: PayoutAccountModel - SubmitReportInput: GQLSubmitReportInput - SubmitTopicChannelFeedbackInput: GQLSubmitTopicChannelFeedbackInput - SubscribeCircleInput: GQLSubscribeCircleInput - SubscribeCircleResult: Omit & { - circle: GQLResolversParentTypes['Circle'] - } - Tag: TagModel - TagArticlesInput: GQLTagArticlesInput - TagConnection: Omit & { - edges?: Maybe> - } - TagEdge: Omit & { node: GQLResolversParentTypes['Tag'] } - TagOSS: TagModel - TagWritingConnection: Omit & { - edges?: Maybe> - } - TagWritingEdge: Omit & { - node: GQLResolversParentTypes['Writing'] - } - TagsInput: GQLTagsInput - ToggleCircleMemberInput: GQLToggleCircleMemberInput - ToggleItemInput: GQLToggleItemInput - TogglePinChannelArticlesInput: GQLTogglePinChannelArticlesInput - ToggleRecommendInput: GQLToggleRecommendInput - ToggleSeedingUsersInput: GQLToggleSeedingUsersInput - ToggleUsersBadgeInput: GQLToggleUsersBadgeInput - ToggleWritingChallengeFeaturedArticlesInput: GQLToggleWritingChallengeFeaturedArticlesInput - TopDonatorConnection: Omit & { - edges?: Maybe> - } - TopDonatorEdge: Omit & { - node: GQLResolversParentTypes['Donator'] - } - TopDonatorFilter: GQLTopDonatorFilter - TopDonatorInput: GQLTopDonatorInput - TopicChannel: TopicChannelModel - TopicChannelClassification: ArticleModel - TopicChannelFeedback: TopicChannelFeedbackModel - TopicChannelFeedbackConnection: Omit< - GQLTopicChannelFeedbackConnection, - 'edges' - > & { edges: Array } - TopicChannelFeedbackEdge: Omit & { - node: GQLResolversParentTypes['TopicChannelFeedback'] - } - TopicChannelFeedbacksFilterInput: GQLTopicChannelFeedbacksFilterInput - TopicChannelFeedbacksInput: GQLTopicChannelFeedbacksInput - Transaction: TransactionModel - TransactionConnection: Omit & { - edges?: Maybe> - } - TransactionEdge: Omit & { - node: GQLResolversParentTypes['Transaction'] - } - TransactionNotice: NoticeItemModel - TransactionTarget: GQLResolversUnionTypes['TransactionTarget'] - TransactionsArgs: GQLTransactionsArgs - TransactionsFilter: GQLTransactionsFilter - TransactionsReceivedByArgs: GQLTransactionsReceivedByArgs - TranslatedAnnouncement: GQLTranslatedAnnouncement - TranslationArgs: GQLTranslationArgs - TranslationInput: GQLTranslationInput - UnbindLikerIdInput: GQLUnbindLikerIdInput - UnlikeCollectionInput: GQLUnlikeCollectionInput - UnlikeMomentInput: GQLUnlikeMomentInput - UnpinCommentInput: GQLUnpinCommentInput - UnsubscribeCircleInput: GQLUnsubscribeCircleInput - UnvoteCommentInput: GQLUnvoteCommentInput - UpdateArticleSensitiveInput: GQLUpdateArticleSensitiveInput - UpdateArticleStateInput: GQLUpdateArticleStateInput - UpdateCampaignApplicationStateInput: GQLUpdateCampaignApplicationStateInput - UpdateCommentsStateInput: GQLUpdateCommentsStateInput - UpdateCommunityWatchActionStateInput: GQLUpdateCommunityWatchActionStateInput - UpdateMomentFeedApplicationStateInput: GQLUpdateMomentFeedApplicationStateInput - UpdateNotificationSettingInput: GQLUpdateNotificationSettingInput - UpdateUserExtraInput: GQLUpdateUserExtraInput - UpdateUserInfoInput: GQLUpdateUserInfoInput - UpdateUserRoleInput: GQLUpdateUserRoleInput - UpdateUserStateInput: GQLUpdateUserStateInput - Upload: Scalars['Upload']['output'] - User: UserModel - UserActivity: UserModel - UserAddArticleTagActivity: Omit< - GQLUserAddArticleTagActivity, - 'actor' | 'node' | 'target' - > & { - actor: GQLResolversParentTypes['User'] - node: GQLResolversParentTypes['Article'] - target: GQLResolversParentTypes['Tag'] - } - UserAnalytics: UserModel - UserArticlesFilter: GQLUserArticlesFilter - UserArticlesInput: GQLUserArticlesInput - UserBroadcastCircleActivity: Omit< - GQLUserBroadcastCircleActivity, - 'actor' | 'node' | 'target' - > & { - actor: GQLResolversParentTypes['User'] - node: GQLResolversParentTypes['Comment'] - target: GQLResolversParentTypes['Circle'] - } - UserConnection: Omit & { - edges?: Maybe> - } - UserCreateCircleActivity: Omit< - GQLUserCreateCircleActivity, - 'actor' | 'node' - > & { - actor: GQLResolversParentTypes['User'] - node: GQLResolversParentTypes['Circle'] - } - UserEdge: Omit & { - node: GQLResolversParentTypes['User'] - } - UserFeatureFlag: GQLUserFeatureFlag - UserFeatures: GQLUserFeatures - UserFederationSetting: GQLUserFederationSetting - UserInfo: UserModel - UserInput: GQLUserInput - UserNotice: NoticeItemModel - UserOSS: UserModel - UserPostMomentActivity: Omit< - GQLUserPostMomentActivity, - 'actor' | 'more' | 'node' - > & { - actor: GQLResolversParentTypes['User'] - more: Array - node: GQLResolversParentTypes['Moment'] - } - UserPublishArticleActivity: Omit< - GQLUserPublishArticleActivity, - 'actor' | 'node' - > & { - actor: GQLResolversParentTypes['User'] - node: GQLResolversParentTypes['Article'] - } - UserRecommendationActivity: Omit & { - nodes?: Maybe> - } - UserRestriction: GQLUserRestriction - UserSettings: UserModel - UserStatus: UserModel - VerifyEmailInput: GQLVerifyEmailInput - VoteCommentInput: GQLVoteCommentInput - Wallet: UserModel - WalletLoginInput: GQLWalletLoginInput - WithdrawLockedTokensResult: Omit< - GQLWithdrawLockedTokensResult, - 'transaction' - > & { transaction: GQLResolversParentTypes['Transaction'] } - Writing: WritingModel - WritingChallenge: CampaignModel - WritingConnection: Omit & { - edges?: Maybe> - } - WritingEdge: Omit & { - node: GQLResolversParentTypes['Writing'] - } - WritingInput: GQLWritingInput -}> + AdStatus: GQLAdStatus; + AddCollectionsArticlesInput: GQLAddCollectionsArticlesInput; + AddCreditInput: GQLAddCreditInput; + AddCreditResult: Omit & { transaction: GQLResolversParentTypes['Transaction'] }; + AddCurationChannelArticlesInput: GQLAddCurationChannelArticlesInput; + Announcement: AnnouncementModel; + AnnouncementChannel: Omit & { channel: GQLResolversParentTypes['Channel'] }; + AnnouncementChannelInput: GQLAnnouncementChannelInput; + AnnouncementsInput: GQLAnnouncementsInput; + ApplyCampaignInput: GQLApplyCampaignInput; + AppreciateArticleInput: GQLAppreciateArticleInput; + Appreciation: AppreciationModel; + AppreciationConnection: Omit & { edges?: Maybe> }; + AppreciationEdge: Omit & { node: GQLResolversParentTypes['Appreciation'] }; + ArchiveUserFailure: GQLArchiveUserFailure; + ArchiveUsersInput: GQLArchiveUsersInput; + ArchiveUsersResult: Omit & { archived: Array }; + Article: ArticleModel; + ArticleAccess: ArticleModel; + ArticleArticleNotice: NoticeItemModel; + ArticleCampaign: Omit & { campaign: GQLResolversParentTypes['Campaign'], stage?: Maybe }; + ArticleCampaignInput: GQLArticleCampaignInput; + ArticleClassification: ArticleModel; + ArticleConnection: Omit & { edges?: Maybe> }; + ArticleContents: ArticleVersionModel; + ArticleDonation: Omit & { sender?: Maybe }; + ArticleDonationConnection: Omit & { edges?: Maybe> }; + ArticleDonationEdge: Omit & { node: GQLResolversParentTypes['ArticleDonation'] }; + ArticleEdge: Omit & { node: GQLResolversParentTypes['Article'] }; + ArticleFederationEligibility: GQLArticleFederationEligibility; + ArticleFederationSetting: GQLArticleFederationSetting; + ArticleInput: GQLArticleInput; + ArticleNotice: NoticeItemModel; + ArticleOSS: ArticleModel; + ArticleRecommendationActivity: Omit & { nodes?: Maybe> }; + ArticleTopicChannel: Omit & { channel: GQLResolversParentTypes['TopicChannel'] }; + ArticleTranslation: GQLArticleTranslation; + ArticleTranslationInput: GQLArticleTranslationInput; + ArticleVersion: ArticleVersionModel; + ArticleVersionEdge: Omit & { node: GQLResolversParentTypes['ArticleVersion'] }; + ArticleVersionsConnection: Omit & { edges: Array> }; + ArticleVersionsInput: GQLArticleVersionsInput; + Asset: AssetModel; + AuthResult: Omit & { user?: Maybe }; + Badge: GQLBadge; + BadgedUsersInput: GQLBadgedUsersInput; + Balance: GQLBalance; + BanCampaignArticlesInput: GQLBanCampaignArticlesInput; + BlockchainTransaction: GQLBlockchainTransaction; + BlockedSearchKeyword: GQLBlockedSearchKeyword; + Boolean: Scalars['Boolean']['output']; + Campaign: CampaignModel; + CampaignApplication: GQLCampaignApplication; + CampaignArticleConnection: Omit & { edges: Array }; + CampaignArticleEdge: Omit & { node: GQLResolversParentTypes['Article'] }; + CampaignArticleNotice: NoticeItemModel; + CampaignArticlesFilter: GQLCampaignArticlesFilter; + CampaignArticlesInput: GQLCampaignArticlesInput; + CampaignConnection: Omit & { edges?: Maybe> }; + CampaignEdge: Omit & { node: GQLResolversParentTypes['Campaign'] }; + CampaignInput: GQLCampaignInput; + CampaignOSS: CampaignModel; + CampaignParticipantConnection: Omit & { edges?: Maybe> }; + CampaignParticipantEdge: Omit & { application?: Maybe, node: GQLResolversParentTypes['User'] }; + CampaignParticipantsInput: GQLCampaignParticipantsInput; + CampaignStage: CampaignStageModel; + CampaignStageInput: GQLCampaignStageInput; + CampaignsFilter: GQLCampaignsFilter; + CampaignsInput: GQLCampaignsInput; + Channel: GQLResolversInterfaceTypes['Channel']; + ChannelArticleConnection: Omit & { edges?: Maybe> }; + ChannelArticleEdge: Omit & { node: GQLResolversParentTypes['Article'] }; + ChannelArticlesFilter: GQLChannelArticlesFilter; + ChannelArticlesInput: GQLChannelArticlesInput; + ChannelInput: GQLChannelInput; + ChannelsInput: GQLChannelsInput; + Circle: CircleModel; + CircleAnalytics: CircleModel; + CircleConnection: Omit & { edges?: Maybe> }; + CircleContentAnalytics: CircleModel; + CircleContentAnalyticsDatum: Omit & { node: GQLResolversParentTypes['Article'] }; + CircleEdge: Omit & { node: GQLResolversParentTypes['Circle'] }; + CircleFollowerAnalytics: CircleModel; + CircleIncomeAnalytics: CircleModel; + CircleInput: GQLCircleInput; + CircleNotice: NoticeItemModel; + CircleRecommendationActivity: Omit & { nodes?: Maybe> }; + CircleSubscriberAnalytics: CircleModel; + ClaimLogbooksInput: GQLClaimLogbooksInput; + ClaimLogbooksResult: GQLClaimLogbooksResult; + ClaimPersonhoodBadgeInput: GQLClaimPersonhoodBadgeInput; + ClassifyArticlesChannelsInput: GQLClassifyArticlesChannelsInput; + ClearCommunityWatchOriginalContentInput: GQLClearCommunityWatchOriginalContentInput; + ClearReadHistoryInput: GQLClearReadHistoryInput; + Collection: CollectionModel; + CollectionArticlesInput: GQLCollectionArticlesInput; + CollectionConnection: Omit & { edges?: Maybe> }; + CollectionEdge: Omit & { node: GQLResolversParentTypes['Collection'] }; + CollectionNotice: NoticeItemModel; + Comment: CommentModel; + CommentCommentNotice: NoticeItemModel; + CommentCommentsInput: GQLCommentCommentsInput; + CommentConnection: Omit & { edges?: Maybe> }; + CommentEdge: Omit & { node: GQLResolversParentTypes['Comment'] }; + CommentInput: GQLCommentInput; + CommentNotice: NoticeItemModel; + CommentsFilter: GQLCommentsFilter; + CommentsInput: GQLCommentsInput; + CommunityWatchAction: CommunityWatchActionModel; + CommunityWatchActionConnection: Omit & { edges?: Maybe> }; + CommunityWatchActionEdge: Omit & { node: GQLResolversParentTypes['CommunityWatchAction'] }; + CommunityWatchActionInput: GQLCommunityWatchActionInput; + CommunityWatchActionsInput: GQLCommunityWatchActionsInput; + CommunityWatchRemoveCommentInput: GQLCommunityWatchRemoveCommentInput; + ConfirmVerificationCodeInput: GQLConfirmVerificationCodeInput; + ConnectStripeAccountInput: GQLConnectStripeAccountInput; + ConnectStripeAccountResult: GQLConnectStripeAccountResult; + Connection: GQLResolversInterfaceTypes['Connection']; + ConnectionArgs: GQLConnectionArgs; + CreatePersonhoodHandoffInput: GQLCreatePersonhoodHandoffInput; + CryptoWallet: ETHWalletModel; + CurationChannel: CurationChannelModel; + DateTime: Scalars['DateTime']['output']; + DatetimeRange: GQLDatetimeRange; + DatetimeRangeInput: GQLDatetimeRangeInput; + DeleteAnnouncementsInput: GQLDeleteAnnouncementsInput; + DeleteCollectionArticlesInput: GQLDeleteCollectionArticlesInput; + DeleteCollectionsInput: GQLDeleteCollectionsInput; + DeleteCommentInput: GQLDeleteCommentInput; + DeleteCurationChannelArticlesInput: GQLDeleteCurationChannelArticlesInput; + DeleteDraftInput: GQLDeleteDraftInput; + DeleteMomentInput: GQLDeleteMomentInput; + DeleteQuoteInput: GQLDeleteQuoteInput; + DeleteTagsInput: GQLDeleteTagsInput; + DirectImageUploadInput: GQLDirectImageUploadInput; + DismissSpamRingInput: GQLDismissSpamRingInput; + Donator: GQLResolversUnionTypes['Donator']; + Draft: DraftModel; + DraftAccess: DraftModel; + DraftConnection: Omit & { edges?: Maybe> }; + DraftEdge: Omit & { node: GQLResolversParentTypes['Draft'] }; + EditArticleInput: GQLEditArticleInput; + EmailLoginInput: GQLEmailLoginInput; + ExchangeRate: GQLExchangeRate; + ExchangeRatesInput: GQLExchangeRatesInput; + Feature: GQLFeature; + FeaturedCommentsInput: GQLFeaturedCommentsInput; + FeaturedTagsInput: GQLFeaturedTagsInput; + FilterInput: GQLFilterInput; + Float: Scalars['Float']['output']; + Following: UserModel; + FollowingActivity: GQLResolversUnionTypes['FollowingActivity']; + FollowingActivityConnection: Omit & { edges?: Maybe> }; + FollowingActivityEdge: Omit & { node: GQLResolversParentTypes['FollowingActivity'] }; + FreezeSpamRingInput: GQLFreezeSpamRingInput; + FreezeSpamRingResult: Omit & { frozen: Array, ring: GQLResolversParentTypes['SpamRing'], skipped: Array }; + FrequentSearchInput: GQLFrequentSearchInput; + GenerateSigningMessageInput: GQLGenerateSigningMessageInput; + ID: Scalars['ID']['output']; + IcymiTopic: MattersChoiceTopicModel; + IcymiTopicConnection: Omit & { edges: Array }; + IcymiTopicEdge: Omit & { node: GQLResolversParentTypes['IcymiTopic'] }; + IdentityInput: GQLIdentityInput; + Int: Scalars['Int']['output']; + Invitation: CircleInvitationModel; + InvitationConnection: Omit & { edges?: Maybe> }; + InvitationEdge: Omit & { node: GQLResolversParentTypes['Invitation'] }; + InviteCircleInput: GQLInviteCircleInput; + InviteCircleInvitee: GQLInviteCircleInvitee; + Invitee: GQLResolversUnionTypes['Invitee']; + Invites: CircleModel; + KeywordInput: GQLKeywordInput; + KeywordsInput: GQLKeywordsInput; + LikeCollectionInput: GQLLikeCollectionInput; + LikeMomentInput: GQLLikeMomentInput; + Liker: UserModel; + LogRecordInput: GQLLogRecordInput; + Member: CircleMemberModel; + MemberConnection: Omit & { edges?: Maybe> }; + MemberEdge: Omit & { node: GQLResolversParentTypes['Member'] }; + MergeTagsInput: GQLMergeTagsInput; + MigrationInput: GQLMigrationInput; + Moment: MomentModel; + MomentConnection: Omit & { edges?: Maybe> }; + MomentEdge: Omit & { node: GQLResolversParentTypes['Moment'] }; + MomentFeedApplication: MomentFeedUserModel; + MomentFeedUsersInput: GQLMomentFeedUsersInput; + MomentInput: GQLMomentInput; + MomentNotice: NoticeItemModel; + MonthlyDatum: GQLMonthlyDatum; + Mutation: {}; + NFTAsset: GQLNftAsset; + Node: GQLResolversInterfaceTypes['Node']; + NodeInput: GQLNodeInput; + NodesInput: GQLNodesInput; + Notice: NoticeItemModel; + NoticeConnection: Omit & { edges?: Maybe> }; + NoticeEdge: Omit & { node: GQLResolversParentTypes['Notice'] }; + NotificationSetting: GQLNotificationSetting; + OAuthClient: OAuthClientDBModel; + OAuthClientConnection: Omit & { edges?: Maybe> }; + OAuthClientEdge: Omit & { node: GQLResolversParentTypes['OAuthClient'] }; + OAuthClientInput: GQLOAuthClientInput; + OSS: Omit & { articles: GQLResolversParentTypes['ArticleConnection'], badgedUsers: GQLResolversParentTypes['UserConnection'], comments: GQLResolversParentTypes['CommentConnection'], icymiTopics: GQLResolversParentTypes['IcymiTopicConnection'], momentFeedUsers: GQLResolversParentTypes['UserConnection'], moments: GQLResolversParentTypes['MomentConnection'], oauthClients: GQLResolversParentTypes['OAuthClientConnection'], reports: GQLResolversParentTypes['ReportConnection'], restrictedUsers: GQLResolversParentTypes['UserConnection'], seedingUsers: GQLResolversParentTypes['UserConnection'], spamRings: GQLResolversParentTypes['SpamRingConnection'], tags: GQLResolversParentTypes['TagConnection'], topicChannelFeedbacks: GQLResolversParentTypes['TopicChannelFeedbackConnection'], users: GQLResolversParentTypes['UserConnection'] }; + OSSArticlesFilterInput: GQLOssArticlesFilterInput; + OSSArticlesInput: GQLOssArticlesInput; + OSSCommentsInput: GQLOssCommentsInput; + OSSMomentsInput: GQLOssMomentsInput; + OSSReportsFilter: GQLOssReportsFilter; + OSSReportsInput: GQLOssReportsInput; + OSSSpamDatetimeFilterInput: GQLOssSpamDatetimeFilterInput; + OSSSpamRingsFilter: GQLOssSpamRingsFilter; + OSSSpamRingsInput: GQLOssSpamRingsInput; + Oauth1CredentialInput: GQLOauth1CredentialInput; + Official: Omit & { announcements?: Maybe> }; + OfficialAnnouncementNotice: NoticeItemModel; + PageInfo: GQLPageInfo; + PayToInput: GQLPayToInput; + PayToResult: Omit & { transaction: GQLResolversParentTypes['Transaction'] }; + PayoutInput: GQLPayoutInput; + Person: GQLPerson; + PersonhoodHandoff: GQLPersonhoodHandoff; + PinCommentInput: GQLPinCommentInput; + PinHistory: Omit & { feed: GQLResolversParentTypes['Node'] }; + PinnableWork: GQLResolversInterfaceTypes['PinnableWork']; + Price: CirclePriceModel; + PublishArticleInput: GQLPublishArticleInput; + PutAnnouncementInput: GQLPutAnnouncementInput; + PutArticleFederationSettingInput: GQLPutArticleFederationSettingInput; + PutCircleArticlesInput: GQLPutCircleArticlesInput; + PutCircleInput: GQLPutCircleInput; + PutCollectionInput: GQLPutCollectionInput; + PutCommentInput: GQLPutCommentInput; + PutCurationChannelInput: GQLPutCurationChannelInput; + PutDraftInput: GQLPutDraftInput; + PutIcymiTopicInput: GQLPutIcymiTopicInput; + PutMomentInput: GQLPutMomentInput; + PutOAuthClientInput: GQLPutOAuthClientInput; + PutQuoteInput: GQLPutQuoteInput; + PutRemarkInput: GQLPutRemarkInput; + PutRestrictedUsersInput: GQLPutRestrictedUsersInput; + PutSkippedListItemInput: GQLPutSkippedListItemInput; + PutTagChannelInput: GQLPutTagChannelInput; + PutTopicChannelInput: GQLPutTopicChannelInput; + PutUserFeatureFlagsInput: GQLPutUserFeatureFlagsInput; + PutUserFederationSettingInput: GQLPutUserFederationSettingInput; + PutWritingChallengeInput: GQLPutWritingChallengeInput; + Query: {}; + Quote: QuoteModel; + QuoteConnection: Omit & { edges?: Maybe> }; + QuoteEdge: Omit & { node: GQLResolversParentTypes['Quote'] }; + QuotesInput: GQLQuotesInput; + ReadArticleInput: GQLReadArticleInput; + ReadHistory: Omit & { article: GQLResolversParentTypes['Article'] }; + ReadHistoryConnection: Omit & { edges?: Maybe> }; + ReadHistoryEdge: Omit & { node: GQLResolversParentTypes['ReadHistory'] }; + RecentSearchConnection: GQLRecentSearchConnection; + RecentSearchEdge: GQLRecentSearchEdge; + RecommendFilterInput: GQLRecommendFilterInput; + RecommendInput: GQLRecommendInput; + Recommendation: UserModel; + RecommendationFollowingFilterInput: GQLRecommendationFollowingFilterInput; + RecommendationFollowingInput: GQLRecommendationFollowingInput; + RecommendationNewestInput: GQLRecommendationNewestInput; + RefreshIPNSFeedInput: GQLRefreshIpnsFeedInput; + RelatedDonationArticlesInput: GQLRelatedDonationArticlesInput; + RemoveSocialLoginInput: GQLRemoveSocialLoginInput; + RenameTagInput: GQLRenameTagInput; + ReorderChannelsInput: GQLReorderChannelsInput; + ReorderCollectionArticlesInput: GQLReorderCollectionArticlesInput; + ReorderMoveInput: GQLReorderMoveInput; + Report: ReportModel; + ReportConnection: Omit & { edges?: Maybe> }; + ReportEdge: Omit & { node: GQLResolversParentTypes['Report'] }; + ResetLikerIdInput: GQLResetLikerIdInput; + ResetPasswordInput: GQLResetPasswordInput; + Response: GQLResolversUnionTypes['Response']; + ResponseConnection: Omit & { edges?: Maybe> }; + ResponseEdge: Omit & { node: GQLResolversParentTypes['Response'] }; + ResponsesInput: GQLResponsesInput; + RestoreCommunityWatchCommentInput: GQLRestoreCommunityWatchCommentInput; + ReviewTopicChannelFeedbackInput: GQLReviewTopicChannelFeedbackInput; + SearchFilter: GQLSearchFilter; + SearchInput: GQLSearchInput; + SearchResultConnection: Omit & { edges?: Maybe> }; + SearchResultEdge: Omit & { node: GQLResolversParentTypes['Node'] }; + SendCampaignAnnouncementInput: GQLSendCampaignAnnouncementInput; + SendVerificationCodeInput: GQLSendVerificationCodeInput; + SetAdStatusInput: GQLSetAdStatusInput; + SetArticleFederationSettingInput: GQLSetArticleFederationSettingInput; + SetArticleTopicChannelsInput: GQLSetArticleTopicChannelsInput; + SetBoostInput: GQLSetBoostInput; + SetCurrencyInput: GQLSetCurrencyInput; + SetEmailInput: GQLSetEmailInput; + SetFeatureInput: GQLSetFeatureInput; + SetPasswordInput: GQLSetPasswordInput; + SetSpamStatusInput: GQLSetSpamStatusInput; + SetUserNameInput: GQLSetUserNameInput; + SetViewerFederationSettingInput: GQLSetViewerFederationSettingInput; + SigningMessageResult: GQLSigningMessageResult; + SingleFileUploadInput: GQLSingleFileUploadInput; + SkippedListItem: GQLSkippedListItem; + SkippedListItemEdge: GQLSkippedListItemEdge; + SkippedListItemsConnection: GQLSkippedListItemsConnection; + SkippedListItemsInput: GQLSkippedListItemsInput; + SocialAccount: GQLSocialAccount; + SocialLoginInput: GQLSocialLoginInput; + SpamRing: SpamRingModel; + SpamRingCandidateInput: GQLSpamRingCandidateInput; + SpamRingConnection: Omit & { edges?: Maybe> }; + SpamRingEdge: Omit & { node: GQLResolversParentTypes['SpamRing'] }; + SpamRingEvent: SpamRingEventModel; + SpamRingMember: SpamRingMemberModel; + SpamRingMemberConnection: Omit & { edges?: Maybe> }; + SpamRingMemberEdge: Omit & { node: GQLResolversParentTypes['SpamRingMember'] }; + SpamRingSignals: SpamRingSignalsModel; + SpamRingSignalsInput: GQLSpamRingSignalsInput; + SpamRingSkip: Omit & { user: GQLResolversParentTypes['User'] }; + SpamStatus: GQLSpamStatus; + String: Scalars['String']['output']; + StripeAccount: PayoutAccountModel; + SubmitReportInput: GQLSubmitReportInput; + SubmitTopicChannelFeedbackInput: GQLSubmitTopicChannelFeedbackInput; + SubscribeCircleInput: GQLSubscribeCircleInput; + SubscribeCircleResult: Omit & { circle: GQLResolversParentTypes['Circle'] }; + Tag: TagModel; + TagArticlesInput: GQLTagArticlesInput; + TagConnection: Omit & { edges?: Maybe> }; + TagEdge: Omit & { node: GQLResolversParentTypes['Tag'] }; + TagOSS: TagModel; + TagWritingConnection: Omit & { edges?: Maybe> }; + TagWritingEdge: Omit & { node: GQLResolversParentTypes['Writing'] }; + TagsInput: GQLTagsInput; + ToggleCircleMemberInput: GQLToggleCircleMemberInput; + ToggleItemInput: GQLToggleItemInput; + TogglePinChannelArticlesInput: GQLTogglePinChannelArticlesInput; + ToggleRecommendInput: GQLToggleRecommendInput; + ToggleSeedingUsersInput: GQLToggleSeedingUsersInput; + ToggleUsersBadgeInput: GQLToggleUsersBadgeInput; + ToggleWritingChallengeFeaturedArticlesInput: GQLToggleWritingChallengeFeaturedArticlesInput; + TopDonatorConnection: Omit & { edges?: Maybe> }; + TopDonatorEdge: Omit & { node: GQLResolversParentTypes['Donator'] }; + TopDonatorFilter: GQLTopDonatorFilter; + TopDonatorInput: GQLTopDonatorInput; + TopicChannel: TopicChannelModel; + TopicChannelClassification: ArticleModel; + TopicChannelFeedback: TopicChannelFeedbackModel; + TopicChannelFeedbackConnection: Omit & { edges: Array }; + TopicChannelFeedbackEdge: Omit & { node: GQLResolversParentTypes['TopicChannelFeedback'] }; + TopicChannelFeedbacksFilterInput: GQLTopicChannelFeedbacksFilterInput; + TopicChannelFeedbacksInput: GQLTopicChannelFeedbacksInput; + Transaction: TransactionModel; + TransactionConnection: Omit & { edges?: Maybe> }; + TransactionEdge: Omit & { node: GQLResolversParentTypes['Transaction'] }; + TransactionNotice: NoticeItemModel; + TransactionTarget: GQLResolversUnionTypes['TransactionTarget']; + TransactionsArgs: GQLTransactionsArgs; + TransactionsFilter: GQLTransactionsFilter; + TransactionsReceivedByArgs: GQLTransactionsReceivedByArgs; + TranslatedAnnouncement: GQLTranslatedAnnouncement; + TranslationArgs: GQLTranslationArgs; + TranslationInput: GQLTranslationInput; + UnbindLikerIdInput: GQLUnbindLikerIdInput; + UnfreezeSpamRingInput: GQLUnfreezeSpamRingInput; + UnfreezeSpamRingResult: Omit & { ring: GQLResolversParentTypes['SpamRing'], skipped: Array, unbanned: Array }; + UnlikeCollectionInput: GQLUnlikeCollectionInput; + UnlikeMomentInput: GQLUnlikeMomentInput; + UnpinCommentInput: GQLUnpinCommentInput; + UnsubscribeCircleInput: GQLUnsubscribeCircleInput; + UnvoteCommentInput: GQLUnvoteCommentInput; + UpdateArticleSensitiveInput: GQLUpdateArticleSensitiveInput; + UpdateArticleStateInput: GQLUpdateArticleStateInput; + UpdateCampaignApplicationStateInput: GQLUpdateCampaignApplicationStateInput; + UpdateCommentsStateInput: GQLUpdateCommentsStateInput; + UpdateCommunityWatchActionStateInput: GQLUpdateCommunityWatchActionStateInput; + UpdateMomentFeedApplicationStateInput: GQLUpdateMomentFeedApplicationStateInput; + UpdateNotificationSettingInput: GQLUpdateNotificationSettingInput; + UpdateUserExtraInput: GQLUpdateUserExtraInput; + UpdateUserInfoInput: GQLUpdateUserInfoInput; + UpdateUserRoleInput: GQLUpdateUserRoleInput; + UpdateUserStateInput: GQLUpdateUserStateInput; + Upload: Scalars['Upload']['output']; + UpsertSpamRingCandidatesInput: GQLUpsertSpamRingCandidatesInput; + UpsertSpamRingCandidatesResult: Omit & { rings: Array }; + User: UserModel; + UserActivity: UserModel; + UserAddArticleTagActivity: Omit & { actor: GQLResolversParentTypes['User'], node: GQLResolversParentTypes['Article'], target: GQLResolversParentTypes['Tag'] }; + UserAnalytics: UserModel; + UserArticlesFilter: GQLUserArticlesFilter; + UserArticlesInput: GQLUserArticlesInput; + UserBroadcastCircleActivity: Omit & { actor: GQLResolversParentTypes['User'], node: GQLResolversParentTypes['Comment'], target: GQLResolversParentTypes['Circle'] }; + UserConnection: Omit & { edges?: Maybe> }; + UserCreateCircleActivity: Omit & { actor: GQLResolversParentTypes['User'], node: GQLResolversParentTypes['Circle'] }; + UserEdge: Omit & { node: GQLResolversParentTypes['User'] }; + UserFeatureFlag: GQLUserFeatureFlag; + UserFeatures: GQLUserFeatures; + UserFederationSetting: GQLUserFederationSetting; + UserInfo: UserModel; + UserInput: GQLUserInput; + UserNotice: NoticeItemModel; + UserOSS: UserModel; + UserPostMomentActivity: Omit & { actor: GQLResolversParentTypes['User'], more: Array, node: GQLResolversParentTypes['Moment'] }; + UserPublishArticleActivity: Omit & { actor: GQLResolversParentTypes['User'], node: GQLResolversParentTypes['Article'] }; + UserRecommendationActivity: Omit & { nodes?: Maybe> }; + UserRestriction: GQLUserRestriction; + UserSettings: UserModel; + UserStatus: UserModel; + VerifyEmailInput: GQLVerifyEmailInput; + VoteCommentInput: GQLVoteCommentInput; + Wallet: UserModel; + WalletLoginInput: GQLWalletLoginInput; + WithdrawLockedTokensResult: Omit & { transaction: GQLResolversParentTypes['Transaction'] }; + Writing: WritingModel; + WritingChallenge: CampaignModel; + WritingConnection: Omit & { edges?: Maybe> }; + WritingEdge: Omit & { node: GQLResolversParentTypes['Writing'] }; + WritingInput: GQLWritingInput; +}>; export type GQLAuthDirectiveArgs = { - group?: Maybe - mode: Scalars['String']['input'] -} + group?: Maybe; + mode: Scalars['String']['input']; +}; -export type GQLAuthDirectiveResolver< - Result, - Parent, - ContextType = Context, - Args = GQLAuthDirectiveArgs -> = DirectiveResolverFn +export type GQLAuthDirectiveResolver = DirectiveResolverFn; export type GQLCacheControlDirectiveArgs = { - inheritMaxAge?: Maybe - maxAge?: Maybe - scope?: Maybe -} + inheritMaxAge?: Maybe; + maxAge?: Maybe; + scope?: Maybe; +}; -export type GQLCacheControlDirectiveResolver< - Result, - Parent, - ContextType = Context, - Args = GQLCacheControlDirectiveArgs -> = DirectiveResolverFn +export type GQLCacheControlDirectiveResolver = DirectiveResolverFn; export type GQLComplexityDirectiveArgs = { - multipliers?: Maybe> - value: Scalars['Int']['input'] -} + multipliers?: Maybe>; + value: Scalars['Int']['input']; +}; -export type GQLComplexityDirectiveResolver< - Result, - Parent, - ContextType = Context, - Args = GQLComplexityDirectiveArgs -> = DirectiveResolverFn +export type GQLComplexityDirectiveResolver = DirectiveResolverFn; export type GQLConstraintDirectiveArgs = { - contains?: Maybe - endsWith?: Maybe - exclusiveMax?: Maybe - exclusiveMin?: Maybe - format?: Maybe - max?: Maybe - maxItems?: Maybe - maxLength?: Maybe - min?: Maybe - minItems?: Maybe - minLength?: Maybe - multipleOf?: Maybe - notContains?: Maybe - pattern?: Maybe - startsWith?: Maybe - uniqueTypeName?: Maybe -} - -export type GQLConstraintDirectiveResolver< - Result, - Parent, - ContextType = Context, - Args = GQLConstraintDirectiveArgs -> = DirectiveResolverFn + contains?: Maybe; + endsWith?: Maybe; + exclusiveMax?: Maybe; + exclusiveMin?: Maybe; + format?: Maybe; + max?: Maybe; + maxItems?: Maybe; + maxLength?: Maybe; + min?: Maybe; + minItems?: Maybe; + minLength?: Maybe; + multipleOf?: Maybe; + notContains?: Maybe; + pattern?: Maybe; + startsWith?: Maybe; + uniqueTypeName?: Maybe; +}; + +export type GQLConstraintDirectiveResolver = DirectiveResolverFn; export type GQLLogCacheDirectiveArgs = { - identifier?: Maybe - type: Scalars['String']['input'] -} + identifier?: Maybe; + type: Scalars['String']['input']; +}; -export type GQLLogCacheDirectiveResolver< - Result, - Parent, - ContextType = Context, - Args = GQLLogCacheDirectiveArgs -> = DirectiveResolverFn +export type GQLLogCacheDirectiveResolver = DirectiveResolverFn; export type GQLObjectCacheDirectiveArgs = { - maxAge?: Maybe -} + maxAge?: Maybe; +}; -export type GQLObjectCacheDirectiveResolver< - Result, - Parent, - ContextType = Context, - Args = GQLObjectCacheDirectiveArgs -> = DirectiveResolverFn +export type GQLObjectCacheDirectiveResolver = DirectiveResolverFn; export type GQLPrivateCacheDirectiveArgs = { - strict?: Scalars['Boolean']['input'] -} + strict?: Scalars['Boolean']['input']; +}; -export type GQLPrivateCacheDirectiveResolver< - Result, - Parent, - ContextType = Context, - Args = GQLPrivateCacheDirectiveArgs -> = DirectiveResolverFn +export type GQLPrivateCacheDirectiveResolver = DirectiveResolverFn; export type GQLPurgeCacheDirectiveArgs = { - identifier?: Maybe - type: Scalars['String']['input'] -} + identifier?: Maybe; + type: Scalars['String']['input']; +}; -export type GQLPurgeCacheDirectiveResolver< - Result, - Parent, - ContextType = Context, - Args = GQLPurgeCacheDirectiveArgs -> = DirectiveResolverFn +export type GQLPurgeCacheDirectiveResolver = DirectiveResolverFn; export type GQLRateLimitDirectiveArgs = { - ip?: Maybe - limit: Scalars['Int']['input'] - period: Scalars['Int']['input'] -} - -export type GQLRateLimitDirectiveResolver< - Result, - Parent, - ContextType = Context, - Args = GQLRateLimitDirectiveArgs -> = DirectiveResolverFn - -export type GQLAdStatusResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['AdStatus'] = GQLResolversParentTypes['AdStatus'] -> = ResolversObject<{ - isAd?: Resolver, ParentType, ContextType> - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLAddCreditResultResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['AddCreditResult'] = GQLResolversParentTypes['AddCreditResult'] -> = ResolversObject<{ - client_secret?: Resolver - transaction?: Resolver< - GQLResolversTypes['Transaction'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLAnnouncementResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Announcement'] = GQLResolversParentTypes['Announcement'] -> = ResolversObject<{ - channels?: Resolver< - Array, - ParentType, - ContextType - > - content?: Resolver< - Maybe, - ParentType, - ContextType, - Partial - > - cover?: Resolver, ParentType, ContextType> - createdAt?: Resolver - expiredAt?: Resolver< - Maybe, - ParentType, - ContextType - > - id?: Resolver - link?: Resolver< - Maybe, - ParentType, - ContextType, - Partial - > - order?: Resolver - title?: Resolver< - Maybe, - ParentType, - ContextType, - Partial - > - translations?: Resolver< - Maybe>, - ParentType, - ContextType - > - type?: Resolver< - GQLResolversTypes['AnnouncementType'], - ParentType, - ContextType - > - updatedAt?: Resolver - visible?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLAnnouncementChannelResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['AnnouncementChannel'] = GQLResolversParentTypes['AnnouncementChannel'] -> = ResolversObject<{ - channel?: Resolver - order?: Resolver - visible?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLAppreciationResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Appreciation'] = GQLResolversParentTypes['Appreciation'] -> = ResolversObject<{ - amount?: Resolver - content?: Resolver - createdAt?: Resolver - purpose?: Resolver< - GQLResolversTypes['AppreciationPurpose'], - ParentType, - ContextType - > - recipient?: Resolver - sender?: Resolver, ParentType, ContextType> - target?: Resolver< - Maybe, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLAppreciationConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['AppreciationConnection'] = GQLResolversParentTypes['AppreciationConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLAppreciationEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['AppreciationEdge'] = GQLResolversParentTypes['AppreciationEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArchiveUserFailureResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArchiveUserFailure'] = GQLResolversParentTypes['ArchiveUserFailure'] -> = ResolversObject<{ - id?: Resolver - message?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArchiveUsersResultResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArchiveUsersResult'] = GQLResolversParentTypes['ArchiveUsersResult'] -> = ResolversObject<{ - archived?: Resolver, ParentType, ContextType> - skipped?: Resolver< - Array, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Article'] = GQLResolversParentTypes['Article'] -> = ResolversObject<{ - access?: Resolver - appreciateLeft?: Resolver - appreciateLimit?: Resolver - appreciationsReceived?: Resolver< - GQLResolversTypes['AppreciationConnection'], - ParentType, - ContextType, - RequireFields - > - appreciationsReceivedTotal?: Resolver< - GQLResolversTypes['Int'], - ParentType, - ContextType - > - assets?: Resolver, ParentType, ContextType> - author?: Resolver - availableTranslations?: Resolver< - Maybe>, - ParentType, - ContextType - > - bookmarkCount?: Resolver - bookmarked?: Resolver - campaigns?: Resolver< - Array, - ParentType, - ContextType - > - canComment?: Resolver - canSuperLike?: Resolver - classification?: Resolver< - GQLResolversTypes['ArticleClassification'], - ParentType, - ContextType - > - collection?: Resolver< - GQLResolversTypes['ArticleConnection'], - ParentType, - ContextType, - RequireFields - > - collections?: Resolver< - GQLResolversTypes['CollectionConnection'], - ParentType, - ContextType, - RequireFields - > - commentCount?: Resolver - comments?: Resolver< - GQLResolversTypes['CommentConnection'], - ParentType, - ContextType, - RequireFields - > - connectedBy?: Resolver< - GQLResolversTypes['ArticleConnection'], - ParentType, - ContextType, - RequireFields - > - connections?: Resolver< - GQLResolversTypes['ArticleConnection'], - ParentType, - ContextType, - RequireFields - > - content?: Resolver - contents?: Resolver< - GQLResolversTypes['ArticleContents'], - ParentType, - ContextType - > - cover?: Resolver, ParentType, ContextType> - createdAt?: Resolver - dataHash?: Resolver - displayCover?: Resolver< - Maybe, - ParentType, - ContextType - > - donated?: Resolver - donationCount?: Resolver - donations?: Resolver< - GQLResolversTypes['ArticleDonationConnection'], - ParentType, - ContextType, - RequireFields - > - featuredComments?: Resolver< - GQLResolversTypes['CommentConnection'], - ParentType, - ContextType, - RequireFields - > - federationEligibility?: Resolver< - GQLResolversTypes['ArticleFederationEligibility'], - ParentType, - ContextType - > - federationSetting?: Resolver< - Maybe, - ParentType, - ContextType - > - hasAppreciate?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - id?: Resolver - indentFirstLine?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - iscnId?: Resolver, ParentType, ContextType> - language?: Resolver< - Maybe, - ParentType, - ContextType - > - license?: Resolver< - GQLResolversTypes['ArticleLicenseType'], - ParentType, - ContextType - > - mediaHash?: Resolver - noindex?: Resolver - oss?: Resolver - pinCommentLeft?: Resolver - pinCommentLimit?: Resolver - pinned?: Resolver - pinnedComments?: Resolver< - Maybe>, - ParentType, - ContextType - > - readTime?: Resolver - readerCount?: Resolver - relatedArticles?: Resolver< - GQLResolversTypes['ArticleConnection'], - ParentType, - ContextType, - RequireFields - > - relatedDonationArticles?: Resolver< - GQLResolversTypes['ArticleConnection'], - ParentType, - ContextType, - RequireFields - > - remark?: Resolver, ParentType, ContextType> - replyToDonator?: Resolver< - Maybe, - ParentType, - ContextType - > - requestForDonation?: Resolver< - Maybe, - ParentType, - ContextType - > - responseCount?: Resolver - responses?: Resolver< - GQLResolversTypes['ResponseConnection'], - ParentType, - ContextType, - RequireFields - > - revisedAt?: Resolver< - Maybe, - ParentType, - ContextType - > - revisionCount?: Resolver - sensitiveByAdmin?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - sensitiveByAuthor?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - shortHash?: Resolver - slug?: Resolver - state?: Resolver - subscribed?: Resolver - summary?: Resolver - summaryCustomized?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - tags?: Resolver< - Maybe>, - ParentType, - ContextType - > - title?: Resolver - transactionsReceivedBy?: Resolver< - GQLResolversTypes['UserConnection'], - ParentType, - ContextType, - RequireFields - > - translation?: Resolver< - Maybe, - ParentType, - ContextType, - Partial - > - versions?: Resolver< - GQLResolversTypes['ArticleVersionsConnection'], - ParentType, - ContextType, - RequireFields - > - wordCount?: Resolver, ParentType, ContextType> - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleAccessResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArticleAccess'] = GQLResolversParentTypes['ArticleAccess'] -> = ResolversObject<{ - circle?: Resolver, ParentType, ContextType> - secret?: Resolver, ParentType, ContextType> - type?: Resolver< - GQLResolversTypes['ArticleAccessType'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleArticleNoticeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArticleArticleNotice'] = GQLResolversParentTypes['ArticleArticleNotice'] -> = ResolversObject<{ - actors?: Resolver< - Maybe>, - ParentType, - ContextType - > - article?: Resolver - createdAt?: Resolver - id?: Resolver - target?: Resolver - type?: Resolver< - GQLResolversTypes['ArticleArticleNoticeType'], - ParentType, - ContextType - > - unread?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleCampaignResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArticleCampaign'] = GQLResolversParentTypes['ArticleCampaign'] -> = ResolversObject<{ - campaign?: Resolver - stage?: Resolver< - Maybe, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleClassificationResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArticleClassification'] = GQLResolversParentTypes['ArticleClassification'] -> = ResolversObject<{ - topicChannel?: Resolver< - GQLResolversTypes['TopicChannelClassification'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArticleConnection'] = GQLResolversParentTypes['ArticleConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleContentsResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArticleContents'] = GQLResolversParentTypes['ArticleContents'] -> = ResolversObject<{ - html?: Resolver - markdown?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleDonationResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArticleDonation'] = GQLResolversParentTypes['ArticleDonation'] -> = ResolversObject<{ - id?: Resolver - sender?: Resolver, ParentType, ContextType> - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleDonationConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArticleDonationConnection'] = GQLResolversParentTypes['ArticleDonationConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleDonationEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArticleDonationEdge'] = GQLResolversParentTypes['ArticleDonationEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArticleEdge'] = GQLResolversParentTypes['ArticleEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleFederationEligibilityResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArticleFederationEligibility'] = GQLResolversParentTypes['ArticleFederationEligibility'] -> = ResolversObject<{ - effectiveArticleSetting?: Resolver< - GQLResolversTypes['FederationArticleSettingState'], - ParentType, - ContextType - > - eligible?: Resolver - reason?: Resolver< - GQLResolversTypes['FederationExportDecisionReason'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleFederationSettingResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArticleFederationSetting'] = GQLResolversParentTypes['ArticleFederationSetting'] -> = ResolversObject<{ - articleId?: Resolver - state?: Resolver< - GQLResolversTypes['FederationArticleSettingState'], - ParentType, - ContextType - > - updatedBy?: Resolver, ParentType, ContextType> - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleNoticeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArticleNotice'] = GQLResolversParentTypes['ArticleNotice'] -> = ResolversObject<{ - actors?: Resolver< - Maybe>, - ParentType, - ContextType - > - createdAt?: Resolver - entities?: Resolver, ParentType, ContextType> - id?: Resolver - target?: Resolver - type?: Resolver< - GQLResolversTypes['ArticleNoticeType'], - ParentType, - ContextType - > - unread?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleOssResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArticleOSS'] = GQLResolversParentTypes['ArticleOSS'] -> = ResolversObject<{ - adStatus?: Resolver - boost?: Resolver - inRecommendHottest?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - inRecommendIcymi?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - inRecommendNewest?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - inSearch?: Resolver - pinHistory?: Resolver< - Array>, - ParentType, - ContextType - > - score?: Resolver - spamStatus?: Resolver< - GQLResolversTypes['SpamStatus'], - ParentType, - ContextType - > - topicChannels?: Resolver< - Maybe>, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleRecommendationActivityResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArticleRecommendationActivity'] = GQLResolversParentTypes['ArticleRecommendationActivity'] -> = ResolversObject<{ - nodes?: Resolver< - Maybe>, - ParentType, - ContextType - > - source?: Resolver< - Maybe, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleTopicChannelResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArticleTopicChannel'] = GQLResolversParentTypes['ArticleTopicChannel'] -> = ResolversObject<{ - antiFlooded?: Resolver - channel?: Resolver - classicfiedAt?: Resolver< - GQLResolversTypes['DateTime'], - ParentType, - ContextType - > - enabled?: Resolver - isLabeled?: Resolver - pinned?: Resolver - score?: Resolver, ParentType, ContextType> - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleTranslationResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArticleTranslation'] = GQLResolversParentTypes['ArticleTranslation'] -> = ResolversObject<{ - content?: Resolver< - Maybe, - ParentType, - ContextType - > - language?: Resolver< - Maybe, - ParentType, - ContextType - > - model?: Resolver< - Maybe, - ParentType, - ContextType - > - summary?: Resolver< - Maybe, - ParentType, - ContextType - > - title?: Resolver, ParentType, ContextType> - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleVersionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArticleVersion'] = GQLResolversParentTypes['ArticleVersion'] -> = ResolversObject<{ - contents?: Resolver< - GQLResolversTypes['ArticleContents'], - ParentType, - ContextType - > - createdAt?: Resolver - dataHash?: Resolver< - Maybe, - ParentType, - ContextType - > - description?: Resolver< - Maybe, - ParentType, - ContextType - > - id?: Resolver - mediaHash?: Resolver< - Maybe, - ParentType, - ContextType - > - summary?: Resolver - title?: Resolver - translation?: Resolver< - Maybe, - ParentType, - ContextType, - Partial - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleVersionEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArticleVersionEdge'] = GQLResolversParentTypes['ArticleVersionEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLArticleVersionsConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ArticleVersionsConnection'] = GQLResolversParentTypes['ArticleVersionsConnection'] -> = ResolversObject<{ - edges?: Resolver< - Array>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLAssetResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Asset'] = GQLResolversParentTypes['Asset'] -> = ResolversObject<{ - createdAt?: Resolver - draft?: Resolver, ParentType, ContextType> - id?: Resolver - path?: Resolver - type?: Resolver - uploadURL?: Resolver< - Maybe, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLAuthResultResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['AuthResult'] = GQLResolversParentTypes['AuthResult'] -> = ResolversObject<{ - auth?: Resolver - token?: Resolver, ParentType, ContextType> - type?: Resolver - user?: Resolver, ParentType, ContextType> - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLBadgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Badge'] = GQLResolversParentTypes['Badge'] -> = ResolversObject<{ - type?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLBalanceResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Balance'] = GQLResolversParentTypes['Balance'] -> = ResolversObject<{ - HKD?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLBlockchainTransactionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['BlockchainTransaction'] = GQLResolversParentTypes['BlockchainTransaction'] -> = ResolversObject<{ - chain?: Resolver - txHash?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLBlockedSearchKeywordResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['BlockedSearchKeyword'] = GQLResolversParentTypes['BlockedSearchKeyword'] -> = ResolversObject<{ - createdAt?: Resolver - id?: Resolver - searchKey?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCampaignResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Campaign'] = GQLResolversParentTypes['Campaign'] -> = ResolversObject<{ - __resolveType: TypeResolveFn<'WritingChallenge', ParentType, ContextType> -}> - -export type GQLCampaignApplicationResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CampaignApplication'] = GQLResolversParentTypes['CampaignApplication'] -> = ResolversObject<{ - createdAt?: Resolver - state?: Resolver< - GQLResolversTypes['CampaignApplicationState'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCampaignArticleConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CampaignArticleConnection'] = GQLResolversParentTypes['CampaignArticleConnection'] -> = ResolversObject<{ - edges?: Resolver< - Array, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCampaignArticleEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CampaignArticleEdge'] = GQLResolversParentTypes['CampaignArticleEdge'] -> = ResolversObject<{ - announcement?: Resolver - cursor?: Resolver - featured?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCampaignArticleNoticeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CampaignArticleNotice'] = GQLResolversParentTypes['CampaignArticleNotice'] -> = ResolversObject<{ - actors?: Resolver< - Maybe>, - ParentType, - ContextType - > - article?: Resolver - createdAt?: Resolver - id?: Resolver - target?: Resolver - type?: Resolver< - GQLResolversTypes['CampaignArticleNoticeType'], - ParentType, - ContextType - > - unread?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCampaignConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CampaignConnection'] = GQLResolversParentTypes['CampaignConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCampaignEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CampaignEdge'] = GQLResolversParentTypes['CampaignEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCampaignOssResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CampaignOSS'] = GQLResolversParentTypes['CampaignOSS'] -> = ResolversObject<{ - boost?: Resolver - exclusive?: Resolver - managers?: Resolver, ParentType, ContextType> - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCampaignParticipantConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CampaignParticipantConnection'] = GQLResolversParentTypes['CampaignParticipantConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCampaignParticipantEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CampaignParticipantEdge'] = GQLResolversParentTypes['CampaignParticipantEdge'] -> = ResolversObject<{ - application?: Resolver< - Maybe, - ParentType, - ContextType - > - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCampaignStageResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CampaignStage'] = GQLResolversParentTypes['CampaignStage'] -> = ResolversObject<{ - description?: Resolver< - GQLResolversTypes['String'], - ParentType, - ContextType, - Partial - > - id?: Resolver - name?: Resolver< - GQLResolversTypes['String'], - ParentType, - ContextType, - Partial - > - period?: Resolver< - Maybe, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLChannelResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Channel'] = GQLResolversParentTypes['Channel'] -> = ResolversObject<{ - __resolveType: TypeResolveFn< - 'CurationChannel' | 'Tag' | 'TopicChannel' | 'WritingChallenge', - ParentType, - ContextType - > -}> - -export type GQLChannelArticleConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ChannelArticleConnection'] = GQLResolversParentTypes['ChannelArticleConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLChannelArticleEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ChannelArticleEdge'] = GQLResolversParentTypes['ChannelArticleEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - pinned?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCircleResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Circle'] = GQLResolversParentTypes['Circle'] -> = ResolversObject<{ - analytics?: Resolver< - GQLResolversTypes['CircleAnalytics'], - ParentType, - ContextType - > - avatar?: Resolver, ParentType, ContextType> - broadcast?: Resolver< - GQLResolversTypes['CommentConnection'], - ParentType, - ContextType, - RequireFields - > - cover?: Resolver, ParentType, ContextType> - createdAt?: Resolver - description?: Resolver< - Maybe, - ParentType, - ContextType - > - discussion?: Resolver< - GQLResolversTypes['CommentConnection'], - ParentType, - ContextType, - RequireFields - > - discussionCount?: Resolver - discussionThreadCount?: Resolver< - GQLResolversTypes['Int'], - ParentType, - ContextType - > - displayName?: Resolver - followers?: Resolver< - GQLResolversTypes['UserConnection'], - ParentType, - ContextType, - RequireFields - > - id?: Resolver - invitedBy?: Resolver< - Maybe, - ParentType, - ContextType - > - invites?: Resolver - isFollower?: Resolver - isMember?: Resolver - members?: Resolver< - GQLResolversTypes['MemberConnection'], - ParentType, - ContextType, - RequireFields - > - name?: Resolver - owner?: Resolver - pinnedBroadcast?: Resolver< - Maybe>, - ParentType, - ContextType - > - prices?: Resolver< - Maybe>, - ParentType, - ContextType - > - state?: Resolver - updatedAt?: Resolver - works?: Resolver< - GQLResolversTypes['ArticleConnection'], - ParentType, - ContextType, - RequireFields - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCircleAnalyticsResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CircleAnalytics'] = GQLResolversParentTypes['CircleAnalytics'] -> = ResolversObject<{ - content?: Resolver< - GQLResolversTypes['CircleContentAnalytics'], - ParentType, - ContextType - > - follower?: Resolver< - GQLResolversTypes['CircleFollowerAnalytics'], - ParentType, - ContextType - > - income?: Resolver< - GQLResolversTypes['CircleIncomeAnalytics'], - ParentType, - ContextType - > - subscriber?: Resolver< - GQLResolversTypes['CircleSubscriberAnalytics'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCircleConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CircleConnection'] = GQLResolversParentTypes['CircleConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCircleContentAnalyticsResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CircleContentAnalytics'] = GQLResolversParentTypes['CircleContentAnalytics'] -> = ResolversObject<{ - paywall?: Resolver< - Maybe>, - ParentType, - ContextType - > - public?: Resolver< - Maybe>, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCircleContentAnalyticsDatumResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CircleContentAnalyticsDatum'] = GQLResolversParentTypes['CircleContentAnalyticsDatum'] -> = ResolversObject<{ - node?: Resolver - readCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCircleEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CircleEdge'] = GQLResolversParentTypes['CircleEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCircleFollowerAnalyticsResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CircleFollowerAnalytics'] = GQLResolversParentTypes['CircleFollowerAnalytics'] -> = ResolversObject<{ - current?: Resolver - followerPercentage?: Resolver< - GQLResolversTypes['Float'], - ParentType, - ContextType - > - history?: Resolver< - Array, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCircleIncomeAnalyticsResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CircleIncomeAnalytics'] = GQLResolversParentTypes['CircleIncomeAnalytics'] -> = ResolversObject<{ - history?: Resolver< - Array, - ParentType, - ContextType - > - nextMonth?: Resolver - thisMonth?: Resolver - total?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCircleNoticeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CircleNotice'] = GQLResolversParentTypes['CircleNotice'] -> = ResolversObject<{ - actors?: Resolver< - Maybe>, - ParentType, - ContextType - > - comments?: Resolver< - Maybe>, - ParentType, - ContextType - > - createdAt?: Resolver - id?: Resolver - mentions?: Resolver< - Maybe>, - ParentType, - ContextType - > - replies?: Resolver< - Maybe>, - ParentType, - ContextType - > - target?: Resolver - type?: Resolver< - GQLResolversTypes['CircleNoticeType'], - ParentType, - ContextType - > - unread?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCircleRecommendationActivityResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CircleRecommendationActivity'] = GQLResolversParentTypes['CircleRecommendationActivity'] -> = ResolversObject<{ - nodes?: Resolver< - Maybe>, - ParentType, - ContextType - > - source?: Resolver< - Maybe, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCircleSubscriberAnalyticsResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CircleSubscriberAnalytics'] = GQLResolversParentTypes['CircleSubscriberAnalytics'] -> = ResolversObject<{ - currentInvitee?: Resolver - currentSubscriber?: Resolver< - GQLResolversTypes['Int'], - ParentType, - ContextType - > - inviteeHistory?: Resolver< - Array, - ParentType, - ContextType - > - subscriberHistory?: Resolver< - Array, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLClaimLogbooksResultResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ClaimLogbooksResult'] = GQLResolversParentTypes['ClaimLogbooksResult'] -> = ResolversObject<{ - ids?: Resolver>, ParentType, ContextType> - txHash?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCollectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Collection'] = GQLResolversParentTypes['Collection'] -> = ResolversObject<{ - articles?: Resolver< - GQLResolversTypes['ArticleConnection'], - ParentType, - ContextType, - RequireFields - > - author?: Resolver - contains?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType, - RequireFields - > - cover?: Resolver, ParentType, ContextType> - description?: Resolver< - Maybe, - ParentType, - ContextType - > - id?: Resolver - likeCount?: Resolver - liked?: Resolver - pinned?: Resolver - title?: Resolver - updatedAt?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCollectionConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CollectionConnection'] = GQLResolversParentTypes['CollectionConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCollectionEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CollectionEdge'] = GQLResolversParentTypes['CollectionEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCollectionNoticeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CollectionNotice'] = GQLResolversParentTypes['CollectionNotice'] -> = ResolversObject<{ - actors?: Resolver< - Maybe>, - ParentType, - ContextType - > - createdAt?: Resolver - id?: Resolver - target?: Resolver - unread?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCommentResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Comment'] = GQLResolversParentTypes['Comment'] -> = ResolversObject<{ - author?: Resolver - comments?: Resolver< - GQLResolversTypes['CommentConnection'], - ParentType, - ContextType, - RequireFields - > - communityWatchAction?: Resolver< - Maybe, - ParentType, - ContextType - > - content?: Resolver< - Maybe, - ParentType, - ContextType - > - createdAt?: Resolver - downvotes?: Resolver - fromDonator?: Resolver - id?: Resolver - myVote?: Resolver, ParentType, ContextType> - node?: Resolver - parentComment?: Resolver< - Maybe, - ParentType, - ContextType - > - pinned?: Resolver - remark?: Resolver, ParentType, ContextType> - replyTo?: Resolver< - Maybe, - ParentType, - ContextType - > - spamStatus?: Resolver< - GQLResolversTypes['SpamStatus'], - ParentType, - ContextType - > - state?: Resolver - type?: Resolver - upvotes?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCommentCommentNoticeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CommentCommentNotice'] = GQLResolversParentTypes['CommentCommentNotice'] -> = ResolversObject<{ - actors?: Resolver< - Maybe>, - ParentType, - ContextType - > - comment?: Resolver - createdAt?: Resolver - id?: Resolver - target?: Resolver - type?: Resolver< - GQLResolversTypes['CommentCommentNoticeType'], - ParentType, - ContextType - > - unread?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCommentConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CommentConnection'] = GQLResolversParentTypes['CommentConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCommentEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CommentEdge'] = GQLResolversParentTypes['CommentEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCommentNoticeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CommentNotice'] = GQLResolversParentTypes['CommentNotice'] -> = ResolversObject<{ - actors?: Resolver< - Maybe>, - ParentType, - ContextType - > - createdAt?: Resolver - id?: Resolver - target?: Resolver - type?: Resolver< - GQLResolversTypes['CommentNoticeType'], - ParentType, - ContextType - > - unread?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCommunityWatchActionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CommunityWatchAction'] = GQLResolversParentTypes['CommunityWatchAction'] -> = ResolversObject<{ - actionState?: Resolver< - GQLResolversTypes['CommunityWatchActionState'], - ParentType, - ContextType - > - actorDisplayName?: Resolver< - GQLResolversTypes['String'], - ParentType, - ContextType - > - appealState?: Resolver< - GQLResolversTypes['CommunityWatchAppealState'], - ParentType, - ContextType - > - commentId?: Resolver - contentCleared?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - contentHash?: Resolver< - Maybe, - ParentType, - ContextType - > - createdAt?: Resolver - originalContent?: Resolver< - Maybe, - ParentType, - ContextType - > - reason?: Resolver< - GQLResolversTypes['CommunityWatchRemoveCommentReason'], - ParentType, - ContextType - > - reportSynced?: Resolver - reviewState?: Resolver< - GQLResolversTypes['CommunityWatchReviewState'], - ParentType, - ContextType - > - sourceId?: Resolver - sourceTitle?: Resolver - sourceType?: Resolver< - GQLResolversTypes['CommunityWatchActionSourceType'], - ParentType, - ContextType - > - sourceUrl?: Resolver< - Maybe, - ParentType, - ContextType - > - uuid?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCommunityWatchActionConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CommunityWatchActionConnection'] = GQLResolversParentTypes['CommunityWatchActionConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCommunityWatchActionEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CommunityWatchActionEdge'] = GQLResolversParentTypes['CommunityWatchActionEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver< - GQLResolversTypes['CommunityWatchAction'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLConnectStripeAccountResultResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ConnectStripeAccountResult'] = GQLResolversParentTypes['ConnectStripeAccountResult'] -> = ResolversObject<{ - redirectUrl?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Connection'] = GQLResolversParentTypes['Connection'] -> = ResolversObject<{ - __resolveType: TypeResolveFn< - | 'AppreciationConnection' - | 'ArticleConnection' - | 'ArticleVersionsConnection' - | 'CampaignArticleConnection' - | 'CampaignConnection' - | 'CampaignParticipantConnection' - | 'ChannelArticleConnection' - | 'CircleConnection' - | 'CollectionConnection' - | 'CommentConnection' - | 'CommunityWatchActionConnection' - | 'DraftConnection' - | 'FollowingActivityConnection' - | 'IcymiTopicConnection' - | 'InvitationConnection' - | 'MemberConnection' - | 'MomentConnection' - | 'NoticeConnection' - | 'OAuthClientConnection' - | 'ReadHistoryConnection' - | 'RecentSearchConnection' - | 'ReportConnection' - | 'ResponseConnection' - | 'SearchResultConnection' - | 'SkippedListItemsConnection' - | 'TagConnection' - | 'TagWritingConnection' - | 'TopDonatorConnection' - | 'TopicChannelFeedbackConnection' - | 'TransactionConnection' - | 'UserConnection' - | 'WritingConnection', - ParentType, - ContextType - > -}> - -export type GQLCryptoWalletResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CryptoWallet'] = GQLResolversParentTypes['CryptoWallet'] -> = ResolversObject<{ - address?: Resolver - hasNFTs?: Resolver - id?: Resolver - nfts?: Resolver< - Maybe>, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLCurationChannelResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['CurationChannel'] = GQLResolversParentTypes['CurationChannel'] -> = ResolversObject<{ - activePeriod?: Resolver< - GQLResolversTypes['DatetimeRange'], - ParentType, - ContextType - > - articles?: Resolver< - GQLResolversTypes['ChannelArticleConnection'], - ParentType, - ContextType, - RequireFields - > - color?: Resolver - id?: Resolver - name?: Resolver< - GQLResolversTypes['String'], - ParentType, - ContextType, - Partial - > - navbarTitle?: Resolver< - GQLResolversTypes['String'], - ParentType, - ContextType, - Partial - > - note?: Resolver< - Maybe, - ParentType, - ContextType, - Partial - > - pinAmount?: Resolver - shortHash?: Resolver - showRecommendation?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - state?: Resolver< - GQLResolversTypes['CurationChannelState'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export interface GQLDateTimeScalarConfig - extends GraphQLScalarTypeConfig { - name: 'DateTime' -} - -export type GQLDatetimeRangeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['DatetimeRange'] = GQLResolversParentTypes['DatetimeRange'] -> = ResolversObject<{ - end?: Resolver, ParentType, ContextType> - start?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLDonatorResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Donator'] = GQLResolversParentTypes['Donator'] -> = ResolversObject<{ - __resolveType: TypeResolveFn<'CryptoWallet' | 'User', ParentType, ContextType> -}> - -export type GQLDraftResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Draft'] = GQLResolversParentTypes['Draft'] -> = ResolversObject<{ - access?: Resolver - article?: Resolver< - Maybe, - ParentType, - ContextType - > - assets?: Resolver, ParentType, ContextType> - campaigns?: Resolver< - Array, - ParentType, - ContextType - > - canComment?: Resolver - collection?: Resolver< - GQLResolversTypes['ArticleConnection'], - ParentType, - ContextType, - RequireFields - > - collections?: Resolver< - GQLResolversTypes['CollectionConnection'], - ParentType, - ContextType, - RequireFields - > - connections?: Resolver< - GQLResolversTypes['ArticleConnection'], - ParentType, - ContextType, - RequireFields - > - content?: Resolver< - Maybe, - ParentType, - ContextType - > - cover?: Resolver, ParentType, ContextType> - createdAt?: Resolver - id?: Resolver - indentFirstLine?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - iscnPublish?: Resolver< - Maybe, - ParentType, - ContextType - > - license?: Resolver< - GQLResolversTypes['ArticleLicenseType'], - ParentType, - ContextType - > - mediaHash?: Resolver< - Maybe, - ParentType, - ContextType - > - publishAt?: Resolver< - Maybe, - ParentType, - ContextType - > - publishState?: Resolver< - GQLResolversTypes['PublishState'], - ParentType, - ContextType - > - replyToDonator?: Resolver< - Maybe, - ParentType, - ContextType - > - requestForDonation?: Resolver< - Maybe, - ParentType, - ContextType - > - sensitiveByAuthor?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - slug?: Resolver - summary?: Resolver< - Maybe, - ParentType, - ContextType - > - summaryCustomized?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - tags?: Resolver< - Maybe>, - ParentType, - ContextType - > - title?: Resolver, ParentType, ContextType> - updatedAt?: Resolver - wordCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLDraftAccessResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['DraftAccess'] = GQLResolversParentTypes['DraftAccess'] -> = ResolversObject<{ - circle?: Resolver, ParentType, ContextType> - type?: Resolver< - GQLResolversTypes['ArticleAccessType'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLDraftConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['DraftConnection'] = GQLResolversParentTypes['DraftConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLDraftEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['DraftEdge'] = GQLResolversParentTypes['DraftEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLExchangeRateResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ExchangeRate'] = GQLResolversParentTypes['ExchangeRate'] -> = ResolversObject<{ - from?: Resolver< - GQLResolversTypes['TransactionCurrency'], - ParentType, - ContextType - > - rate?: Resolver - to?: Resolver - updatedAt?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLFeatureResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Feature'] = GQLResolversParentTypes['Feature'] -> = ResolversObject<{ - enabled?: Resolver - name?: Resolver - value?: Resolver, ParentType, ContextType> - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLFollowingResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Following'] = GQLResolversParentTypes['Following'] -> = ResolversObject<{ - circles?: Resolver< - GQLResolversTypes['CircleConnection'], - ParentType, - ContextType, - RequireFields - > - users?: Resolver< - GQLResolversTypes['UserConnection'], - ParentType, - ContextType, - RequireFields - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLFollowingActivityResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['FollowingActivity'] = GQLResolversParentTypes['FollowingActivity'] -> = ResolversObject<{ - __resolveType: TypeResolveFn< - | 'ArticleRecommendationActivity' - | 'CircleRecommendationActivity' - | 'UserAddArticleTagActivity' - | 'UserBroadcastCircleActivity' - | 'UserCreateCircleActivity' - | 'UserPostMomentActivity' - | 'UserPublishArticleActivity' - | 'UserRecommendationActivity', - ParentType, - ContextType - > -}> - -export type GQLFollowingActivityConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['FollowingActivityConnection'] = GQLResolversParentTypes['FollowingActivityConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLFollowingActivityEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['FollowingActivityEdge'] = GQLResolversParentTypes['FollowingActivityEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver< - GQLResolversTypes['FollowingActivity'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLIcymiTopicResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['IcymiTopic'] = GQLResolversParentTypes['IcymiTopic'] -> = ResolversObject<{ - archivedAt?: Resolver< - Maybe, - ParentType, - ContextType - > - articles?: Resolver< - Array, - ParentType, - ContextType - > - id?: Resolver - note?: Resolver< - Maybe, - ParentType, - ContextType, - Partial - > - pinAmount?: Resolver - publishedAt?: Resolver< - Maybe, - ParentType, - ContextType - > - state?: Resolver< - GQLResolversTypes['IcymiTopicState'], - ParentType, - ContextType - > - title?: Resolver< - GQLResolversTypes['String'], - ParentType, - ContextType, - Partial - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLIcymiTopicConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['IcymiTopicConnection'] = GQLResolversParentTypes['IcymiTopicConnection'] -> = ResolversObject<{ - edges?: Resolver< - Array, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLIcymiTopicEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['IcymiTopicEdge'] = GQLResolversParentTypes['IcymiTopicEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLInvitationResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Invitation'] = GQLResolversParentTypes['Invitation'] -> = ResolversObject<{ - acceptedAt?: Resolver< - Maybe, - ParentType, - ContextType - > - circle?: Resolver - createdAt?: Resolver - freePeriod?: Resolver - id?: Resolver - invitee?: Resolver - inviter?: Resolver - sentAt?: Resolver - state?: Resolver< - GQLResolversTypes['InvitationState'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLInvitationConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['InvitationConnection'] = GQLResolversParentTypes['InvitationConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLInvitationEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['InvitationEdge'] = GQLResolversParentTypes['InvitationEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLInviteeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Invitee'] = GQLResolversParentTypes['Invitee'] -> = ResolversObject<{ - __resolveType: TypeResolveFn<'Person' | 'User', ParentType, ContextType> -}> - -export type GQLInvitesResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Invites'] = GQLResolversParentTypes['Invites'] -> = ResolversObject<{ - accepted?: Resolver< - GQLResolversTypes['InvitationConnection'], - ParentType, - ContextType, - RequireFields - > - pending?: Resolver< - GQLResolversTypes['InvitationConnection'], - ParentType, - ContextType, - RequireFields - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLLikerResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Liker'] = GQLResolversParentTypes['Liker'] -> = ResolversObject<{ - civicLiker?: Resolver - likerId?: Resolver< - Maybe, - ParentType, - ContextType - > - total?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLMemberResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Member'] = GQLResolversParentTypes['Member'] -> = ResolversObject<{ - price?: Resolver - user?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLMemberConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['MemberConnection'] = GQLResolversParentTypes['MemberConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLMemberEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['MemberEdge'] = GQLResolversParentTypes['MemberEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLMomentResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Moment'] = GQLResolversParentTypes['Moment'] -> = ResolversObject<{ - adStatus?: Resolver - articles?: Resolver< - Array, - ParentType, - ContextType - > - assets?: Resolver, ParentType, ContextType> - author?: Resolver - commentCount?: Resolver - commentedFollowees?: Resolver< - Array, - ParentType, - ContextType - > - comments?: Resolver< - GQLResolversTypes['CommentConnection'], - ParentType, - ContextType, - RequireFields - > - content?: Resolver< - Maybe, - ParentType, - ContextType - > - createdAt?: Resolver - id?: Resolver - likeCount?: Resolver - liked?: Resolver - shortHash?: Resolver - spamStatus?: Resolver< - GQLResolversTypes['SpamStatus'], - ParentType, - ContextType - > - state?: Resolver - tags?: Resolver< - Array>, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLMomentConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['MomentConnection'] = GQLResolversParentTypes['MomentConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLMomentEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['MomentEdge'] = GQLResolversParentTypes['MomentEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLMomentFeedApplicationResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['MomentFeedApplication'] = GQLResolversParentTypes['MomentFeedApplication'] -> = ResolversObject<{ - createdAt?: Resolver - reviewedBy?: Resolver< - Maybe, - ParentType, - ContextType - > - reviewer?: Resolver, ParentType, ContextType> - state?: Resolver< - GQLResolversTypes['MomentFeedUserState'], - ParentType, - ContextType - > - updatedAt?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLMomentNoticeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['MomentNotice'] = GQLResolversParentTypes['MomentNotice'] -> = ResolversObject<{ - actors?: Resolver< - Maybe>, - ParentType, - ContextType - > - createdAt?: Resolver - id?: Resolver - target?: Resolver - type?: Resolver< - GQLResolversTypes['MomentNoticeType'], - ParentType, - ContextType - > - unread?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLMonthlyDatumResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['MonthlyDatum'] = GQLResolversParentTypes['MonthlyDatum'] -> = ResolversObject<{ - date?: Resolver - value?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLMutationResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Mutation'] = GQLResolversParentTypes['Mutation'] -> = ResolversObject<{ - addBlockedSearchKeyword?: Resolver< - GQLResolversTypes['BlockedSearchKeyword'], - ParentType, - ContextType, - RequireFields - > - addCollectionsArticles?: Resolver< - Array, - ParentType, - ContextType, - RequireFields - > - addCredit?: Resolver< - GQLResolversTypes['AddCreditResult'], - ParentType, - ContextType, - RequireFields - > - addCurationChannelArticles?: Resolver< - GQLResolversTypes['CurationChannel'], - ParentType, - ContextType, - RequireFields - > - addSocialLogin?: Resolver< - GQLResolversTypes['User'], - ParentType, - ContextType, - RequireFields - > - addWalletLogin?: Resolver< - GQLResolversTypes['User'], - ParentType, - ContextType, - RequireFields - > - applyCampaign?: Resolver< - GQLResolversTypes['Campaign'], - ParentType, - ContextType, - RequireFields - > - applyMomentFeed?: Resolver - appreciateArticle?: Resolver< - GQLResolversTypes['Article'], - ParentType, - ContextType, - RequireFields - > - archiveUsers?: Resolver< - GQLResolversTypes['ArchiveUsersResult'], - ParentType, - ContextType, - RequireFields - > - banCampaignArticles?: Resolver< - GQLResolversTypes['Campaign'], - ParentType, - ContextType, - RequireFields - > - claimLogbooks?: Resolver< - GQLResolversTypes['ClaimLogbooksResult'], - ParentType, - ContextType, - RequireFields - > - claimPersonhoodBadge?: Resolver< - GQLResolversTypes['User'], - ParentType, - ContextType, - RequireFields - > - classifyArticlesChannels?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType, - RequireFields - > - clearCommunityWatchOriginalContent?: Resolver< - GQLResolversTypes['CommunityWatchAction'], - ParentType, - ContextType, - RequireFields - > - clearReadHistory?: Resolver< - GQLResolversTypes['User'], - ParentType, - ContextType, - RequireFields - > - clearSearchHistory?: Resolver< - Maybe, - ParentType, - ContextType - > - communityWatchRemoveComment?: Resolver< - GQLResolversTypes['Comment'], - ParentType, - ContextType, - RequireFields - > - confirmVerificationCode?: Resolver< - GQLResolversTypes['ID'], - ParentType, - ContextType, - RequireFields - > - connectStripeAccount?: Resolver< - GQLResolversTypes['ConnectStripeAccountResult'], - ParentType, - ContextType, - RequireFields - > - createPersonhoodHandoff?: Resolver< - GQLResolversTypes['PersonhoodHandoff'], - ParentType, - ContextType, - RequireFields - > - deleteAnnouncements?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType, - RequireFields - > - deleteBlockedSearchKeywords?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - > - deleteCollectionArticles?: Resolver< - GQLResolversTypes['Collection'], - ParentType, - ContextType, - RequireFields - > - deleteCollections?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType, - RequireFields - > - deleteComment?: Resolver< - GQLResolversTypes['Comment'], - ParentType, - ContextType, - RequireFields - > - deleteCurationChannelArticles?: Resolver< - GQLResolversTypes['CurationChannel'], - ParentType, - ContextType, - RequireFields - > - deleteDraft?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - > - deleteMoment?: Resolver< - GQLResolversTypes['Moment'], - ParentType, - ContextType, - RequireFields - > - deleteTags?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - > - directImageUpload?: Resolver< - GQLResolversTypes['Asset'], - ParentType, - ContextType, - RequireFields - > - editArticle?: Resolver< - GQLResolversTypes['Article'], - ParentType, - ContextType, - RequireFields - > - emailLogin?: Resolver< - GQLResolversTypes['AuthResult'], - ParentType, - ContextType, - RequireFields - > - generateSigningMessage?: Resolver< - GQLResolversTypes['SigningMessageResult'], - ParentType, - ContextType, - RequireFields - > - invite?: Resolver< - Maybe>, - ParentType, - ContextType, - RequireFields - > - likeCollection?: Resolver< - GQLResolversTypes['Collection'], - ParentType, - ContextType, - RequireFields - > - likeMoment?: Resolver< - GQLResolversTypes['Moment'], - ParentType, - ContextType, - RequireFields - > - logRecord?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - > - markAllNoticesAsRead?: Resolver< - Maybe, - ParentType, - ContextType - > - mergeTags?: Resolver< - GQLResolversTypes['Tag'], - ParentType, - ContextType, - RequireFields - > - migration?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - > - payTo?: Resolver< - GQLResolversTypes['PayToResult'], - ParentType, - ContextType, - RequireFields - > - payout?: Resolver< - GQLResolversTypes['Transaction'], - ParentType, - ContextType, - RequireFields - > - pinComment?: Resolver< - GQLResolversTypes['Comment'], - ParentType, - ContextType, - RequireFields - > - publishArticle?: Resolver< - GQLResolversTypes['Draft'], - ParentType, - ContextType, - RequireFields - > - putAnnouncement?: Resolver< - GQLResolversTypes['Announcement'], - ParentType, - ContextType, - RequireFields - > - putArticleFederationSetting?: Resolver< - GQLResolversTypes['ArticleFederationSetting'], - ParentType, - ContextType, - RequireFields - > - putCircle?: Resolver< - GQLResolversTypes['Circle'], - ParentType, - ContextType, - RequireFields - > - putCircleArticles?: Resolver< - GQLResolversTypes['Circle'], - ParentType, - ContextType, - RequireFields - > - putCollection?: Resolver< - GQLResolversTypes['Collection'], - ParentType, - ContextType, - RequireFields - > - putComment?: Resolver< - GQLResolversTypes['Comment'], - ParentType, - ContextType, - RequireFields - > - putCurationChannel?: Resolver< - GQLResolversTypes['CurationChannel'], - ParentType, - ContextType, - RequireFields - > - putDraft?: Resolver< - GQLResolversTypes['Draft'], - ParentType, - ContextType, - RequireFields - > - putFeaturedTags?: Resolver< - Maybe>, - ParentType, - ContextType, - RequireFields - > - putIcymiTopic?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - > - putMoment?: Resolver< - GQLResolversTypes['Moment'], - ParentType, - ContextType, - RequireFields - > - putOAuthClient?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - > - putRemark?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - > - putRestrictedUsers?: Resolver< - Array, - ParentType, - ContextType, - RequireFields - > - putSkippedListItem?: Resolver< - Maybe>, - ParentType, - ContextType, - RequireFields - > - putTagChannel?: Resolver< - GQLResolversTypes['Tag'], - ParentType, - ContextType, - RequireFields - > - putTopicChannel?: Resolver< - GQLResolversTypes['TopicChannel'], - ParentType, - ContextType, - RequireFields - > - putUserFeatureFlags?: Resolver< - Array, - ParentType, - ContextType, - RequireFields - > - putUserFederationSetting?: Resolver< - GQLResolversTypes['UserFederationSetting'], - ParentType, - ContextType, - RequireFields - > - putWritingChallenge?: Resolver< - GQLResolversTypes['WritingChallenge'], - ParentType, - ContextType, - RequireFields - > - readArticle?: Resolver< - GQLResolversTypes['Article'], - ParentType, - ContextType, - RequireFields - > - removeSocialLogin?: Resolver< - GQLResolversTypes['User'], - ParentType, - ContextType, - RequireFields - > - removeWalletLogin?: Resolver< - GQLResolversTypes['User'], - ParentType, - ContextType - > - renameTag?: Resolver< - GQLResolversTypes['Tag'], - ParentType, - ContextType, - RequireFields - > - reorderChannels?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType, - RequireFields - > - reorderCollectionArticles?: Resolver< - GQLResolversTypes['Collection'], - ParentType, - ContextType, - RequireFields - > - resetLikerId?: Resolver< - GQLResolversTypes['User'], - ParentType, - ContextType, - RequireFields - > - resetPassword?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - > - restoreCommunityWatchComment?: Resolver< - GQLResolversTypes['CommunityWatchAction'], - ParentType, - ContextType, - RequireFields - > - reviewTopicChannelFeedback?: Resolver< - GQLResolversTypes['TopicChannelFeedback'], - ParentType, - ContextType, - RequireFields - > - sendCampaignAnnouncement?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - > - sendVerificationCode?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - > - setAdStatus?: Resolver< - GQLResolversTypes['Article'], - ParentType, - ContextType, - RequireFields - > - setArticleFederationSetting?: Resolver< - GQLResolversTypes['ArticleFederationSetting'], - ParentType, - ContextType, - RequireFields - > - setArticleTopicChannels?: Resolver< - GQLResolversTypes['Article'], - ParentType, - ContextType, - RequireFields - > - setBoost?: Resolver< - GQLResolversTypes['Node'], - ParentType, - ContextType, - RequireFields - > - setCurrency?: Resolver< - GQLResolversTypes['User'], - ParentType, - ContextType, - RequireFields - > - setEmail?: Resolver< - GQLResolversTypes['User'], - ParentType, - ContextType, - RequireFields - > - setFeature?: Resolver< - GQLResolversTypes['Feature'], - ParentType, - ContextType, - RequireFields - > - setPassword?: Resolver< - GQLResolversTypes['User'], - ParentType, - ContextType, - RequireFields - > - setSpamStatus?: Resolver< - GQLResolversTypes['Writing'], - ParentType, - ContextType, - RequireFields - > - setUserName?: Resolver< - GQLResolversTypes['User'], - ParentType, - ContextType, - RequireFields - > - setViewerFederationSetting?: Resolver< - GQLResolversTypes['UserFederationSetting'], - ParentType, - ContextType, - RequireFields - > - setWritingAdStatus?: Resolver< - GQLResolversTypes['Writing'], - ParentType, - ContextType, - RequireFields - > - singleFileUpload?: Resolver< - GQLResolversTypes['Asset'], - ParentType, - ContextType, - RequireFields - > - socialLogin?: Resolver< - GQLResolversTypes['AuthResult'], - ParentType, - ContextType, - RequireFields - > - submitReport?: Resolver< - GQLResolversTypes['Report'], - ParentType, - ContextType, - RequireFields - > - submitTopicChannelFeedback?: Resolver< - GQLResolversTypes['TopicChannelFeedback'], - ParentType, - ContextType, - RequireFields - > - subscribeCircle?: Resolver< - GQLResolversTypes['SubscribeCircleResult'], - ParentType, - ContextType, - RequireFields - > - toggleArticleRecommend?: Resolver< - GQLResolversTypes['Article'], - ParentType, - ContextType, - RequireFields - > - toggleBlockUser?: Resolver< - GQLResolversTypes['User'], - ParentType, - ContextType, - RequireFields - > - toggleBookmarkArticle?: Resolver< - GQLResolversTypes['Article'], - ParentType, - ContextType, - RequireFields - > - toggleBookmarkTag?: Resolver< - GQLResolversTypes['Tag'], - ParentType, - ContextType, - RequireFields - > - toggleFollowCircle?: Resolver< - GQLResolversTypes['Circle'], - ParentType, - ContextType, - RequireFields - > - toggleFollowTag?: Resolver< - GQLResolversTypes['Tag'], - ParentType, - ContextType, - RequireFields - > - toggleFollowUser?: Resolver< - GQLResolversTypes['User'], - ParentType, - ContextType, - RequireFields - > - togglePinChannelArticles?: Resolver< - Array, - ParentType, - ContextType, - RequireFields - > - togglePinComment?: Resolver< - GQLResolversTypes['Comment'], - ParentType, - ContextType, - RequireFields - > - toggleSeedingUsers?: Resolver< - Array>, - ParentType, - ContextType, - RequireFields - > - toggleSubscribeArticle?: Resolver< - GQLResolversTypes['Article'], - ParentType, - ContextType, - RequireFields - > - toggleUsersBadge?: Resolver< - Array>, - ParentType, - ContextType, - RequireFields - > - toggleWritingChallengeFeaturedArticles?: Resolver< - GQLResolversTypes['Campaign'], - ParentType, - ContextType, - RequireFields< - GQLMutationToggleWritingChallengeFeaturedArticlesArgs, - 'input' - > - > - unbindLikerId?: Resolver< - GQLResolversTypes['User'], - ParentType, - ContextType, - RequireFields - > - unlikeCollection?: Resolver< - GQLResolversTypes['Collection'], - ParentType, - ContextType, - RequireFields - > - unlikeMoment?: Resolver< - GQLResolversTypes['Moment'], - ParentType, - ContextType, - RequireFields - > - unpinComment?: Resolver< - GQLResolversTypes['Comment'], - ParentType, - ContextType, - RequireFields - > - unsubscribeCircle?: Resolver< - GQLResolversTypes['Circle'], - ParentType, - ContextType, - RequireFields - > - unvoteComment?: Resolver< - GQLResolversTypes['Comment'], - ParentType, - ContextType, - RequireFields - > - updateArticleSensitive?: Resolver< - GQLResolversTypes['Article'], - ParentType, - ContextType, - RequireFields - > - updateArticleState?: Resolver< - GQLResolversTypes['Article'], - ParentType, - ContextType, - RequireFields - > - updateCampaignApplicationState?: Resolver< - GQLResolversTypes['Campaign'], - ParentType, - ContextType, - RequireFields - > - updateCommentsState?: Resolver< - Array, - ParentType, - ContextType, - RequireFields - > - updateCommunityWatchActionState?: Resolver< - GQLResolversTypes['CommunityWatchAction'], - ParentType, - ContextType, - RequireFields - > - updateMomentFeedApplicationState?: Resolver< - GQLResolversTypes['User'], - ParentType, - ContextType, - RequireFields - > - updateNotificationSetting?: Resolver< - GQLResolversTypes['User'], - ParentType, - ContextType, - RequireFields - > - updateUserExtra?: Resolver< - GQLResolversTypes['User'], - ParentType, - ContextType, - RequireFields - > - updateUserInfo?: Resolver< - GQLResolversTypes['User'], - ParentType, - ContextType, - RequireFields - > - updateUserRole?: Resolver< - GQLResolversTypes['User'], - ParentType, - ContextType, - RequireFields - > - updateUserState?: Resolver< - Maybe>, - ParentType, - ContextType, - RequireFields - > - userLogout?: Resolver - verifyEmail?: Resolver< - GQLResolversTypes['AuthResult'], - ParentType, - ContextType, - RequireFields - > - voteComment?: Resolver< - GQLResolversTypes['Comment'], - ParentType, - ContextType, - RequireFields - > - walletLogin?: Resolver< - GQLResolversTypes['AuthResult'], - ParentType, - ContextType, - RequireFields - > - withdrawLockedTokens?: Resolver< - GQLResolversTypes['WithdrawLockedTokensResult'], - ParentType, - ContextType - > -}> - -export type GQLNftAssetResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['NFTAsset'] = GQLResolversParentTypes['NFTAsset'] -> = ResolversObject<{ - collectionName?: Resolver< - GQLResolversTypes['String'], - ParentType, - ContextType - > - contractAddress?: Resolver< - GQLResolversTypes['String'], - ParentType, - ContextType - > - description?: Resolver< - Maybe, - ParentType, - ContextType - > - id?: Resolver - imagePreviewUrl?: Resolver< - Maybe, - ParentType, - ContextType - > - imageUrl?: Resolver - name?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLNodeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Node'] = GQLResolversParentTypes['Node'] -> = ResolversObject<{ - __resolveType: TypeResolveFn< - | 'Article' - | 'ArticleVersion' - | 'Circle' - | 'Collection' - | 'Comment' - | 'CurationChannel' - | 'Draft' - | 'IcymiTopic' - | 'Moment' - | 'Report' - | 'Tag' - | 'TopicChannel' - | 'User' - | 'WritingChallenge', - ParentType, - ContextType - > -}> - -export type GQLNoticeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Notice'] = GQLResolversParentTypes['Notice'] -> = ResolversObject<{ - __resolveType: TypeResolveFn< - | 'ArticleArticleNotice' - | 'ArticleNotice' - | 'CampaignArticleNotice' - | 'CircleNotice' - | 'CollectionNotice' - | 'CommentCommentNotice' - | 'CommentNotice' - | 'MomentNotice' - | 'OfficialAnnouncementNotice' - | 'TransactionNotice' - | 'UserNotice', - ParentType, - ContextType - > -}> - -export type GQLNoticeConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['NoticeConnection'] = GQLResolversParentTypes['NoticeConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLNoticeEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['NoticeEdge'] = GQLResolversParentTypes['NoticeEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLNotificationSettingResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['NotificationSetting'] = GQLResolversParentTypes['NotificationSetting'] -> = ResolversObject<{ - articleNewAppreciation?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - articleNewCollected?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - articleNewComment?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - articleNewSubscription?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - circleMemberNewBroadcastReply?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - circleMemberNewDiscussion?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - circleMemberNewDiscussionReply?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - circleNewFollower?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - circleNewSubscriber?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - circleNewUnsubscriber?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - email?: Resolver - inCircleNewArticle?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - inCircleNewBroadcast?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - inCircleNewBroadcastReply?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - inCircleNewDiscussion?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - inCircleNewDiscussionReply?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - mention?: Resolver - newComment?: Resolver - newLike?: Resolver - userNewFollower?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLOAuthClientResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['OAuthClient'] = GQLResolversParentTypes['OAuthClient'] -> = ResolversObject<{ - avatar?: Resolver, ParentType, ContextType> - createdAt?: Resolver - description?: Resolver< - Maybe, - ParentType, - ContextType - > - grantTypes?: Resolver< - Maybe>, - ParentType, - ContextType - > - id?: Resolver - name?: Resolver - redirectURIs?: Resolver< - Maybe>, - ParentType, - ContextType - > - scope?: Resolver< - Maybe>, - ParentType, - ContextType - > - secret?: Resolver - user?: Resolver, ParentType, ContextType> - website?: Resolver< - Maybe, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLOAuthClientConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['OAuthClientConnection'] = GQLResolversParentTypes['OAuthClientConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLOAuthClientEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['OAuthClientEdge'] = GQLResolversParentTypes['OAuthClientEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLOssResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['OSS'] = GQLResolversParentTypes['OSS'] -> = ResolversObject<{ - articles?: Resolver< - GQLResolversTypes['ArticleConnection'], - ParentType, - ContextType, - RequireFields - > - badgedUsers?: Resolver< - GQLResolversTypes['UserConnection'], - ParentType, - ContextType, - RequireFields - > - comments?: Resolver< - GQLResolversTypes['CommentConnection'], - ParentType, - ContextType, - RequireFields - > - icymiTopics?: Resolver< - GQLResolversTypes['IcymiTopicConnection'], - ParentType, - ContextType, - RequireFields - > - momentFeedUsers?: Resolver< - GQLResolversTypes['UserConnection'], - ParentType, - ContextType, - RequireFields - > - moments?: Resolver< - GQLResolversTypes['MomentConnection'], - ParentType, - ContextType, - RequireFields - > - oauthClients?: Resolver< - GQLResolversTypes['OAuthClientConnection'], - ParentType, - ContextType, - RequireFields - > - reports?: Resolver< - GQLResolversTypes['ReportConnection'], - ParentType, - ContextType, - RequireFields - > - restrictedUsers?: Resolver< - GQLResolversTypes['UserConnection'], - ParentType, - ContextType, - RequireFields - > - seedingUsers?: Resolver< - GQLResolversTypes['UserConnection'], - ParentType, - ContextType, - RequireFields - > - skippedListItems?: Resolver< - GQLResolversTypes['SkippedListItemsConnection'], - ParentType, - ContextType, - RequireFields - > - tags?: Resolver< - GQLResolversTypes['TagConnection'], - ParentType, - ContextType, - RequireFields - > - topicChannelFeedbacks?: Resolver< - GQLResolversTypes['TopicChannelFeedbackConnection'], - ParentType, - ContextType, - RequireFields - > - users?: Resolver< - GQLResolversTypes['UserConnection'], - ParentType, - ContextType, - RequireFields - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLOfficialResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Official'] = GQLResolversParentTypes['Official'] -> = ResolversObject<{ - announcements?: Resolver< - Maybe>, - ParentType, - ContextType, - RequireFields - > - features?: Resolver< - Array, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLOfficialAnnouncementNoticeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['OfficialAnnouncementNotice'] = GQLResolversParentTypes['OfficialAnnouncementNotice'] -> = ResolversObject<{ - createdAt?: Resolver - id?: Resolver - link?: Resolver, ParentType, ContextType> - message?: Resolver - unread?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLPageInfoResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['PageInfo'] = GQLResolversParentTypes['PageInfo'] -> = ResolversObject<{ - endCursor?: Resolver< - Maybe, - ParentType, - ContextType - > - hasNextPage?: Resolver - hasPreviousPage?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - startCursor?: Resolver< - Maybe, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLPayToResultResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['PayToResult'] = GQLResolversParentTypes['PayToResult'] -> = ResolversObject<{ - redirectUrl?: Resolver< - Maybe, - ParentType, - ContextType - > - transaction?: Resolver< - GQLResolversTypes['Transaction'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLPersonResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Person'] = GQLResolversParentTypes['Person'] -> = ResolversObject<{ - email?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLPersonhoodHandoffResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['PersonhoodHandoff'] = GQLResolversParentTypes['PersonhoodHandoff'] -> = ResolversObject<{ - expiresAt?: Resolver - token?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLPinHistoryResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['PinHistory'] = GQLResolversParentTypes['PinHistory'] -> = ResolversObject<{ - feed?: Resolver - pinnedAt?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLPinnableWorkResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['PinnableWork'] = GQLResolversParentTypes['PinnableWork'] -> = ResolversObject<{ - __resolveType: TypeResolveFn< - 'Article' | 'Collection', - ParentType, - ContextType - > -}> - -export type GQLPriceResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Price'] = GQLResolversParentTypes['Price'] -> = ResolversObject<{ - amount?: Resolver - circle?: Resolver - createdAt?: Resolver - currency?: Resolver< - GQLResolversTypes['TransactionCurrency'], - ParentType, - ContextType - > - id?: Resolver - state?: Resolver - updatedAt?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLQueryResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Query'] = GQLResolversParentTypes['Query'] -> = ResolversObject<{ - article?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - > - campaign?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - > - campaignOrganizers?: Resolver< - GQLResolversTypes['UserConnection'], - ParentType, - ContextType, - RequireFields - > - campaigns?: Resolver< - GQLResolversTypes['CampaignConnection'], - ParentType, - ContextType, - RequireFields - > - channel?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - > - channels?: Resolver< - Array, - ParentType, - ContextType, - Partial - > - circle?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - > - communityWatchAction?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - > - communityWatchActions?: Resolver< - GQLResolversTypes['CommunityWatchActionConnection'], - ParentType, - ContextType, - RequireFields - > - exchangeRates?: Resolver< - Maybe>, - ParentType, - ContextType, - Partial - > - frequentSearch?: Resolver< - Maybe>, - ParentType, - ContextType, - RequireFields - > - moment?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - > - node?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - > - nodes?: Resolver< - Maybe>, - ParentType, - ContextType, - RequireFields - > - oauthClient?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - > - oauthRequestToken?: Resolver< - Maybe, - ParentType, - ContextType - > - official?: Resolver - oss?: Resolver - search?: Resolver< - GQLResolversTypes['SearchResultConnection'], - ParentType, - ContextType, - RequireFields - > - user?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - > - viewer?: Resolver, ParentType, ContextType> -}> - -export type GQLReadHistoryResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ReadHistory'] = GQLResolversParentTypes['ReadHistory'] -> = ResolversObject<{ - article?: Resolver - readAt?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLReadHistoryConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ReadHistoryConnection'] = GQLResolversParentTypes['ReadHistoryConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLReadHistoryEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ReadHistoryEdge'] = GQLResolversParentTypes['ReadHistoryEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLRecentSearchConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['RecentSearchConnection'] = GQLResolversParentTypes['RecentSearchConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLRecentSearchEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['RecentSearchEdge'] = GQLResolversParentTypes['RecentSearchEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLRecommendationResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Recommendation'] = GQLResolversParentTypes['Recommendation'] -> = ResolversObject<{ - authors?: Resolver< - GQLResolversTypes['UserConnection'], - ParentType, - ContextType, - RequireFields - > - following?: Resolver< - GQLResolversTypes['FollowingActivityConnection'], - ParentType, - ContextType, - RequireFields - > - hottest?: Resolver< - GQLResolversTypes['ArticleConnection'], - ParentType, - ContextType, - RequireFields - > - hottestMoments?: Resolver< - GQLResolversTypes['MomentConnection'], - ParentType, - ContextType, - RequireFields - > - icymi?: Resolver< - GQLResolversTypes['ArticleConnection'], - ParentType, - ContextType, - RequireFields - > - icymiTopic?: Resolver< - Maybe, - ParentType, - ContextType - > - newest?: Resolver< - GQLResolversTypes['ArticleConnection'], - ParentType, - ContextType, - RequireFields - > - tags?: Resolver< - GQLResolversTypes['TagConnection'], - ParentType, - ContextType, - RequireFields - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLReportResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Report'] = GQLResolversParentTypes['Report'] -> = ResolversObject<{ - communityWatchAction?: Resolver< - Maybe, - ParentType, - ContextType - > - createdAt?: Resolver - id?: Resolver - reason?: Resolver - reporter?: Resolver - source?: Resolver - target?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLReportConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ReportConnection'] = GQLResolversParentTypes['ReportConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLReportEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ReportEdge'] = GQLResolversParentTypes['ReportEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLResponseResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Response'] = GQLResolversParentTypes['Response'] -> = ResolversObject<{ - __resolveType: TypeResolveFn<'Article' | 'Comment', ParentType, ContextType> -}> - -export type GQLResponseConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ResponseConnection'] = GQLResolversParentTypes['ResponseConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLResponseEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['ResponseEdge'] = GQLResolversParentTypes['ResponseEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLSearchResultConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['SearchResultConnection'] = GQLResolversParentTypes['SearchResultConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLSearchResultEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['SearchResultEdge'] = GQLResolversParentTypes['SearchResultEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLSigningMessageResultResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['SigningMessageResult'] = GQLResolversParentTypes['SigningMessageResult'] -> = ResolversObject<{ - createdAt?: Resolver - expiredAt?: Resolver - nonce?: Resolver - purpose?: Resolver< - GQLResolversTypes['SigningMessagePurpose'], - ParentType, - ContextType - > - signingMessage?: Resolver< - GQLResolversTypes['String'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLSkippedListItemResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['SkippedListItem'] = GQLResolversParentTypes['SkippedListItem'] -> = ResolversObject<{ - archived?: Resolver - createdAt?: Resolver - id?: Resolver - type?: Resolver< - GQLResolversTypes['SkippedListItemType'], - ParentType, - ContextType - > - updatedAt?: Resolver - uuid?: Resolver - value?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLSkippedListItemEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['SkippedListItemEdge'] = GQLResolversParentTypes['SkippedListItemEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver< - Maybe, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLSkippedListItemsConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['SkippedListItemsConnection'] = GQLResolversParentTypes['SkippedListItemsConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLSocialAccountResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['SocialAccount'] = GQLResolversParentTypes['SocialAccount'] -> = ResolversObject<{ - email?: Resolver, ParentType, ContextType> - type?: Resolver< - GQLResolversTypes['SocialAccountType'], - ParentType, - ContextType - > - userName?: Resolver< - Maybe, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLSpamStatusResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['SpamStatus'] = GQLResolversParentTypes['SpamStatus'] -> = ResolversObject<{ - isSpam?: Resolver< - Maybe, - ParentType, - ContextType - > - score?: Resolver, ParentType, ContextType> - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLStripeAccountResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['StripeAccount'] = GQLResolversParentTypes['StripeAccount'] -> = ResolversObject<{ - id?: Resolver - loginUrl?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLSubscribeCircleResultResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['SubscribeCircleResult'] = GQLResolversParentTypes['SubscribeCircleResult'] -> = ResolversObject<{ - circle?: Resolver - client_secret?: Resolver< - Maybe, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLTagResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Tag'] = GQLResolversParentTypes['Tag'] -> = ResolversObject<{ - articles?: Resolver< - GQLResolversTypes['ChannelArticleConnection'], - ParentType, - ContextType, - RequireFields - > - channelEnabled?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - content?: Resolver - createdAt?: Resolver - deleted?: Resolver - id?: Resolver - isFollower?: Resolver< - Maybe, - ParentType, - ContextType - > - navbarTitle?: Resolver< - GQLResolversTypes['String'], - ParentType, - ContextType, - Partial - > - numArticles?: Resolver - numAuthors?: Resolver - numMoments?: Resolver - oss?: Resolver - recommended?: Resolver< - GQLResolversTypes['TagConnection'], - ParentType, - ContextType, - RequireFields - > - recommendedAuthors?: Resolver< - GQLResolversTypes['UserConnection'], - ParentType, - ContextType, - RequireFields - > - remark?: Resolver, ParentType, ContextType> - shortHash?: Resolver - writings?: Resolver< - GQLResolversTypes['TagWritingConnection'], - ParentType, - ContextType, - RequireFields - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLTagConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['TagConnection'] = GQLResolversParentTypes['TagConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLTagEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['TagEdge'] = GQLResolversParentTypes['TagEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLTagOssResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['TagOSS'] = GQLResolversParentTypes['TagOSS'] -> = ResolversObject<{ - boost?: Resolver - score?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLTagWritingConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['TagWritingConnection'] = GQLResolversParentTypes['TagWritingConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLTagWritingEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['TagWritingEdge'] = GQLResolversParentTypes['TagWritingEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - pinned?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLTopDonatorConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['TopDonatorConnection'] = GQLResolversParentTypes['TopDonatorConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLTopDonatorEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['TopDonatorEdge'] = GQLResolversParentTypes['TopDonatorEdge'] -> = ResolversObject<{ - cursor?: Resolver - donationCount?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLTopicChannelResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['TopicChannel'] = GQLResolversParentTypes['TopicChannel'] -> = ResolversObject<{ - articles?: Resolver< - GQLResolversTypes['ChannelArticleConnection'], - ParentType, - ContextType, - RequireFields - > - enabled?: Resolver - id?: Resolver - name?: Resolver< - GQLResolversTypes['String'], - ParentType, - ContextType, - Partial - > - navbarTitle?: Resolver< - GQLResolversTypes['String'], - ParentType, - ContextType, - Partial - > - note?: Resolver< - Maybe, - ParentType, - ContextType, - Partial - > - parent?: Resolver< - Maybe, - ParentType, - ContextType - > - providerId?: Resolver< - Maybe, - ParentType, - ContextType - > - shortHash?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLTopicChannelClassificationResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['TopicChannelClassification'] = GQLResolversParentTypes['TopicChannelClassification'] -> = ResolversObject<{ - channels?: Resolver< - Maybe>, - ParentType, - ContextType - > - enabled?: Resolver - feedback?: Resolver< - Maybe, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLTopicChannelFeedbackResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['TopicChannelFeedback'] = GQLResolversParentTypes['TopicChannelFeedback'] -> = ResolversObject<{ - article?: Resolver - channels?: Resolver< - Maybe>, - ParentType, - ContextType - > - createdAt?: Resolver - id?: Resolver - state?: Resolver< - Maybe, - ParentType, - ContextType - > - type?: Resolver< - GQLResolversTypes['TopicChannelFeedbackType'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLTopicChannelFeedbackConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['TopicChannelFeedbackConnection'] = GQLResolversParentTypes['TopicChannelFeedbackConnection'] -> = ResolversObject<{ - edges?: Resolver< - Array, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLTopicChannelFeedbackEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['TopicChannelFeedbackEdge'] = GQLResolversParentTypes['TopicChannelFeedbackEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver< - GQLResolversTypes['TopicChannelFeedback'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLTransactionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Transaction'] = GQLResolversParentTypes['Transaction'] -> = ResolversObject<{ - amount?: Resolver - blockchainTx?: Resolver< - Maybe, - ParentType, - ContextType - > - createdAt?: Resolver - currency?: Resolver< - GQLResolversTypes['TransactionCurrency'], - ParentType, - ContextType - > - fee?: Resolver - id?: Resolver - message?: Resolver< - Maybe, - ParentType, - ContextType - > - purpose?: Resolver< - GQLResolversTypes['TransactionPurpose'], - ParentType, - ContextType - > - recipient?: Resolver< - Maybe, - ParentType, - ContextType - > - sender?: Resolver, ParentType, ContextType> - state?: Resolver< - GQLResolversTypes['TransactionState'], - ParentType, - ContextType - > - target?: Resolver< - Maybe, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLTransactionConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['TransactionConnection'] = GQLResolversParentTypes['TransactionConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLTransactionEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['TransactionEdge'] = GQLResolversParentTypes['TransactionEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLTransactionNoticeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['TransactionNotice'] = GQLResolversParentTypes['TransactionNotice'] -> = ResolversObject<{ - actors?: Resolver< - Maybe>, - ParentType, - ContextType - > - createdAt?: Resolver - id?: Resolver - target?: Resolver - type?: Resolver< - GQLResolversTypes['TransactionNoticeType'], - ParentType, - ContextType - > - unread?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLTransactionTargetResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['TransactionTarget'] = GQLResolversParentTypes['TransactionTarget'] -> = ResolversObject<{ - __resolveType: TypeResolveFn< - 'Article' | 'Circle' | 'Transaction', - ParentType, - ContextType - > -}> - -export type GQLTranslatedAnnouncementResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['TranslatedAnnouncement'] = GQLResolversParentTypes['TranslatedAnnouncement'] -> = ResolversObject<{ - content?: Resolver< - Maybe, - ParentType, - ContextType - > - cover?: Resolver, ParentType, ContextType> - language?: Resolver< - GQLResolversTypes['UserLanguage'], - ParentType, - ContextType - > - link?: Resolver, ParentType, ContextType> - title?: Resolver, ParentType, ContextType> - __isTypeOf?: IsTypeOfResolverFn -}> - -export interface GQLUploadScalarConfig - extends GraphQLScalarTypeConfig { - name: 'Upload' -} - -export type GQLUserResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['User'] = GQLResolversParentTypes['User'] -> = ResolversObject<{ - activity?: Resolver< - GQLResolversTypes['UserActivity'], - ParentType, - ContextType - > - analytics?: Resolver< - GQLResolversTypes['UserAnalytics'], - ParentType, - ContextType - > - articles?: Resolver< - GQLResolversTypes['ArticleConnection'], - ParentType, - ContextType, - RequireFields - > - avatar?: Resolver, ParentType, ContextType> - blockList?: Resolver< - GQLResolversTypes['UserConnection'], - ParentType, - ContextType, - RequireFields - > - bookmarkedArticles?: Resolver< - GQLResolversTypes['ArticleConnection'], - ParentType, - ContextType, - RequireFields - > - bookmarkedTags?: Resolver< - GQLResolversTypes['TagConnection'], - ParentType, - ContextType, - RequireFields - > - campaigns?: Resolver< - GQLResolversTypes['CampaignConnection'], - ParentType, - ContextType, - RequireFields - > - collections?: Resolver< - GQLResolversTypes['CollectionConnection'], - ParentType, - ContextType, - RequireFields - > - commentedArticles?: Resolver< - GQLResolversTypes['ArticleConnection'], - ParentType, - ContextType, - RequireFields - > - displayName?: Resolver< - Maybe, - ParentType, - ContextType - > - drafts?: Resolver< - GQLResolversTypes['DraftConnection'], - ParentType, - ContextType, - RequireFields - > - features?: Resolver< - GQLResolversTypes['UserFeatures'], - ParentType, - ContextType - > - federationSetting?: Resolver< - Maybe, - ParentType, - ContextType - > - followers?: Resolver< - GQLResolversTypes['UserConnection'], - ParentType, - ContextType, - RequireFields - > - following?: Resolver - id?: Resolver - info?: Resolver - isBlocked?: Resolver - isBlocking?: Resolver - isFollowee?: Resolver - isFollower?: Resolver - isMomentFeedApplied?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - latestWorks?: Resolver< - Array, - ParentType, - ContextType - > - liker?: Resolver - likerId?: Resolver< - Maybe, - ParentType, - ContextType - > - notices?: Resolver< - GQLResolversTypes['NoticeConnection'], - ParentType, - ContextType, - RequireFields - > - oss?: Resolver - ownCircles?: Resolver< - Maybe>, - ParentType, - ContextType - > - paymentPointer?: Resolver< - Maybe, - ParentType, - ContextType - > - pinnedWorks?: Resolver< - Array, - ParentType, - ContextType - > - recommendation?: Resolver< - GQLResolversTypes['Recommendation'], - ParentType, - ContextType - > - remark?: Resolver, ParentType, ContextType> - settings?: Resolver< - GQLResolversTypes['UserSettings'], - ParentType, - ContextType - > - status?: Resolver< - Maybe, - ParentType, - ContextType - > - subscribedCircles?: Resolver< - GQLResolversTypes['CircleConnection'], - ParentType, - ContextType, - RequireFields - > - tags?: Resolver< - GQLResolversTypes['TagConnection'], - ParentType, - ContextType, - RequireFields - > - userName?: Resolver< - Maybe, - ParentType, - ContextType - > - wallet?: Resolver - writings?: Resolver< - GQLResolversTypes['WritingConnection'], - ParentType, - ContextType, - RequireFields - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLUserActivityResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['UserActivity'] = GQLResolversParentTypes['UserActivity'] -> = ResolversObject<{ - appreciationsReceived?: Resolver< - GQLResolversTypes['AppreciationConnection'], - ParentType, - ContextType, - RequireFields - > - appreciationsReceivedTotal?: Resolver< - GQLResolversTypes['Int'], - ParentType, - ContextType - > - appreciationsSent?: Resolver< - GQLResolversTypes['AppreciationConnection'], - ParentType, - ContextType, - RequireFields - > - appreciationsSentTotal?: Resolver< - GQLResolversTypes['Int'], - ParentType, - ContextType - > - history?: Resolver< - GQLResolversTypes['ReadHistoryConnection'], - ParentType, - ContextType, - RequireFields - > - recentSearches?: Resolver< - GQLResolversTypes['RecentSearchConnection'], - ParentType, - ContextType, - RequireFields - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLUserAddArticleTagActivityResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['UserAddArticleTagActivity'] = GQLResolversParentTypes['UserAddArticleTagActivity'] -> = ResolversObject<{ - actor?: Resolver - createdAt?: Resolver - node?: Resolver - target?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLUserAnalyticsResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['UserAnalytics'] = GQLResolversParentTypes['UserAnalytics'] -> = ResolversObject<{ - topDonators?: Resolver< - GQLResolversTypes['TopDonatorConnection'], - ParentType, - ContextType, - RequireFields - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLUserBroadcastCircleActivityResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['UserBroadcastCircleActivity'] = GQLResolversParentTypes['UserBroadcastCircleActivity'] -> = ResolversObject<{ - actor?: Resolver - createdAt?: Resolver - node?: Resolver - target?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLUserConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['UserConnection'] = GQLResolversParentTypes['UserConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLUserCreateCircleActivityResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['UserCreateCircleActivity'] = GQLResolversParentTypes['UserCreateCircleActivity'] -> = ResolversObject<{ - actor?: Resolver - createdAt?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLUserEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['UserEdge'] = GQLResolversParentTypes['UserEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLUserFeatureFlagResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['UserFeatureFlag'] = GQLResolversParentTypes['UserFeatureFlag'] -> = ResolversObject<{ - createdAt?: Resolver - type?: Resolver< - GQLResolversTypes['UserFeatureFlagType'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLUserFeaturesResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['UserFeatures'] = GQLResolversParentTypes['UserFeatures'] -> = ResolversObject<{ - communityWatch?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - fediverseBeta?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLUserFederationSettingResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['UserFederationSetting'] = GQLResolversParentTypes['UserFederationSetting'] -> = ResolversObject<{ - state?: Resolver< - GQLResolversTypes['FederationAuthorSettingState'], - ParentType, - ContextType - > - updatedBy?: Resolver, ParentType, ContextType> - userId?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLUserInfoResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['UserInfo'] = GQLResolversParentTypes['UserInfo'] -> = ResolversObject<{ - agreeOn?: Resolver< - Maybe, - ParentType, - ContextType - > - badges?: Resolver< - Maybe>, - ParentType, - ContextType - > - createdAt?: Resolver< - Maybe, - ParentType, - ContextType - > - cryptoWallet?: Resolver< - Maybe, - ParentType, - ContextType - > - description?: Resolver< - Maybe, - ParentType, - ContextType - > - email?: Resolver, ParentType, ContextType> - emailVerified?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - ethAddress?: Resolver< - Maybe, - ParentType, - ContextType - > - featuredTags?: Resolver< - Maybe>, - ParentType, - ContextType - > - group?: Resolver - ipnsKey?: Resolver< - Maybe, - ParentType, - ContextType - > - isWalletAuth?: Resolver - profileCover?: Resolver< - Maybe, - ParentType, - ContextType - > - socialAccounts?: Resolver< - Array, - ParentType, - ContextType - > - userNameEditable?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLUserNoticeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['UserNotice'] = GQLResolversParentTypes['UserNotice'] -> = ResolversObject<{ - actors?: Resolver< - Maybe>, - ParentType, - ContextType - > - createdAt?: Resolver - id?: Resolver - target?: Resolver - type?: Resolver - unread?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLUserOssResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['UserOSS'] = GQLResolversParentTypes['UserOSS'] -> = ResolversObject<{ - boost?: Resolver - featureFlags?: Resolver< - Array, - ParentType, - ContextType - > - momentFeedApplication?: Resolver< - Maybe, - ParentType, - ContextType - > - restrictions?: Resolver< - Array, - ParentType, - ContextType - > - score?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLUserPostMomentActivityResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['UserPostMomentActivity'] = GQLResolversParentTypes['UserPostMomentActivity'] -> = ResolversObject<{ - actor?: Resolver - createdAt?: Resolver - more?: Resolver, ParentType, ContextType> - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLUserPublishArticleActivityResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['UserPublishArticleActivity'] = GQLResolversParentTypes['UserPublishArticleActivity'] -> = ResolversObject<{ - actor?: Resolver - createdAt?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLUserRecommendationActivityResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['UserRecommendationActivity'] = GQLResolversParentTypes['UserRecommendationActivity'] -> = ResolversObject<{ - nodes?: Resolver< - Maybe>, - ParentType, - ContextType - > - source?: Resolver< - Maybe, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLUserRestrictionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['UserRestriction'] = GQLResolversParentTypes['UserRestriction'] -> = ResolversObject<{ - createdAt?: Resolver - type?: Resolver< - GQLResolversTypes['UserRestrictionType'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLUserSettingsResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['UserSettings'] = GQLResolversParentTypes['UserSettings'] -> = ResolversObject<{ - currency?: Resolver< - GQLResolversTypes['QuoteCurrency'], - ParentType, - ContextType - > - language?: Resolver< - GQLResolversTypes['UserLanguage'], - ParentType, - ContextType - > - notification?: Resolver< - Maybe, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLUserStatusResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['UserStatus'] = GQLResolversParentTypes['UserStatus'] -> = ResolversObject<{ - articleCount?: Resolver - changeEmailTimesLeft?: Resolver< - GQLResolversTypes['Int'], - ParentType, - ContextType - > - commentCount?: Resolver - donatedArticleCount?: Resolver< - GQLResolversTypes['Int'], - ParentType, - ContextType - > - hasEmailLoginPassword?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - hasPaymentPassword?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - momentCount?: Resolver - receivedDonationCount?: Resolver< - GQLResolversTypes['Int'], - ParentType, - ContextType - > - role?: Resolver - state?: Resolver - totalReferredCount?: Resolver< - GQLResolversTypes['Int'], - ParentType, - ContextType - > - totalWordCount?: Resolver - unreadFollowing?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - unreadNoticeCount?: Resolver< - GQLResolversTypes['Int'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLWalletResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Wallet'] = GQLResolversParentTypes['Wallet'] -> = ResolversObject<{ - balance?: Resolver - cardLast4?: Resolver< - Maybe, - ParentType, - ContextType - > - customerPortal?: Resolver< - Maybe, - ParentType, - ContextType - > - stripeAccount?: Resolver< - Maybe, - ParentType, - ContextType - > - transactions?: Resolver< - GQLResolversTypes['TransactionConnection'], - ParentType, - ContextType, - RequireFields - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLWithdrawLockedTokensResultResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['WithdrawLockedTokensResult'] = GQLResolversParentTypes['WithdrawLockedTokensResult'] -> = ResolversObject<{ - transaction?: Resolver< - GQLResolversTypes['Transaction'], - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLWritingResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['Writing'] = GQLResolversParentTypes['Writing'] -> = ResolversObject<{ - __resolveType: TypeResolveFn< - 'Article' | 'Comment' | 'Moment', - ParentType, - ContextType - > -}> - -export type GQLWritingChallengeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['WritingChallenge'] = GQLResolversParentTypes['WritingChallenge'] -> = ResolversObject<{ - announcements?: Resolver< - Array, - ParentType, - ContextType - > - application?: Resolver< - Maybe, - ParentType, - ContextType - > - applicationPeriod?: Resolver< - Maybe, - ParentType, - ContextType - > - articles?: Resolver< - GQLResolversTypes['CampaignArticleConnection'], - ParentType, - ContextType, - RequireFields - > - channelEnabled?: Resolver< - GQLResolversTypes['Boolean'], - ParentType, - ContextType - > - cover?: Resolver, ParentType, ContextType> - description?: Resolver< - Maybe, - ParentType, - ContextType, - Partial - > - featuredDescription?: Resolver< - GQLResolversTypes['String'], - ParentType, - ContextType, - Partial - > - id?: Resolver - isManager?: Resolver - link?: Resolver - name?: Resolver< - GQLResolversTypes['String'], - ParentType, - ContextType, - Partial - > - navbarTitle?: Resolver< - GQLResolversTypes['String'], - ParentType, - ContextType, - Partial - > - organizers?: Resolver< - Array, - ParentType, - ContextType - > - oss?: Resolver - participants?: Resolver< - GQLResolversTypes['CampaignParticipantConnection'], - ParentType, - ContextType, - RequireFields - > - shortHash?: Resolver - showAd?: Resolver - showOther?: Resolver - stages?: Resolver< - Array, - ParentType, - ContextType - > - state?: Resolver - writingPeriod?: Resolver< - Maybe, - ParentType, - ContextType - > - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLWritingConnectionResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['WritingConnection'] = GQLResolversParentTypes['WritingConnection'] -> = ResolversObject<{ - edges?: Resolver< - Maybe>, - ParentType, - ContextType - > - pageInfo?: Resolver - totalCount?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> - -export type GQLWritingEdgeResolvers< - ContextType = Context, - ParentType extends GQLResolversParentTypes['WritingEdge'] = GQLResolversParentTypes['WritingEdge'] -> = ResolversObject<{ - cursor?: Resolver - node?: Resolver - __isTypeOf?: IsTypeOfResolverFn -}> + ip?: Maybe; + limit: Scalars['Int']['input']; + period: Scalars['Int']['input']; +}; + +export type GQLRateLimitDirectiveResolver = DirectiveResolverFn; + +export type GQLAdStatusResolvers = ResolversObject<{ + isAd?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLAddCreditResultResolvers = ResolversObject<{ + client_secret?: Resolver; + transaction?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLAnnouncementResolvers = ResolversObject<{ + channels?: Resolver, ParentType, ContextType>; + content?: Resolver, ParentType, ContextType, Partial>; + cover?: Resolver, ParentType, ContextType>; + createdAt?: Resolver; + expiredAt?: Resolver, ParentType, ContextType>; + id?: Resolver; + link?: Resolver, ParentType, ContextType, Partial>; + order?: Resolver; + title?: Resolver, ParentType, ContextType, Partial>; + translations?: Resolver>, ParentType, ContextType>; + type?: Resolver; + updatedAt?: Resolver; + visible?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLAnnouncementChannelResolvers = ResolversObject<{ + channel?: Resolver; + order?: Resolver; + visible?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLAppreciationResolvers = ResolversObject<{ + amount?: Resolver; + content?: Resolver; + createdAt?: Resolver; + purpose?: Resolver; + recipient?: Resolver; + sender?: Resolver, ParentType, ContextType>; + target?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLAppreciationConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLAppreciationEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArchiveUserFailureResolvers = ResolversObject<{ + id?: Resolver; + message?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArchiveUsersResultResolvers = ResolversObject<{ + archived?: Resolver, ParentType, ContextType>; + skipped?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleResolvers = ResolversObject<{ + access?: Resolver; + appreciateLeft?: Resolver; + appreciateLimit?: Resolver; + appreciationsReceived?: Resolver>; + appreciationsReceivedTotal?: Resolver; + assets?: Resolver, ParentType, ContextType>; + author?: Resolver; + availableTranslations?: Resolver>, ParentType, ContextType>; + bookmarkCount?: Resolver; + bookmarked?: Resolver; + campaigns?: Resolver, ParentType, ContextType>; + canComment?: Resolver; + canSuperLike?: Resolver; + classification?: Resolver; + collection?: Resolver>; + collections?: Resolver>; + commentCount?: Resolver; + comments?: Resolver>; + connectedBy?: Resolver>; + connections?: Resolver>; + content?: Resolver; + contents?: Resolver; + cover?: Resolver, ParentType, ContextType>; + createdAt?: Resolver; + dataHash?: Resolver; + displayCover?: Resolver, ParentType, ContextType>; + donated?: Resolver; + donationCount?: Resolver; + donations?: Resolver>; + featuredComments?: Resolver>; + federationEligibility?: Resolver; + federationSetting?: Resolver, ParentType, ContextType>; + hasAppreciate?: Resolver; + id?: Resolver; + indentFirstLine?: Resolver; + iscnId?: Resolver, ParentType, ContextType>; + language?: Resolver, ParentType, ContextType>; + license?: Resolver; + mediaHash?: Resolver; + noindex?: Resolver; + oss?: Resolver; + pinCommentLeft?: Resolver; + pinCommentLimit?: Resolver; + pinned?: Resolver; + pinnedComments?: Resolver>, ParentType, ContextType>; + readTime?: Resolver; + readerCount?: Resolver; + relatedArticles?: Resolver>; + relatedDonationArticles?: Resolver>; + remark?: Resolver, ParentType, ContextType>; + replyToDonator?: Resolver, ParentType, ContextType>; + requestForDonation?: Resolver, ParentType, ContextType>; + responseCount?: Resolver; + responses?: Resolver>; + revisedAt?: Resolver, ParentType, ContextType>; + revisionCount?: Resolver; + sensitiveByAdmin?: Resolver; + sensitiveByAuthor?: Resolver; + shortHash?: Resolver; + slug?: Resolver; + state?: Resolver; + subscribed?: Resolver; + summary?: Resolver; + summaryCustomized?: Resolver; + tags?: Resolver>, ParentType, ContextType>; + title?: Resolver; + transactionsReceivedBy?: Resolver>; + translation?: Resolver, ParentType, ContextType, Partial>; + versions?: Resolver>; + wordCount?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleAccessResolvers = ResolversObject<{ + circle?: Resolver, ParentType, ContextType>; + secret?: Resolver, ParentType, ContextType>; + type?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleArticleNoticeResolvers = ResolversObject<{ + actors?: Resolver>, ParentType, ContextType>; + article?: Resolver; + createdAt?: Resolver; + id?: Resolver; + target?: Resolver; + type?: Resolver; + unread?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleCampaignResolvers = ResolversObject<{ + campaign?: Resolver; + stage?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleClassificationResolvers = ResolversObject<{ + topicChannel?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleContentsResolvers = ResolversObject<{ + html?: Resolver; + markdown?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleDonationResolvers = ResolversObject<{ + id?: Resolver; + sender?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleDonationConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleDonationEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleFederationEligibilityResolvers = ResolversObject<{ + effectiveArticleSetting?: Resolver; + eligible?: Resolver; + reason?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleFederationSettingResolvers = ResolversObject<{ + articleId?: Resolver; + state?: Resolver; + updatedBy?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleNoticeResolvers = ResolversObject<{ + actors?: Resolver>, ParentType, ContextType>; + createdAt?: Resolver; + entities?: Resolver, ParentType, ContextType>; + id?: Resolver; + target?: Resolver; + type?: Resolver; + unread?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleOssResolvers = ResolversObject<{ + adStatus?: Resolver; + boost?: Resolver; + inRecommendHottest?: Resolver; + inRecommendIcymi?: Resolver; + inRecommendNewest?: Resolver; + inSearch?: Resolver; + pinHistory?: Resolver>, ParentType, ContextType>; + score?: Resolver; + spamStatus?: Resolver; + topicChannels?: Resolver>, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleRecommendationActivityResolvers = ResolversObject<{ + nodes?: Resolver>, ParentType, ContextType>; + source?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleTopicChannelResolvers = ResolversObject<{ + antiFlooded?: Resolver; + channel?: Resolver; + classicfiedAt?: Resolver; + enabled?: Resolver; + isLabeled?: Resolver; + pinned?: Resolver; + score?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleTranslationResolvers = ResolversObject<{ + content?: Resolver, ParentType, ContextType>; + language?: Resolver, ParentType, ContextType>; + model?: Resolver, ParentType, ContextType>; + summary?: Resolver, ParentType, ContextType>; + title?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleVersionResolvers = ResolversObject<{ + contents?: Resolver; + createdAt?: Resolver; + dataHash?: Resolver, ParentType, ContextType>; + description?: Resolver, ParentType, ContextType>; + id?: Resolver; + mediaHash?: Resolver, ParentType, ContextType>; + summary?: Resolver; + title?: Resolver; + translation?: Resolver, ParentType, ContextType, Partial>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleVersionEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLArticleVersionsConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLAssetResolvers = ResolversObject<{ + createdAt?: Resolver; + draft?: Resolver, ParentType, ContextType>; + id?: Resolver; + path?: Resolver; + type?: Resolver; + uploadURL?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLAuthResultResolvers = ResolversObject<{ + auth?: Resolver; + token?: Resolver, ParentType, ContextType>; + type?: Resolver; + user?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLBadgeResolvers = ResolversObject<{ + type?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLBalanceResolvers = ResolversObject<{ + HKD?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLBlockchainTransactionResolvers = ResolversObject<{ + chain?: Resolver; + txHash?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLBlockedSearchKeywordResolvers = ResolversObject<{ + createdAt?: Resolver; + id?: Resolver; + searchKey?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCampaignResolvers = ResolversObject<{ + __resolveType: TypeResolveFn<'WritingChallenge', ParentType, ContextType>; +}>; + +export type GQLCampaignApplicationResolvers = ResolversObject<{ + createdAt?: Resolver; + state?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCampaignArticleConnectionResolvers = ResolversObject<{ + edges?: Resolver, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCampaignArticleEdgeResolvers = ResolversObject<{ + announcement?: Resolver; + cursor?: Resolver; + featured?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCampaignArticleNoticeResolvers = ResolversObject<{ + actors?: Resolver>, ParentType, ContextType>; + article?: Resolver; + createdAt?: Resolver; + id?: Resolver; + target?: Resolver; + type?: Resolver; + unread?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCampaignConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCampaignEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCampaignOssResolvers = ResolversObject<{ + boost?: Resolver; + exclusive?: Resolver; + managers?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCampaignParticipantConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCampaignParticipantEdgeResolvers = ResolversObject<{ + application?: Resolver, ParentType, ContextType>; + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCampaignStageResolvers = ResolversObject<{ + description?: Resolver>; + id?: Resolver; + name?: Resolver>; + period?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLChannelResolvers = ResolversObject<{ + __resolveType: TypeResolveFn<'CurationChannel' | 'Tag' | 'TopicChannel' | 'WritingChallenge', ParentType, ContextType>; +}>; + +export type GQLChannelArticleConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLChannelArticleEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + pinned?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCircleResolvers = ResolversObject<{ + analytics?: Resolver; + avatar?: Resolver, ParentType, ContextType>; + broadcast?: Resolver>; + cover?: Resolver, ParentType, ContextType>; + createdAt?: Resolver; + description?: Resolver, ParentType, ContextType>; + discussion?: Resolver>; + discussionCount?: Resolver; + discussionThreadCount?: Resolver; + displayName?: Resolver; + followers?: Resolver>; + id?: Resolver; + invitedBy?: Resolver, ParentType, ContextType>; + invites?: Resolver; + isFollower?: Resolver; + isMember?: Resolver; + members?: Resolver>; + name?: Resolver; + owner?: Resolver; + pinnedBroadcast?: Resolver>, ParentType, ContextType>; + prices?: Resolver>, ParentType, ContextType>; + state?: Resolver; + updatedAt?: Resolver; + works?: Resolver>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCircleAnalyticsResolvers = ResolversObject<{ + content?: Resolver; + follower?: Resolver; + income?: Resolver; + subscriber?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCircleConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCircleContentAnalyticsResolvers = ResolversObject<{ + paywall?: Resolver>, ParentType, ContextType>; + public?: Resolver>, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCircleContentAnalyticsDatumResolvers = ResolversObject<{ + node?: Resolver; + readCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCircleEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCircleFollowerAnalyticsResolvers = ResolversObject<{ + current?: Resolver; + followerPercentage?: Resolver; + history?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCircleIncomeAnalyticsResolvers = ResolversObject<{ + history?: Resolver, ParentType, ContextType>; + nextMonth?: Resolver; + thisMonth?: Resolver; + total?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCircleNoticeResolvers = ResolversObject<{ + actors?: Resolver>, ParentType, ContextType>; + comments?: Resolver>, ParentType, ContextType>; + createdAt?: Resolver; + id?: Resolver; + mentions?: Resolver>, ParentType, ContextType>; + replies?: Resolver>, ParentType, ContextType>; + target?: Resolver; + type?: Resolver; + unread?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCircleRecommendationActivityResolvers = ResolversObject<{ + nodes?: Resolver>, ParentType, ContextType>; + source?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCircleSubscriberAnalyticsResolvers = ResolversObject<{ + currentInvitee?: Resolver; + currentSubscriber?: Resolver; + inviteeHistory?: Resolver, ParentType, ContextType>; + subscriberHistory?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLClaimLogbooksResultResolvers = ResolversObject<{ + ids?: Resolver>, ParentType, ContextType>; + txHash?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCollectionResolvers = ResolversObject<{ + articles?: Resolver>; + author?: Resolver; + contains?: Resolver>; + cover?: Resolver, ParentType, ContextType>; + description?: Resolver, ParentType, ContextType>; + id?: Resolver; + likeCount?: Resolver; + liked?: Resolver; + pinned?: Resolver; + title?: Resolver; + updatedAt?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCollectionConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCollectionEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCollectionNoticeResolvers = ResolversObject<{ + actors?: Resolver>, ParentType, ContextType>; + createdAt?: Resolver; + id?: Resolver; + target?: Resolver; + unread?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCommentResolvers = ResolversObject<{ + author?: Resolver; + comments?: Resolver>; + communityWatchAction?: Resolver, ParentType, ContextType>; + content?: Resolver, ParentType, ContextType>; + createdAt?: Resolver; + downvotes?: Resolver; + fromDonator?: Resolver; + id?: Resolver; + myVote?: Resolver, ParentType, ContextType>; + node?: Resolver; + parentComment?: Resolver, ParentType, ContextType>; + pinned?: Resolver; + remark?: Resolver, ParentType, ContextType>; + replyTo?: Resolver, ParentType, ContextType>; + spamStatus?: Resolver; + state?: Resolver; + type?: Resolver; + upvotes?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCommentCommentNoticeResolvers = ResolversObject<{ + actors?: Resolver>, ParentType, ContextType>; + comment?: Resolver; + createdAt?: Resolver; + id?: Resolver; + target?: Resolver; + type?: Resolver; + unread?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCommentConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCommentEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCommentNoticeResolvers = ResolversObject<{ + actors?: Resolver>, ParentType, ContextType>; + createdAt?: Resolver; + id?: Resolver; + target?: Resolver; + type?: Resolver; + unread?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCommunityWatchActionResolvers = ResolversObject<{ + actionState?: Resolver; + actorDisplayName?: Resolver; + appealState?: Resolver; + commentId?: Resolver; + contentCleared?: Resolver; + contentHash?: Resolver, ParentType, ContextType>; + createdAt?: Resolver; + originalContent?: Resolver, ParentType, ContextType>; + reason?: Resolver; + reportSynced?: Resolver; + reviewState?: Resolver; + sourceId?: Resolver; + sourceTitle?: Resolver; + sourceType?: Resolver; + sourceUrl?: Resolver, ParentType, ContextType>; + uuid?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCommunityWatchActionConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCommunityWatchActionEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLConnectStripeAccountResultResolvers = ResolversObject<{ + redirectUrl?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLConnectionResolvers = ResolversObject<{ + __resolveType: TypeResolveFn<'AppreciationConnection' | 'ArticleConnection' | 'ArticleVersionsConnection' | 'CampaignArticleConnection' | 'CampaignConnection' | 'CampaignParticipantConnection' | 'ChannelArticleConnection' | 'CircleConnection' | 'CollectionConnection' | 'CommentConnection' | 'CommunityWatchActionConnection' | 'DraftConnection' | 'FollowingActivityConnection' | 'IcymiTopicConnection' | 'InvitationConnection' | 'MemberConnection' | 'MomentConnection' | 'NoticeConnection' | 'OAuthClientConnection' | 'QuoteConnection' | 'ReadHistoryConnection' | 'RecentSearchConnection' | 'ReportConnection' | 'ResponseConnection' | 'SearchResultConnection' | 'SkippedListItemsConnection' | 'SpamRingConnection' | 'SpamRingMemberConnection' | 'TagConnection' | 'TagWritingConnection' | 'TopDonatorConnection' | 'TopicChannelFeedbackConnection' | 'TransactionConnection' | 'UserConnection' | 'WritingConnection', ParentType, ContextType>; +}>; + +export type GQLCryptoWalletResolvers = ResolversObject<{ + address?: Resolver; + hasNFTs?: Resolver; + id?: Resolver; + nfts?: Resolver>, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLCurationChannelResolvers = ResolversObject<{ + activePeriod?: Resolver; + articles?: Resolver>; + color?: Resolver; + id?: Resolver; + name?: Resolver>; + navbarTitle?: Resolver>; + note?: Resolver, ParentType, ContextType, Partial>; + pinAmount?: Resolver; + shortHash?: Resolver; + showRecommendation?: Resolver; + state?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export interface GQLDateTimeScalarConfig extends GraphQLScalarTypeConfig { + name: 'DateTime'; +} + +export type GQLDatetimeRangeResolvers = ResolversObject<{ + end?: Resolver, ParentType, ContextType>; + start?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLDonatorResolvers = ResolversObject<{ + __resolveType: TypeResolveFn<'CryptoWallet' | 'User', ParentType, ContextType>; +}>; + +export type GQLDraftResolvers = ResolversObject<{ + access?: Resolver; + article?: Resolver, ParentType, ContextType>; + assets?: Resolver, ParentType, ContextType>; + campaigns?: Resolver, ParentType, ContextType>; + canComment?: Resolver; + collection?: Resolver>; + collections?: Resolver>; + connections?: Resolver>; + content?: Resolver, ParentType, ContextType>; + cover?: Resolver, ParentType, ContextType>; + createdAt?: Resolver; + id?: Resolver; + indentFirstLine?: Resolver; + iscnPublish?: Resolver, ParentType, ContextType>; + license?: Resolver; + mediaHash?: Resolver, ParentType, ContextType>; + publishAt?: Resolver, ParentType, ContextType>; + publishState?: Resolver; + replyToDonator?: Resolver, ParentType, ContextType>; + requestForDonation?: Resolver, ParentType, ContextType>; + sensitiveByAuthor?: Resolver; + slug?: Resolver; + summary?: Resolver, ParentType, ContextType>; + summaryCustomized?: Resolver; + tags?: Resolver>, ParentType, ContextType>; + title?: Resolver, ParentType, ContextType>; + updatedAt?: Resolver; + wordCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLDraftAccessResolvers = ResolversObject<{ + circle?: Resolver, ParentType, ContextType>; + type?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLDraftConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLDraftEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLExchangeRateResolvers = ResolversObject<{ + from?: Resolver; + rate?: Resolver; + to?: Resolver; + updatedAt?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLFeatureResolvers = ResolversObject<{ + enabled?: Resolver; + name?: Resolver; + value?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLFollowingResolvers = ResolversObject<{ + circles?: Resolver>; + users?: Resolver>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLFollowingActivityResolvers = ResolversObject<{ + __resolveType: TypeResolveFn<'ArticleRecommendationActivity' | 'CircleRecommendationActivity' | 'UserAddArticleTagActivity' | 'UserBroadcastCircleActivity' | 'UserCreateCircleActivity' | 'UserPostMomentActivity' | 'UserPublishArticleActivity' | 'UserRecommendationActivity', ParentType, ContextType>; +}>; + +export type GQLFollowingActivityConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLFollowingActivityEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLFreezeSpamRingResultResolvers = ResolversObject<{ + frozen?: Resolver, ParentType, ContextType>; + ring?: Resolver; + skipped?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLIcymiTopicResolvers = ResolversObject<{ + archivedAt?: Resolver, ParentType, ContextType>; + articles?: Resolver, ParentType, ContextType>; + id?: Resolver; + note?: Resolver, ParentType, ContextType, Partial>; + pinAmount?: Resolver; + publishedAt?: Resolver, ParentType, ContextType>; + state?: Resolver; + title?: Resolver>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLIcymiTopicConnectionResolvers = ResolversObject<{ + edges?: Resolver, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLIcymiTopicEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLInvitationResolvers = ResolversObject<{ + acceptedAt?: Resolver, ParentType, ContextType>; + circle?: Resolver; + createdAt?: Resolver; + freePeriod?: Resolver; + id?: Resolver; + invitee?: Resolver; + inviter?: Resolver; + sentAt?: Resolver; + state?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLInvitationConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLInvitationEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLInviteeResolvers = ResolversObject<{ + __resolveType: TypeResolveFn<'Person' | 'User', ParentType, ContextType>; +}>; + +export type GQLInvitesResolvers = ResolversObject<{ + accepted?: Resolver>; + pending?: Resolver>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLLikerResolvers = ResolversObject<{ + civicLiker?: Resolver; + likerId?: Resolver, ParentType, ContextType>; + total?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLMemberResolvers = ResolversObject<{ + price?: Resolver; + user?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLMemberConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLMemberEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLMomentResolvers = ResolversObject<{ + adStatus?: Resolver; + articles?: Resolver, ParentType, ContextType>; + assets?: Resolver, ParentType, ContextType>; + author?: Resolver; + commentCount?: Resolver; + commentedFollowees?: Resolver, ParentType, ContextType>; + comments?: Resolver>; + content?: Resolver, ParentType, ContextType>; + createdAt?: Resolver; + id?: Resolver; + likeCount?: Resolver; + liked?: Resolver; + shortHash?: Resolver; + spamStatus?: Resolver; + state?: Resolver; + tags?: Resolver>, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLMomentConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLMomentEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLMomentFeedApplicationResolvers = ResolversObject<{ + createdAt?: Resolver; + reviewedBy?: Resolver, ParentType, ContextType>; + reviewer?: Resolver, ParentType, ContextType>; + state?: Resolver; + updatedAt?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLMomentNoticeResolvers = ResolversObject<{ + actors?: Resolver>, ParentType, ContextType>; + createdAt?: Resolver; + id?: Resolver; + target?: Resolver; + type?: Resolver; + unread?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLMonthlyDatumResolvers = ResolversObject<{ + date?: Resolver; + value?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLMutationResolvers = ResolversObject<{ + addBlockedSearchKeyword?: Resolver>; + addCollectionsArticles?: Resolver, ParentType, ContextType, RequireFields>; + addCredit?: Resolver>; + addCurationChannelArticles?: Resolver>; + addSocialLogin?: Resolver>; + addWalletLogin?: Resolver>; + applyCampaign?: Resolver>; + applyMomentFeed?: Resolver; + appreciateArticle?: Resolver>; + archiveUsers?: Resolver>; + banCampaignArticles?: Resolver>; + claimLogbooks?: Resolver>; + claimPersonhoodBadge?: Resolver>; + classifyArticlesChannels?: Resolver>; + clearCommunityWatchOriginalContent?: Resolver>; + clearReadHistory?: Resolver>; + clearSearchHistory?: Resolver, ParentType, ContextType>; + communityWatchRemoveComment?: Resolver>; + confirmVerificationCode?: Resolver>; + connectStripeAccount?: Resolver>; + createPersonhoodHandoff?: Resolver>; + deleteAnnouncements?: Resolver>; + deleteBlockedSearchKeywords?: Resolver, ParentType, ContextType, RequireFields>; + deleteCollectionArticles?: Resolver>; + deleteCollections?: Resolver>; + deleteComment?: Resolver>; + deleteCurationChannelArticles?: Resolver>; + deleteDraft?: Resolver, ParentType, ContextType, RequireFields>; + deleteMoment?: Resolver>; + deleteQuote?: Resolver>; + deleteTags?: Resolver, ParentType, ContextType, RequireFields>; + directImageUpload?: Resolver>; + dismissSpamRing?: Resolver>; + editArticle?: Resolver>; + emailLogin?: Resolver>; + freezeSpamRing?: Resolver>; + generateSigningMessage?: Resolver>; + invite?: Resolver>, ParentType, ContextType, RequireFields>; + likeCollection?: Resolver>; + likeMoment?: Resolver>; + logRecord?: Resolver, ParentType, ContextType, RequireFields>; + markAllNoticesAsRead?: Resolver, ParentType, ContextType>; + mergeTags?: Resolver>; + migration?: Resolver, ParentType, ContextType, RequireFields>; + payTo?: Resolver>; + payout?: Resolver>; + pinComment?: Resolver>; + publishArticle?: Resolver>; + putAnnouncement?: Resolver>; + putArticleFederationSetting?: Resolver>; + putCircle?: Resolver>; + putCircleArticles?: Resolver>; + putCollection?: Resolver>; + putComment?: Resolver>; + putCurationChannel?: Resolver>; + putDraft?: Resolver>; + putFeaturedTags?: Resolver>, ParentType, ContextType, RequireFields>; + putIcymiTopic?: Resolver, ParentType, ContextType, RequireFields>; + putMoment?: Resolver>; + putOAuthClient?: Resolver, ParentType, ContextType, RequireFields>; + putQuote?: Resolver>; + putRemark?: Resolver, ParentType, ContextType, RequireFields>; + putRestrictedUsers?: Resolver, ParentType, ContextType, RequireFields>; + putSkippedListItem?: Resolver>, ParentType, ContextType, RequireFields>; + putTagChannel?: Resolver>; + putTopicChannel?: Resolver>; + putUserFeatureFlags?: Resolver, ParentType, ContextType, RequireFields>; + putUserFederationSetting?: Resolver>; + putWritingChallenge?: Resolver>; + readArticle?: Resolver>; + removeSocialLogin?: Resolver>; + removeWalletLogin?: Resolver; + renameTag?: Resolver>; + reorderChannels?: Resolver>; + reorderCollectionArticles?: Resolver>; + resetLikerId?: Resolver>; + resetPassword?: Resolver, ParentType, ContextType, RequireFields>; + restoreCommunityWatchComment?: Resolver>; + reviewTopicChannelFeedback?: Resolver>; + sendCampaignAnnouncement?: Resolver, ParentType, ContextType, RequireFields>; + sendVerificationCode?: Resolver, ParentType, ContextType, RequireFields>; + setAdStatus?: Resolver>; + setArticleFederationSetting?: Resolver>; + setArticleTopicChannels?: Resolver>; + setBoost?: Resolver>; + setCurrency?: Resolver>; + setEmail?: Resolver>; + setFeature?: Resolver>; + setPassword?: Resolver>; + setSpamStatus?: Resolver>; + setUserName?: Resolver>; + setViewerFederationSetting?: Resolver>; + setWritingAdStatus?: Resolver>; + singleFileUpload?: Resolver>; + socialLogin?: Resolver>; + submitReport?: Resolver>; + submitTopicChannelFeedback?: Resolver>; + subscribeCircle?: Resolver>; + toggleArticleRecommend?: Resolver>; + toggleBlockUser?: Resolver>; + toggleBookmarkArticle?: Resolver>; + toggleBookmarkTag?: Resolver>; + toggleFollowCircle?: Resolver>; + toggleFollowTag?: Resolver>; + toggleFollowUser?: Resolver>; + togglePinChannelArticles?: Resolver, ParentType, ContextType, RequireFields>; + togglePinComment?: Resolver>; + toggleSeedingUsers?: Resolver>, ParentType, ContextType, RequireFields>; + toggleSubscribeArticle?: Resolver>; + toggleUsersBadge?: Resolver>, ParentType, ContextType, RequireFields>; + toggleWritingChallengeFeaturedArticles?: Resolver>; + unbindLikerId?: Resolver>; + unfreezeSpamRing?: Resolver>; + unlikeCollection?: Resolver>; + unlikeMoment?: Resolver>; + unpinComment?: Resolver>; + unsubscribeCircle?: Resolver>; + unvoteComment?: Resolver>; + updateArticleSensitive?: Resolver>; + updateArticleState?: Resolver>; + updateCampaignApplicationState?: Resolver>; + updateCommentsState?: Resolver, ParentType, ContextType, RequireFields>; + updateCommunityWatchActionState?: Resolver>; + updateMomentFeedApplicationState?: Resolver>; + updateNotificationSetting?: Resolver>; + updateUserExtra?: Resolver>; + updateUserInfo?: Resolver>; + updateUserRole?: Resolver>; + updateUserState?: Resolver>, ParentType, ContextType, RequireFields>; + upsertSpamRingCandidates?: Resolver>; + userLogout?: Resolver; + verifyEmail?: Resolver>; + voteComment?: Resolver>; + walletLogin?: Resolver>; + withdrawLockedTokens?: Resolver; +}>; + +export type GQLNftAssetResolvers = ResolversObject<{ + collectionName?: Resolver; + contractAddress?: Resolver; + description?: Resolver, ParentType, ContextType>; + id?: Resolver; + imagePreviewUrl?: Resolver, ParentType, ContextType>; + imageUrl?: Resolver; + name?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLNodeResolvers = ResolversObject<{ + __resolveType: TypeResolveFn<'Article' | 'ArticleVersion' | 'Circle' | 'Collection' | 'Comment' | 'CurationChannel' | 'Draft' | 'IcymiTopic' | 'Moment' | 'Report' | 'SpamRing' | 'Tag' | 'TopicChannel' | 'User' | 'WritingChallenge', ParentType, ContextType>; +}>; + +export type GQLNoticeResolvers = ResolversObject<{ + __resolveType: TypeResolveFn<'ArticleArticleNotice' | 'ArticleNotice' | 'CampaignArticleNotice' | 'CircleNotice' | 'CollectionNotice' | 'CommentCommentNotice' | 'CommentNotice' | 'MomentNotice' | 'OfficialAnnouncementNotice' | 'TransactionNotice' | 'UserNotice', ParentType, ContextType>; +}>; + +export type GQLNoticeConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLNoticeEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLNotificationSettingResolvers = ResolversObject<{ + articleNewAppreciation?: Resolver; + articleNewCollected?: Resolver; + articleNewComment?: Resolver; + articleNewSubscription?: Resolver; + circleMemberNewBroadcastReply?: Resolver; + circleMemberNewDiscussion?: Resolver; + circleMemberNewDiscussionReply?: Resolver; + circleNewFollower?: Resolver; + circleNewSubscriber?: Resolver; + circleNewUnsubscriber?: Resolver; + email?: Resolver; + inCircleNewArticle?: Resolver; + inCircleNewBroadcast?: Resolver; + inCircleNewBroadcastReply?: Resolver; + inCircleNewDiscussion?: Resolver; + inCircleNewDiscussionReply?: Resolver; + mention?: Resolver; + newComment?: Resolver; + newLike?: Resolver; + userNewFollower?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLOAuthClientResolvers = ResolversObject<{ + avatar?: Resolver, ParentType, ContextType>; + createdAt?: Resolver; + description?: Resolver, ParentType, ContextType>; + grantTypes?: Resolver>, ParentType, ContextType>; + id?: Resolver; + name?: Resolver; + redirectURIs?: Resolver>, ParentType, ContextType>; + scope?: Resolver>, ParentType, ContextType>; + secret?: Resolver; + user?: Resolver, ParentType, ContextType>; + website?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLOAuthClientConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLOAuthClientEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLOssResolvers = ResolversObject<{ + articles?: Resolver>; + badgedUsers?: Resolver>; + comments?: Resolver>; + icymiTopics?: Resolver>; + momentFeedUsers?: Resolver>; + moments?: Resolver>; + oauthClients?: Resolver>; + reports?: Resolver>; + restrictedUsers?: Resolver>; + seedingUsers?: Resolver>; + skippedListItems?: Resolver>; + spamRings?: Resolver>; + tags?: Resolver>; + topicChannelFeedbacks?: Resolver>; + users?: Resolver>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLOfficialResolvers = ResolversObject<{ + announcements?: Resolver>, ParentType, ContextType, RequireFields>; + features?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLOfficialAnnouncementNoticeResolvers = ResolversObject<{ + createdAt?: Resolver; + id?: Resolver; + link?: Resolver, ParentType, ContextType>; + message?: Resolver; + unread?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLPageInfoResolvers = ResolversObject<{ + endCursor?: Resolver, ParentType, ContextType>; + hasNextPage?: Resolver; + hasPreviousPage?: Resolver; + startCursor?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLPayToResultResolvers = ResolversObject<{ + redirectUrl?: Resolver, ParentType, ContextType>; + transaction?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLPersonResolvers = ResolversObject<{ + email?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLPersonhoodHandoffResolvers = ResolversObject<{ + expiresAt?: Resolver; + token?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLPinHistoryResolvers = ResolversObject<{ + feed?: Resolver; + pinnedAt?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLPinnableWorkResolvers = ResolversObject<{ + __resolveType: TypeResolveFn<'Article' | 'Collection', ParentType, ContextType>; +}>; + +export type GQLPriceResolvers = ResolversObject<{ + amount?: Resolver; + circle?: Resolver; + createdAt?: Resolver; + currency?: Resolver; + id?: Resolver; + state?: Resolver; + updatedAt?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLQueryResolvers = ResolversObject<{ + article?: Resolver, ParentType, ContextType, RequireFields>; + campaign?: Resolver, ParentType, ContextType, RequireFields>; + campaignOrganizers?: Resolver>; + campaigns?: Resolver>; + channel?: Resolver, ParentType, ContextType, RequireFields>; + channels?: Resolver, ParentType, ContextType, Partial>; + circle?: Resolver, ParentType, ContextType, RequireFields>; + communityWatchAction?: Resolver, ParentType, ContextType, RequireFields>; + communityWatchActions?: Resolver>; + exchangeRates?: Resolver>, ParentType, ContextType, Partial>; + frequentSearch?: Resolver>, ParentType, ContextType, RequireFields>; + moment?: Resolver, ParentType, ContextType, RequireFields>; + node?: Resolver, ParentType, ContextType, RequireFields>; + nodes?: Resolver>, ParentType, ContextType, RequireFields>; + oauthClient?: Resolver, ParentType, ContextType, RequireFields>; + oauthRequestToken?: Resolver, ParentType, ContextType>; + official?: Resolver; + oss?: Resolver; + search?: Resolver>; + user?: Resolver, ParentType, ContextType, RequireFields>; + viewer?: Resolver, ParentType, ContextType>; +}>; + +export type GQLQuoteResolvers = ResolversObject<{ + article?: Resolver; + content?: Resolver; + createdAt?: Resolver; + id?: Resolver; + poster?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLQuoteConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLQuoteEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLReadHistoryResolvers = ResolversObject<{ + article?: Resolver; + readAt?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLReadHistoryConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLReadHistoryEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLRecentSearchConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLRecentSearchEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLRecommendationResolvers = ResolversObject<{ + authors?: Resolver>; + following?: Resolver>; + hottest?: Resolver>; + hottestMoments?: Resolver>; + icymi?: Resolver>; + icymiTopic?: Resolver, ParentType, ContextType>; + newest?: Resolver>; + tags?: Resolver>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLReportResolvers = ResolversObject<{ + communityWatchAction?: Resolver, ParentType, ContextType>; + createdAt?: Resolver; + id?: Resolver; + reason?: Resolver; + reporter?: Resolver; + source?: Resolver; + target?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLReportConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLReportEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLResponseResolvers = ResolversObject<{ + __resolveType: TypeResolveFn<'Article' | 'Comment', ParentType, ContextType>; +}>; + +export type GQLResponseConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLResponseEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLSearchResultConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLSearchResultEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLSigningMessageResultResolvers = ResolversObject<{ + createdAt?: Resolver; + expiredAt?: Resolver; + nonce?: Resolver; + purpose?: Resolver; + signingMessage?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLSkippedListItemResolvers = ResolversObject<{ + archived?: Resolver; + createdAt?: Resolver; + id?: Resolver; + type?: Resolver; + updatedAt?: Resolver; + uuid?: Resolver; + value?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLSkippedListItemEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLSkippedListItemsConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLSocialAccountResolvers = ResolversObject<{ + email?: Resolver, ParentType, ContextType>; + type?: Resolver; + userName?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLSpamRingResolvers = ResolversObject<{ + detectedAt?: Resolver; + events?: Resolver, ParentType, ContextType>; + fingerprint?: Resolver; + firstSeenAt?: Resolver, ParentType, ContextType>; + frozenAt?: Resolver, ParentType, ContextType>; + frozenBy?: Resolver, ParentType, ContextType>; + id?: Resolver; + lastSeenAt?: Resolver, ParentType, ContextType>; + memberSample?: Resolver, ParentType, ContextType, Partial>; + members?: Resolver>; + nArticles?: Resolver; + nAuthors?: Resolver; + newAccountRatio?: Resolver, ParentType, ContextType>; + note?: Resolver, ParentType, ContextType>; + score?: Resolver, ParentType, ContextType>; + severity?: Resolver, ParentType, ContextType>; + signals?: Resolver; + status?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLSpamRingConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLSpamRingEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLSpamRingEventResolvers = ResolversObject<{ + action?: Resolver; + actor?: Resolver, ParentType, ContextType>; + createdAt?: Resolver; + detail?: Resolver, ParentType, ContextType>; + id?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLSpamRingMemberResolvers = ResolversObject<{ + bannedByThisRing?: Resolver; + createdAt?: Resolver; + id?: Resolver; + skipReason?: Resolver, ParentType, ContextType>; + status?: Resolver; + user?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLSpamRingMemberConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLSpamRingMemberEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLSpamRingSignalsResolvers = ResolversObject<{ + botUsernameRatio?: Resolver, ParentType, ContextType>; + contentModelMax?: Resolver, ParentType, ContextType>; + entityRingSize?: Resolver, ParentType, ContextType>; + nearDupRingSize?: Resolver, ParentType, ContextType>; + sampleBrands?: Resolver>, ParentType, ContextType>; + sampleCodes?: Resolver>, ParentType, ContextType>; + topEntity?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLSpamRingSkipResolvers = ResolversObject<{ + reason?: Resolver; + user?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLSpamStatusResolvers = ResolversObject<{ + isSpam?: Resolver, ParentType, ContextType>; + score?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLStripeAccountResolvers = ResolversObject<{ + id?: Resolver; + loginUrl?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLSubscribeCircleResultResolvers = ResolversObject<{ + circle?: Resolver; + client_secret?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLTagResolvers = ResolversObject<{ + articles?: Resolver>; + channelEnabled?: Resolver; + content?: Resolver; + createdAt?: Resolver; + deleted?: Resolver; + id?: Resolver; + isFollower?: Resolver, ParentType, ContextType>; + navbarTitle?: Resolver>; + numArticles?: Resolver; + numAuthors?: Resolver; + numMoments?: Resolver; + oss?: Resolver; + recommended?: Resolver>; + recommendedAuthors?: Resolver>; + remark?: Resolver, ParentType, ContextType>; + shortHash?: Resolver; + writings?: Resolver>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLTagConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLTagEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLTagOssResolvers = ResolversObject<{ + boost?: Resolver; + score?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLTagWritingConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLTagWritingEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + pinned?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLTopDonatorConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLTopDonatorEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + donationCount?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLTopicChannelResolvers = ResolversObject<{ + articles?: Resolver>; + enabled?: Resolver; + id?: Resolver; + name?: Resolver>; + navbarTitle?: Resolver>; + note?: Resolver, ParentType, ContextType, Partial>; + parent?: Resolver, ParentType, ContextType>; + providerId?: Resolver, ParentType, ContextType>; + shortHash?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLTopicChannelClassificationResolvers = ResolversObject<{ + channels?: Resolver>, ParentType, ContextType>; + enabled?: Resolver; + feedback?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLTopicChannelFeedbackResolvers = ResolversObject<{ + article?: Resolver; + channels?: Resolver>, ParentType, ContextType>; + createdAt?: Resolver; + id?: Resolver; + state?: Resolver, ParentType, ContextType>; + type?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLTopicChannelFeedbackConnectionResolvers = ResolversObject<{ + edges?: Resolver, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLTopicChannelFeedbackEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLTransactionResolvers = ResolversObject<{ + amount?: Resolver; + blockchainTx?: Resolver, ParentType, ContextType>; + createdAt?: Resolver; + currency?: Resolver; + fee?: Resolver; + id?: Resolver; + message?: Resolver, ParentType, ContextType>; + purpose?: Resolver; + recipient?: Resolver, ParentType, ContextType>; + sender?: Resolver, ParentType, ContextType>; + state?: Resolver; + target?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLTransactionConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLTransactionEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLTransactionNoticeResolvers = ResolversObject<{ + actors?: Resolver>, ParentType, ContextType>; + createdAt?: Resolver; + id?: Resolver; + target?: Resolver; + type?: Resolver; + unread?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLTransactionTargetResolvers = ResolversObject<{ + __resolveType: TypeResolveFn<'Article' | 'Circle' | 'Transaction', ParentType, ContextType>; +}>; + +export type GQLTranslatedAnnouncementResolvers = ResolversObject<{ + content?: Resolver, ParentType, ContextType>; + cover?: Resolver, ParentType, ContextType>; + language?: Resolver; + link?: Resolver, ParentType, ContextType>; + title?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUnfreezeSpamRingResultResolvers = ResolversObject<{ + ring?: Resolver; + skipped?: Resolver, ParentType, ContextType>; + unbanned?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export interface GQLUploadScalarConfig extends GraphQLScalarTypeConfig { + name: 'Upload'; +} + +export type GQLUpsertSpamRingCandidatesResultResolvers = ResolversObject<{ + created?: Resolver; + rings?: Resolver, ParentType, ContextType>; + skipped?: Resolver; + updated?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUserResolvers = ResolversObject<{ + activity?: Resolver; + analytics?: Resolver; + articles?: Resolver>; + avatar?: Resolver, ParentType, ContextType>; + blockList?: Resolver>; + bookmarkedArticles?: Resolver>; + bookmarkedTags?: Resolver>; + campaigns?: Resolver>; + collections?: Resolver>; + commentedArticles?: Resolver>; + displayName?: Resolver, ParentType, ContextType>; + drafts?: Resolver>; + features?: Resolver; + federationSetting?: Resolver, ParentType, ContextType>; + followers?: Resolver>; + following?: Resolver; + id?: Resolver; + info?: Resolver; + isBlocked?: Resolver; + isBlocking?: Resolver; + isFollowee?: Resolver; + isFollower?: Resolver; + isMomentFeedApplied?: Resolver; + latestWorks?: Resolver, ParentType, ContextType>; + liker?: Resolver; + likerId?: Resolver, ParentType, ContextType>; + notices?: Resolver>; + oss?: Resolver; + ownCircles?: Resolver>, ParentType, ContextType>; + paymentPointer?: Resolver, ParentType, ContextType>; + pinnedWorks?: Resolver, ParentType, ContextType>; + recommendation?: Resolver; + remark?: Resolver, ParentType, ContextType>; + settings?: Resolver; + status?: Resolver, ParentType, ContextType>; + subscribedCircles?: Resolver>; + tags?: Resolver>; + userName?: Resolver, ParentType, ContextType>; + wallet?: Resolver; + writings?: Resolver>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUserActivityResolvers = ResolversObject<{ + appreciationsReceived?: Resolver>; + appreciationsReceivedTotal?: Resolver; + appreciationsSent?: Resolver>; + appreciationsSentTotal?: Resolver; + history?: Resolver>; + recentSearches?: Resolver>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUserAddArticleTagActivityResolvers = ResolversObject<{ + actor?: Resolver; + createdAt?: Resolver; + node?: Resolver; + target?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUserAnalyticsResolvers = ResolversObject<{ + topDonators?: Resolver>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUserBroadcastCircleActivityResolvers = ResolversObject<{ + actor?: Resolver; + createdAt?: Resolver; + node?: Resolver; + target?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUserConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUserCreateCircleActivityResolvers = ResolversObject<{ + actor?: Resolver; + createdAt?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUserEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUserFeatureFlagResolvers = ResolversObject<{ + createdAt?: Resolver; + type?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUserFeaturesResolvers = ResolversObject<{ + communityWatch?: Resolver; + fediverseBeta?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUserFederationSettingResolvers = ResolversObject<{ + state?: Resolver; + updatedBy?: Resolver, ParentType, ContextType>; + userId?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUserInfoResolvers = ResolversObject<{ + agreeOn?: Resolver, ParentType, ContextType>; + badges?: Resolver>, ParentType, ContextType>; + createdAt?: Resolver, ParentType, ContextType>; + cryptoWallet?: Resolver, ParentType, ContextType>; + description?: Resolver, ParentType, ContextType>; + email?: Resolver, ParentType, ContextType>; + emailVerified?: Resolver; + ethAddress?: Resolver, ParentType, ContextType>; + featuredTags?: Resolver>, ParentType, ContextType>; + group?: Resolver; + ipnsKey?: Resolver, ParentType, ContextType>; + isWalletAuth?: Resolver; + profileCover?: Resolver, ParentType, ContextType>; + socialAccounts?: Resolver, ParentType, ContextType>; + userNameEditable?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUserNoticeResolvers = ResolversObject<{ + actors?: Resolver>, ParentType, ContextType>; + createdAt?: Resolver; + id?: Resolver; + target?: Resolver; + type?: Resolver; + unread?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUserOssResolvers = ResolversObject<{ + boost?: Resolver; + featureFlags?: Resolver, ParentType, ContextType>; + momentFeedApplication?: Resolver, ParentType, ContextType>; + restrictions?: Resolver, ParentType, ContextType>; + score?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUserPostMomentActivityResolvers = ResolversObject<{ + actor?: Resolver; + createdAt?: Resolver; + more?: Resolver, ParentType, ContextType>; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUserPublishArticleActivityResolvers = ResolversObject<{ + actor?: Resolver; + createdAt?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUserRecommendationActivityResolvers = ResolversObject<{ + nodes?: Resolver>, ParentType, ContextType>; + source?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUserRestrictionResolvers = ResolversObject<{ + createdAt?: Resolver; + type?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUserSettingsResolvers = ResolversObject<{ + currency?: Resolver; + language?: Resolver; + notification?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLUserStatusResolvers = ResolversObject<{ + articleCount?: Resolver; + changeEmailTimesLeft?: Resolver; + commentCount?: Resolver; + donatedArticleCount?: Resolver; + hasEmailLoginPassword?: Resolver; + hasPaymentPassword?: Resolver; + momentCount?: Resolver; + receivedDonationCount?: Resolver; + role?: Resolver; + state?: Resolver; + totalReferredCount?: Resolver; + totalWordCount?: Resolver; + unreadFollowing?: Resolver; + unreadNoticeCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLWalletResolvers = ResolversObject<{ + balance?: Resolver; + cardLast4?: Resolver, ParentType, ContextType>; + customerPortal?: Resolver, ParentType, ContextType>; + stripeAccount?: Resolver, ParentType, ContextType>; + transactions?: Resolver>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLWithdrawLockedTokensResultResolvers = ResolversObject<{ + transaction?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLWritingResolvers = ResolversObject<{ + __resolveType: TypeResolveFn<'Article' | 'Comment' | 'Moment', ParentType, ContextType>; +}>; + +export type GQLWritingChallengeResolvers = ResolversObject<{ + announcements?: Resolver, ParentType, ContextType>; + application?: Resolver, ParentType, ContextType>; + applicationPeriod?: Resolver, ParentType, ContextType>; + articles?: Resolver>; + channelEnabled?: Resolver; + cover?: Resolver, ParentType, ContextType>; + description?: Resolver, ParentType, ContextType, Partial>; + discussion?: Resolver>; + discussionCount?: Resolver; + enableQuoteWall?: Resolver; + featuredDescription?: Resolver>; + id?: Resolver; + isManager?: Resolver; + link?: Resolver; + name?: Resolver>; + navbarTitle?: Resolver>; + organizers?: Resolver, ParentType, ContextType>; + oss?: Resolver; + participants?: Resolver>; + quoteCount?: Resolver; + quotes?: Resolver>; + shortHash?: Resolver; + showAd?: Resolver; + showOther?: Resolver; + stages?: Resolver, ParentType, ContextType>; + state?: Resolver; + writingPeriod?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLWritingConnectionResolvers = ResolversObject<{ + edges?: Resolver>, ParentType, ContextType>; + pageInfo?: Resolver; + totalCount?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type GQLWritingEdgeResolvers = ResolversObject<{ + cursor?: Resolver; + node?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; export type GQLResolvers = ResolversObject<{ - AdStatus?: GQLAdStatusResolvers - AddCreditResult?: GQLAddCreditResultResolvers - Announcement?: GQLAnnouncementResolvers - AnnouncementChannel?: GQLAnnouncementChannelResolvers - Appreciation?: GQLAppreciationResolvers - AppreciationConnection?: GQLAppreciationConnectionResolvers - AppreciationEdge?: GQLAppreciationEdgeResolvers - ArchiveUserFailure?: GQLArchiveUserFailureResolvers - ArchiveUsersResult?: GQLArchiveUsersResultResolvers - Article?: GQLArticleResolvers - ArticleAccess?: GQLArticleAccessResolvers - ArticleArticleNotice?: GQLArticleArticleNoticeResolvers - ArticleCampaign?: GQLArticleCampaignResolvers - ArticleClassification?: GQLArticleClassificationResolvers - ArticleConnection?: GQLArticleConnectionResolvers - ArticleContents?: GQLArticleContentsResolvers - ArticleDonation?: GQLArticleDonationResolvers - ArticleDonationConnection?: GQLArticleDonationConnectionResolvers - ArticleDonationEdge?: GQLArticleDonationEdgeResolvers - ArticleEdge?: GQLArticleEdgeResolvers - ArticleFederationEligibility?: GQLArticleFederationEligibilityResolvers - ArticleFederationSetting?: GQLArticleFederationSettingResolvers - ArticleNotice?: GQLArticleNoticeResolvers - ArticleOSS?: GQLArticleOssResolvers - ArticleRecommendationActivity?: GQLArticleRecommendationActivityResolvers - ArticleTopicChannel?: GQLArticleTopicChannelResolvers - ArticleTranslation?: GQLArticleTranslationResolvers - ArticleVersion?: GQLArticleVersionResolvers - ArticleVersionEdge?: GQLArticleVersionEdgeResolvers - ArticleVersionsConnection?: GQLArticleVersionsConnectionResolvers - Asset?: GQLAssetResolvers - AuthResult?: GQLAuthResultResolvers - Badge?: GQLBadgeResolvers - Balance?: GQLBalanceResolvers - BlockchainTransaction?: GQLBlockchainTransactionResolvers - BlockedSearchKeyword?: GQLBlockedSearchKeywordResolvers - Campaign?: GQLCampaignResolvers - CampaignApplication?: GQLCampaignApplicationResolvers - CampaignArticleConnection?: GQLCampaignArticleConnectionResolvers - CampaignArticleEdge?: GQLCampaignArticleEdgeResolvers - CampaignArticleNotice?: GQLCampaignArticleNoticeResolvers - CampaignConnection?: GQLCampaignConnectionResolvers - CampaignEdge?: GQLCampaignEdgeResolvers - CampaignOSS?: GQLCampaignOssResolvers - CampaignParticipantConnection?: GQLCampaignParticipantConnectionResolvers - CampaignParticipantEdge?: GQLCampaignParticipantEdgeResolvers - CampaignStage?: GQLCampaignStageResolvers - Channel?: GQLChannelResolvers - ChannelArticleConnection?: GQLChannelArticleConnectionResolvers - ChannelArticleEdge?: GQLChannelArticleEdgeResolvers - Circle?: GQLCircleResolvers - CircleAnalytics?: GQLCircleAnalyticsResolvers - CircleConnection?: GQLCircleConnectionResolvers - CircleContentAnalytics?: GQLCircleContentAnalyticsResolvers - CircleContentAnalyticsDatum?: GQLCircleContentAnalyticsDatumResolvers - CircleEdge?: GQLCircleEdgeResolvers - CircleFollowerAnalytics?: GQLCircleFollowerAnalyticsResolvers - CircleIncomeAnalytics?: GQLCircleIncomeAnalyticsResolvers - CircleNotice?: GQLCircleNoticeResolvers - CircleRecommendationActivity?: GQLCircleRecommendationActivityResolvers - CircleSubscriberAnalytics?: GQLCircleSubscriberAnalyticsResolvers - ClaimLogbooksResult?: GQLClaimLogbooksResultResolvers - Collection?: GQLCollectionResolvers - CollectionConnection?: GQLCollectionConnectionResolvers - CollectionEdge?: GQLCollectionEdgeResolvers - CollectionNotice?: GQLCollectionNoticeResolvers - Comment?: GQLCommentResolvers - CommentCommentNotice?: GQLCommentCommentNoticeResolvers - CommentConnection?: GQLCommentConnectionResolvers - CommentEdge?: GQLCommentEdgeResolvers - CommentNotice?: GQLCommentNoticeResolvers - CommunityWatchAction?: GQLCommunityWatchActionResolvers - CommunityWatchActionConnection?: GQLCommunityWatchActionConnectionResolvers - CommunityWatchActionEdge?: GQLCommunityWatchActionEdgeResolvers - ConnectStripeAccountResult?: GQLConnectStripeAccountResultResolvers - Connection?: GQLConnectionResolvers - CryptoWallet?: GQLCryptoWalletResolvers - CurationChannel?: GQLCurationChannelResolvers - DateTime?: GraphQLScalarType - DatetimeRange?: GQLDatetimeRangeResolvers - Donator?: GQLDonatorResolvers - Draft?: GQLDraftResolvers - DraftAccess?: GQLDraftAccessResolvers - DraftConnection?: GQLDraftConnectionResolvers - DraftEdge?: GQLDraftEdgeResolvers - ExchangeRate?: GQLExchangeRateResolvers - Feature?: GQLFeatureResolvers - Following?: GQLFollowingResolvers - FollowingActivity?: GQLFollowingActivityResolvers - FollowingActivityConnection?: GQLFollowingActivityConnectionResolvers - FollowingActivityEdge?: GQLFollowingActivityEdgeResolvers - IcymiTopic?: GQLIcymiTopicResolvers - IcymiTopicConnection?: GQLIcymiTopicConnectionResolvers - IcymiTopicEdge?: GQLIcymiTopicEdgeResolvers - Invitation?: GQLInvitationResolvers - InvitationConnection?: GQLInvitationConnectionResolvers - InvitationEdge?: GQLInvitationEdgeResolvers - Invitee?: GQLInviteeResolvers - Invites?: GQLInvitesResolvers - Liker?: GQLLikerResolvers - Member?: GQLMemberResolvers - MemberConnection?: GQLMemberConnectionResolvers - MemberEdge?: GQLMemberEdgeResolvers - Moment?: GQLMomentResolvers - MomentConnection?: GQLMomentConnectionResolvers - MomentEdge?: GQLMomentEdgeResolvers - MomentFeedApplication?: GQLMomentFeedApplicationResolvers - MomentNotice?: GQLMomentNoticeResolvers - MonthlyDatum?: GQLMonthlyDatumResolvers - Mutation?: GQLMutationResolvers - NFTAsset?: GQLNftAssetResolvers - Node?: GQLNodeResolvers - Notice?: GQLNoticeResolvers - NoticeConnection?: GQLNoticeConnectionResolvers - NoticeEdge?: GQLNoticeEdgeResolvers - NotificationSetting?: GQLNotificationSettingResolvers - OAuthClient?: GQLOAuthClientResolvers - OAuthClientConnection?: GQLOAuthClientConnectionResolvers - OAuthClientEdge?: GQLOAuthClientEdgeResolvers - OSS?: GQLOssResolvers - Official?: GQLOfficialResolvers - OfficialAnnouncementNotice?: GQLOfficialAnnouncementNoticeResolvers - PageInfo?: GQLPageInfoResolvers - PayToResult?: GQLPayToResultResolvers - Person?: GQLPersonResolvers - PersonhoodHandoff?: GQLPersonhoodHandoffResolvers - PinHistory?: GQLPinHistoryResolvers - PinnableWork?: GQLPinnableWorkResolvers - Price?: GQLPriceResolvers - Query?: GQLQueryResolvers - ReadHistory?: GQLReadHistoryResolvers - ReadHistoryConnection?: GQLReadHistoryConnectionResolvers - ReadHistoryEdge?: GQLReadHistoryEdgeResolvers - RecentSearchConnection?: GQLRecentSearchConnectionResolvers - RecentSearchEdge?: GQLRecentSearchEdgeResolvers - Recommendation?: GQLRecommendationResolvers - Report?: GQLReportResolvers - ReportConnection?: GQLReportConnectionResolvers - ReportEdge?: GQLReportEdgeResolvers - Response?: GQLResponseResolvers - ResponseConnection?: GQLResponseConnectionResolvers - ResponseEdge?: GQLResponseEdgeResolvers - SearchResultConnection?: GQLSearchResultConnectionResolvers - SearchResultEdge?: GQLSearchResultEdgeResolvers - SigningMessageResult?: GQLSigningMessageResultResolvers - SkippedListItem?: GQLSkippedListItemResolvers - SkippedListItemEdge?: GQLSkippedListItemEdgeResolvers - SkippedListItemsConnection?: GQLSkippedListItemsConnectionResolvers - SocialAccount?: GQLSocialAccountResolvers - SpamStatus?: GQLSpamStatusResolvers - StripeAccount?: GQLStripeAccountResolvers - SubscribeCircleResult?: GQLSubscribeCircleResultResolvers - Tag?: GQLTagResolvers - TagConnection?: GQLTagConnectionResolvers - TagEdge?: GQLTagEdgeResolvers - TagOSS?: GQLTagOssResolvers - TagWritingConnection?: GQLTagWritingConnectionResolvers - TagWritingEdge?: GQLTagWritingEdgeResolvers - TopDonatorConnection?: GQLTopDonatorConnectionResolvers - TopDonatorEdge?: GQLTopDonatorEdgeResolvers - TopicChannel?: GQLTopicChannelResolvers - TopicChannelClassification?: GQLTopicChannelClassificationResolvers - TopicChannelFeedback?: GQLTopicChannelFeedbackResolvers - TopicChannelFeedbackConnection?: GQLTopicChannelFeedbackConnectionResolvers - TopicChannelFeedbackEdge?: GQLTopicChannelFeedbackEdgeResolvers - Transaction?: GQLTransactionResolvers - TransactionConnection?: GQLTransactionConnectionResolvers - TransactionEdge?: GQLTransactionEdgeResolvers - TransactionNotice?: GQLTransactionNoticeResolvers - TransactionTarget?: GQLTransactionTargetResolvers - TranslatedAnnouncement?: GQLTranslatedAnnouncementResolvers - Upload?: GraphQLScalarType - User?: GQLUserResolvers - UserActivity?: GQLUserActivityResolvers - UserAddArticleTagActivity?: GQLUserAddArticleTagActivityResolvers - UserAnalytics?: GQLUserAnalyticsResolvers - UserBroadcastCircleActivity?: GQLUserBroadcastCircleActivityResolvers - UserConnection?: GQLUserConnectionResolvers - UserCreateCircleActivity?: GQLUserCreateCircleActivityResolvers - UserEdge?: GQLUserEdgeResolvers - UserFeatureFlag?: GQLUserFeatureFlagResolvers - UserFeatures?: GQLUserFeaturesResolvers - UserFederationSetting?: GQLUserFederationSettingResolvers - UserInfo?: GQLUserInfoResolvers - UserNotice?: GQLUserNoticeResolvers - UserOSS?: GQLUserOssResolvers - UserPostMomentActivity?: GQLUserPostMomentActivityResolvers - UserPublishArticleActivity?: GQLUserPublishArticleActivityResolvers - UserRecommendationActivity?: GQLUserRecommendationActivityResolvers - UserRestriction?: GQLUserRestrictionResolvers - UserSettings?: GQLUserSettingsResolvers - UserStatus?: GQLUserStatusResolvers - Wallet?: GQLWalletResolvers - WithdrawLockedTokensResult?: GQLWithdrawLockedTokensResultResolvers - Writing?: GQLWritingResolvers - WritingChallenge?: GQLWritingChallengeResolvers - WritingConnection?: GQLWritingConnectionResolvers - WritingEdge?: GQLWritingEdgeResolvers -}> + AdStatus?: GQLAdStatusResolvers; + AddCreditResult?: GQLAddCreditResultResolvers; + Announcement?: GQLAnnouncementResolvers; + AnnouncementChannel?: GQLAnnouncementChannelResolvers; + Appreciation?: GQLAppreciationResolvers; + AppreciationConnection?: GQLAppreciationConnectionResolvers; + AppreciationEdge?: GQLAppreciationEdgeResolvers; + ArchiveUserFailure?: GQLArchiveUserFailureResolvers; + ArchiveUsersResult?: GQLArchiveUsersResultResolvers; + Article?: GQLArticleResolvers; + ArticleAccess?: GQLArticleAccessResolvers; + ArticleArticleNotice?: GQLArticleArticleNoticeResolvers; + ArticleCampaign?: GQLArticleCampaignResolvers; + ArticleClassification?: GQLArticleClassificationResolvers; + ArticleConnection?: GQLArticleConnectionResolvers; + ArticleContents?: GQLArticleContentsResolvers; + ArticleDonation?: GQLArticleDonationResolvers; + ArticleDonationConnection?: GQLArticleDonationConnectionResolvers; + ArticleDonationEdge?: GQLArticleDonationEdgeResolvers; + ArticleEdge?: GQLArticleEdgeResolvers; + ArticleFederationEligibility?: GQLArticleFederationEligibilityResolvers; + ArticleFederationSetting?: GQLArticleFederationSettingResolvers; + ArticleNotice?: GQLArticleNoticeResolvers; + ArticleOSS?: GQLArticleOssResolvers; + ArticleRecommendationActivity?: GQLArticleRecommendationActivityResolvers; + ArticleTopicChannel?: GQLArticleTopicChannelResolvers; + ArticleTranslation?: GQLArticleTranslationResolvers; + ArticleVersion?: GQLArticleVersionResolvers; + ArticleVersionEdge?: GQLArticleVersionEdgeResolvers; + ArticleVersionsConnection?: GQLArticleVersionsConnectionResolvers; + Asset?: GQLAssetResolvers; + AuthResult?: GQLAuthResultResolvers; + Badge?: GQLBadgeResolvers; + Balance?: GQLBalanceResolvers; + BlockchainTransaction?: GQLBlockchainTransactionResolvers; + BlockedSearchKeyword?: GQLBlockedSearchKeywordResolvers; + Campaign?: GQLCampaignResolvers; + CampaignApplication?: GQLCampaignApplicationResolvers; + CampaignArticleConnection?: GQLCampaignArticleConnectionResolvers; + CampaignArticleEdge?: GQLCampaignArticleEdgeResolvers; + CampaignArticleNotice?: GQLCampaignArticleNoticeResolvers; + CampaignConnection?: GQLCampaignConnectionResolvers; + CampaignEdge?: GQLCampaignEdgeResolvers; + CampaignOSS?: GQLCampaignOssResolvers; + CampaignParticipantConnection?: GQLCampaignParticipantConnectionResolvers; + CampaignParticipantEdge?: GQLCampaignParticipantEdgeResolvers; + CampaignStage?: GQLCampaignStageResolvers; + Channel?: GQLChannelResolvers; + ChannelArticleConnection?: GQLChannelArticleConnectionResolvers; + ChannelArticleEdge?: GQLChannelArticleEdgeResolvers; + Circle?: GQLCircleResolvers; + CircleAnalytics?: GQLCircleAnalyticsResolvers; + CircleConnection?: GQLCircleConnectionResolvers; + CircleContentAnalytics?: GQLCircleContentAnalyticsResolvers; + CircleContentAnalyticsDatum?: GQLCircleContentAnalyticsDatumResolvers; + CircleEdge?: GQLCircleEdgeResolvers; + CircleFollowerAnalytics?: GQLCircleFollowerAnalyticsResolvers; + CircleIncomeAnalytics?: GQLCircleIncomeAnalyticsResolvers; + CircleNotice?: GQLCircleNoticeResolvers; + CircleRecommendationActivity?: GQLCircleRecommendationActivityResolvers; + CircleSubscriberAnalytics?: GQLCircleSubscriberAnalyticsResolvers; + ClaimLogbooksResult?: GQLClaimLogbooksResultResolvers; + Collection?: GQLCollectionResolvers; + CollectionConnection?: GQLCollectionConnectionResolvers; + CollectionEdge?: GQLCollectionEdgeResolvers; + CollectionNotice?: GQLCollectionNoticeResolvers; + Comment?: GQLCommentResolvers; + CommentCommentNotice?: GQLCommentCommentNoticeResolvers; + CommentConnection?: GQLCommentConnectionResolvers; + CommentEdge?: GQLCommentEdgeResolvers; + CommentNotice?: GQLCommentNoticeResolvers; + CommunityWatchAction?: GQLCommunityWatchActionResolvers; + CommunityWatchActionConnection?: GQLCommunityWatchActionConnectionResolvers; + CommunityWatchActionEdge?: GQLCommunityWatchActionEdgeResolvers; + ConnectStripeAccountResult?: GQLConnectStripeAccountResultResolvers; + Connection?: GQLConnectionResolvers; + CryptoWallet?: GQLCryptoWalletResolvers; + CurationChannel?: GQLCurationChannelResolvers; + DateTime?: GraphQLScalarType; + DatetimeRange?: GQLDatetimeRangeResolvers; + Donator?: GQLDonatorResolvers; + Draft?: GQLDraftResolvers; + DraftAccess?: GQLDraftAccessResolvers; + DraftConnection?: GQLDraftConnectionResolvers; + DraftEdge?: GQLDraftEdgeResolvers; + ExchangeRate?: GQLExchangeRateResolvers; + Feature?: GQLFeatureResolvers; + Following?: GQLFollowingResolvers; + FollowingActivity?: GQLFollowingActivityResolvers; + FollowingActivityConnection?: GQLFollowingActivityConnectionResolvers; + FollowingActivityEdge?: GQLFollowingActivityEdgeResolvers; + FreezeSpamRingResult?: GQLFreezeSpamRingResultResolvers; + IcymiTopic?: GQLIcymiTopicResolvers; + IcymiTopicConnection?: GQLIcymiTopicConnectionResolvers; + IcymiTopicEdge?: GQLIcymiTopicEdgeResolvers; + Invitation?: GQLInvitationResolvers; + InvitationConnection?: GQLInvitationConnectionResolvers; + InvitationEdge?: GQLInvitationEdgeResolvers; + Invitee?: GQLInviteeResolvers; + Invites?: GQLInvitesResolvers; + Liker?: GQLLikerResolvers; + Member?: GQLMemberResolvers; + MemberConnection?: GQLMemberConnectionResolvers; + MemberEdge?: GQLMemberEdgeResolvers; + Moment?: GQLMomentResolvers; + MomentConnection?: GQLMomentConnectionResolvers; + MomentEdge?: GQLMomentEdgeResolvers; + MomentFeedApplication?: GQLMomentFeedApplicationResolvers; + MomentNotice?: GQLMomentNoticeResolvers; + MonthlyDatum?: GQLMonthlyDatumResolvers; + Mutation?: GQLMutationResolvers; + NFTAsset?: GQLNftAssetResolvers; + Node?: GQLNodeResolvers; + Notice?: GQLNoticeResolvers; + NoticeConnection?: GQLNoticeConnectionResolvers; + NoticeEdge?: GQLNoticeEdgeResolvers; + NotificationSetting?: GQLNotificationSettingResolvers; + OAuthClient?: GQLOAuthClientResolvers; + OAuthClientConnection?: GQLOAuthClientConnectionResolvers; + OAuthClientEdge?: GQLOAuthClientEdgeResolvers; + OSS?: GQLOssResolvers; + Official?: GQLOfficialResolvers; + OfficialAnnouncementNotice?: GQLOfficialAnnouncementNoticeResolvers; + PageInfo?: GQLPageInfoResolvers; + PayToResult?: GQLPayToResultResolvers; + Person?: GQLPersonResolvers; + PersonhoodHandoff?: GQLPersonhoodHandoffResolvers; + PinHistory?: GQLPinHistoryResolvers; + PinnableWork?: GQLPinnableWorkResolvers; + Price?: GQLPriceResolvers; + Query?: GQLQueryResolvers; + Quote?: GQLQuoteResolvers; + QuoteConnection?: GQLQuoteConnectionResolvers; + QuoteEdge?: GQLQuoteEdgeResolvers; + ReadHistory?: GQLReadHistoryResolvers; + ReadHistoryConnection?: GQLReadHistoryConnectionResolvers; + ReadHistoryEdge?: GQLReadHistoryEdgeResolvers; + RecentSearchConnection?: GQLRecentSearchConnectionResolvers; + RecentSearchEdge?: GQLRecentSearchEdgeResolvers; + Recommendation?: GQLRecommendationResolvers; + Report?: GQLReportResolvers; + ReportConnection?: GQLReportConnectionResolvers; + ReportEdge?: GQLReportEdgeResolvers; + Response?: GQLResponseResolvers; + ResponseConnection?: GQLResponseConnectionResolvers; + ResponseEdge?: GQLResponseEdgeResolvers; + SearchResultConnection?: GQLSearchResultConnectionResolvers; + SearchResultEdge?: GQLSearchResultEdgeResolvers; + SigningMessageResult?: GQLSigningMessageResultResolvers; + SkippedListItem?: GQLSkippedListItemResolvers; + SkippedListItemEdge?: GQLSkippedListItemEdgeResolvers; + SkippedListItemsConnection?: GQLSkippedListItemsConnectionResolvers; + SocialAccount?: GQLSocialAccountResolvers; + SpamRing?: GQLSpamRingResolvers; + SpamRingConnection?: GQLSpamRingConnectionResolvers; + SpamRingEdge?: GQLSpamRingEdgeResolvers; + SpamRingEvent?: GQLSpamRingEventResolvers; + SpamRingMember?: GQLSpamRingMemberResolvers; + SpamRingMemberConnection?: GQLSpamRingMemberConnectionResolvers; + SpamRingMemberEdge?: GQLSpamRingMemberEdgeResolvers; + SpamRingSignals?: GQLSpamRingSignalsResolvers; + SpamRingSkip?: GQLSpamRingSkipResolvers; + SpamStatus?: GQLSpamStatusResolvers; + StripeAccount?: GQLStripeAccountResolvers; + SubscribeCircleResult?: GQLSubscribeCircleResultResolvers; + Tag?: GQLTagResolvers; + TagConnection?: GQLTagConnectionResolvers; + TagEdge?: GQLTagEdgeResolvers; + TagOSS?: GQLTagOssResolvers; + TagWritingConnection?: GQLTagWritingConnectionResolvers; + TagWritingEdge?: GQLTagWritingEdgeResolvers; + TopDonatorConnection?: GQLTopDonatorConnectionResolvers; + TopDonatorEdge?: GQLTopDonatorEdgeResolvers; + TopicChannel?: GQLTopicChannelResolvers; + TopicChannelClassification?: GQLTopicChannelClassificationResolvers; + TopicChannelFeedback?: GQLTopicChannelFeedbackResolvers; + TopicChannelFeedbackConnection?: GQLTopicChannelFeedbackConnectionResolvers; + TopicChannelFeedbackEdge?: GQLTopicChannelFeedbackEdgeResolvers; + Transaction?: GQLTransactionResolvers; + TransactionConnection?: GQLTransactionConnectionResolvers; + TransactionEdge?: GQLTransactionEdgeResolvers; + TransactionNotice?: GQLTransactionNoticeResolvers; + TransactionTarget?: GQLTransactionTargetResolvers; + TranslatedAnnouncement?: GQLTranslatedAnnouncementResolvers; + UnfreezeSpamRingResult?: GQLUnfreezeSpamRingResultResolvers; + Upload?: GraphQLScalarType; + UpsertSpamRingCandidatesResult?: GQLUpsertSpamRingCandidatesResultResolvers; + User?: GQLUserResolvers; + UserActivity?: GQLUserActivityResolvers; + UserAddArticleTagActivity?: GQLUserAddArticleTagActivityResolvers; + UserAnalytics?: GQLUserAnalyticsResolvers; + UserBroadcastCircleActivity?: GQLUserBroadcastCircleActivityResolvers; + UserConnection?: GQLUserConnectionResolvers; + UserCreateCircleActivity?: GQLUserCreateCircleActivityResolvers; + UserEdge?: GQLUserEdgeResolvers; + UserFeatureFlag?: GQLUserFeatureFlagResolvers; + UserFeatures?: GQLUserFeaturesResolvers; + UserFederationSetting?: GQLUserFederationSettingResolvers; + UserInfo?: GQLUserInfoResolvers; + UserNotice?: GQLUserNoticeResolvers; + UserOSS?: GQLUserOssResolvers; + UserPostMomentActivity?: GQLUserPostMomentActivityResolvers; + UserPublishArticleActivity?: GQLUserPublishArticleActivityResolvers; + UserRecommendationActivity?: GQLUserRecommendationActivityResolvers; + UserRestriction?: GQLUserRestrictionResolvers; + UserSettings?: GQLUserSettingsResolvers; + UserStatus?: GQLUserStatusResolvers; + Wallet?: GQLWalletResolvers; + WithdrawLockedTokensResult?: GQLWithdrawLockedTokensResultResolvers; + Writing?: GQLWritingResolvers; + WritingChallenge?: GQLWritingChallengeResolvers; + WritingConnection?: GQLWritingConnectionResolvers; + WritingEdge?: GQLWritingEdgeResolvers; +}>; export type GQLDirectiveResolvers = ResolversObject<{ - auth?: GQLAuthDirectiveResolver - cacheControl?: GQLCacheControlDirectiveResolver - complexity?: GQLComplexityDirectiveResolver - constraint?: GQLConstraintDirectiveResolver - logCache?: GQLLogCacheDirectiveResolver - objectCache?: GQLObjectCacheDirectiveResolver - privateCache?: GQLPrivateCacheDirectiveResolver - purgeCache?: GQLPurgeCacheDirectiveResolver - rateLimit?: GQLRateLimitDirectiveResolver -}> + auth?: GQLAuthDirectiveResolver; + cacheControl?: GQLCacheControlDirectiveResolver; + complexity?: GQLComplexityDirectiveResolver; + constraint?: GQLConstraintDirectiveResolver; + logCache?: GQLLogCacheDirectiveResolver; + objectCache?: GQLObjectCacheDirectiveResolver; + privateCache?: GQLPrivateCacheDirectiveResolver; + purgeCache?: GQLPurgeCacheDirectiveResolver; + rateLimit?: GQLRateLimitDirectiveResolver; +}>; diff --git a/src/definitions/spamRing.d.ts b/src/definitions/spamRing.d.ts new file mode 100644 index 000000000..b05402dcc --- /dev/null +++ b/src/definitions/spamRing.d.ts @@ -0,0 +1,72 @@ +export type SpamRingStatus = 'pending' | 'frozen' | 'dismissed' | 'restored' +export type SpamRingMemberStatus = + | 'pending' + | 'frozen' + | 'skipped' + | 'restored' +export type SpamRingSeverity = 'low' | 'medium' | 'high' | 'critical' +export type SpamRingEventAction = + | 'detected' + | 'frozen' + | 'unfrozen' + | 'dismissed' + | 'member_banned' + | 'member_skipped' + | 'member_restored' + +// app 層精修訊號摘要(偵測 job 寫入;snake_case 鍵存 jsonb,GraphQL 層轉 camelCase) +export interface SpamRingSignals { + nearDupRingSize?: number | null + entityRingSize?: number | null + botUsernameRatio?: number | null + topEntity?: string | null + sampleCodes?: string[] | null + sampleBrands?: string[] | null + contentModelMax?: number | null +} + +export interface SpamRing { + id: string + uuid: string + fingerprint: string + status: SpamRingStatus + signals: SpamRingSignals + nArticles: number + nAuthors: number + newAccountRatio: number | null + score: number | null + severity: SpamRingSeverity | null + detectedAt: Date + firstSeenAt: Date | null + lastSeenAt: Date | null + frozenAt: Date | null + frozenBy: string | null + note: string | null + createdAt: Date + updatedAt: Date +} + +export interface SpamRingMember { + id: string + uuid: string + ringId: string + userId: string + status: SpamRingMemberStatus + bannedByThisRing: boolean + skipReason: string | null + preFreezeState: 'active' | 'banned' | 'archived' | 'frozen' | null + evidence: Record + createdAt: Date + updatedAt: Date +} + +export interface SpamRingEvent { + id: string + uuid: string + ringId: string + memberId: string | null + actorId: string | null + action: SpamRingEventAction + detail: Record + createdAt: Date +} diff --git a/src/mutations/campaign/putWritingChallenge.ts b/src/mutations/campaign/putWritingChallenge.ts index 7bfe5f4f0..2fc8e1147 100644 --- a/src/mutations/campaign/putWritingChallenge.ts +++ b/src/mutations/campaign/putWritingChallenge.ts @@ -42,6 +42,7 @@ const resolver: GQLMutationResolvers['putWritingChallenge'] = async ( managers: managerGlobalIds, showOther, showAd, + enableQuoteWall, }, }, { @@ -155,6 +156,7 @@ const resolver: GQLMutationResolvers['putWritingChallenge'] = async ( exclusive, showOther, showAd, + enableQuoteWall, }) // invalidate campaign list cache @@ -210,6 +212,7 @@ const resolver: GQLMutationResolvers['putWritingChallenge'] = async ( exclusive, showOther, showAd, + enableQuoteWall, } campaign = await atomService.update({ diff --git a/src/mutations/comment/deleteComment.ts b/src/mutations/comment/deleteComment.ts index 9bb68dadf..71caf2505 100644 --- a/src/mutations/comment/deleteComment.ts +++ b/src/mutations/comment/deleteComment.ts @@ -42,6 +42,14 @@ const resolver: GQLMutationResolvers['deleteComment'] = async ( ? [(await atomService.momentIdLoader.load(comment.targetId)).authorId] : []), ] + if (comment.type === COMMENT_TYPE.campaignDiscussion) { + const campaign = await atomService.campaignIdLoader.load(comment.targetId) + authorized.push( + campaign.creatorId, + ...(campaign.organizerIds ?? []), + ...(campaign.managerIds ?? []) + ) + } if (!authorized.includes(viewer.id)) { throw new ForbiddenError('viewer has no permission') } @@ -65,6 +73,8 @@ const resolver: GQLMutationResolvers['deleteComment'] = async ( ? NODE_TYPES.Article : comment.type === COMMENT_TYPE.moment ? NODE_TYPES.Moment + : comment.type === COMMENT_TYPE.campaignDiscussion + ? NODE_TYPES.Campaign : NODE_TYPES.Circle, }, redis: connections.redis, diff --git a/src/mutations/comment/putComment.ts b/src/mutations/comment/putComment.ts index e148c4b42..6f9bfec43 100644 --- a/src/mutations/comment/putComment.ts +++ b/src/mutations/comment/putComment.ts @@ -6,16 +6,19 @@ import type { Circle, Comment, Moment, + Campaign, } from '#definitions/index.js' import { ARTICLE_ACCESS_TYPE, ARTICLE_STATE, BUNDLED_NOTICE_TYPE, + CAMPAIGN_STATE, COMMENT_TYPE, COMMENT_STATE, NOTICE_TYPE, MAX_ARTICLE_COMMENT_LENGTH, + MAX_CAMPAIGN_COMMENT_LENGTH, MAX_MOMENT_COMMENT_LENGTH, MAX_CONTENT_LINK_TEXT_LENGTH, NODE_TYPES, @@ -24,10 +27,12 @@ import { } from '#common/enums/index.js' import { ArticleNotFoundError, + CampaignNotFoundError, CircleNotFoundError, CommentNotFoundError, MomentNotFoundError, ForbiddenByStateError, + ForbiddenByTargetStateError, ForbiddenError, UserInputError, } from '#common/errors.js' @@ -60,6 +65,7 @@ const resolver: GQLMutationResolvers['putComment'] = async ( articleId, circleId, momentId, + campaignId, }, id, }, @@ -104,6 +110,7 @@ const resolver: GQLMutationResolvers['putComment'] = async ( const isCircleDiscussion = type === 'circleDiscussion' const isCircleBroadcast = type === 'circleBroadcast' const isMoment = type === 'moment' + const isCampaignDiscussion = type === 'campaignDiscussion' if (isArticleType && !articleId) { throw new UserInputError('`articleId` is required if `type` is `article`') } else if ((isCircleDiscussion || isCircleBroadcast) && !circleId) { @@ -112,6 +119,10 @@ const resolver: GQLMutationResolvers['putComment'] = async ( ) } else if (isMoment && !momentId) { throw new UserInputError('`momentId` is required if `type` is `moment`') + } else if (isCampaignDiscussion && !campaignId) { + throw new UserInputError( + '`campaignId` is required if `type` is `campaignDiscussion`' + ) } else { data.type = COMMENT_TYPE[type] } @@ -130,6 +141,12 @@ const resolver: GQLMutationResolvers['putComment'] = async ( if (isMoment && stripHtml(content).length > MAX_MOMENT_COMMENT_LENGTH) { throw new UserInputError('content reach length limit') } + if ( + isCampaignDiscussion && + stripHtml(content).length > MAX_CAMPAIGN_COMMENT_LENGTH + ) { + throw new UserInputError('content reach length limit') + } /** * check target @@ -137,6 +154,7 @@ const resolver: GQLMutationResolvers['putComment'] = async ( let article: Article | undefined let circle: Circle | undefined let moment: Moment | undefined + let campaign: Campaign | undefined let targetAuthor: string | undefined if (articleId) { const { id: articleDbId } = fromGlobalId(articleId) @@ -191,9 +209,30 @@ const resolver: GQLMutationResolvers['putComment'] = async ( data.targetId = moment.id targetAuthor = moment.authorId + } else if (campaignId) { + const { id: campaignDbId } = fromGlobalId(campaignId) + campaign = await atomService.campaignIdLoader.load(campaignDbId) + + if (!campaign) { + throw new CampaignNotFoundError('target campaign does not exists') + } + + if (campaign.state === CAMPAIGN_STATE.archived) { + throw new ForbiddenByTargetStateError('campaign is archived') + } + + const { id: typeId } = await atomService.findFirst({ + table: 'entity_type', + where: { table: 'campaign' }, + }) + data.targetTypeId = typeId + data.targetId = campaign.id + + // campaign discussion has no single "author" to notify / block against + targetAuthor = undefined } else { throw new UserInputError( - '`articleId` or `circleId` or `momentId` is required' + '`articleId` or `circleId` or `momentId` or `campaignId` is required' ) } @@ -269,13 +308,20 @@ const resolver: GQLMutationResolvers['putComment'] = async ( } } - // check whether viewer is blocked by target author - const isBlocked = await userService.blocked({ - userId: targetAuthor, - targetId: viewer.id, - }) - if (isBlocked) { - throw new ForbiddenError('viewer is blocked by target author') + // campaign discussion is public to read; any logged-in user may comment. + // (relaxed from the previous participant-only restriction — basic user-state + // and campaign-state guards are still enforced above.) + + // check whether viewer is blocked by target author (skip when no single author, + // e.g. campaign discussion) + if (targetAuthor) { + const isBlocked = await userService.blocked({ + userId: targetAuthor, + targetId: viewer.id, + }) + if (isBlocked) { + throw new ForbiddenError('viewer is blocked by target author') + } } data.mentionedUserIds = @@ -369,7 +415,7 @@ const resolver: GQLMutationResolvers['putComment'] = async ( (targetAuthor !== parentCommentAuthor && targetAuthor !== replyToCommentAuthor)) - if (isArticleType && shouldNotifyArticleAuthor) { + if (isArticleType && targetAuthor && shouldNotifyArticleAuthor) { const isMentioned = !!data.mentionedUserIds?.includes(targetAuthor) if (!isMentioned) { @@ -503,7 +549,7 @@ const resolver: GQLMutationResolvers['putComment'] = async ( } } - if (isMoment) { + if (isMoment && targetAuthor) { const isMentioned = !!data.mentionedUserIds?.includes(targetAuthor) if (!isMentioned) { notificationService.trigger({ @@ -534,7 +580,11 @@ const resolver: GQLMutationResolvers['putComment'] = async ( ], tag: `put-comment:${newComment.id}`, }) - } else if (!(isCircleBroadcast && isLevel1Comment)) { + } else if ( + (isCircleDiscussion || isCircleBroadcast) && + !(isCircleBroadcast && isLevel1Comment) + ) { + // NOTE: campaignDiscussion mentions intentionally send no notice in MVP const noticeType = isCircleBroadcast ? NOTICE_TYPE.circle_new_broadcast_comments : NOTICE_TYPE.circle_new_discussion_comments @@ -587,6 +637,11 @@ const resolver: GQLMutationResolvers['putComment'] = async ( id: moment?.id as string, type: NODE_TYPES.Moment, } + : isCampaignDiscussion + ? { + id: campaign?.id as string, + type: NODE_TYPES.Campaign, + } : { id: circle?.id as string, type: NODE_TYPES.Circle, diff --git a/src/mutations/comment/togglePinComment.ts b/src/mutations/comment/togglePinComment.ts index 18e9f940e..334eddef8 100644 --- a/src/mutations/comment/togglePinComment.ts +++ b/src/mutations/comment/togglePinComment.ts @@ -38,6 +38,8 @@ const resolver: Exclude< if (article.authorId !== viewer.id) { throw new ForbiddenError('viewer has no permission') } + } else if (comment.type === COMMENT_TYPE.campaignDiscussion) { + throw new ForbiddenError('cannot pin campaign discussion comment') } else { circle = await atomService.circleIdLoader.load(comment.targetId) const targetAuthor = circle.owner diff --git a/src/mutations/comment/unvoteComment.ts b/src/mutations/comment/unvoteComment.ts index 6028e58b7..37a955fc4 100644 --- a/src/mutations/comment/unvoteComment.ts +++ b/src/mutations/comment/unvoteComment.ts @@ -3,6 +3,7 @@ import type { Article, Circle, Moment, + Campaign, } from '#definitions/index.js' import { COMMENT_TYPE, USER_STATE, NOTICE_TYPE } from '#common/enums/index.js' @@ -17,6 +18,7 @@ const resolver: GQLMutationResolvers['unvoteComment'] = async ( dataSources: { atomService, paymentService, + campaignService, commentService, notificationService, }, @@ -33,13 +35,17 @@ const resolver: GQLMutationResolvers['unvoteComment'] = async ( let article: Article let circle: Circle | undefined = undefined let moment: Moment - let targetAuthor: string + let campaign: Campaign | undefined = undefined + let targetAuthor: string | undefined if (comment.type === COMMENT_TYPE.article) { article = await atomService.articleIdLoader.load(comment.targetId) targetAuthor = article.authorId } else if (comment.type === COMMENT_TYPE.moment) { moment = await atomService.momentIdLoader.load(comment.targetId) targetAuthor = moment.authorId + } else if (comment.type === COMMENT_TYPE.campaignDiscussion) { + // campaign discussion has no single target author + campaign = await atomService.campaignIdLoader.load(comment.targetId) } else { circle = await atomService.circleIdLoader.load(comment.targetId) targetAuthor = circle.owner @@ -68,6 +74,21 @@ const resolver: GQLMutationResolvers['unvoteComment'] = async ( } } + if (campaign) { + const isParticipant = await campaignService.isParticipant( + campaign.id, + viewer.id + ) + const isOrganizer = + campaign.creatorId === viewer.id || + (campaign.organizerIds ?? []).includes(viewer.id) || + (campaign.managerIds ?? []).includes(viewer.id) + + if (!isParticipant && !isOrganizer) { + throw new ForbiddenError('only campaign participants have the permission') + } + } + await commentService.unvote({ commentId: dbId, userId: viewer.id }) if ( diff --git a/src/mutations/index.ts b/src/mutations/index.ts index a3e2e1324..215acf224 100644 --- a/src/mutations/index.ts +++ b/src/mutations/index.ts @@ -10,6 +10,7 @@ import draft from './draft/index.js' import moment from './moment/index.js' import notice from './notice/index.js' import oauthClient from './oauthClient/index.js' +import quote from './quote/index.js' import system from './system/index.js' import user from './user/index.js' @@ -25,5 +26,6 @@ export default merge( oauthClient, collection, moment, + quote, channel ) diff --git a/src/mutations/quote/deleteQuote.ts b/src/mutations/quote/deleteQuote.ts new file mode 100644 index 000000000..726e8ef35 --- /dev/null +++ b/src/mutations/quote/deleteQuote.ts @@ -0,0 +1,65 @@ +import type { GQLMutationResolvers } from '#definitions/index.js' + +import { NODE_TYPES, QUOTE_STATE } from '#common/enums/index.js' +import { + EntityNotFoundError, + ForbiddenError, + UserInputError, +} from '#common/errors.js' +import { fromGlobalId } from '#common/utils/index.js' +import { invalidateFQC } from '@matters/apollo-response-cache' + +const resolver: GQLMutationResolvers['deleteQuote'] = async ( + _, + { input: { id } }, + { + viewer, + dataSources: { + atomService, + connections: { redis }, + }, + } +) => { + const { id: quoteDbId, type } = fromGlobalId(id) + if (type !== 'Quote') { + throw new UserInputError('invalid id') + } + const quote = await atomService.findFirst({ + table: 'quote', + where: { id: quoteDbId }, + }) + if (!quote) { + throw new EntityNotFoundError('quote does not exists') + } + + // retraction is allowed for: the poster, the source article's author + // (the quoted words are theirs), or admin. checked before any idempotent + // shortcut so an unauthorized viewer can never probe a quote's existence + const article = await atomService.articleIdLoader.load(quote.articleId) + const isPoster = viewer.id === quote.userId + const isArticleAuthor = viewer.id === article?.authorId + if (!isPoster && !isArticleAuthor && !viewer.hasRole('admin')) { + throw new ForbiddenError('viewer has no permission') + } + + // idempotent: already retracted, nothing to do + if (quote.state !== QUOTE_STATE.active) { + return true + } + + // soft delete: hidden, not erased + await atomService.update({ + table: 'quote', + where: { id: quote.id }, + data: { state: QUOTE_STATE.archived }, + }) + + invalidateFQC({ + node: { id: quote.campaignId, type: NODE_TYPES.Campaign }, + redis, + }) + + return true +} + +export default resolver diff --git a/src/mutations/quote/index.ts b/src/mutations/quote/index.ts new file mode 100644 index 000000000..b93f3e273 --- /dev/null +++ b/src/mutations/quote/index.ts @@ -0,0 +1,9 @@ +import deleteQuote from './deleteQuote.js' +import putQuote from './putQuote.js' + +export default { + Mutation: { + putQuote, + deleteQuote, + }, +} diff --git a/src/mutations/quote/putQuote.ts b/src/mutations/quote/putQuote.ts new file mode 100644 index 000000000..43df816cb --- /dev/null +++ b/src/mutations/quote/putQuote.ts @@ -0,0 +1,191 @@ +import type { GQLMutationResolvers } from '#definitions/index.js' + +import { + ARTICLE_LICENSE_TYPE, + ARTICLE_STATE, + MAX_QUOTE_LENGTH, + NODE_TYPES, + QUOTE_DAILY_LIMIT, + QUOTE_PER_ARTICLE_LIMIT, + QUOTE_STATE, + USER_STATE, +} from '#common/enums/index.js' +import { + ActionLimitExceededError, + ArticleNotFoundError, + ForbiddenByStateError, + ForbiddenError, + UserInputError, +} from '#common/errors.js' +import { fromGlobalId, stripHtml } from '#common/utils/index.js' +import { invalidateFQC } from '@matters/apollo-response-cache' + +// collapse whitespace so "selected text" can be matched against the +// article content regardless of line breaks / indentation +const normalize = (text: string) => text.replace(/\s+/g, '') + +const resolver: GQLMutationResolvers['putQuote'] = async ( + _, + { input: { articleId, content } }, + { + viewer, + dataSources: { + atomService, + articleService, + connections: { knexRO, redis }, + }, + } +) => { + if (!viewer.userName) { + throw new ForbiddenError('user has no username') + } + if ( + [USER_STATE.banned, USER_STATE.archived, USER_STATE.frozen].includes( + viewer.state + ) + ) { + throw new ForbiddenByStateError(`${viewer.state} user has no permission`) + } + + // content: required, plain text, capped at MAX_QUOTE_LENGTH + const quoteText = stripHtml(content).trim() + if (quoteText.length <= 0) { + throw new UserInputError('"content" is required') + } + if (quoteText.length > MAX_QUOTE_LENGTH) { + throw new UserInputError( + `quote can not be longer than ${MAX_QUOTE_LENGTH} characters` + ) + } + + // target article + const { id: articleDbId, type } = fromGlobalId(articleId) + if (type !== 'Article') { + throw new UserInputError('invalid id') + } + const article = await atomService.findFirst({ + table: 'article', + where: { id: articleDbId, state: ARTICLE_STATE.active }, + }) + if (!article) { + throw new ArticleNotFoundError('target article does not exists') + } + + // license gate: ARR (all rights reserved) -> only the author may quote + const isAuthor = viewer.id === article.authorId + const articleVersion = await articleService.loadLatestArticleVersion( + article.id + ) + if (articleVersion.license === ARTICLE_LICENSE_TYPE.arr && !isAuthor) { + throw new ForbiddenError( + 'only the author can quote an all-rights-reserved article' + ) + } + + // the quote must be selected from the article content, not free-typed; + // this is the primary anti-abuse mechanism + const articleContent = await articleService.loadLatestArticleContent( + article.id + ) + if (!normalize(stripHtml(articleContent)).includes(normalize(quoteText))) { + throw new UserInputError('quote must be an excerpt of the article') + } + + // wall is campaign-scoped: the article must belong to a campaign + const campaignArticle = await atomService.findFirst({ + table: 'campaign_article', + where: { articleId: article.id, deleted: false }, + orderBy: [{ column: 'createdAt', order: 'desc' }], + }) + if (!campaignArticle) { + throw new UserInputError('only campaign articles can be quoted onto wall') + } + const campaignId = campaignArticle.campaignId + + // the quote wall is opt-in per campaign (e.g. 七日書): the campaign must have + // it enabled. this is the authoritative gate — the client also hides the + // post-to-wall affordance, but the server is the source of truth. + const campaign = await atomService.findUnique({ + table: 'campaign', + where: { id: campaignId }, + }) + if (!campaign?.enableQuoteWall) { + throw new UserInputError('this campaign does not have a quote wall') + } + + // dedupe: same user + same article + identical content + const duplicated = await atomService.findFirst({ + table: 'quote', + where: { + userId: viewer.id, + articleId: article.id, + content: quoteText, + state: QUOTE_STATE.active, + }, + }) + if (duplicated) { + throw new UserInputError('this quote is already on the wall') + } + + // per-article cap (prevents plastering the wall with one article) + const perArticleCount = await atomService.count({ + table: 'quote', + where: { + userId: viewer.id, + articleId: article.id, + state: QUOTE_STATE.active, + }, + }) + if (perArticleCount >= QUOTE_PER_ARTICLE_LIMIT) { + throw new ActionLimitExceededError( + `up to ${QUOTE_PER_ARTICLE_LIMIT} quotes per article` + ) + } + + // daily cap; counts posting actions (UTC day), retraction does not refund + const todayStart = new Date() + todayStart.setUTCHours(0, 0, 0, 0) + const dailyCount = await knexRO('quote') + .count('id') + .where({ userId: viewer.id }) + .andWhere('createdAt', '>=', todayStart) + .first() + if (Number(dailyCount?.count ?? 0) >= QUOTE_DAILY_LIMIT) { + throw new ActionLimitExceededError( + `up to ${QUOTE_DAILY_LIMIT} quotes per day` + ) + } + + let quote + try { + quote = await atomService.create({ + table: 'quote', + data: { + content: quoteText, + articleId: article.id, + campaignId, + userId: viewer.id, + state: QUOTE_STATE.active, + }, + }) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (err: any) { + // duplicate key error + if ( + err.code === '23505' && + err.constraint === 'quote_user_id_article_id_content_unique' + ) { + throw new UserInputError('this quote is already on the wall') + } + throw err + } + + invalidateFQC({ + node: { id: campaignId, type: NODE_TYPES.Campaign }, + redis, + }) + + return quote +} + +export default resolver diff --git a/src/mutations/user/dismissSpamRing.ts b/src/mutations/user/dismissSpamRing.ts new file mode 100644 index 000000000..2b3b0741c --- /dev/null +++ b/src/mutations/user/dismissSpamRing.ts @@ -0,0 +1,18 @@ +import type { GQLMutationResolvers } from '#definitions/index.js' + +import { ForbiddenError } from '#common/errors.js' +import { fromGlobalId } from '#common/utils/index.js' + +const resolver: GQLMutationResolvers['dismissSpamRing'] = async ( + _, + { input: { id, note } }, + { viewer, dataSources: { spamRingService } } +) => { + if (!viewer.id) { + throw new ForbiddenError('viewer has no id') + } + const { id: ringId } = fromGlobalId(id) + return spamRingService.dismissRing({ ringId, actorId: viewer.id, note }) +} + +export default resolver diff --git a/src/mutations/user/freezeSpamRing.ts b/src/mutations/user/freezeSpamRing.ts new file mode 100644 index 000000000..f59940f25 --- /dev/null +++ b/src/mutations/user/freezeSpamRing.ts @@ -0,0 +1,23 @@ +import type { GQLMutationResolvers } from '#definitions/index.js' + +import { ForbiddenError } from '#common/errors.js' +import { fromGlobalId } from '#common/utils/index.js' + +const resolver: GQLMutationResolvers['freezeSpamRing'] = async ( + _, + { input: { id, remark } }, + { viewer, dataSources: { spamRingService, userService } } +) => { + if (!viewer.id) { + throw new ForbiddenError('viewer has no id') + } + const { id: ringId } = fromGlobalId(id) + return spamRingService.freezeRing({ + ringId, + actorId: viewer.id, + remark, + userService, + }) +} + +export default resolver diff --git a/src/mutations/user/index.ts b/src/mutations/user/index.ts index 3390ef249..83a68066c 100644 --- a/src/mutations/user/index.ts +++ b/src/mutations/user/index.ts @@ -7,7 +7,9 @@ import clearSearchHistory from './clearSearchHistory.js' import confirmVerificationCode from './confirmVerificationCode.js' import connectStripeAccount from './connectStripeAccount.js' import createPersonhoodHandoff from './createPersonhoodHandoff.js' +import dismissSpamRing from './dismissSpamRing.js' import emailLogin from './emailLogin.js' +import freezeSpamRing from './freezeSpamRing.js' import generateSigningMessage from './generateSigningMessage.js' import migration from './migration.js' import payout from './payout.js' @@ -31,11 +33,13 @@ import toggleBookmarkTag from './toggleBookmarkTag.js' import toggleFollowUser from './toggleFollowUser.js' import toggleUsersBadge from './toggleUsersBadge.js' import unbindLikerId from './unbindLikerId.js' +import unfreezeSpamRing from './unfreezeSpamRing.js' import updateNotificationSetting from './updateNotificationSetting.js' import updateUserExtra from './updateUserExtra.js' import updateUserInfo from './updateUserInfo.js' import updateUserRole from './updateUserRole.js' import updateUserState from './updateUserState.js' +import upsertSpamRingCandidates from './upsertSpamRingCandidates.js' import userLogout from './userLogout.js' import verifyEmail from './verifyEmail.js' import { @@ -70,6 +74,10 @@ export default { clearReadHistory, clearSearchHistory, archiveUsers, + freezeSpamRing, + unfreezeSpamRing, + dismissSpamRing, + upsertSpamRingCandidates, updateUserState, updateUserRole, updateUserExtra, diff --git a/src/mutations/user/socialLogin.ts b/src/mutations/user/socialLogin.ts index 392bb9780..a54e650bf 100644 --- a/src/mutations/user/socialLogin.ts +++ b/src/mutations/user/socialLogin.ts @@ -1,7 +1,12 @@ import type { GQLMutationResolvers, AuthMode } from '#definitions/index.js' -import { AUTH_RESULT_TYPE, SOCIAL_LOGIN_TYPE } from '#common/enums/index.js' -import { UserInputError } from '#common/errors.js' +import { + AUTH_RESULT_TYPE, + SOCIAL_LOGIN_TYPE, + USER_ROLE, +} from '#common/enums/index.js' +import { environment } from '#common/environment.js' +import { ForbiddenError, UserInputError } from '#common/errors.js' import { checkIfE2ETest, throwOrReturnUserInfo } from '#common/utils/e2e.js' import { setCookie, getViewerFromUser } from '#common/utils/index.js' @@ -16,6 +21,7 @@ export const socialLogin: GQLMutationResolvers['socialLogin'] = async ( oauth1Credential, language, referralCode, + redirectUri, }, }, context @@ -112,6 +118,17 @@ export const socialLogin: GQLMutationResolvers['socialLogin'] = async ( if (nonce === undefined || authorizationCode === undefined) { throw new UserInputError('nonce and authorizationCode is required') } + // OSS SSO: when a redirectUri is supplied it must be allowlisted. This both + // (a) lets the token exchange use the OSS callback — Google requires the + // token-exchange redirect_uri to match the authorization request — and + // (b) flags this as an OSS admin login (existing admins only, no creation). + const isOSSLogin = !!redirectUri + if ( + isOSSLogin && + !environment.ossGoogleRedirectUris.includes(redirectUri) + ) { + throw new UserInputError('redirectUri is not allowed') + } let userInfo: { id: string email: string @@ -120,16 +137,34 @@ export const socialLogin: GQLMutationResolvers['socialLogin'] = async ( if (isE2ETest) { userInfo = throwOrReturnUserInfo(authorizationCode, type) as any } else { - userInfo = await userService.fetchGoogleUserInfo(authorizationCode, nonce) + userInfo = await userService.fetchGoogleUserInfo( + authorizationCode, + nonce, + isOSSLogin ? redirectUri : undefined + ) + } + if (isOSSLogin) { + // Restrict OSS login to existing admin accounts; never auto-create one. + if (!userInfo.emailVerified) { + throw new ForbiddenError('Google email is not verified') + } + const existingUser = await userService.findByEmail(userInfo.email) + if (!existingUser || existingUser.role !== USER_ROLE.admin) { + throw new ForbiddenError( + 'OSS login is restricted to existing admin accounts' + ) + } + user = existingUser + } else { + user = await userService.getOrCreateUserBySocialAccount({ + providerAccountId: userInfo.id, + type: SOCIAL_LOGIN_TYPE.Google, + email: userInfo.email, + emailVerified: userInfo.emailVerified, + language: language || viewer.language, + referralCode, + }) } - user = await userService.getOrCreateUserBySocialAccount({ - providerAccountId: userInfo.id, - type: SOCIAL_LOGIN_TYPE.Google, - email: userInfo.email, - emailVerified: userInfo.emailVerified, - language: language || viewer.language, - referralCode, - }) } const sessionToken = await userService.genSessionToken(user.id) setCookie({ req, res, token: sessionToken, user }) diff --git a/src/mutations/user/unfreezeSpamRing.ts b/src/mutations/user/unfreezeSpamRing.ts new file mode 100644 index 000000000..32ac95d3f --- /dev/null +++ b/src/mutations/user/unfreezeSpamRing.ts @@ -0,0 +1,22 @@ +import type { GQLMutationResolvers } from '#definitions/index.js' + +import { ForbiddenError } from '#common/errors.js' +import { fromGlobalId } from '#common/utils/index.js' + +const resolver: GQLMutationResolvers['unfreezeSpamRing'] = async ( + _, + { input: { id } }, + { viewer, dataSources: { spamRingService, userService } } +) => { + if (!viewer.id) { + throw new ForbiddenError('viewer has no id') + } + const { id: ringId } = fromGlobalId(id) + return spamRingService.unfreezeRing({ + ringId, + actorId: viewer.id, + userService, + }) +} + +export default resolver diff --git a/src/mutations/user/upsertSpamRingCandidates.ts b/src/mutations/user/upsertSpamRingCandidates.ts new file mode 100644 index 000000000..973934d8b --- /dev/null +++ b/src/mutations/user/upsertSpamRingCandidates.ts @@ -0,0 +1,27 @@ +import type { GQLMutationResolvers } from '#definitions/index.js' + +const resolver: GQLMutationResolvers['upsertSpamRingCandidates'] = async ( + _, + { input: { candidates } }, + { dataSources: { spamRingService } } +) => { + const mapped = candidates.map((c) => ({ + fingerprint: c.fingerprint, + memberUserIds: c.memberUserIds ?? undefined, + memberUserNames: c.memberUserNames ?? undefined, + signals: c.signals, + nArticles: c.nArticles, + nAuthors: c.nAuthors, + newAccountRatio: c.newAccountRatio ?? undefined, + score: c.score ?? undefined, + severity: c.severity ?? undefined, + firstSeenAt: c.firstSeenAt ?? undefined, + lastSeenAt: c.lastSeenAt ?? undefined, + memberEvidence: c.memberEvidence + ? JSON.parse(c.memberEvidence) + : undefined, + })) + return spamRingService.upsertCandidates(mapped) +} + +export default resolver diff --git a/src/queries/campaign/index.ts b/src/queries/campaign/index.ts index 245a73a1b..e9412f8ba 100644 --- a/src/queries/campaign/index.ts +++ b/src/queries/campaign/index.ts @@ -3,6 +3,9 @@ import type { GQLResolvers } from '#definitions/index.js' import { NODE_TYPES } from '#common/enums/index.js' import { toGlobalId, fromDatetimeRangeString } from '#common/utils/index.js' +import campaignDiscussion from '../comment/campaign/discussion.js' +import campaignDiscussionCount from '../comment/campaign/discussionCount.js' + import announcements from './announcements.js' import application from './application.js' import articles from './articles.js' @@ -18,6 +21,8 @@ import name from './name.js' import navbarTitle from './navbarTitle.js' import organizers from './organizers.js' import participants from './participants.js' +import quoteCount from './quoteCount.js' +import quotes from './quotes.js' import stageDescription from './stage/description.js' import stageName from './stage/name.js' import stages from './stages.js' @@ -55,9 +60,14 @@ const schema: GQLResolvers = { managerIds?.includes(viewer.id) ?? false, participants, articles, + discussion: campaignDiscussion, + discussionCount: campaignDiscussionCount, + quotes, + quoteCount, channelEnabled, showOther: ({ showOther }) => showOther, showAd: ({ showAd }) => showAd, + enableQuoteWall: ({ enableQuoteWall }) => enableQuoteWall, organizers, oss: (root) => root, }, diff --git a/src/queries/campaign/quoteCount.ts b/src/queries/campaign/quoteCount.ts new file mode 100644 index 000000000..2860a48d9 --- /dev/null +++ b/src/queries/campaign/quoteCount.ts @@ -0,0 +1,18 @@ +import type { GQLWritingChallengeResolvers } from '#definitions/index.js' + +import { QUOTE_STATE } from '#common/enums/index.js' + +const resolver: GQLWritingChallengeResolvers['quoteCount'] = async ( + { id }, + _, + { dataSources: { atomService } } +) => { + const count = await atomService.count({ + table: 'quote', + where: { campaignId: id, state: QUOTE_STATE.active }, + }) + + return count +} + +export default resolver diff --git a/src/queries/campaign/quotes.ts b/src/queries/campaign/quotes.ts new file mode 100644 index 000000000..45388196d --- /dev/null +++ b/src/queries/campaign/quotes.ts @@ -0,0 +1,50 @@ +import type { GQLWritingChallengeResolvers } from '#definitions/index.js' + +import { QUOTE_STATE } from '#common/enums/index.js' +import { connectionFromArray, fromConnectionArgs } from '#common/utils/index.js' + +const DEFAULT_TAKE = 12 + +// public quote wall of a campaign; `random: true` returns a random sample +// (the "shuffle" button simply refetches), in which case `after` is ignored +const resolver: GQLWritingChallengeResolvers['quotes'] = async ( + { id }, + { input }, + { + dataSources: { + atomService, + connections: { knexRO }, + }, + } +) => { + const { random } = input + const { take, skip } = fromConnectionArgs(input, { + defaultTake: DEFAULT_TAKE, + }) + + const [quotes, totalCount] = await Promise.all([ + knexRO('quote') + .select() + .where({ campaignId: id, state: QUOTE_STATE.active }) + .modify((builder) => { + if (random) { + builder.orderByRaw('random()') + } else { + builder.orderBy('id', 'desc').offset(skip) + } + }) + .limit(take), + atomService.count({ + table: 'quote', + where: { campaignId: id, state: QUOTE_STATE.active }, + }), + ]) + + return connectionFromArray( + quotes, + random ? { first: take } : input, + totalCount + ) +} + +export default resolver diff --git a/src/queries/comment/campaign/discussion.ts b/src/queries/comment/campaign/discussion.ts new file mode 100644 index 000000000..939dd6b10 --- /dev/null +++ b/src/queries/comment/campaign/discussion.ts @@ -0,0 +1,88 @@ +import type { CommentFilter } from '#connectors/index.js' +import type { GQLWritingChallengeResolvers } from '#definitions/index.js' + +import { COMMENT_TYPE } from '#common/enums/index.js' +import { + connectionFromArray, + connectionFromArrayWithKeys, + cursorToKeys, + fromGlobalId, +} from '#common/utils/index.js' + +// Campaign discussion is public to read: unlike circle discussion, there is no +// membership check here. Write permission is enforced in the putComment mutation. +const resolver: GQLWritingChallengeResolvers['discussion'] = async ( + { id }, + { input: { sort, first, ...rest } }, + { dataSources: { atomService, commentService } } +) => { + if (!id) { + return connectionFromArray([], rest) + } + + // resolve sort to order + const order = sort === 'oldest' ? 'asc' : 'desc' + + // set default for first in forward pagination. use null for query all. + // TODO: use "last" for backward pagination + if (!rest.before && typeof first === 'undefined') { + first = 10 + } + + // handle pagination + let before + let after + if (rest.after) { + after = cursorToKeys(rest.after).idCursor?.toString() + } + if (rest.before) { + before = cursorToKeys(rest.before).idCursor?.toString() + } + + // handle filter + const { id: targetTypeId } = await atomService.findFirst({ + table: 'entity_type', + where: { table: 'campaign' }, + }) + + const where = { + type: COMMENT_TYPE.campaignDiscussion, + targetId: id, + targetTypeId, + parentCommentId: null, + } as CommentFilter + + if (rest.filter) { + const { parentComment, author, state } = rest.filter + if (parentComment || parentComment === null) { + where.parentCommentId = parentComment + ? fromGlobalId(parentComment).id + : null + } + if (author) { + where.authorId = fromGlobalId(author).id + } + if (state) { + where.state = state + } + } + + const [comments, totalCount] = await commentService.find({ + sort, + before, + after, + first, + where, + order, + includeAfter: rest.includeAfter, + includeBefore: rest.includeBefore, + }) + + if (!comments.length) { + return connectionFromArray([], rest) + } + + return connectionFromArrayWithKeys(comments, rest, totalCount) +} + +export default resolver diff --git a/src/queries/comment/campaign/discussionCount.ts b/src/queries/comment/campaign/discussionCount.ts new file mode 100644 index 000000000..eca085749 --- /dev/null +++ b/src/queries/comment/campaign/discussionCount.ts @@ -0,0 +1,11 @@ +import type { GQLWritingChallengeResolvers } from '#definitions/index.js' + +import { COMMENT_TYPE } from '#common/enums/index.js' + +const resolver: GQLWritingChallengeResolvers['discussionCount'] = async ( + { id }, + _, + { dataSources: { commentService } } +) => commentService.count(id, COMMENT_TYPE.campaignDiscussion) + +export default resolver diff --git a/src/queries/comment/node.ts b/src/queries/comment/node.ts index 5bed1d9c3..8b64d4037 100644 --- a/src/queries/comment/node.ts +++ b/src/queries/comment/node.ts @@ -18,6 +18,9 @@ const resolver: GQLCommentResolvers['node'] = async ( } else if (type === COMMENT_TYPE.moment) { const moment = await atomService.momentIdLoader.load(targetId) return { ...moment, __type: 'Moment' } + } else if (type === COMMENT_TYPE.campaignDiscussion) { + const campaign = await atomService.campaignIdLoader.load(targetId) + return { ...campaign, __type: 'WritingChallenge' } } else { const circle = await atomService.findFirst({ table: 'circle', diff --git a/src/queries/index.ts b/src/queries/index.ts index c37b7cda1..27d7eb213 100644 --- a/src/queries/index.ts +++ b/src/queries/index.ts @@ -11,6 +11,7 @@ import moment from './moment/index.js' import notice from './notice/index.js' import oauthClient from './oauthClient/index.js' import oauthRequestToken from './oauthRequestToken.js' +import quote from './quote/index.js' import recommendation from './recommendation.js' import response from './response/index.js' import scalars from './scalars.js' @@ -32,6 +33,7 @@ export default merge( exchangeRates, recommendation, moment, + quote, campaign, channel ) diff --git a/src/queries/quote/index.ts b/src/queries/quote/index.ts new file mode 100644 index 000000000..b8cad6531 --- /dev/null +++ b/src/queries/quote/index.ts @@ -0,0 +1,17 @@ +import type { GQLResolvers } from '#definitions/index.js' + +import { NODE_TYPES } from '#common/enums/index.js' +import { toGlobalId } from '#common/utils/index.js' + +const schema: GQLResolvers = { + Quote: { + id: ({ id }) => toGlobalId({ type: NODE_TYPES.Quote, id }), + article: ({ articleId }, _, { dataSources: { atomService } }) => + atomService.articleIdLoader.load(articleId), + poster: ({ userId }, _, { dataSources: { atomService } }) => + atomService.userIdLoader.load(userId), + createdAt: ({ createdAt }) => createdAt, + }, +} + +export default schema diff --git a/src/queries/system/index.ts b/src/queries/system/index.ts index e5fdf6cdd..0c5fd059d 100644 --- a/src/queries/system/index.ts +++ b/src/queries/system/index.ts @@ -14,6 +14,11 @@ import { announcements, features, translations } from './official/index.js' import OSS from './oss/index.js' import report from './report.js' import search from './search.js' +import { + SpamRing, + SpamRingMember, + SpamRingEvent, +} from './spamRing/index.js' const system: GQLResolvers = { Query: { @@ -50,6 +55,9 @@ const system: GQLResolvers = { }, OSS, Report: report, + SpamRing, + SpamRingMember, + SpamRingEvent, } export default system diff --git a/src/queries/system/oss/articles.ts b/src/queries/system/oss/articles.ts index af1f44119..0536dbab2 100644 --- a/src/queries/system/oss/articles.ts +++ b/src/queries/system/oss/articles.ts @@ -93,6 +93,12 @@ export const articles: GQLOssResolvers['articles'] = async ( orderBy = { column, order: 'desc' } break } + case 'mostSpam': { + // rank scored articles by spam score, high to low + query = query.whereNotNull('spam_score') + orderBy = { column: 'spamScore', order: 'desc' } + break + } default: break } diff --git a/src/queries/system/oss/comments.ts b/src/queries/system/oss/comments.ts index b22db9c61..cf4f0a265 100644 --- a/src/queries/system/oss/comments.ts +++ b/src/queries/system/oss/comments.ts @@ -1,26 +1,31 @@ import type { GQLOssResolvers } from '#definitions/index.js' -import { - connectionFromPromisedArray, - fromConnectionArgs, -} from '#common/utils/index.js' +import { connectionFromQuery } from '#common/utils/index.js' export const comments: GQLOssResolvers['comments'] = async ( _, { input }, { dataSources: { commentService } } ) => { - const { take, skip } = fromConnectionArgs(input) + let query = commentService.findComments() - const totalCount = await commentService.baseCount() + const range = input?.filter?.datetimeRange + if (range?.start) { + query = query.where('created_at', '>=', range.start) + } + if (range?.end) { + query = query.where('created_at', '<=', range.end) + } - return connectionFromPromisedArray( - commentService.baseFind({ - skip, - take, - orderBy: [{ column: 'id', order: 'desc' }], - }), - input, - totalCount - ) + let orderBy: { column: string; order: 'asc' | 'desc' } = { + column: 'id', + order: 'desc', + } + if (input?.sort === 'mostSpam') { + // rank scored comments by spam score, high to low + query = query.whereNotNull('spam_score') + orderBy = { column: 'spamScore', order: 'desc' } + } + + return connectionFromQuery({ query, args: input, orderBy }) } diff --git a/src/queries/system/oss/index.ts b/src/queries/system/oss/index.ts index c989181d3..b8c8df3d9 100644 --- a/src/queries/system/oss/index.ts +++ b/src/queries/system/oss/index.ts @@ -9,6 +9,7 @@ import { reports } from './reports.js' import { restrictedUsers } from './restrictedUsers.js' import { seedingUsers } from './seedingUsers.js' import { skippedListItems } from './skippedListItems.js' +import { spamRings } from './spamRings.js' import { tags } from './tags.js' import { topicChannelFeedbacks } from './topicChannelFeedbacks.js' import { users } from './users.js' @@ -26,6 +27,7 @@ export default { skippedListItems, restrictedUsers, reports, + spamRings, icymiTopics, topicChannelFeedbacks, } diff --git a/src/queries/system/oss/moments.ts b/src/queries/system/oss/moments.ts index 6af5bfc5d..688439898 100644 --- a/src/queries/system/oss/moments.ts +++ b/src/queries/system/oss/moments.ts @@ -7,9 +7,25 @@ export const moments: GQLOssResolvers['moments'] = async ( { input }, { dataSources: { momentService } } ) => { - return connectionFromQuery({ - query: momentService.findMoments(), - orderBy: { column: 'id', order: 'desc' }, - args: input, - }) + let query = momentService.findMoments() + + const range = input?.filter?.datetimeRange + if (range?.start) { + query = query.where('created_at', '>=', range.start) + } + if (range?.end) { + query = query.where('created_at', '<=', range.end) + } + + let orderBy: { column: string; order: 'asc' | 'desc' } = { + column: 'id', + order: 'desc', + } + if (input?.sort === 'mostSpam') { + // rank scored moments by spam score, high to low + query = query.whereNotNull('spam_score') + orderBy = { column: 'spamScore', order: 'desc' } + } + + return connectionFromQuery({ query, args: input, orderBy }) } diff --git a/src/queries/system/oss/spamRings.ts b/src/queries/system/oss/spamRings.ts new file mode 100644 index 000000000..d1acef1a6 --- /dev/null +++ b/src/queries/system/oss/spamRings.ts @@ -0,0 +1,30 @@ +import type { GQLOssResolvers } from '#definitions/index.js' +import type { Knex } from 'knex' + +import { connectionFromQuery } from '#common/utils/connections.js' + +export const spamRings: GQLOssResolvers['spamRings'] = async ( + _, + { input }, + { dataSources: { spamRingService } } +) => { + const query: Knex.QueryBuilder = spamRingService.findRings({ + status: input?.filter?.status ?? undefined, + }) + + let orderBy: { column: string; order: 'asc' | 'desc' } + switch (input?.sort) { + case 'detectedAt': + orderBy = { column: 'detectedAt', order: 'desc' } + break + case 'nAuthors': + orderBy = { column: 'nAuthors', order: 'desc' } + break + case 'score': + default: + orderBy = { column: 'score', order: 'desc' } + break + } + + return connectionFromQuery({ query, args: input, orderBy }) +} diff --git a/src/queries/system/spamRing/index.ts b/src/queries/system/spamRing/index.ts new file mode 100644 index 000000000..9c4eed19e --- /dev/null +++ b/src/queries/system/spamRing/index.ts @@ -0,0 +1,53 @@ +import type { + GQLSpamRingResolvers, + GQLSpamRingMemberResolvers, + GQLSpamRingEventResolvers, + User, +} from '#definitions/index.js' + +import { NODE_TYPES } from '#common/enums/index.js' +import { + connectionFromArray, + fromConnectionArgs, + toGlobalId, +} from '#common/utils/index.js' + +export const SpamRing: GQLSpamRingResolvers = { + id: ({ id }) => toGlobalId({ type: NODE_TYPES.SpamRing, id }), + frozenBy: ({ frozenBy }, _, { dataSources: { atomService } }) => + frozenBy ? atomService.userIdLoader.load(frozenBy) : null, + members: async ({ id }, { input }, { dataSources: { spamRingService } }) => { + const { take, skip } = fromConnectionArgs(input) + const [members, totalCount] = await spamRingService.findMembersAndCount( + id, + { take, skip } + ) + return connectionFromArray(members, input, totalCount) + }, + memberSample: async ( + { id }, + { limit }, + { dataSources: { atomService, spamRingService } } + ) => { + const members = await spamRingService.findMembers(id, limit ?? 5) + const users = await Promise.all( + members.map((m) => atomService.userIdLoader.load(m.userId)) + ) + return users.filter((u): u is User => Boolean(u)) + }, + events: ({ id }, _, { dataSources: { spamRingService } }) => + spamRingService.findEvents(id), +} + +export const SpamRingMember: GQLSpamRingMemberResolvers = { + id: ({ id }) => toGlobalId({ type: NODE_TYPES.SpamRingMember, id }), + user: ({ userId }, _, { dataSources: { atomService } }) => + atomService.userIdLoader.load(userId), +} + +export const SpamRingEvent: GQLSpamRingEventResolvers = { + id: ({ id }) => toGlobalId({ type: NODE_TYPES.SpamRingEvent, id }), + actor: ({ actorId }, _, { dataSources: { atomService } }) => + actorId ? atomService.userIdLoader.load(actorId) : null, + detail: ({ detail }) => (detail ? JSON.stringify(detail) : null), +} diff --git a/src/routes/graphql.ts b/src/routes/graphql.ts index 4e235d8a6..06df85ac2 100644 --- a/src/routes/graphql.ts +++ b/src/routes/graphql.ts @@ -34,6 +34,7 @@ import { LikeCoin, ExchangeRate, FederationExportService, + SpamRingService, } from '#connectors/index.js' import { RevisionQueue, @@ -165,6 +166,7 @@ export const graphql = async (app: Express) => { notificationService: new NotificationService(connections), searchService: new SearchService(connections), federationExportService: new FederationExportService(connections), + spamRingService: new SpamRingService(connections), connections, queues, } diff --git a/src/types/__test__/2/auth.test.ts b/src/types/__test__/2/auth.test.ts index fe190d800..906a4050a 100644 --- a/src/types/__test__/2/auth.test.ts +++ b/src/types/__test__/2/auth.test.ts @@ -7,8 +7,10 @@ import { AUTH_MODE, NODE_TYPES, SCOPE_PREFIX, + USER_ROLE, VERIFICATION_CODE_STATUS, } from '#common/enums/index.js' +import { environment } from '#common/environment.js' import { toGlobalId } from '#common/utils/index.js' import { UserService, SystemService } from '#connectors/index.js' @@ -1161,6 +1163,89 @@ describe('socialLogin with Threads', () => { }) }) +describe('socialLogin with Google (OSS SSO)', () => { + const SOCIAL_LOGIN = /* GraphQL */ ` + mutation ($input: SocialLoginInput!) { + socialLogin(input: $input) { + auth + token + } + } + ` + const OSS_REDIRECT_URI = 'https://oss.matters.icu/callback/google' + + beforeAll(() => { + // simulate MATTERS_OSS_GOOGLE_REDIRECT_URIS being configured + if (!environment.ossGoogleRedirectUris.includes(OSS_REDIRECT_URI)) { + environment.ossGoogleRedirectUris.push(OSS_REDIRECT_URI) + } + }) + + // A redirectUri that is not in the allowlist must be rejected before token + // exchange, guarding against an attacker-controlled redirect_uri. + test('rejects a non-allowlisted redirectUri', async () => { + const server = await testClient({ connections }) + const { errors } = await server.executeOperation({ + query: SOCIAL_LOGIN, + variables: { + input: { + type: 'Google', + authorizationCode: 'e2etest-oss-google', + nonce: 'e2etest-nonce', + redirectUri: 'https://attacker.example/callback/google', + }, + }, + }) + expect(errors && errors.length).toBeGreaterThanOrEqual(1) + expect(errors?.[0]?.message).toContain('redirectUri') + }) + + // OSS login must be restricted to existing admin accounts; an unknown or + // non-admin Google account is rejected and never auto-created. + test('rejects a non-admin account', async () => { + const server = await testClient({ connections }) + const { errors } = await server.executeOperation({ + query: SOCIAL_LOGIN, + variables: { + input: { + type: 'Google', + authorizationCode: 'e2etest-oss-nonadmin', + nonce: 'e2etest-nonce', + redirectUri: OSS_REDIRECT_URI, + }, + }, + }) + expect(errors && errors.length).toBeGreaterThanOrEqual(1) + expect(errors?.[0]?.message).toContain('admin') + }) + + // An existing admin account whose verified Google email matches logs in. + test('logs in an existing admin account', async () => { + const code = 'e2etest-oss-admin' + const email = `${code}@gmail.com` + const created = await userService.create({ email, emailVerified: true }) + await userService.baseUpdate(created.id, { + role: USER_ROLE.admin as 'admin', + }) + + const server = await testClient({ connections }) + const { data, errors } = await server.executeOperation({ + query: SOCIAL_LOGIN, + variables: { + input: { + type: 'Google', + authorizationCode: code, + nonce: 'e2etest-nonce', + redirectUri: OSS_REDIRECT_URI, + }, + }, + }) + expect(errors).toBeUndefined() + expect(data?.socialLogin.auth).toBe(true) + expect(data?.socialLogin.token).toBeTruthy() + }) +}) + describe('add social accounts', () => { const ADD_SOCIAL_LOGIN = /* GraphQL */ ` mutation ($input: SocialLoginInput!) { diff --git a/src/types/__test__/2/campaignComment.test.ts b/src/types/__test__/2/campaignComment.test.ts new file mode 100644 index 000000000..26fc5db98 --- /dev/null +++ b/src/types/__test__/2/campaignComment.test.ts @@ -0,0 +1,611 @@ +import type { Connections, Campaign } from '#definitions/index.js' + +import { v4 as uuidv4 } from 'uuid' + +import { + CAMPAIGN_STATE, + CAMPAIGN_USER_STATE, + COMMENT_STATE, + COMMENT_TYPE, + MAX_CAMPAIGN_COMMENT_LENGTH, + NODE_TYPES, +} from '#common/enums/index.js' +import { + AtomService, + CampaignService, + CommentService, +} from '#connectors/index.js' +import { toGlobalId } from '#common/utils/index.js' + +import { testClient, genConnections, closeConnections } from '../utils.js' + +let connections: Connections +let atomService: AtomService +let campaignService: CampaignService +let commentService: CommentService + +beforeAll(async () => { + connections = await genConnections() + atomService = new AtomService(connections) + campaignService = new CampaignService(connections) + commentService = new CommentService(connections) +}, 30000) + +afterAll(async () => { + await closeConnections(connections) +}) + +const PUT_COMMENT = /* GraphQL */ ` + mutation ($input: PutCommentInput!) { + putComment(input: $input) { + id + node { + ... on Campaign { + id + } + } + } + } +` + +const DELETE_COMMENT = /* GraphQL */ ` + mutation ($input: DeleteCommentInput!) { + deleteComment(input: $input) { + state + } + } +` + +const VOTE_COMMENT = /* GraphQL */ ` + mutation ($input: VoteCommentInput!) { + voteComment(input: $input) { + id + upvotes + downvotes + } + } +` + +const UNVOTE_COMMENT = /* GraphQL */ ` + mutation ($input: UnvoteCommentInput!) { + unvoteComment(input: $input) { + id + upvotes + downvotes + } + } +` + +const TOGGLE_PIN_COMMENT = /* GraphQL */ ` + mutation ($input: ToggleItemInput!) { + togglePinComment(input: $input) { + id + pinned + } + } +` + +const baseCampaignData = { + name: 'test campaign discussion', + applicationPeriod: [new Date('2024-01-01'), new Date('2024-01-02')] as const, + writingPeriod: [new Date('2024-01-03'), new Date('2024-01-04')] as const, +} + +// directly set a campaign_user record to a given state, bypassing the +// auto-approve flow in campaignService.apply (which always succeeds) +const setApplicationState = async ( + campaignId: string, + userId: string, + state: (typeof CAMPAIGN_USER_STATE)[keyof typeof CAMPAIGN_USER_STATE] +) => { + const existing = await atomService.findFirst({ + table: 'campaign_user', + where: { campaignId, userId }, + }) + if (existing) { + return atomService.update({ + table: 'campaign_user', + where: { id: existing.id }, + data: { state }, + }) + } + return atomService.create({ + table: 'campaign_user', + data: { campaignId, userId, state }, + }) +} + +const createCampaignComment = async ( + campaign: Campaign, + authorId: string, + state: (typeof COMMENT_STATE)[keyof typeof COMMENT_STATE] = COMMENT_STATE.active, + parentCommentId: string | null = null +) => { + const { id: targetTypeId } = await atomService.findFirst({ + table: 'entity_type', + where: { table: 'campaign' }, + }) + return atomService.create({ + table: 'comment', + data: { + uuid: uuidv4(), + content: '

campaign discussion comment

', + authorId, + targetId: campaign.id, + targetTypeId, + parentCommentId, + type: COMMENT_TYPE.campaignDiscussion, + state, + }, + }) +} + +describe('put campaignDiscussion comment', () => { + // existing seeded users with usernames + const participantId = '2' + const nonParticipantId = '3' + const pendingId = '4' + const rejectedId = '5' + const creatorId = '1' + const organizerId = '6' + const managerId = '7' + + let campaign: Campaign + let campaignGlobalId: string + + const putCampaignComment = async (userId: string, campaignId: string) => { + const server = await testClient({ userId, isAuth: true, connections }) + return server.executeOperation({ + query: PUT_COMMENT, + variables: { + input: { + comment: { + content: 'test campaign discussion comment', + campaignId, + type: 'campaignDiscussion', + }, + }, + }, + }) + } + + beforeAll(async () => { + campaign = await campaignService.createWritingChallenge({ + ...baseCampaignData, + creatorId, + state: CAMPAIGN_STATE.active, + organizerIds: [organizerId], + managerIds: [managerId], + }) + campaignGlobalId = toGlobalId({ + type: NODE_TYPES.Campaign, + id: campaign.id, + }) + await setApplicationState( + campaign.id, + participantId, + CAMPAIGN_USER_STATE.succeeded + ) + await setApplicationState( + campaign.id, + pendingId, + CAMPAIGN_USER_STATE.pending + ) + await setApplicationState( + campaign.id, + rejectedId, + CAMPAIGN_USER_STATE.rejected + ) + }) + + test('succeeded participant can comment', async () => { + const { errors, data } = await putCampaignComment( + participantId, + campaignGlobalId + ) + expect(errors).toBeUndefined() + expect(data.putComment.id).toBeDefined() + expect(data.putComment.node.id).toBe(campaignGlobalId) + }) + + test('creator/organizer/manager can comment', async () => { + for (const userId of [creatorId, organizerId, managerId]) { + const { errors, data } = await putCampaignComment( + userId, + campaignGlobalId + ) + expect(errors).toBeUndefined() + expect(data.putComment.id).toBeDefined() + } + }) + + // the discussion is open to every logged-in user (the participant-only + // restriction was relaxed), so non-participant / pending / rejected may comment + test('non-participant can comment', async () => { + const { errors, data } = await putCampaignComment( + nonParticipantId, + campaignGlobalId + ) + expect(errors).toBeUndefined() + expect(data.putComment.id).toBeDefined() + }) + + test('pending applicant can comment', async () => { + const { errors, data } = await putCampaignComment( + pendingId, + campaignGlobalId + ) + expect(errors).toBeUndefined() + expect(data.putComment.id).toBeDefined() + }) + + test('rejected applicant can comment', async () => { + const { errors, data } = await putCampaignComment( + rejectedId, + campaignGlobalId + ) + expect(errors).toBeUndefined() + expect(data.putComment.id).toBeDefined() + }) + + test('can not comment on archived campaign', async () => { + const archivedCampaign = await campaignService.createWritingChallenge({ + ...baseCampaignData, + creatorId, + state: CAMPAIGN_STATE.archived, + }) + await setApplicationState( + archivedCampaign.id, + participantId, + CAMPAIGN_USER_STATE.succeeded + ) + const { errors } = await putCampaignComment( + participantId, + toGlobalId({ type: NODE_TYPES.Campaign, id: archivedCampaign.id }) + ) + expect(errors?.[0].extensions.code).toBe('FORBIDDEN_BY_TARGET_STATE') + }) + + test('finished and pending campaigns accept comments', async () => { + for (const state of [CAMPAIGN_STATE.finished, CAMPAIGN_STATE.pending]) { + const c = await campaignService.createWritingChallenge({ + ...baseCampaignData, + creatorId, + state, + }) + await setApplicationState( + c.id, + participantId, + CAMPAIGN_USER_STATE.succeeded + ) + const { errors, data } = await putCampaignComment( + participantId, + toGlobalId({ type: NODE_TYPES.Campaign, id: c.id }) + ) + expect(errors).toBeUndefined() + expect(data.putComment.id).toBeDefined() + } + }) + + test('campaignId is required for campaignDiscussion type', async () => { + const server = await testClient({ + userId: participantId, + isAuth: true, + connections, + }) + const { errors } = await server.executeOperation({ + query: PUT_COMMENT, + variables: { + input: { + comment: { + content: 'test campaign discussion comment', + type: 'campaignDiscussion', + }, + }, + }, + }) + expect(errors?.[0].extensions.code).toBe('BAD_USER_INPUT') + }) + + test('can not comment on non-existing campaign', async () => { + const { errors } = await putCampaignComment( + participantId, + toGlobalId({ type: NODE_TYPES.Campaign, id: '99999999' }) + ) + expect(errors?.[0].extensions.code).toBe('CAMPAIGN_NOT_FOUND') + }) + + test('content exceeding length limit is rejected', async () => { + const server = await testClient({ + userId: participantId, + isAuth: true, + connections, + }) + const { errors } = await server.executeOperation({ + query: PUT_COMMENT, + variables: { + input: { + comment: { + content: 'x'.repeat(MAX_CAMPAIGN_COMMENT_LENGTH + 1), + campaignId: campaignGlobalId, + type: 'campaignDiscussion', + }, + }, + }, + }) + expect(errors?.[0].extensions.code).toBe('BAD_USER_INPUT') + }) +}) + +describe('vote/unvote campaignDiscussion comment', () => { + const participantId = '2' + const nonParticipantId = '3' + const organizerId = '6' + let campaign: Campaign + let comment: { id: string } + + beforeAll(async () => { + campaign = await campaignService.createWritingChallenge({ + ...baseCampaignData, + creatorId: '1', + state: CAMPAIGN_STATE.active, + organizerIds: [organizerId], + }) + await setApplicationState( + campaign.id, + participantId, + CAMPAIGN_USER_STATE.succeeded + ) + comment = await createCampaignComment(campaign, participantId) + }) + + test('participant can upvote a campaign discussion comment (no circle fallthrough)', async () => { + const server = await testClient({ + userId: participantId, + isAuth: true, + connections, + }) + const { errors, data } = await server.executeOperation({ + query: VOTE_COMMENT, + variables: { + input: { + id: toGlobalId({ type: NODE_TYPES.Comment, id: comment.id }), + vote: 'up', + }, + }, + }) + expect(errors).toBeUndefined() + expect(data.voteComment.upvotes).toBe(1) + expect(data.voteComment.downvotes).toBe(0) + + const upvotes = await commentService.countUpVote(comment.id) + expect(upvotes).toBe(1) + }) + + test('participant can unvote a campaign discussion comment', async () => { + const server = await testClient({ + userId: participantId, + isAuth: true, + connections, + }) + const { errors, data } = await server.executeOperation({ + query: UNVOTE_COMMENT, + variables: { + input: { + id: toGlobalId({ type: NODE_TYPES.Comment, id: comment.id }), + }, + }, + }) + expect(errors).toBeUndefined() + expect(data.unvoteComment.upvotes).toBe(0) + + const upvotes = await commentService.countUpVote(comment.id) + expect(upvotes).toBe(0) + }) + + test('non-participant can not upvote a campaign discussion comment', async () => { + const server = await testClient({ + userId: nonParticipantId, + isAuth: true, + connections, + }) + const { errors } = await server.executeOperation({ + query: VOTE_COMMENT, + variables: { + input: { + id: toGlobalId({ type: NODE_TYPES.Comment, id: comment.id }), + vote: 'up', + }, + }, + }) + expect(errors?.[0].extensions.code).toBe('FORBIDDEN') + }) + + test('organizer (non-participant) can upvote a campaign discussion comment', async () => { + const server = await testClient({ + userId: organizerId, + isAuth: true, + connections, + }) + const { errors, data } = await server.executeOperation({ + query: VOTE_COMMENT, + variables: { + input: { + id: toGlobalId({ type: NODE_TYPES.Comment, id: comment.id }), + vote: 'up', + }, + }, + }) + expect(errors).toBeUndefined() + expect(data.voteComment.upvotes).toBe(1) + }) + + test('non-participant can not unvote a campaign discussion comment', async () => { + const server = await testClient({ + userId: nonParticipantId, + isAuth: true, + connections, + }) + const { errors } = await server.executeOperation({ + query: UNVOTE_COMMENT, + variables: { + input: { + id: toGlobalId({ type: NODE_TYPES.Comment, id: comment.id }), + }, + }, + }) + expect(errors?.[0].extensions.code).toBe('FORBIDDEN') + }) +}) + +describe('delete campaignDiscussion comment', () => { + const authorId = '2' + const otherUserId = '3' + const creatorId = '1' + const organizerId = '6' + const managerId = '7' + + let campaign: Campaign + + const deleteComment = async (userId: string, commentId: string) => { + const server = await testClient({ userId, isAuth: true, connections }) + return server.executeOperation({ + query: DELETE_COMMENT, + variables: { + input: { id: toGlobalId({ type: NODE_TYPES.Comment, id: commentId }) }, + }, + }) + } + + beforeAll(async () => { + campaign = await campaignService.createWritingChallenge({ + ...baseCampaignData, + creatorId, + state: CAMPAIGN_STATE.active, + organizerIds: [organizerId], + managerIds: [managerId], + }) + await setApplicationState( + campaign.id, + authorId, + CAMPAIGN_USER_STATE.succeeded + ) + }) + + test('comment author can delete own comment', async () => { + const comment = await createCampaignComment(campaign, authorId) + const { errors, data } = await deleteComment(authorId, comment.id) + expect(errors).toBeUndefined() + expect(data.deleteComment.state).toBe(COMMENT_STATE.archived) + }) + + test('creator/organizer/manager can delete others comments', async () => { + for (const userId of [creatorId, organizerId, managerId]) { + const comment = await createCampaignComment(campaign, authorId) + const { errors, data } = await deleteComment(userId, comment.id) + expect(errors).toBeUndefined() + expect(data.deleteComment.state).toBe(COMMENT_STATE.archived) + } + }) + + test('unrelated user can not delete others comment', async () => { + const comment = await createCampaignComment(campaign, authorId) + const { errors } = await deleteComment(otherUserId, comment.id) + expect(errors?.[0].extensions.code).toBe('FORBIDDEN') + }) +}) + +describe('pin campaignDiscussion comment', () => { + test('togglePinComment on a campaign discussion comment is forbidden', async () => { + const campaign = await campaignService.createWritingChallenge({ + ...baseCampaignData, + creatorId: '1', + state: CAMPAIGN_STATE.active, + }) + const comment = await createCampaignComment(campaign, '1') + const server = await testClient({ userId: '1', isAuth: true, connections }) + const { errors } = await server.executeOperation({ + query: TOGGLE_PIN_COMMENT, + variables: { + input: { + id: toGlobalId({ type: NODE_TYPES.Comment, id: comment.id }), + enabled: true, + }, + }, + }) + expect(errors?.[0].extensions.code).toBe('FORBIDDEN') + }) +}) + +describe('query campaign discussion list and count', () => { + const QUERY_DISCUSSION = /* GraphQL */ ` + query ($input: CampaignInput!, $commentsInput: CommentsInput!) { + campaign(input: $input) { + id + ... on WritingChallenge { + discussionCount + discussion(input: $commentsInput) { + totalCount + edges { + node { + id + state + } + } + } + } + } + } + ` + + const authorId = '2' + let campaign: Campaign + + beforeAll(async () => { + campaign = await campaignService.createWritingChallenge({ + ...baseCampaignData, + creatorId: '1', + state: CAMPAIGN_STATE.active, + }) + await setApplicationState( + campaign.id, + authorId, + CAMPAIGN_USER_STATE.succeeded + ) + // 2 active top-level comments, 1 archived, 1 banned + await createCampaignComment(campaign, authorId, COMMENT_STATE.active) + await createCampaignComment(campaign, authorId, COMMENT_STATE.active) + await createCampaignComment(campaign, authorId, COMMENT_STATE.archived) + await createCampaignComment(campaign, authorId, COMMENT_STATE.banned) + }) + + test('archived/banned comments are excluded from public list', async () => { + const server = await testClient({ connections }) + const { errors, data } = await server.executeOperation({ + query: QUERY_DISCUSSION, + variables: { + input: { shortHash: campaign.shortHash }, + commentsInput: { first: 10 }, + }, + }) + expect(errors).toBeUndefined() + const states = data.campaign.discussion.edges.map((e: any) => e.node.state) + expect(states).not.toContain(COMMENT_STATE.archived) + expect(states).not.toContain(COMMENT_STATE.banned) + expect(states.length).toBe(2) + }) + + test('discussionCount counts active/collapsed comments', async () => { + const server = await testClient({ connections }) + const { errors, data } = await server.executeOperation({ + query: QUERY_DISCUSSION, + variables: { + input: { shortHash: campaign.shortHash }, + commentsInput: { first: 10 }, + }, + }) + expect(errors).toBeUndefined() + // count is by service.count: active + collapsed only + expect(data.campaign.discussionCount).toBe(2) + }) +}) diff --git a/src/types/__test__/2/quote.test.ts b/src/types/__test__/2/quote.test.ts new file mode 100644 index 000000000..c892725d1 --- /dev/null +++ b/src/types/__test__/2/quote.test.ts @@ -0,0 +1,489 @@ +import type { Connections, Campaign, Article } from '#definitions/index.js' + +import { + NODE_TYPES, + USER_STATE, + CAMPAIGN_STATE, + QUOTE_STATE, + QUOTE_DAILY_LIMIT, + QUOTE_PER_ARTICLE_LIMIT, +} from '#common/enums/index.js' +import { toGlobalId, fromGlobalId } from '#common/utils/index.js' +import { AtomService, CampaignService } from '#connectors/index.js' + +import { genConnections, closeConnections, testClient } from '../utils.js' + +let connections: Connections +let atomService: AtomService +let campaignService: CampaignService + +// seed article #1 (author = user #1, license cc_by_nc_nd_4) has content +// "
some html string
". excerpts below are all valid sub-strings, +// which matters because putQuote rejects anything that is not an excerpt. +const ARTICLE_DB_ID = '1' +const articleGlobalId = toGlobalId({ + type: NODE_TYPES.Article, + id: ARTICLE_DB_ID, +}) + +// poster is user #2 so that "poster", "article author" and "other" are three +// distinct identities for the deleteQuote permission matrix. +const posterUser = { id: '2', state: USER_STATE.active, userName: 'test2' } + +const campaignData = { + name: 'quote test campaign', + applicationPeriod: [new Date('2024-01-01'), new Date('2024-01-02')] as const, + writingPeriod: [new Date('2024-01-03'), new Date('2024-01-04')] as const, + creatorId: '1', + state: CAMPAIGN_STATE.active, + // the quote wall is opt-in per campaign; the seed campaign has it enabled + enableQuoteWall: true, +} + +let campaign: Campaign + +// put the seed article onto a campaign wall so putQuote's campaign gate passes +const setupCampaignWithArticle = async () => { + const article = (await atomService.findFirst({ + table: 'article', + where: { id: ARTICLE_DB_ID }, + })) as Article + const _campaign = await campaignService.createWritingChallenge(campaignData) + const _stages = await campaignService.updateStages(_campaign.id, [ + { name: 'stage1' }, + ]) + await campaignService.apply(_campaign, { + id: article.authorId, + userName: 'test1', + state: USER_STATE.active, + }) + await campaignService.submitArticleToCampaign( + article, + _campaign.id, + _stages[0].id + ) + return _campaign +} + +beforeAll(async () => { + connections = await genConnections() + atomService = new AtomService(connections) + campaignService = new CampaignService(connections) + campaign = await setupCampaignWithArticle() +}, 30000) + +afterAll(async () => { + await closeConnections(connections) +}) + +// remove every quote between tests so per-article / daily caps and dedupe +// start from a clean slate each time +afterEach(async () => { + await connections.knex('quote').del() +}) + +const PUT_QUOTE = /* GraphQL */ ` + mutation ($input: PutQuoteInput!) { + putQuote(input: $input) { + id + content + article { + id + } + poster { + id + } + } + } +` + +const DELETE_QUOTE = /* GraphQL */ ` + mutation ($input: DeleteQuoteInput!) { + deleteQuote(input: $input) + } +` + +// create a quote row directly, bypassing the resolver, for delete/query tests +const seedQuote = async ({ + content, + userId = posterUser.id, + state = QUOTE_STATE.active, + campaignId = campaign.id, + articleId = ARTICLE_DB_ID, +}: { + content: string + userId?: string + state?: keyof typeof QUOTE_STATE + campaignId?: string + articleId?: string +}) => + atomService.create({ + table: 'quote', + data: { content, articleId, campaignId, userId, state }, + }) + +describe('putQuote', () => { + test('happy path: logged-in user puts an excerpt onto the wall', async () => { + const server = await testClient({ + connections, + context: { viewer: posterUser }, + isAuth: true, + }) + const content = 'some html string' + const { errors, data } = await server.executeOperation({ + query: PUT_QUOTE, + variables: { input: { articleId: articleGlobalId, content } }, + }) + expect(errors).toBeUndefined() + expect(data.putQuote.content).toBe(content) + expect(data.putQuote.article.id).toBe(articleGlobalId) + expect(data.putQuote.poster.id).toBe( + toGlobalId({ type: NODE_TYPES.User, id: posterUser.id }) + ) + + // persisted with the correct campaign attribution + const { id: quoteDbId } = fromGlobalId(data.putQuote.id) + const row = await atomService.findFirst({ + table: 'quote', + where: { id: quoteDbId }, + }) + expect(row.campaignId).toBe(campaign.id) + expect(row.userId).toBe(posterUser.id) + expect(row.state).toBe(QUOTE_STATE.active) + }) + + test('rejects posting when the campaign has no quote wall', async () => { + // temporarily disable the wall on the seed campaign + await atomService.update({ + table: 'campaign', + where: { id: campaign.id }, + data: { enableQuoteWall: false }, + }) + try { + const server = await testClient({ + connections, + context: { viewer: posterUser }, + isAuth: true, + }) + const { errors } = await server.executeOperation({ + query: PUT_QUOTE, + variables: { + input: { articleId: articleGlobalId, content: 'some html string' }, + }, + }) + expect(errors).toBeDefined() + expect(errors?.[0].extensions.code).toBe('BAD_USER_INPUT') + } finally { + // restore so the rest of the suite is unaffected + await atomService.update({ + table: 'campaign', + where: { id: campaign.id }, + data: { enableQuoteWall: true }, + }) + } + }) + + test('visitors are blocked by the auth directive', async () => { + const server = await testClient({ connections, isAuth: false }) + const { errors } = await server.executeOperation({ + query: PUT_QUOTE, + variables: { + input: { articleId: articleGlobalId, content: 'some html string' }, + }, + }) + expect(errors).toBeDefined() + expect(errors.length).toBe(1) + }) + + test('content longer than the cap is rejected', async () => { + const server = await testClient({ + connections, + context: { viewer: posterUser }, + isAuth: true, + }) + const { errors } = await server.executeOperation({ + query: PUT_QUOTE, + variables: { + input: { articleId: articleGlobalId, content: 'a'.repeat(81) }, + }, + }) + expect(errors?.[0].extensions.code).toBe('BAD_USER_INPUT') + }) + + test('content that is not an excerpt of the article is rejected', async () => { + const server = await testClient({ + connections, + context: { viewer: posterUser }, + isAuth: true, + }) + const { errors } = await server.executeOperation({ + query: PUT_QUOTE, + variables: { + input: { + articleId: articleGlobalId, + content: 'this text is not in the article', + }, + }, + }) + expect(errors?.[0].extensions.code).toBe('BAD_USER_INPUT') + }) + + test('dedupe: same user + article + content is rejected on second put', async () => { + const server = await testClient({ + connections, + context: { viewer: posterUser }, + isAuth: true, + }) + const content = 'html string' + const { errors: errors1 } = await server.executeOperation({ + query: PUT_QUOTE, + variables: { input: { articleId: articleGlobalId, content } }, + }) + expect(errors1).toBeUndefined() + + const { errors: errors2 } = await server.executeOperation({ + query: PUT_QUOTE, + variables: { input: { articleId: articleGlobalId, content } }, + }) + expect(errors2?.[0].extensions.code).toBe('BAD_USER_INPUT') + + // only one row persisted + const count = await atomService.count({ + table: 'quote', + where: { userId: posterUser.id, articleId: ARTICLE_DB_ID }, + }) + expect(count).toBe(1) + }) + + test('per-article cap blocks the next quote once the limit is reached', async () => { + // pre-fill up to the per-article limit with distinct excerpts + await seedQuote({ content: 'some' }) + await seedQuote({ content: 'html' }) + expect(QUOTE_PER_ARTICLE_LIMIT).toBe(2) + + const server = await testClient({ + connections, + context: { viewer: posterUser }, + isAuth: true, + }) + const { errors } = await server.executeOperation({ + query: PUT_QUOTE, + variables: { input: { articleId: articleGlobalId, content: 'string' } }, + }) + expect(errors?.[0].extensions.code).toBe('ACTION_LIMIT_EXCEEDED') + }) + + test('daily cap blocks the next quote once the limit is reached', async () => { + // seed the daily limit worth of quotes for this user (today, any article) + expect(QUOTE_DAILY_LIMIT).toBe(5) + for (let i = 0; i < QUOTE_DAILY_LIMIT; i++) { + await seedQuote({ content: `daily-${i}` }) + } + const server = await testClient({ + connections, + context: { viewer: posterUser }, + isAuth: true, + }) + const { errors } = await server.executeOperation({ + query: PUT_QUOTE, + variables: { input: { articleId: articleGlobalId, content: 'string' } }, + }) + expect(errors?.[0].extensions.code).toBe('ACTION_LIMIT_EXCEEDED') + }) +}) + +describe('deleteQuote', () => { + test('poster can retract their own quote', async () => { + const quote = await seedQuote({ content: 'some html string' }) + const server = await testClient({ + connections, + context: { viewer: posterUser }, + isAuth: true, + }) + const { errors, data } = await server.executeOperation({ + query: DELETE_QUOTE, + variables: { + input: { id: toGlobalId({ type: NODE_TYPES.Quote, id: quote.id }) }, + }, + }) + expect(errors).toBeUndefined() + expect(data.deleteQuote).toBe(true) + + const row = await atomService.findFirst({ + table: 'quote', + where: { id: quote.id }, + }) + expect(row.state).toBe(QUOTE_STATE.archived) + }) + + test('a non-poster, non-author, non-admin is forbidden', async () => { + // quote posted by user #2 on article authored by user #1; viewer is user + // #3, who is none of poster/author/admin + const quote = await seedQuote({ content: 'some html string' }) + const other = { id: '3', state: USER_STATE.active, userName: 'test3' } + const server = await testClient({ + connections, + context: { viewer: other }, + isAuth: true, + }) + const { errors } = await server.executeOperation({ + query: DELETE_QUOTE, + variables: { + input: { id: toGlobalId({ type: NODE_TYPES.Quote, id: quote.id }) }, + }, + }) + expect(errors?.[0].extensions.code).toBe('FORBIDDEN') + }) + + test('archived quote does not leak existence: still FORBIDDEN to outsiders', async () => { + const quote = await seedQuote({ + content: 'some html string', + state: QUOTE_STATE.archived, + }) + const other = { id: '3', state: USER_STATE.active, userName: 'test3' } + const server = await testClient({ + connections, + context: { viewer: other }, + isAuth: true, + }) + const { errors } = await server.executeOperation({ + query: DELETE_QUOTE, + variables: { + input: { id: toGlobalId({ type: NODE_TYPES.Quote, id: quote.id }) }, + }, + }) + // permission is checked before the idempotent short-circuit + expect(errors?.[0].extensions.code).toBe('FORBIDDEN') + }) + + test('non-existent id yields ENTITY_NOT_FOUND', async () => { + const server = await testClient({ + connections, + context: { viewer: posterUser }, + isAuth: true, + }) + const { errors } = await server.executeOperation({ + query: DELETE_QUOTE, + variables: { + input: { id: toGlobalId({ type: NODE_TYPES.Quote, id: '9999999' }) }, + }, + }) + expect(errors?.[0].extensions.code).toBe('ENTITY_NOT_FOUND') + }) + + test('idempotent: deleting an already-archived quote (by poster) succeeds', async () => { + const quote = await seedQuote({ + content: 'some html string', + state: QUOTE_STATE.archived, + }) + const server = await testClient({ + connections, + context: { viewer: posterUser }, + isAuth: true, + }) + const { errors, data } = await server.executeOperation({ + query: DELETE_QUOTE, + variables: { + input: { id: toGlobalId({ type: NODE_TYPES.Quote, id: quote.id }) }, + }, + }) + expect(errors).toBeUndefined() + expect(data.deleteQuote).toBe(true) + }) +}) + +describe('quotes query', () => { + const QUERY_CAMPAIGN_QUOTES = /* GraphQL */ ` + query ($campaignInput: CampaignInput!, $quotesInput: QuotesInput!) { + campaign(input: $campaignInput) { + ... on WritingChallenge { + quotes(input: $quotesInput) { + totalCount + pageInfo { + hasNextPage + endCursor + } + edges { + cursor + node { + id + content + } + } + } + } + } + } + ` + + test('returns active quotes and filters out archived / banned', async () => { + await seedQuote({ content: 'some' }) + await seedQuote({ content: 'html', state: QUOTE_STATE.archived }) + await seedQuote({ content: 'string', state: QUOTE_STATE.banned }) + + const server = await testClient({ connections }) + const { errors, data } = await server.executeOperation({ + query: QUERY_CAMPAIGN_QUOTES, + variables: { + campaignInput: { shortHash: campaign.shortHash }, + quotesInput: { first: 10 }, + }, + }) + expect(errors).toBeUndefined() + expect(data.campaign.quotes.totalCount).toBe(1) + expect(data.campaign.quotes.edges.length).toBe(1) + expect(data.campaign.quotes.edges[0].node.content).toBe('some') + }) + + test('pagination: after cursor advances pages and reports hasNextPage', async () => { + await seedQuote({ content: 'some' }) + await seedQuote({ content: 'html' }) + + const server = await testClient({ connections }) + const { data, errors } = await server.executeOperation({ + query: QUERY_CAMPAIGN_QUOTES, + variables: { + campaignInput: { shortHash: campaign.shortHash }, + quotesInput: { first: 1 }, + }, + }) + expect(errors).toBeUndefined() + expect(data.campaign.quotes.totalCount).toBe(2) + expect(data.campaign.quotes.edges.length).toBe(1) + expect(data.campaign.quotes.pageInfo.hasNextPage).toBe(true) + + const { data: data2, errors: errors2 } = await server.executeOperation({ + query: QUERY_CAMPAIGN_QUOTES, + variables: { + campaignInput: { shortHash: campaign.shortHash }, + quotesInput: { + first: 1, + after: data.campaign.quotes.edges[0].cursor, + }, + }, + }) + expect(errors2).toBeUndefined() + expect(data2.campaign.quotes.edges.length).toBe(1) + expect(data2.campaign.quotes.edges[0].node.id).not.toBe( + data.campaign.quotes.edges[0].node.id + ) + expect(data2.campaign.quotes.pageInfo.hasNextPage).toBe(false) + }) + + test('random mode does not error', async () => { + await seedQuote({ content: 'some' }) + await seedQuote({ content: 'html' }) + + const server = await testClient({ connections }) + const { errors, data } = await server.executeOperation({ + query: QUERY_CAMPAIGN_QUOTES, + variables: { + campaignInput: { shortHash: campaign.shortHash }, + quotesInput: { first: 10, random: true }, + }, + }) + expect(errors).toBeUndefined() + expect(data.campaign.quotes.totalCount).toBe(2) + expect(data.campaign.quotes.edges.length).toBe(2) + }) +}) diff --git a/src/types/__test__/2/system.test.ts b/src/types/__test__/2/system.test.ts index a789906ba..a975eb5db 100644 --- a/src/types/__test__/2/system.test.ts +++ b/src/types/__test__/2/system.test.ts @@ -1907,7 +1907,7 @@ describe('setWritingAdStatus', () => { describe('query OSS moments', () => { const QUERY_MOMENTS = ` - query($input: ConnectionArgs!) { + query($input: OSSMomentsInput!) { oss { moments(input: $input) { totalCount @@ -1975,4 +1975,90 @@ describe('query OSS moments', () => { expect(errors).toBeDefined() }) + + test('query moments by spam score within a datetime range', async () => { + const serverAdmin = await testClient({ + isAuth: true, + isAdmin: true, + connections, + }) + const { data, errors } = await serverAdmin.executeOperation({ + query: QUERY_MOMENTS, + variables: { + input: { + first: 10, + sort: 'mostSpam', + filter: { datetimeRange: { start: '2020-01-01T00:00:00.000Z' } }, + }, + }, + }) + expect(errors).toBeUndefined() + expect(_get(data, 'oss.moments.edges')).toBeDefined() + }) +}) + +describe('query OSS comments', () => { + const QUERY_COMMENTS = ` + query ($input: OSSCommentsInput!) { + oss { + comments(input: $input) { + totalCount + edges { + node { + id + content + createdAt + } + } + } + } + } + ` + + test('query comments successfully (newest)', async () => { + const serverAdmin = await testClient({ + isAuth: true, + isAdmin: true, + connections, + }) + const { data, errors } = await serverAdmin.executeOperation({ + query: QUERY_COMMENTS, + variables: { input: { first: 10 } }, + }) + expect(errors).toBeUndefined() + expect(_get(data, 'oss.comments.edges')).toBeDefined() + }) + + test('query comments by spam score within a datetime range', async () => { + const serverAdmin = await testClient({ + isAuth: true, + isAdmin: true, + connections, + }) + const { data, errors } = await serverAdmin.executeOperation({ + query: QUERY_COMMENTS, + variables: { + input: { + first: 10, + sort: 'mostSpam', + filter: { datetimeRange: { start: '2020-01-01T00:00:00.000Z' } }, + }, + }, + }) + expect(errors).toBeUndefined() + expect(_get(data, 'oss.comments.edges')).toBeDefined() + }) + + test('non-admin user cannot query comments', async () => { + const serverUser = await testClient({ + isAuth: true, + isAdmin: false, + connections, + }) + const { errors } = await serverUser.executeOperation({ + query: QUERY_COMMENTS, + variables: { input: { first: 10 } }, + }) + expect(errors).toBeDefined() + }) }) diff --git a/src/types/article.ts b/src/types/article.ts index a690c9353..27f410ee2 100644 --- a/src/types/article.ts +++ b/src/types/article.ts @@ -661,5 +661,7 @@ export default /* GraphQL */ ` mostComments mostDonations mostReadTime + "Order by spam score from high to low (only scored articles)" + mostSpam } ` diff --git a/src/types/campaign.ts b/src/types/campaign.ts index c45cfe8df..efb429925 100644 --- a/src/types/campaign.ts +++ b/src/types/campaign.ts @@ -49,6 +49,8 @@ export default /* GraphQL */ ` managers: [ID!] showOther: Boolean showAd: Boolean + "enable the quote wall (post-to-wall) for this campaign" + enableQuoteWall: Boolean } input ApplyCampaignInput { @@ -130,6 +132,12 @@ export default /* GraphQL */ ` participants(input: CampaignParticipantsInput!): CampaignParticipantConnection! articles(input: CampaignArticlesInput!): CampaignArticleConnection! + "Comments made by campaign participants (public to read)." + discussion(input: CommentsInput!): CommentConnection! @complexity(multipliers: ["input.first"], value: 1) + + "Discussion (include replies) count of this campaign." + discussionCount: Int! + application: CampaignApplication @privateCache featuredDescription(input: TranslationArgs): String! @@ -139,6 +147,8 @@ export default /* GraphQL */ ` isManager: Boolean! @privateCache showOther: Boolean! showAd: Boolean! + "whether this campaign exposes a quote wall (post-to-wall affordance)" + enableQuoteWall: Boolean! oss: CampaignOSS! @auth(mode: "${AUTH_MODE.admin}") } diff --git a/src/types/comment.ts b/src/types/comment.ts index 705e48de5..25b6dc7de 100644 --- a/src/types/comment.ts +++ b/src/types/comment.ts @@ -180,6 +180,7 @@ export default /* GraphQL */ ` articleId: ID circleId: ID momentId: ID + campaignId: ID } input CommentCommentsInput { @@ -361,5 +362,6 @@ export default /* GraphQL */ ` circleDiscussion circleBroadcast moment + campaignDiscussion } ` diff --git a/src/types/index.ts b/src/types/index.ts index bbe1d6830..d273bb83d 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -9,6 +9,7 @@ import moment from './moment.js' import notice from './notice.js' import oauthClient from './oauthClient.js' import payment from './payment.js' +import quote from './quote.js' import response from './response.js' import scalars from './scalars.js' import system from './system.js' @@ -40,5 +41,6 @@ export default [ oauthClient, collection, moment, + quote, channel, ] diff --git a/src/types/quote.ts b/src/types/quote.ts new file mode 100644 index 000000000..f9c05c06f --- /dev/null +++ b/src/types/quote.ts @@ -0,0 +1,61 @@ +import { AUTH_MODE, NODE_TYPES } from '#common/enums/index.js' +import { isProd } from '#common/environment.js' + +const PUT_QUOTE_RATE_LIMIT = isProd ? 6 : 30 + +export default /* GraphQL */ ` + extend type Mutation { + "Post a quote (selected from an article) onto the campaign quote wall." + putQuote(input: PutQuoteInput!): Quote! @auth(mode: "${AUTH_MODE.oauth}") @rateLimit(limit: ${PUT_QUOTE_RATE_LIMIT}, period: 300) + + "Retract a quote from the wall (poster, source article author, or admin)." + deleteQuote(input: DeleteQuoteInput!): Boolean! @auth(mode: "${AUTH_MODE.oauth}") + } + + extend type WritingChallenge { + "Quotes on this campaign's quote wall (public)." + quotes(input: QuotesInput!): QuoteConnection! @complexity(multipliers: ["input.first"], value: 1) + + "Quote count of this campaign's quote wall." + quoteCount: Int! + } + + input PutQuoteInput { + articleId: ID! + content: String! + } + + input DeleteQuoteInput { + id: ID! + } + + input QuotesInput { + first: Int @constraint(min: 0, max: 50) + after: String + + "random sampling for wall display; refetch to shuffle. when true, after is ignored" + random: Boolean + } + + type Quote { + id: ID! + content: String! + article: Article! @logCache(type: "${NODE_TYPES.Article}") + + "the user who posted this quote onto the wall" + poster: User! @logCache(type: "${NODE_TYPES.User}") + + createdAt: DateTime! + } + + type QuoteConnection implements Connection { + totalCount: Int! + pageInfo: PageInfo! + edges: [QuoteEdge!] + } + + type QuoteEdge { + cursor: String! + node: Quote! + } +` diff --git a/src/types/system.ts b/src/types/system.ts index dc42b5106..55c86ce9c 100644 --- a/src/types/system.ts +++ b/src/types/system.ts @@ -144,8 +144,8 @@ export default /* GraphQL */ ` type OSS @cacheControl(maxAge: ${CACHE_TTL.INSTANT}) { users(input: ConnectionArgs!): UserConnection! - comments(input: ConnectionArgs!): CommentConnection! - moments(input: ConnectionArgs!): MomentConnection! + comments(input: OSSCommentsInput!): CommentConnection! + moments(input: OSSMomentsInput!): MomentConnection! articles(input: OSSArticlesInput!): ArticleConnection! tags(input: TagsInput!): TagConnection! oauthClients(input: ConnectionArgs!): OAuthClientConnection! @@ -154,6 +154,7 @@ export default /* GraphQL */ ` badgedUsers(input: BadgedUsersInput!): UserConnection! restrictedUsers(input: ConnectionArgs!): UserConnection! reports(input: OSSReportsInput!): ReportConnection! + spamRings(input: OSSSpamRingsInput!): SpamRingConnection! icymiTopics(input: ConnectionArgs!): IcymiTopicConnection! topicChannelFeedbacks(input: TopicChannelFeedbacksInput!): TopicChannelFeedbackConnection! } @@ -272,6 +273,133 @@ export default /* GraphQL */ ` source: ReportSource } + """ + A spam ring: a cluster of accounts posting the same templated abuse, + surfaced by the account-layer ring detector (軸一 D). + """ + type SpamRing implements Node { + id: ID! + "模板/家族指紋(偵測 job 的歸群 key)" + fingerprint: String! + status: SpamRingStatus! + signals: SpamRingSignals! + nArticles: Int! + nAuthors: Int! + newAccountRatio: Float + score: Float + severity: SpamRingSeverity + detectedAt: DateTime! + firstSeenAt: DateTime + lastSeenAt: DateTime + frozenAt: DateTime + frozenBy: User + note: String + "群內成員帳號(可分頁)" + members(input: ConnectionArgs!): SpamRingMemberConnection! + "列表渲染用的少量樣本,免分頁" + memberSample(limit: Int): [User!]! + events: [SpamRingEvent!]! + } + + type SpamRingSignals { + nearDupRingSize: Int + entityRingSize: Int + botUsernameRatio: Float + topEntity: String + sampleCodes: [String!] + sampleBrands: [String!] + contentModelMax: Float + } + + type SpamRingMember { + id: ID! + user: User! + status: SpamRingMemberStatus! + "是否由本 ring 的凍結造成封禁(解凍時只還原此類)" + bannedByThisRing: Boolean! + skipReason: String + createdAt: DateTime! + } + + type SpamRingEvent { + id: ID! + action: SpamRingEventAction! + actor: User + "JSON 字串" + detail: String + createdAt: DateTime! + } + + enum SpamRingStatus { + pending + frozen + dismissed + restored + } + + enum SpamRingMemberStatus { + pending + frozen + skipped + restored + } + + enum SpamRingSeverity { + low + medium + high + critical + } + + enum SpamRingEventAction { + detected + frozen + unfrozen + dismissed + member_banned + member_skipped + member_restored + } + + type SpamRingConnection implements Connection { + totalCount: Int! + pageInfo: PageInfo! + edges: [SpamRingEdge!] + } + + type SpamRingEdge { + cursor: String! + node: SpamRing! + } + + type SpamRingMemberConnection implements Connection { + totalCount: Int! + pageInfo: PageInfo! + edges: [SpamRingMemberEdge!] + } + + type SpamRingMemberEdge { + cursor: String! + node: SpamRingMember! + } + + enum SpamRingsSort { + score + detectedAt + nAuthors + } + + input OSSSpamRingsInput { + after: String + first: Int @constraint(min: 0) + sort: SpamRingsSort = score + filter: OSSSpamRingsFilter + } + + input OSSSpamRingsFilter { + status: SpamRingStatus + } + input NodeInput { id: ID! } @@ -731,6 +859,31 @@ export default /* GraphQL */ ` searchKey: String } + "Sort options shared by OSS comment/moment lists for spam triage." + enum OSSContentSpamSort { + newest + "Order by spam score from high to low (only scored items)" + mostSpam + } + + input OSSSpamDatetimeFilterInput { + datetimeRange: DatetimeRangeInput + } + + input OSSCommentsInput { + after: String + first: Int @constraint(min: 0) + sort: OSSContentSpamSort = newest + filter: OSSSpamDatetimeFilterInput + } + + input OSSMomentsInput { + after: String + first: Int @constraint(min: 0) + sort: OSSContentSpamSort = newest + filter: OSSSpamDatetimeFilterInput + } + #################### # Directives # #################### diff --git a/src/types/user.ts b/src/types/user.ts index ce8bd9bcc..73de94a73 100644 --- a/src/types/user.ts +++ b/src/types/user.ts @@ -113,6 +113,18 @@ export default /* GraphQL */ ` "Archive multiple users from OSS with per-user results." archiveUsers(input: ArchiveUsersInput!): ArchiveUsersResult! @auth(mode: "${AUTH_MODE.admin}") @purgeCache(type: "${NODE_TYPES.User}") + "Freeze a spam ring: permanently (but reversibly) ban all member accounts. OSS." + freezeSpamRing(input: FreezeSpamRingInput!): FreezeSpamRingResult! @auth(mode: "${AUTH_MODE.admin}") @purgeCache(type: "${NODE_TYPES.User}") + + "Reverse a spam ring freeze: unban only the members this ring banned. OSS." + unfreezeSpamRing(input: UnfreezeSpamRingInput!): UnfreezeSpamRingResult! @auth(mode: "${AUTH_MODE.admin}") @purgeCache(type: "${NODE_TYPES.User}") + + "Mark a spam ring as a false positive (feeds training as ham). OSS." + dismissSpamRing(input: DismissSpamRingInput!): SpamRing! @auth(mode: "${AUTH_MODE.admin}") + + "Upsert spam ring candidates from the detection job (admin service principal). OSS." + upsertSpamRingCandidates(input: UpsertSpamRingCandidatesInput!): UpsertSpamRingCandidatesResult! @auth(mode: "${AUTH_MODE.admin}") + "Update state of a user, used in OSS." updateUserRole(input: UpdateUserRoleInput!): User! @auth(mode: "${AUTH_MODE.admin}") @purgeCache(type: "${NODE_TYPES.User}") @@ -826,6 +838,76 @@ export default /* GraphQL */ ` message: String! } + input FreezeSpamRingInput { + id: ID! + remark: String + } + + type FreezeSpamRingResult { + ring: SpamRing! + frozen: [User!]! + "Members not banned (old account, high karma, already banned, archived…) — for manual review." + skipped: [SpamRingSkip!]! + } + + input UnfreezeSpamRingInput { + id: ID! + } + + type UnfreezeSpamRingResult { + ring: SpamRing! + unbanned: [User!]! + skipped: [SpamRingSkip!]! + } + + type SpamRingSkip { + user: User! + reason: String! + } + + input DismissSpamRingInput { + id: ID! + note: String + } + + input UpsertSpamRingCandidatesInput { + candidates: [SpamRingCandidateInput!]! + } + + input SpamRingCandidateInput { + fingerprint: String! + "Raw DB user ids (the detection job reads them from the replica)." + memberUserIds: [String!] + memberUserNames: [String!] + signals: SpamRingSignalsInput! + nArticles: Int! + nAuthors: Int! + newAccountRatio: Float + score: Float + severity: SpamRingSeverity + firstSeenAt: DateTime + lastSeenAt: DateTime + "JSON string: map of user id -> evidence." + memberEvidence: String + } + + input SpamRingSignalsInput { + nearDupRingSize: Int + entityRingSize: Int + botUsernameRatio: Float + topEntity: String + sampleCodes: [String!] + sampleBrands: [String!] + contentModelMax: Float + } + + type UpsertSpamRingCandidatesResult { + created: Int! + updated: Int! + skipped: Int! + rings: [SpamRing!]! + } + input UpdateUserRoleInput { id: ID! role: UserRole! @@ -1068,6 +1150,8 @@ export default /* GraphQL */ ` "used in register" language: UserLanguage referralCode: String + "Google OIDC redirect_uri for OSS SSO. When set, must be allowlisted; login is restricted to existing admin accounts and no new account is created." + redirectUri: String } input Oauth1CredentialInput {