Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ember-resources

Package Overview
Dependencies
Maintainers
1
Versions
94
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ember-resources - npm Package Versions

13
10

6.3.1

Diff

Changelog

Source

6.3.1

Patch Changes

nullvoxpopuli
published 6.3.0 •

Changelog

Source

6.3.0

Minor Changes

  • #952 1551b33 Thanks @NullVoxPopuli! - Introduce resources as modifiers. This brings alignment with Starbeam's plans for modifiers as a universal primitive.

    In ember-resources, using modifiers as resources looks like this:

    import { resource } from 'ember-resources';
    import { modifier } from 'ember-resources/modifier';
    
    const wiggle = modifier((element, arg1, arg2, namedArgs) => {
        return resource(({ on }) => {
            let animation = element.animate([
                { transform: `translateX(${arg1}px)` },
                { transform: `translateX(-${arg2}px)` },
            ], {
                duration: 100,
                iterations: Infinity,
            });
    
            on.cleanup(() => animation.cancel());
        });
    });
    
    <template>
        <div {{wiggle 2 5 named="hello"}}>hello</div>
    </template>
    

    The signature for the modifier here is different from ember-modifier, where positional args and named args are grouped together into an array and object respectively.

    This signature for ember-resource's modifier follows the plain function invocation signature.

    <details><summary>in Starbeam</summary>
    import { resource } from '@starbeam/universal';
    
    function wiggle(element, arg1, arg2, namedArgs) {
        return resource(({ on }) => {
            let animation = element.animate([
                { transform: `translateX(${arg1}px)` },
                { transform: `translateX(-${arg2}px)` },
            ], {
                duration: 100,
                iterations: Infinity,
            });
    
            on.cleanup(() => animation.cancel());
        });
    }
    
    <template>
        <div {{wiggle 2 5 named="hello"}}>hello</div>
    </template>
    
    </details>
nullvoxpopuli
published 6.2.2 •

Changelog

Source

6.2.2

Patch Changes

nullvoxpopuli
published 6.2.1 •

Changelog

Source

6.2.1

Patch Changes

  • #941 bfc432b Thanks @NullVoxPopuli! - Fix an issue with a new (not yet used feature) where Resources could directly return a Cell, and it would have its .current method automatically called when resolving the value of a Resource.

    import { resource, cell } from 'ember-resources';
    
    export const Now = resource(({ on }) => {
      const now = cell(Date.now());
      const timer = setInterval(() => now.set(Date.now()));
    
      on.cleanup(() => clearInterval(timer));
    
      return now;
    });
    
    <template>
      It is: <time>{{Now}}</time>
    </template>
    
nullvoxpopuli
published 6.2.0 •

Changelog

Source

6.2.0

