{"id":18768549,"url":"https://github.com/dacili/rxjs","last_synced_at":"2026-05-01T00:31:49.764Z","repository":{"id":255482401,"uuid":"851195311","full_name":"Dacili/RxJS","owner":"Dacili","description":"RxJS things","archived":false,"fork":false,"pushed_at":"2024-09-19T09:25:18.000Z","size":207,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-20T23:12:37.278Z","etag":null,"topics":["angular","async","javascript","reactive-programming","rxjs","rxjs-library","rxjs-observables","rxjs-operators","rxjs-subjects","rxjs-subscriptions","subscribers"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Dacili.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-09-02T15:51:32.000Z","updated_at":"2024-09-19T09:25:22.000Z","dependencies_parsed_at":"2025-05-20T23:12:40.044Z","dependency_job_id":"495c8bff-048d-4729-a19c-6e1d4594e754","html_url":"https://github.com/Dacili/RxJS","commit_stats":null,"previous_names":["dacili/rxjs"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Dacili/RxJS","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dacili%2FRxJS","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dacili%2FRxJS/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dacili%2FRxJS/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dacili%2FRxJS/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Dacili","download_url":"https://codeload.github.com/Dacili/RxJS/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dacili%2FRxJS/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32481553,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"ssl_error","status_checked_at":"2026-04-30T13:12:06.837Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","async","javascript","reactive-programming","rxjs","rxjs-library","rxjs-observables","rxjs-operators","rxjs-subjects","rxjs-subscriptions","subscribers"],"created_at":"2024-11-07T19:13:07.335Z","updated_at":"2026-05-01T00:31:49.743Z","avatar_url":"https://github.com/Dacili.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# RxJS = Reactive Extensions for JavaScript\n### What is a programming paradigm?\nA programming paradigm is a relatively high-level way to conceptualize and structure the implementation of a computer program.   \nhttps://en.wikipedia.org/wiki/Programming_paradigm  \nTypes of programming paradigm:  \n![image](https://github.com/user-attachments/assets/2230b708-cc7e-412b-ac5c-48b452619e16)\n### Imperative vs declarative programming\n\u003e Imperative programming tells us **how to do it**, while Declarative programming tells us **what we want to happen**.\n \nImperative Programming provides flexibility but brings in complexity, Declarative programming hides complexity and provides simplicity.  \nIn imperative you're dictating instructions, and in declarative the system knows enough to figure out instructions on its own. In an imperative approach, you're working with a blank slate.  \n![images](https://github.com/user-attachments/assets/f4cc207a-1727-40a0-ba16-d5cc29991038)  \n![image](https://github.com/user-attachments/assets/7b339e65-15bd-403a-b0b8-8e3bc58cdbcd)  \n\n**Examples:**  \n- Imperative languages: C, C++, Java and Fortran.\n- Declarative languages: HTML, SQL, CSS and XML, and mix of functional and logic programming languages, such as Prolog, Haskell, and Lisp.\n### What is declarative programming?\nDeclarative programming is a programming paradigm, a style of building the structure and elements of computer programs that expresses the *logic of a computation without describing its control flow*.  \nDeclarative programming is an abstraction of functions that underlying it is an imperative implementation.\n\n### What is reactive programming?\n\u003e Reactive programming is programming with **asynchronous data streams.**\n\nReactive programming is a programming paradigm, or model, that centers around the concept of **reacting to changes in data and events**.  \nIn computing, reactive programming is a declarative programming paradigm concerned with **data streams and the propagation of change**.   \nIt relies on asynchronous programming logic.  \n\n-----\n\n### What is RxJS?\nRxJS is a powerful library for web development. It's focused on managing asynchronous data streams and enabling reactive programming paradigms.\n### Why to use it?  \nIf anything in your app happens asynchronously, an RxJS Observable will **make your life easier.**   \n\n---\n### Concepts of RxJS:\n- #### Observable\n \u003e **emits a values or events**\n  \n represents the idea of an invokable collection of future values or events.\n```\nimport { Observable } from 'rxjs';\n \nconst observable = new Observable((subscriber) =\u003e {\n  subscriber.next(1);\n  setTimeout(() =\u003e {\n    subscriber.next(4);\n    subscriber.complete();\n  }, 1000);\n});\n```\n```\nobservable.subscribe({\n  next(x) {\n    console.log('got value ' + x);\n  },\n  error(err) {\n    console.error('something wrong occurred: ' + err);\n  },\n  complete() {\n    console.log('done');\n  },\n});\n```\n**Observables vs functions:**  \nFunctions **can only return one value**. Observables can return multiple:  \n![image](https://github.com/user-attachments/assets/e0f52222-a891-431a-8430-3a9b5e520924)  \n![image](https://github.com/user-attachments/assets/d32fae4d-4313-4fc6-8dfe-1e8806dc2f57)  \n  \n**Observables vs promises:**  \nhttps://stackoverflow.com/questions/37364973/what-is-the-difference-between-promises-and-observables  \n\nA Promise handles a **single** event when an async operation completes or fails.  \nAn Observable is like a Stream (in many languages) and allows you to pass **zero or more** events where the callback is called for each event.  \nObservable is easily **cancellable**.  \nWhile a **Promise starts immediately**, an **Observable** only starts **if you subscribe** to it. This is why Observables are called lazy.  \n![image](https://github.com/user-attachments/assets/cd502520-de6e-45d2-9cc2-3f2b9959acbd)\n\n\n- #### Observer\n \u003e **subscribes to observable**\n\n is a consumer of values delivered by an Observable.  \n ![image](https://github.com/user-attachments/assets/0592e133-a9c0-4691-8961-ddc3a008098d)\n\n\n- #### Subscription\n   \u003e **saved instance of observer which you can use to unsubscribe**\n   \n represents the execution of an Observable, is primarily useful for cancelling (unsubscribing) the execution.  \n```\nconst subscription = observable.subscribe(x =\u003e console.log(x));\nsubscription.unsubscribe();\n```\n\n\n- #### Subject\n  \u003e **Observable that can have multiple subscribers**\n   \n is equivalent to an EventEmitter, and the only way of multicasting a value or event to multiple Observers.  \n Every Subject is an Observable.  \n \u003e If you try to subscribe \u003e 1 times to the same Observable, **only the last one will get values!** That's the reason why we need Subjects. \n https://stackoverflow.com/questions/36814995/multiple-subscriptions-to-observable\n\n\n ```\nimport { Subject } from 'rxjs';\nconst subject = new Subject\u003cnumber\u003e();\n \nsubject.subscribe({\n  next: (v) =\u003e console.log(`observerA: ${v}`),\n});\nsubject.subscribe({\n  next: (v) =\u003e console.log(`observerB: ${v}`),\n});\n \nsubject.next(1);\n// observerA: 1\n// observerB: 1\n```\n**Types of subjects:**\n![image](https://github.com/user-attachments/assets/aa2bbad6-2b38-4bf6-87b0-64cbdee1ae61)  \n\n1. **BehaviorSubject** - new subscribers receive last emitted value  \n ```const subject = new BehaviorSubject(0); // 0 is the initial value```  \n3. **ReplaySubject** - new subscribers receive last N emitted values  \n    ```const subject = new ReplaySubject(3); // buffer 3 values for new subscribers```  \n5. **AsyncSubject** - all (old + new) subscribers receive last emitted value **when** AsyncSubject ***completes***  \n    ```const subject = new AsyncSubject(); ```\n\n- #### Schedulers\n are centralized dispatchers to control concurrency, allowing us to coordinate when computation happens on e.g. setTimeout or requestAnimationFrame or others.\n\n\n- #### Operators\n are pure functions that enable a functional programming style of dealing with collections with operations like map, filter, concat, reduce, etc.  \n\n### pipe()\n.pipe() method is chained on an Observable to apply pipeable operators and return a new observable\n```\nof(1, 2, 3).pipe(map(num =\u003e num * 10)).subscribe(value =\u003e {\n   console.log(value);\n});\n```\n\nTwo kinds of operators:\n1. **Pipeable** Operators - is a function that takes an Observable as its input and returns another Observable. It is a **pure operation**: the **previous Observable stays unmodified**.\n ```\nmediObservable.pipe(someOperator)\n```\nEx. when operator is *filter*:  \n```\nmediObservable.pipe(filter(ev =\u003e (ev.id == id));\n```\n2. **Creation** Operators - can be called as standalone functions to create a new Observable.\n   ```\n    of(1, 2, 3) // creates an observable that will emit 1, 2, and 3\n   ```\n   \n**Marble diagrams**  \n  \nMarble Diagrams are visual representations of ***how operators work***, and include the:  \na) **input** Observable(s),   \nb) the **operator** and its parameters, and   \nc) the **output** Observable \n\u003e In a marble diagram, time flows to the right, and the diagram describes how **values (\"marbles\")** are emitted on the Observable execution.\n\n![image](https://github.com/user-attachments/assets/da92ccb3-a548-42f6-90e2-4233c1ed3d3b)  \n\n\n### **Categories of operators**:\n#### ***Creation***\n- **EMPTY** - A simple Observable that emits no items to the Observer and immediately emits a complete notification. \n```\nEMPTY.subscribe({\nnext: () =\u003e console.log('Next'), // this will NOT be shown\ncomplete: () =\u003e console.log('Complete!') // this will be shown\n});\n```\n\n\n- **of** - Converts the arguments to an observable sequence.  \n```\n of(10, 20, 30).subscribe(\n{next: value =\u003e console.log(value)}\n)\n```  \n- **defer** - Observable emits only when some Observer subscribes\n```\nconst mediDeferObs = defer(() =\u003e {\n  return new Date(); //will capture date time at the moment of subscription\n});\nmediDeferObs.subscribe(x =\u003e console.log(x)); // it will show date time when this subscription happened  \n```\n- **interval** - Observable keeps emitting a value, after every 'interval of time' has passed (it's like setInterval in JS = setInterval(code, delay))\nThe emitted value is *auto incrementing*.  \n```\ninterval(1000).subscribe(x =\u003e {\n    console.log(x); // we will see a number written to the console every second, starting at 0 and incrementing from there\n});\n```\n- **timer** - delays emitting for a certain interval of time  \n ``` timer(dueTime, interval)```  \n  dueTime = time in milliseconds to wait before emit  \n  interval = if not provided, it will emit a 0 value and complete immediately, if provided, then it's the same as interval, it will emit a incremented value every interval time (auto incrementing)\n```\n timer(1000, 2000).subscribe(val =\u003e console.log(val)); // it will print 0, then after every 2 seconds,\n//it will increment the previous value (0, 1, 2...)\n\n timer(1000).subscribe(val =\u003e console.log(val)); // it will print 0, and complete\n\n// these two are same, they never complete\ntimer(0, 1000).subscribe(n =\u003e console.log('timer', n)); // 0, 1, 2...\ninterval(1000).subscribe(n =\u003e console.log('interval', n)); // 0, 1, 2...\n```  \n- **from** - Creates an Observable from an **Array, an array-like object, a Promise, an iterable object, or an Observable-like object.**  \n\u003e *of vs from*: of always accepts **only values** and performs no conversion. You can't forward Promise or Observable objects to *of*.  \n ```\nconst result = from([10, 20, 30]);\nresult.subscribe(x =\u003e console.log(x));\n\n// These 2 are the same (second is getting array as argument, first is not)\nObservable.of(1,2,3).subscribe(() =\u003e {})\nObservable.from([1,2,3]).subscribe(() =\u003e {})\n\n// These 2 are not the same, passing array as argument to both\nObservable.of([1,2,3]).subscribe(() =\u003e {}) // emits whole array at once ([1,2,3])\nObservable.from([1,2,3]).subscribe(() =\u003e {}) // emits 1 by 1 value (1 2 3)\n```\n- **fromEvent** - creates observable from event  \n ```\nconst clicks = fromEvent(document, 'click');\nclicks.subscribe(x =\u003e console.log(x));\n```  \n- **throwError** - Just errors and does nothing else.   \n\u003e A stream can error out only once. The **stream will not emit** any further values **after an error is thrown**.  \n ```\n return throwError(() =\u003e new Error(`Invalid time`));\n// or\n throw new Error(`Invalid time}`);\n\n// it will be executed in the error part if implemented\n.subscribe({\n  next: console.log,\n  error: console.error // if you have error implemented, you can do the logic you want, and that will be executed\n// if you don't have error implemented, it will just be automatically thrown in console.log\n});\n\n```\nCreating my own observable (will emit 1, 2, and error):  \n```\nconst observable = new Observable((subscriber) =\u003e {\n      subscriber.next(1);\n      subscriber.next(2);\n  throw new Error(`Invalid time}`);\n});\n// 1st implementation\n    observable.subscribe(x =\u003e {\n      console.log(x) // here we don't implement error, and by default it will be logged in console log, even if we don't have this line console.log\n    })\n// 2nd implementation\n    observable.subscribe({\n      next: console.log,\n      error: console.error // here we implemented error, it will console error \n    })\n// 3rd implementation\n  observable.subscribe({\n    next(x) {\n      console.log('got value ' + x);\n    },\n    error(err) {\n      console.error('something wrong occurred: ' + err); //  here we implemented error, we could add logic, whatever we want, this will shown error in the way we implemented it\n    },\n    complete() {\n      console.log('done');\n    },\n  });\n```\n\n#### ***Join Creation***  \n- **forkJoin** - wait for multiple observables completion, and use last emitted values as result  \n\nIf we send **object**, the result is object. We can name however we want (the properties of the object)\n\n```\nconst observable = forkJoin({\n  medi1: of(1, 2, 3, 4),\n  medi2: Promise.resolve(8),\n  daci: timer(4000)\n});\nobservable.subscribe({\n next: value =\u003e console.log(value),\n complete: () =\u003e console.log('This is how it ends!'),\n});\n \n// { medi1: 4, medi2: 8, daci: 0 } after 4 seconds, object\n// 'This is how it ends!' immediately after\n```\nIf we send **array**, result is array:  \n```\nconst observable = forkJoin([\n  of(1, 2, 3, 4),\n  Promise.resolve(8),\n  timer(4000)\n]);\n// [4, 8, 0] array\n```\n- **concat** - emits all values from first observable until it completes, then from the second same  \n\n```\nconcat(of(0,1), of(3,4)).subscribe(x =\u003e console.log(x))\n// 0,1,3,4\n```\n- **merge** - running multiple observables at the same time, creates new observable that merge them  \nIt is similar like concat, but concat waits for the first one to complete, while merge emits as obs emits, and does not wait for one to be completed, it fires emissions as they come. \n```\nmerge(of(1), of(3, 4)).subscribe(x =\u003e console.log(x))\n// 1, 3, 4\n```\n#### ***Transformation***  \n- **map** - it's like map in js, iterates trough values of observable, and returns new observable  \nIn JS ```map vs forEach```:  \n  ```map``` - returns new list, and does not mutate original one  \n  ```forEach``` - mutates original list\n\n```\nof(1,2,3).pipe(map(x =\u003e x*2))\n.subscribe(x =\u003e console.log(x))\n// 2, 4, 6\n```\n- **switchMap** - for every value of the first observable, it does the operation defined in the output observable (switchMap), and emits the modified values\n\n```\nof(1,2,3).pipe(switchMap(x =\u003e of(x**2, x**3)))\n.subscribe(x =\u003e console.log(x))\n// 1, 1, 4, 8, 9, 27\n```\n- **expand** - used for recursion until defined condition is met \n\n```\n.pipe(\n     expand((data) =\u003e\n       data.length \u003c limit // condition\n         ? EMPTY           // end the recursion\n         : this.getDashboardDataForApplicants((offset += limit)) // continue to call recursive function\n     )\n```\n\n#### ***Filtering***  \n- **debounceTime** - It's like delay, but passes only the most recent notification from each burst of emissions.  \nIn delay, it only delays the emitting of the value. All values are emitted.    \nIn debounce time, it does not emit value, until time is elapsed, and there is no new value emitted during that time.  \nIf a new value is emitted during that time, then time starts ticking again before emitting the most recent one.  \n\n```\nthis.searchControl.valueChanges\n.pipe(debounceTime(2000)) // don't emit value, until 2 sec passed. Then emit latest value\n.subscribe(x =\u003e console.log(x))\n```\n- **distinct** - Returns an Observable that emits all items emitted by the source Observable that are distinct by comparison from previous items.\n\n```\nof(1, 1, 2, 2, 2, 1, 3, 4, 3)\n  .pipe(distinct())\n  .subscribe(x =\u003e console.log(x));\n// 1, 2, 3\n```\n- **filter** - Filter items emitted by the source Observable by only emitting those that satisfy a specified predicate.\n\n```\n let id = 3;\n of(1, 2, 3, 4).pipe(filter(x =\u003e (x == id)))\n.subscribe(x =\u003e console.log(x));\n// 3\n```\n- **take** - Takes the first count values from the source, then completes.\n\n```\nof(1,2,3).pipe(take(1)).subscribe(x =\u003e console.log(x));\n// 1\n```\n- **skip** - Returns an Observable that skips the first count items emitted by the source Observable.\n\n```\nof(1,2,3).pipe(skip(2)).subscribe(x =\u003e console.log(x));\n// 3\n```\n\n#### ***Join***  \n\n#### ***Multicasting***  \n\n#### ***Error Handling***  \n- **catchError** - Catches errors on the observable to be handled by:\n  \na) returning a new observable\n```\n// emit 1, 2, 3, on 4 error is thrown\n  catchError(err =\u003e of('new', 'obs', 'emit')) // catch, create new obs, continue to emit values\n// 1, 2, 3, new, obs, emit\n```\n   b) throwing an error \n```\n catchError(err =\u003e {\n      throw 'error Medi: ' + err; // catch, edit error, rethrow\n    })\n// 1, 2, 3, error Medi: four! \n```\n- **retry** - *if an error happens*, it will resubscribe to the observable for the N times, and return combined values.\n\u003e If there is no error occurred, retry will not be executed\n\nAll items emitted by the source Observable will be emitted by the resulting Observable, even those emitted during failed subscriptions.  \n For example, if an Observable fails at first but emits [1, 2] then succeeds the second time and emits: [1, 2, 3, 4, 5, complete] then the complete stream of emissions and notifications would be: [1, 2, 1, 2, 3, 4, 5, complete].\n\n```\n    of(1, 2).pipe(\n      tap(n =\u003e {\n        console.log(n)\n        throw new Error('medi err'); // if we did not have this line, retry would not be executed\n      }),\n      retry(3)\n    ).subscribe();\n// 1, 1, 1, 1\n```\n#### ***Utility***  \n- **tap** - Used to perform side-effects actions for values recieved from observable  \nThe most common use of tap is actually **for debugging**. You can place a *tap(console.log)* anywhere in your observable pipe, log out the notifications as they are emitted by the source returned by the previous operation.\n```\n of(1, 2).pipe(\n   tap(n =\u003e {\n     console.log(n)\n   })\n ).subscribe();\n// or\nof(1, 2).pipe(tap(console.log)).subscribe();\n```\n- **delay** - Delays the emission of values from the Observable by a given timeout (or until a given Date)  \n\n```\n.pipe(delay(1000))\n```\n#### ***Conditional and Boolean***  \n#### ***Mathematical and Aggregate***  \n- **reduce** - Applies an accumulator function over the source Observable, and returns the accumulated result when the source completes, given an optional seed (initial) value.  \nUse it to combine values, for example, to sum numbers, or to get multiple arrays, and accumulate them into one.  \n![image](https://github.com/user-attachments/assets/dd322eb1-f2c9-4aff-a441-93372ba6ff35)  \n```\nreduce((acc, val: any) =\u003e {\n       acc = [...acc, ...val.body]; // acc contains 1st initial value, and after that accumulated returned value\n       return acc;                  // modified acc will be forwarded to the next iteration until the observable completes\n     }, [])                         // empty arr is seed (initial) value\n```\n- **max, min, count** - when observable completes, it returns max value, min value, or count of emitted values\n------\n# If you are unsure which operator do you need, you can use Operator Decision Tree\nhttps://rxjs.dev/operator-decision-tree  \nIt's very cool, it asks you questions, what do you want to achieve, and returns the needed operator.  \n\n------\n# Coding examples\n## 1. Keep triggering HTTP calls in Angular until a condition is met\nUsually when you have paging or something, APIs are created to get specific amount of data per request, for example we have a limit of getting 100 records/objects per request.  \nCall this API recursively with RxJS functions.  \n\nEffect: \n```\n  getDashboardWithApplicants$ = createEffect(() =\u003e {\n    return this.actions$.pipe(\n      ofType(actions.getDashboardWithApplicants),\n      concatLatestFrom(() =\u003e [this.store.select(selectState)]),\n      switchMap(([action, state]) =\u003e {\n        return this.getAllDashboardDataForApplicants().pipe(\n          map((dashboardData: any) =\u003e {\n            this.addInitialsAndAvatarColors(dashboardData);\n            this.getColorForUserAvatar(dashboardData);\n            return actions.getDashboardWithApplicantsSuccess({ data: dashboardData });\n          })\n        );\n      })\n    );\n  });\n```  \nImplementation of recursive calls of API:  \n***offset*** - in APIs, **ignore first N objects**, ```someApi?offset=10```, will skip first 10 records, and return the rest\n```\n getDashboardDataForApplicants(offset = 0): Observable\u003cany\u003e {\n   return this.bgcService.getBackgroundCheckDashboard(SubjectTypeEnum.Applicant, offset);\n }\n\n getAllDashboardDataForApplicants() {\n   let offset = 0;\n   return this.getDashboardDataForApplicants(offset).pipe(\n     // expand is used to call recursively until condition is met\n     expand((data) =\u003e\n       data.body.length \u003c limitForDashboardData\n         ? EMPTY\n         : this.getDashboardDataForApplicants((offset += limitForDashboardData))\n     ),\n     // use the reduce operator to emit the accumulated array with all items\n     reduce((acc, val: any) =\u003e {\n       acc = [...acc, ...val.body];\n       return acc;\n     }, [])\n   );\n }\n```\nRxJS:  \n- **expand** - for recursion  \n  Recursively projects each source value to an Observable which is merged in the output Observable.\n- **reduce** - to combine multiple responses into one.  \n  Applies an accumulator function over the source Observable, and returns the accumulated result when the source completes, given an optional seed (initial) value.\n- **EMPTY** - A simple Observable that emits no items to the Observer and immediately emits a complete notification.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdacili%2Frxjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdacili%2Frxjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdacili%2Frxjs/lists"}