@lindle/sharepoint_requests 0.1.18 → 0.1.19

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 (47) hide show
  1. package/README.md +121 -116
  2. package/dist/index.d.ts +2 -2
  3. package/dist/root/index.d.ts +104 -29
  4. package/dist/root/internal/context.d.ts +2 -2
  5. package/dist/root/internal/digest.d.ts +1 -1
  6. package/dist/root/internal/emailRequests.d.ts +3 -3
  7. package/dist/root/internal/listRequests/createAttachment.d.ts +2 -2
  8. package/dist/root/internal/listRequests/createListItem.d.ts +2 -2
  9. package/dist/root/internal/listRequests/deleteFile.d.ts +2 -2
  10. package/dist/root/internal/listRequests/deleteItem.d.ts +2 -2
  11. package/dist/root/internal/listRequests/getFiles.d.ts +2 -2
  12. package/dist/root/internal/listRequests/getListItems.d.ts +3 -3
  13. package/dist/root/internal/listRequests/getOnly.d.ts +2 -2
  14. package/dist/root/internal/listRequests/normalizePayload.d.ts +1 -1
  15. package/dist/root/internal/listRequests/updateListItem.d.ts +2 -2
  16. package/dist/root/internal/listRequests/uploadFile.d.ts +3 -3
  17. package/dist/root/internal/odata.d.ts +1 -1
  18. package/dist/root/internal/sharepointUrl.d.ts +2 -0
  19. package/dist/root/internal/userRequests.d.ts +3 -3
  20. package/dist/sharepoint_requests.cjs.development.js +397 -225
  21. package/dist/sharepoint_requests.cjs.development.js.map +1 -1
  22. package/dist/sharepoint_requests.cjs.production.min.js +1 -1
  23. package/dist/sharepoint_requests.cjs.production.min.js.map +1 -1
  24. package/dist/sharepoint_requests.esm.js +397 -225
  25. package/dist/sharepoint_requests.esm.js.map +1 -1
  26. package/dist/types.d.ts +10 -6
  27. package/package.json +1 -1
  28. package/src/index.ts +3 -5
  29. package/src/root/index.ts +260 -145
  30. package/src/root/internal/context.ts +2 -2
  31. package/src/root/internal/digest.ts +4 -3
  32. package/src/root/internal/emailRequests.ts +4 -7
  33. package/src/root/internal/listRequests/createAttachment.ts +14 -3
  34. package/src/root/internal/listRequests/createListItem.ts +18 -12
  35. package/src/root/internal/listRequests/deleteFile.ts +4 -3
  36. package/src/root/internal/listRequests/deleteItem.ts +17 -3
  37. package/src/root/internal/listRequests/getFiles.ts +4 -10
  38. package/src/root/internal/listRequests/getListItems.ts +16 -9
  39. package/src/root/internal/listRequests/getOnly.ts +10 -7
  40. package/src/root/internal/listRequests/normalizePayload.ts +1 -1
  41. package/src/root/internal/listRequests/updateListItem.ts +24 -14
  42. package/src/root/internal/listRequests/uploadFile.ts +5 -8
  43. package/src/root/internal/listRequests/utils.ts +1 -1
  44. package/src/root/internal/odata.ts +2 -4
  45. package/src/root/internal/sharepointUrl.ts +7 -0
  46. package/src/root/internal/userRequests.ts +43 -11
  47. package/src/types.ts +152 -148
package/src/root/index.ts CHANGED
@@ -2,41 +2,58 @@ import { AxiosInstance, CreateAxiosDefaults as AxiosConfig } from 'axios';
2
2
  import instance from './instance';
