@nkzw/fate 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/README.md +98 -29
  2. package/docs/api/classes/FateClient.md +36 -36
  3. package/docs/api/functions/clientRoot.md +1 -1
  4. package/docs/api/functions/createClient.md +1 -1
  5. package/docs/api/functions/createHTTPTransport.md +1 -1
  6. package/docs/api/functions/createTRPCTransport.md +1 -1
  7. package/docs/api/functions/getListEntries.md +1 -1
  8. package/docs/api/functions/getSelectionPlan.md +1 -1
  9. package/docs/api/functions/isRecord.md +1 -1
  10. package/docs/api/functions/isViewTag.md +1 -1
  11. package/docs/api/functions/liveConnectionTopic.md +1 -1
  12. package/docs/api/functions/liveEntityTopic.md +1 -1
  13. package/docs/api/functions/liveGlobalConnectionTopic.md +1 -1
  14. package/docs/api/functions/mutation.md +1 -1
  15. package/docs/api/functions/toEntityId.md +1 -1
  16. package/docs/api/functions/view.md +1 -1
  17. package/docs/api/interfaces/FateThenable.md +3 -3
  18. package/docs/api/interfaces/Transport.md +7 -7
  19. package/docs/api/server/classes/FateRequestError.md +5 -5
  20. package/docs/api/server/drizzle/functions/createDrizzleFate.md +1 -1
  21. package/docs/api/server/drizzle/functions/createDrizzleSourceAdapter.md +1 -1
  22. package/docs/api/server/drizzle/functions/createDrizzleSourceRegistry.md +1 -1
  23. package/docs/api/server/drizzle/index.md +1 -1
  24. package/docs/api/server/drizzle/type-aliases/DrizzleManyToManyConfig.md +1 -1
  25. package/docs/api/server/drizzle/type-aliases/DrizzleManyToManyInput.md +1 -1
  26. package/docs/api/server/drizzle/type-aliases/DrizzleQueryExtra.md +3 -3
  27. package/docs/api/server/drizzle/type-aliases/DrizzleSourceAdapter.md +9 -9
  28. package/docs/api/server/drizzle/type-aliases/DrizzleViewConfig.md +1 -1
  29. package/docs/api/server/functions/bindSourceProcedures.md +1 -1
  30. package/docs/api/server/functions/computed.md +1 -1
  31. package/docs/api/server/functions/count.md +1 -1
  32. package/docs/api/server/functions/createFateFetchHandler.md +1 -1
  33. package/docs/api/server/functions/createFateServer.md +1 -1
  34. package/docs/api/server/functions/createHonoFateHandler.md +1 -1
  35. package/docs/api/server/functions/createLiveEventBus.md +2 -2
  36. package/docs/api/server/functions/createNestedSourcePlan.md +1 -1
  37. package/docs/api/server/functions/createResolver.md +1 -1
  38. package/docs/api/server/functions/createSourcePlan.md +1 -1
  39. package/docs/api/server/functions/createSourceProcedures.md +2 -2
  40. package/docs/api/server/functions/dataView.md +1 -1
  41. package/docs/api/server/functions/field.md +1 -1
  42. package/docs/api/server/functions/getNestedSelection.md +1 -1
  43. package/docs/api/server/functions/getScopedArgs.md +1 -1
  44. package/docs/api/server/functions/hasNestedSelection.md +1 -1
  45. package/docs/api/server/functions/list.md +1 -1
  46. package/docs/api/server/functions/refetchSourceById.md +1 -1
  47. package/docs/api/server/functions/resolveSourceById.md +1 -1
  48. package/docs/api/server/functions/resolveSourceByIds.md +1 -1
  49. package/docs/api/server/functions/resolveSourceConnection.md +1 -1
  50. package/docs/api/server/functions/resolver.md +1 -1
  51. package/docs/api/server/functions/toPrismaSelect.md +1 -1
  52. package/docs/api/server/functions/withConnection.md +1 -1
  53. package/docs/api/server/prisma/functions/createPrismaFate.md +1 -1
  54. package/docs/api/server/prisma/functions/createPrismaSourceAdapter.md +1 -1
  55. package/docs/api/server/prisma/functions/createPrismaSourceRegistry.md +1 -1
  56. package/docs/api/server/prisma/functions/prismaConnectionArgs.md +1 -1
  57. package/docs/api/server/prisma/index.md +1 -1
  58. package/docs/api/server/prisma/type-aliases/PrismaDelegate.md +4 -4
  59. package/docs/api/server/prisma/type-aliases/PrismaQueryExtra.md +1 -1
  60. package/docs/api/server/prisma/type-aliases/PrismaSourceAdapter.md +9 -9
  61. package/docs/api/server/prisma/type-aliases/PrismaViewConfig.md +1 -1
  62. package/docs/api/server/type-aliases/ComputedField.md +5 -5
  63. package/docs/api/server/type-aliases/ComputedSelection.md +1 -1
  64. package/docs/api/server/type-aliases/ConnectionItem.md +3 -3
  65. package/docs/api/server/type-aliases/ConnectionPagination.md +5 -5
  66. package/docs/api/server/type-aliases/ConnectionResult.md +3 -3
  67. package/docs/api/server/type-aliases/CountSelection.md +4 -4
  68. package/docs/api/server/type-aliases/CountWhere.md +1 -1
  69. package/docs/api/server/type-aliases/DataViewListOptions.md +2 -2
  70. package/docs/api/server/type-aliases/DataViewOrderBy.md +1 -1
  71. package/docs/api/server/type-aliases/DataViewOrderDirection.md +1 -1
  72. package/docs/api/server/type-aliases/DataViewResult.md +1 -1
  73. package/docs/api/server/type-aliases/Entity.md +1 -1
  74. package/docs/api/server/type-aliases/FateServer.md +5 -5
  75. package/docs/api/server/type-aliases/FateServerManifest.md +1 -1
  76. package/docs/api/server/type-aliases/FieldSelection.md +3 -3
  77. package/docs/api/server/type-aliases/LiveConnectionEventType.md +1 -1
  78. package/docs/api/server/type-aliases/LiveConnectionSourceEvent.md +1 -1
  79. package/docs/api/server/type-aliases/LiveEventBus.md +1 -1
  80. package/docs/api/server/type-aliases/LiveEventType.md +1 -1
  81. package/docs/api/server/type-aliases/LiveSourceEvent.md +1 -1
  82. package/docs/api/server/type-aliases/NativeFateAPI.md +4 -4
  83. package/docs/api/server/type-aliases/OrderDirection.md +1 -1
  84. package/docs/api/server/type-aliases/SourceConfig.md +6 -6
  85. package/docs/api/server/type-aliases/SourceDefinition.md +6 -6
  86. package/docs/api/server/type-aliases/SourceOrder.md +1 -1
  87. package/docs/api/server/type-aliases/SourceOrderField.md +3 -3
  88. package/docs/api/server/type-aliases/SourcePlan.md +1 -1
  89. package/docs/api/server/type-aliases/SourcePlanNode.md +1 -1
  90. package/docs/api/server/type-aliases/SourceRegistry.md +1 -1
  91. package/docs/api/server/type-aliases/SourceRelation.md +1 -1
  92. package/docs/api/server/type-aliases/SourceRelationConfig.md +1 -1
  93. package/docs/api/server/variables/byIdInput.md +1 -1
  94. package/docs/api/server/variables/connectionArgs.md +1 -1
  95. package/docs/api/type-aliases/ConnectionMetadata.md +1 -1
  96. package/docs/api/type-aliases/ConnectionRef.md +1 -1
  97. package/docs/api/type-aliases/Entity.md +2 -2
  98. package/docs/api/type-aliases/EntityId.md +1 -1
  99. package/docs/api/type-aliases/FateLiveConnectionEvent.md +1 -1
  100. package/docs/api/type-aliases/FateLiveEvent.md +1 -1
  101. package/docs/api/type-aliases/FateMutations.md +1 -1
  102. package/docs/api/type-aliases/FateOperation.md +1 -1
  103. package/docs/api/type-aliases/FateProtocolRequest.md +1 -1
  104. package/docs/api/type-aliases/FateProtocolResponse.md +1 -1
  105. package/docs/api/type-aliases/FateRecord.md +1 -1
  106. package/docs/api/type-aliases/FateRoots.md +1 -1
  107. package/docs/api/type-aliases/InferFateAPI.md +1 -1
  108. package/docs/api/type-aliases/List.md +1 -1
  109. package/docs/api/type-aliases/ListEntry.md +1 -1
  110. package/docs/api/type-aliases/ListItem.md +1 -1
  111. package/docs/api/type-aliases/Mask.md +1 -1
  112. package/docs/api/type-aliases/MutationDefinition.md +1 -1
  113. package/docs/api/type-aliases/MutationEntity.md +1 -1
  114. package/docs/api/type-aliases/MutationIdentifier.md +1 -1
  115. package/docs/api/type-aliases/MutationInput.md +1 -1
  116. package/docs/api/type-aliases/MutationResult.md +1 -1
  117. package/docs/api/type-aliases/NodesItem.md +1 -1
  118. package/docs/api/type-aliases/Pagination.md +5 -5
  119. package/docs/api/type-aliases/Request.md +1 -1
  120. package/docs/api/type-aliases/RequestMode.md +1 -1
  121. package/docs/api/type-aliases/RequestOptions.md +1 -1
  122. package/docs/api/type-aliases/RequestResult.md +1 -1
  123. package/docs/api/type-aliases/Selection.md +1 -1
  124. package/docs/api/type-aliases/Snapshot.md +1 -1
  125. package/docs/api/type-aliases/TypeConfig.md +4 -4
  126. package/docs/api/type-aliases/View.md +1 -1
  127. package/docs/api/type-aliases/ViewData.md +1 -1
  128. package/docs/api/type-aliases/ViewEntity.md +1 -1
  129. package/docs/api/type-aliases/ViewEntityName.md +1 -1
  130. package/docs/api/type-aliases/ViewRef.md +1 -1
  131. package/docs/api/type-aliases/ViewSelection.md +1 -1
  132. package/docs/api/type-aliases/ViewSnapshot.md +1 -1
  133. package/docs/api/type-aliases/ViewTag.md +1 -1
  134. package/docs/api/variables/ConnectionTag.md +1 -1
  135. package/docs/guide/actions.md +46 -4
  136. package/docs/guide/live-views.md +15 -2
  137. package/docs/guide/requests.md +1 -1
  138. package/docs/guide/server-integration.md +35 -21
  139. package/docs/guide/views.md +1 -1
  140. package/docs/guide/void-integration.md +3 -3
  141. package/lib/index.d.mts +1 -1
  142. package/lib/index.mjs +5 -4
  143. package/lib/{record-ENh92gyb.d.mts → record-CirbfZWX.d.mts} +2 -1
  144. package/lib/server/drizzle.d.mts +2 -0
  145. package/lib/server/drizzle.mjs +89 -6
  146. package/lib/server/prisma.mjs +2 -2
  147. package/lib/server.d.mts +2 -2
  148. package/lib/server.mjs +39 -8
  149. package/lib/{sourceRouter-Bwpkr062.mjs → sourceRouter-C22uFcZg.mjs} +1 -1
  150. package/package.json +1 -1
