@apvee/spfx-react-toolkit 1.0.0

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 (220) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2012 -0
  3. package/lib/core/atoms.internal.d.ts +53 -0
  4. package/lib/core/atoms.internal.d.ts.map +1 -0
  5. package/lib/core/atoms.internal.js +35 -0
  6. package/lib/core/atoms.internal.js.map +1 -0
  7. package/lib/core/context.internal.d.ts +23 -0
  8. package/lib/core/context.internal.d.ts.map +1 -0
  9. package/lib/core/context.internal.js +34 -0
  10. package/lib/core/context.internal.js.map +1 -0
  11. package/lib/core/index.d.ts +6 -0
  12. package/lib/core/index.d.ts.map +1 -0
  13. package/lib/core/index.js +6 -0
  14. package/lib/core/index.js.map +1 -0
  15. package/lib/core/provider-application-customizer.d.ts +57 -0
  16. package/lib/core/provider-application-customizer.d.ts.map +1 -0
  17. package/lib/core/provider-application-customizer.js +45 -0
  18. package/lib/core/provider-application-customizer.js.map +1 -0
  19. package/lib/core/provider-base.internal.d.ts +20 -0
  20. package/lib/core/provider-base.internal.d.ts.map +1 -0
  21. package/lib/core/provider-base.internal.js +126 -0
  22. package/lib/core/provider-base.internal.js.map +1 -0
  23. package/lib/core/provider-field-customizer.d.ts +58 -0
  24. package/lib/core/provider-field-customizer.d.ts.map +1 -0
  25. package/lib/core/provider-field-customizer.js +46 -0
  26. package/lib/core/provider-field-customizer.js.map +1 -0
  27. package/lib/core/provider-listview-commandset.d.ts +60 -0
  28. package/lib/core/provider-listview-commandset.d.ts.map +1 -0
  29. package/lib/core/provider-listview-commandset.js +48 -0
  30. package/lib/core/provider-listview-commandset.js.map +1 -0
  31. package/lib/core/provider-webpart.d.ts +48 -0
  32. package/lib/core/provider-webpart.d.ts.map +1 -0
  33. package/lib/core/provider-webpart.js +36 -0
  34. package/lib/core/provider-webpart.js.map +1 -0
  35. package/lib/core/types.d.ts +84 -0
  36. package/lib/core/types.d.ts.map +1 -0
  37. package/lib/core/types.js +4 -0
  38. package/lib/core/types.js.map +1 -0
  39. package/lib/hooks/index.d.ts +34 -0
  40. package/lib/hooks/index.d.ts.map +1 -0
  41. package/lib/hooks/index.js +34 -0
  42. package/lib/hooks/index.js.map +1 -0
  43. package/lib/hooks/useSPFxAadHttpClient.d.ts +231 -0
  44. package/lib/hooks/useSPFxAadHttpClient.d.ts.map +1 -0
  45. package/lib/hooks/useSPFxAadHttpClient.js +299 -0
  46. package/lib/hooks/useSPFxAadHttpClient.js.map +1 -0
  47. package/lib/hooks/useSPFxContainerInfo.d.ts +41 -0
  48. package/lib/hooks/useSPFxContainerInfo.d.ts.map +1 -0
  49. package/lib/hooks/useSPFxContainerInfo.js +47 -0
  50. package/lib/hooks/useSPFxContainerInfo.js.map +1 -0
  51. package/lib/hooks/useSPFxContainerSize.d.ts +119 -0
  52. package/lib/hooks/useSPFxContainerSize.d.ts.map +1 -0
  53. package/lib/hooks/useSPFxContainerSize.js +150 -0
  54. package/lib/hooks/useSPFxContainerSize.js.map +1 -0
  55. package/lib/hooks/useSPFxContext.d.ts +14 -0
  56. package/lib/hooks/useSPFxContext.d.ts.map +1 -0
  57. package/lib/hooks/useSPFxContext.js +16 -0
  58. package/lib/hooks/useSPFxContext.js.map +1 -0
  59. package/lib/hooks/useSPFxCorrelationInfo.d.ts +51 -0
  60. package/lib/hooks/useSPFxCorrelationInfo.d.ts.map +1 -0
  61. package/lib/hooks/useSPFxCorrelationInfo.js +58 -0
  62. package/lib/hooks/useSPFxCorrelationInfo.js.map +1 -0
  63. package/lib/hooks/useSPFxCrossSitePermissions.d.ts +81 -0
  64. package/lib/hooks/useSPFxCrossSitePermissions.d.ts.map +1 -0
  65. package/lib/hooks/useSPFxCrossSitePermissions.js +132 -0
  66. package/lib/hooks/useSPFxCrossSitePermissions.js.map +1 -0
  67. package/lib/hooks/useSPFxDisplayMode.d.ts +61 -0
  68. package/lib/hooks/useSPFxDisplayMode.d.ts.map +1 -0
  69. package/lib/hooks/useSPFxDisplayMode.js +69 -0
  70. package/lib/hooks/useSPFxDisplayMode.js.map +1 -0
  71. package/lib/hooks/useSPFxEnvironmentInfo.d.ts +63 -0
  72. package/lib/hooks/useSPFxEnvironmentInfo.d.ts.map +1 -0
  73. package/lib/hooks/useSPFxEnvironmentInfo.js +91 -0
  74. package/lib/hooks/useSPFxEnvironmentInfo.js.map +1 -0
  75. package/lib/hooks/useSPFxFluent9ThemeInfo.d.ts +105 -0
  76. package/lib/hooks/useSPFxFluent9ThemeInfo.d.ts.map +1 -0
  77. package/lib/hooks/useSPFxFluent9ThemeInfo.js +136 -0
  78. package/lib/hooks/useSPFxFluent9ThemeInfo.js.map +1 -0
  79. package/lib/hooks/useSPFxHubSiteInfo.d.ts +80 -0
  80. package/lib/hooks/useSPFxHubSiteInfo.d.ts.map +1 -0
  81. package/lib/hooks/useSPFxHubSiteInfo.js +127 -0
  82. package/lib/hooks/useSPFxHubSiteInfo.js.map +1 -0
  83. package/lib/hooks/useSPFxInstanceInfo.d.ts +41 -0
  84. package/lib/hooks/useSPFxInstanceInfo.d.ts.map +1 -0
  85. package/lib/hooks/useSPFxInstanceInfo.js +40 -0
  86. package/lib/hooks/useSPFxInstanceInfo.js.map +1 -0
  87. package/lib/hooks/useSPFxListInfo.d.ts +64 -0
  88. package/lib/hooks/useSPFxListInfo.d.ts.map +1 -0
  89. package/lib/hooks/useSPFxListInfo.js +70 -0
  90. package/lib/hooks/useSPFxListInfo.js.map +1 -0
  91. package/lib/hooks/useSPFxLocaleInfo.d.ts +123 -0
  92. package/lib/hooks/useSPFxLocaleInfo.d.ts.map +1 -0
  93. package/lib/hooks/useSPFxLocaleInfo.js +109 -0
  94. package/lib/hooks/useSPFxLocaleInfo.js.map +1 -0
  95. package/lib/hooks/useSPFxLogger.d.ts +108 -0
  96. package/lib/hooks/useSPFxLogger.d.ts.map +1 -0
  97. package/lib/hooks/useSPFxLogger.js +117 -0
  98. package/lib/hooks/useSPFxLogger.js.map +1 -0
  99. package/lib/hooks/useSPFxMSGraphClient.d.ts +200 -0
  100. package/lib/hooks/useSPFxMSGraphClient.d.ts.map +1 -0
  101. package/lib/hooks/useSPFxMSGraphClient.js +264 -0
  102. package/lib/hooks/useSPFxMSGraphClient.js.map +1 -0
  103. package/lib/hooks/useSPFxOneDriveAppData.d.ts +264 -0
  104. package/lib/hooks/useSPFxOneDriveAppData.d.ts.map +1 -0
  105. package/lib/hooks/useSPFxOneDriveAppData.js +395 -0
  106. package/lib/hooks/useSPFxOneDriveAppData.js.map +1 -0
  107. package/lib/hooks/useSPFxPageContext.d.ts +37 -0
  108. package/lib/hooks/useSPFxPageContext.d.ts.map +1 -0
  109. package/lib/hooks/useSPFxPageContext.js +49 -0
  110. package/lib/hooks/useSPFxPageContext.js.map +1 -0
  111. package/lib/hooks/useSPFxPageType.d.ts +82 -0
  112. package/lib/hooks/useSPFxPageType.d.ts.map +1 -0
  113. package/lib/hooks/useSPFxPageType.js +137 -0
  114. package/lib/hooks/useSPFxPageType.js.map +1 -0
  115. package/lib/hooks/useSPFxPerformance.d.ts +72 -0
  116. package/lib/hooks/useSPFxPerformance.d.ts.map +1 -0
  117. package/lib/hooks/useSPFxPerformance.js +167 -0
  118. package/lib/hooks/useSPFxPerformance.js.map +1 -0
  119. package/lib/hooks/useSPFxPermissions.d.ts +61 -0
  120. package/lib/hooks/useSPFxPermissions.d.ts.map +1 -0
  121. package/lib/hooks/useSPFxPermissions.js +73 -0
  122. package/lib/hooks/useSPFxPermissions.js.map +1 -0
  123. package/lib/hooks/useSPFxPnP.d.ts +539 -0
  124. package/lib/hooks/useSPFxPnP.d.ts.map +1 -0
  125. package/lib/hooks/useSPFxPnP.js +533 -0
  126. package/lib/hooks/useSPFxPnP.js.map +1 -0
  127. package/lib/hooks/useSPFxPnPContext.d.ts +290 -0
  128. package/lib/hooks/useSPFxPnPContext.d.ts.map +1 -0
  129. package/lib/hooks/useSPFxPnPContext.js +340 -0
  130. package/lib/hooks/useSPFxPnPContext.js.map +1 -0
  131. package/lib/hooks/useSPFxPnPList.d.ts +545 -0
  132. package/lib/hooks/useSPFxPnPList.d.ts.map +1 -0
  133. package/lib/hooks/useSPFxPnPList.js +906 -0
  134. package/lib/hooks/useSPFxPnPList.js.map +1 -0
  135. package/lib/hooks/useSPFxPnPSearch.d.ts +540 -0
  136. package/lib/hooks/useSPFxPnPSearch.d.ts.map +1 -0
  137. package/lib/hooks/useSPFxPnPSearch.js +672 -0
  138. package/lib/hooks/useSPFxPnPSearch.js.map +1 -0
  139. package/lib/hooks/useSPFxProperties.d.ts +80 -0
  140. package/lib/hooks/useSPFxProperties.d.ts.map +1 -0
  141. package/lib/hooks/useSPFxProperties.js +95 -0
  142. package/lib/hooks/useSPFxProperties.js.map +1 -0
  143. package/lib/hooks/useSPFxSPHttpClient.d.ts +218 -0
  144. package/lib/hooks/useSPFxSPHttpClient.d.ts.map +1 -0
  145. package/lib/hooks/useSPFxSPHttpClient.js +287 -0
  146. package/lib/hooks/useSPFxSPHttpClient.js.map +1 -0
  147. package/lib/hooks/useSPFxServiceScope.d.ts +107 -0
  148. package/lib/hooks/useSPFxServiceScope.d.ts.map +1 -0
  149. package/lib/hooks/useSPFxServiceScope.js +105 -0
  150. package/lib/hooks/useSPFxServiceScope.js.map +1 -0
  151. package/lib/hooks/useSPFxSiteInfo.d.ts +116 -0
  152. package/lib/hooks/useSPFxSiteInfo.d.ts.map +1 -0
  153. package/lib/hooks/useSPFxSiteInfo.js +109 -0
  154. package/lib/hooks/useSPFxSiteInfo.js.map +1 -0
  155. package/lib/hooks/useSPFxStorage.d.ts +81 -0
  156. package/lib/hooks/useSPFxStorage.d.ts.map +1 -0
  157. package/lib/hooks/useSPFxStorage.js +140 -0
  158. package/lib/hooks/useSPFxStorage.js.map +1 -0
  159. package/lib/hooks/useSPFxTeams.d.ts +63 -0
  160. package/lib/hooks/useSPFxTeams.d.ts.map +1 -0
  161. package/lib/hooks/useSPFxTeams.js +198 -0
  162. package/lib/hooks/useSPFxTeams.js.map +1 -0
  163. package/lib/hooks/useSPFxTenantProperty.d.ts +389 -0
  164. package/lib/hooks/useSPFxTenantProperty.d.ts.map +1 -0
  165. package/lib/hooks/useSPFxTenantProperty.js +683 -0
  166. package/lib/hooks/useSPFxTenantProperty.js.map +1 -0
  167. package/lib/hooks/useSPFxThemeInfo.d.ts +27 -0
  168. package/lib/hooks/useSPFxThemeInfo.d.ts.map +1 -0
  169. package/lib/hooks/useSPFxThemeInfo.js +33 -0
  170. package/lib/hooks/useSPFxThemeInfo.js.map +1 -0
  171. package/lib/hooks/useSPFxUserInfo.d.ts +47 -0
  172. package/lib/hooks/useSPFxUserInfo.d.ts.map +1 -0
  173. package/lib/hooks/useSPFxUserInfo.js +47 -0
  174. package/lib/hooks/useSPFxUserInfo.js.map +1 -0
  175. package/lib/hooks/useSPFxUserPhoto.d.ts +270 -0
  176. package/lib/hooks/useSPFxUserPhoto.d.ts.map +1 -0
  177. package/lib/hooks/useSPFxUserPhoto.js +346 -0
  178. package/lib/hooks/useSPFxUserPhoto.js.map +1 -0
  179. package/lib/index.d.ts +3 -0
  180. package/lib/index.d.ts.map +1 -0
  181. package/lib/index.js +3 -0
  182. package/lib/index.js.map +1 -0
  183. package/lib/utils/index.d.ts +1 -0
  184. package/lib/utils/index.d.ts.map +1 -0
  185. package/lib/utils/index.js +3 -0
  186. package/lib/utils/index.js.map +1 -0
  187. package/lib/utils/resize-observer.internal.d.ts +10 -0
  188. package/lib/utils/resize-observer.internal.d.ts.map +1 -0
  189. package/lib/utils/resize-observer.internal.js +34 -0
  190. package/lib/utils/resize-observer.internal.js.map +1 -0
  191. package/lib/utils/theme-subscription.internal.d.ts +11 -0
  192. package/lib/utils/theme-subscription.internal.d.ts.map +1 -0
  193. package/lib/utils/theme-subscription.internal.js +58 -0
  194. package/lib/utils/theme-subscription.internal.js.map +1 -0
  195. package/lib/utils/type-guards.internal.d.ts +35 -0
  196. package/lib/utils/type-guards.internal.d.ts.map +1 -0
  197. package/lib/utils/type-guards.internal.js +88 -0
  198. package/lib/utils/type-guards.internal.js.map +1 -0
  199. package/lib/webparts/spFxReactToolkitTest/SpFxReactToolkitTestWebPart.d.ts +13 -0
  200. package/lib/webparts/spFxReactToolkitTest/SpFxReactToolkitTestWebPart.d.ts.map +1 -0
  201. package/lib/webparts/spFxReactToolkitTest/SpFxReactToolkitTestWebPart.js +67 -0
  202. package/lib/webparts/spFxReactToolkitTest/SpFxReactToolkitTestWebPart.js.map +1 -0
  203. package/lib/webparts/spFxReactToolkitTest/SpFxReactToolkitTestWebPart.manifest.json +21 -0
  204. package/lib/webparts/spFxReactToolkitTest/assets/welcome-dark.png +0 -0
  205. package/lib/webparts/spFxReactToolkitTest/assets/welcome-light.png +0 -0
  206. package/lib/webparts/spFxReactToolkitTest/components/ISpFxReactToolkitTestProps.d.ts +8 -0
  207. package/lib/webparts/spFxReactToolkitTest/components/ISpFxReactToolkitTestProps.d.ts.map +1 -0
  208. package/lib/webparts/spFxReactToolkitTest/components/ISpFxReactToolkitTestProps.js +2 -0
  209. package/lib/webparts/spFxReactToolkitTest/components/ISpFxReactToolkitTestProps.js.map +1 -0
  210. package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.d.ts +8 -0
  211. package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.d.ts.map +1 -0
  212. package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.js +1351 -0
  213. package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.js.map +1 -0
  214. package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.module.css +2 -0
  215. package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.module.scss.d.ts +18 -0
  216. package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.module.scss.d.ts.map +1 -0
  217. package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.module.scss.js +19 -0
  218. package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.module.scss.js.map +1 -0
  219. package/lib/webparts/spFxReactToolkitTest/loc/en-us.js +16 -0
  220. package/package.json +95 -0
