packages feed

notion-client-effectful (empty) → 0.2.0.0

raw patch · 7 files changed

+1069/−0 lines, 7 filesdep +aesondep +basedep +effectful-core

Dependencies added: aeson, base, effectful-core, notion-client, text

Files

+ CHANGELOG.md view
@@ -0,0 +1,21 @@+# Changelog for `notion-client-effectful`++## 0.2.0.0 - 2026-09-15++### Breaking Changes++* Requires `notion-client >=0.8 && <0.9`.+* `queryDataSource` and `search` now return `ListOf PageOrDataSource` (was `ListOf PageObject` and `ListOf Value`), following `notion-client`.+* `updateBlock` takes `Blocks.BlockUpdatePayload` (was `Blocks.BlockUpdate`).+* `createComment` returns `CommentResponse` (was `CommentObject`).+* Remove `queryView` / `QueryView`; use `createViewQuery`, `getViewQueryResults` and `deleteViewQuery`.++### New Features++* New operations `createPageFiltered`, `updatePageFiltered`, `createPageAsync`, `updatePageMarkdownAsync`, `retrieveAsyncTask`, `retrieveComment`, `updateComment`, `deleteComment`, `createViewQuery`, `getViewQueryResults`, `deleteViewQuery`, `createMeetingNote` and `queryMeetingNotes`.++## 0.1.0.0 - 2026-04-17++* Initial release: `Notion` effect and `runNotion` interpreter covering+  every `Notion.V1.Methods` field at the time of release+  (notion-client 0.7.x).
+ LICENSE view
@@ -0,0 +1,21 @@+MIT License++Copyright (c) 2024 Nadeem Bitar++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ README.md view
@@ -0,0 +1,115 @@+# notion-client-effectful++An [effectful][effectful] surface for+[`notion-client`](https://hackage.haskell.org/package/notion-client).++[effectful]: https://hackage.haskell.org/package/effectful++This package wraps the `Notion.V1.Methods` record as a dynamic+effect — so code written against `effectful` does not have to+thread the `Methods` value through every call site and does not+have to drop into `IO` at each API boundary.++## Purpose++`notion-client` exposes a single `Methods` record whose fields+are `IO`-typed API calls. That is ergonomic for a plain-`IO`+program but awkward for an `effectful`-based caller: every call+requires `liftIO` and escapes the ambient `Error` / `Reader` /+`Log` stack.++`notion-client-effectful` gives that caller an equivalent set of+operations surfaced as an `Effect` so the stack is preserved.++## Import pattern++Every smart constructor shares its name with the matching+`Notion.V1.Methods` record selector. That is on purpose — it+keeps migration from IO mechanical — but it means a file that+imports both modules unqualified will see name clashes. Import+one of the two qualified:++```haskell+import Notion.V1                    (Methods, getClientEnv, makeMethods)+import Notion.V1.Effectful qualified as NE+```++Then `NE.retrievePage`, `NE.search`, `NE.runNotion`, and so on.++## Error handling++`runNotion` catches `Notion.V1.Error.NotionError` thrown by the+underlying `Methods` and re-raises it via the `Error NotionError`+effect, so callers can branch on API error shapes+(`object_not_found`, validation failures, etc.) without reaching+for `IO`-level exception handling.++Other `Servant.Client.ClientError` values — network failures,+decoding errors — are *not* caught and remain `IO` exceptions.+This preserves the contract of the underlying `notion-client`+library and lets callers layer their own `Error ClientError`+interpretation on top later. The same applies to+`UnknownHTTPResponseError`, `RequestTimeoutError` and+`InvalidPathParameterError` from `Notion.V1.Error`. Retries of+rate-limited requests happen inside `Methods`, before an error reaches+`runNotion`.++## Minimum viable usage++```haskell+module Demo where++import Data.Text (Text)+import Data.Text qualified as Text+import Effectful (Eff, runEff, (:>))+import Effectful.Error.Static (Error, runErrorNoCallStack)+import Notion.V1                    (getClientEnv, makeMethods)+import Notion.V1.Common             (UUID (..))+import Notion.V1.Effectful qualified as NE+import Notion.V1.Error              (NotionError)+import System.Environment qualified as Env++demo ::+  (NE.Notion :> es, Error NotionError :> es) =>+  UUID ->+  Eff es Text+demo pid = do+  page <- NE.retrievePage pid+  pure (Text.pack (show page))++main :: IO ()+main = do+  token <- Text.pack <$> Env.getEnv "NOTION_TOKEN"+  env <- getClientEnv "https://api.notion.com/v1"+  let methods = makeMethods env token+  result <-+    runEff+      . runErrorNoCallStack @NotionError+      . NE.runNotion methods+      $ demo (UUID "00000000-0000-0000-0000-000000000000")+  print result+```++## What you get++One smart constructor per field of `Notion.V1.Methods`. The+argument types and order match the underlying field, so an+existing call like++```haskell+page <- retrievePage methods pid+```++becomes++```haskell+page <- NE.retrievePage pid+```++with no other change to the call site.++## Versioning++The `0.y.z` series tracks `notion-client` 0.7.x. A major version+bump is planned if `notion-client` changes the shape of `Methods`+in a way that forces a constructor rename.
+ notion-client-effectful.cabal view
@@ -0,0 +1,62 @@+cabal-version: 3.4+name: notion-client-effectful+version: 0.2.0.0+synopsis: Effectful effects for notion-client+description:+  Effectful effect + default interpreter for shinzui/notion-client.+  Exposes every operation on 'Notion.V1.Methods' as a smart+  constructor of the 'Notion.V1.Effectful.Notion' effect and provides+  a 'runNotion' interpreter that dispatches through a concrete+  @Methods@ value. API-level 'Notion.V1.Error.NotionError' responses+  are surfaced via the @Error NotionError@ effect; other+  @Servant.Client.ClientError@ values remain 'IO' exceptions.+  See @README.md@ for the full import pattern and a worked example.++license: MIT+license-file: LICENSE+author: Nadeem Bitar+maintainer: nadeem@gmail.com+category: Web+build-type: Simple+extra-doc-files:+  CHANGELOG.md+  README.md++common warnings+  ghc-options:+    -Wall+    -Wcompat+    -Widentities+    -Wincomplete-uni-patterns+    -Wincomplete-record-updates+    -Wredundant-constraints+    -fhide-source-paths+    -Wmissing-export-lists+    -Wpartial-fields+    -Wmissing-deriving-strategies++library+  import: warnings+  exposed-modules:+    Notion.V1.Effectful+    Notion.V1.Effectful.Effect+    Notion.V1.Effectful.Interpreter++  default-extensions:+    DataKinds+    DuplicateRecordFields+    GADTs+    LambdaCase+    OverloadedStrings+    TypeFamilies+    TypeOperators++  build-depends:+    aeson >=2.2 && <2.3,+    base >=4.18 && <5,+    effectful-core >=2.5 && <3,+    notion-client >=0.8 && <0.9,+    text >=2.0 && <2.2,++  hs-source-dirs: src+  default-language: GHC2024
+ src/Notion/V1/Effectful.hs view
@@ -0,0 +1,137 @@+-- | Effectful surface for @notion-client@.+--+-- This module re-exports the 'Notion' effect, its smart constructors,+-- and the default 'runNotion' interpreter. A caller typically writes:+--+-- @+-- import Notion.V1                    (Methods, getClientEnv, makeMethods)+-- import Notion.V1.Effectful qualified as NE+-- @+--+-- and then uses @NE.retrievePage@, @NE.search@, @NE.runNotion@, etc.+-- The qualified import avoids name clashes with the matching+-- 'Notion.V1.Methods' record selectors — every smart constructor+-- here shares its name with a field of @Methods@ on purpose, so+-- migrating an IO call site is a near-mechanical rewrite.+--+-- Error handling: 'runNotion' catches 'NotionError' from the+-- underlying 'Methods' value and re-throws via the @Error NotionError@+-- effect. Other 'Servant.Client.ClientError' values (network+-- failures, decoding errors) remain 'IO' exceptions.+module Notion.V1.Effectful+  ( -- * Effect+    Notion,++    -- * Interpreter+    runNotion,++    -- * Databases+    createDatabase,+    retrieveDatabase,+    updateDatabase,+    queryDatabase,++    -- * Data Sources+    retrieveDataSource,+    createDataSource,+    updateDataSource,+    queryDataSource,+    listDataSourceTemplates,++    -- * Pages+    createPage,+    retrievePage,+    retrievePageFiltered,+    updatePage,+    retrievePageProperty,+    retrievePageMarkdown,+    updatePageMarkdown,+    movePage,++    -- * Blocks+    retrieveBlock,+    updateBlock,+    listBlockChildren,+    appendBlockChildren,+    deleteBlock,++    -- * Users+    retrieveUser,+    listUsers,+    retrieveMyUser,++    -- * Search+    search,++    -- * Comments+    createComment,+    listComments,++    -- * Views+    createView,+    retrieveView,+    updateView,+    deleteView,+    listViews,+    createViewQuery,+    getViewQueryResults,+    deleteViewQuery,++    -- * Custom Emojis+    listCustomEmojis,++    -- * File Uploads+    createFileUpload,+    retrieveFileUpload,+    sendFileUploadContent,+    completeFileUpload,+    listFileUploads,+  )+where++import Notion.V1.Effectful.Effect+  ( Notion,+    appendBlockChildren,+    completeFileUpload,+    createComment,+    createDataSource,+    createDatabase,+    createFileUpload,+    createPage,+    createView,+    createViewQuery,+    deleteBlock,+    deleteView,+    deleteViewQuery,+    getViewQueryResults,+    listBlockChildren,+    listComments,+    listCustomEmojis,+    listDataSourceTemplates,+    listFileUploads,+    listUsers,+    listViews,+    movePage,+    queryDataSource,+    queryDatabase,+    retrieveBlock,+    retrieveDataSource,+    retrieveDatabase,+    retrieveFileUpload,+    retrieveMyUser,+    retrievePage,+    retrievePageFiltered,+    retrievePageMarkdown,+    retrievePageProperty,+    retrieveUser,+    retrieveView,+    search,+    sendFileUploadContent,+    updateBlock,+    updateDataSource,+    updateDatabase,+    updatePage,+    updatePageMarkdown,+    updateView,+  )+import Notion.V1.Effectful.Interpreter (runNotion)
+ src/Notion/V1/Effectful/Effect.hs view
@@ -0,0 +1,534 @@+-- | The 'Notion' effect and its smart constructors.+--+-- One constructor per field of 'Notion.V1.Methods'. Each smart+-- constructor has the same name, same argument order, and same+-- argument types as the corresponding @Methods@ field — so migrating+-- an 'IO'-based call site amounts to dropping the explicit+-- @methods@ argument.+--+-- /Import note./ Every smart constructor name clashes with the+-- matching 'Notion.V1.Methods' record selector. Import one of the+-- two modules qualified (mirroring how 'Notion.V1' itself qualifies+-- @Pages@, @Databases@, etc.).+module Notion.V1.Effectful.Effect+  ( -- * Effect+    Notion (..),++    -- * Databases+    createDatabase,+    retrieveDatabase,+    updateDatabase,+    queryDatabase,++    -- * Data Sources+    retrieveDataSource,+    createDataSource,+    updateDataSource,+    queryDataSource,+    listDataSourceTemplates,++    -- * Pages+    createPage,+    createPageFiltered,+    retrievePage,+    retrievePageFiltered,+    updatePage,+    updatePageFiltered,+    retrievePageProperty,+    retrievePageMarkdown,+    updatePageMarkdown,+    movePage,+    createPageAsync,+    updatePageMarkdownAsync,++    -- * Blocks+    retrieveBlock,+    updateBlock,+    listBlockChildren,+    appendBlockChildren,+    deleteBlock,++    -- * Users+    retrieveUser,+    listUsers,+    retrieveMyUser,++    -- * Search+    search,++    -- * Comments+    createComment,+    listComments,+    retrieveComment,+    updateComment,+    deleteComment,++    -- * Views+    createView,+    retrieveView,+    updateView,+    deleteView,+    listViews,+    createViewQuery,+    getViewQueryResults,+    deleteViewQuery,++    -- * Custom Emojis+    listCustomEmojis,++    -- * File Uploads+    createFileUpload,+    retrieveFileUpload,+    sendFileUploadContent,+    completeFileUpload,+    listFileUploads,++    -- * Async Tasks+    retrieveAsyncTask,++    -- * Meeting Notes+    createMeetingNote,+    queryMeetingNotes,+  )+where++import Data.Text (Text)+import Effectful (Dispatch (..), DispatchOf, Eff, Effect, (:>))+import Effectful.Dispatch.Dynamic (send)+import Notion.V1.AsyncTasks (AsyncOr, AsyncTask, AsyncTaskID)+import Notion.V1.Blocks (BlockID, BlockObject)+import Notion.V1.Blocks qualified as Blocks+import Notion.V1.Comments (CommentObject, CommentResponse)+import Notion.V1.Comments qualified as Comments+import Notion.V1.Common (ParentID, UUID)+import Notion.V1.CustomEmojis (CustomEmoji)+import Notion.V1.DataSources (DataSourceID, DataSourceObject)+import Notion.V1.DataSources qualified as DataSources+import Notion.V1.Databases (CreateDatabase, DatabaseID, DatabaseObject, QueryDatabase, UpdateDatabase)+import Notion.V1.FileUploads (FileUploadID, FileUploadObject, FileUploadStatus)+import Notion.V1.FileUploads qualified as FileUploads+import Notion.V1.ListOf (ListOf)+import Notion.V1.MeetingNotes qualified as MeetingNotes+import Notion.V1.Pages (CreatePage, MovePage, PageID, PageMarkdown, PageObject, PartialPageObject, PropertyItemResponse, UpdatePage, UpdatePageMarkdown)+import Notion.V1.Search (PageOrDataSource, SearchRequest)+import Notion.V1.Users (UserID, UserObject)+import Notion.V1.Views (ViewObject)+import Notion.V1.Views qualified as Views+import Numeric.Natural (Natural)++-- | Operations on a Notion workspace.+--+-- One constructor per field of 'Notion.V1.Methods'. The constructor+-- names are the @PascalCase@ form of the field names; argument order+-- matches the field signature.+data Notion :: Effect where+  -- Databases+  CreateDatabase :: CreateDatabase -> Notion m DatabaseObject+  RetrieveDatabase :: DatabaseID -> Notion m DatabaseObject+  UpdateDatabase :: DatabaseID -> UpdateDatabase -> Notion m DatabaseObject+  QueryDatabase :: DatabaseID -> QueryDatabase -> Notion m (ListOf PageObject)+  -- Data Sources+  RetrieveDataSource :: DataSourceID -> Notion m DataSourceObject+  CreateDataSource :: DataSources.CreateDataSource -> Notion m DataSourceObject+  UpdateDataSource :: DataSourceID -> DataSources.UpdateDataSource -> Notion m DataSourceObject+  QueryDataSource :: DataSourceID -> DataSources.QueryDataSource -> Notion m (ListOf DataSources.PageOrDataSource)+  ListDataSourceTemplates ::+    DataSourceID ->+    Maybe Text ->+    Maybe Text ->+    Maybe Natural ->+    Notion m DataSources.ListTemplatesResponse+  -- Pages+  CreatePage :: CreatePage -> Notion m PageObject+  CreatePageFiltered :: [Text] -> CreatePage -> Notion m PageObject+  RetrievePage :: PageID -> Notion m PageObject+  RetrievePageFiltered :: PageID -> [Text] -> Notion m PageObject+  UpdatePage :: PageID -> UpdatePage -> Notion m PageObject+  UpdatePageFiltered :: PageID -> [Text] -> UpdatePage -> Notion m PageObject+  RetrievePageProperty ::+    PageID ->+    Text ->+    Maybe Text ->+    Maybe Natural ->+    Notion m PropertyItemResponse+  RetrievePageMarkdown :: PageID -> Maybe Bool -> Notion m PageMarkdown+  UpdatePageMarkdown :: PageID -> UpdatePageMarkdown -> Notion m PageMarkdown+  MovePage :: PageID -> MovePage -> Notion m PageObject+  CreatePageAsync :: CreatePage -> Notion m (AsyncOr PageObject)+  UpdatePageMarkdownAsync :: PageID -> UpdatePageMarkdown -> Notion m (AsyncOr PageMarkdown)+  -- Blocks+  RetrieveBlock :: BlockID -> Notion m BlockObject+  UpdateBlock :: BlockID -> Blocks.BlockUpdatePayload -> Notion m BlockObject+  ListBlockChildren :: ParentID -> Maybe Natural -> Maybe Text -> Notion m (ListOf BlockObject)+  AppendBlockChildren :: ParentID -> Blocks.AppendBlockChildren -> Notion m (ListOf BlockObject)+  DeleteBlock :: BlockID -> Notion m BlockObject+  -- Users+  RetrieveUser :: UserID -> Notion m UserObject+  ListUsers :: Maybe Natural -> Maybe Text -> Notion m (ListOf UserObject)+  RetrieveMyUser :: Notion m UserObject+  -- Search+  Search :: SearchRequest -> Notion m (ListOf PageOrDataSource)+  -- Comments+  CreateComment :: Comments.CreateComment -> Notion m CommentResponse+  ListComments :: Maybe BlockID -> Maybe Text -> Maybe Natural -> Notion m (ListOf CommentObject)+  RetrieveComment :: Comments.CommentID -> Notion m CommentResponse+  UpdateComment :: Comments.CommentID -> Comments.CommentContent -> Notion m CommentResponse+  DeleteComment :: Comments.CommentID -> Notion m CommentResponse+  -- Views+  CreateView :: Views.CreateView -> Notion m ViewObject+  RetrieveView :: Views.ViewID -> Notion m ViewObject+  UpdateView :: Views.ViewID -> Views.UpdateView -> Notion m ViewObject+  DeleteView :: Views.ViewID -> Notion m ViewObject+  ListViews ::+    Maybe UUID ->+    Maybe UUID ->+    Maybe Text ->+    Maybe Natural ->+    Notion m (ListOf ViewObject)+  CreateViewQuery :: Views.ViewID -> Views.CreateViewQuery -> Notion m Views.ViewQuery+  GetViewQueryResults :: Views.ViewID -> Views.ViewQueryID -> Maybe Text -> Maybe Natural -> Notion m (ListOf PartialPageObject)+  DeleteViewQuery :: Views.ViewID -> Views.ViewQueryID -> Notion m Views.DeletedViewQuery+  -- Custom Emojis+  ListCustomEmojis ::+    Maybe Text ->+    Maybe Text ->+    Maybe Natural ->+    Notion m (ListOf CustomEmoji)+  -- File Uploads+  CreateFileUpload :: FileUploads.CreateFileUpload -> Notion m FileUploadObject+  RetrieveFileUpload :: FileUploadID -> Notion m FileUploadObject+  SendFileUploadContent :: FileUploadID -> FileUploads.SendFileUpload -> Notion m FileUploadObject+  CompleteFileUpload :: FileUploadID -> Notion m FileUploadObject+  ListFileUploads ::+    Maybe FileUploadStatus ->+    Maybe Text ->+    Maybe Natural ->+    Notion m (ListOf FileUploadObject)+  -- Async Tasks+  RetrieveAsyncTask :: AsyncTaskID -> Notion m AsyncTask+  -- Meeting Notes+  CreateMeetingNote :: MeetingNotes.CreateMeetingNote -> Notion m MeetingNotes.CreateMeetingNoteResponse+  QueryMeetingNotes :: MeetingNotes.QueryMeetingNotes -> Notion m MeetingNotes.QueryMeetingNotesResponse++type instance DispatchOf Notion = 'Dynamic++-- ── Databases ─────────────────────────────────────────────────────++-- | See 'Notion.V1.Methods'.'Notion.V1.createDatabase'.+createDatabase :: (Notion :> es) => CreateDatabase -> Eff es DatabaseObject+createDatabase = send . CreateDatabase++-- | See 'Notion.V1.Methods'.'Notion.V1.retrieveDatabase'.+retrieveDatabase :: (Notion :> es) => DatabaseID -> Eff es DatabaseObject+retrieveDatabase = send . RetrieveDatabase++-- | See 'Notion.V1.Methods'.'Notion.V1.updateDatabase'.+updateDatabase :: (Notion :> es) => DatabaseID -> UpdateDatabase -> Eff es DatabaseObject+updateDatabase dbId upd = send (UpdateDatabase dbId upd)++{-# DEPRECATED queryDatabase "Use 'queryDataSource' instead." #-}++-- | See 'Notion.V1.Methods'.'Notion.V1.queryDatabase'. Deprecated upstream;+-- the constructor is retained for parity so existing call sites can migrate+-- in lockstep with the base library.+queryDatabase ::+  (Notion :> es) =>+  DatabaseID ->+  QueryDatabase ->+  Eff es (ListOf PageObject)+queryDatabase dbId q = send (QueryDatabase dbId q)++-- ── Data Sources ──────────────────────────────────────────────────++-- | See 'Notion.V1.Methods'.'Notion.V1.retrieveDataSource'.+retrieveDataSource :: (Notion :> es) => DataSourceID -> Eff es DataSourceObject+retrieveDataSource = send . RetrieveDataSource++-- | See 'Notion.V1.Methods'.'Notion.V1.createDataSource'.+createDataSource :: (Notion :> es) => DataSources.CreateDataSource -> Eff es DataSourceObject+createDataSource = send . CreateDataSource++-- | See 'Notion.V1.Methods'.'Notion.V1.updateDataSource'.+updateDataSource ::+  (Notion :> es) =>+  DataSourceID ->+  DataSources.UpdateDataSource ->+  Eff es DataSourceObject+updateDataSource dsId upd = send (UpdateDataSource dsId upd)++-- | See 'Notion.V1.Methods'.'Notion.V1.queryDataSource'.+queryDataSource ::+  (Notion :> es) =>+  DataSourceID ->+  DataSources.QueryDataSource ->+  Eff es (ListOf DataSources.PageOrDataSource)+queryDataSource dsId q = send (QueryDataSource dsId q)++-- | See 'Notion.V1.Methods'.'Notion.V1.listDataSourceTemplates'.+listDataSourceTemplates ::+  (Notion :> es) =>+  DataSourceID ->+  Maybe Text ->+  Maybe Text ->+  Maybe Natural ->+  Eff es DataSources.ListTemplatesResponse+listDataSourceTemplates dsId nameFilter startCursor pageSize =+  send (ListDataSourceTemplates dsId nameFilter startCursor pageSize)++-- ── Pages ─────────────────────────────────────────────────────────++-- | See 'Notion.V1.Methods'.'Notion.V1.createPage'.+createPage :: (Notion :> es) => CreatePage -> Eff es PageObject+createPage = send . CreatePage++-- | See 'Notion.V1.Methods'.'Notion.V1.createPageFiltered'.+createPageFiltered :: (Notion :> es) => [Text] -> CreatePage -> Eff es PageObject+createPageFiltered props req = send (CreatePageFiltered props req)++-- | See 'Notion.V1.Methods'.'Notion.V1.retrievePage'.+retrievePage :: (Notion :> es) => PageID -> Eff es PageObject+retrievePage = send . RetrievePage++-- | See 'Notion.V1.Methods'.'Notion.V1.retrievePageFiltered'.+retrievePageFiltered :: (Notion :> es) => PageID -> [Text] -> Eff es PageObject+retrievePageFiltered pid props = send (RetrievePageFiltered pid props)++-- | See 'Notion.V1.Methods'.'Notion.V1.updatePage'.+updatePage :: (Notion :> es) => PageID -> UpdatePage -> Eff es PageObject+updatePage pid upd = send (UpdatePage pid upd)++-- | See 'Notion.V1.Methods'.'Notion.V1.updatePageFiltered'.+updatePageFiltered :: (Notion :> es) => PageID -> [Text] -> UpdatePage -> Eff es PageObject+updatePageFiltered pid props upd = send (UpdatePageFiltered pid props upd)++-- | See 'Notion.V1.Methods'.'Notion.V1.retrievePageProperty'.+retrievePageProperty ::+  (Notion :> es) =>+  PageID ->+  Text ->+  Maybe Text ->+  Maybe Natural ->+  Eff es PropertyItemResponse+retrievePageProperty pid prop cursor size =+  send (RetrievePageProperty pid prop cursor size)++-- | See 'Notion.V1.Methods'.'Notion.V1.retrievePageMarkdown'.+retrievePageMarkdown :: (Notion :> es) => PageID -> Maybe Bool -> Eff es PageMarkdown+retrievePageMarkdown pid includeTx = send (RetrievePageMarkdown pid includeTx)++-- | See 'Notion.V1.Methods'.'Notion.V1.updatePageMarkdown'.+updatePageMarkdown :: (Notion :> es) => PageID -> UpdatePageMarkdown -> Eff es PageMarkdown+updatePageMarkdown pid upd = send (UpdatePageMarkdown pid upd)++-- | See 'Notion.V1.Methods'.'Notion.V1.movePage'.+movePage :: (Notion :> es) => PageID -> MovePage -> Eff es PageObject+movePage pid mv = send (MovePage pid mv)++-- | See 'Notion.V1.Methods'.'Notion.V1.createPageAsync'.+createPageAsync :: (Notion :> es) => CreatePage -> Eff es (AsyncOr PageObject)+createPageAsync = send . CreatePageAsync++-- | See 'Notion.V1.Methods'.'Notion.V1.updatePageMarkdownAsync'.+updatePageMarkdownAsync ::+  (Notion :> es) =>+  PageID ->+  UpdatePageMarkdown ->+  Eff es (AsyncOr PageMarkdown)+updatePageMarkdownAsync pid upd = send (UpdatePageMarkdownAsync pid upd)++-- ── Blocks ────────────────────────────────────────────────────────++-- | See 'Notion.V1.Methods'.'Notion.V1.retrieveBlock'.+retrieveBlock :: (Notion :> es) => BlockID -> Eff es BlockObject+retrieveBlock = send . RetrieveBlock++-- | See 'Notion.V1.Methods'.'Notion.V1.updateBlock'.+updateBlock :: (Notion :> es) => BlockID -> Blocks.BlockUpdatePayload -> Eff es BlockObject+updateBlock bid upd = send (UpdateBlock bid upd)++-- | See 'Notion.V1.Methods'.'Notion.V1.listBlockChildren'.+listBlockChildren ::+  (Notion :> es) =>+  ParentID ->+  Maybe Natural ->+  Maybe Text ->+  Eff es (ListOf BlockObject)+listBlockChildren pid pageSize startCursor =+  send (ListBlockChildren pid pageSize startCursor)++-- | See 'Notion.V1.Methods'.'Notion.V1.appendBlockChildren'.+appendBlockChildren ::+  (Notion :> es) =>+  ParentID ->+  Blocks.AppendBlockChildren ->+  Eff es (ListOf BlockObject)+appendBlockChildren pid append = send (AppendBlockChildren pid append)++-- | See 'Notion.V1.Methods'.'Notion.V1.deleteBlock'.+deleteBlock :: (Notion :> es) => BlockID -> Eff es BlockObject+deleteBlock = send . DeleteBlock++-- ── Users ─────────────────────────────────────────────────────────++-- | See 'Notion.V1.Methods'.'Notion.V1.retrieveUser'.+retrieveUser :: (Notion :> es) => UserID -> Eff es UserObject+retrieveUser = send . RetrieveUser++-- | See 'Notion.V1.Methods'.'Notion.V1.listUsers'.+listUsers :: (Notion :> es) => Maybe Natural -> Maybe Text -> Eff es (ListOf UserObject)+listUsers pageSize startCursor = send (ListUsers pageSize startCursor)++-- | See 'Notion.V1.Methods'.'Notion.V1.retrieveMyUser'.+retrieveMyUser :: (Notion :> es) => Eff es UserObject+retrieveMyUser = send RetrieveMyUser++-- ── Search ────────────────────────────────────────────────────────++-- | See 'Notion.V1.Methods'.'Notion.V1.search'.+search :: (Notion :> es) => SearchRequest -> Eff es (ListOf PageOrDataSource)+search = send . Search++-- ── Comments ──────────────────────────────────────────────────────++-- | See 'Notion.V1.Methods'.'Notion.V1.createComment'.+createComment :: (Notion :> es) => Comments.CreateComment -> Eff es CommentResponse+createComment = send . CreateComment++-- | See 'Notion.V1.Methods'.'Notion.V1.listComments'.+listComments ::+  (Notion :> es) =>+  Maybe BlockID ->+  Maybe Text ->+  Maybe Natural ->+  Eff es (ListOf CommentObject)+listComments bid startCursor pageSize = send (ListComments bid startCursor pageSize)++-- | See 'Notion.V1.Methods'.'Notion.V1.retrieveComment'.+retrieveComment :: (Notion :> es) => Comments.CommentID -> Eff es CommentResponse+retrieveComment = send . RetrieveComment++-- | See 'Notion.V1.Methods'.'Notion.V1.updateComment'.+updateComment ::+  (Notion :> es) =>+  Comments.CommentID ->+  Comments.CommentContent ->+  Eff es CommentResponse+updateComment cid content = send (UpdateComment cid content)++-- | See 'Notion.V1.Methods'.'Notion.V1.deleteComment'.+deleteComment :: (Notion :> es) => Comments.CommentID -> Eff es CommentResponse+deleteComment = send . DeleteComment++-- ── Views ─────────────────────────────────────────────────────────++-- | See 'Notion.V1.Methods'.'Notion.V1.createView'.+createView :: (Notion :> es) => Views.CreateView -> Eff es ViewObject+createView = send . CreateView++-- | See 'Notion.V1.Methods'.'Notion.V1.retrieveView'.+retrieveView :: (Notion :> es) => Views.ViewID -> Eff es ViewObject+retrieveView = send . RetrieveView++-- | See 'Notion.V1.Methods'.'Notion.V1.updateView'.+updateView :: (Notion :> es) => Views.ViewID -> Views.UpdateView -> Eff es ViewObject+updateView vid upd = send (UpdateView vid upd)++-- | See 'Notion.V1.Methods'.'Notion.V1.deleteView'.+deleteView :: (Notion :> es) => Views.ViewID -> Eff es ViewObject+deleteView = send . DeleteView++-- | See 'Notion.V1.Methods'.'Notion.V1.listViews'.+listViews ::+  (Notion :> es) =>+  Maybe UUID ->+  Maybe UUID ->+  Maybe Text ->+  Maybe Natural ->+  Eff es (ListOf ViewObject)+listViews dbId dsId startCursor pageSize =+  send (ListViews dbId dsId startCursor pageSize)++-- | See 'Notion.V1.Methods'.'Notion.V1.createViewQuery'.+createViewQuery :: (Notion :> es) => Views.ViewID -> Views.CreateViewQuery -> Eff es Views.ViewQuery+createViewQuery vid req = send (CreateViewQuery vid req)++-- | See 'Notion.V1.Methods'.'Notion.V1.getViewQueryResults'.+getViewQueryResults ::+  (Notion :> es) =>+  Views.ViewID ->+  Views.ViewQueryID ->+  Maybe Text ->+  Maybe Natural ->+  Eff es (ListOf PartialPageObject)+getViewQueryResults vid qid cursor size = send (GetViewQueryResults vid qid cursor size)++-- | See 'Notion.V1.Methods'.'Notion.V1.deleteViewQuery'.+deleteViewQuery :: (Notion :> es) => Views.ViewID -> Views.ViewQueryID -> Eff es Views.DeletedViewQuery+deleteViewQuery vid qid = send (DeleteViewQuery vid qid)++-- ── Custom Emojis ─────────────────────────────────────────────────++-- | See 'Notion.V1.Methods'.'Notion.V1.listCustomEmojis'.+listCustomEmojis ::+  (Notion :> es) =>+  Maybe Text ->+  Maybe Text ->+  Maybe Natural ->+  Eff es (ListOf CustomEmoji)+listCustomEmojis nameFilter startCursor pageSize =+  send (ListCustomEmojis nameFilter startCursor pageSize)++-- ── File Uploads ──────────────────────────────────────────────────++-- | See 'Notion.V1.Methods'.'Notion.V1.createFileUpload'.+createFileUpload :: (Notion :> es) => FileUploads.CreateFileUpload -> Eff es FileUploadObject+createFileUpload = send . CreateFileUpload++-- | See 'Notion.V1.Methods'.'Notion.V1.retrieveFileUpload'.+retrieveFileUpload :: (Notion :> es) => FileUploadID -> Eff es FileUploadObject+retrieveFileUpload = send . RetrieveFileUpload++-- | See 'Notion.V1.Methods'.'Notion.V1.sendFileUploadContent'.+sendFileUploadContent ::+  (Notion :> es) =>+  FileUploadID ->+  FileUploads.SendFileUpload ->+  Eff es FileUploadObject+sendFileUploadContent fid payload = send (SendFileUploadContent fid payload)++-- | See 'Notion.V1.Methods'.'Notion.V1.completeFileUpload'.+completeFileUpload :: (Notion :> es) => FileUploadID -> Eff es FileUploadObject+completeFileUpload = send . CompleteFileUpload++-- | See 'Notion.V1.Methods'.'Notion.V1.listFileUploads'.+listFileUploads ::+  (Notion :> es) =>+  Maybe FileUploadStatus ->+  Maybe Text ->+  Maybe Natural ->+  Eff es (ListOf FileUploadObject)+listFileUploads statusFilter startCursor pageSize =+  send (ListFileUploads statusFilter startCursor pageSize)++-- ── Async Tasks ───────────────────────────────────────────────────++-- | See 'Notion.V1.Methods'.'Notion.V1.retrieveAsyncTask'. Pass it to+-- 'Notion.V1.AsyncTasks.waitForAsyncTask' to poll from 'Eff'.+retrieveAsyncTask :: (Notion :> es) => AsyncTaskID -> Eff es AsyncTask+retrieveAsyncTask = send . RetrieveAsyncTask++-- ── Meeting Notes ─────────────────────────────────────────────────++-- | See 'Notion.V1.Methods'.'Notion.V1.createMeetingNote'.+createMeetingNote ::+  (Notion :> es) =>+  MeetingNotes.CreateMeetingNote ->+  Eff es MeetingNotes.CreateMeetingNoteResponse+createMeetingNote = send . CreateMeetingNote++-- | See 'Notion.V1.Methods'.'Notion.V1.queryMeetingNotes'.+queryMeetingNotes ::+  (Notion :> es) =>+  MeetingNotes.QueryMeetingNotes ->+  Eff es MeetingNotes.QueryMeetingNotesResponse+queryMeetingNotes = send . QueryMeetingNotes
+ src/Notion/V1/Effectful/Interpreter.hs view
@@ -0,0 +1,179 @@+-- | Default interpreter for the 'Notion' effect.+--+-- 'runNotion' dispatches every 'Notion' constructor through a+-- concrete 'Notion.V1.Methods' value. Any 'NotionError' thrown by+-- the underlying 'IO' action is caught and re-raised via the+-- 'Error' effect, so callers can branch on Notion API error shapes+-- (e.g. @object_not_found@) without resorting to 'IO'-level exception+-- handling. Other 'Servant.Client.ClientError' values (network+-- failures, decoding errors) are intentionally /not/ caught: they+-- remain 'IO' exceptions, preserving the existing 'Notion.V1' contract.+-- The same holds for 'Notion.V1.Error.UnknownHTTPResponseError',+-- 'Notion.V1.Error.RequestTimeoutError' and+-- 'Notion.V1.Error.InvalidPathParameterError'. Retries happen inside the+-- 'Notion.V1.Methods' value, before an error reaches the interpreter.+module Notion.V1.Effectful.Interpreter+  ( runNotion,+  )+where++import Control.Exception qualified as Exception+import Effectful (Eff, IOE, liftIO, (:>))+import Effectful.Dispatch.Dynamic (interpret)+import Effectful.Error.Static (Error, throwError)+import Notion.V1 (Methods)+import Notion.V1 qualified as Notion+import Notion.V1.Effectful.Effect+  ( Notion+      ( AppendBlockChildren,+        CompleteFileUpload,+        CreateComment,+        CreateDataSource,+        CreateDatabase,+        CreateFileUpload,+        CreateMeetingNote,+        CreatePage,+        CreatePageAsync,+        CreatePageFiltered,+        CreateView,+        CreateViewQuery,+        DeleteBlock,+        DeleteComment,+        DeleteView,+        DeleteViewQuery,+        GetViewQueryResults,+        ListBlockChildren,+        ListComments,+        ListCustomEmojis,+        ListDataSourceTemplates,+        ListFileUploads,+        ListUsers,+        ListViews,+        MovePage,+        QueryDataSource,+        QueryDatabase,+        QueryMeetingNotes,+        RetrieveAsyncTask,+        RetrieveBlock,+        RetrieveComment,+        RetrieveDataSource,+        RetrieveDatabase,+        RetrieveFileUpload,+        RetrieveMyUser,+        RetrievePage,+        RetrievePageFiltered,+        RetrievePageMarkdown,+        RetrievePageProperty,+        RetrieveUser,+        RetrieveView,+        Search,+        SendFileUploadContent,+        UpdateBlock,+        UpdateComment,+        UpdateDataSource,+        UpdateDatabase,+        UpdatePage,+        UpdatePageFiltered,+        UpdatePageMarkdown,+        UpdatePageMarkdownAsync,+        UpdateView+      ),+  )+import Notion.V1.Error (NotionError)++-- | Interpret 'Notion' using a concrete 'Methods' value.+--+-- >>> runEff . runErrorNoCallStack @NotionError . runNotion methods $ retrievePage pid+--+-- The dispatched 'IO' action is wrapped with 'Control.Exception.try':+-- a 'NotionError' is re-thrown via 'throwError', anything else+-- propagates as an 'IO' exception.+runNotion ::+  (IOE :> es, Error NotionError :> es) =>+  Methods ->+  Eff (Notion : es) a ->+  Eff es a+runNotion methods = interpret $ \_ -> \case+  -- Databases+  CreateDatabase req -> runIO (Notion.createDatabase methods req)+  RetrieveDatabase dbId -> runIO (Notion.retrieveDatabase methods dbId)+  UpdateDatabase dbId req -> runIO (Notion.updateDatabase methods dbId req)+  QueryDatabase dbId req -> runIO (Notion.queryDatabase methods dbId req)+  -- Data Sources+  RetrieveDataSource dsId -> runIO (Notion.retrieveDataSource methods dsId)+  CreateDataSource req -> runIO (Notion.createDataSource methods req)+  UpdateDataSource dsId req -> runIO (Notion.updateDataSource methods dsId req)+  QueryDataSource dsId req -> runIO (Notion.queryDataSource methods dsId req)+  ListDataSourceTemplates dsId nameFilter cursor pageSize ->+    runIO (Notion.listDataSourceTemplates methods dsId nameFilter cursor pageSize)+  -- Pages+  CreatePage req -> runIO (Notion.createPage methods req)+  CreatePageFiltered props req -> runIO (Notion.createPageFiltered methods props req)+  RetrievePage pid -> runIO (Notion.retrievePage methods pid)+  RetrievePageFiltered pid props -> runIO (Notion.retrievePageFiltered methods pid props)+  UpdatePage pid req -> runIO (Notion.updatePage methods pid req)+  UpdatePageFiltered pid props req -> runIO (Notion.updatePageFiltered methods pid props req)+  RetrievePageProperty pid prop cursor size ->+    runIO (Notion.retrievePageProperty methods pid prop cursor size)+  RetrievePageMarkdown pid includeTx ->+    runIO (Notion.retrievePageMarkdown methods pid includeTx)+  UpdatePageMarkdown pid req -> runIO (Notion.updatePageMarkdown methods pid req)+  MovePage pid req -> runIO (Notion.movePage methods pid req)+  CreatePageAsync req -> runIO (Notion.createPageAsync methods req)+  UpdatePageMarkdownAsync pid req -> runIO (Notion.updatePageMarkdownAsync methods pid req)+  -- Blocks+  RetrieveBlock bid -> runIO (Notion.retrieveBlock methods bid)+  UpdateBlock bid req -> runIO (Notion.updateBlock methods bid req)+  ListBlockChildren pid pageSize cursor ->+    runIO (Notion.listBlockChildren methods pid pageSize cursor)+  AppendBlockChildren pid req -> runIO (Notion.appendBlockChildren methods pid req)+  DeleteBlock bid -> runIO (Notion.deleteBlock methods bid)+  -- Users+  RetrieveUser uid -> runIO (Notion.retrieveUser methods uid)+  ListUsers pageSize cursor -> runIO (Notion.listUsers methods pageSize cursor)+  RetrieveMyUser -> runIO (Notion.retrieveMyUser methods)+  -- Search+  Search req -> runIO (Notion.search methods req)+  -- Comments+  CreateComment req -> runIO (Notion.createComment methods req)+  ListComments bid cursor pageSize ->+    runIO (Notion.listComments methods bid cursor pageSize)+  RetrieveComment cid -> runIO (Notion.retrieveComment methods cid)+  UpdateComment cid content -> runIO (Notion.updateComment methods cid content)+  DeleteComment cid -> runIO (Notion.deleteComment methods cid)+  -- Views+  CreateView req -> runIO (Notion.createView methods req)+  RetrieveView vid -> runIO (Notion.retrieveView methods vid)+  UpdateView vid req -> runIO (Notion.updateView methods vid req)+  DeleteView vid -> runIO (Notion.deleteView methods vid)+  ListViews dbId dsId cursor pageSize ->+    runIO (Notion.listViews methods dbId dsId cursor pageSize)+  CreateViewQuery vid req -> runIO (Notion.createViewQuery methods vid req)+  GetViewQueryResults vid qid cursor size ->+    runIO (Notion.getViewQueryResults methods vid qid cursor size)+  DeleteViewQuery vid qid -> runIO (Notion.deleteViewQuery methods vid qid)+  -- Custom Emojis+  ListCustomEmojis nameFilter cursor pageSize ->+    runIO (Notion.listCustomEmojis methods nameFilter cursor pageSize)+  -- File Uploads+  CreateFileUpload req -> runIO (Notion.createFileUpload methods req)+  RetrieveFileUpload fid -> runIO (Notion.retrieveFileUpload methods fid)+  SendFileUploadContent fid payload ->+    runIO (Notion.sendFileUploadContent methods fid payload)+  CompleteFileUpload fid -> runIO (Notion.completeFileUpload methods fid)+  ListFileUploads statusFilter cursor pageSize ->+    runIO (Notion.listFileUploads methods statusFilter cursor pageSize)+  -- Async Tasks+  RetrieveAsyncTask tid -> runIO (Notion.retrieveAsyncTask methods tid)+  -- Meeting Notes+  CreateMeetingNote req -> runIO (Notion.createMeetingNote methods req)+  QueryMeetingNotes req -> runIO (Notion.queryMeetingNotes methods req)++-- | Run an 'IO' action, funneling any thrown 'NotionError' through+-- the 'Error' effect.+runIO :: (IOE :> es, Error NotionError :> es) => IO a -> Eff es a+runIO action = do+  result <- liftIO (Exception.try action)+  case result of+    Left (ne :: NotionError) -> throwError ne+    Right a -> pure a