@entifix/react-integration 0.4.2 → 0.5.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
@@ -12,10 +12,11 @@ pnpm add @entifix/react-integration @tanstack/react-form @tanstack/react-query e
12
12
 
13
13
  ## Entry points
14
14
 
15
- | Import | What it holds |
16
- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
17
- | `@entifix/react-integration` | `EntifixQueryProvider`, `useEntityRecord`, `useEntityForm`, `useEntityMutation`, `useWizard`, `useReactiveInvalidation`, `useTransactionSettlement` |
18
- | `@entifix/react-integration/url` | `defineUrlQuery`, `useUrlState`, `useEntityLoad`, `useUrlFilter`: a filter kept in the query string, answered by `loadAllUCFactory` over an `EntitySource`. No TanStack |
15
+ | Import | What it holds |
16
+ | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
17
+ | `@entifix/react-integration` | `EntifixQueryProvider`, `useEntityRecord`, `useEntityForm`, `useEntityMutation`, `useWizard`, `useReactiveInvalidation`, `useTransactionSettlement` |
18
+ | `@entifix/react-integration/url` | `defineUrlQuery`, `useUrlState`, `useEntityLoad`, `useUrlFilter`: a filter kept in the query string, answered by `loadAllUCFactory` over an `EntitySource`. No TanStack |
19
+ | `@entifix/react-integration/event-source` | `makeEventSourceReactiveChannel`, the browser transport behind `ReactiveChannelTag` — imported by the composition root that picks it, never by a component |
19
20
 
20
21
  ---
21
22
 
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The browser transport behind `ReactiveChannelTag`: one `EventSource` over a
3
+ * same-origin URL.
4
+ *
5
+ * Its own entry point because choosing the transport and using the port are
6
+ * different acts. A component that reacts to change events reads
7
+ * `ReactiveChannelTag` from `.`; only the composition root that picks SSE
8
+ * imports this (ADR 0006).
9
+ */
10
+ export * from './reactive/event-source-channel.js';
11
+ //# sourceMappingURL=event-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-source.d.ts","sourceRoot":"","sources":["../src/event-source.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,cAAc,oCAAoC,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The browser transport behind `ReactiveChannelTag`: one `EventSource` over a
3
+ * same-origin URL.
4
+ *
5
+ * Its own entry point because choosing the transport and using the port are
6
+ * different acts. A component that reacts to change events reads
7
+ * `ReactiveChannelTag` from `.`; only the composition root that picks SSE
8
+ * imports this (ADR 0006).
9
+ */ export * from './reactive/event-source-channel.js';
10
+
11
+ //# sourceMappingURL=event-source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/event-source.ts"],"sourcesContent":["/**\n * The browser transport behind `ReactiveChannelTag`: one `EventSource` over a\n * same-origin URL.\n *\n * Its own entry point because choosing the transport and using the port are\n * different acts. A component that reacts to change events reads\n * `ReactiveChannelTag` from `.`; only the composition root that picks SSE\n * imports this (ADR 0006).\n */\nexport * from './reactive/event-source-channel.js';\n"],"names":[],"mappings":"AAAA;;;;;;;;CAQC,GACD,cAAc,qCAAqC"}
@@ -1,4 +1,4 @@
1
- import { type ConfigurationRepositoryTag, createEntityLinkResolver, type EntityLinkRegistration, type EntityLinkResolverTag } from '@entifix/business';
1
+ import { createEntityLinkResolver, type EntityLinkRegistration, type EntityLinkResolverTag } from '@entifix/business';
2
2
  import type { Context } from 'effect';
3
3
  export type { EntityLinkRegistration };
4
4
  export { createEntityLinkResolver };
@@ -13,5 +13,5 @@ export { createEntityLinkResolver };
13
13
  * component needs it without dragging this package's hooks along. Re-exported
14
14
  * here so existing client call sites keep one import.
15
15
  */
