@haverstack/core 0.40.0 → 0.42.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 +121 -59
- package/dist/access.d.ts +34 -36
- package/dist/access.d.ts.map +1 -1
- package/dist/access.js +65 -42
- package/dist/access.js.map +1 -1
- package/dist/{combine.d.ts → adapter/combine.d.ts} +8 -1
- package/dist/adapter/combine.d.ts.map +1 -0
- package/dist/{combine.js → adapter/combine.js} +7 -0
- package/dist/adapter/combine.js.map +1 -0
- package/dist/{adapter-entry.d.ts → adapter/index.d.ts} +6 -5
- package/dist/adapter/index.d.ts.map +1 -0
- package/dist/{adapter-entry.js → adapter/index.js} +5 -4
- package/dist/adapter/index.js.map +1 -0
- package/dist/{sort.d.ts → adapter/sort.d.ts} +20 -20
- package/dist/adapter/sort.d.ts.map +1 -0
- package/dist/{sort.js → adapter/sort.js} +37 -27
- package/dist/adapter/sort.js.map +1 -0
- package/dist/associations/identity.d.ts +93 -0
- package/dist/associations/identity.d.ts.map +1 -0
- package/dist/associations/identity.js +198 -0
- package/dist/associations/identity.js.map +1 -0
- package/dist/associations/validation.d.ts +90 -0
- package/dist/associations/validation.d.ts.map +1 -0
- package/dist/associations/validation.js +339 -0
- package/dist/associations/validation.js.map +1 -0
- package/dist/attachment-records.d.ts +48 -0
- package/dist/attachment-records.d.ts.map +1 -0
- package/dist/attachment-records.js +52 -0
- package/dist/attachment-records.js.map +1 -0
- package/dist/collection.d.ts +182 -0
- package/dist/collection.d.ts.map +1 -0
- package/dist/collection.js +407 -0
- package/dist/collection.js.map +1 -0
- package/dist/content-match.d.ts +25 -0
- package/dist/content-match.d.ts.map +1 -0
- package/dist/content-match.js +51 -0
- package/dist/content-match.js.map +1 -0
- package/dist/content-translation.d.ts +42 -0
- package/dist/content-translation.d.ts.map +1 -0
- package/dist/content-translation.js +108 -0
- package/dist/content-translation.js.map +1 -0
- package/dist/did/did.d.ts.map +1 -0
- package/dist/{did.js → did/did.js} +3 -4
- package/dist/did/did.js.map +1 -0
- package/dist/{did-entry.d.ts → did/index.d.ts} +1 -1
- package/dist/did/index.d.ts.map +1 -0
- package/dist/{did-entry.js → did/index.js} +3 -3
- package/dist/did/index.js.map +1 -0
- package/dist/errors.d.ts +36 -63
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +35 -58
- package/dist/errors.js.map +1 -1
- package/dist/grants.d.ts +20 -43
- package/dist/grants.d.ts.map +1 -1
- package/dist/grants.js +71 -134
- package/dist/grants.js.map +1 -1
- package/dist/id.d.ts +13 -31
- package/dist/id.d.ts.map +1 -1
- package/dist/id.js +13 -31
- package/dist/id.js.map +1 -1
- package/dist/index.d.ts +14 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -5
- package/dist/index.js.map +1 -1
- package/dist/install.d.ts +141 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +219 -0
- package/dist/install.js.map +1 -0
- package/dist/merge.d.ts.map +1 -1
- package/dist/merge.js +5 -11
- package/dist/merge.js.map +1 -1
- package/dist/migration-steps.d.ts +102 -0
- package/dist/migration-steps.d.ts.map +1 -0
- package/dist/migration-steps.js +293 -0
- package/dist/migration-steps.js.map +1 -0
- package/dist/query-validation.d.ts +28 -94
- package/dist/query-validation.d.ts.map +1 -1
- package/dist/query-validation.js +156 -336
- package/dist/query-validation.js.map +1 -1
- package/dist/record-changes.d.ts +2 -117
- package/dist/record-changes.d.ts.map +1 -1
- package/dist/record-changes.js +10 -212
- package/dist/record-changes.js.map +1 -1
- package/dist/schema.d.ts +18 -7
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +59 -30
- package/dist/schema.js.map +1 -1
- package/dist/scoped-stack/authority.d.ts +156 -0
- package/dist/scoped-stack/authority.d.ts.map +1 -0
- package/dist/scoped-stack/authority.js +384 -0
- package/dist/scoped-stack/authority.js.map +1 -0
- package/dist/scoped-stack/scoped-stack.d.ts +338 -0
- package/dist/scoped-stack/scoped-stack.d.ts.map +1 -0
- package/dist/scoped-stack/scoped-stack.js +776 -0
- package/dist/scoped-stack/scoped-stack.js.map +1 -0
- package/dist/scoped-stack/subscription.d.ts +55 -0
- package/dist/scoped-stack/subscription.d.ts.map +1 -0
- package/dist/scoped-stack/subscription.js +110 -0
- package/dist/scoped-stack/subscription.js.map +1 -0
- package/dist/stack/attachments.d.ts +24 -0
- package/dist/stack/attachments.d.ts.map +1 -0
- package/dist/stack/attachments.js +113 -0
- package/dist/stack/attachments.js.map +1 -0
- package/dist/{changes.d.ts → stack/changes.d.ts} +29 -65
- package/dist/stack/changes.d.ts.map +1 -0
- package/dist/{changes.js → stack/changes.js} +32 -66
- package/dist/stack/changes.js.map +1 -0
- package/dist/stack/client.d.ts +271 -0
- package/dist/stack/client.d.ts.map +1 -0
- package/dist/stack/client.js +9 -0
- package/dist/stack/client.js.map +1 -0
- package/dist/stack/identity-bindings.d.ts.map +1 -0
- package/dist/{identity-bindings.js → stack/identity-bindings.js} +8 -14
- package/dist/stack/identity-bindings.js.map +1 -0
- package/dist/stack/install-app.d.ts +22 -0
- package/dist/stack/install-app.d.ts.map +1 -0
- package/dist/stack/install-app.js +260 -0
- package/dist/stack/install-app.js.map +1 -0
- package/dist/stack/integrity.d.ts +94 -0
- package/dist/stack/integrity.d.ts.map +1 -0
- package/dist/stack/integrity.js +268 -0
- package/dist/stack/integrity.js.map +1 -0
- package/dist/{limits.d.ts → stack/limits.d.ts} +2 -5
- package/dist/stack/limits.d.ts.map +1 -0
- package/dist/{limits.js → stack/limits.js} +3 -6
- package/dist/stack/limits.js.map +1 -0
- package/dist/stack/migrations.d.ts +59 -0
- package/dist/stack/migrations.d.ts.map +1 -0
- package/dist/stack/migrations.js +141 -0
- package/dist/stack/migrations.js.map +1 -0
- package/dist/{stack-reads.d.ts → stack/reads.d.ts} +33 -6
- package/dist/stack/reads.d.ts.map +1 -0
- package/dist/{stack-reads.js → stack/reads.js} +49 -7
- package/dist/stack/reads.js.map +1 -0
- package/dist/stack/record-id.d.ts +35 -0
- package/dist/stack/record-id.d.ts.map +1 -0
- package/dist/stack/record-id.js +82 -0
- package/dist/stack/record-id.js.map +1 -0
- package/dist/stack/stack.d.ts +438 -0
- package/dist/stack/stack.d.ts.map +1 -0
- package/dist/stack/stack.js +1366 -0
- package/dist/stack/stack.js.map +1 -0
- package/dist/stack/system-types.d.ts +16 -0
- package/dist/stack/system-types.d.ts.map +1 -0
- package/dist/stack/system-types.js +111 -0
- package/dist/stack/system-types.js.map +1 -0
- package/dist/stack/type-grants.d.ts +20 -0
- package/dist/stack/type-grants.d.ts.map +1 -0
- package/dist/stack/type-grants.js +69 -0
- package/dist/stack/type-grants.js.map +1 -0
- package/dist/stack/write-expectation.d.ts +78 -0
- package/dist/stack/write-expectation.d.ts.map +1 -0
- package/dist/stack/write-expectation.js +71 -0
- package/dist/stack/write-expectation.js.map +1 -0
- package/dist/testing.d.ts +21 -26
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +50 -70
- package/dist/testing.js.map +1 -1
- package/dist/type-handle.d.ts +67 -78
- package/dist/type-handle.d.ts.map +1 -1
- package/dist/type-handle.js +44 -111
- package/dist/type-handle.js.map +1 -1
- package/dist/types/adapter.d.ts +223 -0
- package/dist/types/adapter.d.ts.map +1 -0
- package/dist/types/adapter.js +5 -0
- package/dist/types/adapter.js.map +1 -0
- package/dist/types/associations.d.ts +156 -0
- package/dist/types/associations.d.ts.map +1 -0
- package/dist/types/associations.js +13 -0
- package/dist/types/associations.js.map +1 -0
- package/dist/types/capabilities.d.ts +89 -0
- package/dist/types/capabilities.d.ts.map +1 -0
- package/dist/types/capabilities.js +5 -0
- package/dist/types/capabilities.js.map +1 -0
- package/dist/types/events.d.ts +155 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +5 -0
- package/dist/types/events.js.map +1 -0
- package/dist/types/ids.d.ts +43 -0
- package/dist/types/ids.d.ts.map +1 -0
- package/dist/types/ids.js +5 -0
- package/dist/types/ids.js.map +1 -0
- package/dist/types/index.d.ts +19 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +19 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/journal.d.ts +47 -0
- package/dist/types/journal.d.ts.map +1 -0
- package/dist/types/journal.js +5 -0
- package/dist/types/journal.js.map +1 -0
- package/dist/types/query.d.ts +185 -0
- package/dist/types/query.d.ts.map +1 -0
- package/dist/types/query.js +10 -0
- package/dist/types/query.js.map +1 -0
- package/dist/types/records.d.ts +76 -0
- package/dist/types/records.d.ts.map +1 -0
- package/dist/types/records.js +5 -0
- package/dist/types/records.js.map +1 -0
- package/dist/types/schema.d.ts +74 -0
- package/dist/types/schema.d.ts.map +1 -0
- package/dist/types/schema.js +5 -0
- package/dist/types/schema.js.map +1 -0
- package/dist/types/system.d.ts +161 -0
- package/dist/types/system.d.ts.map +1 -0
- package/dist/types/system.js +32 -0
- package/dist/types/system.js.map +1 -0
- package/dist/types/tokens.d.ts +39 -0
- package/dist/types/tokens.d.ts.map +1 -0
- package/dist/types/tokens.js +5 -0
- package/dist/types/tokens.js.map +1 -0
- package/dist/validate.d.ts +29 -70
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +65 -97
- package/dist/validate.js.map +1 -1
- package/dist/{attachment-download.d.ts → wire/attachment-download.d.ts} +0 -57
- package/dist/wire/attachment-download.d.ts.map +1 -0
- package/dist/{attachment-download.js → wire/attachment-download.js} +0 -61
- package/dist/wire/attachment-download.js.map +1 -0
- package/dist/{auth.d.ts → wire/auth.d.ts} +5 -8
- package/dist/wire/auth.d.ts.map +1 -0
- package/dist/{auth.js → wire/auth.js} +5 -8
- package/dist/wire/auth.js.map +1 -0
- package/dist/{wire-body.d.ts → wire/body.d.ts} +13 -5
- package/dist/wire/body.d.ts.map +1 -0
- package/dist/{wire-body.js → wire/body.js} +65 -7
- package/dist/wire/body.js.map +1 -0
- package/dist/{wire-entry.d.ts → wire/index.d.ts} +12 -12
- package/dist/wire/index.d.ts.map +1 -0
- package/dist/{wire-entry.js → wire/index.js} +13 -17
- package/dist/wire/index.js.map +1 -0
- package/dist/{wire-record.d.ts → wire/record.d.ts} +10 -22
- package/dist/wire/record.d.ts.map +1 -0
- package/dist/{wire-record.js → wire/record.js} +12 -24
- package/dist/wire/record.js.map +1 -0
- package/dist/{wire-request.d.ts → wire/request.d.ts} +20 -37
- package/dist/wire/request.d.ts.map +1 -0
- package/dist/{wire-request.js → wire/request.js} +79 -54
- package/dist/wire/request.js.map +1 -0
- package/package.json +7 -7
- package/dist/adapter-entry.d.ts.map +0 -1
- package/dist/adapter-entry.js.map +0 -1
- package/dist/attachment-download.d.ts.map +0 -1
- package/dist/attachment-download.js.map +0 -1
- package/dist/auth.d.ts.map +0 -1
- package/dist/auth.js.map +0 -1
- package/dist/changes.d.ts.map +0 -1
- package/dist/changes.js.map +0 -1
- package/dist/combine.d.ts.map +0 -1
- package/dist/combine.js.map +0 -1
- package/dist/did-entry.d.ts.map +0 -1
- package/dist/did-entry.js.map +0 -1
- package/dist/did.d.ts.map +0 -1
- package/dist/did.js.map +0 -1
- package/dist/identity-bindings.d.ts.map +0 -1
- package/dist/identity-bindings.js.map +0 -1
- package/dist/limits.d.ts.map +0 -1
- package/dist/limits.js.map +0 -1
- package/dist/record-id.d.ts +0 -70
- package/dist/record-id.d.ts.map +0 -1
- package/dist/record-id.js +0 -127
- package/dist/record-id.js.map +0 -1
- package/dist/scoped-stack.d.ts +0 -532
- package/dist/scoped-stack.d.ts.map +0 -1
- package/dist/scoped-stack.js +0 -1219
- package/dist/scoped-stack.js.map +0 -1
- package/dist/sort.d.ts.map +0 -1
- package/dist/sort.js.map +0 -1
- package/dist/stack-reads.d.ts.map +0 -1
- package/dist/stack-reads.js.map +0 -1
- package/dist/stack.d.ts +0 -971
- package/dist/stack.d.ts.map +0 -1
- package/dist/stack.js +0 -2012
- package/dist/stack.js.map +0 -1
- package/dist/types.d.ts +0 -1250
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -49
- package/dist/types.js.map +0 -1
- package/dist/wire-body.d.ts.map +0 -1
- package/dist/wire-body.js.map +0 -1
- package/dist/wire-entry.d.ts.map +0 -1
- package/dist/wire-entry.js.map +0 -1
- package/dist/wire-record.d.ts.map +0 -1
- package/dist/wire-record.js.map +0 -1
- package/dist/wire-request.d.ts.map +0 -1
- package/dist/wire-request.js.map +0 -1
- /package/dist/{did.d.ts → did/did.d.ts} +0 -0
- /package/dist/{identity-bindings.d.ts → stack/identity-bindings.d.ts} +0 -0
package/dist/record-id.js
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Record ID and clock-field validation
|
|
3
|
-
* -------------------------------------------------------
|
|
4
|
-
* The rules a caller-supplied `id`, `parentId`, `createdAt` or `updatedAt`
|
|
5
|
-
* is held to before any of them reaches storage. A client may mint its own
|
|
6
|
-
* id and backdate a record's clock, so both are untrusted input here even
|
|
7
|
-
* when the types say otherwise.
|
|
8
|
-
*
|
|
9
|
-
* See docs/spec/data-model.md § Record IDs.
|
|
10
|
-
*/
|
|
11
|
-
import { isValidIdFormat, idTimestamp, MAX_ID_TIMESTAMP } from './id.js';
|
|
12
|
-
import { StackBadRequestError, StackValidationError } from './errors.js';
|
|
13
|
-
// -------------------------------------------------------
|
|
14
|
-
// Record ID validation
|
|
15
|
-
// -------------------------------------------------------
|
|
16
|
-
const RESERVED_ID_PREFIX = '_';
|
|
17
|
-
export const DEFAULT_ID_TIMESTAMP_SKEW_MS = 24 * 60 * 60 * 1000;
|
|
18
|
-
/**
|
|
19
|
-
* The same format rule applied to a `parentId` a caller names. Separate
|
|
20
|
-
* from validateRecordId() only for its message: the id under discussion is
|
|
21
|
-
* the destination, not the record being written, and a shared message would
|
|
22
|
-
* report the wrong one. See docs/spec/data-model.md § Reparenting.
|
|
23
|
-
*/
|
|
24
|
-
export function validateParentId(parentId) {
|
|
25
|
-
if (parentId.startsWith(RESERVED_ID_PREFIX)) {
|
|
26
|
-
throw new StackBadRequestError(`Invalid parentId "${parentId}": uses the reserved "${RESERVED_ID_PREFIX}" prefix.`);
|
|
27
|
-
}
|
|
28
|
-
if (!isValidIdFormat(parentId)) {
|
|
29
|
-
throw new StackBadRequestError(`Invalid parentId "${parentId}": expected 12 lowercase Crockford base-32 characters.`);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Format and reserved-prefix checks — full-trust context (Stack.create()).
|
|
34
|
-
* Checked before the format check: the Crockford charset already excludes
|
|
35
|
-
* "_", so a reserved-looking id (e.g. "_config") would otherwise just fail
|
|
36
|
-
* as a generic format error instead of a specific, actionable one.
|
|
37
|
-
*
|
|
38
|
-
* Throws StackBadRequestError, not StackValidationError: a malformed id is
|
|
39
|
-
* structurally bad input the request never gets past — it doesn't reach
|
|
40
|
-
* type-schema validation — the same reasoning that makes an undecodable
|
|
41
|
-
* pagination cursor a StackBadRequestError rather than a content-validation
|
|
42
|
-
* failure. See StackBadRequestError's doc comment.
|
|
43
|
-
*/
|
|
44
|
-
export function validateRecordId(id) {
|
|
45
|
-
if (id.startsWith(RESERVED_ID_PREFIX)) {
|
|
46
|
-
throw new StackBadRequestError(`ID "${id}" uses the reserved "${RESERVED_ID_PREFIX}" prefix.`);
|
|
47
|
-
}
|
|
48
|
-
if (!isValidIdFormat(id)) {
|
|
49
|
-
throw new StackBadRequestError(`Invalid ID "${id}": expected 12 lowercase Crockford base-32 characters.`);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Validity and range check for the backdating options on unscoped
|
|
54
|
-
* Stack.create(). A Date is only as good as what the caller parsed it
|
|
55
|
-
* from, and the two failure modes both need catching here rather than
|
|
56
|
-
* downstream:
|
|
57
|
-
*
|
|
58
|
-
* - **Invalid Date** (`new Date('13/45/2020')` off a malformed import row)
|
|
59
|
-
* has a NaN getTime(), and every comparison against NaN is false — so an
|
|
60
|
-
* unchecked Invalid Date passes the updatedAt/createdAt ordering check
|
|
61
|
-
* and the id/createdAt skew check by turning them off, mints the
|
|
62
|
-
* epoch-zero ID `000000000xxx`, and persists a record whose
|
|
63
|
-
* `createdAt.toISOString()` throws RangeError in serializeRecord() —
|
|
64
|
-
* making that record, and any wire response containing it,
|
|
65
|
-
* permanently unreadable.
|
|
66
|
-
* - **Out of encodable range** — before 1970 crockford32Encode() throws a
|
|
67
|
-
* bare RangeError from deep inside the ID encoder, and past
|
|
68
|
-
* MAX_ID_TIMESTAMP the derived ID silently grows to 13 characters and
|
|
69
|
-
* fails isValidIdFormat().
|
|
70
|
-
*
|
|
71
|
-
* Checked at the door for both, as a StackValidationError naming the
|
|
72
|
-
* field. Applies whether or not an `id` is supplied: a clock field outside
|
|
73
|
-
* this range is unrepresentable regardless of where the ID came from.
|
|
74
|
-
*/
|
|
75
|
-
export function validateClockField(value, path) {
|
|
76
|
-
if (value === undefined)
|
|
77
|
-
return [];
|
|
78
|
-
// Type-checked callers always pass a Date, but this option is
|
|
79
|
-
// reachable from the wire: JSON has no Date, so a server that forwards a
|
|
80
|
-
// parsed `POST /records` body hands us the ISO *string* it deserialized.
|
|
81
|
-
// Without this the very next line is `"2020-…".getTime()` — an unhandled
|
|
82
|
-
// TypeError, a 500 where the caller should have got a 400 naming the
|
|
83
|
-
// field.
|
|
84
|
-
if (!(value instanceof Date)) {
|
|
85
|
-
return [{ path, message: `${path} must be a Date.` }];
|
|
86
|
-
}
|
|
87
|
-
const ms = value.getTime();
|
|
88
|
-
if (Number.isNaN(ms)) {
|
|
89
|
-
return [{ path, message: `${path} is not a valid Date.` }];
|
|
90
|
-
}
|
|
91
|
-
if (ms < 0 || ms > MAX_ID_TIMESTAMP) {
|
|
92
|
-
return [
|
|
93
|
-
{
|
|
94
|
-
path,
|
|
95
|
-
message: `${path} is outside the representable range ` +
|
|
96
|
-
`(1970-01-01T00:00:00.000Z…${new Date(MAX_ID_TIMESTAMP).toISOString()}).`,
|
|
97
|
-
},
|
|
98
|
-
];
|
|
99
|
-
}
|
|
100
|
-
return [];
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Timestamp-prefix plausibility check, shared by callers that compare an
|
|
104
|
-
* ID's embedded millisecond against a different reference each:
|
|
105
|
-
* ScopedStack.create() against the current time for any non-backdated
|
|
106
|
-
* create (a grantee is untrusted and could otherwise mint an ID that
|
|
107
|
-
* forges its sort position, and this is the one check standing between a
|
|
108
|
-
* delegated or grantee caller and doing so), and Stack.create() — reached
|
|
109
|
-
* directly when unscoped, or via ScopedStack.create() when the requester
|
|
110
|
-
* is the owner acting alone with an explicit `createdAt` — against that
|
|
111
|
-
* `createdAt` instead (the two must agree, not silently diverge — see
|
|
112
|
-
* docs/spec/data-model.md § Record IDs). Pass null to disable.
|
|
113
|
-
*/
|
|
114
|
-
export function validateIdTimestampSkew(id, toleranceMs, referenceMs, referenceLabel) {
|
|
115
|
-
if (toleranceMs === null)
|
|
116
|
-
return;
|
|
117
|
-
const skew = Math.abs(referenceMs - idTimestamp(id));
|
|
118
|
-
if (skew > toleranceMs) {
|
|
119
|
-
throw new StackValidationError([
|
|
120
|
-
{
|
|
121
|
-
path: 'id',
|
|
122
|
-
message: `ID "${id}" timestamp disagrees with ${referenceLabel} by more than the allowed clock-skew tolerance (${toleranceMs}ms).`,
|
|
123
|
-
},
|
|
124
|
-
]);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
//# sourceMappingURL=record-id.js.map
|
package/dist/record-id.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"record-id.js","sourceRoot":"","sources":["../src/record-id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGzE,0DAA0D;AAC1D,uBAAuB;AACvB,0DAA0D;AAE1D,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAC/B,MAAM,CAAC,MAAM,4BAA4B,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEhE;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,IAAI,QAAQ,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,oBAAoB,CAC5B,qBAAqB,QAAQ,yBAAyB,kBAAkB,WAAW,CACpF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,oBAAoB,CAC5B,qBAAqB,QAAQ,wDAAwD,CACtF,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAAU;IACzC,IAAI,EAAE,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,oBAAoB,CAAC,OAAO,EAAE,wBAAwB,kBAAkB,WAAW,CAAC,CAAC;IACjG,CAAC;IACD,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,oBAAoB,CAC5B,eAAe,EAAE,wDAAwD,CAC1E,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAuB,EAAE,IAAY;IACtE,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACnC,8DAA8D;IAC9D,yEAAyE;IACzE,yEAAyE;IACzE,yEAAyE;IACzE,qEAAqE;IACrE,SAAS;IACT,IAAI,CAAC,CAAC,KAAK,YAAY,IAAI,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,kBAAkB,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;IAC3B,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;QACrB,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,uBAAuB,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,gBAAgB,EAAE,CAAC;QACpC,OAAO;YACL;gBACE,IAAI;gBACJ,OAAO,EACL,GAAG,IAAI,sCAAsC;oBAC7C,6BAA6B,IAAI,IAAI,CAAC,gBAAgB,CAAC,CAAC,WAAW,EAAE,IAAI;aAC5E;SACF,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,uBAAuB,CACrC,EAAU,EACV,WAA0B,EAC1B,WAAmB,EACnB,cAAsB;IAEtB,IAAI,WAAW,KAAK,IAAI;QAAE,OAAO;IACjC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;IACrD,IAAI,IAAI,GAAG,WAAW,EAAE,CAAC;QACvB,MAAM,IAAI,oBAAoB,CAAC;YAC7B;gBACE,IAAI,EAAE,IAAI;gBACV,OAAO,EAAE,OAAO,EAAE,8BAA8B,cAAc,mDAAmD,WAAW,MAAM;aACnI;SACF,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
|
package/dist/scoped-stack.d.ts
DELETED
|
@@ -1,532 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ScopedStack — the permission-enforcing view
|
|
3
|
-
* -------------------------------------------------------
|
|
4
|
-
* A `Stack` answers every question; a `ScopedStack` answers only the ones a
|
|
5
|
-
* particular requester is entitled to. It wraps a Stack rather than an
|
|
6
|
-
* adapter, so every invariant the Stack layer holds is already in force by
|
|
7
|
-
* the time a check here runs, and the gates below only ever narrow.
|
|
8
|
-
*
|
|
9
|
-
* Two identities, one rule: **the principal governs authority, the subject
|
|
10
|
-
* governs attribution.** Both are DIDs and both are often equal, which is
|
|
11
|
-
* what makes them easy to confuse — so the split is stated on every gate
|
|
12
|
-
* that depends on it.
|
|
13
|
-
*
|
|
14
|
-
* Also holds the feed side of the same rule: a subscription's deliveries
|
|
15
|
-
* run through the same canRead() a get() answers with, so a feed can never
|
|
16
|
-
* disagree with a read about what a session sees.
|
|
17
|
-
*
|
|
18
|
-
* See docs/spec/access-control.md and docs/spec/events.md § Permission scoping.
|
|
19
|
-
*/
|
|
20
|
-
import { ChangeEmitter } from './changes.js';
|
|
21
|
-
import type { PutAttachmentOptions, AssociationEdit, AttachmentContent, AuthorityAssociation, DataAssociation, EntityId, FileId, QueryResult, RecordChange, RecordId, RecordVersion, RecordJournalEntry, JournalQuery, VersionsQuery, StackAdapter, StackCapabilities, IfVersionOptions, StackQuery, StackRecord, SubscribeOptions, TypeId, Unsubscribe, RecordChangeSet } from './types.js';
|
|
22
|
-
import type { ContentOf, PatchOf, ReadonlyTypeSchema, TypedChange, TypedChangeSet, TypedQuery, TypedSubscribeOptions, TypedRecord, TypeHandle } from './type-handle.js';
|
|
23
|
-
import type { Stack, BackdatableCreateRecordOptions, CollectAttachmentGarbageOptions, CollectAttachmentGarbageResult, DeleteAndReturnResult, DeleteRecordOptions, DeleteResult, GetRecordOptions, StackClient } from './stack.js';
|
|
24
|
-
/**
|
|
25
|
-
* Held by Stack alone: the index re-exports ScopedStack but not this, so
|
|
26
|
-
* asEntity()/asActor() stay the only way to one, and the actor
|
|
27
|
-
* normalization and open-check they run can't be skipped.
|
|
28
|
-
*/
|
|
29
|
-
export declare const scopeToken: unique symbol;
|
|
30
|
-
/** Everything a ScopedStack borrows from the Stack that scoped it. */
|
|
31
|
-
export type ScopedStackInit = {
|
|
32
|
-
stack: Stack;
|
|
33
|
-
principalId: EntityId | null;
|
|
34
|
-
subjectId: EntityId | null;
|
|
35
|
-
idTimestampSkewMs: number | null;
|
|
36
|
-
/**
|
|
37
|
-
* Bytes-storage primitive for putAttachment(), which composes bytes with
|
|
38
|
-
* its own create() so the record carries the subject and principal as
|
|
39
|
-
* `createdBy` — neither of which the adapter-level atomic capability takes.
|
|
40
|
-
*/
|
|
41
|
-
adapter: StackAdapter;
|
|
42
|
-
/** The stack's own unfiltered stream, which subscribe() narrows. */
|
|
43
|
-
changes: ChangeEmitter;
|
|
44
|
-
assertOpen: () => void;
|
|
45
|
-
/** Whether changes reach the stack from elsewhere — see subscribe(). */
|
|
46
|
-
relaysChanges: boolean;
|
|
47
|
-
};
|
|
48
|
-
/**
|
|
49
|
-
* A permission-enforcing view of a Stack for a single (principal, subject)
|
|
50
|
-
* pair, obtained via `stack.asEntity(entityId)`. A record the request
|
|
51
|
-
* cannot read answers exactly as a missing one does — null on reads,
|
|
52
|
-
* StackNotFoundError on the verbs that name one — so only a requester who
|
|
53
|
-
* could have read it is told a refusal was about access.
|
|
54
|
-
* See docs/spec/disclosure.md § Which refusal a Record answers with.
|
|
55
|
-
*
|
|
56
|
-
* Which identity each gate keys on follows the module comment's rule.
|
|
57
|
-
* Grant lookup and the privilege-bearing gates no grant reaches
|
|
58
|
-
* (resharing, group management, purge, widening access at create
|
|
59
|
-
* time) key on `principalId`; authorship, `-own` matching,
|
|
60
|
-
* record-level permission resolution and "files I uploaded" lookups key on
|
|
61
|
-
* `subjectId`. Unconditional owner access splits the same way: an
|
|
62
|
-
* owner subject resolves past every permission check, an owner principal
|
|
63
|
-
* is not bounded by grants, and under delegation both halves apply.
|
|
64
|
-
*/
|
|
65
|
-
export declare class ScopedStack implements StackClient {
|
|
66
|
-
#private;
|
|
67
|
-
private readonly stack;
|
|
68
|
-
private readonly idTimestampSkewMs;
|
|
69
|
-
private readonly adapter;
|
|
70
|
-
private readonly changes;
|
|
71
|
-
private readonly assertStackOpen;
|
|
72
|
-
private readonly relaysChanges;
|
|
73
|
-
/** Not callable from outside the package — see ScopedStackInit. */
|
|
74
|
-
constructor(token: typeof scopeToken, init: ScopedStackInit);
|
|
75
|
-
/**
|
|
76
|
-
* The identity whose authority this view acts with; `null` when
|
|
77
|
-
* anonymous. See docs/spec/access-control.md § Delegation: principal and subject.
|
|
78
|
-
*/
|
|
79
|
-
get principalId(): EntityId | null;
|
|
80
|
-
/**
|
|
81
|
-
* The identity this view acts for and attributes writes to; `null` when
|
|
82
|
-
* anonymous. Equal to `principalId` unless an app is acting for a user.
|
|
83
|
-
*/
|
|
84
|
-
get subjectId(): EntityId | null;
|
|
85
|
-
get capabilities(): StackCapabilities;
|
|
86
|
-
private resolveRecord;
|
|
87
|
-
/** Every `_grant` Record — see loadGrantRecords(). */
|
|
88
|
-
private loadGrants;
|
|
89
|
-
/** Whether a delegated app is acting for someone other than itself. */
|
|
90
|
-
private get delegated();
|
|
91
|
-
/**
|
|
92
|
-
* Whether any grant could name this request — the one question every
|
|
93
|
-
* prefetch asks before scanning the `_grant` family, since an anonymous
|
|
94
|
-
* requester is reached by none. Both identities are read: `asEntity()`
|
|
95
|
-
* refuses an anonymous principal acting for a subject, so they are null
|
|
96
|
-
* together, and saying so costs nothing.
|
|
97
|
-
*/
|
|
98
|
-
private get identified();
|
|
99
|
-
/**
|
|
100
|
-
* Who this request is, for stamping onto whatever it mutates. Attribution
|
|
101
|
-
* follows record-level authorship: the subject is the actor, and the
|
|
102
|
-
* principal is named beside it only when the two differ.
|
|
103
|
-
* See docs/spec/data-model.md § Authorship and attribution.
|
|
104
|
-
*/
|
|
105
|
-
private get requester();
|
|
106
|
-
private get actor();
|
|
107
|
-
/**
|
|
108
|
-
* Whether unconditional owner authority applies — the owner acting as
|
|
109
|
-
* itself. The verbs that rest on it are irreversible or disclose the
|
|
110
|
-
* sharing graph, so delegation never carries one to a subject, whichever
|
|
111
|
-
* side the owner is on. Shared with the predicate a server applies to a
|
|
112
|
-
* session, which decides the same tier one step earlier. See
|
|
113
|
-
* docs/spec/access-control.md § Delegation: principal and subject.
|
|
114
|
-
*/
|
|
115
|
-
private get ownerActingAlone();
|
|
116
|
-
/** Refuse anything but the owner acting as itself — see ownerActingAlone. */
|
|
117
|
-
private requireOwnerActingAlone;
|
|
118
|
-
private checkRead;
|
|
119
|
-
private checkWrite;
|
|
120
|
-
/**
|
|
121
|
-
* Whether `grantee` holds a _grant covering one of `actions` for the
|
|
122
|
-
* type's family (grants match by baseId, so a version bump never orphans
|
|
123
|
-
* one). -own actions additionally require the author to be `grantee`,
|
|
124
|
-
* unless `matchOwn` is false — on the principal side of a delegated
|
|
125
|
-
* request the suffix reads as the bare verb, since which records are
|
|
126
|
-
* reachable is the subject's business. `allowDefault` decides whether a
|
|
127
|
-
* grant naming nobody counts.
|
|
128
|
-
*
|
|
129
|
-
* Reached only through subjectAllows()/principalAllows(), which fix those
|
|
130
|
-
* two flags per side. Call one of those instead.
|
|
131
|
-
*/
|
|
132
|
-
private hasGrant;
|
|
133
|
-
/**
|
|
134
|
-
* The principal half of a delegated request's authority: does the app
|
|
135
|
-
* hold any grant permitting these verbs on this type at all. Bounds what
|
|
136
|
-
* the subject's own authority can reach through it, so a powerful app
|
|
137
|
-
* can never lend its reach to a weaker subject — nor the reverse.
|
|
138
|
-
* Vacuously true when there's no delegation, where the principal and
|
|
139
|
-
* subject checks would be the same question asked twice.
|
|
140
|
-
*
|
|
141
|
-
* Neither default nor group-targeted grants count here. "Any
|
|
142
|
-
* authenticated entity" is about people who turn up, not software the
|
|
143
|
-
* owner installed; and a roster is editable by any of the group's admins,
|
|
144
|
-
* so authority reaching a principal through one would let someone other
|
|
145
|
-
* than the owner name an app to a type.
|
|
146
|
-
*/
|
|
147
|
-
private principalAllows;
|
|
148
|
-
/**
|
|
149
|
-
* The subject half: which records are reachable, answered with `-own`
|
|
150
|
-
* matching and default grants both in force — the ordinary reading of a
|
|
151
|
-
* grant, since the subject is the entity a grant is written about.
|
|
152
|
-
*
|
|
153
|
-
* Paired with principalAllows() so that the two halves of the
|
|
154
|
-
* intersection are the only callers of hasGrant(): its flags differ per
|
|
155
|
-
* side and mean nothing on their own, so no call site sets them by hand.
|
|
156
|
-
*/
|
|
157
|
-
private subjectAllows;
|
|
158
|
-
/**
|
|
159
|
-
* How to refuse a record this request addressed by ID. A requester who
|
|
160
|
-
* can read the record is told it exists and the verb was refused;
|
|
161
|
-
* everyone else is told what a missing ID is told, so no one learns an ID
|
|
162
|
-
* is live who could not have learned it by reading. `message` therefore
|
|
163
|
-
* only ever reaches someone holding the record already.
|
|
164
|
-
* See docs/spec/disclosure.md § Which refusal a Record answers with.
|
|
165
|
-
*/
|
|
166
|
-
private denialFor;
|
|
167
|
-
private canRead;
|
|
168
|
-
private checkCreateGrant;
|
|
169
|
-
/**
|
|
170
|
-
* `_group` records are managed, not merely written: only the owner or an
|
|
171
|
-
* `admin` roster holder may mutate them — ordinary write permissions and
|
|
172
|
-
* grants don't apply. Asked of both identities under delegation, like
|
|
173
|
-
* a reshare. See docs/spec/identity.md § Group.
|
|
174
|
-
*/
|
|
175
|
-
private isGroupManager;
|
|
176
|
-
/** Whether one identity, on its own, manages `record` — see isGroupManager(). */
|
|
177
|
-
private managesGroup;
|
|
178
|
-
/**
|
|
179
|
-
* Fetch a record the subject can reach and the principal holds `update` on
|
|
180
|
-
* (via permissions or an update grant), or throw. `mutating: false` marks
|
|
181
|
-
* the history readers, which borrow this gate without changing anything —
|
|
182
|
-
* the one way through it a `_grant` Record stays open to.
|
|
183
|
-
*/
|
|
184
|
-
private requireUpdatable;
|
|
185
|
-
/**
|
|
186
|
-
* The write gate both requireUpdatable() and requireDeletable() are: the
|
|
187
|
-
* subject can reach the record (record-level permission or a grant) and
|
|
188
|
-
* the principal holds the same verb, intersected — or, for a `_group`, the
|
|
189
|
-
* stricter management rule that no grant reaches.
|
|
190
|
-
* See docs/spec/access-control.md § Delegation: principal and subject.
|
|
191
|
-
*/
|
|
192
|
-
private requireVerb;
|
|
193
|
-
/**
|
|
194
|
-
* Fetch a record the subject can reach and the principal holds `delete` on
|
|
195
|
-
* (via permissions or a delete grant), or throw.
|
|
196
|
-
*/
|
|
197
|
-
private requireDeletable;
|
|
198
|
-
/**
|
|
199
|
-
* Whether this request may reference `recordId` (as a parentId or
|
|
200
|
-
* relationship target). Missing and unreadable both return false —
|
|
201
|
-
* indistinguishable, so this can't probe for a record's existence.
|
|
202
|
-
*
|
|
203
|
-
* The owner acting alone passes without the lookup: there is no record in
|
|
204
|
-
* their own stack they may not read, so the gate could only refuse them
|
|
205
|
-
* for absence — which is `Stack`'s to answer, with a conflict that names
|
|
206
|
-
* the problem. See docs/spec/access-control.md § Reference-creation gating.
|
|
207
|
-
*/
|
|
208
|
-
private canReadReferent;
|
|
209
|
-
/**
|
|
210
|
-
* Whether this request can read some record referencing `fileId` —
|
|
211
|
-
* shared by canAccessFile() and the non-owner _attachment@1 create()
|
|
212
|
-
* carve-out, which deliberately excludes the uploader clause.
|
|
213
|
-
* `_attachment@1` records never match: the carve-out has to be satisfied
|
|
214
|
-
* by some *other* record referencing the file, or one successful guess
|
|
215
|
-
* would unlock unlimited further metadata records for the same fileId.
|
|
216
|
-
* See docs/spec/attachments.md § Creating `_attachment@1` records directly.
|
|
217
|
-
*/
|
|
218
|
-
private hasReadableReference;
|
|
219
|
-
/**
|
|
220
|
-
* Whether this request may reference or download `fileId` — the dual of
|
|
221
|
-
* getAttachment()'s access rule. Nonexistent and inaccessible are
|
|
222
|
-
* indistinguishable (both false), so no confirmation oracle for guessed
|
|
223
|
-
* hashes. See docs/spec/access-control.md § Reference-creation gating.
|
|
224
|
-
*/
|
|
225
|
-
private canAccessFile;
|
|
226
|
-
/** Names of the type's top-level file-ref fields — the content-reference half of referencesFileId matching. */
|
|
227
|
-
private fileRefFieldNames;
|
|
228
|
-
/**
|
|
229
|
-
* Gates file-ref content fields on file access, mirroring the
|
|
230
|
-
* attachment-association gate — a file-ref field conveys attachment
|
|
231
|
-
* access exactly like an `attachment` association. Only fields present
|
|
232
|
-
* in `content` are checked (a content patch is a merge patch; untouched fields
|
|
233
|
-
* carry no new reference).
|
|
234
|
-
*/
|
|
235
|
-
private requireFileRefAccess;
|
|
236
|
-
/**
|
|
237
|
-
* Reference-creation gate for one association: `attachment` requires
|
|
238
|
-
* file access, and a `relationship` naming a record in this stack
|
|
239
|
-
* requires read access to it. `tag` is unchecked, and `_group` roster
|
|
240
|
-
* associations are gated by the stricter isGroupManager() instead.
|
|
241
|
-
*
|
|
242
|
-
* The other target arms are ungated because the gate's purpose —
|
|
243
|
-
* refusing a reference that would convey access to, or confirm the
|
|
244
|
-
* existence of, an unreadable record — has nothing to bite on: core
|
|
245
|
-
* never resolves them, so no access flows through one.
|
|
246
|
-
* See docs/spec/access-control.md § Reference-creation gating.
|
|
247
|
-
*/
|
|
248
|
-
private requireAssociationAccess;
|
|
249
|
-
/**
|
|
250
|
-
* Create a record on behalf of the subject: create grant required,
|
|
251
|
-
* anonymous denied, `createdBy` set to the requester, client IDs skew-checked,
|
|
252
|
-
* reference-creating options gated, and non-owner `_attachment@1`
|
|
253
|
-
* creation refused save one carve-out. A scoped create always stamps
|
|
254
|
-
* authorship — an absent `createdBy` means an unscoped `Stack` wrote it.
|
|
255
|
-
* `createdAt`/`updatedAt` are refused to everyone but the owner acting
|
|
256
|
-
* alone, rather than dropped, so an app never believes it published
|
|
257
|
-
* something it didn't. See docs/spec/access-control.md and
|
|
258
|
-
* docs/spec/data-model.md § Record IDs.
|
|
259
|
-
*/
|
|
260
|
-
create<S extends ReadonlyTypeSchema>(handle: TypeHandle<S>, content: ContentOf<S>, opts?: BackdatableCreateRecordOptions): Promise<TypedRecord<S>>;
|
|
261
|
-
create<T extends Record<string, unknown> = Record<string, unknown>>(typeId: TypeId, content: T, opts?: BackdatableCreateRecordOptions): Promise<StackRecord & {
|
|
262
|
-
content: T;
|
|
263
|
-
}>;
|
|
264
|
-
/**
|
|
265
|
-
* Whether this request may decide who else reaches a record — the rule
|
|
266
|
-
* a reshare enforces, asked at create time too so the reach it
|
|
267
|
-
* withholds can't be taken one step earlier while authoring. A delegated
|
|
268
|
-
* app is denied it: widening access is the one thing containment most
|
|
269
|
-
* needs to hold. Refused rather than silently ignored, so an app never
|
|
270
|
-
* believes it published something it didn't. Not `ownerActingAlone`:
|
|
271
|
-
* the record is the subject's own, so an owner principal grants it no
|
|
272
|
-
* reach the subject lacks.
|
|
273
|
-
* See docs/spec/access-control.md § Delegation: principal and subject.
|
|
274
|
-
*/
|
|
275
|
-
private mayGrantAccess;
|
|
276
|
-
/**
|
|
277
|
-
* Whether one identity, on its own, may decide who else reaches `record`
|
|
278
|
-
* — the owner-or-creator rule a reshare enforces, asked of one
|
|
279
|
-
* side at a time. See
|
|
280
|
-
* docs/spec/access-control.md § Delegation: principal and subject.
|
|
281
|
-
*/
|
|
282
|
-
private mayReshare;
|
|
283
|
-
/**
|
|
284
|
-
* A record this request may read, or null. Never throws
|
|
285
|
-
* StackPermissionError: an unreadable record answers exactly as a missing
|
|
286
|
-
* one does, so a caller learns only what it may read.
|
|
287
|
-
* See docs/spec/disclosure.md § Which refusal a Record answers with.
|
|
288
|
-
*/
|
|
289
|
-
get<S extends ReadonlyTypeSchema>(handle: TypeHandle<S>, id: RecordId): Promise<TypedRecord<S> | null>;
|
|
290
|
-
get(id: RecordId, opts?: GetRecordOptions): Promise<StackRecord | null>;
|
|
291
|
-
/**
|
|
292
|
-
* Runs through this.query(), so canRead() still applies — this answers a
|
|
293
|
-
* question the caller asks on its own behalf. includeUnlisted is passed
|
|
294
|
-
* only when the request is the owner acting alone, per
|
|
295
|
-
* docs/spec/identity.md § DID bindings.
|
|
296
|
-
*/
|
|
297
|
-
getEntityByDid(did: EntityId): Promise<StackRecord | null>;
|
|
298
|
-
getOwnerEntity(): Promise<StackRecord | null>;
|
|
299
|
-
/**
|
|
300
|
-
* Query records, filtered to those this request can read. Pages are
|
|
301
|
-
* filtered then refilled, so a page may slightly overshoot `limit` but
|
|
302
|
-
* never skips a record. Grants are prefetched once, cursor-walked to
|
|
303
|
-
* exhaustion.
|
|
304
|
-
*/
|
|
305
|
-
query<S extends ReadonlyTypeSchema>(handle: TypeHandle<S>, query?: TypedQuery): Promise<{
|
|
306
|
-
records: TypedRecord<S>[];
|
|
307
|
-
cursor: string | null;
|
|
308
|
-
}>;
|
|
309
|
-
query(query?: StackQuery): Promise<QueryResult>;
|
|
310
|
-
/**
|
|
311
|
-
* Apply a change set on behalf of the subject. Authority is resolved
|
|
312
|
-
* **per key** and every gate reads the record as it stands, never as the
|
|
313
|
-
* change set would leave it: a widened `permissions` never satisfies the
|
|
314
|
-
* read check on a `parentId` named in the same call, and a `_group`
|
|
315
|
-
* roster never satisfies the admin check that same call has to pass.
|
|
316
|
-
* One refused key refuses the whole call, so nothing is partially
|
|
317
|
-
* applied and no key is silently dropped.
|
|
318
|
-
* See docs/spec/access-control.md § Composing a change set.
|
|
319
|
-
*/
|
|
320
|
-
mutate<S extends ReadonlyTypeSchema>(handle: TypeHandle<S>, id: RecordId, changes: TypedChangeSet<S>, opts?: IfVersionOptions): Promise<TypedRecord<S>>;
|
|
321
|
-
mutate(id: RecordId, changes: RecordChangeSet, opts?: IfVersionOptions): Promise<StackRecord>;
|
|
322
|
-
patchContent<S extends ReadonlyTypeSchema>(handle: TypeHandle<S>, id: RecordId, patch: PatchOf<S>, opts?: IfVersionOptions): Promise<TypedRecord<S>>;
|
|
323
|
-
patchContent(id: RecordId, patch: Record<string, unknown | null>, opts?: IfVersionOptions): Promise<StackRecord>;
|
|
324
|
-
/**
|
|
325
|
-
* The record, having established that this request may decide who else
|
|
326
|
-
* reaches it — the owner-or-creator rule, asked of both sides of a
|
|
327
|
-
* delegation, or a Group's admin rule for a `_group`. The gate the
|
|
328
|
-
* `permissions` and `unlisted` keys carry, which the write bit
|
|
329
|
-
* deliberately does not confer.
|
|
330
|
-
*/
|
|
331
|
-
private requireReshareable;
|
|
332
|
-
/**
|
|
333
|
-
* Whether a change set's `permissions` key actually moves the ACL. Read
|
|
334
|
-
* off the computed delta rather than the elements the caller supplied:
|
|
335
|
-
* a gate that inspected only what was named would miss the wholesale
|
|
336
|
-
* replacement that drops everything, which names nothing at all. Any
|
|
337
|
-
* add, remove or repoint in either direction is a reshare.
|
|
338
|
-
* See docs/spec/access-control.md § Record-level permissions.
|
|
339
|
-
*/
|
|
340
|
-
private permissionsMove;
|
|
341
|
-
/** The reshare decision alone, for a record already read and write-gated. */
|
|
342
|
-
private requireReshareOf;
|
|
343
|
-
/**
|
|
344
|
-
* Whether this request may decide who else reaches `record` — the
|
|
345
|
-
* decision requireReshareOf() refuses on, without the refusal, for the
|
|
346
|
-
* read paths that project on it rather than throw.
|
|
347
|
-
*
|
|
348
|
-
* A `_group` asks management, not authorship: a creator later demoted
|
|
349
|
-
* from the admin roster shouldn't retain a side door to reassign who can
|
|
350
|
-
* read or write the group record. Everything else is intersected like
|
|
351
|
-
* every other authority here, or an owner principal would carry its
|
|
352
|
-
* subject to records the subject cannot touch.
|
|
353
|
-
*/
|
|
354
|
-
private canReshare;
|
|
355
|
-
/**
|
|
356
|
-
* Naming the software behind a key is the trust decision the `_app`
|
|
357
|
-
* registry exists to record, so both halves of that binding — `did` and
|
|
358
|
-
* `appId` — belong to the owner alone. Without this, record-level `write`
|
|
359
|
-
* on a card would be a second way in: one carrying no DID yet could be
|
|
360
|
-
* pointed at a write-holder's own key, or relabelled to claim another
|
|
361
|
-
* app's `appId`. `name` and `version` stay writable — display, not lookup.
|
|
362
|
-
*
|
|
363
|
-
* Owner *acting alone*, in both directions, or the same route reopens
|
|
364
|
-
* from the subject's side. `_entity` deliberately does not get this rule:
|
|
365
|
-
* naming people is what a contacts app does, so its cards stay writable
|
|
366
|
-
* by grant. See docs/spec/identity.md § DID bindings.
|
|
367
|
-
*/
|
|
368
|
-
private requireOwnerForAppIdentity;
|
|
369
|
-
/**
|
|
370
|
-
* A self-reported `appId` must agree with the `_app` card naming the
|
|
371
|
-
* principal's DID, where the owner registered one: `principalId` is
|
|
372
|
-
* verified, so letting the pair disagree would leave a verified principal
|
|
373
|
-
* claiming a name the owner gave different software. A principal with no
|
|
374
|
-
* card keeps `appId` as the bare self-report it is for every undelegated
|
|
375
|
-
* writer. See docs/spec/identity.md § Attribution and what can be trusted.
|
|
376
|
-
*/
|
|
377
|
-
private requireAppIdMatchesPrincipal;
|
|
378
|
-
/**
|
|
379
|
-
* The owner's own DID is the one `_entity` binding a grantee may not claim.
|
|
380
|
-
* `ownerProfile` adopts whichever card holds it, so a card minted by
|
|
381
|
-
* someone else becomes the stack's own profile, and uniqueness then makes
|
|
382
|
-
* that permanent. Every other DID stays open to a contacts app, which is
|
|
383
|
-
* the reach `_entity` is grantable for.
|
|
384
|
-
* See docs/spec/identity.md § DID bindings.
|
|
385
|
-
*/
|
|
386
|
-
private requireOwnerForOwnerDid;
|
|
387
|
-
/**
|
|
388
|
-
* A `_grant` Record *is* authority, so rewriting one is the escalation
|
|
389
|
-
* UNGRANTABLE_SYSTEM_TYPES refuses at evaluation, reached by editing an
|
|
390
|
-
* existing grant rather than minting a fresh one. `grantType()` and `revokeType()`
|
|
391
|
-
* live on `Stack`, never `StackClient`, so no scoped write is lost. Writes
|
|
392
|
-
* only: reading a grant Record and its history stays on the ordinary gate.
|
|
393
|
-
* See docs/spec/access-control.md § Type-level grants.
|
|
394
|
-
*/
|
|
395
|
-
private requireOwnerForGrantRecord;
|
|
396
|
-
/**
|
|
397
|
-
* Gated on the write bit alone, which is why the list is held to its
|
|
398
|
-
* rules first: authority reached through this verb would be exactly the
|
|
399
|
-
* escalation the partition exists to stop, decided before any record is
|
|
400
|
-
* read so it cannot depend on who is asking.
|
|
401
|
-
*/
|
|
402
|
-
associate(id: RecordId, associations: DataAssociation[]): Promise<StackRecord>;
|
|
403
|
-
/** See associate() — the same write gate, the same kind refusal. */
|
|
404
|
-
dissociate(id: RecordId, associations: DataAssociation[]): Promise<StackRecord>;
|
|
405
|
-
/**
|
|
406
|
-
* The write gate, plus the per-element reference gate on each add: what a
|
|
407
|
-
* remove names is already on the record, so it is gated by the write bit
|
|
408
|
-
* alone. See associate().
|
|
409
|
-
*/
|
|
410
|
-
amendAssociations(id: RecordId, changes: AssociationEdit[], surface?: string): Promise<StackRecord>;
|
|
411
|
-
/**
|
|
412
|
-
* Extend who reaches a record — the reshare gate's own verb, on the
|
|
413
|
-
* owner-or-creator rule the `permissions` key carries. The write bit
|
|
414
|
-
* does not confer it: a write-holder who could grant would escalate to
|
|
415
|
-
* deciding who else reaches the record, which is the whole of what
|
|
416
|
-
* scoping access is for.
|
|
417
|
-
* See docs/spec/access-control.md § Record-level permissions.
|
|
418
|
-
*/
|
|
419
|
-
grantAccess(id: RecordId, permissions: AuthorityAssociation[]): Promise<StackRecord>;
|
|
420
|
-
/** Withdraw elements of who reaches a record — see grantAccess(). */
|
|
421
|
-
revokeAccess(id: RecordId, permissions: AuthorityAssociation[]): Promise<StackRecord>;
|
|
422
|
-
/** The reshare gate over an edit list — see grantAccess(). */
|
|
423
|
-
amendAccess(id: RecordId, changes: AssociationEdit[], surface?: string): Promise<StackRecord>;
|
|
424
|
-
/**
|
|
425
|
-
* Purge is owner-only: it is irreversible and destroys version
|
|
426
|
-
* history, so neither the write bit nor delete-own/delete-any grants
|
|
427
|
-
* reach it, and delegation doesn't carry it either. Everyone else is
|
|
428
|
-
* limited to soft delete.
|
|
429
|
-
*/
|
|
430
|
-
delete(id: RecordId, opts?: DeleteRecordOptions): Promise<DeleteResult>;
|
|
431
|
-
/**
|
|
432
|
-
* delete(), plus the record it acted on. Gated identically — the
|
|
433
|
-
* existence/visibility check that produces a 404 ahead of the 403
|
|
434
|
-
* permission gate still runs via requireDeletable() before either kind
|
|
435
|
-
* of delete, so this changes what a successful call reports, not the
|
|
436
|
-
* disclosure ordering a refused one follows.
|
|
437
|
-
*/
|
|
438
|
-
deleteAndReturn(id: RecordId, opts?: DeleteRecordOptions): Promise<DeleteAndReturnResult>;
|
|
439
|
-
/**
|
|
440
|
-
* Reverse a soft delete. Gated the same as delete() — undelete is the
|
|
441
|
-
* inverse of soft delete, so granting one direction without the other
|
|
442
|
-
* would be backwards. Idempotent, per Stack.undelete().
|
|
443
|
-
*/
|
|
444
|
-
undelete(id: RecordId, opts?: IfVersionOptions): Promise<StackRecord>;
|
|
445
|
-
/**
|
|
446
|
-
* History is the mutation/recovery surface, not a read surface — gated
|
|
447
|
-
* like patchContent(). Reading it changes nothing, so it is the one path
|
|
448
|
-
* the `_grant` write fence leaves alone: seeing how a Record you can
|
|
449
|
-
* already read got that way is not the escalation that fence exists to
|
|
450
|
-
* stop. See docs/spec/versioning.md § History access.
|
|
451
|
-
*/
|
|
452
|
-
getVersions(id: RecordId, query?: VersionsQuery): Promise<RecordVersion[]>;
|
|
453
|
-
/**
|
|
454
|
-
* See getVersions() — the same mutate-surface gate, for the same reason.
|
|
455
|
-
*
|
|
456
|
-
* The journal is where a Record's sharing history lives, and that half
|
|
457
|
-
* is the resharer's: a reader who could not have moved the ACL is served
|
|
458
|
-
* the `reshare` op without the elements beneath it, so the entry
|
|
459
|
-
* still names that it moved. Asked of both identities, so delegation is
|
|
460
|
-
* no route to it either. See docs/spec/journal.md § Reading it.
|
|
461
|
-
*/
|
|
462
|
-
getJournal(id: RecordId, query?: JournalQuery): Promise<RecordJournalEntry[]>;
|
|
463
|
-
/** See getVersions() — the same mutate-surface gate. */
|
|
464
|
-
getVersion(id: RecordId, version: number): Promise<RecordVersion | null>;
|
|
465
|
-
/**
|
|
466
|
-
* Re-runs the reference-creation checks against the snapshot, so a
|
|
467
|
-
* restore can't re-convey access to a file the subject can no longer
|
|
468
|
-
* reach today. Only the owner acting alone is exempt: under delegation
|
|
469
|
-
* the checks resolve against the subject, which is whose reach the
|
|
470
|
-
* restore would widen. See docs/spec/versioning.md § Restore semantics.
|
|
471
|
-
*/
|
|
472
|
-
restoreVersion(id: RecordId, version: number, opts?: IfVersionOptions): Promise<StackRecord>;
|
|
473
|
-
/**
|
|
474
|
-
* Commit a per-record migration — **the owner acting alone, only**, the
|
|
475
|
-
* same restriction the bulk `migrateAll()` carries by living on `Stack`.
|
|
476
|
-
*
|
|
477
|
-
* Migrate replaces `content` and `typeId` wholesale, so a grant-based
|
|
478
|
-
* version would have to re-derive every gate `create()` applies at the
|
|
479
|
-
* destination *and* every gate `mutate()` applies over the existing
|
|
480
|
-
* content, reopening each one it missed. The sharpest is create()'s
|
|
481
|
-
* non-owner `_attachment@1` refusal: without it, a requester could
|
|
482
|
-
* migrate a record they authored into the family naming any `fileId` and
|
|
483
|
-
* read the bytes through canAccessFile()'s uploader clause. Ordinary
|
|
484
|
-
* write access to a record is not consent to move it between families.
|
|
485
|
-
* See docs/spec/data-model.md § Type migrations.
|
|
486
|
-
*/
|
|
487
|
-
commitMigration(id: RecordId, toTypeId: TypeId, content: Record<string, unknown>, opts?: IfVersionOptions): Promise<StackRecord>;
|
|
488
|
-
/**
|
|
489
|
-
* Store bytes and create an _attachment@1 metadata record (create grant
|
|
490
|
-
* on `_attachment@1` required; anonymous denied), returning that record.
|
|
491
|
-
* Authorship and principal are stamped exactly as create() does.
|
|
492
|
-
*/
|
|
493
|
-
putAttachment(data: Uint8Array, opts: PutAttachmentOptions): Promise<StackRecord & {
|
|
494
|
-
content: AttachmentContent;
|
|
495
|
-
}>;
|
|
496
|
-
/**
|
|
497
|
-
* Download attachment bytes. Accessible to the owner, a reader of any
|
|
498
|
-
* referencing record, or the uploader pre-association — the same
|
|
499
|
-
* predicate as the reference-creation gate (canAccessFile).
|
|
500
|
-
*/
|
|
501
|
-
getAttachment(fileId: FileId): Promise<Uint8Array>;
|
|
502
|
-
/**
|
|
503
|
-
* Delete an attachment. Only the stack owner may delete attachments.
|
|
504
|
-
* Delegates to Stack.deleteAttachment(), which enforces the "not referenced" check.
|
|
505
|
-
*/
|
|
506
|
-
deleteAttachment(fileId: FileId): Promise<void>;
|
|
507
|
-
/**
|
|
508
|
-
* Sweep for unreferenced attachment bytes and delete them. Only the stack
|
|
509
|
-
* owner may run this. Delegates to Stack.collectAttachmentGarbage().
|
|
510
|
-
*/
|
|
511
|
-
collectAttachmentGarbage(opts?: CollectAttachmentGarbageOptions): Promise<CollectAttachmentGarbageResult>;
|
|
512
|
-
/**
|
|
513
|
-
* Observe the changes this request may read. The predicate is canRead
|
|
514
|
-
* applied per event — the same one get() and query() answer with, so a
|
|
515
|
-
* feed can't disagree with them about what this session sees.
|
|
516
|
-
*
|
|
517
|
-
* A record the subscriber cannot read produces no event at all, rather
|
|
518
|
-
* than an empty or redacted one: the existence of a change is itself a
|
|
519
|
-
* disclosure, the same reasoning that keeps a count of the whole match
|
|
520
|
-
* off a query result. See docs/spec/events.md § Permission scoping.
|
|
521
|
-
*/
|
|
522
|
-
subscribe<S extends ReadonlyTypeSchema>(handle: TypeHandle<S>, handler: (change: TypedChange<S>) => void, opts?: TypedSubscribeOptions): Promise<Unsubscribe>;
|
|
523
|
-
subscribe(handler: (change: RecordChange) => void, opts?: SubscribeOptions): Promise<Unsubscribe>;
|
|
524
|
-
/**
|
|
525
|
-
* canRead for one event, through the subscription's own cache. Grants
|
|
526
|
-
* are prefetched once and refilled after an invalidation rather than
|
|
527
|
-
* re-queried per event, which would be a `_grant` scan for every change
|
|
528
|
-
* the stack makes.
|
|
529
|
-
*/
|
|
530
|
-
private canReadCached;
|
|
531
|
-
}
|
|
532
|
-
//# sourceMappingURL=scoped-stack.d.ts.map
|