@substrat-run/connector-planima 0.2.0
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 +75 -0
- package/package.json +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# @substrat-run/connector-planima
|
|
2
|
+
|
|
3
|
+
The Substrat connector for [Planima](https://planima.se/) — Swedish planned facility
|
|
4
|
+
maintenance (*underhållsplan*). Reads a maintenance plan on a poll and lands it into a
|
|
5
|
+
scope through the consuming vertical's own operation.
|
|
6
|
+
|
|
7
|
+
Full documentation: **[substrat.net/connectors/planima](https://substrat.net/connectors/planima)**.
|
|
8
|
+
|
|
9
|
+
> **Not yet verified against a live account.** Every claim here comes from Planima's
|
|
10
|
+
> published [OpenAPI document](https://developer.planima.se/) and is held up by a mock
|
|
11
|
+
> that encodes the same reading — so mock and client can agree with each other while both
|
|
12
|
+
> disagree with Planima. `test/live.test.ts` is written and skips until `PLANIMA_TOKEN` is
|
|
13
|
+
> present.
|
|
14
|
+
|
|
15
|
+
## What it is
|
|
16
|
+
|
|
17
|
+
- **Poll-only.** No event handler, no dispatch. Nothing inside a scope initiates this —
|
|
18
|
+
the plan changes in Planima and the platform finds out by looking.
|
|
19
|
+
- **Read-only.** Every call is a `GET`. Planima's write endpoints exist and are not used.
|
|
20
|
+
- **Host code**, never module code: it is swept on a `ScopeHost`, and module code cannot
|
|
21
|
+
reach `fetch` at all.
|
|
22
|
+
|
|
23
|
+
## Using it
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { bindPlanimaScope, sweepPlanimaPlan } from '@substrat-run/connector-planima';
|
|
27
|
+
import { globalFetch } from '@substrat-run/kernel';
|
|
28
|
+
|
|
29
|
+
// Once, per scope. Refuses if the connection does not hold the permission.
|
|
30
|
+
await bindPlanimaScope(host, {
|
|
31
|
+
connectionId,
|
|
32
|
+
tenantId,
|
|
33
|
+
scopeId,
|
|
34
|
+
vertical: 'maintenance',
|
|
35
|
+
operation: 'maintenance/record-plan', // YOUR operation
|
|
36
|
+
permission: 'plan:record', // which it checks
|
|
37
|
+
organizationId: null, // or one id
|
|
38
|
+
currency: 'SEK',
|
|
39
|
+
horizonYears: 10,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// On a timer, from the platform sweeper.
|
|
43
|
+
await sweepPlanimaPlan(host, connectionId, { fetch: globalFetch });
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Your landing operation receives a `PlanimaPlanPage`. Pages are global across one sync and
|
|
47
|
+
each names one facility: buildings and components ride the facility's first page
|
|
48
|
+
(`facilityHead`), actions ride every page 500 at a time, and `final` marks the last page of
|
|
49
|
+
the sync. Every page of one sync carries the same `syncId`, so an upsert keyed on it is
|
|
50
|
+
idempotent.
|
|
51
|
+
|
|
52
|
+
## The credential
|
|
53
|
+
|
|
54
|
+
One static API token, created in Planima under *account settings → API*.
|
|
55
|
+
|
|
56
|
+
**Mint it as a read-only user.** A Planima token carries the full access of whoever created
|
|
57
|
+
it and there are no scopes to narrow it — so choosing the user is the only control there
|
|
58
|
+
is, and this connector never writes.
|
|
59
|
+
|
|
60
|
+
## Development
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
pnpm --filter @substrat-run/connector-planima test # against the in-memory mock
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The live suite runs when a token is present, in `secrets/connectors.env` at the repo root
|
|
67
|
+
(canonical, shared by every connector), this package's `.dev.vars`, or `PLANIMA_TOKEN` in
|
|
68
|
+
the environment. See [`.dev.vars.example`](./.dev.vars.example).
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
PLANIMA_TOKEN=… pnpm --filter @substrat-run/connector-planima test
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
It is read-only and creates nothing, so it is safe against a real account — but it does
|
|
75
|
+
spend requests against a 10-per-10-second budget.
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@substrat-run/connector-planima",
|
|
3
|
+
"version": "0.2.0",
|
|
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
|
+
"license": "AGPL-3.0-only",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/substrat-run/substrat.git",
|
|
9
|
+
"directory": "connectors/planima"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://substrat.net/connectors/planima",
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"type": "module",
|
|
19
|
+
"main": "./dist/index.js",
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"default": "./dist/index.js"
|
|
25
|
+
}
|
|
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
|
+
"dependencies": {
|
|
33
|
+
"@substrat-run/contracts": "workspace:^",
|
|
34
|
+
"@substrat-run/kernel": "workspace:^"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@substrat-run/adapter-sqlite": "workspace:^",
|
|
38
|
+
"typescript": "catalog:",
|
|
39
|
+
"vitest": "catalog:",
|
|
40
|
+
"zod": "catalog:"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"zod": "^4.4.0"
|
|
44
|
+
}
|
|
45
|
+
}
|