@milaboratories/pl-client 3.16.1 → 3.17.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@milaboratories/pl-client",
3
- "version": "3.16.1",
3
+ "version": "3.17.0",
4
4
  "description": "New TS/JS client for Platform API",
5
5
  "files": [
6
6
  "./dist/**/*",
@@ -30,9 +30,9 @@
30
30
  "undici": "~7.16.0",
31
31
  "utility-types": "^3.11.0",
32
32
  "yaml": "^2.8.0",
33
- "@milaboratories/pl-model-common": "1.48.0",
34
- "@milaboratories/ts-helpers": "1.8.6",
35
- "@milaboratories/pl-http": "1.2.4"
33
+ "@milaboratories/pl-http": "1.2.4",
34
+ "@milaboratories/pl-model-common": "1.49.0",
35
+ "@milaboratories/ts-helpers": "1.8.6"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@protobuf-ts/plugin": "2.11.1",
@@ -42,8 +42,8 @@
42
42
  "typescript": "7.0.2",
43
43
  "vitest": "^4.1.3",
44
44
  "@milaboratories/build-configs": "2.0.1",
45
- "@milaboratories/ts-builder": "1.7.2",
46
- "@milaboratories/ts-configs": "1.4.0"
45
+ "@milaboratories/ts-configs": "1.4.0",
46
+ "@milaboratories/ts-builder": "1.7.2"
47
47
  },
