rune-lab 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/core/index.d.ts +1 -0
  2. package/dist/core/index.d.ts.map +1 -1
  3. package/dist/core/index.js +1 -0
  4. package/dist/core/money/index.d.ts +2 -0
  5. package/dist/core/money/index.d.ts.map +1 -0
  6. package/dist/core/money/index.js +2 -0
  7. package/dist/core/money/money.d.ts +37 -0
  8. package/dist/core/money/money.d.ts.map +1 -0
  9. package/dist/core/money/money.js +79 -0
  10. package/dist/index.d.ts +0 -6
  11. package/dist/index.js +1 -7
  12. package/dist/state/auth/index.d.ts +2 -0
  13. package/dist/state/auth/index.js +2 -0
  14. package/dist/state/auth/session.svelte.d.ts +40 -0
  15. package/dist/state/auth/session.svelte.js +57 -0
  16. package/dist/state/auth/types.d.ts +30 -0
  17. package/dist/state/auth/types.js +3 -0
  18. package/dist/state/cart.svelte.d.ts +64 -0
  19. package/dist/state/cart.svelte.js +122 -0
  20. package/dist/state/composables/useMoney.d.ts +15 -0
  21. package/dist/state/composables/useMoney.js +48 -0
  22. package/dist/state/composables/useRuneLab.d.ts +3 -1
  23. package/dist/state/composables/useRuneLab.js +11 -0
  24. package/dist/state/context.d.ts +2 -0
  25. package/dist/state/context.js +2 -0
  26. package/dist/state/createConfigStore.svelte.d.ts +8 -3
  27. package/dist/state/createConfigStore.svelte.js +10 -0
  28. package/dist/state/currency.svelte.d.ts +9 -1
  29. package/dist/state/currency.svelte.js +28 -7
  30. package/dist/state/index.d.ts +7 -4
  31. package/dist/state/index.js +6 -2
  32. package/dist/state/language.svelte.d.ts +1 -0
  33. package/dist/state/persistence/drivers.d.ts +3 -1
  34. package/dist/state/persistence/drivers.js +5 -1
  35. package/dist/state/theme.svelte.d.ts +9 -1
  36. package/dist/state/theme.svelte.js +34 -8
  37. package/dist/ui/components/Icon.svelte +5 -2
  38. package/dist/ui/components/RuneProvider.svelte +59 -4
  39. package/dist/ui/components/RuneProvider.svelte.d.ts +19 -0
  40. package/dist/ui/components/money/MoneyDisplay.svelte +59 -0
  41. package/dist/ui/components/money/MoneyDisplay.svelte.d.ts +13 -0
  42. package/dist/ui/components/money/MoneyInput.svelte +106 -0
  43. package/dist/ui/components/money/MoneyInput.svelte.d.ts +19 -0
  44. package/dist/ui/components/money/index.d.ts +2 -0
  45. package/dist/ui/components/money/index.js +3 -0
  46. package/dist/ui/components/user/UserAvatar.svelte +66 -0
  47. package/dist/ui/components/user/UserAvatar.svelte.d.ts +13 -0
  48. package/dist/ui/components/user/UserProfile.svelte +79 -0
  49. package/dist/ui/components/user/UserProfile.svelte.d.ts +17 -0
  50. package/dist/ui/components/user/index.d.ts +2 -0
  51. package/dist/ui/components/user/index.js +3 -0
  52. package/dist/ui/features/notifications/NotificationBell.svelte +89 -0
  53. package/dist/ui/features/notifications/NotificationBell.svelte.d.ts +11 -0
  54. package/dist/ui/features/notifications/index.d.ts +1 -0
  55. package/dist/ui/features/notifications/index.js +2 -0
  56. package/dist/ui/index.d.ts +6 -0
  57. package/dist/ui/index.js +10 -0
  58. package/dist/ui/layout/WorkspaceLayout.svelte +9 -0
  59. package/dist/ui/paraglide/messages/_index.d.ts +4 -0
  60. package/dist/ui/paraglide/messages/_index.js +4 -0
  61. package/dist/ui/paraglide/messages/brl3.d.ts +17 -0
  62. package/dist/ui/paraglide/messages/brl3.js +85 -0
  63. package/dist/ui/paraglide/messages/cad3.d.ts +17 -0
  64. package/dist/ui/paraglide/messages/cad3.js +85 -0
  65. package/dist/ui/paraglide/messages/gbp3.d.ts +17 -0
  66. package/dist/ui/paraglide/messages/gbp3.js +85 -0
  67. package/dist/ui/paraglide/messages/inr3.d.ts +17 -0
  68. package/dist/ui/paraglide/messages/inr3.js +85 -0
  69. package/dist/ui/primitives/DatePicker.svelte +257 -0
  70. package/dist/ui/primitives/DatePicker.svelte.d.ts +17 -0
  71. package/dist/ui/primitives/index.d.ts +1 -0
  72. package/dist/ui/primitives/index.js +3 -0
  73. package/package.json +28 -18
  74. package/dist/state/config.d.ts +0 -4
  75. package/dist/state/config.js +0 -8
