GithubHelp home page GithubHelp logo

lemmynet / lemmy-js-client Goto Github PK

View Code? Open in Web Editor NEW
135.0 135.0 55.0 931 KB

A javascript / typescript http and websocket client and type system for Lemmy.

License: GNU Affero General Public License v3.0

TypeScript 98.72% Shell 0.63% JavaScript 0.65%

lemmy-js-client's People

Contributors

aeharding avatar arseniy-gl avatar biosfood avatar cinderisles avatar dessalines avatar experibass avatar flamingo-cant-draw avatar hbroer avatar ismailkarsli avatar l3v3l avatar makotech222 avatar matc-pub avatar mv-gh avatar nothing4you avatar nutomic avatar shilangyu avatar sleeplessone1917 avatar sunaurus avatar tgxn avatar thebrokenrail avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lemmy-js-client's Issues

Create a common interface for http/websocket

The apis of this library are completely separate, depending on whether you use it over http or websocket. This means any application needs to pick one or the other, and switching between them would require code changes. I think its possible to rewrite the code, so that the backend can easily be switched at runtime.

It would roughly look like this:

interface LemmyApi {
  async getSite(form: GetSite): Promise<GetSiteResponse>;
  async createSite(form: CreateSite): Promise<SiteResponse>;
}

class Websocket implements LemmyApi {
  ...
}

class Http implements LemmyApi {
  ...
}

Then the application just needs to construct either Websocket or Http class on startup depending on some conditions. For the rest of the code, it deals with LemmyApi, and doesnt need to care about the connection method at all.

getUnreadRegistrationApplicationCount returns bad request

I'm simply doing this:

await client.getUnreadRegistrationApplicationCount({
  auth: jwt,
});

and it keeps throwing Bad Request, I am logged in as an instance Admin and the backend is running on version 0.18.4 and the version of lemmy-js-client I have installed is the latest on npm (0.19.0-rc.8)

using client.listRegistrationApplications({ auth: jwt, unread_only: true }) also seems to be giving Bad Request when there is an entry? otherwise it does successfully return empty arrays when there's nothing.

Make types for arguments not error when not using monads

Suppose I want to get comments (http or websockets, it affects both).

If I'm using typescript, I need to write something like this:

client.getComments({
    sort: CommentSortType.NEW
} as unknown as GetComments);

Bleck! This is necessary for many of the client functions. The issue seems to be with the Option monad. Even though there's logic in the class to transform the values into options where needed, typescript doesn't know about this.

Fortunately I think I know the right bit of typescript-foo to get around this with a single utility type. Expect a PR from me on this issue in the near future.

P.S. Don't let the double issue posting fool you, I love the project so much so that a Lemmy instance has become my primary stop for my social media needs. Keep up the great work!

Large limit filter leads to JSON parse error

request: client.listCommunities,
payload:

{
    auth: "my jwt",
    type_: "Subscribed",
    limit: 999,
    page: 1,
    sort: "TopAll",
  }

Result:
[SyntaxError: JSON Parse error: Unexpected token: F]

image

Semi-related: is there any better way to actually pull all communities user is subscribed to? This endpoint just returns a community list without total/pages and I have no idea how far pagination should go (which actually causes bug on web: open communities/listing_type/Subscribed/page/1 and click next page until you see empty screen)

Create post doesnt support an image

When you create a post via the GUI you can select an image, but the JS API does not support it currently.

In many cases this doesn't matter because a thumbnail image will be automaticly retrieved from the posted URL, but for URL's that don't provide an image, it would be nice to be able to explictly specify the thumbnail.

Move Necessary dependencies from dev dependencies to dependencies

Currently if you want to use the client you have to import the following dependencies:

  • @sniptt/monads
  • class-transformer
  • node-fetch
  • reflect-metadata

In addition to this, I couldn't get my code to work with the latest version of node-fetch. I wouldn't have even thought to use a lower version of that specific dependency had I not seen the most recent issue before this one. I don't think it makes much sense to manually install dependencies that your dependencies depend on unless you happen to need to use them directly.

Fixing this should be as easy as moving the previously listed dependencies from devDependencies to dependencies in package.json and maybe pinning the correct version of node-fetch. I'll make a PR either on my lunch break or after work.

Pictrs upload