@@ -1,9 +1,9 @@
1
1
  import { t as isRecord } from "../record-AeZJC9fd.mjs";
2
- import { O as withConnection, S as isDataView, c as resolveSourceConnection, d as createSourceDefinitions, f as createSourcePlan, g as attachComputedState, i as createSourceRegistry, l as collectDataViewConfigs, o as resolveSourceById, p as getDataViewSourceConfig, s as resolveSourceByIds, t as bindSourceProcedures } from "../sourceRouter-Bwpkr062.mjs";
3
- import { and, asc, createTableRelationsHelpers, desc, eq, extractTablesRelationalConfig, getTableColumns, gt, inArray, isTable, lt, normalizeRelation, or, sql } from "drizzle-orm";
2
+ import { O as withConnection, S as isDataView, c as resolveSourceConnection, d as createSourceDefinitions, f as createSourcePlan, g as attachComputedState, i as createSourceRegistry, l as collectDataViewConfigs, o as resolveSourceById, p as getDataViewSourceConfig, s as resolveSourceByIds, t as bindSourceProcedures } from "../sourceRouter-C22uFcZg.mjs";
3
+ import { Many, and, asc, createTableRelationsHelpers, desc, eq, extractTablesRelationalConfig, getTableColumns, gt, inArray, is, isTable, lt, normalizeRelation, or, sql } from "drizzle-orm";
4
4
  //#region src/server/drizzle.ts