@@ -1,3 +1,4 @@
1
1
  export * from "./internal/message-resolver";
2
2
  export * from "./persistence/types";
3
+ export * from "./money/index";
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sdk/core/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC;AAE5C,cAAc,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sdk/core/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC;AAE5C,cAAc,qBAAqB,CAAC;AAEpC,cAAc,eAAe,CAAC"}
@@ -1,2 +1,3 @@
1
1
  export * from "./internal/message-resolver";
2
2
  export * from "./persistence/types";
3
+ export * from "./money/index";
@@ -0,0 +1,2 @@
1
+ export { addMoney, createMoney, CURRENCY_MAP, type Dinero, type DineroCurrency, formatAmount, formatMoney, multiplyMoney, subtractMoney, } from "./money";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/sdk/core/src/money/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,KAAK,MAAM,EACX,KAAK,cAAc,EACnB,YAAY,EACZ,WAAW,EACX,aAAa,EACb,aAAa,GACd,MAAM,SAAS,CAAC"}
@@ -0,0 +1,2 @@
1
+ // sdk/core/src/money/index.ts
2
+ export { addMoney, createMoney, CURRENCY_MAP, formatAmount, formatMoney, multiplyMoney, subtractMoney, } from "./money";
@@ -0,0 +1,37 @@
1
+ import { type Dinero, type DineroCurrency } from "dinero.js";
2
+ /**
3
+ * Map of ISO 4217 currency codes to Dinero currency objects
4
+ */
5
+ export declare const CURRENCY_MAP: Record<string, DineroCurrency<number>>;
6
+ /**
7
+ * Create a Dinero monetary value from an amount in minor units (cents)
8
+ * @param amount - Amount in minor units (e.g., 1234 = $12.34 for USD)
9
+ * @param currencyCode - ISO 4217 currency code (e.g., "USD")
10
+ */
11
+ export declare function createMoney(amount: number, currencyCode: string): Dinero<number>;
12
+ /**
13
+ * Format a Dinero value as a locale-aware string
14
+ * @param money - Dinero monetary value
15
+ * @param locale - BCP 47 locale string (e.g., "en-US", "es-MX")
16
+ * @param currencyCode - ISO 4217 code for Intl.NumberFormat (e.g., "USD")
17
+ */
18
+ export declare function formatMoney(money: Dinero<number>, locale?: string, currencyCode?: string): string;
19
+ /**
20
+ * Format a raw amount (minor units) as a locale-aware currency string
21
+ * Convenience wrapper around createMoney + formatMoney
22
+ */
23
+ export declare function formatAmount(amount: number, currencyCode: string, locale?: string): string;
24
+ /**
25
+ * Add two monetary values (must be same currency)
26
+ */
27
+ export declare function addMoney(a: Dinero<number>, b: Dinero<number>): Dinero<number>;
28
+ /**
29
+ * Subtract two monetary values (must be same currency)
30
+ */
31
+ export declare function subtractMoney(a: Dinero<number>, b: Dinero<number>): Dinero<number>;
32
+ /**
33
+ * Multiply a monetary value by a factor
34
+ */
35
+ export declare function multiplyMoney(money: Dinero<number>, factor: number): Dinero<number>;
36
+ export type { Dinero, DineroCurrency };
37
+ //# sourceMappingURL=money.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"money.d.ts","sourceRoot":"","sources":["../../../src/sdk/core/src/money/money.ts"],"names":[],"mappings":"AAIA,OAAO,EAML,KAAK,MAAM,EAEX,KAAK,cAAc,EAYpB,MAAM,WAAW,CAAC;AAEnB;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,CAY/D,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,GACnB,MAAM,CAAC,MAAM,CAAC,CAQhB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,EACrB,MAAM,GAAE,MAAgB,EACxB,YAAY,CAAC,EAAE,MAAM,GACpB,MAAM,CAeR;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,MAAM,GAAE,MAAgB,GACvB,MAAM,CAGR;AAED;;GAEG;AACH,wBAAgB,QAAQ,CACtB,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,EACjB,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,GAChB,MAAM,CAAC,MAAM,CAAC,CAEhB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,EACjB,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,GAChB,MAAM,CAAC,MAAM,CAAC,CAEhB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,EACrB,MAAM,EAAE,MAAM,GACb,MAAM,CAAC,MAAM,CAAC,CAEhB;AAGD,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC"}
@@ -0,0 +1,79 @@
1
+ // sdk/core/src/money/money.ts
2
+ // Framework-agnostic money utilities using Dinero.js v2
3
+ // Consumers should never import Dinero directly — these helpers encapsulate it.
4
+ import { add as dineroAdd, AED, BRL, CAD, CNY, dinero, EUR, GBP, INR, JPY, KRW, multiply as dineroMultiply, MXN, subtract as dineroSubtract, toDecimal,
5
+ // ISO 4217 currency definitions
6
+ USD, } from "dinero.js";
7
+ /**
8
+ * Map of ISO 4217 currency codes to Dinero currency objects
9
+ */
10
+ export const CURRENCY_MAP = {
11
+ USD,
12
+ EUR,
13
+ MXN,
14
+ JPY,
15
+ KRW,
16
+ CNY,
17
+ AED,
18
+ GBP,
19
+ CAD,
20
+ BRL,
21
+ INR,
22
+ };
23
+ /**
24
+ * Create a Dinero monetary value from an amount in minor units (cents)
25
+ * @param amount - Amount in minor units (e.g., 1234 = $12.34 for USD)
26
+ * @param currencyCode - ISO 4217 currency code (e.g., "USD")
27
+ */
28
+ export function createMoney(amount, currencyCode) {
29
+ const currency = CURRENCY_MAP[currencyCode];
30
+ if (!currency) {
31
+ throw new Error(`Unknown currency code: ${currencyCode}. Add it to CURRENCY_MAP.`);
32
+ }
33
+ return dinero({ amount, currency });
34
+ }
35
+ /**
36
+ * Format a Dinero value as a locale-aware string
37
+ * @param money - Dinero monetary value
38
+ * @param locale - BCP 47 locale string (e.g., "en-US", "es-MX")
39
+ * @param currencyCode - ISO 4217 code for Intl.NumberFormat (e.g., "USD")
40
+ */
41
+ export function formatMoney(money, locale = "en-US", currencyCode) {
42
+ return toDecimal(money, ({ value, currency }) => {
43
+ const code = currencyCode ??
44
+ Object.entries(CURRENCY_MAP).find(([, c]) => c.code === currency.code)?.[0] ??
45
+ currency.code;
46
+ return new Intl.NumberFormat(locale, {
47
+ style: "currency",
48
+ currency: code,
49
+ minimumFractionDigits: currency.exponent,
50
+ maximumFractionDigits: currency.exponent,
51
+ }).format(Number(value));
52
+ });
53
+ }
54
+ /**
55
+ * Format a raw amount (minor units) as a locale-aware currency string
56
+ * Convenience wrapper around createMoney + formatMoney
57
+ */
58
+ export function formatAmount(amount, currencyCode, locale = "en-US") {
59
+ const money = createMoney(amount, currencyCode);
60
+ return formatMoney(money, locale, currencyCode);
61
+ }
62
+ /**
63
+ * Add two monetary values (must be same currency)
64
+ */
65
+ export function addMoney(a, b) {
66
+ return dineroAdd(a, b);
67
+ }
68
+ /**
69
+ * Subtract two monetary values (must be same currency)
70
+ */
71
+ export function subtractMoney(a, b) {
72
+ return dineroSubtract(a, b);
73
+ }
74
+ /**
75
+ * Multiply a monetary value by a factor
76
+ */
77
+ export function multiplyMoney(money, factor) {
78
+ return dineroMultiply(money, factor);
79
+ }
package/dist/index.d.ts CHANGED
@@ -2,10 +2,4 @@ export * from "rune-lab/core";
2
2
  export * from "rune-lab/state";
