anchordb-sync-server 0.2.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.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -0
  3. package/dist/cjs/adapters/express.d.ts +33 -0
  4. package/dist/cjs/adapters/express.d.ts.map +1 -0
  5. package/dist/cjs/adapters/express.js +40 -0
  6. package/dist/cjs/adapters/express.js.map +1 -0
  7. package/dist/cjs/adapters/nestjs.d.ts +34 -0
  8. package/dist/cjs/adapters/nestjs.d.ts.map +1 -0
  9. package/dist/cjs/adapters/nestjs.js +98 -0
  10. package/dist/cjs/adapters/nestjs.js.map +1 -0
  11. package/dist/cjs/adapters/nextjs.d.ts +20 -0
  12. package/dist/cjs/adapters/nextjs.d.ts.map +1 -0
  13. package/dist/cjs/adapters/nextjs.js +43 -0
  14. package/dist/cjs/adapters/nextjs.js.map +1 -0
  15. package/dist/cjs/handlers.d.ts +17 -0
  16. package/dist/cjs/handlers.d.ts.map +1 -0
  17. package/dist/cjs/handlers.js +168 -0
  18. package/dist/cjs/handlers.js.map +1 -0
  19. package/dist/cjs/index.d.ts +16 -0
  20. package/dist/cjs/index.d.ts.map +1 -0
  21. package/dist/cjs/index.js +27 -0
  22. package/dist/cjs/index.js.map +1 -0
  23. package/dist/cjs/package.json +3 -0
  24. package/dist/cjs/store/memory.d.ts +25 -0
  25. package/dist/cjs/store/memory.d.ts.map +1 -0
  26. package/dist/cjs/store/memory.js +65 -0
  27. package/dist/cjs/store/memory.js.map +1 -0
  28. package/dist/cjs/store/mongoose.d.ts +90 -0
  29. package/dist/cjs/store/mongoose.d.ts.map +1 -0
  30. package/dist/cjs/store/mongoose.js +129 -0
  31. package/dist/cjs/store/mongoose.js.map +1 -0
  32. package/dist/cjs/store/types.d.ts +62 -0
  33. package/dist/cjs/store/types.d.ts.map +1 -0
  34. package/dist/cjs/store/types.js +3 -0
  35. package/dist/cjs/store/types.js.map +1 -0
  36. package/dist/esm/adapters/express.d.ts +33 -0
  37. package/dist/esm/adapters/express.d.ts.map +1 -0
  38. package/dist/esm/adapters/express.js +37 -0
  39. package/dist/esm/adapters/express.js.map +1 -0
  40. package/dist/esm/adapters/nestjs.d.ts +34 -0
  41. package/dist/esm/adapters/nestjs.d.ts.map +1 -0
  42. package/dist/esm/adapters/nestjs.js +93 -0
  43. package/dist/esm/adapters/nestjs.js.map +1 -0
  44. package/dist/esm/adapters/nextjs.d.ts +20 -0
  45. package/dist/esm/adapters/nextjs.d.ts.map +1 -0
  46. package/dist/esm/adapters/nextjs.js +40 -0
  47. package/dist/esm/adapters/nextjs.js.map +1 -0
  48. package/dist/esm/handlers.d.ts +17 -0
  49. package/dist/esm/handlers.d.ts.map +1 -0
  50. package/dist/esm/handlers.js +162 -0
  51. package/dist/esm/handlers.js.map +1 -0
  52. package/dist/esm/index.d.ts +16 -0
  53. package/dist/esm/index.d.ts.map +1 -0
  54. package/dist/esm/index.js +13 -0
  55. package/dist/esm/index.js.map +1 -0
  56. package/dist/esm/package.json +3 -0
  57. package/dist/esm/store/memory.d.ts +25 -0
  58. package/dist/esm/store/memory.d.ts.map +1 -0
  59. package/dist/esm/store/memory.js +61 -0
  60. package/dist/esm/store/memory.js.map +1 -0
  61. package/dist/esm/store/mongoose.d.ts +90 -0
  62. package/dist/esm/store/mongoose.d.ts.map +1 -0
  63. package/dist/esm/store/mongoose.js +124 -0
  64. package/dist/esm/store/mongoose.js.map +1 -0
  65. package/dist/esm/store/types.d.ts +62 -0
  66. package/dist/esm/store/types.d.ts.map +1 -0
  67. package/dist/esm/store/types.js +2 -0
  68. package/dist/esm/store/types.js.map +1 -0
  69. package/package.json +109 -0
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Schema definitions for the two collections the protocol needs.
3
+ *
4
+ * Timestamps are `Date`, which Mongoose casts from the ISO-8601 UTC strings the client sends — one
5
+ * of the reasons the wire format uses strings rather than a custom encoding.
6
+ */
7
+ export function anchorSchemas() {
8
+ return {
9
+ document: {
10
+ documentId: { type: String, required: true, index: true },
11
+ collection: { type: String, required: true, index: true },
12
+ document: { type: Object, default: {} },
13
+ version: { type: Number, required: true, default: 0 },
14
+ deleted: { type: Boolean, default: false },
15
+ updatedAt: { type: Date, required: true },
16
+ hlc: { type: String, default: "" },
17
+ // Monotonic global sequence. Indexed because every pull is a range scan over it.
18
+ seq: { type: Number, required: true, index: true },
19
+ },
20
+ idempotency: {
21
+ clientId: { type: String, required: true },
22
+ mutationId: { type: String, required: true },
23
+ result: { type: Object, required: true },
24
+ createdAt: { type: Date, default: Date.now, expires: "30d" },
25
+ },
26
+ };
27
+ }
28
+ export class MongooseStore {
29
+ constructor(options) {
30
+ this.name = "mongoose";
31
+ const { mongoose } = options;
32
+ const schemas = anchorSchemas();
33
+ const docName = options.documentModelName ?? "AnchorDocument";
34
+ const idemName = options.idempotencyModelName ?? "AnchorIdempotency";
35
+ const counterName = "AnchorCounter";
36
+ // Reuse an already-registered model rather than re-registering, which Mongoose treats as an
37
+ // error (OverwriteModelError) and which is easy to trigger under hot reload.
38
+ this.documents =
39
+ mongoose.models[docName] ??
40
+ mongoose.model(docName, new mongoose.Schema(schemas.document, { versionKey: false }), options.documentCollection);
41
+ this.idempotency =
42
+ mongoose.models[idemName] ??
43
+ mongoose.model(idemName, new mongoose.Schema(schemas.idempotency, { versionKey: false }), options.idempotencyCollection);
44
+ this.counters =
45
+ mongoose.models[counterName] ??
46
+ mongoose.model(counterName, new mongoose.Schema({ _id: String, value: { type: Number, default: 0 } }, { versionKey: false }));
47
+ }
48
+ async get(collection, documentId) {
49
+ const found = await this.documents.findOne({ collection, documentId }).lean().exec();
50
+ return found ? toStored(found) : null;
51
+ }
52
+ /**
53
+ * Allocate the next sequence number atomically.
54
+ *
55
+ * `findOneAndUpdate` with `$inc` is a single atomic operation in MongoDB, so two concurrent
56
+ * pushes cannot receive the same seq. Reading-then-writing a counter would race, and duplicate
57
+ * sequence numbers would make pull cursors skip changes.
58
+ */
59
+ async nextSeq() {
60
+ const doc = (await this.counters
61
+ .findOneAndUpdate({ _id: "seq" }, { $inc: { value: 1 } }, { upsert: true, new: true })
62
+ .lean()
63
+ .exec());
64
+ return doc?.value ?? 1;
65
+ }
66
+ async put(doc) {
67
+ const seq = await this.nextSeq();
68
+ const stored = { ...doc, seq };
69
+ await this.documents
70
+ .findOneAndUpdate({ collection: doc.collection, documentId: doc.documentId }, { $set: { ...stored, updatedAt: new Date(doc.updatedAt) } }, { upsert: true, new: true })
71
+ .lean()
72
+ .exec();
73
+ return stored;
74
+ }
75
+ async listChanges(afterSeq, limit, collections) {
76
+ const filter = { seq: { $gt: afterSeq } };
77
+ if (collections?.length)
78
+ filter.collection = { $in: collections };
79
+ const rows = await this.documents.find(filter).sort({ seq: 1 }).limit(limit).lean().exec();
80
+ return rows.map(toStored);
81
+ }
82
+ async hasMoreAfter(seq, collections) {
83
+ const filter = { seq: { $gt: seq } };
84
+ if (collections?.length)
85
+ filter.collection = { $in: collections };
86
+ return (await this.documents.countDocuments(filter).exec()) > 0;
87
+ }
88
+ async getIdempotent(clientId, mutationId) {
89
+ const found = (await this.idempotency.findOne({ clientId, mutationId }).lean().exec());
90
+ return found?.result ?? null;
91
+ }
92
+ async setIdempotent(clientId, mutationId, result) {
93
+ await this.idempotency
94
+ .findOneAndUpdate({ clientId, mutationId }, { $set: { result } }, { upsert: true, new: true })
95
+ .lean()
96
+ .exec();
97
+ }
98
+ async findByUniqueField(collection, field, value, exceptDocumentId) {
99
+ const found = await this.documents
100
+ .findOne({
101
+ collection,
102
+ deleted: false,
103
+ documentId: { $ne: exceptDocumentId },
104
+ [`document.${field}`]: value,
105
+ })
106
+ .lean()
107
+ .exec();
108
+ return found ? toStored(found) : null;
109
+ }
110
+ }
111
+ function toStored(row) {
112
+ const updatedAt = row.updatedAt;
113
+ return {
114
+ documentId: String(row.documentId),
115
+ collection: String(row.collection),
116
+ document: (row.document ?? {}),
117
+ version: Number(row.version ?? 0),
118
+ deleted: Boolean(row.deleted),
119
+ updatedAt: updatedAt instanceof Date ? updatedAt.toISOString() : String(updatedAt),
120
+ hlc: String(row.hlc ?? ""),
121
+ seq: Number(row.seq ?? 0),
122
+ };
123
+ }
124
+ //# sourceMappingURL=mongoose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mongoose.js","sourceRoot":"","sources":["../../../src/store/mongoose.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ import type { ChangeResult } from "anchordb";
2
+ /**
3
+ * The storage contract the sync protocol needs from a backend.
4
+ *
5
+ * Kept deliberately small — five reads and two writes — so implementing it against a new database
6
+ * is a short afternoon rather than a port. The protocol semantics (version checks, conflict
7
+ * verdicts, idempotency) live in `handlers.ts` and are identical for every store, which is what
8
+ * makes the conformance suite meaningful: MemoryStore and MongooseStore are held to the same tests.
9
+ */
10
+ export interface StoredServerDocument {
11
+ documentId: string;
12
+ collection: string;
13
+ document: Record<string, unknown>;
14
+ /** Monotonic per document. The basis of optimistic concurrency. */
15
+ version: number;
16
+ deleted: boolean;
17
+ updatedAt: string;
18
+ hlc: string;
19
+ /** Position in the global change sequence — what pull cursors point at. */
20
+ seq: number;
21
+ }
22
+ export interface UniqueIndexSpec {
23
+ collection: string;
24
+ field: string;
25
+ }
26
+ export interface ServerStore {
27
+ readonly name: string;
28
+ get(collection: string, documentId: string): Promise<StoredServerDocument | null>;
29
+ /** Persist a document and assign it the next global sequence number. */
30
+ put(doc: Omit<StoredServerDocument, "seq">): Promise<StoredServerDocument>;
31
+ /** Documents whose seq is greater than `afterSeq`, ascending, at most `limit`. */
32
+ listChanges(afterSeq: number, limit: number, collections?: string[]): Promise<StoredServerDocument[]>;
33
+ /** True when more changes remain beyond the returned page. */
34
+ hasMoreAfter(seq: number, collections?: string[]): Promise<boolean>;
35
+ /**
36
+ * Look up a memoised verdict.
37
+ *
38
+ * This is what makes retries safe: a client that times out and re-sends must receive the original
39
+ * decision, not have the write applied a second time.
40
+ */
41
+ getIdempotent(clientId: string, mutationId: string): Promise<ChangeResult | null>;
42
+ setIdempotent(clientId: string, mutationId: string, result: ChangeResult): Promise<void>;
43
+ /**
44
+ * Find a document that already holds `value` in `field`, excluding `exceptDocumentId`.
45
+ *
46
+ * Unique constraints are checked here rather than in the handler because a real database can do
47
+ * it with an index; scanning in the handler would be correct but O(n) per push.
48
+ */
49
+ findByUniqueField(collection: string, field: string, value: unknown, exceptDocumentId: string): Promise<StoredServerDocument | null>;
50
+ }
51
+ export interface SyncServerOptions {
52
+ store: ServerStore;
53
+ /** Unique constraints to enforce, mirroring the indexes declared in the client schema. */
54
+ uniqueIndexes?: UniqueIndexSpec[];
55
+ /** Injectable for deterministic tests. */
56
+ now?: () => number;
57
+ /** Reject collections not in this list, if provided. */
58
+ allowedCollections?: string[];
59
+ /** Resolve the tenant/user this request belongs to. Return null to reject. */
60
+ authenticate?: (headers: Record<string, string | undefined>) => Promise<string | null> | string | null;
61
+ }
62
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/store/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C;;;;;;;GAOG;AAEH,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,2EAA2E;IAC3E,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;IAElF,wEAAwE;IACxE,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,oBAAoB,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAE3E,kFAAkF;IAClF,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IAEtG,8DAA8D;IAC9D,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEpE;;;;;OAKG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IAClF,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzF;;;;;OAKG;IACH,iBAAiB,CACf,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,OAAO,EACd,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,WAAW,CAAC;IACnB,0FAA0F;IAC1F,aAAa,CAAC,EAAE,eAAe,EAAE,CAAC;IAClC,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,wDAAwD;IACxD,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,8EAA8E;IAC9E,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC;CACxG"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/store/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,109 @@
1
+ {
2
+ "name": "anchordb-sync-server",
3
+ "version": "0.2.0",
4
+ "description": "Framework-agnostic server implementation of the Anchor sync protocol, with Express, NestJS and Next.js adapters.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "engines": {
9
+ "node": ">=20"
10
+ },
11
+ "main": "./dist/cjs/index.js",
12
+ "module": "./dist/esm/index.js",
13
+ "types": "./dist/esm/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "import": {
17
+ "types": "./dist/esm/index.d.ts",
18
+ "default": "./dist/esm/index.js"
19
+ },
20
+ "require": {
21
+ "types": "./dist/cjs/index.d.ts",
22
+ "default": "./dist/cjs/index.js"
23
+ }
24
+ },
25
+ "./express": {
26
+ "import": {
27
+ "types": "./dist/esm/adapters/express.d.ts",
28
+ "default": "./dist/esm/adapters/express.js"
29
+ },
30
+ "require": {
31
+ "types": "./dist/cjs/adapters/express.d.ts",
32
+ "default": "./dist/cjs/adapters/express.js"
33
+ }
34
+ },
35
+ "./nestjs": {
36
+ "import": {
37
+ "types": "./dist/esm/adapters/nestjs.d.ts",
38
+ "default": "./dist/esm/adapters/nestjs.js"
39
+ },
40
+ "require": {
41
+ "types": "./dist/cjs/adapters/nestjs.d.ts",
42
+ "default": "./dist/cjs/adapters/nestjs.js"
43
+ }
44
+ },
45
+ "./nextjs": {
46
+ "import": {
47
+ "types": "./dist/esm/adapters/nextjs.d.ts",
48
+ "default": "./dist/esm/adapters/nextjs.js"
49
+ },
50
+ "require": {
51
+ "types": "./dist/cjs/adapters/nextjs.d.ts",
52
+ "default": "./dist/cjs/adapters/nextjs.js"
53
+ }
54
+ },
55
+ "./mongoose": {
56
+ "import": {
57
+ "types": "./dist/esm/store/mongoose.d.ts",
58
+ "default": "./dist/esm/store/mongoose.js"
59
+ },
60
+ "require": {
61
+ "types": "./dist/cjs/store/mongoose.d.ts",
62
+ "default": "./dist/cjs/store/mongoose.js"
63
+ }
64
+ },
65
+ "./package.json": "./package.json"
66
+ },
67
+ "files": [
68
+ "dist",
69
+ "README.md",
70
+ "LICENSE"
71
+ ],
72
+ "scripts": {
73
+ "build": "rimraf dist && tsc -p tsconfig.build.json && tsc -p tsconfig.build.cjs.json && node ../core/scripts/finalize-dist.mjs",
74
+ "typecheck": "tsc --noEmit -p tsconfig.json",
75
+ "check:package": "publint && attw --pack . --profile node16",
76
+ "prepublishOnly": "npm run typecheck && npm run build"
77
+ },
78
+ "dependencies": {
79
+ "anchordb": "^0.2.0"
80
+ },
81
+ "peerDependencies": {
82
+ "mongoose": ">=7",
83
+ "express": ">=4"
84
+ },
85
+ "peerDependenciesMeta": {
86
+ "mongoose": {
87
+ "optional": true
88
+ },
89
+ "express": {
90
+ "optional": true
91
+ }
92
+ },
93
+ "devDependencies": {
94
+ "rimraf": "^6.0.1"
95
+ },
96
+ "publishConfig": {
97
+ "access": "public"
98
+ },
99
+ "repository": {
100
+ "type": "git",
101
+ "url": "git+https://github.com/knnadeera/anchordb.git",
102
+ "directory": "packages/sync-server"
103
+ },
104
+ "homepage": "https://github.com/knnadeera/anchordb#readme",
105
+ "bugs": {
106
+ "url": "https://github.com/knnadeera/anchordb/issues"
107
+ },
108
+ "author": "Nisala Nadeera <knnadeera@gmail.com>"
109
+ }