@kedaruma/revlm-client 1.0.0 → 1.0.2

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.
@@ -0,0 +1,179 @@
1
+ import { Timestamp, Long } from 'bson';
2
+
3
+ type FindOneOptions = {
4
+ readonly projection?: Record<string, unknown>;
5
+ readonly sort?: Record<string, unknown>;
6
+ };
7
+ type FindOptions = FindOneOptions & {
8
+ readonly limit?: number;
9
+ };
10
+ type FindOneAndModifyOptions = FindOneOptions & {
11
+ readonly upsert?: boolean;
12
+ readonly returnNewDocument?: boolean;
13
+ };
14
+ type CountOptions = {
15
+ readonly limit?: number;
16
+ };
17
+ type UpdateOptions = {
18
+ readonly upsert?: boolean;
19
+ readonly arrayFilters?: Filter[];
20
+ };
21
+ type Document<IdType = unknown> = {
22
+ _id: IdType;
23
+ };
24
+ type NewDocument<T extends Document> = Omit<T, "_id"> & Partial<Pick<T, "_id">>;
25
+ type InsertOneResult<IdType> = {
26
+ readonly insertedId: IdType;
27
+ };
28
+ type InsertManyResult<IdType> = {
29
+ readonly insertedIds: IdType[];
30
+ };
31
+ type DeleteResult = {
32
+ readonly deletedCount: number;
33
+ };
34
+ type UpdateResult<IdType> = {
35
+ readonly matchedCount: number;
36
+ readonly modifiedCount: number;
37
+ readonly upsertedId?: IdType;
38
+ };
39
+ type Filter = Record<string, unknown>;
40
+ type Update = Record<string, unknown>;
41
+ type AggregatePipelineStage = Record<string, unknown>;
42
+ type OperationType = "insert" | "delete" | "replace" | "update" | "drop" | "rename" | "dropDatabase" | "invalidate";
43
+ type DocumentNamespace = {
44
+ db: string;
45
+ coll: string;
46
+ };
47
+ type UpdateDescription = {
48
+ updatedFields: Record<string, unknown>;
49
+ removedFields: string[];
50
+ };
51
+ type ChangeEventId = unknown;
52
+ type DocumentKey<IdType> = {
53
+ _id: IdType;
54
+ } & Record<string, unknown>;
55
+ type BaseChangeEvent<T extends OperationType> = {
56
+ _id: ChangeEventId;
57
+ operationType: T;
58
+ clusterTime: Timestamp;
59
+ txnNumber?: Long;
60
+ lsid?: Record<string, unknown>;
61
+ };
62
+ type InsertEvent<T extends Document> = {
63
+ ns: DocumentNamespace;
64
+ documentKey: DocumentKey<T["_id"]>;
65
+ fullDocument: T;
66
+ } & BaseChangeEvent<"insert">;
67
+ type UpdateEvent<T extends Document> = {
68
+ ns: DocumentNamespace;
69
+ documentKey: DocumentKey<T["_id"]>;
70
+ updateDescription: UpdateDescription;
71
+ fullDocument?: T;
72
+ } & BaseChangeEvent<"update">;
73
+ type ReplaceEvent<T extends Document> = {
74
+ ns: DocumentNamespace;
75
+ documentKey: DocumentKey<T["_id"]>;
76
+ fullDocument: T;
77
+ } & BaseChangeEvent<"replace">;
78
+ type DeleteEvent<T extends Document> = {
79
+ ns: DocumentNamespace;
80
+ documentKey: DocumentKey<T["_id"]>;
81
+ } & BaseChangeEvent<"delete">;
82
+ type DropEvent = {
83
+ ns: DocumentNamespace;
84
+ } & BaseChangeEvent<"drop">;
85
+ type RenameEvent = {
86
+ ns: DocumentNamespace;
87
+ to: DocumentNamespace;
88
+ } & BaseChangeEvent<"rename">;
89
+ type DropDatabaseEvent = {
90
+ ns: Omit<DocumentNamespace, "coll">;
91
+ } & BaseChangeEvent<"dropDatabase">;
92
+ type InvalidateEvent = BaseChangeEvent<"invalidate">;
93
+ type ChangeEvent<T extends Document> = InsertEvent<T> | UpdateEvent<T> | ReplaceEvent<T> | DeleteEvent<T> | DropEvent | RenameEvent | DropDatabaseEvent | InvalidateEvent;
94
+ type WatchOptionsIds<T extends Document> = {
95
+ ids: T["_id"][];
96
+ filter?: never;
97
+ };
98
+ type WatchOptionsFilter = {
99
+ ids?: never;
100
+ filter: Filter;
101
+ };
102
+
103
+ declare class RevlmCollection<T extends Document = Document> {
104
+ private _revlm;
105
+ private _dbName;
106
+ private _collection;
107
+ constructor(collection: string, dbName: string, revlm: Revlm);
108
+ get name(): string;
109
+ private vg;
110
+ find(filter?: Filter, options?: FindOptions): Promise<T[]>;
111
+ findOne(filter?: Filter, options?: FindOneOptions): Promise<T | null>;
112
+ findOneAndUpdate(filter: Filter, update: Update, options?: FindOneAndModifyOptions): Promise<T | null>;
113
+ findOneAndReplace(filter: Filter, replacement: unknown, options?: FindOneAndModifyOptions): Promise<T | null>;
114
+ findOneAndDelete(filter?: Filter, options?: FindOneOptions): Promise<T | null>;
115
+ aggregate(pipeline: AggregatePipelineStage[]): Promise<unknown>;
116
+ count(filter?: Filter, options?: CountOptions): Promise<number>;
117
+ insertOne(document: NewDocument<T>): Promise<InsertOneResult<T["_id"]>>;
118
+ insertMany(documents: NewDocument<T>[]): Promise<InsertManyResult<T["_id"]>>;
119
+ deleteOne(filter?: Filter): Promise<DeleteResult>;
120
+ deleteMany(filter?: Filter): Promise<DeleteResult>;
121
+ updateOne(filter: Filter, update: Update, options?: UpdateOptions): Promise<UpdateResult<T["_id"]>>;
122
+ updateMany(filter: Filter, update: Update, options?: UpdateOptions): Promise<UpdateResult<T["_id"]>>;
123
+ watch(options?: WatchOptionsIds<T> | WatchOptionsFilter): AsyncGenerator<ChangeEvent<T>>;
124
+ }
125
+
126
+ declare class RevlmDBDatabase {
127
+ private _revlm;
128
+ private _dbName;
129
+ constructor(dbName: string, revlm: Revlm);
130
+ collection<T extends Document = Document>(collection: string): RevlmCollection<T>;
131
+ }
132
+
133
+ type RevlmOptions = {
134
+ fetchImpl?: typeof fetch;
135
+ defaultHeaders?: Record<string, string>;
136
+ provisionalEnabled?: boolean;
137
+ provisionalAuthSecretMaster?: string;
138
+ provisionalAuthDomain?: string;
139
+ autoSetToken?: boolean;
140
+ };
141
+ type RevlmResponse<T = any> = {
142
+ ok: boolean;
143
+ error?: string;
144
+ token?: string;
145
+ user?: any;
146
+ result?: T;
147
+ [k: string]: any;
148
+ };
149
+ declare class Revlm {
150
+ baseUrl: string;
151
+ fetchImpl: typeof fetch;
152
+ defaultHeaders: Record<string, string>;
153
+ private _token;
154
+ private provisionalEnabled;
155
+ private provisionalAuthSecretMaster;
156
+ private provisionalAuthDomain;
157
+ private autoSetToken;
158
+ constructor(baseUrl: string, opts?: RevlmOptions);
159
+ setToken(token: string): void;
160
+ getToken(): string | undefined;
161
+ clearToken(): void;
162
+ logout(): void;
163
+ refreshToken(): Promise<RevlmResponse>;
164
+ verifyToken(): Promise<RevlmResponse>;
165
+ private makeHeaders;
166
+ private parseResponse;
167
+ private request;
168
+ login(authId: string, password: string): Promise<RevlmResponse<any>>;
169
+ provisionalLogin(authId: string): Promise<RevlmResponse<any>>;
170
+ registerUser(user: any, password: string): Promise<RevlmResponse<any>>;
171
+ deleteUser(params: {
172
+ _id?: any;
173
+ authId?: string;
174
+ }): Promise<RevlmResponse<any>>;
175
+ revlmGate(payload: any): Promise<RevlmResponse<any>>;
176
+ db(dbName: string): RevlmDBDatabase;
177
+ }
178
+
179
+ export { Revlm, type RevlmOptions, type RevlmResponse };
@@ -0,0 +1,179 @@
1
+ import { Timestamp, Long } from 'bson';
2
+
3
+ type FindOneOptions = {
4
+ readonly projection?: Record<string, unknown>;
5
+ readonly sort?: Record<string, unknown>;
6
+ };
7
+ type FindOptions = FindOneOptions & {
8
+ readonly limit?: number;
9
+ };
10
+ type FindOneAndModifyOptions = FindOneOptions & {
11
+ readonly upsert?: boolean;
12
+ readonly returnNewDocument?: boolean;
13
+ };
14
+ type CountOptions = {
15
+ readonly limit?: number;
16
+ };
17
+ type UpdateOptions = {
18
+ readonly upsert?: boolean;
19
+ readonly arrayFilters?: Filter[];
20
+ };
21
+ type Document<IdType = unknown> = {
22
+ _id: IdType;
23
+ };
24
+ type NewDocument<T extends Document> = Omit<T, "_id"> & Partial<Pick<T, "_id">>;
25
+ type InsertOneResult<IdType> = {
26
+ readonly insertedId: IdType;
27
+ };
28
+ type InsertManyResult<IdType> = {
29
+ readonly insertedIds: IdType[];
30
+ };
31
+ type DeleteResult = {
32
+ readonly deletedCount: number;
33
+ };
34
+ type UpdateResult<IdType> = {
35
+ readonly matchedCount: number;
36
+ readonly modifiedCount: number;
37
+ readonly upsertedId?: IdType;
38
+ };
39
+ type Filter = Record<string, unknown>;
40
+ type Update = Record<string, unknown>;
41
+ type AggregatePipelineStage = Record<string, unknown>;
42
+ type OperationType = "insert" | "delete" | "replace" | "update" | "drop" | "rename" | "dropDatabase" | "invalidate";
43
+ type DocumentNamespace = {
44
+ db: string;
45
+ coll: string;
46
+ };
47
+ type UpdateDescription = {
48
+ updatedFields: Record<string, unknown>;
49
+ removedFields: string[];
50
+ };
51
+ type ChangeEventId = unknown;
52
+ type DocumentKey<IdType> = {
53
+ _id: IdType;
54
+ } & Record<string, unknown>;
55
+ type BaseChangeEvent<T extends OperationType> = {
56
+ _id: ChangeEventId;
57
+ operationType: T;
58
+ clusterTime: Timestamp;
59
+ txnNumber?: Long;
60
+ lsid?: Record<string, unknown>;
61
+ };
62
+ type InsertEvent<T extends Document> = {
63
+ ns: DocumentNamespace;
64
+ documentKey: DocumentKey<T["_id"]>;
65
+ fullDocument: T;
66
+ } & BaseChangeEvent<"insert">;
67
+ type UpdateEvent<T extends Document> = {
68
+ ns: DocumentNamespace;
69
+ documentKey: DocumentKey<T["_id"]>;
70
+ updateDescription: UpdateDescription;
71
+ fullDocument?: T;
72
+ } & BaseChangeEvent<"update">;
73
+ type ReplaceEvent<T extends Document> = {
74
+ ns: DocumentNamespace;
75
+ documentKey: DocumentKey<T["_id"]>;
76
+ fullDocument: T;
77
+ } & BaseChangeEvent<"replace">;
78
+ type DeleteEvent<T extends Document> = {
79
+ ns: DocumentNamespace;
80
+ documentKey: DocumentKey<T["_id"]>;
81
+ } & BaseChangeEvent<"delete">;
82
+ type DropEvent = {
83
+ ns: DocumentNamespace;
84
+ } & BaseChangeEvent<"drop">;
85
+ type RenameEvent = {
86
+ ns: DocumentNamespace;
87
+ to: DocumentNamespace;
88
+ } & BaseChangeEvent<"rename">;
89
+ type DropDatabaseEvent = {
90
+ ns: Omit<DocumentNamespace, "coll">;
91
+ } & BaseChangeEvent<"dropDatabase">;
92
+ type InvalidateEvent = BaseChangeEvent<"invalidate">;
93
+ type ChangeEvent<T extends Document> = InsertEvent<T> | UpdateEvent<T> | ReplaceEvent<T> | DeleteEvent<T> | DropEvent | RenameEvent | DropDatabaseEvent | InvalidateEvent;
94
+ type WatchOptionsIds<T extends Document> = {
95
+ ids: T["_id"][];
96
+ filter?: never;
97
+ };
98
+ type WatchOptionsFilter = {
99
+ ids?: never;
100
+ filter: Filter;
101
+ };
102
+
103
+ declare class RevlmCollection<T extends Document = Document> {
104
+ private _revlm;
105
+ private _dbName;
106
+ private _collection;
107
+ constructor(collection: string, dbName: string, revlm: Revlm);
108
+ get name(): string;
109
+ private vg;
110
+ find(filter?: Filter, options?: FindOptions): Promise<T[]>;
111
+ findOne(filter?: Filter, options?: FindOneOptions): Promise<T | null>;
112
+ findOneAndUpdate(filter: Filter, update: Update, options?: FindOneAndModifyOptions): Promise<T | null>;
113
+ findOneAndReplace(filter: Filter, replacement: unknown, options?: FindOneAndModifyOptions): Promise<T | null>;
114
+ findOneAndDelete(filter?: Filter, options?: FindOneOptions): Promise<T | null>;
115
+ aggregate(pipeline: AggregatePipelineStage[]): Promise<unknown>;
116
+ count(filter?: Filter, options?: CountOptions): Promise<number>;
117
+ insertOne(document: NewDocument<T>): Promise<InsertOneResult<T["_id"]>>;
118
+ insertMany(documents: NewDocument<T>[]): Promise<InsertManyResult<T["_id"]>>;
119
+ deleteOne(filter?: Filter): Promise<DeleteResult>;
120
+ deleteMany(filter?: Filter): Promise<DeleteResult>;
121
+ updateOne(filter: Filter, update: Update, options?: UpdateOptions): Promise<UpdateResult<T["_id"]>>;
122
+ updateMany(filter: Filter, update: Update, options?: UpdateOptions): Promise<UpdateResult<T["_id"]>>;
123
+ watch(options?: WatchOptionsIds<T> | WatchOptionsFilter): AsyncGenerator<ChangeEvent<T>>;
124
+ }
125
+
126
+ declare class RevlmDBDatabase {
127
+ private _revlm;
128
+ private _dbName;
129
+ constructor(dbName: string, revlm: Revlm);
130
+ collection<T extends Document = Document>(collection: string): RevlmCollection<T>;
131
+ }
132
+
133
+ type RevlmOptions = {
134
+ fetchImpl?: typeof fetch;
135
+ defaultHeaders?: Record<string, string>;
136
+ provisionalEnabled?: boolean;
137
+ provisionalAuthSecretMaster?: string;
138
+ provisionalAuthDomain?: string;
139
+ autoSetToken?: boolean;
140
+ };
141
+ type RevlmResponse<T = any> = {
142
+ ok: boolean;
143
+ error?: string;
144
+ token?: string;
145
+ user?: any;
146
+ result?: T;
147
+ [k: string]: any;
148
+ };
149
+ declare class Revlm {
150
+ baseUrl: string;
151
+ fetchImpl: typeof fetch;
152
+ defaultHeaders: Record<string, string>;
153
+ private _token;
154
+ private provisionalEnabled;
155
+ private provisionalAuthSecretMaster;
156
+ private provisionalAuthDomain;
157
+ private autoSetToken;
158
+ constructor(baseUrl: string, opts?: RevlmOptions);
159
+ setToken(token: string): void;
160
+ getToken(): string | undefined;
161
+ clearToken(): void;
162
+ logout(): void;
163
+ refreshToken(): Promise<RevlmResponse>;
164
+ verifyToken(): Promise<RevlmResponse>;
165
+ private makeHeaders;
166
+ private parseResponse;
167
+ private request;
168
+ login(authId: string, password: string): Promise<RevlmResponse<any>>;
169
+ provisionalLogin(authId: string): Promise<RevlmResponse<any>>;
170
+ registerUser(user: any, password: string): Promise<RevlmResponse<any>>;
171
+ deleteUser(params: {
172
+ _id?: any;
173
+ authId?: string;
174
+ }): Promise<RevlmResponse<any>>;
175
+ revlmGate(payload: any): Promise<RevlmResponse<any>>;
176
+ db(dbName: string): RevlmDBDatabase;
177
+ }
178
+
179
+ export { Revlm, type RevlmOptions, type RevlmResponse };
package/dist/index.js ADDED
@@ -0,0 +1,276 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ Revlm: () => Revlm
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+
27
+ // src/Revlm.ts
28
+ var import_bson = require("bson");
29
+ var import_revlm_shared = require("@kedaruma/revlm-shared");
30
+
31
+ // src/RevlmCollection.ts
32
+ var RevlmCollection = class {
33
+ _revlm;
34
+ _dbName;
35
+ _collection;
36
+ constructor(collection, dbName, revlm) {
37
+ this._collection = collection;
38
+ this._dbName = dbName;
39
+ this._revlm = revlm;
40
+ }
41
+ get name() {
42
+ return this._collection;
43
+ }
44
+ // Helper to call server revlm-gate and return parsed result or throw on error
45
+ async vg(method, params = {}) {
46
+ const payload = { db: this._dbName, collection: this._collection, method, ...params };
47
+ const res = await this._revlm.revlmGate(payload);
48
+ if (!res || !res.ok) {
49
+ const errMsg = res && (res.error || res.reason) ? res.error || res.reason : "revlm-gate error";
50
+ const e = new Error(String(errMsg));
51
+ e.response = res;
52
+ throw e;
53
+ }
54
+ return res.result;
55
+ }
56
+ async find(filter, options) {
57
+ const result = await this.vg("find", { filter: filter || {}, options: options || {} });
58
+ return Array.isArray(result) ? result : result || [];
59
+ }
60
+ async findOne(filter, options) {
61
+ const result = await this.vg("findOne", { filter: filter || {}, options: options || {} });
62
+ return result === void 0 ? null : result;
63
+ }
64
+ async findOneAndUpdate(filter, update, options) {
65
+ const result = await this.vg("findOneAndUpdate", { filter, update, options: options || {} });
66
+ return result && (result.value ?? result);
67
+ }
68
+ async findOneAndReplace(filter, replacement, options) {
69
+ const result = await this.vg("findOneAndReplace", { filter, replacement, options: options || {} });
70
+ return result && (result.value ?? result);
71
+ }
72
+ async findOneAndDelete(filter, options) {
73
+ const result = await this.vg("findOneAndDelete", { filter: filter || {}, options: options || {} });
74
+ return result && (result.value ?? result);
75
+ }
76
+ async aggregate(pipeline) {
77
+ return await this.vg("aggregate", { pipeline });
78
+ }
79
+ async count(filter, options) {
80
+ const result = await this.vg("count", { filter: filter || {}, options: options || {} });
81
+ return Number(result || 0);
82
+ }
83
+ async insertOne(document) {
84
+ const result = await this.vg("insertOne", { document });
85
+ return result;
86
+ }
87
+ async insertMany(documents) {
88
+ const result = await this.vg("insertMany", { documents });
89
+ return result;
90
+ }
91
+ async deleteOne(filter) {
92
+ const result = await this.vg("deleteOne", { filter: filter || {} });
93
+ return result;
94
+ }
95
+ async deleteMany(filter) {
96
+ const result = await this.vg("deleteMany", { filter: filter || {} });
97
+ return result;
98
+ }
99
+ async updateOne(filter, update, options) {
100
+ const result = await this.vg("updateOne", { filter, update, options: options || {} });
101
+ return result;
102
+ }
103
+ async updateMany(filter, update, options) {
104
+ const result = await this.vg("updateMany", { filter, update, options: options || {} });
105
+ return result;
106
+ }
107
+ // single watch implementation with optional options
108
+ async *watch(options) {
109
+ const arr = await this.vg("watch", { options: options || {} }) || [];
110
+ for (const it of Array.isArray(arr) ? arr : []) {
111
+ yield it;
112
+ }
113
+ }
114
+ };
115
+
116
+ // src/RevlmDBDatabase.ts
117
+ var RevlmDBDatabase = class {
118
+ _revlm;
119
+ _dbName;
120
+ constructor(dbName, revlm) {
121
+ this._dbName = dbName;
122
+ this._revlm = revlm;
123
+ }
124
+ collection(collection) {
125
+ return new RevlmCollection(collection, this._dbName, this._revlm);
126
+ }
127
+ };
128
+
129
+ // src/Revlm.ts
130
+ var Revlm = class {
131
+ baseUrl;
132
+ fetchImpl;
133
+ defaultHeaders;
134
+ _token;
135
+ provisionalEnabled;
136
+ provisionalAuthSecretMaster;
137
+ provisionalAuthDomain;
138
+ autoSetToken;
139
+ constructor(baseUrl, opts = {}) {
140
+ if (!baseUrl) throw new Error("baseUrl is required");
141
+ this.baseUrl = baseUrl.replace(/\/$/, "");
142
+ this.fetchImpl = opts.fetchImpl || (typeof fetch !== "undefined" ? fetch : void 0);
143
+ this.defaultHeaders = opts.defaultHeaders || {};
144
+ this.provisionalEnabled = opts.provisionalEnabled || false;
145
+ this.provisionalAuthSecretMaster = opts.provisionalAuthSecretMaster || "";
146
+ this.provisionalAuthDomain = opts.provisionalAuthDomain || "";
147
+ this.autoSetToken = opts.autoSetToken ?? true;
148
+ if (!this.fetchImpl) {
149
+ throw new Error("No fetch implementation available. Provide fetchImpl in options or run in Node 18+ with global fetch.");
150
+ }
151
+ }
152
+ setToken(token) {
153
+ this._token = token;
154
+ }
155
+ getToken() {
156
+ return this._token;
157
+ }
158
+ clearToken() {
159
+ this._token = void 0;
160
+ }
161
+ // Logout clears client-side token (simple, synchronous)
162
+ logout() {
163
+ this.clearToken();
164
+ }
165
+ // Call server to refresh token. Uses Authorization header with current token.
166
+ // On success, if autoSetToken is true and res.token is set, update the client token.
167
+ async refreshToken() {
168
+ if (!this._token) return { ok: false, error: "No token set" };
169
+ const res = await this.request("/refresh-token", "POST");
170
+ if (this.autoSetToken && res && res.ok && res.token) {
171
+ this.setToken(res.token);
172
+ }
173
+ return res;
174
+ }
175
+ // Verify current token with server. If invalid/expired, clear local token.
176
+ async verifyToken() {
177
+ if (!this._token) return { ok: false, error: "No token set" };
178
+ const res = await this.request("/verify-token", "POST");
179
+ const reason = res.reason || res.error;
180
+ if (res && !res.ok) {
181
+ if (reason === "invalid_token" || reason === "token_expired" || reason === "no_token" || res.status === 401 || res.status === 403) {
182
+ this.clearToken();
183
+ }
184
+ }
185
+ return res;
186
+ }
187
+ makeHeaders(hasBody) {
188
+ const headers = {
189
+ Accept: "application/ejson",
190
+ ...this.defaultHeaders
191
+ };
192
+ if (hasBody) {
193
+ headers["Content-Type"] = "application/ejson";
194
+ }
195
+ if (this._token) {
196
+ headers["Authorization"] = `Bearer ${this._token}`;
197
+ }
198
+ return headers;
199
+ }
200
+ async parseResponse(res) {
201
+ const text = await res.text();
202
+ if (!text) return null;
203
+ try {
204
+ return import_bson.EJSON.parse(text);
205
+ } catch (e) {
206
+ }
207
+ try {
208
+ return JSON.parse(text);
209
+ } catch (e) {
210
+ return text;
211
+ }
212
+ }
213
+ async request(path, method = "POST", body) {
214
+ const url = path.startsWith("http") ? path : `${this.baseUrl}${path.startsWith("/") ? "" : "/"}${path}`;
215
+ const hasBody = body !== void 0;
216
+ const headers = this.makeHeaders(hasBody);
217
+ let serializedBody;
218
+ if (hasBody) {
219
+ serializedBody = import_bson.EJSON.stringify(body);
220
+ }
221
+ try {
222
+ const res = await this.fetchImpl(url, {
223
+ method,
224
+ headers,
225
+ body: serializedBody
226
+ });
227
+ const parsed = await this.parseResponse(res);
228
+ const out = parsed && typeof parsed === "object" ? parsed : { ok: res.ok, result: parsed };
229
+ out.status = res.status;
230
+ return out;
231
+ } catch (err) {
232
+ return { ok: false, error: err?.message || String(err) };
233
+ }
234
+ }
235
+ async login(authId, password) {
236
+ if (!authId || !password) throw new Error("authId and password are required");
237
+ const res = await this.request("/login", "POST", { authId, password });
238
+ if (this.autoSetToken && res && res.ok && res.token) {
239
+ this.setToken(res.token);
240
+ }
241
+ return res;
242
+ }
243
+ async provisionalLogin(authId) {
244
+ if (!this.provisionalEnabled) {
245
+ throw new Error("provisional login is disabled by client configuration");
246
+ }
247
+ if (!authId) throw new Error("authId is required");
248
+ const provisionalClient = new import_revlm_shared.AuthClient({ secretMaster: this.provisionalAuthSecretMaster, authDomain: this.provisionalAuthDomain });
249
+ const provisionalPassword = await provisionalClient.producePassword(String(Date.now() * 1e3));
250
+ const res = await this.request("/provisional-login", "POST", { authId, password: provisionalPassword });
251
+ if (this.autoSetToken && res && res.ok && res.token) {
252
+ this.setToken(res.token);
253
+ }
254
+ return res;
255
+ }
256
+ async registerUser(user, password) {
257
+ if (!user) throw new Error("user is required");
258
+ if (!password) throw new Error("password is required");
259
+ return this.request("/registerUser", "POST", { user, password });
260
+ }
261
+ async deleteUser(params) {
262
+ if (!params || !params._id && !params.authId) throw new Error("Either _id or authId must be provided");
263
+ return this.request("/deleteUser", "POST", params);
264
+ }
265
+ async revlmGate(payload) {
266
+ if (!payload || typeof payload !== "object") throw new Error("payload object is required");
267
+ return this.request("/revlm-gate", "POST", payload);
268
+ }
269
+ db(dbName) {
270
+ return new RevlmDBDatabase(dbName, this);
271
+ }
272
+ };
273
+ // Annotate the CommonJS export names for ESM import in node:
274
+ 0 && (module.exports = {
275
+ Revlm
276
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,249 @@
1
+ // src/Revlm.ts
2
+ import { EJSON } from "bson";
3
+ import { AuthClient } from "@kedaruma/revlm-shared";
4
+
5
+ // src/RevlmCollection.ts
6
+ var RevlmCollection = class {
7
+ _revlm;
8
+ _dbName;
9
+ _collection;
10
+ constructor(collection, dbName, revlm) {
11
+ this._collection = collection;
12
+ this._dbName = dbName;
13
+ this._revlm = revlm;
14
+ }
15
+ get name() {
16
+ return this._collection;
17
+ }
18
+ // Helper to call server revlm-gate and return parsed result or throw on error
19
+ async vg(method, params = {}) {
20
+ const payload = { db: this._dbName, collection: this._collection, method, ...params };
21
+ const res = await this._revlm.revlmGate(payload);
22
+ if (!res || !res.ok) {
23
+ const errMsg = res && (res.error || res.reason) ? res.error || res.reason : "revlm-gate error";
24
+ const e = new Error(String(errMsg));
25
+ e.response = res;
26
+ throw e;
27
+ }
28
+ return res.result;
29
+ }
30
+ async find(filter, options) {
31
+ const result = await this.vg("find", { filter: filter || {}, options: options || {} });
32
+ return Array.isArray(result) ? result : result || [];
33
+ }
34
+ async findOne(filter, options) {
35
+ const result = await this.vg("findOne", { filter: filter || {}, options: options || {} });
36
+ return result === void 0 ? null : result;
37
+ }
38
+ async findOneAndUpdate(filter, update, options) {
39
+ const result = await this.vg("findOneAndUpdate", { filter, update, options: options || {} });
40
+ return result && (result.value ?? result);
41
+ }
42
+ async findOneAndReplace(filter, replacement, options) {
43
+ const result = await this.vg("findOneAndReplace", { filter, replacement, options: options || {} });
44
+ return result && (result.value ?? result);
45
+ }
46
+ async findOneAndDelete(filter, options) {
47
+ const result = await this.vg("findOneAndDelete", { filter: filter || {}, options: options || {} });
48
+ return result && (result.value ?? result);
49
+ }
50
+ async aggregate(pipeline) {
51
+ return await this.vg("aggregate", { pipeline });
52
+ }
53
+ async count(filter, options) {
54
+ const result = await this.vg("count", { filter: filter || {}, options: options || {} });
55
+ return Number(result || 0);
56
+ }
57
+ async insertOne(document) {
58
+ const result = await this.vg("insertOne", { document });
59
+ return result;
60
+ }
61
+ async insertMany(documents) {
62
+ const result = await this.vg("insertMany", { documents });
63
+ return result;
64
+ }
65
+ async deleteOne(filter) {
66
+ const result = await this.vg("deleteOne", { filter: filter || {} });
67
+ return result;
68
+ }
69
+ async deleteMany(filter) {
70
+ const result = await this.vg("deleteMany", { filter: filter || {} });
71
+ return result;
72
+ }
73
+ async updateOne(filter, update, options) {
74
+ const result = await this.vg("updateOne", { filter, update, options: options || {} });
75
+ return result;
76
+ }
77
+ async updateMany(filter, update, options) {
78
+ const result = await this.vg("updateMany", { filter, update, options: options || {} });
79
+ return result;
80
+ }
81
+ // single watch implementation with optional options
82
+ async *watch(options) {
83
+ const arr = await this.vg("watch", { options: options || {} }) || [];
84
+ for (const it of Array.isArray(arr) ? arr : []) {
85
+ yield it;
86
+ }
87
+ }
88
+ };
89
+
90
+ // src/RevlmDBDatabase.ts
91
+ var RevlmDBDatabase = class {
92
+ _revlm;
93
+ _dbName;
94
+ constructor(dbName, revlm) {
95
+ this._dbName = dbName;
96
+ this._revlm = revlm;
97
+ }
98
+ collection(collection) {
99
+ return new RevlmCollection(collection, this._dbName, this._revlm);
100
+ }
101
+ };
102
+
103
+ // src/Revlm.ts
104
+ var Revlm = class {
105
+ baseUrl;
106
+ fetchImpl;
107
+ defaultHeaders;
108
+ _token;
109
+ provisionalEnabled;
110
+ provisionalAuthSecretMaster;
111
+ provisionalAuthDomain;
112
+ autoSetToken;
113
+ constructor(baseUrl, opts = {}) {
114
+ if (!baseUrl) throw new Error("baseUrl is required");
115
+ this.baseUrl = baseUrl.replace(/\/$/, "");
116
+ this.fetchImpl = opts.fetchImpl || (typeof fetch !== "undefined" ? fetch : void 0);
117
+ this.defaultHeaders = opts.defaultHeaders || {};
118
+ this.provisionalEnabled = opts.provisionalEnabled || false;
119
+ this.provisionalAuthSecretMaster = opts.provisionalAuthSecretMaster || "";
120
+ this.provisionalAuthDomain = opts.provisionalAuthDomain || "";
121
+ this.autoSetToken = opts.autoSetToken ?? true;
122
+ if (!this.fetchImpl) {
123
+ throw new Error("No fetch implementation available. Provide fetchImpl in options or run in Node 18+ with global fetch.");
124
+ }
125
+ }
126
+ setToken(token) {
127
+ this._token = token;
128
+ }
129
+ getToken() {
130
+ return this._token;
131
+ }
132
+ clearToken() {
133
+ this._token = void 0;
134
+ }
135
+ // Logout clears client-side token (simple, synchronous)
136
+ logout() {
137
+ this.clearToken();
138
+ }
139
+ // Call server to refresh token. Uses Authorization header with current token.
140
+ // On success, if autoSetToken is true and res.token is set, update the client token.
141
+ async refreshToken() {
142
+ if (!this._token) return { ok: false, error: "No token set" };
143
+ const res = await this.request("/refresh-token", "POST");
144
+ if (this.autoSetToken && res && res.ok && res.token) {
145
+ this.setToken(res.token);
146
+ }
147
+ return res;
148
+ }
149
+ // Verify current token with server. If invalid/expired, clear local token.
150
+ async verifyToken() {
151
+ if (!this._token) return { ok: false, error: "No token set" };
152
+ const res = await this.request("/verify-token", "POST");
153
+ const reason = res.reason || res.error;
154
+ if (res && !res.ok) {
155
+ if (reason === "invalid_token" || reason === "token_expired" || reason === "no_token" || res.status === 401 || res.status === 403) {
156
+ this.clearToken();
157
+ }
158
+ }
159
+ return res;
160
+ }
161
+ makeHeaders(hasBody) {
162
+ const headers = {
163
+ Accept: "application/ejson",
164
+ ...this.defaultHeaders
165
+ };
166
+ if (hasBody) {
167
+ headers["Content-Type"] = "application/ejson";
168
+ }
169
+ if (this._token) {
170
+ headers["Authorization"] = `Bearer ${this._token}`;
171
+ }
172
+ return headers;
173
+ }
174
+ async parseResponse(res) {
175
+ const text = await res.text();
176
+ if (!text) return null;
177
+ try {
178
+ return EJSON.parse(text);
179
+ } catch (e) {
180
+ }
181
+ try {
182
+ return JSON.parse(text);
183
+ } catch (e) {
184
+ return text;
185
+ }
186
+ }
187
+ async request(path, method = "POST", body) {
188
+ const url = path.startsWith("http") ? path : `${this.baseUrl}${path.startsWith("/") ? "" : "/"}${path}`;
189
+ const hasBody = body !== void 0;
190
+ const headers = this.makeHeaders(hasBody);
191
+ let serializedBody;
192
+ if (hasBody) {
193
+ serializedBody = EJSON.stringify(body);
194
+ }
195
+ try {
196
+ const res = await this.fetchImpl(url, {
197
+ method,
198
+ headers,
199
+ body: serializedBody
200
+ });
201
+ const parsed = await this.parseResponse(res);
202
+ const out = parsed && typeof parsed === "object" ? parsed : { ok: res.ok, result: parsed };
203
+ out.status = res.status;
204
+ return out;
205
+ } catch (err) {
206
+ return { ok: false, error: err?.message || String(err) };
207
+ }
208
+ }
209
+ async login(authId, password) {
210
+ if (!authId || !password) throw new Error("authId and password are required");
211
+ const res = await this.request("/login", "POST", { authId, password });
212
+ if (this.autoSetToken && res && res.ok && res.token) {
213
+ this.setToken(res.token);
214
+ }
215
+ return res;
216
+ }
217
+ async provisionalLogin(authId) {
218
+ if (!this.provisionalEnabled) {
219
+ throw new Error("provisional login is disabled by client configuration");
220
+ }
221
+ if (!authId) throw new Error("authId is required");
222
+ const provisionalClient = new AuthClient({ secretMaster: this.provisionalAuthSecretMaster, authDomain: this.provisionalAuthDomain });
223
+ const provisionalPassword = await provisionalClient.producePassword(String(Date.now() * 1e3));
224
+ const res = await this.request("/provisional-login", "POST", { authId, password: provisionalPassword });
225
+ if (this.autoSetToken && res && res.ok && res.token) {
226
+ this.setToken(res.token);
227
+ }
228
+ return res;
229
+ }
230
+ async registerUser(user, password) {
231
+ if (!user) throw new Error("user is required");
232
+ if (!password) throw new Error("password is required");
233
+ return this.request("/registerUser", "POST", { user, password });
234
+ }
235
+ async deleteUser(params) {
236
+ if (!params || !params._id && !params.authId) throw new Error("Either _id or authId must be provided");
237
+ return this.request("/deleteUser", "POST", params);
238
+ }
239
+ async revlmGate(payload) {
240
+ if (!payload || typeof payload !== "object") throw new Error("payload object is required");
241
+ return this.request("/revlm-gate", "POST", payload);
242
+ }
243
+ db(dbName) {
244
+ return new RevlmDBDatabase(dbName, this);
245
+ }
246
+ };
247
+ export {
248
+ Revlm
249
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kedaruma/revlm-client",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "private": false,
5
5
  "description": "TypeScript client SDK for talking to the Revlm server replacement for MongoDB Realm.",
6
6
  "main": "dist/index.js",
@@ -29,13 +29,13 @@
29
29
  "dependencies": {
30
30
  "bson": "^6.10.4",
31
31
  "dotenv": "^17.2.3",
32
- "@kedaruma/revlm-shared": "1.0.0"
32
+ "@kedaruma/revlm-shared": "1.0.2"
33
33
  },
34
34
  "devDependencies": {
35
35
  "tsup": "^8.5.1"
36
36
  },
37
37
  "scripts": {
38
- "build": "tsup src/index.ts --format cjs,esm --dts",
38
+ "build": "tsup src/index.ts --format cjs,esm --dts --tsconfig tsconfig.build.json",
39
39
  "clean": "rm -rf dist node_modules kedaruma-revlm-client-*.tgz",
40
40
  "test": "pnpm exec jest --config ../../jest.config.cjs packages/revlm-client/src/__tests__/ --runInBand --watchman=false --verbose"
41
41
  }