16
- export declare function useEntityLinkResolver(configurationStore: Context.Context<ConfigurationRepositoryTag>, registrations: ReadonlyArray<EntityLinkRegistration>): Context.Context<EntityLinkResolverTag>;
16
+ export declare function useEntityLinkResolver(registrations: ReadonlyArray<EntityLinkRegistration>): Context.Context<EntityLinkResolverTag>;
17
17
  //# sourceMappingURL=use-entity-link-resolver.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-entity-link-resolver.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-entity-link-resolver/use-entity-link-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,0BAA0B,EAC/B,wBAAwB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC3B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGtC,YAAY,EAAE,sBAAsB,EAAE,CAAC;AACvC,OAAO,EAAE,wBAAwB,EAAE,CAAC;AAEpC;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,kBAAkB,EAAE,OAAO,CAAC,OAAO,CAAC,0BAA0B,CAAC,EAC/D,aAAa,EAAE,aAAa,CAAC,sBAAsB,CAAC,GACnD,OAAO,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAaxC"}
1
+ {"version":3,"file":"use-entity-link-resolver.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-entity-link-resolver/use-entity-link-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC3B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGtC,YAAY,EAAE,sBAAsB,EAAE,CAAC;AACvC,OAAO,EAAE,wBAAwB,EAAE,CAAC;AAEpC;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,aAAa,CAAC,sBAAsB,CAAC,GACnD,OAAO,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAaxC"}
@@ -11,14 +11,13 @@ export { createEntityLinkResolver };
11
11
  * `@entifix/business` — nothing about it is React, and a server
12
12
  * component needs it without dragging this package's hooks along. Re-exported
13
13
  * here so existing client call sites keep one import.
