@haverstack/core 0.43.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 -2
- package/dist/access.d.ts +7 -3
- package/dist/access.d.ts.map +1 -1
- package/dist/access.js +11 -2
- package/dist/access.js.map +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 +15 -8
- package/dist/adapter/combine.js.map +1 -1
- package/dist/adapter/copy.d.ts +31 -0
- package/dist/adapter/copy.d.ts.map +1 -0
- package/dist/adapter/copy.js +131 -0
- package/dist/adapter/copy.js.map +1 -0
- 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 +9 -2
- package/dist/adapter/index.d.ts.map +1 -1
- package/dist/adapter/index.js +6 -1
- package/dist/adapter/index.js.map +1 -1
- package/dist/adapter/seed.d.ts +13 -0
- package/dist/adapter/seed.d.ts.map +1 -0
- package/dist/adapter/seed.js +26 -0
- package/dist/adapter/seed.js.map +1 -0
- package/dist/errors.d.ts +18 -4
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +28 -6
- package/dist/errors.js.map +1 -1
- package/dist/grants.d.ts +16 -4
- package/dist/grants.d.ts.map +1 -1
- package/dist/grants.js +44 -16
- package/dist/grants.js.map +1 -1
- package/dist/hash.d.ts +8 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +14 -0
- package/dist/hash.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/install.d.ts +29 -5
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +69 -44
- package/dist/install.js.map +1 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +2 -5
- package/dist/schema.js.map +1 -1
- package/dist/scoped-stack/authority.d.ts +19 -14
- package/dist/scoped-stack/authority.d.ts.map +1 -1
- package/dist/scoped-stack/authority.js +30 -18
- package/dist/scoped-stack/authority.js.map +1 -1
- package/dist/scoped-stack/family-policy.js +1 -1
- package/dist/scoped-stack/family-policy.js.map +1 -1
- package/dist/scoped-stack/scoped-stack.d.ts +12 -5
- package/dist/scoped-stack/scoped-stack.d.ts.map +1 -1
- package/dist/scoped-stack/scoped-stack.js +52 -29
- package/dist/scoped-stack/scoped-stack.js.map +1 -1
- package/dist/stack/field-rules.d.ts +27 -0
- package/dist/stack/field-rules.d.ts.map +1 -0
- package/dist/stack/field-rules.js +50 -0
- package/dist/stack/field-rules.js.map +1 -0
- package/dist/stack/install-app.d.ts +2 -2
- package/dist/stack/install-app.d.ts.map +1 -1
- package/dist/stack/install-app.js +9 -9
- package/dist/stack/install-app.js.map +1 -1
- package/dist/stack/integrity.d.ts +9 -53
- package/dist/stack/integrity.d.ts.map +1 -1
- package/dist/stack/integrity.js +45 -105
- package/dist/stack/integrity.js.map +1 -1
- package/dist/stack/stack.d.ts +10 -11
- package/dist/stack/stack.d.ts.map +1 -1
- package/dist/stack/stack.js +35 -71
- package/dist/stack/stack.js.map +1 -1
- package/dist/stack/system-types.d.ts.map +1 -1
- package/dist/stack/system-types.js +1 -3
- package/dist/stack/system-types.js.map +1 -1
- package/dist/stack/type-grants.d.ts.map +1 -1
- package/dist/stack/type-grants.js +5 -2
- package/dist/stack/type-grants.js.map +1 -1
- package/dist/testing.d.ts +18 -17
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +43 -41
- package/dist/testing.js.map +1 -1
- package/dist/types/adapter.d.ts +71 -15
- package/dist/types/adapter.d.ts.map +1 -1
- package/dist/types/system.d.ts +1 -7
- package/dist/types/system.d.ts.map +1 -1
- package/dist/types/system.js.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/dist/stack/identity-bindings.d.ts +0 -13
- package/dist/stack/identity-bindings.d.ts.map +0 -1
- package/dist/stack/identity-bindings.js +0 -36
- package/dist/stack/identity-bindings.js.map +0 -1
package/README.md
CHANGED
|
@@ -34,7 +34,6 @@ const keyPath = './my-stack.key.json'; // see "Key custody" under Identity for w
|
|
|
34
34
|
const adapter = await LocalAdapter.open({
|
|
35
35
|
path: dbPath,
|
|
36
36
|
create: 'ifMissing',
|
|
37
|
-
timezone: 'America/New_York',
|
|
38
37
|
ownerEntityId: async () => {
|
|
39
38
|
const { did, privateKey } = await generateDidKeypair();
|
|
40
39
|
await writeFile(keyPath, JSON.stringify(await exportDidPrivateKeyJwk(privateKey)));
|
|
@@ -204,7 +203,7 @@ export const manifest: AppManifest = {
|
|
|
204
203
|
|
|
205
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))`.
|
|
206
205
|
|
|
207
|
-
**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).
|
|
208
207
|
|
|
209
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.
|
|
210
209
|
|
package/dist/access.d.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* it. Every tier is affirmative, so an element read past its own kind —
|
|
13
13
|
* or carrying no kind at all — confers nothing.
|
|
14
14
|
*/
|
|
15
|
-
import type { AuthorityAssociation, DataAssociation, EntityId, GroupRole, Grantee, RecordId, StackRecord } from './types/index.js';
|
|
15
|
+
import type { Actor, AuthorityAssociation, DataAssociation, EntityId, GroupRole, Grantee, RecordId, StackRecord, TypeId } from './types/index.js';
|
|
16
16
|
import type { ValidationError } from './validate.js';
|
|
17
17
|
/** Resolves a Record by ID, for walks that need no full adapter. */
|
|
18
18
|
export type RecordResolver = (id: RecordId) => Promise<StackRecord | null>;
|
|
@@ -67,8 +67,12 @@ export declare function groupRoleFromAssociations(associations: DataAssociation[
|
|
|
67
67
|
* the last. Reads associations alone, like groupRoleFromAssociations().
|
|
68
68
|
*/
|
|
69
69
|
export declare function hasGroupAdmin(associations: DataAssociation[] | undefined): boolean;
|
|
70
|
-
/**
|
|
71
|
-
|
|
70
|
+
/**
|
|
71
|
+
* The associations a create stores: as given, plus a `_group`'s creator —
|
|
72
|
+
* the owner when none is named — stamped as its first admin.
|
|
73
|
+
* See docs/spec/identity.md § Group.
|
|
74
|
+
*/
|
|
75
|
+
export declare function createAssociations(typeId: TypeId, associations: DataAssociation[] | undefined, createdBy: Actor | undefined, ownerEntityId: EntityId): DataAssociation[] | undefined;
|
|
72
76
|
/**
|
|
73
77
|
* Whether a request is the stack owner acting alone — the tier behind every
|
|
74
78
|
* unconditional owner authority. Being the owner is never sufficient on its
|
package/dist/access.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"access.d.ts","sourceRoot":"","sources":["../src/access.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"access.d.ts","sourceRoot":"","sources":["../src/access.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EACV,KAAK,EAEL,oBAAoB,EACpB,eAAe,EACf,QAAQ,EAER,SAAS,EACT,OAAO,EACP,QAAQ,EAER,WAAW,EACX,MAAM,EACP,MAAM,kBAAkB,CAAC;AAG1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,oEAAoE;AACpE,MAAM,MAAM,cAAc,GAAG,CAAC,EAAE,EAAE,QAAQ,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;AAE3E;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;AAE1E;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,oBAAoB,EAAE,CAKvE;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GACjD,OAAO,CAAC,OAAO,CAAC,CAelB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,oBAAoB,EAAE,GAAG,SAAS,EAC/C,IAAI,SAAgB,GACnB,eAAe,EAAE,CAcnB;AAED,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,EAAE,QAAQ,EAAE,SAAS,GAAG,OAAO,CAElF;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAE1D;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,eAAe,EAAE,GAAG,SAAS,EAC3C,QAAQ,EAAE,QAAQ,GACjB,SAAS,GAAG,IAAI,CASlB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,eAAe,EAAE,GAAG,SAAS,GAAG,OAAO,CAElF;AAkBD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,eAAe,EAAE,GAAG,SAAS,EAC3C,SAAS,EAAE,KAAK,GAAG,SAAS,EAC5B,aAAa,EAAE,QAAQ,GACtB,eAAe,EAAE,GAAG,SAAS,CAG/B;AAiBD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE;IAAE,SAAS,EAAE,QAAQ,GAAG,IAAI,CAAC;IAAC,WAAW,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAA;CAAE,EACpE,aAAa,EAAE,QAAQ,GACtB,OAAO,CAGT"}
|
package/dist/access.js
CHANGED
|
@@ -122,8 +122,17 @@ function isGroupAdminAssociation(association) {
|
|
|
122
122
|
association.label === 'admin' &&
|
|
123
123
|
association.target.kind === 'entity');
|
|
124
124
|
}
|
|
125
|
-
/**
|
|
126
|
-
|
|
125
|
+
/**
|
|
126
|
+
* The associations a create stores: as given, plus a `_group`'s creator —
|
|
127
|
+
* the owner when none is named — stamped as its first admin.
|
|
128
|
+
* See docs/spec/identity.md § Group.
|
|
129
|
+
*/
|
|
130
|
+
export function createAssociations(typeId, associations, createdBy, ownerEntityId) {
|
|
131
|
+
if (baseIdOf(typeId) !== SYSTEM_TYPES.GROUP)
|
|
132
|
+
return associations;
|
|
133
|
+
return stampGroupAdmin(associations, createdBy?.subjectId ?? ownerEntityId);
|
|
134
|
+
}
|
|
135
|
+
function stampGroupAdmin(associations, creator) {
|
|
127
136
|
const list = associations ?? [];
|
|
128
137
|
const alreadyAdmin = list.some((a) => isGroupAdminAssociation(a) && a.target.entityId === creator);
|
|
129
138
|
if (alreadyAdmin)
|
package/dist/access.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"access.js","sourceRoot":"","sources":["../src/access.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"access.js","sourceRoot":"","sources":["../src/access.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAehD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAcvC;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,OAAgB;IAC7C,OAAO;QACL,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE;QAC9C,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE;KAClC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAgB,EAChB,QAAkB,EAClB,IAAkD;IAElD,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC1D,MAAM,CAAC,GAAG,OAAqF,CAAC;IAChG,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,QAAQ;YACX,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC;QACjD,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,IAAI,IAAI,CAAC,UAAU,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO;gBAAE,OAAO,KAAK,CAAC;YAC1D,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO;gBAAE,OAAO,KAAK,CAAC;YAC5D,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;YACzD,OAAO,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACrC,CAAC;QACD;YACE,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CACjC,WAA+C,EAC/C,IAAI,GAAG,aAAa;IAEpB,MAAM,IAAI,GAAG,WAAW,IAAI,EAAE,CAAC;IAC/B,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACpB,IAAI,CAAC,EAAE,IAAI,KAAK,YAAY,IAAI,CAAC,CAAC,KAAK,KAAK,OAAO;YAAE,OAAO;QAC5D,IAAI,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO;QAC/E,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,GAAG,IAAI,IAAI,CAAC,GAAG;YACrB,OAAO,EACL,0PAA0P;SAC7P,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,aAAa,CAAC,IAAsB,EAAE,QAAmB;IACvE,OAAO,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC;AACjE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,MAAmB;IAC/C,OAAO,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,YAAY,CAAC,KAAK,CAAC;AACxD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CACvC,YAA2C,EAC3C,QAAkB;IAElB,IAAI,IAAI,GAAqB,IAAI,CAAC;IAClC,KAAK,MAAM,CAAC,IAAI,YAAY,IAAI,EAAE,EAAE,CAAC;QACnC,IAAI,CAAC,CAAC,IAAI,KAAK,cAAc,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC9F,IAAI,CAAC,CAAC,KAAK,KAAK,OAAO;gBAAE,OAAO,OAAO,CAAC;YACxC,IAAI,CAAC,CAAC,KAAK,KAAK,QAAQ;gBAAE,IAAI,GAAG,QAAQ,CAAC;QAC5C,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,YAA2C;IACvE,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;AAC5D,CAAC;AAED;;;;;GAKG;AACH,SAAS,uBAAuB,CAC9B,WAAwB;IAExB,OAAO,CACL,WAAW,CAAC,IAAI,KAAK,cAAc;QACnC,WAAW,CAAC,KAAK,KAAK,OAAO;QAC7B,WAAW,CAAC,MAAM,CAAC,IAAI,KAAK,QAAQ,CACrC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAc,EACd,YAA2C,EAC3C,SAA4B,EAC5B,aAAuB;IAEvB,IAAI,QAAQ,CAAC,MAAM,CAAC,KAAK,YAAY,CAAC,KAAK;QAAE,OAAO,YAAY,CAAC;IACjE,OAAO,eAAe,CAAC,YAAY,EAAE,SAAS,EAAE,SAAS,IAAI,aAAa,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,eAAe,CACtB,YAA2C,EAC3C,OAAiB;IAEjB,MAAM,IAAI,GAAG,YAAY,IAAI,EAAE,CAAC;IAChC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAC5B,CAAC,CAAC,EAAE,EAAE,CAAC,uBAAuB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,KAAK,OAAO,CACnE,CAAC;IACF,IAAI,YAAY;QAAE,OAAO,IAAI,CAAC;IAC9B,OAAO;QACL,GAAG,IAAI;QACP,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE;KACxF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAAoE,EACpE,aAAuB;IAEvB,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;IAC1F,OAAO,WAAW,KAAK,aAAa,IAAI,KAAK,CAAC,SAAS,KAAK,aAAa,CAAC;AAC5E,CAAC"}
|
|
@@ -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,
|
|
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,8 +21,9 @@ export function combineAdapters(parts) {
|
|
|
20
21
|
get ownerEntityId() {
|
|
21
22
|
return parts.record.ownerEntityId;
|
|
22
23
|
},
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
// The record half's, since writers names who writes the Records.
|
|
25
|
+
get writers() {
|
|
26
|
+
return parts.record.writers;
|
|
25
27
|
},
|
|
26
28
|
createRecord: (r, opts) => parts.record.createRecord(r, opts),
|
|
27
29
|
getRecord: (id) => parts.record.getRecord(id),
|
|
@@ -37,7 +39,6 @@ export function combineAdapters(parts) {
|
|
|
37
39
|
setAccess: (id, list, opts) => parts.record.setAccess(id, list, opts),
|
|
38
40
|
getVersions: (id, query) => parts.record.getVersions(id, query),
|
|
39
41
|
getVersion: (id, v) => parts.record.getVersion(id, v),
|
|
40
|
-
saveVersion: (id, v) => parts.record.saveVersion(id, v),
|
|
41
42
|
getJournal: (id, query) => parts.record.getJournal(id, query),
|
|
42
43
|
restoreVersion: (id, v, opts) => parts.record.restoreVersion(id, v, opts),
|
|
43
44
|
commitMigration: (id, toTypeId, content, opts) => parts.record.commitMigration(id, toTypeId, content, opts),
|
|
@@ -50,13 +51,14 @@ export function combineAdapters(parts) {
|
|
|
50
51
|
...(parts.record.deleteUnreferencedAttachmentRecords && {
|
|
51
52
|
deleteUnreferencedAttachmentRecords: (fileId, metadataBaseId) => parts.record.deleteUnreferencedAttachmentRecords(fileId, metadataBaseId),
|
|
52
53
|
}),
|
|
54
|
+
...(parts.record.importRecord && {
|
|
55
|
+
importRecord: (r, history) => parts.record.importRecord(r, history),
|
|
56
|
+
}),
|
|
53
57
|
...(parts.record.queryReadable && {
|
|
54
58
|
queryReadable: (q, reach) => parts.record.queryReadable(q, reach),
|
|
55
59
|
}),
|
|
56
|
-
// Forwarded on the same terms
|
|
57
|
-
//
|
|
58
|
-
// leave a combined stack quietly emitting only its own writes while a
|
|
59
|
-
// 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.
|
|
60
62
|
...(parts.record.subscribeChanges && {
|
|
61
63
|
subscribeChanges: (opts, handler) => parts.record.subscribeChanges(opts, handler),
|
|
62
64
|
}),
|
|
@@ -68,7 +70,12 @@ export function combineAdapters(parts) {
|
|
|
68
70
|
getBlob: (id) => parts.blob.getBlob(id),
|
|
69
71
|
deleteBlob: (id) => parts.blob.deleteBlob(id),
|
|
70
72
|
...(parts.blob.listBlobs && {
|
|
71
|
-
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()),
|
|
72
79
|
}),
|
|
73
80
|
async flush() {
|
|
74
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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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copying a stack
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* One stack, read in full from one adapter and written in full to a new
|
|
5
|
+
* store: every Record (soft-deleted and unlisted included) with its version
|
|
6
|
+
* snapshots and journal, `_config` among them as the seed the store is
|
|
7
|
+
* created from, every Type, and every blob. Each is read as the store
|
|
8
|
+
* enumerates it, never by what a Record says, so nothing is filtered on the
|
|
9
|
+
* way. Export, import and moving
|
|
10
|
+
* between storage engines are all this one call, with a different source
|
|
11
|
+
* and a different kind of store to create. Full trust, like any direct
|
|
12
|
+
* adapter access: authorship and history land as recorded, which no write
|
|
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.
|
|
18
|
+
*/
|
|
19
|
+
import type { StackAdapter, StoreSeed } from '../types/index.js';
|
|
20
|
+
/** Creates a new store from `seed`: `LocalAdapter.open({ path, seed })`, say. */
|
|
21
|
+
export type CreateStore = (seed: StoreSeed) => Promise<StackAdapter> | StackAdapter;
|
|
22
|
+
/**
|
|
23
|
+
* Copy everything `from` holds into the store `create` makes from its
|
|
24
|
+
* `_config` record and that record's history, and return that store, open.
|
|
25
|
+
* Not atomic: a failure closes the store part-written, and the caller, whose
|
|
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.
|
|
28
|
+
* See docs/spec/portability.md § Copying a stack.
|
|
29
|
+
*/
|
|
30
|
+
export declare function copyStack(from: StackAdapter, create: CreateStore): Promise<StackAdapter>;
|
|
31
|
+
//# sourceMappingURL=copy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copying a stack
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* One stack, read in full from one adapter and written in full to a new
|
|
5
|
+
* store: every Record (soft-deleted and unlisted included) with its version
|
|
6
|
+
* snapshots and journal, `_config` among them as the seed the store is
|
|
7
|
+
* created from, every Type, and every blob. Each is read as the store
|
|
8
|
+
* enumerates it, never by what a Record says, so nothing is filtered on the
|
|
9
|
+
* way. Export, import and moving
|
|
10
|
+
* between storage engines are all this one call, with a different source
|
|
11
|
+
* and a different kind of store to create. Full trust, like any direct
|
|
12
|
+
* adapter access: authorship and history land as recorded, which no write
|
|
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.
|
|
18
|
+
*/
|
|
19
|
+
import { InvalidAdapterError, OwnerMismatchError, StackConflictError } from '../errors.js';
|
|
20
|
+
import { resolveQuery } from '../query-validation.js';
|
|
21
|
+
import { SYSTEM_TYPES } from '../types/index.js';
|
|
22
|
+
/** Records read per page; any size works, as each page is written before the next is read. */
|
|
23
|
+
const PAGE_SIZE = 100;
|
|
24
|
+
/** Every Record a store holds but `_config`, which no query reaches: a store is created from it. */
|
|
25
|
+
const EVERYTHING = {
|
|
26
|
+
filter: { includeDeleted: true, includeUnlisted: true },
|
|
27
|
+
sort: { field: 'createdAt', direction: 'asc' },
|
|
28
|
+
limit: PAGE_SIZE,
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Copy everything `from` holds into the store `create` makes from its
|
|
32
|
+
* `_config` record and that record's history, and return that store, open.
|
|
33
|
+
* Not atomic: a failure closes the store part-written, and the caller, whose
|
|
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.
|
|
36
|
+
* See docs/spec/portability.md § Copying a stack.
|
|
37
|
+
*/
|
|
38
|
+
export async function copyStack(from, create) {
|
|
39
|
+
const listBlobs = from.listBlobs?.bind(from);
|
|
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();
|
|
47
|
+
const config = await from.getRecord(SYSTEM_TYPES.CONFIG);
|
|
48
|
+
if (!config)
|
|
49
|
+
refuseSource('it holds no _config record');
|
|
50
|
+
const [versions, journal] = await Promise.all([
|
|
51
|
+
from.getVersions(config.id),
|
|
52
|
+
from.getJournal(config.id),
|
|
53
|
+
]);
|
|
54
|
+
const to = await create({ config, history: { versions, journal } });
|
|
55
|
+
try {
|
|
56
|
+
const importRecord = to.importRecord?.bind(to);
|
|
57
|
+
if (!importRecord)
|
|
58
|
+
refuseTarget('it has no importRecord(), so it cannot write history');
|
|
59
|
+
const listHeld = to.listBlobs?.bind(to);
|
|
60
|
+
if (!listHeld)
|
|
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');
|
|
64
|
+
await assertNewStore(to, config.content.ownerEntityId, listHeld);
|
|
65
|
+
for (const type of await from.listTypes())
|
|
66
|
+
await to.saveType(type);
|
|
67
|
+
// Bytes before the Records that name them, as every upload writes them.
|
|
68
|
+
await copyBlobs(from, to, listBlobs);
|
|
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
|
+
}
|
|
73
|
+
return to;
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
// The failure that stopped the copy is the one to report.
|
|
77
|
+
await to.close?.().catch(() => { });
|
|
78
|
+
throw err;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function refuseSource(why) {
|
|
82
|
+
throw new InvalidAdapterError(`Cannot copy from this adapter: ${why}.`);
|
|
83
|
+
}
|
|
84
|
+
function refuseTarget(why) {
|
|
85
|
+
throw new InvalidAdapterError(`Cannot copy into the store create() returned: ${why}.`);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* A target is a store as its adapter creates one: the source's owner,
|
|
89
|
+
* checked as open() checks it, and nothing held yet — no Record, no Type, no
|
|
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.
|
|
92
|
+
*/
|
|
93
|
+
async function assertNewStore(to, ownerEntityId, listHeld) {
|
|
94
|
+
if (to.ownerEntityId !== ownerEntityId) {
|
|
95
|
+
throw new OwnerMismatchError(ownerEntityId, to.ownerEntityId, 'the store create() returned');
|
|
96
|
+
}
|
|
97
|
+
if ((await to.queryRecords(resolveQuery({ ...EVERYTHING, limit: 1 }))).records.length) {
|
|
98
|
+
refuseTarget('it already holds Records');
|
|
99
|
+
}
|
|
100
|
+
if ((await to.listTypes()).length)
|
|
101
|
+
refuseTarget('it already holds Types');
|
|
102
|
+
if ((await listHeld({ limit: 1 })).length)
|
|
103
|
+
refuseTarget('it already holds blobs');
|
|
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
|
+
}
|
|
116
|
+
async function copyRecords(from, importRecord) {
|
|
117
|
+
let cursor;
|
|
118
|
+
do {
|
|
119
|
+
const page = await from.queryRecords(resolveQuery({ ...EVERYTHING, cursor }));
|
|
120
|
+
for (const record of page.records) {
|
|
121
|
+
// One Record's history is read whole, as importRecord() takes it.
|
|
122
|
+
const [versions, journal] = await Promise.all([
|
|
123
|
+
from.getVersions(record.id),
|
|
124
|
+
from.getJournal(record.id),
|
|
125
|
+
]);
|
|
126
|
+
await importRecord(record, { versions, journal });
|
|
127
|
+
}
|
|
128
|
+
cursor = page.cursor ?? undefined;
|
|
129
|
+
} while (cursor);
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=copy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy.js","sourceRoot":"","sources":["../../src/adapter/copy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC3F,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAStD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAKjD,8FAA8F;AAC9F,MAAM,SAAS,GAAG,GAAG,CAAC;AAEtB,oGAAoG;AACpG,MAAM,UAAU,GAAe;IAC7B,MAAM,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE;IACvD,IAAI,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE;IAC9C,KAAK,EAAE,SAAS;CACjB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAkB,EAAE,MAAmB;IACrE,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7C,IAAI,CAAC,SAAS;QAAE,YAAY,CAAC,0DAA0D,CAAC,CAAC;IACzF,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC,IAAI;QAAE,YAAY,CAAC,oEAAoE,CAAC,CAAC;IAC9F,6EAA6E;IAC7E,MAAM,OAAO,GAAG,MAAM,IAAI,EAAE,CAAC;IAC7B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IACzD,IAAI,CAAC,MAAM;QAAE,YAAY,CAAC,4BAA4B,CAAC,CAAC;IACxD,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC5C,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;KAC3B,CAAC,CAAC;IACH,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IACpE,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QAC/C,IAAI,CAAC,YAAY;YAAE,YAAY,CAAC,sDAAsD,CAAC,CAAC;QACxF,MAAM,QAAQ,GAAG,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QACxC,IAAI,CAAC,QAAQ;YAAE,YAAY,CAAC,+DAA+D,CAAC,CAAC;QAC7F,IAAI,CAAC,EAAE,CAAC,IAAI;YAAE,YAAY,CAAC,0DAA0D,CAAC,CAAC;QACvF,MAAM,cAAc,CAAC,EAAE,EAAG,MAAM,CAAC,OAAyB,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;QACpF,KAAK,MAAM,IAAI,IAAI,MAAM,IAAI,CAAC,SAAS,EAAE;YAAE,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACnE,wEAAwE;QACxE,MAAM,SAAS,CAAC,IAAI,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC;QACrC,MAAM,WAAW,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,KAAK,OAAO,EAAE,CAAC;YAC/B,MAAM,IAAI,kBAAkB,CAC1B,6EAA6E,CAC9E,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,0DAA0D;QAC1D,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACnC,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,GAAW;IAC/B,MAAM,IAAI,mBAAmB,CAAC,kCAAkC,GAAG,GAAG,CAAC,CAAC;AAC1E,CAAC;AAED,SAAS,YAAY,CAAC,GAAW;IAC/B,MAAM,IAAI,mBAAmB,CAAC,iDAAiD,GAAG,GAAG,CAAC,CAAC;AACzF,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,cAAc,CAC3B,EAAgB,EAChB,aAAqB,EACrB,QAAgD;IAEhD,IAAI,EAAE,CAAC,aAAa,KAAK,aAAa,EAAE,CAAC;QACvC,MAAM,IAAI,kBAAkB,CAAC,aAAa,EAAE,EAAE,CAAC,aAAa,EAAE,6BAA6B,CAAC,CAAC;IAC/F,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,GAAG,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QACtF,YAAY,CAAC,0BAA0B,CAAC,CAAC;IAC3C,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM;QAAE,YAAY,CAAC,wBAAwB,CAAC,CAAC;IAC1E,IAAI,CAAC,MAAM,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM;QAAE,YAAY,CAAC,wBAAwB,CAAC,CAAC;AACpF,CAAC;AAED,KAAK,UAAU,SAAS,CACtB,IAAkB,EAClB,EAAgB,EAChB,SAAiD;IAEjD,IAAI,WAA+B,CAAC;IACpC,SAAS,CAAC;QACR,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QAChE,KAAK,MAAM,EAAE,MAAM,EAAE,IAAI,IAAI;YAAE,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;QAC5E,IAAI,IAAI,CAAC,MAAM,GAAG,SAAS;YAAE,OAAO;QACpC,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;IAC7C,CAAC;AACH,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,IAAkB,EAClB,YAA6D;IAE7D,IAAI,MAA0B,CAAC;IAC/B,GAAG,CAAC;QACF,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,GAAG,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QAC9E,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClC,kEAAkE;YAClE,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBAC5C,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC3B,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;aAC3B,CAAC,CAAC;YACH,MAAM,YAAY,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QACpD,CAAC;QACD,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,SAAS,CAAC;IACpC,CAAC,QAAQ,MAAM,EAAE;AACnB,CAAC"}
|
|
@@ -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,10 +7,17 @@
|
|
|
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, } 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
|
-
export { ElementSetMovedError, OwnerMismatchError, softDeletedRefusal } from '../errors.js';
|
|
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';
|
|
18
|
+
export { copyStack } from './copy.js';
|
|
19
|
+
export type { CreateStore } from './copy.js';
|
|
20
|
+
export { newStoreSeed } from './seed.js';
|
|
14
21
|
export { inReach } from './reach.js';
|
|
15
22
|
export type { ReachedRecord } from './reach.js';
|
|
16
23
|
export { assertQueryCapabilities, assertValidSort, resolveQuery, assertValidAssociationFilters, assertValidJournalQuery, assertValidVersionsQuery, filtersContent, parseContentFilterKey, } from '../query-validation.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,
|
|
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
|
@@ -8,8 +8,13 @@
|
|
|
8
8
|
* the root entry point instead: every export has exactly one home.
|
|
9
9
|
*/
|
|
10
10
|
export { sameAssociationSet } from '../associations/identity.js';
|
|
11
|
-
export { ElementSetMovedError, OwnerMismatchError, softDeletedRefusal } from '../errors.js';
|
|
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';
|
|
16
|
+
export { copyStack } from './copy.js';
|
|
17
|
+
export { newStoreSeed } from './seed.js';
|
|
13
18
|
export { inReach } from './reach.js';
|
|
14
19
|
export { assertQueryCapabilities, assertValidSort, resolveQuery, assertValidAssociationFilters, assertValidJournalQuery, assertValidVersionsQuery, filtersContent, parseContentFilterKey, } from '../query-validation.js';
|
|
15
20
|
export { contentSortEntry, contentSortKey, compareSortEntries, constantSortEntry, sortConstant, } from './sort.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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Store seeds
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* A store is created holding one Record, `_config`, which says whose stack
|
|
5
|
+
* it is. A seed is that Record with its history: fresh for a new stack, the
|
|
6
|
+
* source's own for a copy, so the one Record every store starts with is
|
|
7
|
+
* written the way every other Record is. See docs/spec/adapters.md
|
|
8
|
+
* § Construction.
|
|
9
|
+
*/
|
|
10
|
+
import type { ConfigContent, StoreSeed } from '../types/index.js';
|
|
11
|
+
/** The seed of a stack that has no past: `_config` at version 1, holding `config`. */
|
|
12
|
+
export declare function newStoreSeed(config: ConfigContent): StoreSeed;
|
|
13
|
+
//# sourceMappingURL=seed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../../src/adapter/seed.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAGlE,sFAAsF;AACtF,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,CAa7D"}
|