@substrat-run/connector-planima 0.2.0 → 0.2.2

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/plan.js ADDED
@@ -0,0 +1,226 @@
1
+ import { z } from 'zod';
2
+ import { money, moneyAmount } from '@substrat-run/contracts';
3
+ /**
4
+ * Provider rows → the neutral facts that cross into a scope.
5
+ *
6
+ * Two conversions happen here and nowhere else, and both are the kind of thing that is
7
+ * wrong forever if it is wrong once:
8
+ *
9
+ * 1. **Every number that is money becomes a decimal string.** Planima sends JSON
10
+ * numbers — `total_price: 125000.5` — and a JSON number is an IEEE double. Substrat
11
+ * money is decimal strings via `@substrat-run/contracts`, never floats (K-14), so
12
+ * the conversion belongs at the edge where the double arrives rather than in every
13
+ * consumer that later adds two of them up.
14
+ * 2. **`snake_case` becomes `camelCase`.** The provider's spelling stops at this file.
15
+ * A vertical reading `zip_code` off a payload has Planima's API shape leaking into
16
+ * its own vocabulary, and the day Planima renames a field, every consumer changes.
17
+ *
18
+ * What does NOT happen here is interpretation. A status stays whatever string arrived,
19
+ * a category stays a name, and nothing is mapped to a vertical's vocabulary — that is
20
+ * the consumer's layer, and a connector that did it would be a vertical wearing a
21
+ * connector's clothes.
22
+ */
23
+ /**
24
+ * A JSON number as a decimal string, at `moneyAmount`'s six-decimal ceiling.
25
+ *
26
+ * **It rounds, and that is a deliberate choice rather than an oversight.** `toFixed(6)`
27
+ * is half-away-from-zero at the sixth decimal, so `1.0000009` becomes `1.000001`. The
28
+ * alternative — refusing any value that does not round-trip — was considered and
29
+ * rejected, because it fails on data Planima legitimately sends: `investment_rate` is a
30
+ * computed fraction, and a third is `0.3333333333333333`. Refusing would take down a
31
+ * whole tenant's sync over a ratio, which is a far worse outcome than losing precision
32
+ * below the sixth decimal of a value that is either kronor (two decimals of real
33
+ * precision) or a ratio (where six is already more than anyone means).
34
+ *
35
+ * What that costs is worth naming: the rounded value is what lands AND what the content
36
+ * hash is computed over, so two plans differing only past the sixth decimal are one
37
+ * plan as far as this connector is concerned. For prices and ratios, they are.
38
+ *
39
+ * Trailing zeros are trimmed so `125000.50` and `125000.5` are the same string — the
40
+ * content hash is a change detector, and two spellings of one number would make an
41
+ * unchanged plan look changed on every sweep.
42
+ *
43
+ * Two inputs are refused rather than coerced, because both would produce a string that
44
+ * lies: a non-finite number has no decimal form at all, and `toFixed` switches to
45
+ * exponential notation at 1e21, which `moneyAmount`'s regex rejects downstream — far
46
+ * from here, with no clue which field caused it.
47
+ */
48
+ export function decimalOf(value, what) {
49
+ if (!Number.isFinite(value)) {
50
+ throw new Error(`Planima sent a non-finite number for ${what}: ${String(value)}`);
51
+ }
52
+ if (Math.abs(value) >= 1e21) {
53
+ throw new Error(`Planima sent an out-of-range number for ${what}: ${String(value)}`);
54
+ }
55
+ const fixed = value.toFixed(6);
56
+ const trimmed = fixed.includes('.') ? fixed.replace(/0+$/, '').replace(/\.$/, '') : fixed;
57
+ // `(-0).toFixed(6)` is `"-0.000000"`, which trims to `"-0"` — a legal `moneyAmount`
58
+ // that is nonetheless a second spelling of zero, and therefore a phantom change.
59
+ return trimmed === '-0' ? '0' : trimmed;
60
+ }
61
+ /** A nullable JSON number as nullable money in the plan's currency. */
62
+ const moneyOrNull = (value, currency, what) => value === null ? null : money.parse({ amount: decimalOf(value, what), currency });
63
+ /** A nullable JSON number as a nullable decimal string — for rates and quantities, which are not money. */
64
+ const decimalOrNull = (value, what) => value === null ? null : decimalOf(value, what);
65
+ // ---------------------------------------------------------------------------
66
+ // The facts. These are the published shape — parsed on the way OUT, before every
67
+ // invoke, for the reason `returns()` exists on an engine seam.
68
+ // ---------------------------------------------------------------------------
69
+ /** A decimal string, in the same six-decimal shape money uses, for values that are not money. */
70
+ export const planimaDecimal = z.string().regex(/^-?\d+(\.\d{1,6})?$/);
71
+ export const planimaFacilityFact = z.object({
72
+ id: z.number().int(),
73
+ name: z.string(),
74
+ address: z.string().nullable(),
75
+ zipCode: z.string().nullable(),
76
+ region: z.string().nullable(),
77
+ tags: z.array(z.string()),
78
+ /** Residential area (sv. BOA) in m². */
79
+ residentialArea: planimaDecimal.nullable(),
80
+ /** Non-residential area (sv. LOA) in m². */
81
+ nonResidentialArea: planimaDecimal.nullable(),
82
+ yearOfConstruction: z.number().int().nullable(),
83
+ description: z.string().nullable(),
84
+ });
85
+ export const planimaBuildingFact = z.object({
86
+ id: z.number().int(),
87
+ facilityId: z.number().int(),
88
+ name: z.string(),
89
+ address: z.string().nullable(),
90
+ zipCode: z.string().nullable(),
91
+ region: z.string().nullable(),
92
+ yearOfConstruction: z.number().int().nullable(),
93
+ });
94
+ export const planimaComponentFact = z.object({
95
+ id: z.number().int(),
96
+ facilityId: z.number().int(),
97
+ buildingId: z.number().int().nullable(),
98
+ name: z.string(),
99
+ /** The component DEFINITION's name — what kind of thing this is, as against what it is called. */
100
+ component: z.string().nullable(),
101
+ category: z.string().nullable(),
102
+ type: z.string().nullable(),
103
+ amount: planimaDecimal.nullable(),
104
+ unit: z.string().nullable(),
105
+ });
106
+ export const planimaActionFact = z.object({
107
+ id: z.number().int(),
108
+ facilityId: z.number().int(),
109
+ buildingId: z.number().int().nullable(),
110
+ componentId: z.number().int().nullable(),
111
+ projectId: z.number().int().nullable(),
112
+ name: z.string(),
113
+ /** The year the action is to be performed — the axis a maintenance plan is read along. */
114
+ year: z.number().int(),
115
+ /**
116
+ * Planima's own status string, passed through unmapped.
117
+ *
118
+ * Not an enum, deliberately: Planima types this `string` in its own spec even though
119
+ * it documents eight values for the matching filter, so a ninth is a product change
120
+ * rather than a protocol break. `PLANIMA_ACTION_STATUSES` is exported for a consumer
121
+ * that wants to branch, but nothing here refuses an unknown one — a whole tenant's
122
+ * plan failing to land because one action moved to a new status is a worse outcome
123
+ * than a consumer seeing a string it does not recognise.
124
+ */
125
+ status: z.string(),
126
+ description: z.string().nullable(),
127
+ amount: planimaDecimal.nullable(),
128
+ unit: z.string().nullable(),
129
+ unitPrice: money.nullable(),
130
+ totalPrice: money.nullable(),
131
+ totalPriceInclVat: money.nullable(),
132
+ /** Set once the action is completed. */
133
+ finalCost: money.nullable(),
134
+ /** A decimal FRACTION, as Planima states it: `0.25` is 25 %. */
135
+ vatRate: planimaDecimal.nullable(),
136
+ /** The fraction of the cost treated as investment rather than maintenance. */
137
+ investmentRate: planimaDecimal.nullable(),
138
+ isEnergySaving: z.boolean(),
139
+ co2EquivalentKg: planimaDecimal.nullable(),
140
+ /** Top-level category name, and the facility/building NAMES Planima denormalizes onto an action. */
141
+ category: z.string().nullable(),
142
+ location: z.string().nullable(),
143
+ building: z.string().nullable(),
144
+ tags: z.array(z.string()),
145
+ updatedAt: z.string().nullable(),
146
+ });
147
+ // ---------------------------------------------------------------------------
148
+ // Conversion
149
+ // ---------------------------------------------------------------------------
150
+ export const facilityFact = (row) => ({
151
+ id: row.id,
152
+ name: row.name,
153
+ address: row.address,
154
+ zipCode: row.zip_code,
155
+ region: row.region,
156
+ tags: row.tags,
157
+ residentialArea: decimalOrNull(row.residential_area, `facility ${row.id} residential_area`),
158
+ nonResidentialArea: decimalOrNull(row.non_residential_area, `facility ${row.id} non_residential_area`),
159
+ yearOfConstruction: row.year_of_construction === null ? null : Math.trunc(row.year_of_construction),
160
+ description: row.description,
161
+ });
162
+ export const buildingFact = (row) => ({
163
+ id: row.id,
164
+ facilityId: row.facility_id,
165
+ name: row.name,
166
+ address: row.address,
167
+ zipCode: row.zip_code,
168
+ region: row.region,
169
+ yearOfConstruction: row.year_of_construction === null ? null : Math.trunc(row.year_of_construction),
170
+ });
171
+ export const componentFact = (row) => ({
172
+ id: row.id,
173
+ facilityId: row.facility_id,
174
+ buildingId: row.building_id === null ? null : Math.trunc(row.building_id),
175
+ name: row.name,
176
+ component: row.component,
177
+ category: row.category,
178
+ type: row.type,
179
+ amount: decimalOrNull(row.amount, `component ${row.id} amount`),
180
+ unit: row.unit,
181
+ });
182
+ export const actionFact = (row, currency) => ({
183
+ id: row.id,
184
+ // Planima nests the facility on an action rather than sending a flat id. The
185
+ // connector always fetches actions BY facility, so the id is known either way — but
186
+ // reading it from the row keeps the fact self-describing for a consumer that stores
187
+ // one action without its page.
188
+ facilityId: row.facility?.id ?? 0,
189
+ buildingId: row.building_id === null ? null : Math.trunc(row.building_id),
190
+ componentId: row.component_id === null ? null : Math.trunc(row.component_id),
191
+ projectId: row.project_id === null ? null : Math.trunc(row.project_id),
192
+ name: row.name,
193
+ year: row.year,
194
+ status: row.status,
195
+ description: row.description,
196
+ amount: decimalOrNull(row.amount, `action ${row.id} amount`),
197
+ unit: row.unit,
198
+ unitPrice: moneyOrNull(row.unit_price, currency, `action ${row.id} unit_price`),
199
+ totalPrice: moneyOrNull(row.total_price, currency, `action ${row.id} total_price`),
200
+ totalPriceInclVat: moneyOrNull(row.total_price_incl_vat, currency, `action ${row.id} total_price_incl_vat`),
201
+ finalCost: moneyOrNull(row.final_cost, currency, `action ${row.id} final_cost`),
202
+ vatRate: decimalOrNull(row.vat_rate, `action ${row.id} vat_rate`),
203
+ investmentRate: decimalOrNull(row.investment_rate, `action ${row.id} investment_rate`),
204
+ isEnergySaving: row.is_energy_saving,
205
+ co2EquivalentKg: decimalOrNull(row.co2_equivalent, `action ${row.id} co2_equivalent`),
206
+ category: row.category,
207
+ location: row.location,
208
+ building: row.building,
209
+ tags: row.tags,
210
+ updatedAt: row.updated_at,
211
+ });
212
+ /**
213
+ * An action fact with the facility id filled in from the fetch that produced it.
214
+ *
215
+ * `Action.facility` is documented as present, but it is one optional nesting away from
216
+ * being absent, and a fact whose `facilityId` is `0` is worse than one that throws:
217
+ * it silently attaches a real action to a facility that does not exist. The caller
218
+ * always knows which facility it asked for, so it says so.
219
+ */
220
+ export const actionFactIn = (row, facilityId, currency) => ({
221
+ ...actionFact(row, currency),
222
+ facilityId,
223
+ });
224
+ /** The moneyAmount brand, re-exported so a consumer can parse a bare amount without importing contracts twice. */
225
+ export { moneyAmount };
226
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.js","sourceRoot":"","sources":["../src/plan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,KAAK,EAAE,WAAW,EAAc,MAAM,yBAAyB,CAAC;AAGzE;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,SAAS,CAAC,KAAa,EAAE,IAAY;IACnD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,KAAK,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACpF,CAAC;IACD,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,2CAA2C,IAAI,KAAK,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACvF,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAC1F,oFAAoF;IACpF,iFAAiF;IACjF,OAAO,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;AAC1C,CAAC;AAED,uEAAuE;AACvE,MAAM,WAAW,GAAG,CAAC,KAAoB,EAAE,QAAgB,EAAE,IAAY,EAAgB,EAAE,CACzF,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;AAEpF,2GAA2G;AAC3G,MAAM,aAAa,GAAG,CAAC,KAAoB,EAAE,IAAY,EAAiB,EAAE,CAC1E,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AAEjD,8EAA8E;AAC9E,iFAAiF;AACjF,+DAA+D;AAC/D,8EAA8E;AAE9E,iGAAiG;AACjG,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;AAEtE,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACpB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACzB,wCAAwC;IACxC,eAAe,EAAE,cAAc,CAAC,QAAQ,EAAE;IAC1C,4CAA4C;IAC5C,kBAAkB,EAAE,cAAc,CAAC,QAAQ,EAAE;IAC7C,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAC/C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACnC,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACpB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IAC5B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;CAChD,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACpB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IAC5B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACvC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,kGAAkG;IAClG,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,MAAM,EAAE,cAAc,CAAC,QAAQ,EAAE;IACjC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC5B,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACpB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IAC5B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACvC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACxC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACtC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,0FAA0F;IAC1F,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACtB;;;;;;;;;OASG;IACH,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAClC,MAAM,EAAE,cAAc,CAAC,QAAQ,EAAE;IACjC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,SAAS,EAAE,KAAK,CAAC,QAAQ,EAAE;IAC3B,UAAU,EAAE,KAAK,CAAC,QAAQ,EAAE;IAC5B,iBAAiB,EAAE,KAAK,CAAC,QAAQ,EAAE;IACnC,wCAAwC;IACxC,SAAS,EAAE,KAAK,CAAC,QAAQ,EAAE;IAC3B,gEAAgE;IAChE,OAAO,EAAE,cAAc,CAAC,QAAQ,EAAE;IAClC,8EAA8E;IAC9E,cAAc,EAAE,cAAc,CAAC,QAAQ,EAAE;IACzC,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE;IAC3B,eAAe,EAAE,cAAc,CAAC,QAAQ,EAAE;IAC1C,oGAAoG;IACpG,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACzB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAC;AAGH,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAoB,EAAuB,EAAE,CAAC,CAAC;IAC1E,EAAE,EAAE,GAAG,CAAC,EAAE;IACV,IAAI,EAAE,GAAG,CAAC,IAAI;IACd,OAAO,EAAE,GAAG,CAAC,OAAO;IACpB,OAAO,EAAE,GAAG,CAAC,QAAQ;IACrB,MAAM,EAAE,GAAG,CAAC,MAAM;IAClB,IAAI,EAAE,GAAG,CAAC,IAAI;IACd,eAAe,EAAE,aAAa,CAAC,GAAG,CAAC,gBAAgB,EAAE,YAAY,GAAG,CAAC,EAAE,mBAAmB,CAAC;IAC3F,kBAAkB,EAAE,aAAa,CAAC,GAAG,CAAC,oBAAoB,EAAE,YAAY,GAAG,CAAC,EAAE,uBAAuB,CAAC;IACtG,kBAAkB,EAAE,GAAG,CAAC,oBAAoB,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,oBAAoB,CAAC;IACnG,WAAW,EAAE,GAAG,CAAC,WAAW;CAC7B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAoB,EAAuB,EAAE,CAAC,CAAC;IAC1E,EAAE,EAAE,GAAG,CAAC,EAAE;IACV,UAAU,EAAE,GAAG,CAAC,WAAW;IAC3B,IAAI,EAAE,GAAG,CAAC,IAAI;IACd,OAAO,EAAE,GAAG,CAAC,OAAO;IACpB,OAAO,EAAE,GAAG,CAAC,QAAQ;IACrB,MAAM,EAAE,GAAG,CAAC,MAAM;IAClB,kBAAkB,EAAE,GAAG,CAAC,oBAAoB,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,oBAAoB,CAAC;CACpG,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAqB,EAAwB,EAAE,CAAC,CAAC;IAC7E,EAAE,EAAE,GAAG,CAAC,EAAE;IACV,UAAU,EAAE,GAAG,CAAC,WAAW;IAC3B,UAAU,EAAE,GAAG,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC;IACzE,IAAI,EAAE,GAAG,CAAC,IAAI;IACd,SAAS,EAAE,GAAG,CAAC,SAAS;IACxB,QAAQ,EAAE,GAAG,CAAC,QAAQ;IACtB,IAAI,EAAE,GAAG,CAAC,IAAI;IACd,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,GAAG,CAAC,EAAE,SAAS,CAAC;IAC/D,IAAI,EAAE,GAAG,CAAC,IAAI;CACf,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,GAAkB,EAAE,QAAgB,EAAqB,EAAE,CAAC,CAAC;IACtF,EAAE,EAAE,GAAG,CAAC,EAAE;IACV,6EAA6E;IAC7E,oFAAoF;IACpF,oFAAoF;IACpF,+BAA+B;IAC/B,UAAU,EAAE,GAAG,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC;IACjC,UAAU,EAAE,GAAG,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC;IACzE,WAAW,EAAE,GAAG,CAAC,YAAY,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC;IAC5E,SAAS,EAAE,GAAG,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC;IACtE,IAAI,EAAE,GAAG,CAAC,IAAI;IACd,IAAI,EAAE,GAAG,CAAC,IAAI;IACd,MAAM,EAAE,GAAG,CAAC,MAAM;IAClB,WAAW,EAAE,GAAG,CAAC,WAAW;IAC5B,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,GAAG,CAAC,EAAE,SAAS,CAAC;IAC5D,IAAI,EAAE,GAAG,CAAC,IAAI;IACd,SAAS,EAAE,WAAW,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,EAAE,UAAU,GAAG,CAAC,EAAE,aAAa,CAAC;IAC/E,UAAU,EAAE,WAAW,CAAC,GAAG,CAAC,WAAW,EAAE,QAAQ,EAAE,UAAU,GAAG,CAAC,EAAE,cAAc,CAAC;IAClF,iBAAiB,EAAE,WAAW,CAAC,GAAG,CAAC,oBAAoB,EAAE,QAAQ,EAAE,UAAU,GAAG,CAAC,EAAE,uBAAuB,CAAC;IAC3G,SAAS,EAAE,WAAW,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,EAAE,UAAU,GAAG,CAAC,EAAE,aAAa,CAAC;IAC/E,OAAO,EAAE,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,GAAG,CAAC,EAAE,WAAW,CAAC;IACjE,cAAc,EAAE,aAAa,CAAC,GAAG,CAAC,eAAe,EAAE,UAAU,GAAG,CAAC,EAAE,kBAAkB,CAAC;IACtF,cAAc,EAAE,GAAG,CAAC,gBAAgB;IACpC,eAAe,EAAE,aAAa,CAAC,GAAG,CAAC,cAAc,EAAE,UAAU,GAAG,CAAC,EAAE,iBAAiB,CAAC;IACrF,QAAQ,EAAE,GAAG,CAAC,QAAQ;IACtB,QAAQ,EAAE,GAAG,CAAC,QAAQ;IACtB,QAAQ,EAAE,GAAG,CAAC,QAAQ;IACtB,IAAI,EAAE,GAAG,CAAC,IAAI;IACd,SAAS,EAAE,GAAG,CAAC,UAAU;CAC1B,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAkB,EAAE,UAAkB,EAAE,QAAgB,EAAqB,EAAE,CAAC,CAAC;IAC5G,GAAG,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC;IAC5B,UAAU;CACX,CAAC,CAAC;AAEH,kHAAkH;AAClH,OAAO,EAAE,WAAW,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@substrat-run/connector-planima",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Substrat connector: Planima planned facility maintenance (Swedish). Reads a maintenance plan — facilities, buildings, components and actions — on a poll and lands it into a scope through the vertical's own operation. Auth is a static API token, so there is no token to refresh. Host code — swept on a ScopeHost, never module code.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {
@@ -24,22 +24,22 @@
24
24
  "default": "./dist/index.js"
25
25
  }
26
26
  },
27
- "scripts": {
28
- "build": "tsc -p tsconfig.json",
29
- "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit",
30
- "test": "vitest run"
31
- },
32
27
  "dependencies": {
33
- "@substrat-run/contracts": "workspace:^",
34
- "@substrat-run/kernel": "workspace:^"
28
+ "@substrat-run/contracts": "^0.105.0",
29
+ "@substrat-run/kernel": "^0.105.0"
35
30
  },
36
31
  "devDependencies": {
37
- "@substrat-run/adapter-sqlite": "workspace:^",
38
- "typescript": "catalog:",
39
- "vitest": "catalog:",
40
- "zod": "catalog:"
32
+ "typescript": "^7.0.0",
33
+ "vitest": "^3.2.7",
34
+ "zod": "^4.4.3",
35
+ "@substrat-run/adapter-sqlite": "^0.105.0"
41
36
  },
42
37
  "peerDependencies": {
43
38
  "zod": "^4.4.0"
39
+ },
40
+ "scripts": {
41
+ "build": "tsc -p tsconfig.json",
42
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit",
43
+ "test": "vitest run"
44
44
  }
45
- }
45
+ }