@bcis/sdk 0.0.1 → 0.1.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/README.md +268 -1
- package/dist/index.d.mts +604 -0
- package/dist/index.d.ts +604 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +3 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +31 -15
- package/.github/workflows/npm-publish.yml +0 -31
- package/.github/workflows/release.yml +0 -30
- package/.github/workflows/tag.yml +0 -17
- package/LICENSE +0 -201
- package/index.js +0 -5
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,604 @@
|
|
|
1
|
+
/** Configuration union for the centralized AuthManager */
|
|
2
|
+
type AuthConfig = ClientCredentialsConfig | AuthorizationCodeConfig;
|
|
3
|
+
interface ClientCredentialsConfig {
|
|
4
|
+
flow: 'client-credentials';
|
|
5
|
+
/** OAuth2 client ID */
|
|
6
|
+
clientId: string;
|
|
7
|
+
/** OAuth2 client secret */
|
|
8
|
+
clientSecret: string;
|
|
9
|
+
/** Token endpoint URL, e.g. 'https://auth.bcis.co.uk/oauth/token' */
|
|
10
|
+
tokenUrl: string;
|
|
11
|
+
/** Space-separated or array of OAuth2 scopes to request */
|
|
12
|
+
scopes?: string[];
|
|
13
|
+
}
|
|
14
|
+
interface AuthorizationCodeConfig {
|
|
15
|
+
flow: 'authorization-code';
|
|
16
|
+
/** OAuth2 client ID */
|
|
17
|
+
clientId: string;
|
|
18
|
+
/** Token endpoint URL */
|
|
19
|
+
tokenUrl: string;
|
|
20
|
+
/** Authorization endpoint URL (where users are redirected to log in) */
|
|
21
|
+
authorizationUrl: string;
|
|
22
|
+
/** Redirect URI registered with the OAuth2 provider */
|
|
23
|
+
redirectUri: string;
|
|
24
|
+
/** Scopes to request */
|
|
25
|
+
scopes?: string[];
|
|
26
|
+
}
|
|
27
|
+
/** Standard OAuth2 token response */
|
|
28
|
+
interface TokenResponse {
|
|
29
|
+
access_token: string;
|
|
30
|
+
token_type: string;
|
|
31
|
+
expires_in?: number;
|
|
32
|
+
refresh_token?: string;
|
|
33
|
+
scope?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Centralized OAuth2 authentication manager.
|
|
38
|
+
*
|
|
39
|
+
* Supports:
|
|
40
|
+
* - Client Credentials flow (server-to-server, fully automatic)
|
|
41
|
+
* - Authorization Code + PKCE flow (user-facing applications)
|
|
42
|
+
*
|
|
43
|
+
* @example Client Credentials
|
|
44
|
+
* ```ts
|
|
45
|
+
* const auth = new AuthManager({
|
|
46
|
+
* flow: 'client-credentials',
|
|
47
|
+
* clientId: 'my-id',
|
|
48
|
+
* clientSecret: 'my-secret',
|
|
49
|
+
* tokenUrl: 'https://auth.bcis.co.uk/oauth/token',
|
|
50
|
+
* });
|
|
51
|
+
* const token = await auth.getAccessToken();
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* @example Authorization Code
|
|
55
|
+
* ```ts
|
|
56
|
+
* const auth = new AuthManager({
|
|
57
|
+
* flow: 'authorization-code',
|
|
58
|
+
* clientId: 'my-id',
|
|
59
|
+
* tokenUrl: 'https://auth.bcis.co.uk/oauth/token',
|
|
60
|
+
* authorizationUrl: 'https://auth.bcis.co.uk/authorize',
|
|
61
|
+
* redirectUri: 'https://myapp.com/callback',
|
|
62
|
+
* scopes: ['openid', 'profile'],
|
|
63
|
+
* });
|
|
64
|
+
*
|
|
65
|
+
* // Step 1: redirect user
|
|
66
|
+
* const { url, codeVerifier } = await auth.getAuthorizationUrl();
|
|
67
|
+
* // store codeVerifier in session, redirect user to url
|
|
68
|
+
*
|
|
69
|
+
* // Step 2: on callback
|
|
70
|
+
* await auth.handleCallback(code, codeVerifier);
|
|
71
|
+
*
|
|
72
|
+
* // Step 3: use the SDK
|
|
73
|
+
* const token = await auth.getAccessToken();
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
declare class AuthManager {
|
|
77
|
+
private readonly config;
|
|
78
|
+
private readonly store;
|
|
79
|
+
/** Pending token fetch promise to prevent concurrent requests */
|
|
80
|
+
private inflight;
|
|
81
|
+
constructor(config: AuthConfig);
|
|
82
|
+
/**
|
|
83
|
+
* Returns a valid access token, fetching or refreshing as needed.
|
|
84
|
+
* For Client Credentials flow this is fully automatic.
|
|
85
|
+
* For Authorization Code flow, `handleCallback` must have been called first.
|
|
86
|
+
*/
|
|
87
|
+
getAccessToken(): Promise<string>;
|
|
88
|
+
/**
|
|
89
|
+
* Authorization Code flow only.
|
|
90
|
+
* Builds and returns the authorization URL to redirect the user to.
|
|
91
|
+
* The returned `codeVerifier` must be persisted (e.g. in session storage)
|
|
92
|
+
* and passed to `handleCallback`.
|
|
93
|
+
*/
|
|
94
|
+
getAuthorizationUrl(state?: string): Promise<{
|
|
95
|
+
url: string;
|
|
96
|
+
codeVerifier: string;
|
|
97
|
+
}>;
|
|
98
|
+
/**
|
|
99
|
+
* Authorization Code flow only.
|
|
100
|
+
* Exchanges the authorization code (from the redirect callback) for tokens
|
|
101
|
+
* and stores them internally.
|
|
102
|
+
*/
|
|
103
|
+
handleCallback(code: string, codeVerifier: string): Promise<void>;
|
|
104
|
+
/** Clears all stored tokens. */
|
|
105
|
+
clearTokens(): void;
|
|
106
|
+
private refresh;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Thrown when an API response is not 2xx. */
|
|
110
|
+
declare class BcisApiError extends Error {
|
|
111
|
+
readonly status: number;
|
|
112
|
+
readonly statusText: string;
|
|
113
|
+
readonly body: unknown;
|
|
114
|
+
constructor(status: number, statusText: string, body: unknown);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
interface AbpResponseDto {
|
|
118
|
+
abpStudy?: {
|
|
119
|
+
/** Date the study was compiled */
|
|
120
|
+
dateCompiled: string;
|
|
121
|
+
/** Date the study was updated */
|
|
122
|
+
dateUpdated: string;
|
|
123
|
+
/** A six-character code identifying the BCIS study */
|
|
124
|
+
studyType: string;
|
|
125
|
+
/** The description of the BCIS study */
|
|
126
|
+
studyName: string;
|
|
127
|
+
/** The numerator */
|
|
128
|
+
numerator: string;
|
|
129
|
+
/** The demominator */
|
|
130
|
+
demominator: string;
|
|
131
|
+
/** The description of the price level */
|
|
132
|
+
priceLevelDescription: string;
|
|
133
|
+
/** The quarter of the price level */
|
|
134
|
+
priceLevelQuarter: string;
|
|
135
|
+
/** The index of the price level */
|
|
136
|
+
priceLevelIndex: number;
|
|
137
|
+
/** The base of the price level */
|
|
138
|
+
priceLevelIndexBase: string;
|
|
139
|
+
};
|
|
140
|
+
categories?: Array<{
|
|
141
|
+
/** Type of work, e.g. Newbuild, Refurbishment */
|
|
142
|
+
typeOfWork: string;
|
|
143
|
+
/** A code identifying the building function */
|
|
144
|
+
buildingFunctionCode: string;
|
|
145
|
+
/** A description of the building function */
|
|
146
|
+
buildingFunctionDescription: string;
|
|
147
|
+
/** A description of the subclass */
|
|
148
|
+
subclass: string;
|
|
149
|
+
/** Frame and upper floors */
|
|
150
|
+
elementDescription: string;
|
|
151
|
+
nonZeroSample?: number;
|
|
152
|
+
mean?: number;
|
|
153
|
+
standardDeviation?: number;
|
|
154
|
+
decile0?: number;
|
|
155
|
+
decile1?: number;
|
|
156
|
+
decile2?: number;
|
|
157
|
+
decile3?: number;
|
|
158
|
+
decile4?: number;
|
|
159
|
+
decile5?: number;
|
|
160
|
+
decile6?: number;
|
|
161
|
+
decile7?: number;
|
|
162
|
+
decile8?: number;
|
|
163
|
+
decile9?: number;
|
|
164
|
+
decile10?: number;
|
|
165
|
+
quartile1?: number;
|
|
166
|
+
quartile3?: number;
|
|
167
|
+
graphScale?: number;
|
|
168
|
+
graphIntervalWidth?: number;
|
|
169
|
+
graphData: Array<{
|
|
170
|
+
rateScale: number;
|
|
171
|
+
frequency: number;
|
|
172
|
+
}>;
|
|
173
|
+
}>;
|
|
174
|
+
result?: string;
|
|
175
|
+
}
|
|
176
|
+
interface IndicesResponseDto {
|
|
177
|
+
result?: string;
|
|
178
|
+
indexSet?: {
|
|
179
|
+
/** Date the index set was compiled */
|
|
180
|
+
dateCompiled: string;
|
|
181
|
+
};
|
|
182
|
+
indexSeries?: Array<{
|
|
183
|
+
/** Short name of the index series */
|
|
184
|
+
shortName: string;
|
|
185
|
+
/** Regularity of the index series, e.g. monthly, quarterly */
|
|
186
|
+
regularity: string;
|
|
187
|
+
/** Title of the index series */
|
|
188
|
+
title: string;
|
|
189
|
+
/** Date the index series was last updated */
|
|
190
|
+
dateUpdated: unknown;
|
|
191
|
+
/** Title of the index */
|
|
192
|
+
indexTitle: string;
|
|
193
|
+
/** Number of decimal places for the index value */
|
|
194
|
+
indexDecimalPlaces: number;
|
|
195
|
+
/** Title of the description for the index series */
|
|
196
|
+
descriptionTitle: string;
|
|
197
|
+
/** Number of decimal places for the description value */
|
|
198
|
+
descriptionDecimalPlaces: number;
|
|
199
|
+
/** Description of the base for the index series */
|
|
200
|
+
baseDescription: string;
|
|
201
|
+
/** Base value of the index series */
|
|
202
|
+
baseValue: number;
|
|
203
|
+
/** Base year for the index series */
|
|
204
|
+
baseYear: number;
|
|
205
|
+
indexData: Array<{
|
|
206
|
+
quarterApplicable: string;
|
|
207
|
+
/** Index value for the series */
|
|
208
|
+
index: string;
|
|
209
|
+
/** Status of the index data, e.g. firm, provisional */
|
|
210
|
+
status: string;
|
|
211
|
+
}>;
|
|
212
|
+
}>;
|
|
213
|
+
}
|
|
214
|
+
interface TpsResponseDto {
|
|
215
|
+
tpsSet?: {
|
|
216
|
+
/** Date the study was compiled */
|
|
217
|
+
dateCompiled: string;
|
|
218
|
+
};
|
|
219
|
+
studies?: Array<{
|
|
220
|
+
/** The description of the TPS study */
|
|
221
|
+
studyName: string;
|
|
222
|
+
/** Description of the base for the TPS study */
|
|
223
|
+
baseDescription: string;
|
|
224
|
+
/** Base value of the TPS study */
|
|
225
|
+
baseValue: string;
|
|
226
|
+
/** Date the study was last updated */
|
|
227
|
+
dateUpdated: unknown;
|
|
228
|
+
entries: Array<{
|
|
229
|
+
/** Code for the entry, e.g. H, H1, H1N */
|
|
230
|
+
code: string;
|
|
231
|
+
/** Description of the entry, e.g. London, Inner London Boroughs, Westminster */
|
|
232
|
+
description: string;
|
|
233
|
+
/** Index value for the entry */
|
|
234
|
+
index: number;
|
|
235
|
+
/** Sample size for the entry */
|
|
236
|
+
sample: number;
|
|
237
|
+
}>;
|
|
238
|
+
}>;
|
|
239
|
+
result?: string;
|
|
240
|
+
}
|
|
241
|
+
interface CodesResponseDto {
|
|
242
|
+
codesUpdateSet?: {
|
|
243
|
+
/** Date the study was compiled */
|
|
244
|
+
dateCompiled: string;
|
|
245
|
+
};
|
|
246
|
+
result?: string;
|
|
247
|
+
codesTable?: Array<{
|
|
248
|
+
tableType: string;
|
|
249
|
+
codes: Array<Record<string, string>>;
|
|
250
|
+
}>;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
interface AbpRetrieveParams {
|
|
254
|
+
/** When true, returns additional data for graph plotting. Default false. */
|
|
255
|
+
'include-data-for-graph'?: boolean;
|
|
256
|
+
/** When true, includes sub-divided categories (e.g., size bands) in results. Default false. */
|
|
257
|
+
'include-subclasses'?: boolean;
|
|
258
|
+
/** A comma-separated list of building function codes used to filter study results. [See the Codes Update API](/docs/bcis-grace-svc-core-apis/1a5fdc770c00d-codes-update). */
|
|
259
|
+
'building-function': string[];
|
|
260
|
+
/** A list of type of work codes to filter the results by, the example contains all valid codes. */
|
|
261
|
+
'type-of-work': string[];
|
|
262
|
+
/** A six-character code identifying the BCIS study */
|
|
263
|
+
'abp-study': 'ABPBUI' | 'ABPFUN' | 'ABPGRP' | 'ABPEM2' | 'ABPEUR' | 'ABPEXT';
|
|
264
|
+
}
|
|
265
|
+
interface IndicesRetrieveParams {
|
|
266
|
+
/** Restricts the index series by year e.g. `1985` or description `1985 mean = 100`. Ignored if a series number is provided. Descriptions must match text exactly, case-insensitive but including spaces. */
|
|
267
|
+
'base-of-series'?: string;
|
|
268
|
+
/** Restricts index series by `regularity` (`monthly`, `quarterly`, `annual`). Ignored if a series number is used. Defaults to `quarterly`, then `monthly`, then `annual`. */
|
|
269
|
+
regularity?: string[];
|
|
270
|
+
/** Restricts index figures up to a specific month `yyyy-mm`, or leave blank for latest available. */
|
|
271
|
+
'end-date'?: string;
|
|
272
|
+
/** Restricts index figures to a specific month `yyyy-mm`, or leave blank for earliest available. */
|
|
273
|
+
'start-date'?: string;
|
|
274
|
+
/** Comma-delimited list of short names (e.g. `BCISTPI:AllIn`) or series numbers. [See the Codes Update API](/docs/bcis-grace-svc-core-apis/1a5fdc770c00d-codes-update). */
|
|
275
|
+
'series-identification': string[];
|
|
276
|
+
}
|
|
277
|
+
interface TpsRetrieveParams {
|
|
278
|
+
/** Supports suffixes to filter or refine the study data: - Level Filters: - `:region`, `:county`, `:district` - Example: `location2000:region` (regional indices), `location2000:county,district` (county and district indices) - Postcode Filter: - `:postcode:<POSTCODE>` (no spaces) - Example: `location2000:postcode:SW1P3AD` - Cannot be combined with level filters. - Effective Date Filter: - `:EffectiveDate:<YYYYQn>` - Example: `location2000:EffectiveDate:2015Q2` - Can be combined with postcode or level filters. - Outcode List: - `:outcode` - Example: `location2000:outcode` - Not supported for 1980 boundaries or with EffectiveDate. `short-tps-name` is not case sensitive. For available studies, use the `codesUpdate` web service with `codeType=shortTPSName`. */
|
|
279
|
+
'short-tps-name': string;
|
|
280
|
+
}
|
|
281
|
+
interface CodesUpdateParams {
|
|
282
|
+
/** A date in `yyyy-mm-dd` format. Returns only codes added or modified since this date. Not supported for all code types. Leave blank to return all codes. */
|
|
283
|
+
'if-changed-since'?: string;
|
|
284
|
+
/** A version string to select relevant code tables. */
|
|
285
|
+
version?: string;
|
|
286
|
+
/** A string to select the code list required. The supported values are: - `seriesIdentification`: All regularity names (for `/indices-retrieve`) - `shortTPSName`: Tender Price Studies - short names (for `/tps-retrieve`) - `ABPStudy`: Average building prices study codes (for `/abp-retrieve`) - `BuildingFunction`: List of building function codes (for `/abp-retrieve`, and `/analyses-search`) - `BuildingFunction:Categories`: List of building function categories - `BuildingFunction:[1-9]`: List of building function codes for the category specified after the colon - `BuildingFunction:Duration`: List of building function codes for duration calculator (for `Duration Model Calculate Api`) - `BuildingFunction:Duration:Categories`: List of building function categories for duration calculator (for `Duration Model Calculate Api`) - `BuildingFunction:Duration:[1-9]`: List of building function codes for duration calculator for category specified after the colon (for `Duration Model Calculate Api`) - `BuildingFunction:ABP`: List of building function codes for average building prices study where results are available to the user (for `/abp-retrieve`) - `SimplifiedTypeOfWork`: List of shorter type of work codes (for `/abp-retrieve`) The list of supported code types may be extended in the future. */
|
|
287
|
+
'code-type': 'shortTPSName' | 'ABPStudy' | 'BuildingFunction' | 'BuildingFunction:Categories' | 'BuildingFunction:[1-9]' | 'BuildingFunction:Duration' | 'BuildingFunction:Duration:Categories' | 'BuildingFunction:Duration:[1-9]' | 'BuildingFunction:ABP' | 'SimplifiedTypeOfWork';
|
|
288
|
+
}
|
|
289
|
+
declare class CoreApiClient {
|
|
290
|
+
private readonly client;
|
|
291
|
+
constructor(auth: AuthManager);
|
|
292
|
+
/** abp-retrieve */
|
|
293
|
+
abpRetrieve(params: AbpRetrieveParams): Promise<AbpResponseDto>;
|
|
294
|
+
/** indices-retrieve */
|
|
295
|
+
indicesRetrieve(params: IndicesRetrieveParams): Promise<IndicesResponseDto>;
|
|
296
|
+
/** tps-retrieve */
|
|
297
|
+
tpsRetrieve(params: TpsRetrieveParams): Promise<TpsResponseDto>;
|
|
298
|
+
/** codes-update */
|
|
299
|
+
codesUpdate(params: CodesUpdateParams): Promise<CodesResponseDto>;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
type UsageResponse = Array<{
|
|
303
|
+
/** Month of calculations report */
|
|
304
|
+
calculationMonth?: string;
|
|
305
|
+
/** Number of successful calculations */
|
|
306
|
+
successfulCalculations?: number;
|
|
307
|
+
/** Number of unsuccessful calculations calculations */
|
|
308
|
+
unsuccessfulCalculations?: number;
|
|
309
|
+
}>;
|
|
310
|
+
interface CalculationResponse {
|
|
311
|
+
/** Detailed description of the calculations process and results */
|
|
312
|
+
summary?: string;
|
|
313
|
+
/** The expected reinstatement cost */
|
|
314
|
+
expectedTotal?: number;
|
|
315
|
+
/** The minimum reinstatement cost */
|
|
316
|
+
minimumTotal?: number;
|
|
317
|
+
/** The maximum reinstatement cost */
|
|
318
|
+
maximumTotal?: number;
|
|
319
|
+
}
|
|
320
|
+
interface Error$1 {
|
|
321
|
+
/** The code of the error */
|
|
322
|
+
errorCode?: number;
|
|
323
|
+
/** A human readable error message */
|
|
324
|
+
errorMessage?: string;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
interface CalculateParams {
|
|
328
|
+
/** Postcode of the property */
|
|
329
|
+
postCode: string;
|
|
330
|
+
/** Type of the property */
|
|
331
|
+
type: string;
|
|
332
|
+
/** Number of storeys in the property */
|
|
333
|
+
storeys: string;
|
|
334
|
+
/** Style of the property: detached, terraced, etc */
|
|
335
|
+
style: string;
|
|
336
|
+
/** Type of the walls of the property */
|
|
337
|
+
wallType: string;
|
|
338
|
+
/** Type of the roof of the property */
|
|
339
|
+
roofType?: string;
|
|
340
|
+
/** Year the property was built */
|
|
341
|
+
yearBuilt: number;
|
|
342
|
+
/** Number of flats */
|
|
343
|
+
noOfFlats?: number;
|
|
344
|
+
/** Area of the property in sq.m. */
|
|
345
|
+
area?: number;
|
|
346
|
+
/** Number of rooms in the property */
|
|
347
|
+
noOfRooms?: number;
|
|
348
|
+
/** Number of bedrooms in the property */
|
|
349
|
+
noOfBedrooms?: number;
|
|
350
|
+
/** Number of garage spaces in the property */
|
|
351
|
+
noOfGarageSpaces?: number;
|
|
352
|
+
/** Number of bathrooms in the property */
|
|
353
|
+
noOfBathrooms?: number;
|
|
354
|
+
/** Special features of the property, Must be blank, or a comma delimited list containing one or more of 'cellar' or 'noexternals' */
|
|
355
|
+
specialFeatures?: string;
|
|
356
|
+
}
|
|
357
|
+
interface ReportUsageParams {
|
|
358
|
+
/** First month of the usage report */
|
|
359
|
+
startMonth?: string;
|
|
360
|
+
/** Last month of the usage report */
|
|
361
|
+
endMonth?: string;
|
|
362
|
+
}
|
|
363
|
+
declare class ResidentialRebuildClient {
|
|
364
|
+
private readonly client;
|
|
365
|
+
constructor(auth: AuthManager);
|
|
366
|
+
/** rbls-calculate */
|
|
367
|
+
calculate(params: CalculateParams): Promise<CalculationResponse>;
|
|
368
|
+
/** rbls-report-use */
|
|
369
|
+
reportUsage(params: ReportUsageParams): Promise<UsageResponse>;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
type EditionsDto = Array<{
|
|
373
|
+
/** Unique identifier for the book/edition */
|
|
374
|
+
id: string;
|
|
375
|
+
/** Parent book identifier (null for root books) */
|
|
376
|
+
idParent: string | null;
|
|
377
|
+
/** Root book identifier in hierarchy */
|
|
378
|
+
idRoot: string;
|
|
379
|
+
/** Hierarchical depth level (0 = root level) */
|
|
380
|
+
depth: number;
|
|
381
|
+
/** Whether this book has child editions/sections */
|
|
382
|
+
hasChildren: boolean;
|
|
383
|
+
/** Book/edition code (e.g., "SOR2024", "MP2024") */
|
|
384
|
+
code: string;
|
|
385
|
+
/** Human-readable description of the book */
|
|
386
|
+
description: string;
|
|
387
|
+
/** Publication context/environment */
|
|
388
|
+
publicationEnvironment: string;
|
|
389
|
+
/** Upper price range (if applicable) */
|
|
390
|
+
priceUpper: number | null;
|
|
391
|
+
/** Lower price range (if applicable) */
|
|
392
|
+
priceLower: number | null;
|
|
393
|
+
/** Current pricing information */
|
|
394
|
+
priceCurrent: string | null;
|
|
395
|
+
/** Publication date (ISO 8601 format) */
|
|
396
|
+
datePublished: string | null;
|
|
397
|
+
/** Regional location adjustment factor */
|
|
398
|
+
locationFactor: number;
|
|
399
|
+
/** Sort order/priority for display */
|
|
400
|
+
sort: string;
|
|
401
|
+
}>;
|
|
402
|
+
interface GetRateResponseDto {
|
|
403
|
+
rootNodes: Array<{
|
|
404
|
+
/** Unique identifier for the rate node */
|
|
405
|
+
id: string;
|
|
406
|
+
/** Parent node identifier (null for root nodes) */
|
|
407
|
+
parentId: string | null;
|
|
408
|
+
/** Root node identifier in the hierarchy */
|
|
409
|
+
rootId: string;
|
|
410
|
+
/** Indicates if this node has child nodes */
|
|
411
|
+
isParent: boolean;
|
|
412
|
+
/** Type or category description of the rate item */
|
|
413
|
+
itemTypeDescription: string;
|
|
414
|
+
/** Rate or item code */
|
|
415
|
+
code: string;
|
|
416
|
+
/** Human-readable description of the rate item */
|
|
417
|
+
description: string;
|
|
418
|
+
/** Total cost for this rate item (nullable) */
|
|
419
|
+
total: number | null;
|
|
420
|
+
/** Unit of measurement for the rate item (nullable) */
|
|
421
|
+
unit: string | null;
|
|
422
|
+
/** Labour hours required (nullable) */
|
|
423
|
+
manHours: number | null;
|
|
424
|
+
/** Plant hours required (nullable) */
|
|
425
|
+
plantHours: number | null;
|
|
426
|
+
/** Net labour cost (nullable) */
|
|
427
|
+
netLabour: number | null;
|
|
428
|
+
/** Net material cost (nullable) */
|
|
429
|
+
netMaterial: number | null;
|
|
430
|
+
/** Net plant cost (nullable) */
|
|
431
|
+
netPlant: number | null;
|
|
432
|
+
/** Specialist cost (nullable) */
|
|
433
|
+
specialist: number | null;
|
|
434
|
+
/** Hierarchical depth level of the node */
|
|
435
|
+
depth: number;
|
|
436
|
+
}>;
|
|
437
|
+
expandedNodes?: Array<{
|
|
438
|
+
/** Unique identifier for the rate node */
|
|
439
|
+
id: string;
|
|
440
|
+
/** Parent node identifier (null for root nodes) */
|
|
441
|
+
parentId: string | null;
|
|
442
|
+
/** Root node identifier in the hierarchy */
|
|
443
|
+
rootId: string;
|
|
444
|
+
/** Indicates if this node has child nodes */
|
|
445
|
+
isParent: boolean;
|
|
446
|
+
/** Type or category description of the rate item */
|
|
447
|
+
itemTypeDescription: string;
|
|
448
|
+
/** Rate or item code */
|
|
449
|
+
code: string;
|
|
450
|
+
/** Human-readable description of the rate item */
|
|
451
|
+
description: string;
|
|
452
|
+
/** Total cost for this rate item (nullable) */
|
|
453
|
+
total: number | null;
|
|
454
|
+
/** Unit of measurement for the rate item (nullable) */
|
|
455
|
+
unit: string | null;
|
|
456
|
+
/** Labour hours required (nullable) */
|
|
457
|
+
manHours: number | null;
|
|
458
|
+
/** Plant hours required (nullable) */
|
|
459
|
+
plantHours: number | null;
|
|
460
|
+
/** Net labour cost (nullable) */
|
|
461
|
+
netLabour: number | null;
|
|
462
|
+
/** Net material cost (nullable) */
|
|
463
|
+
netMaterial: number | null;
|
|
464
|
+
/** Net plant cost (nullable) */
|
|
465
|
+
netPlant: number | null;
|
|
466
|
+
/** Specialist cost (nullable) */
|
|
467
|
+
specialist: number | null;
|
|
468
|
+
/** Hierarchical depth level of the node */
|
|
469
|
+
depth: number;
|
|
470
|
+
}>;
|
|
471
|
+
}
|
|
472
|
+
interface GetResourceResponseDto {
|
|
473
|
+
rootNodes: Array<{
|
|
474
|
+
/** Unique identifier for the resource */
|
|
475
|
+
id: string;
|
|
476
|
+
/** Parent node ID (null for root resources) */
|
|
477
|
+
idParent: string | null;
|
|
478
|
+
/** Root node identifier in hierarchy */
|
|
479
|
+
idRoot: string;
|
|
480
|
+
/** Human-readable description of the resource */
|
|
481
|
+
description: string;
|
|
482
|
+
/** Resource code */
|
|
483
|
+
code: string;
|
|
484
|
+
/** Whether this resource has child resources */
|
|
485
|
+
isParent: boolean;
|
|
486
|
+
/** Total cost for this resource (nullable) */
|
|
487
|
+
total: number | null;
|
|
488
|
+
/** Unit of measurement for the resource */
|
|
489
|
+
unit: string;
|
|
490
|
+
/** Unit price for the resource */
|
|
491
|
+
unitPrice: number;
|
|
492
|
+
/** Quantity of the resource */
|
|
493
|
+
quantity: number;
|
|
494
|
+
/** Waste percentage or amount (nullable) */
|
|
495
|
+
waste: number | null;
|
|
496
|
+
/** Overhead and profit */
|
|
497
|
+
ohp: number;
|
|
498
|
+
/** Net labour cost (nullable) */
|
|
499
|
+
netLabour: number | null;
|
|
500
|
+
/** Net material cost (nullable) */
|
|
501
|
+
netMaterial: number | null;
|
|
502
|
+
/** Net plant cost (nullable) */
|
|
503
|
+
netPlant: number | null;
|
|
504
|
+
/** Specialist work (nullable) */
|
|
505
|
+
specialist: number | null;
|
|
506
|
+
/** Hierarchical depth level of the resource */
|
|
507
|
+
depth: number;
|
|
508
|
+
}>;
|
|
509
|
+
expandedNodes?: Array<{
|
|
510
|
+
/** Unique identifier for the resource */
|
|
511
|
+
id: string;
|
|
512
|
+
/** Parent node ID (null for root resources) */
|
|
513
|
+
idParent: string | null;
|
|
514
|
+
/** Root node identifier in hierarchy */
|
|
515
|
+
idRoot: string;
|
|
516
|
+
/** Human-readable description of the resource */
|
|
517
|
+
description: string;
|
|
518
|
+
/** Resource code */
|
|
519
|
+
code: string;
|
|
520
|
+
/** Whether this resource has child resources */
|
|
521
|
+
isParent: boolean;
|
|
522
|
+
/** Total cost for this resource (nullable) */
|
|
523
|
+
total: number | null;
|
|
524
|
+
/** Unit of measurement for the resource */
|
|
525
|
+
unit: string;
|
|
526
|
+
/** Unit price for the resource */
|
|
527
|
+
unitPrice: number;
|
|
528
|
+
/** Quantity of the resource */
|
|
529
|
+
quantity: number;
|
|
530
|
+
/** Waste percentage or amount (nullable) */
|
|
531
|
+
waste: number | null;
|
|
532
|
+
/** Overhead and profit */
|
|
533
|
+
ohp: number;
|
|
534
|
+
/** Net labour cost (nullable) */
|
|
535
|
+
netLabour: number | null;
|
|
536
|
+
/** Net material cost (nullable) */
|
|
537
|
+
netMaterial: number | null;
|
|
538
|
+
/** Net plant cost (nullable) */
|
|
539
|
+
netPlant: number | null;
|
|
540
|
+
/** Specialist work (nullable) */
|
|
541
|
+
specialist: number | null;
|
|
542
|
+
/** Hierarchical depth level of the resource */
|
|
543
|
+
depth: number;
|
|
544
|
+
}>;
|
|
545
|
+
}
|
|
546
|
+
type GetBuildUpResponseDto = Array<{
|
|
547
|
+
/** Unique identifier for the build-up item */
|
|
548
|
+
id: string | null;
|
|
549
|
+
/** Type clasification for the component) */
|
|
550
|
+
type: string | null;
|
|
551
|
+
/** Root code identifier for the component */
|
|
552
|
+
rootCode: string;
|
|
553
|
+
/** Specific code for the build-up item, can be null if not applicable */
|
|
554
|
+
itemCode: string | null;
|
|
555
|
+
/** Description of the build-up item, providing details about it */
|
|
556
|
+
description: string | null;
|
|
557
|
+
/** Quantity of the build-up item, can be null if not applicable */
|
|
558
|
+
quantity: number | null;
|
|
559
|
+
/** Unit of measurement for the build-up item (e.g., kg, m³) */
|
|
560
|
+
unit: string | null;
|
|
561
|
+
/** Rate or cost per unit of the build-up item, can be null if not applicable */
|
|
562
|
+
rate: number | null;
|
|
563
|
+
/** Total cost for the build-up item, calculated as quantity * rate */
|
|
564
|
+
total: number | null;
|
|
565
|
+
/** Item overhead allowance */
|
|
566
|
+
itemOA: number;
|
|
567
|
+
/** Hierarchical depth of the build-up item, indicating its level in a structure */
|
|
568
|
+
depth: number;
|
|
569
|
+
}>;
|
|
570
|
+
|
|
571
|
+
interface GetRatesParams {
|
|
572
|
+
/** node id, returned data are for the selected node */
|
|
573
|
+
'selected-node-id'?: string;
|
|
574
|
+
/** filter term, returned nodes contain the text somewhere in that branch */
|
|
575
|
+
'filter-text'?: string;
|
|
576
|
+
/** id obtained from get-books-edition */
|
|
577
|
+
'edition-id': string;
|
|
578
|
+
}
|
|
579
|
+
interface GetResourcesParams {
|
|
580
|
+
/** node id, returned data are for the selected node */
|
|
581
|
+
'selected-node-id'?: string;
|
|
582
|
+
/** filter term, returned nodes contain the text somewhere in that branch */
|
|
583
|
+
'filter-text'?: string;
|
|
584
|
+
/** id obtained from get-books-edition */
|
|
585
|
+
'edition-id': string;
|
|
586
|
+
}
|
|
587
|
+
interface GetBuildUpParams {
|
|
588
|
+
/** Id as returned from GetRates or GetResources */
|
|
589
|
+
'entity-id': string;
|
|
590
|
+
}
|
|
591
|
+
declare class ScheduleOfRatesClient {
|
|
592
|
+
private readonly client;
|
|
593
|
+
constructor(auth: AuthManager);
|
|
594
|
+
/** Lists books and editions available to user */
|
|
595
|
+
getBooksEdition(): Promise<EditionsDto>;
|
|
596
|
+
/** Lists matching rates */
|
|
597
|
+
getRates(params: GetRatesParams): Promise<GetRateResponseDto>;
|
|
598
|
+
/** Lists matching resources */
|
|
599
|
+
getResources(params: GetResourcesParams): Promise<GetResourceResponseDto>;
|
|
600
|
+
/** Lists components of a rate or buildUp */
|
|
601
|
+
getBuildUp(params: GetBuildUpParams): Promise<GetBuildUpResponseDto>;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
export { type AbpResponseDto, type AuthConfig, AuthManager, type AuthorizationCodeConfig, BcisApiError, type CalculationResponse, type ClientCredentialsConfig, type CodesResponseDto, CoreApiClient, type EditionsDto, type Error$1 as Error, type GetBuildUpResponseDto, type GetRateResponseDto, type GetResourceResponseDto, type IndicesResponseDto, ResidentialRebuildClient, ScheduleOfRatesClient, type TokenResponse, type TpsResponseDto, type UsageResponse };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
'use strict';var l=class{constructor(){this.token=null;}store(e){let r=e.expires_in!=null?Date.now()+e.expires_in*1e3:null;this.token={accessToken:e.access_token,expiresAt:r,refreshToken:e.refresh_token??null};}getAccessToken(){return this.token?.accessToken??null}getRefreshToken(){return this.token?.refreshToken??null}isExpired(e=30){return this.token?this.token.expiresAt===null?false:Date.now()>=this.token.expiresAt-e*1e3:true}clear(){this.token=null;}};async function m(t){let e=new URLSearchParams({grant_type:"client_credentials",client_id:t.clientId,client_secret:t.clientSecret});t.scopes&&t.scopes.length>0&&e.set("scope",t.scopes.join(" "));let r=await fetch(t.tokenUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:e.toString()});if(!r.ok){let n=await r.text().catch(()=>"");throw new Error(`Token request failed: ${r.status} ${r.statusText}${n?` \u2014 ${n}`:""}`)}return r.json()}function b(){let t=new Uint8Array(32);return crypto.getRandomValues(t),y(t)}async function A(t){let r=new TextEncoder().encode(t),n=await crypto.subtle.digest("SHA-256",r);return y(new Uint8Array(n))}function y(t){let e=String.fromCharCode(...t);return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}async function k(t,e){let r=b(),n=await A(r),s=new URLSearchParams({response_type:"code",client_id:t.clientId,redirect_uri:t.redirectUri,code_challenge:n,code_challenge_method:"S256"});return t.scopes&&t.scopes.length>0&&s.set("scope",t.scopes.join(" ")),e&&s.set("state",e),{url:`${t.authorizationUrl}?${s.toString()}`,codeVerifier:r}}async function R(t,e,r){let n=new URLSearchParams({grant_type:"authorization_code",client_id:t.clientId,redirect_uri:t.redirectUri,code:e,code_verifier:r});return C(t.tokenUrl,n)}async function w(t,e){let r=new URLSearchParams({grant_type:"refresh_token",client_id:t.clientId,refresh_token:e});return C(t.tokenUrl,r)}async function C(t,e){let r=await fetch(t,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:e.toString()});if(!r.ok){let n=await r.text().catch(()=>"");throw new Error(`Token request failed: ${r.status} ${r.statusText}${n?` \u2014 ${n}`:""}`)}return r.json()}var d=class{constructor(e){this.config=e;this.store=new l;this.inflight=null;}async getAccessToken(){if(!this.store.isExpired())return this.store.getAccessToken();if(this.inflight)return await this.inflight,this.store.getAccessToken();this.inflight=this.refresh();try{await this.inflight;}finally{this.inflight=null;}let e=this.store.getAccessToken();if(!e)throw new Error("Failed to obtain access token");return e}async getAuthorizationUrl(e){if(this.config.flow!=="authorization-code")throw new Error("getAuthorizationUrl is only available for authorization-code flow");return k(this.config,e)}async handleCallback(e,r){if(this.config.flow!=="authorization-code")throw new Error("handleCallback is only available for authorization-code flow");let n=await R(this.config,e,r);this.store.store(n);}clearTokens(){this.store.clear();}async refresh(){if(this.config.flow==="client-credentials"){let r=await m(this.config);this.store.store(r);return}let e=this.store.getRefreshToken();if(e){let r=await w(this.config,e);this.store.store(r);return}throw new Error("No valid token available. Call getAuthorizationUrl() and handleCallback() first.")}};var p=class extends Error{constructor(r,n,s){super(`BCIS API error ${r} ${n}`);this.status=r;this.statusText=n;this.body=s;this.name="BcisApiError";}},o=class{constructor(e){this.auth=e;}async get(e,r,n={}){let s=await this.auth.getAccessToken(),u=new URL(e+r);for(let[a,c]of Object.entries(n))if(c!=null)if(Array.isArray(c))for(let P of c)u.searchParams.append(a,String(P));else u.searchParams.set(a,String(c));let i=await fetch(u.toString(),{method:"GET",headers:{Authorization:`Bearer ${s}`,Accept:"application/json"}});if(!i.ok){let a;try{a=await i.json();}catch{a=await i.text();}throw new p(i.status,i.statusText,a)}return i.json()}};var h=class{constructor(e){this.client=new o(e);}async abpRetrieve(e){return this.client.get("https://api.bcis.co.uk/core-apis","/abp-retrieve",e)}async indicesRetrieve(e){return this.client.get("https://api.bcis.co.uk/core-apis","/indices-retrieve",e)}async tpsRetrieve(e){return this.client.get("https://api.bcis.co.uk/core-apis","/tps-retrieve",e)}async codesUpdate(e){return this.client.get("https://api.bcis.co.uk/core-apis","/codes-update",e)}};var g=class{constructor(e){this.client=new o(e);}async calculate(e){return this.client.get("https://api.bcis.co.uk/residential-rebuild-calculator","/rbls-calculate",e)}async reportUsage(e){return this.client.get("https://api.bcis.co.uk/residential-rebuild-calculator","/rbls-report-use",e)}};var f=class{constructor(e){this.client=new o(e);}async getBooksEdition(){return this.client.get("https://api.bcis.co.uk/schedule-of-rates","/get-books-edition",{})}async getRates(e){return this.client.get("https://api.bcis.co.uk/schedule-of-rates","/get-rates",e)}async getResources(e){return this.client.get("https://api.bcis.co.uk/schedule-of-rates","/get-resources",e)}async getBuildUp(e){return this.client.get("https://api.bcis.co.uk/schedule-of-rates","/get-build-up",e)}};
|
|
2
|
+
exports.AuthManager=d;exports.BcisApiError=p;exports.CoreApiClient=h;exports.ResidentialRebuildClient=g;exports.ScheduleOfRatesClient=f;//# sourceMappingURL=index.js.map
|
|
3
|
+
//# sourceMappingURL=index.js.map
|