@zxncij2390/monorepo3 3.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (921) hide show
  1. package/.eslintignore +16 -0
  2. package/.eslintrc.cjs +150 -0
  3. package/.github/ISSUE_TEMPLATE/bug-report.yml +178 -0
  4. package/.github/ISSUE_TEMPLATE/enhancement.yml +99 -0
  5. package/.github/ISSUE_TEMPLATE/question.yml +72 -0
  6. package/.github/ISSUE_TEMPLATE.md +39 -0
  7. package/.github/PULL_REQUEST_TEMPLATE.md +24 -0
  8. package/.github/workflows/lock.yml +18 -0
  9. package/.github/workflows/publish-buildsystem.yml +34 -0
  10. package/.github/workflows/publish-docs.yml +21 -0
  11. package/.github/workflows/publish.yml +40 -0
  12. package/.github/workflows/pull_request.yaml +28 -0
  13. package/.github/workflows/push.yaml +32 -0
  14. package/.github/workflows/v3-nightly.yml +40 -0
  15. package/.mocharc.cjs +68 -0
  16. package/.vscode/launch.json +103 -0
  17. package/.vscode/settings.json +17 -0
  18. package/.vscode/tasks.json +124 -0
  19. package/AUTHORS +13 -0
  20. package/CHANGELOG.md +33 -0
  21. package/CODE_OF_CONDUCT.md +6 -0
  22. package/CONTRIBUTING.md +9 -0
  23. package/LICENSE +25 -0
  24. package/README.md +66 -0
  25. package/buildsystem-config.ts +146 -0
  26. package/debug/launch/graph.ts +20 -0
  27. package/debug/launch/main.ts +38 -0
  28. package/debug/launch/setup.ts +50 -0
  29. package/debug/launch/sp.ts +21 -0
  30. package/debug/launch/tsconfig.json +27 -0
  31. package/debug/serve/main.ts +47 -0
  32. package/debug/serve/plumbing/local-module-resolver-plugin.ts +68 -0
  33. package/debug/serve/plumbing/run.ts +24 -0
  34. package/debug/serve/plumbing/serve.ts +27 -0
  35. package/debug/serve/plumbing/webpack.config.ts +43 -0
  36. package/debug/serve/spa.html +12 -0
  37. package/debug/serve/tsconfig.json +15 -0
  38. package/debug/spfx/.eslintrc.js +352 -0
  39. package/debug/spfx/README.md +73 -0
  40. package/debug/spfx/package-lock.json +57299 -0
  41. package/debug/spfx/package.json +38 -0
  42. package/debug/spfx/pnpjs-local-debug-start.js +19 -0
  43. package/debug/spfx/teams/f4c0e5ff-c402-46b7-8073-8cc506808d06_color.png +0 -0
  44. package/debug/spfx/teams/f4c0e5ff-c402-46b7-8073-8cc506808d06_outline.png +0 -0
  45. package/docs/_theme/main.html +5 -0
  46. package/docs/azidjsclient/index.md +36 -0
  47. package/docs/concepts/adv-clientside-pages.md +169 -0
  48. package/docs/concepts/auth-browser.md +42 -0
  49. package/docs/concepts/auth-nodejs.md +101 -0
  50. package/docs/concepts/auth-spfx.md +76 -0
  51. package/docs/concepts/authentication.md +42 -0
  52. package/docs/concepts/batching-caching.md +77 -0
  53. package/docs/concepts/batching.md +257 -0
  54. package/docs/concepts/calling-other-endpoints.md +213 -0
  55. package/docs/concepts/custom-bundle.md +15 -0
  56. package/docs/concepts/error-handling.md +245 -0
  57. package/docs/concepts/invokable.md +7 -0
  58. package/docs/concepts/nightly-builds.md +19 -0
  59. package/docs/concepts/project-preset.md +123 -0
  60. package/docs/concepts/selective-imports.md +106 -0
  61. package/docs/concepts/typings.md +23 -0
  62. package/docs/contributing/debug-tests.md +76 -0
  63. package/docs/contributing/debugging.md +135 -0
  64. package/docs/contributing/documentation.md +34 -0
  65. package/docs/contributing/extending-the-library.md +223 -0
  66. package/docs/contributing/index.md +22 -0
  67. package/docs/contributing/local-debug-configuration.md +28 -0
  68. package/docs/contributing/npm-scripts.md +148 -0
  69. package/docs/contributing/pull-requests.md +27 -0
  70. package/docs/contributing/settings.md +98 -0
  71. package/docs/contributing/setup-dev-machine.md +36 -0
  72. package/docs/core/behavior-recipes.md +199 -0
  73. package/docs/core/behaviors.md +179 -0
  74. package/docs/core/moments.md +215 -0
  75. package/docs/core/observers.md +100 -0
  76. package/docs/core/storage.md +90 -0
  77. package/docs/core/timeline.md +190 -0
  78. package/docs/core/util.md +191 -0
  79. package/docs/css/extra.css +33 -0
  80. package/docs/getting-started.md +361 -0
  81. package/docs/graph/behaviors.md +267 -0
  82. package/docs/graph/bookings.md +180 -0
  83. package/docs/graph/calendars.md +270 -0
  84. package/docs/graph/cloud-communications.md +40 -0
  85. package/docs/graph/columns.md +125 -0
  86. package/docs/graph/contacts.md +298 -0
  87. package/docs/graph/content-types.md +193 -0
  88. package/docs/graph/directoryobjects.md +106 -0
  89. package/docs/graph/groups.md +164 -0
  90. package/docs/graph/insights.md +151 -0
  91. package/docs/graph/invitations.md +22 -0
  92. package/docs/graph/items.md +38 -0
  93. package/docs/graph/lists.md +87 -0
  94. package/docs/graph/messages.md +20 -0
  95. package/docs/graph/onedrive.md +614 -0
  96. package/docs/graph/outlook.md +82 -0
  97. package/docs/graph/photos.md +71 -0
  98. package/docs/graph/planner.md +249 -0
  99. package/docs/graph/search.md +25 -0
  100. package/docs/graph/shares.md +44 -0
  101. package/docs/graph/sites.md +47 -0
  102. package/docs/graph/subscriptions.md +79 -0
  103. package/docs/graph/teams.md +293 -0
  104. package/docs/graph/users.md +134 -0
  105. package/docs/img/ConsoleListenerColors.png +0 -0
  106. package/docs/img/Logo.png +0 -0
  107. package/docs/img/PnPJS_FluentAPI.gif +0 -0
  108. package/docs/img/SPFx-On-Premesis-2016-1.png +0 -0
  109. package/docs/img/TimelineArchitecture.jpg +0 -0
  110. package/docs/img/csp_copyccvalue.png +0 -0
  111. package/docs/img/csp_networktab.png +0 -0
  112. package/docs/img/office365-header-icon.png +0 -0
  113. package/docs/img/usage-2020-eoy.png +0 -0
  114. package/docs/img/usage-2021-eoy.png +0 -0
  115. package/docs/img/usage-2022-eoy.png +0 -0
  116. package/docs/index.md +56 -0
  117. package/docs/logging/index.md +262 -0
  118. package/docs/msaljsclient/index.md +33 -0
  119. package/docs/news/2020-year-in-review.md +162 -0
  120. package/docs/news/2021-year-in-review.md +148 -0
  121. package/docs/news/2022-year-in-review.md +122 -0
  122. package/docs/nodejs/behaviors.md +164 -0
  123. package/docs/nodejs/sp-extensions.md +99 -0
  124. package/docs/packages.md +53 -0
  125. package/docs/queryable/behaviors.md +496 -0
  126. package/docs/queryable/extensions.md +204 -0
  127. package/docs/queryable/queryable.md +385 -0
  128. package/docs/sp/alias-parameters.md +76 -0
  129. package/docs/sp/alm.md +139 -0
  130. package/docs/sp/attachments.md +157 -0
  131. package/docs/sp/behaviors.md +142 -0
  132. package/docs/sp/clientside-pages.md +1048 -0
  133. package/docs/sp/column-defaults.md +241 -0
  134. package/docs/sp/comments-likes.md +302 -0
  135. package/docs/sp/content-types.md +131 -0
  136. package/docs/sp/context-info.md +67 -0
  137. package/docs/sp/favorites.md +91 -0
  138. package/docs/sp/features.md +83 -0
  139. package/docs/sp/fields.md +668 -0
  140. package/docs/sp/files.md +559 -0
  141. package/docs/sp/folders.md +532 -0
  142. package/docs/sp/forms.md +22 -0
  143. package/docs/sp/groupSiteManager.md +40 -0
  144. package/docs/sp/hubsites.md +140 -0
  145. package/docs/sp/items.md +601 -0
  146. package/docs/sp/lists.md +572 -0
  147. package/docs/sp/navigation.md +171 -0
  148. package/docs/sp/permissions.md +82 -0
  149. package/docs/sp/profiles.md +407 -0
  150. package/docs/sp/publishing-sitepageservice.md +16 -0
  151. package/docs/sp/recycle-bin.md +72 -0
  152. package/docs/sp/regional-settings.md +108 -0
  153. package/docs/sp/related-items.md +136 -0
  154. package/docs/sp/search.md +207 -0
  155. package/docs/sp/security.md +196 -0
  156. package/docs/sp/sharing.md +273 -0
  157. package/docs/sp/site-designs.md +117 -0
  158. package/docs/sp/site-groups.md +144 -0
  159. package/docs/sp/site-scripts.md +123 -0
  160. package/docs/sp/site-users.md +211 -0
  161. package/docs/sp/sites.md +269 -0
  162. package/docs/sp/social.md +182 -0
  163. package/docs/sp/sp-utilities-utility.md +159 -0
  164. package/docs/sp/subscriptions.md +79 -0
  165. package/docs/sp/taxonomy.md +470 -0
  166. package/docs/sp/tenant-properties.md +55 -0
  167. package/docs/sp/user-custom-actions.md +95 -0
  168. package/docs/sp/views.md +226 -0
  169. package/docs/sp/webs.md +947 -0
  170. package/docs/sp-admin/index.md +139 -0
  171. package/docs/transition-guide.md +87 -0
  172. package/docs/v1/404.html +1611 -0
  173. package/docs/v1/assets/fonts/font-awesome.css +4 -0
  174. package/docs/v1/assets/fonts/material-icons.css +13 -0
  175. package/docs/v1/assets/fonts/specimen/FontAwesome.ttf +0 -0
  176. package/docs/v1/assets/fonts/specimen/FontAwesome.woff +0 -0
  177. package/docs/v1/assets/fonts/specimen/FontAwesome.woff2 +0 -0
  178. package/docs/v1/assets/fonts/specimen/MaterialIcons-Regular.ttf +0 -0
  179. package/docs/v1/assets/fonts/specimen/MaterialIcons-Regular.woff +0 -0
  180. package/docs/v1/assets/fonts/specimen/MaterialIcons-Regular.woff2 +0 -0
  181. package/docs/v1/assets/images/favicon.png +0 -0
  182. package/docs/v1/assets/images/icons/bitbucket.1b09e088.svg +20 -0
  183. package/docs/v1/assets/images/icons/github.f0b8504a.svg +18 -0
  184. package/docs/v1/assets/images/icons/gitlab.6dd19c00.svg +38 -0
  185. package/docs/v1/assets/javascripts/application.583bbe55.js +1 -0
  186. package/docs/v1/assets/javascripts/lunr/lunr.da.js +1 -0
  187. package/docs/v1/assets/javascripts/lunr/lunr.de.js +1 -0
  188. package/docs/v1/assets/javascripts/lunr/lunr.du.js +1 -0
  189. package/docs/v1/assets/javascripts/lunr/lunr.es.js +1 -0
  190. package/docs/v1/assets/javascripts/lunr/lunr.fi.js +1 -0
  191. package/docs/v1/assets/javascripts/lunr/lunr.fr.js +1 -0
  192. package/docs/v1/assets/javascripts/lunr/lunr.hu.js +1 -0
  193. package/docs/v1/assets/javascripts/lunr/lunr.it.js +1 -0
  194. package/docs/v1/assets/javascripts/lunr/lunr.jp.js +1 -0
  195. package/docs/v1/assets/javascripts/lunr/lunr.multi.js +1 -0
  196. package/docs/v1/assets/javascripts/lunr/lunr.no.js +1 -0
  197. package/docs/v1/assets/javascripts/lunr/lunr.pt.js +1 -0
  198. package/docs/v1/assets/javascripts/lunr/lunr.ro.js +1 -0
  199. package/docs/v1/assets/javascripts/lunr/lunr.ru.js +1 -0
  200. package/docs/v1/assets/javascripts/lunr/lunr.stemmer.support.js +1 -0
  201. package/docs/v1/assets/javascripts/lunr/lunr.sv.js +1 -0
  202. package/docs/v1/assets/javascripts/lunr/lunr.tr.js +1 -0
  203. package/docs/v1/assets/javascripts/lunr/tinyseg.js +1 -0
  204. package/docs/v1/assets/javascripts/modernizr.1aa3b519.js +1 -0
  205. package/docs/v1/assets/stylesheets/application-palette.22915126.css +1176 -0
  206. package/docs/v1/assets/stylesheets/application.451f80e5.css +2552 -0
  207. package/docs/v1/common/docs/adalclient/index.html +1994 -0
  208. package/docs/v1/common/docs/collections/index.html +1786 -0
  209. package/docs/v1/common/docs/custom-httpclientimpl/index.html +1798 -0
  210. package/docs/v1/common/docs/index.html +1787 -0
  211. package/docs/v1/common/docs/libconfig/index.html +1930 -0
  212. package/docs/v1/common/docs/netutil/index.html +1860 -0
  213. package/docs/v1/common/docs/storage/index.html +1850 -0
  214. package/docs/v1/common/docs/util/index.html +2058 -0
  215. package/docs/v1/config-store/docs/configuration/index.html +1730 -0
  216. package/docs/v1/config-store/docs/index.html +1761 -0
  217. package/docs/v1/config-store/docs/providers/index.html +1782 -0
  218. package/docs/v1/documentation/SPFx-On-Premesis-2016/index.html +1720 -0
  219. package/docs/v1/documentation/beta-versions/index.html +1742 -0
  220. package/docs/v1/documentation/css/extra.css +33 -0
  221. package/docs/v1/documentation/debugging/index.html +2098 -0
  222. package/docs/v1/documentation/deployment/index.html +1972 -0
  223. package/docs/v1/documentation/documentation/index.html +1760 -0
  224. package/docs/v1/documentation/getting-started/index.html +2280 -0
  225. package/docs/v1/documentation/getting-started-dev/index.html +1799 -0
  226. package/docs/v1/documentation/gulp-commands/index.html +2100 -0
  227. package/docs/v1/documentation/img/Logo.png +0 -0
  228. package/docs/v1/documentation/img/PnPJS_FluentAPI.gif +0 -0
  229. package/docs/v1/documentation/img/SPFx-On-Premesis-2016-1.png +0 -0
  230. package/docs/v1/documentation/img/office365-header-icon.png +0 -0
  231. package/docs/v1/documentation/img/pnpjs-common-uml.svg +220 -0
  232. package/docs/v1/documentation/img/pnpjs-config-store-uml.svg +56 -0
  233. package/docs/v1/documentation/img/pnpjs-graph-uml.svg +602 -0
  234. package/docs/v1/documentation/img/pnpjs-logging-uml.svg +59 -0
  235. package/docs/v1/documentation/img/pnpjs-nodejs-uml.svg +85 -0
  236. package/docs/v1/documentation/img/pnpjs-odata-uml.svg +253 -0
  237. package/docs/v1/documentation/img/pnpjs-sp-addinhelpers-uml.svg +48 -0
  238. package/docs/v1/documentation/img/pnpjs-sp-clientsvc-uml.svg +167 -0
  239. package/docs/v1/documentation/img/pnpjs-sp-taxonomy-uml.svg +458 -0
  240. package/docs/v1/documentation/img/pnpjs-sp-uml.svg +2833 -0
  241. package/docs/v1/documentation/package-structure/index.html +1875 -0
  242. package/docs/v1/documentation/packages/index.html +1741 -0
  243. package/docs/v1/documentation/polyfill/index.html +1877 -0
  244. package/docs/v1/documentation/theme/main.html +5 -0
  245. package/docs/v1/documentation/transition-guide/index.html +1977 -0
  246. package/docs/v1/graph/docs/contacts/index.html +2080 -0
  247. package/docs/v1/graph/docs/directoryobjects/index.html +1865 -0
  248. package/docs/v1/graph/docs/index.html +1858 -0
  249. package/docs/v1/graph/docs/insights/index.html +1698 -0
  250. package/docs/v1/graph/docs/invitations/index.html +1742 -0
  251. package/docs/v1/graph/docs/onedrive/index.html +2086 -0
  252. package/docs/v1/graph/docs/people/index.html +1664 -0
  253. package/docs/v1/graph/docs/planner/index.html +2097 -0
  254. package/docs/v1/graph/docs/security/index.html +1692 -0
  255. package/docs/v1/graph/docs/sites/index.html +2043 -0
  256. package/docs/v1/graph/docs/subscriptions/index.html +1835 -0
  257. package/docs/v1/graph/docs/teams/index.html +2097 -0
  258. package/docs/v1/index.html +1889 -0
  259. package/docs/v1/logging/docs/index.html +2045 -0
  260. package/docs/v1/nodejs/docs/adal-certificate-fetch-client/index.html +1676 -0
  261. package/docs/v1/nodejs/docs/adal-fetch-client/index.html +1713 -0
  262. package/docs/v1/nodejs/docs/bearer-token-fetch-client/index.html +1712 -0
  263. package/docs/v1/nodejs/docs/index.html +1764 -0
  264. package/docs/v1/nodejs/docs/provider-hosted-app/index.html +1725 -0
  265. package/docs/v1/nodejs/docs/proxy/index.html +1699 -0
  266. package/docs/v1/nodejs/docs/sp-fetch-client/index.html +1895 -0
  267. package/docs/v1/odata/docs/caching/index.html +1988 -0
  268. package/docs/v1/odata/docs/core/index.html +1829 -0
  269. package/docs/v1/odata/docs/index.html +1781 -0
  270. package/docs/v1/odata/docs/odata-batch/index.html +1755 -0
  271. package/docs/v1/odata/docs/parsers/index.html +1862 -0
  272. package/docs/v1/odata/docs/pipeline/index.html +1811 -0
  273. package/docs/v1/odata/docs/queryable/index.html +1967 -0
  274. package/docs/v1/pnpjs/docs/index.html +1814 -0
  275. package/docs/v1/search/search_index.json +1 -0
  276. package/docs/v1/sitemap.xml +428 -0
  277. package/docs/v1/sitemap.xml.gz +0 -0
  278. package/docs/v1/sp/docs/alias-parameters/index.html +1830 -0
  279. package/docs/v1/sp/docs/alm/index.html +1920 -0
  280. package/docs/v1/sp/docs/attachments/index.html +1998 -0
  281. package/docs/v1/sp/docs/client-side-pages/index.html +2031 -0
  282. package/docs/v1/sp/docs/comments-likes/index.html +1958 -0
  283. package/docs/v1/sp/docs/content-types/index.html +1758 -0
  284. package/docs/v1/sp/docs/entity-merging/index.html +1838 -0
  285. package/docs/v1/sp/docs/features/index.html +1824 -0
  286. package/docs/v1/sp/docs/fields/index.html +2031 -0
  287. package/docs/v1/sp/docs/files/index.html +2178 -0
  288. package/docs/v1/sp/docs/index.html +1894 -0
  289. package/docs/v1/sp/docs/items/index.html +2362 -0
  290. package/docs/v1/sp/docs/navigation-service/index.html +1791 -0
  291. package/docs/v1/sp/docs/permissions/index.html +1860 -0
  292. package/docs/v1/sp/docs/profiles/index.html +1794 -0
  293. package/docs/v1/sp/docs/related-items/index.html +1886 -0
  294. package/docs/v1/sp/docs/search/index.html +1830 -0
  295. package/docs/v1/sp/docs/sharing/index.html +2058 -0
  296. package/docs/v1/sp/docs/sitedesigns/index.html +1851 -0
  297. package/docs/v1/sp/docs/sites/index.html +2186 -0
  298. package/docs/v1/sp/docs/social/index.html +2011 -0
  299. package/docs/v1/sp/docs/sp-utilities-utility/index.html +2061 -0
  300. package/docs/v1/sp/docs/tenant-properties/index.html +1795 -0
  301. package/docs/v1/sp/docs/views/index.html +1869 -0
  302. package/docs/v1/sp/docs/webs/index.html +1972 -0
  303. package/docs/v1/sp-addinhelpers/docs/index.html +1771 -0
  304. package/docs/v1/sp-addinhelpers/docs/sp-request-executor-client/index.html +1760 -0
  305. package/docs/v1/sp-addinhelpers/docs/sp-rest-addin/index.html +1711 -0
  306. package/docs/v1/sp-clientsvc/docs/index.html +1736 -0
  307. package/docs/v1/sp-taxonomy/docs/index.html +1887 -0
  308. package/docs/v1/sp-taxonomy/docs/labels/index.html +1827 -0
  309. package/docs/v1/sp-taxonomy/docs/term-groups/index.html +1875 -0
  310. package/docs/v1/sp-taxonomy/docs/term-sets/index.html +1946 -0
  311. package/docs/v1/sp-taxonomy/docs/term-stores/index.html +2111 -0
  312. package/docs/v1/sp-taxonomy/docs/terms/index.html +2036 -0
  313. package/docs/v1/sp-taxonomy/docs/utilities/index.html +1783 -0
  314. package/docs/v2/404.html +2108 -0
  315. package/docs/v2/SPFx-on-premises/index.html +2278 -0
  316. package/docs/v2/_theme/main.html +5 -0
  317. package/docs/v2/adaljsclient/adalclient/index.html +15 -0
  318. package/docs/v2/adaljsclient/index.html +15 -0
  319. package/docs/v2/assets/images/favicon.png +0 -0
  320. package/docs/v2/assets/javascripts/bundle.9554a270.min.js +2 -0
  321. package/docs/v2/assets/javascripts/bundle.9554a270.min.js.map +1 -0
  322. package/docs/v2/assets/javascripts/lunr/min/lunr.ar.min.js +1 -0
  323. package/docs/v2/assets/javascripts/lunr/min/lunr.da.min.js +18 -0
  324. package/docs/v2/assets/javascripts/lunr/min/lunr.de.min.js +18 -0
  325. package/docs/v2/assets/javascripts/lunr/min/lunr.du.min.js +18 -0
  326. package/docs/v2/assets/javascripts/lunr/min/lunr.es.min.js +18 -0
  327. package/docs/v2/assets/javascripts/lunr/min/lunr.fi.min.js +18 -0
  328. package/docs/v2/assets/javascripts/lunr/min/lunr.fr.min.js +18 -0
  329. package/docs/v2/assets/javascripts/lunr/min/lunr.hu.min.js +18 -0
  330. package/docs/v2/assets/javascripts/lunr/min/lunr.it.min.js +18 -0
  331. package/docs/v2/assets/javascripts/lunr/min/lunr.ja.min.js +1 -0
  332. package/docs/v2/assets/javascripts/lunr/min/lunr.jp.min.js +1 -0
  333. package/docs/v2/assets/javascripts/lunr/min/lunr.multi.min.js +1 -0
  334. package/docs/v2/assets/javascripts/lunr/min/lunr.nl.min.js +18 -0
  335. package/docs/v2/assets/javascripts/lunr/min/lunr.no.min.js +18 -0
  336. package/docs/v2/assets/javascripts/lunr/min/lunr.pt.min.js +18 -0
  337. package/docs/v2/assets/javascripts/lunr/min/lunr.ro.min.js +18 -0
  338. package/docs/v2/assets/javascripts/lunr/min/lunr.ru.min.js +18 -0
  339. package/docs/v2/assets/javascripts/lunr/min/lunr.stemmer.support.min.js +1 -0
  340. package/docs/v2/assets/javascripts/lunr/min/lunr.sv.min.js +18 -0
  341. package/docs/v2/assets/javascripts/lunr/min/lunr.tr.min.js +18 -0
  342. package/docs/v2/assets/javascripts/lunr/min/lunr.vi.min.js +1 -0
  343. package/docs/v2/assets/javascripts/lunr/tinyseg.min.js +1 -0
  344. package/docs/v2/assets/javascripts/vendor.77e55a48.min.js +30 -0
  345. package/docs/v2/assets/javascripts/vendor.77e55a48.min.js.map +1 -0
  346. package/docs/v2/assets/javascripts/worker/search.4ac00218.min.js +59 -0
  347. package/docs/v2/assets/javascripts/worker/search.4ac00218.min.js.map +1 -0
  348. package/docs/v2/assets/stylesheets/main.38780c08.min.css +3 -0
  349. package/docs/v2/assets/stylesheets/main.38780c08.min.css.map +1 -0
  350. package/docs/v2/assets/stylesheets/palette.3f72e892.min.css +3 -0
  351. package/docs/v2/assets/stylesheets/palette.3f72e892.min.css.map +1 -0
  352. package/docs/v2/authentication/adaljsclient/index.html +2510 -0
  353. package/docs/v2/authentication/bearertokenclient/index.html +2251 -0
  354. package/docs/v2/authentication/client-spa/index.html +2206 -0
  355. package/docs/v2/authentication/client-spfx/index.html +2397 -0
  356. package/docs/v2/authentication/index.html +2307 -0
  357. package/docs/v2/authentication/lambdaclient/index.html +2304 -0
  358. package/docs/v2/authentication/msaljsclient/index.html +2413 -0
  359. package/docs/v2/authentication/server-nodejs/index.html +2404 -0
  360. package/docs/v2/authentication/sp-app-registration/index.html +2273 -0
  361. package/docs/v2/common/collections/index.html +2277 -0
  362. package/docs/v2/common/custom-httpclientimpl/index.html +2300 -0
  363. package/docs/v2/common/index.html +2262 -0
  364. package/docs/v2/common/libconfig/index.html +2413 -0
  365. package/docs/v2/common/netutil/index.html +2350 -0
  366. package/docs/v2/common/storage/index.html +2339 -0
  367. package/docs/v2/common/util/index.html +2638 -0
  368. package/docs/v2/concepts/configuration/index.html +2685 -0
  369. package/docs/v2/concepts/custom-bundle/index.html +2279 -0
  370. package/docs/v2/concepts/error-handling/index.html +2539 -0
  371. package/docs/v2/concepts/ie11-mode/index.html +2278 -0
  372. package/docs/v2/concepts/invokable/index.html +2254 -0
  373. package/docs/v2/concepts/polyfill/index.html +2401 -0
  374. package/docs/v2/concepts/selective-imports/index.html +2360 -0
  375. package/docs/v2/concepts/settings/index.html +2551 -0
  376. package/docs/v2/config-store/configuration/index.html +2226 -0
  377. package/docs/v2/config-store/index.html +2239 -0
  378. package/docs/v2/config-store/providers/index.html +2275 -0
  379. package/docs/v2/contributing/debug-tests/index.html +2323 -0
  380. package/docs/v2/contributing/debugging/index.html +2514 -0
  381. package/docs/v2/contributing/documentation/index.html +2291 -0
  382. package/docs/v2/contributing/extending-the-library/index.html +2521 -0
  383. package/docs/v2/contributing/index.html +2270 -0
  384. package/docs/v2/contributing/local-debug-configuration/index.html +2284 -0
  385. package/docs/v2/contributing/pull-requests/index.html +2261 -0
  386. package/docs/v2/contributing/setup-dev-machine/index.html +2284 -0
  387. package/docs/v2/css/extra.css +33 -0
  388. package/docs/v2/debug-tests/index.html +15 -0
  389. package/docs/v2/debugging/index.html +15 -0
  390. package/docs/v2/documentation/index.html +15 -0
  391. package/docs/v2/getting-started/index.html +2789 -0
  392. package/docs/v2/getting-started-dev/index.html +15 -0
  393. package/docs/v2/graph/calendars/index.html +2569 -0
  394. package/docs/v2/graph/contacts/index.html +2673 -0
  395. package/docs/v2/graph/directoryobjects/index.html +2402 -0
  396. package/docs/v2/graph/groups/index.html +2488 -0
  397. package/docs/v2/graph/index.html +2333 -0
  398. package/docs/v2/graph/insights/index.html +2478 -0
  399. package/docs/v2/graph/invitations/index.html +2273 -0
  400. package/docs/v2/graph/onedrive/index.html +2617 -0
  401. package/docs/v2/graph/outlook/index.html +2363 -0
  402. package/docs/v2/graph/photos/index.html +2351 -0
  403. package/docs/v2/graph/planner/index.html +2628 -0
  404. package/docs/v2/graph/search/index.html +2264 -0
  405. package/docs/v2/graph/subscriptions/index.html +2333 -0
  406. package/docs/v2/graph/teams/index.html +2619 -0
  407. package/docs/v2/graph/users/index.html +2461 -0
  408. package/docs/v2/img/ConsoleListenerColors.png +0 -0
  409. package/docs/v2/img/Logo.png +0 -0
  410. package/docs/v2/img/PnPJS_FluentAPI.gif +0 -0
  411. package/docs/v2/img/SPFx-On-Premesis-2016-1.png +0 -0
  412. package/docs/v2/img/office365-header-icon.png +0 -0
  413. package/docs/v2/img/usage-2020-eoy.png +0 -0
  414. package/docs/v2/index.html +2410 -0
  415. package/docs/v2/logging/index.html +2622 -0
  416. package/docs/v2/news/2020-year-in-review/index.html +2525 -0
  417. package/docs/v2/nodejs/adal-fetch-client/index.html +2204 -0
  418. package/docs/v2/nodejs/bearer-token-fetch-client/index.html +2203 -0
  419. package/docs/v2/nodejs/index.html +2261 -0
  420. package/docs/v2/nodejs/provider-hosted-app/index.html +2220 -0
  421. package/docs/v2/nodejs/proxy/index.html +2238 -0
  422. package/docs/v2/nodejs/sp-extensions/index.html +2362 -0
  423. package/docs/v2/nodejs/sp-fetch-client/index.html +2294 -0
  424. package/docs/v2/nodejs-support/index.html +2398 -0
  425. package/docs/v2/npm-scripts/index.html +2521 -0
  426. package/docs/v2/odata/caching/index.html +2465 -0
  427. package/docs/v2/odata/core/index.html +2322 -0
  428. package/docs/v2/odata/debug/index.html +2358 -0
  429. package/docs/v2/odata/extensions/index.html +2581 -0
  430. package/docs/v2/odata/index.html +2259 -0
  431. package/docs/v2/odata/odata-batch/index.html +2250 -0
  432. package/docs/v2/odata/parsers/index.html +2355 -0
  433. package/docs/v2/odata/pipeline/index.html +2297 -0
  434. package/docs/v2/odata/queryable/index.html +2455 -0
  435. package/docs/v2/packages/index.html +2251 -0
  436. package/docs/v2/pnpjs/index.html +2281 -0
  437. package/docs/v2/search/search_index.json +1 -0
  438. package/docs/v2/sitemap.xml +483 -0
  439. package/docs/v2/sitemap.xml.gz +0 -0
  440. package/docs/v2/sp/alias-parameters/index.html +2330 -0
  441. package/docs/v2/sp/alm/index.html +2433 -0
  442. package/docs/v2/sp/attachments/index.html +2504 -0
  443. package/docs/v2/sp/clientside-pages/index.html +3477 -0
  444. package/docs/v2/sp/column-defaults/index.html +2540 -0
  445. package/docs/v2/sp/comments-likes/index.html +2646 -0
  446. package/docs/v2/sp/content-types/index.html +2462 -0
  447. package/docs/v2/sp/custom-irequestclient/index.html +2339 -0
  448. package/docs/v2/sp/entity-merging/index.html +2325 -0
  449. package/docs/v2/sp/features/index.html +2440 -0
  450. package/docs/v2/sp/fields/index.html +3103 -0
  451. package/docs/v2/sp/files/index.html +2949 -0
  452. package/docs/v2/sp/folders/index.html +2968 -0
  453. package/docs/v2/sp/forms/index.html +2289 -0
  454. package/docs/v2/sp/hubsites/index.html +2485 -0
  455. package/docs/v2/sp/index.html +2328 -0
  456. package/docs/v2/sp/items/index.html +2974 -0
  457. package/docs/v2/sp/lists/index.html +3387 -0
  458. package/docs/v2/sp/navigation/index.html +2535 -0
  459. package/docs/v2/sp/permissions/index.html +2338 -0
  460. package/docs/v2/sp/profiles/index.html +2806 -0
  461. package/docs/v2/sp/regional-settings/index.html +2394 -0
  462. package/docs/v2/sp/related-items/index.html +2417 -0
  463. package/docs/v2/sp/search/index.html +2474 -0
  464. package/docs/v2/sp/security/index.html +2432 -0
  465. package/docs/v2/sp/sharing/index.html +2589 -0
  466. package/docs/v2/sp/site-designs/index.html +2414 -0
  467. package/docs/v2/sp/site-groups/index.html +2504 -0
  468. package/docs/v2/sp/site-scripts/index.html +2433 -0
  469. package/docs/v2/sp/site-users/index.html +2641 -0
  470. package/docs/v2/sp/sites/index.html +2727 -0
  471. package/docs/v2/sp/social/index.html +2517 -0
  472. package/docs/v2/sp/sp-utilities-utility/index.html +2460 -0
  473. package/docs/v2/sp/subscriptions/index.html +2395 -0
  474. package/docs/v2/sp/taxonomy/index.html +2565 -0
  475. package/docs/v2/sp/tenant-properties/index.html +2286 -0
  476. package/docs/v2/sp/user-custom-actions/index.html +2424 -0
  477. package/docs/v2/sp/views/index.html +2652 -0
  478. package/docs/v2/sp/webs/index.html +4190 -0
  479. package/docs/v2/sp-addinhelpers/index.html +2274 -0
  480. package/docs/v2/sp-addinhelpers/sp-request-executor-client/index.html +2253 -0
  481. package/docs/v2/sp-addinhelpers/sp-rest-addin/index.html +2206 -0
  482. package/docs/v2/transition-guide/index.html +2435 -0
  483. package/mkdocs-requirements.txt +2 -0
  484. package/mkdocs.yml +188 -0
  485. package/package.json +96 -0
  486. package/packages/azidjsclient/index.ts +68 -0
  487. package/packages/azidjsclient/package.json +13 -0
  488. package/packages/azidjsclient/tsconfig.json +12 -0
  489. package/packages/core/behaviors/assign-from.ts +17 -0
  490. package/packages/core/behaviors/copy-from.ts +58 -0
  491. package/packages/core/extendable.ts +193 -0
  492. package/packages/core/index.ts +11 -0
  493. package/packages/core/moments.ts +117 -0
  494. package/packages/core/package.json +10 -0
  495. package/packages/core/storage.ts +274 -0
  496. package/packages/core/timeline.ts +387 -0
  497. package/packages/core/tsconfig.json +10 -0
  498. package/packages/core/util.ts +169 -0
  499. package/packages/graph/attachments/conversations.ts +14 -0
  500. package/packages/graph/attachments/index.ts +8 -0
  501. package/packages/graph/attachments/types.ts +37 -0
  502. package/packages/graph/batching.ts +408 -0
  503. package/packages/graph/behaviors/consistency-level.ts +17 -0
  504. package/packages/graph/behaviors/defaults.ts +41 -0
  505. package/packages/graph/behaviors/endpoint.ts +22 -0
  506. package/packages/graph/behaviors/graphbrowser.ts +38 -0
  507. package/packages/graph/behaviors/paged.ts +109 -0
  508. package/packages/graph/behaviors/spfx.ts +46 -0
  509. package/packages/graph/behaviors/telemetry.ts +19 -0
  510. package/packages/graph/bookings/funcs.ts +18 -0
  511. package/packages/graph/bookings/index.ts +62 -0
  512. package/packages/graph/bookings/types.ts +352 -0
  513. package/packages/graph/calendars/funcs.ts +58 -0
  514. package/packages/graph/calendars/groups.ts +19 -0
  515. package/packages/graph/calendars/index.ts +18 -0
  516. package/packages/graph/calendars/types.ts +73 -0
  517. package/packages/graph/calendars/users.ts +28 -0
  518. package/packages/graph/cloud-communications/index.ts +24 -0
  519. package/packages/graph/cloud-communications/types.ts +32 -0
  520. package/packages/graph/cloud-communications/users.ts +15 -0
  521. package/packages/graph/columns/addColumns.ts +28 -0
  522. package/packages/graph/columns/content-types.ts +44 -0
  523. package/packages/graph/columns/index.ts +14 -0
  524. package/packages/graph/columns/lists.ts +33 -0
  525. package/packages/graph/columns/sites.ts +32 -0
  526. package/packages/graph/columns/types.ts +24 -0
  527. package/packages/graph/contacts/index.ts +14 -0
  528. package/packages/graph/contacts/types.ts +126 -0
  529. package/packages/graph/contacts/users.ts +17 -0
  530. package/packages/graph/content-types/index.ts +11 -0
  531. package/packages/graph/content-types/lists.ts +44 -0
  532. package/packages/graph/content-types/sites.ts +70 -0
  533. package/packages/graph/content-types/types.ts +112 -0
  534. package/packages/graph/conversations/groups.ts +20 -0
  535. package/packages/graph/conversations/index.ts +19 -0
  536. package/packages/graph/conversations/types.ts +147 -0
  537. package/packages/graph/decorators.ts +164 -0
  538. package/packages/graph/directory-objects/index.ts +24 -0
  539. package/packages/graph/directory-objects/types.ts +94 -0
  540. package/packages/graph/fi.ts +46 -0
  541. package/packages/graph/graphqueryable.ts +193 -0
  542. package/packages/graph/groups/index.ts +25 -0
  543. package/packages/graph/groups/types.ts +130 -0
  544. package/packages/graph/index.ts +21 -0
  545. package/packages/graph/insights/index.ts +20 -0
  546. package/packages/graph/insights/types.ts +105 -0
  547. package/packages/graph/insights/users.ts +14 -0
  548. package/packages/graph/invitations/index.ts +22 -0
  549. package/packages/graph/invitations/types.ts +41 -0
  550. package/packages/graph/lists/drive.ts +21 -0
  551. package/packages/graph/lists/index.ts +10 -0
  552. package/packages/graph/lists/sites.ts +16 -0
  553. package/packages/graph/lists/types.ts +47 -0
  554. package/packages/graph/members/groups.ts +17 -0
  555. package/packages/graph/members/index.ts +8 -0
  556. package/packages/graph/members/types.ts +40 -0
  557. package/packages/graph/messages/index.ts +14 -0
  558. package/packages/graph/messages/types.ts +46 -0
  559. package/packages/graph/messages/users.ts +27 -0
  560. package/packages/graph/onedrive/funcs.ts +40 -0
  561. package/packages/graph/onedrive/groups.ts +33 -0
  562. package/packages/graph/onedrive/index.ts +48 -0
  563. package/packages/graph/onedrive/sites.ts +35 -0
  564. package/packages/graph/onedrive/types.ts +482 -0
  565. package/packages/graph/onedrive/users.ts +56 -0
  566. package/packages/graph/onenote/index.ts +16 -0
  567. package/packages/graph/onenote/types.ts +119 -0
  568. package/packages/graph/onenote/users.ts +14 -0
  569. package/packages/graph/operations.ts +22 -0
  570. package/packages/graph/outlook/index.ts +11 -0
  571. package/packages/graph/outlook/types.ts +58 -0
  572. package/packages/graph/outlook/users.ts +14 -0
  573. package/packages/graph/package.json +16 -0
  574. package/packages/graph/photos/groups.ts +14 -0
  575. package/packages/graph/photos/index.ts +7 -0
  576. package/packages/graph/photos/types.ts +33 -0
  577. package/packages/graph/photos/users.ts +14 -0
  578. package/packages/graph/planner/groups.ts +14 -0
  579. package/packages/graph/planner/index.ts +42 -0
  580. package/packages/graph/planner/types.ts +213 -0
  581. package/packages/graph/planner/users.ts +14 -0
  582. package/packages/graph/post-install.cjs +20 -0
  583. package/packages/graph/presets/all.ts +42 -0
  584. package/packages/graph/search/index.ts +18 -0
  585. package/packages/graph/search/types.ts +20 -0
  586. package/packages/graph/shares/index.ts +23 -0
  587. package/packages/graph/shares/types.ts +47 -0
  588. package/packages/graph/sites/group.ts +14 -0
  589. package/packages/graph/sites/index.ts +25 -0
  590. package/packages/graph/sites/types.ts +45 -0
  591. package/packages/graph/subscriptions/index.ts +24 -0
  592. package/packages/graph/subscriptions/types.ts +59 -0
  593. package/packages/graph/teams/index.ts +68 -0
  594. package/packages/graph/teams/types.ts +333 -0
  595. package/packages/graph/teams/users.ts +14 -0
  596. package/packages/graph/tsconfig.json +16 -0
  597. package/packages/graph/users/index.ts +34 -0
  598. package/packages/graph/users/types.ts +56 -0
  599. package/packages/graph/utils/type.ts +3 -0
  600. package/packages/logging/index.ts +145 -0
  601. package/packages/logging/listeners.ts +134 -0
  602. package/packages/logging/package.json +10 -0
  603. package/packages/logging/tsconfig.json +7 -0
  604. package/packages/msaljsclient/index.ts +40 -0
  605. package/packages/msaljsclient/package.json +12 -0
  606. package/packages/msaljsclient/tsconfig.json +12 -0
  607. package/packages/nodejs/behaviors/fetch.ts +130 -0
  608. package/packages/nodejs/behaviors/graphdefault.ts +50 -0
  609. package/packages/nodejs/behaviors/msal.ts +24 -0
  610. package/packages/nodejs/behaviors/spdefault.ts +45 -0
  611. package/packages/nodejs/behaviors/stream-parse.ts +7 -0
  612. package/packages/nodejs/index.ts +33 -0
  613. package/packages/nodejs/package.json +17 -0
  614. package/packages/nodejs/sp-extensions/stream.ts +136 -0
  615. package/packages/nodejs/tsconfig.json +28 -0
  616. package/packages/queryable/add-prop.ts +18 -0
  617. package/packages/queryable/behaviors/bearer-token.ts +15 -0
  618. package/packages/queryable/behaviors/browser-fetch.ts +131 -0
  619. package/packages/queryable/behaviors/caching-pessimistic.ts +67 -0
  620. package/packages/queryable/behaviors/caching.ts +149 -0
  621. package/packages/queryable/behaviors/cancelable.ts +264 -0
  622. package/packages/queryable/behaviors/inject-headers.ts +23 -0
  623. package/packages/queryable/behaviors/parsers.ts +134 -0
  624. package/packages/queryable/behaviors/resolvers.ts +28 -0
  625. package/packages/queryable/behaviors/timeout.ts +24 -0
  626. package/packages/queryable/index.ts +19 -0
  627. package/packages/queryable/invokable.ts +42 -0
  628. package/packages/queryable/operations.ts +32 -0
  629. package/packages/queryable/package.json +11 -0
  630. package/packages/queryable/queryable-factory.ts +19 -0
  631. package/packages/queryable/queryable.ts +239 -0
  632. package/packages/queryable/request-builders.ts +20 -0
  633. package/packages/queryable/tsconfig.json +11 -0
  634. package/packages/readme.md +21 -0
  635. package/packages/sp/appcatalog/index.ts +35 -0
  636. package/packages/sp/appcatalog/types.ts +176 -0
  637. package/packages/sp/appcatalog/web.ts +19 -0
  638. package/packages/sp/attachments/index.ts +11 -0
  639. package/packages/sp/attachments/item.ts +17 -0
  640. package/packages/sp/attachments/types.ts +95 -0
  641. package/packages/sp/batching.ts +483 -0
  642. package/packages/sp/behaviors/defaults.ts +38 -0
  643. package/packages/sp/behaviors/request-digest.ts +78 -0
  644. package/packages/sp/behaviors/spbrowser.ts +40 -0
  645. package/packages/sp/behaviors/spfx.ts +83 -0
  646. package/packages/sp/behaviors/telemetry.ts +35 -0
  647. package/packages/sp/clientside-pages/funcs.ts +27 -0
  648. package/packages/sp/clientside-pages/index.ts +27 -0
  649. package/packages/sp/clientside-pages/types.ts +1661 -0
  650. package/packages/sp/clientside-pages/web.ts +93 -0
  651. package/packages/sp/column-defaults/folder.ts +89 -0
  652. package/packages/sp/column-defaults/index.ts +8 -0
  653. package/packages/sp/column-defaults/list.ts +219 -0
  654. package/packages/sp/column-defaults/types.ts +19 -0
  655. package/packages/sp/comments/clientside-page.ts +120 -0
  656. package/packages/sp/comments/index.ts +14 -0
  657. package/packages/sp/comments/item.ts +77 -0
  658. package/packages/sp/comments/types.ts +160 -0
  659. package/packages/sp/content-types/index.ts +17 -0
  660. package/packages/sp/content-types/item.ts +17 -0
  661. package/packages/sp/content-types/list.ts +17 -0
  662. package/packages/sp/content-types/types.ts +181 -0
  663. package/packages/sp/content-types/web.ts +17 -0
  664. package/packages/sp/context-info/index.ts +40 -0
  665. package/packages/sp/decorators.ts +18 -0
  666. package/packages/sp/favorites/index.ts +32 -0
  667. package/packages/sp/favorites/types.ts +187 -0
  668. package/packages/sp/features/index.ts +11 -0
  669. package/packages/sp/features/site.ts +17 -0
  670. package/packages/sp/features/types.ts +73 -0
  671. package/packages/sp/features/web.ts +17 -0
  672. package/packages/sp/fi.ts +46 -0
  673. package/packages/sp/fields/index.ts +22 -0
  674. package/packages/sp/fields/list.ts +17 -0
  675. package/packages/sp/fields/types.ts +648 -0
  676. package/packages/sp/fields/web.ts +23 -0
  677. package/packages/sp/files/folder.ts +17 -0
  678. package/packages/sp/files/index.ts +25 -0
  679. package/packages/sp/files/item.ts +17 -0
  680. package/packages/sp/files/readable-file.ts +40 -0
  681. package/packages/sp/files/types.ts +771 -0
  682. package/packages/sp/files/web.ts +46 -0
  683. package/packages/sp/folders/index.ts +19 -0
  684. package/packages/sp/folders/item.ts +16 -0
  685. package/packages/sp/folders/list.ts +17 -0
  686. package/packages/sp/folders/types.ts +439 -0
  687. package/packages/sp/folders/web.ts +50 -0
  688. package/packages/sp/forms/index.ts +9 -0
  689. package/packages/sp/forms/list.ts +14 -0
  690. package/packages/sp/forms/types.ts +41 -0
  691. package/packages/sp/groupsitemanager/index.ts +18 -0
  692. package/packages/sp/groupsitemanager/types.ts +433 -0
  693. package/packages/sp/hubsites/index.ts +31 -0
  694. package/packages/sp/hubsites/site.ts +43 -0
  695. package/packages/sp/hubsites/types.ts +71 -0
  696. package/packages/sp/hubsites/web.ts +38 -0
  697. package/packages/sp/index.ts +24 -0
  698. package/packages/sp/items/get-all.ts +52 -0
  699. package/packages/sp/items/index.ts +18 -0
  700. package/packages/sp/items/list.ts +14 -0
  701. package/packages/sp/items/types.ts +405 -0
  702. package/packages/sp/lists/index.ts +23 -0
  703. package/packages/sp/lists/types.ts +851 -0
  704. package/packages/sp/lists/web.ts +68 -0
  705. package/packages/sp/navigation/index.ts +35 -0
  706. package/packages/sp/navigation/types.ts +243 -0
  707. package/packages/sp/navigation/web.ts +19 -0
  708. package/packages/sp/operations.ts +33 -0
  709. package/packages/sp/package.json +15 -0
  710. package/packages/sp/post-install.cjs +20 -0
  711. package/packages/sp/presets/all.ts +75 -0
  712. package/packages/sp/profiles/index.ts +30 -0
  713. package/packages/sp/profiles/types.ts +595 -0
  714. package/packages/sp/publishing-sitepageservice/index.ts +22 -0
  715. package/packages/sp/publishing-sitepageservice/types.ts +18 -0
  716. package/packages/sp/recycle-bin/index.ts +36 -0
  717. package/packages/sp/recycle-bin/types.ts +113 -0
  718. package/packages/sp/regional-settings/content-type.ts +11 -0
  719. package/packages/sp/regional-settings/field.ts +11 -0
  720. package/packages/sp/regional-settings/funcs.ts +10 -0
  721. package/packages/sp/regional-settings/index.ts +18 -0
  722. package/packages/sp/regional-settings/list.ts +11 -0
  723. package/packages/sp/regional-settings/types.ts +159 -0
  724. package/packages/sp/regional-settings/user-custom-actions.ts +11 -0
  725. package/packages/sp/regional-settings/web.ts +21 -0
  726. package/packages/sp/related-items/index.ts +7 -0
  727. package/packages/sp/related-items/types.ts +194 -0
  728. package/packages/sp/related-items/web.ts +22 -0
  729. package/packages/sp/search/index.ts +48 -0
  730. package/packages/sp/search/query.ts +254 -0
  731. package/packages/sp/search/suggest.ts +130 -0
  732. package/packages/sp/search/types.ts +480 -0
  733. package/packages/sp/security/funcs.ts +94 -0
  734. package/packages/sp/security/index.ts +21 -0
  735. package/packages/sp/security/item.ts +29 -0
  736. package/packages/sp/security/list.ts +29 -0
  737. package/packages/sp/security/types.ts +440 -0
  738. package/packages/sp/security/web.ts +34 -0
  739. package/packages/sp/sharing/file.ts +75 -0
  740. package/packages/sp/sharing/folder.ts +69 -0
  741. package/packages/sp/sharing/funcs.ts +258 -0
  742. package/packages/sp/sharing/index.ts +27 -0
  743. package/packages/sp/sharing/item.ts +53 -0
  744. package/packages/sp/sharing/types.ts +626 -0
  745. package/packages/sp/sharing/web.ts +109 -0
  746. package/packages/sp/site-designs/index.ts +29 -0
  747. package/packages/sp/site-designs/types.ts +456 -0
  748. package/packages/sp/site-designs/web.ts +41 -0
  749. package/packages/sp/site-groups/index.ts +11 -0
  750. package/packages/sp/site-groups/types.ts +133 -0
  751. package/packages/sp/site-groups/web.ts +73 -0
  752. package/packages/sp/site-scripts/index.ts +27 -0
  753. package/packages/sp/site-scripts/list.ts +27 -0
  754. package/packages/sp/site-scripts/types.ts +243 -0
  755. package/packages/sp/site-scripts/web.ts +24 -0
  756. package/packages/sp/site-users/index.ts +12 -0
  757. package/packages/sp/site-users/types.ts +195 -0
  758. package/packages/sp/site-users/web.ts +56 -0
  759. package/packages/sp/sites/index.ts +26 -0
  760. package/packages/sp/sites/types.ts +422 -0
  761. package/packages/sp/social/index.ts +33 -0
  762. package/packages/sp/social/types.ts +381 -0
  763. package/packages/sp/spqueryable.ts +244 -0
  764. package/packages/sp/sputilities/index.ts +23 -0
  765. package/packages/sp/sputilities/types.ts +197 -0
  766. package/packages/sp/subscriptions/index.ts +10 -0
  767. package/packages/sp/subscriptions/list.ts +18 -0
  768. package/packages/sp/subscriptions/types.ts +107 -0
  769. package/packages/sp/taxonomy/index.ts +50 -0
  770. package/packages/sp/taxonomy/types.ts +508 -0
  771. package/packages/sp/tsconfig.json +16 -0
  772. package/packages/sp/types.ts +283 -0
  773. package/packages/sp/user-custom-actions/index.ts +15 -0
  774. package/packages/sp/user-custom-actions/list.ts +18 -0
  775. package/packages/sp/user-custom-actions/site.ts +18 -0
  776. package/packages/sp/user-custom-actions/types.ts +133 -0
  777. package/packages/sp/user-custom-actions/web.ts +21 -0
  778. package/packages/sp/utils/encode-path-str.ts +29 -0
  779. package/packages/sp/utils/extract-web-url.ts +21 -0
  780. package/packages/sp/utils/file-names.ts +35 -0
  781. package/packages/sp/utils/metadata.ts +5 -0
  782. package/packages/sp/utils/odata-url-from.ts +42 -0
  783. package/packages/sp/utils/to-resource-path.ts +9 -0
  784. package/packages/sp/views/index.ts +14 -0
  785. package/packages/sp/views/list.ts +33 -0
  786. package/packages/sp/views/types.ts +210 -0
  787. package/packages/sp/webparts/file.ts +21 -0
  788. package/packages/sp/webparts/index.ts +11 -0
  789. package/packages/sp/webparts/types.ts +141 -0
  790. package/packages/sp/webs/index.ts +32 -0
  791. package/packages/sp/webs/types.ts +350 -0
  792. package/packages/sp-admin/index.ts +46 -0
  793. package/packages/sp-admin/office-tenant.ts +567 -0
  794. package/packages/sp-admin/package.json +13 -0
  795. package/packages/sp-admin/site-properties.ts +45 -0
  796. package/packages/sp-admin/tenant.ts +595 -0
  797. package/packages/sp-admin/tsconfig.json +20 -0
  798. package/packages/sp-admin/types.ts +1679 -0
  799. package/packages/tsconfig-watch.json +9 -0
  800. package/packages/tsconfig.json +37 -0
  801. package/pre-install.cjs +1 -0
  802. package/samples/custom-bundle-webpack/index.ts +33 -0
  803. package/samples/custom-bundle-webpack/package-lock.json +4601 -0
  804. package/samples/custom-bundle-webpack/package.json +18 -0
  805. package/samples/custom-bundle-webpack/readme.md +102 -0
  806. package/samples/custom-bundle-webpack/tsconfig.json +12 -0
  807. package/samples/custom-bundle-webpack/webpack.config.js +27 -0
  808. package/samples/nodejs-app/.vscode/launch.json +27 -0
  809. package/samples/nodejs-app/.vscode/settings.json +10 -0
  810. package/samples/nodejs-app/.vscode/tasks.json +22 -0
  811. package/samples/nodejs-app/index.ts +63 -0
  812. package/samples/nodejs-app/package-lock.json +259 -0
  813. package/samples/nodejs-app/package.json +21 -0
  814. package/samples/nodejs-app/readme.md +140 -0
  815. package/samples/nodejs-app/tsconfig.json +14 -0
  816. package/samples/nodejs-commonjs/package-lock.json +702 -0
  817. package/samples/nodejs-commonjs/package.json +21 -0
  818. package/samples/nodejs-commonjs/readme.md +58 -0
  819. package/samples/nodejs-commonjs/src/index.ts +23 -0
  820. package/samples/nodejs-commonjs/src/settings.ts +35 -0
  821. package/samples/nodejs-commonjs/tsconfig.json +35 -0
  822. package/samples/project-preset/README.md +73 -0
  823. package/samples/project-preset/package-lock.json +21097 -0
  824. package/samples/project-preset/package.json +29 -0
  825. package/samples/project-preset/teams/4530a515-8ba7-45bb-9a27-be06b33c59d4_color.png +0 -0
  826. package/samples/project-preset/teams/4530a515-8ba7-45bb-9a27-be06b33c59d4_outline.png +0 -0
  827. package/samples/readme.md +16 -0
  828. package/settings.example.js +57 -0
  829. package/test/args.ts +107 -0
  830. package/test/clean-subsite.ts +36 -0
  831. package/test/core/assumptions.ts +99 -0
  832. package/test/core/storage.ts +60 -0
  833. package/test/core/timeline.ts +205 -0
  834. package/test/core/util.ts +205 -0
  835. package/test/graph/assets/testconvert.docx +0 -0
  836. package/test/graph/batch.ts +125 -0
  837. package/test/graph/calendars.ts +234 -0
  838. package/test/graph/columns.ts +247 -0
  839. package/test/graph/contacts.ts +254 -0
  840. package/test/graph/content-types.ts +206 -0
  841. package/test/graph/directoryobjects.ts +115 -0
  842. package/test/graph/groups.ts +130 -0
  843. package/test/graph/lists.ts +72 -0
  844. package/test/graph/onedrive.ts +365 -0
  845. package/test/graph/outlook.ts +95 -0
  846. package/test/graph/paging.ts +91 -0
  847. package/test/graph/planner.ts +160 -0
  848. package/test/graph/querable.ts +97 -0
  849. package/test/graph/search.ts +4 -0
  850. package/test/graph/shares.ts +26 -0
  851. package/test/graph/sites.ts +40 -0
  852. package/test/graph/teams.ts +76 -0
  853. package/test/graph/utilities/getTestingGraphSPSite.ts +27 -0
  854. package/test/graph/utilities/getValidUser.ts +37 -0
  855. package/test/load-settings.ts +103 -0
  856. package/test/logging/logging.ts +86 -0
  857. package/test/mocha-root-hooks.ts +227 -0
  858. package/test/nodejs/sp-extensions.ts +86 -0
  859. package/test/pnp-test.ts +60 -0
  860. package/test/queryable/add-prop.ts +24 -0
  861. package/test/queryable/behaviors.ts +188 -0
  862. package/test/queryable/invokable.ts +35 -0
  863. package/test/queryable/queryable.ts +118 -0
  864. package/test/sp/alias.ts +46 -0
  865. package/test/sp/appcatalog.ts +142 -0
  866. package/test/sp/assets/helloworld.sppkg +0 -0
  867. package/test/sp/assets/sample_file.jpg +0 -0
  868. package/test/sp/attachments.ts +134 -0
  869. package/test/sp/batch.ts +362 -0
  870. package/test/sp/clientside-pages.ts +426 -0
  871. package/test/sp/column-defaults.ts +225 -0
  872. package/test/sp/comments.ts +202 -0
  873. package/test/sp/content-types.ts +68 -0
  874. package/test/sp/favorites.ts +2 -0
  875. package/test/sp/features.ts +201 -0
  876. package/test/sp/fields.ts +396 -0
  877. package/test/sp/files.ts +338 -0
  878. package/test/sp/folders.ts +242 -0
  879. package/test/sp/forms.ts +22 -0
  880. package/test/sp/groupsitemanager.ts +88 -0
  881. package/test/sp/hubsites.ts +41 -0
  882. package/test/sp/items.ts +179 -0
  883. package/test/sp/lists.ts +319 -0
  884. package/test/sp/navigation.ts +167 -0
  885. package/test/sp/profiles.ts +2 -0
  886. package/test/sp/query-escaping.ts +94 -0
  887. package/test/sp/recycle-bin.ts +1 -0
  888. package/test/sp/regional-settings.ts +58 -0
  889. package/test/sp/related-items.ts +94 -0
  890. package/test/sp/search.ts +39 -0
  891. package/test/sp/security.ts +90 -0
  892. package/test/sp/sharing.ts +313 -0
  893. package/test/sp/site-designs.ts +224 -0
  894. package/test/sp/site-groups.ts +98 -0
  895. package/test/sp/site-scripts.ts +162 -0
  896. package/test/sp/site-users.ts +93 -0
  897. package/test/sp/sites.ts +156 -0
  898. package/test/sp/social.ts +2 -0
  899. package/test/sp/spfx.ts +52 -0
  900. package/test/sp/sputilities.ts +78 -0
  901. package/test/sp/subscriptions.ts +64 -0
  902. package/test/sp/taxonomy.ts +178 -0
  903. package/test/sp/user-custom-actions.ts +31 -0
  904. package/test/sp/views.ts +117 -0
  905. package/test/sp/webparts.ts +38 -0
  906. package/test/sp/webs.ts +249 -0
  907. package/test/test-invokable-props.ts +35 -0
  908. package/test/test-props.ts +90 -0
  909. package/test/test-recording.ts +171 -0
  910. package/test/tsconfig.json +18 -0
  911. package/tools/buildsystem/package-lock.json +4404 -0
  912. package/tools/buildsystem/package.json +56 -0
  913. package/tools/buildsystem/readme.md +23 -0
  914. package/tools/config.js +34 -0
  915. package/tools/local-module-resolver/cjs.ts +33 -0
  916. package/tools/local-module-resolver/esm-debug.ts +2 -0
  917. package/tools/local-module-resolver/esm-test.ts +2 -0
  918. package/tools/local-module-resolver/esm.ts +112 -0
  919. package/tools/local-module-resolver/readme.md +8 -0
  920. package/tsconfig.buildsystem.json +17 -0
  921. package/tsconfig.json +42 -0
@@ -0,0 +1 @@
1
+ {"config":{"lang":["en"],"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"PnPjs is a collection of fluent libraries for consuming SharePoint, Graph, and Office 365 REST APIs in a type-safe way. You can use it within SharePoint Framework, Nodejs, or any JavaScript project. This an open source initiative and we encourage contributions and constructive feedback from the community. Animation of the library in use, note intellisense help in building your queries General Guidance \u00b6 These articles provide general guidance for working with the libraries. If you are migrating from sp-pnp-js please review the transition guide . Getting Started Getting Started Contributing Documentation Gulp Commands Debugging Deployment Install Beta Versions Polyfills Package Structure Packages \u00b6 Patterns and Practices client side libraries (PnPjs) are comprised of the packages listed below. All of the packages are published as a set and depend on their peers within the @pnp scope. @pnp/ common Provides shared functionality across all pnp libraries config-store Provides a way to manage configuration within your application graph Provides a fluent api for working with Microsoft Graph logging Light-weight, subscribable logging framework nodejs Provides functionality enabling the @pnp libraries within nodejs odata Provides shared odata functionality and base classes pnpjs Rollup library of core functionality (mimics sp-pnp-js) sp Provides a fluent api for working with SharePoint REST sp-addinhelpers Provides functionality for working within SharePoint add-ins sp-clientsvc Provides based classes used to create a fluent api for working with SharePoint Managed Metadata sp-taxonomy Provides a fluent api for working with SharePoint Managed Metadata Issues, Questions, Ideas \u00b6 Please log an issue using our template as a guide. This will let us track your request and ensure we respond. We appreciate any contructive feedback, questions, ideas, or bug reports with our thanks for giving back to the project. Code of Conduct \u00b6 This project has adopted the Microsoft Open Source Code of Conduct . For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments. \"Sharing is Caring\" \u00b6 Please use http://aka.ms/sppnp for the latest updates around the whole SharePoint Patterns and Practices (PnP) program . Disclaimer \u00b6 THIS CODE IS PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.","title":"Home"},{"location":"#general-guidance","text":"These articles provide general guidance for working with the libraries. If you are migrating from sp-pnp-js please review the transition guide . Getting Started Getting Started Contributing Documentation Gulp Commands Debugging Deployment Install Beta Versions Polyfills Package Structure","title":"General Guidance"},{"location":"#packages","text":"Patterns and Practices client side libraries (PnPjs) are comprised of the packages listed below. All of the packages are published as a set and depend on their peers within the @pnp scope. @pnp/ common Provides shared functionality across all pnp libraries config-store Provides a way to manage configuration within your application graph Provides a fluent api for working with Microsoft Graph logging Light-weight, subscribable logging framework nodejs Provides functionality enabling the @pnp libraries within nodejs odata Provides shared odata functionality and base classes pnpjs Rollup library of core functionality (mimics sp-pnp-js) sp Provides a fluent api for working with SharePoint REST sp-addinhelpers Provides functionality for working within SharePoint add-ins sp-clientsvc Provides based classes used to create a fluent api for working with SharePoint Managed Metadata sp-taxonomy Provides a fluent api for working with SharePoint Managed Metadata","title":"Packages"},{"location":"#issues-questions-ideas","text":"Please log an issue using our template as a guide. This will let us track your request and ensure we respond. We appreciate any contructive feedback, questions, ideas, or bug reports with our thanks for giving back to the project.","title":"Issues, Questions, Ideas"},{"location":"#code-of-conduct","text":"This project has adopted the Microsoft Open Source Code of Conduct . For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.","title":"Code of Conduct"},{"location":"#sharing-is-caring","text":"Please use http://aka.ms/sppnp for the latest updates around the whole SharePoint Patterns and Practices (PnP) program .","title":"\"Sharing is Caring\""},{"location":"#disclaimer","text":"THIS CODE IS PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.","title":"Disclaimer"},{"location":"common/docs/","text":"@pnp/core \u00b6 The common modules provides a set of utilities classes and reusable building blocks used throughout the @pnp modules. They can be used within your applications as well. Getting Started \u00b6 Install the library and required dependencies npm install @pnp/core --save Import and use functionality, see details on modules below. import { getGUID } from \"@pnp/core\" ; console . log ( getGUID ()); Exports \u00b6 adalclient collections libconfig netutil storage util Custom HttpClient UML \u00b6 Graphical UML diagram of @pnp/core. Right-click the diagram and open in new tab if it is too small.","title":"common"},{"location":"common/docs/#pnpcommon","text":"The common modules provides a set of utilities classes and reusable building blocks used throughout the @pnp modules. They can be used within your applications as well.","title":"@pnp/core"},{"location":"common/docs/#getting-started","text":"Install the library and required dependencies npm install @pnp/core --save Import and use functionality, see details on modules below. import { getGUID } from \"@pnp/core\" ; console . log ( getGUID ());","title":"Getting Started"},{"location":"common/docs/#exports","text":"adalclient collections libconfig netutil storage util Custom HttpClient","title":"Exports"},{"location":"common/docs/#uml","text":"Graphical UML diagram of @pnp/core. Right-click the diagram and open in new tab if it is too small.","title":"UML"},{"location":"common/docs/adalclient/","text":"@pnp/core/adalclient \u00b6 Added in 1.0.4 This module contains the AdalClient class which can be used to authenticate to any AzureAD secured resource. It is designed to work seamlessly with SharePoint Framework's permissions. Setup and Use inside SharePoint Framework \u00b6 Using the SharePoint Framework is the preferred way to make use of the AdalClient as we can use the AADTokenProvider to efficiently get tokens on your behalf. You can also read more about how this process works and the necessary SPFx configurations in the SharePoint Framework 1.6 release notes . This method only work for SharePoint Framework >= 1.6. For earlier versions of SharePoint Framework you can still use the AdalClient as outlined above using the constructor to specify the values for an AAD Application you have setup. Calling the graph api \u00b6 By providing the context in the onInit we can create the adal client from known information. import { graph } from \"@pnp/graph\" ; import { getRandomString } from \"@pnp/core\" ; // ... public onInit () : Promise < void > { return super . onInit (). then ( _ => { // other init code may be present graph . setup ({ spfxContext : this.context }); }); } public render () : void { // here we are creating a team with a random name, required Group ReadWrite All permissions const teamName = `ATeam. ${ getRandomString ( 4 ) } ` ; this . domElement . innerHTML = `Hello, I am creating a team named \" ${ teamName } \" for you...` ; graph . teams . create ( teamName , \"This is a description\" ). then ( t => { this . domElement . innerHTML += \"done!\" ; }). catch ( e => { this . domElement . innerHTML = `Oops, I ran into a problem... ${ JSON . stringify ( e , null , 4 ) } ` ; }); } Calling the SharePoint API \u00b6 This example shows how to use the ADALClient with the @pnp/sp library to call import { sp } from \"@pnp/sp\" ; import { AdalClient } from \"@pnp/core\" ; // ... public onInit () : Promise < void > { return super . onInit (). then ( _ => { // other init code may be present sp . setup ({ spfxContext : this.context , sp : { fetchClientFactory : () => , }, }); }); } public render () : void { sp . web . get (). then ( t => { this . domElement . innerHTML = JSON . stringify ( t ); }). catch ( e => { this . domElement . innerHTML = JSON . stringify ( e ); }); } Calling the any API \u00b6 You can also use the AdalClient to execute AAD authenticated requests to any API which is properly configured to accept the incoming tokens. This approach will only work within SharePoint Framework >= 1.6. Here we call the SharePoint REST API without the sp library as an example. import { AdalClient , FetchOptions } from \"@pnp/core\" ; import { ODataDefaultParser } from \"@pnp/queryable\" ; // ... public render () : void { // create an ADAL Client const client = AdalClient . fromSPFxContext ( this . context ); // setup the request options const opts : FetchOptions = { method : \"GET\" , headers : { \"Accept\" : \"application/json\" , }, }; // execute the request client . fetch ( \"https://tenant.sharepoint.com/_api/web\" , opts ). then ( response => { // create a parser to convert the response into JSON. // You can create your own, at this point you have a fetch Response to work with const parser = new ODataDefaultParser (); parser . parse ( response ). then ( json => { this . domElement . innerHTML = JSON . stringify ( json ); }); }). catch ( e => { this . domElement . innerHTML = JSON . stringify ( e ); }); } Manually Configure \u00b6 This example shows setting up and using the AdalClient to make queries using information you have setup. You can review this article for more information on setting up and securing any application using AzureAD. Setup and Use with Microsoft Graph \u00b6 This sample uses a custom AzureAd app you have created and granted the appropriate permissions. import { AdalClient } from \"@pnp/core\" ; import { graph } from \"@pnp/graph\" ; // configure the graph client // parameters are: // client id - the id of the application you created in azure ad // tenant - can be id or URL (shown) // redirect url - absolute url of a page to which your application and Azure AD app allows replies graph . setup ({ graph : { fetchClientFactory : () => { return new AdalClient ( \"e3e9048e-ea28-423b-aca9-3ea931cc7972\" , \"{tenant}.onmicrosoft.com\" , \"https://myapp/singlesignon.aspx\" ); }, }, }); try { // call the graph API const groups = await graph . groups . get (); console . log ( JSON . stringify ( groups , null , 4 )); } catch ( e ) { console . error ( e ); } Nodejs Applications \u00b6 We have a dedicated node client in @pnp/nodejs.","title":"adalclient"},{"location":"common/docs/adalclient/#pnpcommonadalclient","text":"Added in 1.0.4 This module contains the AdalClient class which can be used to authenticate to any AzureAD secured resource. It is designed to work seamlessly with SharePoint Framework's permissions.","title":"@pnp/core/adalclient"},{"location":"common/docs/adalclient/#setup-and-use-inside-sharepoint-framework","text":"Using the SharePoint Framework is the preferred way to make use of the AdalClient as we can use the AADTokenProvider to efficiently get tokens on your behalf. You can also read more about how this process works and the necessary SPFx configurations in the SharePoint Framework 1.6 release notes . This method only work for SharePoint Framework >= 1.6. For earlier versions of SharePoint Framework you can still use the AdalClient as outlined above using the constructor to specify the values for an AAD Application you have setup.","title":"Setup and Use inside SharePoint Framework"},{"location":"common/docs/adalclient/#calling-the-graph-api","text":"By providing the context in the onInit we can create the adal client from known information. import { graph } from \"@pnp/graph\" ; import { getRandomString } from \"@pnp/core\" ; // ... public onInit () : Promise < void > { return super . onInit (). then ( _ => { // other init code may be present graph . setup ({ spfxContext : this.context }); }); } public render () : void { // here we are creating a team with a random name, required Group ReadWrite All permissions const teamName = `ATeam. ${ getRandomString ( 4 ) } ` ; this . domElement . innerHTML = `Hello, I am creating a team named \" ${ teamName } \" for you...` ; graph . teams . create ( teamName , \"This is a description\" ). then ( t => { this . domElement . innerHTML += \"done!\" ; }). catch ( e => { this . domElement . innerHTML = `Oops, I ran into a problem... ${ JSON . stringify ( e , null , 4 ) } ` ; }); }","title":"Calling the graph api"},{"location":"common/docs/adalclient/#calling-the-sharepoint-api","text":"This example shows how to use the ADALClient with the @pnp/sp library to call import { sp } from \"@pnp/sp\" ; import { AdalClient } from \"@pnp/core\" ; // ... public onInit () : Promise < void > { return super . onInit (). then ( _ => { // other init code may be present sp . setup ({ spfxContext : this.context , sp : { fetchClientFactory : () => , }, }); }); } public render () : void { sp . web . get (). then ( t => { this . domElement . innerHTML = JSON . stringify ( t ); }). catch ( e => { this . domElement . innerHTML = JSON . stringify ( e ); }); }","title":"Calling the SharePoint API"},{"location":"common/docs/adalclient/#calling-the-any-api","text":"You can also use the AdalClient to execute AAD authenticated requests to any API which is properly configured to accept the incoming tokens. This approach will only work within SharePoint Framework >= 1.6. Here we call the SharePoint REST API without the sp library as an example. import { AdalClient , FetchOptions } from \"@pnp/core\" ; import { ODataDefaultParser } from \"@pnp/queryable\" ; // ... public render () : void { // create an ADAL Client const client = AdalClient . fromSPFxContext ( this . context ); // setup the request options const opts : FetchOptions = { method : \"GET\" , headers : { \"Accept\" : \"application/json\" , }, }; // execute the request client . fetch ( \"https://tenant.sharepoint.com/_api/web\" , opts ). then ( response => { // create a parser to convert the response into JSON. // You can create your own, at this point you have a fetch Response to work with const parser = new ODataDefaultParser (); parser . parse ( response ). then ( json => { this . domElement . innerHTML = JSON . stringify ( json ); }); }). catch ( e => { this . domElement . innerHTML = JSON . stringify ( e ); }); }","title":"Calling the any API"},{"location":"common/docs/adalclient/#manually-configure","text":"This example shows setting up and using the AdalClient to make queries using information you have setup. You can review this article for more information on setting up and securing any application using AzureAD.","title":"Manually Configure"},{"location":"common/docs/adalclient/#setup-and-use-with-microsoft-graph","text":"This sample uses a custom AzureAd app you have created and granted the appropriate permissions. import { AdalClient } from \"@pnp/core\" ; import { graph } from \"@pnp/graph\" ; // configure the graph client // parameters are: // client id - the id of the application you created in azure ad // tenant - can be id or URL (shown) // redirect url - absolute url of a page to which your application and Azure AD app allows replies graph . setup ({ graph : { fetchClientFactory : () => { return new AdalClient ( \"e3e9048e-ea28-423b-aca9-3ea931cc7972\" , \"{tenant}.onmicrosoft.com\" , \"https://myapp/singlesignon.aspx\" ); }, }, }); try { // call the graph API const groups = await graph . groups . get (); console . log ( JSON . stringify ( groups , null , 4 )); } catch ( e ) { console . error ( e ); }","title":"Setup and Use with Microsoft Graph"},{"location":"common/docs/adalclient/#nodejs-applications","text":"We have a dedicated node client in @pnp/nodejs.","title":"Nodejs Applications"},{"location":"common/docs/collections/","text":"@pnp/core/collections \u00b6 The collections module provides typings and classes related to working with dictionaries. TypedHash \u00b6 Interface used to described an object with string keys corresponding to values of type T export interface TypedHash < T > { [ key : string ] : T ; } objectToMap \u00b6 Converts a plain object to a Map instance const map = objectToMap ({ a : \"b\" , c : \"d\" }); mergeMaps \u00b6 Merges two or more maps, overwriting values with the same key. Last value in wins. const m1 = new Map (); const m2 = new Map (); const m3 = new Map (); const m4 = new Map (); const m = mergeMaps ( m1 , m2 , m3 , m4 );","title":"collections"},{"location":"common/docs/collections/#pnpcommoncollections","text":"The collections module provides typings and classes related to working with dictionaries.","title":"@pnp/core/collections"},{"location":"common/docs/collections/#typedhash","text":"Interface used to described an object with string keys corresponding to values of type T export interface TypedHash < T > { [ key : string ] : T ; }","title":"TypedHash"},{"location":"common/docs/collections/#objecttomap","text":"Converts a plain object to a Map instance const map = objectToMap ({ a : \"b\" , c : \"d\" });","title":"objectToMap"},{"location":"common/docs/collections/#mergemaps","text":"Merges two or more maps, overwriting values with the same key. Last value in wins. const m1 = new Map (); const m2 = new Map (); const m3 = new Map (); const m4 = new Map (); const m = mergeMaps ( m1 , m2 , m3 , m4 );","title":"mergeMaps"},{"location":"common/docs/custom-httpclientimpl/","text":"Custom HttpClientImpl \u00b6 This should be considered an advanced topic and creating a custom HttpClientImpl is not something you will likely need to do. Also, we don't offer support beyond this article for writing your own implementation. It is possible you may need complete control over the sending and receiving of requests. Before you get started read and understand the fetch specification as you are essentially writing a custom fetch implementation. The first step (second if you read the fetch spec as mentioned just above) is to understand the interface you need to implement, HttpClientImpl. export interface HttpClientImpl { fetch ( url : string , options : FetchOptions ) : Promise < Response > ; } There is a single method \"fetch\" which takes a url string and a set of options. These options can be just about anything but are constrained within the library to the FetchOptions interface. export interface FetchOptions { method? : string ; headers? : HeadersInit | { [ index : string ] : string }; body? : BodyInit ; mode? : string | RequestMode ; credentials? : string | RequestCredentials ; cache? : string | RequestCache ; } So you will need to handle any of those options along with the provided url when sending your request. The library will expect your implementation to return a Promise that resolves to a Response defined by the fetch specification - which you've already read \ud83d\udc4d. Using Your Custom HttpClientImpl \u00b6 Once you have written your implementation using it on your requests is done by setting it in the global library configuration: import { setup } from \"@pnp/core\" ; import { sp , Web } from \"@pnp/sp\" ; import { MyAwesomeClient } from \"./awesomeclient\" ; sp . setup ({ sp : { fetchClientFactory : () => { return new MyAwesomeClient (); } } }); let w = new Web ( \"{site url}\" ); // this request will use your client. w . select ( \"Title\" ). get (). then ( w => { console . log ( w ); }); Subclassing is Better \u00b6 You can of course inherit from one of the implementations available within the @pnp scope if you just need to say add a header or need to do something to every request sent. Perhaps some advanced logging. This approach will save you from needing to fully write a fetch implementation. A FINAL NOTE \u00b6 Whatever you do, do not write a client that uses a client id and secret and exposes them on the client side. Client Id and Secret should only ever be used on a server, never exposed to clients as anyone with those values has the full permissions granted to that id and secret.","title":"Custom HttpClientImpl"},{"location":"common/docs/custom-httpclientimpl/#custom-httpclientimpl","text":"This should be considered an advanced topic and creating a custom HttpClientImpl is not something you will likely need to do. Also, we don't offer support beyond this article for writing your own implementation. It is possible you may need complete control over the sending and receiving of requests. Before you get started read and understand the fetch specification as you are essentially writing a custom fetch implementation. The first step (second if you read the fetch spec as mentioned just above) is to understand the interface you need to implement, HttpClientImpl. export interface HttpClientImpl { fetch ( url : string , options : FetchOptions ) : Promise < Response > ; } There is a single method \"fetch\" which takes a url string and a set of options. These options can be just about anything but are constrained within the library to the FetchOptions interface. export interface FetchOptions { method? : string ; headers? : HeadersInit | { [ index : string ] : string }; body? : BodyInit ; mode? : string | RequestMode ; credentials? : string | RequestCredentials ; cache? : string | RequestCache ; } So you will need to handle any of those options along with the provided url when sending your request. The library will expect your implementation to return a Promise that resolves to a Response defined by the fetch specification - which you've already read \ud83d\udc4d.","title":"Custom HttpClientImpl"},{"location":"common/docs/custom-httpclientimpl/#using-your-custom-httpclientimpl","text":"Once you have written your implementation using it on your requests is done by setting it in the global library configuration: import { setup } from \"@pnp/core\" ; import { sp , Web } from \"@pnp/sp\" ; import { MyAwesomeClient } from \"./awesomeclient\" ; sp . setup ({ sp : { fetchClientFactory : () => { return new MyAwesomeClient (); } } }); let w = new Web ( \"{site url}\" ); // this request will use your client. w . select ( \"Title\" ). get (). then ( w => { console . log ( w ); });","title":"Using Your Custom HttpClientImpl"},{"location":"common/docs/custom-httpclientimpl/#subclassing-is-better","text":"You can of course inherit from one of the implementations available within the @pnp scope if you just need to say add a header or need to do something to every request sent. Perhaps some advanced logging. This approach will save you from needing to fully write a fetch implementation.","title":"Subclassing is Better"},{"location":"common/docs/custom-httpclientimpl/#a-final-note","text":"Whatever you do, do not write a client that uses a client id and secret and exposes them on the client side. Client Id and Secret should only ever be used on a server, never exposed to clients as anyone with those values has the full permissions granted to that id and secret.","title":"A FINAL NOTE"},{"location":"common/docs/libconfig/","text":"@pnp/core/libconfig \u00b6 Contains the shared classes and interfaces used to configure the libraries. These bases classes are expanded on in dependent libraries with the core configuration defined here. This module exposes an instance of the RuntimeConfigImpl class: RuntimeConfig. This configuration object can be referenced and contains the global configuration shared across the libraries. You can also extend the configuration for use within your own applications. LibraryConfiguration Interface \u00b6 Defines the shared configurable values used across the library as shown below. Each of these has a default value as shown below export interface LibraryConfiguration { /** * Allows caching to be global disabled, default: false */ globalCacheDisable? : boolean ; /** * Defines the default store used by the usingCaching method, default: session */ defaultCachingStore ?: \"session\" | \"local\" ; /** * Defines the default timeout in seconds used by the usingCaching method, default 30 */ defaultCachingTimeoutSeconds? : number ; /** * If true a timeout expired items will be removed from the cache in intervals determined by cacheTimeoutInterval */ enableCacheExpiration? : boolean ; /** * Determines the interval in milliseconds at which the cache is checked to see if items have expired (min: 100) */ cacheExpirationIntervalMilliseconds? : number ; /** * Used to supply the current context from an SPFx webpart to the library */ spfxContext? : any ; } RuntimeConfigImpl \u00b6 The class which implements the runtime configuration management as well as sets the default values used within the library. At its heart lies a Dictionary used to track the configuration values. The keys will match the values in the interface or plain object passed to the extend method. extend \u00b6 The extend method is used to add configuration to the global configuration instance. You can pass it any plain object with string keys and those values will be added. Any existing values will be overwritten based on the keys. Last value in wins. For a more detailed scenario of using the RuntimeConfig instance in your own application please see the section below \"Using RuntimeConfig within your application\". Note there are no methods to remove/clear the global config as it should be considered fairly static as frequent updates may have unpredictable side effects as it is a global shared object. Generally it should be set at the start of your application. import { RuntimeConfig } from \"@pnp/core\" ; // add your custom keys to the global configuration // note you can use object hashes as values RuntimeConfig . extend ({ \"myKey1\" : \"value 1\" , \"myKey2\" : { \"subKey\" : \"sub value 1\" , \"subKey2\" : \"sub value 2\" , }, }); // read your custom values const v = RuntimeConfig . get ( \"myKey1\" ); // \"value 1\" Using RuntimeConfig within your Application \u00b6 If you have a set of properties you will access very frequently it may be desirable to implement your own configuration object and expose those values as properties. To do so you will need to create an interface for your configuration (optional) and a wrapper class for RuntimeConfig to expose your properties import { LibraryConfiguration , RuntimeConfig } from \"@pnp/core\" ; // first we create our own interface by extending LibraryConfiguration. This allows your class to accept all the values with correct type checking. Note, because // TypeScript allows you to extend from multiple interfaces you can build a complex configuration definition from many sub definitions. // create the interface of your properties // by creating this separately you allows others to compose your parts into their own config interface MyConfigurationPart { // you can create a grouped definition and access your settings as an object // keys can be optional or required as defined by your interface my ?: { prop1? : string ; prop2? : string ; } // and/or define multiple top level properties (beware key collision) // it is good practice to use a unique prefix myProp1 : string ; myProp2 : number ; } // now create a combined interface interface MyConfiguration extends LibraryConfiguration , MyConfigurationPart { } // now create a wrapper object and expose your properties class MyRuntimeConfigImpl { // exposing a nested property public get prop1 () : TypedHash < string > { const myPart = RuntimeConfig . get ( \"my\" ); if ( myPart !== null && typeof myPart !== \"undefined\" && typeof myPart . prop1 !== \"undefined\" ) { return myPart . prop1 ; } return {}; } // exposing a root level property public get myProp1 () : string | null { let myProp1 = RuntimeConfig . get ( \"myProp1\" ); if ( myProp1 === null ) { myProp1 = \"some default value\" ; } return myProp1 ; } setup ( config : MyConfiguration ) : void { RuntimeConfig . extend ( config ); } } // create a single static instance of your impl class export let MyRuntimeConfig = new MyRuntimeConfigImpl (); Now in other files you can use and set your configuration with a typed interface and properties import { MyRuntimeConfig } from \"{location of module}\" ; MyRuntimeConfig . setup ({ my : { prop1 : \"hello\" , }, }); const value = MyRuntimeConfig . prop1 ; // \"hello\"","title":"libconfig"},{"location":"common/docs/libconfig/#pnpcommonlibconfig","text":"Contains the shared classes and interfaces used to configure the libraries. These bases classes are expanded on in dependent libraries with the core configuration defined here. This module exposes an instance of the RuntimeConfigImpl class: RuntimeConfig. This configuration object can be referenced and contains the global configuration shared across the libraries. You can also extend the configuration for use within your own applications.","title":"@pnp/core/libconfig"},{"location":"common/docs/libconfig/#libraryconfiguration-interface","text":"Defines the shared configurable values used across the library as shown below. Each of these has a default value as shown below export interface LibraryConfiguration { /** * Allows caching to be global disabled, default: false */ globalCacheDisable? : boolean ; /** * Defines the default store used by the usingCaching method, default: session */ defaultCachingStore ?: \"session\" | \"local\" ; /** * Defines the default timeout in seconds used by the usingCaching method, default 30 */ defaultCachingTimeoutSeconds? : number ; /** * If true a timeout expired items will be removed from the cache in intervals determined by cacheTimeoutInterval */ enableCacheExpiration? : boolean ; /** * Determines the interval in milliseconds at which the cache is checked to see if items have expired (min: 100) */ cacheExpirationIntervalMilliseconds? : number ; /** * Used to supply the current context from an SPFx webpart to the library */ spfxContext? : any ; }","title":"LibraryConfiguration Interface"},{"location":"common/docs/libconfig/#runtimeconfigimpl","text":"The class which implements the runtime configuration management as well as sets the default values used within the library. At its heart lies a Dictionary used to track the configuration values. The keys will match the values in the interface or plain object passed to the extend method.","title":"RuntimeConfigImpl"},{"location":"common/docs/libconfig/#extend","text":"The extend method is used to add configuration to the global configuration instance. You can pass it any plain object with string keys and those values will be added. Any existing values will be overwritten based on the keys. Last value in wins. For a more detailed scenario of using the RuntimeConfig instance in your own application please see the section below \"Using RuntimeConfig within your application\". Note there are no methods to remove/clear the global config as it should be considered fairly static as frequent updates may have unpredictable side effects as it is a global shared object. Generally it should be set at the start of your application. import { RuntimeConfig } from \"@pnp/core\" ; // add your custom keys to the global configuration // note you can use object hashes as values RuntimeConfig . extend ({ \"myKey1\" : \"value 1\" , \"myKey2\" : { \"subKey\" : \"sub value 1\" , \"subKey2\" : \"sub value 2\" , }, }); // read your custom values const v = RuntimeConfig . get ( \"myKey1\" ); // \"value 1\"","title":"extend"},{"location":"common/docs/libconfig/#using-runtimeconfig-within-your-application","text":"If you have a set of properties you will access very frequently it may be desirable to implement your own configuration object and expose those values as properties. To do so you will need to create an interface for your configuration (optional) and a wrapper class for RuntimeConfig to expose your properties import { LibraryConfiguration , RuntimeConfig } from \"@pnp/core\" ; // first we create our own interface by extending LibraryConfiguration. This allows your class to accept all the values with correct type checking. Note, because // TypeScript allows you to extend from multiple interfaces you can build a complex configuration definition from many sub definitions. // create the interface of your properties // by creating this separately you allows others to compose your parts into their own config interface MyConfigurationPart { // you can create a grouped definition and access your settings as an object // keys can be optional or required as defined by your interface my ?: { prop1? : string ; prop2? : string ; } // and/or define multiple top level properties (beware key collision) // it is good practice to use a unique prefix myProp1 : string ; myProp2 : number ; } // now create a combined interface interface MyConfiguration extends LibraryConfiguration , MyConfigurationPart { } // now create a wrapper object and expose your properties class MyRuntimeConfigImpl { // exposing a nested property public get prop1 () : TypedHash < string > { const myPart = RuntimeConfig . get ( \"my\" ); if ( myPart !== null && typeof myPart !== \"undefined\" && typeof myPart . prop1 !== \"undefined\" ) { return myPart . prop1 ; } return {}; } // exposing a root level property public get myProp1 () : string | null { let myProp1 = RuntimeConfig . get ( \"myProp1\" ); if ( myProp1 === null ) { myProp1 = \"some default value\" ; } return myProp1 ; } setup ( config : MyConfiguration ) : void { RuntimeConfig . extend ( config ); } } // create a single static instance of your impl class export let MyRuntimeConfig = new MyRuntimeConfigImpl (); Now in other files you can use and set your configuration with a typed interface and properties import { MyRuntimeConfig } from \"{location of module}\" ; MyRuntimeConfig . setup ({ my : { prop1 : \"hello\" , }, }); const value = MyRuntimeConfig . prop1 ; // \"hello\"","title":"Using RuntimeConfig within your Application"},{"location":"common/docs/netutil/","text":"@pnp/core/netutil \u00b6 This module contains a set of classes and interfaces used to characterize shared http interactions and configuration of the libraries. Some of the interfaces are described below (many have no use outside the library) as well as several classes. Interfaces \u00b6 HttpClientImpl \u00b6 Defines an implementation of an Http Client within the context of @pnp. This being a class with a a single method \"fetch\" take a URL and options and returning a Promise . Used primarily with the shared request pipeline to define the client used to make the actual request. You can write your own custom implementation if needed. RequestClient \u00b6 An abstraction that contains specific methods related to each of the primary request methods get, post, patch, delete as well as fetch and fetchRaw. The difference between fetch and fetchRaw is that a client may include additional logic or processing in fetch, where fetchRaw should be a direct call to the underlying HttpClientImpl fetch method. Classes \u00b6 This module export two classes of note, FetchClient and BearerTokenFetchClient. Both implement HttpClientImpl. FetchClient \u00b6 Basic implementation that calls the global (window) fetch method with no additional processing. import { FetchClient } from \"@pnp/core\" ; const client = new FetchClient (); client . fetch ( \"{url}\" , {}); BearerTokenFetchClient \u00b6 A simple implementation that takes a provided authentication token and adds the Authentication Bearer header to the request. No other processing is done and the token is treated as a static string. import { BearerTokenFetchClient } from \"@pnp/core\" ; const client = new BearerTokenFetchClient ( \"{authentication token}\" ); client . fetch ( \"{url}\" , {});","title":"netutil"},{"location":"common/docs/netutil/#pnpcommonnetutil","text":"This module contains a set of classes and interfaces used to characterize shared http interactions and configuration of the libraries. Some of the interfaces are described below (many have no use outside the library) as well as several classes.","title":"@pnp/core/netutil"},{"location":"common/docs/netutil/#interfaces","text":"","title":"Interfaces"},{"location":"common/docs/netutil/#httpclientimpl","text":"Defines an implementation of an Http Client within the context of @pnp. This being a class with a a single method \"fetch\" take a URL and options and returning a Promise . Used primarily with the shared request pipeline to define the client used to make the actual request. You can write your own custom implementation if needed.","title":"HttpClientImpl"},{"location":"common/docs/netutil/#requestclient","text":"An abstraction that contains specific methods related to each of the primary request methods get, post, patch, delete as well as fetch and fetchRaw. The difference between fetch and fetchRaw is that a client may include additional logic or processing in fetch, where fetchRaw should be a direct call to the underlying HttpClientImpl fetch method.","title":"RequestClient"},{"location":"common/docs/netutil/#classes","text":"This module export two classes of note, FetchClient and BearerTokenFetchClient. Both implement HttpClientImpl.","title":"Classes"},{"location":"common/docs/netutil/#fetchclient","text":"Basic implementation that calls the global (window) fetch method with no additional processing. import { FetchClient } from \"@pnp/core\" ; const client = new FetchClient (); client . fetch ( \"{url}\" , {});","title":"FetchClient"},{"location":"common/docs/netutil/#bearertokenfetchclient","text":"A simple implementation that takes a provided authentication token and adds the Authentication Bearer header to the request. No other processing is done and the token is treated as a static string. import { BearerTokenFetchClient } from \"@pnp/core\" ; const client = new BearerTokenFetchClient ( \"{authentication token}\" ); client . fetch ( \"{url}\" , {});","title":"BearerTokenFetchClient"},{"location":"common/docs/storage/","text":"@pnp/core/storage \u00b6 This module provides a thin wrapper over the browser storage options, local and session. If neither option is available it shims storage with a non-persistent in memory polyfill. Optionally through configuration you can activate expiration. Sample usage is shown below. PnPClientStorage \u00b6 The main export of this module, contains properties representing local and session storage. import { PnPClientStorage } from \"@pnp/core\" ; const storage = new PnPClientStorage (); const myvalue = storage . local . get ( \"mykey\" ); PnPClientStorageWrapper \u00b6 Each of the storage locations (session and local) are wrapped with this helper class. You can use it directly, but generally it would be used from an instance of PnPClientStorage as shown below. These examples all use local storage, the operations are identical for session storage. import { PnPClientStorage } from \"@pnp/core\" ; const storage = new PnPClientStorage (); // get a value from storage const value = storage . local . get ( \"mykey\" ); // put a value into storage storage . local . put ( \"mykey2\" , \"my value\" ); // put a value into storage with an expiration storage . local . put ( \"mykey2\" , \"my value\" , new Date ()); // put a simple object into storage // because JSON.stringify is used to package the object we do NOT do a deep rehydration of stored objects storage . local . put ( \"mykey3\" , { key : \"value\" , key2 : \"value2\" , }); // remove a value from storage storage . local . delete ( \"mykey3\" ); // get an item or add it if it does not exist // returns a promise in case you need time to get the value for storage // optionally takes a third parameter specifying the expiration storage . local . getOrPut ( \"mykey4\" , () => { return Promise . resolve ( \"value\" ); }); // delete expired items storage . local . deleteExpired (); Cache Expiration \u00b6 The ability remove of expired items based on a configured timeout can help if the cache is filling up. This can be accomplished in two ways. The first is to explicitly call the new deleteExpired method on the cache you wish to clear. A suggested usage is to add this into your page init code as clearing expired items once per page load is likely sufficient. import { PnPClientStorage } from \"@pnp/core\" ; const storage = new PnPClientStorage (); // session storage storage . session . deleteExpired (); // local storage storage . local . deleteExpired (); // this returns a promise, so you can perform some activity after the expired items are removed: storage . local . deleteExpired (). then ( _ => { // init my application }); The second method is to enable automated cache expiration through global config. Setting the enableCacheExpiration property to true will enable the timer. Optionally you can set the interval at which the cache is checked via the cacheExpirationIntervalMilliseconds property, by default 750 milliseconds is used. We enforce a minimum of 300 milliseconds as this functionality is enabled via setTimeout and there is little value in having an excessive number of cache checks. This method is more appropriate for a single page application where the page is infrequently reloaded and many cached operations are performed. There is no advantage to enabling cache expiration unless you are experiencing cache storage space pressure in a long running page - and you may see a performance hit due to the use of setTimeout. import { setup } from \"@pnp/core\" ; setup ({ enableCacheExpiration : true , cacheExpirationIntervalMilliseconds : 1000 , // optional });","title":"storage"},{"location":"common/docs/storage/#pnpcommonstorage","text":"This module provides a thin wrapper over the browser storage options, local and session. If neither option is available it shims storage with a non-persistent in memory polyfill. Optionally through configuration you can activate expiration. Sample usage is shown below.","title":"@pnp/core/storage"},{"location":"common/docs/storage/#pnpclientstorage","text":"The main export of this module, contains properties representing local and session storage. import { PnPClientStorage } from \"@pnp/core\" ; const storage = new PnPClientStorage (); const myvalue = storage . local . get ( \"mykey\" );","title":"PnPClientStorage"},{"location":"common/docs/storage/#pnpclientstoragewrapper","text":"Each of the storage locations (session and local) are wrapped with this helper class. You can use it directly, but generally it would be used from an instance of PnPClientStorage as shown below. These examples all use local storage, the operations are identical for session storage. import { PnPClientStorage } from \"@pnp/core\" ; const storage = new PnPClientStorage (); // get a value from storage const value = storage . local . get ( \"mykey\" ); // put a value into storage storage . local . put ( \"mykey2\" , \"my value\" ); // put a value into storage with an expiration storage . local . put ( \"mykey2\" , \"my value\" , new Date ()); // put a simple object into storage // because JSON.stringify is used to package the object we do NOT do a deep rehydration of stored objects storage . local . put ( \"mykey3\" , { key : \"value\" , key2 : \"value2\" , }); // remove a value from storage storage . local . delete ( \"mykey3\" ); // get an item or add it if it does not exist // returns a promise in case you need time to get the value for storage // optionally takes a third parameter specifying the expiration storage . local . getOrPut ( \"mykey4\" , () => { return Promise . resolve ( \"value\" ); }); // delete expired items storage . local . deleteExpired ();","title":"PnPClientStorageWrapper"},{"location":"common/docs/storage/#cache-expiration","text":"The ability remove of expired items based on a configured timeout can help if the cache is filling up. This can be accomplished in two ways. The first is to explicitly call the new deleteExpired method on the cache you wish to clear. A suggested usage is to add this into your page init code as clearing expired items once per page load is likely sufficient. import { PnPClientStorage } from \"@pnp/core\" ; const storage = new PnPClientStorage (); // session storage storage . session . deleteExpired (); // local storage storage . local . deleteExpired (); // this returns a promise, so you can perform some activity after the expired items are removed: storage . local . deleteExpired (). then ( _ => { // init my application }); The second method is to enable automated cache expiration through global config. Setting the enableCacheExpiration property to true will enable the timer. Optionally you can set the interval at which the cache is checked via the cacheExpirationIntervalMilliseconds property, by default 750 milliseconds is used. We enforce a minimum of 300 milliseconds as this functionality is enabled via setTimeout and there is little value in having an excessive number of cache checks. This method is more appropriate for a single page application where the page is infrequently reloaded and many cached operations are performed. There is no advantage to enabling cache expiration unless you are experiencing cache storage space pressure in a long running page - and you may see a performance hit due to the use of setTimeout. import { setup } from \"@pnp/core\" ; setup ({ enableCacheExpiration : true , cacheExpirationIntervalMilliseconds : 1000 , // optional });","title":"Cache Expiration"},{"location":"common/docs/util/","text":"@pnp/core/util \u00b6 This module contains utility methods that you can import individually from the common library. import { getRandomString , } from \"@pnp/core\" ; // use from individual;y imported method console . log ( getRandomString ( 10 )); getCtxCallback \u00b6 Gets a callback function which will maintain context across async calls. import { getCtxCallback } from \"@pnp/core\" ; const contextThis = { myProp : 6 , }; function theFunction() { // \"this\" within this function will be the context object supplied // in this case the variable contextThis, so myProp will exist return this . myProp ; } const callback = getCtxCallback ( contextThis , theFunction ); callback (); // returns 6 // You can also supply additional parameters if needed function theFunction2 ( g : number ) { // \"this\" within this function will be the context object supplied // in this case the variable contextThis, so myProp will exist return this . myProp + g ; } const callback2 = getCtxCallback ( contextThis , theFunction , 4 ); callback2 (); // returns 10 (6 + 4) dateAdd \u00b6 Manipulates a date, please see the Stackoverflow discussion from where this method was taken. combine \u00b6 Combines any number of paths, normalizing the slashes as required import { combine } from \"@pnp/core\" ; // \"https://microsoft.com/something/more\" const paths = combine ( \"https://microsoft.com\" , \"something\" , \"more\" ); // \"also/works/with/relative\" const paths2 = combine ( \"/also/\" , \"/works\" , \"with/\" , \"/relative\\\\\" ); getRandomString \u00b6 Gets a random string consisting of the number of characters requested. import { getRandomString } from \"@pnp/core\" ; const randomString = getRandomString ( 10 ); getGUID \u00b6 Creates a random guid, please see the Stackoverflow discussion from where this method was taken. isFunc \u00b6 Determines if a supplied variable represents a function. objectDefinedNotNull \u00b6 Determines if an object is defined and not null. isArray \u00b6 Determines if a supplied variable represents an array. extend \u00b6 Merges a source object's own enumerable properties into a single target object. Similar to Object.assign, but allows control of overwriting of existing properties. import { extend } from \"@pnp/core\" ; let obj1 = { prop : 1 , prop2 : 2 , }; const obj2 = { prop : 4 , prop3 : 9 , }; const example1 = extend ( obj1 , obj2 ); // example1 = { prop: 4, prop2: 2, prop3: 9 } const example2 = extend ( obj1 , obj2 , true ); // example2 = { prop: 1, prop2: 2, prop3: 9 } isUrlAbsolute \u00b6 Determines if a supplied url is absolute and returns true; otherwise returns false. stringIsNullOrEmpty \u00b6 Determines if a supplied string is null or empty Removed \u00b6 Some methods that were no longer used internally by the @pnp libraries have been removed. You can find the source for those methods below for use in your projects should you require. /** * Loads a stylesheet into the current page * * @param path The url to the stylesheet * @param avoidCache If true a value will be appended as a query string to avoid browser caching issues */ public static loadStylesheet ( path : string , avoidCache : boolean ) : void { if ( avoidCache ) { path += \"?\" + encodeURIComponent (( new Date ()). getTime (). toString ()); } const head = document . getElementsByTagName ( \"head\" ); if ( head . length > 0 ) { const e = document . createElement ( \"link\" ); head [ 0 ]. appendChild ( e ); e . setAttribute ( \"type\" , \"text/css\" ); e . setAttribute ( \"rel\" , \"stylesheet\" ); e . setAttribute ( \"href\" , path ); } } /** * Tests if a url param exists * * @param name The name of the url parameter to check */ public static urlParamExists ( name : string ) : boolean { name = name . replace ( /[\\[]/ , \"\\\\[\" ). replace ( /[\\]]/ , \"\\\\]\" ); const regex = new RegExp ( \"[\\\\?&]\" + name + \"=([^&#]*)\" ); return regex . test ( location . search ); } /** * Gets a url param value by name * * @param name The name of the parameter for which we want the value */ public static getUrlParamByName ( name : string ) : string { name = name . replace ( /[\\[]/ , \"\\\\[\" ). replace ( /[\\]]/ , \"\\\\]\" ); const regex = new RegExp ( \"[\\\\?&]\" + name + \"=([^&#]*)\" ); const results = regex . exec ( location . search ); return results == null ? \"\" : decodeURIComponent ( results [ 1 ]. replace ( /\\+/g , \" \" )); } /** * Gets a url param by name and attempts to parse a bool value * * @param name The name of the parameter for which we want the boolean value */ public static getUrlParamBoolByName ( name : string ) : boolean { const p = this . getUrlParamByName ( name ); const isFalse = ( p === \"\" || /false|0/i . test ( p )); return ! isFalse ; } /** * Inserts the string s into the string target as the index specified by index * * @param target The string into which we will insert s * @param index The location in target to insert s (zero based) * @param s The string to insert into target at position index */ public static stringInsert ( target : string , index : number , s : string ) : string { if ( index > 0 ) { return target . substring ( 0 , index ) + s + target . substring ( index , target . length ); } return s + target ; }","title":"util"},{"location":"common/docs/util/#pnpcommonutil","text":"This module contains utility methods that you can import individually from the common library. import { getRandomString , } from \"@pnp/core\" ; // use from individual;y imported method console . log ( getRandomString ( 10 ));","title":"@pnp/core/util"},{"location":"common/docs/util/#getctxcallback","text":"Gets a callback function which will maintain context across async calls. import { getCtxCallback } from \"@pnp/core\" ; const contextThis = { myProp : 6 , }; function theFunction() { // \"this\" within this function will be the context object supplied // in this case the variable contextThis, so myProp will exist return this . myProp ; } const callback = getCtxCallback ( contextThis , theFunction ); callback (); // returns 6 // You can also supply additional parameters if needed function theFunction2 ( g : number ) { // \"this\" within this function will be the context object supplied // in this case the variable contextThis, so myProp will exist return this . myProp + g ; } const callback2 = getCtxCallback ( contextThis , theFunction , 4 ); callback2 (); // returns 10 (6 + 4)","title":"getCtxCallback"},{"location":"common/docs/util/#dateadd","text":"Manipulates a date, please see the Stackoverflow discussion from where this method was taken.","title":"dateAdd"},{"location":"common/docs/util/#combine","text":"Combines any number of paths, normalizing the slashes as required import { combine } from \"@pnp/core\" ; // \"https://microsoft.com/something/more\" const paths = combine ( \"https://microsoft.com\" , \"something\" , \"more\" ); // \"also/works/with/relative\" const paths2 = combine ( \"/also/\" , \"/works\" , \"with/\" , \"/relative\\\\\" );","title":"combine"},{"location":"common/docs/util/#getrandomstring","text":"Gets a random string consisting of the number of characters requested. import { getRandomString } from \"@pnp/core\" ; const randomString = getRandomString ( 10 );","title":"getRandomString"},{"location":"common/docs/util/#getguid","text":"Creates a random guid, please see the Stackoverflow discussion from where this method was taken.","title":"getGUID"},{"location":"common/docs/util/#isfunc","text":"Determines if a supplied variable represents a function.","title":"isFunc"},{"location":"common/docs/util/#objectdefinednotnull","text":"Determines if an object is defined and not null.","title":"objectDefinedNotNull"},{"location":"common/docs/util/#isarray","text":"Determines if a supplied variable represents an array.","title":"isArray"},{"location":"common/docs/util/#extend","text":"Merges a source object's own enumerable properties into a single target object. Similar to Object.assign, but allows control of overwriting of existing properties. import { extend } from \"@pnp/core\" ; let obj1 = { prop : 1 , prop2 : 2 , }; const obj2 = { prop : 4 , prop3 : 9 , }; const example1 = extend ( obj1 , obj2 ); // example1 = { prop: 4, prop2: 2, prop3: 9 } const example2 = extend ( obj1 , obj2 , true ); // example2 = { prop: 1, prop2: 2, prop3: 9 }","title":"extend"},{"location":"common/docs/util/#isurlabsolute","text":"Determines if a supplied url is absolute and returns true; otherwise returns false.","title":"isUrlAbsolute"},{"location":"common/docs/util/#stringisnullorempty","text":"Determines if a supplied string is null or empty","title":"stringIsNullOrEmpty"},{"location":"common/docs/util/#removed","text":"Some methods that were no longer used internally by the @pnp libraries have been removed. You can find the source for those methods below for use in your projects should you require. /** * Loads a stylesheet into the current page * * @param path The url to the stylesheet * @param avoidCache If true a value will be appended as a query string to avoid browser caching issues */ public static loadStylesheet ( path : string , avoidCache : boolean ) : void { if ( avoidCache ) { path += \"?\" + encodeURIComponent (( new Date ()). getTime (). toString ()); } const head = document . getElementsByTagName ( \"head\" ); if ( head . length > 0 ) { const e = document . createElement ( \"link\" ); head [ 0 ]. appendChild ( e ); e . setAttribute ( \"type\" , \"text/css\" ); e . setAttribute ( \"rel\" , \"stylesheet\" ); e . setAttribute ( \"href\" , path ); } } /** * Tests if a url param exists * * @param name The name of the url parameter to check */ public static urlParamExists ( name : string ) : boolean { name = name . replace ( /[\\[]/ , \"\\\\[\" ). replace ( /[\\]]/ , \"\\\\]\" ); const regex = new RegExp ( \"[\\\\?&]\" + name + \"=([^&#]*)\" ); return regex . test ( location . search ); } /** * Gets a url param value by name * * @param name The name of the parameter for which we want the value */ public static getUrlParamByName ( name : string ) : string { name = name . replace ( /[\\[]/ , \"\\\\[\" ). replace ( /[\\]]/ , \"\\\\]\" ); const regex = new RegExp ( \"[\\\\?&]\" + name + \"=([^&#]*)\" ); const results = regex . exec ( location . search ); return results == null ? \"\" : decodeURIComponent ( results [ 1 ]. replace ( /\\+/g , \" \" )); } /** * Gets a url param by name and attempts to parse a bool value * * @param name The name of the parameter for which we want the boolean value */ public static getUrlParamBoolByName ( name : string ) : boolean { const p = this . getUrlParamByName ( name ); const isFalse = ( p === \"\" || /false|0/i . test ( p )); return ! isFalse ; } /** * Inserts the string s into the string target as the index specified by index * * @param target The string into which we will insert s * @param index The location in target to insert s (zero based) * @param s The string to insert into target at position index */ public static stringInsert ( target : string , index : number , s : string ) : string { if ( index > 0 ) { return target . substring ( 0 , index ) + s + target . substring ( index , target . length ); } return s + target ; }","title":"Removed"},{"location":"config-store/docs/","text":"@pnp/config-store \u00b6 This module providers a way to load application configuration from one or more providers and share it across an application in a consistent way. A provider can be anything - but we have included one to load information from a SharePoint list. This library is most helpful for larger applications where a formal configuration model is needed. Getting Started \u00b6 Install the library and required dependencies npm install @pnp/logging @pnp/core @pnp/queryable @pnp/sp @pnp/config-store --save See the topics below for usage: configuration providers UML \u00b6 Graphical UML diagram of @pnp/config-store. Right-click the diagram and open in new tab if it is too small.","title":"config-store"},{"location":"config-store/docs/#pnpconfig-store","text":"This module providers a way to load application configuration from one or more providers and share it across an application in a consistent way. A provider can be anything - but we have included one to load information from a SharePoint list. This library is most helpful for larger applications where a formal configuration model is needed.","title":"@pnp/config-store"},{"location":"config-store/docs/#getting-started","text":"Install the library and required dependencies npm install @pnp/logging @pnp/core @pnp/queryable @pnp/sp @pnp/config-store --save See the topics below for usage: configuration providers","title":"Getting Started"},{"location":"config-store/docs/#uml","text":"Graphical UML diagram of @pnp/config-store. Right-click the diagram and open in new tab if it is too small.","title":"UML"},{"location":"config-store/docs/configuration/","text":"@pnp/config-store/configuration \u00b6 The main class exported from the config-store package is Settings. This is the class through which you will load and access your settings via providers . import { Web } from \"@pnp/sp\" ; import { Settings , SPListConfigurationProvider } from \"@pnp/config-store\" ; // create an instance of the settings class, could be static and shared across your application // or built as needed. const settings = new Settings (); // you can add/update a single value using add settings . add ( \"mykey\" , \"myvalue\" ); // you can also add/update a JSON value which will be stringified for you as a shorthand settings . addJSON ( \"mykey2\" , { field : 1 , field2 : 2 , field3 : 3 , }); // and you can apply a plain object of keys/values that will be written as single values // this results in each enumerable property of the supplied object being added to the settings collection settings . apply ({ field : 1 , field2 : 2 , field3 : 3 , }); // and finally you can load values from a configuration provider const w = new Web ( \"https://mytenant.sharepoint.com/sites/dev\" ); const provider = new SPListConfigurationProvider ( w , \"myconfiglistname\" ); // this will load values from the supplied list // by default the key will be from the Title field and the value from a column named Value await settings . load ( provider ); // once we have loaded values we can then read them const value = settings . get ( \"mykey\" ); // or read JSON that will be parsed for you from the store const value2 = settings . getJSON ( \"mykey2\" );","title":"configuration"},{"location":"config-store/docs/configuration/#pnpconfig-storeconfiguration","text":"The main class exported from the config-store package is Settings. This is the class through which you will load and access your settings via providers . import { Web } from \"@pnp/sp\" ; import { Settings , SPListConfigurationProvider } from \"@pnp/config-store\" ; // create an instance of the settings class, could be static and shared across your application // or built as needed. const settings = new Settings (); // you can add/update a single value using add settings . add ( \"mykey\" , \"myvalue\" ); // you can also add/update a JSON value which will be stringified for you as a shorthand settings . addJSON ( \"mykey2\" , { field : 1 , field2 : 2 , field3 : 3 , }); // and you can apply a plain object of keys/values that will be written as single values // this results in each enumerable property of the supplied object being added to the settings collection settings . apply ({ field : 1 , field2 : 2 , field3 : 3 , }); // and finally you can load values from a configuration provider const w = new Web ( \"https://mytenant.sharepoint.com/sites/dev\" ); const provider = new SPListConfigurationProvider ( w , \"myconfiglistname\" ); // this will load values from the supplied list // by default the key will be from the Title field and the value from a column named Value await settings . load ( provider ); // once we have loaded values we can then read them const value = settings . get ( \"mykey\" ); // or read JSON that will be parsed for you from the store const value2 = settings . getJSON ( \"mykey2\" );","title":"@pnp/config-store/configuration"},{"location":"config-store/docs/providers/","text":"@pnp/config-store/providers \u00b6 Currently there is a single provider included in the library, but contributions of additional providers are welcome. SPListConfigurationProvider \u00b6 This provider is based on a SharePoint list and read all of the rows and makes them available as a TypedHash . By default the column names used are Title for key and \"Value\" for value, but you can update these as needed. Additionally the settings class supports the idea of last value in wins - so you can easily load multiple configurations. This helps to support a common scenario in the enterprise where you might have one main list for global configuration but some settings can be set at the web level. In this case you would first load the global, then the local settings and any local values will take precedence. import { Web } from \"@pnp/sp\" ; import { Settings , SPListConfigurationProvider } from \"@pnp/config-store\" ; // create a new provider instance const w = new Web ( \"https://mytenant.sharepoint.com/sites/dev\" ); const provider = new SPListConfigurationProvider ( w , \"myconfiglistname\" ); const settings = new Settings (); // load our values from the list await settings . load ( provider ); CachingConfigurationProvider \u00b6 Because making requests on each page load is very inefficient you can optionally use the caching configuration provider, which wraps a provider and caches the configuration in local or session storage. import { Web } from \"@pnp/sp\" ; import { Settings , SPListConfigurationProvider } from \"@pnp/config-store\" ; // create a new provider instance const w = new Web ( \"https://mytenant.sharepoint.com/sites/dev\" ); const provider = new SPListConfigurationProvider ( w , \"myconfiglistname\" ); // get an instance of the provider wrapped // you can optionally provide a key that will be used in the cache to the asCaching method const wrappedProvider = provider . asCaching (); // use that wrapped provider to populate the settings await settings . load ( wrappedProvider );","title":"providers"},{"location":"config-store/docs/providers/#pnpconfig-storeproviders","text":"Currently there is a single provider included in the library, but contributions of additional providers are welcome.","title":"@pnp/config-store/providers"},{"location":"config-store/docs/providers/#splistconfigurationprovider","text":"This provider is based on a SharePoint list and read all of the rows and makes them available as a TypedHash . By default the column names used are Title for key and \"Value\" for value, but you can update these as needed. Additionally the settings class supports the idea of last value in wins - so you can easily load multiple configurations. This helps to support a common scenario in the enterprise where you might have one main list for global configuration but some settings can be set at the web level. In this case you would first load the global, then the local settings and any local values will take precedence. import { Web } from \"@pnp/sp\" ; import { Settings , SPListConfigurationProvider } from \"@pnp/config-store\" ; // create a new provider instance const w = new Web ( \"https://mytenant.sharepoint.com/sites/dev\" ); const provider = new SPListConfigurationProvider ( w , \"myconfiglistname\" ); const settings = new Settings (); // load our values from the list await settings . load ( provider );","title":"SPListConfigurationProvider"},{"location":"config-store/docs/providers/#cachingconfigurationprovider","text":"Because making requests on each page load is very inefficient you can optionally use the caching configuration provider, which wraps a provider and caches the configuration in local or session storage. import { Web } from \"@pnp/sp\" ; import { Settings , SPListConfigurationProvider } from \"@pnp/config-store\" ; // create a new provider instance const w = new Web ( \"https://mytenant.sharepoint.com/sites/dev\" ); const provider = new SPListConfigurationProvider ( w , \"myconfiglistname\" ); // get an instance of the provider wrapped // you can optionally provide a key that will be used in the cache to the asCaching method const wrappedProvider = provider . asCaching (); // use that wrapped provider to populate the settings await settings . load ( wrappedProvider );","title":"CachingConfigurationProvider"},{"location":"documentation/SPFx-On-Premesis-2016/","text":"Workaround for SPFx TypeScript Version \u00b6 Note this article applies to version 1.4.1 SharePoint Framework projects targetting on-premesis only. When using the Yeoman generator to create a SharePoint Framework 1.4.1 project targeting on-premesis it installs TypeScript version 2.2.2. Unfortunately this library relies on 2.4.2 or later due to extensive use of default values for generic type parameters in the libraries. To work around this limitation you can follow the steps in this article. Open package-lock.json Search for \"typescript\": \"2.2.2\" Replace \"2.2.2\" with \"2.4.2\" Search for the next \"typescript\" occurance and replace the block with: \"typescript\" : { \"version\" : \"2.4.2\" , \"resolved\" : \"https://registry.npmjs.org/typescript/-/typescript-2.4.2.tgz\" , \"integrity\" : \"sha1-+DlfhdRZJ2BnyYiqQYN6j4KHCEQ=\" , \"dev\" : true } Remove node_modules folder rm -rf node_modules/ Run npm install This can be checked with: npm list typescript +-- @microsoft/sp-build-web@1.1.0 | `-- @microsoft/gulp-core-build-typescript@3.1.1 | +-- @microsoft/api-extractor@2.3.8 | | `-- typescript@2.4.2 | `-- typescript@2.4.2","title":"SPFx On-Premises 2016"},{"location":"documentation/SPFx-On-Premesis-2016/#workaround-for-spfx-typescript-version","text":"Note this article applies to version 1.4.1 SharePoint Framework projects targetting on-premesis only. When using the Yeoman generator to create a SharePoint Framework 1.4.1 project targeting on-premesis it installs TypeScript version 2.2.2. Unfortunately this library relies on 2.4.2 or later due to extensive use of default values for generic type parameters in the libraries. To work around this limitation you can follow the steps in this article. Open package-lock.json Search for \"typescript\": \"2.2.2\" Replace \"2.2.2\" with \"2.4.2\" Search for the next \"typescript\" occurance and replace the block with: \"typescript\" : { \"version\" : \"2.4.2\" , \"resolved\" : \"https://registry.npmjs.org/typescript/-/typescript-2.4.2.tgz\" , \"integrity\" : \"sha1-+DlfhdRZJ2BnyYiqQYN6j4KHCEQ=\" , \"dev\" : true } Remove node_modules folder rm -rf node_modules/ Run npm install This can be checked with: npm list typescript +-- @microsoft/sp-build-web@1.1.0 | `-- @microsoft/gulp-core-build-typescript@3.1.1 | +-- @microsoft/api-extractor@2.3.8 | | `-- typescript@2.4.2 | `-- typescript@2.4.2","title":"Workaround for SPFx TypeScript Version"},{"location":"documentation/beta-versions/","text":"Beta Versions \u00b6 To help folks try out new features early and provide feedback prior to releases we publish beta versions of the packages. Released as a set with matching version numbers, just like when we do a normal release. Generally every Friday a new set of beta libraries will be released. While not ready for production use we encourage you to try out these pre-release packages and provide us feedback. Installing \u00b6 To install the beta packages in your project you use the @beta version number on the packages. This applies to all packages, not just the ones shown in the example below. npm install @pnp/logging@beta @pnp/core@beta @pnp/queryable@beta @pnp/sp@beta --save Please remember that it is possible something may not work in a beta version, so be aware and if you find something please report an issue .","title":"Install Beta Versions"},{"location":"documentation/beta-versions/#beta-versions","text":"To help folks try out new features early and provide feedback prior to releases we publish beta versions of the packages. Released as a set with matching version numbers, just like when we do a normal release. Generally every Friday a new set of beta libraries will be released. While not ready for production use we encourage you to try out these pre-release packages and provide us feedback.","title":"Beta Versions"},{"location":"documentation/beta-versions/#installing","text":"To install the beta packages in your project you use the @beta version number on the packages. This applies to all packages, not just the ones shown in the example below. npm install @pnp/logging@beta @pnp/core@beta @pnp/queryable@beta @pnp/sp@beta --save Please remember that it is possible something may not work in a beta version, so be aware and if you find something please report an issue .","title":"Installing"},{"location":"documentation/debugging/","text":"Debugging \u00b6 Debugging Library Features in Code using Node \u00b6 The easiest way to debug the library when working on new features is using F5 in Visual Studio Code. This uses the launch.json file to build and run the library using ./debug/launch/main.ts as the program entry. You can add any number of files to this directory and they will be ignored by git, however the debug.ts file is not, so please ensure you don't commit any login information. Setup settings.js \u00b6 If you have not already you need to create a settings.js files by copying settings.example.js and renaming it to settings.js. Then update the clientId, clientSecret, and siteUrl fields in the testing section. (See below for guidance on registering a client id and secret) Test your setup \u00b6 If you hit F5 now you should be able to see the full response from getting the web's title in the internal console window. If not, ensure that you have properly updated the settings file and registered the add-in perms correctly. Create a debug module \u00b6 Using ./debug/launch/example.ts as a reference create a debugging file in the debug folder, let's call it mydebug.ts and add this content: // note we can use the actual package names for our imports import { sp , ListEnsureResult } from \"@pnp/sp\" ; import { Logger , LogLevel , ConsoleListener } from \"@pnp/logging\" ; declare var process : { exit ( code? : number ) : void }; export function MyDebug() { // run some debugging sp . web . lists . ensure ( \"MyFirstList\" ). then (( list : ListEnsureResult ) => { Logger . log ({ data : list.created , message : \"Was list created?\" , level : LogLevel.Verbose }); if ( list . created ) { Logger . log ({ data : list.data , message : \"Raw data from list creation.\" , level : LogLevel.Verbose }); } else { Logger . log ({ data : null , message : \"List already existed!\" , level : LogLevel.Verbose }); } process . exit ( 0 ); }). catch ( e => { Logger . error ( e ); process . exit ( 1 ); }); } Update main.ts to launch your module \u00b6 First comment out the import for the default example and then add the import and function call for yours, the updated main.ts should look like this: // ... // comment out the example // import { Example } from \"./example\"; // Example(); import { MyDebug } from \"./mydebug\" MyDebug (); // ... Debug! \u00b6 Place a break point within the promise resolution in your debug file and hit F5. Your module should be run and your break point hit. You can then examine the contents of the objects and see the run time state. Remember you can also set breakpoints within the package src folders to see exactly how things are working during your debugging scenarios. Next Steps \u00b6 Using this pattern you can create and preserve multiple debugging scenarios in separate modules locally. In Browser Debugging \u00b6 You can also serve files locally to debug in a browser through two methods. The first will serve code using ./debug/serve/main.ts as the entry. Meaning you can easily write code and test it in the browser. The second method allows you to serve a single package (bundled with all dependencies) for in browser testing. Both methods serve the file from https://localhost:8080/assets/pnp.js, allowing you to create a single page in your tenant for in browser testing. Start the local serve \u00b6 This will serve a package with ./debug/serve/main.ts as the entry. gulp serve Add reference to library \u00b6 Within a SharePoint page add a script editor web part and then paste in the following code. The div is to give you a place to target with visual updates should you desire. < script src = \"https://localhost:8080/assets/pnp.js\" ></ script > < div id = \"pnptestdiv\" ></ div > You should see an alert with the current web's title using the default main.ts. Feel free to update main.ts to do whatever you would like, but note that any changes included as part of a PR to this file will not be allowed. Serve a specific package \u00b6 For example if you wanted to serve the @pnp/sp package for testing you would use: gulp serve --p sp This will serve a bundle of the sp functionality along with all dependencies and place a global variable named \"pnp.{packagename}\", in this case pnp.sp. This will be true for each package, if you served just the graph package the global would be pnp.graph. This mirrors how the umd modules are built in the distributed npm packages to allow testing with matching packages. Next Steps \u00b6 You can make changes to the library and immediately see them reflected in the browser. All files are watched regardless of which serve method you choose. Register an Add-in \u00b6 Before you can begin debugging you need to register a low-trust add-in with SharePoint. This is primarily designed for Office 365, but can work on-premises if you configure your farm accordingly . Navigation to {site url}/_layouts/appregnew.aspx Click \"Generate\" for both the Client Id and Secret values Give you add-in a title, this can be anything but will let you locate it in the list of add-in permissions Provide a fake value for app domain and redirect uri, you can use the values shown in the examples Click \"Create\" Copy the returned block of text containing the client id and secret as well as app name for your records and later in this article. Grant Your Add-In Permissions \u00b6 Now that we have created an add-in registration we need to tell SharePoint what permissions it can use. Due to an update in SharePoint Online you now have to register add-ins with certain permissions in the admin site . Navigate to {admin site url}/_layouts/appinv.aspx Paste your client id from the above section into the Add Id box and click \"Lookup\" You should see the information populated into the form from the last section, if not ensure you have the correct id value Paste the below XML into the permissions request xml box and hit \"Create\" You should get a confirmation message. <AppPermissionRequests AllowAppOnlyPolicy= \"true\" > <AppPermissionRequest Scope= \"http://sharepoint/content/tenant\" Right= \"FullControl\" /> <AppPermissionRequest Scope= \"http://sharepoint/social/tenant\" Right= \"FullControl\" /> <AppPermissionRequest Scope= \"http://sharepoint/search\" Right= \"QueryAsUserIgnoreAppPrincipal\" /> </AppPermissionRequests> Note these are very broad permissions to ensure you can test any feature of the library, for production you should tailor the permissions to only those required Configure the project settings file \u00b6 If you have not already, make a copy of settings.example.js and name it settings.js Edit this file to set the values on the testing.sp object to id: \"The client id you created\" secret: \"The client secret you created\" url: \"{site url}\" You can disable web tests at any time by setting enableWebTests to false in settings.js, this can be helpful as they take a few minutes to run","title":"Debugging"},{"location":"documentation/debugging/#debugging","text":"","title":"Debugging"},{"location":"documentation/debugging/#debugging-library-features-in-code-using-node","text":"The easiest way to debug the library when working on new features is using F5 in Visual Studio Code. This uses the launch.json file to build and run the library using ./debug/launch/main.ts as the program entry. You can add any number of files to this directory and they will be ignored by git, however the debug.ts file is not, so please ensure you don't commit any login information.","title":"Debugging Library Features in Code using Node"},{"location":"documentation/debugging/#setup-settingsjs","text":"If you have not already you need to create a settings.js files by copying settings.example.js and renaming it to settings.js. Then update the clientId, clientSecret, and siteUrl fields in the testing section. (See below for guidance on registering a client id and secret)","title":"Setup settings.js"},{"location":"documentation/debugging/#test-your-setup","text":"If you hit F5 now you should be able to see the full response from getting the web's title in the internal console window. If not, ensure that you have properly updated the settings file and registered the add-in perms correctly.","title":"Test your setup"},{"location":"documentation/debugging/#create-a-debug-module","text":"Using ./debug/launch/example.ts as a reference create a debugging file in the debug folder, let's call it mydebug.ts and add this content: // note we can use the actual package names for our imports import { sp , ListEnsureResult } from \"@pnp/sp\" ; import { Logger , LogLevel , ConsoleListener } from \"@pnp/logging\" ; declare var process : { exit ( code? : number ) : void }; export function MyDebug() { // run some debugging sp . web . lists . ensure ( \"MyFirstList\" ). then (( list : ListEnsureResult ) => { Logger . log ({ data : list.created , message : \"Was list created?\" , level : LogLevel.Verbose }); if ( list . created ) { Logger . log ({ data : list.data , message : \"Raw data from list creation.\" , level : LogLevel.Verbose }); } else { Logger . log ({ data : null , message : \"List already existed!\" , level : LogLevel.Verbose }); } process . exit ( 0 ); }). catch ( e => { Logger . error ( e ); process . exit ( 1 ); }); }","title":"Create a debug module"},{"location":"documentation/debugging/#update-maints-to-launch-your-module","text":"First comment out the import for the default example and then add the import and function call for yours, the updated main.ts should look like this: // ... // comment out the example // import { Example } from \"./example\"; // Example(); import { MyDebug } from \"./mydebug\" MyDebug (); // ...","title":"Update main.ts to launch your module"},{"location":"documentation/debugging/#debug","text":"Place a break point within the promise resolution in your debug file and hit F5. Your module should be run and your break point hit. You can then examine the contents of the objects and see the run time state. Remember you can also set breakpoints within the package src folders to see exactly how things are working during your debugging scenarios.","title":"Debug!"},{"location":"documentation/debugging/#next-steps","text":"Using this pattern you can create and preserve multiple debugging scenarios in separate modules locally.","title":"Next Steps"},{"location":"documentation/debugging/#in-browser-debugging","text":"You can also serve files locally to debug in a browser through two methods. The first will serve code using ./debug/serve/main.ts as the entry. Meaning you can easily write code and test it in the browser. The second method allows you to serve a single package (bundled with all dependencies) for in browser testing. Both methods serve the file from https://localhost:8080/assets/pnp.js, allowing you to create a single page in your tenant for in browser testing.","title":"In Browser Debugging"},{"location":"documentation/debugging/#start-the-local-serve","text":"This will serve a package with ./debug/serve/main.ts as the entry. gulp serve","title":"Start the local serve"},{"location":"documentation/debugging/#add-reference-to-library","text":"Within a SharePoint page add a script editor web part and then paste in the following code. The div is to give you a place to target with visual updates should you desire. < script src = \"https://localhost:8080/assets/pnp.js\" ></ script > < div id = \"pnptestdiv\" ></ div > You should see an alert with the current web's title using the default main.ts. Feel free to update main.ts to do whatever you would like, but note that any changes included as part of a PR to this file will not be allowed.","title":"Add reference to library"},{"location":"documentation/debugging/#serve-a-specific-package","text":"For example if you wanted to serve the @pnp/sp package for testing you would use: gulp serve --p sp This will serve a bundle of the sp functionality along with all dependencies and place a global variable named \"pnp.{packagename}\", in this case pnp.sp. This will be true for each package, if you served just the graph package the global would be pnp.graph. This mirrors how the umd modules are built in the distributed npm packages to allow testing with matching packages.","title":"Serve a specific package"},{"location":"documentation/debugging/#next-steps_1","text":"You can make changes to the library and immediately see them reflected in the browser. All files are watched regardless of which serve method you choose.","title":"Next Steps"},{"location":"documentation/debugging/#register-an-add-in","text":"Before you can begin debugging you need to register a low-trust add-in with SharePoint. This is primarily designed for Office 365, but can work on-premises if you configure your farm accordingly . Navigation to {site url}/_layouts/appregnew.aspx Click \"Generate\" for both the Client Id and Secret values Give you add-in a title, this can be anything but will let you locate it in the list of add-in permissions Provide a fake value for app domain and redirect uri, you can use the values shown in the examples Click \"Create\" Copy the returned block of text containing the client id and secret as well as app name for your records and later in this article.","title":"Register an Add-in"},{"location":"documentation/debugging/#grant-your-add-in-permissions","text":"Now that we have created an add-in registration we need to tell SharePoint what permissions it can use. Due to an update in SharePoint Online you now have to register add-ins with certain permissions in the admin site . Navigate to {admin site url}/_layouts/appinv.aspx Paste your client id from the above section into the Add Id box and click \"Lookup\" You should see the information populated into the form from the last section, if not ensure you have the correct id value Paste the below XML into the permissions request xml box and hit \"Create\" You should get a confirmation message. <AppPermissionRequests AllowAppOnlyPolicy= \"true\" > <AppPermissionRequest Scope= \"http://sharepoint/content/tenant\" Right= \"FullControl\" /> <AppPermissionRequest Scope= \"http://sharepoint/social/tenant\" Right= \"FullControl\" /> <AppPermissionRequest Scope= \"http://sharepoint/search\" Right= \"QueryAsUserIgnoreAppPrincipal\" /> </AppPermissionRequests> Note these are very broad permissions to ensure you can test any feature of the library, for production you should tailor the permissions to only those required","title":"Grant Your Add-In Permissions"},{"location":"documentation/debugging/#configure-the-project-settings-file","text":"If you have not already, make a copy of settings.example.js and name it settings.js Edit this file to set the values on the testing.sp object to id: \"The client id you created\" secret: \"The client secret you created\" url: \"{site url}\" You can disable web tests at any time by setting enableWebTests to false in settings.js, this can be helpful as they take a few minutes to run","title":"Configure the project settings file"},{"location":"documentation/deployment/","text":"Deployment \u00b6 There are two recommended ways to consume the library in a production deployment: bundle the code into your solution (such as with webpack), or reference the code from a CDN. These methods are outlined here but this is not meant to be an exhaustive guide on all the ways to package and deploy solutions. Bundle \u00b6 If you have installed the library via NPM into your application solution bundlers such as webpack can bundle the PnPjs libraries along with your solution. This can make deployment easier, but will increase the size of your application by the size of the included libraries. The PnPjs libraries are setup to support tree shaking which can help with the bundle size. CDN \u00b6 If you have public internet access you can reference the library from cdnjs or unpkg which maintains copies of all versions. This is ideal as you do not need to host the file yourself, and it is easy to update to a newer release by updating the URL in your solution. Below lists all of the library locations within cdnjs, you will need to ensure you have the full url to the file you need, such as: \"https://cdnjs.cloudflare.com/ajax/libs/pnp-common/1.1.1/common.es5.umd.min.js\". To use the libraries with a script tag in a page it is recommended to use the *.es5.umd.min.js versions. This will add a global pnp value with each library added as pnp.{lib name} such as pnp.sp, pnp.common, etc. https://cdnjs.com/libraries/pnp-common https://cdnjs.com/libraries/pnp-config-store https://cdnjs.com/libraries/pnp-graph https://cdnjs.com/libraries/pnp-logging https://cdnjs.com/libraries/pnp-odata https://cdnjs.com/libraries/pnp-pnpjs https://cdnjs.com/libraries/pnp-sp https://cdnjs.com/libraries/pnp-sp-addinhelpers https://cdnjs.com/libraries/pnp-sp-clientsvc https://cdnjs.com/libraries/pnp-sp-taxonomy CDN and SPFx \u00b6 If you are developing in SPFx and install and import the PnPjs libraries the default behavior will be to bundle the library into your solution. You have a couple of choices on how best to work with CDNs and SPFx. Because SPFx doesn't currently respect peer dependencies it is easier to reference the pnpjs rollup package for your project. In this case you would install the package, reference it in your code, and update your config.js file externals as follows: Install \u00b6 npm install @pnp/pnpjs --save In Code \u00b6 import { sp } from \"@pnp/pnpjs\" ; sp . web . lists . getByTitle ( \"BigList\" ). get (). then ( r => { this . domElement . innerHTML += r . Title ; }); config.json \u00b6 \"externals\" : { \"@pnp/pnpjs\" : { \"path\" : \"https://cdnjs.cloudflare.com/ajax/libs/pnp-pnpjs/1.1.4/pnpjs.es5.umd.bundle.min.js\" , \"globalName\" : \"pnp\" } } , You can still work with the individual packages from a cdn, but you have a bit more work to do. First install the modules you need, update the config with the JSON externals below, and add some blind require statements into your code. These are needed because peer dependencies are not processed by SPFx so you have to \"trigger\" the SPFx manifest creator to include those packages. Note this approach requires using version 1.1.5 (specifically beta 1.1.5-2) or later of the libraries as we had make a few updates to how things are packaged to make this a little easier. Install \u00b6 npm install @pnp/logging @pnp/core @pnp/queryable @pnp/sp --save In Code \u00b6 // blind require statements require ( \"tslib\" ); require ( \"@pnp/logging\" ); require ( \"@pnp/core\" ); require ( \"@pnp/queryable\" ); import { sp } from \"@pnp/sp\" ; sp . web . lists . getByTitle ( \"BigList\" ). get (). then ( r => { this . domElement . innerHTML += r . Title ; }); config.json \u00b6 \"externals\" : { \"@pnp/sp\" : { \"path\" : \"https://unpkg.com/@pnp/sp@1.1.5-2/dist/sp.es5.umd.min.js\" , \"globalName\" : \"pnp.sp\" , \"globalDependencies\" : [ \"@pnp/logging\" , \"@pnp/core\" , \"@pnp/queryable\" , \"tslib\" ] }, \"@pnp/queryable\" : { \"path\" : \"https://unpkg.com/@pnp/queryable@1.1.5-2/dist/odata.es5.umd.min.js\" , \"globalName\" : \"pnp.odata\" , \"globalDependencies\" : [ \"@pnp/core\" , \"@pnp/logging\" , \"tslib\" ] }, \"@pnp/core\" : { \"path\" : \"https://unpkg.com/@pnp/core@1.1.5-2/dist/common.es5.umd.bundle.min.js\" , \"globalName\" : \"pnp.common\" }, \"@pnp/logging\" : { \"path\" : \"https://unpkg.com/@pnp/logging@1.1.5-2/dist/logging.es5.umd.min.js\" , \"globalName\" : \"pnp.logging\" , \"globalDependencies\" : [ \"tslib\" ] }, \"tslib\" : { \"path\" : \"https://cdnjs.cloudflare.com/ajax/libs/tslib/1.9.3/tslib.min.js\" , \"globalName\" : \"tslib\" } } Don't forget to update the version number in the url to match the version you want to use. This will stop the library from being bundled directly into the solution and instead use the copy from the CDN. When a new version of the PnPjs libraries are released and you are ready to update just update this url in your SPFX project's config.js file.","title":"Deployment"},{"location":"documentation/deployment/#deployment","text":"There are two recommended ways to consume the library in a production deployment: bundle the code into your solution (such as with webpack), or reference the code from a CDN. These methods are outlined here but this is not meant to be an exhaustive guide on all the ways to package and deploy solutions.","title":"Deployment"},{"location":"documentation/deployment/#bundle","text":"If you have installed the library via NPM into your application solution bundlers such as webpack can bundle the PnPjs libraries along with your solution. This can make deployment easier, but will increase the size of your application by the size of the included libraries. The PnPjs libraries are setup to support tree shaking which can help with the bundle size.","title":"Bundle"},{"location":"documentation/deployment/#cdn","text":"If you have public internet access you can reference the library from cdnjs or unpkg which maintains copies of all versions. This is ideal as you do not need to host the file yourself, and it is easy to update to a newer release by updating the URL in your solution. Below lists all of the library locations within cdnjs, you will need to ensure you have the full url to the file you need, such as: \"https://cdnjs.cloudflare.com/ajax/libs/pnp-common/1.1.1/common.es5.umd.min.js\". To use the libraries with a script tag in a page it is recommended to use the *.es5.umd.min.js versions. This will add a global pnp value with each library added as pnp.{lib name} such as pnp.sp, pnp.common, etc. https://cdnjs.com/libraries/pnp-common https://cdnjs.com/libraries/pnp-config-store https://cdnjs.com/libraries/pnp-graph https://cdnjs.com/libraries/pnp-logging https://cdnjs.com/libraries/pnp-odata https://cdnjs.com/libraries/pnp-pnpjs https://cdnjs.com/libraries/pnp-sp https://cdnjs.com/libraries/pnp-sp-addinhelpers https://cdnjs.com/libraries/pnp-sp-clientsvc https://cdnjs.com/libraries/pnp-sp-taxonomy","title":"CDN"},{"location":"documentation/deployment/#cdn-and-spfx","text":"If you are developing in SPFx and install and import the PnPjs libraries the default behavior will be to bundle the library into your solution. You have a couple of choices on how best to work with CDNs and SPFx. Because SPFx doesn't currently respect peer dependencies it is easier to reference the pnpjs rollup package for your project. In this case you would install the package, reference it in your code, and update your config.js file externals as follows:","title":"CDN and SPFx"},{"location":"documentation/deployment/#install","text":"npm install @pnp/pnpjs --save","title":"Install"},{"location":"documentation/deployment/#in-code","text":"import { sp } from \"@pnp/pnpjs\" ; sp . web . lists . getByTitle ( \"BigList\" ). get (). then ( r => { this . domElement . innerHTML += r . Title ; });","title":"In Code"},{"location":"documentation/deployment/#configjson","text":"\"externals\" : { \"@pnp/pnpjs\" : { \"path\" : \"https://cdnjs.cloudflare.com/ajax/libs/pnp-pnpjs/1.1.4/pnpjs.es5.umd.bundle.min.js\" , \"globalName\" : \"pnp\" } } , You can still work with the individual packages from a cdn, but you have a bit more work to do. First install the modules you need, update the config with the JSON externals below, and add some blind require statements into your code. These are needed because peer dependencies are not processed by SPFx so you have to \"trigger\" the SPFx manifest creator to include those packages. Note this approach requires using version 1.1.5 (specifically beta 1.1.5-2) or later of the libraries as we had make a few updates to how things are packaged to make this a little easier.","title":"config.json"},{"location":"documentation/deployment/#install_1","text":"npm install @pnp/logging @pnp/core @pnp/queryable @pnp/sp --save","title":"Install"},{"location":"documentation/deployment/#in-code_1","text":"// blind require statements require ( \"tslib\" ); require ( \"@pnp/logging\" ); require ( \"@pnp/core\" ); require ( \"@pnp/queryable\" ); import { sp } from \"@pnp/sp\" ; sp . web . lists . getByTitle ( \"BigList\" ). get (). then ( r => { this . domElement . innerHTML += r . Title ; });","title":"In Code"},{"location":"documentation/deployment/#configjson_1","text":"\"externals\" : { \"@pnp/sp\" : { \"path\" : \"https://unpkg.com/@pnp/sp@1.1.5-2/dist/sp.es5.umd.min.js\" , \"globalName\" : \"pnp.sp\" , \"globalDependencies\" : [ \"@pnp/logging\" , \"@pnp/core\" , \"@pnp/queryable\" , \"tslib\" ] }, \"@pnp/queryable\" : { \"path\" : \"https://unpkg.com/@pnp/queryable@1.1.5-2/dist/odata.es5.umd.min.js\" , \"globalName\" : \"pnp.odata\" , \"globalDependencies\" : [ \"@pnp/core\" , \"@pnp/logging\" , \"tslib\" ] }, \"@pnp/core\" : { \"path\" : \"https://unpkg.com/@pnp/core@1.1.5-2/dist/common.es5.umd.bundle.min.js\" , \"globalName\" : \"pnp.common\" }, \"@pnp/logging\" : { \"path\" : \"https://unpkg.com/@pnp/logging@1.1.5-2/dist/logging.es5.umd.min.js\" , \"globalName\" : \"pnp.logging\" , \"globalDependencies\" : [ \"tslib\" ] }, \"tslib\" : { \"path\" : \"https://cdnjs.cloudflare.com/ajax/libs/tslib/1.9.3/tslib.min.js\" , \"globalName\" : \"tslib\" } } Don't forget to update the version number in the url to match the version you want to use. This will stop the library from being bundled directly into the solution and instead use the copy from the CDN. When a new version of the PnPjs libraries are released and you are ready to update just update this url in your SPFX project's config.js file.","title":"config.json"},{"location":"documentation/documentation/","text":"Building the Documentation \u00b6 Building the documentation locally can help you visualize change you are making to the docs. What you see locally should be what you see online. Building \u00b6 Documentation is built using MkDocs. You will need to latest version of Python (tested on version 3.7.1) and pip. If you're on the Windows operating system, make sure you have added Python to your Path environment variable . When executing the pip module on Windows you can prefix it with python -m . For example: python -m pip install mkdocs-material Install MkDocs pip install mkdocs Install the Material theme pip install mkdocs-material install the mkdocs-markdownextradata-plugin - this is used for the version variable pip install mkdocs-markdownextradata-plugin (doesn't work on Python v2.7) Serve it up mkdocs serve Open a browser to http://127.0.0.1:8000/","title":"Building Docs"},{"location":"documentation/documentation/#building-the-documentation","text":"Building the documentation locally can help you visualize change you are making to the docs. What you see locally should be what you see online.","title":"Building the Documentation"},{"location":"documentation/documentation/#building","text":"Documentation is built using MkDocs. You will need to latest version of Python (tested on version 3.7.1) and pip. If you're on the Windows operating system, make sure you have added Python to your Path environment variable . When executing the pip module on Windows you can prefix it with python -m . For example: python -m pip install mkdocs-material Install MkDocs pip install mkdocs Install the Material theme pip install mkdocs-material install the mkdocs-markdownextradata-plugin - this is used for the version variable pip install mkdocs-markdownextradata-plugin (doesn't work on Python v2.7) Serve it up mkdocs serve Open a browser to http://127.0.0.1:8000/","title":"Building"},{"location":"documentation/getting-started-dev/","text":"Contribution Guide \u00b6 Thank you for your interest in contributing to our work. This guide should help you get started, please let us know if you have any questions. Contributor Guidance \u00b6 Target your pull requests to the dev branch Add/Update any relevant docs articles in the relevant package's docs folder related to your changes Include a test for any new functionality and ensure all existing tests are passing by running gulp test Ensure tslint checks pass by typing gulp lint Keep your PRs as simple as possible and describe the changes to help the reviewer understand your work If you have an idea for a larger change to the library please open an issue and let's discuss before you invest many hours - these are very welcome but want to ensure it is something we can merge before you spend the time :) Setup your development environment \u00b6 These steps will help you get your environment setup for contributing to the core library. Install Visual Studio Code - this is the development environment we will use. It is similar to a light-weight Visual Studio designed for each editing of client file types such as .ts and .js. (Note that if you prefer you can use Visual Studio). Install Node JS - this provides two key capabilities; the first is the nodejs server which will act as our development server (think iisexpress), the second is npm a package manager (think nuget). On Windows: Install Python v2.7.10 - this is used by some of the plug-ins and build tools inside Node JS - (Python v3.x.x is not supported by those modules). If Visual Studio is not installed on the client in addition to this C++ runtime is required. Please see node-gyp Readme Install a console emulator of your choice, for Windows Cmder is popular. If installing Cmder choosing the full option will allow you to use git for windows. Whatever option you choose we will refer in the rest of the guide to \"console\" as the thing you installed in this step. Install the tslint extension in VS Code: Press Shift + Ctrl + \"p\" to open the command panel Begin typing \"install extension\" and select the command when it appears in view Begin typing \"tslint\" and select the package when it appears in view Restart Code after installation Install the gulp command line globally by typing the following code in your console npm install -g gulp-cli Now we need to fork and clone the git repository. This can be done using your console or using your preferred Git GUI tool. Once you have the code locally, navigate to the root of the project in your console. Type the following command: npm install - installs all of the npm package dependencies (may take awhile the first time) Copy settings.example.js in the root of your project to settings.js. Edit settings.js to reflect your personal environment (usename, password, siteUrl, etc.). Then you can follow the guidance in the debugging article to get started testing right away!","title":"Getting Started Contributing"},{"location":"documentation/getting-started-dev/#contribution-guide","text":"Thank you for your interest in contributing to our work. This guide should help you get started, please let us know if you have any questions.","title":"Contribution Guide"},{"location":"documentation/getting-started-dev/#contributor-guidance","text":"Target your pull requests to the dev branch Add/Update any relevant docs articles in the relevant package's docs folder related to your changes Include a test for any new functionality and ensure all existing tests are passing by running gulp test Ensure tslint checks pass by typing gulp lint Keep your PRs as simple as possible and describe the changes to help the reviewer understand your work If you have an idea for a larger change to the library please open an issue and let's discuss before you invest many hours - these are very welcome but want to ensure it is something we can merge before you spend the time :)","title":"Contributor Guidance"},{"location":"documentation/getting-started-dev/#setup-your-development-environment","text":"These steps will help you get your environment setup for contributing to the core library. Install Visual Studio Code - this is the development environment we will use. It is similar to a light-weight Visual Studio designed for each editing of client file types such as .ts and .js. (Note that if you prefer you can use Visual Studio). Install Node JS - this provides two key capabilities; the first is the nodejs server which will act as our development server (think iisexpress), the second is npm a package manager (think nuget). On Windows: Install Python v2.7.10 - this is used by some of the plug-ins and build tools inside Node JS - (Python v3.x.x is not supported by those modules). If Visual Studio is not installed on the client in addition to this C++ runtime is required. Please see node-gyp Readme Install a console emulator of your choice, for Windows Cmder is popular. If installing Cmder choosing the full option will allow you to use git for windows. Whatever option you choose we will refer in the rest of the guide to \"console\" as the thing you installed in this step. Install the tslint extension in VS Code: Press Shift + Ctrl + \"p\" to open the command panel Begin typing \"install extension\" and select the command when it appears in view Begin typing \"tslint\" and select the package when it appears in view Restart Code after installation Install the gulp command line globally by typing the following code in your console npm install -g gulp-cli Now we need to fork and clone the git repository. This can be done using your console or using your preferred Git GUI tool. Once you have the code locally, navigate to the root of the project in your console. Type the following command: npm install - installs all of the npm package dependencies (may take awhile the first time) Copy settings.example.js in the root of your project to settings.js. Edit settings.js to reflect your personal environment (usename, password, siteUrl, etc.). Then you can follow the guidance in the debugging article to get started testing right away!","title":"Setup your development environment"},{"location":"documentation/getting-started/","text":"Getting Started \u00b6 These libraries are geared towards folks working with TypeScript but will work equally well for JavaScript projects. To get started you need to install the libraries you need via npm. Many of the packages have a peer dependency to other packages with the @pnp namespace meaning you may need to install more than one package. All packages are released together eliminating version confusion - all packages will depend on packages with the same version number. If you need to support older browsers please review the article on polyfills for required functionality. Install \u00b6 First you will need to install those libraries you want to use in your application. Here we will install the most frequently used packages. This step applies to any environment or project. npm install @pnp/logging @pnp/core @pnp/queryable @pnp/sp @pnp/graph --save Next we can import and use the functionality within our application. The below is a very simple example, please see the individual package documentation for more details. import { getRandomString } from \"@pnp/core\" ; ( function () { // get and log a random string console . log ( getRandomString ( 20 )); })() Getting Started with SharePoint Framework \u00b6 The @pnp/sp and @pnp/graph libraries are designed to work seamlessly within SharePoint Framework projects with a small amount of upfront configuration. If you are running in 2016 on-premises please read this note on a workaround for the included TypeScript version. If you are targetting SharePoint online you do not need to take any additional steps. Establish Context \u00b6 Because SharePoint Framework provides a local context to each component we need to set that context within the library. This allows us to determine request urls as well as use the SPFx HttpGraphClient within @pnp/graph. There are two ways to provide the spfx context to the library. Either through the setup method imported from @pnp/core or using the setup method on either the @pnp/sp or @pnp/graph main export. All three are shown below and are equivalent, meaning if you are already importing the sp variable from @pnp/sp or the graph variable from @pnp/graph you should use their setup method to reduce imports. The setup is always done in the onInit method to ensure it runs before your other lifecycle code. You can also set any other settings at this time. Using @pnp/core setup \u00b6 import { setup as pnpSetup } from \"@pnp/core\" ; // ... public onInit () : Promise < void > { return super . onInit (). then ( _ => { // other init code may be present pnpSetup ({ spfxContext : this.context }); }); } // ... Using @pnp/sp setup \u00b6 import { sp } from \"@pnp/sp\" ; // ... public onInit () : Promise < void > { return super . onInit (). then ( _ => { // other init code may be present sp . setup ({ spfxContext : this.context }); }); } // ... Using @pnp/graph setup \u00b6 import { graph } from \"@pnp/graph\" ; // ... public onInit () : Promise < void > { return super . onInit (). then ( _ => { // other init code may be present graph . setup ({ spfxContext : this.context }); }); } // ... Establish Context with an SPFx Service \u00b6 Because you do not have access to the full context object within a service you need to setup things slightly differently. This works for the sp library, but not the graph library as we don't have access to the AAD token provider from the full context. import { ServiceKey , ServiceScope } from \"@microsoft/sp-core-library\" ; import { PageContext } from \"@microsoft/sp-page-context\" ; import { AadTokenProviderFactory } from \"@microsoft/sp-http\" ; import { sp } from \"@pnp/sp\" ; export interface ISampleService { getLists () : Promise < any [] > ; } export class SampleService { public static readonly serviceKey : ServiceKey < ISampleService > = ServiceKey . create < ISampleService > ( 'SPFx:SampleService' , SampleService ); constructor ( serviceScope : ServiceScope ) { serviceScope . whenFinished (() => { const pageContext = serviceScope . consume ( PageContext . serviceKey ); const tokenProviderFactory = serviceScope . consume ( AadTokenProviderFactory . serviceKey ); // we need to \"spoof\" the context object with the parts we need for PnPjs sp . setup ({ spfxContext : { aadTokenProviderFactory : tokenProviderFactory , pageContext : pageContext , } }); // This approach also works if you do not require AAD tokens // you don't need to do both // sp.setup({ // sp : { // baseUrl : pageContext.web.absoluteUrl // } // }); }); } public getLists () : Promise < any [] > { return sp . web . lists . get (); } } Connect to SharePoint from Node \u00b6 Because peer dependencies are not installed automatically you will need to list out each package to install. Don't worry if you forget one you will get a message on the command line that a peer dependency is missing. Let's for example look at installing the required libraries to connect to SharePoint from nodejs. You can see ./debug/launch/sp.ts for a live example. npm i @pnp/logging @pnp/core @pnp/queryable @pnp/sp @pnp/nodejs This will install the logging, common, odata, sp, and nodejs packages. You can read more about what each package does starting on the packages page. Once these are installed you need to import them into your project, to communicate with SharePoint from node we'll need the following imports: import { sp } from \"@pnp/sp\" ; import { SPFetchClient } from \"@pnp/nodejs\" ; Once you have imported the necessary resources you can update your code to setup the node fetch client as well as make a call to SharePoint. // configure your node options (only once in your application) sp . setup ({ sp : { fetchClientFactory : () => { return new SPFetchClient ( \"{site url}\" , \"{client id}\" , \"{client secret}\" ); }, }, }); // make a call to SharePoint and log it in the console sp . web . select ( \"Title\" , \"Description\" ). get (). then ( w => { console . log ( JSON . stringify ( w , null , 4 )); }); Connect to Microsoft Graph From Node \u00b6 Similar to the above you can also make calls to the Graph api from node using the libraries. Again we start with installing the required resources. You can see ./debug/launch/graph.ts for a live example. npm i @pnp/logging @pnp/core @pnp/queryable @pnp/graph @pnp/nodejs Now we need to import what we'll need to call graph import { graph } from \"@pnp/graph\" ; import { AdalFetchClient } from \"@pnp/nodejs\" ; Now we can make our graph calls after setting up the Adal client. Note you'll need to setup an AzureAD App registration with the necessary permissions. graph . setup ({ graph : { fetchClientFactory : () => { return new AdalFetchClient ( \"{mytenant}.onmicrosoft.com\" , \"{application id}\" , \"{application secret}\" ); }, }, }); // make a call to Graph and get all the groups graph . v1 . groups . get (). then ( g => { console . log ( JSON . stringify ( g , null , 4 )); }); Getting Started outside SharePoint Framework \u00b6 In some cases you may be working in a way such that we cannot determine the base url for the web. In this scenario you have two options. Set baseUrl through setup: \u00b6 Here we are setting the baseUrl via the sp.setup method. We are also setting the headers to use verbose mode, something you may have to do when working against unpatched versions of SharePoint 2013 as discussed here . This is optional for 2016 or SharePoint Online. import { sp } from \"@pnp/sp\" ; sp . setup ({ sp : { headers : { Accept : \"application/json;odata=verbose\" , }, baseUrl : \"{Absolute SharePoint Web URL}\" }, }); const w = await sp . web . get (); Create Web instances directly \u00b6 Using this method you create the web directly with the url you want to use as the base. import { Web } from \"@pnp/sp\" ; const web = new Web ( \"{Absolute SharePoint Web URL}\" ); const w = await web . get ();","title":"Getting Started"},{"location":"documentation/getting-started/#getting-started","text":"These libraries are geared towards folks working with TypeScript but will work equally well for JavaScript projects. To get started you need to install the libraries you need via npm. Many of the packages have a peer dependency to other packages with the @pnp namespace meaning you may need to install more than one package. All packages are released together eliminating version confusion - all packages will depend on packages with the same version number. If you need to support older browsers please review the article on polyfills for required functionality.","title":"Getting Started"},{"location":"documentation/getting-started/#install","text":"First you will need to install those libraries you want to use in your application. Here we will install the most frequently used packages. This step applies to any environment or project. npm install @pnp/logging @pnp/core @pnp/queryable @pnp/sp @pnp/graph --save Next we can import and use the functionality within our application. The below is a very simple example, please see the individual package documentation for more details. import { getRandomString } from \"@pnp/core\" ; ( function () { // get and log a random string console . log ( getRandomString ( 20 )); })()","title":"Install"},{"location":"documentation/getting-started/#getting-started-with-sharepoint-framework","text":"The @pnp/sp and @pnp/graph libraries are designed to work seamlessly within SharePoint Framework projects with a small amount of upfront configuration. If you are running in 2016 on-premises please read this note on a workaround for the included TypeScript version. If you are targetting SharePoint online you do not need to take any additional steps.","title":"Getting Started with SharePoint Framework"},{"location":"documentation/getting-started/#establish-context","text":"Because SharePoint Framework provides a local context to each component we need to set that context within the library. This allows us to determine request urls as well as use the SPFx HttpGraphClient within @pnp/graph. There are two ways to provide the spfx context to the library. Either through the setup method imported from @pnp/core or using the setup method on either the @pnp/sp or @pnp/graph main export. All three are shown below and are equivalent, meaning if you are already importing the sp variable from @pnp/sp or the graph variable from @pnp/graph you should use their setup method to reduce imports. The setup is always done in the onInit method to ensure it runs before your other lifecycle code. You can also set any other settings at this time.","title":"Establish Context"},{"location":"documentation/getting-started/#using-pnpcommon-setup","text":"import { setup as pnpSetup } from \"@pnp/core\" ; // ... public onInit () : Promise < void > { return super . onInit (). then ( _ => { // other init code may be present pnpSetup ({ spfxContext : this.context }); }); } // ...","title":"Using @pnp/core setup"},{"location":"documentation/getting-started/#using-pnpsp-setup","text":"import { sp } from \"@pnp/sp\" ; // ... public onInit () : Promise < void > { return super . onInit (). then ( _ => { // other init code may be present sp . setup ({ spfxContext : this.context }); }); } // ...","title":"Using @pnp/sp setup"},{"location":"documentation/getting-started/#using-pnpgraph-setup","text":"import { graph } from \"@pnp/graph\" ; // ... public onInit () : Promise < void > { return super . onInit (). then ( _ => { // other init code may be present graph . setup ({ spfxContext : this.context }); }); } // ...","title":"Using @pnp/graph setup"},{"location":"documentation/getting-started/#establish-context-with-an-spfx-service","text":"Because you do not have access to the full context object within a service you need to setup things slightly differently. This works for the sp library, but not the graph library as we don't have access to the AAD token provider from the full context. import { ServiceKey , ServiceScope } from \"@microsoft/sp-core-library\" ; import { PageContext } from \"@microsoft/sp-page-context\" ; import { AadTokenProviderFactory } from \"@microsoft/sp-http\" ; import { sp } from \"@pnp/sp\" ; export interface ISampleService { getLists () : Promise < any [] > ; } export class SampleService { public static readonly serviceKey : ServiceKey < ISampleService > = ServiceKey . create < ISampleService > ( 'SPFx:SampleService' , SampleService ); constructor ( serviceScope : ServiceScope ) { serviceScope . whenFinished (() => { const pageContext = serviceScope . consume ( PageContext . serviceKey ); const tokenProviderFactory = serviceScope . consume ( AadTokenProviderFactory . serviceKey ); // we need to \"spoof\" the context object with the parts we need for PnPjs sp . setup ({ spfxContext : { aadTokenProviderFactory : tokenProviderFactory , pageContext : pageContext , } }); // This approach also works if you do not require AAD tokens // you don't need to do both // sp.setup({ // sp : { // baseUrl : pageContext.web.absoluteUrl // } // }); }); } public getLists () : Promise < any [] > { return sp . web . lists . get (); } }","title":"Establish Context with an SPFx Service"},{"location":"documentation/getting-started/#connect-to-sharepoint-from-node","text":"Because peer dependencies are not installed automatically you will need to list out each package to install. Don't worry if you forget one you will get a message on the command line that a peer dependency is missing. Let's for example look at installing the required libraries to connect to SharePoint from nodejs. You can see ./debug/launch/sp.ts for a live example. npm i @pnp/logging @pnp/core @pnp/queryable @pnp/sp @pnp/nodejs This will install the logging, common, odata, sp, and nodejs packages. You can read more about what each package does starting on the packages page. Once these are installed you need to import them into your project, to communicate with SharePoint from node we'll need the following imports: import { sp } from \"@pnp/sp\" ; import { SPFetchClient } from \"@pnp/nodejs\" ; Once you have imported the necessary resources you can update your code to setup the node fetch client as well as make a call to SharePoint. // configure your node options (only once in your application) sp . setup ({ sp : { fetchClientFactory : () => { return new SPFetchClient ( \"{site url}\" , \"{client id}\" , \"{client secret}\" ); }, }, }); // make a call to SharePoint and log it in the console sp . web . select ( \"Title\" , \"Description\" ). get (). then ( w => { console . log ( JSON . stringify ( w , null , 4 )); });","title":"Connect to SharePoint from Node"},{"location":"documentation/getting-started/#connect-to-microsoft-graph-from-node","text":"Similar to the above you can also make calls to the Graph api from node using the libraries. Again we start with installing the required resources. You can see ./debug/launch/graph.ts for a live example. npm i @pnp/logging @pnp/core @pnp/queryable @pnp/graph @pnp/nodejs Now we need to import what we'll need to call graph import { graph } from \"@pnp/graph\" ; import { AdalFetchClient } from \"@pnp/nodejs\" ; Now we can make our graph calls after setting up the Adal client. Note you'll need to setup an AzureAD App registration with the necessary permissions. graph . setup ({ graph : { fetchClientFactory : () => { return new AdalFetchClient ( \"{mytenant}.onmicrosoft.com\" , \"{application id}\" , \"{application secret}\" ); }, }, }); // make a call to Graph and get all the groups graph . v1 . groups . get (). then ( g => { console . log ( JSON . stringify ( g , null , 4 )); });","title":"Connect to Microsoft Graph From Node"},{"location":"documentation/getting-started/#getting-started-outside-sharepoint-framework","text":"In some cases you may be working in a way such that we cannot determine the base url for the web. In this scenario you have two options.","title":"Getting Started outside SharePoint Framework"},{"location":"documentation/getting-started/#set-baseurl-through-setup","text":"Here we are setting the baseUrl via the sp.setup method. We are also setting the headers to use verbose mode, something you may have to do when working against unpatched versions of SharePoint 2013 as discussed here . This is optional for 2016 or SharePoint Online. import { sp } from \"@pnp/sp\" ; sp . setup ({ sp : { headers : { Accept : \"application/json;odata=verbose\" , }, baseUrl : \"{Absolute SharePoint Web URL}\" }, }); const w = await sp . web . get ();","title":"Set baseUrl through setup:"},{"location":"documentation/getting-started/#create-web-instances-directly","text":"Using this method you create the web directly with the url you want to use as the base. import { Web } from \"@pnp/sp\" ; const web = new Web ( \"{Absolute SharePoint Web URL}\" ); const w = await web . get ();","title":"Create Web instances directly"},{"location":"documentation/gulp-commands/","text":"Gulp Commands \u00b6 This library uses Gulp to orchestrate various tasks. The tasks described below are available for your use. Please review the getting started for development to ensure you've setup your environment correctly. The source for the gulp commands can be found in the tools\\gulptasks folder at the root of the project. Basics \u00b6 All gulp commands are run on the command line in the fashion shown below. gulp <command> [optional pararms] build \u00b6 The build command transpiles the solution from TypeScript into JavaScript using our custom build system . It is controlled by the pnp-build.js file at the project root. Build all of the packages \u00b6 gulp build Building individual packages \u00b6 Note when building a single package none of the dependencies are currently built, so you need to specify in order those packages to build which are dependencies. # fails gulp build --p sp # works as all the dependencies are built in order gulp build --p logging,common,odata,sp You can also build the packages and then not clean using the nc flag. So for example if you are working on the sp package you can build all the packages once, then use the \"nc\" flag to leave those that aren't changing. # run once gulp build --p logging,common,odata,sp # run on subsequent builds gulp build --p sp --nc clean \u00b6 The clean command removes all of the generated folders from the project and is generally used automatically before other commands to ensure there is a clean workspace. gulp clean To clean the build folder. This build folder is no longer included in automatic cleaning after the move to use the TypeScript project references feature that compares previous output and doesn't rebuild unchanged files. This command will erase the entire build folder ensuring you can conduct a clean build/test/etc. gulp clean-build lint \u00b6 Runs the project linting based on the tslint.json rules defined at the project root. This should be done before any PR submissions as linting failures will block merging. gulp lint package \u00b6 Used to create the packages in the ./dist folder as they would exist for a release. gulp package Packaging individual packages \u00b6 You can also package individual packages, but as with build you must also package any dependencies at the same time. gulp package --p logging,common,odata,sp publish \u00b6 This command is only for use by package authors to publish a version to npm and is not for developer use. serve \u00b6 The serve command allows you to serve either code from the ./debug/serve folder OR an individual package for testing in the browser. The file will always be served as https://localhost:8080/assets/pnp.js so can create a static page in your tenant for easy testing of a variety of scenarios. NOTE that in most browsers this file will be flagged as unsafe so you will need to trust it for it to execute on the page. debug serve \u00b6 When running the command with no parameters you will generate a package with the entry being based on the tsconfig.json file in ./debug/serve. By default this will use serve.ts. This allows you to write any code you want to test to easily run it in the browser with all changes being watched and triggering a rebuild. gulp serve package serve \u00b6 If instead you want to test how a particular package will work in the browser you can serve just that package. In this case you do not need to specify the dependencies and specifying multiple packages will throw an error. Packages will be injected into the global namespace on a variable named pnp. gulp serve --p sp test \u00b6 Runs the tests specified in each package's tests folder gulp test Verbose \u00b6 The test command will switch to the \"spec\" mocha reporter if you supply the verbose flag. Doing so will list out each test's description and sucess instead of the \"dot\" used by default. This flag works with all other test options. gulp test --verbose Test individual packages \u00b6 You can test individual packages as needed, and there is no need to include dependencies in this case # test the logging and sp packages gulp test --p logging,sp If you are working on a specific set of tests for a single module you can also use the single or s parameter to select just a single module of tests. You specify the filename without the \".test.ts\" suffix. It must be within the specified package and this option can only be used with a single package for --p # will test only the client-side pages module within the sp package gulp test --p sp --s clientsidepages If you want you can test within the same site and avoid creating a new one, though for some tests this might cause conflicts. This flag can be helpful if you are rapidly testing things with no conflict as you can avoid creating a site each time. Works with both of the above options --p and --s as well as individually. The url must be absolute. #testing using the specified site. gulp test --site https://{tenant}.sharepoint.com/sites/testing # with other options gulp test --p logging,sp --site https://{tenant}.sharepoint.com/sites/testing gulp test --p sp --s clientsidepages --site https://{tenant}.sharepoint.com/sites/testing","title":"Gulp Commands"},{"location":"documentation/gulp-commands/#gulp-commands","text":"This library uses Gulp to orchestrate various tasks. The tasks described below are available for your use. Please review the getting started for development to ensure you've setup your environment correctly. The source for the gulp commands can be found in the tools\\gulptasks folder at the root of the project.","title":"Gulp Commands"},{"location":"documentation/gulp-commands/#basics","text":"All gulp commands are run on the command line in the fashion shown below. gulp <command> [optional pararms]","title":"Basics"},{"location":"documentation/gulp-commands/#build","text":"The build command transpiles the solution from TypeScript into JavaScript using our custom build system . It is controlled by the pnp-build.js file at the project root.","title":"build"},{"location":"documentation/gulp-commands/#build-all-of-the-packages","text":"gulp build","title":"Build all of the packages"},{"location":"documentation/gulp-commands/#building-individual-packages","text":"Note when building a single package none of the dependencies are currently built, so you need to specify in order those packages to build which are dependencies. # fails gulp build --p sp # works as all the dependencies are built in order gulp build --p logging,common,odata,sp You can also build the packages and then not clean using the nc flag. So for example if you are working on the sp package you can build all the packages once, then use the \"nc\" flag to leave those that aren't changing. # run once gulp build --p logging,common,odata,sp # run on subsequent builds gulp build --p sp --nc","title":"Building individual packages"},{"location":"documentation/gulp-commands/#clean","text":"The clean command removes all of the generated folders from the project and is generally used automatically before other commands to ensure there is a clean workspace. gulp clean To clean the build folder. This build folder is no longer included in automatic cleaning after the move to use the TypeScript project references feature that compares previous output and doesn't rebuild unchanged files. This command will erase the entire build folder ensuring you can conduct a clean build/test/etc. gulp clean-build","title":"clean"},{"location":"documentation/gulp-commands/#lint","text":"Runs the project linting based on the tslint.json rules defined at the project root. This should be done before any PR submissions as linting failures will block merging. gulp lint","title":"lint"},{"location":"documentation/gulp-commands/#package","text":"Used to create the packages in the ./dist folder as they would exist for a release. gulp package","title":"package"},{"location":"documentation/gulp-commands/#packaging-individual-packages","text":"You can also package individual packages, but as with build you must also package any dependencies at the same time. gulp package --p logging,common,odata,sp","title":"Packaging individual packages"},{"location":"documentation/gulp-commands/#publish","text":"This command is only for use by package authors to publish a version to npm and is not for developer use.","title":"publish"},{"location":"documentation/gulp-commands/#serve","text":"The serve command allows you to serve either code from the ./debug/serve folder OR an individual package for testing in the browser. The file will always be served as https://localhost:8080/assets/pnp.js so can create a static page in your tenant for easy testing of a variety of scenarios. NOTE that in most browsers this file will be flagged as unsafe so you will need to trust it for it to execute on the page.","title":"serve"},{"location":"documentation/gulp-commands/#debug-serve","text":"When running the command with no parameters you will generate a package with the entry being based on the tsconfig.json file in ./debug/serve. By default this will use serve.ts. This allows you to write any code you want to test to easily run it in the browser with all changes being watched and triggering a rebuild. gulp serve","title":"debug serve"},{"location":"documentation/gulp-commands/#package-serve","text":"If instead you want to test how a particular package will work in the browser you can serve just that package. In this case you do not need to specify the dependencies and specifying multiple packages will throw an error. Packages will be injected into the global namespace on a variable named pnp. gulp serve --p sp","title":"package serve"},{"location":"documentation/gulp-commands/#test","text":"Runs the tests specified in each package's tests folder gulp test","title":"test"},{"location":"documentation/gulp-commands/#verbose","text":"The test command will switch to the \"spec\" mocha reporter if you supply the verbose flag. Doing so will list out each test's description and sucess instead of the \"dot\" used by default. This flag works with all other test options. gulp test --verbose","title":"Verbose"},{"location":"documentation/gulp-commands/#test-individual-packages","text":"You can test individual packages as needed, and there is no need to include dependencies in this case # test the logging and sp packages gulp test --p logging,sp If you are working on a specific set of tests for a single module you can also use the single or s parameter to select just a single module of tests. You specify the filename without the \".test.ts\" suffix. It must be within the specified package and this option can only be used with a single package for --p # will test only the client-side pages module within the sp package gulp test --p sp --s clientsidepages If you want you can test within the same site and avoid creating a new one, though for some tests this might cause conflicts. This flag can be helpful if you are rapidly testing things with no conflict as you can avoid creating a site each time. Works with both of the above options --p and --s as well as individually. The url must be absolute. #testing using the specified site. gulp test --site https://{tenant}.sharepoint.com/sites/testing # with other options gulp test --p logging,sp --site https://{tenant}.sharepoint.com/sites/testing gulp test --p sp --s clientsidepages --site https://{tenant}.sharepoint.com/sites/testing","title":"Test individual packages"},{"location":"documentation/package-structure/","text":"Package Structure \u00b6 Each of the packages is published with the same structure, so this article applies to all of the packages. We will use @pnp/core as an example for discussion. Folders \u00b6 In addition to the files in the root each package has three folders dist, docs, and src. Root Files \u00b6 These files are found at the root of each package. File Description index.d.ts Referenced in package.json typings property and provides the TypeScript type information for consumers LICENSE Package license package.json npm package definition readme.md Basic readme referencing the docs site Dist \u00b6 The dist folder contains the transpiled files bundled in various ways. You can choose the best file for your usage as needed. Below the {package} will be replaced with the name of the package - in our examples case this would be \"common\" making the file name \"{package}.es5.js\" = \"common.es5.js\". All of the *.map files are the debug mapping files related to the .js file of the same name. File Description {package}.es5.js Library packaged in es5 format not wrapped as a module {package}.es5.umd.bundle.js The library bundled with all dependencies into a single UMD module. Global variable will be \"pnp.{package}\". Referenced in the main property of package.json {package}.es5.umd.bundle.min.js Minified version of the bundled umd module {package}.es5.umd.js The library in es5 bundled as a UMD modules with no included dependencies. They are designed to work with the other *.es5.umd.js files. Referenced in the module property of package.json {package}.es5.umd.min.js Minified version of the es5 umd module {package}.js es6 format file of the library. Referenced by es2015 property of package.json Docs \u00b6 This folder contains markdown documentation for the library. All packages will include an index.md which serves as the root of the docs. These files are also used to build the public site . To edit these files they can be found in the packages/{package}/docs folder. Src \u00b6 Contains the TypeScript definition files refrenced by the index.d.ts in the package root. These files serve to provide typing information about the library to consumers who can process typing information.","title":"Package Structure"},{"location":"documentation/package-structure/#package-structure","text":"Each of the packages is published with the same structure, so this article applies to all of the packages. We will use @pnp/core as an example for discussion.","title":"Package Structure"},{"location":"documentation/package-structure/#folders","text":"In addition to the files in the root each package has three folders dist, docs, and src.","title":"Folders"},{"location":"documentation/package-structure/#root-files","text":"These files are found at the root of each package. File Description index.d.ts Referenced in package.json typings property and provides the TypeScript type information for consumers LICENSE Package license package.json npm package definition readme.md Basic readme referencing the docs site","title":"Root Files"},{"location":"documentation/package-structure/#dist","text":"The dist folder contains the transpiled files bundled in various ways. You can choose the best file for your usage as needed. Below the {package} will be replaced with the name of the package - in our examples case this would be \"common\" making the file name \"{package}.es5.js\" = \"common.es5.js\". All of the *.map files are the debug mapping files related to the .js file of the same name. File Description {package}.es5.js Library packaged in es5 format not wrapped as a module {package}.es5.umd.bundle.js The library bundled with all dependencies into a single UMD module. Global variable will be \"pnp.{package}\". Referenced in the main property of package.json {package}.es5.umd.bundle.min.js Minified version of the bundled umd module {package}.es5.umd.js The library in es5 bundled as a UMD modules with no included dependencies. They are designed to work with the other *.es5.umd.js files. Referenced in the module property of package.json {package}.es5.umd.min.js Minified version of the es5 umd module {package}.js es6 format file of the library. Referenced by es2015 property of package.json","title":"Dist"},{"location":"documentation/package-structure/#docs","text":"This folder contains markdown documentation for the library. All packages will include an index.md which serves as the root of the docs. These files are also used to build the public site . To edit these files they can be found in the packages/{package}/docs folder.","title":"Docs"},{"location":"documentation/package-structure/#src","text":"Contains the TypeScript definition files refrenced by the index.d.ts in the package root. These files serve to provide typing information about the library to consumers who can process typing information.","title":"Src"},{"location":"documentation/packages/","text":"The following packages comprise the Patterns and Practices client side libraries. All of the packages are published as a set and depend on their peers within the @pnp scope. The latest published version is ****. @pnp/ common Provides shared functionality across all pnp libraries config-store Provides a way to manage configuration within your application graph Provides a fluent api for working with Microsoft Graph logging Light-weight, subscribable logging framework nodejs Provides functionality enabling the @pnp libraries within nodejs odata Provides shared odata functionality and base classes pnpjs Rollup library of core functionality (mimics sp-pnp-js) sp Provides a fluent api for working with SharePoint REST sp-addinhelpers Provides functionality for working within SharePoint add-ins sp-clientsvc Provides base classes for working with the legacy SharePoint sp-taxonomy Provides a fluent api for working with SharePoint Managed Metadata","title":"Packages"},{"location":"documentation/polyfill/","text":"Polyfills \u00b6 These libraries may make use of some features not found in older browsers, mainly fetch, Map, and Proxy. This primarily affects Internet Explorer 11, which requires that we provide this missing functionality. There are several ways to include this missing functionality. IE 11 Polyfill package \u00b6 We created a package you can use to include the needed functionality without having to determine what polyfills are required. Also, this package is independent of the other @pnp/* packages and does not need to be updated monthly unless we introduce additional polyfills and publish a new version. This package is only needed if you need to support IE 11. Install \u00b6 npm install --save @pnp/polyfill-ie11 Use \u00b6 import \"@pnp/polyfill-ie11\" ; import { sp } from \"@pnp/sp\" ; sp . web . lists . getByTitle ( \"BigList\" ). items . filter ( `ID gt 6000` ). get (). then ( r => { this . domElement . innerHTML += r . map ( l => ` ${ l . Title } <br />` ); }); SearchQueryBuilder \u00b6 Because the latest version of SearchQueryBuilder uses Proxy internally you can fall back on the older version for IE 11 as shown below. import \"@pnp/polyfill-ie11\" ; import { SearchQueryBuilder } from \"@pnp/polyfill-ie11/dist/searchquerybuilder\" ; import { sp , ISearchQueryBuilder } from \"@pnp/sp\" ; // works in IE11 and other browsers const builder : ISearchQueryBuilder = SearchQueryBuilder (). text ( \"test\" ); sp . search ( builder ). then ( r => { this . domElement . innerHTML = JSON . stringify ( r ); }); Polyfill Service \u00b6 If acceptable to your design and security requirements you can use a service to provide missing functionality. This loads scripts from a service outside of your and our control, so please ensure you understand any associated risks. To use this option you need to wrap the code in a function, here called \"stuffisloaded\". Then you need to add another script tag as shown below that will load what you need from the polyfill service. Note the parameter \"callback\" takes our function name. < script src = \"https://cdnjs.cloudflare.com/ajax/libs/pnp-pnpjs/1.2.1/pnpjs.es5.umd.bundle.min.js\" type = \"text/javascript\" ></ script > < script > // this function will be executed once the polyfill is loaded. function stuffisloaded () { pnp . sp . web . select ( \"Title\" ). get () . then ( function ( data ){ document . getElementById ( \"main\" ). innerText = data . Title ; }) . catch ( function ( err ){ document . getElementById ( \"main\" ). innerText = err ; }); } </ script > <!-- This script tag loads the required polyfills from the service --> < script src = \"https://cdn.polyfill.io/v2/polyfill.min.js?callback=stuffisloaded&features=es6,fetch,Map&flags=always,gated\" ></ script > Module Loader \u00b6 If you are using a module loader you need to load the following two files as well. You can do this form a CDN or your style library. Download the es6-promises polyfill from https://github.com/stefanpenner/es6-promise and upload it to your style library. Download the fetch polyfill from https://github.com/github/fetch and upload it to your style library. Download the corejs polyfill from https://github.com/zloirock/core-js and upload it to your style library. Update your module loader to set these files as dependencies before the pnp library is opened. One issue you still may see is that you get errors that certain libraries are undefined when you try to run your code. This is because your code is running before these libraries are loaded. You need to ensure that all dependencies are loaded before making use of the pnp libraries.","title":"Polyfills"},{"location":"documentation/polyfill/#polyfills","text":"These libraries may make use of some features not found in older browsers, mainly fetch, Map, and Proxy. This primarily affects Internet Explorer 11, which requires that we provide this missing functionality. There are several ways to include this missing functionality.","title":"Polyfills"},{"location":"documentation/polyfill/#ie-11-polyfill-package","text":"We created a package you can use to include the needed functionality without having to determine what polyfills are required. Also, this package is independent of the other @pnp/* packages and does not need to be updated monthly unless we introduce additional polyfills and publish a new version. This package is only needed if you need to support IE 11.","title":"IE 11 Polyfill package"},{"location":"documentation/polyfill/#install","text":"npm install --save @pnp/polyfill-ie11","title":"Install"},{"location":"documentation/polyfill/#use","text":"import \"@pnp/polyfill-ie11\" ; import { sp } from \"@pnp/sp\" ; sp . web . lists . getByTitle ( \"BigList\" ). items . filter ( `ID gt 6000` ). get (). then ( r => { this . domElement . innerHTML += r . map ( l => ` ${ l . Title } <br />` ); });","title":"Use"},{"location":"documentation/polyfill/#searchquerybuilder","text":"Because the latest version of SearchQueryBuilder uses Proxy internally you can fall back on the older version for IE 11 as shown below. import \"@pnp/polyfill-ie11\" ; import { SearchQueryBuilder } from \"@pnp/polyfill-ie11/dist/searchquerybuilder\" ; import { sp , ISearchQueryBuilder } from \"@pnp/sp\" ; // works in IE11 and other browsers const builder : ISearchQueryBuilder = SearchQueryBuilder (). text ( \"test\" ); sp . search ( builder ). then ( r => { this . domElement . innerHTML = JSON . stringify ( r ); });","title":"SearchQueryBuilder"},{"location":"documentation/polyfill/#polyfill-service","text":"If acceptable to your design and security requirements you can use a service to provide missing functionality. This loads scripts from a service outside of your and our control, so please ensure you understand any associated risks. To use this option you need to wrap the code in a function, here called \"stuffisloaded\". Then you need to add another script tag as shown below that will load what you need from the polyfill service. Note the parameter \"callback\" takes our function name. < script src = \"https://cdnjs.cloudflare.com/ajax/libs/pnp-pnpjs/1.2.1/pnpjs.es5.umd.bundle.min.js\" type = \"text/javascript\" ></ script > < script > // this function will be executed once the polyfill is loaded. function stuffisloaded () { pnp . sp . web . select ( \"Title\" ). get () . then ( function ( data ){ document . getElementById ( \"main\" ). innerText = data . Title ; }) . catch ( function ( err ){ document . getElementById ( \"main\" ). innerText = err ; }); } </ script > <!-- This script tag loads the required polyfills from the service --> < script src = \"https://cdn.polyfill.io/v2/polyfill.min.js?callback=stuffisloaded&features=es6,fetch,Map&flags=always,gated\" ></ script >","title":"Polyfill Service"},{"location":"documentation/polyfill/#module-loader","text":"If you are using a module loader you need to load the following two files as well. You can do this form a CDN or your style library. Download the es6-promises polyfill from https://github.com/stefanpenner/es6-promise and upload it to your style library. Download the fetch polyfill from https://github.com/github/fetch and upload it to your style library. Download the corejs polyfill from https://github.com/zloirock/core-js and upload it to your style library. Update your module loader to set these files as dependencies before the pnp library is opened. One issue you still may see is that you get errors that certain libraries are undefined when you try to run your code. This is because your code is running before these libraries are loaded. You need to ensure that all dependencies are loaded before making use of the pnp libraries.","title":"Module Loader"},{"location":"documentation/transition-guide/","text":"Transition Guide \u00b6 These libraries are based on the sp-pnp-js library and our goal was to make transition as easy as possible. The most obvious difference is the splitting of the library into multiple packages. We have however created a rollup library to help folks make the move - though our recommendation is to switch to the separate packages. This article outlines transitioning your existing projects from sp-pnp-js to the new libraries, please provide feedback on how we can improve out guidance. Installing @pnp libraries \u00b6 With the separation of the packages we needed a way to indicate how they are related, while making things easy for folks to track and update and we have used peer dependencies between the packages to do this. With each release we will release all packages so that the version numbers move in lock-step, making it easy to ensure you are working with compatible versions. One thing to keep in mind with peer dependencies is that they are not automatically installed. The advantage is you will only have one copy of each library in your project. Installing peer dependencies is easy, you can specify each of the packages in a single line, here we are installing everything required to use the @pnp/sp package. npm i @pnp/logging @pnp/core @pnp/queryable @pnp/sp If you do not install all of the peer dependencies you will get a message specifying which ones are missing along with the version expected. Import Simplification \u00b6 With the separation of packages we have also simplified the imports, and allowed you more control over what you are importing. Compare these two examples showing the same set of imports, but one is done via sp-pnp-js and the other using the @pnp libraries. From sp-pnp-js \u00b6 import pnp , { Web , Util , Logger , FunctionListener , LogLevel , } from \"sp-pnp-js\" ; From @pnp libraries \u00b6 import { Logger , LogLevel , FunctionListener } from \"@pnp/logging\" ; import * as Util from \"@pnp/core\" ; import { sp , Web } from \"@pnp/sp\" ; In the above example the \"sp\" import replaces \"pnp\" and is the root of your method chains. Once we have updated our imports we have a few small code changes to make, depending on how you have used the library in your applications. Watch this short video discussing the most common updates: Updated settings file format \u00b6 If you are doing local debugging or testing you have likely created a settings.js from the supplied settings.example.js. Please note the format of that file has changed, the new format is shown below. var settings = { spsave : { username : \"develina.devsson@mydevtenant.onmicrosoft.com\" , password : \"pass@word1\" , siteUrl : \"https://mydevtenant.sharepoint.com/\" }, testing : { enableWebTests : true , sp : { id : \"{ client id }\" , secret : \"{ client secret }\" , url : \"{ site collection url }\" , notificationUrl : \"{ notification url }\" , }, graph : { tenant : \"{tenant.onmicrosoft.com}\" , id : \"{your app id}\" , secret : \"{your secret}\" }, } } HttpClient Renamed \u00b6 If you used HttpClient from sp-pnp-js it was renamed to SPHttpClient. A transition to @pnp/sp assumes replacement of: import { HttpClient } from 'sp-pnp-js' ; to the following import statement: import { SPHttpClient } from '@pnp/sp' ;","title":"Transition Guide"},{"location":"documentation/transition-guide/#transition-guide","text":"These libraries are based on the sp-pnp-js library and our goal was to make transition as easy as possible. The most obvious difference is the splitting of the library into multiple packages. We have however created a rollup library to help folks make the move - though our recommendation is to switch to the separate packages. This article outlines transitioning your existing projects from sp-pnp-js to the new libraries, please provide feedback on how we can improve out guidance.","title":"Transition Guide"},{"location":"documentation/transition-guide/#installing-pnp-libraries","text":"With the separation of the packages we needed a way to indicate how they are related, while making things easy for folks to track and update and we have used peer dependencies between the packages to do this. With each release we will release all packages so that the version numbers move in lock-step, making it easy to ensure you are working with compatible versions. One thing to keep in mind with peer dependencies is that they are not automatically installed. The advantage is you will only have one copy of each library in your project. Installing peer dependencies is easy, you can specify each of the packages in a single line, here we are installing everything required to use the @pnp/sp package. npm i @pnp/logging @pnp/core @pnp/queryable @pnp/sp If you do not install all of the peer dependencies you will get a message specifying which ones are missing along with the version expected.","title":"Installing @pnp libraries"},{"location":"documentation/transition-guide/#import-simplification","text":"With the separation of packages we have also simplified the imports, and allowed you more control over what you are importing. Compare these two examples showing the same set of imports, but one is done via sp-pnp-js and the other using the @pnp libraries.","title":"Import Simplification"},{"location":"documentation/transition-guide/#from-sp-pnp-js","text":"import pnp , { Web , Util , Logger , FunctionListener , LogLevel , } from \"sp-pnp-js\" ;","title":"From sp-pnp-js"},{"location":"documentation/transition-guide/#from-pnp-libraries","text":"import { Logger , LogLevel , FunctionListener } from \"@pnp/logging\" ; import * as Util from \"@pnp/core\" ; import { sp , Web } from \"@pnp/sp\" ; In the above example the \"sp\" import replaces \"pnp\" and is the root of your method chains. Once we have updated our imports we have a few small code changes to make, depending on how you have used the library in your applications. Watch this short video discussing the most common updates:","title":"From @pnp libraries"},{"location":"documentation/transition-guide/#updated-settings-file-format","text":"If you are doing local debugging or testing you have likely created a settings.js from the supplied settings.example.js. Please note the format of that file has changed, the new format is shown below. var settings = { spsave : { username : \"develina.devsson@mydevtenant.onmicrosoft.com\" , password : \"pass@word1\" , siteUrl : \"https://mydevtenant.sharepoint.com/\" }, testing : { enableWebTests : true , sp : { id : \"{ client id }\" , secret : \"{ client secret }\" , url : \"{ site collection url }\" , notificationUrl : \"{ notification url }\" , }, graph : { tenant : \"{tenant.onmicrosoft.com}\" , id : \"{your app id}\" , secret : \"{your secret}\" }, } }","title":"Updated settings file format"},{"location":"documentation/transition-guide/#httpclient-renamed","text":"If you used HttpClient from sp-pnp-js it was renamed to SPHttpClient. A transition to @pnp/sp assumes replacement of: import { HttpClient } from 'sp-pnp-js' ; to the following import statement: import { SPHttpClient } from '@pnp/sp' ;","title":"HttpClient Renamed"},{"location":"graph/docs/","text":"@pnp/graph \u00b6 This package contains the fluent api used to call the graph rest services. Getting Started \u00b6 Install the library and required dependencies npm install @pnp/logging @pnp/core @pnp/queryable @pnp/graph --save Import the library into your application and access the root sp object import { graph } from \"@pnp/graph\" ; ( function main() { // here we will load the current web's properties graph . groups . get (). then ( g => { console . log ( `Groups: ${ JSON . stringify ( g , null , 4 ) } ` ); }); })() Getting Started with SharePoint Framework \u00b6 Install the library and required dependencies npm install @pnp/logging @pnp/core @pnp/queryable @pnp/graph --save Import the library into your application, update OnInit, and access the root sp object in render import { graph } from \"@pnp/graph\" ; // ... public onInit () : Promise < void > { return super . onInit (). then ( _ => { // other init code may be present graph . setup ({ spfxContext : this.context }); }); } // ... public render () : void { // A simple loading message this . domElement . innerHTML = `Loading...` ; // here we will load the current web's properties graph . groups . get (). then ( groups => { this . domElement . innerHTML = `Groups: <ul> ${ groups . map ( g => `<li> ${ g . displayName } </li>` ). join ( \"\" ) } </ul>` ; }); } Getting Started on Nodejs \u00b6 Install the library and required dependencies npm install @pnp/logging @pnp/core @pnp/queryable @pnp/graph @pnp/nodejs --save Import the library into your application, setup the node client, make a request import { graph } from \"@pnp/graph\" ; import { AdalFetchClient } from \"@pnp/nodejs\" ; // do this once per page load graph . setup ({ graph : { fetchClientFactory : () => { return new AdalFetchClient ( \"{tenant}.onmicrosoft.com\" , \"AAD Application Id\" , \"AAD Application Secret\" ); }, }, }); // here we will load the groups information graph . groups . get (). then ( g => { console . log ( `Groups: ${ JSON . stringify ( g , null , 4 ) } ` ); }); UML \u00b6 Graphical UML diagram of @pnp/graph. Right-click the diagram and open in new tab if it is too small.","title":"graph"},{"location":"graph/docs/#pnpgraph","text":"This package contains the fluent api used to call the graph rest services.","title":"@pnp/graph"},{"location":"graph/docs/#getting-started","text":"Install the library and required dependencies npm install @pnp/logging @pnp/core @pnp/queryable @pnp/graph --save Import the library into your application and access the root sp object import { graph } from \"@pnp/graph\" ; ( function main() { // here we will load the current web's properties graph . groups . get (). then ( g => { console . log ( `Groups: ${ JSON . stringify ( g , null , 4 ) } ` ); }); })()","title":"Getting Started"},{"location":"graph/docs/#getting-started-with-sharepoint-framework","text":"Install the library and required dependencies npm install @pnp/logging @pnp/core @pnp/queryable @pnp/graph --save Import the library into your application, update OnInit, and access the root sp object in render import { graph } from \"@pnp/graph\" ; // ... public onInit () : Promise < void > { return super . onInit (). then ( _ => { // other init code may be present graph . setup ({ spfxContext : this.context }); }); } // ... public render () : void { // A simple loading message this . domElement . innerHTML = `Loading...` ; // here we will load the current web's properties graph . groups . get (). then ( groups => { this . domElement . innerHTML = `Groups: <ul> ${ groups . map ( g => `<li> ${ g . displayName } </li>` ). join ( \"\" ) } </ul>` ; }); }","title":"Getting Started with SharePoint Framework"},{"location":"graph/docs/#getting-started-on-nodejs","text":"Install the library and required dependencies npm install @pnp/logging @pnp/core @pnp/queryable @pnp/graph @pnp/nodejs --save Import the library into your application, setup the node client, make a request import { graph } from \"@pnp/graph\" ; import { AdalFetchClient } from \"@pnp/nodejs\" ; // do this once per page load graph . setup ({ graph : { fetchClientFactory : () => { return new AdalFetchClient ( \"{tenant}.onmicrosoft.com\" , \"AAD Application Id\" , \"AAD Application Secret\" ); }, }, }); // here we will load the groups information graph . groups . get (). then ( g => { console . log ( `Groups: ${ JSON . stringify ( g , null , 4 ) } ` ); });","title":"Getting Started on Nodejs"},{"location":"graph/docs/#uml","text":"Graphical UML diagram of @pnp/graph. Right-click the diagram and open in new tab if it is too small.","title":"UML"},{"location":"graph/docs/contacts/","text":"@pnp/graph/contacts \u00b6 The ability to manage contacts and folders in Outlook is a capability introduced in version 1.2.2 of @pnp/graph. Through the methods described you can add and edit both contacts and folders in a users Outlook. Get all of the Contacts \u00b6 Using the contacts() you can get the users contacts from Outlook import { graph } from \"@pnp/graph\" ; const contacts = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contacts . get (); const contacts = await graph . me . contacts . get (); Add a new Contact \u00b6 Using the contacts.add() you can a add Contact to the users Outlook import { graph } from \"@pnp/graph\" ; const addedContact = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contacts . add ( 'Pavel' , 'Bansky' , [ < EmailAddress > { address : 'pavelb@fabrikam.onmicrosoft.com' , name : 'Pavel Bansky' }], [ '+1 732 555 0102' ]); const addedContact = await graph . me . contacts . add ( 'Pavel' , 'Bansky' , [ < EmailAddress > { address : 'pavelb@fabrikam.onmicrosoft.com' , name : 'Pavel Bansky' }], [ '+1 732 555 0102' ]); Get Contact by Id \u00b6 Using the contacts.getById() you can get one of the users Contacts in Outlook import { graph } from \"@pnp/graph\" ; const contact = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contacts . getById ( 'userId' ); const contact = await graph . me . contacts . getById ( 'userId' ); Delete a Contact \u00b6 Using the delete you can remove one of the users Contacts in Outlook import { graph } from \"@pnp/graph\" ; const delContact = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contacts . getById ( 'userId' ). delete (); const delContact = await graph . me . contacts . getById ( 'userId' ). delete (); Update a Contact \u00b6 Using the update you can update one of the users Contacts in Outlook import { graph } from \"@pnp/graph\" ; const updContact = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contacts . getById ( 'userId' ). update ({ birthday : \"1986-05-30\" }); const updContact = await graph . me . contacts . getById ( 'userId' ). update ({ birthday : \"1986-05-30\" }); Get all of the Contact Folders \u00b6 Using the contactFolders() you can get the users Contact Folders from Outlook import { graph } from \"@pnp/graph\" ; const contactFolders = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contactFolders . get (); const contactFolders = await graph . me . contactFolders . get (); Add a new Contact Folder \u00b6 Using the contactFolders.add() you can a add Contact Folder to the users Outlook import { graph } from \"@pnp/graph\" ; const addedContactFolder = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contactFolders . add ( 'displayName' , '<ParentFolderId>' ); const addedContactFolder = await graph . me . contactFolders . contactFolders . add ( 'displayName' , '<ParentFolderId>' ); Get Contact Folder by Id \u00b6 Using the contactFolders.getById() you can get one of the users Contact Folders in Outlook import { graph } from \"@pnp/graph\" ; const contactFolder = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contactFolders . getById ( 'folderId' ); const contactFolder = await graph . me . contactFolders . getById ( 'folderId' ); Delete a Contact Folder \u00b6 Using the delete you can remove one of the users Contact Folders in Outlook import { graph } from \"@pnp/graph\" ; const delContactFolder = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contactFolders . getById ( 'folderId' ). delete (); const delContactFolder = await graph . me . contactFolders . getById ( 'folderId' ). delete (); Update a Contact Folder \u00b6 Using the update you can update one of the users Contact Folders in Outlook import { graph } from \"@pnp/graph\" ; const updContactFolder = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contactFolders . getById ( 'userId' ). update ({ displayName : \"value\" }); const updContactFolder = await graph . me . contactFolders . getById ( 'userId' ). update ({ displayName : \"value\" }); Get all of the Contacts from the Contact Folder \u00b6 Using the contacts() in the Contact Folder gets the users Contact from the folder. import { graph } from \"@pnp/graph\" ; const contactsInContactFolder = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contactFolders . getById ( 'folderId' ). contacts . get (); const contactsInContactFolder = await graph . me . contactFolders . getById ( 'folderId' ). contacts . get (); Get Child Folders of the Contact Folder \u00b6 Using the childFolders() you can get the Child Folders of the current Contact Folder from Outlook import { graph } from \"@pnp/graph\" ; const childFolders = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contactFolders . getById ( '<id>' ). childFolders . get (); const childFolders = await graph . me . contactFolders . getById ( '<id>' ). childFolders . get (); Add a new Child Folder \u00b6 Using the childFolders.add() you can a add Child Folder in a Contact Folder import { graph } from \"@pnp/graph\" ; const addedChildFolder = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contactFolders . getById ( '<id>' ). childFolders . add ( 'displayName' , '<ParentFolderId>' ); const addedChildFolder = await graph . me . contactFolders . getById ( '<id>' ). childFolders . add ( 'displayName' , '<ParentFolderId>' ); Get Child Folder by Id \u00b6 Using the childFolders.getById() you can get one of the users Child Folders in Outlook import { graph } from \"@pnp/graph\" ; const childFolder = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contactFolders . getById ( '<id>' ). childFolders . getById ( 'folderId' ); const childFolder = await graph . me . contactFolders . getById ( '<id>' ). childFolders . getById ( 'folderId' ); Add Contact in Child Folder of Contact Folder \u00b6 Using contacts.add in the Child Folder of a Contact Folder, adds a new Contact to that folder import { graph } from \"@pnp/graph\" ; const addedContact = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contactFolders . getById ( '<id>' ). childFolders . getById ( 'folderId' ). contacts . add ( 'Pavel' , 'Bansky' , [ < EmailAddress > { address : 'pavelb@fabrikam.onmicrosoft.com' , name : 'Pavel Bansky' }], [ '+1 732 555 0102' ]); const addedContact = await graph . me . contactFolders . getById ( '<id>' ). childFolders . getById ( 'folderId' ). contacts . add ( 'Pavel' , 'Bansky' , [ < EmailAddress > { address : 'pavelb@fabrikam.onmicrosoft.com' , name : 'Pavel Bansky' }], [ '+1 732 555 0102' ]);","title":"contacts"},{"location":"graph/docs/contacts/#pnpgraphcontacts","text":"The ability to manage contacts and folders in Outlook is a capability introduced in version 1.2.2 of @pnp/graph. Through the methods described you can add and edit both contacts and folders in a users Outlook.","title":"@pnp/graph/contacts"},{"location":"graph/docs/contacts/#get-all-of-the-contacts","text":"Using the contacts() you can get the users contacts from Outlook import { graph } from \"@pnp/graph\" ; const contacts = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contacts . get (); const contacts = await graph . me . contacts . get ();","title":"Get all of the Contacts"},{"location":"graph/docs/contacts/#add-a-new-contact","text":"Using the contacts.add() you can a add Contact to the users Outlook import { graph } from \"@pnp/graph\" ; const addedContact = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contacts . add ( 'Pavel' , 'Bansky' , [ < EmailAddress > { address : 'pavelb@fabrikam.onmicrosoft.com' , name : 'Pavel Bansky' }], [ '+1 732 555 0102' ]); const addedContact = await graph . me . contacts . add ( 'Pavel' , 'Bansky' , [ < EmailAddress > { address : 'pavelb@fabrikam.onmicrosoft.com' , name : 'Pavel Bansky' }], [ '+1 732 555 0102' ]);","title":"Add a new Contact"},{"location":"graph/docs/contacts/#get-contact-by-id","text":"Using the contacts.getById() you can get one of the users Contacts in Outlook import { graph } from \"@pnp/graph\" ; const contact = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contacts . getById ( 'userId' ); const contact = await graph . me . contacts . getById ( 'userId' );","title":"Get Contact by Id"},{"location":"graph/docs/contacts/#delete-a-contact","text":"Using the delete you can remove one of the users Contacts in Outlook import { graph } from \"@pnp/graph\" ; const delContact = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contacts . getById ( 'userId' ). delete (); const delContact = await graph . me . contacts . getById ( 'userId' ). delete ();","title":"Delete a Contact"},{"location":"graph/docs/contacts/#update-a-contact","text":"Using the update you can update one of the users Contacts in Outlook import { graph } from \"@pnp/graph\" ; const updContact = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contacts . getById ( 'userId' ). update ({ birthday : \"1986-05-30\" }); const updContact = await graph . me . contacts . getById ( 'userId' ). update ({ birthday : \"1986-05-30\" });","title":"Update a Contact"},{"location":"graph/docs/contacts/#get-all-of-the-contact-folders","text":"Using the contactFolders() you can get the users Contact Folders from Outlook import { graph } from \"@pnp/graph\" ; const contactFolders = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contactFolders . get (); const contactFolders = await graph . me . contactFolders . get ();","title":"Get all of the Contact Folders"},{"location":"graph/docs/contacts/#add-a-new-contact-folder","text":"Using the contactFolders.add() you can a add Contact Folder to the users Outlook import { graph } from \"@pnp/graph\" ; const addedContactFolder = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contactFolders . add ( 'displayName' , '<ParentFolderId>' ); const addedContactFolder = await graph . me . contactFolders . contactFolders . add ( 'displayName' , '<ParentFolderId>' );","title":"Add a new Contact Folder"},{"location":"graph/docs/contacts/#get-contact-folder-by-id","text":"Using the contactFolders.getById() you can get one of the users Contact Folders in Outlook import { graph } from \"@pnp/graph\" ; const contactFolder = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contactFolders . getById ( 'folderId' ); const contactFolder = await graph . me . contactFolders . getById ( 'folderId' );","title":"Get Contact Folder by Id"},{"location":"graph/docs/contacts/#delete-a-contact-folder","text":"Using the delete you can remove one of the users Contact Folders in Outlook import { graph } from \"@pnp/graph\" ; const delContactFolder = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contactFolders . getById ( 'folderId' ). delete (); const delContactFolder = await graph . me . contactFolders . getById ( 'folderId' ). delete ();","title":"Delete a Contact Folder"},{"location":"graph/docs/contacts/#update-a-contact-folder","text":"Using the update you can update one of the users Contact Folders in Outlook import { graph } from \"@pnp/graph\" ; const updContactFolder = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contactFolders . getById ( 'userId' ). update ({ displayName : \"value\" }); const updContactFolder = await graph . me . contactFolders . getById ( 'userId' ). update ({ displayName : \"value\" });","title":"Update a Contact Folder"},{"location":"graph/docs/contacts/#get-all-of-the-contacts-from-the-contact-folder","text":"Using the contacts() in the Contact Folder gets the users Contact from the folder. import { graph } from \"@pnp/graph\" ; const contactsInContactFolder = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contactFolders . getById ( 'folderId' ). contacts . get (); const contactsInContactFolder = await graph . me . contactFolders . getById ( 'folderId' ). contacts . get ();","title":"Get all of the Contacts from the Contact Folder"},{"location":"graph/docs/contacts/#get-child-folders-of-the-contact-folder","text":"Using the childFolders() you can get the Child Folders of the current Contact Folder from Outlook import { graph } from \"@pnp/graph\" ; const childFolders = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contactFolders . getById ( '<id>' ). childFolders . get (); const childFolders = await graph . me . contactFolders . getById ( '<id>' ). childFolders . get ();","title":"Get Child Folders of the Contact Folder"},{"location":"graph/docs/contacts/#add-a-new-child-folder","text":"Using the childFolders.add() you can a add Child Folder in a Contact Folder import { graph } from \"@pnp/graph\" ; const addedChildFolder = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contactFolders . getById ( '<id>' ). childFolders . add ( 'displayName' , '<ParentFolderId>' ); const addedChildFolder = await graph . me . contactFolders . getById ( '<id>' ). childFolders . add ( 'displayName' , '<ParentFolderId>' );","title":"Add a new Child Folder"},{"location":"graph/docs/contacts/#get-child-folder-by-id","text":"Using the childFolders.getById() you can get one of the users Child Folders in Outlook import { graph } from \"@pnp/graph\" ; const childFolder = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contactFolders . getById ( '<id>' ). childFolders . getById ( 'folderId' ); const childFolder = await graph . me . contactFolders . getById ( '<id>' ). childFolders . getById ( 'folderId' );","title":"Get Child Folder by Id"},{"location":"graph/docs/contacts/#add-contact-in-child-folder-of-contact-folder","text":"Using contacts.add in the Child Folder of a Contact Folder, adds a new Contact to that folder import { graph } from \"@pnp/graph\" ; const addedContact = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). contactFolders . getById ( '<id>' ). childFolders . getById ( 'folderId' ). contacts . add ( 'Pavel' , 'Bansky' , [ < EmailAddress > { address : 'pavelb@fabrikam.onmicrosoft.com' , name : 'Pavel Bansky' }], [ '+1 732 555 0102' ]); const addedContact = await graph . me . contactFolders . getById ( '<id>' ). childFolders . getById ( 'folderId' ). contacts . add ( 'Pavel' , 'Bansky' , [ < EmailAddress > { address : 'pavelb@fabrikam.onmicrosoft.com' , name : 'Pavel Bansky' }], [ '+1 732 555 0102' ]);","title":"Add Contact in Child Folder of Contact Folder"},{"location":"graph/docs/directoryobjects/","text":"@pnp/graph/directoryObjects \u00b6 The groups and directory roles for the user \u00b6 import { graph } from \"@pnp/graph\" ; const memberOf = await graph . users . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). memberOf . get (); const memberOf = await graph . me . memberOf . get (); Return all the groups the user, group or directoryObject is a member of \u00b6 import { graph } from \"@pnp/graph\" ; const memberGroups = await graph . users . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). getMemberGroups (); const memberGroups = await graph . me . getMemberGroups (); const memberGroups = await graph . groups . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). getMemberGroups (); const memberGroups = await graph . directoryObjects . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). getMemberGroups (); Returns all the groups, administrative units and directory roles that a user, group, or directory object is a member of. \u00b6 import { graph } from \"@pnp/graph\" ; const memberObjects = await graph . users . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). getMemberObjects (); const memberObjects = await graph . me . getMemberObjects (); const memberObjects = await graph . groups . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). getMemberObjects (); const memberObjects = await graph . directoryObjects . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). getMemberObjects (); Check for membership in a specified list of groups \u00b6 And returns from that list those groups of which the specified user, group, or directory object is a member import { graph } from \"@pnp/graph\" ; const checkedMembers = await graph . users . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). checkMemberGroups ([ \"c2fb52d1-5c60-42b1-8c7e-26ce8dc1e741\" , \"2001bb09-1d46-40a6-8176-7bb867fb75aa\" ]); const checkedMembers = await graph . me . checkMemberGroups ([ \"c2fb52d1-5c60-42b1-8c7e-26ce8dc1e741\" , \"2001bb09-1d46-40a6-8176-7bb867fb75aa\" ]); const checkedMembers = await graph . groups . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). checkMemberGroups ([ \"c2fb52d1-5c60-42b1-8c7e-26ce8dc1e741\" , \"2001bb09-1d46-40a6-8176-7bb867fb75aa\" ]); const checkedMembers = await graph . directoryObjects . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). checkMemberGroups ([ \"c2fb52d1-5c60-42b1-8c7e-26ce8dc1e741\" , \"2001bb09-1d46-40a6-8176-7bb867fb75aa\" ]); Get directoryObject by Id \u00b6 import { graph } from \"@pnp/graph\" ; const dirObject = await graph . directoryObjects . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). get (); Delete directoryObject \u00b6 import { graph } from \"@pnp/graph\" ; const deleted = await graph . directoryObjects . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). delete ()","title":"directory objects"},{"location":"graph/docs/directoryobjects/#pnpgraphdirectoryobjects","text":"","title":"@pnp/graph/directoryObjects"},{"location":"graph/docs/directoryobjects/#the-groups-and-directory-roles-for-the-user","text":"import { graph } from \"@pnp/graph\" ; const memberOf = await graph . users . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). memberOf . get (); const memberOf = await graph . me . memberOf . get ();","title":"The groups and directory roles for the user"},{"location":"graph/docs/directoryobjects/#return-all-the-groups-the-user-group-or-directoryobject-is-a-member-of","text":"import { graph } from \"@pnp/graph\" ; const memberGroups = await graph . users . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). getMemberGroups (); const memberGroups = await graph . me . getMemberGroups (); const memberGroups = await graph . groups . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). getMemberGroups (); const memberGroups = await graph . directoryObjects . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). getMemberGroups ();","title":"Return all the groups the user, group or directoryObject is a member of"},{"location":"graph/docs/directoryobjects/#returns-all-the-groups-administrative-units-and-directory-roles-that-a-user-group-or-directory-object-is-a-member-of","text":"import { graph } from \"@pnp/graph\" ; const memberObjects = await graph . users . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). getMemberObjects (); const memberObjects = await graph . me . getMemberObjects (); const memberObjects = await graph . groups . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). getMemberObjects (); const memberObjects = await graph . directoryObjects . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). getMemberObjects ();","title":"Returns all the groups, administrative units and directory roles that a user, group, or directory object is a member of."},{"location":"graph/docs/directoryobjects/#check-for-membership-in-a-specified-list-of-groups","text":"And returns from that list those groups of which the specified user, group, or directory object is a member import { graph } from \"@pnp/graph\" ; const checkedMembers = await graph . users . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). checkMemberGroups ([ \"c2fb52d1-5c60-42b1-8c7e-26ce8dc1e741\" , \"2001bb09-1d46-40a6-8176-7bb867fb75aa\" ]); const checkedMembers = await graph . me . checkMemberGroups ([ \"c2fb52d1-5c60-42b1-8c7e-26ce8dc1e741\" , \"2001bb09-1d46-40a6-8176-7bb867fb75aa\" ]); const checkedMembers = await graph . groups . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). checkMemberGroups ([ \"c2fb52d1-5c60-42b1-8c7e-26ce8dc1e741\" , \"2001bb09-1d46-40a6-8176-7bb867fb75aa\" ]); const checkedMembers = await graph . directoryObjects . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). checkMemberGroups ([ \"c2fb52d1-5c60-42b1-8c7e-26ce8dc1e741\" , \"2001bb09-1d46-40a6-8176-7bb867fb75aa\" ]);","title":"Check for membership in a specified list of groups"},{"location":"graph/docs/directoryobjects/#get-directoryobject-by-id","text":"import { graph } from \"@pnp/graph\" ; const dirObject = await graph . directoryObjects . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). get ();","title":"Get directoryObject by Id"},{"location":"graph/docs/directoryobjects/#delete-directoryobject","text":"import { graph } from \"@pnp/graph\" ; const deleted = await graph . directoryObjects . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). delete ()","title":"Delete directoryObject"},{"location":"graph/docs/insights/","text":"@pnp/graph/insights \u00b6 Insights are relationships calculated using advanced analytics and machine learning techniques. You can, for example, identify OneDrive documents trending around users. Get the trending documents \u00b6 Using the trending() returns documents from OneDrive and from SharePoint sites trending around a user. import { graph } from \"@pnp/graph\" ; const trending = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). insights . trending . get (); const trending = await graph . me . insights . trending . get (); Get the used documents \u00b6 Using the used() returns documents viewed and modified by a user. Includes documents the user used in OneDrive for Business, SharePoint, opened as email attachments, and as link attachments from sources like Box, DropBox and Google Drive. import { graph } from \"@pnp/graph\" ; const used = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). insights . used . get (); const used = await graph . me . insights . used . get (); Get the shared documents \u00b6 Using the shared() returns documents shared with a user. Documents can be shared as email attachments or as OneDrive for Business links sent in emails. import { graph } from \"@pnp/graph\" ; const shared = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). insights . shared . get (); const shared = await graph . me . insights . shared . get ();","title":"@pnp/graph/insights"},{"location":"graph/docs/insights/#pnpgraphinsights","text":"Insights are relationships calculated using advanced analytics and machine learning techniques. You can, for example, identify OneDrive documents trending around users.","title":"@pnp/graph/insights"},{"location":"graph/docs/insights/#get-the-trending-documents","text":"Using the trending() returns documents from OneDrive and from SharePoint sites trending around a user. import { graph } from \"@pnp/graph\" ; const trending = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). insights . trending . get (); const trending = await graph . me . insights . trending . get ();","title":"Get the trending documents"},{"location":"graph/docs/insights/#get-the-used-documents","text":"Using the used() returns documents viewed and modified by a user. Includes documents the user used in OneDrive for Business, SharePoint, opened as email attachments, and as link attachments from sources like Box, DropBox and Google Drive. import { graph } from \"@pnp/graph\" ; const used = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). insights . used . get (); const used = await graph . me . insights . used . get ();","title":"Get the used documents"},{"location":"graph/docs/insights/#get-the-shared-documents","text":"Using the shared() returns documents shared with a user. Documents can be shared as email attachments or as OneDrive for Business links sent in emails. import { graph } from \"@pnp/graph\" ; const shared = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). insights . shared . get (); const shared = await graph . me . insights . shared . get ();","title":"Get the shared documents"},{"location":"graph/docs/invitations/","text":"@pnp/graph/invitations \u00b6 The ability invite an external user via the invitation manager Create Invitation \u00b6 Using the invitations.create() you can create an Invitation. We need the email address of the user being invited and the URL user should be redirected to once the invitation is redeemed (redirect URL). import { graph } from \"@pnp/graph\" ; const invitationResult = await graph . invitations . create ( 'external.user@emailadress.com' , 'https://tenant.sharepoint.com/sites/redirecturi' );","title":"invitations"},{"location":"graph/docs/invitations/#pnpgraphinvitations","text":"The ability invite an external user via the invitation manager","title":"@pnp/graph/invitations"},{"location":"graph/docs/invitations/#create-invitation","text":"Using the invitations.create() you can create an Invitation. We need the email address of the user being invited and the URL user should be redirected to once the invitation is redeemed (redirect URL). import { graph } from \"@pnp/graph\" ; const invitationResult = await graph . invitations . create ( 'external.user@emailadress.com' , 'https://tenant.sharepoint.com/sites/redirecturi' );","title":"Create Invitation"},{"location":"graph/docs/onedrive/","text":"@pnp/graph/onedrive \u00b6 The ability to manage drives and drive items in Onedrive is a capability introduced in version 1.2.4 of @pnp/graph. Through the methods described you can manage drives and drive items in Onedrive. Get the default drive \u00b6 Using the drive() you can get the default drive from Onedrive import { graph } from \"@pnp/graph\" ; const drives = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . get (); const drives = await graph . me . drives . get (); Get all of the drives \u00b6 Using the drives() you can get the users available drives from Onedrive import { graph } from \"@pnp/graph\" ; const drives = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . get (); const drives = await graph . me . drives . get (); Get drive by Id \u00b6 Using the drives.getById() you can get one of the available drives in Outlook import { graph } from \"@pnp/graph\" ; const drive = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ); const drive = await graph . me . drives . getById ( 'driveId' ); Get the associated list of a drive \u00b6 Using the list() you get the associated list import { graph } from \"@pnp/graph\" ; const list = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). list . get (); const list = await graph . me . drives . getById ( 'driveId' ). list . get (); Get the recent files \u00b6 Using the recent() you get the recent files import { graph } from \"@pnp/graph\" ; const files = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). recent . get (); const files = await graph . me . drives . getById ( 'driveId' ). recent . get (); Get the files shared with me \u00b6 Using the sharedWithMe() you get the files shared with the user import { graph } from \"@pnp/graph\" ; const shared = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). sharedWithMe . get (); const shared = await graph . me . drives . getById ( 'driveId' ). sharedWithMe . get (); Get the Root folder \u00b6 Using the root() you get the root folder import { graph } from \"@pnp/graph\" ; const root = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). root . get (); const root = await graph . me . drives . getById ( 'driveId' ). root . get (); Get the Children \u00b6 Using the children() you get the children import { graph } from \"@pnp/graph\" ; const rootChildren = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). root . children . get (); const rootChildren = await graph . me . drives . getById ( 'driveId' ). root . children . get (); const itemChildren = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). items . getById ( 'itemId' ). children . get (); const itemChildren = await graph . me . drives . getById ( 'driveId' ). root . items . getById ( 'itemId' ). children . get (); Add folder or item \u00b6 Using the add you can add a folder or an item import { graph } from \"@pnp/graph\" ; import { DriveItem as IDriveItem } from \"@microsoft/microsoft-graph-types\" ; const addFolder = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). root . children . add ( 'New Folder' , < IDriveItem > { folder : {}}); const addFolder = await graph . me . drives . getById ( 'driveId' ). root . children . add ( 'New Folder' , < IDriveItem > { folder : {}}); Search items \u00b6 Using the search() you can search for items, and optionally select properties import { graph } from \"@pnp/graph\" ; const search = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ) root . search ( 'queryText' ). get (); const search = await graph . me . drives . getById ( 'driveId' ) root . search ( 'queryText' ). get (); Get specific item in drive \u00b6 Using the items.getById() you can get a specific item from the current drive import { graph } from \"@pnp/graph\" ; const item = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). items . getById ( 'itemId' ); const item = await graph . me . drives . getById ( 'driveId' ). items . getById ( 'itemId' ); Get thumbnails \u00b6 Using the thumbnails() you get the thumbnails import { graph } from \"@pnp/graph\" ; const thumbs = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). items . getById ( 'itemId' ). thumbnails . get (); const thumbs = await graph . me . drives . getById ( 'driveId' ). items . getById ( 'itemId' ). thumbnails . get (); Delete drive item \u00b6 Using the delete() you delete the current item import { graph } from \"@pnp/graph\" ; const thumbs = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). items . getById ( 'itemId' ). delete (); const thumbs = await graph . me . drives . getById ( 'driveId' ). items . getById ( 'itemId' ). delete (); Update drive item \u00b6 Using the update() you update the current item import { graph } from \"@pnp/graph\" ; const update = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). items . getById ( 'itemId' ). update ({ name : \"New Name\" }); const update = await graph . me . drives . getById ( 'driveId' ). items . getById ( 'itemId' ). update ({ name : \"New Name\" }); Move drive item \u00b6 Using the move() you move the current item, and optionally update it import { graph } from \"@pnp/graph\" ; // Requires a parentReference to the new folder location const move = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). items . getById ( 'itemId' ). move ({ parentReference : { id : 'itemId' }}, { name : \"New Name\" }); const move = await graph . me . drives . getById ( 'driveId' ). items . getById ( 'itemId' ). move ({ parentReference : { id : 'itemId' }}, { name : \"New Name\" });","title":"onedrive"},{"location":"graph/docs/onedrive/#pnpgraphonedrive","text":"The ability to manage drives and drive items in Onedrive is a capability introduced in version 1.2.4 of @pnp/graph. Through the methods described you can manage drives and drive items in Onedrive.","title":"@pnp/graph/onedrive"},{"location":"graph/docs/onedrive/#get-the-default-drive","text":"Using the drive() you can get the default drive from Onedrive import { graph } from \"@pnp/graph\" ; const drives = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . get (); const drives = await graph . me . drives . get ();","title":"Get the default drive"},{"location":"graph/docs/onedrive/#get-all-of-the-drives","text":"Using the drives() you can get the users available drives from Onedrive import { graph } from \"@pnp/graph\" ; const drives = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . get (); const drives = await graph . me . drives . get ();","title":"Get all of the drives"},{"location":"graph/docs/onedrive/#get-drive-by-id","text":"Using the drives.getById() you can get one of the available drives in Outlook import { graph } from \"@pnp/graph\" ; const drive = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ); const drive = await graph . me . drives . getById ( 'driveId' );","title":"Get drive by Id"},{"location":"graph/docs/onedrive/#get-the-associated-list-of-a-drive","text":"Using the list() you get the associated list import { graph } from \"@pnp/graph\" ; const list = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). list . get (); const list = await graph . me . drives . getById ( 'driveId' ). list . get ();","title":"Get the associated list of a drive"},{"location":"graph/docs/onedrive/#get-the-recent-files","text":"Using the recent() you get the recent files import { graph } from \"@pnp/graph\" ; const files = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). recent . get (); const files = await graph . me . drives . getById ( 'driveId' ). recent . get ();","title":"Get the recent files"},{"location":"graph/docs/onedrive/#get-the-files-shared-with-me","text":"Using the sharedWithMe() you get the files shared with the user import { graph } from \"@pnp/graph\" ; const shared = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). sharedWithMe . get (); const shared = await graph . me . drives . getById ( 'driveId' ). sharedWithMe . get ();","title":"Get the files shared with me"},{"location":"graph/docs/onedrive/#get-the-root-folder","text":"Using the root() you get the root folder import { graph } from \"@pnp/graph\" ; const root = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). root . get (); const root = await graph . me . drives . getById ( 'driveId' ). root . get ();","title":"Get the Root folder"},{"location":"graph/docs/onedrive/#get-the-children","text":"Using the children() you get the children import { graph } from \"@pnp/graph\" ; const rootChildren = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). root . children . get (); const rootChildren = await graph . me . drives . getById ( 'driveId' ). root . children . get (); const itemChildren = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). items . getById ( 'itemId' ). children . get (); const itemChildren = await graph . me . drives . getById ( 'driveId' ). root . items . getById ( 'itemId' ). children . get ();","title":"Get the Children"},{"location":"graph/docs/onedrive/#add-folder-or-item","text":"Using the add you can add a folder or an item import { graph } from \"@pnp/graph\" ; import { DriveItem as IDriveItem } from \"@microsoft/microsoft-graph-types\" ; const addFolder = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). root . children . add ( 'New Folder' , < IDriveItem > { folder : {}}); const addFolder = await graph . me . drives . getById ( 'driveId' ). root . children . add ( 'New Folder' , < IDriveItem > { folder : {}});","title":"Add folder or item"},{"location":"graph/docs/onedrive/#search-items","text":"Using the search() you can search for items, and optionally select properties import { graph } from \"@pnp/graph\" ; const search = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ) root . search ( 'queryText' ). get (); const search = await graph . me . drives . getById ( 'driveId' ) root . search ( 'queryText' ). get ();","title":"Search items"},{"location":"graph/docs/onedrive/#get-specific-item-in-drive","text":"Using the items.getById() you can get a specific item from the current drive import { graph } from \"@pnp/graph\" ; const item = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). items . getById ( 'itemId' ); const item = await graph . me . drives . getById ( 'driveId' ). items . getById ( 'itemId' );","title":"Get specific item in drive"},{"location":"graph/docs/onedrive/#get-thumbnails","text":"Using the thumbnails() you get the thumbnails import { graph } from \"@pnp/graph\" ; const thumbs = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). items . getById ( 'itemId' ). thumbnails . get (); const thumbs = await graph . me . drives . getById ( 'driveId' ). items . getById ( 'itemId' ). thumbnails . get ();","title":"Get thumbnails"},{"location":"graph/docs/onedrive/#delete-drive-item","text":"Using the delete() you delete the current item import { graph } from \"@pnp/graph\" ; const thumbs = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). items . getById ( 'itemId' ). delete (); const thumbs = await graph . me . drives . getById ( 'driveId' ). items . getById ( 'itemId' ). delete ();","title":"Delete drive item"},{"location":"graph/docs/onedrive/#update-drive-item","text":"Using the update() you update the current item import { graph } from \"@pnp/graph\" ; const update = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). items . getById ( 'itemId' ). update ({ name : \"New Name\" }); const update = await graph . me . drives . getById ( 'driveId' ). items . getById ( 'itemId' ). update ({ name : \"New Name\" });","title":"Update drive item"},{"location":"graph/docs/onedrive/#move-drive-item","text":"Using the move() you move the current item, and optionally update it import { graph } from \"@pnp/graph\" ; // Requires a parentReference to the new folder location const move = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). drives . getById ( 'driveId' ). items . getById ( 'itemId' ). move ({ parentReference : { id : 'itemId' }}, { name : \"New Name\" }); const move = await graph . me . drives . getById ( 'driveId' ). items . getById ( 'itemId' ). move ({ parentReference : { id : 'itemId' }}, { name : \"New Name\" });","title":"Move drive item"},{"location":"graph/docs/people/","text":"@pnp/graph/people \u00b6 The ability to retrieve a list of person objects ordered by their relevance to the user, which is determined by the user's communication and collaboration patterns, and business relationships. Get all of the people \u00b6 Using the people() you can retrieve a list of person objects ordered by their relevance to the user. import { graph } from \"@pnp/graph\" ; const people = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). people . get (); const people = await graph . me . people . get ();","title":"@pnp/graph/people"},{"location":"graph/docs/people/#pnpgraphpeople","text":"The ability to retrieve a list of person objects ordered by their relevance to the user, which is determined by the user's communication and collaboration patterns, and business relationships.","title":"@pnp/graph/people"},{"location":"graph/docs/people/#get-all-of-the-people","text":"Using the people() you can retrieve a list of person objects ordered by their relevance to the user. import { graph } from \"@pnp/graph\" ; const people = await graph . users . getById ( 'user@tenant.onmicrosoft.com' ). people . get (); const people = await graph . me . people . get ();","title":"Get all of the people"},{"location":"graph/docs/planner/","text":"@pnp/graph/planner \u00b6 The ability to manage plans and tasks in Planner is a capability introduced in version 1.2.4 of @pnp/graph. Through the methods described you can add, update and delete items in Planner. Get Plans by Id \u00b6 Using the planner.plans.getById() you can get a specific Plan. Planner.plans is not an available endpoint, you need to get a specific Plan. import { graph } from \"@pnp/graph\" ; const plan = await graph . planner . plans . getById ( 'planId' ); Add new Plan \u00b6 Using the planner.plans.add() you can create a new Plan. import { graph } from \"@pnp/graph\" ; const newPlan = await graph . planner . plans . add ( 'groupObjectId' , 'title' ); Get Tasks in Plan \u00b6 Using the tasks() you can get the Tasks in a Plan. import { graph } from \"@pnp/graph\" ; const planTasks = await graph . planner . plans . getById ( 'planId' ). tasks . get (); Get Buckets in Plan \u00b6 Using the buckets() you can get the Buckets in a Plan. import { graph } from \"@pnp/graph\" ; const planBuckets = await graph . planner . plans . getById ( 'planId' ). buckets . get (); Get Details in Plan \u00b6 Using the details() you can get the details in a Plan. import { graph } from \"@pnp/graph\" ; const planDetails = await graph . planner . plans . getById ( 'planId' ). details . get (); Delete Plan \u00b6 Using the delete() you can get delete a Plan. import { graph } from \"@pnp/graph\" ; const delPlan = await graph . planner . plans . getById ( 'planId' ). delete (); Update Plan \u00b6 Using the update() you can get update a Plan. import { graph } from \"@pnp/graph\" ; const updPlan = await graph . planner . plans . getById ( 'planId' ). update ({ title : 'New Title' }); Get Task by Id \u00b6 Using the planner.tasks.getById() you can get a specific Task. Planner.tasks is not an available endpoint, you need to get a specific Task. import { graph } from \"@pnp/graph\" ; const task = await graph . planner . tasks . getById ( 'taskId' ); Add new Task \u00b6 Using the planner.tasks.add() you can create a new Task. import { graph } from \"@pnp/graph\" ; const newTask = await graph . planner . tasks . add ( 'planId' , 'title' ); Get Details in Task \u00b6 Using the details() you can get the details in a Task. import { graph } from \"@pnp/graph\" ; const taskDetails = await graph . planner . tasks . getById ( 'taskId' ). details . get (); Delete Task \u00b6 Using the delete() you can get delete a Task. import { graph } from \"@pnp/graph\" ; const delTask = await graph . planner . tasks . getById ( 'taskId' ). delete (); Update Task \u00b6 Using the update() you can get update a Task. import { graph } from \"@pnp/graph\" ; const updTask = await graph . planner . tasks . getById ( 'taskId' ). update ({ properties }); Get Buckets by Id \u00b6 Using the planner.buckets.getById() you can get a specific Bucket. planner.buckets is not an available endpoint, you need to get a specific Bucket. import { graph } from \"@pnp/graph\" ; const bucket = await graph . planner . buckets . getById ( 'bucketId' ); Add new Bucket \u00b6 Using the planner.buckets.add() you can create a new Bucket. import { graph } from \"@pnp/graph\" ; const newBucket = await graph . planner . buckets . add ( 'name' , 'planId' ); Update Bucket \u00b6 Using the update() you can get update a Bucket. import { graph } from \"@pnp/graph\" ; const updBucket = await graph . planner . buckets . getById ( 'bucketId' ). update ({ name : \"Name\" }); Delete Bucket \u00b6 Using the delete() you can get delete a Bucket. import { graph } from \"@pnp/graph\" ; const delBucket = await graph . planner . buckets . getById ( 'bucketId' ). delete (); Get Bucket Tasks \u00b6 Using the tasks() you can get Tasks in a Bucket. import { graph } from \"@pnp/graph\" ; const bucketTasks = await graph . planner . buckets . getById ( 'bucketId' ). tasks . get ();","title":"planner"},{"location":"graph/docs/planner/#pnpgraphplanner","text":"The ability to manage plans and tasks in Planner is a capability introduced in version 1.2.4 of @pnp/graph. Through the methods described you can add, update and delete items in Planner.","title":"@pnp/graph/planner"},{"location":"graph/docs/planner/#get-plans-by-id","text":"Using the planner.plans.getById() you can get a specific Plan. Planner.plans is not an available endpoint, you need to get a specific Plan. import { graph } from \"@pnp/graph\" ; const plan = await graph . planner . plans . getById ( 'planId' );","title":"Get Plans by Id"},{"location":"graph/docs/planner/#add-new-plan","text":"Using the planner.plans.add() you can create a new Plan. import { graph } from \"@pnp/graph\" ; const newPlan = await graph . planner . plans . add ( 'groupObjectId' , 'title' );","title":"Add new Plan"},{"location":"graph/docs/planner/#get-tasks-in-plan","text":"Using the tasks() you can get the Tasks in a Plan. import { graph } from \"@pnp/graph\" ; const planTasks = await graph . planner . plans . getById ( 'planId' ). tasks . get ();","title":"Get Tasks in Plan"},{"location":"graph/docs/planner/#get-buckets-in-plan","text":"Using the buckets() you can get the Buckets in a Plan. import { graph } from \"@pnp/graph\" ; const planBuckets = await graph . planner . plans . getById ( 'planId' ). buckets . get ();","title":"Get Buckets in Plan"},{"location":"graph/docs/planner/#get-details-in-plan","text":"Using the details() you can get the details in a Plan. import { graph } from \"@pnp/graph\" ; const planDetails = await graph . planner . plans . getById ( 'planId' ). details . get ();","title":"Get Details in Plan"},{"location":"graph/docs/planner/#delete-plan","text":"Using the delete() you can get delete a Plan. import { graph } from \"@pnp/graph\" ; const delPlan = await graph . planner . plans . getById ( 'planId' ). delete ();","title":"Delete Plan"},{"location":"graph/docs/planner/#update-plan","text":"Using the update() you can get update a Plan. import { graph } from \"@pnp/graph\" ; const updPlan = await graph . planner . plans . getById ( 'planId' ). update ({ title : 'New Title' });","title":"Update Plan"},{"location":"graph/docs/planner/#get-task-by-id","text":"Using the planner.tasks.getById() you can get a specific Task. Planner.tasks is not an available endpoint, you need to get a specific Task. import { graph } from \"@pnp/graph\" ; const task = await graph . planner . tasks . getById ( 'taskId' );","title":"Get Task by Id"},{"location":"graph/docs/planner/#add-new-task","text":"Using the planner.tasks.add() you can create a new Task. import { graph } from \"@pnp/graph\" ; const newTask = await graph . planner . tasks . add ( 'planId' , 'title' );","title":"Add new Task"},{"location":"graph/docs/planner/#get-details-in-task","text":"Using the details() you can get the details in a Task. import { graph } from \"@pnp/graph\" ; const taskDetails = await graph . planner . tasks . getById ( 'taskId' ). details . get ();","title":"Get Details in Task"},{"location":"graph/docs/planner/#delete-task","text":"Using the delete() you can get delete a Task. import { graph } from \"@pnp/graph\" ; const delTask = await graph . planner . tasks . getById ( 'taskId' ). delete ();","title":"Delete Task"},{"location":"graph/docs/planner/#update-task","text":"Using the update() you can get update a Task. import { graph } from \"@pnp/graph\" ; const updTask = await graph . planner . tasks . getById ( 'taskId' ). update ({ properties });","title":"Update Task"},{"location":"graph/docs/planner/#get-buckets-by-id","text":"Using the planner.buckets.getById() you can get a specific Bucket. planner.buckets is not an available endpoint, you need to get a specific Bucket. import { graph } from \"@pnp/graph\" ; const bucket = await graph . planner . buckets . getById ( 'bucketId' );","title":"Get Buckets by Id"},{"location":"graph/docs/planner/#add-new-bucket","text":"Using the planner.buckets.add() you can create a new Bucket. import { graph } from \"@pnp/graph\" ; const newBucket = await graph . planner . buckets . add ( 'name' , 'planId' );","title":"Add new Bucket"},{"location":"graph/docs/planner/#update-bucket","text":"Using the update() you can get update a Bucket. import { graph } from \"@pnp/graph\" ; const updBucket = await graph . planner . buckets . getById ( 'bucketId' ). update ({ name : \"Name\" });","title":"Update Bucket"},{"location":"graph/docs/planner/#delete-bucket","text":"Using the delete() you can get delete a Bucket. import { graph } from \"@pnp/graph\" ; const delBucket = await graph . planner . buckets . getById ( 'bucketId' ). delete ();","title":"Delete Bucket"},{"location":"graph/docs/planner/#get-bucket-tasks","text":"Using the tasks() you can get Tasks in a Bucket. import { graph } from \"@pnp/graph\" ; const bucketTasks = await graph . planner . buckets . getById ( 'bucketId' ). tasks . get ();","title":"Get Bucket Tasks"},{"location":"graph/docs/security/","text":"@pnp/graph/security \u00b6 The Microsoft Graph Security API can be used as a federated security aggregation service to submit queries to all onboarded security providers to get aggregated responses. Get all Alerts \u00b6 Using the alerts() to retrieve a list of Alert objects import { graph } from \"@pnp/graph\" ; const alerts = await graph . security . alerts . get (); Get an Alert by Id \u00b6 Using the alerts.getById() to retrieve a specific Alert object import { graph } from \"@pnp/graph\" ; const alert = await graph . security . alerts . getById ( 'alertId' ). get (); Update an Alert \u00b6 Using the alerts.getById().update() to retrieve a specific Alert object import { graph } from \"@pnp/graph\" ; const updAlert = await graph . security . alerts . getById ( 'alertId' ). update ({ status : 'Status' });","title":"@pnp/graph/security"},{"location":"graph/docs/security/#pnpgraphsecurity","text":"The Microsoft Graph Security API can be used as a federated security aggregation service to submit queries to all onboarded security providers to get aggregated responses.","title":"@pnp/graph/security"},{"location":"graph/docs/security/#get-all-alerts","text":"Using the alerts() to retrieve a list of Alert objects import { graph } from \"@pnp/graph\" ; const alerts = await graph . security . alerts . get ();","title":"Get all Alerts"},{"location":"graph/docs/security/#get-an-alert-by-id","text":"Using the alerts.getById() to retrieve a specific Alert object import { graph } from \"@pnp/graph\" ; const alert = await graph . security . alerts . getById ( 'alertId' ). get ();","title":"Get an Alert by Id"},{"location":"graph/docs/security/#update-an-alert","text":"Using the alerts.getById().update() to retrieve a specific Alert object import { graph } from \"@pnp/graph\" ; const updAlert = await graph . security . alerts . getById ( 'alertId' ). update ({ status : 'Status' });","title":"Update an Alert"},{"location":"graph/docs/sites/","text":"@pnp/graph/sites \u00b6 The ability to manage sites, lists and listitems in SharePoint is a capability introduced in version 1.3.0 of @pnp/graph. Get the Root Site \u00b6 Using the sites.root()() you can get the tenant root site import { graph } from \"@pnp/graph\" ; const tenantRootSite = await graph . sites . root . get () Get the Root Site by Id \u00b6 Using the sites.getById()() you can get the root site as well import { graph } from \"@pnp/graph\" ; const tenantRootSite = await graph . sites . getById ( 'contoso.sharepoint.com' ). get () Access a Site by server-relative URL \u00b6 Using the sites.getById()() you can get a specific site. With the combination of the base URL and a relative URL. We are using an internal method for combining the URL in the right combination, with : ex: contoso.sharepoint.com:/sites/site1: Here are a few url combinations that works: import { graph } from \"@pnp/graph\" ; // No / in the URLs const siteByRelativeUrl = await graph . sites . getById ( 'contoso.sharepoint.com' , 'sites/site1' ). get () // Both trailing / in the base URL and starting / in the relative URL const siteByRelativeUrl = await graph . sites . getById ( 'contoso.sharepoint.com/' , '/sites/site1' ). get () // Both trailing / in the base URL and starting and trailing / in the relative URL const siteByRelativeUrl = await graph . sites . getById ( 'contoso.sharepoint.com/' , '/sites/site1/' ). get () Get the Sub Sites in a Site \u00b6 Using the sites()() you can get the sub sites of a site. As this is returned as Sites, you could use getById() for a specific site and use the operations. import { graph } from \"@pnp/graph\" ; const subsites = await graph . sites . getById ( 'contoso.sharepoint.com' ). sites . get (); Get Content Types \u00b6 Using the contentTypes()() you can get the Content Types from a Site or from a List import { graph } from \"@pnp/graph\" ; const contentTypesFromSite = await graph . sites . getById ( 'contoso.sharepoint.com' ). contentTypes . get (); const contentTypesFromList = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). contentTypes . get (); Get Specific Content Type \u00b6 Using the getById() you can get a specific Content Type from a Site or from a List import { graph } from \"@pnp/graph\" ; const contentTypeFromSite = await graph . sites . getById ( 'contoso.sharepoint.com' ). contentTypes . getById ( 'contentTypeId' ). get (); const contentTypeFromList = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). contentTypes . getById ( 'contentTypeId' ). get (); Get the Lists in a Site \u00b6 Using the lists() you can get the lists of a site. import { graph } from \"@pnp/graph\" ; const lists = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . get (); Get a specific List in a Site \u00b6 Using the lists.getById() you can get the lists of a site. import { graph } from \"@pnp/graph\" ; const list = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). get (); Create a Lists in a Site \u00b6 Using the lists.create() you can create a list in a site. import { graph } from \"@pnp/graph\" ; const newLists = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . create ( 'DisplayName' , { contentTypesEnabled : true , hidden : false , template : \"genericList\" }) Get the default drive \u00b6 Using the drive() you can get the default drive from a Site or a List import { graph } from \"@pnp/graph\" ; const drive = await graph . sites . getById ( 'contoso.sharepoint.com' ). drive . get (); const drive = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). drive . get (); Get all of the drives \u00b6 Using the drives() you can get the drives from the Site import { graph } from \"@pnp/graph\" ; const drives = await graph . sites . getById ( 'contoso.sharepoint.com' ). drives . get (); Get drive by Id \u00b6 Using the drives.getById() you can get one specific Drive. For more operations make sure to have a look in the onedrive documentation. import { graph } from \"@pnp/graph\" ; const drive = await raph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). drives . getById ( 'driveId' ). get (); Get Columns \u00b6 Using the columns() you can get the columns from a Site or from a List import { graph } from \"@pnp/graph\" ; const columnsFromSite = await graph . sites . getById ( 'contoso.sharepoint.com' ). columns . get (); const columnsFromList = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). columns . get (); Get Specific Column \u00b6 Using the columns.getById() you can get a specific column from a Site or from a List import { graph } from \"@pnp/graph\" ; const columnFromSite = await graph . sites . getById ( 'contoso.sharepoint.com' ). columns . getById ( 'columnId' ). get (); const columnsFromList = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). columns . getById ( 'columnId' ). get (); Get Column Links \u00b6 Using the column.columnLinks() you can get the column links for a specific column, from a Site or from a List import { graph } from \"@pnp/graph\" ; const columnLinksFromSite = await graph . sites . getById ( 'contoso.sharepoint.com' ). columns . getById ( 'columnId' ). columnLinks . get (); const columnLinksFromList = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). columns . getById ( 'columnId' ). columnLinks . get (); Get Column Link \u00b6 Using the column.columnLinks().getById() you can get a specific column link for a specific column, from a Site or from a List import { graph } from \"@pnp/graph\" ; const columnLinkFromSite = await graph . sites . getById ( 'contoso.sharepoint.com' ). columns . getById ( 'columnId' ). columnLinks . getById ( 'columnLinkId' ). get (); const columnLinkFromList = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). columns . getById ( 'columnId' ). columnLinks . getById ( 'columnLinkId' ). get (); Get Items \u00b6 Using the items() you can get the Items from a List import { graph } from \"@pnp/graph\" ; const itemsFromList = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). items . get (); Get Specific Item \u00b6 Using the getById()() you can get a specific Item from a List import { graph } from \"@pnp/graph\" ; const itemFromList = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). items . getById ( 'itemId' ). get (); Create Item \u00b6 Using the items.create() you can create an Item in a List. import { graph } from \"@pnp/graph\" ; const newItem = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). items . create ({ \"Title\" : \"Widget\" , \"Color\" : \"Purple\" , \"Weight\" : 32 }); Update Item \u00b6 Using the update() you can update an Item in a List. import { graph } from \"@pnp/graph\" ; const Item = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). items . getById ( 'itemId' ). update ({ { \"Color\" : \"Fuchsia\" } }) Delete Item \u00b6 Using the delete() you can delete an Item in a List. import { graph } from \"@pnp/graph\" ; const Item = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). items . getById ( 'itemId' ). delete () Get Fields from Item \u00b6 Using the fields() you can the Fields in an Item import { graph } from \"@pnp/graph\" ; const fieldsFromItem = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). items . getById ( 'itemId' ). fields . get (); Get Versions from Item \u00b6 Using the versions() you can the Versions of an Item import { graph } from \"@pnp/graph\" ; const versionsFromItem = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). items . getById ( 'itemId' ). versions . get (); Get Version from Item \u00b6 Using the versions.getById()() you can the Versions of an Item import { graph } from \"@pnp/graph\" ; const versionFromItem = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). items . getById ( 'itemId' ). versions . getById ( 'versionId' ). get ();","title":"@pnp/graph/sites"},{"location":"graph/docs/sites/#pnpgraphsites","text":"The ability to manage sites, lists and listitems in SharePoint is a capability introduced in version 1.3.0 of @pnp/graph.","title":"@pnp/graph/sites"},{"location":"graph/docs/sites/#get-the-root-site","text":"Using the sites.root()() you can get the tenant root site import { graph } from \"@pnp/graph\" ; const tenantRootSite = await graph . sites . root . get ()","title":"Get the Root Site"},{"location":"graph/docs/sites/#get-the-root-site-by-id","text":"Using the sites.getById()() you can get the root site as well import { graph } from \"@pnp/graph\" ; const tenantRootSite = await graph . sites . getById ( 'contoso.sharepoint.com' ). get ()","title":"Get the Root Site by Id"},{"location":"graph/docs/sites/#access-a-site-by-server-relative-url","text":"Using the sites.getById()() you can get a specific site. With the combination of the base URL and a relative URL. We are using an internal method for combining the URL in the right combination, with : ex: contoso.sharepoint.com:/sites/site1: Here are a few url combinations that works: import { graph } from \"@pnp/graph\" ; // No / in the URLs const siteByRelativeUrl = await graph . sites . getById ( 'contoso.sharepoint.com' , 'sites/site1' ). get () // Both trailing / in the base URL and starting / in the relative URL const siteByRelativeUrl = await graph . sites . getById ( 'contoso.sharepoint.com/' , '/sites/site1' ). get () // Both trailing / in the base URL and starting and trailing / in the relative URL const siteByRelativeUrl = await graph . sites . getById ( 'contoso.sharepoint.com/' , '/sites/site1/' ). get ()","title":"Access a Site by server-relative URL"},{"location":"graph/docs/sites/#get-the-sub-sites-in-a-site","text":"Using the sites()() you can get the sub sites of a site. As this is returned as Sites, you could use getById() for a specific site and use the operations. import { graph } from \"@pnp/graph\" ; const subsites = await graph . sites . getById ( 'contoso.sharepoint.com' ). sites . get ();","title":"Get the Sub Sites in a Site"},{"location":"graph/docs/sites/#get-content-types","text":"Using the contentTypes()() you can get the Content Types from a Site or from a List import { graph } from \"@pnp/graph\" ; const contentTypesFromSite = await graph . sites . getById ( 'contoso.sharepoint.com' ). contentTypes . get (); const contentTypesFromList = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). contentTypes . get ();","title":"Get Content Types"},{"location":"graph/docs/sites/#get-specific-content-type","text":"Using the getById() you can get a specific Content Type from a Site or from a List import { graph } from \"@pnp/graph\" ; const contentTypeFromSite = await graph . sites . getById ( 'contoso.sharepoint.com' ). contentTypes . getById ( 'contentTypeId' ). get (); const contentTypeFromList = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). contentTypes . getById ( 'contentTypeId' ). get ();","title":"Get Specific Content Type"},{"location":"graph/docs/sites/#get-the-lists-in-a-site","text":"Using the lists() you can get the lists of a site. import { graph } from \"@pnp/graph\" ; const lists = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . get ();","title":"Get the Lists in a Site"},{"location":"graph/docs/sites/#get-a-specific-list-in-a-site","text":"Using the lists.getById() you can get the lists of a site. import { graph } from \"@pnp/graph\" ; const list = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). get ();","title":"Get a specific List in a Site"},{"location":"graph/docs/sites/#create-a-lists-in-a-site","text":"Using the lists.create() you can create a list in a site. import { graph } from \"@pnp/graph\" ; const newLists = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . create ( 'DisplayName' , { contentTypesEnabled : true , hidden : false , template : \"genericList\" })","title":"Create a Lists in a Site"},{"location":"graph/docs/sites/#get-the-default-drive","text":"Using the drive() you can get the default drive from a Site or a List import { graph } from \"@pnp/graph\" ; const drive = await graph . sites . getById ( 'contoso.sharepoint.com' ). drive . get (); const drive = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). drive . get ();","title":"Get the default drive"},{"location":"graph/docs/sites/#get-all-of-the-drives","text":"Using the drives() you can get the drives from the Site import { graph } from \"@pnp/graph\" ; const drives = await graph . sites . getById ( 'contoso.sharepoint.com' ). drives . get ();","title":"Get all of the drives"},{"location":"graph/docs/sites/#get-drive-by-id","text":"Using the drives.getById() you can get one specific Drive. For more operations make sure to have a look in the onedrive documentation. import { graph } from \"@pnp/graph\" ; const drive = await raph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). drives . getById ( 'driveId' ). get ();","title":"Get drive by Id"},{"location":"graph/docs/sites/#get-columns","text":"Using the columns() you can get the columns from a Site or from a List import { graph } from \"@pnp/graph\" ; const columnsFromSite = await graph . sites . getById ( 'contoso.sharepoint.com' ). columns . get (); const columnsFromList = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). columns . get ();","title":"Get Columns"},{"location":"graph/docs/sites/#get-specific-column","text":"Using the columns.getById() you can get a specific column from a Site or from a List import { graph } from \"@pnp/graph\" ; const columnFromSite = await graph . sites . getById ( 'contoso.sharepoint.com' ). columns . getById ( 'columnId' ). get (); const columnsFromList = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). columns . getById ( 'columnId' ). get ();","title":"Get Specific Column"},{"location":"graph/docs/sites/#get-column-links","text":"Using the column.columnLinks() you can get the column links for a specific column, from a Site or from a List import { graph } from \"@pnp/graph\" ; const columnLinksFromSite = await graph . sites . getById ( 'contoso.sharepoint.com' ). columns . getById ( 'columnId' ). columnLinks . get (); const columnLinksFromList = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). columns . getById ( 'columnId' ). columnLinks . get ();","title":"Get Column Links"},{"location":"graph/docs/sites/#get-column-link","text":"Using the column.columnLinks().getById() you can get a specific column link for a specific column, from a Site or from a List import { graph } from \"@pnp/graph\" ; const columnLinkFromSite = await graph . sites . getById ( 'contoso.sharepoint.com' ). columns . getById ( 'columnId' ). columnLinks . getById ( 'columnLinkId' ). get (); const columnLinkFromList = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). columns . getById ( 'columnId' ). columnLinks . getById ( 'columnLinkId' ). get ();","title":"Get Column Link"},{"location":"graph/docs/sites/#get-items","text":"Using the items() you can get the Items from a List import { graph } from \"@pnp/graph\" ; const itemsFromList = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). items . get ();","title":"Get Items"},{"location":"graph/docs/sites/#get-specific-item","text":"Using the getById()() you can get a specific Item from a List import { graph } from \"@pnp/graph\" ; const itemFromList = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). items . getById ( 'itemId' ). get ();","title":"Get Specific Item"},{"location":"graph/docs/sites/#create-item","text":"Using the items.create() you can create an Item in a List. import { graph } from \"@pnp/graph\" ; const newItem = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). items . create ({ \"Title\" : \"Widget\" , \"Color\" : \"Purple\" , \"Weight\" : 32 });","title":"Create Item"},{"location":"graph/docs/sites/#update-item","text":"Using the update() you can update an Item in a List. import { graph } from \"@pnp/graph\" ; const Item = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). items . getById ( 'itemId' ). update ({ { \"Color\" : \"Fuchsia\" } })","title":"Update Item"},{"location":"graph/docs/sites/#delete-item","text":"Using the delete() you can delete an Item in a List. import { graph } from \"@pnp/graph\" ; const Item = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). items . getById ( 'itemId' ). delete ()","title":"Delete Item"},{"location":"graph/docs/sites/#get-fields-from-item","text":"Using the fields() you can the Fields in an Item import { graph } from \"@pnp/graph\" ; const fieldsFromItem = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). items . getById ( 'itemId' ). fields . get ();","title":"Get Fields from Item"},{"location":"graph/docs/sites/#get-versions-from-item","text":"Using the versions() you can the Versions of an Item import { graph } from \"@pnp/graph\" ; const versionsFromItem = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). items . getById ( 'itemId' ). versions . get ();","title":"Get Versions from Item"},{"location":"graph/docs/sites/#get-version-from-item","text":"Using the versions.getById()() you can the Versions of an Item import { graph } from \"@pnp/graph\" ; const versionFromItem = await graph . sites . getById ( 'contoso.sharepoint.com' ). lists . getById ( 'listId' ). items . getById ( 'itemId' ). versions . getById ( 'versionId' ). get ();","title":"Get Version from Item"},{"location":"graph/docs/subscriptions/","text":"@pnp/graph/subscriptions \u00b6 The ability to manage subscriptions is a capability introduced in version 1.2.9 of @pnp/graph. A subscription allows a client app to receive notifications about changes to data in Microsoft Graph. Currently, subscriptions are enabled for the following resources: Mail, events, and contacts from Outlook. Conversations from Office Groups. Drive root items from OneDrive. Users and Groups from Azure Active Directory. * Alerts from the Microsoft Graph Security API. Get all of the Subscriptions \u00b6 Using the subscriptions(). If successful this method returns a 200 OK response code and a list of subscription objects in the response body. import { graph } from \"@pnp/graph\" ; const subscriptions = await graph . subscriptions . get (); Create a new Subscription \u00b6 Using the subscriptions.add(). Creating a subscription requires read scope to the resource. For example, to get notifications messages, your app needs the Mail.Read permission. To learn more about the scopes visit this url. import { graph } from \"@pnp/graph\" ; const addedSubscription = await graph . subscriptions . add ( \"created,updated\" , \"https://webhook.azurewebsites.net/api/send/myNotifyClient\" , \"me/mailFolders('Inbox')/messages\" , \"2019-11-20T18:23:45.9356913Z\" ); Get Subscription by Id \u00b6 Using the subscriptions.getById() you can get one of the subscriptions import { graph } from \"@pnp/graph\" ; const subscription = await graph . subscriptions . getById ( 'subscriptionId' ); Delete a Subscription \u00b6 Using the subscriptions.getById().delete() you can remove one of the Subscriptions import { graph } from \"@pnp/graph\" ; const delSubscription = await graph . subscription . getById ( 'subscriptionId' ). delete (); Update a Subscription \u00b6 Using the subscriptions.getById().update() you can update one of the Subscriptions import { graph } from \"@pnp/graph\" ; const updSubscription = await graph . subscriptions . getById ( 'subscriptionId' ). update ({ changeType : \"created,updated,deleted\" });","title":"subscriptions"},{"location":"graph/docs/subscriptions/#pnpgraphsubscriptions","text":"The ability to manage subscriptions is a capability introduced in version 1.2.9 of @pnp/graph. A subscription allows a client app to receive notifications about changes to data in Microsoft Graph. Currently, subscriptions are enabled for the following resources: Mail, events, and contacts from Outlook. Conversations from Office Groups. Drive root items from OneDrive. Users and Groups from Azure Active Directory. * Alerts from the Microsoft Graph Security API.","title":"@pnp/graph/subscriptions"},{"location":"graph/docs/subscriptions/#get-all-of-the-subscriptions","text":"Using the subscriptions(). If successful this method returns a 200 OK response code and a list of subscription objects in the response body. import { graph } from \"@pnp/graph\" ; const subscriptions = await graph . subscriptions . get ();","title":"Get all of the Subscriptions"},{"location":"graph/docs/subscriptions/#create-a-new-subscription","text":"Using the subscriptions.add(). Creating a subscription requires read scope to the resource. For example, to get notifications messages, your app needs the Mail.Read permission. To learn more about the scopes visit this url. import { graph } from \"@pnp/graph\" ; const addedSubscription = await graph . subscriptions . add ( \"created,updated\" , \"https://webhook.azurewebsites.net/api/send/myNotifyClient\" , \"me/mailFolders('Inbox')/messages\" , \"2019-11-20T18:23:45.9356913Z\" );","title":"Create a new Subscription"},{"location":"graph/docs/subscriptions/#get-subscription-by-id","text":"Using the subscriptions.getById() you can get one of the subscriptions import { graph } from \"@pnp/graph\" ; const subscription = await graph . subscriptions . getById ( 'subscriptionId' );","title":"Get Subscription by Id"},{"location":"graph/docs/subscriptions/#delete-a-subscription","text":"Using the subscriptions.getById().delete() you can remove one of the Subscriptions import { graph } from \"@pnp/graph\" ; const delSubscription = await graph . subscription . getById ( 'subscriptionId' ). delete ();","title":"Delete a Subscription"},{"location":"graph/docs/subscriptions/#update-a-subscription","text":"Using the subscriptions.getById().update() you can update one of the Subscriptions import { graph } from \"@pnp/graph\" ; const updSubscription = await graph . subscriptions . getById ( 'subscriptionId' ). update ({ changeType : \"created,updated,deleted\" });","title":"Update a Subscription"},{"location":"graph/docs/teams/","text":"@pnp/graph/teams \u00b6 The ability to manage Team is a capability introduced in the 1.2.7 of @pnp/graph. Through the methods described you can add, update and delete items in Teams. Teams the user is a member of \u00b6 import { graph } from \"@pnp/graph\" ; const joinedTeams = await graph . users . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). joinedTeams . get (); const myJoinedTeams = await graph . me . joinedTeams . get (); Get Teams by Id \u00b6 Using the teams.getById() you can get a specific Team. import { graph } from \"@pnp/graph\" ; const team = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). get (); Create new Group and Team \u00b6 When you create a new group and add a Team, the group needs to have an Owner. Or else we get an error. So the owner Id is important, and you could just get the users Ids from import { graph } from \"@pnp/graph\" ; const users = await graph . users . get (); Then create import { graph } from \"@pnp/graph\" ; const createdGroupTeam = await graph . teams . create ( 'Groupname' , 'mailNickname' , 'description' , 'OwnerId' ,{ \"memberSettings\" : { \"allowCreateUpdateChannels\" : true }, \"messagingSettings\" : { \"allowUserEditMessages\" : true , \"allowUserDeleteMessages\" : true }, \"funSettings\" : { \"allowGiphy\" : true , \"giphyContentRating\" : \"strict\" }}); Create a Team via a specific group \u00b6 Here we get the group via id and use createTeam import { graph } from \"@pnp/graph\" ; const createdTeam = await graph . groups . getById ( '679c8ff4-f07d-40de-b02b-60ec332472dd' ). createTeam ({ \"memberSettings\" : { \"allowCreateUpdateChannels\" : true }, \"messagingSettings\" : { \"allowUserEditMessages\" : true , \"allowUserDeleteMessages\" : true }, \"funSettings\" : { \"allowGiphy\" : true , \"giphyContentRating\" : \"strict\" }}); Archive a Team \u00b6 import { graph } from \"@pnp/graph\" ; const archived = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). archive (); Unarchive a Team \u00b6 import { graph } from \"@pnp/graph\" ; const archived = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). unarchive (); Clone a Team \u00b6 import { graph } from \"@pnp/graph\" ; const clonedTeam = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). cloneTeam ( 'Cloned' , 'mailNickname' , 'description' , 'apps,tabs,settings,channels,members' , 'public' ); Get all channels of a Team \u00b6 import { graph } from \"@pnp/graph\" ; const channels = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). channels . get (); Get channel by Id \u00b6 import { graph } from \"@pnp/graph\" ; const channel = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). channels . getById ( '19:65723d632b384ca89c81115c281428a3@thread.skype' ). get (); Create a new Channel \u00b6 import { graph } from \"@pnp/graph\" ; const newChannel = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). channels . create ( 'New Channel' , 'Description' ); Get installed Apps \u00b6 import { graph } from \"@pnp/graph\" ; const installedApps = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). installedApps . get (); Add an App \u00b6 import { graph } from \"@pnp/graph\" ; const addedApp = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). installedApps . add ( 'https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/12345678-9abc-def0-123456789a' ); Remove an App \u00b6 import { graph } from \"@pnp/graph\" ; const removedApp = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). installedApps . remove (); Get Tabs from a Channel \u00b6 import { graph } from \"@pnp/graph\" ; const tabs = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). channels . getById ( '19:65723d632b384ca89c81115c281428a3@thread.skype' ). tabs . get (); Get Tab by Id \u00b6 import { graph } from \"@pnp/graph\" ; const tab = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). channels . getById ( '19:65723d632b384ca89c81115c281428a3@thread.skype' ). tabs . getById ( 'Id' ); Add a new Tab \u00b6 import { graph } from \"@pnp/graph\" ; const newTab = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). channels . getById ( '19:65723d632b384ca89c81115c281428a3@thread.skype' ). tabs . add ( 'Tab' , 'https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/12345678-9abc-def0-123456789a' , < TabsConfiguration > {});","title":"teams"},{"location":"graph/docs/teams/#pnpgraphteams","text":"The ability to manage Team is a capability introduced in the 1.2.7 of @pnp/graph. Through the methods described you can add, update and delete items in Teams.","title":"@pnp/graph/teams"},{"location":"graph/docs/teams/#teams-the-user-is-a-member-of","text":"import { graph } from \"@pnp/graph\" ; const joinedTeams = await graph . users . getById ( '99dc1039-eb80-43b1-a09e-250d50a80b26' ). joinedTeams . get (); const myJoinedTeams = await graph . me . joinedTeams . get ();","title":"Teams the user is a member of"},{"location":"graph/docs/teams/#get-teams-by-id","text":"Using the teams.getById() you can get a specific Team. import { graph } from \"@pnp/graph\" ; const team = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). get ();","title":"Get Teams by Id"},{"location":"graph/docs/teams/#create-new-group-and-team","text":"When you create a new group and add a Team, the group needs to have an Owner. Or else we get an error. So the owner Id is important, and you could just get the users Ids from import { graph } from \"@pnp/graph\" ; const users = await graph . users . get (); Then create import { graph } from \"@pnp/graph\" ; const createdGroupTeam = await graph . teams . create ( 'Groupname' , 'mailNickname' , 'description' , 'OwnerId' ,{ \"memberSettings\" : { \"allowCreateUpdateChannels\" : true }, \"messagingSettings\" : { \"allowUserEditMessages\" : true , \"allowUserDeleteMessages\" : true }, \"funSettings\" : { \"allowGiphy\" : true , \"giphyContentRating\" : \"strict\" }});","title":"Create new Group and Team"},{"location":"graph/docs/teams/#create-a-team-via-a-specific-group","text":"Here we get the group via id and use createTeam import { graph } from \"@pnp/graph\" ; const createdTeam = await graph . groups . getById ( '679c8ff4-f07d-40de-b02b-60ec332472dd' ). createTeam ({ \"memberSettings\" : { \"allowCreateUpdateChannels\" : true }, \"messagingSettings\" : { \"allowUserEditMessages\" : true , \"allowUserDeleteMessages\" : true }, \"funSettings\" : { \"allowGiphy\" : true , \"giphyContentRating\" : \"strict\" }});","title":"Create a Team via a specific group"},{"location":"graph/docs/teams/#archive-a-team","text":"import { graph } from \"@pnp/graph\" ; const archived = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). archive ();","title":"Archive a Team"},{"location":"graph/docs/teams/#unarchive-a-team","text":"import { graph } from \"@pnp/graph\" ; const archived = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). unarchive ();","title":"Unarchive a Team"},{"location":"graph/docs/teams/#clone-a-team","text":"import { graph } from \"@pnp/graph\" ; const clonedTeam = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). cloneTeam ( 'Cloned' , 'mailNickname' , 'description' , 'apps,tabs,settings,channels,members' , 'public' );","title":"Clone a Team"},{"location":"graph/docs/teams/#get-all-channels-of-a-team","text":"import { graph } from \"@pnp/graph\" ; const channels = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). channels . get ();","title":"Get all channels of a Team"},{"location":"graph/docs/teams/#get-channel-by-id","text":"import { graph } from \"@pnp/graph\" ; const channel = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). channels . getById ( '19:65723d632b384ca89c81115c281428a3@thread.skype' ). get ();","title":"Get channel by Id"},{"location":"graph/docs/teams/#create-a-new-channel","text":"import { graph } from \"@pnp/graph\" ; const newChannel = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). channels . create ( 'New Channel' , 'Description' );","title":"Create a new Channel"},{"location":"graph/docs/teams/#get-installed-apps","text":"import { graph } from \"@pnp/graph\" ; const installedApps = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). installedApps . get ();","title":"Get installed Apps"},{"location":"graph/docs/teams/#add-an-app","text":"import { graph } from \"@pnp/graph\" ; const addedApp = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). installedApps . add ( 'https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/12345678-9abc-def0-123456789a' );","title":"Add an App"},{"location":"graph/docs/teams/#remove-an-app","text":"import { graph } from \"@pnp/graph\" ; const removedApp = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). installedApps . remove ();","title":"Remove an App"},{"location":"graph/docs/teams/#get-tabs-from-a-channel","text":"import { graph } from \"@pnp/graph\" ; const tabs = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). channels . getById ( '19:65723d632b384ca89c81115c281428a3@thread.skype' ). tabs . get ();","title":"Get Tabs from a Channel"},{"location":"graph/docs/teams/#get-tab-by-id","text":"import { graph } from \"@pnp/graph\" ; const tab = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). channels . getById ( '19:65723d632b384ca89c81115c281428a3@thread.skype' ). tabs . getById ( 'Id' );","title":"Get Tab by Id"},{"location":"graph/docs/teams/#add-a-new-tab","text":"import { graph } from \"@pnp/graph\" ; const newTab = await graph . teams . getById ( '3531f3fb-f9ee-4f43-982a-6c90d8226528' ). channels . getById ( '19:65723d632b384ca89c81115c281428a3@thread.skype' ). tabs . add ( 'Tab' , 'https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/12345678-9abc-def0-123456789a' , < TabsConfiguration > {});","title":"Add a new Tab"},{"location":"logging/docs/","text":"@pnp/logging \u00b6 The logging module provides light weight subscribable and extensiable logging framework which is used internally and available for use in your projects. This article outlines how to setup logging and use the various loggers. Getting Started \u00b6 Install the logging module, it has no other dependencies npm install @pnp/logging --save Understanding the Logging Framework \u00b6 The logging framework is based on the Logger class to which any number of listeners can be subscribed. Each of these listeners will receive each of the messages logged. Each listener must implement the LogListener interface, shown below. There is only one method to implement and it takes an instance of the LogEntry interface. /** * Interface that defines a log listener * */ export interface LogListener { /** * Any associated data that a given logging listener may choose to log or ignore * * @param entry The information to be logged */ log ( entry : LogEntry ) : void ; } /** * Interface that defines a log entry * */ export interface LogEntry { /** * The main message to be logged */ message : string ; /** * The level of information this message represents */ level : LogLevel ; /** * Any associated data that a given logging listener may choose to log or ignore */ data? : any ; } Log Levels \u00b6 export const enum LogLevel { Verbose = 0 , Info = 1 , Warning = 2 , Error = 3 , Off = 99 , } Writing to the Logger \u00b6 To write information to a logger you can use either write, writeJSON, or log. import { Logger , LogLevel } from \"@pnp/logging\" ; // write logs a simple string as the message value of the LogEntry Logger . write ( \"This is logging a simple string\" ); // optionally passing a level, default level is Verbose Logger . write ( \"This is logging a simple string\" , LogLevel . Error ); // this will convert the object to a string using JSON.stringify and set the message with the result Logger . writeJSON ({ name : \"value\" , name2 : \"value2\" }); // optionally passing a level, default level is Verbose Logger . writeJSON ({ name : \"value\" , name2 : \"value2\" }, LogLevel . Warn ); // specify the entire LogEntry interface using log Logger . log ({ data : { name : \"value\" , name2 : \"value2\" }, level : LogLevel.Warning , message : \"This is my message\" }); Log an error \u00b6 There exists a shortcut method to log an error to the Logger. This will log an entry to the subscribed loggers where the data property will be the Error instance pased in, the level will be Error, and the message will be the Error instance message. const e = new Error ( \"An Error\" ); Logger . error ( e ); Subscribing a Listener \u00b6 By default no listeners are subscribed, so if you would like to get logging information you need to subscribe at least one listener. This is done as shown below by importing the Logger and your listener(s) of choice. Here we are using the provided ConsoleListener. We are also setting the active log level, which controls the level of logging that will be output. Be aware that Verbose produces a substantial amount of data about each request. import { Logger , ConsoleListener , LogLevel } from \"@pnp/logging\" ; // subscribe a listener Logger . subscribe ( new ConsoleListener ()); // set the active log level Logger . activeLogLevel = LogLevel . Info ; Available Listeners \u00b6 There are two listeners included in the library, ConsoleListener and FunctionListener. ConsoleListener \u00b6 This listener outputs information to the console and works in Node as well as within browsers. It takes no settings and writes to the appropriate console method based on message level. For example a LogEntry with level Warning will be written to console.warn. Usage is shown in the example above. FunctionListener \u00b6 The FunctionListener allows you to wrap any functionality by creating a function that takes a LogEntry as its single argument. This produces the same result as implementing the LogListener interface, but is useful if you already have a logging method or framework to which you want to pass the messages. import { Logger , FunctionListener , LogEntry } from \"@pnp/logging\" ; let listener = new FunctionListener (( entry : LogEntry ) => { // pass all logging data to an existing framework MyExistingCompanyLoggingFramework . log ( entry . message ); }); Logger . subscribe ( listener ); Create a Custom Listener \u00b6 If desirable for your project you can create a custom listener to perform any logging action you would like. This is done by implementing the LogListener interface. import { Logger , LogListener , LogEntry } from \"@pnp/logging\" ; class MyListener implements LogListener { log ( entry : LogEntry ) : void { // here you would do something with the entry } } Logger . subscribe ( new MyListener ()); UML \u00b6 Graphical UML diagram of @pnp/logging. Right-click the diagram and open in new tab if it is too small.","title":"logging"},{"location":"logging/docs/#pnplogging","text":"The logging module provides light weight subscribable and extensiable logging framework which is used internally and available for use in your projects. This article outlines how to setup logging and use the various loggers.","title":"@pnp/logging"},{"location":"logging/docs/#getting-started","text":"Install the logging module, it has no other dependencies npm install @pnp/logging --save","title":"Getting Started"},{"location":"logging/docs/#understanding-the-logging-framework","text":"The logging framework is based on the Logger class to which any number of listeners can be subscribed. Each of these listeners will receive each of the messages logged. Each listener must implement the LogListener interface, shown below. There is only one method to implement and it takes an instance of the LogEntry interface. /** * Interface that defines a log listener * */ export interface LogListener { /** * Any associated data that a given logging listener may choose to log or ignore * * @param entry The information to be logged */ log ( entry : LogEntry ) : void ; } /** * Interface that defines a log entry * */ export interface LogEntry { /** * The main message to be logged */ message : string ; /** * The level of information this message represents */ level : LogLevel ; /** * Any associated data that a given logging listener may choose to log or ignore */ data? : any ; }","title":"Understanding the Logging Framework"},{"location":"logging/docs/#log-levels","text":"export const enum LogLevel { Verbose = 0 , Info = 1 , Warning = 2 , Error = 3 , Off = 99 , }","title":"Log Levels"},{"location":"logging/docs/#writing-to-the-logger","text":"To write information to a logger you can use either write, writeJSON, or log. import { Logger , LogLevel } from \"@pnp/logging\" ; // write logs a simple string as the message value of the LogEntry Logger . write ( \"This is logging a simple string\" ); // optionally passing a level, default level is Verbose Logger . write ( \"This is logging a simple string\" , LogLevel . Error ); // this will convert the object to a string using JSON.stringify and set the message with the result Logger . writeJSON ({ name : \"value\" , name2 : \"value2\" }); // optionally passing a level, default level is Verbose Logger . writeJSON ({ name : \"value\" , name2 : \"value2\" }, LogLevel . Warn ); // specify the entire LogEntry interface using log Logger . log ({ data : { name : \"value\" , name2 : \"value2\" }, level : LogLevel.Warning , message : \"This is my message\" });","title":"Writing to the Logger"},{"location":"logging/docs/#log-an-error","text":"There exists a shortcut method to log an error to the Logger. This will log an entry to the subscribed loggers where the data property will be the Error instance pased in, the level will be Error, and the message will be the Error instance message. const e = new Error ( \"An Error\" ); Logger . error ( e );","title":"Log an error"},{"location":"logging/docs/#subscribing-a-listener","text":"By default no listeners are subscribed, so if you would like to get logging information you need to subscribe at least one listener. This is done as shown below by importing the Logger and your listener(s) of choice. Here we are using the provided ConsoleListener. We are also setting the active log level, which controls the level of logging that will be output. Be aware that Verbose produces a substantial amount of data about each request. import { Logger , ConsoleListener , LogLevel } from \"@pnp/logging\" ; // subscribe a listener Logger . subscribe ( new ConsoleListener ()); // set the active log level Logger . activeLogLevel = LogLevel . Info ;","title":"Subscribing a Listener"},{"location":"logging/docs/#available-listeners","text":"There are two listeners included in the library, ConsoleListener and FunctionListener.","title":"Available Listeners"},{"location":"logging/docs/#consolelistener","text":"This listener outputs information to the console and works in Node as well as within browsers. It takes no settings and writes to the appropriate console method based on message level. For example a LogEntry with level Warning will be written to console.warn. Usage is shown in the example above.","title":"ConsoleListener"},{"location":"logging/docs/#functionlistener","text":"The FunctionListener allows you to wrap any functionality by creating a function that takes a LogEntry as its single argument. This produces the same result as implementing the LogListener interface, but is useful if you already have a logging method or framework to which you want to pass the messages. import { Logger , FunctionListener , LogEntry } from \"@pnp/logging\" ; let listener = new FunctionListener (( entry : LogEntry ) => { // pass all logging data to an existing framework MyExistingCompanyLoggingFramework . log ( entry . message ); }); Logger . subscribe ( listener );","title":"FunctionListener"},{"location":"logging/docs/#create-a-custom-listener","text":"If desirable for your project you can create a custom listener to perform any logging action you would like. This is done by implementing the LogListener interface. import { Logger , LogListener , LogEntry } from \"@pnp/logging\" ; class MyListener implements LogListener { log ( entry : LogEntry ) : void { // here you would do something with the entry } } Logger . subscribe ( new MyListener ());","title":"Create a Custom Listener"},{"location":"logging/docs/#uml","text":"Graphical UML diagram of @pnp/logging. Right-click the diagram and open in new tab if it is too small.","title":"UML"},{"location":"nodejs/docs/","text":"@pnp/nodejs \u00b6 This package supplies helper code when using the @pnp libraries within the context of nodejs. This removes the node specific functionality from any of the packages. Primarily these consist of clients to enable use of the libraries in nodejs. Getting Started \u00b6 Install the library and required dependencies. You will also need to install other libraries such as @pnp/sp or @pnp/graph to use the exported functionality. npm install @pnp/logging @pnp/core @pnp/nodejs --save AdalFetchClient SPFetchClient BearerTokenFetchClient Using A Proxy UML \u00b6 Graphical UML diagram of @pnp/nodejs. Right-click the diagram and open in new tab if it is too small.","title":"nodejs"},{"location":"nodejs/docs/#pnpnodejs","text":"This package supplies helper code when using the @pnp libraries within the context of nodejs. This removes the node specific functionality from any of the packages. Primarily these consist of clients to enable use of the libraries in nodejs.","title":"@pnp/nodejs"},{"location":"nodejs/docs/#getting-started","text":"Install the library and required dependencies. You will also need to install other libraries such as @pnp/sp or @pnp/graph to use the exported functionality. npm install @pnp/logging @pnp/core @pnp/nodejs --save AdalFetchClient SPFetchClient BearerTokenFetchClient Using A Proxy","title":"Getting Started"},{"location":"nodejs/docs/#uml","text":"Graphical UML diagram of @pnp/nodejs. Right-click the diagram and open in new tab if it is too small.","title":"UML"},{"location":"nodejs/docs/adal-certificate-fetch-client/","text":"@pnp/nodejs/adalcertificatefetchclient \u00b6 The AdalCertificateFetchClient class depends on the adal-node package to authenticate against Azure AD using the client credentials with a client certificate flow. The example below outlines usage with the @pnp/graph library, though it would work in any case where an Azure AD Bearer token is expected. import { AdalCertificateFetchClient } from \"@pnp/nodejs\" ; import { graph } from \"@pnp/graph\" ; import * as fs from \"fs\" ; import * as path from \"path\" ; // Get the private key from a file (Assuming it's a .pem file) const keyPemFile = \"/path/to/privatekey.pem\" ; const privateKey = fs . readFileSync ( path . resolve ( __dirname , keyPemFile ), { encoding : 'utf8' } ); // setup the client using graph setup function graph . setup ({ graph : { fetchClientFactory : () => { return new AdalCertificateFetchClient ( \"{tenant id}\" , \"{app id}\" , \"{certificate thumbprint}\" , privateKey ); }, }, }); // execute a library request as normal graph . groups . get (). then ( g => { console . log ( JSON . stringify ( g , null , 4 )); }). catch ( e => { console . error ( e ); });","title":"@pnp/nodejs/adalcertificatefetchclient"},{"location":"nodejs/docs/adal-certificate-fetch-client/#pnpnodejsadalcertificatefetchclient","text":"The AdalCertificateFetchClient class depends on the adal-node package to authenticate against Azure AD using the client credentials with a client certificate flow. The example below outlines usage with the @pnp/graph library, though it would work in any case where an Azure AD Bearer token is expected. import { AdalCertificateFetchClient } from \"@pnp/nodejs\" ; import { graph } from \"@pnp/graph\" ; import * as fs from \"fs\" ; import * as path from \"path\" ; // Get the private key from a file (Assuming it's a .pem file) const keyPemFile = \"/path/to/privatekey.pem\" ; const privateKey = fs . readFileSync ( path . resolve ( __dirname , keyPemFile ), { encoding : 'utf8' } ); // setup the client using graph setup function graph . setup ({ graph : { fetchClientFactory : () => { return new AdalCertificateFetchClient ( \"{tenant id}\" , \"{app id}\" , \"{certificate thumbprint}\" , privateKey ); }, }, }); // execute a library request as normal graph . groups . get (). then ( g => { console . log ( JSON . stringify ( g , null , 4 )); }). catch ( e => { console . error ( e ); });","title":"@pnp/nodejs/adalcertificatefetchclient"},{"location":"nodejs/docs/adal-fetch-client/","text":"@pnp/nodejs/adalfetchclient \u00b6 The AdalFetchClient class depends on the adal-node package to authenticate against Azure AD. The example below outlines usage with the @pnp/graph library, though it would work in any case where an Azure AD Bearer token is expected. import { AdalFetchClient } from \"@pnp/nodejs\" ; import { graph } from \"@pnp/graph\" ; // setup the client using graph setup function graph . setup ({ graph : { fetchClientFactory : () => { return new AdalFetchClient ( \"{tenant}\" , \"{app id}\" , \"{app secret}\" ); }, }, }); // execute a library request as normal graph . groups . get (). then ( g => { console . log ( JSON . stringify ( g , null , 4 )); }). catch ( e => { console . error ( e ); });","title":"AdalFetchClient"},{"location":"nodejs/docs/adal-fetch-client/#pnpnodejsadalfetchclient","text":"The AdalFetchClient class depends on the adal-node package to authenticate against Azure AD. The example below outlines usage with the @pnp/graph library, though it would work in any case where an Azure AD Bearer token is expected. import { AdalFetchClient } from \"@pnp/nodejs\" ; import { graph } from \"@pnp/graph\" ; // setup the client using graph setup function graph . setup ({ graph : { fetchClientFactory : () => { return new AdalFetchClient ( \"{tenant}\" , \"{app id}\" , \"{app secret}\" ); }, }, }); // execute a library request as normal graph . groups . get (). then ( g => { console . log ( JSON . stringify ( g , null , 4 )); }). catch ( e => { console . error ( e ); });","title":"@pnp/nodejs/adalfetchclient"},{"location":"nodejs/docs/bearer-token-fetch-client/","text":"@pnp/nodejs/BearerTokenFetchClient \u00b6 The BearerTokenFetchClient class allows you to easily specify your own Bearer tokens to be used in the requests. How you derive the token is up to you. import { BearerTokenFetchClient } from \"@pnp/nodejs\" ; import { graph } from \"@pnp/graph\" ; // setup the client using graph setup function graph . setup ({ graph : { fetchClientFactory : () => { return new BearerTokenFetchClient ( \"{Bearer Token}\" ); }, }, }); // execute a library request as normal graph . groups . get (). then ( g => { console . log ( JSON . stringify ( g , null , 4 )); }). catch ( e => { console . error ( e ); });","title":"BearerTokenFetchClient"},{"location":"nodejs/docs/bearer-token-fetch-client/#pnpnodejsbearertokenfetchclient","text":"The BearerTokenFetchClient class allows you to easily specify your own Bearer tokens to be used in the requests. How you derive the token is up to you. import { BearerTokenFetchClient } from \"@pnp/nodejs\" ; import { graph } from \"@pnp/graph\" ; // setup the client using graph setup function graph . setup ({ graph : { fetchClientFactory : () => { return new BearerTokenFetchClient ( \"{Bearer Token}\" ); }, }, }); // execute a library request as normal graph . groups . get (). then ( g => { console . log ( JSON . stringify ( g , null , 4 )); }). catch ( e => { console . error ( e ); });","title":"@pnp/nodejs/BearerTokenFetchClient"},{"location":"nodejs/docs/provider-hosted-app/","text":"@pnp/nodejs/providerhostedrequestcontext \u00b6 Added in 1.2.7 The ProviderHostedRequestcontext enables the creation of provider-hosted add-ins built in node.js to use pnpjs to interact with SharePoint. The context is associated to a SharePoint user, allowing requests to be made by the add-in on the behalf of the user. The usage of this class assumes the provider-hosted add-in is called from SharePoint with a valid SPAppToken. This is typically done by means of accessing /_layouts/15/AppRedirect.aspx with the app's client ID and app's redirect URI. Note : To support concurrent requests by different users and/or add-ins on different tenants, do not use the SPFetchClient class. Instead, use the more generic NodeFetchClient class. The downside is that you have to manually configure each request to use the desired user/app context. import { sp , SPRest } from \"@pnp/sp\" ; import { NodeFetchClient , ProviderHostedRequestContext } from \"@pnp/nodejs\" ; // configure your node options sp . setup ({ sp : { fetchClientFactory : () => { return new NodeFetchClient (); }, }, }); // get request data generated by /_layouts/15/AppRedirect.aspx const spAppToken = request . body . SPAppToken ; const spSiteUrl = request . body . SPSiteUrl ; // create a context based on the add-in details and SPAppToken const ctx = await ProviderHostedRequestContext . create ( spSiteUrl , \"{client id}\" , \"{client secret}\" , spAppToken ); // create an SPRest object configured to use our context // this is used in place of the global sp object const userSP = new SPRest (). configure ( await ctx . getUserConfig (), spSiteUrl ); const addinSP = new SPRest (). configure ( await ctx . getAddInOnlyConfig (), spSiteUrl ); // make a request on behalf of the user const user = await userSP . web . currentUser . get (); console . log ( `Hello ${ user . Title } ` ); // make an add-in only request const app = await addinSP . web . currentUser . get (); console . log ( `Add-in principal: ${ app . Title } ` );","title":"ProviderHostedRequestContext"},{"location":"nodejs/docs/provider-hosted-app/#pnpnodejsproviderhostedrequestcontext","text":"Added in 1.2.7 The ProviderHostedRequestcontext enables the creation of provider-hosted add-ins built in node.js to use pnpjs to interact with SharePoint. The context is associated to a SharePoint user, allowing requests to be made by the add-in on the behalf of the user. The usage of this class assumes the provider-hosted add-in is called from SharePoint with a valid SPAppToken. This is typically done by means of accessing /_layouts/15/AppRedirect.aspx with the app's client ID and app's redirect URI. Note : To support concurrent requests by different users and/or add-ins on different tenants, do not use the SPFetchClient class. Instead, use the more generic NodeFetchClient class. The downside is that you have to manually configure each request to use the desired user/app context. import { sp , SPRest } from \"@pnp/sp\" ; import { NodeFetchClient , ProviderHostedRequestContext } from \"@pnp/nodejs\" ; // configure your node options sp . setup ({ sp : { fetchClientFactory : () => { return new NodeFetchClient (); }, }, }); // get request data generated by /_layouts/15/AppRedirect.aspx const spAppToken = request . body . SPAppToken ; const spSiteUrl = request . body . SPSiteUrl ; // create a context based on the add-in details and SPAppToken const ctx = await ProviderHostedRequestContext . create ( spSiteUrl , \"{client id}\" , \"{client secret}\" , spAppToken ); // create an SPRest object configured to use our context // this is used in place of the global sp object const userSP = new SPRest (). configure ( await ctx . getUserConfig (), spSiteUrl ); const addinSP = new SPRest (). configure ( await ctx . getAddInOnlyConfig (), spSiteUrl ); // make a request on behalf of the user const user = await userSP . web . currentUser . get (); console . log ( `Hello ${ user . Title } ` ); // make an add-in only request const app = await addinSP . web . currentUser . get (); console . log ( `Add-in principal: ${ app . Title } ` );","title":"@pnp/nodejs/providerhostedrequestcontext"},{"location":"nodejs/docs/proxy/","text":"@pnp/nodejs/proxy \u00b6 Added in 1.3.2 In some cases when deploying on node you may need to use a proxy as governed by corporate policy, or perhaps you want to examine the traffic using a tool such as Fiddler. In the 1.3.2 relesae we introduced the ability to use a proxy with the @pnp/nodejs library. Basic Usage \u00b6 You need to import the new setProxyUrl function from the library and call it with your proxy url. Once done an https-proxy-agent will be used with each request. This works across all clients within the @pnp/nodejs library. import { SPFetchClient , SPOAuthEnv , setProxyUrl } from \"@pnp/nodejs\" ; sp . setup ({ sp : { fetchClientFactory : () => { // call the set proxy url function and it will be used for all requests regardless of client setProxyUrl ( \"{your proxy url}\" ); return new SPFetchClient ( settings . testing . sp . url , settings . testing . sp . id , settings . testing . sp . secret , SPOAuthEnv . SPO ); }, }, }); Use with Fiddler \u00b6 To get Fiddler to work you may need to set an environment variable. This should only be done for testing! import { SPFetchClient , SPOAuthEnv , setProxyUrl } from \"@pnp/nodejs\" ; sp . setup ({ sp : { fetchClientFactory : () => { // ignore certificate errors: ONLY FOR TESTING!! process . env . NODE_TLS_REJECT_UNAUTHORIZED = \"0\" ; // this is my fiddler url locally setProxyUrl ( \"http://127.0.0.1:8888\" ); return new SPFetchClient ( settings . testing . sp . url , settings . testing . sp . id , settings . testing . sp . secret , SPOAuthEnv . SPO ); }, }, });","title":"@pnp/nodejs/proxy"},{"location":"nodejs/docs/proxy/#pnpnodejsproxy","text":"Added in 1.3.2 In some cases when deploying on node you may need to use a proxy as governed by corporate policy, or perhaps you want to examine the traffic using a tool such as Fiddler. In the 1.3.2 relesae we introduced the ability to use a proxy with the @pnp/nodejs library.","title":"@pnp/nodejs/proxy"},{"location":"nodejs/docs/proxy/#basic-usage","text":"You need to import the new setProxyUrl function from the library and call it with your proxy url. Once done an https-proxy-agent will be used with each request. This works across all clients within the @pnp/nodejs library. import { SPFetchClient , SPOAuthEnv , setProxyUrl } from \"@pnp/nodejs\" ; sp . setup ({ sp : { fetchClientFactory : () => { // call the set proxy url function and it will be used for all requests regardless of client setProxyUrl ( \"{your proxy url}\" ); return new SPFetchClient ( settings . testing . sp . url , settings . testing . sp . id , settings . testing . sp . secret , SPOAuthEnv . SPO ); }, }, });","title":"Basic Usage"},{"location":"nodejs/docs/proxy/#use-with-fiddler","text":"To get Fiddler to work you may need to set an environment variable. This should only be done for testing! import { SPFetchClient , SPOAuthEnv , setProxyUrl } from \"@pnp/nodejs\" ; sp . setup ({ sp : { fetchClientFactory : () => { // ignore certificate errors: ONLY FOR TESTING!! process . env . NODE_TLS_REJECT_UNAUTHORIZED = \"0\" ; // this is my fiddler url locally setProxyUrl ( \"http://127.0.0.1:8888\" ); return new SPFetchClient ( settings . testing . sp . url , settings . testing . sp . id , settings . testing . sp . secret , SPOAuthEnv . SPO ); }, }, });","title":"Use with Fiddler"},{"location":"nodejs/docs/sp-fetch-client/","text":"@pnp/nodejs/spfetchclient \u00b6 The SPFetchClient is used to authentication to SharePoint as a provider hosted add-in using a client and secret in nodejs. Remember it is not a good practice to expose client ids and secrets on the client and use of this class is intended for nodejs exclusively. import { SPFetchClient } from \"@pnp/nodejs\" ; import { sp } from \"@pnp/sp\" ; sp . setup ({ sp : { fetchClientFactory : () => { return new SPFetchClient ( \"{site url}\" , \"{client id}\" , \"{client secret}\" ); }, }, }); // execute a library request as normal sp . web . get (). then ( w => { console . log ( JSON . stringify ( w , null , 4 )); }). catch ( e => { console . error ( e ); }); Set Authentication Environment \u00b6 Added in 1.1.2 For some areas such as Germany, China, and US Gov clouds you need to specify a different authentication url to the service. This is done by specifying the correct SPOAuthEnv enumeration to the SPFetchClient constructor. The options are listed below. If you are not sure which option to specify the default is likely OK. SPO : (default) for all *.sharepoint.com urls China: for China hosted cloud Germany: for Germany local cloud USDef: USA Defense cloud USGov: USA Government cloud import { sp } from \"@pnp/sp\" ; import { SPFetchClient , SPOAuthEnv } from \"@pnp/nodejs\" ; sp . setup ({ sp : { fetchClientFactory : () => { return new SPFetchClient ( \"{site url}\" , \"{client id}\" , \"{client secret}\" , SPOAuthEnv . China ); }, }, }); Set Realm \u00b6 In some cases automatically resolving the realm may not work. In this case you can set the realm parameter in the SPFetchClient constructor. You can determine the correct value for the realm by navigating to \"https://{site name}-admin.sharepoint.com/_layouts/15/TA_AllAppPrincipals.aspx\" and copying the GUID value that appears after the \"@\" - this is the realm id. As of version 1.1.2 the realm parameter is now the 5th parameter in the constructor. import { sp } from \"@pnp/sp\" ; import { SPFetchClient , SPOAuthEnv } from \"@pnp/nodejs\" ; sp . setup ({ sp : { fetchClientFactory : () => { return new SPFetchClient ( \"{site url}\" , \"{client id}\" , \"{client secret}\" , SPOAuthEnv . SPO , \"{realm}\" ); }, }, }); Creating a client id and secret \u00b6 This section outlines how to register for a client id and secret for use in the above code. Register An Add-In \u00b6 Before you can begin running tests you need to register a low-trust add-in with SharePoint. This is primarily designed for Office 365, but can work on-premises if you configure your farm accordingly . Navigation to {site url}/_layouts/appregnew.aspx Click \"Generate\" for both the Client Id and Secret values Give you add-in a title, this can be anything but will let you locate it in the list of add-in permissions Provide a fake value for app domain and redirect uri, you can use the values shown in the examples Click \"Create\" Copy the returned block of text containing the client id and secret as well as app name for your records and later in this article. Grant Your Add-In Permissions \u00b6 Now that we have created an add-in registration we need to tell SharePoint what permissions it can use. Due to an update in SharePoint Online you now have to register add-ins with certain permissions in the admin site . Navigate to {admin site url}/_layouts/appinv.aspx Paste your client id from the above section into the Add Id box and click \"Lookup\" You should see the information populated into the form from the last section, if not ensure you have the correct id value Paste the below XML into the permissions request xml box and hit \"Create\" You should get a confirmation message. <AppPermissionRequests AllowAppOnlyPolicy= \"true\" > <AppPermissionRequest Scope= \"http://sharepoint/content/tenant\" Right= \"FullControl\" /> <AppPermissionRequest Scope= \"http://sharepoint/social/tenant\" Right= \"FullControl\" /> <AppPermissionRequest Scope= \"http://sharepoint/search\" Right= \"QueryAsUserIgnoreAppPrincipal\" /> </AppPermissionRequests> Note that the above XML will grant full tenant control, you should grant only those permissions necessary for your application","title":"SPFetchClient"},{"location":"nodejs/docs/sp-fetch-client/#pnpnodejsspfetchclient","text":"The SPFetchClient is used to authentication to SharePoint as a provider hosted add-in using a client and secret in nodejs. Remember it is not a good practice to expose client ids and secrets on the client and use of this class is intended for nodejs exclusively. import { SPFetchClient } from \"@pnp/nodejs\" ; import { sp } from \"@pnp/sp\" ; sp . setup ({ sp : { fetchClientFactory : () => { return new SPFetchClient ( \"{site url}\" , \"{client id}\" , \"{client secret}\" ); }, }, }); // execute a library request as normal sp . web . get (). then ( w => { console . log ( JSON . stringify ( w , null , 4 )); }). catch ( e => { console . error ( e ); });","title":"@pnp/nodejs/spfetchclient"},{"location":"nodejs/docs/sp-fetch-client/#set-authentication-environment","text":"Added in 1.1.2 For some areas such as Germany, China, and US Gov clouds you need to specify a different authentication url to the service. This is done by specifying the correct SPOAuthEnv enumeration to the SPFetchClient constructor. The options are listed below. If you are not sure which option to specify the default is likely OK. SPO : (default) for all *.sharepoint.com urls China: for China hosted cloud Germany: for Germany local cloud USDef: USA Defense cloud USGov: USA Government cloud import { sp } from \"@pnp/sp\" ; import { SPFetchClient , SPOAuthEnv } from \"@pnp/nodejs\" ; sp . setup ({ sp : { fetchClientFactory : () => { return new SPFetchClient ( \"{site url}\" , \"{client id}\" , \"{client secret}\" , SPOAuthEnv . China ); }, }, });","title":"Set Authentication Environment"},{"location":"nodejs/docs/sp-fetch-client/#set-realm","text":"In some cases automatically resolving the realm may not work. In this case you can set the realm parameter in the SPFetchClient constructor. You can determine the correct value for the realm by navigating to \"https://{site name}-admin.sharepoint.com/_layouts/15/TA_AllAppPrincipals.aspx\" and copying the GUID value that appears after the \"@\" - this is the realm id. As of version 1.1.2 the realm parameter is now the 5th parameter in the constructor. import { sp } from \"@pnp/sp\" ; import { SPFetchClient , SPOAuthEnv } from \"@pnp/nodejs\" ; sp . setup ({ sp : { fetchClientFactory : () => { return new SPFetchClient ( \"{site url}\" , \"{client id}\" , \"{client secret}\" , SPOAuthEnv . SPO , \"{realm}\" ); }, }, });","title":"Set Realm"},{"location":"nodejs/docs/sp-fetch-client/#creating-a-client-id-and-secret","text":"This section outlines how to register for a client id and secret for use in the above code.","title":"Creating a client id and secret"},{"location":"nodejs/docs/sp-fetch-client/#register-an-add-in","text":"Before you can begin running tests you need to register a low-trust add-in with SharePoint. This is primarily designed for Office 365, but can work on-premises if you configure your farm accordingly . Navigation to {site url}/_layouts/appregnew.aspx Click \"Generate\" for both the Client Id and Secret values Give you add-in a title, this can be anything but will let you locate it in the list of add-in permissions Provide a fake value for app domain and redirect uri, you can use the values shown in the examples Click \"Create\" Copy the returned block of text containing the client id and secret as well as app name for your records and later in this article.","title":"Register An Add-In"},{"location":"nodejs/docs/sp-fetch-client/#grant-your-add-in-permissions","text":"Now that we have created an add-in registration we need to tell SharePoint what permissions it can use. Due to an update in SharePoint Online you now have to register add-ins with certain permissions in the admin site . Navigate to {admin site url}/_layouts/appinv.aspx Paste your client id from the above section into the Add Id box and click \"Lookup\" You should see the information populated into the form from the last section, if not ensure you have the correct id value Paste the below XML into the permissions request xml box and hit \"Create\" You should get a confirmation message. <AppPermissionRequests AllowAppOnlyPolicy= \"true\" > <AppPermissionRequest Scope= \"http://sharepoint/content/tenant\" Right= \"FullControl\" /> <AppPermissionRequest Scope= \"http://sharepoint/social/tenant\" Right= \"FullControl\" /> <AppPermissionRequest Scope= \"http://sharepoint/search\" Right= \"QueryAsUserIgnoreAppPrincipal\" /> </AppPermissionRequests> Note that the above XML will grant full tenant control, you should grant only those permissions necessary for your application","title":"Grant Your Add-In Permissions"},{"location":"odata/docs/","text":"@pnp/queryable \u00b6 This modules contains the abstract core classes used to process odata requests. They can also be used to build your own odata library should you wish to. By sharing the core functionality across libraries we can provide a consistent API as well as ensure the core code is solid and well tested, with any updates benefitting all inheriting libraries. Getting Started \u00b6 Install the library and required dependencies npm install @pnp/logging @pnp/core @pnp/queryable --save Library Topics \u00b6 caching core OData Batching Parsers Pipeline Queryable UML \u00b6 Graphical UML diagram of @pnp/queryable. Right-click the diagram and open in new tab if it is too small.","title":"odata"},{"location":"odata/docs/#pnpodata","text":"This modules contains the abstract core classes used to process odata requests. They can also be used to build your own odata library should you wish to. By sharing the core functionality across libraries we can provide a consistent API as well as ensure the core code is solid and well tested, with any updates benefitting all inheriting libraries.","title":"@pnp/queryable"},{"location":"odata/docs/#getting-started","text":"Install the library and required dependencies npm install @pnp/logging @pnp/core @pnp/queryable --save","title":"Getting Started"},{"location":"odata/docs/#library-topics","text":"caching core OData Batching Parsers Pipeline Queryable","title":"Library Topics"},{"location":"odata/docs/#uml","text":"Graphical UML diagram of @pnp/queryable. Right-click the diagram and open in new tab if it is too small.","title":"UML"},{"location":"odata/docs/caching/","text":"@pnp/queryable/caching \u00b6 Often times data doesn't change that quickly, especially in the case of rolling up corporate news or upcoming events. These types of things can be cached for minutes if not hours. To help make caching easy you just need to insert the usingCaching method in your chain. This only applies to get requests. The usingCaching method can be used with the inBatch method as well to cache the results of batched requests. The below examples uses the @pnp/sp library as the example - but this works equally well for any library making use of the @pnp/queryable base classes, such as @pnp/graph. Basic example \u00b6 You can use the method without any additional configuration. We have made some default choices for you and will discuss ways to override them later. The below code will get the items from the list, first checking the cache for the value. You can also use it with OData operators such as top and orderBy. The usingCaching() should always be the last method in the chain before the get() (OR if you are using [[batching]] these methods can be transposed, more details below). import { sp } from \"@pnp/sp\" ; sp . web . lists . getByTitle ( \"Tasks\" ). items . usingCaching (). get (). then ( r => { console . log ( r ) }); sp . web . lists . getByTitle ( \"Tasks\" ). items . top ( 5 ). orderBy ( \"Modified\" ). usingCaching (). get (). then ( r => { console . log ( r ) }); Globally Configure Cache Settings \u00b6 If you would like to not use the default values, but don't want to clutter your code by setting the caching values on each request you can configure custom options globally. These will be applied to all calls to usingCaching() throughout your application. import { sp } from \"@pnp/sp\" ; sp . setup ({ defaultCachingStore : \"session\" , // or \"local\" defaultCachingTimeoutSeconds : 30 , globalCacheDisable : false // or true to disable caching in case of debugging/testing }); sp . web . lists . getByTitle ( \"Tasks\" ). items . top ( 5 ). orderBy ( \"Modified\" ). usingCaching (). get (). then ( r => { console . log ( r ) }); Per Call Configuration \u00b6 If you prefer more verbose code or have a need to manage the cache settings on a per request basis you can include individual caching settings for each request. These settings are passed to the usingCaching method call and are defined in the following interface. If you want to use the per-request options you must include the key. export interface ICachingOptions { expiration? : Date ; storeName ?: \"session\" | \"local\" ; key : string ; } import { sp } from \"@pnp/sp\" ; import { dateAdd } from \"@pnp/core\" ; sp . web . lists . getByTitle ( \"Tasks\" ). items . top ( 5 ). orderBy ( \"Modified\" ). usingCaching ({ expiration : dateAdd ( new Date (), \"minute\" , 20 ), key : \"My Key\" , storeName : \"local\" }). get (). then ( r => { console . log ( r ) }); Using Batching with Caching \u00b6 You can use batching and caching together, but remember caching is only applied to get requests. When you use them together the methods can be transposed, the below example is valid. import { sp } from \"@pnp/sp\" ; let batch = sp . createBatch (); sp . web . lists . inBatch ( batch ). usingCaching (). get (). then ( r => { console . log ( r ) }); sp . web . lists . getByTitle ( \"Tasks\" ). items . usingCaching (). inBatch ( batch ). get (). then ( r => { console . log ( r ) }); batch . execute (). then (() => console . log ( \"All done!\" )); Implement Custom Caching \u00b6 You may desire to use a different caching strategy than the one we implemented within the library. The easiest way to achieve this is to wrap the request in your custom caching functionality using the unresolved promise as needed. Here we show how to implement the Stale While Revalidate pattern as discussed here . Implement caching helper method: \u00b6 We create a map to act as our cache storage and a function to wrap the request caching logic const map = new Map < string , any > (); async function staleWhileRevalidate < T > ( key : string , p : Promise < T > ) : Promise < T > { if ( map . has ( key )) { // In Cache p . then ( u => { // Update Cache once we have a result map . set ( key , u ); }); // Return from Cache return map . get ( key ); } // Not In Cache so we need to wait for the value const r = await p ; // Set Cache map . set ( key , r ); // Return from Promise return r ; } Usage \u00b6 Don't call usingCaching just apply the helper method // this one will wait for the request to finish const r1 = await staleWhileRevalidate ( \"test1\" , sp . web . select ( \"Title\" , \"Description\" ). get ()); console . log ( JSON . stringify ( r1 , null , 2 )); // this one will return the result from cache and then update the cache in the background const r2 = await staleWhileRevalidate ( \"test1\" , sp . web . select ( \"Title\" , \"Description\" ). get ()); console . log ( JSON . stringify ( r2 , null , 2 )); Wrapper Function \u00b6 You can wrap this call into a single function you can reuse within your application each time you need the web data for example. You can update the select and interface to match your needs as well. interface WebData { Title : string ; Description : string ; } function getWebData () : Promise < WebData > { return staleWhileRevalidate ( \"test1\" , sp . web . select ( \"Title\" , \"Description\" ). get ()); } // this one will wait for the request to finish const r1 = await getWebData (); console . log ( JSON . stringify ( r1 , null , 2 )); // this one will return the result from cache and then update the cache in the background const r2 = await getWebData (); console . log ( JSON . stringify ( r2 , null , 2 ));","title":"caching"},{"location":"odata/docs/caching/#pnpodatacaching","text":"Often times data doesn't change that quickly, especially in the case of rolling up corporate news or upcoming events. These types of things can be cached for minutes if not hours. To help make caching easy you just need to insert the usingCaching method in your chain. This only applies to get requests. The usingCaching method can be used with the inBatch method as well to cache the results of batched requests. The below examples uses the @pnp/sp library as the example - but this works equally well for any library making use of the @pnp/queryable base classes, such as @pnp/graph.","title":"@pnp/queryable/caching"},{"location":"odata/docs/caching/#basic-example","text":"You can use the method without any additional configuration. We have made some default choices for you and will discuss ways to override them later. The below code will get the items from the list, first checking the cache for the value. You can also use it with OData operators such as top and orderBy. The usingCaching() should always be the last method in the chain before the get() (OR if you are using [[batching]] these methods can be transposed, more details below). import { sp } from \"@pnp/sp\" ; sp . web . lists . getByTitle ( \"Tasks\" ). items . usingCaching (). get (). then ( r => { console . log ( r ) }); sp . web . lists . getByTitle ( \"Tasks\" ). items . top ( 5 ). orderBy ( \"Modified\" ). usingCaching (). get (). then ( r => { console . log ( r ) });","title":"Basic example"},{"location":"odata/docs/caching/#globally-configure-cache-settings","text":"If you would like to not use the default values, but don't want to clutter your code by setting the caching values on each request you can configure custom options globally. These will be applied to all calls to usingCaching() throughout your application. import { sp } from \"@pnp/sp\" ; sp . setup ({ defaultCachingStore : \"session\" , // or \"local\" defaultCachingTimeoutSeconds : 30 , globalCacheDisable : false // or true to disable caching in case of debugging/testing }); sp . web . lists . getByTitle ( \"Tasks\" ). items . top ( 5 ). orderBy ( \"Modified\" ). usingCaching (). get (). then ( r => { console . log ( r ) });","title":"Globally Configure Cache Settings"},{"location":"odata/docs/caching/#per-call-configuration","text":"If you prefer more verbose code or have a need to manage the cache settings on a per request basis you can include individual caching settings for each request. These settings are passed to the usingCaching method call and are defined in the following interface. If you want to use the per-request options you must include the key. export interface ICachingOptions { expiration? : Date ; storeName ?: \"session\" | \"local\" ; key : string ; } import { sp } from \"@pnp/sp\" ; import { dateAdd } from \"@pnp/core\" ; sp . web . lists . getByTitle ( \"Tasks\" ). items . top ( 5 ). orderBy ( \"Modified\" ). usingCaching ({ expiration : dateAdd ( new Date (), \"minute\" , 20 ), key : \"My Key\" , storeName : \"local\" }). get (). then ( r => { console . log ( r ) });","title":"Per Call Configuration"},{"location":"odata/docs/caching/#using-batching-with-caching","text":"You can use batching and caching together, but remember caching is only applied to get requests. When you use them together the methods can be transposed, the below example is valid. import { sp } from \"@pnp/sp\" ; let batch = sp . createBatch (); sp . web . lists . inBatch ( batch ). usingCaching (). get (). then ( r => { console . log ( r ) }); sp . web . lists . getByTitle ( \"Tasks\" ). items . usingCaching (). inBatch ( batch ). get (). then ( r => { console . log ( r ) }); batch . execute (). then (() => console . log ( \"All done!\" ));","title":"Using Batching with Caching"},{"location":"odata/docs/caching/#implement-custom-caching","text":"You may desire to use a different caching strategy than the one we implemented within the library. The easiest way to achieve this is to wrap the request in your custom caching functionality using the unresolved promise as needed. Here we show how to implement the Stale While Revalidate pattern as discussed here .","title":"Implement Custom Caching"},{"location":"odata/docs/caching/#implement-caching-helper-method","text":"We create a map to act as our cache storage and a function to wrap the request caching logic const map = new Map < string , any > (); async function staleWhileRevalidate < T > ( key : string , p : Promise < T > ) : Promise < T > { if ( map . has ( key )) { // In Cache p . then ( u => { // Update Cache once we have a result map . set ( key , u ); }); // Return from Cache return map . get ( key ); } // Not In Cache so we need to wait for the value const r = await p ; // Set Cache map . set ( key , r ); // Return from Promise return r ; }","title":"Implement caching helper method:"},{"location":"odata/docs/caching/#usage","text":"Don't call usingCaching just apply the helper method // this one will wait for the request to finish const r1 = await staleWhileRevalidate ( \"test1\" , sp . web . select ( \"Title\" , \"Description\" ). get ()); console . log ( JSON . stringify ( r1 , null , 2 )); // this one will return the result from cache and then update the cache in the background const r2 = await staleWhileRevalidate ( \"test1\" , sp . web . select ( \"Title\" , \"Description\" ). get ()); console . log ( JSON . stringify ( r2 , null , 2 ));","title":"Usage"},{"location":"odata/docs/caching/#wrapper-function","text":"You can wrap this call into a single function you can reuse within your application each time you need the web data for example. You can update the select and interface to match your needs as well. interface WebData { Title : string ; Description : string ; } function getWebData () : Promise < WebData > { return staleWhileRevalidate ( \"test1\" , sp . web . select ( \"Title\" , \"Description\" ). get ()); } // this one will wait for the request to finish const r1 = await getWebData (); console . log ( JSON . stringify ( r1 , null , 2 )); // this one will return the result from cache and then update the cache in the background const r2 = await getWebData (); console . log ( JSON . stringify ( r2 , null , 2 ));","title":"Wrapper Function"},{"location":"odata/docs/core/","text":"@pnp/queryable/core \u00b6 This modules contains shared interfaces and abstract classes used within, and by inheritors of, the @pnp/queryable package. ProcessHttpClientResponseException \u00b6 The exception thrown when a response is returned and cannot be processed. interface ODataParser \u00b6 Base interface used to describe a class that that will parse incoming responses. It takes a single type parameter representing the type of the value to be returned. It has two methods, one is optional: parse(r: Response): Promise - main method use to parse a response and return a Promise resolving to an object of type T hydrate?: (d: any) => T - optional method used when getting an object from the cache if it requires calling a constructor ODataParserBase \u00b6 The base class used by all parsers in the @pnp libraries. It is optional to use when creating your own custom parsers, but does contain several helper methods. Create a custom parser from ODataParserBase \u00b6 You can always create custom parsers for your projects, however it is likely you will not require this step as the default parsers should work for most cases. class MyParser extends ODataParserBase < any > { // we need to override the parse method to do our custom stuff public parse ( r : Response ) : Promise < T > { // we wrap everything in a promise return new Promise (( resolve , reject ) => { // lets use the default error handling which returns true for no error // and will call reject with an error if one exists if ( this . handleError ( r , reject )) { // now we add our custom parsing here r . text (). then ( txt => { // here we call a madeup function to parse the result // this is where we would do our parsing as required myCustomerUnencode ( txt ). then ( v => { resolve ( v ); }); }); } }); } }","title":"core"},{"location":"odata/docs/core/#pnpodatacore","text":"This modules contains shared interfaces and abstract classes used within, and by inheritors of, the @pnp/queryable package.","title":"@pnp/queryable/core"},{"location":"odata/docs/core/#processhttpclientresponseexception","text":"The exception thrown when a response is returned and cannot be processed.","title":"ProcessHttpClientResponseException"},{"location":"odata/docs/core/#interface-odataparser","text":"Base interface used to describe a class that that will parse incoming responses. It takes a single type parameter representing the type of the value to be returned. It has two methods, one is optional: parse(r: Response): Promise - main method use to parse a response and return a Promise resolving to an object of type T hydrate?: (d: any) => T - optional method used when getting an object from the cache if it requires calling a constructor","title":"interface ODataParser"},{"location":"odata/docs/core/#odataparserbase","text":"The base class used by all parsers in the @pnp libraries. It is optional to use when creating your own custom parsers, but does contain several helper methods.","title":"ODataParserBase"},{"location":"odata/docs/core/#create-a-custom-parser-from-odataparserbase","text":"You can always create custom parsers for your projects, however it is likely you will not require this step as the default parsers should work for most cases. class MyParser extends ODataParserBase < any > { // we need to override the parse method to do our custom stuff public parse ( r : Response ) : Promise < T > { // we wrap everything in a promise return new Promise (( resolve , reject ) => { // lets use the default error handling which returns true for no error // and will call reject with an error if one exists if ( this . handleError ( r , reject )) { // now we add our custom parsing here r . text (). then ( txt => { // here we call a madeup function to parse the result // this is where we would do our parsing as required myCustomerUnencode ( txt ). then ( v => { resolve ( v ); }); }); } }); } }","title":"Create a custom parser from ODataParserBase"},{"location":"odata/docs/odata-batch/","text":"@pnp/queryable/odatabatch \u00b6 This module contains an abstract class used as a base when inheriting libraries support batching. ODataBatchRequestInfo \u00b6 This interface defines what each batch needs to know about each request. It is generic in that any library can provide the information but will be responsible for processing that info by implementing the abstract executeImpl method. ODataBatch \u00b6 Base class for building batching support for a library inheriting from @pnp/queryable. You can see implementations of this abstract class in the @pnp/sp and @pnp/graph modules.","title":"OData Batching"},{"location":"odata/docs/odata-batch/#pnpodataodatabatch","text":"This module contains an abstract class used as a base when inheriting libraries support batching.","title":"@pnp/queryable/odatabatch"},{"location":"odata/docs/odata-batch/#odatabatchrequestinfo","text":"This interface defines what each batch needs to know about each request. It is generic in that any library can provide the information but will be responsible for processing that info by implementing the abstract executeImpl method.","title":"ODataBatchRequestInfo"},{"location":"odata/docs/odata-batch/#odatabatch","text":"Base class for building batching support for a library inheriting from @pnp/queryable. You can see implementations of this abstract class in the @pnp/sp and @pnp/graph modules.","title":"ODataBatch"},{"location":"odata/docs/parsers/","text":"@pnp/queryable/parsers \u00b6 This modules contains a set of generic parsers. These can be used or extended as needed, though it is likely in most cases the default parser will be all you need. ODataDefaultParser \u00b6 The simplest parser used to transform a Response into its JSON representation. The default parser will handle errors in a consistent manner throwing an HttpRequestError instance. This class extends Error and adds the response, status, and statusText properties. The response object is unread. You can use this custom error as shown below to gather more information about what went wrong in the request. import { sp } from \"@pnp/sp\" ; import { JSONParser } from \"@pnp/queryable\" ; try { const parser = new JSONParser (); // this always throws a 404 error await sp . web . getList ( \"doesn't exist\" ). get ( parser ); } catch ( e ) { // we can check for the property \"isHttpRequestError\" to see if this is an instance of our class // this gets by all the many limitations of subclassing Error and type detection in JavaScript if ( e . hasOwnProperty ( \"isHttpRequestError\" )) { console . log ( \"e is HttpRequestError\" ); // now we can access the various properties and make use of the response object. // at this point the body is unread console . log ( `status: ${ e . status } ` ); console . log ( `statusText: ${ e . statusText } ` ); const json = await e . response . clone (). json (); console . log ( JSON . stringify ( json )); const text = await e . response . clone (). text (); console . log ( text ); const headers = e . response . headers ; } console . error ( e ); } TextParser \u00b6 Specialized parser used to parse the response using the .text() method with no other processing. Used primarily for files. BlobParser \u00b6 Specialized parser used to parse the response using the .blob() method with no other processing. Used primarily for files. JSONParser \u00b6 Specialized parser used to parse the response using the .json() method with no other processing. Used primarily for files. BufferParser \u00b6 Specialized parser used to parse the response using the .arrayBuffer() [node] for .buffer() [browser] method with no other processing. Used primarily for files. LambdaParser \u00b6 Allows you to pass in any handler function you want, called if the request does not result in an error that transforms the raw, unread request into the result type. import { LambdaParser } from \"@pnp/queryable\" ; import { sp } from \"@pnp/sp\" ; // here a simple parser duplicating the functionality of the JSONParser const parser = new LambdaParser (( r : Response ) => r . json ()); const webDataJson = await sp . web . get ( parser ); console . log ( webDataJson );","title":"Parsers"},{"location":"odata/docs/parsers/#pnpodataparsers","text":"This modules contains a set of generic parsers. These can be used or extended as needed, though it is likely in most cases the default parser will be all you need.","title":"@pnp/queryable/parsers"},{"location":"odata/docs/parsers/#odatadefaultparser","text":"The simplest parser used to transform a Response into its JSON representation. The default parser will handle errors in a consistent manner throwing an HttpRequestError instance. This class extends Error and adds the response, status, and statusText properties. The response object is unread. You can use this custom error as shown below to gather more information about what went wrong in the request. import { sp } from \"@pnp/sp\" ; import { JSONParser } from \"@pnp/queryable\" ; try { const parser = new JSONParser (); // this always throws a 404 error await sp . web . getList ( \"doesn't exist\" ). get ( parser ); } catch ( e ) { // we can check for the property \"isHttpRequestError\" to see if this is an instance of our class // this gets by all the many limitations of subclassing Error and type detection in JavaScript if ( e . hasOwnProperty ( \"isHttpRequestError\" )) { console . log ( \"e is HttpRequestError\" ); // now we can access the various properties and make use of the response object. // at this point the body is unread console . log ( `status: ${ e . status } ` ); console . log ( `statusText: ${ e . statusText } ` ); const json = await e . response . clone (). json (); console . log ( JSON . stringify ( json )); const text = await e . response . clone (). text (); console . log ( text ); const headers = e . response . headers ; } console . error ( e ); }","title":"ODataDefaultParser"},{"location":"odata/docs/parsers/#textparser","text":"Specialized parser used to parse the response using the .text() method with no other processing. Used primarily for files.","title":"TextParser"},{"location":"odata/docs/parsers/#blobparser","text":"Specialized parser used to parse the response using the .blob() method with no other processing. Used primarily for files.","title":"BlobParser"},{"location":"odata/docs/parsers/#jsonparser","text":"Specialized parser used to parse the response using the .json() method with no other processing. Used primarily for files.","title":"JSONParser"},{"location":"odata/docs/parsers/#bufferparser","text":"Specialized parser used to parse the response using the .arrayBuffer() [node] for .buffer() [browser] method with no other processing. Used primarily for files.","title":"BufferParser"},{"location":"odata/docs/parsers/#lambdaparser","text":"Allows you to pass in any handler function you want, called if the request does not result in an error that transforms the raw, unread request into the result type. import { LambdaParser } from \"@pnp/queryable\" ; import { sp } from \"@pnp/sp\" ; // here a simple parser duplicating the functionality of the JSONParser const parser = new LambdaParser (( r : Response ) => r . json ()); const webDataJson = await sp . web . get ( parser ); console . log ( webDataJson );","title":"LambdaParser"},{"location":"odata/docs/pipeline/","text":"@pnp/queryable/pipeline \u00b6 All of the odata requests processed by @pnp/queryable pass through an extensible request pipeline. Each request is executed in a specific request context defined by the RequestContext interface with the type parameter representing the type ultimately returned at the end a successful processing through the pipeline. Unless you are writing a pipeline method it is unlikely you will ever interact directly with the request pipeline. interface RequestContext \u00b6 The interface that defines the context within which all requests are executed. Note that the pipeline methods to be executed are part of the context. This allows full control over the methods called during a request, and allows for the insertion of any custom methods required. interface RequestContext < T > { batch : ODataBatch ; batchDependency : () => void ; cachingOptions : ICachingOptions ; hasResult? : boolean ; isBatched : boolean ; isCached : boolean ; options : FetchOptions ; parser : ODataParser < T > ; pipeline : Array < ( c : RequestContext < T > ) => Promise < RequestContext < T >>> ; requestAbsoluteUrl : string ; requestId : string ; result? : T ; verb : string ; clientFactory : () => RequestClient ; } requestPipelineMethod decorator \u00b6 The requestPipelineMethod decorator is used to tag a pipeline method and add functionality to bypass processing if a result is already present in the pipeline. If you would like your method to always run regardless of the existance of a result you can pass true to ensure it will always run. Each pipeline method takes a single argument of the current RequestContext and returns a promise resolving to the RequestContext updated as needed. @requestPipelineMethod ( true ) public static myPipelineMethod < T > ( context : RequestContext < T > ) : Promise < RequestContext < T >> { return new Promise < RequestContext < T >> ( resolve => { // do something resolve ( context ); }); } Default Pipeline \u00b6 logs the start of the request checks the cache for a value based on the context's cache settings sends the request if no value from found in the cache logs the end of the request","title":"Pipeline"},{"location":"odata/docs/pipeline/#pnpodatapipeline","text":"All of the odata requests processed by @pnp/queryable pass through an extensible request pipeline. Each request is executed in a specific request context defined by the RequestContext interface with the type parameter representing the type ultimately returned at the end a successful processing through the pipeline. Unless you are writing a pipeline method it is unlikely you will ever interact directly with the request pipeline.","title":"@pnp/queryable/pipeline"},{"location":"odata/docs/pipeline/#interface-requestcontext","text":"The interface that defines the context within which all requests are executed. Note that the pipeline methods to be executed are part of the context. This allows full control over the methods called during a request, and allows for the insertion of any custom methods required. interface RequestContext < T > { batch : ODataBatch ; batchDependency : () => void ; cachingOptions : ICachingOptions ; hasResult? : boolean ; isBatched : boolean ; isCached : boolean ; options : FetchOptions ; parser : ODataParser < T > ; pipeline : Array < ( c : RequestContext < T > ) => Promise < RequestContext < T >>> ; requestAbsoluteUrl : string ; requestId : string ; result? : T ; verb : string ; clientFactory : () => RequestClient ; }","title":"interface RequestContext"},{"location":"odata/docs/pipeline/#requestpipelinemethod-decorator","text":"The requestPipelineMethod decorator is used to tag a pipeline method and add functionality to bypass processing if a result is already present in the pipeline. If you would like your method to always run regardless of the existance of a result you can pass true to ensure it will always run. Each pipeline method takes a single argument of the current RequestContext and returns a promise resolving to the RequestContext updated as needed. @requestPipelineMethod ( true ) public static myPipelineMethod < T > ( context : RequestContext < T > ) : Promise < RequestContext < T >> { return new Promise < RequestContext < T >> ( resolve => { // do something resolve ( context ); }); }","title":"requestPipelineMethod decorator"},{"location":"odata/docs/pipeline/#default-pipeline","text":"logs the start of the request checks the cache for a value based on the context's cache settings sends the request if no value from found in the cache logs the end of the request","title":"Default Pipeline"},{"location":"odata/docs/queryable/","text":"@pnp/queryable/queryable \u00b6 The Queryable class is the base class for all of the libraries building fluent request apis. abstract class ODataQueryable \u00b6 This class takes a single type parameter representing the type of the batch implementation object. If your api will not support batching you can create a dummy class here and simply not use the batching calls. properties \u00b6 query \u00b6 Provides access to the query string builder for this url public methods \u00b6 concat \u00b6 Directly concatenates the supplied string to the current url, not normalizing \"/\" chars configure \u00b6 Sets custom options for current object and all derived objects accessible via chaining import { ConfigOptions } from \"@pnp/queryable\" ; import { sp } from \"@pnp/sp\" ; const headers : ConfigOptions = { Accept : 'application/json;odata=nometadata' }; // here we use configure to set the headers value for all child requests of the list instance const list = sp . web . lists . getByTitle ( \"List1\" ). configure ({ headers }); // this will use the values set in configure list . items . get (). then ( items => console . log ( JSON . stringify ( items , null , 2 )); For reference the ConfigOptions interface is shown below: export interface ConfigOptions { headers? : string [][] | { [ key : string ] : string } | Headers ; mode ?: \"navigate\" | \"same-origin\" | \"no-cors\" | \"cors\" ; credentials ?: \"omit\" | \"same-origin\" | \"include\" ; cache ?: \"default\" | \"no-store\" | \"reload\" | \"no-cache\" | \"force-cache\" | \"only-if-cached\" ; } configureFrom \u00b6 Sets custom options from another queryable instance's options. Identical to configure except the options are derived from the supplied instance. usingCaching \u00b6 Enables caching for this request. See caching for more details. import { sp } from \"@pnp/sp\" sp . web . usingCaching (). get (). then (...); inBatch \u00b6 Adds this query to the supplied batch toUrl \u00b6 Gets the current url abstract toUrlAndQuery() \u00b6 When implemented by an inheriting class will build the full url with appropriate query string used to make the actual request get \u00b6 Execute the current request. Takes an optional type parameter allowing for the typing of the value or the user of parsers that will create specific object instances.","title":"Queryable"},{"location":"odata/docs/queryable/#pnpodataqueryable","text":"The Queryable class is the base class for all of the libraries building fluent request apis.","title":"@pnp/queryable/queryable"},{"location":"odata/docs/queryable/#abstract-class-odataqueryable","text":"This class takes a single type parameter representing the type of the batch implementation object. If your api will not support batching you can create a dummy class here and simply not use the batching calls.","title":"abstract class ODataQueryable"},{"location":"odata/docs/queryable/#properties","text":"","title":"properties"},{"location":"odata/docs/queryable/#query","text":"Provides access to the query string builder for this url","title":"query"},{"location":"odata/docs/queryable/#public-methods","text":"","title":"public methods"},{"location":"odata/docs/queryable/#concat","text":"Directly concatenates the supplied string to the current url, not normalizing \"/\" chars","title":"concat"},{"location":"odata/docs/queryable/#configure","text":"Sets custom options for current object and all derived objects accessible via chaining import { ConfigOptions } from \"@pnp/queryable\" ; import { sp } from \"@pnp/sp\" ; const headers : ConfigOptions = { Accept : 'application/json;odata=nometadata' }; // here we use configure to set the headers value for all child requests of the list instance const list = sp . web . lists . getByTitle ( \"List1\" ). configure ({ headers }); // this will use the values set in configure list . items . get (). then ( items => console . log ( JSON . stringify ( items , null , 2 )); For reference the ConfigOptions interface is shown below: export interface ConfigOptions { headers? : string [][] | { [ key : string ] : string } | Headers ; mode ?: \"navigate\" | \"same-origin\" | \"no-cors\" | \"cors\" ; credentials ?: \"omit\" | \"same-origin\" | \"include\" ; cache ?: \"default\" | \"no-store\" | \"reload\" | \"no-cache\" | \"force-cache\" | \"only-if-cached\" ; }","title":"configure"},{"location":"odata/docs/queryable/#configurefrom","text":"Sets custom options from another queryable instance's options. Identical to configure except the options are derived from the supplied instance.","title":"configureFrom"},{"location":"odata/docs/queryable/#usingcaching","text":"Enables caching for this request. See caching for more details. import { sp } from \"@pnp/sp\" sp . web . usingCaching (). get (). then (...);","title":"usingCaching"},{"location":"odata/docs/queryable/#inbatch","text":"Adds this query to the supplied batch","title":"inBatch"},{"location":"odata/docs/queryable/#tourl","text":"Gets the current url","title":"toUrl"},{"location":"odata/docs/queryable/#abstract-tourlandquery","text":"When implemented by an inheriting class will build the full url with appropriate query string used to make the actual request","title":"abstract toUrlAndQuery()"},{"location":"odata/docs/queryable/#get","text":"Execute the current request. Takes an optional type parameter allowing for the typing of the value or the user of parsers that will create specific object instances.","title":"get"},{"location":"pnpjs/docs/","text":"@pnp/pnpjs \u00b6 The pnpjs library is a rollup of the core libraries across the @pnp scope and is designed only as a bridge to help folks transition from sp-pnp-js, primarily in scenarios where a single file is being imported via a script tag. It is recommended to not use this rollup library where possible and migrate to the individual libraries . Getting Started \u00b6 There are two approaches to using this library: the first is to import, the second is to manually extract the bundled file for use in your project. Install \u00b6 npm install @pnp/pnpjs --save You can then make use of the pnpjs rollup library within your application. It's structure matches sp-pnp-js, though some things may have changed based on the rolled-up dependencies. import pnp from \"@pnp/pnpjs\" ; pnp . sp . web . get (). then ( w => { console . log ( JSON . stringify ( w , null , 4 )); }); Grab Bundle File \u00b6 This method is useful if you are primarily working within a script editor web part or similar case where you are not using a build pipeline to bundle your application. Install only this library. npm install @pnp/pnpjs Browse to ./node_modules/@pnp/pnpjs/dist and grab either pnpjs.es5.umd.bundle.js or pnpjs.es5.umd.bundle.min.js depending on your needs. You can then add a script tag referencing this file and you will have a global variable \"pnp\". For example you could paste the following into a script editor web part: < p > Script Editor is on page. </ p > < script src = \"https://mysite/site_assets/pnpjs.es5.umd.bundle.min.js\" type = \"text/javascript\" ></ script > < script type = \"text/javascript\" > pnp . Logger . subscribe ( new pnp . ConsoleListener ()); pnp . Logger . activeLogLevel = pnp . LogLevel . Info ; pnp . sp . web . get (). then ( w => { console . log ( JSON . stringify ( w , null , 4 )); }); </ script > Alternatively to serve the script from the project at \"https://localhost:8080/assets/pnp.js\" you can use: gulp serve --p pnpjs This will allow you to test your changes to the entire bundle live while making updates.","title":"pnpjs"},{"location":"pnpjs/docs/#pnppnpjs","text":"The pnpjs library is a rollup of the core libraries across the @pnp scope and is designed only as a bridge to help folks transition from sp-pnp-js, primarily in scenarios where a single file is being imported via a script tag. It is recommended to not use this rollup library where possible and migrate to the individual libraries .","title":"@pnp/pnpjs"},{"location":"pnpjs/docs/#getting-started","text":"There are two approaches to using this library: the first is to import, the second is to manually extract the bundled file for use in your project.","title":"Getting Started"},{"location":"pnpjs/docs/#install","text":"npm install @pnp/pnpjs --save You can then make use of the pnpjs rollup library within your application. It's structure matches sp-pnp-js, though some things may have changed based on the rolled-up dependencies. import pnp from \"@pnp/pnpjs\" ; pnp . sp . web . get (). then ( w => { console . log ( JSON . stringify ( w , null , 4 )); });","title":"Install"},{"location":"pnpjs/docs/#grab-bundle-file","text":"This method is useful if you are primarily working within a script editor web part or similar case where you are not using a build pipeline to bundle your application. Install only this library. npm install @pnp/pnpjs Browse to ./node_modules/@pnp/pnpjs/dist and grab either pnpjs.es5.umd.bundle.js or pnpjs.es5.umd.bundle.min.js depending on your needs. You can then add a script tag referencing this file and you will have a global variable \"pnp\". For example you could paste the following into a script editor web part: < p > Script Editor is on page. </ p > < script src = \"https://mysite/site_assets/pnpjs.es5.umd.bundle.min.js\" type = \"text/javascript\" ></ script > < script type = \"text/javascript\" > pnp . Logger . subscribe ( new pnp . ConsoleListener ()); pnp . Logger . activeLogLevel = pnp . LogLevel . Info ; pnp . sp . web . get (). then ( w => { console . log ( JSON . stringify ( w , null , 4 )); }); </ script > Alternatively to serve the script from the project at \"https://localhost:8080/assets/pnp.js\" you can use: gulp serve --p pnpjs This will allow you to test your changes to the entire bundle live while making updates.","title":"Grab Bundle File"},{"location":"sp/docs/","text":"@pnp/sp \u00b6 This package contains the fluent api used to call the SharePoint rest services. Getting Started \u00b6 Install the library and required dependencies npm install @pnp/logging @pnp/core @pnp/queryable @pnp/sp --save Import the library into your application and access the root sp object import { sp } from \"@pnp/sp\" ; ( function main() { // here we will load the current web's title sp . web . select ( \"Title\" ). get (). then ( w => { console . log ( `Web Title: ${ w . Title } ` ); }); })() Getting Started: SharePoint Framework \u00b6 Install the library and required dependencies npm install @pnp/logging @pnp/core @pnp/queryable @pnp/sp --save Import the library into your application, update OnInit, and access the root sp object in render import { sp } from \"@pnp/sp\" ; // ... public onInit () : Promise < void > { return super . onInit (). then ( _ => { // other init code may be present sp . setup ({ spfxContext : this.context }); }); } // ... public render () : void { // A simple loading message this . domElement . innerHTML = `Loading...` ; sp . web . select ( \"Title\" ). get (). then ( w => { this . domElement . innerHTML = `Web Title: ${ w . Title } ` ; }); } Getting Started: Nodejs \u00b6 Install the library and required dependencies npm install @pnp/logging @pnp/core @pnp/queryable @pnp/sp @pnp/nodejs --save Import the library into your application, setup the node client, make a request import { sp } from \"@pnp/sp\" ; import { SPFetchClient } from \"@pnp/nodejs\" ; // do this once per page load sp . setup ({ sp : { fetchClientFactory : () => { return new SPFetchClient ( \"{your site url}\" , \"{your client id}\" , \"{your client secret}\" ); }, }, }); // now make any calls you need using the configured client sp . web . select ( \"Title\" ). get (). then ( w => { console . log ( `Web Title: ${ w . Title } ` ); }); Library Topics \u00b6 Alias Parameters ALM api Attachments Client-side Pages Features Fields Files List Items Navigation Service Permissions Related Items Search Sharing Site Designs Social SP.Utilities.Utility Tenant Properties Views Webs Comments and Likes UML \u00b6 Graphical UML diagram of @pnp/sp. Right-click the diagram and open in new tab if it is too small.","title":"sp"},{"location":"sp/docs/#pnpsp","text":"This package contains the fluent api used to call the SharePoint rest services.","title":"@pnp/sp"},{"location":"sp/docs/#getting-started","text":"Install the library and required dependencies npm install @pnp/logging @pnp/core @pnp/queryable @pnp/sp --save Import the library into your application and access the root sp object import { sp } from \"@pnp/sp\" ; ( function main() { // here we will load the current web's title sp . web . select ( \"Title\" ). get (). then ( w => { console . log ( `Web Title: ${ w . Title } ` ); }); })()","title":"Getting Started"},{"location":"sp/docs/#getting-started-sharepoint-framework","text":"Install the library and required dependencies npm install @pnp/logging @pnp/core @pnp/queryable @pnp/sp --save Import the library into your application, update OnInit, and access the root sp object in render import { sp } from \"@pnp/sp\" ; // ... public onInit () : Promise < void > { return super . onInit (). then ( _ => { // other init code may be present sp . setup ({ spfxContext : this.context }); }); } // ... public render () : void { // A simple loading message this . domElement . innerHTML = `Loading...` ; sp . web . select ( \"Title\" ). get (). then ( w => { this . domElement . innerHTML = `Web Title: ${ w . Title } ` ; }); }","title":"Getting Started: SharePoint Framework"},{"location":"sp/docs/#getting-started-nodejs","text":"Install the library and required dependencies npm install @pnp/logging @pnp/core @pnp/queryable @pnp/sp @pnp/nodejs --save Import the library into your application, setup the node client, make a request import { sp } from \"@pnp/sp\" ; import { SPFetchClient } from \"@pnp/nodejs\" ; // do this once per page load sp . setup ({ sp : { fetchClientFactory : () => { return new SPFetchClient ( \"{your site url}\" , \"{your client id}\" , \"{your client secret}\" ); }, }, }); // now make any calls you need using the configured client sp . web . select ( \"Title\" ). get (). then ( w => { console . log ( `Web Title: ${ w . Title } ` ); });","title":"Getting Started: Nodejs"},{"location":"sp/docs/#library-topics","text":"Alias Parameters ALM api Attachments Client-side Pages Features Fields Files List Items Navigation Service Permissions Related Items Search Sharing Site Designs Social SP.Utilities.Utility Tenant Properties Views Webs Comments and Likes","title":"Library Topics"},{"location":"sp/docs/#uml","text":"Graphical UML diagram of @pnp/sp. Right-click the diagram and open in new tab if it is too small.","title":"UML"},{"location":"sp/docs/alias-parameters/","text":"@pnp/sp - Aliased Parameters \u00b6 Within the @pnp/sp api you can alias any of the parameters so they will be written into the querystring. This is most helpful if you are hitting up against the url length limits when working with files and folders. To alias a parameter you include the label name, a separator (\"::\") and the value in the string. You also need to prepend a \"!\" to the string to trigger the replacement. You can see this below, as well as the string that will be generated. Labels must start with a \"@\" followed by a letter. It is also your responsibility to ensure that the aliases you supply do not conflict, for example if you use \"@p1\" you should use \"@p2\" for a second parameter alias in the same query. Construct a parameter alias \u00b6 Pattern: !@{label name}::{value} Example: \"!@p1::\\sites\\dev\" or \"!@p2::\\text.txt\" Example without aliasing \u00b6 import { sp } from \"@pnp/sp\" ; // still works as expected, no aliasing const query = sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/\" ). files . select ( \"Title\" ). top ( 3 ); console . log ( query . toUrl ()); // _api/web/getFolderByServerRelativeUrl('/sites/dev/Shared Documents/')/files console . log ( query . toUrlAndQuery ()); // _api/web/getFolderByServerRelativeUrl('/sites/dev/Shared Documents/')/files?$select=Title&$top=3 query . get (). then ( r => { console . log ( r ); }); Example with aliasing \u00b6 import { sp } from \"@pnp/sp\" ; // same query with aliasing const query = sp . web . getFolderByServerRelativeUrl ( \"!@p1::/sites/dev/Shared Documents/\" ). files . select ( \"Title\" ). top ( 3 ); console . log ( query . toUrl ()); // _api/web/getFolderByServerRelativeUrl('!@p1::/sites/dev/Shared Documents/')/files console . log ( query . toUrlAndQuery ()); // _api/web/getFolderByServerRelativeUrl(@p1)/files?@p1='/sites/dev/Shared Documents/'&$select=Title&$top=3 query . get (). then ( r => { console . log ( r ); }); Example with aliasing and batching \u00b6 Aliasing is supported with batching as well: import { sp } from \"@pnp/sp\" ; // same query with aliasing and batching const batch = sp . web . createBatch (); const query = sp . web . getFolderByServerRelativeUrl ( \"!@p1::/sites/dev/Shared Documents/\" ). files . select ( \"Title\" ). top ( 3 ); console . log ( query . toUrl ()); // _api/web/getFolderByServerRelativeUrl('!@p1::/sites/dev/Shared Documents/')/files console . log ( query . toUrlAndQuery ()); // _api/web/getFolderByServerRelativeUrl(@p1)/files?@p1='/sites/dev/Shared Documents/'&$select=Title&$top=3 query . inBatch ( batch ). get (). then ( r => { console . log ( r ); }); batch . execute ();","title":"Alias Parameters"},{"location":"sp/docs/alias-parameters/#pnpsp-aliased-parameters","text":"Within the @pnp/sp api you can alias any of the parameters so they will be written into the querystring. This is most helpful if you are hitting up against the url length limits when working with files and folders. To alias a parameter you include the label name, a separator (\"::\") and the value in the string. You also need to prepend a \"!\" to the string to trigger the replacement. You can see this below, as well as the string that will be generated. Labels must start with a \"@\" followed by a letter. It is also your responsibility to ensure that the aliases you supply do not conflict, for example if you use \"@p1\" you should use \"@p2\" for a second parameter alias in the same query.","title":"@pnp/sp - Aliased Parameters"},{"location":"sp/docs/alias-parameters/#construct-a-parameter-alias","text":"Pattern: !@{label name}::{value} Example: \"!@p1::\\sites\\dev\" or \"!@p2::\\text.txt\"","title":"Construct a parameter alias"},{"location":"sp/docs/alias-parameters/#example-without-aliasing","text":"import { sp } from \"@pnp/sp\" ; // still works as expected, no aliasing const query = sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/\" ). files . select ( \"Title\" ). top ( 3 ); console . log ( query . toUrl ()); // _api/web/getFolderByServerRelativeUrl('/sites/dev/Shared Documents/')/files console . log ( query . toUrlAndQuery ()); // _api/web/getFolderByServerRelativeUrl('/sites/dev/Shared Documents/')/files?$select=Title&$top=3 query . get (). then ( r => { console . log ( r ); });","title":"Example without aliasing"},{"location":"sp/docs/alias-parameters/#example-with-aliasing","text":"import { sp } from \"@pnp/sp\" ; // same query with aliasing const query = sp . web . getFolderByServerRelativeUrl ( \"!@p1::/sites/dev/Shared Documents/\" ). files . select ( \"Title\" ). top ( 3 ); console . log ( query . toUrl ()); // _api/web/getFolderByServerRelativeUrl('!@p1::/sites/dev/Shared Documents/')/files console . log ( query . toUrlAndQuery ()); // _api/web/getFolderByServerRelativeUrl(@p1)/files?@p1='/sites/dev/Shared Documents/'&$select=Title&$top=3 query . get (). then ( r => { console . log ( r ); });","title":"Example with aliasing"},{"location":"sp/docs/alias-parameters/#example-with-aliasing-and-batching","text":"Aliasing is supported with batching as well: import { sp } from \"@pnp/sp\" ; // same query with aliasing and batching const batch = sp . web . createBatch (); const query = sp . web . getFolderByServerRelativeUrl ( \"!@p1::/sites/dev/Shared Documents/\" ). files . select ( \"Title\" ). top ( 3 ); console . log ( query . toUrl ()); // _api/web/getFolderByServerRelativeUrl('!@p1::/sites/dev/Shared Documents/')/files console . log ( query . toUrlAndQuery ()); // _api/web/getFolderByServerRelativeUrl(@p1)/files?@p1='/sites/dev/Shared Documents/'&$select=Title&$top=3 query . inBatch ( batch ). get (). then ( r => { console . log ( r ); }); batch . execute ();","title":"Example with aliasing and batching"},{"location":"sp/docs/alm/","text":"@pnp/sp/appcatalog \u00b6 The ALM api allows you to manage app installations both in the tenant app catalog and individual site app catalogs. Some of the methods are still in beta and as such may change in the future. This article outlines how to call this api using @pnp/sp. Remember all these actions are bound by permissions so it is likely most users will not have the rights to perform these ALM actions. Understanding the App Catalog Heirarchy \u00b6 Before you begin provisioning applications it is important to understand the relationship between a local web catalog and the tenant app catalog. Some of the methods described below only work within the context of the tenant app catalog web, such as adding an app to the catalog and the app actions retract, remove, and deploy. You can install, uninstall, and upgrade an app in any web. Read more in the official documentation . Reference an App Catalog \u00b6 There are several ways using @pnp/sp to get a reference to an app catalog. These methods are to provide you the greatest amount of flexibility in gaining access to the app catalog. Ultimately each method produces an AppCatalog instance differentiated only by the web to which it points. import { sp } from \"@pnp/sp\" ; // get the curren't context web's app catalog const catalog = sp . web . getAppCatalog (); // you can also chain off the app catalog pnp . sp . web . getAppCatalog (). get (). then ( console . log ); import { sp } from \"@pnp/sp\" ; // you can get the tenant app catalog (or any app catalog) by passing in a url // get the tenant app catalog const tenantCatalog = sp . web . getAppCatalog ( \"https://mytenant.sharepoint.com/sites/appcatalog\" ); // get a different app catalog const catalog = sp . web . getAppCatalog ( \"https://mytenant.sharepoint.com/sites/anothersite\" ); // alternatively you can create a new app catalog instance directly by importing the AppCatalog class import { AppCatalog } from \"@pnp/sp\" ; const catalog = new AppCatalog ( \"https://mytenant.sharepoint.com/sites/dev\" ); // and finally you can combine use of the Web and AppCatalog classes to create an AppCatalog instance from an existing Web import { Web , AppCatalog } from \"@pnp/sp\" ; const web = new Web ( \"https://mytenant.sharepoint.com/sites/dev\" ); const catalog = new AppCatalog ( web ); The following examples make use of a variable \"catalog\" which is assumed to represent an AppCatalog instance obtained using one of the above methods, supporting code is omitted for brevity. List Available Apps \u00b6 The AppCatalog is itself a queryable collection so you can query this object directly to get a list of available apps. Also, the odata operators work on the catalog to sort, filter, and select. // get available apps catalog . get (). then ( console . log ); // get available apps selecting two fields catalog . select ( \"Title\" , \"Deployed\" ). get (). then ( console . log ); Add an App \u00b6 This action must be performed in the context of the tenant app catalog // this represents the file bytes of the app package file const blob = new Blob (); // there is an optional third argument to control overwriting existing files catalog . add ( \"myapp.app\" , blob ). then ( r => { // this is at its core a file add operation so you have access to the response data as well // as a File isntance representing the created file console . log ( JSON . stringify ( r . data , null , 4 )); // all file operations are available r . file . select ( \"Name\" ). get (). then ( console . log ); }); Get an App \u00b6 You can get the details of a single app by GUID id. This is also the branch point to perform specific app actions catalog . getAppById ( \"5137dff1-0b79-4ebc-8af4-ca01f7bd393c\" ). get (). then ( console . log ); Perform app actions \u00b6 Remember: retract, deploy, and remove only work in the context of the tenant app catalog web. All of these methods return void and you can monitor success using then and catch. // deploy catalog . getAppById ( \"5137dff1-0b79-4ebc-8af4-ca01f7bd393c\" ). deploy (). then ( console . log ). catch ( console . error ); // retract catalog . getAppById ( \"5137dff1-0b79-4ebc-8af4-ca01f7bd393c\" ). retract (). then ( console . log ). catch ( console . error ); // install catalog . getAppById ( \"5137dff1-0b79-4ebc-8af4-ca01f7bd393c\" ). install (). then ( console . log ). catch ( console . error ); // uninstall catalog . getAppById ( \"5137dff1-0b79-4ebc-8af4-ca01f7bd393c\" ). uninstall (). then ( console . log ). catch ( console . error ); // upgrade catalog . getAppById ( \"5137dff1-0b79-4ebc-8af4-ca01f7bd393c\" ). upgrade (). then ( console . log ). catch ( console . error ); // remove catalog . getAppById ( \"5137dff1-0b79-4ebc-8af4-ca01f7bd393c\" ). remove (). then ( console . log ). catch ( console . error ); Notes \u00b6 The app catalog is just a document library under the hood, so you can also perform non-ALM actions on the library if needed. But you should be aware of possible side-effects to the ALM life-cycle when doing so.","title":"ALM api"},{"location":"sp/docs/alm/#pnpspappcatalog","text":"The ALM api allows you to manage app installations both in the tenant app catalog and individual site app catalogs. Some of the methods are still in beta and as such may change in the future. This article outlines how to call this api using @pnp/sp. Remember all these actions are bound by permissions so it is likely most users will not have the rights to perform these ALM actions.","title":"@pnp/sp/appcatalog"},{"location":"sp/docs/alm/#understanding-the-app-catalog-heirarchy","text":"Before you begin provisioning applications it is important to understand the relationship between a local web catalog and the tenant app catalog. Some of the methods described below only work within the context of the tenant app catalog web, such as adding an app to the catalog and the app actions retract, remove, and deploy. You can install, uninstall, and upgrade an app in any web. Read more in the official documentation .","title":"Understanding the App Catalog Heirarchy"},{"location":"sp/docs/alm/#reference-an-app-catalog","text":"There are several ways using @pnp/sp to get a reference to an app catalog. These methods are to provide you the greatest amount of flexibility in gaining access to the app catalog. Ultimately each method produces an AppCatalog instance differentiated only by the web to which it points. import { sp } from \"@pnp/sp\" ; // get the curren't context web's app catalog const catalog = sp . web . getAppCatalog (); // you can also chain off the app catalog pnp . sp . web . getAppCatalog (). get (). then ( console . log ); import { sp } from \"@pnp/sp\" ; // you can get the tenant app catalog (or any app catalog) by passing in a url // get the tenant app catalog const tenantCatalog = sp . web . getAppCatalog ( \"https://mytenant.sharepoint.com/sites/appcatalog\" ); // get a different app catalog const catalog = sp . web . getAppCatalog ( \"https://mytenant.sharepoint.com/sites/anothersite\" ); // alternatively you can create a new app catalog instance directly by importing the AppCatalog class import { AppCatalog } from \"@pnp/sp\" ; const catalog = new AppCatalog ( \"https://mytenant.sharepoint.com/sites/dev\" ); // and finally you can combine use of the Web and AppCatalog classes to create an AppCatalog instance from an existing Web import { Web , AppCatalog } from \"@pnp/sp\" ; const web = new Web ( \"https://mytenant.sharepoint.com/sites/dev\" ); const catalog = new AppCatalog ( web ); The following examples make use of a variable \"catalog\" which is assumed to represent an AppCatalog instance obtained using one of the above methods, supporting code is omitted for brevity.","title":"Reference an App Catalog"},{"location":"sp/docs/alm/#list-available-apps","text":"The AppCatalog is itself a queryable collection so you can query this object directly to get a list of available apps. Also, the odata operators work on the catalog to sort, filter, and select. // get available apps catalog . get (). then ( console . log ); // get available apps selecting two fields catalog . select ( \"Title\" , \"Deployed\" ). get (). then ( console . log );","title":"List Available Apps"},{"location":"sp/docs/alm/#add-an-app","text":"This action must be performed in the context of the tenant app catalog // this represents the file bytes of the app package file const blob = new Blob (); // there is an optional third argument to control overwriting existing files catalog . add ( \"myapp.app\" , blob ). then ( r => { // this is at its core a file add operation so you have access to the response data as well // as a File isntance representing the created file console . log ( JSON . stringify ( r . data , null , 4 )); // all file operations are available r . file . select ( \"Name\" ). get (). then ( console . log ); });","title":"Add an App"},{"location":"sp/docs/alm/#get-an-app","text":"You can get the details of a single app by GUID id. This is also the branch point to perform specific app actions catalog . getAppById ( \"5137dff1-0b79-4ebc-8af4-ca01f7bd393c\" ). get (). then ( console . log );","title":"Get an App"},{"location":"sp/docs/alm/#perform-app-actions","text":"Remember: retract, deploy, and remove only work in the context of the tenant app catalog web. All of these methods return void and you can monitor success using then and catch. // deploy catalog . getAppById ( \"5137dff1-0b79-4ebc-8af4-ca01f7bd393c\" ). deploy (). then ( console . log ). catch ( console . error ); // retract catalog . getAppById ( \"5137dff1-0b79-4ebc-8af4-ca01f7bd393c\" ). retract (). then ( console . log ). catch ( console . error ); // install catalog . getAppById ( \"5137dff1-0b79-4ebc-8af4-ca01f7bd393c\" ). install (). then ( console . log ). catch ( console . error ); // uninstall catalog . getAppById ( \"5137dff1-0b79-4ebc-8af4-ca01f7bd393c\" ). uninstall (). then ( console . log ). catch ( console . error ); // upgrade catalog . getAppById ( \"5137dff1-0b79-4ebc-8af4-ca01f7bd393c\" ). upgrade (). then ( console . log ). catch ( console . error ); // remove catalog . getAppById ( \"5137dff1-0b79-4ebc-8af4-ca01f7bd393c\" ). remove (). then ( console . log ). catch ( console . error );","title":"Perform app actions"},{"location":"sp/docs/alm/#notes","text":"The app catalog is just a document library under the hood, so you can also perform non-ALM actions on the library if needed. But you should be aware of possible side-effects to the ALM life-cycle when doing so.","title":"Notes"},{"location":"sp/docs/attachments/","text":"@pnp/sp/attachments \u00b6 The ability to attach file to list items allows users to track documents outside of a document library. You can use the PnP JS Core library to work with attachments as outlined below. Get attachments \u00b6 import { sp } from \"@pnp/sp\" ; let item = sp . web . lists . getByTitle ( \"MyList\" ). items . getById ( 1 ); // get all the attachments item . attachmentFiles . get (). then ( v => { console . log ( v ); }); // get a single file by file name item . attachmentFiles . getByName ( \"file.txt\" ). get (). then ( v => { console . log ( v ); }); // select specific properties using odata operators item . attachmentFiles . select ( \"ServerRelativeUrl\" ). get (). then ( v => { console . log ( v ); }); Add an Attachment \u00b6 You can add an attachment to a list item using the add method. This method takes either a string, Blob, or ArrayBuffer. import { sp } from \"@pnp/sp\" ; let item = sp . web . lists . getByTitle ( \"MyList\" ). items . getById ( 1 ); item . attachmentFiles . add ( \"file2.txt\" , \"Here is my content\" ). then ( v => { console . log ( v ); }); Add Multiple \u00b6 This method allows you to pass an array of AttachmentFileInfo plain objects that will be added one at a time as attachments. Essentially automating the promise chaining. const list = sp . web . lists . getByTitle ( \"MyList\" ); var fileInfos : AttachmentFileInfo [] = []; fileInfos . push ({ name : \"My file name 1\" , content : \"string, blob, or array\" }); fileInfos . push ({ name : \"My file name 2\" , content : \"string, blob, or array\" }); list . items . getById ( 2 ). attachmentFiles . addMultiple ( fileInfos ). then ( r => { console . log ( r ); }); Delete Multiple \u00b6 const list = sp . web . lists . getByTitle ( \"MyList\" ); list . items . getById ( 2 ). attachmentFiles . deleteMultiple ( \"1.txt\" , \"2.txt\" ). then ( r => { console . log ( r ); }); Read Attachment Content \u00b6 You can read the content of an attachment as a string, Blob, ArrayBuffer, or json using the methods supplied. import { sp } from \"@pnp/sp\" ; let item = sp . web . lists . getByTitle ( \"MyList\" ). items . getById ( 1 ); item . attachmentFiles . getByName ( \"file.txt\" ). getText (). then ( v => { console . log ( v ); }); // use this in the browser, does not work in nodejs item . attachmentFiles . getByName ( \"file.mp4\" ). getBlob (). then ( v => { console . log ( v ); }); // use this in nodejs item . attachmentFiles . getByName ( \"file.mp4\" ). getBuffer (). then ( v => { console . log ( v ); }); // file must be valid json item . attachmentFiles . getByName ( \"file.json\" ). getJSON (). then ( v => { console . log ( v ); }); Update Attachment Content \u00b6 You can also update the content of an attachment. This API is limited compared to the full file API - so if you need to upload large files consider using a document library. import { sp } from \"@pnp/sp\" ; let item = sp . web . lists . getByTitle ( \"MyList\" ). items . getById ( 1 ); item . attachmentFiles . getByName ( \"file2.txt\" ). setContent ( \"My new content!!!\" ). then ( v => { console . log ( v ); }); Delete Attachment \u00b6 import { sp } from \"@pnp/sp\" ; let item = sp . web . lists . getByTitle ( \"MyList\" ). items . getById ( 1 ); item . attachmentFiles . getByName ( \"file2.txt\" ). delete (). then ( v => { console . log ( v ); }); Recycle Attachment \u00b6 Added in 1.2.4 Delete the attachment and send it to recycle bin import { sp } from \"@pnp/sp\" ; let item = sp . web . lists . getByTitle ( \"MyList\" ). items . getById ( 1 ); item . attachmentFiles . getByName ( \"file2.txt\" ). recycle (). then ( v => { console . log ( v ); }); Recycle Multiple Attachments \u00b6 Added in 1.2.4 Delete multiple attachments and send them to recycle bin import { sp } from \"@pnp/sp\" ; const list = sp . web . lists . getByTitle ( \"MyList\" ); list . items . getById ( 2 ). attachmentFiles . recycleMultiple ( \"1.txt\" , \"2.txt\" ). then ( r => { console . log ( r ); });","title":"Attachments"},{"location":"sp/docs/attachments/#pnpspattachments","text":"The ability to attach file to list items allows users to track documents outside of a document library. You can use the PnP JS Core library to work with attachments as outlined below.","title":"@pnp/sp/attachments"},{"location":"sp/docs/attachments/#get-attachments","text":"import { sp } from \"@pnp/sp\" ; let item = sp . web . lists . getByTitle ( \"MyList\" ). items . getById ( 1 ); // get all the attachments item . attachmentFiles . get (). then ( v => { console . log ( v ); }); // get a single file by file name item . attachmentFiles . getByName ( \"file.txt\" ). get (). then ( v => { console . log ( v ); }); // select specific properties using odata operators item . attachmentFiles . select ( \"ServerRelativeUrl\" ). get (). then ( v => { console . log ( v ); });","title":"Get attachments"},{"location":"sp/docs/attachments/#add-an-attachment","text":"You can add an attachment to a list item using the add method. This method takes either a string, Blob, or ArrayBuffer. import { sp } from \"@pnp/sp\" ; let item = sp . web . lists . getByTitle ( \"MyList\" ). items . getById ( 1 ); item . attachmentFiles . add ( \"file2.txt\" , \"Here is my content\" ). then ( v => { console . log ( v ); });","title":"Add an Attachment"},{"location":"sp/docs/attachments/#add-multiple","text":"This method allows you to pass an array of AttachmentFileInfo plain objects that will be added one at a time as attachments. Essentially automating the promise chaining. const list = sp . web . lists . getByTitle ( \"MyList\" ); var fileInfos : AttachmentFileInfo [] = []; fileInfos . push ({ name : \"My file name 1\" , content : \"string, blob, or array\" }); fileInfos . push ({ name : \"My file name 2\" , content : \"string, blob, or array\" }); list . items . getById ( 2 ). attachmentFiles . addMultiple ( fileInfos ). then ( r => { console . log ( r ); });","title":"Add Multiple"},{"location":"sp/docs/attachments/#delete-multiple","text":"const list = sp . web . lists . getByTitle ( \"MyList\" ); list . items . getById ( 2 ). attachmentFiles . deleteMultiple ( \"1.txt\" , \"2.txt\" ). then ( r => { console . log ( r ); });","title":"Delete Multiple"},{"location":"sp/docs/attachments/#read-attachment-content","text":"You can read the content of an attachment as a string, Blob, ArrayBuffer, or json using the methods supplied. import { sp } from \"@pnp/sp\" ; let item = sp . web . lists . getByTitle ( \"MyList\" ). items . getById ( 1 ); item . attachmentFiles . getByName ( \"file.txt\" ). getText (). then ( v => { console . log ( v ); }); // use this in the browser, does not work in nodejs item . attachmentFiles . getByName ( \"file.mp4\" ). getBlob (). then ( v => { console . log ( v ); }); // use this in nodejs item . attachmentFiles . getByName ( \"file.mp4\" ). getBuffer (). then ( v => { console . log ( v ); }); // file must be valid json item . attachmentFiles . getByName ( \"file.json\" ). getJSON (). then ( v => { console . log ( v ); });","title":"Read Attachment Content"},{"location":"sp/docs/attachments/#update-attachment-content","text":"You can also update the content of an attachment. This API is limited compared to the full file API - so if you need to upload large files consider using a document library. import { sp } from \"@pnp/sp\" ; let item = sp . web . lists . getByTitle ( \"MyList\" ). items . getById ( 1 ); item . attachmentFiles . getByName ( \"file2.txt\" ). setContent ( \"My new content!!!\" ). then ( v => { console . log ( v ); });","title":"Update Attachment Content"},{"location":"sp/docs/attachments/#delete-attachment","text":"import { sp } from \"@pnp/sp\" ; let item = sp . web . lists . getByTitle ( \"MyList\" ). items . getById ( 1 ); item . attachmentFiles . getByName ( \"file2.txt\" ). delete (). then ( v => { console . log ( v ); });","title":"Delete Attachment"},{"location":"sp/docs/attachments/#recycle-attachment","text":"Added in 1.2.4 Delete the attachment and send it to recycle bin import { sp } from \"@pnp/sp\" ; let item = sp . web . lists . getByTitle ( \"MyList\" ). items . getById ( 1 ); item . attachmentFiles . getByName ( \"file2.txt\" ). recycle (). then ( v => { console . log ( v ); });","title":"Recycle Attachment"},{"location":"sp/docs/attachments/#recycle-multiple-attachments","text":"Added in 1.2.4 Delete multiple attachments and send them to recycle bin import { sp } from \"@pnp/sp\" ; const list = sp . web . lists . getByTitle ( \"MyList\" ); list . items . getById ( 2 ). attachmentFiles . recycleMultiple ( \"1.txt\" , \"2.txt\" ). then ( r => { console . log ( r ); });","title":"Recycle Multiple Attachments"},{"location":"sp/docs/client-side-pages/","text":"@pnp/sp/clientsidepages \u00b6 The ability to manage client-side pages is a capability introduced in version 1.0.2 of @pnp/sp. Through the methods described you can add and edit \"modern\" pages in SharePoint sites. Add Client-side page \u00b6 Using the addClientSidePage you can add a new client side page to a site, specifying the filename. import { sp } from \"@pnp/sp\" ; const page = await sp . web . addClientSidePage ( `file-name` ); // OR const page = await sp . web . addClientSidePage ( `file-name` , `Page Display Title` ); Added in 1.0.5 you can also add a client side page using the list path. This gets around potential language issues with list title. You must specify the list path when calling this method in addition to the new page's filename. import { sp } from \"@pnp/sp\" ; const page = await sp . web . addClientSidePageByPath ( `file-name` , \"/sites/dev/SitePages\" ); Load Client-side page \u00b6 You can also load an existing page based on the file representing that page. Note that the static fromFile returns a promise which resolves so the loaded page. Here we are showing use of the getFileByServerRelativeUrl method to get the File instance, but any of the ways of getting a File instance will work. Also note we are passing the File instance, not the file content. import { sp , ClientSidePage , } from \"@pnp/sp\" ; const page = await ClientSidePage . fromFile ( sp . web . getFileByServerRelativeUrl ( \"/sites/dev/SitePages/ExistingFile.aspx\" )); The remaining examples below reference a variable \"page\" which is assumed to be a ClientSidePage instance loaded through one of the above means. Add Controls \u00b6 A client-side page is made up of sections, which have columns, which contain controls. A new page will have none of these and an existing page may have any combination of these. There are a few rules to understand how sections and columns layout on a page for display. A section is a horizontal piece of a page that extends 100% of the page width. A page with multiple sections will stack these sections based on the section's order property - a 1 based index. Within a section you can have one or more columns. Each column is ordered left to right based on the column's order property. The width of each column is controlled by the factor property whose value is one of 0, 2, 4, 6, 8, 10, or 12. The columns in a section should have factors that add up to 12. Meaning if you wanted to have two equal columns you can set a factor of 6 for each. A page can have empty columns. import { sp , ClientSideText , } from \"@pnp/sp\" ; // this code adds a section, and then adds a control to that section. The control is added to the section's defaultColumn, and if there are no columns a single // column of factor 12 is created as a default. Here we add the ClientSideText part page . addSection (). addControl ( new ClientSideText ( \"@pnp/sp is a great library!\" )); // here we add a section, add two columns, and add a text control to the second section so it will appear on the right of the page // add and get a reference to a new section const section = page . addSection (); // add a column of factor 6 section . addColumn ( 6 ); // add and get a reference to a new column of factor 6 const column = section . addColumn ( 6 ); // add a text control to the second new column column . addControl ( new ClientSideText ( \"Be sure to check out the @pnp docs at https://pnp.github.io/pnpjs/\" )); // we need to save our content changes await page . save (); Add Client-side Web Parts \u00b6 Beyond the text control above you can also add any of the available client-side web parts in a given site. To find out what web parts are available you first call the web's getClientSideWebParts method. Once you have a list of parts you need to find the defintion you want to use, here we get the Embed web part whose's id is \"490d7c76-1824-45b2-9de3-676421c997fa\" (at least in one farm, your mmv). import { sp , ClientSideWebpart , ClientSideWebpartPropertyTypes , } from \"@pnp/sp\" ; // this will be a ClientSidePageComponent array // this can be cached on the client in production scenarios const partDefs = await sp . web . getClientSideWebParts (); // find the definition we want, here by id const partDef = partDefs . filter ( c => c . Id === \"490d7c76-1824-45b2-9de3-676421c997fa\" ); // optionally ensure you found the def if ( partDef . length < 1 ) { // we didn't find it so we throw an error throw new Error ( \"Could not find the web part\" ); } // create a ClientWebPart instance from the definition const part = ClientSideWebpart . fromComponentDef ( partDef [ 0 ]); // set the properties on the web part. Here we have imported the ClientSideWebpartPropertyTypes module and can use that to type // the available settings object. You can use your own types or help us out and add some typings to the module :). // here for the embed web part we only have to supply an embedCode - in this case a youtube video. part . setProperties < ClientSideWebpartPropertyTypes . Embed > ({ embedCode : \"https://www.youtube.com/watch?v=IWQFZ7Lx-rg\" , }); // we add that part to a new section page . addSection (). addControl ( part ); // save our content changes back to the server await page . save (); Find Controls \u00b6 Added in 1.0.3 You can use the either of the two available method to locate controls within a page. These method search through all sections, columns, and controls returning the first instance that meets the supplied criteria. import { ClientSideWebPart } from \"@pnp/sp\" ; // find a control by instance id const control1 = page . findControlById ( \"b99bfccc-164e-4d3d-9b96-da48db62eb78\" ); // type the returned control const control2 = page . findControlById < ClientSideWebPart > ( \"c99bfccc-164e-4d3d-9b96-da48db62eb78\" ); const control3 = page . findControlById < ClientSideText > ( \"a99bfccc-164e-4d3d-9b96-da48db62eb78\" ); // use any predicate to find a control const control4 = page2 . findControl < ClientSideWebpart > (( c : CanvasControl ) => { // any logic you wish can be used on the control here // return true to return that control return c . order > 3 ; }); Control Comments \u00b6 You can choose to enable or disable comments on a page using these methods // indicates if comments are disabled, not valid until the page is loaded (Added in _1.0.3_) page . commentsDisabled // enable comments await page . enableComments (); // disable comments await page . disableComments (); Like/Unlike Client-side page, get like information about page \u00b6 Added in 1.2.4 You can like or unlike a modern page. You can also get information about the likes (i.e like Count and which users liked the page) // Like a Client-side page (Added in _1.2.4_) await page . like (); // Unlike a Client-side page await page . unlike (); // Get liked by information such as like count and user's who liked the page await page . getLikedByInformation (); Sample \u00b6 The below sample shows the process to add a Yammer feed webpart to the page. The properties required as well as the data version are found by adding the part using the UI and reviewing the values. Some or all of these may be discoverable using Yammer APIs . An identical process can be used to add web parts of any type by adjusting the definition, data version, and properties appropriately. // get webpart defs const defs = await sp . web . getClientSideWebParts (); // this is the id of the definition in my farm const yammerPartDef = defs . filter ( d => d . Id === \"31e9537e-f9dc-40a4-8834-0e3b7df418bc\" )[ 0 ]; // page file const file = sp . web . getFileByServerRelativePath ( \"/sites/dev/SitePages/Testing_kVKF.aspx\" ); // create page instance const page = await ClientSidePage . fromFile ( file ); // create part instance from definition const part = ClientSideWebpart . fromComponentDef ( yammerPartDef ); // update data version part . dataVersion = \"1.5\" ; // set the properties required part . setProperties ({ feedType : 0 , isSuiteConnected : false , mode : 2 , networkId : 9999999 , yammerEmbedContainerHeight : 400 , yammerFeedURL : \"\" , yammerGroupId : - 1 , yammerGroupMugshotUrl : \"https://mug0.assets-yammer.com/mugshot/images/{width}x{height}/all_company.png\" , yammerGroupName : \"All Company\" , yammerGroupUrl : \"https://www.yammer.com/{tenant}/#/threads/company?type=general\" , }); // add to the section/column you want page . sections [ 0 ]. addControl ( part ); // persist changes page . save ();","title":"Client-side Pages"},{"location":"sp/docs/client-side-pages/#pnpspclientsidepages","text":"The ability to manage client-side pages is a capability introduced in version 1.0.2 of @pnp/sp. Through the methods described you can add and edit \"modern\" pages in SharePoint sites.","title":"@pnp/sp/clientsidepages"},{"location":"sp/docs/client-side-pages/#add-client-side-page","text":"Using the addClientSidePage you can add a new client side page to a site, specifying the filename. import { sp } from \"@pnp/sp\" ; const page = await sp . web . addClientSidePage ( `file-name` ); // OR const page = await sp . web . addClientSidePage ( `file-name` , `Page Display Title` ); Added in 1.0.5 you can also add a client side page using the list path. This gets around potential language issues with list title. You must specify the list path when calling this method in addition to the new page's filename. import { sp } from \"@pnp/sp\" ; const page = await sp . web . addClientSidePageByPath ( `file-name` , \"/sites/dev/SitePages\" );","title":"Add Client-side page"},{"location":"sp/docs/client-side-pages/#load-client-side-page","text":"You can also load an existing page based on the file representing that page. Note that the static fromFile returns a promise which resolves so the loaded page. Here we are showing use of the getFileByServerRelativeUrl method to get the File instance, but any of the ways of getting a File instance will work. Also note we are passing the File instance, not the file content. import { sp , ClientSidePage , } from \"@pnp/sp\" ; const page = await ClientSidePage . fromFile ( sp . web . getFileByServerRelativeUrl ( \"/sites/dev/SitePages/ExistingFile.aspx\" )); The remaining examples below reference a variable \"page\" which is assumed to be a ClientSidePage instance loaded through one of the above means.","title":"Load Client-side page"},{"location":"sp/docs/client-side-pages/#add-controls","text":"A client-side page is made up of sections, which have columns, which contain controls. A new page will have none of these and an existing page may have any combination of these. There are a few rules to understand how sections and columns layout on a page for display. A section is a horizontal piece of a page that extends 100% of the page width. A page with multiple sections will stack these sections based on the section's order property - a 1 based index. Within a section you can have one or more columns. Each column is ordered left to right based on the column's order property. The width of each column is controlled by the factor property whose value is one of 0, 2, 4, 6, 8, 10, or 12. The columns in a section should have factors that add up to 12. Meaning if you wanted to have two equal columns you can set a factor of 6 for each. A page can have empty columns. import { sp , ClientSideText , } from \"@pnp/sp\" ; // this code adds a section, and then adds a control to that section. The control is added to the section's defaultColumn, and if there are no columns a single // column of factor 12 is created as a default. Here we add the ClientSideText part page . addSection (). addControl ( new ClientSideText ( \"@pnp/sp is a great library!\" )); // here we add a section, add two columns, and add a text control to the second section so it will appear on the right of the page // add and get a reference to a new section const section = page . addSection (); // add a column of factor 6 section . addColumn ( 6 ); // add and get a reference to a new column of factor 6 const column = section . addColumn ( 6 ); // add a text control to the second new column column . addControl ( new ClientSideText ( \"Be sure to check out the @pnp docs at https://pnp.github.io/pnpjs/\" )); // we need to save our content changes await page . save ();","title":"Add Controls"},{"location":"sp/docs/client-side-pages/#add-client-side-web-parts","text":"Beyond the text control above you can also add any of the available client-side web parts in a given site. To find out what web parts are available you first call the web's getClientSideWebParts method. Once you have a list of parts you need to find the defintion you want to use, here we get the Embed web part whose's id is \"490d7c76-1824-45b2-9de3-676421c997fa\" (at least in one farm, your mmv). import { sp , ClientSideWebpart , ClientSideWebpartPropertyTypes , } from \"@pnp/sp\" ; // this will be a ClientSidePageComponent array // this can be cached on the client in production scenarios const partDefs = await sp . web . getClientSideWebParts (); // find the definition we want, here by id const partDef = partDefs . filter ( c => c . Id === \"490d7c76-1824-45b2-9de3-676421c997fa\" ); // optionally ensure you found the def if ( partDef . length < 1 ) { // we didn't find it so we throw an error throw new Error ( \"Could not find the web part\" ); } // create a ClientWebPart instance from the definition const part = ClientSideWebpart . fromComponentDef ( partDef [ 0 ]); // set the properties on the web part. Here we have imported the ClientSideWebpartPropertyTypes module and can use that to type // the available settings object. You can use your own types or help us out and add some typings to the module :). // here for the embed web part we only have to supply an embedCode - in this case a youtube video. part . setProperties < ClientSideWebpartPropertyTypes . Embed > ({ embedCode : \"https://www.youtube.com/watch?v=IWQFZ7Lx-rg\" , }); // we add that part to a new section page . addSection (). addControl ( part ); // save our content changes back to the server await page . save ();","title":"Add Client-side Web Parts"},{"location":"sp/docs/client-side-pages/#find-controls","text":"Added in 1.0.3 You can use the either of the two available method to locate controls within a page. These method search through all sections, columns, and controls returning the first instance that meets the supplied criteria. import { ClientSideWebPart } from \"@pnp/sp\" ; // find a control by instance id const control1 = page . findControlById ( \"b99bfccc-164e-4d3d-9b96-da48db62eb78\" ); // type the returned control const control2 = page . findControlById < ClientSideWebPart > ( \"c99bfccc-164e-4d3d-9b96-da48db62eb78\" ); const control3 = page . findControlById < ClientSideText > ( \"a99bfccc-164e-4d3d-9b96-da48db62eb78\" ); // use any predicate to find a control const control4 = page2 . findControl < ClientSideWebpart > (( c : CanvasControl ) => { // any logic you wish can be used on the control here // return true to return that control return c . order > 3 ; });","title":"Find Controls"},{"location":"sp/docs/client-side-pages/#control-comments","text":"You can choose to enable or disable comments on a page using these methods // indicates if comments are disabled, not valid until the page is loaded (Added in _1.0.3_) page . commentsDisabled // enable comments await page . enableComments (); // disable comments await page . disableComments ();","title":"Control Comments"},{"location":"sp/docs/client-side-pages/#likeunlike-client-side-page-get-like-information-about-page","text":"Added in 1.2.4 You can like or unlike a modern page. You can also get information about the likes (i.e like Count and which users liked the page) // Like a Client-side page (Added in _1.2.4_) await page . like (); // Unlike a Client-side page await page . unlike (); // Get liked by information such as like count and user's who liked the page await page . getLikedByInformation ();","title":"Like/Unlike Client-side page, get like information about page"},{"location":"sp/docs/client-side-pages/#sample","text":"The below sample shows the process to add a Yammer feed webpart to the page. The properties required as well as the data version are found by adding the part using the UI and reviewing the values. Some or all of these may be discoverable using Yammer APIs . An identical process can be used to add web parts of any type by adjusting the definition, data version, and properties appropriately. // get webpart defs const defs = await sp . web . getClientSideWebParts (); // this is the id of the definition in my farm const yammerPartDef = defs . filter ( d => d . Id === \"31e9537e-f9dc-40a4-8834-0e3b7df418bc\" )[ 0 ]; // page file const file = sp . web . getFileByServerRelativePath ( \"/sites/dev/SitePages/Testing_kVKF.aspx\" ); // create page instance const page = await ClientSidePage . fromFile ( file ); // create part instance from definition const part = ClientSideWebpart . fromComponentDef ( yammerPartDef ); // update data version part . dataVersion = \"1.5\" ; // set the properties required part . setProperties ({ feedType : 0 , isSuiteConnected : false , mode : 2 , networkId : 9999999 , yammerEmbedContainerHeight : 400 , yammerFeedURL : \"\" , yammerGroupId : - 1 , yammerGroupMugshotUrl : \"https://mug0.assets-yammer.com/mugshot/images/{width}x{height}/all_company.png\" , yammerGroupName : \"All Company\" , yammerGroupUrl : \"https://www.yammer.com/{tenant}/#/threads/company?type=general\" , }); // add to the section/column you want page . sections [ 0 ]. addControl ( part ); // persist changes page . save ();","title":"Sample"},{"location":"sp/docs/comments-likes/","text":"@pnp/sp/comments and likes \u00b6 Likes and comments in the context of modern sites are based on list items, meaning the operations branch from the Item class. To load an item you can refer to the guidance in the items article . If you want to set the likes or comments on a modern page and don't know the item id but do know the url you can first load the file and then use the getItem method to get an item instance: These APIs are currently in BETA and are subject to change or may not work on all tenants. import { sp } from \"@pnp/sp\" ; const item = await sp . web . getFileByServerRelativeUrl ( \"/sites/dev/SitePages/Test_8q5L.aspx\" ). getItem (); // as an example, or any of the below options await item . like (); The below examples use a variable named \"item\" which is taken to represent an instance of the Item class. Comments \u00b6 Get Comments \u00b6 const comments = await item . comments . get (); You can also get the comments merged with instances of the Comment class to immediately start accessing the properties and methods: import { spODataEntityArray , Comment , CommentData } from \"@pnp/sp\" ; const comments = await item . comments . get ( spODataEntityArray < Comment , CommentData > ( Comment )); // these will be Comment instances in the array comments [ 0 ]. replies . add ({ text : \"#PnPjs is pretty ok!\" }); //load the top 20 replies and comments for an item including likedBy information const comments = await item . comments . expand ( \"replies\" , \"likedBy\" , \"replies/likedBy\" ). top ( 20 ). get (); Add Comment \u00b6 // you can add a comment as a string item . comments . add ( \"string comment\" ); // or you can add it as an object to include mentions item . comments . add ({ text : \"comment from object property\" }); Delete a Comment \u00b6 import { spODataEntityArray , Comment , CommentData } from \"@pnp/sp\" ; const comments = await item . comments . get ( spODataEntityArray < Comment , CommentData > ( Comment )); // these will be Comment instances in the array comments [ 0 ]. delete () Like Comment \u00b6 import { spODataEntityArray , Comment , CommentData } from \"@pnp/sp\" ; const comments = await item . comments . get ( spODataEntityArray < Comment , CommentData > ( Comment )); // these will be Comment instances in the array comments [ 0 ]. like () Unlike Comment \u00b6 import { spODataEntityArray , Comment , CommentData } from \"@pnp/sp\" ; const comments = await item . comments . get ( spODataEntityArray < Comment , CommentData > ( Comment )); comments [ 0 ]. unlike () Reply to a Comment \u00b6 import { spODataEntityArray , Comment , CommentData } from \"@pnp/sp\" ; const comments = await item . comments . get ( spODataEntityArray < Comment , CommentData > ( Comment )); const comment : Comment & CommentData = await comments [ 0 ]. replies . add ({ text : \"#PnPjs is pretty ok!\" }); Load Replies to a Comment \u00b6 import { spODataEntityArray , Comment , CommentData } from \"@pnp/sp\" ; const comments = await item . comments . get ( spODataEntityArray < Comment , CommentData > ( Comment )); const replies = await comments [ 0 ]. replies . get (); Like \u00b6 You can like items and comments on items. See above for how to like or unlike a comment. Below you can see how to like and unlike an items, as well as get the liked by data. import { LikeData } from \"@pnp/sp\" ; // like an item await item . like (); // unlike an item await item . unlike (); // get the liked by information const likedByData : LikeData [] = await item . getLikedBy ();","title":"Comments and Likes"},{"location":"sp/docs/comments-likes/#pnpspcomments-and-likes","text":"Likes and comments in the context of modern sites are based on list items, meaning the operations branch from the Item class. To load an item you can refer to the guidance in the items article . If you want to set the likes or comments on a modern page and don't know the item id but do know the url you can first load the file and then use the getItem method to get an item instance: These APIs are currently in BETA and are subject to change or may not work on all tenants. import { sp } from \"@pnp/sp\" ; const item = await sp . web . getFileByServerRelativeUrl ( \"/sites/dev/SitePages/Test_8q5L.aspx\" ). getItem (); // as an example, or any of the below options await item . like (); The below examples use a variable named \"item\" which is taken to represent an instance of the Item class.","title":"@pnp/sp/comments and likes"},{"location":"sp/docs/comments-likes/#comments","text":"","title":"Comments"},{"location":"sp/docs/comments-likes/#get-comments","text":"const comments = await item . comments . get (); You can also get the comments merged with instances of the Comment class to immediately start accessing the properties and methods: import { spODataEntityArray , Comment , CommentData } from \"@pnp/sp\" ; const comments = await item . comments . get ( spODataEntityArray < Comment , CommentData > ( Comment )); // these will be Comment instances in the array comments [ 0 ]. replies . add ({ text : \"#PnPjs is pretty ok!\" }); //load the top 20 replies and comments for an item including likedBy information const comments = await item . comments . expand ( \"replies\" , \"likedBy\" , \"replies/likedBy\" ). top ( 20 ). get ();","title":"Get Comments"},{"location":"sp/docs/comments-likes/#add-comment","text":"// you can add a comment as a string item . comments . add ( \"string comment\" ); // or you can add it as an object to include mentions item . comments . add ({ text : \"comment from object property\" });","title":"Add Comment"},{"location":"sp/docs/comments-likes/#delete-a-comment","text":"import { spODataEntityArray , Comment , CommentData } from \"@pnp/sp\" ; const comments = await item . comments . get ( spODataEntityArray < Comment , CommentData > ( Comment )); // these will be Comment instances in the array comments [ 0 ]. delete ()","title":"Delete a Comment"},{"location":"sp/docs/comments-likes/#like-comment","text":"import { spODataEntityArray , Comment , CommentData } from \"@pnp/sp\" ; const comments = await item . comments . get ( spODataEntityArray < Comment , CommentData > ( Comment )); // these will be Comment instances in the array comments [ 0 ]. like ()","title":"Like Comment"},{"location":"sp/docs/comments-likes/#unlike-comment","text":"import { spODataEntityArray , Comment , CommentData } from \"@pnp/sp\" ; const comments = await item . comments . get ( spODataEntityArray < Comment , CommentData > ( Comment )); comments [ 0 ]. unlike ()","title":"Unlike Comment"},{"location":"sp/docs/comments-likes/#reply-to-a-comment","text":"import { spODataEntityArray , Comment , CommentData } from \"@pnp/sp\" ; const comments = await item . comments . get ( spODataEntityArray < Comment , CommentData > ( Comment )); const comment : Comment & CommentData = await comments [ 0 ]. replies . add ({ text : \"#PnPjs is pretty ok!\" });","title":"Reply to a Comment"},{"location":"sp/docs/comments-likes/#load-replies-to-a-comment","text":"import { spODataEntityArray , Comment , CommentData } from \"@pnp/sp\" ; const comments = await item . comments . get ( spODataEntityArray < Comment , CommentData > ( Comment )); const replies = await comments [ 0 ]. replies . get ();","title":"Load Replies to a Comment"},{"location":"sp/docs/comments-likes/#like","text":"You can like items and comments on items. See above for how to like or unlike a comment. Below you can see how to like and unlike an items, as well as get the liked by data. import { LikeData } from \"@pnp/sp\" ; // like an item await item . like (); // unlike an item await item . unlike (); // get the liked by information const likedByData : LikeData [] = await item . getLikedBy ();","title":"Like"},{"location":"sp/docs/content-types/","text":"@pnp/sp/content types \u00b6 Set Folder Unique Content Type Order \u00b6 interface OrderData { ContentTypeOrder : { StringValue : string }[]; UniqueContentTypeOrder ?: { StringValue : string }[]; } const folder = sp . web . lists . getById ( \"{list id guid}\" ). rootFolder ; // here you need to see if there are unique content type orders already or just the default const existingOrders = await folder . select ( \"ContentTypeOrder\" , \"UniqueContentTypeOrder\" ). get < OrderData > (); const activeOrder = existingOrders . UniqueContentTypeOrder ? existingOrders.UniqueContentTypeOrder : existingOrders.ContentTypeOrder ; // manipulate the order here however you want (I am just reversing the array as an example) const newOrder = activeOrder . reverse (); // update the content type order thusly: await folder . update ({ UniqueContentTypeOrder : { __metadata : { type : \"Collection(SP.ContentTypeId)\" }, results : newOrder , }, });","title":"Content Types"},{"location":"sp/docs/content-types/#pnpspcontent-types","text":"","title":"@pnp/sp/content types"},{"location":"sp/docs/content-types/#set-folder-unique-content-type-order","text":"interface OrderData { ContentTypeOrder : { StringValue : string }[]; UniqueContentTypeOrder ?: { StringValue : string }[]; } const folder = sp . web . lists . getById ( \"{list id guid}\" ). rootFolder ; // here you need to see if there are unique content type orders already or just the default const existingOrders = await folder . select ( \"ContentTypeOrder\" , \"UniqueContentTypeOrder\" ). get < OrderData > (); const activeOrder = existingOrders . UniqueContentTypeOrder ? existingOrders.UniqueContentTypeOrder : existingOrders.ContentTypeOrder ; // manipulate the order here however you want (I am just reversing the array as an example) const newOrder = activeOrder . reverse (); // update the content type order thusly: await folder . update ({ UniqueContentTypeOrder : { __metadata : { type : \"Collection(SP.ContentTypeId)\" }, results : newOrder , }, });","title":"Set Folder Unique Content Type Order"},{"location":"sp/docs/entity-merging/","text":"@pnp/sp - entity merging \u00b6 Sometimes when we make a query entity's data we would like then to immediately run other commands on the returned entity. To have data returned as its represending type we make use of the spODataEntity and spODataEntityArray parsers. The below approach works for all instance types such as List, Web, Item, or Field as examples. Request a single entity \u00b6 If we are loading a single entity we use the spODataEntity method. Here we show loading a list item using the Item class and a simple get query. import { sp , spODataEntity , Item } from \"@pnp/sp\" ; // interface defining the returned properites interface MyProps { Id : number ; } try { // get a list item laoded with data and merged into an instance of Item const item = await sp . web . lists . getByTitle ( \"ListTitle\" ). items . getById ( 1 ). get ( spODataEntity < Item , MyProps > ( Item )); // log the item id, all properties specified in MyProps will be type checked Logger . write ( `Item id: ${ item . Id } ` ); // now we can call update because we have an instance of the Item type to work with as well await item . update ({ Title : \"New title.\" , }); } catch ( e ) { Logger . error ( e ); } Request a collection \u00b6 The same pattern works when requesting a collection of objects with the exception of using the spODataEntityArray method. import { sp , spODataEntityArray , Item } from \"@pnp/sp\" ; // interface defining the returned properites interface MyProps { Id : number ; Title : string ; } try { // get a list item laoded with data and merged into an instance of Item const items = await sp . web . lists . getByTitle ( \"ListTitle\" ). items . select ( \"Id\" , \"Title\" ). get ( spODataEntityArray < Item , MyProps > ( Item )); Logger . write ( `Item id: ${ items . length } ` ); Logger . write ( `Item id: ${ items [ 0 ]. Title } ` ); // now we can call update because we have an instance of the Item type to work with as well await items [ 0 ]. update ({ Title : \"New title.\" , }); } catch ( e ) { Logger . error ( e ); } Use with Item getPaged \u00b6 Added in 1.3.4 Starting with 1.3.4 you can now include entity merging in the getPaged command as shown below. This approach will work with any objects matching the required factory pattern. // create Item instances with the defined property Title const items = await sp . web . lists . getByTitle ( \"BigList\" ). items . select ( \"Title\" ). getPaged ( spODataEntityArray < Item , { Title : string } > ( Item )); console . log ( items . results . length ); // now invoke methods on the Item object const perms = await items . results [ 0 ]. getCurrentUserEffectivePermissions (); console . log ( JSON . stringify ( perms , null , 2 )); // you can also type the result slightly differently if you prefer this, but the results are the same functionally. const items2 = await sp . web . lists . getByTitle ( \"BigList\" ). items . select ( \"Title\" ). getPaged < ( Item & { Title : string })[] > ( spODataEntityArray ( Item ));","title":"Entity Merging"},{"location":"sp/docs/entity-merging/#pnpsp-entity-merging","text":"Sometimes when we make a query entity's data we would like then to immediately run other commands on the returned entity. To have data returned as its represending type we make use of the spODataEntity and spODataEntityArray parsers. The below approach works for all instance types such as List, Web, Item, or Field as examples.","title":"@pnp/sp - entity merging"},{"location":"sp/docs/entity-merging/#request-a-single-entity","text":"If we are loading a single entity we use the spODataEntity method. Here we show loading a list item using the Item class and a simple get query. import { sp , spODataEntity , Item } from \"@pnp/sp\" ; // interface defining the returned properites interface MyProps { Id : number ; } try { // get a list item laoded with data and merged into an instance of Item const item = await sp . web . lists . getByTitle ( \"ListTitle\" ). items . getById ( 1 ). get ( spODataEntity < Item , MyProps > ( Item )); // log the item id, all properties specified in MyProps will be type checked Logger . write ( `Item id: ${ item . Id } ` ); // now we can call update because we have an instance of the Item type to work with as well await item . update ({ Title : \"New title.\" , }); } catch ( e ) { Logger . error ( e ); }","title":"Request a single entity"},{"location":"sp/docs/entity-merging/#request-a-collection","text":"The same pattern works when requesting a collection of objects with the exception of using the spODataEntityArray method. import { sp , spODataEntityArray , Item } from \"@pnp/sp\" ; // interface defining the returned properites interface MyProps { Id : number ; Title : string ; } try { // get a list item laoded with data and merged into an instance of Item const items = await sp . web . lists . getByTitle ( \"ListTitle\" ). items . select ( \"Id\" , \"Title\" ). get ( spODataEntityArray < Item , MyProps > ( Item )); Logger . write ( `Item id: ${ items . length } ` ); Logger . write ( `Item id: ${ items [ 0 ]. Title } ` ); // now we can call update because we have an instance of the Item type to work with as well await items [ 0 ]. update ({ Title : \"New title.\" , }); } catch ( e ) { Logger . error ( e ); }","title":"Request a collection"},{"location":"sp/docs/entity-merging/#use-with-item-getpaged","text":"Added in 1.3.4 Starting with 1.3.4 you can now include entity merging in the getPaged command as shown below. This approach will work with any objects matching the required factory pattern. // create Item instances with the defined property Title const items = await sp . web . lists . getByTitle ( \"BigList\" ). items . select ( \"Title\" ). getPaged ( spODataEntityArray < Item , { Title : string } > ( Item )); console . log ( items . results . length ); // now invoke methods on the Item object const perms = await items . results [ 0 ]. getCurrentUserEffectivePermissions (); console . log ( JSON . stringify ( perms , null , 2 )); // you can also type the result slightly differently if you prefer this, but the results are the same functionally. const items2 = await sp . web . lists . getByTitle ( \"BigList\" ). items . select ( \"Title\" ). getPaged < ( Item & { Title : string })[] > ( spODataEntityArray ( Item ));","title":"Use with Item getPaged"},{"location":"sp/docs/features/","text":"@pnp/sp/features \u00b6 Features are used by SharePoint to package a set of functionality and either enable (activate) or disable (deactivate) that functionality based on requirements for a specific site. You can manage feature activation using the library as shown below. Note that the features collection only contains active features. List all Features \u00b6 import { sp } from \"@pnp/sp\" ; let web = sp . web ; // get all the active features web . features . get (). then ( f => { console . log ( f ); }); // select properties using odata operators web . features . select ( \"DisplayName\" , \"DefinitionId\" ). get (). then ( f => { console . log ( f ); }); // get a particular feature by id web . features . getById ( \"87294c72-f260-42f3-a41b-981a2ffce37a\" ). select ( \"DisplayName\" , \"DefinitionId\" ). get (). then ( f => { console . log ( f ); }); // get features using odata operators web . features . filter ( \"DisplayName eq 'MDSFeature'\" ). get (). then ( f => { console . log ( f ); }); Activate a Feature \u00b6 To activate a feature you must know the feature id. You can optionally force activation - if you aren't sure don't use force. import { sp } from \"@pnp/sp\" ; let web = sp . web ; // activate the minimum download strategy feature web . features . add ( \"87294c72-f260-42f3-a41b-981a2ffce37a\" ). then ( f => { console . log ( f ); }); Deactivate a Feature \u00b6 import { sp } from \"@pnp/sp\" ; let web = sp . web ; web . features . remove ( \"87294c72-f260-42f3-a41b-981a2ffce37a\" ). then ( f => { console . log ( f ); }); // you can also deactivate a feature but going through the collection's remove method is faster web . features . getById ( \"87294c72-f260-42f3-a41b-981a2ffce37a\" ). deactivate (). then ( f => { console . log ( f ); });","title":"Features"},{"location":"sp/docs/features/#pnpspfeatures","text":"Features are used by SharePoint to package a set of functionality and either enable (activate) or disable (deactivate) that functionality based on requirements for a specific site. You can manage feature activation using the library as shown below. Note that the features collection only contains active features.","title":"@pnp/sp/features"},{"location":"sp/docs/features/#list-all-features","text":"import { sp } from \"@pnp/sp\" ; let web = sp . web ; // get all the active features web . features . get (). then ( f => { console . log ( f ); }); // select properties using odata operators web . features . select ( \"DisplayName\" , \"DefinitionId\" ). get (). then ( f => { console . log ( f ); }); // get a particular feature by id web . features . getById ( \"87294c72-f260-42f3-a41b-981a2ffce37a\" ). select ( \"DisplayName\" , \"DefinitionId\" ). get (). then ( f => { console . log ( f ); }); // get features using odata operators web . features . filter ( \"DisplayName eq 'MDSFeature'\" ). get (). then ( f => { console . log ( f ); });","title":"List all Features"},{"location":"sp/docs/features/#activate-a-feature","text":"To activate a feature you must know the feature id. You can optionally force activation - if you aren't sure don't use force. import { sp } from \"@pnp/sp\" ; let web = sp . web ; // activate the minimum download strategy feature web . features . add ( \"87294c72-f260-42f3-a41b-981a2ffce37a\" ). then ( f => { console . log ( f ); });","title":"Activate a Feature"},{"location":"sp/docs/features/#deactivate-a-feature","text":"import { sp } from \"@pnp/sp\" ; let web = sp . web ; web . features . remove ( \"87294c72-f260-42f3-a41b-981a2ffce37a\" ). then ( f => { console . log ( f ); }); // you can also deactivate a feature but going through the collection's remove method is faster web . features . getById ( \"87294c72-f260-42f3-a41b-981a2ffce37a\" ). deactivate (). then ( f => { console . log ( f ); });","title":"Deactivate a Feature"},{"location":"sp/docs/fields/","text":"@pnp/sp/fields \u00b6 Fields allow you to store typed information within a SharePoint list. There are many types of fields and the library seeks to simplify working with the most common types. Fields exist in both site collections (site columns) or lists (list columns) and you can add/modify/delete them at either of these levels. Get Fields \u00b6 import { sp } from \"@pnp/sp\" ; let web = sp . web ; // get all the fields in a web web . fields . get (). then ( f => { console . log ( f ); }); // you can use odata operators on the fields collection web . fields . select ( \"Title\" , \"InternalName\" , \"TypeAsString\" ). top ( 10 ). orderBy ( \"Id\" ). get (). then ( f => { console . log ( f ); }); // get all the available fields in a web (includes parent web's fields) web . availablefields . get (). then ( f => { console . log ( f ); }); // get the fields in a list web . lists . getByTitle ( \"MyList\" ). fields . get (). then ( f => { console . log ( f ); }); // you can also get individual fields using getById, getByTitle, or getByInternalNameOrTitle web . fields . getById ( \"dee9c205-2537-44d6-94e2-7c957e6ebe6e\" ). get (). then ( f => { console . log ( f ); }); web . fields . getByTitle ( \"MyField4\" ). get (). then ( f => { console . log ( f ); }); web . fields . getByInternalNameOrTitle ( \"MyField4\" ). get (). then ( f => { console . log ( f ); }); Filtering Fields \u00b6 Sometimes you only want a subset of fields from the collection. Below are some examples of using the filter operator with the fields collection. import { sp } from '@pnp/sp' ; const list = sp . web . lists . getByTitle ( 'Custom' ); // Fields which can be updated const filter1 = `Hidden eq false and ReadOnlyField eq false` ; list . fields . select ( 'InternalName' ). filter ( filter1 ). get (). then ( fields => { console . log ( `Can be updated: ${ fields . map ( f => f . InternalName ). join ( ', ' ) } ` ); // Title, ...Custom, ContentType, Attachments }); // Only custom field const filter2 = `Hidden eq false and CanBeDeleted eq true` ; list . fields . select ( 'InternalName' ). filter ( filter2 ). get (). then ( fields => { console . log ( `Custom fields: ${ fields . map ( f => f . InternalName ). join ( ', ' ) } ` ); // ...Custom }); // Application specific fields const includeFields = [ 'Title' , 'Author' , 'Editor' , 'Modified' , 'Created' ]; const filter3 = `Hidden eq false and (ReadOnlyField eq false or ( ${ includeFields . map ( field => `InternalName eq ' ${ field } '` ). join ( ' or ' ) } ))` ; list . fields . select ( 'InternalName' ). filter ( filter3 ). get (). then ( fields => { console . log ( `Application specific: ${ fields . map ( f => f . InternalName ). join ( ', ' ) } ` ); // Title, ...Custom, ContentType, Modified, Created, Author, Editor, Attachments }); // Fields in a view list . defaultView . fields . select ( 'Items' ). get (). then ( f => { const fields = ( f as any ). Items . results || ( f as any ). Items ; console . log ( `Fields in a view: ${ fields . join ( ', ' ) } ` ); }); Add Fields \u00b6 You can add fields using the add, createFieldAsXml, or one of the type specific methods. Functionally there is no difference, however one method may be easier given a certain scenario. import { sp } from \"@pnp/sp\" ; let web = sp . web ; // if you use add you _must_ include the correct FieldTypeKind in the extended properties web . fields . add ( \"MyField1\" , \"SP.FieldText\" , { Group : \"~Example\" , FieldTypeKind : 2 , Filterable : true , Hidden : false , EnforceUniqueValues : true , }). then ( f => { console . log ( f ); }); // you can also use the addText or any of the other type specific methods on the collection web . fields . addText ( \"MyField2\" , 75 , { Group : \"~Example\" }). then ( f => { console . log ( f ); }); // if you have the field schema (for example from an old elements file) you can use createFieldAsXml let xml = `<Field DisplayName=\"MyField4\" Type=\"Text\" Required=\"FALSE\" StaticName=\"MyField4\" Name=\"MyField4\" MaxLength=\"125\" Group=\"~Example\" />` ; web . fields . createFieldAsXml ( xml ). then ( f => { console . log ( f ); }); // the same operations work on a list's fields collection web . lists . getByTitle ( \"MyList\" ). fields . addText ( \"MyField5\" , 100 ). then ( f => { console . log ( f ); }); // Create a lookup field, and a dependent lookup field web . lists . getByTitle ( \"MyList\" ). fields . addLookup ( \"MyLookup\" , \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\" , \"MyLookupTargetField\" ). then ( f => { console . log ( f ); // Create the dependent lookup field return web . lists . getByTitle ( \"MyList\" ). fields . addDependentLookupField ( \"MyLookup_ID\" , f . Id , \"ID\" ); }). then ( fDep => { console . log ( fDep ); }); Adding Multiline Text Fields with FullHtml \u00b6 Because the RichTextMode property is not exposed to the clients we cannot set this value via the API directly. The work around is to use the createFieldAsXml method as shown below import { sp } from \"@pnp/sp\" ; let web = sp . web ; const fieldAddResult = await web . fields . createFieldAsXml ( `<Field Type=\"Note\" Name=\"Content\" DisplayName=\"Content\" Required=\"{TRUE|FALSE}\" RichText=\"TRUE\" RichTextMode=\"FullHtml\" />` ); Update a Field \u00b6 You can also update the properties of a field in both webs and lists, but not all properties are able to be updated after creation. You can review this list for details. import { sp } from \"@pnp/sp\" ; let web = sp . web ; web . fields . getByTitle ( \"MyField4\" ). update ({ Description : \"A new description\" , }). then ( f => { console . log ( f ); }); Update a Url/Picture Field \u00b6 When updating a URL or Picture field you need to include the __metadata descriptor as shown below. import { sp } from \"@pnp/sp\" ; const data = { \"My_Field_Name\" : { \"__metadata\" : { \"type\" : \"SP.FieldUrlValue\" }, \"Description\" : \"A Pretty picture\" , \"Url\" : \"https://tenant.sharepoint.com/sites/dev/Style%20Library/DSC_0024.JPG\" , }, }; await sp . web . lists . getByTitle ( \"MyListTitle\" ). items . getById ( 1 ). update ( data ); Delete a Field \u00b6 import { sp } from \"@pnp/sp\" ; let web = sp . web ; web . fields . getByTitle ( \"MyField4\" ). delete (). then ( f => { console . log ( f ); });","title":"Fields"},{"location":"sp/docs/fields/#pnpspfields","text":"Fields allow you to store typed information within a SharePoint list. There are many types of fields and the library seeks to simplify working with the most common types. Fields exist in both site collections (site columns) or lists (list columns) and you can add/modify/delete them at either of these levels.","title":"@pnp/sp/fields"},{"location":"sp/docs/fields/#get-fields","text":"import { sp } from \"@pnp/sp\" ; let web = sp . web ; // get all the fields in a web web . fields . get (). then ( f => { console . log ( f ); }); // you can use odata operators on the fields collection web . fields . select ( \"Title\" , \"InternalName\" , \"TypeAsString\" ). top ( 10 ). orderBy ( \"Id\" ). get (). then ( f => { console . log ( f ); }); // get all the available fields in a web (includes parent web's fields) web . availablefields . get (). then ( f => { console . log ( f ); }); // get the fields in a list web . lists . getByTitle ( \"MyList\" ). fields . get (). then ( f => { console . log ( f ); }); // you can also get individual fields using getById, getByTitle, or getByInternalNameOrTitle web . fields . getById ( \"dee9c205-2537-44d6-94e2-7c957e6ebe6e\" ). get (). then ( f => { console . log ( f ); }); web . fields . getByTitle ( \"MyField4\" ). get (). then ( f => { console . log ( f ); }); web . fields . getByInternalNameOrTitle ( \"MyField4\" ). get (). then ( f => { console . log ( f ); });","title":"Get Fields"},{"location":"sp/docs/fields/#filtering-fields","text":"Sometimes you only want a subset of fields from the collection. Below are some examples of using the filter operator with the fields collection. import { sp } from '@pnp/sp' ; const list = sp . web . lists . getByTitle ( 'Custom' ); // Fields which can be updated const filter1 = `Hidden eq false and ReadOnlyField eq false` ; list . fields . select ( 'InternalName' ). filter ( filter1 ). get (). then ( fields => { console . log ( `Can be updated: ${ fields . map ( f => f . InternalName ). join ( ', ' ) } ` ); // Title, ...Custom, ContentType, Attachments }); // Only custom field const filter2 = `Hidden eq false and CanBeDeleted eq true` ; list . fields . select ( 'InternalName' ). filter ( filter2 ). get (). then ( fields => { console . log ( `Custom fields: ${ fields . map ( f => f . InternalName ). join ( ', ' ) } ` ); // ...Custom }); // Application specific fields const includeFields = [ 'Title' , 'Author' , 'Editor' , 'Modified' , 'Created' ]; const filter3 = `Hidden eq false and (ReadOnlyField eq false or ( ${ includeFields . map ( field => `InternalName eq ' ${ field } '` ). join ( ' or ' ) } ))` ; list . fields . select ( 'InternalName' ). filter ( filter3 ). get (). then ( fields => { console . log ( `Application specific: ${ fields . map ( f => f . InternalName ). join ( ', ' ) } ` ); // Title, ...Custom, ContentType, Modified, Created, Author, Editor, Attachments }); // Fields in a view list . defaultView . fields . select ( 'Items' ). get (). then ( f => { const fields = ( f as any ). Items . results || ( f as any ). Items ; console . log ( `Fields in a view: ${ fields . join ( ', ' ) } ` ); });","title":"Filtering Fields"},{"location":"sp/docs/fields/#add-fields","text":"You can add fields using the add, createFieldAsXml, or one of the type specific methods. Functionally there is no difference, however one method may be easier given a certain scenario. import { sp } from \"@pnp/sp\" ; let web = sp . web ; // if you use add you _must_ include the correct FieldTypeKind in the extended properties web . fields . add ( \"MyField1\" , \"SP.FieldText\" , { Group : \"~Example\" , FieldTypeKind : 2 , Filterable : true , Hidden : false , EnforceUniqueValues : true , }). then ( f => { console . log ( f ); }); // you can also use the addText or any of the other type specific methods on the collection web . fields . addText ( \"MyField2\" , 75 , { Group : \"~Example\" }). then ( f => { console . log ( f ); }); // if you have the field schema (for example from an old elements file) you can use createFieldAsXml let xml = `<Field DisplayName=\"MyField4\" Type=\"Text\" Required=\"FALSE\" StaticName=\"MyField4\" Name=\"MyField4\" MaxLength=\"125\" Group=\"~Example\" />` ; web . fields . createFieldAsXml ( xml ). then ( f => { console . log ( f ); }); // the same operations work on a list's fields collection web . lists . getByTitle ( \"MyList\" ). fields . addText ( \"MyField5\" , 100 ). then ( f => { console . log ( f ); }); // Create a lookup field, and a dependent lookup field web . lists . getByTitle ( \"MyList\" ). fields . addLookup ( \"MyLookup\" , \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\" , \"MyLookupTargetField\" ). then ( f => { console . log ( f ); // Create the dependent lookup field return web . lists . getByTitle ( \"MyList\" ). fields . addDependentLookupField ( \"MyLookup_ID\" , f . Id , \"ID\" ); }). then ( fDep => { console . log ( fDep ); });","title":"Add Fields"},{"location":"sp/docs/fields/#adding-multiline-text-fields-with-fullhtml","text":"Because the RichTextMode property is not exposed to the clients we cannot set this value via the API directly. The work around is to use the createFieldAsXml method as shown below import { sp } from \"@pnp/sp\" ; let web = sp . web ; const fieldAddResult = await web . fields . createFieldAsXml ( `<Field Type=\"Note\" Name=\"Content\" DisplayName=\"Content\" Required=\"{TRUE|FALSE}\" RichText=\"TRUE\" RichTextMode=\"FullHtml\" />` );","title":"Adding Multiline Text Fields with FullHtml"},{"location":"sp/docs/fields/#update-a-field","text":"You can also update the properties of a field in both webs and lists, but not all properties are able to be updated after creation. You can review this list for details. import { sp } from \"@pnp/sp\" ; let web = sp . web ; web . fields . getByTitle ( \"MyField4\" ). update ({ Description : \"A new description\" , }). then ( f => { console . log ( f ); });","title":"Update a Field"},{"location":"sp/docs/fields/#update-a-urlpicture-field","text":"When updating a URL or Picture field you need to include the __metadata descriptor as shown below. import { sp } from \"@pnp/sp\" ; const data = { \"My_Field_Name\" : { \"__metadata\" : { \"type\" : \"SP.FieldUrlValue\" }, \"Description\" : \"A Pretty picture\" , \"Url\" : \"https://tenant.sharepoint.com/sites/dev/Style%20Library/DSC_0024.JPG\" , }, }; await sp . web . lists . getByTitle ( \"MyListTitle\" ). items . getById ( 1 ). update ( data );","title":"Update a Url/Picture Field"},{"location":"sp/docs/fields/#delete-a-field","text":"import { sp } from \"@pnp/sp\" ; let web = sp . web ; web . fields . getByTitle ( \"MyField4\" ). delete (). then ( f => { console . log ( f ); });","title":"Delete a Field"},{"location":"sp/docs/files/","text":"@pnp/sp/files \u00b6 One of the more challenging tasks on the client side is working with SharePoint files, especially if they are large files. We have added some methods to the library to help and their use is outlined below. Reading Files \u00b6 Reading files from the client using REST is covered in the below examples. The important thing to remember is choosing which format you want the file in so you can appropriately process it. You can retrieve a file as Blob, Buffer, JSON, or Text. If you have a special requirement you could also write your own parser . import { sp } from \"@pnp/sp\" ; sp . web . getFileByServerRelativeUrl ( \"/sites/dev/documents/file.avi\" ). getBlob (). then (( blob : Blob ) => {}); sp . web . getFileByServerRelativeUrl ( \"/sites/dev/documents/file.avi\" ). getBuffer (). then (( buffer : ArrayBuffer ) => {}); sp . web . getFileByServerRelativeUrl ( \"/sites/dev/documents/file.json\" ). getJSON (). then (( json : any ) => {}); sp . web . getFileByServerRelativeUrl ( \"/sites/dev/documents/file.txt\" ). getText (). then (( text : string ) => {}); // all of these also work from a file object no matter how you access it sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/documents\" ). files . getByName ( \"file.txt\" ). getText (). then (( text : string ) => {}); Adding Files \u00b6 Likewise you can add files using one of two methods, add or addChunked. The second is appropriate for larger files, generally larger than 10 MB but this may differ based on your bandwidth/latency so you can adjust the code to use the chunked method. The below example shows getting the file object from an input and uploading it to SharePoint, choosing the upload method based on file size. declare var require : ( s : string ) => any ; import { ConsoleListener , Web , Logger , LogLevel , ODataRaw } from \"@pnp/sp\" ; import { auth } from \"./auth\" ; let $ = require ( \"jquery\" ); let siteUrl = \"https://mytenant.sharepoint.com/sites/dev\" ; // comment this out for non-node execution // auth(siteUrl); Logger . subscribe ( new ConsoleListener ()); Logger . activeLogLevel = LogLevel . Verbose ; let web = new Web ( siteUrl ); $ (() => { $ ( \"#testingdiv\" ). append ( \"<button id='thebuttontodoit'>Do It</button>\" ); $ ( \"#thebuttontodoit\" ). on ( 'click' , ( e ) => { e . preventDefault (); let input = < HTMLInputElement > document . getElementById ( \"thefileinput\" ); let file = input . files [ 0 ]; // you can adjust this number to control what size files are uploaded in chunks if ( file . size <= 10485760 ) { // small upload web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared%20Documents/test/\" ). files . add ( file . name , file , true ). then ( _ => Logger . write ( \"done\" )); } else { // large upload web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared%20Documents/test/\" ). files . addChunked ( file . name , file , data => { Logger . log ({ data : data , level : LogLevel.Verbose , message : \"progress\" }); }, true ). then ( _ => Logger . write ( \"done!\" )); } }); }); Setting Associated Item Values \u00b6 You can also update the file properties of a newly uploaded file using code similar to the below snippet: import { sp } from \"@pnp/sp\" ; sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared%20Documents/test/\" ). files . add ( file . name , file , true ). then ( f => { f . file . getItem (). then ( item => { item . update ({ Title : \"A Title\" , OtherField : \"My Other Value\" }); }); }); Update File Content \u00b6 You can of course use similar methods to update existing files as shown below: import { sp } from \"@pnp/sp\" ; sp . web . getFileByServerRelativeUrl ( \"/sites/dev/documents/test.txt\" ). setContent ( \"New string content for the file.\" ); sp . web . getFileByServerRelativeUrl ( \"/sites/dev/documents/test.mp4\" ). setContentChunked ( file ); Check in, Check out, and Approve & Deny \u00b6 The library provides helper methods for checking in, checking out, and approving files. Examples of these methods are shown below. Check In \u00b6 Check in takes two optional arguments, comment and check in type. import { sp , CheckinType } from \"@pnp/sp\" ; // default options with empty comment and CheckinType.Major sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). checkin (). then ( _ => { console . log ( \"File checked in!\" ); }); // supply a comment (< 1024 chars) and using default check in type CheckinType.Major sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). checkin ( \"A comment\" ). then ( _ => { console . log ( \"File checked in!\" ); }); // Supply both comment and check in type sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). checkin ( \"A comment\" , CheckinType . Overwrite ). then ( _ => { console . log ( \"File checked in!\" ); }); Check Out \u00b6 Check out takes no arguments. import { sp } from \"@pnp/sp\" ; sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). checkout (). then ( _ => { console . log ( \"File checked out!\" ); }); Approve and Deny \u00b6 You can also approve or deny files in libraries that use approval. Approve takes a single required argument of comment, the comment is optional for deny. import { sp } from \"@pnp/sp\" ; sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). approve ( \"Approval Comment\" ). then ( _ => { console . log ( \"File approved!\" ); }); // deny with no comment sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). deny (). then ( _ => { console . log ( \"File denied!\" ); }); // deny with a supplied comment. sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). deny ( \"Deny comment\" ). then ( _ => { console . log ( \"File denied!\" ); }); Publish and Unpublish \u00b6 You can both publish and unpublish a file using the library. Both methods take an optional comment argument. import { sp } from \"@pnp/sp\" ; // publish with no comment sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). publish (). then ( _ => { console . log ( \"File published!\" ); }); // publish with a supplied comment. sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). publish ( \"Publish comment\" ). then ( _ => { console . log ( \"File published!\" ); }); // unpublish with no comment sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). unpublish (). then ( _ => { console . log ( \"File unpublished!\" ); }); // unpublish with a supplied comment. sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). unpublish ( \"Unpublish comment\" ). then ( _ => { console . log ( \"File unpublished!\" ); }); Advanced Upload Options \u00b6 Both the addChunked and setContentChunked methods support options beyond just supplying the file content. progress function \u00b6 A method that is called each time a chunk is uploaded and provides enough information to report progress or update a progress bar easily. The method has the signature: (data: ChunkedFileUploadProgressData) => void The data interface is: export interface ChunkedFileUploadProgressData { stage : \"starting\" | \"continue\" | \"finishing\" ; blockNumber : number ; totalBlocks : number ; chunkSize : number ; currentPointer : number ; fileSize : number ; } chunkSize \u00b6 This property controls the size of the individual chunks and is defaulted to 10485760 bytes (10 MB). You can adjust this based on your bandwidth needs - especially if writing code for mobile uploads or you are seeing frequent timeouts. getItem \u00b6 This method allows you to get the item associated with this file. You can optionally specify one or more select fields. The result will be merged with a new Item instance so you will have both the returned property values and chaining ability in a single object. import { sp } from \"@pnp/sp\" ; sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). getItem (). then ( item => { console . log ( item ); }); sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). getItem ( \"Title\" , \"Modified\" ). then ( item => { console . log ( item ); }); sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). getItem (). then ( item => { // you can also chain directly off this item instance item . getCurrentUserEffectivePermissions (). then ( perms => { console . log ( perms ); }); }); You can also supply a generic typing parameter and the resulting type will be a union type of Item and the generic type parameter. This allows you to have proper intellisense and type checking. import { sp } from \"@pnp/sp\" ; // also supports typing the objects so your type will be a union type sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). getItem < { Id : number , Title : string } > ( \"Id\" , \"Title\" ). then ( item => { // You get intellisense and proper typing of the returned object console . log ( `Id: ${ item . Id } -- ${ item . Title } ` ); // You can also chain directly off this item instance item . getCurrentUserEffectivePermissions (). then ( perms => { console . log ( perms ); }); });","title":"Files"},{"location":"sp/docs/files/#pnpspfiles","text":"One of the more challenging tasks on the client side is working with SharePoint files, especially if they are large files. We have added some methods to the library to help and their use is outlined below.","title":"@pnp/sp/files"},{"location":"sp/docs/files/#reading-files","text":"Reading files from the client using REST is covered in the below examples. The important thing to remember is choosing which format you want the file in so you can appropriately process it. You can retrieve a file as Blob, Buffer, JSON, or Text. If you have a special requirement you could also write your own parser . import { sp } from \"@pnp/sp\" ; sp . web . getFileByServerRelativeUrl ( \"/sites/dev/documents/file.avi\" ). getBlob (). then (( blob : Blob ) => {}); sp . web . getFileByServerRelativeUrl ( \"/sites/dev/documents/file.avi\" ). getBuffer (). then (( buffer : ArrayBuffer ) => {}); sp . web . getFileByServerRelativeUrl ( \"/sites/dev/documents/file.json\" ). getJSON (). then (( json : any ) => {}); sp . web . getFileByServerRelativeUrl ( \"/sites/dev/documents/file.txt\" ). getText (). then (( text : string ) => {}); // all of these also work from a file object no matter how you access it sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/documents\" ). files . getByName ( \"file.txt\" ). getText (). then (( text : string ) => {});","title":"Reading Files"},{"location":"sp/docs/files/#adding-files","text":"Likewise you can add files using one of two methods, add or addChunked. The second is appropriate for larger files, generally larger than 10 MB but this may differ based on your bandwidth/latency so you can adjust the code to use the chunked method. The below example shows getting the file object from an input and uploading it to SharePoint, choosing the upload method based on file size. declare var require : ( s : string ) => any ; import { ConsoleListener , Web , Logger , LogLevel , ODataRaw } from \"@pnp/sp\" ; import { auth } from \"./auth\" ; let $ = require ( \"jquery\" ); let siteUrl = \"https://mytenant.sharepoint.com/sites/dev\" ; // comment this out for non-node execution // auth(siteUrl); Logger . subscribe ( new ConsoleListener ()); Logger . activeLogLevel = LogLevel . Verbose ; let web = new Web ( siteUrl ); $ (() => { $ ( \"#testingdiv\" ). append ( \"<button id='thebuttontodoit'>Do It</button>\" ); $ ( \"#thebuttontodoit\" ). on ( 'click' , ( e ) => { e . preventDefault (); let input = < HTMLInputElement > document . getElementById ( \"thefileinput\" ); let file = input . files [ 0 ]; // you can adjust this number to control what size files are uploaded in chunks if ( file . size <= 10485760 ) { // small upload web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared%20Documents/test/\" ). files . add ( file . name , file , true ). then ( _ => Logger . write ( \"done\" )); } else { // large upload web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared%20Documents/test/\" ). files . addChunked ( file . name , file , data => { Logger . log ({ data : data , level : LogLevel.Verbose , message : \"progress\" }); }, true ). then ( _ => Logger . write ( \"done!\" )); } }); });","title":"Adding Files"},{"location":"sp/docs/files/#setting-associated-item-values","text":"You can also update the file properties of a newly uploaded file using code similar to the below snippet: import { sp } from \"@pnp/sp\" ; sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared%20Documents/test/\" ). files . add ( file . name , file , true ). then ( f => { f . file . getItem (). then ( item => { item . update ({ Title : \"A Title\" , OtherField : \"My Other Value\" }); }); });","title":"Setting Associated Item Values"},{"location":"sp/docs/files/#update-file-content","text":"You can of course use similar methods to update existing files as shown below: import { sp } from \"@pnp/sp\" ; sp . web . getFileByServerRelativeUrl ( \"/sites/dev/documents/test.txt\" ). setContent ( \"New string content for the file.\" ); sp . web . getFileByServerRelativeUrl ( \"/sites/dev/documents/test.mp4\" ). setContentChunked ( file );","title":"Update File Content"},{"location":"sp/docs/files/#check-in-check-out-and-approve-deny","text":"The library provides helper methods for checking in, checking out, and approving files. Examples of these methods are shown below.","title":"Check in, Check out, and Approve &amp; Deny"},{"location":"sp/docs/files/#check-in","text":"Check in takes two optional arguments, comment and check in type. import { sp , CheckinType } from \"@pnp/sp\" ; // default options with empty comment and CheckinType.Major sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). checkin (). then ( _ => { console . log ( \"File checked in!\" ); }); // supply a comment (< 1024 chars) and using default check in type CheckinType.Major sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). checkin ( \"A comment\" ). then ( _ => { console . log ( \"File checked in!\" ); }); // Supply both comment and check in type sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). checkin ( \"A comment\" , CheckinType . Overwrite ). then ( _ => { console . log ( \"File checked in!\" ); });","title":"Check In"},{"location":"sp/docs/files/#check-out","text":"Check out takes no arguments. import { sp } from \"@pnp/sp\" ; sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). checkout (). then ( _ => { console . log ( \"File checked out!\" ); });","title":"Check Out"},{"location":"sp/docs/files/#approve-and-deny","text":"You can also approve or deny files in libraries that use approval. Approve takes a single required argument of comment, the comment is optional for deny. import { sp } from \"@pnp/sp\" ; sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). approve ( \"Approval Comment\" ). then ( _ => { console . log ( \"File approved!\" ); }); // deny with no comment sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). deny (). then ( _ => { console . log ( \"File denied!\" ); }); // deny with a supplied comment. sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). deny ( \"Deny comment\" ). then ( _ => { console . log ( \"File denied!\" ); });","title":"Approve and Deny"},{"location":"sp/docs/files/#publish-and-unpublish","text":"You can both publish and unpublish a file using the library. Both methods take an optional comment argument. import { sp } from \"@pnp/sp\" ; // publish with no comment sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). publish (). then ( _ => { console . log ( \"File published!\" ); }); // publish with a supplied comment. sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). publish ( \"Publish comment\" ). then ( _ => { console . log ( \"File published!\" ); }); // unpublish with no comment sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). unpublish (). then ( _ => { console . log ( \"File unpublished!\" ); }); // unpublish with a supplied comment. sp . web . getFileByServerRelativeUrl ( \"/sites/dev/shared documents/file.txt\" ). unpublish ( \"Unpublish comment\" ). then ( _ => { console . log ( \"File unpublished!\" ); });","title":"Publish and Unpublish"},{"location":"sp/docs/files/#advanced-upload-options","text":"Both the addChunked and setContentChunked methods support options beyond just supplying the file content.","title":"Advanced Upload Options"},{"location":"sp/docs/files/#progress-function","text":"A method that is called each time a chunk is uploaded and provides enough information to report progress or update a progress bar easily. The method has the signature: (data: ChunkedFileUploadProgressData) => void The data interface is: export interface ChunkedFileUploadProgressData { stage : \"starting\" | \"continue\" | \"finishing\" ; blockNumber : number ; totalBlocks : number ; chunkSize : number ; currentPointer : number ; fileSize : number ; }","title":"progress function"},{"location":"sp/docs/files/#chunksize","text":"This property controls the size of the individual chunks and is defaulted to 10485760 bytes (10 MB). You can adjust this based on your bandwidth needs - especially if writing code for mobile uploads or you are seeing frequent timeouts.","title":"chunkSize"},{"location":"sp/docs/files/#getitem","text":"This method allows you to get the item associated with this file. You can optionally specify one or more select fields. The result will be merged with a new Item instance so you will have both the returned property values and chaining ability in a single object. import { sp } from \"@pnp/sp\" ; sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). getItem (). then ( item => { console . log ( item ); }); sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). getItem ( \"Title\" , \"Modified\" ). then ( item => { console . log ( item ); }); sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). getItem (). then ( item => { // you can also chain directly off this item instance item . getCurrentUserEffectivePermissions (). then ( perms => { console . log ( perms ); }); }); You can also supply a generic typing parameter and the resulting type will be a union type of Item and the generic type parameter. This allows you to have proper intellisense and type checking. import { sp } from \"@pnp/sp\" ; // also supports typing the objects so your type will be a union type sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). getItem < { Id : number , Title : string } > ( \"Id\" , \"Title\" ). then ( item => { // You get intellisense and proper typing of the returned object console . log ( `Id: ${ item . Id } -- ${ item . Title } ` ); // You can also chain directly off this item instance item . getCurrentUserEffectivePermissions (). then ( perms => { console . log ( perms ); }); });","title":"getItem"},{"location":"sp/docs/items/","text":"@pnp/sp/items \u00b6 GET \u00b6 Getting items from a list is one of the basic actions that most applications require. This is made easy through the library and the following examples demonstrate these actions. Basic Get \u00b6 import { sp } from \"@pnp/sp\" ; // get all the items from a list sp . web . lists . getByTitle ( \"My List\" ). items . get (). then (( items : any []) => { console . log ( items ); }); // get a specific item by id sp . web . lists . getByTitle ( \"My List\" ). items . getById ( 1 ). get (). then (( item : any ) => { console . log ( item ); }); // use odata operators for more efficient queries sp . web . lists . getByTitle ( \"My List\" ). items . select ( \"Title\" , \"Description\" ). top ( 5 ). orderBy ( \"Modified\" , true ). get (). then (( items : any []) => { console . log ( items ); }); Get Paged Items \u00b6 Working with paging can be a challenge as it is based on skip tokens and item ids, something that is hard to guess at runtime. To simplify things you can use the getPaged method on the Items class to assist. Note that there isn't a way to move backwards in the collection, this is by design. The pattern you should use to support backwards navigation in the results is to cache the results into a local array and use the standard array operators to get previous pages. Alternatively you can append the results to the UI, but this can have performance impact for large result sets. import { sp } from \"@pnp/sp\" ; // basic case to get paged items form a list let items = await sp . web . lists . getByTitle ( \"BigList\" ). items . getPaged (); // you can also provide a type for the returned values instead of any let items = await sp . web . lists . getByTitle ( \"BigList\" ). items . getPaged < { Title : string }[] > (); // the query also works with select to choose certain fields and top to set the page size let items = await sp . web . lists . getByTitle ( \"BigList\" ). items . select ( \"Title\" , \"Description\" ). top ( 50 ). getPaged < { Title : string }[] > (); // the results object will have two properties and one method: // the results property will be an array of the items returned if ( items . results . length > 0 ) { console . log ( \"We got results!\" ); for ( let i = 0 ; i < items . results . length ; i ++ ) { // type checking works here if we specify the return type console . log ( items . results [ i ]. Title ); } } // the hasNext property is used with the getNext method to handle paging // hasNext will be true so long as there are additional results if ( items . hasNext ) { // this will carry over the type specified in the original query for the results array items = await items . getNext (); console . log ( items . results . length ); } getListItemChangesSinceToken \u00b6 The GetListItemChangesSinceToken method allows clients to track changes on a list. Changes, including deleted items, are returned along with a token that represents the moment in time when those changes were requested. By including this token when you call GetListItemChangesSinceToken, the server looks for only those changes that have occurred since the token was generated. Sending a GetListItemChangesSinceToken request without including a token returns the list schema, the full list contents and a token. import { sp } from \"@pnp/sp\" ; // Using RowLimit. Enables paging let changes = await sp . web . lists . getByTitle ( \"BigList\" ). getListItemChangesSinceToken ({ RowLimit : '5' }); // Use QueryOptions to make a XML-style query. // Because it's XML we need to escape special characters // Instead of & we use &amp; in the query let changes = await sp . web . lists . getByTitle ( \"BigList\" ). getListItemChangesSinceToken ({ QueryOptions : '<Paging ListItemCollectionPositionNext=\"Paged=TRUE&amp;p_ID=5\" />' }); // Get everything. Using null with ChangeToken gets everything let changes = await sp . web . lists . getByTitle ( \"BigList\" ). getListItemChangesSinceToken ({ ChangeToken : null }); Get All Items \u00b6 Added in 1.0.2 Using the items collection's getAll method you can get all of the items in a list regardless of the size of the list. Sample usage is shown below. Only the odata operations top, select, and filter are supported. usingCaching and inBatch are ignored - you will need to handle caching the results on your own. This method will write a warning to the Logger and should not frequently be used. Instead the standard paging operations should be used. import { sp } from \"@pnp/sp\" ; // basic usage sp . web . lists . getByTitle ( \"BigList\" ). items . getAll (). then (( allItems : any []) => { // how many did we get console . log ( allItems . length ); }); // set page size sp . web . lists . getByTitle ( \"BigList\" ). items . getAll ( 4000 ). then (( allItems : any []) => { // how many did we get console . log ( allItems . length ); }); // use select and top. top will set page size and override the any value passed to getAll sp . web . lists . getByTitle ( \"BigList\" ). items . select ( \"Title\" ). top ( 4000 ). getAll (). then (( allItems : any []) => { // how many did we get console . log ( allItems . length ); }); // we can also use filter as a supported odata operation, but this will likely fail on large lists sp . web . lists . getByTitle ( \"BigList\" ). items . select ( \"Title\" ). filter ( \"Title eq 'Test'\" ). getAll (). then (( allItems : any []) => { // how many did we get console . log ( allItems . length ); }); Retrieving Lookup Fields \u00b6 When working with lookup fields you need to use the expand operator along with select to get the related fields from the lookup column. This works for both the items collection and item instances. import { sp } from \"@pnp/sp\" ; sp . web . lists . getByTitle ( \"LookupList\" ). items . select ( \"Title\" , \"Lookup/Title\" , \"Lookup/ID\" ). expand ( \"Lookup\" ). get (). then (( items : any []) => { console . log ( items ); }); sp . web . lists . getByTitle ( \"LookupList\" ). items . getById ( 1 ). select ( \"Title\" , \"Lookup/Title\" , \"Lookup/ID\" ). expand ( \"Lookup\" ). get (). then (( item : any ) => { console . log ( item ); }); Retrieving PublishingPageImage \u00b6 The PublishingPageImage and some other publishing-related fields aren't stored in normal fields, rather in the MetaInfo field. To get these values you need to use the technique shown below, and originally outlined in this thread . Note that a lot of information can be stored in this field so will pull back potentially a significant amount of data, so limit the rows as possible to aid performance. import { Web } from \"@pnp/sp\" ; const w = new Web ( \"https://{publishing site url}\" ); w . lists . getByTitle ( \"Pages\" ). items . select ( \"Title\" , \"FileRef\" , \"FieldValuesAsText/MetaInfo\" ) . expand ( \"FieldValuesAsText\" ) . get (). then ( r => { // look through the returned items. for ( var i = 0 ; i < r . length ; i ++ ) { // the title field value console . log ( r [ i ]. Title ); // find the value in the MetaInfo string using regex const matches = /PublishingPageImage:SW\\|(.*?)\\r\\n/ig . exec ( r [ i ]. FieldValuesAsText . MetaInfo ); if ( matches !== null && matches . length > 1 ) { // this wil be the value of the PublishingPageImage field console . log ( matches [ 1 ]); } } }). catch ( e => { console . error ( e ); }); Add Items \u00b6 There are several ways to add items to a list. The simplest just uses the add method of the items collection passing in the properties as a plain object. import { sp , ItemAddResult } from \"@pnp/sp\" ; // add an item to the list sp . web . lists . getByTitle ( \"My List\" ). items . add ({ Title : \"Title\" , Description : \"Description\" }). then (( iar : ItemAddResult ) => { console . log ( iar ); }); Content Type \u00b6 You can also set the content type id when you create an item as shown in the example below: import { sp } from \"@pnp/sp\" ; sp . web . lists . getById ( \"4D5A36EA-6E84-4160-8458-65C436DB765C\" ). items . add ({ Title : \"Test 1\" , ContentTypeId : \"0x01030058FD86C279252341AB303852303E4DAF\" }); User Fields \u00b6 There are two types of user fields, those that allow a single value and those that allow multiple. For both types, you first need to determine the Id field name, which you can do by doing a GET REST request on an existing item. Typically the value will be the user field internal name with \"Id\" appended. So in our example, we have two fields User1 and User2 so the Id fields are User1Id and User2Id. Next, you need to remember there are two types of user fields, those that take a single value and those that allow multiple - these are updated in different ways. For single value user fields you supply just the user's id. For multiple value fields, you need to supply an object with a \"results\" property and an array. Examples for both are shown below. import { sp } from \"@pnp/sp\" ; import { getGUID } from \"@pnp/core\" ; sp . web . lists . getByTitle ( \"PeopleFields\" ). items . add ({ Title : getGUID (), User1Id : 9 , // allows a single user User2Id : { results : [ 16 , 45 ] // allows multiple users } }). then ( i => { console . log ( i ); }); If you want to update or add user field values when using validateUpdateListItem you need to use the form shown below. You can specify multiple values in the array. import { sp } from \"@pnp/sp\" ; const result = await sp . web . lists . getByTitle ( \"UserFieldList\" ). items . getById ( 1 ). validateUpdateListItem ([{ FieldName : \"UserField\" , FieldValue : JSON.stringify ([{ \"Key\" : \"i:0#.f|membership|person@tenant.com\" }]), }, { FieldName : \"Title\" , FieldValue : \"Test - Updated\" , }]); Lookup Fields \u00b6 What is said for User Fields is, in general, relevant to Lookup Fields: - Lookup Field types: - Single-valued lookup - Multiple-valued lookup - Id suffix should be appended to the end of lookup's EntityPropertyName in payloads - Numeric Ids for lookups' items should be passed as values import { sp } from \"@pnp/sp\" ; import { getGUID } from \"@pnp/core\" ; sp . web . lists . getByTitle ( \"LookupFields\" ). items . add ({ Title : getGUID (), LookupFieldId : 2 , // allows a single lookup value MuptiLookupFieldId : { results : [ 1 , 56 ] // allows multiple lookup value } }). then ( console . log ). catch ( console . log ); Add Multiple Items \u00b6 import { sp } from \"@pnp/sp\" ; let list = sp . web . lists . getByTitle ( \"rapidadd\" ); list . getListItemEntityTypeFullName (). then ( entityTypeFullName => { let batch = sp . web . createBatch (); list . items . inBatch ( batch ). add ({ Title : \"Batch 6\" }, entityTypeFullName ). then ( b => { console . log ( b ); }); list . items . inBatch ( batch ). add ({ Title : \"Batch 7\" }, entityTypeFullName ). then ( b => { console . log ( b ); }); batch . execute (). then ( d => console . log ( \"Done\" )); }); Update \u00b6 The update method is very similar to the add method in that it takes a plain object representing the fields to update. The property names are the internal names of the fields. If you aren't sure you can always do a get request for an item in the list and see the field names that come back - you would use these same names to update the item. import { sp } from \"@pnp/sp\" ; let list = sp . web . lists . getByTitle ( \"MyList\" ); list . items . getById ( 1 ). update ({ Title : \"My New Title\" , Description : \"Here is a new description\" }). then ( i => { console . log ( i ); }); Getting and updating a collection using filter \u00b6 import { sp } from \"@pnp/sp\" ; // you are getting back a collection here sp . web . lists . getByTitle ( \"MyList\" ). items . top ( 1 ). filter ( \"Title eq 'A Title'\" ). get (). then (( items : any []) => { // see if we got something if ( items . length > 0 ) { sp . web . lists . getByTitle ( \"MyList\" ). items . getById ( items [ 0 ]. Id ). update ({ Title : \"Updated Title\" , }). then ( result => { // here you will have updated the item console . log ( JSON . stringify ( result )); }); } }); Update Multiple Items \u00b6 This approach avoids multiple calls for the same list's entity type name. import { sp } from \"@pnp/sp\" ; let list = sp . web . lists . getByTitle ( \"rapidupdate\" ); list . getListItemEntityTypeFullName (). then ( entityTypeFullName => { let batch = sp . web . createBatch (); // note requirement of \"*\" eTag param - or use a specific eTag value as needed list . items . getById ( 1 ). inBatch ( batch ). update ({ Title : \"Batch 6\" }, \"*\" , entityTypeFullName ). then ( b => { console . log ( b ); }); list . items . getById ( 2 ). inBatch ( batch ). update ({ Title : \"Batch 7\" }, \"*\" , entityTypeFullName ). then ( b => { console . log ( b ); }); batch . execute (). then ( d => console . log ( \"Done\" )); }); Recycle \u00b6 Sending an item to the Recycle Bin is as simple as calling the .recycle method. import { sp } from \"@pnp/sp\" ; let list = sp . web . lists . getByTitle ( \"MyList\" ); list . items . getById ( 1 ). recycle (). then ( _ => {}); Delete \u00b6 Delete is as simple as calling the .delete method. It optionally takes an eTag if you need to manage concurrency. import { sp } from \"@pnp/sp\" ; let list = sp . web . lists . getByTitle ( \"MyList\" ); list . items . getById ( 1 ). delete (). then ( _ => {}); Resolving field names \u00b6 It's a very common mistake trying wrong field names in the requests. Field's EntityPropertyName value should be used. The easiest way to get know EntityPropertyName is to use the following snippet: import { sp } from \"@pnp/sp\" ; sp . web . lists . getByTitle ( '[Lists_Title]' ) . fields . select ( 'Title, EntityPropertyName' ) . filter ( `Hidden eq false and Title eq '[Field's_Display_Name]'` ) . get () . then ( response => { console . log ( response . map ( field => { return { Title : field.Title , EntityPropertyName : field.EntityPropertyName }; })); }) . catch ( console . log ); Lookup fields' names should be ended with additional Id suffix. E.g. for Editor EntityPropertyName EditorId should be used.","title":"List Items"},{"location":"sp/docs/items/#pnpspitems","text":"","title":"@pnp/sp/items"},{"location":"sp/docs/items/#get","text":"Getting items from a list is one of the basic actions that most applications require. This is made easy through the library and the following examples demonstrate these actions.","title":"GET"},{"location":"sp/docs/items/#basic-get","text":"import { sp } from \"@pnp/sp\" ; // get all the items from a list sp . web . lists . getByTitle ( \"My List\" ). items . get (). then (( items : any []) => { console . log ( items ); }); // get a specific item by id sp . web . lists . getByTitle ( \"My List\" ). items . getById ( 1 ). get (). then (( item : any ) => { console . log ( item ); }); // use odata operators for more efficient queries sp . web . lists . getByTitle ( \"My List\" ). items . select ( \"Title\" , \"Description\" ). top ( 5 ). orderBy ( \"Modified\" , true ). get (). then (( items : any []) => { console . log ( items ); });","title":"Basic Get"},{"location":"sp/docs/items/#get-paged-items","text":"Working with paging can be a challenge as it is based on skip tokens and item ids, something that is hard to guess at runtime. To simplify things you can use the getPaged method on the Items class to assist. Note that there isn't a way to move backwards in the collection, this is by design. The pattern you should use to support backwards navigation in the results is to cache the results into a local array and use the standard array operators to get previous pages. Alternatively you can append the results to the UI, but this can have performance impact for large result sets. import { sp } from \"@pnp/sp\" ; // basic case to get paged items form a list let items = await sp . web . lists . getByTitle ( \"BigList\" ). items . getPaged (); // you can also provide a type for the returned values instead of any let items = await sp . web . lists . getByTitle ( \"BigList\" ). items . getPaged < { Title : string }[] > (); // the query also works with select to choose certain fields and top to set the page size let items = await sp . web . lists . getByTitle ( \"BigList\" ). items . select ( \"Title\" , \"Description\" ). top ( 50 ). getPaged < { Title : string }[] > (); // the results object will have two properties and one method: // the results property will be an array of the items returned if ( items . results . length > 0 ) { console . log ( \"We got results!\" ); for ( let i = 0 ; i < items . results . length ; i ++ ) { // type checking works here if we specify the return type console . log ( items . results [ i ]. Title ); } } // the hasNext property is used with the getNext method to handle paging // hasNext will be true so long as there are additional results if ( items . hasNext ) { // this will carry over the type specified in the original query for the results array items = await items . getNext (); console . log ( items . results . length ); }","title":"Get Paged Items"},{"location":"sp/docs/items/#getlistitemchangessincetoken","text":"The GetListItemChangesSinceToken method allows clients to track changes on a list. Changes, including deleted items, are returned along with a token that represents the moment in time when those changes were requested. By including this token when you call GetListItemChangesSinceToken, the server looks for only those changes that have occurred since the token was generated. Sending a GetListItemChangesSinceToken request without including a token returns the list schema, the full list contents and a token. import { sp } from \"@pnp/sp\" ; // Using RowLimit. Enables paging let changes = await sp . web . lists . getByTitle ( \"BigList\" ). getListItemChangesSinceToken ({ RowLimit : '5' }); // Use QueryOptions to make a XML-style query. // Because it's XML we need to escape special characters // Instead of & we use &amp; in the query let changes = await sp . web . lists . getByTitle ( \"BigList\" ). getListItemChangesSinceToken ({ QueryOptions : '<Paging ListItemCollectionPositionNext=\"Paged=TRUE&amp;p_ID=5\" />' }); // Get everything. Using null with ChangeToken gets everything let changes = await sp . web . lists . getByTitle ( \"BigList\" ). getListItemChangesSinceToken ({ ChangeToken : null });","title":"getListItemChangesSinceToken"},{"location":"sp/docs/items/#get-all-items","text":"Added in 1.0.2 Using the items collection's getAll method you can get all of the items in a list regardless of the size of the list. Sample usage is shown below. Only the odata operations top, select, and filter are supported. usingCaching and inBatch are ignored - you will need to handle caching the results on your own. This method will write a warning to the Logger and should not frequently be used. Instead the standard paging operations should be used. import { sp } from \"@pnp/sp\" ; // basic usage sp . web . lists . getByTitle ( \"BigList\" ). items . getAll (). then (( allItems : any []) => { // how many did we get console . log ( allItems . length ); }); // set page size sp . web . lists . getByTitle ( \"BigList\" ). items . getAll ( 4000 ). then (( allItems : any []) => { // how many did we get console . log ( allItems . length ); }); // use select and top. top will set page size and override the any value passed to getAll sp . web . lists . getByTitle ( \"BigList\" ). items . select ( \"Title\" ). top ( 4000 ). getAll (). then (( allItems : any []) => { // how many did we get console . log ( allItems . length ); }); // we can also use filter as a supported odata operation, but this will likely fail on large lists sp . web . lists . getByTitle ( \"BigList\" ). items . select ( \"Title\" ). filter ( \"Title eq 'Test'\" ). getAll (). then (( allItems : any []) => { // how many did we get console . log ( allItems . length ); });","title":"Get All Items"},{"location":"sp/docs/items/#retrieving-lookup-fields","text":"When working with lookup fields you need to use the expand operator along with select to get the related fields from the lookup column. This works for both the items collection and item instances. import { sp } from \"@pnp/sp\" ; sp . web . lists . getByTitle ( \"LookupList\" ). items . select ( \"Title\" , \"Lookup/Title\" , \"Lookup/ID\" ). expand ( \"Lookup\" ). get (). then (( items : any []) => { console . log ( items ); }); sp . web . lists . getByTitle ( \"LookupList\" ). items . getById ( 1 ). select ( \"Title\" , \"Lookup/Title\" , \"Lookup/ID\" ). expand ( \"Lookup\" ). get (). then (( item : any ) => { console . log ( item ); });","title":"Retrieving Lookup Fields"},{"location":"sp/docs/items/#retrieving-publishingpageimage","text":"The PublishingPageImage and some other publishing-related fields aren't stored in normal fields, rather in the MetaInfo field. To get these values you need to use the technique shown below, and originally outlined in this thread . Note that a lot of information can be stored in this field so will pull back potentially a significant amount of data, so limit the rows as possible to aid performance. import { Web } from \"@pnp/sp\" ; const w = new Web ( \"https://{publishing site url}\" ); w . lists . getByTitle ( \"Pages\" ). items . select ( \"Title\" , \"FileRef\" , \"FieldValuesAsText/MetaInfo\" ) . expand ( \"FieldValuesAsText\" ) . get (). then ( r => { // look through the returned items. for ( var i = 0 ; i < r . length ; i ++ ) { // the title field value console . log ( r [ i ]. Title ); // find the value in the MetaInfo string using regex const matches = /PublishingPageImage:SW\\|(.*?)\\r\\n/ig . exec ( r [ i ]. FieldValuesAsText . MetaInfo ); if ( matches !== null && matches . length > 1 ) { // this wil be the value of the PublishingPageImage field console . log ( matches [ 1 ]); } } }). catch ( e => { console . error ( e ); });","title":"Retrieving PublishingPageImage"},{"location":"sp/docs/items/#add-items","text":"There are several ways to add items to a list. The simplest just uses the add method of the items collection passing in the properties as a plain object. import { sp , ItemAddResult } from \"@pnp/sp\" ; // add an item to the list sp . web . lists . getByTitle ( \"My List\" ). items . add ({ Title : \"Title\" , Description : \"Description\" }). then (( iar : ItemAddResult ) => { console . log ( iar ); });","title":"Add Items"},{"location":"sp/docs/items/#content-type","text":"You can also set the content type id when you create an item as shown in the example below: import { sp } from \"@pnp/sp\" ; sp . web . lists . getById ( \"4D5A36EA-6E84-4160-8458-65C436DB765C\" ). items . add ({ Title : \"Test 1\" , ContentTypeId : \"0x01030058FD86C279252341AB303852303E4DAF\" });","title":"Content Type"},{"location":"sp/docs/items/#user-fields","text":"There are two types of user fields, those that allow a single value and those that allow multiple. For both types, you first need to determine the Id field name, which you can do by doing a GET REST request on an existing item. Typically the value will be the user field internal name with \"Id\" appended. So in our example, we have two fields User1 and User2 so the Id fields are User1Id and User2Id. Next, you need to remember there are two types of user fields, those that take a single value and those that allow multiple - these are updated in different ways. For single value user fields you supply just the user's id. For multiple value fields, you need to supply an object with a \"results\" property and an array. Examples for both are shown below. import { sp } from \"@pnp/sp\" ; import { getGUID } from \"@pnp/core\" ; sp . web . lists . getByTitle ( \"PeopleFields\" ). items . add ({ Title : getGUID (), User1Id : 9 , // allows a single user User2Id : { results : [ 16 , 45 ] // allows multiple users } }). then ( i => { console . log ( i ); }); If you want to update or add user field values when using validateUpdateListItem you need to use the form shown below. You can specify multiple values in the array. import { sp } from \"@pnp/sp\" ; const result = await sp . web . lists . getByTitle ( \"UserFieldList\" ). items . getById ( 1 ). validateUpdateListItem ([{ FieldName : \"UserField\" , FieldValue : JSON.stringify ([{ \"Key\" : \"i:0#.f|membership|person@tenant.com\" }]), }, { FieldName : \"Title\" , FieldValue : \"Test - Updated\" , }]);","title":"User Fields"},{"location":"sp/docs/items/#lookup-fields","text":"What is said for User Fields is, in general, relevant to Lookup Fields: - Lookup Field types: - Single-valued lookup - Multiple-valued lookup - Id suffix should be appended to the end of lookup's EntityPropertyName in payloads - Numeric Ids for lookups' items should be passed as values import { sp } from \"@pnp/sp\" ; import { getGUID } from \"@pnp/core\" ; sp . web . lists . getByTitle ( \"LookupFields\" ). items . add ({ Title : getGUID (), LookupFieldId : 2 , // allows a single lookup value MuptiLookupFieldId : { results : [ 1 , 56 ] // allows multiple lookup value } }). then ( console . log ). catch ( console . log );","title":"Lookup Fields"},{"location":"sp/docs/items/#add-multiple-items","text":"import { sp } from \"@pnp/sp\" ; let list = sp . web . lists . getByTitle ( \"rapidadd\" ); list . getListItemEntityTypeFullName (). then ( entityTypeFullName => { let batch = sp . web . createBatch (); list . items . inBatch ( batch ). add ({ Title : \"Batch 6\" }, entityTypeFullName ). then ( b => { console . log ( b ); }); list . items . inBatch ( batch ). add ({ Title : \"Batch 7\" }, entityTypeFullName ). then ( b => { console . log ( b ); }); batch . execute (). then ( d => console . log ( \"Done\" )); });","title":"Add Multiple Items"},{"location":"sp/docs/items/#update","text":"The update method is very similar to the add method in that it takes a plain object representing the fields to update. The property names are the internal names of the fields. If you aren't sure you can always do a get request for an item in the list and see the field names that come back - you would use these same names to update the item. import { sp } from \"@pnp/sp\" ; let list = sp . web . lists . getByTitle ( \"MyList\" ); list . items . getById ( 1 ). update ({ Title : \"My New Title\" , Description : \"Here is a new description\" }). then ( i => { console . log ( i ); });","title":"Update"},{"location":"sp/docs/items/#getting-and-updating-a-collection-using-filter","text":"import { sp } from \"@pnp/sp\" ; // you are getting back a collection here sp . web . lists . getByTitle ( \"MyList\" ). items . top ( 1 ). filter ( \"Title eq 'A Title'\" ). get (). then (( items : any []) => { // see if we got something if ( items . length > 0 ) { sp . web . lists . getByTitle ( \"MyList\" ). items . getById ( items [ 0 ]. Id ). update ({ Title : \"Updated Title\" , }). then ( result => { // here you will have updated the item console . log ( JSON . stringify ( result )); }); } });","title":"Getting and updating a collection using filter"},{"location":"sp/docs/items/#update-multiple-items","text":"This approach avoids multiple calls for the same list's entity type name. import { sp } from \"@pnp/sp\" ; let list = sp . web . lists . getByTitle ( \"rapidupdate\" ); list . getListItemEntityTypeFullName (). then ( entityTypeFullName => { let batch = sp . web . createBatch (); // note requirement of \"*\" eTag param - or use a specific eTag value as needed list . items . getById ( 1 ). inBatch ( batch ). update ({ Title : \"Batch 6\" }, \"*\" , entityTypeFullName ). then ( b => { console . log ( b ); }); list . items . getById ( 2 ). inBatch ( batch ). update ({ Title : \"Batch 7\" }, \"*\" , entityTypeFullName ). then ( b => { console . log ( b ); }); batch . execute (). then ( d => console . log ( \"Done\" )); });","title":"Update Multiple Items"},{"location":"sp/docs/items/#recycle","text":"Sending an item to the Recycle Bin is as simple as calling the .recycle method. import { sp } from \"@pnp/sp\" ; let list = sp . web . lists . getByTitle ( \"MyList\" ); list . items . getById ( 1 ). recycle (). then ( _ => {});","title":"Recycle"},{"location":"sp/docs/items/#delete","text":"Delete is as simple as calling the .delete method. It optionally takes an eTag if you need to manage concurrency. import { sp } from \"@pnp/sp\" ; let list = sp . web . lists . getByTitle ( \"MyList\" ); list . items . getById ( 1 ). delete (). then ( _ => {});","title":"Delete"},{"location":"sp/docs/items/#resolving-field-names","text":"It's a very common mistake trying wrong field names in the requests. Field's EntityPropertyName value should be used. The easiest way to get know EntityPropertyName is to use the following snippet: import { sp } from \"@pnp/sp\" ; sp . web . lists . getByTitle ( '[Lists_Title]' ) . fields . select ( 'Title, EntityPropertyName' ) . filter ( `Hidden eq false and Title eq '[Field's_Display_Name]'` ) . get () . then ( response => { console . log ( response . map ( field => { return { Title : field.Title , EntityPropertyName : field.EntityPropertyName }; })); }) . catch ( console . log ); Lookup fields' names should be ended with additional Id suffix. E.g. for Editor EntityPropertyName EditorId should be used.","title":"Resolving field names"},{"location":"sp/docs/navigation-service/","text":"@pnp/sp/navigation service \u00b6 The global navigation service located at \"_api/navigation\" provides access to the SiteMapProvider instances available in a given site collection. getMenuState \u00b6 The MenuState service operation returns a Menu-State (dump) of a SiteMapProvider on a site. It will return an exception if the SiteMapProvider cannot be found on the site, the SiteMapProvider does not implement the IEditableSiteMapProvider interface or the SiteMapNode key cannot be found within the provider hierarchy. The IEditableSiteMapProvider also supports Custom Properties which is an optional feature. What will be return in the custom properties is up to the IEditableSiteMapProvider implementation and can differ for for each SiteMapProvider implementation. The custom properties can be requested by providing a comma seperated string of property names like: property1,property2,property3\\,containingcomma NOTE: the , seperator can be escaped using the \\ as escape character as done in the example above. The string above would split like: property1 property2 * property3,containingcomma import { sp } from \"@pnp/sp\" ; // Will return a menu state of the default SiteMapProvider 'SPSiteMapProvider' where the dump starts a the RootNode (within the site) with a depth of 10 levels. sp . navigation . getMenuState (). then ( r => { console . log ( JSON . stringify ( r , null , 4 )); }). catch ( console . error ); // Will return the menu state of the 'SPSiteMapProvider', starting with the node with the key '1002' with a depth of 5 sp . navigation . getMenuState ( \"1002\" , 5 ). then ( r => { console . log ( JSON . stringify ( r , null , 4 )); }). catch ( console . error ); // Will return the menu state of the 'CurrentNavSiteMapProviderNoEncode' from the root node of the provider with a depth of 5 sp . navigation . getMenuState ( null , 5 , \"CurrentNavSiteMapProviderNoEncode\" ). then ( r => { console . log ( JSON . stringify ( r , null , 4 )); }). catch ( console . error ); getMenuNodeKey \u00b6 Tries to get a SiteMapNode.Key for a given URL within a site collection. If the SiteMapNode cannot be found an Exception is returned. The method is using SiteMapProvider.FindSiteMapNodeFromKey(string rawUrl) to lookup the SiteMapNode. Depending on the actual implementation of FindSiteMapNodeFromKey the matching can differ for different SiteMapProviders. import { sp } from \"@pnp/sp\" ; sp . navigation . getMenuNodeKey ( \"/sites/dev/Lists/SPPnPJSExampleList/AllItems.aspx\" ). then ( r => { console . log ( JSON . stringify ( r , null , 4 )); }). catch ( console . error );","title":"Navigation Service"},{"location":"sp/docs/navigation-service/#pnpspnavigation-service","text":"The global navigation service located at \"_api/navigation\" provides access to the SiteMapProvider instances available in a given site collection.","title":"@pnp/sp/navigation service"},{"location":"sp/docs/navigation-service/#getmenustate","text":"The MenuState service operation returns a Menu-State (dump) of a SiteMapProvider on a site. It will return an exception if the SiteMapProvider cannot be found on the site, the SiteMapProvider does not implement the IEditableSiteMapProvider interface or the SiteMapNode key cannot be found within the provider hierarchy. The IEditableSiteMapProvider also supports Custom Properties which is an optional feature. What will be return in the custom properties is up to the IEditableSiteMapProvider implementation and can differ for for each SiteMapProvider implementation. The custom properties can be requested by providing a comma seperated string of property names like: property1,property2,property3\\,containingcomma NOTE: the , seperator can be escaped using the \\ as escape character as done in the example above. The string above would split like: property1 property2 * property3,containingcomma import { sp } from \"@pnp/sp\" ; // Will return a menu state of the default SiteMapProvider 'SPSiteMapProvider' where the dump starts a the RootNode (within the site) with a depth of 10 levels. sp . navigation . getMenuState (). then ( r => { console . log ( JSON . stringify ( r , null , 4 )); }). catch ( console . error ); // Will return the menu state of the 'SPSiteMapProvider', starting with the node with the key '1002' with a depth of 5 sp . navigation . getMenuState ( \"1002\" , 5 ). then ( r => { console . log ( JSON . stringify ( r , null , 4 )); }). catch ( console . error ); // Will return the menu state of the 'CurrentNavSiteMapProviderNoEncode' from the root node of the provider with a depth of 5 sp . navigation . getMenuState ( null , 5 , \"CurrentNavSiteMapProviderNoEncode\" ). then ( r => { console . log ( JSON . stringify ( r , null , 4 )); }). catch ( console . error );","title":"getMenuState"},{"location":"sp/docs/navigation-service/#getmenunodekey","text":"Tries to get a SiteMapNode.Key for a given URL within a site collection. If the SiteMapNode cannot be found an Exception is returned. The method is using SiteMapProvider.FindSiteMapNodeFromKey(string rawUrl) to lookup the SiteMapNode. Depending on the actual implementation of FindSiteMapNodeFromKey the matching can differ for different SiteMapProviders. import { sp } from \"@pnp/sp\" ; sp . navigation . getMenuNodeKey ( \"/sites/dev/Lists/SPPnPJSExampleList/AllItems.aspx\" ). then ( r => { console . log ( JSON . stringify ( r , null , 4 )); }). catch ( console . error );","title":"getMenuNodeKey"},{"location":"sp/docs/permissions/","text":"@pnp/sp - permissions \u00b6 A common task is to determine if a user or the current user has a certain permission level. It is a great idea to check before performing a task such as creating a list to ensure a user can without getting back an error. This allows you to provide a better experience to the user. Permissions in SharePoint are assigned to the set of securable objects which include Site, Web, List, and List Item. These are the four level to which unique permissions can be assigned. As such @pnp/sp provides a set of methods defined in the QueryableSecurable class to handle these permissions. These examples all use the Web to get the values, however the methods work identically on all securables. Get Role Assignments \u00b6 This gets a collection of all the role assignments on a given securable. The property returns a RoleAssignments collection which supports the OData collection operators. import { sp } from \"@pnp/sp\" ; import { Logger } from \"@pnp/logging\" ; sp . web . roleAssignments . get (). then ( roles => { Logger . writeJSON ( roles ); }); First Unique Ancestor Securable Object \u00b6 This method can be used to find the securable parent up the hierarchy that has unique permissions. If everything inherits permissions this will be the Site. If a sub web has unique permissions it will be the web, and so on. import { sp } from \"@pnp/sp\" ; import { Logger } from \"@pnp/logging\" ; sp . web . firstUniqueAncestorSecurableObject . get (). then ( obj => { Logger . writeJSON ( obj ); }); User Effective Permissions \u00b6 This method returns the BasePermissions for a given user or the current user. This value contains the High and Low values for a user on the securable you have queried. import { sp } from \"@pnp/sp\" ; import { Logger } from \"@pnp/logging\" ; sp . web . getUserEffectivePermissions ( \"i:0#.f|membership|user@site.com\" ). then ( perms => { Logger . writeJSON ( perms ); }); sp . web . getCurrentUserEffectivePermissions (). then ( perms => { Logger . writeJSON ( perms ); }); User Has Permissions \u00b6 Because the High and Low values in the BasePermission don't obviously mean anything you can use these methods along with the PermissionKind enumeration to check actual rights on the securable. import { sp , PermissionKind } from \"@pnp/sp\" ; sp . web . userHasPermissions ( \"i:0#.f|membership|user@site.com\" , PermissionKind . ApproveItems ). then ( perms => { console . log ( perms ); }); sp . web . currentUserHasPermissions ( PermissionKind . ApproveItems ). then ( perms => { console . log ( perms ); }); Has Permissions \u00b6 If you need to check multiple permissions it can be more efficient to get the BasePermissions once and then use the hasPermissions method to check them as shown below. import { sp , PermissionKind } from \"@pnp/sp\" ; sp . web . getCurrentUserEffectivePermissions (). then ( perms => { if ( sp . web . hasPermissions ( perms , PermissionKind . AddListItems ) && sp . web . hasPermissions ( perms , PermissionKind . DeleteVersions )) { // ... } });","title":"Permissions"},{"location":"sp/docs/permissions/#pnpsp-permissions","text":"A common task is to determine if a user or the current user has a certain permission level. It is a great idea to check before performing a task such as creating a list to ensure a user can without getting back an error. This allows you to provide a better experience to the user. Permissions in SharePoint are assigned to the set of securable objects which include Site, Web, List, and List Item. These are the four level to which unique permissions can be assigned. As such @pnp/sp provides a set of methods defined in the QueryableSecurable class to handle these permissions. These examples all use the Web to get the values, however the methods work identically on all securables.","title":"@pnp/sp - permissions"},{"location":"sp/docs/permissions/#get-role-assignments","text":"This gets a collection of all the role assignments on a given securable. The property returns a RoleAssignments collection which supports the OData collection operators. import { sp } from \"@pnp/sp\" ; import { Logger } from \"@pnp/logging\" ; sp . web . roleAssignments . get (). then ( roles => { Logger . writeJSON ( roles ); });","title":"Get Role Assignments"},{"location":"sp/docs/permissions/#first-unique-ancestor-securable-object","text":"This method can be used to find the securable parent up the hierarchy that has unique permissions. If everything inherits permissions this will be the Site. If a sub web has unique permissions it will be the web, and so on. import { sp } from \"@pnp/sp\" ; import { Logger } from \"@pnp/logging\" ; sp . web . firstUniqueAncestorSecurableObject . get (). then ( obj => { Logger . writeJSON ( obj ); });","title":"First Unique Ancestor Securable Object"},{"location":"sp/docs/permissions/#user-effective-permissions","text":"This method returns the BasePermissions for a given user or the current user. This value contains the High and Low values for a user on the securable you have queried. import { sp } from \"@pnp/sp\" ; import { Logger } from \"@pnp/logging\" ; sp . web . getUserEffectivePermissions ( \"i:0#.f|membership|user@site.com\" ). then ( perms => { Logger . writeJSON ( perms ); }); sp . web . getCurrentUserEffectivePermissions (). then ( perms => { Logger . writeJSON ( perms ); });","title":"User Effective Permissions"},{"location":"sp/docs/permissions/#user-has-permissions","text":"Because the High and Low values in the BasePermission don't obviously mean anything you can use these methods along with the PermissionKind enumeration to check actual rights on the securable. import { sp , PermissionKind } from \"@pnp/sp\" ; sp . web . userHasPermissions ( \"i:0#.f|membership|user@site.com\" , PermissionKind . ApproveItems ). then ( perms => { console . log ( perms ); }); sp . web . currentUserHasPermissions ( PermissionKind . ApproveItems ). then ( perms => { console . log ( perms ); });","title":"User Has Permissions"},{"location":"sp/docs/permissions/#has-permissions","text":"If you need to check multiple permissions it can be more efficient to get the BasePermissions once and then use the hasPermissions method to check them as shown below. import { sp , PermissionKind } from \"@pnp/sp\" ; sp . web . getCurrentUserEffectivePermissions (). then ( perms => { if ( sp . web . hasPermissions ( perms , PermissionKind . AddListItems ) && sp . web . hasPermissions ( perms , PermissionKind . DeleteVersions )) { // ... } });","title":"Has Permissions"},{"location":"sp/docs/profiles/","text":"@pnp/sp/profiles \u00b6 The profile services allows to to work with the SharePoint User Profile Store. Profiles \u00b6 Profiles is accessed directly from the root sp object. import { sp } from \"@pnp/sp\" ; GET \u00b6 Get profile properties for a specific user \u00b6 getPropertiesFor(loginName: string): Promise<any>; sp . profiles . getPropertiesFor ( loginName ). then (( profile : any ) => { console . log ( profile . DisplayName ); console . log ( profile . Email ); console . log ( profile . Title ); console . log ( profile . UserProfileProperties . length ); // Properties are stored in inconvenient Key/Value pairs, // so parse into an object called userProperties var properties = {}; profile . UserProfileProperties . forEach ( function ( prop ) { properties [ prop . Key ] = prop . Value ; }); profile . userProperties = properties ; } Get a specific property for a specific user \u00b6 getUserProfilePropertyFor(loginName: string, propertyName: string): Promise<string>; sp . profiles . getUserProfilePropertyFor ( loginName , propName ). then (( prop : string ) => { console . log ( prop ); }; Find whether a user is following another user \u00b6 isFollowing(follower: string, followee: string): Promise<boolean>; sp . profiles . isFollowing ( follower , followee ). then (( followed : boolean ) => { console . log ( followed ); }; Find out who a user is following \u00b6 getPeopleFollowedBy(loginName: string): Promise<any[]>; sp . profiles . getPeopleFollowedBy ( loginName ). then (( followed : any []) => { console . log ( followed . length ); }; Find out if the current user is followed by another user \u00b6 amIFollowedBy(loginName: string): Promise<boolean>; Returns a boolean indicating if the current user is followed by the user with loginName. Get a specific property for the specified user. sp . profiles . amIFollowedBy ( loginName ). then (( followed : boolean ) => { console . log ( followed ); }; Get the people who are following the specified user \u00b6 getFollowersFor(loginName: string): Promise<any[]>; sp . profiles . getFollowersFor ( loginName ). then (( followed : any ) => { console . log ( followed . length ); }; SET \u00b6 Set a single value property value \u00b6 setSingleValueProfileProperty(accountName: string, propertyName: string, propertyValue: string) Set a user's user profile property. sp . profiles . setSingleValueProfileProperty ( accountName , propertyName , propertyValue ); Set multi valued User Profile property \u00b6 setMultiValuedProfileProperty(accountName: string, propertyName: string, propertyValues: string[]): Promise<void>; sp . profiles . setSingleValueProfileProperty ( accountName , propertyName , propertyValues ); Upload and set the user profile picture \u00b6 Users can upload a picture to their own profile only). Not supported for batching. Blob data representing the user's picture in BMP, JPEG, or PNG format of up to 4.76MB setMyProfilePic(profilePicSource: Blob): Promise<void>;","title":"Profiles"},{"location":"sp/docs/profiles/#pnpspprofiles","text":"The profile services allows to to work with the SharePoint User Profile Store.","title":"@pnp/sp/profiles"},{"location":"sp/docs/profiles/#profiles","text":"Profiles is accessed directly from the root sp object. import { sp } from \"@pnp/sp\" ;","title":"Profiles"},{"location":"sp/docs/profiles/#get","text":"","title":"GET"},{"location":"sp/docs/profiles/#get-profile-properties-for-a-specific-user","text":"getPropertiesFor(loginName: string): Promise<any>; sp . profiles . getPropertiesFor ( loginName ). then (( profile : any ) => { console . log ( profile . DisplayName ); console . log ( profile . Email ); console . log ( profile . Title ); console . log ( profile . UserProfileProperties . length ); // Properties are stored in inconvenient Key/Value pairs, // so parse into an object called userProperties var properties = {}; profile . UserProfileProperties . forEach ( function ( prop ) { properties [ prop . Key ] = prop . Value ; }); profile . userProperties = properties ; }","title":"Get profile properties for a specific user"},{"location":"sp/docs/profiles/#get-a-specific-property-for-a-specific-user","text":"getUserProfilePropertyFor(loginName: string, propertyName: string): Promise<string>; sp . profiles . getUserProfilePropertyFor ( loginName , propName ). then (( prop : string ) => { console . log ( prop ); };","title":"Get a specific property for a specific user"},{"location":"sp/docs/profiles/#find-whether-a-user-is-following-another-user","text":"isFollowing(follower: string, followee: string): Promise<boolean>; sp . profiles . isFollowing ( follower , followee ). then (( followed : boolean ) => { console . log ( followed ); };","title":"Find whether a user is following another user"},{"location":"sp/docs/profiles/#find-out-who-a-user-is-following","text":"getPeopleFollowedBy(loginName: string): Promise<any[]>; sp . profiles . getPeopleFollowedBy ( loginName ). then (( followed : any []) => { console . log ( followed . length ); };","title":"Find out who a user is following"},{"location":"sp/docs/profiles/#find-out-if-the-current-user-is-followed-by-another-user","text":"amIFollowedBy(loginName: string): Promise<boolean>; Returns a boolean indicating if the current user is followed by the user with loginName. Get a specific property for the specified user. sp . profiles . amIFollowedBy ( loginName ). then (( followed : boolean ) => { console . log ( followed ); };","title":"Find out if the current user is followed by another user"},{"location":"sp/docs/profiles/#get-the-people-who-are-following-the-specified-user","text":"getFollowersFor(loginName: string): Promise<any[]>; sp . profiles . getFollowersFor ( loginName ). then (( followed : any ) => { console . log ( followed . length ); };","title":"Get the people who are following the specified user"},{"location":"sp/docs/profiles/#set","text":"","title":"SET"},{"location":"sp/docs/profiles/#set-a-single-value-property-value","text":"setSingleValueProfileProperty(accountName: string, propertyName: string, propertyValue: string) Set a user's user profile property. sp . profiles . setSingleValueProfileProperty ( accountName , propertyName , propertyValue );","title":"Set a single value property value"},{"location":"sp/docs/profiles/#set-multi-valued-user-profile-property","text":"setMultiValuedProfileProperty(accountName: string, propertyName: string, propertyValues: string[]): Promise<void>; sp . profiles . setSingleValueProfileProperty ( accountName , propertyName , propertyValues );","title":"Set multi valued User Profile property"},{"location":"sp/docs/profiles/#upload-and-set-the-user-profile-picture","text":"Users can upload a picture to their own profile only). Not supported for batching. Blob data representing the user's picture in BMP, JPEG, or PNG format of up to 4.76MB setMyProfilePic(profilePicSource: Blob): Promise<void>;","title":"Upload and set the user profile picture"},{"location":"sp/docs/related-items/","text":"@pnp/sp/relateditems \u00b6 Related items are used in Task and Workflow lists (as well as others) to track items that have relationships similar to database relationships. All methods chain off the Web's relatedItems property as shown below: getRelatedItems \u00b6 Expects the named library to exist within the contextual web. import { sp , RelatedItem } from \"@pnp/sp\" ; sp . web . relatedItems . getRelatedItems ( \"Documents\" , 1 ). then (( result : RelatedItem []) => { console . log ( result ); }); getPageOneRelatedItems \u00b6 Expects the named library to exist within the contextual web. import { sp , RelatedItem } from \"@pnp/sp\" ; sp . web . relatedItems . getPageOneRelatedItems ( \"Documents\" , 1 ). then (( result : RelatedItem []) => { console . log ( result ); }); addSingleLink \u00b6 import { sp } from \"@pnp/sp\" ; sp . web . relatedItems . addSingleLink ( \"RelatedItemsList1\" , 2 , \"https://site.sharepoint.com/sites/dev/subsite\" , \"RelatedItemsList2\" , 1 , \"https://site.sharepoint.com/sites/dev\" ). then ( _ => { // ... return is void }); sp . web . relatedItems . addSingleLink ( \"RelatedItemsList1\" , 2 , \"https://site.sharepoint.com/sites/dev/subsite\" , \"RelatedItemsList2\" , 1 , \"https://site.sharepoint.com/sites/dev\" , true ). then ( _ => { // ... return is void }); addSingleLinkToUrl \u00b6 Adds a related item link from an item specified by list name and item id, to an item specified by url import { sp } from \"@pnp/sp\" ; sp . web . relatedItems . addSingleLinkToUrl ( \"RelatedItemsList1\" , 2 , \"https://site.sharepoint.com/sites/dev/subsite/Documents/test.txt\" ). then ( _ => { // ... return is void }); sp . web . relatedItems . addSingleLinkToUrl ( \"RelatedItemsList1\" , 2 , \"https://site.sharepoint.com/sites/dev/subsite/Documents/test.txt\" , true ). then ( _ => { // ... return is void }); addSingleLinkFromUrl \u00b6 Adds a related item link from an item specified by url, to an item specified by list name and item id import { sp } from \"@pnp/sp\" ; sp . web . relatedItems . addSingleLinkFromUrl ( \"https://site.sharepoint.com/sites/dev/subsite/Documents/test.txt\" , \"RelatedItemsList1\" , 2 ). then ( _ => { // ... return is void }); sp . web . relatedItems . addSingleLinkFromUrl ( \"https://site.sharepoint.com/sites/dev/subsite/Documents/test.txt\" , \"RelatedItemsList1\" , 2 , true ). then ( _ => { // ... return is void }); deleteSingleLink \u00b6 import { sp } from \"@pnp/sp\" ; sp . web . relatedItems . deleteSingleLink ( \"RelatedItemsList1\" , 2 , \"https://site.sharepoint.com/sites/dev/subsite\" , \"RelatedItemsList2\" , 1 , \"https://site.sharepoint.com/sites/dev\" ). then ( _ => { // ... return is void }); sp . web . relatedItems . deleteSingleLink ( \"RelatedItemsList1\" , 2 , \"https://site.sharepoint.com/sites/dev/subsite\" , \"RelatedItemsList2\" , 1 , \"https://site.sharepoint.com/sites/dev\" , true ). then ( _ => { // ... return is void });","title":"Related Items"},{"location":"sp/docs/related-items/#pnpsprelateditems","text":"Related items are used in Task and Workflow lists (as well as others) to track items that have relationships similar to database relationships. All methods chain off the Web's relatedItems property as shown below:","title":"@pnp/sp/relateditems"},{"location":"sp/docs/related-items/#getrelateditems","text":"Expects the named library to exist within the contextual web. import { sp , RelatedItem } from \"@pnp/sp\" ; sp . web . relatedItems . getRelatedItems ( \"Documents\" , 1 ). then (( result : RelatedItem []) => { console . log ( result ); });","title":"getRelatedItems"},{"location":"sp/docs/related-items/#getpageonerelateditems","text":"Expects the named library to exist within the contextual web. import { sp , RelatedItem } from \"@pnp/sp\" ; sp . web . relatedItems . getPageOneRelatedItems ( \"Documents\" , 1 ). then (( result : RelatedItem []) => { console . log ( result ); });","title":"getPageOneRelatedItems"},{"location":"sp/docs/related-items/#addsinglelink","text":"import { sp } from \"@pnp/sp\" ; sp . web . relatedItems . addSingleLink ( \"RelatedItemsList1\" , 2 , \"https://site.sharepoint.com/sites/dev/subsite\" , \"RelatedItemsList2\" , 1 , \"https://site.sharepoint.com/sites/dev\" ). then ( _ => { // ... return is void }); sp . web . relatedItems . addSingleLink ( \"RelatedItemsList1\" , 2 , \"https://site.sharepoint.com/sites/dev/subsite\" , \"RelatedItemsList2\" , 1 , \"https://site.sharepoint.com/sites/dev\" , true ). then ( _ => { // ... return is void });","title":"addSingleLink"},{"location":"sp/docs/related-items/#addsinglelinktourl","text":"Adds a related item link from an item specified by list name and item id, to an item specified by url import { sp } from \"@pnp/sp\" ; sp . web . relatedItems . addSingleLinkToUrl ( \"RelatedItemsList1\" , 2 , \"https://site.sharepoint.com/sites/dev/subsite/Documents/test.txt\" ). then ( _ => { // ... return is void }); sp . web . relatedItems . addSingleLinkToUrl ( \"RelatedItemsList1\" , 2 , \"https://site.sharepoint.com/sites/dev/subsite/Documents/test.txt\" , true ). then ( _ => { // ... return is void });","title":"addSingleLinkToUrl"},{"location":"sp/docs/related-items/#addsinglelinkfromurl","text":"Adds a related item link from an item specified by url, to an item specified by list name and item id import { sp } from \"@pnp/sp\" ; sp . web . relatedItems . addSingleLinkFromUrl ( \"https://site.sharepoint.com/sites/dev/subsite/Documents/test.txt\" , \"RelatedItemsList1\" , 2 ). then ( _ => { // ... return is void }); sp . web . relatedItems . addSingleLinkFromUrl ( \"https://site.sharepoint.com/sites/dev/subsite/Documents/test.txt\" , \"RelatedItemsList1\" , 2 , true ). then ( _ => { // ... return is void });","title":"addSingleLinkFromUrl"},{"location":"sp/docs/related-items/#deletesinglelink","text":"import { sp } from \"@pnp/sp\" ; sp . web . relatedItems . deleteSingleLink ( \"RelatedItemsList1\" , 2 , \"https://site.sharepoint.com/sites/dev/subsite\" , \"RelatedItemsList2\" , 1 , \"https://site.sharepoint.com/sites/dev\" ). then ( _ => { // ... return is void }); sp . web . relatedItems . deleteSingleLink ( \"RelatedItemsList1\" , 2 , \"https://site.sharepoint.com/sites/dev/subsite\" , \"RelatedItemsList2\" , 1 , \"https://site.sharepoint.com/sites/dev\" , true ). then ( _ => { // ... return is void });","title":"deleteSingleLink"},{"location":"sp/docs/search/","text":"@pnp/sp/search \u00b6 Using search you can access content throughout your organization in a secure and consistent manner. The library provides support for searching and search suggest - as well as some interfaces and helper classes to make building your queries and processing responses easier. Search \u00b6 Search is accessed directly from the root sp object and can take either a string representing the query text, a plain object matching the SearchQuery interface, or a SearchQueryBuilder instance. The first two are shown below. import { sp , SearchQuery , SearchResults } from \"@pnp/sp\" ; // text search using SharePoint default values for other parameters sp . search ( \"test\" ). then (( r : SearchResults ) => { console . log ( r . ElapsedTime ); console . log ( r . RowCount ); console . log ( r . PrimarySearchResults ); }); // define a search query object matching the SearchQuery interface sp . search ( < SearchQuery > { Querytext : \"test\" , RowLimit : 10 , EnableInterleaving : true , }). then (( r : SearchResults ) => { console . log ( r . ElapsedTime ); console . log ( r . RowCount ); console . log ( r . PrimarySearchResults ); }); Search Result Caching \u00b6 Added in 1.1.5 As of version 1.1.5 you can also use the searchWithCaching method to enable cache support for your search results this option works with any of the options for providing a query, just replace \"search\" with \"searchWithCaching\" in your method chain and gain all the benefits of caching. The second parameter is optional and allows you to specify the cache options import { sp , SearchQuery , SearchResults , SearchQueryBuilder } from \"@pnp/sp\" ; sp . searchWithCaching ( < SearchQuery > { Querytext : \"test\" , RowLimit : 10 , EnableInterleaving : true , }). then (( r : SearchResults ) => { console . log ( r . ElapsedTime ); console . log ( r . RowCount ); console . log ( r . PrimarySearchResults ); }); const builder = SearchQueryBuilder (). text ( \"test\" ). rowLimit ( 3 ); // supply a search query builder and caching options sp . searchWithCaching ( builder , { key : \"mykey\" , expiration : dateAdd ( new Date (), \"month\" , 1 ) }). then ( r2 => { console . log ( r2 . TotalRows ); }); Paging with SearchResults.getPage \u00b6 Paging is controlled by a start row and page size parameter. You can specify both arguments in your initial query however you can use the getPage method to jump to any page. The second parameter page size is optional and will use the previous RowLimit or default to 10. import { sp , SearchQueryBuilder , SearchResults } from \"@pnp/sp\" ; // this will hold our current results let currentResults : SearchResults = null ; let page = 1 ; // triggered on page load through some means function onStart() { // construct our query that will be throughout the paging process, likely from user input const q = SearchQueryBuilder . create ( \"test\" ). rowLimit ( 5 ); sp . search ( q ). then (( r : SearchResults ) => { currentResults = r ; // update the current results page = 1 ; // reset if needed // update UI with data... }); } // triggered by an event function next() { currentResults . getPage ( ++ page ). then (( r : SearchResults ) => { currentResults = r ; // update the current results // update UI with data... }); } // triggered by an event function prev() { currentResults . getPage ( -- page ). then (( r : SearchResults ) => { currentResults = r ; // update the current results // update UI with data... }); } SearchQueryBuilder \u00b6 The SearchQueryBuilder allows you to build your queries in a fluent manner. It also accepts constructor arguments for query text and a base query plain object, should you have a shared configuration for queries in an application you can define them once. The methods and properties match those on the SearchQuery interface. Boolean properties add the flag to the query while methods require that you supply one or more arguments. Also arguments supplied later in the chain will overwrite previous values. import { SearchQueryBuilder } from \"@pnp/sp\" ; // basic usage let q = SearchQueryBuilder (). text ( \"test\" ). rowLimit ( 4 ). enablePhonetic ; sp . search ( q ). then ( h => { /* ... */ }); // provide a default query text in the create() let q2 = SearchQueryBuilder ( \"text\" ). rowLimit ( 4 ). enablePhonetic ; sp . search ( q2 ). then ( h => { /* ... */ }); // provide query text and a template // shared settings across queries const appSearchSettings : SearchQuery = { EnablePhonetic : true , HiddenConstraints : \"reports\" }; let q3 = SearchQueryBuilder ( \"test\" , appSearchSettings ). enableQueryRules ; let q4 = SearchQueryBuilder ( \"financial data\" , appSearchSettings ). enableSorting . enableStemming ; sp . search ( q3 ). then ( h => { /* ... */ }); sp . search ( q4 ). then ( h => { /* ... */ }); Search Suggest \u00b6 Search suggest works in much the same way as search, except against the suggest end point. It takes a string or a plain object that matches SearchSuggestQuery. import { sp , SearchSuggestQuery , SearchSuggestResult } from \"@pnp/sp\" ; sp . searchSuggest ( \"test\" ). then (( r : SearchSuggestResult ) => { console . log ( r ); }); sp . searchSuggest ( < SearchSuggestQuery > { querytext : \"test\" , count : 5 , }). then (( r : SearchSuggestResult ) => { console . log ( r ); });","title":"Search"},{"location":"sp/docs/search/#pnpspsearch","text":"Using search you can access content throughout your organization in a secure and consistent manner. The library provides support for searching and search suggest - as well as some interfaces and helper classes to make building your queries and processing responses easier.","title":"@pnp/sp/search"},{"location":"sp/docs/search/#search","text":"Search is accessed directly from the root sp object and can take either a string representing the query text, a plain object matching the SearchQuery interface, or a SearchQueryBuilder instance. The first two are shown below. import { sp , SearchQuery , SearchResults } from \"@pnp/sp\" ; // text search using SharePoint default values for other parameters sp . search ( \"test\" ). then (( r : SearchResults ) => { console . log ( r . ElapsedTime ); console . log ( r . RowCount ); console . log ( r . PrimarySearchResults ); }); // define a search query object matching the SearchQuery interface sp . search ( < SearchQuery > { Querytext : \"test\" , RowLimit : 10 , EnableInterleaving : true , }). then (( r : SearchResults ) => { console . log ( r . ElapsedTime ); console . log ( r . RowCount ); console . log ( r . PrimarySearchResults ); });","title":"Search"},{"location":"sp/docs/search/#search-result-caching","text":"Added in 1.1.5 As of version 1.1.5 you can also use the searchWithCaching method to enable cache support for your search results this option works with any of the options for providing a query, just replace \"search\" with \"searchWithCaching\" in your method chain and gain all the benefits of caching. The second parameter is optional and allows you to specify the cache options import { sp , SearchQuery , SearchResults , SearchQueryBuilder } from \"@pnp/sp\" ; sp . searchWithCaching ( < SearchQuery > { Querytext : \"test\" , RowLimit : 10 , EnableInterleaving : true , }). then (( r : SearchResults ) => { console . log ( r . ElapsedTime ); console . log ( r . RowCount ); console . log ( r . PrimarySearchResults ); }); const builder = SearchQueryBuilder (). text ( \"test\" ). rowLimit ( 3 ); // supply a search query builder and caching options sp . searchWithCaching ( builder , { key : \"mykey\" , expiration : dateAdd ( new Date (), \"month\" , 1 ) }). then ( r2 => { console . log ( r2 . TotalRows ); });","title":"Search Result Caching"},{"location":"sp/docs/search/#paging-with-searchresultsgetpage","text":"Paging is controlled by a start row and page size parameter. You can specify both arguments in your initial query however you can use the getPage method to jump to any page. The second parameter page size is optional and will use the previous RowLimit or default to 10. import { sp , SearchQueryBuilder , SearchResults } from \"@pnp/sp\" ; // this will hold our current results let currentResults : SearchResults = null ; let page = 1 ; // triggered on page load through some means function onStart() { // construct our query that will be throughout the paging process, likely from user input const q = SearchQueryBuilder . create ( \"test\" ). rowLimit ( 5 ); sp . search ( q ). then (( r : SearchResults ) => { currentResults = r ; // update the current results page = 1 ; // reset if needed // update UI with data... }); } // triggered by an event function next() { currentResults . getPage ( ++ page ). then (( r : SearchResults ) => { currentResults = r ; // update the current results // update UI with data... }); } // triggered by an event function prev() { currentResults . getPage ( -- page ). then (( r : SearchResults ) => { currentResults = r ; // update the current results // update UI with data... }); }","title":"Paging with SearchResults.getPage"},{"location":"sp/docs/search/#searchquerybuilder","text":"The SearchQueryBuilder allows you to build your queries in a fluent manner. It also accepts constructor arguments for query text and a base query plain object, should you have a shared configuration for queries in an application you can define them once. The methods and properties match those on the SearchQuery interface. Boolean properties add the flag to the query while methods require that you supply one or more arguments. Also arguments supplied later in the chain will overwrite previous values. import { SearchQueryBuilder } from \"@pnp/sp\" ; // basic usage let q = SearchQueryBuilder (). text ( \"test\" ). rowLimit ( 4 ). enablePhonetic ; sp . search ( q ). then ( h => { /* ... */ }); // provide a default query text in the create() let q2 = SearchQueryBuilder ( \"text\" ). rowLimit ( 4 ). enablePhonetic ; sp . search ( q2 ). then ( h => { /* ... */ }); // provide query text and a template // shared settings across queries const appSearchSettings : SearchQuery = { EnablePhonetic : true , HiddenConstraints : \"reports\" }; let q3 = SearchQueryBuilder ( \"test\" , appSearchSettings ). enableQueryRules ; let q4 = SearchQueryBuilder ( \"financial data\" , appSearchSettings ). enableSorting . enableStemming ; sp . search ( q3 ). then ( h => { /* ... */ }); sp . search ( q4 ). then ( h => { /* ... */ });","title":"SearchQueryBuilder"},{"location":"sp/docs/search/#search-suggest","text":"Search suggest works in much the same way as search, except against the suggest end point. It takes a string or a plain object that matches SearchSuggestQuery. import { sp , SearchSuggestQuery , SearchSuggestResult } from \"@pnp/sp\" ; sp . searchSuggest ( \"test\" ). then (( r : SearchSuggestResult ) => { console . log ( r ); }); sp . searchSuggest ( < SearchSuggestQuery > { querytext : \"test\" , count : 5 , }). then (( r : SearchSuggestResult ) => { console . log ( r ); });","title":"Search Suggest"},{"location":"sp/docs/sharing/","text":"@pnp/sp/sharing \u00b6 Note: This API is still considered \"beta\" meaning it may change and some behaviors may differ across tenants by version. It is also supported only in SharePoint Online. One of the newer abilities in SharePoint is the ability to share webs, files, or folders with both internal and external folks. It is important to remember that these settings are managed at the tenant level and override anything you may supply as an argument to these methods. If you receive an InvalidOperationException when using these methods please check your tenant sharing settings to ensure sharing is not blocked before submitting an issue. getShareLink \u00b6 Applies to: Item, Folder, File Creates a sharing link for the given resource with an optional expiration. import { sp , SharingLinkKind , ShareLinkResponse } from \"@pnp/sp\" ; import { dateAdd } from \"@pnp/core\" ; sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/folder1\" ). getShareLink ( SharingLinkKind . AnonymousView ). then ((( result : ShareLinkResponse ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/folder1\" ). getShareLink ( SharingLinkKind . AnonymousView , dateAdd ( new Date (), \"day\" , 5 )). then (( result : ShareLinkResponse ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); shareWith \u00b6 Applies to: Item, Folder, File, Web Shares the given resource with the specified permissions (View or Edit) and optionally sends an email to the users. You can supply a single string for the loginnames parameter or an array of loginnames. The folder method takes an optional parameter \"shareEverything\" which determines if the shared permissions are pushed down to all items in the folder, even those with unique permissions. import { sp , SharingResult , SharingRole } from \"@pnp/sp\" ; sp . web . shareWith ( \"i:0#.f|membership|user@site.com\" ). then (( result : SharingResult ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); sp . web . shareWith ( \"i:0#.f|membership|user@site.com\" , SharingRole . Edit ). then (( result : SharingResult ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/folder1\" ). shareWith ( \"i:0#.f|membership|user@site.com\" ). then (( result : SharingResult ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). shareWith ( \"i:0#.f|membership|user@site.com\" , SharingRole . Edit , true , true ). then (( result : SharingResult ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); sp . web . getFileByServerRelativeUrl ( \"/sites/dev/Shared Documents/test.txt\" ). shareWith ( \"i:0#.f|membership|user@site.com\" ). then (( result : SharingResult ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); sp . web . getFileByServerRelativeUrl ( \"/sites/dev/Shared Documents/test.txt\" ). shareWith ( \"i:0#.f|membership|user@site.com\" , SharingRole . Edit ). then (( result : SharingResult ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); shareObject & shareObjectRaw \u00b6 Applies to: Web Allows you to share any shareable object in a web by providing the appropriate parameters. These two methods differ in that shareObject will try and fix up your query based on the supplied parameters where shareObjectRaw will send your supplied json object directly to the server. The later method is provided for the greatest amount of flexibility. import { sp , SharingResult , SharingRole } from \"@pnp/sp\" ; sp . web . shareObject ( \"https://mysite.sharepoint.com/sites/dev/Docs/test.txt\" , \"i:0#.f|membership|user@site.com\" , SharingRole . View ). then (( result : SharingResult ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); sp . web . shareObjectRaw ({ url : \"https://mysite.sharepoint.com/sites/dev/Docs/test.txt\" , peoplePickerInput : [{ Key : \"i:0#.f|membership|user@site.com\" }], roleValue : \"role: 1973741327\" , groupId : 0 , propagateAcl : false , sendEmail : true , includeAnonymousLinkInEmail : false , emailSubject : \"subject\" , emailBody : \"body\" , useSimplifiedRoles : true , }); unshareObject \u00b6 Applies to: Web import { sp , SharingResult } from \"@pnp/sp\" ; sp . web . unshareObject ( \"https://mysite.sharepoint.com/sites/dev/Docs/test.txt\" ). then (( result : SharingResult ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); checkSharingPermissions \u00b6 Applies to: Item, Folder, File Checks Permissions on the list of Users and returns back role the users have on the Item. import { sp , SharingEntityPermission } from \"@pnp/sp\" ; sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). checkSharingPermissions ([{ alias : \"i:0#.f|membership|user@site.com\" }]). then (( result : SharingEntityPermission []) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); getSharingInformation \u00b6 Applies to: Item, Folder, File Get Sharing Information. import { sp , SharingInformation } from \"@pnp/sp\" ; sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). getSharingInformation (). then (( result : SharingInformation ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); getObjectSharingSettings \u00b6 Applies to: Item, Folder, File Gets the sharing settings import { sp , ObjectSharingSettings } from \"@pnp/sp\" ; sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). getObjectSharingSettings (). then (( result : ObjectSharingSettings ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); unshare \u00b6 Applies to: Item, Folder, File Unshares a given resource import { sp , SharingResult } from \"@pnp/sp\" ; sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). unshare (). then (( result : SharingResult ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); deleteSharingLinkByKind \u00b6 Applies to: Item, Folder, File import { sp , SharingLinkKind , SharingResult } from \"@pnp/sp\" ; sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). deleteSharingLinkByKind ( SharingLinkKind . AnonymousEdit ). then (( result : SharingResult ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); unshareLink \u00b6 Applies to: Item, Folder, File import { sp , SharingLinkKind } from \"@pnp/sp\" ; sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). unshareLink ( SharingLinkKind . AnonymousEdit ). then ( _ => { console . log ( \"done\" ); }). catch ( e => { console . error ( e ); }); sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). unshareLink ( SharingLinkKind . AnonymousEdit , \"12345\" ). then ( _ => { console . log ( \"done\" ); }). catch ( e => { console . error ( e ); });","title":"Sharing"},{"location":"sp/docs/sharing/#pnpspsharing","text":"Note: This API is still considered \"beta\" meaning it may change and some behaviors may differ across tenants by version. It is also supported only in SharePoint Online. One of the newer abilities in SharePoint is the ability to share webs, files, or folders with both internal and external folks. It is important to remember that these settings are managed at the tenant level and override anything you may supply as an argument to these methods. If you receive an InvalidOperationException when using these methods please check your tenant sharing settings to ensure sharing is not blocked before submitting an issue.","title":"@pnp/sp/sharing"},{"location":"sp/docs/sharing/#getsharelink","text":"Applies to: Item, Folder, File Creates a sharing link for the given resource with an optional expiration. import { sp , SharingLinkKind , ShareLinkResponse } from \"@pnp/sp\" ; import { dateAdd } from \"@pnp/core\" ; sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/folder1\" ). getShareLink ( SharingLinkKind . AnonymousView ). then ((( result : ShareLinkResponse ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/folder1\" ). getShareLink ( SharingLinkKind . AnonymousView , dateAdd ( new Date (), \"day\" , 5 )). then (( result : ShareLinkResponse ) => { console . log ( result ); }). catch ( e => { console . error ( e ); });","title":"getShareLink"},{"location":"sp/docs/sharing/#sharewith","text":"Applies to: Item, Folder, File, Web Shares the given resource with the specified permissions (View or Edit) and optionally sends an email to the users. You can supply a single string for the loginnames parameter or an array of loginnames. The folder method takes an optional parameter \"shareEverything\" which determines if the shared permissions are pushed down to all items in the folder, even those with unique permissions. import { sp , SharingResult , SharingRole } from \"@pnp/sp\" ; sp . web . shareWith ( \"i:0#.f|membership|user@site.com\" ). then (( result : SharingResult ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); sp . web . shareWith ( \"i:0#.f|membership|user@site.com\" , SharingRole . Edit ). then (( result : SharingResult ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/folder1\" ). shareWith ( \"i:0#.f|membership|user@site.com\" ). then (( result : SharingResult ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). shareWith ( \"i:0#.f|membership|user@site.com\" , SharingRole . Edit , true , true ). then (( result : SharingResult ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); sp . web . getFileByServerRelativeUrl ( \"/sites/dev/Shared Documents/test.txt\" ). shareWith ( \"i:0#.f|membership|user@site.com\" ). then (( result : SharingResult ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); sp . web . getFileByServerRelativeUrl ( \"/sites/dev/Shared Documents/test.txt\" ). shareWith ( \"i:0#.f|membership|user@site.com\" , SharingRole . Edit ). then (( result : SharingResult ) => { console . log ( result ); }). catch ( e => { console . error ( e ); });","title":"shareWith"},{"location":"sp/docs/sharing/#shareobject-shareobjectraw","text":"Applies to: Web Allows you to share any shareable object in a web by providing the appropriate parameters. These two methods differ in that shareObject will try and fix up your query based on the supplied parameters where shareObjectRaw will send your supplied json object directly to the server. The later method is provided for the greatest amount of flexibility. import { sp , SharingResult , SharingRole } from \"@pnp/sp\" ; sp . web . shareObject ( \"https://mysite.sharepoint.com/sites/dev/Docs/test.txt\" , \"i:0#.f|membership|user@site.com\" , SharingRole . View ). then (( result : SharingResult ) => { console . log ( result ); }). catch ( e => { console . error ( e ); }); sp . web . shareObjectRaw ({ url : \"https://mysite.sharepoint.com/sites/dev/Docs/test.txt\" , peoplePickerInput : [{ Key : \"i:0#.f|membership|user@site.com\" }], roleValue : \"role: 1973741327\" , groupId : 0 , propagateAcl : false , sendEmail : true , includeAnonymousLinkInEmail : false , emailSubject : \"subject\" , emailBody : \"body\" , useSimplifiedRoles : true , });","title":"shareObject &amp; shareObjectRaw"},{"location":"sp/docs/sharing/#unshareobject","text":"Applies to: Web import { sp , SharingResult } from \"@pnp/sp\" ; sp . web . unshareObject ( \"https://mysite.sharepoint.com/sites/dev/Docs/test.txt\" ). then (( result : SharingResult ) => { console . log ( result ); }). catch ( e => { console . error ( e ); });","title":"unshareObject"},{"location":"sp/docs/sharing/#checksharingpermissions","text":"Applies to: Item, Folder, File Checks Permissions on the list of Users and returns back role the users have on the Item. import { sp , SharingEntityPermission } from \"@pnp/sp\" ; sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). checkSharingPermissions ([{ alias : \"i:0#.f|membership|user@site.com\" }]). then (( result : SharingEntityPermission []) => { console . log ( result ); }). catch ( e => { console . error ( e ); });","title":"checkSharingPermissions"},{"location":"sp/docs/sharing/#getsharinginformation","text":"Applies to: Item, Folder, File Get Sharing Information. import { sp , SharingInformation } from \"@pnp/sp\" ; sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). getSharingInformation (). then (( result : SharingInformation ) => { console . log ( result ); }). catch ( e => { console . error ( e ); });","title":"getSharingInformation"},{"location":"sp/docs/sharing/#getobjectsharingsettings","text":"Applies to: Item, Folder, File Gets the sharing settings import { sp , ObjectSharingSettings } from \"@pnp/sp\" ; sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). getObjectSharingSettings (). then (( result : ObjectSharingSettings ) => { console . log ( result ); }). catch ( e => { console . error ( e ); });","title":"getObjectSharingSettings"},{"location":"sp/docs/sharing/#unshare","text":"Applies to: Item, Folder, File Unshares a given resource import { sp , SharingResult } from \"@pnp/sp\" ; sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). unshare (). then (( result : SharingResult ) => { console . log ( result ); }). catch ( e => { console . error ( e ); });","title":"unshare"},{"location":"sp/docs/sharing/#deletesharinglinkbykind","text":"Applies to: Item, Folder, File import { sp , SharingLinkKind , SharingResult } from \"@pnp/sp\" ; sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). deleteSharingLinkByKind ( SharingLinkKind . AnonymousEdit ). then (( result : SharingResult ) => { console . log ( result ); }). catch ( e => { console . error ( e ); });","title":"deleteSharingLinkByKind"},{"location":"sp/docs/sharing/#unsharelink","text":"Applies to: Item, Folder, File import { sp , SharingLinkKind } from \"@pnp/sp\" ; sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). unshareLink ( SharingLinkKind . AnonymousEdit ). then ( _ => { console . log ( \"done\" ); }). catch ( e => { console . error ( e ); }); sp . web . getFolderByServerRelativeUrl ( \"/sites/dev/Shared Documents/test\" ). unshareLink ( SharingLinkKind . AnonymousEdit , \"12345\" ). then ( _ => { console . log ( \"done\" ); }). catch ( e => { console . error ( e ); });","title":"unshareLink"},{"location":"sp/docs/sitedesigns/","text":"@pnp/sp/sitedesigns \u00b6 You can create site designs to provide reusable lists, themes, layouts, pages, or custom actions so that your users can quickly build new SharePoint sites with the features they need. Check out SharePoint site design and site script overview for more information. Site Designs \u00b6 Create a new site design \u00b6 import { sp } from \"@pnp/sp\" ; // WebTemplate: 64 Team site template, 68 Communication site template const siteDesign = await sp . siteDesigns . createSiteDesign ({ SiteScriptIds : [ \"884ed56b-1aab-4653-95cf-4be0bfa5ef0a\" ], Title : \"SiteDesign001\" , WebTemplate : \"64\" , }); console . log ( siteDesign . Title ); Applying a site design to a site \u00b6 import { sp } from \"@pnp/sp\" ; // Limited to 30 actions in a site script, but runs synchronously await sp . siteDesigns . applySiteDesign ( \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" , \"https://contoso.sharepoint.com/sites/teamsite-pnpjs001\" ); // Better use the following method for 300 actions in a site script const task = await sp . web . addSiteDesignTask ( \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" ); Retrieval \u00b6 import { sp } from \"@pnp/sp\" ; // Retrieving all site designs const allSiteDesigns = await sp . siteDesigns . getSiteDesigns (); console . log ( `Total site designs: ${ allSiteDesigns . length } ` ); // Retrieving a single site design by Id const siteDesign = await sp . siteDesigns . getSiteDesignMetadata ( \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" ); console . log ( siteDesign . Title ); Update and delete \u00b6 import { sp } from \"@pnp/sp\" ; // Update const updatedSiteDesign = await sp . siteDesigns . updateSiteDesign ({ Id : \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" , Title : \"SiteDesignUpdatedTitle001\" }); // Delete await sp . siteDesigns . deleteSiteDesign ( \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" ); Setting Rights/Permissions \u00b6 import { sp } from \"@pnp/sp\" ; // Get const rights = await sp . siteDesigns . getSiteDesignRights ( \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" ); console . log ( rights . length > 0 ? rights [ 0 ]. PrincipalName : \"\" ); // Grant await sp . siteDesigns . grantSiteDesignRights ( \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" , [ \"user@contoso.onmicrosoft.com\" ]); // Revoke await sp . siteDesigns . revokeSiteDesignRights ( \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" , [ \"user@contoso.onmicrosoft.com\" ]); // Reset all view rights const rights = await sp . siteDesigns . getSiteDesignRights ( \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" ); await sp . siteDesigns . revokeSiteDesignRights ( \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" , rights . map ( u => u . PrincipalName )); Get a history of site designs that have run on a web \u00b6 import { sp } from \"@pnp/sp\" ; const runs = await sp . web . getSiteDesignRuns (); const runs2 = await sp . siteDesigns . getSiteDesignRun ( \"https://TENANT.sharepoint.com/sites/mysite\" ); // Get runs specific to a site design const runs3 = await sp . web . getSiteDesignRuns ( \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" ); const runs4 = await sp . siteDesigns . getSiteDesignRun ( \"https://TENANT.sharepoint.com/sites/mysite\" , \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" ); // For more information about the site script actions const runStatus = await sp . web . getSiteDesignRunStatus ( runs [ 0 ]. ID ); const runStatus2 = await sp . siteDesigns . getSiteDesignRunStatus ( \"https://TENANT.sharepoint.com/sites/mysite\" , runs [ 0 ]. ID ); Site Scripts \u00b6 Create a new site script \u00b6 import { sp } from \"@pnp/sp\" ; const sitescriptContent = { \"$schema\" : \"schema.json\" , \"actions\" : [ { \"themeName\" : \"Theme Name 123\" , \"verb\" : \"applyTheme\" , }, ], \"bindata\" : {}, \"version\" : 1 , }; const siteScript = await sp . siteScripts . createSiteScript ( \"Title\" , \"description\" , sitescriptContent ); console . log ( siteScript . Title ); Retrieval \u00b6 import { sp } from \"@pnp/sp\" ; // Retrieving all site scripts const allSiteScripts = await sp . siteScripts . getSiteScripts (); console . log ( allSiteScripts . length > 0 ? allSiteScripts [ 0 ]. Title : \"\" ); // Retrieving a single site script by Id const siteScript = await sp . siteScripts . getSiteScriptMetadata ( \"884ed56b-1aab-4653-95cf-4be0bfa5ef0a\" ); console . log ( siteScript . Title ); Update and delete \u00b6 import { sp } from \"@pnp/sp\" ; // Update const updatedSiteScript = await sp . siteScripts . updateSiteScript ({ Id : \"884ed56b-1aab-4653-95cf-4be0bfa5ef0a\" , Title : \"New Title\" }); console . log ( updatedSiteScript . Title ); // Delete await sp . siteScripts . deleteSiteScript ( \"884ed56b-1aab-4653-95cf-4be0bfa5ef0a\" ); Get site script from a list \u00b6 import { sp } from \"@pnp/sp\" ; // Using the absolute URL of the list const ss = await sp . siteScripts . getSiteScriptFromList ( \"https://TENANT.sharepoint.com/Lists/mylist\" ); // Using the PnPjs web object to fetch the site script from a specific list const ss2 = await sp . web . lists . getByTitle ( \"mylist\" ). getSiteScript (); Get site script from a web \u00b6 import { sp } from \"@pnp/sp\" ; const extractInfo = { IncludeBranding : true , IncludeLinksToExportedItems : true , IncludeRegionalSettings : true , IncludeSiteExternalSharingCapability : true , IncludeTheme : true , IncludedLists : [ \"Lists/MyList\" ] }; const ss = await sp . siteScripts . getSiteScriptFromWeb ( \"https://TENANT.sharepoint.com/sites/mysite\" , extractInfo ); // Using the PnPjs web object to fetch the site script from a specific web const ss2 = await sp . web . getSiteScript ( extractInfo );","title":"Site Designs"},{"location":"sp/docs/sitedesigns/#pnpspsitedesigns","text":"You can create site designs to provide reusable lists, themes, layouts, pages, or custom actions so that your users can quickly build new SharePoint sites with the features they need. Check out SharePoint site design and site script overview for more information.","title":"@pnp/sp/sitedesigns"},{"location":"sp/docs/sitedesigns/#site-designs","text":"","title":"Site Designs"},{"location":"sp/docs/sitedesigns/#create-a-new-site-design","text":"import { sp } from \"@pnp/sp\" ; // WebTemplate: 64 Team site template, 68 Communication site template const siteDesign = await sp . siteDesigns . createSiteDesign ({ SiteScriptIds : [ \"884ed56b-1aab-4653-95cf-4be0bfa5ef0a\" ], Title : \"SiteDesign001\" , WebTemplate : \"64\" , }); console . log ( siteDesign . Title );","title":"Create a new site design"},{"location":"sp/docs/sitedesigns/#applying-a-site-design-to-a-site","text":"import { sp } from \"@pnp/sp\" ; // Limited to 30 actions in a site script, but runs synchronously await sp . siteDesigns . applySiteDesign ( \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" , \"https://contoso.sharepoint.com/sites/teamsite-pnpjs001\" ); // Better use the following method for 300 actions in a site script const task = await sp . web . addSiteDesignTask ( \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" );","title":"Applying a site design to a site"},{"location":"sp/docs/sitedesigns/#retrieval","text":"import { sp } from \"@pnp/sp\" ; // Retrieving all site designs const allSiteDesigns = await sp . siteDesigns . getSiteDesigns (); console . log ( `Total site designs: ${ allSiteDesigns . length } ` ); // Retrieving a single site design by Id const siteDesign = await sp . siteDesigns . getSiteDesignMetadata ( \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" ); console . log ( siteDesign . Title );","title":"Retrieval"},{"location":"sp/docs/sitedesigns/#update-and-delete","text":"import { sp } from \"@pnp/sp\" ; // Update const updatedSiteDesign = await sp . siteDesigns . updateSiteDesign ({ Id : \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" , Title : \"SiteDesignUpdatedTitle001\" }); // Delete await sp . siteDesigns . deleteSiteDesign ( \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" );","title":"Update and delete"},{"location":"sp/docs/sitedesigns/#setting-rightspermissions","text":"import { sp } from \"@pnp/sp\" ; // Get const rights = await sp . siteDesigns . getSiteDesignRights ( \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" ); console . log ( rights . length > 0 ? rights [ 0 ]. PrincipalName : \"\" ); // Grant await sp . siteDesigns . grantSiteDesignRights ( \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" , [ \"user@contoso.onmicrosoft.com\" ]); // Revoke await sp . siteDesigns . revokeSiteDesignRights ( \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" , [ \"user@contoso.onmicrosoft.com\" ]); // Reset all view rights const rights = await sp . siteDesigns . getSiteDesignRights ( \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" ); await sp . siteDesigns . revokeSiteDesignRights ( \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" , rights . map ( u => u . PrincipalName ));","title":"Setting Rights/Permissions"},{"location":"sp/docs/sitedesigns/#get-a-history-of-site-designs-that-have-run-on-a-web","text":"import { sp } from \"@pnp/sp\" ; const runs = await sp . web . getSiteDesignRuns (); const runs2 = await sp . siteDesigns . getSiteDesignRun ( \"https://TENANT.sharepoint.com/sites/mysite\" ); // Get runs specific to a site design const runs3 = await sp . web . getSiteDesignRuns ( \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" ); const runs4 = await sp . siteDesigns . getSiteDesignRun ( \"https://TENANT.sharepoint.com/sites/mysite\" , \"75b9d8fe-4381-45d9-88c6-b03f483ae6a8\" ); // For more information about the site script actions const runStatus = await sp . web . getSiteDesignRunStatus ( runs [ 0 ]. ID ); const runStatus2 = await sp . siteDesigns . getSiteDesignRunStatus ( \"https://TENANT.sharepoint.com/sites/mysite\" , runs [ 0 ]. ID );","title":"Get a history of site designs that have run on a web"},{"location":"sp/docs/sitedesigns/#site-scripts","text":"","title":"Site Scripts"},{"location":"sp/docs/sitedesigns/#create-a-new-site-script","text":"import { sp } from \"@pnp/sp\" ; const sitescriptContent = { \"$schema\" : \"schema.json\" , \"actions\" : [ { \"themeName\" : \"Theme Name 123\" , \"verb\" : \"applyTheme\" , }, ], \"bindata\" : {}, \"version\" : 1 , }; const siteScript = await sp . siteScripts . createSiteScript ( \"Title\" , \"description\" , sitescriptContent ); console . log ( siteScript . Title );","title":"Create a new site script"},{"location":"sp/docs/sitedesigns/#retrieval_1","text":"import { sp } from \"@pnp/sp\" ; // Retrieving all site scripts const allSiteScripts = await sp . siteScripts . getSiteScripts (); console . log ( allSiteScripts . length > 0 ? allSiteScripts [ 0 ]. Title : \"\" ); // Retrieving a single site script by Id const siteScript = await sp . siteScripts . getSiteScriptMetadata ( \"884ed56b-1aab-4653-95cf-4be0bfa5ef0a\" ); console . log ( siteScript . Title );","title":"Retrieval"},{"location":"sp/docs/sitedesigns/#update-and-delete_1","text":"import { sp } from \"@pnp/sp\" ; // Update const updatedSiteScript = await sp . siteScripts . updateSiteScript ({ Id : \"884ed56b-1aab-4653-95cf-4be0bfa5ef0a\" , Title : \"New Title\" }); console . log ( updatedSiteScript . Title ); // Delete await sp . siteScripts . deleteSiteScript ( \"884ed56b-1aab-4653-95cf-4be0bfa5ef0a\" );","title":"Update and delete"},{"location":"sp/docs/sitedesigns/#get-site-script-from-a-list","text":"import { sp } from \"@pnp/sp\" ; // Using the absolute URL of the list const ss = await sp . siteScripts . getSiteScriptFromList ( \"https://TENANT.sharepoint.com/Lists/mylist\" ); // Using the PnPjs web object to fetch the site script from a specific list const ss2 = await sp . web . lists . getByTitle ( \"mylist\" ). getSiteScript ();","title":"Get site script from a list"},{"location":"sp/docs/sitedesigns/#get-site-script-from-a-web","text":"import { sp } from \"@pnp/sp\" ; const extractInfo = { IncludeBranding : true , IncludeLinksToExportedItems : true , IncludeRegionalSettings : true , IncludeSiteExternalSharingCapability : true , IncludeTheme : true , IncludedLists : [ \"Lists/MyList\" ] }; const ss = await sp . siteScripts . getSiteScriptFromWeb ( \"https://TENANT.sharepoint.com/sites/mysite\" , extractInfo ); // Using the PnPjs web object to fetch the site script from a specific web const ss2 = await sp . web . getSiteScript ( extractInfo );","title":"Get site script from a web"},{"location":"sp/docs/sites/","text":"@pnp/sp/site - Site properties \u00b6 Site collection are one of the fundamental entry points while working with SharePoint. Sites serve as container for webs, lists, features and other entity types. Get context information for the current site collection \u00b6 Using the library, you can get the context information of the current site collection import { sp } from \"@pnp/sp\" ; sp . site . getContextInfo (). then ( d => { console . log ( d . FormDigestValue ); }); Get document libraries of a web \u00b6 Using the library, you can get a list of the document libraries present in the a given web. Note: Works only in SharePoint online import { sp } from \"@pnp/sp\" ; sp . site . getDocumentLibraries ( \"https://tenant.sharepoint.com/sites/test/subsite\" ). then (( d : DocumentLibraryInformation []) => { // iterate over the array of doc lib }); Open Web By Id \u00b6 Because this method is a POST request you can chain off it directly. You will get back the full web properties in the data property of the return object. You can also chain directly off the returned Web instance on the web property. sp . site . openWebById ( \"111ca453-90f5-482e-a381-cee1ff383c9e\" ). then ( w => { //we got all the data from the web as well console . log ( w . data ); // we can chain w . web . select ( \"Title\" ). get (). then ( w2 => { // ... }); }); Get site collection url from page \u00b6 Using the library, you can get the site collection url by providing a page url import { sp } from \"@pnp/sp\" ; sp . site . getWebUrlFromPageUrl ( \"https://tenant.sharepoint.com/sites/test/Pages/test.aspx\" ). then ( d => { console . log ( d ); }); Join a hub site \u00b6 Added in 1.2.4 Note: Works only in SharePoint online Join the current site collection to a hub site collection import { sp , Site } from \"@pnp/sp\" ; var site = new Site ( \"https://tenant.sharepoint.com/sites/HubSite/\" ); var hubSiteID = \"\" ; site . select ( \"ID\" ). get (). then ( d => { // get ID of the hub site collection hubSiteID = d . Id ; // associate the current site collection the hub site collection sp . site . joinHubSite ( hubSiteID ). then ( d => { console . log ( d ); }); }); Disassociate the current site collection from a hub site collection \u00b6 Added in 1.2.4 Note: Works only in SharePoint online import { sp } from \"@pnp/sp\" ; sp . site . joinHubSite ( \"00000000-0000-0000-0000-000000000000\" ). then ( d => { console . log ( d ); }); Register a hub site \u00b6 Added in 1.2.4 Note: Works only in SharePoint online Registers the current site collection as a hub site collection import { sp } from \"@pnp/sp\" ; sp . site . registerHubSite (). then ( d => { console . log ( d ); }); Un-Register a hub site \u00b6 Added in 1.2.4 Note: Works only in SharePoint online Un-Registers the current site collection as a hub site collection import { sp } from \"@pnp/sp\" ; sp . site . unRegisterHubSite (). then ( d => { console . log ( d ); }); Create a modern communication site \u00b6 Added in 1.2.6 Note: Works only in SharePoint online Creates a modern communication site. Property Type Required Description Title string yes The title of the site to create. lcid number yes The default language to use for the site. shareByEmailEnabled boolean yes If set to true, it will enable sharing files via Email. By default it is set to false url string yes The fully qualified URL (e.g. https://yourtenant.sharepoint.com/sites/mysitecollection) of the site. description string no The description of the communication site. classification string no The Site classification to use. For instance 'Contoso Classified'. See https://www.youtube.com/watch?v=E-8Z2ggHcS0 for more information siteDesignId string no The Guid of the site design to be used. You can use the below default OOTB GUIDs: Topic: null Showcase: 6142d2a0-63a5-4ba0-aede-d9fefca2c767 Blank: f6cc5403-0d63-442e-96c0-285923709ffc hubSiteId string no The Guid of the already existing Hub site owner string no Required when using app-only context. Owner principal name e.g. user@tenant.onmicrosoft.com import { sp } from \"@pnp/sp\" ; const s = await sp . site . createCommunicationSite ( \"Title\" , 1033 , true , \"https://tenant.sharepoint.com/sites/commSite\" , \"Description\" , \"HBI\" , \"f6cc5403-0d63-442e-96c0-285923709ffc\" , \"a00ec589-ea9f-4dba-a34e-67e78d41e509\" , \"user@TENANT.onmicrosoft.com\" ); Create a modern team site \u00b6 Added in 1.2.6 Note: Works only in SharePoint online. It wont work with App only tokens Creates a modern team site backed by O365 group. Property Type Required Description displayName string yes The title/displayName of the site to be created. alias string yes Alias of the underlying Office 365 Group. isPublic boolean yes Defines whether the Office 365 Group will be public (default), or private. lcid number yes The language to use for the site. If not specified will default to English (1033). description string no The description of the modern team site. classification string no The Site classification to use. For instance 'Contoso Classified'. See https://www.youtube.com/watch?v=E-8Z2ggHcS0 for more information owners string array (string[]) no The Owners of the site to be created hubSiteId string no The Guid of the already existing Hub site import { sp } from \"@pnp/sp\" ; sp . site . createModernTeamSite ( \"displayName\" , \"alias\" , true , 1033 , \"description\" , \"HBI\" , [ \"user1@tenant.onmicrosoft.com\" , \"user2@tenant.onmicrosoft.com\" , \"user3@tenant.onmicrosoft.com\" ], \"a00ec589-ea9f-4dba-a34e-67e78d41e509\" ) . then ( d => { console . log ( d ); }); Delete a site collection \u00b6 import { sp } from \"@pnp/sp\" ; // Delete the current site await sp . site . delete (); // Specify which site to delete const siteUrl = \"https://tenant.sharepoint.com/sites/tstpnpsitecoldelete5\" ; const site2 = new Site ( siteUrl ); await site2 . delete ();","title":"Sites"},{"location":"sp/docs/sites/#pnpspsite-site-properties","text":"Site collection are one of the fundamental entry points while working with SharePoint. Sites serve as container for webs, lists, features and other entity types.","title":"@pnp/sp/site - Site properties"},{"location":"sp/docs/sites/#get-context-information-for-the-current-site-collection","text":"Using the library, you can get the context information of the current site collection import { sp } from \"@pnp/sp\" ; sp . site . getContextInfo (). then ( d => { console . log ( d . FormDigestValue ); });","title":"Get context information for the current site collection"},{"location":"sp/docs/sites/#get-document-libraries-of-a-web","text":"Using the library, you can get a list of the document libraries present in the a given web. Note: Works only in SharePoint online import { sp } from \"@pnp/sp\" ; sp . site . getDocumentLibraries ( \"https://tenant.sharepoint.com/sites/test/subsite\" ). then (( d : DocumentLibraryInformation []) => { // iterate over the array of doc lib });","title":"Get document libraries of a web"},{"location":"sp/docs/sites/#open-web-by-id","text":"Because this method is a POST request you can chain off it directly. You will get back the full web properties in the data property of the return object. You can also chain directly off the returned Web instance on the web property. sp . site . openWebById ( \"111ca453-90f5-482e-a381-cee1ff383c9e\" ). then ( w => { //we got all the data from the web as well console . log ( w . data ); // we can chain w . web . select ( \"Title\" ). get (). then ( w2 => { // ... }); });","title":"Open Web By Id"},{"location":"sp/docs/sites/#get-site-collection-url-from-page","text":"Using the library, you can get the site collection url by providing a page url import { sp } from \"@pnp/sp\" ; sp . site . getWebUrlFromPageUrl ( \"https://tenant.sharepoint.com/sites/test/Pages/test.aspx\" ). then ( d => { console . log ( d ); });","title":"Get site collection url from page"},{"location":"sp/docs/sites/#join-a-hub-site","text":"Added in 1.2.4 Note: Works only in SharePoint online Join the current site collection to a hub site collection import { sp , Site } from \"@pnp/sp\" ; var site = new Site ( \"https://tenant.sharepoint.com/sites/HubSite/\" ); var hubSiteID = \"\" ; site . select ( \"ID\" ). get (). then ( d => { // get ID of the hub site collection hubSiteID = d . Id ; // associate the current site collection the hub site collection sp . site . joinHubSite ( hubSiteID ). then ( d => { console . log ( d ); }); });","title":"Join a hub site"},{"location":"sp/docs/sites/#disassociate-the-current-site-collection-from-a-hub-site-collection","text":"Added in 1.2.4 Note: Works only in SharePoint online import { sp } from \"@pnp/sp\" ; sp . site . joinHubSite ( \"00000000-0000-0000-0000-000000000000\" ). then ( d => { console . log ( d ); });","title":"Disassociate the current site collection from a hub site collection"},{"location":"sp/docs/sites/#register-a-hub-site","text":"Added in 1.2.4 Note: Works only in SharePoint online Registers the current site collection as a hub site collection import { sp } from \"@pnp/sp\" ; sp . site . registerHubSite (). then ( d => { console . log ( d ); });","title":"Register a hub site"},{"location":"sp/docs/sites/#un-register-a-hub-site","text":"Added in 1.2.4 Note: Works only in SharePoint online Un-Registers the current site collection as a hub site collection import { sp } from \"@pnp/sp\" ; sp . site . unRegisterHubSite (). then ( d => { console . log ( d ); });","title":"Un-Register a hub site"},{"location":"sp/docs/sites/#create-a-modern-communication-site","text":"Added in 1.2.6 Note: Works only in SharePoint online Creates a modern communication site. Property Type Required Description Title string yes The title of the site to create. lcid number yes The default language to use for the site. shareByEmailEnabled boolean yes If set to true, it will enable sharing files via Email. By default it is set to false url string yes The fully qualified URL (e.g. https://yourtenant.sharepoint.com/sites/mysitecollection) of the site. description string no The description of the communication site. classification string no The Site classification to use. For instance 'Contoso Classified'. See https://www.youtube.com/watch?v=E-8Z2ggHcS0 for more information siteDesignId string no The Guid of the site design to be used. You can use the below default OOTB GUIDs: Topic: null Showcase: 6142d2a0-63a5-4ba0-aede-d9fefca2c767 Blank: f6cc5403-0d63-442e-96c0-285923709ffc hubSiteId string no The Guid of the already existing Hub site owner string no Required when using app-only context. Owner principal name e.g. user@tenant.onmicrosoft.com import { sp } from \"@pnp/sp\" ; const s = await sp . site . createCommunicationSite ( \"Title\" , 1033 , true , \"https://tenant.sharepoint.com/sites/commSite\" , \"Description\" , \"HBI\" , \"f6cc5403-0d63-442e-96c0-285923709ffc\" , \"a00ec589-ea9f-4dba-a34e-67e78d41e509\" , \"user@TENANT.onmicrosoft.com\" );","title":"Create a modern communication site"},{"location":"sp/docs/sites/#create-a-modern-team-site","text":"Added in 1.2.6 Note: Works only in SharePoint online. It wont work with App only tokens Creates a modern team site backed by O365 group. Property Type Required Description displayName string yes The title/displayName of the site to be created. alias string yes Alias of the underlying Office 365 Group. isPublic boolean yes Defines whether the Office 365 Group will be public (default), or private. lcid number yes The language to use for the site. If not specified will default to English (1033). description string no The description of the modern team site. classification string no The Site classification to use. For instance 'Contoso Classified'. See https://www.youtube.com/watch?v=E-8Z2ggHcS0 for more information owners string array (string[]) no The Owners of the site to be created hubSiteId string no The Guid of the already existing Hub site import { sp } from \"@pnp/sp\" ; sp . site . createModernTeamSite ( \"displayName\" , \"alias\" , true , 1033 , \"description\" , \"HBI\" , [ \"user1@tenant.onmicrosoft.com\" , \"user2@tenant.onmicrosoft.com\" , \"user3@tenant.onmicrosoft.com\" ], \"a00ec589-ea9f-4dba-a34e-67e78d41e509\" ) . then ( d => { console . log ( d ); });","title":"Create a modern team site"},{"location":"sp/docs/sites/#delete-a-site-collection","text":"import { sp } from \"@pnp/sp\" ; // Delete the current site await sp . site . delete (); // Specify which site to delete const siteUrl = \"https://tenant.sharepoint.com/sites/tstpnpsitecoldelete5\" ; const site2 = new Site ( siteUrl ); await site2 . delete ();","title":"Delete a site collection"},{"location":"sp/docs/social/","text":"@pnp/sp/social \u00b6 The social API allows you to track followed sites, people, and docs. Note, many of these methods only work with the context of a logged in user, and not with app-only permissions. getFollowedSitesUri \u00b6 Gets a URI to a site that lists the current user's followed sites. import { sp } from \"@pnp/sp\" ; const uri = await sp . social . getFollowedSitesUri (); getFollowedDocumentsUri \u00b6 Gets a URI to a site that lists the current user's followed documents. import { sp } from \"@pnp/sp\" ; const uri = await sp . social . getFollowedDocumentsUri (); follow \u00b6 Makes the current user start following a user, document, site, or tag import { sp , SocialActorType } from \"@pnp/sp\" ; // follow a site const r1 = await sp . social . follow ({ ActorType : SocialActorType.Site , ContentUri : \"htts://tenant.sharepoint.com/sites/site\" , }); // follow a person const r2 = await sp . social . follow ({ AccountName : \"i:0#.f|membership|person@tenant.com\" , ActorType : SocialActorType.User , }); // follow a doc const r3 = await sp . social . follow ({ ActorType : SocialActorType.Document , ContentUri : \"https://tenant.sharepoint.com/sites/dev/SitePages/Test.aspx\" , }); // follow a tag // You need the tag GUID to start following a tag. // You can't get the GUID by using the REST service, but you can use the .NET client object model or the JavaScript object model. // See How to get a tag's GUID based on the tag's name by using the JavaScript object model. // https://docs.microsoft.com/en-us/sharepoint/dev/general-development/follow-content-in-sharepoint#bk_getTagGuid const r4 = await sp . social . follow ({ ActorType : SocialActorType.Tag , TagGuid : \"19a4a484-c1dc-4bc5-8c93-bb96245ce928\" , }); isFollowed \u00b6 Indicates whether the current user is following a specified user, document, site, or tag import { sp , SocialActorType } from \"@pnp/sp\" ; // pass the same social actor struct as shown in follow example for each type const r = await sp . social . isFollowed ({ AccountName : \"i:0#.f|membership|person@tenant.com\" , ActorType : SocialActorType.User , }); stopFollowing \u00b6 Makes the current user stop following a user, document, site, or tag import { sp , SocialActorType } from \"@pnp/sp\" ; // pass the same social actor struct as shown in follow example for each type const r = await sp . social . stopFollowing ({ AccountName : \"i:0#.f|membership|person@tenant.com\" , ActorType : SocialActorType.User , }); my \u00b6 get \u00b6 Gets this user's social information import { sp } from \"@pnp/sp\" ; const r = await sp . social . my . get (); followed \u00b6 Gets users, documents, sites, and tags that the current user is following based on the supplied flags. import { sp , SocialActorTypes } from \"@pnp/sp\" ; // get all the followed documents const r1 = await sp . social . my . followed ( SocialActorTypes . Document ); // get all the followed documents and sites const r2 = await sp . social . my . followed ( SocialActorTypes . Document | SocialActorTypes . Site ); // get all the followed sites updated in the last 24 hours const r3 = await sp . social . my . followed ( SocialActorTypes . Site | SocialActorTypes . WithinLast24Hours ); followedCount \u00b6 Works as followed but returns on the count of actors specifed by the query import { sp , SocialActorTypes } from \"@pnp/sp\" ; // get the followed documents count const r = await sp . social . my . followedCount ( SocialActorTypes . Document ); followers \u00b6 Gets the users who are following the current user. import { sp } from \"@pnp/sp\" ; // get the followed documents count const r = await sp . social . my . followers (); suggestions \u00b6 Gets users who the current user might want to follow. import { sp } from \"@pnp/sp\" ; // get the followed documents count const r = await sp . social . my . suggestions ();","title":"Social"},{"location":"sp/docs/social/#pnpspsocial","text":"The social API allows you to track followed sites, people, and docs. Note, many of these methods only work with the context of a logged in user, and not with app-only permissions.","title":"@pnp/sp/social"},{"location":"sp/docs/social/#getfollowedsitesuri","text":"Gets a URI to a site that lists the current user's followed sites. import { sp } from \"@pnp/sp\" ; const uri = await sp . social . getFollowedSitesUri ();","title":"getFollowedSitesUri"},{"location":"sp/docs/social/#getfolloweddocumentsuri","text":"Gets a URI to a site that lists the current user's followed documents. import { sp } from \"@pnp/sp\" ; const uri = await sp . social . getFollowedDocumentsUri ();","title":"getFollowedDocumentsUri"},{"location":"sp/docs/social/#follow","text":"Makes the current user start following a user, document, site, or tag import { sp , SocialActorType } from \"@pnp/sp\" ; // follow a site const r1 = await sp . social . follow ({ ActorType : SocialActorType.Site , ContentUri : \"htts://tenant.sharepoint.com/sites/site\" , }); // follow a person const r2 = await sp . social . follow ({ AccountName : \"i:0#.f|membership|person@tenant.com\" , ActorType : SocialActorType.User , }); // follow a doc const r3 = await sp . social . follow ({ ActorType : SocialActorType.Document , ContentUri : \"https://tenant.sharepoint.com/sites/dev/SitePages/Test.aspx\" , }); // follow a tag // You need the tag GUID to start following a tag. // You can't get the GUID by using the REST service, but you can use the .NET client object model or the JavaScript object model. // See How to get a tag's GUID based on the tag's name by using the JavaScript object model. // https://docs.microsoft.com/en-us/sharepoint/dev/general-development/follow-content-in-sharepoint#bk_getTagGuid const r4 = await sp . social . follow ({ ActorType : SocialActorType.Tag , TagGuid : \"19a4a484-c1dc-4bc5-8c93-bb96245ce928\" , });","title":"follow"},{"location":"sp/docs/social/#isfollowed","text":"Indicates whether the current user is following a specified user, document, site, or tag import { sp , SocialActorType } from \"@pnp/sp\" ; // pass the same social actor struct as shown in follow example for each type const r = await sp . social . isFollowed ({ AccountName : \"i:0#.f|membership|person@tenant.com\" , ActorType : SocialActorType.User , });","title":"isFollowed"},{"location":"sp/docs/social/#stopfollowing","text":"Makes the current user stop following a user, document, site, or tag import { sp , SocialActorType } from \"@pnp/sp\" ; // pass the same social actor struct as shown in follow example for each type const r = await sp . social . stopFollowing ({ AccountName : \"i:0#.f|membership|person@tenant.com\" , ActorType : SocialActorType.User , });","title":"stopFollowing"},{"location":"sp/docs/social/#my","text":"","title":"my"},{"location":"sp/docs/social/#get","text":"Gets this user's social information import { sp } from \"@pnp/sp\" ; const r = await sp . social . my . get ();","title":"get"},{"location":"sp/docs/social/#followed","text":"Gets users, documents, sites, and tags that the current user is following based on the supplied flags. import { sp , SocialActorTypes } from \"@pnp/sp\" ; // get all the followed documents const r1 = await sp . social . my . followed ( SocialActorTypes . Document ); // get all the followed documents and sites const r2 = await sp . social . my . followed ( SocialActorTypes . Document | SocialActorTypes . Site ); // get all the followed sites updated in the last 24 hours const r3 = await sp . social . my . followed ( SocialActorTypes . Site | SocialActorTypes . WithinLast24Hours );","title":"followed"},{"location":"sp/docs/social/#followedcount","text":"Works as followed but returns on the count of actors specifed by the query import { sp , SocialActorTypes } from \"@pnp/sp\" ; // get the followed documents count const r = await sp . social . my . followedCount ( SocialActorTypes . Document );","title":"followedCount"},{"location":"sp/docs/social/#followers","text":"Gets the users who are following the current user. import { sp } from \"@pnp/sp\" ; // get the followed documents count const r = await sp . social . my . followers ();","title":"followers"},{"location":"sp/docs/social/#suggestions","text":"Gets users who the current user might want to follow. import { sp } from \"@pnp/sp\" ; // get the followed documents count const r = await sp . social . my . suggestions ();","title":"suggestions"},{"location":"sp/docs/sp-utilities-utility/","text":"@pnp/sp/utilities \u00b6 Through the REST api you are able to call a subset of the SP.Utilities.Utility methods. We have explicitly defined some of these methods and provided a method to call any others in a generic manner. These methods are exposed on pnp.sp.utility and support batching and caching. sendEmail \u00b6 This methods allows you to send an email based on the supplied arguments. The method takes a single argument, a plain object defined by the EmailProperties interface (shown below). EmailProperties \u00b6 export interface EmailProperties { To : string []; CC? : string []; BCC? : string []; Subject : string ; Body : string ; AdditionalHeaders? : TypedHash < string > ; From? : string ; } Usage \u00b6 You must define the To, Subject, and Body values - the remaining are optional. import { sp , EmailProperties } from \"@pnp/sp\" ; const emailProps : EmailProperties = { To : [ \"user@site.com\" ], CC : [ \"user2@site.com\" , \"user3@site.com\" ], Subject : \"This email is about...\" , Body : \"Here is the body. <b>It supports html</b>\" , }; sp . utility . sendEmail ( emailProps ). then ( _ => { console . log ( \"Email Sent!\" ); }); getCurrentUserEmailAddresses \u00b6 This method returns the current user's email addresses known to SharePoint. import { sp } from \"@pnp/sp\" ; sp . utility . getCurrentUserEmailAddresses (). then (( addressString : string ) => { console . log ( addressString ); }); resolvePrincipal \u00b6 Gets information about a principal that matches the specified Search criteria import { sp , PrincipalType , PrincipalSource , PrincipalInfo } from \"@pnp/sp\" ; sp . utility . resolvePrincipal ( \"user@site.com\" , PrincipalType . User , PrincipalSource . All , true , false ). then (( principal : PrincipalInfo ) => { console . log ( principal ); }); searchPrincipals \u00b6 Gets information about the principals that match the specified Search criteria. import { sp , PrincipalType , PrincipalSource , PrincipalInfo } from \"@pnp/sp\" ; sp . utility . searchPrincipals ( \"john\" , PrincipalType . User , PrincipalSource . All , \"\" , 10 ). then (( principals : PrincipalInfo []) => { console . log ( principals ); }); createEmailBodyForInvitation \u00b6 Gets the external (outside the firewall) URL to a document or resource in a site. import { sp } from \"@pnp/sp\" ; sp . utility . createEmailBodyForInvitation ( \"https://contoso.sharepoint.com/sites/dev/SitePages/DevHome.aspx\" ). then (( r : string ) => { console . log ( r ); }); expandGroupsToPrincipals \u00b6 Resolves the principals contained within the supplied groups import { sp , PrincipalInfo } from \"@pnp/sp\" ; sp . utility . expandGroupsToPrincipals ([ \"Dev Owners\" , \"Dev Members\" ]). then (( principals : PrincipalInfo []) => { console . log ( principals ); }); // optionally supply a max results count. Default is 30. sp . utility . expandGroupsToPrincipals ([ \"Dev Owners\" , \"Dev Members\" ], 10 ). then (( principals : PrincipalInfo []) => { console . log ( principals ); }); createWikiPage \u00b6 import { sp , CreateWikiPageResult } from \"@pnp/sp\" ; sp . utility . createWikiPage ({ ServerRelativeUrl : \"/sites/dev/SitePages/mynewpage.aspx\" , WikiHtmlContent : \"This is my <b>page</b> content. It supports rich html.\" , }). then (( result : CreateWikiPageResult ) => { // result contains the raw data returned by the service console . log ( result . data ); // result contains a File instance you can use to further update the new page result . file . get (). then ( f => { console . log ( f ); }); }); containsInvalidFileFolderChars \u00b6 Checks if file or folder name contains invalid characters import { sp } from \"@pnp/sp\" ; const isInvalid = sp . utility . containsInvalidFileFolderChars ( \"Filename?.txt\" ); console . log ( isInvalid ); // true stripInvalidFileFolderChars \u00b6 Removes invalid characters from file or folder name import { sp } from \"@pnp/sp\" ; const validName = sp . utility . stripInvalidFileFolderChars ( \"Filename?.txt\" ); console . log ( validName ); // Filename.txt Call Other Methods \u00b6 Even if a method does not have an explicit implementation on the utility api you can still call it using the UtilityMethod class. In this example we will show calling the GetLowerCaseString method, but the technique works for any of the utility methods. import { UtilityMethod } from \"@pnp/sp\" ; // the first parameter is the web url. You can use an empty string for the current web, // or specify it to call other web's. The second parameter is the method name. const method = new UtilityMethod ( \"\" , \"GetLowerCaseString\" ); // you must supply the correctly formatted parameters to the execute method which // is generic and types the result as the supplied generic type parameter. method . excute < string > ({ sourceValue : \"HeRe IS my StrINg\" , lcid : 1033 , }). then (( s : string ) => { console . log ( s ); });","title":"SP.Utilities.Utility"},{"location":"sp/docs/sp-utilities-utility/#pnpsputilities","text":"Through the REST api you are able to call a subset of the SP.Utilities.Utility methods. We have explicitly defined some of these methods and provided a method to call any others in a generic manner. These methods are exposed on pnp.sp.utility and support batching and caching.","title":"@pnp/sp/utilities"},{"location":"sp/docs/sp-utilities-utility/#sendemail","text":"This methods allows you to send an email based on the supplied arguments. The method takes a single argument, a plain object defined by the EmailProperties interface (shown below).","title":"sendEmail"},{"location":"sp/docs/sp-utilities-utility/#emailproperties","text":"export interface EmailProperties { To : string []; CC? : string []; BCC? : string []; Subject : string ; Body : string ; AdditionalHeaders? : TypedHash < string > ; From? : string ; }","title":"EmailProperties"},{"location":"sp/docs/sp-utilities-utility/#usage","text":"You must define the To, Subject, and Body values - the remaining are optional. import { sp , EmailProperties } from \"@pnp/sp\" ; const emailProps : EmailProperties = { To : [ \"user@site.com\" ], CC : [ \"user2@site.com\" , \"user3@site.com\" ], Subject : \"This email is about...\" , Body : \"Here is the body. <b>It supports html</b>\" , }; sp . utility . sendEmail ( emailProps ). then ( _ => { console . log ( \"Email Sent!\" ); });","title":"Usage"},{"location":"sp/docs/sp-utilities-utility/#getcurrentuseremailaddresses","text":"This method returns the current user's email addresses known to SharePoint. import { sp } from \"@pnp/sp\" ; sp . utility . getCurrentUserEmailAddresses (). then (( addressString : string ) => { console . log ( addressString ); });","title":"getCurrentUserEmailAddresses"},{"location":"sp/docs/sp-utilities-utility/#resolveprincipal","text":"Gets information about a principal that matches the specified Search criteria import { sp , PrincipalType , PrincipalSource , PrincipalInfo } from \"@pnp/sp\" ; sp . utility . resolvePrincipal ( \"user@site.com\" , PrincipalType . User , PrincipalSource . All , true , false ). then (( principal : PrincipalInfo ) => { console . log ( principal ); });","title":"resolvePrincipal"},{"location":"sp/docs/sp-utilities-utility/#searchprincipals","text":"Gets information about the principals that match the specified Search criteria. import { sp , PrincipalType , PrincipalSource , PrincipalInfo } from \"@pnp/sp\" ; sp . utility . searchPrincipals ( \"john\" , PrincipalType . User , PrincipalSource . All , \"\" , 10 ). then (( principals : PrincipalInfo []) => { console . log ( principals ); });","title":"searchPrincipals"},{"location":"sp/docs/sp-utilities-utility/#createemailbodyforinvitation","text":"Gets the external (outside the firewall) URL to a document or resource in a site. import { sp } from \"@pnp/sp\" ; sp . utility . createEmailBodyForInvitation ( \"https://contoso.sharepoint.com/sites/dev/SitePages/DevHome.aspx\" ). then (( r : string ) => { console . log ( r ); });","title":"createEmailBodyForInvitation"},{"location":"sp/docs/sp-utilities-utility/#expandgroupstoprincipals","text":"Resolves the principals contained within the supplied groups import { sp , PrincipalInfo } from \"@pnp/sp\" ; sp . utility . expandGroupsToPrincipals ([ \"Dev Owners\" , \"Dev Members\" ]). then (( principals : PrincipalInfo []) => { console . log ( principals ); }); // optionally supply a max results count. Default is 30. sp . utility . expandGroupsToPrincipals ([ \"Dev Owners\" , \"Dev Members\" ], 10 ). then (( principals : PrincipalInfo []) => { console . log ( principals ); });","title":"expandGroupsToPrincipals"},{"location":"sp/docs/sp-utilities-utility/#createwikipage","text":"import { sp , CreateWikiPageResult } from \"@pnp/sp\" ; sp . utility . createWikiPage ({ ServerRelativeUrl : \"/sites/dev/SitePages/mynewpage.aspx\" , WikiHtmlContent : \"This is my <b>page</b> content. It supports rich html.\" , }). then (( result : CreateWikiPageResult ) => { // result contains the raw data returned by the service console . log ( result . data ); // result contains a File instance you can use to further update the new page result . file . get (). then ( f => { console . log ( f ); }); });","title":"createWikiPage"},{"location":"sp/docs/sp-utilities-utility/#containsinvalidfilefolderchars","text":"Checks if file or folder name contains invalid characters import { sp } from \"@pnp/sp\" ; const isInvalid = sp . utility . containsInvalidFileFolderChars ( \"Filename?.txt\" ); console . log ( isInvalid ); // true","title":"containsInvalidFileFolderChars"},{"location":"sp/docs/sp-utilities-utility/#stripinvalidfilefolderchars","text":"Removes invalid characters from file or folder name import { sp } from \"@pnp/sp\" ; const validName = sp . utility . stripInvalidFileFolderChars ( \"Filename?.txt\" ); console . log ( validName ); // Filename.txt","title":"stripInvalidFileFolderChars"},{"location":"sp/docs/sp-utilities-utility/#call-other-methods","text":"Even if a method does not have an explicit implementation on the utility api you can still call it using the UtilityMethod class. In this example we will show calling the GetLowerCaseString method, but the technique works for any of the utility methods. import { UtilityMethod } from \"@pnp/sp\" ; // the first parameter is the web url. You can use an empty string for the current web, // or specify it to call other web's. The second parameter is the method name. const method = new UtilityMethod ( \"\" , \"GetLowerCaseString\" ); // you must supply the correctly formatted parameters to the execute method which // is generic and types the result as the supplied generic type parameter. method . excute < string > ({ sourceValue : \"HeRe IS my StrINg\" , lcid : 1033 , }). then (( s : string ) => { console . log ( s ); });","title":"Call Other Methods"},{"location":"sp/docs/tenant-properties/","text":"@pnp/sp/web - tenant properties \u00b6 You can set, read, and remove tenant properties using the methods shown below: setStorageEntity \u00b6 This method MUST be called in the context of the app catalog web or you will get an access denied message. import { Web } from \"@pnp/sp\" ; const w = new Web ( \"https://tenant.sharepoint.com/sites/appcatalog/\" ); // specify required key and value await w . setStorageEntity ( \"Test1\" , \"Value 1\" ); // specify optional description and comments await w . setStorageEntity ( \"Test2\" , \"Value 2\" , \"description\" , \"comments\" ); getStorageEntity \u00b6 This method can be used from any web to retrieve values previsouly set. import { sp , StorageEntity } from \"@pnp/sp\" ; const prop : StorageEntity = await sp . web . getStorageEntity ( \"Test1\" ); console . log ( prop . Value ); removeStorageEntity \u00b6 This method MUST be called in the context of the app catalog web or you will get an access denied message. import { Web } from \"@pnp/sp\" ; const w = new Web ( \"https://tenant.sharepoint.com/sites/appcatalog/\" ); await w . removeStorageEntity ( \"Test1\" );","title":"Tenant Properties"},{"location":"sp/docs/tenant-properties/#pnpspweb-tenant-properties","text":"You can set, read, and remove tenant properties using the methods shown below:","title":"@pnp/sp/web - tenant properties"},{"location":"sp/docs/tenant-properties/#setstorageentity","text":"This method MUST be called in the context of the app catalog web or you will get an access denied message. import { Web } from \"@pnp/sp\" ; const w = new Web ( \"https://tenant.sharepoint.com/sites/appcatalog/\" ); // specify required key and value await w . setStorageEntity ( \"Test1\" , \"Value 1\" ); // specify optional description and comments await w . setStorageEntity ( \"Test2\" , \"Value 2\" , \"description\" , \"comments\" );","title":"setStorageEntity"},{"location":"sp/docs/tenant-properties/#getstorageentity","text":"This method can be used from any web to retrieve values previsouly set. import { sp , StorageEntity } from \"@pnp/sp\" ; const prop : StorageEntity = await sp . web . getStorageEntity ( \"Test1\" ); console . log ( prop . Value );","title":"getStorageEntity"},{"location":"sp/docs/tenant-properties/#removestorageentity","text":"This method MUST be called in the context of the app catalog web or you will get an access denied message. import { Web } from \"@pnp/sp\" ; const w = new Web ( \"https://tenant.sharepoint.com/sites/appcatalog/\" ); await w . removeStorageEntity ( \"Test1\" );","title":"removeStorageEntity"},{"location":"sp/docs/views/","text":"@pnp/sp/views \u00b6 Views define the columns, ordering, and other details we see when we look at a list. You can have multiple views for a list, including private views - and one default view. Get a View's Properties \u00b6 To get a views properties you need to know it's id or title. You can use the standard OData operators as expected to select properties. For a list of the properties, please see this article . import { sp } from \"@pnp/sp\" ; // know a view's GUID id sp . web . lists . getByTitle ( \"Documents\" ). getView ( \"2B382C69-DF64-49C4-85F1-70FB9CECACFE\" ). select ( \"Title\" ). get (). then ( v => { console . log ( v ); }); // get by the display title of the view sp . web . lists . getByTitle ( \"Documents\" ). views . getByTitle ( \"All Documents\" ). select ( \"Title\" ). get (). then ( v => { console . log ( v ); }); Add a View \u00b6 To add a view you use the add method of the views collection. You must supply a title and can supply other parameters as well. import { sp , ViewAddResult } from \"@pnp/sp\" ; // create a new view with default fields and properties sp . web . lists . getByTitle ( \"Documents\" ). views . add ( \"My New View\" ). then ( v => { console . log ( v ); }); // create a new view with specific properties sp . web . lists . getByTitle ( \"Documents\" ). views . add ( \"My New View 2\" , false , { RowLimit : 10 , ViewQuery : \"<OrderBy><FieldRef Name='Modified' Ascending='False' /></OrderBy>\" , }). then (( v : ViewAddResult ) => { // manipulate the view's fields v . view . fields . removeAll (). then ( _ => { Promise . all ([ v . view . fields . add ( \"Title\" ), v . view . fields . add ( \"Modified\" ), ]). then ( _ => { console . log ( \"View created\" ); }); }); }); Update a View \u00b6 import { sp , ViewUpdateResult } from \"@pnp/sp\" ; sp . web . lists . getByTitle ( \"Documents\" ). views . getByTitle ( \"My New View\" ). update ({ RowLimit : 20 , }). then (( v : ViewUpdateResult ) => { console . log ( v ); }); Set View XML \u00b6 Added in 1.2.6 import { sp } from \"@pnp/sp\" ; const viewXml : string = \"...\" ; await sp . web . lists . getByTitle ( \"Documents\" ). views . getByTitle ( \"My New View\" ). setViewXml ( viewXml ); Delete a View \u00b6 import { sp } from \"@pnp/sp\" ; sp . web . lists . getByTitle ( \"Documents\" ). views . getByTitle ( \"My New View\" ). delete (). then ( _ => { console . log ( \"View deleted\" ); });","title":"Views"},{"location":"sp/docs/views/#pnpspviews","text":"Views define the columns, ordering, and other details we see when we look at a list. You can have multiple views for a list, including private views - and one default view.","title":"@pnp/sp/views"},{"location":"sp/docs/views/#get-a-views-properties","text":"To get a views properties you need to know it's id or title. You can use the standard OData operators as expected to select properties. For a list of the properties, please see this article . import { sp } from \"@pnp/sp\" ; // know a view's GUID id sp . web . lists . getByTitle ( \"Documents\" ). getView ( \"2B382C69-DF64-49C4-85F1-70FB9CECACFE\" ). select ( \"Title\" ). get (). then ( v => { console . log ( v ); }); // get by the display title of the view sp . web . lists . getByTitle ( \"Documents\" ). views . getByTitle ( \"All Documents\" ). select ( \"Title\" ). get (). then ( v => { console . log ( v ); });","title":"Get a View's Properties"},{"location":"sp/docs/views/#add-a-view","text":"To add a view you use the add method of the views collection. You must supply a title and can supply other parameters as well. import { sp , ViewAddResult } from \"@pnp/sp\" ; // create a new view with default fields and properties sp . web . lists . getByTitle ( \"Documents\" ). views . add ( \"My New View\" ). then ( v => { console . log ( v ); }); // create a new view with specific properties sp . web . lists . getByTitle ( \"Documents\" ). views . add ( \"My New View 2\" , false , { RowLimit : 10 , ViewQuery : \"<OrderBy><FieldRef Name='Modified' Ascending='False' /></OrderBy>\" , }). then (( v : ViewAddResult ) => { // manipulate the view's fields v . view . fields . removeAll (). then ( _ => { Promise . all ([ v . view . fields . add ( \"Title\" ), v . view . fields . add ( \"Modified\" ), ]). then ( _ => { console . log ( \"View created\" ); }); }); });","title":"Add a View"},{"location":"sp/docs/views/#update-a-view","text":"import { sp , ViewUpdateResult } from \"@pnp/sp\" ; sp . web . lists . getByTitle ( \"Documents\" ). views . getByTitle ( \"My New View\" ). update ({ RowLimit : 20 , }). then (( v : ViewUpdateResult ) => { console . log ( v ); });","title":"Update a View"},{"location":"sp/docs/views/#set-view-xml","text":"Added in 1.2.6 import { sp } from \"@pnp/sp\" ; const viewXml : string = \"...\" ; await sp . web . lists . getByTitle ( \"Documents\" ). views . getByTitle ( \"My New View\" ). setViewXml ( viewXml );","title":"Set View XML"},{"location":"sp/docs/views/#delete-a-view","text":"import { sp } from \"@pnp/sp\" ; sp . web . lists . getByTitle ( \"Documents\" ). views . getByTitle ( \"My New View\" ). delete (). then ( _ => { console . log ( \"View deleted\" ); });","title":"Delete a View"},{"location":"sp/docs/webs/","text":"@pnp/sp/webs \u00b6 Webs are one of the fundamental entry points when working with SharePoint. Webs serve as a container for lists, features, sub-webs, and all of the entity types. Add a Web \u00b6 Using the library you can add a web to another web's collection of subwebs. The basic usage requires only a title and url. This will result in a team site with all of the default settings. import { sp , WebAddResult } from \"@pnp/sp\" ; sp . web . webs . add ( \"title\" , \"subweb1\" ). then (( w : WebAddResult ) => { // show the response from the server when adding the web console . log ( w . data ); w . web . select ( \"Title\" ). get (). then ( w => { // show our title console . log ( w . Title ); }); }); You can also provide other settings such as description, template, language, and inherit permissions. import { sp , WebAddResult } from \"@pnp/sp\" ; // create a German language wiki site with title, url, description, which inherits permissions sp . web . webs . add ( \"wiki\" , \"subweb2\" , \"a wiki web\" , \"WIKI#0\" , 1031 , true ). then (( w : WebAddResult ) => { // show the response from the server when adding the web console . log ( w . data ); w . web . select ( \"Title\" ). get (). then ( w => { // show our title console . log ( w . Title ); }); }); Create Default Associated Groups \u00b6 If you create a web that doesn't inherit permissions from the parent web, you can create its default associated groups (Members, Owners, Visitors) with the default role assigments (Contribute, Full Control, Read) import { sp , WebAddResult } from \"@pnp/sp\" ; sp . web . webs . add ( \"title\" , \"subweb1\" , \"a wiki web\" , \"WIKI#0\" , 1031 , false ). then (( w : WebAddResult ) => { w . web . createDefaultAssociatedGroups (). then (() => { // ... }); }); Get A Web's properties \u00b6 import { sp } from \"@pnp/sp\" ; // basic get of the webs properties sp . web . get (). then ( w => { console . log ( w . Title ); }); // use odata operators to get specific fields sp . web . select ( \"Title\" ). get (). then ( w => { console . log ( w . Title ); }); // use with get to give the result a type sp . web . select ( \"Title\" ). get < { Title : string } > (). then ( w => { console . log ( w . Title ); }); Get Complex Properties \u00b6 Some properties, such as AllProperties, are not returned by default. You can still access them using the expand operator. import { sp } from \"@pnp/sp\" ; sp . web . select ( \"AllProperties\" ). expand ( \"AllProperties\" ). get (). then ( w => { console . log ( w . AllProperties ); }); Get a Web Directly \u00b6 You can also use the Web object directly to get any web, though of course the current user must have the necessary permissions. This is done by importing the web object. import { Web } from \"@pnp/sp\" ; let web = new Web ( \"https://my-tenant.sharepoint.com/sites/mysite\" ); web . get (). then ( w => { console . log ( w ); }); Open Web By Id \u00b6 Because this method is a POST request you can chain off it directly. You will get back the full web properties in the data property of the return object. You can also chain directly off the returned Web instance on the web property. sp . site . openWebById ( \"111ca453-90f5-482e-a381-cee1ff383c9e\" ). then ( w => { //we got all the data from the web as well console . log ( w . data ); // we can chain w . web . select ( \"Title\" ). get (). then ( w2 => { // ... }); }); Update Web Properties \u00b6 You can update web properties using the update method. The properties available for update are listed in this table . Updating is a simple as passing a plain object with the properties you want to update. import { Web } from \"@pnp/sp\" ; let web = new Web ( \"https://my-tenant.sharepoint.com/sites/mysite\" ); web . update ({ Title : \"New Title\" , CustomMasterUrl : \"{path to masterpage}\" , Description : \"My new description\" , }). then ( w => { console . log ( w ); }); Delete a Web \u00b6 import { Web } from \"@pnp/sp\" ; let web = new Web ( \"https://my-tenant.sharepoint.com/sites/mysite\" ); web . delete (). then ( w => { console . log ( w ); });","title":"Webs"},{"location":"sp/docs/webs/#pnpspwebs","text":"Webs are one of the fundamental entry points when working with SharePoint. Webs serve as a container for lists, features, sub-webs, and all of the entity types.","title":"@pnp/sp/webs"},{"location":"sp/docs/webs/#add-a-web","text":"Using the library you can add a web to another web's collection of subwebs. The basic usage requires only a title and url. This will result in a team site with all of the default settings. import { sp , WebAddResult } from \"@pnp/sp\" ; sp . web . webs . add ( \"title\" , \"subweb1\" ). then (( w : WebAddResult ) => { // show the response from the server when adding the web console . log ( w . data ); w . web . select ( \"Title\" ). get (). then ( w => { // show our title console . log ( w . Title ); }); }); You can also provide other settings such as description, template, language, and inherit permissions. import { sp , WebAddResult } from \"@pnp/sp\" ; // create a German language wiki site with title, url, description, which inherits permissions sp . web . webs . add ( \"wiki\" , \"subweb2\" , \"a wiki web\" , \"WIKI#0\" , 1031 , true ). then (( w : WebAddResult ) => { // show the response from the server when adding the web console . log ( w . data ); w . web . select ( \"Title\" ). get (). then ( w => { // show our title console . log ( w . Title ); }); });","title":"Add a Web"},{"location":"sp/docs/webs/#create-default-associated-groups","text":"If you create a web that doesn't inherit permissions from the parent web, you can create its default associated groups (Members, Owners, Visitors) with the default role assigments (Contribute, Full Control, Read) import { sp , WebAddResult } from \"@pnp/sp\" ; sp . web . webs . add ( \"title\" , \"subweb1\" , \"a wiki web\" , \"WIKI#0\" , 1031 , false ). then (( w : WebAddResult ) => { w . web . createDefaultAssociatedGroups (). then (() => { // ... }); });","title":"Create Default Associated Groups"},{"location":"sp/docs/webs/#get-a-webs-properties","text":"import { sp } from \"@pnp/sp\" ; // basic get of the webs properties sp . web . get (). then ( w => { console . log ( w . Title ); }); // use odata operators to get specific fields sp . web . select ( \"Title\" ). get (). then ( w => { console . log ( w . Title ); }); // use with get to give the result a type sp . web . select ( \"Title\" ). get < { Title : string } > (). then ( w => { console . log ( w . Title ); });","title":"Get A Web's properties"},{"location":"sp/docs/webs/#get-complex-properties","text":"Some properties, such as AllProperties, are not returned by default. You can still access them using the expand operator. import { sp } from \"@pnp/sp\" ; sp . web . select ( \"AllProperties\" ). expand ( \"AllProperties\" ). get (). then ( w => { console . log ( w . AllProperties ); });","title":"Get Complex Properties"},{"location":"sp/docs/webs/#get-a-web-directly","text":"You can also use the Web object directly to get any web, though of course the current user must have the necessary permissions. This is done by importing the web object. import { Web } from \"@pnp/sp\" ; let web = new Web ( \"https://my-tenant.sharepoint.com/sites/mysite\" ); web . get (). then ( w => { console . log ( w ); });","title":"Get a Web Directly"},{"location":"sp/docs/webs/#open-web-by-id","text":"Because this method is a POST request you can chain off it directly. You will get back the full web properties in the data property of the return object. You can also chain directly off the returned Web instance on the web property. sp . site . openWebById ( \"111ca453-90f5-482e-a381-cee1ff383c9e\" ). then ( w => { //we got all the data from the web as well console . log ( w . data ); // we can chain w . web . select ( \"Title\" ). get (). then ( w2 => { // ... }); });","title":"Open Web By Id"},{"location":"sp/docs/webs/#update-web-properties","text":"You can update web properties using the update method. The properties available for update are listed in this table . Updating is a simple as passing a plain object with the properties you want to update. import { Web } from \"@pnp/sp\" ; let web = new Web ( \"https://my-tenant.sharepoint.com/sites/mysite\" ); web . update ({ Title : \"New Title\" , CustomMasterUrl : \"{path to masterpage}\" , Description : \"My new description\" , }). then ( w => { console . log ( w ); });","title":"Update Web Properties"},{"location":"sp/docs/webs/#delete-a-web","text":"import { Web } from \"@pnp/sp\" ; let web = new Web ( \"https://my-tenant.sharepoint.com/sites/mysite\" ); web . delete (). then ( w => { console . log ( w ); });","title":"Delete a Web"},{"location":"sp-addinhelpers/docs/","text":"@pnp/sp-addinhelpers \u00b6 This module contains classes to allow use of the libraries within a SharePoint add-in. Getting Started \u00b6 Install the library and all dependencies, npm install @pnp/logging @pnp/core @pnp/queryable @pnp/sp @pnp/sp-addinhelpers --save Now you can make requests to the host web from your add-in using the crossDomainWeb method. // note we are getting the sp variable from this library, it extends the sp export from @pnp/sp to add the required helper methods import { sp , SPRequestExecutorClient } from \"@pnp/sp-addinhelpers\" ; // this only needs to be done once within your application sp . setup ({ sp : { fetchClientFactory : () => { return new SPRequestExecutorClient (); } } }); // now we need to use the crossDomainWeb method to make our requests to the host web const addInWenUrl = \"{The add-in web url, likely from the query string}\" ; const hostWebUrl = \"{The host web url, likely from the query string}\" ; // make requests into the host web via the SP.RequestExecutor sp . crossDomainWeb ( addInWenUrl , hostWebUrl ). get (). then ( w => { console . log ( JSON . stringify ( w , null , 4 )); }); Libary Topics \u00b6 SPRequestExecutorClient SPRestAddIn UML \u00b6 Graphical UML diagram of @pnp/sp-addinhelpers. Right-click the diagram and open in new tab if it is too small.","title":"sp-addinhelpers"},{"location":"sp-addinhelpers/docs/#pnpsp-addinhelpers","text":"This module contains classes to allow use of the libraries within a SharePoint add-in.","title":"@pnp/sp-addinhelpers"},{"location":"sp-addinhelpers/docs/#getting-started","text":"Install the library and all dependencies, npm install @pnp/logging @pnp/core @pnp/queryable @pnp/sp @pnp/sp-addinhelpers --save Now you can make requests to the host web from your add-in using the crossDomainWeb method. // note we are getting the sp variable from this library, it extends the sp export from @pnp/sp to add the required helper methods import { sp , SPRequestExecutorClient } from \"@pnp/sp-addinhelpers\" ; // this only needs to be done once within your application sp . setup ({ sp : { fetchClientFactory : () => { return new SPRequestExecutorClient (); } } }); // now we need to use the crossDomainWeb method to make our requests to the host web const addInWenUrl = \"{The add-in web url, likely from the query string}\" ; const hostWebUrl = \"{The host web url, likely from the query string}\" ; // make requests into the host web via the SP.RequestExecutor sp . crossDomainWeb ( addInWenUrl , hostWebUrl ). get (). then ( w => { console . log ( JSON . stringify ( w , null , 4 )); });","title":"Getting Started"},{"location":"sp-addinhelpers/docs/#libary-topics","text":"SPRequestExecutorClient SPRestAddIn","title":"Libary Topics"},{"location":"sp-addinhelpers/docs/#uml","text":"Graphical UML diagram of @pnp/sp-addinhelpers. Right-click the diagram and open in new tab if it is too small.","title":"UML"},{"location":"sp-addinhelpers/docs/sp-request-executor-client/","text":"@pnp/sp-addinhelpers/sprequestexecutorclient \u00b6 The SPRequestExecutorClient is an implementation of the HttpClientImpl interface that facilitates requests to SharePoint from an add-in. It relies on the SharePoint SP product libraries being present to allow use of the SP.RequestExecutor to make the request. Setup \u00b6 To use the client you need to set it using the fetch client factory using the setup method as shown below. This is only required when working within a SharePoint add-in web. // note we are getting the sp variable from this library, it extends the sp export from @pnp/sp to add the required helper methods import { sp , SPRequestExecutorClient } from \"@pnp/sp-addinhelpers\" ; // this only needs to be done once within your application sp . setup ({ sp : { fetchClientFactory : () => { return new SPRequestExecutorClient (); } } }); // now we need to use the crossDomainWeb method to make our requests to the host web const addInWenUrl = \"{The add-in web url, likely from the query string}\" ; const hostWebUrl = \"{The host web url, likely from the query string}\" ; // make requests into the host web via the SP.RequestExecutor sp . crossDomainWeb ( addInWenUrl , hostWebUrl ). get (). then ( w => { console . log ( JSON . stringify ( w , null , 4 )); });","title":"SPRequestExecutorClient"},{"location":"sp-addinhelpers/docs/sp-request-executor-client/#pnpsp-addinhelperssprequestexecutorclient","text":"The SPRequestExecutorClient is an implementation of the HttpClientImpl interface that facilitates requests to SharePoint from an add-in. It relies on the SharePoint SP product libraries being present to allow use of the SP.RequestExecutor to make the request.","title":"@pnp/sp-addinhelpers/sprequestexecutorclient"},{"location":"sp-addinhelpers/docs/sp-request-executor-client/#setup","text":"To use the client you need to set it using the fetch client factory using the setup method as shown below. This is only required when working within a SharePoint add-in web. // note we are getting the sp variable from this library, it extends the sp export from @pnp/sp to add the required helper methods import { sp , SPRequestExecutorClient } from \"@pnp/sp-addinhelpers\" ; // this only needs to be done once within your application sp . setup ({ sp : { fetchClientFactory : () => { return new SPRequestExecutorClient (); } } }); // now we need to use the crossDomainWeb method to make our requests to the host web const addInWenUrl = \"{The add-in web url, likely from the query string}\" ; const hostWebUrl = \"{The host web url, likely from the query string}\" ; // make requests into the host web via the SP.RequestExecutor sp . crossDomainWeb ( addInWenUrl , hostWebUrl ). get (). then ( w => { console . log ( JSON . stringify ( w , null , 4 )); });","title":"Setup"},{"location":"sp-addinhelpers/docs/sp-rest-addin/","text":"@pnp/sp-addinhelpers/sprestaddin \u00b6 This class extends the sp export from @pnp/sp and adds in the methods required to make cross domain calls // note we are getting the sp variable from this library, it extends the sp export from @pnp/sp to add the required helper methods import { sp , SPRequestExecutorClient } from \"@pnp/sp-addinhelpers\" ; // this only needs to be done once within your application sp . setup ({ sp : { fetchClientFactory : () => { return new SPRequestExecutorClient (); } } }); // now we need to use the crossDomainWeb method to make our requests to the host web const addInWenUrl = \"{The add-in web url, likely from the query string}\" ; const hostWebUrl = \"{The host web url, likely from the query string}\" ; // make requests into the host web via the SP.RequestExecutor sp . crossDomainWeb ( addInWenUrl , hostWebUrl ). get (). then ( w => { console . log ( JSON . stringify ( w , null , 4 )); });","title":"SPRestAddIn"},{"location":"sp-addinhelpers/docs/sp-rest-addin/#pnpsp-addinhelperssprestaddin","text":"This class extends the sp export from @pnp/sp and adds in the methods required to make cross domain calls // note we are getting the sp variable from this library, it extends the sp export from @pnp/sp to add the required helper methods import { sp , SPRequestExecutorClient } from \"@pnp/sp-addinhelpers\" ; // this only needs to be done once within your application sp . setup ({ sp : { fetchClientFactory : () => { return new SPRequestExecutorClient (); } } }); // now we need to use the crossDomainWeb method to make our requests to the host web const addInWenUrl = \"{The add-in web url, likely from the query string}\" ; const hostWebUrl = \"{The host web url, likely from the query string}\" ; // make requests into the host web via the SP.RequestExecutor sp . crossDomainWeb ( addInWenUrl , hostWebUrl ). get (). then ( w => { console . log ( JSON . stringify ( w , null , 4 )); });","title":"@pnp/sp-addinhelpers/sprestaddin"},{"location":"sp-addinhelpers/node_modules/@types/microsoft-ajax/","text":"Installation \u00b6 npm install --save @types/microsoft-ajax Summary \u00b6 This package contains type definitions for Microsoft ASP.NET Ajax client side library (http://msdn.microsoft.com/en-us/library/ee341002(v=vs.100).aspx). Details \u00b6 Files were exported from https://www.github.com/DefinitelyTyped/DefinitelyTyped/tree/main/types/microsoft-ajax Additional Details * Last updated: Mon, 21 Aug 2017 21:55:03 GMT * Dependencies: none * Global values: $addHandler, $addHandlers, $clearHandlers, $create, $find, $get, $removeHandler, Sys, Type Credits \u00b6 These definitions were written by Patrick Magee https://github.com/pjmagee .","title":"Installation"},{"location":"sp-addinhelpers/node_modules/@types/microsoft-ajax/#installation","text":"npm install --save @types/microsoft-ajax","title":"Installation"},{"location":"sp-addinhelpers/node_modules/@types/microsoft-ajax/#summary","text":"This package contains type definitions for Microsoft ASP.NET Ajax client side library (http://msdn.microsoft.com/en-us/library/ee341002(v=vs.100).aspx).","title":"Summary"},{"location":"sp-addinhelpers/node_modules/@types/microsoft-ajax/#details","text":"Files were exported from https://www.github.com/DefinitelyTyped/DefinitelyTyped/tree/main/types/microsoft-ajax Additional Details * Last updated: Mon, 21 Aug 2017 21:55:03 GMT * Dependencies: none * Global values: $addHandler, $addHandlers, $clearHandlers, $create, $find, $get, $removeHandler, Sys, Type","title":"Details"},{"location":"sp-addinhelpers/node_modules/@types/microsoft-ajax/#credits","text":"These definitions were written by Patrick Magee https://github.com/pjmagee .","title":"Credits"},{"location":"sp-addinhelpers/node_modules/@types/sharepoint/","text":"Installation \u00b6 npm install --save @types/sharepoint Summary \u00b6 This package contains type definitions for Microsoft SharePoint: (https://msdn.microsoft.com/en-us/library/office/jj193034.aspx). Details \u00b6 Files were exported from https://www.github.com/DefinitelyTyped/DefinitelyTyped/tree/main/types/sharepoint Additional Details * Last updated: Thu, 15 Jun 2017 22:02:56 GMT * Dependencies: microsoft-ajax * Global values: $addRenderContextCallback, $contentLineText, $findResultObjectFromDOM, $getCachedItemValue, $getClientControl, $getItemValue, $getResultItem, $getResultObject, $htmlEncode, $imgSrcUrl, $includeCSS, $includeLanguageScript, $includeScript, $isEmptyArray, $isEmptyString, $isInArray, $isNull, $registerResourceDictionary, $resource, $scriptEncode, $setItemWrapperCallback, $setResultItem, $setResultObject, $urlHtmlEncode, $urlKeyValueEncode, $urlPathEncode, AddEvtHandler, AjaxNavigate, BrowserDetection, BrowserStorage, Browseris, CSSUtil, Callout, CalloutAction, CalloutActionMenu, CalloutActionMenuEntry, CalloutActionOptions, CalloutManager, CalloutOpenOptions, CalloutOptions, CoreRender, DOM, Define, Encoding, ExecuteOrDelayUntilBodyLoaded, ExecuteOrDelayUntilEventNotified, ExecuteOrDelayUntilScriptLoaded, GenerateIID, GenerateIIDForListItem, GetCurrentCtx, GetUrlKeyValue, IE8Support, JSRequest, ListModule, Microsoft, Nav, RefreshCommandUI, RegisterModuleInit, SP, SPAnimation, SPAnimationUtility, SPClientAutoFill, SPClientForms, SPClientPeoplePicker, SPClientPeoplePickerCSRTemplate, SPClientPeoplePickerMRU, SPClientPeoplePickerProcessedUser, SPClientTemplates, SPFieldAttachments_Default, SPFieldBoolean_Edit, SPFieldChoice_Dropdown_Edit, SPFieldChoice_Edit, SPFieldChoice_Radio_Edit, SPFieldDateTime_Display, SPFieldDateTime_Edit, SPFieldFile_Display, SPFieldFile_Edit, SPFieldLookupMulti_Edit, SPFieldLookup_Display, SPFieldLookup_Edit, SPFieldMultiChoice_Edit, SPFieldNote_Display, SPFieldNote_Edit, SPFieldNumber_Edit, SPFieldText_Edit, SPFieldUrl_Display, SPFieldUrl_Edit, SPFieldUserMulti_Display, SPFieldUser_Display, SPField_FormDisplay_Default, SPField_FormDisplay_DefaultNoEncode, SPField_FormDisplay_Empty, SPFormControl_AppendValidationErrorMessage, SPMgr, SPNotifications, SPStatusNotificationData, SPThemeUtils, STSHtmlDecode, STSHtmlEncode, SetFullScreenMode, Srch, StringUtil, Strings, TypeUtil, URI_Encoding, Verify, _spBodyOnLoadCalled, _spBodyOnLoadFunctionNames, _spBodyOnLoadFunctions, _spFriendlyUrlPageContextInfo, _spPageContextInfo, ajaxNavigate, browseris, m$, spMgr Credits \u00b6 These definitions were written by Stanislav Vyshchepan http:// blog.gandjustas.ru , Andrey Markeev http:// markeev.com , Vincent Biret https://github.com/baywet .","title":"Installation"},{"location":"sp-addinhelpers/node_modules/@types/sharepoint/#installation","text":"npm install --save @types/sharepoint","title":"Installation"},{"location":"sp-addinhelpers/node_modules/@types/sharepoint/#summary","text":"This package contains type definitions for Microsoft SharePoint: (https://msdn.microsoft.com/en-us/library/office/jj193034.aspx).","title":"Summary"},{"location":"sp-addinhelpers/node_modules/@types/sharepoint/#details","text":"Files were exported from https://www.github.com/DefinitelyTyped/DefinitelyTyped/tree/main/types/sharepoint Additional Details * Last updated: Thu, 15 Jun 2017 22:02:56 GMT * Dependencies: microsoft-ajax * Global values: $addRenderContextCallback, $contentLineText, $findResultObjectFromDOM, $getCachedItemValue, $getClientControl, $getItemValue, $getResultItem, $getResultObject, $htmlEncode, $imgSrcUrl, $includeCSS, $includeLanguageScript, $includeScript, $isEmptyArray, $isEmptyString, $isInArray, $isNull, $registerResourceDictionary, $resource, $scriptEncode, $setItemWrapperCallback, $setResultItem, $setResultObject, $urlHtmlEncode, $urlKeyValueEncode, $urlPathEncode, AddEvtHandler, AjaxNavigate, BrowserDetection, BrowserStorage, Browseris, CSSUtil, Callout, CalloutAction, CalloutActionMenu, CalloutActionMenuEntry, CalloutActionOptions, CalloutManager, CalloutOpenOptions, CalloutOptions, CoreRender, DOM, Define, Encoding, ExecuteOrDelayUntilBodyLoaded, ExecuteOrDelayUntilEventNotified, ExecuteOrDelayUntilScriptLoaded, GenerateIID, GenerateIIDForListItem, GetCurrentCtx, GetUrlKeyValue, IE8Support, JSRequest, ListModule, Microsoft, Nav, RefreshCommandUI, RegisterModuleInit, SP, SPAnimation, SPAnimationUtility, SPClientAutoFill, SPClientForms, SPClientPeoplePicker, SPClientPeoplePickerCSRTemplate, SPClientPeoplePickerMRU, SPClientPeoplePickerProcessedUser, SPClientTemplates, SPFieldAttachments_Default, SPFieldBoolean_Edit, SPFieldChoice_Dropdown_Edit, SPFieldChoice_Edit, SPFieldChoice_Radio_Edit, SPFieldDateTime_Display, SPFieldDateTime_Edit, SPFieldFile_Display, SPFieldFile_Edit, SPFieldLookupMulti_Edit, SPFieldLookup_Display, SPFieldLookup_Edit, SPFieldMultiChoice_Edit, SPFieldNote_Display, SPFieldNote_Edit, SPFieldNumber_Edit, SPFieldText_Edit, SPFieldUrl_Display, SPFieldUrl_Edit, SPFieldUserMulti_Display, SPFieldUser_Display, SPField_FormDisplay_Default, SPField_FormDisplay_DefaultNoEncode, SPField_FormDisplay_Empty, SPFormControl_AppendValidationErrorMessage, SPMgr, SPNotifications, SPStatusNotificationData, SPThemeUtils, STSHtmlDecode, STSHtmlEncode, SetFullScreenMode, Srch, StringUtil, Strings, TypeUtil, URI_Encoding, Verify, _spBodyOnLoadCalled, _spBodyOnLoadFunctionNames, _spBodyOnLoadFunctions, _spFriendlyUrlPageContextInfo, _spPageContextInfo, ajaxNavigate, browseris, m$, spMgr","title":"Details"},{"location":"sp-addinhelpers/node_modules/@types/sharepoint/#credits","text":"These definitions were written by Stanislav Vyshchepan http:// blog.gandjustas.ru , Andrey Markeev http:// markeev.com , Vincent Biret https://github.com/baywet .","title":"Credits"},{"location":"sp-addinhelpers/node_modules/tslib/","text":"tslib \u00b6 This is a runtime library for TypeScript that contains all of the TypeScript helper functions. This library is primarily used by the --importHelpers flag in TypeScript. When using --importHelpers , a module that uses helper functions like __extends and __assign in the following emitted file: var __assign = ( this && this . __assign ) || Object . assign || function ( t ) { for ( var s , i = 1 , n = arguments . length ; i < n ; i ++ ) { s = arguments [ i ]; for ( var p in s ) if ( Object . prototype . hasOwnProperty . call ( s , p )) t [ p ] = s [ p ]; } return t ; }; exports . x = {}; exports . y = __assign ({}, exports . x ); will instead be emitted as something like the following: var tslib_1 = require ( \"tslib\" ); exports . x = {}; exports . y = tslib_1 . __assign ({}, exports . x ); Because this can avoid duplicate declarations of things like __extends , __assign , etc., this means delivering users smaller files on average, as well as less runtime overhead. For optimized bundles with TypeScript, you should absolutely consider using tslib and --importHelpers . Installing \u00b6 For the latest stable version, run: npm \u00b6 # TypeScript 2.3.3 or later npm install --save tslib # TypeScript 2.3.2 or earlier npm install --save tslib@1.6.1 bower \u00b6 # TypeScript 2.3.3 or later bower install tslib # TypeScript 2.3.2 or earlier bower install tslib@1.6.1 JSPM \u00b6 # TypeScript 2.3.3 or later jspm install tslib # TypeScript 2.3.2 or earlier jspm install tslib@1.6.1 Usage \u00b6 Set the importHelpers compiler option on the command line: tsc --importHelpers file.ts or in your tsconfig.json: { \"compilerOptions\" : { \"importHelpers\" : true } } For bower and JSPM users \u00b6 You will need to add a paths mapping for tslib , e.g. For Bower users: { \"compilerOptions\" : { \"module\" : \"amd\" , \"importHelpers\" : true , \"baseUrl\" : \"./\" , \"paths\" : { \"tslib\" : [ \"bower_components/tslib/tslib.d.ts\" ] } } } For JSPM users: { \"compilerOptions\" : { \"module\" : \"system\" , \"importHelpers\" : true , \"baseUrl\" : \"./\" , \"paths\" : { \"tslib\" : [ \"jspm_packages/npm/tslib@1.9.3/tslib.d.ts\" ] } } } Contribute \u00b6 There are many ways to contribute to TypeScript. Submit bugs and help us verify fixes as they are checked in. Review the source code changes . Engage with other TypeScript users and developers on StackOverflow . Join the #typescript discussion on Twitter. Contribute bug fixes . Read the language specification ( docx , pdf ). Documentation \u00b6 Quick tutorial Programming handbook Language specification Homepage","title":"tslib"},{"location":"sp-addinhelpers/node_modules/tslib/#tslib","text":"This is a runtime library for TypeScript that contains all of the TypeScript helper functions. This library is primarily used by the --importHelpers flag in TypeScript. When using --importHelpers , a module that uses helper functions like __extends and __assign in the following emitted file: var __assign = ( this && this . __assign ) || Object . assign || function ( t ) { for ( var s , i = 1 , n = arguments . length ; i < n ; i ++ ) { s = arguments [ i ]; for ( var p in s ) if ( Object . prototype . hasOwnProperty . call ( s , p )) t [ p ] = s [ p ]; } return t ; }; exports . x = {}; exports . y = __assign ({}, exports . x ); will instead be emitted as something like the following: var tslib_1 = require ( \"tslib\" ); exports . x = {}; exports . y = tslib_1 . __assign ({}, exports . x ); Because this can avoid duplicate declarations of things like __extends , __assign , etc., this means delivering users smaller files on average, as well as less runtime overhead. For optimized bundles with TypeScript, you should absolutely consider using tslib and --importHelpers .","title":"tslib"},{"location":"sp-addinhelpers/node_modules/tslib/#installing","text":"For the latest stable version, run:","title":"Installing"},{"location":"sp-addinhelpers/node_modules/tslib/#npm","text":"# TypeScript 2.3.3 or later npm install --save tslib # TypeScript 2.3.2 or earlier npm install --save tslib@1.6.1","title":"npm"},{"location":"sp-addinhelpers/node_modules/tslib/#bower","text":"# TypeScript 2.3.3 or later bower install tslib # TypeScript 2.3.2 or earlier bower install tslib@1.6.1","title":"bower"},{"location":"sp-addinhelpers/node_modules/tslib/#jspm","text":"# TypeScript 2.3.3 or later jspm install tslib # TypeScript 2.3.2 or earlier jspm install tslib@1.6.1","title":"JSPM"},{"location":"sp-addinhelpers/node_modules/tslib/#usage","text":"Set the importHelpers compiler option on the command line: tsc --importHelpers file.ts or in your tsconfig.json: { \"compilerOptions\" : { \"importHelpers\" : true } }","title":"Usage"},{"location":"sp-addinhelpers/node_modules/tslib/#for-bower-and-jspm-users","text":"You will need to add a paths mapping for tslib , e.g. For Bower users: { \"compilerOptions\" : { \"module\" : \"amd\" , \"importHelpers\" : true , \"baseUrl\" : \"./\" , \"paths\" : { \"tslib\" : [ \"bower_components/tslib/tslib.d.ts\" ] } } } For JSPM users: { \"compilerOptions\" : { \"module\" : \"system\" , \"importHelpers\" : true , \"baseUrl\" : \"./\" , \"paths\" : { \"tslib\" : [ \"jspm_packages/npm/tslib@1.9.3/tslib.d.ts\" ] } } }","title":"For bower and JSPM users"},{"location":"sp-addinhelpers/node_modules/tslib/#contribute","text":"There are many ways to contribute to TypeScript. Submit bugs and help us verify fixes as they are checked in. Review the source code changes . Engage with other TypeScript users and developers on StackOverflow . Join the #typescript discussion on Twitter. Contribute bug fixes . Read the language specification ( docx , pdf ).","title":"Contribute"},{"location":"sp-addinhelpers/node_modules/tslib/#documentation","text":"Quick tutorial Programming handbook Language specification Homepage","title":"Documentation"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/","text":"The __generator helper \u00b6 The __generator helper is a function designed to support TypeScript's down-level emit for async functions when targeting ES5 and earlier. But how, exactly, does it work? Here's the body of the __generator helper: __generator = function ( thisArg , body ) { var _ = { label : 0 , sent : function () { if ( t [ 0 ] & 1 ) throw t [ 1 ]; return t [ 1 ]; }, trys : [], ops : [] }, f , y , t ; return { next : verb ( 0 ), \"throw\" : verb ( 1 ), \"return\" : verb ( 2 ) }; function verb ( n ) { return function ( v ) { return step ([ n , v ]); }; } function step ( op ) { if ( f ) throw new TypeError ( \"Generator is already executing.\" ); while ( _ ) try { if ( f = 1 , y && ( t = y [ op [ 0 ] & 2 ? \"return\" : op [ 0 ] ? \"throw\" : \"next\" ]) && ! ( t = t . call ( y , op [ 1 ])). done ) return t ; if ( y = 0 , t ) op = [ 0 , t . value ]; switch ( op [ 0 ]) { case 0 : case 1 : t = op ; break ; case 4 : _ . label ++ ; return { value : op [ 1 ], done : false }; case 5 : _ . label ++ ; y = op [ 1 ]; op = [ 0 ]; continue ; case 7 : op = _ . ops . pop (); _ . trys . pop (); continue ; default : if ( ! ( t = _ . trys , t = t . length > 0 && t [ t . length - 1 ]) && ( op [ 0 ] === 6 || op [ 0 ] === 2 )) { _ = 0 ; continue ; } if ( op [ 0 ] === 3 && ( ! t || ( op [ 1 ] > t [ 0 ] && op [ 1 ] < t [ 3 ]))) { _ . label = op [ 1 ]; break ; } if ( op [ 0 ] === 6 && _ . label < t [ 1 ]) { _ . label = t [ 1 ]; t = op ; break ; } if ( t && _ . label < t [ 2 ]) { _ . label = t [ 2 ]; _ . ops . push ( op ); break ; } if ( t [ 2 ]) _ . ops . pop (); _ . trys . pop (); continue ; } op = body . call ( thisArg , _ ); } catch ( e ) { op = [ 6 , e ]; y = 0 ; } finally { f = t = 0 ; } if ( op [ 0 ] & 5 ) throw op [ 1 ]; return { value : op [ 0 ] ? op [ 1 ] : void 0 , done : true }; } }; And here's an example of it in use: // source async function func ( x ) { try { await x ; } catch ( e ) { console . error ( e ); } finally { console . log ( \"finally\" ); } } // generated function func ( x ) { return __awaiter ( this , void 0 , void 0 , function () { var e_1 ; return __generator ( this , function ( _a ) { switch ( _a . label ) { case 0 : _a.trys.push ([ 0 , 1 , 3 , 4 ]); return [ 4 /*yield*/ , x ]; case 1 : _a.sent (); return [ 3 /*break*/ , 4 ]; case 2 : e_1 = _a . sent (); console . error ( e_1 ); return [ 3 /*break*/ , 4 ]; case 3 : console.log ( \"finally\" ); return [ 7 /*endfinally*/ ]; case 4 : return [ 2 /*return*/ ]; } }); }); } There is a lot going on in this function, so the following will break down what each part of the __generator helper does and how it works. Opcodes \u00b6 The __generator helper uses opcodes which represent various operations that are interpreted by the helper to affect its internal state. The following table lists the various opcodes, their arguments, and their purpose: Opcode Arguments Purpose 0 (next) value Starts the generator, or resumes the generator with value as the result of the AwaitExpression where execution was paused. 1 (throw) value Resumes the generator, throwing value at AwaitExpression where execution was paused. 2 (return) value Exits the generator, executing any finally blocks starting at the AwaitExpression where execution was paused. 3 (break) label Performs an unconditional jump to the specified label, executing any finally between the current instruction and the label. 4 (yield) value Suspends the generator, setting the resume point at the next label and yielding the value. 5 (yieldstar) value Suspends the generator, setting the resume point at the next label and delegating operations to the supplied value. 6 (catch) error An internal instruction used to indicate an exception that was thrown from the body of the generator. 7 (endfinally) Exits a finally block, resuming any previous operation (such as a break, return, throw, etc.) State \u00b6 The _ , f , y , and t variables make up the persistent state of the __generator function. Each variable has a specific purpose, as described in the following sections: The _ variable \u00b6 The __generator helper must share state between its internal step orchestration function and the body function passed to the helper. var _ = { label : 0 , sent : function () { if ( t [ 0 ] & 1 ) // NOTE: true for `throw`, but not `next` or `catch` throw t [ 1 ]; return sent [ 1 ]; }, trys : [], ops : [] }; The following table describes the members of the _ state object and their purpose: Name Description label Specifies the next switch case to execute in the body function. sent Handles the completion result passed to the generator. trys A stack of Protected Regions , which are 4-tuples that describe the labels that make up a try..catch..finally block. ops A stack of pending operations used for try..finally blocks. The __generator helper passes this state object to the body function for use with switching between switch cases in the body, handling completions from AwaitExpression , etc. The f variable \u00b6 The f variable indicates whether the generator is currently executing, to prevent re-entry of the same generator during its execution. The y variable \u00b6 The y variable stores the iterator passed to a yieldstar instruction to which operations should be delegated. The t variable \u00b6 The t variable is a temporary variable that stores one of the following values: The completion value when resuming from a yield or yield* . The error value for a catch block. The current Protected Region . The verb ( next , throw , or return method) to delegate to the expression of a yield* . The result of evaluating the verb delegated to the expression of a yield* . NOTE: None of the above cases overlap. Protected Regions \u00b6 A Protected Region is a region within the body function that indicates a try..catch..finally statement. It consists of a 4-tuple that contains 4 labels: Offset Description 0 Required The label that indicates the beginning of a try..catch..finally statement. 1 Optional The label that indicates the beginning of a catch clause. 2 Optional The label that indicates the beginning of a finally clause. 3 Required The label that indicates the end of the try..catch..finally statement. The generator object \u00b6 The final step of the __generator helper is the allocation of an object that implements the Generator protocol, to be used by the __awaiter helper: return { next : verb ( 0 ), \"throw\" : verb ( 1 ), \"return\" : verb ( 2 ) }; function verb ( n ) { return function ( v ) { return step ([ n , v ]); }; } This object translates calls to next , throw , and return to the appropriate Opcodes and invokes the step orchestration function to continue execution. The throw and return method names are quoted to better support ES3. Orchestration \u00b6 The step function is the main orechestration mechanism for the __generator helper. It interprets opcodes, handles protected regions , and communicates results back to the caller. Here's a closer look at the step function: function step ( op ) { if ( f ) throw new TypeError ( \"Generator is already executing.\" ); while ( _ ) try { if ( f = 1 , y && ( t = y [ op [ 0 ] & 2 ? \"return\" : op [ 0 ] ? \"throw\" : \"next\" ]) && ! ( t = t . call ( y , op [ 1 ])). done ) return t ; if ( y = 0 , t ) op = [ 0 , t . value ]; switch ( op [ 0 ]) { case 0 : case 1 : t = op ; break ; case 4 : _.label ++ ; return { value : op [ 1 ], done : false }; case 5 : _.label ++ ; y = op [ 1 ]; op = [ 0 ]; continue ; case 7 : op = _ . ops . pop (); _ . trys . pop (); continue ; default : if ( ! ( t = _ . trys , t = t . length > 0 && t [ t . length - 1 ]) && ( op [ 0 ] === 6 || op [ 0 ] === 2 )) { _ = 0 ; continue ; } if ( op [ 0 ] === 3 && ( ! t || ( op [ 1 ] > t [ 0 ] && op [ 1 ] < t [ 3 ]))) { _ . label = op [ 1 ]; break ; } if ( op [ 0 ] === 6 && _ . label < t [ 1 ]) { _ . label = t [ 1 ]; t = op ; break ; } if ( t && _ . label < t [ 2 ]) { _ . label = t [ 2 ]; _ . ops . push ( op ); break ; } if ( t [ 2 ]) _ . ops . pop (); _ . trys . pop (); continue ; } op = body . call ( thisArg , _ ); } catch ( e ) { op = [ 6 , e ]; y = 0 ; } finally { f = t = 0 ; } if ( op [ 0 ] & 5 ) throw op [ 1 ]; return { value : op [ 0 ] ? op [ 1 ] : void 0 , done : true }; } The main body of step exists in a while loop. This allows us to continually interpret operations until we have reached some completion value, be it a return , await , or throw . Preventing re-entry \u00b6 The first part of the step function is used as a check to prevent re-entry into a currently executing generator: if ( f ) throw new TypeError ( \"Generator is already executing.\" ); Running the generator \u00b6 The main body of the step function consists of a while loop which continues to evaluate instructions until the generator exits or is suspended: while ( _ ) try ... When the generator has run to completion, the _ state variable will be cleared, forcing the loop to exit. Evaluating the generator body. \u00b6 try { ... op = body . call ( thisArg , _ ); } catch ( e ) { op = [ 6 , e ]; y = 0 ; } finally { f = t = 0 ; } Depending on the current operation, we re-enter the generator body to start or continue execution. Here we invoke body with thisArg as the this binding and the _ state object as the only argument. The result is a tuple that contains the next Opcode and argument. If evaluation of the body resulted in an exception, we convert this into an Opcode 6 (\"catch\") operation to be handled in the next spin of the while loop. We also clear the y variable in case it is set to ensure we are no longer delegating operations as the exception occurred in user code outside of, or at the function boundary of, the delegated iterator (otherwise the iterator would have handled the exception itself). After executing user code, we clear the f flag that indicates we are executing the generator, as well as the t temporary value so that we don't hold onto values sent to the generator for longer than necessary. Inside of the try..finally statement are a series of statements that are used to evaluate the operations of the transformed generator body. The first thing we do is mark the generator as executing: if ( f = 1 , ...) Despite the fact this expression is part of the head of an if statement, the comma operator causes it to be evaluated and the result thrown out. This is a minification added purely to reduce the overall footprint of the helper. Delegating yield* \u00b6 The first two statements of the try..finally statement handle delegation for yield* : if ( f = 1 , y && ( t = y [ op [ 0 ] & 2 ? \"return\" : op [ 0 ] ? \"throw\" : \"next\" ]) && ! ( t = t . call ( y , op [ 1 ])). done ) return t ; if ( y = 0 , t ) op = [ 0 , t . value ]; If the y variable is set, and y has a next , throw , or return method (depending on the current operation), we invoke this method and store the return value (an IteratorResult) in t . If t indicates it is a yielded value (e.g. t.done === false ), we return t to the caller. If t indicates it is a returned value (e.g. t.done === true ), we mark the operation with the next Opcode, and the returned value. If y did not have the appropriate method, or t was a returned value, we reset y to a falsey value and continue processing the operation. Handling operations \u00b6 The various Opcodes are handled in the following switch statement: switch ( op [ 0 ]) { case 0 : case 1 : t = op ; break ; case 4 : _.label ++ ; return { value : op [ 1 ], done : false }; case 5 : _.label ++ ; y = op [ 1 ]; op = [ 0 ]; continue ; case 7 : op = _ . ops . pop (); _ . trys . pop (); continue ; default : if ( ! ( t = _ . trys , t = t . length > 0 && t [ t . length - 1 ]) && ( op [ 0 ] === 6 || op [ 0 ] === 2 )) { _ = 0 ; continue ; } if ( op [ 0 ] === 3 && ( ! t || ( op [ 1 ] > t [ 0 ] && op [ 1 ] < t [ 3 ]))) { _ . label = op [ 1 ]; break ; } if ( op [ 0 ] === 6 && _ . label < t [ 1 ]) { _ . label = t [ 1 ]; t = op ; break ; } if ( t && _ . label < t [ 2 ]) { _ . label = t [ 2 ]; _ . ops . push ( op ); break ; } if ( t [ 2 ]) _ . ops . pop (); _ . trys . pop (); continue ; } The following sections describe the various Opcodes: Opcode 0 (\"next\") and Opcode 1 (\"throw\") \u00b6 case 0 : // next case 1 : // throw t = op ; break ; Both Opcode 0 (\"next\") and Opcode 1 (\"throw\") have the same behavior. The current operation is stored in the t variable and the body function is invoked. The body function should call _.sent() which will evaluate the appropriate completion result. Opcode 4 (\"yield\") \u00b6 case 4 : // yield _ . label ++ ; return { value : op [ 1 ], done : false }; When we encounter Opcode 4 (\"yield\"), we increment the label by one to indicate the point at which the generator will resume execution. We then return an IteratorResult whose value is the yielded value, and done is false . Opcode 5 (\"yieldstar\") \u00b6 case 5 : // yieldstar _ . label ++ ; y = op [ 1 ]; op = [ 0 ]; continue ; When we receive Opcode 5 (\"yieldstar\"), we increment the label by one to indicate the point at which the generator will resume execution. We then store the iterator in op[1] in the y variable, and set the operation to delegate to Opcode 0 (\"next\") with no value. Finally, we continue execution at the top of the loop to start delegation. Opcode 7 (\"endfinally\") \u00b6 case 7 : op = _ . ops . pop (); _ . trys . pop (); continue ; Opcode 7 (\"endfinally\") indicates that we have hit the end of a finally clause, and that the last operation recorded before entering the finally block should be evaluated. Opcode 2 (\"return\"), Opcode 3 (\"break\"), and Opcode 6 (\"catch\") \u00b6 default : if ( ! ( t = _ . trys , t = t . length > 0 && t [ t . length - 1 ]) && ( op [ 0 ] === 6 || op [ 0 ] === 2 )) { _ = 0 ; continue ; } if ( op [ 0 ] === 3 && ( ! t || ( op [ 1 ] > t [ 0 ] && op [ 1 ] < t [ 3 ]))) { _ . label = op [ 1 ]; break ; } if ( op [ 0 ] === 6 && _ . label < t [ 1 ]) { _ . label = t [ 1 ]; t = op ; break ; } if ( t && _ . label < t [ 2 ]) { _ . label = t [ 2 ]; _ . ops . push ( op ); break ; } if ( t [ 2 ]) _ . ops . pop (); _ . trys . pop (); continue ; } The handling for Opcode 2 (\"return\"), Opcode 3 (\"break\") and Opcode 6 (\"catch\") is more complicated, as we must obey the specified runtime semantics of generators. The first line in this clause gets the current Protected Region if found and stores it in the t temp variable: if ( ! ( t = _ . trys , t = t . length > 0 && t [ t . length - 1 ]) && ...) ... The remainder of this statement, as well as the following by several if statements test for more complex conditions. The first of these is the following: if ( ! ( t = ...) && ( op [ 0 ] === 6 || op [ 0 ] === 2 )) { _ = 0 ; continue ; } If we encounter an Opcode 6 (\"catch\") or Opcode 2 (\"return\"), and we are not in a protected region, then this operation completes the generator by setting the _ variable to a falsey value. The continue statement resumes execution at the top of the while statement, which will exit the loop so that we continue execution at the statement following the loop. if ( op [ 0 ] === 3 && ( ! t || ( op [ 1 ] > t [ 0 ] && op [ 1 ] < t [ 3 ]))) { _ . label = op [ 1 ]; break ; } The if statement above handles Opcode 3 (\"break\") when we are either not in a protected region , or are performing an unconditional jump to a label inside of the current protected region . In this case we can unconditionally jump to the specified label. if ( op [ 0 ] === 6 && _ . label < t [ 1 ]) { _ . label = t [ 1 ]; t = op ; break ; } The if statement above handles Opcode 6 (\"catch\") when inside the try block of a protected region . In this case we jump to the catch block, if present. We replace the value of t with the operation so that the exception can be read as the first statement of the transformed catch clause of the transformed generator body. if ( t && _ . label < t [ 2 ]) { _ . label = t [ 2 ]; _ . ops . push ( op ); break ; } This if statement handles all Opcodes when in a protected region with a finally clause. As long as we are not already inside the finally clause, we jump to the finally clause and push the pending operation onto the _.ops stack. This allows us to resume execution of the pending operation once we have completed execution of the finally clause, as long as it does not supersede this operation with its own completion value. if ( t [ 2 ]) _ . ops . pop (); Any other completion value inside of a finally clause will supersede the pending completion value from the try or catch clauses. The above if statement pops the pending completion from the stack. _ . trys . pop (); continue ; The remaining statements handle the point at which we exit a protected region . Here we pop the current protected region from the stack and spin the while statement to evaluate the current operation again in the next protected region or at the function boundary. Handling a completed generator \u00b6 Once the generator has completed, the _ state variable will be falsey. As a result, the while loop will terminate and hand control off to the final statement of the orchestration function, which deals with how a completed generator is evaluated: if ( op [ 0 ] & 5 ) throw op [ 1 ]; return { value : op [ 0 ] ? op [ 1 ] : void 0 , done : true }; If the caller calls throw on the generator it will send Opcode 1 (\"throw\"). If an exception is uncaught within the body of the generator, it will send Opcode 6 (\"catch\"). As the generator has completed, it throws the exception. Both of these cases are caught by the bitmask 5 , which does not collide with the only two other valid completion Opcodes. If the caller calls next on the generator, it will send Opcode 0 (\"next\"). As the generator has completed, it returns an IteratorResult where value is undefined and done is true. If the caller calls return on the generator, it will send Opcode 2 (\"return\"). As the generator has completed, it returns an IteratorResult where value is the value provided to return , and done is true.","title":"The `__generator` helper"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#the-__generator-helper","text":"The __generator helper is a function designed to support TypeScript's down-level emit for async functions when targeting ES5 and earlier. But how, exactly, does it work? Here's the body of the __generator helper: __generator = function ( thisArg , body ) { var _ = { label : 0 , sent : function () { if ( t [ 0 ] & 1 ) throw t [ 1 ]; return t [ 1 ]; }, trys : [], ops : [] }, f , y , t ; return { next : verb ( 0 ), \"throw\" : verb ( 1 ), \"return\" : verb ( 2 ) }; function verb ( n ) { return function ( v ) { return step ([ n , v ]); }; } function step ( op ) { if ( f ) throw new TypeError ( \"Generator is already executing.\" ); while ( _ ) try { if ( f = 1 , y && ( t = y [ op [ 0 ] & 2 ? \"return\" : op [ 0 ] ? \"throw\" : \"next\" ]) && ! ( t = t . call ( y , op [ 1 ])). done ) return t ; if ( y = 0 , t ) op = [ 0 , t . value ]; switch ( op [ 0 ]) { case 0 : case 1 : t = op ; break ; case 4 : _ . label ++ ; return { value : op [ 1 ], done : false }; case 5 : _ . label ++ ; y = op [ 1 ]; op = [ 0 ]; continue ; case 7 : op = _ . ops . pop (); _ . trys . pop (); continue ; default : if ( ! ( t = _ . trys , t = t . length > 0 && t [ t . length - 1 ]) && ( op [ 0 ] === 6 || op [ 0 ] === 2 )) { _ = 0 ; continue ; } if ( op [ 0 ] === 3 && ( ! t || ( op [ 1 ] > t [ 0 ] && op [ 1 ] < t [ 3 ]))) { _ . label = op [ 1 ]; break ; } if ( op [ 0 ] === 6 && _ . label < t [ 1 ]) { _ . label = t [ 1 ]; t = op ; break ; } if ( t && _ . label < t [ 2 ]) { _ . label = t [ 2 ]; _ . ops . push ( op ); break ; } if ( t [ 2 ]) _ . ops . pop (); _ . trys . pop (); continue ; } op = body . call ( thisArg , _ ); } catch ( e ) { op = [ 6 , e ]; y = 0 ; } finally { f = t = 0 ; } if ( op [ 0 ] & 5 ) throw op [ 1 ]; return { value : op [ 0 ] ? op [ 1 ] : void 0 , done : true }; } }; And here's an example of it in use: // source async function func ( x ) { try { await x ; } catch ( e ) { console . error ( e ); } finally { console . log ( \"finally\" ); } } // generated function func ( x ) { return __awaiter ( this , void 0 , void 0 , function () { var e_1 ; return __generator ( this , function ( _a ) { switch ( _a . label ) { case 0 : _a.trys.push ([ 0 , 1 , 3 , 4 ]); return [ 4 /*yield*/ , x ]; case 1 : _a.sent (); return [ 3 /*break*/ , 4 ]; case 2 : e_1 = _a . sent (); console . error ( e_1 ); return [ 3 /*break*/ , 4 ]; case 3 : console.log ( \"finally\" ); return [ 7 /*endfinally*/ ]; case 4 : return [ 2 /*return*/ ]; } }); }); } There is a lot going on in this function, so the following will break down what each part of the __generator helper does and how it works.","title":"The __generator helper"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#opcodes","text":"The __generator helper uses opcodes which represent various operations that are interpreted by the helper to affect its internal state. The following table lists the various opcodes, their arguments, and their purpose: Opcode Arguments Purpose 0 (next) value Starts the generator, or resumes the generator with value as the result of the AwaitExpression where execution was paused. 1 (throw) value Resumes the generator, throwing value at AwaitExpression where execution was paused. 2 (return) value Exits the generator, executing any finally blocks starting at the AwaitExpression where execution was paused. 3 (break) label Performs an unconditional jump to the specified label, executing any finally between the current instruction and the label. 4 (yield) value Suspends the generator, setting the resume point at the next label and yielding the value. 5 (yieldstar) value Suspends the generator, setting the resume point at the next label and delegating operations to the supplied value. 6 (catch) error An internal instruction used to indicate an exception that was thrown from the body of the generator. 7 (endfinally) Exits a finally block, resuming any previous operation (such as a break, return, throw, etc.)","title":"Opcodes"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#state","text":"The _ , f , y , and t variables make up the persistent state of the __generator function. Each variable has a specific purpose, as described in the following sections:","title":"State"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#the-_-variable","text":"The __generator helper must share state between its internal step orchestration function and the body function passed to the helper. var _ = { label : 0 , sent : function () { if ( t [ 0 ] & 1 ) // NOTE: true for `throw`, but not `next` or `catch` throw t [ 1 ]; return sent [ 1 ]; }, trys : [], ops : [] }; The following table describes the members of the _ state object and their purpose: Name Description label Specifies the next switch case to execute in the body function. sent Handles the completion result passed to the generator. trys A stack of Protected Regions , which are 4-tuples that describe the labels that make up a try..catch..finally block. ops A stack of pending operations used for try..finally blocks. The __generator helper passes this state object to the body function for use with switching between switch cases in the body, handling completions from AwaitExpression , etc.","title":"The _ variable"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#the-f-variable","text":"The f variable indicates whether the generator is currently executing, to prevent re-entry of the same generator during its execution.","title":"The f variable"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#the-y-variable","text":"The y variable stores the iterator passed to a yieldstar instruction to which operations should be delegated.","title":"The y variable"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#the-t-variable","text":"The t variable is a temporary variable that stores one of the following values: The completion value when resuming from a yield or yield* . The error value for a catch block. The current Protected Region . The verb ( next , throw , or return method) to delegate to the expression of a yield* . The result of evaluating the verb delegated to the expression of a yield* . NOTE: None of the above cases overlap.","title":"The t variable"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#protected-regions","text":"A Protected Region is a region within the body function that indicates a try..catch..finally statement. It consists of a 4-tuple that contains 4 labels: Offset Description 0 Required The label that indicates the beginning of a try..catch..finally statement. 1 Optional The label that indicates the beginning of a catch clause. 2 Optional The label that indicates the beginning of a finally clause. 3 Required The label that indicates the end of the try..catch..finally statement.","title":"Protected Regions"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#the-generator-object","text":"The final step of the __generator helper is the allocation of an object that implements the Generator protocol, to be used by the __awaiter helper: return { next : verb ( 0 ), \"throw\" : verb ( 1 ), \"return\" : verb ( 2 ) }; function verb ( n ) { return function ( v ) { return step ([ n , v ]); }; } This object translates calls to next , throw , and return to the appropriate Opcodes and invokes the step orchestration function to continue execution. The throw and return method names are quoted to better support ES3.","title":"The generator object"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#orchestration","text":"The step function is the main orechestration mechanism for the __generator helper. It interprets opcodes, handles protected regions , and communicates results back to the caller. Here's a closer look at the step function: function step ( op ) { if ( f ) throw new TypeError ( \"Generator is already executing.\" ); while ( _ ) try { if ( f = 1 , y && ( t = y [ op [ 0 ] & 2 ? \"return\" : op [ 0 ] ? \"throw\" : \"next\" ]) && ! ( t = t . call ( y , op [ 1 ])). done ) return t ; if ( y = 0 , t ) op = [ 0 , t . value ]; switch ( op [ 0 ]) { case 0 : case 1 : t = op ; break ; case 4 : _.label ++ ; return { value : op [ 1 ], done : false }; case 5 : _.label ++ ; y = op [ 1 ]; op = [ 0 ]; continue ; case 7 : op = _ . ops . pop (); _ . trys . pop (); continue ; default : if ( ! ( t = _ . trys , t = t . length > 0 && t [ t . length - 1 ]) && ( op [ 0 ] === 6 || op [ 0 ] === 2 )) { _ = 0 ; continue ; } if ( op [ 0 ] === 3 && ( ! t || ( op [ 1 ] > t [ 0 ] && op [ 1 ] < t [ 3 ]))) { _ . label = op [ 1 ]; break ; } if ( op [ 0 ] === 6 && _ . label < t [ 1 ]) { _ . label = t [ 1 ]; t = op ; break ; } if ( t && _ . label < t [ 2 ]) { _ . label = t [ 2 ]; _ . ops . push ( op ); break ; } if ( t [ 2 ]) _ . ops . pop (); _ . trys . pop (); continue ; } op = body . call ( thisArg , _ ); } catch ( e ) { op = [ 6 , e ]; y = 0 ; } finally { f = t = 0 ; } if ( op [ 0 ] & 5 ) throw op [ 1 ]; return { value : op [ 0 ] ? op [ 1 ] : void 0 , done : true }; } The main body of step exists in a while loop. This allows us to continually interpret operations until we have reached some completion value, be it a return , await , or throw .","title":"Orchestration"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#preventing-re-entry","text":"The first part of the step function is used as a check to prevent re-entry into a currently executing generator: if ( f ) throw new TypeError ( \"Generator is already executing.\" );","title":"Preventing re-entry"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#running-the-generator","text":"The main body of the step function consists of a while loop which continues to evaluate instructions until the generator exits or is suspended: while ( _ ) try ... When the generator has run to completion, the _ state variable will be cleared, forcing the loop to exit.","title":"Running the generator"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#evaluating-the-generator-body","text":"try { ... op = body . call ( thisArg , _ ); } catch ( e ) { op = [ 6 , e ]; y = 0 ; } finally { f = t = 0 ; } Depending on the current operation, we re-enter the generator body to start or continue execution. Here we invoke body with thisArg as the this binding and the _ state object as the only argument. The result is a tuple that contains the next Opcode and argument. If evaluation of the body resulted in an exception, we convert this into an Opcode 6 (\"catch\") operation to be handled in the next spin of the while loop. We also clear the y variable in case it is set to ensure we are no longer delegating operations as the exception occurred in user code outside of, or at the function boundary of, the delegated iterator (otherwise the iterator would have handled the exception itself). After executing user code, we clear the f flag that indicates we are executing the generator, as well as the t temporary value so that we don't hold onto values sent to the generator for longer than necessary. Inside of the try..finally statement are a series of statements that are used to evaluate the operations of the transformed generator body. The first thing we do is mark the generator as executing: if ( f = 1 , ...) Despite the fact this expression is part of the head of an if statement, the comma operator causes it to be evaluated and the result thrown out. This is a minification added purely to reduce the overall footprint of the helper.","title":"Evaluating the generator body."},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#delegating-yield","text":"The first two statements of the try..finally statement handle delegation for yield* : if ( f = 1 , y && ( t = y [ op [ 0 ] & 2 ? \"return\" : op [ 0 ] ? \"throw\" : \"next\" ]) && ! ( t = t . call ( y , op [ 1 ])). done ) return t ; if ( y = 0 , t ) op = [ 0 , t . value ]; If the y variable is set, and y has a next , throw , or return method (depending on the current operation), we invoke this method and store the return value (an IteratorResult) in t . If t indicates it is a yielded value (e.g. t.done === false ), we return t to the caller. If t indicates it is a returned value (e.g. t.done === true ), we mark the operation with the next Opcode, and the returned value. If y did not have the appropriate method, or t was a returned value, we reset y to a falsey value and continue processing the operation.","title":"Delegating yield*"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#handling-operations","text":"The various Opcodes are handled in the following switch statement: switch ( op [ 0 ]) { case 0 : case 1 : t = op ; break ; case 4 : _.label ++ ; return { value : op [ 1 ], done : false }; case 5 : _.label ++ ; y = op [ 1 ]; op = [ 0 ]; continue ; case 7 : op = _ . ops . pop (); _ . trys . pop (); continue ; default : if ( ! ( t = _ . trys , t = t . length > 0 && t [ t . length - 1 ]) && ( op [ 0 ] === 6 || op [ 0 ] === 2 )) { _ = 0 ; continue ; } if ( op [ 0 ] === 3 && ( ! t || ( op [ 1 ] > t [ 0 ] && op [ 1 ] < t [ 3 ]))) { _ . label = op [ 1 ]; break ; } if ( op [ 0 ] === 6 && _ . label < t [ 1 ]) { _ . label = t [ 1 ]; t = op ; break ; } if ( t && _ . label < t [ 2 ]) { _ . label = t [ 2 ]; _ . ops . push ( op ); break ; } if ( t [ 2 ]) _ . ops . pop (); _ . trys . pop (); continue ; } The following sections describe the various Opcodes:","title":"Handling operations"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#opcode-0-next-and-opcode-1-throw","text":"case 0 : // next case 1 : // throw t = op ; break ; Both Opcode 0 (\"next\") and Opcode 1 (\"throw\") have the same behavior. The current operation is stored in the t variable and the body function is invoked. The body function should call _.sent() which will evaluate the appropriate completion result.","title":"Opcode 0 (\"next\") and Opcode 1 (\"throw\")"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#opcode-4-yield","text":"case 4 : // yield _ . label ++ ; return { value : op [ 1 ], done : false }; When we encounter Opcode 4 (\"yield\"), we increment the label by one to indicate the point at which the generator will resume execution. We then return an IteratorResult whose value is the yielded value, and done is false .","title":"Opcode 4 (\"yield\")"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#opcode-5-yieldstar","text":"case 5 : // yieldstar _ . label ++ ; y = op [ 1 ]; op = [ 0 ]; continue ; When we receive Opcode 5 (\"yieldstar\"), we increment the label by one to indicate the point at which the generator will resume execution. We then store the iterator in op[1] in the y variable, and set the operation to delegate to Opcode 0 (\"next\") with no value. Finally, we continue execution at the top of the loop to start delegation.","title":"Opcode 5 (\"yieldstar\")"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#opcode-7-endfinally","text":"case 7 : op = _ . ops . pop (); _ . trys . pop (); continue ; Opcode 7 (\"endfinally\") indicates that we have hit the end of a finally clause, and that the last operation recorded before entering the finally block should be evaluated.","title":"Opcode 7 (\"endfinally\")"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#opcode-2-return-opcode-3-break-and-opcode-6-catch","text":"default : if ( ! ( t = _ . trys , t = t . length > 0 && t [ t . length - 1 ]) && ( op [ 0 ] === 6 || op [ 0 ] === 2 )) { _ = 0 ; continue ; } if ( op [ 0 ] === 3 && ( ! t || ( op [ 1 ] > t [ 0 ] && op [ 1 ] < t [ 3 ]))) { _ . label = op [ 1 ]; break ; } if ( op [ 0 ] === 6 && _ . label < t [ 1 ]) { _ . label = t [ 1 ]; t = op ; break ; } if ( t && _ . label < t [ 2 ]) { _ . label = t [ 2 ]; _ . ops . push ( op ); break ; } if ( t [ 2 ]) _ . ops . pop (); _ . trys . pop (); continue ; } The handling for Opcode 2 (\"return\"), Opcode 3 (\"break\") and Opcode 6 (\"catch\") is more complicated, as we must obey the specified runtime semantics of generators. The first line in this clause gets the current Protected Region if found and stores it in the t temp variable: if ( ! ( t = _ . trys , t = t . length > 0 && t [ t . length - 1 ]) && ...) ... The remainder of this statement, as well as the following by several if statements test for more complex conditions. The first of these is the following: if ( ! ( t = ...) && ( op [ 0 ] === 6 || op [ 0 ] === 2 )) { _ = 0 ; continue ; } If we encounter an Opcode 6 (\"catch\") or Opcode 2 (\"return\"), and we are not in a protected region, then this operation completes the generator by setting the _ variable to a falsey value. The continue statement resumes execution at the top of the while statement, which will exit the loop so that we continue execution at the statement following the loop. if ( op [ 0 ] === 3 && ( ! t || ( op [ 1 ] > t [ 0 ] && op [ 1 ] < t [ 3 ]))) { _ . label = op [ 1 ]; break ; } The if statement above handles Opcode 3 (\"break\") when we are either not in a protected region , or are performing an unconditional jump to a label inside of the current protected region . In this case we can unconditionally jump to the specified label. if ( op [ 0 ] === 6 && _ . label < t [ 1 ]) { _ . label = t [ 1 ]; t = op ; break ; } The if statement above handles Opcode 6 (\"catch\") when inside the try block of a protected region . In this case we jump to the catch block, if present. We replace the value of t with the operation so that the exception can be read as the first statement of the transformed catch clause of the transformed generator body. if ( t && _ . label < t [ 2 ]) { _ . label = t [ 2 ]; _ . ops . push ( op ); break ; } This if statement handles all Opcodes when in a protected region with a finally clause. As long as we are not already inside the finally clause, we jump to the finally clause and push the pending operation onto the _.ops stack. This allows us to resume execution of the pending operation once we have completed execution of the finally clause, as long as it does not supersede this operation with its own completion value. if ( t [ 2 ]) _ . ops . pop (); Any other completion value inside of a finally clause will supersede the pending completion value from the try or catch clauses. The above if statement pops the pending completion from the stack. _ . trys . pop (); continue ; The remaining statements handle the point at which we exit a protected region . Here we pop the current protected region from the stack and spin the while statement to evaluate the current operation again in the next protected region or at the function boundary.","title":"Opcode 2 (\"return\"), Opcode 3 (\"break\"), and Opcode 6 (\"catch\")"},{"location":"sp-addinhelpers/node_modules/tslib/docs/generator/#handling-a-completed-generator","text":"Once the generator has completed, the _ state variable will be falsey. As a result, the while loop will terminate and hand control off to the final statement of the orchestration function, which deals with how a completed generator is evaluated: if ( op [ 0 ] & 5 ) throw op [ 1 ]; return { value : op [ 0 ] ? op [ 1 ] : void 0 , done : true }; If the caller calls throw on the generator it will send Opcode 1 (\"throw\"). If an exception is uncaught within the body of the generator, it will send Opcode 6 (\"catch\"). As the generator has completed, it throws the exception. Both of these cases are caught by the bitmask 5 , which does not collide with the only two other valid completion Opcodes. If the caller calls next on the generator, it will send Opcode 0 (\"next\"). As the generator has completed, it returns an IteratorResult where value is undefined and done is true. If the caller calls return on the generator, it will send Opcode 2 (\"return\"). As the generator has completed, it returns an IteratorResult where value is the value provided to return , and done is true.","title":"Handling a completed generator"},{"location":"sp-clientsvc/docs/","text":"@pnp/sp-clientsvc \u00b6 This library provides base classes for working with the legacy SharePoint client.svc/ProcessQuery endpoint. The base classes support most of the possibilities for types of query calls, as well as supporting fluent batching and caching. They are based on the same @pnp/queryable foundation as the other libraries so should feel familiar when extending. You can see @pnp/sp-taxonomy for an example showing how to extend these base classes into a functional fluent model. UML \u00b6 Graphical UML diagram of @pnp/sp-clientsvc. Right-click the diagram and open in new tab if it is too small.","title":"sp-clientsvc"},{"location":"sp-clientsvc/docs/#pnpsp-clientsvc","text":"This library provides base classes for working with the legacy SharePoint client.svc/ProcessQuery endpoint. The base classes support most of the possibilities for types of query calls, as well as supporting fluent batching and caching. They are based on the same @pnp/queryable foundation as the other libraries so should feel familiar when extending. You can see @pnp/sp-taxonomy for an example showing how to extend these base classes into a functional fluent model.","title":"@pnp/sp-clientsvc"},{"location":"sp-clientsvc/docs/#uml","text":"Graphical UML diagram of @pnp/sp-clientsvc. Right-click the diagram and open in new tab if it is too small.","title":"UML"},{"location":"sp-taxonomy/docs/","text":"@pnp/sp-taxonomy \u00b6 This module provides a fluent interface for working with the SharePoint term store. It does not rely on SP.taxonomy.js or other dependencies outside the @pnp scope. It is designed to function in a similar manner and present a similar feel to the other data retrieval libraries. It works by calling the \"/_vti_bin/client.svc/ProcessQuery\" endpoint. Getting Started \u00b6 You will need to install the @pnp/sp-taxonomy package as well as the packages it requires to run. npm install @pnp/logging @pnp/core @pnp/queryable @pnp/sp @pnp/sp-taxonomy @pnp/sp-clientsvc --save Root Object \u00b6 All fluent taxonomy operations originate from the Taxonomy object. You can access it in several ways. Import existing instance \u00b6 This method will grab an existing instance of the Taxonomy class and allow you to immediately chain additional methods. import { taxonomy } from \"@pnp/sp-taxonomy\" ; await taxonomy . termStores . get (); Import class and create instance \u00b6 You can also import the Taxonomy class and create a new instance. This useful in those cases where you want to work with taxonomy in another web than the current web. import { Session } from \"@pnp/sp-taxonomy\" ; const taxonomy = new Session ( \"https://mytenant.sharepoint.com/sites/dev\" ); await taxonomy . termStores . get (); Setup \u00b6 Because the sp-taxonomy library uses the same @pnp/queryable request pipeline as the other libraries you can call the setup method with the same options used for the @pnp/sp library. The setup method is provided as shorthand and avoids the need to import anything from @pnp/sp if you do not need to. A call to this setup method is equivilent to calling the sp.setup method and the configuration is shared between the libraries within your application. In the below example all requests for the @pnp/sp-taxonomy library and the @pnp/sp library will be routed through the specified SPFetchClient. Sharing the configuration like this handles the most common scenario of working on the same web easily. You can set other values here as well such as baseUrl and they will be respected by both libraries. import { taxonomy } from \"@pnp/sp-taxonomy\" ; import { SPFetchClient } from \"@pnp/nodejs\" ; // example for setting up the node client using setup method // we also set a custom header, as an example taxonomy . setup ({ sp : { fetchClientFactory : () => { return new SPFetchClient ( \"{url}\" , \"{client id}\" , \"{client secret}\" ); }, headers : { \"X-Custom-Header\" : \"A Great Value\" , }, }, }); Library Topics \u00b6 Term Stores Term Groups Term Sets Terms Labels UML \u00b6 Graphical UML diagram of @pnp/sp-taxonomy. Right-click the diagram and open in new tab if it is too small.","title":"sp-taxonomy"},{"location":"sp-taxonomy/docs/#pnpsp-taxonomy","text":"This module provides a fluent interface for working with the SharePoint term store. It does not rely on SP.taxonomy.js or other dependencies outside the @pnp scope. It is designed to function in a similar manner and present a similar feel to the other data retrieval libraries. It works by calling the \"/_vti_bin/client.svc/ProcessQuery\" endpoint.","title":"@pnp/sp-taxonomy"},{"location":"sp-taxonomy/docs/#getting-started","text":"You will need to install the @pnp/sp-taxonomy package as well as the packages it requires to run. npm install @pnp/logging @pnp/core @pnp/queryable @pnp/sp @pnp/sp-taxonomy @pnp/sp-clientsvc --save","title":"Getting Started"},{"location":"sp-taxonomy/docs/#root-object","text":"All fluent taxonomy operations originate from the Taxonomy object. You can access it in several ways.","title":"Root Object"},{"location":"sp-taxonomy/docs/#import-existing-instance","text":"This method will grab an existing instance of the Taxonomy class and allow you to immediately chain additional methods. import { taxonomy } from \"@pnp/sp-taxonomy\" ; await taxonomy . termStores . get ();","title":"Import existing instance"},{"location":"sp-taxonomy/docs/#import-class-and-create-instance","text":"You can also import the Taxonomy class and create a new instance. This useful in those cases where you want to work with taxonomy in another web than the current web. import { Session } from \"@pnp/sp-taxonomy\" ; const taxonomy = new Session ( \"https://mytenant.sharepoint.com/sites/dev\" ); await taxonomy . termStores . get ();","title":"Import class and create instance"},{"location":"sp-taxonomy/docs/#setup","text":"Because the sp-taxonomy library uses the same @pnp/queryable request pipeline as the other libraries you can call the setup method with the same options used for the @pnp/sp library. The setup method is provided as shorthand and avoids the need to import anything from @pnp/sp if you do not need to. A call to this setup method is equivilent to calling the sp.setup method and the configuration is shared between the libraries within your application. In the below example all requests for the @pnp/sp-taxonomy library and the @pnp/sp library will be routed through the specified SPFetchClient. Sharing the configuration like this handles the most common scenario of working on the same web easily. You can set other values here as well such as baseUrl and they will be respected by both libraries. import { taxonomy } from \"@pnp/sp-taxonomy\" ; import { SPFetchClient } from \"@pnp/nodejs\" ; // example for setting up the node client using setup method // we also set a custom header, as an example taxonomy . setup ({ sp : { fetchClientFactory : () => { return new SPFetchClient ( \"{url}\" , \"{client id}\" , \"{client secret}\" ); }, headers : { \"X-Custom-Header\" : \"A Great Value\" , }, }, });","title":"Setup"},{"location":"sp-taxonomy/docs/#library-topics","text":"Term Stores Term Groups Term Sets Terms Labels","title":"Library Topics"},{"location":"sp-taxonomy/docs/#uml","text":"Graphical UML diagram of @pnp/sp-taxonomy. Right-click the diagram and open in new tab if it is too small.","title":"UML"},{"location":"sp-taxonomy/docs/labels/","text":"@pnp/sp-taxonomy/labels \u00b6 Load labels \u00b6 You can load labels by accessing the labels property of a term . import { ILabel , ILabelData , ITerm } from \"@pnp/sp-taxonomy\" ; const term : ITerm = < see terms article for loading term > // load the terms merged with data const labelsWithData : ( ILabel & ILabelData )[] = await term . labels . get (); // get a label by value const label : ILabel = term . labels . getByValue ( \"term value\" ); // get a label merged with data const label2 : ILabel & ILabelData = term . labels . getByValue ( \"term value\" ). get (); Label Properties and Methods \u00b6 setAsDefaultForLanguage \u00b6 Sets this labels as the default for the language import { ILabel , ILabelData , ITerm } from \"@pnp/sp-taxonomy\" ; const term : ITerm = < see terms article for loading term > // get a label by value await term . labels . getByValue ( \"term value\" ). setAsDefaultForLanguage (); delete \u00b6 Deletes this label import { ILabel , ILabelData , ITerm } from \"@pnp/sp-taxonomy\" ; const term : ITerm = < see terms article for loading term > // get a label by value await term . labels . getByValue ( \"term value\" ). delete ();","title":"Labels"},{"location":"sp-taxonomy/docs/labels/#pnpsp-taxonomylabels","text":"","title":"@pnp/sp-taxonomy/labels"},{"location":"sp-taxonomy/docs/labels/#load-labels","text":"You can load labels by accessing the labels property of a term . import { ILabel , ILabelData , ITerm } from \"@pnp/sp-taxonomy\" ; const term : ITerm = < see terms article for loading term > // load the terms merged with data const labelsWithData : ( ILabel & ILabelData )[] = await term . labels . get (); // get a label by value const label : ILabel = term . labels . getByValue ( \"term value\" ); // get a label merged with data const label2 : ILabel & ILabelData = term . labels . getByValue ( \"term value\" ). get ();","title":"Load labels"},{"location":"sp-taxonomy/docs/labels/#label-properties-and-methods","text":"","title":"Label Properties and Methods"},{"location":"sp-taxonomy/docs/labels/#setasdefaultforlanguage","text":"Sets this labels as the default for the language import { ILabel , ILabelData , ITerm } from \"@pnp/sp-taxonomy\" ; const term : ITerm = < see terms article for loading term > // get a label by value await term . labels . getByValue ( \"term value\" ). setAsDefaultForLanguage ();","title":"setAsDefaultForLanguage"},{"location":"sp-taxonomy/docs/labels/#delete","text":"Deletes this label import { ILabel , ILabelData , ITerm } from \"@pnp/sp-taxonomy\" ; const term : ITerm = < see terms article for loading term > // get a label by value await term . labels . getByValue ( \"term value\" ). delete ();","title":"delete"},{"location":"sp-taxonomy/docs/term-groups/","text":"@pnp/sp-taxonomy/termgroups \u00b6 Term groups are used as a container for terms within a term store. Load a term group \u00b6 Term groups are loaded from a term store import { taxonomy , ITermStore , ITermGroup } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const group : ITermGroup = store . getTermGroupById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); Term Group methods and properties \u00b6 addContributor \u00b6 Adds a contributor to the Group import { taxonomy , ITermStore , ITermGroup } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const group : ITermGroup = store . getTermGroupById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); await group . addContributor ( \"i:0#.f|membership|person@tenant.com\" ); addGroupManager \u00b6 Adds a group manager to the Group import { taxonomy , ITermStore , ITermGroup } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const group : ITermGroup = store . getTermGroupById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); await group . addGroupManager ( \"i:0#.f|membership|person@tenant.com\" ); createTermSet \u00b6 Creates a new term set import { taxonomy , ITermStore , ITermGroup , ITermSet , ITermSetData } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const group : ITermGroup = store . getTermGroupById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); const set : ITermSet & ITermSetData = await group . createTermSet ( \"name\" , 1031 ); // you can optionally supply the term set id, if you do not we create a new id for you const set2 : ITermSet & ITermSetData = await group . createTermSet ( \"name\" , 1031 , \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); get \u00b6 Gets this term group's data import { taxonomy , ITermStore , ITermGroupData , ITermGroup } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const group : ITermGroup & ITermGroupData = store . getTermGroupById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ). get ();","title":"Term Groups"},{"location":"sp-taxonomy/docs/term-groups/#pnpsp-taxonomytermgroups","text":"Term groups are used as a container for terms within a term store.","title":"@pnp/sp-taxonomy/termgroups"},{"location":"sp-taxonomy/docs/term-groups/#load-a-term-group","text":"Term groups are loaded from a term store import { taxonomy , ITermStore , ITermGroup } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const group : ITermGroup = store . getTermGroupById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" );","title":"Load a term group"},{"location":"sp-taxonomy/docs/term-groups/#term-group-methods-and-properties","text":"","title":"Term Group methods and properties"},{"location":"sp-taxonomy/docs/term-groups/#addcontributor","text":"Adds a contributor to the Group import { taxonomy , ITermStore , ITermGroup } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const group : ITermGroup = store . getTermGroupById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); await group . addContributor ( \"i:0#.f|membership|person@tenant.com\" );","title":"addContributor"},{"location":"sp-taxonomy/docs/term-groups/#addgroupmanager","text":"Adds a group manager to the Group import { taxonomy , ITermStore , ITermGroup } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const group : ITermGroup = store . getTermGroupById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); await group . addGroupManager ( \"i:0#.f|membership|person@tenant.com\" );","title":"addGroupManager"},{"location":"sp-taxonomy/docs/term-groups/#createtermset","text":"Creates a new term set import { taxonomy , ITermStore , ITermGroup , ITermSet , ITermSetData } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const group : ITermGroup = store . getTermGroupById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); const set : ITermSet & ITermSetData = await group . createTermSet ( \"name\" , 1031 ); // you can optionally supply the term set id, if you do not we create a new id for you const set2 : ITermSet & ITermSetData = await group . createTermSet ( \"name\" , 1031 , \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" );","title":"createTermSet"},{"location":"sp-taxonomy/docs/term-groups/#get","text":"Gets this term group's data import { taxonomy , ITermStore , ITermGroupData , ITermGroup } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const group : ITermGroup & ITermGroupData = store . getTermGroupById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ). get ();","title":"get"},{"location":"sp-taxonomy/docs/term-sets/","text":"@pnp/sp-taxonomy/termsets \u00b6 Term sets contain terms within the taxonomy heirarchy. Load a term set \u00b6 You load a term set directly from a term store. import { taxonomy , ITermStore , ITermSet } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const set : ITermSet = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); Or you can load a term set from a collection - though if you know the id it is more efficient to get the term set directly. import { taxonomy , ITermStore , ITermSet } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const set = store . getTermSetsByName ( \"my set\" , 1031 ). getById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); const setWithData = store . getTermSetsByName ( \"my set\" , 1031 ). getByName ( \"my set\" ). get (); Term set methods and properties \u00b6 addStakeholder \u00b6 Adds a stakeholder to the TermSet import { taxonomy , ITermStore , ITermSet } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const set : ITermSet = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); await set . addStakeholder ( \"i:0#.f|membership|person@tenant.com\" ); deleteStakeholder \u00b6 Deletes a stakeholder to the TermSet import { taxonomy , ITermStore , ITermSet } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const set : ITermSet = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); await set . deleteStakeholder ( \"i:0#.f|membership|person@tenant.com\" ); get \u00b6 Gets the data for this TermSet import { taxonomy , ITermStore , ITermSet , ITermSetData } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const set : ITermSet = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); const setWithData : ITermSet & ITermSetData = await set . get (); terms \u00b6 Provides access to the terms collection for this termset import { taxonomy , ITermStore , ITermSet , ITerms , ITermData , ITerm } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const set : ITermSet = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); const terms : ITerms = set . terms ; // load the data into the terms instances const termsWithData : ( ITermData & ITerm )[] = set . terms . get (); getTermById \u00b6 Gets a term by id from this set import { taxonomy , ITermStore , ITermSet , ITermData , ITerm } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const set : ITermSet = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); const term : ITerm = set . getTermById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); // load the data into the term instances const termWithData : ITermData & ITerm = term . get (); addTerm \u00b6 Adds a term to a term set import { taxonomy , ITermStore , ITermSet , ITermData , ITerm } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const set : ITermSet = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); const term : ITerm & ITermData = await set . addTerm ( \"name\" , 1031 , true ); // you can optionally set the id when you create the term const term2 : ITerm & ITermData = await set . addTerm ( \"name\" , 1031 , true , \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" );","title":"Term Sets"},{"location":"sp-taxonomy/docs/term-sets/#pnpsp-taxonomytermsets","text":"Term sets contain terms within the taxonomy heirarchy.","title":"@pnp/sp-taxonomy/termsets"},{"location":"sp-taxonomy/docs/term-sets/#load-a-term-set","text":"You load a term set directly from a term store. import { taxonomy , ITermStore , ITermSet } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const set : ITermSet = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); Or you can load a term set from a collection - though if you know the id it is more efficient to get the term set directly. import { taxonomy , ITermStore , ITermSet } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const set = store . getTermSetsByName ( \"my set\" , 1031 ). getById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); const setWithData = store . getTermSetsByName ( \"my set\" , 1031 ). getByName ( \"my set\" ). get ();","title":"Load a term set"},{"location":"sp-taxonomy/docs/term-sets/#term-set-methods-and-properties","text":"","title":"Term set methods and properties"},{"location":"sp-taxonomy/docs/term-sets/#addstakeholder","text":"Adds a stakeholder to the TermSet import { taxonomy , ITermStore , ITermSet } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const set : ITermSet = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); await set . addStakeholder ( \"i:0#.f|membership|person@tenant.com\" );","title":"addStakeholder"},{"location":"sp-taxonomy/docs/term-sets/#deletestakeholder","text":"Deletes a stakeholder to the TermSet import { taxonomy , ITermStore , ITermSet } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const set : ITermSet = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); await set . deleteStakeholder ( \"i:0#.f|membership|person@tenant.com\" );","title":"deleteStakeholder"},{"location":"sp-taxonomy/docs/term-sets/#get","text":"Gets the data for this TermSet import { taxonomy , ITermStore , ITermSet , ITermSetData } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const set : ITermSet = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); const setWithData : ITermSet & ITermSetData = await set . get ();","title":"get"},{"location":"sp-taxonomy/docs/term-sets/#terms","text":"Provides access to the terms collection for this termset import { taxonomy , ITermStore , ITermSet , ITerms , ITermData , ITerm } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const set : ITermSet = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); const terms : ITerms = set . terms ; // load the data into the terms instances const termsWithData : ( ITermData & ITerm )[] = set . terms . get ();","title":"terms"},{"location":"sp-taxonomy/docs/term-sets/#gettermbyid","text":"Gets a term by id from this set import { taxonomy , ITermStore , ITermSet , ITermData , ITerm } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const set : ITermSet = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); const term : ITerm = set . getTermById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); // load the data into the term instances const termWithData : ITermData & ITerm = term . get ();","title":"getTermById"},{"location":"sp-taxonomy/docs/term-sets/#addterm","text":"Adds a term to a term set import { taxonomy , ITermStore , ITermSet , ITermData , ITerm } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const set : ITermSet = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); const term : ITerm & ITermData = await set . addTerm ( \"name\" , 1031 , true ); // you can optionally set the id when you create the term const term2 : ITerm & ITermData = await set . addTerm ( \"name\" , 1031 , true , \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" );","title":"addTerm"},{"location":"sp-taxonomy/docs/term-stores/","text":"@pnp/sp-taxonomy/termstores \u00b6 Term stores contain term groups, term sets, and terms. This article describes how to work find, load, and use a term store to access the terms inside. List term stores \u00b6 You can access a list of all term stores via the termstores property of the Taxonomy class. // get a list of term stores and return all properties const stores = await taxonomy . termStores . get (); // you can also select the fields to return for the term stores using the select operator. const stores2 = await taxonomy . termStores . select ( \"Name\" ). get (); Load a term store \u00b6 To load a specific term store you can use the getByName or getById methods. Using the get method executes the request to the server. const store = await taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ). get (); const store2 = await taxonomy . termStores . getById ( \"f6112509-fba7-4544-b2ed-ce6c9396b646\" ). get (); // you can use select as well with either method to choose the fields to return const store3 = await taxonomy . termStores . getById ( \"f6112509-fba7-4544-b2ed-ce6c9396b646\" ). select ( \"Name\" ). get (); For term stores and all other objects data is returned as a merger of the data and a new instance of the representative class. Allowing you to immediately begin acting on the object. IF you do not need the data, skip the get call until you do. // no data loaded yet, store is an instance of TermStore class const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); // I can call subsequent methods on the same object and will now have an object with data // I could have called get above as well - this is just an example const store2 : ITermStore & ITermStoreData = await store . get (); // log the Name property console . log ( store2 . Name ); // call another TermStore method on the same object await store2 . addLanguage ( 1031 ); Term store methods and properties \u00b6 get \u00b6 Loads the data for this term store import { taxonomy , ITermStore } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = await taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ). get (); getTermSetsByName \u00b6 Gets the collection of term sets with a matching name import { taxonomy , ITermSets } from \"@pnp/sp-taxonomy\" ; const sets : ITermSets = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ). getTermSetsByName ( \"My Set\" , 1033 ); getTermSetById \u00b6 Gets the term set with a matching id import { taxonomy , ITermStore , ITermSet } from \"@pnp/sp-taxonomy\" ; // note that you can also use instances if you wanted to conduct multiple operations on a single store const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const set : ITermSet = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); // we will handle normalizing guids for you as well :) const set2 : ITermSet = store . getTermSetById ( \"{a63aefc9-359d-42b7-a0d2-cb1809acd260}\" ); getTermById \u00b6 Gets a term by id import { taxonomy , ITermStore , ITerm , ITermData } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const term : ITerm = store . getTermById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); const termWithData : ITerm & ITermData = await term . get (); getTermsById \u00b6 Added in 1.2.6 import { taxonomy , ITermStore , ITerms , ITermData } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const terms : ITerms = store . getTermsById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" , \"0ba6845c-1468-4ec5-a5a8-718f1fb05432\" ); const termWithData : ( ITerm & ITermData )[] = await term . get (); getTermGroupById \u00b6 Gets a term group by id import { taxonomy , ITermStore , ITermGroup } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const group : ITermGroup = store . getTermGroupById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); getTerms \u00b6 Gets terms that match the provided criteria. Please see this article for details on valid querys. import { taxonomy , ITermStore , ILabelMatchInfo , ITerm , ITermData } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const terms : ITerms = store . getTerms ({ TermLabel : \"test label\" , TrimUnavailable : true , }); // load the data based on the above query const termsWithData : ( ITerm & ITermData )[] = terms . get (); // select works here too :) const termsWithData2 : ( ITerm & ITermData )[] = terms . select ( \"Name\" ). get (); addLanguage \u00b6 Adds a language to the term store by LCID import { taxonomy , ITermStore } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); await store . addLanguage ( 1031 ); addGroup \u00b6 Adds a term group to the term store import { taxonomy , ITermStore } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const group : ITermGroup & ITermGroupData = await store . addGroup ( \"My Group Name\" ); // you can optionally specify the guid of the group, if you don't we just create a new guid for you const groups : ITermGroup & ITermGroupData = await store . addGroup ( \"My Group Name\" , \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); commitAll \u00b6 Commits all updates to the database that have occurred since the last commit or rollback. import { taxonomy , ITermStore } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); await store . commitAll (); deleteLanguage \u00b6 Delete a working language from the TermStore import { taxonomy , ITermStore } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); await store . deleteLanguage ( 1031 ); rollbackAll \u00b6 Discards all updates that have occurred since the last commit or rollback. It is unlikely you will need to call this method through this library due to how things are structured. import { taxonomy , ITermStore } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); await store . rollbackAll ();","title":"Term Stores"},{"location":"sp-taxonomy/docs/term-stores/#pnpsp-taxonomytermstores","text":"Term stores contain term groups, term sets, and terms. This article describes how to work find, load, and use a term store to access the terms inside.","title":"@pnp/sp-taxonomy/termstores"},{"location":"sp-taxonomy/docs/term-stores/#list-term-stores","text":"You can access a list of all term stores via the termstores property of the Taxonomy class. // get a list of term stores and return all properties const stores = await taxonomy . termStores . get (); // you can also select the fields to return for the term stores using the select operator. const stores2 = await taxonomy . termStores . select ( \"Name\" ). get ();","title":"List term stores"},{"location":"sp-taxonomy/docs/term-stores/#load-a-term-store","text":"To load a specific term store you can use the getByName or getById methods. Using the get method executes the request to the server. const store = await taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ). get (); const store2 = await taxonomy . termStores . getById ( \"f6112509-fba7-4544-b2ed-ce6c9396b646\" ). get (); // you can use select as well with either method to choose the fields to return const store3 = await taxonomy . termStores . getById ( \"f6112509-fba7-4544-b2ed-ce6c9396b646\" ). select ( \"Name\" ). get (); For term stores and all other objects data is returned as a merger of the data and a new instance of the representative class. Allowing you to immediately begin acting on the object. IF you do not need the data, skip the get call until you do. // no data loaded yet, store is an instance of TermStore class const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); // I can call subsequent methods on the same object and will now have an object with data // I could have called get above as well - this is just an example const store2 : ITermStore & ITermStoreData = await store . get (); // log the Name property console . log ( store2 . Name ); // call another TermStore method on the same object await store2 . addLanguage ( 1031 );","title":"Load a term store"},{"location":"sp-taxonomy/docs/term-stores/#term-store-methods-and-properties","text":"","title":"Term store methods and properties"},{"location":"sp-taxonomy/docs/term-stores/#get","text":"Loads the data for this term store import { taxonomy , ITermStore } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = await taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ). get ();","title":"get"},{"location":"sp-taxonomy/docs/term-stores/#gettermsetsbyname","text":"Gets the collection of term sets with a matching name import { taxonomy , ITermSets } from \"@pnp/sp-taxonomy\" ; const sets : ITermSets = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ). getTermSetsByName ( \"My Set\" , 1033 );","title":"getTermSetsByName"},{"location":"sp-taxonomy/docs/term-stores/#gettermsetbyid","text":"Gets the term set with a matching id import { taxonomy , ITermStore , ITermSet } from \"@pnp/sp-taxonomy\" ; // note that you can also use instances if you wanted to conduct multiple operations on a single store const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const set : ITermSet = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); // we will handle normalizing guids for you as well :) const set2 : ITermSet = store . getTermSetById ( \"{a63aefc9-359d-42b7-a0d2-cb1809acd260}\" );","title":"getTermSetById"},{"location":"sp-taxonomy/docs/term-stores/#gettermbyid","text":"Gets a term by id import { taxonomy , ITermStore , ITerm , ITermData } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const term : ITerm = store . getTermById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); const termWithData : ITerm & ITermData = await term . get ();","title":"getTermById"},{"location":"sp-taxonomy/docs/term-stores/#gettermsbyid","text":"Added in 1.2.6 import { taxonomy , ITermStore , ITerms , ITermData } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const terms : ITerms = store . getTermsById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" , \"0ba6845c-1468-4ec5-a5a8-718f1fb05432\" ); const termWithData : ( ITerm & ITermData )[] = await term . get ();","title":"getTermsById"},{"location":"sp-taxonomy/docs/term-stores/#gettermgroupbyid","text":"Gets a term group by id import { taxonomy , ITermStore , ITermGroup } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const group : ITermGroup = store . getTermGroupById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" );","title":"getTermGroupById"},{"location":"sp-taxonomy/docs/term-stores/#getterms","text":"Gets terms that match the provided criteria. Please see this article for details on valid querys. import { taxonomy , ITermStore , ILabelMatchInfo , ITerm , ITermData } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const terms : ITerms = store . getTerms ({ TermLabel : \"test label\" , TrimUnavailable : true , }); // load the data based on the above query const termsWithData : ( ITerm & ITermData )[] = terms . get (); // select works here too :) const termsWithData2 : ( ITerm & ITermData )[] = terms . select ( \"Name\" ). get ();","title":"getTerms"},{"location":"sp-taxonomy/docs/term-stores/#addlanguage","text":"Adds a language to the term store by LCID import { taxonomy , ITermStore } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); await store . addLanguage ( 1031 );","title":"addLanguage"},{"location":"sp-taxonomy/docs/term-stores/#addgroup","text":"Adds a term group to the term store import { taxonomy , ITermStore } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const group : ITermGroup & ITermGroupData = await store . addGroup ( \"My Group Name\" ); // you can optionally specify the guid of the group, if you don't we just create a new guid for you const groups : ITermGroup & ITermGroupData = await store . addGroup ( \"My Group Name\" , \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" );","title":"addGroup"},{"location":"sp-taxonomy/docs/term-stores/#commitall","text":"Commits all updates to the database that have occurred since the last commit or rollback. import { taxonomy , ITermStore } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); await store . commitAll ();","title":"commitAll"},{"location":"sp-taxonomy/docs/term-stores/#deletelanguage","text":"Delete a working language from the TermStore import { taxonomy , ITermStore } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); await store . deleteLanguage ( 1031 );","title":"deleteLanguage"},{"location":"sp-taxonomy/docs/term-stores/#rollbackall","text":"Discards all updates that have occurred since the last commit or rollback. It is unlikely you will need to call this method through this library due to how things are structured. import { taxonomy , ITermStore } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); await store . rollbackAll ();","title":"rollbackAll"},{"location":"sp-taxonomy/docs/terms/","text":"@pnp/sp-taxonomy/terms \u00b6 Terms are the individual entries with a term set. Load Terms \u00b6 You can load a collection of terms through a term set or term store . import { taxonomy , ITermStore , ITerms , ILabelMatchInfo , ITerm , ITermData } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = await taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const labelMatchInfo : ILabelMatchInfo = { TermLabel : \"My Label\" , TrimUnavailable : true , }; const terms : ITerms = store . getTerms ( labelMatchInfo ); // get term instances merged with data const terms2 : ( ITermData & ITerm )[] = await store . getTerms ( labelMatchInfo ). get (); const terms3 : ITerms = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ). terms ; // get terms merged with data from a term set const terms4 : ( ITerm & ITermData )[] = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ). terms . get (); Load Single Term \u00b6 You can get a single term a variety of ways as shown below. The \"best\" way will be determined by what information is available to do the lookup but ultimately will result in the same end product. import { taxonomy , ITermStore , ITerms , ILabelMatchInfo , ITerm , ITermData } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = await taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); // get a single term by id const term : ITerm = store . getTermById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); // get single get merged with data const term2 : ITerm = store . getTermById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ). get (); // use select to choose which fields to return const term3 : ITerm = store . getTermById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ). select ( \"Name\" ). get (); // get a term from a term set const term4 : ITerm = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ). getTermById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); Term methods and properties \u00b6 labels \u00b6 Accesses the labels collection for this term import { taxonomy , ITermStore , ITerm , ILabels } from \"@pnp/sp-taxonomy\" ; const term : ITerm = < from one of the above methods > ; const labels : ILabels = term . labels ; // labels merged with data const labelsWithData = term . labels . get (); createLabel \u00b6 Creates a new label for this Term import { taxonomy , ITermStore , ITerm , ILabelData , ILabel } from \"@pnp/sp-taxonomy\" ; const term : ITerm = < from one of the above methods > ; const label : ILabelData & ILabel = term . createLabel ( \"label text\" , 1031 ); // optionally specify this is the default label const label2 : ILabelData & ILabel = term . createLabel ( \"label text\" , 1031 , true ); deprecate \u00b6 Sets the deprecation flag on a term import { ITerm } from \"@pnp/sp-taxonomy\" ; const term : ITerm = < from one of the above methods > ; await term . deprecate ( true ); get \u00b6 Loads the term data import { ITerm , ITermData } from \"@pnp/sp-taxonomy\" ; const term : ITerm = < from one of the above methods > ; // load term instance merged with data const term2 : ITerm & ITermData = await term . get (); getDescription \u00b6 Sets the description import { ITerm } from \"@pnp/sp-taxonomy\" ; const term : ITerm = < from one of the above methods > ; // load term instance merged with data const description = await term . getDescription ( 1031 ); setDescription \u00b6 Sets the description import { ITerm } from \"@pnp/sp-taxonomy\" ; const term : ITerm = < from one of the above methods > ; // load term instance merged with data await term . setDescription ( \"the description\" , 1031 ); setLocalCustomProperty \u00b6 Sets a custom property on this term import { ITerm } from \"@pnp/sp-taxonomy\" ; const term : ITerm = < from one of the above methods > ; // load term instance merged with data await term . setLocalCustomProperty ( \"name\" , \"value\" ); addTerm \u00b6 Added in 1.2.8 Adds a child term to an existing term instance. import { ITerm } from \"@pnp/sp-taxonomy\" ; const parentTerm : ITerm = < from one of the above methods > ; await parentTerm . addTerm ( \"child 1\" , 1033 ); await parentTerm . addTerm ( \"child 2\" , 1033 );","title":"Terms"},{"location":"sp-taxonomy/docs/terms/#pnpsp-taxonomyterms","text":"Terms are the individual entries with a term set.","title":"@pnp/sp-taxonomy/terms"},{"location":"sp-taxonomy/docs/terms/#load-terms","text":"You can load a collection of terms through a term set or term store . import { taxonomy , ITermStore , ITerms , ILabelMatchInfo , ITerm , ITermData } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = await taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); const labelMatchInfo : ILabelMatchInfo = { TermLabel : \"My Label\" , TrimUnavailable : true , }; const terms : ITerms = store . getTerms ( labelMatchInfo ); // get term instances merged with data const terms2 : ( ITermData & ITerm )[] = await store . getTerms ( labelMatchInfo ). get (); const terms3 : ITerms = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ). terms ; // get terms merged with data from a term set const terms4 : ( ITerm & ITermData )[] = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ). terms . get ();","title":"Load Terms"},{"location":"sp-taxonomy/docs/terms/#load-single-term","text":"You can get a single term a variety of ways as shown below. The \"best\" way will be determined by what information is available to do the lookup but ultimately will result in the same end product. import { taxonomy , ITermStore , ITerms , ILabelMatchInfo , ITerm , ITermData } from \"@pnp/sp-taxonomy\" ; const store : ITermStore = await taxonomy . termStores . getByName ( \"Taxonomy_v5o/SbcTE2cegwO2dtAN9l==\" ); // get a single term by id const term : ITerm = store . getTermById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ); // get single get merged with data const term2 : ITerm = store . getTermById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ). get (); // use select to choose which fields to return const term3 : ITerm = store . getTermById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ). select ( \"Name\" ). get (); // get a term from a term set const term4 : ITerm = store . getTermSetById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" ). getTermById ( \"0ba6845c-1468-4ec5-a5a8-718f1fb05431\" );","title":"Load Single Term"},{"location":"sp-taxonomy/docs/terms/#term-methods-and-properties","text":"","title":"Term methods and properties"},{"location":"sp-taxonomy/docs/terms/#labels","text":"Accesses the labels collection for this term import { taxonomy , ITermStore , ITerm , ILabels } from \"@pnp/sp-taxonomy\" ; const term : ITerm = < from one of the above methods > ; const labels : ILabels = term . labels ; // labels merged with data const labelsWithData = term . labels . get ();","title":"labels"},{"location":"sp-taxonomy/docs/terms/#createlabel","text":"Creates a new label for this Term import { taxonomy , ITermStore , ITerm , ILabelData , ILabel } from \"@pnp/sp-taxonomy\" ; const term : ITerm = < from one of the above methods > ; const label : ILabelData & ILabel = term . createLabel ( \"label text\" , 1031 ); // optionally specify this is the default label const label2 : ILabelData & ILabel = term . createLabel ( \"label text\" , 1031 , true );","title":"createLabel"},{"location":"sp-taxonomy/docs/terms/#deprecate","text":"Sets the deprecation flag on a term import { ITerm } from \"@pnp/sp-taxonomy\" ; const term : ITerm = < from one of the above methods > ; await term . deprecate ( true );","title":"deprecate"},{"location":"sp-taxonomy/docs/terms/#get","text":"Loads the term data import { ITerm , ITermData } from \"@pnp/sp-taxonomy\" ; const term : ITerm = < from one of the above methods > ; // load term instance merged with data const term2 : ITerm & ITermData = await term . get ();","title":"get"},{"location":"sp-taxonomy/docs/terms/#getdescription","text":"Sets the description import { ITerm } from \"@pnp/sp-taxonomy\" ; const term : ITerm = < from one of the above methods > ; // load term instance merged with data const description = await term . getDescription ( 1031 );","title":"getDescription"},{"location":"sp-taxonomy/docs/terms/#setdescription","text":"Sets the description import { ITerm } from \"@pnp/sp-taxonomy\" ; const term : ITerm = < from one of the above methods > ; // load term instance merged with data await term . setDescription ( \"the description\" , 1031 );","title":"setDescription"},{"location":"sp-taxonomy/docs/terms/#setlocalcustomproperty","text":"Sets a custom property on this term import { ITerm } from \"@pnp/sp-taxonomy\" ; const term : ITerm = < from one of the above methods > ; // load term instance merged with data await term . setLocalCustomProperty ( \"name\" , \"value\" );","title":"setLocalCustomProperty"},{"location":"sp-taxonomy/docs/terms/#addterm","text":"Added in 1.2.8 Adds a child term to an existing term instance. import { ITerm } from \"@pnp/sp-taxonomy\" ; const parentTerm : ITerm = < from one of the above methods > ; await parentTerm . addTerm ( \"child 1\" , 1033 ); await parentTerm . addTerm ( \"child 2\" , 1033 );","title":"addTerm"},{"location":"sp-taxonomy/docs/utilities/","text":"@pnp/sp-taxonomy/utilities \u00b6 These are a collection of helper methods you may find useful. setItemMetaDataField \u00b6 Allows you to easily set the value of a metadata field in a list item. import { sp } from \"@pnp/sp\" ; import { taxonomy , setItemMetaDataField } from \"@pnp/sp-taxonomy\" ; // create a new item, or load an existing const itemResult = await sp . web . lists . getByTitle ( \"TaxonomyList\" ). items . add ({ Title : \"My Title\" , }); // get a term const term = await taxonomy . getDefaultSiteCollectionTermStore () . getTermById ( \"99992696-1111-1111-1111-15e65b221111\" ). get (); setItemMetaDataField ( itemResult . item , \"MetaDataFieldName\" , term ); setItemMetaDataMultiField \u00b6 Allows you to easily set the value of a multi-value metadata field in a list item. import { sp } from \"@pnp/sp\" ; import { taxonomy , setItemMetaDataMultiField } from \"@pnp/sp-taxonomy\" ; // create a new item, or load an existing const itemResult = await sp . web . lists . getByTitle ( \"TaxonomyList\" ). items . add ({ Title : \"My Title\" , }); // get a term const term = await taxonomy . getDefaultSiteCollectionTermStore () . getTermById ( \"99992696-1111-1111-1111-15e65b221111\" ). get (); // get another term const term2 = await taxonomy . getDefaultSiteCollectionTermStore () . getTermById ( \"99992696-1111-1111-1111-15e65b221112\" ). get (); // get yet another term const term3 = await taxonomy . getDefaultSiteCollectionTermStore () . getTermById ( \"99992696-1111-1111-1111-15e65b221113\" ). get (); setItemMetaDataMultiField ( itemResult . item , \"MultiValueMetaDataFieldName\" , term , term2 , term3 );","title":"Utilities"},{"location":"sp-taxonomy/docs/utilities/#pnpsp-taxonomyutilities","text":"These are a collection of helper methods you may find useful.","title":"@pnp/sp-taxonomy/utilities"},{"location":"sp-taxonomy/docs/utilities/#setitemmetadatafield","text":"Allows you to easily set the value of a metadata field in a list item. import { sp } from \"@pnp/sp\" ; import { taxonomy , setItemMetaDataField } from \"@pnp/sp-taxonomy\" ; // create a new item, or load an existing const itemResult = await sp . web . lists . getByTitle ( \"TaxonomyList\" ). items . add ({ Title : \"My Title\" , }); // get a term const term = await taxonomy . getDefaultSiteCollectionTermStore () . getTermById ( \"99992696-1111-1111-1111-15e65b221111\" ). get (); setItemMetaDataField ( itemResult . item , \"MetaDataFieldName\" , term );","title":"setItemMetaDataField"},{"location":"sp-taxonomy/docs/utilities/#setitemmetadatamultifield","text":"Allows you to easily set the value of a multi-value metadata field in a list item. import { sp } from \"@pnp/sp\" ; import { taxonomy , setItemMetaDataMultiField } from \"@pnp/sp-taxonomy\" ; // create a new item, or load an existing const itemResult = await sp . web . lists . getByTitle ( \"TaxonomyList\" ). items . add ({ Title : \"My Title\" , }); // get a term const term = await taxonomy . getDefaultSiteCollectionTermStore () . getTermById ( \"99992696-1111-1111-1111-15e65b221111\" ). get (); // get another term const term2 = await taxonomy . getDefaultSiteCollectionTermStore () . getTermById ( \"99992696-1111-1111-1111-15e65b221112\" ). get (); // get yet another term const term3 = await taxonomy . getDefaultSiteCollectionTermStore () . getTermById ( \"99992696-1111-1111-1111-15e65b221113\" ). get (); setItemMetaDataMultiField ( itemResult . item , \"MultiValueMetaDataFieldName\" , term , term2 , term3 );","title":"setItemMetaDataMultiField"}]}