@dyrected/sdk 2.5.39 → 2.5.41

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/dist/index.cjs CHANGED
@@ -73,7 +73,8 @@ var QueryBuilder = class {
73
73
  executor;
74
74
  args = {};
75
75
  where(where) {
76
- this.args.where = { ...this.args.where, ...where };
76
+ const currentWhere = this.args.where;
77
+ this.args.where = currentWhere && typeof currentWhere === "object" ? { ...currentWhere, ...where } : { ...where };
77
78
  return this;
78
79
  }
79
80
  sort(sort) {
@@ -165,6 +166,15 @@ var DyrectedClient = class {
165
166
  async getSchemas() {
166
167
  return this.request("/api/schemas");
167
168
  }
169
+ async getAdminAuthConfig() {
170
+ return this.request("/api/admin/auth/providers");
171
+ }
172
+ async exchangeAdminAuth(providerId, body) {
173
+ return this.request(`/api/admin/auth/${providerId}/exchange`, {
174
+ method: "POST",
175
+ body: JSON.stringify(body)
176
+ });
177
+ }
168
178
  async getPreference(key, options) {
169
179
  const scopeParam = options?.scope ? `?scope=${options.scope}` : "";
170
180
  return this.request(`/api/preferences/${encodeURIComponent(key)}${scopeParam}`);
@@ -192,23 +202,16 @@ var DyrectedClient = class {
192
202
  async find(collection, args = {}) {
193
203
  const { initialData, ...queryArgs } = args;
194
204
  const normalizedArgs = { ...queryArgs };
195
- if (normalizedArgs.where && typeof normalizedArgs.where === "object") {
196
- normalizedArgs.where = JSON.stringify(normalizedArgs.where);
205
+ if (queryArgs.where && typeof queryArgs.where === "object") {
206
+ normalizedArgs.where = JSON.stringify(queryArgs.where);
197
207
  }
198
208
  const query = stringifyQuery(normalizedArgs, { addQueryPrefix: true });
199
- const res = await this.request(
200
- `/api/collections/${collection}${query}`
201
- );
209
+ const res = await this.request(`/api/collections/${collection}${query}`);
202
210
  if (res.docs.length === 0 && initialData && initialData.length > 0) {
203
211
  this.request(`/api/collections/${collection}/seed`, {
204
212
  method: "POST",
205
213
  body: JSON.stringify({ data: initialData })
206
- }).catch(
207
- (err) => console.error(
208
- `[dyrected/sdk] Failed to auto-seed collection "${collection}":`,
209
- err
210
- )
211
- );
214
+ }).catch((err) => console.error(`[dyrected/sdk] Failed to auto-seed collection "${collection}":`, err));
212
215
  return {
213
216
  docs: initialData,
214
217
  total: initialData.length,
@@ -229,10 +232,10 @@ var DyrectedClient = class {
229
232
  find: (args) => {
230
233
  const qb = new QueryBuilder(
231
234
  slug,
232
- (c, a) => this.find(c, a)
235
+ (collectionName, queryArgs) => this.find(collectionName, queryArgs)
233
236
  );
234
237
  if (args) {
235
- if (args.where) qb.where(args.where);
238
+ if (args.where && typeof args.where === "object") qb.where(args.where);
236
239
  if (args.sort) qb.sort(args.sort);
237
240
  if (args.limit) qb.limit(args.limit);
238
241
  if (args.page) qb.page(args.page);
@@ -328,12 +331,7 @@ var DyrectedClient = class {
328
331
  * comment: 'Please add more detail to section 2.',
329
332
  * })
330
333
  */
331
- transition: (id, transitionName, opts) => this.transition(
332
- slug,
333
- id,
334
- transitionName,
335
- opts
336
- ),
334
+ transition: (id, transitionName, opts) => this.transition(slug, id, transitionName, opts),
337
335
  /**
338
336
  * Fetch the workflow history for a single document — every transition that
339
337
  * has ever been performed, newest first.
@@ -366,10 +364,7 @@ var DyrectedClient = class {
366
364
  method: "POST",
367
365
  body: JSON.stringify({ data: [{ id, ...initialData }] })
368
366
  }).catch(
369
- (err2) => console.error(
370
- `[dyrected/sdk] Failed to auto-seed document "${id}" in collection "${collection}":`,
371
- err2
372
- )
367
+ (err2) => console.error(`[dyrected/sdk] Failed to auto-seed document "${id}" in collection "${collection}":`, err2)
373
368
  );
374
369
  return initialData;
375
370
  }
@@ -408,13 +403,10 @@ var DyrectedClient = class {
408
403
  * const updated = await client.transition('posts', postId, 'publish')
409
404
  */
410
405
  async transition(collection, id, transitionName, opts = {}) {
411
- return this.request(
412
- `/api/collections/${collection}/${id}/transitions/${encodeURIComponent(transitionName)}`,
413
- {
414
- method: "POST",
415
- body: JSON.stringify(opts)
416
- }
417
- );
406
+ return this.request(`/api/collections/${collection}/${id}/transitions/${encodeURIComponent(transitionName)}`, {
407
+ method: "POST",
408
+ body: JSON.stringify(opts)
409
+ });
418
410
  }
419
411
  /**
420
412
  * Fetch the workflow history for a document.
@@ -427,9 +419,7 @@ var DyrectedClient = class {
427
419
  */
428
420
  async workflowHistory(collection, id, args = {}) {
429
421
  const query = args.limit ? `?limit=${args.limit}` : "";
430
- return this.request(
431
- `/api/collections/${collection}/${id}/workflow-history${query}`
432
- );
422
+ return this.request(`/api/collections/${collection}/${id}/workflow-history${query}`);
433
423
  }
434
424
  async deleteMany(collection, ids) {
435
425
  return this.request(`/api/collections/${collection}/delete-many`, {
@@ -442,16 +432,12 @@ var DyrectedClient = class {
442
432
  const query = stringifyQuery(queryArgs, { addQueryPrefix: true });
443
433
  try {
444
434
  const res = await this.request(`/api/globals/${slug}${query}`);
445
- if ((!res || Object.keys(res).length === 0) && initialData) {
435
+ if ((!res || isFunctionallyEmpty(res)) && !isFunctionallyEmpty(initialData)) {
436
+ console.log("[getGlobal] We are seeding", res);
446
437
  this.request(`/api/globals/${slug}/seed`, {
447
438
  method: "POST",
448
439
  body: JSON.stringify({ data: initialData })
449
- }).catch(
450
- (err) => console.error(
451
- `[dyrected/sdk] Failed to auto-seed global "${slug}":`,
452
- err
453
- )
454
- );
440
+ }).catch((err) => console.error(`[dyrected/sdk] Failed to auto-seed global "${slug}":`, err));
455
441
  return initialData;
456
442
  }
457
443
  return res;
@@ -460,12 +446,7 @@ var DyrectedClient = class {
460
446
  this.request(`/api/globals/${slug}/seed`, {
461
447
  method: "POST",
462
448
  body: JSON.stringify({ data: initialData })
463
- }).catch(
464
- (err2) => console.error(
465
- `[dyrected/sdk] Failed to auto-seed global "${slug}":`,
466
- err2
467
- )
468
- );
449
+ }).catch((err2) => console.error(`[dyrected/sdk] Failed to auto-seed global "${slug}":`, err2));
469
450
  return initialData;
470
451
  }
471
452
  throw err;
@@ -478,7 +459,8 @@ var DyrectedClient = class {
478
459
  });
479
460
  }
480
461
  async listMedia(args = {}, collection = "media") {
481
- return this.find(collection, args);
462
+ const query = stringifyQuery(normalizeQueryArgs(args), { addQueryPrefix: true });
463
+ return this.request(`/api/collections/${collection}${query}`);
482
464
  }
483
465
  /** @deprecated Use client.collection('media').upload(file, data) instead */
484
466
  async uploadMedia(file, collection = "media") {
@@ -498,10 +480,7 @@ var DyrectedClient = class {
498
480
  const { "Content-Type": _, ...headers } = this.headers;
499
481
  return this.request(`/api/collections/${collection}`, {
500
482
  method: "POST",
501
- headers: {
502
- ...headers,
503
- "Content-Type": void 0
504
- },
483
+ headers,
505
484
  body: formData
506
485
  });
507
486
  }
@@ -510,15 +489,7 @@ var DyrectedClient = class {
510
489
  }
511
490
  async request(path, init) {
512
491
  const url = `${this.baseUrl}${path}`;
513
- const allHeaders = {
514
- ...this.headers,
515
- ...init?.headers
516
- };
517
- Object.keys(allHeaders).forEach((key) => {
518
- if (allHeaders[key] === void 0) {
519
- delete allHeaders[key];
520
- }
521
- });
492
+ const allHeaders = mergeHeaders(this.headers, init?.headers);
522
493
  const res = await this.fetch(url, {
523
494
  ...init,
524
495
  headers: allHeaders
@@ -533,11 +504,8 @@ var DyrectedClient = class {
533
504
  })
534
505
  );
535
506
  }
536
- throw new DyrectedError(
537
- body.message || `Request failed with status ${res.status}`,
538
- res.status,
539
- body.code
540
- );
507
+ console.log("[DyrectedError]", body, res.status);
508
+ throw new DyrectedError(body.message || `Request failed with status ${res.status}`, res.status, body.code);
541
509
  }
542
510
  return res.json();
543
511
  }
@@ -547,6 +515,45 @@ var DyrectedClient = class {
547
515
  function createClient(config) {
548
516
  return new DyrectedClient(config);
549
517
  }
518
+ function isFunctionallyEmpty(obj) {
519
+ if (obj === null || obj === void 0 || obj === "") return true;
520
+ if (Array.isArray(obj)) {
521
+ if (obj.length === 0) return true;
522
+ return obj.every(isFunctionallyEmpty);
523
+ }
524
+ if (typeof obj === "object") {
525
+ const keys = Object.keys(obj);
526
+ if (keys.length === 0) return true;
527
+ return keys.every((key) => isFunctionallyEmpty(obj[key]));
528
+ }
529
+ return false;
530
+ }
531
+ function mergeHeaders(baseHeaders, overrideHeaders) {
532
+ const merged = new Headers(baseHeaders);
533
+ if (overrideHeaders instanceof Headers) {
534
+ overrideHeaders.forEach((value, key) => merged.set(key, value));
535
+ } else if (Array.isArray(overrideHeaders)) {
536
+ for (const [key, value] of overrideHeaders) {
537
+ merged.set(key, value);
538
+ }
539
+ } else if (overrideHeaders) {
540
+ for (const [key, value] of Object.entries(overrideHeaders)) {
541
+ if (value === void 0) {
542
+ merged.delete(key);
543
+ } else {
544
+ merged.set(key, String(value));
545
+ }
546
+ }
547
+ }
548
+ return Object.fromEntries(merged.entries());
549
+ }
550
+ function normalizeQueryArgs(args) {
551
+ const normalizedArgs = { ...args };
552
+ if (args.where && typeof args.where === "object") {
553
+ normalizedArgs.where = JSON.stringify(args.where);
554
+ }
555
+ return normalizedArgs;
556
+ }
550
557
  // Annotate the CommonJS export names for ESM import in node:
551
558
  0 && (module.exports = {
552
559
  DyrectedClient,
package/dist/index.d.cts CHANGED
@@ -1,29 +1,38 @@
1
- import { PaginatedResult, WorkflowMetadata, FileData, CollectionConfig, GlobalConfig } from '@dyrected/core';
2
- export { AdminIconName, Block, CollectionConfig, Field, FieldType, GlobalConfig, LifecycleEvent, FileData as Media, PaginatedResult, WorkflowMetadata } from '@dyrected/core';
1
+ import { PaginatedResult, CollectionConfig, GlobalConfig, AdminConfig, PublicAdminAuthConfig, FileData, WorkflowMetadata } from '@dyrected/core';
2
+ export { AdminIconName, Block, CollectionConfig, EmailField, Field, FieldType, GlobalConfig, IconField, LifecycleEvent, FileData as Media, NumberField, PaginatedResult, TextField, TextareaField, UrlField, WorkflowMetadata } from '@dyrected/core';
3
3
 
4
- interface QueryArgs {
4
+ type UnknownRecord$1 = Record<string, unknown>;
5
+ interface QueryArgs<TDoc = UnknownRecord$1> {
5
6
  limit?: number;
6
7
  page?: number;
7
8
  depth?: number;
8
- where?: any;
9
+ where?: UnknownRecord$1 | string;
9
10
  sort?: string;
10
- initialData?: any[];
11
+ initialData?: TDoc[];
11
12
  }
12
- declare class QueryBuilder<T = any> {
13
+ declare class QueryBuilder<T = UnknownRecord$1> {
13
14
  private collection;
14
15
  private executor;
15
16
  private args;
16
- constructor(collection: string, executor: (collection: string, args: QueryArgs) => Promise<PaginatedResult<T>>);
17
- where(where: any): this;
17
+ constructor(collection: string, executor: (collection: string, args: QueryArgs<T>) => Promise<PaginatedResult<T>>);
18
+ where(where: UnknownRecord$1): this;
18
19
  sort(sort: string): this;
19
20
  limit(limit: number): this;
20
21
  page(page: number): this;
21
22
  depth(depth: number): this;
22
23
  seed(data: T[]): this;
23
24
  exec(): Promise<PaginatedResult<T>>;
24
- then<TResult1 = PaginatedResult<T>, TResult2 = never>(onfulfilled?: ((value: PaginatedResult<T>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
25
+ then<TResult1 = PaginatedResult<T>, TResult2 = never>(onfulfilled?: ((value: PaginatedResult<T>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
25
26
  }
26
27
 
28
+ type UnknownRecord = Record<string, unknown>;
29
+ type SchemaResponse = {
30
+ collections: CollectionConfig[];
31
+ globals: GlobalConfig[];
32
+ admin?: AdminConfig;
33
+ adminAuth?: PublicAdminAuthConfig;
34
+ };
35
+
27
36
  /** Shape of a document returned from a workflow-enabled collection. */
28
37
  interface WorkflowDocument {
29
38
  id: string;
@@ -82,7 +91,7 @@ type ExtractDoc<T> = T extends CollectionConfig<infer TDoc> ? TDoc : T extends G
82
91
  * // client.global('settings').get() → { siteName?: string; ... }
83
92
  * ```
84
93
  */
85
- type InferSchema<TCollections extends Record<string, CollectionConfig<any>>, TGlobals extends Record<string, GlobalConfig<any>> = Record<never, never>> = {
94
+ type InferSchema<TCollections extends Record<string, CollectionConfig<UnknownRecord>>, TGlobals extends Record<string, GlobalConfig<UnknownRecord>> = Record<never, never>> = {
86
95
  collections: {
87
96
  [K in keyof TCollections]: ExtractDoc<TCollections[K]>;
88
97
  };
@@ -114,10 +123,10 @@ interface DyrectedClientConfig {
114
123
  defaultDepth?: number;
115
124
  }
116
125
  interface BaseSchema {
117
- collections: Record<string, any>;
118
- globals: Record<string, any>;
126
+ collections: Record<string, UnknownRecord>;
127
+ globals: Record<string, UnknownRecord>;
119
128
  }
120
- declare class DyrectedClient<TSchema extends BaseSchema = any> {
129
+ declare class DyrectedClient<TSchema extends BaseSchema = BaseSchema> {
121
130
  private baseUrl;
122
131
  private headers;
123
132
  private fetch;
@@ -140,24 +149,27 @@ declare class DyrectedClient<TSchema extends BaseSchema = any> {
140
149
  */
141
150
  getAuthHeaders(): Record<string, string>;
142
151
  getBaseUrl(): string;
143
- getSchemas(): Promise<{
144
- collections: any[];
145
- globals: any[];
152
+ getSchemas(): Promise<SchemaResponse>;
153
+ getAdminAuthConfig(): Promise<PublicAdminAuthConfig>;
154
+ exchangeAdminAuth(providerId: string, body: Record<string, unknown>): Promise<{
155
+ token: string;
156
+ collectionSlug: string;
157
+ providerId: string;
146
158
  }>;
147
159
  getPreference<T = unknown>(key: string, options?: {
148
- scope?: 'personal' | 'global';
160
+ scope?: "personal" | "global";
149
161
  }): Promise<{
150
162
  key: string;
151
163
  value: T | null;
152
164
  }>;
153
165
  setPreference<T = unknown>(key: string, value: T, options?: {
154
- scope?: 'personal' | 'global';
166
+ scope?: "personal" | "global";
155
167
  }): Promise<{
156
168
  key: string;
157
169
  value: T;
158
170
  }>;
159
171
  deletePreference(key: string, options?: {
160
- scope?: 'personal' | 'global';
172
+ scope?: "personal" | "global";
161
173
  }): Promise<{
162
174
  success: boolean;
163
175
  }>;
@@ -165,19 +177,19 @@ declare class DyrectedClient<TSchema extends BaseSchema = any> {
165
177
  * Fetch draft data for a specific preview token.
166
178
  * Used in "token" preview mode.
167
179
  */
168
- getPreviewData(token: string): Promise<any>;
169
- find<K extends keyof TSchema["collections"]>(collection: K & string, args?: QueryArgs): Promise<PaginatedResult<TSchema["collections"][K]>>;
180
+ getPreviewData<T = unknown>(token: string): Promise<T>;
181
+ find<K extends keyof TSchema["collections"]>(collection: K & string, args?: QueryArgs<TSchema["collections"][K]>): Promise<PaginatedResult<TSchema["collections"][K]>>;
170
182
  /**
171
183
  * Returns a fluent query builder for a collection.
172
184
  */
173
185
  collection<K extends keyof TSchema["collections"]>(slug: K & string): {
174
- find: (args?: QueryArgs) => QueryBuilder<TSchema["collections"][K]>;
186
+ find: (args?: QueryArgs<TSchema["collections"][K]>) => QueryBuilder<TSchema["collections"][K]>;
175
187
  findOne: (id: string, args?: {
176
188
  depth?: number;
177
189
  initialData?: TSchema["collections"][K];
178
190
  }) => Promise<TSchema["collections"][K]>;
179
- create: (data: any) => Promise<TSchema["collections"][K]>;
180
- update: (id: string, data: any) => Promise<TSchema["collections"][K]>;
191
+ create: (data: Partial<TSchema["collections"][K]>) => Promise<TSchema["collections"][K]>;
192
+ update: (id: string, data: Partial<TSchema["collections"][K]>) => Promise<TSchema["collections"][K]>;
181
193
  delete: (id: string) => Promise<{
182
194
  message: string;
183
195
  }>;
@@ -189,7 +201,7 @@ declare class DyrectedClient<TSchema extends BaseSchema = any> {
189
201
  * @param file - A File or Blob (browser) or Buffer with filename/mimeType (Node.js)
190
202
  * @param data - Additional metadata fields to save alongside the file (e.g. alt, caption)
191
203
  */
192
- upload: (file: File | Blob, data?: Record<string, string>) => Promise<any>;
204
+ upload: (file: File | Blob, data?: Record<string, string>) => Promise<FileData>;
193
205
  /**
194
206
  * Log in with email + password. Returns a JWT token and the user document.
195
207
  * Call `client.setToken(token)` afterwards to authenticate subsequent requests.
@@ -213,7 +225,7 @@ declare class DyrectedClient<TSchema extends BaseSchema = any> {
213
225
  initialized: boolean;
214
226
  }>;
215
227
  /** Register the very first user in an empty auth collection. */
216
- registerFirstUser: (data: any) => Promise<{
228
+ registerFirstUser: (data: UnknownRecord) => Promise<{
217
229
  token: string;
218
230
  user: TSchema["collections"][K];
219
231
  }>;
@@ -223,7 +235,7 @@ declare class DyrectedClient<TSchema extends BaseSchema = any> {
223
235
  message: string;
224
236
  }>;
225
237
  /** Accept an invitation and create an account. Returns token + user. */
226
- acceptInvite: (token: string, password: string, extraFields?: Record<string, any>) => Promise<{
238
+ acceptInvite: (token: string, password: string, extraFields?: UnknownRecord) => Promise<{
227
239
  token: string;
228
240
  user: TSchema["collections"][K];
229
241
  }>;
@@ -295,14 +307,14 @@ declare class DyrectedClient<TSchema extends BaseSchema = any> {
295
307
  depth?: number;
296
308
  initialData?: TSchema["globals"][K];
297
309
  }) => Promise<TSchema["globals"][K]>;
298
- update: (data: any) => Promise<TSchema["globals"][K]>;
310
+ update: (data: Partial<TSchema["globals"][K]>) => Promise<TSchema["globals"][K]>;
299
311
  };
300
- findOne<T = any>(collection: string, id: string, args?: {
312
+ findOne<T = UnknownRecord>(collection: string, id: string, args?: {
301
313
  depth?: number;
302
314
  initialData?: T;
303
315
  }): Promise<T>;
304
- create<T = any>(collection: string, data: any): Promise<T>;
305
- update<T = any>(collection: string, id: string, data: any): Promise<T>;
316
+ create<T = UnknownRecord>(collection: string, data: Partial<T>): Promise<T>;
317
+ update<T = UnknownRecord>(collection: string, id: string, data: Partial<T>): Promise<T>;
306
318
  delete(collection: string, id: string): Promise<{
307
319
  message: string;
308
320
  }>;
@@ -336,12 +348,12 @@ declare class DyrectedClient<TSchema extends BaseSchema = any> {
336
348
  deleteMany(collection: string, ids: string[]): Promise<{
337
349
  message: string;
338
350
  }>;
339
- getGlobal<T = any>(slug: string, args?: {
351
+ getGlobal<T = UnknownRecord>(slug: string, args?: {
340
352
  depth?: number;
341
353
  initialData?: T;
342
354
  }): Promise<T>;
343
- updateGlobal<T = any>(slug: string, data: any): Promise<T>;
344
- listMedia(args?: QueryArgs, collection?: string): Promise<PaginatedResult<FileData>>;
355
+ updateGlobal<T = UnknownRecord>(slug: string, data: Partial<T>): Promise<T>;
356
+ listMedia(args?: QueryArgs<FileData>, collection?: string): Promise<PaginatedResult<FileData>>;
345
357
  /** @deprecated Use client.collection('media').upload(file, data) instead */
346
358
  uploadMedia(file: File, collection?: string): Promise<FileData>;
347
359
  /**
@@ -353,9 +365,6 @@ declare class DyrectedClient<TSchema extends BaseSchema = any> {
353
365
  }>;
354
366
  private request;
355
367
  }
356
- declare function createClient<TSchema extends {
357
- collections: any;
358
- globals: any;
359
- } = any>(config: DyrectedClientConfig): DyrectedClient<TSchema>;
368
+ declare function createClient<TSchema extends BaseSchema = BaseSchema>(config: DyrectedClientConfig): DyrectedClient<TSchema>;
360
369
 
361
370
  export { type BaseSchema, DyrectedClient, type DyrectedClientConfig, DyrectedError, type InferSchema, type TransitionOptions, type WorkflowDocument, type WorkflowHistoryEntry, createClient };
package/dist/index.d.ts CHANGED
@@ -1,29 +1,38 @@
1
- import { PaginatedResult, WorkflowMetadata, FileData, CollectionConfig, GlobalConfig } from '@dyrected/core';
2
- export { AdminIconName, Block, CollectionConfig, Field, FieldType, GlobalConfig, LifecycleEvent, FileData as Media, PaginatedResult, WorkflowMetadata } from '@dyrected/core';
1
+ import { PaginatedResult, CollectionConfig, GlobalConfig, AdminConfig, PublicAdminAuthConfig, FileData, WorkflowMetadata } from '@dyrected/core';
2
+ export { AdminIconName, Block, CollectionConfig, EmailField, Field, FieldType, GlobalConfig, IconField, LifecycleEvent, FileData as Media, NumberField, PaginatedResult, TextField, TextareaField, UrlField, WorkflowMetadata } from '@dyrected/core';
3
3
 
4
- interface QueryArgs {
4
+ type UnknownRecord$1 = Record<string, unknown>;
5
+ interface QueryArgs<TDoc = UnknownRecord$1> {
5
6
  limit?: number;
6
7
  page?: number;
7
8
  depth?: number;
8
- where?: any;
9
+ where?: UnknownRecord$1 | string;
9
10
  sort?: string;
10
- initialData?: any[];
11
+ initialData?: TDoc[];
11
12
  }
12
- declare class QueryBuilder<T = any> {
13
+ declare class QueryBuilder<T = UnknownRecord$1> {
13
14
  private collection;
14
15
  private executor;
15
16
  private args;
16
- constructor(collection: string, executor: (collection: string, args: QueryArgs) => Promise<PaginatedResult<T>>);
17
- where(where: any): this;
17
+ constructor(collection: string, executor: (collection: string, args: QueryArgs<T>) => Promise<PaginatedResult<T>>);
18
+ where(where: UnknownRecord$1): this;
18
19
  sort(sort: string): this;
19
20
  limit(limit: number): this;
20
21
  page(page: number): this;
21
22
  depth(depth: number): this;
22
23
  seed(data: T[]): this;
23
24
  exec(): Promise<PaginatedResult<T>>;
24
- then<TResult1 = PaginatedResult<T>, TResult2 = never>(onfulfilled?: ((value: PaginatedResult<T>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
25
+ then<TResult1 = PaginatedResult<T>, TResult2 = never>(onfulfilled?: ((value: PaginatedResult<T>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
25
26
  }
26
27
 
28
+ type UnknownRecord = Record<string, unknown>;
29
+ type SchemaResponse = {
30
+ collections: CollectionConfig[];
31
+ globals: GlobalConfig[];
32
+ admin?: AdminConfig;
33
+ adminAuth?: PublicAdminAuthConfig;
34
+ };
35
+
27
36
  /** Shape of a document returned from a workflow-enabled collection. */
28
37
  interface WorkflowDocument {
29
38
  id: string;
@@ -82,7 +91,7 @@ type ExtractDoc<T> = T extends CollectionConfig<infer TDoc> ? TDoc : T extends G
82
91
  * // client.global('settings').get() → { siteName?: string; ... }
83
92
  * ```
84
93
  */
85
- type InferSchema<TCollections extends Record<string, CollectionConfig<any>>, TGlobals extends Record<string, GlobalConfig<any>> = Record<never, never>> = {
94
+ type InferSchema<TCollections extends Record<string, CollectionConfig<UnknownRecord>>, TGlobals extends Record<string, GlobalConfig<UnknownRecord>> = Record<never, never>> = {
86
95
  collections: {
87
96
  [K in keyof TCollections]: ExtractDoc<TCollections[K]>;
88
97
  };
@@ -114,10 +123,10 @@ interface DyrectedClientConfig {
114
123
  defaultDepth?: number;
115
124
  }
116
125
  interface BaseSchema {
117
- collections: Record<string, any>;
118
- globals: Record<string, any>;
126
+ collections: Record<string, UnknownRecord>;
127
+ globals: Record<string, UnknownRecord>;
119
128
  }
120
- declare class DyrectedClient<TSchema extends BaseSchema = any> {
129
+ declare class DyrectedClient<TSchema extends BaseSchema = BaseSchema> {
121
130
  private baseUrl;
122
131
  private headers;
123
132
  private fetch;
@@ -140,24 +149,27 @@ declare class DyrectedClient<TSchema extends BaseSchema = any> {
140
149
  */
141
150
  getAuthHeaders(): Record<string, string>;
142
151
  getBaseUrl(): string;
143
- getSchemas(): Promise<{
144
- collections: any[];
145
- globals: any[];
152
+ getSchemas(): Promise<SchemaResponse>;
153
+ getAdminAuthConfig(): Promise<PublicAdminAuthConfig>;
154
+ exchangeAdminAuth(providerId: string, body: Record<string, unknown>): Promise<{
155
+ token: string;
156
+ collectionSlug: string;
157
+ providerId: string;
146
158
  }>;
147
159
  getPreference<T = unknown>(key: string, options?: {
148
- scope?: 'personal' | 'global';
160
+ scope?: "personal" | "global";
149
161
  }): Promise<{
150
162
  key: string;
151
163
  value: T | null;
152
164
  }>;
153
165
  setPreference<T = unknown>(key: string, value: T, options?: {
154
- scope?: 'personal' | 'global';
166
+ scope?: "personal" | "global";
155
167
  }): Promise<{
156
168
  key: string;
157
169
  value: T;
158
170
  }>;
159
171
  deletePreference(key: string, options?: {
160
- scope?: 'personal' | 'global';
172
+ scope?: "personal" | "global";
161
173
  }): Promise<{
162
174
  success: boolean;
163
175
  }>;
@@ -165,19 +177,19 @@ declare class DyrectedClient<TSchema extends BaseSchema = any> {
165
177
  * Fetch draft data for a specific preview token.
166
178
  * Used in "token" preview mode.
167
179
  */
168
- getPreviewData(token: string): Promise<any>;
169
- find<K extends keyof TSchema["collections"]>(collection: K & string, args?: QueryArgs): Promise<PaginatedResult<TSchema["collections"][K]>>;
180
+ getPreviewData<T = unknown>(token: string): Promise<T>;
181
+ find<K extends keyof TSchema["collections"]>(collection: K & string, args?: QueryArgs<TSchema["collections"][K]>): Promise<PaginatedResult<TSchema["collections"][K]>>;
170
182
  /**
171
183
  * Returns a fluent query builder for a collection.
172
184
  */
173
185
  collection<K extends keyof TSchema["collections"]>(slug: K & string): {
174
- find: (args?: QueryArgs) => QueryBuilder<TSchema["collections"][K]>;
186
+ find: (args?: QueryArgs<TSchema["collections"][K]>) => QueryBuilder<TSchema["collections"][K]>;
175
187
  findOne: (id: string, args?: {
176
188
  depth?: number;
177
189
  initialData?: TSchema["collections"][K];
178
190
  }) => Promise<TSchema["collections"][K]>;
179
- create: (data: any) => Promise<TSchema["collections"][K]>;
180
- update: (id: string, data: any) => Promise<TSchema["collections"][K]>;
191
+ create: (data: Partial<TSchema["collections"][K]>) => Promise<TSchema["collections"][K]>;
192
+ update: (id: string, data: Partial<TSchema["collections"][K]>) => Promise<TSchema["collections"][K]>;
181
193
  delete: (id: string) => Promise<{
182
194
  message: string;
183
195
  }>;
@@ -189,7 +201,7 @@ declare class DyrectedClient<TSchema extends BaseSchema = any> {
189
201
  * @param file - A File or Blob (browser) or Buffer with filename/mimeType (Node.js)
190
202
  * @param data - Additional metadata fields to save alongside the file (e.g. alt, caption)
191
203
  */
192
- upload: (file: File | Blob, data?: Record<string, string>) => Promise<any>;
204
+ upload: (file: File | Blob, data?: Record<string, string>) => Promise<FileData>;
193
205
  /**
194
206
  * Log in with email + password. Returns a JWT token and the user document.
195
207
  * Call `client.setToken(token)` afterwards to authenticate subsequent requests.
@@ -213,7 +225,7 @@ declare class DyrectedClient<TSchema extends BaseSchema = any> {
213
225
  initialized: boolean;
214
226
  }>;
215
227
  /** Register the very first user in an empty auth collection. */
216
- registerFirstUser: (data: any) => Promise<{
228
+ registerFirstUser: (data: UnknownRecord) => Promise<{
217
229
  token: string;
218
230
  user: TSchema["collections"][K];
219
231
  }>;
@@ -223,7 +235,7 @@ declare class DyrectedClient<TSchema extends BaseSchema = any> {
223
235
  message: string;
224
236
  }>;
225
237
  /** Accept an invitation and create an account. Returns token + user. */
226
- acceptInvite: (token: string, password: string, extraFields?: Record<string, any>) => Promise<{
238
+ acceptInvite: (token: string, password: string, extraFields?: UnknownRecord) => Promise<{
227
239
  token: string;
228
240
  user: TSchema["collections"][K];
229
241
  }>;
@@ -295,14 +307,14 @@ declare class DyrectedClient<TSchema extends BaseSchema = any> {
295
307
  depth?: number;
296
308
  initialData?: TSchema["globals"][K];
297
309
  }) => Promise<TSchema["globals"][K]>;
298
- update: (data: any) => Promise<TSchema["globals"][K]>;
310
+ update: (data: Partial<TSchema["globals"][K]>) => Promise<TSchema["globals"][K]>;
299
311
  };
300
- findOne<T = any>(collection: string, id: string, args?: {
312
+ findOne<T = UnknownRecord>(collection: string, id: string, args?: {
301
313
  depth?: number;
302
314
  initialData?: T;
303
315
  }): Promise<T>;
304
- create<T = any>(collection: string, data: any): Promise<T>;
305
- update<T = any>(collection: string, id: string, data: any): Promise<T>;
316
+ create<T = UnknownRecord>(collection: string, data: Partial<T>): Promise<T>;
317
+ update<T = UnknownRecord>(collection: string, id: string, data: Partial<T>): Promise<T>;
306
318
  delete(collection: string, id: string): Promise<{
307
319
  message: string;
308
320
  }>;
@@ -336,12 +348,12 @@ declare class DyrectedClient<TSchema extends BaseSchema = any> {
336
348
  deleteMany(collection: string, ids: string[]): Promise<{
337
349
  message: string;
338
350
  }>;
339
- getGlobal<T = any>(slug: string, args?: {
351
+ getGlobal<T = UnknownRecord>(slug: string, args?: {
340
352
  depth?: number;
341
353
  initialData?: T;
342
354
  }): Promise<T>;
343
- updateGlobal<T = any>(slug: string, data: any): Promise<T>;
344
- listMedia(args?: QueryArgs, collection?: string): Promise<PaginatedResult<FileData>>;
355
+ updateGlobal<T = UnknownRecord>(slug: string, data: Partial<T>): Promise<T>;
356
+ listMedia(args?: QueryArgs<FileData>, collection?: string): Promise<PaginatedResult<FileData>>;
345
357
  /** @deprecated Use client.collection('media').upload(file, data) instead */
346
358
  uploadMedia(file: File, collection?: string): Promise<FileData>;
347
359
  /**
@@ -353,9 +365,6 @@ declare class DyrectedClient<TSchema extends BaseSchema = any> {
353
365
  }>;
354
366
  private request;
355
367
  }
356
- declare function createClient<TSchema extends {
357
- collections: any;
358
- globals: any;
359
- } = any>(config: DyrectedClientConfig): DyrectedClient<TSchema>;
368
+ declare function createClient<TSchema extends BaseSchema = BaseSchema>(config: DyrectedClientConfig): DyrectedClient<TSchema>;
360
369
 
361
370
  export { type BaseSchema, DyrectedClient, type DyrectedClientConfig, DyrectedError, type InferSchema, type TransitionOptions, type WorkflowDocument, type WorkflowHistoryEntry, createClient };
package/dist/index.js CHANGED
@@ -45,7 +45,8 @@ var QueryBuilder = class {
45
45
  executor;
46
46
  args = {};
47
47
  where(where) {
48
- this.args.where = { ...this.args.where, ...where };
48
+ const currentWhere = this.args.where;
49
+ this.args.where = currentWhere && typeof currentWhere === "object" ? { ...currentWhere, ...where } : { ...where };
49
50
  return this;
50
51
  }
51
52
  sort(sort) {
@@ -137,6 +138,15 @@ var DyrectedClient = class {
137
138
  async getSchemas() {
138
139
  return this.request("/api/schemas");
139
140
  }
141
+ async getAdminAuthConfig() {
142
+ return this.request("/api/admin/auth/providers");
143
+ }
144
+ async exchangeAdminAuth(providerId, body) {
145
+ return this.request(`/api/admin/auth/${providerId}/exchange`, {
146
+ method: "POST",
147
+ body: JSON.stringify(body)
148
+ });
149
+ }
140
150
  async getPreference(key, options) {
141
151
  const scopeParam = options?.scope ? `?scope=${options.scope}` : "";
142
152
  return this.request(`/api/preferences/${encodeURIComponent(key)}${scopeParam}`);
@@ -164,23 +174,16 @@ var DyrectedClient = class {
164
174
  async find(collection, args = {}) {
165
175
  const { initialData, ...queryArgs } = args;
166
176
  const normalizedArgs = { ...queryArgs };
167
- if (normalizedArgs.where && typeof normalizedArgs.where === "object") {
168
- normalizedArgs.where = JSON.stringify(normalizedArgs.where);
177
+ if (queryArgs.where && typeof queryArgs.where === "object") {
178
+ normalizedArgs.where = JSON.stringify(queryArgs.where);
169
179
  }
170
180
  const query = stringifyQuery(normalizedArgs, { addQueryPrefix: true });
171
- const res = await this.request(
172
- `/api/collections/${collection}${query}`
173
- );
181
+ const res = await this.request(`/api/collections/${collection}${query}`);
174
182
  if (res.docs.length === 0 && initialData && initialData.length > 0) {
175
183
  this.request(`/api/collections/${collection}/seed`, {
176
184
  method: "POST",
177
185
  body: JSON.stringify({ data: initialData })
178
- }).catch(
179
- (err) => console.error(
180
- `[dyrected/sdk] Failed to auto-seed collection "${collection}":`,
181
- err
182
- )
183
- );
186
+ }).catch((err) => console.error(`[dyrected/sdk] Failed to auto-seed collection "${collection}":`, err));
184
187
  return {
185
188
  docs: initialData,
186
189
  total: initialData.length,
@@ -201,10 +204,10 @@ var DyrectedClient = class {
201
204
  find: (args) => {
202
205
  const qb = new QueryBuilder(
203
206
  slug,
204
- (c, a) => this.find(c, a)
207
+ (collectionName, queryArgs) => this.find(collectionName, queryArgs)
205
208
  );
206
209
  if (args) {
207
- if (args.where) qb.where(args.where);
210
+ if (args.where && typeof args.where === "object") qb.where(args.where);
208
211
  if (args.sort) qb.sort(args.sort);
209
212
  if (args.limit) qb.limit(args.limit);
210
213
  if (args.page) qb.page(args.page);
@@ -300,12 +303,7 @@ var DyrectedClient = class {
300
303
  * comment: 'Please add more detail to section 2.',
301
304
  * })
302
305
  */
303
- transition: (id, transitionName, opts) => this.transition(
304
- slug,
305
- id,
306
- transitionName,
307
- opts
308
- ),
306
+ transition: (id, transitionName, opts) => this.transition(slug, id, transitionName, opts),
309
307
  /**
310
308
  * Fetch the workflow history for a single document — every transition that
311
309
  * has ever been performed, newest first.
@@ -338,10 +336,7 @@ var DyrectedClient = class {
338
336
  method: "POST",
339
337
  body: JSON.stringify({ data: [{ id, ...initialData }] })
340
338
  }).catch(
341
- (err2) => console.error(
342
- `[dyrected/sdk] Failed to auto-seed document "${id}" in collection "${collection}":`,
343
- err2
344
- )
339
+ (err2) => console.error(`[dyrected/sdk] Failed to auto-seed document "${id}" in collection "${collection}":`, err2)
345
340
  );
346
341
  return initialData;
347
342
  }
@@ -380,13 +375,10 @@ var DyrectedClient = class {
380
375
  * const updated = await client.transition('posts', postId, 'publish')
381
376
  */
382
377
  async transition(collection, id, transitionName, opts = {}) {
383
- return this.request(
384
- `/api/collections/${collection}/${id}/transitions/${encodeURIComponent(transitionName)}`,
385
- {
386
- method: "POST",
387
- body: JSON.stringify(opts)
388
- }
389
- );
378
+ return this.request(`/api/collections/${collection}/${id}/transitions/${encodeURIComponent(transitionName)}`, {
379
+ method: "POST",
380
+ body: JSON.stringify(opts)
381
+ });
390
382
  }
391
383
  /**
392
384
  * Fetch the workflow history for a document.
@@ -399,9 +391,7 @@ var DyrectedClient = class {
399
391
  */
400
392
  async workflowHistory(collection, id, args = {}) {
401
393
  const query = args.limit ? `?limit=${args.limit}` : "";
402
- return this.request(
403
- `/api/collections/${collection}/${id}/workflow-history${query}`
404
- );
394
+ return this.request(`/api/collections/${collection}/${id}/workflow-history${query}`);
405
395
  }
406
396
  async deleteMany(collection, ids) {
407
397
  return this.request(`/api/collections/${collection}/delete-many`, {
@@ -414,16 +404,12 @@ var DyrectedClient = class {
414
404
  const query = stringifyQuery(queryArgs, { addQueryPrefix: true });
415
405
  try {
416
406
  const res = await this.request(`/api/globals/${slug}${query}`);
417
- if ((!res || Object.keys(res).length === 0) && initialData) {
407
+ if ((!res || isFunctionallyEmpty(res)) && !isFunctionallyEmpty(initialData)) {
408
+ console.log("[getGlobal] We are seeding", res);
418
409
  this.request(`/api/globals/${slug}/seed`, {
419
410
  method: "POST",
420
411
  body: JSON.stringify({ data: initialData })
421
- }).catch(
422
- (err) => console.error(
423
- `[dyrected/sdk] Failed to auto-seed global "${slug}":`,
424
- err
425
- )
426
- );
412
+ }).catch((err) => console.error(`[dyrected/sdk] Failed to auto-seed global "${slug}":`, err));
427
413
  return initialData;
428
414
  }
429
415
  return res;
@@ -432,12 +418,7 @@ var DyrectedClient = class {
432
418
  this.request(`/api/globals/${slug}/seed`, {
433
419
  method: "POST",
434
420
  body: JSON.stringify({ data: initialData })
435
- }).catch(
436
- (err2) => console.error(
437
- `[dyrected/sdk] Failed to auto-seed global "${slug}":`,
438
- err2
439
- )
440
- );
421
+ }).catch((err2) => console.error(`[dyrected/sdk] Failed to auto-seed global "${slug}":`, err2));
441
422
  return initialData;
442
423
  }
443
424
  throw err;
@@ -450,7 +431,8 @@ var DyrectedClient = class {
450
431
  });
451
432
  }
452
433
  async listMedia(args = {}, collection = "media") {
453
- return this.find(collection, args);
434
+ const query = stringifyQuery(normalizeQueryArgs(args), { addQueryPrefix: true });
435
+ return this.request(`/api/collections/${collection}${query}`);
454
436
  }
455
437
  /** @deprecated Use client.collection('media').upload(file, data) instead */
456
438
  async uploadMedia(file, collection = "media") {
@@ -470,10 +452,7 @@ var DyrectedClient = class {
470
452
  const { "Content-Type": _, ...headers } = this.headers;
471
453
  return this.request(`/api/collections/${collection}`, {
472
454
  method: "POST",
473
- headers: {
474
- ...headers,
475
- "Content-Type": void 0
476
- },
455
+ headers,
477
456
  body: formData
478
457
  });
479
458
  }
@@ -482,15 +461,7 @@ var DyrectedClient = class {
482
461
  }
483
462
  async request(path, init) {
484
463
  const url = `${this.baseUrl}${path}`;
485
- const allHeaders = {
486
- ...this.headers,
487
- ...init?.headers
488
- };
489
- Object.keys(allHeaders).forEach((key) => {
490
- if (allHeaders[key] === void 0) {
491
- delete allHeaders[key];
492
- }
493
- });
464
+ const allHeaders = mergeHeaders(this.headers, init?.headers);
494
465
  const res = await this.fetch(url, {
495
466
  ...init,
496
467
  headers: allHeaders
@@ -505,11 +476,8 @@ var DyrectedClient = class {
505
476
  })
506
477
  );
507
478
  }
508
- throw new DyrectedError(
509
- body.message || `Request failed with status ${res.status}`,
510
- res.status,
511
- body.code
512
- );
479
+ console.log("[DyrectedError]", body, res.status);
480
+ throw new DyrectedError(body.message || `Request failed with status ${res.status}`, res.status, body.code);
513
481
  }
514
482
  return res.json();
515
483
  }
@@ -519,6 +487,45 @@ var DyrectedClient = class {
519
487
  function createClient(config) {
520
488
  return new DyrectedClient(config);
521
489
  }
490
+ function isFunctionallyEmpty(obj) {
491
+ if (obj === null || obj === void 0 || obj === "") return true;
492
+ if (Array.isArray(obj)) {
493
+ if (obj.length === 0) return true;
494
+ return obj.every(isFunctionallyEmpty);
495
+ }
496
+ if (typeof obj === "object") {
497
+ const keys = Object.keys(obj);
498
+ if (keys.length === 0) return true;
499
+ return keys.every((key) => isFunctionallyEmpty(obj[key]));
500
+ }
501
+ return false;
502
+ }
503
+ function mergeHeaders(baseHeaders, overrideHeaders) {
504
+ const merged = new Headers(baseHeaders);
505
+ if (overrideHeaders instanceof Headers) {
506
+ overrideHeaders.forEach((value, key) => merged.set(key, value));
507
+ } else if (Array.isArray(overrideHeaders)) {
508
+ for (const [key, value] of overrideHeaders) {
509
+ merged.set(key, value);
510
+ }
511
+ } else if (overrideHeaders) {
512
+ for (const [key, value] of Object.entries(overrideHeaders)) {
513
+ if (value === void 0) {
514
+ merged.delete(key);
515
+ } else {
516
+ merged.set(key, String(value));
517
+ }
518
+ }
519
+ }
520
+ return Object.fromEntries(merged.entries());
521
+ }
522
+ function normalizeQueryArgs(args) {
523
+ const normalizedArgs = { ...args };
524
+ if (args.where && typeof args.where === "object") {
525
+ normalizedArgs.where = JSON.stringify(args.where);
526
+ }
527
+ return normalizedArgs;
528
+ }
522
529
  export {
523
530
  DyrectedClient,
524
531
  DyrectedError,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dyrected/sdk",
3
- "version": "2.5.39",
3
+ "version": "2.5.41",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -30,7 +30,7 @@
30
30
  "tsup": "^8.5.1",
31
31
  "typescript": "^5.4.5",
32
32
  "vitest": "^1.0.0",
33
- "@dyrected/core": "2.5.39"
33
+ "@dyrected/core": "2.5.41"
34
34
  },
35
35
  "license": "BSL-1.1",
36
36
  "author": "Busola Okeowo <busolaokemoney@gmail.com>",