floppy-disk 2.16.0 → 3.0.0-alpha.2

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/README.md +0 -835
  2. package/esm/index.d.mts +1 -0
  3. package/esm/index.mjs +1 -0
  4. package/esm/react/create-mutation.d.mts +135 -0
  5. package/esm/react/create-query.d.mts +319 -0
  6. package/esm/react/create-store.d.mts +25 -0
  7. package/esm/react/create-stores.d.mts +32 -0
  8. package/esm/react/use-isomorphic-layout-effect.d.mts +6 -0
  9. package/esm/react/use-store.d.mts +18 -0
  10. package/esm/react.d.mts +6 -0
  11. package/esm/react.mjs +503 -0
  12. package/esm/vanilla/basic.d.mts +21 -0
  13. package/esm/vanilla/hash.d.mts +7 -0
  14. package/esm/vanilla/shallow.d.mts +6 -0
  15. package/esm/vanilla/store.d.mts +75 -0
  16. package/esm/vanilla.d.mts +4 -0
  17. package/esm/vanilla.mjs +109 -0
  18. package/index.d.ts +1 -0
  19. package/index.js +12 -0
  20. package/package.json +50 -45
  21. package/react/create-mutation.d.ts +135 -0
  22. package/react/create-query.d.ts +319 -0
  23. package/react/create-store.d.ts +25 -0
  24. package/react/create-stores.d.ts +32 -0
  25. package/react/use-isomorphic-layout-effect.d.ts +6 -0
  26. package/react/use-store.d.ts +18 -0
  27. package/{lib/index.d.ts → react.d.ts} +2 -4
  28. package/react.js +511 -0
  29. package/ts_version_4.5_and_above_is_required.d.ts +0 -0
  30. package/vanilla/basic.d.ts +21 -0
  31. package/vanilla/hash.d.ts +7 -0
  32. package/vanilla/shallow.d.ts +6 -0
  33. package/vanilla/store.d.ts +75 -0
  34. package/vanilla.d.ts +4 -0
  35. package/vanilla.js +118 -0
  36. package/esm/fetcher.d.ts +0 -27
  37. package/esm/fetcher.js +0 -95
  38. package/esm/index.d.ts +0 -8
  39. package/esm/index.js +0 -8
  40. package/esm/react/create-bi-direction-query.d.ts +0 -166
  41. package/esm/react/create-bi-direction-query.js +0 -74
  42. package/esm/react/create-mutation.d.ts +0 -39
  43. package/esm/react/create-mutation.js +0 -56
  44. package/esm/react/create-query.d.ts +0 -319
  45. package/esm/react/create-query.js +0 -434
  46. package/esm/react/create-store.d.ts +0 -51
  47. package/esm/react/create-store.js +0 -38
  48. package/esm/react/create-stores.d.ts +0 -77
  49. package/esm/react/create-stores.js +0 -125
  50. package/esm/react/with-context.d.ts +0 -5
  51. package/esm/react/with-context.js +0 -14
  52. package/esm/store.d.ts +0 -24
  53. package/esm/store.js +0 -51
  54. package/esm/utils.d.ts +0 -24
  55. package/esm/utils.js +0 -31
  56. package/lib/fetcher.d.ts +0 -27
  57. package/lib/fetcher.js +0 -99
  58. package/lib/index.js +0 -11
  59. package/lib/react/create-bi-direction-query.d.ts +0 -166
  60. package/lib/react/create-bi-direction-query.js +0 -78
  61. package/lib/react/create-mutation.d.ts +0 -39
  62. package/lib/react/create-mutation.js +0 -60
  63. package/lib/react/create-query.d.ts +0 -319
  64. package/lib/react/create-query.js +0 -438
  65. package/lib/react/create-store.d.ts +0 -51
  66. package/lib/react/create-store.js +0 -42
  67. package/lib/react/create-stores.d.ts +0 -77
  68. package/lib/react/create-stores.js +0 -130
  69. package/lib/react/with-context.d.ts +0 -5
  70. package/lib/react/with-context.js +0 -18
  71. package/lib/store.d.ts +0 -24
  72. package/lib/store.js +0 -55
  73. package/lib/utils.d.ts +0 -24
  74. package/lib/utils.js +0 -39
  75. package/utils/package.json +0 -6
