@quranjs/api 3.7.0 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -82,6 +82,82 @@ the same event IDs so downstream processing can identify duplicates.
82
82
 
83
83
  For browser or mobile apps, use `@quranjs/api/public`. Public usage docs live in the API docs portal.
84
84
 
85
+ ### App State
86
+
87
+ App State stores app-owned JSON documents for signed-in users. It is available
88
+ from both runtime entrypoints under `client.auth.v1.appState`. Read the enabled
89
+ data groups before writing, use a fresh high-entropy idempotency key for each
90
+ logical mutation, and store quoted ETags unchanged.
91
+
92
+ ```typescript
93
+ const config = await client.auth.v1.appState.getConfiguration();
94
+
95
+ const created = await client.auth.v1.appState.putDocument(
96
+ "settings",
97
+ "theme",
98
+ { value: { mode: "dark" }, schemaVersion: 1 },
99
+ { idempotencyKey: crypto.randomUUID(), ifNoneMatch: "*" },
100
+ );
101
+
102
+ const current = await client.auth.v1.appState.getDocument("settings", "theme");
103
+ await client.auth.v1.appState.putDocument(
104
+ "settings",
105
+ "theme",
106
+ { value: { mode: "light" }, schemaVersion: 1 },
107
+ { idempotencyKey: crypto.randomUUID(), ifMatch: current.etag! },
108
+ );
109
+ ```
110
+
111
+ For offline startup, page through `bootstrap()` until `hasMore` is false and
112
+ then persist `nextSyncToken`. Apply each `getChanges()` page and its next token
113
+ atomically. On HTTP 410, preserve pending writes, bootstrap and drain changes,
114
+ replay pending writes, and then pull again. An unchanged replay request retains
115
+ its idempotency key; a conflict rebase rotates it with the changed fingerprint.
116
+
117
+ For transactional offline reconciliation, provide an account-scoped durable
118
+ `AppStateStore`. Its `transaction(accountId, reducer)` implementation must
119
+ initialize missing accounts, run the reducer synchronously, and atomically
120
+ commit the complete draft only when the reducer returns successfully. Reducers
121
+ must not perform network I/O. The reconciler stages bootstrap pages separately,
122
+ applies change pages with their tokens atomically, replays immutable local
123
+ replacements, and rejects responses from an account that is no longer active.
124
+
125
+ ```typescript
126
+ import { createAppStateReconciler } from "@quranjs/api/public";
127
+
128
+ const appState = createAppStateReconciler({
129
+ accountId: signedInAccountId, // Explicit identity; never derive it from a token.
130
+ store: durableAppStateStore,
131
+ transport: client.auth.v1.appState,
132
+ });
133
+
134
+ await appState.putDocument("settings", "theme", {
135
+ schemaVersion: 1,
136
+ value: { mode: "dark" },
137
+ });
138
+ await appState.reconcile();
139
+
140
+ const state = await appState.getState();
141
+ const theme = state.visible["settings/theme"];
142
+
143
+ await appState.switchAccount(
144
+ nextSignedInAccountId,
145
+ nextAccountClient.auth.v1.appState,
146
+ );
147
+ ```
148
+
149
+ Account switching replaces the local account boundary and transport atomically. Create a separate
150
+ client/transport whose immutable session belongs to the target account; do not pass a facade that
151
+ reads a mutable cross-account session at request time. An in-flight request retains the transport
152
+ captured for its original account, and its late result cannot commit after the generation changes.
153
+
154
+ `putDocument()` and `deleteDocument()` only queue local mutations. Call
155
+ `reconcile()` to pull, replay the captured pending set, and pull again. Calls to
156
+ `reconcile()` are serialized, while local queue writes remain available. On a
157
+ strict `412` conflict, the complete replacement is rebased onto the refreshed
158
+ ETag with a new idempotency key. `createAppStateMemoryStore()` is available for
159
+ tests and short-lived sessions; it is not durable across process restarts.
160
+
85
161
  Existing `QuranClient` imports from `@quranjs/api` remain supported for backwards compatibility:
86
162
 