Minor Changes

  • #936 6246a3c Thanks @NullVoxPopuli! - The use import from ember-resources now supports an alternate style of usage. This is partly to provide consistency across the different kinds of resources (and resource builders), whether or not arguments are provided.

    The motivation from this change comes from trying to better align with Starbeam's composition capabilities, and "define something once, use it anywhere" approach to that composition.

    For example, before, only this was possible:

    import { resource, use } from "ember-resources";
    
    const StuckClock = resource(() => 2);
    
    class MyClass {
      @use data = StuckClock;
    }
    
    new MyClass().data === 2;
    

    That looks a little awkward, because it looks like data is set to a constant. In TypeScript, this still worked out, and the type of data would be a number, but it still didn't look intuitive.

    Now, we can do this:

    import { resource, use } from "ember-resources";
    
    const StuckClock = resource(() => 2);
    
    class MyClass {
      data = use(this, StuckClock);
    }
    
    new MyClass().data.current === 2;
    

    The key difference here is that data is now a Reactive<number>, which, like a cell, has a .current property. This is a readonly value -- however current can still return a mutable data structure.

    This style of use ends up extending nicely to Resources that take arguments:

    import { tracked } from "@glimmer/tracking";
    import { resource, use, resourceFactory } from "ember-resources";
    
    const Clock = resourceFactory((locale) => resource(/* ... */));
    
    class MyClass {
      @tracked locale = "en-US";
    
      data = use(
        this,
        Clock(() => this.locale),
      );
    }
    

    Note <br> The old way of using @use as a decorator is still supported, and has no plans of being deprecated.

    <details><summary>Another approach</summary>

    I can't recommend this approach for general usage, but it is supported under SemVer (for exploration and feedback).

    import { resource, use } from "ember-resources";
    
    const StuckClock = resource(() => 2);
    
    class MyClass {
      @use(StuckClock) declare data: number;
    }
    
    new MyClass().data === 2;
    

    This should feel familiar as it looks like what we're familiar with when it comes to declaring @tracked properties as well as @services.

    However, this has the same problems as @service -- in TypeScript, it requires you to use declare and specify a type, which may or may not match the actual type of StuckClock.

    Additionally, whenever we want to pass arguments to the resource, like this:

    import { tracked } from '@glimmer/tracking';
    import { resource, use } from 'ember-resources';
    
    const Clock = resourceFactory((locale) => resource( /* ... */);
    
    class MyClass {
      @tracked locale = 'en-US';
    
      @use(Clock(() => this.locale) declare data: number;
    }
    

    The arrow function passed to Clock would not have the correct this. This is confusing, because in every other situation where we use classes, the arrow function has the same context as the instance of the class. But due to how decorators are configured / transpiled, the this is actually the surrounding context around MyClass, because decorators are statically applied.

    class MyClass {
      @tracked locale = 'en-US';
    
      @use(Clock( static context here, not instance ) declare data: number;
    }
    

    So... that's why I want to recommend property = use(this, Foo) by default.

    class MyClass {
      @tracked locale = 'en-US';
    
      data = use(this, (Clock( instance access ));
    }
    
    </details>
nullvoxpopuli
published 6.1.1 •

Changelog

Source

6.1.1

Patch Changes

  • #925 e320cf8 Thanks @NullVoxPopuli! - Fix situation where, when composing with blueprint/factory-creted Resources, the owner was not passed to the tusedd resource.

    <details><summay>Example from the added test</summary>
    const Now = resourceFactory((ms = 1000) =>
      resource(({ on }) => {
        let now = cell(nowDate);
        let timer = setInterval(() => now.set(Date.now()), ms);
    
        on.cleanup(() => clearInterval(timer));
    
        return () => now.current;
      })
    );
    
    const Stopwatch = resourceFactory((ms = 500) =>
      resource(({ use }) => {
        let time = use(Now(ms));
    
        return () => format(time);
      })
    );
    
    await render(<template><time>{{Stopwatch 250}}</time></template>);
    

    The owner is part of the hooks API for resource and an error is thrown when it is undefined - regardless if used.

    const Demo = resource(({ on, use, owner }) => {
      // ...
    });
    
    </details>
nullvoxpopuli
published 6.1.0 •

Changelog

Source

6.1.0

Minor Changes

  • #866 e1e4f66 Thanks @NullVoxPopuli! - Add the ability to compose function resources. This is enabled only for function resources as class-based resources could already compose.

    <details><summary>how function resources compose</summary>
    let formatter = new Intl.DateTimeFormat("en-US", {
      hour: "numeric",
      minute: "numeric",
      second: "numeric",
      hour12: false,
    });
    
    let format = (time) => formatter.format(time.current);
    
    // representing the current time.
    // This could be rendered directly as {{Now}}
    // but Date does not serialize nicely for humans (Date.now() is a number)
    const Now = resource(({ on }) => {
      let now = cell(Date.now());
      let timer = setInterval(() => now.set(Date.now()), 1000);
    
      on.cleanup(() => clearInterval(timer));
    
      return () => now.current;
    });
    
    const Clock = resource(({ use }) => {
      let time = use(Now);
    
      return () => format(time);
    });
    
    // Rendered, Clock is always the formatted time
    <template>
      <time>{{ Clock }}</time>
    </template>;
    
    </details>

Patch Changes

  • #829 ff776b1 Thanks @NullVoxPopuli! - Move ember-async-data to "dependencies" because users are not required to import from that package ever"
nullvoxpopuli
published 6.0.0 •

Changelog

Source

6.0.0

Major Changes

  • #715 e8155b2 Thanks @NullVoxPopuli! - Drop support for TypeScript < 4.8 in order to support Glint.

  • #778 901ae9a Thanks @NullVoxPopuli! - The map utility resource has changed its first type-argument for better inference.

    The utility already supported inference, so this change should not impact too many folks.

    <details><summary>Migration and Reasoning</summary>

    When explicit type-arguments were specified,

    class Demo {
      // previously
      a = map<Element>(this, {
        data: () => [
          /* ... list of Element(s) ... */
        ],
        map: (element) => {
          /* some transform */
        },
      });
    
      // now
      a = map<Element[]>(this, {
        data: () => [
          /* ... list of Element(s) ... */
        ],
        map: (element) => {
          /* some transform */
        },
      });
    }
    

    This is advantageous, because with @tsconfig/ember, the option noUncheckedIndexedAccess is enabled by default. This is a great strictness / quality option to have enabled, as arrays in javascript are mutable, and we can't guarantee that they don't change between index-accesses.

    However the map utility resource explicitly disallows the indicies to get out of sync with the source data.

    But!, with noUncheckedIndexedAccess, you can only infer so much before TS goes the safe route, and makes the returned type X | undefined.

    For example, in these type-tests:

    import { map } from "ember-resources/util/map";
    import { expectType } from "ts-expect";
    
    const constArray = [1, 2, 3];
    
    b = map(this, {
      data: () => constArray,
      map: (element) => {
        expectType<number>(element);
        return element;
      },
    });
    
    // index-access here is *safely* `| undefined`, due to `constArray` being mutable.
    expectType<number | undefined>(b[0]);
    expectType<number | undefined>(b.values()[0]);
    
    // but when we use a const as const array, we define a tuple,
    // and can correctly infer and return real values via index access
    const tupleArray = [1, 2, 3] as const;
    
    c = map(this, {
      data: () => tupleArray,
      map: (element) => {
        expectType<number>(element);
        return element;
      },
    });
    
    // No `| undefined` here
    expectType<number>(c[0]);
    expectType<number>(c.values()[0]);
    
    </details>
  • #815 54e2b50 Thanks @NullVoxPopuli! - The RemoteData resource now has the same state changes and semantics as trackedFunction.

    Breaking Changes:

    • isResolved is only true when the request succeeds. During migration, you may use isFinished for previous behavior.
  • #779 a471d9b Thanks @NullVoxPopuli! - trackedFunction has a new API and thus a major version release is required.

    Work by @lolmaus

    tl;dr: the breaking changes:

    • no more manual initial value
    • isResolved is only true on success

    other changes:

    • trackedFunction is a wrapper around ember-async-data's TrackedAsyncData
      • ember-async-data will need to be installed in the consumer's app to continue using trackedFunction This keeps installs minimal for folks using ember-resources and are not using trackedFunction
    • behavior is otherwise the same

    NOTE: trackedFunction is an example utility of how to use auto-tracking with function invocation, and abstract away the various states involved with async behavior. Now that the heavy lifting is done by ember-async-data, trackedFunction is now more of an example of how to integrated existing tracked utilities in to resources.

    <details><summary>Migration</summary>

    Previously, the state's isResolved property on trackedFunction was true on both success and error.

    now, isFinished can be used instead. isResolved is now only true when the function runs to completion without error, aligning with the semantics of promises.

    class Demo {
      foo = trackedFunction(this, async () => {
        /* ... */
      });
    
      <template>
        {{this.foo.isFinished}} =
          {{this.foo.isResolved}} or
          {{this.foo.isError}}
      </template>
    }
    

    Previously, trackedFunction could take an initial value for its second argument.

    class Demo {
      foo = trackedFunction(this, "initial value", async () => {
        /* ... */
      });
    }
    

    This has been removed, as initial value can be better maintained and made more explicit in user-space. For example:

    class Demo {
      foo = trackedFunction(this, async () => {
        /* ... */
      });
    
      get value() {
        return this.foo.value ?? "initial value";
      }
    }
    

    Or, in a template:

    {{#if this.foo.value}}
      {{this.foo.value}}
    {{else}}
      initial displayed content
    {{/if}}
    

    Or, in gjs/strict mode:

    const withDefault = (value) => value ?? 'initial value';
    
    class Demo extends Component {
      foo = trackedFunction(this, async () => { /* ... */ });
    
      <template>
        {{withDefault this.foo.value}}
      </template>
    }
    
    </details>
  • #785 66cee0e Thanks @NullVoxPopuli! - The import path ember-resources/util/function-resource has been removed, as all the relevent exports have been available from ember-resources since v5.

Minor Changes

  • #797 18adb86 Thanks @NullVoxPopuli! - Add link() and @link, importable from ember-resources/link.

    NOTE: for existing users of ember-resources, this addition has no impact on your bundle.

    <details><summary>Example property usage</summary>
    import { link } from 'ember-resources/link';
    
    class MyClass {  ... }
    
    export default class Demo extends Component {
      // This usage does now allow passing args to `MyClass`
      @link(MyClass) myInstance;
    }
    
    </details> <details><summary>Example inline usage</summary>
    import Component from "@glimmer/component";
    import { cached } from "@glimmer/tracking";
    import { link } from "ember-resources/link";
    
    export default class Demo extends Component {
      // To pass args to `MyClass`, you must use this form
      // NOTE though, that `instance` is linked to the `Demo`s lifecycle.
      //  So if @foo is changing frequently, memory pressure will increase rapidly
      //  until the `Demo` instance is destroyed.
      //
      //  Resources are a better fit for this use case, as they won't add to memory pressure.
      @cached
      get myFunction() {
        let instance = new MyClass(this.args.foo);
    
        return link(instance, this);
      }
    }
    
    </details>

    This abstracts away the following boilerplate:

    import { getOwner, setOwner } from "@ember/owner";
    import { associateDestroyableChild } from "@ember/destroyable";
    
    class MyClass {
      /* ... */
    }
    
    export default class Demo extends Component {
      @cached
      get myInstance() {
        let instance = new MyClass();
    
        associateDestroyableChild(this, instance);
    
        let owner = getOwner(this);
    
        if (owner) {
          setOwner(instance, owner);
        }
    
        return instance;
      }
    }
    
  • #778 f841a98 Thanks @NullVoxPopuli! - Use strictest possible settings with TypeScript so that consumers can't be stricter than this library

  • #776 a99793e Thanks @NullVoxPopuli! - Glint is now supported starting with 1.0.0-beta.3

  • #818 feeb2db Thanks @NullVoxPopuli! - RemoteData now checks the response's Content-Type header to decide whether to convert to JSON or Text

  • #794 8989bbb Thanks @NullVoxPopuli! - New Utils: UpdateFrequency and FrameRate

    NOTE: for existing users of ember-resources, this addition has no impact on your bundle.

    <details><summary>FrameRate</summary>

    Utility that uses requestAnimationFrame to report how many frames per second the current monitor is rendering at.

    The result is rounded to two decimal places.

    import { FramRate } from "ember-resources/util/fps";
    
    <template>{{ FrameRate }}</template>;
    
    </details> <details><summary>UpdateFrequency</summary>

    Utility that will report the frequency of updates to tracked data.

    import { UpdateFrequency } from 'ember-resources/util/fps';
    
    export default class Demo extends Component {
      @tracked someProp;
    
      @use updateFrequency = UpdateFrequency(() => this.someProp);
    
      <template>
        {{this.updateFrequency}}
      </template>
    }
    

    NOTE: the function passed to UpdateFrequency may not set tracked data.

    </details>

Patch Changes

  • #769 abaad4a Thanks @GreatWizard! - fix typo in map error message when checking if every datum is an object

  • #828 24b540e Thanks @NullVoxPopuli! - ember-async-data@v1 is out, so since we're just now using it, that can be the minimum version. NOTE: ember-async-data's minimum ember-source is 4.8, so while things might work with earlier ember-source's it's not guaranteed.

  • #826 50ad1ba Thanks @NullVoxPopuli! - When using RemoteData, isError should be true when the http status code is >= 400. Resolves #825". Previously, when you had a JSON response with 404 status code, isError would be false instead of true.

  • #865 6df54b1 Thanks @NullVoxPopuli! - Add the last v4 LTS, ember-source v4.12, to the test matrix

  • #806 00e8f2f Thanks @sergey-zhidkov! - trackedTask must return correct last value.

    Fixes the issue described at #793 If the task was called multiple times and the last returned value was null or undefined, then trackedTask will return the previous value instead of the current one.

  • #838 acbf03d Thanks @NullVoxPopuli! - Fixes #835 - resolves regression introduced by PR: #808 which aimed to correctly return the previous task instance's value if the current task hasn't finished yet. The regression described by #835 was that if a task in cancelled (e.g.: dropped), it is considered finished, and that canceled task's value would be used instead of the last compuleted task. In normal ember-concurrency APIs, this is abstracted over via the .lastSuccessful property on the TaskProperty. The goal of the .value on trackedTask is to mimic the property chain: taskProperty.lastSuccessful?.value.

  • #830 0767c08 Thanks @NullVoxPopuli! - Support TS 5.0

  • #868 b6f78c9 Thanks @NullVoxPopuli! - Test against ember-concurrency@v3, and add it as an allowed peerDepnedency

nullvoxpopuli
published 6.0.0-beta.6 •

Changelog

Source

6.0.0-beta.6

Patch Changes

  • #838 acbf03d Thanks @NullVoxPopuli! - Fixes #835 - resolves regression introduced by PR: #808 which aimed to correctly return the previous task instance's value if the current task hasn't finished yet. The regression described by #835 was that if a task in cancelled (e.g.: dropped), it is considered finished, and that canceled task's value would be used instead of the last compuleted task. In normal ember-concurrency APIs, this is abstracted over via the .lastSuccessful property on the TaskProperty. The goal of the .value on trackedTask is to mimic the property chain: taskProperty.lastSuccessful?.value.
nullvoxpopuli
published 5.6.4 •

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc