diff --git a/.changes/config.json b/.changes/config.json index 68ec835..f46da63 100644 --- a/.changes/config.json +++ b/.changes/config.json @@ -1,5 +1,5 @@ { - "gitSiteUrl": "https://www.github.com/your-org/tauri-plugin-graphql/", + "gitSiteUrl": "https://www.github.com/tonymushah/mizuki", "pkgManagers": { "rust": { "version": true, @@ -65,14 +65,14 @@ } }, "packages": { - "tauri-plugin-graphql": { + "mizuki": { "path": ".", "manager": "rust" }, - "tauri-plugin-graphql-urql": { + "@mizuki/urql": { "path": "packages/urql", "manager": "javascript", - "dependencies": ["tauri-plugin-graphql"] + "dependencies": ["mizuki"] } } -} +} \ No newline at end of file diff --git a/.changes/readme.md b/.changes/readme.md deleted file mode 100644 index 3196498..0000000 --- a/.changes/readme.md +++ /dev/null @@ -1,16 +0,0 @@ -# Changes -##### via https://github.com/jbolda/covector - -As you create PRs and make changes that require a version bump, please add a new markdown file in this folder. You do not note the version *number*, but rather the type of bump that you expect: major, minor, or patch. The filename is not important, as long as it is a `.md`, but we recommend it represents the overall change for our sanity. - -When you select the version bump required, you do *not* need to consider depedencies. Only note the package with the actual change, and any packages that depend on that package will be bumped automatically in the process. - -Use the following format: -```md ---- -"tauri-plugin-graphql": patch ---- - -Change summary goes here - -``` \ No newline at end of file diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 2b8f4c5..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,5 +0,0 @@ -# These are supported funding model platforms - -github: [JonasKruckenberg] -open_collective: # Replace with a single Open Collective username -custom: ['https://paypal.me/jonaskruckie'] diff --git a/.github/workflows/audit-javascript.yml b/.github/workflows/audit-javascript.yml index e29601b..481d3d4 100644 --- a/.github/workflows/audit-javascript.yml +++ b/.github/workflows/audit-javascript.yml @@ -37,7 +37,7 @@ jobs: ${{ runner.os }}- - uses: actions/setup-node@v3 with: - node-version: '14' + node-version: '18' - uses: pnpm/action-setup@v2.2.4 with: run_install: true diff --git a/.github/workflows/covector-status.yml b/.github/workflows/covector-status.yml index 7809dfe..fd2faa4 100644 --- a/.github/workflows/covector-status.yml +++ b/.github/workflows/covector-status.yml @@ -6,12 +6,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: '14' + node-version: '18' - uses: pnpm/action-setup@v2.2.4 with: run_install: true diff --git a/.github/workflows/covector-version-or-publish.yml b/.github/workflows/covector-version-or-publish.yml index aa39695..b5dc82c 100644 --- a/.github/workflows/covector-version-or-publish.yml +++ b/.github/workflows/covector-version-or-publish.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: actions-rs/toolchain@v1 @@ -25,9 +25,9 @@ jobs: key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | ${{ runner.os }}- - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: '14' + node-version: '18' - uses: pnpm/action-setup@v2.2.4 with: run_install: true diff --git a/.github/workflows/format-javascript.yml b/.github/workflows/format-javascript.yml index e5d82f0..b1a5876 100644 --- a/.github/workflows/format-javascript.yml +++ b/.github/workflows/format-javascript.yml @@ -22,7 +22,7 @@ jobs: audit-js: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Cache pnpm modules uses: actions/cache@v3 with: @@ -30,9 +30,9 @@ jobs: key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | ${{ runner.os }}- - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: '14' + node-version: '18' - uses: pnpm/action-setup@v2.2.4 with: run_install: true diff --git a/.github/workflows/format-rust.yml b/.github/workflows/format-rust.yml index cdea2a1..b866d29 100644 --- a/.github/workflows/format-rust.yml +++ b/.github/workflows/format-rust.yml @@ -21,12 +21,12 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v3 - - name: Install rustfmt with nightly toolchain + - uses: actions/checkout@v4 + - name: Install rustfmt with stable toolchain uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: nightly + toolchain: stable override: true components: rustfmt - uses: actions-rs/cargo@v1 diff --git a/.github/workflows/lint-javascript.yml b/.github/workflows/lint-javascript.yml index 505d074..fb95035 100644 --- a/.github/workflows/lint-javascript.yml +++ b/.github/workflows/lint-javascript.yml @@ -22,7 +22,7 @@ jobs: audit-js: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Cache pnpm modules uses: actions/cache@v3 with: @@ -30,9 +30,9 @@ jobs: key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | ${{ runner.os }}- - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: '14' + node-version: '18' - uses: pnpm/action-setup@v2.2.4 with: run_install: true diff --git a/.github/workflows/lint-rust.yml b/.github/workflows/lint-rust.yml index 8298771..9fef2be 100644 --- a/.github/workflows/lint-rust.yml +++ b/.github/workflows/lint-rust.yml @@ -25,7 +25,7 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: install webkit2gtk run: | sudo apt-get update diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 68e358c..a65c1b9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,7 +28,7 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install stable toolchain uses: actions-rs/toolchain@v1 with: diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 553d5e7..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,71 +0,0 @@ -# Changelog - -## \[2.1.0] - -- Bump `async-graphql` to v5. - - [9551574](https://www.github.com/your-org/tauri-plugin-graphql/commit/95515743ca143d68743ae9817865fe31dffd7fd9) Create update-async-graphql.md on 2023-01-10 - -## \[2.0.1] - -- Drop tauri >1.0.0 - - [1d5a578](https://www.github.com/your-org/tauri-plugin-graphql/commit/1d5a578cb4595ee04b9705d448a5fd44f6c61659) Create adjust-dependency-version.md on 2022-09-22 - -## \[2.0.0] - -- Added optional support for the GraphiQL IDE, to explore the Schema during Development. This is gated behind the `graphiql` feature flag. - - [209e0b4](https://www.github.com/your-org/tauri-plugin-graphql/commit/209e0b416ad6d845f7121e8bf8c270ced4d81be9) update changesets on 2022-09-21 -- Re-export `async_graphql` from crate. - - [d587a33](https://www.github.com/your-org/tauri-plugin-graphql/commit/d587a33674a33a98edffec1b211dcf668905e7b5) feat: re-export async_graphql on 2022-09-22 -- Switch from [`juniper`](https://github.com/async-graphql/async-graphql) to [`async-graphql`](https://github.com/graphql-rust/juniper). This adds integration with more crates, including the `log`, `tracing` and `opentelemetry` ecosystems. It also improves performance and simplifies the implementation. - - [f7ec823](https://www.github.com/your-org/tauri-plugin-graphql/commit/f7ec823ac12cbded1fcc2d27ae0aae7251fe4269) add changeset on 2022-09-20 - - [78649ef](https://www.github.com/your-org/tauri-plugin-graphql/commit/78649ef6e58298876ebcfc5e48977adf31a2f688) Update switch-to-async-graphql.md on 2022-09-20 - - [209e0b4](https://www.github.com/your-org/tauri-plugin-graphql/commit/209e0b416ad6d845f7121e8bf8c270ced4d81be9) update changesets on 2022-09-21 - -## \[1.0.0] - -- Mark as `stable` - - [d6ba689](https://www.github.com/your-org/tauri-plugin-graphql/commit/d6ba6891a0132ea67fbf58b10b4d500c37592b35) Create mark-as-stable.md on 2022-06-16 -- Update Tauri to v1.0.0 - - [42d98bb](https://www.github.com/your-org/tauri-plugin-graphql/commit/42d98bb34ea8d0c350659b669128ad632590131c) add tauri changefile on 2022-04-27 - - [5f9cbdf](https://www.github.com/your-org/tauri-plugin-graphql/commit/5f9cbdf21e3f6d55c5ae41a19751b7d37fc56683) \[create-pull-request] automated change on 2022-04-27 - - [01838a3](https://www.github.com/your-org/tauri-plugin-graphql/commit/01838a3cfb2eba7208e979dad89050902c36e2e7) Create update-tauri.md on 2022-05-25 - - [fa12cf5](https://www.github.com/your-org/tauri-plugin-graphql/commit/fa12cf5756a9d7ccf282a465a0376b09b499cd01) \[create-pull-request] automated change on 2022-05-25 - - [9a9bde4](https://www.github.com/your-org/tauri-plugin-graphql/commit/9a9bde4e8a5bc0b6d792fcf25c3530943ac27fb5) add changefile on 2022-06-16 - -## \[0.2.4] - -- Update Tauri to v1.0.0-rc.12 - - [42d98bb](https://www.github.com/your-org/tauri-plugin-graphql/commit/42d98bb34ea8d0c350659b669128ad632590131c) add tauri changefile on 2022-04-27 - - [5f9cbdf](https://www.github.com/your-org/tauri-plugin-graphql/commit/5f9cbdf21e3f6d55c5ae41a19751b7d37fc56683) \[create-pull-request] automated change on 2022-04-27 - - [01838a3](https://www.github.com/your-org/tauri-plugin-graphql/commit/01838a3cfb2eba7208e979dad89050902c36e2e7) Create update-tauri.md on 2022-05-25 - -## \[0.2.3] - -- Update dependencies. - - [f15f662](https://www.github.com/your-org/tauri-plugin-graphql/commit/f15f6628a4aee793691b13a9b41c7884abd9c5d0) Create chore-update-deps.md on 2022-05-18 - - [4f73836](https://www.github.com/your-org/tauri-plugin-graphql/commit/4f73836c1843b31009289c47d1951e11a1980a49) Update chore-update-deps.md on 2022-05-19 - -## \[0.2.2] - -- Update dependencies - - [7c8a65d](https://www.github.com/your-org/tauri-plugin-graphql/commit/7c8a65d2ccdf9ea8f0cced2fc8734ba9aec9d1c0) Create update-deps.md on 2022-05-11 -- Update documentation - - [de4c1fa](https://www.github.com/your-org/tauri-plugin-graphql/commit/de4c1fa22fbaaa84f786f92568bc4a52201a3a2d) Create update-docs.md on 2022-05-03 - -## \[0.2.1] - -- Update dependency `tauri` to `1.0.0-rc.8` - - [42d98bb](https://www.github.com/your-org/tauri-plugin-graphql/commit/42d98bb34ea8d0c350659b669128ad632590131c) add tauri changefile on 2022-04-27 - -## \[0.2.0] - -- Add support for GraphQL subscriptions. Subscriptions provide a type-safe way to model real-time state changes. This feature is currently gated by the `subscriptions` flag but will be enabled by default in a future release. - - [d73c988](https://www.github.com/your-org/tauri-plugin-graphql/commit/d73c988230b5616dd3ce77c782a39cdfd2d10a8c) add changefiles on 2022-04-01 -- Replace panicking behavior with proper error handling. - - [d73c988](https://www.github.com/your-org/tauri-plugin-graphql/commit/d73c988230b5616dd3ce77c782a39cdfd2d10a8c) add changefiles on 2022-04-01 - -## \[0.1.0] - -- Initial release. - - [691ebc1](https://www.github.com/your-org/tauri-plugin-graphql/commit/691ebc16f90aba3f0d33ca6b2dadb0552b098239) initial commit on 2022-03-30 - - [85e7726](https://www.github.com/your-org/tauri-plugin-graphql/commit/85e7726dd7e55b70c7bc739835d4ff08685fe220) update changefile on 2022-03-30 diff --git a/Cargo.toml b/Cargo.toml index 14c32ab..6e1463d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "mizuki" version = "0.1.0" -authors = [ "tonymushah " ] +authors = [ "Jonas Kruckenberg", "tonymushah " ] description = "A toolkit for building Tauri Plugins that enables type-safe IPC through GraphQL." edition = "2021" rust-version = "1.59" @@ -11,9 +11,6 @@ repository = "https://github.com/tonymushah/mizuki" categories = [ "gui", "web-programming" ] keywords = [ "tauri-plugin", "graphql" ] -[package.metadata.docs.rs] -features = [ "graphiql" ] - [dependencies] serde = { version = "1", features = [ "derive" ] } serde_json = "1" @@ -22,7 +19,6 @@ async-graphql = "6" [features] log = [ "async-graphql/log" ] -tracing = [ "async-graphql/tracing" ] opentelemetry = [ "async-graphql/opentelemetry" ] bson = [ "async-graphql/bson" ] chrono = [ "async-graphql/chrono" ] diff --git a/LICENSE b/LICENSE index 1da5f59..f7f5d94 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Jonas Kruckenberg +Copyright (c) 2023 Tony Mushah Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 0f20796..cab4e17 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,24 @@ -# Tauri Plugin graphql +# Mizuki [![Crates.io][crates-badge]][crates-url] [![Documentation][docs-badge]][docs-url] [![MIT licensed][mit-badge]][mit-url] -[crates-badge]: https://img.shields.io/crates/v/tauri-plugin-graphql.svg -[crates-url]: https://crates.io/crates/tauri-plugin-graphql -[docs-badge]: https://img.shields.io/docsrs/tauri-plugin-graphql.svg -[docs-url]: https://docs.rs/tauri-plugin-graphql +[crates-badge]: https://img.shields.io/crates/v/mizuki.svg +[crates-url]: https://crates.io/crates/mizuki +[docs-badge]: https://img.shields.io/docsrs/mizuki.svg +[docs-url]: https://docs.rs/mizuki [mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg [mit-url]: LICENSE -A plugin for Tauri that enables type-safe IPC through GraphQL. +A toolkit for building Tauri plugins that enables type-safe IPC through GraphQL. + +## Notice + +This project is a fork from [JonasKruckenberg/tauri-plugin-graphql][initial-repo]. + +But I thought that it would be a great a idea to push the plugin futher +and create a toolkit for building GraphQL Tauri Plugins. ## Install @@ -19,17 +26,17 @@ A plugin for Tauri that enables type-safe IPC through GraphQL. ```toml [dependencies] -tauri-plugin-graphql = "2.0.0" +mizuki = "0.1.0" ``` ### JavaScript -The only client-side adapter currently is `tauri-plugin-graphql-urql`, a custom exchange for [`urql`]. +The only client-side adapter currently is `@mizuki/urql`, a custom exchange for [`urql`]. If you need adapters for other GraphQL clients, open a PR! | Package | Version (click for changelogs) | |-------------------------------|--------------------------------| -| [`tauri-plugin-graphql-urql`] | [![urql adapter version][urql-adapter-version-badge]][urql-adapter-changelog] +| [`@mizuki/urql`] | [![urql adapter version][urql-adapter-version-badge]][urql-adapter-changelog] ## Usage @@ -75,7 +82,8 @@ fn main() { ); tauri::Builder::default() - .plugin(tauri_plugin_graphql::init(schema)) + // The plugin name is required + .plugin(mizuki::MizukiPlugin::new("todo-plugin", schema)) .run(tauri::generate_context!()) .expect("failed to run app"); } @@ -91,10 +99,11 @@ PRs are welcome! ## License -[MIT © Jonas Kruckenberg](./LICENSE) +[MIT © Tony Mushah](./LICENSE) -[`tauri-plugin-graphql-urql`]: packages/urql -[urql-adapter-version-badge]: https://img.shields.io/npm/v/tauri-plugin-graphql-urql?label=%20 +[`@mizuki/urql`]: packages/urql +[urql-adapter-version-badge]: https://img.shields.io/npm/v/@mizuki/urql?label=%20 [urql-adapter-changelog]: packages/urql/CHANGELOG.md [`urql`]: https://formidable.com/open-source/urql/ [`async_graphql::Schema`]: https://docs.rs/async-graphql/latest/async_graphql/struct.Schema.html +[initial-repo]: https://github.com/JonasKruckenberg/tauri-plugin-graphql diff --git a/examples/preact-app/codegen.ts b/examples/preact-app/codegen.ts index 3d17cc3..88fa549 100644 --- a/examples/preact-app/codegen.ts +++ b/examples/preact-app/codegen.ts @@ -1,4 +1,4 @@ -import { CodegenConfig } from '@graphql-codegen/cli'; +import {CodegenConfig} from '@graphql-codegen/cli' const config: CodegenConfig = { schema: './myschema.graphqls', @@ -7,9 +7,9 @@ const config: CodegenConfig = { generates: { './src/gql/': { preset: 'client', - plugins: [], - }, - }, -}; + plugins: [] + } + } +} -export default config; \ No newline at end of file +export default config diff --git a/examples/preact-app/src-tauri/src/main.rs b/examples/preact-app/src-tauri/src/main.rs index 9008330..b271a48 100644 --- a/examples/preact-app/src-tauri/src/main.rs +++ b/examples/preact-app/src-tauri/src/main.rs @@ -34,7 +34,10 @@ impl Subscription { } fn main() { - let my_plugin = mizuki::Mizuki::new("mizuki-test", Schema::new(Query, EmptyMutation, Subscription)); + let my_plugin = mizuki::MizukiPlugin::new( + "mizuki-test", + Schema::new(Query, EmptyMutation, Subscription), + ); my_plugin.export_sdl("../myschema.graphqls").unwrap(); tauri::Builder::default() .plugin(my_plugin) diff --git a/examples/preact-app/src/gql/fragment-masking.ts b/examples/preact-app/src/gql/fragment-masking.ts index 2ba06f1..5d52577 100644 --- a/examples/preact-app/src/gql/fragment-masking.ts +++ b/examples/preact-app/src/gql/fragment-masking.ts @@ -1,66 +1,83 @@ -import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; -import { FragmentDefinitionNode } from 'graphql'; -import { Incremental } from './graphql'; +import { + ResultOf, + DocumentTypeDecoration, + TypedDocumentNode +} from '@graphql-typed-document-node/core' +import {FragmentDefinitionNode} from 'graphql' +import {Incremental} from './graphql' - -export type FragmentType> = TDocumentType extends DocumentTypeDecoration< - infer TType, - any -> - ? [TType] extends [{ ' $fragmentName'?: infer TKey }] +export type FragmentType< + TDocumentType extends DocumentTypeDecoration +> = TDocumentType extends DocumentTypeDecoration + ? [TType] extends [{' $fragmentName'?: infer TKey}] ? TKey extends string - ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + ? {' $fragmentRefs'?: {[key in TKey]: TType}} : never : never - : never; + : never // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> -): TType; +): TType // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, - fragmentType: FragmentType> | null | undefined -): TType | null | undefined; + fragmentType: + | FragmentType> + | null + | undefined +): TType | null | undefined // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> -): ReadonlyArray; +): ReadonlyArray // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, - fragmentType: ReadonlyArray>> | null | undefined -): ReadonlyArray | null | undefined; + fragmentType: + | ReadonlyArray>> + | null + | undefined +): ReadonlyArray | null | undefined export function useFragment( _documentNode: DocumentTypeDecoration, - fragmentType: FragmentType> | ReadonlyArray>> | null | undefined + fragmentType: + | FragmentType> + | ReadonlyArray>> + | null + | undefined ): TType | ReadonlyArray | null | undefined { - return fragmentType as any; + return fragmentType as any } - export function makeFragmentData< F extends DocumentTypeDecoration, FT extends ResultOf >(data: FT, _fragment: F): FragmentType { - return data as FragmentType; + return data as FragmentType } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, - data: FragmentType, any>> | null | undefined + data: + | FragmentType, any>> + | null + | undefined ): data is FragmentType { - const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ - ?.deferredFields; + const deferredFields = ( + queryNode as {__meta__?: {deferredFields: Record}} + ).__meta__?.deferredFields - if (!deferredFields) return true; + if (!deferredFields) return true - const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; - const fragName = fragDef?.name?.value; + const fragDef = fragmentNode.definitions[0] as + | FragmentDefinitionNode + | undefined + const fragName = fragDef?.name?.value - const fields = (fragName && deferredFields[fragName]) || []; - return fields.length > 0 && fields.every(field => data && field in data); + const fields = (fragName && deferredFields[fragName]) || [] + return fields.length > 0 && fields.every(field => data && field in data) } diff --git a/examples/preact-app/src/gql/gql.ts b/examples/preact-app/src/gql/gql.ts index fa4d12f..a47882c 100644 --- a/examples/preact-app/src/gql/gql.ts +++ b/examples/preact-app/src/gql/gql.ts @@ -1,6 +1,6 @@ /* eslint-disable */ -import * as types from './graphql'; -import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import * as types from './graphql' +import {TypedDocumentNode as DocumentNode} from '@graphql-typed-document-node/core' /** * Map of all GraphQL operations in the project. @@ -13,9 +13,10 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/ * Therefore it is highly recommended to use the babel or swc plugin for production. */ const documents = { - "\nquery getHero {\n hero {\n name\n }\n}\n": types.GetHeroDocument, - "\n subscription MessageSub {\n helloWorld\n }\n": types.MessageSubDocument, -}; + '\nquery getHero {\n hero {\n name\n }\n}\n': types.GetHeroDocument, + '\n subscription MessageSub {\n helloWorld\n }\n': + types.MessageSubDocument +} /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. @@ -29,19 +30,24 @@ const documents = { * The query argument is unknown! * Please regenerate the types. */ -export function graphql(source: string): unknown; +export function graphql(source: string): unknown /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\nquery getHero {\n hero {\n name\n }\n}\n"): (typeof documents)["\nquery getHero {\n hero {\n name\n }\n}\n"]; +export function graphql( + source: '\nquery getHero {\n hero {\n name\n }\n}\n' +): typeof documents['\nquery getHero {\n hero {\n name\n }\n}\n'] /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n subscription MessageSub {\n helloWorld\n }\n"): (typeof documents)["\n subscription MessageSub {\n helloWorld\n }\n"]; +export function graphql( + source: '\n subscription MessageSub {\n helloWorld\n }\n' +): typeof documents['\n subscription MessageSub {\n helloWorld\n }\n'] export function graphql(source: string) { - return (documents as any)[source] ?? {}; + return (documents as any)[source] ?? {} } -export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never; \ No newline at end of file +export type DocumentType> = + TDocumentNode extends DocumentNode ? TType : never diff --git a/examples/preact-app/src/gql/graphql.ts b/examples/preact-app/src/gql/graphql.ts index 0e528bb..c12572d 100644 --- a/examples/preact-app/src/gql/graphql.ts +++ b/examples/preact-app/src/gql/graphql.ts @@ -1,46 +1,95 @@ /* eslint-disable */ -import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; -export type Maybe = T | null; -export type InputMaybe = Maybe; -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 }; +import {TypedDocumentNode as DocumentNode} from '@graphql-typed-document-node/core' +export type Maybe = T | null +export type InputMaybe = Maybe +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} /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { - ID: { input: string; output: string; } - String: { input: string; output: string; } - Boolean: { input: boolean; output: boolean; } - Int: { input: number; output: number; } - Float: { input: number; output: number; } -}; + ID: {input: string; output: string} + String: {input: string; output: string} + Boolean: {input: boolean; output: boolean} + Int: {input: number; output: number} + Float: {input: number; output: number} +} export type Human = { - __typename?: 'Human'; - name: Scalars['String']['output']; -}; + __typename?: 'Human' + name: Scalars['String']['output'] +} export type Query = { - __typename?: 'Query'; - hero: Human; -}; + __typename?: 'Query' + hero: Human +} export type Subscription = { - __typename?: 'Subscription'; - helloWorld: Scalars['String']['output']; -}; + __typename?: 'Subscription' + helloWorld: Scalars['String']['output'] +} -export type GetHeroQueryVariables = Exact<{ [key: string]: never; }>; +export type GetHeroQueryVariables = Exact<{[key: string]: never}> +export type GetHeroQuery = { + __typename?: 'Query' + hero: {__typename?: 'Human'; name: string} +} -export type GetHeroQuery = { __typename?: 'Query', hero: { __typename?: 'Human', name: string } }; +export type MessageSubSubscriptionVariables = Exact<{[key: string]: never}> -export type MessageSubSubscriptionVariables = Exact<{ [key: string]: never; }>; +export type MessageSubSubscription = { + __typename?: 'Subscription' + helloWorld: string +} - -export type MessageSubSubscription = { __typename?: 'Subscription', helloWorld: string }; - - -export const GetHeroDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"getHero"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hero"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; -export const MessageSubDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"subscription","name":{"kind":"Name","value":"MessageSub"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"helloWorld"}}]}}]} as unknown as DocumentNode; \ No newline at end of file +export const GetHeroDocument = { + kind: 'Document', + definitions: [ + { + kind: 'OperationDefinition', + operation: 'query', + name: {kind: 'Name', value: 'getHero'}, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: {kind: 'Name', value: 'hero'}, + selectionSet: { + kind: 'SelectionSet', + selections: [{kind: 'Field', name: {kind: 'Name', value: 'name'}}] + } + } + ] + } + } + ] +} as unknown as DocumentNode +export const MessageSubDocument = { + kind: 'Document', + definitions: [ + { + kind: 'OperationDefinition', + operation: 'subscription', + name: {kind: 'Name', value: 'MessageSub'}, + selectionSet: { + kind: 'SelectionSet', + selections: [{kind: 'Field', name: {kind: 'Name', value: 'helloWorld'}}] + } + } + ] +} as unknown as DocumentNode< + MessageSubSubscription, + MessageSubSubscriptionVariables +> diff --git a/examples/preact-app/src/gql/index.ts b/examples/preact-app/src/gql/index.ts index f515991..f9bc8e5 100644 --- a/examples/preact-app/src/gql/index.ts +++ b/examples/preact-app/src/gql/index.ts @@ -1,2 +1,2 @@ -export * from "./fragment-masking"; -export * from "./gql"; \ No newline at end of file +export * from './fragment-masking' +export * from './gql' diff --git a/package.json b/package.json index 2a5f9c9..d63d22c 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "mizukiw", + "name": "mizuki", "version": "0.0.0", "private": true, "description": "", diff --git a/packages/graphiql/.gitignore b/packages/graphiql/.gitignore deleted file mode 100644 index a547bf3..0000000 --- a/packages/graphiql/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/packages/graphiql/index.html b/packages/graphiql/index.html deleted file mode 100644 index 5c68172..0000000 --- a/packages/graphiql/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Vite + React + TS - - -
Loading...
- - - diff --git a/packages/graphiql/package.json b/packages/graphiql/package.json deleted file mode 100644 index 574a1ed..0000000 --- a/packages/graphiql/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "graphiql", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "dependencies": { - "@graphiql/create-fetcher": "^0.1.0", - "@tauri-apps/api": "^1.1.0", - "graphiql": "^2.0.7", - "react": "^18.2.0", - "react-dom": "^18.2.0" - }, - "devDependencies": { - "@types/react": "^18.0.17", - "@types/react-dom": "^18.0.6", - "@vitejs/plugin-react": "^3.0.0", - "typescript": "^4.6.4", - "vite": "^4.0.0", - "vite-plugin-singlefile": "^0.13.0" - } -} \ No newline at end of file diff --git a/packages/graphiql/src/main.tsx b/packages/graphiql/src/main.tsx deleted file mode 100644 index bad06c4..0000000 --- a/packages/graphiql/src/main.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import React from 'react' -import ReactDOM from 'react-dom/client' -import { GraphiQL } from 'graphiql' -import { createGraphiQLFetcher } from '@graphiql/create-fetcher' -import { invoke } from '@tauri-apps/api/tauri' -import { listen } from '@tauri-apps/api/event' - -async function invokeFetch(_url: globalThis.RequestInfo | URL, options: globalThis.RequestInit) { - // the JSON.parse here is a bit annoying, but there is currently no good way around it - // @ts-ignore - const [str, isOk] = await invoke('plugin:graphql|graphql', options.body && JSON.parse(options.body.toString())) - return new Response(str, isOk) -} - -class Response { - #str: string - readonly ok: boolean - - constructor(str: string, ok: boolean) { - this.#str = str - this.ok = ok - } - - json() { - return JSON.parse(this.#str) - } -} - -class InvokeSubscriptionClient { - // @ts-ignore - subscribe(payload, sink) { - let unlisten = () => {} - - const id = Math.floor(Math.random() * 10000000) - - console.log(payload); - - Promise.resolve() - .then(async () => - listen(`graphql://${id}`, (event) => { - if (event.payload === null) return sink.complete() - // @ts-ignore - sink.next(JSON.parse(event.payload)) - }) - ) - .then(_unlisten => (unlisten = _unlisten)) - .then(() => - invoke('plugin:graphql|subscriptions', {...payload, id}) - ) - .catch(err => console.error(err)) - - return unlisten - } -} - -ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( - - {/* @ts-ignore */} - - -) diff --git a/packages/graphiql/src/vite-env.d.ts b/packages/graphiql/src/vite-env.d.ts deleted file mode 100644 index 11f02fe..0000000 --- a/packages/graphiql/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/packages/graphiql/tsconfig.json b/packages/graphiql/tsconfig.json deleted file mode 100644 index 3d0a51a..0000000 --- a/packages/graphiql/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "lib": ["DOM", "DOM.Iterable", "ESNext"], - "allowJs": false, - "skipLibCheck": true, - "esModuleInterop": false, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "module": "ESNext", - "moduleResolution": "Node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx" - }, - "include": ["src"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/packages/graphiql/tsconfig.node.json b/packages/graphiql/tsconfig.node.json deleted file mode 100644 index 9d31e2a..0000000 --- a/packages/graphiql/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "module": "ESNext", - "moduleResolution": "Node", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/packages/graphiql/vite.config.ts b/packages/graphiql/vite.config.ts deleted file mode 100644 index 09e68fb..0000000 --- a/packages/graphiql/vite.config.ts +++ /dev/null @@ -1,11 +0,0 @@ -import {defineConfig} from 'vite' -import react from '@vitejs/plugin-react' -import {viteSingleFile} from 'vite-plugin-singlefile' - -// https://vitejs.dev/config/ -export default defineConfig({ - build: { - minify: 'esbuild' - }, - plugins: [react(), viteSingleFile()] -}) diff --git a/packages/urql/index.ts b/packages/urql/index.ts index 39f2e0a..172bbbd 100644 --- a/packages/urql/index.ts +++ b/packages/urql/index.ts @@ -1,14 +1,14 @@ -import { invoke } from '@tauri-apps/api' -import { listen, Event } from '@tauri-apps/api/event' +import {invoke} from '@tauri-apps/api' +import {listen, Event} from '@tauri-apps/api/event' import { Exchange, makeErrorResult, makeResult, Operation, OperationResult, - subscriptionExchange + subscriptionExchange as subEx } from '@urql/core' -import { print } from 'graphql' +import {print} from 'graphql' import { filter, make, @@ -28,73 +28,77 @@ import { * * ```javascript * import { createClient } from 'urql' - * import { tauriExchange } from 'tauri-plugin-graphql/urql' + * import { invokeExchange } from '@mizuki/urql' * * const client = createClient({ * url: 'graphql', // this endpoint is important, don't touch - * exchanges: [tauriExchange] + * exchanges: [invokeExchange("")] * }) * ``` + * @param name Your plugin name */ -export const invokeExchange: (name: string) => Exchange = (name) => ({ forward }) => { - return ops$ => { - const sharedOps$ = share(ops$); - const fetchResults$ = pipe( - sharedOps$, - filter(op => op.kind === 'query' || op.kind === 'mutation'), - mergeMap(operation => { - const { key } = operation - const teardown$ = pipe( - sharedOps$, - filter(op => op.kind === 'teardown' && op.key === key) - ) - - const args = { - query: print(operation.query), - variables: operation.variables || undefined - } - - const command = `plugin:${name}|${operation.context.url}` +export const invokeExchange: (name: string) => Exchange = + name => + ({forward}) => { + return ops$ => { + const sharedOps$ = share(ops$) + const fetchResults$ = pipe( + sharedOps$, + filter(op => op.kind === 'query' || op.kind === 'mutation'), + mergeMap(operation => { + const {key} = operation + const teardown$ = pipe( + sharedOps$, + filter(op => op.kind === 'teardown' && op.key === key) + ) - console.debug({ - type: 'invokeRequest', - message: 'An invoke request is being executed.', - operation, - data: { - command, - args + const args = { + query: print(operation.query), + variables: operation.variables || undefined } - }) - return pipe( - makeInvokeSource(operation, command, args), - takeUntil(teardown$), - onPush(result => { - const error = !result.data ? result.error : undefined + const command = `plugin:${name}|${operation.context.url}` - console.debug({ - type: error ? 'invokeError' : 'invokeSuccess', - message: `A ${error ? 'failed' : 'successful' + console.debug({ + type: 'invokeRequest', + message: 'An invoke request is being executed.', + operation, + data: { + command, + args + } + }) + + return pipe( + makeInvokeSource(operation, command, args), + takeUntil(teardown$), + onPush(result => { + const error = !result.data ? result.error : undefined + + console.debug({ + type: error ? 'invokeError' : 'invokeSuccess', + message: `A ${ + error ? 'failed' : 'successful' } invoke response has been returned.`, - operation, - data: { - value: error || result - } + operation, + data: { + value: error || result + } + }) }) - }) - ) - }) - ) + ) + }) + ) - const forward$ = pipe( - sharedOps$, - filter(op => op.kind !== 'query' && op.kind !== 'mutation'), - forward - ) + const forward$ = pipe( + sharedOps$, + filter(op => op.kind !== 'query' && op.kind !== 'mutation'), + forward + ) - return merge([fetchResults$, forward$]) + return merge([fetchResults$, forward$]) + } } -} type Response = [body: string, isOk: boolean] @@ -103,7 +107,7 @@ function makeInvokeSource( command: string, invokeArgs: Record ): Source { - return make(({ next, complete }) => { + return make(({next, complete}) => { let ended = false Promise.resolve() @@ -143,33 +147,28 @@ function makeInvokeSource( * * ```javascript * import { createClient } from 'urql' - * import { tauriExchange } from 'tauri-plugin-graphql/urql' + * import { subscriptionExchange } from '@mizuki/urql' * + * const name = "" + * * const client = createClient({ * url: "graphql", // this endpoint is important, don't touch * exchanges: [ - * invokeExchange, - * subscriptionExchange({ - * forwardSubscription: (operation) => ({ - * subscribe: (sink) => ({ - * unsubscribe: subscribe(operation, sink), - * }), - * }), - * }), + * invokeExchange(name), + subscriptionExchange(name) * ], * }); * ``` * - * @param operation The GraphQL Operation generated by urql - * @param sink The sink that will receive the stream of subscription results + * @param name Your plugin name * @returns */ -export function subscribe(name: string) { - return subscriptionExchange({ - forwardSubscription: (operation) => ({ - subscribe: (sink) => { - let unlisten: () => void = () => { } +export function subscriptionExchange(name: string) { + return subEx({ + forwardSubscription: operation => ({ + subscribe: sink => { + let unlisten: () => void = () => {} const id = Math.floor(Math.random() * 10000000) @@ -181,7 +180,9 @@ export function subscribe(name: string) { }) ) .then(_unlisten => (unlisten = _unlisten)) - .then(() => invoke(`plugin:${name}|subscriptions`, { ...operation, id })) + .then(() => + invoke(`plugin:${name}|subscriptions`, {...operation, id}) + ) .catch(err => console.error(err)) return { unsubscribe: unlisten @@ -191,9 +192,26 @@ export function subscribe(name: string) { }) } -export function getExchanges(name: string){ - return [ - invokeExchange(name), - subscribe(name) - ] -} \ No newline at end of file +/** + * Get the `invokeExchange` and the `subscriptionExchange` through one function + * + * ## Example + * + * ```javascript + * import { createClient } from 'urql' + * import { getExchanges } from '@mizuki/urql' + * + * const name = "" + * + * const client = createClient({ + * url: "graphql", // this endpoint is important, don't touch + * exchanges: getExchanges(name) + * }); + * ``` + * + * @param name Your plugin name + * @returns + */ +export function getExchanges(name: string) { + return [invokeExchange(name), subscriptionExchange(name)] +} diff --git a/packages/urql/package.json b/packages/urql/package.json index 71c108e..760a7cf 100644 --- a/packages/urql/package.json +++ b/packages/urql/package.json @@ -2,7 +2,7 @@ "name": "@mizuki/urql", "version": "0.1.0", "description": "A toolkit for building Tauri Plugin that enables type-safe IPC through GraphQL.", - "author": "Jonas Kruckenberg", + "author": "Jonas Kruckenberg, Tony Mushah", "license": "MIT", "repository": "https://github.com/tonymushah/mizuki", "homepage": "https://github.com/tonymushah/mizuki/tree/main/packages/urql", diff --git a/src/lib.rs b/src/lib.rs index 7194137..a2ea600 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ -// Copyright 2022 Jonas Kruckenberg +// Copyright 2023 Tony Mushah // SPDX-License-Identifier: MIT -//! This crate contains a Tauri plugin used to expose a [`async_graphql`] +//! This crate contains a Tauri plugin builder used to expose a [`async_graphql`] //! GraphQL endpoint through Tauri's IPC system. This plugin can be used as //! safer alternative to Tauri's existing Command API since both the Rust and //! JavaScript side of the interface can be generated from a common schema. @@ -71,7 +71,7 @@ //! ); //! //! tauri::Builder::default() -//! .plugin(tauri_plugin_graphql::init(schema)); +//! .plugin(mizuki::MizukiPlugin::new("todo-plugin", schema)); //! ``` //! //! ### Mutations @@ -145,7 +145,7 @@ //! ); //! //! tauri::Builder::default() -//! .plugin(tauri_plugin_graphql::init(schema)) +//! .plugin(mizuki::MizukiPlugin::new("list-plugin", schema)) //! .setup(|app| { //! app.manage(List::default()); //! @@ -194,7 +194,7 @@ //! ); //! //! tauri::Builder::default() -//! .plugin(tauri_plugin_graphql::init(schema)); +//! .plugin(mizuki::MizukiPlugin::new("subsciption", schema)); //! ``` //! //! ## Stability @@ -216,16 +216,17 @@ mod subscription; use subscription::SubscriptionRequest; pub use async_graphql; -use async_graphql::{ - futures_util::StreamExt, BatchRequest, ObjectType, Schema, SubscriptionType, -}; -use std::{any::Any, io::{BufWriter, Write}, fs::File, path::Path}; -use tauri::{ - plugin::Plugin, - Invoke, InvokeError, Manager, Runtime, +use async_graphql::{futures_util::StreamExt, BatchRequest, ObjectType, Schema, SubscriptionType}; +use std::{ + any::Any, + fs::File, + io::{BufWriter, Write}, + path::Path, }; +use tauri::{plugin::Plugin, Invoke, InvokeError, Manager, Runtime}; -pub struct Mizuki +#[derive(Clone)] +pub struct MizukiPlugin where Query: ObjectType + 'static, Mutation: ObjectType + 'static, @@ -237,7 +238,7 @@ where context: Option, } -impl Mizuki +impl MizukiPlugin where Query: ObjectType + 'static, Mutation: ObjectType + 'static, @@ -255,16 +256,25 @@ where context: Some(context), } } + /// Get the actual SDL schema format pub fn sdl(&self) -> String { self.schema.sdl() } + /// Export the schema to a new file pub fn export_sdl>(&self, path: P) -> std::io::Result<()> { let mut file = BufWriter::new(File::create(path)?); file.write_all(self.sdl().as_bytes()) } + pub fn drop_context(self) -> MizukiPlugin<(), Query, Mutation, Subscription> { + MizukiPlugin { + name: self.name, + schema: self.schema, + context: None::<()>, + } + } } -impl Mizuki<(), Query, Mutation, Subscription> +impl MizukiPlugin<(), Query, Mutation, Subscription> where Query: ObjectType + 'static, Mutation: ObjectType + 'static, @@ -277,9 +287,20 @@ where context: None::<()>, } } + pub fn add_context( + self, + context: D, + ) -> MizukiPlugin { + MizukiPlugin { + name: self.name, + schema: self.schema, + context: Some(context), + } + } } -impl Plugin for Mizuki +impl Plugin + for MizukiPlugin where R: Runtime, Query: ObjectType + 'static, @@ -348,4 +369,4 @@ where )), } } -} \ No newline at end of file +}