@pylonsync/sdk 0.3.346 → 0.3.348
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/index.d.ts +46 -1
- package/package.json +1 -1
- package/src/index.ts +57 -1
package/dist/index.d.ts
CHANGED
|
@@ -282,8 +282,44 @@ export interface EntityDefinition {
|
|
|
282
282
|
* `db.useSearch` + by-id fetch instead of holding the whole table locally:
|
|
283
283
|
* `sync: false` keeps it out of the replica entirely. Direct reads
|
|
284
284
|
* (`/api/entities/X`, `/api/search/X`) and policies are unchanged.
|
|
285
|
+
*
|
|
286
|
+
* Pass an object to keep the entity live but bound WHICH rows replicate —
|
|
287
|
+
* see {@link SyncScope}. That's the middle setting between "every row you
|
|
288
|
+
* can read" and "nothing".
|
|
285
289
|
*/
|
|
286
|
-
sync?: boolean;
|
|
290
|
+
sync?: boolean | SyncScope;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Bounded replication for an entity that should stay live but shouldn't ship
|
|
294
|
+
* its whole history to every client.
|
|
295
|
+
*
|
|
296
|
+
* ```ts
|
|
297
|
+
* entity("Message", { … }, {
|
|
298
|
+
* sync: { where: "data.roomId == auth.tenantId", limit: 5_000 },
|
|
299
|
+
* })
|
|
300
|
+
* ```
|
|
301
|
+
*
|
|
302
|
+
* `where` is the SAME expression language as policies (including
|
|
303
|
+
* `exists(...)`), evaluated per row per caller. It is applied ON TOP of the
|
|
304
|
+
* read policy, never instead of it — a scope can only remove rows from a
|
|
305
|
+
* replica, so getting one wrong is a missing-data bug, never a leak.
|
|
306
|
+
*
|
|
307
|
+
* Applies to REPLICATION only: the snapshot, the sync engine's bootstrap, and
|
|
308
|
+
* the change-log delta. Direct reads (`/api/entities/X`, `/api/search/X`) are
|
|
309
|
+
* unchanged, exactly as with `sync: false`.
|
|
310
|
+
*
|
|
311
|
+
* A row that leaves scope is pushed to clients as a DELETE, so replicas evict
|
|
312
|
+
* it rather than holding a copy that never updates again.
|
|
313
|
+
*/
|
|
314
|
+
export interface SyncScope {
|
|
315
|
+
/** Policy-DSL predicate. Omit to bound by `limit` alone. */
|
|
316
|
+
where?: string;
|
|
317
|
+
/**
|
|
318
|
+
* Hard ceiling on rows replicated per client for this entity. Belt to
|
|
319
|
+
* `where`'s braces — a predicate that turns out not to bound growth still
|
|
320
|
+
* can't flood a replica. Survives snapshot pagination.
|
|
321
|
+
*/
|
|
322
|
+
limit?: number;
|
|
287
323
|
}
|
|
288
324
|
export declare function entity(name: string, fields: Record<string, FieldBuilder>, options?: {
|
|
289
325
|
indexes?: IndexDefinition[];
|
|
@@ -465,6 +501,15 @@ export interface ManifestEntity {
|
|
|
465
501
|
/** Client replication; omitted when true (the default). `false` keeps the
|
|
466
502
|
* entity out of the client replica (snapshot + delta) — server-queried only. */
|
|
467
503
|
sync?: boolean;
|
|
504
|
+
/**
|
|
505
|
+
* Replication scope, flattened out of {@link SyncScope}. Sibling keys
|
|
506
|
+
* rather than a nested object so `sync` keeps its boolean shape on the
|
|
507
|
+
* wire — an older binary reading this manifest still sees `sync: true`
|
|
508
|
+
* and replicates everything, which is the right way for a version skew
|
|
509
|
+
* to degrade.
|
|
510
|
+
*/
|
|
511
|
+
sync_scope?: string;
|
|
512
|
+
sync_limit?: number;
|
|
468
513
|
}
|
|
469
514
|
export interface ManifestRoute {
|
|
470
515
|
path: string;
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -367,8 +367,45 @@ export interface EntityDefinition {
|
|
|
367
367
|
* `db.useSearch` + by-id fetch instead of holding the whole table locally:
|
|
368
368
|
* `sync: false` keeps it out of the replica entirely. Direct reads
|
|
369
369
|
* (`/api/entities/X`, `/api/search/X`) and policies are unchanged.
|
|
370
|
+
*
|
|
371
|
+
* Pass an object to keep the entity live but bound WHICH rows replicate —
|
|
372
|
+
* see {@link SyncScope}. That's the middle setting between "every row you
|
|
373
|
+
* can read" and "nothing".
|
|
370
374
|
*/
|
|
371
|
-
sync?: boolean;
|
|
375
|
+
sync?: boolean | SyncScope;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Bounded replication for an entity that should stay live but shouldn't ship
|
|
380
|
+
* its whole history to every client.
|
|
381
|
+
*
|
|
382
|
+
* ```ts
|
|
383
|
+
* entity("Message", { … }, {
|
|
384
|
+
* sync: { where: "data.roomId == auth.tenantId", limit: 5_000 },
|
|
385
|
+
* })
|
|
386
|
+
* ```
|
|
387
|
+
*
|
|
388
|
+
* `where` is the SAME expression language as policies (including
|
|
389
|
+
* `exists(...)`), evaluated per row per caller. It is applied ON TOP of the
|
|
390
|
+
* read policy, never instead of it — a scope can only remove rows from a
|
|
391
|
+
* replica, so getting one wrong is a missing-data bug, never a leak.
|
|
392
|
+
*
|
|
393
|
+
* Applies to REPLICATION only: the snapshot, the sync engine's bootstrap, and
|
|
394
|
+
* the change-log delta. Direct reads (`/api/entities/X`, `/api/search/X`) are
|
|
395
|
+
* unchanged, exactly as with `sync: false`.
|
|
396
|
+
*
|
|
397
|
+
* A row that leaves scope is pushed to clients as a DELETE, so replicas evict
|
|
398
|
+
* it rather than holding a copy that never updates again.
|
|
399
|
+
*/
|
|
400
|
+
export interface SyncScope {
|
|
401
|
+
/** Policy-DSL predicate. Omit to bound by `limit` alone. */
|
|
402
|
+
where?: string;
|
|
403
|
+
/**
|
|
404
|
+
* Hard ceiling on rows replicated per client for this entity. Belt to
|
|
405
|
+
* `where`'s braces — a predicate that turns out not to bound growth still
|
|
406
|
+
* can't flood a replica. Survives snapshot pagination.
|
|
407
|
+
*/
|
|
408
|
+
limit?: number;
|
|
372
409
|
}
|
|
373
410
|
|
|
374
411
|
export function entity(
|
|
@@ -627,6 +664,15 @@ export interface ManifestEntity {
|
|
|
627
664
|
/** Client replication; omitted when true (the default). `false` keeps the
|
|
628
665
|
* entity out of the client replica (snapshot + delta) — server-queried only. */
|
|
629
666
|
sync?: boolean;
|
|
667
|
+
/**
|
|
668
|
+
* Replication scope, flattened out of {@link SyncScope}. Sibling keys
|
|
669
|
+
* rather than a nested object so `sync` keeps its boolean shape on the
|
|
670
|
+
* wire — an older binary reading this manifest still sees `sync: true`
|
|
671
|
+
* and replicates everything, which is the right way for a version skew
|
|
672
|
+
* to degrade.
|
|
673
|
+
*/
|
|
674
|
+
sync_scope?: string;
|
|
675
|
+
sync_limit?: number;
|
|
630
676
|
}
|
|
631
677
|
|
|
632
678
|
export interface ManifestRoute {
|
|
@@ -916,6 +962,16 @@ export function entitiesToManifest(
|
|
|
916
962
|
// Emit only when opted OUT — the runtime defaults sync to true.
|
|
917
963
|
if (e.sync === false) {
|
|
918
964
|
result.sync = false;
|
|
965
|
+
} else if (e.sync && typeof e.sync === "object") {
|
|
966
|
+
// A SCOPE. Flattened into sibling keys rather than nested under `sync`
|
|
967
|
+
// so the field keeps its boolean shape on the wire: an older binary
|
|
968
|
+
// reading this manifest still sees `sync: true` and replicates
|
|
969
|
+
// everything — more data than intended, which is the right way for
|
|
970
|
+
// this to degrade. Nesting would make `sync` fail to deserialize as a
|
|
971
|
+
// bool and take the whole app down on a version skew.
|
|
972
|
+
const scope = e.sync;
|
|
973
|
+
if (scope.where !== undefined) result.sync_scope = scope.where;
|
|
974
|
+
if (scope.limit !== undefined) result.sync_limit = scope.limit;
|
|
919
975
|
}
|
|
920
976
|
return result;
|
|
921
977
|
});
|