@haverstack/core 0.44.0 → 0.45.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 +1 -1
- package/dist/adapter/blobs.d.ts +18 -0
- package/dist/adapter/blobs.d.ts.map +1 -0
- package/dist/adapter/blobs.js +27 -0
- package/dist/adapter/blobs.js.map +1 -0
- package/dist/adapter/combine.d.ts.map +1 -1
- package/dist/adapter/combine.js +13 -5
- package/dist/adapter/combine.js.map +1 -1
- package/dist/adapter/copy.d.ts +7 -3
- package/dist/adapter/copy.d.ts.map +1 -1
- package/dist/adapter/copy.js +41 -15
- package/dist/adapter/copy.js.map +1 -1
- package/dist/adapter/head.d.ts +38 -0
- package/dist/adapter/head.d.ts.map +1 -0
- package/dist/adapter/head.js +85 -0
- package/dist/adapter/head.js.map +1 -0
- package/dist/adapter/index.d.ts +5 -1
- package/dist/adapter/index.d.ts.map +1 -1
- package/dist/adapter/index.js +3 -0
- package/dist/adapter/index.js.map +1 -1
- package/dist/stack/stack.d.ts +3 -3
- package/dist/stack/stack.d.ts.map +1 -1
- package/dist/stack/stack.js +13 -6
- package/dist/stack/stack.js.map +1 -1
- package/dist/testing.d.ts +6 -2
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +14 -11
- package/dist/testing.js.map +1 -1
- package/dist/types/adapter.d.ts +48 -5
- package/dist/types/adapter.d.ts.map +1 -1
- package/dist/validate.d.ts +2 -0
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +2 -2
- package/dist/validate.js.map +1 -1
- package/dist/wire/index.d.ts +1 -1
- package/dist/wire/index.d.ts.map +1 -1
- package/dist/wire/index.js +1 -1
- package/dist/wire/index.js.map +1 -1
- package/dist/wire/request.d.ts +8 -1
- package/dist/wire/request.d.ts.map +1 -1
- package/dist/wire/request.js +20 -0
- package/dist/wire/request.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -203,7 +203,7 @@ export const manifest: AppManifest = {
|
|
|
203
203
|
|
|
204
204
|
**When the owner runs the app**, it opens with `Stack.open(adapter, { migrations })`, calls `install(stack)`, then `new Library(stack)`. A server hands each requester `new Library(stack.asActor(session))`.
|
|
205
205
|
|
|
206
|
-
**When the app runs elsewhere** — holding its own key and reaching the stack through `APIAdapter` — it can't define types, so it asks: `adapter.requestInstall(manifest)
|
|
206
|
+
**When the app runs elsewhere** — holding its own key and reaching the stack through `APIAdapter` — it can't define types, so it asks: `adapter.requestInstall(manifest)`, present when the server advertises install requests, resolves to `pending` until the owner approves. The owner reviews `stack.planInstall(manifest, { did })` and applies it with `stack.installApp(manifest, { did, fingerprint: plan.fingerprint })`, which defines the types, registers the app's key and grants it the requests. The app still opens with its `migrations`, then builds `new Library(stack)` over its own connection. See [App installs](https://github.com/haverstack/core/blob/main/docs/spec/apps.md).
|
|
207
207
|
|
|
208
208
|
**Name content with an interface**, as above. `ContentOf` flattens its result, so a `type` alias shows the expanded object in editor hovers, while an interface keeps its name. typescript-eslint's recommended `no-empty-object-type` rule rejects an empty interface; its `allowInterfaces: 'with-single-extends'` option admits this one.
|
|
209
209
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Blob listing windows and file ids
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* `listBlobs()` reads in `fileId` order and pages forward from
|
|
5
|
+
* `afterFileId`, on every adapter. An adapter whose storage hands back an
|
|
6
|
+
* unordered set of names windows it here, so the order and the cursor mean
|
|
7
|
+
* the same thing whatever stores the bytes. See docs/spec/data-model.md
|
|
8
|
+
* § List order.
|
|
9
|
+
*/
|
|
10
|
+
import type { BlobsQuery, FileId } from '../types/index.js';
|
|
11
|
+
/** The `fileId`s a `listBlobs(query)` answers with, out of every one stored. */
|
|
12
|
+
export declare function blobWindow(fileIds: Iterable<FileId>, query?: BlobsQuery): FileId[];
|
|
13
|
+
/**
|
|
14
|
+
* Refuses a name no blob could have, before a store or a page is asked for
|
|
15
|
+
* it. `label` names where it arrived, such as a request's `afterFileId`.
|
|
16
|
+
*/
|
|
17
|
+
export declare function assertFileId(fileId: string, label?: string): void;
|
|
18
|
+
//# sourceMappingURL=blobs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blobs.d.ts","sourceRoot":"","sources":["../../src/adapter/blobs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAG5D,gFAAgF;AAChF,wBAAgB,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,GAAE,UAAe,GAAG,MAAM,EAAE,CAItF;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,SAAW,GAAG,IAAI,CAInE"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Blob listing windows and file ids
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* `listBlobs()` reads in `fileId` order and pages forward from
|
|
5
|
+
* `afterFileId`, on every adapter. An adapter whose storage hands back an
|
|
6
|
+
* unordered set of names windows it here, so the order and the cursor mean
|
|
7
|
+
* the same thing whatever stores the bytes. See docs/spec/data-model.md
|
|
8
|
+
* § List order.
|
|
9
|
+
*/
|
|
10
|
+
import { StackBadRequestError } from '../errors.js';
|
|
11
|
+
import { FILE_ID_RE } from '../validate.js';
|
|
12
|
+
/** The `fileId`s a `listBlobs(query)` answers with, out of every one stored. */
|
|
13
|
+
export function blobWindow(fileIds, query = {}) {
|
|
14
|
+
const { afterFileId, limit } = query;
|
|
15
|
+
const after = [...fileIds].filter((id) => afterFileId === undefined || id > afterFileId).sort();
|
|
16
|
+
return limit === undefined ? after : after.slice(0, limit);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Refuses a name no blob could have, before a store or a page is asked for
|
|
20
|
+
* it. `label` names where it arrived, such as a request's `afterFileId`.
|
|
21
|
+
*/
|
|
22
|
+
export function assertFileId(fileId, label = 'fileId') {
|
|
23
|
+
if (!FILE_ID_RE.test(fileId)) {
|
|
24
|
+
throw new StackBadRequestError(`Invalid ${label}: expected 64-character lowercase hex string`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=blobs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blobs.js","sourceRoot":"","sources":["../../src/adapter/blobs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,gFAAgF;AAChF,MAAM,UAAU,UAAU,CAAC,OAAyB,EAAE,QAAoB,EAAE;IAC1E,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;IACrC,MAAM,KAAK,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,GAAG,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC;IAChG,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AAC7D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,KAAK,GAAG,QAAQ;IAC3D,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,oBAAoB,CAAC,WAAW,KAAK,8CAA8C,CAAC,CAAC;IACjG,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"combine.d.ts","sourceRoot":"","sources":["../../src/adapter/combine.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAKV,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EAGjB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"combine.d.ts","sourceRoot":"","sources":["../../src/adapter/combine.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAKV,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EAGjB,MAAM,mBAAmB,CAAC;AAG3B;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,IAAI,EAAE,gBAAgB,CAAC;CACxB,GAAG,YAAY,CAqFf"}
|
package/dist/adapter/combine.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* deployment can keep records and bytes in different backends without
|
|
6
6
|
* either adapter knowing about the other.
|
|
7
7
|
*/
|
|
8
|
+
import { combinedHead } from './head.js';
|
|
8
9
|
/**
|
|
9
10
|
* Compose a StackRecordAdapter and a StackBlobAdapter into a single StackAdapter.
|
|
10
11
|
* Use this when you want different backends for records and blobs, e.g.:
|
|
@@ -20,6 +21,10 @@ export function combineAdapters(parts) {
|
|
|
20
21
|
get ownerEntityId() {
|
|
21
22
|
return parts.record.ownerEntityId;
|
|
22
23
|
},
|
|
24
|
+
// The record half's, since writers names who writes the Records.
|
|
25
|
+
get writers() {
|
|
26
|
+
return parts.record.writers;
|
|
27
|
+
},
|
|
23
28
|
createRecord: (r, opts) => parts.record.createRecord(r, opts),
|
|
24
29
|
getRecord: (id) => parts.record.getRecord(id),
|
|
25
30
|
patchContent: (id, patch, opts) => parts.record.patchContent(id, patch, opts),
|
|
@@ -52,10 +57,8 @@ export function combineAdapters(parts) {
|
|
|
52
57
|
...(parts.record.queryReadable && {
|
|
53
58
|
queryReadable: (q, reach) => parts.record.queryReadable(q, reach),
|
|
54
59
|
}),
|
|
55
|
-
// Forwarded on the same terms
|
|
56
|
-
//
|
|
57
|
-
// leave a combined stack quietly emitting only its own writes while a
|
|
58
|
-
// remote record backend's feed went unread.
|
|
60
|
+
// Forwarded on the same terms: dropping it would leave a shared record
|
|
61
|
+
// backend's feed unread, and Stack would refuse to subscribe at all.
|
|
59
62
|
...(parts.record.subscribeChanges && {
|
|
60
63
|
subscribeChanges: (opts, handler) => parts.record.subscribeChanges(opts, handler),
|
|
61
64
|
}),
|
|
@@ -67,7 +70,12 @@ export function combineAdapters(parts) {
|
|
|
67
70
|
getBlob: (id) => parts.blob.getBlob(id),
|
|
68
71
|
deleteBlob: (id) => parts.blob.deleteBlob(id),
|
|
69
72
|
...(parts.blob.listBlobs && {
|
|
70
|
-
listBlobs: () => parts.blob.listBlobs(),
|
|
73
|
+
listBlobs: (query) => parts.blob.listBlobs(query),
|
|
74
|
+
}),
|
|
75
|
+
// One head for the whole store, so a write to either half moves it.
|
|
76
|
+
...(parts.record.head &&
|
|
77
|
+
parts.blob.head && {
|
|
78
|
+
head: async () => combinedHead(await parts.record.head(), await parts.blob.head()),
|
|
71
79
|
}),
|
|
72
80
|
async flush() {
|
|
73
81
|
await parts.record.flush?.();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"combine.js","sourceRoot":"","sources":["../../src/adapter/combine.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"combine.js","sourceRoot":"","sources":["../../src/adapter/combine.ts"],"names":[],"mappings":"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"}
|
package/dist/adapter/copy.d.ts
CHANGED
|
@@ -10,7 +10,11 @@
|
|
|
10
10
|
* between storage engines are all this one call, with a different source
|
|
11
11
|
* and a different kind of store to create. Full trust, like any direct
|
|
12
12
|
* adapter access: authorship and history land as recorded, which no write
|
|
13
|
-
* through Stack may do.
|
|
13
|
+
* through Stack may do.
|
|
14
|
+
*
|
|
15
|
+
* A copy reads one moment of its source: it reads the source's head before
|
|
16
|
+
* and after, and refuses the copy if the two differ. One rule for every
|
|
17
|
+
* source, whoever else writes to it. See docs/spec/portability.md.
|
|
14
18
|
*/
|
|
15
19
|
import type { StackAdapter, StoreSeed } from '../types/index.js';
|
|
16
20
|
/** Creates a new store from `seed`: `LocalAdapter.open({ path, seed })`, say. */
|
|
@@ -19,8 +23,8 @@ export type CreateStore = (seed: StoreSeed) => Promise<StackAdapter> | StackAdap
|
|
|
19
23
|
* Copy everything `from` holds into the store `create` makes from its
|
|
20
24
|
* `_config` record and that record's history, and return that store, open.
|
|
21
25
|
* Not atomic: a failure closes the store part-written, and the caller, whose
|
|
22
|
-
* store it is, removes it.
|
|
23
|
-
*
|
|
26
|
+
* store it is, removes it. A source written meanwhile is refused with
|
|
27
|
+
* StackConflictError, and the copy is run again into a new store.
|
|
24
28
|
* See docs/spec/portability.md § Copying a stack.
|
|
25
29
|
*/
|
|
26
30
|
export declare function copyStack(from: StackAdapter, create: CreateStore): Promise<StackAdapter>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copy.d.ts","sourceRoot":"","sources":["../../src/adapter/copy.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"copy.d.ts","sourceRoot":"","sources":["../../src/adapter/copy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,KAAK,EAIV,YAAY,EAEZ,SAAS,EACV,MAAM,mBAAmB,CAAC;AAG3B,iFAAiF;AACjF,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC;AAYpF;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAoC9F"}
|
package/dist/adapter/copy.js
CHANGED
|
@@ -10,9 +10,13 @@
|
|
|
10
10
|
* between storage engines are all this one call, with a different source
|
|
11
11
|
* and a different kind of store to create. Full trust, like any direct
|
|
12
12
|
* adapter access: authorship and history land as recorded, which no write
|
|
13
|
-
* through Stack may do.
|
|
13
|
+
* through Stack may do.
|
|
14
|
+
*
|
|
15
|
+
* A copy reads one moment of its source: it reads the source's head before
|
|
16
|
+
* and after, and refuses the copy if the two differ. One rule for every
|
|
17
|
+
* source, whoever else writes to it. See docs/spec/portability.md.
|
|
14
18
|
*/
|
|
15
|
-
import { InvalidAdapterError, OwnerMismatchError } from '../errors.js';
|
|
19
|
+
import { InvalidAdapterError, OwnerMismatchError, StackConflictError } from '../errors.js';
|
|
16
20
|
import { resolveQuery } from '../query-validation.js';
|
|
17
21
|
import { SYSTEM_TYPES } from '../types/index.js';
|
|
18
22
|
/** Records read per page; any size works, as each page is written before the next is read. */
|
|
@@ -27,19 +31,22 @@ const EVERYTHING = {
|
|
|
27
31
|
* Copy everything `from` holds into the store `create` makes from its
|
|
28
32
|
* `_config` record and that record's history, and return that store, open.
|
|
29
33
|
* Not atomic: a failure closes the store part-written, and the caller, whose
|
|
30
|
-
* store it is, removes it.
|
|
31
|
-
*
|
|
34
|
+
* store it is, removes it. A source written meanwhile is refused with
|
|
35
|
+
* StackConflictError, and the copy is run again into a new store.
|
|
32
36
|
* See docs/spec/portability.md § Copying a stack.
|
|
33
37
|
*/
|
|
34
38
|
export async function copyStack(from, create) {
|
|
35
39
|
const listBlobs = from.listBlobs?.bind(from);
|
|
36
|
-
if (!listBlobs)
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
if (!listBlobs)
|
|
41
|
+
refuseSource('it has no listBlobs(), so its blobs cannot be enumerated');
|
|
42
|
+
const head = from.head?.bind(from);
|
|
43
|
+
if (!head)
|
|
44
|
+
refuseSource('it has no head(), so a write during the copy could not be detected');
|
|
45
|
+
// Before the first read, so every write that could land during one moves it.
|
|
46
|
+
const started = await head();
|
|
39
47
|
const config = await from.getRecord(SYSTEM_TYPES.CONFIG);
|
|
40
|
-
if (!config)
|
|
41
|
-
|
|
42
|
-
}
|
|
48
|
+
if (!config)
|
|
49
|
+
refuseSource('it holds no _config record');
|
|
43
50
|
const [versions, journal] = await Promise.all([
|
|
44
51
|
from.getVersions(config.id),
|
|
45
52
|
from.getJournal(config.id),
|
|
@@ -52,13 +59,17 @@ export async function copyStack(from, create) {
|
|
|
52
59
|
const listHeld = to.listBlobs?.bind(to);
|
|
53
60
|
if (!listHeld)
|
|
54
61
|
refuseTarget('it has no listBlobs(), so it could not be copied from in turn');
|
|
62
|
+
if (!to.head)
|
|
63
|
+
refuseTarget('it has no head(), so it could not be copied from in turn');
|
|
55
64
|
await assertNewStore(to, config.content.ownerEntityId, listHeld);
|
|
56
65
|
for (const type of await from.listTypes())
|
|
57
66
|
await to.saveType(type);
|
|
58
67
|
// Bytes before the Records that name them, as every upload writes them.
|
|
59
|
-
|
|
60
|
-
await to.putBlob(await from.getBlob(fileId));
|
|
68
|
+
await copyBlobs(from, to, listBlobs);
|
|
61
69
|
await copyRecords(from, importRecord);
|
|
70
|
+
if ((await head()) !== started) {
|
|
71
|
+
throw new StackConflictError('The source was written while it was copied. Copy it again into a new store.');
|
|
72
|
+
}
|
|
62
73
|
return to;
|
|
63
74
|
}
|
|
64
75
|
catch (err) {
|
|
@@ -67,14 +78,17 @@ export async function copyStack(from, create) {
|
|
|
67
78
|
throw err;
|
|
68
79
|
}
|
|
69
80
|
}
|
|
81
|
+
function refuseSource(why) {
|
|
82
|
+
throw new InvalidAdapterError(`Cannot copy from this adapter: ${why}.`);
|
|
83
|
+
}
|
|
70
84
|
function refuseTarget(why) {
|
|
71
85
|
throw new InvalidAdapterError(`Cannot copy into the store create() returned: ${why}.`);
|
|
72
86
|
}
|
|
73
87
|
/**
|
|
74
88
|
* A target is a store as its adapter creates one: the source's owner,
|
|
75
89
|
* checked as open() checks it, and nothing held yet — no Record, no Type, no
|
|
76
|
-
* blob. Every end of a copy lists all it holds, so a target
|
|
77
|
-
* store a later copy can read
|
|
90
|
+
* blob. Every end of a copy lists all it holds and has a head, so a target
|
|
91
|
+
* is itself a store a later copy can read.
|
|
78
92
|
*/
|
|
79
93
|
async function assertNewStore(to, ownerEntityId, listHeld) {
|
|
80
94
|
if (to.ownerEntityId !== ownerEntityId) {
|
|
@@ -85,14 +99,26 @@ async function assertNewStore(to, ownerEntityId, listHeld) {
|
|
|
85
99
|
}
|
|
86
100
|
if ((await to.listTypes()).length)
|
|
87
101
|
refuseTarget('it already holds Types');
|
|
88
|
-
if ((await listHeld()).length)
|
|
102
|
+
if ((await listHeld({ limit: 1 })).length)
|
|
89
103
|
refuseTarget('it already holds blobs');
|
|
90
104
|
}
|
|
105
|
+
async function copyBlobs(from, to, listBlobs) {
|
|
106
|
+
let afterFileId;
|
|
107
|
+
for (;;) {
|
|
108
|
+
const page = await listBlobs({ afterFileId, limit: PAGE_SIZE });
|
|
109
|
+
for (const { fileId } of page)
|
|
110
|
+
await to.putBlob(await from.getBlob(fileId));
|
|
111
|
+
if (page.length < PAGE_SIZE)
|
|
112
|
+
return;
|
|
113
|
+
afterFileId = page[page.length - 1].fileId;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
91
116
|
async function copyRecords(from, importRecord) {
|
|
92
117
|
let cursor;
|
|
93
118
|
do {
|
|
94
119
|
const page = await from.queryRecords(resolveQuery({ ...EVERYTHING, cursor }));
|
|
95
120
|
for (const record of page.records) {
|
|
121
|
+
// One Record's history is read whole, as importRecord() takes it.
|
|
96
122
|
const [versions, journal] = await Promise.all([
|
|
97
123
|
from.getVersions(record.id),
|
|
98
124
|
from.getJournal(record.id),
|
package/dist/adapter/copy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copy.js","sourceRoot":"","sources":["../../src/adapter/copy.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"copy.js","sourceRoot":"","sources":["../../src/adapter/copy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Write heads
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* A head says where a store's writes stand, so a reader that takes one
|
|
5
|
+
* before and one after learns whether anything was written between. A
|
|
6
|
+
* local store's writer is the process that owns it, so that process can
|
|
7
|
+
* count its own writes: trackWrites() wraps every write method an adapter
|
|
8
|
+
* has, so no method has to remember to. The count starts in a random
|
|
9
|
+
* epoch, so a store reopened (or a server restarted) never returns to a
|
|
10
|
+
* head it reported before. See docs/spec/portability.md § Copying a stack.
|
|
11
|
+
*/
|
|
12
|
+
/** One store's writes, counted for its `head()`. */
|
|
13
|
+
declare class WriteHead {
|
|
14
|
+
private readonly epoch;
|
|
15
|
+
private settled;
|
|
16
|
+
private inFlight;
|
|
17
|
+
private busyReads;
|
|
18
|
+
/**
|
|
19
|
+
* A write in flight may land on either side of a read, so a head read
|
|
20
|
+
* meanwhile matches no other head; one read after it settles differs from
|
|
21
|
+
* every head read before.
|
|
22
|
+
*/
|
|
23
|
+
read(): string;
|
|
24
|
+
track<T>(write: () => Promise<T>): Promise<T>;
|
|
25
|
+
}
|
|
26
|
+
/** The head a `head()` reports. */
|
|
27
|
+
export type { WriteHead };
|
|
28
|
+
/**
|
|
29
|
+
* Wrap every write method `adapter` has so it moves the returned head, and
|
|
30
|
+
* return that head for the adapter's `head()` to read. Call once, from the
|
|
31
|
+
* adapter's own constructor: it wraps the methods present then, so a write
|
|
32
|
+
* method assigned as a field after that call goes uncounted (the
|
|
33
|
+
* conformance suite's head tests catch one).
|
|
34
|
+
*/
|
|
35
|
+
export declare function trackWrites(adapter: object): WriteHead;
|
|
36
|
+
/** The head of a store made of two halves: it moves when either does. */
|
|
37
|
+
export declare function combinedHead(record: string, blob: string): string;
|
|
38
|
+
//# sourceMappingURL=head.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"head.d.ts","sourceRoot":"","sources":["../../src/adapter/head.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA6BH,oDAAoD;AACpD,cAAM,SAAS;IACb,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuB;IAC7C,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,SAAS,CAAK;IAEtB;;;;OAIG;IACH,IAAI,IAAI,MAAM;IAKR,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CASpD;AAED,mCAAmC;AACnC,YAAY,EAAE,SAAS,EAAE,CAAC;AAE1B;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAUtD;AAED,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjE"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Write heads
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* A head says where a store's writes stand, so a reader that takes one
|
|
5
|
+
* before and one after learns whether anything was written between. A
|
|
6
|
+
* local store's writer is the process that owns it, so that process can
|
|
7
|
+
* count its own writes: trackWrites() wraps every write method an adapter
|
|
8
|
+
* has, so no method has to remember to. The count starts in a random
|
|
9
|
+
* epoch, so a store reopened (or a server restarted) never returns to a
|
|
10
|
+
* head it reported before. See docs/spec/portability.md § Copying a stack.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Every write method, keyed so a method added to StackAdapter fails
|
|
14
|
+
* typecheck here until it is listed or named a read.
|
|
15
|
+
*/
|
|
16
|
+
const WRITE_METHODS = {
|
|
17
|
+
createRecord: true,
|
|
18
|
+
importRecord: true,
|
|
19
|
+
patchContent: true,
|
|
20
|
+
deleteRecord: true,
|
|
21
|
+
undeleteRecord: true,
|
|
22
|
+
setParent: true,
|
|
23
|
+
setUnlisted: true,
|
|
24
|
+
editAssociations: true,
|
|
25
|
+
setAssociations: true,
|
|
26
|
+
editAccess: true,
|
|
27
|
+
setAccess: true,
|
|
28
|
+
restoreVersion: true,
|
|
29
|
+
commitMigration: true,
|
|
30
|
+
saveType: true,
|
|
31
|
+
deleteUnreferencedAttachmentRecords: true,
|
|
32
|
+
putBlob: true,
|
|
33
|
+
deleteBlob: true,
|
|
34
|
+
putAttachmentWithMetadata: true,
|
|
35
|
+
};
|
|
36
|
+
/** One store's writes, counted for its `head()`. */
|
|
37
|
+
class WriteHead {
|
|
38
|
+
epoch = crypto.randomUUID();
|
|
39
|
+
settled = 0;
|
|
40
|
+
inFlight = 0;
|
|
41
|
+
busyReads = 0;
|
|
42
|
+
/**
|
|
43
|
+
* A write in flight may land on either side of a read, so a head read
|
|
44
|
+
* meanwhile matches no other head; one read after it settles differs from
|
|
45
|
+
* every head read before.
|
|
46
|
+
*/
|
|
47
|
+
read() {
|
|
48
|
+
if (this.inFlight)
|
|
49
|
+
return `${this.epoch}.${this.settled}.${++this.busyReads}`;
|
|
50
|
+
return `${this.epoch}.${this.settled}`;
|
|
51
|
+
}
|
|
52
|
+
async track(write) {
|
|
53
|
+
this.inFlight++;
|
|
54
|
+
try {
|
|
55
|
+
return await write();
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
this.inFlight--;
|
|
59
|
+
this.settled++;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Wrap every write method `adapter` has so it moves the returned head, and
|
|
65
|
+
* return that head for the adapter's `head()` to read. Call once, from the
|
|
66
|
+
* adapter's own constructor: it wraps the methods present then, so a write
|
|
67
|
+
* method assigned as a field after that call goes uncounted (the
|
|
68
|
+
* conformance suite's head tests catch one).
|
|
69
|
+
*/
|
|
70
|
+
export function trackWrites(adapter) {
|
|
71
|
+
const head = new WriteHead();
|
|
72
|
+
const members = adapter;
|
|
73
|
+
for (const name of Object.keys(WRITE_METHODS)) {
|
|
74
|
+
const write = members[name];
|
|
75
|
+
if (typeof write !== 'function')
|
|
76
|
+
continue;
|
|
77
|
+
members[name] = (...args) => head.track(() => write.apply(adapter, args));
|
|
78
|
+
}
|
|
79
|
+
return head;
|
|
80
|
+
}
|
|
81
|
+
/** The head of a store made of two halves: it moves when either does. */
|
|
82
|
+
export function combinedHead(record, blob) {
|
|
83
|
+
return `${record}/${blob}`;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=head.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"head.js","sourceRoot":"","sources":["../../src/adapter/head.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH;;;GAGG;AACH,MAAM,aAAa,GAAmC;IACpD,YAAY,EAAE,IAAI;IAClB,YAAY,EAAE,IAAI;IAClB,YAAY,EAAE,IAAI;IAClB,YAAY,EAAE,IAAI;IAClB,cAAc,EAAE,IAAI;IACpB,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,IAAI;IACjB,gBAAgB,EAAE,IAAI;IACtB,eAAe,EAAE,IAAI;IACrB,UAAU,EAAE,IAAI;IAChB,SAAS,EAAE,IAAI;IACf,cAAc,EAAE,IAAI;IACpB,eAAe,EAAE,IAAI;IACrB,QAAQ,EAAE,IAAI;IACd,mCAAmC,EAAE,IAAI;IACzC,OAAO,EAAE,IAAI;IACb,UAAU,EAAE,IAAI;IAChB,yBAAyB,EAAE,IAAI;CAChC,CAAC;AAEF,oDAAoD;AACpD,MAAM,SAAS;IACI,KAAK,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;IACrC,OAAO,GAAG,CAAC,CAAC;IACZ,QAAQ,GAAG,CAAC,CAAC;IACb,SAAS,GAAG,CAAC,CAAC;IAEtB;;;;OAIG;IACH,IAAI;QACF,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,OAAO,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;QAC9E,OAAO,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,KAAK,CAAI,KAAuB;QACpC,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC;YACH,OAAO,MAAM,KAAK,EAAE,CAAC;QACvB,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChB,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;CACF;AAKD;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,MAAM,IAAI,GAAG,IAAI,SAAS,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAG,OAAkC,CAAC;IACnD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC5B,IAAI,OAAO,KAAK,KAAK,UAAU;YAAE,SAAS;QAC1C,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAe,EAAE,EAAE,CACrC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAE,KAA+C,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;IAC5F,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,IAAY;IACvD,OAAO,GAAG,MAAM,IAAI,IAAI,EAAE,CAAC;AAC7B,CAAC"}
|
package/dist/adapter/index.d.ts
CHANGED
|
@@ -7,9 +7,13 @@
|
|
|
7
7
|
* adapters). Types an app reads too, such as StackCapabilities, live in
|
|
8
8
|
* the root entry point instead: every export has exactly one home.
|
|
9
9
|
*/
|
|
10
|
-
export type { AdapterQuery, PlainQuery, AdapterSort, StackAdapter, StackRecordAdapter, StackBlobAdapter, BlobInfo, SnapshotOptions, JournalEntryInput, JournalOptions, MutateOptions, AspectWriteOptions, ElementWriteOptions, Reach, RecordHistory, StoreSeed, } from '../types/index.js';
|
|
10
|
+
export type { AdapterQuery, PlainQuery, AdapterSort, StackAdapter, StackRecordAdapter, StackBlobAdapter, BlobInfo, BlobsQuery, StoreWriters, StoreReadMember, StoreWriteMethod, RecordWriteMethod, BlobWriteMethod, SnapshotOptions, JournalEntryInput, JournalOptions, MutateOptions, AspectWriteOptions, ElementWriteOptions, Reach, RecordHistory, StoreSeed, } from '../types/index.js';
|
|
11
11
|
export { sameAssociationSet } from '../associations/identity.js';
|
|
12
12
|
export { ElementSetMovedError, FormatMismatchError, OwnerMismatchError, softDeletedRefusal, } from '../errors.js';
|
|
13
|
+
export { assertFileId, blobWindow } from './blobs.js';
|
|
14
|
+
export { trackWrites, combinedHead } from './head.js';
|
|
15
|
+
export type { WriteHead } from './head.js';
|
|
16
|
+
export { FILE_ID_RE } from '../validate.js';
|
|
13
17
|
export { combineAdapters } from './combine.js';
|
|
14
18
|
export { copyStack } from './copy.js';
|
|
15
19
|
export type { CreateStore } from './copy.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,YAAY,EACV,YAAY,EACZ,UAAU,EACV,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,KAAK,EACL,aAAa,EACb,SAAS,GACV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EACL,uBAAuB,EACvB,eAAe,EACf,YAAY,EACZ,6BAA6B,EAC7B,uBAAuB,EACvB,wBAAwB,EACxB,cAAc,EACd,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,YAAY,EACV,YAAY,EACZ,UAAU,EACV,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,KAAK,EACL,aAAa,EACb,SAAS,GACV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACtD,YAAY,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EACL,uBAAuB,EACvB,eAAe,EACf,YAAY,EACZ,6BAA6B,EAC7B,uBAAuB,EACvB,wBAAwB,EACxB,cAAc,EACd,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/adapter/index.js
CHANGED
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
*/
|
|
10
10
|
export { sameAssociationSet } from '../associations/identity.js';
|
|
11
11
|
export { ElementSetMovedError, FormatMismatchError, OwnerMismatchError, softDeletedRefusal, } from '../errors.js';
|
|
12
|
+
export { assertFileId, blobWindow } from './blobs.js';
|
|
13
|
+
export { trackWrites, combinedHead } from './head.js';
|
|
14
|
+
export { FILE_ID_RE } from '../validate.js';
|
|
12
15
|
export { combineAdapters } from './combine.js';
|
|
13
16
|
export { copyStack } from './copy.js';
|
|
14
17
|
export { newStoreSeed } from './seed.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA0BH,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC,OAAO,EACL,uBAAuB,EACvB,eAAe,EACf,YAAY,EACZ,6BAA6B,EAC7B,uBAAuB,EACvB,wBAAwB,EACxB,cAAc,EACd,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,GACb,MAAM,WAAW,CAAC"}
|
package/dist/stack/stack.d.ts
CHANGED
|
@@ -93,8 +93,8 @@ export declare class Stack implements StackClient {
|
|
|
93
93
|
asActor(actor: Actor): ScopedStack;
|
|
94
94
|
/**
|
|
95
95
|
* A scoped view needs a stack that owns its storage: one whose adapter
|
|
96
|
-
* queries within a reach and
|
|
97
|
-
*
|
|
96
|
+
* queries within a reach and is its store's only writer. A server-backed
|
|
97
|
+
* stack is scoped by the session that opened it instead.
|
|
98
98
|
* See docs/spec/access-control.md § Enforcement: Stack.asEntity().
|
|
99
99
|
*/
|
|
100
100
|
private scope;
|
|
@@ -345,7 +345,7 @@ export declare class Stack implements StackClient {
|
|
|
345
345
|
* from.
|
|
346
346
|
*/
|
|
347
347
|
private openRelay;
|
|
348
|
-
/** Whether
|
|
348
|
+
/** Whether a relay can be opened; whether one is needed is `writers`. */
|
|
349
349
|
private get relaysChanges();
|
|
350
350
|
/**
|
|
351
351
|
* Flush pending writes to the underlying storage. A no-op for adapters
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stack.d.ts","sourceRoot":"","sources":["../../src/stack/stack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AA4BH,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,UAAU,EACV,MAAM,EACN,MAAM,EACN,YAAY,EACZ,UAAU,EAEV,WAAW,EAEX,eAAe,EACf,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACT,oBAAoB,EACpB,iBAAiB,EACjB,MAAM,EACN,QAAQ,EAER,KAAK,EACL,cAAc,EACd,QAAQ,EACR,KAAK,EACL,YAAY,EAEZ,YAAY,EAGZ,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,aAAa,EACb,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAqC3B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAgBjF,OAAO,EAAE,WAAW,EAAc,MAAM,iCAAiC,CAAC;AAa1E,OAAO,KAAK,EACV,8BAA8B,EAC9B,+BAA+B,EAC/B,8BAA8B,EAC9B,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,EACX,YAAY,EACb,MAAM,aAAa,CAAC;AAOrB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEnF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAkEnD,qBAAa,KAAM,YAAW,WAAW;IAoBrC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,sBAAsB;IACvC,OAAO,CAAC,QAAQ,CAAC,UAAU;IArB7B;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgC;IAE1D,6DAA6D;IAC7D,OAAO,CAAC,MAAM,CAAS;IAEvB;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAE/C,OAAO;IAMP;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ;IAIhB;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;YAKZ,aAAa;IAQ3B;;OAEG;WACU,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,KAAK,CAAC;IAmBjF;;;;;OAKG;YACW,iBAAiB;IAY/B,IAAI,aAAa,IAAI,QAAQ,CAE5B;IAEK,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAI1D,cAAc,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAInD,IAAI,YAAY,IAAI,iBAAiB,CAEpC;IAED;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,GAAG,WAAW;IAIhD;;;;;OAKG;IACH,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,WAAW;IAKlC;;;;;OAKG;IACH,OAAO,CAAC,KAAK;
|
|
1
|
+
{"version":3,"file":"stack.d.ts","sourceRoot":"","sources":["../../src/stack/stack.ts"],"names":[],"mappings":"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"}
|
package/dist/stack/stack.js
CHANGED
|
@@ -219,8 +219,8 @@ export class Stack {
|
|
|
219
219
|
}
|
|
220
220
|
/**
|
|
221
221
|
* A scoped view needs a stack that owns its storage: one whose adapter
|
|
222
|
-
* queries within a reach and
|
|
223
|
-
*
|
|
222
|
+
* queries within a reach and is its store's only writer. A server-backed
|
|
223
|
+
* stack is scoped by the session that opened it instead.
|
|
224
224
|
* See docs/spec/access-control.md § Enforcement: Stack.asEntity().
|
|
225
225
|
*/
|
|
226
226
|
scope(principalId, subjectId) {
|
|
@@ -231,9 +231,10 @@ export class Stack {
|
|
|
231
231
|
"query could not be kept to the requester's reach. Every local adapter must; a " +
|
|
232
232
|
'server-backed stack is scoped by opening it with the session you mean.');
|
|
233
233
|
}
|
|
234
|
-
if (this.
|
|
235
|
-
throw new ScopeUnavailableError('This stack cannot be scoped:
|
|
236
|
-
'scoped by the session that opened the feed. Open it with the session
|
|
234
|
+
if (this.adapter.writers === 'shared') {
|
|
235
|
+
throw new ScopeUnavailableError('This stack cannot be scoped: others write its store, and their changes reach it ' +
|
|
236
|
+
'scoped by the session that opened the feed, if at all. Open it with the session ' +
|
|
237
|
+
'you mean.');
|
|
237
238
|
}
|
|
238
239
|
return new ScopedStack(scopeToken, {
|
|
239
240
|
stack: this,
|
|
@@ -1098,6 +1099,12 @@ export class Stack {
|
|
|
1098
1099
|
*/
|
|
1099
1100
|
async subscribe(handler, opts = {}) {
|
|
1100
1101
|
this.assertOpen();
|
|
1102
|
+
if (this.adapter.writers === 'shared' && !this.relaysChanges) {
|
|
1103
|
+
throw new StackBadRequestError('subscribe() cannot be served: others write this stack, and its adapter has no ' +
|
|
1104
|
+
"subscribeChanges() to relay their changes, so a stream of this client's own writes " +
|
|
1105
|
+
'would pass for the whole. Connect to a server that advertises a change feed, or ' +
|
|
1106
|
+
'poll query().');
|
|
1107
|
+
}
|
|
1101
1108
|
assertSinceUsable(opts.since, this.relaysChanges);
|
|
1102
1109
|
assertValidBaseIdFilter(opts.filter);
|
|
1103
1110
|
const unsubscribe = this.changes.subscribe(handler, opts);
|
|
@@ -1138,7 +1145,7 @@ export class Stack {
|
|
|
1138
1145
|
void stop();
|
|
1139
1146
|
};
|
|
1140
1147
|
}
|
|
1141
|
-
/** Whether
|
|
1148
|
+
/** Whether a relay can be opened; whether one is needed is `writers`. */
|
|
1142
1149
|
get relaysChanges() {
|
|
1143
1150
|
return typeof this.adapter.subscribeChanges === 'function';
|
|
1144
1151
|
}
|