CAKE20

AI Web PaaS

Store

Share global UI state with a built-in store.

Built-in file type Store

  • The default export object in app/stores/<name>.store.ts is registered as store.<name> with the same name.
  • Store also recognizes subfolders recursively. Folders are for organizing purposes. File names must be unique across app/stores.
  • The state and functions that change the state are placed in one file, and there is no need for separate import, reactive, or state management packages.
  • The store file uses an English variable name and is placed directly under app/stores.
  • A function can read and change the state of the same module as this.
  • Generated store types provide autocomplete directly in Cake20 View TSX.
// app/stores/cart.store.ts
type CartItem = {
  id: string;
  name: string;
  price: number;
  count: number;
};

export const config = {
  // "none": Until refresh |"session": Up to current tab |"local": Remains even if you close the browser
  persist: "local"
} as const;

export default {
  items: [] as CartItem[],

  add(item: Omit<CartItem, "count">) {
    const found = this.items.find((row) => row.id === item.id);
    if (found) {
      found.count++;
      return;
    }
    this.items.push({ ...item, count: 1 });
  },

  remove(id: string) {
    this.items = this.items.filter((item) => item.id !== id);
  },

  clear() {
    this.items = [];
  }
};

Used in Cake20 View

  • store is used in all Cake20 View pages, layouts, and components without import.
  • State is reactive, so reading it directly or changing it with a function updates the screen immediately.
  • Since it is a browser UI-only interface, it is not used in server code such as API, Task, or Job.
export const computed = {
  total: () =>
  store.cart.items.reduce(
    (sum, item) => sum + item.price * item.count,
    0
  )
};

export const addCake = () => {
  store.cart.add({
    id: "strawberry",
    name: "strawberry cake",
    price: 32000
  });
};

export default () => (
  <>
    <Button onClick={addCake}>Add to cart</Button>
    <p>{store.cart.items.length} items · {computed.total().toLocaleString()} won</p>
  </>
);

Storage method

  • Currently, the only item that can be set in store config is persist.
  • none is memory, session is sessionStorage, local is localStorage, and the state of the module is stored as JSON.
  • Omitting config or persist will only keep the current page in memory, like persist: "none".
  • The stored values ​​are merged into the default state at startup, so functions declared in the file are preserved.
  • The local module automatically synchronizes changes made in other tabs of the same website.
  • The test address and operation address have different origins, so their saved states are not mixed.
  • The UI preview in the manager also separates the storage area into the base path for each website.
  • Functions, circular references, and values ​​that cannot be expressed in JSON are not used for storage.
  • Authentication tokens, passwords, secrets and sensitive information are not stored in the store. Login uses the HttpOnly cookie of server auth.
// Persist after closing and reopening the browser
export const config = { persist: "local" } as const;

// Keep current tab until you close it
export const config = { persist: "session" } as const;

// Maintained only in memory and reset when refreshed
export const config = { persist: "none" } as const;

// Reset one or all modules to default values
store.$reset("cart");
store.$reset();