@powerportalspro/core 5.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1263 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +5982 -0
- package/dist/index.d.ts +5982 -0
- package/dist/index.js +1231 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1263 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/routes.ts
|
|
4
|
+
var apiRoot = "/api";
|
|
5
|
+
var authRoot = `${apiRoot}/auth`;
|
|
6
|
+
var manageRoot = `${authRoot}/manage`;
|
|
7
|
+
var tables = {
|
|
8
|
+
/** Template: `/api/table/{tableLogicalName}`. POST creates a record. */
|
|
9
|
+
createRoute: `${apiRoot}/table/{tableLogicalName}`,
|
|
10
|
+
/** Template: `/api/table/{tableLogicalName}/{recordId}`. GET reads, PATCH updates, DELETE removes. */
|
|
11
|
+
readUpdateDeleteRoute: `${apiRoot}/table/{tableLogicalName}/{recordId}`,
|
|
12
|
+
/** Resolved URL for creating a record of the given table. */
|
|
13
|
+
getCreateRoute: (tableLogicalName) => `${apiRoot}/table/${tableLogicalName}`,
|
|
14
|
+
/**
|
|
15
|
+
* Resolved URL for retrieving a specific record, optionally with a column allow-list.
|
|
16
|
+
* @param columns Optional list of column logical names — joined with `,` and sent as `?columns=`.
|
|
17
|
+
*/
|
|
18
|
+
getRetrieveRoute: (tableLogicalName, recordId, columns) => {
|
|
19
|
+
const base = `${apiRoot}/table/${tableLogicalName}/${recordId}`;
|
|
20
|
+
return columns && columns.length > 0 ? `${base}?columns=${columns.join(",")}` : base;
|
|
21
|
+
},
|
|
22
|
+
/** Resolved URL for updating a record (PATCH). */
|
|
23
|
+
getUpdateRoute: (tableLogicalName, recordId) => `${apiRoot}/table/${tableLogicalName}/${recordId}`,
|
|
24
|
+
/** Resolved URL for deleting a record (DELETE). */
|
|
25
|
+
getDeleteRoute: (tableLogicalName, recordId) => `${apiRoot}/table/${tableLogicalName}/${recordId}`
|
|
26
|
+
};
|
|
27
|
+
var manage = {
|
|
28
|
+
/** Base path under which all manage endpoints live (`/api/auth/manage`). */
|
|
29
|
+
root: manageRoot,
|
|
30
|
+
/** GET — read first/last/mobile from the linked Dataverse contact + Identity status flags. */
|
|
31
|
+
profile: `${manageRoot}/profile`,
|
|
32
|
+
/** POST — update first/last/mobile on the linked Dataverse contact. */
|
|
33
|
+
updateProfile: `${manageRoot}/profile`,
|
|
34
|
+
/** POST — add a local password to an account that doesn't have one. */
|
|
35
|
+
setPassword: `${manageRoot}/password/set`,
|
|
36
|
+
/** POST — change the local password (requires the current password). */
|
|
37
|
+
changePassword: `${manageRoot}/password/change`,
|
|
38
|
+
/** POST — start a change-email flow by emailing the new address a confirmation link. */
|
|
39
|
+
changeEmail: `${manageRoot}/email/change`,
|
|
40
|
+
/** POST — re-send the confirmation link to the user's current email. */
|
|
41
|
+
sendEmailConfirmation: `${manageRoot}/email/send-confirmation`,
|
|
42
|
+
/** GET — read 2FA status. */
|
|
43
|
+
twoFactorStatus: `${manageRoot}/2fa`,
|
|
44
|
+
/** GET — shared key + otpauth URI for the QR-code enrollment screen. */
|
|
45
|
+
authenticatorSetup: `${manageRoot}/authenticator/setup`,
|
|
46
|
+
/** POST — verify a code from the authenticator app. */
|
|
47
|
+
verifyAuthenticator: `${manageRoot}/authenticator/verify`,
|
|
48
|
+
/** POST — rotate the authenticator key (also disables 2FA). */
|
|
49
|
+
resetAuthenticator: `${manageRoot}/authenticator/reset`,
|
|
50
|
+
/** POST — disable 2FA on the account. */
|
|
51
|
+
disable2fa: `${manageRoot}/2fa/disable`,
|
|
52
|
+
/** POST — regenerate the user's recovery codes. */
|
|
53
|
+
generateRecoveryCodes: `${manageRoot}/2fa/recovery-codes/generate`,
|
|
54
|
+
/** POST — clear this browser's "trust this device" 2FA cookie. */
|
|
55
|
+
forget2faClient: `${manageRoot}/2fa/forget-browser`,
|
|
56
|
+
/** GET — list the signed-in user's linked external logins + available providers to add. */
|
|
57
|
+
externalLogins: `${manageRoot}/external-logins`,
|
|
58
|
+
/** GET — combined snapshot of sign-in paths (linked external logins + whether a local password exists). */
|
|
59
|
+
loginInfo: `${manageRoot}/login-info`,
|
|
60
|
+
/** GET — kicks off the OAuth flow that links an additional external login. Full-page navigate, do not fetch. */
|
|
61
|
+
linkExternalLogin: `${manageRoot}/external-logins/link`,
|
|
62
|
+
/** GET — OAuth callback target for {@link linkExternalLogin}. */
|
|
63
|
+
linkExternalLoginCallback: `${manageRoot}/external-logins/link/callback`,
|
|
64
|
+
/** POST — remove one external login by provider + key. */
|
|
65
|
+
removeExternalLogin: `${manageRoot}/external-logins/remove`,
|
|
66
|
+
/** GET — dump every `[PersonalData]` property + linked external logins. */
|
|
67
|
+
personalData: `${manageRoot}/personal-data`,
|
|
68
|
+
/** POST — permanently delete the user's account. */
|
|
69
|
+
deletePersonalData: `${manageRoot}/personal-data/delete`,
|
|
70
|
+
/** Resolved URL for {@link linkExternalLogin} with the provider + return URL pre-encoded. */
|
|
71
|
+
getLinkExternalLoginRoute: (provider, returnUrl) => {
|
|
72
|
+
const query = `?provider=${encodeURIComponent(provider)}`;
|
|
73
|
+
return returnUrl ? `${manageRoot}/external-logins/link${query}&returnUrl=${encodeURIComponent(returnUrl)}` : `${manageRoot}/external-logins/link${query}`;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
var auth = {
|
|
77
|
+
/** Base path under which all auth endpoints live (`/api/auth`). */
|
|
78
|
+
root: authRoot,
|
|
79
|
+
/** POST — submit credentials. */
|
|
80
|
+
login: `${authRoot}/login`,
|
|
81
|
+
/** POST — submit the second-factor code after a Login that returned RequiresTwoFactor. */
|
|
82
|
+
loginTwoFactor: `${authRoot}/login/2fa`,
|
|
83
|
+
/** POST — clear the auth cookie. */
|
|
84
|
+
logout: `${authRoot}/logout`,
|
|
85
|
+
/** POST — create a new user account. */
|
|
86
|
+
register: `${authRoot}/register`,
|
|
87
|
+
/** POST — send a password-reset email. */
|
|
88
|
+
forgotPassword: `${authRoot}/forgot-password`,
|
|
89
|
+
/** POST — complete a password reset with the email-link token. */
|
|
90
|
+
resetPassword: `${authRoot}/reset-password`,
|
|
91
|
+
/** POST — confirm a registered user's email with the email-link token. */
|
|
92
|
+
confirmEmail: `${authRoot}/confirm-email`,
|
|
93
|
+
/** POST — send a fresh confirmation email. */
|
|
94
|
+
resendEmailConfirmation: `${authRoot}/resend-email-confirmation`,
|
|
95
|
+
/** GET — list of configured external (OAuth) login providers. */
|
|
96
|
+
externalProviders: `${authRoot}/external-providers`,
|
|
97
|
+
/** GET — kicks off the OAuth flow for the named external provider. Full-page navigate, do not fetch. */
|
|
98
|
+
externalLogin: `${authRoot}/external-login`,
|
|
99
|
+
/** GET — snapshot the in-flight external-login cookie set by the OAuth callback. */
|
|
100
|
+
externalLoginPending: `${authRoot}/external-login/pending`,
|
|
101
|
+
/** POST — complete an in-flight external login by registering / linking the account. */
|
|
102
|
+
externalLoginConfirm: `${authRoot}/external-login/confirm`,
|
|
103
|
+
/** POST — complete an in-flight external login when the user has chosen between multiple matching identities. */
|
|
104
|
+
externalLoginSelect: `${authRoot}/external-login/select`,
|
|
105
|
+
/** GET — write the chooser's "remember my choice" cookie + redirect to `returnUrl`. */
|
|
106
|
+
externalLoginRememberChoice: `${authRoot}/external-login/remember-choice`,
|
|
107
|
+
/** POST — swap the current cookie for the user's alt identity (the contact↔systemuser sibling). */
|
|
108
|
+
switchIdentity: `${authRoot}/switch-identity`,
|
|
109
|
+
/** GET — snapshot of the current user (or anonymous shape). */
|
|
110
|
+
me: `${authRoot}/me`,
|
|
111
|
+
/** Account-management endpoints under `/api/auth/manage/*`. */
|
|
112
|
+
manage,
|
|
113
|
+
/** Resolved URL for {@link externalLogin} with the provider + return URL pre-encoded. */
|
|
114
|
+
getExternalLoginRoute: (provider, returnUrl) => {
|
|
115
|
+
const query = `?provider=${encodeURIComponent(provider)}`;
|
|
116
|
+
return returnUrl ? `${authRoot}/external-login${query}&returnUrl=${encodeURIComponent(returnUrl)}` : `${authRoot}/external-login${query}`;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
var api = {
|
|
120
|
+
/** Base path for the API (`/api`). */
|
|
121
|
+
root: apiRoot,
|
|
122
|
+
/** Template — POST a FetchXML query to retrieve multiple records. */
|
|
123
|
+
retrieveMultiple: `${apiRoot}/retrieveMultiple`,
|
|
124
|
+
/** Template — GET table metadata. */
|
|
125
|
+
retrieveTableMetadata: `${apiRoot}/tableMetadata/{tableLogicalName}`,
|
|
126
|
+
/** Template — GET view metadata by view id (Guid-constrained route). */
|
|
127
|
+
retrieveViewMetadata: `${apiRoot}/viewMetadata/{viewId}`,
|
|
128
|
+
/** Template — GET every view metadata record for a table. */
|
|
129
|
+
retrieveViewsForTable: `${apiRoot}/viewMetadata/{tableLogicalName}`,
|
|
130
|
+
/** Template — GET localized strings for a culture. */
|
|
131
|
+
retrieveLocalizedStrings: `${apiRoot}/localizedStrings/{culture}`,
|
|
132
|
+
/** Template — POST a batch of OrganizationRequest payloads. */
|
|
133
|
+
executeMultiple: `${apiRoot}/executeMultiple`,
|
|
134
|
+
/** GET — environment-wide file upload settings (blocked extensions, max upload size). */
|
|
135
|
+
environmentFileSettings: `${apiRoot}/environmentFileSettings`,
|
|
136
|
+
/** POST — clear all server-side caches. SystemAdmin-only. */
|
|
137
|
+
clearAllCaches: `${apiRoot}/caches/clear`,
|
|
138
|
+
/** GET — every server-side cache name. SystemAdmin-only. */
|
|
139
|
+
cacheNames: `${apiRoot}/caches`,
|
|
140
|
+
/** Template — POST to clear a single named cache. SystemAdmin-only. */
|
|
141
|
+
clearCache: `${apiRoot}/caches/{cacheName}/clear`,
|
|
142
|
+
/** Template — GET file metadata + (optionally) content for one record/column. */
|
|
143
|
+
retrieveFileInfo: `${apiRoot}/files/{tableLogicalName}/{recordId}/{columnName}`,
|
|
144
|
+
/** Template — POST record ids; returns file info + content for many records of one column. */
|
|
145
|
+
retrieveFilesBatch: `${apiRoot}/files/{tableLogicalName}/{columnName}/batch`,
|
|
146
|
+
/**
|
|
147
|
+
* POST — builds an archive containing the file payload of every supplied
|
|
148
|
+
* record id for the named table/column. Server returns the binary archive
|
|
149
|
+
* bytes (default) or a JSON envelope when `responseFormat` is `Json`.
|
|
150
|
+
*/
|
|
151
|
+
createFileArchive: `${apiRoot}/files/createFileArchive`,
|
|
152
|
+
/** Resolved URL for retrieving multiple records via FetchXML. */
|
|
153
|
+
getRetrieveMultipleRoute: (fetchXml) => `${apiRoot}/retrieveMultiple?fetchXml=${encodeURIComponent(fetchXml)}`,
|
|
154
|
+
/**
|
|
155
|
+
* Template — POST a GridDataRequest (viewId / fetchXml input modes,
|
|
156
|
+
* searchText, sorts, paging, filters) and get back a shaped
|
|
157
|
+
* GridDataResponse. Server-side IGridService builds the FetchXML via
|
|
158
|
+
* the shared IFetchXmlQueryComposer and runs the query so the client
|
|
159
|
+
* never composes FetchXML directly.
|
|
160
|
+
*/
|
|
161
|
+
gridData: `${apiRoot}/grids/data`,
|
|
162
|
+
/**
|
|
163
|
+
* Template — POST a ChartDataRequest (Aggregate / ViewId / FetchXml
|
|
164
|
+
* input modes) and get back a shaped ChartDataResponse. Server-side
|
|
165
|
+
* IChartService builds the FetchXML and runs the query so the
|
|
166
|
+
* client never composes FetchXML directly.
|
|
167
|
+
*/
|
|
168
|
+
chartData: `${apiRoot}/charts/data`,
|
|
169
|
+
/** Resolved URL for retrieving metadata for one view. */
|
|
170
|
+
getRetrieveViewMetadataRoute: (viewId) => `${apiRoot}/viewMetadata/${viewId}`,
|
|
171
|
+
/** Resolved URL for retrieving every view metadata record for a table. */
|
|
172
|
+
getRetrieveViewsForTableRoute: (tableLogicalName) => `${apiRoot}/viewMetadata/${encodeURIComponent(tableLogicalName)}`,
|
|
173
|
+
/** Resolved URL for retrieving metadata for one table. Mirrors C# behavior of not encoding the segment. */
|
|
174
|
+
getRetrieveTableMetadataRoute: (tableLogicalName) => `${apiRoot}/tableMetadata/${tableLogicalName}`,
|
|
175
|
+
/**
|
|
176
|
+
* Resolved URL for retrieving the current user's combined
|
|
177
|
+
* `TableSecurityPermission` mask for a single table. Mirrors the
|
|
178
|
+
* server-side `ITablePermissionCache.GetPermissionForUserAsync` lookup
|
|
179
|
+
* the Blazor grid buttons already use via DI — exposed so the React
|
|
180
|
+
* client can read the same answer without firing a grid query.
|
|
181
|
+
* `GridDataResponse.tablePermissions` carries the same value when a
|
|
182
|
+
* grid query happens to be in flight; this endpoint covers the other
|
|
183
|
+
* cases (custom toolbars, conditional UI elsewhere on the page).
|
|
184
|
+
*/
|
|
185
|
+
getRetrieveTablePermissionsRoute: (tableLogicalName) => `${apiRoot}/permissions/table/${tableLogicalName}`,
|
|
186
|
+
/** Resolved URL for retrieving localized strings for a culture. */
|
|
187
|
+
getRetrieveLocalizedStringsRoute: (culture) => `${apiRoot}/localizedStrings/${culture}`,
|
|
188
|
+
/** Resolved URL for the localization-bundle manifest endpoint (version + supported locales). */
|
|
189
|
+
getLocalizationBundleManifestRoute: () => `/localizations/version`,
|
|
190
|
+
/**
|
|
191
|
+
* Resolved URL for the per-locale thumbprints endpoint. Returns the
|
|
192
|
+
* content-derived thumbprint for the default bundle plus every loaded
|
|
193
|
+
* table / view at the requested locale. Mirrors C#
|
|
194
|
+
* `Routes.Localizations.GetThumbprintsRoute`.
|
|
195
|
+
*/
|
|
196
|
+
getLocalizationThumbprintsRoute: (locale) => `/localizations/${encodeURIComponent(locale)}/thumbprints`,
|
|
197
|
+
/**
|
|
198
|
+
* Resolved URL for the default localization-bundle file (everything outside
|
|
199
|
+
* `tables.*` / `choices.*`) for a given locale + thumbprint. The thumbprint
|
|
200
|
+
* is purely for cache-busting — the server returns the current bundle for
|
|
201
|
+
* the locale regardless of what thumbprint is in the URL. Mirrors C#
|
|
202
|
+
* `Routes.Localizations.GetDefaultBundleRoute`.
|
|
203
|
+
*/
|
|
204
|
+
getLocalizationBundleRoute: (locale, thumbprint) => `/localizations/default/${locale}.${thumbprint}.json`,
|
|
205
|
+
/**
|
|
206
|
+
* Resolved URL for the per-table localization-bundle file. Returns every
|
|
207
|
+
* `tables.{name}.*` string for the table plus the global `choices.*`
|
|
208
|
+
* strings any of its columns reference. Mirrors C#
|
|
209
|
+
* `Routes.Localizations.GetTableBundleRoute`.
|
|
210
|
+
*/
|
|
211
|
+
getLocalizationTableBundleRoute: (tableName, locale, thumbprint) => `/localizations/tables/${encodeURIComponent(tableName)}/${locale}.${thumbprint}.json`,
|
|
212
|
+
/**
|
|
213
|
+
* Resolved URL for the per-view localization-bundle file. Returns every
|
|
214
|
+
* `tables.{owningTable}.views.{viewId}.*` string. Owning table is resolved
|
|
215
|
+
* server-side from the view id. Mirrors C# `Routes.Localizations.GetViewBundleRoute`.
|
|
216
|
+
*/
|
|
217
|
+
getLocalizationViewBundleRoute: (viewId, locale, thumbprint) => `/localizations/views/${viewId}/${locale}.${thumbprint}.json`,
|
|
218
|
+
/** Resolved URL for executing multiple requests. */
|
|
219
|
+
getExecuteMultipleRoute: (returnResponses) => `${apiRoot}/executeMultiple?returnResponses=${returnResponses}`,
|
|
220
|
+
/** Resolved URL for retrieving file info on one record/column. */
|
|
221
|
+
getRetrieveFileInfoRoute: (tableLogicalName, recordId, columnName, includeData) => `${apiRoot}/files/${encodeURIComponent(tableLogicalName)}/${recordId}/${encodeURIComponent(columnName)}?includeData=${includeData}`,
|
|
222
|
+
/** Resolved URL for the batch retrieve-files endpoint. Body is a JSON array of record ids. */
|
|
223
|
+
getRetrieveFilesBatchRoute: (tableLogicalName, columnName, includeData) => `${apiRoot}/files/${encodeURIComponent(tableLogicalName)}/${encodeURIComponent(columnName)}/batch?includeData=${includeData}`,
|
|
224
|
+
/** Resolved URL for clearing one named cache. */
|
|
225
|
+
getClearCacheRoute: (cacheName) => `${apiRoot}/caches/${encodeURIComponent(cacheName)}/clear`,
|
|
226
|
+
/** Table-scoped CRUD routes. */
|
|
227
|
+
tables,
|
|
228
|
+
/** SPA-facing authentication endpoints. */
|
|
229
|
+
auth
|
|
230
|
+
};
|
|
231
|
+
var ui = {
|
|
232
|
+
localization: {
|
|
233
|
+
/** Template — POST to set the culture cookie + redirect. */
|
|
234
|
+
culture: "Culture/{culture}",
|
|
235
|
+
/** Resolved URL for setting the culture cookie. Mirrors C# behavior of not encoding either segment. */
|
|
236
|
+
getCultureRoute: (culture, returnUrl) => `Culture/${culture}?redirectUri=${returnUrl}`
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
var Routes = {
|
|
240
|
+
api,
|
|
241
|
+
ui
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
// src/errors.ts
|
|
245
|
+
var PowerPortalsProError = class extends Error {
|
|
246
|
+
status;
|
|
247
|
+
url;
|
|
248
|
+
title;
|
|
249
|
+
detail;
|
|
250
|
+
clrType;
|
|
251
|
+
problem;
|
|
252
|
+
constructor(message, init) {
|
|
253
|
+
super(message);
|
|
254
|
+
this.name = "PowerPortalsProError";
|
|
255
|
+
this.status = init.status;
|
|
256
|
+
this.url = init.url;
|
|
257
|
+
this.title = init.title;
|
|
258
|
+
this.detail = init.detail;
|
|
259
|
+
this.clrType = init.clrType;
|
|
260
|
+
this.problem = init.problem;
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
var UnauthorizedAccessError = class extends PowerPortalsProError {
|
|
264
|
+
constructor(message, init) {
|
|
265
|
+
super(message, init);
|
|
266
|
+
this.name = "UnauthorizedAccessError";
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
var ArgumentError = class extends PowerPortalsProError {
|
|
270
|
+
constructor(message, init) {
|
|
271
|
+
super(message, init);
|
|
272
|
+
this.name = "ArgumentError";
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
var ArgumentNullError = class extends ArgumentError {
|
|
276
|
+
constructor(message, init) {
|
|
277
|
+
super(message, init);
|
|
278
|
+
this.name = "ArgumentNullError";
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
var InvalidOperationError = class extends PowerPortalsProError {
|
|
282
|
+
constructor(message, init) {
|
|
283
|
+
super(message, init);
|
|
284
|
+
this.name = "InvalidOperationError";
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
function mapProblemDetails(problem, fallbackStatus, url) {
|
|
288
|
+
const message = problem.detail ?? problem.title ?? `${problem.status ?? fallbackStatus} ${problem.title ?? "HTTP error"}${url ? ` on ${url}` : ""}`;
|
|
289
|
+
const init = {
|
|
290
|
+
status: problem.status ?? fallbackStatus,
|
|
291
|
+
url,
|
|
292
|
+
title: problem.title,
|
|
293
|
+
detail: problem.detail,
|
|
294
|
+
clrType: problem.exceptionType,
|
|
295
|
+
problem
|
|
296
|
+
};
|
|
297
|
+
switch (problem.exceptionType) {
|
|
298
|
+
case "System.UnauthorizedAccessException":
|
|
299
|
+
return new UnauthorizedAccessError(message, init);
|
|
300
|
+
case "System.ArgumentNullException":
|
|
301
|
+
return new ArgumentNullError(message, init);
|
|
302
|
+
case "System.ArgumentException":
|
|
303
|
+
return new ArgumentError(message, init);
|
|
304
|
+
case "System.InvalidOperationException":
|
|
305
|
+
return new InvalidOperationError(message, init);
|
|
306
|
+
default:
|
|
307
|
+
return new PowerPortalsProError(message, init);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// src/transport.ts
|
|
312
|
+
var Transport = class {
|
|
313
|
+
baseUrl;
|
|
314
|
+
fetchImpl;
|
|
315
|
+
constructor(options = {}) {
|
|
316
|
+
this.baseUrl = (options.baseUrl ?? "").replace(/\/+$/, "");
|
|
317
|
+
this.fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
318
|
+
}
|
|
319
|
+
/** Sends a request and returns the parsed JSON response body. */
|
|
320
|
+
async sendJson(method, path, options = {}) {
|
|
321
|
+
const response = await this.send(method, path, options);
|
|
322
|
+
return await response.json();
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Sends a request that may return 204 No Content. Returns `null` for the empty case
|
|
326
|
+
* so the caller can branch without inspecting status codes.
|
|
327
|
+
*/
|
|
328
|
+
async sendNullableJson(method, path, options = {}) {
|
|
329
|
+
const response = await this.send(method, path, options);
|
|
330
|
+
if (response.status === 204) return null;
|
|
331
|
+
const text = await response.text();
|
|
332
|
+
if (text.length === 0) return null;
|
|
333
|
+
return JSON.parse(text);
|
|
334
|
+
}
|
|
335
|
+
/** Sends a request and discards the response body. */
|
|
336
|
+
async sendVoid(method, path, options = {}) {
|
|
337
|
+
const response = await this.send(method, path, options);
|
|
338
|
+
await response.arrayBuffer().catch(() => void 0);
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Low-level send. Throws `PowerPortalsProError` (or a subclass) on non-2xx. Most
|
|
342
|
+
* callers should use {@link sendJson}, {@link sendNullableJson}, or {@link sendVoid}.
|
|
343
|
+
*/
|
|
344
|
+
async send(method, path, options = {}) {
|
|
345
|
+
const url = this.baseUrl + path;
|
|
346
|
+
const hasBody = options.body !== void 0;
|
|
347
|
+
const headers = {
|
|
348
|
+
Accept: "application/json",
|
|
349
|
+
...hasBody ? { "Content-Type": "application/json" } : {},
|
|
350
|
+
...options.headers ?? {}
|
|
351
|
+
};
|
|
352
|
+
const init = {
|
|
353
|
+
method,
|
|
354
|
+
credentials: "include",
|
|
355
|
+
headers,
|
|
356
|
+
...hasBody ? { body: JSON.stringify(options.body) } : {},
|
|
357
|
+
...options.signal ? { signal: options.signal } : {}
|
|
358
|
+
};
|
|
359
|
+
const response = await this.fetchImpl(url, init);
|
|
360
|
+
if (response.ok) return response;
|
|
361
|
+
throw await this.errorFromResponse(response, url);
|
|
362
|
+
}
|
|
363
|
+
async errorFromResponse(response, url) {
|
|
364
|
+
const contentType = response.headers.get("Content-Type") ?? "";
|
|
365
|
+
if (contentType.toLowerCase().includes("application/problem+json")) {
|
|
366
|
+
try {
|
|
367
|
+
const problem = await response.json();
|
|
368
|
+
return mapProblemDetails(problem, response.status, url);
|
|
369
|
+
} catch {
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
let detail;
|
|
373
|
+
try {
|
|
374
|
+
const text = await response.text();
|
|
375
|
+
if (text.length > 0) detail = text;
|
|
376
|
+
} catch {
|
|
377
|
+
}
|
|
378
|
+
return new PowerPortalsProError(
|
|
379
|
+
`${response.status} ${response.statusText} on ${url}`,
|
|
380
|
+
{
|
|
381
|
+
status: response.status,
|
|
382
|
+
url,
|
|
383
|
+
title: response.statusText,
|
|
384
|
+
detail,
|
|
385
|
+
clrType: void 0,
|
|
386
|
+
problem: void 0
|
|
387
|
+
}
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
// src/auth-client.ts
|
|
393
|
+
function bodyAndSignal(body, signal) {
|
|
394
|
+
return {
|
|
395
|
+
...body !== void 0 ? { body } : {},
|
|
396
|
+
...signal ? { signal } : {}
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
var AuthClient = class {
|
|
400
|
+
/**
|
|
401
|
+
* The underlying transport. Exposed so advanced consumers can hit auth endpoints not
|
|
402
|
+
* yet wrapped by a typed method, or share a single transport with a sibling
|
|
403
|
+
* {@link PowerPortalsProClient}.
|
|
404
|
+
*/
|
|
405
|
+
transport;
|
|
406
|
+
constructor(transportOrOptions) {
|
|
407
|
+
this.transport = transportOrOptions instanceof Transport ? transportOrOptions : new Transport(transportOrOptions);
|
|
408
|
+
}
|
|
409
|
+
// --- Login + 2FA + logout --------------------------------------------------------
|
|
410
|
+
/**
|
|
411
|
+
* Submits credentials. On success the auth cookie is set and the next
|
|
412
|
+
* {@link getCurrentUserAsync} will report the user as signed in. The returned
|
|
413
|
+
* `result` enum tells the caller whether to navigate (Success), prompt for 2FA
|
|
414
|
+
* (RequiresTwoFactor), or show a generic error (others).
|
|
415
|
+
*/
|
|
416
|
+
loginAsync(request, signal) {
|
|
417
|
+
return this.transport.sendJson("POST", Routes.api.auth.login, bodyAndSignal(request, signal));
|
|
418
|
+
}
|
|
419
|
+
/** Submits the 2FA code after a {@link loginAsync} that returned `RequiresTwoFactor`. */
|
|
420
|
+
verifyTwoFactorAsync(request, signal) {
|
|
421
|
+
return this.transport.sendJson("POST", Routes.api.auth.loginTwoFactor, bodyAndSignal(request, signal));
|
|
422
|
+
}
|
|
423
|
+
/** Clears the auth cookie. Idempotent — calling on an already-anonymous session is a no-op. */
|
|
424
|
+
logoutAsync(signal) {
|
|
425
|
+
return this.transport.sendVoid("POST", Routes.api.auth.logout, bodyAndSignal(void 0, signal));
|
|
426
|
+
}
|
|
427
|
+
// --- Registration + email confirmation -------------------------------------------
|
|
428
|
+
/**
|
|
429
|
+
* Creates a new user. When the host configured `RequireConfirmedAccount` (the default),
|
|
430
|
+
* the response carries `RegisterResult.ConfirmationEmailSent` and the user is NOT
|
|
431
|
+
* signed in yet — the client should surface "check your email."
|
|
432
|
+
*/
|
|
433
|
+
registerAsync(request, signal) {
|
|
434
|
+
return this.transport.sendJson("POST", Routes.api.auth.register, bodyAndSignal(request, signal));
|
|
435
|
+
}
|
|
436
|
+
/** Confirms a registered email via the registration-link token. */
|
|
437
|
+
confirmEmailAsync(request, signal) {
|
|
438
|
+
return this.transport.sendJson("POST", Routes.api.auth.confirmEmail, bodyAndSignal(request, signal));
|
|
439
|
+
}
|
|
440
|
+
/** Sends a fresh confirmation email. Always 200 — the server doesn't reveal whether the email exists. */
|
|
441
|
+
resendEmailConfirmationAsync(request, signal) {
|
|
442
|
+
return this.transport.sendVoid("POST", Routes.api.auth.resendEmailConfirmation, bodyAndSignal(request, signal));
|
|
443
|
+
}
|
|
444
|
+
// --- Password reset --------------------------------------------------------------
|
|
445
|
+
/** Requests a password-reset email. Always 200 — no enumeration. */
|
|
446
|
+
requestPasswordResetAsync(request, signal) {
|
|
447
|
+
return this.transport.sendVoid("POST", Routes.api.auth.forgotPassword, bodyAndSignal(request, signal));
|
|
448
|
+
}
|
|
449
|
+
/** Completes a password reset using the token from the reset email link. */
|
|
450
|
+
resetPasswordAsync(request, signal) {
|
|
451
|
+
return this.transport.sendJson("POST", Routes.api.auth.resetPassword, bodyAndSignal(request, signal));
|
|
452
|
+
}
|
|
453
|
+
// --- Session ---------------------------------------------------------------------
|
|
454
|
+
/**
|
|
455
|
+
* Snapshot of the current user. Anonymous requests get a non-null `CurrentUserInfo`
|
|
456
|
+
* with `isAuthenticated: false` and the rest of the fields empty — call this on app
|
|
457
|
+
* startup to decide whether to render signed-in UI vs. the login flow.
|
|
458
|
+
*/
|
|
459
|
+
getCurrentUserAsync(signal) {
|
|
460
|
+
return this.transport.sendJson("GET", Routes.api.auth.me, bodyAndSignal(void 0, signal));
|
|
461
|
+
}
|
|
462
|
+
/** Lists the configured external (OAuth) login providers (Microsoft, Google, …). */
|
|
463
|
+
getExternalLoginProvidersAsync(signal) {
|
|
464
|
+
return this.transport.sendJson(
|
|
465
|
+
"GET",
|
|
466
|
+
Routes.api.auth.externalProviders,
|
|
467
|
+
bodyAndSignal(void 0, signal)
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
// --- External login flow ---------------------------------------------------------
|
|
471
|
+
/**
|
|
472
|
+
* Reads the in-flight external-login cookie set by an OAuth callback. Returns
|
|
473
|
+
* `null` when no callback is in flight (the endpoint replies 204) — the client
|
|
474
|
+
* should redirect back to login in that case.
|
|
475
|
+
*/
|
|
476
|
+
getPendingExternalLoginAsync(signal) {
|
|
477
|
+
return this.transport.sendNullableJson(
|
|
478
|
+
"GET",
|
|
479
|
+
Routes.api.auth.externalLoginPending,
|
|
480
|
+
bodyAndSignal(void 0, signal)
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Completes an in-flight external login: registers a new local account (or links
|
|
485
|
+
* the external login to an existing account with the same email) and signs the
|
|
486
|
+
* user in.
|
|
487
|
+
*/
|
|
488
|
+
confirmExternalLoginAsync(request, signal) {
|
|
489
|
+
return this.transport.sendJson(
|
|
490
|
+
"POST",
|
|
491
|
+
Routes.api.auth.externalLoginConfirm,
|
|
492
|
+
bodyAndSignal(request, signal)
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Completes an in-flight external login when the OAuth identity matched more than
|
|
497
|
+
* one portal user (typically a `systemuser` AND a `contact`). Body carries only
|
|
498
|
+
* the `ExternalLoginCandidateKind` the user picked from the chooser; the server
|
|
499
|
+
* re-resolves the underlying record so a malicious caller can't supply an arbitrary id.
|
|
500
|
+
*/
|
|
501
|
+
selectExternalLoginAsync(request, signal) {
|
|
502
|
+
return this.transport.sendJson(
|
|
503
|
+
"POST",
|
|
504
|
+
Routes.api.auth.externalLoginSelect,
|
|
505
|
+
bodyAndSignal(request, signal)
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Swaps the current auth cookie for the user's alt identity (the contact↔systemuser
|
|
510
|
+
* sibling). The alt id is read from the cookie's claims server-side, so the client
|
|
511
|
+
* supplies no parameters.
|
|
512
|
+
*/
|
|
513
|
+
switchIdentityAsync(signal) {
|
|
514
|
+
return this.transport.sendJson(
|
|
515
|
+
"POST",
|
|
516
|
+
Routes.api.auth.switchIdentity,
|
|
517
|
+
bodyAndSignal(void 0, signal)
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
// --- Profile ---------------------------------------------------------------------
|
|
521
|
+
/** Reads the signed-in user's manage-profile snapshot (Identity status + linked contact fields). */
|
|
522
|
+
getProfileAsync(signal) {
|
|
523
|
+
return this.transport.sendJson("GET", Routes.api.auth.manage.profile, bodyAndSignal(void 0, signal));
|
|
524
|
+
}
|
|
525
|
+
/** Updates first/last/mobile on the signed-in user's linked Dataverse contact. */
|
|
526
|
+
updateProfileAsync(request, signal) {
|
|
527
|
+
return this.transport.sendVoid("POST", Routes.api.auth.manage.updateProfile, bodyAndSignal(request, signal));
|
|
528
|
+
}
|
|
529
|
+
// --- Password (set + change) -----------------------------------------------------
|
|
530
|
+
/** Adds a local password to an account that doesn't have one (typically external-login-only). */
|
|
531
|
+
setPasswordAsync(request, signal) {
|
|
532
|
+
return this.transport.sendJson("POST", Routes.api.auth.manage.setPassword, bodyAndSignal(request, signal));
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Changes the local password (requires the current password). On success the auth
|
|
536
|
+
* cookie is refreshed so other sessions are invalidated by the security stamp rotation.
|
|
537
|
+
*/
|
|
538
|
+
changePasswordAsync(request, signal) {
|
|
539
|
+
return this.transport.sendJson(
|
|
540
|
+
"POST",
|
|
541
|
+
Routes.api.auth.manage.changePassword,
|
|
542
|
+
bodyAndSignal(request, signal)
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
// --- Email (change + resend confirmation) ----------------------------------------
|
|
546
|
+
/** Starts a change-email flow by sending a confirmation link to the new address. */
|
|
547
|
+
changeEmailAsync(request, signal) {
|
|
548
|
+
return this.transport.sendJson("POST", Routes.api.auth.manage.changeEmail, bodyAndSignal(request, signal));
|
|
549
|
+
}
|
|
550
|
+
/** Re-sends the confirmation link to the user's current (unconfirmed) email. */
|
|
551
|
+
sendEmailConfirmationAsync(signal) {
|
|
552
|
+
return this.transport.sendJson(
|
|
553
|
+
"POST",
|
|
554
|
+
Routes.api.auth.manage.sendEmailConfirmation,
|
|
555
|
+
bodyAndSignal(void 0, signal)
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
// --- 2FA management --------------------------------------------------------------
|
|
559
|
+
/** Reads the user's two-factor configuration snapshot (enabled, has authenticator, recovery codes left). */
|
|
560
|
+
getTwoFactorStatusAsync(signal) {
|
|
561
|
+
return this.transport.sendJson(
|
|
562
|
+
"GET",
|
|
563
|
+
Routes.api.auth.manage.twoFactorStatus,
|
|
564
|
+
bodyAndSignal(void 0, signal)
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
/** Reads (and creates if missing) the authenticator key + QR-code URI for TOTP enrollment. */
|
|
568
|
+
getAuthenticatorSetupAsync(signal) {
|
|
569
|
+
return this.transport.sendJson(
|
|
570
|
+
"GET",
|
|
571
|
+
Routes.api.auth.manage.authenticatorSetup,
|
|
572
|
+
bodyAndSignal(void 0, signal)
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Verifies a code from the authenticator app to finish enabling 2FA. On success and
|
|
577
|
+
* when the user has zero existing recovery codes, a fresh batch is returned in
|
|
578
|
+
* `recoveryCodes`.
|
|
579
|
+
*/
|
|
580
|
+
verifyAuthenticatorAsync(request, signal) {
|
|
581
|
+
return this.transport.sendJson(
|
|
582
|
+
"POST",
|
|
583
|
+
Routes.api.auth.manage.verifyAuthenticator,
|
|
584
|
+
bodyAndSignal(request, signal)
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
/** Rotates the authenticator key and disables 2FA — the user must re-enroll to re-enable. */
|
|
588
|
+
resetAuthenticatorAsync(signal) {
|
|
589
|
+
return this.transport.sendJson(
|
|
590
|
+
"POST",
|
|
591
|
+
Routes.api.auth.manage.resetAuthenticator,
|
|
592
|
+
bodyAndSignal(void 0, signal)
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
/** Disables 2FA on the account. */
|
|
596
|
+
disable2faAsync(signal) {
|
|
597
|
+
return this.transport.sendJson("POST", Routes.api.auth.manage.disable2fa, bodyAndSignal(void 0, signal));
|
|
598
|
+
}
|
|
599
|
+
/** Regenerates recovery codes — invalidates the previous set. The new codes are returned once and only here. */
|
|
600
|
+
generateRecoveryCodesAsync(signal) {
|
|
601
|
+
return this.transport.sendJson(
|
|
602
|
+
"POST",
|
|
603
|
+
Routes.api.auth.manage.generateRecoveryCodes,
|
|
604
|
+
bodyAndSignal(void 0, signal)
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
/** Clears this browser's "remember this machine" 2FA cookie. */
|
|
608
|
+
forget2faClientAsync(signal) {
|
|
609
|
+
return this.transport.sendJson(
|
|
610
|
+
"POST",
|
|
611
|
+
Routes.api.auth.manage.forget2faClient,
|
|
612
|
+
bodyAndSignal(void 0, signal)
|
|
613
|
+
);
|
|
614
|
+
}
|
|
615
|
+
// --- External logins management --------------------------------------------------
|
|
616
|
+
/** Lists the user's linked external logins plus available providers to add. */
|
|
617
|
+
getExternalLoginsAsync(signal) {
|
|
618
|
+
return this.transport.sendJson(
|
|
619
|
+
"GET",
|
|
620
|
+
Routes.api.auth.manage.externalLogins,
|
|
621
|
+
bodyAndSignal(void 0, signal)
|
|
622
|
+
);
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* Reads the combined sign-in-paths snapshot (linked external logins + whether the
|
|
626
|
+
* account has a local password). Used by the manage-external-logins UI to decide
|
|
627
|
+
* whether unlinking a given external login would lock the user out.
|
|
628
|
+
*/
|
|
629
|
+
getCurrentLoginInfoAsync(signal) {
|
|
630
|
+
return this.transport.sendJson(
|
|
631
|
+
"GET",
|
|
632
|
+
Routes.api.auth.manage.loginInfo,
|
|
633
|
+
bodyAndSignal(void 0, signal)
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
/** Removes one external login from the signed-in user. */
|
|
637
|
+
removeExternalLoginAsync(request, signal) {
|
|
638
|
+
return this.transport.sendJson(
|
|
639
|
+
"POST",
|
|
640
|
+
Routes.api.auth.manage.removeExternalLogin,
|
|
641
|
+
bodyAndSignal(request, signal)
|
|
642
|
+
);
|
|
643
|
+
}
|
|
644
|
+
// --- Personal data ---------------------------------------------------------------
|
|
645
|
+
/** Returns every `[PersonalData]`-marked Identity property + linked external logins. */
|
|
646
|
+
getPersonalDataAsync(signal) {
|
|
647
|
+
return this.transport.sendJson(
|
|
648
|
+
"GET",
|
|
649
|
+
Routes.api.auth.manage.personalData,
|
|
650
|
+
bodyAndSignal(void 0, signal)
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Permanently deletes the user's account. When the account has a local password,
|
|
655
|
+
* `request.password` is required — `RequireLocalPassword` in the response means
|
|
656
|
+
* the client should prompt and retry.
|
|
657
|
+
*/
|
|
658
|
+
deletePersonalDataAsync(request, signal) {
|
|
659
|
+
return this.transport.sendJson(
|
|
660
|
+
"POST",
|
|
661
|
+
Routes.api.auth.manage.deletePersonalData,
|
|
662
|
+
bodyAndSignal(request, signal)
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
|
|
667
|
+
// src/powerportalspro-client.ts
|
|
668
|
+
var PowerPortalsProClient = class {
|
|
669
|
+
/**
|
|
670
|
+
* The underlying transport. Exposed so advanced consumers can hit endpoints not yet
|
|
671
|
+
* wrapped by a typed method (caches, executeMultiple, associate/disassociate, …).
|
|
672
|
+
* Cookie auth, JSON in/out, and problem+json error rehydration apply automatically
|
|
673
|
+
* because the transport owns those concerns.
|
|
674
|
+
*/
|
|
675
|
+
transport;
|
|
676
|
+
constructor(transportOrOptions) {
|
|
677
|
+
this.transport = transportOrOptions instanceof Transport ? transportOrOptions : new Transport(transportOrOptions);
|
|
678
|
+
}
|
|
679
|
+
// --- Records (CRUD + FetchXML) ---------------------------------------------------
|
|
680
|
+
/**
|
|
681
|
+
* Creates a new record. URL is derived from `record.tableName`. Server marks all
|
|
682
|
+
* properties as modified before applying so column values arriving from JSON
|
|
683
|
+
* (which carry no dirty flags) round-trip the same way they do from Blazor's
|
|
684
|
+
* dirty-tracked records.
|
|
685
|
+
*/
|
|
686
|
+
createRecordAsync(record, signal) {
|
|
687
|
+
return this.transport.sendJson(
|
|
688
|
+
"POST",
|
|
689
|
+
Routes.api.tables.getCreateRoute(record.tableName),
|
|
690
|
+
{ body: record, ...signal ? { signal } : {} }
|
|
691
|
+
);
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* Reads a single record. `columns` (logical names) narrows the projection to a subset;
|
|
695
|
+
* omit it for the table's full set of columns visible to the caller.
|
|
696
|
+
*/
|
|
697
|
+
retrieveRecordAsync(tableLogicalName, recordId, columns, signal) {
|
|
698
|
+
return this.transport.sendJson(
|
|
699
|
+
"GET",
|
|
700
|
+
Routes.api.tables.getRetrieveRoute(tableLogicalName, recordId, columns),
|
|
701
|
+
signal ? { signal } : {}
|
|
702
|
+
);
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Runs a FetchXML query and returns the matching records plus paging info.
|
|
706
|
+
* The query is the FetchXML XML literal — the same format Dataverse natively accepts.
|
|
707
|
+
*/
|
|
708
|
+
retrieveRecordsAsync(fetchXml, signal) {
|
|
709
|
+
return this.transport.sendJson(
|
|
710
|
+
"GET",
|
|
711
|
+
Routes.api.getRetrieveMultipleRoute(fetchXml),
|
|
712
|
+
signal ? { signal } : {}
|
|
713
|
+
);
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* Loads grid data via the server-side <c>IGridService</c>. The request
|
|
717
|
+
* picks a base query — a stored Dataverse view (<c>viewId</c>) or a
|
|
718
|
+
* caller-supplied FetchXML (<c>fetchXml</c>) — and the server applies
|
|
719
|
+
* the framework's <c>*</c>/<c>%</c> wildcard convention, AND-merges
|
|
720
|
+
* the search filter into the source's existing filter, dispatches to
|
|
721
|
+
* per-column-type search semantics (string <c>like</c>, choice label
|
|
722
|
+
* match → integer <c>in</c>, lookup link-entity + primary-name match,
|
|
723
|
+
* etc.), and projects each column to a {@link ResolvedColumn} so the
|
|
724
|
+
* client can render headers + dispatch cells without a separate
|
|
725
|
+
* metadata round-trip.
|
|
726
|
+
*
|
|
727
|
+
* Exactly one of <c>request.viewId</c> or <c>request.fetchXml</c> must
|
|
728
|
+
* be supplied; sending both or neither returns a 400.
|
|
729
|
+
*
|
|
730
|
+
* Mirrors how the Blazor `IGridService` is consumed —
|
|
731
|
+
* `@powerportalspro/react`'s `useGridData` hook calls this method
|
|
732
|
+
* internally, so most consumers don't invoke it directly.
|
|
733
|
+
*/
|
|
734
|
+
loadGridAsync(request, signal) {
|
|
735
|
+
return this.transport.sendJson(
|
|
736
|
+
"POST",
|
|
737
|
+
Routes.api.gridData,
|
|
738
|
+
{ body: request, ...signal ? { signal } : {} }
|
|
739
|
+
);
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* Updates an existing record. URL is derived from `record.tableName` and `record.id` —
|
|
743
|
+
* `record.id` must be set. For a new record, use {@link createRecordAsync} instead.
|
|
744
|
+
*/
|
|
745
|
+
updateRecordAsync(record, signal) {
|
|
746
|
+
if (!record.id) {
|
|
747
|
+
throw new Error(
|
|
748
|
+
"PowerPortalsProClient.updateRecordAsync requires record.id. Use createRecordAsync for new records."
|
|
749
|
+
);
|
|
750
|
+
}
|
|
751
|
+
return this.transport.sendJson(
|
|
752
|
+
"PATCH",
|
|
753
|
+
Routes.api.tables.getUpdateRoute(record.tableName, record.id),
|
|
754
|
+
{ body: record, ...signal ? { signal } : {} }
|
|
755
|
+
);
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Executes a batch of {@link OrganizationRequest}s as a single round-trip,
|
|
759
|
+
* matching Blazor's `IPowerPortalsProService.ExecuteMultipleAsync`. The
|
|
760
|
+
* MainContext save flow uses this to ship every dirty descendant's
|
|
761
|
+
* requests in one shot so a multi-record save lands transactionally
|
|
762
|
+
* server-side.
|
|
763
|
+
*
|
|
764
|
+
* When `returnResponses` is `true` (default), the response array carries
|
|
765
|
+
* one `OrganizationResponse` per request in submission order — useful for
|
|
766
|
+
* `CreateRequest` cases that need the newly-allocated record id. Pass
|
|
767
|
+
* `false` for fire-and-forget batches to skip the response payload.
|
|
768
|
+
*/
|
|
769
|
+
executeMultipleAsync(requests, options) {
|
|
770
|
+
const returnResponses = options?.returnResponses ?? true;
|
|
771
|
+
return this.transport.sendJson(
|
|
772
|
+
"POST",
|
|
773
|
+
Routes.api.getExecuteMultipleRoute(returnResponses),
|
|
774
|
+
{
|
|
775
|
+
body: requests,
|
|
776
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
777
|
+
}
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
/** Deletes the record with the given id from the given table. */
|
|
781
|
+
deleteRecordAsync(tableLogicalName, recordId, signal) {
|
|
782
|
+
return this.transport.sendJson(
|
|
783
|
+
"DELETE",
|
|
784
|
+
Routes.api.tables.getDeleteRoute(tableLogicalName, recordId),
|
|
785
|
+
signal ? { signal } : {}
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
// --- Charts ----------------------------------------------------------------------
|
|
789
|
+
/**
|
|
790
|
+
* Loads chart data via the server-side <c>IChartService</c>. The
|
|
791
|
+
* request body picks one of three input modes — typed aggregate
|
|
792
|
+
* config, saved-view id, or raw FetchXML — plus the label/value
|
|
793
|
+
* columns to shape the response. Server builds the FetchXML, runs the
|
|
794
|
+
* query, performs the multi-series pivot, and applies combined
|
|
795
|
+
* date-label formatting using the request culture.
|
|
796
|
+
*
|
|
797
|
+
* Mirrors how the Blazor `IChartService` is consumed —
|
|
798
|
+
* `@powerportalspro/react-charts`'s `DataverseChartDataSource` family
|
|
799
|
+
* calls this method internally, so most consumers don't invoke it
|
|
800
|
+
* directly.
|
|
801
|
+
*/
|
|
802
|
+
loadChartAsync(request, signal) {
|
|
803
|
+
return this.transport.sendJson(
|
|
804
|
+
"POST",
|
|
805
|
+
Routes.api.chartData,
|
|
806
|
+
{ body: request, ...signal ? { signal } : {} }
|
|
807
|
+
);
|
|
808
|
+
}
|
|
809
|
+
// --- Metadata --------------------------------------------------------------------
|
|
810
|
+
/** Reads the metadata describing the columns and relationships of a single Dataverse table. */
|
|
811
|
+
retrieveTableMetadataAsync(tableLogicalName, signal) {
|
|
812
|
+
return this.transport.sendJson(
|
|
813
|
+
"GET",
|
|
814
|
+
Routes.api.getRetrieveTableMetadataRoute(tableLogicalName),
|
|
815
|
+
signal ? { signal } : {}
|
|
816
|
+
);
|
|
817
|
+
}
|
|
818
|
+
/**
|
|
819
|
+
* Returns the current user's combined table-level `TableSecurityPermission`
|
|
820
|
+
* bitmask for `tableLogicalName` — the bitwise union of Read / Create /
|
|
821
|
+
* Write / Delete / Append / AppendTo flags any registered
|
|
822
|
+
* `ITablePermissionHandler` allows for that user on that table. Mirrors
|
|
823
|
+
* the cached `ITablePermissionCache.GetPermissionForUserAsync` lookup
|
|
824
|
+
* Blazor's grid buttons already use directly via DI. Wrapped client-side
|
|
825
|
+
* by the `useTablePermissions(tableName)` React hook with in-flight-promise
|
|
826
|
+
* dedup; reach for the raw client only when you're outside React (e.g.
|
|
827
|
+
* a sample stand-alone script) or need an imperative one-off check.
|
|
828
|
+
*
|
|
829
|
+
* Returns `0` (`TableSecurityPermission.None`) when the user has no
|
|
830
|
+
* permissions on the table; consumers compare via bit math (e.g.
|
|
831
|
+
* `(permissions & TableSecurityPermission.Create) === TableSecurityPermission.Create`).
|
|
832
|
+
*/
|
|
833
|
+
retrieveTablePermissionsAsync(tableLogicalName, signal) {
|
|
834
|
+
return this.transport.sendJson(
|
|
835
|
+
"GET",
|
|
836
|
+
Routes.api.getRetrieveTablePermissionsRoute(tableLogicalName),
|
|
837
|
+
signal ? { signal } : {}
|
|
838
|
+
);
|
|
839
|
+
}
|
|
840
|
+
/** Reads metadata for a single view by its Dataverse view id (a GUID). */
|
|
841
|
+
retrieveViewMetadataAsync(viewId, signal) {
|
|
842
|
+
return this.transport.sendJson(
|
|
843
|
+
"GET",
|
|
844
|
+
Routes.api.getRetrieveViewMetadataRoute(viewId),
|
|
845
|
+
signal ? { signal } : {}
|
|
846
|
+
);
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* Lists every view metadata record for a table — used by view-pickers and default-view
|
|
850
|
+
* resolution. Server-side caching means this is a single Dataverse hit per table per
|
|
851
|
+
* server lifetime.
|
|
852
|
+
*/
|
|
853
|
+
retrieveViewsForTableAsync(tableLogicalName, signal) {
|
|
854
|
+
return this.transport.sendJson(
|
|
855
|
+
"GET",
|
|
856
|
+
Routes.api.getRetrieveViewsForTableRoute(tableLogicalName),
|
|
857
|
+
signal ? { signal } : {}
|
|
858
|
+
);
|
|
859
|
+
}
|
|
860
|
+
// --- Localization ----------------------------------------------------------------
|
|
861
|
+
/**
|
|
862
|
+
* Retrieves the version manifest — just the supported-locale codes.
|
|
863
|
+
* Clients fetch this on app startup, resolve which locale to use, then
|
|
864
|
+
* call {@link retrieveLocalizationThumbprintsAsync} for the per-resource
|
|
865
|
+
* thumbprints at that locale. Cached `no-cache` server-side so a new
|
|
866
|
+
* release is detected on next page load.
|
|
867
|
+
*/
|
|
868
|
+
retrieveLocalizationBundleManifestAsync(signal) {
|
|
869
|
+
return this.transport.sendJson(
|
|
870
|
+
"GET",
|
|
871
|
+
Routes.api.getLocalizationBundleManifestRoute(),
|
|
872
|
+
signal ? { signal } : {}
|
|
873
|
+
);
|
|
874
|
+
}
|
|
875
|
+
/**
|
|
876
|
+
* Retrieves the per-resource thumbprints for a single locale — the
|
|
877
|
+
* default-bundle thumbprint plus thumbprints for every loaded table / view.
|
|
878
|
+
* Returned from a separate endpoint (vs being baked into the version
|
|
879
|
+
* manifest) so the manifest stays small even at large environment scale.
|
|
880
|
+
* Cached `no-cache` server-side; the per-resource immutable URLs do the
|
|
881
|
+
* heavy caching once these are read.
|
|
882
|
+
*/
|
|
883
|
+
retrieveLocalizationThumbprintsAsync(locale, signal) {
|
|
884
|
+
return this.transport.sendJson(
|
|
885
|
+
"GET",
|
|
886
|
+
Routes.api.getLocalizationThumbprintsRoute(locale),
|
|
887
|
+
signal ? { signal } : {}
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
/**
|
|
891
|
+
* Resolved URL for the default localization-bundle file at the given
|
|
892
|
+
* locale + thumbprint. Convenience wrapper around the {@link Routes}
|
|
893
|
+
* helper.
|
|
894
|
+
*/
|
|
895
|
+
getLocalizationBundleUrl(locale, thumbprint) {
|
|
896
|
+
return Routes.api.getLocalizationBundleRoute(locale, thumbprint);
|
|
897
|
+
}
|
|
898
|
+
/**
|
|
899
|
+
* Fetches the default localization-bundle file (everything outside
|
|
900
|
+
* `tables.*` / `choices.*`) for the given locale + thumbprint. Returns
|
|
901
|
+
* the nested-object shape the source JSON files use
|
|
902
|
+
* (`{ app: { buttons: { … } } }`).
|
|
903
|
+
*
|
|
904
|
+
* Per-table and per-view strings come from
|
|
905
|
+
* {@link retrieveLocalizationTableBundleAsync} and
|
|
906
|
+
* {@link retrieveLocalizationViewBundleAsync} — fetched in parallel by the
|
|
907
|
+
* runtime when source-generator-emitted `tables.{name}` / `views.{viewId}`
|
|
908
|
+
* tokens are passed to the localizer's prefix-load hook.
|
|
909
|
+
*
|
|
910
|
+
* The thumbprint is purely cosmetic (server doesn't validate it). Pass
|
|
911
|
+
* the thumbprint from the manifest so the URL is unique per release and
|
|
912
|
+
* the browser's HTTP cache serves subsequent loads from disk.
|
|
913
|
+
*/
|
|
914
|
+
retrieveLocalizationBundleAsync(locale, thumbprint, signal) {
|
|
915
|
+
return this.transport.sendJson(
|
|
916
|
+
"GET",
|
|
917
|
+
Routes.api.getLocalizationBundleRoute(locale, thumbprint),
|
|
918
|
+
signal ? { signal } : {}
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
/**
|
|
922
|
+
* Fetches a per-table localization bundle. Returns every `tables.{name}.*`
|
|
923
|
+
* string for the table plus the global `choices.*` strings any of its
|
|
924
|
+
* columns reference. Owning-side resolution: the server reads the table's
|
|
925
|
+
* column metadata to find which global option sets to include.
|
|
926
|
+
*
|
|
927
|
+
* Pass the thumbprint from the matching locale entry of the manifest so
|
|
928
|
+
* the URL is unique per release; the browser caches the response under
|
|
929
|
+
* `Cache-Control: immutable, max-age=31536000`.
|
|
930
|
+
*/
|
|
931
|
+
retrieveLocalizationTableBundleAsync(tableName, locale, thumbprint, signal) {
|
|
932
|
+
return this.transport.sendJson(
|
|
933
|
+
"GET",
|
|
934
|
+
Routes.api.getLocalizationTableBundleRoute(tableName, locale, thumbprint),
|
|
935
|
+
signal ? { signal } : {}
|
|
936
|
+
);
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* Fetches a per-view localization bundle. Returns every
|
|
940
|
+
* `tables.{owningTable}.views.{viewId}.*` string. The owning table is
|
|
941
|
+
* resolved server-side from the view id, so the client only needs to pass
|
|
942
|
+
* the id (lowercased GUID, no braces).
|
|
943
|
+
*
|
|
944
|
+
* Pass the thumbprint from the matching locale entry of the manifest so
|
|
945
|
+
* the URL is unique per release; the browser caches the response under
|
|
946
|
+
* `Cache-Control: immutable, max-age=31536000`.
|
|
947
|
+
*/
|
|
948
|
+
retrieveLocalizationViewBundleAsync(viewId, locale, thumbprint, signal) {
|
|
949
|
+
return this.transport.sendJson(
|
|
950
|
+
"GET",
|
|
951
|
+
Routes.api.getLocalizationViewBundleRoute(viewId, locale, thumbprint),
|
|
952
|
+
signal ? { signal } : {}
|
|
953
|
+
);
|
|
954
|
+
}
|
|
955
|
+
/**
|
|
956
|
+
* Retrieves the FULL localized-strings catalog for a culture. The server
|
|
957
|
+
* already merges Dataverse-metadata-derived strings (table / column /
|
|
958
|
+
* choice-option labels) with the framework JSON files and any consumer
|
|
959
|
+
* override files (last-wins). Use this to seed the React-side localizer
|
|
960
|
+
* with one round-trip.
|
|
961
|
+
*
|
|
962
|
+
* Returned shape is a nested object that mirrors the source JSON files —
|
|
963
|
+
* `{ app: { buttons: { save: { label: "Save" } } }, tables: { contact: ... } }`.
|
|
964
|
+
* The client typically flattens this to dotted-key form for `t()` lookup
|
|
965
|
+
* (see {@link flattenStrings} in `@powerportalspro/react`).
|
|
966
|
+
*
|
|
967
|
+
* @param culture culture code matching what server-side ASP.NET request
|
|
968
|
+
* localization recognizes — e.g. `"en"`, `"es"`, `"fr-CA"`. Falls back
|
|
969
|
+
* to the default culture server-side when the value isn't supported.
|
|
970
|
+
*/
|
|
971
|
+
retrieveLocalizedStringsAsync(culture, signal) {
|
|
972
|
+
return this.transport.sendJson(
|
|
973
|
+
"GET",
|
|
974
|
+
Routes.api.getRetrieveLocalizedStringsRoute(culture),
|
|
975
|
+
signal ? { signal } : {}
|
|
976
|
+
);
|
|
977
|
+
}
|
|
978
|
+
// --- Files -----------------------------------------------------------------------
|
|
979
|
+
/**
|
|
980
|
+
* Reads file metadata for one record/column pair, optionally including the binary
|
|
981
|
+
* payload. When `includeData` is false (the default), the response carries name,
|
|
982
|
+
* size, and content type but not the bytes — useful for rendering a download link
|
|
983
|
+
* that fetches lazily on click.
|
|
984
|
+
*/
|
|
985
|
+
getFileInfoAsync(tableLogicalName, recordId, columnName, includeData = false, signal) {
|
|
986
|
+
return this.transport.sendJson(
|
|
987
|
+
"GET",
|
|
988
|
+
Routes.api.getRetrieveFileInfoRoute(tableLogicalName, recordId, columnName, includeData),
|
|
989
|
+
signal ? { signal } : {}
|
|
990
|
+
);
|
|
991
|
+
}
|
|
992
|
+
/**
|
|
993
|
+
* Batched read for many records of the same table/column — feeds the FileGrid's
|
|
994
|
+
* "Download All" / "Download Selected" flows in one round-trip. Permission checks
|
|
995
|
+
* still apply per-record server-side, so dropped rows (deleted, unauthorized,
|
|
996
|
+
* file-missing) just don't appear in the response.
|
|
997
|
+
*/
|
|
998
|
+
getFileInfosAsync(tableLogicalName, recordIds, columnName, includeData = false, signal) {
|
|
999
|
+
return this.transport.sendJson(
|
|
1000
|
+
"POST",
|
|
1001
|
+
Routes.api.getRetrieveFilesBatchRoute(tableLogicalName, columnName, includeData),
|
|
1002
|
+
{ body: recordIds, ...signal ? { signal } : {} }
|
|
1003
|
+
);
|
|
1004
|
+
}
|
|
1005
|
+
/**
|
|
1006
|
+
* Builds an archive containing the file payload of every supplied record id for the
|
|
1007
|
+
* named table/column. Replaces the older client-side "fetch each file + zip in the
|
|
1008
|
+
* browser" path with a single server-side step — no base64 round-trip on the wire.
|
|
1009
|
+
*
|
|
1010
|
+
* Two response shapes, selected by `request.responseFormat`:
|
|
1011
|
+
*
|
|
1012
|
+
* - **BinaryStream** (default): the server returns the raw archive bytes; this
|
|
1013
|
+
* method reads them via `response.arrayBuffer()` and wraps the result in a
|
|
1014
|
+
* {@link FileArchiveResult}, deriving `fileName` from the `Content-Disposition`
|
|
1015
|
+
* header and `contentType` from `Content-Type`. Most consumers want this path.
|
|
1016
|
+
* - **Json**: the server returns a {@link FileArchiveJsonResponse} envelope with
|
|
1017
|
+
* the archive bytes base64-encoded. Useful for test harnesses, service workers,
|
|
1018
|
+
* or callers that need to inspect filename/size before triggering a download.
|
|
1019
|
+
*
|
|
1020
|
+
* Either way, the returned `data` is empty (`Uint8Array(0)`) when none of the
|
|
1021
|
+
* supplied records produced a usable file — the caller can surface a "nothing to
|
|
1022
|
+
* download" message instead of streaming an empty archive.
|
|
1023
|
+
*/
|
|
1024
|
+
async createFileArchiveAsync(request, signal) {
|
|
1025
|
+
if (request.responseFormat === 1) {
|
|
1026
|
+
const json = await this.transport.sendJson(
|
|
1027
|
+
"POST",
|
|
1028
|
+
Routes.api.createFileArchive,
|
|
1029
|
+
{ body: request, ...signal ? { signal } : {} }
|
|
1030
|
+
);
|
|
1031
|
+
return {
|
|
1032
|
+
fileName: json.fileName,
|
|
1033
|
+
contentType: json.contentType,
|
|
1034
|
+
data: base64ToUint8Array(json.data)
|
|
1035
|
+
};
|
|
1036
|
+
}
|
|
1037
|
+
const response = await this.transport.send(
|
|
1038
|
+
"POST",
|
|
1039
|
+
Routes.api.createFileArchive,
|
|
1040
|
+
{ body: request, ...signal ? { signal } : {} }
|
|
1041
|
+
);
|
|
1042
|
+
const fileName = parseContentDispositionFileName(response.headers.get("Content-Disposition")) ?? `${request.tableName}-files.zip`;
|
|
1043
|
+
const contentType = response.headers.get("Content-Type")?.split(";")[0]?.trim() ?? "application/octet-stream";
|
|
1044
|
+
const buffer = await response.arrayBuffer();
|
|
1045
|
+
return { fileName, contentType, data: new Uint8Array(buffer) };
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Reads the environment-wide file upload settings (blocked extension list, max
|
|
1049
|
+
* upload size in KB). UI consumers use this to validate uploads client-side before
|
|
1050
|
+
* the round-trip, mirroring what the server enforces.
|
|
1051
|
+
*/
|
|
1052
|
+
getEnvironmentFileSettingsAsync(signal) {
|
|
1053
|
+
return this.transport.sendJson(
|
|
1054
|
+
"GET",
|
|
1055
|
+
Routes.api.environmentFileSettings,
|
|
1056
|
+
signal ? { signal } : {}
|
|
1057
|
+
);
|
|
1058
|
+
}
|
|
1059
|
+
};
|
|
1060
|
+
function base64ToUint8Array(base64) {
|
|
1061
|
+
const binary = atob(base64);
|
|
1062
|
+
const bytes = new Uint8Array(binary.length);
|
|
1063
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
1064
|
+
return bytes;
|
|
1065
|
+
}
|
|
1066
|
+
function parseContentDispositionFileName(header) {
|
|
1067
|
+
if (!header) return null;
|
|
1068
|
+
const star = /filename\*=(?:UTF-8'')?([^;]+)/i.exec(header);
|
|
1069
|
+
if (star?.[1]) {
|
|
1070
|
+
try {
|
|
1071
|
+
return decodeURIComponent(star[1]);
|
|
1072
|
+
} catch {
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
const plain = /filename="?([^";]+)"?/i.exec(header);
|
|
1076
|
+
return plain?.[1] ?? null;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
// src/generated/result-codes.ts
|
|
1080
|
+
var AggregateType = {
|
|
1081
|
+
None: 0,
|
|
1082
|
+
Count: 1,
|
|
1083
|
+
CountColumn: 2,
|
|
1084
|
+
Sum: 3,
|
|
1085
|
+
Avg: 4,
|
|
1086
|
+
Min: 5,
|
|
1087
|
+
Max: 6
|
|
1088
|
+
};
|
|
1089
|
+
var ArchiveFormat = {
|
|
1090
|
+
Zip: 0
|
|
1091
|
+
};
|
|
1092
|
+
var ChangeEmailResult = {
|
|
1093
|
+
ConfirmationEmailSent: 0,
|
|
1094
|
+
SameAsCurrentEmail: 1
|
|
1095
|
+
};
|
|
1096
|
+
var ChangePasswordResult = {
|
|
1097
|
+
Success: 0,
|
|
1098
|
+
IncorrectOldPassword: 1,
|
|
1099
|
+
InvalidPassword: 2
|
|
1100
|
+
};
|
|
1101
|
+
var ChartDateGrouping = {
|
|
1102
|
+
None: 0,
|
|
1103
|
+
Day: 1,
|
|
1104
|
+
Week: 2,
|
|
1105
|
+
Month: 3,
|
|
1106
|
+
Quarter: 4,
|
|
1107
|
+
Year: 5,
|
|
1108
|
+
MonthAndYear: 6,
|
|
1109
|
+
DayAndMonth: 7,
|
|
1110
|
+
DayAndMonthAndYear: 8,
|
|
1111
|
+
WeekAndYear: 9,
|
|
1112
|
+
QuarterAndYear: 10
|
|
1113
|
+
};
|
|
1114
|
+
var ColumnType = {
|
|
1115
|
+
Boolean: 0,
|
|
1116
|
+
Customer: 1,
|
|
1117
|
+
DateTime: 2,
|
|
1118
|
+
Decimal: 3,
|
|
1119
|
+
Double: 4,
|
|
1120
|
+
Integer: 5,
|
|
1121
|
+
Lookup: 6,
|
|
1122
|
+
Memo: 7,
|
|
1123
|
+
Money: 8,
|
|
1124
|
+
Owner: 9,
|
|
1125
|
+
PartyList: 10,
|
|
1126
|
+
Choice: 11,
|
|
1127
|
+
State: 12,
|
|
1128
|
+
Status: 13,
|
|
1129
|
+
String: 14,
|
|
1130
|
+
Uniqueidentifier: 15,
|
|
1131
|
+
CalendarRules: 16,
|
|
1132
|
+
Virtual: 17,
|
|
1133
|
+
BigInt: 18,
|
|
1134
|
+
ManagedProperty: 19,
|
|
1135
|
+
EntityName: 20,
|
|
1136
|
+
MultiSelectChoice: 40,
|
|
1137
|
+
File: 41,
|
|
1138
|
+
Image: 42
|
|
1139
|
+
};
|
|
1140
|
+
var ConfirmExternalLoginResult = {
|
|
1141
|
+
SignedIn: 0,
|
|
1142
|
+
ConfirmationEmailSent: 1,
|
|
1143
|
+
NoPendingExternalLogin: 2,
|
|
1144
|
+
Failure: 3
|
|
1145
|
+
};
|
|
1146
|
+
var DateTimeBehavior = {
|
|
1147
|
+
DateOnly: 1,
|
|
1148
|
+
UserLocal: 2,
|
|
1149
|
+
TimeZoneIndependent: 3
|
|
1150
|
+
};
|
|
1151
|
+
var DeletePersonalDataResult = {
|
|
1152
|
+
Success: 0,
|
|
1153
|
+
IncorrectPassword: 1,
|
|
1154
|
+
RequireLocalPassword: 2
|
|
1155
|
+
};
|
|
1156
|
+
var ExternalLoginCandidateKind = {
|
|
1157
|
+
Contact: 0,
|
|
1158
|
+
SystemUser: 1
|
|
1159
|
+
};
|
|
1160
|
+
var FileArchiveResponseFormat = {
|
|
1161
|
+
BinaryStream: 0,
|
|
1162
|
+
Json: 1
|
|
1163
|
+
};
|
|
1164
|
+
var JoinOperator = {
|
|
1165
|
+
Inner: 0,
|
|
1166
|
+
LeftOuter: 1,
|
|
1167
|
+
Natural: 2,
|
|
1168
|
+
MatchFirstRowUsingCrossApply: 3,
|
|
1169
|
+
In: 4,
|
|
1170
|
+
Exists: 5,
|
|
1171
|
+
Any: 6,
|
|
1172
|
+
NotAny: 7,
|
|
1173
|
+
All: 8,
|
|
1174
|
+
NotAll: 9
|
|
1175
|
+
};
|
|
1176
|
+
var LoginResult = {
|
|
1177
|
+
Success: 0,
|
|
1178
|
+
RequiresTwoFactor: 1,
|
|
1179
|
+
InvalidCredentials: 2,
|
|
1180
|
+
EmailNotConfirmed: 3,
|
|
1181
|
+
LockedOut: 4
|
|
1182
|
+
};
|
|
1183
|
+
var RegisterResult = {
|
|
1184
|
+
ConfirmationEmailSent: 0,
|
|
1185
|
+
SignedIn: 1,
|
|
1186
|
+
EmailAlreadyInUse: 2
|
|
1187
|
+
};
|
|
1188
|
+
var RelationshipFilterMode = {
|
|
1189
|
+
IncludeExistingRecords: 0,
|
|
1190
|
+
ExcludeExistingRecords: 1
|
|
1191
|
+
};
|
|
1192
|
+
var RequiredLevel = {
|
|
1193
|
+
None: 0,
|
|
1194
|
+
SystemRequired: 1,
|
|
1195
|
+
ApplicationRequired: 2,
|
|
1196
|
+
Recommended: 3
|
|
1197
|
+
};
|
|
1198
|
+
var ResetPasswordResult = {
|
|
1199
|
+
Success: 0,
|
|
1200
|
+
InvalidOrExpiredToken: 1,
|
|
1201
|
+
InvalidPassword: 2
|
|
1202
|
+
};
|
|
1203
|
+
var SwitchIdentityResult = {
|
|
1204
|
+
Switched: 0,
|
|
1205
|
+
NoAltIdentity: 1,
|
|
1206
|
+
AltIdentityNotFound: 2,
|
|
1207
|
+
NotAuthenticated: 3
|
|
1208
|
+
};
|
|
1209
|
+
var TableSecurityPermission = {
|
|
1210
|
+
None: 0,
|
|
1211
|
+
Read: 1,
|
|
1212
|
+
Create: 2,
|
|
1213
|
+
Write: 4,
|
|
1214
|
+
Delete: 8,
|
|
1215
|
+
Append: 16,
|
|
1216
|
+
AppendTo: 32,
|
|
1217
|
+
All: 63
|
|
1218
|
+
};
|
|
1219
|
+
|
|
1220
|
+
// src/record-id.ts
|
|
1221
|
+
var EMPTY_GUID = "00000000-0000-0000-0000-000000000000";
|
|
1222
|
+
function getRecordReferenceId(record) {
|
|
1223
|
+
if (!record) return void 0;
|
|
1224
|
+
if (record.id && record.id !== EMPTY_GUID) return record.id;
|
|
1225
|
+
return record._idForCreate ?? void 0;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
// src/index.ts
|
|
1229
|
+
var VERSION = "0.1.0";
|
|
1230
|
+
|
|
1231
|
+
exports.AggregateType = AggregateType;
|
|
1232
|
+
exports.ArchiveFormat = ArchiveFormat;
|
|
1233
|
+
exports.ArgumentError = ArgumentError;
|
|
1234
|
+
exports.ArgumentNullError = ArgumentNullError;
|
|
1235
|
+
exports.AuthClient = AuthClient;
|
|
1236
|
+
exports.ChangeEmailResult = ChangeEmailResult;
|
|
1237
|
+
exports.ChangePasswordResult = ChangePasswordResult;
|
|
1238
|
+
exports.ChartDateGrouping = ChartDateGrouping;
|
|
1239
|
+
exports.ColumnType = ColumnType;
|
|
1240
|
+
exports.ConfirmExternalLoginResult = ConfirmExternalLoginResult;
|
|
1241
|
+
exports.DateTimeBehavior = DateTimeBehavior;
|
|
1242
|
+
exports.DeletePersonalDataResult = DeletePersonalDataResult;
|
|
1243
|
+
exports.ExternalLoginCandidateKind = ExternalLoginCandidateKind;
|
|
1244
|
+
exports.FileArchiveResponseFormat = FileArchiveResponseFormat;
|
|
1245
|
+
exports.InvalidOperationError = InvalidOperationError;
|
|
1246
|
+
exports.JoinOperator = JoinOperator;
|
|
1247
|
+
exports.LoginResult = LoginResult;
|
|
1248
|
+
exports.PowerPortalsProClient = PowerPortalsProClient;
|
|
1249
|
+
exports.PowerPortalsProError = PowerPortalsProError;
|
|
1250
|
+
exports.RegisterResult = RegisterResult;
|
|
1251
|
+
exports.RelationshipFilterMode = RelationshipFilterMode;
|
|
1252
|
+
exports.RequiredLevel = RequiredLevel;
|
|
1253
|
+
exports.ResetPasswordResult = ResetPasswordResult;
|
|
1254
|
+
exports.Routes = Routes;
|
|
1255
|
+
exports.SwitchIdentityResult = SwitchIdentityResult;
|
|
1256
|
+
exports.TableSecurityPermission = TableSecurityPermission;
|
|
1257
|
+
exports.Transport = Transport;
|
|
1258
|
+
exports.UnauthorizedAccessError = UnauthorizedAccessError;
|
|
1259
|
+
exports.VERSION = VERSION;
|
|
1260
|
+
exports.getRecordReferenceId = getRecordReferenceId;
|
|
1261
|
+
exports.mapProblemDetails = mapProblemDetails;
|
|
1262
|
+
//# sourceMappingURL=index.cjs.map
|
|
1263
|
+
//# sourceMappingURL=index.cjs.map
|