48
48
  "engines": {
49
49
  "node": ">=22.19.0"
@@ -17,6 +17,10 @@
17
17
  export type BackendCapability =
18
18
  | "auth:v2"
19
19
  | "treeFilter:v2"
20
+ // Delta tree reads: Tree, ResourceAPI.Get and ResourceKVAPI.List accept a
21
+ // changed_since_token and answer with only what changed since it. Narrower in name
22
+ // than in reach, since it gates all three.
23
+ | "treeChangedSince:v1"
20
24
  | "wasm:v1"
21
25
  // Advertised only where the deployment actually has scratch storage, not merely where the
22
26
  // build understands a 'scratchFreeSpace' request: a client that sees this stops arranging
@@ -158,6 +158,9 @@ test("check timeout error type (active)", async () => {
158
158
  resourceId: id,
159
159
  loadFields: false,
160
160
  resourceSignature,
161
+ showSoftDeletes: false,
162
+ // Required bytes field: undefined fails serialization and kills the tx stream.
163
+ changedSinceToken: new Uint8Array(0),
161
164
  },
162
165
  },
163
166
  false,
@@ -232,6 +235,9 @@ test("check is abort error (active)", async () => {
232
235
  resourceId: id,
233
236
  loadFields: false,
234
237
  resourceSignature,
238
+ showSoftDeletes: false,
239
+ // Required bytes field: undefined fails serialization and kills the tx stream.
240
+ changedSinceToken: new Uint8Array(0),
235
241
  },
236
242
  },
237
243
  false,
@@ -90,10 +90,13 @@ export type ResourceTreeItem = ResourceData & { kv: KeyValue[]; traverseWasStopp
90
90
 
91
91
  /** A single frame from the resourceTree() stream.
92
92
  *
93
- * When the server advertises `treeStopMarker:v1`, a stop-matched node is emitted
94
- * as a lightweight marker instead of a full resource payload. Callers must
95
- * narrow on `frameKind` before accessing type-specific fields.
93
+ * A node the request's `traverseStopRules` matched is emitted as a lightweight marker
94
+ * instead of a full resource payload. Callers must narrow on `frameKind` before accessing
95
+ * type-specific fields.
96
96
  * Note: `frameKind` is distinct from `ResourceData.kind` (which is the resource kind).
97
+ *
98
+ * Under `changedSinceToken` there are no markers: stop rules do not apply, and an unchanged
99
+ * resource produces no frame at all.
97
100
  */
98
101
  export type ResourceTreeFrame =
99
102
  | (ResourceTreeItem & { frameKind: "resource" })
@@ -243,6 +246,7 @@ async function notFoundToUndefined<T>(cb: () => Promise<T>): Promise<T | undefin
243
246
  * This class encapsulates finalization stage and provides ready-to-communication transaction object.
244
247
  * */
245
248
  export class PlTransaction {
249
+ private readonly txOpen: Promise<{ id: bigint; sinceToken?: Uint8Array }>;
246
250
  private readonly globalTxId: Promise<bigint>;
247
251
  private readonly localTxId: number = PlTransaction.nextLocalTxId();
248
252
 
@@ -279,7 +283,7 @@ export class PlTransaction {
279
283
  private readonly enableFormattedErrors: boolean = false,
280
284
  ) {
281
285
  // initiating transaction
282
- this.globalTxId = this.sendSingleAndParse(
286
+ this.txOpen = this.sendSingleAndParse(
283
287
  {
284
288
  oneofKind: "txOpen",
285
289
  txOpen: {
@@ -290,8 +294,15 @@ export class PlTransaction {
290
294
  : TxAPI_Open_Request_WritableTx.NOT_WRITABLE,
291
295
  },
292
296
  },
293
- (r) => notEmpty(r.txOpen.tx?.id),
297
+ (r) => ({
298
+ id: notEmpty(r.txOpen.tx?.id),
299
+ // Empty on a server without treeChangedSince:v1, and on a writable transaction,
300
+ // which is served none: its reads see this transaction's own uncommitted writes,
301
+ // so a token earned here could pin state that never commits.
302
+ sinceToken: r.txOpen.nextSinceToken.length > 0 ? r.txOpen.nextSinceToken : undefined,
303
+ }),
294
304
  );
305
+ this.globalTxId = this.txOpen.then((r) => r.id);
295
306
 
296
307
  void this.track(this.globalTxId);
297
308
 
@@ -742,6 +753,9 @@ export class PlTransaction {
742
753
  ...this.toSignedResourceId(rId),
743
754
  loadFields: loadFields,
744
755
  showSoftDeletes: false,
756
+ // Always empty: an on-demand read asks for what the caller does not hold, so a
757
+ // token here could only suppress the one body it came for.
758
+ changedSinceToken: new Uint8Array(0),
745
759
  },
746
760
  },
747
761
  (r) => protoToResource(notEmpty(r.resourceGet.resource)),
@@ -1014,6 +1028,8 @@ export class PlTransaction {
1014
1028
  ...this.toSignedResourceId(rId),
1015
1029
  startFrom: "",
1016
1030
  limit: 0,
1031
+ // Always empty, as for the single resource read above.
1032
+ changedSinceToken: new Uint8Array(0),
1017
1033
  },
1018
1034
  },
1019
1035
  (r) => r.map((e) => e.resourceKeyValueList.record!),
@@ -1165,6 +1181,21 @@ export class PlTransaction {
1165
1181
  return await this.globalTxId;
1166
1182
  }
1167
1183
 
1184
+ /**
1185
+ * The change token this transaction was opened at, to hand back as
1186
+ * {@link resourceTree}'s `changedSinceToken` on a later poll. `undefined` when the server
1187
+ * does not advertise `treeChangedSince:v1`, and on a writable transaction, which is served
1188
+ * none.
1189
+ *
1190
+ * Store it only after a whole response has been applied - kept after a partial apply, the
1191
+ * dropped resources are never sent again - and discard it when the traversal shape changes,
1192
+ * which the token cannot express itself. Opaque: never parse one, and never compare across
1193
+ * instances.
1194
+ */
1195
+ public async getNextSinceToken(): Promise<Uint8Array | undefined> {
1196
+ return (await this.txOpen).sinceToken;
1197
+ }
1198
+
1168
1199
  /** Closes output event stream */
1169
1200
  public async complete() {
1170
1201
  if (this._completed) return;
@@ -1202,16 +1233,29 @@ export class PlTransaction {
1202
1233
  * with `traverseWasStopped = true` and their children are not visited.
1203
1234
  * This wire field accepts only one filter. Compose multiple rules via
1204
1235
  * `treeFilter.and(...)` / `treeFilter.or(...)`.
1236
+ * Deprecated, and ignored under `changedSinceToken`: a stop rule prunes on mutable state,
1237
+ * so on a delta walk it would hide a changed subtree behind a resource that merely
1238
+ * flipped a gate.
1205
1239
  * @param opts.includeKv - When true, each yielded item includes KV entries.
1206
1240
  * @param opts.maxDepth - Optional depth cap.
1241
+ * @param opts.changedSinceToken - A token from {@link getNextSinceToken}. Yields only
1242
+ * resources newer than it, and the walk ENDS at an unchanged one, so a change beneath one
1243
+ * is not reached. A response may reference resources it does not carry; read those back
1244
+ * with `unconditionalDepth`. An unusable token is answered with the full tree, not an error.
1245
+ * @param opts.unconditionalDepth - Emit every resource at or below this depth whatever its
1246
+ * change token says, the seed being depth 0. Ignored without `changedSinceToken`. Absent
1247
+ * differs from 0, which takes the seeds alone.
1207
1248
  */
1208
1249
  public resourceTree(
1209
1250
  seeds: (ResourceData | SignedResourceId)[],
1210
1251
  opts?: {
1211
1252
  fieldFilter?: ResourceAPI_Tree_Filter;
1253
+ /** @deprecated prune with `changedSinceToken` instead; ignored under one. */
1212
1254
  traverseStopRules?: ResourceAPI_Tree_Filter;
1213
1255
  includeKv?: boolean;
1214
1256
  maxDepth?: number;
1257
+ changedSinceToken?: Uint8Array;
1258
+ unconditionalDepth?: number;
1215
1259
  },
1216
1260
  ): AsyncIterable<ResourceTreeFrame> {
1217
1261
  if (seeds.length === 0) {
@@ -1238,8 +1282,9 @@ export class PlTransaction {
1238
1282
  includeKv: opts?.includeKv ?? false,
1239
1283
  maxDepth: opts?.maxDepth,
1240
1284
  showSoftDeletes: false,
1241
- // Empty token requests the full tree — this call has no continuation to resume.
1242
- changedSinceToken: new Uint8Array(0),
1285
+ // Empty requests the full tree.
1286
+ changedSinceToken: opts?.changedSinceToken ?? new Uint8Array(0),
1287
+ unconditionalDepth: opts?.unconditionalDepth,
1243
1288
  },
1244
1289
  });
1245
1290
 
@@ -1261,7 +1306,7 @@ export class PlTransaction {
1261
1306
  }
1262
1307
 
1263
1308
  if (!frame.resource) {
1264
- // Stop-marker frame: no resource body; server advertised treeStopMarker:v1.
1309
+ // A traverseStopRules match, sent without a body.
1265
1310
  const id = createSignedResourceId(
1266
1311
  frame.resourceId,
1267
1312
  toResourceSignature(frame.resourceSignature),
@@ -170,7 +170,8 @@ export const treeFilter = {
170
170
  * exactly the same nodes where the client BFS would stop, eliminating
171
171
  * unnecessary follow-up calls.
172
172
  *
173
- * Valid only inside `traverseStopRules`.
173
+ * Valid only inside `traverseStopRules`, which the backend ignores under a
174
+ * `changedSinceToken` - prune with the token instead where one is available.
174
175
  */
175
176
  readyOrDuplicateOrError(): Filter {
176
177
  return treeFilter.or(
@@ -1035,12 +1035,18 @@ export interface TxAPI_Open_Response {
1035
1035
  * Absent on a WRITABLE open, which is issued no token: the walk would see
1036
1036
  * that transaction's own uncommitted writes (see changed_since_token).
1037
1037
  *
1038
+ * Also accepted by ResourceAPI.Get and ResourceKVAPI.List, which apply the
1039
+ * same per-resource emission rule.
1040
+ *
1038
1041
  * Store it only after a whole tree response has been applied successfully. A
1039
1042
  * client that keeps it after a partial apply will never be sent the
1040
1043
  * resources it dropped. Clear it on tree rebuild, on a root-set change, and
1041
- * whenever the seed array is invalidated - the server no longer refuses a
1042
- * token presented against a differently shaped request, so that is the
1043
- * client's to enforce.
1044
+ * on any change to the traversal shape it was earned under - the token
1045
+ * carries no request shape, so that is the client's to enforce.
1046
+ *
1047
+ * Opaque, with one promise: two tokens from one server instance may be
1048
+ * compared for order, so a client can tell which of the two it holds is the
1049
+ * later. Never parse or construct one, and never compare across instances.
1044
1050
  *
1045
1051
  * @generated from protobuf field: bytes next_since_token = 2
1046
1052
  */
@@ -1527,12 +1533,36 @@ export interface ResourceAPI_Get_Request {
1527
1533
  * @generated from protobuf field: bool show_soft_deletes = 4
1528
1534
  */
1529
1535
  showSoftDeletes: boolean;
1536
+ /**
1537
+ * Same token and same emission rule as ResourceAPI.Tree's
1538
+ * changed_since_token: the response carries a resource only when its own
1539
+ * change token is newer than the point this one denotes, and otherwise
1540
+ * comes back with resource unset. Empty or absent (the default) always
1541
+ * returns the body.
1542
+ *
1543
+ * A client on a per-resource read path takes this so it answers the same
1544
+ * way the tree does; one that wants a body regardless simply omits it.
1545
+ * There is no unconditional_depth here - nothing traverses, so there is no
1546
+ * depth to bound.
1547
+ *
1548
+ * Ignored on a WRITABLE transaction, for the reason given on
1549
+ * ResourceAPI.Tree.Request.changed_since_token. Gated by the same
1550
+ * "treeChangedSince:v1" capability, whose name is narrower than what it
1551
+ * covers.
1552
+ *
1553
+ * @generated from protobuf field: bytes changed_since_token = 5
1554
+ */
1555
+ changedSinceToken: Uint8Array;
1530
1556
  }
1531
1557
  /**
1532
1558
  * @generated from protobuf message MiLaboratories.PL.API.ResourceAPI.Get.Response
1533
1559
  */
1534
1560
  export interface ResourceAPI_Get_Response {
1535
1561
  /**
1562
+ * Unset when the request carried a changed_since_token and this resource
1563
+ * has not changed since the point it denotes - see changed_since_token.
1564
+ * Populated on every other response.
1565
+ *
1536
1566
  * @generated from protobuf field: MiLaboratories.PL.API.Resource resource = 1
1537
1567
  */
1538
1568
  resource?: Resource;
@@ -1825,7 +1855,15 @@ export interface ResourceAPI_Tree_Request {
1825
1855
  * outputs_locked (bool). Old servers ignore this field and never
1826
1856
  * set traverse_was_stopped.
1827
1857
  *
1828
- * @generated from protobuf field: optional MiLaboratories.PL.API.ResourceAPI.Tree.Filter traverse_stop_rules = 7
1858
+ * Ignored on a request carrying a usable changed_since_token: a delta walk
1859
+ * is pruned by the change token alone, and traverse_was_stopped is never
1860
+ * set on it.
1861
+ *
1862
+ * Deprecated: prune with changed_since_token instead. Still honoured on a
1863
+ * request without a token; scheduled for removal once no client sends it.
1864
+ *
1865
+ * @deprecated
1866
+ * @generated from protobuf field: optional MiLaboratories.PL.API.ResourceAPI.Tree.Filter traverse_stop_rules = 7 [deprecated = true]
1829
1867
  */
1830
1868
  traverseStopRules?: ResourceAPI_Tree_Filter;
1831
1869
  /**
@@ -1847,23 +1885,58 @@ export interface ResourceAPI_Tree_Request {
1847
1885
  */
1848
1886
  showSoftDeletes: boolean;
1849
1887
  /**
1850
- * An opaque continuation token, taken verbatim from a previous response's
1851
- * next_since_token. The server returns bodies only for resources that
1852
- * changed after the point this token denotes; every other visited resource
1853
- * gets a body-less frame with resource_unchanged set. Empty or absent (the
1854
- * default) requests the full tree.
1888
+ * An opaque continuation token, taken verbatim from the next_since_token an
1889
+ * earlier transaction's Open response carried. The server returns bodies
1890
+ * only for resources that changed after the point this token denotes; every
1891
+ * other visited resource is passed over in silence, producing no frame at
1892
+ * all. Empty or absent (the default) requests the full tree.
1893
+ *
1894
+ * A response therefore contains exactly the resources whose own change
1895
+ * token is newer than the point this one denotes, and nothing else. Two
1896
+ * obligations follow, both of them the client's:
1855
1897
  *
1856
- * Clients must not parse, construct or compare this value: its encoding is
1857
- * server-private and may change without a wire version bump. Store the
1858
- * token only after applying a whole response successfully.
1898
+ * - Absence is not removal. A resource missing from a delta response is
1899
+ * either unchanged or gone, and the two are indistinguishable. Detect
1900
+ * removals another way, or poll without a token to reconcile.
1901
+ *
1902
+ * - A body may reference resources the response does not carry. A field
1903
+ * repointed at an older resource, or a subtree the traversal newly
1904
+ * reaches, keeps its old change token and is not sent - this poll or
1905
+ * any later one, since its token never moves again. The reference field
1906
+ * carries the target's resource ID and a valid signature for it, and
1907
+ * every resource the walk visited stays readable by ID inside the
1908
+ * walking transaction, frame or no frame. Read them with one Tree
1909
+ * request naming those IDs in seeds under an unconditional_depth, or
1910
+ * one at a time with ResourceAPI.Get.
1911
+ *
1912
+ * The traversal does not descend below an unchanged resource: the walk ends
1913
+ * on that branch, so a change beneath an unchanged resource arrives only
1914
+ * once something on the path down to it changes as well. Absence is not
1915
+ * removal for that reason too. A response in which nothing changed carries
1916
+ * no frames at all and arrives as an empty multi-message.
1917
+ *
1918
+ * traverse_stop_rules are ignored on a request carrying a usable token: the
1919
+ * token is the only pruning, and traverse_was_stopped is never set.
1920
+ *
1921
+ * Clients must not parse or construct this value: its encoding is
1922
+ * server-private and may change without a wire version bump. Two tokens
1923
+ * issued by one server instance may be compared for order, so a client can
1924
+ * tell which of the two it holds is the later; comparison across instances
1925
+ * is undefined. Store the token only after applying a whole response
1926
+ * successfully.
1859
1927
  *
1860
1928
  * A token the server cannot use is answered with the full tree, never with
1861
1929
  * an error, so it is always safe to send back whatever was last received.
1862
- * The server detects and ignores a token that does not fit the request it
1863
- * arrives on - the token is bound to the traversal-shaping parameters
1864
- * (resource_id, seeds, max_depth, include_kv, show_soft_deletes,
1865
- * field_filter, traverse_stop_rules), so changing any of them costs one
1866
- * full tree instead of silently reporting never-sent resources as held.
1930
+ *
1931
+ * The token carries no request shape and cannot: it is minted as a
1932
+ * transaction OPENS, before any tree request exists, and one transaction
1933
+ * may issue many reads with different depths, filters and seeds. So
1934
+ * discarding it when the traversal shape changes - max_depth, include_kv,
1935
+ * show_soft_deletes, field_filter, traverse_stop_rules, or the seed set -
1936
+ * is the client's obligation. Keeping it across such a change silently
1937
+ * skips resources the new shape reaches. Other seeds and an
1938
+ * unconditional_depth under the same token are NOT a shape change: what
1939
+ * they return is dated the same as the poll they came with.
1867
1940
  *
1868
1941
  * Ignored on a WRITABLE transaction, which also receives no
1869
1942
  * next_since_token: the walk sees that transaction's uncommitted writes, so
@@ -1877,6 +1950,23 @@ export interface ResourceAPI_Tree_Request {
1877
1950
  * @generated from protobuf field: bytes changed_since_token = 10
1878
1951
  */
1879
1952
  changedSinceToken: Uint8Array;
1953
+ /**
1954
+ * Depths at or below this one are emitted whatever changed_since_token
1955
+ * says, the seed being depth 0. Explicitly optional: absent means no
1956
+ * unconditional depth, which differs from 0. Ignored without
1957
+ * changed_since_token, which already sends everything.
1958
+ *
1959
+ * This is how a client reads what a delta response referenced but did not
1960
+ * carry. One Tree request naming the unknown IDs in seeds, under the same
1961
+ * token, returns them here while everything the client already holds below
1962
+ * the frontier stays skipped. The depth is the lever: 0 takes the seeds
1963
+ * alone, 1 takes a level per round trip, a depth past the subtree takes it
1964
+ * whole. Without it such a request comes back empty, and empty is
1965
+ * indistinguishable from not-found.
1966
+ *
1967
+ * @generated from protobuf field: optional uint32 unconditional_depth = 11
1968
+ */
1969
+ unconditionalDepth?: number;
1880
1970
  }
1881
1971
  /**
1882
1972
  * A single entry point for multi-root tree traversal.
@@ -2072,9 +2162,9 @@ export interface ResourceAPI_Tree_KV {
2072
2162
  export interface ResourceAPI_Tree_Response {
2073
2163
  /**
2074
2164
  * Full resource payload. Absent on stop-marker frames (when the server
2075
- * advertises `treeStopMarker:v1` and traverse_was_stopped is true) and on
2076
- * unchanged frames (when resource_unchanged is true). Populated on every
2077
- * other frame.
2165
+ * advertises `treeStopMarker:v1` and traverse_was_stopped is true).
2166
+ * Populated on every other frame. A resource the client already holds
2167
+ * unchanged produces no frame at all - see changed_since_token.
2078
2168
  *
2079
2169
  * @generated from protobuf field: optional MiLaboratories.PL.API.Resource resource = 1
2080
2170
  */
@@ -2111,23 +2201,6 @@ export interface ResourceAPI_Tree_Response {
2111
2201
  * @generated from protobuf field: bytes resource_signature = 5
2112
2202
  */
2113
2203
  resourceSignature: Uint8Array;
2114
- /**
2115
- * True on a body-less frame emitted for a resource the client already holds:
2116
- * resource is unset, and resource_id and resource_signature carry the
2117
- * identity instead. The client keeps everything it holds for that resource,
2118
- * fields and kv alike, and the traversal still descends into it - an
2119
- * unchanged parent routinely has changed children.
2120
- *
2121
- * Orthogonal to traverse_was_stopped; a frame may set both.
2122
- *
2123
- * A resource may appear twice in one response: an unchanged frame, then a
2124
- * body frame later in the same response. The later frame supersedes the
2125
- * earlier one, so apply frames in arrival order and treat an unchanged
2126
- * frame for an unknown resource as benign rather than fatal.
2127
- *
2128
- * @generated from protobuf field: bool resource_unchanged = 6
2129
- */
2130
- resourceUnchanged: boolean;
2131
2204
  }
2132
2205
  /**
2133
2206
  * @generated from protobuf message MiLaboratories.PL.API.ResourceAPI.TreeSize
@@ -2985,6 +3058,25 @@ export interface ResourceKVAPI_List_Request {
2985
3058
  * @generated from protobuf field: uint32 limit = 3
2986
3059
  */
2987
3060
  limit: number;
3061
+ /**
3062
+ * Same token and same emission rule as ResourceAPI.Tree's
3063
+ * changed_since_token: the listing runs only when the resource's own change
3064
+ * token is newer than the point this one denotes, and otherwise comes back
3065
+ * with no records at all. Empty or absent (the default) always lists.
3066
+ *
3067
+ * No records therefore means the metadata is unchanged, empty, or gone,
3068
+ * indistinguishably - which costs nothing, because a client only sends the
3069
+ * token for a resource whose metadata it already holds. One that wants the
3070
+ * listing regardless omits it.
3071
+ *
3072
+ * Ignored on a WRITABLE transaction, for the reason given on
3073
+ * ResourceAPI.Tree.Request.changed_since_token. Gated by the same
3074
+ * "treeChangedSince:v1" capability, whose name is narrower than what it
3075
+ * covers.
3076
+ *
3077
+ * @generated from protobuf field: bytes changed_since_token = 5
3078
+ */
3079
+ changedSinceToken: Uint8Array;
2988
3080
  }
2989
3081
  /**
2990
3082
  * Multi-message
@@ -8547,7 +8639,8 @@ class ResourceAPI_Get_Request$Type extends MessageType<ResourceAPI_Get_Request>
8547
8639
  { no: 1, name: "resource_id", kind: "scalar", T: 4 /*ScalarType.UINT64*/, L: 0 /*LongType.BIGINT*/ },
8548
8640
  { no: 3, name: "resource_signature", kind: "scalar", T: 12 /*ScalarType.BYTES*/ },
8549
8641
  { no: 2, name: "load_fields", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
8550
- { no: 4, name: "show_soft_deletes", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }
8642
+ { no: 4, name: "show_soft_deletes", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
8643
+ { no: 5, name: "changed_since_token", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }
8551
8644
  ]);
8552
8645
  }
8553
8646
  create(value?: PartialMessage<ResourceAPI_Get_Request>): ResourceAPI_Get_Request {
@@ -8556,6 +8649,7 @@ class ResourceAPI_Get_Request$Type extends MessageType<ResourceAPI_Get_Request>
8556
8649
  message.resourceSignature = new Uint8Array(0);
8557
8650
  message.loadFields = false;
8558
8651
  message.showSoftDeletes = false;
8652
+ message.changedSinceToken = new Uint8Array(0);
8559
8653
  if (value !== undefined)
8560
8654
  reflectionMergePartial<ResourceAPI_Get_Request>(this, message, value);
8561
8655
  return message;
@@ -8577,6 +8671,9 @@ class ResourceAPI_Get_Request$Type extends MessageType<ResourceAPI_Get_Request>
8577
8671
  case /* bool show_soft_deletes */ 4:
8578
8672
  message.showSoftDeletes = reader.bool();
8579
8673
  break;
8674
+ case /* bytes changed_since_token */ 5:
8675
+ message.changedSinceToken = reader.bytes();
8676
+ break;
8580
8677
  default:
8581
8678
  let u = options.readUnknownField;
8582
8679
  if (u === "throw")
@@ -8601,6 +8698,9 @@ class ResourceAPI_Get_Request$Type extends MessageType<ResourceAPI_Get_Request>
8601
8698
  /* bool show_soft_deletes = 4; */
8602
8699
  if (message.showSoftDeletes !== false)
8603
8700
  writer.tag(4, WireType.Varint).bool(message.showSoftDeletes);
8701
+ /* bytes changed_since_token = 5; */
8702
+ if (message.changedSinceToken.length)
8703
+ writer.tag(5, WireType.LengthDelimited).bytes(message.changedSinceToken);
8604
8704
  let u = options.writeUnknownFields;
8605
8705
  if (u !== false)
8606
8706
  (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
@@ -9765,7 +9865,8 @@ class ResourceAPI_Tree_Request$Type extends MessageType<ResourceAPI_Tree_Request
9765
9865
  { no: 7, name: "traverse_stop_rules", kind: "message", T: () => ResourceAPI_Tree_Filter },
9766
9866
  { no: 8, name: "seeds", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => ResourceAPI_Tree_SeedResource },
9767
9867
  { no: 9, name: "show_soft_deletes", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
9768
- { no: 10, name: "changed_since_token", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }
9868
+ { no: 10, name: "changed_since_token", kind: "scalar", T: 12 /*ScalarType.BYTES*/ },
9869
+ { no: 11, name: "unconditional_depth", kind: "scalar", opt: true, T: 13 /*ScalarType.UINT32*/ }
9769
9870
  ]);
9770
9871
  }
9771
9872
  create(value?: PartialMessage<ResourceAPI_Tree_Request>): ResourceAPI_Tree_Request {
@@ -9800,7 +9901,7 @@ class ResourceAPI_Tree_Request$Type extends MessageType<ResourceAPI_Tree_Request
9800
9901
  case /* bool include_kv */ 6:
9801
9902
  message.includeKv = reader.bool();
9802
9903
  break;
9803
- case /* optional MiLaboratories.PL.API.ResourceAPI.Tree.Filter traverse_stop_rules */ 7:
9904
+ case /* optional MiLaboratories.PL.API.ResourceAPI.Tree.Filter traverse_stop_rules = 7 [deprecated = true] */ 7:
9804
9905
  message.traverseStopRules = ResourceAPI_Tree_Filter.internalBinaryRead(reader, reader.uint32(), options, message.traverseStopRules);
9805
9906
  break;
9806
9907
  case /* repeated MiLaboratories.PL.API.ResourceAPI.Tree.SeedResource seeds */ 8:
@@ -9812,6 +9913,9 @@ class ResourceAPI_Tree_Request$Type extends MessageType<ResourceAPI_Tree_Request
9812
9913
  case /* bytes changed_since_token */ 10:
9813
9914
  message.changedSinceToken = reader.bytes();
9814
9915
  break;
9916
+ case /* optional uint32 unconditional_depth */ 11:
9917
+ message.unconditionalDepth = reader.uint32();
9918
+ break;
9815
9919
  default:
9816
9920
  let u = options.readUnknownField;
9817
9921
  if (u === "throw")
@@ -9839,7 +9943,7 @@ class ResourceAPI_Tree_Request$Type extends MessageType<ResourceAPI_Tree_Request
9839
9943
  /* bool include_kv = 6; */
9840
9944
  if (message.includeKv !== false)
9841
9945
  writer.tag(6, WireType.Varint).bool(message.includeKv);
9842
- /* optional MiLaboratories.PL.API.ResourceAPI.Tree.Filter traverse_stop_rules = 7; */
9946
+ /* optional MiLaboratories.PL.API.ResourceAPI.Tree.Filter traverse_stop_rules = 7 [deprecated = true]; */
9843
9947
  if (message.traverseStopRules)
9844
9948
  ResourceAPI_Tree_Filter.internalBinaryWrite(message.traverseStopRules, writer.tag(7, WireType.LengthDelimited).fork(), options).join();
9845
9949
  /* repeated MiLaboratories.PL.API.ResourceAPI.Tree.SeedResource seeds = 8; */
@@ -9851,6 +9955,9 @@ class ResourceAPI_Tree_Request$Type extends MessageType<ResourceAPI_Tree_Request
9851
9955
  /* bytes changed_since_token = 10; */
9852
9956
  if (message.changedSinceToken.length)
9853
9957
  writer.tag(10, WireType.LengthDelimited).bytes(message.changedSinceToken);
9958
+ /* optional uint32 unconditional_depth = 11; */
9959
+ if (message.unconditionalDepth !== undefined)
9960
+ writer.tag(11, WireType.Varint).uint32(message.unconditionalDepth);
9854
9961
  let u = options.writeUnknownFields;
9855
9962
  if (u !== false)
9856
9963
  (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
@@ -10111,8 +10218,7 @@ class ResourceAPI_Tree_Response$Type extends MessageType<ResourceAPI_Tree_Respon
10111
10218
  { no: 2, name: "kv", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => ResourceAPI_Tree_KV },
10112
10219
  { no: 3, name: "traverse_was_stopped", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
10113
10220
  { no: 4, name: "resource_id", kind: "scalar", T: 4 /*ScalarType.UINT64*/, L: 0 /*LongType.BIGINT*/ },
10114
- { no: 5, name: "resource_signature", kind: "scalar", T: 12 /*ScalarType.BYTES*/ },
10115
- { no: 6, name: "resource_unchanged", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }
10221
+ { no: 5, name: "resource_signature", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }
10116
10222
  ]);
10117
10223
  }
10118
10224
  create(value?: PartialMessage<ResourceAPI_Tree_Response>): ResourceAPI_Tree_Response {
@@ -10121,7 +10227,6 @@ class ResourceAPI_Tree_Response$Type extends MessageType<ResourceAPI_Tree_Respon
10121
10227
  message.traverseWasStopped = false;
10122
10228
  message.resourceId = 0n;
10123
10229
  message.resourceSignature = new Uint8Array(0);
10124
- message.resourceUnchanged = false;
10125
10230
  if (value !== undefined)
10126
10231
  reflectionMergePartial<ResourceAPI_Tree_Response>(this, message, value);
10127
10232
  return message;
@@ -10146,9 +10251,6 @@ class ResourceAPI_Tree_Response$Type extends MessageType<ResourceAPI_Tree_Respon
10146
10251
  case /* bytes resource_signature */ 5:
10147
10252
  message.resourceSignature = reader.bytes();
10148
10253
  break;
10149
- case /* bool resource_unchanged */ 6:
10150
- message.resourceUnchanged = reader.bool();
10151
- break;
10152
10254
  default:
10153
10255
  let u = options.readUnknownField;
10154
10256
  if (u === "throw")
@@ -10176,9 +10278,6 @@ class ResourceAPI_Tree_Response$Type extends MessageType<ResourceAPI_Tree_Respon
10176
10278
  /* bytes resource_signature = 5; */
10177
10279
  if (message.resourceSignature.length)
10178
10280
  writer.tag(5, WireType.LengthDelimited).bytes(message.resourceSignature);
10179
- /* bool resource_unchanged = 6; */
10180
- if (message.resourceUnchanged !== false)
10181
- writer.tag(6, WireType.Varint).bool(message.resourceUnchanged);
10182
10281
  let u = options.writeUnknownFields;
10183
10282
  if (u !== false)
10184
10283
  (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
@@ -14585,7 +14684,8 @@ class ResourceKVAPI_List_Request$Type extends MessageType<ResourceKVAPI_List_Req
14585
14684
  { no: 1, name: "resource_id", kind: "scalar", T: 4 /*ScalarType.UINT64*/, L: 0 /*LongType.BIGINT*/ },
14586
14685
  { no: 4, name: "resource_signature", kind: "scalar", T: 12 /*ScalarType.BYTES*/ },
14587
14686
  { no: 2, name: "start_from", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
14588
- { no: 3, name: "limit", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }
14687
+ { no: 3, name: "limit", kind: "scalar", T: 13 /*ScalarType.UINT32*/ },
14688
+ { no: 5, name: "changed_since_token", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }
14589
14689
  ]);
14590
14690
  }
14591
14691
  create(value?: PartialMessage<ResourceKVAPI_List_Request>): ResourceKVAPI_List_Request {
@@ -14594,6 +14694,7 @@ class ResourceKVAPI_List_Request$Type extends MessageType<ResourceKVAPI_List_Req
14594
14694
  message.resourceSignature = new Uint8Array(0);
14595
14695
  message.startFrom = "";
14596
14696
  message.limit = 0;
14697
+ message.changedSinceToken = new Uint8Array(0);
14597
14698
  if (value !== undefined)
14598
14699
  reflectionMergePartial<ResourceKVAPI_List_Request>(this, message, value);
14599
14700
  return message;
@@ -14615,6 +14716,9 @@ class ResourceKVAPI_List_Request$Type extends MessageType<ResourceKVAPI_List_Req
14615
14716
  case /* uint32 limit */ 3:
14616
14717
  message.limit = reader.uint32();
14617
14718
  break;
14719
+ case /* bytes changed_since_token */ 5:
14720
+ message.changedSinceToken = reader.bytes();
14721
+ break;
14618
14722
  default:
14619
14723
  let u = options.readUnknownField;
14620
14724
  if (u === "throw")
@@ -14639,6 +14743,9 @@ class ResourceKVAPI_List_Request$Type extends MessageType<ResourceKVAPI_List_Req
14639
14743
  /* bytes resource_signature = 4; */
14640
14744
  if (message.resourceSignature.length)
14641
14745
  writer.tag(4, WireType.LengthDelimited).bytes(message.resourceSignature);
14746
+ /* bytes changed_since_token = 5; */
14747
+ if (message.changedSinceToken.length)
14748
+ writer.tag(5, WireType.LengthDelimited).bytes(message.changedSinceToken);
14642
14749
  let u = options.writeUnknownFields;
14643
14750
  if (u !== false)
14644
14751
  (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);