5
5
  /**
6
- * Fate's Drizzle integration.
6
+ * fate's Drizzle integration.
7
7
  *
8
8
  * @example
9
9
  * import { createDrizzleFate } from '@nkzw/fate/server/drizzle';
@@ -29,6 +29,21 @@ const hasPagination = (args) => {
29
29
  };
30
30
  const getConnectionDirection = (args) => args?.before !== void 0 || typeof args?.last === "number" ? "backward" : "forward";
31
31
  const getConnectionSize = (fallback, args) => (typeof args?.first === "number" ? args.first : void 0) ?? (typeof args?.last === "number" ? args.last : void 0) ?? fallback;
32
+ const defaultNestedPaginationConcurrency = 10;
33
+ const getNestedPaginationConcurrency = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : defaultNestedPaginationConcurrency;
34
+ const mapWithConcurrency = async (items, concurrency, fn) => {
35
+ if (items.length === 0) return [];
36
+ const results = new Array(items.length);
37
+ let nextIndex = 0;
38
+ const workers = Array.from({ length: Math.min(concurrency, items.length) }, async () => {
39
+ while (nextIndex < items.length) {
40
+ const index = nextIndex++;
41
+ results[index] = await fn(items[index], index);
42
+ }
43
+ });
44
+ await Promise.all(workers);
45
+ return results;
46
+ };
32
47
  const buildConnection = ({ cursor, direction, items, pageSize }) => {
33
48
  const hasMore = items.length > pageSize;
34
49
  const connectionItems = (direction === "forward" ? items.slice(0, pageSize) : items.slice(-pageSize)).map((node) => ({
@@ -186,6 +201,51 @@ const inferDirectRelation = ({ field, metadata, sourceConfig, targetConfig }) =>
186
201
  localKey: getColumnKey(sourceTableConfig.columns, normalized.fields[0])
187
202
  };
188
203
  };
204
+ const getComputedCountRelations = (view) => {
205
+ const relations = /* @__PURE__ */ new Set();
206
+ for (const field of Object.values(view.fields)) {
207
+ if (!isRecord(field) || field.kind !== "computed" || !isRecord(field.select)) continue;
208
+ for (const selection of Object.values(field.select)) if (isRecord(selection) && selection.kind === "count" && typeof selection.relation === "string") relations.add(selection.relation);
209
+ }
210
+ return relations;
211
+ };
212
+ const getTableConfigIfAvailable = ({ config, metadata }) => {
213
+ try {
214
+ return getTableConfig({
215
+ config,
216
+ metadata
217
+ });
218
+ } catch {
219
+ return null;
220
+ }
221
+ };
222
+ const inferHiddenCountRelation = ({ field, metadata, sourceConfig, viewConfigs }) => {
223
+ const sourceTableConfig = getTableConfigIfAvailable({
224
+ config: sourceConfig,
225
+ metadata
226
+ });
227
+ const relation = sourceTableConfig?.relations[field];
228
+ if (!sourceTableConfig || !relation || !is(relation, Many)) return null;
229
+ const normalized = normalizeRelation(metadata.schema, metadata.tableNamesMap, relation);
230
+ const localColumn = normalized.fields[0];
231
+ const foreignColumn = normalized.references[0];
232
+ if (!localColumn || !foreignColumn) return null;
233
+ for (const [index, targetConfig] of viewConfigs.entries()) {
234
+ const targetTableConfig = getTableConfigIfAvailable({
235
+ config: targetConfig,
236
+ metadata
237
+ });
238
+ if (!targetTableConfig || !includesColumn(targetTableConfig.columns, foreignColumn)) continue;
239
+ return {
240
+ index,
241
+ relation: {
242
+ foreignKey: getColumnKey(targetTableConfig.columns, foreignColumn),
243
+ localKey: getColumnKey(sourceTableConfig.columns, localColumn)
244
+ }
245
+ };
246
+ }
247
+ return null;
248
+ };
189
249
  const inferManyToManyRelation = ({ field, metadata, sourceConfig, targetConfig }) => {
190
250
  const sourceTableConfig = getTableConfig({
191
251
  config: sourceConfig,
@@ -251,7 +311,8 @@ const resolveManyToManyConfig = ({ field, source, sourceRelation, through: throu
251
311
  table: through.table
252
312
  };
253
313
  };
254
- function createDrizzleSourceAdapter({ db, schema, views }) {
314
+ function createDrizzleSourceAdapter({ db, nestedPaginationConcurrency, schema, views }) {
315
+ const nestedPaginationLimit = getNestedPaginationConcurrency(nestedPaginationConcurrency);
255
316
  const metadata = getDrizzleSchemaMetadata({
256
317
  db,
257
318
  schema
@@ -282,6 +343,28 @@ function createDrizzleSourceAdapter({ db, schema, views }) {
282
343
  targetConfig
283
344
  }) : void 0) ?? void 0;
284
345
  } });
346
+ if (metadata) for (const [index, config] of viewConfigs.entries()) {
347
+ const source = sourceDefinitions[index];
348
+ for (const field of getComputedCountRelations(config.view)) {
349
+ if (source.relations?.[field]) continue;
350
+ const hidden = inferHiddenCountRelation({
351
+ field,
352
+ metadata,
353
+ sourceConfig: config,
354
+ viewConfigs
355
+ });
356
+ const targetSource = hidden && sourceDefinitions[hidden.index];
357
+ if (!hidden || !targetSource) continue;
358
+ source.relations = {
359
+ ...source.relations,
360
+ [field]: {
361
+ ...hidden.relation,
362
+ kind: "many",
363
+ source: targetSource
364
+ }
365
+ };
366
+ }
367
+ }
285
368
  const sourcesByView = new Map(sourceDefinitions.map((source) => [source.view, source]));
286
369
  const sourcesByFields = new Map(sourceDefinitions.map((source) => [source.view.fields, source]));
287
370
  const sourceConfigs = new Map(viewConfigs.map((config, index) => [sourceDefinitions[index], {
@@ -517,7 +600,7 @@ function createDrizzleSourceAdapter({ db, schema, views }) {
517
600
  through: throughConfig
518
601
  });
519
602
  if (hasPagination(relationNode.args)) {
520
- const connections = await Promise.all(items.map(async (item) => [item[sourceRelation.localKey], await fetchManyToManyConnection(item[sourceRelation.localKey], relationNode, sourceRelation, through, ctx)]));
603
+ const connections = await mapWithConcurrency(items, nestedPaginationLimit, async (item) => [item[sourceRelation.localKey], await fetchManyToManyConnection(item[sourceRelation.localKey], relationNode, sourceRelation, through, ctx)]);
521
604
  const connectionByParentKey = new Map(connections);
522
605
  for (const item of items) item[field] = connectionByParentKey.get(item[sourceRelation.localKey]);
523
606
  continue;
@@ -534,7 +617,7 @@ function createDrizzleSourceAdapter({ db, schema, views }) {
534
617
  continue;
535
618
  }
536
619
  if (hasPagination(relationNode.args)) {
537
- const connections = await Promise.all(items.map(async (item) => [item[sourceRelation.localKey], await fetchManyConnection(item[sourceRelation.localKey], relationNode, sourceRelation, ctx)]));
620
+ const connections = await mapWithConcurrency(items, nestedPaginationLimit, async (item) => [item[sourceRelation.localKey], await fetchManyConnection(item[sourceRelation.localKey], relationNode, sourceRelation, ctx)]);
538
621
  const connectionByParentKey = new Map(connections);
539
622
  for (const item of items) item[field] = connectionByParentKey.get(item[sourceRelation.localKey]);
540
623
  continue;
@@ -1,8 +1,8 @@
1
1
  import { t as isRecord } from "../record-AeZJC9fd.mjs";
2
- import { O as withConnection, S as isDataView, T as toPrismaSelect, c as resolveSourceConnection, d as createSourceDefinitions, f as createSourcePlan, g as attachComputedState, i as createSourceRegistry, l as collectDataViewConfigs, o as resolveSourceById, p as getDataViewSourceConfig, s as resolveSourceByIds, t as bindSourceProcedures } from "../sourceRouter-Bwpkr062.mjs";
2
+ import { O as withConnection, S as isDataView, T as toPrismaSelect, c as resolveSourceConnection, d as createSourceDefinitions, f as createSourcePlan, g as attachComputedState, i as createSourceRegistry, l as collectDataViewConfigs, o as resolveSourceById, p as getDataViewSourceConfig, s as resolveSourceByIds, t as bindSourceProcedures } from "../sourceRouter-C22uFcZg.mjs";
3
3
  //#region src/server/prisma.ts
4
4
  /**
5
- * Fate's Prisma integration.
5
+ * fate's Prisma integration.
6
6
  *
7
7
  * @example
8
8
  * import { createPrismaFate } from '@nkzw/fate/server/prisma';
package/lib/server.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { K as AnyProcedure, t as AnyRecord$1 } from "./types-Dz46PXr3.mjs";
2
- import { C as liveGlobalConnectionTopic, S as liveEntityTopic, _ as LiveEventBus, b as createLiveEventBus, c as FateServer, d as NativeFateAPI, f as createFateFetchHandler, g as LiveConnectionSourceEvent, h as LiveConnectionEventType, l as FateServerManifest, m as createHonoFateHandler, p as createFateServer, s as FateRequestError, t as isRecord, u as InferFateAPI, v as LiveEventType, x as liveConnectionTopic, y as LiveSourceEvent } from "./record-ENh92gyb.mjs";
2
+ import { C as liveGlobalConnectionTopic, S as liveEntityTopic, _ as LiveEventBus, b as createLiveEventBus, c as FateServer, d as NativeFateAPI, f as createFateFetchHandler, g as LiveConnectionSourceEvent, h as LiveConnectionEventType, l as FateServerManifest, m as createHonoFateHandler, p as createFateServer, s as FateRequestError, t as isRecord, u as InferFateAPI, v as LiveEventType, x as liveConnectionTopic, y as LiveSourceEvent } from "./record-CirbfZWX.mjs";
3
3
  import { A as DataViewListOptions, B as dataView, C as connectionArgs, D as CountSelection, E as ComputedSelection, F as FieldSelection, H as list$1, I as ViewPlan, L as computed, M as DataViewOrderDirection, N as DataViewResult, O as CountWhere, P as Entity, R as count, S as ConnectionResult, T as ComputedField, U as resolver, V as field, _ as createSourcePlan, a as resolveSourceConnection, b as ConnectionItem, c as SourceConfig, d as SourceOrderField, f as SourcePlan, g as createNestedSourcePlan, h as SourceRelationConfig, i as resolveSourceByIds, j as DataViewOrderBy, l as SourceDefinition, m as SourceRelation, n as refetchSourceById, p as SourcePlanNode, r as resolveSourceById, s as OrderDirection, t as SourceRegistry, u as SourceOrder, v as getNestedSelection, w as withConnection, x as ConnectionPagination, y as hasNestedSelection, z as createResolver } from "./executor-BqwHdN3n.mjs";
4
4
  import { z } from "zod";
5
5
 
@@ -74,7 +74,7 @@ type SourceProcedureResult<ById extends boolean | undefined, List extends boolea
74
74
  list: ConnectionProcedureResult<ConnectionProcedure>;
75
75
  });
76
76
  /**
77
- * Creates standard `byId` and `list` procedures for a Fate source.
77
+ * Creates standard `byId` and `list` procedures for a fate source.
78
78
  *
79
79
  * Use this when a router also has custom mutations or custom queries and you
80
80
  * want to spread the generated source procedures into that router.
package/lib/server.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { t as isRecord } from "./record-AeZJC9fd.mjs";
2
2
  import { d as hashArgs, i as FateRequestError, n as liveEntityTopic, o as toProtocolError, r as liveGlobalConnectionTopic, t as liveConnectionTopic, u as filterConnectionArgs } from "./liveTopics-DzNtJaBD.mjs";
3
- import { C as list, D as resolveConnection, E as connectionArgs, O as withConnection, S as isDataView, T as toPrismaSelect, _ as computed, a as refetchSourceById, b as dataView, c as resolveSourceConnection, f as createSourcePlan, h as hasNestedSelection, k as getScopedArgs, m as getNestedSelection, n as createSourceProcedures, o as resolveSourceById, r as byIdInput, s as resolveSourceByIds, t as bindSourceProcedures, u as createNestedSourcePlan, v as count, w as resolver, x as field, y as createResolver } from "./sourceRouter-Bwpkr062.mjs";
3
+ import { C as list, D as resolveConnection, E as connectionArgs, O as withConnection, S as isDataView, T as toPrismaSelect, _ as computed, a as refetchSourceById, b as dataView, c as resolveSourceConnection, f as createSourcePlan, h as hasNestedSelection, k as getScopedArgs, m as getNestedSelection, n as createSourceProcedures, o as resolveSourceById, r as byIdInput, s as resolveSourceByIds, t as bindSourceProcedures, u as createNestedSourcePlan, v as count, w as resolver, x as field, y as createResolver } from "./sourceRouter-C22uFcZg.mjs";
4
4
  import { EventEmitter, on } from "node:events";
5
5
  //#region src/server/live.ts
6
6
  const eventName = (type, id) => `${type}:${String(id)}`;
@@ -71,7 +71,7 @@ const mergeEvents = (emitter, names, signal) => ({ [Symbol.asyncIterator]() {
71
71
  };
72
72
  } });
73
73
  /**
74
- * Creates a small in-memory event bus for Fate live view subscriptions.
74
+ * Creates a small in-memory event bus for fate live view subscriptions.
75
75
  *
76
76
  * The bus signals that an entity changed and can optionally include changed
77
77
  * field paths. The native live handler refetches the selected record, or only
@@ -218,6 +218,27 @@ const getLiveBus = (live) => {
218
218
  if ("subscribe" in live) return live;
219
219
  return live.bus;
220
220
  };
221
+ const defaultLiveMaxQueueSize = 1e3;
222
+ const getLiveMaxQueueSize = (live) => {
223
+ if (!live || "subscribe" in live) return defaultLiveMaxQueueSize;
224
+ const value = live.maxQueueSize;
225
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : defaultLiveMaxQueueSize;
226
+ };
227
+ const compactLiveQueue = (connection) => {
228
+ if (connection.queueHead === 0) return;
229
+ connection.queue = connection.queue.slice(connection.queueHead);
230
+ connection.queueHead = 0;
231
+ };
232
+ const getLiveQueueSize = (connection) => connection.queue.length - connection.queueHead;
233
+ const dequeueLiveItem = (connection) => {
234
+ if (connection.queueHead >= connection.queue.length) {
235
+ compactLiveQueue(connection);
236
+ return null;
237
+ }
238
+ const item = connection.queue[connection.queueHead++];
239
+ if (connection.queueHead > 64 && connection.queueHead * 2 >= connection.queue.length) compactLiveQueue(connection);
240
+ return item;
241
+ };
221
242
  const getWaitUntil = (adapterContext) => {
222
243
  const context = adapterContext;
223
244
  if (!context) return;
@@ -400,6 +421,7 @@ function createFateServer({ context, lists, live, mutations, queries, roots, sou
400
421
  }
401
422
  for (const name of rootQueries.keys()) if (!queries?.[name]) throw new Error(`Native fate root query '${name}' requires a matching resolver in createFateServer({ queries }).`);
402
423
  const liveBus = getLiveBus(live);
424
+ const liveMaxQueueSize = getLiveMaxQueueSize(live);
403
425
  const getContext = async (request, adapterContext) => context ? await context({
404
426
  adapterContext,
405
427
  request
@@ -540,13 +562,22 @@ function createFateServer({ context, lists, live, mutations, queries, roots, sou
540
562
  connection.closed = true;
541
563
  }
542
564
  };
565
+ const enqueueLiveItem = (connection, item) => {
566
+ if (connection.closed) return;
567
+ if (getLiveQueueSize(connection) >= liveMaxQueueSize) {
568
+ cleanupLiveConnection(connection.id);
569
+ return;
570
+ }
571
+ connection.queue.push(item);
572
+ scheduleLiveDrain(connection);
573
+ };
543
574
  const drainLiveConnection = async (connection) => {
544
575
  if (connection.closed || connection.draining) return;
545
576
  connection.draining = true;
546
577
  let activeOperationId = null;
547
578
  try {
548
- while (!connection.closed && connection.queue.length > 0) {
549
- const item = connection.queue.shift();
579
+ let item;
580
+ while (!connection.closed && (item = dequeueLiveItem(connection))) {
550
581
  activeOperationId = item.operation.id;
551
582
  if (!item.subscription.active || connection.subscriptions.get(item.operation.id) !== item.subscription) continue;
552
583
  if (item.kind === "entity") {
@@ -657,14 +688,13 @@ function createFateServer({ context, lists, live, mutations, queries, roots, sou
657
688
  };
658
689
  if (liveBus.listen) {
659
690
  const unsubscribe = liveBus.listen(operation.type, operation.entityId, (event) => {
660
- connection.queue.push({
691
+ enqueueLiveItem(connection, {
661
692
  event,
662
693
  kind: "entity",
663
694
  operation,
664
695
  source,
665
696
  subscription
666
697
  });
667
- scheduleLiveDrain(connection);
668
698
  }, {
669
699
  lastEventId: operation.lastEventId,
670
700
  signal: subscriptionController.signal
@@ -742,13 +772,12 @@ function createFateServer({ context, lists, live, mutations, queries, roots, sou
742
772
  args: operation.args,
743
773
  procedure: operation.procedure
744
774
  }, (event) => {
745
- connection.queue.push({
775
+ enqueueLiveItem(connection, {
746
776
  event,
747
777
  kind: "connection",
748
778
  operation,
749
779
  subscription
750
780
  });
751
- scheduleLiveDrain(connection);
752
781
  }, {
753
782
  lastEventId: operation.lastEventId,
754
783
  signal: subscriptionController.signal
@@ -842,8 +871,10 @@ function createFateServer({ context, lists, live, mutations, queries, roots, sou
842
871
  closed: false,
843
872
  controller,
844
873
  ctx,
874
+ id: connectionId,
845
875
  lastHeartbeat: Date.now(),
846
876
  queue: [],
877
+ queueHead: 0,
847
878
  subscriptions: /* @__PURE__ */ new Map()
848
879
  };
849
880
  connection.drainInterval = setInterval(() => void drainLiveConnection(connection), 100);
@@ -926,7 +926,7 @@ const byIdInput = z.object({
926
926
  //#region src/server/sourceRouter.ts
927
927
  const normalizeSourceOptions = (input) => "source" in input ? input : { source: input };
928
928
  /**
929
- * Creates standard `byId` and `list` procedures for a Fate source.
929
+ * Creates standard `byId` and `list` procedures for a fate source.
930
930
  *
931
931
  * Use this when a router also has custom mutations or custom queries and you
932
932
  * want to spread the generated source procedures into that router.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nkzw/fate",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "fate is a modern data client for React.",
5
5
  "homepage": "https://github.com/nkzw-tech/fate",
6
6
  "license": "MIT",