@offlinejs/types 0.1.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.
@@ -0,0 +1,289 @@
1
+ type RecordId = string;
2
+ declare const OFFLINEJS_PUBLIC_API_VERSION = "1.0.0";
3
+ declare const STORAGE_ADAPTER_CONTRACT_VERSION = 1;
4
+ declare const SYNC_TRANSPORT_CONTRACT_VERSION = 1;
5
+ type EntityRecord = {
6
+ id: RecordId;
7
+ [key: string]: unknown;
8
+ };
9
+ type PartialEntity<TRecord extends EntityRecord> = Partial<Omit<TRecord, "id">> & {
10
+ id?: RecordId;
11
+ };
12
+ type SortDirection = "asc" | "desc";
13
+ type QueryFilterValue = string | number | boolean | null | Array<string | number | boolean | null> | {
14
+ eq?: unknown;
15
+ ne?: unknown;
16
+ gt?: number | string;
17
+ gte?: number | string;
18
+ lt?: number | string;
19
+ lte?: number | string;
20
+ in?: unknown[];
21
+ contains?: string;
22
+ };
23
+ type QueryFilters<TRecord extends EntityRecord = EntityRecord> = Partial<Record<keyof TRecord, QueryFilterValue>>;
24
+ interface QueryOptions<TRecord extends EntityRecord = EntityRecord> {
25
+ filters?: QueryFilters<TRecord>;
26
+ limit?: number;
27
+ offset?: number;
28
+ orderBy?: keyof TRecord | string;
29
+ search?: string;
30
+ searchFields?: Array<keyof TRecord | string>;
31
+ sort?: SortDirection;
32
+ }
33
+ type IndexKind = "single" | "compound" | "fullText";
34
+ interface IndexDefinition<TRecord extends EntityRecord = EntityRecord> {
35
+ collection: string;
36
+ fields: Array<keyof TRecord | string>;
37
+ name: string;
38
+ unique?: boolean;
39
+ kind?: IndexKind;
40
+ }
41
+ interface PaginatedResult<TRecord extends EntityRecord> {
42
+ data: TRecord[];
43
+ limit: number;
44
+ offset: number;
45
+ total: number;
46
+ }
47
+ interface TransactionStore {
48
+ get<TRecord extends EntityRecord>(collection: string, id: RecordId): Promise<TRecord | null>;
49
+ set<TRecord extends EntityRecord>(collection: string, value: TRecord): Promise<void>;
50
+ delete(collection: string, id: RecordId): Promise<void>;
51
+ find<TRecord extends EntityRecord>(collection: string, query?: QueryOptions<TRecord>): Promise<TRecord[]>;
52
+ clear(collection?: string): Promise<void>;
53
+ }
54
+ interface StorageMigration {
55
+ name: string;
56
+ up(storage: TransactionStore): Promise<void>;
57
+ }
58
+ interface StorageAdapterCapabilities {
59
+ indexes?: boolean;
60
+ migrations?: boolean;
61
+ persistence?: "durable" | "ephemeral";
62
+ transactions?: "atomic" | "best-effort";
63
+ }
64
+ interface StorageAdapter {
65
+ readonly name: string;
66
+ readonly contractVersion?: typeof STORAGE_ADAPTER_CONTRACT_VERSION;
67
+ readonly capabilities?: StorageAdapterCapabilities;
68
+ get<TRecord extends EntityRecord>(collection: string, id: RecordId): Promise<TRecord | null>;
69
+ set<TRecord extends EntityRecord>(collection: string, value: TRecord): Promise<void>;
70
+ delete(collection: string, id: RecordId): Promise<void>;
71
+ find<TRecord extends EntityRecord>(collection: string, query?: QueryOptions<TRecord>): Promise<TRecord[]>;
72
+ clear(collection?: string): Promise<void>;
73
+ transaction<TValue>(scope: string[], run: (store: TransactionStore) => Promise<TValue>): Promise<TValue>;
74
+ migrate?(migrations: StorageMigration[]): Promise<void>;
75
+ }
76
+ interface IndexableStorageAdapter extends StorageAdapter {
77
+ createIndex?<TRecord extends EntityRecord>(definition: IndexDefinition<TRecord>): Promise<void>;
78
+ dropIndex?(collection: string, name: string): Promise<void>;
79
+ listIndexes?(collection?: string): Promise<IndexDefinition[]>;
80
+ }
81
+ type MutationOperation = "create" | "update" | "delete";
82
+ interface QueuedMutation<TRecord extends EntityRecord = EntityRecord> extends EntityRecord {
83
+ collection: string;
84
+ operation: MutationOperation;
85
+ recordId: RecordId;
86
+ payload?: PartialEntity<TRecord>;
87
+ base?: TRecord | null;
88
+ createdAt: number;
89
+ lastAttemptAt?: number;
90
+ priority: number;
91
+ retries: number;
92
+ status: "pending" | "processing" | "failed";
93
+ }
94
+ interface RetryOptions {
95
+ baseDelayMs: number;
96
+ factor: number;
97
+ jitter: boolean;
98
+ maxAttempts: number;
99
+ maxDelayMs: number;
100
+ }
101
+ interface QueueProcessingOptions {
102
+ batchSize: number;
103
+ retry: RetryOptions;
104
+ }
105
+ interface NetworkState {
106
+ online: boolean;
107
+ since: number;
108
+ }
109
+ interface NetworkMonitor {
110
+ getState(): NetworkState;
111
+ isOnline(): boolean;
112
+ subscribe(listener: (state: NetworkState) => void): () => void;
113
+ }
114
+ interface TransportRequest<TBody = unknown> {
115
+ body?: TBody;
116
+ headers?: Record<string, string>;
117
+ method: "DELETE" | "GET" | "PATCH" | "POST" | "PUT";
118
+ path: string;
119
+ query?: Record<string, string | number | boolean | undefined>;
120
+ timeoutMs?: number;
121
+ }
122
+ interface TransportResponse<TData = unknown> {
123
+ data: TData;
124
+ etag?: string;
125
+ status: number;
126
+ }
127
+ interface SyncTransport {
128
+ readonly contractVersion?: typeof SYNC_TRANSPORT_CONTRACT_VERSION;
129
+ request<TData = unknown, TBody = unknown>(request: TransportRequest<TBody>): Promise<TransportResponse<TData>>;
130
+ }
131
+ interface TransportMiddlewareContext<TBody = unknown> {
132
+ request: TransportRequest<TBody>;
133
+ }
134
+ type TransportMiddleware = <TBody = unknown>(context: TransportMiddlewareContext<TBody>) => Promise<TransportRequest<TBody>> | TransportRequest<TBody>;
135
+ interface TransportOptions {
136
+ baseURL: string;
137
+ fetch?: typeof fetch;
138
+ headers?: Record<string, string> | (() => Promise<Record<string, string>> | Record<string, string>);
139
+ middlewares?: TransportMiddleware[];
140
+ timeoutMs?: number;
141
+ }
142
+ /** Named built-in conflict strategies for better DX than raw strings. */
143
+ declare enum ConflictStrategyName {
144
+ ClientWins = "clientWins",
145
+ ServerWins = "serverWins",
146
+ LastWriteWins = "lastWriteWins",
147
+ Merge = "merge"
148
+ }
149
+ type ConflictStrategy<TRecord extends EntityRecord = EntityRecord> = ConflictStrategyName | `${ConflictStrategyName}` | ConflictResolver<TRecord>;
150
+ interface ConflictContext<TRecord extends EntityRecord = EntityRecord> {
151
+ client: TRecord | null;
152
+ collection: string;
153
+ mutation: QueuedMutation<TRecord>;
154
+ server: TRecord | null;
155
+ }
156
+ type ConflictResolver<TRecord extends EntityRecord = EntityRecord> = (context: ConflictContext<TRecord>) => Promise<TRecord | null> | TRecord | null;
157
+ interface SyncOptions<TRecord extends EntityRecord = EntityRecord> {
158
+ autoStart?: boolean;
159
+ batchSize?: number;
160
+ conflictStrategy?: ConflictStrategy<TRecord>;
161
+ deltaField?: string;
162
+ enabled?: boolean;
163
+ pull?: boolean;
164
+ push?: boolean;
165
+ retry?: Partial<RetryOptions>;
166
+ }
167
+ interface OfflineEvents {
168
+ "sync:start": {
169
+ mode: "push" | "pull" | "full";
170
+ queued: number;
171
+ };
172
+ "sync:end": {
173
+ completed: number;
174
+ failed: number;
175
+ };
176
+ offline: NetworkState;
177
+ online: NetworkState;
178
+ "queue:add": QueuedMutation;
179
+ "queue:complete": QueuedMutation;
180
+ conflict: ConflictContext;
181
+ error: Error;
182
+ "worker:message": WorkerSyncMessage;
183
+ "coordination:message": CoordinationMessage;
184
+ }
185
+ type OfflineEventName = keyof OfflineEvents;
186
+ interface EventBus<TEvents extends object = OfflineEvents> {
187
+ emit<TName extends keyof TEvents>(name: TName, payload: TEvents[TName]): void;
188
+ off<TName extends keyof TEvents>(name: TName, listener: (payload: TEvents[TName]) => void): void;
189
+ on<TName extends keyof TEvents>(name: TName, listener: (payload: TEvents[TName]) => void): () => void;
190
+ }
191
+ type CollectionSubscriber<TRecord extends EntityRecord> = (records: TRecord[]) => void;
192
+ interface OfflineCollection<TRecord extends EntityRecord> {
193
+ create(data: PartialEntity<TRecord>): Promise<TRecord>;
194
+ delete(id: RecordId): Promise<void>;
195
+ find(query?: QueryOptions<TRecord>): Promise<TRecord[]>;
196
+ findOne(id: RecordId): Promise<TRecord | null>;
197
+ paginate(query?: QueryOptions<TRecord>): Promise<PaginatedResult<TRecord>>;
198
+ subscribe(callback: CollectionSubscriber<TRecord>): () => void;
199
+ sync(): Promise<void>;
200
+ update(id: RecordId, data: PartialEntity<TRecord>): Promise<TRecord>;
201
+ }
202
+ type CollectionMap = object;
203
+ type CollectionRecord<TCollections extends CollectionMap, TName extends keyof TCollections> = TCollections[TName] extends EntityRecord ? TCollections[TName] : EntityRecord;
204
+ interface OfflineDB<TCollections extends CollectionMap = CollectionMap> extends EventBus<OfflineEvents> {
205
+ collection<TName extends Extract<keyof TCollections, string>>(name: TName): OfflineCollection<CollectionRecord<TCollections, TName>>;
206
+ collection<TRecord extends EntityRecord = EntityRecord>(name: string): OfflineCollection<TRecord>;
207
+ destroy(): Promise<void>;
208
+ sync(): Promise<void>;
209
+ transaction<TValue>(run: (db: OfflineDB<TCollections>) => Promise<TValue>): Promise<TValue>;
210
+ use(plugin: OfflinePlugin<TCollections>): OfflineDB<TCollections>;
211
+ }
212
+ interface OfflinePluginContext<TCollections extends CollectionMap = CollectionMap> {
213
+ db: OfflineDB<TCollections>;
214
+ events: EventBus<OfflineEvents>;
215
+ network: NetworkMonitor;
216
+ storage: StorageAdapter;
217
+ }
218
+ interface ValidationIssue {
219
+ code: string;
220
+ message: string;
221
+ path: string[];
222
+ }
223
+ interface ValidationResult {
224
+ issues: ValidationIssue[];
225
+ valid: boolean;
226
+ }
227
+ type SchemaValidator<TRecord extends EntityRecord = EntityRecord> = (record: PartialEntity<TRecord>, collection: string) => Promise<ValidationResult> | ValidationResult;
228
+ interface EncryptionCodec {
229
+ decrypt(value: Uint8Array): Promise<Uint8Array> | Uint8Array;
230
+ encrypt(value: Uint8Array): Promise<Uint8Array> | Uint8Array;
231
+ }
232
+ interface CoordinationMessage<TPayload = unknown> {
233
+ id: string;
234
+ payload: TPayload;
235
+ source: string;
236
+ timestamp: number;
237
+ type: string;
238
+ }
239
+ interface WorkerSyncMessage<TPayload = unknown> {
240
+ id: string;
241
+ payload?: TPayload;
242
+ timestamp: number;
243
+ type: "sync" | "pause" | "resume" | "status" | "shutdown";
244
+ }
245
+ interface SyncProtocolMutation<TRecord extends EntityRecord = EntityRecord> {
246
+ id: string;
247
+ collection: string;
248
+ operation: MutationOperation;
249
+ payload?: PartialEntity<TRecord>;
250
+ recordId: string;
251
+ }
252
+ interface SyncProtocolPushRequest<TRecord extends EntityRecord = EntityRecord> {
253
+ clientId: string;
254
+ mutations: Array<SyncProtocolMutation<TRecord>>;
255
+ since?: string | number;
256
+ }
257
+ interface SyncProtocolPushResponse<TRecord extends EntityRecord = EntityRecord> {
258
+ accepted: string[];
259
+ conflicts: Array<ConflictContext<TRecord>>;
260
+ rejected: Array<{
261
+ id: string;
262
+ reason: string;
263
+ }>;
264
+ }
265
+ interface SyncProtocolPullRequest {
266
+ clientId: string;
267
+ collection: string;
268
+ limit?: number;
269
+ since?: string | number;
270
+ }
271
+ interface SyncProtocolPullResponse<TRecord extends EntityRecord = EntityRecord> {
272
+ cursor?: string;
273
+ records: TRecord[];
274
+ }
275
+ interface OfflinePlugin<TCollections extends CollectionMap = CollectionMap> {
276
+ name: string;
277
+ setup(context: OfflinePluginContext<TCollections>): void | (() => void) | Promise<void | (() => void)>;
278
+ }
279
+ interface OfflineDBOptions<TCollections extends CollectionMap = CollectionMap> {
280
+ baseURL?: string;
281
+ headers?: Record<string, string> | (() => Promise<Record<string, string>> | Record<string, string>);
282
+ network?: NetworkMonitor;
283
+ plugins?: Array<OfflinePlugin<TCollections>>;
284
+ storage?: StorageAdapter;
285
+ sync?: SyncOptions;
286
+ transport?: SyncTransport;
287
+ }
288
+
289
+ export { type CollectionMap, type CollectionRecord, type CollectionSubscriber, type ConflictContext, type ConflictResolver, type ConflictStrategy, ConflictStrategyName, type CoordinationMessage, type EncryptionCodec, type EntityRecord, type EventBus, type IndexDefinition, type IndexKind, type IndexableStorageAdapter, type MutationOperation, type NetworkMonitor, type NetworkState, OFFLINEJS_PUBLIC_API_VERSION, type OfflineCollection, type OfflineDB, type OfflineDBOptions, type OfflineEventName, type OfflineEvents, type OfflinePlugin, type OfflinePluginContext, type PaginatedResult, type PartialEntity, type QueryFilterValue, type QueryFilters, type QueryOptions, type QueueProcessingOptions, type QueuedMutation, type RecordId, type RetryOptions, STORAGE_ADAPTER_CONTRACT_VERSION, SYNC_TRANSPORT_CONTRACT_VERSION, type SchemaValidator, type SortDirection, type StorageAdapter, type StorageAdapterCapabilities, type StorageMigration, type SyncOptions, type SyncProtocolMutation, type SyncProtocolPullRequest, type SyncProtocolPullResponse, type SyncProtocolPushRequest, type SyncProtocolPushResponse, type SyncTransport, type TransactionStore, type TransportMiddleware, type TransportMiddlewareContext, type TransportOptions, type TransportRequest, type TransportResponse, type ValidationIssue, type ValidationResult, type WorkerSyncMessage };
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ // src/index.ts
2
+ var OFFLINEJS_PUBLIC_API_VERSION = "1.0.0";
3
+ var STORAGE_ADAPTER_CONTRACT_VERSION = 1;
4
+ var SYNC_TRANSPORT_CONTRACT_VERSION = 1;
5
+ var ConflictStrategyName = /* @__PURE__ */ ((ConflictStrategyName2) => {
6
+ ConflictStrategyName2["ClientWins"] = "clientWins";
7
+ ConflictStrategyName2["ServerWins"] = "serverWins";
8
+ ConflictStrategyName2["LastWriteWins"] = "lastWriteWins";
9
+ ConflictStrategyName2["Merge"] = "merge";
10
+ return ConflictStrategyName2;
11
+ })(ConflictStrategyName || {});
12
+
13
+ export { ConflictStrategyName, OFFLINEJS_PUBLIC_API_VERSION, STORAGE_ADAPTER_CONTRACT_VERSION, SYNC_TRANSPORT_CONTRACT_VERSION };
14
+ //# sourceMappingURL=index.js.map
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":["ConflictStrategyName"],"mappings":";AAEO,IAAM,4BAAA,GAA+B;AACrC,IAAM,gCAAA,GAAmC;AACzC,IAAM,+BAAA,GAAkC;AA4LxC,IAAK,oBAAA,qBAAAA,qBAAAA,KAAL;AACL,EAAAA,sBAAA,YAAA,CAAA,GAAa,YAAA;AACb,EAAAA,sBAAA,YAAA,CAAA,GAAa,YAAA;AACb,EAAAA,sBAAA,eAAA,CAAA,GAAgB,eAAA;AAChB,EAAAA,sBAAA,OAAA,CAAA,GAAQ,OAAA;AAJE,EAAA,OAAAA,qBAAAA;AAAA,CAAA,EAAA,oBAAA,IAAA,EAAA","file":"index.js","sourcesContent":["export type RecordId = string;\n\nexport const OFFLINEJS_PUBLIC_API_VERSION = \"1.0.0\";\nexport const STORAGE_ADAPTER_CONTRACT_VERSION = 1;\nexport const SYNC_TRANSPORT_CONTRACT_VERSION = 1;\n\nexport type EntityRecord = {\n id: RecordId;\n [key: string]: unknown;\n};\n\nexport type PartialEntity<TRecord extends EntityRecord> = Partial<Omit<TRecord, \"id\">> & {\n id?: RecordId;\n};\n\nexport type SortDirection = \"asc\" | \"desc\";\n\nexport type QueryFilterValue =\n | string\n | number\n | boolean\n | null\n | Array<string | number | boolean | null>\n | {\n eq?: unknown;\n ne?: unknown;\n gt?: number | string;\n gte?: number | string;\n lt?: number | string;\n lte?: number | string;\n in?: unknown[];\n contains?: string;\n };\n\nexport type QueryFilters<TRecord extends EntityRecord = EntityRecord> = Partial<\n Record<keyof TRecord, QueryFilterValue>\n>;\n\nexport interface QueryOptions<TRecord extends EntityRecord = EntityRecord> {\n filters?: QueryFilters<TRecord>;\n limit?: number;\n offset?: number;\n orderBy?: keyof TRecord | string;\n search?: string;\n searchFields?: Array<keyof TRecord | string>;\n sort?: SortDirection;\n}\n\nexport type IndexKind = \"single\" | \"compound\" | \"fullText\";\n\nexport interface IndexDefinition<TRecord extends EntityRecord = EntityRecord> {\n collection: string;\n fields: Array<keyof TRecord | string>;\n name: string;\n unique?: boolean;\n kind?: IndexKind;\n}\n\nexport interface PaginatedResult<TRecord extends EntityRecord> {\n data: TRecord[];\n limit: number;\n offset: number;\n total: number;\n}\n\nexport interface TransactionStore {\n get<TRecord extends EntityRecord>(collection: string, id: RecordId): Promise<TRecord | null>;\n set<TRecord extends EntityRecord>(collection: string, value: TRecord): Promise<void>;\n delete(collection: string, id: RecordId): Promise<void>;\n find<TRecord extends EntityRecord>(\n collection: string,\n query?: QueryOptions<TRecord>\n ): Promise<TRecord[]>;\n clear(collection?: string): Promise<void>;\n}\n\nexport interface StorageMigration {\n name: string;\n up(storage: TransactionStore): Promise<void>;\n}\n\nexport interface StorageAdapterCapabilities {\n indexes?: boolean;\n migrations?: boolean;\n persistence?: \"durable\" | \"ephemeral\";\n transactions?: \"atomic\" | \"best-effort\";\n}\n\nexport interface StorageAdapter {\n readonly name: string;\n readonly contractVersion?: typeof STORAGE_ADAPTER_CONTRACT_VERSION;\n readonly capabilities?: StorageAdapterCapabilities;\n get<TRecord extends EntityRecord>(collection: string, id: RecordId): Promise<TRecord | null>;\n set<TRecord extends EntityRecord>(collection: string, value: TRecord): Promise<void>;\n delete(collection: string, id: RecordId): Promise<void>;\n find<TRecord extends EntityRecord>(\n collection: string,\n query?: QueryOptions<TRecord>\n ): Promise<TRecord[]>;\n clear(collection?: string): Promise<void>;\n transaction<TValue>(\n scope: string[],\n run: (store: TransactionStore) => Promise<TValue>\n ): Promise<TValue>;\n migrate?(migrations: StorageMigration[]): Promise<void>;\n}\n\nexport interface IndexableStorageAdapter extends StorageAdapter {\n createIndex?<TRecord extends EntityRecord>(definition: IndexDefinition<TRecord>): Promise<void>;\n dropIndex?(collection: string, name: string): Promise<void>;\n listIndexes?(collection?: string): Promise<IndexDefinition[]>;\n}\n\nexport type MutationOperation = \"create\" | \"update\" | \"delete\";\n\nexport interface QueuedMutation<TRecord extends EntityRecord = EntityRecord> extends EntityRecord {\n collection: string;\n operation: MutationOperation;\n recordId: RecordId;\n payload?: PartialEntity<TRecord>;\n base?: TRecord | null;\n createdAt: number;\n lastAttemptAt?: number;\n priority: number;\n retries: number;\n status: \"pending\" | \"processing\" | \"failed\";\n}\n\nexport interface RetryOptions {\n baseDelayMs: number;\n factor: number;\n jitter: boolean;\n maxAttempts: number;\n maxDelayMs: number;\n}\n\nexport interface QueueProcessingOptions {\n batchSize: number;\n retry: RetryOptions;\n}\n\nexport interface NetworkState {\n online: boolean;\n since: number;\n}\n\nexport interface NetworkMonitor {\n getState(): NetworkState;\n isOnline(): boolean;\n subscribe(listener: (state: NetworkState) => void): () => void;\n}\n\nexport interface TransportRequest<TBody = unknown> {\n body?: TBody;\n headers?: Record<string, string>;\n method: \"DELETE\" | \"GET\" | \"PATCH\" | \"POST\" | \"PUT\";\n path: string;\n query?: Record<string, string | number | boolean | undefined>;\n timeoutMs?: number;\n}\n\nexport interface TransportResponse<TData = unknown> {\n data: TData;\n etag?: string;\n status: number;\n}\n\nexport interface SyncTransport {\n readonly contractVersion?: typeof SYNC_TRANSPORT_CONTRACT_VERSION;\n request<TData = unknown, TBody = unknown>(\n request: TransportRequest<TBody>\n ): Promise<TransportResponse<TData>>;\n}\n\nexport interface TransportMiddlewareContext<TBody = unknown> {\n request: TransportRequest<TBody>;\n}\n\nexport type TransportMiddleware = <TBody = unknown>(\n context: TransportMiddlewareContext<TBody>\n) => Promise<TransportRequest<TBody>> | TransportRequest<TBody>;\n\nexport interface TransportOptions {\n baseURL: string;\n fetch?: typeof fetch;\n headers?:\n Record<string, string> | (() => Promise<Record<string, string>> | Record<string, string>);\n middlewares?: TransportMiddleware[];\n timeoutMs?: number;\n}\n\n/** Named built-in conflict strategies for better DX than raw strings. */\nexport enum ConflictStrategyName {\n ClientWins = \"clientWins\",\n ServerWins = \"serverWins\",\n LastWriteWins = \"lastWriteWins\",\n Merge = \"merge\"\n}\n\nexport type ConflictStrategy<TRecord extends EntityRecord = EntityRecord> =\n | ConflictStrategyName\n | `${ConflictStrategyName}`\n | ConflictResolver<TRecord>;\n\nexport interface ConflictContext<TRecord extends EntityRecord = EntityRecord> {\n client: TRecord | null;\n collection: string;\n mutation: QueuedMutation<TRecord>;\n server: TRecord | null;\n}\n\nexport type ConflictResolver<TRecord extends EntityRecord = EntityRecord> = (\n context: ConflictContext<TRecord>\n) => Promise<TRecord | null> | TRecord | null;\n\nexport interface SyncOptions<TRecord extends EntityRecord = EntityRecord> {\n autoStart?: boolean;\n batchSize?: number;\n conflictStrategy?: ConflictStrategy<TRecord>;\n deltaField?: string;\n enabled?: boolean;\n pull?: boolean;\n push?: boolean;\n retry?: Partial<RetryOptions>;\n}\n\nexport interface OfflineEvents {\n \"sync:start\": { mode: \"push\" | \"pull\" | \"full\"; queued: number };\n \"sync:end\": { completed: number; failed: number };\n offline: NetworkState;\n online: NetworkState;\n \"queue:add\": QueuedMutation;\n \"queue:complete\": QueuedMutation;\n conflict: ConflictContext;\n error: Error;\n \"worker:message\": WorkerSyncMessage;\n \"coordination:message\": CoordinationMessage;\n}\n\nexport type OfflineEventName = keyof OfflineEvents;\n\nexport interface EventBus<TEvents extends object = OfflineEvents> {\n emit<TName extends keyof TEvents>(name: TName, payload: TEvents[TName]): void;\n off<TName extends keyof TEvents>(name: TName, listener: (payload: TEvents[TName]) => void): void;\n on<TName extends keyof TEvents>(\n name: TName,\n listener: (payload: TEvents[TName]) => void\n ): () => void;\n}\n\nexport type CollectionSubscriber<TRecord extends EntityRecord> = (records: TRecord[]) => void;\n\nexport interface OfflineCollection<TRecord extends EntityRecord> {\n create(data: PartialEntity<TRecord>): Promise<TRecord>;\n delete(id: RecordId): Promise<void>;\n find(query?: QueryOptions<TRecord>): Promise<TRecord[]>;\n findOne(id: RecordId): Promise<TRecord | null>;\n paginate(query?: QueryOptions<TRecord>): Promise<PaginatedResult<TRecord>>;\n subscribe(callback: CollectionSubscriber<TRecord>): () => void;\n sync(): Promise<void>;\n update(id: RecordId, data: PartialEntity<TRecord>): Promise<TRecord>;\n}\n\nexport type CollectionMap = object;\n\nexport type CollectionRecord<\n TCollections extends CollectionMap,\n TName extends keyof TCollections\n> = TCollections[TName] extends EntityRecord ? TCollections[TName] : EntityRecord;\n\nexport interface OfflineDB<\n TCollections extends CollectionMap = CollectionMap\n> extends EventBus<OfflineEvents> {\n collection<TName extends Extract<keyof TCollections, string>>(\n name: TName\n ): OfflineCollection<CollectionRecord<TCollections, TName>>;\n collection<TRecord extends EntityRecord = EntityRecord>(name: string): OfflineCollection<TRecord>;\n destroy(): Promise<void>;\n sync(): Promise<void>;\n transaction<TValue>(run: (db: OfflineDB<TCollections>) => Promise<TValue>): Promise<TValue>;\n use(plugin: OfflinePlugin<TCollections>): OfflineDB<TCollections>;\n}\n\nexport interface OfflinePluginContext<TCollections extends CollectionMap = CollectionMap> {\n db: OfflineDB<TCollections>;\n events: EventBus<OfflineEvents>;\n network: NetworkMonitor;\n storage: StorageAdapter;\n}\n\nexport interface ValidationIssue {\n code: string;\n message: string;\n path: string[];\n}\n\nexport interface ValidationResult {\n issues: ValidationIssue[];\n valid: boolean;\n}\n\nexport type SchemaValidator<TRecord extends EntityRecord = EntityRecord> = (\n record: PartialEntity<TRecord>,\n collection: string\n) => Promise<ValidationResult> | ValidationResult;\n\nexport interface EncryptionCodec {\n decrypt(value: Uint8Array): Promise<Uint8Array> | Uint8Array;\n encrypt(value: Uint8Array): Promise<Uint8Array> | Uint8Array;\n}\n\nexport interface CoordinationMessage<TPayload = unknown> {\n id: string;\n payload: TPayload;\n source: string;\n timestamp: number;\n type: string;\n}\n\nexport interface WorkerSyncMessage<TPayload = unknown> {\n id: string;\n payload?: TPayload;\n timestamp: number;\n type: \"sync\" | \"pause\" | \"resume\" | \"status\" | \"shutdown\";\n}\n\nexport interface SyncProtocolMutation<TRecord extends EntityRecord = EntityRecord> {\n id: string;\n collection: string;\n operation: MutationOperation;\n payload?: PartialEntity<TRecord>;\n recordId: string;\n}\n\nexport interface SyncProtocolPushRequest<TRecord extends EntityRecord = EntityRecord> {\n clientId: string;\n mutations: Array<SyncProtocolMutation<TRecord>>;\n since?: string | number;\n}\n\nexport interface SyncProtocolPushResponse<TRecord extends EntityRecord = EntityRecord> {\n accepted: string[];\n conflicts: Array<ConflictContext<TRecord>>;\n rejected: Array<{ id: string; reason: string }>;\n}\n\nexport interface SyncProtocolPullRequest {\n clientId: string;\n collection: string;\n limit?: number;\n since?: string | number;\n}\n\nexport interface SyncProtocolPullResponse<TRecord extends EntityRecord = EntityRecord> {\n cursor?: string;\n records: TRecord[];\n}\n\nexport interface OfflinePlugin<TCollections extends CollectionMap = CollectionMap> {\n name: string;\n setup(\n context: OfflinePluginContext<TCollections>\n ): void | (() => void) | Promise<void | (() => void)>;\n}\n\nexport interface OfflineDBOptions<TCollections extends CollectionMap = CollectionMap> {\n baseURL?: string;\n headers?:\n Record<string, string> | (() => Promise<Record<string, string>> | Record<string, string>);\n network?: NetworkMonitor;\n plugins?: Array<OfflinePlugin<TCollections>>;\n storage?: StorageAdapter;\n sync?: SyncOptions;\n transport?: SyncTransport;\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@offlinejs/types",
3
+ "version": "0.1.0",
4
+ "description": "Shared TypeScript contracts for OfflineJS packages.",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsup",
18
+ "typecheck": "tsc --noEmit"
19
+ },
20
+ "devDependencies": {
21
+ "tsup": "latest",
22
+ "typescript": "latest"
23
+ },
24
+ "publishConfig": {
25
+ "access": "public",
26
+ "registry": "https://registry.npmjs.org/"
27
+ }
28
+ }