@@ -0,0 +1,264 @@
1
+ /**
2
+ * Return type for useSPFxOneDriveAppData hook
3
+ */
4
+ export interface SPFxOneDriveAppDataResult<T> {
5
+ /**
6
+ * The loaded data from OneDrive.
7
+ * Undefined if not loaded yet or on error.
8
+ */
9
+ readonly data: T | undefined;
10
+ /**
11
+ * Loading state for read operations.
12
+ * True during initial load or manual load() calls.
13
+ */
14
+ readonly isLoading: boolean;
15
+ /**
16
+ * Last error from read operations.
17
+ * Cleared on successful load or write.
18
+ */
19
+ readonly error: Error | undefined;
20
+ /**
21
+ * Loading state for write operations.
22
+ * True during write() calls.
23
+ */
24
+ readonly isWriting: boolean;
25
+ /**
26
+ * Last error from write operations.
27
+ * Cleared on successful write or load.
28
+ */
29
+ readonly writeError: Error | undefined;
30
+ /**
31
+ * Manually load/reload the file from OneDrive.
32
+ * Updates data, isLoading, and error states.
33
+ *
34
+ * @returns Promise that resolves when load completes
35
+ *
36
+ * @example
37
+ * ```tsx
38
+ * const { data, load } = useSPFxOneDriveAppData<Config>('config.json', undefined, false);
39
+ *
40
+ * // Load on button click
41
+ * <button onClick={load}>Refresh</button>
42
+ * ```
43
+ */
44
+ readonly load: () => Promise<void>;
45
+ /**
46
+ * Write data to OneDrive file.
47
+ * Creates file if it doesn't exist, updates if it does.
48
+ * Updates isWriting and writeError states.
49
+ *
50
+ * @param content - Data to write (will be JSON.stringify'd)
51
+ * @returns Promise that resolves when write completes
52
+ *
53
+ * @example
54
+ * ```tsx
55
+ * const { write, isWriting } = useSPFxOneDriveAppData<Config>('config.json');
56
+ *
57
+ * const handleSave = async () => {
58
+ * await write({ theme: 'dark', language: 'en' });
59
+ * };
60
+ * ```
61
+ */
62
+ readonly write: (content: T) => Promise<void>;
63
+ /**
64
+ * Computed state: true if data is loaded successfully.
65
+ * Equivalent to: !isLoading && !error && data !== undefined
66
+ *
67
+ * Useful for conditional rendering:
68
+ * ```tsx
69
+ * if (!isReady) return <Spinner />;
70
+ * return <div>{data.title}</div>;
71
+ * ```
72
+ */
73
+ readonly isReady: boolean;
74
+ }
75
+ /**
76
+ * Hook to manage JSON files in user's OneDrive appRoot folder
77
+ *
78
+ * Provides unified read/write operations for JSON data stored in OneDrive's special
79
+ * appRoot folder (accessible per-app, user-scoped storage).
80
+ *
81
+ * Features:
82
+ * - Automatic JSON serialization/deserialization
83
+ * - Separate loading states for read/write operations
84
+ * - Optional auto-fetch on mount
85
+ * - Folder/namespace support for file organization
86
+ * - Type-safe with TypeScript generics
87
+ * - Memory leak safe with mounted state tracking
88
+ * - Error handling for both read and write operations
89
+ *
90
+ * Requirements:
91
+ * - Microsoft Graph permissions: Files.ReadWrite or Files.ReadWrite.AppFolder
92
+ * - User must be authenticated
93
+ *
94
+ * @param fileName - Name of the JSON file (e.g., 'config.json', 'settings.json')
95
+ * @param folder - Optional folder/namespace identifier for file organization.
96
+ * Will be sanitized to prevent path traversal.
97
+ * Examples: 'my-app', instanceId (GUID), 'config-v2'
98
+ * @param autoFetch - Whether to automatically load file on mount. Default: true
99
+ *
100
+ * @returns Object with data, loading states, error states, and read/write functions
101
+ *
102
+ * @example Basic usage - auto-fetch from root
103
+ * ```tsx
104
+ * import type { MyConfig } from './types';
105
+ *
106
+ * function ConfigPanel() {
107
+ * const { data, isLoading, error, write, isWriting } =
108
+ * useSPFxOneDriveAppData<MyConfig>('config.json');
109
+ *
110
+ * if (isLoading) return <Spinner label="Loading configuration..." />;
111
+ * if (error) return <MessageBar messageBarType={MessageBarType.error}>
112
+ * Failed to load: {error.message}
113
+ * </MessageBar>;
114
+ *
115
+ * const handleSave = async (newConfig: MyConfig) => {
116
+ * try {
117
+ * await write(newConfig);
118
+ * console.log('Saved successfully!');
119
+ * } catch (err) {
120
+ * console.error('Save failed:', err);
121
+ * }
122
+ * };
123
+ *
124
+ * return (
125
+ * <div>
126
+ * <TextField
127
+ * value={data?.title}
128
+ * onChange={(_, val) => handleSave({ ...data, title: val })}
129
+ * disabled={isWriting}
130
+ * />
131
+ * {isWriting && <Spinner label="Saving..." />}
132
+ * </div>
133
+ * );
134
+ * }
135
+ * ```
136
+ *
137
+ * @example With folder namespace
138
+ * ```tsx
139
+ * // Store files in a dedicated folder
140
+ * const { data, write } = useSPFxOneDriveAppData<State>(
141
+ * 'state.json',
142
+ * 'my-app-v2' // Files stored in appRoot:/my-app-v2/state.json
143
+ * );
144
+ * ```
145
+ *
146
+ * @example Per-instance storage (multi-instance support)
147
+ * ```tsx
148
+ * // Each WebPart instance has its own data
149
+ * const { id } = useSPFxInstanceInfo();
150
+ * const { data, write } = useSPFxOneDriveAppData<Settings>(
151
+ * 'settings.json',
152
+ * id // Files stored in appRoot:/abc-123-guid/settings.json
153
+ * );
154
+ * ```
155
+ *
156
+ * @example Lazy loading (manual load)
157
+ * ```tsx
158
+ * const { data, load, isLoading, write } = useSPFxOneDriveAppData<Cache>(
159
+ * 'cache.json',
160
+ * 'my-app',
161
+ * false // Don't auto-fetch
162
+ * );
163
+ *
164
+ * return (
165
+ * <div>
166
+ * <button onClick={load} disabled={isLoading}>
167
+ * {isLoading ? 'Loading...' : 'Load Cache'}
168
+ * </button>
169
+ * {data && <pre>{JSON.stringify(data, null, 2)}</pre>}
170
+ * </div>
171
+ * );
172
+ * ```
173
+ *
174
+ * @example Multiple files in same namespace
175
+ * ```tsx
176
+ * function MyApp() {
177
+ * const config = useSPFxOneDriveAppData<Config>('config.json', 'myapp');
178
+ * const state = useSPFxOneDriveAppData<State>('state.json', 'myapp');
179
+ * const cache = useSPFxOneDriveAppData<Cache>('cache.json', 'myapp');
180
+ *
181
+ * // All files stored in appRoot:/myapp/
182
+ * // Easy to manage and clean up as a group
183
+ * }
184
+ * ```
185
+ *
186
+ * @example Error handling and retry
187
+ * ```tsx
188
+ * function DataManager() {
189
+ * const { data, error, load, writeError, write, isReady } =
190
+ * useSPFxOneDriveAppData<MyData>('data.json');
191
+ *
192
+ * if (error) {
193
+ * return (
194
+ * <MessageBar
195
+ * messageBarType={MessageBarType.error}
196
+ * actions={<button onClick={load}>Retry</button>}
197
+ * >
198
+ * Load failed: {error.message}
199
+ * </MessageBar>
200
+ * );
201
+ * }
202
+ *
203
+ * if (writeError) {
204
+ * return (
205
+ * <MessageBar messageBarType={MessageBarType.warning}>
206
+ * Save failed: {writeError.message}
207
+ * </MessageBar>
208
+ * );
209
+ * }
210
+ *
211
+ * if (!isReady) return <Spinner />;
212
+ *
213
+ * return <DataDisplay data={data} onSave={write} />;
214
+ * }
215
+ * ```
216
+ *
217
+ * @example CRUD-like operations
218
+ * ```tsx
219
+ * interface TodoList {
220
+ * items: Array<{ id: string; text: string; done: boolean }>;
221
+ * }
222
+ *
223
+ * function TodoApp() {
224
+ * const { data, write, isLoading, isWriting } =
225
+ * useSPFxOneDriveAppData<TodoList>('todos.json', 'todo-app');
226
+ *
227
+ * const addTodo = async (text: string) => {
228
+ * const newItem = { id: crypto.randomUUID(), text, done: false };
229
+ * await write({
230
+ * items: [...(data?.items ?? []), newItem]
231
+ * });
232
+ * };
233
+ *
234
+ * const toggleTodo = async (id: string) => {
235
+ * await write({
236
+ * items: data?.items.map(item =>
237
+ * item.id === id ? { ...item, done: !item.done } : item
238
+ * ) ?? []
239
+ * });
240
+ * };
241
+ *
242
+ * const deleteTodo = async (id: string) => {
243
+ * await write({
244
+ * items: data?.items.filter(item => item.id !== id) ?? []
245
+ * });
246
+ * };
247
+ *
248
+ * if (isLoading) return <Spinner />;
249
+ *
250
+ * return (
251
+ * <div>
252
+ * <TodoList
253
+ * items={data?.items ?? []}
254
+ * onToggle={toggleTodo}
255
+ * onDelete={deleteTodo}
256
+ * />
257
+ * <AddTodoForm onAdd={addTodo} disabled={isWriting} />
258
+ * </div>
259
+ * );
260
+ * }
261
+ * ```
262
+ */
263
+ export declare function useSPFxOneDriveAppData<T = unknown>(fileName: string, folder?: string, autoFetch?: boolean): SPFxOneDriveAppDataResult<T>;
264
+ //# sourceMappingURL=useSPFxOneDriveAppData.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSPFxOneDriveAppData.d.ts","sourceRoot":"","sources":["../../src/hooks/useSPFxOneDriveAppData.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,MAAM,WAAW,yBAAyB,CAAC,CAAC;IAC1C;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,SAAS,CAAC;IAE7B;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAE5B;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,CAAC;IAElC;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAE5B;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,KAAK,GAAG,SAAS,CAAC;IAEvC;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnC;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9C;;;;;;;;;OASG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2LG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,GAAG,OAAO,EAChD,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,MAAM,EACf,SAAS,GAAE,OAAc,GACxB,yBAAyB,CAAC,CAAC,CAAC,CA4J9B"}
@@ -0,0 +1,395 @@
1
+ // useSPFxOneDriveAppData.ts
2
+ // Hook to manage JSON files in OneDrive appRoot folder with state management
3
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
4
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5
+ return new (P || (P = Promise))(function (resolve, reject) {
6
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
7
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
8
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
9
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
10
+ });
11
+ };
12
+ var __generator = (this && this.__generator) || function (thisArg, body) {
13
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
14
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
15
+ function verb(n) { return function (v) { return step([n, v]); }; }
16
+ function step(op) {
17
+ if (f) throw new TypeError("Generator is already executing.");
18
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
19
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
20
+ if (y = 0, t) op = [op[0] & 2, t.value];
21
+ switch (op[0]) {
22
+ case 0: case 1: t = op; break;
23
+ case 4: _.label++; return { value: op[1], done: false };
24
+ case 5: _.label++; y = op[1]; op = [0]; continue;
25
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
26
+ default:
27
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
28
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
29
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
30
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
31
+ if (t[2]) _.ops.pop();
32
+ _.trys.pop(); continue;
33
+ }
34
+ op = body.call(thisArg, _);
35
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
36
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
37
+ }
38
+ };
39
+ import { useState, useCallback, useEffect, useRef } from 'react';
40
+ import { useSPFxMSGraphClient } from './useSPFxMSGraphClient';
41
+ /**
42
+ * Hook to manage JSON files in user's OneDrive appRoot folder
43
+ *
44
+ * Provides unified read/write operations for JSON data stored in OneDrive's special
45
+ * appRoot folder (accessible per-app, user-scoped storage).
46
+ *
47
+ * Features:
48
+ * - Automatic JSON serialization/deserialization
49
+ * - Separate loading states for read/write operations
50
+ * - Optional auto-fetch on mount
51
+ * - Folder/namespace support for file organization
52
+ * - Type-safe with TypeScript generics
53
+ * - Memory leak safe with mounted state tracking
54
+ * - Error handling for both read and write operations
55
+ *
56
+ * Requirements:
57
+ * - Microsoft Graph permissions: Files.ReadWrite or Files.ReadWrite.AppFolder
58
+ * - User must be authenticated
59
+ *
60
+ * @param fileName - Name of the JSON file (e.g., 'config.json', 'settings.json')
61
+ * @param folder - Optional folder/namespace identifier for file organization.
62
+ * Will be sanitized to prevent path traversal.
63
+ * Examples: 'my-app', instanceId (GUID), 'config-v2'
64
+ * @param autoFetch - Whether to automatically load file on mount. Default: true
65
+ *
66
+ * @returns Object with data, loading states, error states, and read/write functions
67
+ *
68
+ * @example Basic usage - auto-fetch from root
69
+ * ```tsx
70
+ * import type { MyConfig } from './types';
71
+ *
72
+ * function ConfigPanel() {
73
+ * const { data, isLoading, error, write, isWriting } =
74
+ * useSPFxOneDriveAppData<MyConfig>('config.json');
75
+ *
76
+ * if (isLoading) return <Spinner label="Loading configuration..." />;
77
+ * if (error) return <MessageBar messageBarType={MessageBarType.error}>
78
+ * Failed to load: {error.message}
79
+ * </MessageBar>;
80
+ *
81
+ * const handleSave = async (newConfig: MyConfig) => {
82
+ * try {
83
+ * await write(newConfig);
84
+ * console.log('Saved successfully!');
85
+ * } catch (err) {
86
+ * console.error('Save failed:', err);
87
+ * }
88
+ * };
89
+ *
90
+ * return (
91
+ * <div>
92
+ * <TextField
93
+ * value={data?.title}
94
+ * onChange={(_, val) => handleSave({ ...data, title: val })}
95
+ * disabled={isWriting}
96
+ * />
97
+ * {isWriting && <Spinner label="Saving..." />}
98
+ * </div>
99
+ * );
100
+ * }
101
+ * ```
102
+ *
103
+ * @example With folder namespace
104
+ * ```tsx
105
+ * // Store files in a dedicated folder
106
+ * const { data, write } = useSPFxOneDriveAppData<State>(
107
+ * 'state.json',
108
+ * 'my-app-v2' // Files stored in appRoot:/my-app-v2/state.json
109
+ * );
110
+ * ```
111
+ *
112
+ * @example Per-instance storage (multi-instance support)
113
+ * ```tsx
114
+ * // Each WebPart instance has its own data
115
+ * const { id } = useSPFxInstanceInfo();
116
+ * const { data, write } = useSPFxOneDriveAppData<Settings>(
117
+ * 'settings.json',
118
+ * id // Files stored in appRoot:/abc-123-guid/settings.json
119
+ * );
120
+ * ```
121
+ *
122
+ * @example Lazy loading (manual load)
123
+ * ```tsx
124
+ * const { data, load, isLoading, write } = useSPFxOneDriveAppData<Cache>(
125
+ * 'cache.json',
126
+ * 'my-app',
127
+ * false // Don't auto-fetch
128
+ * );
129
+ *
130
+ * return (
131
+ * <div>
132
+ * <button onClick={load} disabled={isLoading}>
133
+ * {isLoading ? 'Loading...' : 'Load Cache'}
134
+ * </button>
135
+ * {data && <pre>{JSON.stringify(data, null, 2)}</pre>}
136
+ * </div>
137
+ * );
138
+ * ```
139
+ *
140
+ * @example Multiple files in same namespace
141
+ * ```tsx
142
+ * function MyApp() {
143
+ * const config = useSPFxOneDriveAppData<Config>('config.json', 'myapp');
144
+ * const state = useSPFxOneDriveAppData<State>('state.json', 'myapp');
145
+ * const cache = useSPFxOneDriveAppData<Cache>('cache.json', 'myapp');
146
+ *
147
+ * // All files stored in appRoot:/myapp/
148
+ * // Easy to manage and clean up as a group
149
+ * }
150
+ * ```
151
+ *
152
+ * @example Error handling and retry
153
+ * ```tsx
154
+ * function DataManager() {
155
+ * const { data, error, load, writeError, write, isReady } =
156
+ * useSPFxOneDriveAppData<MyData>('data.json');
157
+ *
158
+ * if (error) {
159
+ * return (
160
+ * <MessageBar
161
+ * messageBarType={MessageBarType.error}
162
+ * actions={<button onClick={load}>Retry</button>}
163
+ * >
164
+ * Load failed: {error.message}
165
+ * </MessageBar>
166
+ * );
167
+ * }
168
+ *
169
+ * if (writeError) {
170
+ * return (
171
+ * <MessageBar messageBarType={MessageBarType.warning}>
172
+ * Save failed: {writeError.message}
173
+ * </MessageBar>
174
+ * );
175
+ * }
176
+ *
177
+ * if (!isReady) return <Spinner />;
178
+ *
179
+ * return <DataDisplay data={data} onSave={write} />;
180
+ * }
181
+ * ```
182
+ *
183
+ * @example CRUD-like operations
184
+ * ```tsx
185
+ * interface TodoList {
186
+ * items: Array<{ id: string; text: string; done: boolean }>;
187
+ * }
188
+ *
189
+ * function TodoApp() {
190
+ * const { data, write, isLoading, isWriting } =
191
+ * useSPFxOneDriveAppData<TodoList>('todos.json', 'todo-app');
192
+ *
193
+ * const addTodo = async (text: string) => {
194
+ * const newItem = { id: crypto.randomUUID(), text, done: false };
195
+ * await write({
196
+ * items: [...(data?.items ?? []), newItem]
197
+ * });
198
+ * };
199
+ *
200
+ * const toggleTodo = async (id: string) => {
201
+ * await write({
202
+ * items: data?.items.map(item =>
203
+ * item.id === id ? { ...item, done: !item.done } : item
204
+ * ) ?? []
205
+ * });
206
+ * };
207
+ *
208
+ * const deleteTodo = async (id: string) => {
209
+ * await write({
210
+ * items: data?.items.filter(item => item.id !== id) ?? []
211
+ * });
212
+ * };
213
+ *
214
+ * if (isLoading) return <Spinner />;
215
+ *
216
+ * return (
217
+ * <div>
218
+ * <TodoList
219
+ * items={data?.items ?? []}
220
+ * onToggle={toggleTodo}
221
+ * onDelete={deleteTodo}
222
+ * />
223
+ * <AddTodoForm onAdd={addTodo} disabled={isWriting} />
224
+ * </div>
225
+ * );
226
+ * }
227
+ * ```
228
+ */
229
+ export function useSPFxOneDriveAppData(fileName, folder, autoFetch) {
230
+ var _this = this;
231
+ if (autoFetch === void 0) { autoFetch = true; }
232
+ var client = useSPFxMSGraphClient().client;
233
+ // State management
234
+ var _a = useState(undefined), data = _a[0], setData = _a[1];
235
+ var _b = useState(false), isLoading = _b[0], setIsLoading = _b[1];
236
+ var _c = useState(undefined), error = _c[0], setError = _c[1];
237
+ var _d = useState(false), isWriting = _d[0], setIsWriting = _d[1];
238
+ var _e = useState(undefined), writeError = _e[0], setWriteError = _e[1];
239
+ // Track component mounted state to prevent memory leaks
240
+ var isMounted = useRef(true);
241
+ useEffect(function () {
242
+ isMounted.current = true;
243
+ return function () {
244
+ isMounted.current = false;
245
+ };
246
+ }, []);
247
+ /**
248
+ * Build Graph API path with optional folder namespace
249
+ * Sanitizes folder name to prevent path traversal attacks
250
+ */
251
+ var buildApiPath = useCallback(function (file, folderName) {
252
+ var basePath = '/me/drive/special/appRoot:';
253
+ if (folderName) {
254
+ // Sanitize folder name: only allow alphanumeric, hyphens, underscores
255
+ // This prevents path traversal (../) and other injection attacks
256
+ var safeFolderName = folderName.replace(/[^a-zA-Z0-9-_]/g, '-');
257
+ return "".concat(basePath, "/").concat(safeFolderName, "/").concat(file, ":/content");
258
+ }
259
+ return "".concat(basePath, "/").concat(file, ":/content");
260
+ }, []);
261
+ /**
262
+ * Load file from OneDrive
263
+ * Updates data, isLoading, and error states
264
+ */
265
+ var load = useCallback(function () { return __awaiter(_this, void 0, void 0, function () {
266
+ var apiPath, fileContent, err_1, error_1;
267
+ return __generator(this, function (_a) {
268
+ switch (_a.label) {
269
+ case 0:
270
+ if (!client) {
271
+ console.warn('Graph client not available yet. Skipping load.');
272
+ return [2 /*return*/];
273
+ }
274
+ if (!fileName) {
275
+ console.warn('fileName is required. Skipping load.');
276
+ return [2 /*return*/];
277
+ }
278
+ setIsLoading(true);
279
+ setError(undefined);
280
+ _a.label = 1;
281
+ case 1:
282
+ _a.trys.push([1, 3, 4, 5]);
283
+ apiPath = buildApiPath(fileName, folder);
284
+ return [4 /*yield*/, client.api(apiPath).get()];
285
+ case 2:
286
+ fileContent = _a.sent();
287
+ if (isMounted.current) {
288
+ // Parse JSON if response is string, otherwise use as-is
289
+ if (typeof fileContent === 'string') {
290
+ try {
291
+ setData(JSON.parse(fileContent));
292
+ }
293
+ catch (parseError) {
294
+ throw new Error("Failed to parse JSON: ".concat(parseError instanceof Error ? parseError.message : 'Unknown error'));
295
+ }
296
+ }
297
+ else {
298
+ setData(fileContent);
299
+ }
300
+ }
301
+ return [3 /*break*/, 5];
302
+ case 3:
303
+ err_1 = _a.sent();
304
+ if (isMounted.current) {
305
+ error_1 = err_1 instanceof Error ? err_1 : new Error(String(err_1));
306
+ setError(error_1);
307
+ // Don't throw - allow component to handle error via state
308
+ console.error('Failed to load file from OneDrive:', error_1);
309
+ }
310
+ return [3 /*break*/, 5];
311
+ case 4:
312
+ if (isMounted.current) {
313
+ setIsLoading(false);
314
+ }
315
+ return [7 /*endfinally*/];
316
+ case 5: return [2 /*return*/];
317
+ }
318
+ });
319
+ }); }, [client, fileName, folder, buildApiPath]);
320
+ /**
321
+ * Write data to OneDrive file
322
+ * Creates file if it doesn't exist, updates if it does (upsert)
323
+ * Updates isWriting and writeError states
324
+ */
325
+ var write = useCallback(function (content) { return __awaiter(_this, void 0, void 0, function () {
326
+ var apiPath, jsonContent, err_2, error_2;
327
+ return __generator(this, function (_a) {
328
+ switch (_a.label) {
329
+ case 0:
330
+ if (!client) {
331
+ throw new Error('Graph client not available. Cannot write file.');
332
+ }
333
+ if (!fileName) {
334
+ throw new Error('fileName is required. Cannot write file.');
335
+ }
336
+ setIsWriting(true);
337
+ setWriteError(undefined);
338
+ _a.label = 1;
339
+ case 1:
340
+ _a.trys.push([1, 3, 4, 5]);
341
+ apiPath = buildApiPath(fileName, folder);
342
+ jsonContent = JSON.stringify(content);
343
+ return [4 /*yield*/, client
344
+ .api(apiPath)
345
+ .header('Content-Type', 'application/json')
346
+ .put(jsonContent)];
347
+ case 2:
348
+ _a.sent();
349
+ if (isMounted.current) {
350
+ // Update local data to reflect successful write
351
+ setData(content);
352
+ // Clear read error if write succeeds (fresh state)
353
+ setError(undefined);
354
+ }
355
+ return [3 /*break*/, 5];
356
+ case 3:
357
+ err_2 = _a.sent();
358
+ if (isMounted.current) {
359
+ error_2 = err_2 instanceof Error ? err_2 : new Error(String(err_2));
360
+ setWriteError(error_2);
361
+ console.error('Failed to write file to OneDrive:', error_2);
362
+ }
363
+ // Re-throw to allow caller to handle
364
+ throw err_2;
365
+ case 4:
366
+ if (isMounted.current) {
367
+ setIsWriting(false);
368
+ }
369
+ return [7 /*endfinally*/];
370
+ case 5: return [2 /*return*/];
371
+ }
372
+ });
373
+ }); }, [client, fileName, folder, buildApiPath]);
374
+ // Auto-fetch on mount if enabled
375
+ useEffect(function () {
376
+ if (autoFetch && client && fileName) {
377
+ load().catch(function () {
378
+ // Error already handled in load() function
379
+ });
380
+ }
381
+ }, [autoFetch, client, fileName, load]);
382
+ // Computed state: ready when data loaded successfully
383
+ var isReady = !isLoading && !error && data !== undefined;
384
+ return {
385
+ data: data,
386
+ isLoading: isLoading,
387
+ error: error,
388
+ isWriting: isWriting,
389
+ writeError: writeError,
390
+ load: load,
391
+ write: write,
392
+ isReady: isReady,
393
+ };
394
+ }
395
+ //# sourceMappingURL=useSPFxOneDriveAppData.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSPFxOneDriveAppData.js","sourceRoot":"","sources":["../../src/hooks/useSPFxOneDriveAppData.ts"],"names":[],"mappings":"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"}