@uns-kit/core 3.0.44 → 3.0.45

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/MIGRATIONS.md CHANGED
@@ -9,6 +9,25 @@ Agents must inspect the application's existing ownership and shutdown flow
9
9
  before editing it. The examples below describe the intended behavior, not a
10
10
  mechanical search-and-replace operation.
11
11
 
12
+ ## 3.0.45 - Opt-in retained-store storage protocol
13
+
14
+ When crossing `<3.0.45` to `>=3.0.45`, ordinary applications keep their current
15
+ behavior. Applications adopting bound
16
+ retained stores must declare `storageProtocol: 1`, resolve only the shared resource
17
+ paths, acquire `openRetainedStoreLease(binding)` before opening payload writers,
18
+ and release it only after final writer cleanup. Do not infer support from a Kit
19
+ version or default an old omitted capability to supported. Classify manifest
20
+ resources explicitly as backup payload or metadata when needed.
21
+
22
+ Read the [bundled guide](dist/runtime/retained-store-guide.md) and the two
23
+ unrelated manifests in `dist/runtime/retained-store-examples/`. The source guide
24
+ is `docs/retained-store-adoption.md` in the SDK repository.
25
+ Managed use requires the Runtime's external retained-store root. Older local
26
+ candidate bindings/layouts need reviewed initialization/relocation; the SDK never
27
+ silently changes their absolute roots or converts application data. Snapshot
28
+ requires stopped owners. Preserve original volumes and handle unknown outcomes
29
+ through the same operation ID before restarting any owner.
30
+
12
31
  ## 3.0.44 - Bounded operator JWKS recovery
13
32
 
14
33
  When crossing `<3.0.44` to `>=3.0.44`, ordinary application handlers, standalone
package/README.md CHANGED
@@ -29,6 +29,20 @@ npm install @uns-kit/core
29
29
  - **MQTT helpers** — resilient publishers, topic builders, throttled queues, and handover support.
30
30
  - **gRPC gateway** — infrastructure to bridge Python workers into the UNS message fabric.
31
31
 