87
163
  ```typescript
@@ -135,6 +211,24 @@ Mushaf snapshots include layout metadata, pages, publicly distributable font
135
211
  assets, and words. Store the final `nextSyncToken` and use it with the same
136
212
  `resources` filter on subsequent sync calls.
137
213
 
214
+ Word-by-word transliterations use their resource content ID and expose a typed,
215
+ camel-cased snapshot payload:
216
+
217
+ ```ts
218
+ import type { WordByWordTransliterationSnapshotRecord } from "@quranjs/api";
219
+
220
+ await client.resources.sync({
221
+ bootstrap: true,
222
+ resources: "word_by_word_transliterations:60",
223
+ });
224
+
225
+ const transliterations =
226
+ await client.resources.findSnapshot<WordByWordTransliterationSnapshotRecord>(
227
+ "word_by_word_transliterations",
228
+ 60,
229
+ );
230
+ ```
231
+
138
232
  ## Links
139
233
 
140
234
  - [Quran Foundation](https://quran.foundation) — Our mission to make the Quran accessible to everyone
@@ -0,0 +1,528 @@
1
+ type ApiParams = Record<string, string | number | boolean | unknown[] | undefined | Record<string, boolean>>;
2
+ /**
3
+ * Base parameters that are common across most API endpoints
4
+ */
5
+ interface BaseApiParams extends ApiParams {
6
+ /** Language for the response */
7
+ language?: Language;
8
+ }
9
+ /**
10
+ * Pagination parameters
11
+ */
12
+ interface PaginationParams extends ApiParams {
13
+ /** Page number for pagination */
14
+ page?: number;
15
+ /** Number of items per page */
16
+ perPage?: number;
17
+ }
18
+ type BinaryString = "0" | "1";
19
+ declare enum SearchMode {
20
+ Advanced = "advanced",
21
+ Quick = "quick"
22
+ }
23
+ /**
24
+ * Search parameters
25
+ */
26
+ interface SearchParams extends BaseApiParams {
27
+ /** Search mode */
28
+ mode: SearchMode;
29
+ /** Search query */
30
+ query: string;
31
+ /** Filter translations */
32
+ filterTranslations?: string | string[];
33
+ /** For advanced search, limit to exact matches */
34
+ exactMatchesOnly?: BinaryString;
35
+ /** Include text in the response */
36
+ getText?: BinaryString;
37
+ /** Include highlighted text */
38
+ highlight?: BinaryString;
39
+ /** Quick search navigational results count */
40
+ navigationalResultsNumber?: number;
41
+ /** Quick search verse results count */
42
+ versesResultsNumber?: number;
43
+ /** Comma-separated list of indexes */
44
+ indexes?: string | string[];
45
+ /** Page number for pagination */
46
+ page?: number;
47
+ /** Number of results to return */
48
+ size?: number;
49
+ /** Translation IDs to use for language detection */
50
+ translationIds?: string | number | Array<string | number>;
51
+ /** Quran fields to include in verse filters */
52
+ fields?: Partial<Record<VerseField, boolean>>;
53
+ /** Translation fields to include in verse filters */
54
+ translationFields?: Partial<Record<TranslationField, boolean>>;
55
+ /** Word fields to include in verse filters */
56
+ wordFields?: Partial<Record<WordField, boolean>>;
57
+ /** Include word data in verse filters */
58
+ words?: boolean;
59
+ }
60
+
61
+ type AppStateJsonValue = boolean | number | string | null | AppStateJsonValue[] | {
62
+ [key: string]: AppStateJsonValue;
63
+ };
64
+ interface AppStateSuccess<T> {
65
+ data: T;
66
+ success: true;
67
+ }
68
+ type AppStateResponse<T> = AppStateSuccess<T> & {
69
+ /** Opaque quoted ETag. Store and send it unchanged. */
70
+ etag: string | null;
71
+ /** HTTP 200 for a read/replacement or 201 for a newly created document. */
72
+ status: number;
73
+ };
74
+ interface AppStateCollection {
75
+ maxDocumentsPerUser: number;
76
+ name: string;
77
+ requiresPrecondition: boolean;
78
+ }
79
+ interface AppStateLimits {
80
+ changeRetentionDays: number;
81
+ maxDocumentBytes: number;
82
+ maxDocumentsPerUser: number;
83
+ quotaBytesPerUser: number;
84
+ }
85
+ interface AppStateConfiguration {
86
+ collections: AppStateCollection[];
87
+ configVersion: number;
88
+ limits: AppStateLimits;
89
+ }
90
+ interface AppStateDocument {
91
+ collection: string;
92
+ key: string;
93
+ schemaVersion: number;
94
+ updatedAt: string;
95
+ value: AppStateJsonValue;
96
+ version: number;
97
+ }
98
+ interface AppStateDocumentWithEtag extends AppStateDocument {
99
+ etag: string;
100
+ }
101
+ interface AppStateMutationResult {
102
+ collection: string;
103
+ key: string;
104
+ schemaVersion: number;
105
+ updatedAt: string;
106
+ version: number;
107
+ }
108
+ interface AppStatePage {
109
+ hasMore: boolean;
110
+ items: AppStateDocumentWithEtag[];
111
+ nextCursor: string | null;
112
+ }
113
+ interface AppStateBootstrapPage extends AppStatePage {
114
+ nextSyncToken: string | null;
115
+ }
116
+ interface AppStateChange extends AppStateDocumentWithEtag {
117
+ operation: "delete" | "upsert";
118
+ }
119
+ interface AppStateChangesPage {
120
+ changes: AppStateChange[];
121
+ hasMore: boolean;
122
+ nextSyncToken: string;
123
+ }
124
+ interface AppStatePageOptions extends ApiParams {
125
+ cursor?: string;
126
+ limit?: number;
127
+ }
128
+ interface AppStateChangesOptions extends ApiParams {
129
+ limit?: number;
130
+ }
131
+ interface AppStatePutBody {
132
+ schemaVersion: number;
133
+ value: AppStateJsonValue;
134
+ }
135
+ type AppStatePrecondition = {
136
+ ifMatch: string;
137
+ ifNoneMatch?: never;
138
+ } | {
139
+ ifMatch?: never;
140
+ ifNoneMatch: string;
141
+ } | {
142
+ ifMatch?: never;
143
+ ifNoneMatch?: never;
144
+ };
145
+ type AppStateMutationOptions = {
146
+ idempotencyKey: string;
147
+ } & AppStatePrecondition;
148
+ /** Structural low-level transport used by App State reconciliation clients. */
149
+ interface AppStateTransport {
150
+ bootstrap(options?: AppStatePageOptions): Promise<AppStateSuccess<AppStateBootstrapPage>>;
151
+ deleteDocument(collection: string, key: string, options: AppStateMutationOptions): Promise<void>;
152
+ getChanges(since: string, options?: AppStateChangesOptions): Promise<AppStateSuccess<AppStateChangesPage>>;
153
+ getConfiguration(): Promise<AppStateSuccess<AppStateConfiguration>>;
154
+ getDocument(collection: string, key: string): Promise<AppStateResponse<AppStateDocument>>;
155
+ listDocuments(collection: string, options?: AppStatePageOptions): Promise<AppStateSuccess<AppStatePage>>;
156
+ putDocument(collection: string, key: string, body: AppStatePutBody, options: AppStateMutationOptions): Promise<AppStateResponse<AppStateMutationResult>>;
157
+ }
158
+ type AppStateStoredDocument = AppStateChange;
159
+ interface AppStatePendingMutationBase {
160
+ collection: string;
161
+ idempotencyKey: string;
162
+ ifMatch?: string;
163
+ ifNoneMatch?: string;
164
+ key: string;
165
+ localRevision: number;
166
+ }
167
+ interface AppStatePendingPut extends AppStatePendingMutationBase {
168
+ body: AppStatePutBody;
169
+ method: "PUT";
170
+ }
171
+ interface AppStatePendingDelete extends AppStatePendingMutationBase {
172
+ method: "DELETE";
173
+ }
174
+ type AppStatePendingMutation = AppStatePendingDelete | AppStatePendingPut;
175
+ interface AppStateAccountState {
176
+ bootstrapCursor: string | null;
177
+ localRevision: number;
178
+ pendingMutations: AppStatePendingMutation[];
179
+ shadow: Record<string, AppStateStoredDocument>;
180
+ stagingBootstrap: Record<string, AppStateStoredDocument> | null;
181
+ syncToken: string | null;
182
+ }
183
+ interface AppStateVisibleDocument {
184
+ collection: string;
185
+ etag: string | null;
186
+ key: string;
187
+ pending: boolean;
188
+ schemaVersion: number;
189
+ updatedAt: string | null;
190
+ value: AppStateJsonValue;
191
+ version: number | null;
192
+ }
193
+ interface AppStateStateView extends AppStateAccountState {
194
+ visible: Record<string, AppStateVisibleDocument>;
195
+ }
196
+ type AppStateStoreReducer<T> = (state: AppStateAccountState) => T;
197
+ /**
198
+ * Account-scoped durable storage for the reconciliation engine. Implementations
199
+ * must initialize missing accounts and commit a reducer's complete synchronous
200
+ * state transition atomically. If the reducer throws, no state may be changed.
201
+ */
202
+ interface AppStateStore {
203
+ transaction<T>(accountId: string, reducer: AppStateStoreReducer<T>): Promise<T>;
204
+ }
205
+ interface AppStateReconcilerOptions {
206
+ accountId: string;
207
+ createIdempotencyKey?: () => string;
208
+ maxRebaseAttempts?: number;
209
+ pageSize?: number;
210
+ store: AppStateStore;
211
+ transport: AppStateTransport;
212
+ }
213
+ interface AppStateReconciler {
214
+ deleteDocument(collection: string, key: string): Promise<AppStateStateView>;
215
+ getState(): Promise<AppStateStateView>;
216
+ putDocument(collection: string, key: string, body: AppStatePutBody): Promise<AppStateStateView>;
217
+ reconcile(): Promise<AppStateStateView>;
218
+ /**
219
+ * Atomically switch the local account boundary and the transport whose
220
+ * credentials are bound to that account. The transport must not read a
221
+ * mutable cross-account session at request time.
222
+ */
223
+ switchAccount(accountId: string, transport: AppStateTransport): Promise<AppStateStateView>;
224
+ }
225
+
226
+ type AuthService = "auth" | "quranReflect";
227
+
228
+ /**
229
+ * Custom fetcher function type that matches the native fetch API
230
+ */
231
+ type CustomFetcher = typeof fetch;
232
+ type RuntimeMode = "server" | "public";
233
+ type HTTPMethod = "DELETE" | "GET" | "PATCH" | "POST" | "PUT";
234
+ interface QuranFetchClient {
235
+ fetch<T = unknown>(url: string, params?: ApiParams): Promise<T>;
236
+ }
237
+ type ApiService = "analytics" | "content" | "search" | AuthService | "oauth2";
238
+ interface ServiceEnvironmentConfig {
239
+ gatewayUrl?: string;
240
+ tokenHost?: string;
241
+ oauth2BaseUrl?: string;
242
+ analyticsBaseUrl?: string;
243
+ contentBaseUrl?: string;
244
+ searchBaseUrl?: string;
245
+ authBaseUrl?: string;
246
+ quranReflectBaseUrl?: string;
247
+ }
248
+ interface QuranClientConfig {
249
+ /** Client ID for authentication */
250
+ clientId: string;
251
+ /** Client secret for authentication */
252
+ clientSecret: string;
253
+ /** Legacy gateway base URL for content/search APIs */
254
+ contentBaseUrl?: string;
255
+ /** Legacy OAuth2 token host URL */
256
+ authBaseUrl?: string;
257
+ /** Custom fetch implementation */
258
+ fetch?: CustomFetcher;
259
+ /** Default parameters for all API calls */
260
+ defaults?: Partial<BaseApiParams>;
261
+ }
262
+ interface UserSession {
263
+ accessToken: string;
264
+ refreshToken?: string;
265
+ idToken?: string;
266
+ scope?: string;
267
+ tokenType?: string;
268
+ expiresAt?: number;
269
+ }
270
+ interface TokenStorage {
271
+ getSession?: () => UserSession | null | undefined | Promise<UserSession | null | undefined>;
272
+ setSession?: (session: UserSession | null) => void | Promise<void>;
273
+ clearSession?: () => void | Promise<void>;
274
+ }
275
+ interface BaseRuntimeClientConfig {
276
+ clientId: string;
277
+ fetch?: CustomFetcher;
278
+ defaults?: Partial<BaseApiParams>;
279
+ services?: ServiceEnvironmentConfig;
280
+ userSession?: UserSession;
281
+ storage?: TokenStorage;
282
+ }
283
+ interface ServerClientConfig extends BaseRuntimeClientConfig {
284
+ clientSecret: string;
285
+ }
286
+ interface PublicClientConfig extends BaseRuntimeClientConfig {
287
+ clientType: "public" | "confidential-proxy";
288
+ }
289
+ interface CachedToken {
290
+ value: string;
291
+ expiresAt: number;
292
+ }
293
+ interface TokenResponse {
294
+ access_token: string;
295
+ token_type?: string;
296
+ expires_in: number;
297
+ refresh_token?: string;
298
+ id_token?: string;
299
+ scope?: string;
300
+ }
301
+ interface OperationRequest {
302
+ path?: Record<string, string | number>;
303
+ query?: ApiParams;
304
+ body?: string | URLSearchParams | Record<string, unknown> | null;
305
+ headers?: Record<string, string>;
306
+ method?: HTTPMethod;
307
+ auth?: "auto" | "none" | "app" | "user";
308
+ accessToken?: string;
309
+ basicAuth?: {
310
+ username: string;
311
+ password: string;
312
+ };
313
+ contentType?: string;
314
+ onResponse?: (metadata: {
315
+ headers: Headers;
316
+ status: number;
317
+ }) => void;
318
+ preserveResponseKeys?: boolean;
319
+ }
320
+
321
+ interface QuranReflectPostReference {
322
+ chapterId: number;
323
+ from: number;
324
+ to: number;
325
+ id?: string;
326
+ }
327
+ interface QuranReflectPostMention {
328
+ marker: string;
329
+ userId: string;
330
+ displayName: string;
331
+ }
332
+ type QuranReflectRoomPostStatus = 0 | 1 | 2;
333
+ interface CreateQuranReflectPostPayload {
334
+ body: string;
335
+ draft: boolean;
336
+ references: QuranReflectPostReference[];
337
+ mentions: QuranReflectPostMention[];
338
+ roomId?: number;
339
+ roomPostStatus?: QuranReflectRoomPostStatus;
340
+ postAsAuthorId?: string;
341
+ publishedAt?: string | Date;
342
+ }
343
+ type UpdateQuranReflectPostPayload = Partial<CreateQuranReflectPostPayload>;
344
+ interface QuranReflectPost {
345
+ id: number | string;
346
+ authorId?: string;
347
+ body?: string;
348
+ commentsCount?: number;
349
+ createdAt?: string;
350
+ discussionId?: number;
351
+ draft?: boolean;
352
+ estimatedReadingTime?: number;
353
+ featuredAt?: string;
354
+ global?: boolean;
355
+ hidden?: boolean;
356
+ languageId?: number;
357
+ languageName?: string;
358
+ likesCount?: number;
359
+ mentions?: QuranReflectPostMention[];
360
+ moderationStatus?: number;
361
+ postTypeId?: number | null;
362
+ postTypeName?: string;
363
+ publishedAt?: string;
364
+ pushedUpAt?: string;
365
+ references?: QuranReflectPostReference[];
366
+ removed?: boolean;
367
+ reported?: boolean;
368
+ reviewedAt?: string;
369
+ roomId?: number | null;
370
+ roomPostStatus?: number;
371
+ toxicityScore?: number;
372
+ updatedAt?: string;
373
+ verified?: boolean;
374
+ views?: number;
375
+ viewsCount?: number;
376
+ }
377
+ interface QuranReflectPostMutationResponse {
378
+ success: boolean;
379
+ data?: QuranReflectPost;
380
+ post?: QuranReflectPost;
381
+ error?: unknown;
382
+ }
383
+
384
+ declare enum Language {
385
+ ARABIC = "ar",
386
+ ENGLISH = "en",
387
+ URDU = "ur",
388
+ BENGALI = "bn",
389
+ TURKISH = "tr",
390
+ SPANISH = "es",
391
+ GERMAN = "de",
392
+ BOSNIAN = "bs",
393
+ RUSSIAN = "ru",
394
+ ALBANIAN_AL = "al",
395
+ FRENCH = "fr",
396
+ DUTCH = "nl",
397
+ TAMIL = "ta",
398
+ TAJIK = "tg",
399
+ INDONESIAN = "id",
400
+ UZBEK = "uz",
401
+ VIETNAMESE = "vi",
402
+ CHINESE = "zh",
403
+ ITALIAN = "it",
404
+ JAPANESE = "ja",
405
+ MALAYALAM = "ml",
406
+ AMHARIC = "am",
407
+ KAZAKH = "kk",
408
+ PORTUGUESE = "pt",
409
+ TAGALOG = "tl",
410
+ THAI = "th",
411
+ KOREAN = "ko",
412
+ HINDI = "hi",
413
+ KURDISH = "ku",
414
+ HAUSA = "ha",
415
+ AZERI = "az",
416
+ SWAHILI = "sw",
417
+ PERSIAN = "fa",
418
+ SERBIAN = "sr",
419
+ MARANAO = "mrn",
420
+ AMAZIGH = "zgh",
421
+ ASSAMESE = "as",
422
+ BULGARIAN = "bg",
423
+ CHECHEN = "ce",
424
+ CZECH = "cs",
425
+ DIVEHI = "dv",
426
+ FINNISH = "fi",
427
+ GUJAARATI = "gu",
428
+ HEBREW = "he",
429
+ GEORGIAN = "ka",
430
+ CENTRAL_KHMER = "km",
431
+ GANDA = "lg",
432
+ MARATHI = "mr",
433
+ YORUBA = "yo",
434
+ MALAY = "ms",
435
+ NEPALI = "ne",
436
+ SWEDISH = "sv",
437
+ TELUGU = "te",
438
+ TATAR = "tt",
439
+ UYGHUR = "ug",
440
+ UKRAINIAN = "uk",
441
+ NORWEGIAN = "no",
442
+ OROMO = "om",
443
+ POLISH = "pl",
444
+ PASHTO = "ps",
445
+ ROMANIAN = "ro",
446
+ SINDHI = "sd",
447
+ NORTHERN_SAMI = "se",
448
+ SINHALA = "si",
449
+ SOMALI = "so",
450
+ ALBANIAN_SQ = "sq"
451
+ }
452
+ declare enum QuranFont {
453
+ MadaniV1 = "code_v1",
454
+ MadaniV2 = "code_v2",
455
+ Uthmani = "text_uthmani"
456
+ }
457
+ type VerseField = "chapterId" | "textUthmani" | "textUthmaniSimple" | "textImlaei" | "textImlaeiSimple" | "textIndopak" | "textIndopakNastaleeq" | "textUthmaniTajweed" | "imageUrl" | "imageWidth" | "codeV1" | "codeV2" | "v1Page" | "v2Page";
458
+ type WordField = "v1Page" | "v2Page" | "textUthmani" | "textImlaei" | "textIndopak" | "verseKey" | "location" | "codeV1" | "codeV2";
459
+ type TranslationField = "resourceName" | "verseId" | "languageId" | "languageName" | "verseKey" | "chapterId" | "verseNumber" | "juzNumber" | "hizbNumber" | "rubNumber" | "pageNumber";
460
+ type VerseRecitationField = "id" | "chapterId" | "segments" | "format";
461
+
462
+ declare const QuranHttpErrorClass: {
463
+ new (response: Response, payload: unknown): {
464
+ readonly headers: Headers;
465
+ readonly payload: unknown;
466
+ readonly status: number;
467
+ name: string;
468
+ message: string;
469
+ stack?: string;
470
+ cause?: unknown;
471
+ };
472
+ fromResponse(response: Response): Promise<{
473
+ readonly headers: Headers;
474
+ readonly payload: unknown;
475
+ readonly status: number;
476
+ name: string;
477
+ message: string;
478
+ stack?: string;
479
+ cause?: unknown;
480
+ }>;
481
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
482
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
483
+ stackTraceLimit: number;
484
+ };
485
+ type QuranHttpErrorConstructor = typeof QuranHttpErrorClass;
486
+ interface QuranHttpError extends Error {
487
+ readonly headers: Headers;
488
+ readonly payload: unknown;
489
+ readonly status: number;
490
+ }
491
+ declare const QuranHttpError: QuranHttpErrorConstructor;
492
+
493
+ type AppStateErrorCode = "app_state_data_deleted" | "app_state_disabled" | "app_state_policy_changed" | "app_state_unavailable" | "bootstrap_required" | "collection_not_allowed" | "document_not_found" | "document_too_large" | "idempotency_key_reused" | "internal_server_error" | "insufficient_scope" | "invalid_collection" | "invalid_etag" | "invalid_idempotency_key" | "invalid_json" | "invalid_key" | "invalid_precondition" | "invalid_sync_token" | "invalid_token" | "namespace_resolution_unavailable" | "payload_too_large" | "precondition_failed" | "precondition_required" | "quota_exceeded" | "rate_limit_exceeded" | "sync_token_expired";
494
+ interface AppStateServiceError {
495
+ code: AppStateErrorCode;
496
+ details?: {
497
+ currentETag?: string | null;
498
+ [key: string]: unknown;
499
+ };
500
+ message?: string;
501
+ [key: string]: unknown;
502
+ }
503
+ interface AppStateErrorPayload {
504
+ details: {
505
+ currentETag?: string | null;
506
+ error: AppStateErrorCode | AppStateServiceError;
507
+ [key: string]: unknown;
508
+ };
509
+ message: string;
510
+ success: false;
511
+ type: string;
512
+ }
513
+ type AppStateHttpError = QuranHttpError & {
514
+ readonly payload: AppStateErrorPayload;
515
+ };
516
+ declare const getAppStateErrorCode: (error: unknown) => AppStateErrorCode | undefined;
517
+ declare function isAppStateHttpError(error: unknown, code?: AppStateErrorCode): error is AppStateHttpError;
518
+
519
+ declare const createAppStateReconciler: ({ accountId: initialAccountId, createIdempotencyKey, maxRebaseAttempts, pageSize, store, transport: initialTransport, }: AppStateReconcilerOptions) => AppStateReconciler;
520
+
521
+ type AppStateProtocolErrorCode = "bootstrap_cursor_missing" | "bootstrap_sync_token_missing" | "put_response_etag_missing" | "same_version_conflict";
522
+ declare class AppStateProtocolError extends Error {
523
+ readonly code: AppStateProtocolErrorCode;
524
+ constructor(code: AppStateProtocolErrorCode);
525
+ }
526
+ declare const createAppStateMemoryStore: (initialStates?: Readonly<Record<string, AppStateAccountState>>) => AppStateStore;
527
+
528
+ export { type RuntimeMode as $, type AppStateErrorCode as A, type BaseApiParams as B, type AppStatePageOptions as C, type AppStateChangesOptions as D, type AppStatePutBody as E, type AppStateMutationOptions as F, type AppStateTransport as G, type AppStateStoredDocument as H, type AppStatePendingMutationBase as I, type AppStatePendingPut as J, type AppStatePendingDelete as K, Language as L, type AppStatePendingMutation as M, type AppStateAccountState as N, type AppStateVisibleDocument as O, type PaginationParams as P, type QuranClientConfig as Q, type AppStateStateView as R, SearchMode as S, type TranslationField as T, type AppStateStoreReducer as U, type VerseField as V, type WordField as W, type AppStateStore as X, type AppStateReconcilerOptions as Y, type AppStateReconciler as Z, type CustomFetcher as _, QuranHttpError as a, type HTTPMethod as a0, type QuranFetchClient as a1, type ApiService as a2, type ServiceEnvironmentConfig as a3, type UserSession as a4, type TokenStorage as a5, type ServerClientConfig as a6, type PublicClientConfig as a7, type CachedToken as a8, type TokenResponse as a9, type OperationRequest as aa, type QuranReflectPostReference as ab, type QuranReflectPostMention as ac, type QuranReflectRoomPostStatus as ad, type CreateQuranReflectPostPayload as ae, type UpdateQuranReflectPostPayload as af, type QuranReflectPost as ag, type QuranReflectPostMutationResponse as ah, type AppStateErrorPayload as b, type AppStateHttpError as c, createAppStateReconciler as d, AppStateProtocolError as e, createAppStateMemoryStore as f, getAppStateErrorCode as g, QuranFont as h, isAppStateHttpError as i, type VerseRecitationField as j, type ApiParams as k, type BinaryString as l, type SearchParams as m, type AppStateJsonValue as n, type AppStateSuccess as o, type AppStateResponse as p, type AppStateCollection as q, type AppStateLimits as r, type AppStateConfiguration as s, type AppStateDocument as t, type AppStateDocumentWithEtag as u, type AppStateMutationResult as v, type AppStatePage as w, type AppStateBootstrapPage as x, type AppStateChange as y, type AppStateChangesPage as z };