@gphone/sdk
    Preparing search index...

    Function createCrudStore

    The list-store factory, so an add-on can have one.

    It lives in services/ because core's own services use it, and it is exported here because an app cannot import by path (§2.7) — without this line, building a list means reimplementing the ordering, the loaded flag and the no-optimism rule that took several rewrites to settle. Paired with CrudOptions.service, which is how an app reaches its own server without a route table entry.

    • A store over a list of rows the server owns.

      Four stores had written the same load/add/update/delete by hand, and every difference between them was an accident rather than a decision:

      • Order — see sort above.
      • Optimism — Mail wrote to the list first and then told the server; everyone else waited. Optimism was load-bearing when fetchNui swallowed failures, because there was no other way to feel responsive. It now throws, so the list follows the server and a refused write no longer leaves the UI asserting something untrue.
      • Validation — Contacts checked its required fields, in the store and again in the component; nobody else checked anything.
      • Bad data — three stores logged and emptied the list on a non-array reply, one let it through.

      Neither reads nor writes pass a defaultValue, so fetchNui throws on failure instead of masking it. Writes propagate the throw to the caller, which already had a value to fall back to. load catches it itself and keeps the store's last known list — the store has nothing better to show, and a background refresh that failed should not wipe out what the player was already looking at.

      Type Parameters

      • T extends { id: number }
      • TDraft = Omit<T, "id">

      Parameters

      Returns {
          add: (draft: TDraft) => Promise<T>;
          delete: (id: number) => Promise<void>;
          load: () => Promise<void>;
          loaded: {
              subscribe: (
                  this: void,
                  run: Subscriber<boolean>,
                  invalidate?: () => void,
              ) => Unsubscriber;
          };
          patch: (id: number, changes: Partial<T>) => void;
          set: (rows: T[]) => void;
          subscribe: (
              this: void,
              run: Subscriber<T[]>,
              invalidate?: () => void,
          ) => Unsubscriber;
          update: (row: T) => Promise<void>;
      }

      • add: (draft: TDraft) => Promise<T>
      • delete: (id: number) => Promise<void>
      • load: () => Promise<void>
      • loaded: {
            subscribe: (
                this: void,
                run: Subscriber<boolean>,
                invalidate?: () => void,
            ) => Unsubscriber;
        }
        • subscribe: (this: void, run: Subscriber<boolean>, invalidate?: () => void) => Unsubscriber
      • patch: (id: number, changes: Partial<T>) => void
      • set: (rows: T[]) => void

        For the paths a list alone cannot express — an incoming message, a local patch.

      • subscribe: (this: void, run: Subscriber<T[]>, invalidate?: () => void) => Unsubscriber
      • update: (row: T) => Promise<void>