@@ -0,0 +1,109 @@
1
+ const isClient = typeof window !== "undefined" && !("Deno" in window);
2
+ const noop = () => {
3
+ };
4
+ const identity = (value) => value;
5
+ const getValue = (valueOrComputeValueFn, ...params) => {
6
+ if (typeof valueOrComputeValueFn === "function") {
7
+ return valueOrComputeValueFn(...params);
8
+ }
9
+ return valueOrComputeValueFn;
10
+ };
11
+
12
+ const shallow = (a, b) => {
13
+ if (Object.is(a, b)) {
14
+ return true;
15
+ }
16
+ if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) {
17
+ return false;
18
+ }
19
+ if (a instanceof Map && b instanceof Map) {
20
+ if (a.size !== b.size) return false;
21
+ for (const [key, value] of a) {
22
+ if (!Object.is(value, b.get(key))) {
23
+ return false;
24
+ }
25
+ }
26
+ return true;
27
+ }
28
+ if (a instanceof Set && b instanceof Set) {
29
+ if (a.size !== b.size) return false;
30
+ for (const value of a) {
31
+ if (!b.has(value)) return false;
32
+ }
33
+ return true;
34
+ }
35
+ const keysA = Object.keys(a);
36
+ if (keysA.length !== Object.keys(b).length) {
37
+ return false;
38
+ }
39
+ for (let i = 0; i < keysA.length; i++) {
40
+ if (!Object.prototype.hasOwnProperty.call(b, keysA[i]) || !Object.is(a[keysA[i]], b[keysA[i]])) {
41
+ return false;
42
+ }
43
+ }
44
+ return true;
45
+ };
46
+
47
+ const hasObjectPrototype = (value) => {
48
+ return Object.prototype.toString.call(value) === "[object Object]";
49
+ };
50
+ const isPlainObject = (value) => {
51
+ if (!hasObjectPrototype(value)) return false;
52
+ const ctor = value.constructor;
53
+ if (typeof ctor === "undefined") return true;
54
+ const prot = ctor.prototype;
55
+ if (!hasObjectPrototype(prot)) return false;
56
+ if (!prot.hasOwnProperty("isPrototypeOf")) return false;
57
+ if (Object.getPrototypeOf(value) !== Object.prototype) return false;
58
+ return true;
59
+ };
60
+ const getHash = (value) => JSON.stringify(
61
+ value,
62
+ (_, val) => isPlainObject(val) ? Object.keys(val).sort().reduce((result, key) => {
63
+ result[key] = val[key];
64
+ return result;
65
+ }, {}) : val
66
+ );
67
+
68
+ const initStore = (initialState, options = {}) => {
69
+ const {
70
+ onFirstSubscribe = noop,
71
+ onSubscribe = noop,
72
+ onUnsubscribe = noop,
73
+ onLastUnsubscribe = noop
74
+ } = options;
75
+ const subscribers = /* @__PURE__ */ new Set();
76
+ const getSubscribers = () => subscribers;
77
+ const subscribe = (subscriber) => {
78
+ subscribers.add(subscriber);
79
+ if (subscribers.size === 1) onFirstSubscribe(state, storeApi);
80
+ onSubscribe(state, storeApi);
81
+ return () => {
82
+ subscribers.delete(subscriber);
83
+ onUnsubscribe(state, storeApi);
84
+ if (subscribers.size === 0) onLastUnsubscribe(state, storeApi);
85
+ };
86
+ };
87
+ let state = initialState;
88
+ const getState = () => state;
89
+ const setState = (value) => {
90
+ const prevState = state;
91
+ const newValue = getValue(value, state);
92
+ for (const key in newValue) {
93
+ if (!Object.is(prevState[key], newValue[key])) {
94
+ state = { ...prevState, ...newValue };
95
+ [...subscribers].forEach((subscriber) => subscriber(state, prevState));
96
+ return;
97
+ }
98
+ }
99
+ };
100
+ const storeApi = {
101
+ getState,
102
+ setState,
103
+ subscribe,
104
+ getSubscribers
105
+ };
106
+ return storeApi;
107
+ };
108
+
109
+ export { getHash, getValue, identity, initStore, isClient, isPlainObject, noop, shallow };
package/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from 'floppy-disk/vanilla';
package/index.js ADDED
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ var vanilla = require('floppy-disk/vanilla');
4
+
5
+
6
+
7
+ Object.keys(vanilla).forEach(function (k) {
8
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
9
+ enumerable: true,
10
+ get: function () { return vanilla[k]; }
11
+ });
12
+ });
package/package.json CHANGED
@@ -1,15 +1,17 @@
1
1
  {
2
2
  "name": "floppy-disk",
3
- "version": "2.16.0",
4
- "description": "FloppyDisk - lightweight, simple, and powerful state management library",
3
+ "description": "Lightweight, simple, and powerful state management library",
4
+ "private": false,
5
+ "version": "3.0.0-alpha.2",
6
+ "publishConfig": {
7
+ "tag": "alpha"
8
+ },
5
9
  "keywords": [
10
+ "utilities",
11
+ "store",
6
12
  "state",
7
- "manager",
8
- "management",
9
13
  "react",
10
14
  "hooks",
11
- "store",
12
- "utilities",
13
15
  "query"
14
16
  ],
15
17
  "author": "Muhammad Afifudin",
@@ -24,59 +26,62 @@
24
26
  "homepage": "https://github.com/afiiif/floppy-disk#readme",
25
27
  "sideEffects": false,
26
28
  "files": [
27
- "lib/",
28
- "esm/",
29
- "utils/"
29
+ "**"
30
30
  ],
31
- "main": "./lib/index.js",
32
- "module": "./esm/index.js",
33
- "types": "./lib/index.d.ts",
31
+ "main": "./index.js",
32
+ "types": "./index.d.ts",
33
+ "typesVersions": {
34
+ ">=4.5": {
35
+ "esm/*": [
36
+ "esm/*"
37
+ ],
38
+ "*": [
39
+ "*"
40
+ ]
41
+ },
42
+ "*": {
43
+ "esm/*": [
44
+ "ts_version_4.5_and_above_is_required.d.ts"
45
+ ],
46
+ "*": [
47
+ "ts_version_4.5_and_above_is_required.d.ts"
48
+ ]
49
+ }
50
+ },
34
51
  "exports": {
35
52
  "./package.json": "./package.json",
36
53
  ".": {
37
54
  "import": {
38
- "types": "./esm/index.d.ts",
39
- "default": "./esm/index.js"
40
- },
41
- "module": {
42
- "types": "./esm/index.d.ts",
43
- "default": "./esm/index.js"
55
+ "types": "./esm/index.d.mts",
56
+ "default": "./esm/index.mjs"
44
57
  },
45
58
  "default": {
46
- "types": "./lib/index.d.ts",
47
- "default": "./lib/index.js"
59
+ "types": "./index.d.ts",
60
+ "default": "./index.js"
48
61
  }
49
62
  },
50
- "./utils": {
63
+ "./*": {
51
64
  "import": {
52
- "types": "./esm/utils.d.ts",
53
- "default": "./esm/utils.js"
54
- },
55
- "module": {
56
- "types": "./esm/utils.d.ts",
57
- "default": "./esm/utils.js"
65
+ "types": "./esm/*.d.mts",
66
+ "default": "./esm/*.mjs"
58
67
  },
59
68
  "default": {
60
- "types": "./lib/utils.d.ts",
61
- "default": "./lib/utils.js"
69
+ "types": "./*.d.ts",
70
+ "default": "./*.js"
62
71
  }
63
72
  }
64
73
  },
65
- "release": {
66
- "branches": [
67
- "main",
68
- {
69
- "name": "beta",
70
- "prerelease": true
71
- },
72
- {
73
- "name": "alpha",
74
- "prerelease": true
75
- },
76
- {
77
- "name": "experimental",
78
- "prerelease": true
79
- }
80
- ]
74
+ "packageManager": "pnpm@10.32.1",
75
+ "peerDependencies": {
76
+ "@types/react": ">=17.0",
77
+ "react": ">=17.0"
78
+ },
79
+ "peerDependenciesMeta": {
80
+ "@types/react": {
81
+ "optional": true
82
+ },
83
+ "react": {
84
+ "optional": true
85
+ }
81
86
  }
82
87
  }
@@ -0,0 +1,135 @@
1
+ import { type InitStoreOptions, type SetState } from 'floppy-disk/vanilla';
2
+ /**
3
+ * Represents the state of a mutation.
4
+ *
5
+ * @remarks
6
+ * A mutation does not cache results and only tracks the latest execution.
7
+ *
8
+ * The state transitions are:
9
+ * - `INITIAL` → before any execution
10
+ * - `SUCCESS` → when mutation resolves successfully
11
+ * - `ERROR` → when mutation fails
12
+ *
13
+ * Unlike queries:
14
+ * - No retry mechanism
15
+ * - No caching across executions
16
+ */
17
+ export type MutationState<TData, TVariable> = {
18
+ isPending: boolean;
19
+ } & ({
20
+ state: 'INITIAL';
21
+ isSuccess: false;
22
+ isError: false;
23
+ variable: undefined;
24
+ data: undefined;
25
+ dataUpdatedAt: undefined;
26
+ error: undefined;
27
+ errorUpdatedAt: undefined;
28
+ } | {
29
+ state: 'SUCCESS';
30
+ isSuccess: true;
31
+ isError: false;
32
+ variable: TVariable;
33
+ data: TData;
34
+ dataUpdatedAt: number;
35
+ error: undefined;
36
+ errorUpdatedAt: undefined;
37
+ } | {
38
+ state: 'ERROR';
39
+ isSuccess: false;
40
+ isError: true;
41
+ variable: TVariable;
42
+ data: undefined;
43
+ dataUpdatedAt: undefined;
44
+ error: any;
45
+ errorUpdatedAt: number;
46
+ });
47
+ /**
48
+ * Configuration options for a mutation.
49
+ *
50
+ * @remarks
51
+ * Lifecycle callbacks are triggered for each execution.
52
+ */
53
+ export type MutationOptions<TData, TVariable> = InitStoreOptions<MutationState<TData, TVariable>> & {
54
+ /**
55
+ * Called when the mutation succeeds.
56
+ */
57
+ onSuccess?: (data: TData, variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable>) => void;
58
+ /**
59
+ * Called when the mutation fails.
60
+ */
61
+ onError?: (error: any, variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable>) => void;
62
+ /**
63
+ * Called after the mutation settles (either success or error).
64
+ */
65
+ onSettled?: (variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable>) => void;
66
+ };
67
+ /**
68
+ * Creates a mutation store for handling async operations that modify data.
69
+ *
70
+ * @param mutationFn - Async function that performs the mutation
71
+ * @param options - Optional configuration and lifecycle callbacks
72
+ *
73
+ * @returns A function that acts as both:
74
+ * - A React hook for subscribing to mutation state
75
+ * - A mutation controller (execute, reset, etc.)
76
+ *
77
+ * @remarks
78
+ * - Mutations are **not cached** and only track the latest execution.
79
+ * - Designed for operations that change data (e.g. create, update, delete).
80
+ * - No retry mechanism is provided by default.
81
+ * - Each execution overwrites the previous state.
82
+ * - The mutation always resolves (never throws): the result contains either `data` or `error`.
83
+ *
84
+ * @example
85
+ * const useCreateUser = createMutation(async (input) => {
86
+ * return api.createUser(input);
87
+ * });
88
+ *
89
+ * const { isPending } = useCreateUser();
90
+ * const result = await useCreateUser.execute({ name: 'John' });
91
+ */
92
+ export declare const createMutation: <TData, TVariable = undefined>(mutationFn: (variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable>) => Promise<TData>, options?: MutationOptions<TData, TVariable>) => (<TStateSlice = MutationState<TData, TVariable>>(selector?: (state: MutationState<TData, TVariable>) => TStateSlice) => TStateSlice) & {
93
+ subscribe: (subscriber: import("../vanilla.ts").Subscriber<MutationState<TData, TVariable>>) => () => void;
94
+ getSubscribers: () => Set<import("../vanilla.ts").Subscriber<MutationState<TData, TVariable>>>;
95
+ getState: () => MutationState<TData, TVariable>;
96
+ /**
97
+ * Manually updates the mutation state.
98
+ *
99
+ * @remarks
100
+ * - Intended for advanced use cases.
101
+ * - Prefer using provided mutation actions (`execute`, `reset`) instead.
102
+ */
103
+ setState: (value: SetState<MutationState<TData, TVariable>>) => void;
104
+ /**
105
+ * Executes the mutation.
106
+ *
107
+ * @param variable - Input passed to the mutation function
108
+ *
109
+ * @returns A promise that always resolves with:
110
+ * - `{ data, variable }` on success
111
+ * - `{ error, variable }` on failure
112
+ *
113
+ * @remarks
114
+ * - If a mutation is already in progress, a warning is logged.
115
+ * - Concurrent executions are allowed but may lead to race conditions.
116
+ * - The promise never rejects to simplify async handling.
117
+ */
118
+ execute: TVariable extends undefined ? () => Promise<{
119
+ variable: undefined;
120
+ data?: TData;
121
+ error?: any;
122
+ }> : (variable: TVariable) => Promise<{
123
+ variable: TVariable;
124
+ data?: TData;
125
+ error?: any;
126
+ }>;
127
+ /**
128
+ * Resets the mutation state back to its initial state.
129
+ *
130
+ * @remarks
131
+ * - Does not cancel any ongoing request.
132
+ * - If a request is still pending, its result may override the reset state.
133
+ */
134
+ reset: () => void;
135
+ };