32
+ ## Optional retained stores (3.0.45)
33
+
34
+ Applications can explicitly declare stable opaque resources for reviewed
35
+ same-host adoption, offline backup and recovery. Import the shared contract from
36
+ `@uns-kit/core/runtime/retained-store.js`; hold its store lease before opening
37
+ payload writers. Ordinary applications retain their existing behavior.
38
+
39
+ Read the [bundled guide](dist/runtime/retained-store-guide.md) and manifests in
40
+ `dist/runtime/retained-store-examples/`, or the
41
+ [source guide](https://github.com/uns-openhub/uns-kit/blob/master/docs/retained-store-adoption.md).
42
+ Runtime mounts, Controller orchestration and helper releases must also support
43
+ the declared capability. The SDK version alone grants no permissions and does
44
+ not move data, enable queues or change the handover protocol.
45
+
32
46
  ## Basic usage
33
47
 
34
48
  ```ts
@@ -0,0 +1,22 @@
1
+ {
2
+ "protocol": 1,
3
+ "format": "text-index-v1",
4
+ "resources": [
5
+ {
6
+ "id": "queue",
7
+ "path": "index-data",
8
+ "kind": "directory",
9
+ "required": true,
10
+ "backup": "payload"
11
+ },
12
+ {
13
+ "id": "replay",
14
+ "path": "maintenance.json",
15
+ "kind": "file",
16
+ "required": false,
17
+ "backup": "metadata"
18
+ }
19
+ ],
20
+ "legacyVersions": [],
21
+ "storageProtocol": 1
22
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "protocol": 1,
3
+ "format": "measurement-journal-v1",
4
+ "resources": [
5
+ {
6
+ "id": "queue",
7
+ "path": "pending-events",
8
+ "kind": "directory",
9
+ "required": true,
10
+ "backup": "payload"
11
+ },
12
+ {
13
+ "id": "policy",
14
+ "path": "destination-policy.json",
15
+ "kind": "file",
16
+ "required": false,
17
+ "backup": "metadata"
18
+ }
19
+ ],
20
+ "legacyVersions": ["1.0.0"],
21
+ "storageProtocol": 1
22
+ }
@@ -0,0 +1,122 @@
1
+ # Retained stores: opt-in same-host adoption
2
+
3
+ Prepared in UNS Kit 3.0.45; npm publication and coordinated Controller/Runtime
4
+ releases are separate steps. Existing applications do not change behavior.
5
+ This is a filesystem capability, separate from the small JSON
6
+ handover-state contract and MQTT output persistence. It does not change the
7
+ default handover protocol, enable disk queues, or transfer data between hosts.
8
+
9
+ ## Ownership
10
+
11
+ The SDK owns the versioned manifest, binding, safe path validation and resumable
12
+ same-filesystem rename helpers. Controller owns authenticated review, launch
13
+ checks, reservations, durable operation state and managed lifecycle fences.
14
+ The application owns data schema compatibility, its exclusive writer/lease,
15
+ maintenance semantics, replay and database acknowledgements. Runtime/tools own
16
+ durable mounts and backup/restore coverage. No Controller package-name branches
17
+ or execution of application code are required.
18
+
19
+ Publish `retained-store.manifest.json` at the installed package root. Give each
20
+ opaque resource a stable ID, a relative legacy path, kind and required flag.
21
+ Declare a format only when both versions can safely open the same data. An
22
+ explicit legacy version list permits sources without a manifest; it is a
23
+ compatibility promise by the application, not an automatic schema conversion.
24
+ Keep keys, tokens and startup configuration outside resource declarations.
25
+
26
+ The two example manifests in `examples/retained-store/` deliberately describe
27
+ different applications/formats. Whole data directories include SQLite WAL/SHM
28
+ sidecars without the Controller reading SQLite or interpreting payloads.
29
+ The npm core package includes this guide at `dist/runtime/retained-store-guide.md`
30
+ and the same manifests at `dist/runtime/retained-store-examples/`.
31
+
32
+ ```ts
33
+ import {
34
+ readRetainedStoreManifest,
35
+ resolveRetainedStoreResources,
36
+ openRetainedStoreLease,
37
+ } from '@uns-kit/core/runtime/retained-store.js';
38
+
39
+ const resolved = resolveRetainedStoreResources(instanceDirectory,
40
+ readRetainedStoreManifest(packageDirectory),
41
+ { rttNode: packageName, version: packageVersion, instanceId });
42
+ const lease = resolved.binding ? openRetainedStoreLease(resolved.binding) : undefined;
43
+ // Now open resolved payload resources and acquire application database leases.
44
+ // Keep the shared lease until writers close; call lease?.close() on shutdown.
45
+ // An attached store enters application maintenance before replay.
46
+ const dataDirectory = resolved.resources.queue;
47
+ ```
48
+
49
+ A binding is private and names an opaque store UUID, generation, operation,
50
+ owner, reviewed configuration digest and stable directory. The shared store
51
+ metadata must match it exactly. A stale owner or fenced instance fails closed.
52
+ The helper does not acquire the application's database lock or authorize an
53
+ operator. Do not bypass either check with an application-specific fallback.
54
+
55
+ ## Host procedure
56
+
57
+ 1. Resolve installed package/instance IDs server-side. Require matching portable
58
+ configuration, compatible declarations, exact compiled artifact fingerprints,
59
+ an unoccupied target and one filesystem. Preview never creates storage.
60
+ 2. Persist the reviewed selection/digest and, before moving, commit operation
61
+ intent. Require the reviewed source launch's clean physical exit according to
62
+ the supervisor; target must also be stopped. Reserve both managed instances.
63
+ 3. Use `prepareRetainedStoreMove` and `applyRetainedStoreMove(plan, 'adopt')`.
64
+ Persist the complete plan before applying it. Moves are atomic per resource,
65
+ fsynced, inode/device pinned and resumable; there is no copy or overwrite
66
+ fallback. Several resources do not form one filesystem transaction.
67
+ 4. Commit the binding/current owner and durable outcome before releasing the
68
+ receiving instance fence. Start only the new owner, initially in maintenance.
69
+ 5. After stopping that owner, capture `prepareRetainedStoreReturn(plan)` and
70
+ persist return intent. Return the *current* resources, including new optional
71
+ or atomically replaced control files. Never restore an old queue snapshot.
72
+
73
+ Reconcile a timeout by reading/repeating the same operation UUID. A different
74
+ request is not a substitute for recovery. Keep the old-side fence after success.
75
+ A direct manual launch of an older binary outside Controller can ignore a fence;
76
+ this protocol protects managed lifecycle and participating SDK consumers.
77
+
78
+ ## Deliberate limits
79
+
80
+ POSIX same-user, same-filesystem storage only. No cross-host transport, resource
81
+ merging, schema conversion, automatic deletion, retention finalization, or
82
+ exactly-once destination guarantee. Unknown write acknowledgements keep their
83
+ existing application semantics. Launches, configurations and artifacts changed
84
+ after review are rejected. An absent target requires the existing installation
85
+ workflow first.
86
+
87
+ Before production release, Runtime and backup tools must explicitly cover the
88
+ stable root, including a queue-excluding backup policy and full restore proof.
89
+ Moving a directory outside the previous archive layout is not backup coverage.
90
+ Consumers must be checked again against published, versioned registry packages;
91
+ a local file tarball is development evidence only.
92
+
93
+ ## Runtime storage and backup extension
94
+
95
+ A bound application must now explicitly declare `storageProtocol: 1` in its
96
+ manifest and acquire `openRetainedStoreLease(binding)` before opening payloads.
97
+ Keep that handle until final writer shutdown and close it then; the SDK also pins
98
+ live leases process-wide, bounded to32. This is a participation contract, not an
99
+ inference from an installed SDK version. Older unbound applications keep their
100
+ legacy behavior. Bound sources/targets lacking the declaration are rejected by
101
+ managed startup/adoption instead of being guessed safe for offline capture.
102
+ The storage program has been tested on Node 24 with POSIX local filesystems;
103
+ application payload formats remain opaque to it.
104
+
105
+ The trusted Runtime root is `UNS_RETAINED_STORE_ROOT`; managed adoption requires
106
+ it, and an existing binding must match it exactly. No automatic rebasing of old
107
+ absolute bindings is performed. `store-resources.json` records the declaration,
108
+ including optional per-resource `backup: "payload" | "metadata"` (default payload).
109
+ An incomplete store operation or root restore blocks startup. A returned legacy
110
+ layout leaves a validated empty-store retirement marker, rather than making old
111
+ bindings appear live.
112
+
113
+ The shared `retained-store-storage.mjs` program supplies leases, offline capture
114
+ and retryable restoration without importing application modules. Runtime tools
115
+ vendor its exact bytes/limits with provenance. Capture requires all bound owners
116
+ stopped; output/input journals retain their existing distinct online protocols.
117
+ The full RTT backup includes the extra capsule inside its existing signed,
118
+ age-encrypted payload. Queue-excluding capture reports excluded payloads and
119
+ cannot be used as a complete queue restore. Restore retains store/owner/generation
120
+ identity at the same logical root on another offline volume, and leaves an applying
121
+ fence until complete. Known private partial staging files may be re-created only
122
+ from the verified snapshot; differing published work is never overwritten.
@@ -0,0 +1,9 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "maximumStores": 32,
4
+ "maximumEntries": 100000,
5
+ "maximumBytes": 68719476736,
6
+ "maximumManifestBytes": 33554432,
7
+ "maximumFileBytes": 34359738368,
8
+ "maximumDepth": 32
9
+ }
@@ -0,0 +1,17 @@
1
+ export function rootLease(root: string, exclusive?: boolean, restoring?: boolean): () => void;
2
+ export function maintenanceLease(directory: string): () => void;
3
+ export function runtimeLease(binding: unknown): { close: () => void };
4
+ export function captureRetained(
5
+ root: string,
6
+ destination: string,
7
+ mode: string,
8
+ limits: unknown,
9
+ ): { state: string; stores: number; files: number; payloadBytes: number };
10
+ export function restoreRetained(
11
+ source: string,
12
+ root: string,
13
+ backupDigest: string,
14
+ limits: unknown,
15
+ afterPublish?: (id: string) => void,
16
+ ): { state: string; stores: number };
17
+ export function available(root: string): void;