14
- */ export function useEntityLinkResolver(configurationStore, registrations) {
14
+ */ export function useEntityLinkResolver(registrations) {
15
15
  // Registrations are a static list per page; key the memo on the registered
16
16
  // constructor names so it stays stable across renders without depending on the
17
17
  // array literal's identity.
18
18
  const registrationKey = registrations.map(([entityConstructor])=>entityConstructor.name).join('|');
19
- return useMemo(()=>createEntityLinkResolver(configurationStore, registrations), // eslint-disable-next-line react-hooks/exhaustive-deps
19
+ return useMemo(()=>createEntityLinkResolver(registrations), // eslint-disable-next-line react-hooks/exhaustive-deps
20
20
  [
21
- configurationStore,
22
21
  registrationKey
23
22
  ]);
24
23
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/hooks/use-entity-link-resolver/use-entity-link-resolver.ts"],"sourcesContent":["import {\n type ConfigurationRepositoryTag,\n createEntityLinkResolver,\n type EntityLinkRegistration,\n type EntityLinkResolverTag,\n} from '@entifix/business';\nimport type { Context } from 'effect';\nimport { useMemo } from 'react';\n\nexport type { EntityLinkRegistration };\nexport { createEntityLinkResolver };\n\n/**\n * React hook that memoizes an {@link EntityLinkResolverTag} context built from\n * the given repository adapters. This is the page-level seam for last-mile\n * wiring: a caller can register cached or state-backed adapters here without\n * touching the base adapters or the use-case.\n *\n * The assembly itself is `createEntityLinkResolver` in\n * `@entifix/business` — nothing about it is React, and a server\n * component needs it without dragging this package's hooks along. Re-exported\n * here so existing client call sites keep one import.\n */\nexport function useEntityLinkResolver(\n configurationStore: Context.Context<ConfigurationRepositoryTag>,\n registrations: ReadonlyArray<EntityLinkRegistration>,\n): Context.Context<EntityLinkResolverTag> {\n // Registrations are a static list per page; key the memo on the registered\n // constructor names so it stays stable across renders without depending on the\n // array literal's identity.\n const registrationKey = registrations\n .map(([entityConstructor]) => entityConstructor.name)\n .join('|');\n\n return useMemo(\n () => createEntityLinkResolver(configurationStore, registrations),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [configurationStore, registrationKey],\n );\n}\n"],"names":["createEntityLinkResolver","useMemo","useEntityLinkResolver","configurationStore","registrations","registrationKey","map","entityConstructor","name","join"],"mappings":"AAAA,SAEEA,wBAAwB,QAGnB,oBAAoB;AAE3B,SAASC,OAAO,QAAQ,QAAQ;AAGhC,SAASD,wBAAwB,GAAG;AAEpC;;;;;;;;;;CAUC,GACD,OAAO,SAASE,sBACdC,kBAA+D,EAC/DC,aAAoD;IAEpD,2EAA2E;IAC3E,+EAA+E;IAC/E,4BAA4B;IAC5B,MAAMC,kBAAkBD,cACrBE,GAAG,CAAC,CAAC,CAACC,kBAAkB,GAAKA,kBAAkBC,IAAI,EACnDC,IAAI,CAAC;IAER,OAAOR,QACL,IAAMD,yBAAyBG,oBAAoBC,gBACnD,uDAAuD;IACvD;QAACD;QAAoBE;KAAgB;AAEzC"}
1
+ {"version":3,"sources":["../../../src/hooks/use-entity-link-resolver/use-entity-link-resolver.ts"],"sourcesContent":["import {\n createEntityLinkResolver,\n type EntityLinkRegistration,\n type EntityLinkResolverTag,\n} from '@entifix/business';\nimport type { Context } from 'effect';\nimport { useMemo } from 'react';\n\nexport type { EntityLinkRegistration };\nexport { createEntityLinkResolver };\n\n/**\n * React hook that memoizes an {@link EntityLinkResolverTag} context built from\n * the given repository adapters. This is the page-level seam for last-mile\n * wiring: a caller can register cached or state-backed adapters here without\n * touching the base adapters or the use-case.\n *\n * The assembly itself is `createEntityLinkResolver` in\n * `@entifix/business` — nothing about it is React, and a server\n * component needs it without dragging this package's hooks along. Re-exported\n * here so existing client call sites keep one import.\n */\nexport function useEntityLinkResolver(\n registrations: ReadonlyArray<EntityLinkRegistration>,\n): Context.Context<EntityLinkResolverTag> {\n // Registrations are a static list per page; key the memo on the registered\n // constructor names so it stays stable across renders without depending on the\n // array literal's identity.\n const registrationKey = registrations\n .map(([entityConstructor]) => entityConstructor.name)\n .join('|');\n\n return useMemo(\n () => createEntityLinkResolver(registrations),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [registrationKey],\n );\n}\n"],"names":["createEntityLinkResolver","useMemo","useEntityLinkResolver","registrations","registrationKey","map","entityConstructor","name","join"],"mappings":"AAAA,SACEA,wBAAwB,QAGnB,oBAAoB;AAE3B,SAASC,OAAO,QAAQ,QAAQ;AAGhC,SAASD,wBAAwB,GAAG;AAEpC;;;;;;;;;;CAUC,GACD,OAAO,SAASE,sBACdC,aAAoD;IAEpD,2EAA2E;IAC3E,+EAA+E;IAC/E,4BAA4B;IAC5B,MAAMC,kBAAkBD,cACrBE,GAAG,CAAC,CAAC,CAACC,kBAAkB,GAAKA,kBAAkBC,IAAI,EACnDC,IAAI,CAAC;IAER,OAAOP,QACL,IAAMD,yBAAyBG,gBAC/B,uDAAuD;IACvD;QAACC;KAAgB;AAErB"}
package/dist/index.d.ts CHANGED
@@ -10,7 +10,6 @@ export * from './hooks/use-wizard/index.js';
10
10
  export * from './query/combine-filtering.js';
11
11
  export * from './query/entity-query-key.js';
12
12
  export * from './query/query-provider.js';
13
- export * from './reactive/event-source-channel.js';
14
13
  export * from './reactive/reactive-channel.js';
15
14
  export * from './reactive/use-reactive-invalidation.js';
16
15
  export * from './reactive/use-transaction-settlement.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qCAAqC,CAAC;AACpD,cAAc,mCAAmC,CAAC;AAClD,cAAc,kCAAkC,CAAC;AACjD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,yCAAyC,CAAC;AACxD,cAAc,sCAAsC,CAAC;AACrD,cAAc,oCAAoC,CAAC;AACnD,cAAc,uCAAuC,CAAC;AACtD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oCAAoC,CAAC;AACnD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yCAAyC,CAAC;AACxD,cAAc,0CAA0C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qCAAqC,CAAC;AACpD,cAAc,mCAAmC,CAAC;AAClD,cAAc,kCAAkC,CAAC;AACjD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,yCAAyC,CAAC;AACxD,cAAc,sCAAsC,CAAC;AACrD,cAAc,oCAAoC,CAAC;AACnD,cAAc,uCAAuC,CAAC;AACtD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yCAAyC,CAAC;AACxD,cAAc,0CAA0C,CAAC"}
package/dist/index.js CHANGED
@@ -10,7 +10,6 @@ export * from './hooks/use-wizard/index.js';
10
10
  export * from './query/combine-filtering.js';
11
11
  export * from './query/entity-query-key.js';
12
12
  export * from './query/query-provider.js';
13
- export * from './reactive/event-source-channel.js';
14
13
  export * from './reactive/reactive-channel.js';
15
14
  export * from './reactive/use-reactive-invalidation.js';
16
15
  export * from './reactive/use-transaction-settlement.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './context/adapters-context/index.js';\nexport * from './hooks/use-data-loading/index.js';\nexport * from './hooks/use-entity-form/index.js';\nexport * from './hooks/use-entity-link-resolver/index.js';\nexport * from './hooks/use-entity-link-source/index.js';\nexport * from './hooks/use-entity-mutation/index.js';\nexport * from './hooks/use-entity-record/index.js';\nexport * from './hooks/use-entity-use-cases/index.js';\nexport * from './hooks/use-wizard/index.js';\nexport * from './query/combine-filtering.js';\nexport * from './query/entity-query-key.js';\nexport * from './query/query-provider.js';\nexport * from './reactive/event-source-channel.js';\nexport * from './reactive/reactive-channel.js';\nexport * from './reactive/use-reactive-invalidation.js';\nexport * from './reactive/use-transaction-settlement.js';\n"],"names":[],"mappings":"AAAA,cAAc,sCAAsC;AACpD,cAAc,oCAAoC;AAClD,cAAc,mCAAmC;AACjD,cAAc,4CAA4C;AAC1D,cAAc,0CAA0C;AACxD,cAAc,uCAAuC;AACrD,cAAc,qCAAqC;AACnD,cAAc,wCAAwC;AACtD,cAAc,8BAA8B;AAC5C,cAAc,+BAA+B;AAC7C,cAAc,8BAA8B;AAC5C,cAAc,4BAA4B;AAC1C,cAAc,qCAAqC;AACnD,cAAc,iCAAiC;AAC/C,cAAc,0CAA0C;AACxD,cAAc,2CAA2C"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './context/adapters-context/index.js';\nexport * from './hooks/use-data-loading/index.js';\nexport * from './hooks/use-entity-form/index.js';\nexport * from './hooks/use-entity-link-resolver/index.js';\nexport * from './hooks/use-entity-link-source/index.js';\nexport * from './hooks/use-entity-mutation/index.js';\nexport * from './hooks/use-entity-record/index.js';\nexport * from './hooks/use-entity-use-cases/index.js';\nexport * from './hooks/use-wizard/index.js';\nexport * from './query/combine-filtering.js';\nexport * from './query/entity-query-key.js';\nexport * from './query/query-provider.js';\nexport * from './reactive/reactive-channel.js';\nexport * from './reactive/use-reactive-invalidation.js';\nexport * from './reactive/use-transaction-settlement.js';\n"],"names":[],"mappings":"AAAA,cAAc,sCAAsC;AACpD,cAAc,oCAAoC;AAClD,cAAc,mCAAmC;AACjD,cAAc,4CAA4C;AAC1D,cAAc,0CAA0C;AACxD,cAAc,uCAAuC;AACrD,cAAc,qCAAqC;AACnD,cAAc,wCAAwC;AACtD,cAAc,8BAA8B;AAC5C,cAAc,+BAA+B;AAC7C,cAAc,8BAA8B;AAC5C,cAAc,4BAA4B;AAC1C,cAAc,iCAAiC;AAC/C,cAAc,0CAA0C;AACxD,cAAc,2CAA2C"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-entity-load.d.ts","sourceRoot":"","sources":["../../src/url/use-entity-load.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,KAAK,MAAM,EACX,KAAK,iBAAiB,EACtB,KAAK,UAAU,EAChB,MAAM,eAAe,CAAC;AAIvB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,MAAM,UAAU,CAAC,OAAO,SAAS,MAAM,IACzC;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AAC7B;;;GAGG;GACD;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAA;CAAE,GACvE;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,CAAA;CAAE,GAC/D;IAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAiC3D;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,OAAO,SAAS,MAAM,EAClD,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,iBAAiB,CAAC,OAAO,CAAC,GAAG,IAAI,GACzC,UAAU,CAAC,OAAO,CAAC,CA0BrB"}
1
+ {"version":3,"file":"use-entity-load.d.ts","sourceRoot":"","sources":["../../src/url/use-entity-load.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,KAAK,MAAM,EACX,KAAK,iBAAiB,EACtB,KAAK,UAAU,EAChB,MAAM,eAAe,CAAC;AAIvB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,MAAM,UAAU,CAAC,OAAO,SAAS,MAAM,IACzC;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AAC7B;;;GAGG;GACD;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAA;CAAE,GACvE;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,CAAA;CAAE,GAC/D;IAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AA2B3D;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,OAAO,SAAS,MAAM,EAClD,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,iBAAiB,CAAC,OAAO,CAAC,GAAG,IAAI,GACzC,UAAU,CAAC,OAAO,CAAC,CA0BrB"}
@@ -1,5 +1,4 @@
1
- import { ConfigurationRepositoryTag, EntityLoadRequestTag, EntityRepositoryTag, loadAllUCFactory } from '@entifix/business';
2
- import { ConfigurationClientInMemory } from '@entifix/core';
1
+ import { EntityLoadRequestTag, EntityRepositoryTag, loadAllUCFactory } from '@entifix/business';
3
2
  import { Context, Effect } from 'effect';
4
3
  import { useEffect, useState } from 'react';
5
4
  const IDLE = {
@@ -7,11 +6,9 @@ const IDLE = {
7
6
  };
8
7
  /**
9
8
  * Every record a request keeps, through the `loadAll` use case: a filter
10
- * never pages. A source's repository reads no configuration here, but the
11
- * port leaves `ConfigurationRepositoryTag` on every method's requirement
12
- * channel, so an empty one discharges it.
9
+ * never pages.
13
10
  */ async function loadEvery(repository, request) {
14
- const context = Context.make(EntityRepositoryTag, repository).pipe(Context.add(ConfigurationRepositoryTag, new ConfigurationClientInMemory({})), Context.add(EntityLoadRequestTag, request));
11
+ const context = Context.make(EntityRepositoryTag, repository).pipe(Context.add(EntityLoadRequestTag, request));
15
12
  const items = await Effect.runPromise(Effect.provide(loadAllUCFactory(), context));
16
13
  return {
17
14
  items,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/url/use-entity-load.ts"],"sourcesContent":["import {\n ConfigurationRepositoryTag,\n EntityLoadRequestTag,\n type EntityRepository,\n EntityRepositoryTag,\n loadAllUCFactory,\n} from '@entifix/business';\nimport {\n ConfigurationClientInMemory,\n type Entity,\n type EntityLoadRequest,\n type EntityPage,\n} from '@entifix/core';\nimport { Context, Effect } from 'effect';\nimport { useEffect, useState } from 'react';\n\nimport type { EntitySource } from './entity-source.js';\n\nexport type EntityLoad<TEntity extends Entity> =\n | { readonly status: 'idle' }\n /**\n * Waiting for an answer. `previous` is the last answer from the same\n * source, so a filter being changed keeps showing what it showed.\n */\n | { readonly status: 'pending'; readonly previous?: EntityPage<TEntity> }\n | { readonly status: 'done'; readonly page: EntityPage<TEntity> }\n | { readonly status: 'failed'; readonly error: unknown };\n\nconst IDLE = { status: 'idle' } as const;\n\n/**\n * Every record a request keeps, through the `loadAll` use case: a filter\n * never pages. A source's repository reads no configuration here, but the\n * port leaves `ConfigurationRepositoryTag` on every method's requirement\n * channel, so an empty one discharges it.\n */\nasync function loadEvery<TEntity extends Entity>(\n repository: EntityRepository,\n request: EntityLoadRequest<TEntity>,\n): Promise<EntityPage<TEntity>> {\n const context = Context.make(EntityRepositoryTag, repository).pipe(\n Context.add(\n ConfigurationRepositoryTag,\n new ConfigurationClientInMemory({}),\n ),\n Context.add(EntityLoadRequestTag, request as unknown as EntityLoadRequest),\n );\n const items = await Effect.runPromise(\n Effect.provide(loadAllUCFactory<TEntity>(), context),\n );\n return { items, total: items.length, request };\n}\n\ninterface Answer<TEntity extends Entity> {\n readonly source: EntitySource;\n readonly key: string;\n readonly load: EntityLoad<TEntity>;\n}\n\n/**\n * Every record a request selects, through the `loadAll` use case over a source.\n *\n * `null` asks for nothing and answers `idle`: before hydration, and while no\n * filter is set, the page shows what the build rendered. An answer counts only\n * for the request it was asked for, so a late answer to an older filter is\n * never shown as the current one.\n */\nexport function useEntityLoad<TEntity extends Entity>(\n source: EntitySource,\n request: EntityLoadRequest<TEntity> | null,\n): EntityLoad<TEntity> {\n const [answer, setAnswer] = useState<Answer<TEntity>>();\n // Requests are rebuilt on every render; their content is what changes.\n const key = request === null ? null : JSON.stringify(request);\n\n useEffect(() => {\n if (request === null || key === null) return;\n const settle = (load: EntityLoad<TEntity>) =>\n setAnswer({ source, key, load });\n source()\n .then(repository => loadEvery<TEntity>(repository, request))\n .then(\n page => settle({ status: 'done', page }),\n (error: unknown) => settle({ status: 'failed', error }),\n );\n // `request` is read through `key`, its content: a new object with the\n // same content is the same request.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [source, key]);\n\n if (key === null) return IDLE;\n if (answer?.source !== source) return { status: 'pending' };\n if (answer.key === key) return answer.load;\n return answer.load.status === 'done'\n ? { status: 'pending', previous: answer.load.page }\n : { status: 'pending' };\n}\n"],"names":["ConfigurationRepositoryTag","EntityLoadRequestTag","EntityRepositoryTag","loadAllUCFactory","ConfigurationClientInMemory","Context","Effect","useEffect","useState","IDLE","status","loadEvery","repository","request","context","make","pipe","add","items","runPromise","provide","total","length","useEntityLoad","source","answer","setAnswer","key","JSON","stringify","settle","load","then","page","error","previous"],"mappings":"AAAA,SACEA,0BAA0B,EAC1BC,oBAAoB,EAEpBC,mBAAmB,EACnBC,gBAAgB,QACX,oBAAoB;AAC3B,SACEC,2BAA2B,QAItB,gBAAgB;AACvB,SAASC,OAAO,EAAEC,MAAM,QAAQ,SAAS;AACzC,SAASC,SAAS,EAAEC,QAAQ,QAAQ,QAAQ;AAc5C,MAAMC,OAAO;IAAEC,QAAQ;AAAO;AAE9B;;;;;CAKC,GACD,eAAeC,UACbC,UAA4B,EAC5BC,OAAmC;IAEnC,MAAMC,UAAUT,QAAQU,IAAI,CAACb,qBAAqBU,YAAYI,IAAI,CAChEX,QAAQY,GAAG,CACTjB,4BACA,IAAII,4BAA4B,CAAC,KAEnCC,QAAQY,GAAG,CAAChB,sBAAsBY;IAEpC,MAAMK,QAAQ,MAAMZ,OAAOa,UAAU,CACnCb,OAAOc,OAAO,CAACjB,oBAA6BW;IAE9C,OAAO;QAAEI;QAAOG,OAAOH,MAAMI,MAAM;QAAET;IAAQ;AAC/C;AAQA;;;;;;;CAOC,GACD,OAAO,SAASU,cACdC,MAAoB,EACpBX,OAA0C;IAE1C,MAAM,CAACY,QAAQC,UAAU,GAAGlB;IAC5B,uEAAuE;IACvE,MAAMmB,MAAMd,YAAY,OAAO,OAAOe,KAAKC,SAAS,CAAChB;IAErDN,UAAU;QACR,IAAIM,YAAY,QAAQc,QAAQ,MAAM;QACtC,MAAMG,SAAS,CAACC,OACdL,UAAU;gBAAEF;gBAAQG;gBAAKI;YAAK;QAChCP,SACGQ,IAAI,CAACpB,CAAAA,aAAcD,UAAmBC,YAAYC,UAClDmB,IAAI,CACHC,CAAAA,OAAQH,OAAO;gBAAEpB,QAAQ;gBAAQuB;YAAK,IACtC,CAACC,QAAmBJ,OAAO;gBAAEpB,QAAQ;gBAAUwB;YAAM;IAEzD,sEAAsE;IACtE,oCAAoC;IACpC,uDAAuD;IACzD,GAAG;QAACV;QAAQG;KAAI;IAEhB,IAAIA,QAAQ,MAAM,OAAOlB;IACzB,IAAIgB,CAAAA,0BAAAA,OAAQD,MAAM,MAAKA,QAAQ,OAAO;QAAEd,QAAQ;IAAU;IAC1D,IAAIe,OAAOE,GAAG,KAAKA,KAAK,OAAOF,OAAOM,IAAI;IAC1C,OAAON,OAAOM,IAAI,CAACrB,MAAM,KAAK,SAC1B;QAAEA,QAAQ;QAAWyB,UAAUV,OAAOM,IAAI,CAACE,IAAI;IAAC,IAChD;QAAEvB,QAAQ;IAAU;AAC1B"}
1
+ {"version":3,"sources":["../../src/url/use-entity-load.ts"],"sourcesContent":["import {\n EntityLoadRequestTag,\n type EntityRepository,\n EntityRepositoryTag,\n loadAllUCFactory,\n} from '@entifix/business';\nimport {\n type Entity,\n type EntityLoadRequest,\n type EntityPage,\n} from '@entifix/core';\nimport { Context, Effect } from 'effect';\nimport { useEffect, useState } from 'react';\n\nimport type { EntitySource } from './entity-source.js';\n\nexport type EntityLoad<TEntity extends Entity> =\n | { readonly status: 'idle' }\n /**\n * Waiting for an answer. `previous` is the last answer from the same\n * source, so a filter being changed keeps showing what it showed.\n */\n | { readonly status: 'pending'; readonly previous?: EntityPage<TEntity> }\n | { readonly status: 'done'; readonly page: EntityPage<TEntity> }\n | { readonly status: 'failed'; readonly error: unknown };\n\nconst IDLE = { status: 'idle' } as const;\n\n/**\n * Every record a request keeps, through the `loadAll` use case: a filter\n * never pages.\n */\nasync function loadEvery<TEntity extends Entity>(\n repository: EntityRepository,\n request: EntityLoadRequest<TEntity>,\n): Promise<EntityPage<TEntity>> {\n const context = Context.make(EntityRepositoryTag, repository).pipe(\n Context.add(EntityLoadRequestTag, request as unknown as EntityLoadRequest),\n );\n const items = await Effect.runPromise(\n Effect.provide(loadAllUCFactory<TEntity>(), context),\n );\n return { items, total: items.length, request };\n}\n\ninterface Answer<TEntity extends Entity> {\n readonly source: EntitySource;\n readonly key: string;\n readonly load: EntityLoad<TEntity>;\n}\n\n/**\n * Every record a request selects, through the `loadAll` use case over a source.\n *\n * `null` asks for nothing and answers `idle`: before hydration, and while no\n * filter is set, the page shows what the build rendered. An answer counts only\n * for the request it was asked for, so a late answer to an older filter is\n * never shown as the current one.\n */\nexport function useEntityLoad<TEntity extends Entity>(\n source: EntitySource,\n request: EntityLoadRequest<TEntity> | null,\n): EntityLoad<TEntity> {\n const [answer, setAnswer] = useState<Answer<TEntity>>();\n // Requests are rebuilt on every render; their content is what changes.\n const key = request === null ? null : JSON.stringify(request);\n\n useEffect(() => {\n if (request === null || key === null) return;\n const settle = (load: EntityLoad<TEntity>) =>\n setAnswer({ source, key, load });\n source()\n .then(repository => loadEvery<TEntity>(repository, request))\n .then(\n page => settle({ status: 'done', page }),\n (error: unknown) => settle({ status: 'failed', error }),\n );\n // `request` is read through `key`, its content: a new object with the\n // same content is the same request.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [source, key]);\n\n if (key === null) return IDLE;\n if (answer?.source !== source) return { status: 'pending' };\n if (answer.key === key) return answer.load;\n return answer.load.status === 'done'\n ? { status: 'pending', previous: answer.load.page }\n : { status: 'pending' };\n}\n"],"names":["EntityLoadRequestTag","EntityRepositoryTag","loadAllUCFactory","Context","Effect","useEffect","useState","IDLE","status","loadEvery","repository","request","context","make","pipe","add","items","runPromise","provide","total","length","useEntityLoad","source","answer","setAnswer","key","JSON","stringify","settle","load","then","page","error","previous"],"mappings":"AAAA,SACEA,oBAAoB,EAEpBC,mBAAmB,EACnBC,gBAAgB,QACX,oBAAoB;AAM3B,SAASC,OAAO,EAAEC,MAAM,QAAQ,SAAS;AACzC,SAASC,SAAS,EAAEC,QAAQ,QAAQ,QAAQ;AAc5C,MAAMC,OAAO;IAAEC,QAAQ;AAAO;AAE9B;;;CAGC,GACD,eAAeC,UACbC,UAA4B,EAC5BC,OAAmC;IAEnC,MAAMC,UAAUT,QAAQU,IAAI,CAACZ,qBAAqBS,YAAYI,IAAI,CAChEX,QAAQY,GAAG,CAACf,sBAAsBW;IAEpC,MAAMK,QAAQ,MAAMZ,OAAOa,UAAU,CACnCb,OAAOc,OAAO,CAAChB,oBAA6BU;IAE9C,OAAO;QAAEI;QAAOG,OAAOH,MAAMI,MAAM;QAAET;IAAQ;AAC/C;AAQA;;;;;;;CAOC,GACD,OAAO,SAASU,cACdC,MAAoB,EACpBX,OAA0C;IAE1C,MAAM,CAACY,QAAQC,UAAU,GAAGlB;IAC5B,uEAAuE;IACvE,MAAMmB,MAAMd,YAAY,OAAO,OAAOe,KAAKC,SAAS,CAAChB;IAErDN,UAAU;QACR,IAAIM,YAAY,QAAQc,QAAQ,MAAM;QACtC,MAAMG,SAAS,CAACC,OACdL,UAAU;gBAAEF;gBAAQG;gBAAKI;YAAK;QAChCP,SACGQ,IAAI,CAACpB,CAAAA,aAAcD,UAAmBC,YAAYC,UAClDmB,IAAI,CACHC,CAAAA,OAAQH,OAAO;gBAAEpB,QAAQ;gBAAQuB;YAAK,IACtC,CAACC,QAAmBJ,OAAO;gBAAEpB,QAAQ;gBAAUwB;YAAM;IAEzD,sEAAsE;IACtE,oCAAoC;IACpC,uDAAuD;IACzD,GAAG;QAACV;QAAQG;KAAI;IAEhB,IAAIA,QAAQ,MAAM,OAAOlB;IACzB,IAAIgB,CAAAA,0BAAAA,OAAQD,MAAM,MAAKA,QAAQ,OAAO;QAAEd,QAAQ;IAAU;IAC1D,IAAIe,OAAOE,GAAG,KAAKA,KAAK,OAAOF,OAAOM,IAAI;IAC1C,OAAON,OAAOM,IAAI,CAACrB,MAAM,KAAK,SAC1B;QAAEA,QAAQ;QAAWyB,UAAUV,OAAOM,IAAI,CAACE,IAAI;IAAC,IAChD;QAAEvB,QAAQ;IAAU;AAC1B"}
package/package.json CHANGED
@@ -21,7 +21,7 @@
21
21
  }
22
22
  }
23
23
  },
24
- "version": "0.4.2",
24
+ "version": "0.5.0",
25
25
  "description": "React hooks that bind entities to data: TanStack Query and Form over the entity adapters, drafts, mutations and live invalidation.",
26
26
  "license": "MIT",
27
27
  "repository": {
@@ -47,6 +47,11 @@
47
47
  "types": "./dist/url.d.ts",
48
48
  "import": "./dist/url.js",
49
49
  "default": "./dist/url.js"
50
+ },
51
+ "./event-source": {
52
+ "types": "./dist/event-source.d.ts",
53
+ "import": "./dist/event-source.js",
54
+ "default": "./dist/event-source.js"
50
55
  }
51
56
  },
52
57
  "files": [
@@ -55,16 +60,16 @@
55
60
  "LICENSE"
56
61
  ],
57
62
  "dependencies": {
58
- "@entifix/business": "0.4.2",
59
- "@entifix/core": "0.4.2",
60
- "@entifix/transactions": "0.4.2"
63
+ "@entifix/business": "0.5.0",
64
+ "@entifix/core": "0.5.0",
65
+ "@entifix/transactions": "0.5.0"
61
66
  },
62
67
  "devDependencies": {
63
68
  "@tanstack/react-form": "1.33.5",
64
69
  "@tanstack/react-query": "^5.104.5",
65
70
  "effect": "4.0.5",
66
71
  "react": "19.3.1",
67
- "@entifix/testing-unit": "0.4.2"
72
+ "@entifix/testing-unit": "0.5.0"
68
73
  },
69
74
  "peerDependencies": {
70
75
  "@tanstack/react-form": ">=1.33 <2",