3
3
  import {
4
4
  CreateFileProps,
5
- DeleteFileProps,
6
5
  CurrentUser,
6
+ DeleteFileProps,
7
7
  EmailProps,
8
8
  Field_Options,
9
9
  Folder_Options,
10
- UploadFileProps,
11
- IListName,
12
10
  ItemID,
13
11
  ListData,
14
12
  Options,
15
13
  PersonField,
16
14
  SHAREPOINT_VER,
15
+ UploadFileProps,
17
16
  UserPermision,
18
17
  UserProfile,
19
18
  } from '../types';
20
19
  import { RequestContext } from './internal/context';
20
+ import { sendEmail as sendEmailRequest } from './internal/emailRequests';
21
+ import { fetchDigest } from './internal/digest';
21
22
  import {
22
23
  createAttachment,
23
24
  createListItem,
24
- deleteItem,
25
25
  deleteFile as deleteLibraryFile,
26
+ deleteItem,
26
27
  getFiles,
27
28
  getListItems,
28
29
  getOnly,
29
30
  updateListItem,
30
31
  uploadFile,
31
32
  } from './internal/listRequests';
32
- import { sendEmail as sendEmailRequest } from './internal/emailRequests';
33
+ import {
34
+ buildListByTitleEndpoint,
35
+ escapeODataStringLiteral,
36
+ } from './internal/sharepointUrl';
33
37
  import {
34
38
  currentUserPermissions as resolveCurrentUserPermissions,
35
39
  currentUserProperties as loadCurrentUserProperties,
36
40
  getSiteUser as fetchSiteUser,
37
41
  typeAhead,
38
42
  } from './internal/userRequests';
39
- import { fetchDigest } from './internal/digest';
43
+
44
+ type ListKey<T extends { LISTS: Record<string, unknown> }> = Extract<
45
+ keyof T['LISTS'],
46
+ string
47
+ >;
48
+
49
+ type EmailApi = ((
50
+ from: string,
51
+ to: string[] | string,
52
+ subject: string | undefined,
53
+ body: string
54
+ ) => ReturnType<typeof sendEmailRequest>) & {
55
+ send: (props: EmailProps) => ReturnType<typeof sendEmailRequest>;
56
+ };
40
57
 
41
58
  class HTTPSharePointRequests<
42
59
  T extends {
@@ -44,52 +61,70 @@ class HTTPSharePointRequests<
44
61
  FOLDERS?: Record<string, unknown>;
45
62
  }