3
3
  export * from "rune-lab/ui";
4
4
 
5
- export {
6
- cookieDriver,
7
- localStorageDriver,
8
- sessionStorageDriver,
9
- } from "rune-lab/state";
10
-
11
5
  export declare const version: () => string;
package/dist/index.js CHANGED
@@ -2,10 +2,4 @@ export * from "rune-lab/core";
2
2
  export * from "rune-lab/state";
3
3
  export * from "rune-lab/ui";
4
4
 
5
- export {
6
- cookieDriver,
7
- localStorageDriver,
8
- sessionStorageDriver,
9
- } from "rune-lab/state";
10
-
11
- export const version = () => "0.2.2";
5
+ export const version = () => "0.2.3";
@@ -0,0 +1,2 @@
1
+ export type { AuthConfig, Session, User } from "./types";
2
+ export { createSessionStore, getSessionStore, SessionStore, } from "./session.svelte";
@@ -0,0 +1,2 @@
1
+ // sdk/state/src/auth/index.ts
2
+ export { createSessionStore, getSessionStore, SessionStore, } from "./session.svelte";
@@ -0,0 +1,40 @@
1
+ import type { Session, User } from "./types";
2
+ /**
3
+ * SessionStore — reactive authentication state.
4
+ *
5
+ * Once Better-Auth is fully integrated, this store will:
6
+ * - Initialize from the Better-Auth client SDK
7
+ * - Manage session lifecycle (login, logout, refresh)
8
+ * - Expose the current user + session tokens
9
+ * - Fire onSessionChange callbacks
10
+ *
11
+ * For now, it provides the interface contract that consuming apps
12
+ * and other rune-lab components (UserAvatar, UserProfile) can code against.
13
+ */
14
+ export declare class SessionStore {
15
+ /** Whether authentication has been checked (vs. loading) */
16
+ isReady: boolean;
17
+ /** Whether a user is currently authenticated */
18
+ isAuthenticated: boolean;
19
+ /** Current user (null when logged out) */
20
+ user: User | null;
21
+ /** Current session (null when logged out) */
22
+ session: Session | null;
23
+ /**
24
+ * Initialize the session — placeholder for Better-Auth client setup
25
+ */
26
+ init(): Promise<void>;
27
+ /**
28
+ * Log in — placeholder
29
+ */
30
+ login(_credentials: {
31
+ email: string;
32
+ password: string;
33
+ }): Promise<boolean>;
34
+ /**
35
+ * Log out — placeholder
36
+ */
37
+ logout(): Promise<void>;
38
+ }
39
+ export declare function createSessionStore(): SessionStore;
40
+ export declare function getSessionStore(): SessionStore;
@@ -0,0 +1,57 @@
1
+ // sdk/state/src/auth/session.svelte.ts
2
+ // SessionStore — manages authentication state via Svelte 5 runes.
3
+ // This is a SKELETON — full Better-Auth wiring is deferred to a dedicated spec.
4
+ import { getContext } from "svelte";
5
+ import { RUNE_LAB_CONTEXT } from "../context";
6
+ /**
7
+ * SessionStore — reactive authentication state.
8
+ *
9
+ * Once Better-Auth is fully integrated, this store will:
10
+ * - Initialize from the Better-Auth client SDK
11
+ * - Manage session lifecycle (login, logout, refresh)
12
+ * - Expose the current user + session tokens
13
+ * - Fire onSessionChange callbacks
14
+ *
15
+ * For now, it provides the interface contract that consuming apps
16
+ * and other rune-lab components (UserAvatar, UserProfile) can code against.
17
+ */
18
+ export class SessionStore {
19
+ /** Whether authentication has been checked (vs. loading) */
20
+ isReady = $state(false);
21
+ /** Whether a user is currently authenticated */
22
+ isAuthenticated = $state(false);
23
+ /** Current user (null when logged out) */
24
+ user = $state(null);
25
+ /** Current session (null when logged out) */
26
+ session = $state(null);
27
+ /**
28
+ * Initialize the session — placeholder for Better-Auth client setup
29
+ */
30
+ async init() {
31
+ // TODO: Wire Better-Auth client.getSession() here
32
+ this.isReady = true;
33
+ }
34
+ /**
35
+ * Log in — placeholder
36
+ */
37
+ async login(_credentials) {
38
+ // TODO: Wire Better-Auth client.signIn.email() here
39
+ console.warn("SessionStore.login() is a stub — implement Better-Auth integration");
40
+ return false;
41
+ }
42
+ /**
43
+ * Log out — placeholder
44
+ */
45
+ async logout() {
46
+ // TODO: Wire Better-Auth client.signOut() here
47
+ this.user = null;
48
+ this.session = null;
49
+ this.isAuthenticated = false;
50
+ }
51
+ }
52
+ export function createSessionStore() {
53
+ return new SessionStore();
54
+ }
55
+ export function getSessionStore() {
56
+ return getContext(RUNE_LAB_CONTEXT.session);
57
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Minimal user representation for rune-lab's auth layer.
3
+ * Consuming apps can extend this with domain-specific fields.
4
+ */
5
+ export interface User {
6
+ id: string;
7
+ name: string;
8
+ email: string;
9
+ avatar_url?: string;
10
+ role?: string;
11
+ }
12
+ /**
13
+ * Active session information
14
+ */
15
+ export interface Session {
16
+ user: User;
17
+ accessToken: string;
18
+ expiresAt: Date;
19
+ }
20
+ /**
21
+ * Auth configuration passed to RuneProvider
22
+ */
23
+ export interface AuthConfig {
24
+ /** Better-Auth client instance */
25
+ client?: any;
26
+ /** Callback when session changes (login, logout, expiry) */
27
+ onSessionChange?: (session: Session | null) => void;
28
+ /** Routes that require authentication */
29
+ protectedRoutes?: string[];
30
+ }
@@ -0,0 +1,3 @@
1
+ // sdk/state/src/auth/types.ts
2
+ // Core auth types — framework-agnostic interfaces
3
+ export {};
@@ -0,0 +1,64 @@
1
+ import type { PersistenceDriver } from "rune-lab/core";
2
+ /**
3
+ * Configuration for creating a CartStore
4
+ */
5
+ export interface CartStoreConfig<T> {
6
+ /** Extract a unique identifier from an item */
7
+ idExtractor: (item: T) => string;
8
+ /** Extract the price (in minor units / cents) from an item */
9
+ priceExtractor: (item: T) => number;
10
+ /** Optional persistence driver for cart recovery */
11
+ driver?: PersistenceDriver;
12
+ /** Storage key for persistence */
13
+ storageKey?: string;
14
+ }
15
+ export interface CartEntry<T> {
16
+ item: T;
17
+ qty: number;
18
+ }
19
+ /**
20
+ * Generic cart store factory.
21
+ * Works with any item type via extractors.
22
+ *
23
+ * **Note**: Consumers must call `setContext(RUNE_LAB_CONTEXT.cart, store)` manually
24
+ * since CartStore is app-specific (needs `idExtractor` and `priceExtractor`).
25
+ * RuneProvider can optionally wire it via `config.cart`.
26
+ *
27
+ * Usage:
28
+ * const cart = createCartStore<Property>({
29
+ * idExtractor: (p) => p.id,
30
+ * priceExtractor: (p) => p.price,
31
+ * });
32
+ * cart.add(someProperty);
33
+ * cart.totalPrice; // sum of all items * qty in minor units
34
+ */
35
+ export declare function createCartStore<T>(config: CartStoreConfig<T>): {
36
+ /** All cart entries */
37
+ readonly items: CartEntry<T>[];
38
+ /** Total number of items (sum of quantities) */
39
+ readonly totalItems: number;
40
+ /** Total price in minor units */
41
+ readonly totalPrice: number;
42
+ /** Whether the cart is empty */
43
+ readonly isEmpty: boolean;
44
+ /** Add an item (or increment quantity if already present) */
45
+ add(item: T, qty?: number): void;
46
+ /** Remove an item entirely */
47
+ remove(id: string): void;
48
+ /** Update the quantity of an item (removes if qty ≤ 0) */
49
+ updateQty(id: string, qty: number): void;
50
+ /** Clear all items */
51
+ clear(): void;
52
+ /** Check if an item is in the cart */
53
+ has(id: string): boolean;
54
+ /** Get a specific entry by ID */
55
+ getEntry(id: string): CartEntry<T> | undefined;
56
+ };
57
+ /** Return type of createCartStore for context typing */
58
+ export type CartStore<T = unknown> = ReturnType<typeof createCartStore<T>>;
59
+ /**
60
+ * Get CartStore from Svelte context.
61
+ * Only works if the consuming app has called setContext(RUNE_LAB_CONTEXT.cart, store)
62
+ * or passed a cart config to RuneProvider.
63
+ */
64
+ export declare function getCartStore<T = unknown>(): CartStore<T>;
@@ -0,0 +1,122 @@
1
+ // sdk/state/src/cart.svelte.ts
2
+ // Generic cart store factory — business-agnostic add/remove/total pattern.
3
+ import { getContext } from "svelte";
4
+ import { RUNE_LAB_CONTEXT } from "./context";
5
+ import { DEV } from "esm-env";
6
+ /**
7
+ * Generic cart store factory.
8
+ * Works with any item type via extractors.
9
+ *
10
+ * **Note**: Consumers must call `setContext(RUNE_LAB_CONTEXT.cart, store)` manually
11
+ * since CartStore is app-specific (needs `idExtractor` and `priceExtractor`).
12
+ * RuneProvider can optionally wire it via `config.cart`.
13
+ *
14
+ * Usage:
15
+ * const cart = createCartStore<Property>({
16
+ * idExtractor: (p) => p.id,
17
+ * priceExtractor: (p) => p.price,
18
+ * });
19
+ * cart.add(someProperty);
20
+ * cart.totalPrice; // sum of all items * qty in minor units
21
+ */
22
+ export function createCartStore(config) {
23
+ const { idExtractor, priceExtractor, driver, storageKey = "cart", } = config;
24
+ // Internal entries store — using a plain array for correct serialization
25
+ let _entries = $state([]);
26
+ /** Lookup by ID */
27
+ function _findIndex(id) {
28
+ return _entries.findIndex((e) => idExtractor(e.item) === id);
29
+ }
30
+ /** @internal Persist current state (Map serialized as Array) */
31
+ function _persist() {
32
+ if (!driver)
33
+ return;
34
+ try {
35
+ const data = _entries.map((entry) => ({
36
+ id: idExtractor(entry.item),
37
+ qty: entry.qty,
38
+ }));
39
+ driver.set(storageKey, JSON.stringify(data));
40
+ }
41
+ catch {
42
+ // Persistence is best-effort
43
+ }
44
+ }
45
+ return {
46
+ /** All cart entries */
47
+ get items() {
48
+ return _entries;
49
+ },
50
+ /** Total number of items (sum of quantities) */
51
+ get totalItems() {
52
+ let total = 0;
53
+ for (const entry of _entries)
54
+ total += entry.qty;
55
+ return total;
56
+ },
57
+ /** Total price in minor units */
58
+ get totalPrice() {
59
+ let total = 0;
60
+ for (const entry of _entries) {
61
+ total += priceExtractor(entry.item) * entry.qty;
62
+ }
63
+ return total;
64
+ },
65
+ /** Whether the cart is empty */
66
+ get isEmpty() {
67
+ return _entries.length === 0;
68
+ },
69
+ /** Add an item (or increment quantity if already present) */
70
+ add(item, qty = 1) {
71
+ const id = idExtractor(item);
72
+ const idx = _findIndex(id);
73
+ if (idx >= 0) {
74
+ _entries[idx] = { ..._entries[idx], qty: _entries[idx].qty + qty };
75
+ }
76
+ else {
77
+ _entries = [..._entries, { item, qty }];
78
+ }
79
+ _persist();
80
+ if (DEV)
81
+ console.log(`🛒 Added ${id} (qty: ${qty})`);
82
+ },
83
+ /** Remove an item entirely */
84
+ remove(id) {
85
+ _entries = _entries.filter((e) => idExtractor(e.item) !== id);
86
+ _persist();
87
+ },
88
+ /** Update the quantity of an item (removes if qty ≤ 0) */
89
+ updateQty(id, qty) {
90
+ if (qty <= 0) {
91
+ this.remove(id);
92
+ return;
93
+ }
94
+ const idx = _findIndex(id);
95
+ if (idx >= 0) {
96
+ _entries[idx] = { ..._entries[idx], qty };
97
+ _persist();
98
+ }
99
+ },
100
+ /** Clear all items */
101
+ clear() {
102
+ _entries = [];
103
+ _persist();
104
+ },
105
+ /** Check if an item is in the cart */
106
+ has(id) {
107
+ return _findIndex(id) >= 0;
108
+ },
109
+ /** Get a specific entry by ID */
110
+ getEntry(id) {
111
+ return _entries.find((e) => idExtractor(e.item) === id);
112
+ },
113
+ };
114
+ }
115
+ /**
116
+ * Get CartStore from Svelte context.
117
+ * Only works if the consuming app has called setContext(RUNE_LAB_CONTEXT.cart, store)
118
+ * or passed a cart config to RuneProvider.
119
+ */
120
+ export function getCartStore() {
121
+ return getContext(RUNE_LAB_CONTEXT.cart);
122
+ }
@@ -0,0 +1,15 @@
1
+ import { type Dinero } from "rune-lab/core";
2
+ /**
3
+ * Context-aware money composable.
4
+ * Reads CurrencyStore and LanguageStore from rune-lab context.
5
+ *
6
+ * Usage:
7
+ * const { format, toDinero, add, subtract } = useMoney();
8
+ * const display = format(15000); // "$150.00" (based on current currency + locale)
9
+ */
10
+ export declare function useMoney(): {
11
+ toDinero: (amount: number, currencyCode?: string) => Dinero<number>;
12
+ format: (amount: number, currencyCode?: string) => string;
13
+ add: (a: number, b: number, currencyCode?: string) => Dinero<number>;
14
+ subtract: (a: number, b: number, currencyCode?: string) => Dinero<number>;
15
+ };
@@ -0,0 +1,48 @@
1
+ // sdk/state/src/composables/useMoney.ts
2
+ // Context-aware money composable that reads CurrencyStore + LanguageStore
3
+ import { getContext } from "svelte";
4
+ import { RUNE_LAB_CONTEXT } from "../context";
5
+ import { addMoney, createMoney, formatMoney, subtractMoney, } from "rune-lab/core";
6
+ /**
7
+ * Context-aware money composable.
8
+ * Reads CurrencyStore and LanguageStore from rune-lab context.
9
+ *
10
+ * Usage:
11
+ * const { format, toDinero, add, subtract } = useMoney();
12
+ * const display = format(15000); // "$150.00" (based on current currency + locale)
13
+ */
14
+ export function useMoney() {
15
+ const currencyStore = getContext(RUNE_LAB_CONTEXT.currency);
16
+ const languageStore = getContext(RUNE_LAB_CONTEXT.language);
17
+ /**
18
+ * Convert minor-unit amount to a Dinero object using current currency
19
+ */
20
+ function toDinero(amount, currencyCode) {
21
+ const code = currencyCode ?? String(currencyStore.current);
22
+ return createMoney(amount, code);
23
+ }
24
+ /**
25
+ * Format an amount (minor units) as a locale-aware currency string
26
+ */
27
+ function format(amount, currencyCode) {
28
+ const code = currencyCode ?? String(currencyStore.current);
29
+ const locale = String(languageStore.current) || "en";
30
+ const money = createMoney(amount, code);
31
+ return formatMoney(money, locale, code);
32
+ }
33
+ /**
34
+ * Add two amounts (minor units) in the current currency
35
+ */
36
+ function add(a, b, currencyCode) {
37
+ const code = currencyCode ?? String(currencyStore.current);
38
+ return addMoney(createMoney(a, code), createMoney(b, code));
39
+ }
40
+ /**
41
+ * Subtract two amounts (minor units) in the current currency
42
+ */
43
+ function subtract(a, b, currencyCode) {
44
+ const code = currencyCode ?? String(currencyStore.current);
45
+ return subtractMoney(createMoney(a, code), createMoney(b, code));
46
+ }
47
+ return { toDinero, format, add, subtract };
48
+ }
@@ -1,4 +1,4 @@
1
- import { getApiStore, getAppStore, getCommandStore, getCurrencyStore, getLanguageStore, getLayoutStore, getShortcutStore, getThemeStore, getToastStore } from "../index";
1
+ import { getApiStore, getAppStore, getCommandStore, getCurrencyStore, getLanguageStore, getLayoutStore, getShortcutStore, getThemeStore, getToastStore, type SessionStore } from "../index";
2
2
  export interface RuneLabContext {
3
3
  app: ReturnType<typeof getAppStore>;
4
4
  api: ReturnType<typeof getApiStore>;
@@ -9,6 +9,8 @@ export interface RuneLabContext {
9
9
  shortcut: ReturnType<typeof getShortcutStore>;
10
10
  layout: ReturnType<typeof getLayoutStore>;
11
11
  commands: ReturnType<typeof getCommandStore>;
12
+ /** Available when auth is enabled in RuneProvider config */
13
+ session?: SessionStore;
12
14
  }
13
15
  /**
14
16
  * Retrieves all Rune Lab stores from the Svelte context tree.
@@ -1,10 +1,20 @@
1
1
  // src/lib/composables/useRuneLab.ts
2
2
  import { getApiStore, getAppStore, getCommandStore, getCurrencyStore, getLanguageStore, getLayoutStore, getShortcutStore, getThemeStore, getToastStore, } from "../index";
3
+ import { getContext } from "svelte";
4
+ import { RUNE_LAB_CONTEXT } from "../context";
3
5
  /**
4
6
  * Retrieves all Rune Lab stores from the Svelte context tree.
5
7
  * Must be called during component initialization (in the `<script>` block).
6
8
  */
7
9
  export function useRuneLab() {
10
+ // Session is optional — only present when auth is enabled
11
+ let session;
12
+ try {
13
+ session = getContext(RUNE_LAB_CONTEXT.session);
14
+ }
15
+ catch {
16
+ // Auth not enabled — session stays undefined
17
+ }
8
18
  return {
9
19
  app: getAppStore(),
10
20
  api: getApiStore(),
@@ -15,5 +25,6 @@ export function useRuneLab() {
15
25
  shortcut: getShortcutStore(),
16
26
  layout: getLayoutStore(),
17
27
  commands: getCommandStore(),
28
+ session,
18
29
  };
19
30
  }
@@ -9,4 +9,6 @@ export declare const RUNE_LAB_CONTEXT: {
9
9
  readonly layout: symbol;
10
10
  readonly commands: symbol;
11
11
  readonly persistence: symbol;
12
+ readonly cart: symbol;
13
+ readonly session: symbol;
12
14
  };
@@ -10,4 +10,6 @@ export const RUNE_LAB_CONTEXT = {
10
10
  layout: Symbol("rl:layout"),
11
11
  commands: Symbol("rl:commands"),
12
12
  persistence: Symbol("rl:persistence"),
13
+ cart: Symbol("rl:cart"),
14
+ session: Symbol("rl:session"),
13
15
  };
@@ -5,16 +5,18 @@ export type ConfigStore<T extends ConfigItem> = {
5
5
  set: (id: T[keyof T]) => void;
6
6
  get: (id: T[keyof T]) => T | undefined;
7
7
  getProp: <K extends keyof T>(prop: K, id?: T[keyof T]) => T[K] | undefined;
8
+ /** Append additional items (e.g. custom themes/currencies from the consuming app) */
9
+ addItems: (newItems: T[]) => void;
8
10
  };
9
11
  /**
10
12
  * Generic configuration store factory
11
13
  * Creates type-safe stores for theme, language, currency, etc.
12
14
  * with validation, persistence, and utilities
13
15
  */
14
- interface ConfigItem {
16
+ export interface ConfigItem {
15
17
  [key: string]: any;
16
18
  }
17
- interface ConfigStoreOptions<T extends ConfigItem> {
19
+ export interface ConfigStoreOptions<T extends ConfigItem> {
18
20
  /** Array of available items */
19
21
  items: readonly T[];
20
22
  /** Storage key used by the persistence driver */
@@ -46,5 +48,8 @@ export declare function createConfigStore<T extends ConfigItem>(options: ConfigS
46
48
  * Get property from current or specified item
47
49
  */
48
50
  getProp<K extends keyof T>(prop: K, id?: T[keyof T]): T[K] | undefined;
51
+ /**
52
+ * Append additional items (deduplicates by idKey)
53
+ */
54
+ addItems(newItems: T[]): void;
49
55
  };
50
- export {};