Do the devs think it makes sense to add a function to the LemmyHttp class that handles uploading pictures to pictrs? I imagine it would look a lot like the following code from lemmy-ui minus all the UI related logic:

handleImageUpload(i: ImageUploadForm, event: any) {
    event.preventDefault();
    let file = event.target.files[0];
    const formData = new FormData();
    formData.append("images[]", file);

    i.setState({ loading: true });

    fetch(pictrsUri, {
      method: "POST",
      body: formData,
    })
      .then(res => res.json())
      .then(res => {
        console.log("pictrs upload:");
        console.log(res);
        if (res.msg == "ok") {
          let hash = res.files[0].file;
          let url = `${pictrsUri}/${hash}`;
          i.setState({ loading: false });
          i.props.onUpload(url);
        } else {
          i.setState({ loading: false });
          toast(JSON.stringify(res), "danger");
        }
      })
      .catch(error => {
        i.setState({ loading: false });
        console.error(error);
        toast(error, "danger");
      });
  }

Adapting the previous code for the LemmyHttp class, the implementation could look something like this:

async uploadImage(image: File) {
  const formData = new FormData();
  formData.append('images[]', image);

  let url: string | undefined = undefined;
  let deleteUrl: string | undefined = undefined;

  const response = await fetch(pictrsUri, {
    method: 'POST',
    body: formData
  });

  const response_json = await response.json();

  console.log('pictrs upload:');
  console.log(response_json);

  if (response_json.msg == 'ok') {
    const { file: hash, delete_token: deleteToken } = response_json.files[0];
    deleteUrl = `${pictrsUri}/delete/${deleteToken}/${hash}`;
    url = `${pictrsUri}/${hash}`;
  }

  return {
    ...response_json,
    url,
    deleteUrl
  };
}

Refactoring the UI code I got the implementation idea from to use the function could look like this:

handleImageUpload(i: ImageUploadForm, event: any) {
  event.preventDefault();
  const file = event.target.files[0];

  client.uploadImage(file).then((res) => {
    console.log('pictrs upload:');
    console.log(res);
    if (res.msg == 'ok') {
      i.setState({ loading: false });
      i.props.onUpload(res.url);
    } else {
      i.setState({ loading: false });
      toast(JSON.stringify(res), 'danger');
    }
  }).catch(error => {
    i.setState({ loading: false });
    console.error(error);
    toast(error, 'danger');
  });
}

If @dessalines and/or @Nutomic like the idea I can open a PR with the change.

Help with implementing in a Nodejs environment

Hey, I'm having trouble getting this to work with the code provided in the README. I would like to have the capability to add posts from a nodejs backend.

I've played around with the README code a bit. I added packages including @sniptt/monads, class-transformer, [email protected] and reflect-metadata. I wasn't quite sure what needs to be included with in the headers?

I have the following and I'm attempting to log in using an administrator account. What's the purpose of retrieving a jwt once logged in?

import {{ LemmyHttp }} from 'lemmy-js-client';

var loginForm = {
    username_or_email: "username",
    password: "password"
};

var baseUrl = 'https://mydomain.io';
var client = new LemmyHttp(baseUrl);
var jwt = await client.login(loginForm).jwt;

Apologies if I'm missing something simple! Appreciate any guidance ๐Ÿ™

API for Crossposting

Hi, I wanted to ask how to crosspost posts between different communities, beacuse I didn't found anything in the documentation.

TypeScript objects do not consider that a field of "error" may be returned at any time (ResolveObjectResponse example)

I am working with lemmy_server's api_tests code, such as comments: https://github.com/LemmyNet/lemmy/blob/38c621091273822f798dfd75046b9ce724cf4bc1/api_tests/src/comment.spec.ts#L42

I am finding that the testing code does not consider an Internet outage/no network interface, and does not look for JSON { error: "lemmy_error_message" } responses from the API.