46
63
  > {
47
- private baseURL: string;
48
- private endpoint: string;
49
- private listName: string;
50
- private instance: AxiosInstance;
51
- private sharepointVersion: SHAREPOINT_VER;
52
- private listItemEntityTypeFullName?: string;
64
+ private readonly baseURL: string;
65
+ private readonly instance: AxiosInstance;
66
+ private readonly listItemEntityTypeCache: Map<string, string>;
67
+ public readonly email: EmailApi;
53
68
 
54
69
  constructor(baseURL: string, config?: AxiosConfig) {
55
70
  this.baseURL = baseURL.endsWith('/') ? baseURL : `${baseURL}/`;
56
- this.endpoint = '/api';
57
- this.listName = '';
58
71
  this.instance = instance(this.baseURL, config);
59
- this.sharepointVersion = '2013';
60
- this.listItemEntityTypeFullName = undefined;
72
+ this.listItemEntityTypeCache = new Map<string, string>();
73
+ this.email = Object.assign(
74
+ (
75
+ from: string,
76
+ to: string[] | string,
77
+ subject: string | undefined,
78
+ body: string
79
+ ) => {
80
+ return this.sendEmail({
81
+ From: from,
82
+ To: to,
83
+ Subject: subject,
84
+ Body: body,
85
+ });
86
+ },
87
+ {
88
+ send: (props: EmailProps) => this.sendEmail(props),
89
+ }
90
+ );
61
91
  }
62
92
 
63
- private getContext<V extends SHAREPOINT_VER = '2013'>(): RequestContext<V> {
93
+ private createContext<V extends SHAREPOINT_VER = '2013'>({
94
+ endpoint,
95
+ listName,
96
+ sharepointVersion,
97
+ listItemEntityTypeFullName,
98
+ resolveListItemEntityType,
99
+ }: {
100
+ endpoint: string;
101
+ listName: string;
102
+ sharepointVersion: V;
103
+ listItemEntityTypeFullName?: string;
104
+ resolveListItemEntityType?: () => Promise<string>;
105
+ }): RequestContext<V> {
64
106
  return {
65
107
  instance: this.instance,
66
108
  baseURL: this.baseURL,
67
- endpoint: this.endpoint,
68
- listName: this.listName,
69
- sharepointVersion: this.sharepointVersion as V,
70
- listItemEntityTypeFullName: this.listItemEntityTypeFullName,
71
- resolveListItemEntityType: this.resolveListItemEntityTypeFullName.bind(
72
- this
73
- ),
109
+ endpoint,
110
+ listName,
111
+ sharepointVersion,
112
+ listItemEntityTypeFullName,
113
+ resolveListItemEntityType,
74
114
  };
75
115
  }
76
116
 
77
- private async resolveListItemEntityTypeFullName(): Promise<string> {
78
- if (this.listItemEntityTypeFullName) {
79
- return this.listItemEntityTypeFullName;
80
- }
81
-
82
- if (!this.listName) {
83
- throw new Error('List name is not set.');
84
- }
85
-
86
- if (this.sharepointVersion !== '2013') {
87
- this.listItemEntityTypeFullName = `SP.Data.${this.listName}ListItem`;
88
- return this.listItemEntityTypeFullName;
117
+ private async resolveListItemEntityTypeFullName(
118
+ listName: string
119
+ ): Promise<string> {
120
+ const cacheKey = listName;
121
+ const cachedType = this.listItemEntityTypeCache.get(cacheKey);
122
+ if (cachedType) {
123
+ return cachedType;
89
124
  }
90
125
 
91
126
  const response = await this.instance.get(
92
- `_api/web/lists/GetByTitle('${this.listName}')?$select=ListItemEntityTypeFullName`
127
+ `${buildListByTitleEndpoint(listName)}?$select=ListItemEntityTypeFullName`
93
128
  );
94
129
 
95
130
  const entityType =
@@ -98,161 +133,241 @@ class HTTPSharePointRequests<
98
133
 
99
134
  if (!entityType || typeof entityType !== 'string') {
100
135
  throw new Error(
101
- `Unable to resolve ListItemEntityTypeFullName for list "${this.listName}".`
136
+ `Unable to resolve ListItemEntityTypeFullName for list "${listName}".`
102
137
  );
103
138
  }
104
139
 
105
- this.listItemEntityTypeFullName = entityType;
106
- return this.listItemEntityTypeFullName;
140
+ this.listItemEntityTypeCache.set(cacheKey, entityType);
141
+ return entityType;
107
142
  }
108
143
 
109
- /**
110
- * @deprecated Use `from` instead.
111
- */
112
- list(listName: IListName<T>) {
113
- this.listName = listName;
114
- this.endpoint = `_vti_bin/ListData.svc/${listName}`;
115
- this.sharepointVersion = '2010';
116
- this.listItemEntityTypeFullName = undefined;
117
- return this;
118
- }
144
+ private buildListScope<
145
+ K extends ListKey<T>,
146
+ V extends SHAREPOINT_VER = '2013'
147
+ >(listName: K, version: V) {
148
+ const listNameValue = String(listName);
149
+ const endpoint =
150
+ version === '2013'
151
+ ? `${buildListByTitleEndpoint(listNameValue)}/items`
152
+ : `_vti_bin/ListData.svc/${encodeURIComponent(listNameValue)}`;
119
153
 
120
- public readonly lists = {
121
- get: () => {
122
- this.endpoint = '_api/web/lists';
123
- this.sharepointVersion = '2013';
124
- return getListItems(this.getContext());
125
- },
126
- };
154
+ let scopedEntityType: string | undefined;
155
+ const resolveListItemEntityType = async () => {
156
+ if (scopedEntityType) {
157
+ return scopedEntityType;
158
+ }
127
159
 
128
- public getDigest() {
129
- return fetchDigest(this.instance, this.baseURL);
130
- }
160
+ if (version !== '2013') {
161
+ scopedEntityType = `SP.Data.${listNameValue}ListItem`;
162
+ return scopedEntityType;
163
+ }
131
164
 
132
- public from<
133
- K extends Extract<keyof T['LISTS'], string>,
134
- V extends SHAREPOINT_VER = '2013'
135
- >(listName: K, sharepoint_ver?: V) {
136
- const version = (sharepoint_ver ?? '2013') as V;
165
+ scopedEntityType = await this.resolveListItemEntityTypeFullName(
166
+ listNameValue
167
+ );
168
+ return scopedEntityType;
169
+ };
137
170
 
138
- this.listName = listName;
139
- this.sharepointVersion = version;
140
- this.listItemEntityTypeFullName = undefined;
141
- this.endpoint =
142
- version === '2013'
143
- ? `_api/web/lists/GetByTitle('${this.listName}')/items`
144
- : `_vti_bin/ListData.svc/${listName}`;
171
+ const getContext = () =>
172
+ this.createContext<V>({
173
+ endpoint,
174
+ listName: listNameValue,
175
+ sharepointVersion: version,
176
+ listItemEntityTypeFullName: scopedEntityType,
177
+ resolveListItemEntityType,
178
+ });
145
179
 
146
- const getContext = () => this.getContext<V>();
180
+ const removeItem = (id: ItemID) => deleteItem(getContext(), id);
181
+ const removeFile = (props: DeleteFileProps) =>
182
+ deleteLibraryFile(getContext(), props);
147
183
 
148
184
  return {
149
185
  create: (data: ListData<T['LISTS'][K]>) =>
150
186
  createListItem<T['LISTS'][K], V>(getContext(), data),
151
187
  get: (options?: Options<T['LISTS'][K], V>) =>
152
188
  getListItems<T['LISTS'][K], V>(getContext(), options),
153
- update: (
154
- id: ItemID,
155
- data: ListData<T['LISTS'][K]>,
156
- digest?: string
157
- ) => updateListItem<T['LISTS'][K], V>(getContext(), id, data, digest),
158
- delete: (id: ItemID) => deleteItem(getContext(), id),
189
+ update: (id: ItemID, data: ListData<T['LISTS'][K]>, digest?: string) =>
190
+ updateListItem<T['LISTS'][K], V>(getContext(), id, data, digest),
191
+ delete: removeItem,
192
+ remove: removeItem,
159
193
  createFile: (props: CreateFileProps) =>
160
194
  createAttachment(getContext(), props),
161
195
  uploadFile: (props: UploadFileProps) => uploadFile(getContext(), props),
162
- deleteFile: (props: DeleteFileProps) =>
163
- deleteLibraryFile(getContext(), props),
196
+ deleteFile: removeFile,
197
+ removeFile,
164
198
  fields: (options?: Field_Options<T['LISTS'][K], V>) => {
165
- this.endpoint = !options?.fieldName
166
- ? `_api/web/lists/GetByTitle('${this.listName}')/fields`
167
- : `_api/web/lists/GetByTitle('${this.listName}')/fields/getbytitle('${options.fieldName}')`;
199
+ const fieldsEndpoint = !options?.fieldName
200
+ ? `${buildListByTitleEndpoint(listNameValue)}/fields`
201
+ : `${buildListByTitleEndpoint(
202
+ listNameValue
203
+ )}/fields/getbytitle('${escapeODataStringLiteral(
204
+ String(options.fieldName)
205
+ )}')`;
168
206
  return {
169
207
  get: () =>
170
- getOnly<T['LISTS'][K], V>(this.instance, this.endpoint, options),
208
+ getOnly<T['LISTS'][K], V>(this.instance, fieldsEndpoint, options),
171
209
  };
172
210
  },
211
+ items: {
212
+ create: (data: ListData<T['LISTS'][K]>) =>
213
+ createListItem<T['LISTS'][K], V>(getContext(), data),
214
+ get: (options?: Options<T['LISTS'][K], V>) =>
215
+ getListItems<T['LISTS'][K], V>(getContext(), options),
216
+ update: (id: ItemID, data: ListData<T['LISTS'][K]>, digest?: string) =>
217
+ updateListItem<T['LISTS'][K], V>(getContext(), id, data, digest),
218
+ delete: removeItem,
219
+ remove: removeItem,
220
+ },
221
+ files: {
222
+ attach: (props: CreateFileProps) =>
223
+ createAttachment(getContext(), props),
224
+ upload: (props: UploadFileProps) => uploadFile(getContext(), props),
225
+ delete: removeFile,
226
+ remove: removeFile,
227
+ },
173
228
  };
174
229
  }
175
230
 
176
- public folders = {
177
- get: () => {
178
- this.endpoint = '_api/web/folders';
179
- this.sharepointVersion = '2013';
180
- getListItems(this.getContext());
181
- },
182
- };
231
+ /**
232
+ * @deprecated Use `from(listName, '2010')` instead.
233
+ */
234
+ list<K extends ListKey<T>>(listName: K) {
235
+ return this.from<K, '2010'>(listName, '2010');
236
+ }
183
237
 
184
- public folder(folderName?: string | string[]) {
185
- let filePath = ['Shared Documents'];
238
+ public from<K extends ListKey<T>, V extends SHAREPOINT_VER = '2013'>(
239
+ listName: K,
240
+ sharepointVersion?: V
241
+ ) {
242
+ const version = (sharepointVersion ?? '2013') as V;
243
+ return this.buildListScope<K, V>(listName, version);
244
+ }
186
245
 
187
- if (folderName) {
188
- filePath = Array.isArray(folderName)
189
- ? [...filePath, ...folderName]
190
- : [...filePath, folderName];
191
- }
246
+ public field<K extends ListKey<T>, V extends SHAREPOINT_VER = '2013'>(
247
+ listName: K,
248
+ fieldName?: Extract<keyof T['LISTS'][K], string>,
249
+ sharepointVersion?: V
250
+ ) {
251
+ return this.from<K, V>(listName, sharepointVersion)
252
+ .fields({
253
+ fieldName,
254
+ } as Field_Options<T['LISTS'][K], V>)
255
+ .get();
256
+ }
257
+
258
+ public lists(options?: Options<Record<string, unknown>, '2013'>) {
259
+ const context = this.createContext<'2013'>({
260
+ endpoint: '_api/web/lists',
261
+ listName: '',
262
+ sharepointVersion: '2013',
263
+ });
264
+
265
+ return {
266
+ get: () => getListItems(context, options),
267
+ };
268
+ }
192
269
 
193
- this.endpoint = `_api/web/GetFolderByServerRelativeUrl('${filePath.join(
194
- '/'
195
- )}')`;
196
- this.sharepointVersion = '2013';
270
+ public getDigest() {
271
+ return fetchDigest(this.instance, this.baseURL);
272
+ }
197
273
 
198
- const getContext = () => this.getContext();
274
+ public folders(options?: Folder_Options<Record<string, unknown>>) {
275
+ const context = this.createContext<'2013'>({
276
+ endpoint: '_api/web/folders',
277
+ listName: '',
278
+ sharepointVersion: '2013',
279
+ });
199
280
 
200
281
  return {
201
- get: (options?: Folder_Options<any>) => {
202
- if (!options?.type) {
203
- this.endpoint += '/Files';
204
- } else {
205
- this.endpoint += `/${options.type}`;
206
- }
207
- return getFiles(getContext(), options);
282
+ get: () => getFiles<Record<string, unknown>, '2013'>(context, options),
283
+ };
284
+ }
285
+
286
+ public folder(folderName?: string | string[]) {
287
+ const defaultPath = ['Shared Documents'];
288
+ const segments = folderName
289
+ ? Array.isArray(folderName)
290
+ ? [...defaultPath, ...folderName]
291
+ : [...defaultPath, ...folderName.split('/').filter(Boolean)]
292
+ : defaultPath;
293
+
294
+ const serverRelativePath = escapeODataStringLiteral(segments.join('/'));
295
+ const baseEndpoint = `_api/web/GetFolderByServerRelativeUrl('${serverRelativePath}')`;
296
+
297
+ return {
298
+ get: (options?: Folder_Options<Record<string, unknown>>) => {
299
+ const folderType = options?.type ?? 'Files';
300
+ const endpoint = `${baseEndpoint}/${folderType}`;
301
+ const context = this.createContext<'2013'>({
302
+ endpoint,
303
+ listName: '',
304
+ sharepointVersion: '2013',
305
+ });
306
+
307
+ return getFiles<Record<string, unknown>, '2013'>(context, {
308
+ ...options,
309
+ type: folderType,
310
+ });
208
311
  },
209
312
  };
210
313
  }
211
314
 
212
- public users(options?: Options<any>) {
213
- this.endpoint = '_api/web/SiteUserInfoList/items';
214
- this.sharepointVersion = '2013';
315
+ public users(options?: Options<Record<string, unknown>, '2013'>) {
316
+ const context = this.createContext<'2013'>({
317
+ endpoint: '_api/web/SiteUserInfoList/items',
318
+ listName: '',
319
+ sharepointVersion: '2013',
320
+ });
321
+
215
322
  return {
216
- get: () => getListItems(this.getContext(), options),
323
+ get: () => getListItems(context, options),
217
324
  };
218
325
  }
219
326
 
220
- public email = {
221
- send: (props: EmailProps) => {
222
- this.sharepointVersion = '2013';
223
- return sendEmailRequest(this.getContext(), props);
224
- },
225
- };
327
+ public sendEmail(props: EmailProps) {
328
+ const context = this.createContext<'2013'>({
329
+ endpoint: '_api/SP.Utilities.Utility.SendEmail',
330
+ listName: '',
331
+ sharepointVersion: '2013',
332
+ });
333
+ return sendEmailRequest(context, props);
334
+ }
226
335
 
227
- public user = {
336
+ public readonly user = {
228
337
  properties: () => ({
229
- get: (): Promise<UserProfile> => {
230
- this.sharepointVersion = '2013';
231
- return loadCurrentUserProperties(this.instance);
232
- },
338
+ get: (): Promise<UserProfile> => loadCurrentUserProperties(this.instance),
339
+ }),
340
+ searchSiteUser: (searchValue: string) =>
341
+ fetchSiteUser(this.instance, searchValue),
342
+ searchUser: (input: string, filter?: string): Promise<PersonField> =>
343
+ typeAhead(this.instance, input, filter),
344
+ current: () => ({
345
+ get: (): Promise<CurrentUser> =>
346
+ getOnly(this.instance, '_api/web/currentUser'),
233
347
  }),
234
- searchSiteUser: (searchValue: string) => {
235
- this.sharepointVersion = '2013';
236
- return fetchSiteUser(this.instance, searchValue);
237
- },
238
- searchUser: (input: string, filter?: string): Promise<PersonField> => {
239
- this.sharepointVersion = '2013';
240
- return typeAhead(this.instance, input, filter);
241
- },
242
- current: () => {
243
- this.endpoint = '_api/web/currentUser';
244
- this.sharepointVersion = '2013';
245
- return {
246
- get: (): Promise<CurrentUser> => getOnly(this.instance, this.endpoint),
247
- };
248
- },
249
348
  currentPermission: () => ({
250
- get: (): Promise<UserPermision> => {
251
- this.sharepointVersion = '2013';
252
- return resolveCurrentUserPermissions(this.getContext());
253
- },
349
+ get: (): Promise<UserPermision> =>
350
+ resolveCurrentUserPermissions(
351
+ this.createContext<'2013'>({
352
+ endpoint: '_api/web/effectiveBasePermissions',
353
+ listName: '',
354
+ sharepointVersion: '2013',
355
+ })
356
+ ),
254
357
  }),
255
358
  };
359
+
360
+ public getCurrentUser() {
361
+ return this.user.current().get();
362
+ }
363
+
364
+ public currentUserProperties() {
365
+ return this.user.properties().get();
366
+ }
367
+
368
+ public currentUserPermission() {
369
+ return this.user.currentPermission().get();
370
+ }
256
371
  }
257
372
 
258
373
  export default HTTPSharePointRequests;
@@ -1,5 +1,5 @@
1
- import type { AxiosInstance } from 'axios';
2
- import type { SHAREPOINT_VER } from '../../types';
1
+ import { AxiosInstance } from 'axios';
2
+ import { SHAREPOINT_VER } from '../../types';
3
3
 
4
4
  export interface RequestContext<V extends SHAREPOINT_VER = '2013'> {
5
5
  instance: AxiosInstance;
@@ -1,4 +1,4 @@
1
- import type { AxiosInstance } from 'axios';
1
+ import { AxiosInstance } from 'axios';
2
2
 
3
3
  export async function fetchDigest(
4
4
  instance: AxiosInstance,
@@ -16,7 +16,8 @@ export async function fetchDigest(
16
16
 
17
17
  return formDigestValue;
18
18
  } catch (error) {
19
- console.error('Failed to retrieve the Form Digest Value:', error);
20
- throw new Error(`Error retrieving Form Digest Value`);
19
+ const cause =
20
+ error instanceof Error ? error.message : 'Unknown contextinfo error';
21
+ throw new Error(`Error retrieving Form Digest Value: ${cause}`);
21
22
  }
22
23
  }
@@ -1,7 +1,7 @@
1
- import type { AxiosResponse } from 'axios';
2
- import type { EmailProps } from '../../types';
1
+ import { AxiosResponse } from 'axios';
2
+ import { EmailProps } from '../../types';
3
3
  import { fetchDigest } from './digest';
4
- import type { RequestContext } from './context';
4
+ import { RequestContext } from './context';
5
5
 
6
6
  type SendEmailResponse = AxiosResponse<{
7
7
  d: {
@@ -19,10 +19,7 @@ export async function sendEmail(
19
19
  url: httpRequest,
20
20
  method: 'POST',
21
21
  headers: {
22
- 'X-RequestDigest': await fetchDigest(
23
- context.instance,
24
- context.baseURL
25
- ),
22
+ 'X-RequestDigest': await fetchDigest(context.instance, context.baseURL),
26
23
  'X-Http-Method': 'POST',
27
24
  'Content-Type': 'application/json;odata=verbose',
28
25
  },
@@ -1,12 +1,23 @@
1
- import type { CreateFileProps, SHAREPOINT_VER } from '../../../types';
1
+ import { CreateFileProps, SHAREPOINT_VER } from '../../../types';
2
2
  import { fetchDigest } from '../digest';
3
- import type { RequestContext } from '../context';
3
+ import { RequestContext } from '../context';
4
+ import { buildListByTitleEndpoint } from '../sharepointUrl';
5
+ import { encodeFileName } from './utils';
4
6
 
5
7
  export async function createAttachment<V extends SHAREPOINT_VER = '2013'>(
6
8
  context: RequestContext<V>,
7
9
  { file, itemId }: CreateFileProps
8
10
  ) {
9
- const requestUrl = `_api/lists/getbytitle('${context.listName}')/items(${itemId})/AttachmentFiles/add(FileName='${file.name}')`;
11
+ if (context.sharepointVersion !== '2013') {
12
+ throw new Error(
13
+ 'createAttachment is only supported for SharePoint 2013 REST endpoints.'
14
+ );
15
+ }
16
+
17
+ const encodedFileName = encodeFileName(file.name);
18
+ const requestUrl = `${buildListByTitleEndpoint(
19
+ context.listName
20
+ )}/items(${itemId})/AttachmentFiles/add(FileName='${encodedFileName}')`;
10
21
  const response = await context.instance.post(requestUrl, file, {
11
22
  headers: {
12
23
  'X-RequestDigest': await fetchDigest(context.instance, context.baseURL),
@@ -1,6 +1,6 @@
1
- import type { ListData, SHAREPOINT_VER } from '../../../types';
1
+ import { ListData, SHAREPOINT_VER } from '../../../types';
2
2
  import { fetchDigest } from '../digest';
3
- import type { RequestContext } from '../context';
3
+ import { RequestContext } from '../context';
4
4
  import { normalizeListPayload } from './normalizePayload';
5
5
 
6
6
  async function resolveMetadataType<V extends SHAREPOINT_VER>(
@@ -21,17 +21,23 @@ export async function createListItem<
21
21
  D = Record<string, unknown>,
22
22
  V extends SHAREPOINT_VER = '2013'
23
23
  >(context: RequestContext<V>, listData: ListData<D>) {
24
- const metadataType = await resolveMetadataType(context);
25
24
  const normalizedData = normalizeListPayload(listData);
26
- const userMetadata =
27
- (listData as { __metadata?: Record<string, unknown> }).__metadata;
28
- const payload = {
29
- ...normalizedData,
30
- __metadata: {
31
- ...(userMetadata && typeof userMetadata === 'object' ? userMetadata : {}),
32
- type: metadataType,
33
- },
34
- };
25
+ let payload: Record<string, unknown> = normalizedData;
26
+
27
+ if (context.sharepointVersion === '2013') {
28
+ const metadataType = await resolveMetadataType(context);
29
+ const userMetadata = (listData as { __metadata?: Record<string, unknown> })
30
+ .__metadata;
31
+ payload = {
32
+ ...normalizedData,
33
+ __metadata: {
34
+ ...(userMetadata && typeof userMetadata === 'object'
35
+ ? userMetadata
36
+ : {}),
37
+ type: metadataType,
38
+ },
39
+ };
40
+ }
35
41
 
36
42
  const response = await context.instance({
37
43
  url: context.endpoint,
@@ -1,7 +1,8 @@
1
- import type { SHAREPOINT_VER, DeleteFileProps } from '../../../types';
1
+ import { SHAREPOINT_VER, DeleteFileProps } from '../../../types';
2
2
  import { fetchDigest } from '../digest';
3
- import type { RequestContext } from '../context';
3
+ import { RequestContext } from '../context';
4
4
  import { buildLibraryPath, encodeFileName } from './utils';
5
+ import { buildListByTitleEndpoint } from '../sharepointUrl';
5
6
 
6
7
  const SUPPORTED_VERSION: SHAREPOINT_VER = '2013';
7
8
 
@@ -16,7 +17,7 @@ export async function deleteFile<V extends SHAREPOINT_VER = '2013'>(
16
17
  }
17
18
 
18
19
  const encodedFileName = encodeFileName(fileName);
19
- let requestUrl = `_api/web/lists/getbytitle('${context.listName}')/RootFolder`;
20
+ let requestUrl = `${buildListByTitleEndpoint(context.listName)}/RootFolder`;
20
21
  requestUrl += buildLibraryPath(folderPath);
21
22
  requestUrl += `/Files('${encodedFileName}')`;
22
23