@substrat-run/connector-planima 0.2.0 → 0.2.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/api.d.ts ADDED
@@ -0,0 +1,284 @@
1
+ import { z } from 'zod';
2
+ import type { ConnectorConnection } from '@substrat-run/kernel';
3
+ /**
4
+ * A thin, typed client over the Planima REST API.
5
+ *
6
+ * Every call goes through the connection's `fetch`, never a global one: that is what
7
+ * gets it a timeout, an egress policy, and health recorded against the right
8
+ * connection. Module code cannot reach any of this — boundary-lint bans `fetch`
9
+ * outright — and a connector is host code.
10
+ *
11
+ * ## One host, and the two headers that are easy to get wrong
12
+ *
13
+ * Unlike Fortnox there is no separate OAuth origin: Planima has a single host and a
14
+ * static token, so there is nothing to mint and nothing to refresh. What replaces that
15
+ * complexity is two header details the docs state once and a client gets wrong
16
+ * silently:
17
+ *
18
+ * 1. **`Authorization` carries the bare token** — no `Bearer` prefix. Planima's own
19
+ * curl example is `-H "Authorization: NotARealToken+tm6rdPsx23u+4/HiguLIFQw="`.
20
+ * Prefixing it is a 401 that reads exactly like a bad token.
21
+ * 2. **`Accept: application/vnd.planima.v1+json`** pins the version. Omitting it works
22
+ * today — v1 is the default — and is precisely the kind of thing that breaks on the
23
+ * day the default moves, months after the code that omitted it was written. So it
24
+ * is sent on every request rather than left to the default.
25
+ */
26
+ /** The one REST host. Everything hangs off this. */
27
+ export declare const PLANIMA_API_BASE = "https://api.planima.se";
28
+ /** The version-pinning `Accept` value — sent on every request, never defaulted to. */
29
+ export declare const PLANIMA_ACCEPT = "application/vnd.planima.v1+json";
30
+ /**
31
+ * Planima's page ceiling. Asking for more is not an error — the server silently caps —
32
+ * so the client asks for exactly this and paginates, rather than asking for a big
33
+ * number and believing the answer is complete.
34
+ */
35
+ export declare const PLANIMA_MAX_PAGE = 50;
36
+ /**
37
+ * A Planima connection's credential — one static API token, and nothing else.
38
+ *
39
+ * Created by a person in Planima under *account settings → API*, and it carries
40
+ * **that person's access level**: a token minted by a read-only user cannot write, and
41
+ * one minted by an admin can do everything that admin can. That is a fact worth
42
+ * stating in a credential's docs because it is the whole security model — there are no
43
+ * scopes to narrow, so the narrowing is done by choosing which user mints the token.
44
+ * A connector that only reads should be handed a read-only user's token, and this one
45
+ * only reads.
46
+ *
47
+ * There is no refresh token and no expiry, which removes the rotation hazard entirely
48
+ * and replaces it with a different one: a token is valid until a human revokes it in
49
+ * Planima, so revocation is out-of-band and the first this connector hears of it is a
50
+ * 401. {@link PlanimaApiError.refused} is what carries that distinction to the health
51
+ * record.
52
+ */
53
+ export declare const planimaSecret: z.ZodObject<{
54
+ token: z.ZodString;
55
+ }, z.core.$strip>;
56
+ export type PlanimaSecret = z.infer<typeof planimaSecret>;
57
+ /**
58
+ * A Planima API failure, with the two bits a caller actually branches on.
59
+ *
60
+ * `refused` means the provider said "not with this token" — a 401 or 403. Everything
61
+ * else (a timeout, a 5xx, a parse failure) says nothing about the credential, and
62
+ * treating it as a refusal would make a Planima outage look like every tenant's token
63
+ * going bad at once.
64
+ *
65
+ * `retryAfterSeconds` is set only on a 429 and only when Planima sent the header. It is
66
+ * the provider's own instruction, so the throttle below obeys it rather than guessing.
67
+ */
68
+ export declare class PlanimaApiError extends Error {
69
+ readonly status: number;
70
+ readonly refused: boolean;
71
+ readonly body: string;
72
+ readonly retryAfterSeconds: number | null;
73
+ constructor(message: string, status: number, body: string, retryAfterSeconds?: number | null);
74
+ }
75
+ /** A list's pagination block — the cursor the walk below is driven by. */
76
+ export declare const planimaPagination: z.ZodObject<{
77
+ total_count: z.ZodNumber;
78
+ offset: z.ZodNumber;
79
+ limit: z.ZodNumber;
80
+ }, z.core.$strip>;
81
+ export type PlanimaPagination = z.infer<typeof planimaPagination>;
82
+ export declare const planimaOrganization: z.ZodObject<{
83
+ id: z.ZodNumber;
84
+ name: z.ZodString;
85
+ updated_at: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
86
+ created_at: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
87
+ }, z.core.$strip>;
88
+ export type PlanimaOrganization = z.infer<typeof planimaOrganization>;
89
+ export declare const planimaFacility: z.ZodObject<{
90
+ id: z.ZodNumber;
91
+ name: z.ZodString;
92
+ address: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
93
+ zip_code: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
94
+ region: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
95
+ tags: z.ZodDefault<z.ZodArray<z.ZodString>>;
96
+ residential_area: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodNull]>>, z.ZodTransform<number | null, number | null | undefined>>;
97
+ non_residential_area: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodNull]>>, z.ZodTransform<number | null, number | null | undefined>>;
98
+ year_of_construction: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodNull]>>, z.ZodTransform<number | null, number | null | undefined>>;
99
+ description: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
100
+ organization: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
101
+ id: z.ZodNumber;
102
+ name: z.ZodString;
103
+ updated_at: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
104
+ created_at: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
105
+ }, z.core.$strip>, z.ZodNull]>>, z.ZodTransform<{
106
+ id: number;
107
+ name: string;
108
+ updated_at: string | null;
109
+ created_at: string | null;
110
+ } | null, {
111
+ id: number;
112
+ name: string;
113
+ updated_at: string | null;
114
+ created_at: string | null;
115
+ } | null | undefined>>;
116
+ updated_at: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
117
+ created_at: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
118
+ }, z.core.$strip>;
119
+ export type PlanimaFacility = z.infer<typeof planimaFacility>;
120
+ export declare const planimaBuilding: z.ZodObject<{
121
+ id: z.ZodNumber;
122
+ name: z.ZodString;
123
+ address: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
124
+ zip_code: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
125
+ region: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
126
+ year_of_construction: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodNull]>>, z.ZodTransform<number | null, number | null | undefined>>;
127
+ facility_id: z.ZodNumber;
128
+ updated_at: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
129
+ created_at: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
130
+ }, z.core.$strip>;
131
+ export type PlanimaBuilding = z.infer<typeof planimaBuilding>;
132
+ export declare const planimaComponent: z.ZodObject<{
133
+ id: z.ZodNumber;
134
+ name: z.ZodString;
135
+ amount: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodNull]>>, z.ZodTransform<number | null, number | null | undefined>>;
136
+ building_id: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodNull]>>, z.ZodTransform<number | null, number | null | undefined>>;
137
+ component: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
138
+ unit: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
139
+ category: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
140
+ type: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
141
+ facility_id: z.ZodNumber;
142
+ updated_at: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
143
+ created_at: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
144
+ }, z.core.$strip>;
145
+ export type PlanimaComponent = z.infer<typeof planimaComponent>;
146
+ /**
147
+ * One planned maintenance action — the row a maintenance plan is actually made of.
148
+ *
149
+ * Every price arrives as a JSON **number**. It does not stay one: see `plan.ts`, where
150
+ * it becomes a decimal string before it can reach a scope.
151
+ */
152
+ export declare const planimaAction: z.ZodObject<{
153
+ id: z.ZodNumber;
154
+ name: z.ZodString;
155
+ amount: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodNull]>>, z.ZodTransform<number | null, number | null | undefined>>;
156
+ unit: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
157
+ unit_price: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodNull]>>, z.ZodTransform<number | null, number | null | undefined>>;
158
+ total_price: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodNull]>>, z.ZodTransform<number | null, number | null | undefined>>;
159
+ total_price_incl_vat: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodNull]>>, z.ZodTransform<number | null, number | null | undefined>>;
160
+ year: z.ZodNumber;
161
+ status: z.ZodString;
162
+ description: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
163
+ investment_rate: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodNull]>>, z.ZodTransform<number | null, number | null | undefined>>;
164
+ vat_rate: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodNull]>>, z.ZodTransform<number | null, number | null | undefined>>;
165
+ category: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
166
+ location: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
167
+ building: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
168
+ building_id: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodNull]>>, z.ZodTransform<number | null, number | null | undefined>>;
169
+ component_id: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodNull]>>, z.ZodTransform<number | null, number | null | undefined>>;
170
+ is_energy_saving: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
171
+ co2_equivalent: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodNull]>>, z.ZodTransform<number | null, number | null | undefined>>;
172
+ final_cost: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodNull]>>, z.ZodTransform<number | null, number | null | undefined>>;
173
+ tags: z.ZodDefault<z.ZodArray<z.ZodString>>;
174
+ facility: z.ZodOptional<z.ZodObject<{
175
+ id: z.ZodNumber;
176
+ name: z.ZodString;
177
+ }, z.core.$strip>>;
178
+ project_id: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodNull]>>, z.ZodTransform<number | null, number | null | undefined>>;
179
+ updated_at: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
180
+ created_at: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | null, string | null | undefined>>;
181
+ }, z.core.$strip>;
182
+ export type PlanimaAction = z.infer<typeof planimaAction>;
183
+ /**
184
+ * The eight action statuses Planima documents as its `status` filter enum.
185
+ *
186
+ * Exported as data rather than enforced as a schema, and that is the point: the field
187
+ * itself is typed `string` in Planima's own spec, so a ninth status is an ordinary
188
+ * product change, not a protocol break. Parsing against a closed set would turn that
189
+ * into a sweep-wide throw — a whole tenant's plan failing to land because one action
190
+ * moved to a status added last week. A consumer that wants to branch on status has the
191
+ * list; the connector passes through whatever arrived.
192
+ */
193
+ export declare const PLANIMA_ACTION_STATUSES: readonly ['draft', 'planned', 'prioritized', 'decided', 'in_progress', 'deferred', 'completed', 'inactive'];
194
+ export interface PlanimaApiOptions {
195
+ apiBase?: string;
196
+ /** Injected so a test can assert elapsed time without sleeping. */
197
+ now?: () => number;
198
+ /** Injected for the same reason — the throttle waits through this, never a real timer. */
199
+ sleep?: (ms: number) => Promise<void>;
200
+ /**
201
+ * How many 429s in a row this client will sit out before giving up on a request.
202
+ * Zero disables the retry entirely, which is what a probe wants.
203
+ */
204
+ maxRateLimitRetries?: number;
205
+ /**
206
+ * A sliding window SHARED with other clients using the same token.
207
+ *
208
+ * Planima's limit is per token, not per client, so a sweep that builds one
209
+ * `PlanimaApi` per bound scope gives each a fresh window — and the second scope's
210
+ * first ten requests go out on top of the first scope's, which is a burst of twenty
211
+ * in one window. Passing one array through a whole sweep makes the throttle model
212
+ * the thing the provider actually meters.
213
+ */
214
+ rateWindow?: number[];
215
+ }
216
+ export declare class PlanimaApi {
217
+ private readonly conn;
218
+ private readonly apiBase;
219
+ private readonly now;
220
+ private readonly sleep;
221
+ private readonly maxRateLimitRetries;
222
+ /**
223
+ * When the last {@link RATE_LIMIT_REQUESTS} requests went out, oldest first.
224
+ *
225
+ * Per-instance by default, matching `FortnoxApi`'s token cache: an instance is built
226
+ * for one unit of work, so the window lives exactly as long as that work and no
227
+ * cross-request state accumulates in a Worker's isolate. But the limit Planima
228
+ * enforces is per TOKEN, so a caller that builds several clients on one token passes
229
+ * {@link PlanimaApiOptions.rateWindow} to share one — which `sweepPlanimaPlan` does
230
+ * across every binding in a pass.
231
+ *
232
+ * What that still does not cover, stated rather than hidden: two sweeps overlapping
233
+ * on one token, or the tenant's own scripts using it. Both are absorbed by the 429
234
+ * retry below rather than prevented here, because preventing them needs a lock this
235
+ * connector has nowhere to keep.
236
+ */
237
+ private readonly sent;
238
+ constructor(conn: ConnectorConnection, options?: PlanimaApiOptions);
239
+ private secret;
240
+ /** Wait, if the sliding window says the next request would breach the limit. */
241
+ private throttle;
242
+ /**
243
+ * A JSON GET against the REST host, throttled, and retried through a 429.
244
+ *
245
+ * The retry exists because the window above cannot be authoritative: it models one
246
+ * client's own traffic, and the tenant's token may be in use by their own scripts at
247
+ * the same time. When Planima says "too many", it says how long to wait — so the
248
+ * client obeys `Retry-After` rather than backing off on a schedule of its own
249
+ * invention, and gives up after {@link PlanimaApiOptions.maxRateLimitRetries} so a
250
+ * pathologically busy token surfaces as a failed sweep instead of a hung one.
251
+ */
252
+ private getJson;
253
+ /**
254
+ * Walk every page of a list endpoint.
255
+ *
256
+ * Termination is driven by what came BACK, never by `total_count` alone: a plan that
257
+ * grows mid-walk would otherwise leave the loop reading past the end, and a
258
+ * `total_count` that disagrees with the rows (a filter applied server-side after the
259
+ * count) would loop forever. An empty page ends the walk, and `total_count` is used
260
+ * only as the belt to that braces — a bound on how many pages can be worth asking
261
+ * for.
262
+ */
263
+ private list;
264
+ /** Every organization this token can see — the probe read, and the sweep's entry point. */
265
+ organizations(): Promise<PlanimaOrganization[]>;
266
+ /** Every facility, optionally narrowed to one organization. */
267
+ facilities(organizationId?: number): Promise<PlanimaFacility[]>;
268
+ /** One facility's buildings. */
269
+ buildings(facilityId: number): Promise<PlanimaBuilding[]>;
270
+ /** One facility's components. */
271
+ components(facilityId: number): Promise<PlanimaComponent[]>;
272
+ /**
273
+ * One facility's planned actions, over a year window.
274
+ *
275
+ * The window is server-side (`start_year`/`end_year`) rather than a filter applied
276
+ * after the fact, because a maintenance plan routinely runs 30 years out and pulling
277
+ * all of it to keep five years is a rate-limit budget spent on rows that get dropped.
278
+ */
279
+ actions(facilityId: number, window: {
280
+ fromYear: number;
281
+ toYear: number;
282
+ }): Promise<PlanimaAction[]>;
283
+ }
284
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}