was-teaching-server 0.9.1 → 0.11.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/CHANGELOG.md +118 -1
- package/README.md +23 -11
- package/dist/backends/filesystem.d.ts +247 -4
- package/dist/backends/filesystem.d.ts.map +1 -1
- package/dist/backends/filesystem.js +711 -81
- package/dist/backends/filesystem.js.map +1 -1
- package/dist/backends/postgres.d.ts +240 -2
- package/dist/backends/postgres.d.ts.map +1 -1
- package/dist/backends/postgres.js +800 -42
- package/dist/backends/postgres.js.map +1 -1
- package/dist/backends/postgresSchema.d.ts.map +1 -1
- package/dist/backends/postgresSchema.js +69 -57
- package/dist/backends/postgresSchema.js.map +1 -1
- package/dist/errors.d.ts +26 -9
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +40 -12
- package/dist/errors.js.map +1 -1
- package/dist/lib/equalityIndex.d.ts +334 -0
- package/dist/lib/equalityIndex.d.ts.map +1 -0
- package/dist/lib/equalityIndex.js +552 -0
- package/dist/lib/equalityIndex.js.map +1 -0
- package/dist/lib/exportManifest.d.ts +9 -0
- package/dist/lib/exportManifest.d.ts.map +1 -1
- package/dist/lib/exportManifest.js +9 -0
- package/dist/lib/exportManifest.js.map +1 -1
- package/dist/lib/importTar.d.ts +18 -2
- package/dist/lib/importTar.d.ts.map +1 -1
- package/dist/lib/importTar.js +77 -4
- package/dist/lib/importTar.js.map +1 -1
- package/dist/lib/paths.d.ts +33 -0
- package/dist/lib/paths.d.ts.map +1 -1
- package/dist/lib/paths.js +28 -0
- package/dist/lib/paths.js.map +1 -1
- package/dist/lib/resourceFileName.d.ts +43 -0
- package/dist/lib/resourceFileName.d.ts.map +1 -1
- package/dist/lib/resourceFileName.js +63 -0
- package/dist/lib/resourceFileName.js.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +5 -2
- package/dist/plugin.js.map +1 -1
- package/dist/requests/ChunkRequest.d.ts +104 -0
- package/dist/requests/ChunkRequest.d.ts.map +1 -0
- package/dist/requests/ChunkRequest.js +396 -0
- package/dist/requests/ChunkRequest.js.map +1 -0
- package/dist/requests/CollectionRequest.d.ts +22 -5
- package/dist/requests/CollectionRequest.d.ts.map +1 -1
- package/dist/requests/CollectionRequest.js +192 -11
- package/dist/requests/CollectionRequest.js.map +1 -1
- package/dist/requests/ResourceRequest.d.ts.map +1 -1
- package/dist/requests/ResourceRequest.js +20 -0
- package/dist/requests/ResourceRequest.js.map +1 -1
- package/dist/requests/SpaceRequest.d.ts +1 -0
- package/dist/requests/SpaceRequest.d.ts.map +1 -1
- package/dist/requests/SpaceRequest.js +21 -1
- package/dist/requests/SpaceRequest.js.map +1 -1
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +21 -0
- package/dist/routes.js.map +1 -1
- package/dist/types.d.ts +165 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +19 -18
- package/src/backends/filesystem.ts +924 -75
- package/src/backends/postgres.ts +1114 -32
- package/src/backends/postgresSchema.ts +69 -57
- package/src/errors.ts +44 -12
- package/src/lib/equalityIndex.ts +769 -0
- package/src/lib/importTar.ts +107 -4
- package/src/lib/paths.ts +48 -0
- package/src/lib/resourceFileName.ts +69 -0
- package/src/plugin.ts +5 -2
- package/src/requests/ChunkRequest.ts +478 -0
- package/src/requests/CollectionRequest.ts +221 -12
- package/src/requests/ResourceRequest.ts +20 -0
- package/src/requests/SpaceRequest.ts +25 -1
- package/src/routes.ts +46 -0
- package/src/types.ts +175 -1
package/src/types.ts
CHANGED
|
@@ -41,6 +41,13 @@ import type {
|
|
|
41
41
|
BlindedIndexQuery,
|
|
42
42
|
BlindedIndexQueryPage
|
|
43
43
|
} from './lib/blindedIndex.js'
|
|
44
|
+
import type {
|
|
45
|
+
EqualityQuery,
|
|
46
|
+
EqualityQueryPage,
|
|
47
|
+
EqualityCandidate,
|
|
48
|
+
EqualityValue,
|
|
49
|
+
NormalizedIndexDeclaration
|
|
50
|
+
} from './lib/equalityIndex.js'
|
|
44
51
|
|
|
45
52
|
// The shared WAS wire model now lives in `@interop/storage-core`. Import the
|
|
46
53
|
// shapes referenced by the `StorageBackend` contract below, and re-export the
|
|
@@ -64,6 +71,17 @@ import type {
|
|
|
64
71
|
// contract (`queryByBlindedIndex`) from this one module.
|
|
65
72
|
export type { BlindedIndexQuery, BlindedIndexQueryPage }
|
|
66
73
|
|
|
74
|
+
// Surface the equality-index query shapes referenced by the `StorageBackend`
|
|
75
|
+
// contract (`queryByEquality` / `findEqualityUniqueViolation`) from this one
|
|
76
|
+
// module, alongside the blinded-index ones.
|
|
77
|
+
export type {
|
|
78
|
+
EqualityQuery,
|
|
79
|
+
EqualityQueryPage,
|
|
80
|
+
EqualityCandidate,
|
|
81
|
+
EqualityValue,
|
|
82
|
+
NormalizedIndexDeclaration
|
|
83
|
+
}
|
|
84
|
+
|
|
67
85
|
// Surface the reused @interop/data-integrity-core types from this one module.
|
|
68
86
|
export type {
|
|
69
87
|
IDID,
|
|
@@ -91,6 +109,7 @@ export type {
|
|
|
91
109
|
ResourceSummary,
|
|
92
110
|
CollectionResourcesList,
|
|
93
111
|
CollectionDescription,
|
|
112
|
+
CollectionIndexDeclaration,
|
|
94
113
|
CollectionEncryption,
|
|
95
114
|
CollectionEncryptionEpoch,
|
|
96
115
|
CollectionEncryptionRecipient,
|
|
@@ -608,12 +627,30 @@ export interface StorageBackend {
|
|
|
608
627
|
* (see `lib/blindedIndex.ts`). Conflicts require `unique: true` on both
|
|
609
628
|
* sides, and a document keeping its own unique attribute across an update
|
|
610
629
|
* never self-conflicts.
|
|
630
|
+
*
|
|
631
|
+
* A backend carrying the `equality-query` feature enforces the analogous
|
|
632
|
+
* plaintext unique-attribute invariant when the request layer passes
|
|
633
|
+
* `uniqueIndexes` (the target Collection's normalized `unique: true`
|
|
634
|
+
* declarations, resolved from its control-plane description): a write whose
|
|
635
|
+
* extracted value for a `unique` content-sourced attribute is already claimed
|
|
636
|
+
* by a different live Resource in the same Collection rejects with
|
|
637
|
+
* `UniqueAttributeConflictError` (409), evaluated atomically with the write
|
|
638
|
+
* (see `lib/equalityIndex.ts`). Unlike the blinded invariant this is
|
|
639
|
+
* Collection-level, so a conflict does not require the other side to opt in.
|
|
611
640
|
*/
|
|
612
641
|
writeResource(options: {
|
|
613
642
|
spaceId: string
|
|
614
643
|
collectionId: string
|
|
615
644
|
resourceId: string
|
|
616
645
|
input: ResourceInput
|
|
646
|
+
/**
|
|
647
|
+
* The target Collection's normalized `unique: true` index declarations,
|
|
648
|
+
* passed by the request layer only when the Collection declares any. The
|
|
649
|
+
* backend enforces the plaintext unique-attribute claim atomically with the
|
|
650
|
+
* write (409 `UniqueAttributeConflictError`), for the content-sourced
|
|
651
|
+
* entries a content write can claim.
|
|
652
|
+
*/
|
|
653
|
+
uniqueIndexes?: NormalizedIndexDeclaration[]
|
|
617
654
|
/**
|
|
618
655
|
* DID of the party whose capability invocation authorized this write (the
|
|
619
656
|
* signing key's DID, fragment stripped). Recorded as the Resource's
|
|
@@ -645,7 +682,9 @@ export interface StorageBackend {
|
|
|
645
682
|
* Deletes a Resource. When `ifMatch` is supplied (`conditional-writes`), the
|
|
646
683
|
* delete proceeds only if the Resource's current ETag matches, evaluated
|
|
647
684
|
* atomically with the removal; a mismatch rejects with `precondition-failed`
|
|
648
|
-
* (412). Without it, the delete is unconditional and idempotent.
|
|
685
|
+
* (412). Without it, the delete is unconditional and idempotent. Deleting a
|
|
686
|
+
* Resource cascade-deletes any chunks stored under it (the `chunked-streams`
|
|
687
|
+
* feature), so chunks never outlive their parent.
|
|
649
688
|
*/
|
|
650
689
|
deleteResource(options: {
|
|
651
690
|
spaceId: string
|
|
@@ -683,6 +722,15 @@ export interface StorageBackend {
|
|
|
683
722
|
collectionId: string
|
|
684
723
|
resourceId: string
|
|
685
724
|
custom: ResourceMetadataCustom | Record<string, unknown>
|
|
725
|
+
/**
|
|
726
|
+
* The target Collection's normalized `unique: true` index declarations,
|
|
727
|
+
* passed by the request layer only when the Collection declares any. The
|
|
728
|
+
* backend enforces the plaintext unique-attribute claim atomically with the
|
|
729
|
+
* metadata write (409 `UniqueAttributeConflictError`), for the
|
|
730
|
+
* custom-sourced entries a metadata write can claim (see
|
|
731
|
+
* `lib/equalityIndex.ts`).
|
|
732
|
+
*/
|
|
733
|
+
uniqueIndexes?: NormalizedIndexDeclaration[]
|
|
686
734
|
/**
|
|
687
735
|
* The client-declared key epoch (the `key-epochs` feature), a sibling of
|
|
688
736
|
* `custom`. Unlike `custom` (full replacement), an OMITTED `epoch`
|
|
@@ -694,6 +742,81 @@ export interface StorageBackend {
|
|
|
694
742
|
ifNoneMatch?: boolean
|
|
695
743
|
}): Promise<{ metaVersion: number } | undefined>
|
|
696
744
|
|
|
745
|
+
/**
|
|
746
|
+
* Writes one chunk of a chunked Resource (the `chunked-streams` feature),
|
|
747
|
+
* keyed by `(spaceId, collectionId, resourceId, chunkIndex)`. The chunk body
|
|
748
|
+
* is opaque bytes + content-type -- stored exactly like a binary Resource
|
|
749
|
+
* representation (same upload cap / quota guards); the server never parses
|
|
750
|
+
* it. The parent Resource MUST already exist: writing a chunk of an absent
|
|
751
|
+
* Resource rejects with `ResourceNotFoundError` (404), so orphan chunks
|
|
752
|
+
* cannot accumulate. An upsert per chunk, bumping the chunk's own monotonic
|
|
753
|
+
* `version` (its ETag validator, independent of the parent's); an `ifMatch` /
|
|
754
|
+
* `ifNoneMatch` precondition is evaluated on that chunk version atomically
|
|
755
|
+
* with the write (`precondition-failed` 412 on mismatch).
|
|
756
|
+
*/
|
|
757
|
+
writeChunk(options: {
|
|
758
|
+
spaceId: string
|
|
759
|
+
collectionId: string
|
|
760
|
+
resourceId: string
|
|
761
|
+
chunkIndex: number
|
|
762
|
+
input: ResourceInput
|
|
763
|
+
ifMatch?: string
|
|
764
|
+
ifNoneMatch?: boolean
|
|
765
|
+
}): Promise<{ version: number }>
|
|
766
|
+
/** Reads a chunk's bytes; rejects with `ResourceNotFoundError` when absent. */
|
|
767
|
+
getChunk(options: {
|
|
768
|
+
spaceId: string
|
|
769
|
+
collectionId: string
|
|
770
|
+
resourceId: string
|
|
771
|
+
chunkIndex: number
|
|
772
|
+
}): Promise<ResourceResult>
|
|
773
|
+
/**
|
|
774
|
+
* Reads a chunk's stored content-type / size / version (the HEAD payload
|
|
775
|
+
* headers). Resolves `undefined` when the chunk is absent.
|
|
776
|
+
*/
|
|
777
|
+
getChunkMetadata(options: {
|
|
778
|
+
spaceId: string
|
|
779
|
+
collectionId: string
|
|
780
|
+
resourceId: string
|
|
781
|
+
chunkIndex: number
|
|
782
|
+
}): Promise<
|
|
783
|
+
{ contentType: string; size: number; version?: number } | undefined
|
|
784
|
+
>
|
|
785
|
+
/**
|
|
786
|
+
* Deletes one chunk. Resolves `true` when a chunk was removed and `false`
|
|
787
|
+
* when none was stored at that index (the handler 404s on `false` -- unlike
|
|
788
|
+
* `deleteResource`, chunk deletes are not silently idempotent, mirroring the
|
|
789
|
+
* EDV chunk contract). An `ifMatch` precondition is evaluated atomically
|
|
790
|
+
* with the removal (`precondition-failed` 412 on mismatch).
|
|
791
|
+
*/
|
|
792
|
+
deleteChunk(options: {
|
|
793
|
+
spaceId: string
|
|
794
|
+
collectionId: string
|
|
795
|
+
resourceId: string
|
|
796
|
+
chunkIndex: number
|
|
797
|
+
ifMatch?: string
|
|
798
|
+
}): Promise<boolean>
|
|
799
|
+
/**
|
|
800
|
+
* Lists a Resource's stored chunks in ascending `index` order -- the
|
|
801
|
+
* discovery/reassembly listing (the server never reassembles; a reader
|
|
802
|
+
* learns the chunk set here). Resolves an empty listing when the Resource
|
|
803
|
+
* has no chunks (including when the Resource itself is absent -- existence
|
|
804
|
+
* is the parent routes' concern).
|
|
805
|
+
*/
|
|
806
|
+
listChunks(options: {
|
|
807
|
+
spaceId: string
|
|
808
|
+
collectionId: string
|
|
809
|
+
resourceId: string
|
|
810
|
+
}): Promise<{
|
|
811
|
+
count: number
|
|
812
|
+
chunks: Array<{
|
|
813
|
+
index: number
|
|
814
|
+
size: number
|
|
815
|
+
contentType: string
|
|
816
|
+
version?: number
|
|
817
|
+
}>
|
|
818
|
+
}>
|
|
819
|
+
|
|
697
820
|
/**
|
|
698
821
|
* OPTIONAL replication change feed (the `changes` query profile.
|
|
699
822
|
* Returns the Collection's JSON-document
|
|
@@ -777,6 +900,57 @@ export interface StorageBackend {
|
|
|
777
900
|
cursor?: string
|
|
778
901
|
}): Promise<{ count: number } | BlindedIndexQueryPage>
|
|
779
902
|
|
|
903
|
+
/**
|
|
904
|
+
* OPTIONAL plaintext equality query (the `equality` query profile; the
|
|
905
|
+
* `equality-query` feature token). Evaluates an equality query -- `equals`
|
|
906
|
+
* (OR across elements of an AND within each element's `{name: value}` pairs)
|
|
907
|
+
* or `has` (every named attribute present with an indexable value) -- over
|
|
908
|
+
* the attributes the server extracts from the Collection's live Resources per
|
|
909
|
+
* the `indexes` declaration. `indexes` is the NORMALIZED declaration array:
|
|
910
|
+
* the request layer resolves it from the control-plane description (a
|
|
911
|
+
* data-plane backend does not hold the description) and passes it in. Matching
|
|
912
|
+
* is strict JSON equality (no coercion); a content-sourced attribute reads a
|
|
913
|
+
* JSON Resource's stored content, a custom-sourced one reads the `custom`
|
|
914
|
+
* metadata object (so blobs are queryable too). With `count`, resolves only
|
|
915
|
+
* the match total; otherwise a page of matching documents (`{ id, data?,
|
|
916
|
+
* custom? }`) in ascending `resourceId` order, paginated with the standard
|
|
917
|
+
* opaque cursor (`cursor` present iff `hasMore`; a malformed one rejects with
|
|
918
|
+
* `invalid-cursor` 400). Both first-party backends answer through
|
|
919
|
+
* `lib/equalityIndex.ts` so semantics cannot drift.
|
|
920
|
+
*
|
|
921
|
+
* OPTIONAL: a backend that omits this method does not serve the profile, and
|
|
922
|
+
* the request layer returns `unsupported-operation` (501). The Space and
|
|
923
|
+
* Collection are guaranteed to exist by the request layer.
|
|
924
|
+
*/
|
|
925
|
+
queryByEquality?(options: {
|
|
926
|
+
spaceId: string
|
|
927
|
+
collectionId: string
|
|
928
|
+
query: EqualityQuery
|
|
929
|
+
indexes: NormalizedIndexDeclaration[]
|
|
930
|
+
count?: boolean
|
|
931
|
+
limit?: number
|
|
932
|
+
cursor?: string
|
|
933
|
+
}): Promise<{ count: number } | EqualityQueryPage>
|
|
934
|
+
|
|
935
|
+
/**
|
|
936
|
+
* OPTIONAL declare-time uniqueness scan for the `equality` profile: given the
|
|
937
|
+
* Collection's normalized `unique: true` declarations, scans its already-
|
|
938
|
+
* stored live Resources for two DIFFERENT Resources that claim the same
|
|
939
|
+
* `(name, value)`, resolving the first such `{ name, value }` or `undefined`
|
|
940
|
+
* when none exists. The request layer runs it when a Collection update ADDS a
|
|
941
|
+
* unique claim, rejecting a found violation with `id-conflict` (409) so a
|
|
942
|
+
* unique claim is never acknowledged over already-conflicting data.
|
|
943
|
+
*
|
|
944
|
+
* OPTIONAL: paired with `queryByEquality` on backends carrying the
|
|
945
|
+
* `equality-query` feature. The Space and Collection are guaranteed to exist
|
|
946
|
+
* by the request layer.
|
|
947
|
+
*/
|
|
948
|
+
findEqualityUniqueViolation?(options: {
|
|
949
|
+
spaceId: string
|
|
950
|
+
collectionId: string
|
|
951
|
+
indexes: NormalizedIndexDeclaration[]
|
|
952
|
+
}): Promise<{ name: string; value: EqualityValue } | undefined>
|
|
953
|
+
|
|
780
954
|
/**
|
|
781
955
|
* Access-control policy documents. The level is selected by which ids are
|
|
782
956
|
* present: Space (`spaceId`), Collection (`+ collectionId`), or Resource
|