For example, in the above comments beforeAll function, it is the first time Internet failure is found when a system has non-localhost networking disabled. Example of more noisy code to detect this situation:

  let resCommunity = await resolveBetaCommunity(alpha);
  expect(resCommunity).toBeDefined();
  expect(resCommunity.error).toBeUndefined();  // TypeScript does not like this error field reference
  let betaCommunity = resCommunity.community;
  expect(betaCommunity).toBeDefined();
  if (betaCommunity) {

The problem is that the Lemmy ResolveObjectResponse has no field for error, and TypeScript does not accept checking that it is undefined (Property 'error' does not exist on type 'ResolveObjectResponse'.).

export interface ResolveObjectResponse {

export interface ResolveObjectResponse {
    comment?: CommentView;
    post?: PostView;
    community?: CommunityView;
    person?: PersonView;
}

What is the best-practices TypeScript / API way of dealing with this? Add a error? field to that object?

[INQUIRY] Should we let the BigInts stay, instead of transforming them to number

Right now the RS to TS types script, Converts all BigInts (which were ints in the Rust Codebase) to numbers. This is a loss of precision but more importantly this is a loss of type information (of the original type). Let's say clients use these TS types to convert them to their more strongtyped language. They won't be able to discern original floats and Ints. And will have to assume that all numbers are Ints. (This is something that Jerboa does). Which they can do right now as there are no floats yet in the Lemmy codebase (as far as I know). But if Lemmy ever would introduce them this would be a big problem.

(This came up during my Lemmy_openapi_spec which generated now with all the id as number instead of ints, which is problematic for the consumers of this spec)

So I propose we keep the bigInts. Thoughts?

How to get banned users from a community?

I was able to find banFromCommunity, but I couldn't find how to get the list of banned users in a community.

Looking at GetCommunityResponse, there's moderators: CommunityModeratorView[], but there's no banned field. I guess that field should be paginated, so it makes sense if it's not there.

When looking at an individual PostView, there's creator_banned_from_community: boolean, same for CommentView and creator_banned_from_community: boolean.

As for getBannedPersons, I guess this is site-wide and not related to any particular community.

Error when calling LemmyHttp.getPosts() with no parameters

Error happens because encodeGetParams() calls Object.entries() on undefined.

Solution is to just give the parameter a default value of {}

/node_modules/.pnpm/[email protected]/node_modules/lemmy-js-client/dist/http.js:815
    return Object.entries(p)
                  ^

TypeError: Cannot convert undefined or null to object
    at Function.entries (<anonymous>)
    at encodeGetParams (/node_modules/.pnpm/[email protected]/node_modules/lemmy-js-client/dist/http.js:815:19)
    at LemmyHttp.<anonymous> (/node_modules/.pnpm/[email protected]/node_modules/lemmy-js-client/dist/http.js:788:136)
    at Generator.next (<anonymous>)
    at /node_modules/.pnpm/[email protected]/node_modules/lemmy-js-client/dist/http.js:8:71
    at new Promise (<anonymous>)
    at __awaiter (/node_modules/.pnpm/[email protected]/node_modules/lemmy-js-client/dist/http.js:4:12)
    at LemmyHttp._LemmyHttp_wrapper (/node_modules/.pnpm/[email protected]/node_modules/lemmy-js-client/dist/http.js:785:12)
    at LemmyHttp.getPosts (/node_modules/.pnpm/[email protected]/node_modules/lemmy-js-client/dist/http.js:275:92)
    at file:///index.mjs:5:26

Breaking API changes for Lemmy `0.17.0`

For API client creators, and Lemmy app devs.

In ~ 2 weeks time, ~Jan 27th, we plan to release Lemmy 0.17.0. This release has a large number of breaking API changes, that will break clients and apps. The additions / removals new finalized API changes for this upcoming release are here:

0.16.4...0.17.0-rc.61

You can use https://enterprise.lemmy.ml to test your clients / apps, we'll have that updated shortly in order to do a lot of testing before this release.

Feel free to ask any questions in the #LemmyDev chat, or here.

cc @Nutomic @shilangyu @makotech222 @arsen6331

`/* integer */` comments seemingly aren't applied accurately

So, #188 was just merged to hopefully make determining which numbers were meant to be integers easier. But now I'm even more confused.

At first glance, my assumption was anything with a /* integer */ comment was meant to be a integer and everything else was floating-point. But types like CommentId and CommunityId do not have this comment. And I highly doubt that CommunityId is supposed to be floating-point.

So my options are:

  1. Assume everything is an integer. This would work for the most part (and is what I'm doing now), but would break for types that are actually floating-point.
  2. Assume everything with the /* integer */ comment is an integer and everything else is floating-point. This would also work for the most part, except it will treat exceptions like CommunityId as floating-point and IMO that's a bad idea.
  3. Assume everything is floating-point. This would work (I mean, it's what JS does), but it would throw away some of the advantages of static typing and just be a bad idea in general IMO.

All of these options kind of suck.

Is there anyway to get ts-rs to encode the real number type as a comment or get the /* integer */ comment to be applied more accurately?

Can't signup

2023-06-13 11-36-19
Websocket breaks when signing up for lemmy.world. Not 100% sure this is the correct repo to post this to so sorry if not. Tried on firefox and chrome.

API methods should throw Error objects instead of bare strings

Throwing bare strings is problematic since JS only attaches stack traces to real error objects. This makes it hard to debug what is going wrong since the string will bubble up without any information where it came from:

lemmy-js-client/src/http.ts

Lines 1364 to 1375 in f439a7c

try {
json = await response.json();
} catch (error) {
throw response.statusText;
}
if (!response.ok) {
throw json["error"] ?? response.statusText;
} else {
return json;
}
}

There's resources online on why throwing non-errors is a bad idea, for example:

https://typescript-eslint.io/rules/no-throw-literal/

https://stackoverflow.com/questions/11502052/throwing-strings-instead-of-errors

my suggestion would be to create an error subclass and throw that

class LemmyApiError extends Error {
   response: // some union type of possibilities
   constructor(response) {
        super(`lemmy api: ${response}`);
        this.response = response;
   }
}

This would be a breaking change since return values for errors would need to be compared by catch (e) { e.response === "couldnt_find_object" } and not e === "couldnt_find_object"

browser js lib?

Hi,
is it possible to use lemmy-js-client client side with a simple <script type="text/javascript> element? And is a detailed api documentation or swagger available?

Think about a custom html / js client with lemmy backend for some experiments.

Regards

Calls to LemmyHttp.getPosts({ community_name }) returns "All" results, not community-specific results

I'm not sure if this is purely an implementation issue on my side, or a bug.

I am doing a getPosts call with the following parameters:

client.getPosts({
      auth: jwt,
      sort: 'New',
      limit: 50,
      community_name: '[email protected]' // note: the instance the user is authenticated from is different from `lemmy.world`
});

For some community_names, I get the correct/expected payload (only posts from that community).

For others (such as the above example), I get no posts from that community. Instead, the client returns the user's "home feed" with a type of All.

question: How to structure the query payload to ensure only the posts for a given community are returned?

call to subscribed posts with getPosts always returns an empty array after 0.18 update

Here's the request I am making.

return client
        .getPosts({
          limit,
          sort,
          type_,
          page,
          community_name,
        })
        .then(
          r => {
            console.log(r, [postsBaseKey, baseUrl, sort, type_, limit, community_name, page]);
            return r;
          },
          e => {
            console.error(e);
            return e;
          }
        );

This is what that console.log logs:

{"posts": []} ["posts", "beehaw.org", "New", "Subscribed", 10, undefined, 0]

This used to work just fine before 0.18, but for some reason I am unable to get subscribed posts anymore. I've tried in multiple instances such as beehay, lemm.ee and voyager.

Remove monads, go back to typescript undefined

The serialization / deserialization with monads has caused more trouble than its worth, and has lead to a lot of undiagnosable errors in lemmy-ui.

It was a good intention to try to use the better-made rust-style options and results, but in the end, typescript just can't handle them as well as its own undefined.

How do I keep websocket connection alive?

This post is a question about how Lemmy's websocket connections work instead of a bug with the client.

I'm currently trying to make a bot for the instance I spend most of my time on. You can see the source code here. There isn't a whole lot to it. It opens up a websocket connection, listens for posts or comments that either mention the bot or contain a specific phrase, and responds when triggered. I've got the bot to have the desired behavior, but there's a hitch: the websocket connection only stays open for about a minute or two before closing. I tried putting in logic to force the bot to reopen the connection if it was closed, but this just lead to the connection rapidly switching between open and closed until the connection failed entirely.

How do I keep the websocket connection alive indefintely?

Request: Edit blocked instances

The one admin task I can't do via this library is edit the defederation (blocked instance) list. Would this be a possible addition?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.